diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index b9aec78919d8..afd5db6d2285 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -143,12 +143,11 @@ int pidfile_remove(struct pidfh *pfh); #ifdef _UFS_UFS_QUOTA_H_ struct quotafile; struct fstab; -struct quotafile *quota_open(const char *); -struct quotafile *quota_create(const char *); +struct quotafile *quota_open(struct fstab *, int, int); void quota_close(struct quotafile *); int quota_read(struct quotafile *, struct dqblk *, int); -int quota_write(struct quotafile *, const struct dqblk *, int); -int hasquota(struct fstab *, int, char *, int); +int quota_write_limits(struct quotafile *, struct dqblk *, int); +int quota_write_usage(struct quotafile *, struct dqblk *, int); #endif __END_DECLS diff --git a/lib/libutil/quotafile.3 b/lib/libutil/quotafile.3 index ac6af0117037..07a08a20c184 100644 --- a/lib/libutil/quotafile.3 +++ b/lib/libutil/quotafile.3 @@ -25,35 +25,132 @@ .\" .\" $FreeBSD$ .\" -.Dd November 4, 2008 +.Dd February 14, 2009 .Dt QUOTAFILE 3 .Os .Sh NAME .Nm quota_open -.Nm quota_create .Nm quota_read -.Nm quota_write +.Nm quota_write_limits +.Nm quota_write_usage .Nm quota_close -.Nd "Manipulate quota files" +.Nd "Manipulate quotas" .Sh LIBRARY .Lb libutil .Sh SYNOPSIS .In ufs/ufs/quota.h .In libutil.h +.In fstab.h .Ft "struct quotafile *" -.Fn quota_open "const char *path" -.Ft "struct quotafile *" -.Fn quota_create "const char *path" +.Fn quota_open "struct fstab *fs" "int quotatype" "int openflags" .Ft int .Fn quota_read "struct quotafile *qf" "struct dqblk *dqb" "int id" .Ft int -.Fn quota_write "struct quotafile *qf" "const struct dqblk *dqb" "int id" +.Fn quota_write_limits "struct quotafile *qf" "struct dqblk *dqb" "int id" +.Ft int +.Fn quota_write_usage "struct quotafile *qf" "struct dqblk *dqb" "int id" .Ft int .Fn quota_close "struct quotafile *qf" -.Ft int -.Fn hasquota "struct fstab *fs" "int type" "char **qfnamep" .Sh DESCRIPTION +These functions are designed to simplify access to filesystem quotas. +If quotas are active on a filesystem, +these functions will access them directly from the kernel using the +.Fn quotactl +system call. +If quotas are not active, +these functions will access them by reading and writing +the quota files directly. +.Pp +The +.Fn quota_open +function takes a pointer to an +.Vt fstab +entry corresponding to the filesystem on which quotas +are to be accessed. +The +.Va quotatype +field indicates the type of quotas being sought, either +.Dv USRQUOTA +or +.Dv GRPQUOTA . +The +.Va openflags +are those used by the +.Fn open +system call, usually either +.Dv O_RDONLY +if the quotas are just to be read, or +.Dv O_RDWR +if the quotas are to be updated. +The +.Dv O_CREAT +flag should be specified if a new quota file of the requested type should +be created if it does not already exist. +.Pp +The +.Fn quota_read +function reads the quota from the filesystem and quota type referenced by +.Va qf +for the user (or group) specified by +.Va id +into the +.Vt dqblk +quota structure pointed to by +.Va dqb . +.Pp +The +.Fn quota_write_limits +function updates the limit fields (but not the usage fields) +for the filesystem and quota type referenced by +.Va qf +for the user (or group) specified by +.Va id +from the +.Vt dqblk +quota structure pointed to by +.Va dqb . +.Pp +The +.Fn quota_write_usage +function updates the usage fields (but not the limit fields) +for the filesystem and quota type referenced by +.Va qf +for the user (or group) specified by +.Va id +from the +.Vt dqblk +quota structure pointed to by +.Va dqb . +.Pp +The +.Fn quota_close +function closes any open file descriptors and frees any storage +associated with the filesystem and quota type referenced by +.Va qf . .Sh RETURN VALUES +If the filesystem has quotas associated with it, +.Fn quota_open +returns a pointer to a +.Vt quotafile +structure used in subsequent quota access calls. +If the filesystem has no quotas, or access permission is denied +.Dv NULL +is returned and +.Va errno +is set to indicate the cause of failure. +.Pp +The +.Fn quota_read , +.Fn quota_write_limits , +.Fn quota_write_usage , +and +.Fn quota_close +functions return zero on success. +On error they return +.Dv -1 +and set +.Va errno +to indicate the cause of failure. .Sh SEE ALSO .Xr quotactl 2 , .Xr quota.user 5 , @@ -68,4 +165,6 @@ functions first appeared in The .Nm functions and this manual page were written by -.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org . +.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org +and +.An Marshall Kirk McKusick . diff --git a/lib/libutil/quotafile.c b/lib/libutil/quotafile.c index 2b43b65a382a..58c02b1c169c 100644 --- a/lib/libutil/quotafile.c +++ b/lib/libutil/quotafile.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2008 Dag-Erling Coïdan Smørgrav + * Copyright (c) 2008 Marshall Kirk McKusick * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,76 +48,132 @@ #include struct quotafile { - int fd; - int type; /* 32 or 64 */ + int fd; /* -1 means using quotactl for access */ + int wordsize; /* 32-bit or 64-bit limits */ + int quotatype; /* USRQUOTA or GRPQUOTA */ + char fsname[MAXPATHLEN + 1]; /* mount point of filesystem */ + char qfname[MAXPATHLEN + 1]; /* quota file if not using quotactl */ }; static const char *qfextension[] = INITQFNAMES; -struct quotafile * -quota_open(const char *fn) +/* + * Check to see if a particular quota is to be enabled. + */ +static int +hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize) { - struct quotafile *qf; - struct dqhdr64 dqh; - int serrno; + char *opt; + char *cp; + struct statfs sfb; + char buf[BUFSIZ]; + static char initname, usrname[100], grpname[100]; - if ((qf = calloc(1, sizeof(*qf))) == NULL) - return (NULL); - if ((qf->fd = open(fn, O_RDWR)) < 0) { - serrno = errno; - free(qf); - errno = serrno; - return (NULL); + if (!initname) { + (void)snprintf(usrname, sizeof(usrname), "%s%s", + qfextension[USRQUOTA], QUOTAFILENAME); + (void)snprintf(grpname, sizeof(grpname), "%s%s", + qfextension[GRPQUOTA], QUOTAFILENAME); + initname = 1; } - qf->type = 32; - switch (read(qf->fd, &dqh, sizeof(dqh))) { - case -1: - serrno = errno; - close(qf->fd); - free(qf); - errno = serrno; - return (NULL); - case sizeof(dqh): - if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) { - /* no magic, assume 32 bits */ - qf->type = 32; - return (qf); - } - if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION || - be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) || - be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) { - /* correct magic, wrong version / lengths */ - close(qf->fd); - free(qf); - errno = EINVAL; - return (NULL); - } - qf->type = 64; - return (qf); - default: - qf->type = 32; - return (qf); + strcpy(buf, fs->fs_mntops); + for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { + if ((cp = index(opt, '='))) + *cp++ = '\0'; + if (type == USRQUOTA && strcmp(opt, usrname) == 0) + break; + if (type == GRPQUOTA && strcmp(opt, grpname) == 0) + break; } - /* not reached */ + if (!opt) + return (0); + /* + * Ensure that the filesystem is mounted. + */ + if (statfs(fs->fs_file, &sfb) != 0 || + strcmp(fs->fs_file, sfb.f_mntonname)) { + return (0); + } + if (cp) { + strncpy(qfnamep, cp, qfbufsize); + } else { + (void)snprintf(qfnamep, qfbufsize, "%s/%s.%s", fs->fs_file, + QUOTAFILENAME, qfextension[type]); + } + return (1); } struct quotafile * -quota_create(const char *fn) +quota_open(struct fstab *fs, int quotatype, int openflags) { struct quotafile *qf; struct dqhdr64 dqh; struct group *grp; - int serrno; + int qcmd, serrno; if ((qf = calloc(1, sizeof(*qf))) == NULL) return (NULL); - if ((qf->fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) { + qf->quotatype = quotatype; + strncpy(qf->fsname, fs->fs_file, sizeof(qf->fsname)); + qcmd = QCMD(Q_GETQUOTA, quotatype); + if (quotactl(fs->fs_file, qcmd, 0, &dqh) == 0) { + qf->wordsize = 64; + qf->fd = -1; + return (qf); + } + if (!hasquota(fs, quotatype, qf->qfname, sizeof(qf->qfname))) { + free(qf); + errno = EOPNOTSUPP; + return (NULL); + } + if ((qf->fd = open(qf->qfname, openflags & O_ACCMODE)) < 0 && + (openflags & O_CREAT) == 0) { serrno = errno; free(qf); errno = serrno; return (NULL); } - qf->type = 64; + /* File open worked, so process it */ + if (qf->fd != -1) { + qf->wordsize = 32; + switch (read(qf->fd, &dqh, sizeof(dqh))) { + case -1: + serrno = errno; + close(qf->fd); + free(qf); + errno = serrno; + return (NULL); + case sizeof(dqh): + if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) { + /* no magic, assume 32 bits */ + qf->wordsize = 32; + return (qf); + } + if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION || + be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) || + be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) { + /* correct magic, wrong version / lengths */ + close(qf->fd); + free(qf); + errno = EINVAL; + return (NULL); + } + qf->wordsize = 64; + return (qf); + default: + qf->wordsize = 32; + return (qf); + } + /* not reached */ + } + /* Open failed above, but O_CREAT specified, so create a new file */ + if ((qf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) { + serrno = errno; + free(qf); + errno = serrno; + return (NULL); + } + qf->wordsize = 64; memset(&dqh, 0, sizeof(dqh)); memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic)); dqh.dqh_version = htobe32(Q_DQHDR64_VERSION); @@ -124,7 +181,7 @@ quota_create(const char *fn) dqh.dqh_reclen = htobe32(sizeof(struct dqblk64)); if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) { serrno = errno; - unlink(fn); + unlink(qf->qfname); close(qf->fd); free(qf); errno = serrno; @@ -140,7 +197,8 @@ void quota_close(struct quotafile *qf) { - close(qf->fd); + if (qf->fd != -1) + close(qf->fd); free(qf); } @@ -203,8 +261,13 @@ quota_read64(struct quotafile *qf, struct dqblk *dqb, int id) int quota_read(struct quotafile *qf, struct dqblk *dqb, int id) { + int qcmd; - switch (qf->type) { + if (qf->fd == -1) { + qcmd = QCMD(Q_GETQUOTA, qf->quotatype); + return (quotactl(qf->fsname, qcmd, id, dqb)); + } + switch (qf->wordsize) { case 32: return quota_read32(qf, dqb, id); case 64: @@ -236,7 +299,9 @@ quota_write32(struct quotafile *qf, const struct dqblk *dqb, int id) off = id * sizeof(struct dqblk32); if (lseek(qf->fd, off, SEEK_SET) == -1) return (-1); - return (write(qf->fd, &dqb32, sizeof(dqb32)) == sizeof(dqb32)); + if (write(qf->fd, &dqb32, sizeof(dqb32)) == sizeof(dqb32)) + return (0); + return (-1); } static int @@ -257,14 +322,98 @@ quota_write64(struct quotafile *qf, const struct dqblk *dqb, int id) off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64); if (lseek(qf->fd, off, SEEK_SET) == -1) return (-1); - return (write(qf->fd, &dqb64, sizeof(dqb64)) == sizeof(dqb64)); + if (write(qf->fd, &dqb64, sizeof(dqb64)) == sizeof(dqb64)) + return (0); + return (-1); } int -quota_write(struct quotafile *qf, const struct dqblk *dqb, int id) +quota_write_usage(struct quotafile *qf, struct dqblk *dqb, int id) { + struct dqblk dqbuf; + int qcmd; - switch (qf->type) { + if (qf->fd == -1) { + qcmd = QCMD(Q_SETUSE, qf->quotatype); + return (quotactl(qf->fsname, qcmd, id, dqb)); + } + /* + * Have to do read-modify-write of quota in file. + */ + if (quota_read(qf, &dqbuf, id) != 0) + return (-1); + /* + * Reset time limit if have a soft limit and were + * previously under it, but are now over it. + */ + if (dqbuf.dqb_bsoftlimit && id != 0 && + dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && + dqb->dqb_curblocks >= dqbuf.dqb_bsoftlimit) + dqbuf.dqb_btime = 0; + if (dqbuf.dqb_isoftlimit && id != 0 && + dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit && + dqb->dqb_curinodes >= dqbuf.dqb_isoftlimit) + dqbuf.dqb_itime = 0; + dqbuf.dqb_curinodes = dqb->dqb_curinodes; + dqbuf.dqb_curblocks = dqb->dqb_curblocks; + /* + * Write it back. + */ + switch (qf->wordsize) { + case 32: + return quota_write32(qf, &dqbuf, id); + case 64: + return quota_write64(qf, &dqbuf, id); + default: + errno = EINVAL; + return (-1); + } + /* not reached */ +} + +int +quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id) +{ + struct dqblk dqbuf; + int qcmd; + + if (qf->fd == -1) { + qcmd = QCMD(Q_SETQUOTA, qf->quotatype); + return (quotactl(qf->fsname, qcmd, id, dqb)); + } + /* + * Have to do read-modify-write of quota in file. + */ + if (quota_read(qf, &dqbuf, id) != 0) + return (-1); + /* + * Reset time limit if have a soft limit and were + * previously under it, but are now over it + * or if there previously was no soft limit, but + * now have one and are over it. + */ + if (dqbuf.dqb_bsoftlimit && id != 0 && + dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && + dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit) + dqb->dqb_btime = 0; + if (dqbuf.dqb_bsoftlimit == 0 && id != 0 && + dqb->dqb_bsoftlimit > 0 && + dqbuf.dqb_curblocks >= dqb->dqb_bsoftlimit) + dqb->dqb_btime = 0; + if (dqbuf.dqb_isoftlimit && id != 0 && + dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit && + dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit) + dqb->dqb_itime = 0; + if (dqbuf.dqb_isoftlimit == 0 && id !=0 && + dqb->dqb_isoftlimit > 0 && + dqbuf.dqb_curinodes >= dqb->dqb_isoftlimit) + dqb->dqb_itime = 0; + dqb->dqb_curinodes = dqbuf.dqb_curinodes; + dqb->dqb_curblocks = dqbuf.dqb_curblocks; + /* + * Write it back. + */ + switch (qf->wordsize) { case 32: return quota_write32(qf, dqb, id); case 64: @@ -275,49 +424,3 @@ quota_write(struct quotafile *qf, const struct dqblk *dqb, int id) } /* not reached */ } - -/* - * Check to see if a particular quota is to be enabled. - */ -int -hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize) -{ - char *opt; - char *cp; - struct statfs sfb; - char buf[BUFSIZ]; - static char initname, usrname[100], grpname[100]; - - if (!initname) { - (void)snprintf(usrname, sizeof(usrname), "%s%s", - qfextension[USRQUOTA], QUOTAFILENAME); - (void)snprintf(grpname, sizeof(grpname), "%s%s", - qfextension[GRPQUOTA], QUOTAFILENAME); - initname = 1; - } - strcpy(buf, fs->fs_mntops); - for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { - if ((cp = index(opt, '='))) - *cp++ = '\0'; - if (type == USRQUOTA && strcmp(opt, usrname) == 0) - break; - if (type == GRPQUOTA && strcmp(opt, grpname) == 0) - break; - } - if (!opt) - return (0); - /* - * Ensure that the filesystem is mounted. - */ - if (statfs(fs->fs_file, &sfb) != 0 || - strcmp(fs->fs_file, sfb.f_mntonname)) { - return (0); - } - if (cp) { - strncpy(qfnamep, cp, qfbufsize); - } else { - (void)snprintf(qfnamep, qfbufsize, "%s/%s.%s", fs->fs_file, - QUOTAFILENAME, qfextension[type]); - } - return (1); -} diff --git a/usr.sbin/edquota/edquota.c b/usr.sbin/edquota/edquota.c index 16594cff3abe..b2e57a155edc 100644 --- a/usr.sbin/edquota/edquota.c +++ b/usr.sbin/edquota/edquota.c @@ -84,16 +84,15 @@ __FBSDID("$FreeBSD$"); #endif const char *qfextension[] = INITQFNAMES; -const char *quotagroup = QUOTAGROUP; char tmpfil[] = _PATH_TMP; int hflag; struct quotause { struct quotause *next; - long flags; + struct quotafile *qf; struct dqblk dqblk; + int flags; char fsname[MAXPATHLEN + 1]; - char qfname[1]; /* actually longer */ }; #define FOUND 0x01 @@ -108,7 +107,7 @@ char *fmthumanvalinos(int64_t); void freeprivs(struct quotause *); int getentry(const char *, int); struct quotause *getprivs(long, int, char *); -void putprivs(long, int, struct quotause *); +void putprivs(long, struct quotause *); int readprivs(struct quotause *, char *); int readtimes(struct quotause *, char *); static void usage(void); @@ -142,6 +141,11 @@ main(int argc, char *argv[]) fspath = optarg; break; case 'p': + if (eflag) { + warnx("cannot specify both -e and -p"); + usage(); + /* not reached */ + } protoname = optarg; pflag++; break; @@ -158,7 +162,12 @@ main(int argc, char *argv[]) tflag++; break; case 'e': - if ((qup = calloc(1, sizeof(*qup) + BUFSIZ)) == NULL) + if (pflag) { + warnx("cannot specify both -e and -p"); + usage(); + /* not reached */ + } + if ((qup = calloc(1, sizeof(*qup))) == NULL) errx(2, "out of memory"); oldoptarg = optarg; for (i = 0, cp = optarg; @@ -214,7 +223,6 @@ main(int argc, char *argv[]) curprivs = qup; } eflag++; - pflag++; break; default: usage(); @@ -223,8 +231,8 @@ main(int argc, char *argv[]) } argc -= optind; argv += optind; - if (pflag) { - if (protoprivs == NULL) { + if (pflag || eflag) { + if (pflag) { if ((protoid = getentry(protoname, quotatype)) == -1) exit(1); protoprivs = getprivs(protoid, quotatype, fspath); @@ -259,22 +267,23 @@ main(int argc, char *argv[]) *argv); if ((id = getentry(buf, quotatype)) < 0) continue; - if (!eflag) { - putprivs(id, quotatype, protoprivs); + if (pflag) { + putprivs(id, protoprivs); continue; } - for (qup = protoprivs; qup; - qup = qup->next) { + for (qup = protoprivs; qup; qup = qup->next) { curprivs = getprivs(id, quotatype, qup->fsname); if (curprivs == NULL) continue; - strcpy(qup->qfname, curprivs->qfname); - strcpy(qup->fsname, curprivs->fsname); - putprivs(id, quotatype, protoprivs); + curprivs->dqblk = qup->dqblk; + putprivs(id, curprivs); + freeprivs(curprivs); } } } + if (pflag) + freeprivs(protoprivs); exit(0); } tmpfd = mkstemp(tmpfil); @@ -283,7 +292,7 @@ main(int argc, char *argv[]) if ((protoprivs = getprivs(0, quotatype, fspath)) != NULL) { if (writetimes(protoprivs, tmpfd, quotatype) != 0 && editit(tmpfil) && readtimes(protoprivs, tmpfil)) - putprivs(0L, quotatype, protoprivs); + putprivs(0L, protoprivs); freeprivs(protoprivs); } close(tmpfd); @@ -298,7 +307,7 @@ main(int argc, char *argv[]) if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) continue; if (editit(tmpfil) && readprivs(curprivs, tmpfil)) - putprivs(id, quotatype, curprivs); + putprivs(id, curprivs); freeprivs(curprivs); } close(tmpfd); @@ -366,46 +375,29 @@ getprivs(long id, int quotatype, char *fspath) struct fstab *fs; struct quotause *qup, *quptail; struct quotause *quphead; - int qcmd, qupsize; - char *qfpathname; - static int warned = 0; setfsent(); quphead = quptail = NULL; - qcmd = QCMD(Q_GETQUOTA, quotatype); while ((fs = getfsent())) { if (fspath && *fspath && strcmp(fspath, fs->fs_spec) && strcmp(fspath, fs->fs_file)) continue; if (strcmp(fs->fs_vfstype, "ufs")) continue; - if (!hasquota(fs, quotatype, &qfpathname)) + if ((qf = quota_open(fs, quotatype, O_CREAT|O_RDWR)) == NULL) { + if (errno != EOPNOTSUPP) + warn("cannot open quotas on %s", fs->fs_file); + continue; + } + if ((qup = (struct quotause *)calloc(1, sizeof(*qup))) == NULL) + errx(2, "out of memory"); + qup->qf = qf; + strncpy(qup->fsname, fs->fs_file, sizeof(qup->fsname)); + if (quota_read(qf, &qup->dqblk, id) == -1) { + warn("cannot read quotas on %s", fs->fs_file); + freeprivs(qup); continue; - qupsize = sizeof(*qup) + strlen(qfpathname); - if ((qup = (struct quotause *)malloc(qupsize)) == NULL) - errx(2, "out of memory"); - if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { - if (errno == EOPNOTSUPP && !warned) { - warned++; - warnx("warning: quotas are not compiled into this kernel"); - sleep(3); - } - if ((qf = quota_open(qfpathname)) == NULL && - (qf = quota_create(qfpathname)) == NULL) { - warn("%s", qfpathname); - free(qup); - continue; - } - if (quota_read(qf, &qup->dqblk, id) != 0) { - warn("read error in %s", qfpathname); - quota_close(qf); - free(qup); - continue; - } - quota_close(qf); } - strcpy(qup->qfname, qfpathname); - strcpy(qup->fsname, fs->fs_file); if (quphead == NULL) quphead = qup; else @@ -424,53 +416,13 @@ getprivs(long id, int quotatype, char *fspath) * Store the requested quota information. */ void -putprivs(long id, int quotatype, struct quotause *quplist) +putprivs(long id, struct quotause *quplist) { - struct quotafile *qf; struct quotause *qup; - int qcmd; - struct dqblk dqbuf; - qcmd = QCMD(Q_SETQUOTA, quotatype); - for (qup = quplist; qup; qup = qup->next) { - if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0) - continue; - if ((qf = quota_open(qup->qfname)) == NULL) { - warn("%s", qup->qfname); - continue; - } - if (quota_read(qf, &dqbuf, id) != 0) { - warn("read error in %s", qup->qfname); - quota_close(qf); - continue; - } - /* - * Reset time limit if have a soft limit and were - * previously under it, but are now over it - * or if there previously was no soft limit, but - * now have one and are over it. - */ - if (dqbuf.dqb_bsoftlimit && id != 0 && - dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && - dqbuf.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) - qup->dqblk.dqb_btime = 0; - if (dqbuf.dqb_bsoftlimit == 0 && id != 0 && - dqbuf.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) - qup->dqblk.dqb_btime = 0; - if (dqbuf.dqb_isoftlimit && id != 0 && - dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit && - dqbuf.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) - qup->dqblk.dqb_itime = 0; - if (dqbuf.dqb_isoftlimit == 0 && id !=0 && - dqbuf.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) - qup->dqblk.dqb_itime = 0; - qup->dqblk.dqb_curinodes = dqbuf.dqb_curinodes; - qup->dqblk.dqb_curblocks = dqbuf.dqb_curblocks; - if (quota_write(qf, &qup->dqblk, id) == 0) { - warn("%s", qup->qfname); - } - quota_close(qf); - } + for (qup = quplist; qup; qup = qup->next) + if (quota_write_limits(qup->qf, &qup->dqblk, id) == -1) + warn("%s", qup->fsname); } /* @@ -978,6 +930,7 @@ freeprivs(struct quotause *quplist) struct quotause *qup, *nextqup; for (qup = quplist; qup; qup = nextqup) { + quota_close(qup->qf); nextqup = qup->next; free(qup); }