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