xref: /illumos-gate/usr/src/cmd/fs.d/ufs/quotaon/quotaon.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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
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
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
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
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
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, &quota);
324 	close(fd);
325 	return (status);
326 }
327 
328 char *
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
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