xref: /onnv-gate/usr/src/cmd/fs.d/cachefs/common/subr.c (revision 633:04519cb7de3b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*633Sgt29601  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Common subroutines used by the programs in these subdirectories.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <locale.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <assert.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <limits.h>
400Sstevel@tonic-gate #include <errno.h>
410Sstevel@tonic-gate #include <wait.h>
420Sstevel@tonic-gate #include <ctype.h>
430Sstevel@tonic-gate #include <fcntl.h>
440Sstevel@tonic-gate #include <ftw.h>
450Sstevel@tonic-gate #include <dirent.h>
460Sstevel@tonic-gate #include <sys/types.h>
470Sstevel@tonic-gate #include <sys/time.h>
480Sstevel@tonic-gate #include <utmpx.h>
490Sstevel@tonic-gate #include <sys/uio.h>
500Sstevel@tonic-gate #include <sys/param.h>
510Sstevel@tonic-gate #include <sys/stat.h>
520Sstevel@tonic-gate #include <sys/fcntl.h>
530Sstevel@tonic-gate #include <sys/mount.h>
540Sstevel@tonic-gate #include <sys/mntent.h>
550Sstevel@tonic-gate #include <sys/mnttab.h>
560Sstevel@tonic-gate #include <sys/mman.h>
570Sstevel@tonic-gate #include <sys/fs/cachefs_fs.h>
580Sstevel@tonic-gate #include "subr.h"
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate  *
620Sstevel@tonic-gate  *			cachefs_dir_lock
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * Description:
650Sstevel@tonic-gate  *	Gets a lock on the cache directory.
660Sstevel@tonic-gate  *	To release the lock, call cachefs_dir_unlock
670Sstevel@tonic-gate  *	with the returned value.
680Sstevel@tonic-gate  * Arguments:
690Sstevel@tonic-gate  *	cachedirp	name of the cache directory
700Sstevel@tonic-gate  *	shared		1 if shared, 0 if not
710Sstevel@tonic-gate  * Returns:
720Sstevel@tonic-gate  *	Returns -1 if the lock cannot be obtained immediatly.
730Sstevel@tonic-gate  *	If the lock is obtained, returns a value >= 0.
740Sstevel@tonic-gate  * Preconditions:
750Sstevel@tonic-gate  *	precond(cachedirp)
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate 
780Sstevel@tonic-gate int
cachefs_dir_lock(const char * cachedirp,int shared)790Sstevel@tonic-gate cachefs_dir_lock(const char *cachedirp, int shared)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	int fd;
820Sstevel@tonic-gate 	int xx;
830Sstevel@tonic-gate 	int len;
840Sstevel@tonic-gate 	char buf[MAXPATHLEN];
850Sstevel@tonic-gate 	struct flock fl;
860Sstevel@tonic-gate 	char *strp;
870Sstevel@tonic-gate 	struct stat statb;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	/* make a path prefix to the cache directory lock file */
900Sstevel@tonic-gate 	strp = CACHEFS_ROOTRUN;
910Sstevel@tonic-gate 	xx = stat(strp, &statb);
920Sstevel@tonic-gate 	if ((xx < 0) || ((statb.st_mode & S_IFMT) != S_IFDIR))
930Sstevel@tonic-gate 		strp = "/tmp";
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	/* won't overflow */
960Sstevel@tonic-gate 	len = snprintf(buf, sizeof (buf), "%s/%s", strp, CACHEFS_LOCKDIR_PRE);
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	if (strlcat(buf, cachedirp, sizeof (buf)) >= sizeof (buf)) {
990Sstevel@tonic-gate 		pr_err(gettext("Cache directory name %s is too long"),
1000Sstevel@tonic-gate 			cachedirp);
1010Sstevel@tonic-gate 		return (-1);
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	strp = &buf[len];
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	while (strp = strchr(strp, '/')) { 	/* convert path to a file */
1070Sstevel@tonic-gate 		*strp = '_';
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	/*
1110Sstevel@tonic-gate 	 * Create and open the cache directory lock file.
1120Sstevel@tonic-gate 	 * This file will be <2G.
1130Sstevel@tonic-gate 	 */
1140Sstevel@tonic-gate 	fd = open(buf, O_RDWR | O_CREAT, 0700);
1150Sstevel@tonic-gate 	if (fd == -1) {
1160Sstevel@tonic-gate 		pr_err(gettext("Cannot open lock file %s"), buf);
1170Sstevel@tonic-gate 		return (-1);
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* try to set the lock */
1210Sstevel@tonic-gate 	fl.l_type = (shared == 1) ? F_RDLCK : F_WRLCK;
1220Sstevel@tonic-gate 	fl.l_whence = 0;
1230Sstevel@tonic-gate 	fl.l_start = 1024;
1240Sstevel@tonic-gate 	fl.l_len = 1024;
1250Sstevel@tonic-gate 	fl.l_sysid = 0;
1260Sstevel@tonic-gate 	fl.l_pid = 0;
1270Sstevel@tonic-gate 	/* CACHEFS_LOCK_FILE will be <2GB */
1280Sstevel@tonic-gate 	xx = fcntl(fd, F_SETLKW, &fl);
1290Sstevel@tonic-gate 	if (xx == -1) {
1300Sstevel@tonic-gate 		if (errno == EAGAIN) {
1310Sstevel@tonic-gate 			pr_err(gettext("Cannot gain access to the "
1320Sstevel@tonic-gate 			    "cache directory %s."), cachedirp);
1330Sstevel@tonic-gate 		} else {
1340Sstevel@tonic-gate 			pr_err(gettext("Unexpected failure on lock file %s %s"),
1350Sstevel@tonic-gate 			    buf, strerror(errno));
1360Sstevel@tonic-gate 		}
1370Sstevel@tonic-gate 		close(fd);
1380Sstevel@tonic-gate 		return (-1);
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/* return the file descriptor which can be used to release the lock */
1420Sstevel@tonic-gate 	return (fd);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate /*
1460Sstevel@tonic-gate  *
1470Sstevel@tonic-gate  *			cachefs_dir_unlock
1480Sstevel@tonic-gate  *
1490Sstevel@tonic-gate  * Description:
1500Sstevel@tonic-gate  *	Releases an advisory lock on the cache directory.
1510Sstevel@tonic-gate  * Arguments:
1520Sstevel@tonic-gate  *	fd	cookie returned by cachefs_dir_lock
1530Sstevel@tonic-gate  * Returns:
1540Sstevel@tonic-gate  *	Returns -1 if the lock cannot be released or 0 for success.
1550Sstevel@tonic-gate  * Preconditions:
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate int
cachefs_dir_unlock(int fd)1590Sstevel@tonic-gate cachefs_dir_unlock(int fd)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate 	struct flock fl;
1620Sstevel@tonic-gate 	int error = 0;
1630Sstevel@tonic-gate 	int xx;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	/* release the lock */
1660Sstevel@tonic-gate 	fl.l_type = F_UNLCK;
1670Sstevel@tonic-gate 	fl.l_whence = 0;
1680Sstevel@tonic-gate 	fl.l_start = 1024;
1690Sstevel@tonic-gate 	fl.l_len = 1024;
1700Sstevel@tonic-gate 	fl.l_sysid = 0;
1710Sstevel@tonic-gate 	fl.l_pid = 0;
1720Sstevel@tonic-gate 	/* fd will be <2GB */
1730Sstevel@tonic-gate 	xx = fcntl(fd, F_SETLK, &fl);
1740Sstevel@tonic-gate 	if (xx == -1) {
1750Sstevel@tonic-gate 		pr_err(gettext("Unexpected failure releasing lock file %s"),
1760Sstevel@tonic-gate 			strerror(errno));
1770Sstevel@tonic-gate 		error = -1;
1780Sstevel@tonic-gate 	}
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/* close the lock file */
1810Sstevel@tonic-gate 	close(fd);
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	return (error);
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate  *
1880Sstevel@tonic-gate  *			cachefs_label_file_get
1890Sstevel@tonic-gate  *
1900Sstevel@tonic-gate  * Description:
1910Sstevel@tonic-gate  *	Gets the contents of a cache label file.
1920Sstevel@tonic-gate  *	Performs error checking on the file.
1930Sstevel@tonic-gate  * Arguments:
1940Sstevel@tonic-gate  *	filep	name of the cache label file
1950Sstevel@tonic-gate  *	clabelp	where to put the file contents
1960Sstevel@tonic-gate  * Returns:
1970Sstevel@tonic-gate  *	Returns 0 for success or -1 if an error occurs.
1980Sstevel@tonic-gate  * Preconditions:
1990Sstevel@tonic-gate  *	precond(filep)
2000Sstevel@tonic-gate  *	precond(clabelp)
2010Sstevel@tonic-gate  */
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate int
cachefs_label_file_get(const char * filep,struct cache_label * clabelp)2040Sstevel@tonic-gate cachefs_label_file_get(const char *filep, struct cache_label *clabelp)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	int xx;
2070Sstevel@tonic-gate 	int fd;
2080Sstevel@tonic-gate 	struct stat64 statinfo;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/* get info on the file */
2110Sstevel@tonic-gate 	xx = lstat64(filep, &statinfo);
2120Sstevel@tonic-gate 	if (xx == -1) {
2130Sstevel@tonic-gate 		if (errno != ENOENT) {
2140Sstevel@tonic-gate 			pr_err(gettext("Cannot stat file %s: %s"),
2150Sstevel@tonic-gate 			    filep, strerror(errno));
2160Sstevel@tonic-gate 		} else {
2170Sstevel@tonic-gate 			pr_err(gettext("File %s does not exist."), filep);
2180Sstevel@tonic-gate 		}
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 		return (-1);
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	/* if the file is the wrong type */
2240Sstevel@tonic-gate 	if (!S_ISREG(statinfo.st_mode)) {
2250Sstevel@tonic-gate 		pr_err(gettext("Cache label file %s corrupted"), filep);
2260Sstevel@tonic-gate 		return (-1);
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	/* if the file is the wrong size; it will be <2GB */
2300Sstevel@tonic-gate 	if (statinfo.st_size != (offset_t)sizeof (struct cache_label)) {
2310Sstevel@tonic-gate 		pr_err(gettext("Cache label file %s wrong size"), filep);
2320Sstevel@tonic-gate 		return (-1);
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/* open the cache label file */
2360Sstevel@tonic-gate 	fd = open(filep, O_RDONLY);
2370Sstevel@tonic-gate 	if (fd == -1) {
2380Sstevel@tonic-gate 		pr_err(gettext("Error opening %s: %s"), filep,
2390Sstevel@tonic-gate 		    strerror(errno));
2400Sstevel@tonic-gate 		return (-1);
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/* read the current set of parameters */
2440Sstevel@tonic-gate 	xx = read(fd, clabelp, sizeof (struct cache_label));
2450Sstevel@tonic-gate 	if (xx != sizeof (struct cache_label)) {
2460Sstevel@tonic-gate 		pr_err(gettext("Reading %s failed: %s\n"), filep,
2470Sstevel@tonic-gate 		    strerror(errno));
2480Sstevel@tonic-gate 		close(fd);
2490Sstevel@tonic-gate 		return (-1);
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 	close(fd);
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	/* return success */
2540Sstevel@tonic-gate 	return (0);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  *			cachefs_label_file_put
2600Sstevel@tonic-gate  *
2610Sstevel@tonic-gate  * Description:
2620Sstevel@tonic-gate  *	Outputs the contents of a cache label object to a file.
2630Sstevel@tonic-gate  * Arguments:
2640Sstevel@tonic-gate  *	filep	name of the cache label file
2650Sstevel@tonic-gate  *	clabelp	where to get the file contents
2660Sstevel@tonic-gate  * Returns:
2670Sstevel@tonic-gate  *	Returns 0 for success or -1 if an error occurs.
2680Sstevel@tonic-gate  * Preconditions:
2690Sstevel@tonic-gate  *	precond(filep)
2700Sstevel@tonic-gate  *	precond(clabelp)
2710Sstevel@tonic-gate  */
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate int
cachefs_label_file_put(const char * filep,struct cache_label * clabelp)2740Sstevel@tonic-gate cachefs_label_file_put(const char *filep, struct cache_label *clabelp)
2750Sstevel@tonic-gate {
2760Sstevel@tonic-gate 	int xx;
2770Sstevel@tonic-gate 	int fd;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	/* get rid of the file if it already exists */
2800Sstevel@tonic-gate 	xx = unlink(filep);
2810Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
2820Sstevel@tonic-gate 		pr_err(gettext("Could not remove %s: %s"), filep,
2830Sstevel@tonic-gate 		    strerror(errno));
2840Sstevel@tonic-gate 		return (-1);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/* open the cache label file; this file will be <2GB */
2880Sstevel@tonic-gate 	fd = open(filep, O_CREAT | O_RDWR, 0600);
2890Sstevel@tonic-gate 	if (fd == -1) {
2900Sstevel@tonic-gate 		pr_err(gettext("Error creating %s: %s"), filep,
2910Sstevel@tonic-gate 		    strerror(errno));
2920Sstevel@tonic-gate 		return (-1);
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	/* write out the cache label object */
2960Sstevel@tonic-gate 	xx = write(fd, clabelp, sizeof (struct cache_label));
2970Sstevel@tonic-gate 	if (xx != sizeof (struct cache_label)) {
2980Sstevel@tonic-gate 		pr_err(gettext("Writing %s failed: %s"), filep,
2990Sstevel@tonic-gate 		    strerror(errno));
3000Sstevel@tonic-gate 		close(fd);
3010Sstevel@tonic-gate 		return (-1);
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	/* make sure the contents get to disk */
3050Sstevel@tonic-gate 	if (fsync(fd) != 0) {
3060Sstevel@tonic-gate 		pr_err(gettext("Writing %s failed on sync: %s"), filep,
3070Sstevel@tonic-gate 		    strerror(errno));
3080Sstevel@tonic-gate 		close(fd);
3090Sstevel@tonic-gate 		return (-1);
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	close(fd);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	/* return success */
3150Sstevel@tonic-gate 	return (0);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate int
cachefs_label_file_vcheck(char * filep,struct cache_label * clabelp)3190Sstevel@tonic-gate cachefs_label_file_vcheck(char *filep, struct cache_label *clabelp)
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	/* check for an invalid version number */
3220Sstevel@tonic-gate 	if (clabelp->cl_cfsversion != CFSVERSION) {
3230Sstevel@tonic-gate 		pr_err(gettext("Cache label file %s corrupted"), filep);
3240Sstevel@tonic-gate 		return (-1);
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	return (0);
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate  *
3320Sstevel@tonic-gate  *			cachefs_inuse
3330Sstevel@tonic-gate  *
3340Sstevel@tonic-gate  * Description:
3350Sstevel@tonic-gate  *	Tests whether or not the cache directory is in use by
3360Sstevel@tonic-gate  *	the cache file system.
3370Sstevel@tonic-gate  * Arguments:
3380Sstevel@tonic-gate  *	cachedirp	name of the file system cache directory
3390Sstevel@tonic-gate  * Returns:
3400Sstevel@tonic-gate  *	Returns 1 if the cache is in use or an error, 0 if not.
3410Sstevel@tonic-gate  * Preconditions:
3420Sstevel@tonic-gate  *	precond(cachedirp)
3430Sstevel@tonic-gate  */
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate int
cachefs_inuse(const char * cachedirp)3460Sstevel@tonic-gate cachefs_inuse(const char *cachedirp)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	int fd;
3490Sstevel@tonic-gate 	int xx;
3500Sstevel@tonic-gate 	char buf[MAXPATHLEN];
3510Sstevel@tonic-gate 	char *lockp = CACHEFS_LOCK_FILE;
3520Sstevel@tonic-gate 	struct flock fl;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/* see if path name is too long */
3550Sstevel@tonic-gate 	xx = strlen(cachedirp) + strlen(lockp) + 3;
3560Sstevel@tonic-gate 	if (xx >= MAXPATHLEN) {
3570Sstevel@tonic-gate 		pr_err(gettext("Cache directory name %s is too long"),
3580Sstevel@tonic-gate 		    cachedirp);
3590Sstevel@tonic-gate 		return (1);
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	/* make a path to the cache directory lock file */
3630Sstevel@tonic-gate 	snprintf(buf, sizeof (buf), "%s/%s", cachedirp, lockp);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/* Open the kernel in use lock file.  This file will be <2GB. */
3660Sstevel@tonic-gate 	fd = open(buf, O_RDWR, 0700);
3670Sstevel@tonic-gate 	if (fd == -1) {
3680Sstevel@tonic-gate 		pr_err(gettext("Cannot open lock file %s"), buf);
3690Sstevel@tonic-gate 		return (1);
3700Sstevel@tonic-gate 	}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	/* test the lock status */
3730Sstevel@tonic-gate 	fl.l_type = F_WRLCK;
3740Sstevel@tonic-gate 	fl.l_whence = 0;
3750Sstevel@tonic-gate 	fl.l_start = 0;
3760Sstevel@tonic-gate 	fl.l_len = 1024;
3770Sstevel@tonic-gate 	fl.l_sysid = 0;
3780Sstevel@tonic-gate 	fl.l_pid = 0;
3790Sstevel@tonic-gate 	xx = fcntl(fd, F_GETLK, &fl);
3800Sstevel@tonic-gate 	if (xx == -1) {
3810Sstevel@tonic-gate 		pr_err(gettext("Unexpected failure on lock file %s %s"),
3820Sstevel@tonic-gate 		    buf, strerror(errno));
3830Sstevel@tonic-gate 		close(fd);
3840Sstevel@tonic-gate 		return (1);
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 	close(fd);
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	if (fl.l_type == F_UNLCK)
3890Sstevel@tonic-gate 		xx = 0;
3900Sstevel@tonic-gate 	else
3910Sstevel@tonic-gate 		xx = 1;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	/* return whether or not the cache is in use */
3940Sstevel@tonic-gate 	return (xx);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate  *
3990Sstevel@tonic-gate  *			cachefs_resouce_size
4000Sstevel@tonic-gate  *
4010Sstevel@tonic-gate  * Description:
4020Sstevel@tonic-gate  *	Returns information about a resource file.
4030Sstevel@tonic-gate  * Arguments:
4040Sstevel@tonic-gate  *	maxinodes	number of inodes to be managed by the resource file
4050Sstevel@tonic-gate  *	rinfop		set to info about the resource file
4060Sstevel@tonic-gate  * Returns:
4070Sstevel@tonic-gate  * Preconditions:
4080Sstevel@tonic-gate  *	precond(rinfop)
4090Sstevel@tonic-gate  */
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate void
cachefs_resource_size(int maxinodes,struct cachefs_rinfo * rinfop)4120Sstevel@tonic-gate cachefs_resource_size(int maxinodes, struct cachefs_rinfo *rinfop)
4130Sstevel@tonic-gate {
4140Sstevel@tonic-gate 	int fsize;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	fsize = MAXBSIZE;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	rinfop->r_ptroffset = fsize;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	fsize += MAXBSIZE * (maxinodes / CACHEFS_RLPMBS);
4210Sstevel@tonic-gate 	if ((maxinodes % CACHEFS_RLPMBS) != 0)
4220Sstevel@tonic-gate 		fsize += MAXBSIZE;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	rinfop->r_fsize = fsize;
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate  *
4290Sstevel@tonic-gate  *			cachefs_create_cache
4300Sstevel@tonic-gate  *
4310Sstevel@tonic-gate  * Description:
4320Sstevel@tonic-gate  *	Creates the specified cache directory and populates it as
4330Sstevel@tonic-gate  *	needed by CFS.
4340Sstevel@tonic-gate  * Arguments:
4350Sstevel@tonic-gate  *	dirp		the name of the cache directory
4360Sstevel@tonic-gate  *	uv		user values (may be NULL)
4370Sstevel@tonic-gate  *	clabel		label file contents, or placeholder for this
4380Sstevel@tonic-gate  * Returns:
4390Sstevel@tonic-gate  *	Returns 0 for success or:
4400Sstevel@tonic-gate  *		-1 for an error
4410Sstevel@tonic-gate  *		-2 for an error and cache directory partially created
4420Sstevel@tonic-gate  * Preconditions:
4430Sstevel@tonic-gate  *	precond(dirp)
4440Sstevel@tonic-gate  */
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate int
cachefs_create_cache(char * dirp,struct cachefs_user_values * uv,struct cache_label * clabel)4470Sstevel@tonic-gate cachefs_create_cache(char *dirp, struct cachefs_user_values *uv,
4480Sstevel@tonic-gate     struct cache_label *clabel)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate 	int xx;
4510Sstevel@tonic-gate 	char path[CACHEFS_XMAXPATH];
4520Sstevel@tonic-gate 	int fd;
4530Sstevel@tonic-gate 	void *bufp;
4540Sstevel@tonic-gate 	int cnt;
4550Sstevel@tonic-gate 	struct cache_usage cu;
4560Sstevel@tonic-gate 	FILE *fp;
4570Sstevel@tonic-gate 	char *parent;
4580Sstevel@tonic-gate 	struct statvfs64 svfs;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	cu.cu_blksused = 0;
4610Sstevel@tonic-gate 	cu.cu_filesused = 0;
4620Sstevel@tonic-gate 	cu.cu_flags = 0;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	/* make sure cache dir name is not too long */
4650Sstevel@tonic-gate 	if (strlen(dirp) > (size_t)PATH_MAX) {
4660Sstevel@tonic-gate 		pr_err(gettext("path name %s is too long."), dirp);
4670Sstevel@tonic-gate 		return (-1);
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/* ensure the path isn't in cachefs */
4710Sstevel@tonic-gate 	parent = cachefs_file_to_dir(dirp);
4720Sstevel@tonic-gate 	if (parent == NULL) {
4730Sstevel@tonic-gate 		pr_err(gettext("Out of memory"));
4740Sstevel@tonic-gate 		return (-1);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 	if (statvfs64(parent, &svfs) != 0) {
4770Sstevel@tonic-gate 		pr_err(gettext("%s: %s"), parent, strerror(errno));
4780Sstevel@tonic-gate 		free(parent);
4790Sstevel@tonic-gate 		return (-1);
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 	if (strcmp(svfs.f_basetype, CACHEFS_BASETYPE) == 0) {
4820Sstevel@tonic-gate 		pr_err(gettext("Cannot create cache in cachefs filesystem"));
4830Sstevel@tonic-gate 		free(parent);
4840Sstevel@tonic-gate 		return (-1);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 	free(parent);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/* make the directory */
4890Sstevel@tonic-gate 	if (mkdir(dirp, 0) == -1) {
4900Sstevel@tonic-gate 		switch (errno) {
4910Sstevel@tonic-gate 		case EEXIST:
4920Sstevel@tonic-gate 			pr_err(gettext("%s already exists."), dirp);
4930Sstevel@tonic-gate 			break;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		default:
4960Sstevel@tonic-gate 			pr_err(gettext("mkdir %s failed: %s"),
4970Sstevel@tonic-gate 			    dirp, strerror(errno));
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 		return (-1);
5000Sstevel@tonic-gate 	}
5010Sstevel@tonic-gate 	cu.cu_filesused += 1;
5020Sstevel@tonic-gate 	cu.cu_blksused += 1;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	/* convert user values to a cache_label */
5050Sstevel@tonic-gate 	if (uv != NULL) {
5060Sstevel@tonic-gate 		xx = cachefs_convert_uv2cl(uv, clabel, dirp);
5070Sstevel@tonic-gate 		if (xx)
5080Sstevel@tonic-gate 			return (-2);
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	/*
5120Sstevel@tonic-gate 	 * Create the cache directory lock file.
5130Sstevel@tonic-gate 	 * Used by the kernel module to indicate the cache is in use.
5140Sstevel@tonic-gate 	 * This file will be <2G.
5150Sstevel@tonic-gate 	 */
5160Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOCK_FILE);
5170Sstevel@tonic-gate 	fd = open(path, O_RDWR | O_CREAT, 0700);
5180Sstevel@tonic-gate 	if (fd == -1) {
5190Sstevel@tonic-gate 		pr_err(gettext("Cannot create lock file %s"), path);
5200Sstevel@tonic-gate 		return (-1);
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate 	close(fd);
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	/* make the directory for the back file system mount points */
5250Sstevel@tonic-gate 	/* note: we do not count this directory in the resources */
5260Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
5270Sstevel@tonic-gate 	if (mkdir(path, 0700) == -1) {
5280Sstevel@tonic-gate 		pr_err(gettext("mkdir %s failed: %s"), path,
5290Sstevel@tonic-gate 		    strerror(errno));
5300Sstevel@tonic-gate 		return (-2);
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	/* make the directory for lost+found */
5340Sstevel@tonic-gate 	/* note: we do not count this directory in the resources */
5350Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOSTFOUND_NAME);
5360Sstevel@tonic-gate 	if (mkdir(path, 0700) == -1) {
5370Sstevel@tonic-gate 		pr_err(gettext("mkdir %s failed: %s"), path,
5380Sstevel@tonic-gate 		    strerror(errno));
5390Sstevel@tonic-gate 		return (-2);
5400Sstevel@tonic-gate 	}
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/* make the networker "don't back up" file; this file is <2GB */
5430Sstevel@tonic-gate 	xx = 0;
5440Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
5450Sstevel@tonic-gate 	if ((fp = fopen(path, "w")) != NULL) {
5460Sstevel@tonic-gate 		if (realpath(dirp, path) != NULL) {
547*633Sgt29601 			fprintf(fp, "<< ./ >>\n");
5480Sstevel@tonic-gate 			fprintf(fp, "+skip: .?* *\n");
5490Sstevel@tonic-gate 			if (fclose(fp) == 0)
5500Sstevel@tonic-gate 				xx = 1;
5510Sstevel@tonic-gate 		}
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 	if (xx == 0) {
5540Sstevel@tonic-gate 		snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
5550Sstevel@tonic-gate 		pr_err(gettext("can't create %s"), path);
5560Sstevel@tonic-gate 		(void) unlink(path);
5570Sstevel@tonic-gate 	} else {
5580Sstevel@tonic-gate 		cu.cu_filesused += 1;
5590Sstevel@tonic-gate 		cu.cu_blksused += 1;
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/* create the unmount file */
5630Sstevel@tonic-gate 	xx = 0;
5640Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_UNMNT_FILE);
5650Sstevel@tonic-gate 	if ((fp = fopen(path, "w")) != NULL) {
5660Sstevel@tonic-gate 		time32_t btime;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 		btime = get_boottime();
5690Sstevel@tonic-gate 		fwrite((void *)&btime, sizeof (btime), 1, fp);
5700Sstevel@tonic-gate 		if (fclose(fp) == 0)
5710Sstevel@tonic-gate 			xx = 1;
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 	if (xx == 0)
5740Sstevel@tonic-gate 		pr_err(gettext("can't create .cfs_unmnt file"));
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	/* create the cache label file */
5770Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
5780Sstevel@tonic-gate 	xx = cachefs_label_file_put(path, clabel);
5790Sstevel@tonic-gate 	if (xx == -1) {
5800Sstevel@tonic-gate 		pr_err(gettext("creating %s failed."), path);
5810Sstevel@tonic-gate 		return (-2);
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 	cu.cu_filesused += 1;
5840Sstevel@tonic-gate 	cu.cu_blksused += 1;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/* create the cache label duplicate file */
5870Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s.dup", dirp, CACHELABEL_NAME);
5880Sstevel@tonic-gate 	xx = cachefs_label_file_put(path, clabel);
5890Sstevel@tonic-gate 	if (xx == -1) {
5900Sstevel@tonic-gate 		pr_err(gettext("creating %s failed."), path);
5910Sstevel@tonic-gate 		return (-2);
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 	cu.cu_filesused += 1;
5940Sstevel@tonic-gate 	cu.cu_blksused += 1;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/* create the resouce file; this file will be <2GB */
5970Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, RESOURCE_NAME);
5980Sstevel@tonic-gate 	fd = open(path, O_CREAT | O_RDWR, 0600);
5990Sstevel@tonic-gate 	if (fd == -1) {
6000Sstevel@tonic-gate 		pr_err(gettext("create %s failed: %s"), path,
6010Sstevel@tonic-gate 		    strerror(errno));
6020Sstevel@tonic-gate 		return (-2);
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 	cu.cu_filesused += 1;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	/* allocate a zeroed buffer for filling the resouce file */
6070Sstevel@tonic-gate 	bufp = calloc(1, MAXBSIZE);
6080Sstevel@tonic-gate 	if (bufp == NULL) {
6090Sstevel@tonic-gate 		pr_err(gettext("out of space %d."), MAXBSIZE);
6100Sstevel@tonic-gate 		close(fd);
6110Sstevel@tonic-gate 		return (-2);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	/* determine number of MAXBSIZE chunks to make the file */
6150Sstevel@tonic-gate 	cnt = 1;	/* for the header */
6160Sstevel@tonic-gate 	cnt += clabel->cl_maxinodes / CACHEFS_RLPMBS;
6170Sstevel@tonic-gate 	if ((clabel->cl_maxinodes % CACHEFS_RLPMBS) != 0)
6180Sstevel@tonic-gate 		++cnt;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	/* fill up the file with zeros */
6210Sstevel@tonic-gate 	for (xx = 0; xx < cnt; xx++) {
6220Sstevel@tonic-gate 		if (write(fd, bufp, MAXBSIZE) != MAXBSIZE) {
6230Sstevel@tonic-gate 			pr_err(gettext("write %s failed: %s"), path,
6240Sstevel@tonic-gate 			    strerror(errno));
6250Sstevel@tonic-gate 			close(fd);
6260Sstevel@tonic-gate 			free(bufp);
6270Sstevel@tonic-gate 			return (-2);
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 	free(bufp);
6310Sstevel@tonic-gate 	cu.cu_blksused += cnt;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	/* position to the begining of the file */
6340Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) == -1) {
6350Sstevel@tonic-gate 		pr_err(gettext("lseek %s failed: %s"), path,
6360Sstevel@tonic-gate 		    strerror(errno));
6370Sstevel@tonic-gate 		close(fd);
6380Sstevel@tonic-gate 		return (-2);
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	/* write the cache usage structure */
6420Sstevel@tonic-gate 	xx = sizeof (struct cache_usage);
6430Sstevel@tonic-gate 	if (write(fd, &cu, xx) != xx) {
6440Sstevel@tonic-gate 		pr_err(gettext("cu write %s failed: %s"), path,
6450Sstevel@tonic-gate 		    strerror(errno));
6460Sstevel@tonic-gate 		close(fd);
6470Sstevel@tonic-gate 		return (-2);
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	/* make sure the contents get to disk */
6510Sstevel@tonic-gate 	if (fsync(fd) != 0) {
6520Sstevel@tonic-gate 		pr_err(gettext("fsync %s failed: %s"), path,
6530Sstevel@tonic-gate 		    strerror(errno));
6540Sstevel@tonic-gate 		close(fd);
6550Sstevel@tonic-gate 		return (-2);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	close(fd);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/* return success */
6600Sstevel@tonic-gate 	return (0);
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate /*
6640Sstevel@tonic-gate  *
6650Sstevel@tonic-gate  *			cachefs_delete_all_cache
6660Sstevel@tonic-gate  *
6670Sstevel@tonic-gate  * Description:
6680Sstevel@tonic-gate  *	Delete all caches in cache directory.
6690Sstevel@tonic-gate  * Arguments:
6700Sstevel@tonic-gate  *	dirp	the pathname of of the cache directory to delete
6710Sstevel@tonic-gate  * Returns:
6720Sstevel@tonic-gate  *	Returns 0 for success or -1 for an error.
6730Sstevel@tonic-gate  * Preconditions:
6740Sstevel@tonic-gate  *	precond(dirp)
6750Sstevel@tonic-gate  */
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate int
cachefs_delete_all_cache(char * dirp)6780Sstevel@tonic-gate cachefs_delete_all_cache(char *dirp)
6790Sstevel@tonic-gate {
6800Sstevel@tonic-gate 	DIR *dp;
6810Sstevel@tonic-gate 	struct dirent64 *dep;
6820Sstevel@tonic-gate 	int xx;
6830Sstevel@tonic-gate 	char path[CACHEFS_XMAXPATH];
6840Sstevel@tonic-gate 	struct stat64 statinfo;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	/* make sure cache dir name is not too long */
6870Sstevel@tonic-gate 	if (strlen(dirp) > (size_t)PATH_MAX) {
6880Sstevel@tonic-gate 		pr_err(gettext("path name %s is too long."),
6890Sstevel@tonic-gate 		    dirp);
6900Sstevel@tonic-gate 		return (-1);
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/* check that dirp is probably a cachefs directory */
6940Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
6950Sstevel@tonic-gate 	xx = access(path, R_OK | W_OK | X_OK);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
6980Sstevel@tonic-gate 	xx |= access(path, R_OK | W_OK);
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	if (xx) {
7010Sstevel@tonic-gate 		pr_err(gettext("%s does not appear to be a "
7020Sstevel@tonic-gate 		    "cachefs cache directory."), dirp);
7030Sstevel@tonic-gate 		return (-1);
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/* remove the lost+found directory if it exists and is empty */
7070Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOSTFOUND_NAME);
7080Sstevel@tonic-gate 	xx = rmdir(path);
7090Sstevel@tonic-gate 	if (xx == -1) {
7100Sstevel@tonic-gate 		if (errno == EEXIST) {
7110Sstevel@tonic-gate 			pr_err(gettext("Cannot delete cache '%s'.  "
7120Sstevel@tonic-gate 			    "First move files in '%s' to a safe location."),
7130Sstevel@tonic-gate 			    dirp, path);
7140Sstevel@tonic-gate 			return (-1);
7150Sstevel@tonic-gate 		} else if (errno != ENOENT) {
7160Sstevel@tonic-gate 			pr_err(gettext("rmdir %s failed: %s"), path,
7170Sstevel@tonic-gate 			    strerror(errno));
7180Sstevel@tonic-gate 			return (-1);
7190Sstevel@tonic-gate 		}
7200Sstevel@tonic-gate 	}
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/* delete the back FS mount point directory if it exists */
7230Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, BACKMNT_NAME);
7240Sstevel@tonic-gate 	xx = lstat64(path, &statinfo);
7250Sstevel@tonic-gate 	if (xx == -1) {
7260Sstevel@tonic-gate 		if (errno != ENOENT) {
7270Sstevel@tonic-gate 			pr_err(gettext("lstat %s failed: %s"), path,
7280Sstevel@tonic-gate 			    strerror(errno));
7290Sstevel@tonic-gate 			return (-1);
7300Sstevel@tonic-gate 		}
7310Sstevel@tonic-gate 	} else {
7320Sstevel@tonic-gate 		xx = nftw64(path, cachefs_delete_file, 16,
7330Sstevel@tonic-gate 		    FTW_PHYS | FTW_DEPTH | FTW_MOUNT);
7340Sstevel@tonic-gate 		if (xx == -1) {
7350Sstevel@tonic-gate 			pr_err(gettext("unable to delete %s"), path);
7360Sstevel@tonic-gate 			return (-1);
7370Sstevel@tonic-gate 		}
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	/* open the cache directory specified */
7410Sstevel@tonic-gate 	if ((dp = opendir(dirp)) == NULL) {
7420Sstevel@tonic-gate 		pr_err(gettext("cannot open cache directory %s: %s"),
7430Sstevel@tonic-gate 		    dirp, strerror(errno));
7440Sstevel@tonic-gate 		return (-1);
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	/* read the file names in the cache directory */
7480Sstevel@tonic-gate 	while ((dep = readdir64(dp)) != NULL) {
7490Sstevel@tonic-gate 		/* ignore . and .. */
7500Sstevel@tonic-gate 		if (strcmp(dep->d_name, ".") == 0 ||
7510Sstevel@tonic-gate 				strcmp(dep->d_name, "..") == 0)
7520Sstevel@tonic-gate 			continue;
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 		/* stat the file */
7550Sstevel@tonic-gate 		snprintf(path, sizeof (path), "%s/%s", dirp, dep->d_name);
7560Sstevel@tonic-gate 		xx = lstat64(path, &statinfo);
7570Sstevel@tonic-gate 		if (xx == -1) {
7580Sstevel@tonic-gate 			if (errno == ENOENT) {
7590Sstevel@tonic-gate 				/* delete_cache may have nuked a directory */
7600Sstevel@tonic-gate 				continue;
7610Sstevel@tonic-gate 			}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 			pr_err(gettext("lstat %s failed: %s"),
7640Sstevel@tonic-gate 			    path, strerror(errno));
7650Sstevel@tonic-gate 			closedir(dp);
7660Sstevel@tonic-gate 			return (-1);
7670Sstevel@tonic-gate 		}
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 		/* ignore anything that is not a link */
7700Sstevel@tonic-gate 		if (!S_ISLNK(statinfo.st_mode))
7710Sstevel@tonic-gate 			continue;
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 		/* delete the file system cache directory */
7740Sstevel@tonic-gate 		xx = cachefs_delete_cache(dirp, dep->d_name);
7750Sstevel@tonic-gate 		if (xx) {
7760Sstevel@tonic-gate 			closedir(dp);
7770Sstevel@tonic-gate 			return (-1);
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate 	closedir(dp);
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/* remove the cache dir unmount file */
7830Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_UNMNT_FILE);
7840Sstevel@tonic-gate 	xx = unlink(path);
7850Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
7860Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
7870Sstevel@tonic-gate 		    strerror(errno));
7880Sstevel@tonic-gate 		return (-1);
7890Sstevel@tonic-gate 	}
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/* remove the cache label file */
7920Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHELABEL_NAME);
7930Sstevel@tonic-gate 	xx = unlink(path);
7940Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
7950Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
7960Sstevel@tonic-gate 		    strerror(errno));
7970Sstevel@tonic-gate 		return (-1);
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	/* remove the cache label duplicate file */
8010Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s.dup", dirp, CACHELABEL_NAME);
8020Sstevel@tonic-gate 	xx = unlink(path);
8030Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
8040Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
8050Sstevel@tonic-gate 		    strerror(errno));
8060Sstevel@tonic-gate 		return (-1);
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	/* remove the resource file */
8100Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, RESOURCE_NAME);
8110Sstevel@tonic-gate 	xx = unlink(path);
8120Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
8130Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
8140Sstevel@tonic-gate 		    strerror(errno));
8150Sstevel@tonic-gate 		return (-1);
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	/* remove the cachefslog file if it exists */
8190Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, LOG_STATUS_NAME);
8200Sstevel@tonic-gate 	(void) unlink(path);
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	/* remove the networker "don't back up" file if it exists */
8230Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, NOBACKUP_NAME);
8240Sstevel@tonic-gate 	(void) unlink(path);
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	/* remove the lock file */
8270Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, CACHEFS_LOCK_FILE);
8280Sstevel@tonic-gate 	xx = unlink(path);
8290Sstevel@tonic-gate 	if ((xx == -1) && (errno != ENOENT)) {
8300Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
8310Sstevel@tonic-gate 		    strerror(errno));
8320Sstevel@tonic-gate 		return (-1);
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	/* remove the directory */
8360Sstevel@tonic-gate 	xx = rmdir(dirp);
8370Sstevel@tonic-gate 	if (xx == -1) {
8380Sstevel@tonic-gate 		pr_err(gettext("rmdir %s failed: %s"), dirp,
8390Sstevel@tonic-gate 		    strerror(errno));
8400Sstevel@tonic-gate 		return (-1);
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	/* return success */
8440Sstevel@tonic-gate 	return (0);
8450Sstevel@tonic-gate }
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate /*
8480Sstevel@tonic-gate  *
8490Sstevel@tonic-gate  *			cachefs_delete_cache
8500Sstevel@tonic-gate  *
8510Sstevel@tonic-gate  * Description:
8520Sstevel@tonic-gate  *	Deletes the specified file system cache.
8530Sstevel@tonic-gate  * Arguments:
8540Sstevel@tonic-gate  *	dirp	cache directory name
8550Sstevel@tonic-gate  *	namep	file system cache directory to delete
8560Sstevel@tonic-gate  * Returns:
8570Sstevel@tonic-gate  *	Returns 0 for success, -1 for failure.
8580Sstevel@tonic-gate  * Preconditions:
8590Sstevel@tonic-gate  *	precond(dirp)
8600Sstevel@tonic-gate  *	precond(namep)
8610Sstevel@tonic-gate  */
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate int
cachefs_delete_cache(char * dirp,char * namep)8640Sstevel@tonic-gate cachefs_delete_cache(char *dirp, char *namep)
8650Sstevel@tonic-gate {
8660Sstevel@tonic-gate 	char path[CACHEFS_XMAXPATH];
8670Sstevel@tonic-gate 	char buf[CACHEFS_XMAXPATH];
8680Sstevel@tonic-gate 	int xx;
8690Sstevel@tonic-gate 	struct stat64 statinfo;
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	/* make sure cache dir name is not too long */
8720Sstevel@tonic-gate 	if (strlen(dirp) > (size_t)PATH_MAX) {
8730Sstevel@tonic-gate 		pr_err(gettext("path name %s is too long."),
8740Sstevel@tonic-gate 		    dirp);
8750Sstevel@tonic-gate 		return (-1);
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/* construct the path name of the file system cache directory */
8790Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, namep);
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	/* stat the specified file */
8820Sstevel@tonic-gate 	xx = lstat64(path, &statinfo);
8830Sstevel@tonic-gate 	if (xx == -1) {
8840Sstevel@tonic-gate 		pr_err(gettext("lstat %s failed: %s"), path,
8850Sstevel@tonic-gate 		    strerror(errno));
8860Sstevel@tonic-gate 		return (-1);
8870Sstevel@tonic-gate 	}
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	/* make sure name is a symbolic link */
8900Sstevel@tonic-gate 	if (!S_ISLNK(statinfo.st_mode)) {
8910Sstevel@tonic-gate 		pr_err(gettext("\"%s\" is not a valid cache id."), namep);
8920Sstevel@tonic-gate 		return (-1);
8930Sstevel@tonic-gate 	}
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	/* read the contents of the symbolic link */
8960Sstevel@tonic-gate 	xx = readlink(path, buf, sizeof (buf));
8970Sstevel@tonic-gate 	if (xx == -1) {
8980Sstevel@tonic-gate 		pr_err(gettext("Readlink of %s failed: %s"), path,
8990Sstevel@tonic-gate 		    strerror(errno));
9000Sstevel@tonic-gate 		return (-1);
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 	buf[xx] = '\0';
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	/* remove the directory */
9050Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, buf);
9060Sstevel@tonic-gate 	xx = nftw64(path, cachefs_delete_file, 16,
9070Sstevel@tonic-gate 	    FTW_PHYS | FTW_DEPTH | FTW_MOUNT);
9080Sstevel@tonic-gate 	if (xx == -1) {
9090Sstevel@tonic-gate 		pr_err(gettext("directory walk of %s failed."), dirp);
9100Sstevel@tonic-gate 		return (-1);
9110Sstevel@tonic-gate 	}
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/* delete the link */
9140Sstevel@tonic-gate 	snprintf(path, sizeof (path), "%s/%s", dirp, namep);
9150Sstevel@tonic-gate 	if (unlink(path) == -1) {
9160Sstevel@tonic-gate 		pr_err(gettext("unlink %s failed: %s"), path,
9170Sstevel@tonic-gate 		    strerror(errno));
9180Sstevel@tonic-gate 		return (-1);
9190Sstevel@tonic-gate 	}
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	/* return success */
9220Sstevel@tonic-gate 	return (0);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate /*
9260Sstevel@tonic-gate  *
9270Sstevel@tonic-gate  *			cachefs_delete_file
9280Sstevel@tonic-gate  *
9290Sstevel@tonic-gate  * Description:
9300Sstevel@tonic-gate  *	Remove a file or directory; called by nftw64().
9310Sstevel@tonic-gate  * Arguments:
9320Sstevel@tonic-gate  *	namep	pathname of the file
9330Sstevel@tonic-gate  *	statp	stat info about the file
9340Sstevel@tonic-gate  *	flg	info about file
9350Sstevel@tonic-gate  *	ftwp	depth information
9360Sstevel@tonic-gate  * Returns:
9370Sstevel@tonic-gate  *	Returns 0 for success, -1 for failure.
9380Sstevel@tonic-gate  * Preconditions:
9390Sstevel@tonic-gate  *	precond(namep)
9400Sstevel@tonic-gate  */
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate int
cachefs_delete_file(const char * namep,const struct stat64 * statp,int flg,struct FTW * ftwp)9430Sstevel@tonic-gate cachefs_delete_file(const char *namep, const struct stat64 *statp, int flg,
9440Sstevel@tonic-gate     struct FTW *ftwp)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate 	/* ignore . and .. */
9470Sstevel@tonic-gate 	if (strcmp(namep, ".") == 0 || strcmp(namep, "..") == 0)
9480Sstevel@tonic-gate 		return (0);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	switch (flg) {
9510Sstevel@tonic-gate 	case FTW_F:	/* files */
9520Sstevel@tonic-gate 	case FTW_SL:
9530Sstevel@tonic-gate 		if (unlink(namep) == -1) {
9540Sstevel@tonic-gate 			pr_err(gettext("unlink %s failed: %s"),
9550Sstevel@tonic-gate 			    namep, strerror(errno));
9560Sstevel@tonic-gate 			return (-1);
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 		break;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	case FTW_DP:	/* directories that have their children processed */
9610Sstevel@tonic-gate 		if (rmdir(namep) == -1) {
9620Sstevel@tonic-gate 			pr_err(gettext("rmdir %s failed: %s"),
9630Sstevel@tonic-gate 			    namep, strerror(errno));
9640Sstevel@tonic-gate 			return (-1);
9650Sstevel@tonic-gate 		}
9660Sstevel@tonic-gate 		break;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	case FTW_D:	/* ignore directories if children not processed */
9690Sstevel@tonic-gate 		break;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	default:
9720Sstevel@tonic-gate 		pr_err(gettext("failure on file %s, flg %d."),
9730Sstevel@tonic-gate 		    namep, flg);
9740Sstevel@tonic-gate 		return (-1);
9750Sstevel@tonic-gate 	}
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	/* return success */
9780Sstevel@tonic-gate 	return (0);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate /*
9820Sstevel@tonic-gate  *
9830Sstevel@tonic-gate  *			cachefs_convert_uv2cl
9840Sstevel@tonic-gate  *
9850Sstevel@tonic-gate  * Description:
9860Sstevel@tonic-gate  *	Copies the contents of a cachefs_user_values object into a
9870Sstevel@tonic-gate  *	cache_label object, performing the necessary conversions.
9880Sstevel@tonic-gate  * Arguments:
9890Sstevel@tonic-gate  *	uvp	cachefs_user_values to copy from
9900Sstevel@tonic-gate  *	clp	cache_label to copy into
9910Sstevel@tonic-gate  *	dirp	cache directory
9920Sstevel@tonic-gate  * Returns:
9930Sstevel@tonic-gate  *	Returns 0 for success, -1 for an error.
9940Sstevel@tonic-gate  * Preconditions:
9950Sstevel@tonic-gate  *	precond(uvp)
9960Sstevel@tonic-gate  *	precond(clp)
9970Sstevel@tonic-gate  *	precond(dirp)
9980Sstevel@tonic-gate  */
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate int
cachefs_convert_uv2cl(const struct cachefs_user_values * uvp,struct cache_label * clp,const char * dirp)10010Sstevel@tonic-gate cachefs_convert_uv2cl(const struct cachefs_user_values *uvp,
10020Sstevel@tonic-gate     struct cache_label *clp, const char *dirp)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate 	struct statvfs64 fs;
10050Sstevel@tonic-gate 	int xx;
10060Sstevel@tonic-gate 	double ftmp;
10070Sstevel@tonic-gate 	double temp;
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	/* get file system information */
10100Sstevel@tonic-gate 	xx = statvfs64(dirp, &fs);
10110Sstevel@tonic-gate 	if (xx == -1) {
10120Sstevel@tonic-gate 		pr_err(gettext("statvfs %s failed: %s"), dirp,
10130Sstevel@tonic-gate 		    strerror(errno));
10140Sstevel@tonic-gate 		return (-1);
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	ftmp = (double)fs.f_frsize / (double)MAXBSIZE;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	/* front fs is less than 1 terabyte */
10200Sstevel@tonic-gate 	temp = (double)uvp->uv_maxblocks / 100.0 *
10210Sstevel@tonic-gate 	    (double)fs.f_blocks * ftmp + .5;
10220Sstevel@tonic-gate 	clp->cl_maxblks = temp < (double)INT_MAX ? (int)temp : INT_MAX;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	temp = (double)uvp->uv_minblocks / 100.0 *
10250Sstevel@tonic-gate 	    (double)fs.f_blocks * ftmp + .5;
10260Sstevel@tonic-gate 	clp->cl_blockmin = temp < (double)INT_MAX ? (int)temp : INT_MAX;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	temp = (double)uvp->uv_threshblocks / 100.0 *
10290Sstevel@tonic-gate 	    (double)fs.f_blocks * ftmp + .5;
10300Sstevel@tonic-gate 	clp->cl_blocktresh = temp < (double)INT_MAX ? (int)temp : INT_MAX;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	temp = (double)uvp->uv_maxfiles / 100.0 * (double)fs.f_files + .5;
10330Sstevel@tonic-gate 	clp->cl_maxinodes = temp < (double)INT_MAX ? (int)temp : INT_MAX;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	temp = (double)uvp->uv_minfiles / 100.0 * (double)fs.f_files + .5;
10360Sstevel@tonic-gate 	clp->cl_filemin = temp < (double)INT_MAX ? (int)temp : INT_MAX;
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	temp = (double)uvp->uv_threshfiles / 100.0 * (double)fs.f_files +.5;
10390Sstevel@tonic-gate 	clp->cl_filetresh = temp < (double)INT_MAX ? (int)temp : INT_MAX;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	ftmp = (double)(1024 * 1024) / (double)MAXBSIZE;
10420Sstevel@tonic-gate 	clp->cl_maxfiles = uvp->uv_maxfilesize * ftmp + .5;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	clp->cl_blkhiwat = uvp->uv_hiblocks / 100.0 * clp->cl_maxblks + .5;
10450Sstevel@tonic-gate 	clp->cl_blklowat = uvp->uv_lowblocks / 100.0 * clp->cl_maxblks + .5;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	clp->cl_filehiwat = uvp->uv_hifiles / 100.0 * clp->cl_maxinodes + .5;
10480Sstevel@tonic-gate 	clp->cl_filelowat = uvp->uv_lowfiles / 100.0 * clp->cl_maxinodes + .5;
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	clp->cl_cfsversion = CFSVERSION;
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	/* return success */
10530Sstevel@tonic-gate 	return (0);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate /*
10570Sstevel@tonic-gate  *
10580Sstevel@tonic-gate  *			cachefs_convert_cl2uv
10590Sstevel@tonic-gate  *
10600Sstevel@tonic-gate  * Description:
10610Sstevel@tonic-gate  *	Copies the contents of a cache_label object into a
10620Sstevel@tonic-gate  *	cachefs_user_values object, performing the necessary conversions.
10630Sstevel@tonic-gate  * Arguments:
10640Sstevel@tonic-gate  *	clp	cache_label to copy from
10650Sstevel@tonic-gate  *	uvp	cachefs_user_values to copy into
10660Sstevel@tonic-gate  *	dirp	cache directory
10670Sstevel@tonic-gate  * Returns:
10680Sstevel@tonic-gate  *	Returns 0 for success, -1 for an error.
10690Sstevel@tonic-gate  * Preconditions:
10700Sstevel@tonic-gate  *	precond(clp)
10710Sstevel@tonic-gate  *	precond(uvp)
10720Sstevel@tonic-gate  *	precond(dirp)
10730Sstevel@tonic-gate  */
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate int
cachefs_convert_cl2uv(const struct cache_label * clp,struct cachefs_user_values * uvp,const char * dirp)10760Sstevel@tonic-gate cachefs_convert_cl2uv(const struct cache_label *clp,
10770Sstevel@tonic-gate     struct cachefs_user_values *uvp, const char *dirp)
10780Sstevel@tonic-gate {
10790Sstevel@tonic-gate 	struct statvfs64 fs;
10800Sstevel@tonic-gate 	int xx;
10810Sstevel@tonic-gate 	double temp;
10820Sstevel@tonic-gate 	double ftmp;
10830Sstevel@tonic-gate 	long long ltmp;
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	/* get file system information */
10860Sstevel@tonic-gate 	xx = statvfs64(dirp, &fs);
10870Sstevel@tonic-gate 	if (xx == -1) {
10880Sstevel@tonic-gate 		pr_err(gettext("statvfs %s failed: %s"), dirp,
10890Sstevel@tonic-gate 		    strerror(errno));
10900Sstevel@tonic-gate 		return (-1);
10910Sstevel@tonic-gate 	}
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate #define	BOUND(yy) \
10940Sstevel@tonic-gate 	yy = (yy < 0) ? 0 : yy; \
10950Sstevel@tonic-gate 	yy = (yy > 100) ? 100 : yy;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	ftmp = (double)MAXBSIZE / (double)fs.f_frsize;
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	temp = (double)clp->cl_maxblks * ftmp /
11000Sstevel@tonic-gate 	    (double)fs.f_blocks * 100. + .5;
11010Sstevel@tonic-gate 	BOUND(temp);
11020Sstevel@tonic-gate 	uvp->uv_maxblocks = (int)temp;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	temp = (double)clp->cl_blockmin * ftmp /
11050Sstevel@tonic-gate 	    (double)fs.f_blocks * 100. + .5;
11060Sstevel@tonic-gate 	BOUND(temp);
11070Sstevel@tonic-gate 	uvp->uv_minblocks = (int)temp;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	temp = (double)clp->cl_blocktresh * ftmp /
11100Sstevel@tonic-gate 	    (double)fs.f_blocks * 100. + .5;
11110Sstevel@tonic-gate 	BOUND(temp);
11120Sstevel@tonic-gate 	uvp->uv_threshblocks = (int)temp;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	temp = ((double)clp->cl_maxinodes / fs.f_files) * 100. + .5;
11150Sstevel@tonic-gate 	BOUND(temp);
11160Sstevel@tonic-gate 	uvp->uv_maxfiles = (int)temp;
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	temp = ((double)clp->cl_filemin / fs.f_files) * 100. + .5;
11190Sstevel@tonic-gate 	BOUND(temp);
11200Sstevel@tonic-gate 	uvp->uv_minfiles = (int)temp;
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	temp = ((double)clp->cl_filetresh / fs.f_files) * 100. + .5;
11230Sstevel@tonic-gate 	BOUND(temp);
11240Sstevel@tonic-gate 	uvp->uv_threshfiles = (int)temp;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	ltmp = ((long long)clp->cl_maxfiles * MAXBSIZE);
11270Sstevel@tonic-gate 	uvp->uv_maxfilesize = (ltmp + (MAXBSIZE / 2)) / (1024 * 1024);
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	xx = ((double)clp->cl_blkhiwat / clp->cl_maxblks) * 100. + .5;
11300Sstevel@tonic-gate 	BOUND(xx);
11310Sstevel@tonic-gate 	uvp->uv_hiblocks = xx;
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	xx = ((double)clp->cl_blklowat / clp->cl_maxblks) * 100. + .5;
11340Sstevel@tonic-gate 	BOUND(xx);
11350Sstevel@tonic-gate 	uvp->uv_lowblocks = xx;
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	xx = ((double)clp->cl_filehiwat / clp->cl_maxinodes) * 100. + .5;
11380Sstevel@tonic-gate 	BOUND(xx);
11390Sstevel@tonic-gate 	uvp->uv_hifiles = xx;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	xx = ((double)clp->cl_filelowat / clp->cl_maxinodes) * 100. + .5;
11420Sstevel@tonic-gate 	BOUND(xx);
11430Sstevel@tonic-gate 	uvp->uv_lowfiles = xx;
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	/* return success */
11460Sstevel@tonic-gate 	return (0);
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate /*
11500Sstevel@tonic-gate  * cachefs_file_to_dir
11510Sstevel@tonic-gate  *
11520Sstevel@tonic-gate  * takes in a path, and returns the parent directory of that path.
11530Sstevel@tonic-gate  *
11540Sstevel@tonic-gate  * it's the caller's responsibility to free the pointer returned by
11550Sstevel@tonic-gate  * this function.
11560Sstevel@tonic-gate  */
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate char *
cachefs_file_to_dir(const char * path)11590Sstevel@tonic-gate cachefs_file_to_dir(const char *path)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate 	char *rc, *cp;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	if (path == NULL)
11640Sstevel@tonic-gate 		return (NULL);
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	rc = strdup(path);
11670Sstevel@tonic-gate 	if (rc == NULL)
11680Sstevel@tonic-gate 		return (NULL);
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if ((cp = strrchr(rc, '/')) == NULL) {
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 		/*
11730Sstevel@tonic-gate 		 * if no slashes at all, return "." (current directory).
11740Sstevel@tonic-gate 		 */
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		(void) free(rc);
11770Sstevel@tonic-gate 		rc = strdup(".");
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	} else if (cp == rc) {
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 		/*
11820Sstevel@tonic-gate 		 * else, if the last '/' is the first character, chop
11830Sstevel@tonic-gate 		 * off from there (i.e. return "/").
11840Sstevel@tonic-gate 		 */
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 		rc[1] = '\0';
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	} else {
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 		/*
11910Sstevel@tonic-gate 		 * else, we have a path like /foo/bar or foo/bar.
11920Sstevel@tonic-gate 		 * chop off from the last '/'.
11930Sstevel@tonic-gate 		 */
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 		*cp = '\0';
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	}
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	return (rc);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate /*
12030Sstevel@tonic-gate  *			cachefs_clean_flag_test
12040Sstevel@tonic-gate  *
12050Sstevel@tonic-gate  * Description:
12060Sstevel@tonic-gate  *	Tests whether or not the clean flag on the file system
12070Sstevel@tonic-gate  *	is set.
12080Sstevel@tonic-gate  * Arguments:
12090Sstevel@tonic-gate  *	cachedirp	name of the the file system cache directory
12100Sstevel@tonic-gate  * Returns:
12110Sstevel@tonic-gate  *	Returns 1 if the cache was shut down cleanly, 0 if not.
12120Sstevel@tonic-gate  * Preconditions:
12130Sstevel@tonic-gate  *	precond(cachedirp)
12140Sstevel@tonic-gate  */
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate int
cachefs_clean_flag_test(const char * cachedirp)12170Sstevel@tonic-gate cachefs_clean_flag_test(const char *cachedirp)
12180Sstevel@tonic-gate {
12190Sstevel@tonic-gate 	char *namep;
12200Sstevel@tonic-gate 	int xx;
12210Sstevel@tonic-gate 	char buf[MAXPATHLEN];
12220Sstevel@tonic-gate 	int fd;
12230Sstevel@tonic-gate 	struct cache_usage cu;
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	/* construct the path name of the resource file */
12260Sstevel@tonic-gate 	namep = RESOURCE_NAME;
12270Sstevel@tonic-gate 	xx = strlen(cachedirp) + strlen(namep) + 3;
12280Sstevel@tonic-gate 	if (xx >= MAXPATHLEN) {
12290Sstevel@tonic-gate 		pr_err(gettext("Path name too long %s/%s"),
12300Sstevel@tonic-gate 		    cachedirp, namep);
12310Sstevel@tonic-gate 		return (39);
12320Sstevel@tonic-gate 	}
12330Sstevel@tonic-gate 	snprintf(buf, sizeof (buf), "%s/%s", cachedirp, namep);
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	/* open the file; it will be <2GB */
12360Sstevel@tonic-gate 	fd = open(buf, O_RDONLY);
12370Sstevel@tonic-gate 	if (fd == -1) {
12380Sstevel@tonic-gate 		pr_err(gettext("Cannot open %s: %s"), buf, strerror(errno));
12390Sstevel@tonic-gate 		return (0);
12400Sstevel@tonic-gate 	}
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	/* read the cache_usage structure */
12430Sstevel@tonic-gate 	xx = read(fd, &cu, sizeof (cu));
12440Sstevel@tonic-gate 	if (xx != sizeof (cu)) {
12450Sstevel@tonic-gate 		pr_err(gettext("Error reading %s: %d %s"), buf,
12460Sstevel@tonic-gate 		    xx, strerror(errno));
12470Sstevel@tonic-gate 		close(fd);
12480Sstevel@tonic-gate 		return (0);
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 	close(fd);
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	/* return state of the cache */
12530Sstevel@tonic-gate 	return ((cu.cu_flags & CUSAGE_ACTIVE) == 0);
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate time32_t
get_boottime()12570Sstevel@tonic-gate get_boottime()
12580Sstevel@tonic-gate {
12590Sstevel@tonic-gate 	struct utmpx id, *putmp;
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	id.ut_type = BOOT_TIME;
12620Sstevel@tonic-gate 	setutxent();
12630Sstevel@tonic-gate 	if ((putmp = getutxid(&id)) != NULL)
12640Sstevel@tonic-gate 		return ((time32_t)putmp->ut_tv.tv_sec);
12650Sstevel@tonic-gate 	return (-1);
12660Sstevel@tonic-gate }
1267