1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 #pragma ident "%Z%%M% %I% %E% SMI"
40
41 /*
42 * Disk quota editor.
43 */
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <signal.h>
47 #include <errno.h>
48 #include <pwd.h>
49 #include <ctype.h>
50 #include <fcntl.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <sys/mnttab.h>
54 #include <sys/param.h>
55 #include <sys/types.h>
56 #include <sys/mntent.h>
57 #include <sys/stat.h>
58 #include <sys/file.h>
59 #include <sys/fs/ufs_quota.h>
60 #include <sys/fs/ufs_fs.h>
61 #include <sys/wait.h>
62 #include <unistd.h>
63 #include <iso/limits_iso.h>
64
65 #define DEFEDITOR "/usr/bin/vi"
66
67 #if DEV_BSIZE < 1024
68 #define dbtok(x) ((x) / (1024 / DEV_BSIZE))
69 #define ktodb(x) ((x) * (1024 / DEV_BSIZE))
70 #else
71 #define dbtok(x) ((x) * (DEV_BSIZE / 1024))
72 #define ktodb(x) ((x) / (DEV_BSIZE / 1024))
73 #endif
74
75 struct fsquot {
76 struct fsquot *fsq_next;
77 struct dqblk fsq_dqb;
78 char *fsq_fs;
79 char *fsq_dev;
80 char *fsq_qfile;
81 };
82
83 static struct fsquot *fsqlist;
84
85 static char tmpfil[] = "/tmp/EdP.aXXXXXX";
86 #define QFNAME "quotas"
87
88 static uid_t getentry(char *);
89 static int editit(void);
90 static void getprivs(uid_t);
91 static void putprivs(uid_t);
92 static void gettimes(uid_t);
93 static void puttimes(uid_t);
94 static char *next(char *, char *);
95 static int alldigits(char *);
96 static void fmttime(char *, ulong_t);
97 static int unfmttime(double, char *, uint32_t *);
98 static void setupfs(void);
99 static void getdiscq(uid_t);
100 static void putdiscq(uid_t);
101 static void sigsetmask(uint_t);
102 static uint_t sigblock(uint_t);
103 static void usage(void);
104 static int quotactl(int, char *, uid_t, caddr_t);
105
106 int
main(int argc,char ** argv)107 main(int argc, char **argv)
108 {
109 uid_t uid;
110 char *basename;
111 int opt;
112 int i;
113 int tmpfd = -1;
114
115 basename = argv[0];
116 if (argc < 2) {
117 usage();
118 }
119 if (quotactl(Q_SYNC, (char *)NULL, 0, (caddr_t)NULL) < 0 &&
120 errno == EINVAL) {
121 (void) printf("Warning: "
122 "Quotas are not compiled into this kernel\n");
123 (void) sleep(3);
124 }
125 if (getuid()) {
126 (void) fprintf(stderr, "%s: permission denied\n", basename);
127 exit(32);
128 }
129 setupfs();
130 if (fsqlist == NULL) {
131 (void) fprintf(stderr, "%s: no UFS filesystems with %s file\n",
132 MNTTAB, QFNAME);
133 exit(32);
134 }
135 tmpfd = mkstemp(tmpfil);
136 if (tmpfd == -1 || fchown(tmpfd, getuid(), getgid()) == -1) {
137 fprintf(stderr, "failure in temporary file %s\n", tmpfil);
138 exit(32);
139 }
140 (void) close(tmpfd);
141 while ((opt = getopt(argc, argv, "p:tV")) != EOF)
142 switch (opt) {
143 case 't':
144 gettimes(0);
145 if (editit())
146 puttimes(0);
147 (void) unlink(tmpfil);
148 exit(0);
149 /*NOTREACHED*/
150
151 case 'p':
152 uid = getentry(optarg);
153 if (uid > MAXUID) {
154 (void) unlink(tmpfil);
155 exit(32);
156 }
157 getprivs(uid);
158 if (optind == argc) {
159 (void) unlink(tmpfil);
160 usage();
161 }
162 for (i = optind; i < argc; i++) {
163 uid = getentry(argv[i]);
164 if (uid > MAXUID) {
165 (void) unlink(tmpfil);
166 exit(32);
167 }
168 getdiscq(uid);
169 putprivs(uid);
170 }
171 (void) unlink(tmpfil);
172 exit(0);
173 /*NOTREACHED*/
174
175 case 'V': /* Print command line */
176 {
177 char *optt;
178 int optc;
179
180 (void) printf("edquota -F UFS");
181 for (optc = 1; optc < argc; optc++) {
182 optt = argv[optc];
183 if (optt)
184 (void) printf(" %s ", optt);
185 }
186 (void) putchar('\n');
187 }
188 break;
189
190 case '?':
191 usage();
192 }
193
194 for (i = optind; i < argc; i++) {
195 uid = getentry(argv[i]);
196 if (uid > MAXUID)
197 continue;
198 getprivs(uid);
199 if (editit())
200 putprivs(uid);
201 if (uid == 0) {
202 (void) printf("edquota: Note that uid 0's quotas "
203 "are used as default values for other users,\n");
204 (void) printf("not as a limit on the uid 0 user.\n");
205 }
206 }
207 (void) unlink(tmpfil);
208 return (0);
209 }
210
211 static uid_t
getentry(char * name)212 getentry(char *name)
213 {
214 struct passwd *pw;
215 uid_t uid;
216
217 if (alldigits(name)) {
218 errno = 0;
219 uid = strtol(name, NULL, 10);
220 if (errno == ERANGE) {
221 /* name would cause overflow in uid */
222 (void) fprintf(stderr, "edquota: uid %s too large\n",
223 name);
224 (void) sleep(1);
225 return (-1);
226 }
227 } else if (pw = getpwnam(name))
228 uid = pw->pw_uid;
229 else {
230 (void) fprintf(stderr, "%s: no such user\n", name);
231 (void) sleep(1);
232 return (-1);
233 }
234 return (uid);
235 }
236
237 #define RESPSZ 128
238
239 static int
editit(void)240 editit(void)
241 {
242 pid_t pid, xpid;
243 char *ed;
244 char resp[RESPSZ];
245 int status, omask;
246
247 #define mask(s) (1 << ((s) - 1))
248 omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP));
249
250 if ((ed = getenv("EDITOR")) == (char *)0)
251 ed = DEFEDITOR;
252
253 /*CONSTANTCONDITION*/
254 while (1) {
255 if ((pid = fork()) < 0) {
256 if (errno == EAGAIN) {
257 (void) fprintf(stderr,
258 "You have too many processes\n");
259 return (0);
260 }
261 perror("fork");
262 return (0);
263 }
264 if (pid == 0) {
265 (void) sigsetmask(omask);
266 (void) setgid(getgid());
267 (void) setuid(getuid());
268 (void) execlp(ed, ed, tmpfil, 0);
269 (void) fprintf(stderr,
270 "Can't exec editor \"%s\": ", ed);
271 perror("");
272 exit(32);
273 }
274 while ((xpid = wait(&status)) >= 0)
275 if (xpid == pid)
276 break;
277
278 if (!isatty(fileno(stdin))) { /* Non-interactive */
279 break;
280 }
281
282 /*
283 * Certain editors can exit with a non-zero status even
284 * though everything is peachy. Best to ask the user what
285 * s/he really wants to do. (N.B.: if we're non-interactive
286 * we'll "break" the while loop before we get here.)
287 */
288 if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) {
289 (void) printf("Non-zero return from \"%s\", ", ed);
290 (void) printf("updated file may contain errors.\n");
291 /*CONSTANTCONDITION*/
292 while (1) {
293 (void) printf("Edit again (e) or quit, "
294 "discarding changes (q)? ");
295 (void) fflush(stdout);
296 if (gets(resp) == NULL) {
297 return (0);
298 }
299 if ((*resp == 'e') || (*resp == 'q')) {
300 break;
301 }
302 }
303
304 if (*resp == 'e') {
305 continue;
306 } else {
307 /*
308 * Since (*resp == 'q'), then we just
309 * want to break out of here and return
310 * the failure.
311 */
312 break;
313 }
314 } else {
315 break; /* Successful return from editor */
316 }
317 }
318 (void) sigsetmask(omask);
319 return (!status);
320 }
321
322 static void
getprivs(uid_t uid)323 getprivs(uid_t uid)
324 {
325 struct fsquot *fsqp;
326 FILE *fd;
327
328 getdiscq(uid);
329 if ((fd = fopen64(tmpfil, "w")) == NULL) {
330 (void) fprintf(stderr, "edquota: ");
331 perror(tmpfil);
332 (void) unlink(tmpfil);
333 exit(32);
334 }
335 for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next)
336 (void) fprintf(fd,
337 "fs %s blocks (soft = %lu, hard = %lu) "
338 "inodes (soft = %lu, hard = %lu)\n",
339 fsqp->fsq_fs,
340 dbtok(fsqp->fsq_dqb.dqb_bsoftlimit),
341 dbtok(fsqp->fsq_dqb.dqb_bhardlimit),
342 fsqp->fsq_dqb.dqb_fsoftlimit,
343 fsqp->fsq_dqb.dqb_fhardlimit);
344 (void) fclose(fd);
345 }
346
347 static void
putprivs(uid_t uid)348 putprivs(uid_t uid)
349 {
350 FILE *fd;
351 uint64_t tmp_bsoftlimit, tmp_bhardlimit, tmp_fsoftlimit,
352 tmp_fhardlimit;
353 char line[BUFSIZ];
354 int changed = 0;
355 uint32_t max_limit;
356 int quota_entry_printed;
357
358 fd = fopen64(tmpfil, "r");
359 if (fd == NULL) {
360 (void) fprintf(stderr, "Can't re-read temp file!!\n");
361 return;
362 }
363 while (fgets(line, sizeof (line), fd) != NULL) {
364 struct fsquot *fsqp;
365 char *cp, *dp;
366 int n;
367
368 cp = next(line, " \t");
369 if (cp == NULL)
370 break;
371 *cp++ = '\0';
372 while (*cp && *cp == '\t' && *cp == ' ')
373 cp++;
374 dp = cp, cp = next(cp, " \t");
375 if (cp == NULL)
376 break;
377 *cp++ = '\0';
378 for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
379 if (strcmp(dp, fsqp->fsq_fs) == 0)
380 break;
381 }
382 if (fsqp == NULL) {
383 (void) fprintf(stderr, "%s: unknown file system\n", cp);
384 continue;
385 }
386 while (*cp && *cp == '\t' && *cp == ' ')
387 cp++;
388
389 /*
390 * At this point, dp points to the mount point of the
391 * file system and cp points to the remainder of the
392 * quota definition string.
393 */
394 n = sscanf(cp,
395 "blocks (soft = %llu, hard = %llu) "
396 "inodes (soft = %llu, hard = %llu)\n",
397 &tmp_bsoftlimit,
398 &tmp_bhardlimit,
399 &tmp_fsoftlimit,
400 &tmp_fhardlimit);
401
402 if (n != 4) {
403 (void) fprintf(stderr, "%s: bad format\n", cp);
404 continue;
405 }
406
407 /*
408 * The values in dqb_bsoftlimit and dqb_bhardlimit
409 * are specified in 1k blocks in the edited quota
410 * file (the one we're reading), but are specified in
411 * disk blocks in the data structure passed to quotactl().
412 * That means that the maximum allowed value for the
413 * hard and soft block limits in the edited quota file
414 * is the maximum number of disk blocks allowed in a
415 * quota (which is 2^32 - 1, since it's a 32-bit unsigned
416 * quantity), converted to 1k blocks.
417 */
418 max_limit = dbtok(UINT_MAX);
419
420 quota_entry_printed = 0; /* only print quota entry once */
421
422 if (tmp_bsoftlimit > max_limit) {
423 tmp_bsoftlimit = max_limit;
424 if (!quota_entry_printed) {
425 (void) fprintf(stderr, "%s %s%\n", dp, cp);
426 quota_entry_printed = 1;
427 }
428 (void) fprintf(stderr,
429 "error: soft limit for blocks exceeds maximum allowed value,\n"
430 " soft limit for blocks set to %lu\n", max_limit);
431 }
432
433 if (tmp_bhardlimit > max_limit) {
434 tmp_bhardlimit = max_limit;
435 if (!quota_entry_printed) {
436 (void) fprintf(stderr, "%s %s%\n", dp, cp);
437 quota_entry_printed = 1;
438 }
439 (void) fprintf(stderr,
440 "error: hard limit for blocks exceeds maximum allowed value,\n"
441 " hard limit for blocks set to %lu\n", max_limit);
442 }
443
444
445 /*
446 * Now check the file limits against their maximum, which
447 * is UINT_MAX (since it must fit in a uint32_t).
448 */
449 max_limit = UINT_MAX;
450
451 if (tmp_fsoftlimit > max_limit) {
452 tmp_fsoftlimit = max_limit;
453 if (!quota_entry_printed) {
454 (void) fprintf(stderr, "%s %s%\n", dp, cp);
455 quota_entry_printed = 1;
456 }
457 (void) fprintf(stderr,
458 "error: soft limit for files exceeds maximum allowed value,\n"
459 " soft limit for files set to %lu\n", max_limit);
460 }
461
462 if (tmp_fhardlimit > max_limit) {
463 tmp_fhardlimit = max_limit;
464 if (!quota_entry_printed) {
465 (void) fprintf(stderr, "%s %s%\n", dp, cp);
466 quota_entry_printed = 1;
467 }
468 (void) fprintf(stderr,
469 "error: hard limit for files exceeds maximum allowed value,\n"
470 " hard limit for files set to %lu\n", max_limit);
471 }
472
473 changed++;
474 tmp_bsoftlimit = ktodb(tmp_bsoftlimit);
475 tmp_bhardlimit = ktodb(tmp_bhardlimit);
476 /*
477 * It we are decreasing the soft limits, set the time limits
478 * to zero, in case the user is now over quota.
479 * the time limit will be started the next time the
480 * user does an allocation.
481 */
482 if (tmp_bsoftlimit < fsqp->fsq_dqb.dqb_bsoftlimit)
483 fsqp->fsq_dqb.dqb_btimelimit = 0;
484 if (tmp_fsoftlimit < fsqp->fsq_dqb.dqb_fsoftlimit)
485 fsqp->fsq_dqb.dqb_ftimelimit = 0;
486 fsqp->fsq_dqb.dqb_bsoftlimit = tmp_bsoftlimit;
487 fsqp->fsq_dqb.dqb_bhardlimit = tmp_bhardlimit;
488 fsqp->fsq_dqb.dqb_fsoftlimit = tmp_fsoftlimit;
489 fsqp->fsq_dqb.dqb_fhardlimit = tmp_fhardlimit;
490 }
491 (void) fclose(fd);
492 if (changed)
493 putdiscq(uid);
494 }
495
496 static void
gettimes(uid_t uid)497 gettimes(uid_t uid)
498 {
499 struct fsquot *fsqp;
500 FILE *fd;
501 char btime[80], ftime[80];
502
503 getdiscq(uid);
504 if ((fd = fopen64(tmpfil, "w")) == NULL) {
505 (void) fprintf(stderr, "edquota: ");
506 perror(tmpfil);
507 (void) unlink(tmpfil);
508 exit(32);
509 }
510 for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
511 fmttime(btime, fsqp->fsq_dqb.dqb_btimelimit);
512 fmttime(ftime, fsqp->fsq_dqb.dqb_ftimelimit);
513 (void) fprintf(fd,
514 "fs %s blocks time limit = %s, files time limit = %s\n",
515 fsqp->fsq_fs, btime, ftime);
516 }
517 (void) fclose(fd);
518 }
519
520 static void
puttimes(uid_t uid)521 puttimes(uid_t uid)
522 {
523 FILE *fd;
524 char line[BUFSIZ];
525 int changed = 0;
526 double btimelimit, ftimelimit;
527 char bunits[80], funits[80];
528
529 fd = fopen64(tmpfil, "r");
530 if (fd == NULL) {
531 (void) fprintf(stderr, "Can't re-read temp file!!\n");
532 return;
533 }
534 while (fgets(line, sizeof (line), fd) != NULL) {
535 struct fsquot *fsqp;
536 char *cp, *dp;
537 int n;
538
539 cp = next(line, " \t");
540 if (cp == NULL)
541 break;
542 *cp++ = '\0';
543 while (*cp && *cp == '\t' && *cp == ' ')
544 cp++;
545 dp = cp, cp = next(cp, " \t");
546 if (cp == NULL)
547 break;
548 *cp++ = '\0';
549 for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
550 if (strcmp(dp, fsqp->fsq_fs) == 0)
551 break;
552 }
553 if (fsqp == NULL) {
554 (void) fprintf(stderr, "%s: unknown file system\n", cp);
555 continue;
556 }
557 while (*cp && *cp == '\t' && *cp == ' ')
558 cp++;
559 n = sscanf(cp,
560 "blocks time limit = %lf %[^,], "
561 "files time limit = %lf %s\n",
562 &btimelimit, bunits, &ftimelimit, funits);
563 if (n != 4 ||
564 !unfmttime(btimelimit, bunits,
565 &fsqp->fsq_dqb.dqb_btimelimit) ||
566 !unfmttime(ftimelimit, funits,
567 &fsqp->fsq_dqb.dqb_ftimelimit)) {
568 (void) fprintf(stderr, "%s: bad format\n", cp);
569 continue;
570 }
571 changed++;
572 }
573 (void) fclose(fd);
574 if (changed)
575 putdiscq(uid);
576 }
577
578 static char *
next(char * cp,char * match)579 next(char *cp, char *match)
580 {
581 char *dp;
582
583 while (cp && *cp) {
584 for (dp = match; dp && *dp; dp++)
585 if (*dp == *cp)
586 return (cp);
587 cp++;
588 }
589 return ((char *)0);
590 }
591
592 static int
alldigits(char * s)593 alldigits(char *s)
594 {
595 int c = *s++;
596
597 do {
598 if (!isdigit(c))
599 return (0);
600 } while ((c = *s++) != '\0');
601
602 return (1);
603 }
604
605 static struct {
606 int c_secs; /* conversion units in secs */
607 char *c_str; /* unit string */
608 } cunits [] = {
609 {60*60*24*28, "month"},
610 {60*60*24*7, "week"},
611 {60*60*24, "day"},
612 {60*60, "hour"},
613 {60, "min"},
614 {1, "sec"}
615 };
616
617 static void
fmttime(char * buf,ulong_t time)618 fmttime(char *buf, ulong_t time)
619 {
620 double value;
621 int i;
622
623 if (time == 0) {
624 (void) strcpy(buf, "0 (default)");
625 return;
626 }
627 for (i = 0; i < sizeof (cunits) / sizeof (cunits[0]); i++)
628 if (time >= cunits[i].c_secs)
629 break;
630
631 value = (double)time / cunits[i].c_secs;
632 (void) sprintf(buf, "%.2f %s%s",
633 value, cunits[i].c_str, value > 1.0 ? "s" : "");
634 }
635
636 static int
unfmttime(double value,char * units,uint32_t * timep)637 unfmttime(double value, char *units, uint32_t *timep)
638 {
639 int i;
640
641 if (value == 0.0) {
642 *timep = 0;
643 return (1);
644 }
645 for (i = 0; i < sizeof (cunits) / sizeof (cunits[0]); i++) {
646 if (strncmp(cunits[i].c_str, units,
647 strlen(cunits[i].c_str)) == 0)
648 break;
649 }
650 if (i >= sizeof (cunits) / sizeof (cunits[0]))
651 return (0);
652 *timep = (ulong_t)(value * cunits[i].c_secs);
653 return (1);
654 }
655
656 static void
setupfs(void)657 setupfs(void)
658 {
659 struct mnttab mntp;
660 struct fsquot *fsqp;
661 struct stat64 statb;
662 dev_t fsdev;
663 FILE *mtab;
664 char qfilename[MAXPATHLEN];
665
666 if ((mtab = fopen(MNTTAB, "r")) == (FILE *)0) {
667 perror("/etc/mnttab");
668 exit(31+1);
669 }
670 while (getmntent(mtab, &mntp) == 0) {
671 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0)
672 continue;
673 if (stat64(mntp.mnt_special, &statb) < 0)
674 continue;
675 if ((statb.st_mode & S_IFMT) != S_IFBLK)
676 continue;
677 fsdev = statb.st_rdev;
678 (void) snprintf(qfilename, sizeof (qfilename), "%s/%s",
679 mntp.mnt_mountp, QFNAME);
680 if (stat64(qfilename, &statb) < 0 || statb.st_dev != fsdev)
681 continue;
682 fsqp = malloc(sizeof (struct fsquot));
683 if (fsqp == NULL) {
684 (void) fprintf(stderr, "out of memory\n");
685 exit(31+1);
686 }
687 fsqp->fsq_next = fsqlist;
688 fsqp->fsq_fs = strdup(mntp.mnt_mountp);
689 fsqp->fsq_dev = strdup(mntp.mnt_special);
690 fsqp->fsq_qfile = strdup(qfilename);
691 if (fsqp->fsq_fs == NULL || fsqp->fsq_dev == NULL ||
692 fsqp->fsq_qfile == NULL) {
693 (void) fprintf(stderr, "out of memory\n");
694 exit(31+1);
695 }
696 fsqlist = fsqp;
697 }
698 (void) fclose(mtab);
699 }
700
701 static void
getdiscq(uid_t uid)702 getdiscq(uid_t uid)
703 {
704 struct fsquot *fsqp;
705 int fd;
706
707 for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
708 if (quotactl(Q_GETQUOTA, fsqp->fsq_dev, uid,
709 (caddr_t)&fsqp->fsq_dqb) != 0) {
710 if ((fd = open64(fsqp->fsq_qfile, O_RDONLY)) < 0) {
711 (void) fprintf(stderr, "edquota: ");
712 perror(fsqp->fsq_qfile);
713 continue;
714 }
715 (void) llseek(fd, (offset_t)dqoff(uid), L_SET);
716 switch (read(fd, (char *)&fsqp->fsq_dqb,
717 sizeof (struct dqblk))) {
718 case 0:
719 /*
720 * Convert implicit 0 quota (EOF)
721 * into an explicit one (zero'ed dqblk)
722 */
723 bzero((caddr_t)&fsqp->fsq_dqb,
724 sizeof (struct dqblk));
725 break;
726
727 case sizeof (struct dqblk): /* OK */
728 break;
729
730 default: /* ERROR */
731 (void) fprintf(stderr,
732 "edquota: read error in ");
733 perror(fsqp->fsq_qfile);
734 break;
735 }
736 (void) close(fd);
737 }
738 }
739 }
740
741 static void
putdiscq(uid_t uid)742 putdiscq(uid_t uid)
743 {
744 struct fsquot *fsqp;
745
746 for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
747 if (quotactl(Q_SETQLIM, fsqp->fsq_dev, uid,
748 (caddr_t)&fsqp->fsq_dqb) != 0) {
749 int fd;
750
751 if ((fd = open64(fsqp->fsq_qfile, O_RDWR)) < 0) {
752 (void) fprintf(stderr, "edquota: ");
753 perror(fsqp->fsq_qfile);
754 continue;
755 }
756 (void) llseek(fd, (offset_t)dqoff(uid), L_SET);
757 if (write(fd, (char *)&fsqp->fsq_dqb,
758 sizeof (struct dqblk)) != sizeof (struct dqblk)) {
759 (void) fprintf(stderr, "edquota: ");
760 perror(fsqp->fsq_qfile);
761 }
762 (void) close(fd);
763 }
764 }
765 }
766
767 static void
sigsetmask(uint_t omask)768 sigsetmask(uint_t omask)
769 {
770 int i;
771
772 for (i = 0; i < 32; i++)
773 if (omask & (1 << i)) {
774 if (sigignore(1 << i) == (int)SIG_ERR) {
775 (void) fprintf(stderr,
776 "Bad signal 0x%x\n", (1 << i));
777 exit(31+1);
778 }
779 }
780 }
781
782 static uint_t
sigblock(uint_t omask)783 sigblock(uint_t omask)
784 {
785 uint_t previous = 0;
786 uint_t temp;
787 int i;
788
789 for (i = 0; i < 32; i++)
790 if (omask & (1 << i)) {
791 if ((temp = sigignore(1 << i)) == (int)SIG_ERR) {
792 (void) fprintf(stderr,
793 "Bad signal 0x%x\n", (1 << i));
794 exit(31+1);
795 }
796 if (i == 0)
797 previous = temp;
798 }
799
800 return (previous);
801 }
802
803 static void
usage(void)804 usage(void)
805 {
806 (void) fprintf(stderr, "ufs usage:\n");
807 (void) fprintf(stderr, "\tedquota [-p username] username ...\n");
808 (void) fprintf(stderr, "\tedquota -t\n");
809 exit(1);
810 }
811
812 static int
quotactl(int cmd,char * special,uid_t uid,caddr_t addr)813 quotactl(int cmd, char *special, uid_t uid, caddr_t addr)
814 {
815 int fd;
816 int status;
817 struct quotctl quota;
818 char qfile[MAXPATHLEN];
819 FILE *fstab;
820 struct mnttab mntp;
821
822 if ((special == NULL) && (cmd == Q_SYNC)) {
823 cmd = Q_ALLSYNC;
824 /*
825 * need to find an acceptable fd to send this Q_ALLSYNC down
826 * on, it needs to be a ufs fd for vfs to at least call the
827 * real quotactl() in the kernel
828 * Here, try to simply find the starting mountpoint of the
829 * first mounted ufs file system
830 */
831 }
832
833 /*
834 * Find the mount point of the special device. This is
835 * because the fcntl that implements the quotactl call has
836 * to go to a real file, and not to the block device.
837 */
838 if ((fstab = fopen(MNTTAB, "r")) == NULL) {
839 (void) fprintf(stderr, "%s: ", MNTTAB);
840 perror("open");
841 exit(31+1);
842 }
843 qfile[0] = '\0';
844 while ((status = getmntent(fstab, &mntp)) == NULL) {
845 /*
846 * check that it is a ufs file system
847 * for all quotactl()s except Q_ALLSYNC check that
848 * the file system is read-write since changes in the
849 * quotas file may be required
850 * for Q_ALLSYNC, this check is skipped since this option
851 * is to determine if quotas are configured into the system
852 */
853 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 ||
854 ((cmd != Q_ALLSYNC) && hasmntopt(&mntp, MNTOPT_RO)))
855 continue;
856 if (cmd == Q_ALLSYNC) { /* implies (special==0) too */
857 if (strlcpy(qfile, mntp.mnt_mountp,
858 sizeof (qfile)) >= sizeof (qfile)) {
859 errno = ENOENT;
860 return (-1);
861 }
862 break;
863 }
864 if (strcmp(special, mntp.mnt_special) == 0) {
865 if (strlcpy(qfile, mntp.mnt_mountp,
866 sizeof (qfile)) >= sizeof (qfile)) {
867 errno = ENOENT;
868 return (-1);
869 }
870 }
871 }
872 (void) fclose(fstab);
873 if (qfile[0] == '\0') {
874 errno = ENOENT;
875 return (-1);
876 }
877 {
878 int open_flags;
879
880 if (cmd == Q_ALLSYNC) {
881 open_flags = O_RDONLY;
882 } else {
883 if (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >=
884 sizeof (qfile)) {
885 errno = ENOENT;
886 return (-1);
887 }
888 open_flags = O_RDWR;
889 }
890
891 if ((fd = open64(qfile, open_flags)) < 0) {
892 (void) fprintf(stderr, "quotactl: ");
893 perror("open");
894 exit(31+1);
895 }
896 }
897
898 quota.op = cmd;
899 quota.uid = uid;
900 quota.addr = addr;
901 status = ioctl(fd, Q_QUOTACTL, "a);
902 (void) close(fd);
903 return (status);
904 }
905