xref: /onnv-gate/usr/src/cmd/fs.d/ufs/fsdb/fsdb.c (revision 12875:d6271820a7fb)
10Sstevel@tonic-gate /*
2*12875SJohn.Zolnowsky@Sun.COM  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate  */
40Sstevel@tonic-gate 
50Sstevel@tonic-gate /*
60Sstevel@tonic-gate  * Copyright (c) 1988 Regents of the University of California.
70Sstevel@tonic-gate  * All rights reserved.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
100Sstevel@tonic-gate  * Computer Consoles Inc.
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
130Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
140Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
150Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
160Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
170Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
180Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
190Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
200Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
210Sstevel@tonic-gate  * from this software without specific prior written permission.
220Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
230Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
240Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #ifndef lint
280Sstevel@tonic-gate char copyright[] =
290Sstevel@tonic-gate "@(#) Copyright(c) 1988 Regents of the University of California.\n\
300Sstevel@tonic-gate All rights reserved.\n";
310Sstevel@tonic-gate #endif /* not lint */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #ifndef lint
340Sstevel@tonic-gate static char sccsid[] = "@(#)fsdb.c	5.8 (Berkeley) 6/1/90";
350Sstevel@tonic-gate #endif /* not lint */
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  *  fsdb - file system debugger
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  *  usage: fsdb [-o suboptions] special
410Sstevel@tonic-gate  *  options/suboptions:
420Sstevel@tonic-gate  *	-o
430Sstevel@tonic-gate  *		?		display usage
440Sstevel@tonic-gate  *		o		override some error conditions
450Sstevel@tonic-gate  *		p="string"	set prompt to string
460Sstevel@tonic-gate  *		w		open for write
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include <sys/param.h>
500Sstevel@tonic-gate #include <sys/signal.h>
510Sstevel@tonic-gate #include <sys/file.h>
520Sstevel@tonic-gate #include <inttypes.h>
530Sstevel@tonic-gate #include <sys/sysmacros.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #ifdef sun
560Sstevel@tonic-gate #include <unistd.h>
570Sstevel@tonic-gate #include <stdlib.h>
580Sstevel@tonic-gate #include <string.h>
590Sstevel@tonic-gate #include <fcntl.h>
600Sstevel@tonic-gate #include <signal.h>
610Sstevel@tonic-gate #include <sys/types.h>
620Sstevel@tonic-gate #include <sys/vnode.h>
630Sstevel@tonic-gate #include <sys/mntent.h>
640Sstevel@tonic-gate #include <sys/wait.h>
650Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
660Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
670Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
680Sstevel@tonic-gate #include <sys/fs/ufs_acl.h>
690Sstevel@tonic-gate #include <sys/fs/ufs_log.h>
700Sstevel@tonic-gate #else
710Sstevel@tonic-gate #include <sys/dir.h>
720Sstevel@tonic-gate #include <ufs/fs.h>
730Sstevel@tonic-gate #include <ufs/dinode.h>
740Sstevel@tonic-gate #include <paths.h>
750Sstevel@tonic-gate #endif /* sun */
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #include <stdio.h>
780Sstevel@tonic-gate #include <setjmp.h>
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #define	OLD_FSDB_COMPATIBILITY	/* To support the obsoleted "-z" option */
810Sstevel@tonic-gate 
820Sstevel@tonic-gate #ifndef _PATH_BSHELL
830Sstevel@tonic-gate #define	_PATH_BSHELL	"/bin/sh"
840Sstevel@tonic-gate #endif /* _PATH_BSHELL */
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3
870Sstevel@tonic-gate  * file system.
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate #ifndef FS_42POSTBLFMT
900Sstevel@tonic-gate #define	cg_blktot(cgp) (((cgp))->cg_btot)
910Sstevel@tonic-gate #define	cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno])
920Sstevel@tonic-gate #define	cg_inosused(cgp) (((cgp))->cg_iused)
930Sstevel@tonic-gate #define	cg_blksfree(cgp) (((cgp))->cg_free)
940Sstevel@tonic-gate #define	cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC)
950Sstevel@tonic-gate #endif
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate  * Never changing defines.
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate #define	OCTAL		8		/* octal base */
1010Sstevel@tonic-gate #define	DECIMAL		10		/* decimal base */
1020Sstevel@tonic-gate #define	HEX		16		/* hexadecimal base */
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * Adjustable defines.
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate #define	NBUF		10		/* number of cache buffers */
1080Sstevel@tonic-gate #define	PROMPTSIZE	80		/* size of user definable prompt */
1090Sstevel@tonic-gate #define	MAXFILES	40000		/* max number of files ls can handle */
1100Sstevel@tonic-gate #define	FIRST_DEPTH	10		/* default depth for find and ls */
1110Sstevel@tonic-gate #define	SECOND_DEPTH	100		/* second try at depth (maximum) */
1120Sstevel@tonic-gate #define	INPUTBUFFER	1040		/* size of input buffer */
1130Sstevel@tonic-gate #define	BYTESPERLINE	16		/* bytes per line of /dxo output */
1140Sstevel@tonic-gate #define	NREG		36		/* number of save registers */
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate #define	DEVPREFIX	"/dev/"		/* Uninteresting part of "special" */
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate #if defined(OLD_FSDB_COMPATIBILITY)
1190Sstevel@tonic-gate #define	FSDB_OPTIONS	"o:wp:z:"
1200Sstevel@tonic-gate #else
1210Sstevel@tonic-gate #define	FSDB_OPTIONS	"o:wp:"
1220Sstevel@tonic-gate #endif /* OLD_FSDB_COMPATIBILITY */
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * Values dependent on sizes of structs and such.
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate #define	NUMB		3			/* these three are arbitrary, */
1290Sstevel@tonic-gate #define	BLOCK		5			/* but must be different from */
1300Sstevel@tonic-gate #define	FRAGMENT	7			/* the rest (hence odd). */
1310Sstevel@tonic-gate #define	BITSPERCHAR	8			/* couldn't find it anywhere  */
1320Sstevel@tonic-gate #define	CHAR		(sizeof (char))
1330Sstevel@tonic-gate #define	SHORT		(sizeof (short))
1340Sstevel@tonic-gate #define	LONG		(sizeof (long))
1350Sstevel@tonic-gate #define	U_OFFSET_T	(sizeof (u_offset_t))	/* essentially "long long" */
1360Sstevel@tonic-gate #define	INODE		(sizeof (struct dinode))
1370Sstevel@tonic-gate #define	DIRECTORY	(sizeof (struct direct))
1380Sstevel@tonic-gate #define	CGRP		(sizeof (struct cg))
1390Sstevel@tonic-gate #define	SB		(sizeof (struct fs))
1400Sstevel@tonic-gate #define	BLKSIZE		(fs->fs_bsize)		/* for clarity */
1410Sstevel@tonic-gate #define	FRGSIZE		(fs->fs_fsize)
1420Sstevel@tonic-gate #define	BLKSHIFT	(fs->fs_bshift)
1430Sstevel@tonic-gate #define	FRGSHIFT	(fs->fs_fshift)
1440Sstevel@tonic-gate #define	SHADOW_DATA	(sizeof (struct ufs_fsd))
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * Messy macros that would otherwise clutter up such glamorous code.
1480Sstevel@tonic-gate  */
1490Sstevel@tonic-gate #define	itob(i)		(((u_offset_t)itod(fs, (i)) << \
1500Sstevel@tonic-gate 	(u_offset_t)FRGSHIFT) + (u_offset_t)itoo(fs, (i)) * (u_offset_t)INODE)
1510Sstevel@tonic-gate #define	min(x, y)	((x) < (y) ? (x) : (y))
1520Sstevel@tonic-gate #define	STRINGSIZE(d)	((long)d->d_reclen - \
1530Sstevel@tonic-gate 				((long)&d->d_name[0] - (long)&d->d_ino))
1540Sstevel@tonic-gate #define	letter(c)	((((c) >= 'a')&&((c) <= 'z')) ||\
1550Sstevel@tonic-gate 				(((c) >= 'A')&&((c) <= 'Z')))
1560Sstevel@tonic-gate #define	digit(c)	(((c) >= '0') && ((c) <= '9'))
1570Sstevel@tonic-gate #define	HEXLETTER(c)	(((c) >= 'A') && ((c) <= 'F'))
1580Sstevel@tonic-gate #define	hexletter(c)	(((c) >= 'a') && ((c) <= 'f'))
1590Sstevel@tonic-gate #define	octaldigit(c)	(((c) >= '0') && ((c) <= '7'))
1600Sstevel@tonic-gate #define	uppertolower(c)	((c) - 'A' + 'a')
1610Sstevel@tonic-gate #define	hextodigit(c)	((c) - 'a' + 10)
1620Sstevel@tonic-gate #define	numtodigit(c)	((c) - '0')
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate #if !defined(loword)
1650Sstevel@tonic-gate #define	loword(X)	(((ushort_t *)&X)[1])
1660Sstevel@tonic-gate #endif /* loword */
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate #if !defined(lobyte)
1690Sstevel@tonic-gate #define	lobyte(X)	(((unsigned char *)&X)[1])
1700Sstevel@tonic-gate #endif /* lobyte */
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate  * buffer cache structure.
1740Sstevel@tonic-gate  */
1750Sstevel@tonic-gate static struct lbuf {
1760Sstevel@tonic-gate 	struct	lbuf  *fwd;
1770Sstevel@tonic-gate 	struct	lbuf  *back;
1780Sstevel@tonic-gate 	char	*blkaddr;
1790Sstevel@tonic-gate 	short	valid;
1800Sstevel@tonic-gate 	u_offset_t	blkno;
1810Sstevel@tonic-gate } lbuf[NBUF], bhdr;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate  * used to hold save registers (see '<' and '>').
1850Sstevel@tonic-gate  */
1860Sstevel@tonic-gate struct	save_registers {
1870Sstevel@tonic-gate 	u_offset_t	sv_addr;
1880Sstevel@tonic-gate 	u_offset_t	sv_value;
1890Sstevel@tonic-gate 	long		sv_objsz;
1900Sstevel@tonic-gate } regs[NREG];
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate  * cd, find, and ls use this to hold filenames.  Each filename is broken
1940Sstevel@tonic-gate  * up by a slash.  In other words, /usr/src/adm would have a len field
1950Sstevel@tonic-gate  * of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
1960Sstevel@tonic-gate  * src, and adm components of the pathname.
1970Sstevel@tonic-gate  */
1980Sstevel@tonic-gate static struct filenames {
1990Sstevel@tonic-gate 	ino_t	ino;		/* inode */
2000Sstevel@tonic-gate 	long	len;		/* number of components */
2010Sstevel@tonic-gate 	char	flag;		/* flag if using SECOND_DEPTH allocator */
2020Sstevel@tonic-gate 	char	find;		/* flag if found by find */
2030Sstevel@tonic-gate 	char	**fname;	/* hold components of pathname */
2040Sstevel@tonic-gate } *filenames, *top;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate enum log_enum { LOG_NDELTAS, LOG_ALLDELTAS, LOG_CHECKSCAN };
2070Sstevel@tonic-gate #ifdef sun
2080Sstevel@tonic-gate struct fs	*fs;
2090Sstevel@tonic-gate static union {
2100Sstevel@tonic-gate 	struct fs	un_filesystem;
2110Sstevel@tonic-gate 	char		un_sbsize[SBSIZE];
2120Sstevel@tonic-gate } fs_un;
2130Sstevel@tonic-gate #define	filesystem	fs_un.un_filesystem
2140Sstevel@tonic-gate #else
2150Sstevel@tonic-gate struct fs filesystem, *fs;	/* super block */
2160Sstevel@tonic-gate #endif /* sun */
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate  * Global data.
2200Sstevel@tonic-gate  */
2210Sstevel@tonic-gate static char		*input_path[MAXPATHLEN];
2220Sstevel@tonic-gate static char		*stack_path[MAXPATHLEN];
2230Sstevel@tonic-gate static char		*current_path[MAXPATHLEN];
2240Sstevel@tonic-gate static char		input_buffer[INPUTBUFFER];
2250Sstevel@tonic-gate static char		*prompt;
2260Sstevel@tonic-gate static char		*buffers;
2270Sstevel@tonic-gate static char		scratch[64];
2280Sstevel@tonic-gate static char		BASE[] = "o u     x";
2290Sstevel@tonic-gate static char		PROMPT[PROMPTSIZE];
2300Sstevel@tonic-gate static char		laststyle = '/';
2310Sstevel@tonic-gate static char		lastpo = 'x';
2320Sstevel@tonic-gate static short		input_pointer;
2330Sstevel@tonic-gate static short		current_pathp;
2340Sstevel@tonic-gate static short		stack_pathp;
2350Sstevel@tonic-gate static short		input_pathp;
2360Sstevel@tonic-gate static short		cmp_level;
2370Sstevel@tonic-gate static int		nfiles;
2380Sstevel@tonic-gate static short		type = NUMB;
2390Sstevel@tonic-gate static short		dirslot;
2400Sstevel@tonic-gate static short		fd;
2410Sstevel@tonic-gate static short		c_count;
2420Sstevel@tonic-gate static short		error;
2430Sstevel@tonic-gate static short		paren;
2440Sstevel@tonic-gate static short		trapped;
2450Sstevel@tonic-gate static short		doing_cd;
2460Sstevel@tonic-gate static short		doing_find;
2470Sstevel@tonic-gate static short		find_by_name;
2480Sstevel@tonic-gate static short		find_by_inode;
2490Sstevel@tonic-gate static short		long_list;
2500Sstevel@tonic-gate static short		recursive;
2510Sstevel@tonic-gate static short		objsz = SHORT;
2520Sstevel@tonic-gate static short		override = 0;
2530Sstevel@tonic-gate static short		wrtflag = O_RDONLY;
2540Sstevel@tonic-gate static short		base = HEX;
2550Sstevel@tonic-gate static short		acting_on_inode;
2560Sstevel@tonic-gate static short		acting_on_directory;
2570Sstevel@tonic-gate static short		should_print = 1;
2580Sstevel@tonic-gate static short		clear;
2590Sstevel@tonic-gate static short		star;
2600Sstevel@tonic-gate static u_offset_t	addr;
2610Sstevel@tonic-gate static u_offset_t	bod_addr;
2620Sstevel@tonic-gate static u_offset_t	value;
2630Sstevel@tonic-gate static u_offset_t	erraddr;
2640Sstevel@tonic-gate static long		errcur_bytes;
2650Sstevel@tonic-gate static u_offset_t	errino;
2660Sstevel@tonic-gate static long		errinum;
2670Sstevel@tonic-gate static long		cur_cgrp;
2680Sstevel@tonic-gate static u_offset_t	cur_ino;
2690Sstevel@tonic-gate static long		cur_inum;
2700Sstevel@tonic-gate static u_offset_t	cur_dir;
2710Sstevel@tonic-gate static long		cur_block;
2720Sstevel@tonic-gate static long		cur_bytes;
2730Sstevel@tonic-gate static long		find_ino;
2740Sstevel@tonic-gate static u_offset_t	filesize;
2750Sstevel@tonic-gate static u_offset_t	blocksize;
2760Sstevel@tonic-gate static long		stringsize;
2770Sstevel@tonic-gate static long		count = 1;
2780Sstevel@tonic-gate static long		commands;
2790Sstevel@tonic-gate static long		read_requests;
2800Sstevel@tonic-gate static long		actual_disk_reads;
2810Sstevel@tonic-gate static jmp_buf		env;
2820Sstevel@tonic-gate static long		maxfiles;
2830Sstevel@tonic-gate static long		cur_shad;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate #ifndef sun
2860Sstevel@tonic-gate extern char	*malloc(), *calloc();
2870Sstevel@tonic-gate #endif
2880Sstevel@tonic-gate static char		getachar();
2890Sstevel@tonic-gate static char		*getblk(), *fmtentry();
2900Sstevel@tonic-gate 
2911051Smaheshvs static offset_t		get(short);
2920Sstevel@tonic-gate static long		bmap();
2930Sstevel@tonic-gate static long		expr();
2940Sstevel@tonic-gate static long		term();
2950Sstevel@tonic-gate static long		getnumb();
2960Sstevel@tonic-gate static u_offset_t	getdirslot();
2971051Smaheshvs static unsigned long	*print_check(unsigned long *, long *, short, int);
2981051Smaheshvs 
2991051Smaheshvs static void		usage(char *);
3001051Smaheshvs static void		ungetachar(char);
3010Sstevel@tonic-gate static void		getnextinput();
3020Sstevel@tonic-gate static void		eat_spaces();
3031051Smaheshvs static void		restore_inode(ino_t);
3040Sstevel@tonic-gate static void		find();
3051051Smaheshvs static void		ls(struct filenames *, struct filenames *, short);
3061051Smaheshvs static void		formatf(struct filenames *, struct filenames *);
3070Sstevel@tonic-gate static void		parse();
3081051Smaheshvs static void		follow_path(long, long);
3090Sstevel@tonic-gate static void		getname();
3101051Smaheshvs static void		freemem(struct filenames *, int);
3111051Smaheshvs static void		print_path(char **, int);
3120Sstevel@tonic-gate static void		fill();
3131051Smaheshvs static void		put(u_offset_t, short);
3141051Smaheshvs static void		insert(struct lbuf *);
3150Sstevel@tonic-gate static void		puta();
3161051Smaheshvs static void		fprnt(char, char);
3170Sstevel@tonic-gate static void		index();
3180Sstevel@tonic-gate #ifdef _LARGEFILE64_SOURCE
3190Sstevel@tonic-gate static void		printll
3200Sstevel@tonic-gate 	(u_offset_t value, int fieldsz, int digits, int lead);
3210Sstevel@tonic-gate #define	print(value, fieldsz, digits, lead) \
3220Sstevel@tonic-gate 	printll((u_offset_t)value, fieldsz, digits, lead)
3230Sstevel@tonic-gate #else /* !_LARGEFILE64_SOURCE */
3240Sstevel@tonic-gate static void		print(long value, int fieldsz, int digits, int lead);
3250Sstevel@tonic-gate #endif /* _LARGEFILE64_SOURCE */
3261051Smaheshvs static void		printsb(struct fs *);
3271051Smaheshvs static void		printcg(struct cg *);
3281051Smaheshvs static void		pbits(unsigned char *, int);
3291051Smaheshvs static void		old_fsdb(int, char *);	/* For old fsdb functionality */
3301051Smaheshvs 
3311051Smaheshvs static int		isnumber(char *);
3321051Smaheshvs static int		icheck(u_offset_t);
3331051Smaheshvs static int		cgrp_check(long);
3340Sstevel@tonic-gate static int		valid_addr();
3351051Smaheshvs static int		match(char *, int);
3361051Smaheshvs static int		devcheck(short);
3370Sstevel@tonic-gate static int		bcomp();
3381051Smaheshvs static int		compare(char *, char *, short);
3391051Smaheshvs static int		check_addr(short, short *, short *, short);
3400Sstevel@tonic-gate static int		fcmp();
3410Sstevel@tonic-gate static int		ffcmp();
3420Sstevel@tonic-gate 
3431051Smaheshvs static int		getshadowslot(long);
3441051Smaheshvs static void		getshadowdata(long *, int);
3451051Smaheshvs static void		syncshadowscan(int);
3461051Smaheshvs static void		log_display_header(void);
3471051Smaheshvs static void		log_show(enum log_enum);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate #ifdef sun
3500Sstevel@tonic-gate static void		err();
3510Sstevel@tonic-gate #else
3520Sstevel@tonic-gate static int		err();
3530Sstevel@tonic-gate #endif /* sun */
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /* Suboption vector */
3560Sstevel@tonic-gate static char *subopt_v[] = {
3570Sstevel@tonic-gate #define	OVERRIDE	0
3580Sstevel@tonic-gate 	"o",
3590Sstevel@tonic-gate #define	NEW_PROMPT	1
3600Sstevel@tonic-gate 	"p",
3610Sstevel@tonic-gate #define	WRITE_ENABLED	2
3620Sstevel@tonic-gate 	"w",
3630Sstevel@tonic-gate #define	ALT_PROMPT	3
3640Sstevel@tonic-gate 	"prompt",
3650Sstevel@tonic-gate 	NULL
3660Sstevel@tonic-gate };
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate /*
3690Sstevel@tonic-gate  * main - lines are read up to the unprotected ('\') newline and
3700Sstevel@tonic-gate  *	held in an input buffer.  Characters may be read from the
3710Sstevel@tonic-gate  *	input buffer using getachar() and unread using ungetachar().
3720Sstevel@tonic-gate  *	Reading the whole line ahead allows the use of debuggers
3730Sstevel@tonic-gate  *	which would otherwise be impossible since the debugger
3740Sstevel@tonic-gate  *	and fsdb could not share stdin.
3750Sstevel@tonic-gate  */
3760Sstevel@tonic-gate 
3771051Smaheshvs int
main(int argc,char * argv[])3781051Smaheshvs main(int argc, char *argv[])
3790Sstevel@tonic-gate {
3800Sstevel@tonic-gate 
3811051Smaheshvs 	char		c, *cptr;
3821051Smaheshvs 	short		i;
3831051Smaheshvs 	struct direct	*dirp;
3841051Smaheshvs 	struct lbuf	*bp;
3851051Smaheshvs 	char		*progname;
3861051Smaheshvs 	short		colon, mode;
3871051Smaheshvs 	long		temp;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/* Options/Suboptions processing */
3900Sstevel@tonic-gate 	int	opt;
3910Sstevel@tonic-gate 	char	*subopts;
3920Sstevel@tonic-gate 	char	*optval;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	/*
3950Sstevel@tonic-gate 	 * The following are used to support the old fsdb functionality
3960Sstevel@tonic-gate 	 * of clearing an inode. It's better to use 'clri'.
3970Sstevel@tonic-gate 	 */
3980Sstevel@tonic-gate 	int			inum;	/* Inode number to clear */
3990Sstevel@tonic-gate 	char			*special;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	setbuf(stdin, NULL);
4020Sstevel@tonic-gate 	progname = argv[0];
4030Sstevel@tonic-gate 	prompt = &PROMPT[0];
4040Sstevel@tonic-gate 	/*
4050Sstevel@tonic-gate 	 * Parse options.
4060Sstevel@tonic-gate 	 */
4070Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, FSDB_OPTIONS)) != EOF) {
4080Sstevel@tonic-gate 		switch (opt) {
4090Sstevel@tonic-gate #if defined(OLD_FSDB_COMPATIBILITY)
4100Sstevel@tonic-gate 		case 'z':	/* Hack - Better to use clri */
4110Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n%s\n%s\n%s\n",
4120Sstevel@tonic-gate "Warning: The '-z' option of 'fsdb_ufs' has been declared obsolete",
4130Sstevel@tonic-gate "and may not be supported in a future version of Solaris.",
4140Sstevel@tonic-gate "While this functionality is currently still supported, the",
4150Sstevel@tonic-gate "recommended procedure to clear an inode is to use clri(1M).");
4160Sstevel@tonic-gate 			if (isnumber(optarg)) {
4170Sstevel@tonic-gate 				inum = atoi(optarg);
4180Sstevel@tonic-gate 				special = argv[optind];
4190Sstevel@tonic-gate 				/* Doesn't return */
4200Sstevel@tonic-gate 				old_fsdb(inum, special);
4210Sstevel@tonic-gate 			} else {
4220Sstevel@tonic-gate 				usage(progname);
4230Sstevel@tonic-gate 				exit(31+1);
4240Sstevel@tonic-gate 			}
4250Sstevel@tonic-gate 			/* Should exit() before here */
4260Sstevel@tonic-gate 			/*NOTREACHED*/
4270Sstevel@tonic-gate #endif /* OLD_FSDB_COMPATIBILITY */
4280Sstevel@tonic-gate 		case 'o':
4290Sstevel@tonic-gate 			/* UFS Specific Options */
4300Sstevel@tonic-gate 			subopts = optarg;
4310Sstevel@tonic-gate 			while (*subopts != '\0') {
4320Sstevel@tonic-gate 				switch (getsubopt(&subopts, subopt_v,
4330Sstevel@tonic-gate 								&optval)) {
4340Sstevel@tonic-gate 				case OVERRIDE:
4350Sstevel@tonic-gate 					printf("error checking off\n");
4360Sstevel@tonic-gate 					override = 1;
4370Sstevel@tonic-gate 					break;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 				/*
4400Sstevel@tonic-gate 				 * Change the "-o prompt=foo" option to
4410Sstevel@tonic-gate 				 * "-o p=foo" to match documentation.
4420Sstevel@tonic-gate 				 * ALT_PROMPT continues support for the
4430Sstevel@tonic-gate 				 * undocumented "-o prompt=foo" option so
4440Sstevel@tonic-gate 				 * that we don't break anyone.
4450Sstevel@tonic-gate 				 */
4460Sstevel@tonic-gate 				case NEW_PROMPT:
4470Sstevel@tonic-gate 				case ALT_PROMPT:
4480Sstevel@tonic-gate 					if (optval == NULL) {
4490Sstevel@tonic-gate 						(void) fprintf(stderr,
4500Sstevel@tonic-gate 							"No prompt string\n");
4510Sstevel@tonic-gate 						usage(progname);
4520Sstevel@tonic-gate 					}
4530Sstevel@tonic-gate 					(void) strncpy(PROMPT, optval,
4540Sstevel@tonic-gate 								PROMPTSIZE);
4550Sstevel@tonic-gate 					break;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 				case WRITE_ENABLED:
4580Sstevel@tonic-gate 					/* suitable for open */
4590Sstevel@tonic-gate 					wrtflag = O_RDWR;
4600Sstevel@tonic-gate 					break;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 				default:
4630Sstevel@tonic-gate 					usage(progname);
4640Sstevel@tonic-gate 					/* Should exit here */
4650Sstevel@tonic-gate 				}
4660Sstevel@tonic-gate 			}
4670Sstevel@tonic-gate 			break;
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 		default:
4700Sstevel@tonic-gate 			usage(progname);
4710Sstevel@tonic-gate 		}
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	if ((argc - optind) != 1) {	/* Should just have "special" left */
4750Sstevel@tonic-gate 		usage(progname);
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 	special = argv[optind];
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	/*
4800Sstevel@tonic-gate 	 * Unless it's already been set, the default prompt includes the
4810Sstevel@tonic-gate 	 * name of the special device.
4820Sstevel@tonic-gate 	 */
4830Sstevel@tonic-gate 	if (*prompt == NULL)
4840Sstevel@tonic-gate 		(void) sprintf(prompt, "%s > ", special);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	/*
4870Sstevel@tonic-gate 	 * Attempt to open the special file.
4880Sstevel@tonic-gate 	 */
4890Sstevel@tonic-gate 	if ((fd = open(special, wrtflag)) < 0) {
4900Sstevel@tonic-gate 		perror(special);
4910Sstevel@tonic-gate 		exit(1);
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 	/*
4940Sstevel@tonic-gate 	 * Read in the super block and validate (not too picky).
4950Sstevel@tonic-gate 	 */
4960Sstevel@tonic-gate 	if (llseek(fd, (offset_t)(SBLOCK * DEV_BSIZE), 0) == -1) {
4970Sstevel@tonic-gate 		perror(special);
4980Sstevel@tonic-gate 		exit(1);
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate #ifdef sun
5020Sstevel@tonic-gate 	if (read(fd, &filesystem, SBSIZE) != SBSIZE) {
5030Sstevel@tonic-gate 		printf("%s: cannot read superblock\n", special);
5040Sstevel@tonic-gate 		exit(1);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate #else
5070Sstevel@tonic-gate 	if (read(fd, &filesystem, sizeof (filesystem)) != sizeof (filesystem)) {
5080Sstevel@tonic-gate 		printf("%s: cannot read superblock\n", special);
5090Sstevel@tonic-gate 		exit(1);
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate #endif /* sun */
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	fs = &filesystem;
5140Sstevel@tonic-gate 	if ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC)) {
5150Sstevel@tonic-gate 		if (!override) {
5160Sstevel@tonic-gate 			printf("%s: Bad magic number in file system\n",
5170Sstevel@tonic-gate 								special);
5180Sstevel@tonic-gate 			exit(1);
5190Sstevel@tonic-gate 		}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 		printf("WARNING: Bad magic number in file system. ");
5220Sstevel@tonic-gate 		printf("Continue? (y/n): ");
5230Sstevel@tonic-gate 		(void) fflush(stdout);
5240Sstevel@tonic-gate 		if (gets(input_buffer) == NULL) {
5250Sstevel@tonic-gate 			exit(1);
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		if (*input_buffer != 'y' && *input_buffer != 'Y') {
5290Sstevel@tonic-gate 			exit(1);
5300Sstevel@tonic-gate 		}
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
533757Svsakar 	if ((fs->fs_magic == FS_MAGIC &&
534757Svsakar 	    (fs->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
535757Svsakar 	    fs->fs_version != UFS_VERSION_MIN)) ||
536757Svsakar 	    (fs->fs_magic == MTB_UFS_MAGIC &&
5370Sstevel@tonic-gate 	    (fs->fs_version > MTB_UFS_VERSION_1 ||
538757Svsakar 	    fs->fs_version < MTB_UFS_VERSION_MIN))) {
5390Sstevel@tonic-gate 		if (!override) {
5400Sstevel@tonic-gate 			printf("%s: Unrecognized UFS version number: %d\n",
5410Sstevel@tonic-gate 			    special, fs->fs_version);
5420Sstevel@tonic-gate 			exit(1);
5430Sstevel@tonic-gate 		}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 		printf("WARNING: Unrecognized UFS version number. ");
5460Sstevel@tonic-gate 		printf("Continue? (y/n): ");
5470Sstevel@tonic-gate 		(void) fflush(stdout);
5480Sstevel@tonic-gate 		if (gets(input_buffer) == NULL) {
5490Sstevel@tonic-gate 			exit(1);
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		if (*input_buffer != 'y' && *input_buffer != 'Y') {
5530Sstevel@tonic-gate 			exit(1);
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 	}
5560Sstevel@tonic-gate #ifdef FS_42POSTBLFMT
5570Sstevel@tonic-gate 	if (fs->fs_postblformat == FS_42POSTBLFMT)
5580Sstevel@tonic-gate 		fs->fs_nrpos = 8;
5590Sstevel@tonic-gate #endif
5600Sstevel@tonic-gate 	printf("fsdb of %s %s -- last mounted on %s\n",
5610Sstevel@tonic-gate 		special,
5620Sstevel@tonic-gate 		(wrtflag == O_RDWR) ? "(Opened for write)" : "(Read only)",
5630Sstevel@tonic-gate 		&fs->fs_fsmnt[0]);
5640Sstevel@tonic-gate #ifdef sun
5650Sstevel@tonic-gate 	printf("fs_clean is currently set to ");
5660Sstevel@tonic-gate 	switch (fs->fs_clean) {
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	case FSACTIVE:
5690Sstevel@tonic-gate 		printf("FSACTIVE\n");
5700Sstevel@tonic-gate 		break;
5710Sstevel@tonic-gate 	case FSCLEAN:
5720Sstevel@tonic-gate 		printf("FSCLEAN\n");
5730Sstevel@tonic-gate 		break;
5740Sstevel@tonic-gate 	case FSSTABLE:
5750Sstevel@tonic-gate 		printf("FSSTABLE\n");
5760Sstevel@tonic-gate 		break;
5770Sstevel@tonic-gate 	case FSBAD:
5780Sstevel@tonic-gate 		printf("FSBAD\n");
5790Sstevel@tonic-gate 		break;
5800Sstevel@tonic-gate 	case FSSUSPEND:
5810Sstevel@tonic-gate 		printf("FSSUSPEND\n");
5820Sstevel@tonic-gate 		break;
5830Sstevel@tonic-gate 	case FSLOG:
5840Sstevel@tonic-gate 		printf("FSLOG\n");
5850Sstevel@tonic-gate 		break;
5860Sstevel@tonic-gate 	case FSFIX:
5870Sstevel@tonic-gate 		printf("FSFIX\n");
5880Sstevel@tonic-gate 		if (!override) {
5890Sstevel@tonic-gate 			printf("%s: fsck may be running on this file system\n",
5900Sstevel@tonic-gate 								special);
5910Sstevel@tonic-gate 			exit(1);
5920Sstevel@tonic-gate 		}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 		printf("WARNING: fsck may be running on this file system. ");
5950Sstevel@tonic-gate 		printf("Continue? (y/n): ");
5960Sstevel@tonic-gate 		(void) fflush(stdout);
5970Sstevel@tonic-gate 		if (gets(input_buffer) == NULL) {
5980Sstevel@tonic-gate 			exit(1);
5990Sstevel@tonic-gate 		}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		if (*input_buffer != 'y' && *input_buffer != 'Y') {
6020Sstevel@tonic-gate 			exit(1);
6030Sstevel@tonic-gate 		}
6040Sstevel@tonic-gate 		break;
6050Sstevel@tonic-gate 	default:
6060Sstevel@tonic-gate 		printf("an unknown value (0x%x)\n", fs->fs_clean);
6070Sstevel@tonic-gate 		break;
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (fs->fs_state == (FSOKAY - fs->fs_time)) {
6110Sstevel@tonic-gate 		printf("fs_state consistent (fs_clean CAN be trusted)\n");
6120Sstevel@tonic-gate 	} else {
6130Sstevel@tonic-gate 		printf("fs_state inconsistent (fs_clean CAN'T trusted)\n");
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate #endif /* sun */
6160Sstevel@tonic-gate 	/*
6170Sstevel@tonic-gate 	 * Malloc buffers and set up cache.
6180Sstevel@tonic-gate 	 */
6190Sstevel@tonic-gate 	buffers = malloc(NBUF * BLKSIZE);
6200Sstevel@tonic-gate 	bhdr.fwd = bhdr.back = &bhdr;
6210Sstevel@tonic-gate 	for (i = 0; i < NBUF; i++) {
6220Sstevel@tonic-gate 		bp = &lbuf[i];
6230Sstevel@tonic-gate 		bp->blkaddr = buffers + (i * BLKSIZE);
6240Sstevel@tonic-gate 		bp->valid = 0;
6250Sstevel@tonic-gate 		insert(bp);
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate 	/*
6280Sstevel@tonic-gate 	 * Malloc filenames structure.  The space for the actual filenames
6290Sstevel@tonic-gate 	 * is allocated as it needs it. We estimate the size based on the
6300Sstevel@tonic-gate 	 * number of inodes(objects) in the filesystem and the number of
6310Sstevel@tonic-gate 	 * directories.  The number of directories are padded by 3 because
6320Sstevel@tonic-gate 	 * each directory traversed during a "find" or "ls -R" needs 3
6330Sstevel@tonic-gate 	 * entries.
6340Sstevel@tonic-gate 	 */
6350Sstevel@tonic-gate 	maxfiles = (long)((((u_offset_t)fs->fs_ncg * (u_offset_t)fs->fs_ipg) -
6360Sstevel@tonic-gate 	    (u_offset_t)fs->fs_cstotal.cs_nifree) +
6370Sstevel@tonic-gate 	    ((u_offset_t)fs->fs_cstotal.cs_ndir * (u_offset_t)3));
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	filenames = (struct filenames *)calloc(maxfiles,
6400Sstevel@tonic-gate 	    sizeof (struct filenames));
6410Sstevel@tonic-gate 	if (filenames == NULL) {
6420Sstevel@tonic-gate 		/*
6430Sstevel@tonic-gate 		 * If we could not allocate memory for all of files
6440Sstevel@tonic-gate 		 * in the filesystem then, back off to the old fixed
6450Sstevel@tonic-gate 		 * value.
6460Sstevel@tonic-gate 		 */
6470Sstevel@tonic-gate 		maxfiles = MAXFILES;
6480Sstevel@tonic-gate 		filenames = (struct filenames *)calloc(maxfiles,
6490Sstevel@tonic-gate 		    sizeof (struct filenames));
6500Sstevel@tonic-gate 		if (filenames == NULL) {
6510Sstevel@tonic-gate 			printf("out of memory\n");
6520Sstevel@tonic-gate 			exit(1);
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	restore_inode(2);
6570Sstevel@tonic-gate 	/*
6580Sstevel@tonic-gate 	 * Malloc a few filenames (needed by pwd for example).
6590Sstevel@tonic-gate 	 */
6600Sstevel@tonic-gate 	for (i = 0; i < MAXPATHLEN; i++) {
6610Sstevel@tonic-gate 		input_path[i] = calloc(1, MAXNAMLEN);
6620Sstevel@tonic-gate 		stack_path[i] = calloc(1, MAXNAMLEN);
6630Sstevel@tonic-gate 		current_path[i] = calloc(1, MAXNAMLEN);
6640Sstevel@tonic-gate 		if (current_path[i] == NULL) {
6650Sstevel@tonic-gate 			printf("out of memory\n");
6660Sstevel@tonic-gate 			exit(1);
6670Sstevel@tonic-gate 		}
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 	current_pathp = -1;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	(void) signal(2, err);
6720Sstevel@tonic-gate 	(void) setjmp(env);
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	getnextinput();
6750Sstevel@tonic-gate 	/*
6760Sstevel@tonic-gate 	 * Main loop and case statement.  If an error condition occurs
6770Sstevel@tonic-gate 	 * initialization and recovery is attempted.
6780Sstevel@tonic-gate 	 */
6790Sstevel@tonic-gate 	for (;;) {
6800Sstevel@tonic-gate 		if (error) {
6810Sstevel@tonic-gate 			freemem(filenames, nfiles);
6820Sstevel@tonic-gate 			nfiles = 0;
6830Sstevel@tonic-gate 			c_count = 0;
6840Sstevel@tonic-gate 			count = 1;
6850Sstevel@tonic-gate 			star = 0;
6860Sstevel@tonic-gate 			error = 0;
6870Sstevel@tonic-gate 			paren = 0;
6880Sstevel@tonic-gate 			acting_on_inode = 0;
6890Sstevel@tonic-gate 			acting_on_directory = 0;
6900Sstevel@tonic-gate 			should_print = 1;
6910Sstevel@tonic-gate 			addr = erraddr;
6920Sstevel@tonic-gate 			cur_ino = errino;
6930Sstevel@tonic-gate 			cur_inum = errinum;
6940Sstevel@tonic-gate 			cur_bytes = errcur_bytes;
6950Sstevel@tonic-gate 			printf("?\n");
6960Sstevel@tonic-gate 			getnextinput();
6970Sstevel@tonic-gate 			if (error)
6980Sstevel@tonic-gate 				continue;
6990Sstevel@tonic-gate 		}
7000Sstevel@tonic-gate 		c_count++;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 		switch (c = getachar()) {
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 		case '\n': /* command end */
7050Sstevel@tonic-gate 			freemem(filenames, nfiles);
7060Sstevel@tonic-gate 			nfiles = 0;
7070Sstevel@tonic-gate 			if (should_print && laststyle == '=') {
7080Sstevel@tonic-gate 				ungetachar(c);
7090Sstevel@tonic-gate 				goto calc;
7100Sstevel@tonic-gate 			}
7110Sstevel@tonic-gate 			if (c_count == 1) {
7120Sstevel@tonic-gate 				clear = 0;
7130Sstevel@tonic-gate 				should_print = 1;
7140Sstevel@tonic-gate 				erraddr = addr;
7150Sstevel@tonic-gate 				errino = cur_ino;
7160Sstevel@tonic-gate 				errinum = cur_inum;
7170Sstevel@tonic-gate 				errcur_bytes = cur_bytes;
7180Sstevel@tonic-gate 				switch (objsz) {
7190Sstevel@tonic-gate 				case DIRECTORY:
7200Sstevel@tonic-gate 					if ((addr = getdirslot(
7210Sstevel@tonic-gate 							(long)dirslot+1)) == 0)
7220Sstevel@tonic-gate 						should_print = 0;
7230Sstevel@tonic-gate 					if (error) {
7240Sstevel@tonic-gate 						ungetachar(c);
7250Sstevel@tonic-gate 						continue;
7260Sstevel@tonic-gate 					}
7270Sstevel@tonic-gate 					break;
7280Sstevel@tonic-gate 				case INODE:
7290Sstevel@tonic-gate 					cur_inum++;
7300Sstevel@tonic-gate 					addr = itob(cur_inum);
7310Sstevel@tonic-gate 					if (!icheck(addr)) {
7320Sstevel@tonic-gate 						cur_inum--;
7330Sstevel@tonic-gate 						should_print = 0;
7340Sstevel@tonic-gate 					}
7350Sstevel@tonic-gate 					break;
7360Sstevel@tonic-gate 				case CGRP:
7370Sstevel@tonic-gate 				case SB:
7380Sstevel@tonic-gate 					cur_cgrp++;
7390Sstevel@tonic-gate 					addr = cgrp_check(cur_cgrp);
7400Sstevel@tonic-gate 					if (addr == 0) {
7410Sstevel@tonic-gate 						cur_cgrp--;
7420Sstevel@tonic-gate 						continue;
7430Sstevel@tonic-gate 					}
7440Sstevel@tonic-gate 					break;
7450Sstevel@tonic-gate 				case SHADOW_DATA:
7460Sstevel@tonic-gate 					if ((addr = getshadowslot(
7470Sstevel@tonic-gate 					    (long)cur_shad + 1)) == 0)
7480Sstevel@tonic-gate 						should_print = 0;
7490Sstevel@tonic-gate 					if (error) {
7500Sstevel@tonic-gate 						ungetachar(c);
7510Sstevel@tonic-gate 						continue;
7520Sstevel@tonic-gate 					}
7530Sstevel@tonic-gate 					break;
7540Sstevel@tonic-gate 				default:
7550Sstevel@tonic-gate 					addr += objsz;
7560Sstevel@tonic-gate 					cur_bytes += objsz;
7570Sstevel@tonic-gate 					if (valid_addr() == 0)
7580Sstevel@tonic-gate 						continue;
7590Sstevel@tonic-gate 				}
7600Sstevel@tonic-gate 			}
7610Sstevel@tonic-gate 			if (type == NUMB)
7620Sstevel@tonic-gate 				trapped = 0;
7630Sstevel@tonic-gate 			if (should_print)
7640Sstevel@tonic-gate 				switch (objsz) {
7650Sstevel@tonic-gate 				case DIRECTORY:
7660Sstevel@tonic-gate 					fprnt('?', 'd');
7670Sstevel@tonic-gate 					break;
7680Sstevel@tonic-gate 				case INODE:
7690Sstevel@tonic-gate 					fprnt('?', 'i');
7700Sstevel@tonic-gate 					if (!error)
7710Sstevel@tonic-gate 						cur_ino = addr;
7720Sstevel@tonic-gate 					break;
7730Sstevel@tonic-gate 				case CGRP:
7740Sstevel@tonic-gate 					fprnt('?', 'c');
7750Sstevel@tonic-gate 					break;
7760Sstevel@tonic-gate 				case SB:
7770Sstevel@tonic-gate 					fprnt('?', 's');
7780Sstevel@tonic-gate 					break;
7790Sstevel@tonic-gate 				case SHADOW_DATA:
7800Sstevel@tonic-gate 					fprnt('?', 'S');
7810Sstevel@tonic-gate 					break;
7820Sstevel@tonic-gate 				case CHAR:
7830Sstevel@tonic-gate 				case SHORT:
7840Sstevel@tonic-gate 				case LONG:
7850Sstevel@tonic-gate 					fprnt(laststyle, lastpo);
7860Sstevel@tonic-gate 				}
7870Sstevel@tonic-gate 			if (error) {
7880Sstevel@tonic-gate 				ungetachar(c);
7890Sstevel@tonic-gate 				continue;
7900Sstevel@tonic-gate 			}
7910Sstevel@tonic-gate 			c_count = colon = acting_on_inode = 0;
7920Sstevel@tonic-gate 			acting_on_directory = 0;
7930Sstevel@tonic-gate 			should_print = 1;
7940Sstevel@tonic-gate 			getnextinput();
7950Sstevel@tonic-gate 			if (error)
7960Sstevel@tonic-gate 				continue;
7970Sstevel@tonic-gate 			erraddr = addr;
7980Sstevel@tonic-gate 			errino = cur_ino;
7990Sstevel@tonic-gate 			errinum = cur_inum;
8000Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
8010Sstevel@tonic-gate 			continue;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		case '(': /* numeric expression or unknown command */
8040Sstevel@tonic-gate 		default:
8050Sstevel@tonic-gate 			colon = 0;
8060Sstevel@tonic-gate 			if (digit(c) || c == '(') {
8070Sstevel@tonic-gate 				ungetachar(c);
8080Sstevel@tonic-gate 				addr = expr();
8090Sstevel@tonic-gate 				type = NUMB;
8100Sstevel@tonic-gate 				value = addr;
8110Sstevel@tonic-gate 				continue;
8120Sstevel@tonic-gate 			}
8130Sstevel@tonic-gate 			printf("unknown command or bad syntax\n");
8140Sstevel@tonic-gate 			error++;
8150Sstevel@tonic-gate 			continue;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 		case '?': /* general print facilities */
8180Sstevel@tonic-gate 		case '/':
8190Sstevel@tonic-gate 			fprnt(c, getachar());
8200Sstevel@tonic-gate 			continue;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 		case ';': /* command separator and . */
8230Sstevel@tonic-gate 		case '\t':
8240Sstevel@tonic-gate 		case ' ':
8250Sstevel@tonic-gate 		case '.':
8260Sstevel@tonic-gate 			continue;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 		case ':': /* command indicator */
8290Sstevel@tonic-gate 			colon++;
8300Sstevel@tonic-gate 			commands++;
8310Sstevel@tonic-gate 			should_print = 0;
8320Sstevel@tonic-gate 			stringsize = 0;
8330Sstevel@tonic-gate 			trapped = 0;
8340Sstevel@tonic-gate 			continue;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 		case ',': /* count indicator */
8370Sstevel@tonic-gate 			colon = star = 0;
8380Sstevel@tonic-gate 			if ((c = getachar()) == '*') {
8390Sstevel@tonic-gate 				star = 1;
8400Sstevel@tonic-gate 				count = BLKSIZE;
8410Sstevel@tonic-gate 			} else {
8420Sstevel@tonic-gate 				ungetachar(c);
8430Sstevel@tonic-gate 				count = expr();
8440Sstevel@tonic-gate 				if (error)
8450Sstevel@tonic-gate 					continue;
8460Sstevel@tonic-gate 				if (!count)
8470Sstevel@tonic-gate 					count = 1;
8480Sstevel@tonic-gate 			}
8490Sstevel@tonic-gate 			clear = 0;
8500Sstevel@tonic-gate 			continue;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 		case '+': /* address addition */
8530Sstevel@tonic-gate 			colon = 0;
8540Sstevel@tonic-gate 			c = getachar();
8550Sstevel@tonic-gate 			ungetachar(c);
8560Sstevel@tonic-gate 			if (c == '\n')
8570Sstevel@tonic-gate 				temp = 1;
8580Sstevel@tonic-gate 			else {
8590Sstevel@tonic-gate 				temp = expr();
8600Sstevel@tonic-gate 				if (error)
8610Sstevel@tonic-gate 					continue;
8620Sstevel@tonic-gate 			}
8630Sstevel@tonic-gate 			erraddr = addr;
8640Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
8650Sstevel@tonic-gate 			switch (objsz) {
8660Sstevel@tonic-gate 			case DIRECTORY:
8670Sstevel@tonic-gate 				addr = getdirslot((long)(dirslot + temp));
8680Sstevel@tonic-gate 				if (error)
8690Sstevel@tonic-gate 					continue;
8700Sstevel@tonic-gate 				break;
8710Sstevel@tonic-gate 			case INODE:
8720Sstevel@tonic-gate 				cur_inum += temp;
8730Sstevel@tonic-gate 				addr = itob(cur_inum);
8740Sstevel@tonic-gate 				if (!icheck(addr)) {
8750Sstevel@tonic-gate 					cur_inum -= temp;
8760Sstevel@tonic-gate 					continue;
8770Sstevel@tonic-gate 				}
8780Sstevel@tonic-gate 				break;
8790Sstevel@tonic-gate 			case CGRP:
8800Sstevel@tonic-gate 			case SB:
8810Sstevel@tonic-gate 				cur_cgrp += temp;
8820Sstevel@tonic-gate 				if ((addr = cgrp_check(cur_cgrp)) == 0) {
8830Sstevel@tonic-gate 					cur_cgrp -= temp;
8840Sstevel@tonic-gate 					continue;
8850Sstevel@tonic-gate 				}
8860Sstevel@tonic-gate 				break;
8870Sstevel@tonic-gate 			case SHADOW_DATA:
8880Sstevel@tonic-gate 				addr = getshadowslot((long)(cur_shad + temp));
8890Sstevel@tonic-gate 				if (error)
8900Sstevel@tonic-gate 				    continue;
8910Sstevel@tonic-gate 				break;
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 			default:
8940Sstevel@tonic-gate 				laststyle = '/';
8950Sstevel@tonic-gate 				addr += temp * objsz;
8960Sstevel@tonic-gate 				cur_bytes += temp * objsz;
8970Sstevel@tonic-gate 				if (valid_addr() == 0)
8980Sstevel@tonic-gate 					continue;
8990Sstevel@tonic-gate 			}
9000Sstevel@tonic-gate 			value = get(objsz);
9010Sstevel@tonic-gate 			continue;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 		case '-': /* address subtraction */
9040Sstevel@tonic-gate 			colon = 0;
9050Sstevel@tonic-gate 			c = getachar();
9060Sstevel@tonic-gate 			ungetachar(c);
9070Sstevel@tonic-gate 			if (c == '\n')
9080Sstevel@tonic-gate 				temp = 1;
9090Sstevel@tonic-gate 			else {
9100Sstevel@tonic-gate 				temp = expr();
9110Sstevel@tonic-gate 				if (error)
9120Sstevel@tonic-gate 					continue;
9130Sstevel@tonic-gate 			}
9140Sstevel@tonic-gate 			erraddr = addr;
9150Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
9160Sstevel@tonic-gate 			switch (objsz) {
9170Sstevel@tonic-gate 			case DIRECTORY:
9180Sstevel@tonic-gate 				addr = getdirslot((long)(dirslot - temp));
9190Sstevel@tonic-gate 				if (error)
9200Sstevel@tonic-gate 					continue;
9210Sstevel@tonic-gate 				break;
9220Sstevel@tonic-gate 			case INODE:
9230Sstevel@tonic-gate 				cur_inum -= temp;
9240Sstevel@tonic-gate 				addr = itob(cur_inum);
9250Sstevel@tonic-gate 				if (!icheck(addr)) {
9260Sstevel@tonic-gate 					cur_inum += temp;
9270Sstevel@tonic-gate 					continue;
9280Sstevel@tonic-gate 				}
9290Sstevel@tonic-gate 				break;
9300Sstevel@tonic-gate 			case CGRP:
9310Sstevel@tonic-gate 			case SB:
9320Sstevel@tonic-gate 				cur_cgrp -= temp;
9330Sstevel@tonic-gate 				if ((addr = cgrp_check(cur_cgrp)) == 0) {
9340Sstevel@tonic-gate 					cur_cgrp += temp;
9350Sstevel@tonic-gate 					continue;
9360Sstevel@tonic-gate 				}
9370Sstevel@tonic-gate 				break;
9380Sstevel@tonic-gate 			case SHADOW_DATA:
9390Sstevel@tonic-gate 				addr = getshadowslot((long)(cur_shad - temp));
9400Sstevel@tonic-gate 				if (error)
9410Sstevel@tonic-gate 					continue;
9420Sstevel@tonic-gate 				break;
9430Sstevel@tonic-gate 			default:
9440Sstevel@tonic-gate 				laststyle = '/';
9450Sstevel@tonic-gate 				addr -= temp * objsz;
9460Sstevel@tonic-gate 				cur_bytes -= temp * objsz;
9470Sstevel@tonic-gate 				if (valid_addr() == 0)
9480Sstevel@tonic-gate 					continue;
9490Sstevel@tonic-gate 			}
9500Sstevel@tonic-gate 			value = get(objsz);
9510Sstevel@tonic-gate 			continue;
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 		case '*': /* address multiplication */
9540Sstevel@tonic-gate 			colon = 0;
9550Sstevel@tonic-gate 			temp = expr();
9560Sstevel@tonic-gate 			if (error)
9570Sstevel@tonic-gate 				continue;
9580Sstevel@tonic-gate 			if (objsz != INODE && objsz != DIRECTORY)
9590Sstevel@tonic-gate 				laststyle = '/';
9600Sstevel@tonic-gate 			addr *= temp;
9610Sstevel@tonic-gate 			value = get(objsz);
9620Sstevel@tonic-gate 			continue;
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 		case '%': /* address division */
9650Sstevel@tonic-gate 			colon = 0;
9660Sstevel@tonic-gate 			temp = expr();
9670Sstevel@tonic-gate 			if (error)
9680Sstevel@tonic-gate 				continue;
9690Sstevel@tonic-gate 			if (!temp) {
9700Sstevel@tonic-gate 				printf("divide by zero\n");
9710Sstevel@tonic-gate 				error++;
9720Sstevel@tonic-gate 				continue;
9730Sstevel@tonic-gate 			}
9740Sstevel@tonic-gate 			if (objsz != INODE && objsz != DIRECTORY)
9750Sstevel@tonic-gate 				laststyle = '/';
9760Sstevel@tonic-gate 			addr /= temp;
9770Sstevel@tonic-gate 			value = get(objsz);
9780Sstevel@tonic-gate 			continue;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 		case '=': { /* assignment operation */
9810Sstevel@tonic-gate 			short tbase;
9820Sstevel@tonic-gate calc:
9830Sstevel@tonic-gate 			tbase = base;
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 			c = getachar();
9860Sstevel@tonic-gate 			if (c == '\n') {
9870Sstevel@tonic-gate 				ungetachar(c);
9880Sstevel@tonic-gate 				c = lastpo;
9890Sstevel@tonic-gate 				if (acting_on_inode == 1) {
9900Sstevel@tonic-gate 					if (c != 'o' && c != 'd' && c != 'x' &&
9910Sstevel@tonic-gate 					    c != 'O' && c != 'D' && c != 'X') {
9920Sstevel@tonic-gate 						switch (objsz) {
9930Sstevel@tonic-gate 						case LONG:
9940Sstevel@tonic-gate 							c = lastpo = 'X';
9950Sstevel@tonic-gate 							break;
9960Sstevel@tonic-gate 						case SHORT:
9970Sstevel@tonic-gate 							c = lastpo = 'x';
9980Sstevel@tonic-gate 							break;
9990Sstevel@tonic-gate 						case CHAR:
10000Sstevel@tonic-gate 							c = lastpo = 'c';
10010Sstevel@tonic-gate 						}
10020Sstevel@tonic-gate 					}
10030Sstevel@tonic-gate 				} else {
10040Sstevel@tonic-gate 					if (acting_on_inode == 2)
10050Sstevel@tonic-gate 						c = lastpo = 't';
10060Sstevel@tonic-gate 				}
10070Sstevel@tonic-gate 			} else if (acting_on_inode)
10080Sstevel@tonic-gate 				lastpo = c;
10090Sstevel@tonic-gate 			should_print = star = 0;
10100Sstevel@tonic-gate 			count = 1;
10110Sstevel@tonic-gate 			erraddr = addr;
10120Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
10130Sstevel@tonic-gate 			switch (c) {
10140Sstevel@tonic-gate 			case '"': /* character string */
10150Sstevel@tonic-gate 				if (type == NUMB) {
10160Sstevel@tonic-gate 					blocksize = BLKSIZE;
10170Sstevel@tonic-gate 					filesize = BLKSIZE * 2;
10180Sstevel@tonic-gate 					cur_bytes = blkoff(fs, addr);
10190Sstevel@tonic-gate 					if (objsz == DIRECTORY ||
10200Sstevel@tonic-gate 								objsz == INODE)
10210Sstevel@tonic-gate 						lastpo = 'X';
10220Sstevel@tonic-gate 				}
10230Sstevel@tonic-gate 				puta();
10240Sstevel@tonic-gate 				continue;
10250Sstevel@tonic-gate 			case '+': /* =+ operator */
10260Sstevel@tonic-gate 				temp = expr();
10270Sstevel@tonic-gate 				value = get(objsz);
10280Sstevel@tonic-gate 				if (!error)
10290Sstevel@tonic-gate 					put(value+temp, objsz);
10300Sstevel@tonic-gate 				continue;
10310Sstevel@tonic-gate 			case '-': /* =- operator */
10320Sstevel@tonic-gate 				temp = expr();
10330Sstevel@tonic-gate 				value = get(objsz);
10340Sstevel@tonic-gate 				if (!error)
10350Sstevel@tonic-gate 					put(value-temp, objsz);
10360Sstevel@tonic-gate 				continue;
10370Sstevel@tonic-gate 			case 'b':
10380Sstevel@tonic-gate 			case 'c':
10390Sstevel@tonic-gate 				if (objsz == CGRP)
10400Sstevel@tonic-gate 					fprnt('?', c);
10410Sstevel@tonic-gate 				else
10420Sstevel@tonic-gate 					fprnt('/', c);
10430Sstevel@tonic-gate 				continue;
10440Sstevel@tonic-gate 			case 'i':
10450Sstevel@tonic-gate 				addr = cur_ino;
10460Sstevel@tonic-gate 				fprnt('?', 'i');
10470Sstevel@tonic-gate 				continue;
10480Sstevel@tonic-gate 			case 's':
10490Sstevel@tonic-gate 				fprnt('?', 's');
10500Sstevel@tonic-gate 				continue;
10510Sstevel@tonic-gate 			case 't':
10520Sstevel@tonic-gate 			case 'T':
10530Sstevel@tonic-gate 				laststyle = '=';
10540Sstevel@tonic-gate 				printf("\t\t");
10550Sstevel@tonic-gate 				{
10560Sstevel@tonic-gate 					/*
10570Sstevel@tonic-gate 					 * Truncation is intentional so
10580Sstevel@tonic-gate 					 * ctime is happy.
10590Sstevel@tonic-gate 					 */
10600Sstevel@tonic-gate 					time_t tvalue = (time_t)value;
10610Sstevel@tonic-gate 					printf("%s", ctime(&tvalue));
10620Sstevel@tonic-gate 				}
10630Sstevel@tonic-gate 				continue;
10640Sstevel@tonic-gate 			case 'o':
10650Sstevel@tonic-gate 				base = OCTAL;
10660Sstevel@tonic-gate 				goto otx;
10670Sstevel@tonic-gate 			case 'd':
10680Sstevel@tonic-gate 				if (objsz == DIRECTORY) {
10690Sstevel@tonic-gate 					addr = cur_dir;
10700Sstevel@tonic-gate 					fprnt('?', 'd');
10710Sstevel@tonic-gate 					continue;
10720Sstevel@tonic-gate 				}
10730Sstevel@tonic-gate 				base = DECIMAL;
10740Sstevel@tonic-gate 				goto otx;
10750Sstevel@tonic-gate 			case 'x':
10760Sstevel@tonic-gate 				base = HEX;
10770Sstevel@tonic-gate otx:
10780Sstevel@tonic-gate 				laststyle = '=';
10790Sstevel@tonic-gate 				printf("\t\t");
10800Sstevel@tonic-gate 				if (acting_on_inode)
10810Sstevel@tonic-gate 					print(value & 0177777L, 12, -8, 0);
10820Sstevel@tonic-gate 				else
10830Sstevel@tonic-gate 					print(addr & 0177777L, 12, -8, 0);
10840Sstevel@tonic-gate 				printf("\n");
10850Sstevel@tonic-gate 				base = tbase;
10860Sstevel@tonic-gate 				continue;
10870Sstevel@tonic-gate 			case 'O':
10880Sstevel@tonic-gate 				base = OCTAL;
10890Sstevel@tonic-gate 				goto OTX;
10900Sstevel@tonic-gate 			case 'D':
10910Sstevel@tonic-gate 				base = DECIMAL;
10920Sstevel@tonic-gate 				goto OTX;
10930Sstevel@tonic-gate 			case 'X':
10940Sstevel@tonic-gate 				base = HEX;
10950Sstevel@tonic-gate OTX:
10960Sstevel@tonic-gate 				laststyle = '=';
10970Sstevel@tonic-gate 				printf("\t\t");
10980Sstevel@tonic-gate 				if (acting_on_inode)
10990Sstevel@tonic-gate 					print(value, 12, -8, 0);
11000Sstevel@tonic-gate 				else
11010Sstevel@tonic-gate 					print(addr, 12, -8, 0);
11020Sstevel@tonic-gate 				printf("\n");
11030Sstevel@tonic-gate 				base = tbase;
11040Sstevel@tonic-gate 				continue;
11050Sstevel@tonic-gate 			default: /* regular assignment */
11060Sstevel@tonic-gate 				ungetachar(c);
11070Sstevel@tonic-gate 				value = expr();
11080Sstevel@tonic-gate 				if (error)
11090Sstevel@tonic-gate 					printf("syntax error\n");
11100Sstevel@tonic-gate 				else
11110Sstevel@tonic-gate 					put(value, objsz);
11120Sstevel@tonic-gate 				continue;
11130Sstevel@tonic-gate 			}
11140Sstevel@tonic-gate 		}
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 		case '>': /* save current address */
11170Sstevel@tonic-gate 			colon = 0;
11180Sstevel@tonic-gate 			should_print = 0;
11190Sstevel@tonic-gate 			c = getachar();
11200Sstevel@tonic-gate 			if (!letter(c) && !digit(c)) {
11210Sstevel@tonic-gate 				printf("invalid register specification, ");
11220Sstevel@tonic-gate 				printf("must be letter or digit\n");
11230Sstevel@tonic-gate 				error++;
11240Sstevel@tonic-gate 				continue;
11250Sstevel@tonic-gate 			}
11260Sstevel@tonic-gate 			if (letter(c)) {
11270Sstevel@tonic-gate 				if (c < 'a')
11280Sstevel@tonic-gate 					c = uppertolower(c);
11290Sstevel@tonic-gate 				c = hextodigit(c);
11300Sstevel@tonic-gate 			} else
11310Sstevel@tonic-gate 				c = numtodigit(c);
11320Sstevel@tonic-gate 			regs[c].sv_addr = addr;
11330Sstevel@tonic-gate 			regs[c].sv_value = value;
11340Sstevel@tonic-gate 			regs[c].sv_objsz = objsz;
11350Sstevel@tonic-gate 			continue;
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 		case '<': /* restore saved address */
11380Sstevel@tonic-gate 			colon = 0;
11390Sstevel@tonic-gate 			should_print = 0;
11400Sstevel@tonic-gate 			c = getachar();
11410Sstevel@tonic-gate 			if (!letter(c) && !digit(c)) {
11420Sstevel@tonic-gate 				printf("invalid register specification, ");
11430Sstevel@tonic-gate 				printf("must be letter or digit\n");
11440Sstevel@tonic-gate 				error++;
11450Sstevel@tonic-gate 				continue;
11460Sstevel@tonic-gate 			}
11470Sstevel@tonic-gate 			if (letter(c)) {
11480Sstevel@tonic-gate 				if (c < 'a')
11490Sstevel@tonic-gate 					c = uppertolower(c);
11500Sstevel@tonic-gate 				c = hextodigit(c);
11510Sstevel@tonic-gate 			} else
11520Sstevel@tonic-gate 				c = numtodigit(c);
11530Sstevel@tonic-gate 			addr = regs[c].sv_addr;
11540Sstevel@tonic-gate 			value = regs[c].sv_value;
11550Sstevel@tonic-gate 			objsz = regs[c].sv_objsz;
11560Sstevel@tonic-gate 			continue;
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 		case 'a':
11590Sstevel@tonic-gate 			if (colon)
11600Sstevel@tonic-gate 				colon = 0;
11610Sstevel@tonic-gate 			else
11620Sstevel@tonic-gate 				goto no_colon;
11630Sstevel@tonic-gate 			if (match("at", 2)) { 		/* access time */
11640Sstevel@tonic-gate 				acting_on_inode = 2;
11650Sstevel@tonic-gate 				should_print = 1;
11661051Smaheshvs 				addr = (long)&((struct dinode *)
11671051Smaheshvs 						(uintptr_t)cur_ino)->di_atime;
11680Sstevel@tonic-gate 				value = get(LONG);
11690Sstevel@tonic-gate 				type = NULL;
11700Sstevel@tonic-gate 				continue;
11710Sstevel@tonic-gate 			}
11720Sstevel@tonic-gate 			goto bad_syntax;
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 		case 'b':
11750Sstevel@tonic-gate 			if (colon)
11760Sstevel@tonic-gate 				colon = 0;
11770Sstevel@tonic-gate 			else
11780Sstevel@tonic-gate 				goto no_colon;
11790Sstevel@tonic-gate 			if (match("block", 2)) { 	/* block conversion */
11800Sstevel@tonic-gate 				if (type == NUMB) {
11810Sstevel@tonic-gate 					value = addr;
11820Sstevel@tonic-gate 					cur_bytes = 0;
11830Sstevel@tonic-gate 					blocksize = BLKSIZE;
11840Sstevel@tonic-gate 					filesize = BLKSIZE * 2;
11850Sstevel@tonic-gate 				}
11860Sstevel@tonic-gate 				addr = value << FRGSHIFT;
11870Sstevel@tonic-gate 				bod_addr = addr;
11880Sstevel@tonic-gate 				value = get(LONG);
11890Sstevel@tonic-gate 				type = BLOCK;
11900Sstevel@tonic-gate 				dirslot = 0;
11910Sstevel@tonic-gate 				trapped++;
11920Sstevel@tonic-gate 				continue;
11930Sstevel@tonic-gate 			}
11940Sstevel@tonic-gate 			if (match("bs", 2)) {		/* block size */
11950Sstevel@tonic-gate 				acting_on_inode = 1;
11960Sstevel@tonic-gate 				should_print = 1;
11970Sstevel@tonic-gate 				if (icheck(cur_ino) == 0)
11980Sstevel@tonic-gate 					continue;
11991051Smaheshvs 				addr = (long)&((struct dinode *)
12001051Smaheshvs 						(uintptr_t)cur_ino)->di_blocks;
12010Sstevel@tonic-gate 				value = get(LONG);
12020Sstevel@tonic-gate 				type = NULL;
12030Sstevel@tonic-gate 				continue;
12040Sstevel@tonic-gate 			}
12050Sstevel@tonic-gate 			if (match("base", 2)) {		/* change/show base */
12060Sstevel@tonic-gate showbase:
12070Sstevel@tonic-gate 				if ((c = getachar()) == '\n') {
12080Sstevel@tonic-gate 					ungetachar(c);
12090Sstevel@tonic-gate 					printf("base =\t\t");
12100Sstevel@tonic-gate 					switch (base) {
12110Sstevel@tonic-gate 					case OCTAL:
12120Sstevel@tonic-gate 						printf("OCTAL\n");
12130Sstevel@tonic-gate 						continue;
12140Sstevel@tonic-gate 					case DECIMAL:
12150Sstevel@tonic-gate 						printf("DECIMAL\n");
12160Sstevel@tonic-gate 						continue;
12170Sstevel@tonic-gate 					case HEX:
12180Sstevel@tonic-gate 						printf("HEX\n");
12190Sstevel@tonic-gate 						continue;
12200Sstevel@tonic-gate 					}
12210Sstevel@tonic-gate 				}
12220Sstevel@tonic-gate 				if (c != '=') {
12230Sstevel@tonic-gate 					printf("missing '='\n");
12240Sstevel@tonic-gate 					error++;
12250Sstevel@tonic-gate 					continue;
12260Sstevel@tonic-gate 				}
12270Sstevel@tonic-gate 				value = expr();
12280Sstevel@tonic-gate 				switch (value) {
12290Sstevel@tonic-gate 				default:
12300Sstevel@tonic-gate 					printf("invalid base\n");
12310Sstevel@tonic-gate 					error++;
12320Sstevel@tonic-gate 					break;
12330Sstevel@tonic-gate 				case OCTAL:
12340Sstevel@tonic-gate 				case DECIMAL:
12350Sstevel@tonic-gate 				case HEX:
12360Sstevel@tonic-gate 					base = (short)value;
12370Sstevel@tonic-gate 				}
12380Sstevel@tonic-gate 				goto showbase;
12390Sstevel@tonic-gate 			}
12400Sstevel@tonic-gate 			goto bad_syntax;
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 		case 'c':
12430Sstevel@tonic-gate 			if (colon)
12440Sstevel@tonic-gate 				colon = 0;
12450Sstevel@tonic-gate 			else
12460Sstevel@tonic-gate 				goto no_colon;
12470Sstevel@tonic-gate 			if (match("cd", 2)) {		/* change directory */
12480Sstevel@tonic-gate 				top = filenames - 1;
12490Sstevel@tonic-gate 				eat_spaces();
12500Sstevel@tonic-gate 				if ((c = getachar()) == '\n') {
12510Sstevel@tonic-gate 					ungetachar(c);
12520Sstevel@tonic-gate 					current_pathp = -1;
12530Sstevel@tonic-gate 					restore_inode(2);
12540Sstevel@tonic-gate 					continue;
12550Sstevel@tonic-gate 				}
12560Sstevel@tonic-gate 				ungetachar(c);
12570Sstevel@tonic-gate 				temp = cur_inum;
12580Sstevel@tonic-gate 				doing_cd = 1;
12590Sstevel@tonic-gate 				parse();
12600Sstevel@tonic-gate 				doing_cd = 0;
12610Sstevel@tonic-gate 				if (nfiles != 1) {
12620Sstevel@tonic-gate 					restore_inode((ino_t)temp);
12630Sstevel@tonic-gate 					if (!error) {
12640Sstevel@tonic-gate 						print_path(input_path,
12650Sstevel@tonic-gate 							(int)input_pathp);
12660Sstevel@tonic-gate 						if (nfiles == 0)
12670Sstevel@tonic-gate 							printf(" not found\n");
12680Sstevel@tonic-gate 						else
12690Sstevel@tonic-gate 							printf(" ambiguous\n");
12700Sstevel@tonic-gate 						error++;
12710Sstevel@tonic-gate 					}
12720Sstevel@tonic-gate 					continue;
12730Sstevel@tonic-gate 				}
12740Sstevel@tonic-gate 				restore_inode(filenames->ino);
12750Sstevel@tonic-gate 				if ((mode = icheck(addr)) == 0)
12760Sstevel@tonic-gate 					continue;
12770Sstevel@tonic-gate 				if ((mode & IFMT) != IFDIR) {
12780Sstevel@tonic-gate 					restore_inode((ino_t)temp);
12790Sstevel@tonic-gate 					print_path(input_path,
12800Sstevel@tonic-gate 							(int)input_pathp);
12810Sstevel@tonic-gate 					printf(" not a directory\n");
12820Sstevel@tonic-gate 					error++;
12830Sstevel@tonic-gate 					continue;
12840Sstevel@tonic-gate 				}
12850Sstevel@tonic-gate 				for (i = 0; i <= top->len; i++)
12860Sstevel@tonic-gate 					(void) strcpy(current_path[i],
12870Sstevel@tonic-gate 						top->fname[i]);
12880Sstevel@tonic-gate 				current_pathp = top->len;
12890Sstevel@tonic-gate 				continue;
12900Sstevel@tonic-gate 			}
12910Sstevel@tonic-gate 			if (match("cg", 2)) {		/* cylinder group */
12920Sstevel@tonic-gate 				if (type == NUMB)
12930Sstevel@tonic-gate 					value = addr;
12940Sstevel@tonic-gate 				if (value > fs->fs_ncg - 1) {
12950Sstevel@tonic-gate 					printf("maximum cylinder group is ");
12960Sstevel@tonic-gate 					print(fs->fs_ncg - 1, 8, -8, 0);
12970Sstevel@tonic-gate 					printf("\n");
12980Sstevel@tonic-gate 					error++;
12990Sstevel@tonic-gate 					continue;
13000Sstevel@tonic-gate 				}
13010Sstevel@tonic-gate 				type = objsz = CGRP;
13020Sstevel@tonic-gate 				cur_cgrp = (long)value;
13030Sstevel@tonic-gate 				addr = cgtod(fs, cur_cgrp) << FRGSHIFT;
13040Sstevel@tonic-gate 				continue;
13050Sstevel@tonic-gate 			}
13060Sstevel@tonic-gate 			if (match("ct", 2)) {		/* creation time */
13070Sstevel@tonic-gate 				acting_on_inode = 2;
13080Sstevel@tonic-gate 				should_print = 1;
13091051Smaheshvs 				addr = (long)&((struct dinode *)
13101051Smaheshvs 						(uintptr_t)cur_ino)->di_ctime;
13110Sstevel@tonic-gate 				value = get(LONG);
13120Sstevel@tonic-gate 				type = NULL;
13130Sstevel@tonic-gate 				continue;
13140Sstevel@tonic-gate 			}
13150Sstevel@tonic-gate 			goto bad_syntax;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 		case 'd':
13180Sstevel@tonic-gate 			if (colon)
13190Sstevel@tonic-gate 				colon = 0;
13200Sstevel@tonic-gate 			else
13210Sstevel@tonic-gate 				goto no_colon;
13220Sstevel@tonic-gate 			if (match("directory", 2)) { 	/* directory offsets */
13230Sstevel@tonic-gate 				if (type == NUMB)
13240Sstevel@tonic-gate 					value = addr;
13250Sstevel@tonic-gate 				objsz = DIRECTORY;
13260Sstevel@tonic-gate 				type = DIRECTORY;
13270Sstevel@tonic-gate 				addr = (u_offset_t)getdirslot((long)value);
13280Sstevel@tonic-gate 				continue;
13290Sstevel@tonic-gate 			}
13300Sstevel@tonic-gate 			if (match("db", 2)) {		/* direct block */
13310Sstevel@tonic-gate 				acting_on_inode = 1;
13320Sstevel@tonic-gate 				should_print = 1;
13330Sstevel@tonic-gate 				if (type == NUMB)
13340Sstevel@tonic-gate 					value = addr;
13350Sstevel@tonic-gate 				if (value >= NDADDR) {
13360Sstevel@tonic-gate 					printf("direct blocks are 0 to ");
13370Sstevel@tonic-gate 					print(NDADDR - 1, 0, 0, 0);
13380Sstevel@tonic-gate 					printf("\n");
13390Sstevel@tonic-gate 					error++;
13400Sstevel@tonic-gate 					continue;
13410Sstevel@tonic-gate 				}
13420Sstevel@tonic-gate 				addr = cur_ino;
13430Sstevel@tonic-gate 				if (!icheck(addr))
13440Sstevel@tonic-gate 					continue;
13450Sstevel@tonic-gate 				addr = (long)
13461051Smaheshvs 					&((struct dinode *)(uintptr_t)cur_ino)->
13470Sstevel@tonic-gate 								di_db[value];
13480Sstevel@tonic-gate 				bod_addr = addr;
13490Sstevel@tonic-gate 				cur_bytes = (value) * BLKSIZE;
13500Sstevel@tonic-gate 				cur_block = (long)value;
13510Sstevel@tonic-gate 				type = BLOCK;
13520Sstevel@tonic-gate 				dirslot = 0;
13530Sstevel@tonic-gate 				value = get(LONG);
13540Sstevel@tonic-gate 				if (!value && !override) {
13550Sstevel@tonic-gate 					printf("non existent block\n");
13560Sstevel@tonic-gate 					error++;
13570Sstevel@tonic-gate 				}
13580Sstevel@tonic-gate 				continue;
13590Sstevel@tonic-gate 			}
13600Sstevel@tonic-gate 			goto bad_syntax;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 		case 'f':
13630Sstevel@tonic-gate 			if (colon)
13640Sstevel@tonic-gate 				colon = 0;
13650Sstevel@tonic-gate 			else
13660Sstevel@tonic-gate 				goto no_colon;
13670Sstevel@tonic-gate 			if (match("find", 3)) {		/* find command */
13680Sstevel@tonic-gate 				find();
13690Sstevel@tonic-gate 				continue;
13700Sstevel@tonic-gate 			}
13710Sstevel@tonic-gate 			if (match("fragment", 2)) {	/* fragment conv. */
13720Sstevel@tonic-gate 				if (type == NUMB) {
13730Sstevel@tonic-gate 					value = addr;
13740Sstevel@tonic-gate 					cur_bytes = 0;
13750Sstevel@tonic-gate 					blocksize = FRGSIZE;
13760Sstevel@tonic-gate 					filesize = FRGSIZE * 2;
13770Sstevel@tonic-gate 				}
13780Sstevel@tonic-gate 				if (min(blocksize, filesize) - cur_bytes >
13790Sstevel@tonic-gate 							FRGSIZE) {
13800Sstevel@tonic-gate 					blocksize = cur_bytes + FRGSIZE;
13810Sstevel@tonic-gate 					filesize = blocksize * 2;
13820Sstevel@tonic-gate 				}
13830Sstevel@tonic-gate 				addr = value << FRGSHIFT;
13840Sstevel@tonic-gate 				bod_addr = addr;
13850Sstevel@tonic-gate 				value = get(LONG);
13860Sstevel@tonic-gate 				type = FRAGMENT;
13870Sstevel@tonic-gate 				dirslot = 0;
13880Sstevel@tonic-gate 				trapped++;
13890Sstevel@tonic-gate 				continue;
13900Sstevel@tonic-gate 			}
13910Sstevel@tonic-gate 			if (match("file", 4)) {		/* access as file */
13920Sstevel@tonic-gate 				acting_on_inode = 1;
13930Sstevel@tonic-gate 				should_print = 1;
13940Sstevel@tonic-gate 				if (type == NUMB)
13950Sstevel@tonic-gate 					value = addr;
13960Sstevel@tonic-gate 				addr = cur_ino;
13970Sstevel@tonic-gate 				if ((mode = icheck(addr)) == 0)
13980Sstevel@tonic-gate 					continue;
13990Sstevel@tonic-gate 				if (!override) {
14000Sstevel@tonic-gate 					switch (mode & IFMT) {
14010Sstevel@tonic-gate 					case IFCHR:
14020Sstevel@tonic-gate 					case IFBLK:
14030Sstevel@tonic-gate 					    printf("special device\n");
14040Sstevel@tonic-gate 					    error++;
14050Sstevel@tonic-gate 					    continue;
14060Sstevel@tonic-gate 					}
14070Sstevel@tonic-gate 				}
14080Sstevel@tonic-gate 				if ((addr = (u_offset_t)
14090Sstevel@tonic-gate 				    (bmap((long)value) << FRGSHIFT)) == 0)
14100Sstevel@tonic-gate 					continue;
14110Sstevel@tonic-gate 				cur_block = (long)value;
14120Sstevel@tonic-gate 				bod_addr = addr;
14130Sstevel@tonic-gate 				type = BLOCK;
14140Sstevel@tonic-gate 				dirslot = 0;
14150Sstevel@tonic-gate 				continue;
14160Sstevel@tonic-gate 			}
14170Sstevel@tonic-gate 			if (match("fill", 4)) {		/* fill */
14180Sstevel@tonic-gate 				if (getachar() != '=') {
14190Sstevel@tonic-gate 					printf("missing '='\n");
14200Sstevel@tonic-gate 					error++;
14210Sstevel@tonic-gate 					continue;
14220Sstevel@tonic-gate 				}
14230Sstevel@tonic-gate 				if (objsz == INODE || objsz == DIRECTORY ||
14240Sstevel@tonic-gate 				    objsz == SHADOW_DATA) {
14250Sstevel@tonic-gate 					printf(
14260Sstevel@tonic-gate 					    "can't fill inode or directory\n");
14270Sstevel@tonic-gate 					error++;
14280Sstevel@tonic-gate 					continue;
14290Sstevel@tonic-gate 				}
14300Sstevel@tonic-gate 				fill();
14310Sstevel@tonic-gate 				continue;
14320Sstevel@tonic-gate 			}
14330Sstevel@tonic-gate 			goto bad_syntax;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 		case 'g':
14360Sstevel@tonic-gate 			if (colon)
14370Sstevel@tonic-gate 				colon = 0;
14380Sstevel@tonic-gate 			else
14390Sstevel@tonic-gate 				goto no_colon;
14400Sstevel@tonic-gate 			if (match("gid", 1)) {		/* group id */
14410Sstevel@tonic-gate 				acting_on_inode = 1;
14420Sstevel@tonic-gate 				should_print = 1;
14431051Smaheshvs 				addr = (long)&((struct dinode *)
14441051Smaheshvs 						(uintptr_t)cur_ino)->di_gid;
14450Sstevel@tonic-gate 				value = get(SHORT);
14460Sstevel@tonic-gate 				type = NULL;
14470Sstevel@tonic-gate 				continue;
14480Sstevel@tonic-gate 			}
14490Sstevel@tonic-gate 			goto bad_syntax;
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 		case 'i':
14520Sstevel@tonic-gate 			if (colon)
14530Sstevel@tonic-gate 				colon = 0;
14540Sstevel@tonic-gate 			else
14550Sstevel@tonic-gate 				goto no_colon;
14560Sstevel@tonic-gate 			if (match("inode", 2)) { /* i# to inode conversion */
14570Sstevel@tonic-gate 				if (c_count == 2) {
14580Sstevel@tonic-gate 					addr = cur_ino;
14590Sstevel@tonic-gate 					value = get(INODE);
14600Sstevel@tonic-gate 					type = NULL;
14610Sstevel@tonic-gate 					laststyle = '=';
14620Sstevel@tonic-gate 					lastpo = 'i';
14630Sstevel@tonic-gate 					should_print = 1;
14640Sstevel@tonic-gate 					continue;
14650Sstevel@tonic-gate 				}
14660Sstevel@tonic-gate 				if (type == NUMB)
14670Sstevel@tonic-gate 					value = addr;
14680Sstevel@tonic-gate 				addr = itob(value);
14690Sstevel@tonic-gate 				if (!icheck(addr))
14700Sstevel@tonic-gate 					continue;
14710Sstevel@tonic-gate 				cur_ino = addr;
14720Sstevel@tonic-gate 				cur_inum = (long)value;
14730Sstevel@tonic-gate 				value = get(INODE);
14740Sstevel@tonic-gate 				type = NULL;
14750Sstevel@tonic-gate 				continue;
14760Sstevel@tonic-gate 			}
14770Sstevel@tonic-gate 			if (match("ib", 2)) {	/* indirect block */
14780Sstevel@tonic-gate 				acting_on_inode = 1;
14790Sstevel@tonic-gate 				should_print = 1;
14800Sstevel@tonic-gate 				if (type == NUMB)
14810Sstevel@tonic-gate 					value = addr;
14820Sstevel@tonic-gate 				if (value >= NIADDR) {
14830Sstevel@tonic-gate 					printf("indirect blocks are 0 to ");
14840Sstevel@tonic-gate 					print(NIADDR - 1, 0, 0, 0);
14850Sstevel@tonic-gate 					printf("\n");
14860Sstevel@tonic-gate 					error++;
14870Sstevel@tonic-gate 					continue;
14880Sstevel@tonic-gate 				}
14891051Smaheshvs 				addr = (long)&((struct dinode *)(uintptr_t)
14901051Smaheshvs 						cur_ino)->di_ib[value];
14910Sstevel@tonic-gate 				cur_bytes = (NDADDR - 1) * BLKSIZE;
14920Sstevel@tonic-gate 				temp = 1;
14930Sstevel@tonic-gate 				for (i = 0; i < value; i++) {
14940Sstevel@tonic-gate 					temp *= NINDIR(fs) * BLKSIZE;
14950Sstevel@tonic-gate 					cur_bytes += temp;
14960Sstevel@tonic-gate 				}
14970Sstevel@tonic-gate 				type = BLOCK;
14980Sstevel@tonic-gate 				dirslot = 0;
14990Sstevel@tonic-gate 				value = get(LONG);
15000Sstevel@tonic-gate 				if (!value && !override) {
15010Sstevel@tonic-gate 					printf("non existent block\n");
15020Sstevel@tonic-gate 					error++;
15030Sstevel@tonic-gate 				}
15040Sstevel@tonic-gate 				continue;
15050Sstevel@tonic-gate 			}
15060Sstevel@tonic-gate 			goto bad_syntax;
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 		case 'l':
15090Sstevel@tonic-gate 			if (colon)
15100Sstevel@tonic-gate 				colon = 0;
15110Sstevel@tonic-gate 			else
15120Sstevel@tonic-gate 				goto no_colon;
15130Sstevel@tonic-gate 			if (match("log_head", 8)) {
15140Sstevel@tonic-gate 				log_display_header();
15150Sstevel@tonic-gate 				should_print = 0;
15160Sstevel@tonic-gate 				continue;
15170Sstevel@tonic-gate 			}
15180Sstevel@tonic-gate 			if (match("log_delta", 9)) {
15190Sstevel@tonic-gate 				log_show(LOG_NDELTAS);
15200Sstevel@tonic-gate 				should_print = 0;
15210Sstevel@tonic-gate 				continue;
15220Sstevel@tonic-gate 			}
15230Sstevel@tonic-gate 			if (match("log_show", 8)) {
15240Sstevel@tonic-gate 				log_show(LOG_ALLDELTAS);
15250Sstevel@tonic-gate 				should_print = 0;
15260Sstevel@tonic-gate 				continue;
15270Sstevel@tonic-gate 			}
15280Sstevel@tonic-gate 			if (match("log_chk", 7)) {
15290Sstevel@tonic-gate 				log_show(LOG_CHECKSCAN);
15300Sstevel@tonic-gate 				should_print = 0;
15310Sstevel@tonic-gate 				continue;
15320Sstevel@tonic-gate 			}
15330Sstevel@tonic-gate 			if (match("log_otodb", 9)) {
15340Sstevel@tonic-gate 				if (log_lodb((u_offset_t)addr, &temp)) {
15350Sstevel@tonic-gate 					addr = temp;
15360Sstevel@tonic-gate 					should_print = 1;
15370Sstevel@tonic-gate 					laststyle = '=';
15380Sstevel@tonic-gate 				} else
15390Sstevel@tonic-gate 					error++;
15400Sstevel@tonic-gate 				continue;
15410Sstevel@tonic-gate 			}
15420Sstevel@tonic-gate 			if (match("ls", 2)) {		/* ls command */
15430Sstevel@tonic-gate 				temp = cur_inum;
15440Sstevel@tonic-gate 				recursive = long_list = 0;
15450Sstevel@tonic-gate 				top = filenames - 1;
15460Sstevel@tonic-gate 				for (;;) {
15470Sstevel@tonic-gate 					eat_spaces();
15480Sstevel@tonic-gate 					if ((c = getachar()) == '-') {
15490Sstevel@tonic-gate 						if ((c = getachar()) == 'R') {
15500Sstevel@tonic-gate 							recursive = 1;
15510Sstevel@tonic-gate 							continue;
15520Sstevel@tonic-gate 						} else if (c == 'l') {
15530Sstevel@tonic-gate 							long_list = 1;
15540Sstevel@tonic-gate 						} else {
15550Sstevel@tonic-gate 							printf(
15560Sstevel@tonic-gate 							    "unknown option ");
15570Sstevel@tonic-gate 							printf("'%c'\n", c);
15580Sstevel@tonic-gate 							error++;
15590Sstevel@tonic-gate 							break;
15600Sstevel@tonic-gate 						}
15610Sstevel@tonic-gate 					} else
15620Sstevel@tonic-gate 						ungetachar(c);
15630Sstevel@tonic-gate 					if ((c = getachar()) == '\n') {
15640Sstevel@tonic-gate 						if (c_count != 2) {
15650Sstevel@tonic-gate 							ungetachar(c);
15660Sstevel@tonic-gate 							break;
15670Sstevel@tonic-gate 						}
15680Sstevel@tonic-gate 					}
15690Sstevel@tonic-gate 					c_count++;
15700Sstevel@tonic-gate 					ungetachar(c);
15710Sstevel@tonic-gate 					parse();
15720Sstevel@tonic-gate 					restore_inode((ino_t)temp);
15730Sstevel@tonic-gate 					if (error)
15740Sstevel@tonic-gate 						break;
15750Sstevel@tonic-gate 				}
15760Sstevel@tonic-gate 				recursive = 0;
15770Sstevel@tonic-gate 				if (error || nfiles == 0) {
15780Sstevel@tonic-gate 					if (!error) {
15790Sstevel@tonic-gate 						print_path(input_path,
15800Sstevel@tonic-gate 							(int)input_pathp);
15810Sstevel@tonic-gate 						printf(" not found\n");
15820Sstevel@tonic-gate 					}
15830Sstevel@tonic-gate 					continue;
15840Sstevel@tonic-gate 				}
15850Sstevel@tonic-gate 				if (nfiles) {
15860Sstevel@tonic-gate 				    cmp_level = 0;
15870Sstevel@tonic-gate 				    qsort((char *)filenames, nfiles,
15880Sstevel@tonic-gate 					sizeof (struct filenames), ffcmp);
15890Sstevel@tonic-gate 				    ls(filenames, filenames + (nfiles - 1), 0);
15900Sstevel@tonic-gate 				} else {
15910Sstevel@tonic-gate 				    printf("no match\n");
15920Sstevel@tonic-gate 				    error++;
15930Sstevel@tonic-gate 				}
15940Sstevel@tonic-gate 				restore_inode((ino_t)temp);
15950Sstevel@tonic-gate 				continue;
15960Sstevel@tonic-gate 			}
15970Sstevel@tonic-gate 			if (match("ln", 2)) {		/* link count */
15980Sstevel@tonic-gate 				acting_on_inode = 1;
15990Sstevel@tonic-gate 				should_print = 1;
16001051Smaheshvs 				addr = (long)&((struct dinode *)
16011051Smaheshvs 						(uintptr_t)cur_ino)->di_nlink;
16020Sstevel@tonic-gate 				value = get(SHORT);
16030Sstevel@tonic-gate 				type = NULL;
16040Sstevel@tonic-gate 				continue;
16050Sstevel@tonic-gate 			}
16060Sstevel@tonic-gate 			goto bad_syntax;
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 		case 'm':
16090Sstevel@tonic-gate 			if (colon)
16100Sstevel@tonic-gate 				colon = 0;
16110Sstevel@tonic-gate 			else
16120Sstevel@tonic-gate 				goto no_colon;
16130Sstevel@tonic-gate 			addr = cur_ino;
16140Sstevel@tonic-gate 			if ((mode = icheck(addr)) == 0)
16150Sstevel@tonic-gate 				continue;
16160Sstevel@tonic-gate 			if (match("mt", 2)) { 		/* modification time */
16170Sstevel@tonic-gate 				acting_on_inode = 2;
16180Sstevel@tonic-gate 				should_print = 1;
16191051Smaheshvs 				addr = (long)&((struct dinode *)
16201051Smaheshvs 						(uintptr_t)cur_ino)->di_mtime;
16210Sstevel@tonic-gate 				value = get(LONG);
16220Sstevel@tonic-gate 				type = NULL;
16230Sstevel@tonic-gate 				continue;
16240Sstevel@tonic-gate 			}
16250Sstevel@tonic-gate 			if (match("md", 2)) {		/* mode */
16260Sstevel@tonic-gate 				acting_on_inode = 1;
16270Sstevel@tonic-gate 				should_print = 1;
16281051Smaheshvs 				addr = (long)&((struct dinode *)
16291051Smaheshvs 						(uintptr_t)cur_ino)->di_mode;
16300Sstevel@tonic-gate 				value = get(SHORT);
16310Sstevel@tonic-gate 				type = NULL;
16320Sstevel@tonic-gate 				continue;
16330Sstevel@tonic-gate 			}
16340Sstevel@tonic-gate 			if (match("maj", 2)) {	/* major device number */
16350Sstevel@tonic-gate 				acting_on_inode = 1;
16360Sstevel@tonic-gate 				should_print = 1;
16370Sstevel@tonic-gate 				if (devcheck(mode))
16380Sstevel@tonic-gate 					continue;
16391051Smaheshvs 				addr = (uintptr_t)&((struct dinode *)(uintptr_t)
16401051Smaheshvs 							cur_ino)->di_ordev;
16410Sstevel@tonic-gate 				{
16420Sstevel@tonic-gate 					long	dvalue;
16430Sstevel@tonic-gate 					dvalue = get(LONG);
16440Sstevel@tonic-gate 					value = major(dvalue);
16450Sstevel@tonic-gate 				}
16460Sstevel@tonic-gate 				type = NULL;
16470Sstevel@tonic-gate 				continue;
16480Sstevel@tonic-gate 			}
16490Sstevel@tonic-gate 			if (match("min", 2)) {	/* minor device number */
16500Sstevel@tonic-gate 				acting_on_inode = 1;
16510Sstevel@tonic-gate 				should_print = 1;
16520Sstevel@tonic-gate 				if (devcheck(mode))
16530Sstevel@tonic-gate 					continue;
16541051Smaheshvs 				addr = (uintptr_t)&((struct dinode *)(uintptr_t)
16551051Smaheshvs 							cur_ino)->di_ordev;
16560Sstevel@tonic-gate 				{
16570Sstevel@tonic-gate 					long	dvalue;
16580Sstevel@tonic-gate 					dvalue = (long)get(LONG);
16590Sstevel@tonic-gate 					value = minor(dvalue);
16600Sstevel@tonic-gate 				}
16610Sstevel@tonic-gate 				type = NULL;
16620Sstevel@tonic-gate 				continue;
16630Sstevel@tonic-gate 			}
16640Sstevel@tonic-gate 			goto bad_syntax;
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 		case 'n':
16670Sstevel@tonic-gate 			if (colon)
16680Sstevel@tonic-gate 				colon = 0;
16690Sstevel@tonic-gate 			else
16700Sstevel@tonic-gate 				goto no_colon;
16710Sstevel@tonic-gate 			if (match("nm", 1)) {		/* directory name */
16720Sstevel@tonic-gate 				objsz = DIRECTORY;
16730Sstevel@tonic-gate 				acting_on_directory = 1;
16740Sstevel@tonic-gate 				cur_dir = addr;
16750Sstevel@tonic-gate 				if ((cptr = getblk(addr)) == 0)
16760Sstevel@tonic-gate 					continue;
16770Sstevel@tonic-gate 				/*LINTED*/
16780Sstevel@tonic-gate 				dirp = (struct direct *)(cptr+blkoff(fs, addr));
16790Sstevel@tonic-gate 				stringsize = (long)dirp->d_reclen -
16800Sstevel@tonic-gate 						((long)&dirp->d_name[0] -
16810Sstevel@tonic-gate 							(long)&dirp->d_ino);
16821051Smaheshvs 				addr = (long)&((struct direct *)
16831051Smaheshvs 						(uintptr_t)addr)->d_name[0];
16840Sstevel@tonic-gate 				type = NULL;
16850Sstevel@tonic-gate 				continue;
16860Sstevel@tonic-gate 			}
16870Sstevel@tonic-gate 			goto bad_syntax;
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 		case 'o':
16900Sstevel@tonic-gate 			if (colon)
16910Sstevel@tonic-gate 				colon = 0;
16920Sstevel@tonic-gate 			else
16930Sstevel@tonic-gate 				goto no_colon;
16940Sstevel@tonic-gate 			if (match("override", 1)) {	/* override flip flop */
16950Sstevel@tonic-gate 				override = !override;
16960Sstevel@tonic-gate 				if (override)
16970Sstevel@tonic-gate 					printf("error checking off\n");
16980Sstevel@tonic-gate 				else
16990Sstevel@tonic-gate 					printf("error checking on\n");
17000Sstevel@tonic-gate 				continue;
17010Sstevel@tonic-gate 			}
17020Sstevel@tonic-gate 			goto bad_syntax;
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 		case 'p':
17050Sstevel@tonic-gate 			if (colon)
17060Sstevel@tonic-gate 				colon = 0;
17070Sstevel@tonic-gate 			else
17080Sstevel@tonic-gate 				goto no_colon;
17090Sstevel@tonic-gate 			if (match("pwd", 2)) {		/* print working dir */
17100Sstevel@tonic-gate 				print_path(current_path, (int)current_pathp);
17110Sstevel@tonic-gate 				printf("\n");
17120Sstevel@tonic-gate 				continue;
17130Sstevel@tonic-gate 			}
17140Sstevel@tonic-gate 			if (match("prompt", 2)) {	/* change prompt */
17150Sstevel@tonic-gate 				if ((c = getachar()) != '=') {
17160Sstevel@tonic-gate 					printf("missing '='\n");
17170Sstevel@tonic-gate 					error++;
17180Sstevel@tonic-gate 					continue;
17190Sstevel@tonic-gate 				}
17200Sstevel@tonic-gate 				if ((c = getachar()) != '"') {
17210Sstevel@tonic-gate 					printf("missing '\"'\n");
17220Sstevel@tonic-gate 					error++;
17230Sstevel@tonic-gate 					continue;
17240Sstevel@tonic-gate 				}
17250Sstevel@tonic-gate 				i = 0;
17260Sstevel@tonic-gate 				prompt = &prompt[0];
17270Sstevel@tonic-gate 				while ((c = getachar()) != '"' && c != '\n') {
17280Sstevel@tonic-gate 					prompt[i++] = c;
17290Sstevel@tonic-gate 					if (i >= PROMPTSIZE) {
17300Sstevel@tonic-gate 						printf("string too long\n");
17310Sstevel@tonic-gate 						error++;
17320Sstevel@tonic-gate 						break;
17330Sstevel@tonic-gate 					}
17340Sstevel@tonic-gate 				}
17350Sstevel@tonic-gate 				prompt[i] = '\0';
17360Sstevel@tonic-gate 				continue;
17370Sstevel@tonic-gate 			}
17380Sstevel@tonic-gate 			goto bad_syntax;
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 		case 'q':
17410Sstevel@tonic-gate 			if (!colon)
17420Sstevel@tonic-gate 				goto no_colon;
17430Sstevel@tonic-gate 			if (match("quit", 1)) {		/* quit */
17440Sstevel@tonic-gate 				if ((c = getachar()) != '\n') {
17450Sstevel@tonic-gate 					error++;
17460Sstevel@tonic-gate 					continue;
17470Sstevel@tonic-gate 				}
17480Sstevel@tonic-gate 				exit(0);
17490Sstevel@tonic-gate 			}
17500Sstevel@tonic-gate 			goto bad_syntax;
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 		case 's':
17530Sstevel@tonic-gate 			if (colon)
17540Sstevel@tonic-gate 				colon = 0;
17550Sstevel@tonic-gate 			else
17560Sstevel@tonic-gate 				goto no_colon;
17570Sstevel@tonic-gate 			if (match("sb", 2)) {		/* super block */
17580Sstevel@tonic-gate 				if (c_count == 2) {
17590Sstevel@tonic-gate 					cur_cgrp = -1;
17600Sstevel@tonic-gate 					type = objsz = SB;
17610Sstevel@tonic-gate 					laststyle = '=';
17620Sstevel@tonic-gate 					lastpo = 's';
17630Sstevel@tonic-gate 					should_print = 1;
17640Sstevel@tonic-gate 					continue;
17650Sstevel@tonic-gate 				}
17660Sstevel@tonic-gate 				if (type == NUMB)
17670Sstevel@tonic-gate 					value = addr;
17680Sstevel@tonic-gate 				if (value > fs->fs_ncg - 1) {
17690Sstevel@tonic-gate 					printf("maximum super block is ");
17700Sstevel@tonic-gate 					print(fs->fs_ncg - 1, 8, -8, 0);
17710Sstevel@tonic-gate 					printf("\n");
17720Sstevel@tonic-gate 					error++;
17730Sstevel@tonic-gate 					continue;
17740Sstevel@tonic-gate 				}
17750Sstevel@tonic-gate 				type = objsz = SB;
17760Sstevel@tonic-gate 				cur_cgrp = (long)value;
17770Sstevel@tonic-gate 				addr = cgsblock(fs, cur_cgrp) << FRGSHIFT;
17780Sstevel@tonic-gate 				continue;
17790Sstevel@tonic-gate 			}
17800Sstevel@tonic-gate 			if (match("shadow", 2)) {	/* shadow inode data */
17810Sstevel@tonic-gate 				if (type == NUMB)
17820Sstevel@tonic-gate 					value = addr;
17830Sstevel@tonic-gate 				objsz = SHADOW_DATA;
17840Sstevel@tonic-gate 				type = SHADOW_DATA;
17850Sstevel@tonic-gate 				addr = getshadowslot(value);
17860Sstevel@tonic-gate 				continue;
17870Sstevel@tonic-gate 			}
17880Sstevel@tonic-gate 			if (match("si", 2)) {   /* shadow inode field */
17890Sstevel@tonic-gate 				acting_on_inode = 1;
17900Sstevel@tonic-gate 				should_print = 1;
17911051Smaheshvs 				addr = (long)&((struct dinode *)
17921051Smaheshvs 						(uintptr_t)cur_ino)->di_shadow;
17930Sstevel@tonic-gate 				value = get(LONG);
17940Sstevel@tonic-gate 				type = NULL;
17950Sstevel@tonic-gate 				continue;
17960Sstevel@tonic-gate 			}
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 			if (match("sz", 2)) {		/* file size */
17990Sstevel@tonic-gate 				acting_on_inode = 1;
18000Sstevel@tonic-gate 				should_print = 1;
18011051Smaheshvs 				addr = (long)&((struct dinode *)
18021051Smaheshvs 						(uintptr_t)cur_ino)->di_size;
18030Sstevel@tonic-gate 				value = get(U_OFFSET_T);
18040Sstevel@tonic-gate 				type = NULL;
18050Sstevel@tonic-gate 				objsz = U_OFFSET_T;
18060Sstevel@tonic-gate 				laststyle = '=';
18070Sstevel@tonic-gate 				lastpo = 'X';
18080Sstevel@tonic-gate 				continue;
18090Sstevel@tonic-gate 			}
18100Sstevel@tonic-gate 			goto bad_syntax;
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 		case 'u':
18130Sstevel@tonic-gate 			if (colon)
18140Sstevel@tonic-gate 				colon = 0;
18150Sstevel@tonic-gate 			else
18160Sstevel@tonic-gate 				goto no_colon;
18170Sstevel@tonic-gate 			if (match("uid", 1)) {		/* user id */
18180Sstevel@tonic-gate 				acting_on_inode = 1;
18190Sstevel@tonic-gate 				should_print = 1;
18201051Smaheshvs 				addr = (long)&((struct dinode *)
18211051Smaheshvs 						(uintptr_t)cur_ino)->di_uid;
18220Sstevel@tonic-gate 				value = get(SHORT);
18230Sstevel@tonic-gate 				type = NULL;
18240Sstevel@tonic-gate 				continue;
18250Sstevel@tonic-gate 			}
18260Sstevel@tonic-gate 			goto bad_syntax;
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 		case 'F': /* buffer status (internal use only) */
18290Sstevel@tonic-gate 			if (colon)
18300Sstevel@tonic-gate 				colon = 0;
18310Sstevel@tonic-gate 			else
18320Sstevel@tonic-gate 				goto no_colon;
18330Sstevel@tonic-gate 			for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
18340Sstevel@tonic-gate 				printf("%8" PRIx64 " %d\n",
18350Sstevel@tonic-gate 				    bp->blkno, bp->valid);
18360Sstevel@tonic-gate 			printf("\n");
18370Sstevel@tonic-gate 			printf("# commands\t\t%ld\n", commands);
18380Sstevel@tonic-gate 			printf("# read requests\t\t%ld\n", read_requests);
18390Sstevel@tonic-gate 			printf("# actual disk reads\t%ld\n", actual_disk_reads);
18400Sstevel@tonic-gate 			continue;
18410Sstevel@tonic-gate no_colon:
18420Sstevel@tonic-gate 		printf("a colon should precede a command\n");
18430Sstevel@tonic-gate 		error++;
18440Sstevel@tonic-gate 		continue;
18450Sstevel@tonic-gate bad_syntax:
18460Sstevel@tonic-gate 		printf("more letters needed to distinguish command\n");
18470Sstevel@tonic-gate 		error++;
18480Sstevel@tonic-gate 		continue;
18490Sstevel@tonic-gate 		}
18500Sstevel@tonic-gate 	}
18510Sstevel@tonic-gate }
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate /*
18540Sstevel@tonic-gate  * usage - print usage and exit
18550Sstevel@tonic-gate  */
18560Sstevel@tonic-gate static void
usage(char * progname)18571051Smaheshvs usage(char *progname)
18580Sstevel@tonic-gate {
18590Sstevel@tonic-gate 	printf("usage:   %s [options] special\n", progname);
18600Sstevel@tonic-gate 	printf("options:\n");
18610Sstevel@tonic-gate 	printf("\t-o		Specify ufs filesystem sepcific options\n");
18620Sstevel@tonic-gate 	printf("		Available suboptions are:\n");
18630Sstevel@tonic-gate 	printf("\t\t?		display usage\n");
18640Sstevel@tonic-gate 	printf("\t\to		override some error conditions\n");
18650Sstevel@tonic-gate 	printf("\t\tp=\"string\"	set prompt to string\n");
18660Sstevel@tonic-gate 	printf("\t\tw		open for write\n");
18670Sstevel@tonic-gate 	exit(1);
18680Sstevel@tonic-gate }
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate /*
18710Sstevel@tonic-gate  * getachar - get next character from input buffer.
18720Sstevel@tonic-gate  */
18730Sstevel@tonic-gate static char
getachar()18740Sstevel@tonic-gate getachar()
18750Sstevel@tonic-gate {
18760Sstevel@tonic-gate 	return (input_buffer[input_pointer++]);
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate /*
18800Sstevel@tonic-gate  * ungetachar - return character to input buffer.
18810Sstevel@tonic-gate  */
18820Sstevel@tonic-gate static void
ungetachar(char c)18831051Smaheshvs ungetachar(char c)
18840Sstevel@tonic-gate {
18850Sstevel@tonic-gate 	if (input_pointer == 0) {
18860Sstevel@tonic-gate 		printf("internal problem maintaining input buffer\n");
18870Sstevel@tonic-gate 		error++;
18880Sstevel@tonic-gate 		return;
18890Sstevel@tonic-gate 	}
18900Sstevel@tonic-gate 	input_buffer[--input_pointer] = c;
18910Sstevel@tonic-gate }
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate /*
18940Sstevel@tonic-gate  * getnextinput - display the prompt and read an input line.
18950Sstevel@tonic-gate  *	An input line is up to 128 characters terminated by the newline
18960Sstevel@tonic-gate  *	character.  Handle overflow, shell escape, and eof.
18970Sstevel@tonic-gate  */
18980Sstevel@tonic-gate static void
getnextinput()18990Sstevel@tonic-gate getnextinput()
19000Sstevel@tonic-gate {
19011051Smaheshvs 	int	i;
19021051Smaheshvs 	char	c;
19031051Smaheshvs 	short	pid, rpid;
19041051Smaheshvs 	int	retcode;
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate newline:
19070Sstevel@tonic-gate 	i = 0;
19080Sstevel@tonic-gate 	printf("%s", prompt);
19090Sstevel@tonic-gate ignore_eol:
19100Sstevel@tonic-gate 	while ((c = getc(stdin)) != '\n' && !(c == '!' && i == 0) &&
19110Sstevel@tonic-gate 					!feof(stdin) && i <= INPUTBUFFER - 2)
19120Sstevel@tonic-gate 		input_buffer[i++] = c;
19130Sstevel@tonic-gate 	if (i > 0 && input_buffer[i - 1] == '\\') {
19140Sstevel@tonic-gate 		input_buffer[i++] = c;
19150Sstevel@tonic-gate 		goto ignore_eol;
19160Sstevel@tonic-gate 	}
19170Sstevel@tonic-gate 	if (feof(stdin)) {
19180Sstevel@tonic-gate 		printf("\n");
19190Sstevel@tonic-gate 		exit(0);
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate 	if (c == '!') {
19220Sstevel@tonic-gate 		if ((pid = fork()) == 0) {
19230Sstevel@tonic-gate 			(void) execl(_PATH_BSHELL, "sh", "-t", 0);
19240Sstevel@tonic-gate 			error++;
19250Sstevel@tonic-gate 			return;
19260Sstevel@tonic-gate 		}
19270Sstevel@tonic-gate 		while ((rpid = wait(&retcode)) != pid && rpid != -1)
19280Sstevel@tonic-gate 			;
19290Sstevel@tonic-gate 		printf("!\n");
19300Sstevel@tonic-gate 		goto newline;
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate 	if (c != '\n')
19330Sstevel@tonic-gate 		printf("input truncated to 128 characters\n");
19340Sstevel@tonic-gate 	input_buffer[i] = '\n';
19350Sstevel@tonic-gate 	input_pointer = 0;
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate /*
19390Sstevel@tonic-gate  * eat_spaces - read extraneous spaces.
19400Sstevel@tonic-gate  */
19410Sstevel@tonic-gate static void
eat_spaces()19420Sstevel@tonic-gate eat_spaces()
19430Sstevel@tonic-gate {
19441051Smaheshvs 	char	c;
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	while ((c = getachar()) == ' ')
19470Sstevel@tonic-gate 		;
19480Sstevel@tonic-gate 	ungetachar(c);
19490Sstevel@tonic-gate }
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate /*
19520Sstevel@tonic-gate  * restore_inode - set up all inode indicators so inum is now
19530Sstevel@tonic-gate  *	the current inode.
19540Sstevel@tonic-gate  */
19550Sstevel@tonic-gate static void
restore_inode(ino_t inum)19561051Smaheshvs restore_inode(ino_t inum)
19570Sstevel@tonic-gate {
19580Sstevel@tonic-gate 	errinum = cur_inum = inum;
19590Sstevel@tonic-gate 	addr = errino = cur_ino = itob(inum);
19600Sstevel@tonic-gate }
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate /*
19630Sstevel@tonic-gate  * match - return false if the input does not match string up to
19640Sstevel@tonic-gate  *	upto letters.   Then proceed to chew up extraneous letters.
19650Sstevel@tonic-gate  */
19660Sstevel@tonic-gate static int
match(char * string,int upto)19671051Smaheshvs match(char *string, int upto)
19680Sstevel@tonic-gate {
19691051Smaheshvs 	int	i, length = strlen(string) - 1;
19701051Smaheshvs 	char	c;
19711051Smaheshvs 	int	save_upto = upto;
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	while (--upto) {
19740Sstevel@tonic-gate 		string++;
19750Sstevel@tonic-gate 		if ((c = getachar()) != *string) {
19760Sstevel@tonic-gate 			for (i = save_upto - upto; i; i--) {
19770Sstevel@tonic-gate 				ungetachar(c);
19780Sstevel@tonic-gate 				c = *--string;
19790Sstevel@tonic-gate 			}
19800Sstevel@tonic-gate 			return (0);
19810Sstevel@tonic-gate 		}
19820Sstevel@tonic-gate 		length--;
19830Sstevel@tonic-gate 	}
19840Sstevel@tonic-gate 	while (length--) {
19850Sstevel@tonic-gate 		string++;
19860Sstevel@tonic-gate 		if ((c = getachar()) != *string) {
19870Sstevel@tonic-gate 			ungetachar(c);
19880Sstevel@tonic-gate 			return (1);
19890Sstevel@tonic-gate 		}
19900Sstevel@tonic-gate 	}
19910Sstevel@tonic-gate 	return (1);
19920Sstevel@tonic-gate }
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate /*
19950Sstevel@tonic-gate  * expr - expression evaluator.  Will evaluate expressions from
19960Sstevel@tonic-gate  *	left to right with no operator precedence.  Parentheses may
19970Sstevel@tonic-gate  *	be used.
19980Sstevel@tonic-gate  */
19990Sstevel@tonic-gate static long
expr()20000Sstevel@tonic-gate expr()
20010Sstevel@tonic-gate {
20021051Smaheshvs 	long	numb = 0, temp;
20031051Smaheshvs 	char	c;
20040Sstevel@tonic-gate 
20050Sstevel@tonic-gate 	numb = term();
20060Sstevel@tonic-gate 	for (;;) {
20070Sstevel@tonic-gate 		if (error)
20080Sstevel@tonic-gate 			return (~0);	/* error is set so value is ignored */
20090Sstevel@tonic-gate 		c = getachar();
20100Sstevel@tonic-gate 		switch (c) {
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 		case '+':
20130Sstevel@tonic-gate 			numb += term();
20140Sstevel@tonic-gate 			continue;
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate 		case '-':
20170Sstevel@tonic-gate 			numb -= term();
20180Sstevel@tonic-gate 			continue;
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 		case '*':
20210Sstevel@tonic-gate 			numb *= term();
20220Sstevel@tonic-gate 			continue;
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 		case '%':
20250Sstevel@tonic-gate 			temp = term();
20260Sstevel@tonic-gate 			if (!temp) {
20270Sstevel@tonic-gate 				printf("divide by zero\n");
20280Sstevel@tonic-gate 				error++;
20290Sstevel@tonic-gate 				return (~0);
20300Sstevel@tonic-gate 			}
20310Sstevel@tonic-gate 			numb /= temp;
20320Sstevel@tonic-gate 			continue;
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 		case ')':
20350Sstevel@tonic-gate 			paren--;
20360Sstevel@tonic-gate 			return (numb);
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 		default:
20390Sstevel@tonic-gate 			ungetachar(c);
20400Sstevel@tonic-gate 			if (paren && !error) {
20410Sstevel@tonic-gate 				printf("missing ')'\n");
20420Sstevel@tonic-gate 				error++;
20430Sstevel@tonic-gate 			}
20440Sstevel@tonic-gate 			return (numb);
20450Sstevel@tonic-gate 		}
20460Sstevel@tonic-gate 	}
20470Sstevel@tonic-gate }
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate /*
20500Sstevel@tonic-gate  * term - used by expression evaluator to get an operand.
20510Sstevel@tonic-gate  */
20520Sstevel@tonic-gate static long
term()20530Sstevel@tonic-gate term()
20540Sstevel@tonic-gate {
20551051Smaheshvs 	char	c;
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	switch (c = getachar()) {
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 	default:
20600Sstevel@tonic-gate 		ungetachar(c);
20610Sstevel@tonic-gate 		/*FALLTHRU*/
20620Sstevel@tonic-gate 	case '+':
20630Sstevel@tonic-gate 		return (getnumb());
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	case '-':
20660Sstevel@tonic-gate 		return (-getnumb());
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate 	case '(':
20690Sstevel@tonic-gate 		paren++;
20700Sstevel@tonic-gate 		return (expr());
20710Sstevel@tonic-gate 	}
20720Sstevel@tonic-gate }
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate /*
20750Sstevel@tonic-gate  * getnumb - read a number from the input stream.  A leading
20760Sstevel@tonic-gate  *	zero signifies octal interpretation, a leading '0x'
20770Sstevel@tonic-gate  *	signifies hexadecimal, and a leading '0t' signifies
20780Sstevel@tonic-gate  *	decimal.  If the first character is a character,
20790Sstevel@tonic-gate  *	return an error.
20800Sstevel@tonic-gate  */
20810Sstevel@tonic-gate static long
getnumb()20820Sstevel@tonic-gate getnumb()
20830Sstevel@tonic-gate {
20840Sstevel@tonic-gate 
20851051Smaheshvs 	char		c, savec;
20860Sstevel@tonic-gate 	long		number = 0, tbase, num;
20870Sstevel@tonic-gate 	extern short	error;
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 	c = getachar();
20900Sstevel@tonic-gate 	if (!digit(c)) {
20910Sstevel@tonic-gate 		error++;
20920Sstevel@tonic-gate 		ungetachar(c);
20930Sstevel@tonic-gate 		return (-1);
20940Sstevel@tonic-gate 	}
20950Sstevel@tonic-gate 	if (c == '0') {
20960Sstevel@tonic-gate 		tbase = OCTAL;
20970Sstevel@tonic-gate 		if ((c = getachar()) == 'x')
20980Sstevel@tonic-gate 			tbase = HEX;
20990Sstevel@tonic-gate 		else if (c == 't')
21000Sstevel@tonic-gate 			tbase = DECIMAL;
21010Sstevel@tonic-gate 		else ungetachar(c);
21020Sstevel@tonic-gate 	} else {
21030Sstevel@tonic-gate 		tbase = base;
21040Sstevel@tonic-gate 		ungetachar(c);
21050Sstevel@tonic-gate 	}
21060Sstevel@tonic-gate 	for (;;) {
21070Sstevel@tonic-gate 		num = tbase;
21080Sstevel@tonic-gate 		c = savec = getachar();
21090Sstevel@tonic-gate 		if (HEXLETTER(c))
21100Sstevel@tonic-gate 			c = uppertolower(c);
21110Sstevel@tonic-gate 		switch (tbase) {
21120Sstevel@tonic-gate 		case HEX:
21130Sstevel@tonic-gate 			if (hexletter(c)) {
21140Sstevel@tonic-gate 				num = hextodigit(c);
21150Sstevel@tonic-gate 				break;
21160Sstevel@tonic-gate 			}
21170Sstevel@tonic-gate 			/*FALLTHRU*/
21180Sstevel@tonic-gate 		case DECIMAL:
21190Sstevel@tonic-gate 			if (digit(c))
21200Sstevel@tonic-gate 				num = numtodigit(c);
21210Sstevel@tonic-gate 			break;
21220Sstevel@tonic-gate 		case OCTAL:
21230Sstevel@tonic-gate 			if (octaldigit(c))
21240Sstevel@tonic-gate 				num = numtodigit(c);
21250Sstevel@tonic-gate 		}
21260Sstevel@tonic-gate 		if (num == tbase)
21270Sstevel@tonic-gate 			break;
21280Sstevel@tonic-gate 		number = number * tbase + num;
21290Sstevel@tonic-gate 	}
21300Sstevel@tonic-gate 	ungetachar(savec);
21310Sstevel@tonic-gate 	return (number);
21320Sstevel@tonic-gate }
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate /*
21350Sstevel@tonic-gate  * find - the syntax is almost identical to the unix command.
21360Sstevel@tonic-gate  *		find dir [-name pattern] [-inum number]
21370Sstevel@tonic-gate  *	Note:  only one of -name or -inum may be used at a time.
21380Sstevel@tonic-gate  *	       Also, the -print is not needed (implied).
21390Sstevel@tonic-gate  */
21400Sstevel@tonic-gate static void
find()21410Sstevel@tonic-gate find()
21420Sstevel@tonic-gate {
21431051Smaheshvs 	struct filenames	*fn;
21441051Smaheshvs 	char			c;
21451051Smaheshvs 	long			temp;
21461051Smaheshvs 	short			mode;
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 	eat_spaces();
21490Sstevel@tonic-gate 	temp = cur_inum;
21500Sstevel@tonic-gate 	top = filenames - 1;
21510Sstevel@tonic-gate 	doing_cd = 1;
21520Sstevel@tonic-gate 	parse();
21530Sstevel@tonic-gate 	doing_cd = 0;
21540Sstevel@tonic-gate 	if (nfiles != 1) {
21550Sstevel@tonic-gate 		restore_inode((ino_t)temp);
21560Sstevel@tonic-gate 		if (!error) {
21570Sstevel@tonic-gate 			print_path(input_path, (int)input_pathp);
21580Sstevel@tonic-gate 			if (nfiles == 0)
21590Sstevel@tonic-gate 				printf(" not found\n");
21600Sstevel@tonic-gate 			else
21610Sstevel@tonic-gate 				printf(" ambiguous\n");
21620Sstevel@tonic-gate 			error++;
21630Sstevel@tonic-gate 			return;
21640Sstevel@tonic-gate 		}
21650Sstevel@tonic-gate 	}
21660Sstevel@tonic-gate 	restore_inode(filenames->ino);
21670Sstevel@tonic-gate 	freemem(filenames, nfiles);
21680Sstevel@tonic-gate 	nfiles = 0;
21690Sstevel@tonic-gate 	top = filenames - 1;
21700Sstevel@tonic-gate 	if ((mode = icheck(addr)) == 0)
21710Sstevel@tonic-gate 		return;
21720Sstevel@tonic-gate 	if ((mode & IFMT) != IFDIR) {
21730Sstevel@tonic-gate 		print_path(input_path, (int)input_pathp);
21740Sstevel@tonic-gate 		printf(" not a directory\n");
21750Sstevel@tonic-gate 		error++;
21760Sstevel@tonic-gate 		return;
21770Sstevel@tonic-gate 	}
21780Sstevel@tonic-gate 	eat_spaces();
21790Sstevel@tonic-gate 	if ((c = getachar()) != '-') {
21800Sstevel@tonic-gate 		restore_inode((ino_t)temp);
21810Sstevel@tonic-gate 		printf("missing '-'\n");
21820Sstevel@tonic-gate 		error++;
21830Sstevel@tonic-gate 		return;
21840Sstevel@tonic-gate 	}
21850Sstevel@tonic-gate 	find_by_name = find_by_inode = 0;
21860Sstevel@tonic-gate 	c = getachar();
21870Sstevel@tonic-gate 	if (match("name", 4)) {
21880Sstevel@tonic-gate 		eat_spaces();
21890Sstevel@tonic-gate 		find_by_name = 1;
21900Sstevel@tonic-gate 	} else if (match("inum", 4)) {
21910Sstevel@tonic-gate 		eat_spaces();
21920Sstevel@tonic-gate 		find_ino = expr();
21930Sstevel@tonic-gate 		if (error) {
21940Sstevel@tonic-gate 			restore_inode((ino_t)temp);
21950Sstevel@tonic-gate 			return;
21960Sstevel@tonic-gate 		}
21970Sstevel@tonic-gate 		while ((c = getachar()) != '\n')
21980Sstevel@tonic-gate 			;
21990Sstevel@tonic-gate 		ungetachar(c);
22000Sstevel@tonic-gate 		find_by_inode = 1;
22010Sstevel@tonic-gate 	} else {
22020Sstevel@tonic-gate 		restore_inode((ino_t)temp);
22030Sstevel@tonic-gate 		printf("use -name or -inum with find\n");
22040Sstevel@tonic-gate 		error++;
22050Sstevel@tonic-gate 		return;
22060Sstevel@tonic-gate 	}
22070Sstevel@tonic-gate 	doing_find = 1;
22080Sstevel@tonic-gate 	parse();
22090Sstevel@tonic-gate 	doing_find = 0;
22100Sstevel@tonic-gate 	if (error) {
22110Sstevel@tonic-gate 		restore_inode((ino_t)temp);
22120Sstevel@tonic-gate 		return;
22130Sstevel@tonic-gate 	}
22140Sstevel@tonic-gate 	for (fn = filenames; fn <= top; fn++) {
22150Sstevel@tonic-gate 		if (fn->find == 0)
22160Sstevel@tonic-gate 			continue;
22170Sstevel@tonic-gate 		printf("i#: ");
22180Sstevel@tonic-gate 		print(fn->ino, 12, -8, 0);
22190Sstevel@tonic-gate 		print_path(fn->fname, (int)fn->len);
22200Sstevel@tonic-gate 		printf("\n");
22210Sstevel@tonic-gate 	}
22220Sstevel@tonic-gate 	restore_inode((ino_t)temp);
22230Sstevel@tonic-gate }
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate /*
22260Sstevel@tonic-gate  * ls - do an ls.  Should behave exactly as ls(1).
22270Sstevel@tonic-gate  *	Only -R and -l is supported and -l gives different results.
22280Sstevel@tonic-gate  */
22290Sstevel@tonic-gate static void
ls(struct filenames * fn0,struct filenames * fnlast,short level)22301051Smaheshvs ls(struct filenames *fn0, struct filenames *fnlast, short level)
22310Sstevel@tonic-gate {
22321051Smaheshvs 	struct filenames	*fn, *fnn;
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	fn = fn0;
22350Sstevel@tonic-gate 	for (;;) {
22360Sstevel@tonic-gate 		fn0 = fn;
22370Sstevel@tonic-gate 		if (fn0->len) {
22380Sstevel@tonic-gate 			cmp_level = level;
22390Sstevel@tonic-gate 			qsort((char *)fn0, fnlast - fn0 + 1,
22400Sstevel@tonic-gate 				sizeof (struct filenames), fcmp);
22410Sstevel@tonic-gate 		}
22420Sstevel@tonic-gate 		for (fnn = fn, fn++; fn <= fnlast; fnn = fn, fn++) {
22430Sstevel@tonic-gate 			if (fnn->len != fn->len && level == fnn->len - 1)
22440Sstevel@tonic-gate 				break;
22450Sstevel@tonic-gate 			if (fnn->len == 0)
22460Sstevel@tonic-gate 				continue;
22470Sstevel@tonic-gate 			if (strcmp(fn->fname[level], fnn->fname[level]))
22480Sstevel@tonic-gate 				break;
22490Sstevel@tonic-gate 		}
22500Sstevel@tonic-gate 		if (fn0->len && level != fn0->len - 1)
22510Sstevel@tonic-gate 			ls(fn0, fnn, level + 1);
22520Sstevel@tonic-gate 		else {
22530Sstevel@tonic-gate 			if (fn0 != filenames)
22540Sstevel@tonic-gate 				printf("\n");
22550Sstevel@tonic-gate 			print_path(fn0->fname, (int)(fn0->len - 1));
22560Sstevel@tonic-gate 			printf(":\n");
22570Sstevel@tonic-gate 			if (fn0->len == 0)
22580Sstevel@tonic-gate 				cmp_level = level;
22590Sstevel@tonic-gate 			else
22600Sstevel@tonic-gate 				cmp_level = level + 1;
22610Sstevel@tonic-gate 			qsort((char *)fn0, fnn - fn0 + 1,
22620Sstevel@tonic-gate 				sizeof (struct filenames), fcmp);
22630Sstevel@tonic-gate 			formatf(fn0, fnn);
22640Sstevel@tonic-gate 			nfiles -= fnn - fn0 + 1;
22650Sstevel@tonic-gate 		}
22660Sstevel@tonic-gate 		if (fn > fnlast)
22670Sstevel@tonic-gate 			return;
22680Sstevel@tonic-gate 	}
22690Sstevel@tonic-gate }
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate /*
22720Sstevel@tonic-gate  * formatf - code lifted from ls.
22730Sstevel@tonic-gate  */
22740Sstevel@tonic-gate static void
formatf(struct filenames * fn0,struct filenames * fnlast)22751051Smaheshvs formatf(struct filenames *fn0, struct filenames *fnlast)
22760Sstevel@tonic-gate {
22771051Smaheshvs 	struct filenames	*fn;
22781051Smaheshvs 	int			width = 0, w, nentry = fnlast - fn0 + 1;
22791051Smaheshvs 	int			i, j, columns, lines;
22801051Smaheshvs 	char			*cp;
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 	if (long_list) {
22830Sstevel@tonic-gate 		columns = 1;
22840Sstevel@tonic-gate 	} else {
22850Sstevel@tonic-gate 		for (fn = fn0; fn <= fnlast; fn++) {
22860Sstevel@tonic-gate 			int len = strlen(fn->fname[cmp_level]) + 2;
22870Sstevel@tonic-gate 
22880Sstevel@tonic-gate 			if (len > width)
22890Sstevel@tonic-gate 				width = len;
22900Sstevel@tonic-gate 		}
22910Sstevel@tonic-gate 		width = (width + 8) &~ 7;
22920Sstevel@tonic-gate 		columns = 80 / width;
22930Sstevel@tonic-gate 		if (columns == 0)
22940Sstevel@tonic-gate 			columns = 1;
22950Sstevel@tonic-gate 	}
22960Sstevel@tonic-gate 	lines = (nentry + columns - 1) / columns;
22970Sstevel@tonic-gate 	for (i = 0; i < lines; i++) {
22980Sstevel@tonic-gate 		for (j = 0; j < columns; j++) {
22990Sstevel@tonic-gate 			fn = fn0 + j * lines + i;
23000Sstevel@tonic-gate 			if (long_list) {
23010Sstevel@tonic-gate 				printf("i#: ");
23020Sstevel@tonic-gate 				print(fn->ino, 12, -8, 0);
23030Sstevel@tonic-gate 			}
23040Sstevel@tonic-gate 			if ((cp = fmtentry(fn)) == NULL) {
23050Sstevel@tonic-gate 				printf("cannot read inode %ld\n", fn->ino);
23060Sstevel@tonic-gate 				return;
23070Sstevel@tonic-gate 			}
23080Sstevel@tonic-gate 			printf("%s", cp);
23090Sstevel@tonic-gate 			if (fn + lines > fnlast) {
23100Sstevel@tonic-gate 				printf("\n");
23110Sstevel@tonic-gate 				break;
23120Sstevel@tonic-gate 			}
23130Sstevel@tonic-gate 			w = strlen(cp);
23140Sstevel@tonic-gate 			while (w < width) {
23150Sstevel@tonic-gate 				w = (w + 8) &~ 7;
23160Sstevel@tonic-gate 				(void) putchar('\t');
23170Sstevel@tonic-gate 			}
23180Sstevel@tonic-gate 		}
23190Sstevel@tonic-gate 	}
23200Sstevel@tonic-gate }
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate /*
23230Sstevel@tonic-gate  * fmtentry - code lifted from ls.
23240Sstevel@tonic-gate  */
23250Sstevel@tonic-gate static char *
fmtentry(struct filenames * fn)23261051Smaheshvs fmtentry(struct filenames *fn)
23270Sstevel@tonic-gate {
23281051Smaheshvs 	static char	fmtres[BUFSIZ];
23291051Smaheshvs 	struct dinode	*ip;
23301051Smaheshvs 	char		*cptr, *cp, *dp;
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 	dp = &fmtres[0];
23330Sstevel@tonic-gate 	for (cp = fn->fname[cmp_level]; *cp; cp++) {
23340Sstevel@tonic-gate 		if (*cp < ' ' || *cp >= 0177)
23350Sstevel@tonic-gate 			*dp++ = '?';
23360Sstevel@tonic-gate 		else
23370Sstevel@tonic-gate 			*dp++ = *cp;
23380Sstevel@tonic-gate 	}
23390Sstevel@tonic-gate 	addr = itob(fn->ino);
23400Sstevel@tonic-gate 	if ((cptr = getblk(addr)) == 0)
23410Sstevel@tonic-gate 		return (NULL);
23420Sstevel@tonic-gate 	cptr += blkoff(fs, addr);
23430Sstevel@tonic-gate 	/*LINTED*/
23440Sstevel@tonic-gate 	ip = (struct dinode *)cptr;
23450Sstevel@tonic-gate 	switch (ip->di_mode & IFMT) {
23460Sstevel@tonic-gate 	case IFDIR:
23470Sstevel@tonic-gate 		*dp++ = '/';
23480Sstevel@tonic-gate 		break;
23490Sstevel@tonic-gate 	case IFLNK:
23500Sstevel@tonic-gate 		*dp++ = '@';
23510Sstevel@tonic-gate 		break;
23520Sstevel@tonic-gate 	case IFSOCK:
23530Sstevel@tonic-gate 		*dp++ = '=';
23540Sstevel@tonic-gate 		break;
23550Sstevel@tonic-gate #ifdef IFIFO
23560Sstevel@tonic-gate 	case IFIFO:
23570Sstevel@tonic-gate 		*dp++ = 'p';
23580Sstevel@tonic-gate 		break;
23590Sstevel@tonic-gate #endif
23600Sstevel@tonic-gate 	case IFCHR:
23610Sstevel@tonic-gate 	case IFBLK:
23620Sstevel@tonic-gate 	case IFREG:
23630Sstevel@tonic-gate 		if (ip->di_mode & 0111)
23640Sstevel@tonic-gate 			*dp++ = '*';
23650Sstevel@tonic-gate 		else
23660Sstevel@tonic-gate 			*dp++ = ' ';
23670Sstevel@tonic-gate 		break;
23680Sstevel@tonic-gate 	default:
23690Sstevel@tonic-gate 		*dp++ = '?';
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	}
23720Sstevel@tonic-gate 	*dp++ = 0;
23730Sstevel@tonic-gate 	return (fmtres);
23740Sstevel@tonic-gate }
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate /*
23770Sstevel@tonic-gate  * fcmp - routine used by qsort.  Will sort first by name, then
23780Sstevel@tonic-gate  *	then by pathname length if names are equal.  Uses global
23790Sstevel@tonic-gate  *	cmp_level to tell what component of the path name we are comparing.
23800Sstevel@tonic-gate  */
23810Sstevel@tonic-gate static int
fcmp(struct filenames * f1,struct filenames * f2)23821051Smaheshvs fcmp(struct filenames *f1, struct filenames *f2)
23830Sstevel@tonic-gate {
23841051Smaheshvs 	int value;
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	if ((value = strcmp(f1->fname[cmp_level], f2->fname[cmp_level])))
23870Sstevel@tonic-gate 		return (value);
23880Sstevel@tonic-gate 	return (f1->len - f2->len);
23890Sstevel@tonic-gate }
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate /*
23920Sstevel@tonic-gate  * ffcmp - routine used by qsort.  Sort only by pathname length.
23930Sstevel@tonic-gate  */
23940Sstevel@tonic-gate static int
ffcmp(struct filenames * f1,struct filenames * f2)23951051Smaheshvs ffcmp(struct filenames *f1, struct filenames *f2)
23960Sstevel@tonic-gate {
23970Sstevel@tonic-gate 	return (f1->len - f2->len);
23980Sstevel@tonic-gate }
23990Sstevel@tonic-gate 
24000Sstevel@tonic-gate /*
24010Sstevel@tonic-gate  * parse - set up the call to follow_path.
24020Sstevel@tonic-gate  */
24030Sstevel@tonic-gate static void
parse()24040Sstevel@tonic-gate parse()
24050Sstevel@tonic-gate {
24061051Smaheshvs 	int	i;
24071051Smaheshvs 	char	c;
24080Sstevel@tonic-gate 
24090Sstevel@tonic-gate 	stack_pathp = input_pathp = -1;
24100Sstevel@tonic-gate 	if ((c = getachar()) == '/') {
24110Sstevel@tonic-gate 		while ((c = getachar()) == '/')
24120Sstevel@tonic-gate 			;
24130Sstevel@tonic-gate 		ungetachar(c);
24140Sstevel@tonic-gate 		cur_inum = 2;
24150Sstevel@tonic-gate 		c = getachar();
24160Sstevel@tonic-gate 		if ((c == '\n') || ((doing_cd) && (c == ' '))) {
24170Sstevel@tonic-gate 			ungetachar(c);
24180Sstevel@tonic-gate 			if (doing_cd) {
24190Sstevel@tonic-gate 				top++;
24200Sstevel@tonic-gate 				top->ino = 2;
24210Sstevel@tonic-gate 				top->len = -1;
24220Sstevel@tonic-gate 				nfiles = 1;
24230Sstevel@tonic-gate 				return;
24240Sstevel@tonic-gate 			}
24250Sstevel@tonic-gate 		} else
24260Sstevel@tonic-gate 			ungetachar(c);
24270Sstevel@tonic-gate 	} else {
24280Sstevel@tonic-gate 		ungetachar(c);
24290Sstevel@tonic-gate 		stack_pathp = current_pathp;
24300Sstevel@tonic-gate 		if (!doing_find)
24310Sstevel@tonic-gate 			input_pathp = current_pathp;
24320Sstevel@tonic-gate 		for (i = 0; i <= current_pathp; i++) {
24330Sstevel@tonic-gate 			if (!doing_find)
24340Sstevel@tonic-gate 				(void) strcpy(input_path[i], current_path[i]);
24350Sstevel@tonic-gate 			(void) strcpy(stack_path[i], current_path[i]);
24360Sstevel@tonic-gate 		}
24370Sstevel@tonic-gate 	}
24380Sstevel@tonic-gate 	getname();
24390Sstevel@tonic-gate 	follow_path((long)(stack_pathp + 1), cur_inum);
24400Sstevel@tonic-gate }
24410Sstevel@tonic-gate 
24420Sstevel@tonic-gate /*
24430Sstevel@tonic-gate  * follow_path - called by cd, find, and ls.
24440Sstevel@tonic-gate  *	input_path holds the name typed by the user.
24450Sstevel@tonic-gate  *	stack_path holds the name at the current depth.
24460Sstevel@tonic-gate  */
24470Sstevel@tonic-gate static void
follow_path(long level,long inum)24481051Smaheshvs follow_path(long level, long inum)
24490Sstevel@tonic-gate {
24501051Smaheshvs 	struct direct		*dirp;
24511051Smaheshvs 	char			**ccptr, *cptr;
24521051Smaheshvs 	int			i;
24530Sstevel@tonic-gate 	struct filenames	*tos, *bos, *fn, *fnn, *fnnn;
24540Sstevel@tonic-gate 	long			block;
24550Sstevel@tonic-gate 	short			mode;
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	tos = top + 1;
24580Sstevel@tonic-gate 	restore_inode((ino_t)inum);
24590Sstevel@tonic-gate 	if ((mode = icheck(addr)) == 0)
24600Sstevel@tonic-gate 		return;
24610Sstevel@tonic-gate 	if ((mode & IFMT) != IFDIR)
24620Sstevel@tonic-gate 	    return;
24630Sstevel@tonic-gate 	block = cur_bytes = 0;
24640Sstevel@tonic-gate 	while (cur_bytes < filesize) {
24650Sstevel@tonic-gate 	    if (block == 0 || bcomp(addr)) {
24660Sstevel@tonic-gate 		error = 0;
24670Sstevel@tonic-gate 		if ((addr = ((u_offset_t)bmap(block++) <<
24680Sstevel@tonic-gate 				(u_offset_t)FRGSHIFT)) == 0)
24690Sstevel@tonic-gate 		    break;
24700Sstevel@tonic-gate 		if ((cptr = getblk(addr)) == 0)
24710Sstevel@tonic-gate 		    break;
24720Sstevel@tonic-gate 		cptr += blkoff(fs, addr);
24730Sstevel@tonic-gate 	    }
24740Sstevel@tonic-gate 		/*LINTED*/
24750Sstevel@tonic-gate 	    dirp = (struct direct *)cptr;
24760Sstevel@tonic-gate 	    if (dirp->d_ino) {
24770Sstevel@tonic-gate 		if (level > input_pathp || doing_find ||
24780Sstevel@tonic-gate 			compare(input_path[level], &dirp->d_name[0], 1)) {
24790Sstevel@tonic-gate 		    if ((doing_find) &&
24800Sstevel@tonic-gate 			((strcmp(dirp->d_name, ".") == 0 ||
24810Sstevel@tonic-gate 					strcmp(dirp->d_name, "..") == 0)))
24820Sstevel@tonic-gate 			goto duplicate;
24830Sstevel@tonic-gate 		    if (++top - filenames >= maxfiles) {
24840Sstevel@tonic-gate 			printf("too many files\n");
24850Sstevel@tonic-gate 			error++;
24860Sstevel@tonic-gate 			return;
24870Sstevel@tonic-gate 		    }
24880Sstevel@tonic-gate 		    top->fname = (char **)calloc(FIRST_DEPTH, sizeof (char **));
24890Sstevel@tonic-gate 		    top->flag = 0;
24900Sstevel@tonic-gate 		    if (top->fname == 0) {
24910Sstevel@tonic-gate 			printf("out of memory\n");
24920Sstevel@tonic-gate 			error++;
24930Sstevel@tonic-gate 			return;
24940Sstevel@tonic-gate 		    }
24950Sstevel@tonic-gate 		    nfiles++;
24960Sstevel@tonic-gate 		    top->ino = dirp->d_ino;
24970Sstevel@tonic-gate 		    top->len = stack_pathp;
24980Sstevel@tonic-gate 		    top->find = 0;
24990Sstevel@tonic-gate 		    if (doing_find) {
25000Sstevel@tonic-gate 			if (find_by_name) {
25010Sstevel@tonic-gate 			    if (compare(input_path[0], &dirp->d_name[0], 1))
25020Sstevel@tonic-gate 				top->find = 1;
25030Sstevel@tonic-gate 			} else if (find_by_inode)
25040Sstevel@tonic-gate 			    if (find_ino == dirp->d_ino)
25050Sstevel@tonic-gate 				top->find = 1;
25060Sstevel@tonic-gate 		    }
25070Sstevel@tonic-gate 		    if (top->len + 1 >= FIRST_DEPTH && top->flag == 0) {
25080Sstevel@tonic-gate 			ccptr = (char **)calloc(SECOND_DEPTH, sizeof (char **));
25090Sstevel@tonic-gate 			if (ccptr == 0) {
25100Sstevel@tonic-gate 			    printf("out of memory\n");
25110Sstevel@tonic-gate 			    error++;
25120Sstevel@tonic-gate 			    return;
25130Sstevel@tonic-gate 			}
25140Sstevel@tonic-gate 			for (i = 0; i < FIRST_DEPTH; i++)
25150Sstevel@tonic-gate 				ccptr[i] = top->fname[i];
25160Sstevel@tonic-gate 			free((char *)top->fname);
25170Sstevel@tonic-gate 			top->fname = ccptr;
25180Sstevel@tonic-gate 			top->flag = 1;
25190Sstevel@tonic-gate 		    }
25200Sstevel@tonic-gate 		    if (top->len >= SECOND_DEPTH) {
25210Sstevel@tonic-gate 			printf("maximum depth exceeded, try to cd lower\n");
25220Sstevel@tonic-gate 			error++;
25230Sstevel@tonic-gate 			return;
25240Sstevel@tonic-gate 		    }
25250Sstevel@tonic-gate 			/*
25260Sstevel@tonic-gate 			 * Copy current depth.
25270Sstevel@tonic-gate 			 */
25280Sstevel@tonic-gate 		    for (i = 0; i <= stack_pathp; i++) {
25290Sstevel@tonic-gate 			top->fname[i] = calloc(1, strlen(stack_path[i])+1);
25300Sstevel@tonic-gate 			if (top->fname[i] == 0) {
25310Sstevel@tonic-gate 			    printf("out of memory\n");
25320Sstevel@tonic-gate 			    error++;
25330Sstevel@tonic-gate 			    return;
25340Sstevel@tonic-gate 			}
25350Sstevel@tonic-gate 			(void) strcpy(top->fname[i], stack_path[i]);
25360Sstevel@tonic-gate 		    }
25370Sstevel@tonic-gate 			/*
25380Sstevel@tonic-gate 			 * Check for '.' or '..' typed.
25390Sstevel@tonic-gate 			 */
25400Sstevel@tonic-gate 		    if ((level <= input_pathp) &&
25410Sstevel@tonic-gate 				(strcmp(input_path[level], ".") == 0 ||
25420Sstevel@tonic-gate 					strcmp(input_path[level], "..") == 0)) {
25430Sstevel@tonic-gate 			if (strcmp(input_path[level], "..") == 0 &&
25440Sstevel@tonic-gate 							top->len >= 0) {
25450Sstevel@tonic-gate 			    free(top->fname[top->len]);
25460Sstevel@tonic-gate 			    top->len -= 1;
25470Sstevel@tonic-gate 			}
25480Sstevel@tonic-gate 		    } else {
25490Sstevel@tonic-gate 			/*
25500Sstevel@tonic-gate 			 * Check for duplicates.
25510Sstevel@tonic-gate 			 */
25520Sstevel@tonic-gate 			if (!doing_cd && !doing_find) {
25530Sstevel@tonic-gate 			    for (fn = filenames; fn < top; fn++) {
25540Sstevel@tonic-gate 				if (fn->ino == dirp->d_ino &&
25550Sstevel@tonic-gate 					    fn->len == stack_pathp + 1) {
25560Sstevel@tonic-gate 				    for (i = 0; i < fn->len; i++)
25570Sstevel@tonic-gate 					if (strcmp(fn->fname[i], stack_path[i]))
25580Sstevel@tonic-gate 					    break;
25590Sstevel@tonic-gate 				    if (i != fn->len ||
25600Sstevel@tonic-gate 					    strcmp(fn->fname[i], dirp->d_name))
25610Sstevel@tonic-gate 					continue;
25620Sstevel@tonic-gate 				    freemem(top, 1);
25630Sstevel@tonic-gate 				    if (top == filenames)
25640Sstevel@tonic-gate 					top = NULL;
25650Sstevel@tonic-gate 				    else
25660Sstevel@tonic-gate 					top--;
25670Sstevel@tonic-gate 					nfiles--;
25680Sstevel@tonic-gate 					goto duplicate;
25690Sstevel@tonic-gate 				}
25700Sstevel@tonic-gate 			    }
25710Sstevel@tonic-gate 			}
25720Sstevel@tonic-gate 			top->len += 1;
25730Sstevel@tonic-gate 			top->fname[top->len] = calloc(1,
25740Sstevel@tonic-gate 						strlen(&dirp->d_name[0])+1);
25750Sstevel@tonic-gate 			if (top->fname[top->len] == 0) {
25760Sstevel@tonic-gate 			    printf("out of memory\n");
25770Sstevel@tonic-gate 			    error++;
25780Sstevel@tonic-gate 			    return;
25790Sstevel@tonic-gate 			}
25800Sstevel@tonic-gate 			(void) strcpy(top->fname[top->len], &dirp->d_name[0]);
25810Sstevel@tonic-gate 		    }
25820Sstevel@tonic-gate 		}
25830Sstevel@tonic-gate 	    }
25840Sstevel@tonic-gate duplicate:
25850Sstevel@tonic-gate 	    addr += dirp->d_reclen;
25860Sstevel@tonic-gate 	    cptr += dirp->d_reclen;
25870Sstevel@tonic-gate 	    cur_bytes += dirp->d_reclen;
25880Sstevel@tonic-gate 	}
25890Sstevel@tonic-gate 	if (top < filenames)
25900Sstevel@tonic-gate 	    return;
25910Sstevel@tonic-gate 	if ((doing_cd && level == input_pathp) ||
25920Sstevel@tonic-gate 		(!recursive && !doing_find && level > input_pathp))
25930Sstevel@tonic-gate 	    return;
25940Sstevel@tonic-gate 	bos = top;
25950Sstevel@tonic-gate 	/*
25960Sstevel@tonic-gate 	 * Check newly added entries to determine if further expansion
25970Sstevel@tonic-gate 	 * is required.
25980Sstevel@tonic-gate 	 */
25990Sstevel@tonic-gate 	for (fn = tos; fn <= bos; fn++) {
26000Sstevel@tonic-gate 		/*
26010Sstevel@tonic-gate 		 * Avoid '.' and '..' if beyond input.
26020Sstevel@tonic-gate 		 */
26030Sstevel@tonic-gate 	    if ((recursive || doing_find) && (level > input_pathp) &&
26040Sstevel@tonic-gate 		(strcmp(fn->fname[fn->len], ".") == 0 ||
26050Sstevel@tonic-gate 			strcmp(fn->fname[fn->len], "..") == 0))
26060Sstevel@tonic-gate 		continue;
26070Sstevel@tonic-gate 	    restore_inode(fn->ino);
26080Sstevel@tonic-gate 	    if ((mode = icheck(cur_ino)) == 0)
26090Sstevel@tonic-gate 		return;
26100Sstevel@tonic-gate 	    if ((mode & IFMT) == IFDIR || level < input_pathp) {
26110Sstevel@tonic-gate 		/*
26120Sstevel@tonic-gate 		 * Set up current depth, remove current entry and
26130Sstevel@tonic-gate 		 * continue recursion.
26140Sstevel@tonic-gate 		 */
26150Sstevel@tonic-gate 		for (i = 0; i <= fn->len; i++)
26160Sstevel@tonic-gate 		    (void) strcpy(stack_path[i], fn->fname[i]);
26170Sstevel@tonic-gate 		stack_pathp = fn->len;
26180Sstevel@tonic-gate 		if (!doing_find &&
26190Sstevel@tonic-gate 			(!recursive || (recursive && level <= input_pathp))) {
26200Sstevel@tonic-gate 			/*
26210Sstevel@tonic-gate 			 * Remove current entry by moving others up.
26220Sstevel@tonic-gate 			 */
26230Sstevel@tonic-gate 		    freemem(fn, 1);
26240Sstevel@tonic-gate 		    fnn = fn;
26250Sstevel@tonic-gate 		    for (fnnn = fnn, fnn++; fnn <= top; fnnn = fnn, fnn++) {
26260Sstevel@tonic-gate 			fnnn->ino = fnn->ino;
26270Sstevel@tonic-gate 			fnnn->len = fnn->len;
26280Sstevel@tonic-gate 			if (fnnn->len + 1 < FIRST_DEPTH) {
26290Sstevel@tonic-gate 			    fnnn->fname = (char **)calloc(FIRST_DEPTH,
26300Sstevel@tonic-gate 							sizeof (char **));
26310Sstevel@tonic-gate 			    fnnn->flag = 0;
26320Sstevel@tonic-gate 			} else if (fnnn->len < SECOND_DEPTH) {
26330Sstevel@tonic-gate 			    fnnn->fname = (char **)calloc(SECOND_DEPTH,
26340Sstevel@tonic-gate 							sizeof (char **));
26350Sstevel@tonic-gate 			    fnnn->flag = 1;
26360Sstevel@tonic-gate 			} else {
26370Sstevel@tonic-gate 			    printf("maximum depth exceeded, ");
26380Sstevel@tonic-gate 			    printf("try to cd lower\n");
26390Sstevel@tonic-gate 			    error++;
26400Sstevel@tonic-gate 			    return;
26410Sstevel@tonic-gate 			}
26420Sstevel@tonic-gate 			for (i = 0; i <= fnn->len; i++)
26430Sstevel@tonic-gate 			    fnnn->fname[i] = fnn->fname[i];
26440Sstevel@tonic-gate 		    }
26450Sstevel@tonic-gate 		    if (fn == tos)
26460Sstevel@tonic-gate 			fn--;
26470Sstevel@tonic-gate 		    top--;
26480Sstevel@tonic-gate 		    bos--;
26490Sstevel@tonic-gate 		    nfiles--;
26500Sstevel@tonic-gate 		}
26510Sstevel@tonic-gate 		follow_path(level + 1, cur_inum);
26520Sstevel@tonic-gate 		if (error)
26530Sstevel@tonic-gate 			return;
26540Sstevel@tonic-gate 	    }
26550Sstevel@tonic-gate 	}
26560Sstevel@tonic-gate }
26570Sstevel@tonic-gate 
26580Sstevel@tonic-gate /*
26590Sstevel@tonic-gate  * getname - break up the pathname entered by the user into components.
26600Sstevel@tonic-gate  */
26610Sstevel@tonic-gate static void
getname()26620Sstevel@tonic-gate getname()
26630Sstevel@tonic-gate {
26641051Smaheshvs 	int	i;
26651051Smaheshvs 	char	c;
26660Sstevel@tonic-gate 
26670Sstevel@tonic-gate 	if ((c = getachar()) == '\n') {
26680Sstevel@tonic-gate 	    ungetachar(c);
26690Sstevel@tonic-gate 	    return;
26700Sstevel@tonic-gate 	}
26710Sstevel@tonic-gate 	ungetachar(c);
26720Sstevel@tonic-gate 	input_pathp++;
26730Sstevel@tonic-gate clear:
26740Sstevel@tonic-gate 	for (i = 0; i < MAXNAMLEN; i++)
26750Sstevel@tonic-gate 	    input_path[input_pathp][i] = '\0';
26760Sstevel@tonic-gate 	for (;;) {
26770Sstevel@tonic-gate 	    c = getachar();
26780Sstevel@tonic-gate 	    if (c == '\\') {
26790Sstevel@tonic-gate 		if ((int)strlen(input_path[input_pathp]) + 1 >= MAXNAMLEN) {
26800Sstevel@tonic-gate 		    printf("maximum name length exceeded, ");
26810Sstevel@tonic-gate 		    printf("truncating\n");
26820Sstevel@tonic-gate 		    return;
26830Sstevel@tonic-gate 		}
26840Sstevel@tonic-gate 		input_path[input_pathp][strlen(input_path[input_pathp])] = c;
26850Sstevel@tonic-gate 		input_path[input_pathp][strlen(input_path[input_pathp])] =
26860Sstevel@tonic-gate 						getachar();
26870Sstevel@tonic-gate 		continue;
26880Sstevel@tonic-gate 	    }
26890Sstevel@tonic-gate 	    if (c == ' ' || c == '\n') {
26900Sstevel@tonic-gate 		ungetachar(c);
26910Sstevel@tonic-gate 		return;
26920Sstevel@tonic-gate 	    }
26930Sstevel@tonic-gate 	    if (!doing_find && c == '/') {
26940Sstevel@tonic-gate 		if (++input_pathp >= MAXPATHLEN) {
26950Sstevel@tonic-gate 		    printf("maximum path length exceeded, ");
26960Sstevel@tonic-gate 		    printf("truncating\n");
26970Sstevel@tonic-gate 		    input_pathp--;
26980Sstevel@tonic-gate 		    return;
26990Sstevel@tonic-gate 		}
27000Sstevel@tonic-gate 		goto clear;
27010Sstevel@tonic-gate 	    }
27020Sstevel@tonic-gate 	    if ((int)strlen(input_path[input_pathp]) >= MAXNAMLEN) {
27030Sstevel@tonic-gate 		printf("maximum name length exceeded, truncating\n");
27040Sstevel@tonic-gate 		return;
27050Sstevel@tonic-gate 	    }
27060Sstevel@tonic-gate 	    input_path[input_pathp][strlen(input_path[input_pathp])] = c;
27070Sstevel@tonic-gate 	}
27080Sstevel@tonic-gate }
27090Sstevel@tonic-gate 
27100Sstevel@tonic-gate /*
27110Sstevel@tonic-gate  * compare - check if a filename matches the pattern entered by the user.
27120Sstevel@tonic-gate  *	Handles '*', '?', and '[]'.
27130Sstevel@tonic-gate  */
27140Sstevel@tonic-gate static int
compare(char * s1,char * s2,short at_start)27151051Smaheshvs compare(char *s1, char *s2, short at_start)
27160Sstevel@tonic-gate {
27171051Smaheshvs 	char	c, *s;
27180Sstevel@tonic-gate 
27190Sstevel@tonic-gate 	s = s2;
27200Sstevel@tonic-gate 	while ((c = *s1) != NULL) {
27210Sstevel@tonic-gate 		if (c == '*') {
27220Sstevel@tonic-gate 			if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
27230Sstevel@tonic-gate 				return (0);
27240Sstevel@tonic-gate 			if (*++s1 == 0)
27250Sstevel@tonic-gate 				return (1);
27260Sstevel@tonic-gate 			while (*s2) {
27270Sstevel@tonic-gate 				if (compare(s1, s2, 0))
27280Sstevel@tonic-gate 					return (1);
27290Sstevel@tonic-gate 				if (error)
27300Sstevel@tonic-gate 					return (0);
27310Sstevel@tonic-gate 				s2++;
27320Sstevel@tonic-gate 			}
27330Sstevel@tonic-gate 		}
27340Sstevel@tonic-gate 		if (*s2 == 0)
27350Sstevel@tonic-gate 			return (0);
27360Sstevel@tonic-gate 		if (c == '\\') {
27370Sstevel@tonic-gate 			s1++;
27380Sstevel@tonic-gate 			goto compare_chars;
27390Sstevel@tonic-gate 		}
27400Sstevel@tonic-gate 		if (c == '?') {
27410Sstevel@tonic-gate 			if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
27420Sstevel@tonic-gate 				return (0);
27430Sstevel@tonic-gate 			s1++;
27440Sstevel@tonic-gate 			s2++;
27450Sstevel@tonic-gate 			continue;
27460Sstevel@tonic-gate 		}
27470Sstevel@tonic-gate 		if (c == '[') {
27480Sstevel@tonic-gate 			s1++;
27490Sstevel@tonic-gate 			if (*s2 >= *s1++) {
27500Sstevel@tonic-gate 				if (*s1++ != '-') {
27510Sstevel@tonic-gate 					printf("missing '-'\n");
27520Sstevel@tonic-gate 					error++;
27530Sstevel@tonic-gate 					return (0);
27540Sstevel@tonic-gate 				}
27550Sstevel@tonic-gate 				if (*s2 <= *s1++) {
27560Sstevel@tonic-gate 					if (*s1++ != ']') {
27570Sstevel@tonic-gate 						printf("missing ']'");
27580Sstevel@tonic-gate 						error++;
27590Sstevel@tonic-gate 						return (0);
27600Sstevel@tonic-gate 					}
27610Sstevel@tonic-gate 					s2++;
27620Sstevel@tonic-gate 					continue;
27630Sstevel@tonic-gate 				}
27640Sstevel@tonic-gate 			}
27650Sstevel@tonic-gate 		}
27660Sstevel@tonic-gate compare_chars:
27670Sstevel@tonic-gate 		if (*s1++ == *s2++)
27680Sstevel@tonic-gate 			continue;
27690Sstevel@tonic-gate 		else
27700Sstevel@tonic-gate 			return (0);
27710Sstevel@tonic-gate 	}
27720Sstevel@tonic-gate 	if (*s1 == *s2)
27730Sstevel@tonic-gate 		return (1);
27740Sstevel@tonic-gate 	return (0);
27750Sstevel@tonic-gate }
27760Sstevel@tonic-gate 
27770Sstevel@tonic-gate /*
27780Sstevel@tonic-gate  * freemem - free the memory allocated to the filenames structure.
27790Sstevel@tonic-gate  */
27800Sstevel@tonic-gate static void
freemem(struct filenames * p,int numb)27811051Smaheshvs freemem(struct filenames *p, int numb)
27820Sstevel@tonic-gate {
27831051Smaheshvs 	int	i, j;
27840Sstevel@tonic-gate 
27850Sstevel@tonic-gate 	if (numb == 0)
27860Sstevel@tonic-gate 		return;
27870Sstevel@tonic-gate 	for (i = 0; i < numb; i++, p++) {
27880Sstevel@tonic-gate 		for (j = 0; j <= p->len; j++)
27890Sstevel@tonic-gate 			free(p->fname[j]);
27900Sstevel@tonic-gate 		free((char *)p->fname);
27910Sstevel@tonic-gate 	}
27920Sstevel@tonic-gate }
27930Sstevel@tonic-gate 
27940Sstevel@tonic-gate /*
27950Sstevel@tonic-gate  * print_path - print the pathname held in p.
27960Sstevel@tonic-gate  */
27970Sstevel@tonic-gate static void
print_path(char * p[],int pntr)27981051Smaheshvs print_path(char *p[], int pntr)
27990Sstevel@tonic-gate {
28001051Smaheshvs 	int	i;
28010Sstevel@tonic-gate 
28020Sstevel@tonic-gate 	printf("/");
28030Sstevel@tonic-gate 	if (pntr >= 0) {
28040Sstevel@tonic-gate 		for (i = 0; i < pntr; i++)
28050Sstevel@tonic-gate 			printf("%s/", p[i]);
28060Sstevel@tonic-gate 		printf("%s", p[pntr]);
28070Sstevel@tonic-gate 	}
28080Sstevel@tonic-gate }
28090Sstevel@tonic-gate 
28100Sstevel@tonic-gate /*
28110Sstevel@tonic-gate  * fill - fill a section with a value or string.
28120Sstevel@tonic-gate  *	addr,count:fill=[value, "string"].
28130Sstevel@tonic-gate  */
28140Sstevel@tonic-gate static void
fill()28150Sstevel@tonic-gate fill()
28160Sstevel@tonic-gate {
28171051Smaheshvs 	char		*cptr;
28181051Smaheshvs 	int		i;
28190Sstevel@tonic-gate 	short		eof_flag, end = 0, eof = 0;
28200Sstevel@tonic-gate 	long		temp, tcount;
28210Sstevel@tonic-gate 	u_offset_t	taddr;
28220Sstevel@tonic-gate 
28230Sstevel@tonic-gate 	if (wrtflag == O_RDONLY) {
28240Sstevel@tonic-gate 		printf("not opened for write '-w'\n");
28250Sstevel@tonic-gate 		error++;
28260Sstevel@tonic-gate 		return;
28270Sstevel@tonic-gate 	}
28280Sstevel@tonic-gate 	temp = expr();
28290Sstevel@tonic-gate 	if (error)
28300Sstevel@tonic-gate 		return;
28310Sstevel@tonic-gate 	if ((cptr = getblk(addr)) == 0)
28320Sstevel@tonic-gate 		return;
28330Sstevel@tonic-gate 	if (type == NUMB)
28340Sstevel@tonic-gate 		eof_flag = 0;
28350Sstevel@tonic-gate 	else
28360Sstevel@tonic-gate 		eof_flag = 1;
28370Sstevel@tonic-gate 	taddr = addr;
28380Sstevel@tonic-gate 	switch (objsz) {
28390Sstevel@tonic-gate 	case LONG:
28400Sstevel@tonic-gate 		addr &= ~(LONG - 1);
28410Sstevel@tonic-gate 		break;
28420Sstevel@tonic-gate 	case SHORT:
28430Sstevel@tonic-gate 		addr &= ~(SHORT - 1);
28440Sstevel@tonic-gate 		temp &= 0177777L;
28450Sstevel@tonic-gate 		break;
28460Sstevel@tonic-gate 	case CHAR:
28470Sstevel@tonic-gate 		temp &= 0377;
28480Sstevel@tonic-gate 	}
28490Sstevel@tonic-gate 	cur_bytes -= taddr - addr;
28500Sstevel@tonic-gate 	cptr += blkoff(fs, addr);
28510Sstevel@tonic-gate 	tcount = check_addr(eof_flag, &end, &eof, 0);
28520Sstevel@tonic-gate 	for (i = 0; i < tcount; i++) {
28530Sstevel@tonic-gate 		switch (objsz) {
28540Sstevel@tonic-gate 		case LONG:
28550Sstevel@tonic-gate 			/*LINTED*/
28560Sstevel@tonic-gate 			*(long *)cptr = temp;
28570Sstevel@tonic-gate 			break;
28580Sstevel@tonic-gate 		case SHORT:
28590Sstevel@tonic-gate 			/*LINTED*/
28600Sstevel@tonic-gate 			*(short *)cptr = temp;
28610Sstevel@tonic-gate 			break;
28620Sstevel@tonic-gate 		case CHAR:
28630Sstevel@tonic-gate 			*cptr = temp;
28640Sstevel@tonic-gate 		}
28650Sstevel@tonic-gate 		cptr += objsz;
28660Sstevel@tonic-gate 	}
28670Sstevel@tonic-gate 	addr += (tcount - 1) * objsz;
28680Sstevel@tonic-gate 	cur_bytes += (tcount - 1) * objsz;
28690Sstevel@tonic-gate 	put((u_offset_t)temp, objsz);
28700Sstevel@tonic-gate 	if (eof) {
28710Sstevel@tonic-gate 		printf("end of file\n");
28720Sstevel@tonic-gate 		error++;
28730Sstevel@tonic-gate 	} else if (end) {
28740Sstevel@tonic-gate 		printf("end of block\n");
28750Sstevel@tonic-gate 		error++;
28760Sstevel@tonic-gate 	}
28770Sstevel@tonic-gate }
28780Sstevel@tonic-gate 
28790Sstevel@tonic-gate /*
28800Sstevel@tonic-gate  * get - read a byte, short or long from the file system.
28810Sstevel@tonic-gate  *	The entire block containing the desired item is read
28820Sstevel@tonic-gate  *	and the appropriate data is extracted and returned.
28830Sstevel@tonic-gate  */
28840Sstevel@tonic-gate static offset_t
get(short lngth)28851051Smaheshvs get(short lngth)
28860Sstevel@tonic-gate {
28870Sstevel@tonic-gate 
28881051Smaheshvs 	char		*bptr;
28890Sstevel@tonic-gate 	u_offset_t	temp = addr;
28900Sstevel@tonic-gate 
28910Sstevel@tonic-gate 	objsz = lngth;
28920Sstevel@tonic-gate 	if (objsz == INODE || objsz == SHORT)
28930Sstevel@tonic-gate 		temp &= ~(SHORT - 1);
28940Sstevel@tonic-gate 	else if (objsz == DIRECTORY || objsz == LONG || objsz == SHADOW_DATA)
28950Sstevel@tonic-gate 		temp &= ~(LONG - 1);
28960Sstevel@tonic-gate 	if ((bptr = getblk(temp)) == 0)
28970Sstevel@tonic-gate 		return (-1);
28980Sstevel@tonic-gate 	bptr += blkoff(fs, temp);
28990Sstevel@tonic-gate 	switch (objsz) {
29000Sstevel@tonic-gate 	case CHAR:
29010Sstevel@tonic-gate 		return ((offset_t)*bptr);
29020Sstevel@tonic-gate 	case SHORT:
29030Sstevel@tonic-gate 	case INODE:
29040Sstevel@tonic-gate 		/*LINTED*/
29050Sstevel@tonic-gate 		return ((offset_t)(*(short *)bptr));
29060Sstevel@tonic-gate 	case LONG:
29070Sstevel@tonic-gate 	case DIRECTORY:
29080Sstevel@tonic-gate 	case SHADOW_DATA:
29090Sstevel@tonic-gate 		/*LINTED*/
29100Sstevel@tonic-gate 		return ((offset_t)(*(long *)bptr));
29110Sstevel@tonic-gate 	case U_OFFSET_T:
29120Sstevel@tonic-gate 		/*LINTED*/
29130Sstevel@tonic-gate 		return (*(offset_t *)bptr);
29140Sstevel@tonic-gate 	}
29150Sstevel@tonic-gate 	return (0);
29160Sstevel@tonic-gate }
29170Sstevel@tonic-gate 
29180Sstevel@tonic-gate /*
29190Sstevel@tonic-gate  * cgrp_check - make sure that we don't bump the cylinder group
29200Sstevel@tonic-gate  *	beyond the total number of cylinder groups or before the start.
29210Sstevel@tonic-gate  */
29220Sstevel@tonic-gate static int
cgrp_check(long cgrp)29231051Smaheshvs cgrp_check(long cgrp)
29240Sstevel@tonic-gate {
29250Sstevel@tonic-gate 	if (cgrp < 0) {
29260Sstevel@tonic-gate 		if (objsz == CGRP)
29270Sstevel@tonic-gate 			printf("beginning of cylinder groups\n");
29280Sstevel@tonic-gate 		else
29290Sstevel@tonic-gate 			printf("beginning of super blocks\n");
29300Sstevel@tonic-gate 		error++;
29310Sstevel@tonic-gate 		return (0);
29320Sstevel@tonic-gate 	}
29330Sstevel@tonic-gate 	if (cgrp >= fs->fs_ncg) {
29340Sstevel@tonic-gate 		if (objsz == CGRP)
29350Sstevel@tonic-gate 			printf("end of cylinder groups\n");
29360Sstevel@tonic-gate 		else
29370Sstevel@tonic-gate 			printf("end of super blocks\n");
29380Sstevel@tonic-gate 		error++;
29390Sstevel@tonic-gate 		return (0);
29400Sstevel@tonic-gate 	}
29410Sstevel@tonic-gate 	if (objsz == CGRP)
29420Sstevel@tonic-gate 		return (cgtod(fs, cgrp) << FRGSHIFT);
29430Sstevel@tonic-gate 	else
29440Sstevel@tonic-gate 		return (cgsblock(fs, cgrp) << FRGSHIFT);
29450Sstevel@tonic-gate }
29460Sstevel@tonic-gate 
29470Sstevel@tonic-gate /*
29480Sstevel@tonic-gate  * icheck -  make sure we can read the block containing the inode
29490Sstevel@tonic-gate  *	and determine the filesize (0 if inode not allocated).  Return
29500Sstevel@tonic-gate  *	0 if error otherwise return the mode.
29510Sstevel@tonic-gate  */
29521051Smaheshvs int
icheck(u_offset_t address)29531051Smaheshvs icheck(u_offset_t address)
29540Sstevel@tonic-gate {
29551051Smaheshvs 	char		*cptr;
29561051Smaheshvs 	struct dinode	*ip;
29570Sstevel@tonic-gate 
29580Sstevel@tonic-gate 	if ((cptr = getblk(address)) == 0)
29590Sstevel@tonic-gate 		return (0);
29600Sstevel@tonic-gate 	cptr += blkoff(fs, address);
29610Sstevel@tonic-gate 	/*LINTED*/
29620Sstevel@tonic-gate 	ip = (struct dinode *)cptr;
29630Sstevel@tonic-gate 	if ((ip->di_mode & IFMT) == 0) {
29640Sstevel@tonic-gate 		if (!override) {
29650Sstevel@tonic-gate 			printf("inode not allocated\n");
29660Sstevel@tonic-gate 			error++;
29670Sstevel@tonic-gate 			return (0);
29680Sstevel@tonic-gate 		}
29690Sstevel@tonic-gate 		blocksize = filesize = 0;
29700Sstevel@tonic-gate 	} else {
29710Sstevel@tonic-gate 		trapped++;
29720Sstevel@tonic-gate 		filesize = ip->di_size;
29730Sstevel@tonic-gate 		blocksize = filesize * 2;
29740Sstevel@tonic-gate 	}
29750Sstevel@tonic-gate 	return (ip->di_mode);
29760Sstevel@tonic-gate }
29770Sstevel@tonic-gate 
29780Sstevel@tonic-gate /*
29790Sstevel@tonic-gate  * getdirslot - get the address of the directory slot desired.
29800Sstevel@tonic-gate  */
29810Sstevel@tonic-gate static u_offset_t
getdirslot(long slot)29821051Smaheshvs getdirslot(long slot)
29830Sstevel@tonic-gate {
29841051Smaheshvs 	char		*cptr;
29851051Smaheshvs 	struct direct	*dirp;
29861051Smaheshvs 	short		i;
29871051Smaheshvs 	char		*string = &scratch[0];
29881051Smaheshvs 	short		bod = 0, mode, temp;
29890Sstevel@tonic-gate 
29900Sstevel@tonic-gate 	if (slot < 0) {
29910Sstevel@tonic-gate 		slot = 0;
29920Sstevel@tonic-gate 		bod++;
29930Sstevel@tonic-gate 	}
29940Sstevel@tonic-gate 	if (type != DIRECTORY) {
29950Sstevel@tonic-gate 		if (type == BLOCK)
29960Sstevel@tonic-gate 			string = "block";
29970Sstevel@tonic-gate 		else
29980Sstevel@tonic-gate 			string = "fragment";
29990Sstevel@tonic-gate 		addr = bod_addr;
30000Sstevel@tonic-gate 		if ((cptr = getblk(addr)) == 0)
30010Sstevel@tonic-gate 			return (0);
30020Sstevel@tonic-gate 		cptr += blkoff(fs, addr);
30030Sstevel@tonic-gate 		cur_bytes = 0;
30040Sstevel@tonic-gate 		/*LINTED*/
30050Sstevel@tonic-gate 		dirp = (struct direct *)cptr;
30060Sstevel@tonic-gate 		for (dirslot = 0; dirslot < slot; dirslot++) {
30070Sstevel@tonic-gate 			/*LINTED*/
30080Sstevel@tonic-gate 			dirp = (struct direct *)cptr;
30090Sstevel@tonic-gate 			if (blocksize > filesize) {
30100Sstevel@tonic-gate 				if (cur_bytes + (long)dirp->d_reclen >=
30110Sstevel@tonic-gate 								filesize) {
30120Sstevel@tonic-gate 					printf("end of file\n");
30130Sstevel@tonic-gate 					erraddr = addr;
30140Sstevel@tonic-gate 					errcur_bytes = cur_bytes;
30150Sstevel@tonic-gate 					stringsize = STRINGSIZE(dirp);
30160Sstevel@tonic-gate 					error++;
30170Sstevel@tonic-gate 					return (addr);
30180Sstevel@tonic-gate 				}
30190Sstevel@tonic-gate 			} else {
30200Sstevel@tonic-gate 				if (cur_bytes + (long)dirp->d_reclen >=
30210Sstevel@tonic-gate 								blocksize) {
30220Sstevel@tonic-gate 					printf("end of %s\n", string);
30230Sstevel@tonic-gate 					erraddr = addr;
30240Sstevel@tonic-gate 					errcur_bytes = cur_bytes;
30250Sstevel@tonic-gate 					stringsize = STRINGSIZE(dirp);
30260Sstevel@tonic-gate 					error++;
30270Sstevel@tonic-gate 					return (addr);
30280Sstevel@tonic-gate 				}
30290Sstevel@tonic-gate 			}
30300Sstevel@tonic-gate 			cptr += dirp->d_reclen;
30310Sstevel@tonic-gate 			addr += dirp->d_reclen;
30320Sstevel@tonic-gate 			cur_bytes += dirp->d_reclen;
30330Sstevel@tonic-gate 		}
30340Sstevel@tonic-gate 		if (bod) {
30350Sstevel@tonic-gate 			if (blocksize > filesize)
30360Sstevel@tonic-gate 				printf("beginning of file\n");
30370Sstevel@tonic-gate 			else
30380Sstevel@tonic-gate 				printf("beginning of %s\n", string);
30390Sstevel@tonic-gate 			erraddr = addr;
30400Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
30410Sstevel@tonic-gate 			error++;
30420Sstevel@tonic-gate 		}
30430Sstevel@tonic-gate 		stringsize = STRINGSIZE(dirp);
30440Sstevel@tonic-gate 		return (addr);
30450Sstevel@tonic-gate 	} else {
30460Sstevel@tonic-gate 		addr = cur_ino;
30470Sstevel@tonic-gate 		if ((mode = icheck(addr)) == 0)
30480Sstevel@tonic-gate 			return (0);
30490Sstevel@tonic-gate 		if (!override && (mode & IFDIR) == 0) {
30500Sstevel@tonic-gate 			printf("inode is not a directory\n");
30510Sstevel@tonic-gate 			error++;
30520Sstevel@tonic-gate 			return (0);
30530Sstevel@tonic-gate 		}
30540Sstevel@tonic-gate 		temp = slot;
30550Sstevel@tonic-gate 		i = cur_bytes = 0;
30560Sstevel@tonic-gate 		for (;;) {
30570Sstevel@tonic-gate 			if (i == 0 || bcomp(addr)) {
30580Sstevel@tonic-gate 				error = 0;
30590Sstevel@tonic-gate 				if ((addr = (bmap((long)i++) << FRGSHIFT)) == 0)
30600Sstevel@tonic-gate 					break;
30610Sstevel@tonic-gate 				if ((cptr = getblk(addr)) == 0)
30620Sstevel@tonic-gate 					break;
30630Sstevel@tonic-gate 				cptr += blkoff(fs, addr);
30640Sstevel@tonic-gate 			}
30650Sstevel@tonic-gate 			/*LINTED*/
30660Sstevel@tonic-gate 			dirp = (struct direct *)cptr;
30670Sstevel@tonic-gate 			value = dirp->d_ino;
30680Sstevel@tonic-gate 			if (!temp--)
30690Sstevel@tonic-gate 				break;
30700Sstevel@tonic-gate 			if (cur_bytes + (long)dirp->d_reclen >= filesize) {
30710Sstevel@tonic-gate 				printf("end of file\n");
30720Sstevel@tonic-gate 				dirslot = slot - temp - 1;
30730Sstevel@tonic-gate 				objsz = DIRECTORY;
30740Sstevel@tonic-gate 				erraddr = addr;
30750Sstevel@tonic-gate 				errcur_bytes = cur_bytes;
30760Sstevel@tonic-gate 				stringsize = STRINGSIZE(dirp);
30770Sstevel@tonic-gate 				error++;
30780Sstevel@tonic-gate 				return (addr);
30790Sstevel@tonic-gate 			}
30800Sstevel@tonic-gate 			addr += dirp->d_reclen;
30810Sstevel@tonic-gate 			cptr += dirp->d_reclen;
30820Sstevel@tonic-gate 			cur_bytes += dirp->d_reclen;
30830Sstevel@tonic-gate 		}
30840Sstevel@tonic-gate 		dirslot = slot;
30850Sstevel@tonic-gate 		objsz = DIRECTORY;
30860Sstevel@tonic-gate 		if (bod) {
30870Sstevel@tonic-gate 			printf("beginning of file\n");
30880Sstevel@tonic-gate 			erraddr = addr;
30890Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
30900Sstevel@tonic-gate 			error++;
30910Sstevel@tonic-gate 		}
30920Sstevel@tonic-gate 		stringsize = STRINGSIZE(dirp);
30930Sstevel@tonic-gate 		return (addr);
30940Sstevel@tonic-gate 	}
30950Sstevel@tonic-gate }
30960Sstevel@tonic-gate 
30970Sstevel@tonic-gate 
30980Sstevel@tonic-gate /*
30990Sstevel@tonic-gate  * getshadowslot - get the address of the shadow data desired
31000Sstevel@tonic-gate  */
31010Sstevel@tonic-gate static int
getshadowslot(long shadow)31021051Smaheshvs getshadowslot(long shadow)
31030Sstevel@tonic-gate {
31040Sstevel@tonic-gate 	struct ufs_fsd		fsd;
31050Sstevel@tonic-gate 	short			bod = 0, mode;
31060Sstevel@tonic-gate 	long			taddr, tcurbytes;
31070Sstevel@tonic-gate 
31080Sstevel@tonic-gate 	if (shadow < 0) {
31090Sstevel@tonic-gate 		shadow = 0;
31100Sstevel@tonic-gate 		bod++;
31110Sstevel@tonic-gate 	}
31120Sstevel@tonic-gate 	if (type != SHADOW_DATA) {
31130Sstevel@tonic-gate 		if (shadow < cur_shad) {
31140Sstevel@tonic-gate 			printf("can't scan shadow data in reverse\n");
31150Sstevel@tonic-gate 			error++;
31160Sstevel@tonic-gate 			return (0);
31170Sstevel@tonic-gate 		}
31180Sstevel@tonic-gate 	} else {
31190Sstevel@tonic-gate 		addr = cur_ino;
31200Sstevel@tonic-gate 		if ((mode = icheck(addr)) == 0)
31210Sstevel@tonic-gate 			return (0);
31220Sstevel@tonic-gate 		if (!override && (mode & IFMT) != IFSHAD) {
31230Sstevel@tonic-gate 			printf("inode is not a shadow\n");
31240Sstevel@tonic-gate 			error++;
31250Sstevel@tonic-gate 			return (0);
31260Sstevel@tonic-gate 		}
31270Sstevel@tonic-gate 		cur_bytes = 0;
31280Sstevel@tonic-gate 		cur_shad = 0;
31290Sstevel@tonic-gate 		syncshadowscan(1);	/* force synchronization */
31300Sstevel@tonic-gate 	}
31310Sstevel@tonic-gate 
31320Sstevel@tonic-gate 	for (; cur_shad < shadow; cur_shad++) {
31330Sstevel@tonic-gate 		taddr = addr;
31340Sstevel@tonic-gate 		tcurbytes = cur_bytes;
31350Sstevel@tonic-gate 		getshadowdata((long *)&fsd, LONG + LONG);
31360Sstevel@tonic-gate 		addr = taddr;
31370Sstevel@tonic-gate 		cur_bytes = tcurbytes;
31380Sstevel@tonic-gate 		if (cur_bytes + (long)fsd.fsd_size > filesize) {
31390Sstevel@tonic-gate 			syncshadowscan(0);
31400Sstevel@tonic-gate 			printf("end of file\n");
31410Sstevel@tonic-gate 			erraddr = addr;
31420Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
31430Sstevel@tonic-gate 			error++;
31440Sstevel@tonic-gate 			return (addr);
31450Sstevel@tonic-gate 		}
31460Sstevel@tonic-gate 		addr += fsd.fsd_size;
31470Sstevel@tonic-gate 		cur_bytes += fsd.fsd_size;
31480Sstevel@tonic-gate 		syncshadowscan(0);
31490Sstevel@tonic-gate 	}
31500Sstevel@tonic-gate 	if (type == SHADOW_DATA)
31510Sstevel@tonic-gate 		objsz = SHADOW_DATA;
31520Sstevel@tonic-gate 	if (bod) {
31530Sstevel@tonic-gate 		printf("beginning of file\n");
31540Sstevel@tonic-gate 		erraddr = addr;
31550Sstevel@tonic-gate 		errcur_bytes = cur_bytes;
31560Sstevel@tonic-gate 		error++;
31570Sstevel@tonic-gate 	}
31580Sstevel@tonic-gate 	return (addr);
31590Sstevel@tonic-gate }
31600Sstevel@tonic-gate 
31610Sstevel@tonic-gate static void
getshadowdata(long * buf,int len)31621051Smaheshvs getshadowdata(long *buf, int len)
31630Sstevel@tonic-gate {
31640Sstevel@tonic-gate 	long	tfsd;
31650Sstevel@tonic-gate 
31660Sstevel@tonic-gate 	len /= LONG;
31670Sstevel@tonic-gate 	for (tfsd = 0; tfsd < len; tfsd++) {
31680Sstevel@tonic-gate 		buf[tfsd] = get(SHADOW_DATA);
31690Sstevel@tonic-gate 		addr += LONG;
31700Sstevel@tonic-gate 		cur_bytes += LONG;
31710Sstevel@tonic-gate 		syncshadowscan(0);
31720Sstevel@tonic-gate 	}
31730Sstevel@tonic-gate }
31740Sstevel@tonic-gate 
31750Sstevel@tonic-gate static void
syncshadowscan(int force)31761051Smaheshvs syncshadowscan(int force)
31770Sstevel@tonic-gate {
31780Sstevel@tonic-gate 	long	curblkoff;
31790Sstevel@tonic-gate 	if (type == SHADOW_DATA && (force ||
31800Sstevel@tonic-gate 	    lblkno(fs, addr) != (bhdr.fwd)->blkno)) {
31810Sstevel@tonic-gate 		curblkoff = blkoff(fs, cur_bytes);
31820Sstevel@tonic-gate 		addr = bmap(lblkno(fs, cur_bytes)) << FRGSHIFT;
31830Sstevel@tonic-gate 		addr += curblkoff;
31840Sstevel@tonic-gate 		cur_bytes += curblkoff;
31850Sstevel@tonic-gate 		(void) getblk(addr);
31860Sstevel@tonic-gate 		objsz = SHADOW_DATA;
31870Sstevel@tonic-gate 	}
31880Sstevel@tonic-gate }
31890Sstevel@tonic-gate 
31900Sstevel@tonic-gate 
31910Sstevel@tonic-gate 
31920Sstevel@tonic-gate /*
31930Sstevel@tonic-gate  * putf - print a byte as an ascii character if possible.
31940Sstevel@tonic-gate  *	The exceptions are tabs, newlines, backslashes
31950Sstevel@tonic-gate  *	and nulls which are printed as the standard C
31960Sstevel@tonic-gate  *	language escapes. Characters which are not
31970Sstevel@tonic-gate  *	recognized are printed as \?.
31980Sstevel@tonic-gate  */
31990Sstevel@tonic-gate static void
putf(char c)32001051Smaheshvs putf(char c)
32010Sstevel@tonic-gate {
32020Sstevel@tonic-gate 
32030Sstevel@tonic-gate 	if (c <= 037 || c >= 0177 || c == '\\') {
32040Sstevel@tonic-gate 		printf("\\");
32050Sstevel@tonic-gate 		switch (c) {
32060Sstevel@tonic-gate 		case '\\':
32070Sstevel@tonic-gate 			printf("\\");
32080Sstevel@tonic-gate 			break;
32090Sstevel@tonic-gate 		case '\t':
32100Sstevel@tonic-gate 			printf("t");
32110Sstevel@tonic-gate 			break;
32120Sstevel@tonic-gate 		case '\n':
32130Sstevel@tonic-gate 			printf("n");
32140Sstevel@tonic-gate 			break;
32150Sstevel@tonic-gate 		case '\0':
32160Sstevel@tonic-gate 			printf("0");
32170Sstevel@tonic-gate 			break;
32180Sstevel@tonic-gate 		default:
32190Sstevel@tonic-gate 			printf("?");
32200Sstevel@tonic-gate 		}
32210Sstevel@tonic-gate 	} else {
32220Sstevel@tonic-gate 		printf("%c", c);
32230Sstevel@tonic-gate 		printf(" ");
32240Sstevel@tonic-gate 	}
32250Sstevel@tonic-gate }
32260Sstevel@tonic-gate 
32270Sstevel@tonic-gate /*
32280Sstevel@tonic-gate  * put - write an item into the buffer for the current address
32290Sstevel@tonic-gate  *	block.  The value is checked to make sure that it will
32300Sstevel@tonic-gate  *	fit in the size given without truncation.  If successful,
32310Sstevel@tonic-gate  *	the entire block is written back to the file system.
32320Sstevel@tonic-gate  */
32330Sstevel@tonic-gate static void
put(u_offset_t item,short lngth)32341051Smaheshvs put(u_offset_t item, short lngth)
32350Sstevel@tonic-gate {
32360Sstevel@tonic-gate 
32371051Smaheshvs 	char	*bptr, *sbptr;
32381051Smaheshvs 	long	s_err, nbytes;
32391051Smaheshvs 	long	olditem;
32400Sstevel@tonic-gate 
32410Sstevel@tonic-gate 	if (wrtflag == O_RDONLY) {
32420Sstevel@tonic-gate 		printf("not opened for write '-w'\n");
32430Sstevel@tonic-gate 		error++;
32440Sstevel@tonic-gate 		return;
32450Sstevel@tonic-gate 	}
32460Sstevel@tonic-gate 	objsz = lngth;
32470Sstevel@tonic-gate 	if ((sbptr = getblk(addr)) == 0)
32480Sstevel@tonic-gate 		return;
32490Sstevel@tonic-gate 	bptr = sbptr + blkoff(fs, addr);
32500Sstevel@tonic-gate 	switch (objsz) {
32510Sstevel@tonic-gate 	case LONG:
32520Sstevel@tonic-gate 	case DIRECTORY:
32530Sstevel@tonic-gate 		/*LINTED*/
32540Sstevel@tonic-gate 		olditem = *(long *)bptr;
32550Sstevel@tonic-gate 		/*LINTED*/
32560Sstevel@tonic-gate 		*(long *)bptr = item;
32570Sstevel@tonic-gate 		break;
32580Sstevel@tonic-gate 	case SHORT:
32590Sstevel@tonic-gate 	case INODE:
32600Sstevel@tonic-gate 		/*LINTED*/
32610Sstevel@tonic-gate 		olditem = (long)*(short *)bptr;
32620Sstevel@tonic-gate 		item &= 0177777L;
32630Sstevel@tonic-gate 		/*LINTED*/
32640Sstevel@tonic-gate 		*(short *)bptr = item;
32650Sstevel@tonic-gate 		break;
32660Sstevel@tonic-gate 	case CHAR:
32670Sstevel@tonic-gate 		olditem = (long)*bptr;
32680Sstevel@tonic-gate 		item &= 0377;
32690Sstevel@tonic-gate 		*bptr = lobyte(loword(item));
32700Sstevel@tonic-gate 		break;
32710Sstevel@tonic-gate 	default:
32720Sstevel@tonic-gate 		error++;
32730Sstevel@tonic-gate 		return;
32740Sstevel@tonic-gate 	}
32750Sstevel@tonic-gate 	if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) {
32760Sstevel@tonic-gate 		error++;
32770Sstevel@tonic-gate 		printf("seek error : %" PRIx64 "\n", addr);
32780Sstevel@tonic-gate 		return;
32790Sstevel@tonic-gate 	}
32800Sstevel@tonic-gate 	if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
32810Sstevel@tonic-gate 		error++;
32820Sstevel@tonic-gate 		printf("write error : addr   = %" PRIx64 "\n", addr);
32830Sstevel@tonic-gate 		printf("            : s_err  = %lx\n", s_err);
32840Sstevel@tonic-gate 		printf("            : nbytes = %lx\n", nbytes);
32850Sstevel@tonic-gate 		return;
32860Sstevel@tonic-gate 	}
32870Sstevel@tonic-gate 	if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
32880Sstevel@tonic-gate 		index(base);
32890Sstevel@tonic-gate 		print(olditem, 8, -8, 0);
32900Sstevel@tonic-gate 		printf("\t=\t");
32910Sstevel@tonic-gate 		print(item, 8, -8, 0);
32920Sstevel@tonic-gate 		printf("\n");
32930Sstevel@tonic-gate 	} else {
32940Sstevel@tonic-gate 		if (objsz == DIRECTORY) {
32950Sstevel@tonic-gate 			addr = cur_dir;
32960Sstevel@tonic-gate 			fprnt('?', 'd');
32970Sstevel@tonic-gate 		} else {
32980Sstevel@tonic-gate 			addr = cur_ino;
32990Sstevel@tonic-gate 			objsz = INODE;
33000Sstevel@tonic-gate 			fprnt('?', 'i');
33010Sstevel@tonic-gate 		}
33020Sstevel@tonic-gate 	}
33030Sstevel@tonic-gate }
33040Sstevel@tonic-gate 
33050Sstevel@tonic-gate /*
33060Sstevel@tonic-gate  * getblk - check if the desired block is in the file system.
33070Sstevel@tonic-gate  *	Search the incore buffers to see if the block is already
33080Sstevel@tonic-gate  *	available. If successful, unlink the buffer control block
33090Sstevel@tonic-gate  *	from its position in the buffer list and re-insert it at
33100Sstevel@tonic-gate  *	the head of the list.  If failure, use the last buffer
33110Sstevel@tonic-gate  *	in the list for the desired block. Again, this control
33120Sstevel@tonic-gate  *	block is placed at the head of the list. This process
33130Sstevel@tonic-gate  *	will leave commonly requested blocks in the in-core buffers.
33140Sstevel@tonic-gate  *	Finally, a pointer to the buffer is returned.
33150Sstevel@tonic-gate  */
33160Sstevel@tonic-gate static char *
getblk(u_offset_t address)33171051Smaheshvs getblk(u_offset_t address)
33180Sstevel@tonic-gate {
33190Sstevel@tonic-gate 
33201051Smaheshvs 	struct lbuf	*bp;
33211051Smaheshvs 	long		s_err, nbytes;
33221051Smaheshvs 	unsigned long	block;
33230Sstevel@tonic-gate 
33240Sstevel@tonic-gate 	read_requests++;
33250Sstevel@tonic-gate 	block = lblkno(fs, address);
33260Sstevel@tonic-gate 	if (block >= fragstoblks(fs, fs->fs_size)) {
33270Sstevel@tonic-gate 		printf("cannot read block %lu\n", block);
33280Sstevel@tonic-gate 		error++;
33290Sstevel@tonic-gate 		return (0);
33300Sstevel@tonic-gate 	}
33310Sstevel@tonic-gate 	for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
33320Sstevel@tonic-gate 		if (bp->valid && bp->blkno == block)
33330Sstevel@tonic-gate 			goto xit;
33340Sstevel@tonic-gate 	actual_disk_reads++;
33350Sstevel@tonic-gate 	bp = bhdr.back;
33360Sstevel@tonic-gate 	bp->blkno = block;
33370Sstevel@tonic-gate 	bp->valid = 0;
33380Sstevel@tonic-gate 	if ((s_err = llseek(fd, (offset_t)(address & fs->fs_bmask), 0)) == -1) {
33390Sstevel@tonic-gate 		error++;
33400Sstevel@tonic-gate 		printf("seek error : %" PRIx64 "\n", address);
33410Sstevel@tonic-gate 		return (0);
33420Sstevel@tonic-gate 	}
33430Sstevel@tonic-gate 	if ((nbytes = read(fd, bp->blkaddr, BLKSIZE)) != BLKSIZE) {
33440Sstevel@tonic-gate 		error++;
33450Sstevel@tonic-gate 		printf("read error : addr   = %" PRIx64 "\n", address);
33460Sstevel@tonic-gate 		printf("           : s_err  = %lx\n", s_err);
33470Sstevel@tonic-gate 		printf("           : nbytes = %lx\n", nbytes);
33480Sstevel@tonic-gate 		return (0);
33490Sstevel@tonic-gate 	}
33500Sstevel@tonic-gate 	bp->valid++;
33510Sstevel@tonic-gate xit:	bp->back->fwd = bp->fwd;
33520Sstevel@tonic-gate 	bp->fwd->back = bp->back;
33530Sstevel@tonic-gate 	insert(bp);
33540Sstevel@tonic-gate 	return (bp->blkaddr);
33550Sstevel@tonic-gate }
33560Sstevel@tonic-gate 
33570Sstevel@tonic-gate /*
33580Sstevel@tonic-gate  * insert - place the designated buffer control block
33590Sstevel@tonic-gate  *	at the head of the linked list of buffers.
33600Sstevel@tonic-gate  */
33610Sstevel@tonic-gate static void
insert(struct lbuf * bp)33621051Smaheshvs insert(struct lbuf *bp)
33630Sstevel@tonic-gate {
33640Sstevel@tonic-gate 
33650Sstevel@tonic-gate 	bp->back = &bhdr;
33660Sstevel@tonic-gate 	bp->fwd = bhdr.fwd;
33670Sstevel@tonic-gate 	bhdr.fwd->back = bp;
33680Sstevel@tonic-gate 	bhdr.fwd = bp;
33690Sstevel@tonic-gate }
33700Sstevel@tonic-gate 
33710Sstevel@tonic-gate /*
33720Sstevel@tonic-gate  * err - called on interrupts.  Set the current address
33730Sstevel@tonic-gate  *	back to the last address stored in erraddr. Reset all
33740Sstevel@tonic-gate  *	appropriate flags.  A reset call is made to return
33750Sstevel@tonic-gate  *	to the main loop;
33760Sstevel@tonic-gate  */
33770Sstevel@tonic-gate #ifdef sun
33780Sstevel@tonic-gate /*ARGSUSED*/
33790Sstevel@tonic-gate static void
err(int sig)33801051Smaheshvs err(int sig)
33810Sstevel@tonic-gate #else
33820Sstevel@tonic-gate err()
33830Sstevel@tonic-gate #endif /* sun */
33840Sstevel@tonic-gate {
33850Sstevel@tonic-gate 	freemem(filenames, nfiles);
33860Sstevel@tonic-gate 	nfiles = 0;
33870Sstevel@tonic-gate 	(void) signal(2, err);
33880Sstevel@tonic-gate 	addr = erraddr;
33890Sstevel@tonic-gate 	cur_ino = errino;
33900Sstevel@tonic-gate 	cur_inum = errinum;
33910Sstevel@tonic-gate 	cur_bytes = errcur_bytes;
33920Sstevel@tonic-gate 	error = 0;
33930Sstevel@tonic-gate 	c_count = 0;
33940Sstevel@tonic-gate 	printf("\n?\n");
33950Sstevel@tonic-gate 	(void) fseek(stdin, 0L, 2);
33960Sstevel@tonic-gate 	longjmp(env, 0);
33970Sstevel@tonic-gate }
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate /*
34000Sstevel@tonic-gate  * devcheck - check that the given mode represents a
34010Sstevel@tonic-gate  *	special device. The IFCHR bit is on for both
34020Sstevel@tonic-gate  *	character and block devices.
34030Sstevel@tonic-gate  */
34040Sstevel@tonic-gate static int
devcheck(short md)34051051Smaheshvs devcheck(short md)
34060Sstevel@tonic-gate {
34070Sstevel@tonic-gate 	if (override)
34080Sstevel@tonic-gate 		return (0);
34090Sstevel@tonic-gate 	switch (md & IFMT) {
34100Sstevel@tonic-gate 	case IFCHR:
34110Sstevel@tonic-gate 	case IFBLK:
34120Sstevel@tonic-gate 		return (0);
34130Sstevel@tonic-gate 	}
34140Sstevel@tonic-gate 
34150Sstevel@tonic-gate 	printf("not character or block device\n");
34160Sstevel@tonic-gate 	error++;
34170Sstevel@tonic-gate 	return (1);
34180Sstevel@tonic-gate }
34190Sstevel@tonic-gate 
34200Sstevel@tonic-gate /*
34210Sstevel@tonic-gate  * nullblk - return error if address is zero.  This is done
34220Sstevel@tonic-gate  *	to prevent block 0 from being used as an indirect block
34230Sstevel@tonic-gate  *	for a large file or as a data block for a small file.
34240Sstevel@tonic-gate  */
34250Sstevel@tonic-gate static int
nullblk(long bn)34261051Smaheshvs nullblk(long bn)
34270Sstevel@tonic-gate {
34280Sstevel@tonic-gate 	if (bn != 0)
34290Sstevel@tonic-gate 		return (0);
34300Sstevel@tonic-gate 	printf("non existent block\n");
34310Sstevel@tonic-gate 	error++;
34320Sstevel@tonic-gate 	return (1);
34330Sstevel@tonic-gate }
34340Sstevel@tonic-gate 
34350Sstevel@tonic-gate /*
34360Sstevel@tonic-gate  * puta - put ascii characters into a buffer.  The string
34370Sstevel@tonic-gate  *	terminates with a quote or newline.  The leading quote,
34380Sstevel@tonic-gate  *	which is optional for directory names, was stripped off
34390Sstevel@tonic-gate  *	by the assignment case in the main loop.
34400Sstevel@tonic-gate  */
34410Sstevel@tonic-gate static void
puta()34420Sstevel@tonic-gate puta()
34430Sstevel@tonic-gate {
34441051Smaheshvs 	char		*cptr, c;
34451051Smaheshvs 	int		i;
34461051Smaheshvs 	char		*sbptr;
34471051Smaheshvs 	short		terror = 0;
34481051Smaheshvs 	long		maxchars, s_err, nbytes, temp;
34491051Smaheshvs 	u_offset_t	taddr = addr;
34501051Smaheshvs 	long		tcount = 0, item, olditem = 0;
34510Sstevel@tonic-gate 
34520Sstevel@tonic-gate 	if (wrtflag == O_RDONLY) {
34530Sstevel@tonic-gate 		printf("not opened for write '-w'\n");
34540Sstevel@tonic-gate 		error++;
34550Sstevel@tonic-gate 		return;
34560Sstevel@tonic-gate 	}
34570Sstevel@tonic-gate 	if ((sbptr = getblk(addr)) == 0)
34580Sstevel@tonic-gate 		return;
34590Sstevel@tonic-gate 	cptr = sbptr + blkoff(fs, addr);
34600Sstevel@tonic-gate 	if (objsz == DIRECTORY) {
34610Sstevel@tonic-gate 		if (acting_on_directory)
34620Sstevel@tonic-gate 			maxchars = stringsize - 1;
34630Sstevel@tonic-gate 		else
34640Sstevel@tonic-gate 			maxchars = LONG;
34650Sstevel@tonic-gate 	} else if (objsz == INODE)
34660Sstevel@tonic-gate 		maxchars = objsz - (addr - cur_ino);
34670Sstevel@tonic-gate 	else
34680Sstevel@tonic-gate 		maxchars = min(blocksize - cur_bytes, filesize - cur_bytes);
34690Sstevel@tonic-gate 	while ((c = getachar()) != '"') {
34700Sstevel@tonic-gate 		if (tcount >= maxchars) {
34710Sstevel@tonic-gate 			printf("string too long\n");
34720Sstevel@tonic-gate 			if (objsz == DIRECTORY)
34730Sstevel@tonic-gate 				addr = cur_dir;
34740Sstevel@tonic-gate 			else if (acting_on_inode || objsz == INODE)
34750Sstevel@tonic-gate 				addr = cur_ino;
34760Sstevel@tonic-gate 			else
34770Sstevel@tonic-gate 				addr = taddr;
34780Sstevel@tonic-gate 			erraddr = addr;
34790Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
34800Sstevel@tonic-gate 			terror++;
34810Sstevel@tonic-gate 			break;
34820Sstevel@tonic-gate 		}
34830Sstevel@tonic-gate 		tcount++;
34840Sstevel@tonic-gate 		if (c == '\n') {
34850Sstevel@tonic-gate 			ungetachar(c);
34860Sstevel@tonic-gate 			break;
34870Sstevel@tonic-gate 		}
34880Sstevel@tonic-gate 		temp = (long)*cptr;
34890Sstevel@tonic-gate 		olditem <<= BITSPERCHAR;
34900Sstevel@tonic-gate 		olditem += temp & 0xff;
34910Sstevel@tonic-gate 		if (c == '\\') {
34920Sstevel@tonic-gate 			switch (c = getachar()) {
34930Sstevel@tonic-gate 			case 't':
34940Sstevel@tonic-gate 				*cptr++ = '\t';
34950Sstevel@tonic-gate 				break;
34960Sstevel@tonic-gate 			case 'n':
34970Sstevel@tonic-gate 				*cptr++ = '\n';
34980Sstevel@tonic-gate 				break;
34990Sstevel@tonic-gate 			case '0':
35000Sstevel@tonic-gate 				*cptr++ = '\0';
35010Sstevel@tonic-gate 				break;
35020Sstevel@tonic-gate 			default:
35030Sstevel@tonic-gate 				*cptr++ = c;
35040Sstevel@tonic-gate 				break;
35050Sstevel@tonic-gate 			}
35060Sstevel@tonic-gate 		}
35070Sstevel@tonic-gate 		else
35080Sstevel@tonic-gate 			*cptr++ = c;
35090Sstevel@tonic-gate 	}
35100Sstevel@tonic-gate 	if (objsz == DIRECTORY && acting_on_directory)
35110Sstevel@tonic-gate 		for (i = tcount; i <= maxchars; i++)
35120Sstevel@tonic-gate 			*cptr++ = '\0';
35130Sstevel@tonic-gate 	if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) {
35140Sstevel@tonic-gate 		error++;
35150Sstevel@tonic-gate 		printf("seek error : %" PRIx64 "\n", addr);
35160Sstevel@tonic-gate 		return;
35170Sstevel@tonic-gate 	}
35180Sstevel@tonic-gate 	if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
35190Sstevel@tonic-gate 		error++;
35200Sstevel@tonic-gate 		printf("write error : addr   = %" PRIx64 "\n", addr);
35210Sstevel@tonic-gate 		printf("            : s_err  = %lx\n", s_err);
35220Sstevel@tonic-gate 		printf("            : nbytes = %lx\n", nbytes);
35230Sstevel@tonic-gate 		return;
35240Sstevel@tonic-gate 	}
35250Sstevel@tonic-gate 	if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
35260Sstevel@tonic-gate 		addr += tcount;
35270Sstevel@tonic-gate 		cur_bytes += tcount;
35280Sstevel@tonic-gate 		taddr = addr;
35290Sstevel@tonic-gate 		if (objsz != CHAR) {
35300Sstevel@tonic-gate 			addr &= ~(objsz - 1);
35310Sstevel@tonic-gate 			cur_bytes -= taddr - addr;
35320Sstevel@tonic-gate 		}
35330Sstevel@tonic-gate 		if (addr == taddr) {
35340Sstevel@tonic-gate 			addr -= objsz;
35350Sstevel@tonic-gate 			taddr = addr;
35360Sstevel@tonic-gate 		}
35370Sstevel@tonic-gate 		tcount = LONG - (taddr - addr);
35380Sstevel@tonic-gate 		index(base);
35390Sstevel@tonic-gate 		if ((cptr = getblk(addr)) == 0)
35400Sstevel@tonic-gate 			return;
35410Sstevel@tonic-gate 		cptr += blkoff(fs, addr);
35420Sstevel@tonic-gate 		switch (objsz) {
35430Sstevel@tonic-gate 		case LONG:
35440Sstevel@tonic-gate 			/*LINTED*/
35450Sstevel@tonic-gate 			item = *(long *)cptr;
35460Sstevel@tonic-gate 			if (tcount < LONG) {
35470Sstevel@tonic-gate 				olditem <<= tcount * BITSPERCHAR;
35480Sstevel@tonic-gate 				temp = 1;
35490Sstevel@tonic-gate 				for (i = 0; i < (tcount*BITSPERCHAR); i++)
35500Sstevel@tonic-gate 					temp <<= 1;
35510Sstevel@tonic-gate 				olditem += item & (temp - 1);
35520Sstevel@tonic-gate 			}
35530Sstevel@tonic-gate 			break;
35540Sstevel@tonic-gate 		case SHORT:
35550Sstevel@tonic-gate 			/*LINTED*/
35560Sstevel@tonic-gate 			item = (long)*(short *)cptr;
35570Sstevel@tonic-gate 			if (tcount < SHORT) {
35580Sstevel@tonic-gate 				olditem <<= tcount * BITSPERCHAR;
35590Sstevel@tonic-gate 				temp = 1;
35600Sstevel@tonic-gate 				for (i = 0; i < (tcount * BITSPERCHAR); i++)
35610Sstevel@tonic-gate 					temp <<= 1;
35620Sstevel@tonic-gate 				olditem += item & (temp - 1);
35630Sstevel@tonic-gate 			}
35640Sstevel@tonic-gate 			olditem &= 0177777L;
35650Sstevel@tonic-gate 			break;
35660Sstevel@tonic-gate 		case CHAR:
35670Sstevel@tonic-gate 			item = (long)*cptr;
35680Sstevel@tonic-gate 			olditem &= 0377;
35690Sstevel@tonic-gate 		}
35700Sstevel@tonic-gate 		print(olditem, 8, -8, 0);
35710Sstevel@tonic-gate 		printf("\t=\t");
35720Sstevel@tonic-gate 		print(item, 8, -8, 0);
35730Sstevel@tonic-gate 		printf("\n");
35740Sstevel@tonic-gate 	} else {
35750Sstevel@tonic-gate 		if (objsz == DIRECTORY) {
35760Sstevel@tonic-gate 			addr = cur_dir;
35770Sstevel@tonic-gate 			fprnt('?', 'd');
35780Sstevel@tonic-gate 		} else {
35790Sstevel@tonic-gate 			addr = cur_ino;
35800Sstevel@tonic-gate 			objsz = INODE;
35810Sstevel@tonic-gate 			fprnt('?', 'i');
35820Sstevel@tonic-gate 		}
35830Sstevel@tonic-gate 	}
35840Sstevel@tonic-gate 	if (terror)
35850Sstevel@tonic-gate 		error++;
35860Sstevel@tonic-gate }
35870Sstevel@tonic-gate 
35880Sstevel@tonic-gate /*
35890Sstevel@tonic-gate  * fprnt - print data.  'count' elements are printed where '*' will
35900Sstevel@tonic-gate  *	print an entire blocks worth or up to the eof, whichever
35910Sstevel@tonic-gate  *	occurs first.  An error will occur if crossing a block boundary
35920Sstevel@tonic-gate  *	is attempted since consecutive blocks don't usually have
35930Sstevel@tonic-gate  *	meaning.  Current print types:
35940Sstevel@tonic-gate  *		/		b   - print as bytes (base sensitive)
35950Sstevel@tonic-gate  *				c   - print as characters
35960Sstevel@tonic-gate  *				o O - print as octal shorts (longs)
35970Sstevel@tonic-gate  *				d D - print as decimal shorts (longs)
35980Sstevel@tonic-gate  *				x X - print as hexadecimal shorts (longs)
35990Sstevel@tonic-gate  *		?		c   - print as cylinder groups
36000Sstevel@tonic-gate  *				d   - print as directories
36010Sstevel@tonic-gate  *				i   - print as inodes
36020Sstevel@tonic-gate  *				s   - print as super blocks
36030Sstevel@tonic-gate  *				S   - print as shadow data
36040Sstevel@tonic-gate  */
36050Sstevel@tonic-gate static void
fprnt(char style,char po)36061051Smaheshvs fprnt(char style, char po)
36070Sstevel@tonic-gate {
36081051Smaheshvs 	int		i;
36091051Smaheshvs 	struct fs	*sb;
36101051Smaheshvs 	struct cg	*cg;
36111051Smaheshvs 	struct direct	*dirp;
36121051Smaheshvs 	struct dinode	*ip;
36131051Smaheshvs 	int		tbase;
36141051Smaheshvs 	char		c, *cptr, *p;
36151051Smaheshvs 	long		tinode, tcount, temp;
36161051Smaheshvs 	u_offset_t	taddr;
36171051Smaheshvs 	short		offset, mode, end = 0, eof = 0, eof_flag;
36181051Smaheshvs 	unsigned short	*sptr;
36191051Smaheshvs 	unsigned long	*lptr;
36201051Smaheshvs 	offset_t	curoff, curioff;
36210Sstevel@tonic-gate 
36220Sstevel@tonic-gate 	laststyle = style;
36230Sstevel@tonic-gate 	lastpo = po;
36240Sstevel@tonic-gate 	should_print = 0;
36250Sstevel@tonic-gate 	if (count != 1) {
36260Sstevel@tonic-gate 		if (clear) {
36270Sstevel@tonic-gate 			count = 1;
36280Sstevel@tonic-gate 			star = 0;
36290Sstevel@tonic-gate 			clear = 0;
36300Sstevel@tonic-gate 		} else
36310Sstevel@tonic-gate 			clear = 1;
36320Sstevel@tonic-gate 	}
36330Sstevel@tonic-gate 	tcount = count;
36340Sstevel@tonic-gate 	offset = blkoff(fs, addr);
36350Sstevel@tonic-gate 
36360Sstevel@tonic-gate 	if (style == '/') {
36370Sstevel@tonic-gate 		if (type == NUMB)
36380Sstevel@tonic-gate 			eof_flag = 0;
36390Sstevel@tonic-gate 		else
36400Sstevel@tonic-gate 			eof_flag = 1;
36410Sstevel@tonic-gate 		switch (po) {
36420Sstevel@tonic-gate 
36430Sstevel@tonic-gate 		case 'c': /* print as characters */
36440Sstevel@tonic-gate 		case 'b': /* or bytes */
36450Sstevel@tonic-gate 			if ((cptr = getblk(addr)) == 0)
36460Sstevel@tonic-gate 				return;
36470Sstevel@tonic-gate 			cptr += offset;
36480Sstevel@tonic-gate 			objsz = CHAR;
36490Sstevel@tonic-gate 			tcount = check_addr(eof_flag, &end, &eof, 0);
36500Sstevel@tonic-gate 			if (tcount) {
36510Sstevel@tonic-gate 				for (i = 0; tcount--; i++) {
36520Sstevel@tonic-gate 					if (i % 16 == 0) {
36530Sstevel@tonic-gate 						if (i)
36540Sstevel@tonic-gate 							printf("\n");
36550Sstevel@tonic-gate 						index(base);
36560Sstevel@tonic-gate 					}
36570Sstevel@tonic-gate 					if (po == 'c') {
36580Sstevel@tonic-gate 						putf(*cptr++);
36590Sstevel@tonic-gate 						if ((i + 1) % 16)
36600Sstevel@tonic-gate 							printf("  ");
36610Sstevel@tonic-gate 					} else {
36620Sstevel@tonic-gate 						if ((i + 1) % 16 == 0)
36630Sstevel@tonic-gate 							print(*cptr++ & 0377L,
36640Sstevel@tonic-gate 								2, -2, 0);
36650Sstevel@tonic-gate 						else
36660Sstevel@tonic-gate 							print(*cptr++ & 0377L,
36670Sstevel@tonic-gate 								4, -2, 0);
36680Sstevel@tonic-gate 					}
36690Sstevel@tonic-gate 					addr += CHAR;
36700Sstevel@tonic-gate 					cur_bytes += CHAR;
36710Sstevel@tonic-gate 				}
36720Sstevel@tonic-gate 				printf("\n");
36730Sstevel@tonic-gate 			}
36740Sstevel@tonic-gate 			addr -= CHAR;
36750Sstevel@tonic-gate 			erraddr = addr;
36760Sstevel@tonic-gate 			cur_bytes -= CHAR;
36770Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
36780Sstevel@tonic-gate 			if (eof) {
36790Sstevel@tonic-gate 				printf("end of file\n");
36800Sstevel@tonic-gate 				error++;
36810Sstevel@tonic-gate 			} else if (end) {
36820Sstevel@tonic-gate 				if (type == BLOCK)
36830Sstevel@tonic-gate 					printf("end of block\n");
36840Sstevel@tonic-gate 				else
36850Sstevel@tonic-gate 					printf("end of fragment\n");
36860Sstevel@tonic-gate 				error++;
36870Sstevel@tonic-gate 			}
36880Sstevel@tonic-gate 			return;
36890Sstevel@tonic-gate 
36900Sstevel@tonic-gate 		case 'o': /* print as octal shorts */
36910Sstevel@tonic-gate 			tbase = OCTAL;
36920Sstevel@tonic-gate 			goto otx;
36930Sstevel@tonic-gate 		case 'd': /* print as decimal shorts */
36940Sstevel@tonic-gate 			tbase = DECIMAL;
36950Sstevel@tonic-gate 			goto otx;
36960Sstevel@tonic-gate 		case 'x': /* print as hex shorts */
36970Sstevel@tonic-gate 			tbase = HEX;
36980Sstevel@tonic-gate otx:
36990Sstevel@tonic-gate 			if ((cptr = getblk(addr)) == 0)
37000Sstevel@tonic-gate 				return;
37010Sstevel@tonic-gate 			taddr = addr;
37020Sstevel@tonic-gate 			addr &= ~(SHORT - 1);
37030Sstevel@tonic-gate 			cur_bytes -= taddr - addr;
37040Sstevel@tonic-gate 			cptr += blkoff(fs, addr);
37050Sstevel@tonic-gate 			/*LINTED*/
37060Sstevel@tonic-gate 			sptr = (unsigned short *)cptr;
37070Sstevel@tonic-gate 			objsz = SHORT;
37080Sstevel@tonic-gate 			tcount = check_addr(eof_flag, &end, &eof, 0);
37090Sstevel@tonic-gate 			if (tcount) {
37100Sstevel@tonic-gate 				for (i = 0; tcount--; i++) {
37110Sstevel@tonic-gate 					sptr = (unsigned short *)print_check(
37120Sstevel@tonic-gate 							/*LINTED*/
37130Sstevel@tonic-gate 							(unsigned long *)sptr,
37140Sstevel@tonic-gate 							&tcount, tbase, i);
37150Sstevel@tonic-gate 					switch (po) {
37160Sstevel@tonic-gate 					case 'o':
37170Sstevel@tonic-gate 						printf("%06o ", *sptr++);
37180Sstevel@tonic-gate 						break;
37190Sstevel@tonic-gate 					case 'd':
37200Sstevel@tonic-gate 						printf("%05d  ", *sptr++);
37210Sstevel@tonic-gate 						break;
37220Sstevel@tonic-gate 					case 'x':
37230Sstevel@tonic-gate 						printf("%04x   ", *sptr++);
37240Sstevel@tonic-gate 					}
37250Sstevel@tonic-gate 					addr += SHORT;
37260Sstevel@tonic-gate 					cur_bytes += SHORT;
37270Sstevel@tonic-gate 				}
37280Sstevel@tonic-gate 				printf("\n");
37290Sstevel@tonic-gate 			}
37300Sstevel@tonic-gate 			addr -= SHORT;
37310Sstevel@tonic-gate 			erraddr = addr;
37320Sstevel@tonic-gate 			cur_bytes -= SHORT;
37330Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
37340Sstevel@tonic-gate 			if (eof) {
37350Sstevel@tonic-gate 				printf("end of file\n");
37360Sstevel@tonic-gate 				error++;
37370Sstevel@tonic-gate 			} else if (end) {
37380Sstevel@tonic-gate 				if (type == BLOCK)
37390Sstevel@tonic-gate 					printf("end of block\n");
37400Sstevel@tonic-gate 				else
37410Sstevel@tonic-gate 					printf("end of fragment\n");
37420Sstevel@tonic-gate 				error++;
37430Sstevel@tonic-gate 			}
37440Sstevel@tonic-gate 			return;
37450Sstevel@tonic-gate 
37460Sstevel@tonic-gate 		case 'O': /* print as octal longs */
37470Sstevel@tonic-gate 			tbase = OCTAL;
37480Sstevel@tonic-gate 			goto OTX;
37490Sstevel@tonic-gate 		case 'D': /* print as decimal longs */
37500Sstevel@tonic-gate 			tbase = DECIMAL;
37510Sstevel@tonic-gate 			goto OTX;
37520Sstevel@tonic-gate 		case 'X': /* print as hex longs */
37530Sstevel@tonic-gate 			tbase = HEX;
37540Sstevel@tonic-gate OTX:
37550Sstevel@tonic-gate 			if ((cptr = getblk(addr)) == 0)
37560Sstevel@tonic-gate 				return;
37570Sstevel@tonic-gate 			taddr = addr;
37580Sstevel@tonic-gate 			addr &= ~(LONG - 1);
37590Sstevel@tonic-gate 			cur_bytes -= taddr - addr;
37600Sstevel@tonic-gate 			cptr += blkoff(fs, addr);
37610Sstevel@tonic-gate 			/*LINTED*/
37620Sstevel@tonic-gate 			lptr = (unsigned long *)cptr;
37630Sstevel@tonic-gate 			objsz = LONG;
37640Sstevel@tonic-gate 			tcount = check_addr(eof_flag, &end, &eof, 0);
37650Sstevel@tonic-gate 			if (tcount) {
37660Sstevel@tonic-gate 				for (i = 0; tcount--; i++) {
37670Sstevel@tonic-gate 					lptr = print_check(lptr, &tcount,
37680Sstevel@tonic-gate 								tbase, i);
37690Sstevel@tonic-gate 					switch (po) {
37700Sstevel@tonic-gate 					case 'O':
37710Sstevel@tonic-gate 						printf("%011lo    ", *lptr++);
37720Sstevel@tonic-gate 						break;
37730Sstevel@tonic-gate 					case 'D':
37740Sstevel@tonic-gate 						printf("%010lu     ", *lptr++);
37750Sstevel@tonic-gate 						break;
37760Sstevel@tonic-gate 					case 'X':
37770Sstevel@tonic-gate 						printf("%08lx       ", *lptr++);
37780Sstevel@tonic-gate 					}
37790Sstevel@tonic-gate 					addr += LONG;
37800Sstevel@tonic-gate 					cur_bytes += LONG;
37810Sstevel@tonic-gate 				}
37820Sstevel@tonic-gate 				printf("\n");
37830Sstevel@tonic-gate 			}
37840Sstevel@tonic-gate 			addr -= LONG;
37850Sstevel@tonic-gate 			erraddr = addr;
37860Sstevel@tonic-gate 			cur_bytes -= LONG;
37870Sstevel@tonic-gate 			errcur_bytes = cur_bytes;
37880Sstevel@tonic-gate 			if (eof) {
37890Sstevel@tonic-gate 				printf("end of file\n");
37900Sstevel@tonic-gate 				error++;
37910Sstevel@tonic-gate 			} else if (end) {
37920Sstevel@tonic-gate 				if (type == BLOCK)
37930Sstevel@tonic-gate 					printf("end of block\n");
37940Sstevel@tonic-gate 				else
37950Sstevel@tonic-gate 					printf("end of fragment\n");
37960Sstevel@tonic-gate 				error++;
37970Sstevel@tonic-gate 			}
37980Sstevel@tonic-gate 			return;
37990Sstevel@tonic-gate 
38000Sstevel@tonic-gate 		default:
38010Sstevel@tonic-gate 			error++;
38020Sstevel@tonic-gate 			printf("no such print option\n");
38030Sstevel@tonic-gate 			return;
38040Sstevel@tonic-gate 		}
38050Sstevel@tonic-gate 	} else
38060Sstevel@tonic-gate 		switch (po) {
38070Sstevel@tonic-gate 
38080Sstevel@tonic-gate 		case 'c': /* print as cylinder group */
38090Sstevel@tonic-gate 			if (type != NUMB)
38100Sstevel@tonic-gate 				if (cur_cgrp + count > fs->fs_ncg) {
38110Sstevel@tonic-gate 					tcount = fs->fs_ncg - cur_cgrp;
38120Sstevel@tonic-gate 					if (!star)
38130Sstevel@tonic-gate 						end++;
38140Sstevel@tonic-gate 				}
38150Sstevel@tonic-gate 			addr &= ~(LONG - 1);
38160Sstevel@tonic-gate 			for (/* void */; tcount--; /* void */) {
38170Sstevel@tonic-gate 				erraddr = addr;
38180Sstevel@tonic-gate 				errcur_bytes = cur_bytes;
38190Sstevel@tonic-gate 				if (type != NUMB) {
38200Sstevel@tonic-gate 					addr = cgtod(fs, cur_cgrp)
38210Sstevel@tonic-gate 						<< FRGSHIFT;
38220Sstevel@tonic-gate 					cur_cgrp++;
38230Sstevel@tonic-gate 				}
38240Sstevel@tonic-gate 				if ((cptr = getblk(addr)) == 0) {
38250Sstevel@tonic-gate 					if (cur_cgrp)
38260Sstevel@tonic-gate 						cur_cgrp--;
38270Sstevel@tonic-gate 					return;
38280Sstevel@tonic-gate 				}
38290Sstevel@tonic-gate 				cptr += blkoff(fs, addr);
38300Sstevel@tonic-gate 				/*LINTED*/
38310Sstevel@tonic-gate 				cg = (struct cg *)cptr;
38320Sstevel@tonic-gate 				if (type == NUMB) {
38330Sstevel@tonic-gate 					cur_cgrp = cg->cg_cgx + 1;
38340Sstevel@tonic-gate 					type = objsz = CGRP;
38350Sstevel@tonic-gate 					if (cur_cgrp + count - 1 > fs->fs_ncg) {
38360Sstevel@tonic-gate 						tcount = fs->fs_ncg - cur_cgrp;
38370Sstevel@tonic-gate 						if (!star)
38380Sstevel@tonic-gate 							end++;
38390Sstevel@tonic-gate 					}
38400Sstevel@tonic-gate 				}
38410Sstevel@tonic-gate 				if (! override && !cg_chkmagic(cg)) {
38420Sstevel@tonic-gate 					printf("invalid cylinder group ");
38430Sstevel@tonic-gate 					printf("magic word\n");
38440Sstevel@tonic-gate 					if (cur_cgrp)
38450Sstevel@tonic-gate 						cur_cgrp--;
38460Sstevel@tonic-gate 					error++;
38470Sstevel@tonic-gate 					return;
38480Sstevel@tonic-gate 				}
38490Sstevel@tonic-gate 				printcg(cg);
38500Sstevel@tonic-gate 				if (tcount)
38510Sstevel@tonic-gate 					printf("\n");
38520Sstevel@tonic-gate 			}
38530Sstevel@tonic-gate 			cur_cgrp--;
38540Sstevel@tonic-gate 			if (end) {
38550Sstevel@tonic-gate 				printf("end of cylinder groups\n");
38560Sstevel@tonic-gate 				error++;
38570Sstevel@tonic-gate 			}
38580Sstevel@tonic-gate 			return;
38590Sstevel@tonic-gate 
38600Sstevel@tonic-gate 		case 'd': /* print as directories */
38610Sstevel@tonic-gate 			if ((cptr = getblk(addr)) == 0)
38620Sstevel@tonic-gate 				return;
38630Sstevel@tonic-gate 			if (type == NUMB) {
38640Sstevel@tonic-gate 				if (fragoff(fs, addr)) {
38650Sstevel@tonic-gate 					printf("address must be at the ");
38660Sstevel@tonic-gate 					printf("beginning of a fragment\n");
38670Sstevel@tonic-gate 					error++;
38680Sstevel@tonic-gate 					return;
38690Sstevel@tonic-gate 				}
38700Sstevel@tonic-gate 				bod_addr = addr;
38710Sstevel@tonic-gate 				type = FRAGMENT;
38720Sstevel@tonic-gate 				dirslot = 0;
38730Sstevel@tonic-gate 				cur_bytes = 0;
38740Sstevel@tonic-gate 				blocksize = FRGSIZE;
38750Sstevel@tonic-gate 				filesize = FRGSIZE * 2;
38760Sstevel@tonic-gate 			}
38770Sstevel@tonic-gate 			cptr += offset;
38780Sstevel@tonic-gate 			objsz = DIRECTORY;
38790Sstevel@tonic-gate 			while (tcount-- && cur_bytes < filesize &&
38800Sstevel@tonic-gate 				cur_bytes < blocksize && !bcomp(addr)) {
38810Sstevel@tonic-gate 				/*LINTED*/
38820Sstevel@tonic-gate 				dirp = (struct direct *)cptr;
38830Sstevel@tonic-gate 				tinode = dirp->d_ino;
38840Sstevel@tonic-gate 				printf("i#: ");
38850Sstevel@tonic-gate 				if (tinode == 0)
38860Sstevel@tonic-gate 					printf("free\t");
38870Sstevel@tonic-gate 				else
38880Sstevel@tonic-gate 					print(tinode, 12, -8, 0);
38890Sstevel@tonic-gate 				printf("%s\n", &dirp->d_name[0]);
38900Sstevel@tonic-gate 				erraddr = addr;
38910Sstevel@tonic-gate 				errcur_bytes = cur_bytes;
38920Sstevel@tonic-gate 				addr += dirp->d_reclen;
38930Sstevel@tonic-gate 				cptr += dirp->d_reclen;
38940Sstevel@tonic-gate 				cur_bytes += dirp->d_reclen;
38950Sstevel@tonic-gate 				dirslot++;
38960Sstevel@tonic-gate 				stringsize = STRINGSIZE(dirp);
38970Sstevel@tonic-gate 			}
38980Sstevel@tonic-gate 			addr = erraddr;
38990Sstevel@tonic-gate 			cur_dir = addr;
39000Sstevel@tonic-gate 			cur_bytes = errcur_bytes;
39010Sstevel@tonic-gate 			dirslot--;
39020Sstevel@tonic-gate 			if (tcount >= 0 && !star) {
39030Sstevel@tonic-gate 				switch (type) {
39040Sstevel@tonic-gate 				case FRAGMENT:
39050Sstevel@tonic-gate 					printf("end of fragment\n");
39060Sstevel@tonic-gate 					break;
39070Sstevel@tonic-gate 				case BLOCK:
39080Sstevel@tonic-gate 					printf("end of block\n");
39090Sstevel@tonic-gate 					break;
39100Sstevel@tonic-gate 				default:
39110Sstevel@tonic-gate 					printf("end of directory\n");
39120Sstevel@tonic-gate 				}
39130Sstevel@tonic-gate 				error++;
39140Sstevel@tonic-gate 			} else
39150Sstevel@tonic-gate 				error = 0;
39160Sstevel@tonic-gate 			return;
39170Sstevel@tonic-gate 
39180Sstevel@tonic-gate 		case 'i': /* print as inodes */
39190Sstevel@tonic-gate 			/*LINTED*/
39200Sstevel@tonic-gate 			if ((ip = (struct dinode *)getblk(addr)) == 0)
39210Sstevel@tonic-gate 				return;
39220Sstevel@tonic-gate 			for (i = 1; i < fs->fs_ncg; i++)
39230Sstevel@tonic-gate 				if (addr < (cgimin(fs, i) << FRGSHIFT))
39240Sstevel@tonic-gate 					break;
39250Sstevel@tonic-gate 			i--;
39260Sstevel@tonic-gate 			offset /= INODE;
39270Sstevel@tonic-gate 			temp = (addr - (cgimin(fs, i) << FRGSHIFT)) >> FRGSHIFT;
39280Sstevel@tonic-gate 			temp = (i * fs->fs_ipg) + fragstoblks(fs, temp) *
39290Sstevel@tonic-gate 							INOPB(fs) + offset;
39300Sstevel@tonic-gate 			if (count + offset > INOPB(fs)) {
39310Sstevel@tonic-gate 				tcount = INOPB(fs) - offset;
39320Sstevel@tonic-gate 				if (!star)
39330Sstevel@tonic-gate 					end++;
39340Sstevel@tonic-gate 			}
39350Sstevel@tonic-gate 			objsz = INODE;
39360Sstevel@tonic-gate 			ip += offset;
39370Sstevel@tonic-gate 			for (i = 0; tcount--; ip++, temp++) {
39380Sstevel@tonic-gate 				if ((mode = icheck(addr)) == 0)
39390Sstevel@tonic-gate 					if (!override)
39400Sstevel@tonic-gate 						continue;
39410Sstevel@tonic-gate 				p = " ugtrwxrwxrwx";
39420Sstevel@tonic-gate 
39430Sstevel@tonic-gate 				switch (mode & IFMT) {
39440Sstevel@tonic-gate 				case IFDIR:
39450Sstevel@tonic-gate 					c = 'd';
39460Sstevel@tonic-gate 					break;
39470Sstevel@tonic-gate 				case IFCHR:
39480Sstevel@tonic-gate 					c = 'c';
39490Sstevel@tonic-gate 					break;
39500Sstevel@tonic-gate 				case IFBLK:
39510Sstevel@tonic-gate 					c = 'b';
39520Sstevel@tonic-gate 					break;
39530Sstevel@tonic-gate 				case IFREG:
39540Sstevel@tonic-gate 					c = '-';
39550Sstevel@tonic-gate 					break;
39560Sstevel@tonic-gate 				case IFLNK:
39570Sstevel@tonic-gate 					c = 'l';
39580Sstevel@tonic-gate 					break;
39590Sstevel@tonic-gate 				case IFSOCK:
39600Sstevel@tonic-gate 					c = 's';
39610Sstevel@tonic-gate 					break;
39620Sstevel@tonic-gate 				case IFSHAD:
39630Sstevel@tonic-gate 					c = 'S';
39640Sstevel@tonic-gate 					break;
39650Sstevel@tonic-gate 				case IFATTRDIR:
39660Sstevel@tonic-gate 					c = 'A';
39670Sstevel@tonic-gate 					break;
39680Sstevel@tonic-gate 				default:
39690Sstevel@tonic-gate 					c = '?';
39700Sstevel@tonic-gate 					if (!override)
39710Sstevel@tonic-gate 						goto empty;
39720Sstevel@tonic-gate 
39730Sstevel@tonic-gate 				}
39740Sstevel@tonic-gate 				printf("i#: ");
39750Sstevel@tonic-gate 				print(temp, 12, -8, 0);
39760Sstevel@tonic-gate 				printf("   md: ");
39770Sstevel@tonic-gate 				printf("%c", c);
39780Sstevel@tonic-gate 				for (mode = mode << 4; *++p; mode = mode << 1) {
39790Sstevel@tonic-gate 					if (mode & IFREG)
39800Sstevel@tonic-gate 						printf("%c", *p);
39810Sstevel@tonic-gate 					else
39820Sstevel@tonic-gate 						printf("-");
39830Sstevel@tonic-gate 				}
39840Sstevel@tonic-gate 				printf("  uid: ");
39850Sstevel@tonic-gate 				print(ip->di_uid, 8, -4, 0);
39860Sstevel@tonic-gate 				printf("      gid: ");
39870Sstevel@tonic-gate 				print(ip->di_gid, 8, -4, 0);
39880Sstevel@tonic-gate 				printf("\n");
39890Sstevel@tonic-gate 				printf("ln: ");
39900Sstevel@tonic-gate 				print((long)ip->di_nlink, 8, -4, 0);
39910Sstevel@tonic-gate 				printf("       bs: ");
39920Sstevel@tonic-gate 				print(ip->di_blocks, 12, -8, 0);
39930Sstevel@tonic-gate 				printf("c_flags : ");
39940Sstevel@tonic-gate 				print(ip->di_cflags, 12, -8, 0);
3995*12875SJohn.Zolnowsky@Sun.COM 				printf("   sz : ");
39960Sstevel@tonic-gate #ifdef _LARGEFILE64_SOURCE
39970Sstevel@tonic-gate 				printll(ip->di_size, 20, -16, 0);
39980Sstevel@tonic-gate #else /* !_LARGEFILE64_SOURCE */
39990Sstevel@tonic-gate 				print(ip->di_size, 12, -8, 0);
40000Sstevel@tonic-gate #endif /* _LARGEFILE64_SOURCE */
40010Sstevel@tonic-gate 				if (ip->di_shadow) {
40020Sstevel@tonic-gate 					printf("   si: ");
40030Sstevel@tonic-gate 					print(ip->di_shadow, 12, -8, 0);
40040Sstevel@tonic-gate 				}
40050Sstevel@tonic-gate 				printf("\n");
40060Sstevel@tonic-gate 				if (ip->di_oeftflag) {
40070Sstevel@tonic-gate 					printf("ai: ");
40080Sstevel@tonic-gate 					print(ip->di_oeftflag, 12, -8, 0);
40090Sstevel@tonic-gate 					printf("\n");
40100Sstevel@tonic-gate 				}
40110Sstevel@tonic-gate 				printf("\n");
40120Sstevel@tonic-gate 				switch (ip->di_mode & IFMT) {
40130Sstevel@tonic-gate 				case IFBLK:
40140Sstevel@tonic-gate 				case IFCHR:
40150Sstevel@tonic-gate 					printf("maj: ");
40160Sstevel@tonic-gate 					print(major(ip->di_ordev), 4, -2, 0);
40170Sstevel@tonic-gate 					printf("  min: ");
40180Sstevel@tonic-gate 					print(minor(ip->di_ordev), 4, -2, 0);
40190Sstevel@tonic-gate 					printf("\n");
40200Sstevel@tonic-gate 					break;
40210Sstevel@tonic-gate 				default:
40220Sstevel@tonic-gate 					/*
40230Sstevel@tonic-gate 					 * only display blocks below the
40240Sstevel@tonic-gate 					 * current file size
40250Sstevel@tonic-gate 					 */
40260Sstevel@tonic-gate 					curoff = 0LL;
40270Sstevel@tonic-gate 					for (i = 0; i < NDADDR; ) {
40280Sstevel@tonic-gate 						if (ip->di_size <= curoff)
40290Sstevel@tonic-gate 							break;
40300Sstevel@tonic-gate 						printf("db#%x: ", i);
40310Sstevel@tonic-gate 						print(ip->di_db[i], 11, -8, 0);
40320Sstevel@tonic-gate 
40330Sstevel@tonic-gate 						if (++i % 4 == 0)
40340Sstevel@tonic-gate 							printf("\n");
40350Sstevel@tonic-gate 						else
40360Sstevel@tonic-gate 							printf("  ");
40370Sstevel@tonic-gate 						curoff += fs->fs_bsize;
40380Sstevel@tonic-gate 					}
40390Sstevel@tonic-gate 					if (i % 4)
40400Sstevel@tonic-gate 						printf("\n");
40410Sstevel@tonic-gate 
40420Sstevel@tonic-gate 					/*
40430Sstevel@tonic-gate 					 * curioff keeps track of the number
40440Sstevel@tonic-gate 					 * of bytes covered by each indirect
40450Sstevel@tonic-gate 					 * pointer in the inode, and is added
40460Sstevel@tonic-gate 					 * to curoff each time to get the
40470Sstevel@tonic-gate 					 * actual offset into the file.
40480Sstevel@tonic-gate 					 */
40490Sstevel@tonic-gate 					curioff = fs->fs_bsize *
40500Sstevel@tonic-gate 					    (fs->fs_bsize / sizeof (daddr_t));
40510Sstevel@tonic-gate 					for (i = 0; i < NIADDR; i++) {
40520Sstevel@tonic-gate 						if (ip->di_size <= curoff)
40530Sstevel@tonic-gate 							break;
40540Sstevel@tonic-gate 						printf("ib#%x: ", i);
40550Sstevel@tonic-gate 						print(ip->di_ib[i], 11, -8, 0);
40560Sstevel@tonic-gate 						printf("  ");
40570Sstevel@tonic-gate 						curoff += curioff;
40580Sstevel@tonic-gate 						curioff *= (fs->fs_bsize /
40590Sstevel@tonic-gate 						    sizeof (daddr_t));
40600Sstevel@tonic-gate 					}
40610Sstevel@tonic-gate 					if (i)
40620Sstevel@tonic-gate 						printf("\n");
40630Sstevel@tonic-gate 					break;
40640Sstevel@tonic-gate 				}
40650Sstevel@tonic-gate 				if (count == 1) {
40660Sstevel@tonic-gate 					time_t t;
40670Sstevel@tonic-gate 
40680Sstevel@tonic-gate 					t = ip->di_atime;
40690Sstevel@tonic-gate 					printf("\taccessed: %s", ctime(&t));
40700Sstevel@tonic-gate 					t = ip->di_mtime;
40710Sstevel@tonic-gate 					printf("\tmodified: %s", ctime(&t));
40720Sstevel@tonic-gate 					t = ip->di_ctime;
40730Sstevel@tonic-gate 					printf("\tcreated : %s", ctime(&t));
40740Sstevel@tonic-gate 				}
40750Sstevel@tonic-gate 				if (tcount)
40760Sstevel@tonic-gate 					printf("\n");
40770Sstevel@tonic-gate empty:
40780Sstevel@tonic-gate 				if (c == '?' && !override) {
40790Sstevel@tonic-gate 					printf("i#: ");
40800Sstevel@tonic-gate 					print(temp, 12, -8, 0);
40810Sstevel@tonic-gate 					printf("  is unallocated\n");
40820Sstevel@tonic-gate 					if (count != 1)
40830Sstevel@tonic-gate 						printf("\n");
40840Sstevel@tonic-gate 				}
40850Sstevel@tonic-gate 				cur_ino = erraddr = addr;
40860Sstevel@tonic-gate 				errcur_bytes = cur_bytes;
40870Sstevel@tonic-gate 				cur_inum++;
40880Sstevel@tonic-gate 				addr = addr + INODE;
40890Sstevel@tonic-gate 			}
40900Sstevel@tonic-gate 			addr = erraddr;
40910Sstevel@tonic-gate 			cur_bytes = errcur_bytes;
40920Sstevel@tonic-gate 			cur_inum--;
40930Sstevel@tonic-gate 			if (end) {
40940Sstevel@tonic-gate 				printf("end of block\n");
40950Sstevel@tonic-gate 				error++;
40960Sstevel@tonic-gate 			}
40970Sstevel@tonic-gate 			return;
40980Sstevel@tonic-gate 
40990Sstevel@tonic-gate 		case 's': /* print as super block */
41000Sstevel@tonic-gate 			if (cur_cgrp == -1) {
41010Sstevel@tonic-gate 				addr = SBLOCK * DEV_BSIZE;
41020Sstevel@tonic-gate 				type = NUMB;
41030Sstevel@tonic-gate 			}
41040Sstevel@tonic-gate 			addr &= ~(LONG - 1);
41050Sstevel@tonic-gate 			if (type != NUMB)
41060Sstevel@tonic-gate 				if (cur_cgrp + count > fs->fs_ncg) {
41070Sstevel@tonic-gate 					tcount = fs->fs_ncg - cur_cgrp;
41080Sstevel@tonic-gate 					if (!star)
41090Sstevel@tonic-gate 						end++;
41100Sstevel@tonic-gate 				}
41110Sstevel@tonic-gate 			for (/* void */; tcount--; /* void */) {
41120Sstevel@tonic-gate 				erraddr = addr;
41130Sstevel@tonic-gate 				cur_bytes = errcur_bytes;
41140Sstevel@tonic-gate 				if (type != NUMB) {
41150Sstevel@tonic-gate 					addr = cgsblock(fs, cur_cgrp)
41160Sstevel@tonic-gate 							<< FRGSHIFT;
41170Sstevel@tonic-gate 					cur_cgrp++;
41180Sstevel@tonic-gate 				}
41190Sstevel@tonic-gate 				if ((cptr = getblk(addr)) == 0) {
41200Sstevel@tonic-gate 					if (cur_cgrp)
41210Sstevel@tonic-gate 						cur_cgrp--;
41220Sstevel@tonic-gate 					return;
41230Sstevel@tonic-gate 				}
41240Sstevel@tonic-gate 				cptr += blkoff(fs, addr);
41250Sstevel@tonic-gate 				/*LINTED*/
41260Sstevel@tonic-gate 				sb = (struct fs *)cptr;
41270Sstevel@tonic-gate 				if (type == NUMB) {
41280Sstevel@tonic-gate 					for (i = 0; i < fs->fs_ncg; i++)
41290Sstevel@tonic-gate 						if (addr == cgsblock(fs, i) <<
41300Sstevel@tonic-gate 								FRGSHIFT)
41310Sstevel@tonic-gate 							break;
41320Sstevel@tonic-gate 					if (i == fs->fs_ncg)
41330Sstevel@tonic-gate 						cur_cgrp = 0;
41340Sstevel@tonic-gate 					else
41350Sstevel@tonic-gate 						cur_cgrp = i + 1;
41360Sstevel@tonic-gate 					type = objsz = SB;
41370Sstevel@tonic-gate 					if (cur_cgrp + count - 1 > fs->fs_ncg) {
41380Sstevel@tonic-gate 						tcount = fs->fs_ncg - cur_cgrp;
41390Sstevel@tonic-gate 						if (!star)
41400Sstevel@tonic-gate 							end++;
41410Sstevel@tonic-gate 					}
41420Sstevel@tonic-gate 				}
41430Sstevel@tonic-gate 				if ((sb->fs_magic != FS_MAGIC) &&
41440Sstevel@tonic-gate 				    (sb->fs_magic != MTB_UFS_MAGIC)) {
41450Sstevel@tonic-gate 					cur_cgrp = 0;
41460Sstevel@tonic-gate 					if (!override) {
41470Sstevel@tonic-gate 						printf("invalid super block ");
41480Sstevel@tonic-gate 						printf("magic word\n");
41490Sstevel@tonic-gate 						cur_cgrp--;
41500Sstevel@tonic-gate 						error++;
41510Sstevel@tonic-gate 						return;
41520Sstevel@tonic-gate 					}
41530Sstevel@tonic-gate 				}
4154757Svsakar 				if (sb->fs_magic == FS_MAGIC &&
4155757Svsakar 				    (sb->fs_version !=
4156757Svsakar 					UFS_EFISTYLE4NONEFI_VERSION_2 &&
4157757Svsakar 				    sb->fs_version != UFS_VERSION_MIN)) {
4158757Svsakar 					cur_cgrp = 0;
4159757Svsakar 					if (!override) {
4160757Svsakar 						printf("invalid super block ");
4161757Svsakar 						printf("version number\n");
4162757Svsakar 						cur_cgrp--;
4163757Svsakar 						error++;
4164757Svsakar 						return;
4165757Svsakar 					}
4166757Svsakar 				}
41670Sstevel@tonic-gate 				if (sb->fs_magic == MTB_UFS_MAGIC &&
41680Sstevel@tonic-gate 				    (sb->fs_version > MTB_UFS_VERSION_1 ||
41690Sstevel@tonic-gate 				    sb->fs_version < MTB_UFS_VERSION_MIN)) {
41700Sstevel@tonic-gate 					cur_cgrp = 0;
41710Sstevel@tonic-gate 					if (!override) {
41720Sstevel@tonic-gate 						printf("invalid super block ");
4173757Svsakar 						printf("version number\n");
41740Sstevel@tonic-gate 						cur_cgrp--;
41750Sstevel@tonic-gate 						error++;
41760Sstevel@tonic-gate 						return;
41770Sstevel@tonic-gate 					}
41780Sstevel@tonic-gate 				}
41790Sstevel@tonic-gate 				if (cur_cgrp == 0)
41800Sstevel@tonic-gate 					printf("\tsuper block:\n");
41810Sstevel@tonic-gate 				else {
41820Sstevel@tonic-gate 					printf("\tsuper block in cylinder ");
41830Sstevel@tonic-gate 					printf("group ");
41840Sstevel@tonic-gate 					print(cur_cgrp - 1, 0, 0, 0);
41850Sstevel@tonic-gate 					printf(":\n");
41860Sstevel@tonic-gate 				}
41870Sstevel@tonic-gate 				printsb(sb);
41880Sstevel@tonic-gate 				if (tcount)
41890Sstevel@tonic-gate 					printf("\n");
41900Sstevel@tonic-gate 			}
41910Sstevel@tonic-gate 			cur_cgrp--;
41920Sstevel@tonic-gate 			if (end) {
41930Sstevel@tonic-gate 				printf("end of super blocks\n");
41940Sstevel@tonic-gate 				error++;
41950Sstevel@tonic-gate 			}
41960Sstevel@tonic-gate 			return;
41970Sstevel@tonic-gate 
41980Sstevel@tonic-gate 		case 'S': /* print as shadow data */
41990Sstevel@tonic-gate 			if (type == NUMB) {
42000Sstevel@tonic-gate 				type = FRAGMENT;
42010Sstevel@tonic-gate 				cur_shad = 0;
42020Sstevel@tonic-gate 				cur_bytes = fragoff(fs, addr);
42030Sstevel@tonic-gate 				bod_addr = addr - cur_bytes;
42040Sstevel@tonic-gate 				/* no more than two fragments */
42050Sstevel@tonic-gate 				filesize = fragroundup(fs,
42060Sstevel@tonic-gate 				    bod_addr + FRGSIZE + 1);
42070Sstevel@tonic-gate 			}
42080Sstevel@tonic-gate 			objsz = SHADOW_DATA;
42090Sstevel@tonic-gate 			while (tcount-- &&
42100Sstevel@tonic-gate 			    (cur_bytes + SHADOW_DATA) <= filesize &&
42110Sstevel@tonic-gate 			    (type != SHADOW_DATA ||
42120Sstevel@tonic-gate 			    (cur_bytes + SHADOW_DATA)) <= blocksize) {
42130Sstevel@tonic-gate 				/*LINTED*/
42140Sstevel@tonic-gate 				struct ufs_fsd fsd;
42150Sstevel@tonic-gate 				long tcur_bytes;
42160Sstevel@tonic-gate 
42170Sstevel@tonic-gate 				taddr = addr;
42180Sstevel@tonic-gate 				tcur_bytes = cur_bytes;
42190Sstevel@tonic-gate 				index(base);
42200Sstevel@tonic-gate 				getshadowdata((long *)&fsd, LONG + LONG);
42210Sstevel@tonic-gate 				printf("  type: ");
42220Sstevel@tonic-gate 				print((long)fsd.fsd_type, 8, -8, 0);
42230Sstevel@tonic-gate 				printf("  size: ");
42240Sstevel@tonic-gate 				print((long)fsd.fsd_size, 8, -8, 0);
42250Sstevel@tonic-gate 				tbase = fsd.fsd_size - LONG - LONG;
42260Sstevel@tonic-gate 				if (tbase > 256)
42270Sstevel@tonic-gate 					tbase = 256;
42280Sstevel@tonic-gate 				for (i = 0; i < tbase; i++) {
42290Sstevel@tonic-gate 					if (i % LONG == 0) {
42300Sstevel@tonic-gate 						if (i % 16 == 0) {
42310Sstevel@tonic-gate 							printf("\n");
42320Sstevel@tonic-gate 							index(base);
42330Sstevel@tonic-gate 						} else
42340Sstevel@tonic-gate 							printf("  ");
42350Sstevel@tonic-gate 						getshadowdata(&temp, LONG);
42360Sstevel@tonic-gate 						p = (char *)&temp;
42370Sstevel@tonic-gate 					} else
42380Sstevel@tonic-gate 						printf(" ");
42390Sstevel@tonic-gate 					printf("%02x", (int)(*p++ & 0377L));
42400Sstevel@tonic-gate 				}
42410Sstevel@tonic-gate 				printf("\n");
42420Sstevel@tonic-gate 				addr = taddr;
42430Sstevel@tonic-gate 				cur_bytes = tcur_bytes;
42440Sstevel@tonic-gate 				erraddr = addr;
42450Sstevel@tonic-gate 				errcur_bytes = cur_bytes;
42460Sstevel@tonic-gate 				addr += FSD_RECSZ((&fsd), fsd.fsd_size);
42470Sstevel@tonic-gate 				cur_bytes += FSD_RECSZ((&fsd), fsd.fsd_size);
42480Sstevel@tonic-gate 				cur_shad++;
42490Sstevel@tonic-gate 				syncshadowscan(0);
42500Sstevel@tonic-gate 			}
42510Sstevel@tonic-gate 			addr = erraddr;
42520Sstevel@tonic-gate 			cur_bytes = errcur_bytes;
42530Sstevel@tonic-gate 			cur_shad--;
42540Sstevel@tonic-gate 			if (tcount >= 0 && !star) {
42550Sstevel@tonic-gate 				switch (type) {
42560Sstevel@tonic-gate 				case FRAGMENT:
42570Sstevel@tonic-gate 					printf("end of fragment\n");
42580Sstevel@tonic-gate 					break;
42590Sstevel@tonic-gate 				default:
42600Sstevel@tonic-gate 					printf("end of shadow data\n");
42610Sstevel@tonic-gate 				}
42620Sstevel@tonic-gate 				error++;
42630Sstevel@tonic-gate 			} else
42640Sstevel@tonic-gate 				error = 0;
42650Sstevel@tonic-gate 			return;
42660Sstevel@tonic-gate 		default:
42670Sstevel@tonic-gate 			error++;
42680Sstevel@tonic-gate 			printf("no such print option\n");
42690Sstevel@tonic-gate 			return;
42700Sstevel@tonic-gate 		}
42710Sstevel@tonic-gate }
42720Sstevel@tonic-gate 
42730Sstevel@tonic-gate /*
42740Sstevel@tonic-gate  * valid_addr - call check_addr to validate the current address.
42750Sstevel@tonic-gate  */
42760Sstevel@tonic-gate static int
valid_addr()42770Sstevel@tonic-gate valid_addr()
42780Sstevel@tonic-gate {
42790Sstevel@tonic-gate 	short	end = 0, eof = 0;
42800Sstevel@tonic-gate 	long	tcount = count;
42810Sstevel@tonic-gate 
42820Sstevel@tonic-gate 	if (!trapped)
42830Sstevel@tonic-gate 		return (1);
42840Sstevel@tonic-gate 	if (cur_bytes < 0) {
42850Sstevel@tonic-gate 		cur_bytes = 0;
42860Sstevel@tonic-gate 		if (blocksize > filesize) {
42870Sstevel@tonic-gate 			printf("beginning of file\n");
42880Sstevel@tonic-gate 		} else {
42890Sstevel@tonic-gate 			if (type == BLOCK)
42900Sstevel@tonic-gate 				printf("beginning of block\n");
42910Sstevel@tonic-gate 			else
42920Sstevel@tonic-gate 				printf("beginning of fragment\n");
42930Sstevel@tonic-gate 		}
42940Sstevel@tonic-gate 		error++;
42950Sstevel@tonic-gate 		return (0);
42960Sstevel@tonic-gate 	}
42970Sstevel@tonic-gate 	count = 1;
42980Sstevel@tonic-gate 	(void) check_addr(1, &end, &eof, (filesize < blocksize));
42990Sstevel@tonic-gate 	count = tcount;
43000Sstevel@tonic-gate 	if (eof) {
43010Sstevel@tonic-gate 		printf("end of file\n");
43020Sstevel@tonic-gate 		error++;
43030Sstevel@tonic-gate 		return (0);
43040Sstevel@tonic-gate 	}
43050Sstevel@tonic-gate 	if (end == 2) {
43060Sstevel@tonic-gate 		if (erraddr > addr) {
43070Sstevel@tonic-gate 			if (type == BLOCK)
43080Sstevel@tonic-gate 				printf("beginning of block\n");
43090Sstevel@tonic-gate 			else
43100Sstevel@tonic-gate 				printf("beginning of fragment\n");
43110Sstevel@tonic-gate 			error++;
43120Sstevel@tonic-gate 			return (0);
43130Sstevel@tonic-gate 		}
43140Sstevel@tonic-gate 	}
43150Sstevel@tonic-gate 	if (end) {
43160Sstevel@tonic-gate 		if (type == BLOCK)
43170Sstevel@tonic-gate 			printf("end of block\n");
43180Sstevel@tonic-gate 		else
43190Sstevel@tonic-gate 			printf("end of fragment\n");
43200Sstevel@tonic-gate 		error++;
43210Sstevel@tonic-gate 		return (0);
43220Sstevel@tonic-gate 	}
43230Sstevel@tonic-gate 	return (1);
43240Sstevel@tonic-gate }
43250Sstevel@tonic-gate 
43260Sstevel@tonic-gate /*
43270Sstevel@tonic-gate  * check_addr - check if the address crosses the end of block or
43280Sstevel@tonic-gate  *	end of file.  Return the proper count.
43290Sstevel@tonic-gate  */
43300Sstevel@tonic-gate static int
check_addr(short eof_flag,short * end,short * eof,short keep_on)43311051Smaheshvs check_addr(short eof_flag, short *end, short *eof, short keep_on)
43320Sstevel@tonic-gate {
43330Sstevel@tonic-gate 	long	temp, tcount = count, tcur_bytes = cur_bytes;
43340Sstevel@tonic-gate 	u_offset_t	taddr = addr;
43350Sstevel@tonic-gate 
43360Sstevel@tonic-gate 	if (bcomp(addr + count * objsz - 1) ||
43370Sstevel@tonic-gate 	    (keep_on && taddr < (bmap(cur_block) << FRGSHIFT))) {
43380Sstevel@tonic-gate 		error = 0;
43390Sstevel@tonic-gate 		addr = taddr;
43400Sstevel@tonic-gate 		cur_bytes = tcur_bytes;
43410Sstevel@tonic-gate 		if (keep_on) {
43420Sstevel@tonic-gate 			if (addr < erraddr) {
43430Sstevel@tonic-gate 				if (cur_bytes < 0) {
43440Sstevel@tonic-gate 					(*end) = 2;
43450Sstevel@tonic-gate 					return (0);	/* Value ignored */
43460Sstevel@tonic-gate 				}
43470Sstevel@tonic-gate 				temp = cur_block - lblkno(fs, cur_bytes);
43480Sstevel@tonic-gate 				cur_block -= temp;
43490Sstevel@tonic-gate 				if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
43500Sstevel@tonic-gate 					cur_block += temp;
43510Sstevel@tonic-gate 					return (0);	/* Value ignored */
43520Sstevel@tonic-gate 				}
43530Sstevel@tonic-gate 				temp = tcur_bytes - cur_bytes;
43540Sstevel@tonic-gate 				addr += temp;
43550Sstevel@tonic-gate 				cur_bytes += temp;
43560Sstevel@tonic-gate 				return (0);	/* Value ignored */
43570Sstevel@tonic-gate 			} else {
43580Sstevel@tonic-gate 				if (cur_bytes >= filesize) {
43590Sstevel@tonic-gate 					(*eof)++;
43600Sstevel@tonic-gate 					return (0);	/* Value ignored */
43610Sstevel@tonic-gate 				}
43620Sstevel@tonic-gate 				temp = lblkno(fs, cur_bytes) - cur_block;
43630Sstevel@tonic-gate 				cur_block += temp;
43640Sstevel@tonic-gate 				if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
43650Sstevel@tonic-gate 					cur_block -= temp;
43660Sstevel@tonic-gate 					return (0);	/* Value ignored */
43670Sstevel@tonic-gate 				}
43680Sstevel@tonic-gate 				temp = tcur_bytes - cur_bytes;
43690Sstevel@tonic-gate 				addr += temp;
43700Sstevel@tonic-gate 				cur_bytes += temp;
43710Sstevel@tonic-gate 				return (0);	/* Value ignored */
43720Sstevel@tonic-gate 			}
43730Sstevel@tonic-gate 		}
43740Sstevel@tonic-gate 		tcount = (blkroundup(fs, addr+1)-addr) / objsz;
43750Sstevel@tonic-gate 		if (!star)
43760Sstevel@tonic-gate 			(*end) = 2;
43770Sstevel@tonic-gate 	}
43780Sstevel@tonic-gate 	addr = taddr;
43790Sstevel@tonic-gate 	cur_bytes = tcur_bytes;
43800Sstevel@tonic-gate 	if (eof_flag) {
43810Sstevel@tonic-gate 		if (blocksize > filesize) {
43820Sstevel@tonic-gate 			if (cur_bytes >= filesize) {
43830Sstevel@tonic-gate 				tcount = 0;
43840Sstevel@tonic-gate 				(*eof)++;
43850Sstevel@tonic-gate 			} else if (tcount > (filesize - cur_bytes) / objsz) {
43860Sstevel@tonic-gate 				tcount = (filesize - cur_bytes) / objsz;
43870Sstevel@tonic-gate 				if (!star || tcount == 0)
43880Sstevel@tonic-gate 					(*eof)++;
43890Sstevel@tonic-gate 			}
43900Sstevel@tonic-gate 		} else {
43910Sstevel@tonic-gate 			if (cur_bytes >= blocksize) {
43920Sstevel@tonic-gate 				tcount = 0;
43930Sstevel@tonic-gate 				(*end)++;
43940Sstevel@tonic-gate 			} else if (tcount > (blocksize - cur_bytes) / objsz) {
43950Sstevel@tonic-gate 				tcount = (blocksize - cur_bytes) / objsz;
43960Sstevel@tonic-gate 				if (!star || tcount == 0)
43970Sstevel@tonic-gate 					(*end)++;
43980Sstevel@tonic-gate 			}
43990Sstevel@tonic-gate 		}
44000Sstevel@tonic-gate 	}
44010Sstevel@tonic-gate 	return (tcount);
44020Sstevel@tonic-gate }
44030Sstevel@tonic-gate 
44040Sstevel@tonic-gate /*
44050Sstevel@tonic-gate  * print_check - check if the index needs to be printed and delete
44060Sstevel@tonic-gate  *	rows of zeros from the output.
44070Sstevel@tonic-gate  */
44080Sstevel@tonic-gate unsigned long *
print_check(unsigned long * lptr,long * tcount,short tbase,int i)44091051Smaheshvs print_check(unsigned long *lptr, long *tcount, short tbase, int i)
44100Sstevel@tonic-gate {
44111051Smaheshvs 	int		j, k, temp = BYTESPERLINE / objsz;
44120Sstevel@tonic-gate 	short		first_time = 0;
44130Sstevel@tonic-gate 	unsigned long	*tlptr;
44140Sstevel@tonic-gate 	unsigned short	*tsptr, *sptr;
44150Sstevel@tonic-gate 
44160Sstevel@tonic-gate 	sptr = (unsigned short *)lptr;
44170Sstevel@tonic-gate 	if (i == 0)
44180Sstevel@tonic-gate 		first_time = 1;
44190Sstevel@tonic-gate 	if (i % temp == 0) {
44200Sstevel@tonic-gate 		if (*tcount >= temp - 1) {
44210Sstevel@tonic-gate 			if (objsz == SHORT)
44220Sstevel@tonic-gate 				tsptr = sptr;
44230Sstevel@tonic-gate 			else
44240Sstevel@tonic-gate 				tlptr = lptr;
44250Sstevel@tonic-gate 			k = *tcount - 1;
44260Sstevel@tonic-gate 			for (j = i; k--; j++)
44270Sstevel@tonic-gate 				if (objsz == SHORT) {
44280Sstevel@tonic-gate 					if (*tsptr++ != 0)
44290Sstevel@tonic-gate 						break;
44300Sstevel@tonic-gate 				} else {
44310Sstevel@tonic-gate 					if (*tlptr++ != 0)
44320Sstevel@tonic-gate 						break;
44330Sstevel@tonic-gate 				}
44340Sstevel@tonic-gate 			if (j > (i + temp - 1)) {
44350Sstevel@tonic-gate 				j = (j - i) / temp;
44360Sstevel@tonic-gate 				while (j-- > 0) {
44370Sstevel@tonic-gate 					if (objsz == SHORT)
44380Sstevel@tonic-gate 						sptr += temp;
44390Sstevel@tonic-gate 					else
44400Sstevel@tonic-gate 						lptr += temp;
44410Sstevel@tonic-gate 					*tcount -= temp;
44420Sstevel@tonic-gate 					i += temp;
44430Sstevel@tonic-gate 					addr += BYTESPERLINE;
44440Sstevel@tonic-gate 					cur_bytes += BYTESPERLINE;
44450Sstevel@tonic-gate 				}
44460Sstevel@tonic-gate 				if (first_time)
44470Sstevel@tonic-gate 					printf("*");
44480Sstevel@tonic-gate 				else
44490Sstevel@tonic-gate 					printf("\n*");
44500Sstevel@tonic-gate 			}
44510Sstevel@tonic-gate 			if (i)
44520Sstevel@tonic-gate 				printf("\n");
44530Sstevel@tonic-gate 			index(tbase);
44540Sstevel@tonic-gate 		} else {
44550Sstevel@tonic-gate 			if (i)
44560Sstevel@tonic-gate 				printf("\n");
44570Sstevel@tonic-gate 			index(tbase);
44580Sstevel@tonic-gate 		}
44590Sstevel@tonic-gate 	}
44600Sstevel@tonic-gate 	if (objsz == SHORT)
44610Sstevel@tonic-gate 		/*LINTED*/
44620Sstevel@tonic-gate 		return ((unsigned long *)sptr);
44630Sstevel@tonic-gate 	else
44640Sstevel@tonic-gate 		return (lptr);
44650Sstevel@tonic-gate }
44660Sstevel@tonic-gate 
44670Sstevel@tonic-gate /*
44680Sstevel@tonic-gate  * index - print a byte index for the printout in base b
44690Sstevel@tonic-gate  *	with leading zeros.
44700Sstevel@tonic-gate  */
44710Sstevel@tonic-gate static void
index(int b)44721051Smaheshvs index(int b)
44730Sstevel@tonic-gate {
44740Sstevel@tonic-gate 	int	tbase = base;
44750Sstevel@tonic-gate 
44760Sstevel@tonic-gate 	base = b;
44770Sstevel@tonic-gate 	print(addr, 8, 8, 1);
44780Sstevel@tonic-gate 	printf(":\t");
44790Sstevel@tonic-gate 	base = tbase;
44800Sstevel@tonic-gate }
44810Sstevel@tonic-gate 
44820Sstevel@tonic-gate /*
44830Sstevel@tonic-gate  * print - print out the value to digits places with/without
44840Sstevel@tonic-gate  *	leading zeros and right/left justified in the current base.
44850Sstevel@tonic-gate  */
44860Sstevel@tonic-gate static void
44870Sstevel@tonic-gate #ifdef _LARGEFILE64_SOURCE
printll(u_offset_t value,int fieldsz,int digits,int lead)44880Sstevel@tonic-gate printll(u_offset_t value, int fieldsz, int digits, int lead)
44890Sstevel@tonic-gate #else /* !_LARGEFILE64_SOURCE */
44900Sstevel@tonic-gate print(long value, int fieldsz, int digits, int lead)
44910Sstevel@tonic-gate #endif /* _LARGEFILE64_SOURCE */
44920Sstevel@tonic-gate {
44931051Smaheshvs 	int	i, left = 0;
44941051Smaheshvs 	char	mode = BASE[base - OCTAL];
44951051Smaheshvs 	char	*string = &scratch[0];
44960Sstevel@tonic-gate 
44970Sstevel@tonic-gate 	if (digits < 0) {
44980Sstevel@tonic-gate 		left = 1;
44990Sstevel@tonic-gate 		digits *= -1;
45000Sstevel@tonic-gate 	}
45010Sstevel@tonic-gate 	if (base != HEX)
45020Sstevel@tonic-gate 		if (digits)
45030Sstevel@tonic-gate 			digits = digits + (digits - 1)/((base >> 1) - 1) + 1;
45040Sstevel@tonic-gate 		else
45050Sstevel@tonic-gate 			digits = 1;
45060Sstevel@tonic-gate 	if (lead) {
45070Sstevel@tonic-gate 		if (left)
45080Sstevel@tonic-gate 			(void) sprintf(string, "%%%c%d%d.%d"
45090Sstevel@tonic-gate #ifdef _LARGEFILE64_SOURCE
45100Sstevel@tonic-gate 				"ll"
45110Sstevel@tonic-gate #endif /* _LARGEFILE64_SOURCE */
45120Sstevel@tonic-gate 				"%c", '-', 0, digits, lead, mode);
45130Sstevel@tonic-gate 		else
45140Sstevel@tonic-gate 			(void) sprintf(string, "%%%d%d.%d"
45150Sstevel@tonic-gate #ifdef _LARGEFILE64_SOURCE
45160Sstevel@tonic-gate 				"ll"
45170Sstevel@tonic-gate #endif /* _LARGEFILE64_SOURCE */
45180Sstevel@tonic-gate 				"%c", 0, digits, lead, mode);
45190Sstevel@tonic-gate 	} else {
45200Sstevel@tonic-gate 		if (left)
45210Sstevel@tonic-gate 			(void) sprintf(string, "%%%c%d"
45220Sstevel@tonic-gate #ifdef _LARGEFILE64_SOURCE
45230Sstevel@tonic-gate 				"ll"
45240Sstevel@tonic-gate #endif /* _LARGEFILE64_SOURCE */
45250Sstevel@tonic-gate 				"%c", '-', digits, mode);
45260Sstevel@tonic-gate 		else
45270Sstevel@tonic-gate 			(void) sprintf(string, "%%%d"
45280Sstevel@tonic-gate #ifdef _LARGEFILE64_SOURCE
45290Sstevel@tonic-gate 				"ll"
45300Sstevel@tonic-gate #endif /* _LARGEFILE64_SOURCE */
45310Sstevel@tonic-gate 				"%c", digits, mode);
45320Sstevel@tonic-gate 	}
45330Sstevel@tonic-gate 	printf(string, value);
45340Sstevel@tonic-gate 	for (i = 0; i < fieldsz - digits; i++)
45350Sstevel@tonic-gate 		printf(" ");
45360Sstevel@tonic-gate }
45370Sstevel@tonic-gate 
45380Sstevel@tonic-gate /*
45390Sstevel@tonic-gate  * Print out the contents of a superblock.
45400Sstevel@tonic-gate  */
45410Sstevel@tonic-gate static void
printsb(struct fs * fs)45421051Smaheshvs printsb(struct fs *fs)
45430Sstevel@tonic-gate {
45440Sstevel@tonic-gate 	int c, i, j, k, size;
45450Sstevel@tonic-gate 	caddr_t sip;
45460Sstevel@tonic-gate 	time_t t;
45470Sstevel@tonic-gate 
45480Sstevel@tonic-gate 	t = fs->fs_time;
45490Sstevel@tonic-gate #ifdef FS_42POSTBLFMT
45500Sstevel@tonic-gate 	if (fs->fs_postblformat == FS_42POSTBLFMT)
45510Sstevel@tonic-gate 		fs->fs_nrpos = 8;
45520Sstevel@tonic-gate 	printf("magic\t%lx\tformat\t%s\ttime\t%s", fs->fs_magic,
45530Sstevel@tonic-gate 	    fs->fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic",
45540Sstevel@tonic-gate 	    ctime(&t));
45550Sstevel@tonic-gate #else
45560Sstevel@tonic-gate 	printf("magic\t%x\ttime\t%s",
45570Sstevel@tonic-gate 	    fs->fs_magic, ctime(&t));
45580Sstevel@tonic-gate #endif
4559757Svsakar 	printf("version\t%x\n", fs->fs_version);
45600Sstevel@tonic-gate 	printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
45610Sstevel@tonic-gate 	    fs->fs_cstotal.cs_nbfree, fs->fs_cstotal.cs_ndir,
45620Sstevel@tonic-gate 	    fs->fs_cstotal.cs_nifree, fs->fs_cstotal.cs_nffree);
45630Sstevel@tonic-gate 	printf("ncg\t%ld\tncyl\t%ld\tsize\t%ld\tblocks\t%ld\n",
45640Sstevel@tonic-gate 	    fs->fs_ncg, fs->fs_ncyl, fs->fs_size, fs->fs_dsize);
45650Sstevel@tonic-gate 	printf("bsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
45660Sstevel@tonic-gate 	    fs->fs_bsize, fs->fs_bshift, fs->fs_bmask);
45670Sstevel@tonic-gate 	printf("fsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
45680Sstevel@tonic-gate 	    fs->fs_fsize, fs->fs_fshift, fs->fs_fmask);
45690Sstevel@tonic-gate 	printf("frag\t%ld\tshift\t%ld\tfsbtodb\t%ld\n",
45700Sstevel@tonic-gate 	    fs->fs_frag, fs->fs_fragshift, fs->fs_fsbtodb);
45710Sstevel@tonic-gate 	printf("cpg\t%ld\tbpg\t%ld\tfpg\t%ld\tipg\t%ld\n",
45720Sstevel@tonic-gate 	    fs->fs_cpg, fs->fs_fpg / fs->fs_frag, fs->fs_fpg, fs->fs_ipg);
45730Sstevel@tonic-gate 	printf("minfree\t%ld%%\toptim\t%s\tmaxcontig %ld\tmaxbpg\t%ld\n",
45740Sstevel@tonic-gate 	    fs->fs_minfree, fs->fs_optim == FS_OPTSPACE ? "space" : "time",
45750Sstevel@tonic-gate 	    fs->fs_maxcontig, fs->fs_maxbpg);
45760Sstevel@tonic-gate #ifdef FS_42POSTBLFMT
45770Sstevel@tonic-gate #ifdef sun
45780Sstevel@tonic-gate 	printf("rotdelay %ldms\tfs_id[0] 0x%lx\tfs_id[1] 0x%lx\trps\t%ld\n",
45790Sstevel@tonic-gate 	    fs->fs_rotdelay, fs->fs_id[0], fs->fs_id[1], fs->fs_rps);
45800Sstevel@tonic-gate #else
45810Sstevel@tonic-gate 	printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
45820Sstevel@tonic-gate 	    fs->fs_rotdelay, fs->fs_headswitch, fs->fs_trkseek, fs->fs_rps);
45830Sstevel@tonic-gate #endif /* sun */
45840Sstevel@tonic-gate 	printf("ntrak\t%ld\tnsect\t%ld\tnpsect\t%ld\tspc\t%ld\n",
45850Sstevel@tonic-gate 	    fs->fs_ntrak, fs->fs_nsect, fs->fs_npsect, fs->fs_spc);
45860Sstevel@tonic-gate 	printf("trackskew %ld\n", fs->fs_trackskew);
45870Sstevel@tonic-gate #else
45880Sstevel@tonic-gate 	printf("rotdelay %ldms\trps\t%ld\n",
45890Sstevel@tonic-gate 	    fs->fs_rotdelay, fs->fs_rps);
45900Sstevel@tonic-gate 	printf("ntrak\t%ld\tnsect\t%ld\tspc\t%ld\n",
45910Sstevel@tonic-gate 	    fs->fs_ntrak, fs->fs_nsect, fs->fs_spc);
45920Sstevel@tonic-gate #endif
45930Sstevel@tonic-gate 	printf("si %ld\n", fs->fs_si);
45940Sstevel@tonic-gate 	printf("nindir\t%ld\tinopb\t%ld\tnspf\t%ld\n",
45950Sstevel@tonic-gate 	    fs->fs_nindir, fs->fs_inopb, fs->fs_nspf);
45960Sstevel@tonic-gate 	printf("sblkno\t%ld\tcblkno\t%ld\tiblkno\t%ld\tdblkno\t%ld\n",
45970Sstevel@tonic-gate 	    fs->fs_sblkno, fs->fs_cblkno, fs->fs_iblkno, fs->fs_dblkno);
45980Sstevel@tonic-gate 	printf("sbsize\t%ld\tcgsize\t%ld\tcgoffset %ld\tcgmask\t0x%08lx\n",
45990Sstevel@tonic-gate 	    fs->fs_sbsize, fs->fs_cgsize, fs->fs_cgoffset, fs->fs_cgmask);
46000Sstevel@tonic-gate 	printf("csaddr\t%ld\tcssize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
46010Sstevel@tonic-gate 	    fs->fs_csaddr, fs->fs_cssize, fs->fs_csshift, fs->fs_csmask);
46020Sstevel@tonic-gate 	printf("cgrotor\t%ld\tfmod\t%d\tronly\t%d\n",
46030Sstevel@tonic-gate 	    fs->fs_cgrotor, fs->fs_fmod, fs->fs_ronly);
46040Sstevel@tonic-gate #ifdef FS_42POSTBLFMT
46050Sstevel@tonic-gate 	if (fs->fs_cpc != 0)
46060Sstevel@tonic-gate 		printf("blocks available in each of %ld rotational positions",
46070Sstevel@tonic-gate 			fs->fs_nrpos);
46080Sstevel@tonic-gate 	else
46090Sstevel@tonic-gate 		printf("insufficient space to maintain rotational tables\n");
46100Sstevel@tonic-gate #endif
46110Sstevel@tonic-gate 	for (c = 0; c < fs->fs_cpc; c++) {
46120Sstevel@tonic-gate 		printf("\ncylinder number %d:", c);
46130Sstevel@tonic-gate #ifdef FS_42POSTBLFMT
46140Sstevel@tonic-gate 		for (i = 0; i < fs->fs_nrpos; i++) {
46150Sstevel@tonic-gate 			/*LINTED*/
46160Sstevel@tonic-gate 			if (fs_postbl(fs, c)[i] == -1)
46170Sstevel@tonic-gate 				continue;
46180Sstevel@tonic-gate 			printf("\n   position %d:\t", i);
46190Sstevel@tonic-gate 			/*LINTED*/
46200Sstevel@tonic-gate 			for (j = fs_postbl(fs, c)[i], k = 1; /* void */;
46210Sstevel@tonic-gate 						j += fs_rotbl(fs)[j], k++) {
46220Sstevel@tonic-gate 				printf("%5d", j);
46230Sstevel@tonic-gate 				if (k % 12 == 0)
46240Sstevel@tonic-gate 					printf("\n\t\t");
46250Sstevel@tonic-gate 				if (fs_rotbl(fs)[j] == 0)
46260Sstevel@tonic-gate 					break;
46270Sstevel@tonic-gate 			}
46280Sstevel@tonic-gate 		}
46290Sstevel@tonic-gate #else
46300Sstevel@tonic-gate 		for (i = 0; i < NRPOS; i++) {
46310Sstevel@tonic-gate 			if (fs->fs_postbl[c][i] == -1)
46320Sstevel@tonic-gate 				continue;
46330Sstevel@tonic-gate 			printf("\n   position %d:\t", i);
46340Sstevel@tonic-gate 			for (j = fs->fs_postbl[c][i], k = 1; /* void */;
46350Sstevel@tonic-gate 						j += fs->fs_rotbl[j], k++) {
46360Sstevel@tonic-gate 				printf("%5d", j);
46370Sstevel@tonic-gate 				if (k % 12 == 0)
46380Sstevel@tonic-gate 					printf("\n\t\t");
46390Sstevel@tonic-gate 				if (fs->fs_rotbl[j] == 0)
46400Sstevel@tonic-gate 					break;
46410Sstevel@tonic-gate 			}
46420Sstevel@tonic-gate 		}
46430Sstevel@tonic-gate #endif
46440Sstevel@tonic-gate 	}
46450Sstevel@tonic-gate 	printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):");
46460Sstevel@tonic-gate 	sip = calloc(1, fs->fs_cssize);
46470Sstevel@tonic-gate 	fs->fs_u.fs_csp = (struct csum *)sip;
46480Sstevel@tonic-gate 	for (i = 0, j = 0; i < fs->fs_cssize; i += fs->fs_bsize, j++) {
46490Sstevel@tonic-gate 		size = fs->fs_cssize - i < fs->fs_bsize ?
46500Sstevel@tonic-gate 		    fs->fs_cssize - i : fs->fs_bsize;
46510Sstevel@tonic-gate 		(void) llseek(fd,
46520Sstevel@tonic-gate 			(offset_t)fsbtodb(fs, (fs->fs_csaddr + j * fs->fs_frag))
46530Sstevel@tonic-gate 				* fs->fs_fsize / fsbtodb(fs, 1), 0);
46540Sstevel@tonic-gate 		if (read(fd, sip, size) != size) {
46550Sstevel@tonic-gate 			free(fs->fs_u.fs_csp);
46560Sstevel@tonic-gate 			return;
46570Sstevel@tonic-gate 		}
46580Sstevel@tonic-gate 		sip += size;
46590Sstevel@tonic-gate 	}
46600Sstevel@tonic-gate 	for (i = 0; i < fs->fs_ncg; i++) {
46610Sstevel@tonic-gate 		struct csum *cs = &fs->fs_cs(fs, i);
46620Sstevel@tonic-gate 		if (i % 4 == 0)
46630Sstevel@tonic-gate 			printf("\n     ");
46640Sstevel@tonic-gate 		printf("%d:(%ld,%ld,%ld,%ld) ", i, cs->cs_nbfree, cs->cs_ndir,
46650Sstevel@tonic-gate 						cs->cs_nifree, cs->cs_nffree);
46660Sstevel@tonic-gate 	}
46670Sstevel@tonic-gate 	free(fs->fs_u.fs_csp);
46680Sstevel@tonic-gate 	printf("\n");
46690Sstevel@tonic-gate 	if (fs->fs_ncyl % fs->fs_cpg) {
46700Sstevel@tonic-gate 		printf("cylinders in last group %d\n",
46710Sstevel@tonic-gate 		    i = fs->fs_ncyl % fs->fs_cpg);
46720Sstevel@tonic-gate 		printf("blocks in last group %ld\n",
46730Sstevel@tonic-gate 		    i * fs->fs_spc / NSPB(fs));
46740Sstevel@tonic-gate 	}
46750Sstevel@tonic-gate }
46760Sstevel@tonic-gate 
46770Sstevel@tonic-gate /*
46780Sstevel@tonic-gate  * Print out the contents of a cylinder group.
46790Sstevel@tonic-gate  */
46800Sstevel@tonic-gate static void
printcg(struct cg * cg)46811051Smaheshvs printcg(struct cg *cg)
46820Sstevel@tonic-gate {
46830Sstevel@tonic-gate 	int i, j;
46840Sstevel@tonic-gate 	time_t t;
46850Sstevel@tonic-gate 
46860Sstevel@tonic-gate 	printf("\ncg %ld:\n", cg->cg_cgx);
46870Sstevel@tonic-gate 	t = cg->cg_time;
46880Sstevel@tonic-gate #ifdef FS_42POSTBLFMT
46890Sstevel@tonic-gate 	printf("magic\t%lx\ttell\t%llx\ttime\t%s",
46900Sstevel@tonic-gate 	    fs->fs_postblformat == FS_42POSTBLFMT ?
46910Sstevel@tonic-gate 	    ((struct ocg *)cg)->cg_magic : cg->cg_magic,
46920Sstevel@tonic-gate 	    fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
46930Sstevel@tonic-gate 	    ctime(&t));
46940Sstevel@tonic-gate #else
46950Sstevel@tonic-gate 	printf("magic\t%x\ttell\t%llx\ttime\t%s",
46960Sstevel@tonic-gate 	    cg->cg_magic,
46970Sstevel@tonic-gate 	    fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
46980Sstevel@tonic-gate 	    ctime(&t));
46990Sstevel@tonic-gate #endif
47000Sstevel@tonic-gate 	printf("cgx\t%ld\tncyl\t%d\tniblk\t%d\tndblk\t%ld\n",
47010Sstevel@tonic-gate 	    cg->cg_cgx, cg->cg_ncyl, cg->cg_niblk, cg->cg_ndblk);
47020Sstevel@tonic-gate 	printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
47030Sstevel@tonic-gate 	    cg->cg_cs.cs_nbfree, cg->cg_cs.cs_ndir,
47040Sstevel@tonic-gate 	    cg->cg_cs.cs_nifree, cg->cg_cs.cs_nffree);
47050Sstevel@tonic-gate 	printf("rotor\t%ld\tirotor\t%ld\tfrotor\t%ld\nfrsum",
47060Sstevel@tonic-gate 	    cg->cg_rotor, cg->cg_irotor, cg->cg_frotor);
47070Sstevel@tonic-gate 	for (i = 1, j = 0; i < fs->fs_frag; i++) {
47080Sstevel@tonic-gate 		printf("\t%ld", cg->cg_frsum[i]);
47090Sstevel@tonic-gate 		j += i * cg->cg_frsum[i];
47100Sstevel@tonic-gate 	}
47110Sstevel@tonic-gate 	printf("\nsum of frsum: %d\niused:\t", j);
47120Sstevel@tonic-gate 	pbits((unsigned char *)cg_inosused(cg), fs->fs_ipg);
47130Sstevel@tonic-gate 	printf("free:\t");
47140Sstevel@tonic-gate 	pbits(cg_blksfree(cg), fs->fs_fpg);
47150Sstevel@tonic-gate 	printf("b:\n");
47160Sstevel@tonic-gate 	for (i = 0; i < fs->fs_cpg; i++) {
47170Sstevel@tonic-gate 		/*LINTED*/
47180Sstevel@tonic-gate 		if (cg_blktot(cg)[i] == 0)
47190Sstevel@tonic-gate 			continue;
47200Sstevel@tonic-gate 		/*LINTED*/
47210Sstevel@tonic-gate 		printf("   c%d:\t(%ld)\t", i, cg_blktot(cg)[i]);
47220Sstevel@tonic-gate #ifdef FS_42POSTBLFMT
47230Sstevel@tonic-gate 		for (j = 0; j < fs->fs_nrpos; j++) {
47240Sstevel@tonic-gate 			if (fs->fs_cpc == 0 ||
47250Sstevel@tonic-gate 				/*LINTED*/
47260Sstevel@tonic-gate 			    fs_postbl(fs, i % fs->fs_cpc)[j] == -1)
47270Sstevel@tonic-gate 				continue;
47280Sstevel@tonic-gate 			/*LINTED*/
47290Sstevel@tonic-gate 			printf(" %d", cg_blks(fs, cg, i)[j]);
47300Sstevel@tonic-gate 		}
47310Sstevel@tonic-gate #else
47320Sstevel@tonic-gate 		for (j = 0; j < NRPOS; j++) {
47330Sstevel@tonic-gate 			if (fs->fs_cpc == 0 ||
47340Sstevel@tonic-gate 			    fs->fs_postbl[i % fs->fs_cpc][j] == -1)
47350Sstevel@tonic-gate 				continue;
47360Sstevel@tonic-gate 			printf(" %d", cg->cg_b[i][j]);
47370Sstevel@tonic-gate 		}
47380Sstevel@tonic-gate #endif
47390Sstevel@tonic-gate 		printf("\n");
47400Sstevel@tonic-gate 	}
47410Sstevel@tonic-gate }
47420Sstevel@tonic-gate 
47430Sstevel@tonic-gate /*
47440Sstevel@tonic-gate  * Print out the contents of a bit array.
47450Sstevel@tonic-gate  */
47460Sstevel@tonic-gate static void
pbits(unsigned char * cp,int max)47471051Smaheshvs pbits(unsigned char *cp, int max)
47480Sstevel@tonic-gate {
47491051Smaheshvs 	int i;
47500Sstevel@tonic-gate 	int count = 0, j;
47510Sstevel@tonic-gate 
47520Sstevel@tonic-gate 	for (i = 0; i < max; i++)
47530Sstevel@tonic-gate 		if (isset(cp, i)) {
47540Sstevel@tonic-gate 			if (count)
47550Sstevel@tonic-gate 				printf(",%s", count % 6 ? " " : "\n\t");
47560Sstevel@tonic-gate 			count++;
47570Sstevel@tonic-gate 			printf("%d", i);
47580Sstevel@tonic-gate 			j = i;
47590Sstevel@tonic-gate 			while ((i+1) < max && isset(cp, i+1))
47600Sstevel@tonic-gate 				i++;
47610Sstevel@tonic-gate 			if (i != j)
47620Sstevel@tonic-gate 				printf("-%d", i);
47630Sstevel@tonic-gate 		}
47640Sstevel@tonic-gate 	printf("\n");
47650Sstevel@tonic-gate }
47660Sstevel@tonic-gate 
47670Sstevel@tonic-gate /*
47680Sstevel@tonic-gate  * bcomp - used to check for block over/under flows when stepping through
47690Sstevel@tonic-gate  *	a file system.
47700Sstevel@tonic-gate  */
47710Sstevel@tonic-gate static int
bcomp(addr)47720Sstevel@tonic-gate bcomp(addr)
47730Sstevel@tonic-gate 	u_offset_t	addr;
47740Sstevel@tonic-gate {
47750Sstevel@tonic-gate 	if (override)
47760Sstevel@tonic-gate 		return (0);
47770Sstevel@tonic-gate 
47780Sstevel@tonic-gate 	if (lblkno(fs, addr) == (bhdr.fwd)->blkno)
47790Sstevel@tonic-gate 		return (0);
47800Sstevel@tonic-gate 	error++;
47810Sstevel@tonic-gate 	return (1);
47820Sstevel@tonic-gate }
47830Sstevel@tonic-gate 
47840Sstevel@tonic-gate /*
47850Sstevel@tonic-gate  * bmap - maps the logical block number of a file into
47860Sstevel@tonic-gate  *	the corresponding physical block on the file
47870Sstevel@tonic-gate  *	system.
47880Sstevel@tonic-gate  */
47890Sstevel@tonic-gate static long
bmap(long bn)47901051Smaheshvs bmap(long bn)
47910Sstevel@tonic-gate {
47921051Smaheshvs 	int		j;
47931051Smaheshvs 	struct dinode	*ip;
47941051Smaheshvs 	int		sh;
47951051Smaheshvs 	long		nb;
47961051Smaheshvs 	char		*cptr;
47970Sstevel@tonic-gate 
47980Sstevel@tonic-gate 	if ((cptr = getblk(cur_ino)) == 0)
47990Sstevel@tonic-gate 		return (0);
48000Sstevel@tonic-gate 
48010Sstevel@tonic-gate 	cptr += blkoff(fs, cur_ino);
48020Sstevel@tonic-gate 
48030Sstevel@tonic-gate 	/*LINTED*/
48040Sstevel@tonic-gate 	ip = (struct dinode *)cptr;
48050Sstevel@tonic-gate 
48060Sstevel@tonic-gate 	if (bn < NDADDR) {
48070Sstevel@tonic-gate 		nb = ip->di_db[bn];
48080Sstevel@tonic-gate 		return (nullblk(nb) ? 0L : nb);
48090Sstevel@tonic-gate 	}
48100Sstevel@tonic-gate 
48110Sstevel@tonic-gate 	sh = 1;
48120Sstevel@tonic-gate 	bn -= NDADDR;
48130Sstevel@tonic-gate 	for (j = NIADDR; j > 0; j--) {
48140Sstevel@tonic-gate 		sh *= NINDIR(fs);
48150Sstevel@tonic-gate 		if (bn < sh)
48160Sstevel@tonic-gate 			break;
48170Sstevel@tonic-gate 		bn -= sh;
48180Sstevel@tonic-gate 	}
48190Sstevel@tonic-gate 	if (j == 0) {
48200Sstevel@tonic-gate 		printf("file too big\n");
48210Sstevel@tonic-gate 		error++;
48220Sstevel@tonic-gate 		return (0L);
48230Sstevel@tonic-gate 	}
48240Sstevel@tonic-gate 	addr = (uintptr_t)&ip->di_ib[NIADDR - j];
48250Sstevel@tonic-gate 	nb = get(LONG);
48260Sstevel@tonic-gate 	if (nb == 0)
48270Sstevel@tonic-gate 		return (0L);
48280Sstevel@tonic-gate 	for (; j <= NIADDR; j++) {
48290Sstevel@tonic-gate 		sh /= NINDIR(fs);
48300Sstevel@tonic-gate 		addr = (nb << FRGSHIFT) + ((bn / sh) % NINDIR(fs)) * LONG;
48310Sstevel@tonic-gate 		if (nullblk(nb = get(LONG)))
48320Sstevel@tonic-gate 			return (0L);
48330Sstevel@tonic-gate 	}
48340Sstevel@tonic-gate 	return (nb);
48350Sstevel@tonic-gate }
48360Sstevel@tonic-gate 
48370Sstevel@tonic-gate #if defined(OLD_FSDB_COMPATIBILITY)
48380Sstevel@tonic-gate 
48390Sstevel@tonic-gate /*
48400Sstevel@tonic-gate  * The following are "tacked on" to support the old fsdb functionality
48410Sstevel@tonic-gate  * of clearing an inode. (All together now...) "It's better to use clri".
48420Sstevel@tonic-gate  */
48430Sstevel@tonic-gate 
48440Sstevel@tonic-gate #define	ISIZE	(sizeof (struct dinode))
48450Sstevel@tonic-gate #define	NI	(MAXBSIZE/ISIZE)
48460Sstevel@tonic-gate 
48470Sstevel@tonic-gate 
48480Sstevel@tonic-gate static struct	dinode	di_buf[NI];
48490Sstevel@tonic-gate 
48500Sstevel@tonic-gate static union {
48510Sstevel@tonic-gate 	char		dummy[SBSIZE];
48520Sstevel@tonic-gate 	struct fs	sblk;
48530Sstevel@tonic-gate } sb_un;
48540Sstevel@tonic-gate 
48550Sstevel@tonic-gate #define	sblock sb_un.sblk
48560Sstevel@tonic-gate 
48570Sstevel@tonic-gate static void
old_fsdb(int inum,char * special)48581051Smaheshvs old_fsdb(int inum, char *special)
48590Sstevel@tonic-gate {
48600Sstevel@tonic-gate 	int		f;	/* File descriptor for "special" */
48610Sstevel@tonic-gate 	int		j;
48620Sstevel@tonic-gate 	int		status = 0;
48630Sstevel@tonic-gate 	u_offset_t	off;
48640Sstevel@tonic-gate 	long		gen;
48650Sstevel@tonic-gate 	time_t		t;
48660Sstevel@tonic-gate 
48670Sstevel@tonic-gate 	f = open(special, 2);
48680Sstevel@tonic-gate 	if (f < 0) {
48690Sstevel@tonic-gate 		perror("open");
48700Sstevel@tonic-gate 		printf("cannot open %s\n", special);
48710Sstevel@tonic-gate 		exit(31+4);
48720Sstevel@tonic-gate 	}
48730Sstevel@tonic-gate 	(void) llseek(f, (offset_t)SBLOCK * DEV_BSIZE, 0);
48740Sstevel@tonic-gate 	if (read(f, &sblock, SBSIZE) != SBSIZE) {
48750Sstevel@tonic-gate 		printf("cannot read %s\n", special);
48760Sstevel@tonic-gate 		exit(31+4);
48770Sstevel@tonic-gate 	}
48780Sstevel@tonic-gate 	if (sblock.fs_magic != FS_MAGIC) {
48790Sstevel@tonic-gate 		printf("bad super block magic number\n");
48800Sstevel@tonic-gate 		exit(31+4);
48810Sstevel@tonic-gate 	}
48820Sstevel@tonic-gate 	if (inum == 0) {
48830Sstevel@tonic-gate 		printf("%d: is zero\n", inum);
48840Sstevel@tonic-gate 		exit(31+1);
48850Sstevel@tonic-gate 	}
48860Sstevel@tonic-gate 	off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE;
48870Sstevel@tonic-gate 	(void) llseek(f, off, 0);
48880Sstevel@tonic-gate 	if (read(f, (char *)di_buf, sblock.fs_bsize) != sblock.fs_bsize) {
48890Sstevel@tonic-gate 		printf("%s: read error\n", special);
48900Sstevel@tonic-gate 		status = 1;
48910Sstevel@tonic-gate 	}
48920Sstevel@tonic-gate 	if (status)
48930Sstevel@tonic-gate 		exit(31+status);
48940Sstevel@tonic-gate 
48950Sstevel@tonic-gate 	/*
48960Sstevel@tonic-gate 	 * Update the time in superblock, so fsck will check this filesystem.
48970Sstevel@tonic-gate 	 */
48980Sstevel@tonic-gate 	(void) llseek(f, (offset_t)(SBLOCK * DEV_BSIZE), 0);
48990Sstevel@tonic-gate 	(void) time(&t);
49000Sstevel@tonic-gate 	sblock.fs_time = (time32_t)t;
49010Sstevel@tonic-gate 	if (write(f, &sblock, SBSIZE) != SBSIZE) {
49020Sstevel@tonic-gate 		printf("cannot update %s\n", special);
49030Sstevel@tonic-gate 		exit(35);
49040Sstevel@tonic-gate 	}
49050Sstevel@tonic-gate 
49060Sstevel@tonic-gate 	printf("clearing %u\n", inum);
49070Sstevel@tonic-gate 	off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE;
49080Sstevel@tonic-gate 	(void) llseek(f, off, 0);
49090Sstevel@tonic-gate 	read(f, (char *)di_buf, sblock.fs_bsize);
49100Sstevel@tonic-gate 	j = itoo(&sblock, inum);
49110Sstevel@tonic-gate 	gen = di_buf[j].di_gen;
49120Sstevel@tonic-gate 	(void) memset((caddr_t)&di_buf[j], 0, ISIZE);
49130Sstevel@tonic-gate 	di_buf[j].di_gen = gen + 1;
49140Sstevel@tonic-gate 	(void) llseek(f, off, 0);
49150Sstevel@tonic-gate 	write(f, (char *)di_buf, sblock.fs_bsize);
49160Sstevel@tonic-gate 	exit(31+status);
49170Sstevel@tonic-gate }
49180Sstevel@tonic-gate 
49190Sstevel@tonic-gate static int
isnumber(char * s)49201051Smaheshvs isnumber(char *s)
49210Sstevel@tonic-gate {
49220Sstevel@tonic-gate 	register int	c;
49230Sstevel@tonic-gate 
49240Sstevel@tonic-gate 	if (s == NULL)
49250Sstevel@tonic-gate 		return (0);
49260Sstevel@tonic-gate 	while ((c = *s++) != NULL)
49270Sstevel@tonic-gate 		if (c < '0' || c > '9')
49280Sstevel@tonic-gate 			return (0);
49290Sstevel@tonic-gate 	return (1);
49300Sstevel@tonic-gate }
49310Sstevel@tonic-gate #endif /* OLD_FSDB_COMPATIBILITY */
49320Sstevel@tonic-gate 
49330Sstevel@tonic-gate enum boolean { True, False };
49340Sstevel@tonic-gate extent_block_t	*log_eb;
49350Sstevel@tonic-gate ml_odunit_t	*log_odi;
49360Sstevel@tonic-gate int		lufs_tid;	/* last valid TID seen */
49370Sstevel@tonic-gate 
49380Sstevel@tonic-gate /*
49390Sstevel@tonic-gate  * no single value is safe to use to indicate
49400Sstevel@tonic-gate  * lufs_tid being invalid so we need a
49410Sstevel@tonic-gate  * seperate variable.
49420Sstevel@tonic-gate  */
49430Sstevel@tonic-gate enum boolean	lufs_tid_valid;
49440Sstevel@tonic-gate 
49450Sstevel@tonic-gate /*
49460Sstevel@tonic-gate  * log_get_header_info - get the basic info of the logging filesystem
49470Sstevel@tonic-gate  */
49480Sstevel@tonic-gate int
log_get_header_info(void)49490Sstevel@tonic-gate log_get_header_info(void)
49500Sstevel@tonic-gate {
49510Sstevel@tonic-gate 	char		*b;
49520Sstevel@tonic-gate 	int		nb;
49530Sstevel@tonic-gate 
49540Sstevel@tonic-gate 	/*
49550Sstevel@tonic-gate 	 * Mark the global tid as invalid everytime we're called to
49560Sstevel@tonic-gate 	 * prevent any false positive responses.
49570Sstevel@tonic-gate 	 */
49580Sstevel@tonic-gate 	lufs_tid_valid = False;
49590Sstevel@tonic-gate 
49600Sstevel@tonic-gate 	/*
49610Sstevel@tonic-gate 	 * See if we've already set up the header areas. The only problem
49620Sstevel@tonic-gate 	 * with this approach is we don't reread the on disk data though
49630Sstevel@tonic-gate 	 * it shouldn't matter since we don't operate on a live disk.
49640Sstevel@tonic-gate 	 */
49650Sstevel@tonic-gate 	if ((log_eb != NULL) && (log_odi != NULL))
49660Sstevel@tonic-gate 		return (1);
49670Sstevel@tonic-gate 
49680Sstevel@tonic-gate 	/*
49690Sstevel@tonic-gate 	 * Either logging is disabled or we've not running 2.7.
49700Sstevel@tonic-gate 	 */
49710Sstevel@tonic-gate 	if (fs->fs_logbno == 0) {
49720Sstevel@tonic-gate 		printf("Logging doesn't appear to be enabled on this disk\n");
49730Sstevel@tonic-gate 		return (0);
49740Sstevel@tonic-gate 	}
49750Sstevel@tonic-gate 
49760Sstevel@tonic-gate 	/*
49770Sstevel@tonic-gate 	 * To find the log we need to first pick up the block allocation
49780Sstevel@tonic-gate 	 * data. The block number for that data is fs_logbno in the
49790Sstevel@tonic-gate 	 * super block.
49800Sstevel@tonic-gate 	 */
49810Sstevel@tonic-gate 	if ((b = getblk((u_offset_t)ldbtob(logbtodb(fs, fs->fs_logbno))))
49820Sstevel@tonic-gate 	    == 0) {
49830Sstevel@tonic-gate 		printf("getblk() indicates an error with logging block\n");
49840Sstevel@tonic-gate 		return (0);
49850Sstevel@tonic-gate 	}
49860Sstevel@tonic-gate 
49870Sstevel@tonic-gate 	/*
49880Sstevel@tonic-gate 	 * Next we need to figure out how big the extent data structure
49890Sstevel@tonic-gate 	 * really is. It can't be more then fs_bsize and you could just
49900Sstevel@tonic-gate 	 * allocate that but, why get sloppy.
49910Sstevel@tonic-gate 	 * 1 is subtracted from nextents because extent_block_t contains
49920Sstevel@tonic-gate 	 * a single extent_t itself.
49930Sstevel@tonic-gate 	 */
49940Sstevel@tonic-gate 	log_eb = (extent_block_t *)b;
49950Sstevel@tonic-gate 	if (log_eb->type != LUFS_EXTENTS) {
49960Sstevel@tonic-gate 		printf("Extents block has invalid type (0x%x)\n",
49970Sstevel@tonic-gate 		    log_eb->type);
49980Sstevel@tonic-gate 		return (0);
49990Sstevel@tonic-gate 	}
50000Sstevel@tonic-gate 	nb = sizeof (extent_block_t) +
50010Sstevel@tonic-gate 	    (sizeof (extent_t) * (log_eb->nextents - 1));
50020Sstevel@tonic-gate 
50030Sstevel@tonic-gate 	log_eb = (extent_block_t *)malloc(nb);
50040Sstevel@tonic-gate 	if (log_eb == NULL) {
50050Sstevel@tonic-gate 		printf("Failed to allocate memory for extent block log\n");
50060Sstevel@tonic-gate 		return (0);
50070Sstevel@tonic-gate 	}
50080Sstevel@tonic-gate 	memcpy(log_eb, b, nb);
50090Sstevel@tonic-gate 
50100Sstevel@tonic-gate 	if (log_eb->nextbno != 0)
50110Sstevel@tonic-gate 		/*
50120Sstevel@tonic-gate 		 * Currently, as of 11-Dec-1997 the field nextbno isn't
50130Sstevel@tonic-gate 		 * implemented. If someone starts using this sucker we'd
50140Sstevel@tonic-gate 		 * better warn somebody.
50150Sstevel@tonic-gate 		 */
50160Sstevel@tonic-gate 		printf("WARNING: extent block field nextbno is non-zero!\n");
50170Sstevel@tonic-gate 
50180Sstevel@tonic-gate 	/*
50190Sstevel@tonic-gate 	 * Now read in the on disk log structure. This is always in the
50200Sstevel@tonic-gate 	 * first block of the first extent.
50210Sstevel@tonic-gate 	 */
50220Sstevel@tonic-gate 	b = getblk((u_offset_t)ldbtob(logbtodb(fs, log_eb->extents[0].pbno)));
50230Sstevel@tonic-gate 	log_odi = (ml_odunit_t *)malloc(sizeof (ml_odunit_t));
50240Sstevel@tonic-gate 	if (log_odi == NULL) {
50250Sstevel@tonic-gate 		free(log_eb);
50260Sstevel@tonic-gate 		log_eb = NULL;
50270Sstevel@tonic-gate 		printf("Failed to allocate memory for ondisk structure\n");
50280Sstevel@tonic-gate 		return (0);
50290Sstevel@tonic-gate 	}
50300Sstevel@tonic-gate 	memcpy(log_odi, b, sizeof (ml_odunit_t));
50310Sstevel@tonic-gate 
50320Sstevel@tonic-gate 	/*
50330Sstevel@tonic-gate 	 * Consistency checks.
50340Sstevel@tonic-gate 	 */
50350Sstevel@tonic-gate 	if (log_odi->od_version != LUFS_VERSION_LATEST) {
50360Sstevel@tonic-gate 		free(log_eb);
50370Sstevel@tonic-gate 		log_eb = NULL;
50380Sstevel@tonic-gate 		free(log_odi);
50390Sstevel@tonic-gate 		log_odi = NULL;
50400Sstevel@tonic-gate 		printf("Version mismatch in on-disk version of log data\n");
50410Sstevel@tonic-gate 		return (0);
50420Sstevel@tonic-gate 	} else if (log_odi->od_badlog) {
50430Sstevel@tonic-gate 		printf("WARNING: Log was marked as bad\n");
50440Sstevel@tonic-gate 	}
50450Sstevel@tonic-gate 
50460Sstevel@tonic-gate 	return (1);
50470Sstevel@tonic-gate }
50480Sstevel@tonic-gate 
50491051Smaheshvs static void
log_display_header(void)50500Sstevel@tonic-gate log_display_header(void)
50510Sstevel@tonic-gate {
50520Sstevel@tonic-gate 	int x;
50530Sstevel@tonic-gate 	if (!log_get_header_info())
50540Sstevel@tonic-gate 		/*
50550Sstevel@tonic-gate 		 * No need to display anything here. The previous routine
50560Sstevel@tonic-gate 		 * has already done so.
50570Sstevel@tonic-gate 		 */
50580Sstevel@tonic-gate 		return;
50590Sstevel@tonic-gate 
50600Sstevel@tonic-gate 	if (fs->fs_magic == FS_MAGIC)
50610Sstevel@tonic-gate 		printf("Log block number: 0x%x\n------------------\n",
50620Sstevel@tonic-gate 		    fs->fs_logbno);
50630Sstevel@tonic-gate 	else
50640Sstevel@tonic-gate 		printf("Log frag number: 0x%x\n------------------\n",
50650Sstevel@tonic-gate 		    fs->fs_logbno);
50660Sstevel@tonic-gate 	printf("Extent Info\n\t# Extents  : %d\n\t# Bytes    : 0x%x\n",
50670Sstevel@tonic-gate 	    log_eb->nextents, log_eb->nbytes);
50680Sstevel@tonic-gate 	printf("\tNext Block : 0x%x\n\tExtent List\n\t--------\n",
50690Sstevel@tonic-gate 	    log_eb->nextbno);
50700Sstevel@tonic-gate 	for (x = 0; x < log_eb->nextents; x++)
50710Sstevel@tonic-gate 		printf("\t  [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n",
50720Sstevel@tonic-gate 		    x, log_eb->extents[x].lbno, log_eb->extents[x].pbno,
50730Sstevel@tonic-gate 		    log_eb->extents[x].nbno);
50740Sstevel@tonic-gate 	printf("\nOn Disk Info\n\tbol_lof    : 0x%08x\n\teol_lof    : 0x%08x\n",
50750Sstevel@tonic-gate 	    log_odi->od_bol_lof, log_odi->od_eol_lof);
50760Sstevel@tonic-gate 	printf("\tlog_size   : 0x%08x\n",
50770Sstevel@tonic-gate 	    log_odi->od_logsize);
50780Sstevel@tonic-gate 	printf("\thead_lof   : 0x%08x\tident : 0x%x\n",
50790Sstevel@tonic-gate 	    log_odi->od_head_lof, log_odi->od_head_ident);
50800Sstevel@tonic-gate 	printf("\ttail_lof   : 0x%08x\tident : 0x%x\n\thead_tid   : 0x%08x\n",
50810Sstevel@tonic-gate 	    log_odi->od_tail_lof, log_odi->od_tail_ident, log_odi->od_head_tid);
50820Sstevel@tonic-gate 	printf("\tcheck sum  : 0x%08x\n", log_odi->od_chksum);
50830Sstevel@tonic-gate 	if (log_odi->od_chksum !=
50840Sstevel@tonic-gate 	    (log_odi->od_head_ident + log_odi->od_tail_ident))
50850Sstevel@tonic-gate 		printf("bad checksum: found 0x%08x, should be 0x%08x\n",
50860Sstevel@tonic-gate 		    log_odi->od_chksum,
50870Sstevel@tonic-gate 		    log_odi->od_head_ident + log_odi->od_tail_ident);
50880Sstevel@tonic-gate 	if (log_odi->od_head_lof == log_odi->od_tail_lof)
50890Sstevel@tonic-gate 		printf("\t --- Log is empty ---\n");
50900Sstevel@tonic-gate }
50910Sstevel@tonic-gate 
50920Sstevel@tonic-gate /*
50930Sstevel@tonic-gate  * log_lodb -- logical log offset to disk block number
50940Sstevel@tonic-gate  */
50951051Smaheshvs int
log_lodb(u_offset_t off,diskaddr_t * pblk)50960Sstevel@tonic-gate log_lodb(u_offset_t off, diskaddr_t *pblk)
50970Sstevel@tonic-gate {
50980Sstevel@tonic-gate 	uint32_t	lblk = (uint32_t)btodb(off);
50990Sstevel@tonic-gate 	int	x;
51000Sstevel@tonic-gate 
51012984Sdmick 	if (!log_get_header_info())
51022984Sdmick 		/*
51032984Sdmick 		 * No need to display anything here. The previous routine
51042984Sdmick 		 * has already done so.
51052984Sdmick 		 */
51062993Sdmick 		return (0);
51072984Sdmick 
51080Sstevel@tonic-gate 	for (x = 0; x < log_eb->nextents; x++)
51090Sstevel@tonic-gate 		if ((lblk >= log_eb->extents[x].lbno) &&
51100Sstevel@tonic-gate 		    (lblk < (log_eb->extents[x].lbno +
51110Sstevel@tonic-gate 			log_eb->extents[x].nbno))) {
51120Sstevel@tonic-gate 			*pblk = (diskaddr_t)lblk - log_eb->extents[x].lbno +
51130Sstevel@tonic-gate 				logbtodb(fs, log_eb->extents[x].pbno);
51140Sstevel@tonic-gate 			return (1);
51150Sstevel@tonic-gate 		}
51160Sstevel@tonic-gate 	return (0);
51170Sstevel@tonic-gate }
51180Sstevel@tonic-gate 
51190Sstevel@tonic-gate /*
51200Sstevel@tonic-gate  * String names for the enumerated types. These are only used
51210Sstevel@tonic-gate  * for display purposes.
51220Sstevel@tonic-gate  */
51230Sstevel@tonic-gate char *dt_str[] = {
51240Sstevel@tonic-gate 	"DT_NONE", "DT_SB", "DT_CG", "DT_SI", "DT_AB",
51250Sstevel@tonic-gate 	"DT_ABZERO", "DT_DIR", "DT_INODE", "DT_FBI",
51260Sstevel@tonic-gate 	"DT_QR", "DT_COMMIT", "DT_CANCEL", "DT_BOT",
51270Sstevel@tonic-gate 	"DT_EOT", "DT_UD", "DT_SUD", "DT_SHAD", "DT_MAX"
51280Sstevel@tonic-gate };
51290Sstevel@tonic-gate 
51300Sstevel@tonic-gate /*
51310Sstevel@tonic-gate  * log_read_log -- transfer information from the log and adjust offset
51320Sstevel@tonic-gate  */
51331051Smaheshvs int
log_read_log(u_offset_t * addr,caddr_t va,int nb,uint32_t * chk)51340Sstevel@tonic-gate log_read_log(u_offset_t *addr, caddr_t va, int nb, uint32_t *chk)
51350Sstevel@tonic-gate {
51360Sstevel@tonic-gate 	int		xfer;
51370Sstevel@tonic-gate 	caddr_t		bp;
51380Sstevel@tonic-gate 	diskaddr_t	pblk;
51390Sstevel@tonic-gate 	sect_trailer_t	*st;
51400Sstevel@tonic-gate 
51410Sstevel@tonic-gate 	while (nb) {
51420Sstevel@tonic-gate 		if (!log_lodb(*addr, &pblk)) {
51430Sstevel@tonic-gate 			printf("Invalid log offset\n");
51440Sstevel@tonic-gate 			return (0);
51450Sstevel@tonic-gate 		}
51460Sstevel@tonic-gate 
51470Sstevel@tonic-gate 		/*
51480Sstevel@tonic-gate 		 * fsdb getblk() expects offsets not block number.
51490Sstevel@tonic-gate 		 */
51500Sstevel@tonic-gate 		if ((bp = getblk((u_offset_t)dbtob(pblk))) == NULL)
51510Sstevel@tonic-gate 			return (0);
51520Sstevel@tonic-gate 
51530Sstevel@tonic-gate 		xfer = MIN(NB_LEFT_IN_SECTOR(*addr), nb);
51540Sstevel@tonic-gate 		if (va != NULL) {
51550Sstevel@tonic-gate 			memcpy(va, bp + blkoff(fs, *addr), xfer);
51560Sstevel@tonic-gate 			va += xfer;
51570Sstevel@tonic-gate 		}
51580Sstevel@tonic-gate 		nb -= xfer;
51590Sstevel@tonic-gate 		*addr += xfer;
51600Sstevel@tonic-gate 
51610Sstevel@tonic-gate 		/*
51620Sstevel@tonic-gate 		 * If the log offset is now at a sector trailer
51630Sstevel@tonic-gate 		 * run the checks if requested.
51640Sstevel@tonic-gate 		 */
51650Sstevel@tonic-gate 		if (NB_LEFT_IN_SECTOR(*addr) == 0) {
51660Sstevel@tonic-gate 			if (chk != NULL) {
51670Sstevel@tonic-gate 				st = (sect_trailer_t *)
51680Sstevel@tonic-gate 				    (bp + blkoff(fs, *addr));
51690Sstevel@tonic-gate 				if (*chk != st->st_ident) {
51700Sstevel@tonic-gate 					printf(
51710Sstevel@tonic-gate 			"Expected sector trailer id 0x%08x, but saw 0x%08x\n",
51720Sstevel@tonic-gate 						*chk, st->st_ident);
51730Sstevel@tonic-gate 					return (0);
51740Sstevel@tonic-gate 				} else {
51750Sstevel@tonic-gate 					*chk = st->st_ident + 1;
51760Sstevel@tonic-gate 					/*
51770Sstevel@tonic-gate 					 * We update the on disk structure
51780Sstevel@tonic-gate 					 * transaction ID each time we see
51790Sstevel@tonic-gate 					 * one. By comparing this value
51800Sstevel@tonic-gate 					 * to the last valid DT_COMMIT record
51810Sstevel@tonic-gate 					 * we can determine if our log is
51820Sstevel@tonic-gate 					 * completely valid.
51830Sstevel@tonic-gate 					 */
51840Sstevel@tonic-gate 					log_odi->od_head_tid = st->st_tid;
51850Sstevel@tonic-gate 				}
51860Sstevel@tonic-gate 			}
51870Sstevel@tonic-gate 			*addr += sizeof (sect_trailer_t);
51880Sstevel@tonic-gate 		}
51890Sstevel@tonic-gate 		if ((int32_t)*addr == log_odi->od_eol_lof)
51900Sstevel@tonic-gate 			*addr = log_odi->od_bol_lof;
51910Sstevel@tonic-gate 	}
51920Sstevel@tonic-gate 	return (1);
51930Sstevel@tonic-gate }
51940Sstevel@tonic-gate 
51950Sstevel@tonic-gate u_offset_t
log_nbcommit(u_offset_t a)51960Sstevel@tonic-gate log_nbcommit(u_offset_t a)
51970Sstevel@tonic-gate {
51980Sstevel@tonic-gate 	/*
51990Sstevel@tonic-gate 	 * Comments are straight from ufs_log.c
52000Sstevel@tonic-gate 	 *
52010Sstevel@tonic-gate 	 * log is the offset following the commit header. However,
52020Sstevel@tonic-gate 	 * if the commit header fell on the end-of-sector, then lof
52030Sstevel@tonic-gate 	 * has already been advanced to the beginning of the next
52040Sstevel@tonic-gate 	 * sector. So do nothgin. Otherwise, return the remaining
52050Sstevel@tonic-gate 	 * bytes in the sector.
52060Sstevel@tonic-gate 	 */
52070Sstevel@tonic-gate 	if ((a & (DEV_BSIZE - 1)) == 0)
52080Sstevel@tonic-gate 		return (0);
52090Sstevel@tonic-gate 	else
52100Sstevel@tonic-gate 		return (NB_LEFT_IN_SECTOR(a));
52110Sstevel@tonic-gate }
52120Sstevel@tonic-gate 
52130Sstevel@tonic-gate /*
52140Sstevel@tonic-gate  * log_show --  pretty print the deltas. The number of which is determined
52150Sstevel@tonic-gate  *		by the log_enum arg. If LOG_ALLDELTAS the routine, as the
52160Sstevel@tonic-gate  *		name implies dumps everything. If LOG_NDELTAS, the routine
52170Sstevel@tonic-gate  *		will print out "count" deltas starting at "addr". If
52180Sstevel@tonic-gate  *		LOG_CHECKSCAN then run through the log checking the st_ident
52190Sstevel@tonic-gate  *		for valid data.
52200Sstevel@tonic-gate  */
52211051Smaheshvs static void
log_show(enum log_enum l)52220Sstevel@tonic-gate log_show(enum log_enum l)
52230Sstevel@tonic-gate {
52240Sstevel@tonic-gate 	struct delta	d;
52250Sstevel@tonic-gate 	int32_t		bol, eol;
52260Sstevel@tonic-gate 	int		x = 0;
52270Sstevel@tonic-gate 	uint32_t	chk;
52280Sstevel@tonic-gate 
52290Sstevel@tonic-gate 	if (!log_get_header_info())
52300Sstevel@tonic-gate 		/*
52310Sstevel@tonic-gate 		 * No need to display any error messages here. The previous
52320Sstevel@tonic-gate 		 * routine has already done so.
52330Sstevel@tonic-gate 		 */
52340Sstevel@tonic-gate 		return;
52350Sstevel@tonic-gate 
52360Sstevel@tonic-gate 	bol = log_odi->od_head_lof;
52370Sstevel@tonic-gate 	eol = log_odi->od_tail_lof;
52380Sstevel@tonic-gate 	chk = log_odi->od_head_ident;
52390Sstevel@tonic-gate 
52400Sstevel@tonic-gate 	if (bol == eol) {
52410Sstevel@tonic-gate 		if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) {
52420Sstevel@tonic-gate 			printf("Empty log.\n");
52430Sstevel@tonic-gate 			return;
52440Sstevel@tonic-gate 		} else
52450Sstevel@tonic-gate 			printf("WARNING: empty log. addr may generate bogus"
52460Sstevel@tonic-gate 			    " information");
52470Sstevel@tonic-gate 	}
52480Sstevel@tonic-gate 
52490Sstevel@tonic-gate 	/*
52500Sstevel@tonic-gate 	 * Only reset the "addr" if we've been requested to show all
52510Sstevel@tonic-gate 	 * deltas in the log.
52520Sstevel@tonic-gate 	 */
52530Sstevel@tonic-gate 	if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN))
52540Sstevel@tonic-gate 		addr = (u_offset_t)bol;
52550Sstevel@tonic-gate 
52560Sstevel@tonic-gate 	if (l != LOG_CHECKSCAN) {
52570Sstevel@tonic-gate 		printf("       Log Offset       Delta       Count     Type\n");
52580Sstevel@tonic-gate 		printf("-----------------------------------------"
52590Sstevel@tonic-gate 			"-----------------\n");
52600Sstevel@tonic-gate 	}
52610Sstevel@tonic-gate 
52620Sstevel@tonic-gate 	while ((bol != eol) && ((l == LOG_ALLDELTAS) ||
52630Sstevel@tonic-gate 	    (l == LOG_CHECKSCAN) || count--)) {
52640Sstevel@tonic-gate 		if (!log_read_log(&addr, (caddr_t)&d, sizeof (d),
52650Sstevel@tonic-gate 		    ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) ?
52660Sstevel@tonic-gate 		    &chk : NULL))
52670Sstevel@tonic-gate 			/*
52680Sstevel@tonic-gate 			 * Two failures are possible. One from getblk()
52690Sstevel@tonic-gate 			 * which prints out a message or when we've hit
52700Sstevel@tonic-gate 			 * an invalid block which may or may not indicate
52710Sstevel@tonic-gate 			 * an error
52720Sstevel@tonic-gate 			 */
52730Sstevel@tonic-gate 			goto end_scan;
52740Sstevel@tonic-gate 
52750Sstevel@tonic-gate 		if ((uint32_t)d.d_nb > log_odi->od_logsize) {
52760Sstevel@tonic-gate 			printf("Bad delta entry. size out of bounds\n");
52770Sstevel@tonic-gate 			return;
52780Sstevel@tonic-gate 		}
52790Sstevel@tonic-gate 		if (l != LOG_CHECKSCAN)
52800Sstevel@tonic-gate 			printf("[%04d]  %08x  %08x.%08x %08x  %s\n", x++, bol,
52810Sstevel@tonic-gate 			    d.d_mof, d.d_nb,
52820Sstevel@tonic-gate 			    dt_str[d.d_typ >= DT_MAX ? DT_MAX : d.d_typ]);
52830Sstevel@tonic-gate 
52840Sstevel@tonic-gate 		switch (d.d_typ) {
52850Sstevel@tonic-gate 		case DT_CANCEL:
52860Sstevel@tonic-gate 		case DT_ABZERO:
52870Sstevel@tonic-gate 			/*
52880Sstevel@tonic-gate 			 * These two deltas don't have log space
52890Sstevel@tonic-gate 			 * associated with the entry even though
52900Sstevel@tonic-gate 			 * d_nb is non-zero.
52910Sstevel@tonic-gate 			 */
52920Sstevel@tonic-gate 			break;
52930Sstevel@tonic-gate 
52940Sstevel@tonic-gate 		case DT_COMMIT:
52950Sstevel@tonic-gate 			/*
52960Sstevel@tonic-gate 			 * Commit records have zero size yet, the
52970Sstevel@tonic-gate 			 * rest of the current disk block is avoided.
52980Sstevel@tonic-gate 			 */
52990Sstevel@tonic-gate 			addr += log_nbcommit(addr);
53000Sstevel@tonic-gate 			lufs_tid = log_odi->od_head_tid;
53010Sstevel@tonic-gate 			lufs_tid_valid = True;
53020Sstevel@tonic-gate 			break;
53030Sstevel@tonic-gate 
53040Sstevel@tonic-gate 		default:
53050Sstevel@tonic-gate 			if (!log_read_log(&addr, NULL, d.d_nb,
53060Sstevel@tonic-gate 			    ((l == LOG_ALLDELTAS) ||
53070Sstevel@tonic-gate 			    (l == LOG_CHECKSCAN)) ? &chk : NULL))
53080Sstevel@tonic-gate 				goto end_scan;
53090Sstevel@tonic-gate 			break;
53100Sstevel@tonic-gate 		}
53110Sstevel@tonic-gate 		bol = (int32_t)addr;
53120Sstevel@tonic-gate 	}
53130Sstevel@tonic-gate 
53140Sstevel@tonic-gate end_scan:
53150Sstevel@tonic-gate 	if (lufs_tid_valid == True) {
53160Sstevel@tonic-gate 		if (lufs_tid == log_odi->od_head_tid)
53170Sstevel@tonic-gate 			printf("scan -- okay\n");
53180Sstevel@tonic-gate 		else
53190Sstevel@tonic-gate 			printf("scan -- some transactions have been lost\n");
53200Sstevel@tonic-gate 	} else {
53210Sstevel@tonic-gate 		printf("scan -- failed to find a single valid transaction\n");
53220Sstevel@tonic-gate 		printf("        (possibly due to an empty log)\n");
53230Sstevel@tonic-gate 	}
53240Sstevel@tonic-gate }
5325