1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 #pragma ident "%Z%%M% %I% %E% SMI"
40
41 /*
42 * Turn quota on/off for a filesystem.
43 */
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/mntent.h>
48
49 #define bcopy(f, t, n) memcpy(t, f, n)
50 #define bzero(s, n) memset(s, 0, n)
51 #define bcmp(s, d, n) memcmp(s, d, n)
52
53 #define index(s, r) strchr(s, r)
54 #define rindex(s, r) strrchr(s, r)
55
56 #include <string.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <sys/file.h>
60 #include <signal.h>
61 #include <fcntl.h>
62 #include <sys/fs/ufs_quota.h>
63 #include <stdio.h>
64 #include <sys/mnttab.h>
65 #include <errno.h>
66 #include <sys/vfstab.h>
67
68 int vflag; /* verbose */
69 int aflag; /* all file systems */
70
71 #define QFNAME "quotas"
72 #define CHUNK 50
73 char **listbuf;
74 char *mntopt(), *hasvfsopt(), *hasmntopt();
75 char *whoami;
76
77 static void fixmntent();
78 static void mnterror();
79 static void usage(char *);
80 static int oneof();
81 static int quotaonoff();
82 static int quotactl(int, char *, uid_t, caddr_t);
83
84 extern int optind;
85 extern char *optarg;
86
87 int
main(int argc,char ** argv)88 main(int argc, char **argv)
89 {
90 struct mnttab mntp;
91 struct vfstab vfsbuf;
92 char **listp;
93 int listcnt;
94 FILE *mtab, *vfstab, *tmp;
95 int offmode = 0;
96 int listmax = 0;
97 int errs = 0;
98 char *tmpname = "/etc/mnttab.temp";
99 int status;
100 int opt;
101 mode_t oldumask;
102 struct stat statbuf;
103
104 whoami = (char *)rindex(*argv, '/') + 1;
105 if (whoami == (char *)1)
106 whoami = *argv;
107 if (strcmp(whoami, "quotaoff") == 0)
108 offmode++;
109 else if (strcmp(whoami, "quotaon") != 0) {
110 fprintf(stderr, "Name must be quotaon or quotaoff not %s\n",
111 whoami);
112 exit(31+1);
113 }
114 if ((listbuf = (char **)malloc(sizeof (char *) * CHUNK)) == NULL) {
115 fprintf(stderr, "Can't alloc lisbuf array.");
116 exit(31+1);
117 }
118 listmax = CHUNK;
119 while ((opt = getopt(argc, argv, "avV")) != EOF) {
120 switch (opt) {
121
122 case 'v':
123 vflag++;
124 break;
125
126 case 'a':
127 aflag++;
128 break;
129
130 case 'V': /* Print command line */
131 {
132 char *opt_text;
133 int opt_cnt;
134
135 (void) fprintf(stdout, "%s -F UFS ", whoami);
136 for (opt_cnt = 1; opt_cnt < argc; opt_cnt++) {
137 opt_text = argv[opt_cnt];
138 if (opt_text)
139 (void) fprintf(stdout, " %s ",
140 opt_text);
141 }
142 (void) fprintf(stdout, "\n");
143 }
144 break;
145
146 case '?':
147 usage(whoami);
148 }
149 }
150 if (argc <= optind && !aflag) {
151 usage(whoami);
152 }
153 /*
154 * If aflag go through vfstab and make a list of appropriate
155 * filesystems.
156 */
157 if (aflag) {
158
159 listp = listbuf;
160 listcnt = 0;
161
162 vfstab = fopen(VFSTAB, "r");
163 if (vfstab == NULL) {
164 fprintf(stderr, "Can't open %s\n", VFSTAB);
165 perror(VFSTAB);
166 exit(31+1);
167 }
168
169 while ((status = getvfsent(vfstab, &vfsbuf)) == NULL) {
170 if (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) != 0 ||
171 (vfsbuf.vfs_mntopts == 0) ||
172 hasvfsopt(&vfsbuf, MNTOPT_RO) ||
173 (!hasvfsopt(&vfsbuf, MNTOPT_RQ) &&
174 !hasvfsopt(&vfsbuf, MNTOPT_QUOTA)))
175 continue;
176 *listp = malloc(strlen(vfsbuf.vfs_special) + 1);
177 strcpy(*listp, vfsbuf.vfs_special);
178 listp++;
179 listcnt++;
180 /* grow listbuf if needed */
181 if (listcnt >= listmax) {
182 listmax += CHUNK;
183 listbuf = (char **)realloc(listbuf,
184 sizeof (char *) * listmax);
185 if (listbuf == NULL) {
186 fprintf(stderr,
187 "Can't grow listbuf.\n");
188 exit(31+1);
189 }
190 listp = &listbuf[listcnt];
191 }
192 }
193 fclose(vfstab);
194 *listp = (char *)0;
195 listp = listbuf;
196 } else {
197 listp = &argv[optind];
198 listcnt = argc - optind;
199 }
200
201 /*
202 * Open real mnttab
203 */
204 mtab = fopen(MNTTAB, "r");
205 if (mtab == NULL) {
206 fprintf(stderr, "Can't open %s\n", MNTTAB);
207 perror(whoami);
208 exit(31+1);
209 }
210 /* check every entry for validity before we change mnttab */
211 while ((status = getmntent(mtab, &mntp)) == 0)
212 ;
213 if (status > 0)
214 mnterror(status);
215 rewind(mtab);
216
217 signal(SIGHUP, SIG_IGN);
218 signal(SIGQUIT, SIG_IGN);
219 signal(SIGINT, SIG_IGN);
220
221 /*
222 * Loop through mnttab, if a file system gets turned on or off
223 * do the quota call.
224 */
225 while ((status = getmntent(mtab, &mntp)) == NULL) {
226 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) == 0 &&
227 !hasmntopt(&mntp, MNTOPT_RO) &&
228 (oneof(mntp.mnt_special, listp, listcnt) ||
229 oneof(mntp.mnt_mountp, listp, listcnt))) {
230 errs += quotaonoff(&mntp, offmode);
231 }
232 }
233 fclose(mtab);
234
235 while (listcnt--) {
236 if (*listp) {
237 fprintf(stderr, "Cannot do %s\n", *listp);
238 errs++;
239 }
240 listp++;
241 }
242 if (errs > 0)
243 errs += 31;
244 return (errs);
245 }
246
247 int
quotaonoff(struct mnttab * mntp,int offmode)248 quotaonoff(struct mnttab *mntp, int offmode)
249 {
250
251 if (offmode) {
252 if (quotactl(Q_QUOTAOFF, mntp->mnt_mountp, (uid_t)0, NULL) < 0)
253 goto bad;
254 if (vflag)
255 printf("%s: quotas turned off\n", mntp->mnt_mountp);
256 } else {
257 if (quotactl(Q_QUOTAON, mntp->mnt_mountp, (uid_t)0, NULL) <
258 0)
259 goto bad;
260 if (vflag)
261 printf("%s: quotas turned on\n", mntp->mnt_mountp);
262 }
263 return (0);
264 bad:
265 fprintf(stderr, "quotactl: ");
266 perror(mntp->mnt_special);
267 return (1);
268 }
269
270 int
oneof(char * target,char ** olistp,int on)271 oneof(char *target, char **olistp, int on)
272 {
273 int n = on;
274 char **listp = olistp;
275
276 while (n--) {
277 if (*listp && strcmp(target, *listp) == 0) {
278 *listp = (char *)0;
279 return (1);
280 }
281 listp++;
282 }
283 return (0);
284 }
285
286 void
usage(char * whoami)287 usage(char *whoami)
288 {
289
290 fprintf(stderr, "ufs usage:\n");
291 fprintf(stderr, "\t%s [-v] -a\n", whoami);
292 fprintf(stderr, "\t%s [-v] filesys ...\n", whoami);
293 exit(31+1);
294 }
295
296
297 int
quotactl(int cmd,char * mountpt,uid_t uid,caddr_t addr)298 quotactl(int cmd, char *mountpt, uid_t uid, caddr_t addr)
299 {
300 int fd;
301 int status;
302 struct quotctl quota;
303 char qfile[MAXPATHLEN];
304
305 if (mountpt == NULL || mountpt[0] == '\0') {
306 errno = ENOENT;
307 return (-1);
308 }
309 if ((strlcpy(qfile, mountpt, sizeof (qfile)) >= sizeof (qfile)) ||
310 (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >= sizeof (qfile))) {
311 errno = ENOENT;
312 return (-1);
313 }
314 if ((fd = open64(qfile, O_RDWR)) < 0) {
315 fprintf(stderr, "quotactl: %s ", qfile);
316 perror("open");
317 exit(31+1);
318 }
319
320 quota.op = cmd;
321 quota.uid = uid;
322 quota.addr = addr;
323 status = ioctl(fd, Q_QUOTACTL, "a);
324 close(fd);
325 return (status);
326 }
327
328 char *
hasvfsopt(struct vfstab * vfs,char * opt)329 hasvfsopt(struct vfstab *vfs, char *opt)
330 {
331 char *f, *opts;
332 static char *tmpopts;
333
334 if (tmpopts == 0) {
335 tmpopts = (char *)calloc(256, sizeof (char));
336 if (tmpopts == 0)
337 return (0);
338 }
339 strcpy(tmpopts, vfs->vfs_mntopts);
340 opts = tmpopts;
341 f = mntopt(&opts);
342 for (; *f; f = mntopt(&opts)) {
343 if (strncmp(opt, f, strlen(opt)) == 0)
344 return (f - tmpopts + vfs->vfs_mntopts);
345 }
346 return (NULL);
347 }
348
349 void
mnterror(int flag)350 mnterror(int flag)
351 {
352 switch (flag) {
353 case MNT_TOOLONG:
354 fprintf(stderr, "%s: line in mnttab exceeds %d characters\n",
355 whoami, MNT_LINE_MAX-2);
356 break;
357 case MNT_TOOFEW:
358 fprintf(stderr, "%s: line in mnttab has too few entries\n",
359 whoami);
360 break;
361 case MNT_TOOMANY:
362 fprintf(stderr, "%s: line in mnttab has too many entries\n",
363 whoami);
364 break;
365 }
366 exit(1);
367 }
368