xref: /titanic_44/usr/src/stand/lib/fs/ufs/ufsops.c (revision e0731422366620894c16c1ee6515551c5f00733d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d6bca47dSsommerfe  * Common Development and Distribution License (the "License").
6d6bca47dSsommerfe  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
224a634bb8Sga159272  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/param.h>
277c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
287c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
297c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
307c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/promif.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/stat.h>
357c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h>
367c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
377c478bd9Sstevel@tonic-gate #include <sys/salib.h>
387c478bd9Sstevel@tonic-gate #include <sys/sacache.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate int print_cache_stats = 0;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * This fd is used when talking to the device file itself.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate static fileid_t *head;
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * hooks into ufs logging support
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate extern void	lufs_boot_init(fileid_t *);
517c478bd9Sstevel@tonic-gate extern void	lufs_closeall(void);
527c478bd9Sstevel@tonic-gate extern void	lufs_merge_deltas(fileid_t *);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /* Only got one of these...ergo, only 1 fs open at once */
557c478bd9Sstevel@tonic-gate /* static */
567c478bd9Sstevel@tonic-gate devid_t		*ufs_devp;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate struct dirinfo {
597c478bd9Sstevel@tonic-gate 	int 	loc;
607c478bd9Sstevel@tonic-gate 	fileid_t *fi;
617c478bd9Sstevel@tonic-gate };
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  *  Function prototypes
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate static int	boot_ufs_mountroot(char *str);
677c478bd9Sstevel@tonic-gate static int	boot_ufs_unmountroot(void);
687c478bd9Sstevel@tonic-gate static int	boot_ufs_open(char *filename, int flags);
697c478bd9Sstevel@tonic-gate static int	boot_ufs_close(int fd);
707c478bd9Sstevel@tonic-gate static ssize_t	boot_ufs_read(int fd, caddr_t buf, size_t size);
717c478bd9Sstevel@tonic-gate static off_t	boot_ufs_lseek(int, off_t, int);
727c478bd9Sstevel@tonic-gate static int	boot_ufs_fstat(int fd, struct bootstat *stp);
737c478bd9Sstevel@tonic-gate static void	boot_ufs_closeall(int flag);
747c478bd9Sstevel@tonic-gate static int	boot_ufs_getdents(int fd, struct dirent *dep, unsigned size);
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate struct boot_fs_ops boot_ufs_ops = {
777c478bd9Sstevel@tonic-gate 	"ufs",
787c478bd9Sstevel@tonic-gate 	boot_ufs_mountroot,
797c478bd9Sstevel@tonic-gate 	boot_ufs_unmountroot,
807c478bd9Sstevel@tonic-gate 	boot_ufs_open,
817c478bd9Sstevel@tonic-gate 	boot_ufs_close,
827c478bd9Sstevel@tonic-gate 	boot_ufs_read,
837c478bd9Sstevel@tonic-gate 	boot_ufs_lseek,
847c478bd9Sstevel@tonic-gate 	boot_ufs_fstat,
857c478bd9Sstevel@tonic-gate 	boot_ufs_closeall,
867c478bd9Sstevel@tonic-gate 	boot_ufs_getdents
877c478bd9Sstevel@tonic-gate };
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static 	ino_t	find(fileid_t *filep, char *path);
907c478bd9Sstevel@tonic-gate static	ino_t	dlook(fileid_t *filep, char *path);
917c478bd9Sstevel@tonic-gate static 	daddr32_t	sbmap(fileid_t *filep, daddr32_t bn);
927c478bd9Sstevel@tonic-gate static  struct direct *readdir(struct dirinfo *dstuff);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /* These are the pools of buffers, etc. */
957c478bd9Sstevel@tonic-gate #define	NBUFS	(NIADDR+1)
967c478bd9Sstevel@tonic-gate /* Compilers like to play with alignment, so force the issue here */
977c478bd9Sstevel@tonic-gate static union {
987c478bd9Sstevel@tonic-gate 	char		*blk[NBUFS];
997c478bd9Sstevel@tonic-gate 	daddr32_t		*dummy;
1007c478bd9Sstevel@tonic-gate } b;
1017c478bd9Sstevel@tonic-gate daddr32_t		blknos[NBUFS];
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  *	There is only 1 open (mounted) device at any given time.
1057c478bd9Sstevel@tonic-gate  *	So we can keep a single, global devp file descriptor to
1067c478bd9Sstevel@tonic-gate  *	use to index into the di[] array.  This is not true for the
1077c478bd9Sstevel@tonic-gate  *	fi[] array.  We can have more than one file open at once,
1087c478bd9Sstevel@tonic-gate  *	so there is no global fd for the fi[].
1097c478bd9Sstevel@tonic-gate  *	The user program must save the fd passed back from open()
1107c478bd9Sstevel@tonic-gate  *	and use it to do subsequent read()'s.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static int
openi(fileid_t * filep,ino_t inode)1147c478bd9Sstevel@tonic-gate openi(fileid_t *filep, ino_t inode)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	int retval;
1177c478bd9Sstevel@tonic-gate 	struct dinode *dp;
1187c478bd9Sstevel@tonic-gate 	devid_t *devp = filep->fi_devp;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/* Try the inode cache first */
1217c478bd9Sstevel@tonic-gate 	if ((filep->fi_inode = get_icache(devp->di_dcookie, inode)) != NULL)
1227c478bd9Sstevel@tonic-gate 		return (0);
1237c478bd9Sstevel@tonic-gate 	/* Nope, not there so lets read it off the disk. */
1247c478bd9Sstevel@tonic-gate 	filep->fi_offset = 0;
1257c478bd9Sstevel@tonic-gate 	filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs,
1267c478bd9Sstevel@tonic-gate 	    itod(&devp->un_fs.di_fs, inode));
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	/* never more than 1 disk block */
1297c478bd9Sstevel@tonic-gate 	filep->fi_count = devp->un_fs.di_fs.fs_bsize;
1307c478bd9Sstevel@tonic-gate 	filep->fi_memp = filep->fi_buf;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	/* Maybe the block is in the disk block cache */
1337c478bd9Sstevel@tonic-gate 	if ((filep->fi_memp = get_bcache(filep)) == NULL) {
1347c478bd9Sstevel@tonic-gate 		/* Not in the block cache so read it from disk */
1357c478bd9Sstevel@tonic-gate 		if (retval = set_bcache(filep))
1367c478bd9Sstevel@tonic-gate 			return (retval);
1377c478bd9Sstevel@tonic-gate 		lufs_merge_deltas(filep);
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	dp = (struct dinode *)filep->fi_memp;
1417c478bd9Sstevel@tonic-gate 	filep->fi_inode = (struct inode *)
1427c478bd9Sstevel@tonic-gate 	    bkmem_alloc(sizeof (struct inode));
1437c478bd9Sstevel@tonic-gate 	bzero((char *)filep->fi_inode, sizeof (struct inode));
1447c478bd9Sstevel@tonic-gate 	filep->fi_inode->i_ic =
1457c478bd9Sstevel@tonic-gate 	    dp[itoo(&devp->un_fs.di_fs, inode)].di_un.di_icom;
1467c478bd9Sstevel@tonic-gate 	filep->fi_inode->i_number = inode;
1477c478bd9Sstevel@tonic-gate 	if (set_ricache(devp->di_dcookie, inode, (void *)filep->fi_inode,
1487c478bd9Sstevel@tonic-gate 	    sizeof (struct inode)))
1497c478bd9Sstevel@tonic-gate 		filep->fi_inode->i_flag = FI_NOCACHE;
1507c478bd9Sstevel@tonic-gate 	return (0);
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate static fileid_t *
find_fp(int fd)1547c478bd9Sstevel@tonic-gate find_fp(int fd)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	fileid_t *filep = head;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
1597c478bd9Sstevel@tonic-gate 		while ((filep = filep->fi_forw) != head)
1607c478bd9Sstevel@tonic-gate 			if (fd == filep->fi_filedes)
1617c478bd9Sstevel@tonic-gate 				return (filep->fi_taken ? filep : 0);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	return (0);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate static ino_t
find(fileid_t * filep,char * path)1687c478bd9Sstevel@tonic-gate find(fileid_t *filep, char *path)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	char *q;
1717c478bd9Sstevel@tonic-gate 	char c;
1727c478bd9Sstevel@tonic-gate 	ino_t inode;
1737c478bd9Sstevel@tonic-gate 	char lpath[MAXPATHLEN];
1747c478bd9Sstevel@tonic-gate 	char *lpathp = lpath;
1757c478bd9Sstevel@tonic-gate 	int len, r;
1767c478bd9Sstevel@tonic-gate 	devid_t	*devp;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (path == NULL || *path == '\0') {
1797c478bd9Sstevel@tonic-gate 		printf("null path\n");
1807c478bd9Sstevel@tonic-gate 		return ((ino_t)0);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	bzero(lpath, sizeof (lpath));
1847c478bd9Sstevel@tonic-gate 	bcopy(path, lpath, strlen(path));
1857c478bd9Sstevel@tonic-gate 	devp = filep->fi_devp;
1867c478bd9Sstevel@tonic-gate 	while (*lpathp) {
1877c478bd9Sstevel@tonic-gate 		/* if at the beginning of pathname get root inode */
1887c478bd9Sstevel@tonic-gate 		r = (lpathp == lpath);
1897c478bd9Sstevel@tonic-gate 		if (r && openi(filep, (ino_t)UFSROOTINO))
1907c478bd9Sstevel@tonic-gate 			return ((ino_t)0);
1917c478bd9Sstevel@tonic-gate 		while (*lpathp == '/')
1927c478bd9Sstevel@tonic-gate 			lpathp++;	/* skip leading slashes */
1937c478bd9Sstevel@tonic-gate 		q = lpathp;
1947c478bd9Sstevel@tonic-gate 		while (*q != '/' && *q != '\0')
1957c478bd9Sstevel@tonic-gate 			q++;		/* find end of component */
1967c478bd9Sstevel@tonic-gate 		c = *q;
1977c478bd9Sstevel@tonic-gate 		*q = '\0';		/* terminate component */
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 		/* Bail out early if opening root */
2007c478bd9Sstevel@tonic-gate 		if (r && (*lpathp == '\0'))
2017c478bd9Sstevel@tonic-gate 			return ((ino_t)UFSROOTINO);
2027c478bd9Sstevel@tonic-gate 		if ((inode = dlook(filep, lpathp)) != 0) {
2037c478bd9Sstevel@tonic-gate 			if (openi(filep, inode))
2047c478bd9Sstevel@tonic-gate 				return ((ino_t)0);
2057c478bd9Sstevel@tonic-gate 			if ((filep->fi_inode->i_smode & IFMT) == IFLNK) {
2067c478bd9Sstevel@tonic-gate 				filep->fi_blocknum =
2077c478bd9Sstevel@tonic-gate 				    fsbtodb(&devp->un_fs.di_fs,
2087c478bd9Sstevel@tonic-gate 				    filep->fi_inode->i_db[0]);
2097c478bd9Sstevel@tonic-gate 				filep->fi_count = DEV_BSIZE;
2107c478bd9Sstevel@tonic-gate 				/* check the block cache */
211986fd29aSsetje 				if ((filep->fi_memp =
212986fd29aSsetje 				    get_bcache(filep)) == NULL) {
2137c478bd9Sstevel@tonic-gate 					if (set_bcache(filep))
2147c478bd9Sstevel@tonic-gate 						return ((ino_t)0);
2157c478bd9Sstevel@tonic-gate 					lufs_merge_deltas(filep);
2167c478bd9Sstevel@tonic-gate 				}
2177c478bd9Sstevel@tonic-gate 				len = strlen(filep->fi_memp);
2187c478bd9Sstevel@tonic-gate 				if (filep->fi_memp[0] == '/')
2197c478bd9Sstevel@tonic-gate 					/* absolute link */
2207c478bd9Sstevel@tonic-gate 					lpathp = lpath;
2217c478bd9Sstevel@tonic-gate 				/* copy rest of unprocessed path up */
2227c478bd9Sstevel@tonic-gate 				bcopy(q, lpathp + len, strlen(q + 1) + 2);
2237c478bd9Sstevel@tonic-gate 				/* point to unprocessed path */
2247c478bd9Sstevel@tonic-gate 				*(lpathp + len) = c;
2257c478bd9Sstevel@tonic-gate 				/* prepend link in before unprocessed path */
2267c478bd9Sstevel@tonic-gate 				bcopy(filep->fi_memp, lpathp, len);
2277c478bd9Sstevel@tonic-gate 				lpathp = lpath;
2287c478bd9Sstevel@tonic-gate 				continue;
2297c478bd9Sstevel@tonic-gate 			} else
2307c478bd9Sstevel@tonic-gate 				*q = c;
2317c478bd9Sstevel@tonic-gate 			if (c == '\0')
2327c478bd9Sstevel@tonic-gate 				break;
2337c478bd9Sstevel@tonic-gate 			lpathp = q;
2347c478bd9Sstevel@tonic-gate 			continue;
2357c478bd9Sstevel@tonic-gate 		} else {
2367c478bd9Sstevel@tonic-gate 			return ((ino_t)0);
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 	return (inode);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
242d6bca47dSsommerfe /*
243d6bca47dSsommerfe  * Map <file, file logical block> into a file system block number.
244d6bca47dSsommerfe  * Reads indirect blocks as needed to find the block.  Returns zero when
245d6bca47dSsommerfe  * block isn't there; returns negative fsbn when block is uninitialized.
246d6bca47dSsommerfe  */
2477c478bd9Sstevel@tonic-gate static daddr32_t
sbmap(fileid_t * filep,daddr32_t bn)2487c478bd9Sstevel@tonic-gate sbmap(fileid_t *filep, daddr32_t bn)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate 	struct inode *inodep;
2517c478bd9Sstevel@tonic-gate 	int i, j, sh;
2527c478bd9Sstevel@tonic-gate 	daddr32_t nb, *bap;
2537c478bd9Sstevel@tonic-gate 	daddr32_t *db;
2547c478bd9Sstevel@tonic-gate 	devid_t	*devp;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	devp = filep->fi_devp;
2577c478bd9Sstevel@tonic-gate 	inodep = filep->fi_inode;
2587c478bd9Sstevel@tonic-gate 	db = inodep->i_db;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/*
2617c478bd9Sstevel@tonic-gate 	 * blocks 0..NDADDR are direct blocks
2627c478bd9Sstevel@tonic-gate 	 */
2637c478bd9Sstevel@tonic-gate 	if (bn < NDADDR) {
2647c478bd9Sstevel@tonic-gate 		nb = db[bn];
2657c478bd9Sstevel@tonic-gate 		return (nb);
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	/*
2697c478bd9Sstevel@tonic-gate 	 * addresses NIADDR have single and double indirect blocks.
2707c478bd9Sstevel@tonic-gate 	 * the first step is to determine how many levels of indirection.
2717c478bd9Sstevel@tonic-gate 	 */
2727c478bd9Sstevel@tonic-gate 	sh = 1;
2737c478bd9Sstevel@tonic-gate 	bn -= NDADDR;
2747c478bd9Sstevel@tonic-gate 	for (j = NIADDR; j > 0; j--) {
2757c478bd9Sstevel@tonic-gate 		sh *= NINDIR(&devp->un_fs.di_fs);
2767c478bd9Sstevel@tonic-gate 		if (bn < sh)
2777c478bd9Sstevel@tonic-gate 			break;
2787c478bd9Sstevel@tonic-gate 		bn -= sh;
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 	if (j == 0) {
2817c478bd9Sstevel@tonic-gate 		return ((daddr32_t)0);
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * fetch the first indirect block address from the inode
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 	nb = inodep->i_ib[NIADDR - j];
2887c478bd9Sstevel@tonic-gate 	if (nb == 0) {
2897c478bd9Sstevel@tonic-gate 		return ((daddr32_t)0);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/*
2937c478bd9Sstevel@tonic-gate 	 * fetch through the indirect blocks
2947c478bd9Sstevel@tonic-gate 	 */
2957c478bd9Sstevel@tonic-gate 	for (; j <= NIADDR; j++) {
2967c478bd9Sstevel@tonic-gate 		if (blknos[j] != nb) {
2977c478bd9Sstevel@tonic-gate 			filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, nb);
2987c478bd9Sstevel@tonic-gate 			filep->fi_count = devp->un_fs.di_fs.fs_bsize;
2997c478bd9Sstevel@tonic-gate 			/* First look through the disk block cache */
3007c478bd9Sstevel@tonic-gate 			if ((filep->fi_memp = get_bcache(filep)) == NULL) {
3017c478bd9Sstevel@tonic-gate 				if (set_bcache(filep)) /* Gotta do I/O */
3027c478bd9Sstevel@tonic-gate 					return (0);
3037c478bd9Sstevel@tonic-gate 				lufs_merge_deltas(filep);
3047c478bd9Sstevel@tonic-gate 			}
3057c478bd9Sstevel@tonic-gate 			b.blk[j] = filep->fi_memp;
3067c478bd9Sstevel@tonic-gate 			blknos[j] = nb;
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 		bap = (daddr32_t *)b.blk[j];
3097c478bd9Sstevel@tonic-gate 		sh /= NINDIR(&devp->un_fs.di_fs);
3107c478bd9Sstevel@tonic-gate 		i = (bn / sh) % NINDIR(&devp->un_fs.di_fs);
3117c478bd9Sstevel@tonic-gate 		nb = bap[i];
3127c478bd9Sstevel@tonic-gate 		if (nb == 0) {
3137c478bd9Sstevel@tonic-gate 			return ((daddr32_t)0);
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 	return (nb);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate static ino_t
dlook(fileid_t * filep,char * path)3207c478bd9Sstevel@tonic-gate dlook(fileid_t *filep, char *path)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	devid_t *devp = filep->fi_devp;
3237c478bd9Sstevel@tonic-gate 	struct direct *dp;
3247c478bd9Sstevel@tonic-gate 	struct inode *ip;
3257c478bd9Sstevel@tonic-gate 	struct dirinfo dirp;
3267c478bd9Sstevel@tonic-gate 	int len;
3277c478bd9Sstevel@tonic-gate 	ino_t in;
3287c478bd9Sstevel@tonic-gate #ifdef DEBUG
3297c478bd9Sstevel@tonic-gate 	static int warned = 0;
3307c478bd9Sstevel@tonic-gate #endif
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	ip = filep->fi_inode;
3337c478bd9Sstevel@tonic-gate 	if (path == NULL || *path == '\0')
3347c478bd9Sstevel@tonic-gate 		return (0);
3357c478bd9Sstevel@tonic-gate 	if ((ip->i_smode & IFMT) != IFDIR)
3367c478bd9Sstevel@tonic-gate 		return (0);
3377c478bd9Sstevel@tonic-gate 	if (ip->i_size == 0)
3387c478bd9Sstevel@tonic-gate 		return (0);
3397c478bd9Sstevel@tonic-gate 	len = strlen(path);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/*
3427c478bd9Sstevel@tonic-gate 	 * First look through the directory entry cache
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	if ((in = get_dcache(devp->di_dcookie, path, ip->i_number)) != 0)
3457c478bd9Sstevel@tonic-gate 		return (in);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/*
3487c478bd9Sstevel@tonic-gate 	 * If the entire directory is cached, return failure
3497c478bd9Sstevel@tonic-gate 	 */
3507c478bd9Sstevel@tonic-gate 	if (ip->i_flag & FI_CACHED)
3517c478bd9Sstevel@tonic-gate 		return (0);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/*
3547c478bd9Sstevel@tonic-gate 	 * Otherwise, read the entire directory into the cache
3557c478bd9Sstevel@tonic-gate 	 */
3567c478bd9Sstevel@tonic-gate 	in = 0;
3577c478bd9Sstevel@tonic-gate 	dirp.loc = 0;
3587c478bd9Sstevel@tonic-gate 	dirp.fi = filep;
3597c478bd9Sstevel@tonic-gate 	if (!(ip->i_flag & FI_NOCACHE))
3607c478bd9Sstevel@tonic-gate 		ip->i_flag |= FI_CACHED;
3617c478bd9Sstevel@tonic-gate 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
3627c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0)
3637c478bd9Sstevel@tonic-gate 			continue;
3647c478bd9Sstevel@tonic-gate 		if (dp->d_namlen == len && strcmp(path, dp->d_name) == 0)
3657c478bd9Sstevel@tonic-gate 			in = dp->d_ino;
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		/*
3687c478bd9Sstevel@tonic-gate 		 * Allow "*" to print all names at that level, w/out match
3697c478bd9Sstevel@tonic-gate 		 */
3707c478bd9Sstevel@tonic-gate 		if (strcmp(path, "*") == 0)
3717c478bd9Sstevel@tonic-gate 			printf("%s\n", dp->d_name);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if (ip->i_flag & FI_NOCACHE)
3747c478bd9Sstevel@tonic-gate 			continue;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		/*
3777c478bd9Sstevel@tonic-gate 		 * Put this entry into the cache.  If the entry has been
3787c478bd9Sstevel@tonic-gate 		 * partially cached, check before inserting.  This should be
3797c478bd9Sstevel@tonic-gate 		 * rare if sized correctly
3807c478bd9Sstevel@tonic-gate 		 */
3817c478bd9Sstevel@tonic-gate 		if ((ip->i_flag & FI_PARTIAL_CACHE) &&
3827c478bd9Sstevel@tonic-gate 		    (get_dcache(devp->di_dcookie, dp->d_name, dp->d_ino) != 0))
3837c478bd9Sstevel@tonic-gate 			continue;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		if (set_rdcache(devp->di_dcookie, dp->d_name, ip->i_number,
3867c478bd9Sstevel@tonic-gate 		    dp->d_ino)) {
3877c478bd9Sstevel@tonic-gate 			ip->i_flag &= ~FI_CACHED;
3887c478bd9Sstevel@tonic-gate 			ip->i_flag |= FI_PARTIAL_CACHE;
3897c478bd9Sstevel@tonic-gate #ifdef DEBUG
3907c478bd9Sstevel@tonic-gate 			if (!warned) {
3917c478bd9Sstevel@tonic-gate 				printf("ufsboot: directory cache too small\n");
3927c478bd9Sstevel@tonic-gate 				warned++;
3937c478bd9Sstevel@tonic-gate 			}
3947c478bd9Sstevel@tonic-gate #endif
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 	return (in);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * get next entry in a directory.
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate struct direct *
readdir(struct dirinfo * dstuff)4047c478bd9Sstevel@tonic-gate readdir(struct dirinfo *dstuff)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	struct direct *dp;
4077c478bd9Sstevel@tonic-gate 	fileid_t *filep;
4087c478bd9Sstevel@tonic-gate 	daddr32_t lbn, d;
4097c478bd9Sstevel@tonic-gate 	int off;
4107c478bd9Sstevel@tonic-gate 	devid_t	*devp;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	filep = dstuff->fi;
4137c478bd9Sstevel@tonic-gate 	devp = filep->fi_devp;
4147c478bd9Sstevel@tonic-gate 	for (;;) {
4157c478bd9Sstevel@tonic-gate 		if (dstuff->loc >= filep->fi_inode->i_size) {
4167c478bd9Sstevel@tonic-gate 			return (NULL);
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 		off = blkoff(&devp->un_fs.di_fs, dstuff->loc);
4197c478bd9Sstevel@tonic-gate 		if (off == 0) {
4207c478bd9Sstevel@tonic-gate 			lbn = lblkno(&devp->un_fs.di_fs, dstuff->loc);
4217c478bd9Sstevel@tonic-gate 			d = sbmap(filep, lbn);
4227c478bd9Sstevel@tonic-gate 
423d6bca47dSsommerfe 			if (d <= 0)
4247c478bd9Sstevel@tonic-gate 				return (NULL);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 			filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, d);
4277c478bd9Sstevel@tonic-gate 			filep->fi_count =
4287c478bd9Sstevel@tonic-gate 			    blksize(&devp->un_fs.di_fs, filep->fi_inode, lbn);
4297c478bd9Sstevel@tonic-gate 			/* check the block cache */
4307c478bd9Sstevel@tonic-gate 			if ((filep->fi_memp = get_bcache(filep)) == NULL) {
4317c478bd9Sstevel@tonic-gate 				if (set_bcache(filep))
4327c478bd9Sstevel@tonic-gate 					return (NULL);
4337c478bd9Sstevel@tonic-gate 				lufs_merge_deltas(filep);
4347c478bd9Sstevel@tonic-gate 			}
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 		dp = (struct direct *)(filep->fi_memp + off);
4377c478bd9Sstevel@tonic-gate 		dstuff->loc += dp->d_reclen;
4387c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0)
4397c478bd9Sstevel@tonic-gate 			continue;
4407c478bd9Sstevel@tonic-gate 		return (dp);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate /*
4457c478bd9Sstevel@tonic-gate  * Get the next block of data from the file.  If possible, dma right into
4467c478bd9Sstevel@tonic-gate  * user's buffer
4477c478bd9Sstevel@tonic-gate  */
4487c478bd9Sstevel@tonic-gate static int
getblock(fileid_t * filep,caddr_t buf,int count,int * rcount)4497c478bd9Sstevel@tonic-gate getblock(fileid_t *filep, caddr_t buf, int count, int *rcount)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	struct fs *fs;
4527c478bd9Sstevel@tonic-gate 	caddr_t p;
453d6bca47dSsommerfe 	int off, size, diff, zeroize;
454d6bca47dSsommerfe 	daddr32_t lbn, fsbn;
4557c478bd9Sstevel@tonic-gate 	devid_t	*devp;
4567c478bd9Sstevel@tonic-gate 	static int	pos;
4577c478bd9Sstevel@tonic-gate 	static char 	ind[] = "|/-\\";	/* that's entertainment? */
4587c478bd9Sstevel@tonic-gate 	static int	blks_read;
4597c478bd9Sstevel@tonic-gate 	devp = filep->fi_devp;
4607c478bd9Sstevel@tonic-gate 	p = filep->fi_memp;
4617c478bd9Sstevel@tonic-gate 	if ((signed)filep->fi_count <= 0) {
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 		/* find the amt left to be read in the file */
4647c478bd9Sstevel@tonic-gate 		diff = filep->fi_inode->i_size - filep->fi_offset;
4657c478bd9Sstevel@tonic-gate 		if (diff <= 0) {
4667c478bd9Sstevel@tonic-gate 			printf("Short read\n");
4677c478bd9Sstevel@tonic-gate 			return (-1);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 		fs = &devp->un_fs.di_fs;
4717c478bd9Sstevel@tonic-gate 		/* which block (or frag) in the file do we read? */
4727c478bd9Sstevel@tonic-gate 		lbn = lblkno(fs, filep->fi_offset);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 		/* which physical block on the device do we read? */
475d6bca47dSsommerfe 		fsbn = sbmap(filep, lbn);
476d6bca47dSsommerfe 
477d6bca47dSsommerfe 		/*
478d6bca47dSsommerfe 		 * zero fsbn -> unallocated hole.
479d6bca47dSsommerfe 		 * negative fsbn -> allocated but uninitialized.
480d6bca47dSsommerfe 		 * since we only read from the fs, treat both the same.
481d6bca47dSsommerfe 		 */
482d6bca47dSsommerfe 		zeroize = (fsbn <= 0);
483d6bca47dSsommerfe 
484d6bca47dSsommerfe 		filep->fi_blocknum = fsbtodb(fs, fsbn);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		off = blkoff(fs, filep->fi_offset);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		/* either blksize or fragsize */
4897c478bd9Sstevel@tonic-gate 		size = blksize(fs, filep->fi_inode, lbn);
4907c478bd9Sstevel@tonic-gate 		filep->fi_count = size;
4917c478bd9Sstevel@tonic-gate 		filep->fi_memp = filep->fi_buf;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 		/*
4947c478bd9Sstevel@tonic-gate 		 * optimization if we are reading large blocks of data then
4957c478bd9Sstevel@tonic-gate 		 * we can go directly to user's buffer
4967c478bd9Sstevel@tonic-gate 		 */
4977c478bd9Sstevel@tonic-gate 		*rcount = 0;
4987c478bd9Sstevel@tonic-gate 		if (off == 0 && count >= size) {
4997c478bd9Sstevel@tonic-gate 			filep->fi_memp = buf;
500d6bca47dSsommerfe 			if (zeroize) {
501d6bca47dSsommerfe 				bzero(buf, size);
502d6bca47dSsommerfe 			} else if (diskread(filep)) {
5037c478bd9Sstevel@tonic-gate 				return (-1);
5047c478bd9Sstevel@tonic-gate 			}
5057c478bd9Sstevel@tonic-gate 			*rcount = size;
5067c478bd9Sstevel@tonic-gate 			filep->fi_count = 0;
5077c478bd9Sstevel@tonic-gate 			read_opt++;
5087c478bd9Sstevel@tonic-gate 			if ((blks_read++ & 0x3) == 0)
5097c478bd9Sstevel@tonic-gate 				printf("%c\b", ind[pos++ & 3]);
5107c478bd9Sstevel@tonic-gate 			return (0);
511d6bca47dSsommerfe 		} else {
512d6bca47dSsommerfe 			if (zeroize) {
513d6bca47dSsommerfe 				bzero(filep->fi_memp, size);
514d6bca47dSsommerfe 			} else if (diskread(filep))
5157c478bd9Sstevel@tonic-gate 				return (-1);
516d6bca47dSsommerfe 		}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 		/*
5197c478bd9Sstevel@tonic-gate 		 * round and round she goes (though not on every block..
5207c478bd9Sstevel@tonic-gate 		 * - OBP's take a fair bit of time to actually print stuff)
5217c478bd9Sstevel@tonic-gate 		 * On x86, the screen oriented bootconf program doesn't
5227c478bd9Sstevel@tonic-gate 		 * want this noise...
5237c478bd9Sstevel@tonic-gate 		 */
5247c478bd9Sstevel@tonic-gate 		if ((blks_read++ & 0x3) == 0)
5257c478bd9Sstevel@tonic-gate 			printf("%c\b", ind[pos++ & 3]);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		if (filep->fi_offset - off + size >= filep->fi_inode->i_size)
5287c478bd9Sstevel@tonic-gate 			filep->fi_count = diff + off;
5297c478bd9Sstevel@tonic-gate 		filep->fi_count -= off;
5307c478bd9Sstevel@tonic-gate 		p = &filep->fi_memp[off];
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 	filep->fi_memp = p;
5337c478bd9Sstevel@tonic-gate 	return (0);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate  *  This is the high-level read function.  It works like this.
5397c478bd9Sstevel@tonic-gate  *  We assume that our IO device buffers up some amount of
5407c478bd9Sstevel@tonic-gate  *  data and that we can get a ptr to it.  Thus we need
5417c478bd9Sstevel@tonic-gate  *  to actually call the device func about filesize/blocksize times
5427c478bd9Sstevel@tonic-gate  *  and this greatly increases our IO speed.  When we already
5437c478bd9Sstevel@tonic-gate  *  have data in the buffer, we just return that data (with bcopy() ).
5447c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate static ssize_t
boot_ufs_read(int fd,caddr_t buf,size_t count)5477c478bd9Sstevel@tonic-gate boot_ufs_read(int fd, caddr_t buf, size_t count)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate 	size_t i, j;
5507c478bd9Sstevel@tonic-gate 	caddr_t	n;
5517c478bd9Sstevel@tonic-gate 	int rcount;
5527c478bd9Sstevel@tonic-gate 	fileid_t *filep;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if (!(filep = find_fp(fd))) {
5557c478bd9Sstevel@tonic-gate 		return (-1);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (filep->fi_offset + count > filep->fi_inode->i_size)
5597c478bd9Sstevel@tonic-gate 		count = filep->fi_inode->i_size - filep->fi_offset;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	/* that was easy */
5627c478bd9Sstevel@tonic-gate 	if ((i = count) == 0)
5637c478bd9Sstevel@tonic-gate 		return (0);
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	n = buf;
5667c478bd9Sstevel@tonic-gate 	while (i > 0) {
5677c478bd9Sstevel@tonic-gate 		/* If we need to reload the buffer, do so */
5687c478bd9Sstevel@tonic-gate 		if ((j = filep->fi_count) == 0) {
5697c478bd9Sstevel@tonic-gate 			getblock(filep, buf, i, &rcount);
5707c478bd9Sstevel@tonic-gate 			i -= rcount;
5717c478bd9Sstevel@tonic-gate 			buf += rcount;
5727c478bd9Sstevel@tonic-gate 			filep->fi_offset += rcount;
5737c478bd9Sstevel@tonic-gate 		} else {
5747c478bd9Sstevel@tonic-gate 			/* else just bcopy from our buffer */
5757c478bd9Sstevel@tonic-gate 			j = MIN(i, j);
5767c478bd9Sstevel@tonic-gate 			bcopy(filep->fi_memp, buf, (unsigned)j);
5777c478bd9Sstevel@tonic-gate 			buf += j;
5787c478bd9Sstevel@tonic-gate 			filep->fi_memp += j;
5797c478bd9Sstevel@tonic-gate 			filep->fi_offset += j;
5807c478bd9Sstevel@tonic-gate 			filep->fi_count -= j;
5817c478bd9Sstevel@tonic-gate 			i -= j;
5827c478bd9Sstevel@tonic-gate 		}
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 	return (buf - n);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate  *	This routine will open a device as it is known by the V2 OBP.
5897c478bd9Sstevel@tonic-gate  *	Interface Defn:
5907c478bd9Sstevel@tonic-gate  *	err = boot_ufs_mountroot(string);
5917c478bd9Sstevel@tonic-gate  *		err = 0 on success
5927c478bd9Sstevel@tonic-gate  *		err = -1 on failure
5937c478bd9Sstevel@tonic-gate  *	string:	char string describing the properties of the device.
5947c478bd9Sstevel@tonic-gate  *	We must not dork with any fi[]'s here.  Save that for later.
5957c478bd9Sstevel@tonic-gate  */
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate static int
boot_ufs_mountroot(char * str)5987c478bd9Sstevel@tonic-gate boot_ufs_mountroot(char *str)
5997c478bd9Sstevel@tonic-gate {
6007c478bd9Sstevel@tonic-gate 	int	h;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	/*
6037c478bd9Sstevel@tonic-gate 	 * Open the device and setup the read of the ufs superblock
6047c478bd9Sstevel@tonic-gate 	 * only the first time mountroot is called.  Subsequent calls
6057c478bd9Sstevel@tonic-gate 	 * to mountroot succeed immediatly
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 	if (ufs_devp == NULL) {
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 		/*
6107c478bd9Sstevel@tonic-gate 		 * Encode the knowledge that we normally boot from the 'a'
6117c478bd9Sstevel@tonic-gate 		 * slice of the leaf device on the OBP path; we also permit
6127c478bd9Sstevel@tonic-gate 		 * a 'nolabel' device, i.e. the entire device.  Since v2path
6137c478bd9Sstevel@tonic-gate 		 * points to 'str' as well, changing str should have the
6147c478bd9Sstevel@tonic-gate 		 * desired result.
6157c478bd9Sstevel@tonic-gate 		 */
6167c478bd9Sstevel@tonic-gate 		if (strchr(str, ':') == NULL) {
6177c478bd9Sstevel@tonic-gate 			(void) strcat(str, ":a");
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 		h = prom_open(str);
6207c478bd9Sstevel@tonic-gate 		if (h == 0) {
6217c478bd9Sstevel@tonic-gate 			printf("Cannot open %s\n", str);
6227c478bd9Sstevel@tonic-gate 			return (-1);
6237c478bd9Sstevel@tonic-gate 		}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		ufs_devp = (devid_t *)bkmem_alloc(sizeof (devid_t));
6267c478bd9Sstevel@tonic-gate 		ufs_devp->di_taken = 1;
6277c478bd9Sstevel@tonic-gate 		ufs_devp->di_dcookie = h;
6287c478bd9Sstevel@tonic-gate 		ufs_devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1);
6297c478bd9Sstevel@tonic-gate 		(void) strcpy(ufs_devp->di_desc, str);
6307c478bd9Sstevel@tonic-gate 		bzero(ufs_devp->un_fs.dummy, SBSIZE);
6317c478bd9Sstevel@tonic-gate 		head = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
6327c478bd9Sstevel@tonic-gate 		head->fi_back = head->fi_forw = head;
6337c478bd9Sstevel@tonic-gate 		head->fi_filedes = 0;
6347c478bd9Sstevel@tonic-gate 		head->fi_taken = 0;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		/* Setup read of the superblock */
6377c478bd9Sstevel@tonic-gate 		head->fi_devp = ufs_devp;
6387c478bd9Sstevel@tonic-gate 		head->fi_blocknum = SBLOCK;
6397c478bd9Sstevel@tonic-gate 		head->fi_count = (uint_t)SBSIZE;
6407c478bd9Sstevel@tonic-gate 		head->fi_memp = (caddr_t)&(ufs_devp->un_fs.di_fs);
6417c478bd9Sstevel@tonic-gate 		head->fi_offset = 0;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 		if (diskread(head) ||
6447c478bd9Sstevel@tonic-gate 		    ufs_devp->un_fs.di_fs.fs_magic != FS_MAGIC) {
6457c478bd9Sstevel@tonic-gate 			boot_ufs_closeall(1);
6467c478bd9Sstevel@tonic-gate 			return (-1);
6477c478bd9Sstevel@tonic-gate 		}
6487c478bd9Sstevel@tonic-gate 		lufs_boot_init(head);
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 	return (0);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate  * Unmount the currently mounted root fs.  In practice, this means
6557c478bd9Sstevel@tonic-gate  * closing all open files and releasing resources.  All of this
6567c478bd9Sstevel@tonic-gate  * is done by boot_ufs_closeall().
6577c478bd9Sstevel@tonic-gate  */
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate int
boot_ufs_unmountroot(void)6607c478bd9Sstevel@tonic-gate boot_ufs_unmountroot(void)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	if (ufs_devp == NULL)
6637c478bd9Sstevel@tonic-gate 		return (-1);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	boot_ufs_closeall(1);
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	return (0);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  *	We allocate an fd here for use when talking
6727c478bd9Sstevel@tonic-gate  *	to the file itself.
6737c478bd9Sstevel@tonic-gate  */
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6767c478bd9Sstevel@tonic-gate static int
boot_ufs_open(char * filename,int flags)6777c478bd9Sstevel@tonic-gate boot_ufs_open(char *filename, int flags)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	fileid_t	*filep;
6807c478bd9Sstevel@tonic-gate 	ino_t	inode;
6817c478bd9Sstevel@tonic-gate 	static int	filedes = 1;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/* build and link a new file descriptor */
6847c478bd9Sstevel@tonic-gate 	filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
6857c478bd9Sstevel@tonic-gate 	filep->fi_back = head->fi_back;
6867c478bd9Sstevel@tonic-gate 	filep->fi_forw = head;
6877c478bd9Sstevel@tonic-gate 	head->fi_back->fi_forw = filep;
6887c478bd9Sstevel@tonic-gate 	head->fi_back = filep;
6897c478bd9Sstevel@tonic-gate 	filep->fi_filedes = filedes++;
6907c478bd9Sstevel@tonic-gate 	filep->fi_taken = 1;
6917c478bd9Sstevel@tonic-gate 	filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1);
6927c478bd9Sstevel@tonic-gate 	(void) strcpy(filep->fi_path, filename);
6937c478bd9Sstevel@tonic-gate 	filep->fi_devp = ufs_devp; /* dev is already "mounted" */
6947c478bd9Sstevel@tonic-gate 	filep->fi_inode = NULL;
6957c478bd9Sstevel@tonic-gate 	bzero(filep->fi_buf, MAXBSIZE);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	inode = find(filep, filename);
6987c478bd9Sstevel@tonic-gate 	if (inode == (ino_t)0) {
6997c478bd9Sstevel@tonic-gate 		boot_ufs_close(filep->fi_filedes);
7007c478bd9Sstevel@tonic-gate 		return (-1);
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 	if (openi(filep, inode)) {
7037c478bd9Sstevel@tonic-gate 		boot_ufs_close(filep->fi_filedes);
7047c478bd9Sstevel@tonic-gate 		return (-1);
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	filep->fi_offset = filep->fi_count = 0;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	return (filep->fi_filedes);
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate /*
7137c478bd9Sstevel@tonic-gate  *  We don't do any IO here.
7147c478bd9Sstevel@tonic-gate  *  We just play games with the device pointers.
7157c478bd9Sstevel@tonic-gate  */
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate static off_t
boot_ufs_lseek(int fd,off_t addr,int whence)7187c478bd9Sstevel@tonic-gate boot_ufs_lseek(int fd, off_t addr, int whence)
7197c478bd9Sstevel@tonic-gate {
7207c478bd9Sstevel@tonic-gate 	fileid_t *filep;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/* Make sure user knows what file he is talking to */
7237c478bd9Sstevel@tonic-gate 	if (!(filep = find_fp(fd)))
7247c478bd9Sstevel@tonic-gate 		return (-1);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	switch (whence) {
7277c478bd9Sstevel@tonic-gate 	case SEEK_CUR:
7287c478bd9Sstevel@tonic-gate 		filep->fi_offset += addr;
7297c478bd9Sstevel@tonic-gate 		break;
7307c478bd9Sstevel@tonic-gate 	case SEEK_SET:
7317c478bd9Sstevel@tonic-gate 		filep->fi_offset = addr;
7327c478bd9Sstevel@tonic-gate 		break;
7337c478bd9Sstevel@tonic-gate 	default:
7347c478bd9Sstevel@tonic-gate 	case SEEK_END:
7357c478bd9Sstevel@tonic-gate 		printf("ufs_lseek(): invalid whence value %d\n", whence);
7367c478bd9Sstevel@tonic-gate 		break;
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	filep->fi_blocknum = addr / DEV_BSIZE;
7407c478bd9Sstevel@tonic-gate 	filep->fi_count = 0;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	return (0);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate /*
7467c478bd9Sstevel@tonic-gate  * ufs_fstat() only supports size, mode, and times at present time.
7477c478bd9Sstevel@tonic-gate  */
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate static int
boot_ufs_fstat(int fd,struct bootstat * stp)7507c478bd9Sstevel@tonic-gate boot_ufs_fstat(int fd, struct bootstat *stp)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	fileid_t	*filep;
7537c478bd9Sstevel@tonic-gate 	struct inode	*ip;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	if (!(filep = find_fp(fd)))
7567c478bd9Sstevel@tonic-gate 		return (-1);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	ip = filep->fi_inode;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	stp->st_mode = 0;
7617c478bd9Sstevel@tonic-gate 	stp->st_size = 0;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	if (ip == NULL)
7647c478bd9Sstevel@tonic-gate 		return (0);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	switch (ip->i_smode & IFMT) {
7677c478bd9Sstevel@tonic-gate 	case IFDIR:
7687c478bd9Sstevel@tonic-gate 		stp->st_mode = S_IFDIR;
7697c478bd9Sstevel@tonic-gate 		break;
7707c478bd9Sstevel@tonic-gate 	case IFLNK:
7717c478bd9Sstevel@tonic-gate 		stp->st_mode = S_IFLNK;
7727c478bd9Sstevel@tonic-gate 		break;
7737c478bd9Sstevel@tonic-gate 	case IFREG:
7747c478bd9Sstevel@tonic-gate 		stp->st_mode = S_IFREG;
7757c478bd9Sstevel@tonic-gate 		break;
7767c478bd9Sstevel@tonic-gate 	default:
7777c478bd9Sstevel@tonic-gate 		break;
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 	stp->st_size = ip->i_size;
7807c478bd9Sstevel@tonic-gate 	stp->st_atim.tv_sec = ip->i_atime.tv_sec;
7817c478bd9Sstevel@tonic-gate 	stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000;
7827c478bd9Sstevel@tonic-gate 	stp->st_mtim.tv_sec = ip->i_mtime.tv_sec;
7837c478bd9Sstevel@tonic-gate 	stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000;
7847c478bd9Sstevel@tonic-gate 	stp->st_ctim.tv_sec = ip->i_ctime.tv_sec;
7857c478bd9Sstevel@tonic-gate 	stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	return (0);
7887c478bd9Sstevel@tonic-gate }
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate static int
boot_ufs_close(int fd)7917c478bd9Sstevel@tonic-gate boot_ufs_close(int fd)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate 	fileid_t *filep;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	/* Make sure user knows what file he is talking to */
7967c478bd9Sstevel@tonic-gate 	if (!(filep = find_fp(fd)))
7977c478bd9Sstevel@tonic-gate 		return (-1);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	if (filep->fi_taken && (filep != head)) {
8007c478bd9Sstevel@tonic-gate 		/* Clear the ranks */
8017c478bd9Sstevel@tonic-gate 		bkmem_free(filep->fi_path, strlen(filep->fi_path)+1);
8027c478bd9Sstevel@tonic-gate 		filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0;
8037c478bd9Sstevel@tonic-gate 		filep->fi_memp = (caddr_t)0;
8047c478bd9Sstevel@tonic-gate 		filep->fi_devp = 0;
8057c478bd9Sstevel@tonic-gate 		filep->fi_taken = 0;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 		/* unlink and deallocate node */
8087c478bd9Sstevel@tonic-gate 		filep->fi_forw->fi_back = filep->fi_back;
8097c478bd9Sstevel@tonic-gate 		filep->fi_back->fi_forw = filep->fi_forw;
8107c478bd9Sstevel@tonic-gate 		bkmem_free((char *)filep, sizeof (fileid_t));
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		return (0);
8137c478bd9Sstevel@tonic-gate 	} else {
8147c478bd9Sstevel@tonic-gate 		/* Big problem */
8157c478bd9Sstevel@tonic-gate 		printf("\nFile descrip %d not allocated!", fd);
8167c478bd9Sstevel@tonic-gate 		return (-1);
8177c478bd9Sstevel@tonic-gate 	}
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate 
820986fd29aSsetje /* closeall is now idempotent */
8217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8227c478bd9Sstevel@tonic-gate static void
boot_ufs_closeall(int flag)8237c478bd9Sstevel@tonic-gate boot_ufs_closeall(int flag)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 	fileid_t *filep = head;
8267c478bd9Sstevel@tonic-gate 
827986fd29aSsetje 	if (ufs_devp == NULL) {
828986fd29aSsetje 		if (head)
829986fd29aSsetje 			prom_panic("boot_ufs_closeall: head != NULL.\n");
830986fd29aSsetje 		return;
831986fd29aSsetje 	}
832986fd29aSsetje 
8337c478bd9Sstevel@tonic-gate 	while ((filep = filep->fi_forw) != head)
8347c478bd9Sstevel@tonic-gate 		if (filep->fi_taken)
8357c478bd9Sstevel@tonic-gate 			if (boot_ufs_close(filep->fi_filedes))
8367c478bd9Sstevel@tonic-gate 				prom_panic("Filesystem may be inconsistent.\n");
8377c478bd9Sstevel@tonic-gate 
838986fd29aSsetje 
8397c478bd9Sstevel@tonic-gate 	release_cache(ufs_devp->di_dcookie);
8407c478bd9Sstevel@tonic-gate 	(void) prom_close(ufs_devp->di_dcookie);
8417c478bd9Sstevel@tonic-gate 	ufs_devp->di_taken = 0;
8427c478bd9Sstevel@tonic-gate 	if (verbosemode & print_cache_stats)
8437c478bd9Sstevel@tonic-gate 		print_cache_data();
8447c478bd9Sstevel@tonic-gate 	lufs_closeall();
8457c478bd9Sstevel@tonic-gate 	bkmem_free((char *)ufs_devp, sizeof (devid_t));
8467c478bd9Sstevel@tonic-gate 	bkmem_free((char *)head, sizeof (fileid_t));
8477c478bd9Sstevel@tonic-gate 	ufs_devp = (devid_t *)NULL;
8487c478bd9Sstevel@tonic-gate 	head = (fileid_t *)NULL;
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate static int
boot_ufs_getdents(int fd,struct dirent * dep,unsigned size)8527c478bd9Sstevel@tonic-gate boot_ufs_getdents(int fd, struct dirent *dep, unsigned size)
8537c478bd9Sstevel@tonic-gate {
8547c478bd9Sstevel@tonic-gate 	/*
8557c478bd9Sstevel@tonic-gate 	 * Read directory entries from the file open on "fd" into the
8567c478bd9Sstevel@tonic-gate 	 * "size"-byte buffer at "dep" until the buffer is exhausted
8577c478bd9Sstevel@tonic-gate 	 * or we reach EOF on the directory.  Returns the number of
8587c478bd9Sstevel@tonic-gate 	 * entries read.
8597c478bd9Sstevel@tonic-gate 	 */
8607c478bd9Sstevel@tonic-gate 	int n;
8617c478bd9Sstevel@tonic-gate 	fileid_t *fp;
8627c478bd9Sstevel@tonic-gate 	unsigned long oldoff, oldblok;
8637c478bd9Sstevel@tonic-gate 
864*e0731422SRichard Lowe #define	SLOP (sizeof (struct dirent) - offsetof(struct dirent, d_name[1]))
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	if (fp = find_fp(fd)) {
8677c478bd9Sstevel@tonic-gate 		/*
8687c478bd9Sstevel@tonic-gate 		 *  File is open, check type to make sure it's a directory.
8697c478bd9Sstevel@tonic-gate 		 */
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 		while ((fp->fi_inode->i_smode & IFMT) == IFLNK) {
8727c478bd9Sstevel@tonic-gate 			/*
8737c478bd9Sstevel@tonic-gate 			 * If file is a symbolic link, we'll follow
8747c478bd9Sstevel@tonic-gate 			 * it JIC it points to a directory!
8757c478bd9Sstevel@tonic-gate 			 */
8767c478bd9Sstevel@tonic-gate 			fileid_t fx;
8777c478bd9Sstevel@tonic-gate 			char pn[MAXPATHLEN];
8787c478bd9Sstevel@tonic-gate 			fp->fi_count = DEV_BSIZE;
8797c478bd9Sstevel@tonic-gate 			fp->fi_blocknum = fsbtodb(&fp->fi_devp->un_fs.di_fs,
8807c478bd9Sstevel@tonic-gate 			    fp->fi_inode->i_db[0]);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 			/*
8837c478bd9Sstevel@tonic-gate 			 * Return failure if:
8847c478bd9Sstevel@tonic-gate 			 * (a) we get an I/O error reading the path name.
8857c478bd9Sstevel@tonic-gate 			 * (b) the path name points to a non-existant file,
8867c478bd9Sstevel@tonic-gate 			 * (c) we get an I/O error reading the target inode.
8877c478bd9Sstevel@tonic-gate 			 */
8887c478bd9Sstevel@tonic-gate 			if ((fp->fi_memp = get_bcache(fp)) == NULL) {
8897c478bd9Sstevel@tonic-gate 				if (set_bcache(fp))
8907c478bd9Sstevel@tonic-gate 					return (-1);
8917c478bd9Sstevel@tonic-gate 				lufs_merge_deltas(fp);
8927c478bd9Sstevel@tonic-gate 			}
8937c478bd9Sstevel@tonic-gate 			if (!(n = find(&fx, strcpy(pn, fp->fi_memp))) ||
8947c478bd9Sstevel@tonic-gate 			    openi(fp = &fx, n)) {
8957c478bd9Sstevel@tonic-gate 				return (-1);
8967c478bd9Sstevel@tonic-gate 			}
8977c478bd9Sstevel@tonic-gate 		}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 		if ((fp->fi_inode->i_smode & IFMT) == IFDIR) {
9007c478bd9Sstevel@tonic-gate 			/*
9017c478bd9Sstevel@tonic-gate 			 * If target file is a directory, go ahead
9027c478bd9Sstevel@tonic-gate 			 * and read it.  This consists of making
9037c478bd9Sstevel@tonic-gate 			 * repeated calls to readdir() until we reach
9047c478bd9Sstevel@tonic-gate 			 * end-of-file or run out of buffer space.
9057c478bd9Sstevel@tonic-gate 			 */
9067c478bd9Sstevel@tonic-gate 			int cnt = 0;
9077c478bd9Sstevel@tonic-gate 			struct direct *dp;
9087c478bd9Sstevel@tonic-gate 			struct dirinfo dir;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 			dir.fi = fp;
9117c478bd9Sstevel@tonic-gate 			oldblok = fp->fi_blocknum;
9127c478bd9Sstevel@tonic-gate 			dir.loc = oldoff = fp->fi_offset;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 			for (dp = readdir(&dir); dp; dp = readdir(&dir)) {
9157c478bd9Sstevel@tonic-gate 				/*
9167c478bd9Sstevel@tonic-gate 				 *  Read all directory entries in the file ...
9177c478bd9Sstevel@tonic-gate 				 */
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 				if (dp->d_ino) {
9207c478bd9Sstevel@tonic-gate 					/*
9217c478bd9Sstevel@tonic-gate 					 *  Next entry is valid.
9227c478bd9Sstevel@tonic-gate 					 * Compute name length and
9237c478bd9Sstevel@tonic-gate 					 * break loop if there's not
9247c478bd9Sstevel@tonic-gate 					 * enough space in the output
9257c478bd9Sstevel@tonic-gate 					 * buffer for the next entry.
9267c478bd9Sstevel@tonic-gate 					 *
9277c478bd9Sstevel@tonic-gate 					 *  NOTE: "SLOP" is the number
9287c478bd9Sstevel@tonic-gate 					 * of bytes inserted into the
9297c478bd9Sstevel@tonic-gate 					 * dirent struct's "d_name"
9307c478bd9Sstevel@tonic-gate 					 * field by the compiler to
9317c478bd9Sstevel@tonic-gate 					 * preserve alignment.
9327c478bd9Sstevel@tonic-gate 					 */
9337c478bd9Sstevel@tonic-gate 					dep->d_ino = dp->d_ino;
9347c478bd9Sstevel@tonic-gate 					n = strlen(dp->d_name);
9357c478bd9Sstevel@tonic-gate 					n = roundup((sizeof (struct dirent) +
9367c478bd9Sstevel@tonic-gate 					    ((n > SLOP) ? n : 0)),
9377c478bd9Sstevel@tonic-gate 					    sizeof (off_t));
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 					if (n > size)
9407c478bd9Sstevel@tonic-gate 						break; /* user buffer is full */
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 					oldblok = fp->fi_blocknum;
9437c478bd9Sstevel@tonic-gate 					oldoff = dir.loc;
9447c478bd9Sstevel@tonic-gate 					size -= n;
9457c478bd9Sstevel@tonic-gate 					cnt += 1;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 					(void) strcpy(dep->d_name, dp->d_name);
9487c478bd9Sstevel@tonic-gate 					dep->d_off = dir.loc;
9497c478bd9Sstevel@tonic-gate 					dep->d_reclen = (ushort_t)n;
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 					dep = (struct dirent *)
9527c478bd9Sstevel@tonic-gate 					    ((char *)dep + n);
9537c478bd9Sstevel@tonic-gate 				}
9547c478bd9Sstevel@tonic-gate 			}
9557c478bd9Sstevel@tonic-gate 			/*
9567c478bd9Sstevel@tonic-gate 			 * Remember where we left off for next time
9577c478bd9Sstevel@tonic-gate 			 */
9587c478bd9Sstevel@tonic-gate 			fp->fi_blocknum = oldblok;
9597c478bd9Sstevel@tonic-gate 			fp->fi_offset = oldoff;
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 			return (cnt);
9627c478bd9Sstevel@tonic-gate 		}
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate #undef SLOP
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	return (-1);
9687c478bd9Sstevel@tonic-gate }
969