Fri Jan 21 16:58:07 2011 UTC ()
Add support for quotactl("getall") command, and convert repquota to new
world.


(bouyer)
diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/quota2.h
diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/quota2_prop.c
diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/quota2_prop.h
diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/ufs_quota.h
diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/ufs_quota2.c
diff -r1.68.4.1 -r1.68.4.2 src/sys/ufs/ufs/ufs_quota.c
diff -r1.6.64.1 -r1.6.64.2 src/usr.bin/quota/Makefile
diff -r0 -r1.1.2.1 src/usr.bin/quota/printquota.c
diff -r0 -r1.1.2.1 src/usr.bin/quota/printquota.h
diff -r1.14.52.2 -r1.14.52.3 src/usr.bin/quota/quota.1
diff -r1.33.2.1 -r1.33.2.2 src/usr.bin/quota/quota.c
diff -r1.5 -r1.5.64.1 src/usr.sbin/repquota/Makefile
diff -r1.9 -r1.9.50.1 src/usr.sbin/repquota/repquota.8
diff -r1.25 -r1.25.2.1 src/usr.sbin/repquota/repquota.c

cvs diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/quota2.h (expand / switch to context diff)
--- src/sys/ufs/ufs/quota2.h 2011/01/20 14:25:03 1.1.2.1
+++ src/sys/ufs/ufs/quota2.h 2011/01/21 16:58:06 1.1.2.2
@@ -1,4 +1,4 @@
-/* $NetBSD: quota2.h,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */
+/* $NetBSD: quota2.h,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */
 /*-
   * Copyright (c) 2010 Manuel Bouyer
   * All rights reserved.
@@ -97,5 +97,4 @@
 /* quota2_subr.c */
 void quota2_addfreeq2e(struct quota2_header *, void *, uint64_t, uint64_t, int);
 void quota2_create_blk0(uint64_t, void *bp, int, int, int);
-
 #endif /*  _UFS_UFS_QUOTA2_H_ */

cvs diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/Attic/quota2_prop.c (expand / switch to context diff)
--- src/sys/ufs/ufs/Attic/quota2_prop.c 2011/01/20 14:25:03 1.1.2.1
+++ src/sys/ufs/ufs/Attic/quota2_prop.c 2011/01/21 16:58:06 1.1.2.2
@@ -1,4 +1,4 @@
-/* $NetBSD: quota2_prop.c,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */
+/* $NetBSD: quota2_prop.c,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */
 /*-
   * Copyright (c) 2010 Manuel Bouyer
   * All rights reserved.
@@ -95,8 +95,6 @@
 {
 	int i, error;
 	prop_dictionary_t val;
-	if (!prop_dictionary_get_uint32(data, "id", &q2e->q2e_uid))
-		return EINVAL;
 	for (i = 0; i < NQ2V; i++) {
 		val = prop_dictionary_get_dict(data, quota2_valnames[i]);
 		if (val == NULL)
@@ -135,6 +133,16 @@
 	return 0;
 }
 
+bool
+prop_array_add_and_rel(prop_array_t array, prop_object_t po)
+{
+	bool ret;
+	if (po == NULL)
+		return false;
+	ret = prop_array_add(array, po);
+	prop_object_release(po);
+	return ret;
+}
 
 bool
 prop_dictionary_set_and_rel(prop_dictionary_t dict, const char *key,

cvs diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/Attic/quota2_prop.h (expand / switch to context diff)
--- src/sys/ufs/ufs/Attic/quota2_prop.h 2011/01/20 14:25:03 1.1.2.1
+++ src/sys/ufs/ufs/Attic/quota2_prop.h 2011/01/21 16:58:06 1.1.2.2
@@ -1,4 +1,4 @@
-/* $NetBSD: quota2_prop.h,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */
+/* $NetBSD: quota2_prop.h,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */
 /*-
   * Copyright (c) 2010 Manuel Bouyer
   * All rights reserved.
@@ -36,6 +36,7 @@
 int quota2_dict_get_q2e_usage(prop_dictionary_t, struct quota2_entry *);
 int quota2_get_cmds(prop_dictionary_t, prop_array_t *);
 
+bool prop_array_add_and_rel(prop_array_t, prop_object_t);
 bool prop_dictionary_set_and_rel(prop_dictionary_t, const char *,
      prop_object_t);
 prop_dictionary_t quota2_prop_create(void);

cvs diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/ufs_quota.h (expand / switch to context diff)
--- src/sys/ufs/ufs/ufs_quota.h 2011/01/20 14:25:03 1.1.2.1
+++ src/sys/ufs/ufs/ufs_quota.h 2011/01/21 16:58:06 1.1.2.2
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_quota.h,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $	*/
+/*	$NetBSD: ufs_quota.h,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1990, 1993, 1995
@@ -96,8 +96,8 @@
  */
 #define	NODQUOT		NULL
 
-static kmutex_t dqlock;
-static kcondvar_t dqcv;
+extern kmutex_t dqlock;
+extern kcondvar_t dqcv;
 /*
  * Quota name to error message mapping.
  */
@@ -128,8 +128,9 @@
 
 int chkdq2(struct inode *, int64_t, kauth_cred_t, int);
 int chkiq2(struct inode *, int32_t, kauth_cred_t, int);
-int quota2_handle_cmd_get(struct ufsmount *, const char *, int, int,
+int quota2_handle_cmd_get(struct ufsmount *, int, int, int,
     prop_array_t);
+int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t);
 int q2sync(struct mount *);
 int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
 int dq2sync(struct vnode *, struct dquot *);

cvs diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/ufs_quota2.c (expand / switch to context diff)
--- src/sys/ufs/ufs/ufs_quota2.c 2011/01/20 14:25:03 1.1.2.1
+++ src/sys/ufs/ufs/ufs_quota2.c 2011/01/21 16:58:06 1.1.2.2
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_quota2.c,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */
+/* $NetBSD: ufs_quota2.c,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */
 /*-
   * Copyright (c) 2010 Manuel Bouyer
   * All rights reserved.
@@ -28,7 +28,7 @@
   */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $");
 
 #include <sys/buf.h>
 #include <sys/param.h>
@@ -58,6 +58,9 @@
     struct quota2_header **, int);
 static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **,
     struct quota2_entry **, int);
+static int quota2_walk_list(struct ufsmount *, struct buf *, int,
+    uint64_t *, int, void *,
+    int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *));
 
 static int
 getq2h(struct ufsmount *ump, int type,
@@ -107,6 +110,80 @@
 	*bpp = bp;
 	return 0;
 }
