xref: /illumos-gate/usr/src/cmd/fs.d/udfs/fsdb/fsdb.c (revision 5801b0f01c3c34499a929ed96164a5a68b470945)
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 		if (desc_type == ICB_FLAG_SHORT_AD) {
816 			elen = sizeof (struct short_ad);
817 			/* LINTED */
818 			sad = (struct short_ad *)
819 				(fe->fe_spec + SWAP_32(fe->fe_len_ear));
820 		} else if (desc_type == ICB_FLAG_LONG_AD) {
821 			elen = sizeof (struct long_ad);
822 			/* LINTED */
823 			lad = (struct long_ad *)
824 				(fe->fe_spec + SWAP_32(fe->fe_len_ear));
825 		} else if (desc_type == ICB_FLAG_ONE_AD) {
826 			*blkno = inode;
827 			return (0);
828 		} else {
829 			/* This cannot happen return */
830 			return (EINVAL);
831 		}
832 
833 		nent = SWAP_32(fe->fe_len_adesc) / elen;
834 		de = malloc(nent * sizeof (struct ext));
835 		if (de == NULL) {
836 			(void) fprintf(stdout,
837 				gettext("could not allocate memeory\n"));
838 			return (1);
839 		}
840 		in = inode;
841 		de_count = nent;
842 		for (d = 0, i = 0; i < nent; i++) {
843 			if (desc_type == ICB_FLAG_SHORT_AD) {
844 				prn = 0;
845 				bno = SWAP_32(sad->sad_ext_loc);
846 				len = SWAP_32(sad->sad_ext_len);
847 			} else if (desc_type == ICB_FLAG_LONG_AD) {
848 				prn = SWAP_16(lad->lad_ext_prn);
849 				bno = SWAP_32(lad->lad_ext_loc);
850 				len = SWAP_32(lad->lad_ext_len);
851 			}
852 			flags = len >> 30;
853 			if (flags == 0x3) {
854 				(void) fprintf(stdout,
855 					gettext("Handle IE\n"));
856 			} else {
857 				de[d].prn = prn;
858 				de[d].flags = flags;
859 				de[d].blkno = bno;
860 				de[d].len = len & 0x3FFFFFFF;
861 				d++;
862 			}
863 		}
864 	}
865 
866 	b_off = 0;
867 	for (i = 0; i < de_count; i++) {
868 		e_off = b_off + de[i].len;
869 		if (off < e_off) {
870 			bno = de[i].blkno + ((off - b_off) >> l2b);
871 			if ((*blkno = ud_xlate_to_daddr(
872 					udh, de[i].prn, bno)) == 0) {
873 				return (1);
874 			}
875 			return (0);
876 		}
877 		b_off = e_off;
878 	}
879 	return (1);
880 }
881 
882 /*
883  * assume the buffer is big enough
884  * for the entire request
885  */
886 int32_t
887 read_file(uint32_t inode, uint8_t *buf, uint32_t count, uint64_t off)
888 {
889 	caddr_t addr;
890 	uint32_t bno, tcount;
891 
892 
893 	while (count) {
894 		if (get_blkno(inode, &bno, off) != 0) {
895 			return (1);
896 		}
897 		if ((addr = getblk(bno << l2b)) == NULL) {
898 			return (1);
899 		}
900 		if (bno == inode) {
901 			struct file_entry *fe;
902 			/*
903 			 * embedded file
904 			 */
905 			/* LINTED */
906 			fe = (struct file_entry *)addr;
907 			addr += 0xB0 + SWAP_32(fe->fe_len_ear);
908 			if (off >= SWAP_64(fe->fe_info_len)) {
909 				return (1);
910 			}
911 		}
912 		tcount = udh->udfs.lbsize - (off & bmask);
913 		if (tcount > count) {
914 			tcount = count;
915 		}
916 		addr += off & bmask;
917 		(void) memcpy(buf, addr, tcount);
918 		count -= tcount;
919 		buf += tcount;
920 		off += tcount;
921 	}
922 	return (0);
923 }
924 
925 int32_t
926 get_fid(uint32_t inode, uint8_t *buf, uint64_t off)
927 {
928 	struct file_id *fid;
929 
930 	/* LINTED */
931 	fid = (struct file_id *)buf;
932 	if ((read_file(inode, buf, sizeof (struct file_id), off)) != 0) {
933 		return (1);
934 	}
935 
936 	if (ud_verify_tag(udh, &fid->fid_tag, UD_FILE_ID_DESC, 0, 0, 1) != 0) {
937 		(void) fprintf(stdout,
938 			gettext("file_id tag does not verify off %llx\n"),
939 			off);
940 		return (1);
941 	}
942 
943 	if ((read_file(inode, buf, FID_LEN(fid), off)) != 0) {
944 		return (1);
945 	}
946 
947 	return (0);
948 }
949 
950 /*
951  * Path is absolute path
952  */
953 int32_t
954 inode_from_path(char *path, uint32_t *in, uint8_t *fl)
955 {
956 	char dname[1024];
957 	char fname[256];
958 	int32_t err;
959 	uint32_t dinode;
960 	struct tag *tag;
961 	uint8_t flags;
962 
963 	uint8_t buf[1024];
964 	uint64_t off;
965 	struct file_id *fid;
966 	uint8_t *addr;
967 
968 	if (strcmp(path, "/") == 0) {
969 		*fl = FID_DIR;
970 		if ((*in = ud_xlate_to_daddr(udh, ricb_prn, ricb_loc)) == 0) {
971 			return (1);
972 		}
973 		return (0);
974 	}
975 
976 	(void) strcpy(dname, path);
977 	(void) strcpy(fname, basename(dname));
978 	(void) dirname(dname);
979 
980 	if ((err = inode_from_path(dname, &dinode, &flags))  != 0) {
981 		return (1);
982 	}
983 
984 
985 	/*
986 	 * Check if dname is a directory
987 	 */
988 	if ((flags & FID_DIR) == 0) {
989 		(void) fprintf(stdout,
990 			gettext("Path %s is not a directory\n"), path);
991 	}
992 
993 	/*
994 	 * Search for the fname in the directory now
995 	 */
996 
997 
998 	off = 0;
999 	/* LINTED */
1000 	fid = (struct file_id *)buf;
1001 	while (get_fid(dinode, buf, off) == 0) {
1002 		off += FID_LEN(fid);
1003 		if (fid->fid_flags & FID_DELETED) {
1004 			continue;
1005 		}
1006 		addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1];
1007 		if (fid->fid_flags & FID_PARENT) {
1008 			addr[0] = '.';
1009 			addr[1] = '.';
1010 			addr[2] = '\0';
1011 		} else {
1012 			addr[fid->fid_idlen] = '\0';
1013 		}
1014 		if (strcmp((caddr_t)addr, fname) == 0) {
1015 			*fl = fid->fid_flags;
1016 			if ((*in = ud_xlate_to_daddr(udh,
1017 				SWAP_16(fid->fid_icb.lad_ext_prn),
1018 				SWAP_32(fid->fid_icb.lad_ext_loc))) == 0) {
1019 				return (1);
1020 			}
1021 			/* LINTED */
1022 			if ((tag = (struct tag *)getblk(*in << l2b)) == NULL) {
1023 				(void) fprintf(stdout,
1024 					gettext("Could not read block %x\n"),
1025 					*in);
1026 				return (1);
1027 			}
1028 			if (ud_verify_tag(udh, tag, UD_FILE_ENTRY,
1029 					0, 0, 1) != 0) {
1030 				(void) fprintf(stdout,
1031 					gettext("Not a file entry(inode)"
1032 					" at %x\n"), *in);
1033 				return (1);
1034 			}
1035 			if (ud_verify_tag(udh, tag, UD_FILE_ENTRY,
1036 					SWAP_32(tag->tag_loc), 1, 1) != 0) {
1037 				(void) fprintf(stdout,
1038 					gettext("CRC failed\n"));
1039 				return (1);
1040 			}
1041 
1042 			return (0);
1043 		}
1044 	}
1045 	return (err);
1046 }
1047 
1048 struct recu_dir {
1049 	struct recu_dir *next;
1050 	uint32_t inode;
1051 	char *nm;
1052 };
1053 
1054 void
1055 list(char *nm, uint32_t in, uint32_t fl)
1056 {
1057 	uint8_t buf[1024];
1058 	uint64_t off;
1059 	struct file_id *fid;
1060 	struct recu_dir *rd, *erd, *temp;
1061 	uint32_t iloc;
1062 
1063 	rd = erd = temp = NULL;
1064 	if (verify_inode(in << l2b, 4) == 0) {
1065 		(void) fprintf(stdout,
1066 			gettext("Inode is not a directory\n"));
1067 		return;
1068 	}
1069 
1070 	if (fl & 2) {
1071 		(void) printf("\n");
1072 		if (fl & 1) {
1073 			(void) fprintf(stdout,
1074 				gettext("i#: %x\t"), in);
1075 		}
1076 		(void) printf("%s\n", nm);
1077 	}
1078 
1079 	off = 0;
1080 	/* LINTED */
1081 	fid = (struct file_id *)buf;
1082 	while (get_fid(in, buf, off) == 0) {
1083 		off += FID_LEN(fid);
1084 		if (fid->fid_flags & FID_DELETED) {
1085 			continue;
1086 		}
1087 		iloc = ud_xlate_to_daddr(udh, SWAP_16(fid->fid_icb.lad_ext_prn),
1088 				SWAP_32(fid->fid_icb.lad_ext_loc));
1089 		if (fl & 1) {
1090 			(void) fprintf(stdout,
1091 				gettext("i#: %x\t"), iloc);
1092 		}
1093 		if (fid->fid_flags & FID_PARENT) {
1094 			(void) fprintf(stdout,
1095 				gettext("..\n"));
1096 		} else {
1097 			int32_t i;
1098 			uint8_t *addr;
1099 
1100 			addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1];
1101 			for (i = 0; i < fid->fid_idlen - 1; i++)
1102 				(void) fprintf(stdout, "%c", addr[i]);
1103 			(void) fprintf(stdout, "\n");
1104 			if ((fid->fid_flags & FID_DIR) &&
1105 				(fl & 2)) {
1106 				temp = (struct recu_dir *)
1107 					malloc(sizeof (struct recu_dir));
1108 				if (temp == NULL) {
1109 					(void) fprintf(stdout,
1110 					gettext("Could not allocate memory\n"));
1111 				} else {
1112 					temp->next = NULL;
1113 					temp->inode = iloc;
1114 					temp->nm = malloc(strlen(nm) + 1 +
1115 						fid->fid_idlen + 1);
1116 					if (temp->nm != NULL) {
1117 						(void) strcpy(temp->nm, nm);
1118 						(void) strcat(temp->nm, "/");
1119 						(void) strncat(temp->nm,
1120 							(char *)addr,
1121 							fid->fid_idlen);
1122 					}
1123 					if (rd == NULL) {
1124 						erd = rd = temp;
1125 					} else {
1126 						erd->next = temp;
1127 						erd = temp;
1128 					}
1129 				}
1130 			}
1131 		}
1132 	}
1133 
1134 	while (rd != NULL) {
1135 		if (rd->nm != NULL) {
1136 			list(rd->nm, rd->inode, fl);
1137 		} else {
1138 			list(".", rd->inode, fl);
1139 		}
1140 		temp = rd;
1141 		rd = rd->next;
1142 		if (temp->nm) {
1143 			free(temp->nm);
1144 		}
1145 		free(temp);
1146 	}
1147 }
1148 
1149 void
1150 fill_pattern(uint32_t addr, uint32_t count, char *pattern)
1151 {
1152 	uint32_t beg, end, soff, lcount;
1153 	int32_t len = strlen(pattern);
1154 	caddr_t buf, p;
1155 
1156 	if (openflg == O_RDONLY) {
1157 		(void) fprintf(stdout,
1158 			gettext("Not run with -w flag\n"));
1159 		return;
1160 	}
1161 
1162 	if (count == 0) {
1163 		count = 1;
1164 	}
1165 	beg = addr;
1166 	end = addr + count * len;
1167 	soff = beg & (~bmask);
1168 	lcount = ((end + bmask) & (~bmask)) - soff;
1169 
1170 	inval_bufs();
1171 
1172 	buf = malloc(lcount);
1173 
1174 	if (llseek(fd, soff, SEEK_SET) != soff) {
1175 		(void) fprintf(stdout,
1176 			gettext("Seek failed fd %x off %llx errno %x\n"),
1177 			fd, soff, errno);
1178 		goto end;
1179 	}
1180 
1181 	if (read(fd, buf, lcount) != lcount) {
1182 		(void) fprintf(stdout,
1183 			gettext("Read failed fd %x off %llx errno %x\n"),
1184 			fd, soff, errno);
1185 		goto end;
1186 	}
1187 
1188 	p = buf + (addr & bmask);
1189 	while (count--) {
1190 		(void) strncpy(p, pattern, len);
1191 		p += len;
1192 	}
1193 
1194 	if (write(fd, buf, lcount) != lcount) {
1195 		(void) fprintf(stdout,
1196 			gettext("Write failed fd %x off %llx errno %x\n"),
1197 			fd, soff, errno);
1198 		goto end;
1199 	}
1200 end:
1201 	free(buf);
1202 }
1203 
1204 void
1205 dump_disk(uint32_t addr, uint32_t count, char *format)
1206 {
1207 	uint32_t beg, end, soff, lcount;
1208 	int32_t len, prperline, n;
1209 	uint8_t *buf, *p;
1210 	uint16_t *p_16;
1211 	uint32_t *p_32;
1212 
1213 	if (strlen(format) != 1) {
1214 		(void) fprintf(stdout,
1215 			gettext("Invalid command\n"));
1216 		return;
1217 	}
1218 	if (count == 0) {
1219 		count = 1;
1220 	}
1221 	switch (*format) {
1222 		case 'b' :
1223 			/* FALLTHROUGH */
1224 		case 'c' :
1225 			/* FALLTHROUGH */
1226 		case 'd' :
1227 			/* FALLTHROUGH */
1228 		case 'o' :
1229 			len = 1;
1230 			prperline = 16;
1231 			break;
1232 		case 'x' :
1233 			len = 2;
1234 			prperline = 8;
1235 			break;
1236 		case 'D' :
1237 			/* FALLTHROUGH */
1238 		case 'O' :
1239 			/* FALLTHROUGH */
1240 		case 'X' :
1241 			len = 4;
1242 			prperline = 4;
1243 			break;
1244 		default :
1245 			(void) fprintf(stdout,
1246 				gettext("Invalid format\n"));
1247 			return;
1248 	}
1249 
1250 	beg = addr;
1251 	end = addr + count * len;
1252 	soff = beg & (~bmask);
1253 	lcount = ((end + bmask) & (~bmask)) - soff;
1254 
1255 	inval_bufs();
1256 
1257 	buf = malloc(lcount);
1258 	if (llseek(fd, soff, SEEK_SET) != soff) {
1259 		(void) fprintf(stdout,
1260 			gettext("Seek failed fd %x off %llx errno %x\n"),
1261 			fd, soff, errno);
1262 		goto end;
1263 	}
1264 
1265 	if (read(fd, buf, lcount) != lcount) {
1266 		(void) fprintf(stdout,
1267 			gettext("Read failed fd %x off %llx errno %x\n"),
1268 			fd, soff, errno);
1269 		goto end;
1270 	}
1271 	p = buf + (addr & bmask);
1272 	/* LINTED */
1273 	p_16 = (uint16_t *)p;
1274 	/* LINTED */
1275 	p_32 = (uint32_t *)p;
1276 	n = 0;
1277 	while (n < count) {
1278 		switch (*format) {
1279 			case 'b' :
1280 				(void) fprintf(stdout,
1281 					"%4x ", *((uint8_t *)p));
1282 				break;
1283 			case 'c' :
1284 				(void) fprintf(stdout,
1285 					"%4c ", *((uint8_t *)p));
1286 				break;
1287 			case 'd' :
1288 				(void) fprintf(stdout,
1289 					"%4d ", *((uint8_t *)p));
1290 				break;
1291 			case 'o' :
1292 				(void) fprintf(stdout,
1293 					"%4o ", *((uint8_t *)p));
1294 				break;
1295 			case 'x' :
1296 				(void) fprintf(stdout,
1297 					"%8x ", *p_16);
1298 				break;
1299 			case 'D' :
1300 				(void) fprintf(stdout,
1301 					"%16d ", *p_32);
1302 				break;
1303 			case 'O' :
1304 				(void) fprintf(stdout,
1305 					"%16o ", *p_32);
1306 				break;
1307 			case 'X' :
1308 				(void) fprintf(stdout,
1309 					"%16x ", *p_32);
1310 				break;
1311 		}
1312 		p += len;
1313 		n++;
1314 		if ((n % prperline) == 0) {
1315 			(void) fprintf(stdout, "\n");
1316 		}
1317 	}
1318 	if (n % prperline) {
1319 		(void) fprintf(stdout, "\n");
1320 	}
1321 end:
1322 	free(buf);
1323 }
1324 
1325 void
1326 find_it(char *dir, char *name, uint32_t in, uint32_t fl)
1327 {
1328 	uint8_t buf[1024], *addr;
1329 	uint64_t off;
1330 	struct file_id *fid;
1331 	uint32_t iloc, d_in;
1332 	uint8_t d_fl;
1333 	struct recu_dir *rd, *erd, *temp;
1334 
1335 	rd = erd = temp = NULL;
1336 
1337 	if (inode_from_path(dir, &d_in, &d_fl) != 0) {
1338 		(void) fprintf(stdout,
1339 			gettext("Could not find directory %s"), dir);
1340 		return;
1341 	}
1342 
1343 	if ((d_fl & FID_DIR) == 0) {
1344 		(void) fprintf(stdout,
1345 			gettext("Path %s is not a directory\n"), dir);
1346 		return;
1347 	}
1348 
1349 	if (verify_inode(d_in << l2b, 4) == 0) {
1350 		(void) fprintf(stdout,
1351 			gettext("Inode is not a directory\n"));
1352 		return;
1353 	}
1354 
1355 	off = 0;
1356 	/* LINTED */
1357 	fid = (struct file_id *)buf;
1358 	while (get_fid(d_in, buf, off) == 0) {
1359 		off += FID_LEN(fid);
1360 		if ((fid->fid_flags & FID_DELETED) ||
1361 			(fid->fid_flags & FID_PARENT)) {
1362 			continue;
1363 		}
1364 
1365 		iloc = ud_xlate_to_daddr(udh, SWAP_16(fid->fid_icb.lad_ext_prn),
1366 				SWAP_32(fid->fid_icb.lad_ext_loc));
1367 		addr = &fid->fid_spec[SWAP_16((fid)->fid_iulen) + 1];
1368 		if (((fl & 4) && (in == iloc)) ||
1369 		((fl & 2) && (strcmp(name, (char *)addr) == 0))) {
1370 			(void) printf("%s %x %s\n", dir, iloc, addr);
1371 		}
1372 
1373 		if (fid->fid_flags & FID_DIR) {
1374 			temp = (struct recu_dir *)
1375 				malloc(sizeof (struct recu_dir));
1376 			if (temp == NULL) {
1377 				(void) fprintf(stdout,
1378 				gettext("Could not allocate memory\n"));
1379 			} else {
1380 				temp->next = NULL;
1381 				temp->inode = iloc;
1382 				temp->nm = malloc(strlen(dir) + 1 +
1383 					fid->fid_idlen + 1);
1384 				if (temp->nm != NULL) {
1385 					(void) strcpy(temp->nm, dir);
1386 					(void) strcat(temp->nm, "/");
1387 					(void) strncat(temp->nm, (char *)addr,
1388 						fid->fid_idlen);
1389 				} else {
1390 					(void) fprintf(stdout, gettext(
1391 					"Could not allocate memory\n"));
1392 				}
1393 				if (rd == NULL) {
1394 					erd = rd = temp;
1395 				} else {
1396 					erd->next = temp;
1397 					erd = temp;
1398 				}
1399 			}
1400 		}
1401 	}
1402 
1403 	while (rd != NULL) {
1404 		if (rd->nm != NULL) {
1405 			find_it(rd->nm, name, in, fl);
1406 		}
1407 		temp = rd;
1408 		rd = rd->next;
1409 		if (temp->nm) {
1410 			free(temp->nm);
1411 		}
1412 		free(temp);
1413 	}
1414 }
1415