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 */
277c478bd9Sstevel@tonic-gate /* 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,
147fabd6b6fSabalfour NULL) == -1) {
148fabd6b6fSabalfour (void) fprintf(stderr,
149fabd6b6fSabalfour gettext("Insufficient privileges, "
150fabd6b6fSabalfour "quota must be set-uid root or have "
151fabd6b6fSabalfour "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");
2677c478bd9Sstevel@tonic-gate while (getmntent(mtab, &mnt) == NULL) {
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,
2757c478bd9Sstevel@tonic-gate mnt.mnt_mountp, uid, &dqblk) != 0 &&
2767c478bd9Sstevel@tonic-gate !(vflag && getdiskquota(&mnt, uid, &dqblk))))
2777c478bd9Sstevel@tonic-gate 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')) {
292*834b3a43SRichard Lowe mntopt += strcspn(mntopt, "=") + 1;
293*834b3a43SRichard 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 &&
4457c478bd9Sstevel@tonic-gate 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 &&
4487c478bd9Sstevel@tonic-gate 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 ?
4787c478bd9Sstevel@tonic-gate "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 ?
4887c478bd9Sstevel@tonic-gate "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 ?
4957c478bd9Sstevel@tonic-gate "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",
5057c478bd9Sstevel@tonic-gate "Filesystem",
5067c478bd9Sstevel@tonic-gate "usage",
5077c478bd9Sstevel@tonic-gate "quota",
5087c478bd9Sstevel@tonic-gate "limit",
5097c478bd9Sstevel@tonic-gate "timeleft",
5107c478bd9Sstevel@tonic-gate "files",
5117c478bd9Sstevel@tonic-gate "quota",
5127c478bd9Sstevel@tonic-gate "limit",
5137c478bd9Sstevel@tonic-gate "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 {
5677c478bd9Sstevel@tonic-gate printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n",
5687c478bd9Sstevel@tonic-gate cp,
5697c478bd9Sstevel@tonic-gate kb(dqp->dqb_curblocks),
5707c478bd9Sstevel@tonic-gate kb(dqp->dqb_bsoftlimit),
5717c478bd9Sstevel@tonic-gate kb(dqp->dqb_bhardlimit),
5727c478bd9Sstevel@tonic-gate btimeleft,
5737c478bd9Sstevel@tonic-gate dqp->dqb_curfiles,
5747c478bd9Sstevel@tonic-gate dqp->dqb_fsoftlimit,
5757c478bd9Sstevel@tonic-gate dqp->dqb_fhardlimit,
5767c478bd9Sstevel@tonic-gate ftimeleft);
5777c478bd9Sstevel@tonic-gate }
578edea4b55SLin Ling }
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",
6347c478bd9Sstevel@tonic-gate 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;
6877c478bd9Sstevel@tonic-gate while ((status = getmntent(fstab, &mnt)) == NULL) {
6887c478bd9Sstevel@tonic-gate if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) != 0 ||
6897c478bd9Sstevel@tonic-gate hasopt(MNTOPT_RO, mnt.mnt_mntopts))
6907c478bd9Sstevel@tonic-gate continue;
6917c478bd9Sstevel@tonic-gate if ((strlcpy(qfile, mnt.mnt_mountp,
6927c478bd9Sstevel@tonic-gate sizeof (qfile)) >= sizeof (qfile)) ||
6937c478bd9Sstevel@tonic-gate (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >=
6947c478bd9Sstevel@tonic-gate 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
7147c478bd9Sstevel@tonic-gate (qfile)) ||
7157c478bd9Sstevel@tonic-gate (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >= sizeof
7167c478bd9Sstevel@tonic-gate (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, "a);
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,
826d1a180b0Smaheshvs 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 ||
8427c478bd9Sstevel@tonic-gate 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