+
+/* walk a quota entry list, calling the callback for each entry */
+#define Q2WL_ABORT 0x10000000
+
+static int
+quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type,
+    uint64_t *offp, int flags, void *a,
+    int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *))
+{
+	const int needswap = UFS_MPNEEDSWAP(ump);
+	daddr_t off = ufs_rw64(*offp, needswap);
+	struct buf *bp, *obp = hbp;
+	int ret = 0, ret2 = 0;
+	struct quota2_entry *q2e;
+	daddr_t lblkno, blkoff;
+
+	KASSERT(mutex_owner(&dqlock));
+
+	while (off != 0) {
+		lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
+		blkoff = (off & ump->umq2_bmask);
+		if (lblkno == 0) {
+			/* in the header block */
+			bp = hbp;
+		} else {
+			ret = bread(ump->um_quotas[type], lblkno, 
+			    ump->umq2_bsize,
+			    ump->um_cred[type], flags, &bp);
+			if (ret)
+				return ret;
+			if (bp->b_resid != 0) {
+				panic("quota2_walk_list: %s quota file corrupted",
+				    quotatypes[type]);
+			}
+		}
+		q2e = (void *)((char *)(bp->b_data) + blkoff);
+		ret = (*func)(ump, offp, q2e, off, a);
+		if (off != ufs_rw64(*offp, needswap)) {
+			/* callback changed parent's pointer, redo */
+			off = ufs_rw64(*offp, needswap);
+			if (bp != hbp && bp != obp)
+				ret2 = VOP_BWRITE(bp);
+		} else {
+			/* parent if now current */
+			if (obp != bp && obp != hbp) {
+				if (flags & B_MODIFY)
+					ret2 = VOP_BWRITE(obp);
+				else
+					brelse(obp, 0);
+			}
+			obp = bp;
+			offp = &(q2e->q2e_next);
+			off = ufs_rw64(*offp, needswap);
+		}
+		if (ret)
+			break;
+		if (ret2) {
+			ret = ret2;
+			break;
+		}
+	}
+	if (obp != hbp) {
+		if (flags & B_MODIFY)
+			ret2 = VOP_BWRITE(obp);
+		else
+			brelse(obp, 0);
+	}
+	if (ret & Q2WL_ABORT)
+		return 0;
+	if (ret == 0)
+		return ret2;
+	return ret;
+}
+
 void
 quota2_umount(struct mount *mp)
 {
@@ -318,7 +395,7 @@
 }
 
 int
-quota2_handle_cmd_get(struct ufsmount *ump, const char *type, int id,
+quota2_handle_cmd_get(struct ufsmount *ump, int type, int id,
     int defaultq, prop_array_t replies)
 {
 	struct dquot *dq;
@@ -327,24 +404,19 @@
 	struct quota2_entry *q2e;
 	struct buf *bp;
 	prop_dictionary_t dict;
-	int q2type;
 
-	if (!strcmp(type, "user")) {
-		q2type = USRQUOTA;
-	} else if (!strcmp(type, "group")) {
-		q2type = GRPQUOTA;
-	} else
-		return EOPNOTSUPP;
-
-	if (ump->um_quotas[q2type] == NULLVP)
+	if (ump->um_quotas[type] == NULLVP)
 		return ENODEV;
 	if (defaultq) {
-		error = getq2h(ump, q2type, &bp, &q2h, 0);
-		if (error)
+		mutex_enter(&dqlock);
+		error = getq2h(ump, type, &bp, &q2h, 0);
+		if (error) {
+			mutex_exit(&dqlock);
 			return error;
+		}
 		q2e = &q2h->q2h_defentry;
 	} else {
-		error = dqget(NULLVP, id, ump, q2type, &dq);
+		error = dqget(NULLVP, id, ump, type, &dq);
 
 		if (error)
 			return error;
@@ -353,66 +425,132 @@
 			dqrele(NULLVP, dq);
 			return ENOENT;
 		}
-		error = getq2e(ump, q2type, dq->dq2_lblkno, dq->dq2_blkoff,
+		error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff,
 		    &bp, &q2e, 0);
-		dqrele(NULLVP, dq);
 		if (error)
 			return error;
 	}
-	dict = q2etoprop(q2e, 0);
+	dict = q2etoprop(q2e, defaultq);
+	if (defaultq)
+		mutex_exit(&dqlock);
+	else
+		dqrele(NULLVP, dq);
 	brelse(bp, 0);
 	if (dict == NULL)
 		return ENOMEM;
 	
-	if (!prop_array_add(replies, dict)) {
+	if (!prop_array_add_and_rel(replies, dict)) {
 		error = ENOMEM;
 	}
-	prop_object_release(dict);
 	return error;
 }
 
+
+static int
+quota2_getall_callback(struct ufsmount *ump, uint64_t *offp,
+    struct quota2_entry *q2e, uint64_t off, void *v)
+{
+	prop_array_t replies = v;
+	prop_dictionary_t dict;
+
+	dict = q2etoprop(q2e, 0);	
+	if (!prop_array_add_and_rel(replies, dict)) {
+		return ENOMEM;
+	}
+	return 0;
+}
+
 int
+quota2_handle_cmd_getall(struct ufsmount *ump, int type, prop_array_t replies)
+{
+	int error;
+	struct quota2_header *q2h;
+	struct buf *hbp;
+	prop_dictionary_t dict;
+	uint64_t offset;
+	int i;
+	int quota2_hash_size;
+	const int needswap = UFS_MPNEEDSWAP(ump);
+
+	if (ump->um_quotas[type] == NULLVP)
+		return ENODEV;
+	error = getq2h(ump, type, &hbp, &q2h, 0);
+	if (error)
+		return error;
+	dict = q2etoprop(&q2h->q2h_defentry, 1);
+	if (!prop_array_add_and_rel(replies, dict)) {
+		brelse(hbp, 0);
+		return ENOMEM;
+	}
+	quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
+	for (i = 0; i < quota2_hash_size ; i++) {
+		offset = ufs_rw64(q2h->q2h_entries[i], needswap);
+		error = quota2_walk_list(ump, hbp, type, &offset, 0, replies,
+		    quota2_getall_callback);
+		if (error)
+			break;
+	}
+	brelse(hbp, 0);
+	return error;
+}
+
+int
 q2sync(struct mount *mp)
 {
 	return 0;
 }
 
+struct dq2get_callback {
+	uid_t id;
+	struct dquot *dq;
+};
+
+static int
+dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
+    uint64_t off, void *v)
+{
+	struct dq2get_callback *c = v;
+	daddr_t lblkno;
+	int blkoff;
+	const int needswap = UFS_MPNEEDSWAP(ump);
+
+	if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
+		lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
+		blkoff = (off & ump->umq2_bmask);
+		c->dq->dq2_lblkno = lblkno;
+		c->dq->dq2_blkoff = blkoff;
+		return Q2WL_ABORT;
+	}
+	return 0;
+}
+
 int
 dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
     struct dquot *dq)
 {
 	struct buf *bp;
 	struct quota2_header *q2h;
-	struct quota2_entry *q2e;
 	int error;
-	daddr_t offset, lblkno;
-	int blkoffset;
+	daddr_t offset;
 	u_long hash_mask;
 	const int needswap = UFS_MPNEEDSWAP(ump);
+	struct dq2get_callback c = {
+		.id = id,
+		.dq = dq
+	};
 
+	mutex_enter(&dqlock);
 	error = getq2h(ump, type, &bp, &q2h, 0);
 	if (error)
-		return error;
+		goto out_mutex;
 	/* look for our entry */
 	hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
 	offset = ufs_rw64(q2h->q2h_entries[id & hash_mask], needswap);
-	dq->dq2_lblkno = 0;
-	dq->dq2_blkoff = 0;
-	while (offset != 0) {
-		lblkno = (offset >> ump->um_mountp->mnt_fs_bshift);
-		blkoffset = (offset & ump->umq2_bmask);
-		brelse(bp, 0);
-		error = getq2e(ump, type, lblkno, blkoffset, &bp, &q2e, 0);
-		if (error)
-			return error;
-		if (ufs_rw32(q2e->q2e_uid, needswap) == id) {
-			dq->dq2_lblkno = lblkno;
-			dq->dq2_blkoff = blkoffset;
-			break;
-		}
-		offset = ufs_rw64(q2e->q2e_next, needswap);
-	}
+	error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c,
+	    dq2get_callback);
 	brelse(bp, 0);
