121516Smckusick /* 221516Smckusick * Copyright (c) 1980 Regents of the University of California. 334362Sbostic * All rights reserved. 434362Sbostic * 534362Sbostic * Redistribution and use in source and binary forms are permitted 634777Sbostic * provided that the above copyright notice and this paragraph are 734777Sbostic * duplicated in all such forms and that any documentation, 834777Sbostic * advertising materials, and other materials related to such 934777Sbostic * distribution and use acknowledge that the software was developed 1034777Sbostic * by the University of California, Berkeley. The name of the 1134777Sbostic * University may not be used to endorse or promote products derived 1234777Sbostic * from this software without specific prior written permission. 1334777Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434777Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534777Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621516Smckusick */ 1721516Smckusick 1812707Smckusick #ifndef lint 1921516Smckusick char copyright[] = 2021516Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 2121516Smckusick All rights reserved.\n"; 2234362Sbostic #endif /* not lint */ 2312707Smckusick 2421516Smckusick #ifndef lint 25*38516Sbostic static char sccsid[] = "@(#)edquota.c 5.10 (Berkeley) 07/30/89"; 2634362Sbostic #endif /* not lint */ 2721516Smckusick 2812707Smckusick /* 2912707Smckusick * Disk quota editor. 3012707Smckusick */ 3136964Sbostic #include <sys/param.h> 3236964Sbostic #include <sys/stat.h> 3336964Sbostic #include <sys/file.h> 34*38516Sbostic #include <sys/signal.h> 35*38516Sbostic #include <ufs/quota.h> 3612707Smckusick #include <errno.h> 3736964Sbostic #include <fstab.h> 3812707Smckusick #include <pwd.h> 3912707Smckusick #include <ctype.h> 4036964Sbostic #include <stdio.h> 4137267Sbostic #include "pathnames.h" 4212707Smckusick 4312707Smckusick struct dquot dq[NMOUNT]; 4412707Smckusick struct dquot odq[NMOUNT]; 4512707Smckusick char dqf[NMOUNT][MAXPATHLEN + 1]; 4612707Smckusick char odqf[NMOUNT][MAXPATHLEN + 1]; 4712707Smckusick 4837976Sbostic char tmpfil[] = _PATH_TMP; 4912716Smckusick char *qfname = "quotas"; 5012707Smckusick char *getenv(); 5112707Smckusick 5212707Smckusick main(argc, argv) 5312707Smckusick char **argv; 5412707Smckusick { 5512803Smckusick int uid; 5612803Smckusick char *arg0; 5712707Smckusick 5812707Smckusick mktemp(tmpfil); 5912707Smckusick close(creat(tmpfil, 0600)); 6012707Smckusick chown(tmpfil, getuid(), getgid()); 6112707Smckusick arg0 = *argv++; 6212707Smckusick if (argc < 2) { 6312803Smckusick fprintf(stderr, "Usage: %s [-p username] username ...\n", arg0); 6412707Smckusick unlink(tmpfil); 6512707Smckusick exit(1); 6612707Smckusick } 6712707Smckusick --argc; 6812707Smckusick if (getuid()) { 6912707Smckusick fprintf(stderr, "%s: permission denied\n", arg0); 7012707Smckusick unlink(tmpfil); 7112707Smckusick exit(1); 7212707Smckusick } 7312803Smckusick if (argc > 2 && strcmp(*argv, "-p") == 0) { 7412803Smckusick argc--, argv++; 7512803Smckusick uid = getentry(*argv++); 7612803Smckusick if (uid < 0) { 7712803Smckusick unlink(tmpfil); 7812803Smckusick exit(1); 7912803Smckusick } 8012803Smckusick getprivs(uid); 8112803Smckusick argc--; 8212803Smckusick while (argc-- > 0) { 8312803Smckusick uid = getentry(*argv++); 8412803Smckusick if (uid < 0) 8512803Smckusick continue; 8612803Smckusick getdiscq(uid, odq, odqf); 8712803Smckusick putprivs(uid); 8812803Smckusick } 8912803Smckusick unlink(tmpfil); 9012803Smckusick exit(0); 9112803Smckusick } 9212803Smckusick while (--argc >= 0) { 9312803Smckusick uid = getentry(*argv++); 9412803Smckusick if (uid < 0) 9512803Smckusick continue; 9612803Smckusick getprivs(uid); 9712803Smckusick if (editit()) 9812803Smckusick putprivs(uid); 9912803Smckusick } 10012707Smckusick unlink(tmpfil); 10112707Smckusick exit(0); 10212707Smckusick } 10312707Smckusick 10412803Smckusick getentry(name) 10512803Smckusick char *name; 10612707Smckusick { 10712803Smckusick struct passwd *pw; 10812803Smckusick int uid; 10912707Smckusick 11012707Smckusick if (alldigits(name)) 11112707Smckusick uid = atoi(name); 11212707Smckusick else if (pw = getpwnam(name)) 11312707Smckusick uid = pw->pw_uid; 11412707Smckusick else { 11512803Smckusick fprintf(stderr, "%s: no such user\n", name); 11612707Smckusick sleep(1); 11712803Smckusick return (-1); 11812707Smckusick } 11912803Smckusick return (uid); 12012707Smckusick } 12112707Smckusick 12212707Smckusick editit() 12312707Smckusick { 12433609Sbostic register int pid, xpid; 12533609Sbostic long omask; 12633609Sbostic int stat; 12712707Smckusick 12833609Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 12912707Smckusick top: 13012707Smckusick if ((pid = fork()) < 0) { 13112707Smckusick extern errno; 13212707Smckusick 13312707Smckusick if (errno == EPROCLIM) { 13412707Smckusick fprintf(stderr, "You have too many processes\n"); 13512707Smckusick return(0); 13612707Smckusick } 13712707Smckusick if (errno == EAGAIN) { 13812707Smckusick sleep(1); 13912707Smckusick goto top; 14012707Smckusick } 14112707Smckusick perror("fork"); 14212707Smckusick return (0); 14312707Smckusick } 14412707Smckusick if (pid == 0) { 14512707Smckusick register char *ed; 14612707Smckusick 14713025Ssam sigsetmask(omask); 14812707Smckusick setgid(getgid()); 14912707Smckusick setuid(getuid()); 15012707Smckusick if ((ed = getenv("EDITOR")) == (char *)0) 15137976Sbostic ed = _PATH_VI; 15212707Smckusick execlp(ed, ed, tmpfil, 0); 15312707Smckusick perror(ed); 15412707Smckusick exit(1); 15512707Smckusick } 15612707Smckusick while ((xpid = wait(&stat)) >= 0) 15712707Smckusick if (xpid == pid) 15812707Smckusick break; 15913025Ssam sigsetmask(omask); 16012707Smckusick return (!stat); 16112707Smckusick } 16212707Smckusick 16312707Smckusick getprivs(uid) 16412707Smckusick register uid; 16512707Smckusick { 16612707Smckusick register i; 16712707Smckusick FILE *fd; 16812707Smckusick 16912707Smckusick getdiscq(uid, dq, dqf); 17012707Smckusick for (i = 0; i < NMOUNT; i++) { 17112707Smckusick odq[i] = dq[i]; 17212707Smckusick strcpy(odqf[i], dqf[i]); 17312707Smckusick } 17412707Smckusick if ((fd = fopen(tmpfil, "w")) == NULL) { 17512707Smckusick fprintf(stderr, "edquota: "); 17612707Smckusick perror(tmpfil); 17712707Smckusick exit(1); 17812707Smckusick } 17912707Smckusick for (i = 0; i < NMOUNT; i++) { 18012707Smckusick if (*dqf[i] == '\0') 18112707Smckusick continue; 18212707Smckusick fprintf(fd, 18312707Smckusick "fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n" 18412707Smckusick , dqf[i] 18525401Sbloom , dbtob(dq[i].dq_bsoftlimit) / 1024 18625401Sbloom , dbtob(dq[i].dq_bhardlimit) / 1024 18712707Smckusick , dq[i].dq_isoftlimit 18812707Smckusick , dq[i].dq_ihardlimit 18912707Smckusick ); 19012707Smckusick } 19112707Smckusick fclose(fd); 19212707Smckusick } 19312707Smckusick 19412707Smckusick putprivs(uid) 19512707Smckusick register uid; 19612707Smckusick { 19712707Smckusick register i, j; 19812707Smckusick int n; 19912707Smckusick FILE *fd; 20012707Smckusick char line[BUFSIZ]; 20112707Smckusick 20212707Smckusick fd = fopen(tmpfil, "r"); 20312707Smckusick if (fd == NULL) { 20412707Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 20512707Smckusick return; 20612707Smckusick } 20712707Smckusick for (i = 0; i < NMOUNT; i++) { 20812707Smckusick char *cp, *dp, *next(); 20912707Smckusick 21012707Smckusick if (fgets(line, sizeof (line), fd) == NULL) 21112707Smckusick break; 21212707Smckusick cp = next(line, " \t"); 21312707Smckusick if (cp == NULL) 21412707Smckusick break; 21512707Smckusick *cp++ = '\0'; 21612707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 21712707Smckusick cp++; 21812707Smckusick dp = cp, cp = next(cp, " \t"); 21912707Smckusick if (cp == NULL) 22012707Smckusick break; 22112707Smckusick *cp++ = '\0'; 22212707Smckusick while (*cp && *cp == '\t' && *cp == ' ') 22312707Smckusick cp++; 22412707Smckusick strcpy(dqf[i], dp); 22512707Smckusick n = sscanf(cp, 22612707Smckusick "blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n" 22712707Smckusick , &dq[i].dq_bsoftlimit 22812707Smckusick , &dq[i].dq_bhardlimit 22912707Smckusick , &dq[i].dq_isoftlimit 23012707Smckusick , &dq[i].dq_ihardlimit 23112707Smckusick ); 23212716Smckusick if (n != 4) { 23312716Smckusick fprintf(stderr, "%s: bad format\n", cp); 23412716Smckusick continue; 23512716Smckusick } 23625401Sbloom dq[i].dq_bsoftlimit = btodb(dq[i].dq_bsoftlimit * 1024); 23725401Sbloom dq[i].dq_bhardlimit = btodb(dq[i].dq_bhardlimit * 1024); 23812707Smckusick } 23912707Smckusick fclose(fd); 24012707Smckusick n = i; 24112707Smckusick for (i = 0; i < n; i++) { 24212707Smckusick if (*dqf[i] == '\0') 24312707Smckusick break; 24412707Smckusick for (j = 0; j < NMOUNT; j++) { 24512707Smckusick if (strcmp(dqf[i], odqf[j]) == 0) 24612707Smckusick break; 24712707Smckusick } 24812707Smckusick if (j >= NMOUNT) 24912707Smckusick continue; 25012707Smckusick *odqf[j] = '\0'; 25112707Smckusick /* 25212707Smckusick * This isn't really good enough, it is quite likely 25312707Smckusick * to have changed while we have been away editing, 25412707Smckusick * but it's not important enough to worry about at 25512707Smckusick * the minute. 25612707Smckusick */ 25712707Smckusick dq[i].dq_curblocks = odq[j].dq_curblocks; 25812707Smckusick dq[i].dq_curinodes = odq[j].dq_curinodes; 25912707Smckusick /* 26012707Smckusick * If we've upped the inode or disk block limits 26112707Smckusick * and the guy is out of warnings, reinitialize. 26212707Smckusick */ 26312707Smckusick if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit && 26412707Smckusick dq[i].dq_bwarn == 0) 26512707Smckusick dq[i].dq_bwarn = MAX_DQ_WARN; 26612707Smckusick if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit && 26712707Smckusick dq[i].dq_iwarn == 0) 26812707Smckusick dq[i].dq_iwarn = MAX_IQ_WARN; 26912707Smckusick } 27012707Smckusick if (i < NMOUNT) { 27112707Smckusick for (j = 0; j < NMOUNT; j++) { 27212707Smckusick if (*odqf[j] == '\0') 27312707Smckusick continue; 27412707Smckusick strcpy(dqf[i], odqf[j]); 27512707Smckusick dq[i].dq_isoftlimit = 0; 27612707Smckusick dq[i].dq_ihardlimit = 0; 27712707Smckusick dq[i].dq_bsoftlimit = 0; 27812707Smckusick dq[i].dq_bhardlimit = 0; 27912707Smckusick /* 28012707Smckusick * Same applies as just above 28112707Smckusick * but matters not at all, as we are just 28212707Smckusick * turning quota'ing off for this filesys. 28312707Smckusick */ 28412707Smckusick dq[i].dq_curblocks = odq[j].dq_curblocks; 28512707Smckusick dq[i].dq_curinodes = odq[j].dq_curinodes; 28612707Smckusick if (++i >= NMOUNT) 28712707Smckusick break; 28812707Smckusick } 28912707Smckusick } 29012707Smckusick if (*dqf[0]) 29112707Smckusick putdiscq(uid, dq, dqf); 29212707Smckusick } 29312707Smckusick 29412707Smckusick char * 29512707Smckusick next(cp, match) 29612707Smckusick register char *cp; 29712707Smckusick char *match; 29812707Smckusick { 29912707Smckusick register char *dp; 30012707Smckusick 30112707Smckusick while (cp && *cp) { 30212707Smckusick for (dp = match; dp && *dp; dp++) 30312707Smckusick if (*dp == *cp) 30412707Smckusick return (cp); 30512707Smckusick cp++; 30612707Smckusick } 30712707Smckusick return ((char *)0); 30812707Smckusick } 30912707Smckusick 31012707Smckusick alldigits(s) 31112707Smckusick register char *s; 31212707Smckusick { 31312707Smckusick register c; 31412707Smckusick 31512707Smckusick c = *s++; 31612707Smckusick do { 31712707Smckusick if (!isdigit(c)) 31812707Smckusick return (0); 31912707Smckusick } while (c = *s++); 32012707Smckusick return (1); 32112707Smckusick } 32212707Smckusick 32312707Smckusick getdiscq(uid, dq, dqf) 32412707Smckusick register uid; 32512707Smckusick register struct dquot *dq; 32612707Smckusick register char (*dqf)[MAXPATHLEN + 1]; 32712707Smckusick { 32812707Smckusick register struct fstab *fs; 32912716Smckusick char qfilename[MAXPATHLEN + 1]; 33021087Smckusick struct stat statb; 33121087Smckusick struct dqblk dqblk; 33221087Smckusick dev_t fsdev; 33321087Smckusick int fd; 33421087Smckusick static int warned = 0; 33521087Smckusick extern int errno; 33612707Smckusick 33712707Smckusick setfsent(); 33812707Smckusick while (fs = getfsent()) { 33912707Smckusick if (stat(fs->fs_spec, &statb) < 0) 34012707Smckusick continue; 34112707Smckusick fsdev = statb.st_rdev; 34212716Smckusick sprintf(qfilename, "%s/%s", fs->fs_file, qfname); 34312716Smckusick if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev) 34412707Smckusick continue; 34512707Smckusick if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) { 34621087Smckusick if (errno == EINVAL && !warned) { 34721087Smckusick warned++; 34821087Smckusick fprintf(stderr, "Warning: %s\n", 34921087Smckusick "Quotas are not compiled into this kernel"); 35021087Smckusick sleep(3); 35121087Smckusick } 35221087Smckusick fd = open(qfilename, O_RDONLY); 35312707Smckusick if (fd < 0) 35412707Smckusick continue; 35512722Smckusick lseek(fd, (long)(uid * sizeof dqblk), L_SET); 35624659Sserge switch (read(fd, &dqblk, sizeof dqblk)) { 35724659Sserge case 0: /* EOF */ 35824659Sserge /* 35924659Sserge * Convert implicit 0 quota (EOF) 36024659Sserge * into an explicit one (zero'ed dqblk) 36124659Sserge */ 36224659Sserge bzero((caddr_t)&dqblk, sizeof dqblk); 36324659Sserge break; 36424659Sserge 36524659Sserge case sizeof dqblk: /* OK */ 36624659Sserge break; 36724659Sserge 36824659Sserge default: /* ERROR */ 36924659Sserge fprintf(stderr, "edquota: read error in "); 37024659Sserge perror(qfilename); 37112707Smckusick close(fd); 37212707Smckusick continue; 37312707Smckusick } 37412707Smckusick close(fd); 37512707Smckusick } 37612707Smckusick dq->dq_dqb = dqblk; 37712707Smckusick dq->dq_dev = fsdev; 37812707Smckusick strcpy(*dqf, fs->fs_file); 37912707Smckusick dq++, dqf++; 38012707Smckusick } 38112707Smckusick endfsent(); 38212707Smckusick **dqf = '\0'; 38312707Smckusick } 38412707Smckusick 38512707Smckusick putdiscq(uid, dq, dqf) 38612707Smckusick register uid; 38712707Smckusick register struct dquot *dq; 38812707Smckusick register char (*dqf)[MAXPATHLEN + 1]; 38912707Smckusick { 39012707Smckusick register fd, cnt; 39112707Smckusick struct stat sb; 39212707Smckusick struct fstab *fs; 39312707Smckusick 39412707Smckusick cnt = 0; 39512707Smckusick for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) { 39612707Smckusick fs = getfsfile(*dqf); 39712716Smckusick if (fs == NULL) { 39837976Sbostic fprintf(stderr, "%s: not in fstab\n", *dqf); 39912716Smckusick continue; 40012716Smckusick } 40112716Smckusick strcat(*dqf, "/"); 40212716Smckusick strcat(*dqf, qfname); 40312716Smckusick if (stat(*dqf, &sb) >= 0) 40412716Smckusick quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb); 40512716Smckusick if ((fd = open(*dqf, 1)) < 0) { 40612716Smckusick perror(*dqf); 40712716Smckusick } else { 40812707Smckusick lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0); 40912707Smckusick if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) != 41012707Smckusick sizeof (struct dqblk)) { 41112707Smckusick fprintf(stderr, "edquota: "); 41212707Smckusick perror(*dqf); 41312707Smckusick } 41412707Smckusick close(fd); 41512707Smckusick } 41612707Smckusick } 41712707Smckusick } 418