*BSD News Article 32137


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!harbinger.cc.monash.edu.au!bunyip.cc.uq.oz.au!munnari.oz.au!spool.mu.edu!howland.reston.ans.net!math.ohio-state.edu!jussieu.fr!univ-lyon1.fr!ensta!bsdtest.ensta.fr!bouyer
From: bouyer@bsdtest.ensta.fr (Manuel Bouyer)
Newsgroups: comp.os.386bsd.questions
Subject: Re: [FreeBSD] rquotad wanted !
Date: 21 Jun 1994 13:44:40 GMT
Organization: Ecole Nationale Superieure de Techniques Avancees, Paris
Lines: 355
Distribution: world
Message-ID: <2u6qs8$1aq@ici-paris.ensta.fr>
References: <2u6lrf$kku@news.simplex.nl>
NNTP-Posting-Host: bsdtest.ensta.fr

In article <2u6lrf$kku@news.simplex.nl>, rob@Simplex.NL (Rob Simons) writes:
|> Hi,
|> 
|> Is there anyone out there who knows where I can find the rquotad 
|> perhaps rpc.rquotad daemon ?
|> This daemon handles requests for quota-information from clients
|> machines to the NFS machine .. 
|> 

Here is the one i wrote for NetBSD some time ago ...
/* rquotad.c, rquotad service */
/* for NetBSD 0.9 by Manuel Bouyer (bouyer@ensta.fr) */

#include <stdio.h>
#include <fstab.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>

#include <syslog.h>
#include <varargs.h>

#include <sys/types.h>
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/signal.h>

#include <machine/param.h>
#include <ufs/quota.h>

#include <rpc/rpc.h>
#include <rpcsvc/rquota.h>


void rquota_svc (), exit_svc(), sendquota(), printerr_reply(), initfs();

int getfsquota();
extern int errno;

