* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)utilities.c 5.13 (Berkeley) %G%";
long diskreads
, totalreads
; /* Disk cache statistics */
switch (dp
->di_mode
& IFMT
) {
printf("bad file type 0%o\n", dp
->di_mode
);
int cont
= (strcmp(s
, "CONTINUE") == 0);
pfatal("INTERNAL ERROR: GOT TO reply()");
if (!cont
&& (nflag
|| dfile
.wfdes
< 0)) {
if (yflag
|| (cont
&& nflag
)) {
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
)
* Malloc buffers and set up cache.
bufp
= (char *)malloc(sblock
.fs_bsize
);
errexit("cannot allocate buffer pool\n");
bufhead
.b_next
= bufhead
.b_prev
= &bufhead
;
bufcnt
= MAXBUFSPACE
/ sblock
.fs_bsize
;
for (i
= 0; i
< bufcnt
; i
++) {
bp
= (BUFAREA
*)malloc(sizeof(BUFAREA
));
bufp
= (char *)malloc(sblock
.fs_bsize
);
if (bp
== 0 || bufp
== 0) {
errexit("cannot allocate buffer pool\n");
bp
->b_next
= bufhead
.b_next
;
bufhead
.b_next
->b_prev
= bp
;
bufhead
.b_size
= i
; /* save number of buffers */
* Manage a cache of directory blocks.
for (bp
= bufhead
.b_next
; bp
!= &bufhead
; bp
= bp
->b_next
)
if (bp
->b_bno
== fsbtodb(&sblock
, blkno
))
for (bp
= bufhead
.b_prev
; bp
!= &bufhead
; bp
= bp
->b_prev
)
if ((bp
->b_flags
& B_INUSE
) == 0)
errexit("deadlocked buffer pool\n");
bp
->b_prev
->b_next
= bp
->b_next
;
bp
->b_next
->b_prev
= bp
->b_prev
;
bp
->b_next
= bufhead
.b_next
;
bufhead
.b_next
->b_prev
= bp
;
register struct filecntl
*fcp
;
dblk
= fsbtodb(&sblock
, blk
);
bp
->b_errs
= bread(fcp
, bp
->b_un
.b_buf
, dblk
, size
);
pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
(bp
->b_errs
== bp
->b_size
/ dev_bsize
) ? "" : "PARTIALLY ",
bwrite(fcp
, bp
->b_un
.b_buf
, bp
->b_bno
, (long)bp
->b_size
);
for (i
= 0, j
= 0; i
< sblock
.fs_cssize
; i
+= sblock
.fs_bsize
, j
++) {
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
);
pfatal("CANNOT %s: BLK %ld", s
, blk
);
if (reply("CONTINUE") == 0)
errexit("Program terminated\n");
if (havesb
&& sblk
.b_bno
!= SBOFF
/ dev_bsize
&&
!preen
&& reply("UPDATE STANDARD SUPERBLOCK")) {
sblk
.b_bno
= SBOFF
/ dev_bsize
;
for (bp
= bufhead
.b_prev
; bp
!= &bufhead
; bp
= bp
->b_prev
) {
if (bufhead
.b_size
!= cnt
)
errexit("Panic: lost %d buffers\n", bufhead
.b_size
- cnt
);
printf("cache missed %d of %d (%d%%)\n", diskreads
,
totalreads
, diskreads
* 100 / totalreads
);
(void)close(dfile
.rfdes
);
(void)close(dfile
.wfdes
);
bread(fcp
, buf
, blk
, size
)
register struct filecntl
*fcp
;
if (lseek(fcp
->rfdes
, blk
* dev_bsize
, 0) < 0)
else if (read(fcp
->rfdes
, buf
, (int)size
) == size
)
if (lseek(fcp
->rfdes
, blk
* dev_bsize
, 0) < 0)
printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
for (cp
= buf
, i
= 0; i
< size
; i
+= secsize
, cp
+= secsize
) {
if (read(fcp
->rfdes
, cp
, secsize
) < 0) {
lseek(fcp
->rfdes
, blk
* dev_bsize
+ i
+ secsize
, 0);
if (secsize
!= dev_bsize
&& dev_bsize
!= 1)
(blk
* dev_bsize
+ i
) / secsize
,
printf(" %d,", blk
+ i
/ dev_bsize
);
bwrite(fcp
, buf
, blk
, size
)
register struct filecntl
*fcp
;
if (lseek(fcp
->wfdes
, blk
* dev_bsize
, 0) < 0)
else if (write(fcp
->wfdes
, buf
, (int)size
) == size
) {
if (lseek(fcp
->wfdes
, blk
* dev_bsize
, 0) < 0)
printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
for (cp
= buf
, i
= 0; i
< size
; i
+= dev_bsize
, cp
+= dev_bsize
)
if (write(fcp
->wfdes
, cp
, dev_bsize
) < 0) {
lseek(fcp
->rfdes
, blk
* dev_bsize
+ i
+ dev_bsize
, 0);
printf(" %d,", blk
+ i
/ dev_bsize
);
* allocate a data block with the specified number of fragments
if (frags
<= 0 || frags
> sblock
.fs_frag
)
for (i
= 0; i
< fmax
- sblock
.fs_frag
; i
+= sblock
.fs_frag
) {
for (j
= 0; j
<= sblock
.fs_frag
- frags
; j
++) {
for (k
= 1; k
< frags
; k
++)
for (k
= 0; k
< frags
; k
++)
* Free a previously allocated block
idesc
.id_numfrags
= frags
;
getpathname(namebuf
, curdir
, ino
)
if (statemap
[ino
] != DSTATE
&& statemap
[ino
] != DFOUND
) {
bzero(&idesc
, sizeof(struct inodesc
));
cp
= &namebuf
[BUFSIZ
- 1];
idesc
.id_parent
= curdir
;
if ((ckinode(ginode(ino
), &idesc
) & FOUND
) == 0)
idesc
.id_number
= idesc
.id_parent
;
idesc
.id_func
= findname
;
if ((ckinode(ginode(idesc
.id_number
), &idesc
) & FOUND
) == 0)
if (cp
< &namebuf
[MAXNAMLEN
])
bcopy(cp
, namebuf
, &namebuf
[BUFSIZ
] - cp
);
* When preening, allow a single quit to signal
* a special exit after filesystem checks complete
* so that reboot sequence may be interrupted.
printf("returning to single-user after filesystem check\n");
(void)signal(SIGQUIT
, SIG_DFL
);
* Ignore a single quit signal; wait and flush just in case.
* Used by child processes in preen.
(void)signal(SIGQUIT
, SIG_IGN
);
(void)signal(SIGQUIT
, SIG_DFL
);
* determine whether an inode should be fixed.
register struct inodesc
*idesc
;
if (idesc
->id_type
== DATA
)
direrr(idesc
->id_number
, msg
);
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",
* 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:");