xref: /netbsd-src/usr.sbin/quotaon/quotaon.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: quotaon.c,v 1.27 2011/09/30 22:08:20 jym Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Robert Elz at The University of Melbourne.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\
38  The Regents of the University of California.  All rights reserved.");
39 #endif /* not lint */
40 
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)quotaon.c	8.1 (Berkeley) 6/6/93";
44 #else
45 __RCSID("$NetBSD: quotaon.c,v 1.27 2011/09/30 22:08:20 jym Exp $");
46 #endif
47 #endif /* not lint */
48 
49 /*
50  * Turn quota on/off for a filesystem.
51  */
52 #include <sys/param.h>
53 #include <sys/file.h>
54 #include <sys/mount.h>
55 
56 #include <quota/quotaprop.h>
57 #include <ufs/ufs/quota1.h>
58 #include <sys/quota.h>
59 
60 
61 #include <err.h>
62 #include <fstab.h>
63 #include <stdio.h>
64 #include <errno.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68 
69 #include "quotautil.h"
70 
71 static int	aflag;		/* all file systems */
72 static int	gflag;		/* operate on group quotas */
73 static int	uflag;		/* operate on user quotas */
74 static int	vflag;		/* verbose */
75 
76 static void usage(void) __attribute__((__noreturn__));
77 static int quotaonoff(struct fstab *, int, int, const char *);
78 static int readonly(struct fstab *);
79 
80 int
81 main(int argc, char *argv[])
82 {
83 	struct fstab *fs;
84 	char qfnp[MAXPATHLEN];
85 	long argnum, done = 0;
86 	int i, offmode = 0, errs = 0;
87 	int ch;
88 
89 	if (strcmp(getprogname(), "quotaoff") == 0)
90 		offmode++;
91 	else if (strcmp(getprogname(), "quotaon") != 0)
92 		errx(1, "Name must be quotaon or quotaoff");
93 
94 	while ((ch = getopt(argc, argv, "avug")) != -1) {
95 		switch(ch) {
96 		case 'a':
97 			aflag++;
98 			break;
99 		case 'g':
100 			gflag++;
101 			break;
102 		case 'u':
103 			uflag++;
104 			break;
105 		case 'v':
106 			vflag++;
107 			break;
108 		default:
109 			usage();
110 			break;
111 		}
112 	}
113 	argc -= optind;
114 	argv += optind;
115 
116 	if (argc <= 0 && !aflag)
117 		usage();
118 
119 	if (!gflag && !uflag) {
120 		gflag++;
121 		uflag++;
122 	}
123 	setfsent();
124 	while ((fs = getfsent()) != NULL) {
125 		if ((strcmp(fs->fs_vfstype, "ffs") &&
126 		     strcmp(fs->fs_vfstype, "lfs")) ||
127 		    strcmp(fs->fs_type, FSTAB_RW))
128 			continue;
129 		if (aflag) {
130 			if (gflag && hasquota(qfnp, sizeof(qfnp), fs, GRPQUOTA))
131 				errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
132 			if (uflag && hasquota(qfnp, sizeof(qfnp), fs, USRQUOTA))
133 				errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
134 			continue;
135 		}
136 		if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
137 		    (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
138 			done |= 1U << argnum;
139 			if (gflag && hasquota(qfnp, sizeof(qfnp), fs, GRPQUOTA))
140 				errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
141 			if (uflag && hasquota(qfnp, sizeof(qfnp), fs, USRQUOTA))
142 				errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
143 		}
144 	}
145 	endfsent();
146 	for (i = 0; i < argc; i++)
147 		if ((done & (1U << i)) == 0)
148 			warnx("%s not found in fstab", argv[i]);
149 	return errs;
150 }
151 
152 static void
153 usage(void)
154 {
155 	const char *p = getprogname();
156 	(void) fprintf(stderr, "Usage: %s [-g] [-u] [-v] -a\n"
157 	    "\t%s [-g] [-u] [-v] filesys ...\n", p, p);
158 	exit(1);
159 }
160 
161 static int
162 quotaonoff( struct fstab *fs, int offmode, int type, const char *qfpathname)
163 {
164 	const char *mode = (offmode == 1) ? "off" : "on";
165 	prop_dictionary_t dict, data, cmd;
166 	prop_array_t cmds, datas;
167 	struct plistref pref;
168 	int8_t error8;
169 
170 	dict = quota_prop_create();
171 	cmds = prop_array_create();
172 	datas = prop_array_create();
173 
174 	if (strcmp(fs->fs_file, "/") && readonly(fs))
175 		return 1;
176 
177 	if (dict == NULL || cmds == NULL || datas == NULL)
178 		errx(1, "can't allocate proplist");
179 
180 	if (offmode) {
181 		if (!quota_prop_add_command(cmds, "quotaoff",
182 		    qfextension[type], datas))
183 			err(1, "prop_add_command");
184 	} else {
185 		data = prop_dictionary_create();
186 		if (data == NULL)
187 			errx(1, "can't allocate proplist");
188 		if (!prop_dictionary_set_cstring(data, "quotafile",
189 		    qfpathname))
190 			err(1, "prop_dictionary_set(quotafile)");
191 		if (!prop_array_add_and_rel(datas, data))
192 			err(1, "prop_array_add(data)");
193 		if (!quota_prop_add_command(cmds, "quotaon",
194 		    qfextension[type], datas))
195 			err(1, "prop_add_command");
196 	}
197 	if (!prop_dictionary_set(dict, "commands", cmds))
198 		err(1, "prop_dictionary_set(command)");
199 
200 	if (prop_dictionary_send_syscall(dict, &pref) != 0)
201 		err(1, "prop_dictionary_send_syscall");
202 	prop_object_release(dict);
203 
204 	if (quotactl(fs->fs_file, &pref) != 0) {
205 		warn("quotactl(%s)", fs->fs_file);
206 		return(1);
207 	}
208 
209 	if (prop_dictionary_recv_syscall(&pref, &dict) != 0)
210 		err(1, "prop_dictionary_recv_syscall");
211 
212 	if ((errno = quota_get_cmds(dict, &cmds)) != 0)
213 		err(1, "quota_get_cmds");
214 
215 	/* only one command, no need to iter */
216 	cmd = prop_array_get(cmds, 0);
217 	if (cmd == NULL)
218 		err(1, "prop_array_get(cmd)");
219 
220 	if (!prop_dictionary_get_int8(cmd, "return", &error8))
221 		err(1, "prop_get(return)");
222 
223 	if (error8) {
224 		errno = error8;
225 		warn("quota%s for %s", mode, fs->fs_file);
226 		return 1;
227 	}
228 
229 	if (vflag) {
230 		printf("%s: %s quotas turned %s\n",
231 		    fs->fs_file, qfextension[type], mode);
232 	}
233 	return 0;
234 }
235 
236 /*
237  * Verify file system is mounted and not readonly.
238  */
239 static int
240 readonly(struct fstab *fs)
241 {
242 	struct statvfs fsbuf;
243 
244 	if (statvfs(fs->fs_file, &fsbuf) < 0 ||
245 	    strcmp(fsbuf.f_mntonname, fs->fs_file) ||
246 	    strcmp(fsbuf.f_mntfromname, fs->fs_spec)) {
247 		printf("%s: not mounted\n", fs->fs_file);
248 		return 1;
249 	}
250 	if (fsbuf.f_flag & MNT_RDONLY) {
251 		printf("%s: mounted read-only\n", fs->fs_file);
252 		return 1;
253 	}
254 	return 0;
255 }
256