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