1 /*
2 * Copyright 2015 Gary Mills
3 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
4 */
5
6 /*
7 * Copyright (c) 1988 Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Computer Consoles Inc.
12 *
13 * Redistribution and use in source and binary forms are permitted
14 * provided that: (1) source distributions retain this entire copyright
15 * notice and comment, and (2) distributions including binaries display
16 * the following acknowledgement: ``This product includes software
17 * developed by the University of California, Berkeley and its contributors''
18 * in the documentation or other materials provided with the distribution
19 * and in all advertising materials mentioning features or use of this
20 * software. Neither the name of the University nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 */
27
28 #ifndef lint
29 char copyright[] =
30 "@(#) Copyright(c) 1988 Regents of the University of California.\n\
31 All rights reserved.\n";
32 #endif /* not lint */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)fsdb.c 5.8 (Berkeley) 6/1/90";
36 #endif /* not lint */
37
38 /*
39 * fsdb - file system debugger
40 *
41 * usage: fsdb [-o suboptions] special
42 * options/suboptions:
43 * -o
44 * ? display usage
45 * o override some error conditions
46 * p="string" set prompt to string
47 * w open for write
48 */
49
50 #include <sys/param.h>
51 #include <sys/signal.h>
52 #include <sys/file.h>
53 #include <inttypes.h>
54 #include <sys/sysmacros.h>
55 #include <sys/mkdev.h>
56
57 #ifdef sun
58 #include <unistd.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <fcntl.h>
62 #include <signal.h>
63 #include <sys/types.h>
64 #include <sys/vnode.h>
65 #include <sys/mntent.h>
66 #include <sys/wait.h>
67 #include <sys/fs/ufs_fsdir.h>
68 #include <sys/fs/ufs_fs.h>
69 #include <sys/fs/ufs_inode.h>
70 #include <sys/fs/ufs_acl.h>
71 #include <sys/fs/ufs_log.h>
72 #else
73 #include <sys/dir.h>
74 #include <ufs/fs.h>
75 #include <ufs/dinode.h>
76 #include <paths.h>
77 #endif /* sun */
78
79 #include <stdio.h>
80 #include <setjmp.h>
81
82 #define OLD_FSDB_COMPATIBILITY /* To support the obsoleted "-z" option */
83
84 #ifndef _PATH_BSHELL
85 #define _PATH_BSHELL "/bin/sh"
86 #endif /* _PATH_BSHELL */
87 /*
88 * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3
89 * file system.
90 */
91 #ifndef FS_42POSTBLFMT
92 #define cg_blktot(cgp) (((cgp))->cg_btot)
93 #define cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno])
94 #define cg_inosused(cgp) (((cgp))->cg_iused)
95 #define cg_blksfree(cgp) (((cgp))->cg_free)
96 #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC)
97 #endif
98
99 /*
100 * Never changing defines.
101 */
102 #define OCTAL 8 /* octal base */
103 #define DECIMAL 10 /* decimal base */
104 #define HEX 16 /* hexadecimal base */
105
106 /*
107 * Adjustable defines.
108 */
109 #define NBUF 10 /* number of cache buffers */
110 #define PROMPTSIZE 80 /* size of user definable prompt */
111 #define MAXFILES 40000 /* max number of files ls can handle */
112 #define FIRST_DEPTH 10 /* default depth for find and ls */
113 #define SECOND_DEPTH 100 /* second try at depth (maximum) */
114 #define INPUTBUFFER 1040 /* size of input buffer */
115 #define BYTESPERLINE 16 /* bytes per line of /dxo output */
116 #define NREG 36 /* number of save registers */
117
118 #define DEVPREFIX "/dev/" /* Uninteresting part of "special" */
119
120 #if defined(OLD_FSDB_COMPATIBILITY)
121 #define FSDB_OPTIONS "o:wp:z:"
122 #else
123 #define FSDB_OPTIONS "o:wp:"
124 #endif /* OLD_FSDB_COMPATIBILITY */
125
126
127 /*
128 * Values dependent on sizes of structs and such.
129 */
130 #define NUMB 3 /* these three are arbitrary, */
131 #define BLOCK 5 /* but must be different from */
132 #define FRAGMENT 7 /* the rest (hence odd). */
133 #define BITSPERCHAR 8 /* couldn't find it anywhere */
134 #define CHAR (sizeof (char))
135 #define SHORT (sizeof (short))
136 #define LONG (sizeof (long))
137 #define U_OFFSET_T (sizeof (u_offset_t)) /* essentially "long long" */
138 #define INODE (sizeof (struct dinode))
139 #define DIRECTORY (sizeof (struct direct))
140 #define CGRP (sizeof (struct cg))
141 #define SB (sizeof (struct fs))
142 #define BLKSIZE (fs->fs_bsize) /* for clarity */
143 #define FRGSIZE (fs->fs_fsize)
144 #define BLKSHIFT (fs->fs_bshift)
145 #define FRGSHIFT (fs->fs_fshift)
146 #define SHADOW_DATA (sizeof (struct ufs_fsd))
147
148 /*
149 * Messy macros that would otherwise clutter up such glamorous code.
150 */
151 #define itob(i) (((u_offset_t)itod(fs, (i)) << \
152 (u_offset_t)FRGSHIFT) + (u_offset_t)itoo(fs, (i)) * (u_offset_t)INODE)
153 #define min(x, y) ((x) < (y) ? (x) : (y))
154 #define STRINGSIZE(d) ((long)d->d_reclen - \
155 ((long)&d->d_name[0] - (long)&d->d_ino))
156 #define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\
157 (((c) >= 'A')&&((c) <= 'Z')))
158 #define digit(c) (((c) >= '0') && ((c) <= '9'))
159 #define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F'))
160 #define hexletter(c) (((c) >= 'a') && ((c) <= 'f'))
161 #define octaldigit(c) (((c) >= '0') && ((c) <= '7'))
162 #define uppertolower(c) ((c) - 'A' + 'a')
163 #define hextodigit(c) ((c) - 'a' + 10)
164 #define numtodigit(c) ((c) - '0')
165
166 #if !defined(loword)
167 #define loword(X) (((ushort_t *)&X)[1])
168 #endif /* loword */
169
170 #if !defined(lobyte)
171 #define lobyte(X) (((unsigned char *)&X)[1])
172 #endif /* lobyte */
173
174 /*
175 * buffer cache structure.
176 */
177 static struct lbuf {
178 struct lbuf *fwd;
179 struct lbuf *back;
180 char *blkaddr;
181 short valid;
182 u_offset_t blkno;
183 } lbuf[NBUF], bhdr;
184
185 /*
186 * used to hold save registers (see '<' and '>').
187 */
188 struct save_registers {
189 u_offset_t sv_addr;
190 u_offset_t sv_value;
191 long sv_objsz;
192 } regs[NREG];
193
194 /*
195 * cd, find, and ls use this to hold filenames. Each filename is broken
196 * up by a slash. In other words, /usr/src/adm would have a len field
197 * of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
198 * src, and adm components of the pathname.
199 */
200 static struct filenames {
201 ino_t ino; /* inode */
202 long len; /* number of components */
203 char flag; /* flag if using SECOND_DEPTH allocator */
204 char find; /* flag if found by find */
205 char **fname; /* hold components of pathname */
206 } *filenames, *top;
207
208 enum log_enum { LOG_NDELTAS, LOG_ALLDELTAS, LOG_CHECKSCAN };
209 #ifdef sun
210 struct fs *fs;
211 static union {
212 struct fs un_filesystem;
213 char un_sbsize[SBSIZE];
214 } fs_un;
215 #define filesystem fs_un.un_filesystem
216 #else
217 struct fs filesystem, *fs; /* super block */
218 #endif /* sun */
219
220 /*
221 * Global data.
222 */
223 static char *input_path[MAXPATHLEN];
224 static char *stack_path[MAXPATHLEN];
225 static char *current_path[MAXPATHLEN];
226 static char input_buffer[INPUTBUFFER];
227 static char *prompt;
228 static char *buffers;
229 static char scratch[64];
230 static char BASE[] = "o u x";
231 static char PROMPT[PROMPTSIZE];
232 static char laststyle = '/';
233 static char lastpo = 'x';
234 static short input_pointer;
235 static short current_pathp;
236 static short stack_pathp;
237 static short input_pathp;
238 static short cmp_level;
239 static int nfiles;
240 static short type = NUMB;
241 static short dirslot;
242 static short fd;
243 static short c_count;
244 static short error;
245 static short paren;
246 static short trapped;
247 static short doing_cd;
248 static short doing_find;
249 static short find_by_name;
250 static short find_by_inode;
251 static short long_list;
252 static short recursive;
253 static short objsz = SHORT;
254 static short override = 0;
255 static short wrtflag = O_RDONLY;
256 static short base = HEX;
257 static short acting_on_inode;
258 static short acting_on_directory;
259 static short should_print = 1;
260 static short clear;
261 static short star;
262 static u_offset_t addr;
263 static u_offset_t bod_addr;
264 static u_offset_t value;
265 static u_offset_t erraddr;
266 static long errcur_bytes;
267 static u_offset_t errino;
268 static long errinum;
269 static long cur_cgrp;
270 static u_offset_t cur_ino;
271 static long cur_inum;
272 static u_offset_t cur_dir;
273 static long cur_block;
274 static long cur_bytes;
275 static long find_ino;
276 static u_offset_t filesize;
277 static u_offset_t blocksize;
278 static long stringsize;
279 static long count = 1;
280 static long commands;
281 static long read_requests;
282 static long actual_disk_reads;
283 static jmp_buf env;
284 static long maxfiles;
285 static long cur_shad;
286
287 #ifndef sun
288 extern char *malloc(), *calloc();
289 #endif
290 static char getachar();
291 static char *getblk(), *fmtentry();
292
293 static offset_t get(short);
294 static long bmap();
295 static long expr();
296 static long term();
297 static long getnumb();
298 static u_offset_t getdirslot();
299 static unsigned long *print_check(unsigned long *, long *, short, int);
300
301 static void usage(char *);
302 static void ungetachar(char);
303 static void getnextinput();
304 static void eat_spaces();
305 static void restore_inode(ino_t);
306 static void find();
307 static void ls(struct filenames *, struct filenames *, short);
308 static void formatf(struct filenames *, struct filenames *);
309 static void parse();
310 static void follow_path(long, long);
311 static void getname();
312 static void freemem(struct filenames *, int);
313 static void print_path(char **, int);
314 static void fill();
315 static void put(u_offset_t, short);
316 static void insert(struct lbuf *);
317 static void puta();
318 static void fprnt(char, char);
319 static void index();
320 #ifdef _LARGEFILE64_SOURCE
321 static void printll
322 (u_offset_t value, int fieldsz, int digits, int lead);
323 #define print(value, fieldsz, digits, lead) \
324 printll((u_offset_t)value, fieldsz, digits, lead)
325 #else /* !_LARGEFILE64_SOURCE */
326 static void print(long value, int fieldsz, int digits, int lead);
327 #endif /* _LARGEFILE64_SOURCE */
328 static void printsb(struct fs *);
329 static void printcg(struct cg *);
330 static void pbits(unsigned char *, int);
331 static void old_fsdb(int, char *); /* For old fsdb functionality */
332
333 static int isnumber(char *);
334 static int icheck(u_offset_t);
335 static int cgrp_check(long);
336 static int valid_addr();
337 static int match(char *, int);
338 static int devcheck(short);
339 static int bcomp();
340 static int compare(char *, char *, short);
341 static int check_addr(short, short *, short *, short);
342 static int fcmp();
343 static int ffcmp();
344
345 static int getshadowslot(long);
346 static void getshadowdata(long *, int);
347 static void syncshadowscan(int);
348 static void log_display_header(void);
349 static void log_show(enum log_enum);
350
351 #ifdef sun
352 static void err();
353 #else
354 static int err();
355 #endif /* sun */
356
357 /* Suboption vector */
358 static char *subopt_v[] = {
359 #define OVERRIDE 0
360 "o",
361 #define NEW_PROMPT 1
362 "p",
363 #define WRITE_ENABLED 2
364 "w",
365 #define ALT_PROMPT 3
366 "prompt",
367 NULL
368 };
369
370 /*
371 * main - lines are read up to the unprotected ('\') newline and
372 * held in an input buffer. Characters may be read from the
373 * input buffer using getachar() and unread using ungetachar().
374 * Reading the whole line ahead allows the use of debuggers
375 * which would otherwise be impossible since the debugger
376 * and fsdb could not share stdin.
377 */
378
379 int
380 main(int argc, char *argv[])
381 {
382
383 char c, *cptr;
384 short i;
385 struct direct *dirp;
386 struct lbuf *bp;
387 char *progname;
388 volatile short colon;
389 short mode;
390 long temp;
391
392 /* Options/Suboptions processing */
393 int opt;
394 char *subopts;
395 char *optval;
396
397 /*
398 * The following are used to support the old fsdb functionality
399 * of clearing an inode. It's better to use 'clri'.
400 */
401 int inum; /* Inode number to clear */
402 char *special;
403
404 setbuf(stdin, NULL);
405 progname = argv[0];
406 prompt = &PROMPT[0];
407 /*
408 * Parse options.
409 */
410 while ((opt = getopt(argc, argv, FSDB_OPTIONS)) != EOF) {
411 switch (opt) {
412 #if defined(OLD_FSDB_COMPATIBILITY)
413 case 'z': /* Hack - Better to use clri */
414 (void) fprintf(stderr, "%s\n%s\n%s\n%s\n",
415 "Warning: The '-z' option of 'fsdb_ufs' has been declared obsolete",
416 "and may not be supported in a future version of Solaris.",
417 "While this functionality is currently still supported, the",
418 "recommended procedure to clear an inode is to use clri(1M).");
419 if (isnumber(optarg)) {
420 inum = atoi(optarg);
421 special = argv[optind];
422 /* Doesn't return */
423 old_fsdb(inum, special);
424 } else {
425 usage(progname);
426 exit(31+1);
427 }
428 /* Should exit() before here */
429 /*NOTREACHED*/
430 #endif /* OLD_FSDB_COMPATIBILITY */
431 case 'o':
432 /* UFS Specific Options */
433 subopts = optarg;
434 while (*subopts != '\0') {
435 switch (getsubopt(&subopts, subopt_v,
436 &optval)) {
437 case OVERRIDE:
438 printf("error checking off\n");
439 override = 1;
440 break;
441
442 /*
443 * Change the "-o prompt=foo" option to
444 * "-o p=foo" to match documentation.
445 * ALT_PROMPT continues support for the
446 * undocumented "-o prompt=foo" option so
447 * that we don't break anyone.
448 */
449 case NEW_PROMPT:
450 case ALT_PROMPT:
451 if (optval == NULL) {
452 (void) fprintf(stderr,
453 "No prompt string\n");
454 usage(progname);
455 }
456 (void) strncpy(PROMPT, optval,
457 PROMPTSIZE);
458 break;
459
460 case WRITE_ENABLED:
461 /* suitable for open */
462 wrtflag = O_RDWR;
463 break;
464
465 default:
466 usage(progname);
467 /* Should exit here */
468 }
469 }
470 break;
471
472 default:
473 usage(progname);
474 }
475 }
476
477 if ((argc - optind) != 1) { /* Should just have "special" left */
478 usage(progname);
479 }
480 special = argv[optind];
481
482 /*
483 * Unless it's already been set, the default prompt includes the
484 * name of the special device.
485 */
486 if (*prompt == NULL)
487 (void) sprintf(prompt, "%s > ", special);
488
489 /*
490 * Attempt to open the special file.
491 */
492 if ((fd = open(special, wrtflag)) < 0) {
493 perror(special);
494 exit(1);
495 }
496 /*
497 * Read in the super block and validate (not too picky).
498 */
499 if (llseek(fd, (offset_t)(SBLOCK * DEV_BSIZE), 0) == -1) {
500 perror(special);
501 exit(1);
502 }
503
504 #ifdef sun
505 if (read(fd, &filesystem, SBSIZE) != SBSIZE) {
506 printf("%s: cannot read superblock\n", special);
507 exit(1);
508 }
509 #else
510 if (read(fd, &filesystem, sizeof (filesystem)) != sizeof (filesystem)) {
511 printf("%s: cannot read superblock\n", special);
512 exit(1);
513 }
514 #endif /* sun */
515
516 fs = &filesystem;
517 if ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC)) {
518 if (!override) {
519 printf("%s: Bad magic number in file system\n",
520 special);
521 exit(1);
522 }
523
524 printf("WARNING: Bad magic number in file system. ");
525 printf("Continue? (y/n): ");
526 (void) fflush(stdout);
527 if (gets(input_buffer) == NULL) {
528 exit(1);
529 }
530
531 if (*input_buffer != 'y' && *input_buffer != 'Y') {
532 exit(1);
533 }
534 }
535
536 if ((fs->fs_magic == FS_MAGIC &&
537 (fs->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
538 fs->fs_version != UFS_VERSION_MIN)) ||
539 (fs->fs_magic == MTB_UFS_MAGIC &&
540 (fs->fs_version > MTB_UFS_VERSION_1 ||
541 fs->fs_version < MTB_UFS_VERSION_MIN))) {
542 if (!override) {
543 printf("%s: Unrecognized UFS version number: %d\n",
544 special, fs->fs_version);
545 exit(1);
546 }
547
548 printf("WARNING: Unrecognized UFS version number. ");
549 printf("Continue? (y/n): ");
550 (void) fflush(stdout);
551 if (gets(input_buffer) == NULL) {
552 exit(1);
553 }
554
555 if (*input_buffer != 'y' && *input_buffer != 'Y') {
556 exit(1);
557 }
558 }
559 #ifdef FS_42POSTBLFMT
560 if (fs->fs_postblformat == FS_42POSTBLFMT)
561 fs->fs_nrpos = 8;
562 #endif
563 printf("fsdb of %s %s -- last mounted on %s\n",
564 special,
565 (wrtflag == O_RDWR) ? "(Opened for write)" : "(Read only)",
566 &fs->fs_fsmnt[0]);
567 #ifdef sun
568 printf("fs_clean is currently set to ");
569 switch (fs->fs_clean) {
570
571 case FSACTIVE:
572 printf("FSACTIVE\n");
573 break;
574 case FSCLEAN:
575 printf("FSCLEAN\n");
576 break;
577 case FSSTABLE:
578 printf("FSSTABLE\n");
579 break;
580 case FSBAD:
581 printf("FSBAD\n");
582 break;
583 case FSSUSPEND:
584 printf("FSSUSPEND\n");
585 break;
586 case FSLOG:
587 printf("FSLOG\n");
588 break;
589 case FSFIX:
590 printf("FSFIX\n");
591 if (!override) {
592 printf("%s: fsck may be running on this file system\n",
593 special);
594 exit(1);
595 }
596
597 printf("WARNING: fsck may be running on this file system. ");
598 printf("Continue? (y/n): ");
599 (void) fflush(stdout);
600 if (gets(input_buffer) == NULL) {
601 exit(1);
602 }
603
604 if (*input_buffer != 'y' && *input_buffer != 'Y') {
605 exit(1);
606 }
607 break;
608 default:
609 printf("an unknown value (0x%x)\n", fs->fs_clean);
610 break;
611 }
612
613 if (fs->fs_state == (FSOKAY - fs->fs_time)) {
614 printf("fs_state consistent (fs_clean CAN be trusted)\n");
615 } else {
616 printf("fs_state inconsistent (fs_clean CAN'T trusted)\n");
617 }
618 #endif /* sun */
619 /*
620 * Malloc buffers and set up cache.
621 */
622 buffers = malloc(NBUF * BLKSIZE);
623 bhdr.fwd = bhdr.back = &bhdr;
624 for (i = 0; i < NBUF; i++) {
625 bp = &lbuf[i];
626 bp->blkaddr = buffers + (i * BLKSIZE);
627 bp->valid = 0;
628 insert(bp);
629 }
630 /*
631 * Malloc filenames structure. The space for the actual filenames
632 * is allocated as it needs it. We estimate the size based on the
633 * number of inodes(objects) in the filesystem and the number of
634 * directories. The number of directories are padded by 3 because
635 * each directory traversed during a "find" or "ls -R" needs 3
636 * entries.
637 */
638 maxfiles = (long)((((u_offset_t)fs->fs_ncg * (u_offset_t)fs->fs_ipg) -
639 (u_offset_t)fs->fs_cstotal.cs_nifree) +
640 ((u_offset_t)fs->fs_cstotal.cs_ndir * (u_offset_t)3));
641
642 filenames = (struct filenames *)calloc(maxfiles,
643 sizeof (struct filenames));
644 if (filenames == NULL) {
645 /*
646 * If we could not allocate memory for all of files
647 * in the filesystem then, back off to the old fixed
648 * value.
649 */
650 maxfiles = MAXFILES;
651 filenames = (struct filenames *)calloc(maxfiles,
652 sizeof (struct filenames));
653 if (filenames == NULL) {
654 printf("out of memory\n");
655 exit(1);
656 }
657 }
658
659 restore_inode(2);
660 /*
661 * Malloc a few filenames (needed by pwd for example).
662 */
663 for (i = 0; i < MAXPATHLEN; i++) {
664 input_path[i] = calloc(1, MAXNAMLEN);
665 stack_path[i] = calloc(1, MAXNAMLEN);
666 current_path[i] = calloc(1, MAXNAMLEN);
667 if (current_path[i] == NULL) {
668 printf("out of memory\n");
669 exit(1);
670 }
671 }
672 current_pathp = -1;
673
674 (void) signal(2, err);
675 (void) setjmp(env);
676
677 getnextinput();
678 /*
679 * Main loop and case statement. If an error condition occurs
680 * initialization and recovery is attempted.
681 */
682 for (;;) {
683 if (error) {
684 freemem(filenames, nfiles);
685 nfiles = 0;
686 c_count = 0;
687 count = 1;
688 star = 0;
689 error = 0;
690 paren = 0;
691 acting_on_inode = 0;
692 acting_on_directory = 0;
693 should_print = 1;
694 addr = erraddr;
695 cur_ino = errino;
696 cur_inum = errinum;
697 cur_bytes = errcur_bytes;
698 printf("?\n");
699 getnextinput();
700 if (error)
701 continue;
702 }
703 c_count++;
704
705 switch (c = getachar()) {
706
707 case '\n': /* command end */
708 freemem(filenames, nfiles);
709 nfiles = 0;
710 if (should_print && laststyle == '=') {
711 ungetachar(c);
712 goto calc;
713 }
714 if (c_count == 1) {
715 clear = 0;
716 should_print = 1;
717 erraddr = addr;
718 errino = cur_ino;
719 errinum = cur_inum;
720 errcur_bytes = cur_bytes;
721 switch (objsz) {
722 case DIRECTORY:
723 if ((addr = getdirslot(
724 (long)dirslot+1)) == 0)
725 should_print = 0;
726 if (error) {
727 ungetachar(c);
728 continue;
729 }
730 break;
731 case INODE:
732 cur_inum++;
733 addr = itob(cur_inum);
734 if (!icheck(addr)) {
735 cur_inum--;
736 should_print = 0;
737 }
738 break;
739 case CGRP:
740 case SB:
741 cur_cgrp++;
742 addr = cgrp_check(cur_cgrp);
743 if (addr == 0) {
744 cur_cgrp--;
745 continue;
746 }
747 break;
748 case SHADOW_DATA:
749 if ((addr = getshadowslot(
750 (long)cur_shad + 1)) == 0)
751 should_print = 0;
752 if (error) {
753 ungetachar(c);
754 continue;
755 }
756 break;
757 default:
758 addr += objsz;
759 cur_bytes += objsz;
760 if (valid_addr() == 0)
761 continue;
762 }
763 }
764 if (type == NUMB)
765 trapped = 0;
766 if (should_print)
767 switch (objsz) {
768 case DIRECTORY:
769 fprnt('?', 'd');
770 break;
771 case INODE:
772 fprnt('?', 'i');
773 if (!error)
774 cur_ino = addr;
775 break;
776 case CGRP:
777 fprnt('?', 'c');
778 break;
779 case SB:
780 fprnt('?', 's');
781 break;
782 case SHADOW_DATA:
783 fprnt('?', 'S');
784 break;
785 case CHAR:
786 case SHORT:
787 case LONG:
788 fprnt(laststyle, lastpo);
789 }
790 if (error) {
791 ungetachar(c);
792 continue;
793 }
794 c_count = colon = acting_on_inode = 0;
795 acting_on_directory = 0;
796 should_print = 1;
797 getnextinput();
798 if (error)
799 continue;
800 erraddr = addr;
801 errino = cur_ino;
802 errinum = cur_inum;
803 errcur_bytes = cur_bytes;
804 continue;
805
806 case '(': /* numeric expression or unknown command */
807 default:
808 colon = 0;
809 if (digit(c) || c == '(') {
810 ungetachar(c);
811 addr = expr();
812 type = NUMB;
813 value = addr;
814 continue;
815 }
816 printf("unknown command or bad syntax\n");
817 error++;
818 continue;
819
820 case '?': /* general print facilities */
821 case '/':
822 fprnt(c, getachar());
823 continue;
824
825 case ';': /* command separator and . */
826 case '\t':
827 case ' ':
828 case '.':
829 continue;
830
831 case ':': /* command indicator */
832 colon++;
833 commands++;
834 should_print = 0;
835 stringsize = 0;
836 trapped = 0;
837 continue;
838
839 case ',': /* count indicator */
840 colon = star = 0;
841 if ((c = getachar()) == '*') {
842 star = 1;
843 count = BLKSIZE;
844 } else {
845 ungetachar(c);
846 count = expr();
847 if (error)
848 continue;
849 if (!count)
850 count = 1;
851 }
852 clear = 0;
853 continue;
854
855 case '+': /* address addition */
856 colon = 0;
857 c = getachar();
858 ungetachar(c);
859 if (c == '\n')
860 temp = 1;
861 else {
862 temp = expr();
863 if (error)
864 continue;
865 }
866 erraddr = addr;
867 errcur_bytes = cur_bytes;
868 switch (objsz) {
869 case DIRECTORY:
870 addr = getdirslot((long)(dirslot + temp));
871 if (error)
872 continue;
873 break;
874 case INODE:
875 cur_inum += temp;
876 addr = itob(cur_inum);
877 if (!icheck(addr)) {
878 cur_inum -= temp;
879 continue;
880 }
881 break;
882 case CGRP:
883 case SB:
884 cur_cgrp += temp;
885 if ((addr = cgrp_check(cur_cgrp)) == 0) {
886 cur_cgrp -= temp;
887 continue;
888 }
889 break;
890 case SHADOW_DATA:
891 addr = getshadowslot((long)(cur_shad + temp));
892 if (error)
893 continue;
894 break;
895
896 default:
897 laststyle = '/';
898 addr += temp * objsz;
899 cur_bytes += temp * objsz;
900 if (valid_addr() == 0)
901 continue;
902 }
903 value = get(objsz);
904 continue;
905
906 case '-': /* address subtraction */
907 colon = 0;
908 c = getachar();
909 ungetachar(c);
910 if (c == '\n')
911 temp = 1;
912 else {
913 temp = expr();
914 if (error)
915 continue;
916 }
917 erraddr = addr;
918 errcur_bytes = cur_bytes;
919 switch (objsz) {
920 case DIRECTORY:
921 addr = getdirslot((long)(dirslot - temp));
922 if (error)
923 continue;
924 break;
925 case INODE:
926 cur_inum -= temp;
927 addr = itob(cur_inum);
928 if (!icheck(addr)) {
929 cur_inum += temp;
930 continue;
931 }
932 break;
933 case CGRP:
934 case SB:
935 cur_cgrp -= temp;
936 if ((addr = cgrp_check(cur_cgrp)) == 0) {
937 cur_cgrp += temp;
938 continue;
939 }
940 break;
941 case SHADOW_DATA:
942 addr = getshadowslot((long)(cur_shad - temp));
943 if (error)
944 continue;
945 break;
946 default:
947 laststyle = '/';
948 addr -= temp * objsz;
949 cur_bytes -= temp * objsz;
950 if (valid_addr() == 0)
951 continue;
952 }
953 value = get(objsz);
954 continue;
955
956 case '*': /* address multiplication */
957 colon = 0;
958 temp = expr();
959 if (error)
960 continue;
961 if (objsz != INODE && objsz != DIRECTORY)
962 laststyle = '/';
963 addr *= temp;
964 value = get(objsz);
965 continue;
966
967 case '%': /* address division */
968 colon = 0;
969 temp = expr();
970 if (error)
971 continue;
972 if (!temp) {
973 printf("divide by zero\n");
974 error++;
975 continue;
976 }
977 if (objsz != INODE && objsz != DIRECTORY)
978 laststyle = '/';
979 addr /= temp;
980 value = get(objsz);
981 continue;
982
983 case '=': { /* assignment operation */
984 short tbase;
985 calc:
986 tbase = base;
987
988 c = getachar();
989 if (c == '\n') {
990 ungetachar(c);
991 c = lastpo;
992 if (acting_on_inode == 1) {
993 if (c != 'o' && c != 'd' && c != 'x' &&
994 c != 'O' && c != 'D' && c != 'X') {
995 switch (objsz) {
996 case LONG:
997 c = lastpo = 'X';
998 break;
999 case SHORT:
1000 c = lastpo = 'x';
1001 break;
1002 case CHAR:
1003 c = lastpo = 'c';
1004 }
1005 }
1006 } else {
1007 if (acting_on_inode == 2)
1008 c = lastpo = 't';
1009 }
1010 } else if (acting_on_inode)
1011 lastpo = c;
1012 should_print = star = 0;
1013 count = 1;
1014 erraddr = addr;
1015 errcur_bytes = cur_bytes;
1016 switch (c) {
1017 case '"': /* character string */
1018 if (type == NUMB) {
1019 blocksize = BLKSIZE;
1020 filesize = BLKSIZE * 2;
1021 cur_bytes = blkoff(fs, addr);
1022 if (objsz == DIRECTORY ||
1023 objsz == INODE)
1024 lastpo = 'X';
1025 }
1026 puta();
1027 continue;
1028 case '+': /* =+ operator */
1029 temp = expr();
1030 value = get(objsz);
1031 if (!error)
1032 put(value+temp, objsz);
1033 continue;
1034 case '-': /* =- operator */
1035 temp = expr();
1036 value = get(objsz);
1037 if (!error)
1038 put(value-temp, objsz);
1039 continue;
1040 case 'b':
1041 case 'c':
1042 if (objsz == CGRP)
1043 fprnt('?', c);
1044 else
1045 fprnt('/', c);
1046 continue;
1047 case 'i':
1048 addr = cur_ino;
1049 fprnt('?', 'i');
1050 continue;
1051 case 's':
1052 fprnt('?', 's');
1053 continue;
1054 case 't':
1055 case 'T':
1056 laststyle = '=';
1057 printf("\t\t");
1058 {
1059 /*
1060 * Truncation is intentional so
1061 * ctime is happy.
1062 */
1063 time_t tvalue = (time_t)value;
1064 printf("%s", ctime(&tvalue));
1065 }
1066 continue;
1067 case 'o':
1068 base = OCTAL;
1069 goto otx;
1070 case 'd':
1071 if (objsz == DIRECTORY) {
1072 addr = cur_dir;
1073 fprnt('?', 'd');
1074 continue;
1075 }
1076 base = DECIMAL;
1077 goto otx;
1078 case 'x':
1079 base = HEX;
1080 otx:
1081 laststyle = '=';
1082 printf("\t\t");
1083 if (acting_on_inode)
1084 print(value & 0177777L, 12, -8, 0);
1085 else
1086 print(addr & 0177777L, 12, -8, 0);
1087 printf("\n");
1088 base = tbase;
1089 continue;
1090 case 'O':
1091 base = OCTAL;
1092 goto OTX;
1093 case 'D':
1094 base = DECIMAL;
1095 goto OTX;
1096 case 'X':
1097 base = HEX;
1098 OTX:
1099 laststyle = '=';
1100 printf("\t\t");
1101 if (acting_on_inode)
1102 print(value, 12, -8, 0);
1103 else
1104 print(addr, 12, -8, 0);
1105 printf("\n");
1106 base = tbase;
1107 continue;
1108 default: /* regular assignment */
1109 ungetachar(c);
1110 value = expr();
1111 if (error)
1112 printf("syntax error\n");
1113 else
1114 put(value, objsz);
1115 continue;
1116 }
1117 }
1118
1119 case '>': /* save current address */
1120 colon = 0;
1121 should_print = 0;
1122 c = getachar();
1123 if (!letter(c) && !digit(c)) {
1124 printf("invalid register specification, ");
1125 printf("must be letter or digit\n");
1126 error++;
1127 continue;
1128 }
1129 if (letter(c)) {
1130 if (c < 'a')
1131 c = uppertolower(c);
1132 c = hextodigit(c);
1133 } else
1134 c = numtodigit(c);
1135 regs[c].sv_addr = addr;
1136 regs[c].sv_value = value;
1137 regs[c].sv_objsz = objsz;
1138 continue;
1139
1140 case '<': /* restore saved address */
1141 colon = 0;
1142 should_print = 0;
1143 c = getachar();
1144 if (!letter(c) && !digit(c)) {
1145 printf("invalid register specification, ");
1146 printf("must be letter or digit\n");
1147 error++;
1148 continue;
1149 }
1150 if (letter(c)) {
1151 if (c < 'a')
1152 c = uppertolower(c);
1153 c = hextodigit(c);
1154 } else
1155 c = numtodigit(c);
1156 addr = regs[c].sv_addr;
1157 value = regs[c].sv_value;
1158 objsz = regs[c].sv_objsz;
1159 continue;
1160
1161 case 'a':
1162 if (colon)
1163 colon = 0;
1164 else
1165 goto no_colon;
1166 if (match("at", 2)) { /* access time */
1167 acting_on_inode = 2;
1168 should_print = 1;
1169 addr = (long)&((struct dinode *)
1170 (uintptr_t)cur_ino)->di_atime;
1171 value = get(LONG);
1172 type = NULL;
1173 continue;
1174 }
1175 goto bad_syntax;
1176
1177 case 'b':
1178 if (colon)
1179 colon = 0;
1180 else
1181 goto no_colon;
1182 if (match("block", 2)) { /* block conversion */
1183 if (type == NUMB) {
1184 value = addr;
1185 cur_bytes = 0;
1186 blocksize = BLKSIZE;
1187 filesize = BLKSIZE * 2;
1188 }
1189 addr = value << FRGSHIFT;
1190 bod_addr = addr;
1191 value = get(LONG);
1192 type = BLOCK;
1193 dirslot = 0;
1194 trapped++;
1195 continue;
1196 }
1197 if (match("bs", 2)) { /* block size */
1198 acting_on_inode = 1;
1199 should_print = 1;
1200 if (icheck(cur_ino) == 0)
1201 continue;
1202 addr = (long)&((struct dinode *)
1203 (uintptr_t)cur_ino)->di_blocks;
1204 value = get(LONG);
1205 type = NULL;
1206 continue;
1207 }
1208 if (match("base", 2)) { /* change/show base */
1209 showbase:
1210 if ((c = getachar()) == '\n') {
1211 ungetachar(c);
1212 printf("base =\t\t");
1213 switch (base) {
1214 case OCTAL:
1215 printf("OCTAL\n");
1216 continue;
1217 case DECIMAL:
1218 printf("DECIMAL\n");
1219 continue;
1220 case HEX:
1221 printf("HEX\n");
1222 continue;
1223 }
1224 }
1225 if (c != '=') {
1226 printf("missing '='\n");
1227 error++;
1228 continue;
1229 }
1230 value = expr();
1231 switch (value) {
1232 default:
1233 printf("invalid base\n");
1234 error++;
1235 break;
1236 case OCTAL:
1237 case DECIMAL:
1238 case HEX:
1239 base = (short)value;
1240 }
1241 goto showbase;
1242 }
1243 goto bad_syntax;
1244
1245 case 'c':
1246 if (colon)
1247 colon = 0;
1248 else
1249 goto no_colon;
1250 if (match("cd", 2)) { /* change directory */
1251 top = filenames - 1;
1252 eat_spaces();
1253 if ((c = getachar()) == '\n') {
1254 ungetachar(c);
1255 current_pathp = -1;
1256 restore_inode(2);
1257 continue;
1258 }
1259 ungetachar(c);
1260 temp = cur_inum;
1261 doing_cd = 1;
1262 parse();
1263 doing_cd = 0;
1264 if (nfiles != 1) {
1265 restore_inode((ino_t)temp);
1266 if (!error) {
1267 print_path(input_path,
1268 (int)input_pathp);
1269 if (nfiles == 0)
1270 printf(" not found\n");
1271 else
1272 printf(" ambiguous\n");
1273 error++;
1274 }
1275 continue;
1276 }
1277 restore_inode(filenames->ino);
1278 if ((mode = icheck(addr)) == 0)
1279 continue;
1280 if ((mode & IFMT) != IFDIR) {
1281 restore_inode((ino_t)temp);
1282 print_path(input_path,
1283 (int)input_pathp);
1284 printf(" not a directory\n");
1285 error++;
1286 continue;
1287 }
1288 for (i = 0; i <= top->len; i++)
1289 (void) strcpy(current_path[i],
1290 top->fname[i]);
1291 current_pathp = top->len;
1292 continue;
1293 }
1294 if (match("cg", 2)) { /* cylinder group */
1295 if (type == NUMB)
1296 value = addr;
1297 if (value > fs->fs_ncg - 1) {
1298 printf("maximum cylinder group is ");
1299 print(fs->fs_ncg - 1, 8, -8, 0);
1300 printf("\n");
1301 error++;
1302 continue;
1303 }
1304 type = objsz = CGRP;
1305 cur_cgrp = (long)value;
1306 addr = cgtod(fs, cur_cgrp) << FRGSHIFT;
1307 continue;
1308 }
1309 if (match("ct", 2)) { /* creation time */
1310 acting_on_inode = 2;
1311 should_print = 1;
1312 addr = (long)&((struct dinode *)
1313 (uintptr_t)cur_ino)->di_ctime;
1314 value = get(LONG);
1315 type = NULL;
1316 continue;
1317 }
1318 goto bad_syntax;
1319
1320 case 'd':
1321 if (colon)
1322 colon = 0;
1323 else
1324 goto no_colon;
1325 if (match("directory", 2)) { /* directory offsets */
1326 if (type == NUMB)
1327 value = addr;
1328 objsz = DIRECTORY;
1329 type = DIRECTORY;
1330 addr = (u_offset_t)getdirslot((long)value);
1331 continue;
1332 }
1333 if (match("db", 2)) { /* direct block */
1334 acting_on_inode = 1;
1335 should_print = 1;
1336 if (type == NUMB)
1337 value = addr;
1338 if (value >= NDADDR) {
1339 printf("direct blocks are 0 to ");
1340 print(NDADDR - 1, 0, 0, 0);
1341 printf("\n");
1342 error++;
1343 continue;
1344 }
1345 addr = cur_ino;
1346 if (!icheck(addr))
1347 continue;
1348 addr = (long)
1349 &((struct dinode *)(uintptr_t)cur_ino)->
1350 di_db[value];
1351 bod_addr = addr;
1352 cur_bytes = (value) * BLKSIZE;
1353 cur_block = (long)value;
1354 type = BLOCK;
1355 dirslot = 0;
1356 value = get(LONG);
1357 if (!value && !override) {
1358 printf("non existent block\n");
1359 error++;
1360 }
1361 continue;
1362 }
1363 goto bad_syntax;
1364
1365 case 'f':
1366 if (colon)
1367 colon = 0;
1368 else
1369 goto no_colon;
1370 if (match("find", 3)) { /* find command */
1371 find();
1372 continue;
1373 }
1374 if (match("fragment", 2)) { /* fragment conv. */
1375 if (type == NUMB) {
1376 value = addr;
1377 cur_bytes = 0;
1378 blocksize = FRGSIZE;
1379 filesize = FRGSIZE * 2;
1380 }
1381 if (min(blocksize, filesize) - cur_bytes >
1382 FRGSIZE) {
1383 blocksize = cur_bytes + FRGSIZE;
1384 filesize = blocksize * 2;
1385 }
1386 addr = value << FRGSHIFT;
1387 bod_addr = addr;
1388 value = get(LONG);
1389 type = FRAGMENT;
1390 dirslot = 0;
1391 trapped++;
1392 continue;
1393 }
1394 if (match("file", 4)) { /* access as file */
1395 acting_on_inode = 1;
1396 should_print = 1;
1397 if (type == NUMB)
1398 value = addr;
1399 addr = cur_ino;
1400 if ((mode = icheck(addr)) == 0)
1401 continue;
1402 if (!override) {
1403 switch (mode & IFMT) {
1404 case IFCHR:
1405 case IFBLK:
1406 printf("special device\n");
1407 error++;
1408 continue;
1409 }
1410 }
1411 if ((addr = (u_offset_t)
1412 (bmap((long)value) << FRGSHIFT)) == 0)
1413 continue;
1414 cur_block = (long)value;
1415 bod_addr = addr;
1416 type = BLOCK;
1417 dirslot = 0;
1418 continue;
1419 }
1420 if (match("fill", 4)) { /* fill */
1421 if (getachar() != '=') {
1422 printf("missing '='\n");
1423 error++;
1424 continue;
1425 }
1426 if (objsz == INODE || objsz == DIRECTORY ||
1427 objsz == SHADOW_DATA) {
1428 printf(
1429 "can't fill inode or directory\n");
1430 error++;
1431 continue;
1432 }
1433 fill();
1434 continue;
1435 }
1436 goto bad_syntax;
1437
1438 case 'g':
1439 if (colon)
1440 colon = 0;
1441 else
1442 goto no_colon;
1443 if (match("gid", 1)) { /* group id */
1444 acting_on_inode = 1;
1445 should_print = 1;
1446 addr = (long)&((struct dinode *)
1447 (uintptr_t)cur_ino)->di_gid;
1448 value = get(SHORT);
1449 type = NULL;
1450 continue;
1451 }
1452 goto bad_syntax;
1453
1454 case 'i':
1455 if (colon)
1456 colon = 0;
1457 else
1458 goto no_colon;
1459 if (match("inode", 2)) { /* i# to inode conversion */
1460 if (c_count == 2) {
1461 addr = cur_ino;
1462 value = get(INODE);
1463 type = NULL;
1464 laststyle = '=';
1465 lastpo = 'i';
1466 should_print = 1;
1467 continue;
1468 }
1469 if (type == NUMB)
1470 value = addr;
1471 addr = itob(value);
1472 if (!icheck(addr))
1473 continue;
1474 cur_ino = addr;
1475 cur_inum = (long)value;
1476 value = get(INODE);
1477 type = NULL;
1478 continue;
1479 }
1480 if (match("ib", 2)) { /* indirect block */
1481 acting_on_inode = 1;
1482 should_print = 1;
1483 if (type == NUMB)
1484 value = addr;
1485 if (value >= NIADDR) {
1486 printf("indirect blocks are 0 to ");
1487 print(NIADDR - 1, 0, 0, 0);
1488 printf("\n");
1489 error++;
1490 continue;
1491 }
1492 addr = (long)&((struct dinode *)(uintptr_t)
1493 cur_ino)->di_ib[value];
1494 cur_bytes = (NDADDR - 1) * BLKSIZE;
1495 temp = 1;
1496 for (i = 0; i < value; i++) {
1497 temp *= NINDIR(fs) * BLKSIZE;
1498 cur_bytes += temp;
1499 }
1500 type = BLOCK;
1501 dirslot = 0;
1502 value = get(LONG);
1503 if (!value && !override) {
1504 printf("non existent block\n");
1505 error++;
1506 }
1507 continue;
1508 }
1509 goto bad_syntax;
1510
1511 case 'l':
1512 if (colon)
1513 colon = 0;
1514 else
1515 goto no_colon;
1516 if (match("log_head", 8)) {
1517 log_display_header();
1518 should_print = 0;
1519 continue;
1520 }
1521 if (match("log_delta", 9)) {
1522 log_show(LOG_NDELTAS);
1523 should_print = 0;
1524 continue;
1525 }
1526 if (match("log_show", 8)) {
1527 log_show(LOG_ALLDELTAS);
1528 should_print = 0;
1529 continue;
1530 }
1531 if (match("log_chk", 7)) {
1532 log_show(LOG_CHECKSCAN);
1533 should_print = 0;
1534 continue;
1535 }
1536 if (match("log_otodb", 9)) {
1537 if (log_lodb((u_offset_t)addr, &temp)) {
1538 addr = temp;
1539 should_print = 1;
1540 laststyle = '=';
1541 } else
1542 error++;
1543 continue;
1544 }
1545 if (match("ls", 2)) { /* ls command */
1546 temp = cur_inum;
1547 recursive = long_list = 0;
1548 top = filenames - 1;
1549 for (;;) {
1550 eat_spaces();
1551 if ((c = getachar()) == '-') {
1552 if ((c = getachar()) == 'R') {
1553 recursive = 1;
1554 continue;
1555 } else if (c == 'l') {
1556 long_list = 1;
1557 } else {
1558 printf(
1559 "unknown option ");
1560 printf("'%c'\n", c);
1561 error++;
1562 break;
1563 }
1564 } else
1565 ungetachar(c);
1566 if ((c = getachar()) == '\n') {
1567 if (c_count != 2) {
1568 ungetachar(c);
1569 break;
1570 }
1571 }
1572 c_count++;
1573 ungetachar(c);
1574 parse();
1575 restore_inode((ino_t)temp);
1576 if (error)
1577 break;
1578 }
1579 recursive = 0;
1580 if (error || nfiles == 0) {
1581 if (!error) {
1582 print_path(input_path,
1583 (int)input_pathp);
1584 printf(" not found\n");
1585 }
1586 continue;
1587 }
1588 if (nfiles) {
1589 cmp_level = 0;
1590 qsort((char *)filenames, nfiles,
1591 sizeof (struct filenames), ffcmp);
1592 ls(filenames, filenames + (nfiles - 1), 0);
1593 } else {
1594 printf("no match\n");
1595 error++;
1596 }
1597 restore_inode((ino_t)temp);
1598 continue;
1599 }
1600 if (match("ln", 2)) { /* link count */
1601 acting_on_inode = 1;
1602 should_print = 1;
1603 addr = (long)&((struct dinode *)
1604 (uintptr_t)cur_ino)->di_nlink;
1605 value = get(SHORT);
1606 type = NULL;
1607 continue;
1608 }
1609 goto bad_syntax;
1610
1611 case 'm':
1612 if (colon)
1613 colon = 0;
1614 else
1615 goto no_colon;
1616 addr = cur_ino;
1617 if ((mode = icheck(addr)) == 0)
1618 continue;
1619 if (match("mt", 2)) { /* modification time */
1620 acting_on_inode = 2;
1621 should_print = 1;
1622 addr = (long)&((struct dinode *)
1623 (uintptr_t)cur_ino)->di_mtime;
1624 value = get(LONG);
1625 type = NULL;
1626 continue;
1627 }
1628 if (match("md", 2)) { /* mode */
1629 acting_on_inode = 1;
1630 should_print = 1;
1631 addr = (long)&((struct dinode *)
1632 (uintptr_t)cur_ino)->di_mode;
1633 value = get(SHORT);
1634 type = NULL;
1635 continue;
1636 }
1637 if (match("maj", 2)) { /* major device number */
1638 acting_on_inode = 1;
1639 should_print = 1;
1640 if (devcheck(mode))
1641 continue;
1642 addr = (uintptr_t)&((struct dinode *)(uintptr_t)
1643 cur_ino)->di_ordev;
1644 {
1645 long dvalue;
1646 dvalue = get(LONG);
1647 value = major(dvalue);
1648 }
1649 type = NULL;
1650 continue;
1651 }
1652 if (match("min", 2)) { /* minor device number */
1653 acting_on_inode = 1;
1654 should_print = 1;
1655 if (devcheck(mode))
1656 continue;
1657 addr = (uintptr_t)&((struct dinode *)(uintptr_t)
1658 cur_ino)->di_ordev;
1659 {
1660 long dvalue;
1661 dvalue = (long)get(LONG);
1662 value = minor(dvalue);
1663 }
1664 type = NULL;
1665 continue;
1666 }
1667 goto bad_syntax;
1668
1669 case 'n':
1670 if (colon)
1671 colon = 0;
1672 else
1673 goto no_colon;
1674 if (match("nm", 1)) { /* directory name */
1675 objsz = DIRECTORY;
1676 acting_on_directory = 1;
1677 cur_dir = addr;
1678 if ((cptr = getblk(addr)) == 0)
1679 continue;
1680 /*LINTED*/
1681 dirp = (struct direct *)(cptr+blkoff(fs, addr));
1682 stringsize = (long)dirp->d_reclen -
1683 ((long)&dirp->d_name[0] -
1684 (long)&dirp->d_ino);
1685 addr = (long)&((struct direct *)
1686 (uintptr_t)addr)->d_name[0];
1687 type = NULL;
1688 continue;
1689 }
1690 goto bad_syntax;
1691
1692 case 'o':
1693 if (colon)
1694 colon = 0;
1695 else
1696 goto no_colon;
1697 if (match("override", 1)) { /* override flip flop */
1698 override = !override;
1699 if (override)
1700 printf("error checking off\n");
1701 else
1702 printf("error checking on\n");
1703 continue;
1704 }
1705 goto bad_syntax;
1706
1707 case 'p':
1708 if (colon)
1709 colon = 0;
1710 else
1711 goto no_colon;
1712 if (match("pwd", 2)) { /* print working dir */
1713 print_path(current_path, (int)current_pathp);
1714 printf("\n");
1715 continue;
1716 }
1717 if (match("prompt", 2)) { /* change prompt */
1718 if ((c = getachar()) != '=') {
1719 printf("missing '='\n");
1720 error++;
1721 continue;
1722 }
1723 if ((c = getachar()) != '"') {
1724 printf("missing '\"'\n");
1725 error++;
1726 continue;
1727 }
1728 i = 0;
1729 prompt = &prompt[0];
1730 while ((c = getachar()) != '"' && c != '\n') {
1731 prompt[i++] = c;
1732 if (i >= PROMPTSIZE) {
1733 printf("string too long\n");
1734 error++;
1735 break;
1736 }
1737 }
1738 prompt[i] = '\0';
1739 continue;
1740 }
1741 goto bad_syntax;
1742
1743 case 'q':
1744 if (!colon)
1745 goto no_colon;
1746 if (match("quit", 1)) { /* quit */
1747 if ((c = getachar()) != '\n') {
1748 error++;
1749 continue;
1750 }
1751 exit(0);
1752 }
1753 goto bad_syntax;
1754
1755 case 's':
1756 if (colon)
1757 colon = 0;
1758 else
1759 goto no_colon;
1760 if (match("sb", 2)) { /* super block */
1761 if (c_count == 2) {
1762 cur_cgrp = -1;
1763 type = objsz = SB;
1764 laststyle = '=';
1765 lastpo = 's';
1766 should_print = 1;
1767 continue;
1768 }
1769 if (type == NUMB)
1770 value = addr;
1771 if (value > fs->fs_ncg - 1) {
1772 printf("maximum super block is ");
1773 print(fs->fs_ncg - 1, 8, -8, 0);
1774 printf("\n");
1775 error++;
1776 continue;
1777 }
1778 type = objsz = SB;
1779 cur_cgrp = (long)value;
1780 addr = cgsblock(fs, cur_cgrp) << FRGSHIFT;
1781 continue;
1782 }
1783 if (match("shadow", 2)) { /* shadow inode data */
1784 if (type == NUMB)
1785 value = addr;
1786 objsz = SHADOW_DATA;
1787 type = SHADOW_DATA;
1788 addr = getshadowslot(value);
1789 continue;
1790 }
1791 if (match("si", 2)) { /* shadow inode field */
1792 acting_on_inode = 1;
1793 should_print = 1;
1794 addr = (long)&((struct dinode *)
1795 (uintptr_t)cur_ino)->di_shadow;
1796 value = get(LONG);
1797 type = NULL;
1798 continue;
1799 }
1800
1801 if (match("sz", 2)) { /* file size */
1802 acting_on_inode = 1;
1803 should_print = 1;
1804 addr = (long)&((struct dinode *)
1805 (uintptr_t)cur_ino)->di_size;
1806 value = get(U_OFFSET_T);
1807 type = NULL;
1808 objsz = U_OFFSET_T;
1809 laststyle = '=';
1810 lastpo = 'X';
1811 continue;
1812 }
1813 goto bad_syntax;
1814
1815 case 'u':
1816 if (colon)
1817 colon = 0;
1818 else
1819 goto no_colon;
1820 if (match("uid", 1)) { /* user id */
1821 acting_on_inode = 1;
1822 should_print = 1;
1823 addr = (long)&((struct dinode *)
1824 (uintptr_t)cur_ino)->di_uid;
1825 value = get(SHORT);
1826 type = NULL;
1827 continue;
1828 }
1829 goto bad_syntax;
1830
1831 case 'F': /* buffer status (internal use only) */
1832 if (colon)
1833 colon = 0;
1834 else
1835 goto no_colon;
1836 for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
1837 printf("%8" PRIx64 " %d\n",
1838 bp->blkno, bp->valid);
1839 printf("\n");
1840 printf("# commands\t\t%ld\n", commands);
1841 printf("# read requests\t\t%ld\n", read_requests);
1842 printf("# actual disk reads\t%ld\n", actual_disk_reads);
1843 continue;
1844 no_colon:
1845 printf("a colon should precede a command\n");
1846 error++;
1847 continue;
1848 bad_syntax:
1849 printf("more letters needed to distinguish command\n");
1850 error++;
1851 continue;
1852 }
1853 }
1854 }
1855
1856 /*
1857 * usage - print usage and exit
1858 */
1859 static void
1860 usage(char *progname)
1861 {
1862 printf("usage: %s [options] special\n", progname);
1863 printf("options:\n");
1864 printf("\t-o Specify ufs filesystem sepcific options\n");
1865 printf(" Available suboptions are:\n");
1866 printf("\t\t? display usage\n");
1867 printf("\t\to override some error conditions\n");
1868 printf("\t\tp=\"string\" set prompt to string\n");
1869 printf("\t\tw open for write\n");
1870 exit(1);
1871 }
1872
1873 /*
1874 * getachar - get next character from input buffer.
1875 */
1876 static char
1877 getachar()
1878 {
1879 return (input_buffer[input_pointer++]);
1880 }
1881
1882 /*
1883 * ungetachar - return character to input buffer.
1884 */
1885 static void
1886 ungetachar(char c)
1887 {
1888 if (input_pointer == 0) {
1889 printf("internal problem maintaining input buffer\n");
1890 error++;
1891 return;
1892 }
1893 input_buffer[--input_pointer] = c;
1894 }
1895
1896 /*
1897 * getnextinput - display the prompt and read an input line.
1898 * An input line is up to 128 characters terminated by the newline
1899 * character. Handle overflow, shell escape, and eof.
1900 */
1901 static void
1902 getnextinput()
1903 {
1904 int i;
1905 char c;
1906 short pid, rpid;
1907 int retcode;
1908
1909 newline:
1910 i = 0;
1911 printf("%s", prompt);
1912 ignore_eol:
1913 while ((c = getc(stdin)) != '\n' && !(c == '!' && i == 0) &&
1914 !feof(stdin) && i <= INPUTBUFFER - 2)
1915 input_buffer[i++] = c;
1916 if (i > 0 && input_buffer[i - 1] == '\\') {
1917 input_buffer[i++] = c;
1918 goto ignore_eol;
1919 }
1920 if (feof(stdin)) {
1921 printf("\n");
1922 exit(0);
1923 }
1924 if (c == '!') {
1925 if ((pid = fork()) == 0) {
1926 (void) execl(_PATH_BSHELL, "sh", "-t", 0);
1927 error++;
1928 return;
1929 }
1930 while ((rpid = wait(&retcode)) != pid && rpid != -1)
1931 ;
1932 printf("!\n");
1933 goto newline;
1934 }
1935 if (c != '\n')
1936 printf("input truncated to 128 characters\n");
1937 input_buffer[i] = '\n';
1938 input_pointer = 0;
1939 }
1940
1941 /*
1942 * eat_spaces - read extraneous spaces.
1943 */
1944 static void
1945 eat_spaces()
1946 {
1947 char c;
1948
1949 while ((c = getachar()) == ' ')
1950 ;
1951 ungetachar(c);
1952 }
1953
1954 /*
1955 * restore_inode - set up all inode indicators so inum is now
1956 * the current inode.
1957 */
1958 static void
1959 restore_inode(ino_t inum)
1960 {
1961 errinum = cur_inum = inum;
1962 addr = errino = cur_ino = itob(inum);
1963 }
1964
1965 /*
1966 * match - return false if the input does not match string up to
1967 * upto letters. Then proceed to chew up extraneous letters.
1968 */
1969 static int
1970 match(char *string, int upto)
1971 {
1972 int i, length = strlen(string) - 1;
1973 char c;
1974 int save_upto = upto;
1975
1976 while (--upto) {
1977 string++;
1978 if ((c = getachar()) != *string) {
1979 for (i = save_upto - upto; i; i--) {
1980 ungetachar(c);
1981 c = *--string;
1982 }
1983 return (0);
1984 }
1985 length--;
1986 }
1987 while (length--) {
1988 string++;
1989 if ((c = getachar()) != *string) {
1990 ungetachar(c);
1991 return (1);
1992 }
1993 }
1994 return (1);
1995 }
1996
1997 /*
1998 * expr - expression evaluator. Will evaluate expressions from
1999 * left to right with no operator precedence. Parentheses may
2000 * be used.
2001 */
2002 static long
2003 expr()
2004 {
2005 long numb = 0, temp;
2006 char c;
2007
2008 numb = term();
2009 for (;;) {
2010 if (error)
2011 return (~0); /* error is set so value is ignored */
2012 c = getachar();
2013 switch (c) {
2014
2015 case '+':
2016 numb += term();
2017 continue;
2018
2019 case '-':
2020 numb -= term();
2021 continue;
2022
2023 case '*':
2024 numb *= term();
2025 continue;
2026
2027 case '%':
2028 temp = term();
2029 if (!temp) {
2030 printf("divide by zero\n");
2031 error++;
2032 return (~0);
2033 }
2034 numb /= temp;
2035 continue;
2036
2037 case ')':
2038 paren--;
2039 return (numb);
2040
2041 default:
2042 ungetachar(c);
2043 if (paren && !error) {
2044 printf("missing ')'\n");
2045 error++;
2046 }
2047 return (numb);
2048 }
2049 }
2050 }
2051
2052 /*
2053 * term - used by expression evaluator to get an operand.
2054 */
2055 static long
2056 term()
2057 {
2058 char c;
2059
2060 switch (c = getachar()) {
2061
2062 default:
2063 ungetachar(c);
2064 /*FALLTHRU*/
2065 case '+':
2066 return (getnumb());
2067
2068 case '-':
2069 return (-getnumb());
2070
2071 case '(':
2072 paren++;
2073 return (expr());
2074 }
2075 }
2076
2077 /*
2078 * getnumb - read a number from the input stream. A leading
2079 * zero signifies octal interpretation, a leading '0x'
2080 * signifies hexadecimal, and a leading '0t' signifies
2081 * decimal. If the first character is a character,
2082 * return an error.
2083 */
2084 static long
2085 getnumb()
2086 {
2087
2088 char c, savec;
2089 long number = 0, tbase, num;
2090 extern short error;
2091
2092 c = getachar();
2093 if (!digit(c)) {
2094 error++;
2095 ungetachar(c);
2096 return (-1);
2097 }
2098 if (c == '0') {
2099 tbase = OCTAL;
2100 if ((c = getachar()) == 'x')
2101 tbase = HEX;
2102 else if (c == 't')
2103 tbase = DECIMAL;
2104 else ungetachar(c);
2105 } else {
2106 tbase = base;
2107 ungetachar(c);
2108 }
2109 for (;;) {
2110 num = tbase;
2111 c = savec = getachar();
2112 if (HEXLETTER(c))
2113 c = uppertolower(c);
2114 switch (tbase) {
2115 case HEX:
2116 if (hexletter(c)) {
2117 num = hextodigit(c);
2118 break;
2119 }
2120 /*FALLTHRU*/
2121 case DECIMAL:
2122 if (digit(c))
2123 num = numtodigit(c);
2124 break;
2125 case OCTAL:
2126 if (octaldigit(c))
2127 num = numtodigit(c);
2128 }
2129 if (num == tbase)
2130 break;
2131 number = number * tbase + num;
2132 }
2133 ungetachar(savec);
2134 return (number);
2135 }
2136
2137 /*
2138 * find - the syntax is almost identical to the unix command.
2139 * find dir [-name pattern] [-inum number]
2140 * Note: only one of -name or -inum may be used at a time.
2141 * Also, the -print is not needed (implied).
2142 */
2143 static void
2144 find()
2145 {
2146 struct filenames *fn;
2147 char c;
2148 long temp;
2149 short mode;
2150
2151 eat_spaces();
2152 temp = cur_inum;
2153 top = filenames - 1;
2154 doing_cd = 1;
2155 parse();
2156 doing_cd = 0;
2157 if (nfiles != 1) {
2158 restore_inode((ino_t)temp);
2159 if (!error) {
2160 print_path(input_path, (int)input_pathp);
2161 if (nfiles == 0)
2162 printf(" not found\n");
2163 else
2164 printf(" ambiguous\n");
2165 error++;
2166 return;
2167 }
2168 }
2169 restore_inode(filenames->ino);
2170 freemem(filenames, nfiles);
2171 nfiles = 0;
2172 top = filenames - 1;
2173 if ((mode = icheck(addr)) == 0)
2174 return;
2175 if ((mode & IFMT) != IFDIR) {
2176 print_path(input_path, (int)input_pathp);
2177 printf(" not a directory\n");
2178 error++;
2179 return;
2180 }
2181 eat_spaces();
2182 if ((c = getachar()) != '-') {
2183 restore_inode((ino_t)temp);
2184 printf("missing '-'\n");
2185 error++;
2186 return;
2187 }
2188 find_by_name = find_by_inode = 0;
2189 c = getachar();
2190 if (match("name", 4)) {
2191 eat_spaces();
2192 find_by_name = 1;
2193 } else if (match("inum", 4)) {
2194 eat_spaces();
2195 find_ino = expr();
2196 if (error) {
2197 restore_inode((ino_t)temp);
2198 return;
2199 }
2200 while ((c = getachar()) != '\n')
2201 ;
2202 ungetachar(c);
2203 find_by_inode = 1;
2204 } else {
2205 restore_inode((ino_t)temp);
2206 printf("use -name or -inum with find\n");
2207 error++;
2208 return;
2209 }
2210 doing_find = 1;
2211 parse();
2212 doing_find = 0;
2213 if (error) {
2214 restore_inode((ino_t)temp);
2215 return;
2216 }
2217 for (fn = filenames; fn <= top; fn++) {
2218 if (fn->find == 0)
2219 continue;
2220 printf("i#: ");
2221 print(fn->ino, 12, -8, 0);
2222 print_path(fn->fname, (int)fn->len);
2223 printf("\n");
2224 }
2225 restore_inode((ino_t)temp);
2226 }
2227
2228 /*
2229 * ls - do an ls. Should behave exactly as ls(1).
2230 * Only -R and -l is supported and -l gives different results.
2231 */
2232 static void
2233 ls(struct filenames *fn0, struct filenames *fnlast, short level)
2234 {
2235 struct filenames *fn, *fnn;
2236
2237 fn = fn0;
2238 for (;;) {
2239 fn0 = fn;
2240 if (fn0->len) {
2241 cmp_level = level;
2242 qsort((char *)fn0, fnlast - fn0 + 1,
2243 sizeof (struct filenames), fcmp);
2244 }
2245 for (fnn = fn, fn++; fn <= fnlast; fnn = fn, fn++) {
2246 if (fnn->len != fn->len && level == fnn->len - 1)
2247 break;
2248 if (fnn->len == 0)
2249 continue;
2250 if (strcmp(fn->fname[level], fnn->fname[level]))
2251 break;
2252 }
2253 if (fn0->len && level != fn0->len - 1)
2254 ls(fn0, fnn, level + 1);
2255 else {
2256 if (fn0 != filenames)
2257 printf("\n");
2258 print_path(fn0->fname, (int)(fn0->len - 1));
2259 printf(":\n");
2260 if (fn0->len == 0)
2261 cmp_level = level;
2262 else
2263 cmp_level = level + 1;
2264 qsort((char *)fn0, fnn - fn0 + 1,
2265 sizeof (struct filenames), fcmp);
2266 formatf(fn0, fnn);
2267 nfiles -= fnn - fn0 + 1;
2268 }
2269 if (fn > fnlast)
2270 return;
2271 }
2272 }
2273
2274 /*
2275 * formatf - code lifted from ls.
2276 */
2277 static void
2278 formatf(struct filenames *fn0, struct filenames *fnlast)
2279 {
2280 struct filenames *fn;
2281 int width = 0, w, nentry = fnlast - fn0 + 1;
2282 int i, j, columns, lines;
2283 char *cp;
2284
2285 if (long_list) {
2286 columns = 1;
2287 } else {
2288 for (fn = fn0; fn <= fnlast; fn++) {
2289 int len = strlen(fn->fname[cmp_level]) + 2;
2290
2291 if (len > width)
2292 width = len;
2293 }
2294 width = (width + 8) &~ 7;
2295 columns = 80 / width;
2296 if (columns == 0)
2297 columns = 1;
2298 }
2299 lines = (nentry + columns - 1) / columns;
2300 for (i = 0; i < lines; i++) {
2301 for (j = 0; j < columns; j++) {
2302 fn = fn0 + j * lines + i;
2303 if (long_list) {
2304 printf("i#: ");
2305 print(fn->ino, 12, -8, 0);
2306 }
2307 if ((cp = fmtentry(fn)) == NULL) {
2308 printf("cannot read inode %ld\n", fn->ino);
2309 return;
2310 }
2311 printf("%s", cp);
2312 if (fn + lines > fnlast) {
2313 printf("\n");
2314 break;
2315 }
2316 w = strlen(cp);
2317 while (w < width) {
2318 w = (w + 8) &~ 7;
2319 (void) putchar('\t');
2320 }
2321 }
2322 }
2323 }
2324
2325 /*
2326 * fmtentry - code lifted from ls.
2327 */
2328 static char *
2329 fmtentry(struct filenames *fn)
2330 {
2331 static char fmtres[BUFSIZ];
2332 struct dinode *ip;
2333 char *cptr, *cp, *dp;
2334
2335 dp = &fmtres[0];
2336 for (cp = fn->fname[cmp_level]; *cp; cp++) {
2337 if (*cp < ' ' || *cp >= 0177)
2338 *dp++ = '?';
2339 else
2340 *dp++ = *cp;
2341 }
2342 addr = itob(fn->ino);
2343 if ((cptr = getblk(addr)) == 0)
2344 return (NULL);
2345 cptr += blkoff(fs, addr);
2346 /*LINTED*/
2347 ip = (struct dinode *)cptr;
2348 switch (ip->di_mode & IFMT) {
2349 case IFDIR:
2350 *dp++ = '/';
2351 break;
2352 case IFLNK:
2353 *dp++ = '@';
2354 break;
2355 case IFSOCK:
2356 *dp++ = '=';
2357 break;
2358 #ifdef IFIFO
2359 case IFIFO:
2360 *dp++ = 'p';
2361 break;
2362 #endif
2363 case IFCHR:
2364 case IFBLK:
2365 case IFREG:
2366 if (ip->di_mode & 0111)
2367 *dp++ = '*';
2368 else
2369 *dp++ = ' ';
2370 break;
2371 default:
2372 *dp++ = '?';
2373
2374 }
2375 *dp++ = 0;
2376 return (fmtres);
2377 }
2378
2379 /*
2380 * fcmp - routine used by qsort. Will sort first by name, then
2381 * then by pathname length if names are equal. Uses global
2382 * cmp_level to tell what component of the path name we are comparing.
2383 */
2384 static int
2385 fcmp(struct filenames *f1, struct filenames *f2)
2386 {
2387 int value;
2388
2389 if ((value = strcmp(f1->fname[cmp_level], f2->fname[cmp_level])))
2390 return (value);
2391 return (f1->len - f2->len);
2392 }
2393
2394 /*
2395 * ffcmp - routine used by qsort. Sort only by pathname length.
2396 */
2397 static int
2398 ffcmp(struct filenames *f1, struct filenames *f2)
2399 {
2400 return (f1->len - f2->len);
2401 }
2402
2403 /*
2404 * parse - set up the call to follow_path.
2405 */
2406 static void
2407 parse()
2408 {
2409 int i;
2410 char c;
2411
2412 stack_pathp = input_pathp = -1;
2413 if ((c = getachar()) == '/') {
2414 while ((c = getachar()) == '/')
2415 ;
2416 ungetachar(c);
2417 cur_inum = 2;
2418 c = getachar();
2419 if ((c == '\n') || ((doing_cd) && (c == ' '))) {
2420 ungetachar(c);
2421 if (doing_cd) {
2422 top++;
2423 top->ino = 2;
2424 top->len = -1;
2425 nfiles = 1;
2426 return;
2427 }
2428 } else
2429 ungetachar(c);
2430 } else {
2431 ungetachar(c);
2432 stack_pathp = current_pathp;
2433 if (!doing_find)
2434 input_pathp = current_pathp;
2435 for (i = 0; i <= current_pathp; i++) {
2436 if (!doing_find)
2437 (void) strcpy(input_path[i], current_path[i]);
2438 (void) strcpy(stack_path[i], current_path[i]);
2439 }
2440 }
2441 getname();
2442 follow_path((long)(stack_pathp + 1), cur_inum);
2443 }
2444
2445 /*
2446 * follow_path - called by cd, find, and ls.
2447 * input_path holds the name typed by the user.
2448 * stack_path holds the name at the current depth.
2449 */
2450 static void
2451 follow_path(long level, long inum)
2452 {
2453 struct direct *dirp;
2454 char **ccptr, *cptr;
2455 int i;
2456 struct filenames *tos, *bos, *fn, *fnn, *fnnn;
2457 long block;
2458 short mode;
2459
2460 tos = top + 1;
2461 restore_inode((ino_t)inum);
2462 if ((mode = icheck(addr)) == 0)
2463 return;
2464 if ((mode & IFMT) != IFDIR)
2465 return;
2466 block = cur_bytes = 0;
2467 while (cur_bytes < filesize) {
2468 if (block == 0 || bcomp(addr)) {
2469 error = 0;
2470 if ((addr = ((u_offset_t)bmap(block++) <<
2471 (u_offset_t)FRGSHIFT)) == 0)
2472 break;
2473 if ((cptr = getblk(addr)) == 0)
2474 break;
2475 cptr += blkoff(fs, addr);
2476 }
2477 /*LINTED*/
2478 dirp = (struct direct *)cptr;
2479 if (dirp->d_ino) {
2480 if (level > input_pathp || doing_find ||
2481 compare(input_path[level], &dirp->d_name[0], 1)) {
2482 if ((doing_find) &&
2483 ((strcmp(dirp->d_name, ".") == 0 ||
2484 strcmp(dirp->d_name, "..") == 0)))
2485 goto duplicate;
2486 if (++top - filenames >= maxfiles) {
2487 printf("too many files\n");
2488 error++;
2489 return;
2490 }
2491 top->fname = (char **)calloc(FIRST_DEPTH, sizeof (char **));
2492 top->flag = 0;
2493 if (top->fname == 0) {
2494 printf("out of memory\n");
2495 error++;
2496 return;
2497 }
2498 nfiles++;
2499 top->ino = dirp->d_ino;
2500 top->len = stack_pathp;
2501 top->find = 0;
2502 if (doing_find) {
2503 if (find_by_name) {
2504 if (compare(input_path[0], &dirp->d_name[0], 1))
2505 top->find = 1;
2506 } else if (find_by_inode)
2507 if (find_ino == dirp->d_ino)
2508 top->find = 1;
2509 }
2510 if (top->len + 1 >= FIRST_DEPTH && top->flag == 0) {
2511 ccptr = (char **)calloc(SECOND_DEPTH, sizeof (char **));
2512 if (ccptr == 0) {
2513 printf("out of memory\n");
2514 error++;
2515 return;
2516 }
2517 for (i = 0; i < FIRST_DEPTH; i++)
2518 ccptr[i] = top->fname[i];
2519 free((char *)top->fname);
2520 top->fname = ccptr;
2521 top->flag = 1;
2522 }
2523 if (top->len >= SECOND_DEPTH) {
2524 printf("maximum depth exceeded, try to cd lower\n");
2525 error++;
2526 return;
2527 }
2528 /*
2529 * Copy current depth.
2530 */
2531 for (i = 0; i <= stack_pathp; i++) {
2532 top->fname[i] = calloc(1, strlen(stack_path[i])+1);
2533 if (top->fname[i] == 0) {
2534 printf("out of memory\n");
2535 error++;
2536 return;
2537 }
2538 (void) strcpy(top->fname[i], stack_path[i]);
2539 }
2540 /*
2541 * Check for '.' or '..' typed.
2542 */
2543 if ((level <= input_pathp) &&
2544 (strcmp(input_path[level], ".") == 0 ||
2545 strcmp(input_path[level], "..") == 0)) {
2546 if (strcmp(input_path[level], "..") == 0 &&
2547 top->len >= 0) {
2548 free(top->fname[top->len]);
2549 top->len -= 1;
2550 }
2551 } else {
2552 /*
2553 * Check for duplicates.
2554 */
2555 if (!doing_cd && !doing_find) {
2556 for (fn = filenames; fn < top; fn++) {
2557 if (fn->ino == dirp->d_ino &&
2558 fn->len == stack_pathp + 1) {
2559 for (i = 0; i < fn->len; i++)
2560 if (strcmp(fn->fname[i], stack_path[i]))
2561 break;
2562 if (i != fn->len ||
2563 strcmp(fn->fname[i], dirp->d_name))
2564 continue;
2565 freemem(top, 1);
2566 if (top == filenames)
2567 top = NULL;
2568 else
2569 top--;
2570 nfiles--;
2571 goto duplicate;
2572 }
2573 }
2574 }
2575 top->len += 1;
2576 top->fname[top->len] = calloc(1,
2577 strlen(&dirp->d_name[0])+1);
2578 if (top->fname[top->len] == 0) {
2579 printf("out of memory\n");
2580 error++;
2581 return;
2582 }
2583 (void) strcpy(top->fname[top->len], &dirp->d_name[0]);
2584 }
2585 }
2586 }
2587 duplicate:
2588 addr += dirp->d_reclen;
2589 cptr += dirp->d_reclen;
2590 cur_bytes += dirp->d_reclen;
2591 }
2592 if (top < filenames)
2593 return;
2594 if ((doing_cd && level == input_pathp) ||
2595 (!recursive && !doing_find && level > input_pathp))
2596 return;
2597 bos = top;
2598 /*
2599 * Check newly added entries to determine if further expansion
2600 * is required.
2601 */
2602 for (fn = tos; fn <= bos; fn++) {
2603 /*
2604 * Avoid '.' and '..' if beyond input.
2605 */
2606 if ((recursive || doing_find) && (level > input_pathp) &&
2607 (strcmp(fn->fname[fn->len], ".") == 0 ||
2608 strcmp(fn->fname[fn->len], "..") == 0))
2609 continue;
2610 restore_inode(fn->ino);
2611 if ((mode = icheck(cur_ino)) == 0)
2612 return;
2613 if ((mode & IFMT) == IFDIR || level < input_pathp) {
2614 /*
2615 * Set up current depth, remove current entry and
2616 * continue recursion.
2617 */
2618 for (i = 0; i <= fn->len; i++)
2619 (void) strcpy(stack_path[i], fn->fname[i]);
2620 stack_pathp = fn->len;
2621 if (!doing_find &&
2622 (!recursive || (recursive && level <= input_pathp))) {
2623 /*
2624 * Remove current entry by moving others up.
2625 */
2626 freemem(fn, 1);
2627 fnn = fn;
2628 for (fnnn = fnn, fnn++; fnn <= top; fnnn = fnn, fnn++) {
2629 fnnn->ino = fnn->ino;
2630 fnnn->len = fnn->len;
2631 if (fnnn->len + 1 < FIRST_DEPTH) {
2632 fnnn->fname = (char **)calloc(FIRST_DEPTH,
2633 sizeof (char **));
2634 fnnn->flag = 0;
2635 } else if (fnnn->len < SECOND_DEPTH) {
2636 fnnn->fname = (char **)calloc(SECOND_DEPTH,
2637 sizeof (char **));
2638 fnnn->flag = 1;
2639 } else {
2640 printf("maximum depth exceeded, ");
2641 printf("try to cd lower\n");
2642 error++;
2643 return;
2644 }
2645 for (i = 0; i <= fnn->len; i++)
2646 fnnn->fname[i] = fnn->fname[i];
2647 }
2648 if (fn == tos)
2649 fn--;
2650 top--;
2651 bos--;
2652 nfiles--;
2653 }
2654 follow_path(level + 1, cur_inum);
2655 if (error)
2656 return;
2657 }
2658 }
2659 }
2660
2661 /*
2662 * getname - break up the pathname entered by the user into components.
2663 */
2664 static void
2665 getname()
2666 {
2667 int i;
2668 char c;
2669
2670 if ((c = getachar()) == '\n') {
2671 ungetachar(c);
2672 return;
2673 }
2674 ungetachar(c);
2675 input_pathp++;
2676 clear:
2677 for (i = 0; i < MAXNAMLEN; i++)
2678 input_path[input_pathp][i] = '\0';
2679 for (;;) {
2680 c = getachar();
2681 if (c == '\\') {
2682 if ((int)strlen(input_path[input_pathp]) + 1 >= MAXNAMLEN) {
2683 printf("maximum name length exceeded, ");
2684 printf("truncating\n");
2685 return;
2686 }
2687 input_path[input_pathp][strlen(input_path[input_pathp])] = c;
2688 input_path[input_pathp][strlen(input_path[input_pathp])] =
2689 getachar();
2690 continue;
2691 }
2692 if (c == ' ' || c == '\n') {
2693 ungetachar(c);
2694 return;
2695 }
2696 if (!doing_find && c == '/') {
2697 if (++input_pathp >= MAXPATHLEN) {
2698 printf("maximum path length exceeded, ");
2699 printf("truncating\n");
2700 input_pathp--;
2701 return;
2702 }
2703 goto clear;
2704 }
2705 if ((int)strlen(input_path[input_pathp]) >= MAXNAMLEN) {
2706 printf("maximum name length exceeded, truncating\n");
2707 return;
2708 }
2709 input_path[input_pathp][strlen(input_path[input_pathp])] = c;
2710 }
2711 }
2712
2713 /*
2714 * compare - check if a filename matches the pattern entered by the user.
2715 * Handles '*', '?', and '[]'.
2716 */
2717 static int
2718 compare(char *s1, char *s2, short at_start)
2719 {
2720 char c, *s;
2721
2722 s = s2;
2723 while ((c = *s1) != NULL) {
2724 if (c == '*') {
2725 if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
2726 return (0);
2727 if (*++s1 == 0)
2728 return (1);
2729 while (*s2) {
2730 if (compare(s1, s2, 0))
2731 return (1);
2732 if (error)
2733 return (0);
2734 s2++;
2735 }
2736 }
2737 if (*s2 == 0)
2738 return (0);
2739 if (c == '\\') {
2740 s1++;
2741 goto compare_chars;
2742 }
2743 if (c == '?') {
2744 if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
2745 return (0);
2746 s1++;
2747 s2++;
2748 continue;
2749 }
2750 if (c == '[') {
2751 s1++;
2752 if (*s2 >= *s1++) {
2753 if (*s1++ != '-') {
2754 printf("missing '-'\n");
2755 error++;
2756 return (0);
2757 }
2758 if (*s2 <= *s1++) {
2759 if (*s1++ != ']') {
2760 printf("missing ']'");
2761 error++;
2762 return (0);
2763 }
2764 s2++;
2765 continue;
2766 }
2767 }
2768 }
2769 compare_chars:
2770 if (*s1++ == *s2++)
2771 continue;
2772 else
2773 return (0);
2774 }
2775 if (*s1 == *s2)
2776 return (1);
2777 return (0);
2778 }
2779
2780 /*
2781 * freemem - free the memory allocated to the filenames structure.
2782 */
2783 static void
2784 freemem(struct filenames *p, int numb)
2785 {
2786 int i, j;
2787
2788 if (numb == 0)
2789 return;
2790 for (i = 0; i < numb; i++, p++) {
2791 for (j = 0; j <= p->len; j++)
2792 free(p->fname[j]);
2793 free((char *)p->fname);
2794 }
2795 }
2796
2797 /*
2798 * print_path - print the pathname held in p.
2799 */
2800 static void
2801 print_path(char *p[], int pntr)
2802 {
2803 int i;
2804
2805 printf("/");
2806 if (pntr >= 0) {
2807 for (i = 0; i < pntr; i++)
2808 printf("%s/", p[i]);
2809 printf("%s", p[pntr]);
2810 }
2811 }
2812
2813 /*
2814 * fill - fill a section with a value or string.
2815 * addr,count:fill=[value, "string"].
2816 */
2817 static void
2818 fill()
2819 {
2820 char *cptr;
2821 int i;
2822 short eof_flag, end = 0, eof = 0;
2823 long temp, tcount;
2824 u_offset_t taddr;
2825
2826 if (wrtflag == O_RDONLY) {
2827 printf("not opened for write '-w'\n");
2828 error++;
2829 return;
2830 }
2831 temp = expr();
2832 if (error)
2833 return;
2834 if ((cptr = getblk(addr)) == 0)
2835 return;
2836 if (type == NUMB)
2837 eof_flag = 0;
2838 else
2839 eof_flag = 1;
2840 taddr = addr;
2841 switch (objsz) {
2842 case LONG:
2843 addr &= ~(LONG - 1);
2844 break;
2845 case SHORT:
2846 addr &= ~(SHORT - 1);
2847 temp &= 0177777L;
2848 break;
2849 case CHAR:
2850 temp &= 0377;
2851 }
2852 cur_bytes -= taddr - addr;
2853 cptr += blkoff(fs, addr);
2854 tcount = check_addr(eof_flag, &end, &eof, 0);
2855 for (i = 0; i < tcount; i++) {
2856 switch (objsz) {
2857 case LONG:
2858 /*LINTED*/
2859 *(long *)cptr = temp;
2860 break;
2861 case SHORT:
2862 /*LINTED*/
2863 *(short *)cptr = temp;
2864 break;
2865 case CHAR:
2866 *cptr = temp;
2867 }
2868 cptr += objsz;
2869 }
2870 addr += (tcount - 1) * objsz;
2871 cur_bytes += (tcount - 1) * objsz;
2872 put((u_offset_t)temp, objsz);
2873 if (eof) {
2874 printf("end of file\n");
2875 error++;
2876 } else if (end) {
2877 printf("end of block\n");
2878 error++;
2879 }
2880 }
2881
2882 /*
2883 * get - read a byte, short or long from the file system.
2884 * The entire block containing the desired item is read
2885 * and the appropriate data is extracted and returned.
2886 */
2887 static offset_t
2888 get(short lngth)
2889 {
2890
2891 char *bptr;
2892 u_offset_t temp = addr;
2893
2894 objsz = lngth;
2895 if (objsz == INODE || objsz == SHORT)
2896 temp &= ~(SHORT - 1);
2897 else if (objsz == DIRECTORY || objsz == LONG || objsz == SHADOW_DATA)
2898 temp &= ~(LONG - 1);
2899 if ((bptr = getblk(temp)) == 0)
2900 return (-1);
2901 bptr += blkoff(fs, temp);
2902 switch (objsz) {
2903 case CHAR:
2904 return ((offset_t)*bptr);
2905 case SHORT:
2906 case INODE:
2907 /*LINTED*/
2908 return ((offset_t)(*(short *)bptr));
2909 case LONG:
2910 case DIRECTORY:
2911 case SHADOW_DATA:
2912 /*LINTED*/
2913 return ((offset_t)(*(long *)bptr));
2914 case U_OFFSET_T:
2915 /*LINTED*/
2916 return (*(offset_t *)bptr);
2917 }
2918 return (0);
2919 }
2920
2921 /*
2922 * cgrp_check - make sure that we don't bump the cylinder group
2923 * beyond the total number of cylinder groups or before the start.
2924 */
2925 static int
2926 cgrp_check(long cgrp)
2927 {
2928 if (cgrp < 0) {
2929 if (objsz == CGRP)
2930 printf("beginning of cylinder groups\n");
2931 else
2932 printf("beginning of super blocks\n");
2933 error++;
2934 return (0);
2935 }
2936 if (cgrp >= fs->fs_ncg) {
2937 if (objsz == CGRP)
2938 printf("end of cylinder groups\n");
2939 else
2940 printf("end of super blocks\n");
2941 error++;
2942 return (0);
2943 }
2944 if (objsz == CGRP)
2945 return (cgtod(fs, cgrp) << FRGSHIFT);
2946 else
2947 return (cgsblock(fs, cgrp) << FRGSHIFT);
2948 }
2949
2950 /*
2951 * icheck - make sure we can read the block containing the inode
2952 * and determine the filesize (0 if inode not allocated). Return
2953 * 0 if error otherwise return the mode.
2954 */
2955 int
2956 icheck(u_offset_t address)
2957 {
2958 char *cptr;
2959 struct dinode *ip;
2960
2961 if ((cptr = getblk(address)) == 0)
2962 return (0);
2963 cptr += blkoff(fs, address);
2964 /*LINTED*/
2965 ip = (struct dinode *)cptr;
2966 if ((ip->di_mode & IFMT) == 0) {
2967 if (!override) {
2968 printf("inode not allocated\n");
2969 error++;
2970 return (0);
2971 }
2972 blocksize = filesize = 0;
2973 } else {
2974 trapped++;
2975 filesize = ip->di_size;
2976 blocksize = filesize * 2;
2977 }
2978 return (ip->di_mode);
2979 }
2980
2981 /*
2982 * getdirslot - get the address of the directory slot desired.
2983 */
2984 static u_offset_t
2985 getdirslot(long slot)
2986 {
2987 char *cptr;
2988 struct direct *dirp;
2989 short i;
2990 char *string = &scratch[0];
2991 short bod = 0, mode, temp;
2992
2993 if (slot < 0) {
2994 slot = 0;
2995 bod++;
2996 }
2997 if (type != DIRECTORY) {
2998 if (type == BLOCK)
2999 string = "block";
3000 else
3001 string = "fragment";
3002 addr = bod_addr;
3003 if ((cptr = getblk(addr)) == 0)
3004 return (0);
3005 cptr += blkoff(fs, addr);
3006 cur_bytes = 0;
3007 /*LINTED*/
3008 dirp = (struct direct *)cptr;
3009 for (dirslot = 0; dirslot < slot; dirslot++) {
3010 /*LINTED*/
3011 dirp = (struct direct *)cptr;
3012 if (blocksize > filesize) {
3013 if (cur_bytes + (long)dirp->d_reclen >=
3014 filesize) {
3015 printf("end of file\n");
3016 erraddr = addr;
3017 errcur_bytes = cur_bytes;
3018 stringsize = STRINGSIZE(dirp);
3019 error++;
3020 return (addr);
3021 }
3022 } else {
3023 if (cur_bytes + (long)dirp->d_reclen >=
3024 blocksize) {
3025 printf("end of %s\n", string);
3026 erraddr = addr;
3027 errcur_bytes = cur_bytes;
3028 stringsize = STRINGSIZE(dirp);
3029 error++;
3030 return (addr);
3031 }
3032 }
3033 cptr += dirp->d_reclen;
3034 addr += dirp->d_reclen;
3035 cur_bytes += dirp->d_reclen;
3036 }
3037 if (bod) {
3038 if (blocksize > filesize)
3039 printf("beginning of file\n");
3040 else
3041 printf("beginning of %s\n", string);
3042 erraddr = addr;
3043 errcur_bytes = cur_bytes;
3044 error++;
3045 }
3046 stringsize = STRINGSIZE(dirp);
3047 return (addr);
3048 } else {
3049 addr = cur_ino;
3050 if ((mode = icheck(addr)) == 0)
3051 return (0);
3052 if (!override && (mode & IFDIR) == 0) {
3053 printf("inode is not a directory\n");
3054 error++;
3055 return (0);
3056 }
3057 temp = slot;
3058 i = cur_bytes = 0;
3059 for (;;) {
3060 if (i == 0 || bcomp(addr)) {
3061 error = 0;
3062 if ((addr = (bmap((long)i++) << FRGSHIFT)) == 0)
3063 break;
3064 if ((cptr = getblk(addr)) == 0)
3065 break;
3066 cptr += blkoff(fs, addr);
3067 }
3068 /*LINTED*/
3069 dirp = (struct direct *)cptr;
3070 value = dirp->d_ino;
3071 if (!temp--)
3072 break;
3073 if (cur_bytes + (long)dirp->d_reclen >= filesize) {
3074 printf("end of file\n");
3075 dirslot = slot - temp - 1;
3076 objsz = DIRECTORY;
3077 erraddr = addr;
3078 errcur_bytes = cur_bytes;
3079 stringsize = STRINGSIZE(dirp);
3080 error++;
3081 return (addr);
3082 }
3083 addr += dirp->d_reclen;
3084 cptr += dirp->d_reclen;
3085 cur_bytes += dirp->d_reclen;
3086 }
3087 dirslot = slot;
3088 objsz = DIRECTORY;
3089 if (bod) {
3090 printf("beginning of file\n");
3091 erraddr = addr;
3092 errcur_bytes = cur_bytes;
3093 error++;
3094 }
3095 stringsize = STRINGSIZE(dirp);
3096 return (addr);
3097 }
3098 }
3099
3100
3101 /*
3102 * getshadowslot - get the address of the shadow data desired
3103 */
3104 static int
3105 getshadowslot(long shadow)
3106 {
3107 struct ufs_fsd fsd;
3108 short bod = 0, mode;
3109 long taddr, tcurbytes;
3110
3111 if (shadow < 0) {
3112 shadow = 0;
3113 bod++;
3114 }
3115 if (type != SHADOW_DATA) {
3116 if (shadow < cur_shad) {
3117 printf("can't scan shadow data in reverse\n");
3118 error++;
3119 return (0);
3120 }
3121 } else {
3122 addr = cur_ino;
3123 if ((mode = icheck(addr)) == 0)
3124 return (0);
3125 if (!override && (mode & IFMT) != IFSHAD) {
3126 printf("inode is not a shadow\n");
3127 error++;
3128 return (0);
3129 }
3130 cur_bytes = 0;
3131 cur_shad = 0;
3132 syncshadowscan(1); /* force synchronization */
3133 }
3134
3135 for (; cur_shad < shadow; cur_shad++) {
3136 taddr = addr;
3137 tcurbytes = cur_bytes;
3138 getshadowdata((long *)&fsd, LONG + LONG);
3139 addr = taddr;
3140 cur_bytes = tcurbytes;
3141 if (cur_bytes + (long)fsd.fsd_size > filesize) {
3142 syncshadowscan(0);
3143 printf("end of file\n");
3144 erraddr = addr;
3145 errcur_bytes = cur_bytes;
3146 error++;
3147 return (addr);
3148 }
3149 addr += fsd.fsd_size;
3150 cur_bytes += fsd.fsd_size;
3151 syncshadowscan(0);
3152 }
3153 if (type == SHADOW_DATA)
3154 objsz = SHADOW_DATA;
3155 if (bod) {
3156 printf("beginning of file\n");
3157 erraddr = addr;
3158 errcur_bytes = cur_bytes;
3159 error++;
3160 }
3161 return (addr);
3162 }
3163
3164 static void
3165 getshadowdata(long *buf, int len)
3166 {
3167 long tfsd;
3168
3169 len /= LONG;
3170 for (tfsd = 0; tfsd < len; tfsd++) {
3171 buf[tfsd] = get(SHADOW_DATA);
3172 addr += LONG;
3173 cur_bytes += LONG;
3174 syncshadowscan(0);
3175 }
3176 }
3177
3178 static void
3179 syncshadowscan(int force)
3180 {
3181 long curblkoff;
3182 if (type == SHADOW_DATA && (force ||
3183 lblkno(fs, addr) != (bhdr.fwd)->blkno)) {
3184 curblkoff = blkoff(fs, cur_bytes);
3185 addr = bmap(lblkno(fs, cur_bytes)) << FRGSHIFT;
3186 addr += curblkoff;
3187 cur_bytes += curblkoff;
3188 (void) getblk(addr);
3189 objsz = SHADOW_DATA;
3190 }
3191 }
3192
3193
3194
3195 /*
3196 * putf - print a byte as an ascii character if possible.
3197 * The exceptions are tabs, newlines, backslashes
3198 * and nulls which are printed as the standard C
3199 * language escapes. Characters which are not
3200 * recognized are printed as \?.
3201 */
3202 static void
3203 putf(char c)
3204 {
3205
3206 if (c <= 037 || c >= 0177 || c == '\\') {
3207 printf("\\");
3208 switch (c) {
3209 case '\\':
3210 printf("\\");
3211 break;
3212 case '\t':
3213 printf("t");
3214 break;
3215 case '\n':
3216 printf("n");
3217 break;
3218 case '\0':
3219 printf("0");
3220 break;
3221 default:
3222 printf("?");
3223 }
3224 } else {
3225 printf("%c", c);
3226 printf(" ");
3227 }
3228 }
3229
3230 /*
3231 * put - write an item into the buffer for the current address
3232 * block. The value is checked to make sure that it will
3233 * fit in the size given without truncation. If successful,
3234 * the entire block is written back to the file system.
3235 */
3236 static void
3237 put(u_offset_t item, short lngth)
3238 {
3239
3240 char *bptr, *sbptr;
3241 long s_err, nbytes;
3242 long olditem;
3243
3244 if (wrtflag == O_RDONLY) {
3245 printf("not opened for write '-w'\n");
3246 error++;
3247 return;
3248 }
3249 objsz = lngth;
3250 if ((sbptr = getblk(addr)) == 0)
3251 return;
3252 bptr = sbptr + blkoff(fs, addr);
3253 switch (objsz) {
3254 case LONG:
3255 case DIRECTORY:
3256 /*LINTED*/
3257 olditem = *(long *)bptr;
3258 /*LINTED*/
3259 *(long *)bptr = item;
3260 break;
3261 case SHORT:
3262 case INODE:
3263 /*LINTED*/
3264 olditem = (long)*(short *)bptr;
3265 item &= 0177777L;
3266 /*LINTED*/
3267 *(short *)bptr = item;
3268 break;
3269 case CHAR:
3270 olditem = (long)*bptr;
3271 item &= 0377;
3272 *bptr = lobyte(loword(item));
3273 break;
3274 default:
3275 error++;
3276 return;
3277 }
3278 if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) {
3279 error++;
3280 printf("seek error : %" PRIx64 "\n", addr);
3281 return;
3282 }
3283 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
3284 error++;
3285 printf("write error : addr = %" PRIx64 "\n", addr);
3286 printf(" : s_err = %lx\n", s_err);
3287 printf(" : nbytes = %lx\n", nbytes);
3288 return;
3289 }
3290 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
3291 index(base);
3292 print(olditem, 8, -8, 0);
3293 printf("\t=\t");
3294 print(item, 8, -8, 0);
3295 printf("\n");
3296 } else {
3297 if (objsz == DIRECTORY) {
3298 addr = cur_dir;
3299 fprnt('?', 'd');
3300 } else {
3301 addr = cur_ino;
3302 objsz = INODE;
3303 fprnt('?', 'i');
3304 }
3305 }
3306 }
3307
3308 /*
3309 * getblk - check if the desired block is in the file system.
3310 * Search the incore buffers to see if the block is already
3311 * available. If successful, unlink the buffer control block
3312 * from its position in the buffer list and re-insert it at
3313 * the head of the list. If failure, use the last buffer
3314 * in the list for the desired block. Again, this control
3315 * block is placed at the head of the list. This process
3316 * will leave commonly requested blocks in the in-core buffers.
3317 * Finally, a pointer to the buffer is returned.
3318 */
3319 static char *
3320 getblk(u_offset_t address)
3321 {
3322
3323 struct lbuf *bp;
3324 long s_err, nbytes;
3325 unsigned long block;
3326
3327 read_requests++;
3328 block = lblkno(fs, address);
3329 if (block >= fragstoblks(fs, fs->fs_size)) {
3330 printf("cannot read block %lu\n", block);
3331 error++;
3332 return (0);
3333 }
3334 for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
3335 if (bp->valid && bp->blkno == block)
3336 goto xit;
3337 actual_disk_reads++;
3338 bp = bhdr.back;
3339 bp->blkno = block;
3340 bp->valid = 0;
3341 if ((s_err = llseek(fd, (offset_t)(address & fs->fs_bmask), 0)) == -1) {
3342 error++;
3343 printf("seek error : %" PRIx64 "\n", address);
3344 return (0);
3345 }
3346 if ((nbytes = read(fd, bp->blkaddr, BLKSIZE)) != BLKSIZE) {
3347 error++;
3348 printf("read error : addr = %" PRIx64 "\n", address);
3349 printf(" : s_err = %lx\n", s_err);
3350 printf(" : nbytes = %lx\n", nbytes);
3351 return (0);
3352 }
3353 bp->valid++;
3354 xit: bp->back->fwd = bp->fwd;
3355 bp->fwd->back = bp->back;
3356 insert(bp);
3357 return (bp->blkaddr);
3358 }
3359
3360 /*
3361 * insert - place the designated buffer control block
3362 * at the head of the linked list of buffers.
3363 */
3364 static void
3365 insert(struct lbuf *bp)
3366 {
3367
3368 bp->back = &bhdr;
3369 bp->fwd = bhdr.fwd;
3370 bhdr.fwd->back = bp;
3371 bhdr.fwd = bp;
3372 }
3373
3374 /*
3375 * err - called on interrupts. Set the current address
3376 * back to the last address stored in erraddr. Reset all
3377 * appropriate flags. A reset call is made to return
3378 * to the main loop;
3379 */
3380 #ifdef sun
3381 /*ARGSUSED*/
3382 static void
3383 err(int sig)
3384 #else
3385 err()
3386 #endif /* sun */
3387 {
3388 freemem(filenames, nfiles);
3389 nfiles = 0;
3390 (void) signal(2, err);
3391 addr = erraddr;
3392 cur_ino = errino;
3393 cur_inum = errinum;
3394 cur_bytes = errcur_bytes;
3395 error = 0;
3396 c_count = 0;
3397 printf("\n?\n");
3398 (void) fseek(stdin, 0L, 2);
3399 longjmp(env, 0);
3400 }
3401
3402 /*
3403 * devcheck - check that the given mode represents a
3404 * special device. The IFCHR bit is on for both
3405 * character and block devices.
3406 */
3407 static int
3408 devcheck(short md)
3409 {
3410 if (override)
3411 return (0);
3412 switch (md & IFMT) {
3413 case IFCHR:
3414 case IFBLK:
3415 return (0);
3416 }
3417
3418 printf("not character or block device\n");
3419 error++;
3420 return (1);
3421 }
3422
3423 /*
3424 * nullblk - return error if address is zero. This is done
3425 * to prevent block 0 from being used as an indirect block
3426 * for a large file or as a data block for a small file.
3427 */
3428 static int
3429 nullblk(long bn)
3430 {
3431 if (bn != 0)
3432 return (0);
3433 printf("non existent block\n");
3434 error++;
3435 return (1);
3436 }
3437
3438 /*
3439 * puta - put ascii characters into a buffer. The string
3440 * terminates with a quote or newline. The leading quote,
3441 * which is optional for directory names, was stripped off
3442 * by the assignment case in the main loop.
3443 */
3444 static void
3445 puta()
3446 {
3447 char *cptr, c;
3448 int i;
3449 char *sbptr;
3450 short terror = 0;
3451 long maxchars, s_err, nbytes, temp;
3452 u_offset_t taddr = addr;
3453 long tcount = 0, item, olditem = 0;
3454
3455 if (wrtflag == O_RDONLY) {
3456 printf("not opened for write '-w'\n");
3457 error++;
3458 return;
3459 }
3460 if ((sbptr = getblk(addr)) == 0)
3461 return;
3462 cptr = sbptr + blkoff(fs, addr);
3463 if (objsz == DIRECTORY) {
3464 if (acting_on_directory)
3465 maxchars = stringsize - 1;
3466 else
3467 maxchars = LONG;
3468 } else if (objsz == INODE)
3469 maxchars = objsz - (addr - cur_ino);
3470 else
3471 maxchars = min(blocksize - cur_bytes, filesize - cur_bytes);
3472 while ((c = getachar()) != '"') {
3473 if (tcount >= maxchars) {
3474 printf("string too long\n");
3475 if (objsz == DIRECTORY)
3476 addr = cur_dir;
3477 else if (acting_on_inode || objsz == INODE)
3478 addr = cur_ino;
3479 else
3480 addr = taddr;
3481 erraddr = addr;
3482 errcur_bytes = cur_bytes;
3483 terror++;
3484 break;
3485 }
3486 tcount++;
3487 if (c == '\n') {
3488 ungetachar(c);
3489 break;
3490 }
3491 temp = (long)*cptr;
3492 olditem <<= BITSPERCHAR;
3493 olditem += temp & 0xff;
3494 if (c == '\\') {
3495 switch (c = getachar()) {
3496 case 't':
3497 *cptr++ = '\t';
3498 break;
3499 case 'n':
3500 *cptr++ = '\n';
3501 break;
3502 case '0':
3503 *cptr++ = '\0';
3504 break;
3505 default:
3506 *cptr++ = c;
3507 break;
3508 }
3509 }
3510 else
3511 *cptr++ = c;
3512 }
3513 if (objsz == DIRECTORY && acting_on_directory)
3514 for (i = tcount; i <= maxchars; i++)
3515 *cptr++ = '\0';
3516 if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) {
3517 error++;
3518 printf("seek error : %" PRIx64 "\n", addr);
3519 return;
3520 }
3521 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
3522 error++;
3523 printf("write error : addr = %" PRIx64 "\n", addr);
3524 printf(" : s_err = %lx\n", s_err);
3525 printf(" : nbytes = %lx\n", nbytes);
3526 return;
3527 }
3528 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
3529 addr += tcount;
3530 cur_bytes += tcount;
3531 taddr = addr;
3532 if (objsz != CHAR) {
3533 addr &= ~(objsz - 1);
3534 cur_bytes -= taddr - addr;
3535 }
3536 if (addr == taddr) {
3537 addr -= objsz;
3538 taddr = addr;
3539 }
3540 tcount = LONG - (taddr - addr);
3541 index(base);
3542 if ((cptr = getblk(addr)) == 0)
3543 return;
3544 cptr += blkoff(fs, addr);
3545 switch (objsz) {
3546 case LONG:
3547 /*LINTED*/
3548 item = *(long *)cptr;
3549 if (tcount < LONG) {
3550 olditem <<= tcount * BITSPERCHAR;
3551 temp = 1;
3552 for (i = 0; i < (tcount*BITSPERCHAR); i++)
3553 temp <<= 1;
3554 olditem += item & (temp - 1);
3555 }
3556 break;
3557 case SHORT:
3558 /*LINTED*/
3559 item = (long)*(short *)cptr;
3560 if (tcount < SHORT) {
3561 olditem <<= tcount * BITSPERCHAR;
3562 temp = 1;
3563 for (i = 0; i < (tcount * BITSPERCHAR); i++)
3564 temp <<= 1;
3565 olditem += item & (temp - 1);
3566 }
3567 olditem &= 0177777L;
3568 break;
3569 case CHAR:
3570 item = (long)*cptr;
3571 olditem &= 0377;
3572 }
3573 print(olditem, 8, -8, 0);
3574 printf("\t=\t");
3575 print(item, 8, -8, 0);
3576 printf("\n");
3577 } else {
3578 if (objsz == DIRECTORY) {
3579 addr = cur_dir;
3580 fprnt('?', 'd');
3581 } else {
3582 addr = cur_ino;
3583 objsz = INODE;
3584 fprnt('?', 'i');
3585 }
3586 }
3587 if (terror)
3588 error++;
3589 }
3590
3591 /*
3592 * fprnt - print data. 'count' elements are printed where '*' will
3593 * print an entire blocks worth or up to the eof, whichever
3594 * occurs first. An error will occur if crossing a block boundary
3595 * is attempted since consecutive blocks don't usually have
3596 * meaning. Current print types:
3597 * / b - print as bytes (base sensitive)
3598 * c - print as characters
3599 * o O - print as octal shorts (longs)
3600 * d D - print as decimal shorts (longs)
3601 * x X - print as hexadecimal shorts (longs)
3602 * ? c - print as cylinder groups
3603 * d - print as directories
3604 * i - print as inodes
3605 * s - print as super blocks
3606 * S - print as shadow data
3607 */
3608 static void
3609 fprnt(char style, char po)
3610 {
3611 int i;
3612 struct fs *sb;
3613 struct cg *cg;
3614 struct direct *dirp;
3615 struct dinode *ip;
3616 int tbase;
3617 char c, *cptr, *p;
3618 long tinode, tcount, temp;
3619 u_offset_t taddr;
3620 short offset, mode, end = 0, eof = 0, eof_flag;
3621 unsigned short *sptr;
3622 unsigned long *lptr;
3623 offset_t curoff, curioff;
3624
3625 laststyle = style;
3626 lastpo = po;
3627 should_print = 0;
3628 if (count != 1) {
3629 if (clear) {
3630 count = 1;
3631 star = 0;
3632 clear = 0;
3633 } else
3634 clear = 1;
3635 }
3636 tcount = count;
3637 offset = blkoff(fs, addr);
3638
3639 if (style == '/') {
3640 if (type == NUMB)
3641 eof_flag = 0;
3642 else
3643 eof_flag = 1;
3644 switch (po) {
3645
3646 case 'c': /* print as characters */
3647 case 'b': /* or bytes */
3648 if ((cptr = getblk(addr)) == 0)
3649 return;
3650 cptr += offset;
3651 objsz = CHAR;
3652 tcount = check_addr(eof_flag, &end, &eof, 0);
3653 if (tcount) {
3654 for (i = 0; tcount--; i++) {
3655 if (i % 16 == 0) {
3656 if (i)
3657 printf("\n");
3658 index(base);
3659 }
3660 if (po == 'c') {
3661 putf(*cptr++);
3662 if ((i + 1) % 16)
3663 printf(" ");
3664 } else {
3665 if ((i + 1) % 16 == 0)
3666 print(*cptr++ & 0377L,
3667 2, -2, 0);
3668 else
3669 print(*cptr++ & 0377L,
3670 4, -2, 0);
3671 }
3672 addr += CHAR;
3673 cur_bytes += CHAR;
3674 }
3675 printf("\n");
3676 }
3677 addr -= CHAR;
3678 erraddr = addr;
3679 cur_bytes -= CHAR;
3680 errcur_bytes = cur_bytes;
3681 if (eof) {
3682 printf("end of file\n");
3683 error++;
3684 } else if (end) {
3685 if (type == BLOCK)
3686 printf("end of block\n");
3687 else
3688 printf("end of fragment\n");
3689 error++;
3690 }
3691 return;
3692
3693 case 'o': /* print as octal shorts */
3694 tbase = OCTAL;
3695 goto otx;
3696 case 'd': /* print as decimal shorts */
3697 tbase = DECIMAL;
3698 goto otx;
3699 case 'x': /* print as hex shorts */
3700 tbase = HEX;
3701 otx:
3702 if ((cptr = getblk(addr)) == 0)
3703 return;
3704 taddr = addr;
3705 addr &= ~(SHORT - 1);
3706 cur_bytes -= taddr - addr;
3707 cptr += blkoff(fs, addr);
3708 /*LINTED*/
3709 sptr = (unsigned short *)cptr;
3710 objsz = SHORT;
3711 tcount = check_addr(eof_flag, &end, &eof, 0);
3712 if (tcount) {
3713 for (i = 0; tcount--; i++) {
3714 sptr = (unsigned short *)print_check(
3715 /*LINTED*/
3716 (unsigned long *)sptr,
3717 &tcount, tbase, i);
3718 switch (po) {
3719 case 'o':
3720 printf("%06o ", *sptr++);
3721 break;
3722 case 'd':
3723 printf("%05d ", *sptr++);
3724 break;
3725 case 'x':
3726 printf("%04x ", *sptr++);
3727 }
3728 addr += SHORT;
3729 cur_bytes += SHORT;
3730 }
3731 printf("\n");
3732 }
3733 addr -= SHORT;
3734 erraddr = addr;
3735 cur_bytes -= SHORT;
3736 errcur_bytes = cur_bytes;
3737 if (eof) {
3738 printf("end of file\n");
3739 error++;
3740 } else if (end) {
3741 if (type == BLOCK)
3742 printf("end of block\n");
3743 else
3744 printf("end of fragment\n");
3745 error++;
3746 }
3747 return;
3748
3749 case 'O': /* print as octal longs */
3750 tbase = OCTAL;
3751 goto OTX;
3752 case 'D': /* print as decimal longs */
3753 tbase = DECIMAL;
3754 goto OTX;
3755 case 'X': /* print as hex longs */
3756 tbase = HEX;
3757 OTX:
3758 if ((cptr = getblk(addr)) == 0)
3759 return;
3760 taddr = addr;
3761 addr &= ~(LONG - 1);
3762 cur_bytes -= taddr - addr;
3763 cptr += blkoff(fs, addr);
3764 /*LINTED*/
3765 lptr = (unsigned long *)cptr;
3766 objsz = LONG;
3767 tcount = check_addr(eof_flag, &end, &eof, 0);
3768 if (tcount) {
3769 for (i = 0; tcount--; i++) {
3770 lptr = print_check(lptr, &tcount,
3771 tbase, i);
3772 switch (po) {
3773 case 'O':
3774 printf("%011lo ", *lptr++);
3775 break;
3776 case 'D':
3777 printf("%010lu ", *lptr++);
3778 break;
3779 case 'X':
3780 printf("%08lx ", *lptr++);
3781 }
3782 addr += LONG;
3783 cur_bytes += LONG;
3784 }
3785 printf("\n");
3786 }
3787 addr -= LONG;
3788 erraddr = addr;
3789 cur_bytes -= LONG;
3790 errcur_bytes = cur_bytes;
3791 if (eof) {
3792 printf("end of file\n");
3793 error++;
3794 } else if (end) {
3795 if (type == BLOCK)
3796 printf("end of block\n");
3797 else
3798 printf("end of fragment\n");
3799 error++;
3800 }
3801 return;
3802
3803 default:
3804 error++;
3805 printf("no such print option\n");
3806 return;
3807 }
3808 } else
3809 switch (po) {
3810
3811 case 'c': /* print as cylinder group */
3812 if (type != NUMB)
3813 if (cur_cgrp + count > fs->fs_ncg) {
3814 tcount = fs->fs_ncg - cur_cgrp;
3815 if (!star)
3816 end++;
3817 }
3818 addr &= ~(LONG - 1);
3819 for (/* void */; tcount--; /* void */) {
3820 erraddr = addr;
3821 errcur_bytes = cur_bytes;
3822 if (type != NUMB) {
3823 addr = cgtod(fs, cur_cgrp)
3824 << FRGSHIFT;
3825 cur_cgrp++;
3826 }
3827 if ((cptr = getblk(addr)) == 0) {
3828 if (cur_cgrp)
3829 cur_cgrp--;
3830 return;
3831 }
3832 cptr += blkoff(fs, addr);
3833 /*LINTED*/
3834 cg = (struct cg *)cptr;
3835 if (type == NUMB) {
3836 cur_cgrp = cg->cg_cgx + 1;
3837 type = objsz = CGRP;
3838 if (cur_cgrp + count - 1 > fs->fs_ncg) {
3839 tcount = fs->fs_ncg - cur_cgrp;
3840 if (!star)
3841 end++;
3842 }
3843 }
3844 if (! override && !cg_chkmagic(cg)) {
3845 printf("invalid cylinder group ");
3846 printf("magic word\n");
3847 if (cur_cgrp)
3848 cur_cgrp--;
3849 error++;
3850 return;
3851 }
3852 printcg(cg);
3853 if (tcount)
3854 printf("\n");
3855 }
3856 cur_cgrp--;
3857 if (end) {
3858 printf("end of cylinder groups\n");
3859 error++;
3860 }
3861 return;
3862
3863 case 'd': /* print as directories */
3864 if ((cptr = getblk(addr)) == 0)
3865 return;
3866 if (type == NUMB) {
3867 if (fragoff(fs, addr)) {
3868 printf("address must be at the ");
3869 printf("beginning of a fragment\n");
3870 error++;
3871 return;
3872 }
3873 bod_addr = addr;
3874 type = FRAGMENT;
3875 dirslot = 0;
3876 cur_bytes = 0;
3877 blocksize = FRGSIZE;
3878 filesize = FRGSIZE * 2;
3879 }
3880 cptr += offset;
3881 objsz = DIRECTORY;
3882 while (tcount-- && cur_bytes < filesize &&
3883 cur_bytes < blocksize && !bcomp(addr)) {
3884 /*LINTED*/
3885 dirp = (struct direct *)cptr;
3886 tinode = dirp->d_ino;
3887 printf("i#: ");
3888 if (tinode == 0)
3889 printf("free\t");
3890 else
3891 print(tinode, 12, -8, 0);
3892 printf("%s\n", &dirp->d_name[0]);
3893 erraddr = addr;
3894 errcur_bytes = cur_bytes;
3895 addr += dirp->d_reclen;
3896 cptr += dirp->d_reclen;
3897 cur_bytes += dirp->d_reclen;
3898 dirslot++;
3899 stringsize = STRINGSIZE(dirp);
3900 }
3901 addr = erraddr;
3902 cur_dir = addr;
3903 cur_bytes = errcur_bytes;
3904 dirslot--;
3905 if (tcount >= 0 && !star) {
3906 switch (type) {
3907 case FRAGMENT:
3908 printf("end of fragment\n");
3909 break;
3910 case BLOCK:
3911 printf("end of block\n");
3912 break;
3913 default:
3914 printf("end of directory\n");
3915 }
3916 error++;
3917 } else
3918 error = 0;
3919 return;
3920
3921 case 'i': /* print as inodes */
3922 /*LINTED*/
3923 if ((ip = (struct dinode *)getblk(addr)) == 0)
3924 return;
3925 for (i = 1; i < fs->fs_ncg; i++)
3926 if (addr < (cgimin(fs, i) << FRGSHIFT))
3927 break;
3928 i--;
3929 offset /= INODE;
3930 temp = (addr - (cgimin(fs, i) << FRGSHIFT)) >> FRGSHIFT;
3931 temp = (i * fs->fs_ipg) + fragstoblks(fs, temp) *
3932 INOPB(fs) + offset;
3933 if (count + offset > INOPB(fs)) {
3934 tcount = INOPB(fs) - offset;
3935 if (!star)
3936 end++;
3937 }
3938 objsz = INODE;
3939 ip += offset;
3940 for (i = 0; tcount--; ip++, temp++) {
3941 if ((mode = icheck(addr)) == 0)
3942 if (!override)
3943 continue;
3944 p = " ugtrwxrwxrwx";
3945
3946 switch (mode & IFMT) {
3947 case IFDIR:
3948 c = 'd';
3949 break;
3950 case IFCHR:
3951 c = 'c';
3952 break;
3953 case IFBLK:
3954 c = 'b';
3955 break;
3956 case IFREG:
3957 c = '-';
3958 break;
3959 case IFLNK:
3960 c = 'l';
3961 break;
3962 case IFSOCK:
3963 c = 's';
3964 break;
3965 case IFSHAD:
3966 c = 'S';
3967 break;
3968 case IFATTRDIR:
3969 c = 'A';
3970 break;
3971 default:
3972 c = '?';
3973 if (!override)
3974 goto empty;
3975
3976 }
3977 printf("i#: ");
3978 print(temp, 12, -8, 0);
3979 printf(" md: ");
3980 printf("%c", c);
3981 for (mode = mode << 4; *++p; mode = mode << 1) {
3982 if (mode & IFREG)
3983 printf("%c", *p);
3984 else
3985 printf("-");
3986 }
3987 printf(" uid: ");
3988 print(ip->di_uid, 8, -4, 0);
3989 printf(" gid: ");
3990 print(ip->di_gid, 8, -4, 0);
3991 printf("\n");
3992 printf("ln: ");
3993 print((long)ip->di_nlink, 8, -4, 0);
3994 printf(" bs: ");
3995 print(ip->di_blocks, 12, -8, 0);
3996 printf("c_flags : ");
3997 print(ip->di_cflags, 12, -8, 0);
3998 printf(" sz : ");
3999 #ifdef _LARGEFILE64_SOURCE
4000 printll(ip->di_size, 20, -16, 0);
4001 #else /* !_LARGEFILE64_SOURCE */
4002 print(ip->di_size, 12, -8, 0);
4003 #endif /* _LARGEFILE64_SOURCE */
4004 if (ip->di_shadow) {
4005 printf(" si: ");
4006 print(ip->di_shadow, 12, -8, 0);
4007 }
4008 printf("\n");
4009 if (ip->di_oeftflag) {
4010 printf("ai: ");
4011 print(ip->di_oeftflag, 12, -8, 0);
4012 printf("\n");
4013 }
4014 printf("\n");
4015 switch (ip->di_mode & IFMT) {
4016 case IFBLK:
4017 case IFCHR:
4018 printf("maj: ");
4019 print(major(ip->di_ordev), 4, -2, 0);
4020 printf(" min: ");
4021 print(minor(ip->di_ordev), 4, -2, 0);
4022 printf("\n");
4023 break;
4024 default:
4025 /*
4026 * only display blocks below the
4027 * current file size
4028 */
4029 curoff = 0LL;
4030 for (i = 0; i < NDADDR; ) {
4031 if (ip->di_size <= curoff)
4032 break;
4033 printf("db#%x: ", i);
4034 print(ip->di_db[i], 11, -8, 0);
4035
4036 if (++i % 4 == 0)
4037 printf("\n");
4038 else
4039 printf(" ");
4040 curoff += fs->fs_bsize;
4041 }
4042 if (i % 4)
4043 printf("\n");
4044
4045 /*
4046 * curioff keeps track of the number
4047 * of bytes covered by each indirect
4048 * pointer in the inode, and is added
4049 * to curoff each time to get the
4050 * actual offset into the file.
4051 */
4052 curioff = fs->fs_bsize *
4053 (fs->fs_bsize / sizeof (daddr_t));
4054 for (i = 0; i < NIADDR; i++) {
4055 if (ip->di_size <= curoff)
4056 break;
4057 printf("ib#%x: ", i);
4058 print(ip->di_ib[i], 11, -8, 0);
4059 printf(" ");
4060 curoff += curioff;
4061 curioff *= (fs->fs_bsize /
4062 sizeof (daddr_t));
4063 }
4064 if (i)
4065 printf("\n");
4066 break;
4067 }
4068 if (count == 1) {
4069 time_t t;
4070
4071 t = ip->di_atime;
4072 printf("\taccessed: %s", ctime(&t));
4073 t = ip->di_mtime;
4074 printf("\tmodified: %s", ctime(&t));
4075 t = ip->di_ctime;
4076 printf("\tcreated : %s", ctime(&t));
4077 }
4078 if (tcount)
4079 printf("\n");
4080 empty:
4081 if (c == '?' && !override) {
4082 printf("i#: ");
4083 print(temp, 12, -8, 0);
4084 printf(" is unallocated\n");
4085 if (count != 1)
4086 printf("\n");
4087 }
4088 cur_ino = erraddr = addr;
4089 errcur_bytes = cur_bytes;
4090 cur_inum++;
4091 addr = addr + INODE;
4092 }
4093 addr = erraddr;
4094 cur_bytes = errcur_bytes;
4095 cur_inum--;
4096 if (end) {
4097 printf("end of block\n");
4098 error++;
4099 }
4100 return;
4101
4102 case 's': /* print as super block */
4103 if (cur_cgrp == -1) {
4104 addr = SBLOCK * DEV_BSIZE;
4105 type = NUMB;
4106 }
4107 addr &= ~(LONG - 1);
4108 if (type != NUMB)
4109 if (cur_cgrp + count > fs->fs_ncg) {
4110 tcount = fs->fs_ncg - cur_cgrp;
4111 if (!star)
4112 end++;
4113 }
4114 for (/* void */; tcount--; /* void */) {
4115 erraddr = addr;
4116 cur_bytes = errcur_bytes;
4117 if (type != NUMB) {
4118 addr = cgsblock(fs, cur_cgrp)
4119 << FRGSHIFT;
4120 cur_cgrp++;
4121 }
4122 if ((cptr = getblk(addr)) == 0) {
4123 if (cur_cgrp)
4124 cur_cgrp--;
4125 return;
4126 }
4127 cptr += blkoff(fs, addr);
4128 /*LINTED*/
4129 sb = (struct fs *)cptr;
4130 if (type == NUMB) {
4131 for (i = 0; i < fs->fs_ncg; i++)
4132 if (addr == cgsblock(fs, i) <<
4133 FRGSHIFT)
4134 break;
4135 if (i == fs->fs_ncg)
4136 cur_cgrp = 0;
4137 else
4138 cur_cgrp = i + 1;
4139 type = objsz = SB;
4140 if (cur_cgrp + count - 1 > fs->fs_ncg) {
4141 tcount = fs->fs_ncg - cur_cgrp;
4142 if (!star)
4143 end++;
4144 }
4145 }
4146 if ((sb->fs_magic != FS_MAGIC) &&
4147 (sb->fs_magic != MTB_UFS_MAGIC)) {
4148 cur_cgrp = 0;
4149 if (!override) {
4150 printf("invalid super block ");
4151 printf("magic word\n");
4152 cur_cgrp--;
4153 error++;
4154 return;
4155 }
4156 }
4157 if (sb->fs_magic == FS_MAGIC &&
4158 (sb->fs_version !=
4159 UFS_EFISTYLE4NONEFI_VERSION_2 &&
4160 sb->fs_version != UFS_VERSION_MIN)) {
4161 cur_cgrp = 0;
4162 if (!override) {
4163 printf("invalid super block ");
4164 printf("version number\n");
4165 cur_cgrp--;
4166 error++;
4167 return;
4168 }
4169 }
4170 if (sb->fs_magic == MTB_UFS_MAGIC &&
4171 (sb->fs_version > MTB_UFS_VERSION_1 ||
4172 sb->fs_version < MTB_UFS_VERSION_MIN)) {
4173 cur_cgrp = 0;
4174 if (!override) {
4175 printf("invalid super block ");
4176 printf("version number\n");
4177 cur_cgrp--;
4178 error++;
4179 return;
4180 }
4181 }
4182 if (cur_cgrp == 0)
4183 printf("\tsuper block:\n");
4184 else {
4185 printf("\tsuper block in cylinder ");
4186 printf("group ");
4187 print(cur_cgrp - 1, 0, 0, 0);
4188 printf(":\n");
4189 }
4190 printsb(sb);
4191 if (tcount)
4192 printf("\n");
4193 }
4194 cur_cgrp--;
4195 if (end) {
4196 printf("end of super blocks\n");
4197 error++;
4198 }
4199 return;
4200
4201 case 'S': /* print as shadow data */
4202 if (type == NUMB) {
4203 type = FRAGMENT;
4204 cur_shad = 0;
4205 cur_bytes = fragoff(fs, addr);
4206 bod_addr = addr - cur_bytes;
4207 /* no more than two fragments */
4208 filesize = fragroundup(fs,
4209 bod_addr + FRGSIZE + 1);
4210 }
4211 objsz = SHADOW_DATA;
4212 while (tcount-- &&
4213 (cur_bytes + SHADOW_DATA) <= filesize &&
4214 (type != SHADOW_DATA ||
4215 (cur_bytes + SHADOW_DATA)) <= blocksize) {
4216 /*LINTED*/
4217 struct ufs_fsd fsd;
4218 long tcur_bytes;
4219
4220 taddr = addr;
4221 tcur_bytes = cur_bytes;
4222 index(base);
4223 getshadowdata((long *)&fsd, LONG + LONG);
4224 printf(" type: ");
4225 print((long)fsd.fsd_type, 8, -8, 0);
4226 printf(" size: ");
4227 print((long)fsd.fsd_size, 8, -8, 0);
4228 tbase = fsd.fsd_size - LONG - LONG;
4229 if (tbase > 256)
4230 tbase = 256;
4231 for (i = 0; i < tbase; i++) {
4232 if (i % LONG == 0) {
4233 if (i % 16 == 0) {
4234 printf("\n");
4235 index(base);
4236 } else
4237 printf(" ");
4238 getshadowdata(&temp, LONG);
4239 p = (char *)&temp;
4240 } else
4241 printf(" ");
4242 printf("%02x", (int)(*p++ & 0377L));
4243 }
4244 printf("\n");
4245 addr = taddr;
4246 cur_bytes = tcur_bytes;
4247 erraddr = addr;
4248 errcur_bytes = cur_bytes;
4249 addr += FSD_RECSZ((&fsd), fsd.fsd_size);
4250 cur_bytes += FSD_RECSZ((&fsd), fsd.fsd_size);
4251 cur_shad++;
4252 syncshadowscan(0);
4253 }
4254 addr = erraddr;
4255 cur_bytes = errcur_bytes;
4256 cur_shad--;
4257 if (tcount >= 0 && !star) {
4258 switch (type) {
4259 case FRAGMENT:
4260 printf("end of fragment\n");
4261 break;
4262 default:
4263 printf("end of shadow data\n");
4264 }
4265 error++;
4266 } else
4267 error = 0;
4268 return;
4269 default:
4270 error++;
4271 printf("no such print option\n");
4272 return;
4273 }
4274 }
4275
4276 /*
4277 * valid_addr - call check_addr to validate the current address.
4278 */
4279 static int
4280 valid_addr()
4281 {
4282 short end = 0, eof = 0;
4283 long tcount = count;
4284
4285 if (!trapped)
4286 return (1);
4287 if (cur_bytes < 0) {
4288 cur_bytes = 0;
4289 if (blocksize > filesize) {
4290 printf("beginning of file\n");
4291 } else {
4292 if (type == BLOCK)
4293 printf("beginning of block\n");
4294 else
4295 printf("beginning of fragment\n");
4296 }
4297 error++;
4298 return (0);
4299 }
4300 count = 1;
4301 (void) check_addr(1, &end, &eof, (filesize < blocksize));
4302 count = tcount;
4303 if (eof) {
4304 printf("end of file\n");
4305 error++;
4306 return (0);
4307 }
4308 if (end == 2) {
4309 if (erraddr > addr) {
4310 if (type == BLOCK)
4311 printf("beginning of block\n");
4312 else
4313 printf("beginning of fragment\n");
4314 error++;
4315 return (0);
4316 }
4317 }
4318 if (end) {
4319 if (type == BLOCK)
4320 printf("end of block\n");
4321 else
4322 printf("end of fragment\n");
4323 error++;
4324 return (0);
4325 }
4326 return (1);
4327 }
4328
4329 /*
4330 * check_addr - check if the address crosses the end of block or
4331 * end of file. Return the proper count.
4332 */
4333 static int
4334 check_addr(short eof_flag, short *end, short *eof, short keep_on)
4335 {
4336 long temp, tcount = count, tcur_bytes = cur_bytes;
4337 u_offset_t taddr = addr;
4338
4339 if (bcomp(addr + count * objsz - 1) ||
4340 (keep_on && taddr < (bmap(cur_block) << FRGSHIFT))) {
4341 error = 0;
4342 addr = taddr;
4343 cur_bytes = tcur_bytes;
4344 if (keep_on) {
4345 if (addr < erraddr) {
4346 if (cur_bytes < 0) {
4347 (*end) = 2;
4348 return (0); /* Value ignored */
4349 }
4350 temp = cur_block - lblkno(fs, cur_bytes);
4351 cur_block -= temp;
4352 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
4353 cur_block += temp;
4354 return (0); /* Value ignored */
4355 }
4356 temp = tcur_bytes - cur_bytes;
4357 addr += temp;
4358 cur_bytes += temp;
4359 return (0); /* Value ignored */
4360 } else {
4361 if (cur_bytes >= filesize) {
4362 (*eof)++;
4363 return (0); /* Value ignored */
4364 }
4365 temp = lblkno(fs, cur_bytes) - cur_block;
4366 cur_block += temp;
4367 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
4368 cur_block -= temp;
4369 return (0); /* Value ignored */
4370 }
4371 temp = tcur_bytes - cur_bytes;
4372 addr += temp;
4373 cur_bytes += temp;
4374 return (0); /* Value ignored */
4375 }
4376 }
4377 tcount = (blkroundup(fs, addr+1)-addr) / objsz;
4378 if (!star)
4379 (*end) = 2;
4380 }
4381 addr = taddr;
4382 cur_bytes = tcur_bytes;
4383 if (eof_flag) {
4384 if (blocksize > filesize) {
4385 if (cur_bytes >= filesize) {
4386 tcount = 0;
4387 (*eof)++;
4388 } else if (tcount > (filesize - cur_bytes) / objsz) {
4389 tcount = (filesize - cur_bytes) / objsz;
4390 if (!star || tcount == 0)
4391 (*eof)++;
4392 }
4393 } else {
4394 if (cur_bytes >= blocksize) {
4395 tcount = 0;
4396 (*end)++;
4397 } else if (tcount > (blocksize - cur_bytes) / objsz) {
4398 tcount = (blocksize - cur_bytes) / objsz;
4399 if (!star || tcount == 0)
4400 (*end)++;
4401 }
4402 }
4403 }
4404 return (tcount);
4405 }
4406
4407 /*
4408 * print_check - check if the index needs to be printed and delete
4409 * rows of zeros from the output.
4410 */
4411 unsigned long *
4412 print_check(unsigned long *lptr, long *tcount, short tbase, int i)
4413 {
4414 int j, k, temp = BYTESPERLINE / objsz;
4415 short first_time = 0;
4416 unsigned long *tlptr;
4417 unsigned short *tsptr, *sptr;
4418
4419 sptr = (unsigned short *)lptr;
4420 if (i == 0)
4421 first_time = 1;
4422 if (i % temp == 0) {
4423 if (*tcount >= temp - 1) {
4424 if (objsz == SHORT)
4425 tsptr = sptr;
4426 else
4427 tlptr = lptr;
4428 k = *tcount - 1;
4429 for (j = i; k--; j++)
4430 if (objsz == SHORT) {
4431 if (*tsptr++ != 0)
4432 break;
4433 } else {
4434 if (*tlptr++ != 0)
4435 break;
4436 }
4437 if (j > (i + temp - 1)) {
4438 j = (j - i) / temp;
4439 while (j-- > 0) {
4440 if (objsz == SHORT)
4441 sptr += temp;
4442 else
4443 lptr += temp;
4444 *tcount -= temp;
4445 i += temp;
4446 addr += BYTESPERLINE;
4447 cur_bytes += BYTESPERLINE;
4448 }
4449 if (first_time)
4450 printf("*");
4451 else
4452 printf("\n*");
4453 }
4454 if (i)
4455 printf("\n");
4456 index(tbase);
4457 } else {
4458 if (i)
4459 printf("\n");
4460 index(tbase);
4461 }
4462 }
4463 if (objsz == SHORT)
4464 /*LINTED*/
4465 return ((unsigned long *)sptr);
4466 else
4467 return (lptr);
4468 }
4469
4470 /*
4471 * index - print a byte index for the printout in base b
4472 * with leading zeros.
4473 */
4474 static void
4475 index(int b)
4476 {
4477 int tbase = base;
4478
4479 base = b;
4480 print(addr, 8, 8, 1);
4481 printf(":\t");
4482 base = tbase;
4483 }
4484
4485 /*
4486 * print - print out the value to digits places with/without
4487 * leading zeros and right/left justified in the current base.
4488 */
4489 static void
4490 #ifdef _LARGEFILE64_SOURCE
4491 printll(u_offset_t value, int fieldsz, int digits, int lead)
4492 #else /* !_LARGEFILE64_SOURCE */
4493 print(long value, int fieldsz, int digits, int lead)
4494 #endif /* _LARGEFILE64_SOURCE */
4495 {
4496 int i, left = 0;
4497 char mode = BASE[base - OCTAL];
4498 char *string = &scratch[0];
4499
4500 if (digits < 0) {
4501 left = 1;
4502 digits *= -1;
4503 }
4504 if (base != HEX)
4505 if (digits)
4506 digits = digits + (digits - 1)/((base >> 1) - 1) + 1;
4507 else
4508 digits = 1;
4509 if (lead) {
4510 if (left)
4511 (void) sprintf(string, "%%%c%d%d.%d"
4512 #ifdef _LARGEFILE64_SOURCE
4513 "ll"
4514 #endif /* _LARGEFILE64_SOURCE */
4515 "%c", '-', 0, digits, lead, mode);
4516 else
4517 (void) sprintf(string, "%%%d%d.%d"
4518 #ifdef _LARGEFILE64_SOURCE
4519 "ll"
4520 #endif /* _LARGEFILE64_SOURCE */
4521 "%c", 0, digits, lead, mode);
4522 } else {
4523 if (left)
4524 (void) sprintf(string, "%%%c%d"
4525 #ifdef _LARGEFILE64_SOURCE
4526 "ll"
4527 #endif /* _LARGEFILE64_SOURCE */
4528 "%c", '-', digits, mode);
4529 else
4530 (void) sprintf(string, "%%%d"
4531 #ifdef _LARGEFILE64_SOURCE
4532 "ll"
4533 #endif /* _LARGEFILE64_SOURCE */
4534 "%c", digits, mode);
4535 }
4536 printf(string, value);
4537 for (i = 0; i < fieldsz - digits; i++)
4538 printf(" ");
4539 }
4540
4541 /*
4542 * Print out the contents of a superblock.
4543 */
4544 static void
4545 printsb(struct fs *fs)
4546 {
4547 int c, i, j, k, size;
4548 caddr_t sip;
4549 time_t t;
4550
4551 t = fs->fs_time;
4552 #ifdef FS_42POSTBLFMT
4553 if (fs->fs_postblformat == FS_42POSTBLFMT)
4554 fs->fs_nrpos = 8;
4555 printf("magic\t%lx\tformat\t%s\ttime\t%s", fs->fs_magic,
4556 fs->fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic",
4557 ctime(&t));
4558 #else
4559 printf("magic\t%x\ttime\t%s",
4560 fs->fs_magic, ctime(&t));
4561 #endif
4562 printf("version\t%x\n", fs->fs_version);
4563 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4564 fs->fs_cstotal.cs_nbfree, fs->fs_cstotal.cs_ndir,
4565 fs->fs_cstotal.cs_nifree, fs->fs_cstotal.cs_nffree);
4566 printf("ncg\t%ld\tncyl\t%ld\tsize\t%ld\tblocks\t%ld\n",
4567 fs->fs_ncg, fs->fs_ncyl, fs->fs_size, fs->fs_dsize);
4568 printf("bsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4569 fs->fs_bsize, fs->fs_bshift, fs->fs_bmask);
4570 printf("fsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4571 fs->fs_fsize, fs->fs_fshift, fs->fs_fmask);
4572 printf("frag\t%ld\tshift\t%ld\tfsbtodb\t%ld\n",
4573 fs->fs_frag, fs->fs_fragshift, fs->fs_fsbtodb);
4574 printf("cpg\t%ld\tbpg\t%ld\tfpg\t%ld\tipg\t%ld\n",
4575 fs->fs_cpg, fs->fs_fpg / fs->fs_frag, fs->fs_fpg, fs->fs_ipg);
4576 printf("minfree\t%ld%%\toptim\t%s\tmaxcontig %ld\tmaxbpg\t%ld\n",
4577 fs->fs_minfree, fs->fs_optim == FS_OPTSPACE ? "space" : "time",
4578 fs->fs_maxcontig, fs->fs_maxbpg);
4579 #ifdef FS_42POSTBLFMT
4580 #ifdef sun
4581 printf("rotdelay %ldms\tfs_id[0] 0x%lx\tfs_id[1] 0x%lx\trps\t%ld\n",
4582 fs->fs_rotdelay, fs->fs_id[0], fs->fs_id[1], fs->fs_rps);
4583 #else
4584 printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
4585 fs->fs_rotdelay, fs->fs_headswitch, fs->fs_trkseek, fs->fs_rps);
4586 #endif /* sun */
4587 printf("ntrak\t%ld\tnsect\t%ld\tnpsect\t%ld\tspc\t%ld\n",
4588 fs->fs_ntrak, fs->fs_nsect, fs->fs_npsect, fs->fs_spc);
4589 printf("trackskew %ld\n", fs->fs_trackskew);
4590 #else
4591 printf("rotdelay %ldms\trps\t%ld\n",
4592 fs->fs_rotdelay, fs->fs_rps);
4593 printf("ntrak\t%ld\tnsect\t%ld\tspc\t%ld\n",
4594 fs->fs_ntrak, fs->fs_nsect, fs->fs_spc);
4595 #endif
4596 printf("si %ld\n", fs->fs_si);
4597 printf("nindir\t%ld\tinopb\t%ld\tnspf\t%ld\n",
4598 fs->fs_nindir, fs->fs_inopb, fs->fs_nspf);
4599 printf("sblkno\t%ld\tcblkno\t%ld\tiblkno\t%ld\tdblkno\t%ld\n",
4600 fs->fs_sblkno, fs->fs_cblkno, fs->fs_iblkno, fs->fs_dblkno);
4601 printf("sbsize\t%ld\tcgsize\t%ld\tcgoffset %ld\tcgmask\t0x%08lx\n",
4602 fs->fs_sbsize, fs->fs_cgsize, fs->fs_cgoffset, fs->fs_cgmask);
4603 printf("csaddr\t%ld\tcssize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4604 fs->fs_csaddr, fs->fs_cssize, fs->fs_csshift, fs->fs_csmask);
4605 printf("cgrotor\t%ld\tfmod\t%d\tronly\t%d\n",
4606 fs->fs_cgrotor, fs->fs_fmod, fs->fs_ronly);
4607 #ifdef FS_42POSTBLFMT
4608 if (fs->fs_cpc != 0)
4609 printf("blocks available in each of %ld rotational positions",
4610 fs->fs_nrpos);
4611 else
4612 printf("insufficient space to maintain rotational tables\n");
4613 #endif
4614 for (c = 0; c < fs->fs_cpc; c++) {
4615 printf("\ncylinder number %d:", c);
4616 #ifdef FS_42POSTBLFMT
4617 for (i = 0; i < fs->fs_nrpos; i++) {
4618 /*LINTED*/
4619 if (fs_postbl(fs, c)[i] == -1)
4620 continue;
4621 printf("\n position %d:\t", i);
4622 /*LINTED*/
4623 for (j = fs_postbl(fs, c)[i], k = 1; /* void */;
4624 j += fs_rotbl(fs)[j], k++) {
4625 printf("%5d", j);
4626 if (k % 12 == 0)
4627 printf("\n\t\t");
4628 if (fs_rotbl(fs)[j] == 0)
4629 break;
4630 }
4631 }
4632 #else
4633 for (i = 0; i < NRPOS; i++) {
4634 if (fs->fs_postbl[c][i] == -1)
4635 continue;
4636 printf("\n position %d:\t", i);
4637 for (j = fs->fs_postbl[c][i], k = 1; /* void */;
4638 j += fs->fs_rotbl[j], k++) {
4639 printf("%5d", j);
4640 if (k % 12 == 0)
4641 printf("\n\t\t");
4642 if (fs->fs_rotbl[j] == 0)
4643 break;
4644 }
4645 }
4646 #endif
4647 }
4648 printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):");
4649 sip = calloc(1, fs->fs_cssize);
4650 fs->fs_u.fs_csp = (struct csum *)sip;
4651 for (i = 0, j = 0; i < fs->fs_cssize; i += fs->fs_bsize, j++) {
4652 size = fs->fs_cssize - i < fs->fs_bsize ?
4653 fs->fs_cssize - i : fs->fs_bsize;
4654 (void) llseek(fd,
4655 (offset_t)fsbtodb(fs, (fs->fs_csaddr + j * fs->fs_frag))
4656 * fs->fs_fsize / fsbtodb(fs, 1), 0);
4657 if (read(fd, sip, size) != size) {
4658 free(fs->fs_u.fs_csp);
4659 return;
4660 }
4661 sip += size;
4662 }
4663 for (i = 0; i < fs->fs_ncg; i++) {
4664 struct csum *cs = &fs->fs_cs(fs, i);
4665 if (i % 4 == 0)
4666 printf("\n ");
4667 printf("%d:(%ld,%ld,%ld,%ld) ", i, cs->cs_nbfree, cs->cs_ndir,
4668 cs->cs_nifree, cs->cs_nffree);
4669 }
4670 free(fs->fs_u.fs_csp);
4671 printf("\n");
4672 if (fs->fs_ncyl % fs->fs_cpg) {
4673 printf("cylinders in last group %d\n",
4674 i = fs->fs_ncyl % fs->fs_cpg);
4675 printf("blocks in last group %ld\n",
4676 i * fs->fs_spc / NSPB(fs));
4677 }
4678 }
4679
4680 /*
4681 * Print out the contents of a cylinder group.
4682 */
4683 static void
4684 printcg(struct cg *cg)
4685 {
4686 int i, j;
4687 time_t t;
4688
4689 printf("\ncg %ld:\n", cg->cg_cgx);
4690 t = cg->cg_time;
4691 #ifdef FS_42POSTBLFMT
4692 printf("magic\t%lx\ttell\t%llx\ttime\t%s",
4693 fs->fs_postblformat == FS_42POSTBLFMT ?
4694 ((struct ocg *)cg)->cg_magic : cg->cg_magic,
4695 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
4696 ctime(&t));
4697 #else
4698 printf("magic\t%x\ttell\t%llx\ttime\t%s",
4699 cg->cg_magic,
4700 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
4701 ctime(&t));
4702 #endif
4703 printf("cgx\t%ld\tncyl\t%d\tniblk\t%d\tndblk\t%ld\n",
4704 cg->cg_cgx, cg->cg_ncyl, cg->cg_niblk, cg->cg_ndblk);
4705 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4706 cg->cg_cs.cs_nbfree, cg->cg_cs.cs_ndir,
4707 cg->cg_cs.cs_nifree, cg->cg_cs.cs_nffree);
4708 printf("rotor\t%ld\tirotor\t%ld\tfrotor\t%ld\nfrsum",
4709 cg->cg_rotor, cg->cg_irotor, cg->cg_frotor);
4710 for (i = 1, j = 0; i < fs->fs_frag; i++) {
4711 printf("\t%ld", cg->cg_frsum[i]);
4712 j += i * cg->cg_frsum[i];
4713 }
4714 printf("\nsum of frsum: %d\niused:\t", j);
4715 pbits((unsigned char *)cg_inosused(cg), fs->fs_ipg);
4716 printf("free:\t");
4717 pbits(cg_blksfree(cg), fs->fs_fpg);
4718 printf("b:\n");
4719 for (i = 0; i < fs->fs_cpg; i++) {
4720 /*LINTED*/
4721 if (cg_blktot(cg)[i] == 0)
4722 continue;
4723 /*LINTED*/
4724 printf(" c%d:\t(%ld)\t", i, cg_blktot(cg)[i]);
4725 #ifdef FS_42POSTBLFMT
4726 for (j = 0; j < fs->fs_nrpos; j++) {
4727 if (fs->fs_cpc == 0 ||
4728 /*LINTED*/
4729 fs_postbl(fs, i % fs->fs_cpc)[j] == -1)
4730 continue;
4731 /*LINTED*/
4732 printf(" %d", cg_blks(fs, cg, i)[j]);
4733 }
4734 #else
4735 for (j = 0; j < NRPOS; j++) {
4736 if (fs->fs_cpc == 0 ||
4737 fs->fs_postbl[i % fs->fs_cpc][j] == -1)
4738 continue;
4739 printf(" %d", cg->cg_b[i][j]);
4740 }
4741 #endif
4742 printf("\n");
4743 }
4744 }
4745
4746 /*
4747 * Print out the contents of a bit array.
4748 */
4749 static void
4750 pbits(unsigned char *cp, int max)
4751 {
4752 int i;
4753 int count = 0, j;
4754
4755 for (i = 0; i < max; i++)
4756 if (isset(cp, i)) {
4757 if (count)
4758 printf(",%s", count % 6 ? " " : "\n\t");
4759 count++;
4760 printf("%d", i);
4761 j = i;
4762 while ((i+1) < max && isset(cp, i+1))
4763 i++;
4764 if (i != j)
4765 printf("-%d", i);
4766 }
4767 printf("\n");
4768 }
4769
4770 /*
4771 * bcomp - used to check for block over/under flows when stepping through
4772 * a file system.
4773 */
4774 static int
4775 bcomp(addr)
4776 u_offset_t addr;
4777 {
4778 if (override)
4779 return (0);
4780
4781 if (lblkno(fs, addr) == (bhdr.fwd)->blkno)
4782 return (0);
4783 error++;
4784 return (1);
4785 }
4786
4787 /*
4788 * bmap - maps the logical block number of a file into
4789 * the corresponding physical block on the file
4790 * system.
4791 */
4792 static long
4793 bmap(long bn)
4794 {
4795 int j;
4796 struct dinode *ip;
4797 int sh;
4798 long nb;
4799 char *cptr;
4800
4801 if ((cptr = getblk(cur_ino)) == 0)
4802 return (0);
4803
4804 cptr += blkoff(fs, cur_ino);
4805
4806 /*LINTED*/
4807 ip = (struct dinode *)cptr;
4808
4809 if (bn < NDADDR) {
4810 nb = ip->di_db[bn];
4811 return (nullblk(nb) ? 0L : nb);
4812 }
4813
4814 sh = 1;
4815 bn -= NDADDR;
4816 for (j = NIADDR; j > 0; j--) {
4817 sh *= NINDIR(fs);
4818 if (bn < sh)
4819 break;
4820 bn -= sh;
4821 }
4822 if (j == 0) {
4823 printf("file too big\n");
4824 error++;
4825 return (0L);
4826 }
4827 addr = (uintptr_t)&ip->di_ib[NIADDR - j];
4828 nb = get(LONG);
4829 if (nb == 0)
4830 return (0L);
4831 for (; j <= NIADDR; j++) {
4832 sh /= NINDIR(fs);
4833 addr = (nb << FRGSHIFT) + ((bn / sh) % NINDIR(fs)) * LONG;
4834 if (nullblk(nb = get(LONG)))
4835 return (0L);
4836 }
4837 return (nb);
4838 }
4839
4840 #if defined(OLD_FSDB_COMPATIBILITY)
4841
4842 /*
4843 * The following are "tacked on" to support the old fsdb functionality
4844 * of clearing an inode. (All together now...) "It's better to use clri".
4845 */
4846
4847 #define ISIZE (sizeof (struct dinode))
4848 #define NI (MAXBSIZE/ISIZE)
4849
4850
4851 static struct dinode di_buf[NI];
4852
4853 static union {
4854 char dummy[SBSIZE];
4855 struct fs sblk;
4856 } sb_un;
4857
4858 #define sblock sb_un.sblk
4859
4860 static void
4861 old_fsdb(int inum, char *special)
4862 {
4863 int f; /* File descriptor for "special" */
4864 int j;
4865 int status = 0;
4866 u_offset_t off;
4867 long gen;
4868 time_t t;
4869
4870 f = open(special, 2);
4871 if (f < 0) {
4872 perror("open");
4873 printf("cannot open %s\n", special);
4874 exit(31+4);
4875 }
4876 (void) llseek(f, (offset_t)SBLOCK * DEV_BSIZE, 0);
4877 if (read(f, &sblock, SBSIZE) != SBSIZE) {
4878 printf("cannot read %s\n", special);
4879 exit(31+4);
4880 }
4881 if (sblock.fs_magic != FS_MAGIC) {
4882 printf("bad super block magic number\n");
4883 exit(31+4);
4884 }
4885 if (inum == 0) {
4886 printf("%d: is zero\n", inum);
4887 exit(31+1);
4888 }
4889 off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE;
4890 (void) llseek(f, off, 0);
4891 if (read(f, (char *)di_buf, sblock.fs_bsize) != sblock.fs_bsize) {
4892 printf("%s: read error\n", special);
4893 status = 1;
4894 }
4895 if (status)
4896 exit(31+status);
4897
4898 /*
4899 * Update the time in superblock, so fsck will check this filesystem.
4900 */
4901 (void) llseek(f, (offset_t)(SBLOCK * DEV_BSIZE), 0);
4902 (void) time(&t);
4903 sblock.fs_time = (time32_t)t;
4904 if (write(f, &sblock, SBSIZE) != SBSIZE) {
4905 printf("cannot update %s\n", special);
4906 exit(35);
4907 }
4908
4909 printf("clearing %u\n", inum);
4910 off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE;
4911 (void) llseek(f, off, 0);
4912 read(f, (char *)di_buf, sblock.fs_bsize);
4913 j = itoo(&sblock, inum);
4914 gen = di_buf[j].di_gen;
4915 (void) memset((caddr_t)&di_buf[j], 0, ISIZE);
4916 di_buf[j].di_gen = gen + 1;
4917 (void) llseek(f, off, 0);
4918 write(f, (char *)di_buf, sblock.fs_bsize);
4919 exit(31+status);
4920 }
4921
4922 static int
4923 isnumber(char *s)
4924 {
4925 register int c;
4926
4927 if (s == NULL)
4928 return (0);
4929 while ((c = *s++) != NULL)
4930 if (c < '0' || c > '9')
4931 return (0);
4932 return (1);
4933 }
4934 #endif /* OLD_FSDB_COMPATIBILITY */
4935
4936 enum boolean { True, False };
4937 extent_block_t *log_eb;
4938 ml_odunit_t *log_odi;
4939 int lufs_tid; /* last valid TID seen */
4940
4941 /*
4942 * no single value is safe to use to indicate
4943 * lufs_tid being invalid so we need a
4944 * seperate variable.
4945 */
4946 enum boolean lufs_tid_valid;
4947
4948 /*
4949 * log_get_header_info - get the basic info of the logging filesystem
4950 */
4951 int
4952 log_get_header_info(void)
4953 {
4954 char *b;
4955 int nb;
4956
4957 /*
4958 * Mark the global tid as invalid everytime we're called to
4959 * prevent any false positive responses.
4960 */
4961 lufs_tid_valid = False;
4962
4963 /*
4964 * See if we've already set up the header areas. The only problem
4965 * with this approach is we don't reread the on disk data though
4966 * it shouldn't matter since we don't operate on a live disk.
4967 */
4968 if ((log_eb != NULL) && (log_odi != NULL))
4969 return (1);
4970
4971 /*
4972 * Either logging is disabled or we've not running 2.7.
4973 */
4974 if (fs->fs_logbno == 0) {
4975 printf("Logging doesn't appear to be enabled on this disk\n");
4976 return (0);
4977 }
4978
4979 /*
4980 * To find the log we need to first pick up the block allocation
4981 * data. The block number for that data is fs_logbno in the
4982 * super block.
4983 */
4984 if ((b = getblk((u_offset_t)ldbtob(logbtodb(fs, fs->fs_logbno))))
4985 == 0) {
4986 printf("getblk() indicates an error with logging block\n");
4987 return (0);
4988 }
4989
4990 /*
4991 * Next we need to figure out how big the extent data structure
4992 * really is. It can't be more then fs_bsize and you could just
4993 * allocate that but, why get sloppy.
4994 * 1 is subtracted from nextents because extent_block_t contains
4995 * a single extent_t itself.
4996 */
4997 log_eb = (extent_block_t *)b;
4998 if (log_eb->type != LUFS_EXTENTS) {
4999 printf("Extents block has invalid type (0x%x)\n",
5000 log_eb->type);
5001 return (0);
5002 }
5003 nb = sizeof (extent_block_t) +
5004 (sizeof (extent_t) * (log_eb->nextents - 1));
5005
5006 log_eb = (extent_block_t *)malloc(nb);
5007 if (log_eb == NULL) {
5008 printf("Failed to allocate memory for extent block log\n");
5009 return (0);
5010 }
5011 memcpy(log_eb, b, nb);
5012
5013 if (log_eb->nextbno != 0)
5014 /*
5015 * Currently, as of 11-Dec-1997 the field nextbno isn't
5016 * implemented. If someone starts using this sucker we'd
5017 * better warn somebody.
5018 */
5019 printf("WARNING: extent block field nextbno is non-zero!\n");
5020
5021 /*
5022 * Now read in the on disk log structure. This is always in the
5023 * first block of the first extent.
5024 */
5025 b = getblk((u_offset_t)ldbtob(logbtodb(fs, log_eb->extents[0].pbno)));
5026 log_odi = (ml_odunit_t *)malloc(sizeof (ml_odunit_t));
5027 if (log_odi == NULL) {
5028 free(log_eb);
5029 log_eb = NULL;
5030 printf("Failed to allocate memory for ondisk structure\n");
5031 return (0);
5032 }
5033 memcpy(log_odi, b, sizeof (ml_odunit_t));
5034
5035 /*
5036 * Consistency checks.
5037 */
5038 if (log_odi->od_version != LUFS_VERSION_LATEST) {
5039 free(log_eb);
5040 log_eb = NULL;
5041 free(log_odi);
5042 log_odi = NULL;
5043 printf("Version mismatch in on-disk version of log data\n");
5044 return (0);
5045 } else if (log_odi->od_badlog) {
5046 printf("WARNING: Log was marked as bad\n");
5047 }
5048
5049 return (1);
5050 }
5051
5052 static void
5053 log_display_header(void)
5054 {
5055 int x;
5056 if (!log_get_header_info())
5057 /*
5058 * No need to display anything here. The previous routine
5059 * has already done so.
5060 */
5061 return;
5062
5063 if (fs->fs_magic == FS_MAGIC)
5064 printf("Log block number: 0x%x\n------------------\n",
5065 fs->fs_logbno);
5066 else
5067 printf("Log frag number: 0x%x\n------------------\n",
5068 fs->fs_logbno);
5069 printf("Extent Info\n\t# Extents : %d\n\t# Bytes : 0x%x\n",
5070 log_eb->nextents, log_eb->nbytes);
5071 printf("\tNext Block : 0x%x\n\tExtent List\n\t--------\n",
5072 log_eb->nextbno);
5073 for (x = 0; x < log_eb->nextents; x++)
5074 printf("\t [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n",
5075 x, log_eb->extents[x].lbno, log_eb->extents[x].pbno,
5076 log_eb->extents[x].nbno);
5077 printf("\nOn Disk Info\n\tbol_lof : 0x%08x\n\teol_lof : 0x%08x\n",
5078 log_odi->od_bol_lof, log_odi->od_eol_lof);
5079 printf("\tlog_size : 0x%08x\n",
5080 log_odi->od_logsize);
5081 printf("\thead_lof : 0x%08x\tident : 0x%x\n",
5082 log_odi->od_head_lof, log_odi->od_head_ident);
5083 printf("\ttail_lof : 0x%08x\tident : 0x%x\n\thead_tid : 0x%08x\n",
5084 log_odi->od_tail_lof, log_odi->od_tail_ident, log_odi->od_head_tid);
5085 printf("\tcheck sum : 0x%08x\n", log_odi->od_chksum);
5086 if (log_odi->od_chksum !=
5087 (log_odi->od_head_ident + log_odi->od_tail_ident))
5088 printf("bad checksum: found 0x%08x, should be 0x%08x\n",
5089 log_odi->od_chksum,
5090 log_odi->od_head_ident + log_odi->od_tail_ident);
5091 if (log_odi->od_head_lof == log_odi->od_tail_lof)
5092 printf("\t --- Log is empty ---\n");
5093 }
5094
5095 /*
5096 * log_lodb -- logical log offset to disk block number
5097 */
5098 int
5099 log_lodb(u_offset_t off, diskaddr_t *pblk)
5100 {
5101 uint32_t lblk = (uint32_t)btodb(off);
5102 int x;
5103
5104 if (!log_get_header_info())
5105 /*
5106 * No need to display anything here. The previous routine
5107 * has already done so.
5108 */
5109 return (0);
5110
5111 for (x = 0; x < log_eb->nextents; x++)
5112 if ((lblk >= log_eb->extents[x].lbno) &&
5113 (lblk < (log_eb->extents[x].lbno +
5114 log_eb->extents[x].nbno))) {
5115 *pblk = (diskaddr_t)lblk - log_eb->extents[x].lbno +
5116 logbtodb(fs, log_eb->extents[x].pbno);
5117 return (1);
5118 }
5119 return (0);
5120 }
5121
5122 /*
5123 * String names for the enumerated types. These are only used
5124 * for display purposes.
5125 */
5126 char *dt_str[] = {
5127 "DT_NONE", "DT_SB", "DT_CG", "DT_SI", "DT_AB",
5128 "DT_ABZERO", "DT_DIR", "DT_INODE", "DT_FBI",
5129 "DT_QR", "DT_COMMIT", "DT_CANCEL", "DT_BOT",
5130 "DT_EOT", "DT_UD", "DT_SUD", "DT_SHAD", "DT_MAX"
5131 };
5132
5133 /*
5134 * log_read_log -- transfer information from the log and adjust offset
5135 */
5136 int
5137 log_read_log(u_offset_t *addr, caddr_t va, int nb, uint32_t *chk)
5138 {
5139 int xfer;
5140 caddr_t bp;
5141 diskaddr_t pblk;
5142 sect_trailer_t *st;
5143
5144 while (nb) {
5145 if (!log_lodb(*addr, &pblk)) {
5146 printf("Invalid log offset\n");
5147 return (0);
5148 }
5149
5150 /*
5151 * fsdb getblk() expects offsets not block number.
5152 */
5153 if ((bp = getblk((u_offset_t)dbtob(pblk))) == NULL)
5154 return (0);
5155
5156 xfer = MIN(NB_LEFT_IN_SECTOR(*addr), nb);
5157 if (va != NULL) {
5158 memcpy(va, bp + blkoff(fs, *addr), xfer);
5159 va += xfer;
5160 }
5161 nb -= xfer;
5162 *addr += xfer;
5163
5164 /*
5165 * If the log offset is now at a sector trailer
5166 * run the checks if requested.
5167 */
5168 if (NB_LEFT_IN_SECTOR(*addr) == 0) {
5169 if (chk != NULL) {
5170 st = (sect_trailer_t *)
5171 (bp + blkoff(fs, *addr));
5172 if (*chk != st->st_ident) {
5173 printf(
5174 "Expected sector trailer id 0x%08x, but saw 0x%08x\n",
5175 *chk, st->st_ident);
5176 return (0);
5177 } else {
5178 *chk = st->st_ident + 1;
5179 /*
5180 * We update the on disk structure
5181 * transaction ID each time we see
5182 * one. By comparing this value
5183 * to the last valid DT_COMMIT record
5184 * we can determine if our log is
5185 * completely valid.
5186 */
5187 log_odi->od_head_tid = st->st_tid;
5188 }
5189 }
5190 *addr += sizeof (sect_trailer_t);
5191 }
5192 if ((int32_t)*addr == log_odi->od_eol_lof)
5193 *addr = log_odi->od_bol_lof;
5194 }
5195 return (1);
5196 }
5197
5198 u_offset_t
5199 log_nbcommit(u_offset_t a)
5200 {
5201 /*
5202 * Comments are straight from ufs_log.c
5203 *
5204 * log is the offset following the commit header. However,
5205 * if the commit header fell on the end-of-sector, then lof
5206 * has already been advanced to the beginning of the next
5207 * sector. So do nothgin. Otherwise, return the remaining
5208 * bytes in the sector.
5209 */
5210 if ((a & (DEV_BSIZE - 1)) == 0)
5211 return (0);
5212 else
5213 return (NB_LEFT_IN_SECTOR(a));
5214 }
5215
5216 /*
5217 * log_show -- pretty print the deltas. The number of which is determined
5218 * by the log_enum arg. If LOG_ALLDELTAS the routine, as the
5219 * name implies dumps everything. If LOG_NDELTAS, the routine
5220 * will print out "count" deltas starting at "addr". If
5221 * LOG_CHECKSCAN then run through the log checking the st_ident
5222 * for valid data.
5223 */
5224 static void
5225 log_show(enum log_enum l)
5226 {
5227 struct delta d;
5228 int32_t bol, eol;
5229 int x = 0;
5230 uint32_t chk;
5231
5232 if (!log_get_header_info())
5233 /*
5234 * No need to display any error messages here. The previous
5235 * routine has already done so.
5236 */
5237 return;
5238
5239 bol = log_odi->od_head_lof;
5240 eol = log_odi->od_tail_lof;
5241 chk = log_odi->od_head_ident;
5242
5243 if (bol == eol) {
5244 if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) {
5245 printf("Empty log.\n");
5246 return;
5247 } else
5248 printf("WARNING: empty log. addr may generate bogus"
5249 " information");
5250 }
5251
5252 /*
5253 * Only reset the "addr" if we've been requested to show all
5254 * deltas in the log.
5255 */
5256 if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN))
5257 addr = (u_offset_t)bol;
5258
5259 if (l != LOG_CHECKSCAN) {
5260 printf(" Log Offset Delta Count Type\n");
5261 printf("-----------------------------------------"
5262 "-----------------\n");
5263 }
5264
5265 while ((bol != eol) && ((l == LOG_ALLDELTAS) ||
5266 (l == LOG_CHECKSCAN) || count--)) {
5267 if (!log_read_log(&addr, (caddr_t)&d, sizeof (d),
5268 ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) ?
5269 &chk : NULL))
5270 /*
5271 * Two failures are possible. One from getblk()
5272 * which prints out a message or when we've hit
5273 * an invalid block which may or may not indicate
5274 * an error
5275 */
5276 goto end_scan;
5277
5278 if ((uint32_t)d.d_nb > log_odi->od_logsize) {
5279 printf("Bad delta entry. size out of bounds\n");
5280 return;
5281 }
5282 if (l != LOG_CHECKSCAN)
5283 printf("[%04d] %08x %08x.%08x %08x %s\n", x++, bol,
5284 d.d_mof, d.d_nb,
5285 dt_str[d.d_typ >= DT_MAX ? DT_MAX : d.d_typ]);
5286
5287 switch (d.d_typ) {
5288 case DT_CANCEL:
5289 case DT_ABZERO:
5290 /*
5291 * These two deltas don't have log space
5292 * associated with the entry even though
5293 * d_nb is non-zero.
5294 */
5295 break;
5296
5297 case DT_COMMIT:
5298 /*
5299 * Commit records have zero size yet, the
5300 * rest of the current disk block is avoided.
5301 */
5302 addr += log_nbcommit(addr);
5303 lufs_tid = log_odi->od_head_tid;
5304 lufs_tid_valid = True;
5305 break;
5306
5307 default:
5308 if (!log_read_log(&addr, NULL, d.d_nb,
5309 ((l == LOG_ALLDELTAS) ||
5310 (l == LOG_CHECKSCAN)) ? &chk : NULL))
5311 goto end_scan;
5312 break;
5313 }
5314 bol = (int32_t)addr;
5315 }
5316
5317 end_scan:
5318 if (lufs_tid_valid == True) {
5319 if (lufs_tid == log_odi->od_head_tid)
5320 printf("scan -- okay\n");
5321 else
5322 printf("scan -- some transactions have been lost\n");
5323 } else {
5324 printf("scan -- failed to find a single valid transaction\n");
5325 printf(" (possibly due to an empty log)\n");
5326 }
5327 }