xref: /csrg-svn/usr.sbin/edquota/edquota.c (revision 68941)
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