From 8bd6a3ab4b32283502a1b58731eb0d0750b4f124 Mon Sep 17 00:00:00 2001 From: Kirk McKusick Date: Sat, 14 Feb 2009 08:08:08 +0000 Subject: [PATCH] Update the quotafile library to manage both active quotas via the quotactl(2) interface and inactive quotas by accessing the quota files directly. Update the edquota program to use this new interface as proof of concept. --- lib/libutil/libutil.h | 7 +- lib/libutil/quotafile.3 | 121 +++++++++++++-- lib/libutil/quotafile.c | 303 +++++++++++++++++++++++++------------ usr.sbin/edquota/edquota.c | 133 ++++++---------- 4 files changed, 359 insertions(+), 205 deletions(-) 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); }