Subject: edquota enhancements
To: None <tech-userlevel@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: tech-userlevel
Date: 12/02/2002 21:53:01
--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,
I'd like to commit the attached patch to edquota. It adds:
- a -f flag, to restrict operations on only one filesystem, instead of
  all quota-enabled filesystems.
- -s and -h flags, to set limits from the command line without edition
  of a temporary file. Would make it easier to call edquota from scripts.

Comments ?

-- 
Manuel Bouyer <bouyer@antioche.eu.org>
     NetBSD: 23 ans d'experience feront toujours la difference
--

--X1bOJ3K7DJ5YkBrT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff

? .gdbinit
? edquota
? edquota.cat8
Index: edquota.8
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/edquota/edquota.8,v
retrieving revision 1.8
diff -u -r1.8 edquota.8
--- edquota.8	2002/01/19 03:11:34	1.8
+++ edquota.8	2002/12/02 20:48:38
@@ -45,15 +45,31 @@
 .Nm
 .Op Fl u
 .Op Fl p Ar proto-username
+.Op Fl f Ar filesystem
 .Ar username ...
 .Nm ""
 .Fl g
 .Op Fl p Ar proto-groupname
+.Op Fl f Ar filesystem
 .Ar groupname ...
 .Nm ""
+.Op Fl u
+.Op Fl s Ar block#/inode#
+.Op Fl h Ar block#/inode#
+.Op Fl f Ar filesystem
+.Ar username ...
+.Nm ""
+.Fl g
+.Op Fl s Ar block#/inode#
+.Op Fl h Ar block#/inode#
+.Op Fl f Ar filesystem
+.Ar groupname ...
+.Nm ""
+.Op Fl f Ar filesystem
 .Fl t
 .Op Fl u
 .Nm ""
+.Op Fl f Ar filesystem
 .Fl t
 .Fl g
 .Sh DESCRIPTION
@@ -63,11 +79,17 @@
 .Fl u
 flag is specified,
 one or more users may be specified on the command line.
-For each user a temporary file is created
-with an ASCII representation of the current
-disk quotas for that user.
+Unless
+.Fl s
+or
+.Fl h
+is used, a temporary file is created for each user with an ASCII
+representation of the current disk quotas for that user.
 The list of filesystems with user quotas is determined from
 .Pa /etc/fstab .
+By default, quota for all quota-enabled filesystems are edited; the
+.Fl f
+option can be used to restrict it to a single filesystem.
 An editor is invoked on the ASCII file.
 The editor invoked is
 .Xr vi 1
@@ -100,6 +122,14 @@
 specified for each user specified.
 This is the normal mechanism used to
 initialize quotas for groups of users.
+.Pp
+The
+.Fl s
+and
+.Fl h
+flags can be used to change quota limits (soft and hard, respectively)
+without user interaction, for usage in e.g. batch scripts. The argument is
+the new block and inode number limit, separated by a slash.
 .Pp
 If the
 .Fl g
Index: edquota.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/edquota/edquota.c,v
retrieving revision 1.21
diff -u -r1.21 edquota.c
--- edquota.c	2000/04/14 06:26:53	1.21
+++ edquota.c	2002/12/02 20:48:41
@@ -88,7 +88,7 @@
 void	usage __P((void));
 int	getentry __P((char *, int));
 struct quotause *
-	getprivs __P((long, int));
+	getprivs __P((long, int, char *));
 void	putprivs __P((long, int, struct quotause *));
 int	editit __P((char *));
 int	writeprivs __P((struct quotause *, int, char *, int));
@@ -110,6 +110,8 @@
 	long id, protoid;
 	int quotatype, tmpfd;
 	char *protoname;
+	char *soft = NULL, *hard = NULL;
+	char *fs = NULL;
 	int ch;
 	int tflag = 0, pflag = 0;
 
@@ -119,7 +121,7 @@
 		errx(1, "permission denied");
 	protoname = NULL;
 	quotatype = USRQUOTA;
