xref: /freebsd/usr.bin/quota/quota.c (revision 5e3934b1)
19b50d902SRodney W. Grimes /*
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1980, 1990, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
89b50d902SRodney W. Grimes  * Robert Elz at The University of Melbourne.
99b50d902SRodney W. Grimes  *
109b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
119b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
129b50d902SRodney W. Grimes  * are met:
139b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
149b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
159b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
169b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
179b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
199b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
209b50d902SRodney W. Grimes  *    without specific prior written permission.
219b50d902SRodney W. Grimes  *
229b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329b50d902SRodney W. Grimes  * SUCH DAMAGE.
339b50d902SRodney W. Grimes  */
349b50d902SRodney W. Grimes 
359b50d902SRodney W. Grimes /*
369b50d902SRodney W. Grimes  * Disk quota reporting program.
379b50d902SRodney W. Grimes  */
385e3934b1SWarner Losh 
399b50d902SRodney W. Grimes #include <sys/param.h>
409288f266SThomas Graichen #include <sys/types.h>
419b50d902SRodney W. Grimes #include <sys/file.h>
429b50d902SRodney W. Grimes #include <sys/stat.h>
439288f266SThomas Graichen #include <sys/mount.h>
449288f266SThomas Graichen #include <sys/socket.h>
45ff288009SMark Murray 
46ff288009SMark Murray #include <rpc/rpc.h>
47ff288009SMark Murray #include <rpc/pmap_prot.h>
48ff288009SMark Murray #include <rpcsvc/rquota.h>
49ff288009SMark Murray 
509b50d902SRodney W. Grimes #include <ufs/ufs/quota.h>
51ff288009SMark Murray 
529d63ad49SPhilippe Charnier #include <ctype.h>
539d63ad49SPhilippe Charnier #include <err.h>
549d63ad49SPhilippe Charnier #include <fstab.h>
559d63ad49SPhilippe Charnier #include <grp.h>
56478bf774SRuslan Ermilov #include <libutil.h>
57ff288009SMark Murray #include <netdb.h>
589d63ad49SPhilippe Charnier #include <pwd.h>
599b50d902SRodney W. Grimes #include <stdio.h>
602ffe6bbfSDavid Malone #include <stdint.h>
619288f266SThomas Graichen #include <stdlib.h>
629288f266SThomas Graichen #include <string.h>
632e1f5ad9SMike Pritchard #include <time.h>
6477ae30e9SAlexander Langer #include <unistd.h>
659b50d902SRodney W. Grimes 
66865ff609SEd Schouten static const char *qfextension[] = INITQFNAMES;
679b50d902SRodney W. Grimes 
689b50d902SRodney W. Grimes struct quotause {
699b50d902SRodney W. Grimes 	struct	quotause *next;
709b50d902SRodney W. Grimes 	long	flags;
719b50d902SRodney W. Grimes 	struct	dqblk dqblk;
729b50d902SRodney W. Grimes 	char	fsname[MAXPATHLEN + 1];
739288f266SThomas Graichen };
749b50d902SRodney W. Grimes 
75829b3f6bSDag-Erling Smørgrav static char *timeprt(int64_t seconds);
76d3cb5dedSWarner Losh static struct quotause *getprivs(long id, int quotatype);
771a7ac2bdSAlfonso Gregory static void usage(void) __dead2;
78dfaa8068SMike Pritchard static int showuid(u_long uid);
79dfaa8068SMike Pritchard static int showgid(u_long gid);
80dfaa8068SMike Pritchard static int showusrname(char *name);
81dfaa8068SMike Pritchard static int showgrpname(char *name);
82dfaa8068SMike Pritchard static int showquotas(int type, u_long id, const char *name);
832e1f5ad9SMike Pritchard static void showrawquotas(int type, u_long id, struct quotause *qup);
84ff288009SMark Murray static void heading(int type, u_long id, const char *name, const char *tag);
85ff288009SMark Murray static int getufsquota(struct fstab *fs, struct quotause *qup, long id,
86ff288009SMark Murray 	int quotatype);
87ff288009SMark Murray static int getnfsquota(struct statfs *fst, struct quotause *qup, long id,
88ff288009SMark Murray 	int quotatype);
89aad5531eSSean Eric Fagan static enum clnt_stat callaurpc(char *host, int prognum, int versnum, int procnum,
9077ae30e9SAlexander Langer 	xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
9177ae30e9SAlexander Langer static int alldigits(char *s);
929288f266SThomas Graichen 
93865ff609SEd Schouten static int	hflag;
94865ff609SEd Schouten static int	lflag;
95865ff609SEd Schouten static int	rflag;
96865ff609SEd Schouten static int	qflag;
97865ff609SEd Schouten static int	vflag;
98865ff609SEd Schouten static char	*filename = NULL;
999b50d902SRodney W. Grimes 
10077ae30e9SAlexander Langer int
main(int argc,char * argv[])101ff288009SMark Murray main(int argc, char *argv[])
1029b50d902SRodney W. Grimes {
1039288f266SThomas Graichen 	int ngroups;
10437ed8e48SKirk McKusick 	gid_t mygid, gidset[NGROUPS];
105dfaa8068SMike Pritchard 	int i, ch, gflag = 0, uflag = 0, errflag = 0;
1069b50d902SRodney W. Grimes 
1072e1f5ad9SMike Pritchard 	while ((ch = getopt(argc, argv, "f:ghlrquv")) != -1) {
1089b50d902SRodney W. Grimes 		switch(ch) {
1092e1f5ad9SMike Pritchard 		case 'f':
1102e1f5ad9SMike Pritchard 			filename = optarg;
1112e1f5ad9SMike Pritchard 			break;
1129b50d902SRodney W. Grimes 		case 'g':
1139b50d902SRodney W. Grimes 			gflag++;
1149b50d902SRodney W. Grimes 			break;
115478bf774SRuslan Ermilov 		case 'h':
116478bf774SRuslan Ermilov 			hflag++;
117478bf774SRuslan Ermilov 			break;
118e56990e4SIan Dowse 		case 'l':
119e56990e4SIan Dowse 			lflag++;
120e56990e4SIan Dowse 			break;
121e608ec61SIan Dowse 		case 'q':
122e608ec61SIan Dowse 			qflag++;
123e608ec61SIan Dowse 			break;
1242e1f5ad9SMike Pritchard 		case 'r':
1252e1f5ad9SMike Pritchard 			rflag++;
1262e1f5ad9SMike Pritchard 			break;
1279b50d902SRodney W. Grimes 		case 'u':
1289b50d902SRodney W. Grimes 			uflag++;
1299b50d902SRodney W. Grimes 			break;
1309b50d902SRodney W. Grimes 		case 'v':
1319b50d902SRodney W. Grimes 			vflag++;
1329b50d902SRodney W. Grimes 			break;
1339b50d902SRodney W. Grimes 		default:
1349b50d902SRodney W. Grimes 			usage();
1359b50d902SRodney W. Grimes 		}
1369b50d902SRodney W. Grimes 	}
1379b50d902SRodney W. Grimes 	argc -= optind;
1389b50d902SRodney W. Grimes 	argv += optind;
1399b50d902SRodney W. Grimes 	if (!uflag && !gflag)
1409b50d902SRodney W. Grimes 		uflag++;
1419b50d902SRodney W. Grimes 	if (argc == 0) {
1429b50d902SRodney W. Grimes 		if (uflag)
143dfaa8068SMike Pritchard 			errflag += showuid(getuid());
1449b50d902SRodney W. Grimes 		if (gflag) {
1459288f266SThomas Graichen 			mygid = getgid();
14637ed8e48SKirk McKusick 			ngroups = getgroups(NGROUPS, gidset);
1479d63ad49SPhilippe Charnier 			if (ngroups < 0)
1489d63ad49SPhilippe Charnier 				err(1, "getgroups");
149dfaa8068SMike Pritchard 			errflag += showgid(mygid);
1509288f266SThomas Graichen 			for (i = 0; i < ngroups; i++)
1519288f266SThomas Graichen 				if (gidset[i] != mygid)
152dfaa8068SMike Pritchard 					errflag += showgid(gidset[i]);
1539b50d902SRodney W. Grimes 		}
154dfaa8068SMike Pritchard 		return(errflag);
1559b50d902SRodney W. Grimes 	}
1569b50d902SRodney W. Grimes 	if (uflag && gflag)
1579b50d902SRodney W. Grimes 		usage();
1589b50d902SRodney W. Grimes 	if (uflag) {
1599b50d902SRodney W. Grimes 		for (; argc > 0; argc--, argv++) {
1609b50d902SRodney W. Grimes 			if (alldigits(*argv))
161dfaa8068SMike Pritchard 				errflag += showuid(atoi(*argv));
1629b50d902SRodney W. Grimes 			else
163dfaa8068SMike Pritchard 				errflag += showusrname(*argv);
1649b50d902SRodney W. Grimes 		}
165dfaa8068SMike Pritchard 		return(errflag);
1669b50d902SRodney W. Grimes 	}
1679b50d902SRodney W. Grimes 	if (gflag) {
1689b50d902SRodney W. Grimes 		for (; argc > 0; argc--, argv++) {
1699b50d902SRodney W. Grimes 			if (alldigits(*argv))
170dfaa8068SMike Pritchard 				errflag += showgid(atoi(*argv));
1719b50d902SRodney W. Grimes 			else
172dfaa8068SMike Pritchard 				errflag += showgrpname(*argv);
1739b50d902SRodney W. Grimes 		}
1749b50d902SRodney W. Grimes 	}
175dfaa8068SMike Pritchard 	return(errflag);
1769b50d902SRodney W. Grimes }
1779b50d902SRodney W. Grimes 
17877ae30e9SAlexander Langer static void
usage(void)179ff288009SMark Murray usage(void)
1809b50d902SRodney W. Grimes {
1819b50d902SRodney W. Grimes 
1829b50d902SRodney W. Grimes 	fprintf(stderr, "%s\n%s\n%s\n",
1832e1f5ad9SMike Pritchard 	    "usage: quota [-ghlu] [-f path] [-v | -q | -r]",
1842e1f5ad9SMike Pritchard 	    "       quota [-hlu] [-f path] [-v | -q | -r] user ...",
1852e1f5ad9SMike Pritchard 	    "       quota -g [-hl] [-f path] [-v | -q | -r] group ...");
1869b50d902SRodney W. Grimes 	exit(1);
1879b50d902SRodney W. Grimes }
1889b50d902SRodney W. Grimes 
1899b50d902SRodney W. Grimes /*
1909b50d902SRodney W. Grimes  * Print out quotas for a specified user identifier.
1919b50d902SRodney W. Grimes  */
192dfaa8068SMike Pritchard static int
showuid(u_long uid)193ff288009SMark Murray showuid(u_long uid)
1949b50d902SRodney W. Grimes {
1959b50d902SRodney W. Grimes 	struct passwd *pwd = getpwuid(uid);
196ff288009SMark Murray 	const char *name;
1979b50d902SRodney W. Grimes 
1989b50d902SRodney W. Grimes 	if (pwd == NULL)
1999b50d902SRodney W. Grimes 		name = "(no account)";
2009b50d902SRodney W. Grimes 	else
2019b50d902SRodney W. Grimes 		name = pwd->pw_name;
202dfaa8068SMike Pritchard 	return(showquotas(USRQUOTA, uid, name));
2039b50d902SRodney W. Grimes }
2049b50d902SRodney W. Grimes 
2059b50d902SRodney W. Grimes /*
20604389c85SGordon Bergling  * Print out quotas for a specified user name.
2079b50d902SRodney W. Grimes  */
208dfaa8068SMike Pritchard static int
showusrname(char * name)209ff288009SMark Murray showusrname(char *name)
2109b50d902SRodney W. Grimes {
2119b50d902SRodney W. Grimes 	struct passwd *pwd = getpwnam(name);
2129b50d902SRodney W. Grimes 
2139b50d902SRodney W. Grimes 	if (pwd == NULL) {
2149d63ad49SPhilippe Charnier 		warnx("%s: unknown user", name);
215dfaa8068SMike Pritchard 		return(1);
2169b50d902SRodney W. Grimes 	}
217dfaa8068SMike Pritchard 	return(showquotas(USRQUOTA, pwd->pw_uid, name));
2189b50d902SRodney W. Grimes }
2199b50d902SRodney W. Grimes 
2209b50d902SRodney W. Grimes /*
2219b50d902SRodney W. Grimes  * Print out quotas for a specified group identifier.
2229b50d902SRodney W. Grimes  */
223dfaa8068SMike Pritchard static int
showgid(u_long gid)224ff288009SMark Murray showgid(u_long gid)
2259b50d902SRodney W. Grimes {
2269b50d902SRodney W. Grimes 	struct group *grp = getgrgid(gid);
227ff288009SMark Murray 	const char *name;
2289b50d902SRodney W. Grimes 
2299b50d902SRodney W. Grimes 	if (grp == NULL)
2309b50d902SRodney W. Grimes 		name = "(no entry)";
2319b50d902SRodney W. Grimes 	else
2329b50d902SRodney W. Grimes 		name = grp->gr_name;
233dfaa8068SMike Pritchard 	return(showquotas(GRPQUOTA, gid, name));
2349b50d902SRodney W. Grimes }
2359b50d902SRodney W. Grimes 
2369b50d902SRodney W. Grimes /*
23704389c85SGordon Bergling  * Print out quotas for a specified group name.
2389b50d902SRodney W. Grimes  */
239dfaa8068SMike Pritchard static int
showgrpname(char * name)240ff288009SMark Murray showgrpname(char *name)
2419b50d902SRodney W. Grimes {
2429b50d902SRodney W. Grimes 	struct group *grp = getgrnam(name);
2439b50d902SRodney W. Grimes 
2449b50d902SRodney W. Grimes 	if (grp == NULL) {
2459d63ad49SPhilippe Charnier 		warnx("%s: unknown group", name);
246dfaa8068SMike Pritchard 		return(1);
2479b50d902SRodney W. Grimes 	}
248dfaa8068SMike Pritchard 	return(showquotas(GRPQUOTA, grp->gr_gid, name));
2499b50d902SRodney W. Grimes }
2509b50d902SRodney W. Grimes 
25177ae30e9SAlexander Langer static void
prthumanval(int len,u_int64_t bytes)25237ed8e48SKirk McKusick prthumanval(int len, u_int64_t bytes)
253478bf774SRuslan Ermilov {
254478bf774SRuslan Ermilov 	char buf[len + 1];
255478bf774SRuslan Ermilov 
2562f39985fSSergey Kandaurov 	/*
2572f39985fSSergey Kandaurov 	 * Limit the width to 5 bytes as that is what users expect.
2582f39985fSSergey Kandaurov 	 */
259a3010446SMarcelo Araujo 	humanize_number(buf, MIN(sizeof(buf), 5), bytes, "",
2602f39985fSSergey Kandaurov 			HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
261478bf774SRuslan Ermilov 
262478bf774SRuslan Ermilov 	(void)printf(" %*s", len, buf);
263478bf774SRuslan Ermilov }
264478bf774SRuslan Ermilov 
265dfaa8068SMike Pritchard static int
showquotas(int type,u_long id,const char * name)266ff288009SMark Murray showquotas(int type, u_long id, const char *name)
2679b50d902SRodney W. Grimes {
268ff288009SMark Murray 	struct quotause *qup;
2699288f266SThomas Graichen 	struct quotause *quplist;
270ff288009SMark Murray 	const char *msgi, *msgb;
271ff288009SMark Murray 	const char *nam;
272829b3f6bSDag-Erling Smørgrav 	char *bgrace = NULL, *igrace = NULL;
273dfaa8068SMike Pritchard 	int lines = 0, overquota = 0;
2749b50d902SRodney W. Grimes 	static time_t now;
2759b50d902SRodney W. Grimes 
2769b50d902SRodney W. Grimes 	if (now == 0)
2779b50d902SRodney W. Grimes 		time(&now);
2789b50d902SRodney W. Grimes 	quplist = getprivs(id, type);
2799b50d902SRodney W. Grimes 	for (qup = quplist; qup; qup = qup->next) {
280829b3f6bSDag-Erling Smørgrav 		msgi = NULL;
2819b50d902SRodney W. Grimes 		if (qup->dqblk.dqb_ihardlimit &&
282dfaa8068SMike Pritchard 		    qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) {
283dfaa8068SMike Pritchard 			overquota++;
2849b50d902SRodney W. Grimes 			msgi = "File limit reached on";
285dfaa8068SMike Pritchard 		}
2869b50d902SRodney W. Grimes 		else if (qup->dqblk.dqb_isoftlimit &&
287ff288009SMark Murray 		    qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) {
288dfaa8068SMike Pritchard 			overquota++;
2899b50d902SRodney W. Grimes 			if (qup->dqblk.dqb_itime > now)
2909b50d902SRodney W. Grimes 				msgi = "In file grace period on";
2919b50d902SRodney W. Grimes 			else
2929b50d902SRodney W. Grimes 				msgi = "Over file quota on";
293ff288009SMark Murray 		}
294829b3f6bSDag-Erling Smørgrav 		msgb = NULL;
2959b50d902SRodney W. Grimes 		if (qup->dqblk.dqb_bhardlimit &&
296dfaa8068SMike Pritchard 		    qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) {
297dfaa8068SMike Pritchard 			overquota++;
2989b50d902SRodney W. Grimes 			msgb = "Block limit reached on";
299dfaa8068SMike Pritchard 		}
3009b50d902SRodney W. Grimes 		else if (qup->dqblk.dqb_bsoftlimit &&
301ff288009SMark Murray 		    qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) {
302dfaa8068SMike Pritchard 			overquota++;
3039b50d902SRodney W. Grimes 			if (qup->dqblk.dqb_btime > now)
3049b50d902SRodney W. Grimes 				msgb = "In block grace period on";
3059b50d902SRodney W. Grimes 			else
3069b50d902SRodney W. Grimes 				msgb = "Over block quota on";
307ff288009SMark Murray 		}
3082e1f5ad9SMike Pritchard 		if (rflag) {
3092e1f5ad9SMike Pritchard 			showrawquotas(type, id, qup);
3102e1f5ad9SMike Pritchard 			continue;
3112e1f5ad9SMike Pritchard 		}
3122e1f5ad9SMike Pritchard 		if (!vflag &&
3132e1f5ad9SMike Pritchard 		    qup->dqblk.dqb_isoftlimit == 0 &&
3142e1f5ad9SMike Pritchard 		    qup->dqblk.dqb_ihardlimit == 0 &&
3152e1f5ad9SMike Pritchard 		    qup->dqblk.dqb_bsoftlimit == 0 &&
3162e1f5ad9SMike Pritchard 		    qup->dqblk.dqb_bhardlimit == 0)
3172e1f5ad9SMike Pritchard 			continue;
3189b50d902SRodney W. Grimes 		if (qflag) {
319829b3f6bSDag-Erling Smørgrav 			if ((msgi != NULL || msgb != NULL) &&
3209b50d902SRodney W. Grimes 			    lines++ == 0)
3219b50d902SRodney W. Grimes 				heading(type, id, name, "");
322829b3f6bSDag-Erling Smørgrav 			if (msgi != NULL)
3239b50d902SRodney W. Grimes 				printf("\t%s %s\n", msgi, qup->fsname);
324829b3f6bSDag-Erling Smørgrav 			if (msgb != NULL)
3259b50d902SRodney W. Grimes 				printf("\t%s %s\n", msgb, qup->fsname);
3269b50d902SRodney W. Grimes 			continue;
3279b50d902SRodney W. Grimes 		}
32837ed8e48SKirk McKusick 		if (!vflag &&
32937ed8e48SKirk McKusick 		    qup->dqblk.dqb_curblocks == 0 &&
33037ed8e48SKirk McKusick 		    qup->dqblk.dqb_curinodes == 0)
33137ed8e48SKirk McKusick 			continue;
3329b50d902SRodney W. Grimes 		if (lines++ == 0)
3339b50d902SRodney W. Grimes 			heading(type, id, name, "");
3349288f266SThomas Graichen 		nam = qup->fsname;
3359288f266SThomas Graichen 		if (strlen(qup->fsname) > 15) {
3369288f266SThomas Graichen 			printf("%s\n", qup->fsname);
3379288f266SThomas Graichen 			nam = "";
3389288f266SThomas Graichen 		}
33937ed8e48SKirk McKusick 		printf("%-15s", nam);
340478bf774SRuslan Ermilov 		if (hflag) {
34137ed8e48SKirk McKusick 			prthumanval(7, dbtob(qup->dqblk.dqb_curblocks));
342829b3f6bSDag-Erling Smørgrav 			printf("%c", (msgb == NULL) ? ' ' : '*');
34337ed8e48SKirk McKusick 			prthumanval(7, dbtob(qup->dqblk.dqb_bsoftlimit));
34437ed8e48SKirk McKusick 			prthumanval(7, dbtob(qup->dqblk.dqb_bhardlimit));
345478bf774SRuslan Ermilov 		} else {
34637ed8e48SKirk McKusick 			printf(" %7ju%c %7ju %7ju",
3472f39985fSSergey Kandaurov 			    (uintmax_t)dbtob(qup->dqblk.dqb_curblocks)
3482f39985fSSergey Kandaurov 				/ 1024,
349829b3f6bSDag-Erling Smørgrav 			    (msgb == NULL) ? ' ' : '*',
3502f39985fSSergey Kandaurov 			    (uintmax_t)dbtob(qup->dqblk.dqb_bsoftlimit)
3512f39985fSSergey Kandaurov 				/ 1024,
3522f39985fSSergey Kandaurov 			    (uintmax_t)dbtob(qup->dqblk.dqb_bhardlimit)
3532f39985fSSergey Kandaurov 				/ 1024);
354478bf774SRuslan Ermilov 		}
355f5374712SMike Pritchard 		if (msgb != NULL)
356829b3f6bSDag-Erling Smørgrav 			bgrace = timeprt(qup->dqblk.dqb_btime);
357f5374712SMike Pritchard 		if (msgi != NULL)
358829b3f6bSDag-Erling Smørgrav 			igrace = timeprt(qup->dqblk.dqb_itime);
35937ed8e48SKirk McKusick 		printf("%8s %6ju%c %6ju %6ju%8s\n"
360829b3f6bSDag-Erling Smørgrav 			, (msgb == NULL) ? "" : bgrace
36137ed8e48SKirk McKusick 			, (uintmax_t)qup->dqblk.dqb_curinodes
362829b3f6bSDag-Erling Smørgrav 			, (msgi == NULL) ? ' ' : '*'
36337ed8e48SKirk McKusick 			, (uintmax_t)qup->dqblk.dqb_isoftlimit
36437ed8e48SKirk McKusick 			, (uintmax_t)qup->dqblk.dqb_ihardlimit
365829b3f6bSDag-Erling Smørgrav 			, (msgi == NULL) ? "" : igrace
3669b50d902SRodney W. Grimes 		);
367829b3f6bSDag-Erling Smørgrav 		if (msgb != NULL)
368f5374712SMike Pritchard 			free(bgrace);
369829b3f6bSDag-Erling Smørgrav 		if (msgi != NULL)
370f5374712SMike Pritchard 			free(igrace);
3719b50d902SRodney W. Grimes 	}
3722e1f5ad9SMike Pritchard 	if (!qflag && !rflag && lines == 0)
3739b50d902SRodney W. Grimes 		heading(type, id, name, "none");
374dfaa8068SMike Pritchard 	return (overquota);
3759b50d902SRodney W. Grimes }
3769b50d902SRodney W. Grimes 
37777ae30e9SAlexander Langer static void
showrawquotas(int type,u_long id,struct quotause * qup)37861328d7aSXin LI showrawquotas(int type, u_long id, struct quotause *qup)
3792e1f5ad9SMike Pritchard {
380829b3f6bSDag-Erling Smørgrav 	time_t t;
38137ed8e48SKirk McKusick 
3822e1f5ad9SMike Pritchard 	printf("Raw %s quota information for id %lu on %s\n",
3832e1f5ad9SMike Pritchard 	    type == USRQUOTA ? "user" : "group", id, qup->fsname);
38437ed8e48SKirk McKusick 	printf("block hard limit:     %ju\n",
38537ed8e48SKirk McKusick 	    (uintmax_t)qup->dqblk.dqb_bhardlimit);
38637ed8e48SKirk McKusick 	printf("block soft limit:     %ju\n",
38737ed8e48SKirk McKusick 	    (uintmax_t)qup->dqblk.dqb_bsoftlimit);
38837ed8e48SKirk McKusick 	printf("current block count:  %ju\n",
38937ed8e48SKirk McKusick 	    (uintmax_t)qup->dqblk.dqb_curblocks);
39037ed8e48SKirk McKusick 	printf("i-node hard limit:    %ju\n",
39137ed8e48SKirk McKusick 	    (uintmax_t)qup->dqblk.dqb_ihardlimit);
39237ed8e48SKirk McKusick 	printf("i-node soft limit:    %ju\n",
39337ed8e48SKirk McKusick 	    (uintmax_t)qup->dqblk.dqb_isoftlimit);
39437ed8e48SKirk McKusick 	printf("current i-node count: %ju\n",
39537ed8e48SKirk McKusick 	    (uintmax_t)qup->dqblk.dqb_curinodes);
39637ed8e48SKirk McKusick 	printf("block grace time:     %jd",
39737ed8e48SKirk McKusick 	    (intmax_t)qup->dqblk.dqb_btime);
398049aa2e8SOlivier Houchard 	if (qup->dqblk.dqb_btime != 0) {
399829b3f6bSDag-Erling Smørgrav 		t = qup->dqblk.dqb_btime;
400829b3f6bSDag-Erling Smørgrav 		printf(" %s", ctime(&t));
40137ed8e48SKirk McKusick 	} else {
4022e1f5ad9SMike Pritchard 		printf("\n");
40337ed8e48SKirk McKusick 	}
4042ffe6bbfSDavid Malone 	printf("i-node grace time:    %jd", (intmax_t)qup->dqblk.dqb_itime);
405049aa2e8SOlivier Houchard 	if (qup->dqblk.dqb_itime != 0) {
406829b3f6bSDag-Erling Smørgrav 		t = qup->dqblk.dqb_itime;
407829b3f6bSDag-Erling Smørgrav 		printf(" %s", ctime(&t));
40837ed8e48SKirk McKusick 	} else {
4092e1f5ad9SMike Pritchard 		printf("\n");
4102e1f5ad9SMike Pritchard 	}
41137ed8e48SKirk McKusick }
4122e1f5ad9SMike Pritchard 
4132e1f5ad9SMike Pritchard 
4142e1f5ad9SMike Pritchard static void
heading(int type,u_long id,const char * name,const char * tag)415ff288009SMark Murray heading(int type, u_long id, const char *name, const char *tag)
4169b50d902SRodney W. Grimes {
4179b50d902SRodney W. Grimes 
4181d00bf00SThomas Graichen 	printf("Disk quotas for %s %s (%cid %lu): %s\n", qfextension[type],
4199b50d902SRodney W. Grimes 	    name, *qfextension[type], id, tag);
4209b50d902SRodney W. Grimes 	if (!qflag && tag[0] == '\0') {
42137ed8e48SKirk McKusick 		printf("%-15s %7s %8s %7s %7s %6s %7s %6s%8s\n"
4229b50d902SRodney W. Grimes 			, "Filesystem"
42344501248SJim Pirzyk 			, "usage"
4249b50d902SRodney W. Grimes 			, "quota"
4259b50d902SRodney W. Grimes 			, "limit"
4269b50d902SRodney W. Grimes 			, "grace"
4279b50d902SRodney W. Grimes 			, "files"
4289b50d902SRodney W. Grimes 			, "quota"
4299b50d902SRodney W. Grimes 			, "limit"
4309b50d902SRodney W. Grimes 			, "grace"
4319b50d902SRodney W. Grimes 		);
4329b50d902SRodney W. Grimes 	}
4339b50d902SRodney W. Grimes }
4349b50d902SRodney W. Grimes 
4359b50d902SRodney W. Grimes /*
4369b50d902SRodney W. Grimes  * Calculate the grace period and return a printable string for it.
4379b50d902SRodney W. Grimes  */
438f5374712SMike Pritchard static char *
timeprt(int64_t seconds)439829b3f6bSDag-Erling Smørgrav timeprt(int64_t seconds)
4409b50d902SRodney W. Grimes {
4419b50d902SRodney W. Grimes 	time_t hours, minutes;
442f5374712SMike Pritchard 	char *buf;
4439b50d902SRodney W. Grimes 	static time_t now;
4449b50d902SRodney W. Grimes 
4459b50d902SRodney W. Grimes 	if (now == 0)
4469b50d902SRodney W. Grimes 		time(&now);
447f5374712SMike Pritchard 	if (now > seconds) {
448829b3f6bSDag-Erling Smørgrav 		if ((buf = strdup("none")) == NULL)
449829b3f6bSDag-Erling Smørgrav 			errx(1, "strdup() failed in timeprt()");
450829b3f6bSDag-Erling Smørgrav 		return (buf);
451f5374712SMike Pritchard 	}
4529b50d902SRodney W. Grimes 	seconds -= now;
4539b50d902SRodney W. Grimes 	minutes = (seconds + 30) / 60;
4549b50d902SRodney W. Grimes 	hours = (minutes + 30) / 60;
4559b50d902SRodney W. Grimes 	if (hours >= 36) {
456f5374712SMike Pritchard 		if (asprintf(&buf, "%lddays", ((long)hours + 12) / 24) < 0)
457829b3f6bSDag-Erling Smørgrav 			errx(1, "asprintf() failed in timeprt(1)");
4589b50d902SRodney W. Grimes 		return (buf);
4599b50d902SRodney W. Grimes 	}
4609b50d902SRodney W. Grimes 	if (minutes >= 60) {
461f5374712SMike Pritchard 		if (asprintf(&buf, "%2ld:%ld", (long)minutes / 60,
462f5374712SMike Pritchard 		    (long)minutes % 60) < 0)
463829b3f6bSDag-Erling Smørgrav 			errx(1, "asprintf() failed in timeprt(2)");
4649b50d902SRodney W. Grimes 		return (buf);
4659b50d902SRodney W. Grimes 	}
466f5374712SMike Pritchard 	if (asprintf(&buf, "%2ld", (long)minutes) < 0)
467829b3f6bSDag-Erling Smørgrav 		errx(1, "asprintf() failed in timeprt(3)");
4689b50d902SRodney W. Grimes 	return (buf);
4699b50d902SRodney W. Grimes }
4709b50d902SRodney W. Grimes 
4719b50d902SRodney W. Grimes /*
4729b50d902SRodney W. Grimes  * Collect the requested quota information.
4739b50d902SRodney W. Grimes  */
47477ae30e9SAlexander Langer static struct quotause *
getprivs(long id,int quotatype)475ff288009SMark Murray getprivs(long id, int quotatype)
4769b50d902SRodney W. Grimes {
477e608ec61SIan Dowse 	struct quotause *qup, *quptail = NULL;
478ff288009SMark Murray 	struct fstab *fs;
4799b50d902SRodney W. Grimes 	struct quotause *quphead;
4809288f266SThomas Graichen 	struct statfs *fst;
4819288f266SThomas Graichen 	int nfst, i;
4822e1f5ad9SMike Pritchard 	struct statfs sfb;
4839b50d902SRodney W. Grimes 
4849288f266SThomas Graichen 	qup = quphead = (struct quotause *)0;
4859288f266SThomas Graichen 
4862e1f5ad9SMike Pritchard 	if (filename != NULL && statfs(filename, &sfb) != 0)
4872e1f5ad9SMike Pritchard 		err(1, "cannot statfs %s", filename);
488ab5ff6a6SIan Dowse 	nfst = getmntinfo(&fst, MNT_NOWAIT);
4899d63ad49SPhilippe Charnier 	if (nfst == 0)
4909d63ad49SPhilippe Charnier 		errx(2, "no filesystems mounted!");
4919b50d902SRodney W. Grimes 	setfsent();
4929288f266SThomas Graichen 	for (i = 0; i < nfst; i++) {
4939288f266SThomas Graichen 		if (qup == NULL) {
4941d00bf00SThomas Graichen 			if ((qup = (struct quotause *)malloc(sizeof *qup))
4959d63ad49SPhilippe Charnier 			    == NULL)
4969d63ad49SPhilippe Charnier 				errx(2, "out of memory");
4979b50d902SRodney W. Grimes 		}
4982e1f5ad9SMike Pritchard 		/*
4992e1f5ad9SMike Pritchard 		 * See if the user requested a specific file system
5002e1f5ad9SMike Pritchard 		 * or specified a file inside a mounted file system.
5012e1f5ad9SMike Pritchard 		 */
5022e1f5ad9SMike Pritchard 		if (filename != NULL &&
5032e1f5ad9SMike Pritchard 		    strcmp(sfb.f_mntonname, fst[i].f_mntonname) != 0)
5042e1f5ad9SMike Pritchard 			continue;
505d63b9ba4SBruce Evans 		if (strcmp(fst[i].f_fstypename, "nfs") == 0) {
506e56990e4SIan Dowse 			if (lflag)
507e56990e4SIan Dowse 				continue;
5082e1f5ad9SMike Pritchard 			if (getnfsquota(&fst[i], qup, id, quotatype) == 0)
5099288f266SThomas Graichen 				continue;
510abf0f067SAndrey A. Chernov 		} else if (strcmp(fst[i].f_fstypename, "ufs") == 0) {
5119b50d902SRodney W. Grimes 			/*
5129288f266SThomas Graichen 			 * XXX
5139288f266SThomas Graichen 			 * UFS filesystems must be in /etc/fstab, and must
5149288f266SThomas Graichen 			 * indicate that they have quotas on (?!) This is quite
5159288f266SThomas Graichen 			 * unlike SunOS where quotas can be enabled/disabled
5169288f266SThomas Graichen 			 * on a filesystem independent of /etc/fstab, and it
5179288f266SThomas Graichen 			 * will still print quotas for them.
5189b50d902SRodney W. Grimes 			 */
5199288f266SThomas Graichen 			if ((fs = getfsspec(fst[i].f_mntfromname)) == NULL)
5209b50d902SRodney W. Grimes 				continue;
521ff288009SMark Murray 			if (getufsquota(fs, qup, id, quotatype) == 0)
5229288f266SThomas Graichen 				continue;
5239288f266SThomas Graichen 		} else
5249288f266SThomas Graichen 			continue;
5259288f266SThomas Graichen 		strcpy(qup->fsname, fst[i].f_mntonname);
5269b50d902SRodney W. Grimes 		if (quphead == NULL)
5279b50d902SRodney W. Grimes 			quphead = qup;
5289b50d902SRodney W. Grimes 		else
5299b50d902SRodney W. Grimes 			quptail->next = qup;
5309b50d902SRodney W. Grimes 		quptail = qup;
5319288f266SThomas Graichen 		quptail->next = 0;
5329288f266SThomas Graichen 		qup = NULL;
5339b50d902SRodney W. Grimes 	}
5349288f266SThomas Graichen 	if (qup)
5359288f266SThomas Graichen 		free(qup);
5369b50d902SRodney W. Grimes 	endfsent();
5379b50d902SRodney W. Grimes 	return (quphead);
5389b50d902SRodney W. Grimes }
5399b50d902SRodney W. Grimes 
5409b50d902SRodney W. Grimes /*
54137ed8e48SKirk McKusick  * Check to see if a particular quota is available.
5429b50d902SRodney W. Grimes  */
54377ae30e9SAlexander Langer static int
getufsquota(struct fstab * fs,struct quotause * qup,long id,int quotatype)544ff288009SMark Murray getufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype)
5459288f266SThomas Graichen {
54637ed8e48SKirk McKusick 	struct quotafile *qf;
5479288f266SThomas Graichen 
54837ed8e48SKirk McKusick 	if ((qf = quota_open(fs, quotatype, O_RDONLY)) == NULL)
5499288f266SThomas Graichen 		return (0);
55037ed8e48SKirk McKusick 	if (quota_read(qf, &qup->dqblk, id) != 0)
5519288f266SThomas Graichen 		return (0);
55237ed8e48SKirk McKusick 	quota_close(qf);
5539288f266SThomas Graichen 	return (1);
5549288f266SThomas Graichen }
5559288f266SThomas Graichen 
55677ae30e9SAlexander Langer static int
getnfsquota(struct statfs * fst,struct quotause * qup,long id,int quotatype)557ff288009SMark Murray getnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype)
5589288f266SThomas Graichen {
559aad5531eSSean Eric Fagan 	struct ext_getquota_args gq_args;
560aad5531eSSean Eric Fagan 	struct getquota_args old_gq_args;
5619288f266SThomas Graichen 	struct getquota_rslt gq_rslt;
5629288f266SThomas Graichen 	struct dqblk *dqp = &qup->dqblk;
5639288f266SThomas Graichen 	struct timeval tv;
564754f368cSHiroki Sato 	char *cp, host[NI_MAXHOST];
565aad5531eSSean Eric Fagan 	enum clnt_stat call_stat;
5669288f266SThomas Graichen 
5679288f266SThomas Graichen 	if (fst->f_flags & MNT_LOCAL)
5689288f266SThomas Graichen 		return (0);
5699288f266SThomas Graichen 
5709288f266SThomas Graichen 	/*
5719288f266SThomas Graichen 	 * must be some form of "hostname:/path"
5729288f266SThomas Graichen 	 */
573754f368cSHiroki Sato 	cp = fst->f_mntfromname;
574754f368cSHiroki Sato 	do {
575754f368cSHiroki Sato 		cp = strrchr(cp, ':');
576754f368cSHiroki Sato 	} while (cp != NULL && *(cp + 1) != '/');
5779288f266SThomas Graichen 	if (cp == NULL) {
578b189011dSPhilippe Charnier 		warnx("cannot find hostname for %s", fst->f_mntfromname);
5799288f266SThomas Graichen 		return (0);
5809288f266SThomas Graichen 	}
581754f368cSHiroki Sato 	memset(host, 0, sizeof(host));
582754f368cSHiroki Sato 	memcpy(host, fst->f_mntfromname, cp - fst->f_mntfromname);
583754f368cSHiroki Sato 	host[sizeof(host) - 1] = '\0';
5849288f266SThomas Graichen 
585ab5ff6a6SIan Dowse 	/* Avoid attempting the RPC for special amd(8) filesystems. */
586ab5ff6a6SIan Dowse 	if (strncmp(fst->f_mntfromname, "pid", 3) == 0 &&
587754f368cSHiroki Sato 	    strchr(fst->f_mntfromname, '@') != NULL)
588ab5ff6a6SIan Dowse 		return (0);
589ab5ff6a6SIan Dowse 
5909288f266SThomas Graichen 	gq_args.gqa_pathp = cp + 1;
591aad5531eSSean Eric Fagan 	gq_args.gqa_id = id;
592aad5531eSSean Eric Fagan 	gq_args.gqa_type = quotatype;
593aad5531eSSean Eric Fagan 
594aad5531eSSean Eric Fagan 	call_stat = callaurpc(host, RQUOTAPROG, EXT_RQUOTAVERS,
595aad5531eSSean Eric Fagan 			      RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_ext_getquota_args, (char *)&gq_args,
596aad5531eSSean Eric Fagan 			      (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt);
597740a5434SHiroki Sato 	if (call_stat == RPC_PROGVERSMISMATCH || call_stat == RPC_PROGNOTREGISTERED) {
598aad5531eSSean Eric Fagan 		if (quotatype == USRQUOTA) {
599aad5531eSSean Eric Fagan 			old_gq_args.gqa_pathp = cp + 1;
600aad5531eSSean Eric Fagan 			old_gq_args.gqa_uid = id;
601aad5531eSSean Eric Fagan 			call_stat = callaurpc(host, RQUOTAPROG, RQUOTAVERS,
602aad5531eSSean Eric Fagan 					      RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&old_gq_args,
603aad5531eSSean Eric Fagan 					      (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt);
604aad5531eSSean Eric Fagan 		} else {
605aad5531eSSean Eric Fagan 			/* Old rpc quota does not support group type */
6069288f266SThomas Graichen 			return (0);
607aad5531eSSean Eric Fagan 		}
608aad5531eSSean Eric Fagan 	}
609aad5531eSSean Eric Fagan 	if (call_stat != 0)
610aad5531eSSean Eric Fagan 		return (call_stat);
6119288f266SThomas Graichen 
6129288f266SThomas Graichen 	switch (gq_rslt.status) {
6139288f266SThomas Graichen 	case Q_NOQUOTA:
6149288f266SThomas Graichen 		break;
6159288f266SThomas Graichen 	case Q_EPERM:
6169d63ad49SPhilippe Charnier 		warnx("quota permission error, host: %s",
6179288f266SThomas Graichen 			fst->f_mntfromname);
6189288f266SThomas Graichen 		break;
6199288f266SThomas Graichen 	case Q_OK:
6209288f266SThomas Graichen 		gettimeofday(&tv, NULL);
6219288f266SThomas Graichen 			/* blocks*/
6229288f266SThomas Graichen 		dqp->dqb_bhardlimit =
623404d2feeSConrad Meyer 		    ((uint64_t)gq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit *
624404d2feeSConrad Meyer 		    gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize) / DEV_BSIZE;
6259288f266SThomas Graichen 		dqp->dqb_bsoftlimit =
626404d2feeSConrad Meyer 		    ((uint64_t)gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit *
627404d2feeSConrad Meyer 		    gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize) / DEV_BSIZE;
6289288f266SThomas Graichen 		dqp->dqb_curblocks =
629404d2feeSConrad Meyer 		    ((uint64_t)gq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks *
630404d2feeSConrad Meyer 		    gq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize) / DEV_BSIZE;
6319288f266SThomas Graichen 			/* inodes */
6329288f266SThomas Graichen 		dqp->dqb_ihardlimit =
6339288f266SThomas Graichen 			gq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit;
6349288f266SThomas Graichen 		dqp->dqb_isoftlimit =
6359288f266SThomas Graichen 			gq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit;
6369288f266SThomas Graichen 		dqp->dqb_curinodes =
6379288f266SThomas Graichen 			gq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles;
6389288f266SThomas Graichen 			/* grace times */
6399288f266SThomas Graichen 		dqp->dqb_btime =
6409288f266SThomas Graichen 		    tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft;
6419288f266SThomas Graichen 		dqp->dqb_itime =
6429288f266SThomas Graichen 		    tv.tv_sec + gq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft;
6439288f266SThomas Graichen 		return (1);
6449288f266SThomas Graichen 	default:
645b189011dSPhilippe Charnier 		warnx("bad rpc result, host: %s", fst->f_mntfromname);
6469288f266SThomas Graichen 		break;
6479288f266SThomas Graichen 	}
648754f368cSHiroki Sato 
6499288f266SThomas Graichen 	return (0);
6509288f266SThomas Graichen }
6519288f266SThomas Graichen 
652aad5531eSSean Eric Fagan static enum clnt_stat
callaurpc(char * host,int prognum,int versnum,int procnum,xdrproc_t inproc,char * in,xdrproc_t outproc,char * out)653ff288009SMark Murray callaurpc(char *host, int prognum, int versnum, int procnum,
654ff288009SMark Murray     xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
6559288f266SThomas Graichen {
6569288f266SThomas Graichen 	enum clnt_stat clnt_stat;
6579288f266SThomas Graichen 	struct timeval timeout, tottimeout;
6589288f266SThomas Graichen 
6599288f266SThomas Graichen 	CLIENT *client = NULL;
6609288f266SThomas Graichen 
661754f368cSHiroki Sato  	client = clnt_create(host, prognum, versnum, "udp");
662754f368cSHiroki Sato 	if (client == NULL)
663754f368cSHiroki Sato 		return ((int)rpc_createerr.cf_stat);
6649288f266SThomas Graichen 	timeout.tv_usec = 0;
6659288f266SThomas Graichen 	timeout.tv_sec = 6;
666754f368cSHiroki Sato 	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
6679288f266SThomas Graichen 
6689288f266SThomas Graichen 	client->cl_auth = authunix_create_default();
6699288f266SThomas Graichen 	tottimeout.tv_sec = 25;
6709288f266SThomas Graichen 	tottimeout.tv_usec = 0;
6719288f266SThomas Graichen 	clnt_stat = clnt_call(client, procnum, inproc, in,
6729288f266SThomas Graichen 	    outproc, out, tottimeout);
673aad5531eSSean Eric Fagan 	return (clnt_stat);
6749288f266SThomas Graichen }
6759288f266SThomas Graichen 
67677ae30e9SAlexander Langer static int
alldigits(char * s)677ff288009SMark Murray alldigits(char *s)
6789b50d902SRodney W. Grimes {
679ff288009SMark Murray 	int c;
6809b50d902SRodney W. Grimes 
6819b50d902SRodney W. Grimes 	c = *s++;
6829b50d902SRodney W. Grimes 	do {
6839b50d902SRodney W. Grimes 		if (!isdigit(c))
6849b50d902SRodney W. Grimes 			return (0);
68577ae30e9SAlexander Langer 	} while ((c = *s++));
6869b50d902SRodney W. Grimes 	return (1);
6879b50d902SRodney W. Grimes }
688