/* structure containing informations about ufs filesystems */
/*initialised by initfs() */
struct fs_stat {
	struct fs_stat *fs_next;  /* next element (NULL if end of the list) */
	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;	/* first element of the list */


main ()  /* no options */


{
SVCXPRT *transport;
int sock = 0;
int proto = 0;
int from_inetd = 1;
struct sockaddr_in from;
int fromlen;


/* from rwalld.c NetBSD 0.9 */
	openlog ("rquotad",LOG_PID,LOG_DAEMON);
        if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
               	{ from_inetd = 0;
                sock = RPC_ANYSOCK;
                proto = IPPROTO_UDP;
        	}
        if (!from_inetd)
	    {daemon(0, 0);
	     pmap_unset(RQUOTAPROG,RQUOTAVERS);
	     signal(SIGINT, exit_svc);/* trap some signals */
   	     signal(SIGQUIT, exit_svc);/* to unregister the service*/
	     signal(SIGTERM, exit_svc);/* before exiting */
	    }

/* create and register the service*/
	if ((transport=svcudp_create(sock))== NULL)
		{syslog(LOG_ERR,"couldn't create UDP transport");exit (1);}
	if (svc_register(transport,RQUOTAPROG,RQUOTAVERS,rquota_svc,proto)==0)
		{syslog(LOG_ERR,"couldn't register service");exit (1);}
	initfs();/* init the fs_stat list */
	svc_run();
	syslog(LOG_ERR,"svc_run has returned !");
	exit(1);		/* svc_run don't return */
}

/* rquota service */
void rquota_svc (request,transport)
struct svc_req *request;
SVCXPRT *transport;

{
	switch (request->rq_proc)
	{ case NULLPROC:
		errno=0;
		if (svc_sendreply(transport,xdr_void,0)==0)
			printerr_reply(transport);
		return;
	  case RQUOTAPROC_GETQUOTA:
	  case RQUOTAPROC_GETACTIVEQUOTA:
		sendquota(request,transport);
		return;
	  default:
		svcerr_noproc(transport);
		return;
	}
}



/* read quota for the specified id, and send it */
void sendquota(request,transport)
struct svc_req *request;
SVCXPRT *transport;
{
struct getquota_args getq_args;
struct getquota_rslt getq_rslt;
struct	dqblk dqblk;
struct timeval timev;

	getq_args.gqa_pathp = NULL;/* allocated by svc_getargs */
	if (svc_getargs(transport,xdr_getquota_args,&getq_args)==0)
		{svcerr_decode(transport);return;}

	
	if (request->rq_cred.oa_flavor!=AUTH_UNIX)
		getq_rslt.status=Q_EPERM; /* bad auth */
	else	/* try to get fs quotas */
		{  if (getfsquota(getq_args.gqa_uid,getq_args.gqa_pathp,&dqblk)
									    ==0)
			getq_rslt.status=Q_NOQUOTA; /* failed,return noquota */
		  else	/* set the right values for getq_rslt, and send it */
		    {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(transport,xdr_getquota_rslt,(char*)&getq_rslt)==0)
		printerr_reply(transport);
	return;
}


void exit_svc (signo)	/* signal trapped */
int signo;
{
syslog(LOG_ERR,"exiting on signal %d",signo);
pmap_unset(RQUOTAPROG,RQUOTAVERS);
exit (0);
}


void printerr_reply(transport)	/* when a reply to a request failed */
SVCXPRT *transport;
{	
char *name;
struct sockaddr_in *caller;	
int save_errno;

	save_errno=errno;

	caller=svc_getcaller(transport);
	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);
	return;
}





void initfs()	/* initialise the fs_tab list */
{
register struct fs_stat *fs_current=NULL;
register struct fs_stat *fs_next=NULL;
register struct fstab *fs;
struct stat st;
char *qfpathname,*malloc();
char *qfextension[] = INITQFNAMES;

	setfsent();			/* get entries in /etc/fstab */
	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; /* whe are going to get the previous*/
				/* of the list */
		}
	endfsent();
	fs_begin=fs_current;	/* done. If no quota file where found */
				/* fs_begin == NULL */
}

		
			

/* gets the quotas for id, filesystem path.Return 0 if fail, 1 otherwise */

int
getfsquota(id, path,dqblk)
	register long id;
	char *path;
	struct dqblk *dqblk;

{
	struct stat st_path;
	register struct fs_stat *fs;
	register int qcmd;
	int  fd;
	register int ret=0;

	char *qfextension[] = INITQFNAMES;



	if (stat(path,&st_path)<0) return (0);

	qcmd = QCMD(Q_GETQUOTA, USRQUOTA);


	for (fs=fs_begin;fs!=NULL;fs=fs->fs_next) /* find the fs_stat element*/
					/*where the devise is the same as path*/
	     {
		if (fs->st_dev!=st_path.st_dev)
			continue;

		/* foud the specified filesystem. get and return quota */
		/* the section below comes from quota.c, NetBSD 0.9*/
                if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0) 
			ret=1;
		else
			{
                        if ((fd = open(fs->qfpathname, O_RDONLY)) < 0) {
                                syslog(LOG_ERR,"couldn't read %s:%m",fs->qfpathname);
                                return (0);
                        }
                        lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
                        switch (read(fd, dqblk, sizeof(struct dqblk))) {
                        case 0:                 /* EOF */
                                /*
                                 * 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 */
hasquota(fs, qfnamep)
	register struct fstab *fs;
	char **qfnamep;
{
	register char *opt;
	char *cp, *index(), *strtok();
	static char initname, usrname[100];
	static char buf[BUFSIZ];

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

	(void) sprintf(buf, "%s/%s.%s", fs->fs_file, QUOTAFILENAME, qfextension[USRQUOTA]);
	*qfnamep = buf;
	return (1);
}




--
Manuel Bouyer, Ecole Nationale Superieure de Techniques Avancees, Paris
email: bouyer@ensta.fr
--