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