xref: /csrg-svn/sbin/fsdb/fsdb.c (revision 69260)
134187Smckusick /*
261494Sbostic  * Copyright (c) 1988, 1993
361494Sbostic  *	The Regents of the University of California.  All rights reserved.
434187Smckusick  *
534187Smckusick  * This code is derived from software contributed to Berkeley by
634187Smckusick  * Computer Consoles Inc.
734187Smckusick  *
866689Sbostic  * %sccs.include.proprietary.c%
934187Smckusick  */
1034187Smckusick 
1134187Smckusick #ifndef lint
1261494Sbostic static char copyright[] =
1361494Sbostic "@(#) Copyright (c) 1988, 1993\n\
1461494Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1534187Smckusick #endif /* not lint */
1634187Smckusick 
1734187Smckusick #ifndef lint
18*69260Smckusick static char sccsid[] = "@(#)fsdb.c	8.5 (Berkeley) 05/04/95";
1934187Smckusick #endif /* not lint */
2034187Smckusick 
2134197Smckusick /*
2234197Smckusick  *  fsdb - file system debugger
2334197Smckusick  *
2434197Smckusick  *  usage: fsdb [options] special
2534187Smckusick  *  options:
2634187Smckusick  *	-?		display usage
2734187Smckusick  *	-o		override some error conditions
2834187Smckusick  *	-p"string"	set prompt to string
2934187Smckusick  *	-w		open for write
3034187Smckusick  */
3134187Smckusick 
3234187Smckusick #include <sys/param.h>
3336249Smckusick #include <sys/file.h>
3438508Sbostic #include <sys/dir.h>
3553732Smckusick #include <sys/time.h>
3651620Sbostic #include <ufs/ufs/dinode.h>
3751620Sbostic #include <ufs/ffs/fs.h>
3837271Sbostic #include <stdio.h>
3957998Sralph #include <unistd.h>
4057998Sralph #include <stdlib.h>
4137271Sbostic #include <setjmp.h>
4237271Sbostic #include <paths.h>
4336249Smckusick 
4434187Smckusick /*
4536249Smckusick  * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3
4636249Smckusick  * file system.
4736249Smckusick  */
4836249Smckusick #ifndef FS_42POSTBLFMT
4936249Smckusick #define cg_blktot(cgp) (((cgp))->cg_btot)
5036249Smckusick #define cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno])
5136249Smckusick #define cg_inosused(cgp) (((cgp))->cg_iused)
5236249Smckusick #define cg_blksfree(cgp) (((cgp))->cg_free)
5336249Smckusick #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC)
5436249Smckusick #endif
5536249Smckusick 
5636249Smckusick /*
5734187Smckusick  * Never changing defines.
5834187Smckusick  */
5934187Smckusick #define	OCTAL		8		/* octal base */
6034187Smckusick #define	DECIMAL		10		/* decimal base */
6134187Smckusick #define	HEX		16		/* hexadecimal base */
6234187Smckusick 
6334187Smckusick /*
6434187Smckusick  * Adjustable defines.
6534187Smckusick  */
6634187Smckusick #define	NBUF		10		/* number of cache buffers */
6734187Smckusick #define PROMPTSIZE	80		/* size of user definable prompt */
6834187Smckusick #define	MAXFILES	40000		/* max number of files ls can handle */
6934187Smckusick #define FIRST_DEPTH	10		/* default depth for find and ls */
7034187Smckusick #define SECOND_DEPTH	100		/* second try at depth (maximum) */
7134187Smckusick #define INPUTBUFFER	1040		/* size of input buffer */
7234187Smckusick #define BYTESPERLINE	16		/* bytes per line of /dxo output */
7334187Smckusick #define	NREG		36		/* number of save registers */
7434187Smckusick 
7534187Smckusick /*
7634187Smckusick  * Values dependent on sizes of structs and such.
7734187Smckusick  */
7834187Smckusick #define NUMB		3			/* these three are arbitrary, */
7934187Smckusick #define	BLOCK		5			/* but must be different from */
8034187Smckusick #define	FRAGMENT	7			/* the rest (hence odd).      */
8134187Smckusick #define	BITSPERCHAR	8			/* couldn't find it anywhere  */
8234187Smckusick #define	CHAR		(sizeof (char))
8334187Smckusick #define	SHORT		(sizeof (short))
8434187Smckusick #define	LONG		(sizeof (long))
8534187Smckusick #define	INODE		(sizeof (struct dinode))
8634187Smckusick #define	DIRECTORY	(sizeof (struct direct))
8734187Smckusick #define	CGRP		(sizeof (struct cg))
8834187Smckusick #define SB		(sizeof (struct fs))
8934187Smckusick #define	BLKSIZE		(fs->fs_bsize)		/* for clarity */
9034187Smckusick #define	FRGSIZE		(fs->fs_fsize)
9134187Smckusick #define	BLKSHIFT	(fs->fs_bshift)
9234187Smckusick #define	FRGSHIFT	(fs->fs_fshift)
9334187Smckusick 
9434187Smckusick /*
9534187Smckusick  * Messy macros that would otherwise clutter up such glamorous code.
9634187Smckusick  */
9764639Sbostic #define itob(i)		((ino_to_fsba(fs,				\
9864639Sbostic 			    (i)) << FRGSHIFT) + ino_to_fsbo(fs, (i)) * INODE)
9934187Smckusick #define min(x, y)	((x) < (y) ? (x) : (y))
10034187Smckusick #define	STRINGSIZE(d)	((long)d->d_reclen - \
10134187Smckusick 				((long)&d->d_name[0] - (long)&d->d_ino))
10234187Smckusick #define	letter(c)	((((c) >= 'a')&&((c) <= 'z')) ||\
10334187Smckusick 				(((c) >= 'A')&&((c) <= 'Z')))
10434187Smckusick #define	digit(c)	(((c) >= '0') && ((c) <= '9'))
10534187Smckusick #define HEXLETTER(c)	(((c) >= 'A') && ((c) <= 'F'))
10634187Smckusick #define hexletter(c)	(((c) >= 'a') && ((c) <= 'f'))
10734187Smckusick #define octaldigit(c)	(((c) >= '0') && ((c) <= '7'))
10834187Smckusick #define uppertolower(c)	((c) - 'A' + 'a')
10934187Smckusick #define hextodigit(c)	((c) - 'a' + 10)
11034187Smckusick #define	numtodigit(c)	((c) - '0')
11134187Smckusick #define loword(X)	(((ushort *)&X)[1])
11234187Smckusick #define lobyte(X)	(((unsigned char *)&X)[1])
11334187Smckusick 
11434187Smckusick /*
11534187Smckusick  * buffer cache structure.
11634187Smckusick  */
11734187Smckusick struct buf {
11834187Smckusick 	struct	buf  *fwd;
11934187Smckusick 	struct	buf  *back;
12034187Smckusick 	char	*blkaddr;
12134187Smckusick 	short	valid;
12234187Smckusick 	long	blkno;
12334187Smckusick } buf[NBUF], bhdr;
12434187Smckusick 
12534187Smckusick /*
12634187Smckusick  * used to hold save registers (see '<' and '>').
12734187Smckusick  */
12834187Smckusick struct	save_registers {
12934187Smckusick 	long	sv_addr;
13034187Smckusick 	long	sv_value;
13134187Smckusick 	long	sv_objsz;
13234187Smckusick } regs[NREG];
13334187Smckusick 
13434187Smckusick /*
13534187Smckusick  * cd, find, and ls use this to hold filenames.  Each filename is broken
13634187Smckusick  * up by a slash.  In other words, /usr/src/adm would have a len field
13734187Smckusick  * of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
13834187Smckusick  * src, and adm components of the pathname.
13934187Smckusick  */
14034187Smckusick struct filenames {
14134187Smckusick 	long	ino;		/* inode */
14234187Smckusick 	long	len;		/* number of components */
14334187Smckusick 	char	flag;		/* flag if using SECOND_DEPTH allocator */
14434187Smckusick 	char	find;		/* flag if found by find */
14534187Smckusick 	char	**fname;	/* hold components of pathname */
14634187Smckusick } *filenames, *top;
14734187Smckusick 
14834187Smckusick struct fs filesystem, *fs;	/* super block */
14934187Smckusick 
15034187Smckusick /*
15134187Smckusick  * Global data.
15234187Smckusick  */
15334187Smckusick char		*input_path[MAXPATHLEN];
15434187Smckusick char		*stack_path[MAXPATHLEN];
15534187Smckusick char		*current_path[MAXPATHLEN];
15634187Smckusick char		input_buffer[INPUTBUFFER];
15734187Smckusick char		*prompt;
15834187Smckusick char		*buffers;
15934187Smckusick char		scratch[64];
16034187Smckusick char		BASE[] = "o u     x";
16134187Smckusick char		PROMPT[PROMPTSIZE] = "> ";
16234187Smckusick char		laststyle = '/';
16334187Smckusick char		lastpo = 'x';
16434187Smckusick short		input_pointer;
16534187Smckusick short		current_pathp;
16634187Smckusick short		stack_pathp;
16734187Smckusick short		input_pathp;
16834187Smckusick short		cmp_level;
16934187Smckusick short		nfiles;
17034187Smckusick short		type = NUMB;
17134187Smckusick short		dirslot;
17234187Smckusick short		fd;
17334187Smckusick short		c_count;
17434187Smckusick short		error;
17534187Smckusick short		paren;
17634187Smckusick short		trapped;
17734187Smckusick short		doing_cd;
17834187Smckusick short		doing_find;
17934187Smckusick short		find_by_name;
18034187Smckusick short		find_by_inode;
18134187Smckusick short		long_list;
18234187Smckusick short		recursive;
18334187Smckusick short		objsz = SHORT;
18434187Smckusick short		override = 0;
18534187Smckusick short		wrtflag;
18634187Smckusick short		base = HEX;
18734187Smckusick short		acting_on_inode;
18834187Smckusick short		acting_on_directory;
18934187Smckusick short		should_print = 1;
19034187Smckusick short		clear;
19134187Smckusick short		star;
19234187Smckusick long		addr;
19334187Smckusick long		bod_addr;
19434187Smckusick long		value;
19534187Smckusick long		erraddr;
19634187Smckusick long		errcur_bytes;
19734187Smckusick long		errino;
19834187Smckusick long		errinum;
19934187Smckusick long		cur_cgrp;
20034187Smckusick long		cur_ino;
20134187Smckusick long		cur_inum;
20234187Smckusick long		cur_dir;
20334187Smckusick long		cur_block;
20434187Smckusick long		cur_bytes;
20534187Smckusick long		find_ino;
20634187Smckusick long		filesize;
20734187Smckusick long		blocksize;
20834187Smckusick long		stringsize;
20934187Smckusick long		count = 1;
21034187Smckusick long		commands;
21134187Smckusick long		read_requests;
21234187Smckusick long		actual_disk_reads;
21334187Smckusick jmp_buf		env;
21434187Smckusick 
21534187Smckusick char		getachar();
21634187Smckusick char		*getblk(), *fmtentry();
21746706Sbostic void		err();
21834187Smckusick long		get(), bmap(), expr(), term(), getnumb();
21934187Smckusick unsigned long	*print_check();
22034187Smckusick 
22134187Smckusick /*
22234187Smckusick  * main - lines are read up to the unprotected ('\') newline and
22334187Smckusick  *	held in an input buffer.  Characters may be read from the
22434187Smckusick  *	input buffer using getachar() and unread using ungetachar().
22534187Smckusick  *	Reading the whole line ahead allows the use of debuggers
22634187Smckusick  *	which would otherwise be impossible since the debugger
22734187Smckusick  *	and fsdb could not share stdin.
22834187Smckusick  */
22934187Smckusick 
main(argc,argv)23057998Sralph main(argc, argv)
23134187Smckusick 	short			argc;
23234187Smckusick 	char			**argv;
23334187Smckusick {
23434187Smckusick 	register char		c, *cptr;
23534187Smckusick 	register short		i, j, *iptr;
23634187Smckusick 	register struct direct	*dirp;
23734187Smckusick 	register struct buf	*bp;
23834187Smckusick 	struct filenames	*fn;
23934187Smckusick 	char			*progname;
24034187Smckusick 	short			colon, mode;
24134187Smckusick 	long			temp;
24234187Smckusick 	unsigned		block;
24334187Smckusick 	int			ffcmp();
24434187Smckusick 
24534187Smckusick 	setbuf(stdin, NULL);
24634187Smckusick 
24734187Smckusick 	progname = argv[0];
24834187Smckusick 	prompt = &PROMPT[0];
24934187Smckusick 	/*
25034187Smckusick 	 * Parse options.
25134187Smckusick 	 */
25234187Smckusick 	while (argc>1 && argv[1][0] == '-') {
25334187Smckusick 		if (strcmp("-?", argv[1]) == 0)
25434187Smckusick 			goto usage;
25534187Smckusick 		if (strcmp("-o", argv[1]) == 0) {
25634187Smckusick 			printf("error checking off\n");
25734187Smckusick 			override = 1;
25834187Smckusick 			argc--; argv++;
25934187Smckusick 			continue;
26034187Smckusick 		}
26157998Sralph 		if (strncmp("-p", argv[1], 2) == 0) {
26234187Smckusick 			prompt = &argv[1][2];
26334187Smckusick 			argc--; argv++;
26434187Smckusick 			continue;
26534187Smckusick 		}
26634187Smckusick 		if (strcmp("-w", argv[1]) == 0) {
26734187Smckusick 			wrtflag = 2;		/* suitable for open */
26834187Smckusick 			argc--; argv++;
26934187Smckusick 			continue;
27034187Smckusick 		}
27134187Smckusick 	}
27257998Sralph 	if (argc != 2) {
27334187Smckusick usage:
27434187Smckusick 		printf("usage:   %s [options] special\n", progname);
27534187Smckusick 		printf("options:\n");
27634187Smckusick 		printf("\t-?		display usage\n");
27734187Smckusick 		printf("\t-o		override some error conditions\n");
27834187Smckusick 		printf("\t-p\"string\"	set prompt to string\n");
27934187Smckusick 		printf("\t-w		open for write\n");
28034187Smckusick 		exit(1);
28134187Smckusick 	}
28234187Smckusick 	/*
28334187Smckusick 	 * Attempt to open the special file.
28434187Smckusick 	 */
28557998Sralph 	if ((fd = open(argv[1], wrtflag)) < 0) {
28634187Smckusick 		perror(argv[1]);
28734187Smckusick 		exit(1);
28834187Smckusick 	}
28934187Smckusick 	/*
29034187Smckusick 	 * Read in the super block and validate (not too picky).
29134187Smckusick 	 */
29257998Sralph 	if (lseek(fd, (off_t)(SBLOCK * DEV_BSIZE), SEEK_SET) == -1) {
29334187Smckusick 		perror(argv[1]);
29434187Smckusick 		exit(1);
29534187Smckusick 	}
29634187Smckusick 	if (read(fd, &filesystem, sizeof filesystem) != sizeof filesystem) {
29734187Smckusick 		printf("%s: cannot read superblock\n", argv[1]);
29834187Smckusick 		exit(1);
29934187Smckusick 	}
30034187Smckusick 	fs = &filesystem;
30134187Smckusick 	if (fs->fs_magic != FS_MAGIC) {
30234187Smckusick 		printf("%s: Bad magic number in file system\n", argv[1]);
30334187Smckusick 		exit(1);
30434187Smckusick 	}
30536249Smckusick #ifdef FS_42POSTBLFMT
30634197Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)
30734197Smckusick 		fs->fs_nrpos = 8;
30836249Smckusick #endif
30934187Smckusick 	printf("fsdb of %s %s -- last mounted on %s\n",
31057998Sralph 		argv[1], wrtflag ? "(Opened for write)" : "(Read only)",
31134187Smckusick 		&fs->fs_fsmnt[0]);
31234187Smckusick 	/*
31334187Smckusick 	 * Malloc buffers and set up cache.
31434187Smckusick 	 */
31534187Smckusick 	buffers = malloc(NBUF * BLKSIZE);
31634187Smckusick 	bhdr.fwd = bhdr.back = &bhdr;
31757998Sralph 	for (i = 0; i < NBUF; i++) {
31834187Smckusick 		bp = &buf[i];
31934187Smckusick 		bp->blkaddr = buffers + (i * BLKSIZE);
32034187Smckusick 		bp->valid = 0;
32134187Smckusick 		insert(bp);
32234187Smckusick 	}
32334187Smckusick 	/*
32434187Smckusick 	 * Malloc filenames structure.  The space for the actual filenames
32534187Smckusick 	 * is allocated as it needs it.
32634187Smckusick 	 */
32734187Smckusick 	filenames = (struct filenames *)calloc(MAXFILES,
32834187Smckusick 						sizeof (struct filenames));
32934187Smckusick 	if (filenames == NULL) {
33034187Smckusick 		printf("out of memory\n");
33134187Smckusick 		exit(1);
33234187Smckusick 	}
33334187Smckusick 
33434187Smckusick 	fn = filenames;
33534187Smckusick 
33634187Smckusick 	restore_inode(2);
33734187Smckusick 	/*
33834187Smckusick 	 * Malloc a few filenames (needed by pwd for example).
33934187Smckusick 	 */
34034187Smckusick 	for (i = 0; i < MAXPATHLEN; i++) {
34134187Smckusick 		input_path[i] = calloc(1, MAXNAMLEN);
34234187Smckusick 		stack_path[i] = calloc(1, MAXNAMLEN);
34334187Smckusick 		current_path[i] = calloc(1, MAXNAMLEN);
34434187Smckusick 		if (current_path[i] == NULL) {
34534187Smckusick 			printf("out of memory\n");
34634187Smckusick 			exit(1);
34734187Smckusick 		}
34834187Smckusick 	}
34934187Smckusick 	current_pathp = -1;
35034187Smckusick 
35157998Sralph 	signal(2, err);
35234187Smckusick 	setjmp(env);
35334187Smckusick 
35434187Smckusick 	getnextinput();
35534187Smckusick 	/*
35634187Smckusick 	 * Main loop and case statement.  If an error condition occurs
35734187Smckusick 	 * initialization and recovery is attempted.
35834187Smckusick 	 */
35934187Smckusick 	for (;;) {
36034187Smckusick 		if (error) {
36134187Smckusick 			freemem(filenames, nfiles);
36234187Smckusick 			nfiles = 0;
36334187Smckusick 			c_count = 0;
36434187Smckusick 			count = 1;
36534187Smckusick 			star = 0;
36634187Smckusick 			error = 0;
36734187Smckusick 			paren = 0;
36834187Smckusick 			acting_on_inode = 0;
36934187Smckusick 			acting_on_directory = 0;
37034187Smckusick 			should_print = 1;
37134187Smckusick 			addr = erraddr;
37234187Smckusick 			cur_ino = errino;
37334187Smckusick 			cur_inum = errinum;
37434187Smckusick 			cur_bytes = errcur_bytes;
37534187Smckusick 			printf("?\n");
37634187Smckusick 			getnextinput();
37734187Smckusick 			if (error)
37834187Smckusick 				continue;
37934187Smckusick 		}
38034187Smckusick 		c_count++;
38134187Smckusick 
38234187Smckusick 		switch (c = getachar()) {
38334187Smckusick 
38434187Smckusick 		case '\n': /* command end */
38534187Smckusick 			freemem(filenames, nfiles);
38634187Smckusick 			nfiles = 0;
38734187Smckusick 			if (should_print && laststyle == '=') {
38834187Smckusick 				ungetachar(c);
38934187Smckusick 				goto calc;
39034187Smckusick 			}
39134187Smckusick 			if (c_count == 1) {
39234187Smckusick 				clear = 0;
39334187Smckusick 				should_print = 1;
39434187Smckusick 				erraddr = addr;
39534187Smckusick 				errino = cur_ino;
39634187Smckusick 				errinum = cur_inum;
39734187Smckusick 				errcur_bytes = cur_bytes;
39834187Smckusick 				switch (objsz) {
39934187Smckusick 				case DIRECTORY:
40057998Sralph 					addr = getdirslot(dirslot + 1);
40157998Sralph 					if (addr == 0)
40234187Smckusick 						should_print = 0;
40334187Smckusick 					if (error) {
40434187Smckusick 						ungetachar(c);
40534187Smckusick 						continue;
40634187Smckusick 					}
40734187Smckusick 					break;
40834187Smckusick 				case INODE:
40934187Smckusick 					cur_inum++;
41034187Smckusick 					addr = itob(cur_inum);
41134187Smckusick 					if (!icheck(addr)) {
41234187Smckusick 						cur_inum--;
41334187Smckusick 						should_print = 0;
41434187Smckusick 					}
41534187Smckusick 					break;
41634187Smckusick 				case CGRP:
41734187Smckusick 				case SB:
41834187Smckusick 					cur_cgrp++;
41957998Sralph 					addr = cgrp_check(cur_cgrp);
42057998Sralph 					if (addr == 0) {
42134187Smckusick 					     cur_cgrp--;
42234187Smckusick 					     continue;
42334187Smckusick 					}
42434187Smckusick 					break;
42534187Smckusick 				default:
42634187Smckusick 					addr += objsz;
42734187Smckusick 					cur_bytes += objsz;
42834187Smckusick 					if (valid_addr() == 0)
42934187Smckusick 						continue;
43034187Smckusick 				}
43134187Smckusick 			}
43234187Smckusick 			if (type == NUMB)
43334187Smckusick 				trapped = 0;
43434187Smckusick 			if (should_print)
43534187Smckusick 				switch (objsz) {
43634187Smckusick 				case DIRECTORY:
43734187Smckusick 					fprnt('?', 'd');
43834187Smckusick 					break;
43934187Smckusick 				case INODE:
44034187Smckusick 					fprnt('?', 'i');
44134187Smckusick 					if (!error)
44234187Smckusick 						cur_ino = addr;
44334187Smckusick 					break;
44434187Smckusick 				case CGRP:
44534187Smckusick 					fprnt('?', 'c');
44634187Smckusick 					break;
44734187Smckusick 				case SB:
44834187Smckusick 					fprnt('?', 's');
44934187Smckusick 					break;
45034187Smckusick 				case CHAR:
45134187Smckusick 				case SHORT:
45234187Smckusick 				case LONG:
45334187Smckusick 					fprnt(laststyle, lastpo);
45434187Smckusick 				}
45534187Smckusick 			if (error) {
45634187Smckusick 				ungetachar(c);
45734187Smckusick 				continue;
45834187Smckusick 			}
45934187Smckusick 			c_count = colon = acting_on_inode = 0;
46034187Smckusick 			acting_on_directory = 0;
46134187Smckusick 			should_print = 1;
46234187Smckusick 			getnextinput();
46334187Smckusick 			if (error)
46434187Smckusick 				continue;
46534187Smckusick 			erraddr = addr;
46634187Smckusick 			errino = cur_ino;
46734187Smckusick 			errinum = cur_inum;
46834187Smckusick 			errcur_bytes = cur_bytes;
46934187Smckusick 			continue;
47034187Smckusick 
47134187Smckusick 		case '(': /* numeric expression or unknown command */
47234187Smckusick 		default:
47334187Smckusick 			colon = 0;
47434187Smckusick 			if (digit(c) || c == '(') {
47534187Smckusick 				ungetachar(c);
47634187Smckusick 				addr = expr();
47734187Smckusick 				type = NUMB;
47834187Smckusick 				value = addr;
47934187Smckusick 				continue;
48034187Smckusick 			}
48134187Smckusick 			printf("unknown command or bad syntax\n");
48234187Smckusick 			error++;
48334187Smckusick 			continue;
48434187Smckusick 
48534187Smckusick 		case '?': /* general print facilities */
48634187Smckusick 		case '/':
48734187Smckusick 			fprnt(c, getachar());
48834187Smckusick 			continue;
48934187Smckusick 
49034187Smckusick 		case ';': /* command separator and . */
49134187Smckusick 		case '\t':
49234187Smckusick 		case ' ':
49334187Smckusick 		case '.':
49434187Smckusick 			continue;
49534187Smckusick 
49634187Smckusick 		case ':': /* command indicator */
49734187Smckusick 			colon++;
49834187Smckusick 			commands++;
49934187Smckusick 			should_print = 0;
50034187Smckusick 			stringsize = 0;
50134187Smckusick 			trapped = 0;
50234187Smckusick 			continue;
50334187Smckusick 
50434187Smckusick 		case ',': /* count indicator */
50534187Smckusick 			colon = star = 0;
50634187Smckusick 			if ((c = getachar()) == '*') {
50734187Smckusick 				star = 1;
50834187Smckusick 				count = BLKSIZE;
50934187Smckusick 			} else {
51034187Smckusick 				ungetachar(c);
51134187Smckusick 				count = expr();
51234187Smckusick 				if (error)
51334187Smckusick 					continue;
51434187Smckusick 				if (!count)
51534187Smckusick 					count = 1;
51634187Smckusick 			}
51734187Smckusick 			clear = 0;
51834187Smckusick 			continue;
51934187Smckusick 
52034187Smckusick 		case '+': /* address addition */
52134187Smckusick 			colon = 0;
52234187Smckusick 			c = getachar();
52334187Smckusick 			ungetachar(c);
52434187Smckusick 			if (c == '\n')
52534187Smckusick 				temp = 1;
52634187Smckusick 			else {
52734187Smckusick 				temp = expr();
52834187Smckusick 				if (error)
52934187Smckusick 					continue;
53034187Smckusick 			}
53134187Smckusick 			erraddr = addr;
53234187Smckusick 			errcur_bytes = cur_bytes;
53334187Smckusick 			switch (objsz) {
53434187Smckusick 			case DIRECTORY:
53534187Smckusick 				addr = getdirslot(dirslot + temp);
53634187Smckusick 				if (error)
53734187Smckusick 					continue;
53834187Smckusick 				break;
53934187Smckusick 			case INODE:
54034187Smckusick 				cur_inum += temp;
54134187Smckusick 				addr = itob(cur_inum);
54234187Smckusick 				if (!icheck(addr)) {
54334187Smckusick 					cur_inum -= temp;
54434187Smckusick 					continue;
54534187Smckusick 				}
54634187Smckusick 				break;
54734187Smckusick 			case CGRP:
54834187Smckusick 			case SB:
54934187Smckusick 				cur_cgrp += temp;
55034187Smckusick 				if ((addr = cgrp_check(cur_cgrp)) == 0) {
55134187Smckusick 					cur_cgrp -= temp;
55234187Smckusick 					continue;
55334187Smckusick 				}
55434187Smckusick 				break;
55534187Smckusick 			default:
55634187Smckusick 				laststyle = '/';
55734187Smckusick 				addr += temp * objsz;
55834187Smckusick 				cur_bytes += temp * objsz;
55934187Smckusick 				if (valid_addr() == 0)
56034187Smckusick 					continue;
56134187Smckusick 			}
56234187Smckusick 			value = get(objsz);
56334187Smckusick 			continue;
56434187Smckusick 
56534187Smckusick 		case '-': /* address subtraction */
56634187Smckusick 			colon = 0;
56734187Smckusick 			c = getachar();
56834187Smckusick 			ungetachar(c);
56934187Smckusick 			if (c == '\n')
57034187Smckusick 				temp = 1;
57134187Smckusick 			else {
57234187Smckusick 				temp = expr();
57334187Smckusick 				if (error)
57434187Smckusick 					continue;
57534187Smckusick 			}
57634187Smckusick 			erraddr = addr;
57734187Smckusick 			errcur_bytes = cur_bytes;
57834187Smckusick 			switch (objsz) {
57934187Smckusick 			case DIRECTORY:
58034187Smckusick 				addr = getdirslot(dirslot - temp);
58134187Smckusick 				if (error)
58234187Smckusick 					continue;
58334187Smckusick 				break;
58434187Smckusick 			case INODE:
58534187Smckusick 				cur_inum -= temp;
58634187Smckusick 				addr = itob(cur_inum);
58734187Smckusick 				if (!icheck(addr)) {
58834187Smckusick 					cur_inum += temp;
58934187Smckusick 					continue;
59034187Smckusick 				}
59134187Smckusick 				break;
59234187Smckusick 			case CGRP:
59334187Smckusick 			case SB:
59434187Smckusick 				cur_cgrp -= temp;
59534187Smckusick 				if ((addr = cgrp_check(cur_cgrp)) == 0) {
59634187Smckusick 					cur_cgrp += temp;
59734187Smckusick 					continue;
59834187Smckusick 				}
59934187Smckusick 				break;
60034187Smckusick 			default:
60134187Smckusick 				laststyle = '/';
60234187Smckusick 				addr -= temp * objsz;
60334187Smckusick 				cur_bytes -= temp * objsz;
60434187Smckusick 				if (valid_addr() == 0)
60534187Smckusick 					continue;
60634187Smckusick 			}
60734187Smckusick 			value = get(objsz);
60834187Smckusick 			continue;
60934187Smckusick 
61034187Smckusick 		case '*': /* address multiplication */
61134187Smckusick 			colon = 0;
61234187Smckusick 			temp = expr();
61334187Smckusick 			if (error)
61434187Smckusick 				continue;
61534187Smckusick 			if (objsz != INODE && objsz != DIRECTORY)
61634187Smckusick 				laststyle = '/';
61734187Smckusick 			addr *= temp;
61834187Smckusick 			value = get(objsz);
61934187Smckusick 			continue;
62034187Smckusick 
62134187Smckusick 		case '%': /* address division */
62234187Smckusick 			colon = 0;
62334187Smckusick 			temp = expr();
62434187Smckusick 			if (error)
62534187Smckusick 				continue;
62634187Smckusick 			if (!temp) {
62734187Smckusick 				printf("divide by zero\n");
62834187Smckusick 				error++;
62934187Smckusick 				continue;
63034187Smckusick 			}
63134187Smckusick 			if (objsz != INODE && objsz != DIRECTORY)
63234187Smckusick 				laststyle = '/';
63334187Smckusick 			addr /= temp;
63434187Smckusick 			value = get(objsz);
63534187Smckusick 			continue;
63634187Smckusick 
63734187Smckusick 		case '=': { /* assignment operation */
63834187Smckusick 			short tbase = base;
63934187Smckusick 
64034187Smckusick calc:
64134187Smckusick 			c = getachar();
64234187Smckusick 			if (c == '\n') {
64334187Smckusick 				ungetachar(c);
64434187Smckusick 				c = lastpo;
64534187Smckusick 				if (acting_on_inode == 1) {
64634187Smckusick 					if (c != 'o' && c != 'd' && c != 'x' &&
64734187Smckusick 					    c != 'O' && c != 'D' && c != 'X') {
64834187Smckusick 						switch (objsz) {
64934187Smckusick 						case LONG:
65034187Smckusick 							c = lastpo = 'X';
65134187Smckusick 							break;
65234187Smckusick 						case SHORT:
65334187Smckusick 							c = lastpo = 'x';
65434187Smckusick 							break;
65534187Smckusick 						case CHAR:
65634187Smckusick 							c = lastpo = 'c';
65734187Smckusick 						}
65834187Smckusick 					}
65934187Smckusick 				} else {
66034187Smckusick 					if (acting_on_inode == 2)
66134187Smckusick 						c = lastpo = 't';
66234187Smckusick 				}
66334187Smckusick 			} else if (acting_on_inode)
66434187Smckusick 				lastpo = c;
66534187Smckusick 			should_print = star = 0;
66634187Smckusick 			count = 1;
66734187Smckusick 			erraddr = addr;
66834187Smckusick 			errcur_bytes = cur_bytes;
66934187Smckusick 			switch (c) {
67034187Smckusick 			case '"': /* character string */
67134187Smckusick 				if (type == NUMB) {
67234187Smckusick 					blocksize = BLKSIZE;
67334187Smckusick 					filesize = BLKSIZE * 2;
67434187Smckusick 					cur_bytes = blkoff(fs, addr);
67534187Smckusick 					if (objsz==DIRECTORY || objsz==INODE)
67634187Smckusick 						lastpo = 'X';
67734187Smckusick 				}
67834187Smckusick 				puta();
67934187Smckusick 				continue;
68034187Smckusick 			case '+': /* =+ operator */
68134187Smckusick 				temp = expr();
68234187Smckusick 				value = get(objsz);
68334187Smckusick 				if (!error)
68457998Sralph 					put(value+temp, objsz);
68534187Smckusick 				continue;
68634187Smckusick 			case '-': /* =- operator */
68734187Smckusick 				temp = expr();
68834187Smckusick 				value = get(objsz);
68934187Smckusick 				if (!error)
69057998Sralph 					put(value-temp, objsz);
69134187Smckusick 				continue;
69234187Smckusick 			case 'b':
69334187Smckusick 			case 'c':
69434187Smckusick 				if (objsz == CGRP)
69534187Smckusick 					fprnt('?', c);
69634187Smckusick 				else
69734187Smckusick 					fprnt('/', c);
69834187Smckusick 				continue;
69934187Smckusick 			case 'i':
70034187Smckusick 				addr = cur_ino;
70134187Smckusick 				fprnt('?', 'i');
70257998Sralph 				continue;
70334187Smckusick 			case 's':
70434187Smckusick 				fprnt('?', 's');
70534187Smckusick 				continue;
70634187Smckusick 			case 't':
70734187Smckusick 			case 'T':
70834187Smckusick 				laststyle = '=';
70934187Smckusick 				printf("\t\t");
71034187Smckusick 				printf("%s", ctime(&value));
71134187Smckusick 				continue;
71234187Smckusick 			case 'o':
71334187Smckusick 				base = OCTAL;
71434187Smckusick 				goto otx;
71534187Smckusick 			case 'd':
71634187Smckusick 				if (objsz == DIRECTORY) {
71734187Smckusick 					addr = cur_dir;
71834187Smckusick 					fprnt('?', 'd');
71934187Smckusick 					continue;
72034187Smckusick 				}
72134187Smckusick 				base = DECIMAL;
72234187Smckusick 				goto otx;
72334187Smckusick 			case 'x':
72434187Smckusick 				base = HEX;
72534187Smckusick otx:
72634187Smckusick 				laststyle = '=';
72734187Smckusick 				printf("\t\t");
72834187Smckusick 				if (acting_on_inode)
72934187Smckusick 					print(value & 0177777L, 12, -8, 0);
73034187Smckusick 				else
73134187Smckusick 					print(addr & 0177777L, 12, -8, 0);
73234187Smckusick 				printf("\n");
73334187Smckusick 				base = tbase;
73434187Smckusick 				continue;
73534187Smckusick 			case 'O':
73634187Smckusick 				base = OCTAL;
73734187Smckusick 				goto OTX;
73834187Smckusick 			case 'D':
73934187Smckusick 				base = DECIMAL;
74034187Smckusick 				goto OTX;
74134187Smckusick 			case 'X':
74234187Smckusick 				base = HEX;
74334187Smckusick OTX:
74434187Smckusick 				laststyle = '=';
74534187Smckusick 			 	printf("\t\t");
74634187Smckusick 				if (acting_on_inode)
74734187Smckusick 					print(value, 12, -8, 0);
74834187Smckusick 				else
74934187Smckusick 					print(addr, 12, -8, 0);
75034187Smckusick 				printf("\n");
75134187Smckusick 				base = tbase;
75234187Smckusick 				continue;
75334187Smckusick 			default: /* regular assignment */
75434187Smckusick 				ungetachar(c);
75534187Smckusick 				value = expr();
75634187Smckusick 				if (error)
75734187Smckusick 					printf("syntax error\n");
75834187Smckusick 				else
75957998Sralph 					put(value, objsz);
76034187Smckusick 				continue;
76134187Smckusick 			}
76234187Smckusick 		}
76334187Smckusick 
76434187Smckusick 		case '>': /* save current address */
76534187Smckusick 			colon = 0;
76634187Smckusick 			should_print = 0;
76734187Smckusick 			c = getachar();
76834187Smckusick 			if (!letter(c) && !digit(c)) {
76934187Smckusick 				printf("invalid register specification, ");
77034187Smckusick 				printf("must be letter or digit\n");
77134187Smckusick 				error++;
77234187Smckusick 				continue;
77334187Smckusick 			}
77434187Smckusick 			if (letter(c)) {
77534187Smckusick 				if (c < 'a')
77634187Smckusick 					c = uppertolower(c);
77734187Smckusick 				c = hextodigit(c);
77834187Smckusick 			} else
77934187Smckusick 				c = numtodigit(c);
78034187Smckusick 			regs[c].sv_addr = addr;
78134187Smckusick 			regs[c].sv_value = value;
78234187Smckusick 			regs[c].sv_objsz = objsz;
78334187Smckusick 			continue;
78434187Smckusick 
78534187Smckusick 		case '<': /* restore saved address */
78634187Smckusick 			colon = 0;
78734187Smckusick 			should_print = 0;
78834187Smckusick 			c = getachar();
78934187Smckusick 			if (!letter(c) && !digit(c)) {
79034187Smckusick 				printf("invalid register specification, ");
79134187Smckusick 				printf("must be letter or digit\n");
79234187Smckusick 				error++;
79334187Smckusick 				continue;
79434187Smckusick 			}
79534187Smckusick 			if (letter(c)) {
79634187Smckusick 				if (c < 'a')
79734187Smckusick 					c = uppertolower(c);
79834187Smckusick 				c = hextodigit(c);
79934187Smckusick 			} else
80034187Smckusick 				c = numtodigit(c);
80134187Smckusick 			addr = regs[c].sv_addr;
80234187Smckusick 			value = regs[c].sv_value;
80334187Smckusick 			objsz = regs[c].sv_objsz;
80434187Smckusick 			continue;
80534187Smckusick 
80634187Smckusick 		case 'a':
80734187Smckusick 			if (colon)
80834187Smckusick 				colon = 0;
80934187Smckusick 			else
81034187Smckusick 				goto no_colon;
81134187Smckusick 			if (match("at", 2)) { 		/* access time */
81234187Smckusick 				acting_on_inode = 2;
81334187Smckusick 				should_print = 1;
81434187Smckusick 				addr = (long)
81534187Smckusick 					&((struct dinode *)cur_ino)->di_atime;
81634187Smckusick 				value = get(LONG);
81734187Smckusick 				type = NULL;
81834187Smckusick 				continue;
81934187Smckusick 			}
82034187Smckusick 			goto bad_syntax;
82134187Smckusick 
82234187Smckusick 		case 'b':
82334187Smckusick 			if (colon)
82434187Smckusick 				colon = 0;
82534187Smckusick 			else
82634187Smckusick 				goto no_colon;
82734187Smckusick 			if (match("block", 2)) { 	/* block conversion */
82834187Smckusick 				if (type == NUMB) {
82934187Smckusick 					value = addr;
83034187Smckusick 					cur_bytes = 0;
83134187Smckusick 					blocksize = BLKSIZE;
83234187Smckusick 					filesize = BLKSIZE * 2;
83334187Smckusick 				}
83434187Smckusick 				addr = value << FRGSHIFT;
83534187Smckusick 				bod_addr = addr;
83634187Smckusick 				value = get(LONG);
83734187Smckusick 				type = BLOCK;
83834187Smckusick 				dirslot = 0;
83934187Smckusick 				trapped++;
84034187Smckusick 				continue;
84134187Smckusick 			}
84234187Smckusick 			if (match("bs", 2)) {		/* block size */
84334187Smckusick 				acting_on_inode = 1;
84434187Smckusick 				should_print = 1;
84534187Smckusick 				if (icheck(cur_ino) == 0)
84634187Smckusick 					continue;
84734187Smckusick 				addr = (long)
84834187Smckusick 					&((struct dinode *)cur_ino)->di_blocks;
84934187Smckusick 				value = get(LONG);
85034187Smckusick 				type = NULL;
85134187Smckusick 				continue;
85234187Smckusick 			}
85334187Smckusick 			if (match("base", 2)) {		/* change/show base */
85434187Smckusick showbase:
85534187Smckusick 				if ((c = getachar()) == '\n') {
85634187Smckusick 					ungetachar(c);
85734187Smckusick 					printf("base =\t\t");
85834187Smckusick 					switch (base) {
85934187Smckusick 					case OCTAL:
86034187Smckusick 						printf("OCTAL\n");
86134187Smckusick 						continue;
86234187Smckusick 					case DECIMAL:
86334187Smckusick 						printf("DECIMAL\n");
86434187Smckusick 						continue;
86534187Smckusick 					case HEX:
86634187Smckusick 						printf("HEX\n");
86734187Smckusick 						continue;
86834187Smckusick 					}
86934187Smckusick 				}
87034187Smckusick 				if (c != '=') {
87134187Smckusick 					printf("missing '='\n");
87234187Smckusick 					error++;
87334187Smckusick 					continue;
87434187Smckusick 				}
87534187Smckusick 				value = expr();
87634187Smckusick 				switch (value) {
87734187Smckusick 				default:
87834187Smckusick 					printf("invalid base\n");
87934187Smckusick 					error++;
88034187Smckusick 					break;
88134187Smckusick 				case OCTAL:
88234187Smckusick 				case DECIMAL:
88334187Smckusick 				case HEX:
88434187Smckusick 					base = value;
88534187Smckusick 				}
88634187Smckusick 				goto showbase;
88734187Smckusick 			}
88834187Smckusick 			goto bad_syntax;
88934187Smckusick 
89034187Smckusick 		case 'c':
89134187Smckusick 			if (colon)
89234187Smckusick 				colon = 0;
89334187Smckusick 			else
89434187Smckusick 				goto no_colon;
89534187Smckusick 			if (match("cd", 2)) {		/* change directory */
89634187Smckusick 				top = filenames - 1;
89734187Smckusick 				eat_spaces();
89834187Smckusick 				if ((c = getachar()) == '\n') {
89934187Smckusick 					ungetachar(c);
90034187Smckusick 					current_pathp = -1;
90134187Smckusick 					restore_inode(2);
90234187Smckusick 					continue;
90334187Smckusick 				}
90434187Smckusick 				ungetachar(c);
90534187Smckusick 				temp = cur_inum;
90634187Smckusick 				doing_cd = 1;
90734187Smckusick 				parse();
90834187Smckusick 				doing_cd = 0;
90934187Smckusick 				if (nfiles != 1) {
91034187Smckusick 					restore_inode(temp);
91134187Smckusick 					if (!error) {
91234187Smckusick 						print_path(input_path,
91334187Smckusick 								input_pathp);
91434187Smckusick 						if (nfiles == 0)
91534187Smckusick 							printf(" not found\n");
91634187Smckusick 						else
91734187Smckusick 							printf(" ambiguous\n");
91834187Smckusick 						error++;
91934187Smckusick 					}
92034187Smckusick 					continue;
92134187Smckusick 				}
92234187Smckusick 				restore_inode(filenames->ino);
92334187Smckusick 				if ((mode = icheck(addr)) == 0)
92434187Smckusick 					continue;
92534187Smckusick 				if ((mode & IFMT) != IFDIR) {
92634187Smckusick 					restore_inode(temp);
92734187Smckusick 					print_path(input_path, input_pathp);
92834187Smckusick 					printf(" not a directory\n");
92934187Smckusick 					error++;
93034187Smckusick 					continue;
93134187Smckusick 				}
93234187Smckusick 				for (i = 0; i <= top->len; i++)
93334187Smckusick 					strcpy(current_path[i],
93434187Smckusick 						top->fname[i]);
93534187Smckusick 				current_pathp = top->len;
93634187Smckusick 				continue;
93734187Smckusick 			}
93834187Smckusick 			if (match("cg", 2)) {		/* cylinder group */
93934187Smckusick 				if (type == NUMB)
94034187Smckusick 					value = addr;
94134187Smckusick 				if (value > fs->fs_ncg - 1) {
94234187Smckusick 					printf("maximum cylinder group is ");
94334187Smckusick 					print(fs->fs_ncg - 1, 8, -8, 0);
94434187Smckusick 					printf("\n");
94534187Smckusick 					error++;
94634187Smckusick 					continue;
94734187Smckusick 				}
94834187Smckusick 				type = objsz = CGRP;
94934187Smckusick 				cur_cgrp = value;
95034187Smckusick 				addr = cgtod(fs, cur_cgrp) << FRGSHIFT;
95134187Smckusick 				continue;
95234187Smckusick 			}
95334187Smckusick 			if (match("ct", 2)) {		/* creation time */
95434187Smckusick 				acting_on_inode = 2;
95534187Smckusick 				should_print = 1;
95634187Smckusick 				addr = (long)
95734187Smckusick 					&((struct dinode *)cur_ino)->di_ctime;
95834187Smckusick 				value = get(LONG);
95934187Smckusick 				type = NULL;
96034187Smckusick 				continue;
96134187Smckusick 			}
96234187Smckusick 			goto bad_syntax;
96334187Smckusick 
96434187Smckusick 		case 'd':
96534187Smckusick 			if (colon)
96634187Smckusick 				colon = 0;
96734187Smckusick 			else
96834187Smckusick 				goto no_colon;
96934187Smckusick 			if (match("directory", 2)) { 	/* directory offsets */
97034187Smckusick 				if (type == NUMB)
97134187Smckusick 					value = addr;
97234187Smckusick 				objsz = DIRECTORY;
97334187Smckusick 				type = DIRECTORY;
97434187Smckusick 				addr = getdirslot(value);
97534187Smckusick 				continue;
97634187Smckusick 			}
97734187Smckusick 			if (match("db", 2)) {		/* direct block */
97834187Smckusick 				acting_on_inode = 1;
97934187Smckusick 				should_print = 1;
98034187Smckusick 				if (type == NUMB)
98134187Smckusick 					value = addr;
98234187Smckusick 				if (value >= NDADDR) {
98334187Smckusick 					printf("direct blocks are 0 to ");
98434187Smckusick 					print(NDADDR - 1, 0, 0, 0);
98534187Smckusick 					printf("\n");
98634187Smckusick 					error++;
98734187Smckusick 					continue;
98834187Smckusick 				}
98934187Smckusick 				addr = cur_ino;
99034187Smckusick 				if (!icheck(addr))
99134187Smckusick 					continue;
99234187Smckusick 				addr = (long)
99334187Smckusick 				      &((struct dinode *)cur_ino)->di_db[value];
99434187Smckusick 				bod_addr = addr;
99534187Smckusick 				cur_bytes = (value) * BLKSIZE;
99634187Smckusick 				cur_block = value;
99734187Smckusick 				type = BLOCK;
99834187Smckusick 				dirslot = 0;
99934187Smckusick 				value = get(LONG);
100034187Smckusick 				if (!value && !override) {
100134187Smckusick 					printf("non existent block\n");
100234187Smckusick 					error++;
100334187Smckusick 				}
100434187Smckusick 				continue;
100534187Smckusick 			}
100634187Smckusick 			goto bad_syntax;
100734187Smckusick 
100834187Smckusick 		case 'f':
100957998Sralph 			if (colon)
101034187Smckusick 				colon = 0;
101134187Smckusick 			else
101234187Smckusick 				goto no_colon;
101334187Smckusick 			if (match("find", 3)) {		/* find command */
101434187Smckusick 				find();
101534187Smckusick 				continue;
101634187Smckusick 			}
101734187Smckusick 			if (match("fragment", 2)) {	/* fragment conv. */
101834187Smckusick 				if (type == NUMB) {
101934187Smckusick 					value = addr;
102034187Smckusick 					cur_bytes = 0;
102134187Smckusick 					blocksize = FRGSIZE;
102234187Smckusick 					filesize = FRGSIZE * 2;
102334187Smckusick 				}
102434187Smckusick 				if (min(blocksize, filesize) - cur_bytes >
102534187Smckusick 							FRGSIZE) {
102634187Smckusick 					blocksize = cur_bytes + FRGSIZE;
102734187Smckusick 					filesize = blocksize * 2;
102834187Smckusick 				}
102934187Smckusick 				addr = value << FRGSHIFT;
103034187Smckusick 				bod_addr = addr;
103134187Smckusick 				value = get(LONG);
103234187Smckusick 				type = FRAGMENT;
103334187Smckusick 				dirslot = 0;
103434187Smckusick 				trapped++;
103534187Smckusick 				continue;
103634187Smckusick 			}
103734187Smckusick 			if (match("file", 4)) {		/* access as file */
103834187Smckusick 				acting_on_inode = 1;
103934187Smckusick 				should_print = 1;
104034187Smckusick 				if (type == NUMB)
104134187Smckusick 					value = addr;
104234187Smckusick 				addr = cur_ino;
104334187Smckusick 				if ((mode = icheck(addr)) == 0)
104434187Smckusick 					continue;
104534187Smckusick 				if ((mode & IFCHR) && !override) {
104634187Smckusick 					printf("special device\n");
104734187Smckusick 					error++;
104834187Smckusick 					continue;
104934187Smckusick 				}
105034187Smckusick 				if ((addr = (bmap(value) << FRGSHIFT)) == 0)
105134187Smckusick 					continue;
105234187Smckusick 				cur_block = value;
105334187Smckusick 				bod_addr = addr;
105434187Smckusick 				type = BLOCK;
105534187Smckusick 				dirslot = 0;
105634187Smckusick 				continue;
105734187Smckusick 			}
105834187Smckusick 			if (match("fill", 4)) {		/* fill */
105934187Smckusick 				if (getachar() != '=') {
106034187Smckusick 					printf("missing '='\n");
106134187Smckusick 					error++;
106234187Smckusick 					continue;
106334187Smckusick 				}
106434187Smckusick 				if (objsz == INODE || objsz == DIRECTORY) {
106534187Smckusick 				      printf("can't fill inode or directory\n");
106634187Smckusick 				      error++;
106734187Smckusick 				      continue;
106834187Smckusick 				}
106934187Smckusick 				fill();
107034187Smckusick 				continue;
107134187Smckusick 			}
107234187Smckusick 			goto bad_syntax;
107334187Smckusick 
107434187Smckusick 		case 'g':
107534187Smckusick 			if (colon)
107634187Smckusick 				colon = 0;
107734187Smckusick 			else
107834187Smckusick 				goto no_colon;
107934187Smckusick 			if (match("gid", 1)) {		/* group id */
108034187Smckusick 				acting_on_inode = 1;
108134187Smckusick 				should_print = 1;
108234187Smckusick 				addr = (long)
108334187Smckusick 					&((struct dinode *)cur_ino)->di_gid;
108434187Smckusick 				value = get(SHORT);
108534187Smckusick 				type = NULL;
108634187Smckusick 				continue;
108734187Smckusick 			}
108834187Smckusick 			goto bad_syntax;
108934187Smckusick 
109034187Smckusick 		case 'i':
109134187Smckusick 			if (colon)
109234187Smckusick 				colon = 0;
109334187Smckusick 			else
109434187Smckusick 				goto no_colon;
109534187Smckusick 			if (match("inode", 2)) { /* i# to inode conversion */
109634187Smckusick 				if (c_count == 2) {
109734187Smckusick 					addr = cur_ino;
109834187Smckusick 					value = get(INODE);
109934187Smckusick 					type = NULL;
110034187Smckusick 					laststyle = '=';
110134187Smckusick 					lastpo = 'i';
110234187Smckusick 					should_print = 1;
110334187Smckusick 					continue;
110434187Smckusick 				}
110534187Smckusick 				if (type == NUMB)
110634187Smckusick 					value = addr;
110734187Smckusick 				addr = itob(value);
110834187Smckusick 				if (!icheck(addr))
110934187Smckusick 					continue;
111034187Smckusick 				cur_ino = addr;
111134187Smckusick 				cur_inum = value;
111234187Smckusick 				value = get(INODE);
111334187Smckusick 				type = NULL;
111434187Smckusick 				continue;
111534187Smckusick 			}
111634187Smckusick 			if (match("ib", 2)) {	/* indirect block */
111734187Smckusick 				acting_on_inode = 1;
111834187Smckusick 				should_print = 1;
111934187Smckusick 				if (type == NUMB)
112034187Smckusick 					value = addr;
112134187Smckusick 				if (value >= NIADDR) {
112234187Smckusick 					printf("indirect blocks are 0 to ");
112334187Smckusick 					print(NIADDR - 1, 0, 0, 0);
112434187Smckusick 					printf("\n");
112534187Smckusick 					error++;
112634187Smckusick 					continue;
112734187Smckusick 				}
112834187Smckusick 				addr = (long)
112934187Smckusick 				      &((struct dinode *)cur_ino)->di_ib[value];
113034187Smckusick 				cur_bytes = (NDADDR - 1) * BLKSIZE;
113134187Smckusick 				temp = 1;
113234187Smckusick 				for (i = 0; i < value; i++) {
113334187Smckusick 					temp *= NINDIR(fs) * BLKSIZE;
113434187Smckusick 					cur_bytes += temp;
113534187Smckusick 				}
113634187Smckusick 				type = BLOCK;
113734187Smckusick 				dirslot = 0;
113834187Smckusick 				value = get(LONG);
113934187Smckusick 				if (!value && !override) {
114034187Smckusick 					printf("non existent block\n");
114134187Smckusick 					error++;
114234187Smckusick 				}
114334187Smckusick 				continue;
114434187Smckusick 			}
114534187Smckusick 			goto bad_syntax;
114634187Smckusick 
114734187Smckusick 		case 'l':
114834187Smckusick 			if (colon)
114934187Smckusick 				colon = 0;
115034187Smckusick 			else
115134187Smckusick 				goto no_colon;
115234187Smckusick 			if (match("ls", 2)) {		/* ls command */
115334187Smckusick 				temp = cur_inum;
115434187Smckusick 				recursive = long_list = 0;
115534187Smckusick 				top = filenames - 1;
115634187Smckusick 				for (;;) {
115734187Smckusick 					eat_spaces();
115834187Smckusick 					if ((c = getachar()) == '-') {
115934187Smckusick 						if ((c = getachar()) == 'R') {
116034187Smckusick 						  recursive = 1;
116134187Smckusick 						  continue;
116234187Smckusick 						} else if (c == 'l') {
116334187Smckusick 						  long_list = 1;
116434187Smckusick 						} else {
116534187Smckusick 						  printf("unknown option ");
116634187Smckusick 						  printf("'%c'\n", c);
116734187Smckusick 						  error++;
116834187Smckusick 						  break;
116934187Smckusick 						}
117034187Smckusick 					} else
117134187Smckusick 						ungetachar(c);
117234187Smckusick 					if ((c = getachar()) == '\n') {
117334187Smckusick 						if (c_count != 2) {
117434187Smckusick 							ungetachar(c);
117534187Smckusick 							break;
117634187Smckusick 						}
117734187Smckusick 					}
117834187Smckusick 					c_count++;
117934187Smckusick 					ungetachar(c);
118034187Smckusick 					parse();
118134187Smckusick 					restore_inode(temp);
118234187Smckusick 					if (error)
118334187Smckusick 						break;
118434187Smckusick 				}
118534187Smckusick 				recursive = 0;
118634187Smckusick 				if (error || nfiles == 0) {
118734187Smckusick 					if (!error) {
118834187Smckusick 						print_path(input_path,
118934187Smckusick 								input_pathp);
119034187Smckusick 						printf(" not found\n");
119134187Smckusick 					}
119234187Smckusick 					continue;
119334187Smckusick 				}
119434187Smckusick 				if (nfiles) {
119534187Smckusick 				    cmp_level = 0;
119634187Smckusick 				    qsort((char *)filenames, nfiles,
119734187Smckusick 					sizeof (struct filenames), ffcmp);
119834187Smckusick 				    ls(filenames, filenames + (nfiles - 1), 0);
119934187Smckusick 				} else {
120034187Smckusick 				    printf("no match\n");
120134187Smckusick 				    error++;
120234187Smckusick 				}
120334187Smckusick 				restore_inode(temp);
120434187Smckusick 				continue;
120534187Smckusick 			}
120634187Smckusick 			if (match("ln", 2)) {		/* link count */
120734187Smckusick 				acting_on_inode = 1;
120834187Smckusick 				should_print = 1;
120934187Smckusick 				addr = (long)
121034187Smckusick 					&((struct dinode *)cur_ino)->di_nlink;
121134187Smckusick 				value = get(SHORT);
121234187Smckusick 				type = NULL;
121334187Smckusick 				continue;
121434187Smckusick 			}
121534187Smckusick 			goto bad_syntax;
121634187Smckusick 
121734187Smckusick 		case 'm':
121834187Smckusick 			if (colon)
121934187Smckusick 				colon = 0;
122034187Smckusick 			else
122134187Smckusick 				goto no_colon;
122234187Smckusick 			addr = cur_ino;
122334187Smckusick 			if ((mode = icheck(addr)) == 0)
122434187Smckusick 				continue;
122534187Smckusick 			if (match("mt", 2)) { 		/* modification time */
122634187Smckusick 				acting_on_inode = 2;
122734187Smckusick 				should_print = 1;
122834187Smckusick 				addr = (long)
122934187Smckusick 					&((struct dinode *)cur_ino)->di_mtime;
123034187Smckusick 				value = get(LONG);
123134187Smckusick 				type = NULL;
123234187Smckusick 				continue;
123334187Smckusick 			}
123434187Smckusick 			if (match("md", 2)) {		/* mode */
123534187Smckusick 				acting_on_inode = 1;
123634187Smckusick 				should_print = 1;
123734187Smckusick 				addr = (long)
123834187Smckusick 					&((struct dinode *)cur_ino)->di_mode;
123934187Smckusick 				value = get(SHORT);
124034187Smckusick 				type = NULL;
124134187Smckusick 				continue;
124234187Smckusick 			}
124334187Smckusick 			if (match("maj", 2)) {	/* major device number */
124434187Smckusick 				acting_on_inode = 1;
124534187Smckusick 				should_print = 1;
124634187Smckusick 				if (devcheck(mode))
124734187Smckusick 					continue;
124834187Smckusick 				addr = (long)
124934187Smckusick 					&((struct dinode *)cur_ino)->di_db[1];
125034187Smckusick 				value = get(LONG);
125134187Smckusick 				type = NULL;
125234187Smckusick 				continue;
125334187Smckusick 			}
125434187Smckusick 			if (match("min", 2)) {	/* minor device number */
125534187Smckusick 				acting_on_inode = 1;
125634187Smckusick 				should_print = 1;
125734187Smckusick 				if (devcheck(mode))
125834187Smckusick 					continue;
125934187Smckusick 				addr = (long)
126034187Smckusick 					&((struct dinode *)cur_ino)->di_db[0];
126134187Smckusick 				value = get(LONG);
126234187Smckusick 				type = NULL;
126334187Smckusick 				continue;
126434187Smckusick 			}
126534187Smckusick 			goto bad_syntax;
126634187Smckusick 
126734187Smckusick 		case 'n':
126834187Smckusick 			if (colon)
126934187Smckusick 				colon = 0;
127034187Smckusick 			else
127134187Smckusick 				goto no_colon;
127234187Smckusick 			if (match("nm", 1)) {		/* directory name */
127334187Smckusick 				objsz = DIRECTORY;
127434187Smckusick 				acting_on_directory = 1;
127534187Smckusick 				cur_dir = addr;
127634187Smckusick 				if ((cptr = getblk(addr)) == 0)
127734187Smckusick 					continue;
127834187Smckusick 				dirp = (struct direct *)(cptr+blkoff(fs, addr));
127934187Smckusick 				stringsize = (long)dirp->d_reclen -
128034187Smckusick 				  ((long)&dirp->d_name[0] - (long)&dirp->d_ino);
128134187Smckusick 				addr = (long)
128234187Smckusick 					&((struct direct *)addr)->d_name[0];
128334187Smckusick 				type = NULL;
128434187Smckusick 				continue;
128534187Smckusick 			}
128634187Smckusick 			goto bad_syntax;
128734187Smckusick 
128834187Smckusick 		case 'o':
128957998Sralph 			if (colon)
129034187Smckusick 				colon = 0;
129134187Smckusick 			else
129234187Smckusick 				goto no_colon;
129334187Smckusick 			if (match("override", 1)) {	/* override flip flop */
129434187Smckusick 				if (override = !override)
129534187Smckusick 					printf("error checking off\n");
129634187Smckusick 				else
129734187Smckusick 					printf("error checking on\n");
129834187Smckusick 				continue;
129934187Smckusick 			}
130034187Smckusick 			goto bad_syntax;
130134187Smckusick 
130234187Smckusick 		case 'p':
130334187Smckusick 			if (colon)
130434187Smckusick 				colon = 0;
130534187Smckusick 			else
130634187Smckusick 				goto no_colon;
130734187Smckusick 			if (match("pwd", 2)) {		/* print working dir */
130834187Smckusick 				print_path(current_path, current_pathp);
130934187Smckusick 				printf("\n");
131034187Smckusick 				continue;
131134187Smckusick 			}
131234187Smckusick 			if (match("prompt", 2)) {	/* change prompt */
131334187Smckusick 				if ((c = getachar()) != '=') {
131434187Smckusick 					printf("missing '='\n");
131534187Smckusick 					error++;
131634187Smckusick 					continue;
131734187Smckusick 				}
131834187Smckusick 				if ((c = getachar()) != '"') {
131934187Smckusick 					printf("missing '\"'\n");
132034187Smckusick 					error++;
132134187Smckusick 					continue;
132234187Smckusick 				}
132334187Smckusick 				i = 0;
132434187Smckusick 				prompt = &prompt[0];
132534187Smckusick 				while ((c = getachar()) != '"' &&
132634187Smckusick 				       c != '\n') {
132734187Smckusick 					prompt[i++] = c;
132834187Smckusick 					if (i >= PROMPTSIZE) {
132934187Smckusick 						printf("string too long\n");
133034187Smckusick 						error++;
133134187Smckusick 						break;
133234187Smckusick 					}
133334187Smckusick 				}
133434187Smckusick 				prompt[i] = '\0';
133534187Smckusick 				continue;
133634187Smckusick 			}
133734187Smckusick 			goto bad_syntax;
133857998Sralph 
133934187Smckusick 		case 'q':
134034187Smckusick 			if (!colon)
134134187Smckusick 				goto no_colon;
134234187Smckusick 			if (match("quit", 1)) {		/* quit */
134334187Smckusick 				if ((c = getachar()) != '\n') {
134434187Smckusick 					error++;
134534187Smckusick 					continue;
134634187Smckusick 				}
134734187Smckusick 				exit(0);
134834187Smckusick 			}
134934187Smckusick 			goto bad_syntax;
135034187Smckusick 
135134187Smckusick 		case 's':
135234187Smckusick 			if (colon)
135334187Smckusick 				colon = 0;
135434187Smckusick 			else
135534187Smckusick 				goto no_colon;
135634187Smckusick 			if (match("sb", 2)) {		/* super block */
135734187Smckusick 				if (c_count == 2) {
135834187Smckusick 					cur_cgrp = -1;
135934187Smckusick 					type = objsz = SB;
136034187Smckusick 					laststyle = '=';
136134187Smckusick 					lastpo = 's';
136234187Smckusick 					should_print = 1;
136334187Smckusick 					continue;
136434187Smckusick 				}
136534187Smckusick 				if (type == NUMB)
136634187Smckusick 					value = addr;
136734187Smckusick 				if (value > fs->fs_ncg - 1) {
136834187Smckusick 					printf("maximum super block is ");
136934187Smckusick 					print(fs->fs_ncg - 1, 8, -8, 0);
137034187Smckusick 					printf("\n");
137134187Smckusick 					error++;
137234187Smckusick 					continue;
137334187Smckusick 				}
137434187Smckusick 				type = objsz = SB;
137534187Smckusick 				cur_cgrp = value;
137634187Smckusick 				addr = cgsblock(fs, cur_cgrp) << FRGSHIFT;
137734187Smckusick 				continue;
137834187Smckusick 			}
137934187Smckusick 			if (match("sz", 2)) {		/* file size */
138034187Smckusick 				acting_on_inode = 1;
138134187Smckusick 				should_print = 1;
138234187Smckusick 				addr = (long)
138334187Smckusick 					&((struct dinode *)cur_ino)->di_size;
138434187Smckusick 				value = get(LONG);
138534187Smckusick 				type = NULL;
138634187Smckusick 				continue;
138734187Smckusick 			}
138834187Smckusick 			goto bad_syntax;
138934187Smckusick 
139034187Smckusick 		case 'u':
139134187Smckusick 			if (colon)
139234187Smckusick 				colon = 0;
139334187Smckusick 			else
139434187Smckusick 				goto no_colon;
139534187Smckusick 			if (match("uid", 1)) {		/* user id */
139634187Smckusick 				acting_on_inode = 1;
139734187Smckusick 				should_print = 1;
139834187Smckusick 				addr = (long)
139934187Smckusick 					&((struct dinode *)cur_ino)->di_uid;
140034187Smckusick 				value = get(SHORT);
140134187Smckusick 				type = NULL;
140234187Smckusick 				continue;
140334187Smckusick 			}
140434187Smckusick 			goto bad_syntax;
140534187Smckusick 
140634187Smckusick 		case 'F': /* buffer status (internal use only) */
140757998Sralph 			if (colon)
140834187Smckusick 				colon = 0;
140934187Smckusick 			else
141034187Smckusick 				goto no_colon;
141134187Smckusick 			for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
141257998Sralph 				printf("%8x %d\n", bp->blkno, bp->valid);
141334187Smckusick 			printf("\n");
141434187Smckusick 			printf("# commands\t\t%d\n", commands);
141534187Smckusick 			printf("# read requests\t\t%d\n", read_requests);
141634187Smckusick 			printf("# actual disk reads\t%d\n", actual_disk_reads);
141734187Smckusick 			continue;
141834187Smckusick no_colon:
141934187Smckusick 		printf("a colon should precede a command\n");
142034187Smckusick 		error++;
142134187Smckusick 		continue;
142234187Smckusick bad_syntax:
142334187Smckusick 		printf("more letters needed to distinguish command\n");
142434187Smckusick 		error++;
142534187Smckusick 		continue;
142634187Smckusick 		}
142734187Smckusick 	}
142834187Smckusick }
142934187Smckusick 
143034187Smckusick /*
143134187Smckusick  * getachar - get next character from input buffer.
143234187Smckusick  */
143334187Smckusick char
getachar()143434187Smckusick getachar()
143534187Smckusick {
143634187Smckusick 	return(input_buffer[input_pointer++]);
143734187Smckusick }
143834187Smckusick 
143934187Smckusick /*
144034187Smckusick  * ungetachar - return character to input buffer.
144134187Smckusick  */
ungetachar(c)144234187Smckusick ungetachar(c)
144334187Smckusick 	register char	c;
144434187Smckusick {
144534187Smckusick 	if (input_pointer == 0) {
144634187Smckusick 		printf("internal problem maintaining input buffer\n");
144734187Smckusick 		error++;
144834187Smckusick 		return;
144934187Smckusick 	}
145034187Smckusick 	input_buffer[--input_pointer] = c;
145134187Smckusick }
145234187Smckusick 
145334187Smckusick /*
145434187Smckusick  * getnextinput - display the prompt and read an input line.
145534187Smckusick  *	An input line is up to 128 characters terminated by the newline
145634187Smckusick  *	character.  Handle overflow, shell escape, and eof.
145734187Smckusick  */
getnextinput()145834187Smckusick getnextinput()
145934187Smckusick {
146034187Smckusick 	register int	i;
146134187Smckusick 	register char	c;
146234187Smckusick 	register short	pid, rpid;
146334187Smckusick 	int		retcode;
146434187Smckusick 
146534187Smckusick newline:
146634187Smckusick 	i = 0;
146734187Smckusick 	printf("%s", prompt);
146834187Smckusick ignore_eol:
146934187Smckusick 	while ((c = getc(stdin)) != '\n' && !(c == '!' && i == 0) &&
147034187Smckusick 	       !feof(stdin) && i <= INPUTBUFFER - 2)
147134187Smckusick 		input_buffer[i++] = c;
147234187Smckusick 	if (input_buffer[i - 1] == '\\') {
147334187Smckusick 		input_buffer[i++] = c;
147434187Smckusick 		goto ignore_eol;
147534187Smckusick 	}
147634187Smckusick 	if (feof(stdin)) {
147734187Smckusick 		printf("\n");
147834187Smckusick 		exit(0);
147934187Smckusick 	}
148034187Smckusick 	if (c == '!') {
148134187Smckusick 		if ((pid = fork()) == 0) {
148237271Sbostic 			execl(_PATH_BSHELL, "sh", "-t", 0);
148334187Smckusick 			error++;
148434187Smckusick 			return;
148534187Smckusick 		}
148634187Smckusick 		while ((rpid = wait(&retcode)) != pid && rpid != -1)
148734187Smckusick 			;
148834187Smckusick 		printf("!\n");
148934187Smckusick 		goto newline;
149034187Smckusick 	}
149134187Smckusick 	if (c != '\n')
149234187Smckusick 		printf("input truncated to 128 characters\n");
149334187Smckusick 	input_buffer[i] = '\n';
149434187Smckusick 	input_pointer = 0;
149534187Smckusick }
149634187Smckusick 
149734187Smckusick /*
149834187Smckusick  * eat_spaces - read extraneous spaces.
149934187Smckusick  */
eat_spaces()150034187Smckusick eat_spaces()
150134187Smckusick {
150234187Smckusick 	register char	c;
150334187Smckusick 
150434187Smckusick 	while ((c = getachar()) == ' ')
150534187Smckusick 		;
150634187Smckusick 	ungetachar(c);
150734187Smckusick }
150834187Smckusick 
150934187Smckusick /*
151034187Smckusick  * restore_inode - set up all inode indicators so inum is now
151134187Smckusick  *	the current inode.
151234187Smckusick  */
restore_inode(inum)151334187Smckusick restore_inode(inum)
151434187Smckusick 	long		inum;
151534187Smckusick {
151634187Smckusick 	errinum = cur_inum = inum;
151734187Smckusick 	addr = errino = cur_ino = itob(inum);
151834187Smckusick }
151934187Smckusick 
152034187Smckusick /*
152134187Smckusick  * match - return false if the input does not match string up to
152234187Smckusick  *	upto letters.   Then proceed to chew up extraneous letters.
152334187Smckusick  */
match(string,upto)152434187Smckusick match(string, upto)
152534187Smckusick 	register char	*string;
152634187Smckusick 	register int	upto;
152734187Smckusick {
152834187Smckusick 	register int	i, length = strlen(string) - 1;
152934187Smckusick 	register char	c;
153034187Smckusick 	int		save_upto = upto;
153134187Smckusick 
153234187Smckusick 	while (--upto) {
153334187Smckusick 		string++;
153434187Smckusick 		if ((c = getachar()) != *string) {
153534187Smckusick 			for (i = save_upto - upto; i; i--) {
153634187Smckusick 				ungetachar(c);
153734187Smckusick 				c = *--string;
153834187Smckusick 			}
153934187Smckusick 			return(0);
154034187Smckusick 		}
154134187Smckusick 		length--;
154234187Smckusick 	}
154334187Smckusick 	while (length--) {
154434187Smckusick 		string++;
154534187Smckusick 		if ((c = getachar()) != *string) {
154634187Smckusick 			ungetachar(c);
154734187Smckusick 			return(1);
154834187Smckusick 		}
154934187Smckusick 	}
155034187Smckusick 	return(1);
155134187Smckusick }
155234187Smckusick 
155334187Smckusick /*
155434187Smckusick  * expr - expression evaluator.  Will evaluate expressions from
155534187Smckusick  *	left to right with no operator precedence.  Parentheses may
155634187Smckusick  *	be used.
155734187Smckusick  */
155834187Smckusick long
expr()155934187Smckusick expr()
156034187Smckusick {
156134187Smckusick 	register long	numb = 0, temp;
156234187Smckusick 	register char	c;
156334187Smckusick 
156434187Smckusick 	numb = term();
156534187Smckusick 	for (;;) {
156634187Smckusick 		if (error)
156734187Smckusick 			return;
156834187Smckusick 		c = getachar();
156934187Smckusick 		switch (c) {
157034187Smckusick 
157134187Smckusick 		case '+':
157234187Smckusick 			numb += term();
157334187Smckusick 			continue;
157434187Smckusick 
157534187Smckusick 		case '-':
157634187Smckusick 			numb -= term();
157734187Smckusick 			continue;
157834187Smckusick 
157934187Smckusick 		case '*':
158034187Smckusick 			numb *= term();
158134187Smckusick 			continue;
158234187Smckusick 
158334187Smckusick 		case '%':
158434187Smckusick 			temp = term();
158534187Smckusick 			if (!temp) {
158634187Smckusick 				printf("divide by zero\n");
158734187Smckusick 				error++;
158834187Smckusick 				return;
158934187Smckusick 			}
159034187Smckusick 			numb /= temp;
159134187Smckusick 			continue;
159234187Smckusick 
159334187Smckusick 		case ')':
159434187Smckusick 			paren--;
159534187Smckusick 			return(numb);
159634187Smckusick 
159734187Smckusick 		default:
159834187Smckusick 			ungetachar(c);
159934187Smckusick 			if (paren && !error) {
160034187Smckusick 				printf("missing ')'\n");
160134187Smckusick 				error++;
160234187Smckusick 			}
160334187Smckusick 			return(numb);
160434187Smckusick 		}
160534187Smckusick 	}
160634187Smckusick }
160734187Smckusick 
160834187Smckusick /*
160934187Smckusick  * term - used by expression evaluator to get an operand.
161034187Smckusick  */
161134187Smckusick long
term()161234187Smckusick term()
161334187Smckusick {
161434187Smckusick 	register char	c;
161534187Smckusick 
161634187Smckusick 	switch (c = getachar()) {
161734187Smckusick 
161834187Smckusick 	default:
161934187Smckusick 		ungetachar(c);
162034187Smckusick 
162134187Smckusick 	case '+':
162234187Smckusick 		return(getnumb());
162334187Smckusick 
162434187Smckusick 	case '-':
162534187Smckusick 		return(-getnumb());
162634187Smckusick 
162734187Smckusick 	case '(':
162834187Smckusick 		paren++;
162934187Smckusick 		return(expr());
163034187Smckusick 	}
163134187Smckusick }
163234187Smckusick 
163334187Smckusick /*
163434187Smckusick  * getnumb - read a number from the input stream.  A leading
163534187Smckusick  *	zero signifies octal interpretation, a leading '0x'
163634187Smckusick  *	signifies hexadecimal, and a leading '0t' signifies
163734187Smckusick  *	decimal.  If the first character is a character,
163834187Smckusick  *	return an error.
163934187Smckusick  */
164034187Smckusick long
getnumb()164134187Smckusick getnumb()
164234187Smckusick {
164334187Smckusick 
164434187Smckusick 	register char	c, savec;
164534187Smckusick 	long		number = 0, tbase, num;
164634187Smckusick 	extern short	error;
164734187Smckusick 
164834187Smckusick 	c = getachar();
164934187Smckusick 	if (!digit(c)) {
165034187Smckusick 		error++;
165134187Smckusick 		ungetachar(c);
165234187Smckusick 		return(-1);
165334187Smckusick 	}
165434187Smckusick 	if (c == '0') {
165534187Smckusick 		tbase = OCTAL;
165634187Smckusick 		if ((c = getachar()) == 'x')
165734187Smckusick 			tbase = HEX;
165834187Smckusick 		else if (c == 't')
165934187Smckusick 			tbase = DECIMAL;
166034187Smckusick 		else ungetachar(c);
166134187Smckusick 	} else {
166234187Smckusick 		tbase = base;
166334187Smckusick 		ungetachar(c);
166434187Smckusick 	}
166534187Smckusick 	for (;;) {
166634187Smckusick 		num = tbase;
166734187Smckusick 		c = savec = getachar();
166834187Smckusick 		if (HEXLETTER(c))
166934187Smckusick 			c = uppertolower(c);
167034187Smckusick 		switch (tbase) {
167134187Smckusick 		case HEX:
167234187Smckusick 			if (hexletter(c)) {
167334187Smckusick 				num = hextodigit(c);
167434187Smckusick 				break;
167534187Smckusick 			}
167634187Smckusick 		case DECIMAL:
167734187Smckusick 			if (digit(c))
167834187Smckusick 				num = numtodigit(c);
167934187Smckusick 			break;
168034187Smckusick 		case OCTAL:
168134187Smckusick 			if (octaldigit(c))
168234187Smckusick 				num = numtodigit(c);
168334187Smckusick 		}
168434187Smckusick 		if (num == tbase)
168534187Smckusick 			break;
168634187Smckusick 		number = number * tbase + num;
168734187Smckusick 	}
168834187Smckusick 	ungetachar(savec);
168934187Smckusick 	return(number);
169034187Smckusick }
169134187Smckusick 
169234187Smckusick /*
169334187Smckusick  * find - the syntax is almost identical to the unix command.
169434187Smckusick  *		find dir [-name pattern] [-inum number]
169534187Smckusick  *	Note:  only one of -name or -inum may be used at a time.
169634187Smckusick  *	       Also, the -print is not needed (implied).
169734187Smckusick  */
find()169834187Smckusick find()
169934187Smckusick {
170034187Smckusick 	register struct filenames	*fn;
170134187Smckusick 	register char			c;
170234187Smckusick 	long				temp;
170334187Smckusick 	short				mode;
170434187Smckusick 
170534187Smckusick 	eat_spaces();
170634187Smckusick 	temp = cur_inum;
170734187Smckusick 	top = filenames - 1;
170834187Smckusick 	doing_cd = 1;
170934187Smckusick 	parse();
171034187Smckusick 	doing_cd = 0;
171134187Smckusick 	if (nfiles != 1) {
171234187Smckusick 		restore_inode(temp);
171334187Smckusick 		if (!error) {
171434187Smckusick 			print_path(input_path, input_pathp);
171534187Smckusick 			if (nfiles == 0)
171634187Smckusick 				printf(" not found\n");
171734187Smckusick 			else
171834187Smckusick 				printf(" ambiguous\n");
171934187Smckusick 			error++;
172034187Smckusick 			return;
172134187Smckusick 		}
172234187Smckusick 	}
172334187Smckusick 	restore_inode(filenames->ino);
172434187Smckusick 	freemem(filenames, nfiles);
172534187Smckusick 	nfiles = 0;
172634187Smckusick 	top = filenames - 1;
172734187Smckusick 	if ((mode = icheck(addr)) == 0)
172834187Smckusick 		return;
172934187Smckusick 	if ((mode & IFMT) != IFDIR) {
173034187Smckusick 		print_path(input_path, input_pathp);
173134187Smckusick 		printf(" not a directory\n");
173234187Smckusick 		error++;
173334187Smckusick 		return;
173434187Smckusick 	}
173534187Smckusick 	eat_spaces();
173634187Smckusick 	if ((c = getachar()) != '-') {
173734187Smckusick 		printf("missing '-'\n");
173834187Smckusick 		error++;
173934187Smckusick 		return;
174034187Smckusick 	}
174134187Smckusick 	find_by_name = find_by_inode = 0;
174234187Smckusick 	c = getachar();
174334187Smckusick 	if (match("name", 4)) {
174434187Smckusick 		eat_spaces();
174534187Smckusick 		find_by_name = 1;
174634187Smckusick 	} else if (match("inum", 4)) {
174734187Smckusick 		eat_spaces();
174834187Smckusick 		find_ino = expr();
174934187Smckusick 		if (error)
175034187Smckusick 			return;
175134187Smckusick 		while ((c = getachar()) != '\n')
175234187Smckusick 			;
175334187Smckusick 		ungetachar(c);
175434187Smckusick 		find_by_inode = 1;
175534187Smckusick 	} else {
175634187Smckusick 		printf("use -name or -inum with find\n");
175734187Smckusick 		error++;
175834187Smckusick 		return;
175934187Smckusick 	}
176034187Smckusick 	doing_find = 1;
176134187Smckusick 	parse();
176234187Smckusick 	doing_find = 0;
176334187Smckusick 	if (error) {
176434187Smckusick 		restore_inode(temp);
176534187Smckusick 		return;
176634187Smckusick 	}
176734187Smckusick 	for (fn = filenames; fn <= top; fn++) {
176834187Smckusick 		if (fn->find == 0)
176934187Smckusick 			continue;
177034187Smckusick 		printf("i#: ");
177134187Smckusick 		print(fn->ino, 12, -8, 0);
177234187Smckusick 		print_path(fn->fname, fn->len);
177334187Smckusick 		printf("\n");
177434187Smckusick 	}
177534187Smckusick 	restore_inode(temp);
177634187Smckusick }
177734187Smckusick 
177834187Smckusick /*
177934187Smckusick  * ls - do an ls.  Should behave exactly as ls(1).
178034187Smckusick  *	Only -R and -l is supported and -l gives different results.
178134187Smckusick  */
178234187Smckusick ls(fn0, fnlast, level)
178334187Smckusick 	struct filenames		*fn0, *fnlast;
178434187Smckusick 	short				level;
178534187Smckusick {
178634187Smckusick 	register struct filenames	*fn, *fnn;
178734187Smckusick 	register int			i;
178834187Smckusick 	int				fcmp();
178934187Smckusick 
179034187Smckusick 	fn = fn0;
179134187Smckusick 	for (;;) {
179234187Smckusick 		fn0 = fn;
179334187Smckusick 		if (fn0->len) {
179434187Smckusick 			cmp_level = level;
179534187Smckusick 			qsort((char *)fn0, fnlast - fn0 + 1,
179634187Smckusick 				sizeof (struct filenames), fcmp);
179734187Smckusick 		}
179834187Smckusick 		for (fnn = fn, fn++; fn <= fnlast; fnn = fn, fn++) {
179934187Smckusick 			if (fnn->len != fn->len && level == fnn->len - 1)
180034187Smckusick 				break;
180134187Smckusick 			if (fnn->len == 0)
180234187Smckusick 				continue;
180334187Smckusick 			if (strcmp(fn->fname[level], fnn->fname[level]))
180434187Smckusick 				break;
180534187Smckusick 		}
180634187Smckusick 		if (fn0->len && level != fn0->len - 1)
180734187Smckusick 			ls(fn0, fnn, level + 1);
180834187Smckusick 		else {
180934187Smckusick 			if (fn0 != filenames)
181034187Smckusick 				printf("\n");
181134187Smckusick 			print_path(fn0->fname, fn0->len - 1);
181234187Smckusick 			printf(":\n");
181334187Smckusick 			if (fn0->len == 0)
181434187Smckusick 				cmp_level = level;
181534187Smckusick 			else
181634187Smckusick 				cmp_level = level + 1;
181734187Smckusick 			qsort((char *)fn0, fnn - fn0 + 1,
181834187Smckusick 				sizeof (struct filenames), fcmp);
181934187Smckusick 			formatf(fn0, fnn);
182034187Smckusick 			nfiles -= fnn - fn0 + 1;
182134187Smckusick 		}
182234187Smckusick 		if (fn > fnlast)
182334187Smckusick 			return;
182434187Smckusick 	}
182534187Smckusick }
182634187Smckusick 
182734187Smckusick /*
182834187Smckusick  * formatf - code lifted from ls.
182934187Smckusick  */
formatf(fn0,fnlast)183034187Smckusick formatf(fn0, fnlast)
183134187Smckusick 	register struct filenames	*fn0, *fnlast;
183234187Smckusick {
183334187Smckusick 	register struct filenames	*fn;
183434187Smckusick 	int				width = 0, w, nentry = fnlast - fn0 + 1;
183534187Smckusick 	int				i, j, columns, lines;
183634187Smckusick 	char				*cp;
183734187Smckusick 
183834187Smckusick 	if (long_list) {
183934187Smckusick 		columns = 1;
184034187Smckusick 	} else {
184134187Smckusick 		for (fn = fn0; fn <= fnlast; fn++) {
184234187Smckusick 			int len = strlen(fn->fname[cmp_level]) + 2;
184334187Smckusick 
184434187Smckusick 			if (len > width)
184534187Smckusick 				width = len;
184634187Smckusick 		}
184734187Smckusick 		width = (width + 8) &~ 7;
184834187Smckusick 		columns = 80 / width;
184934187Smckusick 		if (columns == 0)
185034187Smckusick 			columns = 1;
185134187Smckusick 	}
185234187Smckusick 	lines = (nentry + columns - 1) / columns;
185334187Smckusick 	for (i = 0; i < lines; i++) {
185434187Smckusick 		for (j = 0; j < columns; j++) {
185534187Smckusick 			fn = fn0 + j * lines + i;
185634187Smckusick 			if (long_list) {
185734187Smckusick 				printf("i#: ");
185834187Smckusick 				print(fn->ino, 12, -8, 0);
185934187Smckusick 			}
186034187Smckusick 			cp = fmtentry(fn);
186134187Smckusick 			printf("%s", cp);
186234187Smckusick 			if (fn + lines > fnlast) {
186334187Smckusick 				printf("\n");
186434187Smckusick 				break;
186534187Smckusick 			}
186634187Smckusick 			w = strlen(cp);
186734187Smckusick 			while (w < width) {
186834187Smckusick 				w = (w + 8) &~ 7;
186934187Smckusick 				putchar('\t');
187034187Smckusick 			}
187134187Smckusick 		}
187234187Smckusick 	}
187334187Smckusick }
187434187Smckusick 
187534187Smckusick /*
187634187Smckusick  * fmtentry - code lifted from ls.
187734187Smckusick  */
187834187Smckusick char *
fmtentry(fn)187934187Smckusick fmtentry(fn)
188034187Smckusick 	register struct filenames	*fn;
188134187Smckusick {
188234187Smckusick 	static char			fmtres[BUFSIZ];
188334187Smckusick 	register struct dinode		*ip;
188434187Smckusick 	register char			*cptr, *cp, *dp;
188534187Smckusick 
188634187Smckusick 	dp = &fmtres[0];
188734187Smckusick 	for (cp = fn->fname[cmp_level]; *cp; cp++) {
188834187Smckusick 		if (*cp < ' ' || *cp >= 0177)
188934187Smckusick 			*dp++ = '?';
189034187Smckusick 		else
189134187Smckusick 			*dp++ = *cp;
189234187Smckusick 	}
189334187Smckusick 	addr = itob(fn->ino);
189434187Smckusick 	if ((cptr = getblk(addr)) == 0)
189534187Smckusick 		return(NULL);
189634187Smckusick 	cptr += blkoff(fs, addr);
189734187Smckusick 	ip = (struct dinode *)cptr;
189834187Smckusick 	switch (ip->di_mode & IFMT) {
189934187Smckusick 	case IFDIR:
190034187Smckusick 		*dp++ = '/';
190134187Smckusick 		break;
190234187Smckusick 	case IFLNK:
190334187Smckusick 		*dp++ = '@';
190434187Smckusick 		break;
190534187Smckusick 	case IFSOCK:
190634187Smckusick 		*dp++ = '=';
190734187Smckusick 		break;
190836249Smckusick #ifdef IFIFO
190936249Smckusick 	case IFIFO:
191036249Smckusick 		*dp++ = 'p';
191136249Smckusick 		break;
191236249Smckusick #endif
191334187Smckusick 	case IFCHR:
191434187Smckusick 	case IFBLK:
191534187Smckusick 	case IFREG:
191634187Smckusick 		if (ip->di_mode & 0111)
191734187Smckusick 			*dp++ = '*';
191834187Smckusick 		else
191934187Smckusick 			*dp++ = ' ';
192034187Smckusick 		break;
192134187Smckusick 	default:
192234187Smckusick 		*dp++ = '?';
192334187Smckusick 
192434187Smckusick 	}
192534187Smckusick 	*dp++ = 0;
192634187Smckusick 	return (fmtres);
192734187Smckusick }
192834187Smckusick 
192934187Smckusick /*
193034187Smckusick  * fcmp - routine used by qsort.  Will sort first by name, then
193134187Smckusick  *	then by pathname length if names are equal.  Uses global
193234187Smckusick  *	cmp_level to tell what component of the path name we are comparing.
193334187Smckusick  */
fcmp(f1,f2)193434187Smckusick fcmp(f1, f2)
193534187Smckusick 	register struct filenames	*f1, *f2;
193634187Smckusick {
193734187Smckusick 	int 				value;
193834187Smckusick 
193934187Smckusick 	if ((value = strcmp(f1->fname[cmp_level], f2->fname[cmp_level])))
194034187Smckusick 		return(value);
194134187Smckusick 	return (f1->len - f2->len);
194234187Smckusick }
194334187Smckusick 
194434187Smckusick /*
194534187Smckusick  * ffcmp - routine used by qsort.  Sort only by pathname length.
194634187Smckusick  */
ffcmp(f1,f2)194734187Smckusick ffcmp(f1, f2)
194834187Smckusick 	register struct filenames	*f1, *f2;
194934187Smckusick {
195034187Smckusick 	return (f1->len - f2->len);
195134187Smckusick }
195234187Smckusick 
195334187Smckusick /*
195434187Smckusick  * parse - set up the call to follow_path.
195534187Smckusick  */
parse()195634187Smckusick parse()
195734187Smckusick {
195834187Smckusick 	register int	i, j;
195934187Smckusick 	char		c;
196034187Smckusick 
196134187Smckusick 	stack_pathp = input_pathp = -1;
196234187Smckusick 	if ((c = getachar()) == '/') {
196334187Smckusick 		while ((c = getachar()) == '/')
196434187Smckusick 			;
196534187Smckusick 		ungetachar(c);
196634187Smckusick 		cur_inum = 2;
196734187Smckusick 		if ((c = getachar()) == '\n') {
196834187Smckusick 			ungetachar('\n');
196934187Smckusick 			if (doing_cd) {
197034187Smckusick 				top++;
197134187Smckusick 				top->ino = 2;
197234187Smckusick 				top->len = -1;
197334187Smckusick 				nfiles = 1;
197434187Smckusick 				return;
197534187Smckusick 			}
197634187Smckusick 		} else
197734187Smckusick 			ungetachar(c);
197834187Smckusick 	} else {
197934187Smckusick 		ungetachar(c);
198034187Smckusick 		stack_pathp = current_pathp;
198134187Smckusick 		if (!doing_find)
198234187Smckusick 			input_pathp = current_pathp;
198334187Smckusick 		for (i = 0; i <= current_pathp; i++) {
198434187Smckusick 			if (!doing_find)
198534187Smckusick 				strcpy(input_path[i], current_path[i]);
198634187Smckusick 			strcpy(stack_path[i], current_path[i]);
198734187Smckusick 		}
198834187Smckusick 	}
198934187Smckusick 	getname();
199034187Smckusick 	follow_path(stack_pathp + 1, cur_inum);
199134187Smckusick }
199234187Smckusick 
199334187Smckusick /*
199434187Smckusick  * follow_path - called by cd, find, and ls.
199534187Smckusick  *	input_path holds the name typed by the user.
199634187Smckusick  *	stack_path holds the name at the current depth.
199734187Smckusick  */
follow_path(level,inum)199834187Smckusick follow_path(level, inum)
199934187Smckusick 	long			level, inum;
200034187Smckusick {
200134187Smckusick 	register struct direct	*dirp;
200234187Smckusick 	register char		**ccptr, *cptr, c;
200334187Smckusick 	register int		i;
200434187Smckusick 	struct filenames	*tos, *bos, *fn, *fnn, *fnnn;
200534187Smckusick 	long			block;
200634187Smckusick 	short			mode;
200734187Smckusick 
200834187Smckusick 	tos = top + 1;
200934187Smckusick 	restore_inode(inum);
201034187Smckusick 	if ((mode = icheck(addr)) == 0)
201134187Smckusick 		return;
201234187Smckusick 	if ((mode & IFMT) != IFDIR)
201334187Smckusick 	    return;
201434187Smckusick 	block = cur_bytes = 0;
201534187Smckusick 	while (cur_bytes < filesize) {
201634187Smckusick 	    if (block == 0 || bcomp(addr)) {
201734187Smckusick 		error = 0;
201834187Smckusick 		if ((addr = (bmap(block++) << FRGSHIFT)) == 0)
201934187Smckusick 		    break;
202034187Smckusick 		if ((cptr = getblk(addr)) == 0)
202134187Smckusick 		    break;
202234187Smckusick 		cptr += blkoff(fs, addr);
202334187Smckusick 	    }
202434187Smckusick 	    dirp = (struct direct *)cptr;
202534187Smckusick 	    if (dirp->d_ino) {
202634187Smckusick 		if (level > input_pathp || doing_find ||
202734187Smckusick 			compare(input_path[level], &dirp->d_name[0], 1)) {
202834187Smckusick 		    if (++top - filenames >= MAXFILES) {
202934187Smckusick 			printf("too many files\n");
203034187Smckusick 			error++;
203134187Smckusick 			return;
203234187Smckusick 		    }
203334187Smckusick 		    top->fname = (char **)calloc(FIRST_DEPTH, sizeof (char **));
203434187Smckusick 		    top->flag = 0;
203534187Smckusick 		    if (top->fname == 0) {
203634187Smckusick 			printf("out of memory\n");
203734187Smckusick 			error++;
203834187Smckusick 			return;
203934187Smckusick 		    }
204034187Smckusick 		    nfiles++;
204134187Smckusick 		    top->ino = dirp->d_ino;
204234187Smckusick 		    top->len = stack_pathp;
204334187Smckusick 		    top->find = 0;
204434187Smckusick 		    if (doing_find) {
204534187Smckusick 			if (find_by_name) {
204634187Smckusick 			    if (compare(input_path[0], &dirp->d_name[0], 1))
204734187Smckusick 				top->find = 1;
204834187Smckusick 			} else if (find_by_inode)
204934187Smckusick 			    if (find_ino == dirp->d_ino)
205034187Smckusick 				top->find = 1;
205134187Smckusick 		    }
205234187Smckusick 		    if (top->len + 1 >= FIRST_DEPTH && top->flag == 0) {
205334187Smckusick 			ccptr = (char **)calloc(SECOND_DEPTH, sizeof (char **));
205434187Smckusick 			if (ccptr == 0) {
205534187Smckusick 			    printf("out of memory\n");
205634187Smckusick 			    error++;
205734187Smckusick 			    return;
205834187Smckusick 			}
205934187Smckusick 			for (i = 0; i < FIRST_DEPTH; i++)
206034187Smckusick 				ccptr[i] = top->fname[i];
206134187Smckusick 			free((char *)top->fname);
206234187Smckusick 			top->fname = ccptr;
206334187Smckusick 			top->flag = 1;
206434187Smckusick 		    }
206534187Smckusick 		    if (top->len >= SECOND_DEPTH) {
206634187Smckusick 			printf("maximum depth exceeded, try to cd lower\n");
206734187Smckusick 			error++;
206834187Smckusick 			return;
206934187Smckusick 		    }
207034187Smckusick 		    /*
207134187Smckusick 		     * Copy current depth.
207234187Smckusick 		     */
207334187Smckusick 		    for (i = 0; i <= stack_pathp; i++) {
207434187Smckusick 			top->fname[i]=calloc(1, strlen(stack_path[i])+1);
207534187Smckusick 			if (top->fname[i] == 0) {
207634187Smckusick 			    printf("out of memory\n");
207734187Smckusick 			    error++;
207834187Smckusick 			    return;
207934187Smckusick 			}
208034187Smckusick 			strcpy(top->fname[i], stack_path[i]);
208134187Smckusick 		    }
208234187Smckusick 		    /*
208334187Smckusick 		     * Check for '.' or '..' typed.
208434187Smckusick 		     */
208534187Smckusick 		    if ((level <= input_pathp) &&
208634187Smckusick 				       (strcmp(input_path[level], ".") == 0 ||
208734187Smckusick 					strcmp(input_path[level], "..") == 0)) {
208857998Sralph 			if (strcmp(input_path[level], "..") == 0 &&
208934187Smckusick 							 top->len >= 0) {
209034187Smckusick 			    free(top->fname[top->len]);
209134187Smckusick 			    top->len -= 1;
209234187Smckusick 			}
209334187Smckusick 		    } else {
209434187Smckusick 			/*
209534187Smckusick 			 * Check for duplicates.
209634187Smckusick 			 */
209734187Smckusick 			if (!doing_cd && !doing_find) {
209834187Smckusick 			    for (fn = filenames; fn < top; fn++) {
209934187Smckusick 				if (fn->ino == dirp->d_ino &&
210034187Smckusick 					    fn->len == stack_pathp + 1) {
210134187Smckusick 				    for (i = 0; i < fn->len; i++)
210234187Smckusick 					if (strcmp(fn->fname[i], stack_path[i]))
210334187Smckusick 					    break;
210434187Smckusick 				    if (i != fn->len ||
210534187Smckusick 					    strcmp(fn->fname[i], dirp->d_name))
210634187Smckusick 					continue;
210734187Smckusick 				    freemem(top, 1);
210834187Smckusick 				    if (top == filenames)
210934187Smckusick 					top = NULL;
211034187Smckusick 				    else
211134187Smckusick 					top--;
211234187Smckusick 					nfiles--;
211334187Smckusick 					goto duplicate;
211434187Smckusick 				}
211534187Smckusick 			    }
211634187Smckusick 			}
211734187Smckusick 			top->len += 1;
211834187Smckusick 			top->fname[top->len] = calloc(1,
211934187Smckusick 						strlen(&dirp->d_name[0])+1);
212034187Smckusick 			if (top->fname[top->len] == 0) {
212134187Smckusick 			    printf("out of memory\n");
212234187Smckusick 			    error++;
212334187Smckusick 			    return;
212434187Smckusick 			}
212534187Smckusick 			strcpy(top->fname[top->len], &dirp->d_name[0]);
212634187Smckusick 		    }
212734187Smckusick 		}
212834187Smckusick 	    }
212934187Smckusick duplicate:
213034187Smckusick 	    addr += dirp->d_reclen;
213134187Smckusick 	    cptr += dirp->d_reclen;
213234187Smckusick 	    cur_bytes += dirp->d_reclen;
213334187Smckusick 	}
213434187Smckusick 	if (top < filenames)
213534187Smckusick 	    return;
213634187Smckusick 	if ((doing_cd && level == input_pathp) ||
213734187Smckusick 		(!recursive && !doing_find && level > input_pathp))
213834187Smckusick 	    return;
213934187Smckusick 	bos = top;
214034187Smckusick 	/*
214134187Smckusick 	 * Check newly added entries to determine if further expansion
214234187Smckusick 	 * is required.
214334187Smckusick 	 */
214434187Smckusick 	for (fn = tos; fn <= bos; fn++) {
214534187Smckusick 	    /*
214634187Smckusick 	     * Avoid '.' and '..' if beyond input.
214734187Smckusick 	     */
214834187Smckusick 	    if ((recursive || doing_find) && (level > input_pathp) &&
214934187Smckusick 		(strcmp(fn->fname[fn->len], ".") == 0 ||
215034187Smckusick 		 strcmp(fn->fname[fn->len], "..") == 0))
215134187Smckusick 		 continue;
215234187Smckusick 	    restore_inode(fn->ino);
215334187Smckusick 	    if ((mode = icheck(cur_ino)) == 0)
215434187Smckusick 		return;
215534187Smckusick 	    if ((mode & IFMT) == IFDIR || level < input_pathp) {
215634187Smckusick 		/*
215734187Smckusick 		 * Set up current depth, remove current entry and
215834187Smckusick 		 * continue recursion.
215934187Smckusick 		 */
216034187Smckusick 		for (i = 0; i <= fn->len; i++)
216134187Smckusick 		    strcpy(stack_path[i], fn->fname[i]);
216234187Smckusick 		stack_pathp = fn->len;
216334187Smckusick 		if (!doing_find &&
216434187Smckusick 			(!recursive || (recursive && level <= input_pathp))) {
216534187Smckusick 		    /*
216634187Smckusick 		     * Remove current entry by moving others up.
216734187Smckusick 		     */
216834187Smckusick 		    freemem(fn, 1);
216934187Smckusick 		    fnn = fn;
217034187Smckusick 		    for (fnnn = fnn, fnn++; fnn <= top; fnnn = fnn, fnn++) {
217134187Smckusick 			fnnn->ino = fnn->ino;
217234187Smckusick 			fnnn->len = fnn->len;
217334187Smckusick 			if (fnnn->len + 1 < FIRST_DEPTH) {
217434187Smckusick 			    fnnn->fname = (char **)calloc(FIRST_DEPTH,
217534187Smckusick 							sizeof (char **));
217634187Smckusick 			    fnnn->flag = 0;
217734187Smckusick 			} else if (fnnn->len < SECOND_DEPTH) {
217834187Smckusick 			    fnnn->fname = (char **)calloc(SECOND_DEPTH,
217934187Smckusick 							sizeof (char **));
218034187Smckusick 			    fnnn->flag = 1;
218134187Smckusick 			} else {
218234187Smckusick 			    printf("maximum depth exceeded, ");
218334187Smckusick 			    printf("try to cd lower\n");
218434187Smckusick 			    error++;
218534187Smckusick 			    return;
218634187Smckusick 			}
218734187Smckusick 			for (i = 0; i <= fnn->len; i++)
218834187Smckusick 			    fnnn->fname[i] = fnn->fname[i];
218934187Smckusick 		    }
219034187Smckusick 		    if (fn == tos)
219134187Smckusick 			fn--;
219234187Smckusick 		    top--;
219334187Smckusick 		    bos--;
219434187Smckusick 		    nfiles--;
219534187Smckusick 		}
219634187Smckusick 		follow_path(level + 1, cur_inum);
219734187Smckusick 		if (error)
219834187Smckusick 			return;
219934187Smckusick 	    }
220034187Smckusick 	}
220134187Smckusick }
220234187Smckusick 
220334187Smckusick /*
220434187Smckusick  * getname - break up the pathname entered by the user into components.
220534187Smckusick  */
getname()220634187Smckusick getname()
220734187Smckusick {
220834187Smckusick 	register int	i;
220934187Smckusick 	char		c;
221034187Smckusick 
221134187Smckusick 	if ((c = getachar()) == '\n') {
221234187Smckusick 	    ungetachar(c);
221334187Smckusick 	    return;
221434187Smckusick 	}
221534187Smckusick 	ungetachar(c);
221634187Smckusick 	input_pathp++;
221734187Smckusick clear:
221834187Smckusick 	for (i = 0; i < MAXNAMLEN; i++)
221934187Smckusick 	    input_path[input_pathp][i] = '\0';
222034187Smckusick 	for (;;) {
222134187Smckusick 	    c = getachar();
222234187Smckusick 	    if (c == '\\') {
222334187Smckusick 		if (strlen(input_path[input_pathp]) + 1 >= MAXNAMLEN) {
222434187Smckusick 		    printf("maximum name length exceeded, ");
222534187Smckusick 		    printf("truncating\n");
222634187Smckusick 		    return;
222734187Smckusick 		}
222834187Smckusick 		input_path[input_pathp][strlen(input_path[input_pathp])] = c;
222934187Smckusick 		input_path[input_pathp][strlen(input_path[input_pathp])] =
223034187Smckusick 						getachar();
223134187Smckusick 		continue;
223234187Smckusick 	    }
223334187Smckusick 	    if (c == ' ' || c == '\n') {
223434187Smckusick 		ungetachar(c);
223534187Smckusick 		return;
223634187Smckusick 	    }
223734187Smckusick 	    if (!doing_find && c == '/') {
223834187Smckusick 		if (++input_pathp >= MAXPATHLEN) {
223934187Smckusick 		    printf("maximum path length exceeded, ");
224034187Smckusick 		    printf("truncating\n");
224134187Smckusick 		    input_pathp--;
224234187Smckusick 		    return;
224334187Smckusick 		}
224434187Smckusick 		goto clear;
224534187Smckusick 	    }
224634187Smckusick 	    if (strlen(input_path[input_pathp]) >= MAXNAMLEN) {
224734187Smckusick 		printf("maximum name length exceeded, truncating\n");
224834187Smckusick 		return;
224934187Smckusick 	    }
225034187Smckusick 	    input_path[input_pathp][strlen(input_path[input_pathp])] = c;
225134187Smckusick 	}
225234187Smckusick }
225334187Smckusick 
225434187Smckusick /*
225534187Smckusick  * compare - check if a filename matches the pattern entered by the user.
225634187Smckusick  *	Handles '*', '?', and '[]'.
225734187Smckusick  */
compare(s1,s2,at_start)225834187Smckusick compare(s1, s2, at_start)
225934187Smckusick 	char		*s1, *s2;
226034187Smckusick 	short		at_start;
226134187Smckusick {
226234187Smckusick 	register char	c, *s;
226334187Smckusick 
226434187Smckusick 	s = s2;
226534187Smckusick 	while (c = *s1) {
226634187Smckusick 		if (c == '*') {
226734187Smckusick 			if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
226834187Smckusick 				return(0);
226934187Smckusick 			if (*++s1 == 0)
227034187Smckusick 				return(1);
227134187Smckusick 			while (*s2) {
227234187Smckusick 				if (compare(s1, s2, 0))
227334187Smckusick 					return(1);
227434187Smckusick 				if (error)
227534187Smckusick 					return(0);
227634187Smckusick 				s2++;
227734187Smckusick 			}
227834187Smckusick 		}
227934187Smckusick 		if (*s2 == 0)
228034187Smckusick 			return(0);
228134187Smckusick 		if (c == '\\') {
228234187Smckusick 			s1++;
228334187Smckusick 			goto compare_chars;
228434187Smckusick 		}
228534187Smckusick 		if (c == '?') {
228634187Smckusick 			if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
228734187Smckusick 				return(0);
228834187Smckusick 			s1++;
228934187Smckusick 			s2++;
229034187Smckusick 			continue;
229134187Smckusick 		}
229234187Smckusick 		if (c == '[') {
229334187Smckusick 			s1++;
229434187Smckusick 			if (*s2 >= *s1++) {
229534187Smckusick 				if (*s1++ != '-') {
229634187Smckusick 					printf("missing '-'\n");
229734187Smckusick 					error++;
229834187Smckusick 					return(0);
229934187Smckusick 				}
230034187Smckusick 				if (*s2 <= *s1++) {
230134187Smckusick 					if (*s1++ != ']') {
230234187Smckusick 						printf("missing ']'");
230334187Smckusick 						error++;
230434187Smckusick 						return(0);
230534187Smckusick 					}
230634187Smckusick 					s2++;
230734187Smckusick 					continue;
230834187Smckusick 				}
230934187Smckusick 			}
231034187Smckusick 		}
231134187Smckusick compare_chars:
231234187Smckusick 		if (*s1++ == *s2++)
231334187Smckusick 			continue;
231434187Smckusick 		else
231534187Smckusick 			return(0);
231634187Smckusick 	}
231734187Smckusick 	if (*s1 == *s2)
231834187Smckusick 		return(1);
231934187Smckusick 	return(0);
232034187Smckusick }
232134187Smckusick 
232234187Smckusick /*
232334187Smckusick  * freemem - free the memory allocated to the filenames structure.
232434187Smckusick  */
232534187Smckusick freemem(p, numb)
232634187Smckusick 	struct filenames	*p;
232734187Smckusick 	int			numb;
232834187Smckusick {
232934187Smckusick 	register int		i, j;
233034187Smckusick 
233134187Smckusick 	if (numb == 0)
233234187Smckusick 		return;
233334187Smckusick 	for (i = 0; i < numb; i++, p++) {
233434187Smckusick 		for (j = 0; j <= p->len; j++)
233534187Smckusick 			free(p->fname[j]);
233634187Smckusick 		free((char *)p->fname);
233734187Smckusick 	}
233834187Smckusick }
233934187Smckusick 
234034187Smckusick /*
234134187Smckusick  * print_path - print the pathname held in p.
234234187Smckusick  */
print_path(p,pntr)234334187Smckusick print_path(p, pntr)
234434187Smckusick 	char		*p[];
234534187Smckusick 	short		pntr;
234634187Smckusick {
234734187Smckusick 	register int	i;
234834187Smckusick 
234934187Smckusick 	printf("/");
235034187Smckusick 	if (pntr >= 0) {
235134187Smckusick 		for (i = 0; i < pntr; i++)
235234187Smckusick 			printf("%s/", p[i]);
235334187Smckusick 		printf("%s", p[pntr]);
235434187Smckusick 	}
235534187Smckusick }
235634187Smckusick 
235734187Smckusick /*
235834187Smckusick  * fill - fill a section with a value or string.
235934187Smckusick  *	addr,count:fill=[value, "string"].
236034187Smckusick  */
fill()236134187Smckusick fill()
236234187Smckusick {
236334187Smckusick 	register char	*cptr;
236434187Smckusick 	register int	i;
236534187Smckusick 	short		eof_flag, end = 0, eof = 0;
236634187Smckusick 	long		temp, tcount, taddr;
236734187Smckusick 
236834187Smckusick 	if (!wrtflag) {
236934187Smckusick 		printf("not opened for write '-w'\n");
237034187Smckusick 		error++;
237134187Smckusick 		return;
237234187Smckusick 	}
237334187Smckusick 	temp = expr();
237434187Smckusick 	if (error)
237534187Smckusick 		return;
237634187Smckusick 	if ((cptr = getblk(addr)) == 0)
237734187Smckusick 		return;
237834187Smckusick 	if (type == NUMB)
237934187Smckusick 		eof_flag = 0;
238034187Smckusick 	else
238134187Smckusick 		eof_flag = 1;
238234187Smckusick 	taddr = addr;
238334187Smckusick 	switch (objsz) {
238434187Smckusick 	case LONG:
238534187Smckusick 		addr &= ~(LONG - 1);
238634187Smckusick 		break;
238734187Smckusick 	case SHORT:
238834187Smckusick 		addr &= ~(SHORT - 1);
238934187Smckusick 		temp &= 0177777L;
239034187Smckusick 		break;
239134187Smckusick 	case CHAR:
239234187Smckusick 		temp &= 0377;
239334187Smckusick 	}
239434187Smckusick 	cur_bytes -= taddr - addr;
239534187Smckusick 	cptr += blkoff(fs, addr);
239634187Smckusick 	tcount = check_addr(eof_flag, &end, &eof, 0);
239734187Smckusick 	for (i = 0; i < tcount; i++) {
239834187Smckusick 		switch (objsz) {
239934187Smckusick 		case LONG:
240034187Smckusick 			*(long *)cptr = temp;
240134187Smckusick 			break;
240234187Smckusick 		case SHORT:
240334187Smckusick 			*(short *)cptr = temp;
240434187Smckusick 			break;
240534187Smckusick 		case CHAR:
240634187Smckusick 			*cptr = temp;
240734187Smckusick 		}
240834187Smckusick 		cptr += objsz;
240934187Smckusick 	}
241034187Smckusick 	addr += (tcount - 1) * objsz;
241134187Smckusick 	cur_bytes += (tcount - 1) * objsz;
241234187Smckusick 	put(temp, objsz);
241334187Smckusick 	if (eof) {
241434187Smckusick 		printf("end of file\n");
241534187Smckusick 		error++;
241634187Smckusick 	} else if (end) {
241734187Smckusick 		printf("end of block\n");
241834187Smckusick 		error++;
241934187Smckusick 	}
242034187Smckusick }
242157998Sralph 
242234187Smckusick /*
242334187Smckusick  * get - read a byte, short or long from the file system.
242434187Smckusick  *	The entire block containing the desired item is read
242557998Sralph  *	and the appropriate data is extracted and returned.
242634187Smckusick  */
242734187Smckusick long
get(lngth)242834187Smckusick get(lngth)
242934187Smckusick 	short		lngth;
243034187Smckusick {
243134187Smckusick 
243234187Smckusick 	register char	*bptr;
243334187Smckusick 	long		temp = addr;
243434187Smckusick 
243534187Smckusick 	objsz = lngth;
243634187Smckusick 	if (objsz == INODE || objsz == SHORT)
243734187Smckusick 		temp &= ~(SHORT - 1);
243834187Smckusick 	else if (objsz == DIRECTORY || objsz == LONG)
243934187Smckusick 		temp &= ~(LONG - 1);
244034187Smckusick 	if ((bptr = getblk(temp)) == 0)
244134187Smckusick 		return(-1);
244234187Smckusick 	bptr += blkoff(fs, temp);
244334187Smckusick 	switch (objsz) {
244434187Smckusick 	case CHAR:
244534187Smckusick 		return((long)*bptr);
244634187Smckusick 	case SHORT:
244734187Smckusick 	case INODE:
244834187Smckusick 		return((long)(*(short *)bptr));
244934187Smckusick 	case LONG:
245034187Smckusick 	case DIRECTORY:
245134187Smckusick 		return(*(long *)bptr);
245234187Smckusick 	}
245334187Smckusick 	return(0);
245434187Smckusick }
245534187Smckusick 
245634187Smckusick /*
245734187Smckusick  * cgrp_check - make sure that we don't bump the cylinder group
245834187Smckusick  *	beyond the total number of cylinder groups or before the start.
245934187Smckusick  */
cgrp_check(cgrp)246034187Smckusick cgrp_check(cgrp)
246134187Smckusick 	long		cgrp;
246234187Smckusick {
246334187Smckusick 	if (cgrp < 0) {
246434187Smckusick 		if (objsz == CGRP)
246534187Smckusick 			printf("beginning of cylinder groups\n");
246634187Smckusick 		else
246734187Smckusick 			printf("beginning of super blocks\n");
246834187Smckusick 		error++;
246934187Smckusick 		return(0);
247034187Smckusick 	}
247134187Smckusick 	if (cgrp >= fs->fs_ncg) {
247234187Smckusick 		if (objsz == CGRP)
247334187Smckusick 			printf("end of cylinder groups\n");
247434187Smckusick 		else
247534187Smckusick 			printf("end of super blocks\n");
247634187Smckusick 		error++;
247734187Smckusick 		return(0);
247834187Smckusick 	}
247934187Smckusick 	if (objsz == CGRP)
248034187Smckusick 		return(cgtod(fs, cgrp) << FRGSHIFT);
248134187Smckusick 	else
248234187Smckusick 		return(cgsblock(fs, cgrp) << FRGSHIFT);
248334187Smckusick }
248434187Smckusick 
248534187Smckusick /*
248634187Smckusick  * icheck -  make sure we can read the block containing the inode
248734187Smckusick  *	and determine the filesize (0 if inode not allocated).  Return
248834187Smckusick  *	0 if error otherwise return the mode.
248934187Smckusick  */
icheck(address)249034187Smckusick icheck(address)
249134187Smckusick 	long			address;
249234187Smckusick {
249334187Smckusick 	register char		*cptr;
249434187Smckusick 	register struct dinode	*ip;
249534187Smckusick 
249634187Smckusick 	if ((cptr = getblk(address)) == 0)
249734187Smckusick 		return(0);
249834187Smckusick 	cptr += blkoff(fs, address);
249934187Smckusick 	ip = (struct dinode *)cptr;
250034187Smckusick 	if ((ip->di_mode & IFMT) == 0) {
250134187Smckusick 		if (!override) {
250234187Smckusick 			printf("inode not allocated\n");
250334187Smckusick 			error++;
250434187Smckusick 			return(0);
250534187Smckusick 		}
250634187Smckusick 		blocksize = filesize = 0;
250734187Smckusick 	} else {
250834187Smckusick 		trapped++;
250934187Smckusick 		filesize = ip->di_size;
251034187Smckusick 		blocksize = filesize * 2;
251134187Smckusick 	}
251234187Smckusick 	return(ip->di_mode);
251334187Smckusick }
251434187Smckusick 
251534187Smckusick /*
251634187Smckusick  * getdirslot - get the address of the directory slot desired.
251734187Smckusick  */
getdirslot(slot)251834187Smckusick getdirslot(slot)
251934187Smckusick 	short			slot;
252034187Smckusick {
252134187Smckusick 	register char		*cptr;
252234187Smckusick 	register struct direct	*dirp;
252334187Smckusick 	register short		i;
252434187Smckusick 	char			*string = &scratch[0];
252534187Smckusick 	short			bod = 0, mode, temp;
252634187Smckusick 
252734187Smckusick 	if (slot < 0) {
252834187Smckusick 		slot = 0;
252934187Smckusick 		bod++;
253034187Smckusick 	}
253134187Smckusick 	if (type != DIRECTORY) {
253234187Smckusick 		if (type == BLOCK)
253334187Smckusick 			string = "block";
253434187Smckusick 		else
253534187Smckusick 			string = "fragment";
253634187Smckusick 		addr = bod_addr;
253734187Smckusick 		if ((cptr = getblk(addr)) == 0)
253834187Smckusick 			return(0);
253934187Smckusick 		cptr += blkoff(fs, addr);
254034187Smckusick 		cur_bytes = 0;
254134187Smckusick 		dirp = (struct direct *)cptr;
254234187Smckusick 		for (dirslot = 0; dirslot < slot; dirslot++) {
254334187Smckusick 			dirp = (struct direct *)cptr;
254434187Smckusick 			if (blocksize > filesize) {
254534187Smckusick 				if (cur_bytes + dirp->d_reclen >= filesize) {
254634187Smckusick 					printf("end of file\n");
254734187Smckusick 					erraddr = addr;
254834187Smckusick 					errcur_bytes = cur_bytes;
254934187Smckusick 					stringsize = STRINGSIZE(dirp);
255034187Smckusick 					error++;
255134187Smckusick 					return(addr);
255234187Smckusick 				}
255334187Smckusick 			} else {
255434187Smckusick 				if (cur_bytes + dirp->d_reclen >= blocksize) {
255534187Smckusick 					printf("end of %s\n", string);
255634187Smckusick 					erraddr = addr;
255734187Smckusick 					errcur_bytes = cur_bytes;
255834187Smckusick 					stringsize = STRINGSIZE(dirp);
255934187Smckusick 					error++;
256034187Smckusick 					return(addr);
256134187Smckusick 				}
256234187Smckusick 			}
256334187Smckusick 			cptr += dirp->d_reclen;
256434187Smckusick 			addr += dirp->d_reclen;
256534187Smckusick 			cur_bytes += dirp->d_reclen;
256634187Smckusick 		}
256734187Smckusick 		if (bod) {
256834187Smckusick 			if (blocksize > filesize)
256934187Smckusick 				printf("beginning of file\n");
257034187Smckusick 			else
257134187Smckusick 				printf("beginning of %s\n", string);
257234187Smckusick 			erraddr = addr;
257334187Smckusick 			errcur_bytes = cur_bytes;
257434187Smckusick 			error++;
257534187Smckusick 		}
257634187Smckusick 		stringsize = STRINGSIZE(dirp);
257734187Smckusick 		return(addr);
257834187Smckusick 	} else {
257934187Smckusick 		addr = cur_ino;
258034187Smckusick 		if ((mode = icheck(addr)) == 0)
258134187Smckusick 			return(0);
258234187Smckusick 		if (!override && (mode & IFDIR) == 0) {
258334187Smckusick 			printf("inode is not a directory\n");
258434187Smckusick 			error++;
258534187Smckusick 			return(0);
258634187Smckusick 		}
258734187Smckusick 		temp = slot;
258834187Smckusick 		i = cur_bytes = 0;
258934187Smckusick 		for (;;) {
259034187Smckusick 			if (i == 0 || bcomp(addr)) {
259134187Smckusick 				error = 0;
259234187Smckusick 				if ((addr=(bmap(i++) << FRGSHIFT)) == 0)
259334187Smckusick 					break;
259434187Smckusick 				if ((cptr = getblk(addr)) == 0)
259534187Smckusick 					break;
259634187Smckusick 				cptr += blkoff(fs, addr);
259734187Smckusick 			}
259834187Smckusick 			dirp = (struct direct *)cptr;
259934187Smckusick 			value = dirp->d_ino;
260034187Smckusick 			if (!temp--)
260134187Smckusick 				break;
260234187Smckusick 			if (cur_bytes + dirp->d_reclen >= filesize) {
260334187Smckusick 				printf("end of file\n");
260434187Smckusick 				dirslot = slot - temp - 1;
260534187Smckusick 				objsz = DIRECTORY;
260634187Smckusick 				erraddr = addr;
260734187Smckusick 				errcur_bytes = cur_bytes;
260834187Smckusick 				stringsize = STRINGSIZE(dirp);
260934187Smckusick 				error++;
261034187Smckusick 				return(addr);
261134187Smckusick 			}
261234187Smckusick 			addr += dirp->d_reclen;
261334187Smckusick 			cptr += dirp->d_reclen;
261434187Smckusick 			cur_bytes += dirp->d_reclen;
261534187Smckusick 		}
261634187Smckusick 		dirslot = slot;
261734187Smckusick 		objsz = DIRECTORY;
261834187Smckusick 		if (bod) {
261934187Smckusick 			printf("beginning of file\n");
262034187Smckusick 			erraddr = addr;
262134187Smckusick 			errcur_bytes = cur_bytes;
262234187Smckusick 			error++;
262334187Smckusick 		}
262434187Smckusick 		stringsize = STRINGSIZE(dirp);
262534187Smckusick 		return(addr);
262634187Smckusick 	}
262734187Smckusick }
262834187Smckusick 
262934187Smckusick /*
263034187Smckusick  * putf - print a byte as an ascii character if possible.
263134187Smckusick  *	The exceptions are tabs, newlines, backslashes
263234187Smckusick  *	and nulls which are printed as the standard C
263334187Smckusick  *	language escapes. Characters which are not
263434187Smckusick  *	recognized are printed as \?.
263534187Smckusick  */
putf(c)263634187Smckusick putf(c)
263734187Smckusick 	register	char  c;
263834187Smckusick {
263934187Smckusick 
264034187Smckusick 	if (c<=037 || c>=0177 || c=='\\') {
264134187Smckusick 		printf("\\");
264234187Smckusick 		switch (c) {
264334187Smckusick 		case '\\':
264434187Smckusick 			printf("\\");
264534187Smckusick 			break;
264634187Smckusick 		case '\t':
264734187Smckusick 			printf("t");
264834187Smckusick 			break;
264934187Smckusick 		case '\n':
265034187Smckusick 			printf("n");
265134187Smckusick 			break;
265234187Smckusick 		case '\0':
265334187Smckusick 			printf("0");
265434187Smckusick 			break;
265534187Smckusick 		default:
265634187Smckusick 			printf("?");
265734187Smckusick 		}
265834187Smckusick 	}
265934187Smckusick 	else {
266034187Smckusick 		printf("%c", c);
266134187Smckusick 		printf(" ");
266234187Smckusick 	}
266334187Smckusick }
266434187Smckusick 
266534187Smckusick /*
266634187Smckusick  * put - write an item into the buffer for the current address
266734187Smckusick  *	block.  The value is checked to make sure that it will
266834187Smckusick  *	fit in the size given without truncation.  If successful,
266934187Smckusick  *	the entire block is written back to the file system.
267034187Smckusick  */
put(item,lngth)267157998Sralph put(item, lngth)
267234187Smckusick 	long		item;
267334187Smckusick 	short		lngth;
267434187Smckusick {
267534187Smckusick 
267634187Smckusick 	register char	*bptr, *sbptr;
267734187Smckusick 	register long	*vptr;
267857998Sralph 	off_t		s_err;
267957998Sralph 	long		nbytes;
268034187Smckusick 	long		olditem;
268134187Smckusick 
268234187Smckusick 	if (!wrtflag) {
268334187Smckusick 		printf("not opened for write '-w'\n");
268434187Smckusick 		error++;
268534187Smckusick 		return;
268634187Smckusick 	}
268734187Smckusick 	objsz = lngth;
268834187Smckusick 	if ((sbptr = getblk(addr)) == 0)
268934187Smckusick 		return;
269034187Smckusick 	bptr = sbptr + blkoff(fs, addr);
269134187Smckusick 	switch (objsz) {
269234187Smckusick 	case LONG:
269334187Smckusick 	case DIRECTORY:
269434187Smckusick 		olditem = *(long *)bptr;
269534187Smckusick 		*(long *)bptr = item;
269634187Smckusick 		break;
269734187Smckusick 	case SHORT:
269834187Smckusick 	case INODE:
269934187Smckusick 		olditem = (long)*(short *)bptr;
270034187Smckusick 		item &= 0177777L;
270134187Smckusick 		*(short *)bptr = item;
270234187Smckusick 		break;
270334187Smckusick 	case CHAR:
270434187Smckusick 		olditem = (long)*bptr;
270534187Smckusick 		item &= 0377;
270634187Smckusick 		*bptr = lobyte(loword(item));
270734187Smckusick 		break;
270834187Smckusick 	default:
270934187Smckusick 		error++;
271034187Smckusick 		return;
271134187Smckusick 	}
271257998Sralph 	if ((s_err = lseek(fd, (off_t)(addr & fs->fs_bmask), SEEK_SET)) == -1) {
271334187Smckusick 		error++;
271457998Sralph 		printf("seek error : %x\n", addr);
271534187Smckusick 		return(0);
271634187Smckusick 	}
271734187Smckusick 	if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
271834187Smckusick 		error++;
271957998Sralph 		printf("write error : addr   = %x\n", addr);
272057998Sralph 		printf("            : s_err  = %qx\n", s_err);
272157998Sralph 		printf("            : nbytes = %x\n", nbytes);
272234187Smckusick 		return(0);
272334187Smckusick 	}
272434187Smckusick 	if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
272534187Smckusick 		index(base);
272634187Smckusick 		print(olditem, 8, -8, 0);
272734187Smckusick 		printf("\t=\t");
272834187Smckusick 		print(item, 8, -8, 0);
272934187Smckusick 		printf("\n");
273034187Smckusick 	} else {
273134187Smckusick 		if (objsz == DIRECTORY) {
273234187Smckusick 			addr = cur_dir;
273334187Smckusick 			fprnt('?', 'd');
273434187Smckusick 		} else {
273534187Smckusick 			addr = cur_ino;
273634187Smckusick 			objsz = INODE;
273734187Smckusick 			fprnt('?', 'i');
273834187Smckusick 		}
273934187Smckusick 	}
274034187Smckusick 	return;
274134187Smckusick }
274234187Smckusick 
274334187Smckusick /*
274434187Smckusick  * getblk - check if the desired block is in the file system.
274534187Smckusick  *	Search the incore buffers to see if the block is already
274634187Smckusick  *	available. If successful, unlink the buffer control block
274734187Smckusick  *	from its position in the buffer list and re-insert it at
274834187Smckusick  *	the head of the list.  If failure, use the last buffer
274934187Smckusick  *	in the list for the desired block. Again, this control
275034187Smckusick  *	block is placed at the head of the list. This process
275134187Smckusick  *	will leave commonly requested blocks in the in-core buffers.
275234187Smckusick  *	Finally, a pointer to the buffer is returned.
275334187Smckusick  */
275434187Smckusick char *
getblk(address)275534187Smckusick getblk(address)
275634187Smckusick 	long			address;
275734187Smckusick {
275834187Smckusick 
275934187Smckusick 	register struct buf	*bp;
276057998Sralph 	off_t			s_err;
276157998Sralph 	long			nbytes;
276234187Smckusick 	unsigned long		block;
276334187Smckusick 
276434187Smckusick 	read_requests++;
276534187Smckusick 	block = lblkno(fs, address);
276634187Smckusick 	if (block >= fragstoblks(fs, fs->fs_size)) {
276734187Smckusick 		printf("block exceeds maximum block in file system\n");
276834187Smckusick 		error++;
276934187Smckusick 		return(0);
277034187Smckusick 	}
277134187Smckusick 	for (bp=bhdr.fwd; bp!= &bhdr; bp=bp->fwd)
277234187Smckusick 		if (bp->valid && bp->blkno==block)
277334187Smckusick 			goto xit;
277434187Smckusick 	actual_disk_reads++;
277534187Smckusick 	bp = bhdr.back;
277634187Smckusick 	bp->blkno = block;
277734187Smckusick 	bp->valid = 0;
277857998Sralph 	s_err = lseek(fd, (off_t)(address & fs->fs_bmask), SEEK_SET);
277957998Sralph 	if (s_err == -1) {
278034187Smckusick 		error++;
278157998Sralph 		printf("seek error : %x\n", address);
278234187Smckusick 		return(0);
278334187Smckusick 	}
278434187Smckusick 	if ((nbytes = read(fd, bp->blkaddr, BLKSIZE)) != BLKSIZE) {
278534187Smckusick 		error++;
278657998Sralph 		printf("read error : addr   = %x\n", address);
278757998Sralph 		printf("           : s_err  = %qx\n", s_err);
278857998Sralph 		printf("           : nbytes = %x\n", nbytes);
278934187Smckusick 		return(0);
279034187Smckusick 	}
279134187Smckusick 	bp->valid++;
279234187Smckusick xit:	bp->back->fwd = bp->fwd;
279334187Smckusick 	bp->fwd->back = bp->back;
279434187Smckusick 	insert(bp);
279534187Smckusick 	return(bp->blkaddr);
279634187Smckusick }
279734187Smckusick 
279834187Smckusick /*
279934187Smckusick  * insert - place the designated buffer control block
280034187Smckusick  *	at the head of the linked list of buffers.
280134187Smckusick  */
insert(bp)280234187Smckusick insert(bp)
280334187Smckusick 	register struct buf	*bp;
280434187Smckusick {
280534187Smckusick 
280634187Smckusick 	bp->back = &bhdr;
280734187Smckusick 	bp->fwd = bhdr.fwd;
280834187Smckusick 	bhdr.fwd->back = bp;
280934187Smckusick 	bhdr.fwd = bp;
281034187Smckusick }
281134187Smckusick 
281234187Smckusick /*
281334187Smckusick  * err - called on interrupts.  Set the current address
281434187Smckusick  *	back to the last address stored in erraddr. Reset all
281534187Smckusick  *	appropriate flags.  A reset call is made to return
281634187Smckusick  *	to the main loop;
281734187Smckusick  */
281846706Sbostic void
err()281934187Smckusick err()
282034187Smckusick {
282134187Smckusick 	freemem(filenames, nfiles);
282234187Smckusick 	nfiles = 0;
282357998Sralph 	signal(2, err);
282434187Smckusick 	addr = erraddr;
282534187Smckusick 	cur_ino = errino;
282634187Smckusick 	cur_inum = errinum;
282734187Smckusick 	cur_bytes = errcur_bytes;
282834187Smckusick 	error = 0;
282934187Smckusick 	c_count = 0;
283034187Smckusick 	printf("\n?\n");
283134187Smckusick 	fseek(stdin, 0L, 2);
283257998Sralph 	longjmp(env, 0);
283334187Smckusick }
283434187Smckusick 
283534187Smckusick /*
283657998Sralph  * devcheck - check that the given mode represents a
283734187Smckusick  *	special device. The IFCHR bit is on for both
283834187Smckusick  *	character and block devices.
283934187Smckusick  */
devcheck(md)284034187Smckusick devcheck(md)
284134187Smckusick 	register	short md;
284234187Smckusick {
284334187Smckusick 	if (override)
284434187Smckusick 		return(0);
284534187Smckusick 	if (md & IFCHR)
284634187Smckusick 		return(0);
284734187Smckusick 	printf("not character or block device\n");
284834187Smckusick 	error++;
284934187Smckusick 	return(1);
285034187Smckusick }
285134187Smckusick 
285234187Smckusick /*
285334187Smckusick  * nullblk - return error if address is zero.  This is done
285434187Smckusick  *	to prevent block 0 from being used as an indirect block
285534187Smckusick  *	for a large file or as a data block for a small file.
285634187Smckusick  */
nullblk(bn)285734187Smckusick nullblk(bn)
285834187Smckusick 	long		bn;
285934187Smckusick {
286034187Smckusick 	if (bn != 0)
286134187Smckusick 		return(0);
286234187Smckusick 	printf("non existent block\n");
286334187Smckusick 	error++;
286434187Smckusick 	return(1);
286534187Smckusick }
286634187Smckusick 
286734187Smckusick /*
286834187Smckusick  * puta - put ascii characters into a buffer.  The string
286934187Smckusick  *	terminates with a quote or newline.  The leading quote,
287034187Smckusick  *	which is optional for directory names, was stripped off
287134187Smckusick  *	by the assignment case in the main loop.
287234187Smckusick  */
puta()287334187Smckusick puta()
287434187Smckusick {
287534187Smckusick 	register char		*cptr, c;
287634187Smckusick 	register int		i;
287734187Smckusick 	char			*sbptr;
287834187Smckusick 	short			terror = 0;
287957998Sralph 	long			maxchars, nbytes, temp;
288057998Sralph 	off_t			s_err;
288134187Smckusick 	long			taddr = addr, tcount = 0, item, olditem = 0;
288234187Smckusick 
288334187Smckusick 	if (!wrtflag) {
288434187Smckusick 		printf("not opened for write '-w'\n");
288534187Smckusick 		error++;
288634187Smckusick 		return;
288734187Smckusick 	}
288834187Smckusick 	if ((sbptr = getblk(addr)) == 0)
288934187Smckusick 		return;
289034187Smckusick 	cptr = sbptr + blkoff(fs, addr);
289134187Smckusick 	if (objsz == DIRECTORY) {
289234187Smckusick 		if (acting_on_directory)
289334187Smckusick 			maxchars = stringsize - 1;
289434187Smckusick 		else
289534187Smckusick 			maxchars = LONG;
289634187Smckusick 	} else if (objsz == INODE)
289734187Smckusick 		maxchars = objsz - (addr - cur_ino);
289834187Smckusick 	else
289934187Smckusick 		maxchars = min(blocksize - cur_bytes, filesize - cur_bytes);
290034187Smckusick 	while ((c = getachar()) != '"') {
290134187Smckusick 		if (tcount >= maxchars) {
290234187Smckusick 			printf("string too long\n");
290334187Smckusick 			if (objsz == DIRECTORY)
290434187Smckusick 				addr = cur_dir;
290534187Smckusick 			else if (acting_on_inode || objsz == INODE)
290634187Smckusick 				addr = cur_ino;
290734187Smckusick 			else
290834187Smckusick 				addr = taddr;
290934187Smckusick 			erraddr = addr;
291034187Smckusick 			errcur_bytes = cur_bytes;
291134187Smckusick 			terror++;
291234187Smckusick 			break;
291334187Smckusick 		}
291434187Smckusick 		tcount++;
291534187Smckusick 		if (c == '\n') {
291634187Smckusick 			ungetachar(c);
291734187Smckusick 			break;
291834187Smckusick 		}
291934187Smckusick 		temp = (long)*cptr;
292034187Smckusick 		olditem <<= BITSPERCHAR;
292134187Smckusick 		olditem += temp & 0xff;
292234187Smckusick 		if (c == '\\') {
292334187Smckusick 			switch (c = getachar()) {
292434187Smckusick 			case 't':
292534187Smckusick 				*cptr++ = '\t';
292634187Smckusick 				break;
292734187Smckusick 			case 'n':
292834187Smckusick 				*cptr++ = '\n';
292934187Smckusick 				break;
293034187Smckusick 			case '0':
293134187Smckusick 				*cptr++ = '\0';
293234187Smckusick 				break;
293334187Smckusick 			default:
293434187Smckusick 				*cptr++ = c;
293534187Smckusick 				break;
293634187Smckusick 			}
293734187Smckusick 		}
293834187Smckusick 		else
293934187Smckusick 			*cptr++ = c;
294034187Smckusick 	}
294134187Smckusick 	if (objsz == DIRECTORY && acting_on_directory)
294234187Smckusick 		for (i = tcount; i <= maxchars; i++)
294334187Smckusick 			*cptr++ = '\0';
294457998Sralph 	if ((s_err = lseek(fd, (off_t)(addr & fs->fs_bmask), SEEK_SET)) == -1) {
294534187Smckusick 		error++;
294657998Sralph 		printf("seek error : %x\n", addr);
294734187Smckusick 		return(0);
294834187Smckusick 	}
294934187Smckusick 	if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
295034187Smckusick 		error++;
295157998Sralph 		printf("write error : addr   = %x\n", addr);
295257998Sralph 		printf("            : s_err  = %qx\n", s_err);
295357998Sralph 		printf("            : nbytes = %x\n", nbytes);
295434187Smckusick 		return(0);
295534187Smckusick 	}
295634187Smckusick 	if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
295734187Smckusick 		addr += tcount;
295834187Smckusick 		cur_bytes += tcount;
295934187Smckusick 		taddr = addr;
296034187Smckusick 		if (objsz != CHAR) {
296134187Smckusick 			addr &= ~(objsz - 1);
296234187Smckusick 			cur_bytes -= taddr - addr;
296334187Smckusick 		}
296434187Smckusick 		if (addr == taddr) {
296534187Smckusick 			addr -= objsz;
296634187Smckusick 			taddr = addr;
296734187Smckusick 		}
296834187Smckusick 		tcount = LONG - (taddr - addr);
296934187Smckusick 		index(base);
297034187Smckusick 		if ((cptr = getblk(addr)) == 0)
297134187Smckusick 			return;
297234187Smckusick 		cptr += blkoff(fs, addr);
297334187Smckusick 		switch (objsz) {
297434187Smckusick 		case LONG:
297534187Smckusick 			item = *(long *)cptr;
297634187Smckusick 			if (tcount < LONG) {
297734187Smckusick 				olditem <<= tcount * BITSPERCHAR;
297834187Smckusick 				temp = 1;
297934187Smckusick 				for (i = 0; i < (tcount*BITSPERCHAR); i++)
298034187Smckusick 					temp <<= 1;
298134187Smckusick 				olditem += item & (temp - 1);
298234187Smckusick 			}
298334187Smckusick 			break;
298434187Smckusick 		case SHORT:
298534187Smckusick 			item = (long)*(short *)cptr;
298634187Smckusick 			if (tcount < SHORT) {
298734187Smckusick 				olditem <<= tcount * BITSPERCHAR;
298834187Smckusick 				temp = 1;
298934187Smckusick 				for (i = 0; i < (tcount * BITSPERCHAR); i++)
299034187Smckusick 					temp <<= 1;
299134187Smckusick 				olditem += item & (temp - 1);
299234187Smckusick 			}
299334187Smckusick 			olditem &= 0177777L;
299434187Smckusick 			break;
299534187Smckusick 		case CHAR:
299634187Smckusick 			item = (long)*cptr;
299734187Smckusick 			olditem &= 0377;
299834187Smckusick 		}
299934187Smckusick 		print(olditem, 8, -8, 0);
300034187Smckusick 		printf("\t=\t");
300134187Smckusick 		print(item, 8, -8, 0);
300234187Smckusick 		printf("\n");
300334187Smckusick 	} else {
300434187Smckusick 		if (objsz == DIRECTORY) {
300534187Smckusick 			addr = cur_dir;
300634187Smckusick 			fprnt('?', 'd');
300734187Smckusick 		} else {
300834187Smckusick 			addr = cur_ino;
300934187Smckusick 			objsz = INODE;
301034187Smckusick 			fprnt('?', 'i');
301134187Smckusick 		}
301234187Smckusick 	}
301334187Smckusick 	if (terror)
301434187Smckusick 		error++;
301534187Smckusick }
301634187Smckusick 
301734187Smckusick /*
301834187Smckusick  * fprnt - print data.  'count' elements are printed where '*' will
301934187Smckusick  *	print an entire blocks worth or up to the eof, whichever
302034187Smckusick  *	occurs first.  An error will occur if crossing a block boundary
302134187Smckusick  *	is attempted since consecutive blocks don't usually have
302234187Smckusick  *	meaning.  Current print types:
302334187Smckusick  *		/		b   - print as bytes (base sensitive)
302434187Smckusick  *				c   - print as characters
302534187Smckusick  *				o O - print as octal shorts (longs)
302634187Smckusick  *				d D - print as decimal shorts (longs)
302734187Smckusick  *				x X - print as hexadecimal shorts (longs)
302834187Smckusick  *		?		c   - print as cylinder groups
302934187Smckusick  *				d   - print as directories
303034187Smckusick  *				i   - print as inodes
303134187Smckusick  *				s   - print as super blocks
303234187Smckusick  */
fprnt(style,po)303334187Smckusick fprnt(style, po)
303434187Smckusick 	register char		style, po;
303534187Smckusick {
303634187Smckusick 	register int		i;
303734187Smckusick 	register struct fs	*sb;
303834187Smckusick 	register struct cg	*cg;
303934187Smckusick 	register struct direct	*dirp;
304034187Smckusick 	register struct dinode	*ip;
304134187Smckusick 	int			tbase;
304234187Smckusick 	char			c, *cptr, *p;
304334187Smckusick 	long			tinode, tcount, temp, taddr;
304434187Smckusick 	short			offset, mode, end = 0, eof = 0, eof_flag;
304534187Smckusick 	unsigned short		*sptr;
304634187Smckusick 	unsigned long		*lptr;
304734187Smckusick 
304834187Smckusick 	laststyle = style;
304934187Smckusick 	lastpo = po;
305034187Smckusick 	should_print = 0;
305134187Smckusick 	if (count != 1) {
305234187Smckusick 		if (clear) {
305334187Smckusick 			count = 1;
305434187Smckusick 			star = 0;
305534187Smckusick 			clear = 0;
305634187Smckusick 		} else
305734187Smckusick 			clear = 1;
305834187Smckusick 	}
305934187Smckusick 	tcount = count;
306034187Smckusick 	offset = blkoff(fs, addr);
306134187Smckusick 
306234187Smckusick 	if (style == '/') {
306334187Smckusick 		if (type == NUMB)
306434187Smckusick 			eof_flag = 0;
306534187Smckusick 		else
306634187Smckusick 			eof_flag = 1;
306734187Smckusick 		switch (po) {
306834187Smckusick 
306934187Smckusick 		case 'c': /* print as characters */
307034187Smckusick 		case 'b': /* or bytes */
307134187Smckusick 			if ((cptr = getblk(addr)) == 0)
307234187Smckusick 				return;
307334187Smckusick 			cptr += offset;
307434187Smckusick 			objsz = CHAR;
307534187Smckusick 			tcount = check_addr(eof_flag, &end, &eof, 0);
307634187Smckusick 			if (tcount) {
307734187Smckusick 				for (i=0; tcount--; i++) {
307834187Smckusick 					if (i % 16 == 0) {
307934187Smckusick 						if (i)
308034187Smckusick 							printf("\n");
308134187Smckusick 						index(base);
308234187Smckusick 					}
308334187Smckusick 					if (po == 'c') {
308434187Smckusick 						putf(*cptr++);
308534187Smckusick 						if ((i + 1) % 16)
308634187Smckusick 							printf("  ");
308734187Smckusick 					} else {
308834187Smckusick 						if ((i + 1) % 16 == 0)
308934187Smckusick 							print(*cptr++ & 0377,
309057998Sralph 								2, -2, 0);
309134187Smckusick 						else
309234187Smckusick 							print(*cptr++ & 0377,
309357998Sralph 								4, -2, 0);
309434187Smckusick 					}
309534187Smckusick 					addr += CHAR;
309634187Smckusick 					cur_bytes += CHAR;
309734187Smckusick 				}
309834187Smckusick 				printf("\n");
309934187Smckusick 			}
310034187Smckusick 			addr -= CHAR;
310134187Smckusick 			erraddr = addr;
310234187Smckusick 			cur_bytes -= CHAR;
310334187Smckusick 			errcur_bytes = cur_bytes;
310434187Smckusick 			if (eof) {
310534187Smckusick 				printf("end of file\n");
310634187Smckusick 				error++;
310734187Smckusick 			} else if (end) {
310834187Smckusick 				if (type == BLOCK)
310934187Smckusick 					printf("end of block\n");
311034187Smckusick 				else
311134187Smckusick 					printf("end of fragment\n");
311234187Smckusick 				error++;
311334187Smckusick 			}
311434187Smckusick 			return;
311534187Smckusick 
311634187Smckusick 		case 'o': /* print as octal shorts */
311734187Smckusick 			tbase = OCTAL;
311834187Smckusick 			goto otx;
311934187Smckusick 		case 'd': /* print as decimal shorts */
312034187Smckusick 			tbase = DECIMAL;
312134187Smckusick 			goto otx;
312234187Smckusick 		case 'x': /* print as hex shorts */
312334187Smckusick 			tbase = HEX;
312434187Smckusick otx:
312534187Smckusick 			if ((cptr = getblk(addr)) == 0)
312634187Smckusick 				return;
312734187Smckusick 			taddr = addr;
312834187Smckusick 			addr &= ~(SHORT - 1);
312934187Smckusick 			cur_bytes -= taddr - addr;
313034187Smckusick 			cptr += blkoff(fs, addr);
313134187Smckusick 			sptr = (unsigned short *)cptr;
313234187Smckusick 			objsz = SHORT;
313334187Smckusick 			tcount = check_addr(eof_flag, &end, &eof, 0);
313434187Smckusick 			if (tcount) {
313534187Smckusick 				for (i=0; tcount--; i++) {
313634187Smckusick 					sptr = (unsigned short *)
313734187Smckusick 					   print_check(sptr, &tcount, tbase, i);
313834187Smckusick 					switch (po) {
313934187Smckusick 					case 'o':
314057998Sralph 						printf("%06o ", *sptr++);
314134187Smckusick 						break;
314234187Smckusick 					case 'd':
314357998Sralph 						printf("%05d  ", *sptr++);
314434187Smckusick 						break;
314534187Smckusick 					case 'x':
314657998Sralph 						printf("%04x   ", *sptr++);
314734187Smckusick 					}
314834187Smckusick 					addr += SHORT;
314934187Smckusick 					cur_bytes += SHORT;
315034187Smckusick 				}
315134187Smckusick 				printf("\n");
315234187Smckusick 			}
315334187Smckusick 			addr -= SHORT;
315434187Smckusick 			erraddr = addr;
315534187Smckusick 			cur_bytes -= SHORT;
315634187Smckusick 			errcur_bytes = cur_bytes;
315734187Smckusick 			if (eof) {
315834187Smckusick 				printf("end of file\n");
315934187Smckusick 				error++;
316034187Smckusick 			} else if (end) {
316134187Smckusick 				if (type == BLOCK)
316234187Smckusick 					printf("end of block\n");
316334187Smckusick 				else
316434187Smckusick 					printf("end of fragment\n");
316534187Smckusick 				error++;
316634187Smckusick 			}
316734187Smckusick 			return;
316834187Smckusick 
316934187Smckusick 		case 'O': /* print as octal longs */
317034187Smckusick 			tbase = OCTAL;
317134187Smckusick 			goto OTX;
317234187Smckusick 		case 'D': /* print as decimal longs */
317334187Smckusick 			tbase = DECIMAL;
317434187Smckusick 			goto OTX;
317534187Smckusick 		case 'X': /* print as hex longs */
317634187Smckusick 			tbase = HEX;
317734187Smckusick OTX:
317834187Smckusick 			if ((cptr = getblk(addr)) == 0)
317934187Smckusick 				return;
318034187Smckusick 			taddr = addr;
318134187Smckusick 			addr &= ~(LONG - 1);
318234187Smckusick 			cur_bytes -= taddr - addr;
318334187Smckusick 			cptr += blkoff(fs, addr);
318434187Smckusick 			lptr = (unsigned long *)cptr;
318534187Smckusick 			objsz = LONG;
318634187Smckusick 			tcount = check_addr(eof_flag, &end, &eof, 0);
318734187Smckusick 			if (tcount) {
318834187Smckusick 				for (i=0; tcount--; i++) {
318934187Smckusick 					lptr =
319034187Smckusick 					   print_check(lptr, &tcount, tbase, i);
319134187Smckusick 					switch (po) {
319234187Smckusick 					case 'O':
319357998Sralph 						printf("%011o    ", *lptr++);
319434187Smckusick 						break;
319534187Smckusick 					case 'D':
319657998Sralph 						printf("%010u     ", *lptr++);
319734187Smckusick 						break;
319834187Smckusick 					case 'X':
319957998Sralph 						printf("%08x       ", *lptr++);
320034187Smckusick 					}
320134187Smckusick 					addr += LONG;
320234187Smckusick 					cur_bytes += LONG;
320334187Smckusick 				}
320434187Smckusick 				printf("\n");
320534187Smckusick 			}
320634187Smckusick 			addr -= LONG;
320734187Smckusick 			erraddr = addr;
320834187Smckusick 			cur_bytes -= LONG;
320934187Smckusick 			errcur_bytes = cur_bytes;
321034187Smckusick 			if (eof) {
321134187Smckusick 				printf("end of file\n");
321234187Smckusick 				error++;
321334187Smckusick 			} else if (end) {
321434187Smckusick 				if (type == BLOCK)
321534187Smckusick 					printf("end of block\n");
321634187Smckusick 				else
321734187Smckusick 					printf("end of fragment\n");
321834187Smckusick 				error++;
321934187Smckusick 			}
322034187Smckusick 			return;
322134187Smckusick 
322234187Smckusick 		default:
322334187Smckusick 			error++;
322434187Smckusick 			printf("no such print option\n");
322534187Smckusick 			return;
322634187Smckusick 		}
322734187Smckusick 	} else
322834187Smckusick 		switch (po) {
322934187Smckusick 
323034187Smckusick 		case 'c': /* print as cylinder group */
323134187Smckusick 			if (type != NUMB)
323234187Smckusick 				if (cur_cgrp + count > fs->fs_ncg) {
323334187Smckusick 					tcount = fs->fs_ncg - cur_cgrp;
323434187Smckusick 					if (!star)
323534187Smckusick 						end++;
323634187Smckusick 				}
323734187Smckusick 			addr &= ~(LONG - 1);
323834187Smckusick 			for (; tcount--;) {
323934187Smckusick 				erraddr = addr;
324034187Smckusick 				errcur_bytes = cur_bytes;
324134187Smckusick 				if (type != NUMB) {
324234187Smckusick 					addr = cgtod(fs, cur_cgrp)
324334187Smckusick 						<< FRGSHIFT;
324434187Smckusick 					cur_cgrp++;
324534187Smckusick 				}
324634187Smckusick 				if ((cptr = getblk(addr)) == 0) {
324734187Smckusick 					if (cur_cgrp)
324834187Smckusick 						cur_cgrp--;
324934187Smckusick 					return;
325034187Smckusick 				}
325134187Smckusick 				cptr += blkoff(fs, addr);
325234187Smckusick 				cg = (struct cg *)cptr;
325334187Smckusick 				if (type == NUMB) {
325434187Smckusick 					cur_cgrp = cg->cg_cgx + 1;
325534187Smckusick 					type = objsz = CGRP;
325634187Smckusick 					if (cur_cgrp + count - 1 > fs->fs_ncg) {
325734187Smckusick 						tcount = fs->fs_ncg - cur_cgrp;
325834187Smckusick 						if (!star)
325934187Smckusick 							end++;
326034187Smckusick 					}
326134187Smckusick 				}
326234197Smckusick 				if (!override && !cg_chkmagic(cg)) {
326334187Smckusick 					printf("invalid cylinder group ");
326434187Smckusick 					printf("magic word\n");
326534187Smckusick 					if (cur_cgrp)
326634187Smckusick 						cur_cgrp--;
326734187Smckusick 					error++;
326834187Smckusick 					return;
326934187Smckusick 				}
327034197Smckusick 				printcg(cg);
327134187Smckusick 				if (tcount)
327234187Smckusick 					printf("\n");
327334187Smckusick 			}
327434187Smckusick 			cur_cgrp--;
327534187Smckusick 			if (end) {
327634187Smckusick 				printf("end of cylinder groups\n");
327734187Smckusick 				error++;
327834187Smckusick 			}
327934187Smckusick 			return;
328034187Smckusick 
328134187Smckusick 		case 'd': /* print as directories */
328234187Smckusick 			if ((cptr = getblk(addr)) == 0)
328334187Smckusick 				return;
328434187Smckusick 			if (type == NUMB) {
328534187Smckusick 				if (fragoff(fs, addr)) {
328634187Smckusick 					printf("address must be at the ");
328734187Smckusick 					printf("beginning of a fragment\n");
328834187Smckusick 					error++;
328934187Smckusick 					return;
329034187Smckusick 				}
329134187Smckusick 				bod_addr = addr;
329234187Smckusick 				type = FRAGMENT;
329334187Smckusick 				dirslot = 0;
329434187Smckusick 				cur_bytes = 0;
329534187Smckusick 				blocksize = FRGSIZE;
329634187Smckusick 				filesize = FRGSIZE * 2;
329734187Smckusick 			}
329834187Smckusick 			cptr += offset;
329934187Smckusick 			objsz = DIRECTORY;
330034187Smckusick 			while (tcount-- && cur_bytes < filesize &&
330134187Smckusick 			       cur_bytes < blocksize && !bcomp(addr)) {
330234187Smckusick 				dirp = (struct direct *)cptr;
330334187Smckusick 				tinode = dirp->d_ino;
330434187Smckusick 				printf("i#: ");
330534187Smckusick 				if (tinode == 0)
330634187Smckusick 					printf("free\t");
330734187Smckusick 				else
330834187Smckusick 					print(tinode, 12, -8, 0);
330957998Sralph 				printf("%s\n", &dirp->d_name[0]);
331034187Smckusick 				erraddr = addr;
331134187Smckusick 				errcur_bytes = cur_bytes;
331234187Smckusick 				addr += dirp->d_reclen;
331334187Smckusick 				cptr += dirp->d_reclen;
331434187Smckusick 				cur_bytes += dirp->d_reclen;
331534187Smckusick 				dirslot++;
331634187Smckusick 			}
331734187Smckusick 			addr = erraddr;
331834187Smckusick 			cur_dir = addr;
331934187Smckusick 			cur_bytes = errcur_bytes;
332034187Smckusick 			stringsize = STRINGSIZE(dirp);
332134187Smckusick 			dirslot--;
332234187Smckusick 			if (tcount >= 0 && !star) {
332334187Smckusick 				switch (type) {
332434187Smckusick 				case FRAGMENT:
332534187Smckusick 					printf("end of fragment\n");
332634187Smckusick 					break;
332734187Smckusick 				case BLOCK:
332834187Smckusick 					printf("end of block\n");
332934187Smckusick 					break;
333034187Smckusick 				default:
333134187Smckusick 					printf("end of directory\n");
333234187Smckusick 				}
333334187Smckusick 				error++;
333434187Smckusick 			} else
333534187Smckusick 				error = 0;
333634187Smckusick 			return;
333734187Smckusick 
333834187Smckusick 		case 'i': /* print as inodes */
333934187Smckusick 			if ((ip = (struct dinode *)getblk(addr)) == 0)
334034187Smckusick 				return;
334134187Smckusick 			for (i=1; i < fs->fs_ncg; i++)
334257998Sralph 				if (addr < (cgimin(fs, i) << FRGSHIFT))
334334187Smckusick 					break;
334434187Smckusick 			i--;
334534187Smckusick 			offset /= INODE;
334657998Sralph 			temp = (addr - (cgimin(fs, i) << FRGSHIFT)) >> FRGSHIFT;
334757998Sralph 			temp = (i * fs->fs_ipg) + fragstoblks(fs, temp) *
334834187Smckusick 							INOPB(fs) + offset;
334934187Smckusick 			if (count + offset > INOPB(fs)) {
335034187Smckusick 				tcount = INOPB(fs) - offset;
335134187Smckusick 				if (!star)
335234187Smckusick 					end++;
335334187Smckusick 			}
335434187Smckusick 			objsz = INODE;
335534187Smckusick 			ip += offset;
335634187Smckusick 			for (i=0; tcount--; ip++, temp++) {
335734187Smckusick 				if ((mode = icheck(addr)) == 0)
335834187Smckusick 					if (!override)
335934187Smckusick 						continue;
336034187Smckusick 				p = " ugtrwxrwxrwx";
336134187Smckusick 
336234187Smckusick 				switch (mode & IFMT) {
336334187Smckusick 				case IFDIR:
336434187Smckusick 					c = 'd';
336534187Smckusick 					break;
336634187Smckusick 				case IFCHR:
336734187Smckusick 					c = 'c';
336834187Smckusick 					break;
336934187Smckusick 				case IFBLK:
337034187Smckusick 					c = 'b';
337134187Smckusick 					break;
337234187Smckusick 				case IFREG:
337334187Smckusick 					c = '-';
337434187Smckusick 					break;
337534187Smckusick 				case IFLNK:
337634187Smckusick 					c = 'l';
337734187Smckusick 					break;
337834187Smckusick 				case IFSOCK:
337934187Smckusick 					c = 's';
338034187Smckusick 					break;
338134187Smckusick 				default:
338234187Smckusick 					c = '?';
338334187Smckusick 					if (!override)
338434187Smckusick 						goto empty;
338534187Smckusick 
338634187Smckusick 				}
338734187Smckusick 				printf("i#: ");
338857998Sralph 				print(temp, 12, -8, 0);
338934187Smckusick 				printf("   md: ");
339034187Smckusick 				printf("%c", c);
339134187Smckusick 				for (mode = mode << 4; *++p; mode = mode << 1) {
339234187Smckusick 					if (mode & IFREG)
339334187Smckusick 						printf("%c", *p);
339434187Smckusick 					else
339534187Smckusick 						printf("-");
339657998Sralph 				}
339734187Smckusick 				printf("  uid: ");
339857998Sralph 				print(ip->di_uid, 8, -4, 0);
339934187Smckusick 				printf("      gid: ");
340057998Sralph 				print(ip->di_gid, 8, -4, 0);
340134187Smckusick 				printf("\n");
340234187Smckusick 				printf("ln: ");
340357998Sralph 				print(ip->di_nlink, 8, -4, 0);
340434187Smckusick 				printf("       bs: ");
340557998Sralph 				print(ip->di_blocks, 12, -8, 0);
340634187Smckusick 				printf("   sz : ");
340764645Shibler 				print((int)ip->di_size, 12, -8, 0);
340834187Smckusick 				printf("\n");
340934187Smckusick 				if (ip->di_mode & IFCHR) {
341034187Smckusick 					printf("maj: ");
341157998Sralph 					print(ip->di_db[1] & 0377, 4, -2, 0);
341234187Smckusick 					printf("  min: ");
341357998Sralph 					print(ip->di_db[0] & 0377, 4, -2, 0);
341434187Smckusick 					printf("\n");
341534187Smckusick 				} else {
341634187Smckusick 					for (i = 0; i < NDADDR; ) {
341734187Smckusick 						if (ip->di_db[i] == 0)
341834187Smckusick 							break;
341957998Sralph 						printf("db#%x: ", i);
342057998Sralph 						print(ip->di_db[i], 11, -8, 0);
342134187Smckusick 						if (++i % 4 == 0)
342234187Smckusick 							printf("\n");
342334187Smckusick 						else
342434187Smckusick 							printf("  ");
342534187Smckusick 					}
342634187Smckusick 					if (i % 4)
342734187Smckusick 						printf("\n");
342834187Smckusick 					for (i = 0; i < NIADDR; i++) {
342934187Smckusick 						if (ip->di_ib[i] == 0)
343034187Smckusick 							break;
343157998Sralph 						printf("ib#%x: ", i);
343257998Sralph 						print(ip->di_ib[i], 11, -8, 0);
343334187Smckusick 						printf("  ");
343434187Smckusick 					}
343534187Smckusick 					if (i)
343634187Smckusick 						printf("\n");
343734187Smckusick 				}
343834187Smckusick 				if (count == 1) {
343934187Smckusick 					printf("\taccessed: %s",
3440*69260Smckusick 						ctime(&ip->di_atime));
344134187Smckusick 					printf("\tmodified: %s",
3442*69260Smckusick 						ctime(&ip->di_mtime));
344334187Smckusick 					printf("\tcreated : %s",
3444*69260Smckusick 						ctime(&ip->di_ctime));
344534187Smckusick 				}
344634187Smckusick 				if (tcount)
344734187Smckusick 					printf("\n");
344834187Smckusick empty:
344934187Smckusick 				if (c == '?' && !override) {
345034187Smckusick 					printf("i#: ");
345134187Smckusick 					print(temp, 12, -8, 0);
345234187Smckusick 					printf("  is unallocated\n");
345334187Smckusick 					if (count != 1)
345434187Smckusick 						printf("\n");
345534187Smckusick 				}
345634187Smckusick 				cur_ino = erraddr = addr;
345734187Smckusick 				errcur_bytes = cur_bytes;
345834187Smckusick 				cur_inum++;
345934187Smckusick 				addr = addr + INODE;
346034187Smckusick 			}
346134187Smckusick 			addr = erraddr;
346234187Smckusick 			cur_bytes = errcur_bytes;
346334187Smckusick 			cur_inum--;
346434187Smckusick 			if (end) {
346534187Smckusick 				printf("end of block\n");
346634187Smckusick 				error++;
346734187Smckusick 			}
346834187Smckusick 			return;
346934187Smckusick 
347034187Smckusick 		case 's': /* print as super block */
347134187Smckusick 			if (cur_cgrp == -1) {
347234187Smckusick 				addr = SBLOCK * DEV_BSIZE;
347334187Smckusick 				type = NUMB;
347434187Smckusick 			}
347534187Smckusick 			addr &= ~(LONG - 1);
347634187Smckusick 			if (type != NUMB)
347734187Smckusick 				if (cur_cgrp + count > fs->fs_ncg) {
347834187Smckusick 					tcount = fs->fs_ncg - cur_cgrp;
347934187Smckusick 					if (!star)
348034187Smckusick 						end++;
348134187Smckusick 				}
348234187Smckusick 			for (; tcount--;) {
348334187Smckusick 				erraddr = addr;
348434187Smckusick 				cur_bytes = errcur_bytes;
348534187Smckusick 				if (type != NUMB) {
348634187Smckusick 					addr = cgsblock(fs, cur_cgrp)
348734187Smckusick 							<< FRGSHIFT;
348834187Smckusick 					cur_cgrp++;
348934187Smckusick 				}
349034187Smckusick 				if ((cptr = getblk(addr)) == 0) {
349134187Smckusick 					if (cur_cgrp)
349234187Smckusick 						cur_cgrp--;
349334187Smckusick 					return;
349434187Smckusick 				}
349534187Smckusick 				cptr += blkoff(fs, addr);
349634187Smckusick 				sb = (struct fs *)cptr;
349734187Smckusick 				if (type == NUMB) {
349834187Smckusick 					for (i = 0; i < fs->fs_ncg; i++)
349934187Smckusick 						if (addr == cgsblock(fs, i) <<
350034187Smckusick 								FRGSHIFT)
350134187Smckusick 							break;
350234187Smckusick 					if (i == fs->fs_ncg)
350334187Smckusick 						cur_cgrp = 0;
350434187Smckusick 					else
350534187Smckusick 						cur_cgrp = i + 1;
350634187Smckusick 					type = objsz = SB;
350734187Smckusick 					if (cur_cgrp + count - 1 > fs->fs_ncg) {
350834187Smckusick 						tcount = fs->fs_ncg - cur_cgrp;
350934187Smckusick 						if (!star)
351034187Smckusick 							end++;
351134187Smckusick 					}
351234187Smckusick 				}
351334187Smckusick 				if (sb->fs_magic != FS_MAGIC) {
351434187Smckusick 					cur_cgrp = 0;
351534187Smckusick 					if (!override) {
351634187Smckusick 						printf("invalid super block ");
351734187Smckusick 						printf("magic word\n");
351834187Smckusick 						cur_cgrp--;
351934187Smckusick 						error++;
352034187Smckusick 						return;
352134187Smckusick 					}
352234187Smckusick 				}
352334187Smckusick 				if (cur_cgrp == 0)
352434187Smckusick 					printf("\tsuper block:\n");
352534187Smckusick 				else {
352634187Smckusick 					printf("\tsuper block in cylinder ");
352734187Smckusick 					printf("group ");
352834187Smckusick 					print(cur_cgrp - 1, 0, 0, 0);
352934187Smckusick 					printf(":\n");
353034187Smckusick 				}
353134197Smckusick 				printsb(sb);
353234187Smckusick 				if (tcount)
353334187Smckusick 					printf("\n");
353434187Smckusick 			}
353534187Smckusick 			cur_cgrp--;
353634187Smckusick 			if (end) {
353734187Smckusick 				printf("end of super blocks\n");
353834187Smckusick 				error++;
353934187Smckusick 			}
354034187Smckusick 			return;
354134187Smckusick 		default:
354234187Smckusick 			error++;
354334187Smckusick 			printf("no such print option\n");
354434187Smckusick 			return;
354534187Smckusick 		}
354634187Smckusick }
354734187Smckusick 
354834187Smckusick /*
354934187Smckusick  * valid_addr - call check_addr to validate the current address.
355034187Smckusick  */
valid_addr()355134187Smckusick valid_addr()
355234187Smckusick {
355334187Smckusick 	short	eof_flag, end = 0, eof = 0;
355434187Smckusick 	long	tcount = count;
355534187Smckusick 
355634187Smckusick 	if (!trapped)
355734187Smckusick 		return(1);
355834187Smckusick 	if (cur_bytes < 0) {
355934187Smckusick 		cur_bytes = 0;
356034187Smckusick 		if (blocksize > filesize) {
356134187Smckusick 			printf("beginning of file\n");
356234187Smckusick 		} else {
356334187Smckusick 			if (type == BLOCK)
356434187Smckusick 				printf("beginning of block\n");
356534187Smckusick 			else
356634187Smckusick 				printf("beginning of fragment\n");
356734187Smckusick 		}
356834187Smckusick 		error++;
356934187Smckusick 		return(0);
357034187Smckusick 	}
357134187Smckusick 	count = 1;
357234187Smckusick 	check_addr(1, &end, &eof, (filesize < blocksize));
357334187Smckusick 	count = tcount;
357434187Smckusick 	if (eof) {
357534187Smckusick 		printf("end of file\n");
357634187Smckusick 		error++;
357734187Smckusick 		return(0);
357834187Smckusick 	}
357934187Smckusick 	if (end == 2) {
358034187Smckusick 		if (erraddr > addr) {
358134187Smckusick 			if (type == BLOCK)
358234187Smckusick 				printf("beginning of block\n");
358334187Smckusick 			else
358434187Smckusick 				printf("beginning of fragment\n");
358534187Smckusick 			error++;
358634187Smckusick 			return(0);
358734187Smckusick 		}
358834187Smckusick 	}
358934187Smckusick 	if (end) {
359034187Smckusick 		if (type == BLOCK)
359134187Smckusick 			printf("end of block\n");
359234187Smckusick 		else
359334187Smckusick 			printf("end of fragment\n");
359434187Smckusick 		error++;
359534187Smckusick 		return(0);
359634187Smckusick 	}
359734187Smckusick 	return(1);
359834187Smckusick }
359934187Smckusick 
360034187Smckusick /*
360134187Smckusick  * check_addr - check if the address crosses the end of block or
360234187Smckusick  *	end of file.  Return the proper count.
360334187Smckusick  */
check_addr(eof_flag,end,eof,keep_on)360434187Smckusick check_addr(eof_flag, end, eof, keep_on)
360534187Smckusick 	short	eof_flag, *end, *eof, keep_on;
360634187Smckusick {
360734187Smckusick 	long	temp, tcount = count, taddr = addr, tcur_bytes = cur_bytes;
360834187Smckusick 
360934187Smckusick 	if (bcomp(addr + count * objsz - 1) ||
361034187Smckusick 	    (keep_on && taddr < (bmap(cur_block) << FRGSHIFT))) {
361134187Smckusick 		error = 0;
361234187Smckusick 		addr = taddr;
361334187Smckusick 		cur_bytes = tcur_bytes;
361434187Smckusick 		if (keep_on) {
361534187Smckusick 			if (addr < erraddr) {
361634187Smckusick 				if (cur_bytes < 0) {
361734187Smckusick 					(*end) = 2;
361834187Smckusick 					return;
361934187Smckusick 				}
362034187Smckusick 				temp = cur_block - lblkno(fs, cur_bytes);
362134187Smckusick 				cur_block -= temp;
362234187Smckusick 				if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
362334187Smckusick 					cur_block += temp;
362434187Smckusick 					return;
362534187Smckusick 				}
362634187Smckusick 				temp = tcur_bytes - cur_bytes;
362734187Smckusick 				addr += temp;
362834187Smckusick 				cur_bytes += temp;
362934187Smckusick 				return;
363034187Smckusick 			} else {
363134187Smckusick 				if (cur_bytes >= filesize) {
363234187Smckusick 					(*eof)++;
363334187Smckusick 					return;
363434187Smckusick 				}
363534187Smckusick 				temp = lblkno(fs, cur_bytes) - cur_block;
363634187Smckusick 				cur_block += temp;
363734187Smckusick 				if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
363834187Smckusick 					cur_block -= temp;
363934187Smckusick 					return;
364034187Smckusick 				}
364134187Smckusick 				temp = tcur_bytes - cur_bytes;
364234187Smckusick 				addr += temp;
364334187Smckusick 				cur_bytes += temp;
364434187Smckusick 				return;
364534187Smckusick 			}
364634187Smckusick 		}
364734187Smckusick 		tcount = (blkroundup(fs, addr+1)-addr) / objsz;
364834187Smckusick 		if (!star)
364934187Smckusick 			(*end) = 2;
365034187Smckusick 	}
365134187Smckusick 	addr = taddr;
365234187Smckusick 	cur_bytes = tcur_bytes;
365334187Smckusick 	if (eof_flag) {
365434187Smckusick 		if (blocksize > filesize) {
365534187Smckusick 			if (cur_bytes >= filesize) {
365634187Smckusick 				tcount = 0;
365734187Smckusick 				(*eof)++;
365834187Smckusick 			} else if (tcount > (filesize - cur_bytes) / objsz) {
365934187Smckusick 				tcount = (filesize - cur_bytes) / objsz;
366034187Smckusick 				if (!star || tcount == 0)
366134187Smckusick 					(*eof)++;
366234187Smckusick 			}
366334187Smckusick 		} else {
366434187Smckusick 			if (cur_bytes >= blocksize) {
366534187Smckusick 				tcount = 0;
366634187Smckusick 				(*end)++;
366734187Smckusick 			} else if (tcount > (blocksize - cur_bytes) / objsz) {
366834187Smckusick 				tcount = (blocksize - cur_bytes) / objsz;
366934187Smckusick 				if (!star || tcount == 0)
367034187Smckusick 					(*end)++;
367134187Smckusick 			}
367234187Smckusick 		}
367334187Smckusick 	}
367434187Smckusick 	return(tcount);
367534187Smckusick }
367634187Smckusick 
367734187Smckusick /*
367834187Smckusick  * print_check - check if the index needs to be printed and delete
367934187Smckusick  *	rows of zeros from the output.
368034187Smckusick  */
368134187Smckusick unsigned long *
print_check(lptr,tcount,tbase,i)368234187Smckusick print_check(lptr, tcount, tbase, i)
368334187Smckusick 	unsigned long	*lptr;
368434187Smckusick 	long		*tcount;
368534187Smckusick 	short		tbase;
368634187Smckusick 	register int	i;
368734187Smckusick {
368834187Smckusick 	register int	j, k, temp = BYTESPERLINE / objsz;
368934187Smckusick 	short		first_time = 0;
369034187Smckusick 	unsigned long	*tlptr;
369134187Smckusick 	unsigned short	*tsptr, *sptr;
369234187Smckusick 
369334187Smckusick 	sptr = (unsigned short *)lptr;
369434187Smckusick 	if (i == 0)
369534187Smckusick 		first_time = 1;
369634187Smckusick 	if (i % temp == 0) {
369734187Smckusick 		if (*tcount >= temp - 1) {
369834187Smckusick 			if (objsz == SHORT)
369934187Smckusick 				tsptr = sptr;
370034187Smckusick 			else
370134187Smckusick 				tlptr = lptr;
370234187Smckusick 			k = *tcount - 1;
370334187Smckusick 			for (j = i; k--; j++)
370434187Smckusick 				if (objsz == SHORT) {
370534187Smckusick 					if (*tsptr++ != 0)
370634187Smckusick 						break;
370734187Smckusick 				} else {
370834187Smckusick 					if (*tlptr++ != 0)
370934187Smckusick 						break;
371034187Smckusick 				}
371134187Smckusick 			if (j > (i + temp - 1)) {
371234187Smckusick 				j = (j - i) / temp;
371334187Smckusick 				while (j-- > 0) {
371434187Smckusick 					if (objsz == SHORT)
371534187Smckusick 						sptr += temp;
371634187Smckusick 					else
371734187Smckusick 						lptr += temp;
371834187Smckusick 					*tcount -= temp;
371934187Smckusick 					i += temp;
372057998Sralph 					addr += BYTESPERLINE;
372134187Smckusick 					cur_bytes += BYTESPERLINE;
372234187Smckusick 				}
372334187Smckusick 				if (first_time)
372434187Smckusick 					printf("*");
372534187Smckusick 				else
372634187Smckusick 					printf("\n*");
372734187Smckusick 			}
372834187Smckusick 			if (i)
372934187Smckusick 				printf("\n");
373034187Smckusick 			index(tbase);
373134187Smckusick 		} else {
373234187Smckusick 			if (i)
373334187Smckusick 				printf("\n");
373434187Smckusick 			index(tbase);
373534187Smckusick 		}
373634187Smckusick 	}
373734187Smckusick 	if(objsz == SHORT)
373834187Smckusick 		return((unsigned long *)sptr);
373934187Smckusick 	else
374034187Smckusick 		return(lptr);
374134187Smckusick }
374234187Smckusick 
374334187Smckusick /*
374434187Smckusick  * index - print a byte index for the printout in base b
374534187Smckusick  *	with leading zeros.
374634187Smckusick  */
index(b)374734187Smckusick index(b)
374834187Smckusick 	int	b;
374934187Smckusick {
375034187Smckusick 	int	tbase = base;
375134187Smckusick 
375234187Smckusick 	base = b;
375334187Smckusick 	print(addr, 8, 8, 1);
375434187Smckusick 	printf(":\t");
375534187Smckusick 	base = tbase;
375634187Smckusick }
375734187Smckusick 
375834187Smckusick /*
375934187Smckusick  * print - print out the value to digits places with/without
376034187Smckusick  *	leading zeros and right/left justified in the current base.
376134187Smckusick  */
print(value,fieldsz,digits,lead)376234187Smckusick print(value, fieldsz, digits, lead)
376334187Smckusick 	int		value, fieldsz, digits, lead;
376434187Smckusick {
376534187Smckusick 	register int	i, left = 0;
376634187Smckusick 	char		mode = BASE[base - OCTAL];
376734187Smckusick 	char		*string = &scratch[0];
376834187Smckusick 
376934187Smckusick 	if (digits < 0) {
377034187Smckusick 		left = 1;
377134187Smckusick 		digits *= -1;
377234187Smckusick 	}
377334187Smckusick 	if (base != HEX)
377434187Smckusick 		if (digits)
377534187Smckusick 			digits = digits + (digits - 1)/((base >> 1) - 1) + 1;
377634187Smckusick 		else
377734187Smckusick 			digits = 1;
377834187Smckusick 	if (lead) {
377934187Smckusick 		if (left)
378034187Smckusick 			sprintf(string, "%%%c%d%d.%d%c",
378134187Smckusick 				'-', 0, digits, lead, mode);
378234187Smckusick 		else
378334187Smckusick 			sprintf(string, "%%%d%d.%d%c", 0, digits, lead, mode);
378434187Smckusick 	} else {
378534187Smckusick 		if (left)
378634187Smckusick 			sprintf(string, "%%%c%d%c", '-', digits, mode);
378734187Smckusick 		else
378834187Smckusick 			sprintf(string, "%%%d%c", digits, mode);
378934187Smckusick 	}
379034187Smckusick 	printf(string, value);
379134187Smckusick 	for (i = 0; i < fieldsz - digits; i++)
379234187Smckusick 		printf(" ");
379334187Smckusick }
379434187Smckusick 
379534187Smckusick /*
379634197Smckusick  * Print out the contents of a superblock.
379734197Smckusick  */
379834197Smckusick printsb(fs)
379934197Smckusick 	struct fs *fs;
380034197Smckusick {
380134197Smckusick 	int c, i, j, k, size;
380234197Smckusick 
380336249Smckusick #ifdef FS_42POSTBLFMT
380434197Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)
380534197Smckusick 		fs->fs_nrpos = 8;
380634197Smckusick 	printf("magic\t%x\tformat\t%s\ttime\t%s", fs->fs_magic,
380734197Smckusick 	    fs->fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic",
380834197Smckusick 	    ctime(&fs->fs_time));
380936249Smckusick #else
381036249Smckusick 	printf("magic\t%x\ttime\t%s",
381136249Smckusick 	    fs->fs_magic, ctime(&fs->fs_time));
381236249Smckusick #endif
381334197Smckusick 	printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
381434197Smckusick 	    fs->fs_cstotal.cs_nbfree, fs->fs_cstotal.cs_ndir,
381534197Smckusick 	    fs->fs_cstotal.cs_nifree, fs->fs_cstotal.cs_nffree);
381634197Smckusick 	printf("ncg\t%d\tncyl\t%d\tsize\t%d\tblocks\t%d\n",
381734197Smckusick 	    fs->fs_ncg, fs->fs_ncyl, fs->fs_size, fs->fs_dsize);
381834197Smckusick 	printf("bsize\t%d\tshift\t%d\tmask\t0x%08x\n",
381934197Smckusick 	    fs->fs_bsize, fs->fs_bshift, fs->fs_bmask);
382034197Smckusick 	printf("fsize\t%d\tshift\t%d\tmask\t0x%08x\n",
382134197Smckusick 	    fs->fs_fsize, fs->fs_fshift, fs->fs_fmask);
382234197Smckusick 	printf("frag\t%d\tshift\t%d\tfsbtodb\t%d\n",
382334197Smckusick 	    fs->fs_frag, fs->fs_fragshift, fs->fs_fsbtodb);
382434197Smckusick 	printf("cpg\t%d\tbpg\t%d\tfpg\t%d\tipg\t%d\n",
382534197Smckusick 	    fs->fs_cpg, fs->fs_fpg / fs->fs_frag, fs->fs_fpg, fs->fs_ipg);
382634197Smckusick 	printf("minfree\t%d%%\toptim\t%s\tmaxcontig %d\tmaxbpg\t%d\n",
382734197Smckusick 	    fs->fs_minfree, fs->fs_optim == FS_OPTSPACE ? "space" : "time",
382834197Smckusick 	    fs->fs_maxcontig, fs->fs_maxbpg);
382936249Smckusick #ifdef FS_42POSTBLFMT
383034197Smckusick 	printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
383134197Smckusick 	    fs->fs_rotdelay, fs->fs_headswitch, fs->fs_trkseek, fs->fs_rps);
383234197Smckusick 	printf("ntrak\t%d\tnsect\t%d\tnpsect\t%d\tspc\t%d\n",
383334197Smckusick 	    fs->fs_ntrak, fs->fs_nsect, fs->fs_npsect, fs->fs_spc);
383434197Smckusick 	printf("trackskew %d\tinterleave %d\n",
383534197Smckusick 	    fs->fs_trackskew, fs->fs_interleave);
383636249Smckusick #else
383736249Smckusick 	printf("rotdelay %dms\trps\t%d\n",
383836249Smckusick 	    fs->fs_rotdelay, fs->fs_rps);
383936249Smckusick 	printf("ntrak\t%d\tnsect\t%d\tspc\t%d\n",
384036249Smckusick 	    fs->fs_ntrak, fs->fs_nsect, fs->fs_spc);
384136249Smckusick #endif
384234197Smckusick 	printf("nindir\t%d\tinopb\t%d\tnspf\t%d\n",
384334197Smckusick 	    fs->fs_nindir, fs->fs_inopb, fs->fs_nspf);
384434197Smckusick 	printf("sblkno\t%d\tcblkno\t%d\tiblkno\t%d\tdblkno\t%d\n",
384534197Smckusick 	    fs->fs_sblkno, fs->fs_cblkno, fs->fs_iblkno, fs->fs_dblkno);
384634197Smckusick 	printf("sbsize\t%d\tcgsize\t%d\tcgoffset %d\tcgmask\t0x%08x\n",
384734197Smckusick 	    fs->fs_sbsize, fs->fs_cgsize, fs->fs_cgoffset, fs->fs_cgmask);
384834197Smckusick 	printf("csaddr\t%d\tcssize\t%d\tshift\t%d\tmask\t0x%08x\n",
384934197Smckusick 	    fs->fs_csaddr, fs->fs_cssize, fs->fs_csshift, fs->fs_csmask);
385034197Smckusick 	printf("cgrotor\t%d\tfmod\t%d\tronly\t%d\n",
385134197Smckusick 	    fs->fs_cgrotor, fs->fs_fmod, fs->fs_ronly);
385236249Smckusick #ifdef FS_42POSTBLFMT
385334197Smckusick 	if (fs->fs_cpc != 0)
385434197Smckusick 		printf("blocks available in each of %d rotational positions",
385534197Smckusick 		     fs->fs_nrpos);
385634197Smckusick 	else
385734197Smckusick 		printf("insufficient space to maintain rotational tables\n");
385836249Smckusick #endif
385934197Smckusick 	for (c = 0; c < fs->fs_cpc; c++) {
386034197Smckusick 		printf("\ncylinder number %d:", c);
386136249Smckusick #ifdef FS_42POSTBLFMT
386234197Smckusick 		for (i = 0; i < fs->fs_nrpos; i++) {
386334197Smckusick 			if (fs_postbl(fs, c)[i] == -1)
386434197Smckusick 				continue;
386534197Smckusick 			printf("\n   position %d:\t", i);
386634197Smckusick 			for (j = fs_postbl(fs, c)[i], k = 1; ;
386734197Smckusick 			     j += fs_rotbl(fs)[j], k++) {
386834197Smckusick 				printf("%5d", j);
386934197Smckusick 				if (k % 12 == 0)
387034197Smckusick 					printf("\n\t\t");
387134197Smckusick 				if (fs_rotbl(fs)[j] == 0)
387234197Smckusick 					break;
387334197Smckusick 			}
387434197Smckusick 		}
387536249Smckusick #else
387636249Smckusick 		for (i = 0; i < NRPOS; i++) {
387736249Smckusick 			if (fs->fs_postbl[c][i] == -1)
387836249Smckusick 				continue;
387936249Smckusick 			printf("\n   position %d:\t", i);
388036249Smckusick 			for (j = fs->fs_postbl[c][i], k = 1; ;
388136249Smckusick 			     j += fs->fs_rotbl[j], k++) {
388236249Smckusick 				printf("%5d", j);
388336249Smckusick 				if (k % 12 == 0)
388436249Smckusick 					printf("\n\t\t");
388536249Smckusick 				if (fs->fs_rotbl[j] == 0)
388636249Smckusick 					break;
388736249Smckusick 			}
388836249Smckusick 		}
388936249Smckusick #endif
389034197Smckusick 	}
389157998Sralph 	printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):\n\t");
389234197Smckusick 	for (i = 0, j = 0; i < fs->fs_cssize; i += fs->fs_bsize, j++) {
389334197Smckusick 		size = fs->fs_cssize - i < fs->fs_bsize ?
389434197Smckusick 		    fs->fs_cssize - i : fs->fs_bsize;
389534197Smckusick 		fs->fs_csp[j] = (struct csum *)calloc(1, size);
389657998Sralph 		(void)lseek(fd, fsbtodb(fs, (fs->fs_csaddr + j * fs->fs_frag)) *
389757998Sralph 		    fs->fs_fsize / fsbtodb(fs, 1), SEEK_SET);
389834197Smckusick 		if (read(fd, fs->fs_csp[j], size) != size) {
389934197Smckusick 			for (j--; j >= 0; j--)
390034197Smckusick 				free(fs->fs_csp[j]);
390134197Smckusick 			return;
390234197Smckusick 		}
390334197Smckusick 	}
390434197Smckusick 	for (i = 0; i < fs->fs_ncg; i++) {
390534197Smckusick 		struct csum *cs = &fs->fs_cs(fs, i);
390634197Smckusick 		if (i && i % 4 == 0)
390734197Smckusick 			printf("\n\t");
390834197Smckusick 		printf("(%d,%d,%d,%d) ",
390934197Smckusick 		    cs->cs_nbfree, cs->cs_ndir, cs->cs_nifree, cs->cs_nffree);
391034197Smckusick 	}
391134197Smckusick 	for (j--; j >= 0; j--)
391234197Smckusick 		free(fs->fs_csp[j]);
391334197Smckusick 	printf("\n");
391434197Smckusick 	if (fs->fs_ncyl % fs->fs_cpg) {
391534197Smckusick 		printf("cylinders in last group %d\n",
391634197Smckusick 		    i = fs->fs_ncyl % fs->fs_cpg);
391734197Smckusick 		printf("blocks in last group %d\n",
391834197Smckusick 		    i * fs->fs_spc / NSPB(fs));
391934197Smckusick 	}
392034197Smckusick }
392134197Smckusick 
392234197Smckusick /*
392334197Smckusick  * Print out the contents of a cylinder group.
392434197Smckusick  */
392534197Smckusick printcg(cg)
392634197Smckusick 	struct cg *cg;
392734197Smckusick {
392857998Sralph 	int i, j;
392934197Smckusick 
393034197Smckusick 	printf("\ncg %d:\n", cg->cg_cgx);
393136249Smckusick #ifdef FS_42POSTBLFMT
393234197Smckusick 	printf("magic\t%x\ttell\t%x\ttime\t%s",
393334197Smckusick 	    fs->fs_postblformat == FS_42POSTBLFMT ?
393434197Smckusick 	    ((struct ocg *)cg)->cg_magic : cg->cg_magic,
393534197Smckusick 	    fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
393634197Smckusick 	    ctime(&cg->cg_time));
393736249Smckusick #else
393836249Smckusick 	printf("magic\t%x\ttell\t%x\ttime\t%s",
393936249Smckusick 	    cg->cg_magic,
394036249Smckusick 	    fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
394136249Smckusick 	    ctime(&cg->cg_time));
394236249Smckusick #endif
394334197Smckusick 	printf("cgx\t%d\tncyl\t%d\tniblk\t%d\tndblk\t%d\n",
394434197Smckusick 	    cg->cg_cgx, cg->cg_ncyl, cg->cg_niblk, cg->cg_ndblk);
394534197Smckusick 	printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
394634197Smckusick 	    cg->cg_cs.cs_nbfree, cg->cg_cs.cs_ndir,
394734197Smckusick 	    cg->cg_cs.cs_nifree, cg->cg_cs.cs_nffree);
394834197Smckusick 	printf("rotor\t%d\tirotor\t%d\tfrotor\t%d\nfrsum",
394934197Smckusick 	    cg->cg_rotor, cg->cg_irotor, cg->cg_frotor);
395034197Smckusick 	for (i = 1, j = 0; i < fs->fs_frag; i++) {
395134197Smckusick 		printf("\t%d", cg->cg_frsum[i]);
395234197Smckusick 		j += i * cg->cg_frsum[i];
395334197Smckusick 	}
395434197Smckusick 	printf("\nsum of frsum: %d\niused:\t", j);
395534197Smckusick 	pbits(cg_inosused(cg), fs->fs_ipg);
395634197Smckusick 	printf("free:\t");
395734197Smckusick 	pbits(cg_blksfree(cg), fs->fs_fpg);
395834197Smckusick 	printf("b:\n");
395934197Smckusick 	for (i = 0; i < fs->fs_cpg; i++) {
396034197Smckusick 		if (cg_blktot(cg)[i] == 0)
396134197Smckusick 			continue;
396234197Smckusick 		printf("   c%d:\t(%d)\t", i, cg_blktot(cg)[i]);
396336249Smckusick #ifdef FS_42POSTBLFMT
396434197Smckusick 		for (j = 0; j < fs->fs_nrpos; j++) {
396534197Smckusick 			if (fs->fs_cpc == 0 ||
396634197Smckusick 			    fs_postbl(fs, i % fs->fs_cpc)[j] == -1)
396734197Smckusick 				continue;
396834197Smckusick 			printf(" %d", cg_blks(fs, cg, i)[j]);
396934197Smckusick 		}
397036249Smckusick #else
397136249Smckusick 		for (j = 0; j < NRPOS; j++) {
397236249Smckusick 			if (fs->fs_cpc == 0 ||
397336249Smckusick 			    fs->fs_postbl[i % fs->fs_cpc][j] == -1)
397436249Smckusick 				continue;
397536249Smckusick 			printf(" %d", cg->cg_b[i][j]);
397636249Smckusick 		}
397736249Smckusick #endif
397834197Smckusick 		printf("\n");
397934197Smckusick 	}
398034197Smckusick }
398134197Smckusick 
398234197Smckusick /*
398334197Smckusick  * Print out the contents of a bit array.
398434197Smckusick  */
pbits(cp,max)398534197Smckusick pbits(cp, max)
398634197Smckusick 	register char *cp;
398734197Smckusick 	int max;
398834197Smckusick {
398934197Smckusick 	register int i;
399034197Smckusick 	int count = 0, j;
399134197Smckusick 
399234197Smckusick 	for (i = 0; i < max; i++)
399334197Smckusick 		if (isset(cp, i)) {
399434197Smckusick 			if (count)
399534197Smckusick 				printf(",%s", count % 6 ? " " : "\n\t");
399634197Smckusick 			count++;
399734197Smckusick 			printf("%d", i);
399834197Smckusick 			j = i;
399934197Smckusick 			while ((i+1)<max && isset(cp, i+1))
400034197Smckusick 				i++;
400134197Smckusick 			if (i != j)
400234197Smckusick 				printf("-%d", i);
400334197Smckusick 		}
400434197Smckusick 	printf("\n");
400534197Smckusick }
400634197Smckusick 
400734197Smckusick /*
400834187Smckusick  * bcomp - used to check for block over/under flows when stepping through
400934187Smckusick  *	a file system.
401034187Smckusick  */
bcomp(addr)401134187Smckusick bcomp(addr)
401234187Smckusick 	long	addr;
401334187Smckusick {
401434187Smckusick 	if (override)
401534187Smckusick 		return(0);
401634187Smckusick 	if (lblkno(fs, addr) == (bhdr.fwd)->blkno)
401734187Smckusick 		return(0);
401834187Smckusick 	error++;
401934187Smckusick 	return(1);
402034187Smckusick }
402134187Smckusick 
402234187Smckusick /*
402334187Smckusick  * bmap - maps the logical block number of a file into
402434187Smckusick  *	the corresponding physical block on the file
402534187Smckusick  *	system.
402634187Smckusick  */
402734187Smckusick long
bmap(bn)402834187Smckusick bmap(bn)
402934187Smckusick 	long			bn;
403034187Smckusick {
403134187Smckusick 	register int		i, j;
403234187Smckusick 	register struct dinode	*ip;
403334187Smckusick 	int			sh;
403434187Smckusick 	long			nb;
403534187Smckusick 
403634187Smckusick 	ip = (struct dinode *)cur_ino;
403734187Smckusick 	if (bn < NDADDR) {
403834187Smckusick 		addr = (long)&ip->di_db[bn];
403934187Smckusick 		cur_bytes = bn * BLKSIZE;
404034187Smckusick 		return(nullblk(nb=get(LONG)) ? 0L : nb);
404134187Smckusick 	}
404234187Smckusick 
404334187Smckusick 	sh = 1;
404434187Smckusick 	bn -= NDADDR;
404534187Smckusick 	for (j = NIADDR; j > 0; j--) {
404634187Smckusick 		sh *= NINDIR(fs);
404734187Smckusick 		if (bn < sh)
404834187Smckusick 			break;
404934187Smckusick 		bn -= sh;
405034187Smckusick 	}
405134187Smckusick 	if (j == 0) {
405234187Smckusick 		printf("file too big\n");
405334187Smckusick 		error++;
405434187Smckusick 		return(0L);
405534187Smckusick 	}
405634187Smckusick 	addr = (long)&ip->di_ib[NIADDR - j];
405734187Smckusick 	nb = get(LONG);
405834187Smckusick 	if (nb == 0)
405934187Smckusick 		return(0L);
406034187Smckusick 	for (; j <= NIADDR; j++) {
406134187Smckusick 		sh /= NINDIR(fs);
406234187Smckusick 		addr = (nb << FRGSHIFT) + ((bn / sh) % NINDIR(fs)) * LONG;
406334187Smckusick 		if (nullblk(nb = get(LONG)))
406434187Smckusick 			return(0L);
406534187Smckusick 	}
406634187Smckusick 	return(nb);
406734187Smckusick }
4068