xref: /illumos-gate/usr/src/cmd/fs.d/ufs/quota/quota.c (revision 8509e9ca)
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
5d1a180b0Smaheshvs  * Common Development and Distribution License (the "License").
6d1a180b0Smaheshvs  * 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 /*
22edea4b55SLin Ling  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27*8509e9caSToomas Soome /*	  All Rights Reserved	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
317c478bd9Sstevel@tonic-gate  * The Regents of the University of California
327c478bd9Sstevel@tonic-gate  * All Rights Reserved
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
357c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
367c478bd9Sstevel@tonic-gate  * contributors.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Disk quota reporting program.
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate #include <stdio.h>
437c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
447c478bd9Sstevel@tonic-gate #include <ctype.h>
457c478bd9Sstevel@tonic-gate #include <pwd.h>
467c478bd9Sstevel@tonic-gate #include <errno.h>
477c478bd9Sstevel@tonic-gate #include <fcntl.h>
487c478bd9Sstevel@tonic-gate #include <memory.h>
497c478bd9Sstevel@tonic-gate #include <sys/time.h>
507c478bd9Sstevel@tonic-gate #include <sys/param.h>
517c478bd9Sstevel@tonic-gate #include <sys/types.h>
527c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
537c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
547c478bd9Sstevel@tonic-gate #include <sys/file.h>
557c478bd9Sstevel@tonic-gate #include <sys/stat.h>
567c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_quota.h>
57fabd6b6fSabalfour #include <priv_utils.h>
58fabd6b6fSabalfour #include <locale.h>
59bfa62c28SVallish Vaidyeshwara #include <rpc/rpc.h>
60bfa62c28SVallish Vaidyeshwara #include <netdb.h>
61bfa62c28SVallish Vaidyeshwara #include <rpcsvc/rquota.h>
62bfa62c28SVallish Vaidyeshwara #include <zone.h>
63bfa62c28SVallish Vaidyeshwara #include "../../nfs/lib/replica.h"
64edea4b55SLin Ling #include <dlfcn.h>
65edea4b55SLin Ling #include <libzfs.h>
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate int	vflag;
687c478bd9Sstevel@tonic-gate int	nolocalquota;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate extern int	optind;
717c478bd9Sstevel@tonic-gate extern char	*optarg;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	QFNAME	"quotas"
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #if DEV_BSIZE < 1024
767c478bd9Sstevel@tonic-gate #define	kb(x)	((x) / (1024 / DEV_BSIZE))
777c478bd9Sstevel@tonic-gate #else
787c478bd9Sstevel@tonic-gate #define	kb(x)	((x) * (DEV_BSIZE / 1024))
797c478bd9Sstevel@tonic-gate #endif
807c478bd9Sstevel@tonic-gate 
81fabd6b6fSabalfour #if	!defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
82fabd6b6fSabalfour #define	TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
83fabd6b6fSabalfour #endif
84fabd6b6fSabalfour 
85edea4b55SLin Ling static void zexit(int);
86edea4b55SLin Ling static int getzfsquota(char *, char *, struct dqblk *);
877c478bd9Sstevel@tonic-gate static int getnfsquota(char *, char *, uid_t, struct dqblk *);
88d1a180b0Smaheshvs static void showuid(uid_t);
89d1a180b0Smaheshvs static void showquotas(uid_t, char *);
90d1a180b0Smaheshvs static void warn(struct mnttab *, struct dqblk *);
91d1a180b0Smaheshvs static void heading(uid_t, char *);
92d1a180b0Smaheshvs static void prquota(struct mnttab *, struct dqblk *);
93d1a180b0Smaheshvs static void fmttime(char *, long);
947c478bd9Sstevel@tonic-gate 
95edea4b55SLin Ling static libzfs_handle_t *(*_libzfs_init)(void);
96edea4b55SLin Ling static void (*_libzfs_fini)(libzfs_handle_t *);
97edea4b55SLin Ling static zfs_handle_t *(*_zfs_open)(libzfs_handle_t *, const char *, int);
98edea4b55SLin Ling static void (*_zfs_close)(zfs_handle_t *);
99edea4b55SLin Ling static int (*_zfs_prop_get_userquota_int)(zfs_handle_t *, const char *,
100edea4b55SLin Ling     uint64_t *);
101edea4b55SLin Ling static libzfs_handle_t *g_zfs = NULL;
102edea4b55SLin Ling 
103edea4b55SLin Ling /*
104edea4b55SLin Ling  * Dynamically check for libzfs, in case the user hasn't installed the SUNWzfs
105edea4b55SLin Ling  * packages.  'quota' utility supports zfs as an option.
106edea4b55SLin Ling  */
107edea4b55SLin Ling static void
load_libzfs(void)108edea4b55SLin Ling load_libzfs(void)
109edea4b55SLin Ling {
110edea4b55SLin Ling 	void *hdl;
111edea4b55SLin Ling 
112edea4b55SLin Ling 	if (g_zfs != NULL)
113edea4b55SLin Ling 		return;
114edea4b55SLin Ling 
115edea4b55SLin Ling 	if ((hdl = dlopen("libzfs.so", RTLD_LAZY)) != NULL) {
116edea4b55SLin Ling 		_libzfs_init = (libzfs_handle_t *(*)(void))dlsym(hdl,
117edea4b55SLin Ling 		    "libzfs_init");
118edea4b55SLin Ling 		_libzfs_fini = (void (*)())dlsym(hdl, "libzfs_fini");
119edea4b55SLin Ling 		_zfs_open = (zfs_handle_t *(*)())dlsym(hdl, "zfs_open");
120edea4b55SLin Ling 		_zfs_close = (void (*)())dlsym(hdl, "zfs_close");
121edea4b55SLin Ling 		_zfs_prop_get_userquota_int = (int (*)())
122edea4b55SLin Ling 		    dlsym(hdl, "zfs_prop_get_userquota_int");
123edea4b55SLin Ling 
124edea4b55SLin Ling 		if (_libzfs_init && _libzfs_fini && _zfs_open &&
125edea4b55SLin Ling 		    _zfs_close && _zfs_prop_get_userquota_int)
126edea4b55SLin Ling 			g_zfs = _libzfs_init();
127edea4b55SLin Ling 	}
128edea4b55SLin Ling }
129edea4b55SLin Ling 
130d1a180b0Smaheshvs int
main(int argc,char * argv[])131d1a180b0Smaheshvs main(int argc, char *argv[])
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	int	opt;
1347c478bd9Sstevel@tonic-gate 	int	i;
1357c478bd9Sstevel@tonic-gate 	int	status = 0;
1367c478bd9Sstevel@tonic-gate 
137fabd6b6fSabalfour 	(void) setlocale(LC_ALL, "");
138fabd6b6fSabalfour 	(void) textdomain(TEXT_DOMAIN);
139fabd6b6fSabalfour 
140fabd6b6fSabalfour 	/*
141fabd6b6fSabalfour 	 * PRIV_FILE_DAC_READ is needed to read the QFNAME file
142fabd6b6fSabalfour 	 * Clear all other privleges from the limit set, and add
143fabd6b6fSabalfour 	 * the required privilege to the bracketed set.
144fabd6b6fSabalfour 	 */
145fabd6b6fSabalfour 
146fabd6b6fSabalfour 	if (__init_suid_priv(PU_CLEARLIMITSET, PRIV_FILE_DAC_READ,
147bfa62c28SVallish Vaidyeshwara 	    NULL) == -1) {
148fabd6b6fSabalfour 		(void) fprintf(stderr,
149bfa62c28SVallish Vaidyeshwara 		    gettext("Insufficient privileges, "
150bfa62c28SVallish Vaidyeshwara 		    "quota must be set-uid root or have "
151bfa62c28SVallish Vaidyeshwara 		    "file_dac_read privileges\n"));
152fabd6b6fSabalfour 
153fabd6b6fSabalfour 		exit(1);
154fabd6b6fSabalfour 	}
155fabd6b6fSabalfour 
156edea4b55SLin Ling 	load_libzfs();
157edea4b55SLin Ling 
1587c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "vV")) != EOF) {
1597c478bd9Sstevel@tonic-gate 		switch (opt) {
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 		case 'v':
1627c478bd9Sstevel@tonic-gate 			vflag++;
1637c478bd9Sstevel@tonic-gate 			break;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 		case 'V':		/* Print command line */
1667c478bd9Sstevel@tonic-gate 			{
1677c478bd9Sstevel@tonic-gate 			char	*opt_text;
1687c478bd9Sstevel@tonic-gate 			int	opt_count;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "quota -F UFS ");
1717c478bd9Sstevel@tonic-gate 			for (opt_count = 1; opt_count < argc; opt_count++) {
1727c478bd9Sstevel@tonic-gate 				opt_text = argv[opt_count];
1737c478bd9Sstevel@tonic-gate 				if (opt_text)
174bfa62c28SVallish Vaidyeshwara 					(void) fprintf(stdout, " %s ",
175bfa62c28SVallish Vaidyeshwara 					    opt_text);
1767c478bd9Sstevel@tonic-gate 			}
1777c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "\n");
1787c478bd9Sstevel@tonic-gate 			}
1797c478bd9Sstevel@tonic-gate 			break;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		case '?':
182edea4b55SLin Ling 			fprintf(stderr, "usage: quota [-v] [username]\n");
183edea4b55SLin Ling 			zexit(32);
1847c478bd9Sstevel@tonic-gate 		}
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 	if (quotactl(Q_ALLSYNC, NULL, (uid_t)0, NULL) < 0 && errno == EINVAL) {
1877c478bd9Sstevel@tonic-gate 		if (vflag)
1887c478bd9Sstevel@tonic-gate 			fprintf(stderr, "There are no quotas on this system\n");
1897c478bd9Sstevel@tonic-gate 		nolocalquota++;
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 	if (argc == optind) {
1927c478bd9Sstevel@tonic-gate 		showuid(getuid());
193edea4b55SLin Ling 		zexit(0);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 	for (i = optind; i < argc; i++) {
1967c478bd9Sstevel@tonic-gate 		if (alldigits(argv[i])) {
1977c478bd9Sstevel@tonic-gate 			showuid((uid_t)atoi(argv[i]));
1987c478bd9Sstevel@tonic-gate 		} else
1997c478bd9Sstevel@tonic-gate 			status |= showname(argv[i]);
2007c478bd9Sstevel@tonic-gate 	}
201fabd6b6fSabalfour 	__priv_relinquish();
202d1a180b0Smaheshvs 	return (status);
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate 
205d1a180b0Smaheshvs static void
showuid(uid_t uid)206d1a180b0Smaheshvs showuid(uid_t uid)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	struct passwd *pwd = getpwuid(uid);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (uid == 0) {
2117c478bd9Sstevel@tonic-gate 		if (vflag)
2127c478bd9Sstevel@tonic-gate 			printf("no disk quota for uid 0\n");
2137c478bd9Sstevel@tonic-gate 		return;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	if (pwd == NULL)
2167c478bd9Sstevel@tonic-gate 		showquotas(uid, "(no account)");
2177c478bd9Sstevel@tonic-gate 	else
2187c478bd9Sstevel@tonic-gate 		showquotas(uid, pwd->pw_name);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate int
showname(char * name)222d1a180b0Smaheshvs showname(char *name)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	struct passwd *pwd = getpwnam(name);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	if (pwd == NULL) {
2277c478bd9Sstevel@tonic-gate 		fprintf(stderr, "quota: %s: unknown user\n", name);
2287c478bd9Sstevel@tonic-gate 		return (32);
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	if (pwd->pw_uid == 0) {
2317c478bd9Sstevel@tonic-gate 		if (vflag)
2327c478bd9Sstevel@tonic-gate 			printf("no disk quota for %s (uid 0)\n", name);
2337c478bd9Sstevel@tonic-gate 		return (0);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 	showquotas(pwd->pw_uid, name);
2367c478bd9Sstevel@tonic-gate 	return (0);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
239d1a180b0Smaheshvs static void
showquotas(uid_t uid,char * name)240d1a180b0Smaheshvs showquotas(uid_t uid, char *name)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate 	struct mnttab mnt;
2437c478bd9Sstevel@tonic-gate 	FILE *mtab;
2447c478bd9Sstevel@tonic-gate 	struct dqblk dqblk;
2457c478bd9Sstevel@tonic-gate 	uid_t myuid;
246bfa62c28SVallish Vaidyeshwara 	struct failed_srv {
247bfa62c28SVallish Vaidyeshwara 		char *serv_name;
248bfa62c28SVallish Vaidyeshwara 		struct failed_srv *next;
249bfa62c28SVallish Vaidyeshwara 	};
250bfa62c28SVallish Vaidyeshwara 	struct failed_srv *failed_srv_list = NULL;
251bfa62c28SVallish Vaidyeshwara 	int	rc;
252bfa62c28SVallish Vaidyeshwara 	char	my_zonename[ZONENAME_MAX];
253bfa62c28SVallish Vaidyeshwara 	zoneid_t my_zoneid = getzoneid();
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	myuid = getuid();
2567c478bd9Sstevel@tonic-gate 	if (uid != myuid && myuid != 0) {
2577c478bd9Sstevel@tonic-gate 		printf("quota: %s (uid %d): permission denied\n", name, uid);
258edea4b55SLin Ling 		zexit(32);
2597c478bd9Sstevel@tonic-gate 	}
260bfa62c28SVallish Vaidyeshwara 
261bfa62c28SVallish Vaidyeshwara 	memset(my_zonename, '\0', ZONENAME_MAX);
262bfa62c28SVallish Vaidyeshwara 	getzonenamebyid(my_zoneid, my_zonename, ZONENAME_MAX);
263bfa62c28SVallish Vaidyeshwara 
2647c478bd9Sstevel@tonic-gate 	if (vflag)
2657c478bd9Sstevel@tonic-gate 		heading(uid, name);
2667c478bd9Sstevel@tonic-gate 	mtab = fopen(MNTTAB, "r");
267*8509e9caSToomas Soome 	while (getmntent(mtab, &mnt) == 0) {
268edea4b55SLin Ling 		if (strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) == 0) {
269edea4b55SLin Ling 			bzero(&dqblk, sizeof (dqblk));
270edea4b55SLin Ling 			if (getzfsquota(name, mnt.mnt_special, &dqblk))
271edea4b55SLin Ling 				continue;
272edea4b55SLin Ling 		} else if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) == 0) {
2737c478bd9Sstevel@tonic-gate 			if (nolocalquota ||
2747c478bd9Sstevel@tonic-gate 			    (quotactl(Q_GETQUOTA,
275bfa62c28SVallish Vaidyeshwara 			    mnt.mnt_mountp, uid, &dqblk) != 0 &&
276bfa62c28SVallish Vaidyeshwara 			    !(vflag && getdiskquota(&mnt, uid, &dqblk))))
277bfa62c28SVallish Vaidyeshwara 				continue;
2787c478bd9Sstevel@tonic-gate 		} else if (strcmp(mnt.mnt_fstype, MNTTYPE_NFS) == 0) {
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 			struct replica *rl;
2817c478bd9Sstevel@tonic-gate 			int count;
282bfa62c28SVallish Vaidyeshwara 			char *mntopt = NULL;
283bfa62c28SVallish Vaidyeshwara 
284bfa62c28SVallish Vaidyeshwara 			/*
285bfa62c28SVallish Vaidyeshwara 			 * Skip checking quotas for file systems mounted
286bfa62c28SVallish Vaidyeshwara 			 * in other zones. Zone names will be passed in
287bfa62c28SVallish Vaidyeshwara 			 * following format from hasmntopt():
288bfa62c28SVallish Vaidyeshwara 			 * "zone=<zone-name>,<mnt options...>"
289bfa62c28SVallish Vaidyeshwara 			 */
290bfa62c28SVallish Vaidyeshwara 			if ((mntopt = hasmntopt(&mnt, MNTOPT_ZONE)) &&
291bfa62c28SVallish Vaidyeshwara 			    (my_zonename[0] != '\0')) {
292834b3a43SRichard Lowe 				mntopt += strcspn(mntopt, "=") + 1;
293834b3a43SRichard Lowe 				if (strncmp(mntopt, my_zonename,
294bfa62c28SVallish Vaidyeshwara 				    strcspn(mntopt, ",")) != 0)
295bfa62c28SVallish Vaidyeshwara 					continue;
296bfa62c28SVallish Vaidyeshwara 			}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 			if (hasopt(MNTOPT_NOQUOTA, mnt.mnt_mntopts))
2997c478bd9Sstevel@tonic-gate 				continue;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 			/*
3027c478bd9Sstevel@tonic-gate 			 * Skip quota processing if mounted with public
3037c478bd9Sstevel@tonic-gate 			 * option. We are not likely to be able to pierce
3047c478bd9Sstevel@tonic-gate 			 * a fire wall to contact the quota server.
3057c478bd9Sstevel@tonic-gate 			 */
3067c478bd9Sstevel@tonic-gate 			if (hasopt(MNTOPT_PUBLIC, mnt.mnt_mntopts))
3077c478bd9Sstevel@tonic-gate 				continue;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 			rl = parse_replica(mnt.mnt_special, &count);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 			if (rl == NULL) {
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 				if (count < 0)
3147c478bd9Sstevel@tonic-gate 					fprintf(stderr, "cannot find hostname "
3157c478bd9Sstevel@tonic-gate 					    "and/or pathname for %s\n",
3167c478bd9Sstevel@tonic-gate 					    mnt.mnt_mountp);
3177c478bd9Sstevel@tonic-gate 				else
3187c478bd9Sstevel@tonic-gate 					fprintf(stderr, "no memory to parse "
3197c478bd9Sstevel@tonic-gate 					    "mnttab entry for %s\n",
3207c478bd9Sstevel@tonic-gate 					    mnt.mnt_mountp);
3217c478bd9Sstevel@tonic-gate 				continue;
3227c478bd9Sstevel@tonic-gate 			}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			/*
3257c478bd9Sstevel@tonic-gate 			 * We skip quota reporting on mounts with replicas
3267c478bd9Sstevel@tonic-gate 			 * for the following reasons:
3277c478bd9Sstevel@tonic-gate 			 *
3287c478bd9Sstevel@tonic-gate 			 * (1) Very little point in reporting quotas on
3297c478bd9Sstevel@tonic-gate 			 * a set of read-only replicas ... how will the
3307c478bd9Sstevel@tonic-gate 			 * user correct the problem?
3317c478bd9Sstevel@tonic-gate 			 *
3327c478bd9Sstevel@tonic-gate 			 * (2) Which replica would we report the quota
3337c478bd9Sstevel@tonic-gate 			 * for? If we pick the current replica, what
3347c478bd9Sstevel@tonic-gate 			 * happens when a fail over event occurs? The
3357c478bd9Sstevel@tonic-gate 			 * next time quota is run, the quota will look
3367c478bd9Sstevel@tonic-gate 			 * all different, or there won't even be one.
3377c478bd9Sstevel@tonic-gate 			 * This has the potential to break scripts.
3387c478bd9Sstevel@tonic-gate 			 *
3397c478bd9Sstevel@tonic-gate 			 * If we prnt quouta for all replicas, how do
3407c478bd9Sstevel@tonic-gate 			 * we present the output without breaking scripts?
3417c478bd9Sstevel@tonic-gate 			 */
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 			if (count > 1) {
3447c478bd9Sstevel@tonic-gate 				free_replica(rl, count);
3457c478bd9Sstevel@tonic-gate 				continue;
3467c478bd9Sstevel@tonic-gate 			}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 			/*
3497c478bd9Sstevel@tonic-gate 			 * Skip file systems mounted using public fh.
3507c478bd9Sstevel@tonic-gate 			 * We are not likely to be able to pierce
3517c478bd9Sstevel@tonic-gate 			 * a fire wall to contact the quota server.
3527c478bd9Sstevel@tonic-gate 			 */
3537c478bd9Sstevel@tonic-gate 			if (strcmp(rl[0].host, "nfs") == 0 &&
3547c478bd9Sstevel@tonic-gate 			    strncmp(rl[0].path, "//", 2) == 0) {
3557c478bd9Sstevel@tonic-gate 				free_replica(rl, count);
3567c478bd9Sstevel@tonic-gate 				continue;
3577c478bd9Sstevel@tonic-gate 			}
3587c478bd9Sstevel@tonic-gate 
359bfa62c28SVallish Vaidyeshwara 			/*
360bfa62c28SVallish Vaidyeshwara 			 * Skip getting quotas from failing servers
361bfa62c28SVallish Vaidyeshwara 			 */
362bfa62c28SVallish Vaidyeshwara 			if (failed_srv_list != NULL) {
363bfa62c28SVallish Vaidyeshwara 				struct failed_srv *tmp_list;
364bfa62c28SVallish Vaidyeshwara 				int found_failed = 0;
365bfa62c28SVallish Vaidyeshwara 				size_t len = strlen(rl[0].host);
366bfa62c28SVallish Vaidyeshwara 
367bfa62c28SVallish Vaidyeshwara 				tmp_list = failed_srv_list;
368bfa62c28SVallish Vaidyeshwara 				do {
369bfa62c28SVallish Vaidyeshwara 					if (strncasecmp(rl[0].host,
370bfa62c28SVallish Vaidyeshwara 					    tmp_list->serv_name, len) == 0) {
371bfa62c28SVallish Vaidyeshwara 						found_failed = 1;
372bfa62c28SVallish Vaidyeshwara 						break;
373bfa62c28SVallish Vaidyeshwara 					}
374bfa62c28SVallish Vaidyeshwara 				} while ((tmp_list = tmp_list->next) != NULL);
375bfa62c28SVallish Vaidyeshwara 				if (found_failed) {
376bfa62c28SVallish Vaidyeshwara 					free_replica(rl, count);
377bfa62c28SVallish Vaidyeshwara 					continue;
378bfa62c28SVallish Vaidyeshwara 				}
379bfa62c28SVallish Vaidyeshwara 			}
380bfa62c28SVallish Vaidyeshwara 
381bfa62c28SVallish Vaidyeshwara 			rc = getnfsquota(rl[0].host, rl[0].path, uid, &dqblk);
382bfa62c28SVallish Vaidyeshwara 			if (rc != RPC_SUCCESS) {
383bfa62c28SVallish Vaidyeshwara 				size_t len;
384bfa62c28SVallish Vaidyeshwara 				struct failed_srv *tmp_srv;
385bfa62c28SVallish Vaidyeshwara 
386bfa62c28SVallish Vaidyeshwara 				/*
387bfa62c28SVallish Vaidyeshwara 				 * Failed to get quota from this server. Add
388bfa62c28SVallish Vaidyeshwara 				 * this server to failed_srv_list and skip
389bfa62c28SVallish Vaidyeshwara 				 * getting quotas for other mounted filesystems
390bfa62c28SVallish Vaidyeshwara 				 * from this server.
391bfa62c28SVallish Vaidyeshwara 				 */
392bfa62c28SVallish Vaidyeshwara 				if (rc == RPC_TIMEDOUT || rc == RPC_CANTSEND) {
393bfa62c28SVallish Vaidyeshwara 					len = strlen(rl[0].host);
394bfa62c28SVallish Vaidyeshwara 					tmp_srv = (struct failed_srv *)malloc(
395bfa62c28SVallish Vaidyeshwara 					    sizeof (struct failed_srv));
396bfa62c28SVallish Vaidyeshwara 					tmp_srv->serv_name = (char *)malloc(
397bfa62c28SVallish Vaidyeshwara 					    len * sizeof (char) + 1);
398bfa62c28SVallish Vaidyeshwara 					strncpy(tmp_srv->serv_name, rl[0].host,
399bfa62c28SVallish Vaidyeshwara 					    len);
400bfa62c28SVallish Vaidyeshwara 					tmp_srv->serv_name[len] = '\0';
401bfa62c28SVallish Vaidyeshwara 
402bfa62c28SVallish Vaidyeshwara 					tmp_srv->next = failed_srv_list;
403bfa62c28SVallish Vaidyeshwara 					failed_srv_list = tmp_srv;
404bfa62c28SVallish Vaidyeshwara 				}
405bfa62c28SVallish Vaidyeshwara 
4067c478bd9Sstevel@tonic-gate 				free_replica(rl, count);
4077c478bd9Sstevel@tonic-gate 				continue;
4087c478bd9Sstevel@tonic-gate 			}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 			free_replica(rl, count);
4117c478bd9Sstevel@tonic-gate 		} else {
4127c478bd9Sstevel@tonic-gate 			continue;
4137c478bd9Sstevel@tonic-gate 		}
4147c478bd9Sstevel@tonic-gate 		if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0 &&
4157c478bd9Sstevel@tonic-gate 		    dqblk.dqb_fsoftlimit == 0 && dqblk.dqb_fhardlimit == 0)
4167c478bd9Sstevel@tonic-gate 			continue;
4177c478bd9Sstevel@tonic-gate 		if (vflag)
4187c478bd9Sstevel@tonic-gate 			prquota(&mnt, &dqblk);
4197c478bd9Sstevel@tonic-gate 		else
4207c478bd9Sstevel@tonic-gate 			warn(&mnt, &dqblk);
4217c478bd9Sstevel@tonic-gate 	}
422bfa62c28SVallish Vaidyeshwara 
423bfa62c28SVallish Vaidyeshwara 	/*
424bfa62c28SVallish Vaidyeshwara 	 * Free list of failed servers
425bfa62c28SVallish Vaidyeshwara 	 */
426bfa62c28SVallish Vaidyeshwara 	while (failed_srv_list != NULL) {
427bfa62c28SVallish Vaidyeshwara 		struct failed_srv *tmp_srv = failed_srv_list;
428bfa62c28SVallish Vaidyeshwara 
429bfa62c28SVallish Vaidyeshwara 		failed_srv_list = failed_srv_list->next;
430bfa62c28SVallish Vaidyeshwara 		free(tmp_srv->serv_name);
431bfa62c28SVallish Vaidyeshwara 		free(tmp_srv);
432bfa62c28SVallish Vaidyeshwara 	}
433bfa62c28SVallish Vaidyeshwara 
4347c478bd9Sstevel@tonic-gate 	fclose(mtab);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
437d1a180b0Smaheshvs static void
warn(struct mnttab * mntp,struct dqblk * dqp)438d1a180b0Smaheshvs warn(struct mnttab *mntp, struct dqblk *dqp)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate 	struct timeval tv;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	time(&(tv.tv_sec));
4437c478bd9Sstevel@tonic-gate 	tv.tv_usec = 0;
4447c478bd9Sstevel@tonic-gate 	if (dqp->dqb_bhardlimit &&
445bfa62c28SVallish Vaidyeshwara 	    dqp->dqb_curblocks >= dqp->dqb_bhardlimit) {
4467c478bd9Sstevel@tonic-gate 		printf("Block limit reached on %s\n", mntp->mnt_mountp);
4477c478bd9Sstevel@tonic-gate 	} else if (dqp->dqb_bsoftlimit &&
448bfa62c28SVallish Vaidyeshwara 	    dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
4497c478bd9Sstevel@tonic-gate 		if (dqp->dqb_btimelimit == 0) {
4507c478bd9Sstevel@tonic-gate 			printf("Over disk quota on %s, remove %luK\n",
4517c478bd9Sstevel@tonic-gate 			    mntp->mnt_mountp,
4527c478bd9Sstevel@tonic-gate 			    kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
4537c478bd9Sstevel@tonic-gate 		} else if (dqp->dqb_btimelimit > tv.tv_sec) {
4547c478bd9Sstevel@tonic-gate 			char btimeleft[80];
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 			fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
4577c478bd9Sstevel@tonic-gate 			printf("Over disk quota on %s, remove %luK within %s\n",
4587c478bd9Sstevel@tonic-gate 			    mntp->mnt_mountp,
4597c478bd9Sstevel@tonic-gate 			    kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1),
4607c478bd9Sstevel@tonic-gate 			    btimeleft);
4617c478bd9Sstevel@tonic-gate 		} else {
4627c478bd9Sstevel@tonic-gate 			printf(
4637c478bd9Sstevel@tonic-gate 		"Over disk quota on %s, time limit has expired, remove %luK\n",
4647c478bd9Sstevel@tonic-gate 			    mntp->mnt_mountp,
4657c478bd9Sstevel@tonic-gate 			    kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	if (dqp->dqb_fhardlimit &&
4697c478bd9Sstevel@tonic-gate 	    dqp->dqb_curfiles >= dqp->dqb_fhardlimit) {
4707c478bd9Sstevel@tonic-gate 		printf("File count limit reached on %s\n", mntp->mnt_mountp);
4717c478bd9Sstevel@tonic-gate 	} else if (dqp->dqb_fsoftlimit &&
4727c478bd9Sstevel@tonic-gate 	    dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
4737c478bd9Sstevel@tonic-gate 		if (dqp->dqb_ftimelimit == 0) {
4747c478bd9Sstevel@tonic-gate 			printf("Over file quota on %s, remove %lu file%s\n",
4757c478bd9Sstevel@tonic-gate 			    mntp->mnt_mountp,
4767c478bd9Sstevel@tonic-gate 			    dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
4777c478bd9Sstevel@tonic-gate 			    ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
478bfa62c28SVallish Vaidyeshwara 			    "s" : ""));
4797c478bd9Sstevel@tonic-gate 		} else if (dqp->dqb_ftimelimit > tv.tv_sec) {
4807c478bd9Sstevel@tonic-gate 			char ftimeleft[80];
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 			fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
4837c478bd9Sstevel@tonic-gate 			printf(
4847c478bd9Sstevel@tonic-gate "Over file quota on %s, remove %lu file%s within %s\n",
4857c478bd9Sstevel@tonic-gate 			    mntp->mnt_mountp,
4867c478bd9Sstevel@tonic-gate 			    dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
4877c478bd9Sstevel@tonic-gate 			    ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
488bfa62c28SVallish Vaidyeshwara 			    "s" : ""), ftimeleft);
4897c478bd9Sstevel@tonic-gate 		} else {
4907c478bd9Sstevel@tonic-gate 			printf(
4917c478bd9Sstevel@tonic-gate "Over file quota on %s, time limit has expired, remove %lu file%s\n",
4927c478bd9Sstevel@tonic-gate 			    mntp->mnt_mountp,
4937c478bd9Sstevel@tonic-gate 			    dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
4947c478bd9Sstevel@tonic-gate 			    ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
495bfa62c28SVallish Vaidyeshwara 			    "s" : ""));
4967c478bd9Sstevel@tonic-gate 		}
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
500d1a180b0Smaheshvs static void
heading(uid_t uid,char * name)501d1a180b0Smaheshvs heading(uid_t uid, char *name)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	printf("Disk quotas for %s (uid %ld):\n", name, (long)uid);
5047c478bd9Sstevel@tonic-gate 	printf("%-12s %7s%7s%7s%12s%7s%7s%7s%12s\n",
505bfa62c28SVallish Vaidyeshwara 	    "Filesystem",
506bfa62c28SVallish Vaidyeshwara 	    "usage",
507bfa62c28SVallish Vaidyeshwara 	    "quota",
508bfa62c28SVallish Vaidyeshwara 	    "limit",
509bfa62c28SVallish Vaidyeshwara 	    "timeleft",
510bfa62c28SVallish Vaidyeshwara 	    "files",
511bfa62c28SVallish Vaidyeshwara 	    "quota",
512bfa62c28SVallish Vaidyeshwara 	    "limit",
513bfa62c28SVallish Vaidyeshwara 	    "timeleft");
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
516d1a180b0Smaheshvs static void
prquota(struct mnttab * mntp,struct dqblk * dqp)517d1a180b0Smaheshvs prquota(struct mnttab *mntp, struct dqblk *dqp)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	struct timeval tv;
5207c478bd9Sstevel@tonic-gate 	char ftimeleft[80], btimeleft[80];
5217c478bd9Sstevel@tonic-gate 	char *cp;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	time(&(tv.tv_sec));
5247c478bd9Sstevel@tonic-gate 	tv.tv_usec = 0;
5257c478bd9Sstevel@tonic-gate 	if (dqp->dqb_bsoftlimit && dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
5267c478bd9Sstevel@tonic-gate 		if (dqp->dqb_btimelimit == 0) {
527edea4b55SLin Ling 			strlcpy(btimeleft, "NOT STARTED", sizeof (btimeleft));
5287c478bd9Sstevel@tonic-gate 		} else if (dqp->dqb_btimelimit > tv.tv_sec) {
5297c478bd9Sstevel@tonic-gate 			fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
5307c478bd9Sstevel@tonic-gate 		} else {
531edea4b55SLin Ling 			strlcpy(btimeleft, "EXPIRED", sizeof (btimeleft));
5327c478bd9Sstevel@tonic-gate 		}
5337c478bd9Sstevel@tonic-gate 	} else {
5347c478bd9Sstevel@tonic-gate 		btimeleft[0] = '\0';
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate 	if (dqp->dqb_fsoftlimit && dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
5377c478bd9Sstevel@tonic-gate 		if (dqp->dqb_ftimelimit == 0) {
538edea4b55SLin Ling 			strlcpy(ftimeleft, "NOT STARTED", sizeof (ftimeleft));
5397c478bd9Sstevel@tonic-gate 		} else if (dqp->dqb_ftimelimit > tv.tv_sec) {
5407c478bd9Sstevel@tonic-gate 			fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
5417c478bd9Sstevel@tonic-gate 		} else {
542edea4b55SLin Ling 			strlcpy(ftimeleft, "EXPIRED", sizeof (ftimeleft));
5437c478bd9Sstevel@tonic-gate 		}
5447c478bd9Sstevel@tonic-gate 	} else {
5457c478bd9Sstevel@tonic-gate 		ftimeleft[0] = '\0';
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	if (strlen(mntp->mnt_mountp) > 12) {
5487c478bd9Sstevel@tonic-gate 		printf("%s\n", mntp->mnt_mountp);
5497c478bd9Sstevel@tonic-gate 		cp = "";
5507c478bd9Sstevel@tonic-gate 	} else {
5517c478bd9Sstevel@tonic-gate 		cp = mntp->mnt_mountp;
5527c478bd9Sstevel@tonic-gate 	}
553edea4b55SLin Ling 
554edea4b55SLin Ling 	if (dqp->dqb_curfiles == 0 &&
555edea4b55SLin Ling 	    dqp->dqb_fsoftlimit == 0 && dqp->dqb_fhardlimit == 0) {
556edea4b55SLin Ling 		printf("%-12.12s %7d %6d %6d %11s %6s %6s %6s %11s\n",
557edea4b55SLin Ling 		    cp,
558edea4b55SLin Ling 		    kb(dqp->dqb_curblocks),
559edea4b55SLin Ling 		    kb(dqp->dqb_bsoftlimit),
560edea4b55SLin Ling 		    kb(dqp->dqb_bhardlimit),
561edea4b55SLin Ling 		    "-",
562edea4b55SLin Ling 		    "-",
563edea4b55SLin Ling 		    "-",
564edea4b55SLin Ling 		    "-",
565edea4b55SLin Ling 		    "-");
566edea4b55SLin Ling 	} else {
567edea4b55SLin Ling 		printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n",
568edea4b55SLin Ling 		    cp,
569edea4b55SLin Ling 		    kb(dqp->dqb_curblocks),
570edea4b55SLin Ling 		    kb(dqp->dqb_bsoftlimit),
571edea4b55SLin Ling 		    kb(dqp->dqb_bhardlimit),
572edea4b55SLin Ling 		    btimeleft,
573edea4b55SLin Ling 		    dqp->dqb_curfiles,
574edea4b55SLin Ling 		    dqp->dqb_fsoftlimit,
575edea4b55SLin Ling 		    dqp->dqb_fhardlimit,
576edea4b55SLin Ling 		    ftimeleft);
577edea4b55SLin Ling 	}
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
580d1a180b0Smaheshvs static void
fmttime(char * buf,long time)581d1a180b0Smaheshvs fmttime(char *buf, long time)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	int i;
5847c478bd9Sstevel@tonic-gate 	static struct {
5857c478bd9Sstevel@tonic-gate 		int c_secs;		/* conversion units in secs */
5867c478bd9Sstevel@tonic-gate 		char *c_str;		/* unit string */
5877c478bd9Sstevel@tonic-gate 	} cunits [] = {
5887c478bd9Sstevel@tonic-gate 		{60*60*24*28, "months"},
5897c478bd9Sstevel@tonic-gate 		{60*60*24*7, "weeks"},
5907c478bd9Sstevel@tonic-gate 		{60*60*24, "days"},
5917c478bd9Sstevel@tonic-gate 		{60*60, "hours"},
5927c478bd9Sstevel@tonic-gate 		{60, "mins"},
5937c478bd9Sstevel@tonic-gate 		{1, "secs"}
5947c478bd9Sstevel@tonic-gate 	};
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	if (time <= 0) {
597edea4b55SLin Ling 		strlcpy(buf, "EXPIRED", sizeof (*buf));
5987c478bd9Sstevel@tonic-gate 		return;
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cunits)/sizeof (cunits[0]); i++) {
6017c478bd9Sstevel@tonic-gate 		if (time >= cunits[i].c_secs)
6027c478bd9Sstevel@tonic-gate 			break;
6037c478bd9Sstevel@tonic-gate 	}
604edea4b55SLin Ling 	snprintf(buf, sizeof (*buf), "%.1f %s",
605edea4b55SLin Ling 	    (double)time/cunits[i].c_secs, cunits[i].c_str);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate 
608d1a180b0Smaheshvs int
alldigits(char * s)609d1a180b0Smaheshvs alldigits(char *s)
6107c478bd9Sstevel@tonic-gate {
611d1a180b0Smaheshvs 	int c;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	c = *s++;
6147c478bd9Sstevel@tonic-gate 	do {
6157c478bd9Sstevel@tonic-gate 		if (!isdigit(c))
6167c478bd9Sstevel@tonic-gate 			return (0);
6177c478bd9Sstevel@tonic-gate 	} while (c = *s++);
6187c478bd9Sstevel@tonic-gate 	return (1);
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate int
getdiskquota(struct mnttab * mntp,uid_t uid,struct dqblk * dqp)622d1a180b0Smaheshvs getdiskquota(struct mnttab *mntp, uid_t uid, struct dqblk *dqp)
6237c478bd9Sstevel@tonic-gate {
6247c478bd9Sstevel@tonic-gate 	int fd;
6257c478bd9Sstevel@tonic-gate 	dev_t fsdev;
6267c478bd9Sstevel@tonic-gate 	struct stat64 statb;
6277c478bd9Sstevel@tonic-gate 	char qfilename[MAXPATHLEN];
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	if (stat64(mntp->mnt_special, &statb) < 0 ||
6307c478bd9Sstevel@tonic-gate 	    (statb.st_mode & S_IFMT) != S_IFBLK)
6317c478bd9Sstevel@tonic-gate 		return (0);
6327c478bd9Sstevel@tonic-gate 	fsdev = statb.st_rdev;
6337c478bd9Sstevel@tonic-gate 	(void) snprintf(qfilename, sizeof (qfilename), "%s/%s",
634bfa62c28SVallish Vaidyeshwara 	    mntp->mnt_mountp, QFNAME);
6357c478bd9Sstevel@tonic-gate 	if (stat64(qfilename, &statb) < 0 || statb.st_dev != fsdev)
6367c478bd9Sstevel@tonic-gate 		return (0);
637fabd6b6fSabalfour 	(void) __priv_bracket(PRIV_ON);
638fabd6b6fSabalfour 	fd = open64(qfilename, O_RDONLY);
639fabd6b6fSabalfour 	(void) __priv_bracket(PRIV_OFF);
640fabd6b6fSabalfour 	if (fd < 0)
6417c478bd9Sstevel@tonic-gate 		return (0);
6427c478bd9Sstevel@tonic-gate 	(void) llseek(fd, (offset_t)dqoff(uid), L_SET);
6437c478bd9Sstevel@tonic-gate 	switch (read(fd, dqp, sizeof (struct dqblk))) {
6447c478bd9Sstevel@tonic-gate 	case 0:				/* EOF */
6457c478bd9Sstevel@tonic-gate 		/*
6467c478bd9Sstevel@tonic-gate 		 * Convert implicit 0 quota (EOF)
6477c478bd9Sstevel@tonic-gate 		 * into an explicit one (zero'ed dqblk).
6487c478bd9Sstevel@tonic-gate 		 */
6497c478bd9Sstevel@tonic-gate 		memset((caddr_t)dqp, 0, sizeof (struct dqblk));
6507c478bd9Sstevel@tonic-gate 		break;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	case sizeof (struct dqblk):	/* OK */
6537c478bd9Sstevel@tonic-gate 		break;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	default:			/* ERROR */
6567c478bd9Sstevel@tonic-gate 		close(fd);
6577c478bd9Sstevel@tonic-gate 		return (0);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 	close(fd);
6607c478bd9Sstevel@tonic-gate 	return (1);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
663d1a180b0Smaheshvs int
quotactl(int cmd,char * mountp,uid_t uid,caddr_t addr)664d1a180b0Smaheshvs quotactl(int cmd, char *mountp, uid_t uid, caddr_t addr)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	int		fd;
6677c478bd9Sstevel@tonic-gate 	int		status;
6687c478bd9Sstevel@tonic-gate 	struct quotctl	quota;
6697c478bd9Sstevel@tonic-gate 	char		qfile[MAXPATHLEN];
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	FILE		*fstab;
6727c478bd9Sstevel@tonic-gate 	struct mnttab	mnt;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	if ((mountp == NULL) && (cmd == Q_ALLSYNC)) {
6767c478bd9Sstevel@tonic-gate 	/*
6777c478bd9Sstevel@tonic-gate 	 * Find the mount point of any mounted file system. This is
6787c478bd9Sstevel@tonic-gate 	 * because the ioctl that implements the quotactl call has
6797c478bd9Sstevel@tonic-gate 	 * to go to a real file, and not to the block device.
6807c478bd9Sstevel@tonic-gate 	 */
6817c478bd9Sstevel@tonic-gate 		if ((fstab = fopen(MNTTAB, "r")) == NULL) {
6827c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: ", MNTTAB);
6837c478bd9Sstevel@tonic-gate 			perror("open");
684edea4b55SLin Ling 			zexit(32);
6857c478bd9Sstevel@tonic-gate 		}
6867c478bd9Sstevel@tonic-gate 		fd = -1;
687*8509e9caSToomas Soome 		while ((status = getmntent(fstab, &mnt)) == 0) {
6887c478bd9Sstevel@tonic-gate 			if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0 ||
689bfa62c28SVallish Vaidyeshwara 			    hasopt(MNTOPT_RO, mnt.mnt_mntopts))
6907c478bd9Sstevel@tonic-gate 				continue;
6917c478bd9Sstevel@tonic-gate 			if ((strlcpy(qfile, mnt.mnt_mountp,
692bfa62c28SVallish Vaidyeshwara 			    sizeof (qfile)) >= sizeof (qfile)) ||
6937c478bd9Sstevel@tonic-gate 			    (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >=
694bfa62c28SVallish Vaidyeshwara 			    sizeof (qfile))) {
6957c478bd9Sstevel@tonic-gate 				continue;
6967c478bd9Sstevel@tonic-gate 			}
697fabd6b6fSabalfour 			(void) __priv_bracket(PRIV_ON);
698fabd6b6fSabalfour 			fd = open64(qfile, O_RDONLY);
699fabd6b6fSabalfour 			(void) __priv_bracket(PRIV_OFF);
700fabd6b6fSabalfour 			if (fd != -1)
7017c478bd9Sstevel@tonic-gate 				break;
7027c478bd9Sstevel@tonic-gate 		}
7037c478bd9Sstevel@tonic-gate 		fclose(fstab);
7047c478bd9Sstevel@tonic-gate 		if (fd == -1) {
7057c478bd9Sstevel@tonic-gate 			errno = ENOENT;
7067c478bd9Sstevel@tonic-gate 			return (-1);
7077c478bd9Sstevel@tonic-gate 		}
7087c478bd9Sstevel@tonic-gate 	} else {
7097c478bd9Sstevel@tonic-gate 		if (mountp == NULL || mountp[0] == '\0') {
7107c478bd9Sstevel@tonic-gate 			errno = ENOENT;
7117c478bd9Sstevel@tonic-gate 			return (-1);
7127c478bd9Sstevel@tonic-gate 		}
7137c478bd9Sstevel@tonic-gate 		if ((strlcpy(qfile, mountp, sizeof (qfile)) >= sizeof
714bfa62c28SVallish Vaidyeshwara 		    (qfile)) ||
7157c478bd9Sstevel@tonic-gate 		    (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >= sizeof
716bfa62c28SVallish Vaidyeshwara 		    (qfile))) {
7177c478bd9Sstevel@tonic-gate 			errno = ENOENT;
7187c478bd9Sstevel@tonic-gate 			return (-1);
7197c478bd9Sstevel@tonic-gate 		}
720fabd6b6fSabalfour 		(void) __priv_bracket(PRIV_ON);
721fabd6b6fSabalfour 		fd = open64(qfile, O_RDONLY);
722fabd6b6fSabalfour 		(void) __priv_bracket(PRIV_OFF);
723fabd6b6fSabalfour 		if (fd < 0)
7247c478bd9Sstevel@tonic-gate 			return (-1);
7257c478bd9Sstevel@tonic-gate 	}	/* else */
7267c478bd9Sstevel@tonic-gate 	quota.op = cmd;
7277c478bd9Sstevel@tonic-gate 	quota.uid = uid;
7287c478bd9Sstevel@tonic-gate 	quota.addr = addr;
7297c478bd9Sstevel@tonic-gate 	status = ioctl(fd, Q_QUOTACTL, &quota);
7307c478bd9Sstevel@tonic-gate 	if (fd != 0)
7317c478bd9Sstevel@tonic-gate 		close(fd);
7327c478bd9Sstevel@tonic-gate 	return (status);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate  * Return 1 if opt appears in optlist
7387c478bd9Sstevel@tonic-gate  */
7397c478bd9Sstevel@tonic-gate int
hasopt(char * opt,char * optlist)740d1a180b0Smaheshvs hasopt(char *opt, char *optlist)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate 	char *value;
7437c478bd9Sstevel@tonic-gate 	char *opts[2];
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	opts[0] = opt;
7467c478bd9Sstevel@tonic-gate 	opts[1] = NULL;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	if (optlist == NULL)
7497c478bd9Sstevel@tonic-gate 		return (0);
7507c478bd9Sstevel@tonic-gate 	while (*optlist != '\0') {
7517c478bd9Sstevel@tonic-gate 		if (getsubopt(&optlist, opts, &value) == 0)
7527c478bd9Sstevel@tonic-gate 			return (1);
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 	return (0);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate 
757bfa62c28SVallish Vaidyeshwara /*
758bfa62c28SVallish Vaidyeshwara  * If there are no quotas available, then getnfsquota() returns
759bfa62c28SVallish Vaidyeshwara  * RPC_SYSTEMERROR to caller.
760bfa62c28SVallish Vaidyeshwara  */
7617c478bd9Sstevel@tonic-gate static int
getnfsquota(char * hostp,char * path,uid_t uid,struct dqblk * dqp)7627c478bd9Sstevel@tonic-gate getnfsquota(char *hostp, char *path, uid_t uid, struct dqblk *dqp)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	struct getquota_args gq_args;
7657c478bd9Sstevel@tonic-gate 	struct getquota_rslt gq_rslt;
7667c478bd9Sstevel@tonic-gate 	struct rquota *rquota;
7677c478bd9Sstevel@tonic-gate 	extern char *strchr();
768bfa62c28SVallish Vaidyeshwara 	int	rpc_err;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	gq_args.gqa_pathp = path;
7717c478bd9Sstevel@tonic-gate 	gq_args.gqa_uid = uid;
772bfa62c28SVallish Vaidyeshwara 	rpc_err = callaurpc(hostp, RQUOTAPROG, RQUOTAVERS,
7737c478bd9Sstevel@tonic-gate 	    (vflag? RQUOTAPROC_GETQUOTA: RQUOTAPROC_GETACTIVEQUOTA),
774bfa62c28SVallish Vaidyeshwara 	    xdr_getquota_args, &gq_args, xdr_getquota_rslt, &gq_rslt);
775bfa62c28SVallish Vaidyeshwara 	if (rpc_err != RPC_SUCCESS) {
776bfa62c28SVallish Vaidyeshwara 		return (rpc_err);
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 	switch (gq_rslt.status) {
7797c478bd9Sstevel@tonic-gate 	case Q_OK:
7807c478bd9Sstevel@tonic-gate 		{
7817c478bd9Sstevel@tonic-gate 		struct timeval tv;
7827c478bd9Sstevel@tonic-gate 		u_longlong_t limit;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 		rquota = &gq_rslt.getquota_rslt_u.gqr_rquota;
7857c478bd9Sstevel@tonic-gate 
786bfa62c28SVallish Vaidyeshwara 		if (!vflag && rquota->rq_active == FALSE) {
787bfa62c28SVallish Vaidyeshwara 			return (RPC_SYSTEMERROR);
788bfa62c28SVallish Vaidyeshwara 		}
7897c478bd9Sstevel@tonic-gate 		gettimeofday(&tv, NULL);
7907c478bd9Sstevel@tonic-gate 		limit = (u_longlong_t)(rquota->rq_bhardlimit) *
7917c478bd9Sstevel@tonic-gate 		    rquota->rq_bsize / DEV_BSIZE;
7927c478bd9Sstevel@tonic-gate 		dqp->dqb_bhardlimit = limit;
7937c478bd9Sstevel@tonic-gate 		limit = (u_longlong_t)(rquota->rq_bsoftlimit) *
7947c478bd9Sstevel@tonic-gate 		    rquota->rq_bsize / DEV_BSIZE;
7957c478bd9Sstevel@tonic-gate 		dqp->dqb_bsoftlimit = limit;
7967c478bd9Sstevel@tonic-gate 		limit = (u_longlong_t)(rquota->rq_curblocks) *
7977c478bd9Sstevel@tonic-gate 		    rquota->rq_bsize / DEV_BSIZE;
7987c478bd9Sstevel@tonic-gate 		dqp->dqb_curblocks = limit;
7997c478bd9Sstevel@tonic-gate 		dqp->dqb_fhardlimit = rquota->rq_fhardlimit;
8007c478bd9Sstevel@tonic-gate 		dqp->dqb_fsoftlimit = rquota->rq_fsoftlimit;
8017c478bd9Sstevel@tonic-gate 		dqp->dqb_curfiles = rquota->rq_curfiles;
8027c478bd9Sstevel@tonic-gate 		dqp->dqb_btimelimit =
8037c478bd9Sstevel@tonic-gate 		    tv.tv_sec + rquota->rq_btimeleft;
8047c478bd9Sstevel@tonic-gate 		dqp->dqb_ftimelimit =
8057c478bd9Sstevel@tonic-gate 		    tv.tv_sec + rquota->rq_ftimeleft;
806bfa62c28SVallish Vaidyeshwara 		return (RPC_SUCCESS);
8077c478bd9Sstevel@tonic-gate 		}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	case Q_NOQUOTA:
810bfa62c28SVallish Vaidyeshwara 		return (RPC_SYSTEMERROR);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	case Q_EPERM:
8137c478bd9Sstevel@tonic-gate 		fprintf(stderr, "quota permission error, host: %s\n", hostp);
814bfa62c28SVallish Vaidyeshwara 		return (RPC_AUTHERROR);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	default:
8177c478bd9Sstevel@tonic-gate 		fprintf(stderr, "bad rpc result, host: %s\n",  hostp);
818bfa62c28SVallish Vaidyeshwara 		return (RPC_CANTDECODEARGS);
8197c478bd9Sstevel@tonic-gate 	}
820bfa62c28SVallish Vaidyeshwara 
821bfa62c28SVallish Vaidyeshwara 	/* NOTREACHED */
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate 
824d1a180b0Smaheshvs int
callaurpc(char * host,int prognum,int versnum,int procnum,xdrproc_t inproc,char * in,xdrproc_t outproc,char * out)825d1a180b0Smaheshvs callaurpc(char *host, int prognum, int versnum, int procnum,
826*8509e9caSToomas Soome     xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 	static enum clnt_stat clnt_stat;
829bfa62c28SVallish Vaidyeshwara 	struct timeval tottimeout = {20, 0};
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	static CLIENT *cl = NULL;
8327c478bd9Sstevel@tonic-gate 	static int oldprognum, oldversnum;
8337c478bd9Sstevel@tonic-gate 	static char oldhost[MAXHOSTNAMELEN+1];
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	/*
8367c478bd9Sstevel@tonic-gate 	 * Cache the client handle in case there are lots
8377c478bd9Sstevel@tonic-gate 	 * of entries in the /etc/mnttab for the same
8387c478bd9Sstevel@tonic-gate 	 * server. If the server returns an error, don't
8397c478bd9Sstevel@tonic-gate 	 * make further calls.
8407c478bd9Sstevel@tonic-gate 	 */
8417c478bd9Sstevel@tonic-gate 	if (cl == NULL || oldprognum != prognum || oldversnum != versnum ||
842bfa62c28SVallish Vaidyeshwara 	    strcmp(oldhost, host) != 0) {
8437c478bd9Sstevel@tonic-gate 		if (cl) {
8447c478bd9Sstevel@tonic-gate 			clnt_destroy(cl);
8457c478bd9Sstevel@tonic-gate 			cl = NULL;
8467c478bd9Sstevel@tonic-gate 		}
847bfa62c28SVallish Vaidyeshwara 		cl = clnt_create_timed(host, prognum, versnum, "udp",
848bfa62c28SVallish Vaidyeshwara 		    &tottimeout);
8497c478bd9Sstevel@tonic-gate 		if (cl == NULL)
8507c478bd9Sstevel@tonic-gate 			return ((int)RPC_TIMEDOUT);
8517c478bd9Sstevel@tonic-gate 		if ((cl->cl_auth = authunix_create_default()) == NULL) {
8527c478bd9Sstevel@tonic-gate 			clnt_destroy(cl);
8537c478bd9Sstevel@tonic-gate 			return (RPC_CANTSEND);
8547c478bd9Sstevel@tonic-gate 		}
8557c478bd9Sstevel@tonic-gate 		oldprognum = prognum;
8567c478bd9Sstevel@tonic-gate 		oldversnum = versnum;
857edea4b55SLin Ling 		(void) strlcpy(oldhost, host, sizeof (oldhost));
8587c478bd9Sstevel@tonic-gate 		clnt_stat = RPC_SUCCESS;
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	if (clnt_stat != RPC_SUCCESS)
8627c478bd9Sstevel@tonic-gate 		return ((int)clnt_stat);	/* don't bother retrying */
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	clnt_stat = clnt_call(cl, procnum, inproc, in,
8657c478bd9Sstevel@tonic-gate 	    outproc, out, tottimeout);
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	return ((int)clnt_stat);
8687c478bd9Sstevel@tonic-gate }
869edea4b55SLin Ling 
870edea4b55SLin Ling static int
getzfsquota(char * user,char * dataset,struct dqblk * zq)871edea4b55SLin Ling getzfsquota(char *user, char *dataset, struct dqblk *zq)
872edea4b55SLin Ling {
873edea4b55SLin Ling 	zfs_handle_t *zhp = NULL;
874edea4b55SLin Ling 	char propname[ZFS_MAXPROPLEN];
875edea4b55SLin Ling 	uint64_t userquota, userused;
876edea4b55SLin Ling 
877edea4b55SLin Ling 	if (g_zfs == NULL)
878edea4b55SLin Ling 		return (1);
879edea4b55SLin Ling 
880edea4b55SLin Ling 	if ((zhp = _zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
881edea4b55SLin Ling 		return (1);
882edea4b55SLin Ling 
883edea4b55SLin Ling 	(void) snprintf(propname, sizeof (propname), "userquota@%s", user);
884edea4b55SLin Ling 	if (_zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
885edea4b55SLin Ling 		_zfs_close(zhp);
886edea4b55SLin Ling 		return (1);
887edea4b55SLin Ling 	}
888edea4b55SLin Ling 
889edea4b55SLin Ling 	(void) snprintf(propname, sizeof (propname), "userused@%s", user);
890edea4b55SLin Ling 	if (_zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
891edea4b55SLin Ling 		_zfs_close(zhp);
892edea4b55SLin Ling 		return (1);
893edea4b55SLin Ling 	}
894edea4b55SLin Ling 
895edea4b55SLin Ling 	zq->dqb_bhardlimit = userquota / DEV_BSIZE;
896edea4b55SLin Ling 	zq->dqb_bsoftlimit = userquota / DEV_BSIZE;
897edea4b55SLin Ling 	zq->dqb_curblocks = userused / DEV_BSIZE;
898edea4b55SLin Ling 	_zfs_close(zhp);
899edea4b55SLin Ling 	return (0);
900edea4b55SLin Ling }
901edea4b55SLin Ling 
902edea4b55SLin Ling static void
zexit(int n)903edea4b55SLin Ling zexit(int n)
904edea4b55SLin Ling {
905edea4b55SLin Ling 	if (g_zfs != NULL)
906edea4b55SLin Ling 		_libzfs_fini(g_zfs);
907edea4b55SLin Ling 	exit(n);
908edea4b55SLin Ling }
909