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