| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
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 |
| @@ -31,93 +31,91 @@ | | | @@ -31,93 +31,91 @@ |
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 |
42 | static char sccsid[] = "from: @(#)edquota.c 8.3 (Berkeley) 4/27/95"; | | 42 | static 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 | |
85 | static const char *quotagroup = QUOTAGROUP; | | 83 | static 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 | |
94 | struct quotause { | | 92 | struct 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 | |
102 | struct quotalist { | | 101 | struct quotalist { |
103 | struct quotause *head; | | 102 | struct quotause *head; |
104 | struct quotause *tail; | | 103 | struct quotause *tail; |
105 | }; | | 104 | }; |
106 | | | 105 | |
107 | static void usage(void) __dead; | | 106 | static void usage(void) __dead; |
108 | | | 107 | |
109 | static int Hflag = 0; | | 108 | static int Hflag = 0; |
110 | static 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 | */ |
| @@ -328,47 +326,89 @@ getprivs1(long id, int idtype, const cha | | | @@ -328,47 +326,89 @@ getprivs1(long id, int idtype, const cha |
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 | |
| | | 339 | static int |
| | | 340 | dogetprivs2(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 | |
341 | static struct quotause * | | 358 | static struct quotause * |
342 | getprivs2(long id, int idtype, const char *filesys, int defaultq) | | 359 | getprivs2(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 | |
365 | static void | | 405 | static void |
366 | putprivs2(uint32_t id, int idtype, struct quotause *qup) | | 406 | putprivs2(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"); |
| @@ -638,62 +678,62 @@ writeprivs(struct quotalist *qlist, int | | | @@ -638,62 +678,62 @@ writeprivs(struct quotalist *qlist, int |
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 | */ |
699 | static int | | 739 | static int |
| @@ -1137,31 +1177,28 @@ main(int argc, char *argv[]) | | | @@ -1137,31 +1177,28 @@ main(int argc, char *argv[]) |
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; |