112707Smckusick #ifndef lint 2*21087Smckusick static char sccsid[] = "@(#)edquota.c 4.6 (Berkeley, from Melbourne) 05/24/85"; 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> 1612803Smckusick #include <sys/stat.h> 1712803Smckusick #include <sys/file.h> 1812707Smckusick #include <sys/quota.h> 1912707Smckusick 2012707Smckusick #define DEFEDITOR "/usr/ucb/vi" 2112707Smckusick 2212707Smckusick struct dquot dq[NMOUNT]; 2312707Smckusick struct dquot odq[NMOUNT]; 2412707Smckusick char dqf[NMOUNT][MAXPATHLEN + 1]; 2512707Smckusick char odqf[NMOUNT][MAXPATHLEN + 1]; 2612707Smckusick 2712707Smckusick char tmpfil[] = "/tmp/EdP.aXXXXX"; 2812716Smckusick char *qfname = "quotas"; 2912707Smckusick char *getenv(); 3012707Smckusick 3112707Smckusick main(argc, argv) 3212707Smckusick char **argv; 3312707Smckusick { 3412803Smckusick int uid; 3512803Smckusick char *arg0; 3612707Smckusick 3712707Smckusick mktemp(tmpfil); 3812707Smckusick close(creat(tmpfil, 0600)); 3912707Smckusick chown(tmpfil, getuid(), getgid()); 4012707Smckusick arg0 = *argv++; 4112707Smckusick if (argc < 2) { 4212803Smckusick fprintf(stderr, "Usage: %s [-p username] 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 } 5212803Smckusick if (argc > 2 && strcmp(*argv, "-p") == 0) { 5312803Smckusick argc--, argv++; 5412803Smckusick uid = getentry(*argv++); 5512803Smckusick if (uid < 0) { 5612803Smckusick unlink(tmpfil); 5712803Smckusick exit(1); 5812803Smckusick } 5912803Smckusick getprivs(uid); 6012803Smckusick argc--; 6112803Smckusick while (argc-- > 0) { 6212803Smckusick uid = getentry(*argv++); 6312803Smckusick if (uid < 0) 6412803Smckusick continue; 6512803Smckusick getdiscq(uid, odq, odqf); 6612803Smckusick putprivs(uid); 6712803Smckusick } 6812803Smckusick unlink(tmpfil); 6912803Smckusick exit(0); 7012803Smckusick } 7112803Smckusick while (--argc >= 0) { 7212803Smckusick uid = getentry(*argv++); 7312803Smckusick if (uid < 0) 7412803Smckusick continue; 7512803Smckusick getprivs(uid); 7612803Smckusick if (editit()) 7712803Smckusick putprivs(uid); 7812803Smckusick } 7912707Smckusick unlink(tmpfil); 8012707Smckusick exit(0); 8112707Smckusick } 8212707Smckusick 8312803Smckusick getentry(name) 8412803Smckusick char *name; 8512707Smckusick { 8612803Smckusick struct passwd *pw; 8712803Smckusick int uid; 8812707Smckusick 8912707Smckusick if (alldigits(name)) 9012707Smckusick uid = atoi(name); 9112707Smckusick else if (pw = getpwnam(name)) 9212707Smckusick uid = pw->pw_uid; 9312707Smckusick else { 9412803Smckusick fprintf(stderr, "%s: no such user\n", name); 9512707Smckusick sleep(1); 9612803Smckusick return (-1); 9712707Smckusick } 9812803Smckusick return (uid); 9912707Smckusick } 10012707Smckusick 10112707Smckusick editit() 10212707Smckusick { 10312707Smckusick register pid, xpid; 10413025Ssam int stat, omask; 10512707Smckusick 10613025Ssam #define mask(s) (1<<((s)-1)) 10713025Ssam omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP)); 10812707Smckusick top: 10912707Smckusick if ((pid = fork()) < 0) { 11012707Smckusick extern errno; 11112707Smckusick 11212707Smckusick if (errno == EPROCLIM) { 11312707Smckusick fprintf(stderr, "You have too many processes\n"); 11412707Smckusick return(0); 11512707Smckusick } 11612707Smckusick if (errno == EAGAIN) { 11712707Smckusick sleep(1); 11812707Smckusick goto top; 11912707Smckusick } 12012707Smckusick perror("fork"); 12112707Smckusick return (0); 12212707Smckusick } 12312707Smckusick if (pid == 0) { 12412707Smckusick register char *ed; 12512707Smckusick 12613025Ssam sigsetmask(omask); 12712707Smckusick setgid(getgid()); 12812707Smckusick setuid(getuid()); 12912707Smckusick if ((ed = getenv("EDITOR")) == (char *)0) 13012707Smckusick ed = DEFEDITOR; 13112707Smckusick execlp(ed, ed, tmpfil, 0); 13212707Smckusick perror(ed); 13312707Smckusick exit(1); 13412707Smckusick } 13512707Smckusick while ((xpid = wait(&stat)) >= 0) 13612707Smckusick if (xpid == pid) 13712707Smckusick break; 13813025Ssam sigsetmask(omask); 13912707Smckusick return (!stat); 14012707Smckusick } 14112707Smckusick 14212707Smckusick getprivs(uid) 14312707Smckusick register uid; 14412707Smckusick { 14512707Smckusick register i; 14612707Smckusick FILE *fd; 14712707Smckusick 14812707Smckusick getdiscq(uid, dq, dqf); 14912707Smckusick for (i = 0; i < NMOUNT; i++) { 15012707Smckusick odq[i] = dq[i]; 15112707Smckusick strcpy(odqf[i], dqf[i]); 15212707Smckusick } 15312707Smckusick if ((fd = fopen(tmpfil, "w")) == NULL) { 15412707Smckusick fprintf(stderr, "edquota: "); 15512707Smckusick perror(tmpfil); 15612707Smckusick exit(1); 15712707Smckusick } 15812707Smckusick for (i = 0; i < NMOUNT; i++) { 15912707Smckusick if (*dqf[i] == '\0') 16012707Smckusick continue; 16112707Smckusick fprintf(fd, 16212707Smckusick "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n" 16312707Smckusick , dqf[i] 16412716Smckusick , dq[i].dq_bsoftlimit / btodb(1024) 16512716Smckusick , dq[i].dq_bhardlimit / btodb(1024) 16612707Smckusick , dq[i].dq_isoftlimit 16712707Smckusick , dq[i].dq_ihardlimit 16812707Smckusick ); 16912707Smckusick } 17012707Smckusick fclose(fd); 17112707Smckusick } 17212707Smckusick 17312707Smckusick putprivs(uid) 17412707Smckusick register uid; 17512707Smckusick { 17612707Smckusick register i, j; 17712707Smckusick int n; 17812707Smckusick FILE *fd; 17912707Smckusick char line[BUFSIZ]; 18012707Smckusick 18112707Smckusick fd = fopen(tmpfil, "r"); 18212707Smckusick if (fd == NULL) { 18312707Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 18412707Smckusick return; 18512707Smckusick } 18612707Smckusick for (i = 0; i < NMOUNT; i++) { 18712707Smckusick char *cp, *dp, *next(); 18812707Smckusick 18912707Smckusick if (fgets(line, sizeof (line), fd) == NULL) 19012707Smckusick break; 19112707Smckusick cp = next(line, " \t"); 19212707Smckusick if (cp == NULL) 19312707Smckusick break; 19412707Smckusick *cp++ = '\0'; 19512707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 19612707Smckusick cp++; 19712707Smckusick dp = cp, cp = next(cp, " \t"); 19812707Smckusick if (cp == NULL) 19912707Smckusick break; 20012707Smckusick *cp++ = '\0'; 20112707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 20212707Smckusick cp++; 20312707Smckusick strcpy(dqf[i], dp); 20412707Smckusick n = sscanf(cp, 20512707Smckusick "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n" 20612707Smckusick , &dq[i].dq_bsoftlimit 20712707Smckusick , &dq[i].dq_bhardlimit 20812707Smckusick , &dq[i].dq_isoftlimit 20912707Smckusick , &dq[i].dq_ihardlimit 21012707Smckusick ); 21112716Smckusick if (n != 4) { 21212716Smckusick fprintf(stderr, "%s: bad format\n", cp); 21312716Smckusick continue; 21412716Smckusick } 21512716Smckusick dq[i].dq_bsoftlimit *= btodb(1024); 21612716Smckusick dq[i].dq_bhardlimit *= btodb(1024); 21712707Smckusick } 21812707Smckusick fclose(fd); 21912707Smckusick n = i; 22012707Smckusick for (i = 0; i < n; i++) { 22112707Smckusick if (*dqf[i] == '\0') 22212707Smckusick break; 22312707Smckusick for (j = 0; j < NMOUNT; j++) { 22412707Smckusick if (strcmp(dqf[i], odqf[j]) == 0) 22512707Smckusick break; 22612707Smckusick } 22712707Smckusick if (j >= NMOUNT) 22812707Smckusick continue; 22912707Smckusick *odqf[j] = '\0'; 23012707Smckusick if (dq[i].dq_isoftlimit == odq[j].dq_isoftlimit && 23112707Smckusick dq[i].dq_ihardlimit == odq[j].dq_ihardlimit && 23212707Smckusick dq[i].dq_bsoftlimit == odq[j].dq_bsoftlimit && 23312707Smckusick dq[i].dq_bhardlimit == odq[j].dq_bhardlimit) { 23412716Smckusick for (j = i; j < NMOUNT; j++) { 23512707Smckusick dq[j] = dq[j+1]; 23612707Smckusick strcpy(dqf[j], dqf[j+1]); 23712707Smckusick } 23812707Smckusick *dqf[j] = '\0'; 23912707Smckusick i--; 24012707Smckusick continue; 24112707Smckusick } 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]; 321*21087Smckusick struct stat statb; 322*21087Smckusick struct dqblk dqblk; 323*21087Smckusick dev_t fsdev; 324*21087Smckusick int fd; 325*21087Smckusick static int warned = 0; 326*21087Smckusick 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) { 337*21087Smckusick if (errno == EINVAL && !warned) { 338*21087Smckusick warned++; 339*21087Smckusick fprintf(stderr, "Warning: %s\n", 340*21087Smckusick "Quotas are not compiled into this kernel"); 341*21087Smckusick sleep(3); 342*21087Smckusick } 343*21087Smckusick fd = open(qfilename, O_RDONLY); 34412707Smckusick if (fd < 0) 34512707Smckusick continue; 34612722Smckusick lseek(fd, (long)(uid * sizeof dqblk), L_SET); 34712707Smckusick if (read(fd, &dqblk, sizeof dqblk) != sizeof (dqblk)) { 34812707Smckusick close(fd); 34912707Smckusick continue; 35012707Smckusick } 35112707Smckusick close(fd); 35212707Smckusick } 35312707Smckusick dq->dq_dqb = dqblk; 35412707Smckusick dq->dq_dev = fsdev; 35512707Smckusick strcpy(*dqf, fs->fs_file); 35612707Smckusick dq++, dqf++; 35712707Smckusick } 35812707Smckusick endfsent(); 35912707Smckusick **dqf = '\0'; 36012707Smckusick } 36112707Smckusick 36212707Smckusick putdiscq(uid, dq, dqf) 36312707Smckusick register uid; 36412707Smckusick register struct dquot *dq; 36512707Smckusick register char (*dqf)[MAXPATHLEN + 1]; 36612707Smckusick { 36712707Smckusick register fd, cnt; 36812707Smckusick struct stat sb; 36912707Smckusick struct fstab *fs; 37012707Smckusick 37112707Smckusick cnt = 0; 37212707Smckusick for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) { 37312707Smckusick fs = getfsfile(*dqf); 37412716Smckusick if (fs == NULL) { 37512716Smckusick fprintf(stderr, "%s: not in /etc/fstab\n", *dqf); 37612716Smckusick continue; 37712716Smckusick } 37812716Smckusick strcat(*dqf, "/"); 37912716Smckusick strcat(*dqf, qfname); 38012716Smckusick if (stat(*dqf, &sb) >= 0) 38112716Smckusick quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb); 38212716Smckusick if ((fd = open(*dqf, 1)) < 0) { 38312716Smckusick perror(*dqf); 38412716Smckusick } else { 38512707Smckusick lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0); 38612707Smckusick if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) != 38712707Smckusick sizeof (struct dqblk)) { 38812707Smckusick fprintf(stderr, "edquota: "); 38912707Smckusick perror(*dqf); 39012707Smckusick } 39112707Smckusick close(fd); 39212707Smckusick } 39312707Smckusick } 39412707Smckusick } 395