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/param.h> 37 #include <sys/file.h> 38 #include <sys/mount.h> 39 #include <ufs/ufs/quota.h> 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 extern int optind; 70 int ch; 71 72 whoami = strrchr(*argv, '/') + 1; 73 if (whoami == (char *)1) 74 whoami = *argv; 75 if (strcmp(whoami, "quotaoff") == 0) 76 offmode++; 77 else if (strcmp(whoami, "quotaon") != 0) { 78 fprintf(stderr, "Name must be quotaon or quotaoff not %s\n", 79 whoami); 80 exit(1); 81 } 82 while ((ch = getopt(argc, argv, "avug")) != -1) { 83 switch (ch) { 84 case 'a': 85 aflag++; 86 break; 87 case 'g': 88 gflag++; 89 break; 90 case 'u': 91 uflag++; 92 break; 93 case 'v': 94 vflag++; 95 break; 96 default: 97 usage(whoami); 98 } 99 } 100 argc -= optind; 101 argv += optind; 102 if (argc <= 0 && !aflag) 103 usage(whoami); 104 if (!gflag && !uflag) { 105 gflag++; 106 uflag++; 107 } 108 setfsent(); 109 while ((fs = getfsent()) != NULL) { 110 if (strcmp(fs->fs_type, FSTAB_RW)) 111 continue; 112 if (strcmp(fs->fs_vfstype, "ffs") && 113 strcmp(fs->fs_vfstype, "ufs") && 114 strcmp(fs->fs_vfstype, "mfs")) 115 continue; 116 if (aflag) { 117 if (gflag && hasquota(fs, GRPQUOTA, &qfnp, 0)) 118 errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp); 119 if (uflag && hasquota(fs, USRQUOTA, &qfnp, 0)) 120 errs += quotaonoff(fs, offmode, USRQUOTA, qfnp); 121 continue; 122 } 123 if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 124 (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) { 125 done |= 1 << argnum; 126 if (gflag) { 127 hasquota(fs, GRPQUOTA, &qfnp, 1); 128 errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp); 129 } 130 if (uflag) { 131 hasquota(fs, USRQUOTA, &qfnp, 1); 132 errs += quotaonoff(fs, offmode, USRQUOTA, qfnp); 133 } 134 } 135 } 136 endfsent(); 137 for (i = 0; i < argc; i++) 138 if ((done & (1 << i)) == 0) 139 fprintf(stderr, "%s not found in fstab\n", 140 argv[i]); 141 exit(errs); 142 } 143 144 void 145 usage(char *whoami) 146 { 147 148 fprintf(stderr, "usage: %s [-aguv] filesystem ...\n", whoami); 149 exit(1); 150 } 151 152 int 153 quotaonoff(struct fstab *fs, int offmode, int type, char *qfpathname) 154 { 155 if (strcmp(fs->fs_file, "/") && readonly(fs)) 156 return (1); 157 if (offmode) { 158 if (quotactl(fs->fs_file, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) { 159 fprintf(stderr, "quotaoff: "); 160 perror(fs->fs_file); 161 return (1); 162 } 163 if (vflag) 164 printf("%s: %s quotas turned off\n", fs->fs_file, 165 qfextension[type]); 166 return (0); 167 } 168 if (quotactl(fs->fs_file, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) { 169 warn("%s: %s quotas using %s", fs->fs_file, 170 qfextension[type], qfpathname); 171 return (1); 172 } 173 if (vflag) 174 printf("%s: %s quotas turned on\n", fs->fs_file, 175 qfextension[type]); 176 return (0); 177 } 178 179 /* 180 * Check to see if target appears in list of size cnt. 181 */ 182 int 183 oneof(char *target, char *list[], int cnt) 184 { 185 int i; 186 187 for (i = 0; i < cnt; i++) 188 if (strcmp(target, list[i]) == 0) 189 return (i); 190 return (-1); 191 } 192 193 /* 194 * Check to see if a particular quota is to be enabled. 195 */ 196 int 197 hasquota(struct fstab *fs, int type, char **qfnamep, int force) 198 { 199 char *opt; 200 char *cp; 201 static char initname, usrname[100], grpname[100]; 202 static char buf[BUFSIZ]; 203 204 if (!initname) { 205 snprintf(usrname, sizeof usrname, "%s%s", 206 qfextension[USRQUOTA], qfname); 207 snprintf(grpname, sizeof grpname, "%s%s", 208 qfextension[GRPQUOTA], qfname); 209 initname = 1; 210 } 211 strlcpy(buf, fs->fs_mntops, sizeof buf); 212 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 213 if ((cp = strchr(opt, '=')) != NULL) 214 *cp++ = '\0'; 215 if (type == USRQUOTA && strcmp(opt, usrname) == 0) 216 break; 217 if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 218 break; 219 } 220 if (!force && !opt) 221 return (0); 222 if (cp) { 223 *qfnamep = cp; 224 return (1); 225 } 226 (void) snprintf(buf, sizeof buf, "%s/%s.%s", fs->fs_file, 227 qfname, qfextension[type]); 228 *qfnamep = buf; 229 return (1); 230 } 231 232 /* 233 * Verify file system is mounted and not readonly. 234 * MFS is special -- it puts "mfs:" in the kernel's mount table 235 */ 236 int 237 readonly(struct fstab *fs) 238 { 239 struct statfs fsbuf; 240 241 if (statfs(fs->fs_file, &fsbuf) < 0 || 242 strcmp(fsbuf.f_mntonname, fs->fs_file) || 243 strcmp(fsbuf.f_mntfromname, fs->fs_spec)) { 244 if (strcmp(fs->fs_file, "mfs") || 245 memcmp(fsbuf.f_mntfromname, "mfs:", sizeof("mfs:")-1)) 246 ; 247 else { 248 printf("%s: not mounted\n", fs->fs_file); 249 return (1); 250 } 251 } 252 if (fsbuf.f_flags & MNT_RDONLY) { 253 printf("%s: mounted read-only\n", fs->fs_file); 254 return (1); 255 } 256 return (0); 257 } 258