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