-	while ((ch = getopt(argc, argv, "ugtp:")) != -1) {
+	while ((ch = getopt(argc, argv, "ugtp:s:h:f:")) != -1) {
 		switch(ch) {
 		case 'p':
 			protoname = optarg;
@@ -134,6 +136,15 @@
 		case 't':
 			tflag++;
 			break;
+		case 's':
+			soft = optarg;
+			break;
+		case 'h':
+			hard = optarg;
+			break;
+		case 'f':
+			fs = optarg;
+			break;
 		default:
 			usage();
 		}
@@ -141,9 +152,11 @@
 	argc -= optind;
 	argv += optind;
 	if (pflag) {
+		if (soft || hard)
+			usage();
 		if ((protoid = getentry(protoname, quotatype)) == -1)
 			exit(1);
-		protoprivs = getprivs(protoid, quotatype);
+		protoprivs = getprivs(protoid, quotatype, fs);
 		for (qup = protoprivs; qup; qup = qup->next) {
 			qup->dqblk.dqb_btime = 0;
 			qup->dqblk.dqb_itime = 0;
@@ -155,10 +168,58 @@
 		}
 		exit(0);
 	}
+	if (soft || hard) {
+		struct quotause *qup;
+		u_int32_t softb, hardb, softi, hardi;
+		if (tflag)
+			usage();
+		if (soft) {
+			if (sscanf(soft, "%d/%d", &softb, &softi) != 2)
+				usage();
+			softb = btodb((u_quad_t)softb * 1024);
+		}
+		if (hard) {
+			if (sscanf(hard, "%d/%d", &hardb, &hardi) != 2)
+				usage();
+			hardb = btodb((u_quad_t)hardb * 1024);
+		}
+		for ( ; argc > 0; argc--, argv++) {
+			if ((id = getentry(*argv, quotatype)) == -1)
+				continue;
+			curprivs = getprivs(id, quotatype, fs);
+			for (qup = curprivs; qup; qup = qup->next) {
+				if (soft) {
+					if (softb &&
+					    qup->dqblk.dqb_curblocks >= softb &&
+					    (qup->dqblk.dqb_bsoftlimit == 0 ||
+					    qup->dqblk.dqb_curblocks <
+					    qup->dqblk.dqb_bsoftlimit))
+						qup->dqblk.dqb_btime = 0;
+					if (softi &&
+					    qup->dqblk.dqb_curinodes >= softi &&
+					    (qup->dqblk.dqb_isoftlimit == 0 ||
+					    qup->dqblk.dqb_curinodes <
+					    qup->dqblk.dqb_isoftlimit))
+						qup->dqblk.dqb_itime = 0;
+					qup->dqblk.dqb_bsoftlimit = softb;
+					qup->dqblk.dqb_isoftlimit = softi;
+				}
+				if (hard) {
+					qup->dqblk.dqb_bhardlimit = hardb;
+					qup->dqblk.dqb_ihardlimit = hardi;
+				}
+			}
+			putprivs(id, quotatype, curprivs);
+			freeprivs(curprivs);
+		}
+		exit(0);
+	}
 	tmpfd = mkstemp(tmpfil);
 	fchown(tmpfd, getuid(), getgid());
 	if (tflag) {
-		protoprivs = getprivs(0, quotatype);
+		if (soft || hard)
+			usage();
+		protoprivs = getprivs(0, quotatype, fs);
 		if (writetimes(protoprivs, tmpfd, quotatype) == 0)
 			exit(1);
 		if (editit(tmpfil) && readtimes(protoprivs, tmpfd))
@@ -169,7 +230,7 @@
 	for ( ; argc > 0; argc--, argv++) {
 		if ((id = getentry(*argv, quotatype)) == -1)
 			continue;
-		curprivs = getprivs(id, quotatype);
+		curprivs = getprivs(id, quotatype, fs);
 		if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0)
 			continue;
 		if (editit(tmpfil) && readprivs(curprivs, tmpfd))
@@ -184,10 +245,14 @@
 void
 usage()
 {
-	fprintf(stderr, "%s%s%s%s",
-		"Usage: edquota [-u] [-p username] username ...\n",
-		"\tedquota -g [-p groupname] groupname ...\n",
-		"\tedquota [-u] -t\n", "\tedquota -g -t\n");
+	fprintf(stderr,
+	    "Usage: edquota [-u] [-p username] [-f filesystem] username ...\n"
+	    "\tedquota -g [-p groupname] [-f filesystem] groupname ...\n"
+	    "\tedquota [-u] [-f filesystem] [-s b#/i#] [-h b#/i#] username ...\n"
+	    "\tedquota -g [-f filesystem] [-s b#/i#] [-h b#/i#] groupname ...\n"
+	    "\tedquota [-u] [-f filesystem] -t\n"
+	    "\tedquota -g [-f filesystem] -t\n"
+	    );
 	exit(1);
 }
 
@@ -229,9 +294,10 @@
  * Collect the requested quota information.
  */
 struct quotause *
-getprivs(id, quotatype)
+getprivs(id, quotatype, filesys)
 	long id;
 	int quotatype;
+	char *filesys;
 {
 	struct fstab *fs;
 	struct quotause *qup, *quptail;
@@ -246,6 +312,9 @@
 	qcmd = QCMD(Q_GETQUOTA, quotatype);
 	while ((fs = getfsent()) != NULL) {
 		if (strcmp(fs->fs_vfstype, "ffs"))
+			continue;
+		if (filesys && strcmp(fs->fs_spec, filesys) != 0 &&
+		    strcmp(fs->fs_file, filesys) != 0)
 			continue;
 		if (!hasquota(fs, quotatype, &qfpathname))
 			continue;

--X1bOJ3K7DJ5YkBrT--