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