VFS quota: add a command to set a user's quota
authorFrancois Tigeot <ftigeot@wolfpond.org>
Fri, 23 Mar 2012 22:19:12 +0000 (23:19 +0100)
committerFran├žois Tigeot <ftigeot@wolfpond.org>
Tue, 17 Apr 2012 17:21:15 +0000 (19:21 +0200)
sbin/vquota/vquota.8
sbin/vquota/vquota.c
sys/kern/vfs_quota.c

index 34e1382..2d17ce2 100644 (file)
@@ -90,6 +90,14 @@ Set a global quota of
 .Ar size
 bytes for the filesystem mounted under
 .Ar mount_point .
+.\" ==== ulim ====
+.It Cm ulim Ar mount_point user size
+Set a quota of
+.Ar size
+bytes for the filesystem mounted under
+.Ar mount_point
+and the specified
+.Ar user .
 .El
 .
 .Sh EXAMPLES
index e6348ba..a1f3592 100644 (file)
@@ -63,6 +63,7 @@ usage(int retcode)
        fprintf(stderr, "usage: vquota [-Dhn] check directory\n");
        fprintf(stderr, "       vquota [-Dhn] lsfs\n");
        fprintf(stderr, "       vquota [-Dhn] limit mount_point size\n");
+       fprintf(stderr, "       vquota [-Dhn] ulim  mount_point user  size\n");
        fprintf(stderr, "       vquota [-Dhn] show mount_point\n");
        fprintf(stderr, "       vquota [-Dhn] sync mount_point\n");
        exit(retcode);
@@ -642,10 +643,38 @@ cmd_limit(char *dirname, uint64_t limit)
        return rv;
 }
 
+static int
+cmd_limit_uid(char *dirname, uid_t uid, uint64_t limit)
+{
+       prop_dictionary_t res, args;
+       int rv = 0;
+
+       args = prop_dictionary_create();
+       if (args == NULL)
+               printf("cmd_limit_uid(): couldn't create args dictionary\n");
+       res  = prop_dictionary_create();
+       if (res == NULL)
+               printf("cmd_limit_uid(): couldn't create res dictionary\n");
+
+       (void) prop_dictionary_set_uint32(args, "uid", uid);
+       (void) prop_dictionary_set_uint64(args, "limit", limit);
+
+       if (send_command(dirname, "set limit uid", args, &res) == false) {
+               printf("Failed to send message to kernel\n");
+               rv = 1;
+       }
+
+       prop_object_release(args);
+       prop_object_release(res);
+
+       return rv;
+}
+
 int
 main(int argc, char **argv)
 {
        int ch;
+       uint64_t limit;
 
        while ((ch = getopt(argc, argv, "Dhn")) != -1) {
                switch(ch) {
@@ -674,7 +703,6 @@ main(int argc, char **argv)
                return get_fslist();
        }
        if (strcmp(argv[0], "limit") == 0) {
-               uint64_t limit;
                if (argc != 3)
                        usage(1);
                if (dehumanize_number(argv[2], &limit) < 0)
@@ -692,6 +720,17 @@ main(int argc, char **argv)
                        usage(1);
                return cmd_sync(argv[1]);
        }
+       if (strcmp(argv[0], "ulim") == 0) {
+               struct passwd *pwd;
+               if (argc != 4)
+                       usage(1);
+               if ((pwd = getpwnam(argv[2])) == NULL)
+                       errx(1, "%s: no such user", argv[2]);
+               if (dehumanize_number(argv[3], &limit) < 0)
+                       err(1, "bad number for option: %s", argv[2]);
+
+               return cmd_limit_uid(argv[1], pwd->pw_uid, limit);
+       }
 
        usage(0);
 }
index a7723ef..26004e0 100644 (file)
@@ -283,6 +283,27 @@ cmd_set_limit(struct mount *mp, prop_dictionary_t args)
        return 0;
 }
 
+static int
+cmd_set_limit_uid(struct mount *mp, prop_dictionary_t args)
+{
+       uint64_t limit;
+       uid_t uid;
+       struct ac_unode ufind, *unp;
+
+       prop_dictionary_get_uint32(args, "uid", &uid);
+       prop_dictionary_get_uint64(args, "limit", &limit);
+
+       ufind.left_bits = (uid >> ACCT_CHUNK_BITS);
+
+       spin_lock(&mp->mnt_acct.ac_spin);
+       if ((unp = RB_FIND(ac_utree, &mp->mnt_acct.ac_uroot, &ufind)) == NULL)
+               unp = unode_insert(mp, uid);
+       unp->uid_chunk[(uid & ACCT_CHUNK_MASK)].limit = limit;
+       spin_unlock(&mp->mnt_acct.ac_spin);
+
+       return 0;
+}
+
 int
 sys_vquotactl(struct vquotactl_args *vqa)
 /* const char *path, struct plistref *pref */
@@ -344,6 +365,10 @@ sys_vquotactl(struct vquotactl_args *vqa)
                error = cmd_set_limit(mp, args);
                goto done;
        }
+       if (strcmp(cmd, "set limit uid") == 0) {
+               error = cmd_set_limit_uid(mp, args);
+               goto done;
+       }
        return EINVAL;
 
 done: