112707Smckusick #ifndef lint 2*12716Smckusick static char sccsid[] = "@(#)edquota.c 4.2 (Berkeley, from Melbourne) 05/25/83"; 312707Smckusick #endif 412707Smckusick 512707Smckusick /* 612707Smckusick * Disk quota editor. 712707Smckusick */ 812707Smckusick #include <stdio.h> 912707Smckusick #include <signal.h> 1012707Smckusick #include <errno.h> 1112707Smckusick #include <pwd.h> 1212707Smckusick #include <ctype.h> 1312707Smckusick #include <fstab.h> 1412707Smckusick 1512707Smckusick #include <sys/param.h> 16*12716Smckusick #define QUOTA 1712707Smckusick #include <sys/quota.h> 1812707Smckusick #include <sys/stat.h> 1912707Smckusick #include <sys/file.h> 2012707Smckusick 2112707Smckusick #define DEFEDITOR "/usr/ucb/vi" 2212707Smckusick 2312707Smckusick struct dquot dq[NMOUNT]; 2412707Smckusick struct dquot odq[NMOUNT]; 2512707Smckusick char dqf[NMOUNT][MAXPATHLEN + 1]; 2612707Smckusick char odqf[NMOUNT][MAXPATHLEN + 1]; 2712707Smckusick 2812707Smckusick char tmpfil[] = "/tmp/EdP.aXXXXX"; 29*12716Smckusick char *qfname = "quotas"; 3012707Smckusick char *arg0; 3112707Smckusick char *getenv(); 3212707Smckusick 3312707Smckusick main(argc, argv) 3412707Smckusick char **argv; 3512707Smckusick { 3612707Smckusick 3712707Smckusick mktemp(tmpfil); 3812707Smckusick close(creat(tmpfil, 0600)); 3912707Smckusick chown(tmpfil, getuid(), getgid()); 4012707Smckusick arg0 = *argv++; 4112707Smckusick if (argc < 2) { 4212707Smckusick fprintf(stderr, "Usage: %s username ...\n", arg0); 4312707Smckusick unlink(tmpfil); 4412707Smckusick exit(1); 4512707Smckusick } 4612707Smckusick --argc; 4712707Smckusick if (getuid()) { 4812707Smckusick fprintf(stderr, "%s: permission denied\n", arg0); 4912707Smckusick unlink(tmpfil); 5012707Smckusick exit(1); 5112707Smckusick } 5212707Smckusick while (--argc >= 0) 5312707Smckusick doedit(*argv++); 5412707Smckusick unlink(tmpfil); 5512707Smckusick exit(0); 5612707Smckusick } 5712707Smckusick 5812707Smckusick doedit(name) 5912707Smckusick register char *name; 6012707Smckusick { 6112707Smckusick register uid; 6212707Smckusick register struct passwd *pw; 6312707Smckusick 6412707Smckusick if (alldigits(name)) 6512707Smckusick uid = atoi(name); 6612707Smckusick else if (pw = getpwnam(name)) 6712707Smckusick uid = pw->pw_uid; 6812707Smckusick else { 6912707Smckusick fprintf(stderr, "%s: no such user\n"); 7012707Smckusick sleep(1); 7112707Smckusick return; 7212707Smckusick } 7312707Smckusick getprivs(uid); 7412707Smckusick if (editit()) 7512707Smckusick putprivs(uid); 7612707Smckusick } 7712707Smckusick 7812707Smckusick editit() 7912707Smckusick { 8012707Smckusick register pid, xpid; 8112707Smckusick int stat; 8212707Smckusick 8312707Smckusick sighold(SIGINT); 8412707Smckusick sighold(SIGQUIT); 8512707Smckusick sighold(SIGHUP); 8612707Smckusick 8712707Smckusick top: 8812707Smckusick if ((pid = fork()) < 0) { 8912707Smckusick extern errno; 9012707Smckusick 9112707Smckusick if (errno == EPROCLIM) { 9212707Smckusick fprintf(stderr, "You have too many processes\n"); 9312707Smckusick return(0); 9412707Smckusick } 9512707Smckusick if (errno == EAGAIN) { 9612707Smckusick sleep(1); 9712707Smckusick goto top; 9812707Smckusick } 9912707Smckusick perror("fork"); 10012707Smckusick return (0); 10112707Smckusick } 10212707Smckusick if (pid == 0) { 10312707Smckusick register char *ed; 10412707Smckusick 10512707Smckusick sigrelse(SIGINT); 10612707Smckusick sigrelse(SIGQUIT); 10712707Smckusick sigrelse(SIGHUP); 10812707Smckusick setgid(getgid()); 10912707Smckusick setuid(getuid()); 11012707Smckusick 11112707Smckusick if ((ed = getenv("EDITOR")) == (char *)0) 11212707Smckusick ed = DEFEDITOR; 11312707Smckusick execlp(ed, ed, tmpfil, 0); 11412707Smckusick perror(ed); 11512707Smckusick exit(1); 11612707Smckusick } 11712707Smckusick while ((xpid = wait(&stat)) >= 0) 11812707Smckusick if (xpid == pid) 11912707Smckusick break; 12012707Smckusick sigrelse(SIGINT); 12112707Smckusick sigrelse(SIGQUIT); 12212707Smckusick sigrelse(SIGHUP); 12312707Smckusick return (!stat); 12412707Smckusick } 12512707Smckusick 12612707Smckusick getprivs(uid) 12712707Smckusick register uid; 12812707Smckusick { 12912707Smckusick register i; 13012707Smckusick FILE *fd; 13112707Smckusick 13212707Smckusick getdiscq(uid, dq, dqf); 13312707Smckusick for (i = 0; i < NMOUNT; i++) { 13412707Smckusick odq[i] = dq[i]; 13512707Smckusick strcpy(odqf[i], dqf[i]); 13612707Smckusick } 13712707Smckusick if ((fd = fopen(tmpfil, "w")) == NULL) { 13812707Smckusick fprintf(stderr, "edquota: "); 13912707Smckusick perror(tmpfil); 14012707Smckusick exit(1); 14112707Smckusick } 14212707Smckusick for (i = 0; i < NMOUNT; i++) { 14312707Smckusick if (*dqf[i] == '\0') 14412707Smckusick continue; 14512707Smckusick fprintf(fd, 14612707Smckusick "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n" 14712707Smckusick , dqf[i] 148*12716Smckusick , dq[i].dq_bsoftlimit / btodb(1024) 149*12716Smckusick , dq[i].dq_bhardlimit / btodb(1024) 15012707Smckusick , dq[i].dq_isoftlimit 15112707Smckusick , dq[i].dq_ihardlimit 15212707Smckusick ); 15312707Smckusick } 15412707Smckusick fclose(fd); 15512707Smckusick } 15612707Smckusick 15712707Smckusick putprivs(uid) 15812707Smckusick register uid; 15912707Smckusick { 16012707Smckusick register i, j; 16112707Smckusick int n; 16212707Smckusick FILE *fd; 16312707Smckusick char line[BUFSIZ]; 16412707Smckusick 16512707Smckusick fd = fopen(tmpfil, "r"); 16612707Smckusick if (fd == NULL) { 16712707Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 16812707Smckusick return; 16912707Smckusick } 17012707Smckusick for (i = 0; i < NMOUNT; i++) { 17112707Smckusick char *cp, *dp, *next(); 17212707Smckusick 17312707Smckusick if (fgets(line, sizeof (line), fd) == NULL) 17412707Smckusick break; 17512707Smckusick cp = next(line, " \t"); 17612707Smckusick if (cp == NULL) 17712707Smckusick break; 17812707Smckusick *cp++ = '\0'; 17912707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 18012707Smckusick cp++; 18112707Smckusick dp = cp, cp = next(cp, " \t"); 18212707Smckusick if (cp == NULL) 18312707Smckusick break; 18412707Smckusick *cp++ = '\0'; 18512707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 18612707Smckusick cp++; 18712707Smckusick strcpy(dqf[i], dp); 18812707Smckusick n = sscanf(cp, 18912707Smckusick "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n" 19012707Smckusick , &dq[i].dq_bsoftlimit 19112707Smckusick , &dq[i].dq_bhardlimit 19212707Smckusick , &dq[i].dq_isoftlimit 19312707Smckusick , &dq[i].dq_ihardlimit 19412707Smckusick ); 195*12716Smckusick if (n != 4) { 196*12716Smckusick fprintf(stderr, "%s: bad format\n", cp); 197*12716Smckusick continue; 198*12716Smckusick } 199*12716Smckusick dq[i].dq_bsoftlimit *= btodb(1024); 200*12716Smckusick dq[i].dq_bhardlimit *= btodb(1024); 20112707Smckusick } 20212707Smckusick fclose(fd); 20312707Smckusick n = i; 20412707Smckusick for (i = 0; i < n; i++) { 20512707Smckusick if (*dqf[i] == '\0') 20612707Smckusick break; 20712707Smckusick for (j = 0; j < NMOUNT; j++) { 20812707Smckusick if (strcmp(dqf[i], odqf[j]) == 0) 20912707Smckusick break; 21012707Smckusick } 21112707Smckusick if (j >= NMOUNT) 21212707Smckusick continue; 21312707Smckusick *odqf[j] = '\0'; 21412707Smckusick if (dq[i].dq_isoftlimit == odq[j].dq_isoftlimit && 21512707Smckusick dq[i].dq_ihardlimit == odq[j].dq_ihardlimit && 21612707Smckusick dq[i].dq_bsoftlimit == odq[j].dq_bsoftlimit && 21712707Smckusick dq[i].dq_bhardlimit == odq[j].dq_bhardlimit) { 218*12716Smckusick for (j = i; j < NMOUNT; j++) { 21912707Smckusick dq[j] = dq[j+1]; 22012707Smckusick strcpy(dqf[j], dqf[j+1]); 22112707Smckusick } 22212707Smckusick *dqf[j] = '\0'; 22312707Smckusick i--; 22412707Smckusick continue; 22512707Smckusick } 22612707Smckusick /* 22712707Smckusick * This isn't really good enough, it is quite likely 22812707Smckusick * to have changed while we have been away editing, 22912707Smckusick * but it's not important enough to worry about at 23012707Smckusick * the minute. 23112707Smckusick */ 23212707Smckusick dq[i].dq_curblocks = odq[j].dq_curblocks; 23312707Smckusick dq[i].dq_curinodes = odq[j].dq_curinodes; 23412707Smckusick /* 23512707Smckusick * If we've upped the inode or disk block limits 23612707Smckusick * and the guy is out of warnings, reinitialize. 23712707Smckusick */ 23812707Smckusick if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit && 23912707Smckusick dq[i].dq_bwarn == 0) 24012707Smckusick dq[i].dq_bwarn = MAX_DQ_WARN; 24112707Smckusick if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit && 24212707Smckusick dq[i].dq_iwarn == 0) 24312707Smckusick dq[i].dq_iwarn = MAX_IQ_WARN; 24412707Smckusick } 24512707Smckusick if (i < NMOUNT) { 24612707Smckusick for (j = 0; j < NMOUNT; j++) { 24712707Smckusick if (*odqf[j] == '\0') 24812707Smckusick continue; 24912707Smckusick strcpy(dqf[i], odqf[j]); 25012707Smckusick dq[i].dq_isoftlimit = 0; 25112707Smckusick dq[i].dq_ihardlimit = 0; 25212707Smckusick dq[i].dq_bsoftlimit = 0; 25312707Smckusick dq[i].dq_bhardlimit = 0; 25412707Smckusick /* 25512707Smckusick * Same applies as just above 25612707Smckusick * but matters not at all, as we are just 25712707Smckusick * turning quota'ing off for this filesys. 25812707Smckusick */ 25912707Smckusick dq[i].dq_curblocks = odq[j].dq_curblocks; 26012707Smckusick dq[i].dq_curinodes = odq[j].dq_curinodes; 26112707Smckusick if (++i >= NMOUNT) 26212707Smckusick break; 26312707Smckusick } 26412707Smckusick } 26512707Smckusick if (*dqf[0]) 26612707Smckusick putdiscq(uid, dq, dqf); 26712707Smckusick } 26812707Smckusick 26912707Smckusick char * 27012707Smckusick next(cp, match) 27112707Smckusick register char *cp; 27212707Smckusick char *match; 27312707Smckusick { 27412707Smckusick register char *dp; 27512707Smckusick 27612707Smckusick while (cp && *cp) { 27712707Smckusick for (dp = match; dp && *dp; dp++) 27812707Smckusick if (*dp == *cp) 27912707Smckusick return (cp); 28012707Smckusick cp++; 28112707Smckusick } 28212707Smckusick return ((char *)0); 28312707Smckusick } 28412707Smckusick 28512707Smckusick alldigits(s) 28612707Smckusick register char *s; 28712707Smckusick { 28812707Smckusick register c; 28912707Smckusick 29012707Smckusick c = *s++; 29112707Smckusick do { 29212707Smckusick if (!isdigit(c)) 29312707Smckusick return (0); 29412707Smckusick } while (c = *s++); 29512707Smckusick return (1); 29612707Smckusick } 29712707Smckusick 29812707Smckusick getdiscq(uid, dq, dqf) 29912707Smckusick register uid; 30012707Smckusick register struct dquot *dq; 30112707Smckusick register char (*dqf)[MAXPATHLEN + 1]; 30212707Smckusick { 30312707Smckusick register struct fstab *fs; 304*12716Smckusick char qfilename[MAXPATHLEN + 1]; 30512707Smckusick 30612707Smckusick setfsent(); 30712707Smckusick while (fs = getfsent()) { 30812707Smckusick struct stat statb; 30912707Smckusick struct dqblk dqblk; 31012707Smckusick dev_t fsdev; 31112707Smckusick 31212707Smckusick if (stat(fs->fs_spec, &statb) < 0) 31312707Smckusick continue; 31412707Smckusick fsdev = statb.st_rdev; 315*12716Smckusick sprintf(qfilename, "%s/%s", fs->fs_file, qfname); 316*12716Smckusick if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev) 31712707Smckusick continue; 31812707Smckusick if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) { 319*12716Smckusick register fd = open(qfilename, FRDONLY); 32012707Smckusick 32112707Smckusick if (fd < 0) 32212707Smckusick continue; 32312707Smckusick lseek(fd, (long)(uid * sizeof dqblk), FSEEK_ABSOLUTE); 32412707Smckusick if (read(fd, &dqblk, sizeof dqblk) != sizeof (dqblk)) { 32512707Smckusick close(fd); 32612707Smckusick continue; 32712707Smckusick } 32812707Smckusick close(fd); 32912707Smckusick } 33012707Smckusick dq->dq_dqb = dqblk; 33112707Smckusick dq->dq_dev = fsdev; 33212707Smckusick strcpy(*dqf, fs->fs_file); 33312707Smckusick dq++, dqf++; 33412707Smckusick } 33512707Smckusick endfsent(); 33612707Smckusick **dqf = '\0'; 33712707Smckusick } 33812707Smckusick 33912707Smckusick putdiscq(uid, dq, dqf) 34012707Smckusick register uid; 34112707Smckusick register struct dquot *dq; 34212707Smckusick register char (*dqf)[MAXPATHLEN + 1]; 34312707Smckusick { 34412707Smckusick register fd, cnt; 34512707Smckusick struct stat sb; 34612707Smckusick struct fstab *fs; 34712707Smckusick 34812707Smckusick cnt = 0; 34912707Smckusick for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) { 35012707Smckusick fs = getfsfile(*dqf); 351*12716Smckusick if (fs == NULL) { 352*12716Smckusick fprintf(stderr, "%s: not in /etc/fstab\n", *dqf); 353*12716Smckusick continue; 354*12716Smckusick } 355*12716Smckusick strcat(*dqf, "/"); 356*12716Smckusick strcat(*dqf, qfname); 357*12716Smckusick if (stat(*dqf, &sb) >= 0) 358*12716Smckusick quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb); 359*12716Smckusick if ((fd = open(*dqf, 1)) < 0) { 360*12716Smckusick perror(*dqf); 361*12716Smckusick } else { 36212707Smckusick lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0); 36312707Smckusick if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) != 36412707Smckusick sizeof (struct dqblk)) { 36512707Smckusick fprintf(stderr, "edquota: "); 36612707Smckusick perror(*dqf); 36712707Smckusick } 36812707Smckusick close(fd); 36912707Smckusick } 37012707Smckusick } 37112707Smckusick } 372