xref: /openbsd-src/usr.sbin/quotaon/quotaon.c (revision 10a7b75896683c64bfb039e81ab2b44ce1670578)
1df930be7Sderaadt /*
2df930be7Sderaadt  * Copyright (c) 1980, 1990, 1993
3df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
4df930be7Sderaadt  *
5df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
6df930be7Sderaadt  * Robert Elz at The University of Melbourne.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  * modification, are permitted provided that the following conditions
10df930be7Sderaadt  * are met:
11df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
1629295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
18df930be7Sderaadt  *    without specific prior written permission.
19df930be7Sderaadt  *
20df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt  * SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
33df930be7Sderaadt /*
34df930be7Sderaadt  * Turn quota on/off for a filesystem.
35df930be7Sderaadt  */
36*f4147939Sguenther #include <sys/types.h>
37df930be7Sderaadt #include <sys/mount.h>
38df930be7Sderaadt #include <ufs/ufs/quota.h>
39*f4147939Sguenther 
40b5a78835Sdavid #include <err.h>
41df930be7Sderaadt #include <stdio.h>
42b5a78835Sdavid #include <stdlib.h>
43df930be7Sderaadt #include <string.h>
44df930be7Sderaadt #include <fstab.h>
45b5a78835Sdavid #include <unistd.h>
46df930be7Sderaadt 
47df930be7Sderaadt char *qfname = QUOTAFILENAME;
4895709839Sderaadt char *qfextension[] = INITQFNAMES;
49df930be7Sderaadt 
50df930be7Sderaadt int	aflag;		/* all file systems */
51df930be7Sderaadt int	gflag;		/* operate on group quotas */
52df930be7Sderaadt int	uflag;		/* operate on user quotas */
53df930be7Sderaadt int	vflag;		/* verbose */
54df930be7Sderaadt 
55d2c62849Sderaadt void	usage(char *whoami);
56d2c62849Sderaadt int	hasquota(struct fstab *fs, int type, char **qfnamep, int force);
57d2c62849Sderaadt int	quotaonoff(struct fstab *fs, int offmode, int type, char *qfpathname);
58d2c62849Sderaadt int	oneof(char *target, char *list[], int cnt);
59d2c62849Sderaadt int	readonly(struct fstab *fs);
60d2c62849Sderaadt 
61d2c62849Sderaadt 
62d2c62849Sderaadt int
main(int argc,char * argv[])63f303ad03Sderaadt main(int argc, char *argv[])
64df930be7Sderaadt {
650ac0d02eSmpech 	struct fstab *fs;
66180acc8fSmillert 	char *qfnp, *whoami;
67df930be7Sderaadt 	long argnum, done = 0;
68df930be7Sderaadt 	int i, offmode = 0, errs = 0;
69f3bae140Sderaadt 	int ch;
70df930be7Sderaadt 
71180acc8fSmillert 	whoami = strrchr(*argv, '/') + 1;
72df930be7Sderaadt 	if (whoami == (char *)1)
73df930be7Sderaadt 		whoami = *argv;
74df930be7Sderaadt 	if (strcmp(whoami, "quotaoff") == 0)
7528056f30Sderaadt 		offmode = 1;
76df930be7Sderaadt 	else if (strcmp(whoami, "quotaon") != 0) {
77df930be7Sderaadt 		fprintf(stderr, "Name must be quotaon or quotaoff not %s\n",
78df930be7Sderaadt 			whoami);
79df930be7Sderaadt 		exit(1);
80df930be7Sderaadt 	}
81f3bae140Sderaadt 	while ((ch = getopt(argc, argv, "avug")) != -1) {
82df930be7Sderaadt 		switch (ch) {
83df930be7Sderaadt 		case 'a':
8428056f30Sderaadt 			aflag = 1;
85df930be7Sderaadt 			break;
86df930be7Sderaadt 		case 'g':
8728056f30Sderaadt 			gflag = 1;
88df930be7Sderaadt 			break;
89df930be7Sderaadt 		case 'u':
9028056f30Sderaadt 			uflag = 1;
91df930be7Sderaadt 			break;
92df930be7Sderaadt 		case 'v':
9328056f30Sderaadt 			vflag = 1;
94df930be7Sderaadt 			break;
95df930be7Sderaadt 		default:
96df930be7Sderaadt 			usage(whoami);
97df930be7Sderaadt 		}
98df930be7Sderaadt 	}
99df930be7Sderaadt 	argc -= optind;
100df930be7Sderaadt 	argv += optind;
101df930be7Sderaadt 	if (argc <= 0 && !aflag)
102df930be7Sderaadt 		usage(whoami);
103df930be7Sderaadt 	if (!gflag && !uflag) {
10428056f30Sderaadt 		gflag = 1;
10528056f30Sderaadt 		uflag = 1;
106df930be7Sderaadt 	}
107df930be7Sderaadt 	setfsent();
108df930be7Sderaadt 	while ((fs = getfsent()) != NULL) {
109e5cb37d1Sderaadt 		if (strcmp(fs->fs_type, FSTAB_RW))
110e5cb37d1Sderaadt 			continue;
111e5cb37d1Sderaadt 		if (strcmp(fs->fs_vfstype, "ffs") &&
112dde99675Sderaadt 		    strcmp(fs->fs_vfstype, "ufs") &&
113dde99675Sderaadt 		    strcmp(fs->fs_vfstype, "mfs"))
114df930be7Sderaadt 			continue;
115df930be7Sderaadt 		if (aflag) {
116c25ff6d6Sdm 			if (gflag && hasquota(fs, GRPQUOTA, &qfnp, 0))
117df930be7Sderaadt 				errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
118c25ff6d6Sdm 			if (uflag && hasquota(fs, USRQUOTA, &qfnp, 0))
119df930be7Sderaadt 				errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
120df930be7Sderaadt 			continue;
121df930be7Sderaadt 		}
122df930be7Sderaadt 		if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
123df930be7Sderaadt 		    (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
124df930be7Sderaadt 			done |= 1 << argnum;
125c25ff6d6Sdm 			if (gflag) {
126c25ff6d6Sdm 				hasquota(fs, GRPQUOTA, &qfnp, 1);
127df930be7Sderaadt 				errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
128c25ff6d6Sdm 			}
129c25ff6d6Sdm 			if (uflag) {
130c25ff6d6Sdm 				hasquota(fs, USRQUOTA, &qfnp, 1);
131df930be7Sderaadt 				errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
132df930be7Sderaadt 			}
133df930be7Sderaadt 		}
134c25ff6d6Sdm 	}
135df930be7Sderaadt 	endfsent();
136df930be7Sderaadt 	for (i = 0; i < argc; i++)
137df930be7Sderaadt 		if ((done & (1 << i)) == 0)
138df930be7Sderaadt 			fprintf(stderr, "%s not found in fstab\n",
139df930be7Sderaadt 				argv[i]);
140df930be7Sderaadt 	exit(errs);
141df930be7Sderaadt }
142df930be7Sderaadt 
143d2c62849Sderaadt void
usage(char * whoami)144f303ad03Sderaadt usage(char *whoami)
145df930be7Sderaadt {
146df930be7Sderaadt 
1475a543052Sjmc 	fprintf(stderr, "usage: %s [-aguv] filesystem ...\n", whoami);
148df930be7Sderaadt 	exit(1);
149df930be7Sderaadt }
150df930be7Sderaadt 
151f303ad03Sderaadt int
quotaonoff(struct fstab * fs,int offmode,int type,char * qfpathname)152f303ad03Sderaadt quotaonoff(struct fstab *fs, int offmode, int type, char *qfpathname)
153df930be7Sderaadt {
154df930be7Sderaadt 	if (strcmp(fs->fs_file, "/") && readonly(fs))
155df930be7Sderaadt 		return (1);
156df930be7Sderaadt 	if (offmode) {
157df930be7Sderaadt 		if (quotactl(fs->fs_file, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) {
158df930be7Sderaadt 			fprintf(stderr, "quotaoff: ");
159df930be7Sderaadt 			perror(fs->fs_file);
160df930be7Sderaadt 			return (1);
161df930be7Sderaadt 		}
162df930be7Sderaadt 		if (vflag)
1632908d610Sderaadt 			printf("%s: %s quotas turned off\n", fs->fs_file,
1642908d610Sderaadt 			    qfextension[type]);
165df930be7Sderaadt 		return (0);
166df930be7Sderaadt 	}
167df930be7Sderaadt 	if (quotactl(fs->fs_file, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) {
1682908d610Sderaadt 		warn("%s: %s quotas using %s", fs->fs_file,
1692908d610Sderaadt 		    qfextension[type], qfpathname);
170df930be7Sderaadt 		return (1);
171df930be7Sderaadt 	}
172df930be7Sderaadt 	if (vflag)
173df930be7Sderaadt 		printf("%s: %s quotas turned on\n", fs->fs_file,
174df930be7Sderaadt 		    qfextension[type]);
175df930be7Sderaadt 	return (0);
176df930be7Sderaadt }
177df930be7Sderaadt 
178df930be7Sderaadt /*
179df930be7Sderaadt  * Check to see if target appears in list of size cnt.
180df930be7Sderaadt  */
181f303ad03Sderaadt int
oneof(char * target,char * list[],int cnt)182f303ad03Sderaadt oneof(char *target, char *list[], int cnt)
183df930be7Sderaadt {
1840ac0d02eSmpech 	int i;
185df930be7Sderaadt 
186df930be7Sderaadt 	for (i = 0; i < cnt; i++)
187df930be7Sderaadt 		if (strcmp(target, list[i]) == 0)
188df930be7Sderaadt 			return (i);
189df930be7Sderaadt 	return (-1);
190df930be7Sderaadt }
191df930be7Sderaadt 
192df930be7Sderaadt /*
193df930be7Sderaadt  * Check to see if a particular quota is to be enabled.
194df930be7Sderaadt  */
195f303ad03Sderaadt int
hasquota(struct fstab * fs,int type,char ** qfnamep,int force)196f303ad03Sderaadt hasquota(struct fstab *fs, int type, char **qfnamep, int force)
197df930be7Sderaadt {
1980ac0d02eSmpech 	char *opt;
199180acc8fSmillert 	char *cp;
200df930be7Sderaadt 	static char initname, usrname[100], grpname[100];
201df930be7Sderaadt 	static char buf[BUFSIZ];
202df930be7Sderaadt 
203df930be7Sderaadt 	if (!initname) {
204ead3e1caSderaadt 		snprintf(usrname, sizeof usrname, "%s%s",
205ead3e1caSderaadt 		    qfextension[USRQUOTA], qfname);
206ead3e1caSderaadt 		snprintf(grpname, sizeof grpname, "%s%s",
207ead3e1caSderaadt 		    qfextension[GRPQUOTA], qfname);
208df930be7Sderaadt 		initname = 1;
209df930be7Sderaadt 	}
2102261d3e1Sderaadt 	strlcpy(buf, fs->fs_mntops, sizeof buf);
211df930be7Sderaadt 	for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
212691c72f0Sdhill 		if ((cp = strchr(opt, '=')) != NULL)
213df930be7Sderaadt 			*cp++ = '\0';
214df930be7Sderaadt 		if (type == USRQUOTA && strcmp(opt, usrname) == 0)
215df930be7Sderaadt 			break;
216df930be7Sderaadt 		if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
217df930be7Sderaadt 			break;
218df930be7Sderaadt 	}
219c25ff6d6Sdm 	if (!force && !opt)
220df930be7Sderaadt 		return (0);
221df930be7Sderaadt 	if (cp) {
222df930be7Sderaadt 		*qfnamep = cp;
223df930be7Sderaadt 		return (1);
224df930be7Sderaadt 	}
225ead3e1caSderaadt 	(void) snprintf(buf, sizeof buf, "%s/%s.%s", fs->fs_file,
226ead3e1caSderaadt 	    qfname, qfextension[type]);
227df930be7Sderaadt 	*qfnamep = buf;
228df930be7Sderaadt 	return (1);
229df930be7Sderaadt }
230df930be7Sderaadt 
231df930be7Sderaadt /*
232df930be7Sderaadt  * Verify file system is mounted and not readonly.
233dde99675Sderaadt  * MFS is special -- it puts "mfs:" in the kernel's mount table
234df930be7Sderaadt  */
235f303ad03Sderaadt int
readonly(struct fstab * fs)236f303ad03Sderaadt readonly(struct fstab *fs)
237df930be7Sderaadt {
238df930be7Sderaadt 	struct statfs fsbuf;
239df930be7Sderaadt 
240df930be7Sderaadt 	if (statfs(fs->fs_file, &fsbuf) < 0 ||
241df930be7Sderaadt 	    strcmp(fsbuf.f_mntonname, fs->fs_file) ||
242df930be7Sderaadt 	    strcmp(fsbuf.f_mntfromname, fs->fs_spec)) {
243dde99675Sderaadt 		if (strcmp(fs->fs_file, "mfs") ||
244dde99675Sderaadt 		    memcmp(fsbuf.f_mntfromname, "mfs:", sizeof("mfs:")-1))
245dde99675Sderaadt 			;
246dde99675Sderaadt 		else {
247df930be7Sderaadt 			printf("%s: not mounted\n", fs->fs_file);
248df930be7Sderaadt 			return (1);
249df930be7Sderaadt 		}
250dde99675Sderaadt 	}
251df930be7Sderaadt 	if (fsbuf.f_flags & MNT_RDONLY) {
252df930be7Sderaadt 		printf("%s: mounted read-only\n", fs->fs_file);
253df930be7Sderaadt 		return (1);
254df930be7Sderaadt 	}
255df930be7Sderaadt 	return (0);
256df930be7Sderaadt }
257