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