Obtained from: NetBSD

Imported rpc.rquotad from NetBSD - currently only used by the
quota-command to display quota's over nfs
This commit is contained in:
Thomas Graichen 1996-01-05 08:47:12 +00:00
parent ce39287245
commit 1a3e5dd740
3 changed files with 399 additions and 0 deletions

View File

@ -0,0 +1,10 @@
# $Id: Makefile,v 1.3 1995/04/12 00:47:27 jtc Exp $
PROG = rpc.rquotad
SRCS = rquotad.c
MAN8 = rpc.rquotad.8
DPADD= ${LIBRPCSVC}
LDADD= -lrpcsvc
.include <bsd.prog.mk>

View File

@ -0,0 +1,58 @@
.\"
.\" Copyright (c) 1994 Theo de Raadt
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by Theo de Raadt.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $Id: rpc.rquotad.8,v 1.2 1995/04/12 00:47:32 jtc Exp $
.\"
.Dd June 22, 1994
.Dt RPC.RQUOTAD 8
.Os BSD 4.3
.Sh NAME
.Nm rpc.rquotad
.Nd remote quota server
.Sh SYNOPSIS
.Nm /usr/libexec/rpc.rquotad
.Sh DESCRIPTION
.Nm rpc.rquotad
is a
.Xr rpc 3
server which returns quotas for a user of a local filesystem
which is NFS-mounted onto a remote machine.
.Xr quota 1
uses the results to display user quotas for remote filesystems.
.Nm rpc.rquotad
is normally invoked by
.Xr inetd 8 .
.Pp
.Nm rpc.rquotad
uses an RPC protocol defined in
.Pa /usr/include/rpcsvc/rquota.x .
.Sh BUGS
BSD 4.4 and NetBSD support group quotas but the rquota protocol does not.
.Sh SEE ALSO
.Xr quota 1

View File

