xref: /csrg-svn/usr.sbin/edquota/edquota.c (revision 12716)
112707Smckusick #ifndef lint
2*12716Smckusick static char sccsid[] = "@(#)edquota.c	4.2 (Berkeley, from Melbourne) 05/25/83";
312707Smckusick #endif
412707Smckusick 
512707Smckusick /*
612707Smckusick  * Disk quota editor.
712707Smckusick  */
812707Smckusick #include <stdio.h>
912707Smckusick #include <signal.h>
1012707Smckusick #include <errno.h>
1112707Smckusick #include <pwd.h>
1212707Smckusick #include <ctype.h>
1312707Smckusick #include <fstab.h>
1412707Smckusick 
1512707Smckusick #include <sys/param.h>
16*12716Smckusick #define QUOTA
1712707Smckusick #include <sys/quota.h>
1812707Smckusick #include <sys/stat.h>
1912707Smckusick #include <sys/file.h>
2012707Smckusick 
2112707Smckusick #define	DEFEDITOR	"/usr/ucb/vi"
2212707Smckusick 
2312707Smckusick struct	dquot dq[NMOUNT];
2412707Smckusick struct	dquot odq[NMOUNT];
2512707Smckusick char	dqf[NMOUNT][MAXPATHLEN + 1];
2612707Smckusick char	odqf[NMOUNT][MAXPATHLEN + 1];
2712707Smckusick 
2812707Smckusick char	tmpfil[] = "/tmp/EdP.aXXXXX";
29*12716Smckusick char	*qfname = "quotas";
3012707Smckusick char	*arg0;
3112707Smckusick char	*getenv();
3212707Smckusick 
3312707Smckusick main(argc, argv)
3412707Smckusick 	char **argv;
3512707Smckusick {
3612707Smckusick 
3712707Smckusick 	mktemp(tmpfil);
3812707Smckusick 	close(creat(tmpfil, 0600));
3912707Smckusick 	chown(tmpfil, getuid(), getgid());
4012707Smckusick 	arg0 = *argv++;
4112707Smckusick 	if (argc < 2) {
4212707Smckusick 		fprintf(stderr, "Usage: %s username ...\n", arg0);
4312707Smckusick 		unlink(tmpfil);
4412707Smckusick 		exit(1);
4512707Smckusick 	}
4612707Smckusick 	--argc;
4712707Smckusick 	if (getuid()) {
4812707Smckusick 		fprintf(stderr, "%s: permission denied\n", arg0);
4912707Smckusick 		unlink(tmpfil);
5012707Smckusick 		exit(1);
5112707Smckusick 	}
5212707Smckusick 	while (--argc >= 0)
5312707Smckusick 		doedit(*argv++);
5412707Smckusick 	unlink(tmpfil);
5512707Smckusick 	exit(0);
5612707Smckusick }
5712707Smckusick 
5812707Smckusick doedit(name)
5912707Smckusick 	register char *name;
6012707Smckusick {
6112707Smckusick 	register uid;
6212707Smckusick 	register struct passwd *pw;
6312707Smckusick 
6412707Smckusick 	if (alldigits(name))
6512707Smckusick 		uid = atoi(name);
6612707Smckusick 	else if (pw = getpwnam(name))
6712707Smckusick 		uid = pw->pw_uid;
6812707Smckusick 	else {
6912707Smckusick 		fprintf(stderr, "%s: no such user\n");
7012707Smckusick 		sleep(1);
7112707Smckusick 		return;
7212707Smckusick 	}
7312707Smckusick 	getprivs(uid);
7412707Smckusick 	if (editit())
7512707Smckusick 		putprivs(uid);
7612707Smckusick }
7712707Smckusick 
7812707Smckusick editit()
7912707Smckusick {
8012707Smckusick 	register pid, xpid;
8112707Smckusick 	int stat;
8212707Smckusick 
8312707Smckusick 	sighold(SIGINT);
8412707Smckusick 	sighold(SIGQUIT);
8512707Smckusick 	sighold(SIGHUP);
8612707Smckusick 
8712707Smckusick  top:
8812707Smckusick 	if ((pid = fork()) < 0) {
8912707Smckusick 		extern errno;
9012707Smckusick 
9112707Smckusick 		if (errno == EPROCLIM) {
9212707Smckusick 			fprintf(stderr, "You have too many processes\n");
9312707Smckusick 			return(0);
9412707Smckusick 		}
9512707Smckusick 		if (errno == EAGAIN) {
9612707Smckusick 			sleep(1);
9712707Smckusick 			goto top;
9812707Smckusick 		}
9912707Smckusick 		perror("fork");
10012707Smckusick 		return (0);
10112707Smckusick 	}
10212707Smckusick 	if (pid == 0) {
10312707Smckusick 		register char *ed;
10412707Smckusick 
10512707Smckusick 		sigrelse(SIGINT);
10612707Smckusick 		sigrelse(SIGQUIT);
10712707Smckusick 		sigrelse(SIGHUP);
10812707Smckusick 		setgid(getgid());
10912707Smckusick 		setuid(getuid());
11012707Smckusick 
11112707Smckusick 		if ((ed = getenv("EDITOR")) == (char *)0)
11212707Smckusick 			ed = DEFEDITOR;
11312707Smckusick 		execlp(ed, ed, tmpfil, 0);
11412707Smckusick 		perror(ed);
11512707Smckusick 		exit(1);
11612707Smckusick 	}
11712707Smckusick 	while ((xpid = wait(&stat)) >= 0)
11812707Smckusick 		if (xpid == pid)
11912707Smckusick 			break;
12012707Smckusick 	sigrelse(SIGINT);
12112707Smckusick 	sigrelse(SIGQUIT);
12212707Smckusick 	sigrelse(SIGHUP);
12312707Smckusick 	return (!stat);
12412707Smckusick }
12512707Smckusick 
12612707Smckusick getprivs(uid)
12712707Smckusick 	register uid;
12812707Smckusick {
12912707Smckusick 	register i;
13012707Smckusick 	FILE *fd;
13112707Smckusick 
13212707Smckusick 	getdiscq(uid, dq, dqf);
13312707Smckusick 	for (i = 0; i < NMOUNT; i++) {
13412707Smckusick 		odq[i] = dq[i];
13512707Smckusick 		strcpy(odqf[i], dqf[i]);
13612707Smckusick 	}
13712707Smckusick 	if ((fd = fopen(tmpfil, "w")) == NULL) {
13812707Smckusick 		fprintf(stderr, "edquota: ");
13912707Smckusick 		perror(tmpfil);
14012707Smckusick 		exit(1);
14112707Smckusick 	}
14212707Smckusick 	for (i = 0; i < NMOUNT; i++) {
14312707Smckusick 		if (*dqf[i] == '\0')
14412707Smckusick 			continue;
14512707Smckusick 		fprintf(fd,
14612707Smckusick "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n"
14712707Smckusick 			, dqf[i]
148*12716Smckusick 			, dq[i].dq_bsoftlimit / btodb(1024)
149*12716Smckusick 			, dq[i].dq_bhardlimit / btodb(1024)
15012707Smckusick 			, dq[i].dq_isoftlimit
15112707Smckusick 			, dq[i].dq_ihardlimit
15212707Smckusick 		);
15312707Smckusick 	}
15412707Smckusick 	fclose(fd);
15512707Smckusick }
15612707Smckusick 
15712707Smckusick putprivs(uid)
15812707Smckusick 	register uid;
15912707Smckusick {
16012707Smckusick 	register i, j;
16112707Smckusick 	int n;
16212707Smckusick 	FILE *fd;
16312707Smckusick 	char line[BUFSIZ];
16412707Smckusick 
16512707Smckusick 	fd = fopen(tmpfil, "r");
16612707Smckusick 	if (fd == NULL) {
16712707Smckusick 		fprintf(stderr, "Can't re-read temp file!!\n");
16812707Smckusick 		return;
16912707Smckusick 	}
17012707Smckusick 	for (i = 0; i < NMOUNT; i++) {
17112707Smckusick 		char *cp, *dp, *next();
17212707Smckusick 
17312707Smckusick 		if (fgets(line, sizeof (line), fd) == NULL)
17412707Smckusick 			break;
17512707Smckusick 		cp = next(line, " \t");
17612707Smckusick 		if (cp == NULL)
17712707Smckusick 			break;
17812707Smckusick 		*cp++ = '\0';
17912707Smckusick 		while (*cp && *cp == '\t' && *cp == ' ')
18012707Smckusick 			cp++;
18112707Smckusick 		dp = cp, cp = next(cp, " \t");
18212707Smckusick 		if (cp == NULL)
18312707Smckusick 			break;
18412707Smckusick 		*cp++ = '\0';
18512707Smckusick 		while (*cp && *cp == '\t' && *cp == ' ')
18612707Smckusick 			cp++;
18712707Smckusick 		strcpy(dqf[i], dp);
18812707Smckusick 		n = sscanf(cp,
18912707Smckusick "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n"
19012707Smckusick 			, &dq[i].dq_bsoftlimit
19112707Smckusick 			, &dq[i].dq_bhardlimit
19212707Smckusick 			, &dq[i].dq_isoftlimit
19312707Smckusick 			, &dq[i].dq_ihardlimit
19412707Smckusick 		);
195*12716Smckusick 		if (n != 4) {
196*12716Smckusick 			fprintf(stderr, "%s: bad format\n", cp);
197*12716Smckusick 			continue;
198*12716Smckusick 		}
199*12716Smckusick 		dq[i].dq_bsoftlimit *= btodb(1024);
200*12716Smckusick 		dq[i].dq_bhardlimit *= btodb(1024);
20112707Smckusick 	}
20212707Smckusick 	fclose(fd);
20312707Smckusick 	n = i;
20412707Smckusick 	for (i = 0; i < n; i++) {
20512707Smckusick 		if (*dqf[i] == '\0')
20612707Smckusick 			break;
20712707Smckusick 		for (j = 0; j < NMOUNT; j++) {
20812707Smckusick 			if (strcmp(dqf[i], odqf[j]) == 0)
20912707Smckusick 				break;
21012707Smckusick 		}
21112707Smckusick 		if (j >= NMOUNT)
21212707Smckusick 			continue;
21312707Smckusick 		*odqf[j] = '\0';
21412707Smckusick 		if (dq[i].dq_isoftlimit == odq[j].dq_isoftlimit &&
21512707Smckusick 		    dq[i].dq_ihardlimit == odq[j].dq_ihardlimit &&
21612707Smckusick 		    dq[i].dq_bsoftlimit == odq[j].dq_bsoftlimit &&
21712707Smckusick 		    dq[i].dq_bhardlimit == odq[j].dq_bhardlimit) {
218*12716Smckusick 			for (j = i; j < NMOUNT; j++) {
21912707Smckusick 				dq[j] = dq[j+1];
22012707Smckusick 				strcpy(dqf[j], dqf[j+1]);
22112707Smckusick 			}
22212707Smckusick 			*dqf[j] = '\0';
22312707Smckusick 			i--;
22412707Smckusick 			continue;
22512707Smckusick 		}
22612707Smckusick 		/*
22712707Smckusick 		 * This isn't really good enough, it is quite likely
22812707Smckusick 		 * to have changed while we have been away editing,
22912707Smckusick 		 * but it's not important enough to worry about at
23012707Smckusick 		 * the minute.
23112707Smckusick 		 */
23212707Smckusick 		dq[i].dq_curblocks = odq[j].dq_curblocks;
23312707Smckusick 		dq[i].dq_curinodes = odq[j].dq_curinodes;
23412707Smckusick 		/*
23512707Smckusick 		 * If we've upped the inode or disk block limits
23612707Smckusick 		 * and the guy is out of warnings, reinitialize.
23712707Smckusick 		 */
23812707Smckusick 		if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit &&
23912707Smckusick 		    dq[i].dq_bwarn == 0)
24012707Smckusick 			dq[i].dq_bwarn = MAX_DQ_WARN;
24112707Smckusick 		if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit &&
24212707Smckusick 		    dq[i].dq_iwarn == 0)
24312707Smckusick 			dq[i].dq_iwarn = MAX_IQ_WARN;
24412707Smckusick 	}
24512707Smckusick 	if (i < NMOUNT) {
24612707Smckusick 		for (j = 0; j < NMOUNT; j++) {
24712707Smckusick 			if (*odqf[j] == '\0')
24812707Smckusick 				continue;
24912707Smckusick 			strcpy(dqf[i], odqf[j]);
25012707Smckusick 			dq[i].dq_isoftlimit = 0;
25112707Smckusick 			dq[i].dq_ihardlimit = 0;
25212707Smckusick 			dq[i].dq_bsoftlimit = 0;
25312707Smckusick 			dq[i].dq_bhardlimit = 0;
25412707Smckusick 			/*
25512707Smckusick 			 * Same applies as just above
25612707Smckusick 			 * but matters not at all, as we are just
25712707Smckusick 			 * turning quota'ing off for this filesys.
25812707Smckusick 			 */
25912707Smckusick 			dq[i].dq_curblocks = odq[j].dq_curblocks;
26012707Smckusick 			dq[i].dq_curinodes = odq[j].dq_curinodes;
26112707Smckusick 			if (++i >= NMOUNT)
26212707Smckusick 				break;
26312707Smckusick 		}
26412707Smckusick 	}
26512707Smckusick 	if (*dqf[0])
26612707Smckusick 		putdiscq(uid, dq, dqf);
26712707Smckusick }
26812707Smckusick 
26912707Smckusick char *
27012707Smckusick next(cp, match)
27112707Smckusick 	register char *cp;
27212707Smckusick 	char *match;
27312707Smckusick {
27412707Smckusick 	register char *dp;
27512707Smckusick 
27612707Smckusick 	while (cp && *cp) {
27712707Smckusick 		for (dp = match; dp && *dp; dp++)
27812707Smckusick 			if (*dp == *cp)
27912707Smckusick 				return (cp);
28012707Smckusick 		cp++;
28112707Smckusick 	}
28212707Smckusick 	return ((char *)0);
28312707Smckusick }
28412707Smckusick 
28512707Smckusick alldigits(s)
28612707Smckusick 	register char *s;
28712707Smckusick {
28812707Smckusick 	register c;
28912707Smckusick 
29012707Smckusick 	c = *s++;
29112707Smckusick 	do {
29212707Smckusick 		if (!isdigit(c))
29312707Smckusick 			return (0);
29412707Smckusick 	} while (c = *s++);
29512707Smckusick 	return (1);
29612707Smckusick }
29712707Smckusick 
29812707Smckusick getdiscq(uid, dq, dqf)
29912707Smckusick 	register uid;
30012707Smckusick 	register struct dquot *dq;
30112707Smckusick 	register char (*dqf)[MAXPATHLEN + 1];
30212707Smckusick {
30312707Smckusick 	register struct fstab *fs;
304*12716Smckusick 	char qfilename[MAXPATHLEN + 1];
30512707Smckusick 
30612707Smckusick 	setfsent();
30712707Smckusick 	while (fs = getfsent()) {
30812707Smckusick 		struct	stat statb;
30912707Smckusick 		struct	dqblk dqblk;
31012707Smckusick 		dev_t	fsdev;
31112707Smckusick 
31212707Smckusick 		if (stat(fs->fs_spec, &statb) < 0)
31312707Smckusick 			continue;
31412707Smckusick 		fsdev = statb.st_rdev;
315*12716Smckusick 		sprintf(qfilename, "%s/%s", fs->fs_file, qfname);
316*12716Smckusick 		if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
31712707Smckusick 			continue;
31812707Smckusick 		if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) {
319*12716Smckusick 			register fd = open(qfilename, FRDONLY);
32012707Smckusick 
32112707Smckusick 			if (fd < 0)
32212707Smckusick 				continue;
32312707Smckusick 			lseek(fd, (long)(uid * sizeof dqblk), FSEEK_ABSOLUTE);
32412707Smckusick 			if (read(fd, &dqblk, sizeof dqblk) != sizeof (dqblk)) {
32512707Smckusick 				close(fd);
32612707Smckusick 				continue;
32712707Smckusick 			}
32812707Smckusick 			close(fd);
32912707Smckusick 		}
33012707Smckusick 		dq->dq_dqb = dqblk;
33112707Smckusick 		dq->dq_dev = fsdev;
33212707Smckusick 		strcpy(*dqf, fs->fs_file);
33312707Smckusick 		dq++, dqf++;
33412707Smckusick 	}
33512707Smckusick 	endfsent();
33612707Smckusick 	**dqf = '\0';
33712707Smckusick }
33812707Smckusick 
33912707Smckusick putdiscq(uid, dq, dqf)
34012707Smckusick 	register uid;
34112707Smckusick 	register struct dquot *dq;
34212707Smckusick 	register char (*dqf)[MAXPATHLEN + 1];
34312707Smckusick {
34412707Smckusick 	register fd, cnt;
34512707Smckusick 	struct stat sb;
34612707Smckusick 	struct fstab *fs;
34712707Smckusick 
34812707Smckusick 	cnt = 0;
34912707Smckusick 	for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) {
35012707Smckusick 		fs = getfsfile(*dqf);
351*12716Smckusick 		if (fs == NULL) {
352*12716Smckusick 			fprintf(stderr, "%s: not in /etc/fstab\n", *dqf);
353*12716Smckusick 			continue;
354*12716Smckusick 		}
355*12716Smckusick 		strcat(*dqf, "/");
356*12716Smckusick 		strcat(*dqf, qfname);
357*12716Smckusick 		if (stat(*dqf, &sb) >= 0)
358*12716Smckusick 			quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb);
359*12716Smckusick 		if ((fd = open(*dqf, 1)) < 0) {
360*12716Smckusick 			perror(*dqf);
361*12716Smckusick 		} else {
36212707Smckusick 			lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0);
36312707Smckusick 			if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) !=
36412707Smckusick 			    sizeof (struct dqblk)) {
36512707Smckusick 				fprintf(stderr, "edquota: ");
36612707Smckusick 				perror(*dqf);
36712707Smckusick 			}
36812707Smckusick 			close(fd);
36912707Smckusick 		}
37012707Smckusick 	}
37112707Smckusick }
372