# 2.11BSD#431 - /usr/src/usr.sbin/edquota/edquota.c

##### Functions

    alldigits         X
    editit            X
    freeprivs         X
    getentry          X
    getprivs          X
    hasquota          X
    main              X
    putprivs          X
    readprivs         X
    usage             X
    writeprivs        X

##### Variables

    qfname            X
    tmpfil            X

##### Macros

    FOUND             X

##### struct's

    quotause          X

       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

- in line 151

editit defined in line 307; used 1 times

- in line 125

freeprivs defined in line 474; used 1 times

- in line 127

getentry defined in line 145; used 4 times

- in line 74, 107-111(2), 120

getprivs defined in line 163; used 3 times

- in line 71, 109, 122

hasquota defined in line 504; used 1 times

- in line 185

main defined in line 76; never used
putprivs defined in line 265; used 2 times

- in line 113, 126

readprivs defined in line 386; used 1 times

- in line 125

usage defined in line 134; used 2 times

- in line 89, 101

writeprivs defined in line 353; used 1 times

- in line 123

#### Defined variables

copyright defined in line 38; never used
qfname defined in line 62; used 9 times

- in line 70, 249, 275-276(2), 290-291(2), 297, 514, 532

sccsid defined in line 42; never used
tmpfil defined in line 63; used 4 times

- in line 117, 125-130(2), 365

#### Defined struct's

quotause defined in line 65; used 30 times

- in line 66(2), 80(2), 163-170(6), 179(2), 194(2), 267-269(4), 354-358(4), 387-390(4), 475-477(4)

#### Defined macros

FOUND defined in line 72; used 3 times

- in line 445, 459-460(2)

Last modified: 1996-01-22 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2681 |