edquota.c revision 99800
1207618Srdivacky/* 2207618Srdivacky * Copyright (c) 1980, 1990, 1993 3207618Srdivacky * The Regents of the University of California. All rights reserved. 4207618Srdivacky * 5207618Srdivacky * This code is derived from software contributed to Berkeley by 6207618Srdivacky * Robert Elz at The University of Melbourne. 7207618Srdivacky * 8207618Srdivacky * Redistribution and use in source and binary forms, with or without 9207618Srdivacky * modification, are permitted provided that the following conditions 10207618Srdivacky * are met: 11207618Srdivacky * 1. Redistributions of source code must retain the above copyright 12207618Srdivacky * notice, this list of conditions and the following disclaimer. 13207618Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 14207618Srdivacky * notice, this list of conditions and the following disclaimer in the 15207618Srdivacky * documentation and/or other materials provided with the distribution. 16252723Sdim * 3. All advertising materials mentioning features or use of this software 17252723Sdim * must display the following acknowledgement: 18252723Sdim * This product includes software developed by the University of 19252723Sdim * California, Berkeley and its contributors. 20252723Sdim * 4. Neither the name of the University nor the names of its contributors 21252723Sdim * may be used to endorse or promote products derived from this software 22252723Sdim * without specific prior written permission. 23252723Sdim * 24252723Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25207618Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26207618Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27212904Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28207618Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29207618Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30245431Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31252723Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32207618Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33207618Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34207618Srdivacky * SUCH DAMAGE. 35207618Srdivacky */ 36252723Sdim 37252723Sdim#ifndef lint 38207618Srdivackystatic const char copyright[] = 39207618Srdivacky"@(#) Copyright (c) 1980, 1990, 1993\n\ 40207618Srdivacky The Regents of the University of California. All rights reserved.\n"; 41207618Srdivacky#endif /* not lint */ 42207618Srdivacky 43208599Srdivacky#ifndef lint 44207618Srdivacky#if 0 45207618Srdivackystatic char sccsid[] = "@(#)edquota.c 8.1 (Berkeley) 6/6/93"; 46207618Srdivacky#endif 47207618Srdivackystatic const char rcsid[] = 48207618Srdivacky "$FreeBSD: head/usr.sbin/edquota/edquota.c 99800 2002-07-11 18:31:16Z alfred $"; 49207618Srdivacky#endif /* not lint */ 50207618Srdivacky 51207618Srdivacky/* 52212904Sdim * Disk quota editor. 53235633Sdim */ 54207618Srdivacky#include <sys/param.h> 55207618Srdivacky#include <sys/stat.h> 56207618Srdivacky#include <sys/file.h> 57208599Srdivacky#include <sys/wait.h> 58207618Srdivacky#include <ufs/ufs/quota.h> 59207618Srdivacky#include <ctype.h> 60223017Sdim#include <err.h> 61207618Srdivacky#include <errno.h> 62208599Srdivacky#include <fstab.h> 63208599Srdivacky#include <grp.h> 64208599Srdivacky#include <pwd.h> 65207618Srdivacky#include <signal.h> 66207618Srdivacky#include <stdio.h> 67207618Srdivacky#include <stdlib.h> 68207618Srdivacky#include <string.h> 69208599Srdivacky#include <unistd.h> 70208599Srdivacky#include "pathnames.h" 71208599Srdivacky 72235633Sdimconst char *qfname = QUOTAFILENAME; 73208599Srdivackyconst char *qfextension[] = INITQFNAMES; 74208599Srdivackyconst char *quotagroup = QUOTAGROUP; 75208599Srdivackychar tmpfil[] = _PATH_TMP; 76208599Srdivacky 77235633Sdimstruct quotause { 78235633Sdim struct quotause *next; 79235633Sdim long flags; 80245431Sdim struct dqblk dqblk; 81235633Sdim char fsname[MAXPATHLEN + 1]; 82235633Sdim char qfname[1]; /* actually longer */ 83208599Srdivacky}; 84208599Srdivacky#define FOUND 0x01 85235633Sdim 86208599Srdivackyint alldigits(const char *s); 87208599Srdivackyint cvtatos(time_t, char *, time_t *); 88207618Srdivackychar *cvtstoa(time_t); 89208599Srdivackyint editit(char *); 90207618Srdivackyvoid freeprivs(struct quotause *); 91224145Sdimint getentry(const char *, int); 92212904Sdimstruct quotause *getprivs(long, int, char *); 93208599Srdivackyint hasquota(struct fstab *, int, char **); 94208599Srdivackyvoid putprivs(long, int, struct quotause *); 95208599Srdivackyint readprivs(struct quotause *, char *); 96208599Srdivackyint readtimes(struct quotause *, char *); 97208599Srdivackystatic void usage(void); 98208599Srdivackyint writetimes(struct quotause *, int, int); 99207618Srdivackyint writeprivs(struct quotause *, int, char *, int); 100208599Srdivacky 101208599Srdivackyint 102208599Srdivackymain(argc, argv) 103207618Srdivacky register char **argv; 104221345Sdim int argc; 105208599Srdivacky{ 106208599Srdivacky register struct quotause *qup, *protoprivs, *curprivs; 107208599Srdivacky register long id, protoid; 108208599Srdivacky register int quotatype, tmpfd; 109208599Srdivacky register uid_t startuid, enduid; 110208599Srdivacky char *protoname, *cp, ch; 111208599Srdivacky int tflag = 0, pflag = 0; 112208599Srdivacky char *fspath = NULL; 113208599Srdivacky char buf[30]; 114208599Srdivacky 115208599Srdivacky if (argc < 2) 116252723Sdim usage(); 117245431Sdim if (getuid()) 118207618Srdivacky errx(1, "permission denied"); 119252723Sdim quotatype = USRQUOTA; 120252723Sdim while ((ch = getopt(argc, argv, "ugtf:p:")) != -1) { 121245431Sdim switch(ch) { 122245431Sdim case 'f': 123252723Sdim fspath = optarg; 124252723Sdim break; 125252723Sdim case 'p': 126252723Sdim protoname = optarg; 127252723Sdim pflag++; 128252723Sdim break; 129252723Sdim case 'g': 130252723Sdim quotatype = GRPQUOTA; 131252723Sdim break; 132252723Sdim case 'u': 133252723Sdim quotatype = USRQUOTA; 134252723Sdim break; 135252723Sdim case 't': 136252723Sdim tflag++; 137212904Sdim break; 138212904Sdim default: 139212904Sdim usage(); 140224145Sdim } 141210299Sed } 142208599Srdivacky argc -= optind; 143208599Srdivacky argv += optind; 144208599Srdivacky if (pflag) { 145208599Srdivacky if ((protoid = getentry(protoname, quotatype)) == -1) 146207618Srdivacky exit(1); 147263509Sdim protoprivs = getprivs(protoid, quotatype, fspath); 148208599Srdivacky for (qup = protoprivs; qup; qup = qup->next) { 149208599Srdivacky qup->dqblk.dqb_btime = 0; 150208599Srdivacky qup->dqblk.dqb_itime = 0; 151208599Srdivacky } 152207618Srdivacky while (argc-- > 0) { 153207618Srdivacky if (isdigit(*argv[0]) && 154207618Srdivacky (cp = strchr(*argv, '-')) != NULL) { 155207618Srdivacky *cp++ = '\0'; 156207618Srdivacky startuid = atoi(*argv); 157207618Srdivacky enduid = atoi(cp); 158207618Srdivacky if (enduid < startuid) 159207618Srdivacky errx(1, 160207618Srdivacky "ending uid (%d) must be >= starting uid (%d) when using uid ranges", 161207618Srdivacky enduid, startuid); 162207618Srdivacky for ( ; startuid <= enduid; startuid++) { 163207618Srdivacky snprintf(buf, sizeof(buf), "%d", 164208599Srdivacky startuid); 165210299Sed if ((id = getentry(buf, quotatype)) < 0) 166210299Sed continue; 167207618Srdivacky putprivs(id, quotatype, protoprivs); 168208599Srdivacky } 169207618Srdivacky continue; 170208599Srdivacky } 171208599Srdivacky if ((id = getentry(*argv++, quotatype)) < 0) 172208599Srdivacky continue; 173208599Srdivacky putprivs(id, quotatype, protoprivs); 174208599Srdivacky } 175207618Srdivacky exit(0); 176208599Srdivacky } 177208599Srdivacky tmpfd = mkstemp(tmpfil); 178208599Srdivacky fchown(tmpfd, getuid(), getgid()); 179235633Sdim if (tflag) { 180235633Sdim protoprivs = getprivs(0, quotatype, fspath); 181235633Sdim if (writetimes(protoprivs, tmpfd, quotatype) == 0) 182235633Sdim exit(1); 183235633Sdim if (editit(tmpfil) && readtimes(protoprivs, tmpfil)) 184235633Sdim putprivs(0, quotatype, protoprivs); 185235633Sdim freeprivs(protoprivs); 186235633Sdim close(tmpfd); 187235633Sdim unlink(tmpfil); 188235633Sdim exit(0); 189208599Srdivacky } 190208599Srdivacky for ( ; argc > 0; argc--, argv++) { 191208599Srdivacky if ((id = getentry(*argv, quotatype)) == -1) 192208599Srdivacky continue; 193245431Sdim curprivs = getprivs(id, quotatype, fspath); 194208599Srdivacky if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) 195207618Srdivacky continue; 196207618Srdivacky if (editit(tmpfil) && readprivs(curprivs, tmpfil)) 197207618Srdivacky putprivs(id, quotatype, curprivs); 198207618Srdivacky freeprivs(curprivs); 199207618Srdivacky } 200207618Srdivacky close(tmpfd); 201207618Srdivacky unlink(tmpfil); 202207618Srdivacky exit(0); 203207618Srdivacky} 204207618Srdivacky 205207618Srdivackystatic void 206207618Srdivackyusage() 207207618Srdivacky{ 208207618Srdivacky fprintf(stderr, "%s\n%s\n%s\n%s\n", 209207618Srdivacky "usage: edquota [-u] [-f fspath] [-p username] username ...", 210207618Srdivacky " edquota -g [-f fspath] [-p groupname] groupname ...", 211207618Srdivacky " edquota [-u] -t [-f fspath]", 212207618Srdivacky " edquota -g -t [-f fspath]"); 213207618Srdivacky exit(1); 214207618Srdivacky} 215207618Srdivacky 216208599Srdivacky/* 217208599Srdivacky * This routine converts a name for a particular quota type to 218207618Srdivacky * an identifier. This routine must agree with the kernel routine 219208599Srdivacky * getinoquota as to the interpretation of quota types. 220208599Srdivacky */ 221208599Srdivackyint 222208599Srdivackygetentry(name, quotatype) 223208599Srdivacky const char *name; 224207618Srdivacky int quotatype; 225208599Srdivacky{ 226245431Sdim struct passwd *pw; 227245431Sdim struct group *gr; 228245431Sdim 229245431Sdim if (alldigits(name)) 230208599Srdivacky return (atoi(name)); 231207618Srdivacky switch(quotatype) { 232208599Srdivacky case USRQUOTA: 233208599Srdivacky if ((pw = getpwnam(name))) 234208599Srdivacky return (pw->pw_uid); 235208599Srdivacky warnx("%s: no such user", name); 236208599Srdivacky break; 237208599Srdivacky case GRPQUOTA: 238208599Srdivacky if ((gr = getgrnam(name))) 239208599Srdivacky return (gr->gr_gid); 240208599Srdivacky warnx("%s: no such group", name); 241207618Srdivacky break; 242208599Srdivacky default: 243207618Srdivacky warnx("%d: unknown quota type", quotatype); 244208599Srdivacky break; 245208599Srdivacky } 246235633Sdim sleep(1); 247235633Sdim return (-1); 248235633Sdim} 249235633Sdim 250208599Srdivacky/* 251208599Srdivacky * Collect the requested quota information. 252208599Srdivacky */ 253208599Srdivackystruct quotause * 254207618Srdivackygetprivs(id, quotatype, fspath) 255208599Srdivacky register long id; 256208599Srdivacky int quotatype; 257208599Srdivacky char *fspath; 258208599Srdivacky{ 259235633Sdim register struct fstab *fs; 260208599Srdivacky register struct quotause *qup, *quptail; 261208599Srdivacky struct quotause *quphead; 262207618Srdivacky int qcmd, qupsize, fd; 263207618Srdivacky char *qfpathname; 264208599Srdivacky static int warned = 0; 265212904Sdim 266208599Srdivacky setfsent(); 267208599Srdivacky quphead = (struct quotause *)0; 268208599Srdivacky qcmd = QCMD(Q_GETQUOTA, quotatype); 269235633Sdim while ((fs = getfsent())) { 270208599Srdivacky if (fspath && *fspath && strcmp(fspath, fs->fs_spec) && 271208599Srdivacky strcmp(fspath, fs->fs_file)) 272208599Srdivacky continue; 273207618Srdivacky if (strcmp(fs->fs_vfstype, "ufs")) 274208599Srdivacky continue; 275208599Srdivacky if (!hasquota(fs, quotatype, &qfpathname)) 276208599Srdivacky continue; 277235633Sdim qupsize = sizeof(*qup) + strlen(qfpathname); 278235633Sdim if ((qup = (struct quotause *)malloc(qupsize)) == NULL) 279207618Srdivacky errx(2, "out of memory"); 280208599Srdivacky if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { 281208599Srdivacky if (errno == EOPNOTSUPP && !warned) { 282208599Srdivacky warned++; 283208599Srdivacky warnx("warning: quotas are not compiled into this kernel"); 284208599Srdivacky sleep(3); 285235633Sdim } 286218893Sdim if ((fd = open(qfpathname, O_RDONLY)) < 0) { 287235633Sdim fd = open(qfpathname, O_RDWR|O_CREAT, 0640); 288235633Sdim if (fd < 0 && errno != ENOENT) { 289208599Srdivacky warn("%s", qfpathname); 290208599Srdivacky free(qup); 291208599Srdivacky continue; 292207618Srdivacky } 293212904Sdim warnx("creating quota file %s", qfpathname); 294212904Sdim sleep(3); 295212904Sdim (void) fchown(fd, getuid(), 296263509Sdim getentry(quotagroup, GRPQUOTA)); 297235633Sdim (void) fchmod(fd, 0640); 298224145Sdim } 299224145Sdim lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); 300263509Sdim switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { 301263509Sdim case 0: /* EOF */ 302263509Sdim /* 303212904Sdim * Convert implicit 0 quota (EOF) 304212904Sdim * into an explicit one (zero'ed dqblk) 305212904Sdim */ 306212904Sdim bzero((caddr_t)&qup->dqblk, 307212904Sdim sizeof(struct dqblk)); 308263509Sdim break; 309212904Sdim 310263509Sdim case sizeof(struct dqblk): /* OK */ 311263509Sdim break; 312263509Sdim 313263509Sdim default: /* ERROR */ 314263509Sdim warn("read error in %s", qfpathname); 315263509Sdim close(fd); 316212904Sdim free(qup); 317235633Sdim continue; 318235633Sdim } 319235633Sdim close(fd); 320224145Sdim } 321208599Srdivacky strcpy(qup->qfname, qfpathname); 322208599Srdivacky strcpy(qup->fsname, fs->fs_file); 323207618Srdivacky if (quphead == NULL) 324208599Srdivacky quphead = qup; 325207618Srdivacky else 326207618Srdivacky quptail->next = qup; 327208599Srdivacky quptail = qup; 328245431Sdim qup->next = 0; 329208599Srdivacky } 330208599Srdivacky endfsent(); 331208599Srdivacky return (quphead); 332208599Srdivacky} 333208599Srdivacky 334208599Srdivacky/* 335208599Srdivacky * Store the requested quota information. 336208599Srdivacky */ 337208599Srdivackyvoid 338207618Srdivackyputprivs(id, quotatype, quplist) 339207618Srdivacky long id; 340208599Srdivacky int quotatype; 341208599Srdivacky struct quotause *quplist; 342208599Srdivacky{ 343208599Srdivacky register struct quotause *qup; 344208599Srdivacky int qcmd, fd; 345208599Srdivacky 346208599Srdivacky qcmd = QCMD(Q_SETQUOTA, quotatype); 347208599Srdivacky for (qup = quplist; qup; qup = qup->next) { 348252723Sdim if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0) 349208599Srdivacky continue; 350208599Srdivacky if ((fd = open(qup->qfname, O_WRONLY)) < 0) { 351208599Srdivacky warn("%s", qup->qfname); 352208599Srdivacky } else { 353208599Srdivacky lseek(fd, (long)id * (long)sizeof (struct dqblk), 0); 354208599Srdivacky if (write(fd, &qup->dqblk, sizeof (struct dqblk)) != 355208599Srdivacky sizeof (struct dqblk)) { 356208599Srdivacky warn("%s", qup->qfname); 357208599Srdivacky } 358208599Srdivacky close(fd); 359218893Sdim } 360208599Srdivacky } 361208599Srdivacky} 362208599Srdivacky 363207618Srdivacky/* 364208599Srdivacky * Take a list of priviledges and get it edited. 365245431Sdim */ 366245431Sdimint 367208599Srdivackyeditit(tmpf) 368208599Srdivacky char *tmpf; 369208599Srdivacky{ 370208599Srdivacky long omask; 371208599Srdivacky int pid, status; 372208599Srdivacky 373208599Srdivacky omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 374208599Srdivacky top: 375208599Srdivacky if ((pid = fork()) < 0) { 376208599Srdivacky 377208599Srdivacky if (errno == EPROCLIM) { 378208599Srdivacky warnx("you have too many processes"); 379208599Srdivacky return(0); 380208599Srdivacky } 381208599Srdivacky if (errno == EAGAIN) { 382208599Srdivacky sleep(1); 383208599Srdivacky goto top; 384208599Srdivacky } 385208599Srdivacky warn("fork"); 386208599Srdivacky return (0); 387208599Srdivacky } 388208599Srdivacky if (pid == 0) { 389208599Srdivacky register const char *ed; 390208599Srdivacky 391208599Srdivacky sigsetmask(omask); 392208599Srdivacky setgid(getgid()); 393208599Srdivacky setuid(getuid()); 394207618Srdivacky if ((ed = getenv("EDITOR")) == (char *)0) 395207618Srdivacky ed = _PATH_VI; 396208599Srdivacky execlp(ed, ed, tmpf, (char *)0); 397208599Srdivacky err(1, "%s", ed); 398208599Srdivacky } 399208599Srdivacky waitpid(pid, &status, 0); 400208599Srdivacky sigsetmask(omask); 401252723Sdim if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 402208599Srdivacky return (0); 403208599Srdivacky return (1); 404208599Srdivacky} 405208599Srdivacky 406208599Srdivacky/* 407208599Srdivacky * Convert a quotause list to an ASCII file. 408208599Srdivacky */ 409208599Srdivackyint 410208599Srdivackywriteprivs(quplist, outfd, name, quotatype) 411208599Srdivacky struct quotause *quplist; 412208599Srdivacky int outfd; 413207618Srdivacky char *name; 414208599Srdivacky int quotatype; 415208599Srdivacky{ 416245431Sdim register struct quotause *qup; 417245431Sdim FILE *fd; 418208599Srdivacky 419208599Srdivacky ftruncate(outfd, 0); 420208599Srdivacky lseek(outfd, 0, L_SET); 421208599Srdivacky if ((fd = fdopen(dup(outfd), "w")) == NULL) 422208599Srdivacky err(1, "%s", tmpfil); 423208599Srdivacky fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name); 424208599Srdivacky for (qup = quplist; qup; qup = qup->next) { 425208599Srdivacky fprintf(fd, "%s: %s %lu, limits (soft = %lu, hard = %lu)\n", 426208599Srdivacky qup->fsname, "blocks in use:", 427208599Srdivacky (unsigned long)(dbtob(qup->dqblk.dqb_curblocks) / 1024), 428208599Srdivacky (unsigned long)(dbtob(qup->dqblk.dqb_bsoftlimit) / 1024), 429208599Srdivacky (unsigned long)(dbtob(qup->dqblk.dqb_bhardlimit) / 1024)); 430208599Srdivacky fprintf(fd, "%s %lu, limits (soft = %lu, hard = %lu)\n", 431208599Srdivacky "\tinodes in use:", 432207618Srdivacky (unsigned long)qup->dqblk.dqb_curinodes, 433207618Srdivacky (unsigned long)qup->dqblk.dqb_isoftlimit, 434207618Srdivacky (unsigned long)qup->dqblk.dqb_ihardlimit); 435208599Srdivacky } 436208599Srdivacky fclose(fd); 437208599Srdivacky return (1); 438208599Srdivacky} 439208599Srdivacky 440208599Srdivacky/* 441252723Sdim * Merge changes to an ASCII file into a quotause list. 442224145Sdim */ 443208599Srdivackyint 444221345Sdimreadprivs(quplist, inname) 445208599Srdivacky struct quotause *quplist; 446208599Srdivacky char *inname; 447208599Srdivacky{ 448208599Srdivacky register struct quotause *qup; 449208599Srdivacky FILE *fd; 450208599Srdivacky unsigned long bhardlimit, bsoftlimit, curblocks; 451224145Sdim unsigned long ihardlimit, isoftlimit, curinodes; 452224145Sdim int cnt; 453208599Srdivacky register char *cp; 454235633Sdim struct dqblk dqblk; 455235633Sdim char *fsp, line1[BUFSIZ], line2[BUFSIZ]; 456235633Sdim 457235633Sdim fd = fopen(inname, "r"); 458208599Srdivacky if (fd == NULL) { 459235633Sdim warnx("can't re-read temp file!!"); 460207618Srdivacky return (0); 461221345Sdim } 462224145Sdim /* 463208599Srdivacky * Discard title line, then read pairs of lines to process. 464245431Sdim */ 465245431Sdim (void) fgets(line1, sizeof (line1), fd); 466208599Srdivacky while (fgets(line1, sizeof (line1), fd) != NULL && 467208599Srdivacky fgets(line2, sizeof (line2), fd) != NULL) { 468208599Srdivacky if ((fsp = strtok(line1, " \t:")) == NULL) { 469208599Srdivacky warnx("%s: bad format", line1); 470208599Srdivacky return (0); 471208599Srdivacky } 472208599Srdivacky if ((cp = strtok((char *)0, "\n")) == NULL) { 473208599Srdivacky warnx("%s: %s: bad format", fsp, &fsp[strlen(fsp) + 1]); 474235633Sdim return (0); 475235633Sdim } 476235633Sdim cnt = sscanf(cp, 477235633Sdim " blocks in use: %lu, limits (soft = %lu, hard = %lu)", 478208599Srdivacky &curblocks, &bsoftlimit, &bhardlimit); 479207618Srdivacky if (cnt != 3) { 480235633Sdim warnx("%s:%s: bad format", fsp, cp); 481208599Srdivacky return (0); 482208599Srdivacky } 483207618Srdivacky dqblk.dqb_curblocks = btodb((off_t)curblocks * 1024); 484207618Srdivacky dqblk.dqb_bsoftlimit = btodb((off_t)bsoftlimit * 1024); 485207618Srdivacky dqblk.dqb_bhardlimit = btodb((off_t)bhardlimit * 1024); 486208599Srdivacky if ((cp = strtok(line2, "\n")) == NULL) { 487208599Srdivacky warnx("%s: %s: bad format", fsp, line2); 488208599Srdivacky return (0); 489207618Srdivacky } 490235633Sdim cnt = sscanf(cp, 491235633Sdim "\tinodes in use: %lu, limits (soft = %lu, hard = %lu)", 492218893Sdim &curinodes, &isoftlimit, &ihardlimit); 493235633Sdim if (cnt != 3) { 494235633Sdim warnx("%s: %s: bad format", fsp, line2); 495235633Sdim return (0); 496208599Srdivacky } 497207618Srdivacky dqblk.dqb_curinodes = curinodes; 498235633Sdim dqblk.dqb_isoftlimit = isoftlimit; 499235633Sdim dqblk.dqb_ihardlimit = ihardlimit; 500235633Sdim for (qup = quplist; qup; qup = qup->next) { 501235633Sdim if (strcmp(fsp, qup->fsname)) 502235633Sdim continue; 503235633Sdim /* 504235633Sdim * Cause time limit to be reset when the quota 505235633Sdim * is next used if previously had no soft limit 506208599Srdivacky * or were under it, but now have a soft limit 507235633Sdim * and are over it. 508235633Sdim */ 509235633Sdim if (dqblk.dqb_bsoftlimit && 510235633Sdim qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit && 511207618Srdivacky (qup->dqblk.dqb_bsoftlimit == 0 || 512208599Srdivacky qup->dqblk.dqb_curblocks < 513208599Srdivacky qup->dqblk.dqb_bsoftlimit)) 514207618Srdivacky qup->dqblk.dqb_btime = 0; 515208599Srdivacky if (dqblk.dqb_isoftlimit && 516207618Srdivacky qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit && 517208599Srdivacky (qup->dqblk.dqb_isoftlimit == 0 || 518208599Srdivacky qup->dqblk.dqb_curinodes < 519245431Sdim qup->dqblk.dqb_isoftlimit)) 520208599Srdivacky qup->dqblk.dqb_itime = 0; 521208599Srdivacky qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit; 522208599Srdivacky qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit; 523208599Srdivacky qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit; 524224145Sdim qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit; 525224145Sdim qup->flags |= FOUND; 526224145Sdim if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks && 527224145Sdim dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes) 528224145Sdim break; 529235633Sdim warnx("%s: cannot change current allocation", fsp); 530235633Sdim break; 531235633Sdim } 532207618Srdivacky } 533208599Srdivacky fclose(fd); 534207618Srdivacky /* 535252723Sdim * Disable quotas for any filesystems that have not been found. 536207618Srdivacky */ 537208599Srdivacky for (qup = quplist; qup; qup = qup->next) { 538252723Sdim if (qup->flags & FOUND) { 539208599Srdivacky qup->flags &= ~FOUND; 540252723Sdim continue; 541235633Sdim } 542235633Sdim qup->dqblk.dqb_bsoftlimit = 0; 543235633Sdim qup->dqblk.dqb_bhardlimit = 0; 544208599Srdivacky qup->dqblk.dqb_isoftlimit = 0; 545207618Srdivacky qup->dqblk.dqb_ihardlimit = 0; 546218893Sdim } 547218893Sdim return (1); 548207618Srdivacky} 549208599Srdivacky 550252723Sdim/* 551208599Srdivacky * Convert a quotause list to an ASCII file of grace times. 552224145Sdim */ 553221345Sdimint 554221345Sdimwritetimes(quplist, outfd, quotatype) 555208599Srdivacky struct quotause *quplist; 556235633Sdim int outfd; 557235633Sdim int quotatype; 558235633Sdim{ 559235633Sdim register struct quotause *qup; 560208599Srdivacky FILE *fd; 561208599Srdivacky 562207618Srdivacky ftruncate(outfd, 0); 563207618Srdivacky lseek(outfd, 0, L_SET); 564208599Srdivacky if ((fd = fdopen(dup(outfd), "w")) == NULL) 565208599Srdivacky err(1, "%s", tmpfil); 566235633Sdim fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n"); 567235633Sdim fprintf(fd, "Grace period before enforcing soft limits for %ss:\n", 568235633Sdim qfextension[quotatype]); 569208599Srdivacky for (qup = quplist; qup; qup = qup->next) { 570207618Srdivacky fprintf(fd, "%s: block grace period: %s, ", 571224145Sdim qup->fsname, cvtstoa(qup->dqblk.dqb_btime)); 572263509Sdim fprintf(fd, "file grace period: %s\n", 573263509Sdim cvtstoa(qup->dqblk.dqb_itime)); 574263509Sdim } 575263509Sdim fclose(fd); 576224145Sdim return (1); 577235633Sdim} 578208599Srdivacky 579207618Srdivacky/* 580208599Srdivacky * Merge changes of grace times in an ASCII file into a quotause list. 581208599Srdivacky */ 582208599Srdivackyint 583208599Srdivackyreadtimes(quplist, inname) 584208599Srdivacky struct quotause *quplist; 585208599Srdivacky char *inname; 586208599Srdivacky{ 587208599Srdivacky register struct quotause *qup; 588235633Sdim FILE *fd; 589208599Srdivacky int cnt; 590208599Srdivacky register char *cp; 591208599Srdivacky time_t itime, btime, iseconds, bseconds; 592208599Srdivacky long l_itime, l_btime; 593210299Sed char *fsp, bunits[10], iunits[10], line1[BUFSIZ]; 594208599Srdivacky 595210299Sed fd = fopen(inname, "r"); 596210299Sed if (fd == NULL) { 597207618Srdivacky warnx("can't re-read temp file!!"); 598235633Sdim return (0); 599235633Sdim } 600208599Srdivacky /* 601208599Srdivacky * Discard two title lines, then read lines to process. 602235633Sdim */ 603235633Sdim (void) fgets(line1, sizeof (line1), fd); 604207618Srdivacky (void) fgets(line1, sizeof (line1), fd); 605235633Sdim while (fgets(line1, sizeof (line1), fd) != NULL) { 606235633Sdim if ((fsp = strtok(line1, " \t:")) == NULL) { 607235633Sdim warnx("%s: bad format", line1); 608235633Sdim return (0); 609252723Sdim } 610208599Srdivacky if ((cp = strtok((char *)0, "\n")) == NULL) { 611208599Srdivacky warnx("%s: %s: bad format", fsp, &fsp[strlen(fsp) + 1]); 612207618Srdivacky return (0); 613208599Srdivacky } 614208599Srdivacky cnt = sscanf(cp, 615208599Srdivacky " block grace period: %ld %s file grace period: %ld %s", 616208599Srdivacky &l_btime, bunits, &l_itime, iunits); 617208599Srdivacky if (cnt != 4) { 618208599Srdivacky warnx("%s:%s: bad format", fsp, cp); 619208599Srdivacky return (0); 620208599Srdivacky } 621235633Sdim btime = l_btime; 622208599Srdivacky itime = l_itime; 623208599Srdivacky if (cvtatos(btime, bunits, &bseconds) == 0) 624235633Sdim return (0); 625208599Srdivacky if (cvtatos(itime, iunits, &iseconds) == 0) 626208599Srdivacky return (0); 627218893Sdim for (qup = quplist; qup; qup = qup->next) { 628235633Sdim if (strcmp(fsp, qup->fsname)) 629235633Sdim continue; 630208599Srdivacky qup->dqblk.dqb_btime = bseconds; 631235633Sdim qup->dqblk.dqb_itime = iseconds; 632208599Srdivacky qup->flags |= FOUND; 633208599Srdivacky break; 634210299Sed } 635210299Sed } 636210299Sed fclose(fd); 637210299Sed /* 638208599Srdivacky * reset default grace periods for any filesystems 639208599Srdivacky * that have not been found. 640208599Srdivacky */ 641210299Sed for (qup = quplist; qup; qup = qup->next) { 642210299Sed if (qup->flags & FOUND) { 643210299Sed qup->flags &= ~FOUND; 644207618Srdivacky continue; 645208599Srdivacky } 646208599Srdivacky qup->dqblk.dqb_btime = 0; 647208599Srdivacky qup->dqblk.dqb_itime = 0; 648208599Srdivacky } 649208599Srdivacky return (1); 650208599Srdivacky} 651208599Srdivacky 652210299Sed/* 653210299Sed * Convert seconds to ASCII times. 654210299Sed */ 655207618Srdivackychar * 656235633Sdimcvtstoa(secs) 657235633Sdim time_t secs; 658235633Sdim{ 659252723Sdim static char buf[20]; 660208599Srdivacky 661207618Srdivacky if (secs % (24 * 60 * 60) == 0) { 662207618Srdivacky secs /= 24 * 60 * 60; 663208599Srdivacky sprintf(buf, "%ld day%s", (long)secs, secs == 1 ? "" : "s"); 664208599Srdivacky } else if (secs % (60 * 60) == 0) { 665208599Srdivacky secs /= 60 * 60; 666208599Srdivacky sprintf(buf, "%ld hour%s", (long)secs, secs == 1 ? "" : "s"); 667208599Srdivacky } else if (secs % 60 == 0) { 668245431Sdim secs /= 60; 669208599Srdivacky sprintf(buf, "%ld minute%s", (long)secs, secs == 1 ? "" : "s"); 670208599Srdivacky } else 671245431Sdim sprintf(buf, "%ld second%s", (long)secs, secs == 1 ? "" : "s"); 672207618Srdivacky return (buf); 673207618Srdivacky} 674208599Srdivacky 675208599Srdivacky/* 676208599Srdivacky * Convert ASCII input times to seconds. 677208599Srdivacky */ 678208599Srdivackyint 679208599Srdivackycvtatos(period, units, seconds) 680208599Srdivacky time_t period; 681208599Srdivacky char *units; 682208599Srdivacky time_t *seconds; 683207618Srdivacky{ 684245431Sdim 685245431Sdim if (bcmp(units, "second", 6) == 0) 686245431Sdim *seconds = period; 687245431Sdim else if (bcmp(units, "minute", 6) == 0) 688245431Sdim *seconds = period * 60; 689245431Sdim else if (bcmp(units, "hour", 4) == 0) 690245431Sdim *seconds = period * 60 * 60; 691207618Srdivacky else if (bcmp(units, "day", 3) == 0) 692207618Srdivacky *seconds = period * 24 * 60 * 60; 693210299Sed else { 694210299Sed printf("%s: bad units, specify %s\n", units, 695210299Sed "days, hours, minutes, or seconds"); 696210299Sed return (0); 697210299Sed } 698210299Sed return (1); 699210299Sed} 700210299Sed 701210299Sed/* 702210299Sed * Free a list of quotause structures. 703218893Sdim */ 704218893Sdimvoid 705210299Sedfreeprivs(quplist) 706210299Sed struct quotause *quplist; 707210299Sed{ 708218893Sdim register struct quotause *qup, *nextqup; 709210299Sed 710210299Sed for (qup = quplist; qup; qup = nextqup) { 711210299Sed nextqup = qup->next; 712210299Sed free(qup); 713210299Sed } 714210299Sed} 715210299Sed 716210299Sed/* 717210299Sed * Check whether a string is completely composed of digits. 718210299Sed */ 719210299Sedint 720252723Sdimalldigits(s) 721245431Sdim register const char *s; 722245431Sdim{ 723245431Sdim register int c; 724210299Sed 725210299Sed c = *s++; 726210299Sed do { 727210299Sed if (!isdigit(c)) 728235633Sdim return (0); 729210299Sed } while ((c = *s++)); 730210299Sed return (1); 731210299Sed} 732210299Sed 733218893Sdim/* 734210299Sed * Check to see if a particular quota is to be enabled. 735210299Sed */ 736210299Sedint 737210299Sedhasquota(fs, type, qfnamep) 738210299Sed register struct fstab *fs; 739210299Sed int type; 740235633Sdim char **qfnamep; 741210299Sed{ 742210299Sed register char *opt; 743210299Sed char *cp; 744210299Sed static char initname, usrname[100], grpname[100]; 745210299Sed static char buf[BUFSIZ]; 746210299Sed 747210299Sed if (!initname) { 748210299Sed sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); 749235633Sdim sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); 750210299Sed initname = 1; 751210299Sed } 752210299Sed strcpy(buf, fs->fs_mntops); 753235633Sdim for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 754235633Sdim if ((cp = index(opt, '='))) 755235633Sdim *cp++ = '\0'; 756235633Sdim if (type == USRQUOTA && strcmp(opt, usrname) == 0) 757235633Sdim break; 758235633Sdim if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 759235633Sdim break; 760235633Sdim } 761235633Sdim if (!opt) 762235633Sdim return (0); 763235633Sdim if (cp) { 764235633Sdim *qfnamep = cp; 765235633Sdim return (1); 766235633Sdim } 767235633Sdim (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 768210299Sed *qfnamep = buf; 769245431Sdim return (1); 770210299Sed} 771210299Sed