xref: /csrg-svn/usr.sbin/edquota/edquota.c (revision 43266)
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*43266Smckusick static char sccsid[] = "@(#)edquota.c	5.14 (Berkeley) 06/19/90";
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>
2838516Sbostic #include <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>
3637267Sbostic #include "pathnames.h"
3712707Smckusick 
3841408Smckusick char tmpfil[] = _PATH_TMP;
3912707Smckusick 
4041408Smckusick struct quotause {
4141408Smckusick 	struct	quotause *next;
4241408Smckusick 	long	flags;
4341408Smckusick 	struct	dqblk dqblk;
4441408Smckusick 	char	fsname[MAXPATHLEN + 1];
4541444Smckusick 	char	qfname[1];	/* actually longer */
4641408Smckusick } *getprivs();
4741408Smckusick #define	FOUND	0x01
4812707Smckusick 
4912707Smckusick main(argc, argv)
5041408Smckusick 	register char **argv;
5141408Smckusick 	int argc;
5212707Smckusick {
5341408Smckusick 	register struct quotause *qup, *protoprivs, *curprivs;
5441408Smckusick 	extern char *optarg;
5541408Smckusick 	extern int optind;
5641408Smckusick 	register long id, protoid;
5741408Smckusick 	register int quotatype, tmpfd;
5841408Smckusick 	char *protoname, ch;
5941408Smckusick 	int tflag = 0, pflag = 0;
6012707Smckusick 
6141408Smckusick 	if (argc < 2)
6241408Smckusick 		usage();
6312707Smckusick 	if (getuid()) {
6441408Smckusick 		fprintf(stderr, "edquota: permission denied\n");
6512707Smckusick 		exit(1);
6612707Smckusick 	}
6741408Smckusick 	quotatype = USRQUOTA;
6841408Smckusick 	while ((ch = getopt(argc, argv, "ugtp:")) != EOF) {
6941408Smckusick 		switch(ch) {
7041408Smckusick 		case 'p':
7141408Smckusick 			protoname = optarg;
7241408Smckusick 			pflag++;
7341408Smckusick 			break;
7441408Smckusick 		case 'g':
7541408Smckusick 			quotatype = GRPQUOTA;
7641408Smckusick 			break;
7741408Smckusick 		case 'u':
7841408Smckusick 			quotatype = USRQUOTA;
7941408Smckusick 			break;
8041408Smckusick 		case 't':
8141408Smckusick 			tflag++;
8241408Smckusick 			break;
8341408Smckusick 		default:
8441408Smckusick 			usage();
8541408Smckusick 		}
8641408Smckusick 	}
8741408Smckusick 	argc -= optind;
8841408Smckusick 	argv += optind;
8941408Smckusick 	if (pflag) {
9041408Smckusick 		if ((protoid = getentry(protoname, quotatype)) == -1)
9112803Smckusick 			exit(1);
9241408Smckusick 		protoprivs = getprivs(protoid, quotatype);
9341408Smckusick 		for (qup = protoprivs; qup; qup = qup->next) {
9441408Smckusick 			qup->dqblk.dqb_btime = 0;
9541408Smckusick 			qup->dqblk.dqb_itime = 0;
9612803Smckusick 		}
9712803Smckusick 		while (argc-- > 0) {
9841408Smckusick 			if ((id = getentry(*argv++, quotatype)) < 0)
9912803Smckusick 				continue;
10041408Smckusick 			putprivs(id, quotatype, protoprivs);
10112803Smckusick 		}
10212803Smckusick 		exit(0);
10312803Smckusick 	}
10441408Smckusick 	tmpfd = mkstemp(tmpfil);
10541408Smckusick 	fchown(tmpfd, getuid(), getgid());
10641408Smckusick 	if (tflag) {
10741408Smckusick 		protoprivs = getprivs(0, quotatype);
10841408Smckusick 		if (writetimes(protoprivs, tmpfd, quotatype) == 0)
10941408Smckusick 			exit(1);
11041408Smckusick 		if (editit(tmpfil) && readtimes(protoprivs, tmpfd))
11141408Smckusick 			putprivs(0, quotatype, protoprivs);
11241408Smckusick 		freeprivs(protoprivs);
11341408Smckusick 		exit(0);
11441408Smckusick 	}
11541408Smckusick 	for ( ; argc > 0; argc--, argv++) {
11641408Smckusick 		if ((id = getentry(*argv, quotatype)) == -1)
11712803Smckusick 			continue;
11841408Smckusick 		curprivs = getprivs(id, quotatype);
11941408Smckusick 		if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0)
12041408Smckusick 			continue;
12141408Smckusick 		if (editit(tmpfil) && readprivs(curprivs, tmpfd))
12241408Smckusick 			putprivs(id, quotatype, curprivs);
12341408Smckusick 		freeprivs(curprivs);
12412803Smckusick 	}
12541408Smckusick 	close(tmpfd);
12612707Smckusick 	unlink(tmpfil);
12712707Smckusick 	exit(0);
12812707Smckusick }
12912707Smckusick 
13041408Smckusick usage()
13141408Smckusick {
13241408Smckusick 	fprintf(stderr, "%s%s%s%s",
13341408Smckusick 		"Usage: edquota [-u] [-p username] username ...\n",
13441408Smckusick 		"\tedquota -g [-p groupname] groupname ...\n",
13541408Smckusick 		"\tedquota [-u] -t\n", "\tedquota -g -t\n");
13641408Smckusick 	exit(1);
13741408Smckusick }
13841408Smckusick 
13941408Smckusick /*
14041408Smckusick  * This routine converts a name for a particular quota type to
14141408Smckusick  * an identifier. This routine must agree with the kernel routine
14241408Smckusick  * getinoquota as to the interpretation of quota types.
14341408Smckusick  */
14441408Smckusick getentry(name, quotatype)
14512803Smckusick 	char *name;
14641408Smckusick 	int quotatype;
14712707Smckusick {
14812803Smckusick 	struct passwd *pw;
14941408Smckusick 	struct group *gr;
15012707Smckusick 
15112707Smckusick 	if (alldigits(name))
15241408Smckusick 		return (atoi(name));
15341408Smckusick 	switch(quotatype) {
15441408Smckusick 	case USRQUOTA:
15541408Smckusick 		if (pw = getpwnam(name))
15641408Smckusick 			return (pw->pw_uid);
15712803Smckusick 		fprintf(stderr, "%s: no such user\n", name);
15841408Smckusick 		break;
15941408Smckusick 	case GRPQUOTA:
16041408Smckusick 		if (gr = getgrnam(name))
16141408Smckusick 			return (gr->gr_gid);
16241408Smckusick 		fprintf(stderr, "%s: no such group\n", name);
16341408Smckusick 		break;
16441408Smckusick 	default:
16541408Smckusick 		fprintf(stderr, "%d: unknown quota type\n", quotatype);
16641408Smckusick 		break;
16712707Smckusick 	}
16841408Smckusick 	sleep(1);
16941408Smckusick 	return (-1);
17012707Smckusick }
17112707Smckusick 
17241408Smckusick /*
17341408Smckusick  * Collect the requested quota information.
17441408Smckusick  */
17541408Smckusick struct quotause *
17641408Smckusick getprivs(id, quotatype)
17741408Smckusick 	register long id;
17841408Smckusick 	int quotatype;
17912707Smckusick {
18041408Smckusick 	register struct fstab *fs;
18141408Smckusick 	register struct quotause *qup, *quptail;
18241408Smckusick 	struct quotause *quphead;
18341444Smckusick 	int qcmd, qupsize, fd;
18441444Smckusick 	char *qfpathname;
18541408Smckusick 	static int warned = 0;
18641408Smckusick 	extern int errno;
18741408Smckusick 
18841408Smckusick 	setfsent();
18941408Smckusick 	quphead = (struct quotause *)0;
19041408Smckusick 	qcmd = QCMD(Q_GETQUOTA, quotatype);
19141408Smckusick 	while (fs = getfsent()) {
19241444Smckusick 		if (strcmp(fs->fs_vfstype, "ufs"))
19341408Smckusick 			continue;
19441444Smckusick 		if (!hasquota(fs, quotatype, &qfpathname))
19541408Smckusick 			continue;
19641444Smckusick 		qupsize = sizeof(*qup) + strlen(qfpathname);
19741444Smckusick 		if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
19841408Smckusick 			fprintf(stderr, "edquota: out of memory\n");
19941408Smckusick 			exit(2);
20041408Smckusick 		}
20141444Smckusick 		if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
20241408Smckusick 	    		if (errno == EOPNOTSUPP && !warned) {
20341408Smckusick 				warned++;
20441408Smckusick 				fprintf(stderr, "Warning: %s\n",
20541408Smckusick 				    "Quotas are not compiled into this kernel");
20641408Smckusick 				sleep(3);
20741408Smckusick 			}
20841444Smckusick 			if ((fd = open(qfpathname, O_RDONLY)) < 0) {
20941444Smckusick 				fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
21041444Smckusick 				if (fd < 0 && errno != ENOENT) {
21141444Smckusick 					perror(qfpathname);
21241444Smckusick 					free(qup);
21341444Smckusick 					continue;
21441444Smckusick 				}
21541444Smckusick 				fprintf(stderr, "Creating quota file %s\n",
21641444Smckusick 				    qfpathname);
21741444Smckusick 				sleep(3);
21841444Smckusick 				(void) fchown(fd, getuid(),
21941444Smckusick 				    getentry(quotagroup, GRPQUOTA));
22041444Smckusick 				(void) fchmod(fd, 0640);
22141444Smckusick 			}
22241408Smckusick 			lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
22341408Smckusick 			switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
22441408Smckusick 			case 0:			/* EOF */
22541408Smckusick 				/*
22641408Smckusick 				 * Convert implicit 0 quota (EOF)
22741408Smckusick 				 * into an explicit one (zero'ed dqblk)
22841408Smckusick 				 */
22941408Smckusick 				bzero((caddr_t)&qup->dqblk,
23041408Smckusick 				    sizeof(struct dqblk));
23141408Smckusick 				break;
23241408Smckusick 
23341408Smckusick 			case sizeof(struct dqblk):	/* OK */
23441408Smckusick 				break;
23541408Smckusick 
23641408Smckusick 			default:		/* ERROR */
23741408Smckusick 				fprintf(stderr, "edquota: read error in ");
23841444Smckusick 				perror(qfpathname);
23941408Smckusick 				close(fd);
24041408Smckusick 				free(qup);
24141408Smckusick 				continue;
24241408Smckusick 			}
24341444Smckusick 			close(fd);
24441408Smckusick 		}
24541444Smckusick 		strcpy(qup->qfname, qfpathname);
24641408Smckusick 		strcpy(qup->fsname, fs->fs_file);
24741408Smckusick 		if (quphead == NULL)
24841408Smckusick 			quphead = qup;
24941408Smckusick 		else
25041408Smckusick 			quptail->next = qup;
25141408Smckusick 		quptail = qup;
25241408Smckusick 		qup->next = 0;
25341408Smckusick 	}
25441408Smckusick 	endfsent();
25541408Smckusick 	return (quphead);
25641408Smckusick }
25741408Smckusick 
25841408Smckusick /*
25941408Smckusick  * Store the requested quota information.
26041408Smckusick  */
26141408Smckusick putprivs(id, quotatype, quplist)
26241408Smckusick 	long id;
26341408Smckusick 	int quotatype;
26441408Smckusick 	struct quotause *quplist;
26541408Smckusick {
26641408Smckusick 	register struct quotause *qup;
26741408Smckusick 	int qcmd, fd;
26841408Smckusick 
26941408Smckusick 	qcmd = QCMD(Q_SETQUOTA, quotatype);
27041408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
27141444Smckusick 		if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0)
27241408Smckusick 			continue;
27341444Smckusick 		if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
27441444Smckusick 			perror(qup->qfname);
27541408Smckusick 		} else {
27641408Smckusick 			lseek(fd, (long)id * (long)sizeof (struct dqblk), 0);
27741408Smckusick 			if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
27841408Smckusick 			    sizeof (struct dqblk)) {
27941408Smckusick 				fprintf(stderr, "edquota: ");
28041444Smckusick 				perror(qup->qfname);
28141408Smckusick 			}
28241408Smckusick 			close(fd);
28341408Smckusick 		}
28441408Smckusick 	}
28541408Smckusick }
28641408Smckusick 
28741408Smckusick /*
28841408Smckusick  * Take a list of priviledges and get it edited.
28941408Smckusick  */
29041408Smckusick editit(tmpfile)
29141408Smckusick 	char *tmpfile;
29241408Smckusick {
29333609Sbostic 	long omask;
29441408Smckusick 	int pid, stat;
29541408Smckusick 	extern char *getenv();
29612707Smckusick 
29733609Sbostic 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
29812707Smckusick  top:
29912707Smckusick 	if ((pid = fork()) < 0) {
30012707Smckusick 		extern errno;
30112707Smckusick 
30212707Smckusick 		if (errno == EPROCLIM) {
30312707Smckusick 			fprintf(stderr, "You have too many processes\n");
30412707Smckusick 			return(0);
30512707Smckusick 		}
30612707Smckusick 		if (errno == EAGAIN) {
30712707Smckusick 			sleep(1);
30812707Smckusick 			goto top;
30912707Smckusick 		}
31012707Smckusick 		perror("fork");
31112707Smckusick 		return (0);
31212707Smckusick 	}
31312707Smckusick 	if (pid == 0) {
31412707Smckusick 		register char *ed;
31512707Smckusick 
31613025Ssam 		sigsetmask(omask);
31712707Smckusick 		setgid(getgid());
31812707Smckusick 		setuid(getuid());
31912707Smckusick 		if ((ed = getenv("EDITOR")) == (char *)0)
32037976Sbostic 			ed = _PATH_VI;
32141408Smckusick 		execlp(ed, ed, tmpfile, 0);
32212707Smckusick 		perror(ed);
32312707Smckusick 		exit(1);
32412707Smckusick 	}
32541408Smckusick 	waitpid(pid, &stat, 0);
32613025Ssam 	sigsetmask(omask);
32741408Smckusick 	if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
32841408Smckusick 		return (0);
32941408Smckusick 	return (1);
33012707Smckusick }
33112707Smckusick 
33241408Smckusick /*
33341408Smckusick  * Convert a quotause list to an ASCII file.
33441408Smckusick  */
33541408Smckusick writeprivs(quplist, outfd, name, quotatype)
33641408Smckusick 	struct quotause *quplist;
33741408Smckusick 	int outfd;
33841408Smckusick 	char *name;
33941408Smckusick 	int quotatype;
34012707Smckusick {
34141408Smckusick 	register struct quotause *qup;
34212707Smckusick 	FILE *fd;
34312707Smckusick 
344*43266Smckusick 	ftruncate(outfd, 0);
34541408Smckusick 	lseek(outfd, 0, L_SET);
34641408Smckusick 	if ((fd = fdopen(dup(outfd), "w")) == NULL) {
34712707Smckusick 		fprintf(stderr, "edquota: ");
34812707Smckusick 		perror(tmpfil);
34912707Smckusick 		exit(1);
35012707Smckusick 	}
35141408Smckusick 	fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
35241408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
35341408Smckusick 		fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n",
35441408Smckusick 		    qup->fsname, "blocks in use:",
35541408Smckusick 		    dbtob(qup->dqblk.dqb_curblocks) / 1024,
35641408Smckusick 		    dbtob(qup->dqblk.dqb_bsoftlimit) / 1024,
35741408Smckusick 		    dbtob(qup->dqblk.dqb_bhardlimit) / 1024);
35841408Smckusick 		fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n",
35941408Smckusick 		    "\tinodes in use:", qup->dqblk.dqb_curinodes,
36041408Smckusick 		    qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
36112707Smckusick 	}
36212707Smckusick 	fclose(fd);
36341408Smckusick 	return (1);
36412707Smckusick }
36512707Smckusick 
36641408Smckusick /*
36741408Smckusick  * Merge changes to an ASCII file into a quotause list.
36841408Smckusick  */
36941408Smckusick readprivs(quplist, infd)
37041408Smckusick 	struct quotause *quplist;
37141408Smckusick 	int infd;
37212707Smckusick {
37341408Smckusick 	register struct quotause *qup;
37412707Smckusick 	FILE *fd;
37541408Smckusick 	int cnt;
37641408Smckusick 	register char *cp;
37741408Smckusick 	struct dqblk dqblk;
37841408Smckusick 	char *fsp, line1[BUFSIZ], line2[BUFSIZ];
37912707Smckusick 
38041408Smckusick 	lseek(infd, 0, L_SET);
38141408Smckusick 	fd = fdopen(dup(infd), "r");
38212707Smckusick 	if (fd == NULL) {
38312707Smckusick 		fprintf(stderr, "Can't re-read temp file!!\n");
38441408Smckusick 		return (0);
38512707Smckusick 	}
38641408Smckusick 	/*
38741408Smckusick 	 * Discard title line, then read pairs of lines to process.
38841408Smckusick 	 */
38941408Smckusick 	(void) fgets(line1, sizeof (line1), fd);
39041408Smckusick 	while (fgets(line1, sizeof (line1), fd) != NULL &&
39141408Smckusick 	       fgets(line2, sizeof (line2), fd) != NULL) {
39241408Smckusick 		if ((fsp = strtok(line1, " \t:")) == NULL) {
39341408Smckusick 			fprintf(stderr, "%s: bad format\n", line1);
39441408Smckusick 			return (0);
39541408Smckusick 		}
39641408Smckusick 		if ((cp = strtok((char *)0, "\n")) == NULL) {
39741408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp,
39841408Smckusick 			    &fsp[strlen(fsp) + 1]);
39941408Smckusick 			return (0);
40041408Smckusick 		}
40141408Smckusick 		cnt = sscanf(cp,
40241408Smckusick 		    " blocks in use: %d, limits (soft = %d, hard = %d)",
40341408Smckusick 		    &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
40441408Smckusick 		    &dqblk.dqb_bhardlimit);
40541408Smckusick 		if (cnt != 3) {
40641408Smckusick 			fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
40741408Smckusick 			return (0);
40841408Smckusick 		}
40941408Smckusick 		dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024);
41041408Smckusick 		dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024);
41141408Smckusick 		dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024);
41241408Smckusick 		if ((cp = strtok(line2, "\n")) == NULL) {
41341408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
41441408Smckusick 			return (0);
41541408Smckusick 		}
41641408Smckusick 		cnt = sscanf(cp,
41741408Smckusick 		    "\tinodes in use: %d, limits (soft = %d, hard = %d)",
41841408Smckusick 		    &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
41941408Smckusick 		    &dqblk.dqb_ihardlimit);
42041408Smckusick 		if (cnt != 3) {
42141408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
42241408Smckusick 			return (0);
42341408Smckusick 		}
42441408Smckusick 		for (qup = quplist; qup; qup = qup->next) {
42541408Smckusick 			if (strcmp(fsp, qup->fsname))
42641408Smckusick 				continue;
42741408Smckusick 			/*
42841408Smckusick 			 * Cause time limit to be reset when the quota
42941408Smckusick 			 * is next used if previously had no soft limit
43041408Smckusick 			 * or were under it, but now have a soft limit
43141408Smckusick 			 * and are over it.
43241408Smckusick 			 */
43341408Smckusick 			if (dqblk.dqb_bsoftlimit &&
43441408Smckusick 			    qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit &&
43541408Smckusick 			    (qup->dqblk.dqb_bsoftlimit == 0 ||
43641408Smckusick 			     qup->dqblk.dqb_curblocks <
43741408Smckusick 			     qup->dqblk.dqb_bsoftlimit))
43841408Smckusick 				qup->dqblk.dqb_btime = 0;
43941408Smckusick 			if (dqblk.dqb_isoftlimit &&
44041408Smckusick 			    qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit &&
44141408Smckusick 			    (qup->dqblk.dqb_isoftlimit == 0 ||
44241408Smckusick 			     qup->dqblk.dqb_curinodes <
44341408Smckusick 			     qup->dqblk.dqb_isoftlimit))
44441408Smckusick 				qup->dqblk.dqb_itime = 0;
44541408Smckusick 			qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
44641408Smckusick 			qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
44741408Smckusick 			qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
44841408Smckusick 			qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
44941408Smckusick 			qup->flags |= FOUND;
45041408Smckusick 			if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
45141408Smckusick 			    dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
45241408Smckusick 				break;
45341408Smckusick 			fprintf(stderr,
45441408Smckusick 			    "%s: cannot change current allocation\n", fsp);
45512707Smckusick 			break;
45641408Smckusick 		}
45741408Smckusick 	}
45841408Smckusick 	fclose(fd);
45941408Smckusick 	/*
46041408Smckusick 	 * Disable quotas for any filesystems that have not been found.
46141408Smckusick 	 */
46241408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
46341408Smckusick 		if (qup->flags & FOUND) {
46441408Smckusick 			qup->flags &= ~FOUND;
46512716Smckusick 			continue;
46612716Smckusick 		}
46741408Smckusick 		qup->dqblk.dqb_bsoftlimit = 0;
46841408Smckusick 		qup->dqblk.dqb_bhardlimit = 0;
46941408Smckusick 		qup->dqblk.dqb_isoftlimit = 0;
47041408Smckusick 		qup->dqblk.dqb_ihardlimit = 0;
47112707Smckusick 	}
47241408Smckusick 	return (1);
47341408Smckusick }
47441408Smckusick 
47541408Smckusick /*
47641408Smckusick  * Convert a quotause list to an ASCII file of grace times.
47741408Smckusick  */
47841408Smckusick writetimes(quplist, outfd, quotatype)
47941408Smckusick 	struct quotause *quplist;
48041408Smckusick 	int outfd;
48141408Smckusick 	int quotatype;
48241408Smckusick {
48341408Smckusick 	register struct quotause *qup;
48441408Smckusick 	char *cvtstoa();
48541408Smckusick 	FILE *fd;
48641408Smckusick 
487*43266Smckusick 	ftruncate(outfd, 0);
48841408Smckusick 	lseek(outfd, 0, L_SET);
48941408Smckusick 	if ((fd = fdopen(dup(outfd), "w")) == NULL) {
49041408Smckusick 		fprintf(stderr, "edquota: ");
49141408Smckusick 		perror(tmpfil);
49241408Smckusick 		exit(1);
49341408Smckusick 	}
49441408Smckusick 	fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n");
49541408Smckusick 	fprintf(fd, "Grace period before enforcing soft limits for %ss:\n",
49641408Smckusick 	    qfextension[quotatype]);
49741408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
49841408Smckusick 		fprintf(fd, "%s: block grace period: %s, ",
49941408Smckusick 		    qup->fsname, cvtstoa(qup->dqblk.dqb_btime));
50041408Smckusick 		fprintf(fd, "file grace period: %s\n",
50141408Smckusick 		    cvtstoa(qup->dqblk.dqb_itime));
50241408Smckusick 	}
50312707Smckusick 	fclose(fd);
50441408Smckusick 	return (1);
50541408Smckusick }
50641408Smckusick 
50741408Smckusick /*
50841408Smckusick  * Merge changes of grace times in an ASCII file into a quotause list.
50941408Smckusick  */
51041408Smckusick readtimes(quplist, infd)
51141408Smckusick 	struct quotause *quplist;
51241408Smckusick 	int infd;
51341408Smckusick {
51441408Smckusick 	register struct quotause *qup;
51541408Smckusick 	FILE *fd;
51641408Smckusick 	int cnt;
51741408Smckusick 	register char *cp;
51841408Smckusick 	time_t itime, btime, iseconds, bseconds;
51941408Smckusick 	char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
52041408Smckusick 
52141408Smckusick 	lseek(infd, 0, L_SET);
52241408Smckusick 	fd = fdopen(dup(infd), "r");
52341408Smckusick 	if (fd == NULL) {
52441408Smckusick 		fprintf(stderr, "Can't re-read temp file!!\n");
52541408Smckusick 		return (0);
52641408Smckusick 	}
52741408Smckusick 	/*
52841408Smckusick 	 * Discard two title lines, then read lines to process.
52941408Smckusick 	 */
53041408Smckusick 	(void) fgets(line1, sizeof (line1), fd);
53141408Smckusick 	(void) fgets(line1, sizeof (line1), fd);
53241408Smckusick 	while (fgets(line1, sizeof (line1), fd) != NULL) {
53341408Smckusick 		if ((fsp = strtok(line1, " \t:")) == NULL) {
53441408Smckusick 			fprintf(stderr, "%s: bad format\n", line1);
53541408Smckusick 			return (0);
53641408Smckusick 		}
53741408Smckusick 		if ((cp = strtok((char *)0, "\n")) == NULL) {
53841408Smckusick 			fprintf(stderr, "%s: %s: bad format\n", fsp,
53941408Smckusick 			    &fsp[strlen(fsp) + 1]);
54041408Smckusick 			return (0);
54141408Smckusick 		}
54241408Smckusick 		cnt = sscanf(cp,
54341408Smckusick 		    " block grace period: %d %s file grace period: %d %s",
54441408Smckusick 		    &btime, bunits, &itime, iunits);
54541408Smckusick 		if (cnt != 4) {
54641408Smckusick 			fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
54741408Smckusick 			return (0);
54841408Smckusick 		}
54941408Smckusick 		if (cvtatos(btime, bunits, &bseconds) == 0)
55041408Smckusick 			return (0);
55141408Smckusick 		if (cvtatos(itime, iunits, &iseconds) == 0)
55241408Smckusick 			return (0);
55341408Smckusick 		for (qup = quplist; qup; qup = qup->next) {
55441408Smckusick 			if (strcmp(fsp, qup->fsname))
55541408Smckusick 				continue;
55641408Smckusick 			qup->dqblk.dqb_btime = bseconds;
55741408Smckusick 			qup->dqblk.dqb_itime = iseconds;
55841408Smckusick 			qup->flags |= FOUND;
55912707Smckusick 			break;
56012707Smckusick 		}
56141408Smckusick 	}
56241408Smckusick 	fclose(fd);
56341408Smckusick 	/*
56441408Smckusick 	 * reset default grace periods for any filesystems
56541408Smckusick 	 * that have not been found.
56641408Smckusick 	 */
56741408Smckusick 	for (qup = quplist; qup; qup = qup->next) {
56841408Smckusick 		if (qup->flags & FOUND) {
56941408Smckusick 			qup->flags &= ~FOUND;
57012707Smckusick 			continue;
57112707Smckusick 		}
57241408Smckusick 		qup->dqblk.dqb_btime = 0;
57341408Smckusick 		qup->dqblk.dqb_itime = 0;
57412707Smckusick 	}
57541408Smckusick 	return (1);
57612707Smckusick }
57712707Smckusick 
57841408Smckusick /*
57941408Smckusick  * Convert seconds to ASCII times.
58041408Smckusick  */
58112707Smckusick char *
58241408Smckusick cvtstoa(time)
58341408Smckusick 	time_t time;
58412707Smckusick {
58541408Smckusick 	static char buf[20];
58612707Smckusick 
58741408Smckusick 	if (time % (24 * 60 * 60) == 0) {
58841408Smckusick 		time /= 24 * 60 * 60;
58941408Smckusick 		sprintf(buf, "%d day%s", time, time == 1 ? "" : "s");
59041408Smckusick 	} else if (time % (60 * 60) == 0) {
59141408Smckusick 		time /= 60 * 60;
59241408Smckusick 		sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s");
59341408Smckusick 	} else if (time % 60 == 0) {
59441408Smckusick 		time /= 60;
59541408Smckusick 		sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s");
59641408Smckusick 	} else
59741408Smckusick 		sprintf(buf, "%d second%s", time, time == 1 ? "" : "s");
59841408Smckusick 	return (buf);
59941408Smckusick }
60041408Smckusick 
60141408Smckusick /*
60241408Smckusick  * Convert ASCII input times to seconds.
60341408Smckusick  */
60441408Smckusick cvtatos(time, units, seconds)
60541408Smckusick 	time_t time;
60641408Smckusick 	char *units;
60741408Smckusick 	time_t *seconds;
60841408Smckusick {
60941408Smckusick 
61041408Smckusick 	if (bcmp(units, "second", 6) == 0)
61141408Smckusick 		*seconds = time;
61241408Smckusick 	else if (bcmp(units, "minute", 6) == 0)
61341408Smckusick 		*seconds = time * 60;
61441408Smckusick 	else if (bcmp(units, "hour", 4) == 0)
61541408Smckusick 		*seconds = time * 60 * 60;
61641408Smckusick 	else if (bcmp(units, "day", 3) == 0)
61741408Smckusick 		*seconds = time * 24 * 60 * 60;
61841408Smckusick 	else {
61941408Smckusick 		printf("%s: bad units, specify %s\n", units,
62041408Smckusick 		    "days, hours, minutes, or seconds");
62141408Smckusick 		return (0);
62212707Smckusick 	}
62341408Smckusick 	return (1);
62412707Smckusick }
62512707Smckusick 
62641408Smckusick /*
62741408Smckusick  * Free a list of quotause structures.
62841408Smckusick  */
62941408Smckusick freeprivs(quplist)
63041408Smckusick 	struct quotause *quplist;
63141408Smckusick {
63241408Smckusick 	register struct quotause *qup, *nextqup;
63341408Smckusick 
63441408Smckusick 	for (qup = quplist; qup; qup = nextqup) {
63541408Smckusick 		nextqup = qup->next;
63641408Smckusick 		free(qup);
63741408Smckusick 	}
63841408Smckusick }
63941408Smckusick 
64041408Smckusick /*
64141408Smckusick  * Check whether a string is completely composed of digits.
64241408Smckusick  */
64312707Smckusick alldigits(s)
64412707Smckusick 	register char *s;
64512707Smckusick {
64612707Smckusick 	register c;
64712707Smckusick 
64812707Smckusick 	c = *s++;
64912707Smckusick 	do {
65012707Smckusick 		if (!isdigit(c))
65112707Smckusick 			return (0);
65212707Smckusick 	} while (c = *s++);
65312707Smckusick 	return (1);
65412707Smckusick }
65512707Smckusick 
65641408Smckusick /*
65741408Smckusick  * Check to see if a particular quota is to be enabled.
65841408Smckusick  */
65941444Smckusick hasquota(fs, type, qfnamep)
66041444Smckusick 	register struct fstab *fs;
66141408Smckusick 	int type;
66241444Smckusick 	char **qfnamep;
66312707Smckusick {
66441408Smckusick 	register char *opt;
66541444Smckusick 	char *cp, *index(), *strtok();
66641408Smckusick 	static char initname, usrname[100], grpname[100];
66741444Smckusick 	static char buf[BUFSIZ];
66812707Smckusick 
66941408Smckusick 	if (!initname) {
67041408Smckusick 		sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname);
67141408Smckusick 		sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname);
67241408Smckusick 		initname = 1;
67312707Smckusick 	}
67441444Smckusick 	strcpy(buf, fs->fs_mntops);
67541408Smckusick 	for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
67641444Smckusick 		if (cp = index(opt, '='))
67741444Smckusick 			*cp++ = '\0';
67841408Smckusick 		if (type == USRQUOTA && strcmp(opt, usrname) == 0)
67941444Smckusick 			break;
68041408Smckusick 		if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
68141444Smckusick 			break;
68212707Smckusick 	}
68341444Smckusick 	if (!opt)
68441444Smckusick 		return (0);
68541444Smckusick 	if (cp) {
68641444Smckusick 		*qfnamep = cp;
68741444Smckusick 		return (1);
68841444Smckusick 	}
68941444Smckusick 	(void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
69041444Smckusick 	*qfnamep = buf;
69141444Smckusick 	return (1);
69212707Smckusick }
693