summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorSean Eric Fagan <sef@FreeBSD.org>2018-09-29 00:44:23 +0000
committerSean Eric Fagan <sef@FreeBSD.org>2018-09-29 00:44:23 +0000
commitdc8f03b53541cf5cb6d1d1049944d68db99cf578 (patch)
tree1b8295e331ca0cd612a9cb448d4cdff43519ca6e /libexec
parent0192b6c15a30053b5be0dd27c5138c8f89f5a746 (diff)
Notes
Diffstat (limited to 'libexec')
-rw-r--r--libexec/rpc.rquotad/rquotad.c193
1 files changed, 144 insertions, 49 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;
+ struct ext_getquota_args getq_args;
+ struct getquota_rslt getq_rslt;
+ struct dqblk dqblk;
+ struct timeval timev;
+ int scale;
- 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 */
+ 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);
}