Module Name:    src
Committed By:   dholland
Date:           Mon Jan  9 15:40:10 UTC 2012

Modified Files:
        src/lib/libquota: quota_cursor.c quota_proplib.c quotapvt.h

Log Message:
Implement the libquota cursor interface, using proplib code from repquota.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/lib/libquota/quota_cursor.c
cvs rdiff -u -r1.3 -r1.4 src/lib/libquota/quota_proplib.c
cvs rdiff -u -r1.4 -r1.5 src/lib/libquota/quotapvt.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libquota/quota_cursor.c
diff -u src/lib/libquota/quota_cursor.c:1.1 src/lib/libquota/quota_cursor.c:1.2
--- src/lib/libquota/quota_cursor.c:1.1	Mon Jan  9 15:22:38 2012
+++ src/lib/libquota/quota_cursor.c	Mon Jan  9 15:40:10 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: quota_cursor.c,v 1.1 2012/01/09 15:22:38 dholland Exp $	*/
+/*	$NetBSD: quota_cursor.c,v 1.2 2012/01/09 15:40:10 dholland Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -29,65 +29,81 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: quota_cursor.c,v 1.1 2012/01/09 15:22:38 dholland Exp $");
+__RCSID("$NetBSD: quota_cursor.c,v 1.2 2012/01/09 15:40:10 dholland Exp $");
 
 #include <stdlib.h>
 #include <errno.h>
 
 #include <quota.h>
+#include "quotapvt.h"
 
-/* ARGSUSED */
 struct quotacursor *
 quota_opencursor(struct quotahandle *qh)
 {
-	errno = ENOSYS;
-	return NULL;
+	struct quotacursor *qc;
+	int serrno;
+
+	if (qh->qh_isnfs) {
+		errno = EOPNOTSUPP;
+		return NULL;
+	}
+
+	qc = malloc(sizeof(*qc));
+	if (qc == NULL) {
+		return NULL;
+	}
+
+	qc->qc_qh = qh;
+	qc->u.qc_proplib = __quota_proplib_cursor_create();
+
+	if (qc->u.qc_proplib == NULL) {
+		serrno = errno;
+		free(qc);
+		errno = serrno;
+		return NULL;
+	}
+	return qc;
 }
 
-/* ARGSUSED */
 void
 quotacursor_close(struct quotacursor *qc)
 {
+	__quota_proplib_cursor_destroy(qc->u.qc_proplib);
+	free(qc);
 }
 
-/* ARGSUSED */
 int
 quotacursor_skipidtype(struct quotacursor *qc, unsigned idtype)
 {
-	errno = ENOSYS;
-	return -1;
+	return __quota_proplib_cursor_skipidtype(qc->u.qc_proplib, idtype);
 }
 
-/* ARGSUSED */
 int
 quotacursor_get(struct quotacursor *qc,
 		struct quotakey *qk_ret, struct quotaval *qv_ret)
 {
-	errno = ENOSYS;
-	return -1;
+	return __quota_proplib_cursor_get(qc->qc_qh, qc->u.qc_proplib,
+					  qk_ret, qv_ret);
 }
 
-/* ARGSUSED */
 int
 quotacursor_getn(struct quotacursor *qc,
 		 struct quotakey *keys, struct quotaval *vals, 
 		 unsigned maxnum)
 {
-	errno = ENOSYS;
-	return -1;
+	return __quota_proplib_cursor_getn(qc->qc_qh, qc->u.qc_proplib,
+					   keys, vals, maxnum);
 }
 
-/* ARGSUSED */
 int
 quotacursor_atend(struct quotacursor *qc)
 {
-	return 0;
+	return __quota_proplib_cursor_atend(qc->qc_qh,
+					    qc->u.qc_proplib);
 }
 
-/* ARGSUSED */
 int
 quotacursor_rewind(struct quotacursor *qc)
 {
-	errno = ENOSYS;
-	return -1;
+	return __quota_proplib_cursor_rewind(qc->u.qc_proplib);
 }

Index: src/lib/libquota/quota_proplib.c
diff -u src/lib/libquota/quota_proplib.c:1.3 src/lib/libquota/quota_proplib.c:1.4
--- src/lib/libquota/quota_proplib.c:1.3	Mon Jan  9 15:34:34 2012
+++ src/lib/libquota/quota_proplib.c	Mon Jan  9 15:40:10 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: quota_proplib.c,v 1.3 2012/01/09 15:34:34 dholland Exp $	*/
+/*	$NetBSD: quota_proplib.c,v 1.4 2012/01/09 15:40:10 dholland Exp $	*/
 /*-
   * Copyright (c) 2011 Manuel Bouyer
   * All rights reserved.
@@ -26,9 +26,11 @@
   */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: quota_proplib.c,v 1.3 2012/01/09 15:34:34 dholland Exp $");
