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*68941Sbostic static char sccsid[] = "@(#)edquota.c 8.3 (Berkeley) 04/27/95";
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>
2867977Smckusick #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
main(argc,argv)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
usage()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 */
getentry(name,quotatype)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 *
getprivs(id,quotatype)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 }
227*68941Sbostic lseek(fd, (off_t)(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 */
putprivs(id,quotatype,quplist)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 {
281*68941Sbostic lseek(fd,
282*68941Sbostic (off_t)(id * (long)sizeof (struct dqblk)), L_SET);
28341408Smckusick if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
28441408Smckusick sizeof (struct dqblk)) {
28541408Smckusick fprintf(stderr, "edquota: ");
28641444Smckusick perror(qup->qfname);
28741408Smckusick }
28841408Smckusick close(fd);
28941408Smckusick }
29041408Smckusick }
29141408Smckusick }
29241408Smckusick
29341408Smckusick /*
29441408Smckusick * Take a list of priviledges and get it edited.
29541408Smckusick */
editit(tmpfile)29641408Smckusick editit(tmpfile)
29741408Smckusick char *tmpfile;
29841408Smckusick {
29933609Sbostic long omask;
30041408Smckusick int pid, stat;
30141408Smckusick extern char *getenv();
30212707Smckusick
30333609Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
30412707Smckusick top:
30512707Smckusick if ((pid = fork()) < 0) {
30612707Smckusick extern errno;
30712707Smckusick
30812707Smckusick if (errno == EPROCLIM) {
30912707Smckusick fprintf(stderr, "You have too many processes\n");
31012707Smckusick return(0);
31112707Smckusick }
31212707Smckusick if (errno == EAGAIN) {
31312707Smckusick sleep(1);
31412707Smckusick goto top;
31512707Smckusick }
31612707Smckusick perror("fork");
31712707Smckusick return (0);
31812707Smckusick }
31912707Smckusick if (pid == 0) {
32012707Smckusick register char *ed;
32112707Smckusick
32213025Ssam sigsetmask(omask);
32312707Smckusick setgid(getgid());
32412707Smckusick setuid(getuid());
32512707Smckusick if ((ed = getenv("EDITOR")) == (char *)0)
32637976Sbostic ed = _PATH_VI;
32741408Smckusick execlp(ed, ed, tmpfile, 0);
32812707Smckusick perror(ed);
32912707Smckusick exit(1);
33012707Smckusick }
33141408Smckusick waitpid(pid, &stat, 0);
33213025Ssam sigsetmask(omask);
33341408Smckusick if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
33441408Smckusick return (0);
33541408Smckusick return (1);
33612707Smckusick }
33712707Smckusick
33841408Smckusick /*
33941408Smckusick * Convert a quotause list to an ASCII file.
34041408Smckusick */
34141408Smckusick writeprivs(quplist, outfd, name, quotatype)
34241408Smckusick struct quotause *quplist;
34341408Smckusick int outfd;
34441408Smckusick char *name;
34541408Smckusick int quotatype;
34612707Smckusick {
34741408Smckusick register struct quotause *qup;
34812707Smckusick FILE *fd;
34912707Smckusick
35043266Smckusick ftruncate(outfd, 0);
35141408Smckusick lseek(outfd, 0, L_SET);
35241408Smckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) {
35312707Smckusick fprintf(stderr, "edquota: ");
35412707Smckusick perror(tmpfil);
35512707Smckusick exit(1);
35612707Smckusick }
35741408Smckusick fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
35841408Smckusick for (qup = quplist; qup; qup = qup->next) {
35941408Smckusick fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n",
36041408Smckusick qup->fsname, "blocks in use:",
36141408Smckusick dbtob(qup->dqblk.dqb_curblocks) / 1024,
36241408Smckusick dbtob(qup->dqblk.dqb_bsoftlimit) / 1024,
36341408Smckusick dbtob(qup->dqblk.dqb_bhardlimit) / 1024);
36441408Smckusick fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n",
36541408Smckusick "\tinodes in use:", qup->dqblk.dqb_curinodes,
36641408Smckusick qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
36712707Smckusick }
36812707Smckusick fclose(fd);
36941408Smckusick return (1);
37012707Smckusick }
37112707Smckusick
37241408Smckusick /*
37341408Smckusick * Merge changes to an ASCII file into a quotause list.
37441408Smckusick */
37541408Smckusick readprivs(quplist, infd)
37641408Smckusick struct quotause *quplist;
37741408Smckusick int infd;
37812707Smckusick {
37941408Smckusick register struct quotause *qup;
38012707Smckusick FILE *fd;
38141408Smckusick int cnt;
38241408Smckusick register char *cp;
38341408Smckusick struct dqblk dqblk;
38441408Smckusick char *fsp, line1[BUFSIZ], line2[BUFSIZ];
38512707Smckusick
38641408Smckusick lseek(infd, 0, L_SET);
38741408Smckusick fd = fdopen(dup(infd), "r");
38812707Smckusick if (fd == NULL) {
38912707Smckusick fprintf(stderr, "Can't re-read temp file!!\n");
39041408Smckusick return (0);
39112707Smckusick }
39241408Smckusick /*
39341408Smckusick * Discard title line, then read pairs of lines to process.
39441408Smckusick */
39541408Smckusick (void) fgets(line1, sizeof (line1), fd);
39641408Smckusick while (fgets(line1, sizeof (line1), fd) != NULL &&
39741408Smckusick fgets(line2, sizeof (line2), fd) != NULL) {
39841408Smckusick if ((fsp = strtok(line1, " \t:")) == NULL) {
39941408Smckusick fprintf(stderr, "%s: bad format\n", line1);
40041408Smckusick return (0);
40141408Smckusick }
40241408Smckusick if ((cp = strtok((char *)0, "\n")) == NULL) {
40341408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp,
40441408Smckusick &fsp[strlen(fsp) + 1]);
40541408Smckusick return (0);
40641408Smckusick }
40741408Smckusick cnt = sscanf(cp,
40841408Smckusick " blocks in use: %d, limits (soft = %d, hard = %d)",
40941408Smckusick &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
41041408Smckusick &dqblk.dqb_bhardlimit);
41141408Smckusick if (cnt != 3) {
41241408Smckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
41341408Smckusick return (0);
41441408Smckusick }
41541408Smckusick dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024);
41641408Smckusick dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024);
41741408Smckusick dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024);
41841408Smckusick if ((cp = strtok(line2, "\n")) == NULL) {
41941408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
42041408Smckusick return (0);
42141408Smckusick }
42241408Smckusick cnt = sscanf(cp,
42341408Smckusick "\tinodes in use: %d, limits (soft = %d, hard = %d)",
42441408Smckusick &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
42541408Smckusick &dqblk.dqb_ihardlimit);
42641408Smckusick if (cnt != 3) {
42741408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
42841408Smckusick return (0);
42941408Smckusick }
43041408Smckusick for (qup = quplist; qup; qup = qup->next) {
43141408Smckusick if (strcmp(fsp, qup->fsname))
43241408Smckusick continue;
43341408Smckusick /*
43441408Smckusick * Cause time limit to be reset when the quota
43541408Smckusick * is next used if previously had no soft limit
43641408Smckusick * or were under it, but now have a soft limit
43741408Smckusick * and are over it.
43841408Smckusick */
43941408Smckusick if (dqblk.dqb_bsoftlimit &&
44041408Smckusick qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit &&
44141408Smckusick (qup->dqblk.dqb_bsoftlimit == 0 ||
44241408Smckusick qup->dqblk.dqb_curblocks <
44341408Smckusick qup->dqblk.dqb_bsoftlimit))
44441408Smckusick qup->dqblk.dqb_btime = 0;
44541408Smckusick if (dqblk.dqb_isoftlimit &&
44641408Smckusick qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit &&
44741408Smckusick (qup->dqblk.dqb_isoftlimit == 0 ||
44841408Smckusick qup->dqblk.dqb_curinodes <
44941408Smckusick qup->dqblk.dqb_isoftlimit))
45041408Smckusick qup->dqblk.dqb_itime = 0;
45141408Smckusick qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
45241408Smckusick qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
45341408Smckusick qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
45441408Smckusick qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
45541408Smckusick qup->flags |= FOUND;
45641408Smckusick if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
45741408Smckusick dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
45841408Smckusick break;
45941408Smckusick fprintf(stderr,
46041408Smckusick "%s: cannot change current allocation\n", fsp);
46112707Smckusick break;
46241408Smckusick }
46341408Smckusick }
46441408Smckusick fclose(fd);
46541408Smckusick /*
46641408Smckusick * Disable quotas for any filesystems that have not been found.
46741408Smckusick */
46841408Smckusick for (qup = quplist; qup; qup = qup->next) {
46941408Smckusick if (qup->flags & FOUND) {
47041408Smckusick qup->flags &= ~FOUND;
47112716Smckusick continue;
47212716Smckusick }
47341408Smckusick qup->dqblk.dqb_bsoftlimit = 0;
47441408Smckusick qup->dqblk.dqb_bhardlimit = 0;
47541408Smckusick qup->dqblk.dqb_isoftlimit = 0;
47641408Smckusick qup->dqblk.dqb_ihardlimit = 0;
47712707Smckusick }
47841408Smckusick return (1);
47941408Smckusick }
48041408Smckusick
48141408Smckusick /*
48241408Smckusick * Convert a quotause list to an ASCII file of grace times.
48341408Smckusick */
48441408Smckusick writetimes(quplist, outfd, quotatype)
48541408Smckusick struct quotause *quplist;
48641408Smckusick int outfd;
48741408Smckusick int quotatype;
48841408Smckusick {
48941408Smckusick register struct quotause *qup;
49041408Smckusick char *cvtstoa();
49141408Smckusick FILE *fd;
49241408Smckusick
49343266Smckusick ftruncate(outfd, 0);
49441408Smckusick lseek(outfd, 0, L_SET);
49541408Smckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) {
49641408Smckusick fprintf(stderr, "edquota: ");
49741408Smckusick perror(tmpfil);
49841408Smckusick exit(1);
49941408Smckusick }
50041408Smckusick fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n");
50141408Smckusick fprintf(fd, "Grace period before enforcing soft limits for %ss:\n",
50241408Smckusick qfextension[quotatype]);
50341408Smckusick for (qup = quplist; qup; qup = qup->next) {
50441408Smckusick fprintf(fd, "%s: block grace period: %s, ",
50541408Smckusick qup->fsname, cvtstoa(qup->dqblk.dqb_btime));
50641408Smckusick fprintf(fd, "file grace period: %s\n",
50741408Smckusick cvtstoa(qup->dqblk.dqb_itime));
50841408Smckusick }
50912707Smckusick fclose(fd);
51041408Smckusick return (1);
51141408Smckusick }
51241408Smckusick
51341408Smckusick /*
51441408Smckusick * Merge changes of grace times in an ASCII file into a quotause list.
51541408Smckusick */
51641408Smckusick readtimes(quplist, infd)
51741408Smckusick struct quotause *quplist;
51841408Smckusick int infd;
51941408Smckusick {
52041408Smckusick register struct quotause *qup;
52141408Smckusick FILE *fd;
52241408Smckusick int cnt;
52341408Smckusick register char *cp;
52441408Smckusick time_t itime, btime, iseconds, bseconds;
52541408Smckusick char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
52641408Smckusick
52741408Smckusick lseek(infd, 0, L_SET);
52841408Smckusick fd = fdopen(dup(infd), "r");
52941408Smckusick if (fd == NULL) {
53041408Smckusick fprintf(stderr, "Can't re-read temp file!!\n");
53141408Smckusick return (0);
53241408Smckusick }
53341408Smckusick /*
53441408Smckusick * Discard two title lines, then read lines to process.
53541408Smckusick */
53641408Smckusick (void) fgets(line1, sizeof (line1), fd);
53741408Smckusick (void) fgets(line1, sizeof (line1), fd);
53841408Smckusick while (fgets(line1, sizeof (line1), fd) != NULL) {
53941408Smckusick if ((fsp = strtok(line1, " \t:")) == NULL) {
54041408Smckusick fprintf(stderr, "%s: bad format\n", line1);
54141408Smckusick return (0);
54241408Smckusick }
54341408Smckusick if ((cp = strtok((char *)0, "\n")) == NULL) {
54441408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp,
54541408Smckusick &fsp[strlen(fsp) + 1]);
54641408Smckusick return (0);
54741408Smckusick }
54841408Smckusick cnt = sscanf(cp,
54941408Smckusick " block grace period: %d %s file grace period: %d %s",
55041408Smckusick &btime, bunits, &itime, iunits);
55141408Smckusick if (cnt != 4) {
55241408Smckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
55341408Smckusick return (0);
55441408Smckusick }
55541408Smckusick if (cvtatos(btime, bunits, &bseconds) == 0)
55641408Smckusick return (0);
55741408Smckusick if (cvtatos(itime, iunits, &iseconds) == 0)
55841408Smckusick return (0);
55941408Smckusick for (qup = quplist; qup; qup = qup->next) {
56041408Smckusick if (strcmp(fsp, qup->fsname))
56141408Smckusick continue;
56241408Smckusick qup->dqblk.dqb_btime = bseconds;
56341408Smckusick qup->dqblk.dqb_itime = iseconds;
56441408Smckusick qup->flags |= FOUND;
56512707Smckusick break;
56612707Smckusick }
56741408Smckusick }
56841408Smckusick fclose(fd);
56941408Smckusick /*
57041408Smckusick * reset default grace periods for any filesystems
57141408Smckusick * that have not been found.
57241408Smckusick */
57341408Smckusick for (qup = quplist; qup; qup = qup->next) {
57441408Smckusick if (qup->flags & FOUND) {
57541408Smckusick qup->flags &= ~FOUND;
57612707Smckusick continue;
57712707Smckusick }
57841408Smckusick qup->dqblk.dqb_btime = 0;
57941408Smckusick qup->dqblk.dqb_itime = 0;
58012707Smckusick }
58141408Smckusick return (1);
58212707Smckusick }
58312707Smckusick
58441408Smckusick /*
58541408Smckusick * Convert seconds to ASCII times.
58641408Smckusick */
58712707Smckusick char *
cvtstoa(time)58841408Smckusick cvtstoa(time)
58941408Smckusick time_t time;
59012707Smckusick {
59141408Smckusick static char buf[20];
59212707Smckusick
59341408Smckusick if (time % (24 * 60 * 60) == 0) {
59441408Smckusick time /= 24 * 60 * 60;
59541408Smckusick sprintf(buf, "%d day%s", time, time == 1 ? "" : "s");
59641408Smckusick } else if (time % (60 * 60) == 0) {
59741408Smckusick time /= 60 * 60;
59841408Smckusick sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s");
59941408Smckusick } else if (time % 60 == 0) {
60041408Smckusick time /= 60;
60141408Smckusick sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s");
60241408Smckusick } else
60341408Smckusick sprintf(buf, "%d second%s", time, time == 1 ? "" : "s");
60441408Smckusick return (buf);
60541408Smckusick }
60641408Smckusick
60741408Smckusick /*
60841408Smckusick * Convert ASCII input times to seconds.
60941408Smckusick */
cvtatos(time,units,seconds)61041408Smckusick cvtatos(time, units, seconds)
61141408Smckusick time_t time;
61241408Smckusick char *units;
61341408Smckusick time_t *seconds;
61441408Smckusick {
61541408Smckusick
61641408Smckusick if (bcmp(units, "second", 6) == 0)
61741408Smckusick *seconds = time;
61841408Smckusick else if (bcmp(units, "minute", 6) == 0)
61941408Smckusick *seconds = time * 60;
62041408Smckusick else if (bcmp(units, "hour", 4) == 0)
62141408Smckusick *seconds = time * 60 * 60;
62241408Smckusick else if (bcmp(units, "day", 3) == 0)
62341408Smckusick *seconds = time * 24 * 60 * 60;
62441408Smckusick else {
62541408Smckusick printf("%s: bad units, specify %s\n", units,
62641408Smckusick "days, hours, minutes, or seconds");
62741408Smckusick return (0);
62812707Smckusick }
62941408Smckusick return (1);
63012707Smckusick }
63112707Smckusick
63241408Smckusick /*
63341408Smckusick * Free a list of quotause structures.
63441408Smckusick */
63541408Smckusick freeprivs(quplist)
63641408Smckusick struct quotause *quplist;
63741408Smckusick {
63841408Smckusick register struct quotause *qup, *nextqup;
63941408Smckusick
64041408Smckusick for (qup = quplist; qup; qup = nextqup) {
64141408Smckusick nextqup = qup->next;
64241408Smckusick free(qup);
64341408Smckusick }
64441408Smckusick }
64541408Smckusick
64641408Smckusick /*
64741408Smckusick * Check whether a string is completely composed of digits.
64841408Smckusick */
alldigits(s)64912707Smckusick alldigits(s)
65012707Smckusick register char *s;
65112707Smckusick {
65212707Smckusick register c;
65312707Smckusick
65412707Smckusick c = *s++;
65512707Smckusick do {
65612707Smckusick if (!isdigit(c))
65712707Smckusick return (0);
65812707Smckusick } while (c = *s++);
65912707Smckusick return (1);
66012707Smckusick }
66112707Smckusick
66241408Smckusick /*
66341408Smckusick * Check to see if a particular quota is to be enabled.
66441408Smckusick */
hasquota(fs,type,qfnamep)66541444Smckusick hasquota(fs, type, qfnamep)
66641444Smckusick register struct fstab *fs;
66741408Smckusick int type;
66841444Smckusick char **qfnamep;
66912707Smckusick {
67041408Smckusick register char *opt;
67141444Smckusick char *cp, *index(), *strtok();
67241408Smckusick static char initname, usrname[100], grpname[100];
67341444Smckusick static char buf[BUFSIZ];
67412707Smckusick
67541408Smckusick if (!initname) {
67641408Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
67741408Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
67841408Smckusick initname = 1;
67912707Smckusick }
68041444Smckusick strcpy(buf, fs->fs_mntops);
68141408Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
68241444Smckusick if (cp = index(opt, '='))
68341444Smckusick *cp++ = '\0';
68441408Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0)
68541444Smckusick break;
68641408Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
68741444Smckusick break;
68812707Smckusick }
68941444Smckusick if (!opt)
69041444Smckusick return (0);
69141444Smckusick if (cp) {
69241444Smckusick *qfnamep = cp;
69341444Smckusick return (1);
69441444Smckusick }
69541444Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
69641444Smckusick *qfnamep = buf;
69741444Smckusick return (1);
69812707Smckusick }
699