Mon Jan 30 19:18:36 2012 UTC ()
Rely on libquota for fallback to direct access of old-style quota files.

Keep the code around in #if 0 blocks for now, just in case some of the
logic might turn out to be wanted in libquota.


(dholland)
diff -r1.44 -r1.45 src/usr.sbin/edquota/edquota.c

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

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