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