1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 /* 40 * Turn quota on/off for a filesystem. 41 */ 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/mntent.h> 46 47 #define bcopy(f, t, n) memcpy(t, f, n) 48 #define bzero(s, n) memset(s, 0, n) 49 #define bcmp(s, d, n) memcmp(s, d, n) 50 51 #define index(s, r) strchr(s, r) 52 #define rindex(s, r) strrchr(s, r) 53 54 #include <string.h> 55 #include <stdlib.h> 56 #include <unistd.h> 57 #include <sys/file.h> 58 #include <signal.h> 59 #include <fcntl.h> 60 #include <sys/fs/ufs_quota.h> 61 #include <stdio.h> 62 #include <sys/mnttab.h> 63 #include <errno.h> 64 #include <sys/vfstab.h> 65 66 int vflag; /* verbose */ 67 int aflag; /* all file systems */ 68 69 #define QFNAME "quotas" 70 #define CHUNK 50 71 char **listbuf; 72 char *mntopt(), *hasvfsopt(), *hasmntopt(); 73 char *whoami; 74 75 static void fixmntent(); 76 static void mnterror(); 77 static void usage(char *); 78 static int oneof(); 79 static int quotaonoff(); 80 static int quotactl(int, char *, uid_t, caddr_t); 81 82 extern int optind; 83 extern char *optarg; 84 85 int 86 main(int argc, char **argv) 87 { 88 struct mnttab mntp; 89 struct vfstab vfsbuf; 90 char **listp; 91 int listcnt; 92 FILE *mtab, *vfstab, *tmp; 93 int offmode = 0; 94 int listmax = 0; 95 int errs = 0; 96 char *tmpname = "/etc/mnttab.temp"; 97 int status; 98 int opt; 99 mode_t oldumask; 100 struct stat statbuf; 101 102 whoami = (char *)rindex(*argv, '/') + 1; 103 if (whoami == (char *)1) 104 whoami = *argv; 105 if (strcmp(whoami, "quotaoff") == 0) 106 offmode++; 107 else if (strcmp(whoami, "quotaon") != 0) { 108 fprintf(stderr, "Name must be quotaon or quotaoff not %s\n", 109 whoami); 110 exit(31+1); 111 } 112 if ((listbuf = (char **)malloc(sizeof (char *) * CHUNK)) == NULL) { 113 fprintf(stderr, "Can't alloc lisbuf array."); 114 exit(31+1); 115 } 116 listmax = CHUNK; 117 while ((opt = getopt(argc, argv, "avV")) != EOF) { 118 switch (opt) { 119 120 case 'v': 121 vflag++; 122 break; 123 124 case 'a': 125 aflag++; 126 break; 127 128 case 'V': /* Print command line */ 129 { 130 char *opt_text; 131 int opt_cnt; 132 133 (void) fprintf(stdout, "%s -F UFS ", whoami); 134 for (opt_cnt = 1; opt_cnt < argc; opt_cnt++) { 135 opt_text = argv[opt_cnt]; 136 if (opt_text) 137 (void) fprintf(stdout, " %s ", 138 opt_text); 139 } 140 (void) fprintf(stdout, "\n"); 141 } 142 break; 143 144 case '?': 145 usage(whoami); 146 } 147 } 148 if (argc <= optind && !aflag) { 149 usage(whoami); 150 } 151 /* 152 * If aflag go through vfstab and make a list of appropriate 153 * filesystems. 154 */ 155 if (aflag) { 156 157 listp = listbuf; 158 listcnt = 0; 159 160 vfstab = fopen(VFSTAB, "r"); 161 if (vfstab == NULL) { 162 fprintf(stderr, "Can't open %s\n", VFSTAB); 163 perror(VFSTAB); 164 exit(31+1); 165 } 166 167 while ((status = getvfsent(vfstab, &vfsbuf)) == 0) { 168 if (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) != 0 || 169 (vfsbuf.vfs_mntopts == 0) || 170 hasvfsopt(&vfsbuf, MNTOPT_RO) || 171 (!hasvfsopt(&vfsbuf, MNTOPT_RQ) && 172 !hasvfsopt(&vfsbuf, MNTOPT_QUOTA))) 173 continue; 174 *listp = malloc(strlen(vfsbuf.vfs_special) + 1); 175 strcpy(*listp, vfsbuf.vfs_special); 176 listp++; 177 listcnt++; 178 /* grow listbuf if needed */ 179 if (listcnt >= listmax) { 180 listmax += CHUNK; 181 listbuf = (char **)realloc(listbuf, 182 sizeof (char *) * listmax); 183 if (listbuf == NULL) { 184 fprintf(stderr, 185 "Can't grow listbuf.\n"); 186 exit(31+1); 187 } 188 listp = &listbuf[listcnt]; 189 } 190 } 191 fclose(vfstab); 192 *listp = (char *)0; 193 listp = listbuf; 194 } else { 195 listp = &argv[optind]; 196 listcnt = argc - optind; 197 } 198 199 /* 200 * Open real mnttab 201 */ 202 mtab = fopen(MNTTAB, "r"); 203 if (mtab == NULL) { 204 fprintf(stderr, "Can't open %s\n", MNTTAB); 205 perror(whoami); 206 exit(31+1); 207 } 208 /* check every entry for validity before we change mnttab */ 209 while ((status = getmntent(mtab, &mntp)) == 0) 210 ; 211 if (status > 0) 212 mnterror(status); 213 rewind(mtab); 214 215 signal(SIGHUP, SIG_IGN); 216 signal(SIGQUIT, SIG_IGN); 217 signal(SIGINT, SIG_IGN); 218 219 /* 220 * Loop through mnttab, if a file system gets turned on or off 221 * do the quota call. 222 */ 223 while ((status = getmntent(mtab, &mntp)) == 0) { 224 if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) == 0 && 225 !hasmntopt(&mntp, MNTOPT_RO) && 226 (oneof(mntp.mnt_special, listp, listcnt) || 227 oneof(mntp.mnt_mountp, listp, listcnt))) { 228 errs += quotaonoff(&mntp, offmode); 229 } 230 } 231 fclose(mtab); 232 233 while (listcnt--) { 234 if (*listp) { 235 fprintf(stderr, "Cannot do %s\n", *listp); 236 errs++; 237 } 238 listp++; 239 } 240 if (errs > 0) 241 errs += 31; 242 return (errs); 243 } 244 245 int 246 quotaonoff(struct mnttab *mntp, int offmode) 247 { 248 249 if (offmode) { 250 if (quotactl(Q_QUOTAOFF, mntp->mnt_mountp, (uid_t)0, NULL) < 0) 251 goto bad; 252 if (vflag) 253 printf("%s: quotas turned off\n", mntp->mnt_mountp); 254 } else { 255 if (quotactl(Q_QUOTAON, mntp->mnt_mountp, (uid_t)0, NULL) < 256 0) 257 goto bad; 258 if (vflag) 259 printf("%s: quotas turned on\n", mntp->mnt_mountp); 260 } 261 return (0); 262 bad: 263 fprintf(stderr, "quotactl: "); 264 perror(mntp->mnt_special); 265 return (1); 266 } 267 268 int 269 oneof(char *target, char **olistp, int on) 270 { 271 int n = on; 272 char **listp = olistp; 273 274 while (n--) { 275 if (*listp && strcmp(target, *listp) == 0) { 276 *listp = (char *)0; 277 return (1); 278 } 279 listp++; 280 } 281 return (0); 282 } 283 284 void 285 usage(char *whoami) 286 { 287 288 fprintf(stderr, "ufs usage:\n"); 289 fprintf(stderr, "\t%s [-v] -a\n", whoami); 290 fprintf(stderr, "\t%s [-v] filesys ...\n", whoami); 291 exit(31+1); 292 } 293 294 295 int 296 quotactl(int cmd, char *mountpt, uid_t uid, caddr_t addr) 297 { 298 int fd; 299 int status; 300 struct quotctl quota; 301 char qfile[MAXPATHLEN]; 302 303 if (mountpt == NULL || mountpt[0] == '\0') { 304 errno = ENOENT; 305 return (-1); 306 } 307 if ((strlcpy(qfile, mountpt, sizeof (qfile)) >= sizeof (qfile)) || 308 (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >= sizeof (qfile))) { 309 errno = ENOENT; 310 return (-1); 311 } 312 if ((fd = open64(qfile, O_RDWR)) < 0) { 313 fprintf(stderr, "quotactl: %s ", qfile); 314 perror("open"); 315 exit(31+1); 316 } 317 318 quota.op = cmd; 319 quota.uid = uid; 320 quota.addr = addr; 321 status = ioctl(fd, Q_QUOTACTL, "a); 322 close(fd); 323 return (status); 324 } 325 326 char * 327 hasvfsopt(struct vfstab *vfs, char *opt) 328 { 329 char *f, *opts; 330 static char *tmpopts; 331 332 if (tmpopts == 0) { 333 tmpopts = (char *)calloc(256, sizeof (char)); 334 if (tmpopts == 0) 335 return (0); 336 } 337 strcpy(tmpopts, vfs->vfs_mntopts); 338 opts = tmpopts; 339 f = mntopt(&opts); 340 for (; *f; f = mntopt(&opts)) { 341 if (strncmp(opt, f, strlen(opt)) == 0) 342 return (f - tmpopts + vfs->vfs_mntopts); 343 } 344 return (NULL); 345 } 346 347 void 348 mnterror(int flag) 349 { 350 switch (flag) { 351 case MNT_TOOLONG: 352 fprintf(stderr, "%s: line in mnttab exceeds %d characters\n", 353 whoami, MNT_LINE_MAX-2); 354 break; 355 case MNT_TOOFEW: 356 fprintf(stderr, "%s: line in mnttab has too few entries\n", 357 whoami); 358 break; 359 case MNT_TOOMANY: 360 fprintf(stderr, "%s: line in mnttab has too many entries\n", 361 whoami); 362 break; 363 } 364 exit(1); 365 } 366