1df930be7Sderaadt /*
2df930be7Sderaadt * Copyright (c) 1980, 1990, 1993
3df930be7Sderaadt * The Regents of the University of California. All rights reserved.
4df930be7Sderaadt *
5df930be7Sderaadt * This code is derived from software contributed to Berkeley by
6df930be7Sderaadt * Robert Elz at The University of Melbourne.
7df930be7Sderaadt *
8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt * modification, are permitted provided that the following conditions
10df930be7Sderaadt * are met:
11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt * documentation and/or other materials provided with the distribution.
1629295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt * may be used to endorse or promote products derived from this software
18df930be7Sderaadt * without specific prior written permission.
19df930be7Sderaadt *
20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt * SUCH DAMAGE.
31df930be7Sderaadt */
32df930be7Sderaadt
33df930be7Sderaadt /*
34df930be7Sderaadt * Turn quota on/off for a filesystem.
35df930be7Sderaadt */
36*f4147939Sguenther #include <sys/types.h>
37df930be7Sderaadt #include <sys/mount.h>
38df930be7Sderaadt #include <ufs/ufs/quota.h>
39*f4147939Sguenther
40b5a78835Sdavid #include <err.h>
41df930be7Sderaadt #include <stdio.h>
42b5a78835Sdavid #include <stdlib.h>
43df930be7Sderaadt #include <string.h>
44df930be7Sderaadt #include <fstab.h>
45b5a78835Sdavid #include <unistd.h>
46df930be7Sderaadt
47df930be7Sderaadt char *qfname = QUOTAFILENAME;
4895709839Sderaadt char *qfextension[] = INITQFNAMES;
49df930be7Sderaadt
50df930be7Sderaadt int aflag; /* all file systems */
51df930be7Sderaadt int gflag; /* operate on group quotas */
52df930be7Sderaadt int uflag; /* operate on user quotas */
53df930be7Sderaadt int vflag; /* verbose */
54df930be7Sderaadt
55d2c62849Sderaadt void usage(char *whoami);
56d2c62849Sderaadt int hasquota(struct fstab *fs, int type, char **qfnamep, int force);
57d2c62849Sderaadt int quotaonoff(struct fstab *fs, int offmode, int type, char *qfpathname);
58d2c62849Sderaadt int oneof(char *target, char *list[], int cnt);
59d2c62849Sderaadt int readonly(struct fstab *fs);
60d2c62849Sderaadt
61d2c62849Sderaadt
62d2c62849Sderaadt int
main(int argc,char * argv[])63f303ad03Sderaadt main(int argc, char *argv[])
64df930be7Sderaadt {
650ac0d02eSmpech struct fstab *fs;
66180acc8fSmillert char *qfnp, *whoami;
67df930be7Sderaadt long argnum, done = 0;
68df930be7Sderaadt int i, offmode = 0, errs = 0;
69f3bae140Sderaadt int ch;
70df930be7Sderaadt
71180acc8fSmillert whoami = strrchr(*argv, '/') + 1;
72df930be7Sderaadt if (whoami == (char *)1)
73df930be7Sderaadt whoami = *argv;
74df930be7Sderaadt if (strcmp(whoami, "quotaoff") == 0)
7528056f30Sderaadt offmode = 1;
76df930be7Sderaadt else if (strcmp(whoami, "quotaon") != 0) {
77df930be7Sderaadt fprintf(stderr, "Name must be quotaon or quotaoff not %s\n",
78df930be7Sderaadt whoami);
79df930be7Sderaadt exit(1);
80df930be7Sderaadt }
81f3bae140Sderaadt while ((ch = getopt(argc, argv, "avug")) != -1) {
82df930be7Sderaadt switch (ch) {
83df930be7Sderaadt case 'a':
8428056f30Sderaadt aflag = 1;
85df930be7Sderaadt break;
86df930be7Sderaadt case 'g':
8728056f30Sderaadt gflag = 1;
88df930be7Sderaadt break;
89df930be7Sderaadt case 'u':
9028056f30Sderaadt uflag = 1;
91df930be7Sderaadt break;
92df930be7Sderaadt case 'v':
9328056f30Sderaadt vflag = 1;
94df930be7Sderaadt break;
95df930be7Sderaadt default:
96df930be7Sderaadt usage(whoami);
97df930be7Sderaadt }
98df930be7Sderaadt }
99df930be7Sderaadt argc -= optind;
100df930be7Sderaadt argv += optind;
101df930be7Sderaadt if (argc <= 0 && !aflag)
102df930be7Sderaadt usage(whoami);
103df930be7Sderaadt if (!gflag && !uflag) {
10428056f30Sderaadt gflag = 1;
10528056f30Sderaadt uflag = 1;
106df930be7Sderaadt }
107df930be7Sderaadt setfsent();
108df930be7Sderaadt while ((fs = getfsent()) != NULL) {
109e5cb37d1Sderaadt if (strcmp(fs->fs_type, FSTAB_RW))
110e5cb37d1Sderaadt continue;
111e5cb37d1Sderaadt if (strcmp(fs->fs_vfstype, "ffs") &&
112dde99675Sderaadt strcmp(fs->fs_vfstype, "ufs") &&
113dde99675Sderaadt strcmp(fs->fs_vfstype, "mfs"))
114df930be7Sderaadt continue;
115df930be7Sderaadt if (aflag) {
116c25ff6d6Sdm if (gflag && hasquota(fs, GRPQUOTA, &qfnp, 0))
117df930be7Sderaadt errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
118c25ff6d6Sdm if (uflag && hasquota(fs, USRQUOTA, &qfnp, 0))
119df930be7Sderaadt errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
120df930be7Sderaadt continue;
121df930be7Sderaadt }
122df930be7Sderaadt if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
123df930be7Sderaadt (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
124df930be7Sderaadt done |= 1 << argnum;
125c25ff6d6Sdm if (gflag) {
126c25ff6d6Sdm hasquota(fs, GRPQUOTA, &qfnp, 1);
127df930be7Sderaadt errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
128c25ff6d6Sdm }
129c25ff6d6Sdm if (uflag) {
130c25ff6d6Sdm hasquota(fs, USRQUOTA, &qfnp, 1);
131df930be7Sderaadt errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
132df930be7Sderaadt }
133df930be7Sderaadt }
134c25ff6d6Sdm }
135df930be7Sderaadt endfsent();
136df930be7Sderaadt for (i = 0; i < argc; i++)
137df930be7Sderaadt if ((done & (1 << i)) == 0)
138df930be7Sderaadt fprintf(stderr, "%s not found in fstab\n",
139df930be7Sderaadt argv[i]);
140df930be7Sderaadt exit(errs);
141df930be7Sderaadt }
142df930be7Sderaadt
143d2c62849Sderaadt void
usage(char * whoami)144f303ad03Sderaadt usage(char *whoami)
145df930be7Sderaadt {
146df930be7Sderaadt
1475a543052Sjmc fprintf(stderr, "usage: %s [-aguv] filesystem ...\n", whoami);
148df930be7Sderaadt exit(1);
149df930be7Sderaadt }
150df930be7Sderaadt
151f303ad03Sderaadt int
quotaonoff(struct fstab * fs,int offmode,int type,char * qfpathname)152f303ad03Sderaadt quotaonoff(struct fstab *fs, int offmode, int type, char *qfpathname)
153df930be7Sderaadt {
154df930be7Sderaadt if (strcmp(fs->fs_file, "/") && readonly(fs))
155df930be7Sderaadt return (1);
156df930be7Sderaadt if (offmode) {
157df930be7Sderaadt if (quotactl(fs->fs_file, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) {
158df930be7Sderaadt fprintf(stderr, "quotaoff: ");
159df930be7Sderaadt perror(fs->fs_file);
160df930be7Sderaadt return (1);
161df930be7Sderaadt }
162df930be7Sderaadt if (vflag)
1632908d610Sderaadt printf("%s: %s quotas turned off\n", fs->fs_file,
1642908d610Sderaadt qfextension[type]);
165df930be7Sderaadt return (0);
166df930be7Sderaadt }
167df930be7Sderaadt if (quotactl(fs->fs_file, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) {
1682908d610Sderaadt warn("%s: %s quotas using %s", fs->fs_file,
1692908d610Sderaadt qfextension[type], qfpathname);
170df930be7Sderaadt return (1);
171df930be7Sderaadt }
172df930be7Sderaadt if (vflag)
173df930be7Sderaadt printf("%s: %s quotas turned on\n", fs->fs_file,
174df930be7Sderaadt qfextension[type]);
175df930be7Sderaadt return (0);
176df930be7Sderaadt }
177df930be7Sderaadt
178df930be7Sderaadt /*
179df930be7Sderaadt * Check to see if target appears in list of size cnt.
180df930be7Sderaadt */
181f303ad03Sderaadt int
oneof(char * target,char * list[],int cnt)182f303ad03Sderaadt oneof(char *target, char *list[], int cnt)
183df930be7Sderaadt {
1840ac0d02eSmpech int i;
185df930be7Sderaadt
186df930be7Sderaadt for (i = 0; i < cnt; i++)
187df930be7Sderaadt if (strcmp(target, list[i]) == 0)
188df930be7Sderaadt return (i);
189df930be7Sderaadt return (-1);
190df930be7Sderaadt }
191df930be7Sderaadt
192df930be7Sderaadt /*
193df930be7Sderaadt * Check to see if a particular quota is to be enabled.
194df930be7Sderaadt */
195f303ad03Sderaadt int
hasquota(struct fstab * fs,int type,char ** qfnamep,int force)196f303ad03Sderaadt hasquota(struct fstab *fs, int type, char **qfnamep, int force)
197df930be7Sderaadt {
1980ac0d02eSmpech char *opt;
199180acc8fSmillert char *cp;
200df930be7Sderaadt static char initname, usrname[100], grpname[100];
201df930be7Sderaadt static char buf[BUFSIZ];
202df930be7Sderaadt
203df930be7Sderaadt if (!initname) {
204ead3e1caSderaadt snprintf(usrname, sizeof usrname, "%s%s",
205ead3e1caSderaadt qfextension[USRQUOTA], qfname);
206ead3e1caSderaadt snprintf(grpname, sizeof grpname, "%s%s",
207ead3e1caSderaadt qfextension[GRPQUOTA], qfname);
208df930be7Sderaadt initname = 1;
209df930be7Sderaadt }
2102261d3e1Sderaadt strlcpy(buf, fs->fs_mntops, sizeof buf);
211df930be7Sderaadt for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
212691c72f0Sdhill if ((cp = strchr(opt, '=')) != NULL)
213df930be7Sderaadt *cp++ = '\0';
214df930be7Sderaadt if (type == USRQUOTA && strcmp(opt, usrname) == 0)
215df930be7Sderaadt break;
216df930be7Sderaadt if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
217df930be7Sderaadt break;
218df930be7Sderaadt }
219c25ff6d6Sdm if (!force && !opt)
220df930be7Sderaadt return (0);
221df930be7Sderaadt if (cp) {
222df930be7Sderaadt *qfnamep = cp;
223df930be7Sderaadt return (1);
224df930be7Sderaadt }
225ead3e1caSderaadt (void) snprintf(buf, sizeof buf, "%s/%s.%s", fs->fs_file,
226ead3e1caSderaadt qfname, qfextension[type]);
227df930be7Sderaadt *qfnamep = buf;
228df930be7Sderaadt return (1);
229df930be7Sderaadt }
230df930be7Sderaadt
231df930be7Sderaadt /*
232df930be7Sderaadt * Verify file system is mounted and not readonly.
233dde99675Sderaadt * MFS is special -- it puts "mfs:" in the kernel's mount table
234df930be7Sderaadt */
235f303ad03Sderaadt int
readonly(struct fstab * fs)236f303ad03Sderaadt readonly(struct fstab *fs)
237df930be7Sderaadt {
238df930be7Sderaadt struct statfs fsbuf;
239df930be7Sderaadt
240df930be7Sderaadt if (statfs(fs->fs_file, &fsbuf) < 0 ||
241df930be7Sderaadt strcmp(fsbuf.f_mntonname, fs->fs_file) ||
242df930be7Sderaadt strcmp(fsbuf.f_mntfromname, fs->fs_spec)) {
243dde99675Sderaadt if (strcmp(fs->fs_file, "mfs") ||
244dde99675Sderaadt memcmp(fsbuf.f_mntfromname, "mfs:", sizeof("mfs:")-1))
245dde99675Sderaadt ;
246dde99675Sderaadt else {
247df930be7Sderaadt printf("%s: not mounted\n", fs->fs_file);
248df930be7Sderaadt return (1);
249df930be7Sderaadt }
250dde99675Sderaadt }
251df930be7Sderaadt if (fsbuf.f_flags & MNT_RDONLY) {
252df930be7Sderaadt printf("%s: mounted read-only\n", fs->fs_file);
253df930be7Sderaadt return (1);
254df930be7Sderaadt }
255df930be7Sderaadt return (0);
256df930be7Sderaadt }
257