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