Module Name:    src
Committed By:   bouyer
Date:           Sun Jan 30 19:38:46 UTC 2011

Modified Files:
        src/sys/ufs/ufs [bouyer-quota2]: ufs_quota.c
        src/usr.bin/quota [bouyer-quota2]: getvfsquota.c getvfsquota.h
            printquota.c printquota.h quota.c
        src/usr.sbin/edquota [bouyer-quota2]: edquota.c
        src/usr.sbin/repquota [bouyer-quota2]: repquota.c

Log Message:
Implement "get version" quotactl command, which return the filesystem's
enabled quota versiob (1 for legacy, 2 for new).
For quota2, make quota and repquota print the user's allowed grace period
if -v is given and not overquota (if overquota, the remaining time is
printed instead, as usual).


To generate a diff of this commit:
cvs rdiff -u -r1.68.4.4 -r1.68.4.5 src/sys/ufs/ufs/ufs_quota.c
cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/usr.bin/quota/getvfsquota.c \
    src/usr.bin/quota/getvfsquota.h
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 src/usr.bin/quota/printquota.c \
    src/usr.bin/quota/printquota.h
cvs rdiff -u -r1.33.2.3 -r1.33.2.4 src/usr.bin/quota/quota.c
cvs rdiff -u -r1.29.16.2 -r1.29.16.3 src/usr.sbin/edquota/edquota.c
cvs rdiff -u -r1.25.2.2 -r1.25.2.3 src/usr.sbin/repquota/repquota.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/ufs/ufs/ufs_quota.c
diff -u src/sys/ufs/ufs/ufs_quota.c:1.68.4.4 src/sys/ufs/ufs/ufs_quota.c:1.68.4.5
--- src/sys/ufs/ufs/ufs_quota.c:1.68.4.4	Sun Jan 30 00:25:19 2011
+++ src/sys/ufs/ufs/ufs_quota.c	Sun Jan 30 19:38:46 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_quota.c,v 1.68.4.4 2011/01/30 00:25:19 bouyer Exp $	*/
+/*	$NetBSD: ufs_quota.c,v 1.68.4.5 2011/01/30 19:38:46 bouyer Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1990, 1993, 1995
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.68.4.4 2011/01/30 00:25:19 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.68.4.5 2011/01/30 19:38:46 bouyer Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -60,6 +60,8 @@
 kmutex_t dqlock;
 kcondvar_t dqcv;
 
+static int quota_handle_cmd_get_version(struct mount *, struct lwp *,
+    prop_dictionary_t, prop_array_t);
 static int quota_handle_cmd_get(struct mount *, struct lwp *,
     prop_dictionary_t, int, prop_array_t);
 static int quota_handle_cmd_set(struct mount *, struct lwp *,
@@ -151,6 +153,10 @@
 	prop_object_retain(datas);
 	prop_dictionary_remove(cmddict, "data"); /* prepare for return */
 
+	if (strcmp(cmd, "get version") == 0) {
+		error = quota_handle_cmd_get_version(mp, l, cmddict, datas);
+		goto end;
+	}
 	if (strcmp(cmd, "get") == 0) {
 		error = quota_handle_cmd_get(mp, l, cmddict, q2type, datas);
 		goto end;
@@ -171,6 +177,52 @@
 	return error;
 }
 
