xref: /illumos-gate/usr/src/cmd/fs.d/udfs/fsdb/fsdb.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <fcntl.h>
32 #include <signal.h>
33 #include <setjmp.h>
34 #include <errno.h>
35 #include <inttypes.h>
36 #include <libgen.h>
37 #include <locale.h>
38 
39 #include <sys/param.h>
40 #include <sys/signal.h>
41 #include <sys/file.h>
42 #include <sys/sysmacros.h>
43 #include <sys/types.h>
44 #include <sys/vnode.h>
45 #include <sys/mntent.h>
46 #include <sys/wait.h>
47 #include <sys/vtoc.h>
48 #include <sys/dkio.h>
49 
50 #include <sys/fs/udf_volume.h>
51 #include "ud_lib.h"
52 #include "y.tab.h"
53 
54 typedef unsigned short unicode_t;
55 #define	MAXNAMLEN	0x200
56 
57 extern uint32_t i_number;
58 
59 extern int32_t run_fsdb();
60 
61 void usage();
62 void init_buffers();
63 char *getblk(u_offset_t);
64 int32_t parse_udfs(uint32_t);
65 int32_t parse_vds(uint32_t, uint32_t);
66 int32_t parse_part(struct part_desc *);
67 int32_t parse_lvd(struct log_vol_desc *);
68 int32_t parse_fsds();
69 int32_t get_vat_loc();
70 int32_t get_fid(uint32_t, uint8_t *, uint64_t);
71 
72 
73 char *progname;
74 char prompt[256] = "fsdb>";
75 
76 #define	ARG_OVERRIDE	0
77 #define	ARG_NEW_PROMPT	1
78 #define	ARG_WR_ENABLED	2
79 #define	ARG_USAGE	3
80 
81 char *subopt_v[] = {
82 	"o",
83 	"p",
84 	"w",
85 	"?",
86 	NULL
87 };
88 int32_t override = 0;
89 int32_t openflg = O_RDONLY;
90 
91 #define	MAX_PARTS	10
92 
93 /*
94  * udp_flags
95  */
96 #define	UDP_BITMAPS	0x00
97 #define	UDP_SPACETBLS	0x01
98 
99 ud_handle_t udh;
100 int32_t fd, nparts, nmaps;
101 int32_t bmask, l2d, l2b;
102 
103 
104 uint16_t ricb_prn;
105 uint32_t ricb_loc, ricb_len;
106 extern int value;
107 
108 
109 int32_t
110 main(int argc, char *argv[])
111 {
112 	int opt, ret;
113 	uint32_t bsize;
114 	char *subopts, *optval;
115 
116 #if !defined(TEXT_DOMAIN)
117 #define	TEXT_DOMAIN "SYS_TEST"
118 #endif
119 	(void) textdomain(TEXT_DOMAIN);
120 
121 	progname = argv[0];
122 
123 	while ((opt = getopt(argc, argv, "o:")) != EOF) {
124 		switch (opt) {
125 		case 'o' :
126 			subopts = optarg;
127 			while (*subopts != '\0') {
128 				switch (getsubopt(&subopts,
129 					subopt_v, &optval)) {
130 				case ARG_OVERRIDE :
131 					override = 1;
132 					(void) fprintf(stdout,
133 					gettext("error checking off\n"));
134 					break;
135 				case ARG_NEW_PROMPT :
136 					if (optval == NULL) {
137 						usage();
138 					}
139 					if (strlen(optval) > 255) {
140 						(void) fprintf(stdout,
141 						gettext("prompt should be less"
142 						"than 255 bytes\n"));
143 						exit(1);
144 					}
145 					(void) strcpy(prompt, optval);
146 					break;
147 				case ARG_WR_ENABLED :
148 					openflg = O_RDWR;
149 					break;
150 				case ARG_USAGE :
151 				default :
152 					usage();
153 				}
154 			}
155 			break;
156 		default :
157 			usage();
158 		}
159 	}
160 
161 	if ((argc - optind) != 1) {	/* Should just have "special" left */
162 		usage();
163 	}
164 
165 	if (ud_init(-1, &udh) != 0) {
166 		(void) fprintf(stderr,
167 		gettext("udfs labelit: cannot initialize ud_lib\n"));
168 		exit(1);
169 	}
170 
171 	if ((fd = ud_open_dev(udh, argv[optind], openflg)) < 0) {
172 		perror("open");
173 		exit(1);
174 	}
175 
176 	if ((ret = ud_fill_udfs_info(udh)) != 0) {
177 		return (ret);
178 	}
179 
180 	if ((udh->udfs.flags & VALID_UDFS) == 0) {
181 		return (1);
182 	}
183 
184 	bsize = udh->udfs.lbsize;
185 	bmask = bsize - 1;
186 	l2d = 0;
187 	while ((bsize >> l2d) > DEV_BSIZE) {
188 		l2d++;
189 	}
190 	l2b = l2d + 9;
191 
192 	ricb_prn = udh->udfs.ricb_prn;
193 	ricb_loc = udh->udfs.ricb_loc;
194 	ricb_len = udh->udfs.ricb_len;
195 
196 	value = i_number = ud_xlate_to_daddr(udh, ricb_prn, ricb_loc);
197 
198 	init_buffers();
199 
200 	run_fsdb();
201 
202 	ud_fini(udh);
203 	(void) close(fd);
204 
205 	return (0);
206 }
207 
208 /*
209  * usage - print usage and exit
210  */
211 void
212 usage()
213 {
214 	(void) fprintf(stdout,
215 		gettext("usage:   %s [options] special\n"), progname);
216 	(void) fprintf(stdout,
217 		gettext("options:\n"));
218 	(void) fprintf(stdout,
219 		gettext("\t-o\tSpecify udfs filesystem sepcific options\n"));
220 	(void) fprintf(stdout,
221 		gettext("\t\tAvailable suboptions are:\n"));
222 	(void) fprintf(stdout,
223 		gettext("\t\t?\tdisplay usage\n"));
224 	(void) fprintf(stdout,
225 		gettext("\t\to\toverride some error conditions\n"));
226 	(void) fprintf(stdout,
227 		gettext("\t\tp\t\"string\" set prompt to string\n"));
228 	(void) fprintf(stdout,
229 		gettext("\t\tw\topen for write\n"));
230 	exit(1);
231 }
232 
233 #define	NBUF	10
234 static struct lbuf {
235 	struct lbuf	*fwd;
236 	struct lbuf	*back;
237 	int32_t		valid;
238 	char		*blkaddr;
239 	u_offset_t	blkno;
240 } lbuf[NBUF], bhdr;
241 
242 #define	INSERT(bp)	\
243 	{ \
244 		bp->back = &bhdr; \
245 		bp->fwd = bhdr.fwd; \
246 		bhdr.fwd->back = bp; \
247 		bhdr.fwd = bp; \
248 	}
249 
250 void
251 init_buffers()
252 {
253 	int32_t i;
254 	char *addr;
255 	struct lbuf *bp;
256 
257 	addr = malloc(NBUF * udh->udfs.lbsize);
258 	bhdr.fwd = bhdr.back = &bhdr;
259 	for (i = 0; i < NBUF; i++) {
260 		bp = &lbuf[i];
261 		bp->blkaddr = addr + i * udh->udfs.lbsize;
262 		bp->valid = 0;
263 		INSERT(bp);
264 	}
265 }
266 
267 char *
268 getblk(u_offset_t address)
269 {
270 	u_offset_t off, block;
271 	struct lbuf *bp;
272 
273 	off = address & ~bmask;
274 	block = address >> l2b;
275 	for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) {
276 		if (bp->valid && bp->blkno == block) {
277 			goto found;
278 		}
279 	}
280 	bp = bhdr.back;
281 	bp->blkno = block;
282 	bp->valid = 0;
283 	errno = 0;
284 	if (llseek(fd, off, SEEK_SET) != off) {
285 		(void) fprintf(stdout,
286 			gettext("Seek failed fd %x off %llx errno %x\n"),
287 			fd, off, errno);
288 		return (NULL);
289 	}
290 	errno = 0;
291 	if (read(fd, bp->blkaddr, udh->udfs.lbsize) != udh->udfs.lbsize) {
292 		(void) fprintf(stdout,
293 			gettext("Read failed fd %x off %llx errno %x\n"),
294 			fd, off, errno);
295 		return (NULL);
296 	}
297 	bp->valid = 1;
298 found:
299 	bp->back->fwd = bp->fwd;
300 	bp->fwd->back = bp->back;
301 	INSERT(bp);
302 	return (bp->blkaddr);
303 }
304 
305 
306 int32_t
307 putblk(caddr_t address)
308 {
309 	u_offset_t off;
310 	struct lbuf *bp;
311 
312 	if (openflg == O_RDONLY) {
313 		(void) fprintf(stdout,
314 			gettext("Not run with -w flag\n"));
315 		return (1);
316 	}
317 
318 	for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) {
319 		if (bp->valid && bp->blkaddr == address) {
320 			goto found;
321 		}
322 	}
323 	(void) fprintf(stdout,
324 		gettext("Could not find the buffer\n"));
325 	return (1);
326 
327 found:
328 	off = bp->blkno << l2b;
329 	if (llseek(fd, off, SEEK_SET) == off) {
330 		if (write(fd, bp->blkaddr, udh->udfs.lbsize) ==
331 			udh->udfs.lbsize) {
332 			return (0);
333 		}
334 		(void) fprintf(stdout,
335 			gettext("Write failed fd %x off %llx errno %x\n"),
336 			fd, off, errno);
337 	} else {
338 		(void) fprintf(stdout,
339 			gettext("Seek failed fd %x off %llx errno %x\n"),
340 			fd, off, errno);
341 	}
342 	return (1);
343 }
344 
345 void
346 inval_bufs()
347 {
348 	struct lbuf *bp;
349 
350 	for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd) {
351 		bp->valid = 0;
352 	}
353 }
354 
355 /*
356  * If addr == NULL then use id to print the desc
357  * other wise use addr to self identify the type of desc
358  */
359 void
360 print_desc(uint32_t addr, int32_t id)
361 {
362 	struct tag *tag;
363 	caddr_t baddr;
364 
365 	/*
366 	 * Read the block at addr
367 	 * find out the type of tag
368 	 * and print the descriptor
369 	 */
370 	if (addr != 0) {
371 		if ((baddr = getblk(addr & (~bmask))) == NULL) {
372 			(void) fprintf(stdout,
373 				gettext("Could not read block %x\n"),
374 				addr >> l2b);
375 		}
376 		/* LINTED */
377 		tag = (struct tag *)(baddr + (addr & bmask));
378 	} else {
379 		switch (id) {
380 			case AVD :
381 				/* LINTED */
382 				if ((tag = (struct tag *)getblk(
383 					udh->udfs.avdp_loc << l2b)) == NULL) {
384 					(void) fprintf(stdout,
385 					gettext("Could not read AVDP\n"));
386 				}
387 				break;
388 			case MVDS :
389 			case RVDS :
390 			case INTS :
391 				{
392 					uint32_t i, end;
393 
394 					if (id == MVDS) {
395 						i = udh->udfs.mvds_loc;
396 						end = i +
397 						(udh->udfs.mvds_len >> l2b);
398 					} else if (id == RVDS) {
399 						i = udh->udfs.rvds_loc;
400 						end = i +
401 						(udh->udfs.rvds_len >> l2b);
402 					} else {
403 						i = udh->udfs.lvid_loc;
404 						end = i +
405 						(udh->udfs.lvid_len >> l2b);
406 					}
407 
408 					for (; i < end; i++) {
409 						print_desc(i << l2b, 0);
410 					}
411 				}
412 				return;
413 			case FSDS :
414 			case ROOT :
415 				{
416 					uint16_t prn;
417 					uint32_t i, end, block;
418 
419 					if (id == FSDS) {
420 						prn = udh->udfs.fsds_prn;
421 						i = udh->udfs.fsds_loc;
422 						end = i +
423 						(udh->udfs.fsds_len >> l2b);
424 					} else {
425 						prn = ricb_prn;
426 						i = ricb_loc;
427 						end = i + (ricb_len >> l2b);
428 					}
429 
430 					for (; i < end; i++) {
431 						if ((block = ud_xlate_to_daddr(
432 							udh, prn, i)) == 0) {
433 							(void) fprintf(stdout,
434 							gettext("Cannot xlate "
435 							"prn %x loc %x\n"),
436 							prn, i);
437 							continue;
438 						}
439 						print_desc(block << l2b, 0);
440 					}
441 				}
442 				/* FALLTHROUGH */
443 			default :
444 				return;
445 		}
446 	}
447 
448 	switch (SWAP_16(tag->tag_id)) {
449 		case UD_PRI_VOL_DESC :
450 			print_pvd(stdout, (struct pri_vol_desc *)tag);
451 			break;
452 		case UD_ANCH_VOL_DESC :
453 			print_avd(stdout, (struct anch_vol_desc_ptr *)tag);
454 			break;
455 		case UD_VOL_DESC_PTR :
456 			print_vdp(stdout, (struct vol_desc_ptr *)tag);
457 			break;
458 		case UD_IMPL_USE_DESC :
459 			print_iuvd(stdout, (struct iuvd_desc *)tag);
460 			break;
461 		case UD_PART_DESC :
462 			print_part(stdout, (struct part_desc *)tag);
463 			break;
464 		case UD_LOG_VOL_DESC :
465 			print_lvd(stdout, (struct log_vol_desc *)tag);
466 			break;
467 		case UD_UNALL_SPA_DESC :
468 			print_usd(stdout, (struct unall_spc_desc *)tag);
469 			break;
470 		case UD_TERM_DESC :
471 			(void) fprintf(stdout, "TERM DESC\n");
472 			print_tag(stdout, tag);
473 			break;
474 		case UD_LOG_VOL_INT :
475 			print_lvid(stdout, (struct log_vol_int_desc *)tag);
476 			break;
477 		case UD_FILE_SET_DESC :
478 			print_fsd(stdout, udh, (struct file_set_desc *)tag);
479 			break;
480 		case UD_FILE_ID_DESC :
481 			print_fid(stdout, (struct file_id *)tag);
482 			break;
483 		case UD_ALLOC_EXT_DESC :
484 			print_aed(stdout, (struct alloc_ext_desc *)tag);
485 			break;
486 		case UD_INDIRECT_ENT :
487 			print_ie(stdout, (struct indirect_entry *)tag);
488 			break;
489 		case UD_TERMINAL_ENT :
490 			print_td(stdout, (struct term_desc *)tag);
491 			break;
492 		case UD_FILE_ENTRY :
493 			print_fe(stdout, (struct file_entry *)tag);
494 			break;
495 		case UD_EXT_ATTR_HDR :
496 		case UD_UNALL_SPA_ENT :
497 		case UD_SPA_BMAP_DESC :
498 		case UD_PART_INT_DESC :
499 		case UD_EXT_FILE_ENT :
500 			break;
501 		default :
502 			(void) fprintf(stdout,
503 				gettext("unknown descriptor\n"));
504 			print_tag(stdout, tag);
505 			break;
506 	}
507 }
508 
509 void
510 set_file(int32_t id, uint32_t iloc, uint64_t value)
511 {
512 	uint8_t i8;
513 	uint16_t i16;
514 	uint32_t i32, block, ea_len, ea_off;
515 	uint64_t i64;
516 	struct file_entry *fe;
517 	struct dev_spec_ear *ds;
518 	struct attr_hdr *ah;
519 	struct ext_attr_hdr *eah;
520 
521 	/* LINTED */
522 	if ((fe = (struct file_entry *)getblk(iloc)) == NULL) {
523 		return;
524 	}
525 	if (ud_verify_tag(udh, &fe->fe_tag, UD_FILE_ENTRY,
526 			SWAP_32(fe->fe_tag.tag_loc), 1, 1) != 0) {
527 		return;
528 	}
529 	i8 = (uint8_t)value;
530 	i16 = SWAP_16(((uint16_t)value));
531 	i32 = SWAP_32(((uint32_t)value));
532 	i64 = SWAP_64(value);
533 	switch (id) {
534 		case ATTZ :
535 			fe->fe_acc_time.ts_tzone = i16;
536 			break;
537 		case ATYE  :
538 			fe->fe_acc_time.ts_year = i16;
539 			break;
540 		case ATMO  :
541 			fe->fe_acc_time.ts_month = i8;
542 			break;
543 		case ATDA  :
544 			fe->fe_acc_time.ts_day = i8;
545 			break;
546 		case ATHO  :
547 			fe->fe_acc_time.ts_hour = i8;
548 			break;
549 		case ATMI  :
550 			fe->fe_acc_time.ts_min = i8;
551 			break;
552 		case ATSE  :
553 			fe->fe_acc_time.ts_sec = i8;
554 			break;
555 		case ATCE  :
556 			fe->fe_acc_time.ts_csec = i8;
557 			break;
558 		case ATHU  :
559 			fe->fe_acc_time.ts_husec = i8;
560 			break;
561 		case ATMIC :
562 			fe->fe_acc_time.ts_usec = i8;
563 			break;
564 		case CTTZ  :
565 			fe->fe_attr_time.ts_tzone = i16;
566 			break;
567 		case CTYE  :
568 			fe->fe_attr_time.ts_year = i16;
569 			break;
570 		case CTMO  :
571 			fe->fe_attr_time.ts_month = i8;
572 			break;
573 		case CTDA  :
574 			fe->fe_attr_time.ts_day = i8;
575 			break;
576 		case CTHO  :
577 			fe->fe_attr_time.ts_hour = i8;
578 			break;
579 		case CTMI  :
580 			fe->fe_attr_time.ts_min = i8;
581 			break;
582 		case CTSE  :
583 			fe->fe_attr_time.ts_sec = i8;
584 			break;
585 		case CTCE  :
586 			fe->fe_attr_time.ts_csec = i8;
587 			break;
588 		case CTHU  :
589 			fe->fe_attr_time.ts_husec = i8;
590 			break;
591 		case CTMIC :
592 			fe->fe_attr_time.ts_usec = i8;
593 			break;
594 		case MTTZ  :
595 			fe->fe_mod_time.ts_tzone = i16;
596 			break;
597 		case MTYE  :
598 			fe->fe_mod_time.ts_year = i16;
599 			break;
600 		case MTMO  :
601 			fe->fe_mod_time.ts_month = i8;
602 			break;
603 		case MTDA  :
604 			fe->fe_mod_time.ts_day = i8;
605 			break;
606 		case MTHO  :
607 			fe->fe_mod_time.ts_hour = i8;
608 			break;
609 		case MTMI  :
610 			fe->fe_mod_time.ts_min = i8;
611 			break;
612 		case MTSE  :
613 			fe->fe_mod_time.ts_sec = i8;
614 			break;
615 		case MTCE  :
616 			fe->fe_mod_time.ts_csec = i8;
617 			break;
618 		case MTHU  :
619 			fe->fe_mod_time.ts_husec = i8;
620 			break;
621 		case MTMIC :
622 			fe->fe_mod_time.ts_usec = i8;
623 			break;
624 		case GID  :
625 			fe->fe_gid = i32;
626 			break;
627 		case LN  :
628 			fe->fe_lcount = i16;
629 			break;
630 		case MD  :
631 			fe->fe_perms = i32;
632 			break;
633 		case MAJ  :
634 		case MIO  :
635 			if ((fe->fe_icb_tag.itag_ftype != VBLK) &&
636 				(fe->fe_icb_tag.itag_ftype != VCHR)) {
637 				(void) fprintf(stdout,
638 					gettext("Not a device\n"));
639 				break;
640 			}
641 			/* LINTED */
642 			eah = (struct ext_attr_hdr *)fe->fe_spec;
643 			ea_off = SWAP_32(eah->eah_ial);
644 			ea_len = SWAP_32(fe->fe_len_ear);
645 			block = SWAP_32(eah->eah_tag.tag_loc);
646 			if (ea_len && (ud_verify_tag(udh, &eah->eah_tag,
647 				UD_EXT_ATTR_HDR, block, 1, 1) == 0)) {
648 				while (ea_off < ea_len) {
649 					/* LINTED */
650 					ah = (struct attr_hdr *)
651 						&fe->fe_spec[ea_off];
652 					if ((ah->ahdr_atype == SWAP_32(12)) &&
653 						(ah->ahdr_astype == 1)) {
654 
655 						ds = (struct dev_spec_ear *)ah;
656 						if (id == MAJ) {
657 							ds->ds_major_id = i32;
658 						} else {
659 							ds->ds_minor_id = i32;
660 						}
661 						ud_make_tag(udh, &eah->eah_tag,
662 							UD_EXT_ATTR_HDR, block,
663 						eah->eah_tag.tag_crc_len);
664 						break;
665 					}
666 				}
667 			}
668 			(void) fprintf(stdout,
669 			gettext("does not have a Device Specification EA\n"));
670 			break;
671 		case NM  :
672 			break;
673 		case SZ  :
674 			fe->fe_info_len = i64;
675 			break;
676 		case UID  :
677 			fe->fe_uid = i32;
678 			break;
679 		case UNIQ :
680 			fe->fe_uniq_id = i32;
681 			break;
682 		default :
683 			(void) fprintf(stdout,
684 				gettext("Unknown set\n"));
685 	}
686 	ud_make_tag(udh, &fe->fe_tag, UD_FILE_ENTRY,
687 		SWAP_32(fe->fe_tag.tag_loc), fe->fe_tag.tag_crc_len);
688 	(void) putblk((caddr_t)fe);
689 }
690 
691 caddr_t
692 verify_inode(uint32_t addr, uint32_t type)
693 {
694 	struct file_entry *fe;
695 	struct tag *tag;
696 
697 	/* LINTED */
698 	if ((tag = (struct tag *)getblk(addr & (~bmask))) == NULL) {
699 		(void) fprintf(stdout,
700 			gettext("Could not read block %x\n"),
701 			addr >> l2b);
702 	} else {
703 		if (ud_verify_tag(udh, tag, UD_FILE_ENTRY,
704 			addr >> l2b, 0, 1) != 0) {
705 			(void) fprintf(stdout,
706 				gettext("Not a file entry(inode) at %x\n"),
707 				addr >> l2b);
708 		} else {
709 			if (ud_verify_tag(udh, tag, UD_FILE_ENTRY,
710 				SWAP_32(tag->tag_loc), 1, 1) != 0) {
711 				(void) fprintf(stdout,
712 					gettext("CRC failed\n"));
713 			} else {
714 				fe = (struct file_entry *)tag;
715 				if ((type == 0) ||
716 					(type == fe->fe_icb_tag.itag_ftype)) {
717 					return ((caddr_t)tag);
718 				}
719 			}
720 		}
721 	}
722 	return (0);
723 }
724 
725 void
726 print_inode(uint32_t addr)
727 {
728 	if (verify_inode(addr, 0) != NULL) {
729 		print_desc(addr, 0);
730 	}
731 }
732 
733 int32_t
734 verify_dent(uint32_t i_addr, uint32_t nent)
735 {
736 	uint32_t ent = 0;
737 	uint64_t off = 0;
738 	uint8_t buf[1024];
739 	struct file_id *fid;
740 
741 	/* LINTED */
742 	fid = (struct file_id *)buf;
743 
744 	if (verify_inode(i_addr, 4) == 0) {
745 		(void) fprintf(stdout,
746 			gettext("Inode is not a directory\n"));
747 		return (1);
748 	}
749 
750 	while (get_fid(i_addr >> l2b, buf, off) == 0) {
751 		off += FID_LEN(fid);
752 		if (ent == nent) {
753 			return (0);
754 		}
755 		ent++;
756 	}
757 	(void) fprintf(stdout,
758 		gettext("Reached EOF\n"));
759 	return (1);
760 }
761 
762 void
763 print_dent(uint32_t i_addr, uint32_t nent)
764 {
765 	uint32_t ent = 0;
766 	uint64_t off = 0;
767 	uint8_t buf[1024];
768 	struct file_id *fid;
769 
770 	/* LINTED */
771 	fid = (struct file_id *)buf;
772 
773 	if (verify_dent(i_addr, nent) == 0) {
774 		while (get_fid(i_addr >> l2b, buf, off) == 0) {
775 			off += FID_LEN(fid);
776 			if (ent == nent) {
777 				print_fid(stdout, fid);
778 				return;
779 			}
780 			ent++;
781 		}
782 	}
783 }
784 
785 uint32_t in;
786 uint32_t de_count, ie_count;
787 struct ext {
788 	uint16_t prn;
789 	uint16_t flags;
790 	uint32_t blkno;
791 	uint32_t len;
792 } *de, *ie;
793 
794 int32_t
795 get_blkno(uint32_t inode, uint32_t *blkno, uint64_t off)
796 {
797 	struct file_entry *fe;
798 	int32_t i, d, nent;
799 	uint16_t prn, flags, elen;
800 	uint32_t desc_type, bno, len;
801 	struct short_ad *sad;
802 	struct long_ad *lad;
803 	uint64_t b_off, e_off;
804 
805 	if (inode != in) {
806 		/* LINTED */
807 		if ((fe = (struct file_entry *)
808 				getblk(inode << l2b)) == NULL) {
809 			(void) fprintf(stdout,
810 				gettext("Could not read block %x\n"),
811 				off & (~bmask));
812 			return (1);
813 		}
814 		desc_type = SWAP_16(fe->fe_icb_tag.itag_flags) & 0x7;
815 		sad = NULL;
816 		lad = NULL;
817 		if (desc_type == ICB_FLAG_SHORT_AD) {
818 			elen = sizeof (struct short_ad);
819 			/* LINTED */
820 			sad = (struct short_ad *)
821 				(fe->fe_spec + SWAP_32(fe->fe_len_ear));
822 		} else if (desc_type == ICB_FLAG_LONG_AD) {
823 			elen = sizeof (struct long_ad);
824 			/* LINTED */
825 			lad = (struct long_ad *)
826 				(fe->fe_spec + SWAP_32(fe->fe_len_ear));
827 		} else if (desc_type == ICB_FLAG_ONE_AD) {
828 			*blkno = inode;
829 			return (0);
830 		} else {
831 			/* This cannot happen return */
832 			return (EINVAL);
833 		}
834 
835 		nent = SWAP_32(fe->fe_len_adesc) / elen;
836 		de = malloc(nent * sizeof (struct ext));
837 		if (de == NULL) {
838 			(void) fprintf(stdout,
839 				gettext("could not allocate memeory\n"));
840 			return (1);
841 		}
842 		in = inode;
843 		de_count = nent;
844 		for (d = 0, i = 0; i < nent; i++) {
845 			switch (desc_type) {
846 			case ICB_FLAG_SHORT_AD:
847 				prn = 0;
848 				bno = SWAP_32(sad->sad_ext_loc);
849 				len = SWAP_32(sad->sad_ext_len);
850 				break;
851 			case ICB_FLAG_LONG_AD:
852 				prn = SWAP_16(lad->lad_ext_prn);
853 				bno = SWAP_32(lad->lad_ext_loc);
854 				len = SWAP_32(lad->lad_ext_len);
855 				break;
856 			default:
857 				prn = 0;
858 				bno = 0;
859 				len = 0;
860 			}
861 			flags = len >> 30;
862 			if (flags == 0x3) {
863 				(void) fprintf(stdout,
864 					gettext("Handle IE\n"));
865 			} else {
866 				de[d].prn = prn;
867 				de[d].flags = flags;
868 				de[d].blkno = bno;
869 				de[d].len = len & 0x3FFFFFFF;
870 				d++;
871 			}
872 		}
873 	}
874 
875 	b_off = 0;
876 	for (i = 0; i < de_count; i++) {
877 		e_off = b_off + de[i].len;
878 		if (off < e_off) {
879 			bno = de[i].blkno + ((off - b_off) >> l2b);
880 			if ((*blkno = ud_xlate_to_daddr(
881 					udh, de[i].prn, bno)) == 0) {
882 				return (1);
883 			}
884 			return (0);
885 		}
886 		b_off = e_off;
887 	}
888 	return (1);
889 }
890 
891 /*
892  * assume the buffer is big enough
893  * for the entire request
894  */
895 int32_t
896 read_file(uint32_t inode, uint8_t *buf, uint32_t count, uint64_t off)
897 {
898 	caddr_t addr;
899 	uint32_t bno, tcount;
900 
901 
902 	while (count) {
903 		if (get_blkno(inode, &bno, off) != 0) {
904 			return (1);
905 		}
906 		if ((addr = getblk(bno << l2b)) == NULL) {
907 			return (1);
908 		}
909 		if (bno == inode) {
910 			struct file_entry *fe;
911 			/*
912 			 * embedded file
913 			 */
914 			/* LINTED */
915 			fe = (struct file_entry *)addr;
916 			addr += 0xB0 + SWAP_32(fe->fe_len_ear);
917 			if (off >= SWAP_64(fe->fe_info_len)) {
918 				return (1);
919 			}
920 		}
921 		tcount = udh->udfs.lbsize - (off & bmask);
922 		if (tcount > count) {
923 			tcount = count;
924 		}
925 		addr += off & bmask;
926 		(void) memcpy(buf, addr, tcount);
927 		count -= tcount;
928 		buf += tcount;
929 		off += tcount;
930 	}
931 	return (0);
932 }
933 
934 int32_t
935 get_fid(uint32_t inode, uint8_t *buf, uint64_t off)
936 {
937 	struct file_id *fid;
938 
939 	/* LINTED */
940 	fid = (struct file_id *)buf;
941 	if ((read_file(inode, buf, sizeof (struct file_id), off)) != 0) {
942 		return (1);
943 	}
944 
945 	if (ud_verify_tag(udh, &fid->fid_tag, UD_FILE_ID_DESC, 0, 0, 1) != 0) {
946 		(void) fprintf(stdout,
947 			gettext("file_id tag does not verify off %llx\n"),
948 			off);
949 		return (1);
950 	}
951 
952 	if ((read_file(inode, buf, FID_LEN(fid), off)) != 0) {
953 		return (1);
954 	}
955 
956 	return (0);
957 }
958 
959 /*
960  * Path is absolute path
961  */
962 int32_t
963 inode_from_path(char *path, uint32_t *in, uint8_t *fl)
964 {
965 	char dname[1024];
966 	char fname[256];
967 	int32_t err;
968 	uint32_t dinode;
969 	struct tag *tag;
970 	uint8_t flags;
971 
972 	uint8_t buf[1024];
973 	uint64_t off;
974 	struct file_id *fid;
975 	uint8_t *addr;
976 
977 	if (strcmp(path, "/") == 0) {
978 		*fl = FID_DIR;
979 		if ((*in = ud_xlate_to_daddr(udh, ricb_prn, ricb_loc)) == 0) {
980 			return (1);
981 		}
982 		return (0);
983 	}
984 
985 	(void) strcpy(dname, path);
986 	(void) strcpy(fname, basename(dname));
987 	(void) dirname(dname);
988 
989 	if ((err = inode_from_path(dname, &dinode, &flags))  != 0) {
990 		return (1);
991 	}
992 
993 
994 	/*
995 	 * Check if dname is a directory
996 	 */
997 	if ((flags & FID_DIR) == 0) {
998 		(void) fprintf(stdout,
999 			gettext("Path %s is not a directory\n"), path);
1000 	}
1001 
1002 	/*
1003 	 * Search for the fname in the directory now
1004 	 */
1005 
1006 
1007 	off = 0;
1008 	/* LINTED */
1009 	fid = (struct file_id *)buf;
1010 	while (get_fid(dinode, buf, off) == 0) {
1011 		off += FID_LEN(fid);
1012 		if (fid->fid_flags & FID_DELETED) {
1013 			continue;
1014 		}
1015 		addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1];
1016 		if (fid->fid_flags & FID_PARENT) {
1017 			addr[0] = '.';
1018 			addr[1] = '.';
1019 			addr[2] = '\0';
1020 		} else {
1021 			addr[fid->fid_idlen] = '\0';
1022 		}
1023 		if (strcmp((caddr_t)addr, fname) == 0) {
1024 			*fl = fid->fid_flags;
1025 			if ((*in = ud_xlate_to_daddr(udh,
1026 				SWAP_16(fid->fid_icb.lad_ext_prn),
1027 				SWAP_32(fid->fid_icb.lad_ext_loc))) == 0) {
1028 				return (1);
1029 			}
1030 			/* LINTED */
1031 			if ((tag = (struct tag *)getblk(*in << l2b)) == NULL) {
1032 				(void) fprintf(stdout,
1033 					gettext("Could not read block %x\n"),
1034 					*in);
1035 				return (1);
1036 			}
1037 			if (ud_verify_tag(udh, tag, UD_FILE_ENTRY,
1038 					0, 0, 1) != 0) {
1039 				(void) fprintf(stdout,
1040 					gettext("Not a file entry(inode)"
1041 					" at %x\n"), *in);
1042 				return (1);
1043 			}
1044 			if (ud_verify_tag(udh, tag, UD_FILE_ENTRY,
1045 					SWAP_32(tag->tag_loc), 1, 1) != 0) {
1046 				(void) fprintf(stdout,
1047 					gettext("CRC failed\n"));
1048 				return (1);
1049 			}
1050 
1051 			return (0);
1052 		}
1053 	}
1054 	return (err);
1055 }
1056 
1057 struct recu_dir {
1058 	struct recu_dir *next;
1059 	uint32_t inode;
1060 	char *nm;
1061 };
1062 
1063 void
1064 list(char *nm, uint32_t in, uint32_t fl)
1065 {
1066 	uint8_t buf[1024];
1067 	uint64_t off;
1068 	struct file_id *fid;
1069 	struct recu_dir *rd, *erd, *temp;
1070 	uint32_t iloc;
1071 
1072 	rd = erd = temp = NULL;
1073 	if (verify_inode(in << l2b, 4) == 0) {
1074 		(void) fprintf(stdout,
1075 			gettext("Inode is not a directory\n"));
1076 		return;
1077 	}
1078 
1079 	if (fl & 2) {
1080 		(void) printf("\n");
1081 		if (fl & 1) {
1082 			(void) fprintf(stdout,
1083 				gettext("i#: %x\t"), in);
1084 		}
1085 		(void) printf("%s\n", nm);
1086 	}
1087 
1088 	off = 0;
1089 	/* LINTED */
1090 	fid = (struct file_id *)buf;
1091 	while (get_fid(in, buf, off) == 0) {
1092 		off += FID_LEN(fid);
1093 		if (fid->fid_flags & FID_DELETED) {
1094 			continue;
1095 		}
1096 		iloc = ud_xlate_to_daddr(udh, SWAP_16(fid->fid_icb.lad_ext_prn),
1097 				SWAP_32(fid->fid_icb.lad_ext_loc));
1098 		if (fl & 1) {
1099 			(void) fprintf(stdout,
1100 				gettext("i#: %x\t"), iloc);
1101 		}
1102 		if (fid->fid_flags & FID_PARENT) {
1103 			(void) fprintf(stdout,
1104 				gettext("..\n"));
1105 		} else {
1106 			int32_t i;
1107 			uint8_t *addr;
1108 
1109 			addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1];
1110 			for (i = 0; i < fid->fid_idlen - 1; i++)
1111 				(void) fprintf(stdout, "%c", addr[i]);
1112 			(void) fprintf(stdout, "\n");
1113 			if ((fid->fid_flags & FID_DIR) &&
1114 				(fl & 2)) {
1115 				temp = (struct recu_dir *)
1116 					malloc(sizeof (struct recu_dir));
1117 				if (temp == NULL) {
1118 					(void) fprintf(stdout,
1119 					gettext("Could not allocate memory\n"));
1120 				} else {
1121 					temp->next = NULL;
1122 					temp->inode = iloc;
1123 					temp->nm = malloc(strlen(nm) + 1 +
1124 						fid->fid_idlen + 1);
1125 					if (temp->nm != NULL) {
1126 						(void) strcpy(temp->nm, nm);
1127 						(void) strcat(temp->nm, "/");
1128 						(void) strncat(temp->nm,
1129 							(char *)addr,
1130 							fid->fid_idlen);
1131 					}
1132 					if (rd == NULL) {
1133 						erd = rd = temp;
1134 					} else {
1135 						erd->next = temp;
1136 						erd = temp;
1137 					}
1138 				}
1139 			}
1140 		}
1141 	}
1142 
1143 	while (rd != NULL) {
1144 		if (rd->nm != NULL) {
1145 			list(rd->nm, rd->inode, fl);
1146 		} else {
1147 			list(".", rd->inode, fl);
1148 		}
1149 		temp = rd;
1150 		rd = rd->next;
1151 		if (temp->nm) {
1152 			free(temp->nm);
1153 		}
1154 		free(temp);
1155 	}
1156 }
1157 
1158 void
1159 fill_pattern(uint32_t addr, uint32_t count, char *pattern)
1160 {
1161 	uint32_t beg, end, soff, lcount;
1162 	int32_t len = strlen(pattern);
1163 	caddr_t buf, p;
1164 
1165 	if (openflg == O_RDONLY) {
1166 		(void) fprintf(stdout,
1167 			gettext("Not run with -w flag\n"));
1168 		return;
1169 	}
1170 
1171 	if (count == 0) {
1172 		count = 1;
1173 	}
1174 	beg = addr;
1175 	end = addr + count * len;
1176 	soff = beg & (~bmask);
1177 	lcount = ((end + bmask) & (~bmask)) - soff;
1178 
1179 	inval_bufs();
1180 
1181 	buf = malloc(lcount);
1182 
1183 	if (llseek(fd, soff, SEEK_SET) != soff) {
1184 		(void) fprintf(stdout,
1185 			gettext("Seek failed fd %x off %llx errno %x\n"),
1186 			fd, soff, errno);
1187 		goto end;
1188 	}
1189 
1190 	if (read(fd, buf, lcount) != lcount) {
1191 		(void) fprintf(stdout,
1192 			gettext("Read failed fd %x off %llx errno %x\n"),
1193 			fd, soff, errno);
1194 		goto end;
1195 	}
1196 
1197 	p = buf + (addr & bmask);
1198 	while (count--) {
1199 		(void) strncpy(p, pattern, len);
1200 		p += len;
1201 	}
1202 
1203 	if (write(fd, buf, lcount) != lcount) {
1204 		(void) fprintf(stdout,
1205 			gettext("Write failed fd %x off %llx errno %x\n"),
1206 			fd, soff, errno);
1207 		goto end;
1208 	}
1209 end:
1210 	free(buf);
1211 }
1212 
1213 void
1214 dump_disk(uint32_t addr, uint32_t count, char *format)
1215 {
1216 	uint32_t beg, end, soff, lcount;
1217 	int32_t len, prperline, n;
1218 	uint8_t *buf, *p;
1219 	uint16_t *p_16;
1220 	uint32_t *p_32;
1221 
1222 	if (strlen(format) != 1) {
1223 		(void) fprintf(stdout,
1224 			gettext("Invalid command\n"));
1225 		return;
1226 	}
1227 	if (count == 0) {
1228 		count = 1;
1229 	}
1230 	switch (*format) {
1231 		case 'b' :
1232 			/* FALLTHROUGH */
1233 		case 'c' :
1234 			/* FALLTHROUGH */
1235 		case 'd' :
1236 			/* FALLTHROUGH */
1237 		case 'o' :
1238 			len = 1;
1239 			prperline = 16;
1240 			break;
1241 		case 'x' :
1242 			len = 2;
1243 			prperline = 8;
1244 			break;
1245 		case 'D' :
1246 			/* FALLTHROUGH */
1247 		case 'O' :
1248 			/* FALLTHROUGH */
1249 		case 'X' :
1250 			len = 4;
1251 			prperline = 4;
1252 			break;
1253 		default :
1254 			(void) fprintf(stdout,
1255 				gettext("Invalid format\n"));
1256 			return;
1257 	}
1258 
1259 	beg = addr;
1260 	end = addr + count * len;
1261 	soff = beg & (~bmask);
1262 	lcount = ((end + bmask) & (~bmask)) - soff;
1263 
1264 	inval_bufs();
1265 
1266 	buf = malloc(lcount);
1267 	if (llseek(fd, soff, SEEK_SET) != soff) {
1268 		(void) fprintf(stdout,
1269 			gettext("Seek failed fd %x off %llx errno %x\n"),
1270 			fd, soff, errno);
1271 		goto end;
1272 	}
1273 
1274 	if (read(fd, buf, lcount) != lcount) {
1275 		(void) fprintf(stdout,
1276 			gettext("Read failed fd %x off %llx errno %x\n"),
1277 			fd, soff, errno);
1278 		goto end;
1279 	}
1280 	p = buf + (addr & bmask);
1281 	/* LINTED */
1282 	p_16 = (uint16_t *)p;
1283 	/* LINTED */
1284 	p_32 = (uint32_t *)p;
1285 	n = 0;
1286 	while (n < count) {
1287 		switch (*format) {
1288 			case 'b' :
1289 				(void) fprintf(stdout,
1290 					"%4x ", *((uint8_t *)p));
1291 				break;
1292 			case 'c' :
1293 				(void) fprintf(stdout,
1294 					"%4c ", *((uint8_t *)p));
1295 				break;
1296 			case 'd' :
1297 				(void) fprintf(stdout,
1298 					"%4d ", *((uint8_t *)p));
1299 				break;
1300 			case 'o' :
1301 				(void) fprintf(stdout,
1302 					"%4o ", *((uint8_t *)p));
1303 				break;
1304 			case 'x' :
1305 				(void) fprintf(stdout,
1306 					"%8x ", *p_16);
1307 				break;
1308 			case 'D' :
1309 				(void) fprintf(stdout,
1310 					"%16d ", *p_32);
1311 				break;
1312 			case 'O' :
1313 				(void) fprintf(stdout,
1314 					"%16o ", *p_32);
1315 				break;
1316 			case 'X' :
1317 				(void) fprintf(stdout,
1318 					"%16x ", *p_32);
1319 				break;
1320 		}
1321 		p += len;
1322 		n++;
1323 		if ((n % prperline) == 0) {
1324 			(void) fprintf(stdout, "\n");
1325 		}
1326 	}
1327 	if (n % prperline) {
1328 		(void) fprintf(stdout, "\n");
1329 	}
1330 end:
1331 	free(buf);
1332 }
1333 
1334 void
1335 find_it(char *dir, char *name, uint32_t in, uint32_t fl)
1336 {
1337 	uint8_t buf[1024], *addr;
1338 	uint64_t off;
1339 	struct file_id *fid;
1340 	uint32_t iloc, d_in;
1341 	uint8_t d_fl;
1342 	struct recu_dir *rd, *erd, *temp;
1343 
1344 	rd = erd = temp = NULL;
1345 
1346 	if (inode_from_path(dir, &d_in, &d_fl) != 0) {
1347 		(void) fprintf(stdout,
1348 			gettext("Could not find directory %s"), dir);
1349 		return;
1350 	}
1351 
1352 	if ((d_fl & FID_DIR) == 0) {
1353 		(void) fprintf(stdout,
1354 			gettext("Path %s is not a directory\n"), dir);
1355 		return;
1356 	}
1357 
1358 	if (verify_inode(d_in << l2b, 4) == 0) {
1359 		(void) fprintf(stdout,
1360 			gettext("Inode is not a directory\n"));
1361 		return;
1362 	}
1363 
1364 	off = 0;
1365 	/* LINTED */
1366 	fid = (struct file_id *)buf;
1367 	while (get_fid(d_in, buf, off) == 0) {
1368 		off += FID_LEN(fid);
1369 		if ((fid->fid_flags & FID_DELETED) ||
1370 			(fid->fid_flags & FID_PARENT)) {
1371 			continue;
1372 		}
1373 
1374 		iloc = ud_xlate_to_daddr(udh, SWAP_16(fid->fid_icb.lad_ext_prn),
1375 				SWAP_32(fid->fid_icb.lad_ext_loc));
1376 		addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1];
1377 		if (((fl & 4) && (in == iloc)) ||
1378 		((fl & 2) && (strcmp(name, (char *)addr) == 0))) {
1379 			(void) printf("%s %x %s\n", dir, iloc, addr);
1380 		}
1381 
1382 		if (fid->fid_flags & FID_DIR) {
1383 			temp = (struct recu_dir *)
1384 				malloc(sizeof (struct recu_dir));
1385 			if (temp == NULL) {
1386 				(void) fprintf(stdout,
1387 				gettext("Could not allocate memory\n"));
1388 			} else {
1389 				temp->next = NULL;
1390 				temp->inode = iloc;
1391 				temp->nm = malloc(strlen(dir) + 1 +
1392 					fid->fid_idlen + 1);
1393 				if (temp->nm != NULL) {
1394 					(void) strcpy(temp->nm, dir);
1395 					(void) strcat(temp->nm, "/");
1396 					(void) strncat(temp->nm, (char *)addr,
1397 						fid->fid_idlen);
1398 				} else {
1399 					(void) fprintf(stdout, gettext(
1400 					"Could not allocate memory\n"));
1401 				}
1402 				if (rd == NULL) {
1403 					erd = rd = temp;
1404 				} else {
1405 					erd->next = temp;
1406 					erd = temp;
1407 				}
1408 			}
1409 		}
1410 	}
1411 
1412 	while (rd != NULL) {
1413 		if (rd->nm != NULL) {
1414 			find_it(rd->nm, name, in, fl);
1415 		}
1416 		temp = rd;
1417 		rd = rd->next;
1418 		if (temp->nm) {
1419 			free(temp->nm);
1420 		}
1421 		free(temp);
1422 	}
1423 }
1424