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