+static int 
+quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, 
+    prop_dictionary_t cmddict, prop_array_t datas)
+{
+	struct ufsmount *ump = VFSTOUFS(mp);
+	prop_array_t replies;
+	prop_dictionary_t data;
+	int error = 0;
+
+	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
+		return EOPNOTSUPP;
+
+	replies = prop_array_create();
+	if (replies == NULL)
+		return ENOMEM;
+
+	data = prop_dictionary_create();
+	if (data == NULL) {
+		prop_object_release(replies);
+		return ENOMEM;
+	}
+
+#ifdef QUOTA
+	if (ump->um_flags & UFS_QUOTA) {
+		if (!prop_dictionary_set_int8(data, "version", 1))
+			error = ENOMEM;
+	} else
+#endif
+#ifdef QUOTA2
+	if (ump->um_flags & UFS_QUOTA2) {
+		if (!prop_dictionary_set_int8(data, "version", 2))
+			error = ENOMEM;
+	} else
+#endif
+		error = 0;
+	if (error)
+		prop_object_release(data);
+	else if (!prop_array_add_and_rel(replies, data))
+		error = ENOMEM;
+	if (error)
+		prop_object_release(replies);
+	else if (!prop_dictionary_set_and_rel(cmddict, "data", replies))
+		error = ENOMEM;
+	return error;
+}
+
 /* XXX shouldn't all this be in kauth ? */
 static int
 quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {

Index: src/usr.bin/quota/getvfsquota.c
diff -u src/usr.bin/quota/getvfsquota.c:1.1.2.1 src/usr.bin/quota/getvfsquota.c:1.1.2.2
--- src/usr.bin/quota/getvfsquota.c:1.1.2.1	Fri Jan 28 22:15:36 2011
+++ src/usr.bin/quota/getvfsquota.c	Sun Jan 30 19:38:45 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: getvfsquota.c,v 1.1.2.1 2011/01/28 22:15:36 bouyer Exp $ */
+/*	$NetBSD: getvfsquota.c,v 1.1.2.2 2011/01/30 19:38:45 bouyer Exp $ */
 
 /*-
   * Copyright (c) 2011 Manuel Bouyer
@@ -29,7 +29,7 @@
   */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: getvfsquota.c,v 1.1.2.1 2011/01/28 22:15:36 bouyer Exp $");
+__RCSID("$NetBSD: getvfsquota.c,v 1.1.2.2 2011/01/30 19:38:45 bouyer Exp $");
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -48,15 +48,17 @@
 
 /* retrieve quotas from vfs, for the given user id */
 int
-getvfsquota(const char *mp, struct quota2_entry *q2e, long id, int type,
-    int defaultq, int debug)
+getvfsquota(const char *mp, struct quota2_entry *q2e, int8_t *versp,
+    long id, int type, int defaultq, int debug)
 {
 	prop_dictionary_t dict, data, cmd;
 	prop_array_t cmds, datas;
+	prop_object_iterator_t iter;
 	struct plistref pref;
 	int error;
 	int8_t error8;
 	bool ret;
+	int retval = 0;
 
 	dict = quota2_prop_create();
 	cmds = prop_array_create();
@@ -78,6 +80,9 @@
 	prop_object_release(data);
 	if (!quota2_prop_add_command(cmds, "get", qfextension[type], datas))
 		err(1, "prop_add_command");
+	if (!quota2_prop_add_command(cmds, "get version", qfextension[type],
+	    prop_array_create()))
+		err(1, "prop_add_command");
 	if (!prop_dictionary_set(dict, "commands", cmds))
 		err(1, "prop_dictionary_set(command)");
 	if (debug)
@@ -102,46 +107,64 @@
 		errx(1, "quota2_get_cmds: %s\n",
 		    strerror(error));
 	}
-	/* 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) {
-		if (error8 != ENOENT && error8 != ENODEV) {
-			if (defaultq)
-				fprintf(stderr, "get default %s quota: %s\n",
-				    qfextension[type], strerror(error8));
-			else 
-				fprintf(stderr, "get %s quota for %ld: %s\n",
-				    qfextension[type], id, strerror(error8));
+	iter = prop_array_iterator(cmds);
+	if (iter == NULL)
+		err(1, "prop_array_iterator(cmds)");
+
+	while ((cmd = prop_object_iterator_next(iter)) != NULL) {
+		const char *cmdstr;
+		if (!prop_dictionary_get_cstring_nocopy(cmd, "command",
+		    &cmdstr))
+			err(1, "prop_get(command)");
+		if (!prop_dictionary_get_int8(cmd, "return", &error8))
+			err(1, "prop_get(return)");
+
+		if (error8) {
+			if (error8 != ENOENT && error8 != ENODEV) {
+				if (defaultq) {
+					fprintf(stderr,
+					    "get default %s quota: %s\n",
+					    qfextension[type],
+					    strerror(error8));
+				} else {
+					fprintf(stderr,
+					    "get %s quota for %ld: %s\n",
+					    qfextension[type], id,
+					    strerror(error8));
+				}
+			}
+			prop_object_release(dict);
+			return (0);
+		}
+		datas = prop_dictionary_get(cmd, "data");
+		if (datas == NULL)
+			err(1, "prop_dict_get(datas)");
+
+		if (strcmp("get version", cmdstr) == 0) {
+			data = prop_array_get(datas, 0);
+			if (data == NULL)
+				err(1, "prop_array_get(version)");
+			if (!prop_dictionary_get_int8(data, "version", versp))
+				err(1, "prop_get_int8(version)");
+			continue;
+		}
+		if (strcmp("get", cmdstr) != 0)
+			err(1, "unknown command %s in reply", cmdstr);
+				
+		/* only one data, no need to iter */
+		if (prop_array_count(datas) > 0) {
+			data = prop_array_get(datas, 0);
+			if (data == NULL)
+				err(1, "prop_array_get(data)");
+
+			error = quota2_dict_get_q2e_usage(data, q2e);
+			if (error) {
+				errx(1, "quota2_dict_get_q2e_usage: %s\n",
+				    strerror(error));
+			}
+			retval = 1;
 		}
-		prop_object_release(dict);
-		return (0);
-	}
-	datas = prop_dictionary_get(cmd, "data");
-	if (datas == NULL)
-		err(1, "prop_dict_get(datas)");
-
-	/* only one data, no need to iter */
-	if (prop_array_count(datas) == 0) {
-		/* no quota for this user/group */
-		prop_object_release(dict);
-		return (0);
-	}
-	
-	data = prop_array_get(datas, 0);
-	if (data == NULL)
-		err(1, "prop_array_get(data)");
-
-	error = quota2_dict_get_q2e_usage(data, q2e);
-	if (error) {
-		errx(1, "quota2_dict_get_q2e_usage: %s\n",
-		    strerror(error));
 	}
 	prop_object_release(dict);
