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);