xref: /onnv-gate/usr/src/stand/lib/fs/ufs/ufsops.c (revision 6747:393cf276a040)
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
52122Ssommerfe  * Common Development and Distribution License (the "License").
62122Ssommerfe  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6747Sga159272  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/vnode.h>
300Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
310Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
320Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/promif.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <sys/bootvfs.h>
380Sstevel@tonic-gate #include <sys/bootdebug.h>
390Sstevel@tonic-gate #include <sys/salib.h>
400Sstevel@tonic-gate #include <sys/sacache.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate 
430Sstevel@tonic-gate int print_cache_stats = 0;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * This fd is used when talking to the device file itself.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate static fileid_t *head;
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * hooks into ufs logging support
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate extern void	lufs_boot_init(fileid_t *);
530Sstevel@tonic-gate extern void	lufs_closeall(void);
540Sstevel@tonic-gate extern void	lufs_merge_deltas(fileid_t *);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /* Only got one of these...ergo, only 1 fs open at once */
570Sstevel@tonic-gate /* static */
580Sstevel@tonic-gate devid_t		*ufs_devp;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate struct dirinfo {
610Sstevel@tonic-gate 	int 	loc;
620Sstevel@tonic-gate 	fileid_t *fi;
630Sstevel@tonic-gate };
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  *  Function prototypes
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate static int	boot_ufs_mountroot(char *str);
690Sstevel@tonic-gate static int	boot_ufs_unmountroot(void);
700Sstevel@tonic-gate static int	boot_ufs_open(char *filename, int flags);
710Sstevel@tonic-gate static int	boot_ufs_close(int fd);
720Sstevel@tonic-gate static ssize_t	boot_ufs_read(int fd, caddr_t buf, size_t size);
730Sstevel@tonic-gate static off_t	boot_ufs_lseek(int, off_t, int);
740Sstevel@tonic-gate static int	boot_ufs_fstat(int fd, struct bootstat *stp);
750Sstevel@tonic-gate static void	boot_ufs_closeall(int flag);
760Sstevel@tonic-gate static int	boot_ufs_getdents(int fd, struct dirent *dep, unsigned size);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate struct boot_fs_ops boot_ufs_ops = {
790Sstevel@tonic-gate 	"ufs",
800Sstevel@tonic-gate 	boot_ufs_mountroot,
810Sstevel@tonic-gate 	boot_ufs_unmountroot,
820Sstevel@tonic-gate 	boot_ufs_open,
830Sstevel@tonic-gate 	boot_ufs_close,
840Sstevel@tonic-gate 	boot_ufs_read,
850Sstevel@tonic-gate 	boot_ufs_lseek,
860Sstevel@tonic-gate 	boot_ufs_fstat,
870Sstevel@tonic-gate 	boot_ufs_closeall,
880Sstevel@tonic-gate 	boot_ufs_getdents
890Sstevel@tonic-gate };
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static 	ino_t	find(fileid_t *filep, char *path);
920Sstevel@tonic-gate static	ino_t	dlook(fileid_t *filep, char *path);
930Sstevel@tonic-gate static 	daddr32_t	sbmap(fileid_t *filep, daddr32_t bn);
940Sstevel@tonic-gate static  struct direct *readdir(struct dirinfo *dstuff);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /* These are the pools of buffers, etc. */
970Sstevel@tonic-gate #define	NBUFS	(NIADDR+1)
980Sstevel@tonic-gate /* Compilers like to play with alignment, so force the issue here */
990Sstevel@tonic-gate static union {
1000Sstevel@tonic-gate 	char		*blk[NBUFS];
1010Sstevel@tonic-gate 	daddr32_t		*dummy;
1020Sstevel@tonic-gate } b;
1030Sstevel@tonic-gate daddr32_t		blknos[NBUFS];
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  *	There is only 1 open (mounted) device at any given time.
1070Sstevel@tonic-gate  *	So we can keep a single, global devp file descriptor to
1080Sstevel@tonic-gate  *	use to index into the di[] array.  This is not true for the
1090Sstevel@tonic-gate  *	fi[] array.  We can have more than one file open at once,
1100Sstevel@tonic-gate  *	so there is no global fd for the fi[].
1110Sstevel@tonic-gate  *	The user program must save the fd passed back from open()
1120Sstevel@tonic-gate  *	and use it to do subsequent read()'s.
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static int
openi(fileid_t * filep,ino_t inode)1160Sstevel@tonic-gate openi(fileid_t *filep, ino_t inode)
1170Sstevel@tonic-gate {
1180Sstevel@tonic-gate 	int retval;
1190Sstevel@tonic-gate 	struct dinode *dp;
1200Sstevel@tonic-gate 	devid_t *devp = filep->fi_devp;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	/* Try the inode cache first */
1230Sstevel@tonic-gate 	if ((filep->fi_inode = get_icache(devp->di_dcookie, inode)) != NULL)
1240Sstevel@tonic-gate 		return (0);
1250Sstevel@tonic-gate 	/* Nope, not there so lets read it off the disk. */
1260Sstevel@tonic-gate 	filep->fi_offset = 0;
1270Sstevel@tonic-gate 	filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs,
1285648Ssetje 	    itod(&devp->un_fs.di_fs, inode));
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/* never more than 1 disk block */
1310Sstevel@tonic-gate 	filep->fi_count = devp->un_fs.di_fs.fs_bsize;
1320Sstevel@tonic-gate 	filep->fi_memp = filep->fi_buf;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	/* Maybe the block is in the disk block cache */
1350Sstevel@tonic-gate 	if ((filep->fi_memp = get_bcache(filep)) == NULL) {
1360Sstevel@tonic-gate 		/* Not in the block cache so read it from disk */
1370Sstevel@tonic-gate 		if (retval = set_bcache(filep))
1380Sstevel@tonic-gate 			return (retval);
1390Sstevel@tonic-gate 		lufs_merge_deltas(filep);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	dp = (struct dinode *)filep->fi_memp;
1430Sstevel@tonic-gate 	filep->fi_inode = (struct inode *)
1440Sstevel@tonic-gate 	    bkmem_alloc(sizeof (struct inode));
1450Sstevel@tonic-gate 	bzero((char *)filep->fi_inode, sizeof (struct inode));
1460Sstevel@tonic-gate 	filep->fi_inode->i_ic =
1470Sstevel@tonic-gate 	    dp[itoo(&devp->un_fs.di_fs, inode)].di_un.di_icom;
1480Sstevel@tonic-gate 	filep->fi_inode->i_number = inode;
1490Sstevel@tonic-gate 	if (set_ricache(devp->di_dcookie, inode, (void *)filep->fi_inode,
1505648Ssetje 	    sizeof (struct inode)))
1510Sstevel@tonic-gate 		filep->fi_inode->i_flag = FI_NOCACHE;
1520Sstevel@tonic-gate 	return (0);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate static fileid_t *
find_fp(int fd)1560Sstevel@tonic-gate find_fp(int fd)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	fileid_t *filep = head;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	if (fd >= 0) {
1610Sstevel@tonic-gate 		while ((filep = filep->fi_forw) != head)
1620Sstevel@tonic-gate 			if (fd == filep->fi_filedes)
1630Sstevel@tonic-gate 				return (filep->fi_taken ? filep : 0);
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	return (0);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static ino_t
find(fileid_t * filep,char * path)1700Sstevel@tonic-gate find(fileid_t *filep, char *path)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	char *q;
1730Sstevel@tonic-gate 	char c;
1740Sstevel@tonic-gate 	ino_t inode;
1750Sstevel@tonic-gate 	char lpath[MAXPATHLEN];
1760Sstevel@tonic-gate 	char *lpathp = lpath;
1770Sstevel@tonic-gate 	int len, r;
1780Sstevel@tonic-gate 	devid_t	*devp;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if (path == NULL || *path == '\0') {
1810Sstevel@tonic-gate 		printf("null path\n");
1820Sstevel@tonic-gate 		return ((ino_t)0);
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	bzero(lpath, sizeof (lpath));
1860Sstevel@tonic-gate 	bcopy(path, lpath, strlen(path));
1870Sstevel@tonic-gate 	devp = filep->fi_devp;
1880Sstevel@tonic-gate 	while (*lpathp) {
1890Sstevel@tonic-gate 		/* if at the beginning of pathname get root inode */
1900Sstevel@tonic-gate 		r = (lpathp == lpath);
1910Sstevel@tonic-gate 		if (r && openi(filep, (ino_t)UFSROOTINO))
1920Sstevel@tonic-gate 			return ((ino_t)0);
1930Sstevel@tonic-gate 		while (*lpathp == '/')
1940Sstevel@tonic-gate 			lpathp++;	/* skip leading slashes */
1950Sstevel@tonic-gate 		q = lpathp;
1960Sstevel@tonic-gate 		while (*q != '/' && *q != '\0')
1970Sstevel@tonic-gate 			q++;		/* find end of component */
1980Sstevel@tonic-gate 		c = *q;
1990Sstevel@tonic-gate 		*q = '\0';		/* terminate component */
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 		/* Bail out early if opening root */
2020Sstevel@tonic-gate 		if (r && (*lpathp == '\0'))
2030Sstevel@tonic-gate 			return ((ino_t)UFSROOTINO);
2040Sstevel@tonic-gate 		if ((inode = dlook(filep, lpathp)) != 0) {
2050Sstevel@tonic-gate 			if (openi(filep, inode))
2060Sstevel@tonic-gate 				return ((ino_t)0);
2070Sstevel@tonic-gate 			if ((filep->fi_inode->i_smode & IFMT) == IFLNK) {
2080Sstevel@tonic-gate 				filep->fi_blocknum =
2090Sstevel@tonic-gate 				    fsbtodb(&devp->un_fs.di_fs,
2100Sstevel@tonic-gate 				    filep->fi_inode->i_db[0]);
2110Sstevel@tonic-gate 				filep->fi_count = DEV_BSIZE;
2120Sstevel@tonic-gate 				/* check the block cache */
2135648Ssetje 				if ((filep->fi_memp =
2145648Ssetje 				    get_bcache(filep)) == NULL) {
2150Sstevel@tonic-gate 					if (set_bcache(filep))
2160Sstevel@tonic-gate 						return ((ino_t)0);
2170Sstevel@tonic-gate 					lufs_merge_deltas(filep);
2180Sstevel@tonic-gate 				}
2190Sstevel@tonic-gate 				len = strlen(filep->fi_memp);
2200Sstevel@tonic-gate 				if (filep->fi_memp[0] == '/')
2210Sstevel@tonic-gate 					/* absolute link */
2220Sstevel@tonic-gate 					lpathp = lpath;
2230Sstevel@tonic-gate 				/* copy rest of unprocessed path up */
2240Sstevel@tonic-gate 				bcopy(q, lpathp + len, strlen(q + 1) + 2);
2250Sstevel@tonic-gate 				/* point to unprocessed path */
2260Sstevel@tonic-gate 				*(lpathp + len) = c;
2270Sstevel@tonic-gate 				/* prepend link in before unprocessed path */
2280Sstevel@tonic-gate 				bcopy(filep->fi_memp, lpathp, len);
2290Sstevel@tonic-gate 				lpathp = lpath;
2300Sstevel@tonic-gate 				continue;
2310Sstevel@tonic-gate 			} else
2320Sstevel@tonic-gate 				*q = c;
2330Sstevel@tonic-gate 			if (c == '\0')
2340Sstevel@tonic-gate 				break;
2350Sstevel@tonic-gate 			lpathp = q;
2360Sstevel@tonic-gate 			continue;
2370Sstevel@tonic-gate 		} else {
2380Sstevel@tonic-gate 			return ((ino_t)0);
2390Sstevel@tonic-gate 		}
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 	return (inode);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2442122Ssommerfe /*
2452122Ssommerfe  * Map <file, file logical block> into a file system block number.
2462122Ssommerfe  * Reads indirect blocks as needed to find the block.  Returns zero when
2472122Ssommerfe  * block isn't there; returns negative fsbn when block is uninitialized.
2482122Ssommerfe  */
2490Sstevel@tonic-gate static daddr32_t
sbmap(fileid_t * filep,daddr32_t bn)2500Sstevel@tonic-gate sbmap(fileid_t *filep, daddr32_t bn)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	struct inode *inodep;
2530Sstevel@tonic-gate 	int i, j, sh;
2540Sstevel@tonic-gate 	daddr32_t nb, *bap;
2550Sstevel@tonic-gate 	daddr32_t *db;
2560Sstevel@tonic-gate 	devid_t	*devp;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	devp = filep->fi_devp;
2590Sstevel@tonic-gate 	inodep = filep->fi_inode;
2600Sstevel@tonic-gate 	db = inodep->i_db;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * blocks 0..NDADDR are direct blocks
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 	if (bn < NDADDR) {
2660Sstevel@tonic-gate 		nb = db[bn];
2670Sstevel@tonic-gate 		return (nb);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	/*
2710Sstevel@tonic-gate 	 * addresses NIADDR have single and double indirect blocks.
2720Sstevel@tonic-gate 	 * the first step is to determine how many levels of indirection.
2730Sstevel@tonic-gate 	 */
2740Sstevel@tonic-gate 	sh = 1;
2750Sstevel@tonic-gate 	bn -= NDADDR;
2760Sstevel@tonic-gate 	for (j = NIADDR; j > 0; j--) {
2770Sstevel@tonic-gate 		sh *= NINDIR(&devp->un_fs.di_fs);
2780Sstevel@tonic-gate 		if (bn < sh)
2790Sstevel@tonic-gate 			break;
2800Sstevel@tonic-gate 		bn -= sh;
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 	if (j == 0) {
2830Sstevel@tonic-gate 		return ((daddr32_t)0);
2840Sstevel@tonic-gate 	}
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	/*
2870Sstevel@tonic-gate 	 * fetch the first indirect block address from the inode
2880Sstevel@tonic-gate 	 */
2890Sstevel@tonic-gate 	nb = inodep->i_ib[NIADDR - j];
2900Sstevel@tonic-gate 	if (nb == 0) {
2910Sstevel@tonic-gate 		return ((daddr32_t)0);
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/*
2950Sstevel@tonic-gate 	 * fetch through the indirect blocks
2960Sstevel@tonic-gate 	 */
2970Sstevel@tonic-gate 	for (; j <= NIADDR; j++) {
2980Sstevel@tonic-gate 		if (blknos[j] != nb) {
2990Sstevel@tonic-gate 			filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, nb);
3000Sstevel@tonic-gate 			filep->fi_count = devp->un_fs.di_fs.fs_bsize;
3010Sstevel@tonic-gate 			/* First look through the disk block cache */
3020Sstevel@tonic-gate 			if ((filep->fi_memp = get_bcache(filep)) == NULL) {
3030Sstevel@tonic-gate 				if (set_bcache(filep)) /* Gotta do I/O */
3040Sstevel@tonic-gate 					return (0);
3050Sstevel@tonic-gate 				lufs_merge_deltas(filep);
3060Sstevel@tonic-gate 			}
3070Sstevel@tonic-gate 			b.blk[j] = filep->fi_memp;
3080Sstevel@tonic-gate 			blknos[j] = nb;
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 		bap = (daddr32_t *)b.blk[j];
3110Sstevel@tonic-gate 		sh /= NINDIR(&devp->un_fs.di_fs);
3120Sstevel@tonic-gate 		i = (bn / sh) % NINDIR(&devp->un_fs.di_fs);
3130Sstevel@tonic-gate 		nb = bap[i];
3140Sstevel@tonic-gate 		if (nb == 0) {
3150Sstevel@tonic-gate 			return ((daddr32_t)0);
3160Sstevel@tonic-gate 		}
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 	return (nb);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate static ino_t
dlook(fileid_t * filep,char * path)3220Sstevel@tonic-gate dlook(fileid_t *filep, char *path)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	devid_t *devp = filep->fi_devp;
3250Sstevel@tonic-gate 	struct direct *dp;
3260Sstevel@tonic-gate 	struct inode *ip;
3270Sstevel@tonic-gate 	struct dirinfo dirp;
3280Sstevel@tonic-gate 	int len;
3290Sstevel@tonic-gate 	ino_t in;
3300Sstevel@tonic-gate #ifdef DEBUG
3310Sstevel@tonic-gate 	static int warned = 0;
3320Sstevel@tonic-gate #endif
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	ip = filep->fi_inode;
3350Sstevel@tonic-gate 	if (path == NULL || *path == '\0')
3360Sstevel@tonic-gate 		return (0);
3370Sstevel@tonic-gate 	if ((ip->i_smode & IFMT) != IFDIR)
3380Sstevel@tonic-gate 		return (0);
3390Sstevel@tonic-gate 	if (ip->i_size == 0)
3400Sstevel@tonic-gate 		return (0);
3410Sstevel@tonic-gate 	len = strlen(path);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/*
3440Sstevel@tonic-gate 	 * First look through the directory entry cache
3450Sstevel@tonic-gate 	 */
3460Sstevel@tonic-gate 	if ((in = get_dcache(devp->di_dcookie, path, ip->i_number)) != 0)
3470Sstevel@tonic-gate 		return (in);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	/*
3500Sstevel@tonic-gate 	 * If the entire directory is cached, return failure
3510Sstevel@tonic-gate 	 */
3520Sstevel@tonic-gate 	if (ip->i_flag & FI_CACHED)
3530Sstevel@tonic-gate 		return (0);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/*
3560Sstevel@tonic-gate 	 * Otherwise, read the entire directory into the cache
3570Sstevel@tonic-gate 	 */
3580Sstevel@tonic-gate 	in = 0;
3590Sstevel@tonic-gate 	dirp.loc = 0;
3600Sstevel@tonic-gate 	dirp.fi = filep;
3610Sstevel@tonic-gate 	if (!(ip->i_flag & FI_NOCACHE))
3620Sstevel@tonic-gate 		ip->i_flag |= FI_CACHED;
3630Sstevel@tonic-gate 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
3640Sstevel@tonic-gate 		if (dp->d_ino == 0)
3650Sstevel@tonic-gate 			continue;
3660Sstevel@tonic-gate 		if (dp->d_namlen == len && strcmp(path, dp->d_name) == 0)
3670Sstevel@tonic-gate 			in = dp->d_ino;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		/*
3700Sstevel@tonic-gate 		 * Allow "*" to print all names at that level, w/out match
3710Sstevel@tonic-gate 		 */
3720Sstevel@tonic-gate 		if (strcmp(path, "*") == 0)
3730Sstevel@tonic-gate 			printf("%s\n", dp->d_name);
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 		if (ip->i_flag & FI_NOCACHE)
3760Sstevel@tonic-gate 			continue;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		/*
3790Sstevel@tonic-gate 		 * Put this entry into the cache.  If the entry has been
3800Sstevel@tonic-gate 		 * partially cached, check before inserting.  This should be
3810Sstevel@tonic-gate 		 * rare if sized correctly
3820Sstevel@tonic-gate 		 */
3830Sstevel@tonic-gate 		if ((ip->i_flag & FI_PARTIAL_CACHE) &&
3840Sstevel@tonic-gate 		    (get_dcache(devp->di_dcookie, dp->d_name, dp->d_ino) != 0))
3850Sstevel@tonic-gate 			continue;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 		if (set_rdcache(devp->di_dcookie, dp->d_name, ip->i_number,
3885648Ssetje 		    dp->d_ino)) {
3890Sstevel@tonic-gate 			ip->i_flag &= ~FI_CACHED;
3900Sstevel@tonic-gate 			ip->i_flag |= FI_PARTIAL_CACHE;
3910Sstevel@tonic-gate #ifdef DEBUG
3920Sstevel@tonic-gate 			if (!warned) {
3930Sstevel@tonic-gate 				printf("ufsboot: directory cache too small\n");
3940Sstevel@tonic-gate 				warned++;
3950Sstevel@tonic-gate 			}
3960Sstevel@tonic-gate #endif
3970Sstevel@tonic-gate 		}
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 	return (in);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate  * get next entry in a directory.
4040Sstevel@tonic-gate  */
4050Sstevel@tonic-gate struct direct *
readdir(struct dirinfo * dstuff)4060Sstevel@tonic-gate readdir(struct dirinfo *dstuff)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	struct direct *dp;
4090Sstevel@tonic-gate 	fileid_t *filep;
4100Sstevel@tonic-gate 	daddr32_t lbn, d;
4110Sstevel@tonic-gate 	int off;
4120Sstevel@tonic-gate 	devid_t	*devp;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	filep = dstuff->fi;
4150Sstevel@tonic-gate 	devp = filep->fi_devp;
4160Sstevel@tonic-gate 	for (;;) {
4170Sstevel@tonic-gate 		if (dstuff->loc >= filep->fi_inode->i_size) {
4180Sstevel@tonic-gate 			return (NULL);
4190Sstevel@tonic-gate 		}
4200Sstevel@tonic-gate 		off = blkoff(&devp->un_fs.di_fs, dstuff->loc);
4210Sstevel@tonic-gate 		if (off == 0) {
4220Sstevel@tonic-gate 			lbn = lblkno(&devp->un_fs.di_fs, dstuff->loc);
4230Sstevel@tonic-gate 			d = sbmap(filep, lbn);
4240Sstevel@tonic-gate 
4252122Ssommerfe 			if (d <= 0)
4260Sstevel@tonic-gate 				return (NULL);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 			filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, d);
4290Sstevel@tonic-gate 			filep->fi_count =
4300Sstevel@tonic-gate 			    blksize(&devp->un_fs.di_fs, filep->fi_inode, lbn);
4310Sstevel@tonic-gate 			/* check the block cache */
4320Sstevel@tonic-gate 			if ((filep->fi_memp = get_bcache(filep)) == NULL) {
4330Sstevel@tonic-gate 				if (set_bcache(filep))
4340Sstevel@tonic-gate 					return (NULL);
4350Sstevel@tonic-gate 				lufs_merge_deltas(filep);
4360Sstevel@tonic-gate 			}
4370Sstevel@tonic-gate 		}
4380Sstevel@tonic-gate 		dp = (struct direct *)(filep->fi_memp + off);
4390Sstevel@tonic-gate 		dstuff->loc += dp->d_reclen;
4400Sstevel@tonic-gate 		if (dp->d_ino == 0)
4410Sstevel@tonic-gate 			continue;
4420Sstevel@tonic-gate 		return (dp);
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate  * Get the next block of data from the file.  If possible, dma right into
4480Sstevel@tonic-gate  * user's buffer
4490Sstevel@tonic-gate  */
4500Sstevel@tonic-gate static int
getblock(fileid_t * filep,caddr_t buf,int count,int * rcount)4510Sstevel@tonic-gate getblock(fileid_t *filep, caddr_t buf, int count, int *rcount)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	struct fs *fs;
4540Sstevel@tonic-gate 	caddr_t p;
4552122Ssommerfe 	int off, size, diff, zeroize;
4562122Ssommerfe 	daddr32_t lbn, fsbn;
4570Sstevel@tonic-gate 	devid_t	*devp;
4580Sstevel@tonic-gate 	static int	pos;
4590Sstevel@tonic-gate 	static char 	ind[] = "|/-\\";	/* that's entertainment? */
4600Sstevel@tonic-gate 	static int	blks_read;
4610Sstevel@tonic-gate 	devp = filep->fi_devp;
4620Sstevel@tonic-gate 	p = filep->fi_memp;
4630Sstevel@tonic-gate 	if ((signed)filep->fi_count <= 0) {
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 		/* find the amt left to be read in the file */
4660Sstevel@tonic-gate 		diff = filep->fi_inode->i_size - filep->fi_offset;
4670Sstevel@tonic-gate 		if (diff <= 0) {
4680Sstevel@tonic-gate 			printf("Short read\n");
4690Sstevel@tonic-gate 			return (-1);
4700Sstevel@tonic-gate 		}
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		fs = &devp->un_fs.di_fs;
4730Sstevel@tonic-gate 		/* which block (or frag) in the file do we read? */
4740Sstevel@tonic-gate 		lbn = lblkno(fs, filep->fi_offset);
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 		/* which physical block on the device do we read? */
4772122Ssommerfe 		fsbn = sbmap(filep, lbn);
4782122Ssommerfe 
4792122Ssommerfe 		/*
4802122Ssommerfe 		 * zero fsbn -> unallocated hole.
4812122Ssommerfe 		 * negative fsbn -> allocated but uninitialized.
4822122Ssommerfe 		 * since we only read from the fs, treat both the same.
4832122Ssommerfe 		 */
4842122Ssommerfe 		zeroize = (fsbn <= 0);
4852122Ssommerfe 
4862122Ssommerfe 		filep->fi_blocknum = fsbtodb(fs, fsbn);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 		off = blkoff(fs, filep->fi_offset);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		/* either blksize or fragsize */
4910Sstevel@tonic-gate 		size = blksize(fs, filep->fi_inode, lbn);
4920Sstevel@tonic-gate 		filep->fi_count = size;
4930Sstevel@tonic-gate 		filep->fi_memp = filep->fi_buf;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		/*
4960Sstevel@tonic-gate 		 * optimization if we are reading large blocks of data then
4970Sstevel@tonic-gate 		 * we can go directly to user's buffer
4980Sstevel@tonic-gate 		 */
4990Sstevel@tonic-gate 		*rcount = 0;
5000Sstevel@tonic-gate 		if (off == 0 && count >= size) {
5010Sstevel@tonic-gate 			filep->fi_memp = buf;
5022122Ssommerfe 			if (zeroize) {
5032122Ssommerfe 				bzero(buf, size);
5042122Ssommerfe 			} else if (diskread(filep)) {
5050Sstevel@tonic-gate 				return (-1);
5060Sstevel@tonic-gate 			}
5070Sstevel@tonic-gate 			*rcount = size;
5080Sstevel@tonic-gate 			filep->fi_count = 0;
5090Sstevel@tonic-gate 			read_opt++;
5100Sstevel@tonic-gate 			if ((blks_read++ & 0x3) == 0)
5110Sstevel@tonic-gate 				printf("%c\b", ind[pos++ & 3]);
5120Sstevel@tonic-gate 			return (0);
5132122Ssommerfe 		} else {
5142122Ssommerfe 			if (zeroize) {
5152122Ssommerfe 				bzero(filep->fi_memp, size);
5162122Ssommerfe 			} else if (diskread(filep))
5170Sstevel@tonic-gate 				return (-1);
5182122Ssommerfe 		}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 		/*
5210Sstevel@tonic-gate 		 * round and round she goes (though not on every block..
5220Sstevel@tonic-gate 		 * - OBP's take a fair bit of time to actually print stuff)
5230Sstevel@tonic-gate 		 * On x86, the screen oriented bootconf program doesn't
5240Sstevel@tonic-gate 		 * want this noise...
5250Sstevel@tonic-gate 		 */
5260Sstevel@tonic-gate 		if ((blks_read++ & 0x3) == 0)
5270Sstevel@tonic-gate 			printf("%c\b", ind[pos++ & 3]);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 		if (filep->fi_offset - off + size >= filep->fi_inode->i_size)
5300Sstevel@tonic-gate 			filep->fi_count = diff + off;
5310Sstevel@tonic-gate 		filep->fi_count -= off;
5320Sstevel@tonic-gate 		p = &filep->fi_memp[off];
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 	filep->fi_memp = p;
5350Sstevel@tonic-gate 	return (0);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate /*
5400Sstevel@tonic-gate  *  This is the high-level read function.  It works like this.
5410Sstevel@tonic-gate  *  We assume that our IO device buffers up some amount of
5420Sstevel@tonic-gate  *  data and that we can get a ptr to it.  Thus we need
5430Sstevel@tonic-gate  *  to actually call the device func about filesize/blocksize times
5440Sstevel@tonic-gate  *  and this greatly increases our IO speed.  When we already
5450Sstevel@tonic-gate  *  have data in the buffer, we just return that data (with bcopy() ).
5460Sstevel@tonic-gate  */
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate static ssize_t
boot_ufs_read(int fd,caddr_t buf,size_t count)5490Sstevel@tonic-gate boot_ufs_read(int fd, caddr_t buf, size_t count)
5500Sstevel@tonic-gate {
5510Sstevel@tonic-gate 	size_t i, j;
5520Sstevel@tonic-gate 	caddr_t	n;
5530Sstevel@tonic-gate 	int rcount;
5540Sstevel@tonic-gate 	fileid_t *filep;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	if (!(filep = find_fp(fd))) {
5570Sstevel@tonic-gate 		return (-1);
5580Sstevel@tonic-gate 	}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	if (filep->fi_offset + count > filep->fi_inode->i_size)
5610Sstevel@tonic-gate 		count = filep->fi_inode->i_size - filep->fi_offset;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	/* that was easy */
5640Sstevel@tonic-gate 	if ((i = count) == 0)
5650Sstevel@tonic-gate 		return (0);
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	n = buf;
5680Sstevel@tonic-gate 	while (i > 0) {
5690Sstevel@tonic-gate 		/* If we need to reload the buffer, do so */
5700Sstevel@tonic-gate 		if ((j = filep->fi_count) == 0) {
5710Sstevel@tonic-gate 			getblock(filep, buf, i, &rcount);
5720Sstevel@tonic-gate 			i -= rcount;
5730Sstevel@tonic-gate 			buf += rcount;
5740Sstevel@tonic-gate 			filep->fi_offset += rcount;
5750Sstevel@tonic-gate 		} else {
5760Sstevel@tonic-gate 			/* else just bcopy from our buffer */
5770Sstevel@tonic-gate 			j = MIN(i, j);
5780Sstevel@tonic-gate 			bcopy(filep->fi_memp, buf, (unsigned)j);
5790Sstevel@tonic-gate 			buf += j;
5800Sstevel@tonic-gate 			filep->fi_memp += j;
5810Sstevel@tonic-gate 			filep->fi_offset += j;
5820Sstevel@tonic-gate 			filep->fi_count -= j;
5830Sstevel@tonic-gate 			i -= j;
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 	return (buf - n);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate /*
5900Sstevel@tonic-gate  *	This routine will open a device as it is known by the V2 OBP.
5910Sstevel@tonic-gate  *	Interface Defn:
5920Sstevel@tonic-gate  *	err = boot_ufs_mountroot(string);
5930Sstevel@tonic-gate  *		err = 0 on success
5940Sstevel@tonic-gate  *		err = -1 on failure
5950Sstevel@tonic-gate  *	string:	char string describing the properties of the device.
5960Sstevel@tonic-gate  *	We must not dork with any fi[]'s here.  Save that for later.
5970Sstevel@tonic-gate  */
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate static int
boot_ufs_mountroot(char * str)6000Sstevel@tonic-gate boot_ufs_mountroot(char *str)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate 	int	h;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	/*
6050Sstevel@tonic-gate 	 * Open the device and setup the read of the ufs superblock
6060Sstevel@tonic-gate 	 * only the first time mountroot is called.  Subsequent calls
6070Sstevel@tonic-gate 	 * to mountroot succeed immediatly
6080Sstevel@tonic-gate 	 */
6090Sstevel@tonic-gate 	if (ufs_devp == NULL) {
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 		/*
6120Sstevel@tonic-gate 		 * Encode the knowledge that we normally boot from the 'a'
6130Sstevel@tonic-gate 		 * slice of the leaf device on the OBP path; we also permit
6140Sstevel@tonic-gate 		 * a 'nolabel' device, i.e. the entire device.  Since v2path
6150Sstevel@tonic-gate 		 * points to 'str' as well, changing str should have the
6160Sstevel@tonic-gate 		 * desired result.
6170Sstevel@tonic-gate 		 */
6180Sstevel@tonic-gate 		if (strchr(str, ':') == NULL) {
6190Sstevel@tonic-gate 			(void) strcat(str, ":a");
6200Sstevel@tonic-gate 		}
6210Sstevel@tonic-gate 		h = prom_open(str);
6220Sstevel@tonic-gate 		if (h == 0) {
6230Sstevel@tonic-gate 			printf("Cannot open %s\n", str);
6240Sstevel@tonic-gate 			return (-1);
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 		ufs_devp = (devid_t *)bkmem_alloc(sizeof (devid_t));
6280Sstevel@tonic-gate 		ufs_devp->di_taken = 1;
6290Sstevel@tonic-gate 		ufs_devp->di_dcookie = h;
6300Sstevel@tonic-gate 		ufs_devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1);
6310Sstevel@tonic-gate 		(void) strcpy(ufs_devp->di_desc, str);
6320Sstevel@tonic-gate 		bzero(ufs_devp->un_fs.dummy, SBSIZE);
6330Sstevel@tonic-gate 		head = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
6340Sstevel@tonic-gate 		head->fi_back = head->fi_forw = head;
6350Sstevel@tonic-gate 		head->fi_filedes = 0;
6360Sstevel@tonic-gate 		head->fi_taken = 0;
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 		/* Setup read of the superblock */
6390Sstevel@tonic-gate 		head->fi_devp = ufs_devp;
6400Sstevel@tonic-gate 		head->fi_blocknum = SBLOCK;
6410Sstevel@tonic-gate 		head->fi_count = (uint_t)SBSIZE;
6420Sstevel@tonic-gate 		head->fi_memp = (caddr_t)&(ufs_devp->un_fs.di_fs);
6430Sstevel@tonic-gate 		head->fi_offset = 0;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		if (diskread(head) ||
6460Sstevel@tonic-gate 		    ufs_devp->un_fs.di_fs.fs_magic != FS_MAGIC) {
6470Sstevel@tonic-gate 			boot_ufs_closeall(1);
6480Sstevel@tonic-gate 			return (-1);
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 		lufs_boot_init(head);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 	return (0);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate /*
6560Sstevel@tonic-gate  * Unmount the currently mounted root fs.  In practice, this means
6570Sstevel@tonic-gate  * closing all open files and releasing resources.  All of this
6580Sstevel@tonic-gate  * is done by boot_ufs_closeall().
6590Sstevel@tonic-gate  */
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate int
boot_ufs_unmountroot(void)6620Sstevel@tonic-gate boot_ufs_unmountroot(void)
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate 	if (ufs_devp == NULL)
6650Sstevel@tonic-gate 		return (-1);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	boot_ufs_closeall(1);
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	return (0);
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate  *	We allocate an fd here for use when talking
6740Sstevel@tonic-gate  *	to the file itself.
6750Sstevel@tonic-gate  */
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate /*ARGSUSED*/
6780Sstevel@tonic-gate static int
boot_ufs_open(char * filename,int flags)6790Sstevel@tonic-gate boot_ufs_open(char *filename, int flags)
6800Sstevel@tonic-gate {
6810Sstevel@tonic-gate 	fileid_t	*filep;
6820Sstevel@tonic-gate 	ino_t	inode;
6830Sstevel@tonic-gate 	static int	filedes = 1;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	/* build and link a new file descriptor */
6860Sstevel@tonic-gate 	filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
6870Sstevel@tonic-gate 	filep->fi_back = head->fi_back;
6880Sstevel@tonic-gate 	filep->fi_forw = head;
6890Sstevel@tonic-gate 	head->fi_back->fi_forw = filep;
6900Sstevel@tonic-gate 	head->fi_back = filep;
6910Sstevel@tonic-gate 	filep->fi_filedes = filedes++;
6920Sstevel@tonic-gate 	filep->fi_taken = 1;
6930Sstevel@tonic-gate 	filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1);
6940Sstevel@tonic-gate 	(void) strcpy(filep->fi_path, filename);
6950Sstevel@tonic-gate 	filep->fi_devp = ufs_devp; /* dev is already "mounted" */
6960Sstevel@tonic-gate 	filep->fi_inode = NULL;
6970Sstevel@tonic-gate 	bzero(filep->fi_buf, MAXBSIZE);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	inode = find(filep, filename);
7000Sstevel@tonic-gate 	if (inode == (ino_t)0) {
7010Sstevel@tonic-gate 		boot_ufs_close(filep->fi_filedes);
7020Sstevel@tonic-gate 		return (-1);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 	if (openi(filep, inode)) {
7050Sstevel@tonic-gate 		boot_ufs_close(filep->fi_filedes);
7060Sstevel@tonic-gate 		return (-1);
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	filep->fi_offset = filep->fi_count = 0;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	return (filep->fi_filedes);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate /*
7150Sstevel@tonic-gate  *  We don't do any IO here.
7160Sstevel@tonic-gate  *  We just play games with the device pointers.
7170Sstevel@tonic-gate  */
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate static off_t
boot_ufs_lseek(int fd,off_t addr,int whence)7200Sstevel@tonic-gate boot_ufs_lseek(int fd, off_t addr, int whence)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate 	fileid_t *filep;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	/* Make sure user knows what file he is talking to */
7250Sstevel@tonic-gate 	if (!(filep = find_fp(fd)))
7260Sstevel@tonic-gate 		return (-1);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	switch (whence) {
7290Sstevel@tonic-gate 	case SEEK_CUR:
7300Sstevel@tonic-gate 		filep->fi_offset += addr;
7310Sstevel@tonic-gate 		break;
7320Sstevel@tonic-gate 	case SEEK_SET:
7330Sstevel@tonic-gate 		filep->fi_offset = addr;
7340Sstevel@tonic-gate 		break;
7350Sstevel@tonic-gate 	default:
7360Sstevel@tonic-gate 	case SEEK_END:
7370Sstevel@tonic-gate 		printf("ufs_lseek(): invalid whence value %d\n", whence);
7380Sstevel@tonic-gate 		break;
7390Sstevel@tonic-gate 	}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	filep->fi_blocknum = addr / DEV_BSIZE;
7420Sstevel@tonic-gate 	filep->fi_count = 0;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	return (0);
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate  * ufs_fstat() only supports size, mode, and times at present time.
7490Sstevel@tonic-gate  */
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate static int
boot_ufs_fstat(int fd,struct bootstat * stp)7520Sstevel@tonic-gate boot_ufs_fstat(int fd, struct bootstat *stp)
7530Sstevel@tonic-gate {
7540Sstevel@tonic-gate 	fileid_t	*filep;
7550Sstevel@tonic-gate 	struct inode	*ip;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	if (!(filep = find_fp(fd)))
7580Sstevel@tonic-gate 		return (-1);
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	ip = filep->fi_inode;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	stp->st_mode = 0;
7630Sstevel@tonic-gate 	stp->st_size = 0;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	if (ip == NULL)
7660Sstevel@tonic-gate 		return (0);
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	switch (ip->i_smode & IFMT) {
7690Sstevel@tonic-gate 	case IFDIR:
7700Sstevel@tonic-gate 		stp->st_mode = S_IFDIR;
7710Sstevel@tonic-gate 		break;
7720Sstevel@tonic-gate 	case IFLNK:
7730Sstevel@tonic-gate 		stp->st_mode = S_IFLNK;
7740Sstevel@tonic-gate 		break;
7750Sstevel@tonic-gate 	case IFREG:
7760Sstevel@tonic-gate 		stp->st_mode = S_IFREG;
7770Sstevel@tonic-gate 		break;
7780Sstevel@tonic-gate 	default:
7790Sstevel@tonic-gate 		break;
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate 	stp->st_size = ip->i_size;
7820Sstevel@tonic-gate 	stp->st_atim.tv_sec = ip->i_atime.tv_sec;
7830Sstevel@tonic-gate 	stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000;
7840Sstevel@tonic-gate 	stp->st_mtim.tv_sec = ip->i_mtime.tv_sec;
7850Sstevel@tonic-gate 	stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000;
7860Sstevel@tonic-gate 	stp->st_ctim.tv_sec = ip->i_ctime.tv_sec;
7870Sstevel@tonic-gate 	stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	return (0);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate static int
boot_ufs_close(int fd)7930Sstevel@tonic-gate boot_ufs_close(int fd)
7940Sstevel@tonic-gate {
7950Sstevel@tonic-gate 	fileid_t *filep;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	/* Make sure user knows what file he is talking to */
7980Sstevel@tonic-gate 	if (!(filep = find_fp(fd)))
7990Sstevel@tonic-gate 		return (-1);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	if (filep->fi_taken && (filep != head)) {
8020Sstevel@tonic-gate 		/* Clear the ranks */
8030Sstevel@tonic-gate 		bkmem_free(filep->fi_path, strlen(filep->fi_path)+1);
8040Sstevel@tonic-gate 		filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0;
8050Sstevel@tonic-gate 		filep->fi_memp = (caddr_t)0;
8060Sstevel@tonic-gate 		filep->fi_devp = 0;
8070Sstevel@tonic-gate 		filep->fi_taken = 0;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 		/* unlink and deallocate node */
8100Sstevel@tonic-gate 		filep->fi_forw->fi_back = filep->fi_back;
8110Sstevel@tonic-gate 		filep->fi_back->fi_forw = filep->fi_forw;
8120Sstevel@tonic-gate 		bkmem_free((char *)filep, sizeof (fileid_t));
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 		return (0);
8150Sstevel@tonic-gate 	} else {
8160Sstevel@tonic-gate 		/* Big problem */
8170Sstevel@tonic-gate 		printf("\nFile descrip %d not allocated!", fd);
8180Sstevel@tonic-gate 		return (-1);
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate 
8225648Ssetje /* closeall is now idempotent */
8230Sstevel@tonic-gate /*ARGSUSED*/
8240Sstevel@tonic-gate static void
boot_ufs_closeall(int flag)8250Sstevel@tonic-gate boot_ufs_closeall(int flag)
8260Sstevel@tonic-gate {
8270Sstevel@tonic-gate 	fileid_t *filep = head;
8280Sstevel@tonic-gate 
8295648Ssetje 	if (ufs_devp == NULL) {
8305648Ssetje 		if (head)
8315648Ssetje 			prom_panic("boot_ufs_closeall: head != NULL.\n");
8325648Ssetje 		return;
8335648Ssetje 	}
8345648Ssetje 
8350Sstevel@tonic-gate 	while ((filep = filep->fi_forw) != head)
8360Sstevel@tonic-gate 		if (filep->fi_taken)
8370Sstevel@tonic-gate 			if (boot_ufs_close(filep->fi_filedes))
8380Sstevel@tonic-gate 				prom_panic("Filesystem may be inconsistent.\n");
8390Sstevel@tonic-gate 
8405648Ssetje 
8410Sstevel@tonic-gate 	release_cache(ufs_devp->di_dcookie);
8420Sstevel@tonic-gate 	(void) prom_close(ufs_devp->di_dcookie);
8430Sstevel@tonic-gate 	ufs_devp->di_taken = 0;
8440Sstevel@tonic-gate 	if (verbosemode & print_cache_stats)
8450Sstevel@tonic-gate 		print_cache_data();
8460Sstevel@tonic-gate 	lufs_closeall();
8470Sstevel@tonic-gate 	bkmem_free((char *)ufs_devp, sizeof (devid_t));
8480Sstevel@tonic-gate 	bkmem_free((char *)head, sizeof (fileid_t));
8490Sstevel@tonic-gate 	ufs_devp = (devid_t *)NULL;
8500Sstevel@tonic-gate 	head = (fileid_t *)NULL;
8510Sstevel@tonic-gate }
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate static int
boot_ufs_getdents(int fd,struct dirent * dep,unsigned size)8540Sstevel@tonic-gate boot_ufs_getdents(int fd, struct dirent *dep, unsigned size)
8550Sstevel@tonic-gate {
8560Sstevel@tonic-gate 	/*
8570Sstevel@tonic-gate 	 * Read directory entries from the file open on "fd" into the
8580Sstevel@tonic-gate 	 * "size"-byte buffer at "dep" until the buffer is exhausted
8590Sstevel@tonic-gate 	 * or we reach EOF on the directory.  Returns the number of
8600Sstevel@tonic-gate 	 * entries read.
8610Sstevel@tonic-gate 	 */
8620Sstevel@tonic-gate 	int n;
8630Sstevel@tonic-gate 	fileid_t *fp;
8640Sstevel@tonic-gate 	unsigned long oldoff, oldblok;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate #define	SLOP (sizeof (struct dirent) - (int)&((struct dirent *)0)->d_name[1])
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	if (fp = find_fp(fd)) {
8690Sstevel@tonic-gate 		/*
8700Sstevel@tonic-gate 		 *  File is open, check type to make sure it's a directory.
8710Sstevel@tonic-gate 		 */
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 		while ((fp->fi_inode->i_smode & IFMT) == IFLNK) {
8740Sstevel@tonic-gate 			/*
8750Sstevel@tonic-gate 			 * If file is a symbolic link, we'll follow
8760Sstevel@tonic-gate 			 * it JIC it points to a directory!
8770Sstevel@tonic-gate 			 */
8780Sstevel@tonic-gate 			fileid_t fx;
8790Sstevel@tonic-gate 			char pn[MAXPATHLEN];
8800Sstevel@tonic-gate 			fp->fi_count = DEV_BSIZE;
8810Sstevel@tonic-gate 			fp->fi_blocknum = fsbtodb(&fp->fi_devp->un_fs.di_fs,
8820Sstevel@tonic-gate 			    fp->fi_inode->i_db[0]);
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 			/*
8850Sstevel@tonic-gate 			 * Return failure if:
8860Sstevel@tonic-gate 			 * (a) we get an I/O error reading the path name.
8870Sstevel@tonic-gate 			 * (b) the path name points to a non-existant file,
8880Sstevel@tonic-gate 			 * (c) we get an I/O error reading the target inode.
8890Sstevel@tonic-gate 			 */
8900Sstevel@tonic-gate 			if ((fp->fi_memp = get_bcache(fp)) == NULL) {
8910Sstevel@tonic-gate 				if (set_bcache(fp))
8920Sstevel@tonic-gate 					return (-1);
8930Sstevel@tonic-gate 				lufs_merge_deltas(fp);
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 			if (!(n = find(&fx, strcpy(pn, fp->fi_memp))) ||
8960Sstevel@tonic-gate 			    openi(fp = &fx, n)) {
8970Sstevel@tonic-gate 				return (-1);
8980Sstevel@tonic-gate 			}
8990Sstevel@tonic-gate 		}
9000Sstevel@tonic-gate 
9015648Ssetje 		if ((fp->fi_inode->i_smode & IFMT) == IFDIR) {
9020Sstevel@tonic-gate 			/*
9030Sstevel@tonic-gate 			 * If target file is a directory, go ahead
9040Sstevel@tonic-gate 			 * and read it.  This consists of making
9050Sstevel@tonic-gate 			 * repeated calls to readdir() until we reach
9060Sstevel@tonic-gate 			 * end-of-file or run out of buffer space.
9070Sstevel@tonic-gate 			 */
9080Sstevel@tonic-gate 			int cnt = 0;
9090Sstevel@tonic-gate 			struct direct *dp;
9100Sstevel@tonic-gate 			struct dirinfo dir;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 			dir.fi = fp;
9130Sstevel@tonic-gate 			oldblok = fp->fi_blocknum;
9140Sstevel@tonic-gate 			dir.loc = oldoff = fp->fi_offset;
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 			for (dp = readdir(&dir); dp; dp = readdir(&dir)) {
9170Sstevel@tonic-gate 				/*
9180Sstevel@tonic-gate 				 *  Read all directory entries in the file ...
9190Sstevel@tonic-gate 				 */
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 				if (dp->d_ino) {
9220Sstevel@tonic-gate 					/*
9230Sstevel@tonic-gate 					 *  Next entry is valid.
9240Sstevel@tonic-gate 					 * Compute name length and
9250Sstevel@tonic-gate 					 * break loop if there's not
9260Sstevel@tonic-gate 					 * enough space in the output
9270Sstevel@tonic-gate 					 * buffer for the next entry.
9280Sstevel@tonic-gate 					 *
9290Sstevel@tonic-gate 					 *  NOTE: "SLOP" is the number
9300Sstevel@tonic-gate 					 * of bytes inserted into the
9310Sstevel@tonic-gate 					 * dirent struct's "d_name"
9320Sstevel@tonic-gate 					 * field by the compiler to
9330Sstevel@tonic-gate 					 * preserve alignment.
9340Sstevel@tonic-gate 					 */
9350Sstevel@tonic-gate 					dep->d_ino = dp->d_ino;
9360Sstevel@tonic-gate 					n = strlen(dp->d_name);
9370Sstevel@tonic-gate 					n = roundup((sizeof (struct dirent) +
9380Sstevel@tonic-gate 					    ((n > SLOP) ? n : 0)),
9390Sstevel@tonic-gate 					    sizeof (off_t));
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 					if (n > size)
9420Sstevel@tonic-gate 						break; /* user buffer is full */
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 					oldblok = fp->fi_blocknum;
9450Sstevel@tonic-gate 					oldoff = dir.loc;
9460Sstevel@tonic-gate 					size -= n;
9470Sstevel@tonic-gate 					cnt += 1;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 					(void) strcpy(dep->d_name, dp->d_name);
9500Sstevel@tonic-gate 					dep->d_off = dir.loc;
9510Sstevel@tonic-gate 					dep->d_reclen = (ushort_t)n;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 					dep = (struct dirent *)
9540Sstevel@tonic-gate 					    ((char *)dep + n);
9550Sstevel@tonic-gate 				}
9560Sstevel@tonic-gate 			}
9570Sstevel@tonic-gate 			/*
9580Sstevel@tonic-gate 			 * Remember where we left off for next time
9590Sstevel@tonic-gate 			 */
9600Sstevel@tonic-gate 			fp->fi_blocknum = oldblok;
9610Sstevel@tonic-gate 			fp->fi_offset = oldoff;
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 			return (cnt);
9640Sstevel@tonic-gate 		}
9650Sstevel@tonic-gate 	}
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate #undef SLOP
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	return (-1);
9700Sstevel@tonic-gate }
971