-	return (1);
+	return retval;
 }
Index: src/usr.bin/quota/getvfsquota.h
diff -u src/usr.bin/quota/getvfsquota.h:1.1.2.1 src/usr.bin/quota/getvfsquota.h:1.1.2.2
--- src/usr.bin/quota/getvfsquota.h:1.1.2.1	Fri Jan 28 22:15:36 2011
+++ src/usr.bin/quota/getvfsquota.h	Sun Jan 30 19:38:45 2011
@@ -1,5 +1,6 @@
-/*	$NetBSD: getvfsquota.h,v 1.1.2.1 2011/01/28 22:15:36 bouyer Exp $ */
+/*	$NetBSD: getvfsquota.h,v 1.1.2.2 2011/01/30 19:38:45 bouyer Exp $ */
 
-int getvfsquota(const char *, struct quota2_entry *, long, int, int, int);
+int getvfsquota(const char *, struct quota2_entry *, int8_t *,
+    long, int, int, int);
 
 extern const char *qfextension[];

Index: src/usr.bin/quota/printquota.c
diff -u src/usr.bin/quota/printquota.c:1.1.2.3 src/usr.bin/quota/printquota.c:1.1.2.4
--- src/usr.bin/quota/printquota.c:1.1.2.3	Sun Jan 30 00:21:08 2011
+++ src/usr.bin/quota/printquota.c	Sun Jan 30 19:38:45 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: printquota.c,v 1.1.2.3 2011/01/30 00:21:08 bouyer Exp $ */
+/*	$NetBSD: printquota.c,v 1.1.2.4 2011/01/30 19:38:45 bouyer Exp $ */
 
 /*
  * Copyright (c) 1980, 1990, 1993
@@ -42,7 +42,7 @@
 #if 0
 static char sccsid[] = "@(#)quota.c	8.4 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: printquota.c,v 1.1.2.3 2011/01/30 00:21:08 bouyer Exp $");
+__RCSID("$NetBSD: printquota.c,v 1.1.2.4 2011/01/30 19:38:45 bouyer Exp $");
 #endif
 #endif /* not lint */
 
@@ -100,14 +100,11 @@
  * Calculate the grace period and return a printable string for it.
  */
 const char *
