1/*
2 * Copyright (c) 1999, 2002, 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright (c) 1980, 1990, 1993
25 *	The Regents of the University of California.  All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Robert Elz at The University of Melbourne.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 *    notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in the
37 *    documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 *    must display the following acknowledgement:
40 *	This product includes software developed by the University of
41 *	California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 *    may be used to endorse or promote products derived from this software
44 *    without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58
59#include <sys/cdefs.h>
60
61#ifndef lint
62__unused static char copyright[] =
63"@(#) Copyright (c) 1980, 1990, 1993\n\
64	The Regents of the University of California.  All rights reserved.\n";
65#endif /* not lint */
66
67#ifndef lint
68__unused static char sccsid[] = "@(#)quotaon.c	8.1 (Berkeley) 6/6/93";
69#endif /* not lint */
70
71/*
72 * Turn quota on/off for a filesystem.
73 */
74#include <sys/param.h>
75#include <sys/file.h>
76#include <sys/mount.h>
77#ifdef __APPLE__
78#include <sys/stat.h>
79#endif /* __APPLE__ */
80#include <sys/appleapiopts.h>
81#include <sys/quota.h>
82#include <stdio.h>
83#include <fstab.h>
84#include <string.h>
85#include <stdlib.h>
86#include <unistd.h>
87
88/* Internal functions */
89void usage(char *whoami);
90
91char *qfname = QUOTAFILENAME;
92char *qfextension[] = INITQFNAMES;
93
94int	aflag;		/* all file systems */
95int	gflag;		/* operate on group quotas */
96int	uflag;		/* operate on user quotas */
97int	vflag;		/* verbose */
98
99/* Function prototypes */
100#ifdef __APPLE__
101int hasquota(register struct statfs *, int, char **);
102int quotaonoff(register struct statfs *, int, int, char *);
103#else
104int hasquota(register struct fstab *, int, char **);
105int quotaonoff(register struct fstab *, int, int, char *);
106#endif /* __APPLE__ */
107
108int oneof(register char *, register char **, int);
109
110int main(argc, argv)
111	int argc;
112	char **argv;
113{
114	char ch, *qfnp, *whoami, *rindex();
115	long argnum, done = 0;
116	int i, offmode = 0, errs = 0;
117#ifdef __APPLE__
118	int nfst;
119	struct statfs *fst;
120#endif /* __APPLE__ */
121
122	whoami = rindex(*argv, '/') + 1;
123	if (whoami == (char *)1)
124		whoami = *argv;
125	if (strcmp(whoami, "quotaoff") == 0)
126		offmode++;
127	else if (strcmp(whoami, "quotaon") != 0) {
128		fprintf(stderr, "Name must be quotaon or quotaoff not %s\n",
129			whoami);
130		exit(1);
131	}
132	while ((ch = getopt(argc, argv, "avug")) != EOF) {
133		switch(ch) {
134		case 'a':
135			aflag++;
136			break;
137		case 'g':
138			gflag++;
139			break;
140		case 'u':
141			uflag++;
142			break;
143		case 'v':
144			vflag++;
145			break;
146		default:
147			usage(whoami);
148		}
149	}
150	argc -= optind;
151	argv += optind;
152	if (argc <= 0 && !aflag)
153		usage(whoami);
154	if (!gflag && !uflag) {
155		gflag++;
156		uflag++;
157	}
158
159#ifdef __APPLE__
160	nfst = getmntinfo(&fst, MNT_WAIT);
161	if (nfst==0) {
162	  fprintf(stderr, "no filesystems mounted");
163	  return(1);
164	}
165
166	for (i=0; i<nfst; i++) {
167	  if(strcmp(fst[i].f_fstypename, "hfs")) {
168	      continue;
169	  }
170	  if(fst[i].f_flags & MNT_RDONLY) {
171	    errs++;
172	    continue;
173	  }
174
175	  if (aflag) {
176	    if (gflag && hasquota(&fst[i], GRPQUOTA, &qfnp))
177	      errs += quotaonoff(&fst[i], offmode, GRPQUOTA, qfnp);
178	    if (uflag && hasquota(&fst[i], USRQUOTA, &qfnp))
179	      errs += quotaonoff(&fst[i], offmode, USRQUOTA, qfnp);
180	    continue;
181	  }
182	  if ((argnum = oneof(fst[i].f_mntonname, argv, argc)) >= 0 ||
183	      (argnum = oneof(fst[i].f_mntfromname, argv, argc)) >= 0) {
184	    done |= 1 << argnum;
185	    if (gflag && hasquota(&fst[i], GRPQUOTA, &qfnp))
186	      errs += quotaonoff(&fst[i], offmode, GRPQUOTA, qfnp);
187	    if (uflag && hasquota(&fst[i], USRQUOTA, &qfnp))
188	      errs += quotaonoff(&fst[i], offmode, USRQUOTA, qfnp);
189	  }
190	}
191#else
192	register struct fstab *fs;
193	setfsent();
194	while ((fs = getfsent()) != NULL) {
195		if (strcmp(fs->fs_vfstype, "ufs") ||
196		    strcmp(fs->fs_type, FSTAB_RW))
197			continue;
198		if (aflag) {
199			if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
200				errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
201			if (uflag && hasquota(fs, USRQUOTA, &qfnp))
202				errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
203			continue;
204		}
205		if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
206		    (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
207			done |= 1 << argnum;
208			if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
209				errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
210			if (uflag && hasquota(fs, USRQUOTA, &qfnp))
211				errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
212		}
213	}
214	endfsent();
215#endif /* __APPLE__ */
216	for (i = 0; i < argc; i++)
217		if ((done & (1 << i)) == 0)
218			fprintf(stderr, "%s not found in fstab\n",
219				argv[i]);
220	exit(errs);
221}
222
223void usage(whoami)
224	char *whoami;
225{
226
227	fprintf(stderr, "Usage:\n\t%s [-g] [-u] [-v] -a\n", whoami);
228	fprintf(stderr, "\t%s [-g] [-u] [-v] filesys ...\n", whoami);
229	exit(1);
230}
231
232#ifdef __APPLE__
233int quotaonoff(fst, offmode, type, qfpathname)
234	register struct statfs *fst;
235	int offmode, type;
236	char *qfpathname;
237{
238        if (strcmp(fst->f_mntonname, "/") && (fst->f_flags & MNT_RDONLY))
239		return (1);
240	if (offmode) {
241		if (quotactl(fst->f_mntonname, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) {
242			fprintf(stderr, "quotaoff: ");
243			perror(fst->f_mntonname);
244			return (1);
245		}
246		if (vflag)
247		  printf("%s: %s quotas turned off\n", fst->f_mntonname,
248			       qfextension[type]);
249		return (0);
250	}
251	if (quotactl(fst->f_mntonname, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) {
252		fprintf(stderr, "quotaon: using %s on ", qfpathname);
253		perror(fst->f_mntonname);
254		return (1);
255	}
256	if (vflag)
257		printf("%s: %s quotas turned on\n", fst->f_mntonname,
258		    qfextension[type]);
259	return (0);
260}
261#else
262int quotaonoff(fs, offmode, type, qfpathname)
263	register struct fstab *fs;
264	int offmode, type;
265	char *qfpathname;
266{
267
268	if (strcmp(fs->fs_file, "/") && readonly(fs))
269		return (1);
270	if (offmode) {
271		if (quotactl(fs->fs_file, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) {
272			fprintf(stderr, "quotaoff: ");
273			perror(fs->fs_file);
274			return (1);
275		}
276		if (vflag)
277			printf("%s: quotas turned off\n", fs->fs_file);
278		return (0);
279	}
280	if (quotactl(fs->fs_file, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) {
281		fprintf(stderr, "quotaon: using %s on", qfpathname);
282		perror(fs->fs_file);
283		return (1);
284	}
285	if (vflag)
286		printf("%s: %s quotas turned on\n", fs->fs_file,
287		    qfextension[type]);
288	return (0);
289}
290#endif /* __APPLE__ */
291
292/*
293 * Check to see if target appears in list of size cnt.
294 */
295int oneof(target, list, cnt)
296	register char *target, *list[];
297	int cnt;
298{
299	register int i;
300
301	for (i = 0; i < cnt; i++)
302		if (strcmp(target, list[i]) == 0)
303			return (i);
304	return (-1);
305}
306
307/*
308 * Check to see if a particular quota is to be enabled.
309 */
310#ifdef __APPLE__
311int hasquota(fst, type, qfnamep)
312	register struct statfs *fst;
313	int type;
314	char **qfnamep;
315{
316	struct stat sb;
317	static char initname, usrname[100], grpname[100];
318	static char buf[BUFSIZ];
319
320	if (!initname) {
321		snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
322		snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
323		initname = 1;
324	}
325
326        /*
327	  We only support the default path to the
328	  on disk quota files.
329	*/
330
331        (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname,
332		      QUOTAOPSNAME, qfextension[type] );
333        if (stat(buf, &sb) != 0) {
334          /* There appears to be no mount option file */
335          return(0);
336        }
337
338
339	(void) snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]);
340	*qfnamep = buf;
341	return (1);
342}
343#else
344int hasquota(fs, type, qfnamep)
345	register struct fstab *fs;
346	int type;
347	char **qfnamep;
348{
349	register char *opt;
350	char *cp, *index(), *strtok();
351	static char initname, usrname[100], grpname[100];
352	static char buf[BUFSIZ];
353
354	if (!initname) {
355		snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
356		snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
357		initname = 1;
358	}
359	strlcpy(buf, fs->fs_mntops, sizeof(buf));
360	for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
361		if (cp = index(opt, '='))
362			*cp++ = '\0';
363		if (type == USRQUOTA && strcmp(opt, usrname) == 0)
364			break;
365		if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
366			break;
367	}
368	if (!opt)
369		return (0);
370	if (cp) {
371		*qfnamep = cp;
372		return (1);
373	}
374	(void) snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
375	*qfnamep = buf;
376	return (1);
377}
378#endif /* __APPLE__ */
379
380
381/*
382 * Verify file system is mounted and not readonly.
383 */
384int readonly(fs)
385	register struct fstab *fs;
386{
387	struct statfs fsbuf;
388
389	if (statfs(fs->fs_file, &fsbuf) < 0 ||
390	    strcmp(fsbuf.f_mntonname, fs->fs_file) ||
391	    strcmp(fsbuf.f_mntfromname, fs->fs_spec)) {
392		printf("%s: not mounted\n", fs->fs_file);
393		return (1);
394	}
395	if (fsbuf.f_flags & MNT_RDONLY) {
396		printf("%s: mounted read-only\n", fs->fs_file);
397		return (1);
398	}
399	return (0);
400}
401