17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5edea4b55SLin Ling  * Common Development and Distribution License (the "License").
6edea4b55SLin Ling  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22b1cdc720SAlex Wilson  * Copyright 2017 Joyent Inc
23edea4b55SLin Ling  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
277c478bd9Sstevel@tonic-gate /* All Rights Reserved */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <signal.h>
327c478bd9Sstevel@tonic-gate #include <syslog.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <stropts.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <sys/netconfig.h>
377c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
387c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
397c478bd9Sstevel@tonic-gate #include <sys/param.h>
407c478bd9Sstevel@tonic-gate #include <sys/time.h>
41b1cdc720SAlex Wilson #include <sys/debug.h>
427c478bd9Sstevel@tonic-gate #ifdef notdef
437c478bd9Sstevel@tonic-gate #include <netconfig.h>
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_quota.h>
487c478bd9Sstevel@tonic-gate #include <netdir.h>
497c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
507c478bd9Sstevel@tonic-gate #include <rpcsvc/rquota.h>
517c478bd9Sstevel@tonic-gate #include <tiuser.h>
527c478bd9Sstevel@tonic-gate #include <unistd.h>
53edea4b55SLin Ling #include <dlfcn.h>
54edea4b55SLin Ling #include <libzfs.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #define	QFNAME		"quotas"	/* name of quota file */
577c478bd9Sstevel@tonic-gate #define	RPCSVC_CLOSEDOWN 120		/* 2 minutes */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate struct fsquot {
60edea4b55SLin Ling 	char *fsq_fstype;
617c478bd9Sstevel@tonic-gate 	struct fsquot *fsq_next;
627c478bd9Sstevel@tonic-gate 	char *fsq_dir;
637c478bd9Sstevel@tonic-gate 	char *fsq_devname;
647c478bd9Sstevel@tonic-gate 	dev_t fsq_dev;
657c478bd9Sstevel@tonic-gate };
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate struct fsquot *fsqlist = NULL;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate typedef struct authunix_parms *authp;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static int request_pending;		/* Request in progress ? */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate void closedown();
747c478bd9Sstevel@tonic-gate void dispatch();
757c478bd9Sstevel@tonic-gate struct fsquot *findfsq();
767c478bd9Sstevel@tonic-gate void freefs();
777c478bd9Sstevel@tonic-gate int  getdiskquota();
787c478bd9Sstevel@tonic-gate void getquota();
797c478bd9Sstevel@tonic-gate int  hasquota();
807c478bd9Sstevel@tonic-gate void log_cant_reply();
817c478bd9Sstevel@tonic-gate void setupfs();
826685d298SToomas Soome static void zexit(int) __NORETURN;
83edea4b55SLin Ling 
84edea4b55SLin Ling static libzfs_handle_t *(*_libzfs_init)(void);
85edea4b55SLin Ling static void (*_libzfs_fini)(libzfs_handle_t *);
86edea4b55SLin Ling static zfs_handle_t *(*_zfs_open)(libzfs_handle_t *, const char *, int);
87edea4b55SLin Ling static void (*_zfs_close)(zfs_handle_t *);
88edea4b55SLin Ling static int (*_zfs_prop_get_userquota_int)(zfs_handle_t *, const char *,
89edea4b55SLin Ling     uint64_t *);
90edea4b55SLin Ling static libzfs_handle_t *g_zfs = NULL;
91edea4b55SLin Ling 
92edea4b55SLin Ling /*
93edea4b55SLin Ling  * Dynamically check for libzfs, in case the user hasn't installed the SUNWzfs
94edea4b55SLin Ling  * packages.  'rquotad' supports zfs as an option.
95edea4b55SLin Ling  */
96edea4b55SLin Ling static void
load_libzfs(void)97edea4b55SLin Ling load_libzfs(void)
98edea4b55SLin Ling {
99edea4b55SLin Ling 	void *hdl;
100edea4b55SLin Ling 
101edea4b55SLin Ling 	if (g_zfs != NULL)
102edea4b55SLin Ling 		return;
103edea4b55SLin Ling 
104edea4b55SLin Ling 	if ((hdl = dlopen("libzfs.so", RTLD_LAZY)) != NULL) {
105edea4b55SLin Ling 		_libzfs_init = (libzfs_handle_t *(*)(void))dlsym(hdl,
106edea4b55SLin Ling 		    "libzfs_init");
107edea4b55SLin Ling 		_libzfs_fini = (void (*)())dlsym(hdl, "libzfs_fini");
108edea4b55SLin Ling 		_zfs_open = (zfs_handle_t *(*)())dlsym(hdl, "zfs_open");
109edea4b55SLin Ling 		_zfs_close = (void (*)())dlsym(hdl, "zfs_close");
110edea4b55SLin Ling 		_zfs_prop_get_userquota_int = (int (*)())
111edea4b55SLin Ling 		    dlsym(hdl, "zfs_prop_get_userquota_int");
112edea4b55SLin Ling 
113edea4b55SLin Ling 		if (_libzfs_init && _libzfs_fini && _zfs_open &&
114edea4b55SLin Ling 		    _zfs_close && _zfs_prop_get_userquota_int)
115edea4b55SLin Ling 			g_zfs = _libzfs_init();
116edea4b55SLin Ling 	}
117edea4b55SLin Ling }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12011606941Sjwahlig int
main(int argc,char * argv[])12111606941Sjwahlig main(int argc, char *argv[])
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	register SVCXPRT *transp;
1247c478bd9Sstevel@tonic-gate 
125edea4b55SLin Ling 	load_libzfs();
126edea4b55SLin Ling 
1277c478bd9Sstevel@tonic-gate 	/*
1287c478bd9Sstevel@tonic-gate 	 * If stdin looks like a TLI endpoint, we assume
1297c478bd9Sstevel@tonic-gate 	 * that we were started by a port monitor. If
1307c478bd9Sstevel@tonic-gate 	 * t_getstate fails with TBADF, this is not a
1317c478bd9Sstevel@tonic-gate 	 * TLI endpoint.
1327c478bd9Sstevel@tonic-gate 	 */
1337c478bd9Sstevel@tonic-gate 	if (t_getstate(0) != -1 || t_errno != TBADF) {
1347c478bd9Sstevel@tonic-gate 		char *netid;
1357c478bd9Sstevel@tonic-gate 		struct netconfig *nconf = NULL;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 		openlog("rquotad", LOG_PID, LOG_DAEMON);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 		if ((netid = getenv("NLSPROVIDER")) == NULL) {
1407c478bd9Sstevel@tonic-gate 			struct t_info tinfo;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 			if (t_sync(0) == -1) {
1437c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "could not do t_sync");
144edea4b55SLin Ling 				zexit(1);
1457c478bd9Sstevel@tonic-gate 			}
1467c478bd9Sstevel@tonic-gate 			if (t_getinfo(0, &tinfo) == -1) {
1477c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "t_getinfo failed");
148edea4b55SLin Ling 				zexit(1);
1497c478bd9Sstevel@tonic-gate 			}
1507c478bd9Sstevel@tonic-gate 			if (tinfo.servtype == T_CLTS) {
1517c478bd9Sstevel@tonic-gate 				if (tinfo.addr == INET_ADDRSTRLEN)
1527c478bd9Sstevel@tonic-gate 					netid = "udp";
1537c478bd9Sstevel@tonic-gate 				else
1547c478bd9Sstevel@tonic-gate 					netid = "udp6";
1557c478bd9Sstevel@tonic-gate 			} else {
1567c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "wrong transport");
157edea4b55SLin Ling 				zexit(1);
1587c478bd9Sstevel@tonic-gate 			}
1597c478bd9Sstevel@tonic-gate 		}
1607c478bd9Sstevel@tonic-gate 		if ((nconf = getnetconfigent(netid)) == NULL) {
1617c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "cannot get transport info");
1627c478bd9Sstevel@tonic-gate 		}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 		if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
1657c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "cannot create server handle");
166edea4b55SLin Ling 			zexit(1);
1677c478bd9Sstevel@tonic-gate 		}
1687c478bd9Sstevel@tonic-gate 		if (nconf)
1697c478bd9Sstevel@tonic-gate 			freenetconfigent(nconf);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, dispatch, 0)) {
1727c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
173edea4b55SLin Ling 			    "unable to register (RQUOTAPROG, RQUOTAVERS).");
174edea4b55SLin Ling 			zexit(1);
1757c478bd9Sstevel@tonic-gate 		}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		(void) sigset(SIGALRM, (void(*)(int)) closedown);
1787c478bd9Sstevel@tonic-gate 		(void) alarm(RPCSVC_CLOSEDOWN);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 		svc_run();
181edea4b55SLin Ling 		zexit(1);
1827c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/*
1867c478bd9Sstevel@tonic-gate 	 * Started from a shell - fork the daemon.
1877c478bd9Sstevel@tonic-gate 	 */
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	switch (fork()) {
1907c478bd9Sstevel@tonic-gate 	case 0:		/* child */
1917c478bd9Sstevel@tonic-gate 		break;
1927c478bd9Sstevel@tonic-gate 	case -1:
1937c478bd9Sstevel@tonic-gate 		perror("rquotad: can't fork");
194edea4b55SLin Ling 		zexit(1);
1957c478bd9Sstevel@tonic-gate 	default:	/* parent */
196edea4b55SLin Ling 		zexit(0);
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	/*
2007c478bd9Sstevel@tonic-gate 	 * Close existing file descriptors, open "/dev/null" as
2017c478bd9Sstevel@tonic-gate 	 * standard input, output, and error, and detach from
2027c478bd9Sstevel@tonic-gate 	 * controlling terminal.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	closefrom(0);
2057c478bd9Sstevel@tonic-gate 	(void) open("/dev/null", O_RDONLY);
2067c478bd9Sstevel@tonic-gate 	(void) open("/dev/null", O_WRONLY);
2077c478bd9Sstevel@tonic-gate 	(void) dup(1);
2087c478bd9Sstevel@tonic-gate 	(void) setsid();
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	openlog("rquotad", LOG_PID, LOG_DAEMON);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/*
2137c478bd9Sstevel@tonic-gate 	 * Create datagram service
2147c478bd9Sstevel@tonic-gate 	 */
2157c478bd9Sstevel@tonic-gate 	if (svc_create(dispatch, RQUOTAPROG, RQUOTAVERS, "datagram_v") == 0) {
2167c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "couldn't register datagram_v service");
217edea4b55SLin Ling 		zexit(1);
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	/*
2217c478bd9Sstevel@tonic-gate 	 * Start serving
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate 	svc_run();
2247c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
22511606941Sjwahlig 	return (1);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate void
dispatch(rqstp,transp)2297c478bd9Sstevel@tonic-gate dispatch(rqstp, transp)
2307c478bd9Sstevel@tonic-gate 	register struct svc_req *rqstp;
2317c478bd9Sstevel@tonic-gate 	register SVCXPRT *transp;
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	request_pending = 1;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	switch (rqstp->rq_proc) {
2377c478bd9Sstevel@tonic-gate 	case NULLPROC:
2387c478bd9Sstevel@tonic-gate 		errno = 0;
2397c478bd9Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_void, 0))
2407c478bd9Sstevel@tonic-gate 			log_cant_reply(transp);
2417c478bd9Sstevel@tonic-gate 		break;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	case RQUOTAPROC_GETQUOTA:
2447c478bd9Sstevel@tonic-gate 	case RQUOTAPROC_GETACTIVEQUOTA:
2457c478bd9Sstevel@tonic-gate 		getquota(rqstp, transp);
2467c478bd9Sstevel@tonic-gate 		break;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	default:
2497c478bd9Sstevel@tonic-gate 		svcerr_noproc(transp);
2507c478bd9Sstevel@tonic-gate 		break;
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	request_pending = 0;
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate void
closedown()2577c478bd9Sstevel@tonic-gate closedown()
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	if (!request_pending) {
2607c478bd9Sstevel@tonic-gate 		int i, openfd;
2617c478bd9Sstevel@tonic-gate 		struct t_info tinfo;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		if (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS))
264edea4b55SLin Ling 			zexit(0);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++) {
2677c478bd9Sstevel@tonic-gate 			if (svc_pollfd[i].fd >= 0)
2687c478bd9Sstevel@tonic-gate 				openfd++;
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		if (openfd <= 1)
272edea4b55SLin Ling 			zexit(0);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	(void) alarm(RPCSVC_CLOSEDOWN);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
277edea4b55SLin Ling static int
getzfsquota(uid_t user,char * dataset,struct dqblk * zq)278edea4b55SLin Ling getzfsquota(uid_t user, char *dataset, struct dqblk *zq)
279edea4b55SLin Ling {
280edea4b55SLin Ling 	zfs_handle_t *zhp = NULL;
281edea4b55SLin Ling 	char propname[ZFS_MAXPROPLEN];
282edea4b55SLin Ling 	uint64_t userquota, userused;
283edea4b55SLin Ling 
284edea4b55SLin Ling 	if (g_zfs == NULL)
285edea4b55SLin Ling 		return (1);
286edea4b55SLin Ling 
287edea4b55SLin Ling 	if ((zhp = _zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL) {
288edea4b55SLin Ling 		syslog(LOG_ERR, "can not open zfs dataset %s", dataset);
289edea4b55SLin Ling 		return (1);
290edea4b55SLin Ling 	}
291edea4b55SLin Ling 
292edea4b55SLin Ling 	(void) snprintf(propname, sizeof (propname), "userquota@%u", user);
293edea4b55SLin Ling 	if (_zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
294edea4b55SLin Ling 		_zfs_close(zhp);
295edea4b55SLin Ling 		return (1);
296edea4b55SLin Ling 	}
297edea4b55SLin Ling 
298edea4b55SLin Ling 	(void) snprintf(propname, sizeof (propname), "userused@%u", user);
299edea4b55SLin Ling 	if (_zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
300edea4b55SLin Ling 		_zfs_close(zhp);
301edea4b55SLin Ling 		return (1);
302edea4b55SLin Ling 	}
303edea4b55SLin Ling 
304edea4b55SLin Ling 	zq->dqb_bhardlimit = userquota / DEV_BSIZE;
305edea4b55SLin Ling 	zq->dqb_bsoftlimit = userquota / DEV_BSIZE;
306edea4b55SLin Ling 	zq->dqb_curblocks = userused / DEV_BSIZE;
307edea4b55SLin Ling 	_zfs_close(zhp);
308edea4b55SLin Ling 	return (0);
309edea4b55SLin Ling }
310edea4b55SLin Ling 
3117c478bd9Sstevel@tonic-gate void
getquota(rqstp,transp)3127c478bd9Sstevel@tonic-gate getquota(rqstp, transp)
3137c478bd9Sstevel@tonic-gate 	register struct svc_req *rqstp;
3147c478bd9Sstevel@tonic-gate 	register SVCXPRT *transp;
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate 	struct getquota_args gqa;
3177c478bd9Sstevel@tonic-gate 	struct getquota_rslt gqr;
3187c478bd9Sstevel@tonic-gate 	struct dqblk dqblk;
3197c478bd9Sstevel@tonic-gate 	struct fsquot *fsqp;
3207c478bd9Sstevel@tonic-gate 	struct timeval tv;
3217c478bd9Sstevel@tonic-gate 	bool_t qactive;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	gqa.gqa_pathp = NULL;		/* let xdr allocate the storage */
3247c478bd9Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_getquota_args, (caddr_t)&gqa)) {
3257c478bd9Sstevel@tonic-gate 		svcerr_decode(transp);
3267c478bd9Sstevel@tonic-gate 		return;
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * This authentication is really bogus with the current rpc
3307c478bd9Sstevel@tonic-gate 	 * authentication scheme. One day we will have something for real.
3317c478bd9Sstevel@tonic-gate 	 */
332b1cdc720SAlex Wilson 	CTASSERT(sizeof (authp) <= RQCRED_SIZE);
3337c478bd9Sstevel@tonic-gate 	if (rqstp->rq_cred.oa_flavor != AUTH_UNIX ||
3347c478bd9Sstevel@tonic-gate 	    (((authp) rqstp->rq_clntcred)->aup_uid != 0 &&
3357c478bd9Sstevel@tonic-gate 		((authp) rqstp->rq_clntcred)->aup_uid != (uid_t)gqa.gqa_uid)) {
3367c478bd9Sstevel@tonic-gate 		gqr.status = Q_EPERM;
3377c478bd9Sstevel@tonic-gate 		goto sendreply;
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 	fsqp = findfsq(gqa.gqa_pathp);
3407c478bd9Sstevel@tonic-gate 	if (fsqp == NULL) {
3417c478bd9Sstevel@tonic-gate 		gqr.status = Q_NOQUOTA;
3427c478bd9Sstevel@tonic-gate 		goto sendreply;
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
345edea4b55SLin Ling 	bzero(&dqblk, sizeof (dqblk));
346edea4b55SLin Ling 	if (strcmp(fsqp->fsq_fstype, MNTTYPE_ZFS) == 0) {
347edea4b55SLin Ling 		if (getzfsquota(gqa.gqa_uid, fsqp->fsq_devname, &dqblk)) {
3487c478bd9Sstevel@tonic-gate 			gqr.status = Q_NOQUOTA;
3497c478bd9Sstevel@tonic-gate 			goto sendreply;
3507c478bd9Sstevel@tonic-gate 		}
351edea4b55SLin Ling 		qactive = TRUE;
352edea4b55SLin Ling 	} else {
353edea4b55SLin Ling 		if (quotactl(Q_GETQUOTA, fsqp->fsq_dir,
354edea4b55SLin Ling 		    (uid_t)gqa.gqa_uid, &dqblk) != 0) {
355edea4b55SLin Ling 			qactive = FALSE;
356edea4b55SLin Ling 			if ((errno == ENOENT) ||
357edea4b55SLin Ling 			    (rqstp->rq_proc != RQUOTAPROC_GETQUOTA)) {
3587c478bd9Sstevel@tonic-gate 				gqr.status = Q_NOQUOTA;
3597c478bd9Sstevel@tonic-gate 				goto sendreply;
3607c478bd9Sstevel@tonic-gate 			}
361edea4b55SLin Ling 
362edea4b55SLin Ling 			/*
363edea4b55SLin Ling 			 * If there is no quotas file, don't bother to sync it.
364edea4b55SLin Ling 			 */
365edea4b55SLin Ling 			if (errno != ENOENT) {
366edea4b55SLin Ling 				if (quotactl(Q_ALLSYNC, fsqp->fsq_dir,
367edea4b55SLin Ling 				    (uid_t)gqa.gqa_uid, &dqblk) < 0 &&
368edea4b55SLin Ling 				    errno == EINVAL)
369edea4b55SLin Ling 					syslog(LOG_WARNING,
370edea4b55SLin Ling 					    "Quotas are not compiled "
371edea4b55SLin Ling 					    "into this kernel");
372edea4b55SLin Ling 				if (getdiskquota(fsqp, (uid_t)gqa.gqa_uid,
373edea4b55SLin Ling 				    &dqblk) == 0) {
374edea4b55SLin Ling 					gqr.status = Q_NOQUOTA;
375edea4b55SLin Ling 					goto sendreply;
376edea4b55SLin Ling 				}
377edea4b55SLin Ling 			}
378edea4b55SLin Ling 		} else {
379edea4b55SLin Ling 			qactive = TRUE;
3807c478bd9Sstevel@tonic-gate 		}
381edea4b55SLin Ling 		/*
382edea4b55SLin Ling 		 * We send the remaining time instead of the absolute time
383edea4b55SLin Ling 		 * because clock skew between machines should be much greater
384edea4b55SLin Ling 		 * than rpc delay.
385edea4b55SLin Ling 		 */
3867c478bd9Sstevel@tonic-gate #define	gqrslt getquota_rslt_u.gqr_rquota
3877c478bd9Sstevel@tonic-gate 
388edea4b55SLin Ling 		gettimeofday(&tv, NULL);
389edea4b55SLin Ling 		gqr.gqrslt.rq_btimeleft	= dqblk.dqb_btimelimit - tv.tv_sec;
390edea4b55SLin Ling 		gqr.gqrslt.rq_ftimeleft	= dqblk.dqb_ftimelimit - tv.tv_sec;
391edea4b55SLin Ling 	}
392edea4b55SLin Ling 
3937c478bd9Sstevel@tonic-gate 	gqr.status = Q_OK;
3947c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_active	= qactive;
3957c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_bsize	= DEV_BSIZE;
3967c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_bhardlimit = dqblk.dqb_bhardlimit;
3977c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_bsoftlimit = dqblk.dqb_bsoftlimit;
3987c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_curblocks = dqblk.dqb_curblocks;
3997c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_fhardlimit = dqblk.dqb_fhardlimit;
4007c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_fsoftlimit = dqblk.dqb_fsoftlimit;
4017c478bd9Sstevel@tonic-gate 	gqr.gqrslt.rq_curfiles	= dqblk.dqb_curfiles;
4027c478bd9Sstevel@tonic-gate sendreply:
4037c478bd9Sstevel@tonic-gate 	errno = 0;
4047c478bd9Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_getquota_rslt, (caddr_t)&gqr))
4057c478bd9Sstevel@tonic-gate 		log_cant_reply(transp);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
40811606941Sjwahlig int
quotactl(int cmd,char * mountp,uid_t uid,struct dqblk * dqp)409*8509e9caSToomas Soome quotactl(int cmd, char *mountp, uid_t uid, struct dqblk *dqp)
4107c478bd9Sstevel@tonic-gate {
411*8509e9caSToomas Soome 	int		fd;
412*8509e9caSToomas Soome 	int		status;
413*8509e9caSToomas Soome 	struct quotctl	quota;
4147c478bd9Sstevel@tonic-gate 	char		mountpoint[256];
4157c478bd9Sstevel@tonic-gate 	FILE		*fstab;
4167c478bd9Sstevel@tonic-gate 	struct mnttab	mntp;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if ((mountp == NULL) && (cmd == Q_ALLSYNC)) {
4197c478bd9Sstevel@tonic-gate 		/*
4207c478bd9Sstevel@tonic-gate 		 * Find the mount point of any ufs file system. this is
4217c478bd9Sstevel@tonic-gate 		 * because the ioctl that implements the quotactl call has
4227c478bd9Sstevel@tonic-gate 		 * to go to a real file, and not to the block device.
4237c478bd9Sstevel@tonic-gate 		 */
4247c478bd9Sstevel@tonic-gate 		if ((fstab = fopen(MNTTAB, "r")) == NULL) {
4257c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "can not open %s: %m ", MNTTAB);
4267c478bd9Sstevel@tonic-gate 			return (-1);
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 		fd = -1;
429*8509e9caSToomas Soome 		while ((status = getmntent(fstab, &mntp)) == 0) {
4307c478bd9Sstevel@tonic-gate 			if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 ||
4317c478bd9Sstevel@tonic-gate 				!(hasmntopt(&mntp, MNTOPT_RQ) ||
4327c478bd9Sstevel@tonic-gate 				hasmntopt(&mntp, MNTOPT_QUOTA)))
4337c478bd9Sstevel@tonic-gate 				continue;
434edea4b55SLin Ling 			(void) strlcpy(mountpoint, mntp.mnt_mountp,
435edea4b55SLin Ling 			    sizeof (mountpoint));
4367c478bd9Sstevel@tonic-gate 			strcat(mountpoint, "/quotas");
4377c478bd9Sstevel@tonic-gate 			if ((fd = open64(mountpoint, O_RDWR)) >= 0)
4387c478bd9Sstevel@tonic-gate 				break;
4397c478bd9Sstevel@tonic-gate 		}
4407c478bd9Sstevel@tonic-gate 		fclose(fstab);
4417c478bd9Sstevel@tonic-gate 		if (fd == -1) {
4427c478bd9Sstevel@tonic-gate 			errno = ENOENT;
4437c478bd9Sstevel@tonic-gate 			return (-1);
4447c478bd9Sstevel@tonic-gate 		}
4457c478bd9Sstevel@tonic-gate 	} else {
4467c478bd9Sstevel@tonic-gate 		if (mountp == NULL || mountp[0] == '\0') {
4477c478bd9Sstevel@tonic-gate 			errno = ENOENT;
4487c478bd9Sstevel@tonic-gate 			return (-1);
4497c478bd9Sstevel@tonic-gate 		}
450edea4b55SLin Ling 		(void) strlcpy(mountpoint, mountp, sizeof (mountpoint));
4517c478bd9Sstevel@tonic-gate 		strcat(mountpoint, "/quotas");
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		if ((fd = open64(mountpoint, O_RDONLY)) < 0) {
4547c478bd9Sstevel@tonic-gate 			errno = ENOENT;
4557c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "can not open %s: %m ", mountpoint);
4567c478bd9Sstevel@tonic-gate 			return (-1);
4577c478bd9Sstevel@tonic-gate 		}
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 	quota.op = cmd;
4607c478bd9Sstevel@tonic-gate 	quota.uid = uid;
4617c478bd9Sstevel@tonic-gate 	quota.addr = (caddr_t)dqp;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	status = ioctl(fd, Q_QUOTACTL, &quota);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	close(fd);
4667c478bd9Sstevel@tonic-gate 	return (status);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate  * Return the quota information for the given path.  Returns NULL if none
4717c478bd9Sstevel@tonic-gate  * was found.
4727c478bd9Sstevel@tonic-gate  */
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate struct fsquot *
findfsq(char * dir)4752c151c63SLin Ling findfsq(char *dir)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	struct stat sb;
4782c151c63SLin Ling 	struct fsquot *fsqp;
479*8509e9caSToomas Soome 	static time_t lastmtime = 0;	/* mount table's previous mtime */
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/*
4827c478bd9Sstevel@tonic-gate 	 * If we've never looked at the mount table, or it has changed
4837c478bd9Sstevel@tonic-gate 	 * since the last time, rebuild the list of quota'd file systems
4847c478bd9Sstevel@tonic-gate 	 * and remember the current mod time for the mount table.
4857c478bd9Sstevel@tonic-gate 	 */
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (stat(MNTTAB, &sb) < 0) {
4887c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "can't stat %s: %m", MNTTAB);
4897c478bd9Sstevel@tonic-gate 		return (NULL);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 	if (lastmtime == 0 || sb.st_mtime != lastmtime) {
4927c478bd9Sstevel@tonic-gate 		freefs();
4937c478bd9Sstevel@tonic-gate 		setupfs();
4947c478bd9Sstevel@tonic-gate 		lastmtime = sb.st_mtime;
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	 * Try to find the given path in the list of file systems with
4997c478bd9Sstevel@tonic-gate 	 * quotas.
5007c478bd9Sstevel@tonic-gate 	 */
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	if (fsqlist == NULL)
5037c478bd9Sstevel@tonic-gate 		return (NULL);
5047c478bd9Sstevel@tonic-gate 	if (stat(dir, &sb) < 0)
5057c478bd9Sstevel@tonic-gate 		return (NULL);
506be961672SLin Ling 
5077c478bd9Sstevel@tonic-gate 	for (fsqp = fsqlist; fsqp != NULL; fsqp = fsqp->fsq_next) {
5082c151c63SLin Ling 		if (sb.st_dev == fsqp->fsq_dev)
5097c478bd9Sstevel@tonic-gate 			return (fsqp);
5107c478bd9Sstevel@tonic-gate 	}
5112c151c63SLin Ling 
5127c478bd9Sstevel@tonic-gate 	return (NULL);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
515edea4b55SLin Ling static void
setup_zfs(struct mnttab * mp)516edea4b55SLin Ling setup_zfs(struct mnttab *mp)
517edea4b55SLin Ling {
518edea4b55SLin Ling 	struct fsquot *fsqp;
5192c151c63SLin Ling 	struct stat sb;
5202c151c63SLin Ling 
5212c151c63SLin Ling 	if (stat(mp->mnt_mountp, &sb) < 0)
5222c151c63SLin Ling 		return;
523edea4b55SLin Ling 
524edea4b55SLin Ling 	fsqp = malloc(sizeof (struct fsquot));
525edea4b55SLin Ling 	if (fsqp == NULL) {
526edea4b55SLin Ling 		syslog(LOG_ERR, "out of memory");
527edea4b55SLin Ling 		zexit(1);
528edea4b55SLin Ling 	}
529edea4b55SLin Ling 	fsqp->fsq_dir = strdup(mp->mnt_mountp);
530edea4b55SLin Ling 	fsqp->fsq_devname = strdup(mp->mnt_special);
531edea4b55SLin Ling 	if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) {
532edea4b55SLin Ling 		syslog(LOG_ERR, "out of memory");
533edea4b55SLin Ling 		zexit(1);
534edea4b55SLin Ling 	}
5352c151c63SLin Ling 
536edea4b55SLin Ling 	fsqp->fsq_fstype = MNTTYPE_ZFS;
5372c151c63SLin Ling 	fsqp->fsq_dev = sb.st_dev;
538edea4b55SLin Ling 	fsqp->fsq_next = fsqlist;
539edea4b55SLin Ling 	fsqlist = fsqp;
540edea4b55SLin Ling }
541edea4b55SLin Ling 
5427c478bd9Sstevel@tonic-gate void
setupfs()5437c478bd9Sstevel@tonic-gate setupfs()
5447c478bd9Sstevel@tonic-gate {
545edea4b55SLin Ling 	struct fsquot *fsqp;
5467c478bd9Sstevel@tonic-gate 	FILE *mt;
5477c478bd9Sstevel@tonic-gate 	struct mnttab m;
5487c478bd9Sstevel@tonic-gate 	struct stat sb;
5497c478bd9Sstevel@tonic-gate 	char qfilename[MAXPATHLEN];
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	mt = fopen(MNTTAB, "r");
5527c478bd9Sstevel@tonic-gate 	if (mt == NULL) {
5537c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "can't read %s: %m", MNTTAB);
5547c478bd9Sstevel@tonic-gate 		return;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	while (getmntent(mt, &m) == 0) {
558edea4b55SLin Ling 		if (strcmp(m.mnt_fstype, MNTTYPE_ZFS) == 0) {
559edea4b55SLin Ling 			setup_zfs(&m);
560edea4b55SLin Ling 			continue;
561edea4b55SLin Ling 		}
562edea4b55SLin Ling 
5637c478bd9Sstevel@tonic-gate 		if (strcmp(m.mnt_fstype, MNTTYPE_UFS) != 0)
5647c478bd9Sstevel@tonic-gate 			continue;
5657c478bd9Sstevel@tonic-gate 		if (!hasquota(m.mnt_mntopts)) {
566edea4b55SLin Ling 			snprintf(qfilename, sizeof (qfilename), "%s/%s",
567edea4b55SLin Ling 			    m.mnt_mountp, QFNAME);
5687c478bd9Sstevel@tonic-gate 			if (access(qfilename, F_OK) < 0)
5697c478bd9Sstevel@tonic-gate 				continue;
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate 		if (stat(m.mnt_special, &sb) < 0 ||
5727c478bd9Sstevel@tonic-gate 		    (sb.st_mode & S_IFMT) != S_IFBLK)
5737c478bd9Sstevel@tonic-gate 			continue;
574edea4b55SLin Ling 		fsqp = malloc(sizeof (struct fsquot));
5757c478bd9Sstevel@tonic-gate 		if (fsqp == NULL) {
5767c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "out of memory");
577edea4b55SLin Ling 			zexit(1);
5787c478bd9Sstevel@tonic-gate 		}
579edea4b55SLin Ling 		fsqp->fsq_dir = strdup(m.mnt_mountp);
580edea4b55SLin Ling 		fsqp->fsq_devname = strdup(m.mnt_special);
5817c478bd9Sstevel@tonic-gate 		if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) {
5827c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "out of memory");
583edea4b55SLin Ling 			zexit(1);
5847c478bd9Sstevel@tonic-gate 		}
585edea4b55SLin Ling 		fsqp->fsq_fstype = MNTTYPE_UFS;
5867c478bd9Sstevel@tonic-gate 		fsqp->fsq_dev = sb.st_rdev;
587edea4b55SLin Ling 		fsqp->fsq_next = fsqlist;
5887c478bd9Sstevel@tonic-gate 		fsqlist = fsqp;
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 	(void) fclose(mt);
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate /*
5947c478bd9Sstevel@tonic-gate  * Free the memory used by the current list of quota'd file systems.  Nulls
5957c478bd9Sstevel@tonic-gate  * out the list.
5967c478bd9Sstevel@tonic-gate  */
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate void
freefs()5997c478bd9Sstevel@tonic-gate freefs()
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	register struct fsquot *fsqp;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	while ((fsqp = fsqlist) != NULL) {
6047c478bd9Sstevel@tonic-gate 		fsqlist = fsqp->fsq_next;
6057c478bd9Sstevel@tonic-gate 		free(fsqp->fsq_dir);
6067c478bd9Sstevel@tonic-gate 		free(fsqp->fsq_devname);
6077c478bd9Sstevel@tonic-gate 		free(fsqp);
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate int
getdiskquota(fsqp,uid,dqp)6127c478bd9Sstevel@tonic-gate getdiskquota(fsqp, uid, dqp)
6137c478bd9Sstevel@tonic-gate 	struct fsquot *fsqp;
6147c478bd9Sstevel@tonic-gate 	uid_t uid;
6157c478bd9Sstevel@tonic-gate 	struct dqblk *dqp;
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	int fd;
6187c478bd9Sstevel@tonic-gate 	char qfilename[MAXPATHLEN];
6197c478bd9Sstevel@tonic-gate 
620edea4b55SLin Ling 	snprintf(qfilename, sizeof (qfilename), "%s/%s", fsqp->fsq_dir, QFNAME);
6217c478bd9Sstevel@tonic-gate 	if ((fd = open64(qfilename, O_RDONLY)) < 0)
6227c478bd9Sstevel@tonic-gate 		return (0);
6237c478bd9Sstevel@tonic-gate 	(void) llseek(fd, (offset_t)dqoff(uid), L_SET);
6247c478bd9Sstevel@tonic-gate 	if (read(fd, dqp, sizeof (struct dqblk)) != sizeof (struct dqblk)) {
6257c478bd9Sstevel@tonic-gate 		close(fd);
6267c478bd9Sstevel@tonic-gate 		return (0);
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 	close(fd);
6297c478bd9Sstevel@tonic-gate 	if (dqp->dqb_bhardlimit == 0 && dqp->dqb_bsoftlimit == 0 &&
6307c478bd9Sstevel@tonic-gate 	    dqp->dqb_fhardlimit == 0 && dqp->dqb_fsoftlimit == 0) {
6317c478bd9Sstevel@tonic-gate 		return (0);
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 	return (1);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate /*
6377c478bd9Sstevel@tonic-gate  * Get the client's hostname from the transport handle
6387c478bd9Sstevel@tonic-gate  * If the name is not available then return "(anon)".
6397c478bd9Sstevel@tonic-gate  */
6407c478bd9Sstevel@tonic-gate struct nd_hostservlist *
getclientsnames(transp)6417c478bd9Sstevel@tonic-gate getclientsnames(transp)
6427c478bd9Sstevel@tonic-gate 	SVCXPRT *transp;
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	struct netbuf *nbuf;
6457c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
6467c478bd9Sstevel@tonic-gate 	static struct nd_hostservlist	*serv;
6477c478bd9Sstevel@tonic-gate 	static struct nd_hostservlist	anon_hsl;
6487c478bd9Sstevel@tonic-gate 	static struct nd_hostserv	anon_hs;
6497c478bd9Sstevel@tonic-gate 	static char anon_hname[] = "(anon)";
6507c478bd9Sstevel@tonic-gate 	static char anon_sname[] = "";
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* Set up anonymous client */
6537c478bd9Sstevel@tonic-gate 	anon_hs.h_host = anon_hname;
6547c478bd9Sstevel@tonic-gate 	anon_hs.h_serv = anon_sname;
6557c478bd9Sstevel@tonic-gate 	anon_hsl.h_cnt = 1;
6567c478bd9Sstevel@tonic-gate 	anon_hsl.h_hostservs = &anon_hs;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	if (serv) {
6597c478bd9Sstevel@tonic-gate 		netdir_free((char *)serv, ND_HOSTSERVLIST);
6607c478bd9Sstevel@tonic-gate 		serv = NULL;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 	nconf = getnetconfigent(transp->xp_netid);
6637c478bd9Sstevel@tonic-gate 	if (nconf == NULL) {
6647c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: getnetconfigent failed",
6657c478bd9Sstevel@tonic-gate 			transp->xp_netid);
6667c478bd9Sstevel@tonic-gate 		return (&anon_hsl);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	nbuf = svc_getrpccaller(transp);
6707c478bd9Sstevel@tonic-gate 	if (nbuf == NULL) {
6717c478bd9Sstevel@tonic-gate 		freenetconfigent(nconf);
6727c478bd9Sstevel@tonic-gate 		return (&anon_hsl);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 	if (netdir_getbyaddr(nconf, &serv, nbuf)) {
6757c478bd9Sstevel@tonic-gate 		freenetconfigent(nconf);
6767c478bd9Sstevel@tonic-gate 		return (&anon_hsl);
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 	freenetconfigent(nconf);
6797c478bd9Sstevel@tonic-gate 	return (serv);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate void
log_cant_reply(transp)6837c478bd9Sstevel@tonic-gate log_cant_reply(transp)
6847c478bd9Sstevel@tonic-gate 	SVCXPRT *transp;
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate 	int saverrno;
6877c478bd9Sstevel@tonic-gate 	struct nd_hostservlist *clnames;
6887c478bd9Sstevel@tonic-gate 	register char *name;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	saverrno = errno;	/* save error code */
6917c478bd9Sstevel@tonic-gate 	clnames = getclientsnames(transp);
6927c478bd9Sstevel@tonic-gate 	if (clnames == NULL)
6937c478bd9Sstevel@tonic-gate 		return;
6947c478bd9Sstevel@tonic-gate 	name = clnames->h_hostservs->h_host;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	errno = saverrno;
6977c478bd9Sstevel@tonic-gate 	if (errno == 0)
6987c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "couldn't send reply to %s", name);
6997c478bd9Sstevel@tonic-gate 	else
7007c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "couldn't send reply to %s: %m", name);
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate char *mntopts[] = { MNTOPT_QUOTA, NULL };
7047c478bd9Sstevel@tonic-gate #define	QUOTA    0
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate /*
7077c478bd9Sstevel@tonic-gate  * Return 1 if "quota" appears in the options string
7087c478bd9Sstevel@tonic-gate  */
7097c478bd9Sstevel@tonic-gate int
hasquota(opts)7107c478bd9Sstevel@tonic-gate hasquota(opts)
7117c478bd9Sstevel@tonic-gate 	char *opts;
7127c478bd9Sstevel@tonic-gate {
7137c478bd9Sstevel@tonic-gate 	char *value;
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	if (opts == NULL)
7167c478bd9Sstevel@tonic-gate 		return (0);
7177c478bd9Sstevel@tonic-gate 	while (*opts != '\0') {
7187c478bd9Sstevel@tonic-gate 		if (getsubopt(&opts, mntopts, &value) == QUOTA)
7197c478bd9Sstevel@tonic-gate 			return (1);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	return (0);
7237c478bd9Sstevel@tonic-gate }
724edea4b55SLin Ling 
725edea4b55SLin Ling static void
zexit(int n)726edea4b55SLin Ling zexit(int n)
727edea4b55SLin Ling {
728edea4b55SLin Ling 	if (g_zfs != NULL)
729edea4b55SLin Ling 		_libzfs_fini(g_zfs);
730edea4b55SLin Ling 	exit(n);
731edea4b55SLin Ling }
732