char version
[] = "@(#)main.c 2.29 (Berkeley) %G%";
/* RECONSTRUCT ONLY BAD CG IN PASS 6 */
typedef int (*SIG_TYP
)();
#define MAXNINDIR (MAXBSIZE / sizeof (daddr_t))
#define MAXINOPB (MAXBSIZE / sizeof (struct dinode))
#define SPERB (MAXBSIZE / sizeof(short))
#define MINDIRSIZE (sizeof (struct dirtemplate))
#define MAXDUP 10 /* limit on dup blks (per inode) */
#define MAXBAD 10 /* limit on bad blks (per inode) */
#define USTATE 0 /* inode not allocated */
#define FSTATE 01 /* inode is file */
#define DSTATE 02 /* inode is directory */
#define CLEAR 03 /* inode is to be cleared */
typedef struct dinode DINODE
;
typedef struct direct DIRECT
;
#define ALLOC ((dp->di_mode & IFMT) != 0)
#define DIRCT ((dp->di_mode & IFMT) == IFDIR)
#define REG ((dp->di_mode & IFMT) == IFREG)
#define BLK ((dp->di_mode & IFMT) == IFBLK)
#define CHR ((dp->di_mode & IFMT) == IFCHR)
#define LNK ((dp->di_mode & IFMT) == IFLNK)
#define SOCK ((dp->di_mode & IFMT) == IFSOCK)
#define BADBLK ((dp->di_mode & IFMT) == IFMT)
#define SPECIAL (BLK || CHR)
struct bufarea
*b_next
; /* must be first */
char b_buf
[MAXBSIZE
]; /* buffer space */
short b_lnks
[SPERB
]; /* link counts */
daddr_t b_indir
[MAXNINDIR
]; /* indirect block */
struct fs b_fs
; /* super block */
struct cg b_cg
; /* cylinder group */
struct dinode b_dinode
[MAXINOPB
]; /* inode block */
typedef struct bufarea BUFAREA
;
BUFAREA inoblk
; /* inode blocks */
BUFAREA fileblk
; /* other blks in filesys */
BUFAREA sblk
; /* file system superblock */
BUFAREA cgblk
; /* cylinder group blocks */
#define initbarea(x) (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
#define dirty(x) (x)->b_dirty = 1
#define inodirty() inoblk.b_dirty = 1
#define sbdirty() sblk.b_dirty = 1
#define cgdirty() cgblk.b_dirty = 1
#define dirblk fileblk.b_un
#define sblock sblk.b_un.b_fs
#define cgrp cgblk.b_un.b_cg
} dfile
; /* file descriptors for filesys */
char id_type
; /* type of descriptor, DATA or ADDR */
int (*id_func
)(); /* function to be applied to blocks of inode */
ino_t id_number
; /* inode number described */
ino_t id_parent
; /* for DATA nodes, their parent */
daddr_t id_blkno
; /* current block number being examined */
int id_numfrags
; /* number of frags contained in block */
long id_filesize
; /* for DATA nodes, the size of the directory */
int id_loc
; /* for DATA nodes, current location in dir */
int id_entryno
; /* for DATA nodes, current entry number */
DIRECT
*id_dirp
; /* for data nodes, ptr to current entry */
enum {DONTKNOW
, NOFIX
, FIX
} id_fix
; /* policy on fixing errors */
#define DUPTBLSIZE 100 /* num of dup blocks to remember */
daddr_t duplist
[DUPTBLSIZE
]; /* dup block table */
daddr_t
*enddup
; /* next entry in dup table */
daddr_t
*muldup
; /* multiple dups part of table */
#define MAXLNCNT 500 /* num zero link cnts to remember */
ino_t badlncnt
[MAXLNCNT
]; /* table of inos with zero link cnts */
ino_t
*badlnp
; /* next entry in table */
char nflag
; /* assume a no response */
char yflag
; /* assume a yes response */
int bflag
; /* location of alternate super block */
int debug
; /* output debugging info */
char preen
; /* just fix normal inconsistencies */
char rplyflag
; /* any questions asked? */
char hotroot
; /* checking root device */
char fixcg
; /* corrupted free list bit maps */
char *blockmap
; /* ptr to primary blk allocation map */
char *freemap
; /* ptr to secondary blk allocation map */
char *statemap
; /* ptr to inode state table */
short *lncntp
; /* ptr to link count table */
char *srchname
; /* name being searched for in dir */
char pathname
[BUFSIZ
]; /* current pathname */
char *pathp
; /* pointer to pathname position */
char *endpathname
= &pathname
[BUFSIZ
- 2];
char *lfname
= "lost+found";
ino_t imax
; /* number of inodes */
ino_t lastino
; /* hiwater mark of inodes */
ino_t lfdir
; /* lost & found directory */
off_t maxblk
; /* largest logical blk in file */
off_t bmapsz
; /* num chars in blockmap */
daddr_t n_ffree
; /* number of small free blocks */
daddr_t n_bfree
; /* number of large free blocks */
daddr_t n_blks
; /* number of blocks used */
daddr_t n_files
; /* number of files seen */
daddr_t fmax
; /* number of blocks in the volume */
#define zapino(x) (*(x) = zino)
#define setbmap(x) setbit(blockmap, x)
#define getbmap(x) isset(blockmap, x)
#define clrbmap(x) clrbit(blockmap, x)
#define setfmap(x) setbit(freemap, x)
#define getfmap(x) isset(freemap, x)
#define clrfmap(x) clrbit(freemap, x)
int findino(), mkentry(), chgdd();
int pass1check(), pass1bcheck(), pass2check(), pass4check();
char *rawname(), *unrawname();
char *calloc(), *strcpy(), *strcat(), *rindex();
extern int inside
[], around
[];
extern unsigned char *fragtbl
[];
int pid
, passno
, anygtr
, sumstatus
;
while (--argc
> 0 && **++argv
== '-') {
if (argv
[0][1] != '\0') {
printf("Alternate super block location: %d\n", bflag
);
case 'n': /* default no answer flag */
case 'y': /* default yes answer flag */
errexit("%c option?\n", **argv
);
if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
(void)signal(SIGINT
, catch);
errexit("Can't open checklist file: %s\n", FSTAB
);
while ((fsp
= getfsent()) != 0) {
if (strcmp(fsp
->fs_type
, FSTAB_RW
) &&
strcmp(fsp
->fs_type
, FSTAB_RO
) &&
strcmp(fsp
->fs_type
, FSTAB_RQ
))
passno
== 1 && fsp
->fs_passno
== passno
) {
if (blockcheck(fsp
->fs_spec
) == 0 && preen
)
} else if (fsp
->fs_passno
> passno
)
else if (fsp
->fs_passno
== passno
) {
if (blockcheck(fsp
->fs_spec
)==0)
while (wait(&status
) != -1)
sumstatus
|= status
.w_retcode
;
struct stat stslash
, stblock
, stchar
;
if (stat("/", &stslash
) < 0){
error("Can't stat root\n");
if (stat(name
, &stblock
) < 0){
error("Can't stat %s\n", name
);
if (stblock
.st_mode
& S_IFBLK
) {
if (stat(raw
, &stchar
) < 0){
error("Can't stat %s\n", raw
);
if (stchar
.st_mode
& S_IFCHR
) {
if (stslash
.st_dev
== stblock
.st_rdev
) {
error("%s is not a character device\n", raw
);
} else if (stblock
.st_mode
& S_IFCHR
) {
error("Can't make sense out of name %s\n", name
);
error("Can't make sense out of name %s\n", name
);
if (setup(filesys
) == 0) {
pfatal("CAN'T CHECK FILE SYSTEM.");
/* 1: scan inodes tallying blocks used */
printf("** Last Mounted on %s\n", sblock
.fs_fsmnt
);
printf("** Root file system\n");
printf("** Phase 1 - Check Blocks and Sizes\n");
/* 1b: locate first references to duplicates, if any */
if (enddup
!= &duplist
[0]) {
pfatal("INTERNAL ERROR: dups with -p");
printf("** Phase 1b - Rescan For More DUPS\n");
/* 2: traverse directories from root to mark all connected directories */
printf("** Phase 2 - Check Pathnames\n");
/* 3: scan inodes looking for disconnected directories */
printf("** Phase 3 - Check Connectivity\n");
/* 4: scan inodes looking for disconnected files; check reference counts */
printf("** Phase 4 - Check Reference Counts\n");
/* 5: check resource counts in cylinder groups */
printf("** Phase 5 - Check Cyl groups\n");
printf("** Phase 6 - Salvage Cylinder Groups\n");
n_ffree
= sblock
.fs_cstotal
.cs_nffree
;
n_bfree
= sblock
.fs_cstotal
.cs_nbfree
;
pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
n_files
, n_blks
- howmany(sblock
.fs_cssize
, sblock
.fs_fsize
),
n_ffree
+ sblock
.fs_frag
* n_bfree
, n_ffree
, n_bfree
);
(void)time(&sblock
.fs_time
);
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
printf("\n***** REBOOT UNIX *****\n");
daddr_t super
= bflag
? bflag
: SBLOCK
;
# define altsblock asblk.b_un.b_fs
if (stat("/", &statb
) < 0)
errexit("Can't stat root\n");
if (stat(dev
, &statb
) < 0) {
error("Can't stat %s\n", dev
);
if ((statb
.st_mode
& S_IFMT
) == S_IFBLK
)
else if ((statb
.st_mode
& S_IFMT
) == S_IFCHR
)
if (reply("file is not a block or character device; OK") == 0)
if (rootdev
== statb
.st_rdev
)
if ((dfile
.rfdes
= open(dev
, 0)) < 0) {
error("Can't open %s\n", dev
);
if (nflag
|| (dfile
.wfdes
= open(dev
, 1)) < 0) {
pfatal("NO WRITE ACCESS");
fixcg
= 0; inosumbad
= 0; offsumbad
= 0; frsumbad
= 0; sbsumbad
= 0;
n_files
= n_blks
= n_ffree
= n_bfree
= 0;
muldup
= enddup
= &duplist
[0];
* Read in the super block and its summary info.
if (bread(&dfile
, (char *)&sblock
, super
, (long)SBSIZE
) == 0)
* run a few consistency checks of the super block
if (sblock
.fs_magic
!= FS_MAGIC
)
{ badsb("MAGIC NUMBER WRONG"); return (0); }
{ badsb("NCG OUT OF RANGE"); return (0); }
if (sblock
.fs_cpg
< 1 || sblock
.fs_cpg
> MAXCPG
)
{ badsb("CPG OUT OF RANGE"); return (0); }
if (sblock
.fs_ncg
* sblock
.fs_cpg
< sblock
.fs_ncyl
||
(sblock
.fs_ncg
- 1) * sblock
.fs_cpg
>= sblock
.fs_ncyl
)
{ badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
if (sblock
.fs_sbsize
> SBSIZE
)
{ badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
* Set all possible fields that could differ, then do check
* of whole super block against an alternate super block.
* When an alternate super-block is specified this check is skipped.
if (getblk(&asblk
, cgsblock(&sblock
, sblock
.fs_ncg
- 1),
altsblock
.fs_link
= sblock
.fs_link
;
altsblock
.fs_rlink
= sblock
.fs_rlink
;
altsblock
.fs_time
= sblock
.fs_time
;
altsblock
.fs_cstotal
= sblock
.fs_cstotal
;
altsblock
.fs_cgrotor
= sblock
.fs_cgrotor
;
altsblock
.fs_fmod
= sblock
.fs_fmod
;
altsblock
.fs_clean
= sblock
.fs_clean
;
altsblock
.fs_ronly
= sblock
.fs_ronly
;
altsblock
.fs_flags
= sblock
.fs_flags
;
altsblock
.fs_maxcontig
= sblock
.fs_maxcontig
;
altsblock
.fs_minfree
= sblock
.fs_minfree
;
altsblock
.fs_rotdelay
= sblock
.fs_rotdelay
;
altsblock
.fs_maxbpg
= sblock
.fs_maxbpg
;
bcopy((char *)sblock
.fs_csp
, (char *)altsblock
.fs_csp
,
bcopy((char *)sblock
.fs_fsmnt
, (char *)altsblock
.fs_fsmnt
,
if (bcmp((char *)&sblock
, (char *)&altsblock
, (int)sblock
.fs_sbsize
))
{ badsb("TRASHED VALUES IN SUPER BLOCK"); return (0); }
imax
= sblock
.fs_ncg
* sblock
.fs_ipg
;
n_bad
= cgsblock(&sblock
, 0); /* boot block plus dedicated sblock */
* read in the summary info.
for (i
= 0, j
= 0; i
< sblock
.fs_cssize
; i
+= sblock
.fs_bsize
, j
++) {
size
= sblock
.fs_cssize
- i
< sblock
.fs_bsize
?
sblock
.fs_cssize
- i
: sblock
.fs_bsize
;
sblock
.fs_csp
[j
] = (struct csum
*)calloc(1, (unsigned)size
);
if (bread(&dfile
, (char *)sblock
.fs_csp
[j
],
fsbtodb(&sblock
, sblock
.fs_csaddr
+ j
* sblock
.fs_frag
),
* allocate and initialize the necessary maps
bmapsz
= roundup(howmany(fmax
, NBBY
), sizeof(short));
blockmap
= calloc((unsigned)bmapsz
, sizeof (char));
printf("cannot alloc %d bytes for blockmap\n", bmapsz
);
freemap
= calloc((unsigned)bmapsz
, sizeof (char));
printf("cannot alloc %d bytes for freemap\n", bmapsz
);
statemap
= calloc((unsigned)(imax
+ 1), sizeof(char));
printf("cannot alloc %d bytes for statemap\n", imax
+ 1);
lncntp
= (short *)calloc((unsigned)(imax
+ 1), sizeof(short));
printf("cannot alloc %d bytes for lncntp\n",
(imax
+ 1) * sizeof(short));
for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
cgd
= cgdmin(&sblock
, c
);
cgd
+= howmany(sblock
.fs_cssize
, sblock
.fs_fsize
);
d
= cgsblock(&sblock
, c
);
bzero((char *)&idesc
, sizeof(struct inodesc
));
idesc
.id_func
= pass1check
;
n_blks
+= howmany(sblock
.fs_cssize
, sblock
.fs_fsize
);
for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
if (getblk(&cgblk
, cgtod(&sblock
, c
), sblock
.fs_cgsize
) == 0)
if (cgrp
.cg_magic
!= CG_MAGIC
) {
pfatal("CG %d: BAD MAGIC NUMBER\n", c
);
bzero((char *)&cgrp
, (int)sblock
.fs_cgsize
);
for (i
= 0; i
< sblock
.fs_ipg
; i
++, inumber
++) {
if (!isset(cgrp
.cg_iused
, i
)) {
printf("%d bad, not used\n",
reply("HOLD BAD BLOCK") == 1) {
dp
->di_size
= sblock
.fs_fsize
;
dp
->di_mode
= IFREG
|0600;
} else if (ftypeok(dp
) == 0)
ndb
= howmany(dp
->di_size
, sblock
.fs_bsize
);
for (j
= ndb
; j
< NDADDR
; j
++)
printf("bad direct addr: %d\n",
for (j
= 0, ndb
-= NDADDR
; ndb
> 0; j
++)
printf("bad indirect addr: %d\n",
lncntp
[inumber
] = dp
->di_nlink
;
if (badlnp
< &badlncnt
[MAXLNCNT
])
pfatal("LINK COUNT TABLE OVERFLOW");
if (reply("CONTINUE") == 0)
statemap
[inumber
] = DIRCT
? DSTATE
: FSTATE
;
badblk
= dupblk
= 0; maxblk
= 0;
idesc
.id_number
= inumber
;
(void)ckinode(dp
, &idesc
);
idesc
.id_filesize
*= btodb(sblock
.fs_fsize
);
if (dp
->di_blocks
!= idesc
.id_filesize
) {
pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
printf(" (CORRECTED)\n");
else if (reply("CORRECT") == 0)
dp
->di_blocks
= idesc
.id_filesize
;
pfatal("UNKNOWN FILE TYPE I=%u", inumber
);
if (reply("CLEAR") == 1) {
if (isset(cgrp
.cg_iused
, i
)) {
printf("%d bad, marked used\n",
for (j
= 0; j
< NDADDR
; j
++)
for (j
= 0; j
< NIADDR
; j
++)
if (partial
|| dp
->di_mode
!= 0 ||
pfatal("PARTIALLY ALLOCATED INODE I=%u",
if (reply("CLEAR") == 1) {
if (n
!= cgrp
.cg_cs
.cs_nifree
) {
printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
c
, cgrp
.cg_cs
.cs_nifree
, n
);
if (cgrp
.cg_cs
.cs_nbfree
!= sblock
.fs_cs(&sblock
, c
).cs_nbfree
|| cgrp
.cg_cs
.cs_nffree
!= sblock
.fs_cs(&sblock
, c
).cs_nffree
|| cgrp
.cg_cs
.cs_nifree
!= sblock
.fs_cs(&sblock
, c
).cs_nifree
|| cgrp
.cg_cs
.cs_ndir
!= sblock
.fs_cs(&sblock
, c
).cs_ndir
)
register struct inodesc
*idesc
;
daddr_t blkno
= idesc
->id_blkno
;
anyout
= outrange(blkno
, idesc
->id_numfrags
);
for (nfrags
= idesc
->id_numfrags
; nfrags
> 0; blkno
++, nfrags
--) {
if (anyout
&& outrange(blkno
, 1)) {
blkerr(idesc
->id_number
, "BAD", blkno
);
if (++badblk
>= MAXBAD
) {
pwarn("EXCESSIVE BAD BLKS I=%u",
else if (reply("CONTINUE") == 0)
} else if (getbmap(blkno
)) {
blkerr(idesc
->id_number
, "DUP", blkno
);
if (++dupblk
>= MAXDUP
) {
pwarn("EXCESSIVE DUP BLKS I=%u",
else if (reply("CONTINUE") == 0)
if (enddup
>= &duplist
[DUPTBLSIZE
]) {
pfatal("DUP TABLE OVERFLOW.");
if (reply("CONTINUE") == 0)
for (dlp
= duplist
; dlp
< muldup
; dlp
++)
bzero((char *)&idesc
, sizeof(struct inodesc
));
idesc
.id_func
= pass1bcheck
;
for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
for (i
= 0; i
< sblock
.fs_ipg
; i
++, inumber
++) {
idesc
.id_number
= inumber
;
if (statemap
[inumber
] != USTATE
&&
(ckinode(dp
, &idesc
) & STOP
))
register struct inodesc
*idesc
;
int nfrags
, res
= KEEPON
;
daddr_t blkno
= idesc
->id_blkno
;
for (nfrags
= idesc
->id_numfrags
; nfrags
> 0; blkno
++, nfrags
--) {
for (dlp
= duplist
; dlp
< muldup
; dlp
++)
blkerr(idesc
->id_number
, "DUP", blkno
);
bzero((char *)&rootdesc
, sizeof(struct inodesc
));
rootdesc
.id_func
= pass2check
;
rootdesc
.id_number
= ROOTINO
;
switch (statemap
[ROOTINO
]) {
errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
pfatal("ROOT INODE NOT DIRECTORY");
if (reply("FIX") == 0 || (dp
= ginode(ROOTINO
)) == NULL
)
statemap
[ROOTINO
] = DSTATE
;
descend(&rootdesc
, ROOTINO
);
pfatal("DUPS/BAD IN ROOT INODE");
if (reply("CONTINUE") == 0)
statemap
[ROOTINO
] = DSTATE
;
descend(&rootdesc
, ROOTINO
);
register DIRECT
*dirp
= idesc
->id_dirp
;
int n
, entrysize
, ret
= 0;
if (idesc
->id_entryno
!= 0)
if (dirp
->d_ino
!= 0 && dirp
->d_namlen
== 1 && dirp
->d_name
[0] == '.') {
if (dirp
->d_ino
!= idesc
->id_number
) {
direrr(idesc
->id_number
, "BAD INODE NUMBER FOR '.'");
dirp
->d_ino
= idesc
->id_number
;
direrr(idesc
->id_number
, "MISSING '.'");
proto
.d_ino
= idesc
->id_number
;
(void)strcpy(proto
.d_name
, ".");
entrysize
= DIRSIZ(&proto
);
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
} else if (dirp
->d_reclen
< entrysize
) {
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
} else if (dirp
->d_reclen
< 2 * entrysize
) {
proto
.d_reclen
= dirp
->d_reclen
;
bcopy((char *)&proto
, (char *)dirp
, entrysize
);
n
= dirp
->d_reclen
- entrysize
;
proto
.d_reclen
= entrysize
;
bcopy((char *)&proto
, (char *)dirp
, entrysize
);
dirp
= (DIRECT
*)((char *)(dirp
) + entrysize
);
if (idesc
->id_entryno
> 1)
proto
.d_ino
= idesc
->id_parent
;
(void)strcpy(proto
.d_name
, "..");
entrysize
= DIRSIZ(&proto
);
if (idesc
->id_entryno
== 0) {
if (dirp
->d_reclen
< n
+ entrysize
)
proto
.d_reclen
= dirp
->d_reclen
- n
;
dirp
= (DIRECT
*)((char *)(dirp
) + n
);
if (dirp
->d_ino
!= 0 && dirp
->d_namlen
== 2 &&
strcmp(dirp
->d_name
, "..") == 0) {
if (dirp
->d_ino
!= idesc
->id_parent
) {
direrr(idesc
->id_number
, "BAD INODE NUMBER FOR '..'");
dirp
->d_ino
= idesc
->id_parent
;
direrr(idesc
->id_number
, "MISSING '..'");
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
} else if (dirp
->d_reclen
< entrysize
) {
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
proto
.d_reclen
= dirp
->d_reclen
;
bcopy((char *)&proto
, (char *)dirp
, entrysize
);
if (idesc
->id_entryno
>= 2 &&
dirp
->d_name
[0] == '.') {
if (dirp
->d_namlen
== 1) {
direrr(idesc
->id_number
, "EXTRA '.' ENTRY");
if (dirp
->d_name
[1] == '.') {
direrr(idesc
->id_number
, "EXTRA '..' ENTRY");
if (pathp
+ dirp
->d_namlen
>= endpathname
) {
errexit("NAME TOO LONG %s%s\n", pathname
, dirp
->d_name
);
bcopy(dirp
->d_name
, pathp
, dirp
->d_namlen
+ 1);
if (dirp
->d_ino
> imax
|| dirp
->d_ino
<= 0) {
direrr(dirp
->d_ino
, "I OUT OF RANGE");
switch (statemap
[dirp
->d_ino
]) {
direrr(dirp
->d_ino
, "UNALLOCATED");
direrr(dirp
->d_ino
, "DUP/BAD");
if ((n
= reply("REMOVE")) == 1)
if ((dp
= ginode(dirp
->d_ino
)) == NULL
)
statemap
[dirp
->d_ino
] = DIRCT
? DSTATE
: FSTATE
;
descend(idesc
, dirp
->d_ino
);
if (statemap
[dirp
->d_ino
] != CLEAR
) {
return (ret
|KEEPON
|ALTERED
);
bzero((char *)&idesc
, sizeof(struct inodesc
));
for (inumber
= ROOTINO
; inumber
<= lastino
; inumber
++) {
if (statemap
[inumber
] == DSTATE
) {
idesc
.id_parent
= inumber
;
orphan
= idesc
.id_parent
;
if ((dp
= ginode(orphan
)) == NULL
)
idesc
.id_filesize
= dp
->di_size
;
idesc
.id_number
= orphan
;
(void)ckinode(dp
, &idesc
);
if (idesc
.id_parent
== 0)
} while (statemap
[idesc
.id_parent
] == DSTATE
);
if (linkup(orphan
, idesc
.id_parent
) == 1) {
idesc
.id_func
= pass2check
;
register ino_t inumber
, *blp
;
bzero((char *)&idesc
, sizeof(struct inodesc
));
idesc
.id_func
= pass4check
;
for (inumber
= ROOTINO
; inumber
<= lastino
; inumber
++) {
idesc
.id_number
= inumber
;
switch (statemap
[inumber
]) {
adjust(&idesc
, (short)n
);
for (blp
= badlncnt
;blp
< badlnp
; blp
++)
clri(&idesc
, "UNREF", 1);
clri(&idesc
, "UNREF", 1);
clri(&idesc
, "BAD/DUP", 1);
if (imax
- ROOTINO
- n_files
!= sblock
.fs_cstotal
.cs_nifree
) {
pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
if (preen
|| reply("FIX") == 1) {
sblock
.fs_cstotal
.cs_nifree
= imax
- ROOTINO
- n_files
;
register struct inodesc
*idesc
;
int nfrags
, res
= KEEPON
;
daddr_t blkno
= idesc
->id_blkno
;
for (nfrags
= idesc
->id_numfrags
; nfrags
> 0; blkno
++, nfrags
--) {
else if (getbmap(blkno
)) {
for (dlp
= duplist
; dlp
< enddup
; dlp
++)
register int c
, n
, i
, b
, d
;
int blockbits
= (1<<sblock
.fs_frag
)-1;
bcopy(blockmap
, freemap
, (unsigned)bmapsz
);
n_index
= sblock
.fs_ncg
* (cgdmin(&sblock
, 0) - cgtod(&sblock
, 0));
for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
cbase
= cgbase(&sblock
, c
);
bzero((char *)botot
, sizeof (botot
));
bzero((char *)bo
, sizeof (bo
));
bzero((char *)frsum
, sizeof (frsum
));
* need to account for the super blocks
* which appear (inaccurately) bad
n_bad
+= cgtod(&sblock
, c
) - cgsblock(&sblock
, c
);
if (getblk(&cgblk
, cgtod(&sblock
, c
), sblock
.fs_cgsize
) == 0)
if (cgrp
.cg_magic
!= CG_MAGIC
) {
pfatal("CG %d: BAD MAGIC NUMBER\n", c
);
bzero((char *)&cgrp
, (int)sblock
.fs_cgsize
);
for (b
= 0; b
< sblock
.fs_fpg
; b
+= sblock
.fs_frag
) {
blk
= blkmap(&sblock
, cgrp
.cg_free
, b
);
if (pass5check(cbase
+b
, sblock
.fs_frag
) == STOP
)
n_ffree
-= sblock
.fs_frag
;
botot
[cbtocylno(&sblock
, b
)]++;
bo
[cbtocylno(&sblock
, b
)]
[cbtorpos(&sblock
, b
)]++;
for (d
= 0; d
< sblock
.fs_frag
; d
++)
pass5check(cbase
+ b
+ d
, (long)1) == STOP
)
fragacct(&sblock
, blk
, frsum
, 1);
if (bcmp((char *)cgrp
.cg_frsum
, (char *)frsum
, sizeof(frsum
))) {
for (i
= 0; i
< sblock
.fs_frag
; i
++)
if (cgrp
.cg_frsum
[i
] != frsum
[i
])
printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
c
, i
, cgrp
.cg_frsum
[i
], frsum
[i
]);
if (bcmp((char *)cgrp
.cg_btot
, (char *)botot
, sizeof (botot
))) {
for (n
= 0; n
< sblock
.fs_cpg
; n
++)
if (botot
[n
] != cgrp
.cg_btot
[n
])
printf("cg[%d].cg_btot[%d] have %d calc %d\n",
c
, n
, cgrp
.cg_btot
[n
], botot
[n
]);
if (bcmp((char *)cgrp
.cg_b
, (char *)bo
, sizeof (bo
))) {
for (i
= 0; i
< NRPOS
; i
++)
if (bo
[n
][i
] != cgrp
.cg_b
[n
][i
])
printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
c
, n
, i
, cgrp
.cg_b
[n
][i
], bo
[n
][i
]);
pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk
);
if ((b
= n_blks
+n_ffree
+sblock
.fs_frag
*n_bfree
+n_index
+n_bad
) != fmax
) {
pwarn("%ld BLK(S) MISSING\n", fmax
- b
);
} else if (inosumbad
+ offsumbad
+ frsumbad
+ sbsumbad
) {
pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
inosumbad
? "(INODE FREE) " : "",
offsumbad
? "(BLOCK OFFSETS) " : "",
frsumbad
? "(FRAG SUMMARIES) " : "",
sbsumbad
? "(SUPER BLOCK SUMMARIES) " : "");
} else if (n_ffree
!= sblock
.fs_cstotal
.cs_nffree
||
n_bfree
!= sblock
.fs_cstotal
.cs_nbfree
) {
pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
if (preen
|| reply("FIX") == 1) {
sblock
.fs_cstotal
.cs_nffree
= n_ffree
;
sblock
.fs_cstotal
.cs_nbfree
= n_bfree
;
pwarn("BAD CYLINDER GROUPS");
else if (reply("SALVAGE") == 0)
if (outrange(blk
, (int)size
)) {
pfatal("BAD BLOCKS IN BIT MAPS.");
if (++badblk
>= MAXBAD
) {
printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
if (reply("CONTINUE") == 0)
for (; size
> 0; blk
++, size
--)
register struct inodesc
*idesc
;
idesc
->id_fix
= DONTKNOW
;
ndb
= howmany(dino
.di_size
, sblock
.fs_bsize
);
for (ap
= &dino
.di_db
[0]; ap
< &dino
.di_db
[NDADDR
]; ap
++) {
if (--ndb
== 0 && (offset
= blkoff(&sblock
, dino
.di_size
)) != 0)
numfrags(&sblock
, fragroundup(&sblock
, offset
));
idesc
->id_numfrags
= sblock
.fs_frag
;
if (idesc
->id_type
== ADDR
)
ret
= (*idesc
->id_func
)(idesc
);
idesc
->id_numfrags
= sblock
.fs_frag
;
for (ap
= &dino
.di_ib
[0], n
= 1; n
<= 2; ap
++, n
++) {
dino
.di_size
- sblock
.fs_bsize
* NDADDR
);
iblock(idesc
, ilevel
, isize
)
int i
, n
, (*func
)(), nif
;
if (idesc
->id_type
== ADDR
) {
if (((n
= (*func
)(idesc
)) & KEEPON
) == 0)
if (outrange(idesc
->id_blkno
, idesc
->id_numfrags
)) /* protect thyself */
if (getblk(&ib
, idesc
->id_blkno
, sblock
.fs_bsize
) == NULL
)
nif
= lblkno(&sblock
, isize
) + 1;
} else /* ilevel == 1 */ {
nif
= isize
/ (sblock
.fs_bsize
* NINDIR(&sblock
)) + 1;
if (nif
> NINDIR(&sblock
))
aplim
= &ib
.b_un
.b_indir
[nif
];
for (ap
= ib
.b_un
.b_indir
, i
= 1; ap
< aplim
; ap
++, i
++)
n
= iblock(idesc
, ilevel
,
isize
- i
*NINDIR(&sblock
)*sblock
.fs_bsize
);
if ((unsigned)(blk
+cnt
) > fmax
)
if (blk
< cgdmin(&sblock
, c
)) {
if ((blk
+cnt
) > cgsblock(&sblock
, c
)) {
printf("blk %d < cgdmin %d;",
blk
, cgdmin(&sblock
, c
));
printf(" blk+cnt %d > cgsbase %d\n",
blk
+cnt
, cgsblock(&sblock
, c
));
if ((blk
+cnt
) > cgbase(&sblock
, c
+1)) {
printf("blk %d >= cgdmin %d;",
blk
, cgdmin(&sblock
, c
));
printf(" blk+cnt %d > sblock.fs_fpg %d\n",
pfatal("%ld %s I=%u", blk
, s
, ino
);
descend(parentino
, inumber
)
struct inodesc
*parentino
;
bzero((char *)&curino
, sizeof(struct inodesc
));
statemap
[inumber
] = FSTATE
;
if ((dp
= ginode(inumber
)) == NULL
)
direrr(inumber
, "ZERO LENGTH DIRECTORY");
if (reply("REMOVE") == 1)
statemap
[inumber
] = CLEAR
;
if (dp
->di_size
< MINDIRSIZE
) {
direrr(inumber
, "DIRECTORY TOO SHORT");
dp
->di_size
= MINDIRSIZE
;
curino
.id_func
= parentino
->id_func
;
curino
.id_parent
= parentino
->id_number
;
curino
.id_number
= inumber
;
curino
.id_filesize
= dp
->di_size
;
(void)ckinode(dp
, &curino
);
register struct inodesc
*idesc
;
if (idesc
->id_type
!= DATA
)
errexit("wrong type to dirscan %d\n", idesc
->id_type
);
blksiz
= idesc
->id_numfrags
* sblock
.fs_fsize
;
if (outrange(idesc
->id_blkno
, idesc
->id_numfrags
)) {
idesc
->id_filesize
-= blksiz
;
for (dp
= fsck_readdir(idesc
); dp
!= NULL
; dp
= fsck_readdir(idesc
)) {
bcopy((char *)dp
, dbuf
, dsize
);
idesc
->id_dirp
= (DIRECT
*)dbuf
;
if ((n
= (*idesc
->id_func
)(idesc
)) & ALTERED
) {
if (getblk(&fileblk
, idesc
->id_blkno
, blksiz
) != NULL
) {
bcopy(dbuf
, (char *)dp
, dsize
);
return (idesc
->id_filesize
> 0 ? KEEPON
: STOP
);
* get next entry in a directory.
register struct inodesc
*idesc
;
register DIRECT
*dp
, *ndp
;
blksiz
= idesc
->id_numfrags
* sblock
.fs_fsize
;
if (getblk(&fileblk
, idesc
->id_blkno
, blksiz
) == NULL
) {
idesc
->id_filesize
-= blksiz
- idesc
->id_loc
;
if (idesc
->id_loc
% DIRBLKSIZ
== 0 && idesc
->id_filesize
> 0 &&
idesc
->id_loc
< blksiz
) {
dp
= (DIRECT
*)(dirblk
.b_buf
+ idesc
->id_loc
);
idesc
->id_loc
+= DIRBLKSIZ
;
idesc
->id_filesize
-= DIRBLKSIZ
;
dp
->d_reclen
= DIRBLKSIZ
;
if (idesc
->id_filesize
<= 0 || idesc
->id_loc
>= blksiz
)
dp
= (DIRECT
*)(dirblk
.b_buf
+ idesc
->id_loc
);
idesc
->id_loc
+= dp
->d_reclen
;
idesc
->id_filesize
-= dp
->d_reclen
;
ndp
= (DIRECT
*)(dirblk
.b_buf
+ idesc
->id_loc
);
if ((idesc
->id_filesize
<= 0 && idesc
->id_loc
% DIRBLKSIZ
!= 0) ||
(idesc
->id_loc
< blksiz
&& idesc
->id_filesize
> 0 &&
dircheck(idesc
, ndp
) == 0)) {
size
= DIRBLKSIZ
- (idesc
->id_loc
% DIRBLKSIZ
);
idesc
->id_filesize
-= size
;
* Verify that a directory entry is valid.
* This is a superset of the checks made in the kernel.
spaceleft
= DIRBLKSIZ
- (idesc
->id_loc
% DIRBLKSIZ
);
dp
->d_reclen
<= spaceleft
&&
(dp
->d_reclen
& 0x3) == 0 &&
idesc
->id_filesize
>= size
&&
dp
->d_namlen
<= MAXNAMLEN
) {
for (cp
= dp
->d_name
, size
= 0; size
< dp
->d_namlen
; size
++)
if (*cp
== 0 || (*cp
++ & 0200))
if ((dp
= ginode(ino
)) != NULL
&& ftypeok(dp
))
pfatal("%s=%s\n", DIRCT
?"DIR":"FILE", pathname
);
pfatal("NAME=%s\n", pathname
);
register struct inodesc
*idesc
;
if ((dp
= ginode(idesc
->id_number
)) == NULL
)
if (dp
->di_nlink
== lcnt
) {
if (linkup(idesc
->id_number
, (ino_t
)0) == 0)
(lfdir
==idesc
->id_number
)?lfname
:(DIRCT
?"DIR":"FILE"));
pinode(idesc
->id_number
);
printf(" COUNT %d SHOULD BE %d",
dp
->di_nlink
, dp
->di_nlink
-lcnt
);
if (preen
|| reply("ADJUST") == 1) {
register struct inodesc
*idesc
;
if ((dp
= ginode(idesc
->id_number
)) == NULL
)
pwarn("%s %s", s
, DIRCT
?"DIR":"FILE");
pinode(idesc
->id_number
);
if (preen
|| reply("CLEAR") == 1) {
(void)ckinode(dp
, idesc
);
statemap
[idesc
->id_number
] = USTATE
;
printf("BAD SUPER BLOCK: %s\n", s
);
pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
static ino_t startinum
= 0; /* blk num of first in raw area */
if (inumber
< ROOTINO
|| inumber
> imax
) {
if (debug
&& inumber
> imax
)
printf("inumber out of range (%d)\n", inumber
);
inumber
< startinum
|| inumber
>= startinum
+ INOPB(&sblock
)) {
iblk
= itod(&sblock
, inumber
);
if (getblk(&inoblk
, iblk
, sblock
.fs_bsize
) == NULL
) {
startinum
= (inumber
/ INOPB(&sblock
)) * INOPB(&sblock
);
return (&inoblk
.b_un
.b_dinode
[inumber
% INOPB(&sblock
)]);
switch (dp
->di_mode
& IFMT
) {
printf("bad file type 0%o\n", dp
->di_mode
);
pfatal("INTERNAL ERROR: GOT TO reply()");
if (nflag
|| dfile
.wfdes
< 0) {
if (getline(stdin
, line
, sizeof(line
)) == EOF
)
if (line
[0] == 'y' || line
[0] == 'Y')
register char *p
, *lastloc
;
while ((n
= getc(fp
)) != '\n') {
if (!isspace(n
) && p
< lastloc
)
register struct filecntl
*fcp
;
dblk
= fsbtodb(&sblock
, blk
);
if (bread(fcp
, bp
->b_un
.b_buf
, dblk
, size
) != 0) {
(void)bwrite(fcp
, bp
->b_un
.b_buf
, bp
->b_bno
, (long)bp
->b_size
);
pfatal("CANNOT %s: BLK %ld", s
, blk
);
if (reply("CONTINUE") == 0)
errexit("Program terminated\n");
if (sblk
.b_bno
!= SBLOCK
) {
(void)close(dfile
.rfdes
);
(void)close(dfile
.wfdes
);
if ((dp
= ginode(ino
)) == NULL
)
if (getpw((int)dp
->di_uid
, uidbuf
) == 0) {
for (p
= uidbuf
; *p
!= ':'; p
++);
printf("%d ", dp
->di_uid
);
printf("MODE=%o\n", dp
->di_mode
);
printf("SIZE=%ld ", dp
->di_size
);
p
= ctime(&dp
->di_mtime
);
printf("MTIME=%12.12s %4.4s ", p
+4, p
+20);
daddr_t dbase
, d
, dlower
, dupper
, dmax
;
register struct csum
*cs
;
sblock
.fs_cstotal
.cs_nbfree
= 0;
sblock
.fs_cstotal
.cs_nffree
= 0;
sblock
.fs_cstotal
.cs_nifree
= 0;
sblock
.fs_cstotal
.cs_ndir
= 0;
for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
dbase
= cgbase(&sblock
, c
);
dmax
= dbase
+ sblock
.fs_fpg
;
if (dmax
> sblock
.fs_size
) {
for ( ; dmax
>= sblock
.fs_size
; dmax
--)
clrbit(cgrp
.cg_free
, dmax
- dbase
);
dlower
= cgsblock(&sblock
, c
) - dbase
;
dupper
= cgdmin(&sblock
, c
) - dbase
;
cs
= &sblock
.fs_cs(&sblock
, c
);
(void)time(&cgrp
.cg_time
);
cgrp
.cg_magic
= CG_MAGIC
;
if (c
== sblock
.fs_ncg
- 1)
cgrp
.cg_ncyl
= sblock
.fs_ncyl
% sblock
.fs_cpg
;
cgrp
.cg_ncyl
= sblock
.fs_cpg
;
cgrp
.cg_niblk
= sblock
.fs_ipg
;
cgrp
.cg_ndblk
= dmax
- dbase
;
cgrp
.cg_cs
.cs_nffree
= 0;
cgrp
.cg_cs
.cs_nbfree
= 0;
cgrp
.cg_cs
.cs_nifree
= 0;
for (i
= 0; i
< sblock
.fs_frag
; i
++)
inumber
= sblock
.fs_ipg
* c
;
for (i
= 0; i
< sblock
.fs_ipg
; inumber
++, i
++) {
clrbit(cgrp
.cg_iused
, i
);
setbit(cgrp
.cg_iused
, i
);
clrbit(cgrp
.cg_iused
, i
);
for (i
= 0; i
< ROOTINO
; i
++) {
setbit(cgrp
.cg_iused
, i
);
for (s
= 0; s
< MAXCPG
; s
++) {
for (i
= 0; i
< NRPOS
; i
++)
dupper
+= howmany(sblock
.fs_cssize
, sblock
.fs_fsize
);
for (d
= dlower
; d
< dupper
; d
++)
for (d
= 0; (d
+ sblock
.fs_frag
) <= dmax
- dbase
;
for (i
= 0; i
< sblock
.fs_frag
; i
++) {
if (!getbmap(dbase
+ d
+ i
)) {
setbit(cgrp
.cg_free
, d
+ i
);
clrbit(cgrp
.cg_free
, d
+i
);
if (j
== sblock
.fs_frag
) {
cgrp
.cg_btot
[cbtocylno(&sblock
, d
)]++;
cgrp
.cg_b
[cbtocylno(&sblock
, d
)]
[cbtorpos(&sblock
, d
)]++;
cgrp
.cg_cs
.cs_nffree
+= j
;
blk
= blkmap(&sblock
, cgrp
.cg_free
, d
);
fragacct(&sblock
, blk
, cgrp
.cg_frsum
, 1);
for (j
= d
; d
< dmax
- dbase
; d
++) {
if (!getbmap(dbase
+ d
)) {
for (; d
% sblock
.fs_frag
!= 0; d
++)
blk
= blkmap(&sblock
, cgrp
.cg_free
, j
);
fragacct(&sblock
, blk
, cgrp
.cg_frsum
, 1);
for (d
/= sblock
.fs_frag
; d
< MAXBPG(&sblock
); d
++)
clrblock(&sblock
, cgrp
.cg_free
, d
);
sblock
.fs_cstotal
.cs_nffree
+= cgrp
.cg_cs
.cs_nffree
;
sblock
.fs_cstotal
.cs_nbfree
+= cgrp
.cg_cs
.cs_nbfree
;
sblock
.fs_cstotal
.cs_nifree
+= cgrp
.cg_cs
.cs_nifree
;
sblock
.fs_cstotal
.cs_ndir
+= cgrp
.cg_cs
.cs_ndir
;
(void)bwrite(&dfile
, (char *)&cgrp
,
fsbtodb(&sblock
, cgtod(&sblock
, c
)), sblock
.fs_cgsize
);
for (i
= 0, j
= 0; i
< sblock
.fs_cssize
; i
+= sblock
.fs_bsize
, j
++) {
(void)bwrite(&dfile
, (char *)sblock
.fs_csp
[j
],
fsbtodb(&sblock
, sblock
.fs_csaddr
+ j
* sblock
.fs_frag
),
sblock
.fs_cssize
- i
< sblock
.fs_bsize
?
sblock
.fs_cssize
- i
: sblock
.fs_bsize
);
register DIRECT
*dirp
= idesc
->id_dirp
;
if (!strcmp(dirp
->d_name
, srchname
)) {
if (dirp
->d_ino
>= ROOTINO
&& dirp
->d_ino
<= imax
)
idesc
->id_parent
= dirp
->d_ino
;
register DIRECT
*dirp
= idesc
->id_dirp
;
newlen
= DIRSIZ(&newent
);
if (dirp
->d_reclen
- oldlen
< newlen
)
newent
.d_reclen
= dirp
->d_reclen
- oldlen
;
dirp
= (struct direct
*)(((char *)dirp
) + oldlen
);
dirp
->d_ino
= idesc
->id_parent
; /* ino to be entered is in id_parent */
dirp
->d_reclen
= newent
.d_reclen
;
dirp
->d_namlen
= lftempname(dirp
->d_name
, idesc
->id_parent
);
register DIRECT
*dirp
= idesc
->id_dirp
;
if (dirp
->d_name
[0] == '.' && dirp
->d_name
[1] == '.' &&
bzero((char *)&idesc
, sizeof(struct inodesc
));
if ((dp
= ginode(orphan
)) == NULL
)
pwarn("UNREF %s ", lostdir
? "DIR" : "FILE");
if (preen
&& dp
->di_size
== 0)
printf(" (RECONNECTED)\n");
if (reply("RECONNECT") == 0)
if ((dp
= ginode(ROOTINO
)) == NULL
)
idesc
.id_number
= ROOTINO
;
idesc
.id_filesize
= dp
->di_size
;
(void)ckinode(dp
, &idesc
);
if ((lfdir
= idesc
.id_parent
) == 0) {
pfatal("SORRY. NO lost+found DIRECTORY");
if ((dp
= ginode(lfdir
)) == NULL
||
!DIRCT
|| statemap
[lfdir
] != FSTATE
) {
pfatal("SORRY. NO lost+found DIRECTORY");
if (fragoff(&sblock
, dp
->di_size
)) {
dp
->di_size
= fragroundup(&sblock
, dp
->di_size
);
bcopy(lfname
, pathp
, len
+ 1);
idesc
.id_filesize
= dp
->di_size
;
idesc
.id_parent
= orphan
; /* this is the inode to enter */
if ((ckinode(dp
, &idesc
) & ALTERED
) == 0) {
pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
pathp
+= lftempname(pathp
, orphan
);
idesc
.id_number
= orphan
;
idesc
.id_filesize
= dp
->di_size
;
(void)ckinode(dp
, &idesc
);
if ((dp
= ginode(lfdir
)) != NULL
) {
pwarn("DIR I=%u CONNECTED. ", orphan
);
printf("PARENT WAS I=%u\n", pdir
);
* generate a temporary name for the lost+found directory.
for (in
= imax
; in
> 0; in
/= 10)
bread(fcp
, buf
, blk
, size
)
register struct filecntl
*fcp
;
if (lseek(fcp
->rfdes
, (long)dbtob(blk
), 0) < 0)
else if (read(fcp
->rfdes
, buf
, (int)size
) == size
)
bwrite(fcp
, buf
, blk
, size
)
register struct filecntl
*fcp
;
if (lseek(fcp
->wfdes
, (long)dbtob(blk
), 0) < 0)
else if (write(fcp
->wfdes
, buf
, (int)size
) == size
) {
char *dp
= rindex(cp
, '/');
if ((stb
.st_mode
&S_IFMT
) != S_IFCHR
)
(void)strcpy(dp
+1, dp
+2);
char *dp
= rindex(cp
, '/');
(void)strcpy(rawbuf
, cp
);
(void)strcat(rawbuf
, "/r");
(void)strcat(rawbuf
, dp
+1);
* determine whether an inode should be fixed.
register struct inodesc
*idesc
;
direrr(idesc
->id_number
, "DIRECTORY CORRUPTED");
if (reply("SALVAGE") == 0) {
errexit("UNKNOWN INODESC FIX MODE %d\n", idesc
->id_fix
);
* An inconsistency occured which shouldn't during normal operations.
* Die if preening, otherwise just printf.
printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname
);
* Pwarn is like printf when not preening,
* or a warning (preceded by filename) when preening.
pwarn(s
, a1
, a2
, a3
, a4
, a5
, a6
)
printf(s
, a1
, a2
, a3
, a4
, a5
, a6
);
* Stub for routines from kernel.
pfatal("INTERNAL INCONSISTENCY: %s\n", s
);