@ -0,0 +1,331 @@
/*
* by Manuel Bouyer (bouyer@ensta.fr)
*
* There is no copyright, you can use it as you want.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <signal.h>
#include <stdio.h>
#include <fstab.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <syslog.h>
#include <varargs.h>
#include <ufs/ufs/quota.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpcsvc/rquota.h>
#include <arpa/inet.h>
void rquota_service __P((struct svc_req *request, SVCXPRT *transp));
void sendquota __P((struct svc_req *request, SVCXPRT *transp));
void printerr_reply __P((SVCXPRT *transp));
void initfs __P((void));
int getfsquota __P((long id, char *path, struct dqblk *dqblk));
int hasquota __P((struct fstab *fs, char **qfnamep));
/*
* structure containing informations about ufs filesystems
* initialised by initfs()
*/
struct fs_stat {
struct fs_stat *fs_next; /* next element */
char *fs_file; /* mount point of the filesystem */
char *qfpathname; /* pathname of the quota file */
dev_t st_dev; /* device of the filesystem */
} fs_stat;
struct fs_stat *fs_begin = NULL;
int from_inetd = 1;
void
cleanup()
{
(void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
exit(0);
}
int
main(argc, argv)
int argc;
char *argv[];
{
SVCXPRT *transp;
int sock = 0;
int proto = 0;
struct sockaddr_in from;
int fromlen;
fromlen = sizeof(from);
if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
from_inetd = 0;
sock = RPC_ANYSOCK;
proto = IPPROTO_UDP;
}
if (!from_inetd) {
daemon(0, 0);
(void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
(void) signal(SIGINT, cleanup);
(void) signal(SIGTERM, cleanup);
(void) signal(SIGHUP, cleanup);
}
openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON);
/* create and register the service */
transp = svcudp_create(sock);
if (transp == NULL) {
syslog(LOG_ERR, "couldn't create udp service.");
exit(1);
}
if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquota_service, proto)) {
syslog(LOG_ERR, "unable to register (RQUOTAPROG, RQUOTAVERS, %s).", proto?"udp":"(inetd)");
exit(1);
}
initfs(); /* init the fs_stat list */
svc_run();
syslog(LOG_ERR, "svc_run returned");
exit(1);
}
void
rquota_service(request, transp)
struct svc_req *request;
SVCXPRT *transp;
{
switch (request->rq_proc) {
case NULLPROC:
(void)svc_sendreply(transp, xdr_void, (char *)NULL);
break;
case RQUOTAPROC_GETQUOTA:
case RQUOTAPROC_GETACTIVEQUOTA:
sendquota(request, transp);
break;
default:
svcerr_noproc(transp);
break;
}
if (from_inetd)
exit(0);
}
/* read quota for the specified id, and send it */
void
sendquota(request, transp)
struct svc_req *request;
SVCXPRT *transp;
{
struct getquota_args getq_args;
struct getquota_rslt getq_rslt;
struct dqblk dqblk;
struct timeval timev;
bzero((char *)&getq_args, sizeof(getq_args));
if (!svc_getargs(transp, xdr_getquota_args, (caddr_t)&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_uid, 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;
getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;
getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
dqblk.dqb_bhardlimit;
getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
dqblk.dqb_bsoftlimit;
getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
dqblk.dqb_curblocks;
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, xdr_getquota_rslt, (char *)&getq_rslt)) {
svcerr_systemerr(transp);
}
if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
syslog(LOG_ERR, "unable to free arguments");
exit(1);
}
}
void
printerr_reply(transp) /* when a reply to a request failed */
SVCXPRT *transp;
{
char *name;
struct sockaddr_in *caller;
int save_errno;
save_errno = errno;
caller = svc_getcaller(transp);
name = (char *)inet_ntoa(caller->sin_addr);
errno = save_errno;
if (errno == 0)
syslog(LOG_ERR, "couldn't send reply to %s", name);
else
syslog(LOG_ERR, "couldn't send reply to %s: %m", name);
}
/* initialise the fs_tab list from entries in /etc/fstab */
void
initfs()
{
struct fs_stat *fs_current = NULL;
struct fs_stat *fs_next = NULL;
char *qfpathname;
struct fstab *fs;
struct stat st;
setfsent();
while ((fs = getfsent())) {
if (strcmp(fs->fs_vfstype, "ufs"))
continue;
if (!hasquota(fs, &qfpathname))
continue;
fs_current = (struct fs_stat *) malloc(sizeof(struct fs_stat));
fs_current->fs_next = fs_next; /* next element */
fs_current->fs_file = malloc(sizeof(char) * (strlen(fs->fs_file) + 1));
strcpy(fs_current->fs_file, fs->fs_file);
fs_current->qfpathname = malloc(sizeof(char) * (strlen(qfpathname) + 1));
strcpy(fs_current->qfpathname, qfpathname);
stat(qfpathname, &st);
fs_current->st_dev = st.st_dev;
fs_next = fs_current;
}
endfsent();
fs_begin = fs_current;
}
/*
* gets the quotas for id, filesystem path.
* Return 0 if fail, 1 otherwise
*/
int
getfsquota(id, path, dqblk)
long id;
char *path;
struct dqblk *dqblk;
{
struct stat st_path;
struct fs_stat *fs;
int qcmd, fd, ret = 0;
if (stat(path, &st_path) < 0)
return (0);
qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
for (fs = fs_begin; fs != NULL; fs = fs->fs_next) {
/* where the devise is the same as path */
if (fs->st_dev != st_path.st_dev)
continue;
/* find the specified filesystem. get and return quota */
if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0)
return (1);
if ((fd = open(fs->qfpathname, O_RDONLY)) < 0) {
syslog(LOG_ERR, "open error: %s: %m", fs->qfpathname);
return (0);
}
if (lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET) == (off_t)-1) {
close(fd);
return (1);
}
switch (read(fd, dqblk, sizeof(struct dqblk))) {
case 0:
/*
* Convert implicit 0 quota (EOF)
* into an explicit one (zero'ed dqblk)
*/
bzero((caddr_t) dqblk, sizeof(struct dqblk));
ret = 1;
break;
case sizeof(struct dqblk): /* OK */
ret = 1;
break;
default: /* ERROR */
syslog(LOG_ERR, "read error: %s: %m", fs->qfpathname);
close(fd);
return (0);
}
close(fd);
}
return (ret);
}
/*
* Check to see if a particular quota is to be enabled.
* Comes from quota.c, NetBSD 0.9
*/
int
hasquota(fs, qfnamep)
struct fstab *fs;
char **qfnamep;
{
static char initname, usrname[100];
static char buf[BUFSIZ];
char *opt, *cp;
char *qfextension[] = INITQFNAMES;
if (!initname) {
sprintf(usrname, "%s%s", qfextension[USRQUOTA], QUOTAFILENAME);
initname = 1;
}
strcpy(buf, fs->fs_mntops);
for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
if ((cp = index(opt, '=')))
*cp++ = '\0';
if (strcmp(opt, usrname) == 0)
break;
}
if (!opt)
return (0);
if (cp) {
*qfnamep = cp;
return (1);
}
sprintf(buf, "%s/%s.%s", fs->fs_file, QUOTAFILENAME, qfextension[USRQUOTA]);
*qfnamep = buf;
return (1);
}