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