Mon Jan 30 19:16:36 2012 UTC ()
Don't use the old getvfsquota() here.


(dholland)
diff -r1.8 -r1.9 src/usr.sbin/edquota/Makefile
diff -r1.43 -r1.44 src/usr.sbin/edquota/edquota.c

cvs diff -r1.8 -r1.9 src/usr.sbin/edquota/Makefile (switch to unified diff)

--- src/usr.sbin/edquota/Makefile 2011/03/24 17:05:47 1.8
+++ src/usr.sbin/edquota/Makefile 2012/01/30 19:16:36 1.9
@@ -1,20 +1,20 @@ @@ -1,20 +1,20 @@
1# from: @(#)Makefile 8.1 (Berkeley) 6/6/93 1# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
2# $NetBSD: Makefile,v 1.8 2011/03/24 17:05:47 bouyer Exp $ 2# $NetBSD: Makefile,v 1.9 2012/01/30 19:16:36 dholland Exp $
3 3
4.include <bsd.own.mk> 4.include <bsd.own.mk>
5 5
6WARNS ?= 4 6WARNS ?= 4
7PROG= edquota 7PROG= edquota
8SRCS= edquota.c 8SRCS= edquota.c
9MAN= edquota.8 9MAN= edquota.8
10 10
11CPPFLAGS+=-I${NETBSDSRCDIR}/sys -I${NETBSDSRCDIR}/usr.bin/quota 11CPPFLAGS+=-I${NETBSDSRCDIR}/sys -I${NETBSDSRCDIR}/usr.bin/quota
12DPADD= ${LIBQUOTA} ${LIBPROP} ${LIBRPCSVC} 12DPADD= ${LIBQUOTA} ${LIBPROP} ${LIBRPCSVC}
13LDADD= -lquota -lprop -lrpcsvc 13LDADD= -lquota -lprop -lrpcsvc
14 14
15.PATH: ${NETBSDSRCDIR}/usr.bin/quota 15.PATH: ${NETBSDSRCDIR}/usr.bin/quota
16SRCS+= getvfsquota.c printquota.c quotautil.c 16SRCS+= printquota.c quotautil.c
17.PATH: ${NETBSDSRCDIR}/sys/ufs/ufs  17.PATH: ${NETBSDSRCDIR}/sys/ufs/ufs
18SRCS+= quota1_subr.c 18SRCS+= quota1_subr.c
19 19
20.include <bsd.prog.mk> 20.include <bsd.prog.mk>

cvs diff -r1.43 -r1.44 src/usr.sbin/edquota/edquota.c (switch to unified diff)