+out_mutex:
+	mutex_exit(&dqlock);
 	return error;
 }
 

cvs diff -r1.68.4.1 -r1.68.4.2 src/sys/ufs/ufs/ufs_quota.c (expand / switch to context diff)
--- src/sys/ufs/ufs/ufs_quota.c 2011/01/20 14:25:03 1.68.4.1
+++ src/sys/ufs/ufs/ufs_quota.c 2011/01/21 16:58:06 1.68.4.2
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_quota.c,v 1.68.4.1 2011/01/20 14:25:03 bouyer Exp $	*/
+/*	$NetBSD: ufs_quota.c,v 1.68.4.2 2011/01/21 16:58:06 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.1 2011/01/20 14:25:03 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.68.4.2 2011/01/21 16:58:06 bouyer Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -57,9 +57,13 @@
 #include <ufs/ufs/ufs_quota.h>
 #include <ufs/ufs/quota2_prop.h>
 
+kmutex_t dqlock;
+kcondvar_t dqcv;
 
 static int quota_handle_cmd_get(struct mount *, struct lwp *,
-    prop_dictionary_t, const char *, prop_array_t);
+    prop_dictionary_t, int, prop_array_t);
+static int quota_handle_cmd_getall(struct mount *, struct lwp *,
+    prop_dictionary_t, int, prop_array_t);
 /*
  * Initialize the quota fields of an inode.
  */
@@ -126,11 +130,18 @@
 	int error = 0;
 	const char *cmd, *type;
 	prop_array_t datas;
+	int q2type;
 
 	if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
 		return EINVAL;
 	if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
 		return EINVAL;
+	if (!strcmp(type, "user")) {
+		q2type = USRQUOTA;
+	} else if (!strcmp(type, "group")) {
+		q2type = GRPQUOTA;
+	} else
+		return EOPNOTSUPP;
 	datas = prop_dictionary_get(cmddict, "data");
 	if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
 		return EINVAL;
@@ -139,12 +150,17 @@
 	prop_dictionary_remove(cmddict, "data"); /* prepare for return */
 
 	if (strcmp(cmd, "get") == 0) {
-		error = quota_handle_cmd_get(mp, l, cmddict, type, datas);
+		error = quota_handle_cmd_get(mp, l, cmddict, q2type, datas);
 		goto end;
 	}
-	if (!prop_dictionary_set_int8(cmddict, "return", EOPNOTSUPP))
-		error = ENOMEM;
+	if (strcmp(cmd, "getall") == 0) {
+		error = quota_handle_cmd_getall(mp, l, cmddict, q2type, datas);
+		goto end;
+	}
+	error = EOPNOTSUPP;
 end:
+	error = (prop_dictionary_set_int8(cmddict, "return",
+	    error) ? 0 : ENOMEM);
 	prop_object_release(datas);
 	return error;
 }
@@ -161,7 +177,7 @@
 
 static int 
 quota_handle_cmd_get(struct mount *mp, struct lwp *l, 
-    prop_dictionary_t cmddict, const char *type, prop_array_t datas)
+    prop_dictionary_t cmddict, int type, prop_array_t datas)
 {
 	prop_array_t replies;
 	prop_object_iterator_t iter;
@@ -172,19 +188,16 @@
 	const char *idstr;
 
 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
-		return (prop_dictionary_set_int8(cmddict, "return",
-		    EOPNOTSUPP) ? 0 : ENOMEM);
+		return EOPNOTSUPP;
 	
 	replies = prop_array_create();
 	if (replies == NULL)
-		return (prop_dictionary_set_int8(cmddict, "return", ENOMEM) ?
-		    0 : ENOMEM);
+		return ENOMEM;
 
 	iter = prop_array_iterator(datas);
 	if (iter == NULL) {
 		prop_object_release(replies);
-		return (prop_dictionary_set_int8(cmddict, "return", ENOMEM) ?
-		    0 : ENOMEM);
+		return ENOMEM;
 	}
 	while ((data = prop_object_iterator_next(iter)) != NULL) {
 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
@@ -200,8 +213,6 @@
 		if (error == EPERM)
 			continue;
 		if (error != 0) {
-			error = (prop_dictionary_set_int8(cmddict, "return",
-			    error) ? 0 : ENOMEM);
 			prop_object_release(replies);
 			return error;
 		}
@@ -219,18 +230,50 @@
 			panic("quota_handle_cmd_get: no support ?");
 		
 		if (error && error != ENOENT) {
-			error = (prop_dictionary_set_int8(cmddict, "return",
-			    error) ? 0 : ENOMEM);
 			prop_object_release(replies);
 			return error;
 		}
 	}
 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
-		error = (prop_dictionary_set_int8(cmddict, "return",
-		    ENOMEM) ? 0 : ENOMEM);
+		error = ENOMEM;
 	} else {
-		error = (prop_dictionary_set_int8(cmddict, "return", 0) ?
-		    0 : ENOMEM);
+		error = 0;
+	}
+	return error;
+}
+
+static int 
+quota_handle_cmd_getall(struct mount *mp, struct lwp *l, 
+    prop_dictionary_t cmddict, int type, prop_array_t datas)
+{
+	prop_array_t replies;
+	struct ufsmount *ump = VFSTOUFS(mp);
+	int error;
+
+	if ((ump->um_flags & UFS_QUOTA2) == 0)
+		return EOPNOTSUPP;
+	
+	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
+	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
+	if (error)
+		return error;
+		
+	replies = prop_array_create();
+	if (replies == NULL)
+		return ENOMEM;
+
+#ifdef QUOTA2
+	if (ump->um_flags & UFS_QUOTA2) {
+		mutex_enter(&dqlock);
+		error = quota2_handle_cmd_getall(ump, type, replies);
+		mutex_exit(&dqlock);
+	} else
+#endif
+		panic("quota_handle_cmd_getall: no support ?");
+	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
+		error = ENOMEM;
+	} else {
+		error = 0;
 	}
 	return error;
 }

