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