/*
* Copyright 2015 Gary Mills
*/
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Computer Consoles Inc.
*
* Redistribution and use in source and binary forms are permitted
* provided that: (1) source distributions retain this entire copyright
* notice and comment, and (2) distributions including binaries display
* the following acknowledgement: ``This product includes software
* developed by the University of California, Berkeley and its contributors''
* in the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of this
* software. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright(c) 1988 Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#endif /* not lint */
/*
* fsdb - file system debugger
*
* usage: fsdb [-o suboptions] special
* -o
* ? display usage
* o override some error conditions
* p="string" set prompt to string
* w open for write
*/
#include <inttypes.h>
#include <sys/sysmacros.h>
#ifdef sun
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#else
#include <paths.h>
#endif /* sun */
#include <stdio.h>
#include <setjmp.h>
#ifndef _PATH_BSHELL
#endif /* _PATH_BSHELL */
/*
* Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3
* file system.
*/
#ifndef FS_42POSTBLFMT
#endif
/*
* Never changing defines.
*/
/*
* Adjustable defines.
*/
#if defined(OLD_FSDB_COMPATIBILITY)
#else
#endif /* OLD_FSDB_COMPATIBILITY */
/*
* Values dependent on sizes of structs and such.
*/
#define CHAR (sizeof (char))
#define SHORT (sizeof (short))
#define LONG (sizeof (long))
/*
* Messy macros that would otherwise clutter up such glamorous code.
*/
#define min(x, y) ((x) < (y) ? (x) : (y))
(((c) >= 'A')&&((c) <= 'Z')))
#if !defined(loword)
#endif /* loword */
#if !defined(lobyte)
#endif /* lobyte */
/*
* buffer cache structure.
*/
static struct lbuf {
char *blkaddr;
short valid;
/*
* used to hold save registers (see '<' and '>').
*/
struct save_registers {
long sv_objsz;
/*
* cd, find, and ls use this to hold filenames. Each filename is broken
* of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
* src, and adm components of the pathname.
*/
static struct filenames {
#ifdef sun
static union {
} fs_un;
#else
#endif /* sun */
/*
* Global data.
*/
static char *prompt;
static char *buffers;
static short input_pointer;
static short current_pathp;
static short stack_pathp;
static short input_pathp;
static short cmp_level;
static int nfiles;
static short dirslot;
static short fd;
static short c_count;
static short error;
static short paren;
static short trapped;
static short doing_cd;
static short doing_find;
static short find_by_name;
static short find_by_inode;
static short long_list;
static short recursive;
static short override = 0;
static short acting_on_inode;
static short acting_on_directory;
static short clear;
static short star;
static long errcur_bytes;
static long errinum;
static long cur_cgrp;
static long cur_inum;
static long cur_block;
static long cur_bytes;
static long find_ino;
static long stringsize;
static long commands;
static long read_requests;
static long actual_disk_reads;
static long maxfiles;
static long cur_shad;
#ifndef sun
#endif
static char getachar();
static long bmap();
static long expr();
static long term();
static long getnumb();
static u_offset_t getdirslot();
static unsigned long *print_check(unsigned long *, long *, short, int);
static void usage(char *);
static void ungetachar(char);
static void getnextinput();
static void eat_spaces();
static void restore_inode(ino_t);
static void find();
static void parse();
static void follow_path(long, long);
static void getname();
static void print_path(char **, int);
static void fill();
static void put(u_offset_t, short);
static void puta();
static void fprnt(char, char);
static void index();
#ifdef _LARGEFILE64_SOURCE
static void printll
#else /* !_LARGEFILE64_SOURCE */
#endif /* _LARGEFILE64_SOURCE */
static void pbits(unsigned char *, int);
static void old_fsdb(int, char *); /* For old fsdb functionality */
static int isnumber(char *);
static int icheck(u_offset_t);
static int cgrp_check(long);
static int valid_addr();
static int match(char *, int);
static int devcheck(short);
static int bcomp();
static int compare(char *, char *, short);
static int check_addr(short, short *, short *, short);
static int fcmp();
static int ffcmp();
static int getshadowslot(long);
static void getshadowdata(long *, int);
static void syncshadowscan(int);
static void log_display_header(void);
#ifdef sun
static void err();
#else
static int err();
#endif /* sun */
/* Suboption vector */
static char *subopt_v[] = {
#define OVERRIDE 0
"o",
"p",
"w",
"prompt",
};
/*
* main - lines are read up to the unprotected ('\') newline and
* held in an input buffer. Characters may be read from the
* input buffer using getachar() and unread using ungetachar().
* Reading the whole line ahead allows the use of debuggers
* which would otherwise be impossible since the debugger
* and fsdb could not share stdin.
*/
int
{
char c, *cptr;
short i;
char *progname;
volatile short colon;
short mode;
long temp;
/* Options/Suboptions processing */
int opt;
char *subopts;
char *optval;
/*
* The following are used to support the old fsdb functionality
* of clearing an inode. It's better to use 'clri'.
*/
char *special;
/*
* Parse options.
*/
switch (opt) {
#if defined(OLD_FSDB_COMPATIBILITY)
case 'z': /* Hack - Better to use clri */
"Warning: The '-z' option of 'fsdb_ufs' has been declared obsolete",
"and may not be supported in a future version of Solaris.",
"While this functionality is currently still supported, the",
"recommended procedure to clear an inode is to use clri(1M).");
/* Doesn't return */
} else {
}
/* Should exit() before here */
/*NOTREACHED*/
#endif /* OLD_FSDB_COMPATIBILITY */
case 'o':
/* UFS Specific Options */
while (*subopts != '\0') {
&optval)) {
case OVERRIDE:
printf("error checking off\n");
override = 1;
break;
/*
* Change the "-o prompt=foo" option to
* "-o p=foo" to match documentation.
* ALT_PROMPT continues support for the
* undocumented "-o prompt=foo" option so
* that we don't break anyone.
*/
case NEW_PROMPT:
case ALT_PROMPT:
"No prompt string\n");
}
break;
case WRITE_ENABLED:
/* suitable for open */
break;
default:
/* Should exit here */
}
}
break;
default:
}
}
}
/*
* Unless it's already been set, the default prompt includes the
* name of the special device.
*/
/*
* Attempt to open the special file.
*/
exit(1);
}
/*
* Read in the super block and validate (not too picky).
*/
exit(1);
}
#ifdef sun
exit(1);
}
#else
exit(1);
}
#endif /* sun */
fs = &filesystem;
if (!override) {
printf("%s: Bad magic number in file system\n",
special);
exit(1);
}
printf("WARNING: Bad magic number in file system. ");
printf("Continue? (y/n): ");
exit(1);
}
exit(1);
}
}
if (!override) {
printf("%s: Unrecognized UFS version number: %d\n",
exit(1);
}
printf("WARNING: Unrecognized UFS version number. ");
printf("Continue? (y/n): ");
exit(1);
}
exit(1);
}
}
#ifdef FS_42POSTBLFMT
#endif
printf("fsdb of %s %s -- last mounted on %s\n",
#ifdef sun
printf("fs_clean is currently set to ");
case FSACTIVE:
printf("FSACTIVE\n");
break;
case FSCLEAN:
printf("FSCLEAN\n");
break;
case FSSTABLE:
printf("FSSTABLE\n");
break;
case FSBAD:
printf("FSBAD\n");
break;
case FSSUSPEND:
printf("FSSUSPEND\n");
break;
case FSLOG:
printf("FSLOG\n");
break;
case FSFIX:
printf("FSFIX\n");
if (!override) {
printf("%s: fsck may be running on this file system\n",
special);
exit(1);
}
printf("WARNING: fsck may be running on this file system. ");
printf("Continue? (y/n): ");
exit(1);
}
exit(1);
}
break;
default:
break;
}
printf("fs_state consistent (fs_clean CAN be trusted)\n");
} else {
printf("fs_state inconsistent (fs_clean CAN'T trusted)\n");
}
#endif /* sun */
/*
* Malloc buffers and set up cache.
*/
for (i = 0; i < NBUF; i++) {
}
/*
* Malloc filenames structure. The space for the actual filenames
* is allocated as it needs it. We estimate the size based on the
* number of inodes(objects) in the filesystem and the number of
* directories. The number of directories are padded by 3 because
* each directory traversed during a "find" or "ls -R" needs 3
* entries.
*/
sizeof (struct filenames));
/*
* If we could not allocate memory for all of files
* in the filesystem then, back off to the old fixed
* value.
*/
sizeof (struct filenames));
printf("out of memory\n");
exit(1);
}
}
restore_inode(2);
/*
* Malloc a few filenames (needed by pwd for example).
*/
for (i = 0; i < MAXPATHLEN; i++) {
if (current_path[i] == NULL) {
printf("out of memory\n");
exit(1);
}
}
current_pathp = -1;
getnextinput();
/*
* Main loop and case statement. If an error condition occurs
* initialization and recovery is attempted.
*/
for (;;) {
if (error) {
nfiles = 0;
c_count = 0;
count = 1;
star = 0;
error = 0;
paren = 0;
acting_on_inode = 0;
acting_on_directory = 0;
should_print = 1;
printf("?\n");
getnextinput();
if (error)
continue;
}
c_count++;
switch (c = getachar()) {
case '\n': /* command end */
nfiles = 0;
ungetachar(c);
goto calc;
}
if (c_count == 1) {
clear = 0;
should_print = 1;
switch (objsz) {
case DIRECTORY:
if ((addr = getdirslot(
(long)dirslot+1)) == 0)
should_print = 0;
if (error) {
ungetachar(c);
continue;
}
break;
case INODE:
cur_inum++;
cur_inum--;
should_print = 0;
}
break;
case CGRP:
case SB:
cur_cgrp++;
if (addr == 0) {
cur_cgrp--;
continue;
}
break;
case SHADOW_DATA:
if ((addr = getshadowslot(
(long)cur_shad + 1)) == 0)
should_print = 0;
if (error) {
ungetachar(c);
continue;
}
break;
default:
if (valid_addr() == 0)
continue;
}
}
trapped = 0;
if (should_print)
switch (objsz) {
case DIRECTORY:
break;
case INODE:
if (!error)
break;
case CGRP:
break;
case SB:
break;
case SHADOW_DATA:
break;
case CHAR:
case SHORT:
case LONG:
}
if (error) {
ungetachar(c);
continue;
}
acting_on_directory = 0;
should_print = 1;
getnextinput();
if (error)
continue;
continue;
case '(': /* numeric expression or unknown command */
default:
colon = 0;
if (digit(c) || c == '(') {
ungetachar(c);
continue;
}
printf("unknown command or bad syntax\n");
error++;
continue;
case '?': /* general print facilities */
case '/':
continue;
case ';': /* command separator and . */
case '\t':
case ' ':
case '.':
continue;
case ':': /* command indicator */
colon++;
commands++;
should_print = 0;
stringsize = 0;
trapped = 0;
continue;
case ',': /* count indicator */
if ((c = getachar()) == '*') {
star = 1;
} else {
ungetachar(c);
if (error)
continue;
if (!count)
count = 1;
}
clear = 0;
continue;
case '+': /* address addition */
colon = 0;
c = getachar();
ungetachar(c);
if (c == '\n')
temp = 1;
else {
if (error)
continue;
}
switch (objsz) {
case DIRECTORY:
if (error)
continue;
break;
case INODE:
continue;
}
break;
case CGRP:
case SB:
continue;
}
break;
case SHADOW_DATA:
if (error)
continue;
break;
default:
laststyle = '/';
if (valid_addr() == 0)
continue;
}
continue;
case '-': /* address subtraction */
colon = 0;
c = getachar();
ungetachar(c);
if (c == '\n')
temp = 1;
else {
if (error)
continue;
}
switch (objsz) {
case DIRECTORY:
if (error)
continue;
break;
case INODE:
continue;
}
break;
case CGRP:
case SB:
continue;
}
break;
case SHADOW_DATA:
if (error)
continue;
break;
default:
laststyle = '/';
if (valid_addr() == 0)
continue;
}
continue;
case '*': /* address multiplication */
colon = 0;
if (error)
continue;
laststyle = '/';
continue;
case '%': /* address division */
colon = 0;
if (error)
continue;
if (!temp) {
printf("divide by zero\n");
error++;
continue;
}
laststyle = '/';
continue;
case '=': { /* assignment operation */
short tbase;
calc:
c = getachar();
if (c == '\n') {
ungetachar(c);
c = lastpo;
if (acting_on_inode == 1) {
if (c != 'o' && c != 'd' && c != 'x' &&
c != 'O' && c != 'D' && c != 'X') {
switch (objsz) {
case LONG:
c = lastpo = 'X';
break;
case SHORT:
c = lastpo = 'x';
break;
case CHAR:
c = lastpo = 'c';
}
}
} else {
if (acting_on_inode == 2)
c = lastpo = 't';
}
} else if (acting_on_inode)
lastpo = c;
should_print = star = 0;
count = 1;
switch (c) {
case '"': /* character string */
lastpo = 'X';
}
puta();
continue;
case '+': /* =+ operator */
if (!error)
continue;
case '-': /* =- operator */
if (!error)
continue;
case 'b':
case 'c':
fprnt('?', c);
else
fprnt('/', c);
continue;
case 'i':
continue;
case 's':
continue;
case 't':
case 'T':
laststyle = '=';
printf("\t\t");
{
/*
* Truncation is intentional so
* ctime is happy.
*/
}
continue;
case 'o':
goto otx;
case 'd':
continue;
}
goto otx;
case 'x':
otx:
laststyle = '=';
printf("\t\t");
if (acting_on_inode)
else
printf("\n");
continue;
case 'O':
goto OTX;
case 'D':
goto OTX;
case 'X':
OTX:
laststyle = '=';
printf("\t\t");
if (acting_on_inode)
else
printf("\n");
continue;
default: /* regular assignment */
ungetachar(c);
if (error)
printf("syntax error\n");
else
continue;
}
}
case '>': /* save current address */
colon = 0;
should_print = 0;
c = getachar();
printf("invalid register specification, ");
printf("must be letter or digit\n");
error++;
continue;
}
if (letter(c)) {
if (c < 'a')
c = uppertolower(c);
c = hextodigit(c);
} else
c = numtodigit(c);
continue;
case '<': /* restore saved address */
colon = 0;
should_print = 0;
c = getachar();
printf("invalid register specification, ");
printf("must be letter or digit\n");
error++;
continue;
}
if (letter(c)) {
if (c < 'a')
c = uppertolower(c);
c = hextodigit(c);
} else
c = numtodigit(c);
continue;
case 'a':
if (colon)
colon = 0;
else
goto no_colon;
acting_on_inode = 2;
should_print = 1;
continue;
}
goto bad_syntax;
case 'b':
if (colon)
colon = 0;
else
goto no_colon;
cur_bytes = 0;
}
dirslot = 0;
trapped++;
continue;
}
acting_on_inode = 1;
should_print = 1;
continue;
continue;
}
if ((c = getachar()) == '\n') {
ungetachar(c);
printf("base =\t\t");
switch (base) {
case OCTAL:
printf("OCTAL\n");
continue;
case DECIMAL:
printf("DECIMAL\n");
continue;
case HEX:
printf("HEX\n");
continue;
}
}
if (c != '=') {
printf("missing '='\n");
error++;
continue;
}
switch (value) {
default:
printf("invalid base\n");
error++;
break;
case OCTAL:
case DECIMAL:
case HEX:
}
goto showbase;
}
goto bad_syntax;
case 'c':
if (colon)
colon = 0;
else
goto no_colon;
eat_spaces();
if ((c = getachar()) == '\n') {
ungetachar(c);
current_pathp = -1;
restore_inode(2);
continue;
}
ungetachar(c);
doing_cd = 1;
parse();
doing_cd = 0;
if (nfiles != 1) {
if (!error) {
(int)input_pathp);
if (nfiles == 0)
printf(" not found\n");
else
printf(" ambiguous\n");
error++;
}
continue;
}
continue;
(int)input_pathp);
printf(" not a directory\n");
error++;
continue;
}
(void) strcpy(current_path[i],
continue;
}
printf("maximum cylinder group is ");
printf("\n");
error++;
continue;
}
continue;
}
acting_on_inode = 2;
should_print = 1;
continue;
}
goto bad_syntax;
case 'd':
if (colon)
colon = 0;
else
goto no_colon;
continue;
}
acting_on_inode = 1;
should_print = 1;
printf("direct blocks are 0 to ");
printf("\n");
error++;
continue;
}
continue;
addr = (long)
dirslot = 0;
printf("non existent block\n");
error++;
}
continue;
}
goto bad_syntax;
case 'f':
if (colon)
colon = 0;
else
goto no_colon;
find();
continue;
}
cur_bytes = 0;
}
FRGSIZE) {
}
dirslot = 0;
trapped++;
continue;
}
acting_on_inode = 1;
should_print = 1;
continue;
if (!override) {
case IFCHR:
case IFBLK:
printf("special device\n");
error++;
continue;
}
}
if ((addr = (u_offset_t)
continue;
dirslot = 0;
continue;
}
if (getachar() != '=') {
printf("missing '='\n");
error++;
continue;
}
objsz == SHADOW_DATA) {
"can't fill inode or directory\n");
error++;
continue;
}
fill();
continue;
}
goto bad_syntax;
case 'g':
if (colon)
colon = 0;
else
goto no_colon;
acting_on_inode = 1;
should_print = 1;
continue;
}
goto bad_syntax;
case 'i':
if (colon)
colon = 0;
else
goto no_colon;
if (c_count == 2) {
laststyle = '=';
lastpo = 'i';
should_print = 1;
continue;
}
continue;
continue;
}
acting_on_inode = 1;
should_print = 1;
printf("indirect blocks are 0 to ");
printf("\n");
error++;
continue;
}
temp = 1;
for (i = 0; i < value; i++) {
}
dirslot = 0;
printf("non existent block\n");
error++;
}
continue;
}
goto bad_syntax;
case 'l':
if (colon)
colon = 0;
else
goto no_colon;
should_print = 0;
continue;
}
should_print = 0;
continue;
}
should_print = 0;
continue;
}
should_print = 0;
continue;
}
should_print = 1;
laststyle = '=';
} else
error++;
continue;
}
for (;;) {
eat_spaces();
if ((c = getachar()) == '-') {
if ((c = getachar()) == 'R') {
recursive = 1;
continue;
} else if (c == 'l') {
long_list = 1;
} else {
"unknown option ");
printf("'%c'\n", c);
error++;
break;
}
} else
ungetachar(c);
if ((c = getachar()) == '\n') {
if (c_count != 2) {
ungetachar(c);
break;
}
}
c_count++;
ungetachar(c);
parse();
if (error)
break;
}
recursive = 0;
if (!error) {
(int)input_pathp);
printf(" not found\n");
}
continue;
}
if (nfiles) {
cmp_level = 0;
} else {
printf("no match\n");
error++;
}
continue;
}
acting_on_inode = 1;
should_print = 1;
continue;
}
goto bad_syntax;
case 'm':
if (colon)
colon = 0;
else
goto no_colon;
continue;
acting_on_inode = 2;
should_print = 1;
continue;
}
acting_on_inode = 1;
should_print = 1;
continue;
}
acting_on_inode = 1;
should_print = 1;
continue;
{
long dvalue;
}
continue;
}
acting_on_inode = 1;
should_print = 1;
continue;
{
long dvalue;
}
continue;
}
goto bad_syntax;
case 'n':
if (colon)
colon = 0;
else
goto no_colon;
acting_on_directory = 1;
continue;
/*LINTED*/
continue;
}
goto bad_syntax;
case 'o':
if (colon)
colon = 0;
else
goto no_colon;
if (override)
printf("error checking off\n");
else
printf("error checking on\n");
continue;
}
goto bad_syntax;
case 'p':
if (colon)
colon = 0;
else
goto no_colon;
printf("\n");
continue;
}
if ((c = getachar()) != '=') {
printf("missing '='\n");
error++;
continue;
}
if ((c = getachar()) != '"') {
printf("missing '\"'\n");
error++;
continue;
}
i = 0;
prompt[i++] = c;
if (i >= PROMPTSIZE) {
printf("string too long\n");
error++;
break;
}
}
prompt[i] = '\0';
continue;
}
goto bad_syntax;
case 'q':
if (!colon)
goto no_colon;
if ((c = getachar()) != '\n') {
error++;
continue;
}
exit(0);
}
goto bad_syntax;
case 's':
if (colon)
colon = 0;
else
goto no_colon;
if (c_count == 2) {
cur_cgrp = -1;
laststyle = '=';
lastpo = 's';
should_print = 1;
continue;
}
printf("maximum super block is ");
printf("\n");
error++;
continue;
}
continue;
}
objsz = SHADOW_DATA;
type = SHADOW_DATA;
continue;
}
acting_on_inode = 1;
should_print = 1;
continue;
}
acting_on_inode = 1;
should_print = 1;
objsz = U_OFFSET_T;
laststyle = '=';
lastpo = 'X';
continue;
}
goto bad_syntax;
case 'u':
if (colon)
colon = 0;
else
goto no_colon;
acting_on_inode = 1;
should_print = 1;
continue;
}
goto bad_syntax;
case 'F': /* buffer status (internal use only) */
if (colon)
colon = 0;
else
goto no_colon;
printf("\n");
continue;
printf("a colon should precede a command\n");
error++;
continue;
printf("more letters needed to distinguish command\n");
error++;
continue;
}
}
}
/*
* usage - print usage and exit
*/
static void
{
printf("options:\n");
printf("\t-o Specify ufs filesystem sepcific options\n");
printf(" Available suboptions are:\n");
printf("\t\t? display usage\n");
printf("\t\to override some error conditions\n");
printf("\t\tp=\"string\" set prompt to string\n");
printf("\t\tw open for write\n");
exit(1);
}
/*
* getachar - get next character from input buffer.
*/
static char
getachar()
{
return (input_buffer[input_pointer++]);
}
/*
* ungetachar - return character to input buffer.
*/
static void
ungetachar(char c)
{
if (input_pointer == 0) {
printf("internal problem maintaining input buffer\n");
error++;
return;
}
input_buffer[--input_pointer] = c;
}
/*
* getnextinput - display the prompt and read an input line.
* An input line is up to 128 characters terminated by the newline
* character. Handle overflow, shell escape, and eof.
*/
static void
{
int i;
char c;
int retcode;
i = 0;
input_buffer[i++] = c;
input_buffer[i++] = c;
goto ignore_eol;
}
printf("\n");
exit(0);
}
if (c == '!') {
error++;
return;
}
;
printf("!\n");
goto newline;
}
if (c != '\n')
printf("input truncated to 128 characters\n");
input_buffer[i] = '\n';
input_pointer = 0;
}
/*
* eat_spaces - read extraneous spaces.
*/
static void
{
char c;
while ((c = getachar()) == ' ')
;
ungetachar(c);
}
/*
* restore_inode - set up all inode indicators so inum is now
* the current inode.
*/
static void
{
}
/*
* match - return false if the input does not match string up to
* upto letters. Then proceed to chew up extraneous letters.
*/
static int
{
char c;
while (--upto) {
string++;
ungetachar(c);
c = *--string;
}
return (0);
}
length--;
}
while (length--) {
string++;
ungetachar(c);
return (1);
}
}
return (1);
}
/*
* expr - expression evaluator. Will evaluate expressions from
* left to right with no operator precedence. Parentheses may
* be used.
*/
static long
expr()
{
char c;
for (;;) {
if (error)
return (~0); /* error is set so value is ignored */
c = getachar();
switch (c) {
case '+':
continue;
case '-':
continue;
case '*':
continue;
case '%':
if (!temp) {
printf("divide by zero\n");
error++;
return (~0);
}
continue;
case ')':
paren--;
return (numb);
default:
ungetachar(c);
printf("missing ')'\n");
error++;
}
return (numb);
}
}
}
/*
* term - used by expression evaluator to get an operand.
*/
static long
term()
{
char c;
switch (c = getachar()) {
default:
ungetachar(c);
/*FALLTHRU*/
case '+':
return (getnumb());
case '-':
return (-getnumb());
case '(':
paren++;
return (expr());
}
}
/*
* getnumb - read a number from the input stream. A leading
* zero signifies octal interpretation, a leading '0x'
* signifies hexadecimal, and a leading '0t' signifies
* decimal. If the first character is a character,
* return an error.
*/
static long
getnumb()
{
char c, savec;
extern short error;
c = getachar();
if (!digit(c)) {
error++;
ungetachar(c);
return (-1);
}
if (c == '0') {
if ((c = getachar()) == 'x')
else if (c == 't')
else ungetachar(c);
} else {
ungetachar(c);
}
for (;;) {
if (HEXLETTER(c))
c = uppertolower(c);
switch (tbase) {
case HEX:
if (hexletter(c)) {
num = hextodigit(c);
break;
}
/*FALLTHRU*/
case DECIMAL:
if (digit(c))
num = numtodigit(c);
break;
case OCTAL:
if (octaldigit(c))
num = numtodigit(c);
}
break;
}
return (number);
}
/*
* find - the syntax is almost identical to the unix command.
* find dir [-name pattern] [-inum number]
* Note: only one of -name or -inum may be used at a time.
* Also, the -print is not needed (implied).
*/
static void
find()
{
char c;
long temp;
short mode;
eat_spaces();
doing_cd = 1;
parse();
doing_cd = 0;
if (nfiles != 1) {
if (!error) {
if (nfiles == 0)
printf(" not found\n");
else
printf(" ambiguous\n");
error++;
return;
}
}
nfiles = 0;
return;
printf(" not a directory\n");
error++;
return;
}
eat_spaces();
if ((c = getachar()) != '-') {
printf("missing '-'\n");
error++;
return;
}
find_by_name = find_by_inode = 0;
c = getachar();
eat_spaces();
find_by_name = 1;
eat_spaces();
if (error) {
return;
}
while ((c = getachar()) != '\n')
;
ungetachar(c);
find_by_inode = 1;
} else {
printf("use -name or -inum with find\n");
error++;
return;
}
doing_find = 1;
parse();
doing_find = 0;
if (error) {
return;
}
continue;
printf("i#: ");
printf("\n");
}
}
/*
* ls - do an ls. Should behave exactly as ls(1).
* Only -R and -l is supported and -l gives different results.
*/
static void
{
for (;;) {
}
break;
continue;
break;
}
else {
printf("\n");
printf(":\n");
else
}
return;
}
}
/*
* formatf - code lifted from ls.
*/
static void
{
char *cp;
if (long_list) {
columns = 1;
} else {
}
if (columns == 0)
columns = 1;
}
for (i = 0; i < lines; i++) {
for (j = 0; j < columns; j++) {
if (long_list) {
printf("i#: ");
}
return;
}
printf("\n");
break;
}
while (w < width) {
w = (w + 8) &~ 7;
(void) putchar('\t');
}
}
}
}
/*
* fmtentry - code lifted from ls.
*/
static char *
{
*dp++ = '?';
else
}
return (NULL);
/*LINTED*/
case IFDIR:
*dp++ = '/';
break;
case IFLNK:
*dp++ = '@';
break;
case IFSOCK:
*dp++ = '=';
break;
#ifdef IFIFO
case IFIFO:
*dp++ = 'p';
break;
#endif
case IFCHR:
case IFBLK:
case IFREG:
*dp++ = '*';
else
*dp++ = ' ';
break;
default:
*dp++ = '?';
}
*dp++ = 0;
return (fmtres);
}
/*
* fcmp - routine used by qsort. Will sort first by name, then
* then by pathname length if names are equal. Uses global
* cmp_level to tell what component of the path name we are comparing.
*/
static int
{
int value;
return (value);
}
/*
* ffcmp - routine used by qsort. Sort only by pathname length.
*/
static int
{
}
/*
* parse - set up the call to follow_path.
*/
static void
parse()
{
int i;
char c;
if ((c = getachar()) == '/') {
while ((c = getachar()) == '/')
;
ungetachar(c);
cur_inum = 2;
c = getachar();
ungetachar(c);
if (doing_cd) {
top++;
nfiles = 1;
return;
}
} else
ungetachar(c);
} else {
ungetachar(c);
if (!doing_find)
for (i = 0; i <= current_pathp; i++) {
if (!doing_find)
}
}
getname();
}
/*
* follow_path - called by cd, find, and ls.
* input_path holds the name typed by the user.
* stack_path holds the name at the current depth.
*/
static void
{
int i;
long block;
short mode;
return;
return;
error = 0;
(u_offset_t)FRGSHIFT)) == 0)
break;
break;
}
/*LINTED*/
if ((doing_find) &&
goto duplicate;
printf("too many files\n");
error++;
return;
}
printf("out of memory\n");
error++;
return;
}
nfiles++;
if (doing_find) {
if (find_by_name) {
} else if (find_by_inode)
}
if (ccptr == 0) {
printf("out of memory\n");
error++;
return;
}
for (i = 0; i < FIRST_DEPTH; i++)
}
printf("maximum depth exceeded, try to cd lower\n");
error++;
return;
}
/*
* Copy current depth.
*/
for (i = 0; i <= stack_pathp; i++) {
printf("out of memory\n");
error++;
return;
}
}
/*
* Check for '.' or '..' typed.
*/
if ((level <= input_pathp) &&
}
} else {
/*
* Check for duplicates.
*/
if (!doing_cd && !doing_find) {
break;
continue;
else
top--;
nfiles--;
goto duplicate;
}
}
}
printf("out of memory\n");
error++;
return;
}
}
}
}
}
return;
return;
/*
* Check newly added entries to determine if further expansion
* is required.
*/
/*
* Avoid '.' and '..' if beyond input.
*/
continue;
return;
/*
* Set up current depth, remove current entry and
* continue recursion.
*/
if (!doing_find &&
/*
* Remove current entry by moving others up.
*/
sizeof (char **));
sizeof (char **));
} else {
printf("maximum depth exceeded, ");
printf("try to cd lower\n");
error++;
return;
}
}
fn--;
top--;
bos--;
nfiles--;
}
if (error)
return;
}
}
}
/*
* getname - break up the pathname entered by the user into components.
*/
static void
getname()
{
int i;
char c;
if ((c = getachar()) == '\n') {
ungetachar(c);
return;
}
ungetachar(c);
input_pathp++;
for (i = 0; i < MAXNAMLEN; i++)
for (;;) {
c = getachar();
if (c == '\\') {
printf("maximum name length exceeded, ");
printf("truncating\n");
return;
}
getachar();
continue;
}
if (c == ' ' || c == '\n') {
ungetachar(c);
return;
}
if (!doing_find && c == '/') {
if (++input_pathp >= MAXPATHLEN) {
printf("maximum path length exceeded, ");
printf("truncating\n");
input_pathp--;
return;
}
goto clear;
}
printf("maximum name length exceeded, truncating\n");
return;
}
}
}
/*
* compare - check if a filename matches the pattern entered by the user.
* Handles '*', '?', and '[]'.
*/
static int
{
char c, *s;
s = s2;
if (c == '*') {
return (0);
if (*++s1 == 0)
return (1);
while (*s2) {
return (1);
if (error)
return (0);
s2++;
}
}
if (*s2 == 0)
return (0);
if (c == '\\') {
s1++;
goto compare_chars;
}
if (c == '?') {
return (0);
s1++;
s2++;
continue;
}
if (c == '[') {
s1++;
if (*s1++ != '-') {
printf("missing '-'\n");
error++;
return (0);
}
if (*s1++ != ']') {
printf("missing ']'");
error++;
return (0);
}
s2++;
continue;
}
}
}
continue;
else
return (0);
}
return (1);
return (0);
}
/*
* freemem - free the memory allocated to the filenames structure.
*/
static void
{
int i, j;
if (numb == 0)
return;
for (i = 0; i < numb; i++, p++) {
for (j = 0; j <= p->len; j++)
}
}
/*
* print_path - print the pathname held in p.
*/
static void
{
int i;
printf("/");
if (pntr >= 0) {
for (i = 0; i < pntr; i++)
printf("%s/", p[i]);
}
}
/*
* fill - fill a section with a value or string.
* addr,count:fill=[value, "string"].
*/
static void
fill()
{
char *cptr;
int i;
printf("not opened for write '-w'\n");
error++;
return;
}
if (error)
return;
return;
eof_flag = 0;
else
eof_flag = 1;
switch (objsz) {
case LONG:
break;
case SHORT:
temp &= 0177777L;
break;
case CHAR:
temp &= 0377;
}
for (i = 0; i < tcount; i++) {
switch (objsz) {
case LONG:
/*LINTED*/
break;
case SHORT:
/*LINTED*/
break;
case CHAR:
}
}
if (eof) {
printf("end of file\n");
error++;
} else if (end) {
printf("end of block\n");
error++;
}
}
/*
* get - read a byte, short or long from the file system.
* The entire block containing the desired item is read
* and the appropriate data is extracted and returned.
*/
static offset_t
{
char *bptr;
return (-1);
switch (objsz) {
case CHAR:
case SHORT:
case INODE:
/*LINTED*/
case LONG:
case DIRECTORY:
case SHADOW_DATA:
/*LINTED*/
case U_OFFSET_T:
/*LINTED*/
}
return (0);
}
/*
* cgrp_check - make sure that we don't bump the cylinder group
* beyond the total number of cylinder groups or before the start.
*/
static int
{
if (cgrp < 0) {
printf("beginning of cylinder groups\n");
else
printf("beginning of super blocks\n");
error++;
return (0);
}
printf("end of cylinder groups\n");
else
printf("end of super blocks\n");
error++;
return (0);
}
else
}
/*
* icheck - make sure we can read the block containing the inode
* and determine the filesize (0 if inode not allocated). Return
* 0 if error otherwise return the mode.
*/
int
{
char *cptr;
return (0);
/*LINTED*/
if (!override) {
printf("inode not allocated\n");
error++;
return (0);
}
} else {
trapped++;
}
}
/*
* getdirslot - get the address of the directory slot desired.
*/
static u_offset_t
{
char *cptr;
short i;
if (slot < 0) {
slot = 0;
bod++;
}
string = "block";
else
string = "fragment";
return (0);
cur_bytes = 0;
/*LINTED*/
/*LINTED*/
filesize) {
printf("end of file\n");
error++;
return (addr);
}
} else {
blocksize) {
error++;
return (addr);
}
}
}
if (bod) {
printf("beginning of file\n");
else
error++;
}
return (addr);
} else {
return (0);
printf("inode is not a directory\n");
error++;
return (0);
}
i = cur_bytes = 0;
for (;;) {
error = 0;
break;
break;
}
/*LINTED*/
if (!temp--)
break;
printf("end of file\n");
error++;
return (addr);
}
}
if (bod) {
printf("beginning of file\n");
error++;
}
return (addr);
}
}
/*
* getshadowslot - get the address of the shadow data desired
*/
static int
{
if (shadow < 0) {
shadow = 0;
bod++;
}
if (type != SHADOW_DATA) {
printf("can't scan shadow data in reverse\n");
error++;
return (0);
}
} else {
return (0);
printf("inode is not a shadow\n");
error++;
return (0);
}
cur_bytes = 0;
cur_shad = 0;
}
syncshadowscan(0);
printf("end of file\n");
error++;
return (addr);
}
syncshadowscan(0);
}
if (type == SHADOW_DATA)
objsz = SHADOW_DATA;
if (bod) {
printf("beginning of file\n");
error++;
}
return (addr);
}
static void
{
long tfsd;
syncshadowscan(0);
}
}
static void
{
long curblkoff;
objsz = SHADOW_DATA;
}
}
/*
* putf - print a byte as an ascii character if possible.
* The exceptions are tabs, newlines, backslashes
* and nulls which are printed as the standard C
* language escapes. Characters which are not
* recognized are printed as \?.
*/
static void
putf(char c)
{
if (c <= 037 || c >= 0177 || c == '\\') {
printf("\\");
switch (c) {
case '\\':
printf("\\");
break;
case '\t':
printf("t");
break;
case '\n':
printf("n");
break;
case '\0':
printf("0");
break;
default:
printf("?");
}
} else {
printf("%c", c);
printf(" ");
}
}
/*
* put - write an item into the buffer for the current address
* block. The value is checked to make sure that it will
* fit in the size given without truncation. If successful,
* the entire block is written back to the file system.
*/
static void
{
long olditem;
printf("not opened for write '-w'\n");
error++;
return;
}
return;
switch (objsz) {
case LONG:
case DIRECTORY:
/*LINTED*/
/*LINTED*/
break;
case SHORT:
case INODE:
/*LINTED*/
item &= 0177777L;
/*LINTED*/
break;
case CHAR:
item &= 0377;
break;
default:
error++;
return;
}
error++;
return;
}
error++;
return;
}
printf("\t=\t");
printf("\n");
} else {
} else {
}
}
}
/*
* getblk - check if the desired block is in the file system.
* Search the incore buffers to see if the block is already
* available. If successful, unlink the buffer control block
* from its position in the buffer list and re-insert it at
* the head of the list. If failure, use the last buffer
* in the list for the desired block. Again, this control
* block is placed at the head of the list. This process
* will leave commonly requested blocks in the in-core buffers.
* Finally, a pointer to the buffer is returned.
*/
static char *
{
unsigned long block;
error++;
return (0);
}
goto xit;
error++;
return (0);
}
error++;
return (0);
}
}
/*
* insert - place the designated buffer control block
* at the head of the linked list of buffers.
*/
static void
{
}
/*
* err - called on interrupts. Set the current address
* back to the last address stored in erraddr. Reset all
* appropriate flags. A reset call is made to return
* to the main loop;
*/
#ifdef sun
/*ARGSUSED*/
static void
#else
err()
#endif /* sun */
{
nfiles = 0;
error = 0;
c_count = 0;
printf("\n?\n");
}
/*
* devcheck - check that the given mode represents a
* special device. The IFCHR bit is on for both
* character and block devices.
*/
static int
{
if (override)
return (0);
case IFCHR:
case IFBLK:
return (0);
}
printf("not character or block device\n");
error++;
return (1);
}
/*
* nullblk - return error if address is zero. This is done
* to prevent block 0 from being used as an indirect block
* for a large file or as a data block for a small file.
*/
static int
{
if (bn != 0)
return (0);
printf("non existent block\n");
error++;
return (1);
}
/*
* puta - put ascii characters into a buffer. The string
* terminates with a quote or newline. The leading quote,
* which is optional for directory names, was stripped off
* by the assignment case in the main loop.
*/
static void
puta()
{
char *cptr, c;
int i;
char *sbptr;
short terror = 0;
printf("not opened for write '-w'\n");
error++;
return;
}
return;
if (acting_on_directory)
else
else
while ((c = getachar()) != '"') {
printf("string too long\n");
else
terror++;
break;
}
tcount++;
if (c == '\n') {
ungetachar(c);
break;
}
if (c == '\\') {
switch (c = getachar()) {
case 't':
*cptr++ = '\t';
break;
case 'n':
*cptr++ = '\n';
break;
case '0':
*cptr++ = '\0';
break;
default:
*cptr++ = c;
break;
}
}
else
*cptr++ = c;
}
*cptr++ = '\0';
error++;
return;
}
error++;
return;
}
}
}
return;
switch (objsz) {
case LONG:
/*LINTED*/
temp = 1;
for (i = 0; i < (tcount*BITSPERCHAR); i++)
temp <<= 1;
}
break;
case SHORT:
/*LINTED*/
temp = 1;
for (i = 0; i < (tcount * BITSPERCHAR); i++)
temp <<= 1;
}
olditem &= 0177777L;
break;
case CHAR:
olditem &= 0377;
}
printf("\t=\t");
printf("\n");
} else {
} else {
}
}
if (terror)
error++;
}
/*
* fprnt - print data. 'count' elements are printed where '*' will
* print an entire blocks worth or up to the eof, whichever
* occurs first. An error will occur if crossing a block boundary
* is attempted since consecutive blocks don't usually have
* meaning. Current print types:
* / b - print as bytes (base sensitive)
* c - print as characters
* o O - print as octal shorts (longs)
* d D - print as decimal shorts (longs)
* x X - print as hexadecimal shorts (longs)
* ? c - print as cylinder groups
* d - print as directories
* i - print as inodes
* s - print as super blocks
* S - print as shadow data
*/
static void
{
int i;
int tbase;
char c, *cptr, *p;
unsigned short *sptr;
unsigned long *lptr;
should_print = 0;
if (count != 1) {
if (clear) {
count = 1;
star = 0;
clear = 0;
} else
clear = 1;
}
if (style == '/') {
eof_flag = 0;
else
eof_flag = 1;
switch (po) {
case 'c': /* print as characters */
case 'b': /* or bytes */
return;
if (tcount) {
for (i = 0; tcount--; i++) {
if (i % 16 == 0) {
if (i)
printf("\n");
}
if (po == 'c') {
if ((i + 1) % 16)
printf(" ");
} else {
if ((i + 1) % 16 == 0)
2, -2, 0);
else
4, -2, 0);
}
}
printf("\n");
}
if (eof) {
printf("end of file\n");
error++;
} else if (end) {
printf("end of block\n");
else
printf("end of fragment\n");
error++;
}
return;
case 'o': /* print as octal shorts */
goto otx;
case 'd': /* print as decimal shorts */
goto otx;
case 'x': /* print as hex shorts */
otx:
return;
/*LINTED*/
if (tcount) {
for (i = 0; tcount--; i++) {
sptr = (unsigned short *)print_check(
/*LINTED*/
(unsigned long *)sptr,
switch (po) {
case 'o':
break;
case 'd':
break;
case 'x':
}
}
printf("\n");
}
if (eof) {
printf("end of file\n");
error++;
} else if (end) {
printf("end of block\n");
else
printf("end of fragment\n");
error++;
}
return;
case 'O': /* print as octal longs */
goto OTX;
case 'D': /* print as decimal longs */
goto OTX;
case 'X': /* print as hex longs */
OTX:
return;
/*LINTED*/
if (tcount) {
for (i = 0; tcount--; i++) {
tbase, i);
switch (po) {
case 'O':
break;
case 'D':
break;
case 'X':
}
}
printf("\n");
}
if (eof) {
printf("end of file\n");
error++;
} else if (end) {
printf("end of block\n");
else
printf("end of fragment\n");
error++;
}
return;
default:
error++;
printf("no such print option\n");
return;
}
} else
switch (po) {
case 'c': /* print as cylinder group */
if (!star)
end++;
}
<< FRGSHIFT;
cur_cgrp++;
}
if (cur_cgrp)
cur_cgrp--;
return;
}
/*LINTED*/
if (!star)
end++;
}
}
printf("invalid cylinder group ");
printf("magic word\n");
if (cur_cgrp)
cur_cgrp--;
error++;
return;
}
if (tcount)
printf("\n");
}
cur_cgrp--;
if (end) {
printf("end of cylinder groups\n");
error++;
}
return;
case 'd': /* print as directories */
return;
printf("address must be at the ");
printf("beginning of a fragment\n");
error++;
return;
}
dirslot = 0;
cur_bytes = 0;
}
/*LINTED*/
printf("i#: ");
if (tinode == 0)
printf("free\t");
else
dirslot++;
}
dirslot--;
switch (type) {
case FRAGMENT:
printf("end of fragment\n");
break;
case BLOCK:
printf("end of block\n");
break;
default:
printf("end of directory\n");
}
error++;
} else
error = 0;
return;
case 'i': /* print as inodes */
/*LINTED*/
return;
break;
i--;
if (!star)
end++;
}
if (!override)
continue;
p = " ugtrwxrwxrwx";
case IFDIR:
c = 'd';
break;
case IFCHR:
c = 'c';
break;
case IFBLK:
c = 'b';
break;
case IFREG:
c = '-';
break;
case IFLNK:
c = 'l';
break;
case IFSOCK:
c = 's';
break;
case IFSHAD:
c = 'S';
break;
case IFATTRDIR:
c = 'A';
break;
default:
c = '?';
if (!override)
goto empty;
}
printf("i#: ");
printf(" md: ");
printf("%c", c);
printf("%c", *p);
else
printf("-");
}
printf(" uid: ");
printf(" gid: ");
printf("\n");
printf("ln: ");
printf(" bs: ");
printf("c_flags : ");
printf(" sz : ");
#ifdef _LARGEFILE64_SOURCE
#else /* !_LARGEFILE64_SOURCE */
#endif /* _LARGEFILE64_SOURCE */
printf(" si: ");
}
printf("\n");
if (ip->di_oeftflag) {
printf("ai: ");
printf("\n");
}
printf("\n");
case IFBLK:
case IFCHR:
printf("maj: ");
printf(" min: ");
printf("\n");
break;
default:
/*
* only display blocks below the
* current file size
*/
for (i = 0; i < NDADDR; ) {
break;
printf("db#%x: ", i);
if (++i % 4 == 0)
printf("\n");
else
printf(" ");
}
if (i % 4)
printf("\n");
/*
* curioff keeps track of the number
* of bytes covered by each indirect
* pointer in the inode, and is added
* to curoff each time to get the
* actual offset into the file.
*/
for (i = 0; i < NIADDR; i++) {
break;
printf("ib#%x: ", i);
printf(" ");
sizeof (daddr_t));
}
if (i)
printf("\n");
break;
}
if (count == 1) {
time_t t;
}
if (tcount)
printf("\n");
if (c == '?' && !override) {
printf("i#: ");
printf(" is unallocated\n");
if (count != 1)
printf("\n");
}
cur_inum++;
}
cur_inum--;
if (end) {
printf("end of block\n");
error++;
}
return;
case 's': /* print as super block */
if (cur_cgrp == -1) {
}
if (!star)
end++;
}
<< FRGSHIFT;
cur_cgrp++;
}
if (cur_cgrp)
cur_cgrp--;
return;
}
/*LINTED*/
break;
cur_cgrp = 0;
else
cur_cgrp = i + 1;
if (!star)
end++;
}
}
cur_cgrp = 0;
if (!override) {
printf("invalid super block ");
printf("magic word\n");
cur_cgrp--;
error++;
return;
}
}
(sb->fs_version !=
cur_cgrp = 0;
if (!override) {
printf("invalid super block ");
printf("version number\n");
cur_cgrp--;
error++;
return;
}
}
cur_cgrp = 0;
if (!override) {
printf("invalid super block ");
printf("version number\n");
cur_cgrp--;
error++;
return;
}
}
if (cur_cgrp == 0)
printf("\tsuper block:\n");
else {
printf("\tsuper block in cylinder ");
printf("group ");
printf(":\n");
}
if (tcount)
printf("\n");
}
cur_cgrp--;
if (end) {
printf("end of super blocks\n");
error++;
}
return;
case 'S': /* print as shadow data */
cur_shad = 0;
/* no more than two fragments */
}
objsz = SHADOW_DATA;
while (tcount-- &&
(type != SHADOW_DATA ||
/*LINTED*/
long tcur_bytes;
printf(" type: ");
printf(" size: ");
if (tbase > 256)
tbase = 256;
for (i = 0; i < tbase; i++) {
if (i % LONG == 0) {
if (i % 16 == 0) {
printf("\n");
} else
printf(" ");
p = (char *)&temp;
} else
printf(" ");
}
printf("\n");
cur_shad++;
syncshadowscan(0);
}
cur_shad--;
switch (type) {
case FRAGMENT:
printf("end of fragment\n");
break;
default:
printf("end of shadow data\n");
}
error++;
} else
error = 0;
return;
default:
error++;
printf("no such print option\n");
return;
}
}
/*
* valid_addr - call check_addr to validate the current address.
*/
static int
{
if (!trapped)
return (1);
if (cur_bytes < 0) {
cur_bytes = 0;
printf("beginning of file\n");
} else {
printf("beginning of block\n");
else
printf("beginning of fragment\n");
}
error++;
return (0);
}
count = 1;
if (eof) {
printf("end of file\n");
error++;
return (0);
}
if (end == 2) {
printf("beginning of block\n");
else
printf("beginning of fragment\n");
error++;
return (0);
}
}
if (end) {
printf("end of block\n");
else
printf("end of fragment\n");
error++;
return (0);
}
return (1);
}
/*
* check_addr - check if the address crosses the end of block or
* end of file. Return the proper count.
*/
static int
{
error = 0;
if (keep_on) {
if (cur_bytes < 0) {
(*end) = 2;
return (0); /* Value ignored */
}
return (0); /* Value ignored */
}
return (0); /* Value ignored */
} else {
(*eof)++;
return (0); /* Value ignored */
}
return (0); /* Value ignored */
}
return (0); /* Value ignored */
}
}
if (!star)
(*end) = 2;
}
if (eof_flag) {
tcount = 0;
(*eof)++;
(*eof)++;
}
} else {
tcount = 0;
(*end)++;
(*end)++;
}
}
}
return (tcount);
}
/*
* print_check - check if the index needs to be printed and delete
* rows of zeros from the output.
*/
unsigned long *
{
short first_time = 0;
unsigned long *tlptr;
if (i == 0)
first_time = 1;
if (i % temp == 0) {
else
k = *tcount - 1;
for (j = i; k--; j++)
if (*tsptr++ != 0)
break;
} else {
if (*tlptr++ != 0)
break;
}
if (j > (i + temp - 1)) {
j = (j - i) / temp;
while (j-- > 0) {
else
i += temp;
addr += BYTESPERLINE;
}
if (first_time)
printf("*");
else
printf("\n*");
}
if (i)
printf("\n");
} else {
if (i)
printf("\n");
}
}
/*LINTED*/
return ((unsigned long *)sptr);
else
return (lptr);
}
/*
* index - print a byte index for the printout in base b
* with leading zeros.
*/
static void
index(int b)
{
base = b;
printf(":\t");
}
/*
*/
static void
#ifdef _LARGEFILE64_SOURCE
#else /* !_LARGEFILE64_SOURCE */
#endif /* _LARGEFILE64_SOURCE */
{
int i, left = 0;
if (digits < 0) {
left = 1;
digits *= -1;
}
if (digits)
else
digits = 1;
if (lead) {
if (left)
#ifdef _LARGEFILE64_SOURCE
"ll"
#endif /* _LARGEFILE64_SOURCE */
else
#ifdef _LARGEFILE64_SOURCE
"ll"
#endif /* _LARGEFILE64_SOURCE */
} else {
if (left)
#ifdef _LARGEFILE64_SOURCE
"ll"
#endif /* _LARGEFILE64_SOURCE */
else
#ifdef _LARGEFILE64_SOURCE
"ll"
#endif /* _LARGEFILE64_SOURCE */
}
printf(" ");
}
/*
* Print out the contents of a superblock.
*/
static void
{
int c, i, j, k, size;
time_t t;
#ifdef FS_42POSTBLFMT
ctime(&t));
#else
printf("magic\t%x\ttime\t%s",
#endif
printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
printf("ncg\t%ld\tncyl\t%ld\tsize\t%ld\tblocks\t%ld\n",
printf("bsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
printf("fsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
printf("frag\t%ld\tshift\t%ld\tfsbtodb\t%ld\n",
printf("cpg\t%ld\tbpg\t%ld\tfpg\t%ld\tipg\t%ld\n",
printf("minfree\t%ld%%\toptim\t%s\tmaxcontig %ld\tmaxbpg\t%ld\n",
#ifdef FS_42POSTBLFMT
#ifdef sun
printf("rotdelay %ldms\tfs_id[0] 0x%lx\tfs_id[1] 0x%lx\trps\t%ld\n",
#else
printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
#endif /* sun */
printf("ntrak\t%ld\tnsect\t%ld\tnpsect\t%ld\tspc\t%ld\n",
#else
printf("rotdelay %ldms\trps\t%ld\n",
printf("ntrak\t%ld\tnsect\t%ld\tspc\t%ld\n",
#endif
printf("nindir\t%ld\tinopb\t%ld\tnspf\t%ld\n",
printf("sblkno\t%ld\tcblkno\t%ld\tiblkno\t%ld\tdblkno\t%ld\n",
printf("sbsize\t%ld\tcgsize\t%ld\tcgoffset %ld\tcgmask\t0x%08lx\n",
printf("csaddr\t%ld\tcssize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
printf("cgrotor\t%ld\tfmod\t%d\tronly\t%d\n",
#ifdef FS_42POSTBLFMT
printf("blocks available in each of %ld rotational positions",
else
printf("insufficient space to maintain rotational tables\n");
#endif
printf("\ncylinder number %d:", c);
#ifdef FS_42POSTBLFMT
/*LINTED*/
continue;
printf("\n position %d:\t", i);
/*LINTED*/
printf("%5d", j);
if (k % 12 == 0)
printf("\n\t\t");
break;
}
}
#else
for (i = 0; i < NRPOS; i++) {
continue;
printf("\n position %d:\t", i);
printf("%5d", j);
if (k % 12 == 0)
printf("\n\t\t");
break;
}
}
#endif
}
printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):");
return;
}
}
if (i % 4 == 0)
printf("\n ");
}
printf("\n");
printf("cylinders in last group %d\n",
printf("blocks in last group %ld\n",
}
}
/*
* Print out the contents of a cylinder group.
*/
static void
{
int i, j;
time_t t;
#ifdef FS_42POSTBLFMT
printf("magic\t%lx\ttell\t%llx\ttime\t%s",
ctime(&t));
#else
printf("magic\t%x\ttell\t%llx\ttime\t%s",
ctime(&t));
#endif
printf("cgx\t%ld\tncyl\t%d\tniblk\t%d\tndblk\t%ld\n",
printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
printf("rotor\t%ld\tirotor\t%ld\tfrotor\t%ld\nfrsum",
}
printf("\nsum of frsum: %d\niused:\t", j);
printf("free:\t");
printf("b:\n");
/*LINTED*/
continue;
/*LINTED*/
#ifdef FS_42POSTBLFMT
/*LINTED*/
continue;
/*LINTED*/
}
#else
for (j = 0; j < NRPOS; j++) {
continue;
}
#endif
printf("\n");
}
}
/*
* Print out the contents of a bit array.
*/
static void
{
int i;
int count = 0, j;
for (i = 0; i < max; i++)
if (count)
count++;
printf("%d", i);
j = i;
i++;
if (i != j)
printf("-%d", i);
}
printf("\n");
}
/*
* a file system.
*/
static int
{
if (override)
return (0);
return (0);
error++;
return (1);
}
/*
* bmap - maps the logical block number of a file into
* the corresponding physical block on the file
* system.
*/
static long
{
int j;
int sh;
long nb;
char *cptr;
return (0);
/*LINTED*/
}
sh = 1;
for (j = NIADDR; j > 0; j--) {
break;
}
if (j == 0) {
printf("file too big\n");
error++;
return (0L);
}
if (nb == 0)
return (0L);
for (; j <= NIADDR; j++) {
return (0L);
}
return (nb);
}
#if defined(OLD_FSDB_COMPATIBILITY)
/*
* The following are "tacked on" to support the old fsdb functionality
* of clearing an inode. (All together now...) "It's better to use clri".
*/
static union {
} sb_un;
static void
{
int f; /* File descriptor for "special" */
int j;
int status = 0;
long gen;
time_t t;
if (f < 0) {
perror("open");
}
}
printf("bad super block magic number\n");
}
if (inum == 0) {
}
status = 1;
}
if (status)
/*
* Update the time in superblock, so fsck will check this filesystem.
*/
(void) time(&t);
exit(35);
}
}
static int
isnumber(char *s)
{
register int c;
if (s == NULL)
return (0);
while ((c = *s++) != NULL)
if (c < '0' || c > '9')
return (0);
return (1);
}
#endif /* OLD_FSDB_COMPATIBILITY */
/*
* no single value is safe to use to indicate
* lufs_tid being invalid so we need a
* seperate variable.
*/
/*
* log_get_header_info - get the basic info of the logging filesystem
*/
int
log_get_header_info(void)
{
char *b;
int nb;
/*
* Mark the global tid as invalid everytime we're called to
* prevent any false positive responses.
*/
/*
* See if we've already set up the header areas. The only problem
* with this approach is we don't reread the on disk data though
* it shouldn't matter since we don't operate on a live disk.
*/
return (1);
/*
* Either logging is disabled or we've not running 2.7.
*/
printf("Logging doesn't appear to be enabled on this disk\n");
return (0);
}
/*
* To find the log we need to first pick up the block allocation
* data. The block number for that data is fs_logbno in the
* super block.
*/
== 0) {
printf("getblk() indicates an error with logging block\n");
return (0);
}
/*
* Next we need to figure out how big the extent data structure
* really is. It can't be more then fs_bsize and you could just
* allocate that but, why get sloppy.
* 1 is subtracted from nextents because extent_block_t contains
* a single extent_t itself.
*/
log_eb = (extent_block_t *)b;
printf("Extents block has invalid type (0x%x)\n",
return (0);
}
nb = sizeof (extent_block_t) +
printf("Failed to allocate memory for extent block log\n");
return (0);
}
/*
* Currently, as of 11-Dec-1997 the field nextbno isn't
* implemented. If someone starts using this sucker we'd
* better warn somebody.
*/
printf("WARNING: extent block field nextbno is non-zero!\n");
/*
* Now read in the on disk log structure. This is always in the
* first block of the first extent.
*/
printf("Failed to allocate memory for ondisk structure\n");
return (0);
}
/*
* Consistency checks.
*/
printf("Version mismatch in on-disk version of log data\n");
return (0);
printf("WARNING: Log was marked as bad\n");
}
return (1);
}
static void
log_display_header(void)
{
int x;
if (!log_get_header_info())
/*
* No need to display anything here. The previous routine
* has already done so.
*/
return;
printf("Log block number: 0x%x\n------------------\n",
else
printf("Log frag number: 0x%x\n------------------\n",
printf("Extent Info\n\t# Extents : %d\n\t# Bytes : 0x%x\n",
printf("\tNext Block : 0x%x\n\tExtent List\n\t--------\n",
printf("\t [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n",
printf("\nOn Disk Info\n\tbol_lof : 0x%08x\n\teol_lof : 0x%08x\n",
printf("\tlog_size : 0x%08x\n",
printf("\thead_lof : 0x%08x\tident : 0x%x\n",
printf("\ttail_lof : 0x%08x\tident : 0x%x\n\thead_tid : 0x%08x\n",
printf("bad checksum: found 0x%08x, should be 0x%08x\n",
printf("\t --- Log is empty ---\n");
}
/*
* log_lodb -- logical log offset to disk block number
*/
int
{
int x;
if (!log_get_header_info())
/*
* No need to display anything here. The previous routine
* has already done so.
*/
return (0);
return (1);
}
return (0);
}
/*
* String names for the enumerated types. These are only used
* for display purposes.
*/
char *dt_str[] = {
"DT_NONE", "DT_SB", "DT_CG", "DT_SI", "DT_AB",
"DT_ABZERO", "DT_DIR", "DT_INODE", "DT_FBI",
"DT_QR", "DT_COMMIT", "DT_CANCEL", "DT_BOT",
"DT_EOT", "DT_UD", "DT_SUD", "DT_SHAD", "DT_MAX"
};
/*
* log_read_log -- transfer information from the log and adjust offset
*/
int
{
int xfer;
while (nb) {
printf("Invalid log offset\n");
return (0);
}
/*
* fsdb getblk() expects offsets not block number.
*/
return (0);
}
/*
* If the log offset is now at a sector trailer
* run the checks if requested.
*/
if (NB_LEFT_IN_SECTOR(*addr) == 0) {
st = (sect_trailer_t *)
"Expected sector trailer id 0x%08x, but saw 0x%08x\n",
return (0);
} else {
/*
* We update the on disk structure
* transaction ID each time we see
* one. By comparing this value
* to the last valid DT_COMMIT record
* we can determine if our log is
* completely valid.
*/
}
}
*addr += sizeof (sect_trailer_t);
}
}
return (1);
}
{
/*
* Comments are straight from ufs_log.c
*
* log is the offset following the commit header. However,
* if the commit header fell on the end-of-sector, then lof
* has already been advanced to the beginning of the next
* sector. So do nothgin. Otherwise, return the remaining
* bytes in the sector.
*/
if ((a & (DEV_BSIZE - 1)) == 0)
return (0);
else
return (NB_LEFT_IN_SECTOR(a));
}
/*
* log_show -- pretty print the deltas. The number of which is determined
* by the log_enum arg. If LOG_ALLDELTAS the routine, as the
* name implies dumps everything. If LOG_NDELTAS, the routine
* will print out "count" deltas starting at "addr". If
* LOG_CHECKSCAN then run through the log checking the st_ident
* for valid data.
*/
static void
{
struct delta d;
int x = 0;
if (!log_get_header_info())
/*
* No need to display any error messages here. The previous
* routine has already done so.
*/
return;
if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) {
printf("Empty log.\n");
return;
} else
printf("WARNING: empty log. addr may generate bogus"
" information");
}
/*
* Only reset the "addr" if we've been requested to show all
* deltas in the log.
*/
if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN))
if (l != LOG_CHECKSCAN) {
printf(" Log Offset Delta Count Type\n");
printf("-----------------------------------------"
"-----------------\n");
}
(l == LOG_CHECKSCAN) || count--)) {
((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) ?
/*
* Two failures are possible. One from getblk()
* which prints out a message or when we've hit
* an invalid block which may or may not indicate
* an error
*/
goto end_scan;
printf("Bad delta entry. size out of bounds\n");
return;
}
if (l != LOG_CHECKSCAN)
switch (d.d_typ) {
case DT_CANCEL:
case DT_ABZERO:
/*
* These two deltas don't have log space
* associated with the entry even though
* d_nb is non-zero.
*/
break;
case DT_COMMIT:
/*
* Commit records have zero size yet, the
* rest of the current disk block is avoided.
*/
break;
default:
((l == LOG_ALLDELTAS) ||
goto end_scan;
break;
}
}
if (lufs_tid_valid == True) {
printf("scan -- okay\n");
else
printf("scan -- some transactions have been lost\n");
} else {
printf("scan -- failed to find a single valid transaction\n");
printf(" (possibly due to an empty log)\n");
}
}