cvs diff -r1.6.64.1 -r1.6.64.2 src/usr.bin/quota/Makefile (expand / switch to context diff)
--- src/usr.bin/quota/Makefile 2011/01/20 14:25:05 1.6.64.1
+++ src/usr.bin/quota/Makefile 2011/01/21 16:58:06 1.6.64.2
@@ -1,12 +1,12 @@
-#	$NetBSD: Makefile,v 1.6.64.1 2011/01/20 14:25:05 bouyer Exp $	
+#	$NetBSD: Makefile,v 1.6.64.2 2011/01/21 16:58:06 bouyer Exp $	
 #	from: @(#)Makefile	8.1 (Berkeley) 6/6/93
 
 .include <bsd.own.mk>
 PROG=	quota
-SRCS=	quota.c
+SRCS=	quota.c printquota.c
 
-CPPFLAGS+=-I${NETBSDSRCDIR}/sys
-DPADD=	${LIBRPCSVC}
+CPPFLAGS+=-I${NETBSDSRCDIR}/sys -I${NETBSDSRCDIR}/usr.bin/quota
+DPADD=	${LIBRPCSVC} ${LIBPROP}
 LDADD=	-lrpcsvc -lprop
 
 .PATH:	${NETBSDSRCDIR}/sys/ufs/ufs 

File Added: src/usr.bin/quota/printquota.c
/*	$NetBSD: printquota.c,v 1.1.2.1 2011/01/21 16:58:06 bouyer Exp $	*/

/*
 * Copyright (c) 1980, 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Robert Elz at The University of Melbourne.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\
 The Regents of the University of California.  All rights reserved.");
#endif /* not lint */

#ifndef lint
#if 0
static char sccsid[] = "@(#)quota.c	8.4 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: printquota.c,v 1.1.2.1 2011/01/21 16:58:06 bouyer Exp $");
#endif
#endif /* not lint */

#include <sys/param.h>
#include <sys/types.h>

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include <printquota.h>

/*
 * convert 64bit value to a printable string
 */
const char *
intprt(uint64_t val, int flags, int hflag)
{
	static char buf[21];

	if (val == UQUAD_MAX)
		return("-");

	if (flags & HN_B)
		val = dbtob(val);
	
	if (hflag) {
		humanize_number(buf, 6, val, "", HN_AUTOSCALE, flags);
		return buf;
	}
	if (flags & HN_B) {
		/* traditionnal display: blocks are in kilobytes */
		val = val / 1024;
	}
	snprintf(buf, sizeof(buf), "%" PRIu64, val);
	return buf;
}

/*
 * Calculate the grace period and return a printable string for it.
 */
const char *
timeprt(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;
	minutes = (seconds + 30) / 60;
	hours = (minutes + 30) / 60;
	if (hours >= 36) {
		(void)snprintf(buf, sizeof buf, "%ddays",
		    (int)((hours + 12) / 24));
		return (buf);
	}
	if (minutes >= 60) {
		(void)snprintf(buf, sizeof buf, "%2d:%d",
		    (int)(minutes / 60), (int)(minutes % 60));
		return (buf);
	}
	(void)snprintf(buf, sizeof buf, "%2d", (int)minutes);
	return (buf);
}

File Added: src/usr.bin/quota/printquota.h
/*	$NetBSD: printquota.h,v 1.1.2.1 2011/01/21 16:58:06 bouyer Exp $	*/

const char *intprt(uint64_t, int, int);
const char *timeprt(time_t);

cvs diff -r1.14.52.2 -r1.14.52.3 src/usr.bin/quota/quota.1 (expand / switch to context diff)
--- src/usr.bin/quota/quota.1 2011/01/21 16:36:57 1.14.52.2
+++ src/usr.bin/quota/quota.1 2011/01/21 16:58:06 1.14.52.3
@@ -1,4 +1,4 @@
-.\"	$NetBSD: quota.1,v 1.14.52.2 2011/01/21 16:36:57 bouyer Exp $
+.\"	$NetBSD: quota.1,v 1.14.52.3 2011/01/21 16:58:06 bouyer Exp $
 .\"
 .\" Copyright (c) 1983, 1990, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -135,7 +135,6 @@
 .Nm
 exits with a non-zero status, one or more filesystems
 are over quota.
-.El
 .Sh SEE ALSO
 .Xr quotactl 2 ,
 .Xr fstab 5 ,

cvs diff -r1.33.2.1 -r1.33.2.2 src/usr.bin/quota/quota.c (expand / switch to context diff)
--- src/usr.bin/quota/quota.c 2011/01/20 14:25:05 1.33.2.1
+++ src/usr.bin/quota/quota.c 2011/01/21 16:58:06 1.33.2.2
@@ -1,4 +1,4 @@
-/*	$NetBSD: quota.c,v 1.33.2.1 2011/01/20 14:25:05 bouyer Exp $	*/
+/*	$NetBSD: quota.c,v 1.33.2.2 2011/01/21 16:58:06 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.1 2011/01/20 14:25:05 bouyer Exp $");
+__RCSID("$NetBSD: quota.c,v 1.33.2.2 2011/01/21 16:58:06 bouyer Exp $");
 #endif
 #endif /* not lint */
 
@@ -55,11 +55,10 @@
 #include <sys/stat.h>
 #include <sys/mount.h>
 #include <sys/socket.h>
-#include <sys/queue.h>
-#include <prop/proplib.h>
-#include <sys/quota.h>
 
 #include <ufs/ufs/quota2_prop.h>
+#include <sys/quota.h>
+
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
@@ -77,7 +76,7 @@
 #include <rpc/pmap_prot.h>
 #include <rpcsvc/rquota.h>
 
