aboutsummaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorSean Eric Fagan <sef@FreeBSD.org>2018-07-05 22:56:13 +0000
committerSean Eric Fagan <sef@FreeBSD.org>2018-07-05 22:56:13 +0000
commitaad5531e716d37f9e0b0a0ee50499a33e63a1337 (patch)
treeb0aaf50d11c4211bed716d0aab8007b72a631f9f /libexec
parent3655135d3f59a9ae2a4464203efe9e7680ac4dd8 (diff)
downloadsrc-aad5531e716d37f9e0b0a0ee50499a33e63a1337.tar.gz
src-aad5531e716d37f9e0b0a0ee50499a33e63a1337.zip
This exposes ZFS user and group quotas via the normal
quatactl(2) mechanism. (Read-only at this point, however.) In particular, this is to allow rpc.rquotad query quotas for NFS mounts, allowing users to see their quotas on the hosts using the datasets. The changes specifically: * Add new RPC entry points for querying quotas. * Changes the library routines to allow non-UFS quotas. * Changes rquotad to check for quotas on mounted filesystems, rather than being limited to entries in /etc/fstab * Lastly, adds a VFS entry-point for ZFS to query quotas. Note that this makes one unavoidable behavioural change: if quotas are enabled, then they can be queried, as opposed to the current method of checking for quotas being specified in fstab. (With ZFS, if there are user or group quotas, they're used, always.) Reviewed by: delphij, mav Approved by: mav Sponsored by: iXsystems Inc Differential Revision: https://reviews.freebsd.org/D15886
Notes
Notes: svn path=/head/; revision=336017
Diffstat (limited to 'libexec')
-rw-r--r--libexec/rpc.rquotad/rquotad.c195
1 files changed, 145 insertions, 50 deletions
diff --git a/libexec/rpc.rquotad/rquotad.c b/libexec/rpc.rquotad/rquotad.c
index d9ce06aac82e..cc78a9a71c39 100644
--- a/libexec/rpc.rquotad/rquotad.c
+++ b/libexec/rpc.rquotad/rquotad.c
@@ -28,18 +28,19 @@ __FBSDID("$FreeBSD$");
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <err.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
-static void rquota_service(struct svc_req *request, SVCXPRT *transp);
+static void rquota_service_1(struct svc_req *request, SVCXPRT *transp);
+static void rquota_service_2(struct svc_req *request, SVCXPRT *transp);
static void sendquota(struct svc_req *request, SVCXPRT *transp);
-static void initfs(void);
-static int getfsquota(long id, char *path, struct dqblk *dqblk);
+static void sendquota_extended(struct svc_req *request, SVCXPRT *transp);
+static int getfsquota(int type, long id, char *path, struct dqblk *dqblk);
-static struct quotafile **qfa; /* array of qfs */
-static int nqf, szqf; /* number of qfs and size of array */
static int from_inetd = 1;
+static int debug = 0;
static void
cleanup(int sig)
@@ -51,19 +52,32 @@ cleanup(int sig)
}
int
-main(void)
+main(int argc, char **argv)
{
SVCXPRT *transp;
int ok;
struct sockaddr_storage from;
socklen_t fromlen;
+ int vers;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "d")) != -1) {
+ switch (ch) {
+ case 'd':
+ debug++;
+ break;
+ default:
+ break;
+ }
+ }
fromlen = sizeof(from);
if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
from_inetd = 0;
if (!from_inetd) {
- daemon(0, 0);
+ if (!debug)
+ daemon(0, 0);
(void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
(void)signal(SIGINT, cleanup);
(void)signal(SIGTERM, cleanup);
@@ -79,27 +93,60 @@ main(void)
syslog(LOG_ERR, "couldn't create udp service.");
exit(1);
}
+ vers = RQUOTAVERS;
ok = svc_reg(transp, RQUOTAPROG, RQUOTAVERS,
- rquota_service, NULL);
+ rquota_service_1, NULL);
+ if (ok) {
+ vers = EXT_RQUOTAVERS;
+ ok = svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
+ rquota_service_2, NULL);
+ }
} else {
- ok = svc_create(rquota_service,
+ vers = RQUOTAVERS;
+ ok = svc_create(rquota_service_1,
RQUOTAPROG, RQUOTAVERS, "udp");
+ if (ok) {
+ vers = EXT_RQUOTAVERS;
+ ok = svc_create(rquota_service_2,
+ RQUOTAPROG, EXT_RQUOTAVERS, "udp");
+
+ }
}
if (!ok) {
syslog(LOG_ERR,
- "unable to register (RQUOTAPROG, RQUOTAVERS, %s)",
- from_inetd ? "(inetd)" : "udp");
+ "unable to register (RQUOTAPROG, %s, %s)",
+ vers == RQUOTAVERS ? "RQUOTAVERS" : "EXT_RQUOTAVERS",
+ from_inetd ? "(inetd)" : "udp");
exit(1);
}
- initfs();
svc_run();
syslog(LOG_ERR, "svc_run returned");
exit(1);
}
static void
-rquota_service(struct svc_req *request, SVCXPRT *transp)
+rquota_service_2(struct svc_req *request, SVCXPRT *transp)
+{
+
+ switch (request->rq_proc) {
+ case NULLPROC:
+ (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
+ break;
+ case RQUOTAPROC_GETQUOTA:
+ case RQUOTAPROC_GETACTIVEQUOTA:
+ sendquota_extended(request, transp);
+ break;
+ default:
+ svcerr_noproc(transp);
+ break;
+ }
+ if (from_inetd)
+ exit(0);
+}
+
+static void
+rquota_service_1(struct svc_req *request, SVCXPRT *transp)
{
switch (request->rq_proc) {
@@ -136,7 +183,7 @@ sendquota(struct svc_req *request, SVCXPRT *transp)
if (request->rq_cred.oa_flavor != AUTH_UNIX) {
/* bad auth */
getq_rslt.status = Q_EPERM;
- } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
+ } else if (!getfsquota(USRQUOTA, getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
/* failed, return noquota */
getq_rslt.status = Q_NOQUOTA;
} else {
@@ -172,38 +219,55 @@ sendquota(struct svc_req *request, SVCXPRT *transp)
}
static void
-initfs(void)
+sendquota_extended(struct svc_req *request, SVCXPRT *transp)
{
- struct fstab *fs;
-
- setfsent();
- szqf = 8;
- if ((qfa = malloc(szqf * sizeof *qfa)) == NULL)
- goto enomem;
- while ((fs = getfsent())) {
- if (strcmp(fs->fs_vfstype, "ufs"))
- continue;
- if (nqf >= szqf) {
- szqf *= 2;
- if ((qfa = reallocf(qfa, szqf * sizeof *qfa)) == NULL)
- goto enomem;
- }
- if ((qfa[nqf] = quota_open(fs, USRQUOTA, O_RDONLY)) == NULL) {
- if (errno != EOPNOTSUPP)
- goto fserr;
- continue;
- }
- ++nqf;
- /* XXX */
+ struct ext_getquota_args getq_args;
+ struct getquota_rslt getq_rslt;
+ struct dqblk dqblk;
+ struct timeval timev;
+ int scale;
+
+ bzero(&getq_args, sizeof(getq_args));
+ if (!svc_getargs(transp, (xdrproc_t)xdr_ext_getquota_args, &getq_args)) {
+ svcerr_decode(transp);
+ return;
+ }
+ if (request->rq_cred.oa_flavor != AUTH_UNIX) {
+ /* bad auth */
+ getq_rslt.status = Q_EPERM;
+ } else if (!getfsquota(getq_args.gqa_type, getq_args.gqa_id, getq_args.gqa_pathp, &dqblk)) {
+ /* failed, return noquota */
+ getq_rslt.status = Q_NOQUOTA;
+ } else {
+ gettimeofday(&timev, NULL);
+ getq_rslt.status = Q_OK;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
+ scale = 1 << flsll(dqblk.dqb_bhardlimit >> 32);
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize =
+ DEV_BSIZE * scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
+ dqblk.dqb_bhardlimit / scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
+ dqblk.dqb_bsoftlimit / scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
+ dqblk.dqb_curblocks / scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
+ dqblk.dqb_ihardlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
+ dqblk.dqb_isoftlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
+ dqblk.dqb_curinodes;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
+ dqblk.dqb_btime - timev.tv_sec;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
+ dqblk.dqb_itime - timev.tv_sec;
+ }
+ if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt))
+ svcerr_systemerr(transp);
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
+ syslog(LOG_ERR, "unable to free arguments");
+ exit(1);
}
- endfsent();
- return;
-enomem:
- syslog(LOG_ERR, "out of memory");
- exit(1);
-fserr:
- syslog(LOG_ERR, "%s: %s", fs->fs_file, strerror(errno));
- exit(1);
}
/*
@@ -211,12 +275,43 @@ fserr:
* Return 0 if fail, 1 otherwise
*/
static int
-getfsquota(long id, char *path, struct dqblk *dqblk)
+getfsquota(int type, long id, char *path, struct dqblk *dqblk)
{
- int i;
+ struct quotafile *qf;
+ /*
+ * Remote quota checking is limited to mounted filesystems.
+ * Since UFS and ZFS support the quota system calls, we
+ * only need to make an fstab object that has the path, and
+ * a blank name for the filesystem type.
+ * This allows the quota_open() call to work the way we
+ * expect it to.
+ *
+ * The static char declaration is because compiler warnings
+ * don't allow passing a const char * to a char *.
+ */
+ int rv;
+ static char blank[] = "";
+ struct fstab fst;
+
+ fst.fs_file = path;
+ fst.fs_mntops = blank;
+ fst.fs_vfstype = blank;
+
+ if (type != USRQUOTA && type != GRPQUOTA)
+ return (0);
+
+ qf = quota_open(&fst, type, O_RDONLY);
+ if (debug)
+ warnx("quota_open(<%s, %s>, %d) returned %p",
+ fst.fs_file, fst.fs_mntops, type,
+ qf);
+ if (qf == NULL)
+ return (0);
- for (i = 0; i < nqf; ++i)
- if (quota_check_path(qfa[i], path) == 1)
- return (quota_read(qfa[i], dqblk, id) == 0);
- return (0);
+ rv = quota_read(qf, dqblk, id) == 0;
+ quota_close(qf);
+ if (debug)
+ warnx("getfsquota(%d, %ld, %s, %p) -> %d",
+ type, id, path, dqblk, rv);
+ return (rv);
}