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