1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: char copyright[] = 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: #endif not lint 12: 13: #ifndef lint 14: static char sccsid[] = "@(#)edquota.c 5.3 (Berkeley) 11/4/85"; 15: #endif not lint 16: 17: /* 18: * Disk quota editor. 19: */ 20: #include <stdio.h> 21: #include <signal.h> 22: #include <errno.h> 23: #include <pwd.h> 24: #include <ctype.h> 25: #include <fstab.h> 26: 27: #include <sys/param.h> 28: #include <sys/stat.h> 29: #include <sys/file.h> 30: #include <sys/quota.h> 31: 32: #define DEFEDITOR "/usr/ucb/vi" 33: 34: struct dquot dq[NMOUNT]; 35: struct dquot odq[NMOUNT]; 36: char dqf[NMOUNT][MAXPATHLEN + 1]; 37: char odqf[NMOUNT][MAXPATHLEN + 1]; 38: 39: char tmpfil[] = "/tmp/EdP.aXXXXX"; 40: char *qfname = "quotas"; 41: char *getenv(); 42: 43: main(argc, argv) 44: char **argv; 45: { 46: int uid; 47: char *arg0; 48: 49: mktemp(tmpfil); 50: close(creat(tmpfil, 0600)); 51: chown(tmpfil, getuid(), getgid()); 52: arg0 = *argv++; 53: if (argc < 2) { 54: fprintf(stderr, "Usage: %s [-p username] username ...\n", arg0); 55: unlink(tmpfil); 56: exit(1); 57: } 58: --argc; 59: if (getuid()) { 60: fprintf(stderr, "%s: permission denied\n", arg0); 61: unlink(tmpfil); 62: exit(1); 63: } 64: if (argc > 2 && strcmp(*argv, "-p") == 0) { 65: argc--, argv++; 66: uid = getentry(*argv++); 67: if (uid < 0) { 68: unlink(tmpfil); 69: exit(1); 70: } 71: getprivs(uid); 72: argc--; 73: while (argc-- > 0) { 74: uid = getentry(*argv++); 75: if (uid < 0) 76: continue; 77: getdiscq(uid, odq, odqf); 78: putprivs(uid); 79: } 80: unlink(tmpfil); 81: exit(0); 82: } 83: while (--argc >= 0) { 84: uid = getentry(*argv++); 85: if (uid < 0) 86: continue; 87: getprivs(uid); 88: if (editit()) 89: putprivs(uid); 90: } 91: unlink(tmpfil); 92: exit(0); 93: } 94: 95: getentry(name) 96: char *name; 97: { 98: struct passwd *pw; 99: int uid; 100: 101: if (alldigits(name)) 102: uid = atoi(name); 103: else if (pw = getpwnam(name)) 104: uid = pw->pw_uid; 105: else { 106: fprintf(stderr, "%s: no such user\n", name); 107: sleep(1); 108: return (-1); 109: } 110: return (uid); 111: } 112: 113: editit() 114: { 115: register pid, xpid; 116: int stat, omask; 117: 118: #define mask(s) (1<<((s)-1)) 119: omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP)); 120: top: 121: if ((pid = fork()) < 0) { 122: extern errno; 123: 124: if (errno == EPROCLIM) { 125: fprintf(stderr, "You have too many processes\n"); 126: return(0); 127: } 128: if (errno == EAGAIN) { 129: sleep(1); 130: goto top; 131: } 132: perror("fork"); 133: return (0); 134: } 135: if (pid == 0) { 136: register char *ed; 137: 138: sigsetmask(omask); 139: setgid(getgid()); 140: setuid(getuid()); 141: if ((ed = getenv("EDITOR")) == (char *)0) 142: ed = DEFEDITOR; 143: execlp(ed, ed, tmpfil, 0); 144: perror(ed); 145: exit(1); 146: } 147: while ((xpid = wait(&stat)) >= 0) 148: if (xpid == pid) 149: break; 150: sigsetmask(omask); 151: return (!stat); 152: } 153: 154: getprivs(uid) 155: register uid; 156: { 157: register i; 158: FILE *fd; 159: 160: getdiscq(uid, dq, dqf); 161: for (i = 0; i < NMOUNT; i++) { 162: odq[i] = dq[i]; 163: strcpy(odqf[i], dqf[i]); 164: } 165: if ((fd = fopen(tmpfil, "w")) == NULL) { 166: fprintf(stderr, "edquota: "); 167: perror(tmpfil); 168: exit(1); 169: } 170: for (i = 0; i < NMOUNT; i++) { 171: if (*dqf[i] == '\0') 172: continue; 173: fprintf(fd, 174: "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n" 175: , dqf[i] 176: , dbtob(dq[i].dq_bsoftlimit) / 1024 177: , dbtob(dq[i].dq_bhardlimit) / 1024 178: , dq[i].dq_isoftlimit 179: , dq[i].dq_ihardlimit 180: ); 181: } 182: fclose(fd); 183: } 184: 185: putprivs(uid) 186: register uid; 187: { 188: register i, j; 189: int n; 190: FILE *fd; 191: char line[BUFSIZ]; 192: 193: fd = fopen(tmpfil, "r"); 194: if (fd == NULL) { 195: fprintf(stderr, "Can't re-read temp file!!\n"); 196: return; 197: } 198: for (i = 0; i < NMOUNT; i++) { 199: char *cp, *dp, *next(); 200: 201: if (fgets(line, sizeof (line), fd) == NULL) 202: break; 203: cp = next(line, " \t"); 204: if (cp == NULL) 205: break; 206: *cp++ = '\0'; 207: while (*cp && *cp == '\t' && *cp == ' ') 208: cp++; 209: dp = cp, cp = next(cp, " \t"); 210: if (cp == NULL) 211: break; 212: *cp++ = '\0'; 213: while (*cp && *cp == '\t' && *cp == ' ') 214: cp++; 215: strcpy(dqf[i], dp); 216: n = sscanf(cp, 217: "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n" 218: , &dq[i].dq_bsoftlimit 219: , &dq[i].dq_bhardlimit 220: , &dq[i].dq_isoftlimit 221: , &dq[i].dq_ihardlimit 222: ); 223: if (n != 4) { 224: fprintf(stderr, "%s: bad format\n", cp); 225: continue; 226: } 227: dq[i].dq_bsoftlimit = btodb(dq[i].dq_bsoftlimit * 1024); 228: dq[i].dq_bhardlimit = btodb(dq[i].dq_bhardlimit * 1024); 229: } 230: fclose(fd); 231: n = i; 232: for (i = 0; i < n; i++) { 233: if (*dqf[i] == '\0') 234: break; 235: for (j = 0; j < NMOUNT; j++) { 236: if (strcmp(dqf[i], odqf[j]) == 0) 237: break; 238: } 239: if (j >= NMOUNT) 240: continue; 241: *odqf[j] = '\0'; 242: /* 243: * This isn't really good enough, it is quite likely 244: * to have changed while we have been away editing, 245: * but it's not important enough to worry about at 246: * the minute. 247: */ 248: dq[i].dq_curblocks = odq[j].dq_curblocks; 249: dq[i].dq_curinodes = odq[j].dq_curinodes; 250: /* 251: * If we've upped the inode or disk block limits 252: * and the guy is out of warnings, reinitialize. 253: */ 254: if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit && 255: dq[i].dq_bwarn == 0) 256: dq[i].dq_bwarn = MAX_DQ_WARN; 257: if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit && 258: dq[i].dq_iwarn == 0) 259: dq[i].dq_iwarn = MAX_IQ_WARN; 260: } 261: if (i < NMOUNT) { 262: for (j = 0; j < NMOUNT; j++) { 263: if (*odqf[j] == '\0') 264: continue; 265: strcpy(dqf[i], odqf[j]); 266: dq[i].dq_isoftlimit = 0; 267: dq[i].dq_ihardlimit = 0; 268: dq[i].dq_bsoftlimit = 0; 269: dq[i].dq_bhardlimit = 0; 270: /* 271: * Same applies as just above 272: * but matters not at all, as we are just 273: * turning quota'ing off for this filesys. 274: */ 275: dq[i].dq_curblocks = odq[j].dq_curblocks; 276: dq[i].dq_curinodes = odq[j].dq_curinodes; 277: if (++i >= NMOUNT) 278: break; 279: } 280: } 281: if (*dqf[0]) 282: putdiscq(uid, dq, dqf); 283: } 284: 285: char * 286: next(cp, match) 287: register char *cp; 288: char *match; 289: { 290: register char *dp; 291: 292: while (cp && *cp) { 293: for (dp = match; dp && *dp; dp++) 294: if (*dp == *cp) 295: return (cp); 296: cp++; 297: } 298: return ((char *)0); 299: } 300: 301: alldigits(s) 302: register char *s; 303: { 304: register c; 305: 306: c = *s++; 307: do { 308: if (!isdigit(c)) 309: return (0); 310: } while (c = *s++); 311: return (1); 312: } 313: 314: getdiscq(uid, dq, dqf) 315: register uid; 316: register struct dquot *dq; 317: register char (*dqf)[MAXPATHLEN + 1]; 318: { 319: register struct fstab *fs; 320: char qfilename[MAXPATHLEN + 1]; 321: struct stat statb; 322: struct dqblk dqblk; 323: dev_t fsdev; 324: int fd; 325: static int warned = 0; 326: extern int errno; 327: 328: setfsent(); 329: while (fs = getfsent()) { 330: if (stat(fs->fs_spec, &statb) < 0) 331: continue; 332: fsdev = statb.st_rdev; 333: sprintf(qfilename, "%s/%s", fs->fs_file, qfname); 334: if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev) 335: continue; 336: if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) { 337: if (errno == EINVAL && !warned) { 338: warned++; 339: fprintf(stderr, "Warning: %s\n", 340: "Quotas are not compiled into this kernel"); 341: sleep(3); 342: } 343: fd = open(qfilename, O_RDONLY); 344: if (fd < 0) 345: continue; 346: lseek(fd, (long)(uid * sizeof dqblk), L_SET); 347: switch (read(fd, &dqblk, sizeof dqblk)) { 348: case 0: /* EOF */ 349: /* 350: * Convert implicit 0 quota (EOF) 351: * into an explicit one (zero'ed dqblk) 352: */ 353: bzero((caddr_t)&dqblk, sizeof dqblk); 354: break; 355: 356: case sizeof dqblk: /* OK */ 357: break; 358: 359: default: /* ERROR */ 360: fprintf(stderr, "edquota: read error in "); 361: perror(qfilename); 362: close(fd); 363: continue; 364: } 365: close(fd); 366: } 367: dq->dq_dqb = dqblk; 368: dq->dq_dev = fsdev; 369: strcpy(*dqf, fs->fs_file); 370: dq++, dqf++; 371: } 372: endfsent(); 373: **dqf = '\0'; 374: } 375: 376: putdiscq(uid, dq, dqf) 377: register uid; 378: register struct dquot *dq; 379: register char (*dqf)[MAXPATHLEN + 1]; 380: { 381: register fd, cnt; 382: struct stat sb; 383: struct fstab *fs; 384: 385: cnt = 0; 386: for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) { 387: fs = getfsfile(*dqf); 388: if (fs == NULL) { 389: fprintf(stderr, "%s: not in /etc/fstab\n", *dqf); 390: continue; 391: } 392: strcat(*dqf, "/"); 393: strcat(*dqf, qfname); 394: if (stat(*dqf, &sb) >= 0) 395: quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb); 396: if ((fd = open(*dqf, 1)) < 0) { 397: perror(*dqf); 398: } else { 399: lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0); 400: if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) != 401: sizeof (struct dqblk)) { 402: fprintf(stderr, "edquota: "); 403: perror(*dqf); 404: } 405: close(fd); 406: } 407: } 408: }