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 /* 22*4b3b7fc6SAlex 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> 41*4b3b7fc6SAlex 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(); 82edea4b55SLin Ling static void zexit(); 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 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 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, 1737c478bd9Sstevel@tonic-gate "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 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 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 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 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 */ 332*4b3b7fc6SAlex 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)) { 348edea4b55SLin Ling gqr.status = Q_NOQUOTA; 349edea4b55SLin Ling goto sendreply; 350edea4b55SLin Ling } 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) { 3557c478bd9Sstevel@tonic-gate qactive = FALSE; 3567c478bd9Sstevel@tonic-gate if ((errno == ENOENT) || 3577c478bd9Sstevel@tonic-gate (rqstp->rq_proc != RQUOTAPROC_GETQUOTA)) { 3587c478bd9Sstevel@tonic-gate gqr.status = Q_NOQUOTA; 3597c478bd9Sstevel@tonic-gate goto sendreply; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * If there is no quotas file, don't bother to sync it. 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 3667c478bd9Sstevel@tonic-gate if (quotactl(Q_ALLSYNC, fsqp->fsq_dir, 3677c478bd9Sstevel@tonic-gate (uid_t)gqa.gqa_uid, &dqblk) < 0 && 3687c478bd9Sstevel@tonic-gate errno == EINVAL) 3697c478bd9Sstevel@tonic-gate 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) { 3747c478bd9Sstevel@tonic-gate gqr.status = Q_NOQUOTA; 3757c478bd9Sstevel@tonic-gate goto sendreply; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate } else { 3797c478bd9Sstevel@tonic-gate qactive = TRUE; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * We send the remaining time instead of the absolute time 3837c478bd9Sstevel@tonic-gate * because clock skew between machines should be much greater 3847c478bd9Sstevel@tonic-gate * than rpc delay. 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate #define gqrslt getquota_rslt_u.gqr_rquota 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate 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 4097c478bd9Sstevel@tonic-gate quotactl(cmd, mountp, uid, dqp) 4107c478bd9Sstevel@tonic-gate int cmd; 4117c478bd9Sstevel@tonic-gate char *mountp; 4127c478bd9Sstevel@tonic-gate uid_t uid; 4137c478bd9Sstevel@tonic-gate struct dqblk *dqp; 4147c478bd9Sstevel@tonic-gate { 4157c478bd9Sstevel@tonic-gate int fd; 4167c478bd9Sstevel@tonic-gate int status; 4177c478bd9Sstevel@tonic-gate struct quotctl quota; 4187c478bd9Sstevel@tonic-gate char mountpoint[256]; 4197c478bd9Sstevel@tonic-gate FILE *fstab; 4207c478bd9Sstevel@tonic-gate struct mnttab mntp; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate if ((mountp == NULL) && (cmd == Q_ALLSYNC)) { 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * Find the mount point of any ufs file system. this is 4257c478bd9Sstevel@tonic-gate * because the ioctl that implements the quotactl call has 4267c478bd9Sstevel@tonic-gate * to go to a real file, and not to the block device. 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate if ((fstab = fopen(MNTTAB, "r")) == NULL) { 4297c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "can not open %s: %m ", MNTTAB); 4307c478bd9Sstevel@tonic-gate return (-1); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate fd = -1; 4337c478bd9Sstevel@tonic-gate while ((status = getmntent(fstab, &mntp)) == NULL) { 4347c478bd9Sstevel@tonic-gate if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 || 4357c478bd9Sstevel@tonic-gate !(hasmntopt(&mntp, MNTOPT_RQ) || 4367c478bd9Sstevel@tonic-gate hasmntopt(&mntp, MNTOPT_QUOTA))) 4377c478bd9Sstevel@tonic-gate continue; 438edea4b55SLin Ling (void) strlcpy(mountpoint, mntp.mnt_mountp, 439edea4b55SLin Ling sizeof (mountpoint)); 4407c478bd9Sstevel@tonic-gate strcat(mountpoint, "/quotas"); 4417c478bd9Sstevel@tonic-gate if ((fd = open64(mountpoint, O_RDWR)) >= 0) 4427c478bd9Sstevel@tonic-gate break; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate fclose(fstab); 4457c478bd9Sstevel@tonic-gate if (fd == -1) { 4467c478bd9Sstevel@tonic-gate errno = ENOENT; 4477c478bd9Sstevel@tonic-gate return (-1); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate } else { 4507c478bd9Sstevel@tonic-gate if (mountp == NULL || mountp[0] == '\0') { 4517c478bd9Sstevel@tonic-gate errno = ENOENT; 4527c478bd9Sstevel@tonic-gate return (-1); 4537c478bd9Sstevel@tonic-gate } 454edea4b55SLin Ling (void) strlcpy(mountpoint, mountp, sizeof (mountpoint)); 4557c478bd9Sstevel@tonic-gate strcat(mountpoint, "/quotas"); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate if ((fd = open64(mountpoint, O_RDONLY)) < 0) { 4587c478bd9Sstevel@tonic-gate errno = ENOENT; 4597c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "can not open %s: %m ", mountpoint); 4607c478bd9Sstevel@tonic-gate return (-1); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate quota.op = cmd; 4647c478bd9Sstevel@tonic-gate quota.uid = uid; 4657c478bd9Sstevel@tonic-gate quota.addr = (caddr_t)dqp; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate status = ioctl(fd, Q_QUOTACTL, "a); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate close(fd); 4707c478bd9Sstevel@tonic-gate return (status); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* 4747c478bd9Sstevel@tonic-gate * Return the quota information for the given path. Returns NULL if none 4757c478bd9Sstevel@tonic-gate * was found. 4767c478bd9Sstevel@tonic-gate */ 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate struct fsquot * 4792c151c63SLin Ling findfsq(char *dir) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate struct stat sb; 4822c151c63SLin Ling struct fsquot *fsqp; 4837c478bd9Sstevel@tonic-gate static time_t lastmtime = 0; /* mount table's previous mtime */ 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * If we've never looked at the mount table, or it has changed 4877c478bd9Sstevel@tonic-gate * since the last time, rebuild the list of quota'd file systems 4887c478bd9Sstevel@tonic-gate * and remember the current mod time for the mount table. 4897c478bd9Sstevel@tonic-gate */ 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (stat(MNTTAB, &sb) < 0) { 4927c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "can't stat %s: %m", MNTTAB); 4937c478bd9Sstevel@tonic-gate return (NULL); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate if (lastmtime == 0 || sb.st_mtime != lastmtime) { 4967c478bd9Sstevel@tonic-gate freefs(); 4977c478bd9Sstevel@tonic-gate setupfs(); 4987c478bd9Sstevel@tonic-gate lastmtime = sb.st_mtime; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Try to find the given path in the list of file systems with 5037c478bd9Sstevel@tonic-gate * quotas. 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (fsqlist == NULL) 5077c478bd9Sstevel@tonic-gate return (NULL); 5087c478bd9Sstevel@tonic-gate if (stat(dir, &sb) < 0) 5097c478bd9Sstevel@tonic-gate return (NULL); 510be961672SLin Ling 5117c478bd9Sstevel@tonic-gate for (fsqp = fsqlist; fsqp != NULL; fsqp = fsqp->fsq_next) { 5122c151c63SLin Ling if (sb.st_dev == fsqp->fsq_dev) 5137c478bd9Sstevel@tonic-gate return (fsqp); 5147c478bd9Sstevel@tonic-gate } 5152c151c63SLin Ling 5167c478bd9Sstevel@tonic-gate return (NULL); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 519edea4b55SLin Ling static void 520edea4b55SLin Ling setup_zfs(struct mnttab *mp) 521edea4b55SLin Ling { 522edea4b55SLin Ling struct fsquot *fsqp; 5232c151c63SLin Ling struct stat sb; 5242c151c63SLin Ling 5252c151c63SLin Ling if (stat(mp->mnt_mountp, &sb) < 0) 5262c151c63SLin Ling return; 527edea4b55SLin Ling 528edea4b55SLin Ling fsqp = malloc(sizeof (struct fsquot)); 529edea4b55SLin Ling if (fsqp == NULL) { 530edea4b55SLin Ling syslog(LOG_ERR, "out of memory"); 531edea4b55SLin Ling zexit(1); 532edea4b55SLin Ling } 533edea4b55SLin Ling fsqp->fsq_dir = strdup(mp->mnt_mountp); 534edea4b55SLin Ling fsqp->fsq_devname = strdup(mp->mnt_special); 535edea4b55SLin Ling if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) { 536edea4b55SLin Ling syslog(LOG_ERR, "out of memory"); 537edea4b55SLin Ling zexit(1); 538edea4b55SLin Ling } 5392c151c63SLin Ling 540edea4b55SLin Ling fsqp->fsq_fstype = MNTTYPE_ZFS; 5412c151c63SLin Ling fsqp->fsq_dev = sb.st_dev; 542edea4b55SLin Ling fsqp->fsq_next = fsqlist; 543edea4b55SLin Ling fsqlist = fsqp; 544edea4b55SLin Ling } 545edea4b55SLin Ling 5467c478bd9Sstevel@tonic-gate void 5477c478bd9Sstevel@tonic-gate setupfs() 5487c478bd9Sstevel@tonic-gate { 549edea4b55SLin Ling struct fsquot *fsqp; 5507c478bd9Sstevel@tonic-gate FILE *mt; 5517c478bd9Sstevel@tonic-gate struct mnttab m; 5527c478bd9Sstevel@tonic-gate struct stat sb; 5537c478bd9Sstevel@tonic-gate char qfilename[MAXPATHLEN]; 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate mt = fopen(MNTTAB, "r"); 5567c478bd9Sstevel@tonic-gate if (mt == NULL) { 5577c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "can't read %s: %m", MNTTAB); 5587c478bd9Sstevel@tonic-gate return; 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate while (getmntent(mt, &m) == 0) { 562edea4b55SLin Ling if (strcmp(m.mnt_fstype, MNTTYPE_ZFS) == 0) { 563edea4b55SLin Ling setup_zfs(&m); 564edea4b55SLin Ling continue; 565edea4b55SLin Ling } 566edea4b55SLin Ling 5677c478bd9Sstevel@tonic-gate if (strcmp(m.mnt_fstype, MNTTYPE_UFS) != 0) 5687c478bd9Sstevel@tonic-gate continue; 5697c478bd9Sstevel@tonic-gate if (!hasquota(m.mnt_mntopts)) { 570edea4b55SLin Ling snprintf(qfilename, sizeof (qfilename), "%s/%s", 571edea4b55SLin Ling m.mnt_mountp, QFNAME); 5727c478bd9Sstevel@tonic-gate if (access(qfilename, F_OK) < 0) 5737c478bd9Sstevel@tonic-gate continue; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate if (stat(m.mnt_special, &sb) < 0 || 5767c478bd9Sstevel@tonic-gate (sb.st_mode & S_IFMT) != S_IFBLK) 5777c478bd9Sstevel@tonic-gate continue; 578edea4b55SLin Ling fsqp = malloc(sizeof (struct fsquot)); 5797c478bd9Sstevel@tonic-gate if (fsqp == NULL) { 5807c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "out of memory"); 581edea4b55SLin Ling zexit(1); 5827c478bd9Sstevel@tonic-gate } 583edea4b55SLin Ling fsqp->fsq_dir = strdup(m.mnt_mountp); 584edea4b55SLin Ling fsqp->fsq_devname = strdup(m.mnt_special); 5857c478bd9Sstevel@tonic-gate if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) { 5867c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "out of memory"); 587edea4b55SLin Ling zexit(1); 5887c478bd9Sstevel@tonic-gate } 589edea4b55SLin Ling fsqp->fsq_fstype = MNTTYPE_UFS; 5907c478bd9Sstevel@tonic-gate fsqp->fsq_dev = sb.st_rdev; 591edea4b55SLin Ling fsqp->fsq_next = fsqlist; 5927c478bd9Sstevel@tonic-gate fsqlist = fsqp; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate (void) fclose(mt); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * Free the memory used by the current list of quota'd file systems. Nulls 5997c478bd9Sstevel@tonic-gate * out the list. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate void 6037c478bd9Sstevel@tonic-gate freefs() 6047c478bd9Sstevel@tonic-gate { 6057c478bd9Sstevel@tonic-gate register struct fsquot *fsqp; 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate while ((fsqp = fsqlist) != NULL) { 6087c478bd9Sstevel@tonic-gate fsqlist = fsqp->fsq_next; 6097c478bd9Sstevel@tonic-gate free(fsqp->fsq_dir); 6107c478bd9Sstevel@tonic-gate free(fsqp->fsq_devname); 6117c478bd9Sstevel@tonic-gate free(fsqp); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate int 6167c478bd9Sstevel@tonic-gate getdiskquota(fsqp, uid, dqp) 6177c478bd9Sstevel@tonic-gate struct fsquot *fsqp; 6187c478bd9Sstevel@tonic-gate uid_t uid; 6197c478bd9Sstevel@tonic-gate struct dqblk *dqp; 6207c478bd9Sstevel@tonic-gate { 6217c478bd9Sstevel@tonic-gate int fd; 6227c478bd9Sstevel@tonic-gate char qfilename[MAXPATHLEN]; 6237c478bd9Sstevel@tonic-gate 624edea4b55SLin Ling snprintf(qfilename, sizeof (qfilename), "%s/%s", fsqp->fsq_dir, QFNAME); 6257c478bd9Sstevel@tonic-gate if ((fd = open64(qfilename, O_RDONLY)) < 0) 6267c478bd9Sstevel@tonic-gate return (0); 6277c478bd9Sstevel@tonic-gate (void) llseek(fd, (offset_t)dqoff(uid), L_SET); 6287c478bd9Sstevel@tonic-gate if (read(fd, dqp, sizeof (struct dqblk)) != sizeof (struct dqblk)) { 6297c478bd9Sstevel@tonic-gate close(fd); 6307c478bd9Sstevel@tonic-gate return (0); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate close(fd); 6337c478bd9Sstevel@tonic-gate if (dqp->dqb_bhardlimit == 0 && dqp->dqb_bsoftlimit == 0 && 6347c478bd9Sstevel@tonic-gate dqp->dqb_fhardlimit == 0 && dqp->dqb_fsoftlimit == 0) { 6357c478bd9Sstevel@tonic-gate return (0); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate return (1); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Get the client's hostname from the transport handle 6427c478bd9Sstevel@tonic-gate * If the name is not available then return "(anon)". 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate struct nd_hostservlist * 6457c478bd9Sstevel@tonic-gate getclientsnames(transp) 6467c478bd9Sstevel@tonic-gate SVCXPRT *transp; 6477c478bd9Sstevel@tonic-gate { 6487c478bd9Sstevel@tonic-gate struct netbuf *nbuf; 6497c478bd9Sstevel@tonic-gate struct netconfig *nconf; 6507c478bd9Sstevel@tonic-gate static struct nd_hostservlist *serv; 6517c478bd9Sstevel@tonic-gate static struct nd_hostservlist anon_hsl; 6527c478bd9Sstevel@tonic-gate static struct nd_hostserv anon_hs; 6537c478bd9Sstevel@tonic-gate static char anon_hname[] = "(anon)"; 6547c478bd9Sstevel@tonic-gate static char anon_sname[] = ""; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* Set up anonymous client */ 6577c478bd9Sstevel@tonic-gate anon_hs.h_host = anon_hname; 6587c478bd9Sstevel@tonic-gate anon_hs.h_serv = anon_sname; 6597c478bd9Sstevel@tonic-gate anon_hsl.h_cnt = 1; 6607c478bd9Sstevel@tonic-gate anon_hsl.h_hostservs = &anon_hs; 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate if (serv) { 6637c478bd9Sstevel@tonic-gate netdir_free((char *)serv, ND_HOSTSERVLIST); 6647c478bd9Sstevel@tonic-gate serv = NULL; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate nconf = getnetconfigent(transp->xp_netid); 6677c478bd9Sstevel@tonic-gate if (nconf == NULL) { 6687c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: getnetconfigent failed", 6697c478bd9Sstevel@tonic-gate transp->xp_netid); 6707c478bd9Sstevel@tonic-gate return (&anon_hsl); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate nbuf = svc_getrpccaller(transp); 6747c478bd9Sstevel@tonic-gate if (nbuf == NULL) { 6757c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 6767c478bd9Sstevel@tonic-gate return (&anon_hsl); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate if (netdir_getbyaddr(nconf, &serv, nbuf)) { 6797c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 6807c478bd9Sstevel@tonic-gate return (&anon_hsl); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 6837c478bd9Sstevel@tonic-gate return (serv); 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate void 6877c478bd9Sstevel@tonic-gate log_cant_reply(transp) 6887c478bd9Sstevel@tonic-gate SVCXPRT *transp; 6897c478bd9Sstevel@tonic-gate { 6907c478bd9Sstevel@tonic-gate int saverrno; 6917c478bd9Sstevel@tonic-gate struct nd_hostservlist *clnames; 6927c478bd9Sstevel@tonic-gate register char *name; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate saverrno = errno; /* save error code */ 6957c478bd9Sstevel@tonic-gate clnames = getclientsnames(transp); 6967c478bd9Sstevel@tonic-gate if (clnames == NULL) 6977c478bd9Sstevel@tonic-gate return; 6987c478bd9Sstevel@tonic-gate name = clnames->h_hostservs->h_host; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate errno = saverrno; 7017c478bd9Sstevel@tonic-gate if (errno == 0) 7027c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "couldn't send reply to %s", name); 7037c478bd9Sstevel@tonic-gate else 7047c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "couldn't send reply to %s: %m", name); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate char *mntopts[] = { MNTOPT_QUOTA, NULL }; 7087c478bd9Sstevel@tonic-gate #define QUOTA 0 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * Return 1 if "quota" appears in the options string 7127c478bd9Sstevel@tonic-gate */ 7137c478bd9Sstevel@tonic-gate int 7147c478bd9Sstevel@tonic-gate hasquota(opts) 7157c478bd9Sstevel@tonic-gate char *opts; 7167c478bd9Sstevel@tonic-gate { 7177c478bd9Sstevel@tonic-gate char *value; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate if (opts == NULL) 7207c478bd9Sstevel@tonic-gate return (0); 7217c478bd9Sstevel@tonic-gate while (*opts != '\0') { 7227c478bd9Sstevel@tonic-gate if (getsubopt(&opts, mntopts, &value) == QUOTA) 7237c478bd9Sstevel@tonic-gate return (1); 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate return (0); 7277c478bd9Sstevel@tonic-gate } 728edea4b55SLin Ling 729edea4b55SLin Ling static void 730edea4b55SLin Ling zexit(int n) 731edea4b55SLin Ling { 732edea4b55SLin Ling if (g_zfs != NULL) 733edea4b55SLin Ling _libzfs_fini(g_zfs); 734edea4b55SLin Ling exit(n); 735edea4b55SLin Ling } 736