1: /*
   2:  * Copyright (c) 1980, 1990, 1993
   3:  *	The Regents of the University of California.  All rights reserved.
   4:  *
   5:  * This code is derived from software contributed to Berkeley by
   6:  * Robert Elz at The University of Melbourne.
   7:  *
   8:  * Redistribution and use in source and binary forms, with or without
   9:  * modification, are permitted provided that the following conditions
  10:  * are met:
  11:  * 1. Redistributions of source code must retain the above copyright
  12:  *    notice, this list of conditions and the following disclaimer.
  13:  * 2. Redistributions in binary form must reproduce the above copyright
  14:  *    notice, this list of conditions and the following disclaimer in the
  15:  *    documentation and/or other materials provided with the distribution.
  16:  * 3. All advertising materials mentioning features or use of this software
  17:  *    must display the following acknowledgement:
  18:  *	This product includes software developed by the University of
  19:  *	California, Berkeley and its contributors.
  20:  * 4. Neither the name of the University nor the names of its contributors
  21:  *    may be used to endorse or promote products derived from this software
  22:  *    without specific prior written permission.
  23:  *
  24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34:  * SUCH DAMAGE.
  35:  */
  36: 
  37: #if !defined(lint) && defined(DOSCCS)
  38: static char copyright[] =
  39: "@(#) Copyright (c) 1980, 1990, 1993\n\
  40: 	The Regents of the University of California.  All rights reserved.\n";
  41: 
  42: static char sccsid[] = "@(#)edquota.c	8.1.1 (2.11BSD) 1996/1/21";
  43: #endif /* not lint */
  44: 
  45: /*
  46:  * Disk quota editor.
  47:  */
  48: #include <sys/param.h>
  49: #include <sys/stat.h>
  50: #include <sys/file.h>
  51: #include <sys/wait.h>
  52: #include <sys/quota.h>
  53: #include <errno.h>
  54: #include <fstab.h>
  55: #include <pwd.h>
  56: #include <ctype.h>
  57: #include <stdio.h>
  58: #include <string.h>
  59: #include <unistd.h>
  60: #include <paths.h>
  61: 
  62: char *qfname = "quotas";
  63: char tmpfil[] = "/tmp/EdP.aXXXXXX";
  64: 
  65: struct quotause {
  66:     struct  quotause *next;
  67:     short   flags;
  68:     struct  dqblk dqblk;
  69:     char    fsname[MAXPATHLEN + 1];
  70:     char    qfname[1];  /* actually longer */
  71: } *getprivs();
  72: #define FOUND   0x01
  73: 
  74:     uid_t   getentry();
  75: 
  76: main(argc, argv)
  77:     register char **argv;
  78:     int argc;
  79: {
  80:     register struct quotause *protoprivs, *curprivs;
  81:     extern char *optarg;
  82:     extern int optind;
  83:     uid_t id, protoid;
  84:     int tmpfd;
  85:     char *protoname, ch;
  86:     int pflag = 0;
  87: 
  88:     if (argc < 2)
  89:         usage();
  90:     if (getuid()) {
  91:         fprintf(stderr, "edquota: permission denied\n");
  92:         exit(1);
  93:     }
  94:     while ((ch = getopt(argc, argv, "p:")) != EOF) {
  95:         switch(ch) {
  96:         case 'p':
  97:             protoname = optarg;
  98:             pflag++;
  99:             break;
 100:         default:
 101:             usage();
 102:         }
 103:     }
 104:     argc -= optind;
 105:     argv += optind;
 106:     if (pflag) {
 107:         if ((protoid = getentry(protoname)) == -1)
 108:             exit(1);
 109:         protoprivs = getprivs(protoid);
 110:         while (argc-- > 0) {
 111:             if ((id = getentry(*argv++)) < 0)
 112:                 continue;
 113:             putprivs(id, protoprivs);
 114:         }
 115:         exit(0);
 116:     }
 117:     tmpfd = mkstemp(tmpfil);
 118:     fchown(tmpfd, getuid(), getgid());
 119:     for ( ; argc > 0; argc--, argv++) {
 120:         if ((id = getentry(*argv)) == -1)
 121:             continue;
 122:         curprivs = getprivs(id);
 123:         if (writeprivs(curprivs, tmpfd, *argv) == 0)
 124:             continue;
 125:         if (editit(tmpfil) && readprivs(curprivs, tmpfd))
 126:             putprivs(id, curprivs);
 127:         freeprivs(curprivs);
 128:     }
 129:     close(tmpfd);
 130:     unlink(tmpfil);
 131:     exit(0);
 132: }
 133: 
 134: usage()
 135: {
 136:     fputs("Usage: edquota [-p username] username ...\n", stderr);
 137:     exit(1);
 138: }
 139: 
 140: /*
 141:  * This routine converts a name for a particular quota type to
 142:  * an identifier. This routine must agree with the kernel routine
 143:  * getinoquota as to the interpretation of quota types.
 144:  */
 145: uid_t
 146: getentry(name)
 147:     char *name;
 148: {
 149:     struct passwd *pw;
 150: 
 151:     if (alldigits(name))
 152:         return (atoi(name));
 153:     if (pw = getpwnam(name))
 154:         return (pw->pw_uid);
 155:     fprintf(stderr, "%s: no such user\n", name);
 156:     sleep(1);
 157:     return (-1);
 158: }
 159: 
 160: /*
 161:  * Collect the requested quota information.
 162:  */
 163: struct quotause *
 164: getprivs(id)
 165:     u_int id;
 166: {
 167:     register struct fstab *fs;
 168:     register struct quotause *qup, *quptail;
 169:     struct  dqblk *dq;
 170:     struct quotause *quphead;
 171:     struct  stat    statb;
 172:     dev_t   fsdev;
 173:     int qupsize, fd;
 174:     char *qfpathname;
 175:     static int warned = 0;
 176:     extern int errno;
 177: 
 178:     setfsent();
 179:     quphead = (struct quotause *)0;
 180:     while (fs = getfsent()) {
 181:         if (stat(fs->fs_spec, &statb) < 0)
 182:             continue;
 183:         if (strcmp(fs->fs_vfstype, "ufs"))
 184:             continue;
 185:         if (!hasquota(fs, &qfpathname))
 186:             continue;
 187: /*
 188:  * See the comments in quota.c about the check below.
 189: */
 190:         fsdev = statb.st_rdev;
 191:         if (stat(qfpathname, &statb) < 0 || statb.st_dev != fsdev)
 192:             continue;
 193:         qupsize = sizeof(*qup) + strlen(qfpathname);
 194:         if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
 195:             fprintf(stderr, "edquota: out of memory\n");
 196:             exit(2);
 197:         }
 198:         if (quota(Q_GETDLIM, id, fsdev, &qup->dqblk) != 0) {
 199:                 if (errno == EOPNOTSUPP && !warned) {
 200:                 warned++;
 201:                 fprintf(stderr, "Warning: %s\n",
 202:                     "Quotas are not compiled into this kernel");
 203:                 sleep(3);
 204:             }
 205:             if ((fd = open(qfpathname, O_RDONLY)) < 0) {
 206:                 fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
 207:                 if (fd < 0 && errno != ENOENT) {
 208:                     perror(qfpathname);
 209:                     free(qup);
 210:                     continue;
 211:                 }
 212:                 fprintf(stderr, "Creating quota file %s\n",
 213:                     qfpathname);
 214:                 sleep(3);
 215:                 (void) fchown(fd, getuid(), -1);
 216:                 (void) fchmod(fd, 0640);
 217:             }
 218:             lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
 219:             switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
 220:             case 0:         /* EOF */
 221:                 /*
 222: 				 * Convert implicit 0 quota (EOF)
 223: 				 * into an explicit one (zero'ed dqblk)
 224: 				 */
 225:                 bzero((caddr_t)&qup->dqblk,
 226:                     sizeof(struct dqblk));
 227:                 break;
 228: 
 229:             case sizeof(struct dqblk):  /* OK */
 230: /*
 231:  * We have to convert from bytes to disc blocks because the quotas file
 232:  * entries use bytes like the kernel does.
 233: */
 234:                 dq = &qup->dqblk;
 235:                 dq->dqb_curblocks = btodb(dq->dqb_curblocks);
 236:                 dq->dqb_bhardlimit = btodb(dq->dqb_bhardlimit);
 237:                 dq->dqb_bsoftlimit = btodb(dq->dqb_bsoftlimit);
 238:                 break;
 239: 
 240:             default:        /* ERROR */
 241:                 fprintf(stderr, "edquota: read error in ");
 242:                 perror(qfpathname);
 243:                 close(fd);
 244:                 free(qup);
 245:                 continue;
 246:             }
 247:             close(fd);
 248:         }
 249:         strcpy(qup->qfname, qfpathname);
 250:         strcpy(qup->fsname, fs->fs_file);
 251:         if (quphead == NULL)
 252:             quphead = qup;
 253:         else
 254:             quptail->next = qup;
 255:         quptail = qup;
 256:         qup->next = 0;
 257:     }
 258:     endfsent();
 259:     return (quphead);
 260: }
 261: 
 262: /*
 263:  * Store the requested quota information.
 264:  */
 265: putprivs(id, quplist)
 266:     uid_t id;
 267:     struct quotause *quplist;
 268: {
 269:     register struct quotause *qup;
 270:     struct stat sb;
 271:     int fd;
 272:     register struct dqblk *dq;
 273: 
 274:     for (qup = quplist; qup; qup = qup->next) {
 275:         if (stat(qup->qfname, &sb) < 0) {
 276:             fprintf(stderr,"edquota: can't stat %s\n",qup->qfname);
 277:             continue;
 278:         }
 279: 
 280:         if (quota(Q_SETDLIM, id, sb.st_dev, &qup->dqblk) == 0)
 281:             continue;
 282: /*
 283:  * Have to convert from blocks to bytes now to be compatible with the kernel
 284: */
 285:         dq = &qup->dqblk;
 286:         dq->dqb_bhardlimit = dbtob(dq->dqb_bhardlimit);
 287:         dq->dqb_bsoftlimit = dbtob(dq->dqb_bsoftlimit);
 288:         dq->dqb_curblocks = dbtob(dq->dqb_curblocks);
 289: 
 290:         if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
 291:             perror(qup->qfname);
 292:         } else {
 293:             lseek(fd, (long)id * (long)sizeof (struct dqblk), 0);
 294:             if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
 295:                 sizeof (struct dqblk)) {
 296:                 fprintf(stderr, "edquota: ");
 297:                 perror(qup->qfname);
 298:             }
 299:             close(fd);
 300:         }
 301:     }
 302: }
 303: 
 304: /*
 305:  * Take a list of priviledges and get it edited.
 306:  */
 307: editit(tmpfile)
 308:     char *tmpfile;
 309: {
 310:     long omask;
 311:     pid_t pid;
 312:     union wait stat;
 313:     extern char *getenv();
 314: 
 315:     omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
 316:  top:
 317:     if ((pid = vfork()) < 0) {
 318:         extern int errno;
 319: 
 320:         if (errno == EPROCLIM) {
 321:             fprintf(stderr, "You have too many processes\n");
 322:             return(0);
 323:         }
 324:         if (errno == EAGAIN) {
 325:             sleep(1);
 326:             goto top;
 327:         }
 328:         perror("fork");
 329:         return (0);
 330:     }
 331:     if (pid == 0) {
 332:         register char *ed;
 333: 
 334:         sigsetmask(omask);
 335:         setgid(getgid());
 336:         setuid(getuid());
 337:         if ((ed = getenv("EDITOR")) == (char *)0)
 338:             ed = _PATH_VI;
 339:         execlp(ed, ed, tmpfile, 0);
 340:         perror(ed);
 341:         exit(1);
 342:     }
 343:     waitpid(pid, &stat, 0);
 344:     sigsetmask(omask);
 345:     if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
 346:         return (0);
 347:     return (1);
 348: }
 349: 
 350: /*
 351:  * Convert a quotause list to an ASCII file.
 352:  */
 353: writeprivs(quplist, outfd, name)
 354:     struct quotause *quplist;
 355:     int outfd;
 356:     char *name;
 357: {
 358:     register struct quotause *qup;
 359:     register FILE *fd;
 360: 
 361:     ftruncate(outfd, (off_t)0);
 362:     lseek(outfd, (off_t)0, L_SET);
 363:     if ((fd = fdopen(dup(outfd), "w")) == NULL) {
 364:         fprintf(stderr, "edquota: ");
 365:         perror(tmpfil);
 366:         exit(1);
 367:     }
 368:     fprintf(fd, "Quotas for %s:\n", name);
 369:     for (qup = quplist; qup; qup = qup->next) {
 370:         fprintf(fd, "%s: %s %ld, limits (soft = %ld, hard = %ld)\n",
 371:             qup->fsname, "blocks in use:",
 372:             qup->dqblk.dqb_curblocks,
 373:             qup->dqblk.dqb_bsoftlimit,
 374:             qup->dqblk.dqb_bhardlimit);
 375:         fprintf(fd, "%s %u, limits (soft = %u, hard = %u)\n",
 376:             "\tinodes in use:", qup->dqblk.dqb_curinodes,
 377:             qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
 378:     }
 379:     fclose(fd);
 380:     return (1);
 381: }
 382: 
 383: /*
 384:  * Merge changes to an ASCII file into a quotause list.
 385:  */
 386: readprivs(quplist, infd)
 387:     struct quotause *quplist;
 388:     int infd;
 389: {
 390:     register struct quotause *qup;
 391:     FILE *fd;
 392:     int cnt;
 393:     register char *cp;
 394:     struct dqblk dqblk;
 395:     char *fsp, line1[BUFSIZ], line2[BUFSIZ];
 396: 
 397:     lseek(infd, (off_t)0, L_SET);
 398:     fd = fdopen(dup(infd), "r");
 399:     if (fd == NULL) {
 400:         fprintf(stderr, "Can't re-read temp file!!\n");
 401:         return (0);
 402:     }
 403:     /*
 404: 	 * Discard title line, then read pairs of lines to process.
 405: 	 */
 406:     (void) fgets(line1, sizeof (line1), fd);
 407:     while (fgets(line1, sizeof (line1), fd) != NULL &&
 408:            fgets(line2, sizeof (line2), fd) != NULL) {
 409:         if ((fsp = strtok(line1, " \t:")) == NULL) {
 410:             fprintf(stderr, "%s: bad format\n", line1);
 411:             return (0);
 412:         }
 413:         if ((cp = strtok((char *)0, "\n")) == NULL) {
 414:             fprintf(stderr, "%s: %s: bad format\n", fsp,
 415:                 &fsp[strlen(fsp) + 1]);
 416:             return (0);
 417:         }
 418:         cnt = sscanf(cp,
 419:             " blocks in use: %ld, limits (soft = %ld, hard = %ld)",
 420:             &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
 421:             &dqblk.dqb_bhardlimit);
 422:         if (cnt != 3) {
 423:             fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
 424:             return (0);
 425:         }
 426:         if ((cp = strtok(line2, "\n")) == NULL) {
 427:             fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
 428:             return (0);
 429:         }
 430:         cnt = sscanf(cp,
 431:             "\tinodes in use: %u, limits (soft = %u, hard = %u)",
 432:             &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
 433:             &dqblk.dqb_ihardlimit);
 434:         if (cnt != 3) {
 435:             fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
 436:             return (0);
 437:         }
 438:         for (qup = quplist; qup; qup = qup->next) {
 439:             if (strcmp(fsp, qup->fsname))
 440:                 continue;
 441:             qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
 442:             qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
 443:             qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
 444:             qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
 445:             qup->flags |= FOUND;
 446:             if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
 447:                 dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
 448:                 break;
 449:             fprintf(stderr,
 450:                 "%s: cannot change current allocation\n", fsp);
 451:             break;
 452:         }
 453:     }
 454:     fclose(fd);
 455:     /*
 456: 	 * Disable quotas for any filesystems that have not been found.
 457: 	 */
 458:     for (qup = quplist; qup; qup = qup->next) {
 459:         if (qup->flags & FOUND) {
 460:             qup->flags &= ~FOUND;
 461:             continue;
 462:         }
 463:         qup->dqblk.dqb_bsoftlimit = 0;
 464:         qup->dqblk.dqb_bhardlimit = 0;
 465:         qup->dqblk.dqb_isoftlimit = 0;
 466:         qup->dqblk.dqb_ihardlimit = 0;
 467:     }
 468:     return (1);
 469: }
 470: 
 471: /*
 472:  * Free a list of quotause structures.
 473:  */
 474: freeprivs(quplist)
 475:     struct quotause *quplist;
 476: {
 477:     register struct quotause *qup, *nextqup;
 478: 
 479:     for (qup = quplist; qup; qup = nextqup) {
 480:         nextqup = qup->next;
 481:         free(qup);
 482:     }
 483: }
 484: 
 485: /*
 486:  * Check whether a string is completely composed of digits.
 487:  */
 488: alldigits(s)
 489:     register char *s;
 490: {
 491:     register c;
 492: 
 493:     c = *s++;
 494:     do {
 495:         if (!isdigit(c))
 496:             return (0);
 497:     } while (c = *s++);
 498:     return (1);
 499: }
 500: 
 501: /*
 502:  * Check to see if a particular quota is to be enabled.
 503:  */
 504: hasquota(fs, qfnamep)
 505:     register struct fstab *fs;
 506:     char **qfnamep;
 507: {
 508:     register char *opt;
 509:     char *cp;
 510:     static char initname, usrname[100];
 511:     static char buf[BUFSIZ];
 512: 
 513:     if (!initname) {
 514:         strcpy(usrname, qfname);
 515:         initname = 1;
 516:     }
 517:     strcpy(buf, fs->fs_mntops);
 518:     for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
 519:         if (cp = index(opt, '='))
 520:             *cp++ = '\0';
 521:         if (strcmp(opt, usrname) == 0)
 522:             break;
 523:         if (strcmp(opt, FSTAB_RQ) == 0) /* XXX compatibility */
 524:             break;
 525:     }
 526:     if (!opt)
 527:         return (0);
 528:     if (cp) {
 529:         *qfnamep = cp;
 530:         return (1);
 531:     }
 532:     (void) sprintf(buf, "%s/%s", fs->fs_file, qfname);
 533:     *qfnamep = buf;
 534:     return (1);
 535: }

Defined functions

alldigits defined in line 488; used 1 times
editit defined in line 307; used 1 times
freeprivs defined in line 474; used 1 times
getentry defined in line 145; used 4 times
getprivs defined in line 163; used 3 times
hasquota defined in line 504; used 1 times
main defined in line 76; never used
putprivs defined in line 265; used 2 times
readprivs defined in line 386; used 1 times
usage defined in line 134; used 2 times
writeprivs defined in line 353; used 1 times

Defined variables

copyright defined in line 38; never used
qfname defined in line 62; used 9 times
sccsid defined in line 42; never used
tmpfil defined in line 63; used 4 times

Defined struct's

quotause defined in line 65; used 30 times

Defined macros

FOUND defined in line 72; used 3 times
Last modified: 1996-01-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5789
Valid CSS Valid XHTML 1.0 Strict