xref: /onnv-gate/usr/src/cmd/fs.d/cachefs/common/subr.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Common subroutines used by the programs in these subdirectories.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <locale.h>
34*0Sstevel@tonic-gate #include <stdio.h>
35*0Sstevel@tonic-gate #include <stdlib.h>
36*0Sstevel@tonic-gate #include <string.h>
37*0Sstevel@tonic-gate #include <assert.h>
38*0Sstevel@tonic-gate #include <unistd.h>
39*0Sstevel@tonic-gate #include <limits.h>
40*0Sstevel@tonic-gate #include <errno.h>
41*0Sstevel@tonic-gate #include <wait.h>
42*0Sstevel@tonic-gate #include <ctype.h>
43*0Sstevel@tonic-gate #include <fcntl.h>
44*0Sstevel@tonic-gate #include <ftw.h>
45*0Sstevel@tonic-gate #include <dirent.h>
46*0Sstevel@tonic-gate #include <sys/types.h>
47*0Sstevel@tonic-gate #include <sys/time.h>
48*0Sstevel@tonic-gate #include <utmpx.h>
49*0Sstevel@tonic-gate #include <sys/uio.h>
50*0Sstevel@tonic-gate #include <sys/param.h>
51*0Sstevel@tonic-gate #include <sys/stat.h>
52*0Sstevel@tonic-gate #include <sys/fcntl.h>
53*0Sstevel@tonic-gate #include <sys/mount.h>
54*0Sstevel@tonic-gate #include <sys/mntent.h>
55*0Sstevel@tonic-gate #include <sys/mnttab.h>
56*0Sstevel@tonic-gate #include <sys/mman.h>
57*0Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
58*0Sstevel@tonic-gate #include "subr.h"
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  *
62*0Sstevel@tonic-gate  *			cachefs_dir_lock
63*0Sstevel@tonic-gate  *
64*0Sstevel@tonic-gate  * Description:
65*0Sstevel@tonic-gate  *	Gets a lock on the cache directory.
66*0Sstevel@tonic-gate  *	To release the lock, call cachefs_dir_unlock
67*0Sstevel@tonic-gate  *	with the returned value.
68*0Sstevel@tonic-gate  * Arguments:
69*0Sstevel@tonic-gate  *	cachedirp	name of the cache directory
70*0Sstevel@tonic-gate  *	shared		1 if shared, 0 if not
71*0Sstevel@tonic-gate  * Returns:
72*0Sstevel@tonic-gate  *	Returns -1 if the lock cannot be obtained immediatly.
73*0Sstevel@tonic-gate  *	If the lock is obtained, returns a value >= 0.
74*0Sstevel@tonic-gate  * Preconditions:
75*0Sstevel@tonic-gate  *	precond(cachedirp)
76*0Sstevel@tonic-gate  */
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate int
79*0Sstevel@tonic-gate cachefs_dir_lock(const char *cachedirp, int shared)
80*0Sstevel@tonic-gate {
81*0Sstevel@tonic-gate 	int fd;
82*0Sstevel@tonic-gate 	int xx;
83*0Sstevel@tonic-gate 	int len;
84*0Sstevel@tonic-gate 	char buf[MAXPATHLEN];
85*0Sstevel@tonic-gate 	struct flock fl;
86*0Sstevel@tonic-gate 	char *strp;
87*0Sstevel@tonic-gate 	struct stat statb;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	/* make a path prefix to the cache directory lock file */
90*0Sstevel@tonic-gate 	strp = CACHEFS_ROOTRUN;
91*0Sstevel@tonic-gate 	xx = stat(strp, &statb);
92*0Sstevel@tonic-gate 	if ((xx < 0) || ((statb.st_mode & S_IFMT) != S_IFDIR))
93*0Sstevel@tonic-gate 		strp = "/tmp";
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate 	/* won't overflow */
96*0Sstevel@tonic-gate 	len = snprintf(buf, sizeof (buf), "%s/%s", strp, CACHEFS_LOCKDIR_PRE);
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	if (strlcat(buf, cachedirp, sizeof (buf)) >= sizeof (buf)) {
99*0Sstevel@tonic-gate 		pr_err(gettext("Cache directory name %s is too long"),
100*0Sstevel@tonic-gate 			cachedirp);
101*0Sstevel@tonic-gate 		return (-1);
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	strp = &buf[len];
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	while (strp = strchr(strp, '/')) { 	/* convert path to a file */
107*0Sstevel@tonic-gate 		*strp = '_';
108*0Sstevel@tonic-gate 	}
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	/*
111*0Sstevel@tonic-gate 	 * Create and open the cache directory lock file.
112*0Sstevel@tonic-gate 	 * This file will be <2G.
113*0Sstevel@tonic-gate 	 */
114*0Sstevel@tonic-gate 	fd = open(buf, O_RDWR | O_CREAT, 0700);
115*0Sstevel@tonic-gate 	if (fd == -1) {
116*0Sstevel@tonic-gate 		pr_err(gettext("Cannot open lock file %s"), buf);
117*0Sstevel@tonic-gate 		return (-1);
118*0Sstevel@tonic-gate 	}
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	/* try to set the lock */
121*0Sstevel@tonic-gate 	fl.l_type = (shared == 1) ? F_RDLCK : F_WRLCK;
122*0Sstevel@tonic-gate 	fl.l_whence = 0;
123*0Sstevel@tonic-gate 	fl.l_start = 1024;
124*0Sstevel@tonic-gate 	fl.l_len = 1024;
125*0Sstevel@tonic-gate 	fl.l_sysid = 0;
126*0Sstevel@tonic-gate 	fl.l_pid = 0;
127*0Sstevel@tonic-gate 	/* CACHEFS_LOCK_FILE will be <2GB */
128*0Sstevel@tonic-gate 	xx = fcntl(fd, F_SETLKW, &fl);
129*0Sstevel@tonic-gate 	if (xx == -1) {
130*0Sstevel@tonic-gate 		if (errno == EAGAIN) {
131*0Sstevel@tonic-gate 			pr_err(gettext("Cannot gain access to the "
132*0Sstevel@tonic-gate 			    "cache directory %s."), cachedirp);
133*0Sstevel@tonic-gate 		} else {
134*0Sstevel@tonic-gate 			pr_err(gettext("Unexpected failure on lock file %s %s"),
135*0Sstevel@tonic-gate 			    buf, strerror(errno));
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 		close(fd);
138*0Sstevel@tonic-gate 		return (-1);
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	/* return the file descriptor which can be used to release the lock */
142*0Sstevel@tonic-gate 	return (fd);
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate /*
146*0Sstevel@tonic-gate  *
147*0Sstevel@tonic-gate  *			cachefs_dir_unlock
148*0Sstevel@tonic-gate  *
149*0Sstevel@tonic-gate  * Description:
150*0Sstevel@tonic-gate  *	Releases an advisory lock on the cache directory.
151*0Sstevel@tonic-gate  * Arguments:
152*0Sstevel@tonic-gate  *	fd	cookie returned by cachefs_dir_lock
153*0Sstevel@tonic-gate  * Returns:
154*0Sstevel@tonic-gate  *	Returns -1 if the lock cannot be released or 0 for success.
155*0Sstevel@tonic-gate  * Preconditions:
156*0Sstevel@tonic-gate  */
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate int
159*0Sstevel@tonic-gate cachefs_dir_unlock(int fd)
160*0Sstevel@tonic-gate {
161*0Sstevel@tonic-gate 	struct flock fl;
162*0Sstevel@tonic-gate 	int error = 0;
163*0Sstevel@tonic-gate 	int xx;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/* release the lock */
166*0Sstevel@tonic-gate 	fl.l_type = F_UNLCK;
167*0Sstevel@tonic-gate 	fl.l_whence = 0;
168*0Sstevel@tonic-gate 	fl.l_start = 1024;
169*0Sstevel@tonic-gate 	fl.l_len = 1024;
170*0Sstevel@tonic-gate 	fl.l_sysid = 0;
171*0Sstevel@tonic-gate 	fl.l_pid = 0;
172*0Sstevel@tonic-gate 	/* fd will be <2GB */
173*0Sstevel@tonic-gate 	xx = fcntl(fd, F_SETLK, &fl);
174*0Sstevel@tonic-gate 	if (xx == -1) {
175*0Sstevel@tonic-gate 		pr_err(gettext("Unexpected failure releasing lock file %s"),
176*0Sstevel@tonic-gate 			strerror(errno));
177*0Sstevel@tonic-gate 		error = -1;
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	/* close the lock file */
181*0Sstevel@tonic-gate 	close(fd);
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	return (error);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate /*
187*0Sstevel@tonic-gate  *
188*0Sstevel@tonic-gate  *			cachefs_label_file_get
189*0Sstevel@tonic-gate  *
190*0Sstevel@tonic-gate  * Description:
191*0Sstevel@tonic-gate  *	Gets the contents of a cache label file.
192*0Sstevel@tonic-gate  *	Performs error checking on the file.
193*0Sstevel@tonic-gate  * Arguments:
194*0Sstevel@tonic-gate  *	filep	name of the cache label file
195*0Sstevel@tonic-gate  *	clabelp	where to put the file contents
196*0Sstevel@tonic-gate  * Returns:
197*0Sstevel@tonic-gate  *	Returns 0 for success or -1 if an error occurs.
198*0Sstevel@tonic-gate  * Preconditions:
199*0Sstevel@tonic-gate  *	precond(filep)
200*0Sstevel@tonic-gate  *	precond(clabelp)
201*0Sstevel@tonic-gate  */
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate int
204*0Sstevel@tonic-gate cachefs_label_file_get(const char *filep, struct cache_label *clabelp)
205*0Sstevel@tonic-gate {
206*0Sstevel@tonic-gate 	int xx;
207*0Sstevel@tonic-gate 	int fd;
208*0Sstevel@tonic-gate 	struct stat64 statinfo;
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	/* get info on the file */
211*0Sstevel@tonic-gate 	xx = lstat64(filep, &statinfo);
212*0Sstevel@tonic-gate 	if (xx == -1) {
213*0Sstevel@tonic-gate 		if (errno != ENOENT) {
214*0Sstevel@tonic-gate 			pr_err(gettext("Cannot stat file %s: %s"),
215*0Sstevel@tonic-gate 			    filep, strerror(errno));
216*0Sstevel@tonic-gate 		} else {
217*0Sstevel@tonic-gate 			pr_err(gettext("File %s does not exist."), filep);
218*0Sstevel@tonic-gate 		}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 		return (-1);
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	/* if the file is the wrong type */
224*0Sstevel@tonic-gate 	if (!S_ISREG(statinfo.st_mode)) {
225*0Sstevel@tonic-gate 		pr_err(gettext("Cache label file %s corrupted"), filep);
226*0Sstevel@tonic-gate 		return (-1);
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	/* if the file is the wrong size; it will be <2GB */
230*0Sstevel@tonic-gate 	if (statinfo.st_size != (offset_t)sizeof (struct cache_label)) {
231*0Sstevel@tonic-gate 		pr_err(gettext("Cache label file %s wrong size"), filep);
232*0Sstevel@tonic-gate 		return (-1);
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	/* open the cache label file */
236*0Sstevel@tonic-gate 	fd = open(filep, O_RDONLY);
237*0Sstevel@tonic-gate 	if (fd == -1) {
238*0Sstevel@tonic-gate 		pr_err(gettext("Error opening %s: %s"), filep,
239*0Sstevel@tonic-gate 		    strerror(errno));
240*0Sstevel@tonic-gate 		return (-1);
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	/* read the current set of parameters */
244*0Sstevel@tonic-gate 	xx = read(fd, clabelp, sizeof (struct cache_label));
245*0Sstevel@tonic-gate 	if (xx != sizeof (struct cache_label)) {
246*0Sstevel@tonic-gate 		pr_err(gettext("Reading %s failed: %s\n"), filep,
247*0Sstevel@tonic-gate 		    strerror(errno));
248*0Sstevel@tonic-gate 		close(fd);
249*0Sstevel@tonic-gate 		return (-1);
250*0Sstevel@tonic-gate 	}
251*0Sstevel@tonic-gate 	close(fd);
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/* return success */
254*0Sstevel@tonic-gate 	return (0);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate  *
259*0Sstevel@tonic-gate  *			cachefs_label_file_put
260*0Sstevel@tonic-gate  *
261*0Sstevel@tonic-gate  * Description:
262*0Sstevel@tonic-gate  *	Outputs the contents of a cache label object to a file.
263*0Sstevel@tonic-gate  * Arguments:
264*0Sstevel@tonic-gate  *	filep	name of the cache label file
265*0Sstevel@tonic-gate  *	clabelp	where to get the file contents
266*0Sstevel@tonic-gate  * Returns:
267*0Sstevel@tonic-gate  *	Returns 0 for success or -1 if an error occurs.
268*0Sstevel@tonic-gate  * Preconditions:
269*0Sstevel@tonic-gate  *	precond(filep)
270*0Sstevel@tonic-gate  *	precond(clabelp)
271*0Sstevel@tonic-gate  */
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate int
274*0Sstevel@tonic-gate cachefs_label_file_put(const char *filep, struct cache_label *clabelp)
275*0Sstevel@tonic-gate {
276*0Sstevel@tonic-gate 	int xx;
277*0Sstevel@tonic-gate 	int fd;
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	/* get rid of the file if it already exists */
280*0Sstevel@tonic-gate 	xx = unlink(filep);
281*0Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
282*0Sstevel@tonic-gate 		pr_err(gettext("Could not remove %s: %s"), filep,
283*0Sstevel@tonic-gate 		    strerror(errno));
284*0Sstevel@tonic-gate 		return (-1);
285*0Sstevel@tonic-gate 	}
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	/* open the cache label file; this file will be <2GB */
288*0Sstevel@tonic-gate 	fd = open(filep, O_CREAT | O_RDWR, 0600);
289*0Sstevel@tonic-gate 	if (fd == -1) {
290*0Sstevel@tonic-gate 		pr_err(gettext("Error creating %s: %s"), filep,
291*0Sstevel@tonic-gate 		    strerror(errno));
292*0Sstevel@tonic-gate 		return (-1);
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	/* write out the cache label object */
296*0Sstevel@tonic-gate 	xx = write(fd, clabelp, sizeof (struct cache_label));
297*0Sstevel@tonic-gate 	if (xx != sizeof (struct cache_label)) {
298*0Sstevel@tonic-gate 		pr_err(gettext("Writing %s failed: %s"), filep,
299*0Sstevel@tonic-gate 		    strerror(errno));
300*0Sstevel@tonic-gate 		close(fd);
301*0Sstevel@tonic-gate 		return (-1);
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	/* make sure the contents get to disk */
305*0Sstevel@tonic-gate 	if (fsync(fd) != 0) {
306*0Sstevel@tonic-gate 		pr_err(gettext("Writing %s failed on sync: %s"), filep,
307*0Sstevel@tonic-gate 		    strerror(errno));
308*0Sstevel@tonic-gate 		close(fd);
309*0Sstevel@tonic-gate 		return (-1);
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	close(fd);
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	/* return success */
315*0Sstevel@tonic-gate 	return (0);
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate int
319*0Sstevel@tonic-gate cachefs_label_file_vcheck(char *filep, struct cache_label *clabelp)
320*0Sstevel@tonic-gate {
321*0Sstevel@tonic-gate 	/* check for an invalid version number */
322*0Sstevel@tonic-gate 	if (clabelp->cl_cfsversion != CFSVERSION) {
323*0Sstevel@tonic-gate 		pr_err(gettext("Cache label file %s corrupted"), filep);
324*0Sstevel@tonic-gate 		return (-1);
325*0Sstevel@tonic-gate 	}
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	return (0);
328*0Sstevel@tonic-gate }
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate /*
331*0Sstevel@tonic-gate  *
332*0Sstevel@tonic-gate  *			cachefs_inuse
333*0Sstevel@tonic-gate  *
334*0Sstevel@tonic-gate  * Description:
335*0Sstevel@tonic-gate  *	Tests whether or not the cache directory is in use by
336*0Sstevel@tonic-gate  *	the cache file system.
337*0Sstevel@tonic-gate  * Arguments:
338*0Sstevel@tonic-gate  *	cachedirp	name of the file system cache directory
339*0Sstevel@tonic-gate  * Returns:
340*0Sstevel@tonic-gate  *	Returns 1 if the cache is in use or an error, 0 if not.
341*0Sstevel@tonic-gate  * Preconditions:
342*0Sstevel@tonic-gate  *	precond(cachedirp)
343*0Sstevel@tonic-gate  */
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate int
346*0Sstevel@tonic-gate cachefs_inuse(const char *cachedirp)
347*0Sstevel@tonic-gate {
348*0Sstevel@tonic-gate 	int fd;
349*0Sstevel@tonic-gate 	int xx;
350*0Sstevel@tonic-gate 	char buf[MAXPATHLEN];
351*0Sstevel@tonic-gate 	char *lockp = CACHEFS_LOCK_FILE;
352*0Sstevel@tonic-gate 	struct flock fl;
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	/* see if path name is too long */
355*0Sstevel@tonic-gate 	xx = strlen(cachedirp) + strlen(lockp) + 3;
356*0Sstevel@tonic-gate 	if (xx >= MAXPATHLEN) {
357*0Sstevel@tonic-gate 		pr_err(gettext("Cache directory name %s is too long"),
358*0Sstevel@tonic-gate 		    cachedirp);
359*0Sstevel@tonic-gate 		return (1);
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	/* make a path to the cache directory lock file */
363*0Sstevel@tonic-gate 	snprintf(buf, sizeof (buf), "%s/%s", cachedirp, lockp);
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	/* Open the kernel in use lock file.  This file will be <2GB. */
366*0Sstevel@tonic-gate 	fd = open(buf, O_RDWR, 0700);
367*0Sstevel@tonic-gate 	if (fd == -1) {
368*0Sstevel@tonic-gate 		pr_err(gettext("Cannot open lock file %s"), buf);
369*0Sstevel@tonic-gate 		return (1);
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	/* test the lock status */
373*0Sstevel@tonic-gate 	fl.l_type = F_WRLCK;
374*0Sstevel@tonic-gate 	fl.l_whence = 0;
375*0Sstevel@tonic-gate 	fl.l_start = 0;
376*0Sstevel@tonic-gate 	fl.l_len = 1024;
377*0Sstevel@tonic-gate 	fl.l_sysid = 0;
378*0Sstevel@tonic-gate 	fl.l_pid = 0;
379*0Sstevel@tonic-gate 	xx = fcntl(fd, F_GETLK, &fl);
380*0Sstevel@tonic-gate 	if (xx == -1) {
381*0Sstevel@tonic-gate 		pr_err(gettext("Unexpected failure on lock file %s %s"),
382*0Sstevel@tonic-gate 		    buf, strerror(errno));
383*0Sstevel@tonic-gate 		close(fd);
384*0Sstevel@tonic-gate 		return (1);
385*0Sstevel@tonic-gate 	}
386*0Sstevel@tonic-gate 	close(fd);
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	if (fl.l_type == F_UNLCK)
389*0Sstevel@tonic-gate 		xx = 0;
390*0Sstevel@tonic-gate 	else
391*0Sstevel@tonic-gate 		xx = 1;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	/* return whether or not the cache is in use */
394*0Sstevel@tonic-gate 	return (xx);
395*0Sstevel@tonic-gate }
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate /*
398*0Sstevel@tonic-gate  *
399*0Sstevel@tonic-gate  *			cachefs_resouce_size
400*0Sstevel@tonic-gate  *
401*0Sstevel@tonic-gate  * Description:
402*0Sstevel@tonic-gate  *	Returns information about a resource file.
403*0Sstevel@tonic-gate  * Arguments:
404*0Sstevel@tonic-gate  *	maxinodes	number of inodes to be managed by the resource file
405*0Sstevel@tonic-gate  *	rinfop		set to info about the resource file
406*0Sstevel@tonic-gate  * Returns:
407*0Sstevel@tonic-gate  * Preconditions:
408*0Sstevel@tonic-gate  *	precond(rinfop)
409*0Sstevel@tonic-gate  */
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate void
412*0Sstevel@tonic-gate cachefs_resource_size(int maxinodes, struct cachefs_rinfo *rinfop)
413*0Sstevel@tonic-gate {
414*0Sstevel@tonic-gate 	int fsize;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	fsize = MAXBSIZE;
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	rinfop->r_ptroffset = fsize;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	fsize += MAXBSIZE * (maxinodes / CACHEFS_RLPMBS);
421*0Sstevel@tonic-gate 	if ((maxinodes % CACHEFS_RLPMBS) != 0)
422*0Sstevel@tonic-gate 		fsize += MAXBSIZE;
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	rinfop->r_fsize = fsize;
425*0Sstevel@tonic-gate }
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate /*
428*0Sstevel@tonic-gate  *
429*0Sstevel@tonic-gate  *			cachefs_create_cache
430*0Sstevel@tonic-gate  *
431*0Sstevel@tonic-gate  * Description:
432*0Sstevel@tonic-gate  *	Creates the specified cache directory and populates it as
433*0Sstevel@tonic-gate  *	needed by CFS.
434*0Sstevel@tonic-gate  * Arguments:
435*0Sstevel@tonic-gate  *	dirp		the name of the cache directory
436*0Sstevel@tonic-gate  *	uv		user values (may be NULL)
437*0Sstevel@tonic-gate  *	clabel		label file contents, or placeholder for this
438*0Sstevel@tonic-gate  * Returns:
439*0Sstevel@tonic-gate  *	Returns 0 for success or:
440*0Sstevel@tonic-gate  *		-1 for an error
441*0Sstevel@tonic-gate  *		-2 for an error and cache directory partially created
442*0Sstevel@tonic-gate  * Preconditions:
443*0Sstevel@tonic-gate  *	precond(dirp)
444*0Sstevel@tonic-gate  */
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate int
447*0Sstevel@tonic-gate cachefs_create_cache(char *dirp, struct cachefs_user_values *uv,
448*0Sstevel@tonic-gate     struct cache_label *clabel)
449*0Sstevel@tonic-gate {
450*0Sstevel@tonic-gate 	int xx;
451*0Sstevel@tonic-gate 	char path[CACHEFS_XMAXPATH];
452*0Sstevel@tonic-gate 	int fd;
453*0Sstevel@tonic-gate 	void *bufp;
454*0Sstevel@tonic-gate 	int cnt;
455*0Sstevel@tonic-gate 	struct cache_usage cu;
456*0Sstevel@tonic-gate 	FILE *fp;
457*0Sstevel@tonic-gate 	char *parent;
458*0Sstevel@tonic-gate 	struct statvfs64 svfs;
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	cu.cu_blksused = 0;
461*0Sstevel@tonic-gate 	cu.cu_filesused = 0;
462*0Sstevel@tonic-gate 	cu.cu_flags = 0;
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	/* make sure cache dir name is not too long */
465*0Sstevel@tonic-gate 	if (strlen(dirp) > (size_t)PATH_MAX) {
466*0Sstevel@tonic-gate 		pr_err(gettext("path name %s is too long."), dirp);
467*0Sstevel@tonic-gate 		return (-1);
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	/* ensure the path isn't in cachefs */
471*0Sstevel@tonic-gate 	parent = cachefs_file_to_dir(dirp);
472*0Sstevel@tonic-gate 	if (parent == NULL) {
473*0Sstevel@tonic-gate 		pr_err(gettext("Out of memory"));
474*0Sstevel@tonic-gate 		return (-1);
475*0Sstevel@tonic-gate 	}
476*0Sstevel@tonic-gate 	if (statvfs64(parent, &svfs) != 0) {
477*0Sstevel@tonic-gate 		pr_err(gettext("%s: %s"), parent, strerror(errno));
478*0Sstevel@tonic-gate 		free(parent);
479*0Sstevel@tonic-gate 		return (-1);
480*0Sstevel@tonic-gate 	}
481*0Sstevel@tonic-gate 	if (strcmp(svfs.f_basetype, CACHEFS_BASETYPE) == 0) {
482*0Sstevel@tonic-gate 		pr_err(gettext("Cannot create cache in cachefs filesystem"));
483*0Sstevel@tonic-gate 		free(parent);
484*0Sstevel@tonic-gate 		return (-1);
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 	free(parent);
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	/* make the directory */
489*0Sstevel@tonic-gate 	if (mkdir(dirp, 0) == -1) {
490*0Sstevel@tonic-gate 		switch (errno) {
491*0Sstevel@tonic-gate 		case EEXIST:
492*0Sstevel@tonic-gate 			pr_err(gettext("%s already exists."), dirp);
493*0Sstevel@tonic-gate 			break;
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 		default:
496*0Sstevel@tonic-gate 			pr_err(gettext("mkdir %s failed: %s"),
497*0Sstevel@tonic-gate 			    dirp, strerror(errno));
498*0Sstevel@tonic-gate 		}
499*0Sstevel@tonic-gate 		return (-1);
500*0Sstevel@tonic-gate 	}
501*0Sstevel@tonic-gate 	cu.cu_filesused += 1;
502*0Sstevel@tonic-gate 	cu.cu_blksused += 1;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	/* convert user values to a cache_label */
505*0Sstevel@tonic-gate 	if (uv != NULL) {
506*0Sstevel@tonic-gate 		xx = cachefs_convert_uv2cl(uv, clabel, dirp);
507*0Sstevel@tonic-gate 		if (xx)
508*0Sstevel@tonic-gate 			return (-2);
509*0Sstevel@tonic-gate 	}
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	/*
512*0Sstevel@tonic-gate 	 * Create the cache directory lock file.
513*0Sstevel@tonic-gate 	 * Used by the kernel module to indicate the cache is in use.
514*0Sstevel@tonic-gate 	 * This file will be <2G.
515*0Sstevel@tonic-gate 	 */
516*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOCK_FILE);
517*0Sstevel@tonic-gate 	fd = open(path, O_RDWR | O_CREAT, 0700);
518*0Sstevel@tonic-gate 	if (fd == -1) {
519*0Sstevel@tonic-gate 		pr_err(gettext("Cannot create lock file %s"), path);
520*0Sstevel@tonic-gate 		return (-1);
521*0Sstevel@tonic-gate 	}
522*0Sstevel@tonic-gate 	close(fd);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	/* make the directory for the back file system mount points */
525*0Sstevel@tonic-gate 	/* note: we do not count this directory in the resources */
526*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
527*0Sstevel@tonic-gate 	if (mkdir(path, 0700) == -1) {
528*0Sstevel@tonic-gate 		pr_err(gettext("mkdir %s failed: %s"), path,
529*0Sstevel@tonic-gate 		    strerror(errno));
530*0Sstevel@tonic-gate 		return (-2);
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	/* make the directory for lost+found */
534*0Sstevel@tonic-gate 	/* note: we do not count this directory in the resources */
535*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOSTFOUND_NAME);
536*0Sstevel@tonic-gate 	if (mkdir(path, 0700) == -1) {
537*0Sstevel@tonic-gate 		pr_err(gettext("mkdir %s failed: %s"), path,
538*0Sstevel@tonic-gate 		    strerror(errno));
539*0Sstevel@tonic-gate 		return (-2);
540*0Sstevel@tonic-gate 	}
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	/* make the networker "don't back up" file; this file is <2GB */
543*0Sstevel@tonic-gate 	xx = 0;
544*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
545*0Sstevel@tonic-gate 	if ((fp = fopen(path, "w")) != NULL) {
546*0Sstevel@tonic-gate 		if (realpath(dirp, path) != NULL) {
547*0Sstevel@tonic-gate 			fprintf(fp, "<< ./ >>\n", path);
548*0Sstevel@tonic-gate 			fprintf(fp, "+skip: .?* *\n");
549*0Sstevel@tonic-gate 			if (fclose(fp) == 0)
550*0Sstevel@tonic-gate 				xx = 1;
551*0Sstevel@tonic-gate 		}
552*0Sstevel@tonic-gate 	}
553*0Sstevel@tonic-gate 	if (xx == 0) {
554*0Sstevel@tonic-gate 		snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
555*0Sstevel@tonic-gate 		pr_err(gettext("can't create %s"), path);
556*0Sstevel@tonic-gate 		(void) unlink(path);
557*0Sstevel@tonic-gate 	} else {
558*0Sstevel@tonic-gate 		cu.cu_filesused += 1;
559*0Sstevel@tonic-gate 		cu.cu_blksused += 1;
560*0Sstevel@tonic-gate 	}
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	/* create the unmount file */
563*0Sstevel@tonic-gate 	xx = 0;
564*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_UNMNT_FILE);
565*0Sstevel@tonic-gate 	if ((fp = fopen(path, "w")) != NULL) {
566*0Sstevel@tonic-gate 		time32_t btime;
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 		btime = get_boottime();
569*0Sstevel@tonic-gate 		fwrite((void *)&btime, sizeof (btime), 1, fp);
570*0Sstevel@tonic-gate 		if (fclose(fp) == 0)
571*0Sstevel@tonic-gate 			xx = 1;
572*0Sstevel@tonic-gate 	}
573*0Sstevel@tonic-gate 	if (xx == 0)
574*0Sstevel@tonic-gate 		pr_err(gettext("can't create .cfs_unmnt file"));
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	/* create the cache label file */
577*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
578*0Sstevel@tonic-gate 	xx = cachefs_label_file_put(path, clabel);
579*0Sstevel@tonic-gate 	if (xx == -1) {
580*0Sstevel@tonic-gate 		pr_err(gettext("creating %s failed."), path);
581*0Sstevel@tonic-gate 		return (-2);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	cu.cu_filesused += 1;
584*0Sstevel@tonic-gate 	cu.cu_blksused += 1;
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	/* create the cache label duplicate file */
587*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s.dup", dirp, CACHELABEL_NAME);
588*0Sstevel@tonic-gate 	xx = cachefs_label_file_put(path, clabel);
589*0Sstevel@tonic-gate 	if (xx == -1) {
590*0Sstevel@tonic-gate 		pr_err(gettext("creating %s failed."), path);
591*0Sstevel@tonic-gate 		return (-2);
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate 	cu.cu_filesused += 1;
594*0Sstevel@tonic-gate 	cu.cu_blksused += 1;
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	/* create the resouce file; this file will be <2GB */
597*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, RESOURCE_NAME);
598*0Sstevel@tonic-gate 	fd = open(path, O_CREAT | O_RDWR, 0600);
599*0Sstevel@tonic-gate 	if (fd == -1) {
600*0Sstevel@tonic-gate 		pr_err(gettext("create %s failed: %s"), path,
601*0Sstevel@tonic-gate 		    strerror(errno));
602*0Sstevel@tonic-gate 		return (-2);
603*0Sstevel@tonic-gate 	}
604*0Sstevel@tonic-gate 	cu.cu_filesused += 1;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	/* allocate a zeroed buffer for filling the resouce file */
607*0Sstevel@tonic-gate 	bufp = calloc(1, MAXBSIZE);
608*0Sstevel@tonic-gate 	if (bufp == NULL) {
609*0Sstevel@tonic-gate 		pr_err(gettext("out of space %d."), MAXBSIZE);
610*0Sstevel@tonic-gate 		close(fd);
611*0Sstevel@tonic-gate 		return (-2);
612*0Sstevel@tonic-gate 	}
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	/* determine number of MAXBSIZE chunks to make the file */
615*0Sstevel@tonic-gate 	cnt = 1;	/* for the header */
616*0Sstevel@tonic-gate 	cnt += clabel->cl_maxinodes / CACHEFS_RLPMBS;
617*0Sstevel@tonic-gate 	if ((clabel->cl_maxinodes % CACHEFS_RLPMBS) != 0)
618*0Sstevel@tonic-gate 		++cnt;
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	/* fill up the file with zeros */
621*0Sstevel@tonic-gate 	for (xx = 0; xx < cnt; xx++) {
622*0Sstevel@tonic-gate 		if (write(fd, bufp, MAXBSIZE) != MAXBSIZE) {
623*0Sstevel@tonic-gate 			pr_err(gettext("write %s failed: %s"), path,
624*0Sstevel@tonic-gate 			    strerror(errno));
625*0Sstevel@tonic-gate 			close(fd);
626*0Sstevel@tonic-gate 			free(bufp);
627*0Sstevel@tonic-gate 			return (-2);
628*0Sstevel@tonic-gate 		}
629*0Sstevel@tonic-gate 	}
630*0Sstevel@tonic-gate 	free(bufp);
631*0Sstevel@tonic-gate 	cu.cu_blksused += cnt;
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	/* position to the begining of the file */
634*0Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) == -1) {
635*0Sstevel@tonic-gate 		pr_err(gettext("lseek %s failed: %s"), path,
636*0Sstevel@tonic-gate 		    strerror(errno));
637*0Sstevel@tonic-gate 		close(fd);
638*0Sstevel@tonic-gate 		return (-2);
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	/* write the cache usage structure */
642*0Sstevel@tonic-gate 	xx = sizeof (struct cache_usage);
643*0Sstevel@tonic-gate 	if (write(fd, &cu, xx) != xx) {
644*0Sstevel@tonic-gate 		pr_err(gettext("cu write %s failed: %s"), path,
645*0Sstevel@tonic-gate 		    strerror(errno));
646*0Sstevel@tonic-gate 		close(fd);
647*0Sstevel@tonic-gate 		return (-2);
648*0Sstevel@tonic-gate 	}
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	/* make sure the contents get to disk */
651*0Sstevel@tonic-gate 	if (fsync(fd) != 0) {
652*0Sstevel@tonic-gate 		pr_err(gettext("fsync %s failed: %s"), path,
653*0Sstevel@tonic-gate 		    strerror(errno));
654*0Sstevel@tonic-gate 		close(fd);
655*0Sstevel@tonic-gate 		return (-2);
656*0Sstevel@tonic-gate 	}
657*0Sstevel@tonic-gate 	close(fd);
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	/* return success */
660*0Sstevel@tonic-gate 	return (0);
661*0Sstevel@tonic-gate }
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate /*
664*0Sstevel@tonic-gate  *
665*0Sstevel@tonic-gate  *			cachefs_delete_all_cache
666*0Sstevel@tonic-gate  *
667*0Sstevel@tonic-gate  * Description:
668*0Sstevel@tonic-gate  *	Delete all caches in cache directory.
669*0Sstevel@tonic-gate  * Arguments:
670*0Sstevel@tonic-gate  *	dirp	the pathname of of the cache directory to delete
671*0Sstevel@tonic-gate  * Returns:
672*0Sstevel@tonic-gate  *	Returns 0 for success or -1 for an error.
673*0Sstevel@tonic-gate  * Preconditions:
674*0Sstevel@tonic-gate  *	precond(dirp)
675*0Sstevel@tonic-gate  */
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate int
678*0Sstevel@tonic-gate cachefs_delete_all_cache(char *dirp)
679*0Sstevel@tonic-gate {
680*0Sstevel@tonic-gate 	DIR *dp;
681*0Sstevel@tonic-gate 	struct dirent64 *dep;
682*0Sstevel@tonic-gate 	int xx;
683*0Sstevel@tonic-gate 	char path[CACHEFS_XMAXPATH];
684*0Sstevel@tonic-gate 	struct stat64 statinfo;
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	/* make sure cache dir name is not too long */
687*0Sstevel@tonic-gate 	if (strlen(dirp) > (size_t)PATH_MAX) {
688*0Sstevel@tonic-gate 		pr_err(gettext("path name %s is too long."),
689*0Sstevel@tonic-gate 		    dirp);
690*0Sstevel@tonic-gate 		return (-1);
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	/* check that dirp is probably a cachefs directory */
694*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
695*0Sstevel@tonic-gate 	xx = access(path, R_OK | W_OK | X_OK);
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
698*0Sstevel@tonic-gate 	xx |= access(path, R_OK | W_OK);
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 	if (xx) {
701*0Sstevel@tonic-gate 		pr_err(gettext("%s does not appear to be a "
702*0Sstevel@tonic-gate 		    "cachefs cache directory."), dirp);
703*0Sstevel@tonic-gate 		return (-1);
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	/* remove the lost+found directory if it exists and is empty */
707*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOSTFOUND_NAME);
708*0Sstevel@tonic-gate 	xx = rmdir(path);
709*0Sstevel@tonic-gate 	if (xx == -1) {
710*0Sstevel@tonic-gate 		if (errno == EEXIST) {
711*0Sstevel@tonic-gate 			pr_err(gettext("Cannot delete cache '%s'.  "
712*0Sstevel@tonic-gate 			    "First move files in '%s' to a safe location."),
713*0Sstevel@tonic-gate 			    dirp, path);
714*0Sstevel@tonic-gate 			return (-1);
715*0Sstevel@tonic-gate 		} else if (errno != ENOENT) {
716*0Sstevel@tonic-gate 			pr_err(gettext("rmdir %s failed: %s"), path,
717*0Sstevel@tonic-gate 			    strerror(errno));
718*0Sstevel@tonic-gate 			return (-1);
719*0Sstevel@tonic-gate 		}
720*0Sstevel@tonic-gate 	}
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	/* delete the back FS mount point directory if it exists */
723*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
724*0Sstevel@tonic-gate 	xx = lstat64(path, &statinfo);
725*0Sstevel@tonic-gate 	if (xx == -1) {
726*0Sstevel@tonic-gate 		if (errno != ENOENT) {
727*0Sstevel@tonic-gate 			pr_err(gettext("lstat %s failed: %s"), path,
728*0Sstevel@tonic-gate 			    strerror(errno));
729*0Sstevel@tonic-gate 			return (-1);
730*0Sstevel@tonic-gate 		}
731*0Sstevel@tonic-gate 	} else {
732*0Sstevel@tonic-gate 		xx = nftw64(path, cachefs_delete_file, 16,
733*0Sstevel@tonic-gate 		    FTW_PHYS | FTW_DEPTH | FTW_MOUNT);
734*0Sstevel@tonic-gate 		if (xx == -1) {
735*0Sstevel@tonic-gate 			pr_err(gettext("unable to delete %s"), path);
736*0Sstevel@tonic-gate 			return (-1);
737*0Sstevel@tonic-gate 		}
738*0Sstevel@tonic-gate 	}
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	/* open the cache directory specified */
741*0Sstevel@tonic-gate 	if ((dp = opendir(dirp)) == NULL) {
742*0Sstevel@tonic-gate 		pr_err(gettext("cannot open cache directory %s: %s"),
743*0Sstevel@tonic-gate 		    dirp, strerror(errno));
744*0Sstevel@tonic-gate 		return (-1);
745*0Sstevel@tonic-gate 	}
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 	/* read the file names in the cache directory */
748*0Sstevel@tonic-gate 	while ((dep = readdir64(dp)) != NULL) {
749*0Sstevel@tonic-gate 		/* ignore . and .. */
750*0Sstevel@tonic-gate 		if (strcmp(dep->d_name, ".") == 0 ||
751*0Sstevel@tonic-gate 				strcmp(dep->d_name, "..") == 0)
752*0Sstevel@tonic-gate 			continue;
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 		/* stat the file */
755*0Sstevel@tonic-gate 		snprintf(path, sizeof (path), "%s/%s", dirp, dep->d_name);
756*0Sstevel@tonic-gate 		xx = lstat64(path, &statinfo);
757*0Sstevel@tonic-gate 		if (xx == -1) {
758*0Sstevel@tonic-gate 			if (errno == ENOENT) {
759*0Sstevel@tonic-gate 				/* delete_cache may have nuked a directory */
760*0Sstevel@tonic-gate 				continue;
761*0Sstevel@tonic-gate 			}
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 			pr_err(gettext("lstat %s failed: %s"),
764*0Sstevel@tonic-gate 			    path, strerror(errno));
765*0Sstevel@tonic-gate 			closedir(dp);
766*0Sstevel@tonic-gate 			return (-1);
767*0Sstevel@tonic-gate 		}
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 		/* ignore anything that is not a link */
770*0Sstevel@tonic-gate 		if (!S_ISLNK(statinfo.st_mode))
771*0Sstevel@tonic-gate 			continue;
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 		/* delete the file system cache directory */
774*0Sstevel@tonic-gate 		xx = cachefs_delete_cache(dirp, dep->d_name);
775*0Sstevel@tonic-gate 		if (xx) {
776*0Sstevel@tonic-gate 			closedir(dp);
777*0Sstevel@tonic-gate 			return (-1);
778*0Sstevel@tonic-gate 		}
779*0Sstevel@tonic-gate 	}
780*0Sstevel@tonic-gate 	closedir(dp);
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	/* remove the cache dir unmount file */
783*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_UNMNT_FILE);
784*0Sstevel@tonic-gate 	xx = unlink(path);
785*0Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
786*0Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
787*0Sstevel@tonic-gate 		    strerror(errno));
788*0Sstevel@tonic-gate 		return (-1);
789*0Sstevel@tonic-gate 	}
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	/* remove the cache label file */
792*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
793*0Sstevel@tonic-gate 	xx = unlink(path);
794*0Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
795*0Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
796*0Sstevel@tonic-gate 		    strerror(errno));
797*0Sstevel@tonic-gate 		return (-1);
798*0Sstevel@tonic-gate 	}
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	/* remove the cache label duplicate file */
801*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s.dup", dirp, CACHELABEL_NAME);
802*0Sstevel@tonic-gate 	xx = unlink(path);
803*0Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
804*0Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
805*0Sstevel@tonic-gate 		    strerror(errno));
806*0Sstevel@tonic-gate 		return (-1);
807*0Sstevel@tonic-gate 	}
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	/* remove the resource file */
810*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, RESOURCE_NAME);
811*0Sstevel@tonic-gate 	xx = unlink(path);
812*0Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
813*0Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
814*0Sstevel@tonic-gate 		    strerror(errno));
815*0Sstevel@tonic-gate 		return (-1);
816*0Sstevel@tonic-gate 	}
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	/* remove the cachefslog file if it exists */
819*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, LOG_STATUS_NAME);
820*0Sstevel@tonic-gate 	(void) unlink(path);
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 	/* remove the networker "don't back up" file if it exists */
823*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
824*0Sstevel@tonic-gate 	(void) unlink(path);
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate 	/* remove the lock file */
827*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOCK_FILE);
828*0Sstevel@tonic-gate 	xx = unlink(path);
829*0Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
830*0Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
831*0Sstevel@tonic-gate 		    strerror(errno));
832*0Sstevel@tonic-gate 		return (-1);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	/* remove the directory */
836*0Sstevel@tonic-gate 	xx = rmdir(dirp);
837*0Sstevel@tonic-gate 	if (xx == -1) {
838*0Sstevel@tonic-gate 		pr_err(gettext("rmdir %s failed: %s"), dirp,
839*0Sstevel@tonic-gate 		    strerror(errno));
840*0Sstevel@tonic-gate 		return (-1);
841*0Sstevel@tonic-gate 	}
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	/* return success */
844*0Sstevel@tonic-gate 	return (0);
845*0Sstevel@tonic-gate }
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate /*
848*0Sstevel@tonic-gate  *
849*0Sstevel@tonic-gate  *			cachefs_delete_cache
850*0Sstevel@tonic-gate  *
851*0Sstevel@tonic-gate  * Description:
852*0Sstevel@tonic-gate  *	Deletes the specified file system cache.
853*0Sstevel@tonic-gate  * Arguments:
854*0Sstevel@tonic-gate  *	dirp	cache directory name
855*0Sstevel@tonic-gate  *	namep	file system cache directory to delete
856*0Sstevel@tonic-gate  * Returns:
857*0Sstevel@tonic-gate  *	Returns 0 for success, -1 for failure.
858*0Sstevel@tonic-gate  * Preconditions:
859*0Sstevel@tonic-gate  *	precond(dirp)
860*0Sstevel@tonic-gate  *	precond(namep)
861*0Sstevel@tonic-gate  */
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate int
864*0Sstevel@tonic-gate cachefs_delete_cache(char *dirp, char *namep)
865*0Sstevel@tonic-gate {
866*0Sstevel@tonic-gate 	char path[CACHEFS_XMAXPATH];
867*0Sstevel@tonic-gate 	char buf[CACHEFS_XMAXPATH];
868*0Sstevel@tonic-gate 	int xx;
869*0Sstevel@tonic-gate 	struct stat64 statinfo;
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	/* make sure cache dir name is not too long */
872*0Sstevel@tonic-gate 	if (strlen(dirp) > (size_t)PATH_MAX) {
873*0Sstevel@tonic-gate 		pr_err(gettext("path name %s is too long."),
874*0Sstevel@tonic-gate 		    dirp);
875*0Sstevel@tonic-gate 		return (-1);
876*0Sstevel@tonic-gate 	}
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	/* construct the path name of the file system cache directory */
879*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, namep);
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	/* stat the specified file */
882*0Sstevel@tonic-gate 	xx = lstat64(path, &statinfo);
883*0Sstevel@tonic-gate 	if (xx == -1) {
884*0Sstevel@tonic-gate 		pr_err(gettext("lstat %s failed: %s"), path,
885*0Sstevel@tonic-gate 		    strerror(errno));
886*0Sstevel@tonic-gate 		return (-1);
887*0Sstevel@tonic-gate 	}
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate 	/* make sure name is a symbolic link */
890*0Sstevel@tonic-gate 	if (!S_ISLNK(statinfo.st_mode)) {
891*0Sstevel@tonic-gate 		pr_err(gettext("\"%s\" is not a valid cache id."), namep);
892*0Sstevel@tonic-gate 		return (-1);
893*0Sstevel@tonic-gate 	}
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 	/* read the contents of the symbolic link */
896*0Sstevel@tonic-gate 	xx = readlink(path, buf, sizeof (buf));
897*0Sstevel@tonic-gate 	if (xx == -1) {
898*0Sstevel@tonic-gate 		pr_err(gettext("Readlink of %s failed: %s"), path,
899*0Sstevel@tonic-gate 		    strerror(errno));
900*0Sstevel@tonic-gate 		return (-1);
901*0Sstevel@tonic-gate 	}
902*0Sstevel@tonic-gate 	buf[xx] = '\0';
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 	/* remove the directory */
905*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, buf);
906*0Sstevel@tonic-gate 	xx = nftw64(path, cachefs_delete_file, 16,
907*0Sstevel@tonic-gate 	    FTW_PHYS | FTW_DEPTH | FTW_MOUNT);
908*0Sstevel@tonic-gate 	if (xx == -1) {
909*0Sstevel@tonic-gate 		pr_err(gettext("directory walk of %s failed."), dirp);
910*0Sstevel@tonic-gate 		return (-1);
911*0Sstevel@tonic-gate 	}
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	/* delete the link */
914*0Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, namep);
915*0Sstevel@tonic-gate 	if (unlink(path) == -1) {
916*0Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
917*0Sstevel@tonic-gate 		    strerror(errno));
918*0Sstevel@tonic-gate 		return (-1);
919*0Sstevel@tonic-gate 	}
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	/* return success */
922*0Sstevel@tonic-gate 	return (0);
923*0Sstevel@tonic-gate }
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate /*
926*0Sstevel@tonic-gate  *
927*0Sstevel@tonic-gate  *			cachefs_delete_file
928*0Sstevel@tonic-gate  *
929*0Sstevel@tonic-gate  * Description:
930*0Sstevel@tonic-gate  *	Remove a file or directory; called by nftw64().
931*0Sstevel@tonic-gate  * Arguments:
932*0Sstevel@tonic-gate  *	namep	pathname of the file
933*0Sstevel@tonic-gate  *	statp	stat info about the file
934*0Sstevel@tonic-gate  *	flg	info about file
935*0Sstevel@tonic-gate  *	ftwp	depth information
936*0Sstevel@tonic-gate  * Returns:
937*0Sstevel@tonic-gate  *	Returns 0 for success, -1 for failure.
938*0Sstevel@tonic-gate  * Preconditions:
939*0Sstevel@tonic-gate  *	precond(namep)
940*0Sstevel@tonic-gate  */
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate int
943*0Sstevel@tonic-gate cachefs_delete_file(const char *namep, const struct stat64 *statp, int flg,
944*0Sstevel@tonic-gate     struct FTW *ftwp)
945*0Sstevel@tonic-gate {
946*0Sstevel@tonic-gate 	/* ignore . and .. */
947*0Sstevel@tonic-gate 	if (strcmp(namep, ".") == 0 || strcmp(namep, "..") == 0)
948*0Sstevel@tonic-gate 		return (0);
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	switch (flg) {
951*0Sstevel@tonic-gate 	case FTW_F:	/* files */
952*0Sstevel@tonic-gate 	case FTW_SL:
953*0Sstevel@tonic-gate 		if (unlink(namep) == -1) {
954*0Sstevel@tonic-gate 			pr_err(gettext("unlink %s failed: %s"),
955*0Sstevel@tonic-gate 			    namep, strerror(errno));
956*0Sstevel@tonic-gate 			return (-1);
957*0Sstevel@tonic-gate 		}
958*0Sstevel@tonic-gate 		break;
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	case FTW_DP:	/* directories that have their children processed */
961*0Sstevel@tonic-gate 		if (rmdir(namep) == -1) {
962*0Sstevel@tonic-gate 			pr_err(gettext("rmdir %s failed: %s"),
963*0Sstevel@tonic-gate 			    namep, strerror(errno));
964*0Sstevel@tonic-gate 			return (-1);
965*0Sstevel@tonic-gate 		}
966*0Sstevel@tonic-gate 		break;
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 	case FTW_D:	/* ignore directories if children not processed */
969*0Sstevel@tonic-gate 		break;
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	default:
972*0Sstevel@tonic-gate 		pr_err(gettext("failure on file %s, flg %d."),
973*0Sstevel@tonic-gate 		    namep, flg);
974*0Sstevel@tonic-gate 		return (-1);
975*0Sstevel@tonic-gate 	}
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate 	/* return success */
978*0Sstevel@tonic-gate 	return (0);
979*0Sstevel@tonic-gate }
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate /*
982*0Sstevel@tonic-gate  *
983*0Sstevel@tonic-gate  *			cachefs_convert_uv2cl
984*0Sstevel@tonic-gate  *
985*0Sstevel@tonic-gate  * Description:
986*0Sstevel@tonic-gate  *	Copies the contents of a cachefs_user_values object into a
987*0Sstevel@tonic-gate  *	cache_label object, performing the necessary conversions.
988*0Sstevel@tonic-gate  * Arguments:
989*0Sstevel@tonic-gate  *	uvp	cachefs_user_values to copy from
990*0Sstevel@tonic-gate  *	clp	cache_label to copy into
991*0Sstevel@tonic-gate  *	dirp	cache directory
992*0Sstevel@tonic-gate  * Returns:
993*0Sstevel@tonic-gate  *	Returns 0 for success, -1 for an error.
994*0Sstevel@tonic-gate  * Preconditions:
995*0Sstevel@tonic-gate  *	precond(uvp)
996*0Sstevel@tonic-gate  *	precond(clp)
997*0Sstevel@tonic-gate  *	precond(dirp)
998*0Sstevel@tonic-gate  */
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate int
1001*0Sstevel@tonic-gate cachefs_convert_uv2cl(const struct cachefs_user_values *uvp,
1002*0Sstevel@tonic-gate     struct cache_label *clp, const char *dirp)
1003*0Sstevel@tonic-gate {
1004*0Sstevel@tonic-gate 	struct statvfs64 fs;
1005*0Sstevel@tonic-gate 	int xx;
1006*0Sstevel@tonic-gate 	double ftmp;
1007*0Sstevel@tonic-gate 	double temp;
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate 	/* get file system information */
1010*0Sstevel@tonic-gate 	xx = statvfs64(dirp, &fs);
1011*0Sstevel@tonic-gate 	if (xx == -1) {
1012*0Sstevel@tonic-gate 		pr_err(gettext("statvfs %s failed: %s"), dirp,
1013*0Sstevel@tonic-gate 		    strerror(errno));
1014*0Sstevel@tonic-gate 		return (-1);
1015*0Sstevel@tonic-gate 	}
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 	ftmp = (double)fs.f_frsize / (double)MAXBSIZE;
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 	/* front fs is less than 1 terabyte */
1020*0Sstevel@tonic-gate 	temp = (double)uvp->uv_maxblocks / 100.0 *
1021*0Sstevel@tonic-gate 	    (double)fs.f_blocks * ftmp + .5;
1022*0Sstevel@tonic-gate 	clp->cl_maxblks = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 	temp = (double)uvp->uv_minblocks / 100.0 *
1025*0Sstevel@tonic-gate 	    (double)fs.f_blocks * ftmp + .5;
1026*0Sstevel@tonic-gate 	clp->cl_blockmin = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	temp = (double)uvp->uv_threshblocks / 100.0 *
1029*0Sstevel@tonic-gate 	    (double)fs.f_blocks * ftmp + .5;
1030*0Sstevel@tonic-gate 	clp->cl_blocktresh = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 	temp = (double)uvp->uv_maxfiles / 100.0 * (double)fs.f_files + .5;
1033*0Sstevel@tonic-gate 	clp->cl_maxinodes = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	temp = (double)uvp->uv_minfiles / 100.0 * (double)fs.f_files + .5;
1036*0Sstevel@tonic-gate 	clp->cl_filemin = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate 	temp = (double)uvp->uv_threshfiles / 100.0 * (double)fs.f_files +.5;
1039*0Sstevel@tonic-gate 	clp->cl_filetresh = temp < (double)INT_MAX ? (int)temp : INT_MAX;
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 	ftmp = (double)(1024 * 1024) / (double)MAXBSIZE;
1042*0Sstevel@tonic-gate 	clp->cl_maxfiles = uvp->uv_maxfilesize * ftmp + .5;
1043*0Sstevel@tonic-gate 
1044*0Sstevel@tonic-gate 	clp->cl_blkhiwat = uvp->uv_hiblocks / 100.0 * clp->cl_maxblks + .5;
1045*0Sstevel@tonic-gate 	clp->cl_blklowat = uvp->uv_lowblocks / 100.0 * clp->cl_maxblks + .5;
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 	clp->cl_filehiwat = uvp->uv_hifiles / 100.0 * clp->cl_maxinodes + .5;
1048*0Sstevel@tonic-gate 	clp->cl_filelowat = uvp->uv_lowfiles / 100.0 * clp->cl_maxinodes + .5;
1049*0Sstevel@tonic-gate 
1050*0Sstevel@tonic-gate 	clp->cl_cfsversion = CFSVERSION;
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	/* return success */
1053*0Sstevel@tonic-gate 	return (0);
1054*0Sstevel@tonic-gate }
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate /*
1057*0Sstevel@tonic-gate  *
1058*0Sstevel@tonic-gate  *			cachefs_convert_cl2uv
1059*0Sstevel@tonic-gate  *
1060*0Sstevel@tonic-gate  * Description:
1061*0Sstevel@tonic-gate  *	Copies the contents of a cache_label object into a
1062*0Sstevel@tonic-gate  *	cachefs_user_values object, performing the necessary conversions.
1063*0Sstevel@tonic-gate  * Arguments:
1064*0Sstevel@tonic-gate  *	clp	cache_label to copy from
1065*0Sstevel@tonic-gate  *	uvp	cachefs_user_values to copy into
1066*0Sstevel@tonic-gate  *	dirp	cache directory
1067*0Sstevel@tonic-gate  * Returns:
1068*0Sstevel@tonic-gate  *	Returns 0 for success, -1 for an error.
1069*0Sstevel@tonic-gate  * Preconditions:
1070*0Sstevel@tonic-gate  *	precond(clp)
1071*0Sstevel@tonic-gate  *	precond(uvp)
1072*0Sstevel@tonic-gate  *	precond(dirp)
1073*0Sstevel@tonic-gate  */
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate int
1076*0Sstevel@tonic-gate cachefs_convert_cl2uv(const struct cache_label *clp,
1077*0Sstevel@tonic-gate     struct cachefs_user_values *uvp, const char *dirp)
1078*0Sstevel@tonic-gate {
1079*0Sstevel@tonic-gate 	struct statvfs64 fs;
1080*0Sstevel@tonic-gate 	int xx;
1081*0Sstevel@tonic-gate 	double temp;
1082*0Sstevel@tonic-gate 	double ftmp;
1083*0Sstevel@tonic-gate 	long long ltmp;
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 	/* get file system information */
1086*0Sstevel@tonic-gate 	xx = statvfs64(dirp, &fs);
1087*0Sstevel@tonic-gate 	if (xx == -1) {
1088*0Sstevel@tonic-gate 		pr_err(gettext("statvfs %s failed: %s"), dirp,
1089*0Sstevel@tonic-gate 		    strerror(errno));
1090*0Sstevel@tonic-gate 		return (-1);
1091*0Sstevel@tonic-gate 	}
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate #define	BOUND(yy) \
1094*0Sstevel@tonic-gate 	yy = (yy < 0) ? 0 : yy; \
1095*0Sstevel@tonic-gate 	yy = (yy > 100) ? 100 : yy;
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 	ftmp = (double)MAXBSIZE / (double)fs.f_frsize;
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 	temp = (double)clp->cl_maxblks * ftmp /
1100*0Sstevel@tonic-gate 	    (double)fs.f_blocks * 100. + .5;
1101*0Sstevel@tonic-gate 	BOUND(temp);
1102*0Sstevel@tonic-gate 	uvp->uv_maxblocks = (int)temp;
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	temp = (double)clp->cl_blockmin * ftmp /
1105*0Sstevel@tonic-gate 	    (double)fs.f_blocks * 100. + .5;
1106*0Sstevel@tonic-gate 	BOUND(temp);
1107*0Sstevel@tonic-gate 	uvp->uv_minblocks = (int)temp;
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	temp = (double)clp->cl_blocktresh * ftmp /
1110*0Sstevel@tonic-gate 	    (double)fs.f_blocks * 100. + .5;
1111*0Sstevel@tonic-gate 	BOUND(temp);
1112*0Sstevel@tonic-gate 	uvp->uv_threshblocks = (int)temp;
1113*0Sstevel@tonic-gate 
1114*0Sstevel@tonic-gate 	temp = ((double)clp->cl_maxinodes / fs.f_files) * 100. + .5;
1115*0Sstevel@tonic-gate 	BOUND(temp);
1116*0Sstevel@tonic-gate 	uvp->uv_maxfiles = (int)temp;
1117*0Sstevel@tonic-gate 
1118*0Sstevel@tonic-gate 	temp = ((double)clp->cl_filemin / fs.f_files) * 100. + .5;
1119*0Sstevel@tonic-gate 	BOUND(temp);
1120*0Sstevel@tonic-gate 	uvp->uv_minfiles = (int)temp;
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 	temp = ((double)clp->cl_filetresh / fs.f_files) * 100. + .5;
1123*0Sstevel@tonic-gate 	BOUND(temp);
1124*0Sstevel@tonic-gate 	uvp->uv_threshfiles = (int)temp;
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	ltmp = ((long long)clp->cl_maxfiles * MAXBSIZE);
1127*0Sstevel@tonic-gate 	uvp->uv_maxfilesize = (ltmp + (MAXBSIZE / 2)) / (1024 * 1024);
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate 	xx = ((double)clp->cl_blkhiwat / clp->cl_maxblks) * 100. + .5;
1130*0Sstevel@tonic-gate 	BOUND(xx);
1131*0Sstevel@tonic-gate 	uvp->uv_hiblocks = xx;
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 	xx = ((double)clp->cl_blklowat / clp->cl_maxblks) * 100. + .5;
1134*0Sstevel@tonic-gate 	BOUND(xx);
1135*0Sstevel@tonic-gate 	uvp->uv_lowblocks = xx;
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 	xx = ((double)clp->cl_filehiwat / clp->cl_maxinodes) * 100. + .5;
1138*0Sstevel@tonic-gate 	BOUND(xx);
1139*0Sstevel@tonic-gate 	uvp->uv_hifiles = xx;
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 	xx = ((double)clp->cl_filelowat / clp->cl_maxinodes) * 100. + .5;
1142*0Sstevel@tonic-gate 	BOUND(xx);
1143*0Sstevel@tonic-gate 	uvp->uv_lowfiles = xx;
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	/* return success */
1146*0Sstevel@tonic-gate 	return (0);
1147*0Sstevel@tonic-gate }
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate /*
1150*0Sstevel@tonic-gate  * cachefs_file_to_dir
1151*0Sstevel@tonic-gate  *
1152*0Sstevel@tonic-gate  * takes in a path, and returns the parent directory of that path.
1153*0Sstevel@tonic-gate  *
1154*0Sstevel@tonic-gate  * it's the caller's responsibility to free the pointer returned by
1155*0Sstevel@tonic-gate  * this function.
1156*0Sstevel@tonic-gate  */
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate char *
1159*0Sstevel@tonic-gate cachefs_file_to_dir(const char *path)
1160*0Sstevel@tonic-gate {
1161*0Sstevel@tonic-gate 	char *rc, *cp;
1162*0Sstevel@tonic-gate 
1163*0Sstevel@tonic-gate 	if (path == NULL)
1164*0Sstevel@tonic-gate 		return (NULL);
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	rc = strdup(path);
1167*0Sstevel@tonic-gate 	if (rc == NULL)
1168*0Sstevel@tonic-gate 		return (NULL);
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate 	if ((cp = strrchr(rc, '/')) == NULL) {
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 		/*
1173*0Sstevel@tonic-gate 		 * if no slashes at all, return "." (current directory).
1174*0Sstevel@tonic-gate 		 */
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 		(void) free(rc);
1177*0Sstevel@tonic-gate 		rc = strdup(".");
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate 	} else if (cp == rc) {
1180*0Sstevel@tonic-gate 
1181*0Sstevel@tonic-gate 		/*
1182*0Sstevel@tonic-gate 		 * else, if the last '/' is the first character, chop
1183*0Sstevel@tonic-gate 		 * off from there (i.e. return "/").
1184*0Sstevel@tonic-gate 		 */
1185*0Sstevel@tonic-gate 
1186*0Sstevel@tonic-gate 		rc[1] = '\0';
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	} else {
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 		/*
1191*0Sstevel@tonic-gate 		 * else, we have a path like /foo/bar or foo/bar.
1192*0Sstevel@tonic-gate 		 * chop off from the last '/'.
1193*0Sstevel@tonic-gate 		 */
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate 		*cp = '\0';
1196*0Sstevel@tonic-gate 
1197*0Sstevel@tonic-gate 	}
1198*0Sstevel@tonic-gate 
1199*0Sstevel@tonic-gate 	return (rc);
1200*0Sstevel@tonic-gate }
1201*0Sstevel@tonic-gate 
1202*0Sstevel@tonic-gate /*
1203*0Sstevel@tonic-gate  *			cachefs_clean_flag_test
1204*0Sstevel@tonic-gate  *
1205*0Sstevel@tonic-gate  * Description:
1206*0Sstevel@tonic-gate  *	Tests whether or not the clean flag on the file system
1207*0Sstevel@tonic-gate  *	is set.
1208*0Sstevel@tonic-gate  * Arguments:
1209*0Sstevel@tonic-gate  *	cachedirp	name of the the file system cache directory
1210*0Sstevel@tonic-gate  * Returns:
1211*0Sstevel@tonic-gate  *	Returns 1 if the cache was shut down cleanly, 0 if not.
1212*0Sstevel@tonic-gate  * Preconditions:
1213*0Sstevel@tonic-gate  *	precond(cachedirp)
1214*0Sstevel@tonic-gate  */
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate int
1217*0Sstevel@tonic-gate cachefs_clean_flag_test(const char *cachedirp)
1218*0Sstevel@tonic-gate {
1219*0Sstevel@tonic-gate 	char *namep;
1220*0Sstevel@tonic-gate 	int xx;
1221*0Sstevel@tonic-gate 	char buf[MAXPATHLEN];
1222*0Sstevel@tonic-gate 	int fd;
1223*0Sstevel@tonic-gate 	struct cache_usage cu;
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate 	/* construct the path name of the resource file */
1226*0Sstevel@tonic-gate 	namep = RESOURCE_NAME;
1227*0Sstevel@tonic-gate 	xx = strlen(cachedirp) + strlen(namep) + 3;
1228*0Sstevel@tonic-gate 	if (xx >= MAXPATHLEN) {
1229*0Sstevel@tonic-gate 		pr_err(gettext("Path name too long %s/%s"),
1230*0Sstevel@tonic-gate 		    cachedirp, namep);
1231*0Sstevel@tonic-gate 		return (39);
1232*0Sstevel@tonic-gate 	}
1233*0Sstevel@tonic-gate 	snprintf(buf, sizeof (buf), "%s/%s", cachedirp, namep);
1234*0Sstevel@tonic-gate 
1235*0Sstevel@tonic-gate 	/* open the file; it will be <2GB */
1236*0Sstevel@tonic-gate 	fd = open(buf, O_RDONLY);
1237*0Sstevel@tonic-gate 	if (fd == -1) {
1238*0Sstevel@tonic-gate 		pr_err(gettext("Cannot open %s: %s"), buf, strerror(errno));
1239*0Sstevel@tonic-gate 		return (0);
1240*0Sstevel@tonic-gate 	}
1241*0Sstevel@tonic-gate 
1242*0Sstevel@tonic-gate 	/* read the cache_usage structure */
1243*0Sstevel@tonic-gate 	xx = read(fd, &cu, sizeof (cu));
1244*0Sstevel@tonic-gate 	if (xx != sizeof (cu)) {
1245*0Sstevel@tonic-gate 		pr_err(gettext("Error reading %s: %d %s"), buf,
1246*0Sstevel@tonic-gate 		    xx, strerror(errno));
1247*0Sstevel@tonic-gate 		close(fd);
1248*0Sstevel@tonic-gate 		return (0);
1249*0Sstevel@tonic-gate 	}
1250*0Sstevel@tonic-gate 	close(fd);
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate 	/* return state of the cache */
1253*0Sstevel@tonic-gate 	return ((cu.cu_flags & CUSAGE_ACTIVE) == 0);
1254*0Sstevel@tonic-gate }
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate time32_t
1257*0Sstevel@tonic-gate get_boottime()
1258*0Sstevel@tonic-gate {
1259*0Sstevel@tonic-gate 	struct utmpx id, *putmp;
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 	id.ut_type = BOOT_TIME;
1262*0Sstevel@tonic-gate 	setutxent();
1263*0Sstevel@tonic-gate 	if ((putmp = getutxid(&id)) != NULL)
1264*0Sstevel@tonic-gate 		return ((time32_t)putmp->ut_tv.tv_sec);
1265*0Sstevel@tonic-gate 	return (-1);
1266*0Sstevel@tonic-gate }
1267