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.
30 "@(#) Copyright(c) 1988 Regents of the University of California.\n\
31 All rights reserved.\n";
35 * fsdb - file system debugger
37 * usage: fsdb [-o suboptions] special
41 * o override some error conditions
42 * p="string" set prompt to string
46 #include <sys/param.h>
47 #include <sys/signal.h>
50 #include <sys/sysmacros.h>
58 #include <sys/types.h>
59 #include <sys/vnode.h>
60 #include <sys/mntent.h>
62 #include <sys/fs/ufs_fsdir.h>
63 #include <sys/fs/ufs_fs.h>
64 #include <sys/fs/ufs_inode.h>
65 #include <sys/fs/ufs_acl.h>
66 #include <sys/fs/ufs_log.h>
70 #include <ufs/dinode.h>
77 #define OLD_FSDB_COMPATIBILITY /* To support the obsoleted "-z" option */
80 #define _PATH_BSHELL "/bin/sh"
81 #endif /* _PATH_BSHELL */
83 * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3
86 #ifndef FS_42POSTBLFMT
87 #define cg_blktot(cgp) (((cgp))->cg_btot)
88 #define cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno])
89 #define cg_inosused(cgp) (((cgp))->cg_iused)
90 #define cg_blksfree(cgp) (((cgp))->cg_free)
91 #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC)
95 * Never changing defines.
97 #define OCTAL 8 /* octal base */
98 #define DECIMAL 10 /* decimal base */
99 #define HEX 16 /* hexadecimal base */
102 * Adjustable defines.
104 #define NBUF 10 /* number of cache buffers */
105 #define PROMPTSIZE 80 /* size of user definable prompt */
106 #define MAXFILES 40000 /* max number of files ls can handle */
107 #define FIRST_DEPTH 10 /* default depth for find and ls */
108 #define SECOND_DEPTH 100 /* second try at depth (maximum) */
109 #define INPUTBUFFER 1040 /* size of input buffer */
110 #define BYTESPERLINE 16 /* bytes per line of /dxo output */
111 #define NREG 36 /* number of save registers */
113 #define DEVPREFIX "/dev/" /* Uninteresting part of "special" */
115 #if defined(OLD_FSDB_COMPATIBILITY)
116 #define FSDB_OPTIONS "o:wp:z:"
118 #define FSDB_OPTIONS "o:wp:"
119 #endif /* OLD_FSDB_COMPATIBILITY */
123 * Values dependent on sizes of structs and such.
125 #define NUMB 3 /* these three are arbitrary, */
126 #define BLOCK 5 /* but must be different from */
127 #define FRAGMENT 7 /* the rest (hence odd). */
128 #define BITSPERCHAR 8 /* couldn't find it anywhere */
129 #define CHAR (sizeof (char))
130 #define SHORT (sizeof (short))
131 #define LONG (sizeof (long))
132 #define U_OFFSET_T (sizeof (u_offset_t)) /* essentially "long long" */
133 #define INODE (sizeof (struct dinode))
134 #define DIRECTORY (sizeof (struct direct))
135 #define CGRP (sizeof (struct cg))
136 #define SB (sizeof (struct fs))
137 #define BLKSIZE (fs->fs_bsize) /* for clarity */
138 #define FRGSIZE (fs->fs_fsize)
139 #define BLKSHIFT (fs->fs_bshift)
140 #define FRGSHIFT (fs->fs_fshift)
141 #define SHADOW_DATA (sizeof (struct ufs_fsd))
144 * Messy macros that would otherwise clutter up such glamorous code.
146 #define itob(i) (((u_offset_t)itod(fs, (i)) << \
147 (u_offset_t)FRGSHIFT) + (u_offset_t)itoo(fs, (i)) * (u_offset_t)INODE)
148 #define min(x, y) ((x) < (y) ? (x) : (y))
149 #define STRINGSIZE(d) ((long)d->d_reclen - \
150 ((long)&d->d_name[0] - (long)&d->d_ino))
151 #define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\
152 (((c) >= 'A')&&((c) <= 'Z')))
153 #define digit(c) (((c) >= '0') && ((c) <= '9'))
154 #define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F'))
155 #define hexletter(c) (((c) >= 'a') && ((c) <= 'f'))
156 #define octaldigit(c) (((c) >= '0') && ((c) <= '7'))
157 #define uppertolower(c) ((c) - 'A' + 'a')
158 #define hextodigit(c) ((c) - 'a' + 10)
159 #define numtodigit(c) ((c) - '0')
162 #define loword(X) (((ushort_t *)&X)[1])
166 #define lobyte(X) (((unsigned char *)&X)[1])
170 * buffer cache structure.
181 * used to hold save registers (see '<' and '>').
183 struct save_registers
{
190 * cd, find, and ls use this to hold filenames. Each filename is broken
191 * up by a slash. In other words, /usr/src/adm would have a len field
192 * of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
193 * src, and adm components of the pathname.
195 static struct filenames
{
196 ino_t ino
; /* inode */
197 long len
; /* number of components */
198 char flag
; /* flag if using SECOND_DEPTH allocator */
199 char find
; /* flag if found by find */
200 char **fname
; /* hold components of pathname */
203 enum log_enum
{ LOG_NDELTAS
, LOG_ALLDELTAS
, LOG_CHECKSCAN
};
207 struct fs un_filesystem
;
208 char un_sbsize
[SBSIZE
];
210 #define filesystem fs_un.un_filesystem
212 struct fs filesystem
, *fs
; /* super block */
218 static char *input_path
[MAXPATHLEN
];
219 static char *stack_path
[MAXPATHLEN
];
220 static char *current_path
[MAXPATHLEN
];
221 static char input_buffer
[INPUTBUFFER
];
223 static char *buffers
;
224 static char scratch
[64];
225 static char BASE
[] = "o u x";
226 static char PROMPT
[PROMPTSIZE
];
227 static char laststyle
= '/';
228 static char lastpo
= 'x';
229 static short input_pointer
;
230 static short current_pathp
;
231 static short stack_pathp
;
232 static short input_pathp
;
233 static short cmp_level
;
235 static short type
= NUMB
;
236 static short dirslot
;
238 static short c_count
;
241 static short trapped
;
242 static short doing_cd
;
243 static short doing_find
;
244 static short find_by_name
;
245 static short find_by_inode
;
246 static short long_list
;
247 static short recursive
;
248 static short objsz
= SHORT
;
249 static short override
= 0;
250 static short wrtflag
= O_RDONLY
;
251 static short base
= HEX
;
252 static short acting_on_inode
;
253 static short acting_on_directory
;
254 static short should_print
= 1;
257 static u_offset_t addr
;
258 static u_offset_t bod_addr
;
259 static u_offset_t value
;
260 static u_offset_t erraddr
;
261 static long errcur_bytes
;
262 static u_offset_t errino
;
264 static long cur_cgrp
;
265 static u_offset_t cur_ino
;
266 static long cur_inum
;
267 static u_offset_t cur_dir
;
268 static long cur_block
;
269 static long cur_bytes
;
270 static long find_ino
;
271 static u_offset_t filesize
;
272 static u_offset_t blocksize
;
273 static long stringsize
;
274 static long count
= 1;
275 static long commands
;
276 static long read_requests
;
277 static long actual_disk_reads
;
279 static long maxfiles
;
280 static long cur_shad
;
283 extern char *malloc(), *calloc();
285 static char getachar();
286 static char *getblk(), *fmtentry();
288 static offset_t
get(short);
292 static long getnumb();
293 static u_offset_t
getdirslot();
294 static unsigned long *print_check(unsigned long *, long *, short, int);
296 static void usage(char *);
297 static void ungetachar(char);
298 static void getnextinput();
299 static void eat_spaces();
300 static void restore_inode(ino_t
);
302 static void ls(struct filenames
*, struct filenames
*, short);
303 static void formatf(struct filenames
*, struct filenames
*);
305 static void follow_path(long, long);
306 static void getname();
307 static void freemem(struct filenames
*, int);
308 static void print_path(char **, int);
310 static void put(u_offset_t
, short);
311 static void insert(struct lbuf
*);
313 static void fprnt(char, char);
315 #ifdef _LARGEFILE64_SOURCE
317 (u_offset_t value
, int fieldsz
, int digits
, int lead
);
318 #define print(value, fieldsz, digits, lead) \
319 printll((u_offset_t)value, fieldsz, digits, lead)
320 #else /* !_LARGEFILE64_SOURCE */
321 static void print(long value
, int fieldsz
, int digits
, int lead
);
322 #endif /* _LARGEFILE64_SOURCE */
323 static void printsb(struct fs
*);
324 static void printcg(struct cg
*);
325 static void pbits(unsigned char *, int);
326 static void old_fsdb(int, char *); /* For old fsdb functionality */
328 static int isnumber(char *);
329 static int icheck(u_offset_t
);
330 static int cgrp_check(long);
331 static int valid_addr();
332 static int match(char *, int);
333 static int devcheck(short);
335 static int compare(char *, char *, short);
336 static int check_addr(short, short *, short *, short);
340 static int getshadowslot(long);
341 static void getshadowdata(long *, int);
342 static void syncshadowscan(int);
343 static void log_display_header(void);
344 static void log_show(enum log_enum
);
352 /* Suboption vector */
353 static char *subopt_v
[] = {
358 #define WRITE_ENABLED 2
366 * main - lines are read up to the unprotected ('\') newline and
367 * held in an input buffer. Characters may be read from the
368 * input buffer using getachar() and unread using ungetachar().
369 * Reading the whole line ahead allows the use of debuggers
370 * which would otherwise be impossible since the debugger
371 * and fsdb could not share stdin.
375 main(int argc
, char *argv
[])
383 volatile short colon
;
387 /* Options/Suboptions processing */
393 * The following are used to support the old fsdb functionality
394 * of clearing an inode. It's better to use 'clri'.
396 int inum
; /* Inode number to clear */
405 while ((opt
= getopt(argc
, argv
, FSDB_OPTIONS
)) != EOF
) {
407 #if defined(OLD_FSDB_COMPATIBILITY)
408 case 'z': /* Hack - Better to use clri */
409 (void) fprintf(stderr
, "%s\n%s\n%s\n%s\n",
410 "Warning: The '-z' option of 'fsdb_ufs' has been declared obsolete",
411 "and may not be supported in a future version of Solaris.",
412 "While this functionality is currently still supported, the",
413 "recommended procedure to clear an inode is to use clri(1M).");
414 if (isnumber(optarg
)) {
416 special
= argv
[optind
];
418 old_fsdb(inum
, special
);
423 /* Should exit() before here */
425 #endif /* OLD_FSDB_COMPATIBILITY */
427 /* UFS Specific Options */
429 while (*subopts
!= '\0') {
430 switch (getsubopt(&subopts
, subopt_v
,
433 printf("error checking off\n");
438 * Change the "-o prompt=foo" option to
439 * "-o p=foo" to match documentation.
440 * ALT_PROMPT continues support for the
441 * undocumented "-o prompt=foo" option so
442 * that we don't break anyone.
446 if (optval
== NULL
) {
447 (void) fprintf(stderr
,
448 "No prompt string\n");
451 (void) strncpy(PROMPT
, optval
,
456 /* suitable for open */
462 /* Should exit here */
472 if ((argc
- optind
) != 1) { /* Should just have "special" left */
475 special
= argv
[optind
];
478 * Unless it's already been set, the default prompt includes the
479 * name of the special device.
482 (void) sprintf(prompt
, "%s > ", special
);
485 * Attempt to open the special file.
487 if ((fd
= open(special
, wrtflag
)) < 0) {
492 * Read in the super block and validate (not too picky).
494 if (llseek(fd
, (offset_t
)(SBLOCK
* DEV_BSIZE
), 0) == -1) {
500 if (read(fd
, &filesystem
, SBSIZE
) != SBSIZE
) {
501 printf("%s: cannot read superblock\n", special
);
505 if (read(fd
, &filesystem
, sizeof (filesystem
)) != sizeof (filesystem
)) {
506 printf("%s: cannot read superblock\n", special
);
512 if ((fs
->fs_magic
!= FS_MAGIC
) && (fs
->fs_magic
!= MTB_UFS_MAGIC
)) {
514 printf("%s: Bad magic number in file system\n",
519 printf("WARNING: Bad magic number in file system. ");
520 printf("Continue? (y/n): ");
521 (void) fflush(stdout
);
522 if (gets(input_buffer
) == NULL
) {
526 if (*input_buffer
!= 'y' && *input_buffer
!= 'Y') {
531 if ((fs
->fs_magic
== FS_MAGIC
&&
532 (fs
->fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2
&&
533 fs
->fs_version
!= UFS_VERSION_MIN
)) ||
534 (fs
->fs_magic
== MTB_UFS_MAGIC
&&
535 (fs
->fs_version
> MTB_UFS_VERSION_1
||
536 fs
->fs_version
< MTB_UFS_VERSION_MIN
))) {
538 printf("%s: Unrecognized UFS version number: %d\n",
539 special
, fs
->fs_version
);
543 printf("WARNING: Unrecognized UFS version number. ");
544 printf("Continue? (y/n): ");
545 (void) fflush(stdout
);
546 if (gets(input_buffer
) == NULL
) {
550 if (*input_buffer
!= 'y' && *input_buffer
!= 'Y') {
554 #ifdef FS_42POSTBLFMT
555 if (fs
->fs_postblformat
== FS_42POSTBLFMT
)
558 printf("fsdb of %s %s -- last mounted on %s\n",
560 (wrtflag
== O_RDWR
) ? "(Opened for write)" : "(Read only)",
563 printf("fs_clean is currently set to ");
564 switch (fs
->fs_clean
) {
567 printf("FSACTIVE\n");
573 printf("FSSTABLE\n");
579 printf("FSSUSPEND\n");
587 printf("%s: fsck may be running on this file system\n",
592 printf("WARNING: fsck may be running on this file system. ");
593 printf("Continue? (y/n): ");
594 (void) fflush(stdout
);
595 if (gets(input_buffer
) == NULL
) {
599 if (*input_buffer
!= 'y' && *input_buffer
!= 'Y') {
604 printf("an unknown value (0x%x)\n", fs
->fs_clean
);
608 if (fs
->fs_state
== (FSOKAY
- fs
->fs_time
)) {
609 printf("fs_state consistent (fs_clean CAN be trusted)\n");
611 printf("fs_state inconsistent (fs_clean CAN'T trusted)\n");
615 * Malloc buffers and set up cache.
617 buffers
= malloc(NBUF
* BLKSIZE
);
618 bhdr
.fwd
= bhdr
.back
= &bhdr
;
619 for (i
= 0; i
< NBUF
; i
++) {
621 bp
->blkaddr
= buffers
+ (i
* BLKSIZE
);
626 * Malloc filenames structure. The space for the actual filenames
627 * is allocated as it needs it. We estimate the size based on the
628 * number of inodes(objects) in the filesystem and the number of
629 * directories. The number of directories are padded by 3 because
630 * each directory traversed during a "find" or "ls -R" needs 3
633 maxfiles
= (long)((((u_offset_t
)fs
->fs_ncg
* (u_offset_t
)fs
->fs_ipg
) -
634 (u_offset_t
)fs
->fs_cstotal
.cs_nifree
) +
635 ((u_offset_t
)fs
->fs_cstotal
.cs_ndir
* (u_offset_t
)3));
637 filenames
= (struct filenames
*)calloc(maxfiles
,
638 sizeof (struct filenames
));
639 if (filenames
== NULL
) {
641 * If we could not allocate memory for all of files
642 * in the filesystem then, back off to the old fixed
646 filenames
= (struct filenames
*)calloc(maxfiles
,
647 sizeof (struct filenames
));
648 if (filenames
== NULL
) {
649 printf("out of memory\n");
656 * Malloc a few filenames (needed by pwd for example).
658 for (i
= 0; i
< MAXPATHLEN
; i
++) {
659 input_path
[i
] = calloc(1, MAXNAMLEN
);
660 stack_path
[i
] = calloc(1, MAXNAMLEN
);
661 current_path
[i
] = calloc(1, MAXNAMLEN
);
662 if (current_path
[i
] == NULL
) {
663 printf("out of memory\n");
669 (void) signal(2, err
);
674 * Main loop and case statement. If an error condition occurs
675 * initialization and recovery is attempted.
679 freemem(filenames
, nfiles
);
687 acting_on_directory
= 0;
692 cur_bytes
= errcur_bytes
;
700 switch (c
= getachar()) {
702 case '\n': /* command end */
703 freemem(filenames
, nfiles
);
705 if (should_print
&& laststyle
== '=') {
715 errcur_bytes
= cur_bytes
;
718 if ((addr
= getdirslot(
719 (long)dirslot
+1)) == 0)
728 addr
= itob(cur_inum
);
737 addr
= cgrp_check(cur_cgrp
);
744 if ((addr
= getshadowslot(
745 (long)cur_shad
+ 1)) == 0)
755 if (valid_addr() == 0)
783 fprnt(laststyle
, lastpo
);
789 c_count
= colon
= acting_on_inode
= 0;
790 acting_on_directory
= 0;
798 errcur_bytes
= cur_bytes
;
801 case '(': /* numeric expression or unknown command */
804 if (digit(c
) || c
== '(') {
811 printf("unknown command or bad syntax\n");
815 case '?': /* general print facilities */
817 fprnt(c
, getachar());
820 case ';': /* command separator and . */
826 case ':': /* command indicator */
834 case ',': /* count indicator */
836 if ((c
= getachar()) == '*') {
850 case '+': /* address addition */
862 errcur_bytes
= cur_bytes
;
865 addr
= getdirslot((long)(dirslot
+ temp
));
871 addr
= itob(cur_inum
);
880 if ((addr
= cgrp_check(cur_cgrp
)) == 0) {
886 addr
= getshadowslot((long)(cur_shad
+ temp
));
893 addr
+= temp
* objsz
;
894 cur_bytes
+= temp
* objsz
;
895 if (valid_addr() == 0)
901 case '-': /* address subtraction */
913 errcur_bytes
= cur_bytes
;
916 addr
= getdirslot((long)(dirslot
- temp
));
922 addr
= itob(cur_inum
);
931 if ((addr
= cgrp_check(cur_cgrp
)) == 0) {
937 addr
= getshadowslot((long)(cur_shad
- temp
));
943 addr
-= temp
* objsz
;
944 cur_bytes
-= temp
* objsz
;
945 if (valid_addr() == 0)
951 case '*': /* address multiplication */
956 if (objsz
!= INODE
&& objsz
!= DIRECTORY
)
962 case '%': /* address division */
968 printf("divide by zero\n");
972 if (objsz
!= INODE
&& objsz
!= DIRECTORY
)
978 case '=': { /* assignment operation */
987 if (acting_on_inode
== 1) {
988 if (c
!= 'o' && c
!= 'd' && c
!= 'x' &&
989 c
!= 'O' && c
!= 'D' && c
!= 'X') {
1002 if (acting_on_inode
== 2)
1005 } else if (acting_on_inode
)
1007 should_print
= star
= 0;
1010 errcur_bytes
= cur_bytes
;
1012 case '"': /* character string */
1014 blocksize
= BLKSIZE
;
1015 filesize
= BLKSIZE
* 2;
1016 cur_bytes
= blkoff(fs
, addr
);
1017 if (objsz
== DIRECTORY
||
1023 case '+': /* =+ operator */
1027 put(value
+temp
, objsz
);
1029 case '-': /* =- operator */
1033 put(value
-temp
, objsz
);
1055 * Truncation is intentional so
1058 time_t tvalue
= (time_t)value
;
1059 printf("%s", ctime(&tvalue
));
1066 if (objsz
== DIRECTORY
) {
1078 if (acting_on_inode
)
1079 print(value
& 0177777L, 12, -8, 0);
1081 print(addr
& 0177777L, 12, -8, 0);
1096 if (acting_on_inode
)
1097 print(value
, 12, -8, 0);
1099 print(addr
, 12, -8, 0);
1103 default: /* regular assignment */
1107 printf("syntax error\n");
1114 case '>': /* save current address */
1118 if (!letter(c
) && !digit(c
)) {
1119 printf("invalid register specification, ");
1120 printf("must be letter or digit\n");
1126 c
= uppertolower(c
);
1130 regs
[c
].sv_addr
= addr
;
1131 regs
[c
].sv_value
= value
;
1132 regs
[c
].sv_objsz
= objsz
;
1135 case '<': /* restore saved address */
1139 if (!letter(c
) && !digit(c
)) {
1140 printf("invalid register specification, ");
1141 printf("must be letter or digit\n");
1147 c
= uppertolower(c
);
1151 addr
= regs
[c
].sv_addr
;
1152 value
= regs
[c
].sv_value
;
1153 objsz
= regs
[c
].sv_objsz
;
1161 if (match("at", 2)) { /* access time */
1162 acting_on_inode
= 2;
1164 addr
= (long)&((struct dinode
*)
1165 (uintptr_t)cur_ino
)->di_atime
;
1177 if (match("block", 2)) { /* block conversion */
1181 blocksize
= BLKSIZE
;
1182 filesize
= BLKSIZE
* 2;
1184 addr
= value
<< FRGSHIFT
;
1192 if (match("bs", 2)) { /* block size */
1193 acting_on_inode
= 1;
1195 if (icheck(cur_ino
) == 0)
1197 addr
= (long)&((struct dinode
*)
1198 (uintptr_t)cur_ino
)->di_blocks
;
1203 if (match("base", 2)) { /* change/show base */
1205 if ((c
= getachar()) == '\n') {
1207 printf("base =\t\t");
1213 printf("DECIMAL\n");
1221 printf("missing '='\n");
1228 printf("invalid base\n");
1234 base
= (short)value
;
1245 if (match("cd", 2)) { /* change directory */
1246 top
= filenames
- 1;
1248 if ((c
= getachar()) == '\n') {
1260 restore_inode((ino_t
)temp
);
1262 print_path(input_path
,
1265 printf(" not found\n");
1267 printf(" ambiguous\n");
1272 restore_inode(filenames
->ino
);
1273 if ((mode
= icheck(addr
)) == 0)
1275 if ((mode
& IFMT
) != IFDIR
) {
1276 restore_inode((ino_t
)temp
);
1277 print_path(input_path
,
1279 printf(" not a directory\n");
1283 for (i
= 0; i
<= top
->len
; i
++)
1284 (void) strcpy(current_path
[i
],
1286 current_pathp
= top
->len
;
1289 if (match("cg", 2)) { /* cylinder group */
1292 if (value
> fs
->fs_ncg
- 1) {
1293 printf("maximum cylinder group is ");
1294 print(fs
->fs_ncg
- 1, 8, -8, 0);
1299 type
= objsz
= CGRP
;
1300 cur_cgrp
= (long)value
;
1301 addr
= cgtod(fs
, cur_cgrp
) << FRGSHIFT
;
1304 if (match("ct", 2)) { /* creation time */
1305 acting_on_inode
= 2;
1307 addr
= (long)&((struct dinode
*)
1308 (uintptr_t)cur_ino
)->di_ctime
;
1320 if (match("directory", 2)) { /* directory offsets */
1325 addr
= (u_offset_t
)getdirslot((long)value
);
1328 if (match("db", 2)) { /* direct block */
1329 acting_on_inode
= 1;
1333 if (value
>= NDADDR
) {
1334 printf("direct blocks are 0 to ");
1335 print(NDADDR
- 1, 0, 0, 0);
1344 &((struct dinode
*)(uintptr_t)cur_ino
)->
1347 cur_bytes
= (value
) * BLKSIZE
;
1348 cur_block
= (long)value
;
1352 if (!value
&& !override
) {
1353 printf("non existent block\n");
1365 if (match("find", 3)) { /* find command */
1369 if (match("fragment", 2)) { /* fragment conv. */
1373 blocksize
= FRGSIZE
;
1374 filesize
= FRGSIZE
* 2;
1376 if (min(blocksize
, filesize
) - cur_bytes
>
1378 blocksize
= cur_bytes
+ FRGSIZE
;
1379 filesize
= blocksize
* 2;
1381 addr
= value
<< FRGSHIFT
;
1389 if (match("file", 4)) { /* access as file */
1390 acting_on_inode
= 1;
1395 if ((mode
= icheck(addr
)) == 0)
1398 switch (mode
& IFMT
) {
1401 printf("special device\n");
1406 if ((addr
= (u_offset_t
)
1407 (bmap((long)value
) << FRGSHIFT
)) == 0)
1409 cur_block
= (long)value
;
1415 if (match("fill", 4)) { /* fill */
1416 if (getachar() != '=') {
1417 printf("missing '='\n");
1421 if (objsz
== INODE
|| objsz
== DIRECTORY
||
1422 objsz
== SHADOW_DATA
) {
1424 "can't fill inode or directory\n");
1438 if (match("gid", 1)) { /* group id */
1439 acting_on_inode
= 1;
1441 addr
= (long)&((struct dinode
*)
1442 (uintptr_t)cur_ino
)->di_gid
;
1454 if (match("inode", 2)) { /* i# to inode conversion */
1470 cur_inum
= (long)value
;
1475 if (match("ib", 2)) { /* indirect block */
1476 acting_on_inode
= 1;
1480 if (value
>= NIADDR
) {
1481 printf("indirect blocks are 0 to ");
1482 print(NIADDR
- 1, 0, 0, 0);
1487 addr
= (long)&((struct dinode
*)(uintptr_t)
1488 cur_ino
)->di_ib
[value
];
1489 cur_bytes
= (NDADDR
- 1) * BLKSIZE
;
1491 for (i
= 0; i
< value
; i
++) {
1492 temp
*= NINDIR(fs
) * BLKSIZE
;
1498 if (!value
&& !override
) {
1499 printf("non existent block\n");
1511 if (match("log_head", 8)) {
1512 log_display_header();
1516 if (match("log_delta", 9)) {
1517 log_show(LOG_NDELTAS
);
1521 if (match("log_show", 8)) {
1522 log_show(LOG_ALLDELTAS
);
1526 if (match("log_chk", 7)) {
1527 log_show(LOG_CHECKSCAN
);
1531 if (match("log_otodb", 9)) {
1532 if (log_lodb((u_offset_t
)addr
, &temp
)) {
1540 if (match("ls", 2)) { /* ls command */
1542 recursive
= long_list
= 0;
1543 top
= filenames
- 1;
1546 if ((c
= getachar()) == '-') {
1547 if ((c
= getachar()) == 'R') {
1550 } else if (c
== 'l') {
1555 printf("'%c'\n", c
);
1561 if ((c
= getachar()) == '\n') {
1570 restore_inode((ino_t
)temp
);
1575 if (error
|| nfiles
== 0) {
1577 print_path(input_path
,
1579 printf(" not found\n");
1585 qsort((char *)filenames
, nfiles
,
1586 sizeof (struct filenames
), ffcmp
);
1587 ls(filenames
, filenames
+ (nfiles
- 1), 0);
1589 printf("no match\n");
1592 restore_inode((ino_t
)temp
);
1595 if (match("ln", 2)) { /* link count */
1596 acting_on_inode
= 1;
1598 addr
= (long)&((struct dinode
*)
1599 (uintptr_t)cur_ino
)->di_nlink
;
1612 if ((mode
= icheck(addr
)) == 0)
1614 if (match("mt", 2)) { /* modification time */
1615 acting_on_inode
= 2;
1617 addr
= (long)&((struct dinode
*)
1618 (uintptr_t)cur_ino
)->di_mtime
;
1623 if (match("md", 2)) { /* mode */
1624 acting_on_inode
= 1;
1626 addr
= (long)&((struct dinode
*)
1627 (uintptr_t)cur_ino
)->di_mode
;
1632 if (match("maj", 2)) { /* major device number */
1633 acting_on_inode
= 1;
1637 addr
= (uintptr_t)&((struct dinode
*)(uintptr_t)
1642 value
= major(dvalue
);
1647 if (match("min", 2)) { /* minor device number */
1648 acting_on_inode
= 1;
1652 addr
= (uintptr_t)&((struct dinode
*)(uintptr_t)
1656 dvalue
= (long)get(LONG
);
1657 value
= minor(dvalue
);
1669 if (match("nm", 1)) { /* directory name */
1671 acting_on_directory
= 1;
1673 if ((cptr
= getblk(addr
)) == 0)
1676 dirp
= (struct direct
*)(cptr
+blkoff(fs
, addr
));
1677 stringsize
= (long)dirp
->d_reclen
-
1678 ((long)&dirp
->d_name
[0] -
1679 (long)&dirp
->d_ino
);
1680 addr
= (long)&((struct direct
*)
1681 (uintptr_t)addr
)->d_name
[0];
1692 if (match("override", 1)) { /* override flip flop */
1693 override
= !override
;
1695 printf("error checking off\n");
1697 printf("error checking on\n");
1707 if (match("pwd", 2)) { /* print working dir */
1708 print_path(current_path
, (int)current_pathp
);
1712 if (match("prompt", 2)) { /* change prompt */
1713 if ((c
= getachar()) != '=') {
1714 printf("missing '='\n");
1718 if ((c
= getachar()) != '"') {
1719 printf("missing '\"'\n");
1724 prompt
= &prompt
[0];
1725 while ((c
= getachar()) != '"' && c
!= '\n') {
1727 if (i
>= PROMPTSIZE
) {
1728 printf("string too long\n");
1741 if (match("quit", 1)) { /* quit */
1742 if ((c
= getachar()) != '\n') {
1755 if (match("sb", 2)) { /* super block */
1766 if (value
> fs
->fs_ncg
- 1) {
1767 printf("maximum super block is ");
1768 print(fs
->fs_ncg
- 1, 8, -8, 0);
1774 cur_cgrp
= (long)value
;
1775 addr
= cgsblock(fs
, cur_cgrp
) << FRGSHIFT
;
1778 if (match("shadow", 2)) { /* shadow inode data */
1781 objsz
= SHADOW_DATA
;
1783 addr
= getshadowslot(value
);
1786 if (match("si", 2)) { /* shadow inode field */
1787 acting_on_inode
= 1;
1789 addr
= (long)&((struct dinode
*)
1790 (uintptr_t)cur_ino
)->di_shadow
;
1796 if (match("sz", 2)) { /* file size */
1797 acting_on_inode
= 1;
1799 addr
= (long)&((struct dinode
*)
1800 (uintptr_t)cur_ino
)->di_size
;
1801 value
= get(U_OFFSET_T
);
1815 if (match("uid", 1)) { /* user id */
1816 acting_on_inode
= 1;
1818 addr
= (long)&((struct dinode
*)
1819 (uintptr_t)cur_ino
)->di_uid
;
1826 case 'F': /* buffer status (internal use only) */
1831 for (bp
= bhdr
.fwd
; bp
!= &bhdr
; bp
= bp
->fwd
)
1832 printf("%8" PRIx64
" %d\n",
1833 bp
->blkno
, bp
->valid
);
1835 printf("# commands\t\t%ld\n", commands
);
1836 printf("# read requests\t\t%ld\n", read_requests
);
1837 printf("# actual disk reads\t%ld\n", actual_disk_reads
);
1840 printf("a colon should precede a command\n");
1844 printf("more letters needed to distinguish command\n");
1852 * usage - print usage and exit
1855 usage(char *progname
)
1857 printf("usage: %s [options] special\n", progname
);
1858 printf("options:\n");
1859 printf("\t-o Specify ufs filesystem sepcific options\n");
1860 printf(" Available suboptions are:\n");
1861 printf("\t\t? display usage\n");
1862 printf("\t\to override some error conditions\n");
1863 printf("\t\tp=\"string\" set prompt to string\n");
1864 printf("\t\tw open for write\n");
1869 * getachar - get next character from input buffer.
1874 return (input_buffer
[input_pointer
++]);
1878 * ungetachar - return character to input buffer.
1883 if (input_pointer
== 0) {
1884 printf("internal problem maintaining input buffer\n");
1888 input_buffer
[--input_pointer
] = c
;
1892 * getnextinput - display the prompt and read an input line.
1893 * An input line is up to 128 characters terminated by the newline
1894 * character. Handle overflow, shell escape, and eof.
1906 printf("%s", prompt
);
1908 while ((c
= getc(stdin
)) != '\n' && !(c
== '!' && i
== 0) &&
1909 !feof(stdin
) && i
<= INPUTBUFFER
- 2)
1910 input_buffer
[i
++] = c
;
1911 if (i
> 0 && input_buffer
[i
- 1] == '\\') {
1912 input_buffer
[i
++] = c
;
1920 if ((pid
= fork()) == 0) {
1921 (void) execl(_PATH_BSHELL
, "sh", "-t", 0);
1925 while ((rpid
= wait(&retcode
)) != pid
&& rpid
!= -1)
1931 printf("input truncated to 128 characters\n");
1932 input_buffer
[i
] = '\n';
1937 * eat_spaces - read extraneous spaces.
1944 while ((c
= getachar()) == ' ')
1950 * restore_inode - set up all inode indicators so inum is now
1951 * the current inode.
1954 restore_inode(ino_t inum
)
1956 errinum
= cur_inum
= inum
;
1957 addr
= errino
= cur_ino
= itob(inum
);
1961 * match - return false if the input does not match string up to
1962 * upto letters. Then proceed to chew up extraneous letters.
1965 match(char *string
, int upto
)
1967 int i
, length
= strlen(string
) - 1;
1969 int save_upto
= upto
;
1973 if ((c
= getachar()) != *string
) {
1974 for (i
= save_upto
- upto
; i
; i
--) {
1984 if ((c
= getachar()) != *string
) {
1993 * expr - expression evaluator. Will evaluate expressions from
1994 * left to right with no operator precedence. Parentheses may
2000 long numb
= 0, temp
;
2006 return (~0); /* error is set so value is ignored */
2025 printf("divide by zero\n");
2038 if (paren
&& !error
) {
2039 printf("missing ')'\n");
2048 * term - used by expression evaluator to get an operand.
2055 switch (c
= getachar()) {
2064 return (-getnumb());
2073 * getnumb - read a number from the input stream. A leading
2074 * zero signifies octal interpretation, a leading '0x'
2075 * signifies hexadecimal, and a leading '0t' signifies
2076 * decimal. If the first character is a character,
2084 long number
= 0, tbase
, num
;
2095 if ((c
= getachar()) == 'x')
2106 c
= savec
= getachar();
2108 c
= uppertolower(c
);
2112 num
= hextodigit(c
);
2118 num
= numtodigit(c
);
2122 num
= numtodigit(c
);
2126 number
= number
* tbase
+ num
;
2133 * find - the syntax is almost identical to the unix command.
2134 * find dir [-name pattern] [-inum number]
2135 * Note: only one of -name or -inum may be used at a time.
2136 * Also, the -print is not needed (implied).
2141 struct filenames
*fn
;
2148 top
= filenames
- 1;
2153 restore_inode((ino_t
)temp
);
2155 print_path(input_path
, (int)input_pathp
);
2157 printf(" not found\n");
2159 printf(" ambiguous\n");
2164 restore_inode(filenames
->ino
);
2165 freemem(filenames
, nfiles
);
2167 top
= filenames
- 1;
2168 if ((mode
= icheck(addr
)) == 0)
2170 if ((mode
& IFMT
) != IFDIR
) {
2171 print_path(input_path
, (int)input_pathp
);
2172 printf(" not a directory\n");
2177 if ((c
= getachar()) != '-') {
2178 restore_inode((ino_t
)temp
);
2179 printf("missing '-'\n");
2183 find_by_name
= find_by_inode
= 0;
2185 if (match("name", 4)) {
2188 } else if (match("inum", 4)) {
2192 restore_inode((ino_t
)temp
);
2195 while ((c
= getachar()) != '\n')
2200 restore_inode((ino_t
)temp
);
2201 printf("use -name or -inum with find\n");
2209 restore_inode((ino_t
)temp
);
2212 for (fn
= filenames
; fn
<= top
; fn
++) {
2216 print(fn
->ino
, 12, -8, 0);
2217 print_path(fn
->fname
, (int)fn
->len
);
2220 restore_inode((ino_t
)temp
);
2224 * ls - do an ls. Should behave exactly as ls(1).
2225 * Only -R and -l is supported and -l gives different results.
2228 ls(struct filenames
*fn0
, struct filenames
*fnlast
, short level
)
2230 struct filenames
*fn
, *fnn
;
2237 qsort((char *)fn0
, fnlast
- fn0
+ 1,
2238 sizeof (struct filenames
), fcmp
);
2240 for (fnn
= fn
, fn
++; fn
<= fnlast
; fnn
= fn
, fn
++) {
2241 if (fnn
->len
!= fn
->len
&& level
== fnn
->len
- 1)
2245 if (strcmp(fn
->fname
[level
], fnn
->fname
[level
]))
2248 if (fn0
->len
&& level
!= fn0
->len
- 1)
2249 ls(fn0
, fnn
, level
+ 1);
2251 if (fn0
!= filenames
)
2253 print_path(fn0
->fname
, (int)(fn0
->len
- 1));
2258 cmp_level
= level
+ 1;
2259 qsort((char *)fn0
, fnn
- fn0
+ 1,
2260 sizeof (struct filenames
), fcmp
);
2262 nfiles
-= fnn
- fn0
+ 1;
2270 * formatf - code lifted from ls.
2273 formatf(struct filenames
*fn0
, struct filenames
*fnlast
)
2275 struct filenames
*fn
;
2276 int width
= 0, w
, nentry
= fnlast
- fn0
+ 1;
2277 int i
, j
, columns
, lines
;
2283 for (fn
= fn0
; fn
<= fnlast
; fn
++) {
2284 int len
= strlen(fn
->fname
[cmp_level
]) + 2;
2289 width
= (width
+ 8) &~ 7;
2290 columns
= 80 / width
;
2294 lines
= (nentry
+ columns
- 1) / columns
;
2295 for (i
= 0; i
< lines
; i
++) {
2296 for (j
= 0; j
< columns
; j
++) {
2297 fn
= fn0
+ j
* lines
+ i
;
2300 print(fn
->ino
, 12, -8, 0);
2302 if ((cp
= fmtentry(fn
)) == NULL
) {
2303 printf("cannot read inode %ld\n", fn
->ino
);
2307 if (fn
+ lines
> fnlast
) {
2314 (void) putchar('\t');
2321 * fmtentry - code lifted from ls.
2324 fmtentry(struct filenames
*fn
)
2326 static char fmtres
[BUFSIZ
];
2328 char *cptr
, *cp
, *dp
;
2331 for (cp
= fn
->fname
[cmp_level
]; *cp
; cp
++) {
2332 if (*cp
< ' ' || *cp
>= 0177)
2337 addr
= itob(fn
->ino
);
2338 if ((cptr
= getblk(addr
)) == 0)
2340 cptr
+= blkoff(fs
, addr
);
2342 ip
= (struct dinode
*)cptr
;
2343 switch (ip
->di_mode
& IFMT
) {
2361 if (ip
->di_mode
& 0111)
2375 * fcmp - routine used by qsort. Will sort first by name, then
2376 * then by pathname length if names are equal. Uses global
2377 * cmp_level to tell what component of the path name we are comparing.
2380 fcmp(struct filenames
*f1
, struct filenames
*f2
)
2384 if ((value
= strcmp(f1
->fname
[cmp_level
], f2
->fname
[cmp_level
])))
2386 return (f1
->len
- f2
->len
);
2390 * ffcmp - routine used by qsort. Sort only by pathname length.
2393 ffcmp(struct filenames
*f1
, struct filenames
*f2
)
2395 return (f1
->len
- f2
->len
);
2399 * parse - set up the call to follow_path.
2407 stack_pathp
= input_pathp
= -1;
2408 if ((c
= getachar()) == '/') {
2409 while ((c
= getachar()) == '/')
2414 if ((c
== '\n') || ((doing_cd
) && (c
== ' '))) {
2427 stack_pathp
= current_pathp
;
2429 input_pathp
= current_pathp
;
2430 for (i
= 0; i
<= current_pathp
; i
++) {
2432 (void) strcpy(input_path
[i
], current_path
[i
]);
2433 (void) strcpy(stack_path
[i
], current_path
[i
]);
2437 follow_path((long)(stack_pathp
+ 1), cur_inum
);
2441 * follow_path - called by cd, find, and ls.
2442 * input_path holds the name typed by the user.
2443 * stack_path holds the name at the current depth.
2446 follow_path(long level
, long inum
)
2448 struct direct
*dirp
;
2449 char **ccptr
, *cptr
;
2451 struct filenames
*tos
, *bos
, *fn
, *fnn
, *fnnn
;
2456 restore_inode((ino_t
)inum
);
2457 if ((mode
= icheck(addr
)) == 0)
2459 if ((mode
& IFMT
) != IFDIR
)
2461 block
= cur_bytes
= 0;
2462 while (cur_bytes
< filesize
) {
2463 if (block
== 0 || bcomp(addr
)) {
2465 if ((addr
= ((u_offset_t
)bmap(block
++) <<
2466 (u_offset_t
)FRGSHIFT
)) == 0)
2468 if ((cptr
= getblk(addr
)) == 0)
2470 cptr
+= blkoff(fs
, addr
);
2473 dirp
= (struct direct
*)cptr
;
2475 if (level
> input_pathp
|| doing_find
||
2476 compare(input_path
[level
], &dirp
->d_name
[0], 1)) {
2478 ((strcmp(dirp
->d_name
, ".") == 0 ||
2479 strcmp(dirp
->d_name
, "..") == 0)))
2481 if (++top
- filenames
>= maxfiles
) {
2482 printf("too many files\n");
2486 top
->fname
= (char **)calloc(FIRST_DEPTH
, sizeof (char **));
2488 if (top
->fname
== 0) {
2489 printf("out of memory\n");
2494 top
->ino
= dirp
->d_ino
;
2495 top
->len
= stack_pathp
;
2499 if (compare(input_path
[0], &dirp
->d_name
[0], 1))
2501 } else if (find_by_inode
)
2502 if (find_ino
== dirp
->d_ino
)
2505 if (top
->len
+ 1 >= FIRST_DEPTH
&& top
->flag
== 0) {
2506 ccptr
= (char **)calloc(SECOND_DEPTH
, sizeof (char **));
2508 printf("out of memory\n");
2512 for (i
= 0; i
< FIRST_DEPTH
; i
++)
2513 ccptr
[i
] = top
->fname
[i
];
2514 free((char *)top
->fname
);
2518 if (top
->len
>= SECOND_DEPTH
) {
2519 printf("maximum depth exceeded, try to cd lower\n");
2524 * Copy current depth.
2526 for (i
= 0; i
<= stack_pathp
; i
++) {
2527 top
->fname
[i
] = calloc(1, strlen(stack_path
[i
])+1);
2528 if (top
->fname
[i
] == 0) {
2529 printf("out of memory\n");
2533 (void) strcpy(top
->fname
[i
], stack_path
[i
]);
2536 * Check for '.' or '..' typed.
2538 if ((level
<= input_pathp
) &&
2539 (strcmp(input_path
[level
], ".") == 0 ||
2540 strcmp(input_path
[level
], "..") == 0)) {
2541 if (strcmp(input_path
[level
], "..") == 0 &&
2543 free(top
->fname
[top
->len
]);
2548 * Check for duplicates.
2550 if (!doing_cd
&& !doing_find
) {
2551 for (fn
= filenames
; fn
< top
; fn
++) {
2552 if (fn
->ino
== dirp
->d_ino
&&
2553 fn
->len
== stack_pathp
+ 1) {
2554 for (i
= 0; i
< fn
->len
; i
++)
2555 if (strcmp(fn
->fname
[i
], stack_path
[i
]))
2558 strcmp(fn
->fname
[i
], dirp
->d_name
))
2561 if (top
== filenames
)
2571 top
->fname
[top
->len
] = calloc(1,
2572 strlen(&dirp
->d_name
[0])+1);
2573 if (top
->fname
[top
->len
] == 0) {
2574 printf("out of memory\n");
2578 (void) strcpy(top
->fname
[top
->len
], &dirp
->d_name
[0]);
2583 addr
+= dirp
->d_reclen
;
2584 cptr
+= dirp
->d_reclen
;
2585 cur_bytes
+= dirp
->d_reclen
;
2587 if (top
< filenames
)
2589 if ((doing_cd
&& level
== input_pathp
) ||
2590 (!recursive
&& !doing_find
&& level
> input_pathp
))
2594 * Check newly added entries to determine if further expansion
2597 for (fn
= tos
; fn
<= bos
; fn
++) {
2599 * Avoid '.' and '..' if beyond input.
2601 if ((recursive
|| doing_find
) && (level
> input_pathp
) &&
2602 (strcmp(fn
->fname
[fn
->len
], ".") == 0 ||
2603 strcmp(fn
->fname
[fn
->len
], "..") == 0))
2605 restore_inode(fn
->ino
);
2606 if ((mode
= icheck(cur_ino
)) == 0)
2608 if ((mode
& IFMT
) == IFDIR
|| level
< input_pathp
) {
2610 * Set up current depth, remove current entry and
2611 * continue recursion.
2613 for (i
= 0; i
<= fn
->len
; i
++)
2614 (void) strcpy(stack_path
[i
], fn
->fname
[i
]);
2615 stack_pathp
= fn
->len
;
2617 (!recursive
|| (recursive
&& level
<= input_pathp
))) {
2619 * Remove current entry by moving others up.
2623 for (fnnn
= fnn
, fnn
++; fnn
<= top
; fnnn
= fnn
, fnn
++) {
2624 fnnn
->ino
= fnn
->ino
;
2625 fnnn
->len
= fnn
->len
;
2626 if (fnnn
->len
+ 1 < FIRST_DEPTH
) {
2627 fnnn
->fname
= (char **)calloc(FIRST_DEPTH
,
2630 } else if (fnnn
->len
< SECOND_DEPTH
) {
2631 fnnn
->fname
= (char **)calloc(SECOND_DEPTH
,
2635 printf("maximum depth exceeded, ");
2636 printf("try to cd lower\n");
2640 for (i
= 0; i
<= fnn
->len
; i
++)
2641 fnnn
->fname
[i
] = fnn
->fname
[i
];
2649 follow_path(level
+ 1, cur_inum
);
2657 * getname - break up the pathname entered by the user into components.
2665 if ((c
= getachar()) == '\n') {
2672 for (i
= 0; i
< MAXNAMLEN
; i
++)
2673 input_path
[input_pathp
][i
] = '\0';
2677 if ((int)strlen(input_path
[input_pathp
]) + 1 >= MAXNAMLEN
) {
2678 printf("maximum name length exceeded, ");
2679 printf("truncating\n");
2682 input_path
[input_pathp
][strlen(input_path
[input_pathp
])] = c
;
2683 input_path
[input_pathp
][strlen(input_path
[input_pathp
])] =
2687 if (c
== ' ' || c
== '\n') {
2691 if (!doing_find
&& c
== '/') {
2692 if (++input_pathp
>= MAXPATHLEN
) {
2693 printf("maximum path length exceeded, ");
2694 printf("truncating\n");
2700 if ((int)strlen(input_path
[input_pathp
]) >= MAXNAMLEN
) {
2701 printf("maximum name length exceeded, truncating\n");
2704 input_path
[input_pathp
][strlen(input_path
[input_pathp
])] = c
;
2709 * compare - check if a filename matches the pattern entered by the user.
2710 * Handles '*', '?', and '[]'.
2713 compare(char *s1
, char *s2
, short at_start
)
2718 while ((c
= *s1
) != NULL
) {
2720 if (at_start
&& s
== s2
&& !letter(*s2
) && !digit(*s2
))
2725 if (compare(s1
, s2
, 0))
2739 if (at_start
&& s
== s2
&& !letter(*s2
) && !digit(*s2
))
2749 printf("missing '-'\n");
2755 printf("missing ']'");
2776 * freemem - free the memory allocated to the filenames structure.
2779 freemem(struct filenames
*p
, int numb
)
2785 for (i
= 0; i
< numb
; i
++, p
++) {
2786 for (j
= 0; j
<= p
->len
; j
++)
2788 free((char *)p
->fname
);
2793 * print_path - print the pathname held in p.
2796 print_path(char *p
[], int pntr
)
2802 for (i
= 0; i
< pntr
; i
++)
2803 printf("%s/", p
[i
]);
2804 printf("%s", p
[pntr
]);
2809 * fill - fill a section with a value or string.
2810 * addr,count:fill=[value, "string"].
2817 short eof_flag
, end
= 0, eof
= 0;
2821 if (wrtflag
== O_RDONLY
) {
2822 printf("not opened for write '-w'\n");
2829 if ((cptr
= getblk(addr
)) == 0)
2838 addr
&= ~(LONG
- 1);
2841 addr
&= ~(SHORT
- 1);
2847 cur_bytes
-= taddr
- addr
;
2848 cptr
+= blkoff(fs
, addr
);
2849 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
2850 for (i
= 0; i
< tcount
; i
++) {
2854 *(long *)cptr
= temp
;
2858 *(short *)cptr
= temp
;
2865 addr
+= (tcount
- 1) * objsz
;
2866 cur_bytes
+= (tcount
- 1) * objsz
;
2867 put((u_offset_t
)temp
, objsz
);
2869 printf("end of file\n");
2872 printf("end of block\n");
2878 * get - read a byte, short or long from the file system.
2879 * The entire block containing the desired item is read
2880 * and the appropriate data is extracted and returned.
2887 u_offset_t temp
= addr
;
2890 if (objsz
== INODE
|| objsz
== SHORT
)
2891 temp
&= ~(SHORT
- 1);
2892 else if (objsz
== DIRECTORY
|| objsz
== LONG
|| objsz
== SHADOW_DATA
)
2893 temp
&= ~(LONG
- 1);
2894 if ((bptr
= getblk(temp
)) == 0)
2896 bptr
+= blkoff(fs
, temp
);
2899 return ((offset_t
)*bptr
);
2903 return ((offset_t
)(*(short *)bptr
));
2908 return ((offset_t
)(*(long *)bptr
));
2911 return (*(offset_t
*)bptr
);
2917 * cgrp_check - make sure that we don't bump the cylinder group
2918 * beyond the total number of cylinder groups or before the start.
2921 cgrp_check(long cgrp
)
2925 printf("beginning of cylinder groups\n");
2927 printf("beginning of super blocks\n");
2931 if (cgrp
>= fs
->fs_ncg
) {
2933 printf("end of cylinder groups\n");
2935 printf("end of super blocks\n");
2940 return (cgtod(fs
, cgrp
) << FRGSHIFT
);
2942 return (cgsblock(fs
, cgrp
) << FRGSHIFT
);
2946 * icheck - make sure we can read the block containing the inode
2947 * and determine the filesize (0 if inode not allocated). Return
2948 * 0 if error otherwise return the mode.
2951 icheck(u_offset_t address
)
2956 if ((cptr
= getblk(address
)) == 0)
2958 cptr
+= blkoff(fs
, address
);
2960 ip
= (struct dinode
*)cptr
;
2961 if ((ip
->di_mode
& IFMT
) == 0) {
2963 printf("inode not allocated\n");
2967 blocksize
= filesize
= 0;
2970 filesize
= ip
->di_size
;
2971 blocksize
= filesize
* 2;
2973 return (ip
->di_mode
);
2977 * getdirslot - get the address of the directory slot desired.
2980 getdirslot(long slot
)
2983 struct direct
*dirp
;
2985 char *string
= &scratch
[0];
2986 short bod
= 0, mode
, temp
;
2992 if (type
!= DIRECTORY
) {
2996 string
= "fragment";
2998 if ((cptr
= getblk(addr
)) == 0)
3000 cptr
+= blkoff(fs
, addr
);
3003 dirp
= (struct direct
*)cptr
;
3004 for (dirslot
= 0; dirslot
< slot
; dirslot
++) {
3006 dirp
= (struct direct
*)cptr
;
3007 if (blocksize
> filesize
) {
3008 if (cur_bytes
+ (long)dirp
->d_reclen
>=
3010 printf("end of file\n");
3012 errcur_bytes
= cur_bytes
;
3013 stringsize
= STRINGSIZE(dirp
);
3018 if (cur_bytes
+ (long)dirp
->d_reclen
>=
3020 printf("end of %s\n", string
);
3022 errcur_bytes
= cur_bytes
;
3023 stringsize
= STRINGSIZE(dirp
);
3028 cptr
+= dirp
->d_reclen
;
3029 addr
+= dirp
->d_reclen
;
3030 cur_bytes
+= dirp
->d_reclen
;
3033 if (blocksize
> filesize
)
3034 printf("beginning of file\n");
3036 printf("beginning of %s\n", string
);
3038 errcur_bytes
= cur_bytes
;
3041 stringsize
= STRINGSIZE(dirp
);
3045 if ((mode
= icheck(addr
)) == 0)
3047 if (!override
&& (mode
& IFDIR
) == 0) {
3048 printf("inode is not a directory\n");
3055 if (i
== 0 || bcomp(addr
)) {
3057 if ((addr
= (bmap((long)i
++) << FRGSHIFT
)) == 0)
3059 if ((cptr
= getblk(addr
)) == 0)
3061 cptr
+= blkoff(fs
, addr
);
3064 dirp
= (struct direct
*)cptr
;
3065 value
= dirp
->d_ino
;
3068 if (cur_bytes
+ (long)dirp
->d_reclen
>= filesize
) {
3069 printf("end of file\n");
3070 dirslot
= slot
- temp
- 1;
3073 errcur_bytes
= cur_bytes
;
3074 stringsize
= STRINGSIZE(dirp
);
3078 addr
+= dirp
->d_reclen
;
3079 cptr
+= dirp
->d_reclen
;
3080 cur_bytes
+= dirp
->d_reclen
;
3085 printf("beginning of file\n");
3087 errcur_bytes
= cur_bytes
;
3090 stringsize
= STRINGSIZE(dirp
);
3097 * getshadowslot - get the address of the shadow data desired
3100 getshadowslot(long shadow
)
3103 short bod
= 0, mode
;
3104 long taddr
, tcurbytes
;
3110 if (type
!= SHADOW_DATA
) {
3111 if (shadow
< cur_shad
) {
3112 printf("can't scan shadow data in reverse\n");
3118 if ((mode
= icheck(addr
)) == 0)
3120 if (!override
&& (mode
& IFMT
) != IFSHAD
) {
3121 printf("inode is not a shadow\n");
3127 syncshadowscan(1); /* force synchronization */
3130 for (; cur_shad
< shadow
; cur_shad
++) {
3132 tcurbytes
= cur_bytes
;
3133 getshadowdata((long *)&fsd
, LONG
+ LONG
);
3135 cur_bytes
= tcurbytes
;
3136 if (cur_bytes
+ (long)fsd
.fsd_size
> filesize
) {
3138 printf("end of file\n");
3140 errcur_bytes
= cur_bytes
;
3144 addr
+= fsd
.fsd_size
;
3145 cur_bytes
+= fsd
.fsd_size
;
3148 if (type
== SHADOW_DATA
)
3149 objsz
= SHADOW_DATA
;
3151 printf("beginning of file\n");
3153 errcur_bytes
= cur_bytes
;
3160 getshadowdata(long *buf
, int len
)
3165 for (tfsd
= 0; tfsd
< len
; tfsd
++) {
3166 buf
[tfsd
] = get(SHADOW_DATA
);
3174 syncshadowscan(int force
)
3177 if (type
== SHADOW_DATA
&& (force
||
3178 lblkno(fs
, addr
) != (bhdr
.fwd
)->blkno
)) {
3179 curblkoff
= blkoff(fs
, cur_bytes
);
3180 addr
= bmap(lblkno(fs
, cur_bytes
)) << FRGSHIFT
;
3182 cur_bytes
+= curblkoff
;
3183 (void) getblk(addr
);
3184 objsz
= SHADOW_DATA
;
3191 * putf - print a byte as an ascii character if possible.
3192 * The exceptions are tabs, newlines, backslashes
3193 * and nulls which are printed as the standard C
3194 * language escapes. Characters which are not
3195 * recognized are printed as \?.
3201 if (c
<= 037 || c
>= 0177 || c
== '\\') {
3226 * put - write an item into the buffer for the current address
3227 * block. The value is checked to make sure that it will
3228 * fit in the size given without truncation. If successful,
3229 * the entire block is written back to the file system.
3232 put(u_offset_t item
, short lngth
)
3239 if (wrtflag
== O_RDONLY
) {
3240 printf("not opened for write '-w'\n");
3245 if ((sbptr
= getblk(addr
)) == 0)
3247 bptr
= sbptr
+ blkoff(fs
, addr
);
3252 olditem
= *(long *)bptr
;
3254 *(long *)bptr
= item
;
3259 olditem
= (long)*(short *)bptr
;
3262 *(short *)bptr
= item
;
3265 olditem
= (long)*bptr
;
3267 *bptr
= lobyte(loword(item
));
3273 if ((s_err
= llseek(fd
, (offset_t
)(addr
& fs
->fs_bmask
), 0)) == -1) {
3275 printf("seek error : %" PRIx64
"\n", addr
);
3278 if ((nbytes
= write(fd
, sbptr
, BLKSIZE
)) != BLKSIZE
) {
3280 printf("write error : addr = %" PRIx64
"\n", addr
);
3281 printf(" : s_err = %lx\n", s_err
);
3282 printf(" : nbytes = %lx\n", nbytes
);
3285 if (!acting_on_inode
&& objsz
!= INODE
&& objsz
!= DIRECTORY
) {
3287 print(olditem
, 8, -8, 0);
3289 print(item
, 8, -8, 0);
3292 if (objsz
== DIRECTORY
) {
3304 * getblk - check if the desired block is in the file system.
3305 * Search the incore buffers to see if the block is already
3306 * available. If successful, unlink the buffer control block
3307 * from its position in the buffer list and re-insert it at
3308 * the head of the list. If failure, use the last buffer
3309 * in the list for the desired block. Again, this control
3310 * block is placed at the head of the list. This process
3311 * will leave commonly requested blocks in the in-core buffers.
3312 * Finally, a pointer to the buffer is returned.
3315 getblk(u_offset_t address
)
3320 unsigned long block
;
3323 block
= lblkno(fs
, address
);
3324 if (block
>= fragstoblks(fs
, fs
->fs_size
)) {
3325 printf("cannot read block %lu\n", block
);
3329 for (bp
= bhdr
.fwd
; bp
!= &bhdr
; bp
= bp
->fwd
)
3330 if (bp
->valid
&& bp
->blkno
== block
)
3332 actual_disk_reads
++;
3336 if ((s_err
= llseek(fd
, (offset_t
)(address
& fs
->fs_bmask
), 0)) == -1) {
3338 printf("seek error : %" PRIx64
"\n", address
);
3341 if ((nbytes
= read(fd
, bp
->blkaddr
, BLKSIZE
)) != BLKSIZE
) {
3343 printf("read error : addr = %" PRIx64
"\n", address
);
3344 printf(" : s_err = %lx\n", s_err
);
3345 printf(" : nbytes = %lx\n", nbytes
);
3349 xit
: bp
->back
->fwd
= bp
->fwd
;
3350 bp
->fwd
->back
= bp
->back
;
3352 return (bp
->blkaddr
);
3356 * insert - place the designated buffer control block
3357 * at the head of the linked list of buffers.
3360 insert(struct lbuf
*bp
)
3365 bhdr
.fwd
->back
= bp
;
3370 * err - called on interrupts. Set the current address
3371 * back to the last address stored in erraddr. Reset all
3372 * appropriate flags. A reset call is made to return
3383 freemem(filenames
, nfiles
);
3385 (void) signal(2, err
);
3389 cur_bytes
= errcur_bytes
;
3393 (void) fseek(stdin
, 0L, 2);
3398 * devcheck - check that the given mode represents a
3399 * special device. The IFCHR bit is on for both
3400 * character and block devices.
3407 switch (md
& IFMT
) {
3413 printf("not character or block device\n");
3419 * nullblk - return error if address is zero. This is done
3420 * to prevent block 0 from being used as an indirect block
3421 * for a large file or as a data block for a small file.
3428 printf("non existent block\n");
3434 * puta - put ascii characters into a buffer. The string
3435 * terminates with a quote or newline. The leading quote,
3436 * which is optional for directory names, was stripped off
3437 * by the assignment case in the main loop.
3446 long maxchars
, s_err
, nbytes
, temp
;
3447 u_offset_t taddr
= addr
;
3448 long tcount
= 0, item
, olditem
= 0;
3450 if (wrtflag
== O_RDONLY
) {
3451 printf("not opened for write '-w'\n");
3455 if ((sbptr
= getblk(addr
)) == 0)
3457 cptr
= sbptr
+ blkoff(fs
, addr
);
3458 if (objsz
== DIRECTORY
) {
3459 if (acting_on_directory
)
3460 maxchars
= stringsize
- 1;
3463 } else if (objsz
== INODE
)
3464 maxchars
= objsz
- (addr
- cur_ino
);
3466 maxchars
= min(blocksize
- cur_bytes
, filesize
- cur_bytes
);
3467 while ((c
= getachar()) != '"') {
3468 if (tcount
>= maxchars
) {
3469 printf("string too long\n");
3470 if (objsz
== DIRECTORY
)
3472 else if (acting_on_inode
|| objsz
== INODE
)
3477 errcur_bytes
= cur_bytes
;
3487 olditem
<<= BITSPERCHAR
;
3488 olditem
+= temp
& 0xff;
3490 switch (c
= getachar()) {
3508 if (objsz
== DIRECTORY
&& acting_on_directory
)
3509 for (i
= tcount
; i
<= maxchars
; i
++)
3511 if ((s_err
= llseek(fd
, (offset_t
)(addr
& fs
->fs_bmask
), 0)) == -1) {
3513 printf("seek error : %" PRIx64
"\n", addr
);
3516 if ((nbytes
= write(fd
, sbptr
, BLKSIZE
)) != BLKSIZE
) {
3518 printf("write error : addr = %" PRIx64
"\n", addr
);
3519 printf(" : s_err = %lx\n", s_err
);
3520 printf(" : nbytes = %lx\n", nbytes
);
3523 if (!acting_on_inode
&& objsz
!= INODE
&& objsz
!= DIRECTORY
) {
3525 cur_bytes
+= tcount
;
3527 if (objsz
!= CHAR
) {
3528 addr
&= ~(objsz
- 1);
3529 cur_bytes
-= taddr
- addr
;
3531 if (addr
== taddr
) {
3535 tcount
= LONG
- (taddr
- addr
);
3537 if ((cptr
= getblk(addr
)) == 0)
3539 cptr
+= blkoff(fs
, addr
);
3543 item
= *(long *)cptr
;
3544 if (tcount
< LONG
) {
3545 olditem
<<= tcount
* BITSPERCHAR
;
3547 for (i
= 0; i
< (tcount
*BITSPERCHAR
); i
++)
3549 olditem
+= item
& (temp
- 1);
3554 item
= (long)*(short *)cptr
;
3555 if (tcount
< SHORT
) {
3556 olditem
<<= tcount
* BITSPERCHAR
;
3558 for (i
= 0; i
< (tcount
* BITSPERCHAR
); i
++)
3560 olditem
+= item
& (temp
- 1);
3562 olditem
&= 0177777L;
3568 print(olditem
, 8, -8, 0);
3570 print(item
, 8, -8, 0);
3573 if (objsz
== DIRECTORY
) {
3587 * fprnt - print data. 'count' elements are printed where '*' will
3588 * print an entire blocks worth or up to the eof, whichever
3589 * occurs first. An error will occur if crossing a block boundary
3590 * is attempted since consecutive blocks don't usually have
3591 * meaning. Current print types:
3592 * / b - print as bytes (base sensitive)
3593 * c - print as characters
3594 * o O - print as octal shorts (longs)
3595 * d D - print as decimal shorts (longs)
3596 * x X - print as hexadecimal shorts (longs)
3597 * ? c - print as cylinder groups
3598 * d - print as directories
3599 * i - print as inodes
3600 * s - print as super blocks
3601 * S - print as shadow data
3604 fprnt(char style
, char po
)
3609 struct direct
*dirp
;
3613 long tinode
, tcount
, temp
;
3615 short offset
, mode
, end
= 0, eof
= 0, eof_flag
;
3616 unsigned short *sptr
;
3617 unsigned long *lptr
;
3618 offset_t curoff
, curioff
;
3632 offset
= blkoff(fs
, addr
);
3641 case 'c': /* print as characters */
3642 case 'b': /* or bytes */
3643 if ((cptr
= getblk(addr
)) == 0)
3647 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
3649 for (i
= 0; tcount
--; i
++) {
3660 if ((i
+ 1) % 16 == 0)
3661 print(*cptr
++ & 0377L,
3664 print(*cptr
++ & 0377L,
3675 errcur_bytes
= cur_bytes
;
3677 printf("end of file\n");
3681 printf("end of block\n");
3683 printf("end of fragment\n");
3688 case 'o': /* print as octal shorts */
3691 case 'd': /* print as decimal shorts */
3694 case 'x': /* print as hex shorts */
3697 if ((cptr
= getblk(addr
)) == 0)
3700 addr
&= ~(SHORT
- 1);
3701 cur_bytes
-= taddr
- addr
;
3702 cptr
+= blkoff(fs
, addr
);
3704 sptr
= (unsigned short *)cptr
;
3706 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
3708 for (i
= 0; tcount
--; i
++) {
3709 sptr
= (unsigned short *)print_check(
3711 (unsigned long *)sptr
,
3715 printf("%06o ", *sptr
++);
3718 printf("%05d ", *sptr
++);
3721 printf("%04x ", *sptr
++);
3731 errcur_bytes
= cur_bytes
;
3733 printf("end of file\n");
3737 printf("end of block\n");
3739 printf("end of fragment\n");
3744 case 'O': /* print as octal longs */
3747 case 'D': /* print as decimal longs */
3750 case 'X': /* print as hex longs */
3753 if ((cptr
= getblk(addr
)) == 0)
3756 addr
&= ~(LONG
- 1);
3757 cur_bytes
-= taddr
- addr
;
3758 cptr
+= blkoff(fs
, addr
);
3760 lptr
= (unsigned long *)cptr
;
3762 tcount
= check_addr(eof_flag
, &end
, &eof
, 0);
3764 for (i
= 0; tcount
--; i
++) {
3765 lptr
= print_check(lptr
, &tcount
,
3769 printf("%011lo ", *lptr
++);
3772 printf("%010lu ", *lptr
++);
3775 printf("%08lx ", *lptr
++);
3785 errcur_bytes
= cur_bytes
;
3787 printf("end of file\n");
3791 printf("end of block\n");
3793 printf("end of fragment\n");
3800 printf("no such print option\n");
3806 case 'c': /* print as cylinder group */
3808 if (cur_cgrp
+ count
> fs
->fs_ncg
) {
3809 tcount
= fs
->fs_ncg
- cur_cgrp
;
3813 addr
&= ~(LONG
- 1);
3814 for (/* void */; tcount
--; /* void */) {
3816 errcur_bytes
= cur_bytes
;
3818 addr
= cgtod(fs
, cur_cgrp
)
3822 if ((cptr
= getblk(addr
)) == 0) {
3827 cptr
+= blkoff(fs
, addr
);
3829 cg
= (struct cg
*)cptr
;
3831 cur_cgrp
= cg
->cg_cgx
+ 1;
3832 type
= objsz
= CGRP
;
3833 if (cur_cgrp
+ count
- 1 > fs
->fs_ncg
) {
3834 tcount
= fs
->fs_ncg
- cur_cgrp
;
3839 if (! override
&& !cg_chkmagic(cg
)) {
3840 printf("invalid cylinder group ");
3841 printf("magic word\n");
3853 printf("end of cylinder groups\n");
3858 case 'd': /* print as directories */
3859 if ((cptr
= getblk(addr
)) == 0)
3862 if (fragoff(fs
, addr
)) {
3863 printf("address must be at the ");
3864 printf("beginning of a fragment\n");
3872 blocksize
= FRGSIZE
;
3873 filesize
= FRGSIZE
* 2;
3877 while (tcount
-- && cur_bytes
< filesize
&&
3878 cur_bytes
< blocksize
&& !bcomp(addr
)) {
3880 dirp
= (struct direct
*)cptr
;
3881 tinode
= dirp
->d_ino
;
3886 print(tinode
, 12, -8, 0);
3887 printf("%s\n", &dirp
->d_name
[0]);
3889 errcur_bytes
= cur_bytes
;
3890 addr
+= dirp
->d_reclen
;
3891 cptr
+= dirp
->d_reclen
;
3892 cur_bytes
+= dirp
->d_reclen
;
3894 stringsize
= STRINGSIZE(dirp
);
3898 cur_bytes
= errcur_bytes
;
3900 if (tcount
>= 0 && !star
) {
3903 printf("end of fragment\n");
3906 printf("end of block\n");
3909 printf("end of directory\n");
3916 case 'i': /* print as inodes */
3918 if ((ip
= (struct dinode
*)getblk(addr
)) == 0)
3920 for (i
= 1; i
< fs
->fs_ncg
; i
++)
3921 if (addr
< (cgimin(fs
, i
) << FRGSHIFT
))
3925 temp
= (addr
- (cgimin(fs
, i
) << FRGSHIFT
)) >> FRGSHIFT
;
3926 temp
= (i
* fs
->fs_ipg
) + fragstoblks(fs
, temp
) *
3928 if (count
+ offset
> INOPB(fs
)) {
3929 tcount
= INOPB(fs
) - offset
;
3935 for (i
= 0; tcount
--; ip
++, temp
++) {
3936 if ((mode
= icheck(addr
)) == 0)
3939 p
= " ugtrwxrwxrwx";
3941 switch (mode
& IFMT
) {
3973 print(temp
, 12, -8, 0);
3976 for (mode
= mode
<< 4; *++p
; mode
= mode
<< 1) {
3983 print(ip
->di_uid
, 8, -4, 0);
3985 print(ip
->di_gid
, 8, -4, 0);
3988 print((long)ip
->di_nlink
, 8, -4, 0);
3990 print(ip
->di_blocks
, 12, -8, 0);
3991 printf("c_flags : ");
3992 print(ip
->di_cflags
, 12, -8, 0);
3994 #ifdef _LARGEFILE64_SOURCE
3995 printll(ip
->di_size
, 20, -16, 0);
3996 #else /* !_LARGEFILE64_SOURCE */
3997 print(ip
->di_size
, 12, -8, 0);
3998 #endif /* _LARGEFILE64_SOURCE */
3999 if (ip
->di_shadow
) {
4001 print(ip
->di_shadow
, 12, -8, 0);
4004 if (ip
->di_oeftflag
) {
4006 print(ip
->di_oeftflag
, 12, -8, 0);
4010 switch (ip
->di_mode
& IFMT
) {
4014 print(major(ip
->di_ordev
), 4, -2, 0);
4016 print(minor(ip
->di_ordev
), 4, -2, 0);
4021 * only display blocks below the
4025 for (i
= 0; i
< NDADDR
; ) {
4026 if (ip
->di_size
<= curoff
)
4028 printf("db#%x: ", i
);
4029 print(ip
->di_db
[i
], 11, -8, 0);
4035 curoff
+= fs
->fs_bsize
;
4041 * curioff keeps track of the number
4042 * of bytes covered by each indirect
4043 * pointer in the inode, and is added
4044 * to curoff each time to get the
4045 * actual offset into the file.
4047 curioff
= fs
->fs_bsize
*
4048 (fs
->fs_bsize
/ sizeof (daddr_t
));
4049 for (i
= 0; i
< NIADDR
; i
++) {
4050 if (ip
->di_size
<= curoff
)
4052 printf("ib#%x: ", i
);
4053 print(ip
->di_ib
[i
], 11, -8, 0);
4056 curioff
*= (fs
->fs_bsize
/
4067 printf("\taccessed: %s", ctime(&t
));
4069 printf("\tmodified: %s", ctime(&t
));
4071 printf("\tcreated : %s", ctime(&t
));
4076 if (c
== '?' && !override
) {
4078 print(temp
, 12, -8, 0);
4079 printf(" is unallocated\n");
4083 cur_ino
= erraddr
= addr
;
4084 errcur_bytes
= cur_bytes
;
4086 addr
= addr
+ INODE
;
4089 cur_bytes
= errcur_bytes
;
4092 printf("end of block\n");
4097 case 's': /* print as super block */
4098 if (cur_cgrp
== -1) {
4099 addr
= SBLOCK
* DEV_BSIZE
;
4102 addr
&= ~(LONG
- 1);
4104 if (cur_cgrp
+ count
> fs
->fs_ncg
) {
4105 tcount
= fs
->fs_ncg
- cur_cgrp
;
4109 for (/* void */; tcount
--; /* void */) {
4111 cur_bytes
= errcur_bytes
;
4113 addr
= cgsblock(fs
, cur_cgrp
)
4117 if ((cptr
= getblk(addr
)) == 0) {
4122 cptr
+= blkoff(fs
, addr
);
4124 sb
= (struct fs
*)cptr
;
4126 for (i
= 0; i
< fs
->fs_ncg
; i
++)
4127 if (addr
== cgsblock(fs
, i
) <<
4130 if (i
== fs
->fs_ncg
)
4135 if (cur_cgrp
+ count
- 1 > fs
->fs_ncg
) {
4136 tcount
= fs
->fs_ncg
- cur_cgrp
;
4141 if ((sb
->fs_magic
!= FS_MAGIC
) &&
4142 (sb
->fs_magic
!= MTB_UFS_MAGIC
)) {
4145 printf("invalid super block ");
4146 printf("magic word\n");
4152 if (sb
->fs_magic
== FS_MAGIC
&&
4154 UFS_EFISTYLE4NONEFI_VERSION_2
&&
4155 sb
->fs_version
!= UFS_VERSION_MIN
)) {
4158 printf("invalid super block ");
4159 printf("version number\n");
4165 if (sb
->fs_magic
== MTB_UFS_MAGIC
&&
4166 (sb
->fs_version
> MTB_UFS_VERSION_1
||
4167 sb
->fs_version
< MTB_UFS_VERSION_MIN
)) {
4170 printf("invalid super block ");
4171 printf("version number\n");
4178 printf("\tsuper block:\n");
4180 printf("\tsuper block in cylinder ");
4182 print(cur_cgrp
- 1, 0, 0, 0);
4191 printf("end of super blocks\n");
4196 case 'S': /* print as shadow data */
4200 cur_bytes
= fragoff(fs
, addr
);
4201 bod_addr
= addr
- cur_bytes
;
4202 /* no more than two fragments */
4203 filesize
= fragroundup(fs
,
4204 bod_addr
+ FRGSIZE
+ 1);
4206 objsz
= SHADOW_DATA
;
4208 (cur_bytes
+ SHADOW_DATA
) <= filesize
&&
4209 (type
!= SHADOW_DATA
||
4210 (cur_bytes
+ SHADOW_DATA
)) <= blocksize
) {
4216 tcur_bytes
= cur_bytes
;
4218 getshadowdata((long *)&fsd
, LONG
+ LONG
);
4220 print((long)fsd
.fsd_type
, 8, -8, 0);
4222 print((long)fsd
.fsd_size
, 8, -8, 0);
4223 tbase
= fsd
.fsd_size
- LONG
- LONG
;
4226 for (i
= 0; i
< tbase
; i
++) {
4227 if (i
% LONG
== 0) {
4233 getshadowdata(&temp
, LONG
);
4237 printf("%02x", (int)(*p
++ & 0377L));
4241 cur_bytes
= tcur_bytes
;
4243 errcur_bytes
= cur_bytes
;
4244 addr
+= FSD_RECSZ((&fsd
), fsd
.fsd_size
);
4245 cur_bytes
+= FSD_RECSZ((&fsd
), fsd
.fsd_size
);
4250 cur_bytes
= errcur_bytes
;
4252 if (tcount
>= 0 && !star
) {
4255 printf("end of fragment\n");
4258 printf("end of shadow data\n");
4266 printf("no such print option\n");
4272 * valid_addr - call check_addr to validate the current address.
4277 short end
= 0, eof
= 0;
4278 long tcount
= count
;
4282 if (cur_bytes
< 0) {
4284 if (blocksize
> filesize
) {
4285 printf("beginning of file\n");
4288 printf("beginning of block\n");
4290 printf("beginning of fragment\n");
4296 (void) check_addr(1, &end
, &eof
, (filesize
< blocksize
));
4299 printf("end of file\n");
4304 if (erraddr
> addr
) {
4306 printf("beginning of block\n");
4308 printf("beginning of fragment\n");
4315 printf("end of block\n");
4317 printf("end of fragment\n");
4325 * check_addr - check if the address crosses the end of block or
4326 * end of file. Return the proper count.
4329 check_addr(short eof_flag
, short *end
, short *eof
, short keep_on
)
4331 long temp
, tcount
= count
, tcur_bytes
= cur_bytes
;
4332 u_offset_t taddr
= addr
;
4334 if (bcomp(addr
+ count
* objsz
- 1) ||
4335 (keep_on
&& taddr
< (bmap(cur_block
) << FRGSHIFT
))) {
4338 cur_bytes
= tcur_bytes
;
4340 if (addr
< erraddr
) {
4341 if (cur_bytes
< 0) {
4343 return (0); /* Value ignored */
4345 temp
= cur_block
- lblkno(fs
, cur_bytes
);
4347 if ((addr
= bmap(cur_block
) << FRGSHIFT
) == 0) {
4349 return (0); /* Value ignored */
4351 temp
= tcur_bytes
- cur_bytes
;
4354 return (0); /* Value ignored */
4356 if (cur_bytes
>= filesize
) {
4358 return (0); /* Value ignored */
4360 temp
= lblkno(fs
, cur_bytes
) - cur_block
;
4362 if ((addr
= bmap(cur_block
) << FRGSHIFT
) == 0) {
4364 return (0); /* Value ignored */
4366 temp
= tcur_bytes
- cur_bytes
;
4369 return (0); /* Value ignored */
4372 tcount
= (blkroundup(fs
, addr
+1)-addr
) / objsz
;
4377 cur_bytes
= tcur_bytes
;
4379 if (blocksize
> filesize
) {
4380 if (cur_bytes
>= filesize
) {
4383 } else if (tcount
> (filesize
- cur_bytes
) / objsz
) {
4384 tcount
= (filesize
- cur_bytes
) / objsz
;
4385 if (!star
|| tcount
== 0)
4389 if (cur_bytes
>= blocksize
) {
4392 } else if (tcount
> (blocksize
- cur_bytes
) / objsz
) {
4393 tcount
= (blocksize
- cur_bytes
) / objsz
;
4394 if (!star
|| tcount
== 0)
4403 * print_check - check if the index needs to be printed and delete
4404 * rows of zeros from the output.
4407 print_check(unsigned long *lptr
, long *tcount
, short tbase
, int i
)
4409 int j
, k
, temp
= BYTESPERLINE
/ objsz
;
4410 short first_time
= 0;
4411 unsigned long *tlptr
;
4412 unsigned short *tsptr
, *sptr
;
4414 sptr
= (unsigned short *)lptr
;
4417 if (i
% temp
== 0) {
4418 if (*tcount
>= temp
- 1) {
4424 for (j
= i
; k
--; j
++)
4425 if (objsz
== SHORT
) {
4432 if (j
> (i
+ temp
- 1)) {
4441 addr
+= BYTESPERLINE
;
4442 cur_bytes
+= BYTESPERLINE
;
4460 return ((unsigned long *)sptr
);
4466 * index - print a byte index for the printout in base b
4467 * with leading zeros.
4475 print(addr
, 8, 8, 1);
4481 * print - print out the value to digits places with/without
4482 * leading zeros and right/left justified in the current base.
4485 #ifdef _LARGEFILE64_SOURCE
4486 printll(u_offset_t value
, int fieldsz
, int digits
, int lead
)
4487 #else /* !_LARGEFILE64_SOURCE */
4488 print(long value
, int fieldsz
, int digits
, int lead
)
4489 #endif /* _LARGEFILE64_SOURCE */
4492 char mode
= BASE
[base
- OCTAL
];
4493 char *string
= &scratch
[0];
4501 digits
= digits
+ (digits
- 1)/((base
>> 1) - 1) + 1;
4506 (void) sprintf(string
, "%%%c%d%d.%d"
4507 #ifdef _LARGEFILE64_SOURCE
4509 #endif /* _LARGEFILE64_SOURCE */
4510 "%c", '-', 0, digits
, lead
, mode
);
4512 (void) sprintf(string
, "%%%d%d.%d"
4513 #ifdef _LARGEFILE64_SOURCE
4515 #endif /* _LARGEFILE64_SOURCE */
4516 "%c", 0, digits
, lead
, mode
);
4519 (void) sprintf(string
, "%%%c%d"
4520 #ifdef _LARGEFILE64_SOURCE
4522 #endif /* _LARGEFILE64_SOURCE */
4523 "%c", '-', digits
, mode
);
4525 (void) sprintf(string
, "%%%d"
4526 #ifdef _LARGEFILE64_SOURCE
4528 #endif /* _LARGEFILE64_SOURCE */
4529 "%c", digits
, mode
);
4531 printf(string
, value
);
4532 for (i
= 0; i
< fieldsz
- digits
; i
++)
4537 * Print out the contents of a superblock.
4540 printsb(struct fs
*fs
)
4542 int c
, i
, j
, k
, size
;
4547 #ifdef FS_42POSTBLFMT
4548 if (fs
->fs_postblformat
== FS_42POSTBLFMT
)
4550 printf("magic\t%lx\tformat\t%s\ttime\t%s", fs
->fs_magic
,
4551 fs
->fs_postblformat
== FS_42POSTBLFMT
? "static" : "dynamic",
4554 printf("magic\t%x\ttime\t%s",
4555 fs
->fs_magic
, ctime(&t
));
4557 printf("version\t%x\n", fs
->fs_version
);
4558 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4559 fs
->fs_cstotal
.cs_nbfree
, fs
->fs_cstotal
.cs_ndir
,
4560 fs
->fs_cstotal
.cs_nifree
, fs
->fs_cstotal
.cs_nffree
);
4561 printf("ncg\t%ld\tncyl\t%ld\tsize\t%ld\tblocks\t%ld\n",
4562 fs
->fs_ncg
, fs
->fs_ncyl
, fs
->fs_size
, fs
->fs_dsize
);
4563 printf("bsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4564 fs
->fs_bsize
, fs
->fs_bshift
, fs
->fs_bmask
);
4565 printf("fsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4566 fs
->fs_fsize
, fs
->fs_fshift
, fs
->fs_fmask
);
4567 printf("frag\t%ld\tshift\t%ld\tfsbtodb\t%ld\n",
4568 fs
->fs_frag
, fs
->fs_fragshift
, fs
->fs_fsbtodb
);
4569 printf("cpg\t%ld\tbpg\t%ld\tfpg\t%ld\tipg\t%ld\n",
4570 fs
->fs_cpg
, fs
->fs_fpg
/ fs
->fs_frag
, fs
->fs_fpg
, fs
->fs_ipg
);
4571 printf("minfree\t%ld%%\toptim\t%s\tmaxcontig %ld\tmaxbpg\t%ld\n",
4572 fs
->fs_minfree
, fs
->fs_optim
== FS_OPTSPACE
? "space" : "time",
4573 fs
->fs_maxcontig
, fs
->fs_maxbpg
);
4574 #ifdef FS_42POSTBLFMT
4576 printf("rotdelay %ldms\tfs_id[0] 0x%lx\tfs_id[1] 0x%lx\trps\t%ld\n",
4577 fs
->fs_rotdelay
, fs
->fs_id
[0], fs
->fs_id
[1], fs
->fs_rps
);
4579 printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
4580 fs
->fs_rotdelay
, fs
->fs_headswitch
, fs
->fs_trkseek
, fs
->fs_rps
);
4582 printf("ntrak\t%ld\tnsect\t%ld\tnpsect\t%ld\tspc\t%ld\n",
4583 fs
->fs_ntrak
, fs
->fs_nsect
, fs
->fs_npsect
, fs
->fs_spc
);
4584 printf("trackskew %ld\n", fs
->fs_trackskew
);
4586 printf("rotdelay %ldms\trps\t%ld\n",
4587 fs
->fs_rotdelay
, fs
->fs_rps
);
4588 printf("ntrak\t%ld\tnsect\t%ld\tspc\t%ld\n",
4589 fs
->fs_ntrak
, fs
->fs_nsect
, fs
->fs_spc
);
4591 printf("si %ld\n", fs
->fs_si
);
4592 printf("nindir\t%ld\tinopb\t%ld\tnspf\t%ld\n",
4593 fs
->fs_nindir
, fs
->fs_inopb
, fs
->fs_nspf
);
4594 printf("sblkno\t%ld\tcblkno\t%ld\tiblkno\t%ld\tdblkno\t%ld\n",
4595 fs
->fs_sblkno
, fs
->fs_cblkno
, fs
->fs_iblkno
, fs
->fs_dblkno
);
4596 printf("sbsize\t%ld\tcgsize\t%ld\tcgoffset %ld\tcgmask\t0x%08lx\n",
4597 fs
->fs_sbsize
, fs
->fs_cgsize
, fs
->fs_cgoffset
, fs
->fs_cgmask
);
4598 printf("csaddr\t%ld\tcssize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4599 fs
->fs_csaddr
, fs
->fs_cssize
, fs
->fs_csshift
, fs
->fs_csmask
);
4600 printf("cgrotor\t%ld\tfmod\t%d\tronly\t%d\n",
4601 fs
->fs_cgrotor
, fs
->fs_fmod
, fs
->fs_ronly
);
4602 #ifdef FS_42POSTBLFMT
4603 if (fs
->fs_cpc
!= 0)
4604 printf("blocks available in each of %ld rotational positions",
4607 printf("insufficient space to maintain rotational tables\n");
4609 for (c
= 0; c
< fs
->fs_cpc
; c
++) {
4610 printf("\ncylinder number %d:", c
);
4611 #ifdef FS_42POSTBLFMT
4612 for (i
= 0; i
< fs
->fs_nrpos
; i
++) {
4614 if (fs_postbl(fs
, c
)[i
] == -1)
4616 printf("\n position %d:\t", i
);
4618 for (j
= fs_postbl(fs
, c
)[i
], k
= 1; /* void */;
4619 j
+= fs_rotbl(fs
)[j
], k
++) {
4623 if (fs_rotbl(fs
)[j
] == 0)
4628 for (i
= 0; i
< NRPOS
; i
++) {
4629 if (fs
->fs_postbl
[c
][i
] == -1)
4631 printf("\n position %d:\t", i
);
4632 for (j
= fs
->fs_postbl
[c
][i
], k
= 1; /* void */;
4633 j
+= fs
->fs_rotbl
[j
], k
++) {
4637 if (fs
->fs_rotbl
[j
] == 0)
4643 printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):");
4644 sip
= calloc(1, fs
->fs_cssize
);
4645 fs
->fs_u
.fs_csp
= (struct csum
*)sip
;
4646 for (i
= 0, j
= 0; i
< fs
->fs_cssize
; i
+= fs
->fs_bsize
, j
++) {
4647 size
= fs
->fs_cssize
- i
< fs
->fs_bsize
?
4648 fs
->fs_cssize
- i
: fs
->fs_bsize
;
4650 (offset_t
)fsbtodb(fs
, (fs
->fs_csaddr
+ j
* fs
->fs_frag
))
4651 * fs
->fs_fsize
/ fsbtodb(fs
, 1), 0);
4652 if (read(fd
, sip
, size
) != size
) {
4653 free(fs
->fs_u
.fs_csp
);
4658 for (i
= 0; i
< fs
->fs_ncg
; i
++) {
4659 struct csum
*cs
= &fs
->fs_cs(fs
, i
);
4662 printf("%d:(%ld,%ld,%ld,%ld) ", i
, cs
->cs_nbfree
, cs
->cs_ndir
,
4663 cs
->cs_nifree
, cs
->cs_nffree
);
4665 free(fs
->fs_u
.fs_csp
);
4667 if (fs
->fs_ncyl
% fs
->fs_cpg
) {
4668 printf("cylinders in last group %d\n",
4669 i
= fs
->fs_ncyl
% fs
->fs_cpg
);
4670 printf("blocks in last group %ld\n",
4671 i
* fs
->fs_spc
/ NSPB(fs
));
4676 * Print out the contents of a cylinder group.
4679 printcg(struct cg
*cg
)
4684 printf("\ncg %ld:\n", cg
->cg_cgx
);
4686 #ifdef FS_42POSTBLFMT
4687 printf("magic\t%lx\ttell\t%llx\ttime\t%s",
4688 fs
->fs_postblformat
== FS_42POSTBLFMT
?
4689 ((struct ocg
*)cg
)->cg_magic
: cg
->cg_magic
,
4690 fsbtodb(fs
, cgtod(fs
, cg
->cg_cgx
)) * fs
->fs_fsize
/ fsbtodb(fs
, 1),
4693 printf("magic\t%x\ttell\t%llx\ttime\t%s",
4695 fsbtodb(fs
, cgtod(fs
, cg
->cg_cgx
)) * fs
->fs_fsize
/ fsbtodb(fs
, 1),
4698 printf("cgx\t%ld\tncyl\t%d\tniblk\t%d\tndblk\t%ld\n",
4699 cg
->cg_cgx
, cg
->cg_ncyl
, cg
->cg_niblk
, cg
->cg_ndblk
);
4700 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4701 cg
->cg_cs
.cs_nbfree
, cg
->cg_cs
.cs_ndir
,
4702 cg
->cg_cs
.cs_nifree
, cg
->cg_cs
.cs_nffree
);
4703 printf("rotor\t%ld\tirotor\t%ld\tfrotor\t%ld\nfrsum",
4704 cg
->cg_rotor
, cg
->cg_irotor
, cg
->cg_frotor
);
4705 for (i
= 1, j
= 0; i
< fs
->fs_frag
; i
++) {
4706 printf("\t%ld", cg
->cg_frsum
[i
]);
4707 j
+= i
* cg
->cg_frsum
[i
];
4709 printf("\nsum of frsum: %d\niused:\t", j
);
4710 pbits((unsigned char *)cg_inosused(cg
), fs
->fs_ipg
);
4712 pbits(cg_blksfree(cg
), fs
->fs_fpg
);
4714 for (i
= 0; i
< fs
->fs_cpg
; i
++) {
4716 if (cg_blktot(cg
)[i
] == 0)
4719 printf(" c%d:\t(%ld)\t", i
, cg_blktot(cg
)[i
]);
4720 #ifdef FS_42POSTBLFMT
4721 for (j
= 0; j
< fs
->fs_nrpos
; j
++) {
4722 if (fs
->fs_cpc
== 0 ||
4724 fs_postbl(fs
, i
% fs
->fs_cpc
)[j
] == -1)
4727 printf(" %d", cg_blks(fs
, cg
, i
)[j
]);
4730 for (j
= 0; j
< NRPOS
; j
++) {
4731 if (fs
->fs_cpc
== 0 ||
4732 fs
->fs_postbl
[i
% fs
->fs_cpc
][j
] == -1)
4734 printf(" %d", cg
->cg_b
[i
][j
]);
4742 * Print out the contents of a bit array.
4745 pbits(unsigned char *cp
, int max
)
4750 for (i
= 0; i
< max
; i
++)
4753 printf(",%s", count
% 6 ? " " : "\n\t");
4757 while ((i
+1) < max
&& isset(cp
, i
+1))
4766 * bcomp - used to check for block over/under flows when stepping through
4776 if (lblkno(fs
, addr
) == (bhdr
.fwd
)->blkno
)
4783 * bmap - maps the logical block number of a file into
4784 * the corresponding physical block on the file
4796 if ((cptr
= getblk(cur_ino
)) == 0)
4799 cptr
+= blkoff(fs
, cur_ino
);
4802 ip
= (struct dinode
*)cptr
;
4806 return (nullblk(nb
) ? 0L : nb
);
4811 for (j
= NIADDR
; j
> 0; j
--) {
4818 printf("file too big\n");
4822 addr
= (uintptr_t)&ip
->di_ib
[NIADDR
- j
];
4826 for (; j
<= NIADDR
; j
++) {
4828 addr
= (nb
<< FRGSHIFT
) + ((bn
/ sh
) % NINDIR(fs
)) * LONG
;
4829 if (nullblk(nb
= get(LONG
)))
4835 #if defined(OLD_FSDB_COMPATIBILITY)
4838 * The following are "tacked on" to support the old fsdb functionality
4839 * of clearing an inode. (All together now...) "It's better to use clri".
4842 #define ISIZE (sizeof (struct dinode))
4843 #define NI (MAXBSIZE/ISIZE)
4846 static struct dinode di_buf
[NI
];
4853 #define sblock sb_un.sblk
4856 old_fsdb(int inum
, char *special
)
4858 int f
; /* File descriptor for "special" */
4865 f
= open(special
, 2);
4868 printf("cannot open %s\n", special
);
4871 (void) llseek(f
, (offset_t
)SBLOCK
* DEV_BSIZE
, 0);
4872 if (read(f
, &sblock
, SBSIZE
) != SBSIZE
) {
4873 printf("cannot read %s\n", special
);
4876 if (sblock
.fs_magic
!= FS_MAGIC
) {
4877 printf("bad super block magic number\n");
4881 printf("%d: is zero\n", inum
);
4884 off
= (u_offset_t
)fsbtodb(&sblock
, itod(&sblock
, inum
)) * DEV_BSIZE
;
4885 (void) llseek(f
, off
, 0);
4886 if (read(f
, (char *)di_buf
, sblock
.fs_bsize
) != sblock
.fs_bsize
) {
4887 printf("%s: read error\n", special
);
4894 * Update the time in superblock, so fsck will check this filesystem.
4896 (void) llseek(f
, (offset_t
)(SBLOCK
* DEV_BSIZE
), 0);
4898 sblock
.fs_time
= (time32_t
)t
;
4899 if (write(f
, &sblock
, SBSIZE
) != SBSIZE
) {
4900 printf("cannot update %s\n", special
);
4904 printf("clearing %u\n", inum
);
4905 off
= (u_offset_t
)fsbtodb(&sblock
, itod(&sblock
, inum
)) * DEV_BSIZE
;
4906 (void) llseek(f
, off
, 0);
4907 read(f
, (char *)di_buf
, sblock
.fs_bsize
);
4908 j
= itoo(&sblock
, inum
);
4909 gen
= di_buf
[j
].di_gen
;
4910 (void) memset((caddr_t
)&di_buf
[j
], 0, ISIZE
);
4911 di_buf
[j
].di_gen
= gen
+ 1;
4912 (void) llseek(f
, off
, 0);
4913 write(f
, (char *)di_buf
, sblock
.fs_bsize
);
4924 while ((c
= *s
++) != NULL
)
4925 if (c
< '0' || c
> '9')
4929 #endif /* OLD_FSDB_COMPATIBILITY */
4931 enum boolean
{ True
, False
};
4932 extent_block_t
*log_eb
;
4933 ml_odunit_t
*log_odi
;
4934 int lufs_tid
; /* last valid TID seen */
4937 * no single value is safe to use to indicate
4938 * lufs_tid being invalid so we need a
4939 * seperate variable.
4941 enum boolean lufs_tid_valid
;
4944 * log_get_header_info - get the basic info of the logging filesystem
4947 log_get_header_info(void)
4953 * Mark the global tid as invalid everytime we're called to
4954 * prevent any false positive responses.
4956 lufs_tid_valid
= False
;
4959 * See if we've already set up the header areas. The only problem
4960 * with this approach is we don't reread the on disk data though
4961 * it shouldn't matter since we don't operate on a live disk.
4963 if ((log_eb
!= NULL
) && (log_odi
!= NULL
))
4967 * Either logging is disabled or we've not running 2.7.
4969 if (fs
->fs_logbno
== 0) {
4970 printf("Logging doesn't appear to be enabled on this disk\n");
4975 * To find the log we need to first pick up the block allocation
4976 * data. The block number for that data is fs_logbno in the
4979 if ((b
= getblk((u_offset_t
)ldbtob(logbtodb(fs
, fs
->fs_logbno
))))
4981 printf("getblk() indicates an error with logging block\n");
4986 * Next we need to figure out how big the extent data structure
4987 * really is. It can't be more then fs_bsize and you could just
4988 * allocate that but, why get sloppy.
4989 * 1 is subtracted from nextents because extent_block_t contains
4990 * a single extent_t itself.
4992 log_eb
= (extent_block_t
*)b
;
4993 if (log_eb
->type
!= LUFS_EXTENTS
) {
4994 printf("Extents block has invalid type (0x%x)\n",
4998 nb
= sizeof (extent_block_t
) +
4999 (sizeof (extent_t
) * (log_eb
->nextents
- 1));
5001 log_eb
= (extent_block_t
*)malloc(nb
);
5002 if (log_eb
== NULL
) {
5003 printf("Failed to allocate memory for extent block log\n");
5006 memcpy(log_eb
, b
, nb
);
5008 if (log_eb
->nextbno
!= 0)
5010 * Currently, as of 11-Dec-1997 the field nextbno isn't
5011 * implemented. If someone starts using this sucker we'd
5012 * better warn somebody.
5014 printf("WARNING: extent block field nextbno is non-zero!\n");
5017 * Now read in the on disk log structure. This is always in the
5018 * first block of the first extent.
5020 b
= getblk((u_offset_t
)ldbtob(logbtodb(fs
, log_eb
->extents
[0].pbno
)));
5021 log_odi
= (ml_odunit_t
*)malloc(sizeof (ml_odunit_t
));
5022 if (log_odi
== NULL
) {
5025 printf("Failed to allocate memory for ondisk structure\n");
5028 memcpy(log_odi
, b
, sizeof (ml_odunit_t
));
5031 * Consistency checks.
5033 if (log_odi
->od_version
!= LUFS_VERSION_LATEST
) {
5038 printf("Version mismatch in on-disk version of log data\n");
5040 } else if (log_odi
->od_badlog
) {
5041 printf("WARNING: Log was marked as bad\n");
5048 log_display_header(void)
5051 if (!log_get_header_info())
5053 * No need to display anything here. The previous routine
5054 * has already done so.
5058 if (fs
->fs_magic
== FS_MAGIC
)
5059 printf("Log block number: 0x%x\n------------------\n",
5062 printf("Log frag number: 0x%x\n------------------\n",
5064 printf("Extent Info\n\t# Extents : %d\n\t# Bytes : 0x%x\n",
5065 log_eb
->nextents
, log_eb
->nbytes
);
5066 printf("\tNext Block : 0x%x\n\tExtent List\n\t--------\n",
5068 for (x
= 0; x
< log_eb
->nextents
; x
++)
5069 printf("\t [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n",
5070 x
, log_eb
->extents
[x
].lbno
, log_eb
->extents
[x
].pbno
,
5071 log_eb
->extents
[x
].nbno
);
5072 printf("\nOn Disk Info\n\tbol_lof : 0x%08x\n\teol_lof : 0x%08x\n",
5073 log_odi
->od_bol_lof
, log_odi
->od_eol_lof
);
5074 printf("\tlog_size : 0x%08x\n",
5075 log_odi
->od_logsize
);
5076 printf("\thead_lof : 0x%08x\tident : 0x%x\n",
5077 log_odi
->od_head_lof
, log_odi
->od_head_ident
);
5078 printf("\ttail_lof : 0x%08x\tident : 0x%x\n\thead_tid : 0x%08x\n",
5079 log_odi
->od_tail_lof
, log_odi
->od_tail_ident
, log_odi
->od_head_tid
);
5080 printf("\tcheck sum : 0x%08x\n", log_odi
->od_chksum
);
5081 if (log_odi
->od_chksum
!=
5082 (log_odi
->od_head_ident
+ log_odi
->od_tail_ident
))
5083 printf("bad checksum: found 0x%08x, should be 0x%08x\n",
5085 log_odi
->od_head_ident
+ log_odi
->od_tail_ident
);
5086 if (log_odi
->od_head_lof
== log_odi
->od_tail_lof
)
5087 printf("\t --- Log is empty ---\n");
5091 * log_lodb -- logical log offset to disk block number
5094 log_lodb(u_offset_t off
, diskaddr_t
*pblk
)
5096 uint32_t lblk
= (uint32_t)btodb(off
);
5099 if (!log_get_header_info())
5101 * No need to display anything here. The previous routine
5102 * has already done so.
5106 for (x
= 0; x
< log_eb
->nextents
; x
++)
5107 if ((lblk
>= log_eb
->extents
[x
].lbno
) &&
5108 (lblk
< (log_eb
->extents
[x
].lbno
+
5109 log_eb
->extents
[x
].nbno
))) {
5110 *pblk
= (diskaddr_t
)lblk
- log_eb
->extents
[x
].lbno
+
5111 logbtodb(fs
, log_eb
->extents
[x
].pbno
);
5118 * String names for the enumerated types. These are only used
5119 * for display purposes.
5122 "DT_NONE", "DT_SB", "DT_CG", "DT_SI", "DT_AB",
5123 "DT_ABZERO", "DT_DIR", "DT_INODE", "DT_FBI",
5124 "DT_QR", "DT_COMMIT", "DT_CANCEL", "DT_BOT",
5125 "DT_EOT", "DT_UD", "DT_SUD", "DT_SHAD", "DT_MAX"
5129 * log_read_log -- transfer information from the log and adjust offset
5132 log_read_log(u_offset_t
*addr
, caddr_t va
, int nb
, uint32_t *chk
)
5140 if (!log_lodb(*addr
, &pblk
)) {
5141 printf("Invalid log offset\n");
5146 * fsdb getblk() expects offsets not block number.
5148 if ((bp
= getblk((u_offset_t
)dbtob(pblk
))) == NULL
)
5151 xfer
= MIN(NB_LEFT_IN_SECTOR(*addr
), nb
);
5153 memcpy(va
, bp
+ blkoff(fs
, *addr
), xfer
);
5160 * If the log offset is now at a sector trailer
5161 * run the checks if requested.
5163 if (NB_LEFT_IN_SECTOR(*addr
) == 0) {
5165 st
= (sect_trailer_t
*)
5166 (bp
+ blkoff(fs
, *addr
));
5167 if (*chk
!= st
->st_ident
) {
5169 "Expected sector trailer id 0x%08x, but saw 0x%08x\n",
5170 *chk
, st
->st_ident
);
5173 *chk
= st
->st_ident
+ 1;
5175 * We update the on disk structure
5176 * transaction ID each time we see
5177 * one. By comparing this value
5178 * to the last valid DT_COMMIT record
5179 * we can determine if our log is
5182 log_odi
->od_head_tid
= st
->st_tid
;
5185 *addr
+= sizeof (sect_trailer_t
);
5187 if ((int32_t)*addr
== log_odi
->od_eol_lof
)
5188 *addr
= log_odi
->od_bol_lof
;
5194 log_nbcommit(u_offset_t a
)
5197 * Comments are straight from ufs_log.c
5199 * log is the offset following the commit header. However,
5200 * if the commit header fell on the end-of-sector, then lof
5201 * has already been advanced to the beginning of the next
5202 * sector. So do nothgin. Otherwise, return the remaining
5203 * bytes in the sector.
5205 if ((a
& (DEV_BSIZE
- 1)) == 0)
5208 return (NB_LEFT_IN_SECTOR(a
));
5212 * log_show -- pretty print the deltas. The number of which is determined
5213 * by the log_enum arg. If LOG_ALLDELTAS the routine, as the
5214 * name implies dumps everything. If LOG_NDELTAS, the routine
5215 * will print out "count" deltas starting at "addr". If
5216 * LOG_CHECKSCAN then run through the log checking the st_ident
5220 log_show(enum log_enum l
)
5227 if (!log_get_header_info())
5229 * No need to display any error messages here. The previous
5230 * routine has already done so.
5234 bol
= log_odi
->od_head_lof
;
5235 eol
= log_odi
->od_tail_lof
;
5236 chk
= log_odi
->od_head_ident
;
5239 if ((l
== LOG_ALLDELTAS
) || (l
== LOG_CHECKSCAN
)) {
5240 printf("Empty log.\n");
5243 printf("WARNING: empty log. addr may generate bogus"
5248 * Only reset the "addr" if we've been requested to show all
5249 * deltas in the log.
5251 if ((l
== LOG_ALLDELTAS
) || (l
== LOG_CHECKSCAN
))
5252 addr
= (u_offset_t
)bol
;
5254 if (l
!= LOG_CHECKSCAN
) {
5255 printf(" Log Offset Delta Count Type\n");
5256 printf("-----------------------------------------"
5257 "-----------------\n");
5260 while ((bol
!= eol
) && ((l
== LOG_ALLDELTAS
) ||
5261 (l
== LOG_CHECKSCAN
) || count
--)) {
5262 if (!log_read_log(&addr
, (caddr_t
)&d
, sizeof (d
),
5263 ((l
== LOG_ALLDELTAS
) || (l
== LOG_CHECKSCAN
)) ?
5266 * Two failures are possible. One from getblk()
5267 * which prints out a message or when we've hit
5268 * an invalid block which may or may not indicate
5273 if ((uint32_t)d
.d_nb
> log_odi
->od_logsize
) {
5274 printf("Bad delta entry. size out of bounds\n");
5277 if (l
!= LOG_CHECKSCAN
)
5278 printf("[%04d] %08x %08x.%08x %08x %s\n", x
++, bol
,
5280 dt_str
[d
.d_typ
>= DT_MAX
? DT_MAX
: d
.d_typ
]);
5286 * These two deltas don't have log space
5287 * associated with the entry even though
5294 * Commit records have zero size yet, the
5295 * rest of the current disk block is avoided.
5297 addr
+= log_nbcommit(addr
);
5298 lufs_tid
= log_odi
->od_head_tid
;
5299 lufs_tid_valid
= True
;
5303 if (!log_read_log(&addr
, NULL
, d
.d_nb
,
5304 ((l
== LOG_ALLDELTAS
) ||
5305 (l
== LOG_CHECKSCAN
)) ? &chk
: NULL
))
5309 bol
= (int32_t)addr
;
5313 if (lufs_tid_valid
== True
) {
5314 if (lufs_tid
== log_odi
->od_head_tid
)
5315 printf("scan -- okay\n");
5317 printf("scan -- some transactions have been lost\n");
5319 printf("scan -- failed to find a single valid transaction\n");
5320 printf(" (possibly due to an empty log)\n");