-const char *qfextension[] = INITQFNAMES;
+#include <printquota.h>
 
 struct quotause {
 	struct	quotause *next;
@@ -93,17 +92,18 @@
 int	getnfsquota(struct statvfs *, struct fstab *, struct quotause *,
 	    long, int);
 struct quotause	*getprivs(long id, int quotatype);
-int	getufsquota(struct statvfs *, struct quotause *, long, int);
 void	heading(int, u_long, const char *, const char *);
 void	showgid(gid_t);
 void	showgrpname(const char *);
 void	showquotas(int, u_long, const char *);
 void	showuid(uid_t);
 void	showusrname(const char *);
-const char *intprt(uint64_t, int);
-const char *timeprt(time_t seconds);
 void	usage(void);
 
+extern const char *qfextension[];
+
+int  getufsquota(const char *, struct quota2_entry *, long, int, int, int);
+
 int	qflag = 0;
 int	vflag = 0;
 int	hflag = 0;
@@ -403,21 +403,22 @@
 			printf("%12s%9s%c%8s%9s%8s"
 			    , nam
 			    , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur
-				,HN_B)
+				,HN_B, hflag)
 			    , (msgb == NULL) ? ' ' : '*'
 			    , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_softlimit
-				, HN_B)
+				, HN_B, hflag)
 			    , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit
-				, HN_B)
+				, HN_B, hflag)
 			    , (msgb == NULL) ? ""
 			        : timeprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_time));
 			printf("%8s%c%7s%8s%8s\n"
-			    , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_cur, 0)
+			    , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_cur
+				, 0, hflag)
 			    , (msgi == NULL) ? ' ' : '*'
 			    , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_softlimit
-				, 0)
+				, 0, hflag)
 			    , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit
-				, 0)
+				, 0, hflag)
 			    , (msgi == NULL) ? ""
 			        : timeprt(qup->q2e.q2e_val[Q2V_FILE].q2v_time)
 			);
@@ -458,63 +459,6 @@
 }
 
 /*
- * convert 64bit value to a printable string
- */
-const char *
-intprt(uint64_t val, int flags)
-{
-	static char buf[21];
-
-	if (val == UQUAD_MAX)
-		return("-");
-
-	if (flags & HN_B)
-		val = dbtob(val);
-	
-	if (hflag) {
-		humanize_number(buf, 6, val, "", HN_AUTOSCALE, flags);
-		return buf;
-	}
-	if (flags & HN_B) {
-		/* traditionnal display: blocks are in kilobytes */
-		val = val / 1024;
-	}
-	snprintf(buf, sizeof(buf), "%" PRIu64, val);
-	return buf;
-}
-
-/*
- * Calculate the grace period and return a printable string for it.
- */
-const char *
-timeprt(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;
-	minutes = (seconds + 30) / 60;
-	hours = (minutes + 30) / 60;
-	if (hours >= 36) {
-		(void)snprintf(buf, sizeof buf, "%ddays",
-		    (int)((hours + 12) / 24));
-		return (buf);
-	}
-	if (minutes >= 60) {
-		(void)snprintf(buf, sizeof buf, "%2d:%d",
-		    (int)(minutes / 60), (int)(minutes % 60));
-		return (buf);
-	}
-	(void)snprintf(buf, sizeof buf, "%2d", (int)minutes);
-	return (buf);
-}
-
-/*
  * Collect the requested quota information.
  */
 struct quotause *
@@ -532,7 +476,6 @@
 	nfst = getmntinfo(&fst, MNT_WAIT);
 	if (nfst == 0)
 		errx(2, "no filesystems mounted!");