-timeprt(time_t seconds)
+timeprt(time_t now, time_t seconds)
 {
 	time_t hours, minutes;
 	static char buf[20];
-	static time_t now;
 
-	if (now == 0)
-		time(&now);
 	if (now > seconds)
 		return ("none");
 	seconds -= now;
Index: src/usr.bin/quota/printquota.h
diff -u src/usr.bin/quota/printquota.h:1.1.2.3 src/usr.bin/quota/printquota.h:1.1.2.4
--- src/usr.bin/quota/printquota.h:1.1.2.3	Sat Jan 29 17:42:37 2011
+++ src/usr.bin/quota/printquota.h	Sun Jan 30 19:38:45 2011
@@ -1,7 +1,7 @@
-/*	$NetBSD: printquota.h,v 1.1.2.3 2011/01/29 17:42:37 bouyer Exp $ */
+/*	$NetBSD: printquota.h,v 1.1.2.4 2011/01/30 19:38:45 bouyer Exp $ */
 
 const char *intprt(uint64_t, u_int, int);
 #define HN_PRIV_UNLIMITED 0x80000000	/* print "unlimited" instead of "-" */
-const char *timeprt(time_t);
+const char *timeprt(time_t, time_t);
 int intrd(char *str, uint64_t *val, u_int);
 

Index: src/usr.bin/quota/quota.c
diff -u src/usr.bin/quota/quota.c:1.33.2.3 src/usr.bin/quota/quota.c:1.33.2.4
--- src/usr.bin/quota/quota.c:1.33.2.3	Fri Jan 28 22:15:36 2011
+++ src/usr.bin/quota/quota.c	Sun Jan 30 19:38:45 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: quota.c,v 1.33.2.3 2011/01/28 22:15:36 bouyer Exp $	*/
+/*	$NetBSD: quota.c,v 1.33.2.4 2011/01/30 19:38:45 bouyer Exp $	*/
 
 /*
  * Copyright (c) 1980, 1990, 1993
@@ -42,7 +42,7 @@
 #if 0
 static char sccsid[] = "@(#)quota.c	8.4 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: quota.c,v 1.33.2.3 2011/01/28 22:15:36 bouyer Exp $");
+__RCSID("$NetBSD: quota.c,v 1.33.2.4 2011/01/30 19:38:45 bouyer Exp $");
 #endif
 #endif /* not lint */
 
@@ -85,6 +85,7 @@
 	char	fsname[MAXPATHLEN + 1];
 };
 #define	FOUND	0x01
+#define	QUOTA2	0x02
 
 int	alldigits(char *);
 int	callaurpc(char *, int, int, int, xdrproc_t, void *, xdrproc_t, void *);
@@ -336,7 +337,7 @@
 {
 	struct quotause *qup;
 	struct quotause *quplist;
-	const char *msgi, *msgb, *nam;
+	const char *msgi, *msgb, *nam, *timemsg;
 	int lines = 0;
 	static time_t now;
 
@@ -396,6 +397,15 @@
 				printf("%s\n", qup->fsname);
 				nam = "";
 			} 
+			if (msgb)
+				timemsg = timeprt(now, 
+				    qup->q2e.q2e_val[Q2V_BLOCK].q2v_time);
+			else if ((qup->flags & QUOTA2) != 0 && vflag)
+				timemsg = timeprt(0,
+				    qup->q2e.q2e_val[Q2V_BLOCK].q2v_grace);
+			else
+				timemsg = NULL;
+				
 			printf("%12s%9s%c%8s%9s%8s"
 			    , nam
 			    , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur
@@ -405,8 +415,17 @@
 				, HN_B, hflag)
 			    , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit
 				, HN_B, hflag)
-			    , (msgb == NULL) ? ""
-			        : timeprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_time));
+			    , timemsg);
+
+			if (msgi)
+				timemsg = timeprt(now, 
+				    qup->q2e.q2e_val[Q2V_FILE].q2v_time);
+			else if ((qup->flags & QUOTA2) != 0 && vflag)
+				timemsg = timeprt(0,
+				    qup->q2e.q2e_val[Q2V_FILE].q2v_grace);
+			else
+				timemsg = NULL;
+				
 			printf("%8s%c%7s%8s%8s\n"
 			    , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_cur
 				, 0, hflag)
@@ -415,9 +434,7 @@
 				, 0, hflag)
 			    , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit
 				, 0, hflag)
-			    , (msgi == NULL) ? ""
-			        : timeprt(qup->q2e.q2e_val[Q2V_FILE].q2v_time)
-			);
+			    , timemsg);
 			continue;
 		}
 	}
@@ -466,6 +483,7 @@
 	struct quotause *quphead;
 	struct statvfs *fst;
 	int nfst, i;
+	int8_t version;
 
 	qup = quphead = quptail = NULL;
 
