2 * Copyright 2015 Gary Mills
3 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
7 * Copyright (c) 1988 Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Computer Consoles Inc.
13 * Redistribution and use in source and binary forms are permitted
14 * provided that: (1) source distributions retain this entire copyright
15 * notice and comment, and (2) distributions including binaries display
16 * the following acknowledgement: ``This product includes software
17 * developed by the University of California, Berkeley and its contributors''
18 * in the documentation or other materials provided with the distribution
19 * and in all advertising materials mentioning features or use of this
20 * software. Neither the name of the University nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 "@(#) Copyright(c) 1988 Regents of the University of California.\n\
30 All rights reserved.\n";
33 * fsdb - file system debugger
35 * usage: fsdb [-o suboptions] special
39 * o override some error conditions
40 * p="string" set prompt to string
44 #include <sys/param.h>
45 #include <sys/signal.h>
48 #include <sys/sysmacros.h> /* for MIN */
49 #include <sys/mkdev.h>
57 #include <sys/types.h>
58 #include <sys/vnode.h>
59 #include <sys/mntent.h>
61 #include <sys/fs/ufs_fsdir.h>
62 #include <sys/fs/ufs_fs.h>
63 #include <sys/fs/ufs_inode.h>
64 #include <sys/fs/ufs_acl.h>
65 #include <sys/fs/ufs_log.h>
69 #include <ufs/dinode.h>
76 #define OLD_FSDB_COMPATIBILITY /* To support the obsoleted "-z" option */
79 #define _PATH_BSHELL "/bin/sh"
80 #endif /* _PATH_BSHELL */
82 * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3
85 #ifndef FS_42POSTBLFMT
86 #define cg_blktot(cgp) (((cgp))->cg_btot)
87 #define cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno])
88 #define cg_inosused(cgp) (((cgp))->cg_iused)
89 #define cg_blksfree(cgp) (((cgp))->cg_free)
90 #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC)
94 * Never changing defines.
96 #define OCTAL 8 /* octal base */
97 #define DECIMAL 10 /* decimal base */
98 #define HEX 16 /* hexadecimal base */
101 * Adjustable defines.
103 #define NBUF 10 /* number of cache buffers */
104 #define PROMPTSIZE 80 /* size of user definable prompt */
105 #define MAXFILES 40000 /* max number of files ls can handle */
106 #define FIRST_DEPTH 10 /* default depth for find and ls */
107 #define SECOND_DEPTH 100 /* second try at depth (maximum) */
108 #define INPUTBUFFER 1040 /* size of input buffer */
109 #define BYTESPERLINE 16 /* bytes per line of /dxo output */
110 #define NREG 36 /* number of save registers */
112 #define DEVPREFIX "/dev/" /* Uninteresting part of "special" */
114 #if defined(OLD_FSDB_COMPATIBILITY)
115 #define FSDB_OPTIONS "o:wp:z:"
117 #define FSDB_OPTIONS "o:wp:"
118 #endif /* OLD_FSDB_COMPATIBILITY */
122 * Values dependent on sizes of structs and such.
124 #define NUMB 3 /* these three are arbitrary, */
125 #define BLOCK 5 /* but must be different from */
126 #define FRAGMENT 7 /* the rest (hence odd). */
127 #define BITSPERCHAR 8 /* couldn't find it anywhere */
128 #define CHAR (sizeof (char))
129 #define SHORT (sizeof (short))
130 #define LONG (sizeof (long))
131 #define U_OFFSET_T (sizeof (uoff_t)) /* essentially "long long" */
132 #define INODE (sizeof (struct dinode))
133 #define DIRECTORY (sizeof (struct direct))
134 #define CGRP (sizeof (struct cg))
135 #define SB (sizeof (struct fs))
136 #define BLKSIZE (fs->fs_bsize) /* for clarity */
137 #define FRGSIZE (fs->fs_fsize)
138 #define BLKSHIFT (fs->fs_bshift)
139 #define FRGSHIFT (fs->fs_fshift)
140 #define SHADOW_DATA (sizeof (struct ufs_fsd))
143 * Messy macros that would otherwise clutter up such glamorous code.
145 #define itob(i) (((uoff_t)itod(fs, (i)) << \
146 (uoff_t)FRGSHIFT) + (uoff_t)itoo(fs, (i)) * (uoff_t)INODE)
147 #define min(x, y) ((x) < (y) ? (x) : (y))
148 #define STRINGSIZE(d) ((long)d->d_reclen - \
149 ((long)&d->d_name[0] - (long)&d->d_ino))
150 #define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\
151 (((c) >= 'A')&&((c) <= 'Z')))
152 #define digit(c) (((c) >= '0') && ((c) <= '9'))
153 #define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F'))
154 #define hexletter(c) (((c) >= 'a') && ((c) <= 'f'))
155 #define octaldigit(c) (((c) >= '0') && ((c) <= '7'))
156 #define uppertolower(c) ((c) - 'A' + 'a')
157 #define hextodigit(c) ((c) - 'a' + 10)
158 #define numtodigit(c) ((c) - '0')
161 #define loword(X) (((ushort_t *)&X)[1])
165 #define lobyte(X) (((unsigned char *)&X)[1])
169 * buffer cache structure.
180 * used to hold save registers (see '<' and '>').
182 struct save_registers
{
189 * cd, find, and ls use this to hold filenames. Each filename is broken
190 * up by a slash. In other words, /usr/src/adm would have a len field
191 * of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
192 * src, and adm components of the pathname.
194 static struct filenames
{
195 ino_t ino
; /* inode */
196 long len
; /* number of components */
197 char flag
; /* flag if using SECOND_DEPTH allocator */
198 char find
; /* flag if found by find */
199 char **fname
; /* hold components of pathname */
202 enum log_enum
{ LOG_NDELTAS
, LOG_ALLDELTAS
, LOG_CHECKSCAN
};
206 struct fs un_filesystem
;
207 char un_sbsize
[SBSIZE
];
209 #define filesystem fs_un.un_filesystem
211 struct fs filesystem
, *fs
; /* super block */
217 static char *input_path
[MAXPATHLEN
];
218 static char *stack_path
[MAXPATHLEN
];
219 static char *current_path
[MAXPATHLEN
];
220 static char input_buffer
[INPUTBUFFER
];
222 static char *buffers
;
223 static char scratch
[64];
224 static char BASE
[] = "o u x";
225 static char PROMPT
[PROMPTSIZE
];
226 static char laststyle
= '/';
227 static char lastpo
= 'x';
228 static short input_pointer
;
229 static short current_pathp
;
230 static short stack_pathp
;
231 static short input_pathp
;
232 static short cmp_level
;
234 static short type
= NUMB
;
235 static short dirslot
;
237 static short c_count
;
240 static short trapped
;
241 static short doing_cd
;
242 static short doing_find
;
243 static short find_by_name
;
244 static short find_by_inode
;
245 static short long_list
;
246 static short recursive
;
247 static short objsz
= SHORT
;
248 static short override
= 0;
249 static short wrtflag
= O_RDONLY
;
250 static short base
= HEX
;
251 static short acting_on_inode
;
252 static short acting_on_directory
;
253 static short should_print
= 1;
257 static uoff_t bod_addr
;
259 static uoff_t erraddr
;
260 static long errcur_bytes
;
261 static uoff_t errino
;
263 static long cur_cgrp
;
264 static uoff_t cur_ino
;
265 static long cur_inum
;
266 static uoff_t cur_dir
;
267 static long cur_block
;
268 static long cur_bytes
;
269 static long find_ino
;
270 static uoff_t filesize
;
271 static uoff_t blocksize
;
272 static long stringsize
;
273 static long count
= 1;
274 static long commands
;
275 static long read_requests
;
276 static long actual_disk_reads
;
278 static long maxfiles
;
279 static long cur_shad
;
282 extern char *malloc(), *calloc();
284 static char getachar();
285 static char *getblk(), *fmtentry();
287 static offset_t
get(short);
291 static long getnumb();
292 static uoff_t
getdirslot();
293 static unsigned long *print_check(unsigned long *, long *, short, int);
295 static void usage(char *);
296 static void ungetachar(char);
297 static void getnextinput();
298 static void eat_spaces();
299 static void restore_inode(ino_t
);
301 static void ls(struct filenames
*, struct filenames
*, short);
302 static void formatf(struct filenames
*, struct filenames
*);
304 static void follow_path(long, long);
305 static void getname();
306 static void freemem(struct filenames
*, int);
307 static void print_path(char **, int);
309 static void put(uoff_t
, short);
310 static void insert(struct lbuf
*);
312 static void fprnt(char, char);
314 #ifdef _LARGEFILE64_SOURCE
316 (uoff_t value
, int fieldsz
, int digits
, int lead
);
317 #define print(value, fieldsz, digits, lead) \
318 printll((uoff_t)value, fieldsz, digits, lead)
319 #else /* !_LARGEFILE64_SOURCE */
320 static void print(long value
, int fieldsz
, int digits
, int lead
);
321 #endif /* _LARGEFILE64_SOURCE */
322 static void printsb(struct fs
*);
323 static void printcg(struct cg
*);
324 static void pbits(unsigned char *, int);
325 static void old_fsdb(int, char *); /* For old fsdb functionality */
327 static int isnumber(char *);
328 static int icheck(uoff_t
);
329 static int cgrp_check(long);
330 static int valid_addr();
331 static int match(char *, int);
332 static int devcheck(short);
334 static int compare(char *, char *, short);
335 static int check_addr(short, short *, short *, short);
339 static int getshadowslot(long);
340 static void getshadowdata(long *, int);
341 static void syncshadowscan(int);
342 static void log_display_header(void);
343 static void log_show(enum log_enum
);
351 /* Suboption vector */
352 static char *subopt_v
[] = {
357 #define WRITE_ENABLED 2
365 * main - lines are read up to the unprotected ('\') newline and
366 * held in an input buffer. Characters may be read from the
367 * input buffer using getachar() and unread using ungetachar().
368 * Reading the whole line ahead allows the use of debuggers
369 * which would otherwise be impossible since the debugger
370 * and fsdb could not share stdin.
374 main(int argc
, char *argv
[])
382 volatile short colon
;
386 /* Options/Suboptions processing */
392 * The following are used to support the old fsdb functionality
393 * of clearing an inode. It's better to use 'clri'.
395 int inum
; /* Inode number to clear */
404 while ((opt
= getopt(argc
, argv
, FSDB_OPTIONS
)) != EOF
) {
406 #if defined(OLD_FSDB_COMPATIBILITY)
407 case 'z': /* Hack - Better to use clri */
408 (void) fprintf(stderr
, "%s\n%s\n%s\n%s\n",
409 "Warning: The '-z' option of 'fsdb_ufs' has been declared obsolete",
410 "and may not be supported in a future version of Solaris.",
411 "While this functionality is currently still supported, the",
412 "recommended procedure to clear an inode is to use clri(1M).");
413 if (isnumber(optarg
)) {
415 special
= argv
[optind
];
417 old_fsdb(inum
, special
);
422 /* Should exit() before here */
424 #endif /* OLD_FSDB_COMPATIBILITY */
426 /* UFS Specific Options */
428 while (*subopts
!= '\0') {
429 switch (getsubopt(&subopts
, subopt_v
,
432 printf("error checking off\n");
437 * Change the "-o prompt=foo" option to
438 * "-o p=foo" to match documentation.
439 * ALT_PROMPT continues support for the
440 * undocumented "-o prompt=foo" option so
441 * that we don't break anyone.
445 if (optval
== NULL
) {
446 (void) fprintf(stderr
,
447 "No prompt string\n");
450 (void) strncpy(PROMPT
, optval
,
455 /* suitable for open */
461 /* Should exit here */
471 if ((argc
- optind
) != 1) { /* Should just have "special" left */
474 special
= argv
[optind
];
477 * Unless it's already been set, the default prompt includes the
478 * name of the special device.
481 (void) sprintf(prompt
, "%s > ", special
);
484 * Attempt to open the special file.
486 if ((fd
= open(special
, wrtflag
)) < 0) {
491 * Read in the super block and validate (not too picky).
493 if (llseek(fd
, (offset_t
)(SBLOCK
* DEV_BSIZE
), 0) == -1) {
499 if (read(fd
, &filesystem
, SBSIZE
) != SBSIZE
) {
500 printf("%s: cannot read superblock\n", special
);
504 if (read(fd
, &filesystem
, sizeof (filesystem
)) != sizeof (filesystem
)) {
505 printf("%s: cannot read superblock\n", special
);
511 if ((fs
->fs_magic
!= FS_MAGIC
) && (fs
->fs_magic
!= MTB_UFS_MAGIC
)) {
513 printf("%s: Bad magic number in file system\n",
518 printf("WARNING: Bad magic number in file system. ");
519 printf("Continue? (y/n): ");
520 (void) fflush(stdout
);
521 if (gets(input_buffer
) == NULL
) {
525 if (*input_buffer
!= 'y' && *input_buffer
!= 'Y') {
530 if ((fs
->fs_magic
== FS_MAGIC
&&
531 (fs
->fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2
&&
532 fs
->fs_version
!= UFS_VERSION_MIN
)) ||
533 (fs
->fs_magic
== MTB_UFS_MAGIC
&&
534 (fs
->fs_version
> MTB_UFS_VERSION_1
||
535 fs
->fs_version
< MTB_UFS_VERSION_MIN
))) {
537 printf("%s: Unrecognized UFS version number: %d\n",
538 special
, fs
->fs_version
);
542 printf("WARNING: Unrecognized UFS version number. ");
543 printf("Continue? (y/n): ");
544 (void) fflush(stdout
);
545 if (gets(input_buffer
) == NULL
) {
549 if (*input_buffer
!= 'y' && *input_buffer
!= 'Y') {
553 #ifdef FS_42POSTBLFMT
554 if (fs
->fs_postblformat
== FS_42POSTBLFMT
)
557 printf("fsdb of %s %s -- last mounted on %s\n",
559 (wrtflag
== O_RDWR
) ? "(Opened for write)" : "(Read only)",
562 printf("fs_clean is currently set to ");
563 switch (fs
->fs_clean
) {
566 printf("FSACTIVE\n");
572 printf("FSSTABLE\n");
578 printf("FSSUSPEND\n");
586 printf("%s: fsck may be running on this file system\n",
591 printf("WARNING: fsck may be running on this file system. ");
592 printf("Continue? (y/n): ");
593 (void) fflush(stdout
);
594 if (gets(input_buffer
) == NULL
) {
598 if (*input_buffer
!= 'y' && *input_buffer
!= 'Y') {
603 printf("an unknown value (0x%x)\n", fs
->fs_clean
);
607 if (fs
->fs_state
== (FSOKAY
- fs
->fs_time
)) {
608 printf("fs_state consistent (fs_clean CAN be trusted)\n");
610 printf("fs_state inconsistent (fs_clean CAN'T trusted)\n");
614 * Malloc buffers and set up cache.
616 buffers
= malloc(NBUF
* BLKSIZE
);
617 bhdr
.fwd
= bhdr
.back
= &bhdr
;
618 for (i
= 0; i
< NBUF
; i
++) {
620 bp
->blkaddr
= buffers
+ (i
* BLKSIZE
);
625 * Malloc filenames structure. The space for the actual filenames
626 * is allocated as it needs it. We estimate the size based on the
627 * number of inodes(objects) in the filesystem and the number of
628 * directories. The number of directories are padded by 3 because
629 * each directory traversed during a "find" or "ls -R" needs 3
632 maxfiles
= (long)((((uoff_t
)fs
->fs_ncg
* (uoff_t
)fs
->fs_ipg
) -
633 (uoff_t
)fs
->fs_cstotal
.cs_nifree
) +
634 ((uoff_t
)fs
->fs_cstotal
.cs_ndir
* (uoff_t
)3));
636 filenames
= (struct filenames
*)calloc(maxfiles
,
637 sizeof (struct filenames
));
638 if (filenames
== NULL
) {
640 * If we could not allocate memory for all of files
641 * in the filesystem then, back off to the old fixed
645 filenames
= (struct filenames
*)calloc(maxfiles
,
646 sizeof (struct filenames
));
647 if (filenames
== NULL
) {
648 printf("out of memory\n");
655 * Malloc a few filenames (needed by pwd for example).
657 for (i
= 0; i
< MAXPATHLEN
; i
++) {
658 input_path
[i
] = calloc(1, MAXNAMLEN
);
659 stack_path
[i
] = calloc(1, MAXNAMLEN
);
660 current_path
[i
] = calloc(1, MAXNAMLEN
);
661 if (current_path
[i
] == NULL
) {
662 printf("out of memory\n");
668 (void) signal(2, err
);
673 * Main loop and case statement. If an error condition occurs
674 * initialization and recovery is attempted.
678 freemem(filenames
, nfiles
);
686 acting_on_directory
= 0;
691 cur_bytes
= errcur_bytes
;
699 switch (c
= getachar()) {
701 case '\n': /* command end */
702 freemem(filenames
, nfiles
);
704 if (should_print
&& laststyle
== '=') {
714 errcur_bytes
= cur_bytes
;
717 if ((addr
= getdirslot(
718 (long)dirslot
+1)) == 0)
727 addr
= itob(cur_inum
);
736 addr
= cgrp_check(cur_cgrp
);
743 if ((addr
= getshadowslot(
744 (long)cur_shad
+ 1)) == 0)
754 if (valid_addr() == 0)
782 fprnt(laststyle
, lastpo
);
788 c_count
= colon
= acting_on_inode
= 0;
789 acting_on_directory
= 0;
797 errcur_bytes
= cur_bytes
;
800 case '(': /* numeric expression or unknown command */
803 if (digit(c
) || c
== '(') {
810 printf("unknown command or bad syntax\n");
814 case '?': /* general print facilities */
816 fprnt(c
, getachar());
819 case ';': /* command separator and . */
825 case ':': /* command indicator */
833 case ',': /* count indicator */
835 if ((c
= getachar()) == '*') {
849 case '+': /* address addition */
861 errcur_bytes
= cur_bytes
;
864 addr
= getdirslot((long)(dirslot
+ temp
));
870 addr
= itob(cur_inum
);
879 if ((addr
= cgrp_check(cur_cgrp
)) == 0) {
885 addr
= getshadowslot((long)(cur_shad
+ temp
));
892 addr
+= temp
* objsz
;
893 cur_bytes
+= temp
* objsz
;
894 if (valid_addr() == 0)
900 case '-': /* address subtraction */
912 errcur_bytes
= cur_bytes
;
915 addr
= getdirslot((long)(dirslot
- temp
));
921 addr
= itob(cur_inum
);
930 if ((addr
= cgrp_check(cur_cgrp
)) == 0) {
936 addr
= getshadowslot((long)(cur_shad
- temp
));
942 addr
-= temp
* objsz
;
943 cur_bytes
-= temp
* objsz
;
944 if (valid_addr() == 0)
950 case '*': /* address multiplication */
955 if (objsz
!= INODE
&& objsz
!= DIRECTORY
)
961 case '%': /* address division */
967 printf("divide by zero\n");
971 if (objsz
!= INODE
&& objsz
!= DIRECTORY
)
977 case '=': { /* assignment operation */
986 if (acting_on_inode
== 1) {
987 if (c
!= 'o' && c
!= 'd' && c
!= 'x' &&
988 c
!= 'O' && c
!= 'D' && c
!= 'X') {
1001 if (acting_on_inode
== 2)
1004 } else if (acting_on_inode
)
1006 should_print
= star
= 0;
1009 errcur_bytes
= cur_bytes
;
1011 case '"': /* character string */
1013 blocksize
= BLKSIZE
;
1014 filesize
= BLKSIZE
* 2;
1015 cur_bytes
= blkoff(fs
, addr
);
1016 if (objsz
== DIRECTORY
||
1022 case '+': /* =+ operator */
1026 put(value
+temp
, objsz
);
1028 case '-': /* =- operator */
1032 put(value
-temp
, objsz
);
1054 * Truncation is intentional so
1057 time_t tvalue
= (time_t)value
;
1058 printf("%s", ctime(&tvalue
));
1065 if (objsz
== DIRECTORY
) {
1077 if (acting_on_inode
)
1078 print(value
& 0177777L, 12, -8, 0);
1080 print(addr
& 0177777L, 12, -8, 0);
1095 if (acting_on_inode
)
1096 print(value
, 12, -8, 0);
1098 print(addr
, 12, -8, 0);
1102 default: /* regular assignment */
1106 printf("syntax error\n");
1113 case '>': /* save current address */
1117 if (!letter(c
) && !digit(c
)) {
1118 printf("invalid register specification, ");
1119 printf("must be letter or digit\n");
1125 c
= uppertolower(c
);
1129 regs
[c
].sv_addr
= addr
;
1130 regs
[c
].sv_value
= value
;
1131 regs
[c
].sv_objsz
= objsz
;
1134 case '<': /* restore saved address */
1138 if (!letter(c
) && !digit(c
)) {
1139 printf("invalid register specification, ");
1140 printf("must be letter or digit\n");
1146 c
= uppertolower(c
);
1150 addr
= regs
[c
].sv_addr
;
1151 value
= regs
[c
].sv_value
;
1152 objsz
= regs
[c
].sv_objsz
;
1160 if (match("at", 2)) { /* access time */
1161 acting_on_inode
= 2;
1163 addr
= (long)&((struct dinode
*)
1164 (uintptr_t)cur_ino
)->di_atime
;
1176 if (match("block", 2)) { /* block conversion */
1180 blocksize
= BLKSIZE
;
1181 filesize
= BLKSIZE
* 2;
1183 addr
= value
<< FRGSHIFT
;
1191 if (match("bs", 2)) { /* block size */
1192 acting_on_inode
= 1;
1194 if (icheck(cur_ino
) == 0)
1196 addr
= (long)&((struct dinode
*)
1197 (uintptr_t)cur_ino
)->di_blocks
;
1202 if (match("base", 2)) { /* change/show base */
1204 if ((c
= getachar()) == '\n') {
1206 printf("base =\t\t");
1212 printf("DECIMAL\n");
1220 printf("missing '='\n");
1227 printf("invalid base\n");
1233 base
= (short)value
;
1244 if (match("cd", 2)) { /* change directory */
1245 top
= filenames
- 1;
1247 if ((c
= getachar()) == '\n') {
1259 restore_inode((ino_t
)temp
);
1261 print_path(input_path
,
1264 printf(" not found\n");
1266 printf(" ambiguous\n");
1271 restore_inode(filenames
->ino
);
1272 if ((mode
= icheck(addr
)) == 0)
1274 if ((mode
& IFMT
) != IFDIR
) {
1275 restore_inode((ino_t
)temp
);
1276 print_path(input_path
,
1278 printf(" not a directory\n");
1282 for (i
= 0; i
<= top
->len
; i
++)
1283 (void) strcpy(current_path
[i
],
1285 current_pathp
= top
->len
;
1288 if (match("cg", 2)) { /* cylinder group */
1291 if (value
> fs
->fs_ncg
- 1) {
1292 printf("maximum cylinder group is ");
1293 print(fs
->fs_ncg
- 1, 8, -8, 0);
1298 type
= objsz
= CGRP
;
1299 cur_cgrp
= (long)value
;
1300 addr
= cgtod(fs
, cur_cgrp
) << FRGSHIFT
;
1303 if (match("ct", 2)) { /* creation time */
1304 acting_on_inode
= 2;
1306 addr
= (long)&((struct dinode
*)
1307 (uintptr_t)cur_ino
)->di_ctime
;
1319 if (match("directory", 2)) { /* directory offsets */
1324 addr
= (uoff_t
)getdirslot((long)value
);
1327 if (match("db", 2)) { /* direct block */
1328 acting_on_inode
= 1;
1332 if (value
>= NDADDR
) {
1333 printf("direct blocks are 0 to ");
1334 print(NDADDR
- 1, 0, 0, 0);
1343 &((struct dinode
*)(uintptr_t)cur_ino
)->
1346 cur_bytes
= (value
) * BLKSIZE
;
1347 cur_block
= (long)value
;
1351 if (!value
&& !override
) {
1352 printf("non existent block\n");
1364 if (match("find", 3)) { /* find command */
1368 if (match("fragment", 2)) { /* fragment conv. */
1372 blocksize
= FRGSIZE
;
1373 filesize
= FRGSIZE
* 2;
1375 if (min(blocksize
, filesize
) - cur_bytes
>
1377 blocksize
= cur_bytes
+ FRGSIZE
;
1378 filesize
= blocksize
* 2;
1380 addr
= value
<< FRGSHIFT
;
1388 if (match("file", 4)) { /* access as file */
1389 acting_on_inode
= 1;
1394 if ((mode
= icheck(addr
)) == 0)
1397 switch (mode
& IFMT
) {
1400 printf("special device\n");
1405 if ((addr
= (uoff_t
)
1406 (bmap((long)value
) << FRGSHIFT
)) == 0)
1408 cur_block
= (long)value
;
1414 if (match("fill", 4)) { /* fill */
1415 if (getachar() != '=') {
1416 printf("missing '='\n");
1420 if (objsz
== INODE
|| objsz
== DIRECTORY
||
1421 objsz
== SHADOW_DATA
) {
1423 "can't fill inode or directory\n");
1437 if (match("gid", 1)) { /* group id */
1438 acting_on_inode
= 1;
1440 addr
= (long)&((struct dinode
*)
1441 (uintptr_t)cur_ino
)->di_gid
;
1453 if (match("inode", 2)) { /* i# to inode conversion */
1469 cur_inum
= (long)value
;
1474 if (match("ib", 2)) { /* indirect block */
1475 acting_on_inode
= 1;
1479 if (value
>= NIADDR
) {
1480 printf("indirect blocks are 0 to ");
1481 print(NIADDR
- 1, 0, 0, 0);
1486 addr
= (long)&((struct dinode
*)(uintptr_t)
1487 cur_ino
)->di_ib
[value
];
1488 cur_bytes
= (NDADDR
- 1) * BLKSIZE
;
1490 for (i
= 0; i
< value
; i
++) {
1491 temp
*= NINDIR(fs
) * BLKSIZE
;
1497 if (!value
&& !override
) {
1498 printf("non existent block\n");
1510 if (match("log_head", 8)) {
1511 log_display_header();
1515 if (match("log_delta", 9)) {
1516 log_show(LOG_NDELTAS
);
1520 if (match("log_show", 8)) {
1521 log_show(LOG_ALLDELTAS
);
1525 if (match("log_chk", 7)) {
1526 log_show(LOG_CHECKSCAN
);
1530 if (match("log_otodb", 9)) {
1531 if (log_lodb((uoff_t
)addr
, &temp
)) {
1539 if (match("ls", 2)) { /* ls command */
1541 recursive
= long_list
= 0;
1542 top
= filenames
- 1;
1545 if ((c
= getachar()) == '-') {
1546 if ((c
= getachar()) == 'R') {
1549 } else if (c
== 'l') {
1554 printf("'%c'\n", c
);
1560 if ((c
= getachar()) == '\n') {
1569 restore_inode((ino_t
)temp
);
1574 if (error
|| nfiles
== 0) {
1576 print_path(input_path
,
1578 printf(" not found\n");
1584 qsort((char *)filenames
, nfiles
,
1585 sizeof (struct filenames
), ffcmp
);
1586 ls(filenames
, filenames
+ (nfiles
- 1), 0);
1588 printf("no match\n");
1591 restore_inode((ino_t
)temp
);
1594 if (match("ln", 2)) { /* link count */
1595 acting_on_inode
= 1;
1597 addr
= (long)&((struct dinode
*)
1598 (uintptr_t)cur_ino
)->di_nlink
;
1611 if ((mode
= icheck(addr
)) == 0)
1613 if (match("mt", 2)) { /* modification time */
1614 acting_on_inode
= 2;
1616 addr
= (long)&((struct dinode
*)
1617 (uintptr_t)cur_ino
)->di_mtime
;
1622 if (match("md", 2)) { /* mode */
1623 acting_on_inode
= 1;
1625 addr
= (long)&((struct dinode
*)
1626 (uintptr_t)cur_ino
)->di_mode
;
1631 if (match("maj", 2)) { /* major device number */
1632 acting_on_inode
= 1;
1636 addr
= (uintptr_t)&((struct dinode
*)(uintptr_t)
1641 value
= major(dvalue
);
1646 if (match("min", 2)) { /* minor device number */
1647 acting_on_inode
= 1;
1651 addr
= (uintptr_t)&((struct dinode
*)(uintptr_t)
1655 dvalue
= (long)get(LONG
);
1656 value
= minor(dvalue
);
1668 if (match("nm", 1)) { /* directory name */
1670 acting_on_directory
= 1;
1672 if ((cptr
= getblk(addr
)) == 0)
1675 dirp
= (struct direct
*)(cptr
+blkoff(fs
, addr
));
1676 stringsize
= (long)dirp
->d_reclen
-
1677 ((long)&dirp
->d_name
[0] -
1678 (long)&dirp
->d_ino
);
1679 addr
= (long)&((struct direct
*)
1680 (uintptr_t)addr
)->d_name
[0];
1691 if (match("override", 1)) { /* override flip flop */
1692 override
= !override
;
1694 printf("error checking off\n");
1696 printf("error checking on\n");
1706 if (match("pwd", 2)) { /* print working dir */
1707 print_path(current_path
, (int)current_pathp
);
1711 if (match("prompt", 2)) { /* change prompt */
1712 if ((c
= getachar()) != '=') {
1713 printf("missing '='\n");
1717 if ((c
= getachar()) != '"') {
1718 printf("missing '\"'\n");
1723 prompt
= &prompt
[0];
1724 while ((c
= getachar()) != '"' && c
!= '\n') {
1726 if (i
>= PROMPTSIZE
) {
1727 printf("string too long\n");
1740 if (match("quit", 1)) { /* quit */
1741 if ((c
= getachar()) != '\n') {
1754 if (match("sb", 2)) { /* super block */
1765 if (value
> fs
->fs_ncg
- 1) {
1766 printf("maximum super block is ");
1767 print(fs
->fs_ncg
- 1, 8, -8, 0);
1773 cur_cgrp
= (long)value
;
1774 addr
= cgsblock(fs
, cur_cgrp
) << FRGSHIFT
;
1777 if (match("shadow", 2)) { /* shadow inode data */
1780 objsz
= SHADOW_DATA
;
1782 addr
= getshadowslot(value
);
1785 if (match("si", 2)) { /* shadow inode field */
1786 acting_on_inode
= 1;
1788 addr
= (long)&((struct dinode
*)
1789 (uintptr_t)cur_ino
)->di_shadow
;
1795 if (match("sz", 2)) { /* file size */
1796 acting_on_inode
= 1;
1798 addr
= (long)&((struct dinode
*)
1799 (uintptr_t)cur_ino
)->di_size
;
1800 value
= get(U_OFFSET_T
);
1814 if (match("uid", 1)) { /* user id */
1815 acting_on_inode
= 1;
1817 addr
= (long)&((struct dinode
*)
1818 (uintptr_t)cur_ino
)->di_uid
;
1825 case 'F': /* buffer status (internal use only) */
1830 for (bp
= bhdr
.fwd
; bp
!= &bhdr
; bp
= bp
->fwd
)
1831 printf("%8" PRIx64
" %d\n",
1832 bp
->blkno
, bp
->valid
);
1834 printf("# commands\t\t%ld\n", commands
);
1835 printf("# read requests\t\t%ld\n", read_requests
);
1836 printf("# actual disk reads\t%ld\n", actual_disk_reads
);
1839 printf("a colon should precede a command\n");
1843 printf("more letters needed to distinguish command\n");
1851 * usage - print usage and exit
1854 usage(char *progname
)
1856 printf("usage: %s [options] special\n", progname
);
1857 printf("options:\n");
1858 printf("\t-o Specify ufs filesystem sepcific options\n");
1859 printf(" Available suboptions are:\n");
1860 printf("\t\t? display usage\n");
1861 printf("\t\to override some error conditions\n");
1862 printf("\t\tp=\"string\" set prompt to string\n");
1863 printf("\t\tw open for write\n");
1868 * getachar - get next character from input buffer.
1873 return (input_buffer
[input_pointer
++]);
1877 * ungetachar - return character to input buffer.
1882 if (input_pointer
== 0) {
1883 printf("internal problem maintaining input buffer\n");
1887 input_buffer
[--input_pointer
] = c
;
1891 * getnextinput - display the prompt and read an input line.
1892 * An input line is up to 128 characters terminated by the newline
1893 * character. Handle overflow, shell escape, and eof.
1905 printf("%s", prompt
);
1907 while ((c
= getc(stdin
)) != '\n' && !(c
== '!' && i
== 0) &&
1908 !feof(stdin
) && i
<= INPUTBUFFER
- 2)
1909 input_buffer
[i
++] = c
;
1910 if (i
> 0 && input_buffer
[i
- 1] == '\\') {
1911 input_buffer
[i
++] = c
;
1919 if ((pid
= fork()) == 0) {
1920 (void) execl(_PATH_BSHELL
, "sh", "-t", 0);
1924 while ((rpid
= wait(&retcode
)) != pid
&& rpid
!= -1)
1930 printf("input truncated to 128 characters\n");
1931 input_buffer
[i
] = '\n';
1936 * eat_spaces - read extraneous spaces.
1943 while ((c
= getachar()) == ' ')
1949 * restore_inode - set up all inode indicators so inum is now
1950 * the current inode.
1953 restore_inode(ino_t inum
)
1955 errinum
= cur_inum
= inum
;
1956 addr
= errino
= cur_ino
= itob(inum
);
1960 * match - return false if the input does not match string up to
1961 * upto letters. Then proceed to chew up extraneous letters.
1964 match(char *string
, int upto
)
1966 int i
, length
= strlen(string
) - 1;
1968 int save_upto
= upto
;
1972 if ((c
= getachar()) != *string
) {
1973 for (i
= save_upto
- upto
; i
; i
--) {
1983 if ((c
= getachar()) != *string
) {
1992 * expr - expression evaluator. Will evaluate expressions from
1993 * left to right with no operator precedence. Parentheses may
1999 long numb
= 0, temp
;
2005 return (~0); /* error is set so value is ignored */
2024 printf("divide by zero\n");
2037 if (paren
&& !error
) {
2038 printf("missing ')'\n");
2047 * term - used by expression evaluator to get an operand.
2054 switch (c
= getachar()) {
2063 return (-getnumb());
2072 * getnumb - read a number from the input stream. A leading
2073 * zero signifies octal interpretation, a leading '0x'
2074 * signifies hexadecimal, and a leading '0t' signifies
2075 * decimal. If the first character is a character,
2083 long number
= 0, tbase
, num
;
2094 if ((c
= getachar()) == 'x')
2105 c
= savec
= getachar();
2107 c
= uppertolower(c
);
2111 num
= hextodigit(c
);
2117 num
= numtodigit(c
);
2121 num
= numtodigit(c
);
2125 number
= number
* tbase
+ num
;
2132 * find - the syntax is almost identical to the unix command.
2133 * find dir [-name pattern] [-inum number]
2134 * Note: only one of -name or -inum may be used at a time.
2135 * Also, the -print is not needed (implied).
2140 struct filenames
*fn
;
2147 top
= filenames
- 1;
2152 restore_inode((ino_t
)temp
);
2154 print_path(input_path
, (int)input_pathp
);
2156 printf(" not found\n");
2158 printf(" ambiguous\n");
2163 restore_inode(filenames
->ino
);
2164 freemem(filenames
, nfiles
);
2166 top
= filenames
- 1;
2167 if ((mode
= icheck(addr
)) == 0)
2169 if ((mode
& IFMT
) != IFDIR
) {
2170 print_path(input_path
, (int)input_pathp
);
2171 printf(" not a directory\n");
2176 if ((c
= getachar()) != '-') {
2177 restore_inode((ino_t
)temp
);
2178 printf("missing '-'\n");
2182 find_by_name
= find_by_inode
= 0;
2184 if (match("name", 4)) {
2187 } else if (match("inum", 4)) {
2191 restore_inode((ino_t
)temp
);
2194 while ((c
= getachar()) != '\n')
2199 restore_inode((ino_t
)temp
);
2200 printf("use -name or -inum with find\n");
2208 restore_inode((ino_t
)temp
);
2211 for (fn
= filenames
; fn
<= top
; fn
++) {
2215 print(fn
->ino
, 12, -8, 0);
2216 print_path(fn
->fname
, (int)fn
->len
);
2219 restore_inode((ino_t
)temp
);
2223 * ls - do an ls. Should behave exactly as ls(1).
2224 * Only -R and -l is supported and -l gives different results.
2227 ls(struct filenames
*fn0
, struct filenames
*fnlast
, short level
)
2229 struct filenames
*fn
, *fnn
;
2236 qsort((char *)fn0
, fnlast
- fn0
+ 1,
2237 sizeof (struct filenames
), fcmp
);
2239 for (fnn
= fn
, fn
++; fn
<= fnlast
; fnn
= fn
, fn
++) {
2240 if (fnn
->len
!= fn
->len
&& level
== fnn
->len
- 1)
2244 if (strcmp(fn
->fname
[level
], fnn
->fname
[level
]))
2247 if (fn0
->len
&& level
!= fn0
->len
- 1)
2248 ls(fn0
, fnn
, level
+ 1);
2250 if (fn0
!= filenames
)
2252 print_path(fn0
->fname
, (int)(fn0
->len
- 1));
2257 cmp_level
= level
+ 1;
2258 qsort((char *)fn0
, fnn
- fn0
+ 1,
2259 sizeof (struct filenames
), fcmp
);
2261 nfiles
-= fnn
- fn0
+ 1;
2269 * formatf - code lifted from ls.
2272 formatf(struct filenames
*fn0
, struct filenames
*fnlast
)
2274 struct filenames
*fn
;
2275 int width
= 0, w
, nentry
= fnlast
- fn0
+ 1;
2276 int i
, j
, columns
, lines
;
2282 for (fn
= fn0
; fn
<= fnlast
; fn
++) {
2283 int len
= strlen(fn
->fname
[cmp_level
]) + 2;
2288 width
= (width
+ 8) &~ 7;
2289 columns
= 80 / width
;
2293 lines
= (nentry
+ columns
- 1) / columns
;
2294 for (i
= 0; i
< lines
; i
++) {
2295 for (j
= 0; j
< columns
; j
++) {
2296 fn
= fn0
+ j
* lines
+ i
;
2299 print(fn
->ino
, 12, -8, 0);
2301 if ((cp
= fmtentry(fn
)) == NULL
) {
2302 printf("cannot read inode %ld\n", fn
->ino
);
2306 if (fn
+ lines
> fnlast
) {
2313 (void) putchar('\t');
2320 * fmtentry - code lifted from ls.
2323 fmtentry(struct filenames
*fn
)
2325 static char fmtres
[BUFSIZ
];
2327 char *cptr
, *cp
, *dp
;
2330 for (cp
= fn
->fname
[cmp_level
]; *cp
; cp
++) {
2331 if (*cp
< ' ' || *cp
>= 0177)
2336 addr
= itob(fn
->ino
);
2337 if ((cptr
= getblk(addr
)) == 0)
2339 cptr
+= blkoff(fs
, addr
);
2341 ip
= (struct dinode
*)cptr
;
2342 switch (ip
->di_mode
& IFMT
) {
2360 if (ip
->di_mode
& 0111)
2374 * fcmp - routine used by qsort. Will sort first by name, then
2375 * then by pathname length if names are equal. Uses global
2376 * cmp_level to tell what component of the path name we are comparing.
2379 fcmp(struct filenames
*f1
, struct filenames
*f2
)
2383 if ((value
= strcmp(f1
->fname
[cmp_level
], f2
->fname
[cmp_level
])))
2385 return (f1
->len
- f2
->len
);
2389 * ffcmp - routine used by qsort. Sort only by pathname length.
2392 ffcmp(struct filenames
*f1
, struct filenames
*f2
)
2394 return (f1
->len
- f2
->len
);
2398 * parse - set up the call to follow_path.
2406 stack_pathp
= input_pathp
= -1;
2407 if ((c
= getachar()) == '/') {
2408 while ((c
= getachar()) == '/')
2413 if ((c
== '\n') || ((doing_cd
) && (c
== ' '))) {
2426 stack_pathp
= current_pathp
;
2428 input_pathp
= current_pathp
;
2429 for (i
= 0; i
<= current_pathp
; i
++) {
2431 (void) strcpy(input_path
[i
], current_path
[i
]);
2432 (void) strcpy(stack_path
[i
], current_path
[i
]);
2436 follow_path((long)(stack_pathp
+ 1), cur_inum
);
2440 * follow_path - called by cd, find, and ls.
2441 * input_path holds the name typed by the user.
2442 * stack_path holds the name at the current depth.
2445 follow_path(long level
, long inum
)
2447 struct direct
*dirp
;
2448 char **ccptr
, *cptr
;
2450 struct filenames
*tos
, *bos
, *fn
, *fnn
, *fnnn
;
2455 restore_inode((ino_t
)inum
);
2456 if ((mode
= icheck(addr
)) == 0)
2458 if ((mode
& IFMT
) != IFDIR
)
2460 block
= cur_bytes
= 0;
2461 while (cur_bytes
< filesize
) {
2462 if (block
== 0 || bcomp(addr
)) {
2464 if ((addr
= ((uoff_t
)bmap(block
++) <<
2465 (uoff_t
)FRGSHIFT
)) == 0)
2467 if ((cptr
= getblk(addr
)) == 0)
2469 cptr
+= blkoff(fs
, addr
);
2472 dirp
= (struct direct
*)cptr
;
2474 if (level
> input_pathp
|| doing_find
||
2475 compare(input_path
[level
], &dirp
->d_name
[0], 1)) {
2477 ((strcmp(dirp
->d_name
, ".") == 0 ||
2478 strcmp(dirp
->d_name
, "..") == 0)))
2480 if (++top
- filenames
>= maxfiles
) {
2481 printf("too many files\n");
2485 top
->fname
= (char **)calloc(FIRST_DEPTH
, sizeof (char **));
2487 if (top
->fname
== 0) {
2488 printf("out of memory\n");
2493 top
->ino
= dirp
->d_ino
;
2494 top
->len
= stack_pathp
;
2498 if (compare(input_path
[0], &dirp
->d_name
[0], 1))
2500 } else if (find_by_inode
)
2501 if (find_ino
== dirp
->d_ino
)
2504 if (top
->len
+ 1 >= FIRST_DEPTH
&& top
->flag
== 0) {
2505 ccptr
= (char **)calloc(SECOND_DEPTH
, sizeof (char **));
2507 printf("out of memory\n");
2511 for (i
= 0; i
< FIRST_DEPTH
; i
++)
2512 ccptr
[i
] = top
->fname
[i
];
2513 free((char *)top
->fname
);
2517 if (top
->len
>= SECOND_DEPTH
) {
2518 printf("maximum depth exceeded, try to cd lower\n");
2523 * Copy current depth.
2525 for (i
= 0; i
<= stack_pathp
; i
++) {
2526 top
->fname
[i
] = calloc(1, strlen(stack_path
[i
])+1);
2527 if (top
->fname
[i
] == 0) {
2528 printf("out of memory\n");
2532 (void) strcpy(top
->fname
[i
], stack_path
[i
]);
2535 * Check for '.' or '..' typed.
2537 if ((level
<= input_pathp
) &&
2538 (strcmp(input_path
[level
], ".") == 0 ||
2539 strcmp(input_path
[level
], "..") == 0)) {
2540 if (strcmp(input_path
[level
], "..") == 0 &&
2542 free(top
->fname
[top
->len
]);
2547 * Check for duplicates.
2549 if (!doing_cd
&& !doing_find
) {
2550 for (fn
= filenames
; fn
< top
; fn
++) {
2551 if (fn
->ino
== dirp
->d_ino
&&
2552 fn
->len
== stack_pathp
+ 1) {
2553 for (i
= 0; i
< fn
->len
; i
++)
2554 if (strcmp(fn
->fname
[i
], stack_path
[i
]))
2557 strcmp(fn
->fname
[i
], dirp
->d_name
))
2560 if (top
== filenames
)
2570 top
->fname
[top
->len
] = calloc(1,
2571 strlen(&dirp
->d_name
[0])+1);
2572 if (top
->fname
[top
->len
] == 0) {
2573 printf("out of memory\n");
2577 (void) strcpy(top
->fname
[top
->len
], &dirp
->d_name
[0]);
2582 addr
+= dirp
->d_reclen
;
2583 cptr
+= dirp
->d_reclen
;
2584 cur_bytes
+= dirp
->d_reclen
;
2586 if (top
< filenames
)
2588 if ((doing_cd
&& level
== input_pathp
) ||
2589 (!recursive
&& !doing_find
&& level
> input_pathp
))
2593 * Check newly added entries to determine if further expansion
2596 for (fn
= tos
; fn
<= bos
; fn
++) {
2598 * Avoid '.' and '..' if beyond input.
2600 if ((recursive
|| doing_find
) && (level
> input_pathp
) &&
2601 (strcmp(fn
->fname
[fn
->len
], ".") == 0 ||
2602 strcmp(fn
->fname
[fn
->len
], "..") == 0))
2604 restore_inode(fn
->ino
);
2605 if ((mode
= icheck(cur_ino
)) == 0)
2607 if ((mode
& IFMT
) == IFDIR
|| level
< input_pathp
) {
2609 * Set up current depth, remove current entry and
2610 * continue recursion.
2612 for (i
= 0; i
<= fn
->len
; i
++)
2613 (void) strcpy(stack_path
[i
], fn
->fname
[i
]);
2614 stack_pathp
= fn
->len
;
2616 (!recursive
|| (recursive
&& level
<= input_pathp
))) {
2618 * Remove current entry by moving others up.
2622 for (fnnn
= fnn
, fnn
++; fnn
<= top
; fnnn
= fnn
, fnn
++) {
2623 fnnn
->ino
= fnn
->ino
;
2624 fnnn
->len
= fnn
->len
;
2625 if (fnnn
->len
+ 1 < FIRST_DEPTH
) {
2626 fnnn
->fname
= (char **)calloc(FIRST_DEPTH
,
2629 } else if (fnnn
->len
< SECOND_DEPTH
) {
2630 fnnn
->fname
= (char **)calloc(SECOND_DEPTH
,
2634 printf("maximum depth exceeded, ");
2635 printf("try to cd lower\n");
2639 for (i
= 0; i
<= fnn
->len
; i
++)
2640 fnnn
->fname
[i
] = fnn
->fname
[i
];
2648 follow_path(level
+ 1, cur_inum
);
2656 * getname - break up the pathname entered by the user into components.
2664 if ((c
= getachar()) == '\n') {
2671 for (i
= 0; i
< MAXNAMLEN
; i
++)
2672 input_path
[input_pathp
][i
] = '\0';
2676 if ((int)strlen(input_path
[input_pathp
]) + 1 >= MAXNAMLEN
) {
2677 printf("maximum name length exceeded, ");
2678 printf("truncating\n");
2681 input_path
[input_pathp
][strlen(input_path
[input_pathp
])] = c
;
2682 input_path
[input_pathp
][strlen(input_path
[input_pathp
])] =
2686 if (c
== ' ' || c
== '\n') {
2690 if (!doing_find
&& c
== '/') {
2691 if (++input_pathp
>= MAXPATHLEN
) {
2692 printf("maximum path length exceeded, ");
2693 printf("truncating\n");
2699 if ((int)strlen(input_path
[input_pathp
]) >= MAXNAMLEN
) {
2700 printf("maximum name length exceeded, truncating\n");
2703 input_path
[input_pathp
][strlen(input_path
[input_pathp
])] = c
;
2708 * compare - check if a filename matches the pattern entered by the user.
2709 * Handles '*', '?', and '[]'.
2712 compare(char *s1
, char *s2
, short at_start
)
2717 while ((c
= *s1
) != '\0') {
2719 if (at_start
&& s
== s2
&& !letter(*s2
) && !digit(*s2
))
2724 if (compare(s1
, s2
, 0))
2738 if (at_start
&& s
== s2
&& !letter(*s2
) && !digit(*s2
))
2748 printf("missing '-'\n");
2754 printf("missing ']'");
2775 * freemem - free the memory allocated to the filenames structure.
2778 freemem(struct filenames
*p
, int numb
)
2784 for (i
= 0; i
< numb
; i
++, p
++) {
2785 for (j
= 0; j
<= p
->len
; j
++)
2787 free((char *)p
->fname
);
2792 * print_path - print the pathname held in p.
2795 print_path(char *p
[], int pntr
)
2801 for (i
= 0; i
< pntr
; i
++)
2802 printf("%s/", p
[i
]);
2803 printf("%s", p
[pntr
]);
2808 * fill - fill a section with a value or string.
2809 * addr,count:fill=[value, "string"].
2816 short eof_flag
, end
= 0, eof
= 0;
2820 if (wrtflag
== O_RDONLY
) {
2821 printf("not opened for write '-w'\n");
2828 if ((cptr
= getblk(addr
)) == 0)
2837 addr
&= ~(LONG
- 1);
2840 addr
&= ~(SHORT
- 1);
2846 cur_bytes
-= taddr
- addr
;
2847 cptr
+= blkoff(fs
, addr
);
2848 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
2849 for (i
= 0; i
< tcount
; i
++) {
2853 *(long *)cptr
= temp
;
2857 *(short *)cptr
= temp
;
2864 addr
+= (tcount
- 1) * objsz
;
2865 cur_bytes
+= (tcount
- 1) * objsz
;
2866 put((uoff_t
)temp
, objsz
);
2868 printf("end of file\n");
2871 printf("end of block\n");
2877 * get - read a byte, short or long from the file system.
2878 * The entire block containing the desired item is read
2879 * and the appropriate data is extracted and returned.
2889 if (objsz
== INODE
|| objsz
== SHORT
)
2890 temp
&= ~(SHORT
- 1);
2891 else if (objsz
== DIRECTORY
|| objsz
== LONG
|| objsz
== SHADOW_DATA
)
2892 temp
&= ~(LONG
- 1);
2893 if ((bptr
= getblk(temp
)) == 0)
2895 bptr
+= blkoff(fs
, temp
);
2898 return ((offset_t
)*bptr
);
2902 return ((offset_t
)(*(short *)bptr
));
2907 return ((offset_t
)(*(long *)bptr
));
2910 return (*(offset_t
*)bptr
);
2916 * cgrp_check - make sure that we don't bump the cylinder group
2917 * beyond the total number of cylinder groups or before the start.
2920 cgrp_check(long cgrp
)
2924 printf("beginning of cylinder groups\n");
2926 printf("beginning of super blocks\n");
2930 if (cgrp
>= fs
->fs_ncg
) {
2932 printf("end of cylinder groups\n");
2934 printf("end of super blocks\n");
2939 return (cgtod(fs
, cgrp
) << FRGSHIFT
);
2941 return (cgsblock(fs
, cgrp
) << FRGSHIFT
);
2945 * icheck - make sure we can read the block containing the inode
2946 * and determine the filesize (0 if inode not allocated). Return
2947 * 0 if error otherwise return the mode.
2950 icheck(uoff_t address
)
2955 if ((cptr
= getblk(address
)) == 0)
2957 cptr
+= blkoff(fs
, address
);
2959 ip
= (struct dinode
*)cptr
;
2960 if ((ip
->di_mode
& IFMT
) == 0) {
2962 printf("inode not allocated\n");
2966 blocksize
= filesize
= 0;
2969 filesize
= ip
->di_size
;
2970 blocksize
= filesize
* 2;
2972 return (ip
->di_mode
);
2976 * getdirslot - get the address of the directory slot desired.
2979 getdirslot(long slot
)
2982 struct direct
*dirp
;
2984 char *string
= &scratch
[0];
2985 short bod
= 0, mode
, temp
;
2991 if (type
!= DIRECTORY
) {
2995 string
= "fragment";
2997 if ((cptr
= getblk(addr
)) == 0)
2999 cptr
+= blkoff(fs
, addr
);
3002 dirp
= (struct direct
*)cptr
;
3003 for (dirslot
= 0; dirslot
< slot
; dirslot
++) {
3005 dirp
= (struct direct
*)cptr
;
3006 if (blocksize
> filesize
) {
3007 if (cur_bytes
+ (long)dirp
->d_reclen
>=
3009 printf("end of file\n");
3011 errcur_bytes
= cur_bytes
;
3012 stringsize
= STRINGSIZE(dirp
);
3017 if (cur_bytes
+ (long)dirp
->d_reclen
>=
3019 printf("end of %s\n", string
);
3021 errcur_bytes
= cur_bytes
;
3022 stringsize
= STRINGSIZE(dirp
);
3027 cptr
+= dirp
->d_reclen
;
3028 addr
+= dirp
->d_reclen
;
3029 cur_bytes
+= dirp
->d_reclen
;
3032 if (blocksize
> filesize
)
3033 printf("beginning of file\n");
3035 printf("beginning of %s\n", string
);
3037 errcur_bytes
= cur_bytes
;
3040 stringsize
= STRINGSIZE(dirp
);
3044 if ((mode
= icheck(addr
)) == 0)
3046 if (!override
&& (mode
& IFDIR
) == 0) {
3047 printf("inode is not a directory\n");
3054 if (i
== 0 || bcomp(addr
)) {
3056 if ((addr
= (bmap((long)i
++) << FRGSHIFT
)) == 0)
3058 if ((cptr
= getblk(addr
)) == 0)
3060 cptr
+= blkoff(fs
, addr
);
3063 dirp
= (struct direct
*)cptr
;
3064 value
= dirp
->d_ino
;
3067 if (cur_bytes
+ (long)dirp
->d_reclen
>= filesize
) {
3068 printf("end of file\n");
3069 dirslot
= slot
- temp
- 1;
3072 errcur_bytes
= cur_bytes
;
3073 stringsize
= STRINGSIZE(dirp
);
3077 addr
+= dirp
->d_reclen
;
3078 cptr
+= dirp
->d_reclen
;
3079 cur_bytes
+= dirp
->d_reclen
;
3084 printf("beginning of file\n");
3086 errcur_bytes
= cur_bytes
;
3089 stringsize
= STRINGSIZE(dirp
);
3096 * getshadowslot - get the address of the shadow data desired
3099 getshadowslot(long shadow
)
3102 short bod
= 0, mode
;
3103 long taddr
, tcurbytes
;
3109 if (type
!= SHADOW_DATA
) {
3110 if (shadow
< cur_shad
) {
3111 printf("can't scan shadow data in reverse\n");
3117 if ((mode
= icheck(addr
)) == 0)
3119 if (!override
&& (mode
& IFMT
) != IFSHAD
) {
3120 printf("inode is not a shadow\n");
3126 syncshadowscan(1); /* force synchronization */
3129 for (; cur_shad
< shadow
; cur_shad
++) {
3131 tcurbytes
= cur_bytes
;
3132 getshadowdata((long *)&fsd
, LONG
+ LONG
);
3134 cur_bytes
= tcurbytes
;
3135 if (cur_bytes
+ (long)fsd
.fsd_size
> filesize
) {
3137 printf("end of file\n");
3139 errcur_bytes
= cur_bytes
;
3143 addr
+= fsd
.fsd_size
;
3144 cur_bytes
+= fsd
.fsd_size
;
3147 if (type
== SHADOW_DATA
)
3148 objsz
= SHADOW_DATA
;
3150 printf("beginning of file\n");
3152 errcur_bytes
= cur_bytes
;
3159 getshadowdata(long *buf
, int len
)
3164 for (tfsd
= 0; tfsd
< len
; tfsd
++) {
3165 buf
[tfsd
] = get(SHADOW_DATA
);
3173 syncshadowscan(int force
)
3176 if (type
== SHADOW_DATA
&& (force
||
3177 lblkno(fs
, addr
) != (bhdr
.fwd
)->blkno
)) {
3178 curblkoff
= blkoff(fs
, cur_bytes
);
3179 addr
= bmap(lblkno(fs
, cur_bytes
)) << FRGSHIFT
;
3181 cur_bytes
+= curblkoff
;
3182 (void) getblk(addr
);
3183 objsz
= SHADOW_DATA
;
3190 * putf - print a byte as an ascii character if possible.
3191 * The exceptions are tabs, newlines, backslashes
3192 * and nulls which are printed as the standard C
3193 * language escapes. Characters which are not
3194 * recognized are printed as \?.
3200 if (c
<= 037 || c
>= 0177 || c
== '\\') {
3225 * put - write an item into the buffer for the current address
3226 * block. The value is checked to make sure that it will
3227 * fit in the size given without truncation. If successful,
3228 * the entire block is written back to the file system.
3231 put(uoff_t item
, short lngth
)
3238 if (wrtflag
== O_RDONLY
) {
3239 printf("not opened for write '-w'\n");
3244 if ((sbptr
= getblk(addr
)) == 0)
3246 bptr
= sbptr
+ blkoff(fs
, addr
);
3251 olditem
= *(long *)bptr
;
3253 *(long *)bptr
= item
;
3258 olditem
= (long)*(short *)bptr
;
3261 *(short *)bptr
= item
;
3264 olditem
= (long)*bptr
;
3266 *bptr
= lobyte(loword(item
));
3272 if ((s_err
= llseek(fd
, (offset_t
)(addr
& fs
->fs_bmask
), 0)) == -1) {
3274 printf("seek error : %" PRIx64
"\n", addr
);
3277 if ((nbytes
= write(fd
, sbptr
, BLKSIZE
)) != BLKSIZE
) {
3279 printf("write error : addr = %" PRIx64
"\n", addr
);
3280 printf(" : s_err = %lx\n", s_err
);
3281 printf(" : nbytes = %lx\n", nbytes
);
3284 if (!acting_on_inode
&& objsz
!= INODE
&& objsz
!= DIRECTORY
) {
3286 print(olditem
, 8, -8, 0);
3288 print(item
, 8, -8, 0);
3291 if (objsz
== DIRECTORY
) {
3303 * getblk - check if the desired block is in the file system.
3304 * Search the incore buffers to see if the block is already
3305 * available. If successful, unlink the buffer control block
3306 * from its position in the buffer list and re-insert it at
3307 * the head of the list. If failure, use the last buffer
3308 * in the list for the desired block. Again, this control
3309 * block is placed at the head of the list. This process
3310 * will leave commonly requested blocks in the in-core buffers.
3311 * Finally, a pointer to the buffer is returned.
3314 getblk(uoff_t address
)
3319 unsigned long block
;
3322 block
= lblkno(fs
, address
);
3323 if (block
>= fragstoblks(fs
, fs
->fs_size
)) {
3324 printf("cannot read block %lu\n", block
);
3328 for (bp
= bhdr
.fwd
; bp
!= &bhdr
; bp
= bp
->fwd
)
3329 if (bp
->valid
&& bp
->blkno
== block
)
3331 actual_disk_reads
++;
3335 if ((s_err
= llseek(fd
, (offset_t
)(address
& fs
->fs_bmask
), 0)) == -1) {
3337 printf("seek error : %" PRIx64
"\n", address
);
3340 if ((nbytes
= read(fd
, bp
->blkaddr
, BLKSIZE
)) != BLKSIZE
) {
3342 printf("read error : addr = %" PRIx64
"\n", address
);
3343 printf(" : s_err = %lx\n", s_err
);
3344 printf(" : nbytes = %lx\n", nbytes
);
3348 xit
: bp
->back
->fwd
= bp
->fwd
;
3349 bp
->fwd
->back
= bp
->back
;
3351 return (bp
->blkaddr
);
3355 * insert - place the designated buffer control block
3356 * at the head of the linked list of buffers.
3359 insert(struct lbuf
*bp
)
3364 bhdr
.fwd
->back
= bp
;
3369 * err - called on interrupts. Set the current address
3370 * back to the last address stored in erraddr. Reset all
3371 * appropriate flags. A reset call is made to return
3382 freemem(filenames
, nfiles
);
3384 (void) signal(2, err
);
3388 cur_bytes
= errcur_bytes
;
3392 (void) fseek(stdin
, 0L, 2);
3397 * devcheck - check that the given mode represents a
3398 * special device. The IFCHR bit is on for both
3399 * character and block devices.
3406 switch (md
& IFMT
) {
3412 printf("not character or block device\n");
3418 * nullblk - return error if address is zero. This is done
3419 * to prevent block 0 from being used as an indirect block
3420 * for a large file or as a data block for a small file.
3427 printf("non existent block\n");
3433 * puta - put ascii characters into a buffer. The string
3434 * terminates with a quote or newline. The leading quote,
3435 * which is optional for directory names, was stripped off
3436 * by the assignment case in the main loop.
3445 long maxchars
, s_err
, nbytes
, temp
;
3446 uoff_t taddr
= addr
;
3447 long tcount
= 0, item
, olditem
= 0;
3449 if (wrtflag
== O_RDONLY
) {
3450 printf("not opened for write '-w'\n");
3454 if ((sbptr
= getblk(addr
)) == 0)
3456 cptr
= sbptr
+ blkoff(fs
, addr
);
3457 if (objsz
== DIRECTORY
) {
3458 if (acting_on_directory
)
3459 maxchars
= stringsize
- 1;
3462 } else if (objsz
== INODE
)
3463 maxchars
= objsz
- (addr
- cur_ino
);
3465 maxchars
= min(blocksize
- cur_bytes
, filesize
- cur_bytes
);
3466 while ((c
= getachar()) != '"') {
3467 if (tcount
>= maxchars
) {
3468 printf("string too long\n");
3469 if (objsz
== DIRECTORY
)
3471 else if (acting_on_inode
|| objsz
== INODE
)
3476 errcur_bytes
= cur_bytes
;
3486 olditem
<<= BITSPERCHAR
;
3487 olditem
+= temp
& 0xff;
3489 switch (c
= getachar()) {
3507 if (objsz
== DIRECTORY
&& acting_on_directory
)
3508 for (i
= tcount
; i
<= maxchars
; i
++)
3510 if ((s_err
= llseek(fd
, (offset_t
)(addr
& fs
->fs_bmask
), 0)) == -1) {
3512 printf("seek error : %" PRIx64
"\n", addr
);
3515 if ((nbytes
= write(fd
, sbptr
, BLKSIZE
)) != BLKSIZE
) {
3517 printf("write error : addr = %" PRIx64
"\n", addr
);
3518 printf(" : s_err = %lx\n", s_err
);
3519 printf(" : nbytes = %lx\n", nbytes
);
3522 if (!acting_on_inode
&& objsz
!= INODE
&& objsz
!= DIRECTORY
) {
3524 cur_bytes
+= tcount
;
3526 if (objsz
!= CHAR
) {
3527 addr
&= ~(objsz
- 1);
3528 cur_bytes
-= taddr
- addr
;
3530 if (addr
== taddr
) {
3534 tcount
= LONG
- (taddr
- addr
);
3536 if ((cptr
= getblk(addr
)) == 0)
3538 cptr
+= blkoff(fs
, addr
);
3542 item
= *(long *)cptr
;
3543 if (tcount
< LONG
) {
3544 olditem
<<= tcount
* BITSPERCHAR
;
3546 for (i
= 0; i
< (tcount
*BITSPERCHAR
); i
++)
3548 olditem
+= item
& (temp
- 1);
3553 item
= (long)*(short *)cptr
;
3554 if (tcount
< SHORT
) {
3555 olditem
<<= tcount
* BITSPERCHAR
;
3557 for (i
= 0; i
< (tcount
* BITSPERCHAR
); i
++)
3559 olditem
+= item
& (temp
- 1);
3561 olditem
&= 0177777L;
3567 print(olditem
, 8, -8, 0);
3569 print(item
, 8, -8, 0);
3572 if (objsz
== DIRECTORY
) {
3586 * fprnt - print data. 'count' elements are printed where '*' will
3587 * print an entire blocks worth or up to the eof, whichever
3588 * occurs first. An error will occur if crossing a block boundary
3589 * is attempted since consecutive blocks don't usually have
3590 * meaning. Current print types:
3591 * / b - print as bytes (base sensitive)
3592 * c - print as characters
3593 * o O - print as octal shorts (longs)
3594 * d D - print as decimal shorts (longs)
3595 * x X - print as hexadecimal shorts (longs)
3596 * ? c - print as cylinder groups
3597 * d - print as directories
3598 * i - print as inodes
3599 * s - print as super blocks
3600 * S - print as shadow data
3603 fprnt(char style
, char po
)
3608 struct direct
*dirp
;
3612 long tinode
, tcount
, temp
;
3614 short offset
, mode
, end
= 0, eof
= 0, eof_flag
;
3615 unsigned short *sptr
;
3616 unsigned long *lptr
;
3617 offset_t curoff
, curioff
;
3631 offset
= blkoff(fs
, addr
);
3640 case 'c': /* print as characters */
3641 case 'b': /* or bytes */
3642 if ((cptr
= getblk(addr
)) == 0)
3646 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
3648 for (i
= 0; tcount
--; i
++) {
3659 if ((i
+ 1) % 16 == 0)
3660 print(*cptr
++ & 0377L,
3663 print(*cptr
++ & 0377L,
3674 errcur_bytes
= cur_bytes
;
3676 printf("end of file\n");
3680 printf("end of block\n");
3682 printf("end of fragment\n");
3687 case 'o': /* print as octal shorts */
3690 case 'd': /* print as decimal shorts */
3693 case 'x': /* print as hex shorts */
3696 if ((cptr
= getblk(addr
)) == 0)
3699 addr
&= ~(SHORT
- 1);
3700 cur_bytes
-= taddr
- addr
;
3701 cptr
+= blkoff(fs
, addr
);
3703 sptr
= (unsigned short *)cptr
;
3705 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
3707 for (i
= 0; tcount
--; i
++) {
3708 sptr
= (unsigned short *)print_check(
3710 (unsigned long *)sptr
,
3714 printf("%06o ", *sptr
++);
3717 printf("%05d ", *sptr
++);
3720 printf("%04x ", *sptr
++);
3730 errcur_bytes
= cur_bytes
;
3732 printf("end of file\n");
3736 printf("end of block\n");
3738 printf("end of fragment\n");
3743 case 'O': /* print as octal longs */
3746 case 'D': /* print as decimal longs */
3749 case 'X': /* print as hex longs */
3752 if ((cptr
= getblk(addr
)) == 0)
3755 addr
&= ~(LONG
- 1);
3756 cur_bytes
-= taddr
- addr
;
3757 cptr
+= blkoff(fs
, addr
);
3759 lptr
= (unsigned long *)cptr
;
3761 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
3763 for (i
= 0; tcount
--; i
++) {
3764 lptr
= print_check(lptr
, &tcount
,
3768 printf("%011lo ", *lptr
++);
3771 printf("%010lu ", *lptr
++);
3774 printf("%08lx ", *lptr
++);
3784 errcur_bytes
= cur_bytes
;
3786 printf("end of file\n");
3790 printf("end of block\n");
3792 printf("end of fragment\n");
3799 printf("no such print option\n");
3805 case 'c': /* print as cylinder group */
3807 if (cur_cgrp
+ count
> fs
->fs_ncg
) {
3808 tcount
= fs
->fs_ncg
- cur_cgrp
;
3812 addr
&= ~(LONG
- 1);
3813 for (/* void */; tcount
--; /* void */) {
3815 errcur_bytes
= cur_bytes
;
3817 addr
= cgtod(fs
, cur_cgrp
)
3821 if ((cptr
= getblk(addr
)) == 0) {
3826 cptr
+= blkoff(fs
, addr
);
3828 cg
= (struct cg
*)cptr
;
3830 cur_cgrp
= cg
->cg_cgx
+ 1;
3831 type
= objsz
= CGRP
;
3832 if (cur_cgrp
+ count
- 1 > fs
->fs_ncg
) {
3833 tcount
= fs
->fs_ncg
- cur_cgrp
;
3838 if (! override
&& !cg_chkmagic(cg
)) {
3839 printf("invalid cylinder group ");
3840 printf("magic word\n");
3852 printf("end of cylinder groups\n");
3857 case 'd': /* print as directories */
3858 if ((cptr
= getblk(addr
)) == 0)
3861 if (fragoff(fs
, addr
)) {
3862 printf("address must be at the ");
3863 printf("beginning of a fragment\n");
3871 blocksize
= FRGSIZE
;
3872 filesize
= FRGSIZE
* 2;
3876 while (tcount
-- && cur_bytes
< filesize
&&
3877 cur_bytes
< blocksize
&& !bcomp(addr
)) {
3879 dirp
= (struct direct
*)cptr
;
3880 tinode
= dirp
->d_ino
;
3885 print(tinode
, 12, -8, 0);
3886 printf("%s\n", &dirp
->d_name
[0]);
3888 errcur_bytes
= cur_bytes
;
3889 addr
+= dirp
->d_reclen
;
3890 cptr
+= dirp
->d_reclen
;
3891 cur_bytes
+= dirp
->d_reclen
;
3893 stringsize
= STRINGSIZE(dirp
);
3897 cur_bytes
= errcur_bytes
;
3899 if (tcount
>= 0 && !star
) {
3902 printf("end of fragment\n");
3905 printf("end of block\n");
3908 printf("end of directory\n");
3915 case 'i': /* print as inodes */
3917 if ((ip
= (struct dinode
*)getblk(addr
)) == 0)
3919 for (i
= 1; i
< fs
->fs_ncg
; i
++)
3920 if (addr
< (cgimin(fs
, i
) << FRGSHIFT
))
3924 temp
= (addr
- (cgimin(fs
, i
) << FRGSHIFT
)) >> FRGSHIFT
;
3925 temp
= (i
* fs
->fs_ipg
) + fragstoblks(fs
, temp
) *
3927 if (count
+ offset
> INOPB(fs
)) {
3928 tcount
= INOPB(fs
) - offset
;
3934 for (i
= 0; tcount
--; ip
++, temp
++) {
3935 if ((mode
= icheck(addr
)) == 0)
3938 p
= " ugtrwxrwxrwx";
3940 switch (mode
& IFMT
) {
3972 print(temp
, 12, -8, 0);
3975 for (mode
= mode
<< 4; *++p
; mode
= mode
<< 1) {
3982 print(ip
->di_uid
, 8, -4, 0);
3984 print(ip
->di_gid
, 8, -4, 0);
3987 print((long)ip
->di_nlink
, 8, -4, 0);
3989 print(ip
->di_blocks
, 12, -8, 0);
3990 printf("c_flags : ");
3991 print(ip
->di_cflags
, 12, -8, 0);
3993 #ifdef _LARGEFILE64_SOURCE
3994 printll(ip
->di_size
, 20, -16, 0);
3995 #else /* !_LARGEFILE64_SOURCE */
3996 print(ip
->di_size
, 12, -8, 0);
3997 #endif /* _LARGEFILE64_SOURCE */
3998 if (ip
->di_shadow
) {
4000 print(ip
->di_shadow
, 12, -8, 0);
4003 if (ip
->di_oeftflag
) {
4005 print(ip
->di_oeftflag
, 12, -8, 0);
4009 switch (ip
->di_mode
& IFMT
) {
4013 print(major(ip
->di_ordev
), 4, -2, 0);
4015 print(minor(ip
->di_ordev
), 4, -2, 0);
4020 * only display blocks below the
4024 for (i
= 0; i
< NDADDR
; ) {
4025 if (ip
->di_size
<= curoff
)
4027 printf("db#%x: ", i
);
4028 print(ip
->di_db
[i
], 11, -8, 0);
4034 curoff
+= fs
->fs_bsize
;
4040 * curioff keeps track of the number
4041 * of bytes covered by each indirect
4042 * pointer in the inode, and is added
4043 * to curoff each time to get the
4044 * actual offset into the file.
4046 curioff
= fs
->fs_bsize
*
4047 (fs
->fs_bsize
/ sizeof (daddr_t
));
4048 for (i
= 0; i
< NIADDR
; i
++) {
4049 if (ip
->di_size
<= curoff
)
4051 printf("ib#%x: ", i
);
4052 print(ip
->di_ib
[i
], 11, -8, 0);
4055 curioff
*= (fs
->fs_bsize
/
4066 printf("\taccessed: %s", ctime(&t
));
4068 printf("\tmodified: %s", ctime(&t
));
4070 printf("\tcreated : %s", ctime(&t
));
4075 if (c
== '?' && !override
) {
4077 print(temp
, 12, -8, 0);
4078 printf(" is unallocated\n");
4082 cur_ino
= erraddr
= addr
;
4083 errcur_bytes
= cur_bytes
;
4085 addr
= addr
+ INODE
;
4088 cur_bytes
= errcur_bytes
;
4091 printf("end of block\n");
4096 case 's': /* print as super block */
4097 if (cur_cgrp
== -1) {
4098 addr
= SBLOCK
* DEV_BSIZE
;
4101 addr
&= ~(LONG
- 1);
4103 if (cur_cgrp
+ count
> fs
->fs_ncg
) {
4104 tcount
= fs
->fs_ncg
- cur_cgrp
;
4108 for (/* void */; tcount
--; /* void */) {
4110 cur_bytes
= errcur_bytes
;
4112 addr
= cgsblock(fs
, cur_cgrp
)
4116 if ((cptr
= getblk(addr
)) == 0) {
4121 cptr
+= blkoff(fs
, addr
);
4123 sb
= (struct fs
*)cptr
;
4125 for (i
= 0; i
< fs
->fs_ncg
; i
++)
4126 if (addr
== cgsblock(fs
, i
) <<
4129 if (i
== fs
->fs_ncg
)
4134 if (cur_cgrp
+ count
- 1 > fs
->fs_ncg
) {
4135 tcount
= fs
->fs_ncg
- cur_cgrp
;
4140 if ((sb
->fs_magic
!= FS_MAGIC
) &&
4141 (sb
->fs_magic
!= MTB_UFS_MAGIC
)) {
4144 printf("invalid super block ");
4145 printf("magic word\n");
4151 if (sb
->fs_magic
== FS_MAGIC
&&
4153 UFS_EFISTYLE4NONEFI_VERSION_2
&&
4154 sb
->fs_version
!= UFS_VERSION_MIN
)) {
4157 printf("invalid super block ");
4158 printf("version number\n");
4164 if (sb
->fs_magic
== MTB_UFS_MAGIC
&&
4165 (sb
->fs_version
> MTB_UFS_VERSION_1
||
4166 sb
->fs_version
< MTB_UFS_VERSION_MIN
)) {
4169 printf("invalid super block ");
4170 printf("version number\n");
4177 printf("\tsuper block:\n");
4179 printf("\tsuper block in cylinder ");
4181 print(cur_cgrp
- 1, 0, 0, 0);
4190 printf("end of super blocks\n");
4195 case 'S': /* print as shadow data */
4199 cur_bytes
= fragoff(fs
, addr
);
4200 bod_addr
= addr
- cur_bytes
;
4201 /* no more than two fragments */
4202 filesize
= fragroundup(fs
,
4203 bod_addr
+ FRGSIZE
+ 1);
4205 objsz
= SHADOW_DATA
;
4207 (cur_bytes
+ SHADOW_DATA
) <= filesize
&&
4208 (type
!= SHADOW_DATA
||
4209 (cur_bytes
+ SHADOW_DATA
)) <= blocksize
) {
4215 tcur_bytes
= cur_bytes
;
4217 getshadowdata((long *)&fsd
, LONG
+ LONG
);
4219 print((long)fsd
.fsd_type
, 8, -8, 0);
4221 print((long)fsd
.fsd_size
, 8, -8, 0);
4222 tbase
= fsd
.fsd_size
- LONG
- LONG
;
4225 for (i
= 0; i
< tbase
; i
++) {
4226 if (i
% LONG
== 0) {
4232 getshadowdata(&temp
, LONG
);
4236 printf("%02x", (int)(*p
++ & 0377L));
4240 cur_bytes
= tcur_bytes
;
4242 errcur_bytes
= cur_bytes
;
4243 addr
+= FSD_RECSZ((&fsd
), fsd
.fsd_size
);
4244 cur_bytes
+= FSD_RECSZ((&fsd
), fsd
.fsd_size
);
4249 cur_bytes
= errcur_bytes
;
4251 if (tcount
>= 0 && !star
) {
4254 printf("end of fragment\n");
4257 printf("end of shadow data\n");
4265 printf("no such print option\n");
4271 * valid_addr - call check_addr to validate the current address.
4276 short end
= 0, eof
= 0;
4277 long tcount
= count
;
4281 if (cur_bytes
< 0) {
4283 if (blocksize
> filesize
) {
4284 printf("beginning of file\n");
4287 printf("beginning of block\n");
4289 printf("beginning of fragment\n");
4295 (void) check_addr(1, &end
, &eof
, (filesize
< blocksize
));
4298 printf("end of file\n");
4303 if (erraddr
> addr
) {
4305 printf("beginning of block\n");
4307 printf("beginning of fragment\n");
4314 printf("end of block\n");
4316 printf("end of fragment\n");
4324 * check_addr - check if the address crosses the end of block or
4325 * end of file. Return the proper count.
4328 check_addr(short eof_flag
, short *end
, short *eof
, short keep_on
)
4330 long temp
, tcount
= count
, tcur_bytes
= cur_bytes
;
4331 uoff_t taddr
= addr
;
4333 if (bcomp(addr
+ count
* objsz
- 1) ||
4334 (keep_on
&& taddr
< (bmap(cur_block
) << FRGSHIFT
))) {
4337 cur_bytes
= tcur_bytes
;
4339 if (addr
< erraddr
) {
4340 if (cur_bytes
< 0) {
4342 return (0); /* Value ignored */
4344 temp
= cur_block
- lblkno(fs
, cur_bytes
);
4346 if ((addr
= bmap(cur_block
) << FRGSHIFT
) == 0) {
4348 return (0); /* Value ignored */
4350 temp
= tcur_bytes
- cur_bytes
;
4353 return (0); /* Value ignored */
4355 if (cur_bytes
>= filesize
) {
4357 return (0); /* Value ignored */
4359 temp
= lblkno(fs
, cur_bytes
) - cur_block
;
4361 if ((addr
= bmap(cur_block
) << FRGSHIFT
) == 0) {
4363 return (0); /* Value ignored */
4365 temp
= tcur_bytes
- cur_bytes
;
4368 return (0); /* Value ignored */
4371 tcount
= (blkroundup(fs
, addr
+1)-addr
) / objsz
;
4376 cur_bytes
= tcur_bytes
;
4378 if (blocksize
> filesize
) {
4379 if (cur_bytes
>= filesize
) {
4382 } else if (tcount
> (filesize
- cur_bytes
) / objsz
) {
4383 tcount
= (filesize
- cur_bytes
) / objsz
;
4384 if (!star
|| tcount
== 0)
4388 if (cur_bytes
>= blocksize
) {
4391 } else if (tcount
> (blocksize
- cur_bytes
) / objsz
) {
4392 tcount
= (blocksize
- cur_bytes
) / objsz
;
4393 if (!star
|| tcount
== 0)
4402 * print_check - check if the index needs to be printed and delete
4403 * rows of zeros from the output.
4406 print_check(unsigned long *lptr
, long *tcount
, short tbase
, int i
)
4408 int j
, k
, temp
= BYTESPERLINE
/ objsz
;
4409 short first_time
= 0;
4410 unsigned long *tlptr
;
4411 unsigned short *tsptr
, *sptr
;
4413 sptr
= (unsigned short *)lptr
;
4416 if (i
% temp
== 0) {
4417 if (*tcount
>= temp
- 1) {
4423 for (j
= i
; k
--; j
++)
4424 if (objsz
== SHORT
) {
4431 if (j
> (i
+ temp
- 1)) {
4440 addr
+= BYTESPERLINE
;
4441 cur_bytes
+= BYTESPERLINE
;
4459 return ((unsigned long *)sptr
);
4465 * index - print a byte index for the printout in base b
4466 * with leading zeros.
4474 print(addr
, 8, 8, 1);
4480 * print - print out the value to digits places with/without
4481 * leading zeros and right/left justified in the current base.
4484 #ifdef _LARGEFILE64_SOURCE
4485 printll(uoff_t value
, int fieldsz
, int digits
, int lead
)
4486 #else /* !_LARGEFILE64_SOURCE */
4487 print(long value
, int fieldsz
, int digits
, int lead
)
4488 #endif /* _LARGEFILE64_SOURCE */
4491 char mode
= BASE
[base
- OCTAL
];
4492 char *string
= &scratch
[0];
4500 digits
= digits
+ (digits
- 1)/((base
>> 1) - 1) + 1;
4505 (void) sprintf(string
, "%%%c%d%d.%d"
4506 #ifdef _LARGEFILE64_SOURCE
4508 #endif /* _LARGEFILE64_SOURCE */
4509 "%c", '-', 0, digits
, lead
, mode
);
4511 (void) sprintf(string
, "%%%d%d.%d"
4512 #ifdef _LARGEFILE64_SOURCE
4514 #endif /* _LARGEFILE64_SOURCE */
4515 "%c", 0, digits
, lead
, mode
);
4518 (void) sprintf(string
, "%%%c%d"
4519 #ifdef _LARGEFILE64_SOURCE
4521 #endif /* _LARGEFILE64_SOURCE */
4522 "%c", '-', digits
, mode
);
4524 (void) sprintf(string
, "%%%d"
4525 #ifdef _LARGEFILE64_SOURCE
4527 #endif /* _LARGEFILE64_SOURCE */
4528 "%c", digits
, mode
);
4530 printf(string
, value
);
4531 for (i
= 0; i
< fieldsz
- digits
; i
++)
4536 * Print out the contents of a superblock.
4539 printsb(struct fs
*fs
)
4541 int c
, i
, j
, k
, size
;
4546 #ifdef FS_42POSTBLFMT
4547 if (fs
->fs_postblformat
== FS_42POSTBLFMT
)
4549 printf("magic\t%lx\tformat\t%s\ttime\t%s", fs
->fs_magic
,
4550 fs
->fs_postblformat
== FS_42POSTBLFMT
? "static" : "dynamic",
4553 printf("magic\t%x\ttime\t%s",
4554 fs
->fs_magic
, ctime(&t
));
4556 printf("version\t%x\n", fs
->fs_version
);
4557 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4558 fs
->fs_cstotal
.cs_nbfree
, fs
->fs_cstotal
.cs_ndir
,
4559 fs
->fs_cstotal
.cs_nifree
, fs
->fs_cstotal
.cs_nffree
);
4560 printf("ncg\t%ld\tncyl\t%ld\tsize\t%ld\tblocks\t%ld\n",
4561 fs
->fs_ncg
, fs
->fs_ncyl
, fs
->fs_size
, fs
->fs_dsize
);
4562 printf("bsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4563 fs
->fs_bsize
, fs
->fs_bshift
, fs
->fs_bmask
);
4564 printf("fsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4565 fs
->fs_fsize
, fs
->fs_fshift
, fs
->fs_fmask
);
4566 printf("frag\t%ld\tshift\t%ld\tfsbtodb\t%ld\n",
4567 fs
->fs_frag
, fs
->fs_fragshift
, fs
->fs_fsbtodb
);
4568 printf("cpg\t%ld\tbpg\t%ld\tfpg\t%ld\tipg\t%ld\n",
4569 fs
->fs_cpg
, fs
->fs_fpg
/ fs
->fs_frag
, fs
->fs_fpg
, fs
->fs_ipg
);
4570 printf("minfree\t%ld%%\toptim\t%s\tmaxcontig %ld\tmaxbpg\t%ld\n",
4571 fs
->fs_minfree
, fs
->fs_optim
== FS_OPTSPACE
? "space" : "time",
4572 fs
->fs_maxcontig
, fs
->fs_maxbpg
);
4573 #ifdef FS_42POSTBLFMT
4575 printf("rotdelay %ldms\tfs_id[0] 0x%lx\tfs_id[1] 0x%lx\trps\t%ld\n",
4576 fs
->fs_rotdelay
, fs
->fs_id
[0], fs
->fs_id
[1], fs
->fs_rps
);
4578 printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
4579 fs
->fs_rotdelay
, fs
->fs_headswitch
, fs
->fs_trkseek
, fs
->fs_rps
);
4581 printf("ntrak\t%ld\tnsect\t%ld\tnpsect\t%ld\tspc\t%ld\n",
4582 fs
->fs_ntrak
, fs
->fs_nsect
, fs
->fs_npsect
, fs
->fs_spc
);
4583 printf("trackskew %ld\n", fs
->fs_trackskew
);
4585 printf("rotdelay %ldms\trps\t%ld\n",
4586 fs
->fs_rotdelay
, fs
->fs_rps
);
4587 printf("ntrak\t%ld\tnsect\t%ld\tspc\t%ld\n",
4588 fs
->fs_ntrak
, fs
->fs_nsect
, fs
->fs_spc
);
4590 printf("si %ld\n", fs
->fs_si
);
4591 printf("nindir\t%ld\tinopb\t%ld\tnspf\t%ld\n",
4592 fs
->fs_nindir
, fs
->fs_inopb
, fs
->fs_nspf
);
4593 printf("sblkno\t%ld\tcblkno\t%ld\tiblkno\t%ld\tdblkno\t%ld\n",
4594 fs
->fs_sblkno
, fs
->fs_cblkno
, fs
->fs_iblkno
, fs
->fs_dblkno
);
4595 printf("sbsize\t%ld\tcgsize\t%ld\tcgoffset %ld\tcgmask\t0x%08lx\n",
4596 fs
->fs_sbsize
, fs
->fs_cgsize
, fs
->fs_cgoffset
, fs
->fs_cgmask
);
4597 printf("csaddr\t%ld\tcssize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4598 fs
->fs_csaddr
, fs
->fs_cssize
, fs
->fs_csshift
, fs
->fs_csmask
);
4599 printf("cgrotor\t%ld\tfmod\t%d\tronly\t%d\n",
4600 fs
->fs_cgrotor
, fs
->fs_fmod
, fs
->fs_ronly
);
4601 #ifdef FS_42POSTBLFMT
4602 if (fs
->fs_cpc
!= 0)
4603 printf("blocks available in each of %ld rotational positions",
4606 printf("insufficient space to maintain rotational tables\n");
4608 for (c
= 0; c
< fs
->fs_cpc
; c
++) {
4609 printf("\ncylinder number %d:", c
);
4610 #ifdef FS_42POSTBLFMT
4611 for (i
= 0; i
< fs
->fs_nrpos
; i
++) {
4613 if (fs_postbl(fs
, c
)[i
] == -1)
4615 printf("\n position %d:\t", i
);
4617 for (j
= fs_postbl(fs
, c
)[i
], k
= 1; /* void */;
4618 j
+= fs_rotbl(fs
)[j
], k
++) {
4622 if (fs_rotbl(fs
)[j
] == 0)
4627 for (i
= 0; i
< NRPOS
; i
++) {
4628 if (fs
->fs_postbl
[c
][i
] == -1)
4630 printf("\n position %d:\t", i
);
4631 for (j
= fs
->fs_postbl
[c
][i
], k
= 1; /* void */;
4632 j
+= fs
->fs_rotbl
[j
], k
++) {
4636 if (fs
->fs_rotbl
[j
] == 0)
4642 printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):");
4643 sip
= calloc(1, fs
->fs_cssize
);
4644 fs
->fs_u
.fs_csp
= (struct csum
*)sip
;
4645 for (i
= 0, j
= 0; i
< fs
->fs_cssize
; i
+= fs
->fs_bsize
, j
++) {
4646 size
= fs
->fs_cssize
- i
< fs
->fs_bsize
?
4647 fs
->fs_cssize
- i
: fs
->fs_bsize
;
4649 (offset_t
)fsbtodb(fs
, (fs
->fs_csaddr
+ j
* fs
->fs_frag
))
4650 * fs
->fs_fsize
/ fsbtodb(fs
, 1), 0);
4651 if (read(fd
, sip
, size
) != size
) {
4652 free(fs
->fs_u
.fs_csp
);
4657 for (i
= 0; i
< fs
->fs_ncg
; i
++) {
4658 struct csum
*cs
= &fs
->fs_cs(fs
, i
);
4661 printf("%d:(%ld,%ld,%ld,%ld) ", i
, cs
->cs_nbfree
, cs
->cs_ndir
,
4662 cs
->cs_nifree
, cs
->cs_nffree
);
4664 free(fs
->fs_u
.fs_csp
);
4666 if (fs
->fs_ncyl
% fs
->fs_cpg
) {
4667 printf("cylinders in last group %d\n",
4668 i
= fs
->fs_ncyl
% fs
->fs_cpg
);
4669 printf("blocks in last group %ld\n",
4670 i
* fs
->fs_spc
/ NSPB(fs
));
4675 * Print out the contents of a cylinder group.
4678 printcg(struct cg
*cg
)
4683 printf("\ncg %ld:\n", cg
->cg_cgx
);
4685 #ifdef FS_42POSTBLFMT
4686 printf("magic\t%lx\ttell\t%llx\ttime\t%s",
4687 fs
->fs_postblformat
== FS_42POSTBLFMT
?
4688 ((struct ocg
*)cg
)->cg_magic
: cg
->cg_magic
,
4689 fsbtodb(fs
, cgtod(fs
, cg
->cg_cgx
)) * fs
->fs_fsize
/ fsbtodb(fs
, 1),
4692 printf("magic\t%x\ttell\t%llx\ttime\t%s",
4694 fsbtodb(fs
, cgtod(fs
, cg
->cg_cgx
)) * fs
->fs_fsize
/ fsbtodb(fs
, 1),
4697 printf("cgx\t%ld\tncyl\t%d\tniblk\t%d\tndblk\t%ld\n",
4698 cg
->cg_cgx
, cg
->cg_ncyl
, cg
->cg_niblk
, cg
->cg_ndblk
);
4699 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4700 cg
->cg_cs
.cs_nbfree
, cg
->cg_cs
.cs_ndir
,
4701 cg
->cg_cs
.cs_nifree
, cg
->cg_cs
.cs_nffree
);
4702 printf("rotor\t%ld\tirotor\t%ld\tfrotor\t%ld\nfrsum",
4703 cg
->cg_rotor
, cg
->cg_irotor
, cg
->cg_frotor
);
4704 for (i
= 1, j
= 0; i
< fs
->fs_frag
; i
++) {
4705 printf("\t%ld", cg
->cg_frsum
[i
]);
4706 j
+= i
* cg
->cg_frsum
[i
];
4708 printf("\nsum of frsum: %d\niused:\t", j
);
4709 pbits((unsigned char *)cg_inosused(cg
), fs
->fs_ipg
);
4711 pbits(cg_blksfree(cg
), fs
->fs_fpg
);
4713 for (i
= 0; i
< fs
->fs_cpg
; i
++) {
4715 if (cg_blktot(cg
)[i
] == 0)
4718 printf(" c%d:\t(%ld)\t", i
, cg_blktot(cg
)[i
]);
4719 #ifdef FS_42POSTBLFMT
4720 for (j
= 0; j
< fs
->fs_nrpos
; j
++) {
4721 if (fs
->fs_cpc
== 0 ||
4723 fs_postbl(fs
, i
% fs
->fs_cpc
)[j
] == -1)
4726 printf(" %d", cg_blks(fs
, cg
, i
)[j
]);
4729 for (j
= 0; j
< NRPOS
; j
++) {
4730 if (fs
->fs_cpc
== 0 ||
4731 fs
->fs_postbl
[i
% fs
->fs_cpc
][j
] == -1)
4733 printf(" %d", cg
->cg_b
[i
][j
]);
4741 * Print out the contents of a bit array.
4744 pbits(unsigned char *cp
, int max
)
4749 for (i
= 0; i
< max
; i
++)
4752 printf(",%s", count
% 6 ? " " : "\n\t");
4756 while ((i
+1) < max
&& isset(cp
, i
+1))
4765 * bcomp - used to check for block over/under flows when stepping through
4775 if (lblkno(fs
, addr
) == (bhdr
.fwd
)->blkno
)
4782 * bmap - maps the logical block number of a file into
4783 * the corresponding physical block on the file
4795 if ((cptr
= getblk(cur_ino
)) == 0)
4798 cptr
+= blkoff(fs
, cur_ino
);
4801 ip
= (struct dinode
*)cptr
;
4805 return (nullblk(nb
) ? 0L : nb
);
4810 for (j
= NIADDR
; j
> 0; j
--) {
4817 printf("file too big\n");
4821 addr
= (uintptr_t)&ip
->di_ib
[NIADDR
- j
];
4825 for (; j
<= NIADDR
; j
++) {
4827 addr
= (nb
<< FRGSHIFT
) + ((bn
/ sh
) % NINDIR(fs
)) * LONG
;
4828 if (nullblk(nb
= get(LONG
)))
4834 #if defined(OLD_FSDB_COMPATIBILITY)
4837 * The following are "tacked on" to support the old fsdb functionality
4838 * of clearing an inode. (All together now...) "It's better to use clri".
4841 #define ISIZE (sizeof (struct dinode))
4842 #define NI (MAXBSIZE/ISIZE)
4845 static struct dinode di_buf
[NI
];
4852 #define sblock sb_un.sblk
4855 old_fsdb(int inum
, char *special
)
4857 int f
; /* File descriptor for "special" */
4864 f
= open(special
, O_RDWR
);
4867 printf("cannot open %s\n", special
);
4870 (void) llseek(f
, (offset_t
)SBLOCK
* DEV_BSIZE
, 0);
4871 if (read(f
, &sblock
, SBSIZE
) != SBSIZE
) {
4872 printf("cannot read %s\n", special
);
4875 if (sblock
.fs_magic
!= FS_MAGIC
) {
4876 printf("bad super block magic number\n");
4880 printf("%d: is zero\n", inum
);
4883 off
= (uoff_t
)fsbtodb(&sblock
, itod(&sblock
, inum
)) * DEV_BSIZE
;
4884 (void) llseek(f
, off
, 0);
4885 if (read(f
, (char *)di_buf
, sblock
.fs_bsize
) != sblock
.fs_bsize
) {
4886 printf("%s: read error\n", special
);
4893 * Update the time in superblock, so fsck will check this filesystem.
4895 (void) llseek(f
, (offset_t
)(SBLOCK
* DEV_BSIZE
), 0);
4897 sblock
.fs_time
= (time32_t
)t
;
4898 if (write(f
, &sblock
, SBSIZE
) != SBSIZE
) {
4899 printf("cannot update %s\n", special
);
4903 printf("clearing %u\n", inum
);
4904 off
= (uoff_t
)fsbtodb(&sblock
, itod(&sblock
, inum
)) * DEV_BSIZE
;
4905 (void) llseek(f
, off
, 0);
4906 read(f
, (char *)di_buf
, sblock
.fs_bsize
);
4907 j
= itoo(&sblock
, inum
);
4908 gen
= di_buf
[j
].di_gen
;
4909 (void) memset((caddr_t
)&di_buf
[j
], 0, ISIZE
);
4910 di_buf
[j
].di_gen
= gen
+ 1;
4911 (void) llseek(f
, off
, 0);
4912 write(f
, (char *)di_buf
, sblock
.fs_bsize
);
4923 while ((c
= *s
++) != 0)
4924 if (c
< '0' || c
> '9')
4928 #endif /* OLD_FSDB_COMPATIBILITY */
4930 enum boolean
{ True
, False
};
4931 extent_block_t
*log_eb
;
4932 ml_odunit_t
*log_odi
;
4933 int lufs_tid
; /* last valid TID seen */
4936 * no single value is safe to use to indicate
4937 * lufs_tid being invalid so we need a
4938 * seperate variable.
4940 enum boolean lufs_tid_valid
;
4943 * log_get_header_info - get the basic info of the logging filesystem
4946 log_get_header_info(void)
4952 * Mark the global tid as invalid everytime we're called to
4953 * prevent any false positive responses.
4955 lufs_tid_valid
= False
;
4958 * See if we've already set up the header areas. The only problem
4959 * with this approach is we don't reread the on disk data though
4960 * it shouldn't matter since we don't operate on a live disk.
4962 if ((log_eb
!= NULL
) && (log_odi
!= NULL
))
4966 * Either logging is disabled or we've not running 2.7.
4968 if (fs
->fs_logbno
== 0) {
4969 printf("Logging doesn't appear to be enabled on this disk\n");
4974 * To find the log we need to first pick up the block allocation
4975 * data. The block number for that data is fs_logbno in the
4978 if ((b
= getblk((uoff_t
)ldbtob(logbtodb(fs
, fs
->fs_logbno
))))
4980 printf("getblk() indicates an error with logging block\n");
4985 * Next we need to figure out how big the extent data structure
4986 * really is. It can't be more then fs_bsize and you could just
4987 * allocate that but, why get sloppy.
4988 * 1 is subtracted from nextents because extent_block_t contains
4989 * a single extent_t itself.
4991 log_eb
= (extent_block_t
*)b
;
4992 if (log_eb
->type
!= LUFS_EXTENTS
) {
4993 printf("Extents block has invalid type (0x%x)\n",
4997 nb
= sizeof (extent_block_t
) +
4998 (sizeof (extent_t
) * (log_eb
->nextents
- 1));
5000 log_eb
= (extent_block_t
*)malloc(nb
);
5001 if (log_eb
== NULL
) {
5002 printf("Failed to allocate memory for extent block log\n");
5005 memcpy(log_eb
, b
, nb
);
5007 if (log_eb
->nextbno
!= 0)
5009 * Currently, as of 11-Dec-1997 the field nextbno isn't
5010 * implemented. If someone starts using this sucker we'd
5011 * better warn somebody.
5013 printf("WARNING: extent block field nextbno is non-zero!\n");
5016 * Now read in the on disk log structure. This is always in the
5017 * first block of the first extent.
5019 b
= getblk((uoff_t
)ldbtob(logbtodb(fs
, log_eb
->extents
[0].pbno
)));
5020 log_odi
= (ml_odunit_t
*)malloc(sizeof (ml_odunit_t
));
5021 if (log_odi
== NULL
) {
5024 printf("Failed to allocate memory for ondisk structure\n");
5027 memcpy(log_odi
, b
, sizeof (ml_odunit_t
));
5030 * Consistency checks.
5032 if (log_odi
->od_version
!= LUFS_VERSION_LATEST
) {
5037 printf("Version mismatch in on-disk version of log data\n");
5039 } else if (log_odi
->od_badlog
) {
5040 printf("WARNING: Log was marked as bad\n");
5047 log_display_header(void)
5050 if (!log_get_header_info())
5052 * No need to display anything here. The previous routine
5053 * has already done so.
5057 if (fs
->fs_magic
== FS_MAGIC
)
5058 printf("Log block number: 0x%x\n------------------\n",
5061 printf("Log frag number: 0x%x\n------------------\n",
5063 printf("Extent Info\n\t# Extents : %d\n\t# Bytes : 0x%x\n",
5064 log_eb
->nextents
, log_eb
->nbytes
);
5065 printf("\tNext Block : 0x%x\n\tExtent List\n\t--------\n",
5067 for (x
= 0; x
< log_eb
->nextents
; x
++)
5068 printf("\t [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n",
5069 x
, log_eb
->extents
[x
].lbno
, log_eb
->extents
[x
].pbno
,
5070 log_eb
->extents
[x
].nbno
);
5071 printf("\nOn Disk Info\n\tbol_lof : 0x%08x\n\teol_lof : 0x%08x\n",
5072 log_odi
->od_bol_lof
, log_odi
->od_eol_lof
);
5073 printf("\tlog_size : 0x%08x\n",
5074 log_odi
->od_logsize
);
5075 printf("\thead_lof : 0x%08x\tident : 0x%x\n",
5076 log_odi
->od_head_lof
, log_odi
->od_head_ident
);
5077 printf("\ttail_lof : 0x%08x\tident : 0x%x\n\thead_tid : 0x%08x\n",
5078 log_odi
->od_tail_lof
, log_odi
->od_tail_ident
, log_odi
->od_head_tid
);
5079 printf("\tcheck sum : 0x%08x\n", log_odi
->od_chksum
);
5080 if (log_odi
->od_chksum
!=
5081 (log_odi
->od_head_ident
+ log_odi
->od_tail_ident
))
5082 printf("bad checksum: found 0x%08x, should be 0x%08x\n",
5084 log_odi
->od_head_ident
+ log_odi
->od_tail_ident
);
5085 if (log_odi
->od_head_lof
== log_odi
->od_tail_lof
)
5086 printf("\t --- Log is empty ---\n");
5090 * log_lodb -- logical log offset to disk block number
5093 log_lodb(uoff_t off
, diskaddr_t
*pblk
)
5095 uint32_t lblk
= (uint32_t)btodb(off
);
5098 if (!log_get_header_info())
5100 * No need to display anything here. The previous routine
5101 * has already done so.
5105 for (x
= 0; x
< log_eb
->nextents
; x
++)
5106 if ((lblk
>= log_eb
->extents
[x
].lbno
) &&
5107 (lblk
< (log_eb
->extents
[x
].lbno
+
5108 log_eb
->extents
[x
].nbno
))) {
5109 *pblk
= (diskaddr_t
)lblk
- log_eb
->extents
[x
].lbno
+
5110 logbtodb(fs
, log_eb
->extents
[x
].pbno
);
5117 * String names for the enumerated types. These are only used
5118 * for display purposes.
5121 "DT_NONE", "DT_SB", "DT_CG", "DT_SI", "DT_AB",
5122 "DT_ABZERO", "DT_DIR", "DT_INODE", "DT_FBI",
5123 "DT_QR", "DT_COMMIT", "DT_CANCEL", "DT_BOT",
5124 "DT_EOT", "DT_UD", "DT_SUD", "DT_SHAD", "DT_MAX"
5128 * log_read_log -- transfer information from the log and adjust offset
5131 log_read_log(uoff_t
*addr
, caddr_t va
, int nb
, uint32_t *chk
)
5139 if (!log_lodb(*addr
, &pblk
)) {
5140 printf("Invalid log offset\n");
5145 * fsdb getblk() expects offsets not block number.
5147 if ((bp
= getblk((uoff_t
)dbtob(pblk
))) == NULL
)
5150 xfer
= MIN(NB_LEFT_IN_SECTOR(*addr
), nb
);
5152 memcpy(va
, bp
+ blkoff(fs
, *addr
), xfer
);
5159 * If the log offset is now at a sector trailer
5160 * run the checks if requested.
5162 if (NB_LEFT_IN_SECTOR(*addr
) == 0) {
5164 st
= (sect_trailer_t
*)
5165 (bp
+ blkoff(fs
, *addr
));
5166 if (*chk
!= st
->st_ident
) {
5168 "Expected sector trailer id 0x%08x, but saw 0x%08x\n",
5169 *chk
, st
->st_ident
);
5172 *chk
= st
->st_ident
+ 1;
5174 * We update the on disk structure
5175 * transaction ID each time we see
5176 * one. By comparing this value
5177 * to the last valid DT_COMMIT record
5178 * we can determine if our log is
5181 log_odi
->od_head_tid
= st
->st_tid
;
5184 *addr
+= sizeof (sect_trailer_t
);
5186 if ((int32_t)*addr
== log_odi
->od_eol_lof
)
5187 *addr
= log_odi
->od_bol_lof
;
5193 log_nbcommit(uoff_t a
)
5196 * Comments are straight from ufs_log.c
5198 * log is the offset following the commit header. However,
5199 * if the commit header fell on the end-of-sector, then lof
5200 * has already been advanced to the beginning of the next
5201 * sector. So do nothgin. Otherwise, return the remaining
5202 * bytes in the sector.
5204 if ((a
& (DEV_BSIZE
- 1)) == 0)
5207 return (NB_LEFT_IN_SECTOR(a
));
5211 * log_show -- pretty print the deltas. The number of which is determined
5212 * by the log_enum arg. If LOG_ALLDELTAS the routine, as the
5213 * name implies dumps everything. If LOG_NDELTAS, the routine
5214 * will print out "count" deltas starting at "addr". If
5215 * LOG_CHECKSCAN then run through the log checking the st_ident
5219 log_show(enum log_enum l
)
5226 if (!log_get_header_info())
5228 * No need to display any error messages here. The previous
5229 * routine has already done so.
5233 bol
= log_odi
->od_head_lof
;
5234 eol
= log_odi
->od_tail_lof
;
5235 chk
= log_odi
->od_head_ident
;
5238 if ((l
== LOG_ALLDELTAS
) || (l
== LOG_CHECKSCAN
)) {
5239 printf("Empty log.\n");
5242 printf("WARNING: empty log. addr may generate bogus"
5247 * Only reset the "addr" if we've been requested to show all
5248 * deltas in the log.
5250 if ((l
== LOG_ALLDELTAS
) || (l
== LOG_CHECKSCAN
))
5253 if (l
!= LOG_CHECKSCAN
) {
5254 printf(" Log Offset Delta Count Type\n");
5255 printf("-----------------------------------------"
5256 "-----------------\n");
5259 while ((bol
!= eol
) && ((l
== LOG_ALLDELTAS
) ||
5260 (l
== LOG_CHECKSCAN
) || count
--)) {
5261 if (!log_read_log(&addr
, (caddr_t
)&d
, sizeof (d
),
5262 ((l
== LOG_ALLDELTAS
) || (l
== LOG_CHECKSCAN
)) ?
5265 * Two failures are possible. One from getblk()
5266 * which prints out a message or when we've hit
5267 * an invalid block which may or may not indicate
5272 if ((uint32_t)d
.d_nb
> log_odi
->od_logsize
) {
5273 printf("Bad delta entry. size out of bounds\n");
5276 if (l
!= LOG_CHECKSCAN
)
5277 printf("[%04d] %08x %08x.%08x %08x %s\n", x
++, bol
,
5279 dt_str
[d
.d_typ
>= DT_MAX
? DT_MAX
: d
.d_typ
]);
5285 * These two deltas don't have log space
5286 * associated with the entry even though
5293 * Commit records have zero size yet, the
5294 * rest of the current disk block is avoided.
5296 addr
+= log_nbcommit(addr
);
5297 lufs_tid
= log_odi
->od_head_tid
;
5298 lufs_tid_valid
= True
;
5302 if (!log_read_log(&addr
, NULL
, d
.d_nb
,
5303 ((l
== LOG_ALLDELTAS
) ||
5304 (l
== LOG_CHECKSCAN
)) ? &chk
: NULL
))
5308 bol
= (int32_t)addr
;
5312 if (lufs_tid_valid
== True
) {
5313 if (lufs_tid
== log_odi
->od_head_tid
)
5314 printf("scan -- okay\n");
5316 printf("scan -- some transactions have been lost\n");
5318 printf("scan -- failed to find a single valid transaction\n");
5319 printf(" (possibly due to an empty log)\n");