-	setfsent();
 	for (i = 0; i < nfst; i++) {
 		if (qup == NULL) {
 			if ((qup =
@@ -545,8 +488,9 @@
 				continue;
 		} else if (strncmp(fst[i].f_fstypename, "ffs",
 		    sizeof(fst[i].f_fstypename)) == 0 &&
-		    (fst[i].f_flag &ST_QUOTA) != 0) {
-			if (getufsquota(&fst[i], qup, id, quotatype) == 0)
+		    (fst[i].f_flag & ST_QUOTA) != 0) {
+			if (getufsquota(fst[i].f_mntonname, &qup->q2e,
+			    id, quotatype, dflag, Dflag) == 0)
 				continue;
 		} else
 			continue;
@@ -562,109 +506,10 @@
 	}
 	if (qup)
 		free(qup);
-	endfsent();
 	return (quphead);
 }
 
-
 int
-getufsquota(struct statvfs *fst, struct quotause *qup, long id, int type)
-{
-	prop_dictionary_t dict, data, cmd;
-	prop_array_t cmds, datas;
-	struct plistref pref;
-	int error;
-	int8_t error8;
-	bool ret;
-
-	dict = quota2_prop_create();
-	cmds = prop_array_create();
-	datas = prop_array_create();
-	data = prop_dictionary_create();
-
-	if (dict == NULL || cmds == NULL || datas == NULL || data == NULL)
-		errx(1, "can't allocate proplist");
-
-	if (dflag)
-		ret = prop_dictionary_set_cstring(data, "id", "default");
-	else
-		ret = prop_dictionary_set_uint32(data, "id", id);
-	if (!ret)
-		err(1, "prop_dictionary_set(id)");
-		
-	if (!prop_array_add(datas, data))
-		err(1, "prop_array_add(data)");
-	prop_object_release(data);
-	if (!quota2_prop_add_command(cmds, "get", qfextension[type], datas))
-		err(1, "prop_add_command");
-	if (!prop_dictionary_set(dict, "commands", cmds))
-		err(1, "prop_dictionary_set(command)");
-	if (Dflag)
-		printf("message to kernel:\n%s\n",
-		    prop_dictionary_externalize(dict));
-
-	if (!prop_dictionary_send_syscall(dict, &pref))
-		err(1, "prop_dictionary_send_syscall");
-	prop_object_release(dict);
-
-	if (quotactl(fst->f_mntonname, &pref) != 0)
-		err(1, "quotactl");
-	
-	if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) {
-		errx(1, "prop_dictionary_recv_syscall: %s\n",
-		    strerror(error));
-	}
-	if (Dflag)
-		printf("reply from kernel:\n%s\n",
-		    prop_dictionary_externalize(dict));
-	if ((error = quota2_get_cmds(dict, &cmds)) != 0) {
-		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 (dflag)
-				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)");
-
-	/* 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, &qup->q2e);
-	if (error) {
-		errx(1, "quota2_dict_get_q2e_usage: %s\n",
-		    strerror(error));
-	}
-	return (1);
-}
-
-int
 getnfsquota(fst, fs, qup, id, quotatype)
 	struct statvfs *fst;
 	struct fstab *fs; 
@@ -811,5 +656,106 @@
 		if (!isdigit(c))
 			return (0);
 	} while ((c = *s++) != 0);
+	return (1);
+}
+
+const char *qfextension[] = INITQFNAMES;
+
+int
+getufsquota(const char *mp, struct quota2_entry *q2e, long id, int type,
+    int defaultq, int debug)
+{
+	prop_dictionary_t dict, data, cmd;
+	prop_array_t cmds, datas;
+	struct plistref pref;
+	int error;
+	int8_t error8;
+	bool ret;
+
+	dict = quota2_prop_create();
+	cmds = prop_array_create();
+	datas = prop_array_create();
+	data = prop_dictionary_create();
+
+	if (dict == NULL || cmds == NULL || datas == NULL || data == NULL)
+		errx(1, "can't allocate proplist");
+
+	if (defaultq)
+		ret = prop_dictionary_set_cstring(data, "id", "default");
+	else
+		ret = prop_dictionary_set_uint32(data, "id", id);
+	if (!ret)
+		err(1, "prop_dictionary_set(id)");
+		
+	if (!prop_array_add(datas, data))
+		err(1, "prop_array_add(data)");
+	prop_object_release(data);
+	if (!quota2_prop_add_command(cmds, "get", qfextension[type], datas))
+		err(1, "prop_add_command");
+	if (!prop_dictionary_set(dict, "commands", cmds))
+		err(1, "prop_dictionary_set(command)");
+	if (debug)
+		printf("message to kernel:\n%s\n",
+		    prop_dictionary_externalize(dict));
+
+	if (!prop_dictionary_send_syscall(dict, &pref))
+		err(1, "prop_dictionary_send_syscall");
+	prop_object_release(dict);
+
+	if (quotactl(mp, &pref) != 0)
+		err(1, "quotactl");
+	
+	if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) {
+		errx(1, "prop_dictionary_recv_syscall: %s\n",
+		    strerror(error));
+	}
+	if (debug)
+		printf("reply from kernel:\n%s\n",
+		    prop_dictionary_externalize(dict));
+	if ((error = quota2_get_cmds(dict, &cmds)) != 0) {
+		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));
+		}
+		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);
 }

cvs diff -r1.5 -r1.5.64.1 src/usr.sbin/repquota/Makefile (expand / switch to context diff)
--- src/usr.sbin/repquota/Makefile 1997/10/18 04:37:59 1.5
+++ src/usr.sbin/repquota/Makefile 2011/01/21 16:58:06 1.5.64.1
@@ -1,7 +1,18 @@
 #	from: @(#)Makefile	8.1 (Berkeley) 6/6/93
-#	$NetBSD: Makefile,v 1.5 1997/10/18 04:37:59 lukem Exp $
+#	$NetBSD: Makefile,v 1.5.64.1 2011/01/21 16:58:06 bouyer Exp $
 
+.include <bsd.own.mk>
 PROG=	repquota
+SRCS=	repquota.c 
 MAN=	repquota.8
+
+CPPFLAGS+=-I${NETBSDSRCDIR}/sys -I${NETBSDSRCDIR}/usr.bin/quota
+DPADD=	${LIBPROP}
+LDADD=	-lprop
+
+.PATH:	${NETBSDSRCDIR}/usr.bin/quota
+SRCS+=	printquota.c
+.PATH:	${NETBSDSRCDIR}/sys/ufs/ufs 
+SRCS+=	quota2_prop.c
 
 .include <bsd.prog.mk>

cvs diff -r1.9 -r1.9.50.1 src/usr.sbin/repquota/repquota.8 (expand / switch to context diff)
--- src/usr.sbin/repquota/repquota.8 2003/08/07 11:25:41 1.9
+++ src/usr.sbin/repquota/repquota.8 2011/01/21 16:58:07 1.9.50.1
@@ -29,9 +29,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     from: @(#)repquota.8	8.1 (Berkeley) 6/6/93
-.\"	$NetBSD: repquota.8,v 1.9 2003/08/07 11:25:41 agc Exp $
+.\"	$NetBSD: repquota.8,v 1.9.50.1 2011/01/21 16:58:07 bouyer Exp $
 .\"
-.Dd June 6, 1993
+.Dd January 21, 2011
 .Dt REPQUOTA 8
 .Os
 .Sh NAME
@@ -39,11 +39,15 @@
 .Nd summarize quotas for a file system
 .Sh SYNOPSIS
 .Nm
+.Op Fl h
+.Op Fl D
 .Op Fl g
 .Op Fl u
 .Op Fl v
 .Ar filesystem Ar ...
 .Nm
+.Op Fl h
+.Op Fl D
 .Op Fl g
 .Op Fl u
 .Op Fl v
@@ -56,8 +60,7 @@
 Available options:
 .Bl -tag -width Ds
 .It Fl a
-Print the quotas of all the filesystems listed in
-.Pa /etc/fstab .
+Print the quotas of all the mounted filesystems.
 .It Fl g
 Print only group quotas (the default is to print both
 group and user quotas if they exist).
@@ -66,24 +69,20 @@
 group and user quotas if they exist).
 .It Fl v
 Print a header line before printing each filesystem quotas.
+.It Fl D
+Debug: print plist sent to and received from kernel.
+.It Fl h
+Numbers are displayed in a human readable format.
 .El
 .Pp
 For each user or group, the current
-number files and amount of space (in kilobytes) is
+number files and amount of space (in kilobytes, unless the
+.Fl h
+flag is used) is
 printed, along with any quotas created with
 .Xr edquota 8 .
 .Pp
-Only members of the operator group or the super-user may
-use this command.
-.Sh FILES
-.Bl -tag -width quota.group -compact
-.It Pa quota.user
-at the filesystem root with user quotas
-.It Pa quota.group
-at the filesystem root with group quotas
-.It Pa /etc/fstab
-for file system names and locations
-.El
+Only the super-user may use this command.
 .Sh DIAGNOSTICS
 Various messages about inaccessible files; self-explanatory.
 .Sh SEE ALSO

cvs diff -r1.25 -r1.25.2.1 src/usr.sbin/repquota/repquota.c (expand / switch to context diff)
--- src/usr.sbin/repquota/repquota.c 2010/02/17 18:55:14 1.25
+++ src/usr.sbin/repquota/repquota.c 2011/01/21 16:58:07 1.25.2.1
@@ -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 2010/02/17 18:55:14 bouyer Exp $");
+__RCSID("$NetBSD: repquota.c,v 1.25.2.1 2011/01/21 16:58:07 bouyer Exp $");
 #endif
 #endif /* not lint */
 
@@ -49,9 +49,13 @@
  */
 #include <sys/param.h>
 #include <sys/stat.h>
-#include <sys/queue.h>
-#include <ufs/ufs/quota.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include <prop/proplib.h>
+#include <sys/quota.h>
+
 #include <errno.h>
+#include <err.h>
 #include <fstab.h>
 #include <grp.h>
 #include <pwd.h>
@@ -60,12 +64,17 @@
 #include <string.h>
 #include <unistd.h>
 
-const char *qfname = QUOTAFILENAME;
+#include <ufs/ufs/quota2_prop.h>
+#include <ufs/ufs/quota1.h>
+
+#include <printquota.h>
+
 const char *qfextension[] = INITQFNAMES;
+const char *qfname = QUOTAFILENAME;
 
 struct fileusage {
 	struct	fileusage *fu_next;
-	struct	dqblk fu_dqblk;
+	struct	quota2_entry fu_q2e;
 	u_long	fu_id;
 	char	fu_name[1];
 	/* actually bigger */
@@ -73,33 +82,39 @@
 #define FUHASH 1024	/* must be power of two */
 struct fileusage *fuhead[MAXQUOTAS][FUHASH];
 u_long highid[MAXQUOTAS];	/* highest addid()'ed identifier per type */
+struct quota2_entry defaultq2e[MAXQUOTAS];
 
-int	vflag;			/* verbose */
-int	aflag;			/* all file systems */
+int	vflag = 0;		/* verbose */
+int	aflag = 0;		/* all file systems */
+int	Dflag = 0;		/* debug */
+int	hflag = 0;		/* debug */
 
-struct fileusage *addid __P((u_long, int, const char *));
-int	hasquota __P((struct fstab *, int, char **));
-struct fileusage *lookup __P((u_long, int));
-int	main __P((int, char **));
-int	oneof __P((const char *, char **, int));
-int	repquota __P((struct fstab *, int, char *));
-const char *timeprt __P((time_t));
-void	usage __P((void));
+struct fileusage *addid(u_long, int, const char *);
+int	hasquota(struct fstab *, int, char **);
+struct fileusage *lookup(u_long, int);
+int	main(int, char **);
+int	oneof(const char *, char **, int);
+int	repquota(const struct statvfs *, int);
+int	repquota2(const struct statvfs *, int);
+int	repquota1(const struct statvfs *, int);
+void	usage(void);
+void	printquotas(int, const struct statvfs *);
+void	dqblk2q2e(const struct dqblk *, struct quota2_entry *);
 
 int
 main(argc, argv)
 	int argc;
 	char **argv;
 {
-	struct fstab *fs;
 	struct passwd *pw;
 	struct group *gr;
 	int gflag = 0, uflag = 0, errs = 0;
 	long i, argnum, done = 0;
-	char *qfnp;
 	int ch;
+	struct statvfs *fst;
+	int nfst;
 
-	while ((ch = getopt(argc, argv, "aguv")) != -1) {
+	while ((ch = getopt(argc, argv, "Daguhv")) != -1) {
 		switch(ch) {
 		case 'a':
 			aflag++;
@@ -110,9 +125,15 @@
 		case 'u':
 			uflag++;
 			break;
+		case 'h':
+			hflag++;
+			break;
 		case 'v':
 			vflag++;
 			break;
+		case 'D':
+			Dflag++;
+			break;
 		default:
 			usage();
 		}
@@ -138,30 +159,34 @@
 			(void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
 		endpwent();
 	}
-	setfsent();
-	while ((fs = getfsent()) != NULL) {
-		if (strcmp(fs->fs_vfstype, "ffs"))
+
+	nfst = getmntinfo(&fst, MNT_WAIT);
+	if (nfst == 0)
+		errx(2, "no filesystems mounted!");
+	for (i = 0; i < nfst; i++) {
+		if (strncmp(fst[i].f_fstypename, "ffs",
+		    sizeof(fst[i].f_fstypename)) != 0 ||
+		    (fst[i].f_flag & ST_QUOTA) == 0)
 			continue;
 		if (aflag) {
-			if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
-				errs += repquota(fs, GRPQUOTA, qfnp);
-			if (uflag && hasquota(fs, USRQUOTA, &qfnp))
-				errs += repquota(fs, USRQUOTA, qfnp);
+			if (gflag)
+				errs += repquota(&fst[i], GRPQUOTA);
+			if (uflag)
+				errs += repquota(&fst[i], USRQUOTA);
 			continue;
 		}
-		if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
-		    (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
+		if ((argnum = oneof(fst[i].f_mntonname, argv, argc)) >= 0 ||
+		    (argnum = oneof(fst[i].f_mntfromname, argv, argc)) >= 0) {
 			done |= 1 << argnum;
-			if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
-				errs += repquota(fs, GRPQUOTA, qfnp);
-			if (uflag && hasquota(fs, USRQUOTA, &qfnp))
-				errs += repquota(fs, USRQUOTA, qfnp);
+			if (gflag)
+				errs += repquota(&fst[i], GRPQUOTA);
+			if (uflag)
+				errs += repquota(&fst[i], USRQUOTA);
 		}
 	}
-	endfsent();
 	for (i = 0; i < argc; i++)
 		if ((done & (1 << i)) == 0)
-			fprintf(stderr, "%s not found in fstab\n", argv[i]);
+			fprintf(stderr, "%s not mounted\n", argv[i]);
 	exit(errs);
 }
 
@@ -169,36 +194,150 @@
 usage()
 {
 	fprintf(stderr, "usage:\n\t%s\n\t%s\n",
-		"repquota [-v] [-g] [-u] -a",
-		"repquota [-v] [-g] [-u] filesys ...");
+		"repquota [-D] [-v] [-g] [-u] -a",
+		"repquota [-D] [-v] [-g] [-u] filesys ...");
 	exit(1);
 }
 
 int
-repquota(fs, type, qfpathname)
-	struct fstab *fs;
-	int type;
-	char *qfpathname;
+repquota(const struct statvfs *vfs, int type)
 {
+	if (repquota2(vfs, type) != 0)
+		return (repquota1(vfs, type));
+	return 0;
+}
+
+int
+repquota2(const struct statvfs *vfs, int type)
+{
+	prop_dictionary_t dict, data, cmd;
+	prop_array_t cmds, datas;
+	struct plistref pref;
+	int error;
+	int8_t error8;
+	prop_object_iterator_t iter;
+	struct quota2_entry *q2ep;
 	struct fileusage *fup;
+	const char *strid;
+	uint32_t id;
+
+	dict = quota2_prop_create();
+	cmds = prop_array_create();
+	datas = prop_array_create();
+
+	if (dict == NULL || cmds == NULL || datas == NULL)
+		errx(1, "can't allocate proplist");
+	if (!quota2_prop_add_command(cmds, "getall", qfextension[type], datas))
+		err(1, "prop_add_command");
+	if (!prop_dictionary_set(dict, "commands", cmds))
+		err(1, "prop_dictionary_set(command)");
+	if (Dflag)
+		printf("message to kernel:\n%s\n",
+		    prop_dictionary_externalize(dict));
+	if (!prop_dictionary_send_syscall(dict, &pref))
+		err(1, "prop_dictionary_send_syscall");
+	prop_object_release(dict);
+
+	if (quotactl(vfs->f_mntonname, &pref) != 0)
+		err(1, "quotactl");
+
+	if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) {
+		errx(1, "prop_dictionary_recv_syscall: %s\n",
+		    strerror(error));
+	}
+	if (Dflag)
+		printf("reply from kernel:\n%s\n",
+		    prop_dictionary_externalize(dict));
+	if ((error = quota2_get_cmds(dict, &cmds)) != 0) {
+		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);
+			}
+			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(iter);
+	prop_object_release(dict);
+	printquotas(type, vfs);
+	return (0);
+}
+
+int repquota1(const struct statvfs *vfs, int type)
+{
+	char *qfpathname;
+	struct fstab *fs;
+	struct fileusage *fup;
 	FILE *qf;
 	u_long id;
 	struct dqblk dqbuf;
-	static struct dqblk zerodqblk;
-	static int warned = 0;
-	static int multiple = 0;
 
+#if 0
+	static int warned = 0;
 	if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 &&
 	    errno == EOPNOTSUPP && !warned && vflag) {
 		warned++;
 		fprintf(stdout,
 		    "*** Warning: Quotas are not compiled into this kernel\n");
 	}
-	if (multiple++)
-		printf("\n");
-	if (vflag)
-		fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
-		    qfextension[type], fs->fs_file, fs->fs_spec);
+#endif
+	setfsent();
+	while ((fs = getfsent()) != NULL) {
+		if (strcmp(fs->fs_vfstype, "ffs") == 0 &&
+		   strcmp(fs->fs_file, vfs->f_mntonname) == 0)
+			break;
+	}
+	endfsent();
+	if (fs == NULL) {
+		fprintf(stderr, "%s not found in fstab\n", vfs->f_mntonname);
+		return 1;
+	}
+	if (!hasquota(fs, type, &qfpathname))
+		return 0;
+		
 	if ((qf = fopen(qfpathname, "r")) == NULL) {
 		perror(qfpathname);
 		return (1);
@@ -211,9 +350,25 @@
 			continue;
 		if ((fup = lookup(id, type)) == 0)
 			fup = addid(id, type, (char *)0);
-		fup->fu_dqblk = dqbuf;
+		dqblk2q2e(&dqbuf, &fup->fu_q2e);
 	}
 	fclose(qf);
+	printquotas(type, vfs);
+	return (0);
+}
+
+void
+printquotas(int type, const struct statvfs *vfs)
+{
+	static int multiple = 0;
+	u_long id;
+	struct fileusage *fup;
+
+	if (multiple++)
+		printf("\n");
+	if (vflag)
+		fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
+		    qfextension[type], vfs->f_mntonname, vfs->f_mntfromname);
 	printf("                        Block limits               File limits\n");
 	printf(type == USRQUOTA ? "User " : "Group");
 	printf("            used     soft     hard  grace      used    soft    hard  grace\n");
@@ -221,38 +376,45 @@
 		fup = lookup(id, type);
 		if (fup == 0)
 			continue;
-		if (fup->fu_dqblk.dqb_curinodes == 0 &&
-		    fup->fu_dqblk.dqb_curblocks == 0)
+		if (fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur == 0 &&
+		    fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur == 0)
 			continue;
 		if (strlen(fup->fu_name) > 9)
 			printf("%s ", fup->fu_name);
 		else
 			printf("%-10s", fup->fu_name);
-		printf("%c%c%9d%9d%9d%7s",
-			fup->fu_dqblk.dqb_bsoftlimit && 
-			    fup->fu_dqblk.dqb_curblocks >= 
-			    fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-',
-			fup->fu_dqblk.dqb_isoftlimit &&
-			    fup->fu_dqblk.dqb_curinodes >=
-			    fup->fu_dqblk.dqb_isoftlimit ? '+' : '-',
-			(int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_curblocks) / 1024),
-			(int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_bsoftlimit) / 1024),
-			(int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_bhardlimit) / 1024),
-			fup->fu_dqblk.dqb_bsoftlimit && 
-			    fup->fu_dqblk.dqb_curblocks >= 
-			    fup->fu_dqblk.dqb_bsoftlimit ?
-			    timeprt(fup->fu_dqblk.dqb_btime) : "");
-		printf("  %8d%8d%8d%7s\n",
-			fup->fu_dqblk.dqb_curinodes,
-			fup->fu_dqblk.dqb_isoftlimit,
-			fup->fu_dqblk.dqb_ihardlimit,
-			fup->fu_dqblk.dqb_isoftlimit &&
-			    fup->fu_dqblk.dqb_curinodes >=
-			    fup->fu_dqblk.dqb_isoftlimit ?
-			    timeprt(fup->fu_dqblk.dqb_itime) : "");
-		fup->fu_dqblk = zerodqblk;
+		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 >= 
+			    fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit ?
+			    '+' : '-',
+			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 ?
+			    '+' : '-',
+			intprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur,
+				HN_B, hflag),
+			intprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit,
+				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) : "");
+		printf("  %8s%8s%8s%7s\n",
+			intprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur,
+				0, hflag),
+			intprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit,
+				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) : "");
+		memset(&fup->fu_q2e, 0, sizeof(fup->fu_q2e));
 	}
