svn commit: r188604 - in projects/quota64: lib/libutil usr.sbin/edquota

Kirk McKusick mckusick at FreeBSD.org
Sat Feb 14 00:08:09 PST 2009


Author: mckusick
Date: Sat Feb 14 08:08:08 2009
New Revision: 188604
URL: http://svn.freebsd.org/changeset/base/188604

Log:
  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.

Modified:
  projects/quota64/lib/libutil/libutil.h
  projects/quota64/lib/libutil/quotafile.3
  projects/quota64/lib/libutil/quotafile.c
  projects/quota64/usr.sbin/edquota/edquota.c

Modified: projects/quota64/lib/libutil/libutil.h
==============================================================================
--- projects/quota64/lib/libutil/libutil.h	Fri Feb 13 23:36:08 2009	(r188603)
+++ projects/quota64/lib/libutil/libutil.h	Sat Feb 14 08:08:08 2009	(r188604)
@@ -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

Modified: projects/quota64/lib/libutil/quotafile.3
==============================================================================
--- projects/quota64/lib/libutil/quotafile.3	Fri Feb 13 23:36:08 2009	(r188603)
+++ projects/quota64/lib/libutil/quotafile.3	Sat Feb 14 08:08:08 2009	(r188604)
@@ -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_close "struct quotafile *qf"
+.Fn quota_write_usage "struct quotafile *qf" "struct dqblk *dqb" "int id"
 .Ft int
-.Fn hasquota "struct fstab *fs" "int type" "char **qfnamep"
+.Fn quota_close "struct quotafile *qf"
 .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 at FreeBSD.org .
+.An Dag-Erling Sm\(/orgrav Aq des at FreeBSD.org 
+and
+.An Marshall Kirk McKusick .

Modified: projects/quota64/lib/libutil/quotafile.c
==============================================================================
--- projects/quota64/lib/libutil/quotafile.c	Fri Feb 13 23:36:08 2009	(r188603)
+++ projects/quota64/lib/libutil/quotafile.c	Sat Feb 14 08:08:08 2009	(r188604)
@@ -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 <unistd.h>
 
 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;
 
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+static 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);
+}
+
 struct quotafile *
-quota_open(const char *fn)
+quota_open(struct fstab *fs, int quotatype, int openflags)
 {
 	struct quotafile *qf;
 	struct dqhdr64 dqh;
-	int serrno;
+	struct group *grp;
+	int qcmd, serrno;
 
 	if ((qf = calloc(1, sizeof(*qf))) == NULL)
 		return (NULL);
-	if ((qf->fd = open(fn, O_RDWR)) < 0) {
-		serrno = errno;
+	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 = serrno;
+		errno = EOPNOTSUPP;
 		return (NULL);
 	}
-	qf->type = 32;
-	switch (read(qf->fd, &dqh, sizeof(dqh))) {
-	case -1:
+	if ((qf->fd = open(qf->qfname, openflags & O_ACCMODE)) < 0 &&
+	    (openflags & O_CREAT) == 0) {
 		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 */
+	}
+	/* 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 = EINVAL;
+			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);
 		}
-		qf->type = 64;
-		return (qf);
-	default:
-		qf->type = 32;
-		return (qf);
+		/* not reached */
 	}
-	/* not reached */
-}
-
-struct quotafile *
-quota_create(const char *fn)
-{
-	struct quotafile *qf;
-	struct dqhdr64 dqh;
-	struct group *grp;
-	int serrno;
-
-	if ((qf = calloc(1, sizeof(*qf))) == NULL)
-		return (NULL);
-	if ((qf->fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
+	/* 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->type = 64;
+	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, struc
 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, cons
 	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,18 +322,48 @@ quota_write64(struct quotafile *qf, cons
 	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, dqb, id);
+		return quota_write32(qf, &dqbuf, id);
 	case 64:
-		return quota_write64(qf, dqb, id);
+		return quota_write64(qf, &dqbuf, id);
 	default:
 		errno = EINVAL;
 		return (-1);
@@ -276,48 +371,56 @@ quota_write(struct quotafile *qf, const 
 	/* not reached */
 }
 
-/*
- * Check to see if a particular quota is to be enabled.
- */
 int
-hasquota(struct fstab *fs, int type, char *qfnamep, int qfbufsize)
+quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
 {
-	char *opt;
-	char *cp;
-	struct statfs sfb;
-	char buf[BUFSIZ];
-	static char initname, usrname[100], grpname[100];
+	struct dqblk dqbuf;
+	int qcmd;
 
-	if (!initname) {
-		(void)snprintf(usrname, sizeof(usrname), "%s%s",
-		    qfextension[USRQUOTA], QUOTAFILENAME);
-		(void)snprintf(grpname, sizeof(grpname), "%s%s",
-		    qfextension[GRPQUOTA], QUOTAFILENAME);
-		initname = 1;
+	if (qf->fd == -1) {
+		qcmd = QCMD(Q_SETQUOTA, qf->quotatype);
+		return (quotactl(qf->fsname, qcmd, id, dqb));
 	}
-	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.
+	 * Have to do read-modify-write of quota in file.
 	 */
-	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]);
+	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:
+		return quota_write64(qf, dqb, id);
+	default:
+		errno = EINVAL;
+		return (-1);
 	}
-	return (1);
+	/* not reached */
 }

Modified: projects/quota64/usr.sbin/edquota/edquota.c
==============================================================================
--- projects/quota64/usr.sbin/edquota/edquota.c	Fri Feb 13 23:36:08 2009	(r188603)
+++ projects/quota64/usr.sbin/edquota/edquota.c	Sat Feb 14 08:08:08 2009	(r188604)
@@ -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 *f
 	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;
-		qupsize = sizeof(*qup) + strlen(qfpathname);
-		if ((qup = (struct quotause *)malloc(qupsize)) == NULL)
+		}
+		if ((qup = (struct quotause *)calloc(1, sizeof(*qup))) == 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);
+		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;
 		}
-		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 *f
  * 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);
 	}


More information about the svn-src-projects mailing list