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