121516Smckusick /* 221516Smckusick * Copyright (c) 1980 Regents of the University of California. 321516Smckusick * All rights reserved. The Berkeley software License Agreement 421516Smckusick * specifies the terms and conditions for redistribution. 521516Smckusick */ 621516Smckusick 712707Smckusick #ifndef lint 821516Smckusick char copyright[] = 921516Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021516Smckusick All rights reserved.\n"; 1121516Smckusick #endif not lint 1212707Smckusick 1321516Smckusick #ifndef lint 14*25401Sbloom static char sccsid[] = "@(#)edquota.c 5.3 (Berkeley) 11/04/85"; 1521516Smckusick #endif not lint 1621516Smckusick 1712707Smckusick /* 1812707Smckusick * Disk quota editor. 1912707Smckusick */ 2012707Smckusick #include <stdio.h> 2112707Smckusick #include <signal.h> 2212707Smckusick #include <errno.h> 2312707Smckusick #include <pwd.h> 2412707Smckusick #include <ctype.h> 2512707Smckusick #include <fstab.h> 2612707Smckusick 2712707Smckusick #include <sys/param.h> 2812803Smckusick #include <sys/stat.h> 2912803Smckusick #include <sys/file.h> 3012707Smckusick #include <sys/quota.h> 3112707Smckusick 3212707Smckusick #define DEFEDITOR "/usr/ucb/vi" 3312707Smckusick 3412707Smckusick struct dquot dq[NMOUNT]; 3512707Smckusick struct dquot odq[NMOUNT]; 3612707Smckusick char dqf[NMOUNT][MAXPATHLEN + 1]; 3712707Smckusick char odqf[NMOUNT][MAXPATHLEN + 1]; 3812707Smckusick 3912707Smckusick char tmpfil[] = "/tmp/EdP.aXXXXX"; 4012716Smckusick char *qfname = "quotas"; 4112707Smckusick char *getenv(); 4212707Smckusick 4312707Smckusick main(argc, argv) 4412707Smckusick char **argv; 4512707Smckusick { 4612803Smckusick int uid; 4712803Smckusick char *arg0; 4812707Smckusick 4912707Smckusick mktemp(tmpfil); 5012707Smckusick close(creat(tmpfil, 0600)); 5112707Smckusick chown(tmpfil, getuid(), getgid()); 5212707Smckusick arg0 = *argv++; 5312707Smckusick if (argc < 2) { 5412803Smckusick fprintf(stderr, "Usage: %s [-p username] username ...\n", arg0); 5512707Smckusick unlink(tmpfil); 5612707Smckusick exit(1); 5712707Smckusick } 5812707Smckusick --argc; 5912707Smckusick if (getuid()) { 6012707Smckusick fprintf(stderr, "%s: permission denied\n", arg0); 6112707Smckusick unlink(tmpfil); 6212707Smckusick exit(1); 6312707Smckusick } 6412803Smckusick if (argc > 2 && strcmp(*argv, "-p") == 0) { 6512803Smckusick argc--, argv++; 6612803Smckusick uid = getentry(*argv++); 6712803Smckusick if (uid < 0) { 6812803Smckusick unlink(tmpfil); 6912803Smckusick exit(1); 7012803Smckusick } 7112803Smckusick getprivs(uid); 7212803Smckusick argc--; 7312803Smckusick while (argc-- > 0) { 7412803Smckusick uid = getentry(*argv++); 7512803Smckusick if (uid < 0) 7612803Smckusick continue; 7712803Smckusick getdiscq(uid, odq, odqf); 7812803Smckusick putprivs(uid); 7912803Smckusick } 8012803Smckusick unlink(tmpfil); 8112803Smckusick exit(0); 8212803Smckusick } 8312803Smckusick while (--argc >= 0) { 8412803Smckusick uid = getentry(*argv++); 8512803Smckusick if (uid < 0) 8612803Smckusick continue; 8712803Smckusick getprivs(uid); 8812803Smckusick if (editit()) 8912803Smckusick putprivs(uid); 9012803Smckusick } 9112707Smckusick unlink(tmpfil); 9212707Smckusick exit(0); 9312707Smckusick } 9412707Smckusick 9512803Smckusick getentry(name) 9612803Smckusick char *name; 9712707Smckusick { 9812803Smckusick struct passwd *pw; 9912803Smckusick int uid; 10012707Smckusick 10112707Smckusick if (alldigits(name)) 10212707Smckusick uid = atoi(name); 10312707Smckusick else if (pw = getpwnam(name)) 10412707Smckusick uid = pw->pw_uid; 10512707Smckusick else { 10612803Smckusick fprintf(stderr, "%s: no such user\n", name); 10712707Smckusick sleep(1); 10812803Smckusick return (-1); 10912707Smckusick } 11012803Smckusick return (uid); 11112707Smckusick } 11212707Smckusick 11312707Smckusick editit() 11412707Smckusick { 11512707Smckusick register pid, xpid; 11613025Ssam int stat, omask; 11712707Smckusick 11813025Ssam #define mask(s) (1<<((s)-1)) 11913025Ssam omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP)); 12012707Smckusick top: 12112707Smckusick if ((pid = fork()) < 0) { 12212707Smckusick extern errno; 12312707Smckusick 12412707Smckusick if (errno == EPROCLIM) { 12512707Smckusick fprintf(stderr, "You have too many processes\n"); 12612707Smckusick return(0); 12712707Smckusick } 12812707Smckusick if (errno == EAGAIN) { 12912707Smckusick sleep(1); 13012707Smckusick goto top; 13112707Smckusick } 13212707Smckusick perror("fork"); 13312707Smckusick return (0); 13412707Smckusick } 13512707Smckusick if (pid == 0) { 13612707Smckusick register char *ed; 13712707Smckusick 13813025Ssam sigsetmask(omask); 13912707Smckusick setgid(getgid()); 14012707Smckusick setuid(getuid()); 14112707Smckusick if ((ed = getenv("EDITOR")) == (char *)0) 14212707Smckusick ed = DEFEDITOR; 14312707Smckusick execlp(ed, ed, tmpfil, 0); 14412707Smckusick perror(ed); 14512707Smckusick exit(1); 14612707Smckusick } 14712707Smckusick while ((xpid = wait(&stat)) >= 0) 14812707Smckusick if (xpid == pid) 14912707Smckusick break; 15013025Ssam sigsetmask(omask); 15112707Smckusick return (!stat); 15212707Smckusick } 15312707Smckusick 15412707Smckusick getprivs(uid) 15512707Smckusick register uid; 15612707Smckusick { 15712707Smckusick register i; 15812707Smckusick FILE *fd; 15912707Smckusick 16012707Smckusick getdiscq(uid, dq, dqf); 16112707Smckusick for (i = 0; i < NMOUNT; i++) { 16212707Smckusick odq[i] = dq[i]; 16312707Smckusick strcpy(odqf[i], dqf[i]); 16412707Smckusick } 16512707Smckusick if ((fd = fopen(tmpfil, "w")) == NULL) { 16612707Smckusick fprintf(stderr, "edquota: "); 16712707Smckusick perror(tmpfil); 16812707Smckusick exit(1); 16912707Smckusick } 17012707Smckusick for (i = 0; i < NMOUNT; i++) { 17112707Smckusick if (*dqf[i] == '\0') 17212707Smckusick continue; 17312707Smckusick fprintf(fd, 17412707Smckusick "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n" 17512707Smckusick , dqf[i] 176*25401Sbloom , dbtob(dq[i].dq_bsoftlimit) / 1024 177*25401Sbloom , dbtob(dq[i].dq_bhardlimit) / 1024 17812707Smckusick , dq[i].dq_isoftlimit 17912707Smckusick , dq[i].dq_ihardlimit 18012707Smckusick ); 18112707Smckusick } 18212707Smckusick fclose(fd); 18312707Smckusick } 18412707Smckusick 18512707Smckusick putprivs(uid) 18612707Smckusick register uid; 18712707Smckusick { 18812707Smckusick register i, j; 18912707Smckusick int n; 19012707Smckusick FILE *fd; 19112707Smckusick char line[BUFSIZ]; 19212707Smckusick 19312707Smckusick fd = fopen(tmpfil, "r"); 19412707Smckusick if (fd == NULL) { 19512707Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 19612707Smckusick return; 19712707Smckusick } 19812707Smckusick for (i = 0; i < NMOUNT; i++) { 19912707Smckusick char *cp, *dp, *next(); 20012707Smckusick 20112707Smckusick if (fgets(line, sizeof (line), fd) == NULL) 20212707Smckusick break; 20312707Smckusick cp = next(line, " \t"); 20412707Smckusick if (cp == NULL) 20512707Smckusick break; 20612707Smckusick *cp++ = '\0'; 20712707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 20812707Smckusick cp++; 20912707Smckusick dp = cp, cp = next(cp, " \t"); 21012707Smckusick if (cp == NULL) 21112707Smckusick break; 21212707Smckusick *cp++ = '\0'; 21312707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 21412707Smckusick cp++; 21512707Smckusick strcpy(dqf[i], dp); 21612707Smckusick n = sscanf(cp, 21712707Smckusick "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n" 21812707Smckusick , &dq[i].dq_bsoftlimit 21912707Smckusick , &dq[i].dq_bhardlimit 22012707Smckusick , &dq[i].dq_isoftlimit 22112707Smckusick , &dq[i].dq_ihardlimit 22212707Smckusick ); 22312716Smckusick if (n != 4) { 22412716Smckusick fprintf(stderr, "%s: bad format\n", cp); 22512716Smckusick continue; 22612716Smckusick } 227*25401Sbloom dq[i].dq_bsoftlimit = btodb(dq[i].dq_bsoftlimit * 1024); 228*25401Sbloom dq[i].dq_bhardlimit = btodb(dq[i].dq_bhardlimit * 1024); 22912707Smckusick } 23012707Smckusick fclose(fd); 23112707Smckusick n = i; 23212707Smckusick for (i = 0; i < n; i++) { 23312707Smckusick if (*dqf[i] == '\0') 23412707Smckusick break; 23512707Smckusick for (j = 0; j < NMOUNT; j++) { 23612707Smckusick if (strcmp(dqf[i], odqf[j]) == 0) 23712707Smckusick break; 23812707Smckusick } 23912707Smckusick if (j >= NMOUNT) 24012707Smckusick continue; 24112707Smckusick *odqf[j] = '\0'; 24212707Smckusick /* 24312707Smckusick * This isn't really good enough, it is quite likely 24412707Smckusick * to have changed while we have been away editing, 24512707Smckusick * but it's not important enough to worry about at 24612707Smckusick * the minute. 24712707Smckusick */ 24812707Smckusick dq[i].dq_curblocks = odq[j].dq_curblocks; 24912707Smckusick dq[i].dq_curinodes = odq[j].dq_curinodes; 25012707Smckusick /* 25112707Smckusick * If we've upped the inode or disk block limits 25212707Smckusick * and the guy is out of warnings, reinitialize. 25312707Smckusick */ 25412707Smckusick if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit && 25512707Smckusick dq[i].dq_bwarn == 0) 25612707Smckusick dq[i].dq_bwarn = MAX_DQ_WARN; 25712707Smckusick if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit && 25812707Smckusick dq[i].dq_iwarn == 0) 25912707Smckusick dq[i].dq_iwarn = MAX_IQ_WARN; 26012707Smckusick } 26112707Smckusick if (i < NMOUNT) { 26212707Smckusick for (j = 0; j < NMOUNT; j++) { 26312707Smckusick if (*odqf[j] == '\0') 26412707Smckusick continue; 26512707Smckusick strcpy(dqf[i], odqf[j]); 26612707Smckusick dq[i].dq_isoftlimit = 0; 26712707Smckusick dq[i].dq_ihardlimit = 0; 26812707Smckusick dq[i].dq_bsoftlimit = 0; 26912707Smckusick dq[i].dq_bhardlimit = 0; 27012707Smckusick /* 27112707Smckusick * Same applies as just above 27212707Smckusick * but matters not at all, as we are just 27312707Smckusick * turning quota'ing off for this filesys. 27412707Smckusick */ 27512707Smckusick dq[i].dq_curblocks = odq[j].dq_curblocks; 27612707Smckusick dq[i].dq_curinodes = odq[j].dq_curinodes; 27712707Smckusick if (++i >= NMOUNT) 27812707Smckusick break; 27912707Smckusick } 28012707Smckusick } 28112707Smckusick if (*dqf[0]) 28212707Smckusick putdiscq(uid, dq, dqf); 28312707Smckusick } 28412707Smckusick 28512707Smckusick char * 28612707Smckusick next(cp, match) 28712707Smckusick register char *cp; 28812707Smckusick char *match; 28912707Smckusick { 29012707Smckusick register char *dp; 29112707Smckusick 29212707Smckusick while (cp && *cp) { 29312707Smckusick for (dp = match; dp && *dp; dp++) 29412707Smckusick if (*dp == *cp) 29512707Smckusick return (cp); 29612707Smckusick cp++; 29712707Smckusick } 29812707Smckusick return ((char *)0); 29912707Smckusick } 30012707Smckusick 30112707Smckusick alldigits(s) 30212707Smckusick register char *s; 30312707Smckusick { 30412707Smckusick register c; 30512707Smckusick 30612707Smckusick c = *s++; 30712707Smckusick do { 30812707Smckusick if (!isdigit(c)) 30912707Smckusick return (0); 31012707Smckusick } while (c = *s++); 31112707Smckusick return (1); 31212707Smckusick } 31312707Smckusick 31412707Smckusick getdiscq(uid, dq, dqf) 31512707Smckusick register uid; 31612707Smckusick register struct dquot *dq; 31712707Smckusick register char (*dqf)[MAXPATHLEN + 1]; 31812707Smckusick { 31912707Smckusick register struct fstab *fs; 32012716Smckusick char qfilename[MAXPATHLEN + 1]; 32121087Smckusick struct stat statb; 32221087Smckusick struct dqblk dqblk; 32321087Smckusick dev_t fsdev; 32421087Smckusick int fd; 32521087Smckusick static int warned = 0; 32621087Smckusick extern int errno; 32712707Smckusick 32812707Smckusick setfsent(); 32912707Smckusick while (fs = getfsent()) { 33012707Smckusick if (stat(fs->fs_spec, &statb) < 0) 33112707Smckusick continue; 33212707Smckusick fsdev = statb.st_rdev; 33312716Smckusick sprintf(qfilename, "%s/%s", fs->fs_file, qfname); 33412716Smckusick if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev) 33512707Smckusick continue; 33612707Smckusick if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) { 33721087Smckusick if (errno == EINVAL && !warned) { 33821087Smckusick warned++; 33921087Smckusick fprintf(stderr, "Warning: %s\n", 34021087Smckusick "Quotas are not compiled into this kernel"); 34121087Smckusick sleep(3); 34221087Smckusick } 34321087Smckusick fd = open(qfilename, O_RDONLY); 34412707Smckusick if (fd < 0) 34512707Smckusick continue; 34612722Smckusick lseek(fd, (long)(uid * sizeof dqblk), L_SET); 34724659Sserge switch (read(fd, &dqblk, sizeof dqblk)) { 34824659Sserge case 0: /* EOF */ 34924659Sserge /* 35024659Sserge * Convert implicit 0 quota (EOF) 35124659Sserge * into an explicit one (zero'ed dqblk) 35224659Sserge */ 35324659Sserge bzero((caddr_t)&dqblk, sizeof dqblk); 35424659Sserge break; 35524659Sserge 35624659Sserge case sizeof dqblk: /* OK */ 35724659Sserge break; 35824659Sserge 35924659Sserge default: /* ERROR */ 36024659Sserge fprintf(stderr, "edquota: read error in "); 36124659Sserge perror(qfilename); 36212707Smckusick close(fd); 36312707Smckusick continue; 36412707Smckusick } 36512707Smckusick close(fd); 36612707Smckusick } 36712707Smckusick dq->dq_dqb = dqblk; 36812707Smckusick dq->dq_dev = fsdev; 36912707Smckusick strcpy(*dqf, fs->fs_file); 37012707Smckusick dq++, dqf++; 37112707Smckusick } 37212707Smckusick endfsent(); 37312707Smckusick **dqf = '\0'; 37412707Smckusick } 37512707Smckusick 37612707Smckusick putdiscq(uid, dq, dqf) 37712707Smckusick register uid; 37812707Smckusick register struct dquot *dq; 37912707Smckusick register char (*dqf)[MAXPATHLEN + 1]; 38012707Smckusick { 38112707Smckusick register fd, cnt; 38212707Smckusick struct stat sb; 38312707Smckusick struct fstab *fs; 38412707Smckusick 38512707Smckusick cnt = 0; 38612707Smckusick for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) { 38712707Smckusick fs = getfsfile(*dqf); 38812716Smckusick if (fs == NULL) { 38912716Smckusick fprintf(stderr, "%s: not in /etc/fstab\n", *dqf); 39012716Smckusick continue; 39112716Smckusick } 39212716Smckusick strcat(*dqf, "/"); 39312716Smckusick strcat(*dqf, qfname); 39412716Smckusick if (stat(*dqf, &sb) >= 0) 39512716Smckusick quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb); 39612716Smckusick if ((fd = open(*dqf, 1)) < 0) { 39712716Smckusick perror(*dqf); 39812716Smckusick } else { 39912707Smckusick lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0); 40012707Smckusick if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) != 40112707Smckusick sizeof (struct dqblk)) { 40212707Smckusick fprintf(stderr, "edquota: "); 40312707Smckusick perror(*dqf); 40412707Smckusick } 40512707Smckusick close(fd); 40612707Smckusick } 40712707Smckusick } 40812707Smckusick } 409