+__RCSID("$NetBSD: quota_proplib.c,v 1.4 2012/01/09 15:40:10 dholland Exp $");
 
+#include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 #include <errno.h>
 #include <err.h>
 
@@ -38,6 +40,21 @@ __RCSID("$NetBSD: quota_proplib.c,v 1.3 
 #include <quota/quotaprop.h>
 #include <quota/quota.h>
 
+struct proplib_quotacursor {
+	prop_array_t users;
+	prop_array_t groups;
+
+	unsigned numusers;
+	unsigned numgroups;
+
+	unsigned haveusers;
+	unsigned havegroups;
+
+	unsigned didusers;
+	unsigned pos;
+	unsigned didblocks;
+};
+
 static int
 __quota_proplib_getversion(struct quotahandle *qh, int8_t *version_ret)
 {
@@ -163,6 +180,63 @@ __quota_proplib_getimplname(struct quota
 	return "unknown";
 }
 
+static int
+__quota_proplib_extractval(int objtype, prop_dictionary_t data,
+			   struct quotaval *qv)
+{
+	uint64_t vals[UFS_QUOTA_NENTRIES];
+	uint64_t *valptrs[1];
+	int limitcode;
+
+	/*
+	 * So, the way proptoquota64 works is that you pass it an
+	 * array of pointers to uint64. Each of these pointers is
+	 * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This
+	 * array of pointers is the second argument. The third and
+	 * forth argument are the names of the five values to extract,
+	 * and UFS_QUOTA_NENTRIES. The last two arguments are the
+	 * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK,
+	 * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of
+	 * the existing code was unsafely casting struct quotaval
+	 * (formerly struct ufs_quota_entry) to (uint64_t *) and using
+	 * that as the block of 5 uint64s. I refuse to countenance
+	 * that. Also, most of that code extracts both block and file
+	 * limits at once (last arguments are ufs_quota_limit_names
+	 * and UFS_QUOTA_NLIMITS) but I only need one.
+	 */
+
+	switch (objtype) {
+	    case QUOTA_OBJTYPE_BLOCKS:
+		limitcode = QUOTA_LIMIT_BLOCK;
+		break;
+	    case QUOTA_OBJTYPE_FILES:
+		limitcode = QUOTA_LIMIT_FILE;
+		break;
+	    default:
+		errno = EINVAL;
+		return -1;
+	}
+
+	valptrs[0] = vals;
+	errno = proptoquota64(data, valptrs,
+			      ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
+			      &ufs_quota_limit_names[limitcode], 1);
+	if (errno) {
+		return -1;
+	}
+
+	/*
+	 * there are no symbolic constants for these indexes! XXX
+	 */
+	qv->qv_hardlimit = vals[0];
+	qv->qv_softlimit = vals[1];
+	qv->qv_usage = vals[2];
+	qv->qv_expiretime = vals[3];
+	qv->qv_grace = vals[4];
+
+	return 0;
+}
+
 int
 __quota_proplib_get(struct quotahandle *qh, const struct quotakey *qk,
 		    struct quotaval *qv)
@@ -173,9 +247,6 @@ __quota_proplib_get(struct quotahandle *
 	int8_t error8;
 	const char *idstr;
 	const char *cmdstr;
-	uint64_t vals[UFS_QUOTA_NENTRIES];
-	uint64_t *valptrs[1];
-	int limitcode;
 	int serrno;
 
 	switch (qk->qk_idtype) {
@@ -385,56 +456,356 @@ __quota_proplib_get(struct quotahandle *
 		return -1;
 	}
 
+	if (__quota_proplib_extractval(qk->qk_objtype, data, qv)) {
+		serrno = errno;
+		prop_object_release(dict);
+		errno = serrno;
+		return -1;
+	}
+
+	prop_object_release(dict);
+
+	return 0;
+}
+
+static int
+__quota_proplib_getall(struct quotahandle *qh, int idtype, prop_array_t *ret)
+{
+	prop_dictionary_t dict, cmd;
+	prop_array_t cmds, datas;
+	struct plistref pref;
+	int8_t error8;
+
 	/*
-	 * So, the way proptoquota64 works is that you pass it an
-	 * array of pointers to uint64. Each of these pointers is
-	 * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This
-	 * array of pointers is the second argument. The third and
-	 * forth argument are the names of the five values to extract,
-	 * and UFS_QUOTA_NENTRIES. The last two arguments are the
-	 * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK,
-	 * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of
-	 * the existing code was unsafely casting struct quotaval
-	 * (formerly struct ufs_quota_entry) to (uint64_t *) and using
-	 * that as the block of 5 uint64s. I refuse to countenance
-	 * that. Also, most of that code extracts both block and file
-	 * limits at once (last arguments are ufs_quota_limit_names
-	 * and UFS_QUOTA_NLIMITS) but I only need one.
+	 * XXX this should not crash out on error. But this is what
+	 * the code this came from did... probably because it can just
+	 * leak memory instead of needing the proper cleanup code.
 	 */
 
-	switch (qk->qk_objtype) {
-	    case QUOTA_OBJTYPE_BLOCKS:
-		limitcode = QUOTA_LIMIT_BLOCK;
+	dict = quota_prop_create();
+	cmds = prop_array_create();
+	datas = prop_array_create();
+
+	if (dict == NULL || cmds == NULL || datas == NULL)
+		errx(1, "can't allocate proplist");
+	if (!quota_prop_add_command(cmds, "getall",
+	    ufs_quota_class_names[idtype], datas))
+		err(1, "prop_add_command");
+	if (!prop_dictionary_set(dict, "commands", cmds))
+		err(1, "prop_dictionary_set(command)");
+#if 0
+	if (Dflag)
+		printf("message to kernel:\n%s\n",
+		    prop_dictionary_externalize(dict));
+#endif
+	if (prop_dictionary_send_syscall(dict, &pref) != 0)
+		err(1, "prop_dictionary_send_syscall");
+	prop_object_release(dict);
+
+	if (quotactl(quota_getmountpoint(qh), &pref) != 0)
+		err(1, "quotactl");
+
+	if (prop_dictionary_recv_syscall(&pref, &dict) != 0) {
+		err(1, "prop_dictionary_recv_syscall");
+	}
+#if 0
+	if (Dflag)
+		printf("reply from kernel:\n%s\n",
+		    prop_dictionary_externalize(dict));
+#endif
+	if ((errno = quota_get_cmds(dict, &cmds)) != 0) {
+		err(1, "quota_get_cmds");
+	}
+
+	cmd = prop_array_get(cmds, 0);
+	if (cmd == NULL) {
+		err(1, "prop_array_get(cmds)");
+	}
+
+	const char *cmdstr;
+	if (!prop_dictionary_get_cstring_nocopy(cmd, "command",
+	    &cmdstr))
+		err(1, "prop_get(command)");
+
+	if (!prop_dictionary_get_int8(cmd, "return", &error8))
+		err(1, "prop_get(return)");
+
+	if (error8) {
+		prop_object_release(dict);
+		if (error8 != EOPNOTSUPP) {
+			errno = error8;
+			warn("get %s quotas",
+			    ufs_quota_class_names[idtype]);
+		}
+		return -1;
+	}
+	datas = prop_dictionary_get(cmd, "data");
+	if (datas == NULL)
+		err(1, "prop_dict_get(datas)");
+
+	prop_object_retain(datas);
+	prop_object_release(dict);
+
+	*ret = datas;
+	return 0;
+}
+
+struct proplib_quotacursor *
+__quota_proplib_cursor_create(void)
+{
+	struct proplib_quotacursor *pqc;
+
+	pqc = malloc(sizeof(*pqc));
+	if (pqc == NULL) {
+		return NULL;
+	}
+
+	pqc->users = NULL;
+	pqc->numusers = 0;
+	pqc->haveusers = 0;
+
+	pqc->groups = NULL;
+	pqc->numgroups = 0;
+	pqc->havegroups = 0;
+
+	pqc->didusers = 0;
+	pqc->pos = 0;
+	pqc->didblocks = 0;
+
+	return pqc;
+}
+
+/* ARGSUSED */
+void
+__quota_proplib_cursor_destroy(struct proplib_quotacursor *pqc)
+{
+	prop_object_release(pqc->users);
+	prop_object_release(pqc->groups);
+	free(pqc);
+}
+
+static int
+__quota_proplib_cursor_load(struct quotahandle *qh,
+			    struct proplib_quotacursor *pqc)
+{
+	prop_array_t users, groups;
+
+	if (pqc->haveusers == 0) {
+		if (__quota_proplib_getall(qh, QUOTA_IDTYPE_USER, &users)) {
+			return -1;
+		}
+		pqc->users = users;
+		pqc->numusers = prop_array_count(users);
+		pqc->haveusers = 1;
+	}
+
+	if (pqc->havegroups == 0) {
+		if (__quota_proplib_getall(qh, QUOTA_IDTYPE_GROUP, &groups)) {
+			return -1;
+		}
+		pqc->groups = groups;
+		pqc->numgroups = prop_array_count(groups);
+		pqc->havegroups = 1;
+	}
+	return 0;
+}
+
+int
+__quota_proplib_cursor_skipidtype(struct proplib_quotacursor *pqc,
+				  unsigned idtype)
+{
+	switch (idtype) {
+	    case QUOTA_IDTYPE_USER:
+		/* if not yet loaded, numusers will be 0 and users NULL */
+		pqc->haveusers = 1;
 		break;
-	    case QUOTA_OBJTYPE_FILES:
-		limitcode = QUOTA_LIMIT_FILE;
+	    case QUOTA_IDTYPE_GROUP:
+		/* if not yet loaded, numgroups will be 0 and groups NULL */
+		pqc->havegroups = 1;
 		break;
 	    default:
-		prop_object_release(dict);
 		errno = EINVAL;
 		return -1;
 	}
+	return 0;
+}
 
-	valptrs[0] = vals;
-	errno = proptoquota64(data, valptrs,
-			      ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
-			      &ufs_quota_limit_names[limitcode], 1);
-	if (errno) {
-		serrno = errno;
-		prop_object_release(dict);
-		errno = serrno;
+static int
+__quota_proplib_cursor_subget(struct proplib_quotacursor *pqc,
+			      prop_dictionary_t data,
+			      struct quotakey *key, struct quotaval *val)
+{
+	uint32_t id;
+	const char *strid;
+
+	if (prop_dictionary_get_uint32(data, "id", &id)) {
+		key->qk_id = id;
+	} else if (prop_dictionary_get_cstring_nocopy(data,
+						      "id", &strid) &&
+		   !strcmp(strid, "default")) {
+		key->qk_id = QUOTA_DEFAULTID;
+	} else {
+		/* invalid bundle */
+		errno = EINVAL;
 		return -1;
 	}
-	prop_object_release(dict);
+	if (__quota_proplib_extractval(key->qk_objtype, data, val)) {
+		return -1;
+	}
+	return 0;
+}
 
-	/*
-	 * there are no symbolic constants for these indexes! XXX
-	 */
-	qv->qv_hardlimit = vals[0];
-	qv->qv_softlimit = vals[1];
-	qv->qv_usage = vals[2];
-	qv->qv_expiretime = vals[3];
-	qv->qv_grace = vals[4];
+int
+__quota_proplib_cursor_get(struct quotahandle *qh,
+			   struct proplib_quotacursor *pqc,
+			   struct quotakey *key, struct quotaval *val)
+{
+	prop_dictionary_t data;
+
+	if (pqc->haveusers == 0 || pqc->havegroups == 0) {
+		if (__quota_proplib_cursor_load(qh, pqc)) {
+			return -1;
+		}
+	}
+
+	if (!pqc->didblocks) {
+		key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
+	} else {
+		key->qk_objtype = QUOTA_OBJTYPE_FILES;
+	}
+
+	if (!pqc->didusers && pqc->pos >= pqc->numusers) {
+		/* in case there are 0 users */
+		pqc->didusers = 1;
+	}
+
+	if (!pqc->didusers) {
+		key->qk_idtype = QUOTA_IDTYPE_USER;
+
+		data = prop_array_get(pqc->users, pqc->pos);
+		if (data == NULL) {
+			errno = ENOENT;
+			return -1;
+		}
+
+		/* get id and value */
+		if (__quota_proplib_cursor_subget(pqc, data, key, val)) {
+			return -1;
+		}
+
+		/* advance */
+		if (!pqc->didblocks) {
+			pqc->didblocks = 1;
+		} else {
+			pqc->didblocks = 0;
+			pqc->pos++;
+			if (pqc->pos >= pqc->numusers) {
+				pqc->pos = 0;
+				pqc->didusers = 1;
+			}
+		}
+
+		/* succeed */
+		return 0;
+	} else if (pqc->pos < pqc->numgroups) {
+		key->qk_idtype = QUOTA_IDTYPE_GROUP;
+
+		data = prop_array_get(pqc->groups, pqc->pos);
+		if (data == NULL) {
+			errno = ENOENT;
+			return -1;
+		}
+
+		/* get id and value */
+		if (__quota_proplib_cursor_subget(pqc, data, key, val)) {
+			return -1;
+		}
+
+		/* advance */
+		if (!pqc->didblocks) {
+			pqc->didblocks = 1;
+		} else {
+			pqc->didblocks = 0;
+			pqc->pos++;
+		}
+
+		/* succeed */
+		return 0;
+	} else {
+		/* at EOF */
+		/* XXX is there a better errno for this? */
+		errno = ENOENT;
+		return -1;
+	}
+}
+
+int
+__quota_proplib_cursor_getn(struct quotahandle *qh,
+			    struct proplib_quotacursor *pqc,
+			    struct quotakey *keys, struct quotaval *vals,
+			    unsigned maxnum)
+{
+	unsigned i;
+
+	if (maxnum > INT_MAX) {
+		/* joker, eh? */
+		errno = EINVAL;
+		return -1;
+	}
+
+	for (i=0; i<maxnum; i++) {
+		if (__quota_proplib_cursor_atend(qh, pqc)) {
+			break;
+		}
+		if (__quota_proplib_cursor_get(qh, pqc, &keys[i], &vals[i])) {
+			if (i > 0) {
+				/*
+				 * Succeed witih what we have so far;
+				 * the next attempt will hit the same
+				 * error again.
+				 */
+				break;
+			}
+			return -1;
+		}
+	}
+	return i;
+}
 
+int
+__quota_proplib_cursor_atend(struct quotahandle *qh,
+			     struct proplib_quotacursor *pqc)
+{
+	if (!pqc->haveusers || !pqc->havegroups) {
+		if (__quota_proplib_cursor_load(qh, pqc)) {
+			/*
+			 * Cannot fail here - report that we are not
+			 * at EOF (lying if necessary) and let the
+			 * next get call try to load again, fail and
+			 * return the proper error. 
+			 */
+			return 0;
+		}
+	}
+
+	if (!pqc->didusers && pqc->pos >= pqc->numusers) {
+		pqc->didusers = 1;
+	}
+
+	if (!pqc->didusers) {
+		return 0;
+	}
+	if (pqc->pos < pqc->numgroups) {
+		return 0;
+	}
+	return 1;
+}
+
+int
+__quota_proplib_cursor_rewind(struct proplib_quotacursor *pqc)
+{
+	pqc->didusers = 0;
+	pqc->pos = 0;
+	pqc->didblocks = 0;
 	return 0;
 }

Index: src/lib/libquota/quotapvt.h
diff -u src/lib/libquota/quotapvt.h:1.4 src/lib/libquota/quotapvt.h:1.5
--- src/lib/libquota/quotapvt.h:1.4	Mon Jan  9 15:34:34 2012
+++ src/lib/libquota/quotapvt.h	Mon Jan  9 15:40:10 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: quotapvt.h,v 1.4 2012/01/09 15:34:34 dholland Exp $	*/
+/*	$NetBSD: quotapvt.h,v 1.5 2012/01/09 15:40:10 dholland Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -35,15 +35,39 @@ struct quotahandle {
 	char spare[14*sizeof(char *) + 15 * sizeof(int)];
 };
 
+struct quotacursor {
+	struct quotahandle *qc_qh;
+	union {
+		struct proplib_quotacursor *qc_proplib;
+	} u;
+};
+
+
 /* proplib kernel interface */
 const char *__quota_proplib_getimplname(struct quotahandle *);
 int __quota_proplib_get(struct quotahandle *qh, const struct quotakey *qk,
 			struct quotaval *qv);
+struct proplib_quotacursor *__quota_proplib_cursor_create(void);
+void __quota_proplib_cursor_destroy(struct proplib_quotacursor *);
+int __quota_proplib_cursor_skipidtype(struct proplib_quotacursor *,
+				      unsigned idtype);
+int __quota_proplib_cursor_get(struct quotahandle *,
+			       struct proplib_quotacursor *,
+			       struct quotakey *, struct quotaval *);
+int __quota_proplib_cursor_getn(struct quotahandle *,
+				struct proplib_quotacursor *,
+				struct quotakey *, struct quotaval *,
+				unsigned);
+int __quota_proplib_cursor_atend(struct quotahandle *,
+				 struct proplib_quotacursor *);
+int __quota_proplib_cursor_rewind(struct proplib_quotacursor *);
+
 
 /* nfs rquotad interface */
 int __quota_nfs_get(struct quotahandle *qh, const struct quotakey *qk,
 		    struct quotaval *qv);
 
+
 /* compat for old library */
 int __quota_getquota(const char *path, struct quotaval *qv, uid_t id,
 		     const char *class);

Reply via email to