121516Smckusick /* 241408Smckusick * Copyright (c) 1980, 1990 Regents of the University of California. 334362Sbostic * All rights reserved. 434362Sbostic * 541408Smckusick * This code is derived from software contributed to Berkeley by 641408Smckusick * Robert Elz at The University of Melbourne. 741408Smckusick * 842797Sbostic * %sccs.include.redist.c% 921516Smckusick */ 1021516Smckusick 1112707Smckusick #ifndef lint 1221516Smckusick char copyright[] = 1341408Smckusick "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ 1421516Smckusick All rights reserved.\n"; 1534362Sbostic #endif /* not lint */ 1612707Smckusick 1721516Smckusick #ifndef lint 18*43266Smckusick static char sccsid[] = "@(#)edquota.c 5.14 (Berkeley) 06/19/90"; 1934362Sbostic #endif /* not lint */ 2021516Smckusick 2112707Smckusick /* 2212707Smckusick * Disk quota editor. 2312707Smckusick */ 2436964Sbostic #include <sys/param.h> 2536964Sbostic #include <sys/stat.h> 2636964Sbostic #include <sys/file.h> 2741408Smckusick #include <sys/wait.h> 2838516Sbostic #include <ufs/quota.h> 2912707Smckusick #include <errno.h> 3036964Sbostic #include <fstab.h> 3112707Smckusick #include <pwd.h> 3241408Smckusick #include <grp.h> 3312707Smckusick #include <ctype.h> 3436964Sbostic #include <stdio.h> 3541408Smckusick #include <string.h> 3637267Sbostic #include "pathnames.h" 3712707Smckusick 3841408Smckusick char tmpfil[] = _PATH_TMP; 3912707Smckusick 4041408Smckusick struct quotause { 4141408Smckusick struct quotause *next; 4241408Smckusick long flags; 4341408Smckusick struct dqblk dqblk; 4441408Smckusick char fsname[MAXPATHLEN + 1]; 4541444Smckusick char qfname[1]; /* actually longer */ 4641408Smckusick } *getprivs(); 4741408Smckusick #define FOUND 0x01 4812707Smckusick 4912707Smckusick main(argc, argv) 5041408Smckusick register char **argv; 5141408Smckusick int argc; 5212707Smckusick { 5341408Smckusick register struct quotause *qup, *protoprivs, *curprivs; 5441408Smckusick extern char *optarg; 5541408Smckusick extern int optind; 5641408Smckusick register long id, protoid; 5741408Smckusick register int quotatype, tmpfd; 5841408Smckusick char *protoname, ch; 5941408Smckusick int tflag = 0, pflag = 0; 6012707Smckusick 6141408Smckusick if (argc < 2) 6241408Smckusick usage(); 6312707Smckusick if (getuid()) { 6441408Smckusick fprintf(stderr, "edquota: permission denied\n"); 6512707Smckusick exit(1); 6612707Smckusick } 6741408Smckusick quotatype = USRQUOTA; 6841408Smckusick while ((ch = getopt(argc, argv, "ugtp:")) != EOF) { 6941408Smckusick switch(ch) { 7041408Smckusick case 'p': 7141408Smckusick protoname = optarg; 7241408Smckusick pflag++; 7341408Smckusick break; 7441408Smckusick case 'g': 7541408Smckusick quotatype = GRPQUOTA; 7641408Smckusick break; 7741408Smckusick case 'u': 7841408Smckusick quotatype = USRQUOTA; 7941408Smckusick break; 8041408Smckusick case 't': 8141408Smckusick tflag++; 8241408Smckusick break; 8341408Smckusick default: 8441408Smckusick usage(); 8541408Smckusick } 8641408Smckusick } 8741408Smckusick argc -= optind; 8841408Smckusick argv += optind; 8941408Smckusick if (pflag) { 9041408Smckusick if ((protoid = getentry(protoname, quotatype)) == -1) 9112803Smckusick exit(1); 9241408Smckusick protoprivs = getprivs(protoid, quotatype); 9341408Smckusick for (qup = protoprivs; qup; qup = qup->next) { 9441408Smckusick qup->dqblk.dqb_btime = 0; 9541408Smckusick qup->dqblk.dqb_itime = 0; 9612803Smckusick } 9712803Smckusick while (argc-- > 0) { 9841408Smckusick if ((id = getentry(*argv++, quotatype)) < 0) 9912803Smckusick continue; 10041408Smckusick putprivs(id, quotatype, protoprivs); 10112803Smckusick } 10212803Smckusick exit(0); 10312803Smckusick } 10441408Smckusick tmpfd = mkstemp(tmpfil); 10541408Smckusick fchown(tmpfd, getuid(), getgid()); 10641408Smckusick if (tflag) { 10741408Smckusick protoprivs = getprivs(0, quotatype); 10841408Smckusick if (writetimes(protoprivs, tmpfd, quotatype) == 0) 10941408Smckusick exit(1); 11041408Smckusick if (editit(tmpfil) && readtimes(protoprivs, tmpfd)) 11141408Smckusick putprivs(0, quotatype, protoprivs); 11241408Smckusick freeprivs(protoprivs); 11341408Smckusick exit(0); 11441408Smckusick } 11541408Smckusick for ( ; argc > 0; argc--, argv++) { 11641408Smckusick if ((id = getentry(*argv, quotatype)) == -1) 11712803Smckusick continue; 11841408Smckusick curprivs = getprivs(id, quotatype); 11941408Smckusick if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) 12041408Smckusick continue; 12141408Smckusick if (editit(tmpfil) && readprivs(curprivs, tmpfd)) 12241408Smckusick putprivs(id, quotatype, curprivs); 12341408Smckusick freeprivs(curprivs); 12412803Smckusick } 12541408Smckusick close(tmpfd); 12612707Smckusick unlink(tmpfil); 12712707Smckusick exit(0); 12812707Smckusick } 12912707Smckusick 13041408Smckusick usage() 13141408Smckusick { 13241408Smckusick fprintf(stderr, "%s%s%s%s", 13341408Smckusick "Usage: edquota [-u] [-p username] username ...\n", 13441408Smckusick "\tedquota -g [-p groupname] groupname ...\n", 13541408Smckusick "\tedquota [-u] -t\n", "\tedquota -g -t\n"); 13641408Smckusick exit(1); 13741408Smckusick } 13841408Smckusick 13941408Smckusick /* 14041408Smckusick * This routine converts a name for a particular quota type to 14141408Smckusick * an identifier. This routine must agree with the kernel routine 14241408Smckusick * getinoquota as to the interpretation of quota types. 14341408Smckusick */ 14441408Smckusick getentry(name, quotatype) 14512803Smckusick char *name; 14641408Smckusick int quotatype; 14712707Smckusick { 14812803Smckusick struct passwd *pw; 14941408Smckusick struct group *gr; 15012707Smckusick 15112707Smckusick if (alldigits(name)) 15241408Smckusick return (atoi(name)); 15341408Smckusick switch(quotatype) { 15441408Smckusick case USRQUOTA: 15541408Smckusick if (pw = getpwnam(name)) 15641408Smckusick return (pw->pw_uid); 15712803Smckusick fprintf(stderr, "%s: no such user\n", name); 15841408Smckusick break; 15941408Smckusick case GRPQUOTA: 16041408Smckusick if (gr = getgrnam(name)) 16141408Smckusick return (gr->gr_gid); 16241408Smckusick fprintf(stderr, "%s: no such group\n", name); 16341408Smckusick break; 16441408Smckusick default: 16541408Smckusick fprintf(stderr, "%d: unknown quota type\n", quotatype); 16641408Smckusick break; 16712707Smckusick } 16841408Smckusick sleep(1); 16941408Smckusick return (-1); 17012707Smckusick } 17112707Smckusick 17241408Smckusick /* 17341408Smckusick * Collect the requested quota information. 17441408Smckusick */ 17541408Smckusick struct quotause * 17641408Smckusick getprivs(id, quotatype) 17741408Smckusick register long id; 17841408Smckusick int quotatype; 17912707Smckusick { 18041408Smckusick register struct fstab *fs; 18141408Smckusick register struct quotause *qup, *quptail; 18241408Smckusick struct quotause *quphead; 18341444Smckusick int qcmd, qupsize, fd; 18441444Smckusick char *qfpathname; 18541408Smckusick static int warned = 0; 18641408Smckusick extern int errno; 18741408Smckusick 18841408Smckusick setfsent(); 18941408Smckusick quphead = (struct quotause *)0; 19041408Smckusick qcmd = QCMD(Q_GETQUOTA, quotatype); 19141408Smckusick while (fs = getfsent()) { 19241444Smckusick if (strcmp(fs->fs_vfstype, "ufs")) 19341408Smckusick continue; 19441444Smckusick if (!hasquota(fs, quotatype, &qfpathname)) 19541408Smckusick continue; 19641444Smckusick qupsize = sizeof(*qup) + strlen(qfpathname); 19741444Smckusick if ((qup = (struct quotause *)malloc(qupsize)) == NULL) { 19841408Smckusick fprintf(stderr, "edquota: out of memory\n"); 19941408Smckusick exit(2); 20041408Smckusick } 20141444Smckusick if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { 20241408Smckusick if (errno == EOPNOTSUPP && !warned) { 20341408Smckusick warned++; 20441408Smckusick fprintf(stderr, "Warning: %s\n", 20541408Smckusick "Quotas are not compiled into this kernel"); 20641408Smckusick sleep(3); 20741408Smckusick } 20841444Smckusick if ((fd = open(qfpathname, O_RDONLY)) < 0) { 20941444Smckusick fd = open(qfpathname, O_RDWR|O_CREAT, 0640); 21041444Smckusick if (fd < 0 && errno != ENOENT) { 21141444Smckusick perror(qfpathname); 21241444Smckusick free(qup); 21341444Smckusick continue; 21441444Smckusick } 21541444Smckusick fprintf(stderr, "Creating quota file %s\n", 21641444Smckusick qfpathname); 21741444Smckusick sleep(3); 21841444Smckusick (void) fchown(fd, getuid(), 21941444Smckusick getentry(quotagroup, GRPQUOTA)); 22041444Smckusick (void) fchmod(fd, 0640); 22141444Smckusick } 22241408Smckusick lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); 22341408Smckusick switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 22441408Smckusick case 0: /* EOF */ 22541408Smckusick /* 22641408Smckusick * Convert implicit 0 quota (EOF) 22741408Smckusick * into an explicit one (zero'ed dqblk) 22841408Smckusick */ 22941408Smckusick bzero((caddr_t)&qup->dqblk, 23041408Smckusick sizeof(struct dqblk)); 23141408Smckusick break; 23241408Smckusick 23341408Smckusick case sizeof(struct dqblk): /* OK */ 23441408Smckusick break; 23541408Smckusick 23641408Smckusick default: /* ERROR */ 23741408Smckusick fprintf(stderr, "edquota: read error in "); 23841444Smckusick perror(qfpathname); 23941408Smckusick close(fd); 24041408Smckusick free(qup); 24141408Smckusick continue; 24241408Smckusick } 24341444Smckusick close(fd); 24441408Smckusick } 24541444Smckusick strcpy(qup->qfname, qfpathname); 24641408Smckusick strcpy(qup->fsname, fs->fs_file); 24741408Smckusick if (quphead == NULL) 24841408Smckusick quphead = qup; 24941408Smckusick else 25041408Smckusick quptail->next = qup; 25141408Smckusick quptail = qup; 25241408Smckusick qup->next = 0; 25341408Smckusick } 25441408Smckusick endfsent(); 25541408Smckusick return (quphead); 25641408Smckusick } 25741408Smckusick 25841408Smckusick /* 25941408Smckusick * Store the requested quota information. 26041408Smckusick */ 26141408Smckusick putprivs(id, quotatype, quplist) 26241408Smckusick long id; 26341408Smckusick int quotatype; 26441408Smckusick struct quotause *quplist; 26541408Smckusick { 26641408Smckusick register struct quotause *qup; 26741408Smckusick int qcmd, fd; 26841408Smckusick 26941408Smckusick qcmd = QCMD(Q_SETQUOTA, quotatype); 27041408Smckusick for (qup = quplist; qup; qup = qup->next) { 27141444Smckusick if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0) 27241408Smckusick continue; 27341444Smckusick if ((fd = open(qup->qfname, O_WRONLY)) < 0) { 27441444Smckusick perror(qup->qfname); 27541408Smckusick } else { 27641408Smckusick lseek(fd, (long)id * (long)sizeof (struct dqblk), 0); 27741408Smckusick if (write(fd, &qup->dqblk, sizeof (struct dqblk)) != 27841408Smckusick sizeof (struct dqblk)) { 27941408Smckusick fprintf(stderr, "edquota: "); 28041444Smckusick perror(qup->qfname); 28141408Smckusick } 28241408Smckusick close(fd); 28341408Smckusick } 28441408Smckusick } 28541408Smckusick } 28641408Smckusick 28741408Smckusick /* 28841408Smckusick * Take a list of priviledges and get it edited. 28941408Smckusick */ 29041408Smckusick editit(tmpfile) 29141408Smckusick char *tmpfile; 29241408Smckusick { 29333609Sbostic long omask; 29441408Smckusick int pid, stat; 29541408Smckusick extern char *getenv(); 29612707Smckusick 29733609Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 29812707Smckusick top: 29912707Smckusick if ((pid = fork()) < 0) { 30012707Smckusick extern errno; 30112707Smckusick 30212707Smckusick if (errno == EPROCLIM) { 30312707Smckusick fprintf(stderr, "You have too many processes\n"); 30412707Smckusick return(0); 30512707Smckusick } 30612707Smckusick if (errno == EAGAIN) { 30712707Smckusick sleep(1); 30812707Smckusick goto top; 30912707Smckusick } 31012707Smckusick perror("fork"); 31112707Smckusick return (0); 31212707Smckusick } 31312707Smckusick if (pid == 0) { 31412707Smckusick register char *ed; 31512707Smckusick 31613025Ssam sigsetmask(omask); 31712707Smckusick setgid(getgid()); 31812707Smckusick setuid(getuid()); 31912707Smckusick if ((ed = getenv("EDITOR")) == (char *)0) 32037976Sbostic ed = _PATH_VI; 32141408Smckusick execlp(ed, ed, tmpfile, 0); 32212707Smckusick perror(ed); 32312707Smckusick exit(1); 32412707Smckusick } 32541408Smckusick waitpid(pid, &stat, 0); 32613025Ssam sigsetmask(omask); 32741408Smckusick if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) 32841408Smckusick return (0); 32941408Smckusick return (1); 33012707Smckusick } 33112707Smckusick 33241408Smckusick /* 33341408Smckusick * Convert a quotause list to an ASCII file. 33441408Smckusick */ 33541408Smckusick writeprivs(quplist, outfd, name, quotatype) 33641408Smckusick struct quotause *quplist; 33741408Smckusick int outfd; 33841408Smckusick char *name; 33941408Smckusick int quotatype; 34012707Smckusick { 34141408Smckusick register struct quotause *qup; 34212707Smckusick FILE *fd; 34312707Smckusick 344*43266Smckusick ftruncate(outfd, 0); 34541408Smckusick lseek(outfd, 0, L_SET); 34641408Smckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) { 34712707Smckusick fprintf(stderr, "edquota: "); 34812707Smckusick perror(tmpfil); 34912707Smckusick exit(1); 35012707Smckusick } 35141408Smckusick fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name); 35241408Smckusick for (qup = quplist; qup; qup = qup->next) { 35341408Smckusick fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n", 35441408Smckusick qup->fsname, "blocks in use:", 35541408Smckusick dbtob(qup->dqblk.dqb_curblocks) / 1024, 35641408Smckusick dbtob(qup->dqblk.dqb_bsoftlimit) / 1024, 35741408Smckusick dbtob(qup->dqblk.dqb_bhardlimit) / 1024); 35841408Smckusick fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n", 35941408Smckusick "\tinodes in use:", qup->dqblk.dqb_curinodes, 36041408Smckusick qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit); 36112707Smckusick } 36212707Smckusick fclose(fd); 36341408Smckusick return (1); 36412707Smckusick } 36512707Smckusick 36641408Smckusick /* 36741408Smckusick * Merge changes to an ASCII file into a quotause list. 36841408Smckusick */ 36941408Smckusick readprivs(quplist, infd) 37041408Smckusick struct quotause *quplist; 37141408Smckusick int infd; 37212707Smckusick { 37341408Smckusick register struct quotause *qup; 37412707Smckusick FILE *fd; 37541408Smckusick int cnt; 37641408Smckusick register char *cp; 37741408Smckusick struct dqblk dqblk; 37841408Smckusick char *fsp, line1[BUFSIZ], line2[BUFSIZ]; 37912707Smckusick 38041408Smckusick lseek(infd, 0, L_SET); 38141408Smckusick fd = fdopen(dup(infd), "r"); 38212707Smckusick if (fd == NULL) { 38312707Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 38441408Smckusick return (0); 38512707Smckusick } 38641408Smckusick /* 38741408Smckusick * Discard title line, then read pairs of lines to process. 38841408Smckusick */ 38941408Smckusick (void) fgets(line1, sizeof (line1), fd); 39041408Smckusick while (fgets(line1, sizeof (line1), fd) != NULL && 39141408Smckusick fgets(line2, sizeof (line2), fd) != NULL) { 39241408Smckusick if ((fsp = strtok(line1, " \t:")) == NULL) { 39341408Smckusick fprintf(stderr, "%s: bad format\n", line1); 39441408Smckusick return (0); 39541408Smckusick } 39641408Smckusick if ((cp = strtok((char *)0, "\n")) == NULL) { 39741408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, 39841408Smckusick &fsp[strlen(fsp) + 1]); 39941408Smckusick return (0); 40041408Smckusick } 40141408Smckusick cnt = sscanf(cp, 40241408Smckusick " blocks in use: %d, limits (soft = %d, hard = %d)", 40341408Smckusick &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit, 40441408Smckusick &dqblk.dqb_bhardlimit); 40541408Smckusick if (cnt != 3) { 40641408Smckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp); 40741408Smckusick return (0); 40841408Smckusick } 40941408Smckusick dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024); 41041408Smckusick dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024); 41141408Smckusick dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024); 41241408Smckusick if ((cp = strtok(line2, "\n")) == NULL) { 41341408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2); 41441408Smckusick return (0); 41541408Smckusick } 41641408Smckusick cnt = sscanf(cp, 41741408Smckusick "\tinodes in use: %d, limits (soft = %d, hard = %d)", 41841408Smckusick &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit, 41941408Smckusick &dqblk.dqb_ihardlimit); 42041408Smckusick if (cnt != 3) { 42141408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, line2); 42241408Smckusick return (0); 42341408Smckusick } 42441408Smckusick for (qup = quplist; qup; qup = qup->next) { 42541408Smckusick if (strcmp(fsp, qup->fsname)) 42641408Smckusick continue; 42741408Smckusick /* 42841408Smckusick * Cause time limit to be reset when the quota 42941408Smckusick * is next used if previously had no soft limit 43041408Smckusick * or were under it, but now have a soft limit 43141408Smckusick * and are over it. 43241408Smckusick */ 43341408Smckusick if (dqblk.dqb_bsoftlimit && 43441408Smckusick qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit && 43541408Smckusick (qup->dqblk.dqb_bsoftlimit == 0 || 43641408Smckusick qup->dqblk.dqb_curblocks < 43741408Smckusick qup->dqblk.dqb_bsoftlimit)) 43841408Smckusick qup->dqblk.dqb_btime = 0; 43941408Smckusick if (dqblk.dqb_isoftlimit && 44041408Smckusick qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit && 44141408Smckusick (qup->dqblk.dqb_isoftlimit == 0 || 44241408Smckusick qup->dqblk.dqb_curinodes < 44341408Smckusick qup->dqblk.dqb_isoftlimit)) 44441408Smckusick qup->dqblk.dqb_itime = 0; 44541408Smckusick qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit; 44641408Smckusick qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit; 44741408Smckusick qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit; 44841408Smckusick qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit; 44941408Smckusick qup->flags |= FOUND; 45041408Smckusick if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks && 45141408Smckusick dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes) 45241408Smckusick break; 45341408Smckusick fprintf(stderr, 45441408Smckusick "%s: cannot change current allocation\n", fsp); 45512707Smckusick break; 45641408Smckusick } 45741408Smckusick } 45841408Smckusick fclose(fd); 45941408Smckusick /* 46041408Smckusick * Disable quotas for any filesystems that have not been found. 46141408Smckusick */ 46241408Smckusick for (qup = quplist; qup; qup = qup->next) { 46341408Smckusick if (qup->flags & FOUND) { 46441408Smckusick qup->flags &= ~FOUND; 46512716Smckusick continue; 46612716Smckusick } 46741408Smckusick qup->dqblk.dqb_bsoftlimit = 0; 46841408Smckusick qup->dqblk.dqb_bhardlimit = 0; 46941408Smckusick qup->dqblk.dqb_isoftlimit = 0; 47041408Smckusick qup->dqblk.dqb_ihardlimit = 0; 47112707Smckusick } 47241408Smckusick return (1); 47341408Smckusick } 47441408Smckusick 47541408Smckusick /* 47641408Smckusick * Convert a quotause list to an ASCII file of grace times. 47741408Smckusick */ 47841408Smckusick writetimes(quplist, outfd, quotatype) 47941408Smckusick struct quotause *quplist; 48041408Smckusick int outfd; 48141408Smckusick int quotatype; 48241408Smckusick { 48341408Smckusick register struct quotause *qup; 48441408Smckusick char *cvtstoa(); 48541408Smckusick FILE *fd; 48641408Smckusick 487*43266Smckusick ftruncate(outfd, 0); 48841408Smckusick lseek(outfd, 0, L_SET); 48941408Smckusick if ((fd = fdopen(dup(outfd), "w")) == NULL) { 49041408Smckusick fprintf(stderr, "edquota: "); 49141408Smckusick perror(tmpfil); 49241408Smckusick exit(1); 49341408Smckusick } 49441408Smckusick fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n"); 49541408Smckusick fprintf(fd, "Grace period before enforcing soft limits for %ss:\n", 49641408Smckusick qfextension[quotatype]); 49741408Smckusick for (qup = quplist; qup; qup = qup->next) { 49841408Smckusick fprintf(fd, "%s: block grace period: %s, ", 49941408Smckusick qup->fsname, cvtstoa(qup->dqblk.dqb_btime)); 50041408Smckusick fprintf(fd, "file grace period: %s\n", 50141408Smckusick cvtstoa(qup->dqblk.dqb_itime)); 50241408Smckusick } 50312707Smckusick fclose(fd); 50441408Smckusick return (1); 50541408Smckusick } 50641408Smckusick 50741408Smckusick /* 50841408Smckusick * Merge changes of grace times in an ASCII file into a quotause list. 50941408Smckusick */ 51041408Smckusick readtimes(quplist, infd) 51141408Smckusick struct quotause *quplist; 51241408Smckusick int infd; 51341408Smckusick { 51441408Smckusick register struct quotause *qup; 51541408Smckusick FILE *fd; 51641408Smckusick int cnt; 51741408Smckusick register char *cp; 51841408Smckusick time_t itime, btime, iseconds, bseconds; 51941408Smckusick char *fsp, bunits[10], iunits[10], line1[BUFSIZ]; 52041408Smckusick 52141408Smckusick lseek(infd, 0, L_SET); 52241408Smckusick fd = fdopen(dup(infd), "r"); 52341408Smckusick if (fd == NULL) { 52441408Smckusick fprintf(stderr, "Can't re-read temp file!!\n"); 52541408Smckusick return (0); 52641408Smckusick } 52741408Smckusick /* 52841408Smckusick * Discard two title lines, then read lines to process. 52941408Smckusick */ 53041408Smckusick (void) fgets(line1, sizeof (line1), fd); 53141408Smckusick (void) fgets(line1, sizeof (line1), fd); 53241408Smckusick while (fgets(line1, sizeof (line1), fd) != NULL) { 53341408Smckusick if ((fsp = strtok(line1, " \t:")) == NULL) { 53441408Smckusick fprintf(stderr, "%s: bad format\n", line1); 53541408Smckusick return (0); 53641408Smckusick } 53741408Smckusick if ((cp = strtok((char *)0, "\n")) == NULL) { 53841408Smckusick fprintf(stderr, "%s: %s: bad format\n", fsp, 53941408Smckusick &fsp[strlen(fsp) + 1]); 54041408Smckusick return (0); 54141408Smckusick } 54241408Smckusick cnt = sscanf(cp, 54341408Smckusick " block grace period: %d %s file grace period: %d %s", 54441408Smckusick &btime, bunits, &itime, iunits); 54541408Smckusick if (cnt != 4) { 54641408Smckusick fprintf(stderr, "%s:%s: bad format\n", fsp, cp); 54741408Smckusick return (0); 54841408Smckusick } 54941408Smckusick if (cvtatos(btime, bunits, &bseconds) == 0) 55041408Smckusick return (0); 55141408Smckusick if (cvtatos(itime, iunits, &iseconds) == 0) 55241408Smckusick return (0); 55341408Smckusick for (qup = quplist; qup; qup = qup->next) { 55441408Smckusick if (strcmp(fsp, qup->fsname)) 55541408Smckusick continue; 55641408Smckusick qup->dqblk.dqb_btime = bseconds; 55741408Smckusick qup->dqblk.dqb_itime = iseconds; 55841408Smckusick qup->flags |= FOUND; 55912707Smckusick break; 56012707Smckusick } 56141408Smckusick } 56241408Smckusick fclose(fd); 56341408Smckusick /* 56441408Smckusick * reset default grace periods for any filesystems 56541408Smckusick * that have not been found. 56641408Smckusick */ 56741408Smckusick for (qup = quplist; qup; qup = qup->next) { 56841408Smckusick if (qup->flags & FOUND) { 56941408Smckusick qup->flags &= ~FOUND; 57012707Smckusick continue; 57112707Smckusick } 57241408Smckusick qup->dqblk.dqb_btime = 0; 57341408Smckusick qup->dqblk.dqb_itime = 0; 57412707Smckusick } 57541408Smckusick return (1); 57612707Smckusick } 57712707Smckusick 57841408Smckusick /* 57941408Smckusick * Convert seconds to ASCII times. 58041408Smckusick */ 58112707Smckusick char * 58241408Smckusick cvtstoa(time) 58341408Smckusick time_t time; 58412707Smckusick { 58541408Smckusick static char buf[20]; 58612707Smckusick 58741408Smckusick if (time % (24 * 60 * 60) == 0) { 58841408Smckusick time /= 24 * 60 * 60; 58941408Smckusick sprintf(buf, "%d day%s", time, time == 1 ? "" : "s"); 59041408Smckusick } else if (time % (60 * 60) == 0) { 59141408Smckusick time /= 60 * 60; 59241408Smckusick sprintf(buf, "%d hour%s", time, time == 1 ? "" : "s"); 59341408Smckusick } else if (time % 60 == 0) { 59441408Smckusick time /= 60; 59541408Smckusick sprintf(buf, "%d minute%s", time, time == 1 ? "" : "s"); 59641408Smckusick } else 59741408Smckusick sprintf(buf, "%d second%s", time, time == 1 ? "" : "s"); 59841408Smckusick return (buf); 59941408Smckusick } 60041408Smckusick 60141408Smckusick /* 60241408Smckusick * Convert ASCII input times to seconds. 60341408Smckusick */ 60441408Smckusick cvtatos(time, units, seconds) 60541408Smckusick time_t time; 60641408Smckusick char *units; 60741408Smckusick time_t *seconds; 60841408Smckusick { 60941408Smckusick 61041408Smckusick if (bcmp(units, "second", 6) == 0) 61141408Smckusick *seconds = time; 61241408Smckusick else if (bcmp(units, "minute", 6) == 0) 61341408Smckusick *seconds = time * 60; 61441408Smckusick else if (bcmp(units, "hour", 4) == 0) 61541408Smckusick *seconds = time * 60 * 60; 61641408Smckusick else if (bcmp(units, "day", 3) == 0) 61741408Smckusick *seconds = time * 24 * 60 * 60; 61841408Smckusick else { 61941408Smckusick printf("%s: bad units, specify %s\n", units, 62041408Smckusick "days, hours, minutes, or seconds"); 62141408Smckusick return (0); 62212707Smckusick } 62341408Smckusick return (1); 62412707Smckusick } 62512707Smckusick 62641408Smckusick /* 62741408Smckusick * Free a list of quotause structures. 62841408Smckusick */ 62941408Smckusick freeprivs(quplist) 63041408Smckusick struct quotause *quplist; 63141408Smckusick { 63241408Smckusick register struct quotause *qup, *nextqup; 63341408Smckusick 63441408Smckusick for (qup = quplist; qup; qup = nextqup) { 63541408Smckusick nextqup = qup->next; 63641408Smckusick free(qup); 63741408Smckusick } 63841408Smckusick } 63941408Smckusick 64041408Smckusick /* 64141408Smckusick * Check whether a string is completely composed of digits. 64241408Smckusick */ 64312707Smckusick alldigits(s) 64412707Smckusick register char *s; 64512707Smckusick { 64612707Smckusick register c; 64712707Smckusick 64812707Smckusick c = *s++; 64912707Smckusick do { 65012707Smckusick if (!isdigit(c)) 65112707Smckusick return (0); 65212707Smckusick } while (c = *s++); 65312707Smckusick return (1); 65412707Smckusick } 65512707Smckusick 65641408Smckusick /* 65741408Smckusick * Check to see if a particular quota is to be enabled. 65841408Smckusick */ 65941444Smckusick hasquota(fs, type, qfnamep) 66041444Smckusick register struct fstab *fs; 66141408Smckusick int type; 66241444Smckusick char **qfnamep; 66312707Smckusick { 66441408Smckusick register char *opt; 66541444Smckusick char *cp, *index(), *strtok(); 66641408Smckusick static char initname, usrname[100], grpname[100]; 66741444Smckusick static char buf[BUFSIZ]; 66812707Smckusick 66941408Smckusick if (!initname) { 67041408Smckusick sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 67141408Smckusick sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 67241408Smckusick initname = 1; 67312707Smckusick } 67441444Smckusick strcpy(buf, fs->fs_mntops); 67541408Smckusick for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 67641444Smckusick if (cp = index(opt, '=')) 67741444Smckusick *cp++ = '\0'; 67841408Smckusick if (type == USRQUOTA && strcmp(opt, usrname) == 0) 67941444Smckusick break; 68041408Smckusick if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 68141444Smckusick break; 68212707Smckusick } 68341444Smckusick if (!opt) 68441444Smckusick return (0); 68541444Smckusick if (cp) { 68641444Smckusick *qfnamep = cp; 68741444Smckusick return (1); 68841444Smckusick } 68941444Smckusick (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 69041444Smckusick *qfnamep = buf; 69141444Smckusick return (1); 69212707Smckusick } 693