--- src/usr.sbin/edquota/edquota.c 2012/01/29 07:16:00 1.43
+++ src/usr.sbin/edquota/edquota.c 2012/01/30 19:16:36 1.44
@@ -1,1217 +1,1254 @@ @@ -1,1217 +1,1254 @@
1/* $NetBSD: edquota.c,v 1.43 2012/01/29 07:16:00 dholland Exp $ */ 1/* $NetBSD: edquota.c,v 1.44 2012/01/30 19:16:36 dholland Exp $ */
2/* 2/*
3 * Copyright (c) 1980, 1990, 1993 3 * Copyright (c) 1980, 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
15 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors 17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software 18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission. 19 * without specific prior written permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE. 31 * SUCH DAMAGE.
32 */ 32 */
33 33
34#include <sys/cdefs.h> 34#include <sys/cdefs.h>
35#ifndef lint 35#ifndef lint
36__COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\ 36__COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\
37 The Regents of the University of California. All rights reserved."); 37 The Regents of the University of California. All rights reserved.");
38#endif /* not lint */ 38#endif /* not lint */
39 39
40#ifndef lint 40#ifndef lint
41#if 0 41#if 0
42static char sccsid[] = "from: @(#)edquota.c 8.3 (Berkeley) 4/27/95"; 42static char sccsid[] = "from: @(#)edquota.c 8.3 (Berkeley) 4/27/95";
43#else 43#else
44__RCSID("$NetBSD: edquota.c,v 1.43 2012/01/29 07:16:00 dholland Exp $"); 44__RCSID("$NetBSD: edquota.c,v 1.44 2012/01/30 19:16:36 dholland Exp $");
45#endif 45#endif
46#endif /* not lint */ 46#endif /* not lint */
47 47
48/* 48/*
49 * Disk quota editor. 49 * Disk quota editor.
50 */ 50 */
51#include <sys/param.h> 51#include <sys/param.h>
52#include <sys/stat.h> 52#include <sys/stat.h>
53#include <sys/file.h> 53#include <sys/file.h>
54#include <sys/wait.h> 54#include <sys/wait.h>
55#include <sys/queue.h> 55#include <sys/queue.h>
56#include <sys/types.h> 56#include <sys/types.h>
57#include <sys/statvfs.h> 57#include <sys/statvfs.h>
58 58
59#include <quota.h> 59#include <quota.h>
60#include <quota/quotaprop.h> 60#include <quota/quotaprop.h>
61#include <quota/quota.h> 61#include <quota/quota.h>
62#include <ufs/ufs/quota1.h> 62#include <ufs/ufs/quota1.h>
63#include <sys/quota.h> 
64 63
65#include <assert.h> 64#include <assert.h>
66#include <err.h> 65#include <err.h>
67#include <errno.h> 66#include <errno.h>
68#include <fstab.h> 67#include <fstab.h>
69#include <pwd.h> 68#include <pwd.h>
70#include <grp.h> 69#include <grp.h>
71#include <ctype.h> 70#include <ctype.h>
72#include <signal.h> 71#include <signal.h>
73#include <stdbool.h> 72#include <stdbool.h>
74#include <stdio.h> 73#include <stdio.h>
75#include <stdlib.h> 74#include <stdlib.h>
76#include <string.h> 75#include <string.h>
77#include <unistd.h> 76#include <unistd.h>
78 77
79#include "printquota.h" 78#include "printquota.h"
80#include "getvfsquota.h" 
81#include "quotautil.h" 79#include "quotautil.h"
82 80
83#include "pathnames.h" 81#include "pathnames.h"
84 82
85static const char *quotagroup = QUOTAGROUP; 83static const char *quotagroup = QUOTAGROUP;
86 84
87#define MAX_TMPSTR (100+MAXPATHLEN) 85#define MAX_TMPSTR (100+MAXPATHLEN)
88 86
89/* flags for quotause */ 87/* flags for quotause */
90#define FOUND 0x01 88#define FOUND 0x01
91#define QUOTA2 0x02 89#define XGRACE 0x02 /* extended grace periods (per-id) */
92#define DEFAULT 0x04 90#define DEFAULT 0x04
93 91
94struct quotause { 92struct quotause {
95 struct quotause *next; 93 struct quotause *next;
96 long flags; 94 long flags;
97 struct quotaval qv[QUOTA_NLIMITS]; 95 struct quotaval qv[QUOTA_NLIMITS];
98 char fsname[MAXPATHLEN + 1]; 96 char fsname[MAXPATHLEN + 1];
 97 char implementation[32];
99 char *qfname; 98 char *qfname;
100}; 99};
101 100
102struct quotalist { 101struct quotalist {
103 struct quotause *head; 102 struct quotause *head;
104 struct quotause *tail; 103 struct quotause *tail;
105}; 104};
106 105
107static void usage(void) __dead; 106static void usage(void) __dead;
108 107
109static int Hflag = 0; 108static int Hflag = 0;
110static int Dflag = 0; 
111 109
112/* more compact form of constants */ 110/* more compact form of constants */
113#define QL_BLK QUOTA_LIMIT_BLOCK 111#define QL_BLK QUOTA_LIMIT_BLOCK
114#define QL_FL QUOTA_LIMIT_FILE 112#define QL_FL QUOTA_LIMIT_FILE
115 113
116//////////////////////////////////////////////////////////// 114////////////////////////////////////////////////////////////
117// support code 115// support code
118 116
119/* 117/*
120 * This routine converts a name for a particular quota class to 118 * This routine converts a name for a particular quota class to
121 * an identifier. This routine must agree with the kernel routine 119 * an identifier. This routine must agree with the kernel routine
122 * getinoquota as to the interpretation of quota classes. 120 * getinoquota as to the interpretation of quota classes.
123 */ 121 */
124static int 122static int
125getidbyname(const char *name, int idtype) 123getidbyname(const char *name, int idtype)
126{ 124{
127 struct passwd *pw; 125 struct passwd *pw;
128 struct group *gr; 126 struct group *gr;
129 127
130 if (alldigits(name)) 128 if (alldigits(name))
131 return atoi(name); 129 return atoi(name);
132 switch (idtype) { 130 switch (idtype) {
133 case QUOTA_IDTYPE_USER: 131 case QUOTA_IDTYPE_USER:
134 if ((pw = getpwnam(name)) != NULL) 132 if ((pw = getpwnam(name)) != NULL)
135 return pw->pw_uid; 133 return pw->pw_uid;
136 warnx("%s: no such user", name); 134 warnx("%s: no such user", name);
137 break; 135 break;
138 case QUOTA_IDTYPE_GROUP: 136 case QUOTA_IDTYPE_GROUP:
139 if ((gr = getgrnam(name)) != NULL) 137 if ((gr = getgrnam(name)) != NULL)
140 return gr->gr_gid; 138 return gr->gr_gid;
141 warnx("%s: no such group", name); 139 warnx("%s: no such group", name);
142 break; 140 break;
143 default: 141 default:
144 warnx("%d: unknown quota type", idtype); 142 warnx("%d: unknown quota type", idtype);
145 break; 143 break;
146 } 144 }
147 sleep(1); 145 sleep(1);
148 return -1; 146 return -1;
149} 147}
150 148
151//////////////////////////////////////////////////////////// 149////////////////////////////////////////////////////////////
152// quotause operations 150// quotause operations
153 151
154/* 152/*
155 * Create an empty quotause structure. 153 * Create an empty quotause structure.
156 */ 154 */
157static struct quotause * 155static struct quotause *
158quotause_create(void) 156quotause_create(void)
159{ 157{
160 struct quotause *qup; 158 struct quotause *qup;
161 159
162 qup = malloc(sizeof(*qup)); 160 qup = malloc(sizeof(*qup));
163 if (qup == NULL) { 161 if (qup == NULL) {
164 err(1, "malloc"); 162 err(1, "malloc");
165 } 163 }
166 164
167 qup->next = NULL; 165 qup->next = NULL;
168 qup->flags = 0; 166 qup->flags = 0;
169 memset(qup->qv, 0, sizeof(qup->qv)); 167 memset(qup->qv, 0, sizeof(qup->qv));
170 qup->fsname[0] = '\0'; 168 qup->fsname[0] = '\0';
171 qup->qfname = NULL; 169 qup->qfname = NULL;
172 170
173 return qup; 171 return qup;
174} 172}
175 173
176/* 174/*
177 * Free a quotause structure. 175 * Free a quotause structure.
178 */ 176 */
179static void 177static void
180quotause_destroy(struct quotause *qup) 178quotause_destroy(struct quotause *qup)
181{ 179{
182 free(qup->qfname); 180 free(qup->qfname);
183 free(qup); 181 free(qup);
184} 182}
185 183
186//////////////////////////////////////////////////////////// 184////////////////////////////////////////////////////////////
187// quotalist operations 185// quotalist operations
188 186
189/* 187/*
190 * Create a quotause list. 188 * Create a quotause list.
191 */ 189 */
192static struct quotalist * 190static struct quotalist *
193quotalist_create(void) 191quotalist_create(void)
194{ 192{
195 struct quotalist *qlist; 193 struct quotalist *qlist;
196 194
197 qlist = malloc(sizeof(*qlist)); 195 qlist = malloc(sizeof(*qlist));
198 if (qlist == NULL) { 196 if (qlist == NULL) {
199 err(1, "malloc"); 197 err(1, "malloc");
200 } 198 }
201 199
202 qlist->head = NULL; 200 qlist->head = NULL;
203 qlist->tail = NULL; 201 qlist->tail = NULL;
204 202
205 return qlist; 203 return qlist;
206} 204}
207 205
208/* 206/*
209 * Free a list of quotause structures. 207 * Free a list of quotause structures.
210 */ 208 */
211static void 209static void
212quotalist_destroy(struct quotalist *qlist) 210quotalist_destroy(struct quotalist *qlist)
213{ 211{
214 struct quotause *qup, *nextqup; 212 struct quotause *qup, *nextqup;
215 213
216 for (qup = qlist->head; qup; qup = nextqup) { 214 for (qup = qlist->head; qup; qup = nextqup) {
217 nextqup = qup->next; 215 nextqup = qup->next;
218 quotause_destroy(qup); 216 quotause_destroy(qup);
219 } 217 }
220 free(qlist); 218 free(qlist);
221} 219}
222 220
223static bool 221static bool
224quotalist_empty(struct quotalist *qlist) 222quotalist_empty(struct quotalist *qlist)
225{ 223{
226 return qlist->head == NULL; 224 return qlist->head == NULL;
227} 225}
228 226
229static void 227static void
230quotalist_append(struct quotalist *qlist, struct quotause *qup) 228quotalist_append(struct quotalist *qlist, struct quotause *qup)
231{ 229{
232 /* should not already be on a list */ 230 /* should not already be on a list */
233 assert(qup->next == NULL); 231 assert(qup->next == NULL);
234 232
235 if (qlist->head == NULL) { 233 if (qlist->head == NULL) {
236 qlist->head = qup; 234 qlist->head = qup;
237 } else { 235 } else {
238 qlist->tail->next = qup; 236 qlist->tail->next = qup;
239 } 237 }
240 qlist->tail = qup; 238 qlist->tail = qup;
241} 239}
242 240
243//////////////////////////////////////////////////////////// 241////////////////////////////////////////////////////////////
244// ffs quota v1 242// ffs quota v1
245 243
246static void 244static void
247putprivs1(uint32_t id, int idtype, struct quotause *qup) 245putprivs1(uint32_t id, int idtype, struct quotause *qup)
248{ 246{
249 struct dqblk dqblk; 247 struct dqblk dqblk;
250 int fd; 248 int fd;
251 249
252 quotavals_to_dqblk(&qup->qv[QUOTA_LIMIT_BLOCK], 250 quotavals_to_dqblk(&qup->qv[QUOTA_LIMIT_BLOCK],
253 &qup->qv[QUOTA_LIMIT_FILE], 251 &qup->qv[QUOTA_LIMIT_FILE],
254 &dqblk); 252 &dqblk);
255 assert((qup->flags & DEFAULT) == 0); 253 assert((qup->flags & DEFAULT) == 0);
256 254
257 if ((fd = open(qup->qfname, O_WRONLY)) < 0) { 255 if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
258 warnx("open `%s'", qup->qfname); 256 warnx("open `%s'", qup->qfname);
259 } else { 257 } else {
260 (void)lseek(fd, 258 (void)lseek(fd,
261 (off_t)(id * (long)sizeof (struct dqblk)), 259 (off_t)(id * (long)sizeof (struct dqblk)),
262 SEEK_SET); 260 SEEK_SET);
263 if (write(fd, &dqblk, sizeof (struct dqblk)) != 261 if (write(fd, &dqblk, sizeof (struct dqblk)) !=
264 sizeof (struct dqblk)) 262 sizeof (struct dqblk))
265 warnx("writing `%s'", qup->qfname); 263 warnx("writing `%s'", qup->qfname);
266 close(fd); 264 close(fd);
267 } 265 }
268} 266}
269 267
270static struct quotause * 268static struct quotause *
271getprivs1(long id, int idtype, const char *filesys) 269getprivs1(long id, int idtype, const char *filesys)
272{ 270{
273 struct fstab *fs; 271 struct fstab *fs;
274 char qfpathname[MAXPATHLEN]; 272 char qfpathname[MAXPATHLEN];
275 struct quotause *qup; 273 struct quotause *qup;
276 struct dqblk dqblk; 274 struct dqblk dqblk;
277 int fd; 275 int fd;
278 276
279 setfsent(); 277 setfsent();
280 while ((fs = getfsent()) != NULL) { 278 while ((fs = getfsent()) != NULL) {
281 if (strcmp(fs->fs_vfstype, "ffs")) 279 if (strcmp(fs->fs_vfstype, "ffs"))
282 continue; 280 continue;
283 if (strcmp(fs->fs_spec, filesys) == 0 || 281 if (strcmp(fs->fs_spec, filesys) == 0 ||
284 strcmp(fs->fs_file, filesys) == 0) 282 strcmp(fs->fs_file, filesys) == 0)
285 break; 283 break;
286 } 284 }
287 if (fs == NULL) 285 if (fs == NULL)
288 return NULL; 286 return NULL;
289 287
290 if (!hasquota(qfpathname, sizeof(qfpathname), fs, 288 if (!hasquota(qfpathname, sizeof(qfpathname), fs,
291 quota_idtype_to_ufs(idtype))) 289 quota_idtype_to_ufs(idtype)))
292 return NULL; 290 return NULL;
293 291
294 qup = quotause_create(); 292 qup = quotause_create();
295 strcpy(qup->fsname, fs->fs_file); 293 strcpy(qup->fsname, fs->fs_file);
296 if ((fd = open(qfpathname, O_RDONLY)) < 0) { 294 if ((fd = open(qfpathname, O_RDONLY)) < 0) {
297 fd = open(qfpathname, O_RDWR|O_CREAT, 0640); 295 fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
298 if (fd < 0 && errno != ENOENT) { 296 if (fd < 0 && errno != ENOENT) {
299 warnx("open `%s'", qfpathname); 297 warnx("open `%s'", qfpathname);
300 quotause_destroy(qup); 298 quotause_destroy(qup);
301 return NULL; 299 return NULL;
302 } 300 }
303 warnx("Creating quota file %s", qfpathname); 301 warnx("Creating quota file %s", qfpathname);
304 sleep(3); 302 sleep(3);
305 (void)fchown(fd, getuid(), 303 (void)fchown(fd, getuid(),
306 getidbyname(quotagroup, QUOTA_CLASS_GROUP)); 304 getidbyname(quotagroup, QUOTA_CLASS_GROUP));
307 (void)fchmod(fd, 0640); 305 (void)fchmod(fd, 0640);
308 } 306 }
309 (void)lseek(fd, (off_t)(id * sizeof(struct dqblk)), 307 (void)lseek(fd, (off_t)(id * sizeof(struct dqblk)),
310 SEEK_SET); 308 SEEK_SET);
311 switch (read(fd, &dqblk, sizeof(struct dqblk))) { 309 switch (read(fd, &dqblk, sizeof(struct dqblk))) {
312 case 0: /* EOF */ 310 case 0: /* EOF */
313 /* 311 /*
314 * Convert implicit 0 quota (EOF) 312 * Convert implicit 0 quota (EOF)
315 * into an explicit one (zero'ed dqblk) 313 * into an explicit one (zero'ed dqblk)
316 */ 314 */
317 memset(&dqblk, 0, sizeof(struct dqblk)); 315 memset(&dqblk, 0, sizeof(struct dqblk));
318 break; 316 break;
319 317
320 case sizeof(struct dqblk): /* OK */ 318 case sizeof(struct dqblk): /* OK */
321 break; 319 break;
322 320
323 default: /* ERROR */ 321 default: /* ERROR */
324 warn("read error in `%s'", qfpathname); 322 warn("read error in `%s'", qfpathname);
325 close(fd); 323 close(fd);
326 quotause_destroy(qup); 324 quotause_destroy(qup);
327 return NULL; 325 return NULL;
328 } 326 }
329 close(fd); 327 close(fd);
330 qup->qfname = qfpathname; 328 qup->qfname = qfpathname;
331 endfsent(); 329 endfsent();
332 dqblk_to_quotavals(&dqblk, 330 dqblk_to_quotavals(&dqblk,
333 &qup->qv[QUOTA_LIMIT_BLOCK], 331 &qup->qv[QUOTA_LIMIT_BLOCK],
334 &qup->qv[QUOTA_LIMIT_FILE]); 332 &qup->qv[QUOTA_LIMIT_FILE]);
335 return qup; 333 return qup;
336} 334}
337 335
338//////////////////////////////////////////////////////////// 336////////////////////////////////////////////////////////////
339// ffs quota v2 337// ffs quota v2
340 338
 339static int
 340dogetprivs2(struct quotahandle *qh, int idtype, id_t id, int defaultq,
 341 int objtype, struct quotause *qup)
 342{
 343 struct quotakey qk;
 344
 345 qk.qk_idtype = idtype;
 346 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
 347 qk.qk_objtype = objtype;
 348 if (quota_get(qh, &qk, &qup->qv[objtype])) {
 349 /* no entry, get default entry */
 350 qk.qk_id = QUOTA_DEFAULTID;
 351 if (quota_get(qh, &qk, &qup->qv[objtype])) {
 352 return -1;
 353 }
 354 }
 355 return 0;
 356}
 357
