1404cca70Smckusick /*
2afd66061Sbostic * Copyright (c) 1980, 1990, 1993
3afd66061Sbostic * The Regents of the University of California. All rights reserved.
495bd6a7cSbostic *
54910f3baSmckusick * This code is derived from software contributed to Berkeley by
64910f3baSmckusick * Robert Elz at The University of Melbourne.
74910f3baSmckusick *
834cefc2bSbostic * %sccs.include.redist.c%
9404cca70Smckusick */
10404cca70Smckusick
11c7c65224Smckusick #ifndef lint
12afd66061Sbostic static char copyright[] =
13afd66061Sbostic "@(#) Copyright (c) 1980, 1990, 1993\n\
14afd66061Sbostic The Regents of the University of California. All rights reserved.\n";
1595bd6a7cSbostic #endif /* not lint */
16404cca70Smckusick
17404cca70Smckusick #ifndef lint
18*af968038Sbostic static char sccsid[] = "@(#)edquota.c 8.3 (Berkeley) 04/27/95";
1995bd6a7cSbostic #endif /* not lint */
20c7c65224Smckusick
21c7c65224Smckusick /*
22c7c65224Smckusick * Disk quota editor.
23c7c65224Smckusick */
24c7c65224Smckusick #include <sys/param.h>
25c7c65224Smckusick #include <sys/stat.h>
26c7c65224Smckusick #include <sys/file.h>
274910f3baSmckusick #include <sys/wait.h>
281594458aSmckusick #include <sys/queue.h>
291f7ae5beSbostic #include <ufs/ufs/quota.h>
30a60d7417Sbostic #include <errno.h>
31a60d7417Sbostic #include <fstab.h>
32a60d7417Sbostic #include <pwd.h>
334910f3baSmckusick #include <grp.h>
34a60d7417Sbostic #include <ctype.h>
35a60d7417Sbostic #include <stdio.h>
364910f3baSmckusick #include <string.h>
3731e13fe6Sbostic #include <unistd.h>
38cb749fa4Sbostic #include "pathnames.h"
39c7c65224Smckusick
40c4937015Smckusick char *qfname = QUOTAFILENAME;
41c4937015Smckusick char *qfextension[] = INITQFNAMES;
42c4937015Smckusick char *quotagroup = QUOTAGROUP;
43c49caeabSbostic char tmpfil[] = _PATH_TMP;
444910f3baSmckusick
454910f3baSmckusick struct quotause {
464910f3baSmckusick struct quotause *next;
474910f3baSmckusick long flags;
484910f3baSmckusick struct dqblk dqblk;
494910f3baSmckusick char fsname[MAXPATHLEN + 1];
5096bc10eeSmckusick char qfname[1]; /* actually longer */
514910f3baSmckusick } *getprivs();
524910f3baSmckusick #define FOUND 0x01
53c7c65224Smckusick
main(argc,argv)54c7c65224Smckusick main(argc, argv)
554910f3baSmckusick register char **argv;
564910f3baSmckusick int argc;
57c7c65224Smckusick {
584910f3baSmckusick register struct quotause *qup, *protoprivs, *curprivs;
594910f3baSmckusick extern char *optarg;
604910f3baSmckusick extern int optind;
614910f3baSmckusick register long id, protoid;
624910f3baSmckusick register int quotatype, tmpfd;
634910f3baSmckusick char *protoname, ch;
644910f3baSmckusick int tflag = 0, pflag = 0;
65c7c65224Smckusick
664910f3baSmckusick if (argc < 2)
674910f3baSmckusick usage();
68c7c65224Smckusick if (getuid()) {
694910f3baSmckusick fprintf(stderr, "edquota: permission denied\n");
70c7c65224Smckusick exit(1);
71c7c65224Smckusick }
724910f3baSmckusick quotatype = USRQUOTA;
734910f3baSmckusick while ((ch = getopt(argc, argv, "ugtp:")) != EOF) {
744910f3baSmckusick switch(ch) {
754910f3baSmckusick case 'p':
764910f3baSmckusick protoname = optarg;
774910f3baSmckusick pflag++;
784910f3baSmckusick break;
794910f3baSmckusick case 'g':
804910f3baSmckusick quotatype = GRPQUOTA;
814910f3baSmckusick break;
824910f3baSmckusick case 'u':
834910f3baSmckusick quotatype = USRQUOTA;
844910f3baSmckusick break;
854910f3baSmckusick case 't':
864910f3baSmckusick tflag++;
874910f3baSmckusick break;
884910f3baSmckusick default:
894910f3baSmckusick usage();
90fef234d6Smckusick }
914910f3baSmckusick }
924910f3baSmckusick argc -= optind;
934910f3baSmckusick argv += optind;
944910f3baSmckusick if (pflag) {
954910f3baSmckusick if ((protoid = getentry(protoname, quotatype)) == -1)
964910f3baSmckusick exit(1);
974910f3baSmckusick protoprivs = getprivs(protoid, quotatype);
984910f3baSmckusick for (qup = protoprivs; qup; qup = qup->next) {
994910f3baSmckusick qup->dqblk.dqb_btime = 0;
1004910f3baSmckusick qup->dqblk.dqb_itime = 0;
1014910f3baSmckusick }
102fef234d6Smckusick while (argc-- > 0) {
1034910f3baSmckusick if ((id = getentry(*argv++, quotatype)) < 0)
104fef234d6Smckusick continue;
1054910f3baSmckusick putprivs(id, quotatype, protoprivs);
106fef234d6Smckusick }
107fef234d6Smckusick exit(0);
108fef234d6Smckusick }
1094910f3baSmckusick tmpfd = mkstemp(tmpfil);
1104910f3baSmckusick fchown(tmpfd, getuid(), getgid());
1114910f3baSmckusick if (tflag) {
1124910f3baSmckusick protoprivs = getprivs(0, quotatype);
1134910f3baSmckusick if (writetimes(protoprivs, tmpfd, quotatype) == 0)
1144910f3baSmckusick exit(1);
1154910f3baSmckusick if (editit(tmpfil) && readtimes(protoprivs, tmpfd))
1164910f3baSmckusick putprivs(0, quotatype, protoprivs);
1174910f3baSmckusick freeprivs(protoprivs);
1184910f3baSmckusick exit(0);
119fef234d6Smckusick }
1204910f3baSmckusick for ( ; argc > 0; argc--, argv++) {
1214910f3baSmckusick if ((id = getentry(*argv, quotatype)) == -1)
1224910f3baSmckusick continue;
1234910f3baSmckusick curprivs = getprivs(id, quotatype);
1244910f3baSmckusick if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0)
1254910f3baSmckusick continue;
1264910f3baSmckusick if (editit(tmpfil) && readprivs(curprivs, tmpfd))
1274910f3baSmckusick putprivs(id, quotatype, curprivs);
1284910f3baSmckusick freeprivs(curprivs);
1294910f3baSmckusick }
1304910f3baSmckusick close(tmpfd);
131c7c65224Smckusick unlink(tmpfil);
132c7c65224Smckusick exit(0);
133c7c65224Smckusick }
134c7c65224Smckusick
usage()1354910f3baSmckusick usage()
1364910f3baSmckusick {
1374910f3baSmckusick fprintf(stderr, "%s%s%s%s",
1384910f3baSmckusick "Usage: edquota [-u] [-p username] username ...\n",
1394910f3baSmckusick "\tedquota -g [-p groupname] groupname ...\n",
1404910f3baSmckusick "\tedquota [-u] -t\n", "\tedquota -g -t\n");
1414910f3baSmckusick exit(1);
1424910f3baSmckusick }
1434910f3baSmckusick
1444910f3baSmckusick /*
1454910f3baSmckusick * This routine converts a name for a particular quota type to
1464910f3baSmckusick * an identifier. This routine must agree with the kernel routine
1474910f3baSmckusick * getinoquota as to the interpretation of quota types.
1484910f3baSmckusick */
getentry(name,quotatype)1494910f3baSmckusick getentry(name, quotatype)
150fef234d6Smckusick char *name;
1514910f3baSmckusick int quotatype;
152c7c65224Smckusick {
153fef234d6Smckusick struct passwd *pw;
1544910f3baSmckusick struct group *gr;
155c7c65224Smckusick
156c7c65224Smckusick if (alldigits(name))
1574910f3baSmckusick return (atoi(name));
1584910f3baSmckusick switch(quotatype) {
1594910f3baSmckusick case USRQUOTA:
1604910f3baSmckusick if (pw = getpwnam(name))
1614910f3baSmckusick return (pw->pw_uid);
162fef234d6Smckusick fprintf(stderr, "%s: no such user\n", name);
1634910f3baSmckusick break;
1644910f3baSmckusick case GRPQUOTA:
1654910f3baSmckusick if (gr = getgrnam(name))
1664910f3baSmckusick return (gr->gr_gid);
1674910f3baSmckusick fprintf(stderr, "%s: no such group\n", name);
1684910f3baSmckusick break;
1694910f3baSmckusick default:
1704910f3baSmckusick fprintf(stderr, "%d: unknown quota type\n", quotatype);
1714910f3baSmckusick break;
1724910f3baSmckusick }
173c7c65224Smckusick sleep(1);
174fef234d6Smckusick return (-1);
175c7c65224Smckusick }
1764910f3baSmckusick
1774910f3baSmckusick /*
1784910f3baSmckusick * Collect the requested quota information.
1794910f3baSmckusick */
1804910f3baSmckusick struct quotause *
getprivs(id,quotatype)1814910f3baSmckusick getprivs(id, quotatype)
1824910f3baSmckusick register long id;
1834910f3baSmckusick int quotatype;
1844910f3baSmckusick {
1854910f3baSmckusick register struct fstab *fs;
1864910f3baSmckusick register struct quotause *qup, *quptail;
1874910f3baSmckusick struct quotause *quphead;
18896bc10eeSmckusick int qcmd, qupsize, fd;
18996bc10eeSmckusick char *qfpathname;
1904910f3baSmckusick static int warned = 0;
1914910f3baSmckusick extern int errno;
1924910f3baSmckusick
1934910f3baSmckusick setfsent();
1944910f3baSmckusick quphead = (struct quotause *)0;
1954910f3baSmckusick qcmd = QCMD(Q_GETQUOTA, quotatype);
1964910f3baSmckusick while (fs = getfsent()) {
19796bc10eeSmckusick if (strcmp(fs->fs_vfstype, "ufs"))
1984910f3baSmckusick continue;
19996bc10eeSmckusick if (!hasquota(fs, quotatype, &qfpathname))
2004910f3baSmckusick continue;
20196bc10eeSmckusick qupsize = sizeof(*qup) + strlen(qfpathname);
20296bc10eeSmckusick if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
2034910f3baSmckusick fprintf(stderr, "edquota: out of memory\n");
2044910f3baSmckusick exit(2);
2054910f3baSmckusick }
20696bc10eeSmckusick if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
2074910f3baSmckusick if (errno == EOPNOTSUPP && !warned) {
2084910f3baSmckusick warned++;
2094910f3baSmckusick fprintf(stderr, "Warning: %s\n",
2104910f3baSmckusick "Quotas are not compiled into this kernel");
2114910f3baSmckusick sleep(3);
2124910f3baSmckusick }
21396bc10eeSmckusick if ((fd = open(qfpathname, O_RDONLY)) < 0) {
21496bc10eeSmckusick fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
21596bc10eeSmckusick if (fd < 0 && errno != ENOENT) {
21696bc10eeSmckusick perror(qfpathname);
21796bc10eeSmckusick free(qup);
21896bc10eeSmckusick continue;
21996bc10eeSmckusick }
22096bc10eeSmckusick fprintf(stderr, "Creating quota file %s\n",
22196bc10eeSmckusick qfpathname);
22296bc10eeSmckusick sleep(3);
22396bc10eeSmckusick (void) fchown(fd, getuid(),
22496bc10eeSmckusick getentry(quotagroup, GRPQUOTA));
22596bc10eeSmckusick (void) fchmod(fd, 0640);
22696bc10eeSmckusick }
227*af968038Sbostic lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
2284910f3baSmckusick switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
2294910f3baSmckusick case 0: /* EOF */
2304910f3baSmckusick /*
2314910f3baSmckusick * Convert implicit 0 quota (EOF)
2324910f3baSmckusick * into an explicit one (zero'ed dqblk)
2334910f3baSmckusick */
2344910f3baSmckusick bzero((caddr_t)&qup->dqblk,
2354910f3baSmckusick sizeof(struct dqblk));
2364910f3baSmckusick break;
2374910f3baSmckusick
2384910f3baSmckusick case sizeof(struct dqblk): /* OK */
2394910f3baSmckusick break;
2404910f3baSmckusick
2414910f3baSmckusick default: /* ERROR */
2424910f3baSmckusick fprintf(stderr, "edquota: read error in ");
24396bc10eeSmckusick perror(qfpathname);
2444910f3baSmckusick close(fd);
2454910f3baSmckusick free(qup);
2464910f3baSmckusick continue;
2474910f3baSmckusick }
2484910f3baSmckusick close(fd);
24996bc10eeSmckusick }
25096bc10eeSmckusick strcpy(qup->qfname, qfpathname);
2514910f3baSmckusick strcpy(qup->fsname, fs->fs_file);
2524910f3baSmckusick if (quphead == NULL)
2534910f3baSmckusick quphead = qup;
2544910f3baSmckusick else
2554910f3baSmckusick quptail->next = qup;
2564910f3baSmckusick quptail = qup;
2574910f3baSmckusick qup->next = 0;
2584910f3baSmckusick }
2594910f3baSmckusick endfsent();
2604910f3baSmckusick return (quphead);
261c7c65224Smckusick }
262c7c65224Smckusick
2634910f3baSmckusick /*
2644910f3baSmckusick * Store the requested quota information.
2654910f3baSmckusick */
putprivs(id,quotatype,quplist)2664910f3baSmckusick putprivs(id, quotatype, quplist)
2674910f3baSmckusick long id;
2684910f3baSmckusick int quotatype;
2694910f3baSmckusick struct quotause *quplist;
270c7c65224Smckusick {
2714910f3baSmckusick register struct quotause *qup;
2724910f3baSmckusick int qcmd, fd;
2734910f3baSmckusick
2744910f3baSmckusick qcmd = QCMD(Q_SETQUOTA, quotatype);
2754910f3baSmckusick for (qup = quplist; qup; qup = qup->next) {
27696bc10eeSmckusick if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0)
2774910f3baSmckusick continue;
27896bc10eeSmckusick if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
27996bc10eeSmckusick perror(qup->qfname);
2804910f3baSmckusick } else {
281*af968038Sbostic lseek(fd,
282*af968038Sbostic (off_t)(id * (long)sizeof (struct dqblk)), L_SET);
2834910f3baSmckusick if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
2844910f3baSmckusick sizeof (struct dqblk)) {
2854910f3baSmckusick fprintf(stderr, "edquota: ");
28696bc10eeSmckusick perror(qup->qfname);
2874910f3baSmckusick }
2884910f3baSmckusick close(fd);
2894910f3baSmckusick }
2904910f3baSmckusick }
2914910f3baSmckusick }
2924910f3baSmckusick
2934910f3baSmckusick /*
2944910f3baSmckusick * Take a list of priviledges and get it edited.
2954910f3baSmckusick */
editit(tmpfile)2964910f3baSmckusick editit(tmpfile)
2974910f3baSmckusick char *tmpfile;
2984910f3baSmckusick {
2991450dbd6Sbostic long omask;
3004910f3baSmckusick int pid, stat;
3014910f3baSmckusick extern char *getenv();
302c7c65224Smckusick
3031450dbd6Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
304c7c65224Smckusick top:
305c7c65224Smckusick if ((pid = fork()) < 0) {
306c7c65224Smckusick extern errno;
307c7c65224Smckusick
308c7c65224Smckusick if (errno == EPROCLIM) {
309c7c65224Smckusick fprintf(stderr, "You have too many processes\n");
310c7c65224Smckusick return(0);
311c7c65224Smckusick }
312c7c65224Smckusick if (errno == EAGAIN) {
313c7c65224Smckusick sleep(1);
314c7c65224Smckusick goto top;
315c7c65224Smckusick }
316c7c65224Smckusick perror("fork");
317c7c65224Smckusick return (0);
318c7c65224Smckusick }
319c7c65224Smckusick if (pid == 0) {
320c7c65224Smckusick register char *ed;
321c7c65224Smckusick
322984394e1Ssam sigsetmask(omask);
323c7c65224Smckusick setgid(getgid());
324c7c65224Smckusick setuid(getuid());
325c7c65224Smckusick if ((ed = getenv("EDITOR")) == (char *)0)
326c49caeabSbostic ed = _PATH_VI;
3274910f3baSmckusick execlp(ed, ed, tmpfile, 0);
328c7c65224Smckusick perror(ed);
329c7c65224Smckusick exit(1);
330c7c65224Smckusick }
3314910f3baSmckusick waitpid(pid, &stat, 0);
332984394e1Ssam sigsetmask(omask);
3334910f3baSmckusick if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
3344910f3baSmckusick return (0);
3354910f3baSmckusick return (1);
336c7c65224Smckusick }
337c7c65224Smckusick
3384910f3baSmckusick /*
3394910f3baSmckusick * Convert a quotause list to an ASCII file.
3404910f3baSmckusick */
3414910f3baSmckusick writeprivs(quplist, outfd, name, quotatype)
3424910f3baSmckusick struct quotause *quplist;
3434910f3baSmckusick int outfd;
3444910f3baSmckusick char *name;
3454910f3baSmckusick int quotatype;
346c7c65224Smckusick {
3474910f3baSmckusick register struct quotause *qup;
348c7c65224Smckusick FILE *fd;
349c7c65224Smckusick
350cb64a7e0Smckusick ftruncate(outfd, 0);
3514910f3baSmckusick lseek(outfd, 0, L_SET);
3524910f3baSmckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) {
353c7c65224Smckusick fprintf(stderr, "edquota: ");
354c7c65224Smckusick perror(tmpfil);
355c7c65224Smckusick exit(1);
356c7c65224Smckusick }
3574910f3baSmckusick fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
3584910f3baSmckusick for (qup = quplist; qup; qup = qup->next) {
3594910f3baSmckusick fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n",
3604910f3baSmckusick qup->fsname, "blocks in use:",
3614910f3baSmckusick dbtob(qup->dqblk.dqb_curblocks) / 1024,
3624910f3baSmckusick dbtob(qup->dqblk.dqb_bsoftlimit) / 1024,
3634910f3baSmckusick dbtob(qup->dqblk.dqb_bhardlimit) / 1024);
3644910f3baSmckusick fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n",
3654910f3baSmckusick "\tinodes in use:", qup->dqblk.dqb_curinodes,
3664910f3baSmckusick qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
367c7c65224Smckusick }
368c7c65224Smckusick fclose(fd);
3694910f3baSmckusick return (1);
370c7c65224Smckusick }
371c7c65224Smckusick
3724910f3baSmckusick /*
3734910f3baSmckusick * Merge changes to an ASCII file into a quotause list.
3744910f3baSmckusick */
3754910f3baSmckusick readprivs(quplist, infd)
3764910f3baSmckusick struct quotause *quplist;
3774910f3baSmckusick int infd;
378c7c65224Smckusick {
3794910f3baSmckusick register struct quotause *qup;
380c7c65224Smckusick FILE *fd;
3814910f3baSmckusick int cnt;
3824910f3baSmckusick register char *cp;
3834910f3baSmckusick struct dqblk dqblk;
3844910f3baSmckusick char *fsp, line1[BUFSIZ], line2[BUFSIZ];
385c7c65224Smckusick
3864910f3baSmckusick lseek(infd, 0, L_SET);
3874910f3baSmckusick fd = fdopen(dup(infd), "r");
388c7c65224Smckusick if (fd == NULL) {
389c7c65224Smckusick fprintf(stderr, "Can't re-read temp file!!\n");
3904910f3baSmckusick return (0);
391c7c65224Smckusick }
3924910f3baSmckusick /*
3934910f3baSmckusick * Discard title line, then read pairs of lines to process.
3944910f3baSmckusick */
3954910f3baSmckusick (void) fgets(line1, sizeof (line1), fd);
3964910f3baSmckusick while (fgets(line1, sizeof (line1), fd) != NULL &&
3974910f3baSmckusick fgets(line2, sizeof (line2), fd) != NULL) {
3984910f3baSmckusick if ((fsp = strtok(line1, " \t:")) == NULL) {
3994910f3baSmckusick fprintf(stderr, "%s: bad format\n", line1);
4004910f3baSmckusick return (0);
4014910f3baSmckusick }
4024910f3baSmckusick if ((cp = strtok((char *)0, "\n")) == NULL) {
4034910f3baSmckusick fprintf(stderr, "%s: %s: bad format\n", fsp,
4044910f3baSmckusick &fsp[strlen(fsp) + 1]);
4054910f3baSmckusick return (0);
4064910f3baSmckusick }
4074910f3baSmckusick cnt = sscanf(cp,
4084910f3baSmckusick " blocks in use: %d, limits (soft = %d, hard = %d)",
4094910f3baSmckusick &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
4104910f3baSmckusick &dqblk.dqb_bhardlimit);
4114910f3baSmckusick if (cnt != 3) {
4124910f3baSmckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
4134910f3baSmckusick return (0);
4144910f3baSmckusick }
4154910f3baSmckusick dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024);
4164910f3baSmckusick dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024);
4174910f3baSmckusick dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024);
4184910f3baSmckusick if ((cp = strtok(line2, "\n")) == NULL) {
4194910f3baSmckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
4204910f3baSmckusick return (0);
4214910f3baSmckusick }
4224910f3baSmckusick cnt = sscanf(cp,
4234910f3baSmckusick "\tinodes in use: %d, limits (soft = %d, hard = %d)",
4244910f3baSmckusick &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
4254910f3baSmckusick &dqblk.dqb_ihardlimit);
4264910f3baSmckusick if (cnt != 3) {
4274910f3baSmckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
4284910f3baSmckusick return (0);
4294910f3baSmckusick }
4304910f3baSmckusick for (qup = quplist; qup; qup = qup->next) {
4314910f3baSmckusick if (strcmp(fsp, qup->fsname))
432361e7e32Smckusick continue;
4334910f3baSmckusick /*
4344910f3baSmckusick * Cause time limit to be reset when the quota
4354910f3baSmckusick * is next used if previously had no soft limit
4364910f3baSmckusick * or were under it, but now have a soft limit
4374910f3baSmckusick * and are over it.
4384910f3baSmckusick */
4394910f3baSmckusick if (dqblk.dqb_bsoftlimit &&
4404910f3baSmckusick qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit &&
4414910f3baSmckusick (qup->dqblk.dqb_bsoftlimit == 0 ||
4424910f3baSmckusick qup->dqblk.dqb_curblocks <
4434910f3baSmckusick qup->dqblk.dqb_bsoftlimit))
4444910f3baSmckusick qup->dqblk.dqb_btime = 0;
4454910f3baSmckusick if (dqblk.dqb_isoftlimit &&
4464910f3baSmckusick qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit &&
4474910f3baSmckusick (qup->dqblk.dqb_isoftlimit == 0 ||
4484910f3baSmckusick qup->dqblk.dqb_curinodes <
4494910f3baSmckusick qup->dqblk.dqb_isoftlimit))
4504910f3baSmckusick qup->dqblk.dqb_itime = 0;
4514910f3baSmckusick qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
4524910f3baSmckusick qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
4534910f3baSmckusick qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
4544910f3baSmckusick qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
4554910f3baSmckusick qup->flags |= FOUND;
4564910f3baSmckusick if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
4574910f3baSmckusick dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
4584910f3baSmckusick break;
4594910f3baSmckusick fprintf(stderr,
4604910f3baSmckusick "%s: cannot change current allocation\n", fsp);
4614910f3baSmckusick break;
462361e7e32Smckusick }
463c7c65224Smckusick }
464c7c65224Smckusick fclose(fd);
4654910f3baSmckusick /*
4664910f3baSmckusick * Disable quotas for any filesystems that have not been found.
4674910f3baSmckusick */
4684910f3baSmckusick for (qup = quplist; qup; qup = qup->next) {
4694910f3baSmckusick if (qup->flags & FOUND) {
4704910f3baSmckusick qup->flags &= ~FOUND;
471c7c65224Smckusick continue;
472c7c65224Smckusick }
4734910f3baSmckusick qup->dqblk.dqb_bsoftlimit = 0;
4744910f3baSmckusick qup->dqblk.dqb_bhardlimit = 0;
4754910f3baSmckusick qup->dqblk.dqb_isoftlimit = 0;
4764910f3baSmckusick qup->dqblk.dqb_ihardlimit = 0;
477c7c65224Smckusick }
4784910f3baSmckusick return (1);
479c7c65224Smckusick }
480c7c65224Smckusick
4814910f3baSmckusick /*
4824910f3baSmckusick * Convert a quotause list to an ASCII file of grace times.
4834910f3baSmckusick */
4844910f3baSmckusick writetimes(quplist, outfd, quotatype)
4854910f3baSmckusick struct quotause *quplist;
4864910f3baSmckusick int outfd;
4874910f3baSmckusick int quotatype;
488c7c65224Smckusick {
4894910f3baSmckusick register struct quotause *qup;
4904910f3baSmckusick char *cvtstoa();
4914910f3baSmckusick FILE *fd;
492c7c65224Smckusick
493cb64a7e0Smckusick ftruncate(outfd, 0);
4944910f3baSmckusick lseek(outfd, 0, L_SET);
4954910f3baSmckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) {
4964910f3baSmckusick fprintf(stderr, "edquota: ");
4974910f3baSmckusick perror(tmpfil);
4984910f3baSmckusick exit(1);
499c7c65224Smckusick }
5004910f3baSmckusick fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n");
5014910f3baSmckusick fprintf(fd, "Grace period before enforcing soft limits for %ss:\n",
5024910f3baSmckusick qfextension[quotatype]);
5034910f3baSmckusick for (qup = quplist; qup; qup = qup->next) {
5044910f3baSmckusick fprintf(fd, "%s: block grace period: %s, ",
5054910f3baSmckusick qup->fsname, cvtstoa(qup->dqblk.dqb_btime));
5064910f3baSmckusick fprintf(fd, "file grace period: %s\n",
5074910f3baSmckusick cvtstoa(qup->dqblk.dqb_itime));
5084910f3baSmckusick }
5094910f3baSmckusick fclose(fd);
5104910f3baSmckusick return (1);
511c7c65224Smckusick }
512c7c65224Smckusick
5134910f3baSmckusick /*
5144910f3baSmckusick * Merge changes of grace times in an ASCII file into a quotause list.
5154910f3baSmckusick */
5164910f3baSmckusick readtimes(quplist, infd)
5174910f3baSmckusick struct quotause *quplist;
5184910f3baSmckusick int infd;
5194910f3baSmckusick {
5204910f3baSmckusick register struct quotause *qup;
5214910f3baSmckusick FILE *fd;
5224910f3baSmckusick int cnt;
5234910f3baSmckusick register char *cp;
5244910f3baSmckusick time_t itime, btime, iseconds, bseconds;
5254910f3baSmckusick char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
5264910f3baSmckusick
5274910f3baSmckusick lseek(infd, 0, L_SET);
5284910f3baSmckusick fd = fdopen(dup(infd), "r");
5294910f3baSmckusick if (fd == NULL) {
5304910f3baSmckusick fprintf(stderr, "Can't re-read temp file!!\n");
5314910f3baSmckusick return (0);
5324910f3baSmckusick }
5334910f3baSmckusick /*
5344910f3baSmckusick * Discard two title lines, then read lines to process.
5354910f3baSmckusick */
5364910f3baSmckusick (void) fgets(line1, sizeof (line1), fd);
5374910f3baSmckusick (void) fgets(line1, sizeof (line1), fd);
5384910f3baSmckusick while (fgets(line1, sizeof (line1), fd) != NULL) {
5394910f3baSmckusick if ((fsp = strtok(line1, " \t:")) == NULL) {
5404910f3baSmckusick fprintf(stderr, "%s: bad format\n", line1);
5414910f3baSmckusick return (0);
5424910f3baSmckusick }
5434910f3baSmckusick if ((cp = strtok((char *)0, "\n")) == NULL) {
5444910f3baSmckusick fprintf(stderr, "%s: %s: bad format\n", fsp,
5454910f3baSmckusick &fsp[strlen(fsp) + 1]);
5464910f3baSmckusick return (0);
5474910f3baSmckusick }
5484910f3baSmckusick cnt = sscanf(cp,
5494910f3baSmckusick " block grace period: %d %s file grace period: %d %s",
5504910f3baSmckusick &btime, bunits, &itime, iunits);
5514910f3baSmckusick if (cnt != 4) {
5524910f3baSmckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
5534910f3baSmckusick return (0);
5544910f3baSmckusick }
5554910f3baSmckusick if (cvtatos(btime, bunits, &bseconds) == 0)
5564910f3baSmckusick return (0);
5574910f3baSmckusick if (cvtatos(itime, iunits, &iseconds) == 0)
5584910f3baSmckusick return (0);
5594910f3baSmckusick for (qup = quplist; qup; qup = qup->next) {
5604910f3baSmckusick if (strcmp(fsp, qup->fsname))
5614910f3baSmckusick continue;
5624910f3baSmckusick qup->dqblk.dqb_btime = bseconds;
5634910f3baSmckusick qup->dqblk.dqb_itime = iseconds;
5644910f3baSmckusick qup->flags |= FOUND;
5654910f3baSmckusick break;
5664910f3baSmckusick }
5674910f3baSmckusick }
5684910f3baSmckusick fclose(fd);
5694910f3baSmckusick /*
5704910f3baSmckusick * reset default grace periods for any filesystems
5714910f3baSmckusick * that have not been found.
5724910f3baSmckusick */
5734910f3baSmckusick for (qup = quplist; qup; qup = qup->next) {
5744910f3baSmckusick if (qup->flags & FOUND) {
5754910f3baSmckusick qup->flags &= ~FOUND;
5764910f3baSmckusick continue;
5774910f3baSmckusick }
5784910f3baSmckusick qup->dqblk.dqb_btime = 0;
5794910f3baSmckusick qup->dqblk.dqb_itime = 0;
5804910f3baSmckusick }
5814910f3baSmckusick return (1);
5824910f3baSmckusick }
5834910f3baSmckusick
5844910f3baSmckusick /*
5854910f3baSmckusick * Convert seconds to ASCII times.
5864910f3baSmckusick */
5874910f3baSmckusick char *
cvtstoa(time)5884910f3baSmckusick cvtstoa(time)
5894910f3baSmckusick time_t time;
5904910f3baSmckusick {
5914910f3baSmckusick static char buf[20];
5924910f3baSmckusick
5934910f3baSmckusick if (time % (24 * 60 * 60) == 0) {
5944910f3baSmckusick time /= 24 * 60 * 60;
5954910f3baSmckusick sprintf(buf, "%d day%s", time, time == 1 ? "" : "s");
5964910f3baSmckusick } else if (time % (60 * 60) == 0) {
5974910f3baSmckusick time /= 60 * 60;
5984910f3baSmckusick sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s");
5994910f3baSmckusick } else if (time % 60 == 0) {
6004910f3baSmckusick time /= 60;
6014910f3baSmckusick sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s");
6024910f3baSmckusick } else
6034910f3baSmckusick sprintf(buf, "%d second%s", time, time == 1 ? "" : "s");
6044910f3baSmckusick return (buf);
6054910f3baSmckusick }
6064910f3baSmckusick
6074910f3baSmckusick /*
6084910f3baSmckusick * Convert ASCII input times to seconds.
6094910f3baSmckusick */
cvtatos(time,units,seconds)6104910f3baSmckusick cvtatos(time, units, seconds)
6114910f3baSmckusick time_t time;
6124910f3baSmckusick char *units;
6134910f3baSmckusick time_t *seconds;
6144910f3baSmckusick {
6154910f3baSmckusick
6164910f3baSmckusick if (bcmp(units, "second", 6) == 0)
6174910f3baSmckusick *seconds = time;
6184910f3baSmckusick else if (bcmp(units, "minute", 6) == 0)
6194910f3baSmckusick *seconds = time * 60;
6204910f3baSmckusick else if (bcmp(units, "hour", 4) == 0)
6214910f3baSmckusick *seconds = time * 60 * 60;
6224910f3baSmckusick else if (bcmp(units, "day", 3) == 0)
6234910f3baSmckusick *seconds = time * 24 * 60 * 60;
6244910f3baSmckusick else {
6254910f3baSmckusick printf("%s: bad units, specify %s\n", units,
6264910f3baSmckusick "days, hours, minutes, or seconds");
6274910f3baSmckusick return (0);
6284910f3baSmckusick }
6294910f3baSmckusick return (1);
6304910f3baSmckusick }
6314910f3baSmckusick
6324910f3baSmckusick /*
6334910f3baSmckusick * Free a list of quotause structures.
6344910f3baSmckusick */
6354910f3baSmckusick freeprivs(quplist)
6364910f3baSmckusick struct quotause *quplist;
6374910f3baSmckusick {
6384910f3baSmckusick register struct quotause *qup, *nextqup;
6394910f3baSmckusick
6404910f3baSmckusick for (qup = quplist; qup; qup = nextqup) {
6414910f3baSmckusick nextqup = qup->next;
6424910f3baSmckusick free(qup);
6434910f3baSmckusick }
6444910f3baSmckusick }
6454910f3baSmckusick
6464910f3baSmckusick /*
6474910f3baSmckusick * Check whether a string is completely composed of digits.
6484910f3baSmckusick */
alldigits(s)649c7c65224Smckusick alldigits(s)
650c7c65224Smckusick register char *s;
651c7c65224Smckusick {
652c7c65224Smckusick register c;
653c7c65224Smckusick
654c7c65224Smckusick c = *s++;
655c7c65224Smckusick do {
656c7c65224Smckusick if (!isdigit(c))
657c7c65224Smckusick return (0);
658c7c65224Smckusick } while (c = *s++);
659c7c65224Smckusick return (1);
660c7c65224Smckusick }
661c7c65224Smckusick
6623dcd4551Sserge /*
6634910f3baSmckusick * Check to see if a particular quota is to be enabled.
6643dcd4551Sserge */
hasquota(fs,type,qfnamep)66596bc10eeSmckusick hasquota(fs, type, qfnamep)
66696bc10eeSmckusick register struct fstab *fs;
6674910f3baSmckusick int type;
66896bc10eeSmckusick char **qfnamep;
669c7c65224Smckusick {
6704910f3baSmckusick register char *opt;
67196bc10eeSmckusick char *cp, *index(), *strtok();
6724910f3baSmckusick static char initname, usrname[100], grpname[100];
67396bc10eeSmckusick static char buf[BUFSIZ];
674c7c65224Smckusick
6754910f3baSmckusick if (!initname) {
6764910f3baSmckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
6774910f3baSmckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
6784910f3baSmckusick initname = 1;
679361e7e32Smckusick }
68096bc10eeSmckusick strcpy(buf, fs->fs_mntops);
6814910f3baSmckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
68296bc10eeSmckusick if (cp = index(opt, '='))
68396bc10eeSmckusick *cp++ = '\0';
6844910f3baSmckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0)
68596bc10eeSmckusick break;
6864910f3baSmckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
68796bc10eeSmckusick break;
68896bc10eeSmckusick }
68996bc10eeSmckusick if (!opt)
69096bc10eeSmckusick return (0);
69196bc10eeSmckusick if (cp) {
69296bc10eeSmckusick *qfnamep = cp;
6934910f3baSmckusick return (1);
694c7c65224Smckusick }
69596bc10eeSmckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
69696bc10eeSmckusick *qfnamep = buf;
69796bc10eeSmckusick return (1);
698c7c65224Smckusick }
699