xref: /original-bsd/usr.sbin/edquota/edquota.c (revision af968038)
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