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