-	return (0);
 }
 
 /*
@@ -365,33 +527,16 @@
 	return (fup);
 }
 
-/*
+void
- * Calculate the grace period and return a printable string for it.
+dqblk2q2e(const struct dqblk *dqblk, struct quota2_entry *q2e)
- */
+{ 
-const char *
+	q2e->q2e_val[Q2V_BLOCK].q2v_hardlimit = dqblk->dqb_bhardlimit;  
-timeprt(seconds)
+	q2e->q2e_val[Q2V_BLOCK].q2v_softlimit = dqblk->dqb_bsoftlimit; 
-	time_t seconds;
+	q2e->q2e_val[Q2V_BLOCK].q2v_cur       = dqblk->dqb_curblocks;
-{
+	q2e->q2e_val[Q2V_BLOCK].q2v_time      = dqblk->dqb_btime;
-	time_t hours, minutes;
+  
-	static char buf[20];
+	q2e->q2e_val[Q2V_FILE].q2v_hardlimit = dqblk->dqb_ihardlimit;
-	static time_t now;
+	q2e->q2e_val[Q2V_FILE].q2v_softlimit = dqblk->dqb_isoftlimit;
-
+	q2e->q2e_val[Q2V_FILE].q2v_cur       = dqblk->dqb_curinodes;
-	if (now == 0)
+	q2e->q2e_val[Q2V_FILE].q2v_time      = dqblk->dqb_itime;
-		time(&now);
+} 
-	if (now > seconds)
-		return ("none");
-	seconds -= now;
-	minutes = (seconds + 30) / 60;
-	hours = (minutes + 30) / 60;
-	if (hours >= 36) {
-		sprintf(buf, "%lddays", (long)((hours + 12) / 24));
-		return (buf);
-	}
-	if (minutes >= 60) {
-		sprintf(buf, "%2ld:%ld", (long)(minutes / 60),
-		    (long)(minutes % 60));
-		return (buf);
-	}
-	sprintf(buf, "%2ld", (long)minutes);
-	return (buf);
-}