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;
 }

Reply via email to