121516Smckusick /* 261826Sbostic * Copyright (c) 1980, 1990, 1993 361826Sbostic * The Regents of the University of California. All rights reserved. 434362Sbostic * 541408Smckusick * This code is derived from software contributed to Berkeley by 641408Smckusick * Robert Elz at The University of Melbourne. 741408Smckusick * 842797Sbostic * %sccs.include.redist.c% 921516Smckusick */ 1021516Smckusick 1112707Smckusick #ifndef lint 1261826Sbostic static char copyright[] = 1361826Sbostic "@(#) Copyright (c) 1980, 1990, 1993\n\ 1461826Sbostic The Regents of the University of California. All rights reserved.\n"; 1534362Sbostic #endif /* not lint */ 1612707Smckusick 1721516Smckusick #ifndef lint 18*67977Smckusick static char sccsid[] = "@(#)edquota.c 8.2 (Berkeley) 11/22/94"; 1934362Sbostic #endif /* not lint */ 2021516Smckusick 2112707Smckusick /* 2212707Smckusick * Disk quota editor. 2312707Smckusick */ 2436964Sbostic #include <sys/param.h> 2536964Sbostic #include <sys/stat.h> 2636964Sbostic #include <sys/file.h> 2741408Smckusick #include <sys/wait.h> 28*67977Smckusick #include <sys/queue.h> 2951630Sbostic #include <ufs/ufs/quota.h> 3012707Smckusick #include <errno.h> 3136964Sbostic #include <fstab.h> 3212707Smckusick #include <pwd.h> 3341408Smckusick #include <grp.h> 3412707Smckusick #include <ctype.h> 3536964Sbostic #include <stdio.h> 3641408Smckusick #include <string.h> 3760135Sbostic #include <unistd.h> 3837267Sbostic #include "pathnames.h" 3912707Smckusick 4045255Smckusick char *qfname = QUOTAFILENAME; 4145255Smckusick char *qfextension[] = INITQFNAMES; 4245255Smckusick char *quotagroup = QUOTAGROUP; 4341408Smckusick char tmpfil[] = _PATH_TMP; 4412707Smckusick 4541408Smckusick struct quotause { 4641408Smckusick struct quotause *next; 4741408Smckusick long flags; 4841408Smckusick struct dqblk dqblk; 4941408Smckusick char fsname[MAXPATHLEN + 1]; 5041444Smckusick char qfname[1]; /* actually longer */ 5141408Smckusick } *getprivs(); 5241408Smckusick #define FOUND 0x01 5312707Smckusick 5412707Smckusick main(argc, argv) 5541408Smckusick register char **argv; 5641408Smckusick int argc; 5712707Smckusick { 5841408Smckusick register struct quotause *qup, *protoprivs, *curprivs; 5941408Smckusick extern char *optarg; 6041408Smckusick extern int optind; 6141408Smckusick register long id, protoid; 6241408Smckusick register int quotatype, tmpfd; 6341408Smckusick char *protoname, ch; 6441408Smckusick int tflag = 0, pflag = 0; 6512707Smckusick 6641408Smckusick if (argc < 2) 6741408Smckusick usage(); 6812707Smckusick if (getuid()) { 6941408Smckusick fprintf(stderr, "edquota: permission denied\n"); 7012707Smckusick exit(1); 7112707Smckusick } 7241408Smckusick quotatype = USRQUOTA; 7341408Smckusick while ((ch = getopt(argc, argv, "ugtp:")) != EOF) { 7441408Smckusick switch(ch) { 7541408Smckusick case 'p': 7641408Smckusick protoname = optarg; 7741408Smckusick pflag++; 7841408Smckusick break; 7941408Smckusick case 'g': 8041408Smckusick quotatype = GRPQUOTA; 8141408Smckusick break; 8241408Smckusick case 'u': 8341408Smckusick quotatype = USRQUOTA; 8441408Smckusick break; 8541408Smckusick case 't': 8641408Smckusick tflag++; 8741408Smckusick break; 8841408Smckusick default: 8941408Smckusick usage(); 9041408Smckusick } 9141408Smckusick } 9241408Smckusick argc -= optind; 9341408Smckusick argv += optind; 9441408Smckusick if (pflag) { 9541408Smckusick if ((protoid = getentry(protoname, quotatype)) == -1) 9612803Smckusick exit(1); 9741408Smckusick protoprivs = getprivs(protoid, quotatype); 9841408Smckusick for (qup = protoprivs; qup; qup = qup->next) { 9941408Smckusick qup->dqblk.dqb_btime = 0; 10041408Smckusick qup->dqblk.dqb_itime = 0; 10112803Smckusick } 10212803Smckusick while (argc-- > 0) { 10341408Smckusick if ((id = getentry(*argv++, quotatype)) < 0) 10412803Smckusick continue; 10541408Smckusick putprivs(id, quotatype, protoprivs); 10612803Smckusick } 10712803Smckusick exit(0); 10812803Smckusick } 10941408Smckusick tmpfd = mkstemp(tmpfil); 11041408Smckusick fchown(tmpfd, getuid(), getgid()); 11141408Smckusick if (tflag) { 11241408Smckusick protoprivs = getprivs(0, quotatype); 11341408Smckusick if (writetimes(protoprivs, tmpfd, quotatype) == 0) 11441408Smckusick exit(1); 11541408Smckusick if (editit(tmpfil) && readtimes(protoprivs, tmpfd)) 11641408Smckusick putprivs(0, quotatype, protoprivs); 11741408Smckusick freeprivs(protoprivs); 11841408Smckusick exit(0); 11941408Smckusick } 12041408Smckusick for ( ; argc > 0; argc--, argv++) { 12141408Smckusick if ((id = getentry(*argv, quotatype)) == -1) 12212803Smckusick continue; 12341408Smckusick curprivs = getprivs(id, quotatype); 12441408Smckusick if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) 12541408Smckusick continue; 12641408Smckusick if (editit(tmpfil) && readprivs(curprivs, tmpfd)) 12741408Smckusick putprivs(id, quotatype, curprivs); 12841408Smckusick freeprivs(curprivs); 12912803Smckusick } 13041408Smckusick close(tmpfd); 13112707Smckusick unlink(tmpfil); 13212707Smckusick exit(0); 13312707Smckusick } 13412707Smckusick 13541408Smckusick usage() 13641408Smckusick { 13741408Smckusick fprintf(stderr, "%s%s%s%s", 13841408Smckusick "Usage: edquota [-u] [-p username] username ...\n", 13941408Smckusick "\tedquota -g [-p groupname] groupname ...\n", 14041408Smckusick "\tedquota [-u] -t\n", "\tedquota -g -t\n"); 14141408Smckusick exit(1); 14241408Smckusick } 14341408Smckusick 14441408Smckusick /* 14541408Smckusick * This routine converts a name for a particular quota type to 14641408Smckusick * an identifier. This routine must agree with the kernel routine 14741408Smckusick * getinoquota as to the interpretation of quota types. 14841408Smckusick */ 14941408Smckusick getentry(name, quotatype) 15012803Smckusick char *name; 15141408Smckusick int quotatype; 15212707Smckusick { 15312803Smckusick struct passwd *pw; 15441408Smckusick struct group *gr; 15512707Smckusick 15612707Smckusick if (alldigits(name)) 15741408Smckusick return (atoi(name)); 15841408Smckusick switch(quotatype) { 15941408Smckusick case USRQUOTA: 16041408Smckusick if (pw = getpwnam(name)) 16141408Smckusick return (pw->pw_uid); 16212803Smckusick fprintf(stderr, "%s: no such user\n", name); 16341408Smckusick break; 16441408Smckusick case GRPQUOTA: 16541408Smckusick if (gr = getgrnam(name)) 16641408Smckusick return (gr->gr_gid); 16741408Smckusick fprintf(stderr, "%s: no such group\n", name); 16841408Smckusick break; 16941408Smckusick default: 17041408Smckusick fprintf(stderr, "%d: unknown quota type\n", quotatype); 17141408Smckusick break; 17212707Smckusick } 17341408Smckusick sleep(1); 17441408Smckusick return (-1); 17512707Smckusick } 17612707Smckusick 17741408Smckusick /* 17841408Smckusick * Collect the requested quota information. 17941408Smckusick */ 18041408Smckusick struct quotause * 18141408Smckusick getprivs(id, quotatype) 18241408Smckusick register long id; 18341408Smckusick int quotatype; 18412707Smckusick { 18541408Smckusick register struct fstab *fs; 18641408Smckusick register struct quotause *qup, *quptail; 18741408Smckusick struct quotause *quphead; 18841444Smckusick int qcmd, qupsize, fd; 18941444Smckusick char *qfpathname; 19041408Smckusick static int warned = 0; 19141408Smckusick extern int errno; 19241408Smckusick 19341408Smckusick setfsent(); 19441408Smckusick quphead = (struct quotause *)0; 19541408Smckusick qcmd = QCMD(Q_GETQUOTA, quotatype); 19641408Smckusick while (fs = getfsent()) { 19741444Smckusick if (strcmp(fs->fs_vfstype, "ufs")) 19841408Smckusick continue; 19941444Smckusick if (!hasquota(fs, quotatype, &qfpathname)) 20041408Smckusick continue; 20141444Smckusick qupsize = sizeof(*qup) + strlen(qfpathname); 20241444Smckusick if ((qup = (struct quotause *)malloc(qupsize)) == NULL) { 20341408Smckusick fprintf(stderr, "edquota: out of memory\n"); 20441408Smckusick exit(2); 20541408Smckusick } 20641444Smckusick if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { 20741408Smckusick if (errno == EOPNOTSUPP && !warned) { 20841408Smckusick warned++; 20941408Smckusick fprintf(stderr, "Warning: %s\n", 21041408Smckusick "Quotas are not compiled into this kernel"); 21141408Smckusick sleep(3); 21241408Smckusick } 21341444Smckusick if ((fd = open(qfpathname, O_RDONLY)) < 0) { 21441444Smckusick fd = open(qfpathname, O_RDWR|O_CREAT, 0640); 21541444Smckusick if (fd < 0 && errno != ENOENT) { 21641444Smckusick perror(qfpathname); 21741444Smckusick free(qup); 21841444Smckusick continue; 21941444Smckusick } 22041444Smckusick fprintf(stderr, "Creating quota file %s\n", 22141444Smckusick qfpathname); 22241444Smckusick sleep(3); 22341444Smckusick (void) fchown(fd, getuid(), 22441444Smckusick getentry(quotagroup, GRPQUOTA)); 22541444Smckusick (void) fchmod(fd, 0640); 22641444Smckusick } 22741408Smckusick lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); 22841408Smckusick switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 22941408Smckusick case 0: /* EOF */ 23041408Smckusick /* 23141408Smckusick * Convert implicit 0 quota (EOF) 23241408Smckusick * into an explicit one (zero'ed dqblk) 23341408Smckusick */ 23441408Smckusick bzero((caddr_t)&qup->dqblk, 23541408Smckusick sizeof(struct dqblk)); 23641408Smckusick break; 23741408Smckusick 23841408Smckusick case sizeof(struct dqblk): /* OK */ 23941408Smckusick break; 24041408Smckusick 24141408Smckusick default: /* ERROR */ 24241408Smckusick fprintf(stderr, "edquota: read error in "); 24341444Smckusick perror(qfpathname); 24441408Smckusick close(fd); 24541408Smckusick free(qup); 24641408Smckusick continue; 24741408Smckusick } 24841444Smckusick close(fd); 24941408Smckusick } 25041444Smckusick strcpy(qup->qfname, qfpathname); 25141408Smckusick strcpy(qup->fsname, fs->fs_file); 25241408Smckusick if (quphead == NULL) 25341408Smckusick quphead = qup; 25441408Smckusick else 25541408Smckusick quptail->next = qup; 25641408Smckusick quptail = qup; 25741408Smckusick qup->next = 0; 25841408Smckusick } 25941408Smckusick endfsent(); 26041408Smckusick return (quphead); 26141408Smckusick } 26241408Smckusick 26341408Smckusick /* 26441408Smckusick * Store the requested quota information. 26541408Smckusick */ 26641408Smckusick putprivs(id, quotatype, quplist) 26741408Smckusick long id; 26841408Smckusick int quotatype; 26941408Smckusick struct quotause *quplist; 27041408Smckusick { 27141408Smckusick register struct quotause *qup; 27241408Smckusick int qcmd, fd; 27341408Smckusick 27441408Smckusick qcmd = QCMD(Q_SETQUOTA, quotatype); 27541408Smckusick for (qup = quplist; qup; qup = qup->next) { 27641444Smckusick if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0) 27741408Smckusick continue; 27841444Smckusick if ((fd = open(qup->qfname, O_WRONLY)) < 0) { 27941444Smckusick perror(qup->qfname); 28041408Smckusick } else { 28141408Smckusick lseek(fd, (long)id * (long)sizeof (struct dqblk), 0); 28241408Smckusick if (write(fd, &qup->dqblk, sizeof (struct dqblk)) != 28341408Smckusick sizeof (struct dqblk)) { 28441408Smckusick fprintf(stderr, "edquota: "); 28541444Smckusick perror(qup->qfname); 28641408Smckusick } 28741408Smckusick close(fd); 28841408Smckusick } 28941408Smckusick } 29041408Smckusick } 29141408Smckusick 29241408Smckusick /* 29341408Smckusick * Take a list of priviledges and get it edited. 29441408Smckusick */ 29541408Smckusick editit(tmpfile) 29641408Smckusick char *tmpfile; 29741408Smckusick { 29833609Sbostic long omask; 29941408Smckusick int pid, stat; 30041408Smckusick extern char *getenv(); 30112707Smckusick 30233609Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 30312707Smckusick top: 30412707Smckusick if ((pid = fork()) < 0) { 30512707Smckusick extern errno; 30612707Smckusick 30712707Smckusick if (errno == EPROCLIM) { 30812707Smckusick fprintf(stderr, "You have too many processes\n"); 30912707Smckusick return(0); 31012707Smckusick } 31112707Smckusick if (errno == EAGAIN) { 31212707Smckusick sleep(1); 31312707Smckusick goto top; 31412707Smckusick } 31512707Smckusick perror("fork"); 31612707Smckusick return (0); 31712707Smckusick } 31812707Smckusick if (pid == 0) { 31912707Smckusick register char *ed; 32012707Smckusick 32113025Ssam sigsetmask(omask); 32212707Smckusick setgid(getgid()); 32312707Smckusick setuid(getuid()); 32412707Smckusick if ((ed = getenv("EDITOR")) == (char *)0) 32537976Sbostic ed = _PATH_VI; 32641408Smckusick execlp(ed, ed, tmpfile, 0); 32712707Smckusick perror(ed); 32812707Smckusick exit(1); 32912707Smckusick } 33041408Smckusick waitpid(pid, &stat, 0); 33113025Ssam sigsetmask(omask); 33241408Smckusick if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) 33341408Smckusick return (0); 33441408Smckusick return (1); 33512707Smckusick } 33612707Smckusick 33741408Smckusick /* 33841408Smckusick * Convert a quotause list to an ASCII file. 33941408Smckusick */ 34041408Smckusick writeprivs(quplist, outfd, name, quotatype) 34141408Smckusick struct quotause *quplist; 34241408Smckusick int outfd; 34341408Smckusick char *name; 34441408Smckusick int quotatype; 34512707Smckusick { 34641408Smckusick register struct quotause *qup; 34712707Smckusick FILE *fd; 34812707Smckusick 34943266Smckusick ftruncate(outfd, 0); 35041408Smckusick lseek(outfd, 0, L_SET); 35141408Smckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) { 35212707Smckusick fprintf(stderr, "edquota: "); 35312707Smckusick perror(tmpfil); 35412707Smckusick exit(1); 35512707Smckusick } 35641408Smckusick fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name); 35741408Smckusick for (qup = quplist; qup; qup = qup->next) { 35841408Smckusick fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n", 35941408Smckusick qup->fsname, "blocks in use:", 36041408Smckusick dbtob(qup->dqblk.dqb_curblocks) / 1024, 36141408Smckusick dbtob(qup->dqblk.dqb_bsoftlimit) / 1024, 36241408Smckusick dbtob(qup->dqblk.dqb_bhardlimit) / 1024); 36341408Smckusick fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n", 36441408Smckusick "\tinodes in use:", qup->dqblk.dqb_curinodes, 36541408Smckusick qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit); 36612707Smckusick } 36712707Smckusick fclose(fd); 36841408Smckusick return (1); 36912707Smckusick } 37012707Smckusick 37141408Smckusick /* 37241408Smckusick * Merge changes to an ASCII file into a quotause list. 37341408Smckusick */ 37441408Smckusick readprivs(quplist, infd) 37541408Smckusick struct quotause *quplist; 37641408Smckusick int infd; 37712707Smckusick { 37841408Smckusick register struct quotause *qup; 37912707Smckusick FILE *fd; 38041408Smckusick int cnt; 38141408Smckusick register char *cp; 38241408Smckusick struct dqblk dqblk; 38341408Smckusick char *fsp, line1[BUFSIZ], line2[BUFSIZ]; 38412707Smckusick 38541408Smckusick lseek(infd, 0, L_SET); 38641408Smckusick fd = fdopen(dup(infd), "r"); 38712707Smckusick if (fd == NULL) { 38812707Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 38941408Smckusick return (0); 39012707Smckusick } 39141408Smckusick /* 39241408Smckusick * Discard title line, then read pairs of lines to process. 39341408Smckusick */ 39441408Smckusick (void) fgets(line1, sizeof (line1), fd); 39541408Smckusick while (fgets(line1, sizeof (line1), fd) != NULL && 39641408Smckusick fgets(line2, sizeof (line2), fd) != NULL) { 39741408Smckusick if ((fsp = strtok(line1, " \t:")) == NULL) { 39841408Smckusick fprintf(stderr, "%s: bad format\n", line1); 39941408Smckusick return (0); 40041408Smckusick } 40141408Smckusick if ((cp = strtok((char *)0, "\n")) == NULL) { 40241408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, 40341408Smckusick &fsp[strlen(fsp) + 1]); 40441408Smckusick return (0); 40541408Smckusick } 40641408Smckusick cnt = sscanf(cp, 40741408Smckusick " blocks in use: %d, limits (soft = %d, hard = %d)", 40841408Smckusick &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit, 40941408Smckusick &dqblk.dqb_bhardlimit); 41041408Smckusick if (cnt != 3) { 41141408Smckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp); 41241408Smckusick return (0); 41341408Smckusick } 41441408Smckusick dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024); 41541408Smckusick dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024); 41641408Smckusick dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024); 41741408Smckusick if ((cp = strtok(line2, "\n")) == NULL) { 41841408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2); 41941408Smckusick return (0); 42041408Smckusick } 42141408Smckusick cnt = sscanf(cp, 42241408Smckusick "\tinodes in use: %d, limits (soft = %d, hard = %d)", 42341408Smckusick &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit, 42441408Smckusick &dqblk.dqb_ihardlimit); 42541408Smckusick if (cnt != 3) { 42641408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2); 42741408Smckusick return (0); 42841408Smckusick } 42941408Smckusick for (qup = quplist; qup; qup = qup->next) { 43041408Smckusick if (strcmp(fsp, qup->fsname)) 43141408Smckusick continue; 43241408Smckusick /* 43341408Smckusick * Cause time limit to be reset when the quota 43441408Smckusick * is next used if previously had no soft limit 43541408Smckusick * or were under it, but now have a soft limit 43641408Smckusick * and are over it. 43741408Smckusick */ 43841408Smckusick if (dqblk.dqb_bsoftlimit && 43941408Smckusick qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit && 44041408Smckusick (qup->dqblk.dqb_bsoftlimit == 0 || 44141408Smckusick qup->dqblk.dqb_curblocks < 44241408Smckusick qup->dqblk.dqb_bsoftlimit)) 44341408Smckusick qup->dqblk.dqb_btime = 0; 44441408Smckusick if (dqblk.dqb_isoftlimit && 44541408Smckusick qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit && 44641408Smckusick (qup->dqblk.dqb_isoftlimit == 0 || 44741408Smckusick qup->dqblk.dqb_curinodes < 44841408Smckusick qup->dqblk.dqb_isoftlimit)) 44941408Smckusick qup->dqblk.dqb_itime = 0; 45041408Smckusick qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit; 45141408Smckusick qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit; 45241408Smckusick qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit; 45341408Smckusick qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit; 45441408Smckusick qup->flags |= FOUND; 45541408Smckusick if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks && 45641408Smckusick dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes) 45741408Smckusick break; 45841408Smckusick fprintf(stderr, 45941408Smckusick "%s: cannot change current allocation\n", fsp); 46012707Smckusick break; 46141408Smckusick } 46241408Smckusick } 46341408Smckusick fclose(fd); 46441408Smckusick /* 46541408Smckusick * Disable quotas for any filesystems that have not been found. 46641408Smckusick */ 46741408Smckusick for (qup = quplist; qup; qup = qup->next) { 46841408Smckusick if (qup->flags & FOUND) { 46941408Smckusick qup->flags &= ~FOUND; 47012716Smckusick continue; 47112716Smckusick } 47241408Smckusick qup->dqblk.dqb_bsoftlimit = 0; 47341408Smckusick qup->dqblk.dqb_bhardlimit = 0; 47441408Smckusick qup->dqblk.dqb_isoftlimit = 0; 47541408Smckusick qup->dqblk.dqb_ihardlimit = 0; 47612707Smckusick } 47741408Smckusick return (1); 47841408Smckusick } 47941408Smckusick 48041408Smckusick /* 48141408Smckusick * Convert a quotause list to an ASCII file of grace times. 48241408Smckusick */ 48341408Smckusick writetimes(quplist, outfd, quotatype) 48441408Smckusick struct quotause *quplist; 48541408Smckusick int outfd; 48641408Smckusick int quotatype; 48741408Smckusick { 48841408Smckusick register struct quotause *qup; 48941408Smckusick char *cvtstoa(); 49041408Smckusick FILE *fd; 49141408Smckusick 49243266Smckusick ftruncate(outfd, 0); 49341408Smckusick lseek(outfd, 0, L_SET); 49441408Smckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) { 49541408Smckusick fprintf(stderr, "edquota: "); 49641408Smckusick perror(tmpfil); 49741408Smckusick exit(1); 49841408Smckusick } 49941408Smckusick fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n"); 50041408Smckusick fprintf(fd, "Grace period before enforcing soft limits for %ss:\n", 50141408Smckusick qfextension[quotatype]); 50241408Smckusick for (qup = quplist; qup; qup = qup->next) { 50341408Smckusick fprintf(fd, "%s: block grace period: %s, ", 50441408Smckusick qup->fsname, cvtstoa(qup->dqblk.dqb_btime)); 50541408Smckusick fprintf(fd, "file grace period: %s\n", 50641408Smckusick cvtstoa(qup->dqblk.dqb_itime)); 50741408Smckusick } 50812707Smckusick fclose(fd); 50941408Smckusick return (1); 51041408Smckusick } 51141408Smckusick 51241408Smckusick /* 51341408Smckusick * Merge changes of grace times in an ASCII file into a quotause list. 51441408Smckusick */ 51541408Smckusick readtimes(quplist, infd) 51641408Smckusick struct quotause *quplist; 51741408Smckusick int infd; 51841408Smckusick { 51941408Smckusick register struct quotause *qup; 52041408Smckusick FILE *fd; 52141408Smckusick int cnt; 52241408Smckusick register char *cp; 52341408Smckusick time_t itime, btime, iseconds, bseconds; 52441408Smckusick char *fsp, bunits[10], iunits[10], line1[BUFSIZ]; 52541408Smckusick 52641408Smckusick lseek(infd, 0, L_SET); 52741408Smckusick fd = fdopen(dup(infd), "r"); 52841408Smckusick if (fd == NULL) { 52941408Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 53041408Smckusick return (0); 53141408Smckusick } 53241408Smckusick /* 53341408Smckusick * Discard two title lines, then read lines to process. 53441408Smckusick */ 53541408Smckusick (void) fgets(line1, sizeof (line1), fd); 53641408Smckusick (void) fgets(line1, sizeof (line1), fd); 53741408Smckusick while (fgets(line1, sizeof (line1), fd) != NULL) { 53841408Smckusick if ((fsp = strtok(line1, " \t:")) == NULL) { 53941408Smckusick fprintf(stderr, "%s: bad format\n", line1); 54041408Smckusick return (0); 54141408Smckusick } 54241408Smckusick if ((cp = strtok((char *)0, "\n")) == NULL) { 54341408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, 54441408Smckusick &fsp[strlen(fsp) + 1]); 54541408Smckusick return (0); 54641408Smckusick } 54741408Smckusick cnt = sscanf(cp, 54841408Smckusick " block grace period: %d %s file grace period: %d %s", 54941408Smckusick &btime, bunits, &itime, iunits); 55041408Smckusick if (cnt != 4) { 55141408Smckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp); 55241408Smckusick return (0); 55341408Smckusick } 55441408Smckusick if (cvtatos(btime, bunits, &bseconds) == 0) 55541408Smckusick return (0); 55641408Smckusick if (cvtatos(itime, iunits, &iseconds) == 0) 55741408Smckusick return (0); 55841408Smckusick for (qup = quplist; qup; qup = qup->next) { 55941408Smckusick if (strcmp(fsp, qup->fsname)) 56041408Smckusick continue; 56141408Smckusick qup->dqblk.dqb_btime = bseconds; 56241408Smckusick qup->dqblk.dqb_itime = iseconds; 56341408Smckusick qup->flags |= FOUND; 56412707Smckusick break; 56512707Smckusick } 56641408Smckusick } 56741408Smckusick fclose(fd); 56841408Smckusick /* 56941408Smckusick * reset default grace periods for any filesystems 57041408Smckusick * that have not been found. 57141408Smckusick */ 57241408Smckusick for (qup = quplist; qup; qup = qup->next) { 57341408Smckusick if (qup->flags & FOUND) { 57441408Smckusick qup->flags &= ~FOUND; 57512707Smckusick continue; 57612707Smckusick } 57741408Smckusick qup->dqblk.dqb_btime = 0; 57841408Smckusick qup->dqblk.dqb_itime = 0; 57912707Smckusick } 58041408Smckusick return (1); 58112707Smckusick } 58212707Smckusick 58341408Smckusick /* 58441408Smckusick * Convert seconds to ASCII times. 58541408Smckusick */ 58612707Smckusick char * 58741408Smckusick cvtstoa(time) 58841408Smckusick time_t time; 58912707Smckusick { 59041408Smckusick static char buf[20]; 59112707Smckusick 59241408Smckusick if (time % (24 * 60 * 60) == 0) { 59341408Smckusick time /= 24 * 60 * 60; 59441408Smckusick sprintf(buf, "%d day%s", time, time == 1 ? "" : "s"); 59541408Smckusick } else if (time % (60 * 60) == 0) { 59641408Smckusick time /= 60 * 60; 59741408Smckusick sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s"); 59841408Smckusick } else if (time % 60 == 0) { 59941408Smckusick time /= 60; 60041408Smckusick sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s"); 60141408Smckusick } else 60241408Smckusick sprintf(buf, "%d second%s", time, time == 1 ? "" : "s"); 60341408Smckusick return (buf); 60441408Smckusick } 60541408Smckusick 60641408Smckusick /* 60741408Smckusick * Convert ASCII input times to seconds. 60841408Smckusick */ 60941408Smckusick cvtatos(time, units, seconds) 61041408Smckusick time_t time; 61141408Smckusick char *units; 61241408Smckusick time_t *seconds; 61341408Smckusick { 61441408Smckusick 61541408Smckusick if (bcmp(units, "second", 6) == 0) 61641408Smckusick *seconds = time; 61741408Smckusick else if (bcmp(units, "minute", 6) == 0) 61841408Smckusick *seconds = time * 60; 61941408Smckusick else if (bcmp(units, "hour", 4) == 0) 62041408Smckusick *seconds = time * 60 * 60; 62141408Smckusick else if (bcmp(units, "day", 3) == 0) 62241408Smckusick *seconds = time * 24 * 60 * 60; 62341408Smckusick else { 62441408Smckusick printf("%s: bad units, specify %s\n", units, 62541408Smckusick "days, hours, minutes, or seconds"); 62641408Smckusick return (0); 62712707Smckusick } 62841408Smckusick return (1); 62912707Smckusick } 63012707Smckusick 63141408Smckusick /* 63241408Smckusick * Free a list of quotause structures. 63341408Smckusick */ 63441408Smckusick freeprivs(quplist) 63541408Smckusick struct quotause *quplist; 63641408Smckusick { 63741408Smckusick register struct quotause *qup, *nextqup; 63841408Smckusick 63941408Smckusick for (qup = quplist; qup; qup = nextqup) { 64041408Smckusick nextqup = qup->next; 64141408Smckusick free(qup); 64241408Smckusick } 64341408Smckusick } 64441408Smckusick 64541408Smckusick /* 64641408Smckusick * Check whether a string is completely composed of digits. 64741408Smckusick */ 64812707Smckusick alldigits(s) 64912707Smckusick register char *s; 65012707Smckusick { 65112707Smckusick register c; 65212707Smckusick 65312707Smckusick c = *s++; 65412707Smckusick do { 65512707Smckusick if (!isdigit(c)) 65612707Smckusick return (0); 65712707Smckusick } while (c = *s++); 65812707Smckusick return (1); 65912707Smckusick } 66012707Smckusick 66141408Smckusick /* 66241408Smckusick * Check to see if a particular quota is to be enabled. 66341408Smckusick */ 66441444Smckusick hasquota(fs, type, qfnamep) 66541444Smckusick register struct fstab *fs; 66641408Smckusick int type; 66741444Smckusick char **qfnamep; 66812707Smckusick { 66941408Smckusick register char *opt; 67041444Smckusick char *cp, *index(), *strtok(); 67141408Smckusick static char initname, usrname[100], grpname[100]; 67241444Smckusick static char buf[BUFSIZ]; 67312707Smckusick 67441408Smckusick if (!initname) { 67541408Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 67641408Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 67741408Smckusick initname = 1; 67812707Smckusick } 67941444Smckusick strcpy(buf, fs->fs_mntops); 68041408Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 68141444Smckusick if (cp = index(opt, '=')) 68241444Smckusick *cp++ = '\0'; 68341408Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 68441444Smckusick break; 68541408Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 68641444Smckusick break; 68712707Smckusick } 68841444Smckusick if (!opt) 68941444Smckusick return (0); 69041444Smckusick if (cp) { 69141444Smckusick *qfnamep = cp; 69241444Smckusick return (1); 69341444Smckusick } 69441444Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 69541444Smckusick *qfnamep = buf; 69641444Smckusick return (1); 69712707Smckusick } 698