341static struct quotause * 358static struct quotause *
342getprivs2(long id, int idtype, const char *filesys, int defaultq) 359getprivs2(long id, int idtype, const char *filesys, int defaultq)
343{ 360{
344 struct quotause *qup; 361 struct quotause *qup;
345 int8_t version; 362 struct quotahandle *qh;
 363 const char *impl;
 364 unsigned restrictions;
346 365
347 qup = quotause_create(); 366 qup = quotause_create();
348 strcpy(qup->fsname, filesys); 367 strcpy(qup->fsname, filesys);
349 if (defaultq) 368 if (defaultq)
350 qup->flags |= DEFAULT; 369 qup->flags |= DEFAULT;
351 if (!getvfsquota(filesys, qup->qv, &version, 370
352 id, idtype, defaultq, Dflag)) { 371 qh = quota_open(filesys);
353 /* no entry, get default entry */ 372 if (qh == NULL) {
354 if (!getvfsquota(filesys, qup->qv, &version, 373 quotause_destroy(qup);
355 id, idtype, 1, Dflag)) { 374 return NULL;
356 free(qup); 
357 return NULL; 
358 } 
359 } 375 }
360 if (version == 2) 376
361 qup->flags |= QUOTA2; 377 impl = quota_getimplname(qh);
 378 if (impl == NULL) {
 379 impl = "???";
 380 }
 381 strlcpy(qup->implementation, impl, sizeof(qup->implementation));
 382
 383 restrictions = quota_getrestrictions(qh);
 384 if ((restrictions & QUOTA_RESTRICT_UNIFORMGRACE) == 0) {
 385 qup->flags |= XGRACE;
 386 }
 387
 388 if (dogetprivs2(qh, idtype, id, defaultq, QUOTA_OBJTYPE_BLOCKS, qup)) {
 389 quota_close(qh);
 390 quotause_destroy(qup);
 391 return NULL;
 392 }
 393
 394 if (dogetprivs2(qh, idtype, id, defaultq, QUOTA_OBJTYPE_FILES, qup)) {
 395 quota_close(qh);
 396 quotause_destroy(qup);
 397 return NULL;
 398 }
 399
 400 quota_close(qh);
 401
362 return qup; 402 return qup;
363} 403}
364 404
365static void 405static void
366putprivs2(uint32_t id, int idtype, struct quotause *qup) 406putprivs2(uint32_t id, int idtype, struct quotause *qup)
367{ 407{
368 struct quotahandle *qh; 408 struct quotahandle *qh;
369 struct quotakey qk; 409 struct quotakey qk;
370 char idname[32]; 410 char idname[32];
371 411
372 if (qup->flags & DEFAULT) { 412 if (qup->flags & DEFAULT) {
373 snprintf(idname, sizeof(idname), "%s default", 413 snprintf(idname, sizeof(idname), "%s default",
374 idtype == QUOTA_IDTYPE_USER ? "user" : "group"); 414 idtype == QUOTA_IDTYPE_USER ? "user" : "group");
375 id = QUOTA_DEFAULTID; 415 id = QUOTA_DEFAULTID;
376 } else { 416 } else {
377 snprintf(idname, sizeof(idname), "%s %u", 417 snprintf(idname, sizeof(idname), "%s %u",
378 idtype == QUOTA_IDTYPE_USER ? "uid" : "gid", id); 418 idtype == QUOTA_IDTYPE_USER ? "uid" : "gid", id);
379 } 419 }
380 420
381 qh = quota_open(qup->fsname); 421 qh = quota_open(qup->fsname);
382 if (qh == NULL) { 422 if (qh == NULL) {
383 err(1, "%s: quota_open", qup->fsname); 423 err(1, "%s: quota_open", qup->fsname);
384 } 424 }
385 425
386 qk.qk_idtype = idtype; 426 qk.qk_idtype = idtype;
387 qk.qk_id = id; 427 qk.qk_id = id;
388 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 428 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
389 if (quota_put(qh, &qk, &qup->qv[QL_BLK])) { 429 if (quota_put(qh, &qk, &qup->qv[QL_BLK])) {
390 err(1, "%s: quota_put (%s blocks)", qup->fsname, idname); 430 err(1, "%s: quota_put (%s blocks)", qup->fsname, idname);
391 } 431 }
392 432
393 qk.qk_idtype = idtype; 433 qk.qk_idtype = idtype;
394 qk.qk_id = id; 434 qk.qk_id = id;
395 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 435 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
396 if (quota_put(qh, &qk, &qup->qv[QL_FL])) { 436 if (quota_put(qh, &qk, &qup->qv[QL_FL])) {
397 err(1, "%s: quota_put (%s files)", qup->fsname, idname); 437 err(1, "%s: quota_put (%s files)", qup->fsname, idname);
398 } 438 }
399 439
400 quota_close(qh); 440 quota_close(qh);
401} 441}
402 442
403//////////////////////////////////////////////////////////// 443////////////////////////////////////////////////////////////
404// quota format switch 444// quota format switch
405 445
406/* 446/*
407 * Collect the requested quota information. 447 * Collect the requested quota information.
408 */ 448 */
409static struct quotalist * 449static struct quotalist *
410getprivs(long id, int defaultq, int idtype, const char *filesys) 450getprivs(long id, int defaultq, int idtype, const char *filesys)
411{ 451{
412 struct statvfs *fst; 452 struct statvfs *fst;
413 int nfst, i; 453 int nfst, i;
414 struct quotalist *qlist; 454 struct quotalist *qlist;
415 struct quotause *qup; 455 struct quotause *qup;
416 456
417 qlist = quotalist_create(); 457 qlist = quotalist_create();
418 458
419 nfst = getmntinfo(&fst, MNT_WAIT); 459 nfst = getmntinfo(&fst, MNT_WAIT);
420 if (nfst == 0) 460 if (nfst == 0)
421 errx(1, "no filesystems mounted!"); 461 errx(1, "no filesystems mounted!");
422 462
423 for (i = 0; i < nfst; i++) { 463 for (i = 0; i < nfst; i++) {
424 if ((fst[i].f_flag & ST_QUOTA) == 0) 464 if ((fst[i].f_flag & ST_QUOTA) == 0)
425 continue; 465 continue;
426 if (filesys && 466 if (filesys &&
427 strcmp(fst[i].f_mntonname, filesys) != 0 && 467 strcmp(fst[i].f_mntonname, filesys) != 0 &&
428 strcmp(fst[i].f_mntfromname, filesys) != 0) 468 strcmp(fst[i].f_mntfromname, filesys) != 0)
429 continue; 469 continue;
430 qup = getprivs2(id, idtype, fst[i].f_mntonname, defaultq); 470 qup = getprivs2(id, idtype, fst[i].f_mntonname, defaultq);
431 if (qup == NULL) { 471 if (qup == NULL) {
432 /* 472 /*
433 * XXX: returning NULL is totally wrong. On 473 * XXX: returning NULL is totally wrong. On
434 * serious error, abort; on minor error, warn 474 * serious error, abort; on minor error, warn
435 * and continue. 475 * and continue.
436 * 476 *
437 * Note: we cannot warn unconditionally here 477 * Note: we cannot warn unconditionally here
438 * because this case apparently includes "no 478 * because this case apparently includes "no
439 * quota entry on this volume" and that causes 479 * quota entry on this volume" and that causes
440 * the atf tests to fail. Bletch. 480 * the atf tests to fail. Bletch.
441 */ 481 */
442 /*return NULL;*/ 482 /*return NULL;*/
443 /*warnx("getprivs2 failed");*/ 483 /*warnx("getprivs2 failed");*/
444 continue; 484 continue;
445 } 485 }
446 486
447 quotalist_append(qlist, qup); 487 quotalist_append(qlist, qup);
448 } 488 }
449 489
450 if (filesys && quotalist_empty(qlist)) { 490 if (filesys && quotalist_empty(qlist)) {
451 if (defaultq) 491 if (defaultq)
452 errx(1, "no default quota for version 1"); 492 errx(1, "no default quota for version 1");
453 /* if we get there, filesys is not mounted. try the old way */ 493 /* if we get there, filesys is not mounted. try the old way */
454 qup = getprivs1(id, idtype, filesys); 494 qup = getprivs1(id, idtype, filesys);
455 if (qup == NULL) { 495 if (qup == NULL) {
456 /* XXX. see above */ 496 /* XXX. see above */
457 /*return NULL;*/ 497 /*return NULL;*/
458 /*warnx("getprivs1 failed");*/ 498 /*warnx("getprivs1 failed");*/
459 return qlist; 499 return qlist;
460 } 500 }
461 quotalist_append(qlist, qup); 501 quotalist_append(qlist, qup);
462 } 502 }
463 return qlist; 503 return qlist;
464} 504}
465 505
466/* 506/*
467 * Store the requested quota information. 507 * Store the requested quota information.
468 */ 508 */
469static void 509static void
470putprivs(uint32_t id, int idtype, struct quotalist *qlist) 510putprivs(uint32_t id, int idtype, struct quotalist *qlist)
471{ 511{
472 struct quotause *qup; 512 struct quotause *qup;
473 513
474 for (qup = qlist->head; qup; qup = qup->next) { 514 for (qup = qlist->head; qup; qup = qup->next) {
475 if (qup->qfname == NULL) 515 if (qup->qfname == NULL)
476 putprivs2(id, idtype, qup); 516 putprivs2(id, idtype, qup);
477 else 517 else
478 putprivs1(id, idtype, qup); 518 putprivs1(id, idtype, qup);
479 } 519 }
480} 520}
481 521
482static void 522static void
483clearpriv(int argc, char **argv, const char *filesys, int idtype) 523clearpriv(int argc, char **argv, const char *filesys, int idtype)
484{ 524{
485 struct statvfs *fst; 525 struct statvfs *fst;
486 int nfst, i; 526 int nfst, i;
487 int id; 527 int id;
488 id_t *ids; 528 id_t *ids;
489 unsigned nids, maxids, j; 529 unsigned nids, maxids, j;
490 struct quotahandle *qh; 530 struct quotahandle *qh;
491 struct quotakey qk; 531 struct quotakey qk;
492 char idname[32]; 532 char idname[32];
493 533
494 maxids = 4; 534 maxids = 4;
495 nids = 0; 535 nids = 0;
496 ids = malloc(maxids * sizeof(ids[0])); 536 ids = malloc(maxids * sizeof(ids[0]));
497 if (ids == NULL) { 537 if (ids == NULL) {
498 err(1, "malloc"); 538 err(1, "malloc");
499 } 539 }
500 540
501 for ( ; argc > 0; argc--, argv++) { 541 for ( ; argc > 0; argc--, argv++) {
502 if ((id = getidbyname(*argv, idtype)) == -1) 542 if ((id = getidbyname(*argv, idtype)) == -1)
503 continue; 543 continue;
504 544
505 if (nids + 1 > maxids) { 545 if (nids + 1 > maxids) {
506 maxids *= 2; 546 maxids *= 2;
507 ids = realloc(ids, maxids * sizeof(ids[0])); 547 ids = realloc(ids, maxids * sizeof(ids[0]));
508 if (ids == NULL) { 548 if (ids == NULL) {
509 err(1, "realloc"); 549 err(1, "realloc");
510 } 550 }
511 } 551 }
512 ids[nids++] = id; 552 ids[nids++] = id;
513 } 553 }
514 554
515 /* now loop over quota-enabled filesystems */ 555 /* now loop over quota-enabled filesystems */
516 nfst = getmntinfo(&fst, MNT_WAIT); 556 nfst = getmntinfo(&fst, MNT_WAIT);
517 if (nfst == 0) 557 if (nfst == 0)
518 errx(1, "no filesystems mounted!"); 558 errx(1, "no filesystems mounted!");
519 559
520 for (i = 0; i < nfst; i++) { 560 for (i = 0; i < nfst; i++) {
521 if ((fst[i].f_flag & ST_QUOTA) == 0) 561 if ((fst[i].f_flag & ST_QUOTA) == 0)
522 continue; 562 continue;
523 if (filesys && strcmp(fst[i].f_mntonname, filesys) != 0 && 563 if (filesys && strcmp(fst[i].f_mntonname, filesys) != 0 &&
524 strcmp(fst[i].f_mntfromname, filesys) != 0) 564 strcmp(fst[i].f_mntfromname, filesys) != 0)
525 continue; 565 continue;
526 566
527 qh = quota_open(fst[i].f_mntonname); 567 qh = quota_open(fst[i].f_mntonname);
528 if (qh == NULL) { 568 if (qh == NULL) {
529 err(1, "%s: quota_open", fst[i].f_mntonname); 569 err(1, "%s: quota_open", fst[i].f_mntonname);
530 } 570 }
531 571
532 for (j = 0; j < nids; j++) { 572 for (j = 0; j < nids; j++) {
533 snprintf(idname, sizeof(idname), "%s %u", 573 snprintf(idname, sizeof(idname), "%s %u",
534 idtype == QUOTA_IDTYPE_USER ?  574 idtype == QUOTA_IDTYPE_USER ?
535 "uid" : "gid", ids[j]); 575 "uid" : "gid", ids[j]);
536 576
537 qk.qk_idtype = idtype; 577 qk.qk_idtype = idtype;
538 qk.qk_id = ids[j]; 578 qk.qk_id = ids[j];
539 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 579 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
540 if (quota_delete(qh, &qk)) { 580 if (quota_delete(qh, &qk)) {
541 err(1, "%s: quota_delete (%s blocks)", 581 err(1, "%s: quota_delete (%s blocks)",
542 fst[i].f_mntonname, idname); 582 fst[i].f_mntonname, idname);
543 } 583 }
544 584
545 qk.qk_idtype = idtype; 585 qk.qk_idtype = idtype;
546 qk.qk_id = ids[j]; 586 qk.qk_id = ids[j];
547 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 587 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
548 if (quota_delete(qh, &qk)) { 588 if (quota_delete(qh, &qk)) {
549 if (errno == ENOENT) { 589 if (errno == ENOENT) {
550 /* 590 /*
551 * XXX ignore this case; due 591 * XXX ignore this case; due
552 * to a weakness in the quota 592 * to a weakness in the quota
553 * proplib interface it can 593 * proplib interface it can
554 * appear spuriously. 594 * appear spuriously.
555 */ 595 */
556 } else { 596 } else {
557 err(1, "%s: quota_delete (%s files)", 597 err(1, "%s: quota_delete (%s files)",
558 fst[i].f_mntonname, idname); 598 fst[i].f_mntonname, idname);
559 } 599 }
560 } 600 }
561 } 601 }
562 602
563 quota_close(qh); 603 quota_close(qh);
564 } 604 }
565 605
566 free(ids); 606 free(ids);
567} 607}
568 608
569//////////////////////////////////////////////////////////// 609////////////////////////////////////////////////////////////
570// editor 610// editor
571 611
572/* 612/*
573 * Take a list of privileges and get it edited. 613 * Take a list of privileges and get it edited.
574 */ 614 */
575static int 615static int
576editit(const char *ltmpfile) 616editit(const char *ltmpfile)
577{ 617{
578 pid_t pid; 618 pid_t pid;
579 int lst; 619 int lst;
580 char p[MAX_TMPSTR]; 620 char p[MAX_TMPSTR];
581 const char *ed; 621 const char *ed;
582 sigset_t s, os; 622 sigset_t s, os;
583 623
584 sigemptyset(&s); 624 sigemptyset(&s);
585 sigaddset(&s, SIGINT); 625 sigaddset(&s, SIGINT);
586 sigaddset(&s, SIGQUIT); 626 sigaddset(&s, SIGQUIT);
587 sigaddset(&s, SIGHUP); 627 sigaddset(&s, SIGHUP);
588 if (sigprocmask(SIG_BLOCK, &s, &os) == -1) 628 if (sigprocmask(SIG_BLOCK, &s, &os) == -1)
589 err(1, "sigprocmask"); 629 err(1, "sigprocmask");
590top: 630top:
591 switch ((pid = fork())) { 631 switch ((pid = fork())) {
592 case -1: 632 case -1:
593 if (errno == EPROCLIM) { 633 if (errno == EPROCLIM) {
594 warnx("You have too many processes"); 634 warnx("You have too many processes");
595 return 0; 635 return 0;
596 } 636 }
597 if (errno == EAGAIN) { 637 if (errno == EAGAIN) {
598 sleep(1); 638 sleep(1);
599 goto top; 639 goto top;
600 } 640 }
601 warn("fork"); 641 warn("fork");
602 return 0; 642 return 0;
603 case 0: 643 case 0:
604 if (sigprocmask(SIG_SETMASK, &os, NULL) == -1) 644 if (sigprocmask(SIG_SETMASK, &os, NULL) == -1)
605 err(1, "sigprocmask"); 645 err(1, "sigprocmask");
606 setgid(getgid()); 646 setgid(getgid());
607 setuid(getuid()); 647 setuid(getuid());
608 if ((ed = getenv("EDITOR")) == (char *)0) 648 if ((ed = getenv("EDITOR")) == (char *)0)
609 ed = _PATH_VI; 649 ed = _PATH_VI;
610 if (strlen(ed) + strlen(ltmpfile) + 2 >= MAX_TMPSTR) { 650 if (strlen(ed) + strlen(ltmpfile) + 2 >= MAX_TMPSTR) {
611 errx(1, "%s", "editor or filename too long"); 651 errx(1, "%s", "editor or filename too long");
612 } 652 }
613 snprintf(p, sizeof(p), "%s %s", ed, ltmpfile); 653 snprintf(p, sizeof(p), "%s %s", ed, ltmpfile);
614 execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", p, NULL); 654 execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", p, NULL);
615 err(1, "%s", ed); 655 err(1, "%s", ed);
616 default: 656 default:
617 if (waitpid(pid, &lst, 0) == -1) 657 if (waitpid(pid, &lst, 0) == -1)
618 err(1, "waitpid"); 658 err(1, "waitpid");
619 if (sigprocmask(SIG_SETMASK, &os, NULL) == -1) 659 if (sigprocmask(SIG_SETMASK, &os, NULL) == -1)
620 err(1, "sigprocmask"); 660 err(1, "sigprocmask");
621 if (!WIFEXITED(lst) || WEXITSTATUS(lst) != 0) 661 if (!WIFEXITED(lst) || WEXITSTATUS(lst) != 0)
622 return 0; 662 return 0;
623 return 1; 663 return 1;
624 } 664 }
625} 665}
626 666
627/* 667/*
628 * Convert a quotause list to an ASCII file. 668 * Convert a quotause list to an ASCII file.
629 */ 669 */
630static int 670static int
631writeprivs(struct quotalist *qlist, int outfd, const char *name, 671writeprivs(struct quotalist *qlist, int outfd, const char *name,
632 int idtype) 672 int idtype)
633{ 673{
634 struct quotause *qup; 674 struct quotause *qup;
635 FILE *fd; 675 FILE *fd;
636 char b0[32], b1[32], b2[32], b3[32]; 676 char b0[32], b1[32], b2[32], b3[32];
637 677
638 (void)ftruncate(outfd, 0); 678 (void)ftruncate(outfd, 0);
639 (void)lseek(outfd, (off_t)0, SEEK_SET); 679 (void)lseek(outfd, (off_t)0, SEEK_SET);
640 if ((fd = fdopen(dup(outfd), "w")) == NULL) 680 if ((fd = fdopen(dup(outfd), "w")) == NULL)
641 errx(1, "fdopen"); 681 errx(1, "fdopen");
642 if (name == NULL) { 682 if (name == NULL) {
643 fprintf(fd, "Default %s quotas:\n", 683 fprintf(fd, "Default %s quotas:\n",
644 ufs_quota_class_names[idtype]); 684 ufs_quota_class_names[idtype]);
645 } else { 685 } else {
646 fprintf(fd, "Quotas for %s %s:\n", 686 fprintf(fd, "Quotas for %s %s:\n",
647 ufs_quota_class_names[idtype], name); 687 ufs_quota_class_names[idtype], name);
648 } 688 }
649 for (qup = qlist->head; qup; qup = qup->next) { 689 for (qup = qlist->head; qup; qup = qup->next) {
650 struct quotaval *q = qup->qv; 690 struct quotaval *q = qup->qv;
651 fprintf(fd, "%s (version %d):\n", 691 fprintf(fd, "%s (%s):\n",
652 qup->fsname, (qup->flags & QUOTA2) ? 2 : 1); 692 qup->fsname, qup->implementation);
653 if ((qup->flags & DEFAULT) == 0 || (qup->flags & QUOTA2) != 0) { 693 if ((qup->flags & DEFAULT) == 0 || (qup->flags & XGRACE) != 0) {
654 fprintf(fd, "\tblocks in use: %s, " 694 fprintf(fd, "\tblocks in use: %s, "
655 "limits (soft = %s, hard = %s", 695 "limits (soft = %s, hard = %s",
656 intprt(b1, 21, q[QL_BLK].qv_usage, 696 intprt(b1, 21, q[QL_BLK].qv_usage,
657 HN_NOSPACE | HN_B, Hflag),  697 HN_NOSPACE | HN_B, Hflag),
658 intprt(b2, 21, q[QL_BLK].qv_softlimit, 698 intprt(b2, 21, q[QL_BLK].qv_softlimit,
659 HN_NOSPACE | HN_B, Hflag), 699 HN_NOSPACE | HN_B, Hflag),
660 intprt(b3, 21, q[QL_BLK].qv_hardlimit, 700 intprt(b3, 21, q[QL_BLK].qv_hardlimit,
661 HN_NOSPACE | HN_B, Hflag)); 701 HN_NOSPACE | HN_B, Hflag));
662 if (qup->flags & QUOTA2) 702 if (qup->flags & XGRACE)
663 fprintf(fd, ", "); 703 fprintf(fd, ", ");
664 } else 704 } else
665 fprintf(fd, "\tblocks: ("); 705 fprintf(fd, "\tblocks: (");
666  706
667 if (qup->flags & (QUOTA2|DEFAULT)) { 707 if (qup->flags & (XGRACE|DEFAULT)) {
668 fprintf(fd, "grace = %s", 708 fprintf(fd, "grace = %s",
669 timepprt(b0, 21, q[QL_BLK].qv_grace, Hflag)); 709 timepprt(b0, 21, q[QL_BLK].qv_grace, Hflag));
670 } 710 }
671 fprintf(fd, ")\n"); 711 fprintf(fd, ")\n");
672 if ((qup->flags & DEFAULT) == 0 || (qup->flags & QUOTA2) != 0) { 712 if ((qup->flags & DEFAULT) == 0 || (qup->flags & XGRACE) != 0) {
673 fprintf(fd, "\tinodes in use: %s, " 713 fprintf(fd, "\tinodes in use: %s, "
674 "limits (soft = %s, hard = %s", 714 "limits (soft = %s, hard = %s",
675 intprt(b1, 21, q[QL_FL].qv_usage, 715 intprt(b1, 21, q[QL_FL].qv_usage,
676 HN_NOSPACE, Hflag), 716 HN_NOSPACE, Hflag),
677 intprt(b2, 21, q[QL_FL].qv_softlimit, 717 intprt(b2, 21, q[QL_FL].qv_softlimit,
678 HN_NOSPACE, Hflag), 718 HN_NOSPACE, Hflag),
679 intprt(b3, 21, q[QL_FL].qv_hardlimit, 719 intprt(b3, 21, q[QL_FL].qv_hardlimit,
680 HN_NOSPACE, Hflag)); 720 HN_NOSPACE, Hflag));
681 if (qup->flags & QUOTA2) 721 if (qup->flags & XGRACE)
682 fprintf(fd, ", "); 722 fprintf(fd, ", ");
683 } else 723 } else
684 fprintf(fd, "\tinodes: ("); 724 fprintf(fd, "\tinodes: (");
685 725
686 if (qup->flags & (QUOTA2|DEFAULT)) { 726 if (qup->flags & (XGRACE|DEFAULT)) {
687 fprintf(fd, "grace = %s", 727 fprintf(fd, "grace = %s",
688 timepprt(b0, 21, q[QL_FL].qv_grace, Hflag)); 728 timepprt(b0, 21, q[QL_FL].qv_grace, Hflag));
689 } 729 }
690 fprintf(fd, ")\n"); 730 fprintf(fd, ")\n");
691 } 731 }
692 fclose(fd); 732 fclose(fd);
693 return 1; 733 return 1;
694} 734}
695 735
696/* 736/*
697 * Merge changes to an ASCII file into a quotause list. 737 * Merge changes to an ASCII file into a quotause list.
698 */ 738 */
699static int 739static int
700readprivs(struct quotalist *qlist, int infd, int dflag) 740readprivs(struct quotalist *qlist, int infd, int dflag)
701{ 741{
702 struct quotause *qup; 742 struct quotause *qup;
703 FILE *fd; 743 FILE *fd;
704 int cnt; 744 int cnt;
705 char fsp[BUFSIZ]; 745 char fsp[BUFSIZ];
706 static char line0[BUFSIZ], line1[BUFSIZ], line2[BUFSIZ]; 746 static char line0[BUFSIZ], line1[BUFSIZ], line2[BUFSIZ];
707 static char scurb[BUFSIZ], scuri[BUFSIZ], ssoft[BUFSIZ], shard[BUFSIZ]; 747 static char scurb[BUFSIZ], scuri[BUFSIZ], ssoft[BUFSIZ], shard[BUFSIZ];
708 static char stime[BUFSIZ]; 748 static char stime[BUFSIZ];
709 uint64_t softb, hardb, softi, hardi; 749 uint64_t softb, hardb, softi, hardi;
710 time_t graceb = -1, gracei = -1; 750 time_t graceb = -1, gracei = -1;
711 int version; 751 int version;
712 752
713 (void)lseek(infd, (off_t)0, SEEK_SET); 753 (void)lseek(infd, (off_t)0, SEEK_SET);
714 fd = fdopen(dup(infd), "r"); 754 fd = fdopen(dup(infd), "r");
715 if (fd == NULL) { 755 if (fd == NULL) {
716 warn("Can't re-read temp file"); 756 warn("Can't re-read temp file");
717 return 0; 757 return 0;
718 } 758 }
719 /* 759 /*
720 * Discard title line, then read pairs of lines to process. 760 * Discard title line, then read pairs of lines to process.
721 */ 761 */
722 (void) fgets(line1, sizeof (line1), fd); 762 (void) fgets(line1, sizeof (line1), fd);
723 while (fgets(line0, sizeof (line0), fd) != NULL && 763 while (fgets(line0, sizeof (line0), fd) != NULL &&
724 fgets(line1, sizeof (line2), fd) != NULL && 764 fgets(line1, sizeof (line2), fd) != NULL &&
725 fgets(line2, sizeof (line2), fd) != NULL) { 765 fgets(line2, sizeof (line2), fd) != NULL) {
726 if (sscanf(line0, "%s (version %d):\n", fsp, &version) != 2) { 766 if (sscanf(line0, "%s (version %d):\n", fsp, &version) != 2) {
727 warnx("%s: bad format", line0); 767 warnx("%s: bad format", line0);
728 goto out; 768 goto out;
729 } 769 }
730#define last_char(str) ((str)[strlen(str) - 1]) 770#define last_char(str) ((str)[strlen(str) - 1])
731 if (last_char(line1) != '\n') { 771 if (last_char(line1) != '\n') {
732 warnx("%s:%s: bad format", fsp, line1); 772 warnx("%s:%s: bad format", fsp, line1);
733 goto out; 773 goto out;
734 } 774 }
735 last_char(line1) = '\0'; 775 last_char(line1) = '\0';
736 if (last_char(line2) != '\n') { 776 if (last_char(line2) != '\n') {
737 warnx("%s:%s: bad format", fsp, line2); 777 warnx("%s:%s: bad format", fsp, line2);
738 goto out; 778 goto out;
739 } 779 }
740 last_char(line2) = '\0'; 780 last_char(line2) = '\0';
741 if (dflag && version == 1) { 781 if (dflag && version == 1) {
742 if (sscanf(line1, 782 if (sscanf(line1,
743 "\tblocks: (grace = %s\n", stime) != 1) { 783 "\tblocks: (grace = %s\n", stime) != 1) {
744 warnx("%s:%s: bad format", fsp, line1); 784 warnx("%s:%s: bad format", fsp, line1);
745 goto out; 785 goto out;
746 } 786 }
747 if (last_char(stime) != ')') { 787 if (last_char(stime) != ')') {
748 warnx("%s:%s: bad format", fsp, line1); 788 warnx("%s:%s: bad format", fsp, line1);
749 goto out; 789 goto out;
750 } 790 }
751 last_char(stime) = '\0'; 791 last_char(stime) = '\0';
752 if (timeprd(stime, &graceb) != 0) { 792 if (timeprd(stime, &graceb) != 0) {
753 warnx("%s:%s: bad number", fsp, stime); 793 warnx("%s:%s: bad number", fsp, stime);
754 goto out; 794 goto out;
755 } 795 }
756 if (sscanf(line2, 796 if (sscanf(line2,
757 "\tinodes: (grace = %s\n", stime) != 1) { 797 "\tinodes: (grace = %s\n", stime) != 1) {
758 warnx("%s:%s: bad format", fsp, line2); 798 warnx("%s:%s: bad format", fsp, line2);
759 goto out; 799 goto out;
760 } 800 }
761 if (last_char(stime) != ')') { 801 if (last_char(stime) != ')') {
762 warnx("%s:%s: bad format", fsp, line2); 802 warnx("%s:%s: bad format", fsp, line2);
763 goto out; 803 goto out;
764 } 804 }
765 last_char(stime) = '\0'; 805 last_char(stime) = '\0';
766 if (timeprd(stime, &gracei) != 0) { 806 if (timeprd(stime, &gracei) != 0) {
767 warnx("%s:%s: bad number", fsp, stime); 807 warnx("%s:%s: bad number", fsp, stime);
768 goto out; 808 goto out;
769 } 809 }
770 } else { 810 } else {
771 cnt = sscanf(line1, 811 cnt = sscanf(line1,
772 "\tblocks in use: %s limits (soft = %s hard = %s " 812 "\tblocks in use: %s limits (soft = %s hard = %s "
773 "grace = %s", scurb, ssoft, shard, stime); 813 "grace = %s", scurb, ssoft, shard, stime);
774 if (cnt == 3) { 814 if (cnt == 3) {
775 if (version != 1 || 815 if (version != 1 ||
776 last_char(scurb) != ',' || 816 last_char(scurb) != ',' ||
777 last_char(ssoft) != ',' || 817 last_char(ssoft) != ',' ||
778 last_char(shard) != ')') { 818 last_char(shard) != ')') {
779 warnx("%s:%s: bad format %d", 819 warnx("%s:%s: bad format %d",
780 fsp, line1, cnt); 820 fsp, line1, cnt);
781 goto out; 821 goto out;
782 } 822 }
783 stime[0] = '\0'; 823 stime[0] = '\0';
784 } else if (cnt == 4) { 824 } else if (cnt == 4) {
785 if (version < 2 || 825 if (version < 2 ||
786 last_char(scurb) != ',' || 826 last_char(scurb) != ',' ||
787 last_char(ssoft) != ',' || 827 last_char(ssoft) != ',' ||
788 last_char(shard) != ',' || 828 last_char(shard) != ',' ||
789 last_char(stime) != ')') { 829 last_char(stime) != ')') {
790 warnx("%s:%s: bad format %d", 830 warnx("%s:%s: bad format %d",
791 fsp, line1, cnt); 831 fsp, line1, cnt);
792 goto out; 832 goto out;
793 } 833 }
794 } else { 834 } else {
795 warnx("%s: %s: bad format cnt %d", fsp, line1, 835 warnx("%s: %s: bad format cnt %d", fsp, line1,
796 cnt); 836 cnt);
797 goto out; 837 goto out;
798 } 838 }
799 /* drop last char which is ',' or ')' */ 839 /* drop last char which is ',' or ')' */
800 last_char(scurb) = '\0'; 840 last_char(scurb) = '\0';
801 last_char(ssoft) = '\0'; 841 last_char(ssoft) = '\0';
802 last_char(shard) = '\0'; 842 last_char(shard) = '\0';
803 last_char(stime) = '\0'; 843 last_char(stime) = '\0';
804  844
805 if (intrd(ssoft, &softb, HN_B) != 0) { 845 if (intrd(ssoft, &softb, HN_B) != 0) {
806 warnx("%s:%s: bad number", fsp, ssoft); 846 warnx("%s:%s: bad number", fsp, ssoft);
807 goto out; 847 goto out;
808 } 848 }
809 if (intrd(shard, &hardb, HN_B) != 0) { 849 if (intrd(shard, &hardb, HN_B) != 0) {
810 warnx("%s:%s: bad number", fsp, shard); 850 warnx("%s:%s: bad number", fsp, shard);
811 goto out; 851 goto out;
812 } 852 }
813 if (cnt == 4) { 853 if (cnt == 4) {
814 if (timeprd(stime, &graceb) != 0) { 854 if (timeprd(stime, &graceb) != 0) {
815 warnx("%s:%s: bad number", fsp, stime); 855 warnx("%s:%s: bad number", fsp, stime);
816 goto out; 856 goto out;
817 } 857 }
818 } 858 }
819 859
820 cnt = sscanf(line2, 860 cnt = sscanf(line2,
821 "\tinodes in use: %s limits (soft = %s hard = %s " 861 "\tinodes in use: %s limits (soft = %s hard = %s "
822 "grace = %s", scuri, ssoft, shard, stime); 862 "grace = %s", scuri, ssoft, shard, stime);
823 if (cnt == 3) { 863 if (cnt == 3) {
824 if (version != 1 || 864 if (version != 1 ||
825 last_char(scuri) != ',' || 865 last_char(scuri) != ',' ||
826 last_char(ssoft) != ',' || 866 last_char(ssoft) != ',' ||
827 last_char(shard) != ')') { 867 last_char(shard) != ')') {
828 warnx("%s:%s: bad format %d", 868 warnx("%s:%s: bad format %d",
829 fsp, line2, cnt); 869 fsp, line2, cnt);
830 goto out; 870 goto out;
831 } 871 }
832 stime[0] = '\0'; 872 stime[0] = '\0';
833 } else if (cnt == 4) { 873 } else if (cnt == 4) {
834 if (version < 2 || 874 if (version < 2 ||
835 last_char(scuri) != ',' || 875 last_char(scuri) != ',' ||
836 last_char(ssoft) != ',' || 876 last_char(ssoft) != ',' ||
837 last_char(shard) != ',' || 877 last_char(shard) != ',' ||
838 last_char(stime) != ')') { 878 last_char(stime) != ')') {
839 warnx("%s:%s: bad format %d", 879 warnx("%s:%s: bad format %d",
840 fsp, line2, cnt); 880 fsp, line2, cnt);
841 goto out; 881 goto out;
842 } 882 }
843 } else { 883 } else {
844 warnx("%s: %s: bad format", fsp, line2); 884 warnx("%s: %s: bad format", fsp, line2);
845 goto out; 885 goto out;
846 } 886 }
847 /* drop last char which is ',' or ')' */ 887 /* drop last char which is ',' or ')' */
848 last_char(scuri) = '\0'; 888 last_char(scuri) = '\0';
849 last_char(ssoft) = '\0'; 889 last_char(ssoft) = '\0';
850 last_char(shard) = '\0'; 890 last_char(shard) = '\0';
851 last_char(stime) = '\0'; 891 last_char(stime) = '\0';
852 if (intrd(ssoft, &softi, 0) != 0) { 892 if (intrd(ssoft, &softi, 0) != 0) {
853 warnx("%s:%s: bad number", fsp, ssoft); 893 warnx("%s:%s: bad number", fsp, ssoft);
854 goto out; 894 goto out;
855 } 895 }
856 if (intrd(shard, &hardi, 0) != 0) { 896 if (intrd(shard, &hardi, 0) != 0) {
857 warnx("%s:%s: bad number", fsp, shard); 897 warnx("%s:%s: bad number", fsp, shard);
858 goto out; 898 goto out;
859 } 899 }
860 if (cnt == 4) { 900 if (cnt == 4) {
861 if (timeprd(stime, &gracei) != 0) { 901 if (timeprd(stime, &gracei) != 0) {
862 warnx("%s:%s: bad number", fsp, stime); 902 warnx("%s:%s: bad number", fsp, stime);
863 goto out; 903 goto out;
864 } 904 }
865 } 905 }
866 } 906 }
867 for (qup = qlist->head; qup; qup = qup->next) { 907 for (qup = qlist->head; qup; qup = qup->next) {
868 struct quotaval *q = qup->qv; 908 struct quotaval *q = qup->qv;
869 char b1[32], b2[32]; 909 char b1[32], b2[32];
870 if (strcmp(fsp, qup->fsname)) 910 if (strcmp(fsp, qup->fsname))
871 continue; 911 continue;
872 if (version == 1 && dflag) { 912 if (version == 1 && dflag) {
873 q[QL_BLK].qv_grace = graceb; 913 q[QL_BLK].qv_grace = graceb;
874 q[QL_FL].qv_grace = gracei; 914 q[QL_FL].qv_grace = gracei;
875 qup->flags |= FOUND; 915 qup->flags |= FOUND;
876 continue; 916 continue;
877 } 917 }
878 918
879 if (strcmp(intprt(b1, 21, q[QL_BLK].qv_usage, 919 if (strcmp(intprt(b1, 21, q[QL_BLK].qv_usage,
880 HN_NOSPACE | HN_B, Hflag), 920 HN_NOSPACE | HN_B, Hflag),
881 scurb) != 0 || 921 scurb) != 0 ||
882 strcmp(intprt(b2, 21, q[QL_FL].qv_usage, 922 strcmp(intprt(b2, 21, q[QL_FL].qv_usage,
883 HN_NOSPACE, Hflag), 923 HN_NOSPACE, Hflag),
884 scuri) != 0) { 924 scuri) != 0) {
885 warnx("%s: cannot change current allocation", 925 warnx("%s: cannot change current allocation",
886 fsp); 926 fsp);
887 break; 927 break;
888 } 928 }
889 /* 929 /*
890 * Cause time limit to be reset when the quota 930 * Cause time limit to be reset when the quota
891 * is next used if previously had no soft limit 931 * is next used if previously had no soft limit
892 * or were under it, but now have a soft limit 932 * or were under it, but now have a soft limit
893 * and are over it. 933 * and are over it.
894 */ 934 */
895 if (q[QL_BLK].qv_usage && 935 if (q[QL_BLK].qv_usage &&
896 q[QL_BLK].qv_usage >= softb && 936 q[QL_BLK].qv_usage >= softb &&
897 (q[QL_BLK].qv_softlimit == 0 || 937 (q[QL_BLK].qv_softlimit == 0 ||
898 q[QL_BLK].qv_usage < q[QL_BLK].qv_softlimit)) 938 q[QL_BLK].qv_usage < q[QL_BLK].qv_softlimit))
899 q[QL_BLK].qv_expiretime = 0; 939 q[QL_BLK].qv_expiretime = 0;
900 if (q[QL_FL].qv_usage && 940 if (q[QL_FL].qv_usage &&
901 q[QL_FL].qv_usage >= softi && 941 q[QL_FL].qv_usage >= softi &&
902 (q[QL_FL].qv_softlimit == 0 || 942 (q[QL_FL].qv_softlimit == 0 ||
903 q[QL_FL].qv_usage < q[QL_FL].qv_softlimit)) 943 q[QL_FL].qv_usage < q[QL_FL].qv_softlimit))
904 q[QL_FL].qv_expiretime = 0; 944 q[QL_FL].qv_expiretime = 0;
905 q[QL_BLK].qv_softlimit = softb; 945 q[QL_BLK].qv_softlimit = softb;
906 q[QL_BLK].qv_hardlimit = hardb; 946 q[QL_BLK].qv_hardlimit = hardb;
907 if (version == 2) 947 if (version == 2)
908 q[QL_BLK].qv_grace = graceb; 948 q[QL_BLK].qv_grace = graceb;
909 q[QL_FL].qv_softlimit = softi; 949 q[QL_FL].qv_softlimit = softi;
910 q[QL_FL].qv_hardlimit = hardi; 950 q[QL_FL].qv_hardlimit = hardi;
911 if (version == 2) 951 if (version == 2)
912 q[QL_FL].qv_grace = gracei; 952 q[QL_FL].qv_grace = gracei;
913 qup->flags |= FOUND; 953 qup->flags |= FOUND;
914 } 954 }
915 } 955 }
916out: 956out:
917 fclose(fd); 957 fclose(fd);
918 /* 958 /*
919 * Disable quotas for any filesystems that have not been found. 959 * Disable quotas for any filesystems that have not been found.
920 */ 960 */
921 for (qup = qlist->head; qup; qup = qup->next) { 961 for (qup = qlist->head; qup; qup = qup->next) {
922 struct quotaval *q = qup->qv; 962 struct quotaval *q = qup->qv;
923 if (qup->flags & FOUND) { 963 if (qup->flags & FOUND) {
924 qup->flags &= ~FOUND; 964 qup->flags &= ~FOUND;
925 continue; 965 continue;
926 } 966 }
927 q[QL_BLK].qv_softlimit = UQUAD_MAX; 967 q[QL_BLK].qv_softlimit = UQUAD_MAX;
928 q[QL_BLK].qv_hardlimit = UQUAD_MAX; 968 q[QL_BLK].qv_hardlimit = UQUAD_MAX;
929 q[QL_BLK].qv_grace = 0; 969 q[QL_BLK].qv_grace = 0;
930 q[QL_FL].qv_softlimit = UQUAD_MAX; 970 q[QL_FL].qv_softlimit = UQUAD_MAX;
931 q[QL_FL].qv_hardlimit = UQUAD_MAX; 971 q[QL_FL].qv_hardlimit = UQUAD_MAX;
932 q[QL_FL].qv_grace = 0; 972 q[QL_FL].qv_grace = 0;
933 } 973 }
934 return 1; 974 return 1;
935} 975}
936 976
937//////////////////////////////////////////////////////////// 977////////////////////////////////////////////////////////////
938// actions 978// actions
939 979
940static void 980static void
941replicate(const char *fs, int idtype, const char *protoname, 981replicate(const char *fs, int idtype, const char *protoname,
942 char **names, int numnames) 982 char **names, int numnames)
943{ 983{
944 long protoid, id; 984 long protoid, id;
945 struct quotalist *protoprivs; 985 struct quotalist *protoprivs;
946 struct quotause *qup; 986 struct quotause *qup;
947 int i; 987 int i;
948 988
949 if ((protoid = getidbyname(protoname, idtype)) == -1) 989 if ((protoid = getidbyname(protoname, idtype)) == -1)
950 exit(1); 990 exit(1);
951 protoprivs = getprivs(protoid, 0, idtype, fs); 991 protoprivs = getprivs(protoid, 0, idtype, fs);
952 for (qup = protoprivs->head; qup; qup = qup->next) { 992 for (qup = protoprivs->head; qup; qup = qup->next) {
953 qup->qv[QL_BLK].qv_expiretime = 0; 993 qup->qv[QL_BLK].qv_expiretime = 0;
954 qup->qv[QL_FL].qv_expiretime = 0; 994 qup->qv[QL_FL].qv_expiretime = 0;
955 } 995 }
956 for (i=0; i<numnames; i++) { 996 for (i=0; i<numnames; i++) {
957 id = getidbyname(names[i], idtype); 997 id = getidbyname(names[i], idtype);
958 if (id == -1) 998 if (id == -1)
959 continue; 999 continue;
960 putprivs(id, idtype, protoprivs); 1000 putprivs(id, idtype, protoprivs);
961 } 1001 }
962 /* XXX */ 1002 /* XXX */
963 /* quotalist_destroy(protoprivs); */ 1003 /* quotalist_destroy(protoprivs); */
964} 1004}
965 1005
966static void 1006static void
967assign(const char *fs, int idtype, 1007assign(const char *fs, int idtype,
968 char *soft, char *hard, char *grace, 1008 char *soft, char *hard, char *grace,
969 char **names, int numnames) 1009 char **names, int numnames)
970{ 1010{
971 struct quotalist *curprivs; 1011 struct quotalist *curprivs;
972 struct quotause *lqup; 1012 struct quotause *lqup;
973 u_int64_t softb, hardb, softi, hardi; 1013 u_int64_t softb, hardb, softi, hardi;
974 time_t graceb, gracei; 1014 time_t graceb, gracei;
975 char *str; 1015 char *str;
976 long id; 1016 long id;
977 int dflag; 1017 int dflag;
978 int i; 1018 int i;
979 1019
980 if (soft) { 1020 if (soft) {
981 str = strsep(&soft, "/"); 1021 str = strsep(&soft, "/");
982 if (str[0] == '\0' || soft == NULL || soft[0] == '\0') 1022 if (str[0] == '\0' || soft == NULL || soft[0] == '\0')
983 usage(); 1023 usage();
984 1024
985 if (intrd(str, &softb, HN_B) != 0) 1025 if (intrd(str, &softb, HN_B) != 0)
986 errx(1, "%s: bad number", str); 1026 errx(1, "%s: bad number", str);
987 if (intrd(soft, &softi, 0) != 0) 1027 if (intrd(soft, &softi, 0) != 0)
988 errx(1, "%s: bad number", soft); 1028 errx(1, "%s: bad number", soft);
989 } 1029 }
990 if (hard) { 1030 if (hard) {
991 str = strsep(&hard, "/"); 1031 str = strsep(&hard, "/");
992 if (str[0] == '\0' || hard == NULL || hard[0] == '\0') 1032 if (str[0] == '\0' || hard == NULL || hard[0] == '\0')
993 usage(); 1033 usage();
994 1034
995 if (intrd(str, &hardb, HN_B) != 0) 1035 if (intrd(str, &hardb, HN_B) != 0)
996 errx(1, "%s: bad number", str); 1036 errx(1, "%s: bad number", str);
997 if (intrd(hard, &hardi, 0) != 0) 1037 if (intrd(hard, &hardi, 0) != 0)
998 errx(1, "%s: bad number", hard); 1038 errx(1, "%s: bad number", hard);
999 } 1039 }
1000 if (grace) { 1040 if (grace) {
1001 str = strsep(&grace, "/"); 1041 str = strsep(&grace, "/");
1002 if (str[0] == '\0' || grace == NULL || grace[0] == '\0') 1042 if (str[0] == '\0' || grace == NULL || grace[0] == '\0')
1003 usage(); 1043 usage();
1004 1044
1005 if (timeprd(str, &graceb) != 0) 1045 if (timeprd(str, &graceb) != 0)
1006 errx(1, "%s: bad number", str); 1046 errx(1, "%s: bad number", str);
1007 if (timeprd(grace, &gracei) != 0) 1047 if (timeprd(grace, &gracei) != 0)
1008 errx(1, "%s: bad number", grace); 1048 errx(1, "%s: bad number", grace);
1009 } 1049 }
1010 for (i=0; i<numnames; i++) { 1050 for (i=0; i<numnames; i++) {
1011 if (names[i] == NULL) { 1051 if (names[i] == NULL) {
1012 id = 0; 1052 id = 0;
1013 dflag = 1; 1053 dflag = 1;
1014 } else { 1054 } else {
1015 id = getidbyname(names[i], idtype); 1055 id = getidbyname(names[i], idtype);
1016 if (id == -1) 1056 if (id == -1)
1017 continue; 1057 continue;
1018 dflag = 0; 1058 dflag = 0;
1019 } 1059 }
1020 1060
1021 curprivs = getprivs(id, dflag, idtype, fs); 1061 curprivs = getprivs(id, dflag, idtype, fs);
1022 for (lqup = curprivs->head; lqup; lqup = lqup->next) { 1062 for (lqup = curprivs->head; lqup; lqup = lqup->next) {
1023 struct quotaval *q = lqup->qv; 1063 struct quotaval *q = lqup->qv;
1024 if (soft) { 1064 if (soft) {
1025 if (!dflag && softb && 1065 if (!dflag && softb &&
1026 q[QL_BLK].qv_usage >= softb && 1066 q[QL_BLK].qv_usage >= softb &&
1027 (q[QL_BLK].qv_softlimit == 0 || 1067 (q[QL_BLK].qv_softlimit == 0 ||
1028 q[QL_BLK].qv_usage < 1068 q[QL_BLK].qv_usage <
1029 q[QL_BLK].qv_softlimit)) 1069 q[QL_BLK].qv_softlimit))
1030 q[QL_BLK].qv_expiretime = 0; 1070 q[QL_BLK].qv_expiretime = 0;
1031 if (!dflag && softi && 1071 if (!dflag && softi &&
1032 q[QL_FL].qv_usage >= softb && 1072 q[QL_FL].qv_usage >= softb &&
1033 (q[QL_FL].qv_softlimit == 0 || 1073 (q[QL_FL].qv_softlimit == 0 ||
1034 q[QL_FL].qv_usage < 1074 q[QL_FL].qv_usage <
1035 q[QL_FL].qv_softlimit)) 1075 q[QL_FL].qv_softlimit))
1036 q[QL_FL].qv_expiretime = 0; 1076 q[QL_FL].qv_expiretime = 0;
1037 q[QL_BLK].qv_softlimit = softb; 1077 q[QL_BLK].qv_softlimit = softb;
1038 q[QL_FL].qv_softlimit = softi; 1078 q[QL_FL].qv_softlimit = softi;
1039 } 1079 }
1040 if (hard) { 1080 if (hard) {
1041 q[QL_BLK].qv_hardlimit = hardb; 1081 q[QL_BLK].qv_hardlimit = hardb;
1042 q[QL_FL].qv_hardlimit = hardi; 1082 q[QL_FL].qv_hardlimit = hardi;
1043 } 1083 }
1044 if (grace) { 1084 if (grace) {
1045 q[QL_BLK].qv_grace = graceb; 1085 q[QL_BLK].qv_grace = graceb;
1046 q[QL_FL].qv_grace = gracei; 1086 q[QL_FL].qv_grace = gracei;
1047 } 1087 }
1048 } 1088 }
1049 putprivs(id, idtype, curprivs); 1089 putprivs(id, idtype, curprivs);
1050 quotalist_destroy(curprivs); 1090 quotalist_destroy(curprivs);
1051 } 1091 }
1052} 1092}
1053 1093
1054static void 1094static void
1055clear(const char *fs, int idtype, char **names, int numnames) 1095clear(const char *fs, int idtype, char **names, int numnames)
1056{ 1096{
1057 clearpriv(numnames, names, fs, idtype); 1097 clearpriv(numnames, names, fs, idtype);
1058} 1098}
1059 1099
1060static void 1100static void
1061editone(const char *fs, int idtype, const char *name, 1101editone(const char *fs, int idtype, const char *name,
1062 int tmpfd, const char *tmppath) 1102 int tmpfd, const char *tmppath)
1063{ 1103{
1064 struct quotalist *curprivs; 1104 struct quotalist *curprivs;
1065 long id; 1105 long id;
1066 int dflag; 1106 int dflag;
1067 1107
1068 if (name == NULL) { 1108 if (name == NULL) {
1069 id = 0; 1109 id = 0;
1070 dflag = 1; 1110 dflag = 1;
1071 } else { 1111 } else {
1072 id = getidbyname(name, idtype); 1112 id = getidbyname(name, idtype);
1073 if (id == -1) 1113 if (id == -1)
1074 return; 1114 return;
1075 dflag = 0; 1115 dflag = 0;
1076 } 1116 }
1077 curprivs = getprivs(id, dflag, idtype, fs); 1117 curprivs = getprivs(id, dflag, idtype, fs);
1078 1118
1079 if (writeprivs(curprivs, tmpfd, name, idtype) == 0) 1119 if (writeprivs(curprivs, tmpfd, name, idtype) == 0)
1080 goto fail; 1120 goto fail;
1081 1121
1082 if (editit(tmppath) == 0) 1122 if (editit(tmppath) == 0)
1083 goto fail; 1123 goto fail;
1084 1124
1085 if (readprivs(curprivs, tmpfd, dflag) == 0) 1125 if (readprivs(curprivs, tmpfd, dflag) == 0)
1086 goto fail; 1126 goto fail;
1087 1127
1088 putprivs(id, idtype, curprivs); 1128 putprivs(id, idtype, curprivs);
1089fail: 1129fail:
1090 quotalist_destroy(curprivs); 1130 quotalist_destroy(curprivs);
1091} 1131}
1092 1132
1093static void 1133static void
1094edit(const char *fs, int idtype, char **names, int numnames) 1134edit(const char *fs, int idtype, char **names, int numnames)
1095{ 1135{
1096 char tmppath[] = _PATH_TMPFILE; 1136 char tmppath[] = _PATH_TMPFILE;
1097 int tmpfd, i; 1137 int tmpfd, i;
1098 1138
1099 tmpfd = mkstemp(tmppath); 1139 tmpfd = mkstemp(tmppath);
1100 fchown(tmpfd, getuid(), getgid()); 1140 fchown(tmpfd, getuid(), getgid());
1101 1141
1102 for (i=0; i<numnames; i++) { 1142 for (i=0; i<numnames; i++) {
1103 editone(fs, idtype, names[i], tmpfd, tmppath); 1143 editone(fs, idtype, names[i], tmpfd, tmppath);
1104 } 1144 }
1105 1145
1106 close(tmpfd); 1146 close(tmpfd);
1107 unlink(tmppath); 1147 unlink(tmppath);
1108} 1148}
1109 1149
1110//////////////////////////////////////////////////////////// 1150////////////////////////////////////////////////////////////
1111// main 1151// main
1112 1152
1113static void 1153static void
1114usage(void) 1154usage(void)
1115{ 1155{
1116 const char *p = getprogname(); 1156 const char *p = getprogname();
1117 fprintf(stderr, 1157 fprintf(stderr,
1118 "Usage: %s [-D] [-H] [-u] [-p <username>] [-f <filesystem>] " 1158 "Usage: %s [-D] [-H] [-u] [-p <username>] [-f <filesystem>] "
1119 "-d | <username> ...\n" 1159 "-d | <username> ...\n"
1120 "\t%s [-D] [-H] -g [-p <groupname>] [-f <filesystem>] " 1160 "\t%s [-D] [-H] -g [-p <groupname>] [-f <filesystem>] "
1121 "-d | <groupname> ...\n" 1161 "-d | <groupname> ...\n"
1122 "\t%s [-D] [-u] [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] " 1162 "\t%s [-D] [-u] [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] "
1123 "-d | <username> ...\n" 1163 "-d | <username> ...\n"
1124 "\t%s [-D] -g [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] " 1164 "\t%s [-D] -g [-f <filesystem>] [-s b#/i#] [-h b#/i#] [-t t#/t#] "
1125 "-d | <groupname> ...\n" 1165 "-d | <groupname> ...\n"
1126 "\t%s [-D] [-H] [-u] -c [-f <filesystem>] username ...\n" 1166 "\t%s [-D] [-H] [-u] -c [-f <filesystem>] username ...\n"
1127 "\t%s [-D] [-H] -g -c [-f <filesystem>] groupname ...\n", 1167 "\t%s [-D] [-H] -g -c [-f <filesystem>] groupname ...\n",
1128 p, p, p, p, p, p); 1168 p, p, p, p, p, p);
1129 exit(1); 1169 exit(1);
1130} 1170}
1131 1171
1132int 1172int
1133main(int argc, char *argv[]) 1173main(int argc, char *argv[])
1134{ 1174{
1135 int idtype; 1175 int idtype;
1136 char *protoname; 1176 char *protoname;
1137 char *soft = NULL, *hard = NULL, *grace = NULL; 1177 char *soft = NULL, *hard = NULL, *grace = NULL;
1138 char *fs = NULL; 1178 char *fs = NULL;
1139 int ch; 1179 int ch;
1140 int pflag = 0; 1180 int pflag = 0;
1141 int cflag = 0; 1181 int cflag = 0;
1142 int dflag = 0; 1182 int dflag = 0;
1143 1183
1144 if (argc < 2) 1184 if (argc < 2)
1145 usage(); 1185 usage();
1146 if (getuid()) 1186 if (getuid())
1147 errx(1, "permission denied"); 1187 errx(1, "permission denied");
1148 protoname = NULL; 1188 protoname = NULL;
1149 idtype = QUOTA_IDTYPE_USER; 1189 idtype = QUOTA_IDTYPE_USER;
1150 while ((ch = getopt(argc, argv, "DHcdugp:s:h:t:f:")) != -1) { 1190 while ((ch = getopt(argc, argv, "Hcdugp:s:h:t:f:")) != -1) {
1151 switch(ch) { 1191 switch(ch) {
1152 case 'D': 
1153 Dflag++; 
1154 break; 
1155 case 'H': 1192 case 'H':
1156 Hflag++; 1193 Hflag++;
1157 break; 1194 break;
1158 case 'c': 1195 case 'c':
1159 cflag++; 1196 cflag++;
1160 break; 1197 break;
1161 case 'd': 1198 case 'd':
1162 dflag++; 1199 dflag++;
1163 break; 1200 break;
1164 case 'p': 1201 case 'p':
1165 protoname = optarg; 1202 protoname = optarg;
1166 pflag++; 1203 pflag++;
1167 break; 1204 break;
1168 case 'g': 1205 case 'g':
1169 idtype = QUOTA_IDTYPE_GROUP; 1206 idtype = QUOTA_IDTYPE_GROUP;
1170 break; 1207 break;
1171 case 'u': 1208 case 'u':
1172 idtype = QUOTA_IDTYPE_USER; 1209 idtype = QUOTA_IDTYPE_USER;
1173 break; 1210 break;
1174 case 's': 1211 case 's':
1175 soft = optarg; 1212 soft = optarg;
1176 break; 1213 break;
1177 case 'h': 1214 case 'h':
1178 hard = optarg; 1215 hard = optarg;
1179 break; 1216 break;
1180 case 't': 1217 case 't':
1181 grace = optarg; 1218 grace = optarg;
1182 break; 1219 break;
1183 case 'f': 1220 case 'f':
1184 fs = optarg; 1221 fs = optarg;
1185 break; 1222 break;
1186 default: 1223 default:
1187 usage(); 1224 usage();
1188 } 1225 }
1189 } 1226 }
1190 argc -= optind; 1227 argc -= optind;
1191 argv += optind; 1228 argv += optind;
1192 1229
1193 if (pflag) { 1230 if (pflag) {
1194 if (soft || hard || grace || dflag || cflag) 1231 if (soft || hard || grace || dflag || cflag)
1195 usage(); 1232 usage();
1196 replicate(fs, idtype, protoname, argv, argc); 1233 replicate(fs, idtype, protoname, argv, argc);
1197 } else if (soft || hard || grace) { 1234 } else if (soft || hard || grace) {
1198 if (cflag) 1235 if (cflag)
1199 usage(); 1236 usage();
1200 if (dflag) { 1237 if (dflag) {
1201 /* use argv[argc], which is null, to mean 'default' */ 1238 /* use argv[argc], which is null, to mean 'default' */
1202 argc++; 1239 argc++;
1203 } 1240 }
1204 assign(fs, idtype, soft, hard, grace, argv, argc); 1241 assign(fs, idtype, soft, hard, grace, argv, argc);
1205 } else if (cflag) { 1242 } else if (cflag) {
1206 if (dflag) 1243 if (dflag)
1207 usage(); 1244 usage();
1208 clear(fs, idtype, argv, argc); 1245 clear(fs, idtype, argv, argc);
1209 } else { 1246 } else {
1210 if (dflag) { 1247 if (dflag) {
1211 /* use argv[argc], which is null, to mean 'default' */ 1248 /* use argv[argc], which is null, to mean 'default' */
1212 argc++; 1249 argc++;
1213 } 1250 }
1214 edit(fs, idtype, argv, argc); 1251 edit(fs, idtype, argv, argc);
1215 } 1252 }
1216 return 0; 1253 return 0;
1217} 1254}