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