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