quotaon.c revision 1.28 1 /* $NetBSD: quotaon.c,v 1.28 2012/01/25 01:28:40 dholland 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.28 2012/01/25 01:28:40 dholland 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) __dead;
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