xref: /illumos-gate/usr/src/cmd/fs.d/ufs/quotacheck/quotacheck.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
32*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
33*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
36*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
37*7c478bd9Sstevel@tonic-gate  * contributors.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * Fix up / report on disc quotas & usage
44*7c478bd9Sstevel@tonic-gate  */
45*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
46*7c478bd9Sstevel@tonic-gate #include <string.h>
47*7c478bd9Sstevel@tonic-gate #include <stdio.h>
48*7c478bd9Sstevel@tonic-gate #include <ctype.h>
49*7c478bd9Sstevel@tonic-gate #include <signal.h>
50*7c478bd9Sstevel@tonic-gate #include <errno.h>
51*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/filio.h>
53*7c478bd9Sstevel@tonic-gate #include <limits.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_quota.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
66*7c478bd9Sstevel@tonic-gate #include <pwd.h>
67*7c478bd9Sstevel@tonic-gate #include <iso/limits_iso.h>
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate union {
70*7c478bd9Sstevel@tonic-gate 	struct	fs	sblk;
71*7c478bd9Sstevel@tonic-gate 	char	dummy[MAXBSIZE];
72*7c478bd9Sstevel@tonic-gate } un;
73*7c478bd9Sstevel@tonic-gate #define	sblock	un.sblk
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate #define	ITABSZ	256
76*7c478bd9Sstevel@tonic-gate struct	dinode	itab[ITABSZ];
77*7c478bd9Sstevel@tonic-gate struct	dinode	*dp;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate struct fileusage {
80*7c478bd9Sstevel@tonic-gate 	struct fileusage *fu_next;
81*7c478bd9Sstevel@tonic-gate 	ulong_t fu_curfiles;
82*7c478bd9Sstevel@tonic-gate 	uint64_t fu_curblocks;
83*7c478bd9Sstevel@tonic-gate 	uid_t	fu_uid;
84*7c478bd9Sstevel@tonic-gate };
85*7c478bd9Sstevel@tonic-gate #define	FUHASH 997
86*7c478bd9Sstevel@tonic-gate struct fileusage *fuhead[FUHASH];
87*7c478bd9Sstevel@tonic-gate struct fileusage *lookup(uid_t);
88*7c478bd9Sstevel@tonic-gate struct fileusage *adduid(uid_t);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate int fi;
91*7c478bd9Sstevel@tonic-gate ino_t ino;
92*7c478bd9Sstevel@tonic-gate struct	dinode	*ginode();
93*7c478bd9Sstevel@tonic-gate char *mntopt(), *hasvfsopt(), *hasmntopt();
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate extern int	optind;
96*7c478bd9Sstevel@tonic-gate extern char	*optarg;
97*7c478bd9Sstevel@tonic-gate extern int	fsync(int);
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate static void acct();
100*7c478bd9Sstevel@tonic-gate static void bread();
101*7c478bd9Sstevel@tonic-gate static void usage();
102*7c478bd9Sstevel@tonic-gate static int chkquota();
103*7c478bd9Sstevel@tonic-gate static int quotactl();
104*7c478bd9Sstevel@tonic-gate static int preen();
105*7c478bd9Sstevel@tonic-gate static int waiter();
106*7c478bd9Sstevel@tonic-gate static int oneof();
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate int	vflag;		/* verbose */
109*7c478bd9Sstevel@tonic-gate int	aflag;		/* all file systems */
110*7c478bd9Sstevel@tonic-gate int	pflag;		/* fsck like parallel check */
111*7c478bd9Sstevel@tonic-gate int	fflag;		/* force flag */
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate #define	QFNAME "quotas"
114*7c478bd9Sstevel@tonic-gate #define	CHUNK	50
115*7c478bd9Sstevel@tonic-gate char **listbuf;
116*7c478bd9Sstevel@tonic-gate struct dqblk zerodqbuf;
117*7c478bd9Sstevel@tonic-gate struct fileusage zerofileusage;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate void
120*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
121*7c478bd9Sstevel@tonic-gate {
122*7c478bd9Sstevel@tonic-gate 	struct mnttab mntp;
123*7c478bd9Sstevel@tonic-gate 	struct vfstab vfsbuf;
124*7c478bd9Sstevel@tonic-gate 	char **listp;
125*7c478bd9Sstevel@tonic-gate 	int listcnt;
126*7c478bd9Sstevel@tonic-gate 	int listmax = 0;
127*7c478bd9Sstevel@tonic-gate 	char quotafile[MAXPATHLEN];
128*7c478bd9Sstevel@tonic-gate 	FILE *mtab, *vfstab;
129*7c478bd9Sstevel@tonic-gate 	int errs = 0;
130*7c478bd9Sstevel@tonic-gate 	int	opt;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	if ((listbuf = (char **)malloc(sizeof (char *) * CHUNK)) == NULL) {
133*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "Can't alloc lisbuf array.");
134*7c478bd9Sstevel@tonic-gate 		exit(31+1);
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate 	listmax = CHUNK;
137*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "vapVf")) != EOF) {
138*7c478bd9Sstevel@tonic-gate 		switch (opt) {
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 		case 'v':
141*7c478bd9Sstevel@tonic-gate 			vflag++;
142*7c478bd9Sstevel@tonic-gate 			break;
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 		case 'a':
145*7c478bd9Sstevel@tonic-gate 			aflag++;
146*7c478bd9Sstevel@tonic-gate 			break;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 		case 'p':
149*7c478bd9Sstevel@tonic-gate 			pflag++;
150*7c478bd9Sstevel@tonic-gate 			break;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 		case 'V':		/* Print command line */
153*7c478bd9Sstevel@tonic-gate 			{
154*7c478bd9Sstevel@tonic-gate 				char		*opt_text;
155*7c478bd9Sstevel@tonic-gate 				int		opt_count;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "quotacheck -F UFS ");
158*7c478bd9Sstevel@tonic-gate 				for (opt_count = 1; opt_count < argc;
159*7c478bd9Sstevel@tonic-gate 				    opt_count++) {
160*7c478bd9Sstevel@tonic-gate 					opt_text = argv[opt_count];
161*7c478bd9Sstevel@tonic-gate 					if (opt_text)
162*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stdout, " %s ",
163*7c478bd9Sstevel@tonic-gate 						    opt_text);
164*7c478bd9Sstevel@tonic-gate 				}
165*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
166*7c478bd9Sstevel@tonic-gate 			}
167*7c478bd9Sstevel@tonic-gate 			break;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		case 'f':
170*7c478bd9Sstevel@tonic-gate 			fflag++;
171*7c478bd9Sstevel@tonic-gate 			break;
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 		case '?':
174*7c478bd9Sstevel@tonic-gate 			usage();
175*7c478bd9Sstevel@tonic-gate 		}
176*7c478bd9Sstevel@tonic-gate 	}
177*7c478bd9Sstevel@tonic-gate 	if (argc <= optind && !aflag) {
178*7c478bd9Sstevel@tonic-gate 		usage();
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	if (quotactl(Q_ALLSYNC, NULL, (uid_t)0, NULL) < 0 &&
182*7c478bd9Sstevel@tonic-gate 	    errno == EINVAL && vflag)
183*7c478bd9Sstevel@tonic-gate 		printf("Warning: Quotas are not compiled into this kernel\n");
184*7c478bd9Sstevel@tonic-gate 	sync();
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (aflag) {
187*7c478bd9Sstevel@tonic-gate 		/*
188*7c478bd9Sstevel@tonic-gate 		 * Go through vfstab and make a list of appropriate
189*7c478bd9Sstevel@tonic-gate 		 * filesystems.
190*7c478bd9Sstevel@tonic-gate 		 */
191*7c478bd9Sstevel@tonic-gate 		listp = listbuf;
192*7c478bd9Sstevel@tonic-gate 		listcnt = 0;
193*7c478bd9Sstevel@tonic-gate 		if ((vfstab = fopen(VFSTAB, "r")) == NULL) {
194*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "Can't open ");
195*7c478bd9Sstevel@tonic-gate 			perror(VFSTAB);
196*7c478bd9Sstevel@tonic-gate 			exit(31+8);
197*7c478bd9Sstevel@tonic-gate 		}
198*7c478bd9Sstevel@tonic-gate 		while (getvfsent(vfstab, &vfsbuf) == NULL) {
199*7c478bd9Sstevel@tonic-gate 			if (strcmp(vfsbuf.vfs_fstype, MNTTYPE_UFS) != 0 ||
200*7c478bd9Sstevel@tonic-gate 			    (vfsbuf.vfs_mntopts == 0) ||
201*7c478bd9Sstevel@tonic-gate 			    hasvfsopt(&vfsbuf, MNTOPT_RO) ||
202*7c478bd9Sstevel@tonic-gate 			    (!hasvfsopt(&vfsbuf, MNTOPT_RQ) &&
203*7c478bd9Sstevel@tonic-gate 			    !hasvfsopt(&vfsbuf, MNTOPT_QUOTA)))
204*7c478bd9Sstevel@tonic-gate 				continue;
205*7c478bd9Sstevel@tonic-gate 			*listp = malloc(strlen(vfsbuf.vfs_special) + 1);
206*7c478bd9Sstevel@tonic-gate 			strcpy(*listp, vfsbuf.vfs_special);
207*7c478bd9Sstevel@tonic-gate 			listp++;
208*7c478bd9Sstevel@tonic-gate 			listcnt++;
209*7c478bd9Sstevel@tonic-gate 			/* grow listbuf if needed */
210*7c478bd9Sstevel@tonic-gate 			if (listcnt >= listmax) {
211*7c478bd9Sstevel@tonic-gate 				listmax += CHUNK;
212*7c478bd9Sstevel@tonic-gate 				listbuf = (char **)realloc(listbuf,
213*7c478bd9Sstevel@tonic-gate 					sizeof (char *) * listmax);
214*7c478bd9Sstevel@tonic-gate 				if (listbuf == NULL) {
215*7c478bd9Sstevel@tonic-gate 					fprintf(stderr,
216*7c478bd9Sstevel@tonic-gate 						"Can't grow listbuf.\n");
217*7c478bd9Sstevel@tonic-gate 					exit(31+1);
218*7c478bd9Sstevel@tonic-gate 				}
219*7c478bd9Sstevel@tonic-gate 				listp = &listbuf[listcnt];
220*7c478bd9Sstevel@tonic-gate 			}
221*7c478bd9Sstevel@tonic-gate 		}
222*7c478bd9Sstevel@tonic-gate 		fclose(vfstab);
223*7c478bd9Sstevel@tonic-gate 		*listp = (char *)0;
224*7c478bd9Sstevel@tonic-gate 		listp = listbuf;
225*7c478bd9Sstevel@tonic-gate 	} else {
226*7c478bd9Sstevel@tonic-gate 		listp = &argv[optind];
227*7c478bd9Sstevel@tonic-gate 		listcnt = argc - optind;
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 	if (pflag) {
230*7c478bd9Sstevel@tonic-gate 		errs = preen(listcnt, listp);
231*7c478bd9Sstevel@tonic-gate 	} else {
232*7c478bd9Sstevel@tonic-gate 		if ((mtab = fopen(MNTTAB, "r")) == NULL) {
233*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "Can't open ");
234*7c478bd9Sstevel@tonic-gate 			perror(MNTTAB);
235*7c478bd9Sstevel@tonic-gate 			exit(31+8);
236*7c478bd9Sstevel@tonic-gate 		}
237*7c478bd9Sstevel@tonic-gate 		while (getmntent(mtab, &mntp) == NULL) {
238*7c478bd9Sstevel@tonic-gate 			if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) == 0 &&
239*7c478bd9Sstevel@tonic-gate 			    !hasmntopt(&mntp, MNTOPT_RO) &&
240*7c478bd9Sstevel@tonic-gate 			    (oneof(mntp.mnt_special, listp, listcnt) ||
241*7c478bd9Sstevel@tonic-gate 			    oneof(mntp.mnt_mountp, listp, listcnt))) {
242*7c478bd9Sstevel@tonic-gate 				(void) snprintf(quotafile, sizeof (quotafile),
243*7c478bd9Sstevel@tonic-gate 					"%s/%s", mntp.mnt_mountp, QFNAME);
244*7c478bd9Sstevel@tonic-gate 				errs +=
245*7c478bd9Sstevel@tonic-gate 				    chkquota(mntp.mnt_special,
246*7c478bd9Sstevel@tonic-gate 					mntp.mnt_mountp, quotafile);
247*7c478bd9Sstevel@tonic-gate 			}
248*7c478bd9Sstevel@tonic-gate 		}
249*7c478bd9Sstevel@tonic-gate 		fclose(mtab);
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 	while (listcnt--) {
252*7c478bd9Sstevel@tonic-gate 		if (*listp) {
253*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "Cannot check %s\n", *listp);
254*7c478bd9Sstevel@tonic-gate 			errs++;
255*7c478bd9Sstevel@tonic-gate 		}
256*7c478bd9Sstevel@tonic-gate 		listp++;
257*7c478bd9Sstevel@tonic-gate 	}
258*7c478bd9Sstevel@tonic-gate 	if (errs > 0)
259*7c478bd9Sstevel@tonic-gate 		errs += 31;
260*7c478bd9Sstevel@tonic-gate 	exit(errs);
261*7c478bd9Sstevel@tonic-gate }
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate static struct active {
264*7c478bd9Sstevel@tonic-gate 	char *rdev;
265*7c478bd9Sstevel@tonic-gate 	pid_t pid;
266*7c478bd9Sstevel@tonic-gate 	struct active *nxt;
267*7c478bd9Sstevel@tonic-gate };
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate int
270*7c478bd9Sstevel@tonic-gate preen(listcnt, listp)
271*7c478bd9Sstevel@tonic-gate 	int listcnt;
272*7c478bd9Sstevel@tonic-gate 	char **listp;
273*7c478bd9Sstevel@tonic-gate {
274*7c478bd9Sstevel@tonic-gate 	register int i, rc, errs;
275*7c478bd9Sstevel@tonic-gate 	register char **lp, *rdev, *bdev;
276*7c478bd9Sstevel@tonic-gate 	extern char *getfullrawname(), *getfullblkname();
277*7c478bd9Sstevel@tonic-gate 	struct mnttab mntp, mpref;
278*7c478bd9Sstevel@tonic-gate 	struct active *alist, *ap;
279*7c478bd9Sstevel@tonic-gate 	FILE *mtab;
280*7c478bd9Sstevel@tonic-gate 	char quotafile[MAXPATHLEN];
281*7c478bd9Sstevel@tonic-gate 	char name[MAXPATHLEN];
282*7c478bd9Sstevel@tonic-gate 	int nactive, serially;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	if ((mtab = fopen(MNTTAB, "r")) == NULL) {
285*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "Can't open ");
286*7c478bd9Sstevel@tonic-gate 		perror(MNTTAB);
287*7c478bd9Sstevel@tonic-gate 		exit(31+8);
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 	memset(&mpref, 0, sizeof (struct mnttab));
290*7c478bd9Sstevel@tonic-gate 	errs = 0;
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	for (lp = listp, i = 0; i < listcnt; lp++, i++) {
293*7c478bd9Sstevel@tonic-gate 		serially = 0;
294*7c478bd9Sstevel@tonic-gate 		rdev = getfullrawname(*lp);
295*7c478bd9Sstevel@tonic-gate 		if (rdev == NULL || *rdev == '\0') {
296*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "can't get rawname for `%s'\n", *lp);
297*7c478bd9Sstevel@tonic-gate 			serially = 1;
298*7c478bd9Sstevel@tonic-gate 		} else if (preen_addev(rdev) != 0) {
299*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "preen_addev error\n");
300*7c478bd9Sstevel@tonic-gate 			serially = 1;
301*7c478bd9Sstevel@tonic-gate 		}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		if (rdev != NULL)
304*7c478bd9Sstevel@tonic-gate 			free(rdev);
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 		if (serially) {
307*7c478bd9Sstevel@tonic-gate 			rewind(mtab);
308*7c478bd9Sstevel@tonic-gate 			mpref.mnt_special = *lp;
309*7c478bd9Sstevel@tonic-gate 			if (getmntany(mtab, &mntp, &mpref) == 0 &&
310*7c478bd9Sstevel@tonic-gate 			    strcmp(mntp.mnt_fstype, MNTTYPE_UFS) == 0 &&
311*7c478bd9Sstevel@tonic-gate 			    !hasmntopt(&mntp, MNTOPT_RO)) {
312*7c478bd9Sstevel@tonic-gate 				errs += (31+chkquota(mntp.mnt_special,
313*7c478bd9Sstevel@tonic-gate 				    mntp.mnt_mountp, quotafile));
314*7c478bd9Sstevel@tonic-gate 				*lp = (char *)0;
315*7c478bd9Sstevel@tonic-gate 			}
316*7c478bd9Sstevel@tonic-gate 		}
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	nactive = 0;
320*7c478bd9Sstevel@tonic-gate 	alist = NULL;
321*7c478bd9Sstevel@tonic-gate 	while ((rc = preen_getdev(name)) > 0) {
322*7c478bd9Sstevel@tonic-gate 		switch (rc) {
323*7c478bd9Sstevel@tonic-gate 		case 1:
324*7c478bd9Sstevel@tonic-gate 			bdev = getfullblkname(name);
325*7c478bd9Sstevel@tonic-gate 			if (bdev == NULL || *bdev == '\0') {
326*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "can't get blkname for `%s'\n",
327*7c478bd9Sstevel@tonic-gate 				    name);
328*7c478bd9Sstevel@tonic-gate 				if (bdev)
329*7c478bd9Sstevel@tonic-gate 					free(bdev);
330*7c478bd9Sstevel@tonic-gate 				continue;
331*7c478bd9Sstevel@tonic-gate 			}
332*7c478bd9Sstevel@tonic-gate 			rewind(mtab);
333*7c478bd9Sstevel@tonic-gate 			mpref.mnt_special = bdev;
334*7c478bd9Sstevel@tonic-gate 			if (getmntany(mtab, &mntp, &mpref) != 0) {
335*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "`%s' not mounted?\n", name);
336*7c478bd9Sstevel@tonic-gate 				preen_releasedev(name);
337*7c478bd9Sstevel@tonic-gate 				free(bdev);
338*7c478bd9Sstevel@tonic-gate 				continue;
339*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 ||
340*7c478bd9Sstevel@tonic-gate 			    hasmntopt(&mntp, MNTOPT_RO) ||
341*7c478bd9Sstevel@tonic-gate 			    (!oneof(mntp.mnt_special, listp, listcnt) &&
342*7c478bd9Sstevel@tonic-gate 			    !oneof(mntp.mnt_mountp, listp, listcnt))) {
343*7c478bd9Sstevel@tonic-gate 				preen_releasedev(name);
344*7c478bd9Sstevel@tonic-gate 				free(bdev);
345*7c478bd9Sstevel@tonic-gate 				continue;
346*7c478bd9Sstevel@tonic-gate 			}
347*7c478bd9Sstevel@tonic-gate 			free(bdev);
348*7c478bd9Sstevel@tonic-gate 			ap = (struct active *)malloc(sizeof (struct active));
349*7c478bd9Sstevel@tonic-gate 			if (ap == NULL) {
350*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "out of memory\n");
351*7c478bd9Sstevel@tonic-gate 				exit(31+8);
352*7c478bd9Sstevel@tonic-gate 			}
353*7c478bd9Sstevel@tonic-gate 			ap->rdev = (char *)strdup(name);
354*7c478bd9Sstevel@tonic-gate 			if (ap->rdev == NULL) {
355*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "out of memory\n");
356*7c478bd9Sstevel@tonic-gate 				exit(31+8);
357*7c478bd9Sstevel@tonic-gate 			}
358*7c478bd9Sstevel@tonic-gate 			ap->nxt = alist;
359*7c478bd9Sstevel@tonic-gate 			alist = ap;
360*7c478bd9Sstevel@tonic-gate 			switch (ap->pid = fork()) {
361*7c478bd9Sstevel@tonic-gate 			case -1:
362*7c478bd9Sstevel@tonic-gate 				perror("fork");
363*7c478bd9Sstevel@tonic-gate 				exit(31+8);
364*7c478bd9Sstevel@tonic-gate 				break;
365*7c478bd9Sstevel@tonic-gate 			case 0:
366*7c478bd9Sstevel@tonic-gate 				(void) snprintf(quotafile, sizeof (quotafile),
367*7c478bd9Sstevel@tonic-gate 					"%s/%s", mntp.mnt_mountp, QFNAME);
368*7c478bd9Sstevel@tonic-gate 				exit(31+chkquota(mntp.mnt_special,
369*7c478bd9Sstevel@tonic-gate 				    mntp.mnt_mountp, quotafile));
370*7c478bd9Sstevel@tonic-gate 				break;
371*7c478bd9Sstevel@tonic-gate 			default:
372*7c478bd9Sstevel@tonic-gate 				nactive++;
373*7c478bd9Sstevel@tonic-gate 				break;
374*7c478bd9Sstevel@tonic-gate 			}
375*7c478bd9Sstevel@tonic-gate 			break;
376*7c478bd9Sstevel@tonic-gate 		case 2:
377*7c478bd9Sstevel@tonic-gate 			errs += waiter(&alist);
378*7c478bd9Sstevel@tonic-gate 			nactive--;
379*7c478bd9Sstevel@tonic-gate 			break;
380*7c478bd9Sstevel@tonic-gate 		}
381*7c478bd9Sstevel@tonic-gate 	}
382*7c478bd9Sstevel@tonic-gate 	fclose(mtab);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	while (nactive > 0) {
385*7c478bd9Sstevel@tonic-gate 		errs += waiter(&alist);
386*7c478bd9Sstevel@tonic-gate 		nactive--;
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 	return (errs);
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate int
392*7c478bd9Sstevel@tonic-gate waiter(alp)
393*7c478bd9Sstevel@tonic-gate 	struct active **alp;
394*7c478bd9Sstevel@tonic-gate {
395*7c478bd9Sstevel@tonic-gate 	pid_t curpid;
396*7c478bd9Sstevel@tonic-gate 	int status;
397*7c478bd9Sstevel@tonic-gate 	register struct active *ap, *lap;
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	curpid = wait(&status);
400*7c478bd9Sstevel@tonic-gate 	if (curpid == -1) {
401*7c478bd9Sstevel@tonic-gate 		if (errno == ECHILD)
402*7c478bd9Sstevel@tonic-gate 			return (0);
403*7c478bd9Sstevel@tonic-gate 		perror("wait");
404*7c478bd9Sstevel@tonic-gate 		exit(31+8);
405*7c478bd9Sstevel@tonic-gate 	}
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	for (lap = NULL, ap = *alp; ap != NULL; lap = ap, ap = ap->nxt) {
408*7c478bd9Sstevel@tonic-gate 		if (ap->pid == curpid)
409*7c478bd9Sstevel@tonic-gate 			break;
410*7c478bd9Sstevel@tonic-gate 	}
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	if (ap == NULL) {
413*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "wait returns unknown pid\n");
414*7c478bd9Sstevel@tonic-gate 		exit(31+8);
415*7c478bd9Sstevel@tonic-gate 	} else if (lap) {
416*7c478bd9Sstevel@tonic-gate 		lap->nxt = ap->nxt;
417*7c478bd9Sstevel@tonic-gate 	} else {
418*7c478bd9Sstevel@tonic-gate 		*alp = ap->nxt;
419*7c478bd9Sstevel@tonic-gate 	}
420*7c478bd9Sstevel@tonic-gate 	preen_releasedev(ap->rdev);
421*7c478bd9Sstevel@tonic-gate 	free(ap->rdev);
422*7c478bd9Sstevel@tonic-gate 	free(ap);
423*7c478bd9Sstevel@tonic-gate 	return (WHIBYTE(status));
424*7c478bd9Sstevel@tonic-gate }
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate int
427*7c478bd9Sstevel@tonic-gate chkquota(fsdev, fsfile, qffile)
428*7c478bd9Sstevel@tonic-gate 	char *fsdev;
429*7c478bd9Sstevel@tonic-gate 	char *fsfile;
430*7c478bd9Sstevel@tonic-gate 	char *qffile;
431*7c478bd9Sstevel@tonic-gate {
432*7c478bd9Sstevel@tonic-gate 	register struct fileusage *fup;
433*7c478bd9Sstevel@tonic-gate 	dev_t quotadev;
434*7c478bd9Sstevel@tonic-gate 	FILE *qf;
435*7c478bd9Sstevel@tonic-gate 	uid_t uid;
436*7c478bd9Sstevel@tonic-gate 	struct passwd *pw;
437*7c478bd9Sstevel@tonic-gate 	int cg, i;
438*7c478bd9Sstevel@tonic-gate 	char *rawdisk;
439*7c478bd9Sstevel@tonic-gate 	struct stat64 statb;
440*7c478bd9Sstevel@tonic-gate 	struct dqblk dqbuf;
441*7c478bd9Sstevel@tonic-gate 	extern char *getfullrawname();
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	if ((rawdisk = getfullrawname(fsdev)) == NULL) {
444*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "malloc failed\n");
445*7c478bd9Sstevel@tonic-gate 		return (1);
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	if (*rawdisk == '\0') {
449*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "Could not find character device for %s\n",
450*7c478bd9Sstevel@tonic-gate 		    fsdev);
451*7c478bd9Sstevel@tonic-gate 		return (1);
452*7c478bd9Sstevel@tonic-gate 	}
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	if (vflag)
455*7c478bd9Sstevel@tonic-gate 		printf("*** Checking quotas for %s (%s)\n", rawdisk, fsfile);
456*7c478bd9Sstevel@tonic-gate 	fi = open64(rawdisk, 0);
457*7c478bd9Sstevel@tonic-gate 	if (fi < 0) {
458*7c478bd9Sstevel@tonic-gate 		perror(rawdisk);
459*7c478bd9Sstevel@tonic-gate 		return (1);
460*7c478bd9Sstevel@tonic-gate 	}
461*7c478bd9Sstevel@tonic-gate 	qf = fopen64(qffile, "r+");
462*7c478bd9Sstevel@tonic-gate 	if (qf == NULL) {
463*7c478bd9Sstevel@tonic-gate 		perror(qffile);
464*7c478bd9Sstevel@tonic-gate 		close(fi);
465*7c478bd9Sstevel@tonic-gate 		return (1);
466*7c478bd9Sstevel@tonic-gate 	}
467*7c478bd9Sstevel@tonic-gate 	if (fstat64(fileno(qf), &statb) < 0) {
468*7c478bd9Sstevel@tonic-gate 		perror(qffile);
469*7c478bd9Sstevel@tonic-gate 		fclose(qf);
470*7c478bd9Sstevel@tonic-gate 		close(fi);
471*7c478bd9Sstevel@tonic-gate 		return (1);
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 	quotadev = statb.st_dev;
474*7c478bd9Sstevel@tonic-gate 	if (stat64(fsdev, &statb) < 0) {
475*7c478bd9Sstevel@tonic-gate 		perror(fsdev);
476*7c478bd9Sstevel@tonic-gate 		fclose(qf);
477*7c478bd9Sstevel@tonic-gate 		close(fi);
478*7c478bd9Sstevel@tonic-gate 		return (1);
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 	if (quotadev != statb.st_rdev) {
481*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n",
482*7c478bd9Sstevel@tonic-gate 			qffile, quotadev, fsdev, statb.st_rdev);
483*7c478bd9Sstevel@tonic-gate 		fclose(qf);
484*7c478bd9Sstevel@tonic-gate 		close(fi);
485*7c478bd9Sstevel@tonic-gate 		return (1);
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 	bread((diskaddr_t)SBLOCK, (char *)&sblock, SBSIZE);
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	/*
490*7c478bd9Sstevel@tonic-gate 	 * Flush filesystem since we are going to read
491*7c478bd9Sstevel@tonic-gate 	 * disk raw and we want to make sure everything is
492*7c478bd9Sstevel@tonic-gate 	 * synced to disk before we read it.
493*7c478bd9Sstevel@tonic-gate 	 */
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	if (ioctl(fileno(qf), _FIOFFS, NULL) == -1) {
496*7c478bd9Sstevel@tonic-gate 		perror(qffile);
497*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot flush file system.\n",
498*7c478bd9Sstevel@tonic-gate 				qffile);
499*7c478bd9Sstevel@tonic-gate 		(void) fclose(qf);
500*7c478bd9Sstevel@tonic-gate 		return (1);
501*7c478bd9Sstevel@tonic-gate 	}
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	/*
504*7c478bd9Sstevel@tonic-gate 	 * no need to quotacheck a rw, mounted, and logging file system
505*7c478bd9Sstevel@tonic-gate 	 */
506*7c478bd9Sstevel@tonic-gate 	if ((fflag == 0) && pflag &&
507*7c478bd9Sstevel@tonic-gate 	    (FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
508*7c478bd9Sstevel@tonic-gate 	    (sblock.fs_clean == FSLOG)) {
509*7c478bd9Sstevel@tonic-gate 		fclose(qf);
510*7c478bd9Sstevel@tonic-gate 		close(fi);
511*7c478bd9Sstevel@tonic-gate 		return (0);
512*7c478bd9Sstevel@tonic-gate 	}
513*7c478bd9Sstevel@tonic-gate 	ino = 0;
514*7c478bd9Sstevel@tonic-gate 	for (cg = 0; cg < sblock.fs_ncg; cg++) {
515*7c478bd9Sstevel@tonic-gate 		dp = NULL;
516*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < sblock.fs_ipg; i++)
517*7c478bd9Sstevel@tonic-gate 			acct(ginode());
518*7c478bd9Sstevel@tonic-gate 	}
519*7c478bd9Sstevel@tonic-gate 	for (uid = 0; uid <= MAXUID && uid >= 0; uid++) {
520*7c478bd9Sstevel@tonic-gate 		(void) fread(&dqbuf, sizeof (struct dqblk), 1, qf);
521*7c478bd9Sstevel@tonic-gate 		if (feof(qf))
522*7c478bd9Sstevel@tonic-gate 			break;
523*7c478bd9Sstevel@tonic-gate 		fup = lookup(uid);
524*7c478bd9Sstevel@tonic-gate 		if (fup == 0)
525*7c478bd9Sstevel@tonic-gate 			fup = &zerofileusage;
526*7c478bd9Sstevel@tonic-gate 		if (dqbuf.dqb_bhardlimit == 0 && dqbuf.dqb_bsoftlimit == 0 &&
527*7c478bd9Sstevel@tonic-gate 		    dqbuf.dqb_fhardlimit == 0 && dqbuf.dqb_fsoftlimit == 0) {
528*7c478bd9Sstevel@tonic-gate 			fup->fu_curfiles = 0;
529*7c478bd9Sstevel@tonic-gate 			fup->fu_curblocks = 0;
530*7c478bd9Sstevel@tonic-gate 		}
531*7c478bd9Sstevel@tonic-gate 		if (dqbuf.dqb_curfiles == fup->fu_curfiles &&
532*7c478bd9Sstevel@tonic-gate 		    dqbuf.dqb_curblocks == fup->fu_curblocks) {
533*7c478bd9Sstevel@tonic-gate 			fup->fu_curfiles = 0;
534*7c478bd9Sstevel@tonic-gate 			fup->fu_curblocks = 0;
535*7c478bd9Sstevel@tonic-gate 			continue;
536*7c478bd9Sstevel@tonic-gate 		}
537*7c478bd9Sstevel@tonic-gate 		/*
538*7c478bd9Sstevel@tonic-gate 		 * The maximum number of blocks that can be stored in the
539*7c478bd9Sstevel@tonic-gate 		 * dqb_curblocks field in the quota record is 2^32 - 1,
540*7c478bd9Sstevel@tonic-gate 		 * since it must fit into an unsigned 32-bit quantity.
541*7c478bd9Sstevel@tonic-gate 		 * If this user has more blocks than that, print a message
542*7c478bd9Sstevel@tonic-gate 		 * to that effect and reduce the count of allocated blocks
543*7c478bd9Sstevel@tonic-gate 		 * to the maximum value, which is UINT_MAX.
544*7c478bd9Sstevel@tonic-gate 		 */
545*7c478bd9Sstevel@tonic-gate 		if (fup->fu_curblocks > UINT_MAX) {
546*7c478bd9Sstevel@tonic-gate 			if (pflag || aflag)
547*7c478bd9Sstevel@tonic-gate 				printf("%s: ", rawdisk);
548*7c478bd9Sstevel@tonic-gate 			printf("512-byte blocks allocated to user ");
549*7c478bd9Sstevel@tonic-gate 			if ((pw = getpwuid(uid)) && pw->pw_name[0])
550*7c478bd9Sstevel@tonic-gate 				printf("%-10s ", pw->pw_name);
551*7c478bd9Sstevel@tonic-gate 			else
552*7c478bd9Sstevel@tonic-gate 				printf("#%-9d ", uid);
553*7c478bd9Sstevel@tonic-gate 			printf(" = %lld\n", fup->fu_curblocks);
554*7c478bd9Sstevel@tonic-gate 			printf(
555*7c478bd9Sstevel@tonic-gate "This exceeds the maximum number of blocks recordable in a quota record.\n");
556*7c478bd9Sstevel@tonic-gate 			printf(
557*7c478bd9Sstevel@tonic-gate "The value will be set to the maximum, which is %lu.\n", UINT_MAX);
558*7c478bd9Sstevel@tonic-gate 			fup->fu_curblocks = UINT_MAX;
559*7c478bd9Sstevel@tonic-gate 		}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 		if (vflag) {
562*7c478bd9Sstevel@tonic-gate 			if (pflag || aflag)
563*7c478bd9Sstevel@tonic-gate 				printf("%s: ", rawdisk);
564*7c478bd9Sstevel@tonic-gate 			if ((pw = getpwuid(uid)) && pw->pw_name[0])
565*7c478bd9Sstevel@tonic-gate 				printf("%-10s fixed:", pw->pw_name);
566*7c478bd9Sstevel@tonic-gate 			else
567*7c478bd9Sstevel@tonic-gate 				printf("#%-9d fixed:", uid);
568*7c478bd9Sstevel@tonic-gate 			if (dqbuf.dqb_curfiles != fup->fu_curfiles)
569*7c478bd9Sstevel@tonic-gate 				printf("  files %lu -> %lu",
570*7c478bd9Sstevel@tonic-gate 				    dqbuf.dqb_curfiles, fup->fu_curfiles);
571*7c478bd9Sstevel@tonic-gate 			if (dqbuf.dqb_curblocks != fup->fu_curblocks)
572*7c478bd9Sstevel@tonic-gate 				printf("  blocks %lu -> %llu",
573*7c478bd9Sstevel@tonic-gate 				    dqbuf.dqb_curblocks, fup->fu_curblocks);
574*7c478bd9Sstevel@tonic-gate 			printf("\n");
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 		dqbuf.dqb_curfiles = fup->fu_curfiles;
577*7c478bd9Sstevel@tonic-gate 		dqbuf.dqb_curblocks = fup->fu_curblocks;
578*7c478bd9Sstevel@tonic-gate 		/*
579*7c478bd9Sstevel@tonic-gate 		 * If quotas are not enabled for the current filesystem
580*7c478bd9Sstevel@tonic-gate 		 * then just update the quotas file directly.
581*7c478bd9Sstevel@tonic-gate 		 */
582*7c478bd9Sstevel@tonic-gate 		if ((quotactl(Q_SETQUOTA, fsfile, uid, &dqbuf) < 0) &&
583*7c478bd9Sstevel@tonic-gate 		    (errno == ESRCH)) {
584*7c478bd9Sstevel@tonic-gate 			/* back up, overwrite the entry we just read */
585*7c478bd9Sstevel@tonic-gate 			(void) fseeko64(qf, (offset_t)dqoff(uid), 0);
586*7c478bd9Sstevel@tonic-gate 			(void) fwrite(&dqbuf, sizeof (struct dqblk), 1, qf);
587*7c478bd9Sstevel@tonic-gate 			(void) fflush(qf);
588*7c478bd9Sstevel@tonic-gate 		}
589*7c478bd9Sstevel@tonic-gate 		fup->fu_curfiles = 0;
590*7c478bd9Sstevel@tonic-gate 		fup->fu_curblocks = 0;
591*7c478bd9Sstevel@tonic-gate 	}
592*7c478bd9Sstevel@tonic-gate 	(void) fflush(qf);
593*7c478bd9Sstevel@tonic-gate 	(void) fsync(fileno(qf));
594*7c478bd9Sstevel@tonic-gate 	fclose(qf);
595*7c478bd9Sstevel@tonic-gate 	close(fi);
596*7c478bd9Sstevel@tonic-gate 	return (0);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate void
600*7c478bd9Sstevel@tonic-gate acct(ip)
601*7c478bd9Sstevel@tonic-gate 	register struct dinode *ip;
602*7c478bd9Sstevel@tonic-gate {
603*7c478bd9Sstevel@tonic-gate 	register struct fileusage *fup;
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	if (ip == NULL)
606*7c478bd9Sstevel@tonic-gate 		return;
607*7c478bd9Sstevel@tonic-gate 	ip->di_mode = ip->di_smode;
608*7c478bd9Sstevel@tonic-gate 	if (ip->di_suid != UID_LONG) {
609*7c478bd9Sstevel@tonic-gate 		ip->di_uid = ip->di_suid;
610*7c478bd9Sstevel@tonic-gate 	}
611*7c478bd9Sstevel@tonic-gate 	if (ip->di_mode == 0)
612*7c478bd9Sstevel@tonic-gate 		return;
613*7c478bd9Sstevel@tonic-gate 	fup = adduid(ip->di_uid);
614*7c478bd9Sstevel@tonic-gate 	fup->fu_curfiles++;
615*7c478bd9Sstevel@tonic-gate 	if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK)
616*7c478bd9Sstevel@tonic-gate 		return;
617*7c478bd9Sstevel@tonic-gate 	fup->fu_curblocks += ip->di_blocks;
618*7c478bd9Sstevel@tonic-gate }
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate int
621*7c478bd9Sstevel@tonic-gate oneof(target, olistp, on)
622*7c478bd9Sstevel@tonic-gate 	char *target;
623*7c478bd9Sstevel@tonic-gate 	register char **olistp;
624*7c478bd9Sstevel@tonic-gate 	register int on;
625*7c478bd9Sstevel@tonic-gate {
626*7c478bd9Sstevel@tonic-gate 	char **listp = olistp;
627*7c478bd9Sstevel@tonic-gate 	int n = on;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	while (n--) {
630*7c478bd9Sstevel@tonic-gate 		if (*listp && strcmp(target, *listp) == 0) {
631*7c478bd9Sstevel@tonic-gate 			*listp = (char *)0;
632*7c478bd9Sstevel@tonic-gate 			return (1);
633*7c478bd9Sstevel@tonic-gate 		}
634*7c478bd9Sstevel@tonic-gate 		listp++;
635*7c478bd9Sstevel@tonic-gate 	}
636*7c478bd9Sstevel@tonic-gate 	return (0);
637*7c478bd9Sstevel@tonic-gate }
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate struct dinode *
640*7c478bd9Sstevel@tonic-gate ginode()
641*7c478bd9Sstevel@tonic-gate {
642*7c478bd9Sstevel@tonic-gate 	ulong_t iblk;
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	if (dp == NULL || ++dp >= &itab[ITABSZ]) {
645*7c478bd9Sstevel@tonic-gate 		iblk = itod(&sblock, ino);
646*7c478bd9Sstevel@tonic-gate 		bread(fsbtodb(&sblock, iblk),
647*7c478bd9Sstevel@tonic-gate 		    (char *)itab, sizeof (itab));
648*7c478bd9Sstevel@tonic-gate 		dp = &itab[(int)ino % (int)INOPB(&sblock)];
649*7c478bd9Sstevel@tonic-gate 	}
650*7c478bd9Sstevel@tonic-gate 	if (ino++ < UFSROOTINO)
651*7c478bd9Sstevel@tonic-gate 		return (NULL);
652*7c478bd9Sstevel@tonic-gate 	return (dp);
653*7c478bd9Sstevel@tonic-gate }
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate void
656*7c478bd9Sstevel@tonic-gate bread(diskaddr_t bno, char *buf, int cnt)
657*7c478bd9Sstevel@tonic-gate {
658*7c478bd9Sstevel@tonic-gate 	extern offset_t llseek();
659*7c478bd9Sstevel@tonic-gate 	offset_t pos;
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	pos = (offset_t)bno * DEV_BSIZE;
662*7c478bd9Sstevel@tonic-gate 	if (llseek(fi, pos, 0) != pos) {
663*7c478bd9Sstevel@tonic-gate 		perror("lseek");
664*7c478bd9Sstevel@tonic-gate 		exit(31+1);
665*7c478bd9Sstevel@tonic-gate 	}
666*7c478bd9Sstevel@tonic-gate 	if (read(fi, buf, cnt) != cnt) {
667*7c478bd9Sstevel@tonic-gate 		perror("read");
668*7c478bd9Sstevel@tonic-gate 		exit(31+1);
669*7c478bd9Sstevel@tonic-gate 	}
670*7c478bd9Sstevel@tonic-gate }
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate struct fileusage *
673*7c478bd9Sstevel@tonic-gate lookup(uid_t uid)
674*7c478bd9Sstevel@tonic-gate {
675*7c478bd9Sstevel@tonic-gate 	register struct fileusage *fup;
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next)
678*7c478bd9Sstevel@tonic-gate 		if (fup->fu_uid == uid)
679*7c478bd9Sstevel@tonic-gate 			return (fup);
680*7c478bd9Sstevel@tonic-gate 	return ((struct fileusage *)0);
681*7c478bd9Sstevel@tonic-gate }
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate struct fileusage *
684*7c478bd9Sstevel@tonic-gate adduid(uid_t uid)
685*7c478bd9Sstevel@tonic-gate {
686*7c478bd9Sstevel@tonic-gate 	struct fileusage *fup, **fhp;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	fup = lookup(uid);
689*7c478bd9Sstevel@tonic-gate 	if (fup != 0)
690*7c478bd9Sstevel@tonic-gate 		return (fup);
691*7c478bd9Sstevel@tonic-gate 	fup = (struct fileusage *)calloc(1, sizeof (struct fileusage));
692*7c478bd9Sstevel@tonic-gate 	if (fup == 0) {
693*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "out of memory for fileusage structures\n");
694*7c478bd9Sstevel@tonic-gate 		exit(31+1);
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 	fhp = &fuhead[uid % FUHASH];
697*7c478bd9Sstevel@tonic-gate 	fup->fu_next = *fhp;
698*7c478bd9Sstevel@tonic-gate 	*fhp = fup;
699*7c478bd9Sstevel@tonic-gate 	fup->fu_uid = uid;
700*7c478bd9Sstevel@tonic-gate 	return (fup);
701*7c478bd9Sstevel@tonic-gate }
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate void
704*7c478bd9Sstevel@tonic-gate usage()
705*7c478bd9Sstevel@tonic-gate {
706*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "ufs usage:\n");
707*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\tquotacheck [-v] [-f] [-p] -a\n");
708*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\tquotacheck [-v] [-f] [-p] filesys ...\n");
709*7c478bd9Sstevel@tonic-gate 	exit(31+1);
710*7c478bd9Sstevel@tonic-gate }
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate int
713*7c478bd9Sstevel@tonic-gate quotactl(cmd, mountp, uid, addr)
714*7c478bd9Sstevel@tonic-gate 	int		cmd;
715*7c478bd9Sstevel@tonic-gate 	char		*mountp;
716*7c478bd9Sstevel@tonic-gate 	uid_t		uid;
717*7c478bd9Sstevel@tonic-gate 	caddr_t		addr;
718*7c478bd9Sstevel@tonic-gate {
719*7c478bd9Sstevel@tonic-gate 	int 		fd;
720*7c478bd9Sstevel@tonic-gate 	int 		status;
721*7c478bd9Sstevel@tonic-gate 	struct quotctl	quota;
722*7c478bd9Sstevel@tonic-gate 	char		qfile[MAXPATHLEN];
723*7c478bd9Sstevel@tonic-gate 	FILE		*fstab;
724*7c478bd9Sstevel@tonic-gate 	struct mnttab	mntp;
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	if ((mountp == NULL) && (cmd == Q_ALLSYNC)) {
728*7c478bd9Sstevel@tonic-gate 		/*
729*7c478bd9Sstevel@tonic-gate 		 * Find the mount point of any ufs file system.   This is
730*7c478bd9Sstevel@tonic-gate 		 * because the ioctl that implements the quotactl call has
731*7c478bd9Sstevel@tonic-gate 		 * to go to a real file, and not to the block device.
732*7c478bd9Sstevel@tonic-gate 		 */
733*7c478bd9Sstevel@tonic-gate 		if ((fstab = fopen(MNTTAB, "r")) == NULL) {
734*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: ", MNTTAB);
735*7c478bd9Sstevel@tonic-gate 			perror("open");
736*7c478bd9Sstevel@tonic-gate 			exit(31+1);
737*7c478bd9Sstevel@tonic-gate 		}
738*7c478bd9Sstevel@tonic-gate 		fd = -1;
739*7c478bd9Sstevel@tonic-gate 		while ((status = getmntent(fstab, &mntp)) == NULL) {
740*7c478bd9Sstevel@tonic-gate 			if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 ||
741*7c478bd9Sstevel@tonic-gate 				hasmntopt(&mntp, MNTOPT_RO))
742*7c478bd9Sstevel@tonic-gate 				continue;
743*7c478bd9Sstevel@tonic-gate 			if ((strlcpy(qfile, mntp.mnt_mountp,
744*7c478bd9Sstevel@tonic-gate 				sizeof (qfile)) >= sizeof (qfile)) ||
745*7c478bd9Sstevel@tonic-gate 			    (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >=
746*7c478bd9Sstevel@tonic-gate 				sizeof (qfile))) {
747*7c478bd9Sstevel@tonic-gate 				continue;
748*7c478bd9Sstevel@tonic-gate 			}
749*7c478bd9Sstevel@tonic-gate 			if ((fd = open64(qfile, O_RDWR)) == -1)
750*7c478bd9Sstevel@tonic-gate 				break;
751*7c478bd9Sstevel@tonic-gate 		}
752*7c478bd9Sstevel@tonic-gate 		fclose(fstab);
753*7c478bd9Sstevel@tonic-gate 		if (fd == -1) {
754*7c478bd9Sstevel@tonic-gate 			errno = ENOENT;
755*7c478bd9Sstevel@tonic-gate 			return (-1);
756*7c478bd9Sstevel@tonic-gate 		}
757*7c478bd9Sstevel@tonic-gate 	} else {
758*7c478bd9Sstevel@tonic-gate 		if (mountp == NULL || mountp[0] == '\0') {
759*7c478bd9Sstevel@tonic-gate 			errno =  ENOENT;
760*7c478bd9Sstevel@tonic-gate 			return (-1);
761*7c478bd9Sstevel@tonic-gate 		}
762*7c478bd9Sstevel@tonic-gate 		if ((strlcpy(qfile, mountp, sizeof (qfile)) >=
763*7c478bd9Sstevel@tonic-gate 			sizeof (qfile)) ||
764*7c478bd9Sstevel@tonic-gate 		    (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >=
765*7c478bd9Sstevel@tonic-gate 			sizeof (qfile))) {
766*7c478bd9Sstevel@tonic-gate 			errno = ENOENT;
767*7c478bd9Sstevel@tonic-gate 			return (-1);
768*7c478bd9Sstevel@tonic-gate 		}
769*7c478bd9Sstevel@tonic-gate 		if ((fd = open64(qfile, O_RDWR)) < 0) {
770*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "quotactl: ");
771*7c478bd9Sstevel@tonic-gate 			perror("open");
772*7c478bd9Sstevel@tonic-gate 			exit(31+1);
773*7c478bd9Sstevel@tonic-gate 		}
774*7c478bd9Sstevel@tonic-gate 	}	/* else */
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	quota.op = cmd;
777*7c478bd9Sstevel@tonic-gate 	quota.uid = uid;
778*7c478bd9Sstevel@tonic-gate 	quota.addr = addr;
779*7c478bd9Sstevel@tonic-gate 	status = ioctl(fd, Q_QUOTACTL, &quota);
780*7c478bd9Sstevel@tonic-gate 	if (fd != 0)
781*7c478bd9Sstevel@tonic-gate 		close(fd);
782*7c478bd9Sstevel@tonic-gate 	return (status);
783*7c478bd9Sstevel@tonic-gate }
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate char *
786*7c478bd9Sstevel@tonic-gate hasvfsopt(vfs, opt)
787*7c478bd9Sstevel@tonic-gate 	register struct vfstab *vfs;
788*7c478bd9Sstevel@tonic-gate 	register char *opt;
789*7c478bd9Sstevel@tonic-gate {
790*7c478bd9Sstevel@tonic-gate 	char *f, *opts;
791*7c478bd9Sstevel@tonic-gate 	static char *tmpopts;
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	if (tmpopts == 0) {
794*7c478bd9Sstevel@tonic-gate 		tmpopts = (char *)calloc(256, sizeof (char));
795*7c478bd9Sstevel@tonic-gate 		if (tmpopts == 0)
796*7c478bd9Sstevel@tonic-gate 			return (0);
797*7c478bd9Sstevel@tonic-gate 	}
798*7c478bd9Sstevel@tonic-gate 	strcpy(tmpopts, vfs->vfs_mntopts);
799*7c478bd9Sstevel@tonic-gate 	opts = tmpopts;
800*7c478bd9Sstevel@tonic-gate 	f = mntopt(&opts);
801*7c478bd9Sstevel@tonic-gate 	for (; *f; f = mntopt(&opts)) {
802*7c478bd9Sstevel@tonic-gate 		if (strncmp(opt, f, strlen(opt)) == 0)
803*7c478bd9Sstevel@tonic-gate 			return (f - tmpopts + vfs->vfs_mntopts);
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate 	return (NULL);
806*7c478bd9Sstevel@tonic-gate }
807