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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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