Add support for quotactl("getall") command, and convert repquota to new world.diff -r1.1.2.1 -r1.1.2.2 src/sys/ufs/ufs/quota2.h
(bouyer)
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: quota2.h,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */ | 1 | /* $NetBSD: quota2.h,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2010 Manuel Bouyer | 3 | * Copyright (c) 2010 Manuel Bouyer | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * This software is distributed under the following condiions | 5 | * This software is distributed under the following condiions | |
6 | * compliant with the NetBSD foundation policy. | 6 | * compliant with the NetBSD foundation policy. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
@@ -87,15 +87,14 @@ struct quota2_header { | @@ -87,15 +87,14 @@ struct quota2_header { | |||
87 | 87 | |||
88 | #define Q2_HEAD_MAGIC 0xb746915e | 88 | #define Q2_HEAD_MAGIC 0xb746915e | |
89 | 89 | |||
90 | /* superblock flags */ | 90 | /* superblock flags */ | |
91 | #define FS_Q2_DO_TYPE(type) (0x01 << (type)) | 91 | #define FS_Q2_DO_TYPE(type) (0x01 << (type)) | |
92 | 92 | |||
93 | #define off2qindex(hsize, off) (((off) - (hsize)) / sizeof(struct quota2_entry)) | 93 | #define off2qindex(hsize, off) (((off) - (hsize)) / sizeof(struct quota2_entry)) | |
94 | #define qindex2off(hsize, idx) \ | 94 | #define qindex2off(hsize, idx) \ | |
95 | ((daddr_t)(idx) * sizeof(struct quota2_entry) + (hsize)) | 95 | ((daddr_t)(idx) * sizeof(struct quota2_entry) + (hsize)) | |
96 | 96 | |||
97 | /* quota2_subr.c */ | 97 | /* quota2_subr.c */ | |
98 | void quota2_addfreeq2e(struct quota2_header *, void *, uint64_t, uint64_t, int); | 98 | void quota2_addfreeq2e(struct quota2_header *, void *, uint64_t, uint64_t, int); | |
99 | void quota2_create_blk0(uint64_t, void *bp, int, int, int); | 99 | void quota2_create_blk0(uint64_t, void *bp, int, int, int); | |
100 | ||||
101 | #endif /* _UFS_UFS_QUOTA2_H_ */ | 100 | #endif /* _UFS_UFS_QUOTA2_H_ */ |
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: quota2_prop.c,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */ | 1 | /* $NetBSD: quota2_prop.c,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2010 Manuel Bouyer | 3 | * Copyright (c) 2010 Manuel Bouyer | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * This software is distributed under the following condiions | 5 | * This software is distributed under the following condiions | |
6 | * compliant with the NetBSD foundation policy. | 6 | * compliant with the NetBSD foundation policy. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
@@ -85,28 +85,26 @@ quota2_dict_get_q2v_usage(prop_dictionar | @@ -85,28 +85,26 @@ quota2_dict_get_q2v_usage(prop_dictionar | |||
85 | return EINVAL; | 85 | return EINVAL; | |
86 | q2v->q2v_cur = vu; | 86 | q2v->q2v_cur = vu; | |
87 | if (!prop_dictionary_get_int64(dict, "expire time", &v)) | 87 | if (!prop_dictionary_get_int64(dict, "expire time", &v)) | |
88 | return EINVAL; | 88 | return EINVAL; | |
89 | q2v->q2v_time = v; | 89 | q2v->q2v_time = v; | |
90 | return 0; | 90 | return 0; | |
91 | } | 91 | } | |
92 | 92 | |||
93 | int | 93 | int | |
94 | quota2_dict_get_q2e_usage(prop_dictionary_t data, struct quota2_entry *q2e) | 94 | quota2_dict_get_q2e_usage(prop_dictionary_t data, struct quota2_entry *q2e) | |
95 | { | 95 | { | |
96 | int i, error; | 96 | int i, error; | |
97 | prop_dictionary_t val; | 97 | prop_dictionary_t val; | |
98 | if (!prop_dictionary_get_uint32(data, "id", &q2e->q2e_uid)) | |||
99 | return EINVAL; | |||
100 | for (i = 0; i < NQ2V; i++) { | 98 | for (i = 0; i < NQ2V; i++) { | |
101 | val = prop_dictionary_get_dict(data, quota2_valnames[i]); | 99 | val = prop_dictionary_get_dict(data, quota2_valnames[i]); | |
102 | if (val == NULL) | 100 | if (val == NULL) | |
103 | return EINVAL; | 101 | return EINVAL; | |
104 | error = quota2_dict_get_q2v_usage(val, &q2e->q2e_val[i]); | 102 | error = quota2_dict_get_q2v_usage(val, &q2e->q2e_val[i]); | |
105 | if (error) | 103 | if (error) | |
106 | return error; | 104 | return error; | |
107 | } | 105 | } | |
108 | return 0; | 106 | return 0; | |
109 | } | 107 | } | |
110 | 108 | |||
111 | int | 109 | int | |
112 | quota2_get_cmds(prop_dictionary_t qdict, prop_array_t *cmds) | 110 | quota2_get_cmds(prop_dictionary_t qdict, prop_array_t *cmds) | |
@@ -125,26 +123,36 @@ quota2_get_cmds(prop_dictionary_t qdict, | @@ -125,26 +123,36 @@ quota2_get_cmds(prop_dictionary_t qdict, | |||
125 | return EINVAL; | 123 | return EINVAL; | |
126 | if (prop_number_integer_value(pn) != 2) | 124 | if (prop_number_integer_value(pn) != 2) | |
127 | return EINVAL; | 125 | return EINVAL; | |
128 | 126 | |||
129 | o = prop_dictionary_get(qdict, "commands"); | 127 | o = prop_dictionary_get(qdict, "commands"); | |
130 | if (o == NULL) | 128 | if (o == NULL) | |
131 | return ENOMEM; | 129 | return ENOMEM; | |
132 | if(prop_object_type(o) != PROP_TYPE_ARRAY) | 130 | if(prop_object_type(o) != PROP_TYPE_ARRAY) | |
133 | return EINVAL; | 131 | return EINVAL; | |
134 | *cmds = o; | 132 | *cmds = o; | |
135 | return 0; | 133 | return 0; | |
136 | } | 134 | } | |
137 | 135 | |||
136 | bool | |||
137 | prop_array_add_and_rel(prop_array_t array, prop_object_t po) | |||
138 | { | |||
139 | bool ret; | |||
140 | if (po == NULL) | |||
141 | return false; | |||
142 | ret = prop_array_add(array, po); | |||
143 | prop_object_release(po); | |||
144 | return ret; | |||
145 | } | |||
138 | 146 | |||
139 | bool | 147 | bool | |
140 | prop_dictionary_set_and_rel(prop_dictionary_t dict, const char *key, | 148 | prop_dictionary_set_and_rel(prop_dictionary_t dict, const char *key, | |
141 | prop_object_t po) | 149 | prop_object_t po) | |
142 | { | 150 | { | |
143 | bool ret; | 151 | bool ret; | |
144 | if (po == NULL) | 152 | if (po == NULL) | |
145 | return false; | 153 | return false; | |
146 | ret = prop_dictionary_set(dict, key, po); | 154 | ret = prop_dictionary_set(dict, key, po); | |
147 | prop_object_release(po); | 155 | prop_object_release(po); | |
148 | return ret; | 156 | return ret; | |
149 | } | 157 | } | |
150 | 158 |
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: quota2_prop.h,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */ | 1 | /* $NetBSD: quota2_prop.h,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2010 Manuel Bouyer | 3 | * Copyright (c) 2010 Manuel Bouyer | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * This software is distributed under the following condiions | 5 | * This software is distributed under the following condiions | |
6 | * compliant with the NetBSD foundation policy. | 6 | * compliant with the NetBSD foundation policy. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
@@ -26,20 +26,21 @@ | @@ -26,20 +26,21 @@ | |||
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
27 | * POSSIBILITY OF SUCH DAMAGE. | 27 | * POSSIBILITY OF SUCH DAMAGE. | |
28 | */ | 28 | */ | |
29 | 29 | |||
30 | #include <prop/proplib.h> | 30 | #include <prop/proplib.h> | |
31 | #include <ufs/ufs/quota2.h> | 31 | #include <ufs/ufs/quota2.h> | |
32 | 32 | |||
33 | prop_dictionary_t prop_dictionary_get_dict(prop_dictionary_t, const char *); | 33 | prop_dictionary_t prop_dictionary_get_dict(prop_dictionary_t, const char *); | |
34 | int quota2_dict_get_q2v_limits(prop_dictionary_t, struct quota2_val *, bool); | 34 | int quota2_dict_get_q2v_limits(prop_dictionary_t, struct quota2_val *, bool); | |
35 | int quota2_dict_get_q2v_usage(prop_dictionary_t, struct quota2_val *); | 35 | int quota2_dict_get_q2v_usage(prop_dictionary_t, struct quota2_val *); | |
36 | int quota2_dict_get_q2e_usage(prop_dictionary_t, struct quota2_entry *); | 36 | int quota2_dict_get_q2e_usage(prop_dictionary_t, struct quota2_entry *); | |
37 | int quota2_get_cmds(prop_dictionary_t, prop_array_t *); | 37 | int quota2_get_cmds(prop_dictionary_t, prop_array_t *); | |
38 | 38 | |||
39 | bool prop_array_add_and_rel(prop_array_t, prop_object_t); | |||
39 | bool prop_dictionary_set_and_rel(prop_dictionary_t, const char *, | 40 | bool prop_dictionary_set_and_rel(prop_dictionary_t, const char *, | |
40 | prop_object_t); | 41 | prop_object_t); | |
41 | prop_dictionary_t quota2_prop_create(void); | 42 | prop_dictionary_t quota2_prop_create(void); | |
42 | bool quota2_prop_add_command(prop_array_t, const char *, const char *, | 43 | bool quota2_prop_add_command(prop_array_t, const char *, const char *, | |
43 | prop_array_t); | 44 | prop_array_t); | |
44 | prop_dictionary_t q2vtoprop(struct quota2_val *); | 45 | prop_dictionary_t q2vtoprop(struct quota2_val *); | |
45 | prop_dictionary_t q2etoprop(struct quota2_entry *, int); | 46 | prop_dictionary_t q2etoprop(struct quota2_entry *, int); |
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: ufs_quota.h,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */ | 1 | /* $NetBSD: ufs_quota.h,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | 4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Robert Elz at The University of Melbourne. | 8 | * Robert Elz at The University of Melbourne. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -86,28 +86,28 @@ struct dquot { | @@ -86,28 +86,28 @@ struct dquot { | |||
86 | #define dq_curinodes dq_un.dq1_dqb.dqb_curinodes | 86 | #define dq_curinodes dq_un.dq1_dqb.dqb_curinodes | |
87 | #define dq_btime dq_un.dq_dqb.dqb_btime | 87 | #define dq_btime dq_un.dq_dqb.dqb_btime | |
88 | #define dq_itime dq_un.dq_dqb.dqb_itime | 88 | #define dq_itime dq_un.dq_dqb.dqb_itime | |
89 | 89 | |||
90 | #define dq2_lblkno dq_un.dq2_desc.dq2_lblkno | 90 | #define dq2_lblkno dq_un.dq2_desc.dq2_lblkno | |
91 | #define dq2_blkoff dq_un.dq2_desc.dq2_blkoff | 91 | #define dq2_blkoff dq_un.dq2_desc.dq2_blkoff | |
92 | /* | 92 | /* | |
93 | * If the system has never checked for a quota for this file, then it is | 93 | * If the system has never checked for a quota for this file, then it is | |
94 | * set to NODQUOT. Once a write attempt is made the inode pointer is set | 94 | * set to NODQUOT. Once a write attempt is made the inode pointer is set | |
95 | * to reference a dquot structure. | 95 | * to reference a dquot structure. | |
96 | */ | 96 | */ | |
97 | #define NODQUOT NULL | 97 | #define NODQUOT NULL | |
98 | 98 | |||
99 | static kmutex_t dqlock; | 99 | extern kmutex_t dqlock; | |
100 | static kcondvar_t dqcv; | 100 | extern kcondvar_t dqcv; | |
101 | /* | 101 | /* | |
102 | * Quota name to error message mapping. | 102 | * Quota name to error message mapping. | |
103 | */ | 103 | */ | |
104 | static const char *quotatypes[] = INITQFNAMES; | 104 | static const char *quotatypes[] = INITQFNAMES; | |
105 | 105 | |||
106 | /* | 106 | /* | |
107 | * Code pertaining to management of the in-core dquot data structures. | 107 | * Code pertaining to management of the in-core dquot data structures. | |
108 | */ | 108 | */ | |
109 | #define DQHASH(dqvp, id) \ | 109 | #define DQHASH(dqvp, id) \ | |
110 | (((((long)(dqvp)) >> 8) + id) & dqhash) | 110 | (((((long)(dqvp)) >> 8) + id) & dqhash) | |
111 | static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; | 111 | static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; | |
112 | static u_long dqhash; | 112 | static u_long dqhash; | |
113 | static pool_cache_t dquot_cache; | 113 | static pool_cache_t dquot_cache; | |
@@ -118,18 +118,19 @@ void dqref(struct dquot *); | @@ -118,18 +118,19 @@ void dqref(struct dquot *); | |||
118 | void dqrele(struct vnode *, struct dquot *); | 118 | void dqrele(struct vnode *, struct dquot *); | |
119 | void dqflush(struct vnode *); | 119 | void dqflush(struct vnode *); | |
120 | 120 | |||
121 | int chkdq1(struct inode *, int64_t, kauth_cred_t, int); | 121 | int chkdq1(struct inode *, int64_t, kauth_cred_t, int); | |
122 | int chkiq1(struct inode *, int32_t, kauth_cred_t, int); | 122 | int chkiq1(struct inode *, int32_t, kauth_cred_t, int); | |
123 | int getquota1(struct mount *, u_long, int, struct dqblk *); | 123 | int getquota1(struct mount *, u_long, int, struct dqblk *); | |
124 | int setquota1(struct mount *, u_long, int, struct dqblk *); | 124 | int setquota1(struct mount *, u_long, int, struct dqblk *); | |
125 | int q1sync(struct mount *); | 125 | int q1sync(struct mount *); | |
126 | int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | 126 | int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | |
127 | int dq1sync(struct vnode *, struct dquot *); | 127 | int dq1sync(struct vnode *, struct dquot *); | |
128 | 128 | |||
129 | int chkdq2(struct inode *, int64_t, kauth_cred_t, int); | 129 | int chkdq2(struct inode *, int64_t, kauth_cred_t, int); | |
130 | int chkiq2(struct inode *, int32_t, kauth_cred_t, int); | 130 | int chkiq2(struct inode *, int32_t, kauth_cred_t, int); | |
131 | int quota2_handle_cmd_get(struct ufsmount *, const char *, int, int, | 131 | int quota2_handle_cmd_get(struct ufsmount *, int, int, int, | |
132 | prop_array_t); | 132 | prop_array_t); | |
133 | int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t); | |||
133 | int q2sync(struct mount *); | 134 | int q2sync(struct mount *); | |
134 | int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | 135 | int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | |
135 | int dq2sync(struct vnode *, struct dquot *); | 136 | int dq2sync(struct vnode *, struct dquot *); |
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: ufs_quota2.c,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $ */ | 1 | /* $NetBSD: ufs_quota2.c,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2010 Manuel Bouyer | 3 | * Copyright (c) 2010 Manuel Bouyer | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * This software is distributed under the following condiions | 5 | * This software is distributed under the following condiions | |
6 | * compliant with the NetBSD foundation policy. | 6 | * compliant with the NetBSD foundation policy. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
@@ -18,27 +18,27 @@ | @@ -18,27 +18,27 @@ | |||
18 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 18 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
19 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 19 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
20 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 20 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
27 | * POSSIBILITY OF SUCH DAMAGE. | 27 | * POSSIBILITY OF SUCH DAMAGE. | |
28 | */ | 28 | */ | |
29 | 29 | |||
30 | #include <sys/cdefs.h> | 30 | #include <sys/cdefs.h> | |
31 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.1.2.1 2011/01/20 14:25:03 bouyer Exp $"); | 31 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.1.2.2 2011/01/21 16:58:06 bouyer Exp $"); | |
32 | 32 | |||
33 | #include <sys/buf.h> | 33 | #include <sys/buf.h> | |
34 | #include <sys/param.h> | 34 | #include <sys/param.h> | |
35 | #include <sys/kernel.h> | 35 | #include <sys/kernel.h> | |
36 | #include <sys/systm.h> | 36 | #include <sys/systm.h> | |
37 | #include <sys/namei.h> | 37 | #include <sys/namei.h> | |
38 | #include <sys/file.h> | 38 | #include <sys/file.h> | |
39 | #include <sys/proc.h> | 39 | #include <sys/proc.h> | |
40 | #include <sys/vnode.h> | 40 | #include <sys/vnode.h> | |
41 | #include <sys/mount.h> | 41 | #include <sys/mount.h> | |
42 | #include <sys/fstrans.h> | 42 | #include <sys/fstrans.h> | |
43 | #include <sys/kauth.h> | 43 | #include <sys/kauth.h> | |
44 | #include <sys/wapbl.h> | 44 | #include <sys/wapbl.h> | |
@@ -48,26 +48,29 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c | @@ -48,26 +48,29 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c | |||
48 | #include <ufs/ufs/ufsmount.h> | 48 | #include <ufs/ufs/ufsmount.h> | |
49 | #include <ufs/ufs/ufs_bswap.h> | 49 | #include <ufs/ufs/ufs_bswap.h> | |
50 | #include <ufs/ufs/ufs_extern.h> | 50 | #include <ufs/ufs/ufs_extern.h> | |
51 | #include <ufs/ufs/ufs_quota.h> | 51 | #include <ufs/ufs/ufs_quota.h> | |
52 | #include <ufs/ufs/ufs_wapbl.h> | 52 | #include <ufs/ufs/ufs_wapbl.h> | |
53 | #include <ufs/ufs/quota2_prop.h> | 53 | #include <ufs/ufs/quota2_prop.h> | |
54 | 54 | |||
55 | static int getinoquota2(struct inode *, int, struct buf **, | 55 | static int getinoquota2(struct inode *, int, struct buf **, | |
56 | struct quota2_entry **); | 56 | struct quota2_entry **); | |
57 | static int getq2h(struct ufsmount *, int, struct buf **, | 57 | static int getq2h(struct ufsmount *, int, struct buf **, | |
58 | struct quota2_header **, int); | 58 | struct quota2_header **, int); | |
59 | static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, | 59 | static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, | |
60 | struct quota2_entry **, int); | 60 | struct quota2_entry **, int); | |
61 | static int quota2_walk_list(struct ufsmount *, struct buf *, int, | |||
62 | uint64_t *, int, void *, | |||
63 | int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *)); | |||
61 | 64 | |||
62 | static int | 65 | static int | |
63 | getq2h(struct ufsmount *ump, int type, | 66 | getq2h(struct ufsmount *ump, int type, | |
64 | struct buf **bpp, struct quota2_header **q2hp, int flags) | 67 | struct buf **bpp, struct quota2_header **q2hp, int flags) | |
65 | { | 68 | { | |
66 | const int needswap = UFS_MPNEEDSWAP(ump); | 69 | const int needswap = UFS_MPNEEDSWAP(ump); | |
67 | int error; | 70 | int error; | |
68 | struct buf *bp; | 71 | struct buf *bp; | |
69 | struct quota2_header *q2h; | 72 | struct quota2_header *q2h; | |
70 | 73 | |||
71 | error = bread(ump->um_quotas[type], 0, ump->umq2_bsize, | 74 | error = bread(ump->um_quotas[type], 0, ump->umq2_bsize, | |
72 | ump->um_cred[type], flags, &bp); | 75 | ump->um_cred[type], flags, &bp); | |
73 | if (error) | 76 | if (error) | |
@@ -97,26 +100,100 @@ getq2e(struct ufsmount *ump, int type, d | @@ -97,26 +100,100 @@ getq2e(struct ufsmount *ump, int type, d | |||
97 | } | 100 | } | |
98 | error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize, | 101 | error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize, | |
99 | ump->um_cred[type], flags, &bp); | 102 | ump->um_cred[type], flags, &bp); | |
100 | if (error) | 103 | if (error) | |
101 | return error; | 104 | return error; | |
102 | if (bp->b_resid != 0) { | 105 | if (bp->b_resid != 0) { | |
103 | panic("dq2get: %s quota file corrupted", | 106 | panic("dq2get: %s quota file corrupted", | |
104 | quotatypes[type]); | 107 | quotatypes[type]); | |
105 | } | 108 | } | |
106 | *q2ep = (void *)((char *)bp->b_data + blkoffset); | 109 | *q2ep = (void *)((char *)bp->b_data + blkoffset); | |
107 | *bpp = bp; | 110 | *bpp = bp; | |
108 | return 0; | 111 | return 0; | |
109 | } | 112 | } | |
113 | ||||
114 | /* walk a quota entry list, calling the callback for each entry */ | |||
115 | #define Q2WL_ABORT 0x10000000 | |||
116 | ||||
117 | static int | |||
118 | quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type, | |||
119 | uint64_t *offp, int flags, void *a, | |||
120 | int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *)) | |||
121 | { | |||
122 | const int needswap = UFS_MPNEEDSWAP(ump); | |||
123 | daddr_t off = ufs_rw64(*offp, needswap); | |||
124 | struct buf *bp, *obp = hbp; | |||
125 | int ret = 0, ret2 = 0; | |||
126 | struct quota2_entry *q2e; | |||
127 | daddr_t lblkno, blkoff; | |||
128 | ||||
129 | KASSERT(mutex_owner(&dqlock)); | |||
130 | ||||
131 | while (off != 0) { | |||
132 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | |||
133 | blkoff = (off & ump->umq2_bmask); | |||
134 | if (lblkno == 0) { | |||
135 | /* in the header block */ | |||
136 | bp = hbp; | |||
137 | } else { | |||
138 | ret = bread(ump->um_quotas[type], lblkno, | |||
139 | ump->umq2_bsize, | |||
140 | ump->um_cred[type], flags, &bp); | |||
141 | if (ret) | |||
142 | return ret; | |||
143 | if (bp->b_resid != 0) { | |||
144 | panic("quota2_walk_list: %s quota file corrupted", | |||
145 | quotatypes[type]); | |||
146 | } | |||
147 | } | |||
148 | q2e = (void *)((char *)(bp->b_data) + blkoff); | |||
149 | ret = (*func)(ump, offp, q2e, off, a); | |||
150 | if (off != ufs_rw64(*offp, needswap)) { | |||
151 | /* callback changed parent's pointer, redo */ | |||
152 | off = ufs_rw64(*offp, needswap); | |||
153 | if (bp != hbp && bp != obp) | |||
154 | ret2 = VOP_BWRITE(bp); | |||
155 | } else { | |||
156 | /* parent if now current */ | |||
157 | if (obp != bp && obp != hbp) { | |||
158 | if (flags & B_MODIFY) | |||
159 | ret2 = VOP_BWRITE(obp); | |||
160 | else | |||
161 | brelse(obp, 0); | |||
162 | } | |||
163 | obp = bp; | |||
164 | offp = &(q2e->q2e_next); | |||
165 | off = ufs_rw64(*offp, needswap); | |||
166 | } | |||
167 | if (ret) | |||
168 | break; | |||
169 | if (ret2) { | |||
170 | ret = ret2; | |||
171 | break; | |||
172 | } | |||
173 | } | |||
174 | if (obp != hbp) { | |||
175 | if (flags & B_MODIFY) | |||
176 | ret2 = VOP_BWRITE(obp); | |||
177 | else | |||
178 | brelse(obp, 0); | |||
179 | } | |||
180 | if (ret & Q2WL_ABORT) | |||
181 | return 0; | |||
182 | if (ret == 0) | |||
183 | return ret2; | |||
184 | return ret; | |||
185 | } | |||
186 | ||||
110 | void | 187 | void | |
111 | quota2_umount(struct mount *mp) | 188 | quota2_umount(struct mount *mp) | |
112 | { | 189 | { | |
113 | int i, error; | 190 | int i, error; | |
114 | struct ufsmount *ump = VFSTOUFS(mp); | 191 | struct ufsmount *ump = VFSTOUFS(mp); | |
115 | 192 | |||
116 | for (i = 0; i < MAXQUOTAS; i++) { | 193 | for (i = 0; i < MAXQUOTAS; i++) { | |
117 | if (ump->um_quotas[i]) { | 194 | if (ump->um_quotas[i]) { | |
118 | error = vn_close(ump->um_quotas[i], FREAD|FWRITE, | 195 | error = vn_close(ump->um_quotas[i], FREAD|FWRITE, | |
119 | ump->um_cred[i]); | 196 | ump->um_cred[i]); | |
120 | if (error) { | 197 | if (error) { | |
121 | printf("quota2_umount failed: close(%p) %d\n", | 198 | printf("quota2_umount failed: close(%p) %d\n", | |
122 | ump->um_quotas[i], error); | 199 | ump->um_quotas[i], error); | |
@@ -308,116 +385,177 @@ quota2_check(struct inode *ip, int vtype | @@ -308,116 +385,177 @@ quota2_check(struct inode *ip, int vtype | |||
308 | int | 385 | int | |
309 | chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | 386 | chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | |
310 | { | 387 | { | |
311 | return quota2_check(ip, Q2V_BLOCK, change, cred, flags); | 388 | return quota2_check(ip, Q2V_BLOCK, change, cred, flags); | |
312 | } | 389 | } | |
313 | 390 | |||
314 | int | 391 | int | |
315 | chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | 392 | chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | |
316 | { | 393 | { | |
317 | return quota2_check(ip, Q2V_FILE, change, cred, flags); | 394 | return quota2_check(ip, Q2V_FILE, change, cred, flags); | |
318 | } | 395 | } | |
319 | 396 | |||
320 | int | 397 | int | |
321 | quota2_handle_cmd_get(struct ufsmount *ump, const char *type, int id, | 398 | quota2_handle_cmd_get(struct ufsmount *ump, int type, int id, | |
322 | int defaultq, prop_array_t replies) | 399 | int defaultq, prop_array_t replies) | |
323 | { | 400 | { | |
324 | struct dquot *dq; | 401 | struct dquot *dq; | |
325 | int error; | 402 | int error; | |
326 | struct quota2_header *q2h; | 403 | struct quota2_header *q2h; | |
327 | struct quota2_entry *q2e; | 404 | struct quota2_entry *q2e; | |
328 | struct buf *bp; | 405 | struct buf *bp; | |
329 | prop_dictionary_t dict; | 406 | prop_dictionary_t dict; | |
330 | int q2type; | |||
331 | 407 | |||
332 | if (!strcmp(type, "user")) { | 408 | if (ump->um_quotas[type] == NULLVP) | |
333 | q2type = USRQUOTA; | |||
334 | } else if (!strcmp(type, "group")) { | |||
335 | q2type = GRPQUOTA; | |||
336 | } else | |||
337 | return EOPNOTSUPP; | |||
338 | ||||
339 | if (ump->um_quotas[q2type] == NULLVP) | |||
340 | return ENODEV; | 409 | return ENODEV; | |
341 | if (defaultq) { | 410 | if (defaultq) { | |
342 | error = getq2h(ump, q2type, &bp, &q2h, 0); | 411 | mutex_enter(&dqlock); | |
343 | if (error) | 412 | error = getq2h(ump, type, &bp, &q2h, 0); | |
413 | if (error) { | |||
414 | mutex_exit(&dqlock); | |||
344 | return error; | 415 | return error; | |
416 | } | |||
345 | q2e = &q2h->q2h_defentry; | 417 | q2e = &q2h->q2h_defentry; | |
346 | } else { | 418 | } else { | |
347 | error = dqget(NULLVP, id, ump, q2type, &dq); | 419 | error = dqget(NULLVP, id, ump, type, &dq); | |
348 | 420 | |||
349 | if (error) | 421 | if (error) | |
350 | return error; | 422 | return error; | |
351 | 423 | |||
352 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | 424 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | |
353 | dqrele(NULLVP, dq); | 425 | dqrele(NULLVP, dq); | |
354 | return ENOENT; | 426 | return ENOENT; | |
355 | } | 427 | } | |
356 | error = getq2e(ump, q2type, dq->dq2_lblkno, dq->dq2_blkoff, | 428 | error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff, | |
357 | &bp, &q2e, 0); | 429 | &bp, &q2e, 0); | |
358 | dqrele(NULLVP, dq); | |||
359 | if (error) | 430 | if (error) | |
360 | return error; | 431 | return error; | |
361 | } | 432 | } | |
362 | dict = q2etoprop(q2e, 0); | 433 | dict = q2etoprop(q2e, defaultq); | |
434 | if (defaultq) | |||
435 | mutex_exit(&dqlock); | |||
436 | else | |||
437 | dqrele(NULLVP, dq); | |||
363 | brelse(bp, 0); | 438 | brelse(bp, 0); | |
364 | if (dict == NULL) | 439 | if (dict == NULL) | |
365 | return ENOMEM; | 440 | return ENOMEM; | |
366 | 441 | |||
367 | if (!prop_array_add(replies, dict)) { | 442 | if (!prop_array_add_and_rel(replies, dict)) { | |
368 | error = ENOMEM; | 443 | error = ENOMEM; | |
369 | } | 444 | } | |
370 | prop_object_release(dict); | 445 | return error; | |
446 | } | |||
447 | ||||
448 | ||||
449 | static int | |||
450 | quota2_getall_callback(struct ufsmount *ump, uint64_t *offp, | |||
451 | struct quota2_entry *q2e, uint64_t off, void *v) | |||
452 | { | |||
453 | prop_array_t replies = v; | |||
454 | prop_dictionary_t dict; | |||
455 | ||||
456 | dict = q2etoprop(q2e, 0); | |||
457 | if (!prop_array_add_and_rel(replies, dict)) { | |||
458 | return ENOMEM; | |||
459 | } | |||
460 | return 0; | |||
461 | } | |||
462 | ||||
463 | int | |||
464 | quota2_handle_cmd_getall(struct ufsmount *ump, int type, prop_array_t replies) | |||
465 | { | |||
466 | int error; | |||
467 | struct quota2_header *q2h; | |||
468 | struct buf *hbp; | |||
469 | prop_dictionary_t dict; | |||
470 | uint64_t offset; | |||
471 | int i; | |||
472 | int quota2_hash_size; | |||
473 | const int needswap = UFS_MPNEEDSWAP(ump); | |||
474 | ||||
475 | if (ump->um_quotas[type] == NULLVP) | |||
476 | return ENODEV; | |||
477 | error = getq2h(ump, type, &hbp, &q2h, 0); | |||
478 | if (error) | |||
479 | return error; | |||
480 | dict = q2etoprop(&q2h->q2h_defentry, 1); | |||
481 | if (!prop_array_add_and_rel(replies, dict)) { | |||
482 | brelse(hbp, 0); | |||
483 | return ENOMEM; | |||
484 | } | |||
485 | quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); | |||
486 | for (i = 0; i < quota2_hash_size ; i++) { | |||
487 | offset = ufs_rw64(q2h->q2h_entries[i], needswap); | |||
488 | error = quota2_walk_list(ump, hbp, type, &offset, 0, replies, | |||
489 | quota2_getall_callback); | |||
490 | if (error) | |||
491 | break; | |||
492 | } | |||
493 | brelse(hbp, 0); | |||
371 | return error; | 494 | return error; | |
372 | } | 495 | } | |
373 | 496 | |||
374 | int | 497 | int | |
375 | q2sync(struct mount *mp) | 498 | q2sync(struct mount *mp) | |
376 | { | 499 | { | |
377 | return 0; | 500 | return 0; | |
378 | } | 501 | } | |
379 | 502 | |||
503 | struct dq2get_callback { | |||
504 | uid_t id; | |||
505 | struct dquot *dq; | |||
506 | }; | |||
507 | ||||
508 | static int | |||
509 | dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | |||
510 | uint64_t off, void *v) | |||
511 | { | |||
512 | struct dq2get_callback *c = v; | |||
513 | daddr_t lblkno; | |||
514 | int blkoff; | |||
515 | const int needswap = UFS_MPNEEDSWAP(ump); | |||
516 | ||||
517 | if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { | |||
518 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | |||
519 | blkoff = (off & ump->umq2_bmask); | |||
520 | c->dq->dq2_lblkno = lblkno; | |||
521 | c->dq->dq2_blkoff = blkoff; | |||
522 | return Q2WL_ABORT; | |||
523 | } | |||
524 | return 0; | |||
525 | } | |||
526 | ||||
380 | int | 527 | int | |
381 | dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, | 528 | dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, | |
382 | struct dquot *dq) | 529 | struct dquot *dq) | |
383 | { | 530 | { | |
384 | struct buf *bp; | 531 | struct buf *bp; | |
385 | struct quota2_header *q2h; | 532 | struct quota2_header *q2h; | |
386 | struct quota2_entry *q2e; | |||
387 | int error; | 533 | int error; | |
388 | daddr_t offset, lblkno; | 534 | daddr_t offset; | |
389 | int blkoffset; | |||
390 | u_long hash_mask; | 535 | u_long hash_mask; | |
391 | const int needswap = UFS_MPNEEDSWAP(ump); | 536 | const int needswap = UFS_MPNEEDSWAP(ump); | |
537 | struct dq2get_callback c = { | |||
538 | .id = id, | |||
539 | .dq = dq | |||
540 | }; | |||
392 | 541 | |||
542 | mutex_enter(&dqlock); | |||
393 | error = getq2h(ump, type, &bp, &q2h, 0); | 543 | error = getq2h(ump, type, &bp, &q2h, 0); | |
394 | if (error) | 544 | if (error) | |
395 | return error; | 545 | goto out_mutex; | |
396 | /* look for our entry */ | 546 | /* look for our entry */ | |
397 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | 547 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | |
398 | offset = ufs_rw64(q2h->q2h_entries[id & hash_mask], needswap); | 548 | offset = ufs_rw64(q2h->q2h_entries[id & hash_mask], needswap); | |
399 | dq->dq2_lblkno = 0; | 549 | error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, | |
400 | dq->dq2_blkoff = 0; | 550 | dq2get_callback); | |
401 | while (offset != 0) { | |||
402 | lblkno = (offset >> ump->um_mountp->mnt_fs_bshift); | |||
403 | blkoffset = (offset & ump->umq2_bmask); | |||
404 | brelse(bp, 0); | |||
405 | error = getq2e(ump, type, lblkno, blkoffset, &bp, &q2e, 0); | |||
406 | if (error) | |||
407 | return error; | |||
408 | if (ufs_rw32(q2e->q2e_uid, needswap) == id) { | |||
409 | dq->dq2_lblkno = lblkno; | |||
410 | dq->dq2_blkoff = blkoffset; | |||
411 | break; | |||
412 | } | |||
413 | offset = ufs_rw64(q2e->q2e_next, needswap); | |||
414 | } | |||
415 | brelse(bp, 0); | 551 | brelse(bp, 0); | |
552 | out_mutex: | |||
553 | mutex_exit(&dqlock); | |||
416 | return error; | 554 | return error; | |
417 | } | 555 | } | |
418 | 556 | |||
419 | int | 557 | int | |
420 | dq2sync(struct vnode *vp, struct dquot *dq) | 558 | dq2sync(struct vnode *vp, struct dquot *dq) | |
421 | { | 559 | { | |
422 | return 0; | 560 | return 0; | |
423 | } | 561 | } |
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: ufs_quota.c,v 1.68.4.1 2011/01/20 14:25:03 bouyer Exp $ */ | 1 | /* $NetBSD: ufs_quota.c,v 1.68.4.2 2011/01/21 16:58:06 bouyer Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | 4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Robert Elz at The University of Melbourne. | 8 | * Robert Elz at The University of Melbourne. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -25,51 +25,55 @@ | @@ -25,51 +25,55 @@ | |||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | 34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.68.4.1 2011/01/20 14:25:03 bouyer Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.68.4.2 2011/01/21 16:58:06 bouyer Exp $"); | |
39 | 39 | |||
40 | #if defined(_KERNEL_OPT) | 40 | #if defined(_KERNEL_OPT) | |
41 | #include "opt_quota.h" | 41 | #include "opt_quota.h" | |
42 | #endif | 42 | #endif | |
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <sys/kernel.h> | 44 | #include <sys/kernel.h> | |
45 | #include <sys/systm.h> | 45 | #include <sys/systm.h> | |
46 | #include <sys/namei.h> | 46 | #include <sys/namei.h> | |
47 | #include <sys/file.h> | 47 | #include <sys/file.h> | |
48 | #include <sys/proc.h> | 48 | #include <sys/proc.h> | |
49 | #include <sys/vnode.h> | 49 | #include <sys/vnode.h> | |
50 | #include <sys/mount.h> | 50 | #include <sys/mount.h> | |
51 | #include <sys/kauth.h> | 51 | #include <sys/kauth.h> | |
52 | 52 | |||
53 | #include <ufs/ufs/quota.h> | 53 | #include <ufs/ufs/quota.h> | |
54 | #include <ufs/ufs/inode.h> | 54 | #include <ufs/ufs/inode.h> | |
55 | #include <ufs/ufs/ufsmount.h> | 55 | #include <ufs/ufs/ufsmount.h> | |
56 | #include <ufs/ufs/ufs_extern.h> | 56 | #include <ufs/ufs/ufs_extern.h> | |
57 | #include <ufs/ufs/ufs_quota.h> | 57 | #include <ufs/ufs/ufs_quota.h> | |
58 | #include <ufs/ufs/quota2_prop.h> | 58 | #include <ufs/ufs/quota2_prop.h> | |
59 | 59 | |||
60 | kmutex_t dqlock; | |||
61 | kcondvar_t dqcv; | |||
60 | 62 | |||
61 | static int quota_handle_cmd_get(struct mount *, struct lwp *, | 63 | static int quota_handle_cmd_get(struct mount *, struct lwp *, | |
62 | prop_dictionary_t, const char *, prop_array_t); | 64 | prop_dictionary_t, int, prop_array_t); | |
65 | static int quota_handle_cmd_getall(struct mount *, struct lwp *, | |||
66 | prop_dictionary_t, int, prop_array_t); | |||
63 | /* | 67 | /* | |
64 | * Initialize the quota fields of an inode. | 68 | * Initialize the quota fields of an inode. | |
65 | */ | 69 | */ | |
66 | void | 70 | void | |
67 | ufsquota_init(struct inode *ip) | 71 | ufsquota_init(struct inode *ip) | |
68 | { | 72 | { | |
69 | int i; | 73 | int i; | |
70 | 74 | |||
71 | for (i = 0; i < MAXQUOTAS; i++) | 75 | for (i = 0; i < MAXQUOTAS; i++) | |
72 | ip->i_dquot[i] = NODQUOT; | 76 | ip->i_dquot[i] = NODQUOT; | |
73 | } | 77 | } | |
74 | 78 | |||
75 | /* | 79 | /* | |
@@ -116,131 +120,170 @@ chkiq(struct inode *ip, int32_t change, | @@ -116,131 +120,170 @@ chkiq(struct inode *ip, int32_t change, | |||
116 | #ifdef QUOTA2 | 120 | #ifdef QUOTA2 | |
117 | if (ip->i_ump->um_flags & UFS_QUOTA2) | 121 | if (ip->i_ump->um_flags & UFS_QUOTA2) | |
118 | return chkiq2(ip, change, cred, flags); | 122 | return chkiq2(ip, change, cred, flags); | |
119 | #endif | 123 | #endif | |
120 | return 0; | 124 | return 0; | |
121 | } | 125 | } | |
122 | 126 | |||
123 | int | 127 | int | |
124 | quota_handle_cmd(struct mount *mp, struct lwp *l, prop_dictionary_t cmddict) | 128 | quota_handle_cmd(struct mount *mp, struct lwp *l, prop_dictionary_t cmddict) | |
125 | { | 129 | { | |
126 | int error = 0; | 130 | int error = 0; | |
127 | const char *cmd, *type; | 131 | const char *cmd, *type; | |
128 | prop_array_t datas; | 132 | prop_array_t datas; | |
133 | int q2type; | |||
129 | 134 | |||
130 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | 135 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | |
131 | return EINVAL; | 136 | return EINVAL; | |
132 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | 137 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | |
133 | return EINVAL; | 138 | return EINVAL; | |
139 | if (!strcmp(type, "user")) { | |||
140 | q2type = USRQUOTA; | |||
141 | } else if (!strcmp(type, "group")) { | |||
142 | q2type = GRPQUOTA; | |||
143 | } else | |||
144 | return EOPNOTSUPP; | |||
134 | datas = prop_dictionary_get(cmddict, "data"); | 145 | datas = prop_dictionary_get(cmddict, "data"); | |
135 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | 146 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | |
136 | return EINVAL; | 147 | return EINVAL; | |
137 | 148 | |||
138 | prop_object_retain(datas); | 149 | prop_object_retain(datas); | |
139 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | 150 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | |
140 | 151 | |||
141 | if (strcmp(cmd, "get") == 0) { | 152 | if (strcmp(cmd, "get") == 0) { | |
142 | error = quota_handle_cmd_get(mp, l, cmddict, type, datas); | 153 | error = quota_handle_cmd_get(mp, l, cmddict, q2type, datas); | |
143 | goto end; | 154 | goto end; | |
144 | } | 155 | } | |
145 | if (!prop_dictionary_set_int8(cmddict, "return", EOPNOTSUPP)) | 156 | if (strcmp(cmd, "getall") == 0) { | |
146 | error = ENOMEM; | 157 | error = quota_handle_cmd_getall(mp, l, cmddict, q2type, datas); | |
158 | goto end; | |||
159 | } | |||
160 | error = EOPNOTSUPP; | |||
147 | end: | 161 | end: | |
162 | error = (prop_dictionary_set_int8(cmddict, "return", | |||
163 | error) ? 0 : ENOMEM); | |||
148 | prop_object_release(datas); | 164 | prop_object_release(datas); | |
149 | return error; | 165 | return error; | |
150 | } | 166 | } | |
151 | 167 | |||
152 | /* XXX shouldn't all this be in kauth ? */ | 168 | /* XXX shouldn't all this be in kauth ? */ | |
153 | static int | 169 | static int | |
154 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | 170 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | |
155 | /* The user can always query about his own quota. */ | 171 | /* The user can always query about his own quota. */ | |
156 | if (id == kauth_cred_getuid(l->l_cred)) | 172 | if (id == kauth_cred_getuid(l->l_cred)) | |
157 | return 0; | 173 | return 0; | |
158 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 174 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
159 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | 175 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | |
160 | } | 176 | } | |
161 | 177 | |||
162 | static int | 178 | static int | |
163 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | 179 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | |
164 | prop_dictionary_t cmddict, const char *type, prop_array_t datas) | 180 | prop_dictionary_t cmddict, int type, prop_array_t datas) | |
165 | { | 181 | { | |
166 | prop_array_t replies; | 182 | prop_array_t replies; | |
167 | prop_object_iterator_t iter; | 183 | prop_object_iterator_t iter; | |
168 | prop_dictionary_t data; | 184 | prop_dictionary_t data; | |
169 | uint32_t id; | 185 | uint32_t id; | |
170 | struct ufsmount *ump = VFSTOUFS(mp); | 186 | struct ufsmount *ump = VFSTOUFS(mp); | |
171 | int error, defaultq = 0; | 187 | int error, defaultq = 0; | |
172 | const char *idstr; | 188 | const char *idstr; | |
173 | 189 | |||
174 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | 190 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | |
175 | return (prop_dictionary_set_int8(cmddict, "return", | 191 | return EOPNOTSUPP; | |
176 | EOPNOTSUPP) ? 0 : ENOMEM); | |||
177 | 192 | |||
178 | replies = prop_array_create(); | 193 | replies = prop_array_create(); | |
179 | if (replies == NULL) | 194 | if (replies == NULL) | |
180 | return (prop_dictionary_set_int8(cmddict, "return", ENOMEM) ? | 195 | return ENOMEM; | |
181 | 0 : ENOMEM); | |||
182 | 196 | |||
183 | iter = prop_array_iterator(datas); | 197 | iter = prop_array_iterator(datas); | |
184 | if (iter == NULL) { | 198 | if (iter == NULL) { | |
185 | prop_object_release(replies); | 199 | prop_object_release(replies); | |
186 | return (prop_dictionary_set_int8(cmddict, "return", ENOMEM) ? | 200 | return ENOMEM; | |
187 | 0 : ENOMEM); | |||
188 | } | 201 | } | |
189 | while ((data = prop_object_iterator_next(iter)) != NULL) { | 202 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |
190 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | 203 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |
191 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | 204 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |
192 | &idstr)) | 205 | &idstr)) | |
193 | continue; | 206 | continue; | |
194 | if (strcmp(idstr, "default")) | 207 | if (strcmp(idstr, "default")) | |
195 | continue; | 208 | continue; | |
196 | id = 0; | 209 | id = 0; | |
197 | defaultq = 1; | 210 | defaultq = 1; | |
198 | } | 211 | } | |
199 | error = quota_get_auth(mp, l, id); | 212 | error = quota_get_auth(mp, l, id); | |
200 | if (error == EPERM) | 213 | if (error == EPERM) | |
201 | continue; | 214 | continue; | |
202 | if (error != 0) { | 215 | if (error != 0) { | |
203 | error = (prop_dictionary_set_int8(cmddict, "return", | |||
204 | error) ? 0 : ENOMEM); | |||
205 | prop_object_release(replies); | 216 | prop_object_release(replies); | |
206 | return error; | 217 | return error; | |
207 | } | 218 | } | |
208 | #ifdef QUOTA | 219 | #ifdef QUOTA | |
209 | if (ump->um_flags & UFS_QUOTA) | 220 | if (ump->um_flags & UFS_QUOTA) | |
210 | error = quota1_handle_cmd_get(ump, type, id, replies) | 221 | error = quota1_handle_cmd_get(ump, type, id, replies) | |
211 | else | 222 | else | |
212 | #endif | 223 | #endif | |
213 | #ifdef QUOTA2 | 224 | #ifdef QUOTA2 | |
214 | if (ump->um_flags & UFS_QUOTA2) { | 225 | if (ump->um_flags & UFS_QUOTA2) { | |
215 | error = quota2_handle_cmd_get(ump, type, id, defaultq, | 226 | error = quota2_handle_cmd_get(ump, type, id, defaultq, | |
216 | replies); | 227 | replies); | |
217 | } else | 228 | } else | |
218 | #endif | 229 | #endif | |
219 | panic("quota_handle_cmd_get: no support ?"); | 230 | panic("quota_handle_cmd_get: no support ?"); | |
220 | 231 | |||
221 | if (error && error != ENOENT) { | 232 | if (error && error != ENOENT) { | |
222 | error = (prop_dictionary_set_int8(cmddict, "return", | |||
223 | error) ? 0 : ENOMEM); | |||
224 | prop_object_release(replies); | 233 | prop_object_release(replies); | |
225 | return error; | 234 | return error; | |
226 | } | 235 | } | |
227 | } | 236 | } | |
228 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 237 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
229 | error = (prop_dictionary_set_int8(cmddict, "return", | 238 | error = ENOMEM; | |
230 | ENOMEM) ? 0 : ENOMEM); | 239 | } else { | |
240 | error = 0; | |||
241 | } | |||
242 | return error; | |||
243 | } | |||
244 | ||||
245 | static int | |||
246 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, | |||
247 | prop_dictionary_t cmddict, int type, prop_array_t datas) | |||
248 | { | |||
249 | prop_array_t replies; | |||
250 | struct ufsmount *ump = VFSTOUFS(mp); | |||
251 | int error; | |||
252 | ||||
253 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |||
254 | return EOPNOTSUPP; | |||
255 | ||||
256 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |||
257 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |||
258 | if (error) | |||
259 | return error; | |||
260 | ||||
261 | replies = prop_array_create(); | |||
262 | if (replies == NULL) | |||
263 | return ENOMEM; | |||
264 | ||||
265 | #ifdef QUOTA2 | |||
266 | if (ump->um_flags & UFS_QUOTA2) { | |||
267 | mutex_enter(&dqlock); | |||
268 | error = quota2_handle_cmd_getall(ump, type, replies); | |||
269 | mutex_exit(&dqlock); | |||
270 | } else | |||
271 | #endif | |||
272 | panic("quota_handle_cmd_getall: no support ?"); | |||
273 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |||
274 | error = ENOMEM; | |||
231 | } else { | 275 | } else { | |
232 | error = (prop_dictionary_set_int8(cmddict, "return", 0) ? | 276 | error = 0; | |
233 | 0 : ENOMEM); | |||
234 | } | 277 | } | |
235 | return error; | 278 | return error; | |
236 | } | 279 | } | |
237 | 280 | |||
238 | /* | 281 | /* | |
239 | * Initialize the quota system. | 282 | * Initialize the quota system. | |
240 | */ | 283 | */ | |
241 | void | 284 | void | |
242 | dqinit(void) | 285 | dqinit(void) | |
243 | { | 286 | { | |
244 | 287 | |||
245 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | 288 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | |
246 | cv_init(&dqcv, "quota"); | 289 | cv_init(&dqcv, "quota"); |
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: Makefile,v 1.6.64.1 2011/01/20 14:25:05 bouyer Exp $ | 1 | # $NetBSD: Makefile,v 1.6.64.2 2011/01/21 16:58:06 bouyer Exp $ | |
2 | # from: @(#)Makefile 8.1 (Berkeley) 6/6/93 | 2 | # from: @(#)Makefile 8.1 (Berkeley) 6/6/93 | |
3 | 3 | |||
4 | .include <bsd.own.mk> | 4 | .include <bsd.own.mk> | |
5 | PROG= quota | 5 | PROG= quota | |
6 | SRCS= quota.c | 6 | SRCS= quota.c printquota.c | |
7 | 7 | |||
8 | CPPFLAGS+=-I${NETBSDSRCDIR}/sys | 8 | CPPFLAGS+=-I${NETBSDSRCDIR}/sys -I${NETBSDSRCDIR}/usr.bin/quota | |
9 | DPADD= ${LIBRPCSVC} | 9 | DPADD= ${LIBRPCSVC} ${LIBPROP} | |
10 | LDADD= -lrpcsvc -lprop | 10 | LDADD= -lrpcsvc -lprop | |
11 | 11 | |||
12 | .PATH: ${NETBSDSRCDIR}/sys/ufs/ufs | 12 | .PATH: ${NETBSDSRCDIR}/sys/ufs/ufs | |
13 | SRCS+= quota2_prop.c | 13 | SRCS+= quota2_prop.c | |
14 | .include <bsd.prog.mk> | 14 | .include <bsd.prog.mk> |
/* $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);
}
/* $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);
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | .\" $NetBSD: quota.1,v 1.14.52.2 2011/01/21 16:36:57 bouyer Exp $ | 1 | .\" $NetBSD: quota.1,v 1.14.52.3 2011/01/21 16:58:06 bouyer Exp $ | |
2 | .\" | 2 | .\" | |
3 | .\" Copyright (c) 1983, 1990, 1993 | 3 | .\" Copyright (c) 1983, 1990, 1993 | |
4 | .\" The Regents of the University of California. All rights reserved. | 4 | .\" The Regents of the University of California. All rights reserved. | |
5 | .\" | 5 | .\" | |
6 | .\" This code is derived from software contributed to Berkeley by | 6 | .\" This code is derived from software contributed to Berkeley by | |
7 | .\" Robert Elz at The University of Melbourne. | 7 | .\" Robert Elz at The University of Melbourne. | |
8 | .\" | 8 | .\" | |
9 | .\" Redistribution and use in source and binary forms, with or without | 9 | .\" Redistribution and use in source and binary forms, with or without | |
10 | .\" modification, are permitted provided that the following conditions | 10 | .\" modification, are permitted provided that the following conditions | |
11 | .\" are met: | 11 | .\" are met: | |
12 | .\" 1. Redistributions of source code must retain the above copyright | 12 | .\" 1. Redistributions of source code must retain the above copyright | |
13 | .\" notice, this list of conditions and the following disclaimer. | 13 | .\" notice, this list of conditions and the following disclaimer. | |
14 | .\" 2. Redistributions in binary form must reproduce the above copyright | 14 | .\" 2. Redistributions in binary form must reproduce the above copyright | |
@@ -125,27 +125,26 @@ flag. | @@ -125,27 +125,26 @@ flag. | |||
125 | .Nm | 125 | .Nm | |
126 | tries to report the quotas of all mounted filesystems. | 126 | tries to report the quotas of all mounted filesystems. | |
127 | If the filesystem is mounted via | 127 | If the filesystem is mounted via | |
128 | .Em NFS | 128 | .Em NFS | |
129 | it will attempt to contact the | 129 | it will attempt to contact the | |
130 | .Xr rpc.rquotad 8 | 130 | .Xr rpc.rquotad 8 | |
131 | daemon on the | 131 | daemon on the | |
132 | .Em NFS | 132 | .Em NFS | |
133 | server. | 133 | server. | |
134 | If | 134 | If | |
135 | .Nm | 135 | .Nm | |
136 | exits with a non-zero status, one or more filesystems | 136 | exits with a non-zero status, one or more filesystems | |
137 | are over quota. | 137 | are over quota. | |
138 | .El | |||
139 | .Sh SEE ALSO | 138 | .Sh SEE ALSO | |
140 | .Xr quotactl 2 , | 139 | .Xr quotactl 2 , | |
141 | .Xr fstab 5 , | 140 | .Xr fstab 5 , | |
142 | .Xr edquota 8 , | 141 | .Xr edquota 8 , | |
143 | .Xr quotacheck 8 , | 142 | .Xr quotacheck 8 , | |
144 | .Xr quotaon 8 , | 143 | .Xr quotaon 8 , | |
145 | .Xr repquota 8 , | 144 | .Xr repquota 8 , | |
146 | .Xr rpc.rquotad 8 | 145 | .Xr rpc.rquotad 8 | |
147 | .Sh HISTORY | 146 | .Sh HISTORY | |
148 | The | 147 | The | |
149 | .Nm | 148 | .Nm | |
150 | command appeared in | 149 | command appeared in | |
151 | .Bx 4.2 . | 150 | .Bx 4.2 . |
--- 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,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: quota.c,v 1.33.2.1 2011/01/20 14:25:05 bouyer Exp $ */ | 1 | /* $NetBSD: quota.c,v 1.33.2.2 2011/01/21 16:58:06 bouyer Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1980, 1990, 1993 | 4 | * Copyright (c) 1980, 1990, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Robert Elz at The University of Melbourne. | 8 | * Robert Elz at The University of Melbourne. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -32,88 +32,88 @@ | @@ -32,88 +32,88 @@ | |||
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | #include <sys/cdefs.h> | 35 | #include <sys/cdefs.h> | |
36 | #ifndef lint | 36 | #ifndef lint | |
37 | __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\ | 37 | __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\ | |
38 | The Regents of the University of California. All rights reserved."); | 38 | The Regents of the University of California. All rights reserved."); | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #ifndef lint | 41 | #ifndef lint | |
42 | #if 0 | 42 | #if 0 | |
43 | static char sccsid[] = "@(#)quota.c 8.4 (Berkeley) 4/28/95"; | 43 | static char sccsid[] = "@(#)quota.c 8.4 (Berkeley) 4/28/95"; | |
44 | #else | 44 | #else | |
45 | __RCSID("$NetBSD: quota.c,v 1.33.2.1 2011/01/20 14:25:05 bouyer Exp $"); | 45 | __RCSID("$NetBSD: quota.c,v 1.33.2.2 2011/01/21 16:58:06 bouyer Exp $"); | |
46 | #endif | 46 | #endif | |
47 | #endif /* not lint */ | 47 | #endif /* not lint */ | |
48 | 48 | |||
49 | /* | 49 | /* | |
50 | * Disk quota reporting program. | 50 | * Disk quota reporting program. | |
51 | */ | 51 | */ | |
52 | #include <sys/param.h> | 52 | #include <sys/param.h> | |
53 | #include <sys/types.h> | 53 | #include <sys/types.h> | |
54 | #include <sys/file.h> | 54 | #include <sys/file.h> | |
55 | #include <sys/stat.h> | 55 | #include <sys/stat.h> | |
56 | #include <sys/mount.h> | 56 | #include <sys/mount.h> | |
57 | #include <sys/socket.h> | 57 | #include <sys/socket.h> | |
58 | #include <sys/queue.h> | |||
59 | #include <prop/proplib.h> | |||
60 | #include <sys/quota.h> | |||
61 | 58 | |||
62 | #include <ufs/ufs/quota2_prop.h> | 59 | #include <ufs/ufs/quota2_prop.h> | |
60 | #include <sys/quota.h> | |||
61 | ||||
63 | #include <ctype.h> | 62 | #include <ctype.h> | |
64 | #include <err.h> | 63 | #include <err.h> | |
65 | #include <errno.h> | 64 | #include <errno.h> | |
66 | #include <fstab.h> | 65 | #include <fstab.h> | |
67 | #include <grp.h> | 66 | #include <grp.h> | |
68 | #include <netdb.h> | 67 | #include <netdb.h> | |
69 | #include <pwd.h> | 68 | #include <pwd.h> | |
70 | #include <stdio.h> | 69 | #include <stdio.h> | |
71 | #include <stdlib.h> | 70 | #include <stdlib.h> | |
72 | #include <string.h> | 71 | #include <string.h> | |
73 | #include <time.h> | 72 | #include <time.h> | |
74 | #include <unistd.h> | 73 | #include <unistd.h> | |
75 | 74 | |||
76 | #include <rpc/rpc.h> | 75 | #include <rpc/rpc.h> | |
77 | #include <rpc/pmap_prot.h> | 76 | #include <rpc/pmap_prot.h> | |
78 | #include <rpcsvc/rquota.h> | 77 | #include <rpcsvc/rquota.h> | |
79 | 78 | |||
80 | const char *qfextension[] = INITQFNAMES; | 79 | #include <printquota.h> | |
81 | 80 | |||
82 | struct quotause { | 81 | struct quotause { | |
83 | struct quotause *next; | 82 | struct quotause *next; | |
84 | long flags; | 83 | long flags; | |
85 | struct quota2_entry q2e; | 84 | struct quota2_entry q2e; | |
86 | char fsname[MAXPATHLEN + 1]; | 85 | char fsname[MAXPATHLEN + 1]; | |
87 | }; | 86 | }; | |
88 | #define FOUND 0x01 | 87 | #define FOUND 0x01 | |
89 | 88 | |||
90 | int alldigits(char *); | 89 | int alldigits(char *); | |
91 | int callaurpc(char *, int, int, int, xdrproc_t, void *, xdrproc_t, void *); | 90 | int callaurpc(char *, int, int, int, xdrproc_t, void *, xdrproc_t, void *); | |
92 | int main(int, char **); | 91 | int main(int, char **); | |
93 | int getnfsquota(struct statvfs *, struct fstab *, struct quotause *, | 92 | int getnfsquota(struct statvfs *, struct fstab *, struct quotause *, | |
94 | long, int); | 93 | long, int); | |
95 | struct quotause *getprivs(long id, int quotatype); | 94 | struct quotause *getprivs(long id, int quotatype); | |
96 | int getufsquota(struct statvfs *, struct quotause *, long, int); | |||
97 | void heading(int, u_long, const char *, const char *); | 95 | void heading(int, u_long, const char *, const char *); | |
98 | void showgid(gid_t); | 96 | void showgid(gid_t); | |
99 | void showgrpname(const char *); | 97 | void showgrpname(const char *); | |
100 | void showquotas(int, u_long, const char *); | 98 | void showquotas(int, u_long, const char *); | |
101 | void showuid(uid_t); | 99 | void showuid(uid_t); | |
102 | void showusrname(const char *); | 100 | void showusrname(const char *); | |
103 | const char *intprt(uint64_t, int); | |||
104 | const char *timeprt(time_t seconds); | |||
105 | void usage(void); | 101 | void usage(void); | |
106 | 102 | |||
103 | extern const char *qfextension[]; | |||
104 | ||||
105 | int getufsquota(const char *, struct quota2_entry *, long, int, int, int); | |||
106 | ||||
107 | int qflag = 0; | 107 | int qflag = 0; | |
108 | int vflag = 0; | 108 | int vflag = 0; | |
109 | int hflag = 0; | 109 | int hflag = 0; | |
110 | int dflag = 0; | 110 | int dflag = 0; | |
111 | int Dflag = 0; | 111 | int Dflag = 0; | |
112 | uid_t myuid; | 112 | uid_t myuid; | |
113 | 113 | |||
114 | int | 114 | int | |
115 | main(argc, argv) | 115 | main(argc, argv) | |
116 | int argc; | 116 | int argc; | |
117 | char *argv[]; | 117 | char *argv[]; | |
118 | { | 118 | { | |
119 | int ngroups; | 119 | int ngroups; | |
@@ -393,41 +393,42 @@ showquotas(type, id, name) | @@ -393,41 +393,42 @@ showquotas(type, id, name) | |||
393 | if (vflag || dflag || | 393 | if (vflag || dflag || | |
394 | qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur || | 394 | qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur || | |
395 | qup->q2e.q2e_val[Q2V_FILE].q2v_cur) { | 395 | qup->q2e.q2e_val[Q2V_FILE].q2v_cur) { | |
396 | if (lines++ == 0) | 396 | if (lines++ == 0) | |
397 | heading(type, id, name, ""); | 397 | heading(type, id, name, ""); | |
398 | nam = qup->fsname; | 398 | nam = qup->fsname; | |
399 | if (strlen(qup->fsname) > 4) { | 399 | if (strlen(qup->fsname) > 4) { | |
400 | printf("%s\n", qup->fsname); | 400 | printf("%s\n", qup->fsname); | |
401 | nam = ""; | 401 | nam = ""; | |
402 | } | 402 | } | |
403 | printf("%12s%9s%c%8s%9s%8s" | 403 | printf("%12s%9s%c%8s%9s%8s" | |
404 | , nam | 404 | , nam | |
405 | , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur | 405 | , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_cur | |
406 | ,HN_B) | 406 | ,HN_B, hflag) | |
407 | , (msgb == NULL) ? ' ' : '*' | 407 | , (msgb == NULL) ? ' ' : '*' | |
408 | , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_softlimit | 408 | , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_softlimit | |
409 | , HN_B) | 409 | , HN_B, hflag) | |
410 | , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit | 410 | , intprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit | |
411 | , HN_B) | 411 | , HN_B, hflag) | |
412 | , (msgb == NULL) ? "" | 412 | , (msgb == NULL) ? "" | |
413 | : timeprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_time)); | 413 | : timeprt(qup->q2e.q2e_val[Q2V_BLOCK].q2v_time)); | |
414 | printf("%8s%c%7s%8s%8s\n" | 414 | printf("%8s%c%7s%8s%8s\n" | |
415 | , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_cur, 0) | 415 | , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_cur | |
416 | , 0, hflag) | |||
416 | , (msgi == NULL) ? ' ' : '*' | 417 | , (msgi == NULL) ? ' ' : '*' | |
417 | , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_softlimit | 418 | , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_softlimit | |
418 | , 0) | 419 | , 0, hflag) | |
419 | , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit | 420 | , intprt(qup->q2e.q2e_val[Q2V_FILE].q2v_hardlimit | |
420 | , 0) | 421 | , 0, hflag) | |
421 | , (msgi == NULL) ? "" | 422 | , (msgi == NULL) ? "" | |
422 | : timeprt(qup->q2e.q2e_val[Q2V_FILE].q2v_time) | 423 | : timeprt(qup->q2e.q2e_val[Q2V_FILE].q2v_time) | |
423 | ); | 424 | ); | |
424 | continue; | 425 | continue; | |
425 | } | 426 | } | |
426 | } | 427 | } | |
427 | if (!qflag && lines == 0) | 428 | if (!qflag && lines == 0) | |
428 | heading(type, id, name, "none"); | 429 | heading(type, id, name, "none"); | |
429 | } | 430 | } | |
430 | 431 | |||
431 | void | 432 | void | |
432 | heading(type, id, name, tag) | 433 | heading(type, id, name, tag) | |
433 | int type; | 434 | int type; | |
@@ -448,232 +449,76 @@ heading(type, id, name, tag) | @@ -448,232 +449,76 @@ heading(type, id, name, tag) | |||
448 | , "blocks" | 449 | , "blocks" | |
449 | , "quota" | 450 | , "quota" | |
450 | , "limit" | 451 | , "limit" | |
451 | , "grace" | 452 | , "grace" | |
452 | , "files" | 453 | , "files" | |
453 | , "quota" | 454 | , "quota" | |
454 | , "limit" | 455 | , "limit" | |
455 | , "grace" | 456 | , "grace" | |
456 | ); | 457 | ); | |
457 | } | 458 | } | |
458 | } | 459 | } | |
459 | 460 | |||
460 | /* | 461 | /* | |
461 | * convert 64bit value to a printable string | |||
462 | */ | |||
463 | const char * | |||
464 | intprt(uint64_t val, int flags) | |||
465 | { | |||
466 | static char buf[21]; | |||
467 | ||||
468 | if (val == UQUAD_MAX) | |||
469 | return("-"); | |||
470 | ||||
471 | if (flags & HN_B) | |||
472 | val = dbtob(val); | |||
473 | ||||
474 | if (hflag) { | |||
475 | humanize_number(buf, 6, val, "", HN_AUTOSCALE, flags); | |||
476 | return buf; | |||
477 | } | |||
478 | if (flags & HN_B) { | |||
479 | /* traditionnal display: blocks are in kilobytes */ | |||
480 | val = val / 1024; | |||
481 | } | |||
482 | snprintf(buf, sizeof(buf), "%" PRIu64, val); | |||
483 | return buf; | |||
484 | } | |||
485 | ||||
486 | /* | |||
487 | * Calculate the grace period and return a printable string for it. | |||
488 | */ | |||
489 | const char * | |||
490 | timeprt(time_t seconds) | |||
491 | { | |||
492 | time_t hours, minutes; | |||
493 | static char buf[20]; | |||
494 | static time_t now; | |||
495 | ||||
496 | if (now == 0) | |||
497 | time(&now); | |||
498 | if (now > seconds) | |||
499 | return ("none"); | |||
500 | seconds -= now; | |||
501 | minutes = (seconds + 30) / 60; | |||
502 | hours = (minutes + 30) / 60; | |||
503 | if (hours >= 36) { | |||
504 | (void)snprintf(buf, sizeof buf, "%ddays", | |||
505 | (int)((hours + 12) / 24)); | |||
506 | return (buf); | |||
507 | } | |||
508 | if (minutes >= 60) { | |||
509 | (void)snprintf(buf, sizeof buf, "%2d:%d", | |||
510 | (int)(minutes / 60), (int)(minutes % 60)); | |||
511 | return (buf); | |||
512 | } | |||
513 | (void)snprintf(buf, sizeof buf, "%2d", (int)minutes); | |||
514 | return (buf); | |||
515 | } | |||
516 | ||||
517 | /* | |||
518 | * Collect the requested quota information. | 462 | * Collect the requested quota information. | |
519 | */ | 463 | */ | |
520 | struct quotause * | 464 | struct quotause * | |
521 | getprivs(id, quotatype) | 465 | getprivs(id, quotatype) | |
522 | long id; | 466 | long id; | |
523 | int quotatype; | 467 | int quotatype; | |
524 | { | 468 | { | |
525 | struct quotause *qup, *quptail; | 469 | struct quotause *qup, *quptail; | |
526 | struct quotause *quphead; | 470 | struct quotause *quphead; | |
527 | struct statvfs *fst; | 471 | struct statvfs *fst; | |
528 | int nfst, i; | 472 | int nfst, i; | |
529 | 473 | |||
530 | qup = quphead = quptail = NULL; | 474 | qup = quphead = quptail = NULL; | |
531 | 475 | |||
532 | nfst = getmntinfo(&fst, MNT_WAIT); | 476 | nfst = getmntinfo(&fst, MNT_WAIT); | |
533 | if (nfst == 0) | 477 | if (nfst == 0) | |
534 | errx(2, "no filesystems mounted!"); | 478 | errx(2, "no filesystems mounted!"); | |
535 | setfsent(); | |||
536 | for (i = 0; i < nfst; i++) { | 479 | for (i = 0; i < nfst; i++) { | |
537 | if (qup == NULL) { | 480 | if (qup == NULL) { | |
538 | if ((qup = | 481 | if ((qup = | |
539 | (struct quotause *)malloc(sizeof *qup)) == NULL) | 482 | (struct quotause *)malloc(sizeof *qup)) == NULL) | |
540 | errx(2, "out of memory"); | 483 | errx(2, "out of memory"); | |
541 | } | 484 | } | |
542 | if (strncmp(fst[i].f_fstypename, "nfs", | 485 | if (strncmp(fst[i].f_fstypename, "nfs", | |
543 | sizeof(fst[i].f_fstypename)) == 0) { | 486 | sizeof(fst[i].f_fstypename)) == 0) { | |
544 | if (getnfsquota(&fst[i], NULL, qup, id, quotatype) == 0) | 487 | if (getnfsquota(&fst[i], NULL, qup, id, quotatype) == 0) | |
545 | continue; | 488 | continue; | |
546 | } else if (strncmp(fst[i].f_fstypename, "ffs", | 489 | } else if (strncmp(fst[i].f_fstypename, "ffs", | |
547 | sizeof(fst[i].f_fstypename)) == 0 && | 490 | sizeof(fst[i].f_fstypename)) == 0 && | |
548 | (fst[i].f_flag &ST_QUOTA) != 0) { | 491 | (fst[i].f_flag & ST_QUOTA) != 0) { | |
549 | if (getufsquota(&fst[i], qup, id, quotatype) == 0) | 492 | if (getufsquota(fst[i].f_mntonname, &qup->q2e, | |
493 | id, quotatype, dflag, Dflag) == 0) | |||
550 | continue; | 494 | continue; | |
551 | } else | 495 | } else | |
552 | continue; | 496 | continue; | |
553 | (void)strncpy(qup->fsname, fst[i].f_mntonname, | 497 | (void)strncpy(qup->fsname, fst[i].f_mntonname, | |
554 | sizeof(qup->fsname) - 1); | 498 | sizeof(qup->fsname) - 1); | |
555 | if (quphead == NULL) | 499 | if (quphead == NULL) | |
556 | quphead = qup; | 500 | quphead = qup; | |
557 | else | 501 | else | |
558 | quptail->next = qup; | 502 | quptail->next = qup; | |
559 | quptail = qup; | 503 | quptail = qup; | |
560 | quptail->next = 0; | 504 | quptail->next = 0; | |
561 | qup = NULL; | 505 | qup = NULL; | |
562 | } | 506 | } | |
563 | if (qup) | 507 | if (qup) | |
564 | free(qup); | 508 | free(qup); | |
565 | endfsent(); | |||
566 | return (quphead); | 509 | return (quphead); | |
567 | } | 510 | } | |
568 | 511 | |||
569 | ||||
570 | int | |||
571 | getufsquota(struct statvfs *fst, struct quotause *qup, long id, int type) | |||
572 | { | |||
573 | prop_dictionary_t dict, data, cmd; | |||
574 | prop_array_t cmds, datas; | |||
575 | struct plistref pref; | |||
576 | int error; | |||
577 | int8_t error8; | |||
578 | bool ret; | |||
579 | ||||
580 | dict = quota2_prop_create(); | |||
581 | cmds = prop_array_create(); | |||
582 | datas = prop_array_create(); | |||
583 | data = prop_dictionary_create(); | |||
584 | ||||
585 | if (dict == NULL || cmds == NULL || datas == NULL || data == NULL) | |||
586 | errx(1, "can't allocate proplist"); | |||
587 | ||||
588 | if (dflag) | |||
589 | ret = prop_dictionary_set_cstring(data, "id", "default"); | |||
590 | else | |||
591 | ret = prop_dictionary_set_uint32(data, "id", id); | |||
592 | if (!ret) | |||
593 | err(1, "prop_dictionary_set(id)"); | |||
594 | ||||
595 | if (!prop_array_add(datas, data)) | |||
596 | err(1, "prop_array_add(data)"); | |||
597 | prop_object_release(data); | |||
598 | if (!quota2_prop_add_command(cmds, "get", qfextension[type], datas)) | |||
599 | err(1, "prop_add_command"); | |||
600 | if (!prop_dictionary_set(dict, "commands", cmds)) | |||
601 | err(1, "prop_dictionary_set(command)"); | |||
602 | if (Dflag) | |||
603 | printf("message to kernel:\n%s\n", | |||
604 | prop_dictionary_externalize(dict)); | |||
605 | ||||
606 | if (!prop_dictionary_send_syscall(dict, &pref)) | |||
607 | err(1, "prop_dictionary_send_syscall"); | |||
608 | prop_object_release(dict); | |||
609 | ||||
610 | if (quotactl(fst->f_mntonname, &pref) != 0) | |||
611 | err(1, "quotactl"); | |||
612 | ||||
613 | if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) { | |||
614 | errx(1, "prop_dictionary_recv_syscall: %s\n", | |||
615 | strerror(error)); | |||
616 | } | |||
617 | if (Dflag) | |||
618 | printf("reply from kernel:\n%s\n", | |||
619 | prop_dictionary_externalize(dict)); | |||
620 | if ((error = quota2_get_cmds(dict, &cmds)) != 0) { | |||
621 | errx(1, "quota2_get_cmds: %s\n", | |||
622 | strerror(error)); | |||
623 | } | |||
624 | /* only one command, no need to iter */ | |||
625 | cmd = prop_array_get(cmds, 0); | |||
626 | if (cmd == NULL) | |||
627 | err(1, "prop_array_get(cmd)"); | |||
628 | ||||
629 | if (!prop_dictionary_get_int8(cmd, "return", &error8)) | |||
630 | err(1, "prop_get(return)"); | |||
631 | ||||
632 | if (error8) { | |||
633 | if (error8 != ENOENT && error8 != ENODEV) { | |||
634 | if (dflag) | |||
635 | fprintf(stderr, "get default %s quota: %s\n", | |||
636 | qfextension[type], strerror(error8)); | |||
637 | else | |||
638 | fprintf(stderr, "get %s quota for %ld: %s\n", | |||
639 | qfextension[type], id, strerror(error8)); | |||
640 | } | |||
641 | prop_object_release(dict); | |||
642 | return (0); | |||
643 | } | |||
644 | datas = prop_dictionary_get(cmd, "data"); | |||
645 | if (datas == NULL) | |||
646 | err(1, "prop_dict_get(datas)"); | |||
647 | ||||
648 | /* only one data, no need to iter */ | |||
649 | if (prop_array_count(datas) == 0) { | |||
650 | /* no quota for this user/group */ | |||
651 | prop_object_release(dict); | |||
652 | return (0); | |||
653 | } | |||
654 | ||||
655 | data = prop_array_get(datas, 0); | |||
656 | if (data == NULL) | |||
657 | err(1, "prop_array_get(data)"); | |||
658 | ||||
659 | error = quota2_dict_get_q2e_usage(data, &qup->q2e); | |||
660 | if (error) { | |||
661 | errx(1, "quota2_dict_get_q2e_usage: %s\n", | |||
662 | strerror(error)); | |||
663 | } | |||
664 | return (1); | |||
665 | } | |||
666 | ||||
667 | int | 512 | int | |
668 | getnfsquota(fst, fs, qup, id, quotatype) | 513 | getnfsquota(fst, fs, qup, id, quotatype) | |
669 | struct statvfs *fst; | 514 | struct statvfs *fst; | |
670 | struct fstab *fs; | 515 | struct fstab *fs; | |
671 | struct quotause *qup; | 516 | struct quotause *qup; | |
672 | long id; | 517 | long id; | |
673 | int quotatype; | 518 | int quotatype; | |
674 | { | 519 | { | |
675 | struct getquota_args gq_args; | 520 | struct getquota_args gq_args; | |
676 | struct ext_getquota_args ext_gq_args; | 521 | struct ext_getquota_args ext_gq_args; | |
677 | struct getquota_rslt gq_rslt; | 522 | struct getquota_rslt gq_rslt; | |
678 | struct quota2_entry *q2e = &qup->q2e; | 523 | struct quota2_entry *q2e = &qup->q2e; | |
679 | struct timeval tv; | 524 | struct timeval tv; | |
@@ -803,13 +648,114 @@ callaurpc(host, prognum, versnum, procnu | @@ -803,13 +648,114 @@ callaurpc(host, prognum, versnum, procnu | |||
803 | int | 648 | int | |
804 | alldigits(s) | 649 | alldigits(s) | |
805 | char *s; | 650 | char *s; | |
806 | { | 651 | { | |
807 | int c; | 652 | int c; | |
808 | 653 | |||
809 | c = *s++; | 654 | c = *s++; | |
810 | do { | 655 | do { | |
811 | if (!isdigit(c)) | 656 | if (!isdigit(c)) | |
812 | return (0); | 657 | return (0); | |
813 | } while ((c = *s++) != 0); | 658 | } while ((c = *s++) != 0); | |
814 | return (1); | 659 | return (1); | |
815 | } | 660 | } | |
661 | ||||
662 | const char *qfextension[] = INITQFNAMES; | |||
663 | ||||
664 | int | |||
665 | getufsquota(const char *mp, struct quota2_entry *q2e, long id, int type, | |||
666 | int defaultq, int debug) | |||
667 | { | |||
668 | prop_dictionary_t dict, data, cmd; | |||
669 | prop_array_t cmds, datas; | |||
670 | struct plistref pref; | |||
671 | int error; | |||
672 | int8_t error8; | |||
673 | bool ret; | |||
674 | ||||
675 | dict = quota2_prop_create(); | |||
676 | cmds = prop_array_create(); | |||
677 | datas = prop_array_create(); | |||
678 | data = prop_dictionary_create(); | |||
679 | ||||
680 | if (dict == NULL || cmds == NULL || datas == NULL || data == NULL) | |||
681 | errx(1, "can't allocate proplist"); | |||
682 | ||||
683 | if (defaultq) | |||
684 | ret = prop_dictionary_set_cstring(data, "id", "default"); | |||
685 | else | |||
686 | ret = prop_dictionary_set_uint32(data, "id", id); | |||
687 | if (!ret) | |||
688 | err(1, "prop_dictionary_set(id)"); | |||
689 | ||||
690 | if (!prop_array_add(datas, data)) | |||
691 | err(1, "prop_array_add(data)"); | |||
692 | prop_object_release(data); | |||
693 | if (!quota2_prop_add_command(cmds, "get", qfextension[type], datas)) | |||
694 | err(1, "prop_add_command"); | |||
695 | if (!prop_dictionary_set(dict, "commands", cmds)) | |||
696 | err(1, "prop_dictionary_set(command)"); | |||
697 | if (debug) | |||
698 | printf("message to kernel:\n%s\n", | |||
699 | prop_dictionary_externalize(dict)); | |||
700 | ||||
701 | if (!prop_dictionary_send_syscall(dict, &pref)) | |||
702 | err(1, "prop_dictionary_send_syscall"); | |||
703 | prop_object_release(dict); | |||
704 | ||||
705 | if (quotactl(mp, &pref) != 0) | |||
706 | err(1, "quotactl"); | |||
707 | ||||
708 | if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) { | |||
709 | errx(1, "prop_dictionary_recv_syscall: %s\n", | |||
710 | strerror(error)); | |||
711 | } | |||
712 | if (debug) | |||
713 | printf("reply from kernel:\n%s\n", | |||
714 | prop_dictionary_externalize(dict)); | |||
715 | if ((error = quota2_get_cmds(dict, &cmds)) != 0) { | |||
716 | errx(1, "quota2_get_cmds: %s\n", | |||
717 | strerror(error)); | |||
718 | } | |||
719 | /* only one command, no need to iter */ | |||
720 | cmd = prop_array_get(cmds, 0); | |||
721 | if (cmd == NULL) | |||
722 | err(1, "prop_array_get(cmd)"); | |||
723 | ||||
724 | if (!prop_dictionary_get_int8(cmd, "return", &error8)) | |||
725 | err(1, "prop_get(return)"); | |||
726 | ||||
727 | if (error8) { | |||
728 | if (error8 != ENOENT && error8 != ENODEV) { | |||
729 | if (defaultq) | |||
730 | fprintf(stderr, "get default %s quota: %s\n", | |||
731 | qfextension[type], strerror(error8)); | |||
732 | else | |||
733 | fprintf(stderr, "get %s quota for %ld: %s\n", | |||
734 | qfextension[type], id, strerror(error8)); | |||
735 | } | |||
736 | prop_object_release(dict); | |||
737 | return (0); | |||
738 | } | |||
739 | datas = prop_dictionary_get(cmd, "data"); | |||
740 | if (datas == NULL) | |||
741 | err(1, "prop_dict_get(datas)"); | |||
742 | ||||
743 | /* only one data, no need to iter */ | |||
744 | if (prop_array_count(datas) == 0) { | |||
745 | /* no quota for this user/group */ | |||
746 | prop_object_release(dict); | |||
747 | return (0); | |||
748 | } | |||
749 | ||||
750 | data = prop_array_get(datas, 0); | |||
751 | if (data == NULL) | |||
752 | err(1, "prop_array_get(data)"); | |||
753 | ||||
754 | error = quota2_dict_get_q2e_usage(data, q2e); | |||
755 | if (error) { | |||
756 | errx(1, "quota2_dict_get_q2e_usage: %s\n", | |||
757 | strerror(error)); | |||
758 | } | |||
759 | prop_object_release(dict); | |||
760 | return (1); | |||
761 | } |
--- 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 @@ | @@ -1,7 +1,18 @@ | |||
1 | # from: @(#)Makefile 8.1 (Berkeley) 6/6/93 | 1 | # from: @(#)Makefile 8.1 (Berkeley) 6/6/93 | |
2 | # $NetBSD: Makefile,v 1.5 1997/10/18 04:37:59 lukem Exp $ | 2 | # $NetBSD: Makefile,v 1.5.64.1 2011/01/21 16:58:06 bouyer Exp $ | |
3 | 3 | |||
4 | .include <bsd.own.mk> | |||
4 | PROG= repquota | 5 | PROG= repquota | |
6 | SRCS= repquota.c | |||
5 | MAN= repquota.8 | 7 | MAN= repquota.8 | |
6 | 8 | |||
9 | CPPFLAGS+=-I${NETBSDSRCDIR}/sys -I${NETBSDSRCDIR}/usr.bin/quota | |||
10 | DPADD= ${LIBPROP} | |||
11 | LDADD= -lprop | |||
12 | ||||
13 | .PATH: ${NETBSDSRCDIR}/usr.bin/quota | |||
14 | SRCS+= printquota.c | |||
15 | .PATH: ${NETBSDSRCDIR}/sys/ufs/ufs | |||
16 | SRCS+= quota2_prop.c | |||
17 | ||||
7 | .include <bsd.prog.mk> | 18 | .include <bsd.prog.mk> |
--- 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
@@ -19,81 +19,80 @@ | @@ -19,81 +19,80 @@ | |||
19 | .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | .\" SUCH DAMAGE. | 29 | .\" SUCH DAMAGE. | |
30 | .\" | 30 | .\" | |
31 | .\" from: @(#)repquota.8 8.1 (Berkeley) 6/6/93 | 31 | .\" from: @(#)repquota.8 8.1 (Berkeley) 6/6/93 | |
32 | .\" $NetBSD: repquota.8,v 1.9 2003/08/07 11:25:41 agc Exp $ | 32 | .\" $NetBSD: repquota.8,v 1.9.50.1 2011/01/21 16:58:07 bouyer Exp $ | |
33 | .\" | 33 | .\" | |
34 | .Dd June 6, 1993 | 34 | .Dd January 21, 2011 | |
35 | .Dt REPQUOTA 8 | 35 | .Dt REPQUOTA 8 | |
36 | .Os | 36 | .Os | |
37 | .Sh NAME | 37 | .Sh NAME | |
38 | .Nm repquota | 38 | .Nm repquota | |
39 | .Nd summarize quotas for a file system | 39 | .Nd summarize quotas for a file system | |
40 | .Sh SYNOPSIS | 40 | .Sh SYNOPSIS | |
41 | .Nm | 41 | .Nm | |
42 | .Op Fl h | |||
43 | .Op Fl D | |||
42 | .Op Fl g | 44 | .Op Fl g | |
43 | .Op Fl u | 45 | .Op Fl u | |
44 | .Op Fl v | 46 | .Op Fl v | |
45 | .Ar filesystem Ar ... | 47 | .Ar filesystem Ar ... | |
46 | .Nm | 48 | .Nm | |
49 | .Op Fl h | |||
50 | .Op Fl D | |||
47 | .Op Fl g | 51 | .Op Fl g | |
48 | .Op Fl u | 52 | .Op Fl u | |
49 | .Op Fl v | 53 | .Op Fl v | |
50 | .Fl a | 54 | .Fl a | |
51 | .Sh DESCRIPTION | 55 | .Sh DESCRIPTION | |
52 | .Nm | 56 | .Nm | |
53 | prints a summary of the disk usage and quotas for the | 57 | prints a summary of the disk usage and quotas for the | |
54 | specified file systems. | 58 | specified file systems. | |
55 | .Pp | 59 | .Pp | |
56 | Available options: | 60 | Available options: | |
57 | .Bl -tag -width Ds | 61 | .Bl -tag -width Ds | |
58 | .It Fl a | 62 | .It Fl a | |
59 | Print the quotas of all the filesystems listed in | 63 | Print the quotas of all the mounted filesystems. | |
60 | .Pa /etc/fstab . | |||
61 | .It Fl g | 64 | .It Fl g | |
62 | Print only group quotas (the default is to print both | 65 | Print only group quotas (the default is to print both | |
63 | group and user quotas if they exist). | 66 | group and user quotas if they exist). | |
64 | .It Fl u | 67 | .It Fl u | |
65 | Print only user quotas (the default is to print both | 68 | Print only user quotas (the default is to print both | |
66 | group and user quotas if they exist). | 69 | group and user quotas if they exist). | |
67 | .It Fl v | 70 | .It Fl v | |
68 | Print a header line before printing each filesystem quotas. | 71 | Print a header line before printing each filesystem quotas. | |
72 | .It Fl D | |||
73 | Debug: print plist sent to and received from kernel. | |||
74 | .It Fl h | |||
75 | Numbers are displayed in a human readable format. | |||
69 | .El | 76 | .El | |
70 | .Pp | 77 | .Pp | |
71 | For each user or group, the current | 78 | For each user or group, the current | |
72 | number files and amount of space (in kilobytes) is | 79 | number files and amount of space (in kilobytes, unless the | |
80 | .Fl h | |||
81 | flag is used) is | |||
73 | printed, along with any quotas created with | 82 | printed, along with any quotas created with | |
74 | .Xr edquota 8 . | 83 | .Xr edquota 8 . | |
75 | .Pp | 84 | .Pp | |
76 | Only members of the operator group or the super-user may | 85 | Only the super-user may use this command. | |
77 | use this command. | |||
78 | .Sh FILES | |||
79 | .Bl -tag -width quota.group -compact | |||
80 | .It Pa quota.user | |||
81 | at the filesystem root with user quotas | |||
82 | .It Pa quota.group | |||
83 | at the filesystem root with group quotas | |||
84 | .It Pa /etc/fstab | |||
85 | for file system names and locations | |||
86 | .El | |||
87 | .Sh DIAGNOSTICS | 86 | .Sh DIAGNOSTICS | |
88 | Various messages about inaccessible files; self-explanatory. | 87 | Various messages about inaccessible files; self-explanatory. | |
89 | .Sh SEE ALSO | 88 | .Sh SEE ALSO | |
90 | .Xr quota 1 , | 89 | .Xr quota 1 , | |
91 | .Xr quotactl 2 , | 90 | .Xr quotactl 2 , | |
92 | .Xr fstab 5 , | 91 | .Xr fstab 5 , | |
93 | .Xr edquota 8 , | 92 | .Xr edquota 8 , | |
94 | .Xr quotacheck 8 , | 93 | .Xr quotacheck 8 , | |
95 | .Xr quotaon 8 | 94 | .Xr quotaon 8 | |
96 | .Sh HISTORY | 95 | .Sh HISTORY | |
97 | The | 96 | The | |
98 | .Nm | 97 | .Nm | |
99 | command appeared in | 98 | command appeared in |
--- 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
@@ -30,239 +30,401 @@ | @@ -30,239 +30,401 @@ | |||
30 | * SUCH DAMAGE. | 30 | * SUCH DAMAGE. | |
31 | */ | 31 | */ | |
32 | 32 | |||
33 | #include <sys/cdefs.h> | 33 | #include <sys/cdefs.h> | |
34 | #ifndef lint | 34 | #ifndef lint | |
35 | __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\ | 35 | __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\ | |
36 | The Regents of the University of California. All rights reserved."); | 36 | The Regents of the University of California. All rights reserved."); | |
37 | #endif /* not lint */ | 37 | #endif /* not lint */ | |
38 | 38 | |||
39 | #ifndef lint | 39 | #ifndef lint | |
40 | #if 0 | 40 | #if 0 | |
41 | static char sccsid[] = "@(#)repquota.c 8.2 (Berkeley) 11/22/94"; | 41 | static char sccsid[] = "@(#)repquota.c 8.2 (Berkeley) 11/22/94"; | |
42 | #else | 42 | #else | |
43 | __RCSID("$NetBSD: repquota.c,v 1.25 2010/02/17 18:55:14 bouyer Exp $"); | 43 | __RCSID("$NetBSD: repquota.c,v 1.25.2.1 2011/01/21 16:58:07 bouyer Exp $"); | |
44 | #endif | 44 | #endif | |
45 | #endif /* not lint */ | 45 | #endif /* not lint */ | |
46 | 46 | |||
47 | /* | 47 | /* | |
48 | * Quota report | 48 | * Quota report | |
49 | */ | 49 | */ | |
50 | #include <sys/param.h> | 50 | #include <sys/param.h> | |
51 | #include <sys/stat.h> | 51 | #include <sys/stat.h> | |
52 | #include <sys/queue.h> | 52 | #include <sys/types.h> | |
53 | #include <ufs/ufs/quota.h> | 53 | #include <sys/statvfs.h> | |
54 | #include <prop/proplib.h> | |||
55 | #include <sys/quota.h> | |||
56 | ||||
54 | #include <errno.h> | 57 | #include <errno.h> | |
58 | #include <err.h> | |||
55 | #include <fstab.h> | 59 | #include <fstab.h> | |
56 | #include <grp.h> | 60 | #include <grp.h> | |
57 | #include <pwd.h> | 61 | #include <pwd.h> | |
58 | #include <stdio.h> | 62 | #include <stdio.h> | |
59 | #include <stdlib.h> | 63 | #include <stdlib.h> | |
60 | #include <string.h> | 64 | #include <string.h> | |
61 | #include <unistd.h> | 65 | #include <unistd.h> | |
62 | 66 | |||
63 | const char *qfname = QUOTAFILENAME; | 67 | #include <ufs/ufs/quota2_prop.h> | |
68 | #include <ufs/ufs/quota1.h> | |||
69 | ||||
70 | #include <printquota.h> | |||
71 | ||||
64 | const char *qfextension[] = INITQFNAMES; | 72 | const char *qfextension[] = INITQFNAMES; | |
73 | const char *qfname = QUOTAFILENAME; | |||
65 | 74 | |||
66 | struct fileusage { | 75 | struct fileusage { | |
67 | struct fileusage *fu_next; | 76 | struct fileusage *fu_next; | |
68 | struct dqblk fu_dqblk; | 77 | struct quota2_entry fu_q2e; | |
69 | u_long fu_id; | 78 | u_long fu_id; | |
70 | char fu_name[1]; | 79 | char fu_name[1]; | |
71 | /* actually bigger */ | 80 | /* actually bigger */ | |
72 | }; | 81 | }; | |
73 | #define FUHASH 1024 /* must be power of two */ | 82 | #define FUHASH 1024 /* must be power of two */ | |
74 | struct fileusage *fuhead[MAXQUOTAS][FUHASH]; | 83 | struct fileusage *fuhead[MAXQUOTAS][FUHASH]; | |
75 | u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ | 84 | u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ | |
85 | struct quota2_entry defaultq2e[MAXQUOTAS]; | |||
76 | 86 | |||
77 | int vflag; /* verbose */ | 87 | int vflag = 0; /* verbose */ | |
78 | int aflag; /* all file systems */ | 88 | int aflag = 0; /* all file systems */ | |
79 | 89 | int Dflag = 0; /* debug */ | ||
80 | struct fileusage *addid __P((u_long, int, const char *)); | 90 | int hflag = 0; /* debug */ | |
81 | int hasquota __P((struct fstab *, int, char **)); | 91 | ||
82 | struct fileusage *lookup __P((u_long, int)); | 92 | struct fileusage *addid(u_long, int, const char *); | |
83 | int main __P((int, char **)); | 93 | int hasquota(struct fstab *, int, char **); | |
84 | int oneof __P((const char *, char **, int)); | 94 | struct fileusage *lookup(u_long, int); | |
85 | int repquota __P((struct fstab *, int, char *)); | 95 | int main(int, char **); | |
86 | const char *timeprt __P((time_t)); | 96 | int oneof(const char *, char **, int); | |
87 | void usage __P((void)); | 97 | int repquota(const struct statvfs *, int); | |
98 | int repquota2(const struct statvfs *, int); | |||
99 | int repquota1(const struct statvfs *, int); | |||
100 | void usage(void); | |||
101 | void printquotas(int, const struct statvfs *); | |||
102 | void dqblk2q2e(const struct dqblk *, struct quota2_entry *); | |||
88 | 103 | |||
89 | int | 104 | int | |
90 | main(argc, argv) | 105 | main(argc, argv) | |
91 | int argc; | 106 | int argc; | |
92 | char **argv; | 107 | char **argv; | |
93 | { | 108 | { | |
94 | struct fstab *fs; | |||
95 | struct passwd *pw; | 109 | struct passwd *pw; | |
96 | struct group *gr; | 110 | struct group *gr; | |
97 | int gflag = 0, uflag = 0, errs = 0; | 111 | int gflag = 0, uflag = 0, errs = 0; | |
98 | long i, argnum, done = 0; | 112 | long i, argnum, done = 0; | |
99 | char *qfnp; | |||
100 | int ch; | 113 | int ch; | |
114 | struct statvfs *fst; | |||
115 | int nfst; | |||
101 | 116 | |||
102 | while ((ch = getopt(argc, argv, "aguv")) != -1) { | 117 | while ((ch = getopt(argc, argv, "Daguhv")) != -1) { | |
103 | switch(ch) { | 118 | switch(ch) { | |
104 | case 'a': | 119 | case 'a': | |
105 | aflag++; | 120 | aflag++; | |
106 | break; | 121 | break; | |
107 | case 'g': | 122 | case 'g': | |
108 | gflag++; | 123 | gflag++; | |
109 | break; | 124 | break; | |
110 | case 'u': | 125 | case 'u': | |
111 | uflag++; | 126 | uflag++; | |
112 | break; | 127 | break; | |
128 | case 'h': | |||
129 | hflag++; | |||
130 | break; | |||
113 | case 'v': | 131 | case 'v': | |
114 | vflag++; | 132 | vflag++; | |
115 | break; | 133 | break; | |
134 | case 'D': | |||
135 | Dflag++; | |||
136 | break; | |||
116 | default: | 137 | default: | |
117 | usage(); | 138 | usage(); | |
118 | } | 139 | } | |
119 | } | 140 | } | |
120 | argc -= optind; | 141 | argc -= optind; | |
121 | argv += optind; | 142 | argv += optind; | |
122 | if (argc == 0 && !aflag) | 143 | if (argc == 0 && !aflag) | |
123 | usage(); | 144 | usage(); | |
124 | if (!gflag && !uflag) { | 145 | if (!gflag && !uflag) { | |
125 | if (aflag) | 146 | if (aflag) | |
126 | gflag++; | 147 | gflag++; | |
127 | uflag++; | 148 | uflag++; | |
128 | } | 149 | } | |
129 | if (gflag) { | 150 | if (gflag) { | |
130 | setgrent(); | 151 | setgrent(); | |
131 | while ((gr = getgrent()) != 0) | 152 | while ((gr = getgrent()) != 0) | |
132 | (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); | 153 | (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); | |
133 | endgrent(); | 154 | endgrent(); | |
134 | } | 155 | } | |
135 | if (uflag) { | 156 | if (uflag) { | |
136 | setpwent(); | 157 | setpwent(); | |
137 | while ((pw = getpwent()) != 0) | 158 | while ((pw = getpwent()) != 0) | |
138 | (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); | 159 | (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); | |
139 | endpwent(); | 160 | endpwent(); | |
140 | } | 161 | } | |
141 | setfsent(); | 162 | ||
142 | while ((fs = getfsent()) != NULL) { | 163 | nfst = getmntinfo(&fst, MNT_WAIT); | |
143 | if (strcmp(fs->fs_vfstype, "ffs")) | 164 | if (nfst == 0) | |
165 | errx(2, "no filesystems mounted!"); | |||
166 | for (i = 0; i < nfst; i++) { | |||
167 | if (strncmp(fst[i].f_fstypename, "ffs", | |||
168 | sizeof(fst[i].f_fstypename)) != 0 || | |||
169 | (fst[i].f_flag & ST_QUOTA) == 0) | |||
144 | continue; | 170 | continue; | |
145 | if (aflag) { | 171 | if (aflag) { | |
146 | if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) | 172 | if (gflag) | |
147 | errs += repquota(fs, GRPQUOTA, qfnp); | 173 | errs += repquota(&fst[i], GRPQUOTA); | |
148 | if (uflag && hasquota(fs, USRQUOTA, &qfnp)) | 174 | if (uflag) | |
149 | errs += repquota(fs, USRQUOTA, qfnp); | 175 | errs += repquota(&fst[i], USRQUOTA); | |
150 | continue; | 176 | continue; | |
151 | } | 177 | } | |
152 | if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || | 178 | if ((argnum = oneof(fst[i].f_mntonname, argv, argc)) >= 0 || | |
153 | (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) { | 179 | (argnum = oneof(fst[i].f_mntfromname, argv, argc)) >= 0) { | |
154 | done |= 1 << argnum; | 180 | done |= 1 << argnum; | |
155 | if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) | 181 | if (gflag) | |
156 | errs += repquota(fs, GRPQUOTA, qfnp); | 182 | errs += repquota(&fst[i], GRPQUOTA); | |
157 | if (uflag && hasquota(fs, USRQUOTA, &qfnp)) | 183 | if (uflag) | |
158 | errs += repquota(fs, USRQUOTA, qfnp); | 184 | errs += repquota(&fst[i], USRQUOTA); | |
159 | } | 185 | } | |
160 | } | 186 | } | |
161 | endfsent(); | |||
162 | for (i = 0; i < argc; i++) | 187 | for (i = 0; i < argc; i++) | |
163 | if ((done & (1 << i)) == 0) | 188 | if ((done & (1 << i)) == 0) | |
164 | fprintf(stderr, "%s not found in fstab\n", argv[i]); | 189 | fprintf(stderr, "%s not mounted\n", argv[i]); | |
165 | exit(errs); | 190 | exit(errs); | |
166 | } | 191 | } | |
167 | 192 | |||
168 | void | 193 | void | |
169 | usage() | 194 | usage() | |
170 | { | 195 | { | |
171 | fprintf(stderr, "usage:\n\t%s\n\t%s\n", | 196 | fprintf(stderr, "usage:\n\t%s\n\t%s\n", | |
172 | "repquota [-v] [-g] [-u] -a", | 197 | "repquota [-D] [-v] [-g] [-u] -a", | |
173 | "repquota [-v] [-g] [-u] filesys ..."); | 198 | "repquota [-D] [-v] [-g] [-u] filesys ..."); | |
174 | exit(1); | 199 | exit(1); | |
175 | } | 200 | } | |
176 | 201 | |||
177 | int | 202 | int | |
178 | repquota(fs, type, qfpathname) | 203 | repquota(const struct statvfs *vfs, int type) | |
179 | struct fstab *fs; | 204 | { | |
180 | int type; | 205 | if (repquota2(vfs, type) != 0) | |
181 | char *qfpathname; | 206 | return (repquota1(vfs, type)); | |
207 | return 0; | |||
208 | } | |||
209 | ||||
210 | int | |||
211 | repquota2(const struct statvfs *vfs, int type) | |||
182 | { | 212 | { | |
213 | prop_dictionary_t dict, data, cmd; | |||
214 | prop_array_t cmds, datas; | |||
215 | struct plistref pref; | |||
216 | int error; | |||
217 | int8_t error8; | |||
218 | prop_object_iterator_t iter; | |||
219 | struct quota2_entry *q2ep; | |||
220 | struct fileusage *fup; | |||
221 | const char *strid; | |||
222 | uint32_t id; | |||
223 | ||||
224 | dict = quota2_prop_create(); | |||
225 | cmds = prop_array_create(); | |||
226 | datas = prop_array_create(); | |||
227 | ||||
228 | if (dict == NULL || cmds == NULL || datas == NULL) | |||
229 | errx(1, "can't allocate proplist"); | |||
230 | if (!quota2_prop_add_command(cmds, "getall", qfextension[type], datas)) | |||
231 | err(1, "prop_add_command"); | |||
232 | if (!prop_dictionary_set(dict, "commands", cmds)) | |||
233 | err(1, "prop_dictionary_set(command)"); | |||
234 | if (Dflag) | |||
235 | printf("message to kernel:\n%s\n", | |||
236 | prop_dictionary_externalize(dict)); | |||
237 | if (!prop_dictionary_send_syscall(dict, &pref)) | |||
238 | err(1, "prop_dictionary_send_syscall"); | |||
239 | prop_object_release(dict); | |||
240 | ||||
241 | if (quotactl(vfs->f_mntonname, &pref) != 0) | |||
242 | err(1, "quotactl"); | |||
243 | ||||
244 | if ((error = prop_dictionary_recv_syscall(&pref, &dict)) != 0) { | |||
245 | errx(1, "prop_dictionary_recv_syscall: %s\n", | |||
246 | strerror(error)); | |||
247 | } | |||
248 | if (Dflag) | |||
249 | printf("reply from kernel:\n%s\n", | |||
250 | prop_dictionary_externalize(dict)); | |||
251 | if ((error = quota2_get_cmds(dict, &cmds)) != 0) { | |||
252 | errx(1, "quota2_get_cmds: %s\n", | |||
253 | strerror(error)); | |||
254 | } | |||
255 | /* only one command, no need to iter */ | |||
256 | cmd = prop_array_get(cmds, 0); | |||
257 | if (cmd == NULL) | |||
258 | err(1, "prop_array_get(cmd)"); | |||
259 | ||||
260 | if (!prop_dictionary_get_int8(cmd, "return", &error8)) | |||
261 | err(1, "prop_get(return)"); | |||
262 | ||||
263 | if (error8) { | |||
264 | prop_object_release(dict); | |||
265 | if (error8 != EOPNOTSUPP) { | |||
266 | fprintf(stderr, "get %s quotas: %s\n", | |||
267 | qfextension[type], strerror(error8)); | |||
268 | } | |||
269 | return (error8); | |||
270 | } | |||
271 | datas = prop_dictionary_get(cmd, "data"); | |||
272 | if (datas == NULL) | |||
273 | err(1, "prop_dict_get(datas)"); | |||
274 | ||||
275 | iter = prop_array_iterator(datas); | |||
276 | if (iter == NULL) | |||
277 | err(1, "prop_array_iterator"); | |||
278 | ||||
279 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |||
280 | strid = NULL; | |||
281 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |||
282 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |||
283 | &strid)) | |||
284 | errx(1, "can't find id in quota entry"); | |||
285 | if (strcmp(strid, "default") != 0) { | |||
286 | errx(1, "wrong id string %s in quota entry", | |||
287 | strid); | |||
288 | } | |||
289 | q2ep = &defaultq2e[type]; | |||
290 | } else { | |||
291 | if ((fup = lookup(id, type)) == 0) | |||
292 | fup = addid(id, type, (char *)0); | |||
293 | q2ep = &fup->fu_q2e; | |||
294 | q2ep->q2e_uid = id; | |||
295 | } | |||
296 | ||||
297 | error = quota2_dict_get_q2e_usage(data, q2ep); | |||
298 | if (error) { | |||
299 | errx(1, "quota2_dict_get_q2e_usage: %s\n", | |||
300 | strerror(error)); | |||
301 | } | |||
302 | } | |||
303 | prop_object_iterator_release(iter); | |||
304 | prop_object_release(dict); | |||
305 | printquotas(type, vfs); | |||
306 | return (0); | |||
307 | } | |||
308 | ||||
309 | int repquota1(const struct statvfs *vfs, int type) | |||
310 | { | |||
311 | char *qfpathname; | |||
312 | struct fstab *fs; | |||
183 | struct fileusage *fup; | 313 | struct fileusage *fup; | |
184 | FILE *qf; | 314 | FILE *qf; | |
185 | u_long id; | 315 | u_long id; | |
186 | struct dqblk dqbuf; | 316 | struct dqblk dqbuf; | |
187 | static struct dqblk zerodqblk; | |||
188 | static int warned = 0; | |||
189 | static int multiple = 0; | |||
190 | 317 | |||
318 | #if 0 | |||
319 | static int warned = 0; | |||
191 | if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 && | 320 | if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 && | |
192 | errno == EOPNOTSUPP && !warned && vflag) { | 321 | errno == EOPNOTSUPP && !warned && vflag) { | |
193 | warned++; | 322 | warned++; | |
194 | fprintf(stdout, | 323 | fprintf(stdout, | |
195 | "*** Warning: Quotas are not compiled into this kernel\n"); | 324 | "*** Warning: Quotas are not compiled into this kernel\n"); | |
196 | } | 325 | } | |
197 | if (multiple++) | 326 | #endif | |
198 | printf("\n"); | 327 | setfsent(); | |
199 | if (vflag) | 328 | while ((fs = getfsent()) != NULL) { | |
200 | fprintf(stdout, "*** Report for %s quotas on %s (%s)\n", | 329 | if (strcmp(fs->fs_vfstype, "ffs") == 0 && | |
201 | qfextension[type], fs->fs_file, fs->fs_spec); | 330 | strcmp(fs->fs_file, vfs->f_mntonname) == 0) | |
331 | break; | |||
332 | } | |||
333 | endfsent(); | |||
334 | if (fs == NULL) { | |||
335 | fprintf(stderr, "%s not found in fstab\n", vfs->f_mntonname); | |||
336 | return 1; | |||
337 | } | |||
338 | if (!hasquota(fs, type, &qfpathname)) | |||
339 | return 0; | |||
340 | ||||
202 | if ((qf = fopen(qfpathname, "r")) == NULL) { | 341 | if ((qf = fopen(qfpathname, "r")) == NULL) { | |
203 | perror(qfpathname); | 342 | perror(qfpathname); | |
204 | return (1); | 343 | return (1); | |
205 | } | 344 | } | |
206 | for (id = 0; ; id++) { | 345 | for (id = 0; ; id++) { | |
207 | fread(&dqbuf, sizeof(struct dqblk), 1, qf); | 346 | fread(&dqbuf, sizeof(struct dqblk), 1, qf); | |
208 | if (feof(qf)) | 347 | if (feof(qf)) | |
209 | break; | 348 | break; | |
210 | if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0) | 349 | if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0) | |
211 | continue; | 350 | continue; | |
212 | if ((fup = lookup(id, type)) == 0) | 351 | if ((fup = lookup(id, type)) == 0) | |
213 | fup = addid(id, type, (char *)0); | 352 | fup = addid(id, type, (char *)0); | |
214 | fup->fu_dqblk = dqbuf; | 353 | dqblk2q2e(&dqbuf, &fup->fu_q2e); | |
215 | } | 354 | } | |
216 | fclose(qf); | 355 | fclose(qf); | |
356 | printquotas(type, vfs); | |||
357 | return (0); | |||
358 | } | |||
359 | ||||
360 | void | |||
361 | printquotas(int type, const struct statvfs *vfs) | |||
362 | { | |||
363 | static int multiple = 0; | |||
364 | u_long id; | |||
365 | struct fileusage *fup; | |||
366 | ||||
367 | if (multiple++) | |||
368 | printf("\n"); | |||
369 | if (vflag) | |||
370 | fprintf(stdout, "*** Report for %s quotas on %s (%s)\n", | |||
371 | qfextension[type], vfs->f_mntonname, vfs->f_mntfromname); | |||
217 | printf(" Block limits File limits\n"); | 372 | printf(" Block limits File limits\n"); | |
218 | printf(type == USRQUOTA ? "User " : "Group"); | 373 | printf(type == USRQUOTA ? "User " : "Group"); | |
219 | printf(" used soft hard grace used soft hard grace\n"); | 374 | printf(" used soft hard grace used soft hard grace\n"); | |
220 | for (id = 0; id <= highid[type]; id++) { | 375 | for (id = 0; id <= highid[type]; id++) { | |
221 | fup = lookup(id, type); | 376 | fup = lookup(id, type); | |
222 | if (fup == 0) | 377 | if (fup == 0) | |
223 | continue; | 378 | continue; | |
224 | if (fup->fu_dqblk.dqb_curinodes == 0 && | 379 | if (fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur == 0 && | |
225 | fup->fu_dqblk.dqb_curblocks == 0) | 380 | fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur == 0) | |
226 | continue; | 381 | continue; | |
227 | if (strlen(fup->fu_name) > 9) | 382 | if (strlen(fup->fu_name) > 9) | |
228 | printf("%s ", fup->fu_name); | 383 | printf("%s ", fup->fu_name); | |
229 | else | 384 | else | |
230 | printf("%-10s", fup->fu_name); | 385 | printf("%-10s", fup->fu_name); | |
231 | printf("%c%c%9d%9d%9d%7s", | 386 | printf("%c%c%9s%9s%9s%7s", | |
232 | fup->fu_dqblk.dqb_bsoftlimit && | 387 | fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit && | |
233 | fup->fu_dqblk.dqb_curblocks >= | 388 | fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur >= | |
234 | fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-', | 389 | fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit ? | |
235 | fup->fu_dqblk.dqb_isoftlimit && | 390 | '+' : '-', | |
236 | fup->fu_dqblk.dqb_curinodes >= | 391 | fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit && | |
237 | fup->fu_dqblk.dqb_isoftlimit ? '+' : '-', | 392 | fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur >= | |
238 | (int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_curblocks) / 1024), | 393 | fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit ? | |
239 | (int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_bsoftlimit) / 1024), | 394 | '+' : '-', | |
240 | (int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_bhardlimit) / 1024), | 395 | intprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur, | |
241 | fup->fu_dqblk.dqb_bsoftlimit && | 396 | HN_B, hflag), | |
242 | fup->fu_dqblk.dqb_curblocks >= | 397 | intprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit, | |
243 | fup->fu_dqblk.dqb_bsoftlimit ? | 398 | HN_B, hflag), | |
244 | timeprt(fup->fu_dqblk.dqb_btime) : ""); | 399 | intprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_hardlimit, | |
245 | printf(" %8d%8d%8d%7s\n", | 400 | HN_B, hflag), | |
246 | fup->fu_dqblk.dqb_curinodes, | 401 | (fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit && | |
247 | fup->fu_dqblk.dqb_isoftlimit, | 402 | fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_cur >= | |
248 | fup->fu_dqblk.dqb_ihardlimit, | 403 | fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_softlimit) ? | |
249 | fup->fu_dqblk.dqb_isoftlimit && | 404 | timeprt(fup->fu_q2e.q2e_val[Q2V_BLOCK].q2v_time) : ""); | |
250 | fup->fu_dqblk.dqb_curinodes >= | 405 | printf(" %8s%8s%8s%7s\n", | |
251 | fup->fu_dqblk.dqb_isoftlimit ? | 406 | intprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur, | |
252 | timeprt(fup->fu_dqblk.dqb_itime) : ""); | 407 | 0, hflag), | |
253 | fup->fu_dqblk = zerodqblk; | 408 | intprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit, | |
409 | 0, hflag), | |||
410 | intprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_hardlimit, | |||
411 | 0, hflag), | |||
412 | (fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit && | |||
413 | fup->fu_q2e.q2e_val[Q2V_FILE].q2v_cur >= | |||
414 | fup->fu_q2e.q2e_val[Q2V_FILE].q2v_softlimit) ? | |||
415 | timeprt(fup->fu_q2e.q2e_val[Q2V_FILE].q2v_time) : ""); | |||
416 | memset(&fup->fu_q2e, 0, sizeof(fup->fu_q2e)); | |||
254 | } | 417 | } | |
255 | return (0); | |||
256 | } | 418 | } | |
257 | 419 | |||
258 | /* | 420 | /* | |
259 | * Check to see if target appears in list of size cnt. | 421 | * Check to see if target appears in list of size cnt. | |
260 | */ | 422 | */ | |
261 | int | 423 | int | |
262 | oneof(target, list, cnt) | 424 | oneof(target, list, cnt) | |
263 | const char *target; | 425 | const char *target; | |
264 | char *list[]; | 426 | char *list[]; | |
265 | int cnt; | 427 | int cnt; | |
266 | { | 428 | { | |
267 | int i; | 429 | int i; | |
268 | 430 | |||
@@ -355,43 +517,26 @@ addid(id, type, name) | @@ -355,43 +517,26 @@ addid(id, type, name) | |||
355 | fup->fu_next = *fhp; | 517 | fup->fu_next = *fhp; | |
356 | *fhp = fup; | 518 | *fhp = fup; | |
357 | fup->fu_id = id; | 519 | fup->fu_id = id; | |
358 | if (id > highid[type]) | 520 | if (id > highid[type]) | |
359 | highid[type] = id; | 521 | highid[type] = id; | |
360 | if (name) { | 522 | if (name) { | |
361 | memmove(fup->fu_name, name, len + 1); | 523 | memmove(fup->fu_name, name, len + 1); | |
362 | } else { | 524 | } else { | |
363 | sprintf(fup->fu_name, "%lu", (u_long)id); | 525 | sprintf(fup->fu_name, "%lu", (u_long)id); | |
364 | } | 526 | } | |
365 | return (fup); | 527 | return (fup); | |
366 | } | 528 | } | |
367 | 529 | |||
368 | /* | 530 | void | |
369 | * Calculate the grace period and return a printable string for it. | 531 | dqblk2q2e(const struct dqblk *dqblk, struct quota2_entry *q2e) | |
370 | */ | 532 | { | |
371 | const char * | 533 | q2e->q2e_val[Q2V_BLOCK].q2v_hardlimit = dqblk->dqb_bhardlimit; | |
372 | timeprt(seconds) | 534 | q2e->q2e_val[Q2V_BLOCK].q2v_softlimit = dqblk->dqb_bsoftlimit; | |
373 | time_t seconds; | 535 | q2e->q2e_val[Q2V_BLOCK].q2v_cur = dqblk->dqb_curblocks; | |
374 | { | 536 | q2e->q2e_val[Q2V_BLOCK].q2v_time = dqblk->dqb_btime; | |
375 | time_t hours, minutes; | 537 | ||
376 | static char buf[20]; | 538 | q2e->q2e_val[Q2V_FILE].q2v_hardlimit = dqblk->dqb_ihardlimit; | |
377 | static time_t now; | 539 | q2e->q2e_val[Q2V_FILE].q2v_softlimit = dqblk->dqb_isoftlimit; | |
378 | 540 | q2e->q2e_val[Q2V_FILE].q2v_cur = dqblk->dqb_curinodes; | ||
379 | if (now == 0) | 541 | q2e->q2e_val[Q2V_FILE].q2v_time = dqblk->dqb_itime; | |
380 | time(&now); | 542 | } | |
381 | if (now > seconds) | |||
382 | return ("none"); | |||
383 | seconds -= now; | |||
384 | minutes = (seconds + 30) / 60; | |||
385 | hours = (minutes + 30) / 60; | |||
386 | if (hours >= 36) { | |||
387 | sprintf(buf, "%lddays", (long)((hours + 12) / 24)); | |||
388 | return (buf); | |||
389 | } | |||
390 | if (minutes >= 60) { | |||
391 | sprintf(buf, "%2ld:%ld", (long)(minutes / 60), | |||
392 | (long)(minutes % 60)); | |||
393 | return (buf); | |||
394 | } | |||
395 | sprintf(buf, "%2ld", (long)minutes); | |||
396 | return (buf); | |||
397 | } |