@@ -480,18 +498,21 @@
 		}
 		if (strncmp(fst[i].f_fstypename, "nfs", 
 		    sizeof(fst[i].f_fstypename)) == 0) {
+			version = 0;
 			if (getnfsquota(&fst[i], NULL, qup, id, quotatype) == 0)
 				continue;
 		} else if (strncmp(fst[i].f_fstypename, "ffs",
 		    sizeof(fst[i].f_fstypename)) == 0 &&
 		    (fst[i].f_flag & ST_QUOTA) != 0) {
-			if (getvfsquota(fst[i].f_mntonname, &qup->q2e,
+			if (getvfsquota(fst[i].f_mntonname, &qup->q2e, &version,
 			    id, quotatype, dflag, Dflag) == 0)
 				continue;
 		} else
 			continue;
 		(void)strncpy(qup->fsname, fst[i].f_mntonname,
 		    sizeof(qup->fsname) - 1);
+		if (version == 2)
+			qup->flags |= QUOTA2;
 		if (quphead == NULL)
 			quphead = qup;
 		else

Index: src/usr.sbin/edquota/edquota.c
diff -u src/usr.sbin/edquota/edquota.c:1.29.16.2 src/usr.sbin/edquota/edquota.c:1.29.16.3
--- src/usr.sbin/edquota/edquota.c:1.29.16.2	Sun Jan 30 12:38:32 2011
+++ src/usr.sbin/edquota/edquota.c	Sun Jan 30 19:38:45 2011
@@ -1,4 +1,4 @@
-/*      $NetBSD: edquota.c,v 1.29.16.2 2011/01/30 12:38:32 bouyer Exp $ */
+/*      $NetBSD: edquota.c,v 1.29.16.3 2011/01/30 19:38:45 bouyer Exp $ */
 
 /*
  * Copyright (c) 1980, 1990, 1993
@@ -42,7 +42,7 @@
 #if 0
 static char sccsid[] = "from: @(#)edquota.c	8.3 (Berkeley) 4/27/95";
 #else
-__RCSID("$NetBSD: edquota.c,v 1.29.16.2 2011/01/30 12:38:32 bouyer Exp $");
+__RCSID("$NetBSD: edquota.c,v 1.29.16.3 2011/01/30 19:38:45 bouyer Exp $");
 #endif
 #endif /* not lint */
 
@@ -405,18 +405,26 @@
 getprivs2(long id, int quotatype, const char *filesys, int defaultq)
 {
 	struct quotause *qup;
+	int8_t version;
+
 	if ((qup = (struct quotause *)malloc(sizeof(*qup))) == NULL)
 		errx(2, "out of memory");
-	qup->qfname = NULL;
+	memset(qup, 0, sizeof(*qup));
 	strcpy(qup->fsname, filesys);
-	qup->flags |= QUOTA2;
 	if (defaultq)
 		qup->flags |= DEFAULT;
-	if (!getvfsquota(filesys, &qup->q2e, id, quotatype, defaultq, Dflag)) {
+	if (!getvfsquota(filesys, &qup->q2e, &version,
+	    id, quotatype, defaultq, Dflag)) {
 		/* no entry, get default entry */
-		if (!getvfsquota(filesys, &qup->q2e, id, quotatype, 1, Dflag))
+		if (!getvfsquota(filesys, &qup->q2e, &version,
+		    id, quotatype, 1, Dflag)) {
+			free(qup);
 			return NULL;
+		}
 	}
+	if (version == 2)
+		qup->flags |= QUOTA2;
+	qup->q2e.q2e_uid = id;
 	return qup;
 }
 
@@ -495,7 +503,7 @@
 	struct quotause *qup;
 
         for (qup = quplist; qup; qup = qup->next) {
-		if (qup->flags & QUOTA2)
+		if (qup->qfname == NULL)
 			putprivs2(id, quotatype, qup);
 		else
 			putprivs1(id, quotatype, qup);
@@ -1041,7 +1049,7 @@
 }
 
 /*
- * Check to see if a particular quota is to be enabled.
+ * Check to see if a particular legacy quota is to be enabled in fstab
  */
 int
 hasquota(fs, type, qfnamep)

Index: src/usr.sbin/repquota/repquota.c
diff -u src/usr.sbin/repquota/repquota.c:1.25.2.2 src/usr.sbin/repquota/repquota.c:1.25.2.3
--- src/usr.sbin/repquota/repquota.c:1.25.2.2	Sat Jan 29 11:04:43 2011
+++ src/usr.sbin/repquota/repquota.c	Sun Jan 30 19:38:45 2011
@@ -40,7 +40,7 @@
 #if 0
 static char sccsid[] = "@(#)repquota.c	8.2 (Berkeley) 11/22/94";
 #else
-__RCSID("$NetBSD: repquota.c,v 1.25.2.2 2011/01/29 11:04:43 bouyer Exp $");
+__RCSID("$NetBSD: repquota.c,v 1.25.2.3 2011/01/30 19:38:45 bouyer Exp $");
 #endif
 #endif /* not lint */
 
@@ -98,7 +98,7 @@
 int	repquota2(const struct statvfs *, int);
 int	repquota1(const struct statvfs *, int);
 void	usage(void);
-void	printquotas(int, const struct statvfs *);
+void	printquotas(int, const struct statvfs *, int);
 void	dqblk2q2e(const struct dqblk *, struct quota2_entry *);
 
 int
@@ -214,8 +214,8 @@
 	prop_array_t cmds, datas;
 	struct plistref pref;
 	int error;
-	int8_t error8;
-	prop_object_iterator_t iter;
+	int8_t error8, version = 0;
+	prop_object_iterator_t cmditer, dataiter;
 	struct quota2_entry *q2ep;
 	struct fileusage *fup;
 	const char *strid;
@@ -229,6 +229,9 @@
 		errx(1, "can't allocate proplist");
 	if (!quota2_prop_add_command(cmds, "getall", qfextension[type], datas))
 		err(1, "prop_add_command");
+	if (!quota2_prop_add_command(cmds, "get version", qfextension[type],
+	     prop_array_create()))
+		err(1, "prop_add_command");
 	if (!prop_dictionary_set(dict, "commands", cmds))
 		err(1, "prop_dictionary_set(command)");
 	if (Dflag)
@@ -252,57 +255,74 @@
 		errx(1, "quota2_get_cmds: %s\n",
 		    strerror(error));
 	}
-	/* 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) {
-		prop_object_release(dict);
-		if (error8 != EOPNOTSUPP) {
-			fprintf(stderr, "get %s quotas: %s\n",
-			    qfextension[type], strerror(error8));
-		}
-		return (error8);
-	}
-	datas = prop_dictionary_get(cmd, "data");
-	if (datas == NULL)
-		err(1, "prop_dict_get(datas)");
-
-	iter = prop_array_iterator(datas);
-        if (iter == NULL)
-                err(1, "prop_array_iterator");
-
-	while ((data = prop_object_iterator_next(iter)) != NULL) {
-		strid = NULL;
-		if (!prop_dictionary_get_uint32(data, "id", &id)) {
-			if (!prop_dictionary_get_cstring_nocopy(data, "id",
-			    &strid))
-				errx(1, "can't find id in quota entry");
-			if (strcmp(strid, "default") != 0) {
-				errx(1, "wrong id string %s in quota entry",
-				    strid);
+	cmditer = prop_array_iterator(cmds);
+	if (cmditer == NULL)
+		err(1, "prop_array_iterator(cmds)");
+
+	while ((cmd = prop_object_iterator_next(cmditer)) != NULL) {
+		const char *cmdstr;
+		if (!prop_dictionary_get_cstring_nocopy(cmd, "command",
+		    &cmdstr))
+			err(1, "prop_get(command)");
+
+		if (!prop_dictionary_get_int8(cmd, "return", &error8))
+			err(1, "prop_get(return)");
+
+		if (error8) {
+			prop_object_release(dict);
+			if (error8 != EOPNOTSUPP) {
+				fprintf(stderr, "get %s quotas: %s\n",
+				    qfextension[type], strerror(error8));
 			}
-			q2ep = &defaultq2e[type];
-		} else {
-			if ((fup = lookup(id, type)) == 0)
-				fup = addid(id, type, (char *)0);
-			q2ep = &fup->fu_q2e;
-			q2ep->q2e_uid = id;
+			return (error8);
 		}
-			
-		error = quota2_dict_get_q2e_usage(data, q2ep);
-		if (error) {
-			errx(1, "quota2_dict_get_q2e_usage: %s\n",
-			    strerror(error));
+		datas = prop_dictionary_get(cmd, "data");
+		if (datas == NULL)
+			err(1, "prop_dict_get(datas)");
+
+		if (strcmp("get version", cmdstr) == 0) {
+			data = prop_array_get(datas, 0);
+			if (data == NULL)
+				err(1, "prop_array_get(version)");
+			if (!prop_dictionary_get_int8(data, "version",
+			    &version))
+				err(1, "prop_get_int8(version)");
+			continue;
+		}
+		dataiter = prop_array_iterator(datas);
+		if (dataiter == NULL)
+			err(1, "prop_array_iterator");
+
+		while ((data = prop_object_iterator_next(dataiter)) != NULL) {
+			strid = NULL;
+			if (!prop_dictionary_get_uint32(data, "id", &id)) {
+				if (!prop_dictionary_get_cstring_nocopy(data,
+				    "id", &strid))
+					errx(1, "can't find id in quota entry");
+				if (strcmp(strid, "default") != 0) {
+					errx(1,
+					    "wrong id string %s in quota entry",
+					    strid);
+				}
+				q2ep = &defaultq2e[type];
+			} else {
+				if ((fup = lookup(id, type)) == 0)
+					fup = addid(id, type, (char *)0);
+				q2ep = &fup->fu_q2e;
+				q2ep->q2e_uid = id;
+			}
+				
+			error = quota2_dict_get_q2e_usage(data, q2ep);
+			if (error) {
+				errx(1, "quota2_dict_get_q2e_usage: %s\n",
+				    strerror(error));
+			}
 		}
+		prop_object_iterator_release(dataiter);
 	}
-	prop_object_iterator_release(iter);
+	prop_object_iterator_release(cmditer);
 	prop_object_release(dict);
-	printquotas(type, vfs);
+	printquotas(type, vfs, version);
 	return (0);
 }
 
@@ -353,22 +373,29 @@
 		dqblk2q2e(&dqbuf, &fup->fu_q2e);
 	}
 	fclose(qf);
-	printquotas(type, vfs);
+	printquotas(type, vfs, 1);
 	return (0);
 }
 
 void
-printquotas(int type, const struct statvfs *vfs)
+printquotas(int type, const struct statvfs *vfs, int version)
 {
 	static int multiple = 0;
 	u_long id;
 	struct fileusage *fup;
+	const char *timemsg;
+	static time_t now;
+
+	if (now == 0)
+		time(&now);
 
 	if (multiple++)
 		printf("\n");
 	if (vflag)
-		fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
-		    qfextension[type], vfs->f_mntonname, vfs->f_mntfromname);
+		fprintf(stdout,
+		    "*** Report for %s quotas on %s (%s, version %d)\n",
+		    qfextension[type], vfs->f_mntonname, vfs->f_mntfromname,
+		    version);
 	printf("                        Block limits               File limits\n");
 	printf(type == USRQUOTA ? "User " : "Group");
 	printf("            used     soft     hard  grace      used    soft    hard  grace\n");
@@ -383,6 +410,18 @@
 			printf("%s ", fup->fu_name);
 		else
 			printf("%-10s", fup->fu_name);
+
+		if (fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit && 
+		    fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur >= 
+		    fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit)
+			timemsg = timeprt(now,
+			    fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_time);
+		else if (vflag && version == 2)
+			timemsg = timeprt(0,
+			    fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_grace);
+		else
+			timemsg = "";
+
 		printf("%c%c%9s%9s%9s%7s",
 			fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit && 
 			    fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur >= 
@@ -398,10 +437,17 @@
 				HN_B, hflag),
 			intprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit,
 				HN_B, hflag),
-			(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit && 
-			 fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur >= 
-			 fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit) ?
-			timeprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_time) : "");
+			timemsg);
+		if (fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit && 
+		    fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur >= 
+		    fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit)
+			timemsg = timeprt(now,
+			    fup->fu_q2e.q2e_val[Q2V_FILE].q2v_time);
+		else if (vflag && version == 2)
+			timemsg = timeprt(0,
+			    fup->fu_q2e.q2e_val[Q2V_FILE].q2v_grace);
+		else
+			timemsg = "";
 		printf("  %8s%8s%8s%7s\n",
 			intprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur,
 				0, hflag),
@@ -409,10 +455,7 @@
 				0, hflag),
 			intprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_hardlimit,
 				0, hflag),
-			(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit && 
-			 fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur >= 
-			 fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit) ?
-			timeprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_time) : "");
+			timemsg);
 		memset(&fup->fu_q2e, 0, sizeof(fup->fu_q2e));
 	}
 }

Reply via email to