Module Name: src Committed By: bouyer Date: Fri Jan 21 16:58:07 UTC 2011
Modified Files: src/sys/ufs/ufs [bouyer-quota2]: quota2.h quota2_prop.c quota2_prop.h ufs_quota.c ufs_quota.h ufs_quota2.c src/usr.bin/quota [bouyer-quota2]: Makefile quota.1 quota.c src/usr.sbin/repquota [bouyer-quota2]: Makefile repquota.8 repquota.c Added Files: src/usr.bin/quota [bouyer-quota2]: printquota.c printquota.h Log Message: Add support for quotactl("getall") command, and convert repquota to new world. To generate a diff of this commit: cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/quota2.h \ src/sys/ufs/ufs/quota2_prop.c src/sys/ufs/ufs/quota2_prop.h \ src/sys/ufs/ufs/ufs_quota.h src/sys/ufs/ufs/ufs_quota2.c cvs rdiff -u -r1.68.4.1 -r1.68.4.2 src/sys/ufs/ufs/ufs_quota.c cvs rdiff -u -r1.6.64.1 -r1.6.64.2 src/usr.bin/quota/Makefile cvs rdiff -u -r0 -r1.1.2.1 src/usr.bin/quota/printquota.c \ src/usr.bin/quota/printquota.h cvs rdiff -u -r1.14.52.2 -r1.14.52.3 src/usr.bin/quota/quota.1 cvs rdiff -u -r1.33.2.1 -r1.33.2.2 src/usr.bin/quota/quota.c cvs rdiff -u -r1.5 -r1.5.64.1 src/usr.sbin/repquota/Makefile cvs rdiff -u -r1.9 -r1.9.50.1 src/usr.sbin/repquota/repquota.8 cvs rdiff -u -r1.25 -r1.25.2.1 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/quota2.h diff -u src/sys/ufs/ufs/quota2.h:1.1.2.1 src/sys/ufs/ufs/quota2.h:1.1.2.2 --- src/sys/ufs/ufs/quota2.h:1.1.2.1 Thu Jan 20 14:25:03 2011 +++ src/sys/ufs/ufs/quota2.h Fri Jan 21 16:58:06 2011 @@ -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_ */ Index: src/sys/ufs/ufs/quota2_prop.c diff -u src/sys/ufs/ufs/quota2_prop.c:1.1.2.1 src/sys/ufs/ufs/quota2_prop.c:1.1.2.2 --- src/sys/ufs/ufs/quota2_prop.c:1.1.2.1 Thu Jan 20 14:25:03 2011 +++ src/sys/ufs/ufs/quota2_prop.c Fri Jan 21 16:58:06 2011 @@ -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, Index: src/sys/ufs/ufs/quota2_prop.h diff -u src/sys/ufs/ufs/quota2_prop.h:1.1.2.1 src/sys/ufs/ufs/quota2_prop.h:1.1.2.2 --- src/sys/ufs/ufs/quota2_prop.h:1.1.2.1 Thu Jan 20 14:25:03 2011 +++ src/sys/ufs/ufs/quota2_prop.h Fri Jan 21 16:58:06 2011 @@ -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); Index: src/sys/ufs/ufs/ufs_quota.h diff -u src/sys/ufs/ufs/ufs_quota.h:1.1.2.1 src/sys/ufs/ufs/ufs_quota.h:1.1.2.2 --- src/sys/ufs/ufs/ufs_quota.h:1.1.2.1 Thu Jan 20 14:25:03 2011 +++ src/sys/ufs/ufs/ufs_quota.h Fri Jan 21 16:58:06 2011 @@ -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 *); Index: src/sys/ufs/ufs/ufs_quota2.c diff -u src/sys/ufs/ufs/ufs_quota2.c:1.1.2.1 src/sys/ufs/ufs/ufs_quota2.c:1.1.2.2 --- src/sys/ufs/ufs/ufs_quota2.c:1.1.2.1 Thu Jan 20 14:25:03 2011 +++ src/sys/ufs/ufs/ufs_quota2.c Fri Jan 21 16:58:06 2011 @@ -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,21 +425,72 @@ 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; } @@ -377,42 +500,57 @@ 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; } Index: src/sys/ufs/ufs/ufs_quota.c diff -u src/sys/ufs/ufs/ufs_quota.c:1.68.4.1 src/sys/ufs/ufs/ufs_quota.c:1.68.4.2 --- src/sys/ufs/ufs/ufs_quota.c:1.68.4.1 Thu Jan 20 14:25:03 2011 +++ src/sys/ufs/ufs/ufs_quota.c Fri Jan 21 16:58:06 2011 @@ -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 = 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 = (prop_dictionary_set_int8(cmddict, "return", 0) ? - 0 : ENOMEM); + error = 0; } return error; } Index: src/usr.bin/quota/Makefile diff -u src/usr.bin/quota/Makefile:1.6.64.1 src/usr.bin/quota/Makefile:1.6.64.2 --- src/usr.bin/quota/Makefile:1.6.64.1 Thu Jan 20 14:25:05 2011 +++ src/usr.bin/quota/Makefile Fri Jan 21 16:58:06 2011 @@ -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 Index: src/usr.bin/quota/quota.1 diff -u src/usr.bin/quota/quota.1:1.14.52.2 src/usr.bin/quota/quota.1:1.14.52.3 --- src/usr.bin/quota/quota.1:1.14.52.2 Fri Jan 21 16:36:57 2011 +++ src/usr.bin/quota/quota.1 Fri Jan 21 16:58:06 2011 @@ -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 , Index: src/usr.bin/quota/quota.c diff -u src/usr.bin/quota/quota.c:1.33.2.1 src/usr.bin/quota/quota.c:1.33.2.2 --- src/usr.bin/quota/quota.c:1.33.2.1 Thu Jan 20 14:25:05 2011 +++ src/usr.bin/quota/quota.c Fri Jan 21 16:58:06 2011 @@ -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,108 +506,9 @@ } 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; @@ -813,3 +658,104 @@ } 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); +} Index: src/usr.sbin/repquota/Makefile diff -u src/usr.sbin/repquota/Makefile:1.5 src/usr.sbin/repquota/Makefile:1.5.64.1 --- src/usr.sbin/repquota/Makefile:1.5 Sat Oct 18 04:37:59 1997 +++ src/usr.sbin/repquota/Makefile Fri Jan 21 16:58:06 2011 @@ -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> Index: src/usr.sbin/repquota/repquota.8 diff -u src/usr.sbin/repquota/repquota.8:1.9 src/usr.sbin/repquota/repquota.8:1.9.50.1 --- src/usr.sbin/repquota/repquota.8:1.9 Thu Aug 7 11:25:41 2003 +++ src/usr.sbin/repquota/repquota.8 Fri Jan 21 16:58:07 2011 @@ -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 Index: src/usr.sbin/repquota/repquota.c diff -u src/usr.sbin/repquota/repquota.c:1.25 src/usr.sbin/repquota/repquota.c:1.25.2.1 --- src/usr.sbin/repquota/repquota.c:1.25 Wed Feb 17 18:55:14 2010 +++ src/usr.sbin/repquota/repquota.c Fri Jan 21 16:58:07 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 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 */ - -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)); +int vflag = 0; /* verbose */ +int aflag = 0; /* all file systems */ +int Dflag = 0; /* debug */ +int hflag = 0; /* debug */ + +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); } -/* - * Calculate the grace period and return a printable string for it. - */ -const char * -timeprt(seconds) - 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) { - 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); -} +void +dqblk2q2e(const struct dqblk *dqblk, struct quota2_entry *q2e) +{ + q2e->q2e_val[Q2V_BLOCK].q2v_hardlimit = dqblk->dqb_bhardlimit; + q2e->q2e_val[Q2V_BLOCK].q2v_softlimit = dqblk->dqb_bsoftlimit; + q2e->q2e_val[Q2V_BLOCK].q2v_cur = dqblk->dqb_curblocks; + q2e->q2e_val[Q2V_BLOCK].q2v_time = dqblk->dqb_btime; + + q2e->q2e_val[Q2V_FILE].q2v_hardlimit = dqblk->dqb_ihardlimit; + q2e->q2e_val[Q2V_FILE].q2v_softlimit = dqblk->dqb_isoftlimit; + q2e->q2e_val[Q2V_FILE].q2v_cur = dqblk->dqb_curinodes; + q2e->q2e_val[Q2V_FILE].q2v_time = dqblk->dqb_itime; +} Added files: Index: src/usr.bin/quota/printquota.c diff -u /dev/null src/usr.bin/quota/printquota.c:1.1.2.1 --- /dev/null Fri Jan 21 16:58:07 2011 +++ src/usr.bin/quota/printquota.c Fri Jan 21 16:58:06 2011 @@ -0,0 +1,116 @@ +/* $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); +} Index: src/usr.bin/quota/printquota.h diff -u /dev/null src/usr.bin/quota/printquota.h:1.1.2.1 --- /dev/null Fri Jan 21 16:58:07 2011 +++ src/usr.bin/quota/printquota.h Fri Jan 21 16:58:06 2011 @@ -0,0 +1,4 @@ +/* $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);