xref: /csrg-svn/usr.sbin/edquota/edquota.c (revision 60135)
121516Smckusick /*
241408Smckusick  * Copyright (c) 1980, 1990 Regents of the University of California.
334362Sbostic  * 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
1221516Smckusick char copyright[] =
1341408Smckusick "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\
1421516Smckusick  All rights reserved.\n";
1534362Sbostic #endif /* not lint */
1612707Smckusick 
1721516Smckusick #ifndef lint
18*60135Sbostic static char sccsid[] = "@(#)edquota.c	5.17 (Berkeley) 05/19/93";
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>
2851630Sbostic #include <ufs/ufs/quota.h>
2912707Smckusick #include <errno.h>
3036964Sbostic #include <fstab.h>
3112707Smckusick #include <pwd.h>
3241408Smckusick #include <grp.h>
3312707Smckusick #include <ctype.h>
3436964Sbostic #include <stdio.h>
3541408Smckusick #include <string.h>
36*60135Sbostic #include <unistd.h>
3737267Sbostic #include "pathnames.h"
3812707Smckusick 
3945255Smckusick char *qfname = QUOTAFILENAME;
4045255Smckusick char *qfextension[] = INITQFNAMES;
4145255Smckusick char *quotagroup = QUOTAGROUP;
4241408Smckusick char tmpfil[] = _PATH_TMP;
4312707Smckusick 
4441408Smckusick struct quotause {
4541408Smckusick 	struct	quotause *next;
4641408Smckusick 	long	flags;
4741408Smckusick 	struct	dqblk dqblk;
4841408Smckusick 	char	fsname[MAXPATHLEN + 1];
4941444Smckusick 	char	qfname[1];	/* actually longer */
5041408Smckusick } *getprivs();
5141408Smckusick #define	FOUND	0x01
5212707Smckusick 
5312707Smckusick main(argc, argv)
5441408Smckusick 	register char **argv;
5541408Smckusick 	int argc;
5612707Smckusick {
5741408Smckusick 	register struct quotause *qup, *protoprivs, *curprivs;
5841408Smckusick 	extern char *optarg;
5941408Smckusick 	extern int optind;
6041408Smckusick 	register long id, protoid;
6141408Smckusick 	register int quotatype, tmpfd;
6241408Smckusick 	char *protoname, ch;
6341408Smckusick 	int tflag = 0, pflag = 0;
6412707Smckusick 
6541408Smckusick 	if (argc < 2)
6641408Smckusick 		usage();
6712707Smckusick 	if (getuid()) {
6841408Smckusick 		fprintf(stderr, "edquota: permission denied\n");
6912707Smckusick 		exit(1);
7012707Smckusick 	}
7141408Smckusick 	quotatype = USRQUOTA;
7241408Smckusick 	while ((ch = getopt(argc, argv, "ugtp:")) != EOF) {
7341408Smckusick 		switch(ch) {
7441408Smckusick 		case 'p':
7541408Smckusick 			protoname = optarg;
7641408Smckusick 			pflag++;
7741408Smckusick 			break;
7841408Smckusick 		case 'g':
7941408Smckusick 			quotatype = GRPQUOTA;
8041408Smckusick 			break;
8141408Smckusick 		case 'u':
8241408Smckusick 			quotatype = USRQUOTA;
8341408Smckusick 			break;
8441408Smckusick 		case 't':
8541408Smckusick 			tflag++;
8641408Smckusick 			break;
8741408Smckusick 		default:
8841408Smckusick 			usage();
8941408Smckusick 		}
9041408Smckusick 	}
9141408Smckusick 	argc -= optind;
9241408Smckusick 	argv += optind;
9341408Smckusick 	if (pflag) {
9441408Smckusick 		if ((protoid = getentry(protoname, quotatype)) == -1)
9512803Smckusick 			exit(1);
9641408Smckusick 		protoprivs = getprivs(protoid, quotatype);
9741408Smckusick 		for (qup = protoprivs; qup; qup = qup->next) {
9841408Smckusick 			qup->dqblk.dqb_btime = 0;
9941408Smckusick 			qup->dqblk.dqb_itime = 0;
10012803Smckusick 		}
10112803Smckusick 		while (argc-- > 0) {
10241408Smckusick 			if ((id = getentry(*argv++, quotatype)) < 0)
10312803Smckusick 				continue;
10441408Smckusick 			putprivs(id, quotatype, protoprivs);
10512803Smckusick 		}
10612803Smckusick 		exit(0);
10712803Smckusick 	}
10841408Smckusick 	tmpfd = mkstemp(tmpfil);
10941408Smckusick 	fchown(tmpfd, getuid(), getgid());
11041408Smckusick 	if (tflag) {
11141408Smckusick 		protoprivs = getprivs(0, quotatype);
11241408Smckusick 		if (writetimes(protoprivs, tmpfd, quotatype) == 0)
11341408Smckusick 			exit(1);
11441408Smckusick 		if (editit(tmpfil) && readtimes(protoprivs, tmpfd))
11541408Smckusick 			putprivs(0, quotatype, protoprivs);
11641408Smckusick 		freeprivs(protoprivs);
11741408Smckusick 		exit(0);
11841408Smckusick 	}
11941408Smckusick 	for ( ; argc > 0; argc--, argv++) {
12041408Smckusick 		if ((id = getentry(*argv, quotatype)) == -1)
12112803Smckusick 			continue;
12241408Smckusick 		curprivs = getprivs(id, quotatype);
12341408Smckusick 		if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0)
12441408Smckusick 			continue;
12541408Smckusick 		if (editit(tmpfil) && readprivs(curprivs, tmpfd))
12641408Smckusick 			putprivs(id, quotatype, curprivs);
12741408Smckusick 		freeprivs(curprivs);
12812803Smckusick 	}
12941408Smckusick 	close(tmpfd);
13012707Smckusick 	unlink(tmpfil);
13112707Smckusick 	exit(0);
13212707Smckusick }
13312707Smckusick 
13441408Smckusick usage()
13541408Smckusick {
13641408Smckusick 	fprintf(stderr, "%s%s%s%s",
13741408Smckusick 		"Usage: edquota [-u] [-p username] username ...\n",
13841408Smckusick 		"\tedquota -g [-p groupname] groupname ...\n",
13941408Smckusick 		"\tedquota [-u] -t\n", "\tedquota -g -t\n");
14041408Smckusick 	exit(1);
14141408Smckusick }
14241408Smckusick 
14341408Smckusick /*
14441408Smckusick  * This routine converts a name for a particular quota type to
14541408Smckusick  * an identifier. This routine must agree with the kernel routine
14641408Smckusick  * getinoquota as to the interpretation of quota types.
14741408Smckusick  */
14841408Smckusick getentry(name, quotatype)
14912803Smckusick 	char *name;
15041408Smckusick 	int quotatype;
15112707Smckusick {
15212803Smckusick 	struct passwd *pw;
15341408Smckusick 	struct group *gr;
15412707Smckusick 
15512707Smckusick 	if (alldigits(name))
15641408Smckusick 		return (atoi(name));
15741408Smckusick 	switch(quotatype) {
15841408Smckusick 	case USRQUOTA:
15941408Smckusick 		if (pw = getpwnam(name))
16041408Smckusick 			return (pw->pw_uid);
16112803Smckusick 		fprintf(stderr, "%s: no such user\n", name);
16241408Smckusick 		break;
16341408Smckusick 	case GRPQUOTA:
16441408Smckusick 		if (gr = getgrnam(name))
16541408Smckusick 			return (gr->gr_gid);
16641408Smckusick 		fprintf(stderr, "%s: no such group\n", name);
16741408Smckusick 		break;
16841408Smckusick 	default:
16941408Smckusick 		fprintf(stderr, "%d: unknown quota type\n", quotatype);
17041408Smckusick 		break;
17112707Smckusick 	}
17241408Smckusick 	sleep(1);
17341408Smckusick 	return (-1);
17412707Smckusick }
17512707Smckusick 
17641408Smckusick /*
17741408Smckusick  * Collect the requested quota information.
17841408Smckusick  */
17941408Smckusick struct quotause *
18041408Smckusick getprivs(id, quotatype)
18141408Smckusick 	register long id;
18241408Smckusick 	int quotatype;
18312707Smckusick {
18441408Smckusick 	register struct fstab *fs;
18541408Smckusick 	register struct quotause *qup, *quptail;
18641408Smckusick 	struct quotause *quphead;
18741444Smckusick 	int qcmd, qupsize, fd;
18841444Smckusick 	char *qfpathname;
18941408Smckusick 	static int warned = 0;
19041408Smckusick 	extern int errno;
19141408Smckusick 
19241408Smckusick 	setfsent();
19341408Smckusick 	quphead = (struct quotause *)0;
19441408Smckusick 	qcmd = QCMD(Q_GETQUOTA, quotatype);
19541408Smckusick 	while (fs = getfsent()) {
19641444Smckusick 		if (strcmp(fs->fs_vfstype, "ufs"))
19741408Smckusick 			continue;
19841444Smckusick 		if (!hasquota(fs, quotatype, &qfpathname))
19941408Smckusick 			continue;
20041444Smckusick 		qupsize = sizeof(*qup) + strlen(qfpathname);
20141444Smckusick 		if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
20241408Smckusick 			fprintf(stderr, "edquota: out of memory\n");
20341408Smckusick 			exit(2);
20441408Smckusick 		}
20541444Smckusick 		if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
20641408Smckusick 	    		if (errno == EOPNOTSUPP && !warned) {
20741408Smckusick 				warned++;
20841408Smckusick 				fprintf(stderr, "Warning: %s\n",
20941408Smckusick 				    "Quotas are not compiled into this kernel");
21041408Smckusick 				sleep(3);
21141408Smckusick 			}
21241444Smckusick 			if ((fd = open(qfpathname, O_RDONLY)) < 0) {
21341444Smckusick 				fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
21441444Smckusick 				if (fd < 0 && errno != ENOENT) {
21541444Smckusick 					perror(qfpathname);
21641444Smckusick 					free(qup);
21741444Smckusick 					continue;
21841444Smckusick 				}
21941444Smckusick 				fprintf(stderr, "Creating quota file %s\n",
22041444Smckusick 				    qfpathname);
22141444Smckusick 				sleep(3);
22241444Smckusick 				(void) fchown(fd, getuid(),
22341444Smckusick 				    getentry(quotagroup, GRPQUOTA));
22441444Smckusick 				(void) fchmod(fd, 0640);
22541444Smckusick 			}
22641408Smckusick 			lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
22741408Smckusick 			switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
22841408Smckusick 			case 0:			/* EOF */
22941408Smckusick 				/*
23041408Smckusick 				 * Convert implicit 0 quota (EOF)
23141408Smckusick 				 * into an explicit one (zero'ed dqblk)
23241408Smckusick 				 */
23341408Smckusick 				bzero((caddr_t)&qup->dqblk,
23441408Smckusick 				    sizeof(struct dqblk));
23541408Smckusick 				break;
23641408Smckusick 
23741408Smckusick 			case sizeof(struct dqblk):	/* OK */
23841408Smckusick 				break;
23941408Smckusick 
24041408Smckusick 			default:		/* ERROR */
24141408Smckusick 				fprintf(stderr, "edquota: read error in ");
24241444Smckusick 				perror(qfpathname);
24341408Smckusick 				close(fd);
24441408Smckusick 				free(qup);
24541408Smckusick 				continue;
24641408Smckusick 			}
24741444Smckusick 			close(fd);
24841408Smckusick 		}
24941444Smckusick 		strcpy(qup->qfname, qfpathname);
25041408Smckusick 		strcpy(qup->fsname, fs->fs_file);
25141408Smckusick 		if (quphead == NULL)
25241408Smckusick 			quphead = qup;
25341408Smckusick 		else
25441408Smckusick 			quptail->next = qup;
25541408Smckusick 		quptail = qup;
25641408Smckusick 		qup->next = 0;
25741408Smckusick 	}
25841408Smckusick 	endfsent();
25941408Smckusick 	return (quphead);
26041408Smckusick }
26141408Smckusick 
26241408Smckusick /*
26341408Smckusick  * Store the requested quota information.
26441408Smckusick  */
26541408Smckusick putprivs(id, quotatype, quplist)
26641408Smckusick 	long id;
26741408Smckusick 	int quotatype;
26841408Smckusick 	struct quotause *quplist;
26941408Smckusick {
27041408Smckusick 	register struct quotause *qup;
27141408Smckusick 	int qcmd, fd;
27241408Smckusick 
27341408Smckusick 	qcmd = QCMD(Q_SETQUOTA, quotatype);
27441408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
27541444Smckusick 		if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0)
27641408Smckusick 			continue;
27741444Smckusick 		if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
27841444Smckusick 			perror(qup->qfname);
27941408Smckusick 		} else {
28041408Smckusick 			lseek(fd, (long)id * (long)sizeof (struct dqblk), 0);
28141408Smckusick 			if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
28241408Smckusick 			    sizeof (struct dqblk)) {
28341408Smckusick 				fprintf(stderr, "edquota: ");
28441444Smckusick 				perror(qup->qfname);
28541408Smckusick 			}
28641408Smckusick 			close(fd);
28741408Smckusick 		}
28841408Smckusick 	}
28941408Smckusick }
29041408Smckusick 
29141408Smckusick /*
29241408Smckusick  * Take a list of priviledges and get it edited.
29341408Smckusick  */
29441408Smckusick editit(tmpfile)
29541408Smckusick 	char *tmpfile;
29641408Smckusick {
29733609Sbostic 	long omask;
29841408Smckusick 	int pid, stat;
29941408Smckusick 	extern char *getenv();
30012707Smckusick 
30133609Sbostic 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
30212707Smckusick  top:
30312707Smckusick 	if ((pid = fork()) < 0) {
30412707Smckusick 		extern errno;
30512707Smckusick 
30612707Smckusick 		if (errno == EPROCLIM) {
30712707Smckusick 			fprintf(stderr, "You have too many processes\n");
30812707Smckusick 			return(0);
30912707Smckusick 		}
31012707Smckusick 		if (errno == EAGAIN) {
31112707Smckusick 			sleep(1);
31212707Smckusick 			goto top;
31312707Smckusick 		}
31412707Smckusick 		perror("fork");
31512707Smckusick 		return (0);
31612707Smckusick 	}
31712707Smckusick 	if (pid == 0) {
31812707Smckusick 		register char *ed;
31912707Smckusick 
32013025Ssam 		sigsetmask(omask);
32112707Smckusick 		setgid(getgid());
32212707Smckusick 		setuid(getuid());
32312707Smckusick 		if ((ed = getenv("EDITOR")) == (char *)0)
32437976Sbostic 			ed = _PATH_VI;
32541408Smckusick 		execlp(ed, ed, tmpfile, 0);
32612707Smckusick 		perror(ed);
32712707Smckusick 		exit(1);
32812707Smckusick 	}
32941408Smckusick 	waitpid(pid, &stat, 0);
33013025Ssam 	sigsetmask(omask);
33141408Smckusick 	if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
33241408Smckusick 		return (0);
33341408Smckusick 	return (1);
33412707Smckusick }
33512707Smckusick 
33641408Smckusick /*
33741408Smckusick  * Convert a quotause list to an ASCII file.
33841408Smckusick  */
33941408Smckusick writeprivs(quplist, outfd, name, quotatype)
34041408Smckusick 	struct quotause *quplist;
34141408Smckusick 	int outfd;
34241408Smckusick 	char *name;
34341408Smckusick 	int quotatype;
34412707Smckusick {
34541408Smckusick 	register struct quotause *qup;
34612707Smckusick 	FILE *fd;
34712707Smckusick 
34843266Smckusick 	ftruncate(outfd, 0);
34941408Smckusick 	lseek(outfd, 0, L_SET);
35041408Smckusick 	if ((fd = fdopen(dup(outfd), "w")) == NULL) {
35112707Smckusick 		fprintf(stderr, "edquota: ");
35212707Smckusick 		perror(tmpfil);
35312707Smckusick 		exit(1);
35412707Smckusick 	}
35541408Smckusick 	fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
35641408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
35741408Smckusick 		fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n",
35841408Smckusick 		    qup->fsname, "blocks in use:",
35941408Smckusick 		    dbtob(qup->dqblk.dqb_curblocks) / 1024,
36041408Smckusick 		    dbtob(qup->dqblk.dqb_bsoftlimit) / 1024,
36141408Smckusick 		    dbtob(qup->dqblk.dqb_bhardlimit) / 1024);
36241408Smckusick 		fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n",
36341408Smckusick 		    "\tinodes in use:", qup->dqblk.dqb_curinodes,
36441408Smckusick 		    qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
36512707Smckusick 	}
36612707Smckusick 	fclose(fd);
36741408Smckusick 	return (1);
36812707Smckusick }
36912707Smckusick 
37041408Smckusick /*
37141408Smckusick  * Merge changes to an ASCII file into a quotause list.
37241408Smckusick  */
37341408Smckusick readprivs(quplist, infd)
37441408Smckusick 	struct quotause *quplist;
37541408Smckusick 	int infd;
37612707Smckusick {
37741408Smckusick 	register struct quotause *qup;
37812707Smckusick 	FILE *fd;
37941408Smckusick 	int cnt;
38041408Smckusick 	register char *cp;
38141408Smckusick 	struct dqblk dqblk;
38241408Smckusick 	char *fsp, line1[BUFSIZ], line2[BUFSIZ];
38312707Smckusick 
38441408Smckusick 	lseek(infd, 0, L_SET);
38541408Smckusick 	fd = fdopen(dup(infd), "r");
38612707Smckusick 	if (fd == NULL) {
38712707Smckusick 		fprintf(stderr, "Can't re-read temp file!!\n");
38841408Smckusick 		return (0);
38912707Smckusick 	}
39041408Smckusick 	/*
39141408Smckusick 	 * Discard title line, then read pairs of lines to process.
39241408Smckusick 	 */
39341408Smckusick 	(void) fgets(line1, sizeof (line1), fd);
39441408Smckusick 	while (fgets(line1, sizeof (line1), fd) != NULL &&
39541408Smckusick 	       fgets(line2, sizeof (line2), fd) != NULL) {
39641408Smckusick 		if ((fsp = strtok(line1, " \t:")) == NULL) {
39741408Smckusick 			fprintf(stderr, "%s: bad format\n", line1);
39841408Smckusick 			return (0);
39941408Smckusick 		}
40041408Smckusick 		if ((cp = strtok((char *)0, "\n")) == NULL) {
40141408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp,
40241408Smckusick 			    &fsp[strlen(fsp) + 1]);
40341408Smckusick 			return (0);
40441408Smckusick 		}
40541408Smckusick 		cnt = sscanf(cp,
40641408Smckusick 		    " blocks in use: %d, limits (soft = %d, hard = %d)",
40741408Smckusick 		    &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
40841408Smckusick 		    &dqblk.dqb_bhardlimit);
40941408Smckusick 		if (cnt != 3) {
41041408Smckusick 			fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
41141408Smckusick 			return (0);
41241408Smckusick 		}
41341408Smckusick 		dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024);
41441408Smckusick 		dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024);
41541408Smckusick 		dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024);
41641408Smckusick 		if ((cp = strtok(line2, "\n")) == NULL) {
41741408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
41841408Smckusick 			return (0);
41941408Smckusick 		}
42041408Smckusick 		cnt = sscanf(cp,
42141408Smckusick 		    "\tinodes in use: %d, limits (soft = %d, hard = %d)",
42241408Smckusick 		    &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
42341408Smckusick 		    &dqblk.dqb_ihardlimit);
42441408Smckusick 		if (cnt != 3) {
42541408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
42641408Smckusick 			return (0);
42741408Smckusick 		}
42841408Smckusick 		for (qup = quplist; qup; qup = qup->next) {
42941408Smckusick 			if (strcmp(fsp, qup->fsname))
43041408Smckusick 				continue;
43141408Smckusick 			/*
43241408Smckusick 			 * Cause time limit to be reset when the quota
43341408Smckusick 			 * is next used if previously had no soft limit
43441408Smckusick 			 * or were under it, but now have a soft limit
43541408Smckusick 			 * and are over it.
43641408Smckusick 			 */
43741408Smckusick 			if (dqblk.dqb_bsoftlimit &&
43841408Smckusick 			    qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit &&
43941408Smckusick 			    (qup->dqblk.dqb_bsoftlimit == 0 ||
44041408Smckusick 			     qup->dqblk.dqb_curblocks <
44141408Smckusick 			     qup->dqblk.dqb_bsoftlimit))
44241408Smckusick 				qup->dqblk.dqb_btime = 0;
44341408Smckusick 			if (dqblk.dqb_isoftlimit &&
44441408Smckusick 			    qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit &&
44541408Smckusick 			    (qup->dqblk.dqb_isoftlimit == 0 ||
44641408Smckusick 			     qup->dqblk.dqb_curinodes <
44741408Smckusick 			     qup->dqblk.dqb_isoftlimit))
44841408Smckusick 				qup->dqblk.dqb_itime = 0;
44941408Smckusick 			qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
45041408Smckusick 			qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
45141408Smckusick 			qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
45241408Smckusick 			qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
45341408Smckusick 			qup->flags |= FOUND;
45441408Smckusick 			if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
45541408Smckusick 			    dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
45641408Smckusick 				break;
45741408Smckusick 			fprintf(stderr,
45841408Smckusick 			    "%s: cannot change current allocation\n", fsp);
45912707Smckusick 			break;
46041408Smckusick 		}
46141408Smckusick 	}
46241408Smckusick 	fclose(fd);
46341408Smckusick 	/*
46441408Smckusick 	 * Disable quotas for any filesystems that have not been found.
46541408Smckusick 	 */
46641408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
46741408Smckusick 		if (qup->flags & FOUND) {
46841408Smckusick 			qup->flags &= ~FOUND;
46912716Smckusick 			continue;
47012716Smckusick 		}
47141408Smckusick 		qup->dqblk.dqb_bsoftlimit = 0;
47241408Smckusick 		qup->dqblk.dqb_bhardlimit = 0;
47341408Smckusick 		qup->dqblk.dqb_isoftlimit = 0;
47441408Smckusick 		qup->dqblk.dqb_ihardlimit = 0;
47512707Smckusick 	}
47641408Smckusick 	return (1);
47741408Smckusick }
47841408Smckusick 
47941408Smckusick /*
48041408Smckusick  * Convert a quotause list to an ASCII file of grace times.
48141408Smckusick  */
48241408Smckusick writetimes(quplist, outfd, quotatype)
48341408Smckusick 	struct quotause *quplist;
48441408Smckusick 	int outfd;
48541408Smckusick 	int quotatype;
48641408Smckusick {
48741408Smckusick 	register struct quotause *qup;
48841408Smckusick 	char *cvtstoa();
48941408Smckusick 	FILE *fd;
49041408Smckusick 
49143266Smckusick 	ftruncate(outfd, 0);
49241408Smckusick 	lseek(outfd, 0, L_SET);
49341408Smckusick 	if ((fd = fdopen(dup(outfd), "w")) == NULL) {
49441408Smckusick 		fprintf(stderr, "edquota: ");
49541408Smckusick 		perror(tmpfil);
49641408Smckusick 		exit(1);
49741408Smckusick 	}
49841408Smckusick 	fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n");
49941408Smckusick 	fprintf(fd, "Grace period before enforcing soft limits for %ss:\n",
50041408Smckusick 	    qfextension[quotatype]);
50141408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
50241408Smckusick 		fprintf(fd, "%s: block grace period: %s, ",
50341408Smckusick 		    qup->fsname, cvtstoa(qup->dqblk.dqb_btime));
50441408Smckusick 		fprintf(fd, "file grace period: %s\n",
50541408Smckusick 		    cvtstoa(qup->dqblk.dqb_itime));
50641408Smckusick 	}
50712707Smckusick 	fclose(fd);
50841408Smckusick 	return (1);
50941408Smckusick }
51041408Smckusick 
51141408Smckusick /*
51241408Smckusick  * Merge changes of grace times in an ASCII file into a quotause list.
51341408Smckusick  */
51441408Smckusick readtimes(quplist, infd)
51541408Smckusick 	struct quotause *quplist;
51641408Smckusick 	int infd;
51741408Smckusick {
51841408Smckusick 	register struct quotause *qup;
51941408Smckusick 	FILE *fd;
52041408Smckusick 	int cnt;
52141408Smckusick 	register char *cp;
52241408Smckusick 	time_t itime, btime, iseconds, bseconds;
52341408Smckusick 	char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
52441408Smckusick 
52541408Smckusick 	lseek(infd, 0, L_SET);
52641408Smckusick 	fd = fdopen(dup(infd), "r");
52741408Smckusick 	if (fd == NULL) {
52841408Smckusick 		fprintf(stderr, "Can't re-read temp file!!\n");
52941408Smckusick 		return (0);
53041408Smckusick 	}
53141408Smckusick 	/*
53241408Smckusick 	 * Discard two title lines, then read lines to process.
53341408Smckusick 	 */
53441408Smckusick 	(void) fgets(line1, sizeof (line1), fd);
53541408Smckusick 	(void) fgets(line1, sizeof (line1), fd);
53641408Smckusick 	while (fgets(line1, sizeof (line1), fd) != NULL) {
53741408Smckusick 		if ((fsp = strtok(line1, " \t:")) == NULL) {
53841408Smckusick 			fprintf(stderr, "%s: bad format\n", line1);
53941408Smckusick 			return (0);
54041408Smckusick 		}
54141408Smckusick 		if ((cp = strtok((char *)0, "\n")) == NULL) {
54241408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp,
54341408Smckusick 			    &fsp[strlen(fsp) + 1]);
54441408Smckusick 			return (0);
54541408Smckusick 		}
54641408Smckusick 		cnt = sscanf(cp,
54741408Smckusick 		    " block grace period: %d %s file grace period: %d %s",
54841408Smckusick 		    &btime, bunits, &itime, iunits);
54941408Smckusick 		if (cnt != 4) {
55041408Smckusick 			fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
55141408Smckusick 			return (0);
55241408Smckusick 		}
55341408Smckusick 		if (cvtatos(btime, bunits, &bseconds) == 0)
55441408Smckusick 			return (0);
55541408Smckusick 		if (cvtatos(itime, iunits, &iseconds) == 0)
55641408Smckusick 			return (0);
55741408Smckusick 		for (qup = quplist; qup; qup = qup->next) {
55841408Smckusick 			if (strcmp(fsp, qup->fsname))
55941408Smckusick 				continue;
56041408Smckusick 			qup->dqblk.dqb_btime = bseconds;
56141408Smckusick 			qup->dqblk.dqb_itime = iseconds;
56241408Smckusick 			qup->flags |= FOUND;
56312707Smckusick 			break;
56412707Smckusick 		}
56541408Smckusick 	}
56641408Smckusick 	fclose(fd);
56741408Smckusick 	/*
56841408Smckusick 	 * reset default grace periods for any filesystems
56941408Smckusick 	 * that have not been found.
57041408Smckusick 	 */
57141408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
57241408Smckusick 		if (qup->flags & FOUND) {
57341408Smckusick 			qup->flags &= ~FOUND;
57412707Smckusick 			continue;
57512707Smckusick 		}
57641408Smckusick 		qup->dqblk.dqb_btime = 0;
57741408Smckusick 		qup->dqblk.dqb_itime = 0;
57812707Smckusick 	}
57941408Smckusick 	return (1);
58012707Smckusick }
58112707Smckusick 
58241408Smckusick /*
58341408Smckusick  * Convert seconds to ASCII times.
58441408Smckusick  */
58512707Smckusick char *
58641408Smckusick cvtstoa(time)
58741408Smckusick 	time_t time;
58812707Smckusick {
58941408Smckusick 	static char buf[20];
59012707Smckusick 
59141408Smckusick 	if (time % (24 * 60 * 60) == 0) {
59241408Smckusick 		time /= 24 * 60 * 60;
59341408Smckusick 		sprintf(buf, "%d day%s", time, time == 1 ? "" : "s");
59441408Smckusick 	} else if (time % (60 * 60) == 0) {
59541408Smckusick 		time /= 60 * 60;
59641408Smckusick 		sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s");
59741408Smckusick 	} else if (time % 60 == 0) {
59841408Smckusick 		time /= 60;
59941408Smckusick 		sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s");
60041408Smckusick 	} else
60141408Smckusick 		sprintf(buf, "%d second%s", time, time == 1 ? "" : "s");
60241408Smckusick 	return (buf);
60341408Smckusick }
60441408Smckusick 
60541408Smckusick /*
60641408Smckusick  * Convert ASCII input times to seconds.
60741408Smckusick  */
60841408Smckusick cvtatos(time, units, seconds)
60941408Smckusick 	time_t time;
61041408Smckusick 	char *units;
61141408Smckusick 	time_t *seconds;
61241408Smckusick {
61341408Smckusick 
61441408Smckusick 	if (bcmp(units, "second", 6) == 0)
61541408Smckusick 		*seconds = time;
61641408Smckusick 	else if (bcmp(units, "minute", 6) == 0)
61741408Smckusick 		*seconds = time * 60;
61841408Smckusick 	else if (bcmp(units, "hour", 4) == 0)
61941408Smckusick 		*seconds = time * 60 * 60;
62041408Smckusick 	else if (bcmp(units, "day", 3) == 0)
62141408Smckusick 		*seconds = time * 24 * 60 * 60;
62241408Smckusick 	else {
62341408Smckusick 		printf("%s: bad units, specify %s\n", units,
62441408Smckusick 		    "days, hours, minutes, or seconds");
62541408Smckusick 		return (0);
62612707Smckusick 	}
62741408Smckusick 	return (1);
62812707Smckusick }
62912707Smckusick 
63041408Smckusick /*
63141408Smckusick  * Free a list of quotause structures.
63241408Smckusick  */
63341408Smckusick freeprivs(quplist)
63441408Smckusick 	struct quotause *quplist;
63541408Smckusick {
63641408Smckusick 	register struct quotause *qup, *nextqup;
63741408Smckusick 
63841408Smckusick 	for (qup = quplist; qup; qup = nextqup) {
63941408Smckusick 		nextqup = qup->next;
64041408Smckusick 		free(qup);
64141408Smckusick 	}
64241408Smckusick }
64341408Smckusick 
64441408Smckusick /*
64541408Smckusick  * Check whether a string is completely composed of digits.
64641408Smckusick  */
64712707Smckusick alldigits(s)
64812707Smckusick 	register char *s;
64912707Smckusick {
65012707Smckusick 	register c;
65112707Smckusick 
65212707Smckusick 	c = *s++;
65312707Smckusick 	do {
65412707Smckusick 		if (!isdigit(c))
65512707Smckusick 			return (0);
65612707Smckusick 	} while (c = *s++);
65712707Smckusick 	return (1);
65812707Smckusick }
65912707Smckusick 
66041408Smckusick /*
66141408Smckusick  * Check to see if a particular quota is to be enabled.
66241408Smckusick  */
66341444Smckusick hasquota(fs, type, qfnamep)
66441444Smckusick 	register struct fstab *fs;
66541408Smckusick 	int type;
66641444Smckusick 	char **qfnamep;
66712707Smckusick {
66841408Smckusick 	register char *opt;
66941444Smckusick 	char *cp, *index(), *strtok();
67041408Smckusick 	static char initname, usrname[100], grpname[100];
67141444Smckusick 	static char buf[BUFSIZ];
67212707Smckusick 
67341408Smckusick 	if (!initname) {
67441408Smckusick 		sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
67541408Smckusick 		sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
67641408Smckusick 		initname = 1;
67712707Smckusick 	}
67841444Smckusick 	strcpy(buf, fs->fs_mntops);
67941408Smckusick 	for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
68041444Smckusick 		if (cp = index(opt, '='))
68141444Smckusick 			*cp++ = '\0';
68241408Smckusick 		if (type == USRQUOTA && strcmp(opt, usrname) == 0)
68341444Smckusick 			break;
68441408Smckusick 		if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
68541444Smckusick 			break;
68612707Smckusick 	}
68741444Smckusick 	if (!opt)
68841444Smckusick 		return (0);
68941444Smckusick 	if (cp) {
69041444Smckusick 		*qfnamep = cp;
69141444Smckusick 		return (1);
69241444Smckusick 	}
69341444Smckusick 	(void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
69441444Smckusick 	*qfnamep = buf;
69541444Smckusick 	return (1);
69612707Smckusick }
697