Module Name: src
Committed By: dholland
Date: Sun Jul 10 07:31:48 UTC 2011
Modified Files:
src/usr.sbin/edquota: edquota.c
Log Message:
tsort contents of file.
To generate a diff of this commit:
cvs rdiff -u -r1.33 -r1.34 src/usr.sbin/edquota/edquota.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.sbin/edquota/edquota.c
diff -u src/usr.sbin/edquota/edquota.c:1.33 src/usr.sbin/edquota/edquota.c:1.34
--- src/usr.sbin/edquota/edquota.c:1.33 Sun Jul 10 07:19:24 2011
+++ src/usr.sbin/edquota/edquota.c Sun Jul 10 07:31:48 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: edquota.c,v 1.33 2011/07/10 07:19:24 dholland Exp $ */
+/* $NetBSD: edquota.c,v 1.34 2011/07/10 07:31:48 dholland Exp $ */
/*
* Copyright (c) 1980, 1990, 1993
* The Regents of the University of California. All rights reserved.
@@ -41,7 +41,7 @@
#if 0
static char sccsid[] = "from: @(#)edquota.c 8.3 (Berkeley) 4/27/95";
#else
-__RCSID("$NetBSD: edquota.c,v 1.33 2011/07/10 07:19:24 dholland Exp $");
+__RCSID("$NetBSD: edquota.c,v 1.34 2011/07/10 07:31:48 dholland Exp $");
#endif
#endif /* not lint */
@@ -119,228 +119,8 @@
#define QL_BLK QUOTA_LIMIT_BLOCK
#define QL_FL QUOTA_LIMIT_FILE
-int
-main(int argc, char *argv[])
-{
- struct quotause *qup, *protoprivs, *curprivs;
- long id, protoid;
- int quotaclass, tmpfd;
- char *protoname;
- char *soft = NULL, *hard = NULL, *grace = NULL;
- char *fs = NULL;
- int ch;
- int pflag = 0;
- int cflag = 0;
-
- if (argc < 2)
- usage();
- if (getuid())
- errx(1, "permission denied");
- protoname = NULL;
- quotaclass = QUOTA_CLASS_USER;
- while ((ch = getopt(argc, argv, "DHcdugp:s:h:t:f:")) != -1) {
- switch(ch) {
- case 'D':
- Dflag++;
- break;
- case 'H':
- Hflag++;
- break;
- case 'c':
- cflag++;
- break;
- case 'd':
- dflag++;
- break;
- case 'p':
- protoname = optarg;
- pflag++;
- break;
- case 'g':
- quotaclass = QUOTA_CLASS_GROUP;
- break;
- case 'u':
- quotaclass = QUOTA_CLASS_USER;
- break;
- case 's':
- soft = optarg;
- break;
- case 'h':
- hard = optarg;
- break;
- case 't':
- grace = optarg;
- break;
- case 'f':
- fs = optarg;
- break;
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (pflag) {
- if (soft || hard || grace || dflag || cflag)
- usage();
- if ((protoid = getentry(protoname, quotaclass)) == -1)
- return 1;
- protoprivs = getprivs(protoid, quotaclass, fs, 0);
- for (qup = protoprivs; qup; qup = qup->next) {
- qup->qe[QL_BLK].ufsqe_time = 0;
- qup->qe[QL_FL].ufsqe_time = 0;
- }
- while (argc-- > 0) {
- if ((id = getentry(*argv++, quotaclass)) < 0)
- continue;
- putprivs(id, quotaclass, protoprivs);
- }
- return 0;
- }
- if (soft || hard || grace) {
- struct quotause *lqup;
- u_int64_t softb, hardb, softi, hardi;
- time_t graceb, gracei;
- char *str;
-
- if (cflag)
- usage();
- if (soft) {
- str = strsep(&soft, "/");
- if (str[0] == '\0' || soft == NULL || soft[0] == '\0')
- usage();
-
- if (intrd(str, &softb, HN_B) != 0)
- errx(1, "%s: bad number", str);
- if (intrd(soft, &softi, 0) != 0)
- errx(1, "%s: bad number", soft);
- }
- if (hard) {
- str = strsep(&hard, "/");
- if (str[0] == '\0' || hard == NULL || hard[0] == '\0')
- usage();
-
- if (intrd(str, &hardb, HN_B) != 0)
- errx(1, "%s: bad number", str);
- if (intrd(hard, &hardi, 0) != 0)
- errx(1, "%s: bad number", hard);
- }
- if (grace) {
- str = strsep(&grace, "/");
- if (str[0] == '\0' || grace == NULL || grace[0] == '\0')
- usage();
-
- if (timeprd(str, &graceb) != 0)
- errx(1, "%s: bad number", str);
- if (timeprd(grace, &gracei) != 0)
- errx(1, "%s: bad number", grace);
- }
- if (dflag) {
- curprivs = getprivs(0, quotaclass, fs, 1);
- for (lqup = curprivs; lqup; lqup = lqup->next) {
- struct ufs_quota_entry *q = lqup->qe;
- if (soft) {
- q[QL_BLK].ufsqe_softlimit = softb;
- q[QL_FL].ufsqe_softlimit = softi;
- }
- if (hard) {
- q[QL_BLK].ufsqe_hardlimit = hardb;
- q[QL_FL].ufsqe_hardlimit = hardi;
- }
- if (grace) {
- q[QL_BLK].ufsqe_grace = graceb;
- q[QL_FL].ufsqe_grace = gracei;
- }
- }
- putprivs(0, quotaclass, curprivs);
- freeprivs(curprivs);
- return 0;
- }
- for ( ; argc > 0; argc--, argv++) {
- if ((id = getentry(*argv, quotaclass)) == -1)
- continue;
- curprivs = getprivs(id, quotaclass, fs, 0);
- for (lqup = curprivs; lqup; lqup = lqup->next) {
- struct ufs_quota_entry *q = lqup->qe;
- if (soft) {
- if (softb &&
- q[QL_BLK].ufsqe_cur >= softb &&
- (q[QL_BLK].ufsqe_softlimit == 0 ||
- q[QL_BLK].ufsqe_cur <
- q[QL_BLK].ufsqe_softlimit))
- q[QL_BLK].ufsqe_time = 0;
- if (softi &&
- q[QL_FL].ufsqe_cur >= softb &&
- (q[QL_FL].ufsqe_softlimit == 0 ||
- q[QL_FL].ufsqe_cur <
- q[QL_FL].ufsqe_softlimit))
- q[QL_FL].ufsqe_time = 0;
- q[QL_BLK].ufsqe_softlimit = softb;
- q[QL_FL].ufsqe_softlimit = softi;
- }
- if (hard) {
- q[QL_BLK].ufsqe_hardlimit = hardb;
- q[QL_FL].ufsqe_hardlimit = hardi;
- }
- if (grace) {
- q[QL_BLK].ufsqe_grace = graceb;
- q[QL_FL].ufsqe_grace = gracei;
- }
- }
- putprivs(id, quotaclass, curprivs);
- freeprivs(curprivs);
- }
- return 0;
- }
- if (cflag) {
- if (dflag)
- usage();
- clearpriv(argc, argv, fs, quotaclass);
- return 0;
- }
- tmpfd = mkstemp(tmpfil);
- fchown(tmpfd, getuid(), getgid());
- if (dflag) {
- curprivs = getprivs(0, quotaclass, fs, 1);
- if (writeprivs(curprivs, tmpfd, NULL, quotaclass) &&
- editit(tmpfil) && readprivs(curprivs, tmpfd))
- putprivs(0, quotaclass, curprivs);
- freeprivs(curprivs);
- }
- for ( ; argc > 0; argc--, argv++) {
- if ((id = getentry(*argv, quotaclass)) == -1)
- continue;
- curprivs = getprivs(id, quotaclass, fs, 0);
- if (writeprivs(curprivs, tmpfd, *argv, quotaclass) == 0)
- continue;
- if (editit(tmpfil) && readprivs(curprivs, tmpfd))
- putprivs(id, quotaclass, curprivs);
- freeprivs(curprivs);
- }
- close(tmpfd);
- unlink(tmpfil);
- return 0;
-}
-
-static void
-usage(void)
-{
- const char *p = getprogname();
- fprintf(stderr,
- "Usage: %s [-D] [-H] [-u] [-p <username>] [-f <filesystem>] "
- "-d | <username> ...\n"
- "\t%s [-D] [-H] -g [-p <groupname>] [-f <filesystem>] "
- "-d | <groupname> ...\n"
- "\t%s [-D] [-u] [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] "
- "-d | <username> ...\n"
- "\t%s [-D] -g [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] "
- "-d | <groupname> ...\n"
- "\t%s [-D] [-H] [-u] -c [-f <filesystem>] username ...\n"
- "\t%s [-D] [-H] -g -c [-f <filesystem>] groupname ...\n",
- p, p, p, p, p, p);
- exit(1);
-}
+////////////////////////////////////////////////////////////
+// support code
/*
* This routine converts a name for a particular quota type to
@@ -374,79 +154,56 @@
return -1;
}
+////////////////////////////////////////////////////////////
+// quotause operations
+
/*
- * Collect the requested quota information.
+ * Free a quotause structure.
*/
-static struct quotause *
-getprivs(long id, int quotaclass, const char *filesys, int defaultq)
+static void
+freeq(struct quotause *qup)
{
- struct statvfs *fst;
- int nfst, i;
- struct quotause *qup, *quptail = NULL;
- struct quotause *quphead = NULL;
+ free(qup->qfname);
+ free(qup);
+}
- nfst = getmntinfo(&fst, MNT_WAIT);
- if (nfst == 0)
- errx(1, "no filesystems mounted!");
+/*
+ * Free a list of quotause structures.
+ */
+static void
+freeprivs(struct quotause *quplist)
+{
+ struct quotause *qup, *nextqup;
- for (i = 0; i < nfst; i++) {
- if ((fst[i].f_flag & ST_QUOTA) == 0)
- continue;
- if (filesys && strcmp(fst[i].f_mntonname, filesys) != 0 &&
- strcmp(fst[i].f_mntfromname, filesys) != 0)
- continue;
- qup = getprivs2(id, quotaclass, fst[i].f_mntonname, defaultq);
- if (qup == NULL)
- return NULL;
- if (quphead == NULL)
- quphead = qup;
- else
- quptail->next = qup;
- quptail = qup;
- qup->next = 0;
- }
-
- if (filesys && quphead == NULL) {
- if (defaultq)
- errx(1, "no default quota for version 1");
- /* if we get there, filesys is not mounted. try the old way */
- qup = getprivs1(id, quotaclass, filesys);
- if (qup == NULL)
- return NULL;
- if (quphead == NULL)
- quphead = qup;
- else
- quptail->next = qup;
- quptail = qup;
- qup->next = 0;
+ for (qup = quplist; qup; qup = nextqup) {
+ nextqup = qup->next;
+ freeq(qup);
}
- return quphead;
}
-static struct quotause *
-getprivs2(long id, int quotaclass, const char *filesys, int defaultq)
+////////////////////////////////////////////////////////////
+// ffs quota v1
+
+static void
+putprivs1(uint32_t id, int quotaclass, struct quotause *qup)
{
- struct quotause *qup;
- int8_t version;
+ struct dqblk dqblk;
+ int fd;
- if ((qup = malloc(sizeof(*qup))) == NULL)
- err(1, "out of memory");
- memset(qup, 0, sizeof(*qup));
- strcpy(qup->fsname, filesys);
- if (defaultq)
- qup->flags |= DEFAULT;
- if (!getvfsquota(filesys, qup->qe, &version,
- id, quotaclass, defaultq, Dflag)) {
- /* no entry, get default entry */
- if (!getvfsquota(filesys, qup->qe, &version,
- id, quotaclass, 1, Dflag)) {
- free(qup);
- return NULL;
- }
+ ufsqe2dqblk(qup->qe, &dqblk);
+ assert((qup->flags & DEFAULT) == 0);
+
+ if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
+ warnx("open `%s'", qup->qfname);
+ } else {
+ (void)lseek(fd,
+ (off_t)(id * (long)sizeof (struct dqblk)),
+ SEEK_SET);
+ if (write(fd, &dqblk, sizeof (struct dqblk)) !=
+ sizeof (struct dqblk))
+ warnx("writing `%s'", qup->qfname);
+ close(fd);
}
- if (version == 2)
- qup->flags |= QUOTA2;
- return qup;
}
static struct quotause *
@@ -515,20 +272,33 @@
return qup;
}
-/*
- * Store the requested quota information.
- */
-void
-putprivs(uint32_t id, int quotaclass, struct quotause *quplist)
+////////////////////////////////////////////////////////////
+// ffs quota v2
+
+static struct quotause *
+getprivs2(long id, int quotaclass, const char *filesys, int defaultq)
{
struct quotause *qup;
+ int8_t version;
- for (qup = quplist; qup; qup = qup->next) {
- if (qup->qfname == NULL)
- putprivs2(id, quotaclass, qup);
- else
- putprivs1(id, quotaclass, qup);
+ if ((qup = malloc(sizeof(*qup))) == NULL)
+ err(1, "out of memory");
+ memset(qup, 0, sizeof(*qup));
+ strcpy(qup->fsname, filesys);
+ if (defaultq)
+ qup->flags |= DEFAULT;
+ if (!getvfsquota(filesys, qup->qe, &version,
+ id, quotaclass, defaultq, Dflag)) {
+ /* no entry, get default entry */
+ if (!getvfsquota(filesys, qup->qe, &version,
+ id, quotaclass, 1, Dflag)) {
+ free(qup);
+ return NULL;
+ }
}
+ if (version == 2)
+ qup->flags |= QUOTA2;
+ return qup;
}
static void
@@ -611,115 +381,256 @@
prop_object_release(dict);
}
-static void
-putprivs1(uint32_t id, int quotaclass, struct quotause *qup)
+////////////////////////////////////////////////////////////
+// quota format switch
+
+/*
+ * Collect the requested quota information.
+ */
+static struct quotause *
+getprivs(long id, int quotaclass, const char *filesys, int defaultq)
{
- struct dqblk dqblk;
- int fd;
+ struct statvfs *fst;
+ int nfst, i;
+ struct quotause *qup, *quptail = NULL;
+ struct quotause *quphead = NULL;
- ufsqe2dqblk(qup->qe, &dqblk);
- assert((qup->flags & DEFAULT) == 0);
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst == 0)
+ errx(1, "no filesystems mounted!");
- if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
- warnx("open `%s'", qup->qfname);
- } else {
- (void)lseek(fd,
- (off_t)(id * (long)sizeof (struct dqblk)),
- SEEK_SET);
- if (write(fd, &dqblk, sizeof (struct dqblk)) !=
- sizeof (struct dqblk))
- warnx("writing `%s'", qup->qfname);
- close(fd);
+ for (i = 0; i < nfst; i++) {
+ if ((fst[i].f_flag & ST_QUOTA) == 0)
+ continue;
+ if (filesys && strcmp(fst[i].f_mntonname, filesys) != 0 &&
+ strcmp(fst[i].f_mntfromname, filesys) != 0)
+ continue;
+ qup = getprivs2(id, quotaclass, fst[i].f_mntonname, defaultq);
+ if (qup == NULL)
+ return NULL;
+ if (quphead == NULL)
+ quphead = qup;
+ else
+ quptail->next = qup;
+ quptail = qup;
+ qup->next = 0;
+ }
+
+ if (filesys && quphead == NULL) {
+ if (defaultq)
+ errx(1, "no default quota for version 1");
+ /* if we get there, filesys is not mounted. try the old way */
+ qup = getprivs1(id, quotaclass, filesys);
+ if (qup == NULL)
+ return NULL;
+ if (quphead == NULL)
+ quphead = qup;
+ else
+ quptail->next = qup;
+ quptail = qup;
+ qup->next = 0;
}
+ return quphead;
}
/*
- * Take a list of privileges and get it edited.
+ * Store the requested quota information.
*/
-static int
-editit(const char *ltmpfile)
+void
+putprivs(uint32_t id, int quotaclass, struct quotause *quplist)
{
- pid_t pid;
- int lst;
- char p[MAX_TMPSTR];
- const char *ed;
- sigset_t s, os;
+ struct quotause *qup;
- sigemptyset(&s);
- sigaddset(&s, SIGINT);
- sigaddset(&s, SIGQUIT);
- sigaddset(&s, SIGHUP);
- if (sigprocmask(SIG_BLOCK, &s, &os) == -1)
- err(1, "sigprocmask");
-top:
- switch ((pid = fork())) {
- case -1:
- if (errno == EPROCLIM) {
- warnx("You have too many processes");
- return 0;
- }
- if (errno == EAGAIN) {
- sleep(1);
- goto top;
- }
- warn("fork");
- return 0;
- case 0:
- if (sigprocmask(SIG_SETMASK, &os, NULL) == -1)
- err(1, "sigprocmask");
- setgid(getgid());
- setuid(getuid());
- if ((ed = getenv("EDITOR")) == (char *)0)
- ed = _PATH_VI;
- if (strlen(ed) + strlen(ltmpfile) + 2 >= MAX_TMPSTR) {
- errx(1, "%s", "editor or filename too long");
- }
- snprintf(p, sizeof(p), "%s %s", ed, ltmpfile);
- execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", p, NULL);
- err(1, "%s", ed);
- default:
- if (waitpid(pid, &lst, 0) == -1)
- err(1, "waitpid");
- if (sigprocmask(SIG_SETMASK, &os, NULL) == -1)
- err(1, "sigprocmask");
- if (!WIFEXITED(lst) || WEXITSTATUS(lst) != 0)
- return 0;
- return 1;
+ for (qup = quplist; qup; qup = qup->next) {
+ if (qup->qfname == NULL)
+ putprivs2(id, quotaclass, qup);
+ else
+ putprivs1(id, quotaclass, qup);
}
}
-/*
- * Convert a quotause list to an ASCII file.
- */
-static int
-writeprivs(struct quotause *quplist, int outfd, const char *name,
- int quotaclass)
+static void
+clearpriv(int argc, char **argv, const char *filesys, int quotaclass)
{
- struct quotause *qup;
- FILE *fd;
- char b0[32], b1[32], b2[32], b3[32];
+ prop_array_t cmds, datas;
+ prop_dictionary_t protodict, dict, data, cmd;
+ struct plistref pref;
+ bool ret;
+ struct statvfs *fst;
+ int nfst, i;
+ int8_t error8;
+ int id;
- (void)ftruncate(outfd, 0);
- (void)lseek(outfd, (off_t)0, SEEK_SET);
- if ((fd = fdopen(dup(outfd), "w")) == NULL)
- errx(1, "fdopen `%s'", tmpfil);
- if (dflag) {
- fprintf(fd, "Default %s quotas:\n",
- ufs_quota_class_names[quotaclass]);
- } else {
- fprintf(fd, "Quotas for %s %s:\n",
- ufs_quota_class_names[quotaclass], name);
+ /* build a generic command */
+ protodict = quota_prop_create();
+ cmds = prop_array_create();
+ datas = prop_array_create();
+ if (protodict == NULL || cmds == NULL || datas == NULL) {
+ errx(1, "can't allocate proplist");
}
- for (qup = quplist; qup; qup = qup->next) {
- struct ufs_quota_entry *q = qup->qe;
- fprintf(fd, "%s (version %d):\n",
- qup->fsname, (qup->flags & QUOTA2) ? 2 : 1);
- if ((qup->flags & DEFAULT) == 0 || (qup->flags & QUOTA2) != 0) {
- fprintf(fd, "\tblocks in use: %s, "
- "limits (soft = %s, hard = %s",
- intprt(b1, 21, q[QL_BLK].ufsqe_cur,
- HN_NOSPACE | HN_B, Hflag),
- intprt(b2, 21, q[QL_BLK].ufsqe_softlimit,
+
+ for ( ; argc > 0; argc--, argv++) {
+ if ((id = getentry(*argv, quotaclass)) == -1)
+ continue;
+ data = prop_dictionary_create();
+ if (data == NULL)
+ errx(1, "can't allocate proplist");
+
+ ret = prop_dictionary_set_uint32(data, "id", id);
+ if (!ret)
+ err(1, "prop_dictionary_set(id)");
+ if (!prop_array_add_and_rel(datas, data))
+ err(1, "prop_array_add(data)");
+ }
+ if (!quota_prop_add_command(cmds, "clear",
+ ufs_quota_class_names[quotaclass], datas))
+ err(1, "prop_add_command");
+
+ if (!prop_dictionary_set(protodict, "commands", cmds))
+ err(1, "prop_dictionary_set(command)");
+
+ /* now loop over quota-enabled filesystems */
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst == 0)
+ errx(1, "no filesystems mounted!");
+
+ for (i = 0; i < nfst; i++) {
+ if ((fst[i].f_flag & ST_QUOTA) == 0)
+ continue;
+ if (filesys && strcmp(fst[i].f_mntonname, filesys) != 0 &&
+ strcmp(fst[i].f_mntfromname, filesys) != 0)
+ continue;
+ if (Dflag) {
+ fprintf(stderr, "message to kernel for %s:\n%s\n",
+ fst[i].f_mntonname,
+ prop_dictionary_externalize(protodict));
+ }
+
+ if (!prop_dictionary_send_syscall(protodict, &pref))
+ err(1, "prop_dictionary_send_syscall");
+ if (quotactl(fst[i].f_mntonname, &pref) != 0)
+ err(1, "quotactl");
+
+ if ((errno = prop_dictionary_recv_syscall(&pref, &dict)) != 0) {
+ err(1, "prop_dictionary_recv_syscall");
+ }
+
+ if (Dflag) {
+ fprintf(stderr, "reply from kernel for %s:\n%s\n",
+ fst[i].f_mntonname,
+ prop_dictionary_externalize(dict));
+ }
+ if ((errno = quota_get_cmds(dict, &cmds)) != 0) {
+ err(1, "quota_get_cmds");
+ }
+ /* only one command, no need to iter */
+ cmd = prop_array_get(cmds, 0);
+ if (cmd == NULL)
+ err(1, "prop_array_get(cmd)");
+
+ if (!prop_dictionary_get_int8(cmd, "return", &error8))
+ err(1, "prop_get(return)");
+ if (error8) {
+ errno = error8;
+ warn("clear %s quota entries on %s",
+ ufs_quota_class_names[quotaclass],
+ fst[i].f_mntonname);
+ }
+ prop_object_release(dict);
+ }
+ prop_object_release(protodict);
+}
+
+////////////////////////////////////////////////////////////
+// editor
+
+/*
+ * Take a list of privileges and get it edited.
+ */
+static int
+editit(const char *ltmpfile)
+{
+ pid_t pid;
+ int lst;
+ char p[MAX_TMPSTR];
+ const char *ed;
+ sigset_t s, os;
+
+ sigemptyset(&s);
+ sigaddset(&s, SIGINT);
+ sigaddset(&s, SIGQUIT);
+ sigaddset(&s, SIGHUP);
+ if (sigprocmask(SIG_BLOCK, &s, &os) == -1)
+ err(1, "sigprocmask");
+top:
+ switch ((pid = fork())) {
+ case -1:
+ if (errno == EPROCLIM) {
+ warnx("You have too many processes");
+ return 0;
+ }
+ if (errno == EAGAIN) {
+ sleep(1);
+ goto top;
+ }
+ warn("fork");
+ return 0;
+ case 0:
+ if (sigprocmask(SIG_SETMASK, &os, NULL) == -1)
+ err(1, "sigprocmask");
+ setgid(getgid());
+ setuid(getuid());
+ if ((ed = getenv("EDITOR")) == (char *)0)
+ ed = _PATH_VI;
+ if (strlen(ed) + strlen(ltmpfile) + 2 >= MAX_TMPSTR) {
+ errx(1, "%s", "editor or filename too long");
+ }
+ snprintf(p, sizeof(p), "%s %s", ed, ltmpfile);
+ execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", p, NULL);
+ err(1, "%s", ed);
+ default:
+ if (waitpid(pid, &lst, 0) == -1)
+ err(1, "waitpid");
+ if (sigprocmask(SIG_SETMASK, &os, NULL) == -1)
+ err(1, "sigprocmask");
+ if (!WIFEXITED(lst) || WEXITSTATUS(lst) != 0)
+ return 0;
+ return 1;
+ }
+}
+
+/*
+ * Convert a quotause list to an ASCII file.
+ */
+static int
+writeprivs(struct quotause *quplist, int outfd, const char *name,
+ int quotaclass)
+{
+ struct quotause *qup;
+ FILE *fd;
+ char b0[32], b1[32], b2[32], b3[32];
+
+ (void)ftruncate(outfd, 0);
+ (void)lseek(outfd, (off_t)0, SEEK_SET);
+ if ((fd = fdopen(dup(outfd), "w")) == NULL)
+ errx(1, "fdopen `%s'", tmpfil);
+ if (dflag) {
+ fprintf(fd, "Default %s quotas:\n",
+ ufs_quota_class_names[quotaclass]);
+ } else {
+ fprintf(fd, "Quotas for %s %s:\n",
+ ufs_quota_class_names[quotaclass], name);
+ }
+ for (qup = quplist; qup; qup = qup->next) {
+ struct ufs_quota_entry *q = qup->qe;
+ fprintf(fd, "%s (version %d):\n",
+ qup->fsname, (qup->flags & QUOTA2) ? 2 : 1);
+ if ((qup->flags & DEFAULT) == 0 || (qup->flags & QUOTA2) != 0) {
+ fprintf(fd, "\tblocks in use: %s, "
+ "limits (soft = %s, hard = %s",
+ intprt(b1, 21, q[QL_BLK].ufsqe_cur,
+ HN_NOSPACE | HN_B, Hflag),
+ intprt(b2, 21, q[QL_BLK].ufsqe_softlimit,
HN_NOSPACE | HN_B, Hflag),
intprt(b3, 21, q[QL_BLK].ufsqe_hardlimit,
HN_NOSPACE | HN_B, Hflag));
@@ -998,118 +909,228 @@
return 1;
}
-/*
- * Free a quotause structure.
- */
-static void
-freeq(struct quotause *qup)
-{
- free(qup->qfname);
- free(qup);
-}
+////////////////////////////////////////////////////////////
+// main
-/*
- * Free a list of quotause structures.
- */
static void
-freeprivs(struct quotause *quplist)
+usage(void)
{
- struct quotause *qup, *nextqup;
-
- for (qup = quplist; qup; qup = nextqup) {
- nextqup = qup->next;
- freeq(qup);
- }
+ const char *p = getprogname();
+ fprintf(stderr,
+ "Usage: %s [-D] [-H] [-u] [-p <username>] [-f <filesystem>] "
+ "-d | <username> ...\n"
+ "\t%s [-D] [-H] -g [-p <groupname>] [-f <filesystem>] "
+ "-d | <groupname> ...\n"
+ "\t%s [-D] [-u] [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] "
+ "-d | <username> ...\n"
+ "\t%s [-D] -g [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] "
+ "-d | <groupname> ...\n"
+ "\t%s [-D] [-H] [-u] -c [-f <filesystem>] username ...\n"
+ "\t%s [-D] [-H] -g -c [-f <filesystem>] groupname ...\n",
+ p, p, p, p, p, p);
+ exit(1);
}
-static void
-clearpriv(int argc, char **argv, const char *filesys, int quotaclass)
+int
+main(int argc, char *argv[])
{
- prop_array_t cmds, datas;
- prop_dictionary_t protodict, dict, data, cmd;
- struct plistref pref;
- bool ret;
- struct statvfs *fst;
- int nfst, i;
- int8_t error8;
- int id;
+ struct quotause *qup, *protoprivs, *curprivs;
+ long id, protoid;
+ int quotaclass, tmpfd;
+ char *protoname;
+ char *soft = NULL, *hard = NULL, *grace = NULL;
+ char *fs = NULL;
+ int ch;
+ int pflag = 0;
+ int cflag = 0;
- /* build a generic command */
- protodict = quota_prop_create();
- cmds = prop_array_create();
- datas = prop_array_create();
- if (protodict == NULL || cmds == NULL || datas == NULL) {
- errx(1, "can't allocate proplist");
+ if (argc < 2)
+ usage();
+ if (getuid())
+ errx(1, "permission denied");
+ protoname = NULL;
+ quotaclass = QUOTA_CLASS_USER;
+ while ((ch = getopt(argc, argv, "DHcdugp:s:h:t:f:")) != -1) {
+ switch(ch) {
+ case 'D':
+ Dflag++;
+ break;
+ case 'H':
+ Hflag++;
+ break;
+ case 'c':
+ cflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'p':
+ protoname = optarg;
+ pflag++;
+ break;
+ case 'g':
+ quotaclass = QUOTA_CLASS_GROUP;
+ break;
+ case 'u':
+ quotaclass = QUOTA_CLASS_USER;
+ break;
+ case 's':
+ soft = optarg;
+ break;
+ case 'h':
+ hard = optarg;
+ break;
+ case 't':
+ grace = optarg;
+ break;
+ case 'f':
+ fs = optarg;
+ break;
+ default:
+ usage();
+ }
}
+ argc -= optind;
+ argv += optind;
- for ( ; argc > 0; argc--, argv++) {
- if ((id = getentry(*argv, quotaclass)) == -1)
- continue;
- data = prop_dictionary_create();
- if (data == NULL)
- errx(1, "can't allocate proplist");
-
- ret = prop_dictionary_set_uint32(data, "id", id);
- if (!ret)
- err(1, "prop_dictionary_set(id)");
- if (!prop_array_add_and_rel(datas, data))
- err(1, "prop_array_add(data)");
+ if (pflag) {
+ if (soft || hard || grace || dflag || cflag)
+ usage();
+ if ((protoid = getentry(protoname, quotaclass)) == -1)
+ return 1;
+ protoprivs = getprivs(protoid, quotaclass, fs, 0);
+ for (qup = protoprivs; qup; qup = qup->next) {
+ qup->qe[QL_BLK].ufsqe_time = 0;
+ qup->qe[QL_FL].ufsqe_time = 0;
+ }
+ while (argc-- > 0) {
+ if ((id = getentry(*argv++, quotaclass)) < 0)
+ continue;
+ putprivs(id, quotaclass, protoprivs);
+ }
+ return 0;
}
- if (!quota_prop_add_command(cmds, "clear",
- ufs_quota_class_names[quotaclass], datas))
- err(1, "prop_add_command");
-
- if (!prop_dictionary_set(protodict, "commands", cmds))
- err(1, "prop_dictionary_set(command)");
-
- /* now loop over quota-enabled filesystems */
- nfst = getmntinfo(&fst, MNT_WAIT);
- if (nfst == 0)
- errx(1, "no filesystems mounted!");
+ if (soft || hard || grace) {
+ struct quotause *lqup;
+ u_int64_t softb, hardb, softi, hardi;
+ time_t graceb, gracei;
+ char *str;
- for (i = 0; i < nfst; i++) {
- if ((fst[i].f_flag & ST_QUOTA) == 0)
- continue;
- if (filesys && strcmp(fst[i].f_mntonname, filesys) != 0 &&
- strcmp(fst[i].f_mntfromname, filesys) != 0)
- continue;
- if (Dflag) {
- fprintf(stderr, "message to kernel for %s:\n%s\n",
- fst[i].f_mntonname,
- prop_dictionary_externalize(protodict));
+ if (cflag)
+ usage();
+ if (soft) {
+ str = strsep(&soft, "/");
+ if (str[0] == '\0' || soft == NULL || soft[0] == '\0')
+ usage();
+
+ if (intrd(str, &softb, HN_B) != 0)
+ errx(1, "%s: bad number", str);
+ if (intrd(soft, &softi, 0) != 0)
+ errx(1, "%s: bad number", soft);
}
-
- if (!prop_dictionary_send_syscall(protodict, &pref))
- err(1, "prop_dictionary_send_syscall");
- if (quotactl(fst[i].f_mntonname, &pref) != 0)
- err(1, "quotactl");
-
- if ((errno = prop_dictionary_recv_syscall(&pref, &dict)) != 0) {
- err(1, "prop_dictionary_recv_syscall");
+ if (hard) {
+ str = strsep(&hard, "/");
+ if (str[0] == '\0' || hard == NULL || hard[0] == '\0')
+ usage();
+
+ if (intrd(str, &hardb, HN_B) != 0)
+ errx(1, "%s: bad number", str);
+ if (intrd(hard, &hardi, 0) != 0)
+ errx(1, "%s: bad number", hard);
}
-
- if (Dflag) {
- fprintf(stderr, "reply from kernel for %s:\n%s\n",
- fst[i].f_mntonname,
- prop_dictionary_externalize(dict));
+ if (grace) {
+ str = strsep(&grace, "/");
+ if (str[0] == '\0' || grace == NULL || grace[0] == '\0')
+ usage();
+
+ if (timeprd(str, &graceb) != 0)
+ errx(1, "%s: bad number", str);
+ if (timeprd(grace, &gracei) != 0)
+ errx(1, "%s: bad number", grace);
}
- if ((errno = quota_get_cmds(dict, &cmds)) != 0) {
- err(1, "quota_get_cmds");
+ if (dflag) {
+ curprivs = getprivs(0, quotaclass, fs, 1);
+ for (lqup = curprivs; lqup; lqup = lqup->next) {
+ struct ufs_quota_entry *q = lqup->qe;
+ if (soft) {
+ q[QL_BLK].ufsqe_softlimit = softb;
+ q[QL_FL].ufsqe_softlimit = softi;
+ }
+ if (hard) {
+ q[QL_BLK].ufsqe_hardlimit = hardb;
+ q[QL_FL].ufsqe_hardlimit = hardi;
+ }
+ if (grace) {
+ q[QL_BLK].ufsqe_grace = graceb;
+ q[QL_FL].ufsqe_grace = gracei;
+ }
+ }
+ putprivs(0, quotaclass, curprivs);
+ freeprivs(curprivs);
+ return 0;
}
- /* only one command, no need to iter */
- cmd = prop_array_get(cmds, 0);
- if (cmd == NULL)
- err(1, "prop_array_get(cmd)");
-
- if (!prop_dictionary_get_int8(cmd, "return", &error8))
- err(1, "prop_get(return)");
- if (error8) {
- errno = error8;
- warn("clear %s quota entries on %s",
- ufs_quota_class_names[quotaclass],
- fst[i].f_mntonname);
+ for ( ; argc > 0; argc--, argv++) {
+ if ((id = getentry(*argv, quotaclass)) == -1)
+ continue;
+ curprivs = getprivs(id, quotaclass, fs, 0);
+ for (lqup = curprivs; lqup; lqup = lqup->next) {
+ struct ufs_quota_entry *q = lqup->qe;
+ if (soft) {
+ if (softb &&
+ q[QL_BLK].ufsqe_cur >= softb &&
+ (q[QL_BLK].ufsqe_softlimit == 0 ||
+ q[QL_BLK].ufsqe_cur <
+ q[QL_BLK].ufsqe_softlimit))
+ q[QL_BLK].ufsqe_time = 0;
+ if (softi &&
+ q[QL_FL].ufsqe_cur >= softb &&
+ (q[QL_FL].ufsqe_softlimit == 0 ||
+ q[QL_FL].ufsqe_cur <
+ q[QL_FL].ufsqe_softlimit))
+ q[QL_FL].ufsqe_time = 0;
+ q[QL_BLK].ufsqe_softlimit = softb;
+ q[QL_FL].ufsqe_softlimit = softi;
+ }
+ if (hard) {
+ q[QL_BLK].ufsqe_hardlimit = hardb;
+ q[QL_FL].ufsqe_hardlimit = hardi;
+ }
+ if (grace) {
+ q[QL_BLK].ufsqe_grace = graceb;
+ q[QL_FL].ufsqe_grace = gracei;
+ }
+ }
+ putprivs(id, quotaclass, curprivs);
+ freeprivs(curprivs);
}
- prop_object_release(dict);
+ return 0;
}
- prop_object_release(protodict);
+ if (cflag) {
+ if (dflag)
+ usage();
+ clearpriv(argc, argv, fs, quotaclass);
+ return 0;
+ }
+ tmpfd = mkstemp(tmpfil);
+ fchown(tmpfd, getuid(), getgid());
+ if (dflag) {
+ curprivs = getprivs(0, quotaclass, fs, 1);
+ if (writeprivs(curprivs, tmpfd, NULL, quotaclass) &&
+ editit(tmpfil) && readprivs(curprivs, tmpfd))
+ putprivs(0, quotaclass, curprivs);
+ freeprivs(curprivs);
+ }
+ for ( ; argc > 0; argc--, argv++) {
+ if ((id = getentry(*argv, quotaclass)) == -1)
+ continue;
+ curprivs = getprivs(id, quotaclass, fs, 0);
+ if (writeprivs(curprivs, tmpfd, *argv, quotaclass) == 0)
+ continue;
+ if (editit(tmpfil) && readprivs(curprivs, tmpfd))
+ putprivs(id, quotaclass, curprivs);
+ freeprivs(curprivs);
+ }
+ close(tmpfd);
+ unlink(tmpfil);
+ return 0;
}