mirror of
https://github.com/opnsense/src.git
synced 2026-04-02 16:05:17 -04:00
BSD 4.4 Lite sbin Sources
Note: XNSrouted and routed NOT imported here, they shall be imported with usr.sbin.
This commit is contained in:
parent
4b88c807ea
commit
8fae3551ec
304 changed files with 70407 additions and 0 deletions
10
sbin/Makefile
Normal file
10
sbin/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# @(#)Makefile 8.5 (Berkeley) 3/31/94
|
||||
|
||||
SUBDIR= XNSrouted badsect clri disklabel dmesg dump dumpfs dumplfs fastboot \
|
||||
fsck fsdb icheck ifconfig init mknod mount mount_cd9660 mount_fdesc \
|
||||
mount_kernfs mount_lfs mount_nfs mount_null mount_portal \
|
||||
mount_procfs mount_umap mount_union mountd ncheck newfs newlfs nfsd \
|
||||
nfsiod nologin ping quotacheck reboot restore route routed savecore \
|
||||
scsiformat shutdown slattach startslip swapon tunefs umount
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
3
sbin/Makefile.inc
Normal file
3
sbin/Makefile.inc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# @(#)Makefile.inc 8.1 (Berkeley) 6/8/93
|
||||
|
||||
BINDIR?= /sbin
|
||||
6
sbin/badsect/Makefile
Normal file
6
sbin/badsect/Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= badsect
|
||||
MAN8= badsect.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
132
sbin/badsect/badsect.8
Normal file
132
sbin/badsect/badsect.8
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
.\" Copyright (c) 1985, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)badsect.8 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.Dd June 5, 1993
|
||||
.Dt BADSECT 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm badsect
|
||||
.Nd create files to contain bad sectors
|
||||
.Sh SYNOPSIS
|
||||
.Nm /etc/badsect
|
||||
.Ar bbdir sector ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm Badsect
|
||||
makes a file to contain a bad sector. Normally, bad sectors
|
||||
are made inaccessible by the standard formatter, which provides
|
||||
a forwarding table for bad sectors to the driver; see
|
||||
.Xr bad144 8
|
||||
for details.
|
||||
If a driver supports the bad blocking standard it is much preferable to
|
||||
use that method to isolate bad blocks, since the bad block forwarding
|
||||
makes the pack appear perfect, and such packs can then be copied with
|
||||
.Xr dd 1 .
|
||||
The technique used by this program is also less general than
|
||||
bad block forwarding, as
|
||||
.Nm badsect
|
||||
can't make amends for
|
||||
bad blocks in the i-list of file systems or in swap areas.
|
||||
.Pp
|
||||
On some disks,
|
||||
adding a sector which is suddenly bad to the bad sector table
|
||||
currently requires the running of the standard
|
||||
.Tn DEC
|
||||
formatter.
|
||||
Thus to deal with a newly bad block
|
||||
or on disks where the drivers
|
||||
do not support the bad-blocking standard
|
||||
.Nm badsect
|
||||
may be used to good effect.
|
||||
.Pp
|
||||
.Nm Badsect
|
||||
is used on a quiet file system in the following way:
|
||||
First mount the file system, and change to its root directory.
|
||||
Make a directory
|
||||
.Li BAD
|
||||
there. Run
|
||||
.Nm badsect
|
||||
giving as argument the
|
||||
.Ar BAD
|
||||
directory followed by
|
||||
all the bad sectors you wish to add.
|
||||
(The sector numbers must be relative to the beginning of
|
||||
the file system, but this is not hard as the system reports
|
||||
relative sector numbers in its console error messages.)
|
||||
Then change back to the root directory, unmount the file system
|
||||
and run
|
||||
.Xr fsck 8
|
||||
on the file system. The bad sectors should show up in two files
|
||||
or in the bad sector files and the free list. Have
|
||||
.Xr fsck
|
||||
remove files containing the offending bad sectors, but
|
||||
.Em do not
|
||||
have it remove the
|
||||
.Pa BAD/ Ns Em nnnnn
|
||||
files.
|
||||
This will leave the bad sectors in only the
|
||||
.Li BAD
|
||||
files.
|
||||
.Pp
|
||||
.Nm Badsect
|
||||
works by giving the specified sector numbers in a
|
||||
.Xr mknod 2
|
||||
system call,
|
||||
creating an illegal file whose first block address is the block containing
|
||||
bad sector and whose name is the bad sector number.
|
||||
When it is discovered by
|
||||
.Xr fsck
|
||||
it will ask
|
||||
.Dq Li "HOLD BAD BLOCK ?"
|
||||
A positive response will cause
|
||||
.Xr fsck
|
||||
to convert the inode to a regular file containing the bad block.
|
||||
.Sh SEE ALSO
|
||||
.Xr bad144 8 ,
|
||||
.Xr fsck 8 ,
|
||||
.Xr format 8
|
||||
.Sh DIAGNOSTICS
|
||||
.Nm Badsect
|
||||
refuses to attach a block that
|
||||
resides in a critical area or is out of range of the file system.
|
||||
A warning is issued if the block is already in use.
|
||||
.Sh BUGS
|
||||
If more than one sector which comprise a file system fragment are bad,
|
||||
you should specify only one of them to
|
||||
.Nm badsect ,
|
||||
as the blocks in the bad sector files actually cover all the sectors in a
|
||||
file system fragment.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.1 .
|
||||
209
sbin/badsect/badsect.c
Normal file
209
sbin/badsect/badsect.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 1981, 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1981, 1983, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)badsect.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* badsect
|
||||
*
|
||||
* Badsect takes a list of file-system relative sector numbers
|
||||
* and makes files containing the blocks of which these sectors are a part.
|
||||
* It can be used to contain sectors which have problems if these sectors
|
||||
* are not part of the bad file for the pack (see bad144). For instance,
|
||||
* this program can be used if the driver for the file system in question
|
||||
* does not support bad block forwarding.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
union {
|
||||
struct fs fs;
|
||||
char fsx[SBSIZE];
|
||||
} ufs;
|
||||
#define sblock ufs.fs
|
||||
union {
|
||||
struct cg cg;
|
||||
char cgx[MAXBSIZE];
|
||||
} ucg;
|
||||
#define acg ucg.cg
|
||||
struct fs *fs;
|
||||
int fso, fsi;
|
||||
int errs;
|
||||
long dev_bsize = 1;
|
||||
|
||||
char buf[MAXBSIZE];
|
||||
|
||||
void rdfs __P((daddr_t, int, char *));
|
||||
int chkuse __P((daddr_t, int));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
daddr_t number;
|
||||
struct stat stbuf, devstat;
|
||||
register struct direct *dp;
|
||||
DIR *dirp;
|
||||
char name[BUFSIZ];
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: badsect bbdir blkno [ blkno ]\n");
|
||||
exit(1);
|
||||
}
|
||||
if (chdir(argv[1]) < 0 || stat(".", &stbuf) < 0) {
|
||||
perror(argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
strcpy(name, _PATH_DEV);
|
||||
if ((dirp = opendir(name)) == NULL) {
|
||||
perror(name);
|
||||
exit(3);
|
||||
}
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
strcpy(&name[5], dp->d_name);
|
||||
if (stat(name, &devstat) < 0) {
|
||||
perror(name);
|
||||
exit(4);
|
||||
}
|
||||
if (stbuf.st_dev == devstat.st_rdev &&
|
||||
(devstat.st_mode & IFMT) == IFBLK)
|
||||
break;
|
||||
}
|
||||
closedir(dirp);
|
||||
if (dp == NULL) {
|
||||
printf("Cannot find dev 0%o corresponding to %s\n",
|
||||
stbuf.st_rdev, argv[1]);
|
||||
exit(5);
|
||||
}
|
||||
if ((fsi = open(name, 0)) < 0) {
|
||||
perror(name);
|
||||
exit(6);
|
||||
}
|
||||
fs = &sblock;
|
||||
rdfs(SBOFF, SBSIZE, (char *)fs);
|
||||
dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
|
||||
for (argc -= 2, argv += 2; argc > 0; argc--, argv++) {
|
||||
number = atoi(*argv);
|
||||
if (chkuse(number, 1))
|
||||
continue;
|
||||
if (mknod(*argv, IFMT|0600, dbtofsb(fs, number)) < 0) {
|
||||
perror(*argv);
|
||||
errs++;
|
||||
}
|
||||
}
|
||||
printf("Don't forget to run ``fsck %s''\n", name);
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
int
|
||||
chkuse(blkno, cnt)
|
||||
daddr_t blkno;
|
||||
int cnt;
|
||||
{
|
||||
int cg;
|
||||
daddr_t fsbn, bn;
|
||||
|
||||
fsbn = dbtofsb(fs, blkno);
|
||||
if ((unsigned)(fsbn+cnt) > fs->fs_size) {
|
||||
printf("block %d out of range of file system\n", blkno);
|
||||
return (1);
|
||||
}
|
||||
cg = dtog(fs, fsbn);
|
||||
if (fsbn < cgdmin(fs, cg)) {
|
||||
if (cg == 0 || (fsbn+cnt) > cgsblock(fs, cg)) {
|
||||
printf("block %d in non-data area: cannot attach\n",
|
||||
blkno);
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
if ((fsbn+cnt) > cgbase(fs, cg+1)) {
|
||||
printf("block %d in non-data area: cannot attach\n",
|
||||
blkno);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)sblock.fs_cgsize,
|
||||
(char *)&acg);
|
||||
if (!cg_chkmagic(&acg)) {
|
||||
fprintf(stderr, "cg %d: bad magic number\n", cg);
|
||||
errs++;
|
||||
return (1);
|
||||
}
|
||||
bn = dtogd(fs, fsbn);
|
||||
if (isclr(cg_blksfree(&acg), bn))
|
||||
printf("Warning: sector %d is in use\n", blkno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* read a block from the file system
|
||||
*/
|
||||
void
|
||||
rdfs(bno, size, bf)
|
||||
daddr_t bno;
|
||||
int size;
|
||||
char *bf;
|
||||
{
|
||||
int n;
|
||||
|
||||
if (lseek(fsi, (off_t)bno * dev_bsize, SEEK_SET) < 0) {
|
||||
printf("seek error: %ld\n", bno);
|
||||
perror("rdfs");
|
||||
exit(1);
|
||||
}
|
||||
n = read(fsi, bf, size);
|
||||
if (n != size) {
|
||||
printf("read error: %ld\n", bno);
|
||||
perror("rdfs");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
14
sbin/bsdlabel/Makefile
Normal file
14
sbin/bsdlabel/Makefile
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# @(#)Makefile 8.2 (Berkeley) 3/17/94
|
||||
|
||||
PROG= disklabel
|
||||
SRCS= disklabel.c dkcksum.c
|
||||
MAN8= disklabel.0
|
||||
CLEANFILES=disklabel.5.0
|
||||
|
||||
all: ${PROG} disklabel.5.0 ${MAN8}
|
||||
|
||||
beforeinstall:
|
||||
install -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} disklabel.5.0 \
|
||||
${DESTDIR}${MANDIR}5/disklabel.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
343
sbin/bsdlabel/bsdlabel.8
Normal file
343
sbin/bsdlabel/bsdlabel.8
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
.\" Copyright (c) 1987, 1988, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" Symmetric Computer Systems.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)disklabel.8 8.2 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.Dd "April 19, 1994"
|
||||
.Dt DISKLABEL 8
|
||||
.Os BSD 4.2
|
||||
.Sh NAME
|
||||
.Nm disklabel
|
||||
.Nd read and write disk pack label
|
||||
.Sh SYNOPSIS
|
||||
.Nm disklabel
|
||||
.Op Fl r
|
||||
.Ar disk
|
||||
.Nm disklabel
|
||||
.Fl w
|
||||
.Op Fl r
|
||||
.Ar disk Ar disktype
|
||||
.Oo Ar packid Oc
|
||||
.Nm disklabel
|
||||
.Fl e
|
||||
.Op Fl r
|
||||
.Ar disk
|
||||
.Nm disklabel
|
||||
.Fl R
|
||||
.Op Fl r
|
||||
.Ar disk Ar protofile
|
||||
.Nm disklabel
|
||||
.Op Fl NW
|
||||
.Ar disk
|
||||
.sp
|
||||
.Nm disklabel
|
||||
.Fl B
|
||||
.Oo
|
||||
.Fl b Ar boot1
|
||||
.Op Fl s Ar boot2
|
||||
.Oc
|
||||
.Ar disk
|
||||
.Oo Ar disktype Oc
|
||||
.Nm disklabel
|
||||
.Fl w
|
||||
.Fl B
|
||||
.Oo
|
||||
.Fl b Ar boot1
|
||||
.Op Fl s Ar boot2
|
||||
.Oc
|
||||
.Ar disk Ar disktype
|
||||
.Oo Ar packid Oc
|
||||
.Nm disklabel
|
||||
.Fl R
|
||||
.Fl B
|
||||
.Oo
|
||||
.Fl b Ar boot1
|
||||
.Op Fl s Ar boot2
|
||||
.Oc
|
||||
.Ar disk Ar protofile
|
||||
.Oo Ar disktype Oc
|
||||
.Sh DESCRIPTION
|
||||
.Nm Disklabel
|
||||
can be used to install, examine or modify the label on a disk drive or pack.
|
||||
When writing the label, it can be used
|
||||
to change the drive identification,
|
||||
the disk partitions on the drive,
|
||||
or to replace a damaged label.
|
||||
On some systems,
|
||||
.Nm disklabel
|
||||
can be used to install bootstrap code as well.
|
||||
There are several forms of the command that read (display), install or edit
|
||||
the label on a disk.
|
||||
Each form has an additional option,
|
||||
.Fl r ,
|
||||
which causes the label to be read from or written to the disk directly,
|
||||
rather than going through the system's in-core copy of the label.
|
||||
This option may allow a label to be installed on a disk
|
||||
without kernel support for a label, such as when labels are first installed
|
||||
on a system; it must be used when first installing a label on a disk.
|
||||
The specific effect of
|
||||
.Fl r
|
||||
is described under each command.
|
||||
The read and install forms also support the
|
||||
.Fl B
|
||||
option to install bootstrap code.
|
||||
These variants are described later.
|
||||
.Pp
|
||||
The first form of the command (read) is used to examine the label on the named
|
||||
disk drive (e.g. sd0 or /dev/rsd0c).
|
||||
It will display all of the parameters associated with the drive
|
||||
and its partition layout.
|
||||
Unless the
|
||||
.Fl r
|
||||
flag is given,
|
||||
the kernel's in-core copy of the label is displayed;
|
||||
if the disk has no label, or the partition types on the disk are incorrect,
|
||||
the kernel may have constructed or modified the label.
|
||||
If the
|
||||
.Fl r
|
||||
flag is given, the label from the raw disk will be displayed rather
|
||||
than the in-core label.
|
||||
.Pp
|
||||
The second form of the command, with the
|
||||
.Fl w
|
||||
flag, is used to write a standard label on the designated drive.
|
||||
The required arguments to
|
||||
.Nm disklabel
|
||||
are the drive to be labelled (e.g. sd0), and
|
||||
the drive type as described in the
|
||||
.Xr disktab 5
|
||||
file.
|
||||
The drive parameters and partitions are taken from that file.
|
||||
If different disks of the same physical type are to have different
|
||||
partitions, it will be necessary to have separate disktab entries
|
||||
describing each, or to edit the label after installation as described below.
|
||||
The optional argument is a pack identification string,
|
||||
up to 16 characters long.
|
||||
The pack id must be quoted if it contains blanks.
|
||||
If the
|
||||
.Fl r
|
||||
flag is given, the disk sectors containing the label and bootstrap
|
||||
will be written directly.
|
||||
A side-effect of this is that any existing bootstrap code will be overwritten
|
||||
and the disk rendered unbootable.
|
||||
If
|
||||
.Fl r
|
||||
is not specified,
|
||||
the existing label will be updated via the in-core copy and any bootstrap
|
||||
code will be unaffected.
|
||||
If the disk does not already have a label, the
|
||||
.Fl r
|
||||
flag must be used.
|
||||
In either case, the kernel's in-core label is replaced.
|
||||
.Pp
|
||||
An existing disk label may be edited by using the
|
||||
.Fl e
|
||||
flag.
|
||||
The label is read from the in-core kernel copy,
|
||||
or directly from the disk if the
|
||||
.Fl r
|
||||
flag is also given.
|
||||
The label is formatted and then supplied to an editor for changes.
|
||||
If no editor is specified in an
|
||||
.Ev EDITOR
|
||||
environment variable,
|
||||
.Xr vi 1
|
||||
is used.
|
||||
When the editor terminates, the formatted label is reread
|
||||
and used to rewrite the disk label.
|
||||
Existing bootstrap code is unchanged regardless of whether
|
||||
.Fl r
|
||||
was specified.
|
||||
.Pp
|
||||
With the
|
||||
.Fl R
|
||||
flag,
|
||||
.Nm disklabel
|
||||
is capable of restoring a disk label that was formatted
|
||||
in a prior operation and saved in an ascii file.
|
||||
The prototype file used to create the label should be in the same format
|
||||
as that produced when reading or editing a label.
|
||||
Comments are delimited by
|
||||
.Ar \&#
|
||||
and newline.
|
||||
As with
|
||||
.Fl w ,
|
||||
any existing bootstrap code will be clobbered if
|
||||
.Fl r
|
||||
is specified and will be unaffected otherwise.
|
||||
.Pp
|
||||
The
|
||||
.Fl NW
|
||||
flags for
|
||||
.Nm disklabel
|
||||
explicitly disallow and
|
||||
allow, respectively, writing of the pack label area on the selected disk.
|
||||
.Pp
|
||||
The final three forms of
|
||||
.Nm disklabel
|
||||
are used to install boostrap code on machines where the bootstrap is part
|
||||
of the label.
|
||||
The bootstrap code is comprised of one or two boot programs depending on
|
||||
the machine.
|
||||
The
|
||||
.Fl B
|
||||
option is used to denote that bootstrap code is to be installed.
|
||||
The
|
||||
.Fl r
|
||||
flag is implied by
|
||||
.Fl B
|
||||
and never needs to be specified.
|
||||
The name of the boot program(s) to be installed can be selected in a
|
||||
variety of ways.
|
||||
First, the names can be specified explicitly via the
|
||||
.Fl b
|
||||
and
|
||||
.Fl s
|
||||
flags.
|
||||
On machines with only a single level of boot program,
|
||||
.Fl b
|
||||
is the name of that program.
|
||||
For machines with a two-level bootstrap,
|
||||
.Fl b
|
||||
indicates the primary boot program and
|
||||
.Fl s
|
||||
the secondary boot program.
|
||||
If the names are not explicitly given, standard boot programs will be used.
|
||||
The boot programs are located in
|
||||
.Pa /usr/mdec .
|
||||
The names of the programs are taken from the ``b0'' and ``b1'' parameters
|
||||
of the
|
||||
.Xr disktab 5
|
||||
entry for the disk if
|
||||
.Ar disktype
|
||||
was given and its disktab entry exists and includes those parameters.
|
||||
Otherwise, boot program names are derived from the name of the disk.
|
||||
These names are of the form
|
||||
.Pa basename Ns boot
|
||||
for the primary (or only) bootstrap, and
|
||||
.Pf boot Pa basename
|
||||
for the secondary bootstrap;
|
||||
for example,
|
||||
.Pa /usr/mdec/sdboot
|
||||
and
|
||||
.Pa /usr/mdec/bootsd
|
||||
if the disk device is
|
||||
.Em sd0 .
|
||||
.Pp
|
||||
The first of the three boot-installation forms is used to install
|
||||
bootstrap code without changing the existing label.
|
||||
It is essentially a read command with respect to the disk label
|
||||
itself and all options are related to the specification of the boot
|
||||
program as described previously.
|
||||
The final two forms are analogous to the basic write and restore versions
|
||||
except that they will install bootstrap code in addition to a new label.
|
||||
.Sh FILES
|
||||
.Bl -tag -width Pa -compact
|
||||
.It Pa /etc/disktab
|
||||
.It Pa /usr/mdec/ Ns Em xx Ns boot
|
||||
.It Pa /usr/mdec/boot Ns Em xx
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Dl disklabel sd0
|
||||
.Pp
|
||||
Display the in-core label for sd0 as obtained via
|
||||
.Pa /dev/rsd0c .
|
||||
.Pp
|
||||
.Dl disklabel -w -r /dev/rsd0c sd2212 foo
|
||||
.Pp
|
||||
Create a label for sd0 based on information for ``sd2212'' found in
|
||||
.Pa /etc/disktab .
|
||||
Any existing bootstrap code will be clobbered.
|
||||
.Pp
|
||||
.Dl disklabel -e -r sd0
|
||||
.Pp
|
||||
Read the on-disk label for sd0, edit it and reinstall in-core as well
|
||||
as on-disk.
|
||||
Existing bootstrap code is unaffected.
|
||||
.Pp
|
||||
.Dl disklabel -R sd0 mylabel
|
||||
.Pp
|
||||
Restore the on-disk and in-core label for sd0 from information in
|
||||
.Pa mylabel .
|
||||
Existing bootstrap code is unaffected.
|
||||
.Pp
|
||||
.Dl disklabel -B sd0
|
||||
.Pp
|
||||
Install a new bootstrap on sd0.
|
||||
The boot code comes from
|
||||
.Pa /usr/mdec/sdboot
|
||||
and possibly
|
||||
.Pa /usr/mdec/bootsd .
|
||||
On-disk and in-core labels are unchanged.
|
||||
.Pp
|
||||
.Dl disklabel -w -B /dev/rsd0c -b newboot sd2212
|
||||
.Pp
|
||||
Install a new label and bootstrap.
|
||||
The label is derived from disktab information for ``sd2212'' and
|
||||
installed both in-core and on-disk.
|
||||
The bootstrap code comes from the file
|
||||
.Pa /usr/mdec/newboot .
|
||||
.Sh SEE ALSO
|
||||
.Xr disktab 5 ,
|
||||
.Xr disklabel 5
|
||||
.Sh DIAGNOSTICS
|
||||
The kernel device drivers will not allow the size of a disk partition
|
||||
to be decreased or the offset of a partition to be changed while it is open.
|
||||
Some device drivers create a label containing only a single large partition
|
||||
if a disk is unlabeled; thus, the label must be written to the ``a''
|
||||
partition of the disk while it is open.
|
||||
This sometimes requires the desired label to be set in two steps,
|
||||
the first one creating at least one other partition,
|
||||
and the second setting the label on the new partition
|
||||
while shrinking the ``a'' partition.
|
||||
.Pp
|
||||
On some machines the bootstrap code may not fit entirely in the area
|
||||
allocated for it by some filesystems.
|
||||
As a result, it may not be possible to have filesystems on some partitions
|
||||
of a ``bootable'' disk.
|
||||
When installing bootstrap code,
|
||||
.Nm disklabel
|
||||
checks for these cases.
|
||||
If the installed boot code would overlap a partition of type FS_UNUSED
|
||||
it is marked as type FS_BOOT.
|
||||
The
|
||||
.Xr newfs 8
|
||||
utility will disallow creation of filesystems on FS_BOOT partitions.
|
||||
Conversely, if a partition has a type other than FS_UNUSED or FS_BOOT,
|
||||
.Nm disklabel
|
||||
will not install bootstrap code that overlaps it.
|
||||
.Sh BUGS
|
||||
When a disk name is given without a full pathname,
|
||||
the constructed device name uses the ``a'' partition on the tahoe,
|
||||
the ``c'' partition on all others.
|
||||
1314
sbin/bsdlabel/bsdlabel.c
Normal file
1314
sbin/bsdlabel/bsdlabel.c
Normal file
File diff suppressed because it is too large
Load diff
384
sbin/bsdlabel/disklabel.5.5
Normal file
384
sbin/bsdlabel/disklabel.5.5
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
.\" Copyright (c) 1987, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" Symmetric Computer Systems.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)disklabel.5.5 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.Dd June 5, 1993
|
||||
.Dt DISKLABEL 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm disklabel
|
||||
.Nd disk pack label
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <sys/disklabel.h>
|
||||
.Sh DESCRIPTION
|
||||
Each disk or disk pack on a system may contain a disk label
|
||||
which provides detailed information
|
||||
about the geometry of the disk and the partitions into which the disk
|
||||
is divided.
|
||||
It should be initialized when the disk is formatted,
|
||||
and may be changed later with the
|
||||
.Xr disklabel 8
|
||||
program.
|
||||
This information is used by the system disk driver and by the bootstrap
|
||||
program to determine how to program the drive
|
||||
and where to find the filesystems on the disk partitions.
|
||||
Additional information is used by the filesystem in order
|
||||
to use the disk most efficiently and to locate important filesystem information.
|
||||
The description of each partition contains an identifier for the partition
|
||||
type (standard filesystem, swap area, etc.).
|
||||
The filesystem updates the in-core copy of the label if it contains
|
||||
incomplete information about the filesystem.
|
||||
.Pp
|
||||
The label is located in sector number
|
||||
.Dv LABELSECTOR
|
||||
of the drive, usually sector 0 where it may be found
|
||||
without any information about the disk geometry.
|
||||
It is at an offset
|
||||
.Dv LABELOFFSET
|
||||
from the beginning of the sector, to allow room for the initial bootstrap.
|
||||
The disk sector containing the label is normally made read-only
|
||||
so that it is not accidentally overwritten by pack-to-pack copies
|
||||
or swap operations;
|
||||
the
|
||||
.Dv DIOCWLABEL
|
||||
.Xr ioctl 2 ,
|
||||
which is done as needed by the
|
||||
.Xr disklabel
|
||||
program.
|
||||
.Pp
|
||||
A copy of the in-core label for a disk can be obtained with the
|
||||
.Dv DIOCGDINFO
|
||||
.Xr ioctl ;
|
||||
this works with a file descriptor for a block or character (``raw'') device
|
||||
for any partition of the disk.
|
||||
The in-core copy of the label is set by the
|
||||
.Dv DIOCSDINFO
|
||||
.Xr ioctl .
|
||||
The offset of a partition cannot generally be changed while it is open,
|
||||
nor can it be made smaller while it is open.
|
||||
One exception is that any change is allowed if no label was found
|
||||
on the disk, and the driver was able to construct only a skeletal label
|
||||
without partition information.
|
||||
Finally, the
|
||||
.Dv DIOCWDINFO
|
||||
.Xr ioctl
|
||||
operation sets the in-core label and then updates the on-disk label;
|
||||
there must be an existing label on the disk for this operation to succeed.
|
||||
Thus, the initial label for a disk or disk pack must be installed
|
||||
by writing to the raw disk.
|
||||
All of these operations are normally done using
|
||||
.Xr disklabel .
|
||||
.Pp
|
||||
The format of the disk label, as specified in
|
||||
.Aw Pa sys/disklabel.h ,
|
||||
is
|
||||
.Bd -literal
|
||||
/*
|
||||
* Disk description table, see disktab(5)
|
||||
*/
|
||||
#define DISKTAB "/etc/disktab"
|
||||
|
||||
/*
|
||||
* Each disk has a label which includes information about the hardware
|
||||
* disk geometry, filesystem partitions, and drive specific information.
|
||||
* The label is in block 0 or 1, possibly offset from the beginning
|
||||
* to leave room for a bootstrap, etc.
|
||||
*/
|
||||
|
||||
#ifndef LABELSECTOR
|
||||
#define LABELSECTOR 0 /* sector containing label */
|
||||
#endif
|
||||
|
||||
#ifndef LABELOFFSET
|
||||
#define LABELOFFSET 64 /* offset of label in sector */
|
||||
#endif
|
||||
|
||||
#define DISKMAGIC ((u_long) 0x82564557) /* The disk magic number */
|
||||
#ifndef MAXPARTITIONS
|
||||
#define MAXPARTITIONS 8
|
||||
#endif
|
||||
|
||||
#ifndef LOCORE
|
||||
struct disklabel {
|
||||
u_long d_magic; /* the magic number */
|
||||
short d_type; /* drive type */
|
||||
short d_subtype; /* controller/d_type specific */
|
||||
char d_typename[16]; /* type name, e.g. "eagle" */
|
||||
/*
|
||||
* d_packname contains the pack identifier and is returned when
|
||||
* the disklabel is read off the disk or in-core copy.
|
||||
* d_boot0 and d_boot1 are the (optional) names of the
|
||||
* primary (block 0) and secondary (block 1-15) bootstraps
|
||||
* as found in /usr/mdec. These are returned when using
|
||||
* getdiskbyname(3)
|
||||
to retrieve the values from /etc/disktab.
|
||||
*/
|
||||
#if defined(KERNEL) || defined(STANDALONE)
|
||||
char d_packname[16]; /* pack identifier */
|
||||
#else
|
||||
union {
|
||||
char un_d_packname[16]; /* pack identifier */
|
||||
struct {
|
||||
char *un_d_boot0; /* primary bootstrap name */
|
||||
char *un_d_boot1; /* secondary bootstrap name */
|
||||
} un_b;
|
||||
} d_un;
|
||||
|
||||
#define d_packname d_un.un_d_packname
|
||||
#define d_boot0 d_un.un_b.un_d_boot0
|
||||
#define d_boot1 d_un.un_b.un_d_boot1
|
||||
#endif /* ! KERNEL or STANDALONE */
|
||||
|
||||
/* disk geometry: */
|
||||
u_long d_secsize; /* # of bytes per sector */
|
||||
u_long d_nsectors; /* # of data sectors per track */
|
||||
u_long d_ntracks; /* # of tracks per cylinder */
|
||||
u_long d_ncylinders; /* # of data cylinders per unit */
|
||||
u_long d_secpercyl; /* # of data sectors per cylinder */
|
||||
u_long d_secperunit; /* # of data sectors per unit */
|
||||
/*
|
||||
* Spares (bad sector replacements) below
|
||||
* are not counted in d_nsectors or d_secpercyl.
|
||||
* Spare sectors are assumed to be physical sectors
|
||||
* which occupy space at the end of each track and/or cylinder.
|
||||
*/
|
||||
u_short d_sparespertrack; /* # of spare sectors per track */
|
||||
u_short d_sparespercyl; /* # of spare sectors per cylinder */
|
||||
/*
|
||||
* Alternate cylinders include maintenance, replacement,
|
||||
* configuration description areas, etc.
|
||||
*/
|
||||
u_long d_acylinders; /* # of alt. cylinders per unit */
|
||||
|
||||
/* hardware characteristics: */
|
||||
/*
|
||||
* d_interleave, d_trackskew and d_cylskew describe perturbations
|
||||
* in the media format used to compensate for a slow controller.
|
||||
* Interleave is physical sector interleave, set up by the formatter
|
||||
* or controller when formatting. When interleaving is in use,
|
||||
* logically adjacent sectors are not physically contiguous,
|
||||
* but instead are separated by some number of sectors.
|
||||
* It is specified as the ratio of physical sectors traversed
|
||||
* per logical sector. Thus an interleave of 1:1 implies contiguous
|
||||
* layout, while 2:1 implies that logical sector 0 is separated
|
||||
* by one sector from logical sector 1.
|
||||
* d_trackskew is the offset of sector 0 on track N
|
||||
* relative to sector 0 on track N-1 on the same cylinder.
|
||||
* Finally, d_cylskew is the offset of sector 0 on cylinder N
|
||||
* relative to sector 0 on cylinder N-1.
|
||||
*/
|
||||
u_short d_rpm; /* rotational speed */
|
||||
u_short d_interleave; /* hardware sector interleave */
|
||||
u_short d_trackskew; /* sector 0 skew, per track */
|
||||
u_short d_cylskew; /* sector 0 skew, per cylinder */
|
||||
u_long d_headswitch; /* head switch time, usec */
|
||||
u_long d_trkseek; /* track-to-track seek, usec */
|
||||
u_long d_flags; /* generic flags */
|
||||
#define NDDATA 5
|
||||
u_long d_drivedata[NDDATA]; /* drive-type specific information */
|
||||
#define NSPARE 5
|
||||
u_long d_spare[NSPARE]; /* reserved for future use */
|
||||
u_long d_magic2; /* the magic number (again) */
|
||||
u_short d_checksum; /* xor of data incl. partitions */
|
||||
|
||||
/* filesystem and partition information: */
|
||||
u_short d_npartitions; /* number of partitions in following */
|
||||
u_long d_bbsize; /* size of boot area at sn0, bytes */
|
||||
u_long d_sbsize; /* max size of fs superblock, bytes */
|
||||
struct partition { /* the partition table */
|
||||
u_long p_size; /* number of sectors in partition */
|
||||
u_long p_offset; /* starting sector */
|
||||
u_long p_fsize; /* filesystem basic fragment size */
|
||||
u_char p_fstype; /* filesystem type, see below */
|
||||
u_char p_frag; /* filesystem fragments per block */
|
||||
union {
|
||||
u_short cpg; /* UFS: FS cylinders per group */
|
||||
u_short sgs; /* LFS: FS segment shift */
|
||||
} __partition_u1;
|
||||
#define p_cpg __partition_u1.cpg
|
||||
#define p_sgs __partition_u1.sgs
|
||||
u_short p_cpg; /* filesystem cylinders per group */
|
||||
} d_partitions[MAXPARTITIONS]; /* actually may be more */
|
||||
};
|
||||
|
||||
/* d_type values: */
|
||||
#define DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
|
||||
#define DTYPE_MSCP 2 /* MSCP */
|
||||
#define DTYPE_DEC 3 /* other DEC (rk, rl) */
|
||||
#define DTYPE_SCSI 4 /* SCSI */
|
||||
#define DTYPE_ESDI 5 /* ESDI interface */
|
||||
#define DTYPE_ST506 6 /* ST506 etc. */
|
||||
#define DTYPE_HPIB 7 /* CS/80 on HP-IB */
|
||||
#define DTYPE_HPFL 8 /* HP Fiber-link */
|
||||
#define DTYPE_FLOPPY 10 /* floppy */
|
||||
|
||||
#ifdef DKTYPENAMES
|
||||
static char *dktypenames[] = {
|
||||
"unknown",
|
||||
"SMD",
|
||||
"MSCP",
|
||||
"old DEC",
|
||||
"SCSI",
|
||||
"ESDI",
|
||||
"ST506",
|
||||
"HP-IB",
|
||||
"HP-FL",
|
||||
"type 9",
|
||||
"floppy",
|
||||
0
|
||||
};
|
||||
#define DKMAXTYPES (sizeof(dktypenames) / sizeof(dktypenames[0]) - 1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Filesystem type and version.
|
||||
* Used to interpret other filesystem-specific
|
||||
* per-partition information.
|
||||
*/
|
||||
#define FS_UNUSED 0 /* unused */
|
||||
#define FS_SWAP 1 /* swap */
|
||||
#define FS_V6 2 /* Sixth Edition */
|
||||
#define FS_V7 3 /* Seventh Edition */
|
||||
#define FS_SYSV 4 /* System V */
|
||||
#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
|
||||
#define FS_V8 6 /* Eighth Edition, 4K blocks */
|
||||
#define FS_BSDFFS 7 /* 4.2BSD fast file system */
|
||||
#define FS_MSDOS 8 /* MSDOS file system */
|
||||
#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */
|
||||
#define FS_OTHER 10 /* in use, but unknown/unsupported */
|
||||
#define FS_HPFS 11 /* OS/2 high-performance file system */
|
||||
#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
|
||||
#define FS_BOOT 13 /* partition contains bootstrap */
|
||||
|
||||
#ifdef DKTYPENAMES
|
||||
static char *fstypenames[] = {
|
||||
"unused",
|
||||
"swap",
|
||||
"Version 6",
|
||||
"Version 7",
|
||||
"System V",
|
||||
"4.1BSD",
|
||||
"Eighth Edition",
|
||||
"4.2BSD",
|
||||
"MSDOS",
|
||||
"4.4LFS",
|
||||
"unknown",
|
||||
"HPFS",
|
||||
"ISO9660",
|
||||
"boot",
|
||||
0
|
||||
};
|
||||
#define FSMAXTYPES (sizeof(fstypenames) / sizeof(fstypenames[0]) - 1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* flags shared by various drives:
|
||||
*/
|
||||
#define D_REMOVABLE 0x01 /* removable media */
|
||||
#define D_ECC 0x02 /* supports ECC */
|
||||
#define D_BADSECT 0x04 /* supports bad sector forw. */
|
||||
#define D_RAMDISK 0x08 /* disk emulator */
|
||||
#define D_CHAIN 0x10 /* can do back-back transfers */
|
||||
|
||||
/*
|
||||
* Drive data for SMD.
|
||||
*/
|
||||
|
||||
#define d_smdflags d_drivedata[0]
|
||||
#define D_SSE 0x1 /* supports skip sectoring */
|
||||
#define d_mindist d_drivedata[1]
|
||||
#define d_maxdist d_drivedata[2]
|
||||
#define d_sdist d_drivedata[3]
|
||||
|
||||
/*
|
||||
* Drive data for ST506.
|
||||
*/
|
||||
#define d_precompcyl d_drivedata[0]
|
||||
#define d_gap3 d_drivedata[1] /* used only when formatting */
|
||||
|
||||
/*
|
||||
* Drive data for SCSI.
|
||||
*/
|
||||
#define d_blind d_drivedata[0]
|
||||
|
||||
#ifndef LOCORE
|
||||
/*
|
||||
* Structure used to perform a format
|
||||
* or other raw operation, returning data
|
||||
* and/or register values.
|
||||
* Register identification and format
|
||||
* are device- and driver-dependent.
|
||||
*/
|
||||
struct format_op {
|
||||
char *df_buf;
|
||||
int df_count; /* value-result */
|
||||
daddr_t df_startblk;
|
||||
int df_reg[8]; /* result */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure used internally to retrieve
|
||||
* information about a partition on a disk.
|
||||
*/
|
||||
struct partinfo {
|
||||
struct disklabel *disklab;
|
||||
struct partition *part;
|
||||
};
|
||||
|
||||
/*
|
||||
* Disk-specific ioctls.
|
||||
*/
|
||||
/* get and set disklabel; DIOCGPART used internally */
|
||||
#define DIOCGDINFO _IOR('d', 101, struct disklabel) /* get */
|
||||
#define DIOCSDINFO _IOW('d', 102, struct disklabel) /* set */
|
||||
#define DIOCWDINFO _IOW('d', 103, struct disklabel) /* set, update disk */
|
||||
#define DIOCGPART _IOW('d', 104, struct partinfo) /* get partition */
|
||||
|
||||
/* do format operation, read or write */
|
||||
#define DIOCRFORMAT _IOWR('d', 105, struct format_op)
|
||||
#define DIOCWFORMAT _IOWR('d', 106, struct format_op)
|
||||
|
||||
#define DIOCSSTEP _IOW('d', 107, int) /* set step rate */
|
||||
#define DIOCSRETRIES _IOW('d', 108, int) /* set # of retries */
|
||||
#define DIOCWLABEL _IOW('d', 109, int) /* write en/disable label */
|
||||
|
||||
#define DIOCSBAD _IOW('d', 110, struct dkbad) /* set kernel dkbad */
|
||||
|
||||
#endif LOCORE
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr disktab 5 ,
|
||||
.Xr disklabel 8
|
||||
.Sh HISTORY
|
||||
53
sbin/bsdlabel/dkcksum.c
Normal file
53
sbin/bsdlabel/dkcksum.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dkcksum.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/disklabel.h>
|
||||
|
||||
u_short
|
||||
dkcksum(lp)
|
||||
register struct disklabel *lp;
|
||||
{
|
||||
register u_short *start, *end;
|
||||
register u_short sum = 0;
|
||||
|
||||
start = (u_short *)lp;
|
||||
end = (u_short *)&lp->d_partitions[lp->d_npartitions];
|
||||
while (start < end)
|
||||
sum ^= *start++;
|
||||
return (sum);
|
||||
}
|
||||
40
sbin/bsdlabel/pathnames.h
Normal file
40
sbin/bsdlabel/pathnames.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_BOOTDIR "/usr/mdec"
|
||||
#undef _PATH_TMP
|
||||
#define _PATH_TMP "/tmp/EdDk.aXXXXXX"
|
||||
6
sbin/clri/Makefile
Normal file
6
sbin/clri/Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= clri
|
||||
MAN8= clri.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
79
sbin/clri/clri.8
Normal file
79
sbin/clri/clri.8
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
.\" Copyright (c) 1980, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)clri.8 8.2 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.Dd April 19, 1994
|
||||
.Dt CLRI 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm clri
|
||||
.Nd clear an inode
|
||||
.Sh SYNOPSIS
|
||||
.Nm clri
|
||||
.Ar special_device inode_number ...
|
||||
.Sh DESCRIPTION
|
||||
.Bf -symbolic
|
||||
.Nm Clri
|
||||
is obsoleted for normal file system repair work by
|
||||
.Xr fsck 8 .
|
||||
.Ef
|
||||
.Pp
|
||||
.Nm Clri
|
||||
zeros out the inodes with the specified inode number(s)
|
||||
on the filesystem residing on the given
|
||||
.Ar special_device .
|
||||
The
|
||||
.Xr fsck 8
|
||||
utility is usually run after
|
||||
.Nm clri
|
||||
to reclaim the zero'ed inode(s) and the
|
||||
blocks previously claimed by those inode(s).
|
||||
Both read and write permission are required on the specified
|
||||
.Ar special_device .
|
||||
.Pp
|
||||
The primary purpose of this routine
|
||||
is to remove a file which
|
||||
for some reason is not being properly handled by
|
||||
.Xr fsck 8 .
|
||||
Once removed,
|
||||
it is anticipated that
|
||||
.Xr fsck 8
|
||||
will be able to clean up the resulting mess.
|
||||
.Sh "SEE ALSO"
|
||||
.Xr fsck 8 ,
|
||||
.Xr fsdb 8 ,
|
||||
.Xr icheck 8 ,
|
||||
.Xr ncheck 8
|
||||
.Sh BUGS
|
||||
If the file is open, the work of
|
||||
.Nm clri
|
||||
will be lost when the inode is written back to disk from the inode cache.
|
||||
140
sbin/clri/clri.c
Normal file
140
sbin/clri/clri.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Rich $alz of BBN Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1990, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)clri.c 8.2 (Berkeley) 9/23/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register struct fs *sbp;
|
||||
register struct dinode *ip;
|
||||
register int fd;
|
||||
struct dinode ibuf[MAXBSIZE / sizeof (struct dinode)];
|
||||
long generation, bsize;
|
||||
off_t offset;
|
||||
int inonum;
|
||||
char *fs, sblock[SBSIZE];
|
||||
|
||||
if (argc < 3) {
|
||||
(void)fprintf(stderr, "usage: clri filesystem inode ...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fs = *++argv;
|
||||
|
||||
/* get the superblock. */
|
||||
if ((fd = open(fs, O_RDWR, 0)) < 0)
|
||||
err(1, "%s", fs);
|
||||
if (lseek(fd, (off_t)(SBLOCK * DEV_BSIZE), SEEK_SET) < 0)
|
||||
err(1, "%s", fs);
|
||||
if (read(fd, sblock, sizeof(sblock)) != sizeof(sblock)) {
|
||||
(void)fprintf(stderr,
|
||||
"clri: %s: can't read the superblock.\n", fs);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sbp = (struct fs *)sblock;
|
||||
if (sbp->fs_magic != FS_MAGIC) {
|
||||
(void)fprintf(stderr,
|
||||
"clri: %s: superblock magic number 0x%x, not 0x%x.\n",
|
||||
fs, sbp->fs_magic, FS_MAGIC);
|
||||
exit(1);
|
||||
}
|
||||
bsize = sbp->fs_bsize;
|
||||
|
||||
/* remaining arguments are inode numbers. */
|
||||
while (*++argv) {
|
||||
/* get the inode number. */
|
||||
if ((inonum = atoi(*argv)) <= 0) {
|
||||
(void)fprintf(stderr,
|
||||
"clri: %s is not a valid inode number.\n", *argv);
|
||||
exit(1);
|
||||
}
|
||||
(void)printf("clearing %d\n", inonum);
|
||||
|
||||
/* read in the appropriate block. */
|
||||
offset = ino_to_fsba(sbp, inonum); /* inode to fs blk */
|
||||
offset = fsbtodb(sbp, offset); /* fs blk disk blk */
|
||||
offset *= DEV_BSIZE; /* disk blk to bytes */
|
||||
|
||||
/* seek and read the block */
|
||||
if (lseek(fd, offset, SEEK_SET) < 0)
|
||||
err(1, "%s", fs);
|
||||
if (read(fd, ibuf, bsize) != bsize)
|
||||
err(1, "%s", fs);
|
||||
|
||||
/* get the inode within the block. */
|
||||
ip = &ibuf[ino_to_fsbo(sbp, inonum)];
|
||||
|
||||
/* clear the inode, and bump the generation count. */
|
||||
generation = ip->di_gen + 1;
|
||||
memset(ip, 0, sizeof(*ip));
|
||||
ip->di_gen = generation;
|
||||
|
||||
/* backup and write the block */
|
||||
if (lseek(fd, (off_t)-bsize, SEEK_CUR) < 0)
|
||||
err(1, "%s", fs);
|
||||
if (write(fd, ibuf, bsize) != bsize)
|
||||
err(1, "%s", fs);
|
||||
(void)fsync(fd);
|
||||
}
|
||||
(void)close(fd);
|
||||
exit(0);
|
||||
}
|
||||
14
sbin/disklabel/Makefile
Normal file
14
sbin/disklabel/Makefile
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# @(#)Makefile 8.2 (Berkeley) 3/17/94
|
||||
|
||||
PROG= disklabel
|
||||
SRCS= disklabel.c dkcksum.c
|
||||
MAN8= disklabel.0
|
||||
CLEANFILES=disklabel.5.0
|
||||
|
||||
all: ${PROG} disklabel.5.0 ${MAN8}
|
||||
|
||||
beforeinstall:
|
||||
install -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} disklabel.5.0 \
|
||||
${DESTDIR}${MANDIR}5/disklabel.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
384
sbin/disklabel/disklabel.5.5
Normal file
384
sbin/disklabel/disklabel.5.5
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
.\" Copyright (c) 1987, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" Symmetric Computer Systems.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)disklabel.5.5 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.Dd June 5, 1993
|
||||
.Dt DISKLABEL 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm disklabel
|
||||
.Nd disk pack label
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <sys/disklabel.h>
|
||||
.Sh DESCRIPTION
|
||||
Each disk or disk pack on a system may contain a disk label
|
||||
which provides detailed information
|
||||
about the geometry of the disk and the partitions into which the disk
|
||||
is divided.
|
||||
It should be initialized when the disk is formatted,
|
||||
and may be changed later with the
|
||||
.Xr disklabel 8
|
||||
program.
|
||||
This information is used by the system disk driver and by the bootstrap
|
||||
program to determine how to program the drive
|
||||
and where to find the filesystems on the disk partitions.
|
||||
Additional information is used by the filesystem in order
|
||||
to use the disk most efficiently and to locate important filesystem information.
|
||||
The description of each partition contains an identifier for the partition
|
||||
type (standard filesystem, swap area, etc.).
|
||||
The filesystem updates the in-core copy of the label if it contains
|
||||
incomplete information about the filesystem.
|
||||
.Pp
|
||||
The label is located in sector number
|
||||
.Dv LABELSECTOR
|
||||
of the drive, usually sector 0 where it may be found
|
||||
without any information about the disk geometry.
|
||||
It is at an offset
|
||||
.Dv LABELOFFSET
|
||||
from the beginning of the sector, to allow room for the initial bootstrap.
|
||||
The disk sector containing the label is normally made read-only
|
||||
so that it is not accidentally overwritten by pack-to-pack copies
|
||||
or swap operations;
|
||||
the
|
||||
.Dv DIOCWLABEL
|
||||
.Xr ioctl 2 ,
|
||||
which is done as needed by the
|
||||
.Xr disklabel
|
||||
program.
|
||||
.Pp
|
||||
A copy of the in-core label for a disk can be obtained with the
|
||||
.Dv DIOCGDINFO
|
||||
.Xr ioctl ;
|
||||
this works with a file descriptor for a block or character (``raw'') device
|
||||
for any partition of the disk.
|
||||
The in-core copy of the label is set by the
|
||||
.Dv DIOCSDINFO
|
||||
.Xr ioctl .
|
||||
The offset of a partition cannot generally be changed while it is open,
|
||||
nor can it be made smaller while it is open.
|
||||
One exception is that any change is allowed if no label was found
|
||||
on the disk, and the driver was able to construct only a skeletal label
|
||||
without partition information.
|
||||
Finally, the
|
||||
.Dv DIOCWDINFO
|
||||
.Xr ioctl
|
||||
operation sets the in-core label and then updates the on-disk label;
|
||||
there must be an existing label on the disk for this operation to succeed.
|
||||
Thus, the initial label for a disk or disk pack must be installed
|
||||
by writing to the raw disk.
|
||||
All of these operations are normally done using
|
||||
.Xr disklabel .
|
||||
.Pp
|
||||
The format of the disk label, as specified in
|
||||
.Aw Pa sys/disklabel.h ,
|
||||
is
|
||||
.Bd -literal
|
||||
/*
|
||||
* Disk description table, see disktab(5)
|
||||
*/
|
||||
#define DISKTAB "/etc/disktab"
|
||||
|
||||
/*
|
||||
* Each disk has a label which includes information about the hardware
|
||||
* disk geometry, filesystem partitions, and drive specific information.
|
||||
* The label is in block 0 or 1, possibly offset from the beginning
|
||||
* to leave room for a bootstrap, etc.
|
||||
*/
|
||||
|
||||
#ifndef LABELSECTOR
|
||||
#define LABELSECTOR 0 /* sector containing label */
|
||||
#endif
|
||||
|
||||
#ifndef LABELOFFSET
|
||||
#define LABELOFFSET 64 /* offset of label in sector */
|
||||
#endif
|
||||
|
||||
#define DISKMAGIC ((u_long) 0x82564557) /* The disk magic number */
|
||||
#ifndef MAXPARTITIONS
|
||||
#define MAXPARTITIONS 8
|
||||
#endif
|
||||
|
||||
#ifndef LOCORE
|
||||
struct disklabel {
|
||||
u_long d_magic; /* the magic number */
|
||||
short d_type; /* drive type */
|
||||
short d_subtype; /* controller/d_type specific */
|
||||
char d_typename[16]; /* type name, e.g. "eagle" */
|
||||
/*
|
||||
* d_packname contains the pack identifier and is returned when
|
||||
* the disklabel is read off the disk or in-core copy.
|
||||
* d_boot0 and d_boot1 are the (optional) names of the
|
||||
* primary (block 0) and secondary (block 1-15) bootstraps
|
||||
* as found in /usr/mdec. These are returned when using
|
||||
* getdiskbyname(3)
|
||||
to retrieve the values from /etc/disktab.
|
||||
*/
|
||||
#if defined(KERNEL) || defined(STANDALONE)
|
||||
char d_packname[16]; /* pack identifier */
|
||||
#else
|
||||
union {
|
||||
char un_d_packname[16]; /* pack identifier */
|
||||
struct {
|
||||
char *un_d_boot0; /* primary bootstrap name */
|
||||
char *un_d_boot1; /* secondary bootstrap name */
|
||||
} un_b;
|
||||
} d_un;
|
||||
|
||||
#define d_packname d_un.un_d_packname
|
||||
#define d_boot0 d_un.un_b.un_d_boot0
|
||||
#define d_boot1 d_un.un_b.un_d_boot1
|
||||
#endif /* ! KERNEL or STANDALONE */
|
||||
|
||||
/* disk geometry: */
|
||||
u_long d_secsize; /* # of bytes per sector */
|
||||
u_long d_nsectors; /* # of data sectors per track */
|
||||
u_long d_ntracks; /* # of tracks per cylinder */
|
||||
u_long d_ncylinders; /* # of data cylinders per unit */
|
||||
u_long d_secpercyl; /* # of data sectors per cylinder */
|
||||
u_long d_secperunit; /* # of data sectors per unit */
|
||||
/*
|
||||
* Spares (bad sector replacements) below
|
||||
* are not counted in d_nsectors or d_secpercyl.
|
||||
* Spare sectors are assumed to be physical sectors
|
||||
* which occupy space at the end of each track and/or cylinder.
|
||||
*/
|
||||
u_short d_sparespertrack; /* # of spare sectors per track */
|
||||
u_short d_sparespercyl; /* # of spare sectors per cylinder */
|
||||
/*
|
||||
* Alternate cylinders include maintenance, replacement,
|
||||
* configuration description areas, etc.
|
||||
*/
|
||||
u_long d_acylinders; /* # of alt. cylinders per unit */
|
||||
|
||||
/* hardware characteristics: */
|
||||
/*
|
||||
* d_interleave, d_trackskew and d_cylskew describe perturbations
|
||||
* in the media format used to compensate for a slow controller.
|
||||
* Interleave is physical sector interleave, set up by the formatter
|
||||
* or controller when formatting. When interleaving is in use,
|
||||
* logically adjacent sectors are not physically contiguous,
|
||||
* but instead are separated by some number of sectors.
|
||||
* It is specified as the ratio of physical sectors traversed
|
||||
* per logical sector. Thus an interleave of 1:1 implies contiguous
|
||||
* layout, while 2:1 implies that logical sector 0 is separated
|
||||
* by one sector from logical sector 1.
|
||||
* d_trackskew is the offset of sector 0 on track N
|
||||
* relative to sector 0 on track N-1 on the same cylinder.
|
||||
* Finally, d_cylskew is the offset of sector 0 on cylinder N
|
||||
* relative to sector 0 on cylinder N-1.
|
||||
*/
|
||||
u_short d_rpm; /* rotational speed */
|
||||
u_short d_interleave; /* hardware sector interleave */
|
||||
u_short d_trackskew; /* sector 0 skew, per track */
|
||||
u_short d_cylskew; /* sector 0 skew, per cylinder */
|
||||
u_long d_headswitch; /* head switch time, usec */
|
||||
u_long d_trkseek; /* track-to-track seek, usec */
|
||||
u_long d_flags; /* generic flags */
|
||||
#define NDDATA 5
|
||||
u_long d_drivedata[NDDATA]; /* drive-type specific information */
|
||||
#define NSPARE 5
|
||||
u_long d_spare[NSPARE]; /* reserved for future use */
|
||||
u_long d_magic2; /* the magic number (again) */
|
||||
u_short d_checksum; /* xor of data incl. partitions */
|
||||
|
||||
/* filesystem and partition information: */
|
||||
u_short d_npartitions; /* number of partitions in following */
|
||||
u_long d_bbsize; /* size of boot area at sn0, bytes */
|
||||
u_long d_sbsize; /* max size of fs superblock, bytes */
|
||||
struct partition { /* the partition table */
|
||||
u_long p_size; /* number of sectors in partition */
|
||||
u_long p_offset; /* starting sector */
|
||||
u_long p_fsize; /* filesystem basic fragment size */
|
||||
u_char p_fstype; /* filesystem type, see below */
|
||||
u_char p_frag; /* filesystem fragments per block */
|
||||
union {
|
||||
u_short cpg; /* UFS: FS cylinders per group */
|
||||
u_short sgs; /* LFS: FS segment shift */
|
||||
} __partition_u1;
|
||||
#define p_cpg __partition_u1.cpg
|
||||
#define p_sgs __partition_u1.sgs
|
||||
u_short p_cpg; /* filesystem cylinders per group */
|
||||
} d_partitions[MAXPARTITIONS]; /* actually may be more */
|
||||
};
|
||||
|
||||
/* d_type values: */
|
||||
#define DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
|
||||
#define DTYPE_MSCP 2 /* MSCP */
|
||||
#define DTYPE_DEC 3 /* other DEC (rk, rl) */
|
||||
#define DTYPE_SCSI 4 /* SCSI */
|
||||
#define DTYPE_ESDI 5 /* ESDI interface */
|
||||
#define DTYPE_ST506 6 /* ST506 etc. */
|
||||
#define DTYPE_HPIB 7 /* CS/80 on HP-IB */
|
||||
#define DTYPE_HPFL 8 /* HP Fiber-link */
|
||||
#define DTYPE_FLOPPY 10 /* floppy */
|
||||
|
||||
#ifdef DKTYPENAMES
|
||||
static char *dktypenames[] = {
|
||||
"unknown",
|
||||
"SMD",
|
||||
"MSCP",
|
||||
"old DEC",
|
||||
"SCSI",
|
||||
"ESDI",
|
||||
"ST506",
|
||||
"HP-IB",
|
||||
"HP-FL",
|
||||
"type 9",
|
||||
"floppy",
|
||||
0
|
||||
};
|
||||
#define DKMAXTYPES (sizeof(dktypenames) / sizeof(dktypenames[0]) - 1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Filesystem type and version.
|
||||
* Used to interpret other filesystem-specific
|
||||
* per-partition information.
|
||||
*/
|
||||
#define FS_UNUSED 0 /* unused */
|
||||
#define FS_SWAP 1 /* swap */
|
||||
#define FS_V6 2 /* Sixth Edition */
|
||||
#define FS_V7 3 /* Seventh Edition */
|
||||
#define FS_SYSV 4 /* System V */
|
||||
#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
|
||||
#define FS_V8 6 /* Eighth Edition, 4K blocks */
|
||||
#define FS_BSDFFS 7 /* 4.2BSD fast file system */
|
||||
#define FS_MSDOS 8 /* MSDOS file system */
|
||||
#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */
|
||||
#define FS_OTHER 10 /* in use, but unknown/unsupported */
|
||||
#define FS_HPFS 11 /* OS/2 high-performance file system */
|
||||
#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
|
||||
#define FS_BOOT 13 /* partition contains bootstrap */
|
||||
|
||||
#ifdef DKTYPENAMES
|
||||
static char *fstypenames[] = {
|
||||
"unused",
|
||||
"swap",
|
||||
"Version 6",
|
||||
"Version 7",
|
||||
"System V",
|
||||
"4.1BSD",
|
||||
"Eighth Edition",
|
||||
"4.2BSD",
|
||||
"MSDOS",
|
||||
"4.4LFS",
|
||||
"unknown",
|
||||
"HPFS",
|
||||
"ISO9660",
|
||||
"boot",
|
||||
0
|
||||
};
|
||||
#define FSMAXTYPES (sizeof(fstypenames) / sizeof(fstypenames[0]) - 1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* flags shared by various drives:
|
||||
*/
|
||||
#define D_REMOVABLE 0x01 /* removable media */
|
||||
#define D_ECC 0x02 /* supports ECC */
|
||||
#define D_BADSECT 0x04 /* supports bad sector forw. */
|
||||
#define D_RAMDISK 0x08 /* disk emulator */
|
||||
#define D_CHAIN 0x10 /* can do back-back transfers */
|
||||
|
||||
/*
|
||||
* Drive data for SMD.
|
||||
*/
|
||||
|
||||
#define d_smdflags d_drivedata[0]
|
||||
#define D_SSE 0x1 /* supports skip sectoring */
|
||||
#define d_mindist d_drivedata[1]
|
||||
#define d_maxdist d_drivedata[2]
|
||||
#define d_sdist d_drivedata[3]
|
||||
|
||||
/*
|
||||
* Drive data for ST506.
|
||||
*/
|
||||
#define d_precompcyl d_drivedata[0]
|
||||
#define d_gap3 d_drivedata[1] /* used only when formatting */
|
||||
|
||||
/*
|
||||
* Drive data for SCSI.
|
||||
*/
|
||||
#define d_blind d_drivedata[0]
|
||||
|
||||
#ifndef LOCORE
|
||||
/*
|
||||
* Structure used to perform a format
|
||||
* or other raw operation, returning data
|
||||
* and/or register values.
|
||||
* Register identification and format
|
||||
* are device- and driver-dependent.
|
||||
*/
|
||||
struct format_op {
|
||||
char *df_buf;
|
||||
int df_count; /* value-result */
|
||||
daddr_t df_startblk;
|
||||
int df_reg[8]; /* result */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure used internally to retrieve
|
||||
* information about a partition on a disk.
|
||||
*/
|
||||
struct partinfo {
|
||||
struct disklabel *disklab;
|
||||
struct partition *part;
|
||||
};
|
||||
|
||||
/*
|
||||
* Disk-specific ioctls.
|
||||
*/
|
||||
/* get and set disklabel; DIOCGPART used internally */
|
||||
#define DIOCGDINFO _IOR('d', 101, struct disklabel) /* get */
|
||||
#define DIOCSDINFO _IOW('d', 102, struct disklabel) /* set */
|
||||
#define DIOCWDINFO _IOW('d', 103, struct disklabel) /* set, update disk */
|
||||
#define DIOCGPART _IOW('d', 104, struct partinfo) /* get partition */
|
||||
|
||||
/* do format operation, read or write */
|
||||
#define DIOCRFORMAT _IOWR('d', 105, struct format_op)
|
||||
#define DIOCWFORMAT _IOWR('d', 106, struct format_op)
|
||||
|
||||
#define DIOCSSTEP _IOW('d', 107, int) /* set step rate */
|
||||
#define DIOCSRETRIES _IOW('d', 108, int) /* set # of retries */
|
||||
#define DIOCWLABEL _IOW('d', 109, int) /* write en/disable label */
|
||||
|
||||
#define DIOCSBAD _IOW('d', 110, struct dkbad) /* set kernel dkbad */
|
||||
|
||||
#endif LOCORE
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr disktab 5 ,
|
||||
.Xr disklabel 8
|
||||
.Sh HISTORY
|
||||
343
sbin/disklabel/disklabel.8
Normal file
343
sbin/disklabel/disklabel.8
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
.\" Copyright (c) 1987, 1988, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" Symmetric Computer Systems.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)disklabel.8 8.2 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.Dd "April 19, 1994"
|
||||
.Dt DISKLABEL 8
|
||||
.Os BSD 4.2
|
||||
.Sh NAME
|
||||
.Nm disklabel
|
||||
.Nd read and write disk pack label
|
||||
.Sh SYNOPSIS
|
||||
.Nm disklabel
|
||||
.Op Fl r
|
||||
.Ar disk
|
||||
.Nm disklabel
|
||||
.Fl w
|
||||
.Op Fl r
|
||||
.Ar disk Ar disktype
|
||||
.Oo Ar packid Oc
|
||||
.Nm disklabel
|
||||
.Fl e
|
||||
.Op Fl r
|
||||
.Ar disk
|
||||
.Nm disklabel
|
||||
.Fl R
|
||||
.Op Fl r
|
||||
.Ar disk Ar protofile
|
||||
.Nm disklabel
|
||||
.Op Fl NW
|
||||
.Ar disk
|
||||
.sp
|
||||
.Nm disklabel
|
||||
.Fl B
|
||||
.Oo
|
||||
.Fl b Ar boot1
|
||||
.Op Fl s Ar boot2
|
||||
.Oc
|
||||
.Ar disk
|
||||
.Oo Ar disktype Oc
|
||||
.Nm disklabel
|
||||
.Fl w
|
||||
.Fl B
|
||||
.Oo
|
||||
.Fl b Ar boot1
|
||||
.Op Fl s Ar boot2
|
||||
.Oc
|
||||
.Ar disk Ar disktype
|
||||
.Oo Ar packid Oc
|
||||
.Nm disklabel
|
||||
.Fl R
|
||||
.Fl B
|
||||
.Oo
|
||||
.Fl b Ar boot1
|
||||
.Op Fl s Ar boot2
|
||||
.Oc
|
||||
.Ar disk Ar protofile
|
||||
.Oo Ar disktype Oc
|
||||
.Sh DESCRIPTION
|
||||
.Nm Disklabel
|
||||
can be used to install, examine or modify the label on a disk drive or pack.
|
||||
When writing the label, it can be used
|
||||
to change the drive identification,
|
||||
the disk partitions on the drive,
|
||||
or to replace a damaged label.
|
||||
On some systems,
|
||||
.Nm disklabel
|
||||
can be used to install bootstrap code as well.
|
||||
There are several forms of the command that read (display), install or edit
|
||||
the label on a disk.
|
||||
Each form has an additional option,
|
||||
.Fl r ,
|
||||
which causes the label to be read from or written to the disk directly,
|
||||
rather than going through the system's in-core copy of the label.
|
||||
This option may allow a label to be installed on a disk
|
||||
without kernel support for a label, such as when labels are first installed
|
||||
on a system; it must be used when first installing a label on a disk.
|
||||
The specific effect of
|
||||
.Fl r
|
||||
is described under each command.
|
||||
The read and install forms also support the
|
||||
.Fl B
|
||||
option to install bootstrap code.
|
||||
These variants are described later.
|
||||
.Pp
|
||||
The first form of the command (read) is used to examine the label on the named
|
||||
disk drive (e.g. sd0 or /dev/rsd0c).
|
||||
It will display all of the parameters associated with the drive
|
||||
and its partition layout.
|
||||
Unless the
|
||||
.Fl r
|
||||
flag is given,
|
||||
the kernel's in-core copy of the label is displayed;
|
||||
if the disk has no label, or the partition types on the disk are incorrect,
|
||||
the kernel may have constructed or modified the label.
|
||||
If the
|
||||
.Fl r
|
||||
flag is given, the label from the raw disk will be displayed rather
|
||||
than the in-core label.
|
||||
.Pp
|
||||
The second form of the command, with the
|
||||
.Fl w
|
||||
flag, is used to write a standard label on the designated drive.
|
||||
The required arguments to
|
||||
.Nm disklabel
|
||||
are the drive to be labelled (e.g. sd0), and
|
||||
the drive type as described in the
|
||||
.Xr disktab 5
|
||||
file.
|
||||
The drive parameters and partitions are taken from that file.
|
||||
If different disks of the same physical type are to have different
|
||||
partitions, it will be necessary to have separate disktab entries
|
||||
describing each, or to edit the label after installation as described below.
|
||||
The optional argument is a pack identification string,
|
||||
up to 16 characters long.
|
||||
The pack id must be quoted if it contains blanks.
|
||||
If the
|
||||
.Fl r
|
||||
flag is given, the disk sectors containing the label and bootstrap
|
||||
will be written directly.
|
||||
A side-effect of this is that any existing bootstrap code will be overwritten
|
||||
and the disk rendered unbootable.
|
||||
If
|
||||
.Fl r
|
||||
is not specified,
|
||||
the existing label will be updated via the in-core copy and any bootstrap
|
||||
code will be unaffected.
|
||||
If the disk does not already have a label, the
|
||||
.Fl r
|
||||
flag must be used.
|
||||
In either case, the kernel's in-core label is replaced.
|
||||
.Pp
|
||||
An existing disk label may be edited by using the
|
||||
.Fl e
|
||||
flag.
|
||||
The label is read from the in-core kernel copy,
|
||||
or directly from the disk if the
|
||||
.Fl r
|
||||
flag is also given.
|
||||
The label is formatted and then supplied to an editor for changes.
|
||||
If no editor is specified in an
|
||||
.Ev EDITOR
|
||||
environment variable,
|
||||
.Xr vi 1
|
||||
is used.
|
||||
When the editor terminates, the formatted label is reread
|
||||
and used to rewrite the disk label.
|
||||
Existing bootstrap code is unchanged regardless of whether
|
||||
.Fl r
|
||||
was specified.
|
||||
.Pp
|
||||
With the
|
||||
.Fl R
|
||||
flag,
|
||||
.Nm disklabel
|
||||
is capable of restoring a disk label that was formatted
|
||||
in a prior operation and saved in an ascii file.
|
||||
The prototype file used to create the label should be in the same format
|
||||
as that produced when reading or editing a label.
|
||||
Comments are delimited by
|
||||
.Ar \&#
|
||||
and newline.
|
||||
As with
|
||||
.Fl w ,
|
||||
any existing bootstrap code will be clobbered if
|
||||
.Fl r
|
||||
is specified and will be unaffected otherwise.
|
||||
.Pp
|
||||
The
|
||||
.Fl NW
|
||||
flags for
|
||||
.Nm disklabel
|
||||
explicitly disallow and
|
||||
allow, respectively, writing of the pack label area on the selected disk.
|
||||
.Pp
|
||||
The final three forms of
|
||||
.Nm disklabel
|
||||
are used to install boostrap code on machines where the bootstrap is part
|
||||
of the label.
|
||||
The bootstrap code is comprised of one or two boot programs depending on
|
||||
the machine.
|
||||
The
|
||||
.Fl B
|
||||
option is used to denote that bootstrap code is to be installed.
|
||||
The
|
||||
.Fl r
|
||||
flag is implied by
|
||||
.Fl B
|
||||
and never needs to be specified.
|
||||
The name of the boot program(s) to be installed can be selected in a
|
||||
variety of ways.
|
||||
First, the names can be specified explicitly via the
|
||||
.Fl b
|
||||
and
|
||||
.Fl s
|
||||
flags.
|
||||
On machines with only a single level of boot program,
|
||||
.Fl b
|
||||
is the name of that program.
|
||||
For machines with a two-level bootstrap,
|
||||
.Fl b
|
||||
indicates the primary boot program and
|
||||
.Fl s
|
||||
the secondary boot program.
|
||||
If the names are not explicitly given, standard boot programs will be used.
|
||||
The boot programs are located in
|
||||
.Pa /usr/mdec .
|
||||
The names of the programs are taken from the ``b0'' and ``b1'' parameters
|
||||
of the
|
||||
.Xr disktab 5
|
||||
entry for the disk if
|
||||
.Ar disktype
|
||||
was given and its disktab entry exists and includes those parameters.
|
||||
Otherwise, boot program names are derived from the name of the disk.
|
||||
These names are of the form
|
||||
.Pa basename Ns boot
|
||||
for the primary (or only) bootstrap, and
|
||||
.Pf boot Pa basename
|
||||
for the secondary bootstrap;
|
||||
for example,
|
||||
.Pa /usr/mdec/sdboot
|
||||
and
|
||||
.Pa /usr/mdec/bootsd
|
||||
if the disk device is
|
||||
.Em sd0 .
|
||||
.Pp
|
||||
The first of the three boot-installation forms is used to install
|
||||
bootstrap code without changing the existing label.
|
||||
It is essentially a read command with respect to the disk label
|
||||
itself and all options are related to the specification of the boot
|
||||
program as described previously.
|
||||
The final two forms are analogous to the basic write and restore versions
|
||||
except that they will install bootstrap code in addition to a new label.
|
||||
.Sh FILES
|
||||
.Bl -tag -width Pa -compact
|
||||
.It Pa /etc/disktab
|
||||
.It Pa /usr/mdec/ Ns Em xx Ns boot
|
||||
.It Pa /usr/mdec/boot Ns Em xx
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Dl disklabel sd0
|
||||
.Pp
|
||||
Display the in-core label for sd0 as obtained via
|
||||
.Pa /dev/rsd0c .
|
||||
.Pp
|
||||
.Dl disklabel -w -r /dev/rsd0c sd2212 foo
|
||||
.Pp
|
||||
Create a label for sd0 based on information for ``sd2212'' found in
|
||||
.Pa /etc/disktab .
|
||||
Any existing bootstrap code will be clobbered.
|
||||
.Pp
|
||||
.Dl disklabel -e -r sd0
|
||||
.Pp
|
||||
Read the on-disk label for sd0, edit it and reinstall in-core as well
|
||||
as on-disk.
|
||||
Existing bootstrap code is unaffected.
|
||||
.Pp
|
||||
.Dl disklabel -R sd0 mylabel
|
||||
.Pp
|
||||
Restore the on-disk and in-core label for sd0 from information in
|
||||
.Pa mylabel .
|
||||
Existing bootstrap code is unaffected.
|
||||
.Pp
|
||||
.Dl disklabel -B sd0
|
||||
.Pp
|
||||
Install a new bootstrap on sd0.
|
||||
The boot code comes from
|
||||
.Pa /usr/mdec/sdboot
|
||||
and possibly
|
||||
.Pa /usr/mdec/bootsd .
|
||||
On-disk and in-core labels are unchanged.
|
||||
.Pp
|
||||
.Dl disklabel -w -B /dev/rsd0c -b newboot sd2212
|
||||
.Pp
|
||||
Install a new label and bootstrap.
|
||||
The label is derived from disktab information for ``sd2212'' and
|
||||
installed both in-core and on-disk.
|
||||
The bootstrap code comes from the file
|
||||
.Pa /usr/mdec/newboot .
|
||||
.Sh SEE ALSO
|
||||
.Xr disktab 5 ,
|
||||
.Xr disklabel 5
|
||||
.Sh DIAGNOSTICS
|
||||
The kernel device drivers will not allow the size of a disk partition
|
||||
to be decreased or the offset of a partition to be changed while it is open.
|
||||
Some device drivers create a label containing only a single large partition
|
||||
if a disk is unlabeled; thus, the label must be written to the ``a''
|
||||
partition of the disk while it is open.
|
||||
This sometimes requires the desired label to be set in two steps,
|
||||
the first one creating at least one other partition,
|
||||
and the second setting the label on the new partition
|
||||
while shrinking the ``a'' partition.
|
||||
.Pp
|
||||
On some machines the bootstrap code may not fit entirely in the area
|
||||
allocated for it by some filesystems.
|
||||
As a result, it may not be possible to have filesystems on some partitions
|
||||
of a ``bootable'' disk.
|
||||
When installing bootstrap code,
|
||||
.Nm disklabel
|
||||
checks for these cases.
|
||||
If the installed boot code would overlap a partition of type FS_UNUSED
|
||||
it is marked as type FS_BOOT.
|
||||
The
|
||||
.Xr newfs 8
|
||||
utility will disallow creation of filesystems on FS_BOOT partitions.
|
||||
Conversely, if a partition has a type other than FS_UNUSED or FS_BOOT,
|
||||
.Nm disklabel
|
||||
will not install bootstrap code that overlaps it.
|
||||
.Sh BUGS
|
||||
When a disk name is given without a full pathname,
|
||||
the constructed device name uses the ``a'' partition on the tahoe,
|
||||
the ``c'' partition on all others.
|
||||
1314
sbin/disklabel/disklabel.c
Normal file
1314
sbin/disklabel/disklabel.c
Normal file
File diff suppressed because it is too large
Load diff
53
sbin/disklabel/dkcksum.c
Normal file
53
sbin/disklabel/dkcksum.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dkcksum.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/disklabel.h>
|
||||
|
||||
u_short
|
||||
dkcksum(lp)
|
||||
register struct disklabel *lp;
|
||||
{
|
||||
register u_short *start, *end;
|
||||
register u_short sum = 0;
|
||||
|
||||
start = (u_short *)lp;
|
||||
end = (u_short *)&lp->d_partitions[lp->d_npartitions];
|
||||
while (start < end)
|
||||
sum ^= *start++;
|
||||
return (sum);
|
||||
}
|
||||
40
sbin/disklabel/pathnames.h
Normal file
40
sbin/disklabel/pathnames.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_BOOTDIR "/usr/mdec"
|
||||
#undef _PATH_TMP
|
||||
#define _PATH_TMP "/tmp/EdDk.aXXXXXX"
|
||||
10
sbin/dmesg/Makefile
Normal file
10
sbin/dmesg/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= dmesg
|
||||
MAN8= dmesg.0
|
||||
BINGRP= kmem
|
||||
BINMODE=2555
|
||||
LDADD= -lkvm
|
||||
DPADD= ${LIBKVM}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
63
sbin/dmesg/dmesg.8
Normal file
63
sbin/dmesg/dmesg.8
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
.\" Copyright (c) 1980, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)dmesg.8 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.Dd June 5, 1993
|
||||
.Dt DMESG 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm dmesg
|
||||
.Nd "display the system message buffer"
|
||||
.Sh SYNOPSIS
|
||||
.Nm dmesg
|
||||
.Op Fl M Ar core
|
||||
.Op Fl N Ar system
|
||||
.Sh DESCRIPTION
|
||||
.Nm Dmesg
|
||||
displays the contents of the system message buffer.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl M
|
||||
Extract values associated with the name list from the specified core
|
||||
instead of the default ``/dev/kmem''.
|
||||
.It Fl N
|
||||
Extract the name list from the specified system instead of the default
|
||||
``/vmunix''.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr syslogd 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.0 .
|
||||
157
sbin/dmesg/dmesg.c
Normal file
157
sbin/dmesg/dmesg.c
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1991, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dmesg.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/msgbuf.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <kvm.h>
|
||||
#include <limits.h>
|
||||
#include <nlist.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
|
||||
struct nlist nl[] = {
|
||||
#define X_MSGBUF 0
|
||||
{ "_msgbufp" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
void usage __P((void));
|
||||
|
||||
#define KREAD(addr, var) \
|
||||
kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register int ch, newl, skip;
|
||||
register char *p, *ep;
|
||||
struct msgbuf *bufp, cur;
|
||||
char *memf, *nlistf;
|
||||
kvm_t *kd;
|
||||
char buf[5];
|
||||
|
||||
memf = nlistf = NULL;
|
||||
while ((ch = getopt(argc, argv, "M:N:")) != EOF)
|
||||
switch(ch) {
|
||||
case 'M':
|
||||
memf = optarg;
|
||||
break;
|
||||
case 'N':
|
||||
nlistf = optarg;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/*
|
||||
* Discard setgid privileges if not the running kernel so that bad
|
||||
* guys can't print interesting stuff from kernel memory.
|
||||
*/
|
||||
if (memf != NULL || nlistf != NULL)
|
||||
setgid(getgid());
|
||||
|
||||
/* Read in kernel message buffer, do sanity checks. */
|
||||
if ((kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg")) == NULL)
|
||||
exit (1);
|
||||
if (kvm_nlist(kd, nl) == -1)
|
||||
errx(1, "kvm_nlist: %s", kvm_geterr(kd));
|
||||
if (nl[X_MSGBUF].n_type == 0)
|
||||
errx(1, "%s: msgbufp not found", nlistf ? nlistf : "namelist");
|
||||
if (KREAD(nl[X_MSGBUF].n_value, bufp) || KREAD((long)bufp, cur))
|
||||
errx(1, "kvm_read: %s", kvm_geterr(kd));
|
||||
kvm_close(kd);
|
||||
if (cur.msg_magic != MSG_MAGIC)
|
||||
errx(1, "magic number incorrect");
|
||||
if (cur.msg_bufx >= MSG_BSIZE)
|
||||
cur.msg_bufx = 0;
|
||||
|
||||
/*
|
||||
* The message buffer is circular; start at the read pointer, and
|
||||
* go to the write pointer - 1.
|
||||
*/
|
||||
p = cur.msg_bufc + cur.msg_bufx;
|
||||
ep = cur.msg_bufc + cur.msg_bufx - 1;
|
||||
for (newl = skip = 0; p != ep; ++p) {
|
||||
if (p == cur.msg_bufc + MSG_BSIZE)
|
||||
p = cur.msg_bufc;
|
||||
ch = *p;
|
||||
/* Skip "\n<.*>" syslog sequences. */
|
||||
if (skip) {
|
||||
if (ch == '>')
|
||||
newl = skip = 0;
|
||||
continue;
|
||||
}
|
||||
if (newl && ch == '<') {
|
||||
skip = 1;
|
||||
continue;
|
||||
}
|
||||
if (ch == '\0')
|
||||
continue;
|
||||
newl = ch == '\n';
|
||||
(void)vis(buf, ch, 0, 0);
|
||||
if (buf[1] == 0)
|
||||
(void)putchar(buf[0]);
|
||||
else
|
||||
(void)printf("%s", buf);
|
||||
}
|
||||
if (!newl)
|
||||
(void)putchar('\n');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage: dmesg [-M core] [-N system]\n");
|
||||
exit(1);
|
||||
}
|
||||
25
sbin/dump/Makefile
Normal file
25
sbin/dump/Makefile
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
# dump.h header file
|
||||
# itime.c reads /etc/dumpdates
|
||||
# main.c driver
|
||||
# optr.c operator interface
|
||||
# dumprmt.c handles remote tape via rmt(8)
|
||||
# tape.c handles the mag tape and opening/closing
|
||||
# traverse.c traverses the file system
|
||||
# unctime.c undo ctime
|
||||
#
|
||||
# DEBUG use local directory to find ddate and dumpdates
|
||||
# TDEBUG trace out the process forking
|
||||
|
||||
PROG= dump
|
||||
LINKS= ${BINDIR}/dump ${BINDIR}/rdump
|
||||
CFLAGS+=-DRDUMP
|
||||
SRCS= itime.c main.c optr.c dumprmt.c tape.c traverse.c unctime.c
|
||||
BINOWN= root
|
||||
BINGRP= tty
|
||||
BINMODE=6555
|
||||
MAN8= dump.0
|
||||
MLINKS+=dump.8 rdump.8
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
335
sbin/dump/dump.8
Normal file
335
sbin/dump/dump.8
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
.\" Copyright (c) 1980, 1991, 1993
|
||||
.\" Regents of the University of California.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)dump.8 8.1 (Berkeley) 6/16/93
|
||||
.\"
|
||||
.Dd June 16, 1993
|
||||
.Dt DUMP 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm dump
|
||||
.Nd filesystem backup
|
||||
.Sh SYNOPSIS
|
||||
.Nm dump
|
||||
.Op Cm 0123456789BbhfusTdWn Op Ar argument ...
|
||||
.Op Ar filesystem
|
||||
.Sh DESCRIPTION
|
||||
.Nm Dump
|
||||
examines files
|
||||
on a filesystem
|
||||
and determines which files
|
||||
need to be backed up. These files
|
||||
are copied to the given disk, tape or other
|
||||
storage medium for safe keeping (see the
|
||||
.Cm f
|
||||
option below for doing remote backups).
|
||||
A dump that is larger than the output medium is broken into
|
||||
multiple volumes.
|
||||
On most media the size is determined by writing until an
|
||||
end-of-media indication is returned.
|
||||
On media that cannot reliably return an end-of-media indication
|
||||
(such as some cartridge tape drives)
|
||||
each volume is of a fixed size;
|
||||
the actual size is determined by the tape size and density and/or
|
||||
block count options below.
|
||||
By default, the same output file name is used for each volume
|
||||
after prompting the operator to change media.
|
||||
.Pp
|
||||
The following options are supported by
|
||||
.Nm dump:
|
||||
.Bl -tag -width 4n
|
||||
.It Cm 0\-9
|
||||
Dump levels.
|
||||
A level 0, full backup,
|
||||
guarantees the entire file system is copied
|
||||
(but see also the
|
||||
.Cm h
|
||||
option below).
|
||||
A level number above 0,
|
||||
incremental backup,
|
||||
tells dump to
|
||||
copy all files new or modified since the
|
||||
last dump of the same or lower level. The default
|
||||
level is 9.
|
||||
.It Cm B Ar records
|
||||
The number of dump records per volume.
|
||||
This option overrides the calculation of tape size
|
||||
based on length and density.
|
||||
.It Cm b Ar blocksize
|
||||
The number of kilobytes per dump record.
|
||||
.It Cm h Ar level
|
||||
Honor the user
|
||||
.Dq nodump
|
||||
flag
|
||||
.Dp Dv UF_NODUMP
|
||||
only for dumps at or above the given
|
||||
.Ar level .
|
||||
The default honor level is 1,
|
||||
so that incremental backups omit such files
|
||||
but full backups retain them.
|
||||
.It Cm f Ar file
|
||||
Write the backup to
|
||||
.Ar file ;
|
||||
.Ar file
|
||||
may be a special device file
|
||||
like
|
||||
.Pa /dev/rmt12
|
||||
(a tape drive),
|
||||
.Pa /dev/rsd1c
|
||||
(a disk drive),
|
||||
an ordinary file,
|
||||
or
|
||||
.Ql Fl
|
||||
(the standard output).
|
||||
Multiple file names may be given as a single argument separated by commas.
|
||||
Each file will be used for one dump volume in the order listed;
|
||||
if the dump requires more volumes than the number of names given,
|
||||
the last file name will used for all remaining volumes after prompting
|
||||
for media changes.
|
||||
If the name of the file is of the form
|
||||
.Dq host:file ,
|
||||
or
|
||||
.Dq user@host:file ,
|
||||
.Nm dump
|
||||
writes to the named file on the remote host using
|
||||
.Xr rmt 8 .
|
||||
.It Cm d Ar density
|
||||
Set tape density to
|
||||
.Ar density .
|
||||
The default is 1600BPI.
|
||||
.It Cm n
|
||||
Whenever
|
||||
.Nm dump
|
||||
requires operator attention,
|
||||
notify all operators in the group
|
||||
.Dq operator
|
||||
by means similar to a
|
||||
.Xr wall 1 .
|
||||
.It Cm s Ar feet
|
||||
Attempt to calculate the amount of tape needed
|
||||
at a particular density.
|
||||
If this amount is exceeded,
|
||||
.Nm dump
|
||||
prompts for a new tape.
|
||||
It is recommended to be a bit conservative on this option.
|
||||
The default tape length is 2300 feet.
|
||||
.It Cm u
|
||||
Update the file
|
||||
.Pa /etc/dumpdates
|
||||
after a successful dump.
|
||||
The format of
|
||||
.Pa /etc/dumpdates
|
||||
is readable by people, consisting of one
|
||||
free format record per line:
|
||||
filesystem name,
|
||||
increment level
|
||||
and
|
||||
.Xr ctime 3
|
||||
format dump date.
|
||||
There may be only one entry per filesystem at each level.
|
||||
The file
|
||||
.Pa /etc/dumpdates
|
||||
may be edited to change any of the fields,
|
||||
if necessary.
|
||||
.It Cm T Ar date
|
||||
Use the specified date as the starting time for the dump
|
||||
instead of the time determined from looking in
|
||||
.Pa /etc/dumpdates .
|
||||
The format of date is the same as that of
|
||||
.Xr ctime 3 .
|
||||
This option is useful for automated dump scripts that wish to
|
||||
dump over a specific period of time.
|
||||
The
|
||||
.Cm T
|
||||
option is mutually exclusive from the
|
||||
.Cm u
|
||||
option.
|
||||
.It Cm W
|
||||
.Nm Dump
|
||||
tells the operator what file systems need to be dumped.
|
||||
This information is gleaned from the files
|
||||
.Pa /etc/dumpdates
|
||||
and
|
||||
.Pa /etc/fstab .
|
||||
The
|
||||
.Cm W
|
||||
option causes
|
||||
.Nm dump
|
||||
to print out, for each file system in
|
||||
.Pa /etc/dumpdates
|
||||
the most recent dump date and level,
|
||||
and highlights those file systems that should be dumped.
|
||||
If the
|
||||
.Cm W
|
||||
option is set, all other options are ignored, and
|
||||
.Nm dump
|
||||
exits immediately.
|
||||
.It Cm w
|
||||
Is like W, but prints only those filesystems which need to be dumped.
|
||||
.El
|
||||
.Pp
|
||||
.Nm Dump
|
||||
requires operator intervention on these conditions:
|
||||
end of tape,
|
||||
end of dump,
|
||||
tape write error,
|
||||
tape open error or
|
||||
disk read error (if there are more than a threshold of 32).
|
||||
In addition to alerting all operators implied by the
|
||||
.Cm n
|
||||
key,
|
||||
.Nm dump
|
||||
interacts with the operator on
|
||||
.Em dump's
|
||||
control terminal at times when
|
||||
.Nm dump
|
||||
can no longer proceed,
|
||||
or if something is grossly wrong.
|
||||
All questions
|
||||
.Nm dump
|
||||
poses
|
||||
.Em must
|
||||
be answered by typing
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no ,
|
||||
appropriately.
|
||||
.Pp
|
||||
Since making a dump involves a lot of time and effort for full dumps,
|
||||
.Nm dump
|
||||
checkpoints itself at the start of each tape volume.
|
||||
If writing that volume fails for some reason,
|
||||
.Nm dump
|
||||
will,
|
||||
with operator permission,
|
||||
restart itself from the checkpoint
|
||||
after the old tape has been rewound and removed,
|
||||
and a new tape has been mounted.
|
||||
.Pp
|
||||
.Nm Dump
|
||||
tells the operator what is going on at periodic intervals,
|
||||
including usually low estimates of the number of blocks to write,
|
||||
the number of tapes it will take, the time to completion, and
|
||||
the time to the tape change.
|
||||
The output is verbose,
|
||||
so that others know that the terminal
|
||||
controlling
|
||||
.Nm dump
|
||||
is busy,
|
||||
and will be for some time.
|
||||
.Pp
|
||||
In the event of a catastrophic disk event, the time required
|
||||
to restore all the necessary backup tapes or files to disk
|
||||
can be kept to a minimum by staggering the incremental dumps.
|
||||
An efficient method of staggering incremental dumps
|
||||
to minimize the number of tapes follows:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
Always start with a level 0 backup, for example:
|
||||
.Bd -literal -offset indent
|
||||
/etc/dump 0uf /dev/nrst1 /usr/src
|
||||
.Ed
|
||||
.Pp
|
||||
This should be done at set intervals, say once a month or once every two months,
|
||||
and on a set of fresh tapes that is saved forever.
|
||||
.It
|
||||
After a level 0, dumps of active file
|
||||
systems are taken on a daily basis,
|
||||
using a modified Tower of Hanoi algorithm,
|
||||
with this sequence of dump levels:
|
||||
.Bd -literal -offset indent
|
||||
3 2 5 4 7 6 9 8 9 9 ...
|
||||
.Ed
|
||||
.Pp
|
||||
For the daily dumps, it should be possible to use a fixed number of tapes
|
||||
for each day, used on a weekly basis.
|
||||
Each week, a level 1 dump is taken, and
|
||||
the daily Hanoi sequence repeats beginning with 3.
|
||||
For weekly dumps, another fixed set of tapes per dumped file system is
|
||||
used, also on a cyclical basis.
|
||||
.El
|
||||
.Pp
|
||||
After several months or so, the daily and weekly tapes should get
|
||||
rotated out of the dump cycle and fresh tapes brought in.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/dumpdates -compact
|
||||
.It Pa /dev/rmt8
|
||||
default tape unit to dump to
|
||||
.It Pa /etc/dumpdates
|
||||
dump date records
|
||||
.It Pa /etc/fstab
|
||||
dump table: file systems and frequency
|
||||
.It Pa /etc/group
|
||||
to find group
|
||||
.Em operator
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr restore 8 ,
|
||||
.Xr rmt 8 ,
|
||||
.Xr dump 5 ,
|
||||
.Xr fstab 5
|
||||
.Sh DIAGNOSTICS
|
||||
Many, and verbose.
|
||||
.Pp
|
||||
Dump exits with zero status on success.
|
||||
Startup errors are indicated with an exit code of 1;
|
||||
abnormal termination is indicated with an exit code of 3.
|
||||
.Sh BUGS
|
||||
.Pp
|
||||
Fewer than 32 read errors on the filesystem are ignored.
|
||||
Each reel requires a new process, so parent processes for
|
||||
reels already written just hang around until the entire tape
|
||||
is written.
|
||||
.Pp
|
||||
.Nm Dump
|
||||
with the
|
||||
.Cm W
|
||||
or
|
||||
.Cm w
|
||||
options does not report filesystems that have never been recorded
|
||||
in
|
||||
.Pa /etc/dumpdates ,
|
||||
even if listed in
|
||||
.Pa /etc/fstab .
|
||||
.Pp
|
||||
It would be nice if
|
||||
.Nm dump
|
||||
knew about the dump sequence,
|
||||
kept track of the tapes scribbled on,
|
||||
told the operator which tape to mount when,
|
||||
and provided more assistance
|
||||
for the operator running
|
||||
.Xr restore .
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm dump
|
||||
command appeared in Version 6 AT&T UNIX.
|
||||
212
sbin/dump/dump.h
Normal file
212
sbin/dump/dump.h
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)dump.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#define MAXINOPB (MAXBSIZE / sizeof(struct dinode))
|
||||
#define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
|
||||
|
||||
/*
|
||||
* Dump maps used to describe what is to be dumped.
|
||||
*/
|
||||
int mapsize; /* size of the state maps */
|
||||
char *usedinomap; /* map of allocated inodes */
|
||||
char *dumpdirmap; /* map of directories to be dumped */
|
||||
char *dumpinomap; /* map of files to be dumped */
|
||||
/*
|
||||
* Map manipulation macros.
|
||||
*/
|
||||
#define SETINO(ino, map) \
|
||||
map[(u_int)((ino) - 1) / NBBY] |= 1 << ((u_int)((ino) - 1) % NBBY)
|
||||
#define CLRINO(ino, map) \
|
||||
map[(u_int)((ino) - 1) / NBBY] &= ~(1 << ((u_int)((ino) - 1) % NBBY))
|
||||
#define TSTINO(ino, map) \
|
||||
(map[(u_int)((ino) - 1) / NBBY] & (1 << ((u_int)((ino) - 1) % NBBY)))
|
||||
|
||||
/*
|
||||
* All calculations done in 0.1" units!
|
||||
*/
|
||||
char *disk; /* name of the disk file */
|
||||
char *tape; /* name of the tape file */
|
||||
char *dumpdates; /* name of the file containing dump date information*/
|
||||
char *temp; /* name of the file for doing rewrite of dumpdates */
|
||||
char lastlevel; /* dump level of previous dump */
|
||||
char level; /* dump level of this dump */
|
||||
int uflag; /* update flag */
|
||||
int diskfd; /* disk file descriptor */
|
||||
int tapefd; /* tape file descriptor */
|
||||
int pipeout; /* true => output to standard output */
|
||||
ino_t curino; /* current inumber; used globally */
|
||||
int newtape; /* new tape flag */
|
||||
int density; /* density in 0.1" units */
|
||||
long tapesize; /* estimated tape size, blocks */
|
||||
long tsize; /* tape size in 0.1" units */
|
||||
long asize; /* number of 0.1" units written on current tape */
|
||||
int etapes; /* estimated number of tapes */
|
||||
int nonodump; /* if set, do not honor UF_NODUMP user flags */
|
||||
|
||||
int notify; /* notify operator flag */
|
||||
int blockswritten; /* number of blocks written on current tape */
|
||||
int tapeno; /* current tape number */
|
||||
time_t tstart_writing; /* when started writing the first tape block */
|
||||
struct fs *sblock; /* the file system super block */
|
||||
char sblock_buf[MAXBSIZE];
|
||||
long dev_bsize; /* block size of underlying disk device */
|
||||
int dev_bshift; /* log2(dev_bsize) */
|
||||
int tp_bshift; /* log2(TP_BSIZE) */
|
||||
|
||||
#ifndef __P
|
||||
#include <sys/cdefs.h>
|
||||
#endif
|
||||
|
||||
/* operator interface functions */
|
||||
void broadcast __P((char *message));
|
||||
void lastdump __P((int arg)); /* int should be char */
|
||||
void msg __P((const char *fmt, ...));
|
||||
void msgtail __P((const char *fmt, ...));
|
||||
int query __P((char *question));
|
||||
void quit __P((const char *fmt, ...));
|
||||
void set_operators __P((void));
|
||||
void timeest __P((void));
|
||||
time_t unctime __P((char *str));
|
||||
|
||||
/* mapping rouintes */
|
||||
struct dinode;
|
||||
long blockest __P((struct dinode *dp));
|
||||
int mapfiles __P((ino_t maxino, long *tapesize));
|
||||
int mapdirs __P((ino_t maxino, long *tapesize));
|
||||
|
||||
/* file dumping routines */
|
||||
void blksout __P((daddr_t *blkp, int frags, ino_t ino));
|
||||
void bread __P((daddr_t blkno, char *buf, int size));
|
||||
void dumpino __P((struct dinode *dp, ino_t ino));
|
||||
void dumpmap __P((char *map, int type, ino_t ino));
|
||||
void writeheader __P((ino_t ino));
|
||||
|
||||
/* tape writing routines */
|
||||
int alloctape __P((void));
|
||||
void close_rewind __P((void));
|
||||
void dumpblock __P((daddr_t blkno, int size));
|
||||
void startnewtape __P((int top));
|
||||
void trewind __P((void));
|
||||
void writerec __P((char *dp, int isspcl));
|
||||
|
||||
__dead void Exit __P((int status));
|
||||
void dumpabort __P((int signo));
|
||||
void getfstab __P((void));
|
||||
|
||||
char *rawname __P((char *cp));
|
||||
struct dinode *getino __P((ino_t inum));
|
||||
|
||||
/* rdump routines */
|
||||
#ifdef RDUMP
|
||||
void rmtclose __P((void));
|
||||
int rmthost __P((char *host));
|
||||
int rmtopen __P((char *tape, int mode));
|
||||
int rmtwrite __P((char *buf, int count));
|
||||
#endif /* RDUMP */
|
||||
|
||||
void interrupt __P((int signo)); /* in case operator bangs on console */
|
||||
|
||||
/*
|
||||
* Exit status codes
|
||||
*/
|
||||
#define X_FINOK 0 /* normal exit */
|
||||
#define X_REWRITE 2 /* restart writing from the check point */
|
||||
#define X_ABORT 3 /* abort dump; don't attempt checkpointing */
|
||||
|
||||
#define OPGRENT "operator" /* group entry to notify */
|
||||
#define DIALUP "ttyd" /* prefix for dialups */
|
||||
|
||||
struct fstab *fstabsearch __P((char *key)); /* search fs_file and fs_spec */
|
||||
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX 255
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The contents of the file _PATH_DUMPDATES is maintained both on
|
||||
* a linked list, and then (eventually) arrayified.
|
||||
*/
|
||||
struct dumpdates {
|
||||
char dd_name[NAME_MAX+3];
|
||||
char dd_level;
|
||||
time_t dd_ddate;
|
||||
};
|
||||
struct dumptime {
|
||||
struct dumpdates dt_value;
|
||||
struct dumptime *dt_next;
|
||||
};
|
||||
struct dumptime *dthead; /* head of the list version */
|
||||
int nddates; /* number of records (might be zero) */
|
||||
int ddates_in; /* we have read the increment file */
|
||||
struct dumpdates **ddatev; /* the arrayfied version */
|
||||
void initdumptimes __P((void));
|
||||
void getdumptime __P((void));
|
||||
void putdumptime __P((void));
|
||||
#define ITITERATE(i, ddp) \
|
||||
for (ddp = ddatev[i = 0]; i < nddates; ddp = ddatev[++i])
|
||||
|
||||
void sig __P((int signo));
|
||||
|
||||
/*
|
||||
* Compatibility with old systems.
|
||||
*/
|
||||
#ifdef COMPAT
|
||||
#include <sys/file.h>
|
||||
extern char *index(), *rindex(), *strdup();
|
||||
extern char *ctime();
|
||||
extern int read(), write();
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_UTMP
|
||||
#define _PATH_UTMP "/etc/utmp"
|
||||
#endif
|
||||
#ifndef _PATH_FSTAB
|
||||
#define _PATH_FSTAB "/etc/fstab"
|
||||
#endif
|
||||
|
||||
#ifdef sunos
|
||||
extern char *calloc();
|
||||
extern char *malloc();
|
||||
extern long atol();
|
||||
extern char *strcpy();
|
||||
extern char *strncpy();
|
||||
extern char *strcat();
|
||||
extern time_t time();
|
||||
extern void endgrent();
|
||||
extern __dead void exit();
|
||||
extern off_t lseek();
|
||||
extern const char *strerror();
|
||||
#endif
|
||||
380
sbin/dump/dumprmt.c
Normal file
380
sbin/dump/dumprmt.c
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dumprmt.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mtio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/inode.h>
|
||||
#else
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "dump.h"
|
||||
|
||||
#define TS_CLOSED 0
|
||||
#define TS_OPEN 1
|
||||
|
||||
static int rmtstate = TS_CLOSED;
|
||||
static int rmtape;
|
||||
static char *rmtpeer;
|
||||
|
||||
static int okname __P((char *));
|
||||
static int rmtcall __P((char *, char *));
|
||||
static void rmtconnaborted __P((/* int, int */));
|
||||
static int rmtgetb __P((void));
|
||||
static void rmtgetconn __P((void));
|
||||
static void rmtgets __P((char *, int));
|
||||
static int rmtreply __P((char *));
|
||||
|
||||
extern int ntrec; /* blocking factor on tape */
|
||||
|
||||
int
|
||||
rmthost(host)
|
||||
char *host;
|
||||
{
|
||||
|
||||
rmtpeer = malloc(strlen(host) + 1);
|
||||
if (rmtpeer)
|
||||
strcpy(rmtpeer, host);
|
||||
else
|
||||
rmtpeer = host;
|
||||
signal(SIGPIPE, rmtconnaborted);
|
||||
rmtgetconn();
|
||||
if (rmtape < 0)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
rmtconnaborted()
|
||||
{
|
||||
|
||||
(void) fprintf(stderr, "rdump: Lost connection to remote host.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
rmtgetconn()
|
||||
{
|
||||
register char *cp;
|
||||
static struct servent *sp = NULL;
|
||||
static struct passwd *pwd = NULL;
|
||||
#ifdef notdef
|
||||
static int on = 1;
|
||||
#endif
|
||||
char *tuser;
|
||||
int size;
|
||||
int maxseg;
|
||||
|
||||
if (sp == NULL) {
|
||||
sp = getservbyname("shell", "tcp");
|
||||
if (sp == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
"rdump: shell/tcp: unknown service\n");
|
||||
exit(1);
|
||||
}
|
||||
pwd = getpwuid(getuid());
|
||||
if (pwd == NULL) {
|
||||
(void) fprintf(stderr, "rdump: who are you?\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if ((cp = index(rmtpeer, '@')) != NULL) {
|
||||
tuser = rmtpeer;
|
||||
*cp = '\0';
|
||||
if (!okname(tuser))
|
||||
exit(1);
|
||||
rmtpeer = ++cp;
|
||||
} else
|
||||
tuser = pwd->pw_name;
|
||||
rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name, tuser,
|
||||
_PATH_RMT, (int *)0);
|
||||
size = ntrec * TP_BSIZE;
|
||||
if (size > 60 * 1024) /* XXX */
|
||||
size = 60 * 1024;
|
||||
/* Leave some space for rmt request/response protocol */
|
||||
size += 2 * 1024;
|
||||
while (size > TP_BSIZE &&
|
||||
setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
|
||||
size -= TP_BSIZE;
|
||||
(void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
|
||||
maxseg = 1024;
|
||||
if (setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG,
|
||||
&maxseg, sizeof (maxseg)) < 0)
|
||||
perror("TCP_MAXSEG setsockopt");
|
||||
|
||||
#ifdef notdef
|
||||
if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
|
||||
perror("TCP_NODELAY setsockopt");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
okname(cp0)
|
||||
char *cp0;
|
||||
{
|
||||
register char *cp;
|
||||
register int c;
|
||||
|
||||
for (cp = cp0; *cp; cp++) {
|
||||
c = *cp;
|
||||
if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
|
||||
(void) fprintf(stderr, "rdump: invalid user name %s\n",
|
||||
cp0);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
rmtopen(tape, mode)
|
||||
char *tape;
|
||||
int mode;
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
(void)sprintf(buf, "O%s\n%d\n", tape, mode);
|
||||
rmtstate = TS_OPEN;
|
||||
return (rmtcall(tape, buf));
|
||||
}
|
||||
|
||||
void
|
||||
rmtclose()
|
||||
{
|
||||
|
||||
if (rmtstate != TS_OPEN)
|
||||
return;
|
||||
rmtcall("close", "C\n");
|
||||
rmtstate = TS_CLOSED;
|
||||
}
|
||||
|
||||
int
|
||||
rmtread(buf, count)
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
char line[30];
|
||||
int n, i, cc;
|
||||
extern errno;
|
||||
|
||||
(void)sprintf(line, "R%d\n", count);
|
||||
n = rmtcall("read", line);
|
||||
if (n < 0) {
|
||||
errno = n;
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < n; i += cc) {
|
||||
cc = read(rmtape, buf+i, n - i);
|
||||
if (cc <= 0) {
|
||||
rmtconnaborted();
|
||||
}
|
||||
}
|
||||
return (n);
|
||||
}
|
||||
|
||||
int
|
||||
rmtwrite(buf, count)
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
char line[30];
|
||||
|
||||
(void)sprintf(line, "W%d\n", count);
|
||||
write(rmtape, line, strlen(line));
|
||||
write(rmtape, buf, count);
|
||||
return (rmtreply("write"));
|
||||
}
|
||||
|
||||
void
|
||||
rmtwrite0(count)
|
||||
int count;
|
||||
{
|
||||
char line[30];
|
||||
|
||||
(void)sprintf(line, "W%d\n", count);
|
||||
write(rmtape, line, strlen(line));
|
||||
}
|
||||
|
||||
void
|
||||
rmtwrite1(buf, count)
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
|
||||
write(rmtape, buf, count);
|
||||
}
|
||||
|
||||
int
|
||||
rmtwrite2()
|
||||
{
|
||||
|
||||
return (rmtreply("write"));
|
||||
}
|
||||
|
||||
int
|
||||
rmtseek(offset, pos)
|
||||
int offset, pos;
|
||||
{
|
||||
char line[80];
|
||||
|
||||
(void)sprintf(line, "L%d\n%d\n", offset, pos);
|
||||
return (rmtcall("seek", line));
|
||||
}
|
||||
|
||||
struct mtget mts;
|
||||
|
||||
struct mtget *
|
||||
rmtstatus()
|
||||
{
|
||||
register int i;
|
||||
register char *cp;
|
||||
|
||||
if (rmtstate != TS_OPEN)
|
||||
return (NULL);
|
||||
rmtcall("status", "S\n");
|
||||
for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
|
||||
*cp++ = rmtgetb();
|
||||
return (&mts);
|
||||
}
|
||||
|
||||
int
|
||||
rmtioctl(cmd, count)
|
||||
int cmd, count;
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
if (count < 0)
|
||||
return (-1);
|
||||
(void)sprintf(buf, "I%d\n%d\n", cmd, count);
|
||||
return (rmtcall("ioctl", buf));
|
||||
}
|
||||
|
||||
static int
|
||||
rmtcall(cmd, buf)
|
||||
char *cmd, *buf;
|
||||
{
|
||||
|
||||
if (write(rmtape, buf, strlen(buf)) != strlen(buf))
|
||||
rmtconnaborted();
|
||||
return (rmtreply(cmd));
|
||||
}
|
||||
|
||||
static int
|
||||
rmtreply(cmd)
|
||||
char *cmd;
|
||||
{
|
||||
register char *cp;
|
||||
char code[30], emsg[BUFSIZ];
|
||||
|
||||
rmtgets(code, sizeof (code));
|
||||
if (*code == 'E' || *code == 'F') {
|
||||
rmtgets(emsg, sizeof (emsg));
|
||||
msg("%s: %s", cmd, emsg);
|
||||
if (*code == 'F') {
|
||||
rmtstate = TS_CLOSED;
|
||||
return (-1);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
if (*code != 'A') {
|
||||
/* Kill trailing newline */
|
||||
cp = code + strlen(code);
|
||||
if (cp > code && *--cp == '\n')
|
||||
*cp = '\0';
|
||||
|
||||
msg("Protocol to remote tape server botched (code \"%s\").\n",
|
||||
code);
|
||||
rmtconnaborted();
|
||||
}
|
||||
return (atoi(code + 1));
|
||||
}
|
||||
|
||||
int
|
||||
rmtgetb()
|
||||
{
|
||||
char c;
|
||||
|
||||
if (read(rmtape, &c, 1) != 1)
|
||||
rmtconnaborted();
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* Get a line (guaranteed to have a trailing newline). */
|
||||
void
|
||||
rmtgets(line, len)
|
||||
char *line;
|
||||
int len;
|
||||
{
|
||||
register char *cp = line;
|
||||
|
||||
while (len > 1) {
|
||||
*cp = rmtgetb();
|
||||
if (*cp == '\n') {
|
||||
cp[1] = '\0';
|
||||
return;
|
||||
}
|
||||
cp++;
|
||||
len--;
|
||||
}
|
||||
*cp = '\0';
|
||||
msg("Protocol to remote tape server botched.\n");
|
||||
msg("(rmtgets got \"%s\").\n", line);
|
||||
rmtconnaborted();
|
||||
}
|
||||
271
sbin/dump/itime.c
Normal file
271
sbin/dump/itime.c
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)itime.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/fsdir.h>
|
||||
#include <ufs/inode.h>
|
||||
#include <ufs/fs.h>
|
||||
#else
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#endif
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "dump.h"
|
||||
|
||||
struct dumpdates **ddatev = 0;
|
||||
int nddates = 0;
|
||||
int ddates_in = 0;
|
||||
struct dumptime *dthead = 0;
|
||||
|
||||
static void dumprecout __P((FILE *, struct dumpdates *));
|
||||
static int getrecord __P((FILE *, struct dumpdates *));
|
||||
static int makedumpdate __P((struct dumpdates *, char *));
|
||||
static void readdumptimes __P((FILE *));
|
||||
|
||||
void
|
||||
initdumptimes()
|
||||
{
|
||||
FILE *df;
|
||||
|
||||
if ((df = fopen(dumpdates, "r")) == NULL) {
|
||||
if (errno != ENOENT) {
|
||||
quit("cannot read %s: %s\n", dumpdates,
|
||||
strerror(errno));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
/*
|
||||
* Dumpdates does not exist, make an empty one.
|
||||
*/
|
||||
msg("WARNING: no file `%s', making an empty one\n", dumpdates);
|
||||
if ((df = fopen(dumpdates, "w")) == NULL) {
|
||||
quit("cannot create %s: %s\n", dumpdates,
|
||||
strerror(errno));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
(void) fclose(df);
|
||||
if ((df = fopen(dumpdates, "r")) == NULL) {
|
||||
quit("cannot read %s even after creating it: %s\n",
|
||||
dumpdates, strerror(errno));
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
(void) flock(fileno(df), LOCK_SH);
|
||||
readdumptimes(df);
|
||||
(void) fclose(df);
|
||||
}
|
||||
|
||||
static void
|
||||
readdumptimes(df)
|
||||
FILE *df;
|
||||
{
|
||||
register int i;
|
||||
register struct dumptime *dtwalk;
|
||||
|
||||
for (;;) {
|
||||
dtwalk = (struct dumptime *)calloc(1, sizeof (struct dumptime));
|
||||
if (getrecord(df, &(dtwalk->dt_value)) < 0)
|
||||
break;
|
||||
nddates++;
|
||||
dtwalk->dt_next = dthead;
|
||||
dthead = dtwalk;
|
||||
}
|
||||
|
||||
ddates_in = 1;
|
||||
/*
|
||||
* arrayify the list, leaving enough room for the additional
|
||||
* record that we may have to add to the ddate structure
|
||||
*/
|
||||
ddatev = (struct dumpdates **)
|
||||
calloc((unsigned) (nddates + 1), sizeof (struct dumpdates *));
|
||||
dtwalk = dthead;
|
||||
for (i = nddates - 1; i >= 0; i--, dtwalk = dtwalk->dt_next)
|
||||
ddatev[i] = &dtwalk->dt_value;
|
||||
}
|
||||
|
||||
void
|
||||
getdumptime()
|
||||
{
|
||||
register struct dumpdates *ddp;
|
||||
register int i;
|
||||
char *fname;
|
||||
|
||||
fname = disk;
|
||||
#ifdef FDEBUG
|
||||
msg("Looking for name %s in dumpdates = %s for level = %c\n",
|
||||
fname, dumpdates, level);
|
||||
#endif
|
||||
spcl.c_ddate = 0;
|
||||
lastlevel = '0';
|
||||
|
||||
initdumptimes();
|
||||
/*
|
||||
* Go find the entry with the same name for a lower increment
|
||||
* and older date
|
||||
*/
|
||||
ITITERATE(i, ddp) {
|
||||
if (strncmp(fname, ddp->dd_name, sizeof (ddp->dd_name)) != 0)
|
||||
continue;
|
||||
if (ddp->dd_level >= level)
|
||||
continue;
|
||||
if (ddp->dd_ddate <= spcl.c_ddate)
|
||||
continue;
|
||||
spcl.c_ddate = ddp->dd_ddate;
|
||||
lastlevel = ddp->dd_level;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
putdumptime()
|
||||
{
|
||||
FILE *df;
|
||||
register struct dumpdates *dtwalk;
|
||||
register int i;
|
||||
int fd;
|
||||
char *fname;
|
||||
|
||||
if(uflag == 0)
|
||||
return;
|
||||
if ((df = fopen(dumpdates, "r+")) == NULL)
|
||||
quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno));
|
||||
fd = fileno(df);
|
||||
(void) flock(fd, LOCK_EX);
|
||||
fname = disk;
|
||||
free((char *)ddatev);
|
||||
ddatev = 0;
|
||||
nddates = 0;
|
||||
dthead = 0;
|
||||
ddates_in = 0;
|
||||
readdumptimes(df);
|
||||
if (fseek(df, 0L, 0) < 0)
|
||||
quit("fseek: %s\n", strerror(errno));
|
||||
spcl.c_ddate = 0;
|
||||
ITITERATE(i, dtwalk) {
|
||||
if (strncmp(fname, dtwalk->dd_name,
|
||||
sizeof (dtwalk->dd_name)) != 0)
|
||||
continue;
|
||||
if (dtwalk->dd_level != level)
|
||||
continue;
|
||||
goto found;
|
||||
}
|
||||
/*
|
||||
* construct the new upper bound;
|
||||
* Enough room has been allocated.
|
||||
*/
|
||||
dtwalk = ddatev[nddates] =
|
||||
(struct dumpdates *)calloc(1, sizeof (struct dumpdates));
|
||||
nddates += 1;
|
||||
found:
|
||||
(void) strncpy(dtwalk->dd_name, fname, sizeof (dtwalk->dd_name));
|
||||
dtwalk->dd_level = level;
|
||||
dtwalk->dd_ddate = spcl.c_date;
|
||||
|
||||
ITITERATE(i, dtwalk) {
|
||||
dumprecout(df, dtwalk);
|
||||
}
|
||||
if (fflush(df))
|
||||
quit("%s: %s\n", dumpdates, strerror(errno));
|
||||
if (ftruncate(fd, ftell(df)))
|
||||
quit("ftruncate (%s): %s\n", dumpdates, strerror(errno));
|
||||
(void) fclose(df);
|
||||
msg("level %c dump on %s", level,
|
||||
spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
|
||||
}
|
||||
|
||||
static void
|
||||
dumprecout(file, what)
|
||||
FILE *file;
|
||||
struct dumpdates *what;
|
||||
{
|
||||
|
||||
if (fprintf(file, DUMPOUTFMT,
|
||||
what->dd_name,
|
||||
what->dd_level,
|
||||
ctime(&what->dd_ddate)) < 0)
|
||||
quit("%s: %s\n", dumpdates, strerror(errno));
|
||||
}
|
||||
|
||||
int recno;
|
||||
|
||||
static int
|
||||
getrecord(df, ddatep)
|
||||
FILE *df;
|
||||
struct dumpdates *ddatep;
|
||||
{
|
||||
char tbuf[BUFSIZ];
|
||||
|
||||
recno = 0;
|
||||
if ( (fgets(tbuf, sizeof (tbuf), df)) != tbuf)
|
||||
return(-1);
|
||||
recno++;
|
||||
if (makedumpdate(ddatep, tbuf) < 0)
|
||||
msg("Unknown intermediate format in %s, line %d\n",
|
||||
dumpdates, recno);
|
||||
|
||||
#ifdef FDEBUG
|
||||
msg("getrecord: %s %c %s", ddatep->dd_name, ddatep->dd_level,
|
||||
ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate));
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
makedumpdate(ddp, tbuf)
|
||||
struct dumpdates *ddp;
|
||||
char *tbuf;
|
||||
{
|
||||
char un_buf[128];
|
||||
|
||||
(void) sscanf(tbuf, DUMPINFMT, ddp->dd_name, &ddp->dd_level, un_buf);
|
||||
ddp->dd_ddate = unctime(un_buf);
|
||||
if (ddp->dd_ddate < 0)
|
||||
return(-1);
|
||||
return(0);
|
||||
}
|
||||
560
sbin/dump/main.c
Normal file
560
sbin/dump/main.c
Normal file
|
|
@ -0,0 +1,560 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 4/15/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/inode.h>
|
||||
#include <ufs/fs.h>
|
||||
#else
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#endif
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fstab.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "dump.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#ifndef SBOFF
|
||||
#define SBOFF (SBLOCK * DEV_BSIZE)
|
||||
#endif
|
||||
|
||||
int notify = 0; /* notify operator flag */
|
||||
int blockswritten = 0; /* number of blocks written on current tape */
|
||||
int tapeno = 0; /* current tape number */
|
||||
int density = 0; /* density in bytes/0.1" */
|
||||
int ntrec = NTREC; /* # tape blocks in each tape record */
|
||||
int cartridge = 0; /* Assume non-cartridge tape */
|
||||
long dev_bsize = 1; /* recalculated below */
|
||||
long blocksperfile; /* output blocks per file */
|
||||
char *host = NULL; /* remote host (if any) */
|
||||
|
||||
static long numarg __P((int, char *, long, long, int *, char ***));
|
||||
static __dead void missingarg __P((int, char *));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register ino_t ino;
|
||||
register int dirty;
|
||||
register struct dinode *dp;
|
||||
register struct fstab *dt;
|
||||
register char *map;
|
||||
register char *cp;
|
||||
int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1;
|
||||
ino_t maxino;
|
||||
|
||||
spcl.c_date = 0;
|
||||
(void)time((time_t *)&spcl.c_date);
|
||||
|
||||
tsize = 0; /* Default later, based on 'c' option for cart tapes */
|
||||
tape = _PATH_DEFTAPE;
|
||||
dumpdates = _PATH_DUMPDATES;
|
||||
temp = _PATH_DTMP;
|
||||
if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
|
||||
quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
|
||||
level = '0';
|
||||
if (argc == 1) {
|
||||
(void) fprintf(stderr, "Must specify a key.\n");
|
||||
Exit(X_ABORT);
|
||||
}
|
||||
argv++;
|
||||
argc -= 2;
|
||||
for (cp = *argv++; cp != NULL && *cp != '\0'; cp++) {
|
||||
switch (*cp) {
|
||||
case '-':
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
lastdump('w'); /* tell us only what has to be done */
|
||||
exit(0);
|
||||
|
||||
case 'W': /* what to do */
|
||||
lastdump('W'); /* tell us state of what is done */
|
||||
exit(0); /* do nothing else */
|
||||
|
||||
case 'f': /* output file */
|
||||
if (argc < 1)
|
||||
missingarg('f', "output file");
|
||||
tape = *argv++;
|
||||
argc--;
|
||||
break;
|
||||
|
||||
case 'd': /* density, in bits per inch */
|
||||
density = numarg('d', "density",
|
||||
10L, 327670L, &argc, &argv) / 10;
|
||||
if (density >= 625 && !bflag)
|
||||
ntrec = HIGHDENSITYTREC;
|
||||
break;
|
||||
|
||||
case 's': /* tape size, feet */
|
||||
tsize = numarg('s', "size",
|
||||
1L, 0L, &argc, &argv) * 12 * 10;
|
||||
break;
|
||||
|
||||
case 'T': /* time of last dump */
|
||||
if (argc < 1)
|
||||
missingarg('T', "time of last dump");
|
||||
spcl.c_ddate = unctime(*argv);
|
||||
if (spcl.c_ddate < 0) {
|
||||
(void)fprintf(stderr, "bad time \"%s\"\n",
|
||||
*argv);
|
||||
exit(X_ABORT);
|
||||
}
|
||||
Tflag = 1;
|
||||
lastlevel = '?';
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
|
||||
case 'b': /* blocks per tape write */
|
||||
ntrec = numarg('b', "number of blocks per write",
|
||||
1L, 1000L, &argc, &argv);
|
||||
break;
|
||||
|
||||
case 'B': /* blocks per output file */
|
||||
blocksperfile = numarg('B', "number of blocks per file",
|
||||
1L, 0L, &argc, &argv);
|
||||
break;
|
||||
|
||||
case 'c': /* Tape is cart. not 9-track */
|
||||
cartridge = 1;
|
||||
break;
|
||||
|
||||
/* dump level */
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
level = *cp;
|
||||
break;
|
||||
|
||||
case 'u': /* update /etc/dumpdates */
|
||||
uflag = 1;
|
||||
break;
|
||||
|
||||
case 'n': /* notify operators */
|
||||
notify = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
honorlevel = numarg('h', "honor level",
|
||||
0L, 10L, &argc, &argv);
|
||||
break;
|
||||
|
||||
default:
|
||||
(void)fprintf(stderr, "bad key '%c'\n", *cp);
|
||||
exit(X_ABORT);
|
||||
}
|
||||
}
|
||||
if (argc < 1) {
|
||||
(void)fprintf(stderr, "Must specify disk or filesystem\n");
|
||||
exit(X_ABORT);
|
||||
}
|
||||
disk = *argv++;
|
||||
argc--;
|
||||
if (argc >= 1) {
|
||||
(void)fprintf(stderr, "Unknown arguments to dump:");
|
||||
while (argc--)
|
||||
(void)fprintf(stderr, " %s", *argv++);
|
||||
(void)fprintf(stderr, "\n");
|
||||
exit(X_ABORT);
|
||||
}
|
||||
if (Tflag && uflag) {
|
||||
(void)fprintf(stderr,
|
||||
"You cannot use the T and u flags together.\n");
|
||||
exit(X_ABORT);
|
||||
}
|
||||
if (strcmp(tape, "-") == 0) {
|
||||
pipeout++;
|
||||
tape = "standard output";
|
||||
}
|
||||
|
||||
if (blocksperfile)
|
||||
blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
|
||||
else {
|
||||
/*
|
||||
* Determine how to default tape size and density
|
||||
*
|
||||
* density tape size
|
||||
* 9-track 1600 bpi (160 bytes/.1") 2300 ft.
|
||||
* 9-track 6250 bpi (625 bytes/.1") 2300 ft.
|
||||
* cartridge 8000 bpi (100 bytes/.1") 1700 ft.
|
||||
* (450*4 - slop)
|
||||
*/
|
||||
if (density == 0)
|
||||
density = cartridge ? 100 : 160;
|
||||
if (tsize == 0)
|
||||
tsize = cartridge ? 1700L*120L : 2300L*120L;
|
||||
}
|
||||
|
||||
if (index(tape, ':')) {
|
||||
host = tape;
|
||||
tape = index(host, ':');
|
||||
*tape++ = '\0';
|
||||
#ifdef RDUMP
|
||||
if (rmthost(host) == 0)
|
||||
exit(X_ABORT);
|
||||
#else
|
||||
(void)fprintf(stderr, "remote dump not enabled\n");
|
||||
exit(X_ABORT);
|
||||
#endif
|
||||
}
|
||||
(void)setuid(getuid()); /* rmthost() is the only reason to be setuid */
|
||||
|
||||
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGHUP, sig);
|
||||
if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGTRAP, sig);
|
||||
if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGFPE, sig);
|
||||
if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGBUS, sig);
|
||||
if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGSEGV, sig);
|
||||
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGTERM, sig);
|
||||
if (signal(SIGINT, interrupt) == SIG_IGN)
|
||||
signal(SIGINT, SIG_IGN);
|
||||
|
||||
set_operators(); /* /etc/group snarfed */
|
||||
getfstab(); /* /etc/fstab snarfed */
|
||||
/*
|
||||
* disk can be either the full special file name,
|
||||
* the suffix of the special file name,
|
||||
* the special name missing the leading '/',
|
||||
* the file system name with or without the leading '/'.
|
||||
*/
|
||||
dt = fstabsearch(disk);
|
||||
if (dt != NULL) {
|
||||
disk = rawname(dt->fs_spec);
|
||||
(void)strncpy(spcl.c_dev, dt->fs_spec, NAMELEN);
|
||||
(void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
|
||||
} else {
|
||||
(void)strncpy(spcl.c_dev, disk, NAMELEN);
|
||||
(void)strncpy(spcl.c_filesys, "an unlisted file system",
|
||||
NAMELEN);
|
||||
}
|
||||
(void)strcpy(spcl.c_label, "none");
|
||||
(void)gethostname(spcl.c_host, NAMELEN);
|
||||
spcl.c_level = level - '0';
|
||||
spcl.c_type = TS_TAPE;
|
||||
if (!Tflag)
|
||||
getdumptime(); /* /etc/dumpdates snarfed */
|
||||
|
||||
msg("Date of this level %c dump: %s", level,
|
||||
spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
|
||||
msg("Date of last level %c dump: %s", lastlevel,
|
||||
spcl.c_ddate == 0 ? "the epoch\n" : ctime(&spcl.c_ddate));
|
||||
msg("Dumping %s ", disk);
|
||||
if (dt != NULL)
|
||||
msgtail("(%s) ", dt->fs_file);
|
||||
if (host)
|
||||
msgtail("to %s on host %s\n", tape, host);
|
||||
else
|
||||
msgtail("to %s\n", tape);
|
||||
|
||||
if ((diskfd = open(disk, O_RDONLY)) < 0) {
|
||||
msg("Cannot open %s\n", disk);
|
||||
exit(X_ABORT);
|
||||
}
|
||||
sync();
|
||||
sblock = (struct fs *)sblock_buf;
|
||||
bread(SBOFF, (char *) sblock, SBSIZE);
|
||||
if (sblock->fs_magic != FS_MAGIC)
|
||||
quit("bad sblock magic number\n");
|
||||
dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
|
||||
dev_bshift = ffs(dev_bsize) - 1;
|
||||
if (dev_bsize != (1 << dev_bshift))
|
||||
quit("dev_bsize (%d) is not a power of 2", dev_bsize);
|
||||
tp_bshift = ffs(TP_BSIZE) - 1;
|
||||
if (TP_BSIZE != (1 << tp_bshift))
|
||||
quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
|
||||
#ifdef FS_44INODEFMT
|
||||
if (sblock->fs_inodefmt >= FS_44INODEFMT)
|
||||
spcl.c_flags |= DR_NEWINODEFMT;
|
||||
#endif
|
||||
maxino = sblock->fs_ipg * sblock->fs_ncg;
|
||||
mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE);
|
||||
usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
|
||||
dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
|
||||
dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
|
||||
tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
|
||||
|
||||
nonodump = spcl.c_level < honorlevel;
|
||||
|
||||
msg("mapping (Pass I) [regular files]\n");
|
||||
anydirskipped = mapfiles(maxino, &tapesize);
|
||||
|
||||
msg("mapping (Pass II) [directories]\n");
|
||||
while (anydirskipped) {
|
||||
anydirskipped = mapdirs(maxino, &tapesize);
|
||||
}
|
||||
|
||||
if (pipeout) {
|
||||
tapesize += 10; /* 10 trailer blocks */
|
||||
msg("estimated %ld tape blocks.\n", tapesize);
|
||||
} else {
|
||||
double fetapes;
|
||||
|
||||
if (blocksperfile)
|
||||
fetapes = (double) tapesize / blocksperfile;
|
||||
else if (cartridge) {
|
||||
/* Estimate number of tapes, assuming streaming stops at
|
||||
the end of each block written, and not in mid-block.
|
||||
Assume no erroneous blocks; this can be compensated
|
||||
for with an artificially low tape size. */
|
||||
fetapes =
|
||||
( tapesize /* blocks */
|
||||
* TP_BSIZE /* bytes/block */
|
||||
* (1.0/density) /* 0.1" / byte */
|
||||
+
|
||||
tapesize /* blocks */
|
||||
* (1.0/ntrec) /* streaming-stops per block */
|
||||
* 15.48 /* 0.1" / streaming-stop */
|
||||
) * (1.0 / tsize ); /* tape / 0.1" */
|
||||
} else {
|
||||
/* Estimate number of tapes, for old fashioned 9-track
|
||||
tape */
|
||||
int tenthsperirg = (density == 625) ? 3 : 7;
|
||||
fetapes =
|
||||
( tapesize /* blocks */
|
||||
* TP_BSIZE /* bytes / block */
|
||||
* (1.0/density) /* 0.1" / byte */
|
||||
+
|
||||
tapesize /* blocks */
|
||||
* (1.0/ntrec) /* IRG's / block */
|
||||
* tenthsperirg /* 0.1" / IRG */
|
||||
) * (1.0 / tsize ); /* tape / 0.1" */
|
||||
}
|
||||
etapes = fetapes; /* truncating assignment */
|
||||
etapes++;
|
||||
/* count the dumped inodes map on each additional tape */
|
||||
tapesize += (etapes - 1) *
|
||||
(howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
|
||||
tapesize += etapes + 10; /* headers + 10 trailer blks */
|
||||
msg("estimated %ld tape blocks on %3.2f tape(s).\n",
|
||||
tapesize, fetapes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate tape buffer.
|
||||
*/
|
||||
if (!alloctape())
|
||||
quit("can't allocate tape buffers - try a smaller blocking factor.\n");
|
||||
|
||||
startnewtape(1);
|
||||
(void)time((time_t *)&(tstart_writing));
|
||||
dumpmap(usedinomap, TS_CLRI, maxino - 1);
|
||||
|
||||
msg("dumping (Pass III) [directories]\n");
|
||||
dirty = 0; /* XXX just to get gcc to shut up */
|
||||
for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
|
||||
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
|
||||
dirty = *map++;
|
||||
else
|
||||
dirty >>= 1;
|
||||
if ((dirty & 1) == 0)
|
||||
continue;
|
||||
/*
|
||||
* Skip directory inodes deleted and maybe reallocated
|
||||
*/
|
||||
dp = getino(ino);
|
||||
if ((dp->di_mode & IFMT) != IFDIR)
|
||||
continue;
|
||||
(void)dumpino(dp, ino);
|
||||
}
|
||||
|
||||
msg("dumping (Pass IV) [regular files]\n");
|
||||
for (map = dumpinomap, ino = 1; ino < maxino; ino++) {
|
||||
int mode;
|
||||
|
||||
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
|
||||
dirty = *map++;
|
||||
else
|
||||
dirty >>= 1;
|
||||
if ((dirty & 1) == 0)
|
||||
continue;
|
||||
/*
|
||||
* Skip inodes deleted and reallocated as directories.
|
||||
*/
|
||||
dp = getino(ino);
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == IFDIR)
|
||||
continue;
|
||||
(void)dumpino(dp, ino);
|
||||
}
|
||||
|
||||
spcl.c_type = TS_END;
|
||||
for (i = 0; i < ntrec; i++)
|
||||
writeheader(maxino - 1);
|
||||
if (pipeout)
|
||||
msg("DUMP: %ld tape blocks\n",spcl.c_tapea);
|
||||
else
|
||||
msg("DUMP: %ld tape blocks on %d volumes(s)\n",
|
||||
spcl.c_tapea, spcl.c_volume);
|
||||
putdumptime();
|
||||
trewind();
|
||||
broadcast("DUMP IS DONE!\7\7\n");
|
||||
msg("DUMP IS DONE\n");
|
||||
Exit(X_FINOK);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Pick up a numeric argument. It must be nonnegative and in the given
|
||||
* range (except that a vmax of 0 means unlimited).
|
||||
*/
|
||||
static long
|
||||
numarg(letter, meaning, vmin, vmax, pargc, pargv)
|
||||
int letter;
|
||||
char *meaning;
|
||||
long vmin, vmax;
|
||||
int *pargc;
|
||||
char ***pargv;
|
||||
{
|
||||
register char *p;
|
||||
long val;
|
||||
char *str;
|
||||
|
||||
if (--*pargc < 0)
|
||||
missingarg(letter, meaning);
|
||||
str = *(*pargv)++;
|
||||
for (p = str; *p; p++)
|
||||
if (!isdigit(*p))
|
||||
goto bad;
|
||||
val = atol(str);
|
||||
if (val < vmin || (vmax && val > vmax))
|
||||
goto bad;
|
||||
return (val);
|
||||
|
||||
bad:
|
||||
(void)fprintf(stderr, "bad '%c' (%s) value \"%s\"\n",
|
||||
letter, meaning, str);
|
||||
exit(X_ABORT);
|
||||
}
|
||||
|
||||
static __dead void
|
||||
missingarg(letter, meaning)
|
||||
int letter;
|
||||
char *meaning;
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "The '%c' flag (%s) requires an argument\n",
|
||||
letter, meaning);
|
||||
exit(X_ABORT);
|
||||
}
|
||||
|
||||
void
|
||||
sig(signo)
|
||||
int signo;
|
||||
{
|
||||
switch(signo) {
|
||||
case SIGALRM:
|
||||
case SIGBUS:
|
||||
case SIGFPE:
|
||||
case SIGHUP:
|
||||
case SIGTERM:
|
||||
case SIGTRAP:
|
||||
if (pipeout)
|
||||
quit("Signal on pipe: cannot recover\n");
|
||||
msg("Rewriting attempted as response to unknown signal.\n");
|
||||
(void)fflush(stderr);
|
||||
(void)fflush(stdout);
|
||||
close_rewind();
|
||||
exit(X_REWRITE);
|
||||
/* NOTREACHED */
|
||||
case SIGSEGV:
|
||||
msg("SIGSEGV: ABORTING!\n");
|
||||
(void)signal(SIGSEGV, SIG_DFL);
|
||||
(void)kill(0, SIGSEGV);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
rawname(cp)
|
||||
char *cp;
|
||||
{
|
||||
static char rawbuf[MAXPATHLEN];
|
||||
char *dp = rindex(cp, '/');
|
||||
|
||||
if (dp == NULL)
|
||||
return (NULL);
|
||||
*dp = '\0';
|
||||
(void)strcpy(rawbuf, cp);
|
||||
*dp = '/';
|
||||
(void)strcat(rawbuf, "/r");
|
||||
(void)strcat(rawbuf, dp + 1);
|
||||
return (rawbuf);
|
||||
}
|
||||
|
||||
#ifdef sunos
|
||||
const char *
|
||||
strerror(errnum)
|
||||
int errnum;
|
||||
{
|
||||
extern int sys_nerr;
|
||||
extern const char *const sys_errlist[];
|
||||
|
||||
if (errnum < sys_nerr)
|
||||
return (sys_errlist[errnum]);
|
||||
else
|
||||
return ("bogus errno in strerror");
|
||||
}
|
||||
#endif
|
||||
538
sbin/dump/optr.c
Normal file
538
sbin/dump/optr.c
Normal file
|
|
@ -0,0 +1,538 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)optr.c 8.2 (Berkeley) 1/6/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fstab.h>
|
||||
#include <grp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#include <tzfile.h>
|
||||
#ifdef __STDC__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <utmp.h>
|
||||
#ifndef __STDC__
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include "dump.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
void alarmcatch __P((/* int, int */));
|
||||
int datesort __P((const void *, const void *));
|
||||
static void sendmes __P((char *, char *));
|
||||
|
||||
/*
|
||||
* Query the operator; This previously-fascist piece of code
|
||||
* no longer requires an exact response.
|
||||
* It is intended to protect dump aborting by inquisitive
|
||||
* people banging on the console terminal to see what is
|
||||
* happening which might cause dump to croak, destroying
|
||||
* a large number of hours of work.
|
||||
*
|
||||
* Every 2 minutes we reprint the message, alerting others
|
||||
* that dump needs attention.
|
||||
*/
|
||||
static int timeout;
|
||||
static char *attnmessage; /* attention message */
|
||||
|
||||
int
|
||||
query(question)
|
||||
char *question;
|
||||
{
|
||||
char replybuffer[64];
|
||||
int back, errcount;
|
||||
FILE *mytty;
|
||||
|
||||
if ((mytty = fopen(_PATH_TTY, "r")) == NULL)
|
||||
quit("fopen on %s fails: %s\n", _PATH_TTY, strerror(errno));
|
||||
attnmessage = question;
|
||||
timeout = 0;
|
||||
alarmcatch();
|
||||
back = -1;
|
||||
errcount = 0;
|
||||
do {
|
||||
if (fgets(replybuffer, 63, mytty) == NULL) {
|
||||
clearerr(mytty);
|
||||
if (++errcount > 30) /* XXX ugly */
|
||||
quit("excessive operator query failures\n");
|
||||
} else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') {
|
||||
back = 1;
|
||||
} else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') {
|
||||
back = 0;
|
||||
} else {
|
||||
(void) fprintf(stderr,
|
||||
" DUMP: \"Yes\" or \"No\"?\n");
|
||||
(void) fprintf(stderr,
|
||||
" DUMP: %s: (\"yes\" or \"no\") ", question);
|
||||
}
|
||||
} while (back < 0);
|
||||
|
||||
/*
|
||||
* Turn off the alarm, and reset the signal to trap out..
|
||||
*/
|
||||
(void) alarm(0);
|
||||
if (signal(SIGALRM, sig) == SIG_IGN)
|
||||
signal(SIGALRM, SIG_IGN);
|
||||
(void) fclose(mytty);
|
||||
return(back);
|
||||
}
|
||||
|
||||
char lastmsg[100];
|
||||
|
||||
/*
|
||||
* Alert the console operator, and enable the alarm clock to
|
||||
* sleep for 2 minutes in case nobody comes to satisfy dump
|
||||
*/
|
||||
void
|
||||
alarmcatch()
|
||||
{
|
||||
if (notify == 0) {
|
||||
if (timeout == 0)
|
||||
(void) fprintf(stderr,
|
||||
" DUMP: %s: (\"yes\" or \"no\") ",
|
||||
attnmessage);
|
||||
else
|
||||
msgtail("\7\7");
|
||||
} else {
|
||||
if (timeout) {
|
||||
msgtail("\n");
|
||||
broadcast(""); /* just print last msg */
|
||||
}
|
||||
(void) fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ",
|
||||
attnmessage);
|
||||
}
|
||||
signal(SIGALRM, alarmcatch);
|
||||
(void) alarm(120);
|
||||
timeout = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here if an inquisitive operator interrupts the dump program
|
||||
*/
|
||||
void
|
||||
interrupt(signo)
|
||||
int signo;
|
||||
{
|
||||
msg("Interrupt received.\n");
|
||||
if (query("Do you want to abort dump?"))
|
||||
dumpabort(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following variables and routines manage alerting
|
||||
* operators to the status of dump.
|
||||
* This works much like wall(1) does.
|
||||
*/
|
||||
struct group *gp;
|
||||
|
||||
/*
|
||||
* Get the names from the group entry "operator" to notify.
|
||||
*/
|
||||
void
|
||||
set_operators()
|
||||
{
|
||||
if (!notify) /*not going to notify*/
|
||||
return;
|
||||
gp = getgrnam(OPGRENT);
|
||||
(void) endgrent();
|
||||
if (gp == NULL) {
|
||||
msg("No group entry for %s.\n", OPGRENT);
|
||||
notify = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct tm *localclock;
|
||||
|
||||
/*
|
||||
* We fork a child to do the actual broadcasting, so
|
||||
* that the process control groups are not messed up
|
||||
*/
|
||||
void
|
||||
broadcast(message)
|
||||
char *message;
|
||||
{
|
||||
time_t clock;
|
||||
FILE *f_utmp;
|
||||
struct utmp utmp;
|
||||
char **np;
|
||||
int pid, s;
|
||||
|
||||
if (!notify || gp == NULL)
|
||||
return;
|
||||
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
return;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
while (wait(&s) != pid)
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
clock = time((time_t *)0);
|
||||
localclock = localtime(&clock);
|
||||
|
||||
if ((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) {
|
||||
msg("Cannot open %s: %s\n", _PATH_UTMP, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while (!feof(f_utmp)) {
|
||||
if (fread((char *) &utmp, sizeof (struct utmp), 1, f_utmp) != 1)
|
||||
break;
|
||||
if (utmp.ut_name[0] == 0)
|
||||
continue;
|
||||
for (np = gp->gr_mem; *np; np++) {
|
||||
if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
|
||||
continue;
|
||||
/*
|
||||
* Do not send messages to operators on dialups
|
||||
*/
|
||||
if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
|
||||
continue;
|
||||
#ifdef DEBUG
|
||||
msg("Message to %s at %s\n", *np, utmp.ut_line);
|
||||
#endif
|
||||
sendmes(utmp.ut_line, message);
|
||||
}
|
||||
}
|
||||
(void) fclose(f_utmp);
|
||||
Exit(0); /* the wait in this same routine will catch this */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
sendmes(tty, message)
|
||||
char *tty, *message;
|
||||
{
|
||||
char t[50], buf[BUFSIZ];
|
||||
register char *cp;
|
||||
int lmsg = 1;
|
||||
FILE *f_tty;
|
||||
|
||||
(void) strcpy(t, _PATH_DEV);
|
||||
(void) strcat(t, tty);
|
||||
|
||||
if ((f_tty = fopen(t, "w")) != NULL) {
|
||||
setbuf(f_tty, buf);
|
||||
(void) fprintf(f_tty,
|
||||
"\n\
|
||||
\7\7\7Message from the dump program to all operators at %d:%02d ...\r\n\n\
|
||||
DUMP: NEEDS ATTENTION: ",
|
||||
localclock->tm_hour, localclock->tm_min);
|
||||
for (cp = lastmsg; ; cp++) {
|
||||
if (*cp == '\0') {
|
||||
if (lmsg) {
|
||||
cp = message;
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
lmsg = 0;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (*cp == '\n')
|
||||
(void) putc('\r', f_tty);
|
||||
(void) putc(*cp, f_tty);
|
||||
}
|
||||
(void) fclose(f_tty);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* print out an estimate of the amount of time left to do the dump
|
||||
*/
|
||||
|
||||
time_t tschedule = 0;
|
||||
|
||||
void
|
||||
timeest()
|
||||
{
|
||||
time_t tnow, deltat;
|
||||
|
||||
(void) time((time_t *) &tnow);
|
||||
if (tnow >= tschedule) {
|
||||
tschedule = tnow + 300;
|
||||
if (blockswritten < 500)
|
||||
return;
|
||||
deltat = tstart_writing - tnow +
|
||||
(1.0 * (tnow - tstart_writing))
|
||||
/ blockswritten * tapesize;
|
||||
msg("%3.2f%% done, finished in %d:%02d\n",
|
||||
(blockswritten * 100.0) / tapesize,
|
||||
deltat / 3600, (deltat % 3600) / 60);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
#if __STDC__
|
||||
msg(const char *fmt, ...)
|
||||
#else
|
||||
msg(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
(void) fprintf(stderr," DUMP: ");
|
||||
#ifdef TDEBUG
|
||||
(void) fprintf(stderr, "pid=%d ", getpid());
|
||||
#endif
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void) vfprintf(stderr, fmt, ap);
|
||||
(void) fflush(stdout);
|
||||
(void) fflush(stderr);
|
||||
(void) vsprintf(lastmsg, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
#if __STDC__
|
||||
msgtail(const char *fmt, ...)
|
||||
#else
|
||||
msgtail(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void) vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
#if __STDC__
|
||||
quit(const char *fmt, ...)
|
||||
#else
|
||||
quit(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
(void) fprintf(stderr," DUMP: ");
|
||||
#ifdef TDEBUG
|
||||
(void) fprintf(stderr, "pid=%d ", getpid());
|
||||
#endif
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void) vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
(void) fflush(stdout);
|
||||
(void) fflush(stderr);
|
||||
dumpabort(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the operator what has to be done;
|
||||
* we don't actually do it
|
||||
*/
|
||||
|
||||
struct fstab *
|
||||
allocfsent(fs)
|
||||
register struct fstab *fs;
|
||||
{
|
||||
register struct fstab *new;
|
||||
|
||||
new = (struct fstab *)malloc(sizeof (*fs));
|
||||
if (new == NULL ||
|
||||
(new->fs_file = strdup(fs->fs_file)) == NULL ||
|
||||
(new->fs_type = strdup(fs->fs_type)) == NULL ||
|
||||
(new->fs_spec = strdup(fs->fs_spec)) == NULL)
|
||||
quit("%s\n", strerror(errno));
|
||||
new->fs_passno = fs->fs_passno;
|
||||
new->fs_freq = fs->fs_freq;
|
||||
return (new);
|
||||
}
|
||||
|
||||
struct pfstab {
|
||||
struct pfstab *pf_next;
|
||||
struct fstab *pf_fstab;
|
||||
};
|
||||
|
||||
static struct pfstab *table;
|
||||
|
||||
void
|
||||
getfstab()
|
||||
{
|
||||
register struct fstab *fs;
|
||||
register struct pfstab *pf;
|
||||
|
||||
if (setfsent() == 0) {
|
||||
msg("Can't open %s for dump table information: %s\n",
|
||||
_PATH_FSTAB, strerror(errno));
|
||||
return;
|
||||
}
|
||||
while ((fs = getfsent()) != NULL) {
|
||||
if (strcmp(fs->fs_type, FSTAB_RW) &&
|
||||
strcmp(fs->fs_type, FSTAB_RO) &&
|
||||
strcmp(fs->fs_type, FSTAB_RQ))
|
||||
continue;
|
||||
fs = allocfsent(fs);
|
||||
if ((pf = (struct pfstab *)malloc(sizeof (*pf))) == NULL)
|
||||
quit("%s\n", strerror(errno));
|
||||
pf->pf_fstab = fs;
|
||||
pf->pf_next = table;
|
||||
table = pf;
|
||||
}
|
||||
(void) endfsent();
|
||||
}
|
||||
|
||||
/*
|
||||
* Search in the fstab for a file name.
|
||||
* This file name can be either the special or the path file name.
|
||||
*
|
||||
* The entries in the fstab are the BLOCK special names, not the
|
||||
* character special names.
|
||||
* The caller of fstabsearch assures that the character device
|
||||
* is dumped (that is much faster)
|
||||
*
|
||||
* The file name can omit the leading '/'.
|
||||
*/
|
||||
struct fstab *
|
||||
fstabsearch(key)
|
||||
char *key;
|
||||
{
|
||||
register struct pfstab *pf;
|
||||
register struct fstab *fs;
|
||||
char *rn;
|
||||
|
||||
for (pf = table; pf != NULL; pf = pf->pf_next) {
|
||||
fs = pf->pf_fstab;
|
||||
if (strcmp(fs->fs_file, key) == 0 ||
|
||||
strcmp(fs->fs_spec, key) == 0)
|
||||
return (fs);
|
||||
rn = rawname(fs->fs_spec);
|
||||
if (rn != NULL && strcmp(rn, key) == 0)
|
||||
return (fs);
|
||||
if (key[0] != '/') {
|
||||
if (*fs->fs_spec == '/' &&
|
||||
strcmp(fs->fs_spec + 1, key) == 0)
|
||||
return (fs);
|
||||
if (*fs->fs_file == '/' &&
|
||||
strcmp(fs->fs_file + 1, key) == 0)
|
||||
return (fs);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the operator what to do
|
||||
*/
|
||||
void
|
||||
lastdump(arg)
|
||||
char arg; /* w ==> just what to do; W ==> most recent dumps */
|
||||
{
|
||||
register int i;
|
||||
register struct fstab *dt;
|
||||
register struct dumpdates *dtwalk;
|
||||
char *lastname, *date;
|
||||
int dumpme;
|
||||
time_t tnow;
|
||||
|
||||
(void) time(&tnow);
|
||||
getfstab(); /* /etc/fstab input */
|
||||
initdumptimes(); /* /etc/dumpdates input */
|
||||
qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
|
||||
|
||||
if (arg == 'w')
|
||||
(void) printf("Dump these file systems:\n");
|
||||
else
|
||||
(void) printf("Last dump(s) done (Dump '>' file systems):\n");
|
||||
lastname = "??";
|
||||
ITITERATE(i, dtwalk) {
|
||||
if (strncmp(lastname, dtwalk->dd_name,
|
||||
sizeof(dtwalk->dd_name)) == 0)
|
||||
continue;
|
||||
date = (char *)ctime(&dtwalk->dd_ddate);
|
||||
date[16] = '\0'; /* blast away seconds and year */
|
||||
lastname = dtwalk->dd_name;
|
||||
dt = fstabsearch(dtwalk->dd_name);
|
||||
dumpme = (dt != NULL &&
|
||||
dt->fs_freq != 0 &&
|
||||
dtwalk->dd_ddate < tnow - (dt->fs_freq * SECSPERDAY));
|
||||
if (arg != 'w' || dumpme)
|
||||
(void) printf(
|
||||
"%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
|
||||
dumpme && (arg != 'w') ? '>' : ' ',
|
||||
dtwalk->dd_name,
|
||||
dt ? dt->fs_file : "",
|
||||
dtwalk->dd_level,
|
||||
date);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
datesort(a1, a2)
|
||||
const void *a1, *a2;
|
||||
{
|
||||
struct dumpdates *d1 = *(struct dumpdates **)a1;
|
||||
struct dumpdates *d2 = *(struct dumpdates **)a2;
|
||||
int diff;
|
||||
|
||||
diff = strncmp(d1->dd_name, d2->dd_name, sizeof(d1->dd_name));
|
||||
if (diff == 0)
|
||||
return (d2->dd_ddate - d1->dd_ddate);
|
||||
return (diff);
|
||||
}
|
||||
42
sbin/dump/pathnames.h
Normal file
42
sbin/dump/pathnames.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_DEFTAPE "/dev/rmt8"
|
||||
#define _PATH_DTMP "/etc/dtmp"
|
||||
#define _PATH_DUMPDATES "/etc/dumpdates"
|
||||
#define _PATH_LOCK "/tmp/dumplockXXXXXX"
|
||||
#define _PATH_RMT "rmt"
|
||||
859
sbin/dump/tape.c
Normal file
859
sbin/dump/tape.c
Normal file
|
|
@ -0,0 +1,859 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)tape.c 8.2 (Berkeley) 3/17/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/fs.h>
|
||||
#include <ufs/inode.h>
|
||||
#else
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#endif
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
int write(), read();
|
||||
#endif
|
||||
|
||||
#include "dump.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
int writesize; /* size of malloc()ed buffer for tape */
|
||||
long lastspclrec = -1; /* tape block number of last written header */
|
||||
int trecno = 0; /* next record to write in current block */
|
||||
extern long blocksperfile; /* number of blocks per output file */
|
||||
long blocksthisvol; /* number of blocks on current output file */
|
||||
extern int ntrec; /* blocking factor on tape */
|
||||
extern int cartridge;
|
||||
extern char *host;
|
||||
char *nexttape;
|
||||
|
||||
static int atomic __P((int (*)(), int, char *, int));
|
||||
static void doslave __P((int, int));
|
||||
static void enslave __P((void));
|
||||
static void flushtape __P((void));
|
||||
static void killall __P((void));
|
||||
static void rollforward __P((void));
|
||||
|
||||
/*
|
||||
* Concurrent dump mods (Caltech) - disk block reading and tape writing
|
||||
* are exported to several slave processes. While one slave writes the
|
||||
* tape, the others read disk blocks; they pass control of the tape in
|
||||
* a ring via signals. The parent process traverses the filesystem and
|
||||
* sends writeheader()'s and lists of daddr's to the slaves via pipes.
|
||||
* The following structure defines the instruction packets sent to slaves.
|
||||
*/
|
||||
struct req {
|
||||
daddr_t dblk;
|
||||
int count;
|
||||
};
|
||||
int reqsiz;
|
||||
|
||||
#define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */
|
||||
struct slave {
|
||||
int tapea; /* header number at start of this chunk */
|
||||
int count; /* count to next header (used for TS_TAPE */
|
||||
/* after EOT) */
|
||||
int inode; /* inode that we are currently dealing with */
|
||||
int fd; /* FD for this slave */
|
||||
int pid; /* PID for this slave */
|
||||
int sent; /* 1 == we've sent this slave requests */
|
||||
int firstrec; /* record number of this block */
|
||||
char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
|
||||
struct req *req; /* buffer for requests */
|
||||
} slaves[SLAVES+1];
|
||||
struct slave *slp;
|
||||
|
||||
char (*nextblock)[TP_BSIZE];
|
||||
|
||||
int master; /* pid of master, for sending error signals */
|
||||
int tenths; /* length of tape used per block written */
|
||||
static int caught; /* have we caught the signal to proceed? */
|
||||
static int ready; /* have we reached the lock point without having */
|
||||
/* received the SIGUSR2 signal from the prev slave? */
|
||||
static jmp_buf jmpbuf; /* where to jump to if we are ready when the */
|
||||
/* SIGUSR2 arrives from the previous slave */
|
||||
|
||||
int
|
||||
alloctape()
|
||||
{
|
||||
int pgoff = getpagesize() - 1;
|
||||
char *buf;
|
||||
int i;
|
||||
|
||||
writesize = ntrec * TP_BSIZE;
|
||||
reqsiz = (ntrec + 1) * sizeof(struct req);
|
||||
/*
|
||||
* CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
|
||||
* (see DEC TU80 User's Guide). The shorter gaps of 6250-bpi require
|
||||
* repositioning after stopping, i.e, streaming mode, where the gap is
|
||||
* variable, 0.30" to 0.45". The gap is maximal when the tape stops.
|
||||
*/
|
||||
if (blocksperfile == 0)
|
||||
tenths = writesize / density +
|
||||
(cartridge ? 16 : density == 625 ? 5 : 8);
|
||||
/*
|
||||
* Allocate tape buffer contiguous with the array of instruction
|
||||
* packets, so flushtape() can write them together with one write().
|
||||
* Align tape buffer on page boundary to speed up tape write().
|
||||
*/
|
||||
for (i = 0; i <= SLAVES; i++) {
|
||||
buf = (char *)
|
||||
malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
|
||||
if (buf == NULL)
|
||||
return(0);
|
||||
slaves[i].tblock = (char (*)[TP_BSIZE])
|
||||
(((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
|
||||
slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
|
||||
}
|
||||
slp = &slaves[0];
|
||||
slp->count = 1;
|
||||
slp->tapea = 0;
|
||||
slp->firstrec = 0;
|
||||
nextblock = slp->tblock;
|
||||
return(1);
|
||||
}
|
||||
|
||||
void
|
||||
writerec(dp, isspcl)
|
||||
char *dp;
|
||||
int isspcl;
|
||||
{
|
||||
|
||||
slp->req[trecno].dblk = (daddr_t)0;
|
||||
slp->req[trecno].count = 1;
|
||||
*(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)dp;
|
||||
if (isspcl)
|
||||
lastspclrec = spcl.c_tapea;
|
||||
trecno++;
|
||||
spcl.c_tapea++;
|
||||
if (trecno >= ntrec)
|
||||
flushtape();
|
||||
}
|
||||
|
||||
void
|
||||
dumpblock(blkno, size)
|
||||
daddr_t blkno;
|
||||
int size;
|
||||
{
|
||||
int avail, tpblks, dblkno;
|
||||
|
||||
dblkno = fsbtodb(sblock, blkno);
|
||||
tpblks = size >> tp_bshift;
|
||||
while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
|
||||
slp->req[trecno].dblk = dblkno;
|
||||
slp->req[trecno].count = avail;
|
||||
trecno += avail;
|
||||
spcl.c_tapea += avail;
|
||||
if (trecno >= ntrec)
|
||||
flushtape();
|
||||
dblkno += avail << (tp_bshift - dev_bshift);
|
||||
tpblks -= avail;
|
||||
}
|
||||
}
|
||||
|
||||
int nogripe = 0;
|
||||
|
||||
void
|
||||
tperror(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (pipeout) {
|
||||
msg("write error on %s\n", tape);
|
||||
quit("Cannot recover\n");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
msg("write error %d blocks into volume %d\n", blocksthisvol, tapeno);
|
||||
broadcast("DUMP WRITE ERROR!\n");
|
||||
if (!query("Do you want to restart?"))
|
||||
dumpabort(0);
|
||||
msg("Closing this volume. Prepare to restart with new media;\n");
|
||||
msg("this dump volume will be rewritten.\n");
|
||||
killall();
|
||||
nogripe = 1;
|
||||
close_rewind();
|
||||
Exit(X_REWRITE);
|
||||
}
|
||||
|
||||
void
|
||||
sigpipe(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
quit("Broken pipe\n");
|
||||
}
|
||||
|
||||
static void
|
||||
flushtape()
|
||||
{
|
||||
int i, blks, got;
|
||||
long lastfirstrec;
|
||||
|
||||
int siz = (char *)nextblock - (char *)slp->req;
|
||||
|
||||
slp->req[trecno].count = 0; /* Sentinel */
|
||||
|
||||
if (atomic(write, slp->fd, (char *)slp->req, siz) != siz)
|
||||
quit("error writing command pipe: %s\n", strerror(errno));
|
||||
slp->sent = 1; /* we sent a request, read the response later */
|
||||
|
||||
lastfirstrec = slp->firstrec;
|
||||
|
||||
if (++slp >= &slaves[SLAVES])
|
||||
slp = &slaves[0];
|
||||
|
||||
/* Read results back from next slave */
|
||||
if (slp->sent) {
|
||||
if (atomic(read, slp->fd, (char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slp->sent = 0;
|
||||
|
||||
/* Check for end of tape */
|
||||
if (got < writesize) {
|
||||
msg("End of tape detected\n");
|
||||
|
||||
/*
|
||||
* Drain the results, don't care what the values were.
|
||||
* If we read them here then trewind won't...
|
||||
*/
|
||||
for (i = 0; i < SLAVES; i++) {
|
||||
if (slaves[i].sent) {
|
||||
if (atomic(read, slaves[i].fd,
|
||||
(char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slaves[i].sent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
close_rewind();
|
||||
rollforward();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
blks = 0;
|
||||
if (spcl.c_type != TS_END) {
|
||||
for (i = 0; i < spcl.c_count; i++)
|
||||
if (spcl.c_addr[i] != 0)
|
||||
blks++;
|
||||
}
|
||||
slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
|
||||
slp->tapea = spcl.c_tapea;
|
||||
slp->firstrec = lastfirstrec + ntrec;
|
||||
slp->inode = curino;
|
||||
nextblock = slp->tblock;
|
||||
trecno = 0;
|
||||
asize += tenths;
|
||||
blockswritten += ntrec;
|
||||
blocksthisvol += ntrec;
|
||||
if (!pipeout && (blocksperfile ?
|
||||
(blocksthisvol >= blocksperfile) : (asize > tsize))) {
|
||||
close_rewind();
|
||||
startnewtape(0);
|
||||
}
|
||||
timeest();
|
||||
}
|
||||
|
||||
void
|
||||
trewind()
|
||||
{
|
||||
int f;
|
||||
int got;
|
||||
|
||||
for (f = 0; f < SLAVES; f++) {
|
||||
/*
|
||||
* Drain the results, but unlike EOT we DO (or should) care
|
||||
* what the return values were, since if we detect EOT after
|
||||
* we think we've written the last blocks to the tape anyway,
|
||||
* we have to replay those blocks with rollforward.
|
||||
*
|
||||
* fixme: punt for now.
|
||||
*/
|
||||
if (slaves[f].sent) {
|
||||
if (atomic(read, slaves[f].fd, (char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slaves[f].sent = 0;
|
||||
if (got != writesize) {
|
||||
msg("EOT detected in last 2 tape records!\n");
|
||||
msg("Use a longer tape, decrease the size estimate\n");
|
||||
quit("or use no size estimate at all.\n");
|
||||
}
|
||||
}
|
||||
(void) close(slaves[f].fd);
|
||||
}
|
||||
while (wait((int *)NULL) >= 0) /* wait for any signals from slaves */
|
||||
/* void */;
|
||||
|
||||
if (pipeout)
|
||||
return;
|
||||
|
||||
msg("Closing %s\n", tape);
|
||||
|
||||
#ifdef RDUMP
|
||||
if (host) {
|
||||
rmtclose();
|
||||
while (rmtopen(tape, 0) < 0)
|
||||
sleep(10);
|
||||
rmtclose();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
(void) close(tapefd);
|
||||
while ((f = open(tape, 0)) < 0)
|
||||
sleep (10);
|
||||
(void) close(f);
|
||||
}
|
||||
|
||||
void
|
||||
close_rewind()
|
||||
{
|
||||
trewind();
|
||||
if (nexttape)
|
||||
return;
|
||||
if (!nogripe) {
|
||||
msg("Change Volumes: Mount volume #%d\n", tapeno+1);
|
||||
broadcast("CHANGE DUMP VOLUMES!\7\7\n");
|
||||
}
|
||||
while (!query("Is the new volume mounted and ready to go?"))
|
||||
if (query("Do you want to abort?")) {
|
||||
dumpabort(0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rollforward()
|
||||
{
|
||||
register struct req *p, *q, *prev;
|
||||
register struct slave *tslp;
|
||||
int i, size, savedtapea, got;
|
||||
union u_spcl *ntb, *otb;
|
||||
tslp = &slaves[SLAVES];
|
||||
ntb = (union u_spcl *)tslp->tblock[1];
|
||||
|
||||
/*
|
||||
* Each of the N slaves should have requests that need to
|
||||
* be replayed on the next tape. Use the extra slave buffers
|
||||
* (slaves[SLAVES]) to construct request lists to be sent to
|
||||
* each slave in turn.
|
||||
*/
|
||||
for (i = 0; i < SLAVES; i++) {
|
||||
q = &tslp->req[1];
|
||||
otb = (union u_spcl *)slp->tblock;
|
||||
|
||||
/*
|
||||
* For each request in the current slave, copy it to tslp.
|
||||
*/
|
||||
|
||||
prev = NULL;
|
||||
for (p = slp->req; p->count > 0; p += p->count) {
|
||||
*q = *p;
|
||||
if (p->dblk == 0)
|
||||
*ntb++ = *otb++; /* copy the datablock also */
|
||||
prev = q;
|
||||
q += q->count;
|
||||
}
|
||||
if (prev == NULL)
|
||||
quit("rollforward: protocol botch");
|
||||
if (prev->dblk != 0)
|
||||
prev->count -= 1;
|
||||
else
|
||||
ntb--;
|
||||
q -= 1;
|
||||
q->count = 0;
|
||||
q = &tslp->req[0];
|
||||
if (i == 0) {
|
||||
q->dblk = 0;
|
||||
q->count = 1;
|
||||
trecno = 0;
|
||||
nextblock = tslp->tblock;
|
||||
savedtapea = spcl.c_tapea;
|
||||
spcl.c_tapea = slp->tapea;
|
||||
startnewtape(0);
|
||||
spcl.c_tapea = savedtapea;
|
||||
lastspclrec = savedtapea - 1;
|
||||
}
|
||||
size = (char *)ntb - (char *)q;
|
||||
if (atomic(write, slp->fd, (char *)q, size) != size) {
|
||||
perror(" DUMP: error writing command pipe");
|
||||
dumpabort(0);
|
||||
}
|
||||
slp->sent = 1;
|
||||
if (++slp >= &slaves[SLAVES])
|
||||
slp = &slaves[0];
|
||||
|
||||
q->count = 1;
|
||||
|
||||
if (prev->dblk != 0) {
|
||||
/*
|
||||
* If the last one was a disk block, make the
|
||||
* first of this one be the last bit of that disk
|
||||
* block...
|
||||
*/
|
||||
q->dblk = prev->dblk +
|
||||
prev->count * (TP_BSIZE / DEV_BSIZE);
|
||||
ntb = (union u_spcl *)tslp->tblock;
|
||||
} else {
|
||||
/*
|
||||
* It wasn't a disk block. Copy the data to its
|
||||
* new location in the buffer.
|
||||
*/
|
||||
q->dblk = 0;
|
||||
*((union u_spcl *)tslp->tblock) = *ntb;
|
||||
ntb = (union u_spcl *)tslp->tblock[1];
|
||||
}
|
||||
}
|
||||
slp->req[0] = *q;
|
||||
nextblock = slp->tblock;
|
||||
if (q->dblk == 0)
|
||||
nextblock++;
|
||||
trecno = 1;
|
||||
|
||||
/*
|
||||
* Clear the first slaves' response. One hopes that it
|
||||
* worked ok, otherwise the tape is much too short!
|
||||
*/
|
||||
if (slp->sent) {
|
||||
if (atomic(read, slp->fd, (char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slp->sent = 0;
|
||||
|
||||
if (got != writesize) {
|
||||
quit("EOT detected at start of the tape!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We implement taking and restoring checkpoints on the tape level.
|
||||
* When each tape is opened, a new process is created by forking; this
|
||||
* saves all of the necessary context in the parent. The child
|
||||
* continues the dump; the parent waits around, saving the context.
|
||||
* If the child returns X_REWRITE, then it had problems writing that tape;
|
||||
* this causes the parent to fork again, duplicating the context, and
|
||||
* everything continues as if nothing had happened.
|
||||
*/
|
||||
void
|
||||
startnewtape(top)
|
||||
int top;
|
||||
{
|
||||
int parentpid;
|
||||
int childpid;
|
||||
int status;
|
||||
int waitpid;
|
||||
char *p;
|
||||
#ifdef sunos
|
||||
void (*interrupt_save)();
|
||||
#else
|
||||
sig_t interrupt_save;
|
||||
#endif
|
||||
|
||||
interrupt_save = signal(SIGINT, SIG_IGN);
|
||||
parentpid = getpid();
|
||||
|
||||
restore_check_point:
|
||||
(void)signal(SIGINT, interrupt_save);
|
||||
/*
|
||||
* All signals are inherited...
|
||||
*/
|
||||
childpid = fork();
|
||||
if (childpid < 0) {
|
||||
msg("Context save fork fails in parent %d\n", parentpid);
|
||||
Exit(X_ABORT);
|
||||
}
|
||||
if (childpid != 0) {
|
||||
/*
|
||||
* PARENT:
|
||||
* save the context by waiting
|
||||
* until the child doing all of the work returns.
|
||||
* don't catch the interrupt
|
||||
*/
|
||||
signal(SIGINT, SIG_IGN);
|
||||
#ifdef TDEBUG
|
||||
msg("Tape: %d; parent process: %d child process %d\n",
|
||||
tapeno+1, parentpid, childpid);
|
||||
#endif /* TDEBUG */
|
||||
while ((waitpid = wait(&status)) != childpid)
|
||||
msg("Parent %d waiting for child %d has another child %d return\n",
|
||||
parentpid, childpid, waitpid);
|
||||
if (status & 0xFF) {
|
||||
msg("Child %d returns LOB status %o\n",
|
||||
childpid, status&0xFF);
|
||||
}
|
||||
status = (status >> 8) & 0xFF;
|
||||
#ifdef TDEBUG
|
||||
switch(status) {
|
||||
case X_FINOK:
|
||||
msg("Child %d finishes X_FINOK\n", childpid);
|
||||
break;
|
||||
case X_ABORT:
|
||||
msg("Child %d finishes X_ABORT\n", childpid);
|
||||
break;
|
||||
case X_REWRITE:
|
||||
msg("Child %d finishes X_REWRITE\n", childpid);
|
||||
break;
|
||||
default:
|
||||
msg("Child %d finishes unknown %d\n",
|
||||
childpid, status);
|
||||
break;
|
||||
}
|
||||
#endif /* TDEBUG */
|
||||
switch(status) {
|
||||
case X_FINOK:
|
||||
Exit(X_FINOK);
|
||||
case X_ABORT:
|
||||
Exit(X_ABORT);
|
||||
case X_REWRITE:
|
||||
goto restore_check_point;
|
||||
default:
|
||||
msg("Bad return code from dump: %d\n", status);
|
||||
Exit(X_ABORT);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
} else { /* we are the child; just continue */
|
||||
#ifdef TDEBUG
|
||||
sleep(4); /* allow time for parent's message to get out */
|
||||
msg("Child on Tape %d has parent %d, my pid = %d\n",
|
||||
tapeno+1, parentpid, getpid());
|
||||
#endif /* TDEBUG */
|
||||
/*
|
||||
* If we have a name like "/dev/rmt0,/dev/rmt1",
|
||||
* use the name before the comma first, and save
|
||||
* the remaining names for subsequent volumes.
|
||||
*/
|
||||
tapeno++; /* current tape sequence */
|
||||
if (nexttape || index(tape, ',')) {
|
||||
if (nexttape && *nexttape)
|
||||
tape = nexttape;
|
||||
if ((p = index(tape, ',')) != NULL) {
|
||||
*p = '\0';
|
||||
nexttape = p + 1;
|
||||
} else
|
||||
nexttape = NULL;
|
||||
msg("Dumping volume %d on %s\n", tapeno, tape);
|
||||
}
|
||||
#ifdef RDUMP
|
||||
while ((tapefd = (host ? rmtopen(tape, 2) :
|
||||
pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
|
||||
#else
|
||||
while ((tapefd = (pipeout ? 1 :
|
||||
open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
|
||||
#endif
|
||||
{
|
||||
msg("Cannot open output \"%s\".\n", tape);
|
||||
if (!query("Do you want to retry the open?"))
|
||||
dumpabort(0);
|
||||
}
|
||||
|
||||
enslave(); /* Share open tape file descriptor with slaves */
|
||||
|
||||
asize = 0;
|
||||
blocksthisvol = 0;
|
||||
if (top)
|
||||
newtape++; /* new tape signal */
|
||||
spcl.c_count = slp->count;
|
||||
/*
|
||||
* measure firstrec in TP_BSIZE units since restore doesn't
|
||||
* know the correct ntrec value...
|
||||
*/
|
||||
spcl.c_firstrec = slp->firstrec;
|
||||
spcl.c_volume++;
|
||||
spcl.c_type = TS_TAPE;
|
||||
spcl.c_flags |= DR_NEWHEADER;
|
||||
writeheader((ino_t)slp->inode);
|
||||
spcl.c_flags &=~ DR_NEWHEADER;
|
||||
if (tapeno > 1)
|
||||
msg("Volume %d begins with blocks from inode %d\n",
|
||||
tapeno, slp->inode);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dumpabort(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (master != 0 && master != getpid())
|
||||
/* Signals master to call dumpabort */
|
||||
(void) kill(master, SIGTERM);
|
||||
else {
|
||||
killall();
|
||||
msg("The ENTIRE dump is aborted.\n");
|
||||
}
|
||||
#ifdef RDUMP
|
||||
rmtclose();
|
||||
#endif
|
||||
Exit(X_ABORT);
|
||||
}
|
||||
|
||||
__dead void
|
||||
Exit(status)
|
||||
int status;
|
||||
{
|
||||
|
||||
#ifdef TDEBUG
|
||||
msg("pid = %d exits with status %d\n", getpid(), status);
|
||||
#endif /* TDEBUG */
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
|
||||
*/
|
||||
void
|
||||
proceed(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (ready)
|
||||
longjmp(jmpbuf, 1);
|
||||
caught++;
|
||||
}
|
||||
|
||||
void
|
||||
enslave()
|
||||
{
|
||||
int cmd[2];
|
||||
register int i, j;
|
||||
|
||||
master = getpid();
|
||||
|
||||
signal(SIGTERM, dumpabort); /* Slave sends SIGTERM on dumpabort() */
|
||||
signal(SIGPIPE, sigpipe);
|
||||
signal(SIGUSR1, tperror); /* Slave sends SIGUSR1 on tape errors */
|
||||
signal(SIGUSR2, proceed); /* Slave sends SIGUSR2 to next slave */
|
||||
|
||||
for (i = 0; i < SLAVES; i++) {
|
||||
if (i == slp - &slaves[0]) {
|
||||
caught = 1;
|
||||
} else {
|
||||
caught = 0;
|
||||
}
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
|
||||
(slaves[i].pid = fork()) < 0)
|
||||
quit("too many slaves, %d (recompile smaller): %s\n",
|
||||
i, strerror(errno));
|
||||
|
||||
slaves[i].fd = cmd[1];
|
||||
slaves[i].sent = 0;
|
||||
if (slaves[i].pid == 0) { /* Slave starts up here */
|
||||
for (j = 0; j <= i; j++)
|
||||
(void) close(slaves[j].fd);
|
||||
signal(SIGINT, SIG_IGN); /* Master handles this */
|
||||
doslave(cmd[0], i);
|
||||
Exit(X_FINOK);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < SLAVES; i++)
|
||||
(void) atomic(write, slaves[i].fd,
|
||||
(char *) &slaves[(i + 1) % SLAVES].pid,
|
||||
sizeof slaves[0].pid);
|
||||
|
||||
master = 0;
|
||||
}
|
||||
|
||||
void
|
||||
killall()
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < SLAVES; i++)
|
||||
if (slaves[i].pid > 0)
|
||||
(void) kill(slaves[i].pid, SIGKILL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronization - each process has a lockfile, and shares file
|
||||
* descriptors to the following process's lockfile. When our write
|
||||
* completes, we release our lock on the following process's lock-
|
||||
* file, allowing the following process to lock it and proceed. We
|
||||
* get the lock back for the next cycle by swapping descriptors.
|
||||
*/
|
||||
static void
|
||||
doslave(cmd, slave_number)
|
||||
register int cmd;
|
||||
int slave_number;
|
||||
{
|
||||
register int nread;
|
||||
int nextslave, size, wrote, eot_count;
|
||||
|
||||
/*
|
||||
* Need our own seek pointer.
|
||||
*/
|
||||
(void) close(diskfd);
|
||||
if ((diskfd = open(disk, O_RDONLY)) < 0)
|
||||
quit("slave couldn't reopen disk: %s\n", strerror(errno));
|
||||
|
||||
/*
|
||||
* Need the pid of the next slave in the loop...
|
||||
*/
|
||||
if ((nread = atomic(read, cmd, (char *)&nextslave, sizeof nextslave))
|
||||
!= sizeof nextslave) {
|
||||
quit("master/slave protocol botched - didn't get pid of next slave.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get list of blocks to dump, read the blocks into tape buffer
|
||||
*/
|
||||
while ((nread = atomic(read, cmd, (char *)slp->req, reqsiz)) == reqsiz) {
|
||||
register struct req *p = slp->req;
|
||||
|
||||
for (trecno = 0; trecno < ntrec;
|
||||
trecno += p->count, p += p->count) {
|
||||
if (p->dblk) {
|
||||
bread(p->dblk, slp->tblock[trecno],
|
||||
p->count * TP_BSIZE);
|
||||
} else {
|
||||
if (p->count != 1 || atomic(read, cmd,
|
||||
(char *)slp->tblock[trecno],
|
||||
TP_BSIZE) != TP_BSIZE)
|
||||
quit("master/slave protocol botched.\n");
|
||||
}
|
||||
}
|
||||
if (setjmp(jmpbuf) == 0) {
|
||||
ready = 1;
|
||||
if (!caught)
|
||||
(void) pause();
|
||||
}
|
||||
ready = 0;
|
||||
caught = 0;
|
||||
|
||||
/* Try to write the data... */
|
||||
eot_count = 0;
|
||||
size = 0;
|
||||
|
||||
while (eot_count < 10 && size < writesize) {
|
||||
#ifdef RDUMP
|
||||
if (host)
|
||||
wrote = rmtwrite(slp->tblock[0]+size,
|
||||
writesize-size);
|
||||
else
|
||||
#endif
|
||||
wrote = write(tapefd, slp->tblock[0]+size,
|
||||
writesize-size);
|
||||
#ifdef WRITEDEBUG
|
||||
printf("slave %d wrote %d\n", slave_number, wrote);
|
||||
#endif
|
||||
if (wrote < 0)
|
||||
break;
|
||||
if (wrote == 0)
|
||||
eot_count++;
|
||||
size += wrote;
|
||||
}
|
||||
|
||||
#ifdef WRITEDEBUG
|
||||
if (size != writesize)
|
||||
printf("slave %d only wrote %d out of %d bytes and gave up.\n",
|
||||
slave_number, size, writesize);
|
||||
#endif
|
||||
|
||||
if (eot_count > 0)
|
||||
size = 0;
|
||||
|
||||
/*
|
||||
* fixme: Pyramids running OSx return ENOSPC
|
||||
* at EOT on 1/2 inch drives.
|
||||
*/
|
||||
if (size < 0) {
|
||||
(void) kill(master, SIGUSR1);
|
||||
for (;;)
|
||||
(void) sigpause(0);
|
||||
} else {
|
||||
/*
|
||||
* pass size of write back to master
|
||||
* (for EOT handling)
|
||||
*/
|
||||
(void) atomic(write, cmd, (char *)&size, sizeof size);
|
||||
}
|
||||
|
||||
/*
|
||||
* If partial write, don't want next slave to go.
|
||||
* Also jolts him awake.
|
||||
*/
|
||||
(void) kill(nextslave, SIGUSR2);
|
||||
}
|
||||
if (nread != 0)
|
||||
quit("error reading command pipe: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
* Since a read from a pipe may not return all we asked for,
|
||||
* or a write may not write all we ask if we get a signal,
|
||||
* loop until the count is satisfied (or error).
|
||||
*/
|
||||
static int
|
||||
atomic(func, fd, buf, count)
|
||||
int (*func)(), fd;
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
int got, need = count;
|
||||
|
||||
while ((got = (*func)(fd, buf, need)) > 0 && (need -= got) > 0)
|
||||
buf += got;
|
||||
return (got < 0 ? got : count - need);
|
||||
}
|
||||
613
sbin/dump/traverse.c
Normal file
613
sbin/dump/traverse.c
Normal file
|
|
@ -0,0 +1,613 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1988, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)traverse.c 8.2 (Berkeley) 9/23/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/fs.h>
|
||||
#include <ufs/fsdir.h>
|
||||
#include <ufs/inode.h>
|
||||
#else
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#endif
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "dump.h"
|
||||
|
||||
#define HASDUMPEDFILE 0x1
|
||||
#define HASSUBDIRS 0x2
|
||||
|
||||
#ifdef FS_44INODEFMT
|
||||
typedef quad_t fsizeT;
|
||||
#else
|
||||
typedef long fsizeT;
|
||||
#endif
|
||||
|
||||
static int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size));
|
||||
static void dmpindir __P((ino_t ino, daddr_t blk, int level, fsizeT *size));
|
||||
static int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize));
|
||||
|
||||
/*
|
||||
* This is an estimation of the number of TP_BSIZE blocks in the file.
|
||||
* It estimates the number of blocks in files with holes by assuming
|
||||
* that all of the blocks accounted for by di_blocks are data blocks
|
||||
* (when some of the blocks are usually used for indirect pointers);
|
||||
* hence the estimate may be high.
|
||||
*/
|
||||
long
|
||||
blockest(dp)
|
||||
register struct dinode *dp;
|
||||
{
|
||||
long blkest, sizeest;
|
||||
|
||||
/*
|
||||
* dp->di_size is the size of the file in bytes.
|
||||
* dp->di_blocks stores the number of sectors actually in the file.
|
||||
* If there are more sectors than the size would indicate, this just
|
||||
* means that there are indirect blocks in the file or unused
|
||||
* sectors in the last file block; we can safely ignore these
|
||||
* (blkest = sizeest below).
|
||||
* If the file is bigger than the number of sectors would indicate,
|
||||
* then the file has holes in it. In this case we must use the
|
||||
* block count to estimate the number of data blocks used, but
|
||||
* we use the actual size for estimating the number of indirect
|
||||
* dump blocks (sizeest vs. blkest in the indirect block
|
||||
* calculation).
|
||||
*/
|
||||
blkest = howmany(dbtob(dp->di_blocks), TP_BSIZE);
|
||||
sizeest = howmany(dp->di_size, TP_BSIZE);
|
||||
if (blkest > sizeest)
|
||||
blkest = sizeest;
|
||||
if (dp->di_size > sblock->fs_bsize * NDADDR) {
|
||||
/* calculate the number of indirect blocks on the dump tape */
|
||||
blkest +=
|
||||
howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE,
|
||||
TP_NINDIR);
|
||||
}
|
||||
return (blkest + 1);
|
||||
}
|
||||
|
||||
/* Auxiliary macro to pick up files changed since previous dump. */
|
||||
#ifdef FS_44INODEFMT
|
||||
#define CHANGEDSINCE(dp, t) \
|
||||
((dp)->di_mtime.ts_sec >= (t) || (dp)->di_ctime.ts_sec >= (t))
|
||||
#else
|
||||
#define CHANGEDSINCE(dp, t) \
|
||||
((dp)->di_mtime >= (t) || (dp)->di_ctime >= (t))
|
||||
#endif
|
||||
|
||||
/* The WANTTODUMP macro decides whether a file should be dumped. */
|
||||
#ifdef UF_NODUMP
|
||||
#define WANTTODUMP(dp) \
|
||||
(CHANGEDSINCE(dp, spcl.c_ddate) && \
|
||||
(nonodump || ((dp)->di_flags & UF_NODUMP) != UF_NODUMP))
|
||||
#else
|
||||
#define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dump pass 1.
|
||||
*
|
||||
* Walk the inode list for a filesystem to find all allocated inodes
|
||||
* that have been modified since the previous dump time. Also, find all
|
||||
* the directories in the filesystem.
|
||||
*/
|
||||
int
|
||||
mapfiles(maxino, tapesize)
|
||||
ino_t maxino;
|
||||
long *tapesize;
|
||||
{
|
||||
register int mode;
|
||||
register ino_t ino;
|
||||
register struct dinode *dp;
|
||||
int anydirskipped = 0;
|
||||
|
||||
for (ino = ROOTINO; ino < maxino; ino++) {
|
||||
dp = getino(ino);
|
||||
if ((mode = (dp->di_mode & IFMT)) == 0)
|
||||
continue;
|
||||
SETINO(ino, usedinomap);
|
||||
if (mode == IFDIR)
|
||||
SETINO(ino, dumpdirmap);
|
||||
if (WANTTODUMP(dp)) {
|
||||
SETINO(ino, dumpinomap);
|
||||
if (mode != IFREG && mode != IFDIR && mode != IFLNK)
|
||||
*tapesize += 1;
|
||||
else
|
||||
*tapesize += blockest(dp);
|
||||
continue;
|
||||
}
|
||||
if (mode == IFDIR)
|
||||
anydirskipped = 1;
|
||||
}
|
||||
/*
|
||||
* Restore gets very upset if the root is not dumped,
|
||||
* so ensure that it always is dumped.
|
||||
*/
|
||||
SETINO(ROOTINO, dumpinomap);
|
||||
return (anydirskipped);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump pass 2.
|
||||
*
|
||||
* Scan each directory on the filesystem to see if it has any modified
|
||||
* files in it. If it does, and has not already been added to the dump
|
||||
* list (because it was itself modified), then add it. If a directory
|
||||
* has not been modified itself, contains no modified files and has no
|
||||
* subdirectories, then it can be deleted from the dump list and from
|
||||
* the list of directories. By deleting it from the list of directories,
|
||||
* its parent may now qualify for the same treatment on this or a later
|
||||
* pass using this algorithm.
|
||||
*/
|
||||
int
|
||||
mapdirs(maxino, tapesize)
|
||||
ino_t maxino;
|
||||
long *tapesize;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register int i, isdir;
|
||||
register char *map;
|
||||
register ino_t ino;
|
||||
long filesize;
|
||||
int ret, change = 0;
|
||||
|
||||
isdir = 0; /* XXX just to get gcc to shut up */
|
||||
for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
|
||||
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
|
||||
isdir = *map++;
|
||||
else
|
||||
isdir >>= 1;
|
||||
if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap))
|
||||
continue;
|
||||
dp = getino(ino);
|
||||
filesize = dp->di_size;
|
||||
for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
|
||||
if (dp->di_db[i] != 0)
|
||||
ret |= searchdir(ino, dp->di_db[i],
|
||||
(long)dblksize(sblock, dp, i),
|
||||
filesize);
|
||||
if (ret & HASDUMPEDFILE)
|
||||
filesize = 0;
|
||||
else
|
||||
filesize -= sblock->fs_bsize;
|
||||
}
|
||||
for (i = 0; filesize > 0 && i < NIADDR; i++) {
|
||||
if (dp->di_ib[i] == 0)
|
||||
continue;
|
||||
ret |= dirindir(ino, dp->di_ib[i], i, &filesize);
|
||||
}
|
||||
if (ret & HASDUMPEDFILE) {
|
||||
SETINO(ino, dumpinomap);
|
||||
*tapesize += blockest(dp);
|
||||
change = 1;
|
||||
continue;
|
||||
}
|
||||
if ((ret & HASSUBDIRS) == 0) {
|
||||
if (!TSTINO(ino, dumpinomap)) {
|
||||
CLRINO(ino, dumpdirmap);
|
||||
change = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (change);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read indirect blocks, and pass the data blocks to be searched
|
||||
* as directories. Quit as soon as any entry is found that will
|
||||
* require the directory to be dumped.
|
||||
*/
|
||||
static int
|
||||
dirindir(ino, blkno, ind_level, filesize)
|
||||
ino_t ino;
|
||||
daddr_t blkno;
|
||||
int ind_level;
|
||||
long *filesize;
|
||||
{
|
||||
int ret = 0;
|
||||
register int i;
|
||||
daddr_t idblk[MAXNINDIR];
|
||||
|
||||
bread(fsbtodb(sblock, blkno), (char *)idblk, (int)sblock->fs_bsize);
|
||||
if (ind_level <= 0) {
|
||||
for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
|
||||
blkno = idblk[i];
|
||||
if (blkno != 0)
|
||||
ret |= searchdir(ino, blkno, sblock->fs_bsize,
|
||||
*filesize);
|
||||
if (ret & HASDUMPEDFILE)
|
||||
*filesize = 0;
|
||||
else
|
||||
*filesize -= sblock->fs_bsize;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
ind_level--;
|
||||
for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
|
||||
blkno = idblk[i];
|
||||
if (blkno != 0)
|
||||
ret |= dirindir(ino, blkno, ind_level, filesize);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan a disk block containing directory information looking to see if
|
||||
* any of the entries are on the dump list and to see if the directory
|
||||
* contains any subdirectories.
|
||||
*/
|
||||
static int
|
||||
searchdir(ino, blkno, size, filesize)
|
||||
ino_t ino;
|
||||
daddr_t blkno;
|
||||
register long size;
|
||||
long filesize;
|
||||
{
|
||||
register struct direct *dp;
|
||||
register long loc, ret = 0;
|
||||
char dblk[MAXBSIZE];
|
||||
|
||||
bread(fsbtodb(sblock, blkno), dblk, (int)size);
|
||||
if (filesize < size)
|
||||
size = filesize;
|
||||
for (loc = 0; loc < size; ) {
|
||||
dp = (struct direct *)(dblk + loc);
|
||||
if (dp->d_reclen == 0) {
|
||||
msg("corrupted directory, inumber %d\n", ino);
|
||||
break;
|
||||
}
|
||||
loc += dp->d_reclen;
|
||||
if (dp->d_ino == 0)
|
||||
continue;
|
||||
if (dp->d_name[0] == '.') {
|
||||
if (dp->d_name[1] == '\0')
|
||||
continue;
|
||||
if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
|
||||
continue;
|
||||
}
|
||||
if (TSTINO(dp->d_ino, dumpinomap)) {
|
||||
ret |= HASDUMPEDFILE;
|
||||
if (ret & HASSUBDIRS)
|
||||
break;
|
||||
}
|
||||
if (TSTINO(dp->d_ino, dumpdirmap)) {
|
||||
ret |= HASSUBDIRS;
|
||||
if (ret & HASDUMPEDFILE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump passes 3 and 4.
|
||||
*
|
||||
* Dump the contents of an inode to tape.
|
||||
*/
|
||||
void
|
||||
dumpino(dp, ino)
|
||||
register struct dinode *dp;
|
||||
ino_t ino;
|
||||
{
|
||||
int ind_level, cnt;
|
||||
fsizeT size;
|
||||
char buf[TP_BSIZE];
|
||||
|
||||
if (newtape) {
|
||||
newtape = 0;
|
||||
dumpmap(dumpinomap, TS_BITS, ino);
|
||||
}
|
||||
CLRINO(ino, dumpinomap);
|
||||
spcl.c_dinode = *dp;
|
||||
spcl.c_type = TS_INODE;
|
||||
spcl.c_count = 0;
|
||||
switch (dp->di_mode & S_IFMT) {
|
||||
|
||||
case 0:
|
||||
/*
|
||||
* Freed inode.
|
||||
*/
|
||||
return;
|
||||
|
||||
case S_IFLNK:
|
||||
/*
|
||||
* Check for short symbolic link.
|
||||
*/
|
||||
#ifdef FS_44INODEFMT
|
||||
if (dp->di_size > 0 &&
|
||||
dp->di_size < sblock->fs_maxsymlinklen) {
|
||||
spcl.c_addr[0] = 1;
|
||||
spcl.c_count = 1;
|
||||
writeheader(ino);
|
||||
bcopy((caddr_t)dp->di_shortlink, buf,
|
||||
(u_long)dp->di_size);
|
||||
buf[dp->di_size] = '\0';
|
||||
writerec(buf, 0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* fall through */
|
||||
|
||||
case S_IFDIR:
|
||||
case S_IFREG:
|
||||
if (dp->di_size > 0)
|
||||
break;
|
||||
/* fall through */
|
||||
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
writeheader(ino);
|
||||
return;
|
||||
|
||||
default:
|
||||
msg("Warning: undefined file type 0%o\n", dp->di_mode & IFMT);
|
||||
return;
|
||||
}
|
||||
if (dp->di_size > NDADDR * sblock->fs_bsize)
|
||||
cnt = NDADDR * sblock->fs_frag;
|
||||
else
|
||||
cnt = howmany(dp->di_size, sblock->fs_fsize);
|
||||
blksout(&dp->di_db[0], cnt, ino);
|
||||
if ((size = dp->di_size - NDADDR * sblock->fs_bsize) <= 0)
|
||||
return;
|
||||
for (ind_level = 0; ind_level < NIADDR; ind_level++) {
|
||||
dmpindir(ino, dp->di_ib[ind_level], ind_level, &size);
|
||||
if (size <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read indirect blocks, and pass the data blocks to be dumped.
|
||||
*/
|
||||
static void
|
||||
dmpindir(ino, blk, ind_level, size)
|
||||
ino_t ino;
|
||||
daddr_t blk;
|
||||
int ind_level;
|
||||
fsizeT *size;
|
||||
{
|
||||
int i, cnt;
|
||||
daddr_t idblk[MAXNINDIR];
|
||||
|
||||
if (blk != 0)
|
||||
bread(fsbtodb(sblock, blk), (char *)idblk, (int) sblock->fs_bsize);
|
||||
else
|
||||
bzero((char *)idblk, (int)sblock->fs_bsize);
|
||||
if (ind_level <= 0) {
|
||||
if (*size < NINDIR(sblock) * sblock->fs_bsize)
|
||||
cnt = howmany(*size, sblock->fs_fsize);
|
||||
else
|
||||
cnt = NINDIR(sblock) * sblock->fs_frag;
|
||||
*size -= NINDIR(sblock) * sblock->fs_bsize;
|
||||
blksout(&idblk[0], cnt, ino);
|
||||
return;
|
||||
}
|
||||
ind_level--;
|
||||
for (i = 0; i < NINDIR(sblock); i++) {
|
||||
dmpindir(ino, idblk[i], ind_level, size);
|
||||
if (*size <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect up the data into tape record sized buffers and output them.
|
||||
*/
|
||||
void
|
||||
blksout(blkp, frags, ino)
|
||||
daddr_t *blkp;
|
||||
int frags;
|
||||
ino_t ino;
|
||||
{
|
||||
register daddr_t *bp;
|
||||
int i, j, count, blks, tbperdb;
|
||||
|
||||
blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
|
||||
tbperdb = sblock->fs_bsize >> tp_bshift;
|
||||
for (i = 0; i < blks; i += TP_NINDIR) {
|
||||
if (i + TP_NINDIR > blks)
|
||||
count = blks;
|
||||
else
|
||||
count = i + TP_NINDIR;
|
||||
for (j = i; j < count; j++)
|
||||
if (blkp[j / tbperdb] != 0)
|
||||
spcl.c_addr[j - i] = 1;
|
||||
else
|
||||
spcl.c_addr[j - i] = 0;
|
||||
spcl.c_count = count - i;
|
||||
writeheader(ino);
|
||||
bp = &blkp[i / tbperdb];
|
||||
for (j = i; j < count; j += tbperdb, bp++)
|
||||
if (*bp != 0)
|
||||
if (j + tbperdb <= count)
|
||||
dumpblock(*bp, (int)sblock->fs_bsize);
|
||||
else
|
||||
dumpblock(*bp, (count - j) * TP_BSIZE);
|
||||
spcl.c_type = TS_ADDR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump a map to the tape.
|
||||
*/
|
||||
void
|
||||
dumpmap(map, type, ino)
|
||||
char *map;
|
||||
int type;
|
||||
ino_t ino;
|
||||
{
|
||||
register int i;
|
||||
char *cp;
|
||||
|
||||
spcl.c_type = type;
|
||||
spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE);
|
||||
writeheader(ino);
|
||||
for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
|
||||
writerec(cp, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a header record to the dump tape.
|
||||
*/
|
||||
void
|
||||
writeheader(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
register long sum, cnt, *lp;
|
||||
|
||||
spcl.c_inumber = ino;
|
||||
spcl.c_magic = NFS_MAGIC;
|
||||
spcl.c_checksum = 0;
|
||||
lp = (long *)&spcl;
|
||||
sum = 0;
|
||||
cnt = sizeof(union u_spcl) / (4 * sizeof(long));
|
||||
while (--cnt >= 0) {
|
||||
sum += *lp++;
|
||||
sum += *lp++;
|
||||
sum += *lp++;
|
||||
sum += *lp++;
|
||||
}
|
||||
spcl.c_checksum = CHECKSUM - sum;
|
||||
writerec((char *)&spcl, 1);
|
||||
}
|
||||
|
||||
struct dinode *
|
||||
getino(inum)
|
||||
ino_t inum;
|
||||
{
|
||||
static daddr_t minino, maxino;
|
||||
static struct dinode inoblock[MAXINOPB];
|
||||
|
||||
curino = inum;
|
||||
if (inum >= minino && inum < maxino)
|
||||
return (&inoblock[inum - minino]);
|
||||
bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), (char *)inoblock,
|
||||
(int)sblock->fs_bsize);
|
||||
minino = inum - (inum % INOPB(sblock));
|
||||
maxino = minino + INOPB(sblock);
|
||||
return (&inoblock[inum - minino]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a chunk of data from the disk.
|
||||
* Try to recover from hard errors by reading in sector sized pieces.
|
||||
* Error recovery is attempted at most BREADEMAX times before seeking
|
||||
* consent from the operator to continue.
|
||||
*/
|
||||
int breaderrors = 0;
|
||||
#define BREADEMAX 32
|
||||
|
||||
void
|
||||
bread(blkno, buf, size)
|
||||
daddr_t blkno;
|
||||
char *buf;
|
||||
int size;
|
||||
{
|
||||
int cnt, i;
|
||||
extern int errno;
|
||||
|
||||
loop:
|
||||
if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) < 0)
|
||||
msg("bread: lseek fails\n");
|
||||
if ((cnt = read(diskfd, buf, size)) == size)
|
||||
return;
|
||||
if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
|
||||
/*
|
||||
* Trying to read the final fragment.
|
||||
*
|
||||
* NB - dump only works in TP_BSIZE blocks, hence
|
||||
* rounds `dev_bsize' fragments up to TP_BSIZE pieces.
|
||||
* It should be smarter about not actually trying to
|
||||
* read more than it can get, but for the time being
|
||||
* we punt and scale back the read only when it gets
|
||||
* us into trouble. (mkm 9/25/83)
|
||||
*/
|
||||
size -= dev_bsize;
|
||||
goto loop;
|
||||
}
|
||||
if (cnt == -1)
|
||||
msg("read error from %s: %s: [block %d]: count=%d\n",
|
||||
disk, strerror(errno), blkno, size);
|
||||
else
|
||||
msg("short read error from %s: [block %d]: count=%d, got=%d\n",
|
||||
disk, blkno, size, cnt);
|
||||
if (++breaderrors > BREADEMAX) {
|
||||
msg("More than %d block read errors from %d\n",
|
||||
BREADEMAX, disk);
|
||||
broadcast("DUMP IS AILING!\n");
|
||||
msg("This is an unrecoverable error.\n");
|
||||
if (!query("Do you want to attempt to continue?")){
|
||||
dumpabort(0);
|
||||
/*NOTREACHED*/
|
||||
} else
|
||||
breaderrors = 0;
|
||||
}
|
||||
/*
|
||||
* Zero buffer, then try to read each sector of buffer separately.
|
||||
*/
|
||||
bzero(buf, size);
|
||||
for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) {
|
||||
if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) < 0)
|
||||
msg("bread: lseek2 fails!\n");
|
||||
if ((cnt = read(diskfd, buf, (int)dev_bsize)) == dev_bsize)
|
||||
continue;
|
||||
if (cnt == -1) {
|
||||
msg("read error from %s: %s: [sector %d]: count=%d\n",
|
||||
disk, strerror(errno), blkno, dev_bsize);
|
||||
continue;
|
||||
}
|
||||
msg("short read error from %s: [sector %d]: count=%d, got=%d\n",
|
||||
disk, blkno, dev_bsize, cnt);
|
||||
}
|
||||
}
|
||||
157
sbin/dump/unctime.c
Normal file
157
sbin/dump/unctime.c
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)unctime.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifndef __P
|
||||
#include <sys/cdefs.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convert a ctime(3) format string into a system format date.
|
||||
* Return the date thus calculated.
|
||||
*
|
||||
* Return -1 if the string is not in ctime format.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Offsets into the ctime string to various parts.
|
||||
*/
|
||||
|
||||
#define E_MONTH 4
|
||||
#define E_DAY 8
|
||||
#define E_HOUR 11
|
||||
#define E_MINUTE 14
|
||||
#define E_SECOND 17
|
||||
#define E_YEAR 20
|
||||
|
||||
static int dcmp __P((struct tm *, struct tm *));
|
||||
static time_t emitl __P((struct tm *));
|
||||
static int lookup __P((char *));
|
||||
|
||||
|
||||
time_t
|
||||
unctime(str)
|
||||
char *str;
|
||||
{
|
||||
struct tm then;
|
||||
char dbuf[26];
|
||||
|
||||
(void) strncpy(dbuf, str, sizeof(dbuf) - 1);
|
||||
dbuf[sizeof(dbuf) - 1] = '\0';
|
||||
dbuf[E_MONTH+3] = '\0';
|
||||
if ((then.tm_mon = lookup(&dbuf[E_MONTH])) < 0)
|
||||
return (-1);
|
||||
then.tm_mday = atoi(&dbuf[E_DAY]);
|
||||
then.tm_hour = atoi(&dbuf[E_HOUR]);
|
||||
then.tm_min = atoi(&dbuf[E_MINUTE]);
|
||||
then.tm_sec = atoi(&dbuf[E_SECOND]);
|
||||
then.tm_year = atoi(&dbuf[E_YEAR]) - 1900;
|
||||
return(emitl(&then));
|
||||
}
|
||||
|
||||
static char months[] =
|
||||
"JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
|
||||
static int
|
||||
lookup(str)
|
||||
char *str;
|
||||
{
|
||||
register char *cp, *cp2;
|
||||
|
||||
for (cp = months, cp2 = str; *cp != '\0'; cp += 3)
|
||||
if (strncmp(cp, cp2, 3) == 0)
|
||||
return((cp-months) / 3);
|
||||
return(-1);
|
||||
}
|
||||
/*
|
||||
* Routine to convert a localtime(3) format date back into
|
||||
* a system format date.
|
||||
*
|
||||
* Use a binary search.
|
||||
*/
|
||||
|
||||
static time_t
|
||||
emitl(dp)
|
||||
struct tm *dp;
|
||||
{
|
||||
time_t conv;
|
||||
register int i, bit;
|
||||
struct tm dcopy;
|
||||
|
||||
dcopy = *dp;
|
||||
dp = &dcopy;
|
||||
conv = 0;
|
||||
for (i = 30; i >= 0; i--) {
|
||||
bit = 1 << i;
|
||||
conv |= bit;
|
||||
if (dcmp(localtime(&conv), dp) > 0)
|
||||
conv &= ~bit;
|
||||
}
|
||||
return(conv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two localtime dates, return result.
|
||||
*/
|
||||
|
||||
#define DECIDE(a) \
|
||||
if (dp->a > dp2->a) \
|
||||
return(1); \
|
||||
if (dp->a < dp2->a) \
|
||||
return(-1)
|
||||
|
||||
static int
|
||||
dcmp(dp, dp2)
|
||||
register struct tm *dp, *dp2;
|
||||
{
|
||||
|
||||
DECIDE(tm_year);
|
||||
DECIDE(tm_mon);
|
||||
DECIDE(tm_mday);
|
||||
DECIDE(tm_hour);
|
||||
DECIDE(tm_min);
|
||||
DECIDE(tm_sec);
|
||||
return(0);
|
||||
}
|
||||
6
sbin/dumpfs/Makefile
Normal file
6
sbin/dumpfs/Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= dumpfs
|
||||
MAN8= dumpfs.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
62
sbin/dumpfs/dumpfs.8
Normal file
62
sbin/dumpfs/dumpfs.8
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)dumpfs.8 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.Dd June 5, 1993
|
||||
.Dt DUMPFS 8
|
||||
.Os BSD 4.2
|
||||
.Sh NAME
|
||||
.Nm dumpfs
|
||||
.Nd dump file system information
|
||||
.Sh SYNOPSIS
|
||||
.Nm dumpfs
|
||||
.Op Ar filesys No \&| Ar device
|
||||
.Sh DESCRIPTION
|
||||
.Nm Dumpfs
|
||||
prints out the super block and cylinder group information
|
||||
for the file system or special device specified.
|
||||
The listing is very long and detailed. This
|
||||
command is useful mostly for finding out certain file system
|
||||
information such as the file system block size and minimum
|
||||
free space percentage.
|
||||
.Sh SEE ALSO
|
||||
.Xr fs 5 ,
|
||||
.Xr disktab 5 ,
|
||||
.Xr disklabel 8 ,
|
||||
.Xr tunefs 8 ,
|
||||
.Xr newfs 8 ,
|
||||
.Xr fsck 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
315
sbin/dumpfs/dumpfs.c
Normal file
315
sbin/dumpfs/dumpfs.c
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1992, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dumpfs.c 8.2 (Berkeley) 2/2/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <fstab.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
union {
|
||||
struct fs fs;
|
||||
char pad[MAXBSIZE];
|
||||
} fsun;
|
||||
#define afs fsun.fs
|
||||
|
||||
union {
|
||||
struct cg cg;
|
||||
char pad[MAXBSIZE];
|
||||
} cgun;
|
||||
#define acg cgun.cg
|
||||
|
||||
long dev_bsize = 1;
|
||||
|
||||
int dumpfs __P((char *));
|
||||
int dumpcg __P((char *, int, int));
|
||||
void pbits __P((void *, int));
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register struct fstab *fs;
|
||||
int ch, eval;
|
||||
|
||||
while ((ch = getopt(argc, argv, "")) != EOF)
|
||||
switch(ch) {
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1)
|
||||
usage();
|
||||
|
||||
for (eval = 0; *argv; ++argv)
|
||||
if ((fs = getfsfile(*argv)) == NULL)
|
||||
eval |= dumpfs(*argv);
|
||||
else
|
||||
eval |= dumpfs(fs->fs_spec);
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
int
|
||||
dumpfs(name)
|
||||
char *name;
|
||||
{
|
||||
int fd, c, i, j, k, size;
|
||||
|
||||
if ((fd = open(name, O_RDONLY, 0)) < 0)
|
||||
goto err;
|
||||
if (lseek(fd, (off_t)SBOFF, SEEK_SET) == (off_t)-1)
|
||||
goto err;
|
||||
if (read(fd, &afs, SBSIZE) != SBSIZE)
|
||||
goto err;
|
||||
|
||||
if (afs.fs_postblformat == FS_42POSTBLFMT)
|
||||
afs.fs_nrpos = 8;
|
||||
dev_bsize = afs.fs_fsize / fsbtodb(&afs, 1);
|
||||
printf("magic\t%x\ttime\t%s", afs.fs_magic,
|
||||
ctime(&afs.fs_time));
|
||||
printf("cylgrp\t%s\tinodes\t%s\n",
|
||||
afs.fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic",
|
||||
afs.fs_inodefmt < FS_44INODEFMT ? "4.2/4.3BSD" : "4.4BSD");
|
||||
printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
|
||||
afs.fs_cstotal.cs_nbfree, afs.fs_cstotal.cs_ndir,
|
||||
afs.fs_cstotal.cs_nifree, afs.fs_cstotal.cs_nffree);
|
||||
printf("ncg\t%d\tncyl\t%d\tsize\t%d\tblocks\t%d\n",
|
||||
afs.fs_ncg, afs.fs_ncyl, afs.fs_size, afs.fs_dsize);
|
||||
printf("bsize\t%d\tshift\t%d\tmask\t0x%08x\n",
|
||||
afs.fs_bsize, afs.fs_bshift, afs.fs_bmask);
|
||||
printf("fsize\t%d\tshift\t%d\tmask\t0x%08x\n",
|
||||
afs.fs_fsize, afs.fs_fshift, afs.fs_fmask);
|
||||
printf("frag\t%d\tshift\t%d\tfsbtodb\t%d\n",
|
||||
afs.fs_frag, afs.fs_fragshift, afs.fs_fsbtodb);
|
||||
printf("cpg\t%d\tbpg\t%d\tfpg\t%d\tipg\t%d\n",
|
||||
afs.fs_cpg, afs.fs_fpg / afs.fs_frag, afs.fs_fpg, afs.fs_ipg);
|
||||
printf("minfree\t%d%%\toptim\t%s\tmaxcontig %d\tmaxbpg\t%d\n",
|
||||
afs.fs_minfree, afs.fs_optim == FS_OPTSPACE ? "space" : "time",
|
||||
afs.fs_maxcontig, afs.fs_maxbpg);
|
||||
printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
|
||||
afs.fs_rotdelay, afs.fs_headswitch, afs.fs_trkseek, afs.fs_rps);
|
||||
printf("ntrak\t%d\tnsect\t%d\tnpsect\t%d\tspc\t%d\n",
|
||||
afs.fs_ntrak, afs.fs_nsect, afs.fs_npsect, afs.fs_spc);
|
||||
printf("symlinklen %d\ttrackskew %d\tinterleave %d\tcontigsumsize %d\n",
|
||||
afs.fs_maxsymlinklen, afs.fs_trackskew, afs.fs_interleave,
|
||||
afs.fs_contigsumsize);
|
||||
printf("nindir\t%d\tinopb\t%d\tnspf\t%d\n",
|
||||
afs.fs_nindir, afs.fs_inopb, afs.fs_nspf);
|
||||
printf("sblkno\t%d\tcblkno\t%d\tiblkno\t%d\tdblkno\t%d\n",
|
||||
afs.fs_sblkno, afs.fs_cblkno, afs.fs_iblkno, afs.fs_dblkno);
|
||||
printf("sbsize\t%d\tcgsize\t%d\tcgoffset %d\tcgmask\t0x%08x\n",
|
||||
afs.fs_sbsize, afs.fs_cgsize, afs.fs_cgoffset, afs.fs_cgmask);
|
||||
printf("csaddr\t%d\tcssize\t%d\tshift\t%d\tmask\t0x%08x\n",
|
||||
afs.fs_csaddr, afs.fs_cssize, afs.fs_csshift, afs.fs_csmask);
|
||||
printf("cgrotor\t%d\tfmod\t%d\tronly\t%d\n",
|
||||
afs.fs_cgrotor, afs.fs_fmod, afs.fs_ronly);
|
||||
if (afs.fs_cpc != 0)
|
||||
printf("blocks available in each of %d rotational positions",
|
||||
afs.fs_nrpos);
|
||||
else
|
||||
printf("insufficient space to maintain rotational tables\n");
|
||||
for (c = 0; c < afs.fs_cpc; c++) {
|
||||
printf("\ncylinder number %d:", c);
|
||||
for (i = 0; i < afs.fs_nrpos; i++) {
|
||||
if (fs_postbl(&afs, c)[i] == -1)
|
||||
continue;
|
||||
printf("\n position %d:\t", i);
|
||||
for (j = fs_postbl(&afs, c)[i], k = 1; ;
|
||||
j += fs_rotbl(&afs)[j], k++) {
|
||||
printf("%5d", j);
|
||||
if (k % 12 == 0)
|
||||
printf("\n\t\t");
|
||||
if (fs_rotbl(&afs)[j] == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t");
|
||||
for (i = 0, j = 0; i < afs.fs_cssize; i += afs.fs_bsize, j++) {
|
||||
size = afs.fs_cssize - i < afs.fs_bsize ?
|
||||
afs.fs_cssize - i : afs.fs_bsize;
|
||||
afs.fs_csp[j] = calloc(1, size);
|
||||
if (lseek(fd,
|
||||
(off_t)(fsbtodb(&afs, (afs.fs_csaddr + j * afs.fs_frag)) *
|
||||
dev_bsize), SEEK_SET) == (off_t)-1)
|
||||
goto err;
|
||||
if (read(fd, afs.fs_csp[j], size) != size)
|
||||
goto err;
|
||||
}
|
||||
for (i = 0; i < afs.fs_ncg; i++) {
|
||||
struct csum *cs = &afs.fs_cs(&afs, i);
|
||||
if (i && i % 4 == 0)
|
||||
printf("\n\t");
|
||||
printf("(%d,%d,%d,%d) ",
|
||||
cs->cs_nbfree, cs->cs_ndir, cs->cs_nifree, cs->cs_nffree);
|
||||
}
|
||||
printf("\n");
|
||||
if (afs.fs_ncyl % afs.fs_cpg) {
|
||||
printf("cylinders in last group %d\n",
|
||||
i = afs.fs_ncyl % afs.fs_cpg);
|
||||
printf("blocks in last group %d\n",
|
||||
i * afs.fs_spc / NSPB(&afs));
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < afs.fs_ncg; i++)
|
||||
if (dumpcg(name, fd, i))
|
||||
goto err;
|
||||
(void)close(fd);
|
||||
return (0);
|
||||
|
||||
err: if (fd != -1)
|
||||
(void)close(fd);
|
||||
(void)fprintf(stderr, "dumpfs: %s: %s\n", name, strerror(errno));
|
||||
return (1);
|
||||
};
|
||||
|
||||
int
|
||||
dumpcg(name, fd, c)
|
||||
char *name;
|
||||
int fd, c;
|
||||
{
|
||||
off_t cur;
|
||||
int i, j;
|
||||
|
||||
printf("\ncg %d:\n", c);
|
||||
if ((cur = lseek(fd, (off_t)(fsbtodb(&afs, cgtod(&afs, c)) * dev_bsize),
|
||||
SEEK_SET)) == (off_t)-1)
|
||||
return (1);
|
||||
if (read(fd, &acg, afs.fs_bsize) != afs.fs_bsize) {
|
||||
(void)fprintf(stderr, "dumpfs: %s: error reading cg\n", name);
|
||||
return (1);
|
||||
}
|
||||
printf("magic\t%x\ttell\t%qx\ttime\t%s",
|
||||
afs.fs_postblformat == FS_42POSTBLFMT ?
|
||||
((struct ocg *)&acg)->cg_magic : acg.cg_magic,
|
||||
cur, ctime(&acg.cg_time));
|
||||
printf("cgx\t%d\tncyl\t%d\tniblk\t%d\tndblk\t%d\n",
|
||||
acg.cg_cgx, acg.cg_ncyl, acg.cg_niblk, acg.cg_ndblk);
|
||||
printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
|
||||
acg.cg_cs.cs_nbfree, acg.cg_cs.cs_ndir,
|
||||
acg.cg_cs.cs_nifree, acg.cg_cs.cs_nffree);
|
||||
printf("rotor\t%d\tirotor\t%d\tfrotor\t%d\nfrsum",
|
||||
acg.cg_rotor, acg.cg_irotor, acg.cg_frotor);
|
||||
for (i = 1, j = 0; i < afs.fs_frag; i++) {
|
||||
printf("\t%d", acg.cg_frsum[i]);
|
||||
j += i * acg.cg_frsum[i];
|
||||
}
|
||||
printf("\nsum of frsum: %d", j);
|
||||
if (afs.fs_contigsumsize > 0) {
|
||||
for (i = 1; i < afs.fs_contigsumsize; i++) {
|
||||
if ((i - 1) % 8 == 0)
|
||||
printf("\nclusters %d-%d:", i,
|
||||
afs.fs_contigsumsize - 1 < i + 7 ?
|
||||
afs.fs_contigsumsize - 1 : i + 7);
|
||||
printf("\t%d", cg_clustersum(&acg)[i]);
|
||||
}
|
||||
printf("\nclusters size %d and over: %d\n",
|
||||
afs.fs_contigsumsize,
|
||||
cg_clustersum(&acg)[afs.fs_contigsumsize]);
|
||||
printf("clusters free:\t");
|
||||
pbits(cg_clustersfree(&acg), acg.cg_nclusterblks);
|
||||
} else
|
||||
printf("\n");
|
||||
printf("iused:\t");
|
||||
pbits(cg_inosused(&acg), afs.fs_ipg);
|
||||
printf("free:\t");
|
||||
pbits(cg_blksfree(&acg), afs.fs_fpg);
|
||||
printf("b:\n");
|
||||
for (i = 0; i < afs.fs_cpg; i++) {
|
||||
if (cg_blktot(&acg)[i] == 0)
|
||||
continue;
|
||||
printf(" c%d:\t(%d)\t", i, cg_blktot(&acg)[i]);
|
||||
for (j = 0; j < afs.fs_nrpos; j++) {
|
||||
if (afs.fs_cpc > 0 &&
|
||||
fs_postbl(&afs, i % afs.fs_cpc)[j] == -1)
|
||||
continue;
|
||||
printf(" %d", cg_blks(&afs, &acg, i)[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
return (0);
|
||||
};
|
||||
|
||||
void
|
||||
pbits(vp, max)
|
||||
register void *vp;
|
||||
int max;
|
||||
{
|
||||
register int i;
|
||||
register char *p;
|
||||
int count, j;
|
||||
|
||||
for (count = i = 0, p = vp; i < max; i++)
|
||||
if (isset(p, i)) {
|
||||
if (count)
|
||||
printf(",%s", count % 6 ? " " : "\n\t");
|
||||
count++;
|
||||
printf("%d", i);
|
||||
j = i;
|
||||
while ((i+1)<max && isset(p, i+1))
|
||||
i++;
|
||||
if (i != j)
|
||||
printf("-%d", i);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage: dumpfs filesys | device\n");
|
||||
exit(1);
|
||||
}
|
||||
9
sbin/dumplfs/Makefile
Normal file
9
sbin/dumplfs/Makefile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/18/93
|
||||
|
||||
PROG= dumplfs
|
||||
CFLAGS+=-I/sys/ufs/lfs
|
||||
SRCS= dumplfs.c lfs_cksum.c misc.c
|
||||
.PATH: /sys/ufs/lfs
|
||||
MAN8= dumplfs.0
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
59
sbin/dumplfs/dumplfs.8
Normal file
59
sbin/dumplfs/dumplfs.8
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
.\" Copyright (c) 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)dumplfs.8 8.1 (Berkeley) 6/18/93
|
||||
.\"
|
||||
.Dd June 18, 1993
|
||||
.Dt DUMPLFS 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm dumplfs
|
||||
.Nd dump file system information
|
||||
.Sh SYNOPSIS
|
||||
.Nm dumplfs
|
||||
.Op Ar filesys No \&| Ar device
|
||||
.Sh DESCRIPTION
|
||||
.Nm Dumplfs
|
||||
prints out the file system layout information for the
|
||||
LFS file system or special device specified.
|
||||
The listing is very long and detailed.
|
||||
This command is useful mostly for finding out certain file system
|
||||
information such as the file system block size.
|
||||
.Sh SEE ALSO
|
||||
.Xr fs 5 ,
|
||||
.Xr disktab 5 ,
|
||||
.Xr disklabel 8 ,
|
||||
.Xr newlfs 8 ,
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm dumplfs
|
||||
command appeared in
|
||||
.Bx 4.4 .
|
||||
612
sbin/dumplfs/dumplfs.c
Normal file
612
sbin/dumplfs/dumplfs.c
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1991, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dumplfs.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/lfs/lfs.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fstab.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "extern.h"
|
||||
|
||||
static void addseg __P((char *));
|
||||
static void dump_cleaner_info __P((struct lfs *, void *));
|
||||
static void dump_dinode __P((struct dinode *));
|
||||
static void dump_ifile __P((int, struct lfs *, int));
|
||||
static int dump_ipage_ifile __P((int, IFILE *, int));
|
||||
static int dump_ipage_segusage __P((struct lfs *, int, IFILE *, int));
|
||||
static void dump_segment __P((int, int, daddr_t, struct lfs *, int));
|
||||
static int dump_sum __P((int, struct lfs *, SEGSUM *, int, daddr_t));
|
||||
static void dump_super __P((struct lfs *));
|
||||
static void usage __P((void));
|
||||
|
||||
typedef struct seglist SEGLIST;
|
||||
struct seglist {
|
||||
SEGLIST *next;
|
||||
int num;
|
||||
};
|
||||
SEGLIST *seglist;
|
||||
|
||||
int daddr_shift;
|
||||
char *special;
|
||||
|
||||
/* Segment Usage formats */
|
||||
#define print_suheader \
|
||||
(void)printf("segnum\tflags\tnbytes\tninos\tnsums\tlastmod\n")
|
||||
|
||||
#define print_suentry(i, sp) \
|
||||
(void)printf("%d\t%c%c%c\t%d\t%d\t%d\t%s", i, \
|
||||
(((sp)->su_flags & SEGUSE_ACTIVE) ? 'A' : ' '), \
|
||||
(((sp)->su_flags & SEGUSE_DIRTY) ? 'D' : 'C'), \
|
||||
(((sp)->su_flags & SEGUSE_SUPERBLOCK) ? 'S' : ' '), \
|
||||
(sp)->su_nbytes, (sp)->su_ninos, (sp)->su_nsums, \
|
||||
ctime((time_t *)&(sp)->su_lastmod))
|
||||
|
||||
/* Ifile formats */
|
||||
#define print_iheader \
|
||||
(void)printf("inum\tstatus\tversion\tdaddr\t\tfreeptr\n")
|
||||
#define print_ientry(i, ip) \
|
||||
if (ip->if_daddr == LFS_UNUSED_DADDR) \
|
||||
(void)printf("%d\tFREE\t%d\t \t\t%d\n", \
|
||||
i, ip->if_version, ip->if_nextfree); \
|
||||
else \
|
||||
(void)printf("%d\tINUSE\t%d\t%8X \n", \
|
||||
i, ip->if_version, ip->if_daddr)
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct lfs lfs_sb1, lfs_sb2, *lfs_master;
|
||||
daddr_t seg_addr;
|
||||
int ch, do_allsb, do_ientries, fd, segnum;
|
||||
|
||||
do_allsb = 0;
|
||||
do_ientries = 0;
|
||||
while ((ch = getopt(argc, argv, "ais:")) != EOF)
|
||||
switch(ch) {
|
||||
case 'a': /* Dump all superblocks */
|
||||
do_allsb = 1;
|
||||
break;
|
||||
case 'i': /* Dump ifile entries */
|
||||
do_ientries = 1;
|
||||
break;
|
||||
case 's': /* Dump out these segments */
|
||||
addseg(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 1)
|
||||
usage();
|
||||
|
||||
special = argv[0];
|
||||
if ((fd = open(special, O_RDONLY, 0)) < 0)
|
||||
err("%s: %s", special, strerror(errno));
|
||||
|
||||
/* Read the first superblock */
|
||||
get(fd, LFS_LABELPAD, &lfs_sb1, sizeof(struct lfs));
|
||||
daddr_shift = lfs_sb1.lfs_bshift - lfs_sb1.lfs_fsbtodb;
|
||||
|
||||
/*
|
||||
* Read the second superblock and figure out which check point is
|
||||
* most up to date.
|
||||
*/
|
||||
get(fd,
|
||||
lfs_sb1.lfs_sboffs[1] << daddr_shift, &lfs_sb2, sizeof(struct lfs));
|
||||
|
||||
lfs_master = &lfs_sb1;
|
||||
if (lfs_sb1.lfs_tstamp < lfs_sb2.lfs_tstamp)
|
||||
lfs_master = &lfs_sb2;
|
||||
|
||||
(void)printf("Master Superblock:\n");
|
||||
dump_super(lfs_master);
|
||||
|
||||
dump_ifile(fd, lfs_master, do_ientries);
|
||||
|
||||
if (seglist != NULL)
|
||||
for (; seglist != NULL; seglist = seglist->next) {
|
||||
seg_addr = lfs_master->lfs_sboffs[0] + seglist->num *
|
||||
(lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb);
|
||||
dump_segment(fd,
|
||||
seglist->num, seg_addr, lfs_master, do_allsb);
|
||||
}
|
||||
else
|
||||
for (segnum = 0, seg_addr = lfs_master->lfs_sboffs[0];
|
||||
segnum < lfs_master->lfs_nseg; segnum++, seg_addr +=
|
||||
lfs_master->lfs_ssize << lfs_master->lfs_fsbtodb)
|
||||
dump_segment(fd,
|
||||
segnum, seg_addr, lfs_master, do_allsb);
|
||||
|
||||
(void)close(fd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are reading all the blocks of an inode and dumping out the ifile table.
|
||||
* This code could be tighter, but this is a first pass at getting the stuff
|
||||
* printed out rather than making this code incredibly efficient.
|
||||
*/
|
||||
static void
|
||||
dump_ifile(fd, lfsp, do_ientries)
|
||||
int fd;
|
||||
struct lfs *lfsp;
|
||||
int do_ientries;
|
||||
{
|
||||
IFILE *ipage;
|
||||
struct dinode *dip, *dpage;
|
||||
daddr_t addr, *addrp, *dindir, *iaddrp, *indir;
|
||||
int block_limit, i, inum, j, nblocks, nsupb, psize;
|
||||
|
||||
psize = lfsp->lfs_bsize;
|
||||
addr = lfsp->lfs_idaddr;
|
||||
|
||||
if (!(dpage = malloc(psize)))
|
||||
err("%s", strerror(errno));
|
||||
get(fd, addr << daddr_shift, dpage, psize);
|
||||
|
||||
for (dip = dpage + INOPB(lfsp) - 1; dip >= dpage; --dip)
|
||||
if (dip->di_inumber == LFS_IFILE_INUM)
|
||||
break;
|
||||
|
||||
if (dip < dpage)
|
||||
err("unable to locate ifile inode");
|
||||
|
||||
(void)printf("\nIFILE inode\n");
|
||||
dump_dinode(dip);
|
||||
|
||||
(void)printf("\nIFILE contents\n");
|
||||
nblocks = dip->di_size >> lfsp->lfs_bshift;
|
||||
block_limit = MIN(nblocks, NDADDR);
|
||||
|
||||
/* Get the direct block */
|
||||
if ((ipage = malloc(psize)) == NULL)
|
||||
err("%s", strerror(errno));
|
||||
for (inum = 0, addrp = dip->di_db, i = 0; i < block_limit;
|
||||
i++, addrp++) {
|
||||
get(fd, *addrp << daddr_shift, ipage, psize);
|
||||
if (i < lfsp->lfs_cleansz) {
|
||||
dump_cleaner_info(lfsp, ipage);
|
||||
print_suheader;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < (lfsp->lfs_segtabsz + lfsp->lfs_cleansz)) {
|
||||
inum = dump_ipage_segusage(lfsp, inum, ipage,
|
||||
lfsp->lfs_sepb);
|
||||
if (!inum)
|
||||
if(!do_ientries)
|
||||
goto e0;
|
||||
else
|
||||
print_iheader;
|
||||
} else
|
||||
inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb);
|
||||
|
||||
}
|
||||
|
||||
if (nblocks <= NDADDR)
|
||||
goto e0;
|
||||
|
||||
/* Dump out blocks off of single indirect block */
|
||||
if (!(indir = malloc(psize)))
|
||||
err("%s", strerror(errno));
|
||||
get(fd, dip->di_ib[0] << daddr_shift, indir, psize);
|
||||
block_limit = MIN(i + lfsp->lfs_nindir, nblocks);
|
||||
for (addrp = indir; i < block_limit; i++, addrp++) {
|
||||
if (*addrp == LFS_UNUSED_DADDR)
|
||||
break;
|
||||
get(fd, *addrp << daddr_shift,ipage, psize);
|
||||
if (i < lfsp->lfs_cleansz) {
|
||||
dump_cleaner_info(lfsp, ipage);
|
||||
continue;
|
||||
} else
|
||||
i -= lfsp->lfs_cleansz;
|
||||
|
||||
if (i < lfsp->lfs_segtabsz) {
|
||||
inum = dump_ipage_segusage(lfsp, inum, ipage,
|
||||
lfsp->lfs_sepb);
|
||||
if (!inum)
|
||||
if(!do_ientries)
|
||||
goto e1;
|
||||
else
|
||||
print_iheader;
|
||||
} else
|
||||
inum = dump_ipage_ifile(inum, ipage, lfsp->lfs_ifpb);
|
||||
}
|
||||
|
||||
if (nblocks <= lfsp->lfs_nindir * lfsp->lfs_ifpb)
|
||||
goto e1;
|
||||
|
||||
/* Get the double indirect block */
|
||||
if (!(dindir = malloc(psize)))
|
||||
err("%s", strerror(errno));
|
||||
get(fd, dip->di_ib[1] << daddr_shift, dindir, psize);
|
||||
for (iaddrp = dindir, j = 0; j < lfsp->lfs_nindir; j++, iaddrp++) {
|
||||
if (*iaddrp == LFS_UNUSED_DADDR)
|
||||
break;
|
||||
get(fd, *iaddrp << daddr_shift, indir, psize);
|
||||
block_limit = MIN(i + lfsp->lfs_nindir, nblocks);
|
||||
for (addrp = indir; i < block_limit; i++, addrp++) {
|
||||
if (*addrp == LFS_UNUSED_DADDR)
|
||||
break;
|
||||
get(fd, *addrp << daddr_shift, ipage, psize);
|
||||
if (i < lfsp->lfs_cleansz) {
|
||||
dump_cleaner_info(lfsp, ipage);
|
||||
continue;
|
||||
} else
|
||||
i -= lfsp->lfs_cleansz;
|
||||
|
||||
if (i < lfsp->lfs_segtabsz) {
|
||||
inum = dump_ipage_segusage(lfsp,
|
||||
inum, ipage, lfsp->lfs_sepb);
|
||||
if (!inum)
|
||||
if(!do_ientries)
|
||||
goto e2;
|
||||
else
|
||||
print_iheader;
|
||||
} else
|
||||
inum = dump_ipage_ifile(inum,
|
||||
ipage, lfsp->lfs_ifpb);
|
||||
}
|
||||
}
|
||||
e2: free(dindir);
|
||||
e1: free(indir);
|
||||
e0: free(dpage);
|
||||
free(ipage);
|
||||
}
|
||||
|
||||
static int
|
||||
dump_ipage_ifile(i, pp, tot)
|
||||
int i;
|
||||
IFILE *pp;
|
||||
int tot;
|
||||
{
|
||||
IFILE *ip;
|
||||
int cnt, max;
|
||||
|
||||
max = i + tot;
|
||||
|
||||
for (ip = pp, cnt = i; cnt < max; cnt++, ip++)
|
||||
print_ientry(cnt, ip);
|
||||
return (max);
|
||||
}
|
||||
|
||||
static int
|
||||
dump_ipage_segusage(lfsp, i, pp, tot)
|
||||
struct lfs *lfsp;
|
||||
int i;
|
||||
IFILE *pp;
|
||||
int tot;
|
||||
{
|
||||
SEGUSE *sp;
|
||||
int cnt, max;
|
||||
|
||||
max = i + tot;
|
||||
for (sp = (SEGUSE *)pp, cnt = i;
|
||||
cnt < lfsp->lfs_nseg && cnt < max; cnt++, sp++)
|
||||
print_suentry(cnt, sp);
|
||||
if (max >= lfsp->lfs_nseg)
|
||||
return (0);
|
||||
else
|
||||
return (max);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_dinode(dip)
|
||||
struct dinode *dip;
|
||||
{
|
||||
int i;
|
||||
|
||||
(void)printf("%s%d\t%s%d\t%s%d\t%s%d\t%s%d\n",
|
||||
"mode ", dip->di_mode,
|
||||
"nlink ", dip->di_nlink,
|
||||
"uid ", dip->di_uid,
|
||||
"gid ", dip->di_gid,
|
||||
"size ", dip->di_size);
|
||||
(void)printf("%s%s%s%s%s%s",
|
||||
"atime ", ctime(&dip->di_atime.ts_sec),
|
||||
"mtime ", ctime(&dip->di_mtime.ts_sec),
|
||||
"ctime ", ctime(&dip->di_ctime.ts_sec));
|
||||
(void)printf("inum %d\n", dip->di_inumber);
|
||||
(void)printf("Direct Addresses\n");
|
||||
for (i = 0; i < NDADDR; i++) {
|
||||
(void)printf("\t0x%X", dip->di_db[i]);
|
||||
if ((i % 6) == 5)
|
||||
(void)printf("\n");
|
||||
}
|
||||
for (i = 0; i < NIADDR; i++)
|
||||
(void)printf("\t0x%X", dip->di_ib[i]);
|
||||
(void)printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
dump_sum(fd, lfsp, sp, segnum, addr)
|
||||
struct lfs *lfsp;
|
||||
SEGSUM *sp;
|
||||
int fd, segnum;
|
||||
daddr_t addr;
|
||||
{
|
||||
FINFO *fp;
|
||||
long *dp;
|
||||
int i, j;
|
||||
int ck;
|
||||
int numblocks;
|
||||
struct dinode *inop;
|
||||
|
||||
if (sp->ss_sumsum != (ck = cksum(&sp->ss_datasum,
|
||||
LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum)))) {
|
||||
(void)printf("dumplfs: %s %d address 0x%lx\n",
|
||||
"corrupt summary block; segment", segnum, addr);
|
||||
return(0);
|
||||
}
|
||||
|
||||
(void)printf("Segment Summary Info at 0x%lx\n", addr);
|
||||
(void)printf(" %s0x%X\t%s%d\t%s%d\n %s0x%X\t%s0x%X",
|
||||
"next ", sp->ss_next,
|
||||
"nfinfo ", sp->ss_nfinfo,
|
||||
"ninos ", sp->ss_ninos,
|
||||
"sumsum ", sp->ss_sumsum,
|
||||
"datasum ", sp->ss_datasum );
|
||||
(void)printf("\tcreate %s", ctime((time_t *)&sp->ss_create));
|
||||
|
||||
numblocks = (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
|
||||
|
||||
/* Dump out inode disk addresses */
|
||||
dp = (daddr_t *)sp;
|
||||
dp += LFS_SUMMARY_SIZE / sizeof(daddr_t);
|
||||
inop = malloc(1 << lfsp->lfs_bshift);
|
||||
printf(" Inode addresses:");
|
||||
for (dp--, i = 0; i < sp->ss_ninos; dp--) {
|
||||
printf("\t0x%X {", *dp);
|
||||
get(fd, *dp << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb), inop,
|
||||
(1 << lfsp->lfs_bshift));
|
||||
for (j = 0; i < sp->ss_ninos && j < INOPB(lfsp); j++, i++) {
|
||||
if (j > 0)
|
||||
(void)printf(", ");
|
||||
(void)printf("%d", inop[j].di_inumber);
|
||||
}
|
||||
(void)printf("}");
|
||||
if (((i/INOPB(lfsp)) % 4) == 3)
|
||||
(void)printf("\n");
|
||||
}
|
||||
free(inop);
|
||||
|
||||
printf("\n");
|
||||
for (fp = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo; i++) {
|
||||
numblocks += fp->fi_nblocks;
|
||||
(void)printf(" FINFO for inode: %d version %d nblocks %d\n",
|
||||
fp->fi_ino, fp->fi_version, fp->fi_nblocks);
|
||||
dp = &(fp->fi_blocks[0]);
|
||||
for (j = 0; j < fp->fi_nblocks; j++, dp++) {
|
||||
(void)printf("\t%d", *dp);
|
||||
if ((j % 8) == 7)
|
||||
(void)printf("\n");
|
||||
}
|
||||
if ((j % 8) != 0)
|
||||
(void)printf("\n");
|
||||
fp = (FINFO *)dp;
|
||||
}
|
||||
return (numblocks);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_segment(fd, segnum, addr, lfsp, dump_sb)
|
||||
int fd, segnum;
|
||||
daddr_t addr;
|
||||
struct lfs *lfsp;
|
||||
int dump_sb;
|
||||
{
|
||||
struct lfs lfs_sb, *sbp;
|
||||
SEGSUM *sump;
|
||||
char sumblock[LFS_SUMMARY_SIZE];
|
||||
int did_one, nblocks, sb;
|
||||
off_t sum_offset, super_off;
|
||||
|
||||
(void)printf("\nSEGMENT %d (Disk Address 0x%X)\n",
|
||||
addr >> (lfsp->lfs_segshift - daddr_shift), addr);
|
||||
sum_offset = (addr << (lfsp->lfs_bshift - lfsp->lfs_fsbtodb));
|
||||
|
||||
sb = 0;
|
||||
did_one = 0;
|
||||
do {
|
||||
get(fd, sum_offset, sumblock, LFS_SUMMARY_SIZE);
|
||||
sump = (SEGSUM *)sumblock;
|
||||
if (sump->ss_sumsum != cksum (&sump->ss_datasum,
|
||||
LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) {
|
||||
sbp = (struct lfs *)sump;
|
||||
if (sb = (sbp->lfs_magic == LFS_MAGIC)) {
|
||||
super_off = sum_offset;
|
||||
sum_offset += LFS_SBPAD;
|
||||
} else if (did_one)
|
||||
break;
|
||||
else {
|
||||
printf("Segment at 0x%X corrupt\n", addr);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nblocks = dump_sum(fd, lfsp, sump, segnum, sum_offset >>
|
||||
(lfsp->lfs_bshift - lfsp->lfs_fsbtodb));
|
||||
if (nblocks)
|
||||
sum_offset += LFS_SUMMARY_SIZE +
|
||||
(nblocks << lfsp->lfs_bshift);
|
||||
else
|
||||
sum_offset = 0;
|
||||
did_one = 1;
|
||||
}
|
||||
} while (sum_offset);
|
||||
|
||||
if (dump_sb && sb) {
|
||||
get(fd, super_off, &lfs_sb, sizeof(struct lfs));
|
||||
dump_super(&lfs_sb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_super(lfsp)
|
||||
struct lfs *lfsp;
|
||||
{
|
||||
int i;
|
||||
|
||||
(void)printf("%s0x%X\t%s0x%X\t%s%d\t%s%d\n",
|
||||
"magic ", lfsp->lfs_magic,
|
||||
"version ", lfsp->lfs_version,
|
||||
"size ", lfsp->lfs_size,
|
||||
"ssize ", lfsp->lfs_ssize);
|
||||
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
|
||||
"dsize ", lfsp->lfs_dsize,
|
||||
"bsize ", lfsp->lfs_bsize,
|
||||
"fsize ", lfsp->lfs_fsize,
|
||||
"frag ", lfsp->lfs_frag);
|
||||
|
||||
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
|
||||
"minfree ", lfsp->lfs_minfree,
|
||||
"inopb ", lfsp->lfs_inopb,
|
||||
"ifpb ", lfsp->lfs_ifpb,
|
||||
"nindir ", lfsp->lfs_nindir);
|
||||
|
||||
(void)printf("%s%d\t\t%s%d\t%s%d\t%s%d\n",
|
||||
"nseg ", lfsp->lfs_nseg,
|
||||
"nspf ", lfsp->lfs_nspf,
|
||||
"cleansz ", lfsp->lfs_cleansz,
|
||||
"segtabsz ", lfsp->lfs_segtabsz);
|
||||
|
||||
(void)printf("%s0x%X\t%s%d\t%s0x%X\t%s%d\n",
|
||||
"segmask ", lfsp->lfs_segmask,
|
||||
"segshift ", lfsp->lfs_segshift,
|
||||
"bmask ", lfsp->lfs_bmask,
|
||||
"bshift ", lfsp->lfs_bshift);
|
||||
|
||||
(void)printf("%s0x%X\t\t%s%d\t%s0x%X\t%s%d\n",
|
||||
"ffmask ", lfsp->lfs_ffmask,
|
||||
"ffshift ", lfsp->lfs_ffshift,
|
||||
"fbmask ", lfsp->lfs_fbmask,
|
||||
"fbshift ", lfsp->lfs_fbshift);
|
||||
|
||||
(void)printf("%s%d\t%s%d\t%s0x%X\t%s0x%qx\n",
|
||||
"sushift ", lfsp->lfs_sushift,
|
||||
"fsbtodb ", lfsp->lfs_fsbtodb,
|
||||
"cksum ", lfsp->lfs_cksum,
|
||||
"maxfilesize ", lfsp->lfs_maxfilesize);
|
||||
|
||||
(void)printf("Superblock disk addresses:\t");
|
||||
for (i = 0; i < LFS_MAXNUMSB; i++) {
|
||||
(void)printf(" 0x%X", lfsp->lfs_sboffs[i]);
|
||||
if ( i == (LFS_MAXNUMSB >> 1))
|
||||
(void)printf("\n\t\t\t\t");
|
||||
}
|
||||
(void)printf("\n");
|
||||
|
||||
(void)printf("Checkpoint Info\n");
|
||||
(void)printf("%s%d\t%s0x%X\t%s%d\n",
|
||||
"free ", lfsp->lfs_free,
|
||||
"idaddr ", lfsp->lfs_idaddr,
|
||||
"ifile ", lfsp->lfs_ifile);
|
||||
(void)printf("%s%d\t%s%d\t%s%d\n",
|
||||
"bfree ", lfsp->lfs_bfree,
|
||||
"avail ", lfsp->lfs_avail,
|
||||
"uinodes ", lfsp->lfs_uinodes);
|
||||
(void)printf("%s%d\t%s0x%X\t%s0x%X\n%s0x%X\t%s0x%X\t",
|
||||
"nfiles ", lfsp->lfs_nfiles,
|
||||
"lastseg ", lfsp->lfs_lastseg,
|
||||
"nextseg ", lfsp->lfs_nextseg,
|
||||
"curseg ", lfsp->lfs_curseg,
|
||||
"offset ", lfsp->lfs_offset);
|
||||
(void)printf("tstamp %s", ctime((time_t *)&lfsp->lfs_tstamp));
|
||||
(void)printf("\nIn-Memory Information\n");
|
||||
(void)printf("%s%d\t%s0x%X\t%s%d%s%d\t%s%d\n",
|
||||
"seglock ", lfsp->lfs_seglock,
|
||||
"iocount ", lfsp->lfs_iocount,
|
||||
"writer ", lfsp->lfs_writer,
|
||||
"dirops ", lfsp->lfs_dirops,
|
||||
"doifile ", lfsp->lfs_doifile);
|
||||
(void)printf("%s%d\t%s%d\t%s0x%X\t%s%d\n",
|
||||
"nactive ", lfsp->lfs_nactive,
|
||||
"fmod ", lfsp->lfs_fmod,
|
||||
"clean ", lfsp->lfs_clean,
|
||||
"ronly ", lfsp->lfs_ronly);
|
||||
}
|
||||
|
||||
static void
|
||||
addseg(arg)
|
||||
char *arg;
|
||||
{
|
||||
SEGLIST *p;
|
||||
|
||||
if ((p = malloc(sizeof(SEGLIST))) == NULL)
|
||||
err("%s", strerror(errno));
|
||||
p->next = seglist;
|
||||
p->num = atoi(arg);
|
||||
seglist = p;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_cleaner_info(lfsp, ipage)
|
||||
struct lfs *lfsp;
|
||||
void *ipage;
|
||||
{
|
||||
CLEANERINFO *cip;
|
||||
|
||||
cip = (CLEANERINFO *)ipage;
|
||||
(void)printf("segments clean\t%d\tsegments dirty\t%d\n\n",
|
||||
cip->clean, cip->dirty);
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage: dumplfs [-ai] [-s segnum] file\n");
|
||||
exit(1);
|
||||
}
|
||||
39
sbin/dumplfs/extern.h
Normal file
39
sbin/dumplfs/extern.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
void err __P((const char *, ...));
|
||||
void get __P((int, off_t, void *, size_t));
|
||||
|
||||
extern char *special;
|
||||
90
sbin/dumplfs/misc.c
Normal file
90
sbin/dumplfs/misc.c
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "extern.h"
|
||||
|
||||
void
|
||||
get(fd, off, p, len)
|
||||
int fd;
|
||||
off_t off;
|
||||
void *p;
|
||||
size_t len;
|
||||
{
|
||||
int rbytes;
|
||||
|
||||
if (lseek(fd, off, SEEK_SET) < 0)
|
||||
err("%s: %s", special, strerror(errno));
|
||||
if ((rbytes = read(fd, p, len)) < 0)
|
||||
err("%s: %s", special, strerror(errno));
|
||||
if (rbytes != len)
|
||||
err("%s: short read (%d, not %d)", special, rbytes, len);
|
||||
}
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
void
|
||||
#if __STDC__
|
||||
err(const char *fmt, ...)
|
||||
#else
|
||||
err(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
(void)fprintf(stderr, "dumplfs: ");
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
(void)fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
12
sbin/fastboot/Makefile
Normal file
12
sbin/fastboot/Makefile
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
MAN8= fastboot.0
|
||||
MLINKS= fastboot.8 fasthalt.8
|
||||
|
||||
beforeinstall:
|
||||
install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
|
||||
${.CURDIR}/fastboot.sh ${DESTDIR}${BINDIR}/fastboot
|
||||
install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
|
||||
${.CURDIR}/fasthalt.sh ${DESTDIR}${BINDIR}/fasthalt
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
69
sbin/fastboot/fastboot.8
Normal file
69
sbin/fastboot/fastboot.8
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
.\" Copyright (c) 1983, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)fastboot.8 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.Dd June 5, 1993
|
||||
.Dt FASTBOOT 8
|
||||
.Os BSD 4.2
|
||||
.Sh NAME
|
||||
.Nm fastboot ,
|
||||
.Nm fasthalt
|
||||
.Nd "reboot/halt the system without checking the disks"
|
||||
.Sh SYNOPSIS
|
||||
.Nm fastboot
|
||||
.Op Ar boot-options
|
||||
.Nm fasthalt
|
||||
.Op Ar halt-options
|
||||
.Sh DESCRIPTION
|
||||
.Nm Fastboot
|
||||
and
|
||||
.Nm fasthalt
|
||||
are shell scripts which reboot and halt the system without
|
||||
checking the file systems. This is done by creating a
|
||||
file
|
||||
.Pa /fastboot ,
|
||||
then invoking the
|
||||
.Xr reboot
|
||||
program. The system startup script,
|
||||
.Pa /etc/rc ,
|
||||
looks for this file and, if present, skips the normal
|
||||
invocation of
|
||||
.Xr fsck 8 .
|
||||
.Sh SEE ALSO
|
||||
.Xr halt 8 ,
|
||||
.Xr reboot 8 ,
|
||||
.Xr rc 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
38
sbin/fastboot/fastboot.sh
Normal file
38
sbin/fastboot/fastboot.sh
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh -
|
||||
#
|
||||
# Copyright (c) 1985, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)fastboot.sh 8.1 (Berkeley) 6/5/93
|
||||
#
|
||||
|
||||
cp /dev/null /fastboot
|
||||
/sbin/reboot $*
|
||||
38
sbin/fastboot/fasthalt.sh
Normal file
38
sbin/fastboot/fasthalt.sh
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh -
|
||||
#
|
||||
# Copyright (c) 1988, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. All advertising materials mentioning features or use of this software
|
||||
# must display the following acknowledgement:
|
||||
# This product includes software developed by the University of
|
||||
# California, Berkeley and its contributors.
|
||||
# 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)fasthalt.sh 8.1 (Berkeley) 6/5/93
|
||||
#
|
||||
|
||||
cp /dev/null /fastboot
|
||||
/sbin/halt $*
|
||||
9
sbin/fsck/Makefile
Normal file
9
sbin/fsck/Makefile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= fsck
|
||||
MAN8= fsck.0
|
||||
SRCS= dir.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
|
||||
pass5.c preen.c setup.c utilities.c ffs_subr.c ffs_tables.c
|
||||
.PATH: ${.CURDIR}/../../sys/ufs/ffs
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
150
sbin/fsck/SMM.doc/0.t
Normal file
150
sbin/fsck/SMM.doc/0.t
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
.\" Copyright (c) 1986, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)0.t 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.if n .ND
|
||||
.TL
|
||||
Fsck \- The UNIX\(dg File System Check Program
|
||||
.EH 'SMM:3-%''The \s-2UNIX\s+2 File System Check Program'
|
||||
.OH 'The \s-2UNIX\s+2 File System Check Program''SMM:3-%'
|
||||
.AU
|
||||
Marshall Kirk McKusick
|
||||
.AI
|
||||
Computer Systems Research Group
|
||||
Computer Science Division
|
||||
Department of Electrical Engineering and Computer Science
|
||||
University of California, Berkeley
|
||||
Berkeley, CA 94720
|
||||
.AU
|
||||
T. J. Kowalski
|
||||
.AI
|
||||
Bell Laboratories
|
||||
Murray Hill, New Jersey 07974
|
||||
.AB
|
||||
.FS
|
||||
\(dgUNIX is a trademark of Bell Laboratories.
|
||||
.FE
|
||||
.FS
|
||||
This work was done under grants from
|
||||
the National Science Foundation under grant MCS80-05144,
|
||||
and the Defense Advance Research Projects Agency (DoD) under
|
||||
Arpa Order No. 4031 monitored by Naval Electronic System Command under
|
||||
Contract No. N00039-82-C-0235.
|
||||
.FE
|
||||
This document reflects the use of
|
||||
.I fsck
|
||||
with the 4.2BSD and 4.3BSD file system organization. This
|
||||
is a revision of the
|
||||
original paper written by
|
||||
T. J. Kowalski.
|
||||
.PP
|
||||
File System Check Program (\fIfsck\fR)
|
||||
is an interactive file system check and repair program.
|
||||
.I Fsck
|
||||
uses the redundant structural information in the
|
||||
UNIX file system to perform several consistency checks.
|
||||
If an inconsistency is detected, it is reported
|
||||
to the operator, who may elect to fix or ignore
|
||||
each inconsistency.
|
||||
These inconsistencies result from the permanent interruption
|
||||
of the file system updates, which are performed every
|
||||
time a file is modified.
|
||||
Unless there has been a hardware failure,
|
||||
.I fsck
|
||||
is able to repair corrupted file systems
|
||||
using procedures based upon the order in which UNIX honors
|
||||
these file system update requests.
|
||||
.PP
|
||||
The purpose of this document is to describe the normal updating
|
||||
of the file system,
|
||||
to discuss the possible causes of file system corruption,
|
||||
and to present the corrective actions implemented
|
||||
by
|
||||
.I fsck.
|
||||
Both the program and the interaction between the
|
||||
program and the operator are described.
|
||||
.sp 2
|
||||
.LP
|
||||
Revised July 16, 1985
|
||||
.AE
|
||||
.LP
|
||||
.bp
|
||||
.ce
|
||||
.B "TABLE OF CONTENTS"
|
||||
.LP
|
||||
.sp 1
|
||||
.nf
|
||||
.B "1. Introduction"
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B "2. Overview of the file system
|
||||
2.1. Superblock
|
||||
2.2. Summary Information
|
||||
2.3. Cylinder groups
|
||||
2.4. Fragments
|
||||
2.5. Updates to the file system
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B "3. Fixing corrupted file systems
|
||||
3.1. Detecting and correcting corruption
|
||||
3.2. Super block checking
|
||||
3.3. Free block checking
|
||||
3.4. Checking the inode state
|
||||
3.5. Inode links
|
||||
3.6. Inode data size
|
||||
3.7. Checking the data associated with an inode
|
||||
3.8. File system connectivity
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B Acknowledgements
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B References
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B "4. Appendix A
|
||||
4.1. Conventions
|
||||
4.2. Initialization
|
||||
4.3. Phase 1 - Check Blocks and Sizes
|
||||
4.4. Phase 1b - Rescan for more Dups
|
||||
4.5. Phase 2 - Check Pathnames
|
||||
4.6. Phase 3 - Check Connectivity
|
||||
4.7. Phase 4 - Check Reference Counts
|
||||
4.8. Phase 5 - Check Cyl groups
|
||||
4.9. Cleanup
|
||||
.ds RH Introduction
|
||||
.bp
|
||||
83
sbin/fsck/SMM.doc/1.t
Normal file
83
sbin/fsck/SMM.doc/1.t
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
.\" Copyright (c) 1982, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)1.t 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.ds RH Introduction
|
||||
.NH
|
||||
Introduction
|
||||
.PP
|
||||
This document reflects the use of
|
||||
.I fsck
|
||||
with the 4.2BSD and 4.3BSD file system organization. This
|
||||
is a revision of the
|
||||
original paper written by
|
||||
T. J. Kowalski.
|
||||
.PP
|
||||
When a UNIX
|
||||
operating system is brought up, a consistency
|
||||
check of the file systems should always be performed.
|
||||
This precautionary measure helps to insure
|
||||
a reliable environment for file storage on disk.
|
||||
If an inconsistency is discovered,
|
||||
corrective action must be taken.
|
||||
.I Fsck
|
||||
runs in two modes.
|
||||
Normally it is run non-interactively by the system after
|
||||
a normal boot.
|
||||
When running in this mode,
|
||||
it will only make changes to the file system that are known
|
||||
to always be correct.
|
||||
If an unexpected inconsistency is found
|
||||
.I fsck
|
||||
will exit with a non-zero exit status,
|
||||
leaving the system running single-user.
|
||||
Typically the operator then runs
|
||||
.I fsck
|
||||
interactively.
|
||||
When running in this mode,
|
||||
each problem is listed followed by a suggested corrective action.
|
||||
The operator must decide whether or not the suggested correction
|
||||
should be made.
|
||||
.PP
|
||||
The purpose of this memo is to dispel the
|
||||
mystique surrounding
|
||||
file system inconsistencies.
|
||||
It first describes the updating of the file system
|
||||
(the calm before the storm) and
|
||||
then describes file system corruption (the storm).
|
||||
Finally,
|
||||
the set of deterministic corrective actions
|
||||
used by
|
||||
.I fsck
|
||||
(the Coast Guard
|
||||
to the rescue) is presented.
|
||||
.ds RH Overview of the File System
|
||||
265
sbin/fsck/SMM.doc/2.t
Normal file
265
sbin/fsck/SMM.doc/2.t
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
.\" Copyright (c) 1982, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)2.t 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.ds RH Overview of the file system
|
||||
.NH
|
||||
Overview of the file system
|
||||
.PP
|
||||
The file system is discussed in detail in [Mckusick84];
|
||||
this section gives a brief overview.
|
||||
.NH 2
|
||||
Superblock
|
||||
.PP
|
||||
A file system is described by its
|
||||
.I "super-block" .
|
||||
The super-block is built when the file system is created (\c
|
||||
.I newfs (8))
|
||||
and never changes.
|
||||
The super-block
|
||||
contains the basic parameters of the file system,
|
||||
such as the number of data blocks it contains
|
||||
and a count of the maximum number of files.
|
||||
Because the super-block contains critical data,
|
||||
.I newfs
|
||||
replicates it to protect against catastrophic loss.
|
||||
The
|
||||
.I "default super block"
|
||||
always resides at a fixed offset from the beginning
|
||||
of the file system's disk partition.
|
||||
The
|
||||
.I "redundant super blocks"
|
||||
are not referenced unless a head crash
|
||||
or other hard disk error causes the default super-block
|
||||
to be unusable.
|
||||
The redundant blocks are sprinkled throughout the disk partition.
|
||||
.PP
|
||||
Within the file system are files.
|
||||
Certain files are distinguished as directories and contain collections
|
||||
of pointers to files that may themselves be directories.
|
||||
Every file has a descriptor associated with it called an
|
||||
.I "inode".
|
||||
The inode contains information describing ownership of the file,
|
||||
time stamps indicating modification and access times for the file,
|
||||
and an array of indices pointing to the data blocks for the file.
|
||||
In this section,
|
||||
we assume that the first 12 blocks
|
||||
of the file are directly referenced by values stored
|
||||
in the inode structure itself\(dg.
|
||||
.FS
|
||||
\(dgThe actual number may vary from system to system, but is usually in
|
||||
the range 5-13.
|
||||
.FE
|
||||
The inode structure may also contain references to indirect blocks
|
||||
containing further data block indices.
|
||||
In a file system with a 4096 byte block size, a singly indirect
|
||||
block contains 1024 further block addresses,
|
||||
a doubly indirect block contains 1024 addresses of further single indirect
|
||||
blocks,
|
||||
and a triply indirect block contains 1024 addresses of further doubly indirect
|
||||
blocks (the triple indirect block is never needed in practice).
|
||||
.PP
|
||||
In order to create files with up to
|
||||
2\(ua32 bytes,
|
||||
using only two levels of indirection,
|
||||
the minimum size of a file system block is 4096 bytes.
|
||||
The size of file system blocks can be any power of two
|
||||
greater than or equal to 4096.
|
||||
The block size of the file system is maintained in the super-block,
|
||||
so it is possible for file systems of different block sizes
|
||||
to be accessible simultaneously on the same system.
|
||||
The block size must be decided when
|
||||
.I newfs
|
||||
creates the file system;
|
||||
the block size cannot be subsequently
|
||||
changed without rebuilding the file system.
|
||||
.NH 2
|
||||
Summary information
|
||||
.PP
|
||||
Associated with the super block is non replicated
|
||||
.I "summary information" .
|
||||
The summary information changes
|
||||
as the file system is modified.
|
||||
The summary information contains
|
||||
the number of blocks, fragments, inodes and directories in the file system.
|
||||
.NH 2
|
||||
Cylinder groups
|
||||
.PP
|
||||
The file system partitions the disk into one or more areas called
|
||||
.I "cylinder groups".
|
||||
A cylinder group is comprised of one or more consecutive
|
||||
cylinders on a disk.
|
||||
Each cylinder group includes inode slots for files, a
|
||||
.I "block map"
|
||||
describing available blocks in the cylinder group,
|
||||
and summary information describing the usage of data blocks
|
||||
within the cylinder group.
|
||||
A fixed number of inodes is allocated for each cylinder group
|
||||
when the file system is created.
|
||||
The current policy is to allocate one inode for each 2048
|
||||
bytes of disk space;
|
||||
this is expected to be far more inodes than will ever be needed.
|
||||
.PP
|
||||
All the cylinder group bookkeeping information could be
|
||||
placed at the beginning of each cylinder group.
|
||||
However if this approach were used,
|
||||
all the redundant information would be on the top platter.
|
||||
A single hardware failure that destroyed the top platter
|
||||
could cause the loss of all copies of the redundant super-blocks.
|
||||
Thus the cylinder group bookkeeping information
|
||||
begins at a floating offset from the beginning of the cylinder group.
|
||||
The offset for
|
||||
the
|
||||
.I "i+1" st
|
||||
cylinder group is about one track further
|
||||
from the beginning of the cylinder group
|
||||
than it was for the
|
||||
.I "i" th
|
||||
cylinder group.
|
||||
In this way,
|
||||
the redundant
|
||||
information spirals down into the pack;
|
||||
any single track, cylinder,
|
||||
or platter can be lost without losing all copies of the super-blocks.
|
||||
Except for the first cylinder group,
|
||||
the space between the beginning of the cylinder group
|
||||
and the beginning of the cylinder group information stores data.
|
||||
.NH 2
|
||||
Fragments
|
||||
.PP
|
||||
To avoid waste in storing small files,
|
||||
the file system space allocator divides a single
|
||||
file system block into one or more
|
||||
.I "fragments".
|
||||
The fragmentation of the file system is specified
|
||||
when the file system is created;
|
||||
each file system block can be optionally broken into
|
||||
2, 4, or 8 addressable fragments.
|
||||
The lower bound on the size of these fragments is constrained
|
||||
by the disk sector size;
|
||||
typically 512 bytes is the lower bound on fragment size.
|
||||
The block map associated with each cylinder group
|
||||
records the space availability at the fragment level.
|
||||
Aligned fragments are examined
|
||||
to determine block availability.
|
||||
.PP
|
||||
On a file system with a block size of 4096 bytes
|
||||
and a fragment size of 1024 bytes,
|
||||
a file is represented by zero or more 4096 byte blocks of data,
|
||||
and possibly a single fragmented block.
|
||||
If a file system block must be fragmented to obtain
|
||||
space for a small amount of data,
|
||||
the remainder of the block is made available for allocation
|
||||
to other files.
|
||||
For example,
|
||||
consider an 11000 byte file stored on
|
||||
a 4096/1024 byte file system.
|
||||
This file uses two full size blocks and a 3072 byte fragment.
|
||||
If no fragments with at least 3072 bytes
|
||||
are available when the file is created,
|
||||
a full size block is split yielding the necessary 3072 byte
|
||||
fragment and an unused 1024 byte fragment.
|
||||
This remaining fragment can be allocated to another file, as needed.
|
||||
.NH 2
|
||||
Updates to the file system
|
||||
.PP
|
||||
Every working day hundreds of files
|
||||
are created, modified, and removed.
|
||||
Every time a file is modified,
|
||||
the operating system performs a
|
||||
series of file system updates.
|
||||
These updates, when written on disk, yield a consistent file system.
|
||||
The file system stages
|
||||
all modifications of critical information;
|
||||
modification can
|
||||
either be completed or cleanly backed out after a crash.
|
||||
Knowing the information that is first written to the file system,
|
||||
deterministic procedures can be developed to
|
||||
repair a corrupted file system.
|
||||
To understand this process,
|
||||
the order that the update
|
||||
requests were being honored must first be understood.
|
||||
.PP
|
||||
When a user program does an operation to change the file system,
|
||||
such as a
|
||||
.I write ,
|
||||
the data to be written is copied into an internal
|
||||
.I "in-core"
|
||||
buffer in the kernel.
|
||||
Normally, the disk update is handled asynchronously;
|
||||
the user process is allowed to proceed even though
|
||||
the data has not yet been written to the disk.
|
||||
The data,
|
||||
along with the inode information reflecting the change,
|
||||
is eventually written out to disk.
|
||||
The real disk write may not happen until long after the
|
||||
.I write
|
||||
system call has returned.
|
||||
Thus at any given time, the file system,
|
||||
as it resides on the disk,
|
||||
lags the state of the file system represented by the in-core information.
|
||||
.PP
|
||||
The disk information is updated to reflect the in-core information
|
||||
when the buffer is required for another use,
|
||||
when a
|
||||
.I sync (2)
|
||||
is done (at 30 second intervals) by
|
||||
.I "/etc/update" "(8),"
|
||||
or by manual operator intervention with the
|
||||
.I sync (8)
|
||||
command.
|
||||
If the system is halted without writing out the in-core information,
|
||||
the file system on the disk will be in an inconsistent state.
|
||||
.PP
|
||||
If all updates are done asynchronously, several serious
|
||||
inconsistencies can arise.
|
||||
One inconsistency is that a block may be claimed by two inodes.
|
||||
Such an inconsistency can occur when the system is halted before
|
||||
the pointer to the block in the old inode has been cleared
|
||||
in the copy of the old inode on the disk,
|
||||
and after the pointer to the block in the new inode has been written out
|
||||
to the copy of the new inode on the disk.
|
||||
Here,
|
||||
there is no deterministic method for deciding
|
||||
which inode should really claim the block.
|
||||
A similar problem can arise with a multiply claimed inode.
|
||||
.PP
|
||||
The problem with asynchronous inode updates
|
||||
can be avoided by doing all inode deallocations synchronously.
|
||||
Consequently,
|
||||
inodes and indirect blocks are written to the disk synchronously
|
||||
(\fIi.e.\fP the process blocks until the information is
|
||||
really written to disk)
|
||||
when they are being deallocated.
|
||||
Similarly inodes are kept consistent by synchronously
|
||||
deleting, adding, or changing directory entries.
|
||||
.ds RH Fixing corrupted file systems
|
||||
439
sbin/fsck/SMM.doc/3.t
Normal file
439
sbin/fsck/SMM.doc/3.t
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
.\" Copyright (c) 1982, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)3.t 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.ds RH Fixing corrupted file systems
|
||||
.NH
|
||||
Fixing corrupted file systems
|
||||
.PP
|
||||
A file system
|
||||
can become corrupted in several ways.
|
||||
The most common of these ways are
|
||||
improper shutdown procedures
|
||||
and hardware failures.
|
||||
.PP
|
||||
File systems may become corrupted during an
|
||||
.I "unclean halt" .
|
||||
This happens when proper shutdown
|
||||
procedures are not observed,
|
||||
physically write-protecting a mounted file system,
|
||||
or a mounted file system is taken off-line.
|
||||
The most common operator procedural failure is forgetting to
|
||||
.I sync
|
||||
the system before halting the CPU.
|
||||
.PP
|
||||
File systems may become further corrupted if proper startup
|
||||
procedures are not observed, e.g.,
|
||||
not checking a file system for inconsistencies,
|
||||
and not repairing inconsistencies.
|
||||
Allowing a corrupted file system to be used (and, thus, to be modified
|
||||
further) can be disastrous.
|
||||
.PP
|
||||
Any piece of hardware can fail at any time.
|
||||
Failures
|
||||
can be as subtle as a bad block
|
||||
on a disk pack, or as blatant as a non-functional disk-controller.
|
||||
.NH 2
|
||||
Detecting and correcting corruption
|
||||
.PP
|
||||
Normally
|
||||
.I fsck
|
||||
is run non-interactively.
|
||||
In this mode it will only fix
|
||||
corruptions that are expected to occur from an unclean halt.
|
||||
These actions are a proper subset of the actions that
|
||||
.I fsck
|
||||
will take when it is running interactively.
|
||||
Throughout this paper we assume that
|
||||
.I fsck
|
||||
is being run interactively,
|
||||
and all possible errors can be encountered.
|
||||
When an inconsistency is discovered in this mode,
|
||||
.I fsck
|
||||
reports the inconsistency for the operator to
|
||||
chose a corrective action.
|
||||
.PP
|
||||
A quiescent\(dd
|
||||
.FS
|
||||
\(dd I.e., unmounted and not being written on.
|
||||
.FE
|
||||
file system may be checked for structural integrity
|
||||
by performing consistency checks on the
|
||||
redundant data intrinsic to a file system.
|
||||
The redundant data is either read from
|
||||
the file system,
|
||||
or computed from other known values.
|
||||
The file system
|
||||
.B must
|
||||
be in a quiescent state when
|
||||
.I fsck
|
||||
is run,
|
||||
since
|
||||
.I fsck
|
||||
is a multi-pass program.
|
||||
.PP
|
||||
In the following sections,
|
||||
we discuss methods to discover inconsistencies
|
||||
and possible corrective actions
|
||||
for the cylinder group blocks, the inodes, the indirect blocks, and
|
||||
the data blocks containing directory entries.
|
||||
.NH 2
|
||||
Super-block checking
|
||||
.PP
|
||||
The most commonly corrupted item in a file system
|
||||
is the summary information
|
||||
associated with the super-block.
|
||||
The summary information is prone to corruption
|
||||
because it is modified with every change to the file
|
||||
system's blocks or inodes,
|
||||
and is usually corrupted
|
||||
after an unclean halt.
|
||||
.PP
|
||||
The super-block is checked for inconsistencies
|
||||
involving file-system size, number of inodes,
|
||||
free-block count, and the free-inode count.
|
||||
The file-system size must be larger than the
|
||||
number of blocks used by the super-block
|
||||
and the number of blocks used by the list of inodes.
|
||||
The file-system size and layout information
|
||||
are the most critical pieces of information for
|
||||
.I fsck .
|
||||
While there is no way to actually check these sizes,
|
||||
since they are statically determined by
|
||||
.I newfs ,
|
||||
.I fsck
|
||||
can check that these sizes are within reasonable bounds.
|
||||
All other file system checks require that these sizes be correct.
|
||||
If
|
||||
.I fsck
|
||||
detects corruption in the static parameters of the default super-block,
|
||||
.I fsck
|
||||
requests the operator to specify the location of an alternate super-block.
|
||||
.NH 2
|
||||
Free block checking
|
||||
.PP
|
||||
.I Fsck
|
||||
checks that all the blocks
|
||||
marked as free in the cylinder group block maps
|
||||
are not claimed by any files.
|
||||
When all the blocks have been initially accounted for,
|
||||
.I fsck
|
||||
checks that
|
||||
the number of free blocks
|
||||
plus the number of blocks claimed by the inodes
|
||||
equals the total number of blocks in the file system.
|
||||
.PP
|
||||
If anything is wrong with the block allocation maps,
|
||||
.I fsck
|
||||
will rebuild them,
|
||||
based on the list it has computed of allocated blocks.
|
||||
.PP
|
||||
The summary information associated with the super-block
|
||||
counts the total number of free blocks within the file system.
|
||||
.I Fsck
|
||||
compares this count to the
|
||||
number of free blocks it found within the file system.
|
||||
If the two counts do not agree, then
|
||||
.I fsck
|
||||
replaces the incorrect count in the summary information
|
||||
by the actual free-block count.
|
||||
.PP
|
||||
The summary information
|
||||
counts the total number of free inodes within the file system.
|
||||
.I Fsck
|
||||
compares this count to the number
|
||||
of free inodes it found within the file system.
|
||||
If the two counts do not agree, then
|
||||
.I fsck
|
||||
replaces the incorrect count in the
|
||||
summary information by the actual free-inode count.
|
||||
.NH 2
|
||||
Checking the inode state
|
||||
.PP
|
||||
An individual inode is not as likely to be corrupted as
|
||||
the allocation information.
|
||||
However, because of the great number of active inodes,
|
||||
a few of the inodes are usually corrupted.
|
||||
.PP
|
||||
The list of inodes in the file system
|
||||
is checked sequentially starting with inode 2
|
||||
(inode 0 marks unused inodes;
|
||||
inode 1 is saved for future generations)
|
||||
and progressing through the last inode in the file system.
|
||||
The state of each inode is checked for
|
||||
inconsistencies involving format and type,
|
||||
link count,
|
||||
duplicate blocks,
|
||||
bad blocks,
|
||||
and inode size.
|
||||
.PP
|
||||
Each inode contains a mode word.
|
||||
This mode word describes the type and state of the inode.
|
||||
Inodes must be one of six types:
|
||||
regular inode, directory inode, symbolic link inode,
|
||||
special block inode, special character inode, or socket inode.
|
||||
Inodes may be found in one of three allocation states:
|
||||
unallocated, allocated, and neither unallocated nor allocated.
|
||||
This last state suggests an incorrectly formated inode.
|
||||
An inode can get in this state if
|
||||
bad data is written into the inode list.
|
||||
The only possible corrective action is for
|
||||
.I fsck
|
||||
is to clear the inode.
|
||||
.NH 2
|
||||
Inode links
|
||||
.PP
|
||||
Each inode counts the
|
||||
total number of directory entries
|
||||
linked to the inode.
|
||||
.I Fsck
|
||||
verifies the link count of each inode
|
||||
by starting at the root of the file system,
|
||||
and descending through the directory structure.
|
||||
The actual link count for each inode
|
||||
is calculated during the descent.
|
||||
.PP
|
||||
If the stored link count is non-zero and the actual
|
||||
link count is zero,
|
||||
then no directory entry appears for the inode.
|
||||
If this happens,
|
||||
.I fsck
|
||||
will place the disconnected file in the
|
||||
.I lost+found
|
||||
directory.
|
||||
If the stored and actual link counts are non-zero and unequal,
|
||||
a directory entry may have been added or removed without the inode being
|
||||
updated.
|
||||
If this happens,
|
||||
.I fsck
|
||||
replaces the incorrect stored link count by the actual link count.
|
||||
.PP
|
||||
Each inode contains a list,
|
||||
or pointers to
|
||||
lists (indirect blocks),
|
||||
of all the blocks claimed by the inode.
|
||||
Since indirect blocks are owned by an inode,
|
||||
inconsistencies in indirect blocks directly
|
||||
affect the inode that owns it.
|
||||
.PP
|
||||
.I Fsck
|
||||
compares each block number claimed by an inode
|
||||
against a list of already allocated blocks.
|
||||
If another inode already claims a block number,
|
||||
then the block number is added to a list of
|
||||
.I "duplicate blocks" .
|
||||
Otherwise, the list of allocated blocks
|
||||
is updated to include the block number.
|
||||
.PP
|
||||
If there are any duplicate blocks,
|
||||
.I fsck
|
||||
will perform a partial second
|
||||
pass over the inode list
|
||||
to find the inode of the duplicated block.
|
||||
The second pass is needed,
|
||||
since without examining the files associated with
|
||||
these inodes for correct content,
|
||||
not enough information is available
|
||||
to determine which inode is corrupted and should be cleared.
|
||||
If this condition does arise
|
||||
(only hardware failure will cause it),
|
||||
then the inode with the earliest
|
||||
modify time is usually incorrect,
|
||||
and should be cleared.
|
||||
If this happens,
|
||||
.I fsck
|
||||
prompts the operator to clear both inodes.
|
||||
The operator must decide which one should be kept
|
||||
and which one should be cleared.
|
||||
.PP
|
||||
.I Fsck
|
||||
checks the range of each block number claimed by an inode.
|
||||
If the block number is
|
||||
lower than the first data block in the file system,
|
||||
or greater than the last data block,
|
||||
then the block number is a
|
||||
.I "bad block number" .
|
||||
Many bad blocks in an inode are usually caused by
|
||||
an indirect block that was not written to the file system,
|
||||
a condition which can only occur if there has been a hardware failure.
|
||||
If an inode contains bad block numbers,
|
||||
.I fsck
|
||||
prompts the operator to clear it.
|
||||
.NH 2
|
||||
Inode data size
|
||||
.PP
|
||||
Each inode contains a count of the number of data blocks
|
||||
that it contains.
|
||||
The number of actual data blocks
|
||||
is the sum of the allocated data blocks
|
||||
and the indirect blocks.
|
||||
.I Fsck
|
||||
computes the actual number of data blocks
|
||||
and compares that block count against
|
||||
the actual number of blocks the inode claims.
|
||||
If an inode contains an incorrect count
|
||||
.I fsck
|
||||
prompts the operator to fix it.
|
||||
.PP
|
||||
Each inode contains a thirty-two bit size field.
|
||||
The size is the number of data bytes
|
||||
in the file associated with the inode.
|
||||
The consistency of the byte size field is roughly checked
|
||||
by computing from the size field the maximum number of blocks
|
||||
that should be associated with the inode,
|
||||
and comparing that expected block count against
|
||||
the actual number of blocks the inode claims.
|
||||
.NH 2
|
||||
Checking the data associated with an inode
|
||||
.PP
|
||||
An inode can directly or indirectly
|
||||
reference three kinds of data blocks.
|
||||
All referenced blocks must be the same kind.
|
||||
The three types of data blocks are:
|
||||
plain data blocks, symbolic link data blocks, and directory data blocks.
|
||||
Plain data blocks
|
||||
contain the information stored in a file;
|
||||
symbolic link data blocks
|
||||
contain the path name stored in a link.
|
||||
Directory data blocks contain directory entries.
|
||||
.I Fsck
|
||||
can only check the validity of directory data blocks.
|
||||
.PP
|
||||
Each directory data block is checked for
|
||||
several types of inconsistencies.
|
||||
These inconsistencies include
|
||||
directory inode numbers pointing to unallocated inodes,
|
||||
directory inode numbers that are greater than
|
||||
the number of inodes in the file system,
|
||||
incorrect directory inode numbers for ``\fB.\fP'' and ``\fB..\fP'',
|
||||
and directories that are not attached to the file system.
|
||||
If the inode number in a directory data block
|
||||
references an unallocated inode,
|
||||
then
|
||||
.I fsck
|
||||
will remove that directory entry.
|
||||
Again,
|
||||
this condition can only arise when there has been a hardware failure.
|
||||
.PP
|
||||
If a directory entry inode number references
|
||||
outside the inode list, then
|
||||
.I fsck
|
||||
will remove that directory entry.
|
||||
This condition occurs if bad data is written into a directory data block.
|
||||
.PP
|
||||
The directory inode number entry for ``\fB.\fP''
|
||||
must be the first entry in the directory data block.
|
||||
The inode number for ``\fB.\fP''
|
||||
must reference itself;
|
||||
e.g., it must equal the inode number
|
||||
for the directory data block.
|
||||
The directory inode number entry
|
||||
for ``\fB..\fP'' must be
|
||||
the second entry in the directory data block.
|
||||
Its value must equal the inode number for the
|
||||
parent of the directory entry
|
||||
(or the inode number of the directory
|
||||
data block if the directory is the
|
||||
root directory).
|
||||
If the directory inode numbers are
|
||||
incorrect,
|
||||
.I fsck
|
||||
will replace them with the correct values.
|
||||
If there are multiple hard links to a directory,
|
||||
the first one encountered is considered the real parent
|
||||
to which ``\fB..\fP'' should point;
|
||||
\fIfsck\fP recommends deletion for the subsequently discovered names.
|
||||
.NH 2
|
||||
File system connectivity
|
||||
.PP
|
||||
.I Fsck
|
||||
checks the general connectivity of the file system.
|
||||
If directories are not linked into the file system, then
|
||||
.I fsck
|
||||
links the directory back into the file system in the
|
||||
.I lost+found
|
||||
directory.
|
||||
This condition only occurs when there has been a hardware failure.
|
||||
.ds RH "References"
|
||||
.SH
|
||||
\s+2Acknowledgements\s0
|
||||
.PP
|
||||
I thank Bill Joy, Sam Leffler, Robert Elz and Dennis Ritchie
|
||||
for their suggestions and help in implementing the new file system.
|
||||
Thanks also to Robert Henry for his editorial input to
|
||||
get this document together.
|
||||
Finally we thank our sponsors,
|
||||
the National Science Foundation under grant MCS80-05144,
|
||||
and the Defense Advance Research Projects Agency (DoD) under
|
||||
Arpa Order No. 4031 monitored by Naval Electronic System Command under
|
||||
Contract No. N00039-82-C-0235. (Kirk McKusick, July 1983)
|
||||
.PP
|
||||
I would like to thank Larry A. Wehr for advice that lead
|
||||
to the first version of
|
||||
.I fsck
|
||||
and Rick B. Brandt for adapting
|
||||
.I fsck
|
||||
to
|
||||
UNIX/TS. (T. Kowalski, July 1979)
|
||||
.sp 2
|
||||
.SH
|
||||
\s+2References\s0
|
||||
.LP
|
||||
.IP [Dolotta78] 20
|
||||
Dolotta, T. A., and Olsson, S. B. eds.,
|
||||
.I "UNIX User's Manual, Edition 1.1\^" ,
|
||||
January 1978.
|
||||
.IP [Joy83] 20
|
||||
Joy, W., Cooper, E., Fabry, R., Leffler, S., McKusick, M., and Mosher, D.
|
||||
4.2BSD System Manual,
|
||||
.I "University of California at Berkeley" ,
|
||||
.I "Computer Systems Research Group Technical Report"
|
||||
#4, 1982.
|
||||
.IP [McKusick84] 20
|
||||
McKusick, M., Joy, W., Leffler, S., and Fabry, R.
|
||||
A Fast File System for UNIX,
|
||||
\fIACM Transactions on Computer Systems 2\fP, 3.
|
||||
pp. 181-197, August 1984.
|
||||
.IP [Ritchie78] 20
|
||||
Ritchie, D. M., and Thompson, K.,
|
||||
The UNIX Time-Sharing System,
|
||||
.I "The Bell System Technical Journal"
|
||||
.B 57 ,
|
||||
6 (July-August 1978, Part 2), pp. 1905-29.
|
||||
.IP [Thompson78] 20
|
||||
Thompson, K.,
|
||||
UNIX Implementation,
|
||||
.I "The Bell System Technical Journal\^"
|
||||
.B 57 ,
|
||||
6 (July-August 1978, Part 2), pp. 1931-46.
|
||||
.ds RH Appendix A \- Fsck Error Conditions
|
||||
.bp
|
||||
1424
sbin/fsck/SMM.doc/4.t
Normal file
1424
sbin/fsck/SMM.doc/4.t
Normal file
File diff suppressed because it is too large
Load diff
7
sbin/fsck/SMM.doc/Makefile
Normal file
7
sbin/fsck/SMM.doc/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/8/93
|
||||
|
||||
DIR= smm/03.fsck
|
||||
SRCS= 0.t 1.t 2.t 3.t 4.t
|
||||
MACROS= -ms
|
||||
|
||||
.include <bsd.doc.mk>
|
||||
681
sbin/fsck/dir.c
Normal file
681
sbin/fsck/dir.c
Normal file
|
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
char *lfname = "lost+found";
|
||||
int lfmode = 01777;
|
||||
struct dirtemplate emptydir = { 0, DIRBLKSIZ };
|
||||
struct dirtemplate dirhead = {
|
||||
0, 12, DT_DIR, 1, ".",
|
||||
0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
|
||||
};
|
||||
struct odirtemplate odirhead = {
|
||||
0, 12, 1, ".",
|
||||
0, DIRBLKSIZ - 12, 2, ".."
|
||||
};
|
||||
|
||||
struct direct *fsck_readdir();
|
||||
struct bufarea *getdirblk();
|
||||
|
||||
/*
|
||||
* Propagate connected state through the tree.
|
||||
*/
|
||||
propagate()
|
||||
{
|
||||
register struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpend;
|
||||
long change;
|
||||
|
||||
inpend = &inpsort[inplast];
|
||||
do {
|
||||
change = 0;
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0)
|
||||
continue;
|
||||
if (statemap[inp->i_parent] == DFOUND &&
|
||||
statemap[inp->i_number] == DSTATE) {
|
||||
statemap[inp->i_number] = DFOUND;
|
||||
change++;
|
||||
}
|
||||
}
|
||||
} while (change > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan each entry in a directory block.
|
||||
*/
|
||||
dirscan(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dp;
|
||||
register struct bufarea *bp;
|
||||
int dsize, n;
|
||||
long blksiz;
|
||||
char dbuf[DIRBLKSIZ];
|
||||
|
||||
if (idesc->id_type != DATA)
|
||||
errexit("wrong type to dirscan %d\n", idesc->id_type);
|
||||
if (idesc->id_entryno == 0 &&
|
||||
(idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
|
||||
idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
|
||||
blksiz = idesc->id_numfrags * sblock.fs_fsize;
|
||||
if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
|
||||
idesc->id_filesize -= blksiz;
|
||||
return (SKIP);
|
||||
}
|
||||
idesc->id_loc = 0;
|
||||
for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
|
||||
dsize = dp->d_reclen;
|
||||
bcopy((char *)dp, dbuf, (size_t)dsize);
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt) {
|
||||
struct direct *tdp = (struct direct *)dbuf;
|
||||
u_char tmp;
|
||||
|
||||
tmp = tdp->d_namlen;
|
||||
tdp->d_namlen = tdp->d_type;
|
||||
tdp->d_type = tmp;
|
||||
}
|
||||
# endif
|
||||
idesc->id_dirp = (struct direct *)dbuf;
|
||||
if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt && !doinglevel2) {
|
||||
struct direct *tdp;
|
||||
u_char tmp;
|
||||
|
||||
tdp = (struct direct *)dbuf;
|
||||
tmp = tdp->d_namlen;
|
||||
tdp->d_namlen = tdp->d_type;
|
||||
tdp->d_type = tmp;
|
||||
}
|
||||
# endif
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize,
|
||||
(size_t)dsize);
|
||||
dirty(bp);
|
||||
sbdirty();
|
||||
}
|
||||
if (n & STOP)
|
||||
return (n);
|
||||
}
|
||||
return (idesc->id_filesize > 0 ? KEEPON : STOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* get next entry in a directory.
|
||||
*/
|
||||
struct direct *
|
||||
fsck_readdir(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dp, *ndp;
|
||||
register struct bufarea *bp;
|
||||
long size, blksiz, fix, dploc;
|
||||
|
||||
blksiz = idesc->id_numfrags * sblock.fs_fsize;
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
|
||||
idesc->id_loc < blksiz) {
|
||||
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
if (dircheck(idesc, dp))
|
||||
goto dpok;
|
||||
fix = dofix(idesc, "DIRECTORY CORRUPTED");
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
dp->d_reclen = DIRBLKSIZ;
|
||||
dp->d_ino = 0;
|
||||
dp->d_type = 0;
|
||||
dp->d_namlen = 0;
|
||||
dp->d_name[0] = '\0';
|
||||
if (fix)
|
||||
dirty(bp);
|
||||
idesc->id_loc += DIRBLKSIZ;
|
||||
idesc->id_filesize -= DIRBLKSIZ;
|
||||
return (dp);
|
||||
}
|
||||
dpok:
|
||||
if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
|
||||
return NULL;
|
||||
dploc = idesc->id_loc;
|
||||
dp = (struct direct *)(bp->b_un.b_buf + dploc);
|
||||
idesc->id_loc += dp->d_reclen;
|
||||
idesc->id_filesize -= dp->d_reclen;
|
||||
if ((idesc->id_loc % DIRBLKSIZ) == 0)
|
||||
return (dp);
|
||||
ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
|
||||
dircheck(idesc, ndp) == 0) {
|
||||
size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
|
||||
idesc->id_loc += size;
|
||||
idesc->id_filesize -= size;
|
||||
fix = dofix(idesc, "DIRECTORY CORRUPTED");
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
dp = (struct direct *)(bp->b_un.b_buf + dploc);
|
||||
dp->d_reclen += size;
|
||||
if (fix)
|
||||
dirty(bp);
|
||||
}
|
||||
return (dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a directory entry is valid.
|
||||
* This is a superset of the checks made in the kernel.
|
||||
*/
|
||||
dircheck(idesc, dp)
|
||||
struct inodesc *idesc;
|
||||
register struct direct *dp;
|
||||
{
|
||||
register int size;
|
||||
register char *cp;
|
||||
u_char namlen, type;
|
||||
int spaceleft;
|
||||
|
||||
size = DIRSIZ(!newinofmt, dp);
|
||||
spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt) {
|
||||
type = dp->d_namlen;
|
||||
namlen = dp->d_type;
|
||||
} else {
|
||||
namlen = dp->d_namlen;
|
||||
type = dp->d_type;
|
||||
}
|
||||
# else
|
||||
namlen = dp->d_namlen;
|
||||
type = dp->d_type;
|
||||
# endif
|
||||
if (dp->d_ino < maxino &&
|
||||
dp->d_reclen != 0 &&
|
||||
dp->d_reclen <= spaceleft &&
|
||||
(dp->d_reclen & 0x3) == 0 &&
|
||||
dp->d_reclen >= size &&
|
||||
idesc->id_filesize >= size &&
|
||||
namlen <= MAXNAMLEN &&
|
||||
type <= 15) {
|
||||
if (dp->d_ino == 0)
|
||||
return (1);
|
||||
for (cp = dp->d_name, size = 0; size < namlen; size++)
|
||||
if (*cp == 0 || (*cp++ == '/'))
|
||||
return (0);
|
||||
if (*cp == 0)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
direrror(ino, errmesg)
|
||||
ino_t ino;
|
||||
char *errmesg;
|
||||
{
|
||||
|
||||
fileerror(ino, ino, errmesg);
|
||||
}
|
||||
|
||||
fileerror(cwd, ino, errmesg)
|
||||
ino_t cwd, ino;
|
||||
char *errmesg;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
pwarn("%s ", errmesg);
|
||||
pinode(ino);
|
||||
printf("\n");
|
||||
getpathname(pathbuf, cwd, ino);
|
||||
if (ino < ROOTINO || ino > maxino) {
|
||||
pfatal("NAME=%s\n", pathbuf);
|
||||
return;
|
||||
}
|
||||
dp = ginode(ino);
|
||||
if (ftypeok(dp))
|
||||
pfatal("%s=%s\n",
|
||||
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
|
||||
else
|
||||
pfatal("NAME=%s\n", pathbuf);
|
||||
}
|
||||
|
||||
adjust(idesc, lcnt)
|
||||
register struct inodesc *idesc;
|
||||
short lcnt;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
|
||||
dp = ginode(idesc->id_number);
|
||||
if (dp->di_nlink == lcnt) {
|
||||
if (linkup(idesc->id_number, (ino_t)0) == 0)
|
||||
clri(idesc, "UNREF", 0);
|
||||
} else {
|
||||
pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
|
||||
((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
|
||||
pinode(idesc->id_number);
|
||||
printf(" COUNT %d SHOULD BE %d",
|
||||
dp->di_nlink, dp->di_nlink - lcnt);
|
||||
if (preen) {
|
||||
if (lcnt < 0) {
|
||||
printf("\n");
|
||||
pfatal("LINK COUNT INCREASING");
|
||||
}
|
||||
printf(" (ADJUSTED)\n");
|
||||
}
|
||||
if (preen || reply("ADJUST") == 1) {
|
||||
dp->di_nlink -= lcnt;
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mkentry(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
struct direct newent;
|
||||
int newlen, oldlen;
|
||||
|
||||
newent.d_namlen = strlen(idesc->id_name);
|
||||
newlen = DIRSIZ(0, &newent);
|
||||
if (dirp->d_ino != 0)
|
||||
oldlen = DIRSIZ(0, dirp);
|
||||
else
|
||||
oldlen = 0;
|
||||
if (dirp->d_reclen - oldlen < newlen)
|
||||
return (KEEPON);
|
||||
newent.d_reclen = dirp->d_reclen - oldlen;
|
||||
dirp->d_reclen = oldlen;
|
||||
dirp = (struct direct *)(((char *)dirp) + oldlen);
|
||||
dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
|
||||
if (newinofmt)
|
||||
dirp->d_type = typemap[idesc->id_parent];
|
||||
else
|
||||
dirp->d_type = 0;
|
||||
dirp->d_reclen = newent.d_reclen;
|
||||
dirp->d_namlen = newent.d_namlen;
|
||||
bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
|
||||
return (ALTERED|STOP);
|
||||
}
|
||||
|
||||
chgino(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
|
||||
return (KEEPON);
|
||||
dirp->d_ino = idesc->id_parent;
|
||||
if (newinofmt)
|
||||
dirp->d_type = typemap[idesc->id_parent];
|
||||
else
|
||||
dirp->d_type = 0;
|
||||
return (ALTERED|STOP);
|
||||
}
|
||||
|
||||
linkup(orphan, parentdir)
|
||||
ino_t orphan;
|
||||
ino_t parentdir;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
int lostdir;
|
||||
ino_t oldlfdir;
|
||||
struct inodesc idesc;
|
||||
char tempname[BUFSIZ];
|
||||
extern int pass4check();
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
dp = ginode(orphan);
|
||||
lostdir = (dp->di_mode & IFMT) == IFDIR;
|
||||
pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
|
||||
pinode(orphan);
|
||||
if (preen && dp->di_size == 0)
|
||||
return (0);
|
||||
if (preen)
|
||||
printf(" (RECONNECTED)\n");
|
||||
else
|
||||
if (reply("RECONNECT") == 0)
|
||||
return (0);
|
||||
if (lfdir == 0) {
|
||||
dp = ginode(ROOTINO);
|
||||
idesc.id_name = lfname;
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = findino;
|
||||
idesc.id_number = ROOTINO;
|
||||
if ((ckinode(dp, &idesc) & FOUND) != 0) {
|
||||
lfdir = idesc.id_parent;
|
||||
} else {
|
||||
pwarn("NO lost+found DIRECTORY");
|
||||
if (preen || reply("CREATE")) {
|
||||
lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
|
||||
if (lfdir != 0) {
|
||||
if (makeentry(ROOTINO, lfdir, lfname) != 0) {
|
||||
if (preen)
|
||||
printf(" (CREATED)\n");
|
||||
} else {
|
||||
freedir(lfdir, ROOTINO);
|
||||
lfdir = 0;
|
||||
if (preen)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lfdir == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
|
||||
printf("\n\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
dp = ginode(lfdir);
|
||||
if ((dp->di_mode & IFMT) != IFDIR) {
|
||||
pfatal("lost+found IS NOT A DIRECTORY");
|
||||
if (reply("REALLOCATE") == 0)
|
||||
return (0);
|
||||
oldlfdir = lfdir;
|
||||
if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
inodirty();
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
idesc.id_number = oldlfdir;
|
||||
adjust(&idesc, lncntp[oldlfdir] + 1);
|
||||
lncntp[oldlfdir] = 0;
|
||||
dp = ginode(lfdir);
|
||||
}
|
||||
if (statemap[lfdir] != DFOUND) {
|
||||
pfatal("SORRY. NO lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
(void)lftempname(tempname, orphan);
|
||||
if (makeentry(lfdir, orphan, tempname) == 0) {
|
||||
pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
|
||||
printf("\n\n");
|
||||
return (0);
|
||||
}
|
||||
lncntp[orphan]--;
|
||||
if (lostdir) {
|
||||
if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
|
||||
parentdir != (ino_t)-1)
|
||||
(void)makeentry(orphan, lfdir, "..");
|
||||
dp = ginode(lfdir);
|
||||
dp->di_nlink++;
|
||||
inodirty();
|
||||
lncntp[lfdir]++;
|
||||
pwarn("DIR I=%lu CONNECTED. ", orphan);
|
||||
if (parentdir != (ino_t)-1)
|
||||
printf("PARENT WAS I=%lu\n", parentdir);
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* fix an entry in a directory.
|
||||
*/
|
||||
changeino(dir, name, newnum)
|
||||
ino_t dir;
|
||||
char *name;
|
||||
ino_t newnum;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = chgino;
|
||||
idesc.id_number = dir;
|
||||
idesc.id_fix = DONTKNOW;
|
||||
idesc.id_name = name;
|
||||
idesc.id_parent = newnum; /* new value for name */
|
||||
return (ckinode(ginode(dir), &idesc));
|
||||
}
|
||||
|
||||
/*
|
||||
* make an entry in a directory
|
||||
*/
|
||||
makeentry(parent, ino, name)
|
||||
ino_t parent, ino;
|
||||
char *name;
|
||||
{
|
||||
struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
if (parent < ROOTINO || parent >= maxino ||
|
||||
ino < ROOTINO || ino >= maxino)
|
||||
return (0);
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = mkentry;
|
||||
idesc.id_number = parent;
|
||||
idesc.id_parent = ino; /* this is the inode to enter */
|
||||
idesc.id_fix = DONTKNOW;
|
||||
idesc.id_name = name;
|
||||
dp = ginode(parent);
|
||||
if (dp->di_size % DIRBLKSIZ) {
|
||||
dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
|
||||
inodirty();
|
||||
}
|
||||
if ((ckinode(dp, &idesc) & ALTERED) != 0)
|
||||
return (1);
|
||||
getpathname(pathbuf, parent, parent);
|
||||
dp = ginode(parent);
|
||||
if (expanddir(dp, pathbuf) == 0)
|
||||
return (0);
|
||||
return (ckinode(dp, &idesc) & ALTERED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to expand the size of a directory
|
||||
*/
|
||||
expanddir(dp, name)
|
||||
register struct dinode *dp;
|
||||
char *name;
|
||||
{
|
||||
daddr_t lastbn, newblk;
|
||||
register struct bufarea *bp;
|
||||
char *cp, firstblk[DIRBLKSIZ];
|
||||
|
||||
lastbn = lblkno(&sblock, dp->di_size);
|
||||
if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
|
||||
return (0);
|
||||
if ((newblk = allocblk(sblock.fs_frag)) == 0)
|
||||
return (0);
|
||||
dp->di_db[lastbn + 1] = dp->di_db[lastbn];
|
||||
dp->di_db[lastbn] = newblk;
|
||||
dp->di_size += sblock.fs_bsize;
|
||||
dp->di_blocks += btodb(sblock.fs_bsize);
|
||||
bp = getdirblk(dp->di_db[lastbn + 1],
|
||||
(long)dblksize(&sblock, dp, lastbn + 1));
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
|
||||
bp = getdirblk(newblk, sblock.fs_bsize);
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_bsize];
|
||||
cp += DIRBLKSIZ)
|
||||
bcopy((char *)&emptydir, cp, sizeof emptydir);
|
||||
dirty(bp);
|
||||
bp = getdirblk(dp->di_db[lastbn + 1],
|
||||
(long)dblksize(&sblock, dp, lastbn + 1));
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
|
||||
pwarn("NO SPACE LEFT IN %s", name);
|
||||
if (preen)
|
||||
printf(" (EXPANDED)\n");
|
||||
else if (reply("EXPAND") == 0)
|
||||
goto bad;
|
||||
dirty(bp);
|
||||
inodirty();
|
||||
return (1);
|
||||
bad:
|
||||
dp->di_db[lastbn] = dp->di_db[lastbn + 1];
|
||||
dp->di_db[lastbn + 1] = 0;
|
||||
dp->di_size -= sblock.fs_bsize;
|
||||
dp->di_blocks -= btodb(sblock.fs_bsize);
|
||||
freeblk(newblk, sblock.fs_frag);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a new directory
|
||||
*/
|
||||
allocdir(parent, request, mode)
|
||||
ino_t parent, request;
|
||||
int mode;
|
||||
{
|
||||
ino_t ino;
|
||||
char *cp;
|
||||
struct dinode *dp;
|
||||
register struct bufarea *bp;
|
||||
struct dirtemplate *dirp;
|
||||
|
||||
ino = allocino(request, IFDIR|mode);
|
||||
if (newinofmt)
|
||||
dirp = &dirhead;
|
||||
else
|
||||
dirp = (struct dirtemplate *)&odirhead;
|
||||
dirp->dot_ino = ino;
|
||||
dirp->dotdot_ino = parent;
|
||||
dp = ginode(ino);
|
||||
bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
|
||||
if (bp->b_errs) {
|
||||
freeino(ino);
|
||||
return (0);
|
||||
}
|
||||
bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate));
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_fsize];
|
||||
cp += DIRBLKSIZ)
|
||||
bcopy((char *)&emptydir, cp, sizeof emptydir);
|
||||
dirty(bp);
|
||||
dp->di_nlink = 2;
|
||||
inodirty();
|
||||
if (ino == ROOTINO) {
|
||||
lncntp[ino] = dp->di_nlink;
|
||||
cacheino(dp, ino);
|
||||
return(ino);
|
||||
}
|
||||
if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
|
||||
freeino(ino);
|
||||
return (0);
|
||||
}
|
||||
cacheino(dp, ino);
|
||||
statemap[ino] = statemap[parent];
|
||||
if (statemap[ino] == DSTATE) {
|
||||
lncntp[ino] = dp->di_nlink;
|
||||
lncntp[parent]++;
|
||||
}
|
||||
dp = ginode(parent);
|
||||
dp->di_nlink++;
|
||||
inodirty();
|
||||
return (ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* free a directory inode
|
||||
*/
|
||||
freedir(ino, parent)
|
||||
ino_t ino, parent;
|
||||
{
|
||||
struct dinode *dp;
|
||||
|
||||
if (ino != parent) {
|
||||
dp = ginode(parent);
|
||||
dp->di_nlink--;
|
||||
inodirty();
|
||||
}
|
||||
freeino(ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a temporary name for the lost+found directory.
|
||||
*/
|
||||
lftempname(bufp, ino)
|
||||
char *bufp;
|
||||
ino_t ino;
|
||||
{
|
||||
register ino_t in;
|
||||
register char *cp;
|
||||
int namlen;
|
||||
|
||||
cp = bufp + 2;
|
||||
for (in = maxino; in > 0; in /= 10)
|
||||
cp++;
|
||||
*--cp = 0;
|
||||
namlen = cp - bufp;
|
||||
in = ino;
|
||||
while (cp > bufp) {
|
||||
*--cp = (in % 10) + '0';
|
||||
in /= 10;
|
||||
}
|
||||
*cp = '#';
|
||||
return (namlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a directory block.
|
||||
* Insure that it is held until another is requested.
|
||||
*/
|
||||
struct bufarea *
|
||||
getdirblk(blkno, size)
|
||||
daddr_t blkno;
|
||||
long size;
|
||||
{
|
||||
|
||||
if (pdirbp != 0)
|
||||
pdirbp->b_flags &= ~B_INUSE;
|
||||
pdirbp = getdatablk(blkno, size);
|
||||
return (pdirbp);
|
||||
}
|
||||
291
sbin/fsck/fsck.8
Normal file
291
sbin/fsck/fsck.8
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
.\" Copyright (c) 1980, 1989, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)fsck.8 8.2 (Berkeley) 12/11/93
|
||||
.\"
|
||||
.Dd December 11, 1993
|
||||
.Dt FSCK 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm fsck
|
||||
.Nd filesystem consistency check and interactive repair
|
||||
.Sh SYNOPSIS
|
||||
.Nm fsck
|
||||
.Fl p
|
||||
.Op Fl m Ar mode
|
||||
.Nm fsck
|
||||
.Op Fl b Ar block#
|
||||
.Op Fl c Ar level
|
||||
.Op Fl l Ar maxparallel
|
||||
.Op Fl y
|
||||
.Op Fl n
|
||||
.Op Fl m Ar mode
|
||||
.Op Ar filesystem
|
||||
.Ar ...
|
||||
.Sh DESCRIPTION
|
||||
The first form of
|
||||
.Nm fsck
|
||||
preens a standard set of filesystems or the specified filesystems.
|
||||
It is normally used in the script
|
||||
.Pa /etc/rc
|
||||
during automatic reboot.
|
||||
Here
|
||||
.Nm fsck
|
||||
reads the table
|
||||
.Pa /etc/fstab
|
||||
to determine which filesystems to check.
|
||||
Only partitions in fstab that are mounted ``rw,'' ``rq'' or ``ro''
|
||||
and that have non-zero pass number are checked.
|
||||
Filesystems with pass number 1 (normally just the root filesystem)
|
||||
are checked one at a time.
|
||||
When pass 1 completes, all remaining filesystems are checked,
|
||||
running one process per disk drive.
|
||||
The disk drive containing each filesystem is inferred from the longest prefix
|
||||
of the device name that ends in a digit; the remaining characters are assumed
|
||||
to be the partition designator.
|
||||
.Pp
|
||||
The kernel takes care that only a restricted class of innocuous filesystem
|
||||
inconsistencies can happen unless hardware or software failures intervene.
|
||||
These are limited to the following:
|
||||
.Bl -item -compact
|
||||
.It
|
||||
Unreferenced inodes
|
||||
.It
|
||||
Link counts in inodes too large
|
||||
.It
|
||||
Missing blocks in the free map
|
||||
.It
|
||||
Blocks in the free map also in files
|
||||
.It
|
||||
Counts in the super-block wrong
|
||||
.El
|
||||
.Pp
|
||||
These are the only inconsistencies that
|
||||
.Nm fsck
|
||||
with the
|
||||
.Fl p
|
||||
option will correct; if it encounters other inconsistencies, it exits
|
||||
with an abnormal return status and an automatic reboot will then fail.
|
||||
For each corrected inconsistency one or more lines will be printed
|
||||
identifying the filesystem on which the correction will take place,
|
||||
and the nature of the correction. After successfully correcting a filesystem,
|
||||
.Nm fsck
|
||||
will print the number of files on that filesystem,
|
||||
the number of used and free blocks,
|
||||
and the percentage of fragmentation.
|
||||
.Pp
|
||||
If sent a
|
||||
.Dv QUIT
|
||||
signal,
|
||||
.Nm fsck
|
||||
will finish the filesystem checks, then exit with an abnormal
|
||||
return status that causes an automatic reboot to fail.
|
||||
This is useful when you want to finish the filesystem checks during an
|
||||
automatic reboot,
|
||||
but do not want the machine to come up multiuser after the checks complete.
|
||||
.Pp
|
||||
Without the
|
||||
.Fl p
|
||||
option,
|
||||
.Nm fsck
|
||||
audits and interactively repairs inconsistent conditions for filesystems.
|
||||
If the filesystem is inconsistent the operator is prompted for concurrence
|
||||
before each correction is attempted.
|
||||
It should be noted that some of the corrective actions which are not
|
||||
correctable under the
|
||||
.Fl p
|
||||
option will result in some loss of data.
|
||||
The amount and severity of data lost may be determined from the diagnostic
|
||||
output.
|
||||
The default action for each consistency correction
|
||||
is to wait for the operator to respond
|
||||
.Li yes
|
||||
or
|
||||
.Li no .
|
||||
If the operator does not have write permission on the filesystem
|
||||
.Nm fsck
|
||||
will default to a
|
||||
.Fl n
|
||||
action.
|
||||
.Pp
|
||||
.Nm Fsck
|
||||
has more consistency checks than
|
||||
its predecessors
|
||||
.Em check , dcheck , fcheck ,
|
||||
and
|
||||
.Em icheck
|
||||
combined.
|
||||
.Pp
|
||||
The following flags are interpreted by
|
||||
.Nm fsck .
|
||||
.Bl -tag -width indent
|
||||
.It Fl b
|
||||
Use the block specified immediately after the flag as
|
||||
the super block for the filesystem. Block 32 is usually
|
||||
an alternate super block.
|
||||
.It Fl l
|
||||
Limit the number of parallel checks to the number specified in the following
|
||||
argument.
|
||||
By default, the limit is the number of disks, running one process per disk.
|
||||
If a smaller limit is given, the disks are checked round-robin, one filesystem
|
||||
at a time.
|
||||
.It Fl m
|
||||
Use the mode specified in octal immediately after the flag as the
|
||||
permission bits to use when creating the
|
||||
.Pa lost+found
|
||||
directory rather than the default 1777.
|
||||
In particular, systems that do not wish to have lost files accessible
|
||||
by all users on the system should use a more restrictive
|
||||
set of permissions such as 700.
|
||||
.It Fl y
|
||||
Assume a yes response to all questions asked by
|
||||
.Nm fsck ;
|
||||
this should be used with great caution as this is a free license
|
||||
to continue after essentially unlimited trouble has been encountered.
|
||||
.It Fl n
|
||||
Assume a no response to all questions asked by
|
||||
.Nm fsck
|
||||
except for
|
||||
.Ql CONTINUE? ,
|
||||
which is assumed to be affirmative;
|
||||
do not open the filesystem for writing.
|
||||
.It Fl c
|
||||
Convert the filesystem to the specified level.
|
||||
Note that the level of a filesystem can only be raised.
|
||||
.Bl -tag -width indent
|
||||
There are currently three levels defined:
|
||||
.It 0
|
||||
The filesystem is in the old (static table) format.
|
||||
.It 1
|
||||
The filesystem is in the new (dynamic table) format.
|
||||
.It 2
|
||||
The filesystem supports 32-bit uid's and gid's,
|
||||
short symbolic links are stored in the inode,
|
||||
and directories have an added field showing the file type.
|
||||
.El
|
||||
.Pp
|
||||
In interactive mode,
|
||||
.Nm fsck
|
||||
will list the conversion to be made
|
||||
and ask whether the conversion should be done.
|
||||
If a negative answer is given,
|
||||
no further operations are done on the filesystem.
|
||||
In preen mode,
|
||||
the conversion is listed and done if
|
||||
possible without user interaction.
|
||||
Conversion in preen mode is best used when all the filesystems
|
||||
are being converted at once.
|
||||
The format of a filesystem can be determined from the
|
||||
first line of output from
|
||||
.Xr dumpfs 8 .
|
||||
.El
|
||||
.Pp
|
||||
If no filesystems are given to
|
||||
.Nm fsck
|
||||
then a default list of filesystems is read from
|
||||
the file
|
||||
.Pa /etc/fstab .
|
||||
.Pp
|
||||
.Bl -enum -indent indent -compact
|
||||
Inconsistencies checked are as follows:
|
||||
.It
|
||||
Blocks claimed by more than one inode or the free map.
|
||||
.It
|
||||
Blocks claimed by an inode outside the range of the filesystem.
|
||||
.It
|
||||
Incorrect link counts.
|
||||
.It
|
||||
Size checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
Directory size not a multiple of DIRBLKSIZ.
|
||||
.It
|
||||
Partially truncated file.
|
||||
.El
|
||||
.It
|
||||
Bad inode format.
|
||||
.It
|
||||
Blocks not accounted for anywhere.
|
||||
.It
|
||||
Directory checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
File pointing to unallocated inode.
|
||||
.It
|
||||
Inode number out of range.
|
||||
.It
|
||||
Dot or dot-dot not the first two entries of a directory
|
||||
or having the wrong inode number.
|
||||
.El
|
||||
.It
|
||||
Super Block checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
More blocks for inodes than there are in the filesystem.
|
||||
.It
|
||||
Bad free block map format.
|
||||
.It
|
||||
Total free block and/or free inode count incorrect.
|
||||
.El
|
||||
.El
|
||||
.Pp
|
||||
Orphaned files and directories (allocated but unreferenced) are,
|
||||
with the operator's concurrence, reconnected by
|
||||
placing them in the
|
||||
.Pa lost+found
|
||||
directory.
|
||||
The name assigned is the inode number.
|
||||
If the
|
||||
.Pa lost+found
|
||||
directory does not exist, it is created.
|
||||
If there is insufficient space its size is increased.
|
||||
.Pp
|
||||
Because of inconsistencies between the block device and the buffer cache,
|
||||
the raw device should always be used.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/fstab -compact
|
||||
.It Pa /etc/fstab
|
||||
contains default list of filesystems to check.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
The diagnostics produced by
|
||||
.Nm fsck
|
||||
are fully enumerated and explained in Appendix A of
|
||||
.Rs
|
||||
.%T "Fsck \- The UNIX File System Check Program"
|
||||
.Re
|
||||
.Sh SEE ALSO
|
||||
.Xr fstab 5 ,
|
||||
.Xr fs 5 ,
|
||||
.Xr fsdb 8 ,
|
||||
.Xr newfs 8 ,
|
||||
.Xr mkfs 8 ,
|
||||
.Xr reboot 8
|
||||
215
sbin/fsck/fsck.h
Normal file
215
sbin/fsck/fsck.h
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fsck.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#define MAXDUP 10 /* limit on dup blks (per inode) */
|
||||
#define MAXBAD 10 /* limit on bad blks (per inode) */
|
||||
#define MAXBUFSPACE 40*1024 /* maximum space to allocate to buffers */
|
||||
#define INOBUFSIZE 56*1024 /* size of buffer to read inodes in pass1 */
|
||||
|
||||
#ifndef BUFSIZ
|
||||
#define BUFSIZ 1024
|
||||
#endif
|
||||
|
||||
#define USTATE 01 /* inode not allocated */
|
||||
#define FSTATE 02 /* inode is file */
|
||||
#define DSTATE 03 /* inode is directory */
|
||||
#define DFOUND 04 /* directory found during descent */
|
||||
#define DCLEAR 05 /* directory is to be cleared */
|
||||
#define FCLEAR 06 /* file is to be cleared */
|
||||
|
||||
/*
|
||||
* buffer cache structure.
|
||||
*/
|
||||
struct bufarea {
|
||||
struct bufarea *b_next; /* free list queue */
|
||||
struct bufarea *b_prev; /* free list queue */
|
||||
daddr_t b_bno;
|
||||
int b_size;
|
||||
int b_errs;
|
||||
int b_flags;
|
||||
union {
|
||||
char *b_buf; /* buffer space */
|
||||
daddr_t *b_indir; /* indirect block */
|
||||
struct fs *b_fs; /* super block */
|
||||
struct cg *b_cg; /* cylinder group */
|
||||
struct dinode *b_dinode; /* inode block */
|
||||
} b_un;
|
||||
char b_dirty;
|
||||
};
|
||||
|
||||
#define B_INUSE 1
|
||||
|
||||
#define MINBUFS 5 /* minimum number of buffers required */
|
||||
struct bufarea bufhead; /* head of list of other blks in filesys */
|
||||
struct bufarea sblk; /* file system superblock */
|
||||
struct bufarea cgblk; /* cylinder group blocks */
|
||||
struct bufarea *pdirbp; /* current directory contents */
|
||||
struct bufarea *pbp; /* current inode block */
|
||||
struct bufarea *getdatablk();
|
||||
|
||||
#define dirty(bp) (bp)->b_dirty = 1
|
||||
#define initbarea(bp) \
|
||||
(bp)->b_dirty = 0; \
|
||||
(bp)->b_bno = (daddr_t)-1; \
|
||||
(bp)->b_flags = 0;
|
||||
|
||||
#define sbdirty() sblk.b_dirty = 1
|
||||
#define cgdirty() cgblk.b_dirty = 1
|
||||
#define sblock (*sblk.b_un.b_fs)
|
||||
#define cgrp (*cgblk.b_un.b_cg)
|
||||
|
||||
enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
|
||||
|
||||
struct inodesc {
|
||||
enum fixstate id_fix; /* policy on fixing errors */
|
||||
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 */
|
||||
quad_t 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 */
|
||||
struct direct *id_dirp; /* for DATA nodes, ptr to current entry */
|
||||
char *id_name; /* for DATA nodes, name to find or enter */
|
||||
char id_type; /* type of descriptor, DATA or ADDR */
|
||||
};
|
||||
/* file types */
|
||||
#define DATA 1
|
||||
#define ADDR 2
|
||||
|
||||
/*
|
||||
* Linked list of duplicate blocks.
|
||||
*
|
||||
* The list is composed of two parts. The first part of the
|
||||
* list (from duplist through the node pointed to by muldup)
|
||||
* contains a single copy of each duplicate block that has been
|
||||
* found. The second part of the list (from muldup to the end)
|
||||
* contains duplicate blocks that have been found more than once.
|
||||
* To check if a block has been found as a duplicate it is only
|
||||
* necessary to search from duplist through muldup. To find the
|
||||
* total number of times that a block has been found as a duplicate
|
||||
* the entire list must be searched for occurences of the block
|
||||
* in question. The following diagram shows a sample list where
|
||||
* w (found twice), x (found once), y (found three times), and z
|
||||
* (found once) are duplicate block numbers:
|
||||
*
|
||||
* w -> y -> x -> z -> y -> w -> y
|
||||
* ^ ^
|
||||
* | |
|
||||
* duplist muldup
|
||||
*/
|
||||
struct dups {
|
||||
struct dups *next;
|
||||
daddr_t dup;
|
||||
};
|
||||
struct dups *duplist; /* head of dup list */
|
||||
struct dups *muldup; /* end of unique duplicate dup block numbers */
|
||||
|
||||
/*
|
||||
* Linked list of inodes with zero link counts.
|
||||
*/
|
||||
struct zlncnt {
|
||||
struct zlncnt *next;
|
||||
ino_t zlncnt;
|
||||
};
|
||||
struct zlncnt *zlnhead; /* head of zero link count list */
|
||||
|
||||
/*
|
||||
* Inode cache data structures.
|
||||
*/
|
||||
struct inoinfo {
|
||||
struct inoinfo *i_nexthash; /* next entry in hash chain */
|
||||
ino_t i_number; /* inode number of this entry */
|
||||
ino_t i_parent; /* inode number of parent */
|
||||
ino_t i_dotdot; /* inode number of `..' */
|
||||
size_t i_isize; /* size of inode */
|
||||
u_int i_numblks; /* size of block array in bytes */
|
||||
daddr_t i_blks[1]; /* actually longer */
|
||||
} **inphead, **inpsort;
|
||||
long numdirs, listmax, inplast;
|
||||
|
||||
char *cdevname; /* name of device being checked */
|
||||
long dev_bsize; /* computed value of DEV_BSIZE */
|
||||
long secsize; /* actual disk sector size */
|
||||
char nflag; /* assume a no response */
|
||||
char yflag; /* assume a yes response */
|
||||
int bflag; /* location of alternate super block */
|
||||
int debug; /* output debugging info */
|
||||
int cvtlevel; /* convert to newer file system format */
|
||||
int doinglevel1; /* converting to new cylinder group format */
|
||||
int doinglevel2; /* converting to new inode format */
|
||||
int newinofmt; /* filesystem has new inode format */
|
||||
char preen; /* just fix normal inconsistencies */
|
||||
char hotroot; /* checking root device */
|
||||
char havesb; /* superblock has been read */
|
||||
int fsmodified; /* 1 => write done to file system */
|
||||
int fsreadfd; /* file descriptor for reading file system */
|
||||
int fswritefd; /* file descriptor for writing file system */
|
||||
|
||||
daddr_t maxfsblock; /* number of blocks in the file system */
|
||||
char *blockmap; /* ptr to primary blk allocation map */
|
||||
ino_t maxino; /* number of inodes in file system */
|
||||
ino_t lastino; /* last inode in use */
|
||||
char *statemap; /* ptr to inode state table */
|
||||
char *typemap; /* ptr to inode type table */
|
||||
short *lncntp; /* ptr to link count table */
|
||||
|
||||
ino_t lfdir; /* lost & found directory inode number */
|
||||
char *lfname; /* lost & found directory name */
|
||||
int lfmode; /* lost & found directory creation mode */
|
||||
|
||||
daddr_t n_blks; /* number of blocks in use */
|
||||
daddr_t n_files; /* number of files in use */
|
||||
|
||||
#define clearinode(dp) (*(dp) = zino)
|
||||
struct dinode zino;
|
||||
|
||||
#define setbmap(blkno) setbit(blockmap, blkno)
|
||||
#define testbmap(blkno) isset(blockmap, blkno)
|
||||
#define clrbmap(blkno) clrbit(blockmap, blkno)
|
||||
|
||||
#define STOP 0x01
|
||||
#define SKIP 0x02
|
||||
#define KEEPON 0x04
|
||||
#define ALTERED 0x08
|
||||
#define FOUND 0x10
|
||||
|
||||
time_t time();
|
||||
struct dinode *ginode();
|
||||
struct inoinfo *getinoinfo();
|
||||
void getblk();
|
||||
ino_t allocino();
|
||||
int findino();
|
||||
543
sbin/fsck/inode.c
Normal file
543
sbin/fsck/inode.c
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)inode.c 8.4 (Berkeley) 4/18/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
static ino_t startinum;
|
||||
|
||||
ckinode(dp, idesc)
|
||||
struct dinode *dp;
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register daddr_t *ap;
|
||||
long ret, n, ndb, offset;
|
||||
struct dinode dino;
|
||||
quad_t remsize, sizepb;
|
||||
mode_t mode;
|
||||
|
||||
if (idesc->id_fix != IGNORE)
|
||||
idesc->id_fix = DONTKNOW;
|
||||
idesc->id_entryno = 0;
|
||||
idesc->id_filesize = dp->di_size;
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
|
||||
dp->di_size < sblock.fs_maxsymlinklen))
|
||||
return (KEEPON);
|
||||
dino = *dp;
|
||||
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)
|
||||
idesc->id_numfrags =
|
||||
numfrags(&sblock, fragroundup(&sblock, offset));
|
||||
else
|
||||
idesc->id_numfrags = sblock.fs_frag;
|
||||
if (*ap == 0)
|
||||
continue;
|
||||
idesc->id_blkno = *ap;
|
||||
if (idesc->id_type == ADDR)
|
||||
ret = (*idesc->id_func)(idesc);
|
||||
else
|
||||
ret = dirscan(idesc);
|
||||
if (ret & STOP)
|
||||
return (ret);
|
||||
}
|
||||
idesc->id_numfrags = sblock.fs_frag;
|
||||
remsize = dino.di_size - sblock.fs_bsize * NDADDR;
|
||||
sizepb = sblock.fs_bsize;
|
||||
for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
|
||||
if (*ap) {
|
||||
idesc->id_blkno = *ap;
|
||||
ret = iblock(idesc, n, remsize);
|
||||
if (ret & STOP)
|
||||
return (ret);
|
||||
}
|
||||
sizepb *= NINDIR(&sblock);
|
||||
remsize -= sizepb;
|
||||
}
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
iblock(idesc, ilevel, isize)
|
||||
struct inodesc *idesc;
|
||||
long ilevel;
|
||||
quad_t isize;
|
||||
{
|
||||
register daddr_t *ap;
|
||||
register daddr_t *aplim;
|
||||
register struct bufarea *bp;
|
||||
int i, n, (*func)(), nif;
|
||||
quad_t sizepb;
|
||||
char buf[BUFSIZ];
|
||||
extern int dirscan(), pass1check();
|
||||
|
||||
if (idesc->id_type == ADDR) {
|
||||
func = idesc->id_func;
|
||||
if (((n = (*func)(idesc)) & KEEPON) == 0)
|
||||
return (n);
|
||||
} else
|
||||
func = dirscan;
|
||||
if (chkrange(idesc->id_blkno, idesc->id_numfrags))
|
||||
return (SKIP);
|
||||
bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
|
||||
ilevel--;
|
||||
for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
|
||||
sizepb *= NINDIR(&sblock);
|
||||
nif = howmany(isize , sizepb);
|
||||
if (nif > NINDIR(&sblock))
|
||||
nif = NINDIR(&sblock);
|
||||
if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
|
||||
aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
|
||||
for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
|
||||
if (*ap == 0)
|
||||
continue;
|
||||
(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
|
||||
idesc->id_number);
|
||||
if (dofix(idesc, buf)) {
|
||||
*ap = 0;
|
||||
dirty(bp);
|
||||
}
|
||||
}
|
||||
flush(fswritefd, bp);
|
||||
}
|
||||
aplim = &bp->b_un.b_indir[nif];
|
||||
for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
|
||||
if (*ap) {
|
||||
idesc->id_blkno = *ap;
|
||||
if (ilevel == 0)
|
||||
n = (*func)(idesc);
|
||||
else
|
||||
n = iblock(idesc, ilevel, isize);
|
||||
if (n & STOP) {
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return (n);
|
||||
}
|
||||
}
|
||||
isize -= sizepb;
|
||||
}
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that a block in a legal block number.
|
||||
* Return 0 if in range, 1 if out of range.
|
||||
*/
|
||||
chkrange(blk, cnt)
|
||||
daddr_t blk;
|
||||
int cnt;
|
||||
{
|
||||
register int c;
|
||||
|
||||
if ((unsigned)(blk + cnt) > maxfsblock)
|
||||
return (1);
|
||||
c = dtog(&sblock, blk);
|
||||
if (blk < cgdmin(&sblock, c)) {
|
||||
if ((blk + cnt) > cgsblock(&sblock, c)) {
|
||||
if (debug) {
|
||||
printf("blk %ld < cgdmin %ld;",
|
||||
blk, cgdmin(&sblock, c));
|
||||
printf(" blk + cnt %ld > cgsbase %ld\n",
|
||||
blk + cnt, cgsblock(&sblock, c));
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
if ((blk + cnt) > cgbase(&sblock, c+1)) {
|
||||
if (debug) {
|
||||
printf("blk %ld >= cgdmin %ld;",
|
||||
blk, cgdmin(&sblock, c));
|
||||
printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
|
||||
blk+cnt, sblock.fs_fpg);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* General purpose interface for reading inodes.
|
||||
*/
|
||||
struct dinode *
|
||||
ginode(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
daddr_t iblk;
|
||||
|
||||
if (inumber < ROOTINO || inumber > maxino)
|
||||
errexit("bad inode number %d to ginode\n", inumber);
|
||||
if (startinum == 0 ||
|
||||
inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
|
||||
iblk = ino_to_fsba(&sblock, inumber);
|
||||
if (pbp != 0)
|
||||
pbp->b_flags &= ~B_INUSE;
|
||||
pbp = getdatablk(iblk, sblock.fs_bsize);
|
||||
startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
|
||||
}
|
||||
return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special purpose version of ginode used to optimize first pass
|
||||
* over all the inodes in numerical order.
|
||||
*/
|
||||
ino_t nextino, lastinum;
|
||||
long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
|
||||
struct dinode *inodebuf;
|
||||
|
||||
struct dinode *
|
||||
getnextinode(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
long size;
|
||||
daddr_t dblk;
|
||||
static struct dinode *dp;
|
||||
|
||||
if (inumber != nextino++ || inumber > maxino)
|
||||
errexit("bad inode number %d to nextinode\n", inumber);
|
||||
if (inumber >= lastinum) {
|
||||
readcnt++;
|
||||
dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
|
||||
if (readcnt % readpercg == 0) {
|
||||
size = partialsize;
|
||||
lastinum += partialcnt;
|
||||
} else {
|
||||
size = inobufsize;
|
||||
lastinum += fullcnt;
|
||||
}
|
||||
(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
|
||||
dp = inodebuf;
|
||||
}
|
||||
return (dp++);
|
||||
}
|
||||
|
||||
resetinodebuf()
|
||||
{
|
||||
|
||||
startinum = 0;
|
||||
nextino = 0;
|
||||
lastinum = 0;
|
||||
readcnt = 0;
|
||||
inobufsize = blkroundup(&sblock, INOBUFSIZE);
|
||||
fullcnt = inobufsize / sizeof(struct dinode);
|
||||
readpercg = sblock.fs_ipg / fullcnt;
|
||||
partialcnt = sblock.fs_ipg % fullcnt;
|
||||
partialsize = partialcnt * sizeof(struct dinode);
|
||||
if (partialcnt != 0) {
|
||||
readpercg++;
|
||||
} else {
|
||||
partialcnt = fullcnt;
|
||||
partialsize = inobufsize;
|
||||
}
|
||||
if (inodebuf == NULL &&
|
||||
(inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
|
||||
errexit("Cannot allocate space for inode buffer\n");
|
||||
while (nextino < ROOTINO)
|
||||
(void)getnextinode(nextino);
|
||||
}
|
||||
|
||||
freeinodebuf()
|
||||
{
|
||||
|
||||
if (inodebuf != NULL)
|
||||
free((char *)inodebuf);
|
||||
inodebuf = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines to maintain information about directory inodes.
|
||||
* This is built during the first pass and used during the
|
||||
* second and third passes.
|
||||
*
|
||||
* Enter inodes into the cache.
|
||||
*/
|
||||
cacheino(dp, inumber)
|
||||
register struct dinode *dp;
|
||||
ino_t inumber;
|
||||
{
|
||||
register struct inoinfo *inp;
|
||||
struct inoinfo **inpp;
|
||||
unsigned int blks;
|
||||
|
||||
blks = howmany(dp->di_size, sblock.fs_bsize);
|
||||
if (blks > NDADDR)
|
||||
blks = NDADDR + NIADDR;
|
||||
inp = (struct inoinfo *)
|
||||
malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
|
||||
if (inp == NULL)
|
||||
return;
|
||||
inpp = &inphead[inumber % numdirs];
|
||||
inp->i_nexthash = *inpp;
|
||||
*inpp = inp;
|
||||
inp->i_parent = (ino_t)0;
|
||||
inp->i_dotdot = (ino_t)0;
|
||||
inp->i_number = inumber;
|
||||
inp->i_isize = dp->di_size;
|
||||
inp->i_numblks = blks * sizeof(daddr_t);
|
||||
bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
|
||||
(size_t)inp->i_numblks);
|
||||
if (inplast == listmax) {
|
||||
listmax += 100;
|
||||
inpsort = (struct inoinfo **)realloc((char *)inpsort,
|
||||
(unsigned)listmax * sizeof(struct inoinfo *));
|
||||
if (inpsort == NULL)
|
||||
errexit("cannot increase directory list");
|
||||
}
|
||||
inpsort[inplast++] = inp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an inode cache structure.
|
||||
*/
|
||||
struct inoinfo *
|
||||
getinoinfo(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
register struct inoinfo *inp;
|
||||
|
||||
for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
|
||||
if (inp->i_number != inumber)
|
||||
continue;
|
||||
return (inp);
|
||||
}
|
||||
errexit("cannot find inode %d\n", inumber);
|
||||
return ((struct inoinfo *)0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up all the inode cache structure.
|
||||
*/
|
||||
inocleanup()
|
||||
{
|
||||
register struct inoinfo **inpp;
|
||||
|
||||
if (inphead == NULL)
|
||||
return;
|
||||
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
|
||||
free((char *)(*inpp));
|
||||
free((char *)inphead);
|
||||
free((char *)inpsort);
|
||||
inphead = inpsort = NULL;
|
||||
}
|
||||
|
||||
inodirty()
|
||||
{
|
||||
|
||||
dirty(pbp);
|
||||
}
|
||||
|
||||
clri(idesc, type, flag)
|
||||
register struct inodesc *idesc;
|
||||
char *type;
|
||||
int flag;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
|
||||
dp = ginode(idesc->id_number);
|
||||
if (flag == 1) {
|
||||
pwarn("%s %s", type,
|
||||
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
|
||||
pinode(idesc->id_number);
|
||||
}
|
||||
if (preen || reply("CLEAR") == 1) {
|
||||
if (preen)
|
||||
printf(" (CLEARED)\n");
|
||||
n_files--;
|
||||
(void)ckinode(dp, idesc);
|
||||
clearinode(dp);
|
||||
statemap[idesc->id_number] = USTATE;
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
|
||||
findname(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (dirp->d_ino != idesc->id_parent)
|
||||
return (KEEPON);
|
||||
bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
|
||||
return (STOP|FOUND);
|
||||
}
|
||||
|
||||
findino(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (dirp->d_ino == 0)
|
||||
return (KEEPON);
|
||||
if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
|
||||
dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
|
||||
idesc->id_parent = dirp->d_ino;
|
||||
return (STOP|FOUND);
|
||||
}
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
pinode(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register char *p;
|
||||
struct passwd *pw;
|
||||
char *ctime();
|
||||
|
||||
printf(" I=%lu ", ino);
|
||||
if (ino < ROOTINO || ino > maxino)
|
||||
return;
|
||||
dp = ginode(ino);
|
||||
printf(" OWNER=");
|
||||
if ((pw = getpwuid((int)dp->di_uid)) != 0)
|
||||
printf("%s ", pw->pw_name);
|
||||
else
|
||||
printf("%u ", (unsigned)dp->di_uid);
|
||||
printf("MODE=%o\n", dp->di_mode);
|
||||
if (preen)
|
||||
printf("%s: ", cdevname);
|
||||
printf("SIZE=%qu ", dp->di_size);
|
||||
p = ctime(&dp->di_mtime.ts_sec);
|
||||
printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
|
||||
}
|
||||
|
||||
blkerror(ino, type, blk)
|
||||
ino_t ino;
|
||||
char *type;
|
||||
daddr_t blk;
|
||||
{
|
||||
|
||||
pfatal("%ld %s I=%lu", blk, type, ino);
|
||||
printf("\n");
|
||||
switch (statemap[ino]) {
|
||||
|
||||
case FSTATE:
|
||||
statemap[ino] = FCLEAR;
|
||||
return;
|
||||
|
||||
case DSTATE:
|
||||
statemap[ino] = DCLEAR;
|
||||
return;
|
||||
|
||||
case FCLEAR:
|
||||
case DCLEAR:
|
||||
return;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d TO BLKERR", statemap[ino]);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate an unused inode
|
||||
*/
|
||||
ino_t
|
||||
allocino(request, type)
|
||||
ino_t request;
|
||||
int type;
|
||||
{
|
||||
register ino_t ino;
|
||||
register struct dinode *dp;
|
||||
|
||||
if (request == 0)
|
||||
request = ROOTINO;
|
||||
else if (statemap[request] != USTATE)
|
||||
return (0);
|
||||
for (ino = request; ino < maxino; ino++)
|
||||
if (statemap[ino] == USTATE)
|
||||
break;
|
||||
if (ino == maxino)
|
||||
return (0);
|
||||
switch (type & IFMT) {
|
||||
case IFDIR:
|
||||
statemap[ino] = DSTATE;
|
||||
break;
|
||||
case IFREG:
|
||||
case IFLNK:
|
||||
statemap[ino] = FSTATE;
|
||||
break;
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
dp = ginode(ino);
|
||||
dp->di_db[0] = allocblk((long)1);
|
||||
if (dp->di_db[0] == 0) {
|
||||
statemap[ino] = USTATE;
|
||||
return (0);
|
||||
}
|
||||
dp->di_mode = type;
|
||||
(void)time(&dp->di_atime.ts_sec);
|
||||
dp->di_mtime = dp->di_ctime = dp->di_atime;
|
||||
dp->di_size = sblock.fs_fsize;
|
||||
dp->di_blocks = btodb(sblock.fs_fsize);
|
||||
n_files++;
|
||||
inodirty();
|
||||
if (newinofmt)
|
||||
typemap[ino] = IFTODT(type);
|
||||
return (ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* deallocate an inode
|
||||
*/
|
||||
freeino(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
extern int pass4check();
|
||||
struct dinode *dp;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
idesc.id_number = ino;
|
||||
dp = ginode(ino);
|
||||
(void)ckinode(dp, &idesc);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
statemap[ino] = USTATE;
|
||||
n_files--;
|
||||
}
|
||||
318
sbin/fsck/main.c
Normal file
318
sbin/fsck/main.c
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1980, 1986, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mount.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <fstab.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "fsck.h"
|
||||
|
||||
void catch(), catchquit(), voidquit();
|
||||
int returntosingle;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch;
|
||||
int ret, maxrun = 0;
|
||||
extern int docheck(), checkfilesys();
|
||||
extern char *optarg, *blockcheck();
|
||||
extern int optind;
|
||||
|
||||
sync();
|
||||
while ((ch = getopt(argc, argv, "dpnNyYb:c:l:m:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
preen++;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
bflag = argtoi('b', "number", optarg, 10);
|
||||
printf("Alternate super block location: %d\n", bflag);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
cvtlevel = argtoi('c', "conversion level", optarg, 10);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
maxrun = argtoi('l', "number", optarg, 10);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
lfmode = argtoi('m', "mode", optarg, 8);
|
||||
if (lfmode &~ 07777)
|
||||
errexit("bad mode to -m: %o\n", lfmode);
|
||||
printf("** lost+found creation mode %o\n", lfmode);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
nflag++;
|
||||
yflag = 0;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
case 'Y':
|
||||
yflag++;
|
||||
nflag = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("%c option?\n", ch);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
(void)signal(SIGINT, catch);
|
||||
if (preen)
|
||||
(void)signal(SIGQUIT, catchquit);
|
||||
if (argc) {
|
||||
while (argc-- > 0)
|
||||
(void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
|
||||
exit(0);
|
||||
}
|
||||
ret = checkfstab(preen, maxrun, docheck, checkfilesys);
|
||||
if (returntosingle)
|
||||
exit(2);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
argtoi(flag, req, str, base)
|
||||
int flag;
|
||||
char *req, *str;
|
||||
int base;
|
||||
{
|
||||
char *cp;
|
||||
int ret;
|
||||
|
||||
ret = (int)strtol(str, &cp, base);
|
||||
if (cp == str || *cp)
|
||||
errexit("-%c flag requires a %s\n", flag, req);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether a filesystem should be checked.
|
||||
*/
|
||||
docheck(fsp)
|
||||
register struct fstab *fsp;
|
||||
{
|
||||
|
||||
if (strcmp(fsp->fs_vfstype, "ufs") ||
|
||||
(strcmp(fsp->fs_type, FSTAB_RW) &&
|
||||
strcmp(fsp->fs_type, FSTAB_RO)) ||
|
||||
fsp->fs_passno == 0)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the specified filesystem.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
checkfilesys(filesys, mntpt, auxdata, child)
|
||||
char *filesys, *mntpt;
|
||||
long auxdata;
|
||||
{
|
||||
daddr_t n_ffree, n_bfree;
|
||||
struct dups *dp;
|
||||
struct zlncnt *zlnp;
|
||||
int cylno;
|
||||
|
||||
if (preen && child)
|
||||
(void)signal(SIGQUIT, voidquit);
|
||||
cdevname = filesys;
|
||||
if (debug && preen)
|
||||
pwarn("starting\n");
|
||||
if (setup(filesys) == 0) {
|
||||
if (preen)
|
||||
pfatal("CAN'T CHECK FILE SYSTEM.");
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* 1: scan inodes tallying blocks used
|
||||
*/
|
||||
if (preen == 0) {
|
||||
printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
|
||||
if (hotroot)
|
||||
printf("** Root file system\n");
|
||||
printf("** Phase 1 - Check Blocks and Sizes\n");
|
||||
}
|
||||
pass1();
|
||||
|
||||
/*
|
||||
* 1b: locate first references to duplicates, if any
|
||||
*/
|
||||
if (duplist) {
|
||||
if (preen)
|
||||
pfatal("INTERNAL ERROR: dups with -p");
|
||||
printf("** Phase 1b - Rescan For More DUPS\n");
|
||||
pass1b();
|
||||
}
|
||||
|
||||
/*
|
||||
* 2: traverse directories from root to mark all connected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 2 - Check Pathnames\n");
|
||||
pass2();
|
||||
|
||||
/*
|
||||
* 3: scan inodes looking for disconnected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 3 - Check Connectivity\n");
|
||||
pass3();
|
||||
|
||||
/*
|
||||
* 4: scan inodes looking for disconnected files; check reference counts
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 4 - Check Reference Counts\n");
|
||||
pass4();
|
||||
|
||||
/*
|
||||
* 5: check and repair resource counts in cylinder groups
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 5 - Check Cyl groups\n");
|
||||
pass5();
|
||||
|
||||
/*
|
||||
* print out summary statistics
|
||||
*/
|
||||
n_ffree = sblock.fs_cstotal.cs_nffree;
|
||||
n_bfree = sblock.fs_cstotal.cs_nbfree;
|
||||
pwarn("%ld files, %ld used, %ld free ",
|
||||
n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
|
||||
printf("(%ld frags, %ld blocks, %d.%d%% fragmentation)\n",
|
||||
n_ffree, n_bfree, (n_ffree * 100) / sblock.fs_dsize,
|
||||
((n_ffree * 1000 + sblock.fs_dsize / 2) / sblock.fs_dsize) % 10);
|
||||
if (debug &&
|
||||
(n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
|
||||
printf("%ld files missing\n", n_files);
|
||||
if (debug) {
|
||||
n_blks += sblock.fs_ncg *
|
||||
(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
|
||||
n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
|
||||
n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
|
||||
printf("%ld blocks missing\n", n_blks);
|
||||
if (duplist != NULL) {
|
||||
printf("The following duplicate blocks remain:");
|
||||
for (dp = duplist; dp; dp = dp->next)
|
||||
printf(" %ld,", dp->dup);
|
||||
printf("\n");
|
||||
}
|
||||
if (zlnhead != NULL) {
|
||||
printf("The following zero link count inodes remain:");
|
||||
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
|
||||
printf(" %lu,", zlnp->zlncnt);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
zlnhead = (struct zlncnt *)0;
|
||||
duplist = (struct dups *)0;
|
||||
muldup = (struct dups *)0;
|
||||
inocleanup();
|
||||
if (fsmodified) {
|
||||
(void)time(&sblock.fs_time);
|
||||
sbdirty();
|
||||
}
|
||||
if (cvtlevel && sblk.b_dirty) {
|
||||
/*
|
||||
* Write out the duplicate super blocks
|
||||
*/
|
||||
for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
|
||||
bwrite(fswritefd, (char *)&sblock,
|
||||
fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE);
|
||||
}
|
||||
ckfini();
|
||||
free(blockmap);
|
||||
free(statemap);
|
||||
free((char *)lncntp);
|
||||
if (!fsmodified)
|
||||
return (0);
|
||||
if (!preen)
|
||||
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
|
||||
if (hotroot) {
|
||||
struct statfs stfs_buf;
|
||||
/*
|
||||
* We modified the root. Do a mount update on
|
||||
* it, unless it is read-write, so we can continue.
|
||||
*/
|
||||
if (statfs("/", &stfs_buf) == 0) {
|
||||
long flags = stfs_buf.f_flags;
|
||||
struct ufs_args args;
|
||||
int ret;
|
||||
|
||||
if (flags & MNT_RDONLY) {
|
||||
args.fspec = 0;
|
||||
args.export.ex_flags = 0;
|
||||
args.export.ex_root = 0;
|
||||
flags |= MNT_UPDATE | MNT_RELOAD;
|
||||
ret = mount(MOUNT_UFS, "/", flags, &args);
|
||||
if (ret == 0)
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (!preen)
|
||||
printf("\n***** REBOOT NOW *****\n");
|
||||
sync();
|
||||
return (4);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
314
sbin/fsck/pass1.c
Normal file
314
sbin/fsck/pass1.c
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
static daddr_t badblk;
|
||||
static daddr_t dupblk;
|
||||
int pass1check();
|
||||
struct dinode *getnextinode();
|
||||
|
||||
pass1()
|
||||
{
|
||||
ino_t inumber;
|
||||
int c, i, cgd;
|
||||
struct inodesc idesc;
|
||||
|
||||
/*
|
||||
* Set file system reserved blocks in used block map.
|
||||
*/
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
cgd = cgdmin(&sblock, c);
|
||||
if (c == 0) {
|
||||
i = cgbase(&sblock, c);
|
||||
cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
} else
|
||||
i = cgsblock(&sblock, c);
|
||||
for (; i < cgd; i++)
|
||||
setbmap(i);
|
||||
}
|
||||
/*
|
||||
* Find all allocated blocks.
|
||||
*/
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass1check;
|
||||
inumber = 0;
|
||||
n_files = n_blks = 0;
|
||||
resetinodebuf();
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
|
||||
if (inumber < ROOTINO)
|
||||
continue;
|
||||
checkinode(inumber, &idesc);
|
||||
}
|
||||
}
|
||||
freeinodebuf();
|
||||
}
|
||||
|
||||
checkinode(inumber, idesc)
|
||||
ino_t inumber;
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
struct zlncnt *zlnp;
|
||||
int ndb, j;
|
||||
mode_t mode;
|
||||
char symbuf[MAXSYMLINKLEN];
|
||||
|
||||
dp = getnextinode(inumber);
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == 0) {
|
||||
if (bcmp((char *)dp->di_db, (char *)zino.di_db,
|
||||
NDADDR * sizeof(daddr_t)) ||
|
||||
bcmp((char *)dp->di_ib, (char *)zino.di_ib,
|
||||
NIADDR * sizeof(daddr_t)) ||
|
||||
dp->di_mode || dp->di_size) {
|
||||
pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
|
||||
if (reply("CLEAR") == 1) {
|
||||
dp = ginode(inumber);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
statemap[inumber] = USTATE;
|
||||
return;
|
||||
}
|
||||
lastino = inumber;
|
||||
if (/* dp->di_size < 0 || */
|
||||
dp->di_size + sblock.fs_bsize - 1 < dp->di_size) {
|
||||
if (debug)
|
||||
printf("bad size %qu:", dp->di_size);
|
||||
goto unknown;
|
||||
}
|
||||
if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
|
||||
dp = ginode(inumber);
|
||||
dp->di_size = sblock.fs_fsize;
|
||||
dp->di_mode = IFREG|0600;
|
||||
inodirty();
|
||||
}
|
||||
ndb = howmany(dp->di_size, sblock.fs_bsize);
|
||||
if (ndb < 0) {
|
||||
if (debug)
|
||||
printf("bad size %qu ndb %d:",
|
||||
dp->di_size, ndb);
|
||||
goto unknown;
|
||||
}
|
||||
if (mode == IFBLK || mode == IFCHR)
|
||||
ndb++;
|
||||
if (mode == IFLNK) {
|
||||
if (doinglevel2 &&
|
||||
dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
|
||||
dp->di_blocks != 0) {
|
||||
if (bread(fsreadfd, symbuf,
|
||||
fsbtodb(&sblock, dp->di_db[0]),
|
||||
(long)dp->di_size) != 0)
|
||||
errexit("cannot read symlink");
|
||||
if (debug) {
|
||||
symbuf[dp->di_size] = 0;
|
||||
printf("convert symlink %d(%s) of size %d\n",
|
||||
inumber, symbuf, (long)dp->di_size);
|
||||
}
|
||||
dp = ginode(inumber);
|
||||
bcopy(symbuf, (caddr_t)dp->di_shortlink,
|
||||
(long)dp->di_size);
|
||||
dp->di_blocks = 0;
|
||||
inodirty();
|
||||
}
|
||||
/*
|
||||
* Fake ndb value so direct/indirect block checks below
|
||||
* will detect any garbage after symlink string.
|
||||
*/
|
||||
if (dp->di_size < sblock.fs_maxsymlinklen) {
|
||||
ndb = howmany(dp->di_size, sizeof(daddr_t));
|
||||
if (ndb > NDADDR) {
|
||||
j = ndb - NDADDR;
|
||||
for (ndb = 1; j > 1; j--)
|
||||
ndb *= NINDIR(&sblock);
|
||||
ndb += NDADDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = ndb; j < NDADDR; j++)
|
||||
if (dp->di_db[j] != 0) {
|
||||
if (debug)
|
||||
printf("bad direct addr: %ld\n", dp->di_db[j]);
|
||||
goto unknown;
|
||||
}
|
||||
for (j = 0, ndb -= NDADDR; ndb > 0; j++)
|
||||
ndb /= NINDIR(&sblock);
|
||||
for (; j < NIADDR; j++)
|
||||
if (dp->di_ib[j] != 0) {
|
||||
if (debug)
|
||||
printf("bad indirect addr: %ld\n",
|
||||
dp->di_ib[j]);
|
||||
goto unknown;
|
||||
}
|
||||
if (ftypeok(dp) == 0)
|
||||
goto unknown;
|
||||
n_files++;
|
||||
lncntp[inumber] = dp->di_nlink;
|
||||
if (dp->di_nlink <= 0) {
|
||||
zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
|
||||
if (zlnp == NULL) {
|
||||
pfatal("LINK COUNT TABLE OVERFLOW");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
} else {
|
||||
zlnp->zlncnt = inumber;
|
||||
zlnp->next = zlnhead;
|
||||
zlnhead = zlnp;
|
||||
}
|
||||
}
|
||||
if (mode == IFDIR) {
|
||||
if (dp->di_size == 0)
|
||||
statemap[inumber] = DCLEAR;
|
||||
else
|
||||
statemap[inumber] = DSTATE;
|
||||
cacheino(dp, inumber);
|
||||
} else
|
||||
statemap[inumber] = FSTATE;
|
||||
typemap[inumber] = IFTODT(mode);
|
||||
if (doinglevel2 &&
|
||||
(dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
|
||||
dp = ginode(inumber);
|
||||
dp->di_uid = dp->di_ouid;
|
||||
dp->di_ouid = -1;
|
||||
dp->di_gid = dp->di_ogid;
|
||||
dp->di_ogid = -1;
|
||||
inodirty();
|
||||
}
|
||||
badblk = dupblk = 0;
|
||||
idesc->id_number = inumber;
|
||||
(void)ckinode(dp, idesc);
|
||||
idesc->id_entryno *= btodb(sblock.fs_fsize);
|
||||
if (dp->di_blocks != idesc->id_entryno) {
|
||||
pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
|
||||
inumber, dp->di_blocks, idesc->id_entryno);
|
||||
if (preen)
|
||||
printf(" (CORRECTED)\n");
|
||||
else if (reply("CORRECT") == 0)
|
||||
return;
|
||||
dp = ginode(inumber);
|
||||
dp->di_blocks = idesc->id_entryno;
|
||||
inodirty();
|
||||
}
|
||||
return;
|
||||
unknown:
|
||||
pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
|
||||
statemap[inumber] = FCLEAR;
|
||||
if (reply("CLEAR") == 1) {
|
||||
statemap[inumber] = USTATE;
|
||||
dp = ginode(inumber);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
|
||||
pass1check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
int res = KEEPON;
|
||||
int anyout, nfrags;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
register struct dups *dlp;
|
||||
struct dups *new;
|
||||
|
||||
if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
|
||||
blkerror(idesc->id_number, "BAD", blkno);
|
||||
if (badblk++ >= MAXBAD) {
|
||||
pwarn("EXCESSIVE BAD BLKS I=%lu",
|
||||
idesc->id_number);
|
||||
if (preen)
|
||||
printf(" (SKIPPING)\n");
|
||||
else if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
}
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (anyout && chkrange(blkno, 1)) {
|
||||
res = SKIP;
|
||||
} else if (!testbmap(blkno)) {
|
||||
n_blks++;
|
||||
setbmap(blkno);
|
||||
} else {
|
||||
blkerror(idesc->id_number, "DUP", blkno);
|
||||
if (dupblk++ >= MAXDUP) {
|
||||
pwarn("EXCESSIVE DUP BLKS I=%lu",
|
||||
idesc->id_number);
|
||||
if (preen)
|
||||
printf(" (SKIPPING)\n");
|
||||
else if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
new = (struct dups *)malloc(sizeof(struct dups));
|
||||
if (new == NULL) {
|
||||
pfatal("DUP TABLE OVERFLOW.");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
new->dup = blkno;
|
||||
if (muldup == 0) {
|
||||
duplist = muldup = new;
|
||||
new->next = 0;
|
||||
} else {
|
||||
new->next = muldup->next;
|
||||
muldup->next = new;
|
||||
}
|
||||
for (dlp = duplist; dlp != muldup; dlp = dlp->next)
|
||||
if (dlp->dup == blkno)
|
||||
break;
|
||||
if (dlp == muldup && dlp->dup != blkno)
|
||||
muldup = new;
|
||||
}
|
||||
/*
|
||||
* count the number of blocks found in id_entryno
|
||||
*/
|
||||
idesc->id_entryno++;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
99
sbin/fsck/pass1b.c
Normal file
99
sbin/fsck/pass1b.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass1b.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
int pass1bcheck();
|
||||
static struct dups *duphead;
|
||||
|
||||
pass1b()
|
||||
{
|
||||
register int c, i;
|
||||
register struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
ino_t inumber;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass1bcheck;
|
||||
duphead = duplist;
|
||||
inumber = 0;
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
|
||||
if (inumber < ROOTINO)
|
||||
continue;
|
||||
dp = ginode(inumber);
|
||||
if (dp == NULL)
|
||||
continue;
|
||||
idesc.id_number = inumber;
|
||||
if (statemap[inumber] != USTATE &&
|
||||
(ckinode(dp, &idesc) & STOP))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass1bcheck(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (chkrange(blkno, 1))
|
||||
res = SKIP;
|
||||
for (dlp = duphead; dlp; dlp = dlp->next) {
|
||||
if (dlp->dup == blkno) {
|
||||
blkerror(idesc->id_number, "DUP", blkno);
|
||||
dlp->dup = duphead->dup;
|
||||
duphead->dup = blkno;
|
||||
duphead = duphead->next;
|
||||
}
|
||||
if (dlp == muldup)
|
||||
break;
|
||||
}
|
||||
if (muldup == 0 || duphead == muldup->next)
|
||||
return (STOP);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
430
sbin/fsck/pass2.c
Normal file
430
sbin/fsck/pass2.c
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass2.c 8.2 (Berkeley) 2/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
#define MINDIRSIZE (sizeof (struct dirtemplate))
|
||||
|
||||
int pass2check(), blksort();
|
||||
|
||||
pass2()
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpend;
|
||||
struct inodesc curino;
|
||||
struct dinode dino;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
switch (statemap[ROOTINO]) {
|
||||
|
||||
case USTATE:
|
||||
pfatal("ROOT INODE UNALLOCATED");
|
||||
if (reply("ALLOCATE") == 0)
|
||||
errexit("");
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
pfatal("DUPS/BAD IN ROOT INODE");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
}
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
break;
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
pfatal("ROOT INODE NOT DIRECTORY");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
}
|
||||
if (reply("FIX") == 0)
|
||||
errexit("");
|
||||
dp = ginode(ROOTINO);
|
||||
dp->di_mode &= ~IFMT;
|
||||
dp->di_mode |= IFDIR;
|
||||
inodirty();
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
|
||||
}
|
||||
statemap[ROOTINO] = DFOUND;
|
||||
/*
|
||||
* Sort the directory list into disk block order.
|
||||
*/
|
||||
qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
|
||||
/*
|
||||
* Check the integrity of each directory.
|
||||
*/
|
||||
bzero((char *)&curino, sizeof(struct inodesc));
|
||||
curino.id_type = DATA;
|
||||
curino.id_func = pass2check;
|
||||
dp = &dino;
|
||||
inpend = &inpsort[inplast];
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_isize == 0)
|
||||
continue;
|
||||
if (inp->i_isize < MINDIRSIZE) {
|
||||
direrror(inp->i_number, "DIRECTORY TOO SHORT");
|
||||
inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
|
||||
if (reply("FIX") == 1) {
|
||||
dp = ginode(inp->i_number);
|
||||
dp->di_size = inp->i_isize;
|
||||
inodirty();
|
||||
dp = &dino;
|
||||
}
|
||||
} else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
|
||||
getpathname(pathbuf, inp->i_number, inp->i_number);
|
||||
pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
|
||||
pathbuf, inp->i_isize, DIRBLKSIZ);
|
||||
if (preen)
|
||||
printf(" (ADJUSTED)\n");
|
||||
inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
|
||||
if (preen || reply("ADJUST") == 1) {
|
||||
dp = ginode(inp->i_number);
|
||||
dp->di_size = roundup(inp->i_isize, DIRBLKSIZ);
|
||||
inodirty();
|
||||
dp = &dino;
|
||||
}
|
||||
}
|
||||
bzero((char *)&dino, sizeof(struct dinode));
|
||||
dino.di_mode = IFDIR;
|
||||
dp->di_size = inp->i_isize;
|
||||
bcopy((char *)&inp->i_blks[0], (char *)&dp->di_db[0],
|
||||
(size_t)inp->i_numblks);
|
||||
curino.id_number = inp->i_number;
|
||||
curino.id_parent = inp->i_parent;
|
||||
(void)ckinode(dp, &curino);
|
||||
}
|
||||
/*
|
||||
* Now that the parents of all directories have been found,
|
||||
* make another pass to verify the value of `..'
|
||||
*/
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0 || inp->i_isize == 0)
|
||||
continue;
|
||||
if (statemap[inp->i_parent] == DFOUND &&
|
||||
statemap[inp->i_number] == DSTATE)
|
||||
statemap[inp->i_number] = DFOUND;
|
||||
if (inp->i_dotdot == inp->i_parent ||
|
||||
inp->i_dotdot == (ino_t)-1)
|
||||
continue;
|
||||
if (inp->i_dotdot == 0) {
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
|
||||
if (reply("FIX") == 0)
|
||||
continue;
|
||||
(void)makeentry(inp->i_number, inp->i_parent, "..");
|
||||
lncntp[inp->i_parent]--;
|
||||
continue;
|
||||
}
|
||||
fileerror(inp->i_parent, inp->i_number,
|
||||
"BAD INODE NUMBER FOR '..'");
|
||||
if (reply("FIX") == 0)
|
||||
continue;
|
||||
lncntp[inp->i_dotdot]++;
|
||||
lncntp[inp->i_parent]--;
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
(void)changeino(inp->i_number, "..", inp->i_parent);
|
||||
}
|
||||
/*
|
||||
* Mark all the directories that can be found from the root.
|
||||
*/
|
||||
propagate();
|
||||
}
|
||||
|
||||
pass2check(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
register struct inoinfo *inp;
|
||||
int n, entrysize, ret = 0;
|
||||
struct dinode *dp;
|
||||
char *errmsg;
|
||||
struct direct proto;
|
||||
char namebuf[MAXPATHLEN + 1];
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
/*
|
||||
* If converting, set directory entry type.
|
||||
*/
|
||||
if (doinglevel2 && dirp->d_ino > 0 && dirp->d_ino < maxino) {
|
||||
dirp->d_type = typemap[dirp->d_ino];
|
||||
ret |= ALTERED;
|
||||
}
|
||||
/*
|
||||
* check for "."
|
||||
*/
|
||||
if (idesc->id_entryno != 0)
|
||||
goto chk1;
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
|
||||
if (dirp->d_ino != idesc->id_number) {
|
||||
direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
|
||||
dirp->d_ino = idesc->id_number;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
if (newinofmt && dirp->d_type != DT_DIR) {
|
||||
direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
|
||||
dirp->d_type = DT_DIR;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
goto chk1;
|
||||
}
|
||||
direrror(idesc->id_number, "MISSING '.'");
|
||||
proto.d_ino = idesc->id_number;
|
||||
if (newinofmt)
|
||||
proto.d_type = DT_DIR;
|
||||
else
|
||||
proto.d_type = 0;
|
||||
proto.d_namlen = 1;
|
||||
(void)strcpy(proto.d_name, ".");
|
||||
entrysize = DIRSIZ(0, &proto);
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
|
||||
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||
dirp->d_name);
|
||||
} 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, (size_t)entrysize);
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
} else {
|
||||
n = dirp->d_reclen - entrysize;
|
||||
proto.d_reclen = entrysize;
|
||||
bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
|
||||
idesc->id_entryno++;
|
||||
lncntp[dirp->d_ino]--;
|
||||
dirp = (struct direct *)((char *)(dirp) + entrysize);
|
||||
bzero((char *)dirp, (size_t)n);
|
||||
dirp->d_reclen = n;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
chk1:
|
||||
if (idesc->id_entryno > 1)
|
||||
goto chk2;
|
||||
inp = getinoinfo(idesc->id_number);
|
||||
proto.d_ino = inp->i_parent;
|
||||
if (newinofmt)
|
||||
proto.d_type = DT_DIR;
|
||||
else
|
||||
proto.d_type = 0;
|
||||
proto.d_namlen = 2;
|
||||
(void)strcpy(proto.d_name, "..");
|
||||
entrysize = DIRSIZ(0, &proto);
|
||||
if (idesc->id_entryno == 0) {
|
||||
n = DIRSIZ(0, dirp);
|
||||
if (dirp->d_reclen < n + entrysize)
|
||||
goto chk2;
|
||||
proto.d_reclen = dirp->d_reclen - n;
|
||||
dirp->d_reclen = n;
|
||||
idesc->id_entryno++;
|
||||
lncntp[dirp->d_ino]--;
|
||||
dirp = (struct direct *)((char *)(dirp) + n);
|
||||
bzero((char *)dirp, (size_t)proto.d_reclen);
|
||||
dirp->d_reclen = proto.d_reclen;
|
||||
}
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
|
||||
inp->i_dotdot = dirp->d_ino;
|
||||
if (newinofmt && dirp->d_type != DT_DIR) {
|
||||
direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
|
||||
dirp->d_type = DT_DIR;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
goto chk2;
|
||||
}
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||
dirp->d_name);
|
||||
inp->i_dotdot = (ino_t)-1;
|
||||
} else if (dirp->d_reclen < entrysize) {
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
|
||||
inp->i_dotdot = (ino_t)-1;
|
||||
} else if (inp->i_parent != 0) {
|
||||
/*
|
||||
* We know the parent, so fix now.
|
||||
*/
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
proto.d_reclen = dirp->d_reclen;
|
||||
bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
idesc->id_entryno++;
|
||||
if (dirp->d_ino != 0)
|
||||
lncntp[dirp->d_ino]--;
|
||||
return (ret|KEEPON);
|
||||
chk2:
|
||||
if (dirp->d_ino == 0)
|
||||
return (ret|KEEPON);
|
||||
if (dirp->d_namlen <= 2 &&
|
||||
dirp->d_name[0] == '.' &&
|
||||
idesc->id_entryno >= 2) {
|
||||
if (dirp->d_namlen == 1) {
|
||||
direrror(idesc->id_number, "EXTRA '.' ENTRY");
|
||||
dirp->d_ino = 0;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
return (KEEPON | ret);
|
||||
}
|
||||
if (dirp->d_name[1] == '.') {
|
||||
direrror(idesc->id_number, "EXTRA '..' ENTRY");
|
||||
dirp->d_ino = 0;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
return (KEEPON | ret);
|
||||
}
|
||||
}
|
||||
idesc->id_entryno++;
|
||||
n = 0;
|
||||
if (dirp->d_ino > maxino) {
|
||||
fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
|
||||
n = reply("REMOVE");
|
||||
} else {
|
||||
again:
|
||||
switch (statemap[dirp->d_ino]) {
|
||||
case USTATE:
|
||||
if (idesc->id_entryno <= 2)
|
||||
break;
|
||||
fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
|
||||
n = reply("REMOVE");
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
case FCLEAR:
|
||||
if (idesc->id_entryno <= 2)
|
||||
break;
|
||||
if (statemap[dirp->d_ino] == FCLEAR)
|
||||
errmsg = "DUP/BAD";
|
||||
else if (!preen)
|
||||
errmsg = "ZERO LENGTH DIRECTORY";
|
||||
else {
|
||||
n = 1;
|
||||
break;
|
||||
}
|
||||
fileerror(idesc->id_number, dirp->d_ino, errmsg);
|
||||
if ((n = reply("REMOVE")) == 1)
|
||||
break;
|
||||
dp = ginode(dirp->d_ino);
|
||||
statemap[dirp->d_ino] =
|
||||
(dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
|
||||
lncntp[dirp->d_ino] = dp->di_nlink;
|
||||
goto again;
|
||||
|
||||
case DSTATE:
|
||||
if (statemap[idesc->id_number] == DFOUND)
|
||||
statemap[dirp->d_ino] = DFOUND;
|
||||
/* fall through */
|
||||
|
||||
case DFOUND:
|
||||
inp = getinoinfo(dirp->d_ino);
|
||||
if (inp->i_parent != 0 && idesc->id_entryno > 2) {
|
||||
getpathname(pathbuf, idesc->id_number,
|
||||
idesc->id_number);
|
||||
getpathname(namebuf, dirp->d_ino, dirp->d_ino);
|
||||
pwarn("%s %s %s\n", pathbuf,
|
||||
"IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
|
||||
namebuf);
|
||||
if (preen)
|
||||
printf(" (IGNORED)\n");
|
||||
else if ((n = reply("REMOVE")) == 1)
|
||||
break;
|
||||
}
|
||||
if (idesc->id_entryno > 2)
|
||||
inp->i_parent = idesc->id_number;
|
||||
/* fall through */
|
||||
|
||||
case FSTATE:
|
||||
if (newinofmt && dirp->d_type != typemap[dirp->d_ino]) {
|
||||
fileerror(idesc->id_number, dirp->d_ino,
|
||||
"BAD TYPE VALUE");
|
||||
dirp->d_type = typemap[dirp->d_ino];
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
lncntp[dirp->d_ino]--;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[dirp->d_ino], dirp->d_ino);
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
return (ret|KEEPON);
|
||||
dirp->d_ino = 0;
|
||||
return (ret|KEEPON|ALTERED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to sort disk blocks.
|
||||
*/
|
||||
blksort(inpp1, inpp2)
|
||||
struct inoinfo **inpp1, **inpp2;
|
||||
{
|
||||
|
||||
return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]);
|
||||
}
|
||||
71
sbin/fsck/pass3.c
Normal file
71
sbin/fsck/pass3.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass3.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include "fsck.h"
|
||||
|
||||
pass3()
|
||||
{
|
||||
register struct inoinfo **inpp, *inp;
|
||||
ino_t orphan;
|
||||
int loopcnt;
|
||||
|
||||
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
|
||||
inp = *inpp;
|
||||
if (inp->i_number == ROOTINO ||
|
||||
!(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE))
|
||||
continue;
|
||||
if (statemap[inp->i_number] == DCLEAR)
|
||||
continue;
|
||||
for (loopcnt = 0; ; loopcnt++) {
|
||||
orphan = inp->i_number;
|
||||
if (inp->i_parent == 0 ||
|
||||
statemap[inp->i_parent] != DSTATE ||
|
||||
loopcnt > numdirs)
|
||||
break;
|
||||
inp = getinoinfo(inp->i_parent);
|
||||
}
|
||||
(void)linkup(orphan, inp->i_dotdot);
|
||||
inp->i_parent = inp->i_dotdot = lfdir;
|
||||
lncntp[lfdir]--;
|
||||
statemap[orphan] = DFOUND;
|
||||
propagate();
|
||||
}
|
||||
}
|
||||
133
sbin/fsck/pass4.c
Normal file
133
sbin/fsck/pass4.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass4.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
int pass4check();
|
||||
|
||||
pass4()
|
||||
{
|
||||
register ino_t inumber;
|
||||
register struct zlncnt *zlnp;
|
||||
struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
int n;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
for (inumber = ROOTINO; inumber <= lastino; inumber++) {
|
||||
idesc.id_number = inumber;
|
||||
switch (statemap[inumber]) {
|
||||
|
||||
case FSTATE:
|
||||
case DFOUND:
|
||||
n = lncntp[inumber];
|
||||
if (n)
|
||||
adjust(&idesc, (short)n);
|
||||
else {
|
||||
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
|
||||
if (zlnp->zlncnt == inumber) {
|
||||
zlnp->zlncnt = zlnhead->zlncnt;
|
||||
zlnp = zlnhead;
|
||||
zlnhead = zlnhead->next;
|
||||
free((char *)zlnp);
|
||||
clri(&idesc, "UNREF", 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
clri(&idesc, "UNREF", 1);
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
dp = ginode(inumber);
|
||||
if (dp->di_size == 0) {
|
||||
clri(&idesc, "ZERO LENGTH", 1);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case FCLEAR:
|
||||
clri(&idesc, "BAD/DUP", 1);
|
||||
break;
|
||||
|
||||
case USTATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[inumber], inumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass4check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (chkrange(blkno, 1)) {
|
||||
res = SKIP;
|
||||
} else if (testbmap(blkno)) {
|
||||
for (dlp = duplist; dlp; dlp = dlp->next) {
|
||||
if (dlp->dup != blkno)
|
||||
continue;
|
||||
dlp->dup = duplist->dup;
|
||||
dlp = duplist;
|
||||
duplist = duplist->next;
|
||||
free((char *)dlp);
|
||||
break;
|
||||
}
|
||||
if (dlp == 0) {
|
||||
clrbmap(blkno);
|
||||
n_blks--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
319
sbin/fsck/pass5.c
Normal file
319
sbin/fsck/pass5.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass5.c 8.2 (Berkeley) 2/2/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
pass5()
|
||||
{
|
||||
int c, blk, frags, basesize, sumsize, mapsize, savednrpos;
|
||||
register struct fs *fs = &sblock;
|
||||
register struct cg *cg = &cgrp;
|
||||
daddr_t dbase, dmax;
|
||||
register daddr_t d;
|
||||
register long i, j;
|
||||
struct csum *cs;
|
||||
struct csum cstotal;
|
||||
struct inodesc idesc[3];
|
||||
char buf[MAXBSIZE];
|
||||
register struct cg *newcg = (struct cg *)buf;
|
||||
struct ocg *ocg = (struct ocg *)buf;
|
||||
|
||||
bzero((char *)newcg, (size_t)fs->fs_cgsize);
|
||||
newcg->cg_niblk = fs->fs_ipg;
|
||||
if (cvtlevel > 3) {
|
||||
if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) {
|
||||
if (preen)
|
||||
pwarn("DELETING CLUSTERING MAPS\n");
|
||||
if (preen || reply("DELETE CLUSTERING MAPS")) {
|
||||
fs->fs_contigsumsize = 0;
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_maxcontig > 1) {
|
||||
char *doit = 0;
|
||||
|
||||
if (fs->fs_contigsumsize < 1) {
|
||||
doit = "CREAT";
|
||||
} else if (fs->fs_contigsumsize < fs->fs_maxcontig &&
|
||||
fs->fs_contigsumsize < FS_MAXCONTIG) {
|
||||
doit = "EXPAND";
|
||||
}
|
||||
if (doit) {
|
||||
i = fs->fs_contigsumsize;
|
||||
fs->fs_contigsumsize =
|
||||
MIN(fs->fs_maxcontig, FS_MAXCONTIG);
|
||||
if (CGSIZE(fs) > fs->fs_bsize) {
|
||||
pwarn("CANNOT %s CLUSTER MAPS\n", doit);
|
||||
fs->fs_contigsumsize = i;
|
||||
} else if (preen ||
|
||||
reply("CREATE CLUSTER MAPS")) {
|
||||
if (preen)
|
||||
pwarn("%sING CLUSTER MAPS\n",
|
||||
doit);
|
||||
fs->fs_cgsize =
|
||||
fragroundup(fs, CGSIZE(fs));
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch ((int)fs->fs_postblformat) {
|
||||
|
||||
case FS_42POSTBLFMT:
|
||||
basesize = (char *)(&ocg->cg_btot[0]) - (char *)(&ocg->cg_link);
|
||||
sumsize = &ocg->cg_iused[0] - (char *)(&ocg->cg_btot[0]);
|
||||
mapsize = &ocg->cg_free[howmany(fs->fs_fpg, NBBY)] -
|
||||
(u_char *)&ocg->cg_iused[0];
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
savednrpos = fs->fs_nrpos;
|
||||
fs->fs_nrpos = 8;
|
||||
break;
|
||||
|
||||
case FS_DYNAMICPOSTBLFMT:
|
||||
newcg->cg_btotoff =
|
||||
&newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
|
||||
newcg->cg_boff =
|
||||
newcg->cg_btotoff + fs->fs_cpg * sizeof(long);
|
||||
newcg->cg_iusedoff = newcg->cg_boff +
|
||||
fs->fs_cpg * fs->fs_nrpos * sizeof(short);
|
||||
newcg->cg_freeoff =
|
||||
newcg->cg_iusedoff + howmany(fs->fs_ipg, NBBY);
|
||||
if (fs->fs_contigsumsize <= 0) {
|
||||
newcg->cg_nextfreeoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY);
|
||||
} else {
|
||||
newcg->cg_clustersumoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY) -
|
||||
sizeof(long);
|
||||
newcg->cg_clustersumoff =
|
||||
roundup(newcg->cg_clustersumoff, sizeof(long));
|
||||
newcg->cg_clusteroff = newcg->cg_clustersumoff +
|
||||
(fs->fs_contigsumsize + 1) * sizeof(long);
|
||||
newcg->cg_nextfreeoff = newcg->cg_clusteroff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPB(fs), NBBY);
|
||||
}
|
||||
newcg->cg_magic = CG_MAGIC;
|
||||
basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
|
||||
sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
|
||||
mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("UNKNOWN ROTATIONAL TABLE FORMAT %d\n",
|
||||
fs->fs_postblformat);
|
||||
}
|
||||
bzero((char *)&idesc[0], sizeof idesc);
|
||||
for (i = 0; i < 3; i++) {
|
||||
idesc[i].id_type = ADDR;
|
||||
if (doinglevel2)
|
||||
idesc[i].id_fix = FIX;
|
||||
}
|
||||
bzero((char *)&cstotal, sizeof(struct csum));
|
||||
j = blknum(fs, fs->fs_size + fs->fs_frag - 1);
|
||||
for (i = fs->fs_size; i < j; i++)
|
||||
setbmap(i);
|
||||
for (c = 0; c < fs->fs_ncg; c++) {
|
||||
getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize);
|
||||
if (!cg_chkmagic(cg))
|
||||
pfatal("CG %d: BAD MAGIC NUMBER\n", c);
|
||||
dbase = cgbase(fs, c);
|
||||
dmax = dbase + fs->fs_fpg;
|
||||
if (dmax > fs->fs_size)
|
||||
dmax = fs->fs_size;
|
||||
newcg->cg_time = cg->cg_time;
|
||||
newcg->cg_cgx = c;
|
||||
if (c == fs->fs_ncg - 1)
|
||||
newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg;
|
||||
else
|
||||
newcg->cg_ncyl = fs->fs_cpg;
|
||||
newcg->cg_ndblk = dmax - dbase;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
|
||||
newcg->cg_cs.cs_ndir = 0;
|
||||
newcg->cg_cs.cs_nffree = 0;
|
||||
newcg->cg_cs.cs_nbfree = 0;
|
||||
newcg->cg_cs.cs_nifree = fs->fs_ipg;
|
||||
if (cg->cg_rotor < newcg->cg_ndblk)
|
||||
newcg->cg_rotor = cg->cg_rotor;
|
||||
else
|
||||
newcg->cg_rotor = 0;
|
||||
if (cg->cg_frotor < newcg->cg_ndblk)
|
||||
newcg->cg_frotor = cg->cg_frotor;
|
||||
else
|
||||
newcg->cg_frotor = 0;
|
||||
if (cg->cg_irotor < newcg->cg_niblk)
|
||||
newcg->cg_irotor = cg->cg_irotor;
|
||||
else
|
||||
newcg->cg_irotor = 0;
|
||||
bzero((char *)&newcg->cg_frsum[0], sizeof newcg->cg_frsum);
|
||||
bzero((char *)&cg_blktot(newcg)[0],
|
||||
(size_t)(sumsize + mapsize));
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
j = fs->fs_ipg * c;
|
||||
for (i = 0; i < fs->fs_ipg; j++, i++) {
|
||||
switch (statemap[j]) {
|
||||
|
||||
case USTATE:
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
case DCLEAR:
|
||||
case DFOUND:
|
||||
newcg->cg_cs.cs_ndir++;
|
||||
/* fall through */
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
setbit(cg_inosused(newcg), i);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (j < ROOTINO)
|
||||
break;
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[j], j);
|
||||
}
|
||||
}
|
||||
if (c == 0)
|
||||
for (i = 0; i < ROOTINO; i++) {
|
||||
setbit(cg_inosused(newcg), i);
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
}
|
||||
for (i = 0, d = dbase;
|
||||
d < dmax;
|
||||
d += fs->fs_frag, i += fs->fs_frag) {
|
||||
frags = 0;
|
||||
for (j = 0; j < fs->fs_frag; j++) {
|
||||
if (testbmap(d + j))
|
||||
continue;
|
||||
setbit(cg_blksfree(newcg), i + j);
|
||||
frags++;
|
||||
}
|
||||
if (frags == fs->fs_frag) {
|
||||
newcg->cg_cs.cs_nbfree++;
|
||||
j = cbtocylno(fs, i);
|
||||
cg_blktot(newcg)[j]++;
|
||||
cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
setbit(cg_clustersfree(newcg),
|
||||
i / fs->fs_frag);
|
||||
} else if (frags > 0) {
|
||||
newcg->cg_cs.cs_nffree += frags;
|
||||
blk = blkmap(fs, cg_blksfree(newcg), i);
|
||||
ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
|
||||
}
|
||||
}
|
||||
if (fs->fs_contigsumsize > 0) {
|
||||
long *sump = cg_clustersum(newcg);
|
||||
u_char *mapp = cg_clustersfree(newcg);
|
||||
int map = *mapp++;
|
||||
int bit = 1;
|
||||
int run = 0;
|
||||
|
||||
for (i = 0; i < newcg->cg_nclusterblks; i++) {
|
||||
if ((map & bit) != 0) {
|
||||
run++;
|
||||
} else if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
run = 0;
|
||||
}
|
||||
if ((i & (NBBY - 1)) != (NBBY - 1)) {
|
||||
bit <<= 1;
|
||||
} else {
|
||||
map = *mapp++;
|
||||
bit = 1;
|
||||
}
|
||||
}
|
||||
if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
}
|
||||
}
|
||||
cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
|
||||
cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
|
||||
cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
|
||||
cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
|
||||
cs = &fs->fs_cs(fs, c);
|
||||
if (bcmp((char *)&newcg->cg_cs, (char *)cs, sizeof *cs) != 0 &&
|
||||
dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
bcopy((char *)&newcg->cg_cs, (char *)cs, sizeof *cs);
|
||||
sbdirty();
|
||||
}
|
||||
if (doinglevel1) {
|
||||
bcopy((char *)newcg, (char *)cg, (size_t)fs->fs_cgsize);
|
||||
cgdirty();
|
||||
continue;
|
||||
}
|
||||
if (bcmp(cg_inosused(newcg),
|
||||
cg_inosused(cg), mapsize) != 0 &&
|
||||
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
|
||||
bcopy(cg_inosused(newcg), cg_inosused(cg),
|
||||
(size_t)mapsize);
|
||||
cgdirty();
|
||||
}
|
||||
if ((bcmp((char *)newcg, (char *)cg, basesize) != 0 ||
|
||||
bcmp((char *)&cg_blktot(newcg)[0],
|
||||
(char *)&cg_blktot(cg)[0], sumsize) != 0) &&
|
||||
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
|
||||
bcopy((char *)newcg, (char *)cg, (size_t)basesize);
|
||||
bcopy((char *)&cg_blktot(newcg)[0],
|
||||
(char *)&cg_blktot(cg)[0], (size_t)sumsize);
|
||||
cgdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
fs->fs_nrpos = savednrpos;
|
||||
if (bcmp((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs) != 0
|
||||
&& dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
bcopy((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs);
|
||||
fs->fs_ronly = 0;
|
||||
fs->fs_fmod = 0;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
354
sbin/fsck/preen.c
Normal file
354
sbin/fsck/preen.c
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)preen.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fstab.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
char *rawname(), *unrawname(), *blockcheck();
|
||||
|
||||
struct part {
|
||||
struct part *next; /* forward link of partitions on disk */
|
||||
char *name; /* device name */
|
||||
char *fsname; /* mounted filesystem name */
|
||||
long auxdata; /* auxillary data for application */
|
||||
} *badlist, **badnext = &badlist;
|
||||
|
||||
struct disk {
|
||||
char *name; /* disk base name */
|
||||
struct disk *next; /* forward link for list of disks */
|
||||
struct part *part; /* head of list of partitions on disk */
|
||||
int pid; /* If != 0, pid of proc working on */
|
||||
} *disks;
|
||||
|
||||
int nrun, ndisks;
|
||||
char hotroot;
|
||||
|
||||
checkfstab(preen, maxrun, docheck, chkit)
|
||||
int preen, maxrun;
|
||||
int (*docheck)(), (*chkit)();
|
||||
{
|
||||
register struct fstab *fsp;
|
||||
register struct disk *dk, *nextdisk;
|
||||
register struct part *pt;
|
||||
int ret, pid, retcode, passno, sumstatus, status;
|
||||
long auxdata;
|
||||
char *name;
|
||||
|
||||
sumstatus = 0;
|
||||
for (passno = 1; passno <= 2; passno++) {
|
||||
if (setfsent() == 0) {
|
||||
fprintf(stderr, "Can't open checklist file: %s\n",
|
||||
_PATH_FSTAB);
|
||||
return (8);
|
||||
}
|
||||
while ((fsp = getfsent()) != 0) {
|
||||
if ((auxdata = (*docheck)(fsp)) == 0)
|
||||
continue;
|
||||
if (preen == 0 || passno == 1 && fsp->fs_passno == 1) {
|
||||
if (name = blockcheck(fsp->fs_spec)) {
|
||||
if (sumstatus = (*chkit)(name,
|
||||
fsp->fs_file, auxdata, 0))
|
||||
return (sumstatus);
|
||||
} else if (preen)
|
||||
return (8);
|
||||
} else if (passno == 2 && fsp->fs_passno > 1) {
|
||||
if ((name = blockcheck(fsp->fs_spec)) == NULL) {
|
||||
fprintf(stderr, "BAD DISK NAME %s\n",
|
||||
fsp->fs_spec);
|
||||
sumstatus |= 8;
|
||||
continue;
|
||||
}
|
||||
addpart(name, fsp->fs_file, auxdata);
|
||||
}
|
||||
}
|
||||
if (preen == 0)
|
||||
return (0);
|
||||
}
|
||||
if (preen) {
|
||||
if (maxrun == 0)
|
||||
maxrun = ndisks;
|
||||
if (maxrun > ndisks)
|
||||
maxrun = ndisks;
|
||||
nextdisk = disks;
|
||||
for (passno = 0; passno < maxrun; ++passno) {
|
||||
while (ret = startdisk(nextdisk, chkit) && nrun > 0)
|
||||
sleep(10);
|
||||
if (ret)
|
||||
return (ret);
|
||||
nextdisk = nextdisk->next;
|
||||
}
|
||||
while ((pid = wait(&status)) != -1) {
|
||||
for (dk = disks; dk; dk = dk->next)
|
||||
if (dk->pid == pid)
|
||||
break;
|
||||
if (dk == 0) {
|
||||
printf("Unknown pid %d\n", pid);
|
||||
continue;
|
||||
}
|
||||
if (WIFEXITED(status))
|
||||
retcode = WEXITSTATUS(status);
|
||||
else
|
||||
retcode = 0;
|
||||
if (WIFSIGNALED(status)) {
|
||||
printf("%s (%s): EXITED WITH SIGNAL %d\n",
|
||||
dk->part->name, dk->part->fsname,
|
||||
WTERMSIG(status));
|
||||
retcode = 8;
|
||||
}
|
||||
if (retcode != 0) {
|
||||
sumstatus |= retcode;
|
||||
*badnext = dk->part;
|
||||
badnext = &dk->part->next;
|
||||
dk->part = dk->part->next;
|
||||
*badnext = NULL;
|
||||
} else
|
||||
dk->part = dk->part->next;
|
||||
dk->pid = 0;
|
||||
nrun--;
|
||||
if (dk->part == NULL)
|
||||
ndisks--;
|
||||
|
||||
if (nextdisk == NULL) {
|
||||
if (dk->part) {
|
||||
while (ret = startdisk(dk, chkit) &&
|
||||
nrun > 0)
|
||||
sleep(10);
|
||||
if (ret)
|
||||
return (ret);
|
||||
}
|
||||
} else if (nrun < maxrun && nrun < ndisks) {
|
||||
for ( ;; ) {
|
||||
if ((nextdisk = nextdisk->next) == NULL)
|
||||
nextdisk = disks;
|
||||
if (nextdisk->part != NULL &&
|
||||
nextdisk->pid == 0)
|
||||
break;
|
||||
}
|
||||
while (ret = startdisk(nextdisk, chkit) &&
|
||||
nrun > 0)
|
||||
sleep(10);
|
||||
if (ret)
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sumstatus) {
|
||||
if (badlist == 0)
|
||||
return (sumstatus);
|
||||
fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
|
||||
badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
|
||||
for (pt = badlist; pt; pt = pt->next)
|
||||
fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname,
|
||||
pt->next ? ", " : "\n");
|
||||
return (sumstatus);
|
||||
}
|
||||
(void)endfsent();
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct disk *
|
||||
finddisk(name)
|
||||
char *name;
|
||||
{
|
||||
register struct disk *dk, **dkp;
|
||||
register char *p;
|
||||
size_t len;
|
||||
|
||||
for (p = name + strlen(name) - 1; p >= name; --p)
|
||||
if (isdigit(*p)) {
|
||||
len = p - name + 1;
|
||||
break;
|
||||
}
|
||||
if (p < name)
|
||||
len = strlen(name);
|
||||
|
||||
for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
|
||||
if (strncmp(dk->name, name, len) == 0 &&
|
||||
dk->name[len] == 0)
|
||||
return (dk);
|
||||
}
|
||||
if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
dk = *dkp;
|
||||
if ((dk->name = malloc(len + 1)) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
(void)strncpy(dk->name, name, len);
|
||||
dk->name[len] = '\0';
|
||||
dk->part = NULL;
|
||||
dk->next = NULL;
|
||||
dk->pid = 0;
|
||||
ndisks++;
|
||||
return (dk);
|
||||
}
|
||||
|
||||
addpart(name, fsname, auxdata)
|
||||
char *name, *fsname;
|
||||
long auxdata;
|
||||
{
|
||||
struct disk *dk = finddisk(name);
|
||||
register struct part *pt, **ppt = &dk->part;
|
||||
|
||||
for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
|
||||
if (strcmp(pt->name, name) == 0) {
|
||||
printf("%s in fstab more than once!\n", name);
|
||||
return;
|
||||
}
|
||||
if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
pt = *ppt;
|
||||
if ((pt->name = malloc(strlen(name) + 1)) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
(void)strcpy(pt->name, name);
|
||||
if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
(void)strcpy(pt->fsname, fsname);
|
||||
pt->next = NULL;
|
||||
pt->auxdata = auxdata;
|
||||
}
|
||||
|
||||
startdisk(dk, checkit)
|
||||
register struct disk *dk;
|
||||
int (*checkit)();
|
||||
{
|
||||
register struct part *pt = dk->part;
|
||||
|
||||
dk->pid = fork();
|
||||
if (dk->pid < 0) {
|
||||
perror("fork");
|
||||
return (8);
|
||||
}
|
||||
if (dk->pid == 0)
|
||||
exit((*checkit)(pt->name, pt->fsname, pt->auxdata, 1));
|
||||
nrun++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
blockcheck(name)
|
||||
char *name;
|
||||
{
|
||||
struct stat stslash, stblock, stchar;
|
||||
char *raw;
|
||||
int retried = 0;
|
||||
|
||||
hotroot = 0;
|
||||
if (stat("/", &stslash) < 0) {
|
||||
perror("/");
|
||||
printf("Can't stat root\n");
|
||||
return (0);
|
||||
}
|
||||
retry:
|
||||
if (stat(name, &stblock) < 0) {
|
||||
perror(name);
|
||||
printf("Can't stat %s\n", name);
|
||||
return (0);
|
||||
}
|
||||
if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
|
||||
if (stslash.st_dev == stblock.st_rdev)
|
||||
hotroot++;
|
||||
raw = rawname(name);
|
||||
if (stat(raw, &stchar) < 0) {
|
||||
perror(raw);
|
||||
printf("Can't stat %s\n", raw);
|
||||
return (name);
|
||||
}
|
||||
if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
|
||||
return (raw);
|
||||
} else {
|
||||
printf("%s is not a character device\n", raw);
|
||||
return (name);
|
||||
}
|
||||
} else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
|
||||
name = unrawname(name);
|
||||
retried++;
|
||||
goto retry;
|
||||
}
|
||||
printf("Can't make sense out of name %s\n", name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
unrawname(name)
|
||||
char *name;
|
||||
{
|
||||
char *dp;
|
||||
struct stat stb;
|
||||
|
||||
if ((dp = rindex(name, '/')) == 0)
|
||||
return (name);
|
||||
if (stat(name, &stb) < 0)
|
||||
return (name);
|
||||
if ((stb.st_mode & S_IFMT) != S_IFCHR)
|
||||
return (name);
|
||||
if (dp[1] != 'r')
|
||||
return (name);
|
||||
(void)strcpy(&dp[1], &dp[2]);
|
||||
return (name);
|
||||
}
|
||||
|
||||
char *
|
||||
rawname(name)
|
||||
char *name;
|
||||
{
|
||||
static char rawbuf[32];
|
||||
char *dp;
|
||||
|
||||
if ((dp = rindex(name, '/')) == 0)
|
||||
return (0);
|
||||
*dp = 0;
|
||||
(void)strcpy(rawbuf, name);
|
||||
*dp = '/';
|
||||
(void)strcat(rawbuf, "/r");
|
||||
(void)strcat(rawbuf, &dp[1]);
|
||||
return (rawbuf);
|
||||
}
|
||||
466
sbin/fsck/setup.c
Normal file
466
sbin/fsck/setup.c
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)setup.c 8.2 (Berkeley) 2/21/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#define DKTYPENAMES
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/file.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "fsck.h"
|
||||
|
||||
struct bufarea asblk;
|
||||
#define altsblock (*asblk.b_un.b_fs)
|
||||
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
|
||||
|
||||
struct disklabel *getdisklabel();
|
||||
|
||||
setup(dev)
|
||||
char *dev;
|
||||
{
|
||||
long cg, size, asked, i, j;
|
||||
long bmapsize;
|
||||
struct disklabel *lp;
|
||||
off_t sizepb;
|
||||
struct stat statb;
|
||||
struct fs proto;
|
||||
|
||||
havesb = 0;
|
||||
fswritefd = -1;
|
||||
if (stat(dev, &statb) < 0) {
|
||||
printf("Can't stat %s: %s\n", dev, strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
if ((statb.st_mode & S_IFMT) != S_IFCHR) {
|
||||
pfatal("%s is not a character device", dev);
|
||||
if (reply("CONTINUE") == 0)
|
||||
return (0);
|
||||
}
|
||||
if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
|
||||
printf("Can't open %s: %s\n", dev, strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("** %s", dev);
|
||||
if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
|
||||
fswritefd = -1;
|
||||
if (preen)
|
||||
pfatal("NO WRITE ACCESS");
|
||||
printf(" (NO WRITE)");
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
fsmodified = 0;
|
||||
lfdir = 0;
|
||||
initbarea(&sblk);
|
||||
initbarea(&asblk);
|
||||
sblk.b_un.b_buf = malloc(SBSIZE);
|
||||
asblk.b_un.b_buf = malloc(SBSIZE);
|
||||
if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
|
||||
errexit("cannot allocate space for superblock\n");
|
||||
if (lp = getdisklabel((char *)NULL, fsreadfd))
|
||||
dev_bsize = secsize = lp->d_secsize;
|
||||
else
|
||||
dev_bsize = secsize = DEV_BSIZE;
|
||||
/*
|
||||
* Read in the superblock, looking for alternates if necessary
|
||||
*/
|
||||
if (readsb(1) == 0) {
|
||||
if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
|
||||
return(0);
|
||||
if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
|
||||
return (0);
|
||||
for (cg = 0; cg < proto.fs_ncg; cg++) {
|
||||
bflag = fsbtodb(&proto, cgsblock(&proto, cg));
|
||||
if (readsb(0) != 0)
|
||||
break;
|
||||
}
|
||||
if (cg >= proto.fs_ncg) {
|
||||
printf("%s %s\n%s %s\n%s %s\n",
|
||||
"SEARCH FOR ALTERNATE SUPER-BLOCK",
|
||||
"FAILED. YOU MUST USE THE",
|
||||
"-b OPTION TO FSCK TO SPECIFY THE",
|
||||
"LOCATION OF AN ALTERNATE",
|
||||
"SUPER-BLOCK TO SUPPLY NEEDED",
|
||||
"INFORMATION; SEE fsck(8).");
|
||||
return(0);
|
||||
}
|
||||
pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
|
||||
}
|
||||
maxfsblock = sblock.fs_size;
|
||||
maxino = sblock.fs_ncg * sblock.fs_ipg;
|
||||
/*
|
||||
* Check and potentially fix certain fields in the super block.
|
||||
*/
|
||||
if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
|
||||
pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
|
||||
if (reply("SET TO DEFAULT") == 1) {
|
||||
sblock.fs_optim = FS_OPTTIME;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
|
||||
pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
|
||||
sblock.fs_minfree);
|
||||
if (reply("SET TO DEFAULT") == 1) {
|
||||
sblock.fs_minfree = 10;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
if (sblock.fs_interleave < 1 ||
|
||||
sblock.fs_interleave > sblock.fs_nsect) {
|
||||
pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
|
||||
sblock.fs_interleave);
|
||||
sblock.fs_interleave = 1;
|
||||
if (preen)
|
||||
printf(" (FIXED)\n");
|
||||
if (preen || reply("SET TO DEFAULT") == 1) {
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
}
|
||||
if (sblock.fs_npsect < sblock.fs_nsect ||
|
||||
sblock.fs_npsect > sblock.fs_nsect*2) {
|
||||
pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
|
||||
sblock.fs_npsect);
|
||||
sblock.fs_npsect = sblock.fs_nsect;
|
||||
if (preen)
|
||||
printf(" (FIXED)\n");
|
||||
if (preen || reply("SET TO DEFAULT") == 1) {
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
}
|
||||
if (sblock.fs_inodefmt >= FS_44INODEFMT) {
|
||||
newinofmt = 1;
|
||||
} else {
|
||||
sblock.fs_qbmask = ~sblock.fs_bmask;
|
||||
sblock.fs_qfmask = ~sblock.fs_fmask;
|
||||
newinofmt = 0;
|
||||
}
|
||||
/*
|
||||
* Convert to new inode format.
|
||||
*/
|
||||
if (cvtlevel >= 2 && sblock.fs_inodefmt < FS_44INODEFMT) {
|
||||
if (preen)
|
||||
pwarn("CONVERTING TO NEW INODE FORMAT\n");
|
||||
else if (!reply("CONVERT TO NEW INODE FORMAT"))
|
||||
return(0);
|
||||
doinglevel2++;
|
||||
sblock.fs_inodefmt = FS_44INODEFMT;
|
||||
sizepb = sblock.fs_bsize;
|
||||
sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
|
||||
for (i = 0; i < NIADDR; i++) {
|
||||
sizepb *= NINDIR(&sblock);
|
||||
sblock.fs_maxfilesize += sizepb;
|
||||
}
|
||||
sblock.fs_maxsymlinklen = MAXSYMLINKLEN;
|
||||
sblock.fs_qbmask = ~sblock.fs_bmask;
|
||||
sblock.fs_qfmask = ~sblock.fs_fmask;
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
/*
|
||||
* Convert to new cylinder group format.
|
||||
*/
|
||||
if (cvtlevel >= 1 && sblock.fs_postblformat == FS_42POSTBLFMT) {
|
||||
if (preen)
|
||||
pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
|
||||
else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
|
||||
return(0);
|
||||
doinglevel1++;
|
||||
sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
|
||||
sblock.fs_nrpos = 8;
|
||||
sblock.fs_postbloff =
|
||||
(char *)(&sblock.fs_opostbl[0][0]) -
|
||||
(char *)(&sblock.fs_link);
|
||||
sblock.fs_rotbloff = &sblock.fs_space[0] -
|
||||
(u_char *)(&sblock.fs_link);
|
||||
sblock.fs_cgsize =
|
||||
fragroundup(&sblock, CGSIZE(&sblock));
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
if (asblk.b_dirty) {
|
||||
bcopy((char *)&sblock, (char *)&altsblock,
|
||||
(size_t)sblock.fs_sbsize);
|
||||
flush(fswritefd, &asblk);
|
||||
}
|
||||
/*
|
||||
* read in the summary info.
|
||||
*/
|
||||
asked = 0;
|
||||
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(fsreadfd, (char *)sblock.fs_csp[j],
|
||||
fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
|
||||
size) != 0 && !asked) {
|
||||
pfatal("BAD SUMMARY INFORMATION");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
asked++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* allocate and initialize the necessary maps
|
||||
*/
|
||||
bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short));
|
||||
blockmap = calloc((unsigned)bmapsize, sizeof (char));
|
||||
if (blockmap == NULL) {
|
||||
printf("cannot alloc %u bytes for blockmap\n",
|
||||
(unsigned)bmapsize);
|
||||
goto badsb;
|
||||
}
|
||||
statemap = calloc((unsigned)(maxino + 1), sizeof(char));
|
||||
if (statemap == NULL) {
|
||||
printf("cannot alloc %u bytes for statemap\n",
|
||||
(unsigned)(maxino + 1));
|
||||
goto badsb;
|
||||
}
|
||||
typemap = calloc((unsigned)(maxino + 1), sizeof(char));
|
||||
if (typemap == NULL) {
|
||||
printf("cannot alloc %u bytes for typemap\n",
|
||||
(unsigned)(maxino + 1));
|
||||
goto badsb;
|
||||
}
|
||||
lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short));
|
||||
if (lncntp == NULL) {
|
||||
printf("cannot alloc %u bytes for lncntp\n",
|
||||
(unsigned)(maxino + 1) * sizeof(short));
|
||||
goto badsb;
|
||||
}
|
||||
numdirs = sblock.fs_cstotal.cs_ndir;
|
||||
inplast = 0;
|
||||
listmax = numdirs + 10;
|
||||
inpsort = (struct inoinfo **)calloc((unsigned)listmax,
|
||||
sizeof(struct inoinfo *));
|
||||
inphead = (struct inoinfo **)calloc((unsigned)numdirs,
|
||||
sizeof(struct inoinfo *));
|
||||
if (inpsort == NULL || inphead == NULL) {
|
||||
printf("cannot alloc %u bytes for inphead\n",
|
||||
(unsigned)numdirs * sizeof(struct inoinfo *));
|
||||
goto badsb;
|
||||
}
|
||||
bufinit();
|
||||
return (1);
|
||||
|
||||
badsb:
|
||||
ckfini();
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in the super block and its summary info.
|
||||
*/
|
||||
readsb(listerr)
|
||||
int listerr;
|
||||
{
|
||||
daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
|
||||
|
||||
if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
|
||||
return (0);
|
||||
sblk.b_bno = super;
|
||||
sblk.b_size = SBSIZE;
|
||||
/*
|
||||
* run a few consistency checks of the super block
|
||||
*/
|
||||
if (sblock.fs_magic != FS_MAGIC)
|
||||
{ badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
|
||||
if (sblock.fs_ncg < 1)
|
||||
{ badsb(listerr, "NCG OUT OF RANGE"); return (0); }
|
||||
if (sblock.fs_cpg < 1)
|
||||
{ badsb(listerr, "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(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
|
||||
if (sblock.fs_sbsize > SBSIZE)
|
||||
{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
|
||||
/*
|
||||
* Compute block size that the filesystem is based on,
|
||||
* according to fsbtodb, and adjust superblock block number
|
||||
* so we can tell if this is an alternate later.
|
||||
*/
|
||||
super *= dev_bsize;
|
||||
dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
|
||||
sblk.b_bno = super / dev_bsize;
|
||||
if (bflag) {
|
||||
havesb = 1;
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
|
||||
if (asblk.b_errs)
|
||||
return (0);
|
||||
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_optim = sblock.fs_optim;
|
||||
altsblock.fs_rotdelay = sblock.fs_rotdelay;
|
||||
altsblock.fs_maxbpg = sblock.fs_maxbpg;
|
||||
bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
|
||||
sizeof sblock.fs_csp);
|
||||
bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
|
||||
sizeof sblock.fs_fsmnt);
|
||||
bcopy((char *)sblock.fs_sparecon, (char *)altsblock.fs_sparecon,
|
||||
sizeof sblock.fs_sparecon);
|
||||
/*
|
||||
* The following should not have to be copied.
|
||||
*/
|
||||
altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
|
||||
altsblock.fs_interleave = sblock.fs_interleave;
|
||||
altsblock.fs_npsect = sblock.fs_npsect;
|
||||
altsblock.fs_nrpos = sblock.fs_nrpos;
|
||||
altsblock.fs_qbmask = sblock.fs_qbmask;
|
||||
altsblock.fs_qfmask = sblock.fs_qfmask;
|
||||
altsblock.fs_state = sblock.fs_state;
|
||||
altsblock.fs_maxfilesize = sblock.fs_maxfilesize;
|
||||
if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) {
|
||||
badsb(listerr,
|
||||
"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
|
||||
return (0);
|
||||
}
|
||||
havesb = 1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
badsb(listerr, s)
|
||||
int listerr;
|
||||
char *s;
|
||||
{
|
||||
|
||||
if (!listerr)
|
||||
return;
|
||||
if (preen)
|
||||
printf("%s: ", cdevname);
|
||||
pfatal("BAD SUPER BLOCK: %s\n", s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate a prototype superblock based on information in the disk label.
|
||||
* When done the cgsblock macro can be calculated and the fs_ncg field
|
||||
* can be used. Do NOT attempt to use other macros without verifying that
|
||||
* their needed information is available!
|
||||
*/
|
||||
calcsb(dev, devfd, fs)
|
||||
char *dev;
|
||||
int devfd;
|
||||
register struct fs *fs;
|
||||
{
|
||||
register struct disklabel *lp;
|
||||
register struct partition *pp;
|
||||
register char *cp;
|
||||
int i;
|
||||
|
||||
cp = index(dev, '\0') - 1;
|
||||
if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) {
|
||||
pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
|
||||
return (0);
|
||||
}
|
||||
lp = getdisklabel(dev, devfd);
|
||||
if (isdigit(*cp))
|
||||
pp = &lp->d_partitions[0];
|
||||
else
|
||||
pp = &lp->d_partitions[*cp - 'a'];
|
||||
if (pp->p_fstype != FS_BSDFFS) {
|
||||
pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
|
||||
dev, pp->p_fstype < FSMAXTYPES ?
|
||||
fstypenames[pp->p_fstype] : "unknown");
|
||||
return (0);
|
||||
}
|
||||
bzero((char *)fs, sizeof(struct fs));
|
||||
fs->fs_fsize = pp->p_fsize;
|
||||
fs->fs_frag = pp->p_frag;
|
||||
fs->fs_cpg = pp->p_cpg;
|
||||
fs->fs_size = pp->p_size;
|
||||
fs->fs_ntrak = lp->d_ntracks;
|
||||
fs->fs_nsect = lp->d_nsectors;
|
||||
fs->fs_spc = lp->d_secpercyl;
|
||||
fs->fs_nspf = fs->fs_fsize / lp->d_secsize;
|
||||
fs->fs_sblkno = roundup(
|
||||
howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
|
||||
fs->fs_frag);
|
||||
fs->fs_cgmask = 0xffffffff;
|
||||
for (i = fs->fs_ntrak; i > 1; i >>= 1)
|
||||
fs->fs_cgmask <<= 1;
|
||||
if (!POWEROF2(fs->fs_ntrak))
|
||||
fs->fs_cgmask <<= 1;
|
||||
fs->fs_cgoffset = roundup(
|
||||
howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
|
||||
fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
|
||||
fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
|
||||
for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
|
||||
fs->fs_fsbtodb++;
|
||||
dev_bsize = lp->d_secsize;
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct disklabel *
|
||||
getdisklabel(s, fd)
|
||||
char *s;
|
||||
int fd;
|
||||
{
|
||||
static struct disklabel lab;
|
||||
|
||||
if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
|
||||
if (s == NULL)
|
||||
return ((struct disklabel *)NULL);
|
||||
pwarn("ioctl (GCINFO): %s\n", strerror(errno));
|
||||
errexit("%s: can't read disk label\n", s);
|
||||
}
|
||||
return (&lab);
|
||||
}
|
||||
566
sbin/fsck/utilities.c
Normal file
566
sbin/fsck/utilities.c
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)utilities.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "fsck.h"
|
||||
|
||||
long diskreads, totalreads; /* Disk cache statistics */
|
||||
|
||||
ftypeok(dp)
|
||||
struct dinode *dp;
|
||||
{
|
||||
switch (dp->di_mode & IFMT) {
|
||||
|
||||
case IFDIR:
|
||||
case IFREG:
|
||||
case IFBLK:
|
||||
case IFCHR:
|
||||
case IFLNK:
|
||||
case IFSOCK:
|
||||
case IFIFO:
|
||||
return (1);
|
||||
|
||||
default:
|
||||
if (debug)
|
||||
printf("bad file type 0%o\n", dp->di_mode);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
reply(question)
|
||||
char *question;
|
||||
{
|
||||
int persevere;
|
||||
char c;
|
||||
|
||||
if (preen)
|
||||
pfatal("INTERNAL ERROR: GOT TO reply()");
|
||||
persevere = !strcmp(question, "CONTINUE");
|
||||
printf("\n");
|
||||
if (!persevere && (nflag || fswritefd < 0)) {
|
||||
printf("%s? no\n\n", question);
|
||||
return (0);
|
||||
}
|
||||
if (yflag || (persevere && nflag)) {
|
||||
printf("%s? yes\n\n", question);
|
||||
return (1);
|
||||
}
|
||||
do {
|
||||
printf("%s? [yn] ", question);
|
||||
(void) fflush(stdout);
|
||||
c = getc(stdin);
|
||||
while (c != '\n' && getc(stdin) != '\n')
|
||||
if (feof(stdin))
|
||||
return (0);
|
||||
} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
|
||||
printf("\n");
|
||||
if (c == 'y' || c == 'Y')
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Malloc buffers and set up cache.
|
||||
*/
|
||||
bufinit()
|
||||
{
|
||||
register struct bufarea *bp;
|
||||
long bufcnt, i;
|
||||
char *bufp;
|
||||
|
||||
pbp = pdirbp = (struct bufarea *)0;
|
||||
bufp = malloc((unsigned int)sblock.fs_bsize);
|
||||
if (bufp == 0)
|
||||
errexit("cannot allocate buffer pool\n");
|
||||
cgblk.b_un.b_buf = bufp;
|
||||
initbarea(&cgblk);
|
||||
bufhead.b_next = bufhead.b_prev = &bufhead;
|
||||
bufcnt = MAXBUFSPACE / sblock.fs_bsize;
|
||||
if (bufcnt < MINBUFS)
|
||||
bufcnt = MINBUFS;
|
||||
for (i = 0; i < bufcnt; i++) {
|
||||
bp = (struct bufarea *)malloc(sizeof(struct bufarea));
|
||||
bufp = malloc((unsigned int)sblock.fs_bsize);
|
||||
if (bp == NULL || bufp == NULL) {
|
||||
if (i >= MINBUFS)
|
||||
break;
|
||||
errexit("cannot allocate buffer pool\n");
|
||||
}
|
||||
bp->b_un.b_buf = bufp;
|
||||
bp->b_prev = &bufhead;
|
||||
bp->b_next = bufhead.b_next;
|
||||
bufhead.b_next->b_prev = bp;
|
||||
bufhead.b_next = bp;
|
||||
initbarea(bp);
|
||||
}
|
||||
bufhead.b_size = i; /* save number of buffers */
|
||||
}
|
||||
|
||||
/*
|
||||
* Manage a cache of directory blocks.
|
||||
*/
|
||||
struct bufarea *
|
||||
getdatablk(blkno, size)
|
||||
daddr_t blkno;
|
||||
long size;
|
||||
{
|
||||
register struct bufarea *bp;
|
||||
|
||||
for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
|
||||
if (bp->b_bno == fsbtodb(&sblock, blkno))
|
||||
goto foundit;
|
||||
for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
|
||||
if ((bp->b_flags & B_INUSE) == 0)
|
||||
break;
|
||||
if (bp == &bufhead)
|
||||
errexit("deadlocked buffer pool\n");
|
||||
getblk(bp, blkno, size);
|
||||
/* fall through */
|
||||
foundit:
|
||||
totalreads++;
|
||||
bp->b_prev->b_next = bp->b_next;
|
||||
bp->b_next->b_prev = bp->b_prev;
|
||||
bp->b_prev = &bufhead;
|
||||
bp->b_next = bufhead.b_next;
|
||||
bufhead.b_next->b_prev = bp;
|
||||
bufhead.b_next = bp;
|
||||
bp->b_flags |= B_INUSE;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
void
|
||||
getblk(bp, blk, size)
|
||||
register struct bufarea *bp;
|
||||
daddr_t blk;
|
||||
long size;
|
||||
{
|
||||
daddr_t dblk;
|
||||
|
||||
dblk = fsbtodb(&sblock, blk);
|
||||
if (bp->b_bno != dblk) {
|
||||
flush(fswritefd, bp);
|
||||
diskreads++;
|
||||
bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
|
||||
bp->b_bno = dblk;
|
||||
bp->b_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
flush(fd, bp)
|
||||
int fd;
|
||||
register struct bufarea *bp;
|
||||
{
|
||||
register int i, j;
|
||||
|
||||
if (!bp->b_dirty)
|
||||
return;
|
||||
if (bp->b_errs != 0)
|
||||
pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
|
||||
(bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
|
||||
bp->b_bno);
|
||||
bp->b_dirty = 0;
|
||||
bp->b_errs = 0;
|
||||
bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
|
||||
if (bp != &sblk)
|
||||
return;
|
||||
for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
|
||||
bwrite(fswritefd, (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);
|
||||
}
|
||||
}
|
||||
|
||||
rwerror(mesg, blk)
|
||||
char *mesg;
|
||||
daddr_t blk;
|
||||
{
|
||||
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
pfatal("CANNOT %s: BLK %ld", mesg, blk);
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("Program terminated\n");
|
||||
}
|
||||
|
||||
ckfini()
|
||||
{
|
||||
register struct bufarea *bp, *nbp;
|
||||
int cnt = 0;
|
||||
|
||||
if (fswritefd < 0) {
|
||||
(void)close(fsreadfd);
|
||||
return;
|
||||
}
|
||||
flush(fswritefd, &sblk);
|
||||
if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
|
||||
!preen && reply("UPDATE STANDARD SUPERBLOCK")) {
|
||||
sblk.b_bno = SBOFF / dev_bsize;
|
||||
sbdirty();
|
||||
flush(fswritefd, &sblk);
|
||||
}
|
||||
flush(fswritefd, &cgblk);
|
||||
free(cgblk.b_un.b_buf);
|
||||
for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
|
||||
cnt++;
|
||||
flush(fswritefd, bp);
|
||||
nbp = bp->b_prev;
|
||||
free(bp->b_un.b_buf);
|
||||
free((char *)bp);
|
||||
}
|
||||
if (bufhead.b_size != cnt)
|
||||
errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
|
||||
pbp = pdirbp = (struct bufarea *)0;
|
||||
if (debug)
|
||||
printf("cache missed %ld of %ld (%d%%)\n", diskreads,
|
||||
totalreads, (int)(diskreads * 100 / totalreads));
|
||||
(void)close(fsreadfd);
|
||||
(void)close(fswritefd);
|
||||
}
|
||||
|
||||
bread(fd, buf, blk, size)
|
||||
int fd;
|
||||
char *buf;
|
||||
daddr_t blk;
|
||||
long size;
|
||||
{
|
||||
char *cp;
|
||||
int i, errs;
|
||||
off_t offset;
|
||||
|
||||
offset = blk;
|
||||
offset *= dev_bsize;
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
else if (read(fd, buf, (int)size) == size)
|
||||
return (0);
|
||||
rwerror("READ", blk);
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
errs = 0;
|
||||
bzero(buf, (size_t)size);
|
||||
printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
|
||||
for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
|
||||
if (read(fd, cp, (int)secsize) != secsize) {
|
||||
(void)lseek(fd, offset + i + secsize, 0);
|
||||
if (secsize != dev_bsize && dev_bsize != 1)
|
||||
printf(" %ld (%ld),",
|
||||
(blk * dev_bsize + i) / secsize,
|
||||
blk + i / dev_bsize);
|
||||
else
|
||||
printf(" %ld,", blk + i / dev_bsize);
|
||||
errs++;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
return (errs);
|
||||
}
|
||||
|
||||
bwrite(fd, buf, blk, size)
|
||||
int fd;
|
||||
char *buf;
|
||||
daddr_t blk;
|
||||
long size;
|
||||
{
|
||||
int i;
|
||||
char *cp;
|
||||
off_t offset;
|
||||
|
||||
if (fd < 0)
|
||||
return;
|
||||
offset = blk;
|
||||
offset *= dev_bsize;
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
else if (write(fd, buf, (int)size) == size) {
|
||||
fsmodified = 1;
|
||||
return;
|
||||
}
|
||||
rwerror("WRITE", blk);
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
|
||||
for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
|
||||
if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
|
||||
(void)lseek(fd, offset + i + dev_bsize, 0);
|
||||
printf(" %ld,", blk + i / dev_bsize);
|
||||
}
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a data block with the specified number of fragments
|
||||
*/
|
||||
allocblk(frags)
|
||||
long frags;
|
||||
{
|
||||
register int i, j, k;
|
||||
|
||||
if (frags <= 0 || frags > sblock.fs_frag)
|
||||
return (0);
|
||||
for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
|
||||
for (j = 0; j <= sblock.fs_frag - frags; j++) {
|
||||
if (testbmap(i + j))
|
||||
continue;
|
||||
for (k = 1; k < frags; k++)
|
||||
if (testbmap(i + j + k))
|
||||
break;
|
||||
if (k < frags) {
|
||||
j += k;
|
||||
continue;
|
||||
}
|
||||
for (k = 0; k < frags; k++)
|
||||
setbmap(i + j + k);
|
||||
n_blks += frags;
|
||||
return (i + j);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a previously allocated block
|
||||
*/
|
||||
freeblk(blkno, frags)
|
||||
daddr_t blkno;
|
||||
long frags;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
|
||||
idesc.id_blkno = blkno;
|
||||
idesc.id_numfrags = frags;
|
||||
(void)pass4check(&idesc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a pathname
|
||||
*/
|
||||
getpathname(namebuf, curdir, ino)
|
||||
char *namebuf;
|
||||
ino_t curdir, ino;
|
||||
{
|
||||
int len;
|
||||
register char *cp;
|
||||
struct inodesc idesc;
|
||||
static int busy = 0;
|
||||
extern int findname();
|
||||
|
||||
if (curdir == ino && ino == ROOTINO) {
|
||||
(void)strcpy(namebuf, "/");
|
||||
return;
|
||||
}
|
||||
if (busy ||
|
||||
(statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
|
||||
(void)strcpy(namebuf, "?");
|
||||
return;
|
||||
}
|
||||
busy = 1;
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_fix = IGNORE;
|
||||
cp = &namebuf[MAXPATHLEN - 1];
|
||||
*cp = '\0';
|
||||
if (curdir != ino) {
|
||||
idesc.id_parent = curdir;
|
||||
goto namelookup;
|
||||
}
|
||||
while (ino != ROOTINO) {
|
||||
idesc.id_number = ino;
|
||||
idesc.id_func = findino;
|
||||
idesc.id_name = "..";
|
||||
if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
|
||||
break;
|
||||
namelookup:
|
||||
idesc.id_number = idesc.id_parent;
|
||||
idesc.id_parent = ino;
|
||||
idesc.id_func = findname;
|
||||
idesc.id_name = namebuf;
|
||||
if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
|
||||
break;
|
||||
len = strlen(namebuf);
|
||||
cp -= len;
|
||||
bcopy(namebuf, cp, (size_t)len);
|
||||
*--cp = '/';
|
||||
if (cp < &namebuf[MAXNAMLEN])
|
||||
break;
|
||||
ino = idesc.id_number;
|
||||
}
|
||||
busy = 0;
|
||||
if (ino != ROOTINO)
|
||||
*--cp = '?';
|
||||
bcopy(cp, namebuf, (size_t)(&namebuf[MAXPATHLEN] - cp));
|
||||
}
|
||||
|
||||
void
|
||||
catch()
|
||||
{
|
||||
if (!doinglevel2)
|
||||
ckfini();
|
||||
exit(12);
|
||||
}
|
||||
|
||||
/*
|
||||
* When preening, allow a single quit to signal
|
||||
* a special exit after filesystem checks complete
|
||||
* so that reboot sequence may be interrupted.
|
||||
*/
|
||||
void
|
||||
catchquit()
|
||||
{
|
||||
extern returntosingle;
|
||||
|
||||
printf("returning to single-user after filesystem check\n");
|
||||
returntosingle = 1;
|
||||
(void)signal(SIGQUIT, SIG_DFL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore a single quit signal; wait and flush just in case.
|
||||
* Used by child processes in preen.
|
||||
*/
|
||||
void
|
||||
voidquit()
|
||||
{
|
||||
|
||||
sleep(1);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_DFL);
|
||||
}
|
||||
|
||||
/*
|
||||
* determine whether an inode should be fixed.
|
||||
*/
|
||||
dofix(idesc, msg)
|
||||
register struct inodesc *idesc;
|
||||
char *msg;
|
||||
{
|
||||
|
||||
switch (idesc->id_fix) {
|
||||
|
||||
case DONTKNOW:
|
||||
if (idesc->id_type == DATA)
|
||||
direrror(idesc->id_number, msg);
|
||||
else
|
||||
pwarn(msg);
|
||||
if (preen) {
|
||||
printf(" (SALVAGED)\n");
|
||||
idesc->id_fix = FIX;
|
||||
return (ALTERED);
|
||||
}
|
||||
if (reply("SALVAGE") == 0) {
|
||||
idesc->id_fix = NOFIX;
|
||||
return (0);
|
||||
}
|
||||
idesc->id_fix = FIX;
|
||||
return (ALTERED);
|
||||
|
||||
case FIX:
|
||||
return (ALTERED);
|
||||
|
||||
case NOFIX:
|
||||
case IGNORE:
|
||||
return (0);
|
||||
|
||||
default:
|
||||
errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* VARARGS1 */
|
||||
errexit(s1, s2, s3, s4)
|
||||
char *s1;
|
||||
{
|
||||
printf(s1, s2, s3, s4);
|
||||
exit(8);
|
||||
}
|
||||
|
||||
/*
|
||||
* An unexpected inconsistency occured.
|
||||
* Die if preening, otherwise just print message and continue.
|
||||
*/
|
||||
/* VARARGS1 */
|
||||
pfatal(s, a1, a2, a3)
|
||||
char *s;
|
||||
{
|
||||
|
||||
if (preen) {
|
||||
printf("%s: ", cdevname);
|
||||
printf(s, a1, a2, a3);
|
||||
printf("\n");
|
||||
printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
|
||||
cdevname);
|
||||
exit(8);
|
||||
}
|
||||
printf(s, a1, a2, a3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pwarn just prints a message when not preening,
|
||||
* or a warning (preceded by filename) when preening.
|
||||
*/
|
||||
/* VARARGS1 */
|
||||
pwarn(s, a1, a2, a3, a4, a5, a6)
|
||||
char *s;
|
||||
{
|
||||
|
||||
if (preen)
|
||||
printf("%s: ", cdevname);
|
||||
printf(s, a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
|
||||
#ifndef lint
|
||||
/*
|
||||
* Stub for routines from kernel.
|
||||
*/
|
||||
panic(s)
|
||||
char *s;
|
||||
{
|
||||
|
||||
pfatal("INTERNAL INCONSISTENCY:");
|
||||
errexit(s);
|
||||
}
|
||||
#endif
|
||||
9
sbin/fsck_ffs/Makefile
Normal file
9
sbin/fsck_ffs/Makefile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= fsck
|
||||
MAN8= fsck.0
|
||||
SRCS= dir.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
|
||||
pass5.c preen.c setup.c utilities.c ffs_subr.c ffs_tables.c
|
||||
.PATH: ${.CURDIR}/../../sys/ufs/ffs
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
150
sbin/fsck_ffs/SMM.doc/0.t
Normal file
150
sbin/fsck_ffs/SMM.doc/0.t
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
.\" Copyright (c) 1986, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)0.t 8.1 (Berkeley) 6/8/93
|
||||
.\"
|
||||
.if n .ND
|
||||
.TL
|
||||
Fsck \- The UNIX\(dg File System Check Program
|
||||
.EH 'SMM:3-%''The \s-2UNIX\s+2 File System Check Program'
|
||||
.OH 'The \s-2UNIX\s+2 File System Check Program''SMM:3-%'
|
||||
.AU
|
||||
Marshall Kirk McKusick
|
||||
.AI
|
||||
Computer Systems Research Group
|
||||
Computer Science Division
|
||||
Department of Electrical Engineering and Computer Science
|
||||
University of California, Berkeley
|
||||
Berkeley, CA 94720
|
||||
.AU
|
||||
T. J. Kowalski
|
||||
.AI
|
||||
Bell Laboratories
|
||||
Murray Hill, New Jersey 07974
|
||||
.AB
|
||||
.FS
|
||||
\(dgUNIX is a trademark of Bell Laboratories.
|
||||
.FE
|
||||
.FS
|
||||
This work was done under grants from
|
||||
the National Science Foundation under grant MCS80-05144,
|
||||
and the Defense Advance Research Projects Agency (DoD) under
|
||||
Arpa Order No. 4031 monitored by Naval Electronic System Command under
|
||||
Contract No. N00039-82-C-0235.
|
||||
.FE
|
||||
This document reflects the use of
|
||||
.I fsck
|
||||
with the 4.2BSD and 4.3BSD file system organization. This
|
||||
is a revision of the
|
||||
original paper written by
|
||||
T. J. Kowalski.
|
||||
.PP
|
||||
File System Check Program (\fIfsck\fR)
|
||||
is an interactive file system check and repair program.
|
||||
.I Fsck
|
||||
uses the redundant structural information in the
|
||||
UNIX file system to perform several consistency checks.
|
||||
If an inconsistency is detected, it is reported
|
||||
to the operator, who may elect to fix or ignore
|
||||
each inconsistency.
|
||||
These inconsistencies result from the permanent interruption
|
||||
of the file system updates, which are performed every
|
||||
time a file is modified.
|
||||
Unless there has been a hardware failure,
|
||||
.I fsck
|
||||
is able to repair corrupted file systems
|
||||
using procedures based upon the order in which UNIX honors
|
||||
these file system update requests.
|
||||
.PP
|
||||
The purpose of this document is to describe the normal updating
|
||||
of the file system,
|
||||
to discuss the possible causes of file system corruption,
|
||||
and to present the corrective actions implemented
|
||||
by
|
||||
.I fsck.
|
||||
Both the program and the interaction between the
|
||||
program and the operator are described.
|
||||
.sp 2
|
||||
.LP
|
||||
Revised July 16, 1985
|
||||
.AE
|
||||
.LP
|
||||
.bp
|
||||
.ce
|
||||
.B "TABLE OF CONTENTS"
|
||||
.LP
|
||||
.sp 1
|
||||
.nf
|
||||
.B "1. Introduction"
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B "2. Overview of the file system
|
||||
2.1. Superblock
|
||||
2.2. Summary Information
|
||||
2.3. Cylinder groups
|
||||
2.4. Fragments
|
||||
2.5. Updates to the file system
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B "3. Fixing corrupted file systems
|
||||
3.1. Detecting and correcting corruption
|
||||
3.2. Super block checking
|
||||
3.3. Free block checking
|
||||
3.4. Checking the inode state
|
||||
3.5. Inode links
|
||||
3.6. Inode data size
|
||||
3.7. Checking the data associated with an inode
|
||||
3.8. File system connectivity
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B Acknowledgements
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B References
|
||||
.LP
|
||||
.sp .5v
|
||||
.nf
|
||||
.B "4. Appendix A
|
||||
4.1. Conventions
|
||||
4.2. Initialization
|
||||
4.3. Phase 1 - Check Blocks and Sizes
|
||||
4.4. Phase 1b - Rescan for more Dups
|
||||
4.5. Phase 2 - Check Pathnames
|
||||
4.6. Phase 3 - Check Connectivity
|
||||
4.7. Phase 4 - Check Reference Counts
|
||||
4.8. Phase 5 - Check Cyl groups
|
||||
4.9. Cleanup
|
||||
.ds RH Introduction
|
||||
.bp
|
||||
83
sbin/fsck_ffs/SMM.doc/1.t
Normal file
83
sbin/fsck_ffs/SMM.doc/1.t
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
.\" Copyright (c) 1982, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)1.t 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.ds RH Introduction
|
||||
.NH
|
||||
Introduction
|
||||
.PP
|
||||
This document reflects the use of
|
||||
.I fsck
|
||||
with the 4.2BSD and 4.3BSD file system organization. This
|
||||
is a revision of the
|
||||
original paper written by
|
||||
T. J. Kowalski.
|
||||
.PP
|
||||
When a UNIX
|
||||
operating system is brought up, a consistency
|
||||
check of the file systems should always be performed.
|
||||
This precautionary measure helps to insure
|
||||
a reliable environment for file storage on disk.
|
||||
If an inconsistency is discovered,
|
||||
corrective action must be taken.
|
||||
.I Fsck
|
||||
runs in two modes.
|
||||
Normally it is run non-interactively by the system after
|
||||
a normal boot.
|
||||
When running in this mode,
|
||||
it will only make changes to the file system that are known
|
||||
to always be correct.
|
||||
If an unexpected inconsistency is found
|
||||
.I fsck
|
||||
will exit with a non-zero exit status,
|
||||
leaving the system running single-user.
|
||||
Typically the operator then runs
|
||||
.I fsck
|
||||
interactively.
|
||||
When running in this mode,
|
||||
each problem is listed followed by a suggested corrective action.
|
||||
The operator must decide whether or not the suggested correction
|
||||
should be made.
|
||||
.PP
|
||||
The purpose of this memo is to dispel the
|
||||
mystique surrounding
|
||||
file system inconsistencies.
|
||||
It first describes the updating of the file system
|
||||
(the calm before the storm) and
|
||||
then describes file system corruption (the storm).
|
||||
Finally,
|
||||
the set of deterministic corrective actions
|
||||
used by
|
||||
.I fsck
|
||||
(the Coast Guard
|
||||
to the rescue) is presented.
|
||||
.ds RH Overview of the File System
|
||||
265
sbin/fsck_ffs/SMM.doc/2.t
Normal file
265
sbin/fsck_ffs/SMM.doc/2.t
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
.\" Copyright (c) 1982, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)2.t 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.ds RH Overview of the file system
|
||||
.NH
|
||||
Overview of the file system
|
||||
.PP
|
||||
The file system is discussed in detail in [Mckusick84];
|
||||
this section gives a brief overview.
|
||||
.NH 2
|
||||
Superblock
|
||||
.PP
|
||||
A file system is described by its
|
||||
.I "super-block" .
|
||||
The super-block is built when the file system is created (\c
|
||||
.I newfs (8))
|
||||
and never changes.
|
||||
The super-block
|
||||
contains the basic parameters of the file system,
|
||||
such as the number of data blocks it contains
|
||||
and a count of the maximum number of files.
|
||||
Because the super-block contains critical data,
|
||||
.I newfs
|
||||
replicates it to protect against catastrophic loss.
|
||||
The
|
||||
.I "default super block"
|
||||
always resides at a fixed offset from the beginning
|
||||
of the file system's disk partition.
|
||||
The
|
||||
.I "redundant super blocks"
|
||||
are not referenced unless a head crash
|
||||
or other hard disk error causes the default super-block
|
||||
to be unusable.
|
||||
The redundant blocks are sprinkled throughout the disk partition.
|
||||
.PP
|
||||
Within the file system are files.
|
||||
Certain files are distinguished as directories and contain collections
|
||||
of pointers to files that may themselves be directories.
|
||||
Every file has a descriptor associated with it called an
|
||||
.I "inode".
|
||||
The inode contains information describing ownership of the file,
|
||||
time stamps indicating modification and access times for the file,
|
||||
and an array of indices pointing to the data blocks for the file.
|
||||
In this section,
|
||||
we assume that the first 12 blocks
|
||||
of the file are directly referenced by values stored
|
||||
in the inode structure itself\(dg.
|
||||
.FS
|
||||
\(dgThe actual number may vary from system to system, but is usually in
|
||||
the range 5-13.
|
||||
.FE
|
||||
The inode structure may also contain references to indirect blocks
|
||||
containing further data block indices.
|
||||
In a file system with a 4096 byte block size, a singly indirect
|
||||
block contains 1024 further block addresses,
|
||||
a doubly indirect block contains 1024 addresses of further single indirect
|
||||
blocks,
|
||||
and a triply indirect block contains 1024 addresses of further doubly indirect
|
||||
blocks (the triple indirect block is never needed in practice).
|
||||
.PP
|
||||
In order to create files with up to
|
||||
2\(ua32 bytes,
|
||||
using only two levels of indirection,
|
||||
the minimum size of a file system block is 4096 bytes.
|
||||
The size of file system blocks can be any power of two
|
||||
greater than or equal to 4096.
|
||||
The block size of the file system is maintained in the super-block,
|
||||
so it is possible for file systems of different block sizes
|
||||
to be accessible simultaneously on the same system.
|
||||
The block size must be decided when
|
||||
.I newfs
|
||||
creates the file system;
|
||||
the block size cannot be subsequently
|
||||
changed without rebuilding the file system.
|
||||
.NH 2
|
||||
Summary information
|
||||
.PP
|
||||
Associated with the super block is non replicated
|
||||
.I "summary information" .
|
||||
The summary information changes
|
||||
as the file system is modified.
|
||||
The summary information contains
|
||||
the number of blocks, fragments, inodes and directories in the file system.
|
||||
.NH 2
|
||||
Cylinder groups
|
||||
.PP
|
||||
The file system partitions the disk into one or more areas called
|
||||
.I "cylinder groups".
|
||||
A cylinder group is comprised of one or more consecutive
|
||||
cylinders on a disk.
|
||||
Each cylinder group includes inode slots for files, a
|
||||
.I "block map"
|
||||
describing available blocks in the cylinder group,
|
||||
and summary information describing the usage of data blocks
|
||||
within the cylinder group.
|
||||
A fixed number of inodes is allocated for each cylinder group
|
||||
when the file system is created.
|
||||
The current policy is to allocate one inode for each 2048
|
||||
bytes of disk space;
|
||||
this is expected to be far more inodes than will ever be needed.
|
||||
.PP
|
||||
All the cylinder group bookkeeping information could be
|
||||
placed at the beginning of each cylinder group.
|
||||
However if this approach were used,
|
||||
all the redundant information would be on the top platter.
|
||||
A single hardware failure that destroyed the top platter
|
||||
could cause the loss of all copies of the redundant super-blocks.
|
||||
Thus the cylinder group bookkeeping information
|
||||
begins at a floating offset from the beginning of the cylinder group.
|
||||
The offset for
|
||||
the
|
||||
.I "i+1" st
|
||||
cylinder group is about one track further
|
||||
from the beginning of the cylinder group
|
||||
than it was for the
|
||||
.I "i" th
|
||||
cylinder group.
|
||||
In this way,
|
||||
the redundant
|
||||
information spirals down into the pack;
|
||||
any single track, cylinder,
|
||||
or platter can be lost without losing all copies of the super-blocks.
|
||||
Except for the first cylinder group,
|
||||
the space between the beginning of the cylinder group
|
||||
and the beginning of the cylinder group information stores data.
|
||||
.NH 2
|
||||
Fragments
|
||||
.PP
|
||||
To avoid waste in storing small files,
|
||||
the file system space allocator divides a single
|
||||
file system block into one or more
|
||||
.I "fragments".
|
||||
The fragmentation of the file system is specified
|
||||
when the file system is created;
|
||||
each file system block can be optionally broken into
|
||||
2, 4, or 8 addressable fragments.
|
||||
The lower bound on the size of these fragments is constrained
|
||||
by the disk sector size;
|
||||
typically 512 bytes is the lower bound on fragment size.
|
||||
The block map associated with each cylinder group
|
||||
records the space availability at the fragment level.
|
||||
Aligned fragments are examined
|
||||
to determine block availability.
|
||||
.PP
|
||||
On a file system with a block size of 4096 bytes
|
||||
and a fragment size of 1024 bytes,
|
||||
a file is represented by zero or more 4096 byte blocks of data,
|
||||
and possibly a single fragmented block.
|
||||
If a file system block must be fragmented to obtain
|
||||
space for a small amount of data,
|
||||
the remainder of the block is made available for allocation
|
||||
to other files.
|
||||
For example,
|
||||
consider an 11000 byte file stored on
|
||||
a 4096/1024 byte file system.
|
||||
This file uses two full size blocks and a 3072 byte fragment.
|
||||
If no fragments with at least 3072 bytes
|
||||
are available when the file is created,
|
||||
a full size block is split yielding the necessary 3072 byte
|
||||
fragment and an unused 1024 byte fragment.
|
||||
This remaining fragment can be allocated to another file, as needed.
|
||||
.NH 2
|
||||
Updates to the file system
|
||||
.PP
|
||||
Every working day hundreds of files
|
||||
are created, modified, and removed.
|
||||
Every time a file is modified,
|
||||
the operating system performs a
|
||||
series of file system updates.
|
||||
These updates, when written on disk, yield a consistent file system.
|
||||
The file system stages
|
||||
all modifications of critical information;
|
||||
modification can
|
||||
either be completed or cleanly backed out after a crash.
|
||||
Knowing the information that is first written to the file system,
|
||||
deterministic procedures can be developed to
|
||||
repair a corrupted file system.
|
||||
To understand this process,
|
||||
the order that the update
|
||||
requests were being honored must first be understood.
|
||||
.PP
|
||||
When a user program does an operation to change the file system,
|
||||
such as a
|
||||
.I write ,
|
||||
the data to be written is copied into an internal
|
||||
.I "in-core"
|
||||
buffer in the kernel.
|
||||
Normally, the disk update is handled asynchronously;
|
||||
the user process is allowed to proceed even though
|
||||
the data has not yet been written to the disk.
|
||||
The data,
|
||||
along with the inode information reflecting the change,
|
||||
is eventually written out to disk.
|
||||
The real disk write may not happen until long after the
|
||||
.I write
|
||||
system call has returned.
|
||||
Thus at any given time, the file system,
|
||||
as it resides on the disk,
|
||||
lags the state of the file system represented by the in-core information.
|
||||
.PP
|
||||
The disk information is updated to reflect the in-core information
|
||||
when the buffer is required for another use,
|
||||
when a
|
||||
.I sync (2)
|
||||
is done (at 30 second intervals) by
|
||||
.I "/etc/update" "(8),"
|
||||
or by manual operator intervention with the
|
||||
.I sync (8)
|
||||
command.
|
||||
If the system is halted without writing out the in-core information,
|
||||
the file system on the disk will be in an inconsistent state.
|
||||
.PP
|
||||
If all updates are done asynchronously, several serious
|
||||
inconsistencies can arise.
|
||||
One inconsistency is that a block may be claimed by two inodes.
|
||||
Such an inconsistency can occur when the system is halted before
|
||||
the pointer to the block in the old inode has been cleared
|
||||
in the copy of the old inode on the disk,
|
||||
and after the pointer to the block in the new inode has been written out
|
||||
to the copy of the new inode on the disk.
|
||||
Here,
|
||||
there is no deterministic method for deciding
|
||||
which inode should really claim the block.
|
||||
A similar problem can arise with a multiply claimed inode.
|
||||
.PP
|
||||
The problem with asynchronous inode updates
|
||||
can be avoided by doing all inode deallocations synchronously.
|
||||
Consequently,
|
||||
inodes and indirect blocks are written to the disk synchronously
|
||||
(\fIi.e.\fP the process blocks until the information is
|
||||
really written to disk)
|
||||
when they are being deallocated.
|
||||
Similarly inodes are kept consistent by synchronously
|
||||
deleting, adding, or changing directory entries.
|
||||
.ds RH Fixing corrupted file systems
|
||||
439
sbin/fsck_ffs/SMM.doc/3.t
Normal file
439
sbin/fsck_ffs/SMM.doc/3.t
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
.\" Copyright (c) 1982, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)3.t 8.1 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.ds RH Fixing corrupted file systems
|
||||
.NH
|
||||
Fixing corrupted file systems
|
||||
.PP
|
||||
A file system
|
||||
can become corrupted in several ways.
|
||||
The most common of these ways are
|
||||
improper shutdown procedures
|
||||
and hardware failures.
|
||||
.PP
|
||||
File systems may become corrupted during an
|
||||
.I "unclean halt" .
|
||||
This happens when proper shutdown
|
||||
procedures are not observed,
|
||||
physically write-protecting a mounted file system,
|
||||
or a mounted file system is taken off-line.
|
||||
The most common operator procedural failure is forgetting to
|
||||
.I sync
|
||||
the system before halting the CPU.
|
||||
.PP
|
||||
File systems may become further corrupted if proper startup
|
||||
procedures are not observed, e.g.,
|
||||
not checking a file system for inconsistencies,
|
||||
and not repairing inconsistencies.
|
||||
Allowing a corrupted file system to be used (and, thus, to be modified
|
||||
further) can be disastrous.
|
||||
.PP
|
||||
Any piece of hardware can fail at any time.
|
||||
Failures
|
||||
can be as subtle as a bad block
|
||||
on a disk pack, or as blatant as a non-functional disk-controller.
|
||||
.NH 2
|
||||
Detecting and correcting corruption
|
||||
.PP
|
||||
Normally
|
||||
.I fsck
|
||||
is run non-interactively.
|
||||
In this mode it will only fix
|
||||
corruptions that are expected to occur from an unclean halt.
|
||||
These actions are a proper subset of the actions that
|
||||
.I fsck
|
||||
will take when it is running interactively.
|
||||
Throughout this paper we assume that
|
||||
.I fsck
|
||||
is being run interactively,
|
||||
and all possible errors can be encountered.
|
||||
When an inconsistency is discovered in this mode,
|
||||
.I fsck
|
||||
reports the inconsistency for the operator to
|
||||
chose a corrective action.
|
||||
.PP
|
||||
A quiescent\(dd
|
||||
.FS
|
||||
\(dd I.e., unmounted and not being written on.
|
||||
.FE
|
||||
file system may be checked for structural integrity
|
||||
by performing consistency checks on the
|
||||
redundant data intrinsic to a file system.
|
||||
The redundant data is either read from
|
||||
the file system,
|
||||
or computed from other known values.
|
||||
The file system
|
||||
.B must
|
||||
be in a quiescent state when
|
||||
.I fsck
|
||||
is run,
|
||||
since
|
||||
.I fsck
|
||||
is a multi-pass program.
|
||||
.PP
|
||||
In the following sections,
|
||||
we discuss methods to discover inconsistencies
|
||||
and possible corrective actions
|
||||
for the cylinder group blocks, the inodes, the indirect blocks, and
|
||||
the data blocks containing directory entries.
|
||||
.NH 2
|
||||
Super-block checking
|
||||
.PP
|
||||
The most commonly corrupted item in a file system
|
||||
is the summary information
|
||||
associated with the super-block.
|
||||
The summary information is prone to corruption
|
||||
because it is modified with every change to the file
|
||||
system's blocks or inodes,
|
||||
and is usually corrupted
|
||||
after an unclean halt.
|
||||
.PP
|
||||
The super-block is checked for inconsistencies
|
||||
involving file-system size, number of inodes,
|
||||
free-block count, and the free-inode count.
|
||||
The file-system size must be larger than the
|
||||
number of blocks used by the super-block
|
||||
and the number of blocks used by the list of inodes.
|
||||
The file-system size and layout information
|
||||
are the most critical pieces of information for
|
||||
.I fsck .
|
||||
While there is no way to actually check these sizes,
|
||||
since they are statically determined by
|
||||
.I newfs ,
|
||||
.I fsck
|
||||
can check that these sizes are within reasonable bounds.
|
||||
All other file system checks require that these sizes be correct.
|
||||
If
|
||||
.I fsck
|
||||
detects corruption in the static parameters of the default super-block,
|
||||
.I fsck
|
||||
requests the operator to specify the location of an alternate super-block.
|
||||
.NH 2
|
||||
Free block checking
|
||||
.PP
|
||||
.I Fsck
|
||||
checks that all the blocks
|
||||
marked as free in the cylinder group block maps
|
||||
are not claimed by any files.
|
||||
When all the blocks have been initially accounted for,
|
||||
.I fsck
|
||||
checks that
|
||||
the number of free blocks
|
||||
plus the number of blocks claimed by the inodes
|
||||
equals the total number of blocks in the file system.
|
||||
.PP
|
||||
If anything is wrong with the block allocation maps,
|
||||
.I fsck
|
||||
will rebuild them,
|
||||
based on the list it has computed of allocated blocks.
|
||||
.PP
|
||||
The summary information associated with the super-block
|
||||
counts the total number of free blocks within the file system.
|
||||
.I Fsck
|
||||
compares this count to the
|
||||
number of free blocks it found within the file system.
|
||||
If the two counts do not agree, then
|
||||
.I fsck
|
||||
replaces the incorrect count in the summary information
|
||||
by the actual free-block count.
|
||||
.PP
|
||||
The summary information
|
||||
counts the total number of free inodes within the file system.
|
||||
.I Fsck
|
||||
compares this count to the number
|
||||
of free inodes it found within the file system.
|
||||
If the two counts do not agree, then
|
||||
.I fsck
|
||||
replaces the incorrect count in the
|
||||
summary information by the actual free-inode count.
|
||||
.NH 2
|
||||
Checking the inode state
|
||||
.PP
|
||||
An individual inode is not as likely to be corrupted as
|
||||
the allocation information.
|
||||
However, because of the great number of active inodes,
|
||||
a few of the inodes are usually corrupted.
|
||||
.PP
|
||||
The list of inodes in the file system
|
||||
is checked sequentially starting with inode 2
|
||||
(inode 0 marks unused inodes;
|
||||
inode 1 is saved for future generations)
|
||||
and progressing through the last inode in the file system.
|
||||
The state of each inode is checked for
|
||||
inconsistencies involving format and type,
|
||||
link count,
|
||||
duplicate blocks,
|
||||
bad blocks,
|
||||
and inode size.
|
||||
.PP
|
||||
Each inode contains a mode word.
|
||||
This mode word describes the type and state of the inode.
|
||||
Inodes must be one of six types:
|
||||
regular inode, directory inode, symbolic link inode,
|
||||
special block inode, special character inode, or socket inode.
|
||||
Inodes may be found in one of three allocation states:
|
||||
unallocated, allocated, and neither unallocated nor allocated.
|
||||
This last state suggests an incorrectly formated inode.
|
||||
An inode can get in this state if
|
||||
bad data is written into the inode list.
|
||||
The only possible corrective action is for
|
||||
.I fsck
|
||||
is to clear the inode.
|
||||
.NH 2
|
||||
Inode links
|
||||
.PP
|
||||
Each inode counts the
|
||||
total number of directory entries
|
||||
linked to the inode.
|
||||
.I Fsck
|
||||
verifies the link count of each inode
|
||||
by starting at the root of the file system,
|
||||
and descending through the directory structure.
|
||||
The actual link count for each inode
|
||||
is calculated during the descent.
|
||||
.PP
|
||||
If the stored link count is non-zero and the actual
|
||||
link count is zero,
|
||||
then no directory entry appears for the inode.
|
||||
If this happens,
|
||||
.I fsck
|
||||
will place the disconnected file in the
|
||||
.I lost+found
|
||||
directory.
|
||||
If the stored and actual link counts are non-zero and unequal,
|
||||
a directory entry may have been added or removed without the inode being
|
||||
updated.
|
||||
If this happens,
|
||||
.I fsck
|
||||
replaces the incorrect stored link count by the actual link count.
|
||||
.PP
|
||||
Each inode contains a list,
|
||||
or pointers to
|
||||
lists (indirect blocks),
|
||||
of all the blocks claimed by the inode.
|
||||
Since indirect blocks are owned by an inode,
|
||||
inconsistencies in indirect blocks directly
|
||||
affect the inode that owns it.
|
||||
.PP
|
||||
.I Fsck
|
||||
compares each block number claimed by an inode
|
||||
against a list of already allocated blocks.
|
||||
If another inode already claims a block number,
|
||||
then the block number is added to a list of
|
||||
.I "duplicate blocks" .
|
||||
Otherwise, the list of allocated blocks
|
||||
is updated to include the block number.
|
||||
.PP
|
||||
If there are any duplicate blocks,
|
||||
.I fsck
|
||||
will perform a partial second
|
||||
pass over the inode list
|
||||
to find the inode of the duplicated block.
|
||||
The second pass is needed,
|
||||
since without examining the files associated with
|
||||
these inodes for correct content,
|
||||
not enough information is available
|
||||
to determine which inode is corrupted and should be cleared.
|
||||
If this condition does arise
|
||||
(only hardware failure will cause it),
|
||||
then the inode with the earliest
|
||||
modify time is usually incorrect,
|
||||
and should be cleared.
|
||||
If this happens,
|
||||
.I fsck
|
||||
prompts the operator to clear both inodes.
|
||||
The operator must decide which one should be kept
|
||||
and which one should be cleared.
|
||||
.PP
|
||||
.I Fsck
|
||||
checks the range of each block number claimed by an inode.
|
||||
If the block number is
|
||||
lower than the first data block in the file system,
|
||||
or greater than the last data block,
|
||||
then the block number is a
|
||||
.I "bad block number" .
|
||||
Many bad blocks in an inode are usually caused by
|
||||
an indirect block that was not written to the file system,
|
||||
a condition which can only occur if there has been a hardware failure.
|
||||
If an inode contains bad block numbers,
|
||||
.I fsck
|
||||
prompts the operator to clear it.
|
||||
.NH 2
|
||||
Inode data size
|
||||
.PP
|
||||
Each inode contains a count of the number of data blocks
|
||||
that it contains.
|
||||
The number of actual data blocks
|
||||
is the sum of the allocated data blocks
|
||||
and the indirect blocks.
|
||||
.I Fsck
|
||||
computes the actual number of data blocks
|
||||
and compares that block count against
|
||||
the actual number of blocks the inode claims.
|
||||
If an inode contains an incorrect count
|
||||
.I fsck
|
||||
prompts the operator to fix it.
|
||||
.PP
|
||||
Each inode contains a thirty-two bit size field.
|
||||
The size is the number of data bytes
|
||||
in the file associated with the inode.
|
||||
The consistency of the byte size field is roughly checked
|
||||
by computing from the size field the maximum number of blocks
|
||||
that should be associated with the inode,
|
||||
and comparing that expected block count against
|
||||
the actual number of blocks the inode claims.
|
||||
.NH 2
|
||||
Checking the data associated with an inode
|
||||
.PP
|
||||
An inode can directly or indirectly
|
||||
reference three kinds of data blocks.
|
||||
All referenced blocks must be the same kind.
|
||||
The three types of data blocks are:
|
||||
plain data blocks, symbolic link data blocks, and directory data blocks.
|
||||
Plain data blocks
|
||||
contain the information stored in a file;
|
||||
symbolic link data blocks
|
||||
contain the path name stored in a link.
|
||||
Directory data blocks contain directory entries.
|
||||
.I Fsck
|
||||
can only check the validity of directory data blocks.
|
||||
.PP
|
||||
Each directory data block is checked for
|
||||
several types of inconsistencies.
|
||||
These inconsistencies include
|
||||
directory inode numbers pointing to unallocated inodes,
|
||||
directory inode numbers that are greater than
|
||||
the number of inodes in the file system,
|
||||
incorrect directory inode numbers for ``\fB.\fP'' and ``\fB..\fP'',
|
||||
and directories that are not attached to the file system.
|
||||
If the inode number in a directory data block
|
||||
references an unallocated inode,
|
||||
then
|
||||
.I fsck
|
||||
will remove that directory entry.
|
||||
Again,
|
||||
this condition can only arise when there has been a hardware failure.
|
||||
.PP
|
||||
If a directory entry inode number references
|
||||
outside the inode list, then
|
||||
.I fsck
|
||||
will remove that directory entry.
|
||||
This condition occurs if bad data is written into a directory data block.
|
||||
.PP
|
||||
The directory inode number entry for ``\fB.\fP''
|
||||
must be the first entry in the directory data block.
|
||||
The inode number for ``\fB.\fP''
|
||||
must reference itself;
|
||||
e.g., it must equal the inode number
|
||||
for the directory data block.
|
||||
The directory inode number entry
|
||||
for ``\fB..\fP'' must be
|
||||
the second entry in the directory data block.
|
||||
Its value must equal the inode number for the
|
||||
parent of the directory entry
|
||||
(or the inode number of the directory
|
||||
data block if the directory is the
|
||||
root directory).
|
||||
If the directory inode numbers are
|
||||
incorrect,
|
||||
.I fsck
|
||||
will replace them with the correct values.
|
||||
If there are multiple hard links to a directory,
|
||||
the first one encountered is considered the real parent
|
||||
to which ``\fB..\fP'' should point;
|
||||
\fIfsck\fP recommends deletion for the subsequently discovered names.
|
||||
.NH 2
|
||||
File system connectivity
|
||||
.PP
|
||||
.I Fsck
|
||||
checks the general connectivity of the file system.
|
||||
If directories are not linked into the file system, then
|
||||
.I fsck
|
||||
links the directory back into the file system in the
|
||||
.I lost+found
|
||||
directory.
|
||||
This condition only occurs when there has been a hardware failure.
|
||||
.ds RH "References"
|
||||
.SH
|
||||
\s+2Acknowledgements\s0
|
||||
.PP
|
||||
I thank Bill Joy, Sam Leffler, Robert Elz and Dennis Ritchie
|
||||
for their suggestions and help in implementing the new file system.
|
||||
Thanks also to Robert Henry for his editorial input to
|
||||
get this document together.
|
||||
Finally we thank our sponsors,
|
||||
the National Science Foundation under grant MCS80-05144,
|
||||
and the Defense Advance Research Projects Agency (DoD) under
|
||||
Arpa Order No. 4031 monitored by Naval Electronic System Command under
|
||||
Contract No. N00039-82-C-0235. (Kirk McKusick, July 1983)
|
||||
.PP
|
||||
I would like to thank Larry A. Wehr for advice that lead
|
||||
to the first version of
|
||||
.I fsck
|
||||
and Rick B. Brandt for adapting
|
||||
.I fsck
|
||||
to
|
||||
UNIX/TS. (T. Kowalski, July 1979)
|
||||
.sp 2
|
||||
.SH
|
||||
\s+2References\s0
|
||||
.LP
|
||||
.IP [Dolotta78] 20
|
||||
Dolotta, T. A., and Olsson, S. B. eds.,
|
||||
.I "UNIX User's Manual, Edition 1.1\^" ,
|
||||
January 1978.
|
||||
.IP [Joy83] 20
|
||||
Joy, W., Cooper, E., Fabry, R., Leffler, S., McKusick, M., and Mosher, D.
|
||||
4.2BSD System Manual,
|
||||
.I "University of California at Berkeley" ,
|
||||
.I "Computer Systems Research Group Technical Report"
|
||||
#4, 1982.
|
||||
.IP [McKusick84] 20
|
||||
McKusick, M., Joy, W., Leffler, S., and Fabry, R.
|
||||
A Fast File System for UNIX,
|
||||
\fIACM Transactions on Computer Systems 2\fP, 3.
|
||||
pp. 181-197, August 1984.
|
||||
.IP [Ritchie78] 20
|
||||
Ritchie, D. M., and Thompson, K.,
|
||||
The UNIX Time-Sharing System,
|
||||
.I "The Bell System Technical Journal"
|
||||
.B 57 ,
|
||||
6 (July-August 1978, Part 2), pp. 1905-29.
|
||||
.IP [Thompson78] 20
|
||||
Thompson, K.,
|
||||
UNIX Implementation,
|
||||
.I "The Bell System Technical Journal\^"
|
||||
.B 57 ,
|
||||
6 (July-August 1978, Part 2), pp. 1931-46.
|
||||
.ds RH Appendix A \- Fsck Error Conditions
|
||||
.bp
|
||||
1424
sbin/fsck_ffs/SMM.doc/4.t
Normal file
1424
sbin/fsck_ffs/SMM.doc/4.t
Normal file
File diff suppressed because it is too large
Load diff
7
sbin/fsck_ffs/SMM.doc/Makefile
Normal file
7
sbin/fsck_ffs/SMM.doc/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/8/93
|
||||
|
||||
DIR= smm/03.fsck
|
||||
SRCS= 0.t 1.t 2.t 3.t 4.t
|
||||
MACROS= -ms
|
||||
|
||||
.include <bsd.doc.mk>
|
||||
681
sbin/fsck_ffs/dir.c
Normal file
681
sbin/fsck_ffs/dir.c
Normal file
|
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
char *lfname = "lost+found";
|
||||
int lfmode = 01777;
|
||||
struct dirtemplate emptydir = { 0, DIRBLKSIZ };
|
||||
struct dirtemplate dirhead = {
|
||||
0, 12, DT_DIR, 1, ".",
|
||||
0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
|
||||
};
|
||||
struct odirtemplate odirhead = {
|
||||
0, 12, 1, ".",
|
||||
0, DIRBLKSIZ - 12, 2, ".."
|
||||
};
|
||||
|
||||
struct direct *fsck_readdir();
|
||||
struct bufarea *getdirblk();
|
||||
|
||||
/*
|
||||
* Propagate connected state through the tree.
|
||||
*/
|
||||
propagate()
|
||||
{
|
||||
register struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpend;
|
||||
long change;
|
||||
|
||||
inpend = &inpsort[inplast];
|
||||
do {
|
||||
change = 0;
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0)
|
||||
continue;
|
||||
if (statemap[inp->i_parent] == DFOUND &&
|
||||
statemap[inp->i_number] == DSTATE) {
|
||||
statemap[inp->i_number] = DFOUND;
|
||||
change++;
|
||||
}
|
||||
}
|
||||
} while (change > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan each entry in a directory block.
|
||||
*/
|
||||
dirscan(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dp;
|
||||
register struct bufarea *bp;
|
||||
int dsize, n;
|
||||
long blksiz;
|
||||
char dbuf[DIRBLKSIZ];
|
||||
|
||||
if (idesc->id_type != DATA)
|
||||
errexit("wrong type to dirscan %d\n", idesc->id_type);
|
||||
if (idesc->id_entryno == 0 &&
|
||||
(idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
|
||||
idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
|
||||
blksiz = idesc->id_numfrags * sblock.fs_fsize;
|
||||
if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
|
||||
idesc->id_filesize -= blksiz;
|
||||
return (SKIP);
|
||||
}
|
||||
idesc->id_loc = 0;
|
||||
for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
|
||||
dsize = dp->d_reclen;
|
||||
bcopy((char *)dp, dbuf, (size_t)dsize);
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt) {
|
||||
struct direct *tdp = (struct direct *)dbuf;
|
||||
u_char tmp;
|
||||
|
||||
tmp = tdp->d_namlen;
|
||||
tdp->d_namlen = tdp->d_type;
|
||||
tdp->d_type = tmp;
|
||||
}
|
||||
# endif
|
||||
idesc->id_dirp = (struct direct *)dbuf;
|
||||
if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt && !doinglevel2) {
|
||||
struct direct *tdp;
|
||||
u_char tmp;
|
||||
|
||||
tdp = (struct direct *)dbuf;
|
||||
tmp = tdp->d_namlen;
|
||||
tdp->d_namlen = tdp->d_type;
|
||||
tdp->d_type = tmp;
|
||||
}
|
||||
# endif
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize,
|
||||
(size_t)dsize);
|
||||
dirty(bp);
|
||||
sbdirty();
|
||||
}
|
||||
if (n & STOP)
|
||||
return (n);
|
||||
}
|
||||
return (idesc->id_filesize > 0 ? KEEPON : STOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* get next entry in a directory.
|
||||
*/
|
||||
struct direct *
|
||||
fsck_readdir(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dp, *ndp;
|
||||
register struct bufarea *bp;
|
||||
long size, blksiz, fix, dploc;
|
||||
|
||||
blksiz = idesc->id_numfrags * sblock.fs_fsize;
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
|
||||
idesc->id_loc < blksiz) {
|
||||
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
if (dircheck(idesc, dp))
|
||||
goto dpok;
|
||||
fix = dofix(idesc, "DIRECTORY CORRUPTED");
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
dp->d_reclen = DIRBLKSIZ;
|
||||
dp->d_ino = 0;
|
||||
dp->d_type = 0;
|
||||
dp->d_namlen = 0;
|
||||
dp->d_name[0] = '\0';
|
||||
if (fix)
|
||||
dirty(bp);
|
||||
idesc->id_loc += DIRBLKSIZ;
|
||||
idesc->id_filesize -= DIRBLKSIZ;
|
||||
return (dp);
|
||||
}
|
||||
dpok:
|
||||
if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
|
||||
return NULL;
|
||||
dploc = idesc->id_loc;
|
||||
dp = (struct direct *)(bp->b_un.b_buf + dploc);
|
||||
idesc->id_loc += dp->d_reclen;
|
||||
idesc->id_filesize -= dp->d_reclen;
|
||||
if ((idesc->id_loc % DIRBLKSIZ) == 0)
|
||||
return (dp);
|
||||
ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
|
||||
dircheck(idesc, ndp) == 0) {
|
||||
size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
|
||||
idesc->id_loc += size;
|
||||
idesc->id_filesize -= size;
|
||||
fix = dofix(idesc, "DIRECTORY CORRUPTED");
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
dp = (struct direct *)(bp->b_un.b_buf + dploc);
|
||||
dp->d_reclen += size;
|
||||
if (fix)
|
||||
dirty(bp);
|
||||
}
|
||||
return (dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a directory entry is valid.
|
||||
* This is a superset of the checks made in the kernel.
|
||||
*/
|
||||
dircheck(idesc, dp)
|
||||
struct inodesc *idesc;
|
||||
register struct direct *dp;
|
||||
{
|
||||
register int size;
|
||||
register char *cp;
|
||||
u_char namlen, type;
|
||||
int spaceleft;
|
||||
|
||||
size = DIRSIZ(!newinofmt, dp);
|
||||
spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt) {
|
||||
type = dp->d_namlen;
|
||||
namlen = dp->d_type;
|
||||
} else {
|
||||
namlen = dp->d_namlen;
|
||||
type = dp->d_type;
|
||||
}
|
||||
# else
|
||||
namlen = dp->d_namlen;
|
||||
type = dp->d_type;
|
||||
# endif
|
||||
if (dp->d_ino < maxino &&
|
||||
dp->d_reclen != 0 &&
|
||||
dp->d_reclen <= spaceleft &&
|
||||
(dp->d_reclen & 0x3) == 0 &&
|
||||
dp->d_reclen >= size &&
|
||||
idesc->id_filesize >= size &&
|
||||
namlen <= MAXNAMLEN &&
|
||||
type <= 15) {
|
||||
if (dp->d_ino == 0)
|
||||
return (1);
|
||||
for (cp = dp->d_name, size = 0; size < namlen; size++)
|
||||
if (*cp == 0 || (*cp++ == '/'))
|
||||
return (0);
|
||||
if (*cp == 0)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
direrror(ino, errmesg)
|
||||
ino_t ino;
|
||||
char *errmesg;
|
||||
{
|
||||
|
||||
fileerror(ino, ino, errmesg);
|
||||
}
|
||||
|
||||
fileerror(cwd, ino, errmesg)
|
||||
ino_t cwd, ino;
|
||||
char *errmesg;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
pwarn("%s ", errmesg);
|
||||
pinode(ino);
|
||||
printf("\n");
|
||||
getpathname(pathbuf, cwd, ino);
|
||||
if (ino < ROOTINO || ino > maxino) {
|
||||
pfatal("NAME=%s\n", pathbuf);
|
||||
return;
|
||||
}
|
||||
dp = ginode(ino);
|
||||
if (ftypeok(dp))
|
||||
pfatal("%s=%s\n",
|
||||
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
|
||||
else
|
||||
pfatal("NAME=%s\n", pathbuf);
|
||||
}
|
||||
|
||||
adjust(idesc, lcnt)
|
||||
register struct inodesc *idesc;
|
||||
short lcnt;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
|
||||
dp = ginode(idesc->id_number);
|
||||
if (dp->di_nlink == lcnt) {
|
||||
if (linkup(idesc->id_number, (ino_t)0) == 0)
|
||||
clri(idesc, "UNREF", 0);
|
||||
} else {
|
||||
pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
|
||||
((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
|
||||
pinode(idesc->id_number);
|
||||
printf(" COUNT %d SHOULD BE %d",
|
||||
dp->di_nlink, dp->di_nlink - lcnt);
|
||||
if (preen) {
|
||||
if (lcnt < 0) {
|
||||
printf("\n");
|
||||
pfatal("LINK COUNT INCREASING");
|
||||
}
|
||||
printf(" (ADJUSTED)\n");
|
||||
}
|
||||
if (preen || reply("ADJUST") == 1) {
|
||||
dp->di_nlink -= lcnt;
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mkentry(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
struct direct newent;
|
||||
int newlen, oldlen;
|
||||
|
||||
newent.d_namlen = strlen(idesc->id_name);
|
||||
newlen = DIRSIZ(0, &newent);
|
||||
if (dirp->d_ino != 0)
|
||||
oldlen = DIRSIZ(0, dirp);
|
||||
else
|
||||
oldlen = 0;
|
||||
if (dirp->d_reclen - oldlen < newlen)
|
||||
return (KEEPON);
|
||||
newent.d_reclen = dirp->d_reclen - oldlen;
|
||||
dirp->d_reclen = oldlen;
|
||||
dirp = (struct direct *)(((char *)dirp) + oldlen);
|
||||
dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
|
||||
if (newinofmt)
|
||||
dirp->d_type = typemap[idesc->id_parent];
|
||||
else
|
||||
dirp->d_type = 0;
|
||||
dirp->d_reclen = newent.d_reclen;
|
||||
dirp->d_namlen = newent.d_namlen;
|
||||
bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
|
||||
return (ALTERED|STOP);
|
||||
}
|
||||
|
||||
chgino(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
|
||||
return (KEEPON);
|
||||
dirp->d_ino = idesc->id_parent;
|
||||
if (newinofmt)
|
||||
dirp->d_type = typemap[idesc->id_parent];
|
||||
else
|
||||
dirp->d_type = 0;
|
||||
return (ALTERED|STOP);
|
||||
}
|
||||
|
||||
linkup(orphan, parentdir)
|
||||
ino_t orphan;
|
||||
ino_t parentdir;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
int lostdir;
|
||||
ino_t oldlfdir;
|
||||
struct inodesc idesc;
|
||||
char tempname[BUFSIZ];
|
||||
extern int pass4check();
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
dp = ginode(orphan);
|
||||
lostdir = (dp->di_mode & IFMT) == IFDIR;
|
||||
pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
|
||||
pinode(orphan);
|
||||
if (preen && dp->di_size == 0)
|
||||
return (0);
|
||||
if (preen)
|
||||
printf(" (RECONNECTED)\n");
|
||||
else
|
||||
if (reply("RECONNECT") == 0)
|
||||
return (0);
|
||||
if (lfdir == 0) {
|
||||
dp = ginode(ROOTINO);
|
||||
idesc.id_name = lfname;
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = findino;
|
||||
idesc.id_number = ROOTINO;
|
||||
if ((ckinode(dp, &idesc) & FOUND) != 0) {
|
||||
lfdir = idesc.id_parent;
|
||||
} else {
|
||||
pwarn("NO lost+found DIRECTORY");
|
||||
if (preen || reply("CREATE")) {
|
||||
lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
|
||||
if (lfdir != 0) {
|
||||
if (makeentry(ROOTINO, lfdir, lfname) != 0) {
|
||||
if (preen)
|
||||
printf(" (CREATED)\n");
|
||||
} else {
|
||||
freedir(lfdir, ROOTINO);
|
||||
lfdir = 0;
|
||||
if (preen)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lfdir == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
|
||||
printf("\n\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
dp = ginode(lfdir);
|
||||
if ((dp->di_mode & IFMT) != IFDIR) {
|
||||
pfatal("lost+found IS NOT A DIRECTORY");
|
||||
if (reply("REALLOCATE") == 0)
|
||||
return (0);
|
||||
oldlfdir = lfdir;
|
||||
if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
inodirty();
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
idesc.id_number = oldlfdir;
|
||||
adjust(&idesc, lncntp[oldlfdir] + 1);
|
||||
lncntp[oldlfdir] = 0;
|
||||
dp = ginode(lfdir);
|
||||
}
|
||||
if (statemap[lfdir] != DFOUND) {
|
||||
pfatal("SORRY. NO lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
(void)lftempname(tempname, orphan);
|
||||
if (makeentry(lfdir, orphan, tempname) == 0) {
|
||||
pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
|
||||
printf("\n\n");
|
||||
return (0);
|
||||
}
|
||||
lncntp[orphan]--;
|
||||
if (lostdir) {
|
||||
if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
|
||||
parentdir != (ino_t)-1)
|
||||
(void)makeentry(orphan, lfdir, "..");
|
||||
dp = ginode(lfdir);
|
||||
dp->di_nlink++;
|
||||
inodirty();
|
||||
lncntp[lfdir]++;
|
||||
pwarn("DIR I=%lu CONNECTED. ", orphan);
|
||||
if (parentdir != (ino_t)-1)
|
||||
printf("PARENT WAS I=%lu\n", parentdir);
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* fix an entry in a directory.
|
||||
*/
|
||||
changeino(dir, name, newnum)
|
||||
ino_t dir;
|
||||
char *name;
|
||||
ino_t newnum;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = chgino;
|
||||
idesc.id_number = dir;
|
||||
idesc.id_fix = DONTKNOW;
|
||||
idesc.id_name = name;
|
||||
idesc.id_parent = newnum; /* new value for name */
|
||||
return (ckinode(ginode(dir), &idesc));
|
||||
}
|
||||
|
||||
/*
|
||||
* make an entry in a directory
|
||||
*/
|
||||
makeentry(parent, ino, name)
|
||||
ino_t parent, ino;
|
||||
char *name;
|
||||
{
|
||||
struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
if (parent < ROOTINO || parent >= maxino ||
|
||||
ino < ROOTINO || ino >= maxino)
|
||||
return (0);
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = mkentry;
|
||||
idesc.id_number = parent;
|
||||
idesc.id_parent = ino; /* this is the inode to enter */
|
||||
idesc.id_fix = DONTKNOW;
|
||||
idesc.id_name = name;
|
||||
dp = ginode(parent);
|
||||
if (dp->di_size % DIRBLKSIZ) {
|
||||
dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
|
||||
inodirty();
|
||||
}
|
||||
if ((ckinode(dp, &idesc) & ALTERED) != 0)
|
||||
return (1);
|
||||
getpathname(pathbuf, parent, parent);
|
||||
dp = ginode(parent);
|
||||
if (expanddir(dp, pathbuf) == 0)
|
||||
return (0);
|
||||
return (ckinode(dp, &idesc) & ALTERED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to expand the size of a directory
|
||||
*/
|
||||
expanddir(dp, name)
|
||||
register struct dinode *dp;
|
||||
char *name;
|
||||
{
|
||||
daddr_t lastbn, newblk;
|
||||
register struct bufarea *bp;
|
||||
char *cp, firstblk[DIRBLKSIZ];
|
||||
|
||||
lastbn = lblkno(&sblock, dp->di_size);
|
||||
if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
|
||||
return (0);
|
||||
if ((newblk = allocblk(sblock.fs_frag)) == 0)
|
||||
return (0);
|
||||
dp->di_db[lastbn + 1] = dp->di_db[lastbn];
|
||||
dp->di_db[lastbn] = newblk;
|
||||
dp->di_size += sblock.fs_bsize;
|
||||
dp->di_blocks += btodb(sblock.fs_bsize);
|
||||
bp = getdirblk(dp->di_db[lastbn + 1],
|
||||
(long)dblksize(&sblock, dp, lastbn + 1));
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
|
||||
bp = getdirblk(newblk, sblock.fs_bsize);
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_bsize];
|
||||
cp += DIRBLKSIZ)
|
||||
bcopy((char *)&emptydir, cp, sizeof emptydir);
|
||||
dirty(bp);
|
||||
bp = getdirblk(dp->di_db[lastbn + 1],
|
||||
(long)dblksize(&sblock, dp, lastbn + 1));
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
|
||||
pwarn("NO SPACE LEFT IN %s", name);
|
||||
if (preen)
|
||||
printf(" (EXPANDED)\n");
|
||||
else if (reply("EXPAND") == 0)
|
||||
goto bad;
|
||||
dirty(bp);
|
||||
inodirty();
|
||||
return (1);
|
||||
bad:
|
||||
dp->di_db[lastbn] = dp->di_db[lastbn + 1];
|
||||
dp->di_db[lastbn + 1] = 0;
|
||||
dp->di_size -= sblock.fs_bsize;
|
||||
dp->di_blocks -= btodb(sblock.fs_bsize);
|
||||
freeblk(newblk, sblock.fs_frag);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a new directory
|
||||
*/
|
||||
allocdir(parent, request, mode)
|
||||
ino_t parent, request;
|
||||
int mode;
|
||||
{
|
||||
ino_t ino;
|
||||
char *cp;
|
||||
struct dinode *dp;
|
||||
register struct bufarea *bp;
|
||||
struct dirtemplate *dirp;
|
||||
|
||||
ino = allocino(request, IFDIR|mode);
|
||||
if (newinofmt)
|
||||
dirp = &dirhead;
|
||||
else
|
||||
dirp = (struct dirtemplate *)&odirhead;
|
||||
dirp->dot_ino = ino;
|
||||
dirp->dotdot_ino = parent;
|
||||
dp = ginode(ino);
|
||||
bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
|
||||
if (bp->b_errs) {
|
||||
freeino(ino);
|
||||
return (0);
|
||||
}
|
||||
bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate));
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_fsize];
|
||||
cp += DIRBLKSIZ)
|
||||
bcopy((char *)&emptydir, cp, sizeof emptydir);
|
||||
dirty(bp);
|
||||
dp->di_nlink = 2;
|
||||
inodirty();
|
||||
if (ino == ROOTINO) {
|
||||
lncntp[ino] = dp->di_nlink;
|
||||
cacheino(dp, ino);
|
||||
return(ino);
|
||||
}
|
||||
if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
|
||||
freeino(ino);
|
||||
return (0);
|
||||
}
|
||||
cacheino(dp, ino);
|
||||
statemap[ino] = statemap[parent];
|
||||
if (statemap[ino] == DSTATE) {
|
||||
lncntp[ino] = dp->di_nlink;
|
||||
lncntp[parent]++;
|
||||
}
|
||||
dp = ginode(parent);
|
||||
dp->di_nlink++;
|
||||
inodirty();
|
||||
return (ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* free a directory inode
|
||||
*/
|
||||
freedir(ino, parent)
|
||||
ino_t ino, parent;
|
||||
{
|
||||
struct dinode *dp;
|
||||
|
||||
if (ino != parent) {
|
||||
dp = ginode(parent);
|
||||
dp->di_nlink--;
|
||||
inodirty();
|
||||
}
|
||||
freeino(ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a temporary name for the lost+found directory.
|
||||
*/
|
||||
lftempname(bufp, ino)
|
||||
char *bufp;
|
||||
ino_t ino;
|
||||
{
|
||||
register ino_t in;
|
||||
register char *cp;
|
||||
int namlen;
|
||||
|
||||
cp = bufp + 2;
|
||||
for (in = maxino; in > 0; in /= 10)
|
||||
cp++;
|
||||
*--cp = 0;
|
||||
namlen = cp - bufp;
|
||||
in = ino;
|
||||
while (cp > bufp) {
|
||||
*--cp = (in % 10) + '0';
|
||||
in /= 10;
|
||||
}
|
||||
*cp = '#';
|
||||
return (namlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a directory block.
|
||||
* Insure that it is held until another is requested.
|
||||
*/
|
||||
struct bufarea *
|
||||
getdirblk(blkno, size)
|
||||
daddr_t blkno;
|
||||
long size;
|
||||
{
|
||||
|
||||
if (pdirbp != 0)
|
||||
pdirbp->b_flags &= ~B_INUSE;
|
||||
pdirbp = getdatablk(blkno, size);
|
||||
return (pdirbp);
|
||||
}
|
||||
215
sbin/fsck_ffs/fsck.h
Normal file
215
sbin/fsck_ffs/fsck.h
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fsck.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#define MAXDUP 10 /* limit on dup blks (per inode) */
|
||||
#define MAXBAD 10 /* limit on bad blks (per inode) */
|
||||
#define MAXBUFSPACE 40*1024 /* maximum space to allocate to buffers */
|
||||
#define INOBUFSIZE 56*1024 /* size of buffer to read inodes in pass1 */
|
||||
|
||||
#ifndef BUFSIZ
|
||||
#define BUFSIZ 1024
|
||||
#endif
|
||||
|
||||
#define USTATE 01 /* inode not allocated */
|
||||
#define FSTATE 02 /* inode is file */
|
||||
#define DSTATE 03 /* inode is directory */
|
||||
#define DFOUND 04 /* directory found during descent */
|
||||
#define DCLEAR 05 /* directory is to be cleared */
|
||||
#define FCLEAR 06 /* file is to be cleared */
|
||||
|
||||
/*
|
||||
* buffer cache structure.
|
||||
*/
|
||||
struct bufarea {
|
||||
struct bufarea *b_next; /* free list queue */
|
||||
struct bufarea *b_prev; /* free list queue */
|
||||
daddr_t b_bno;
|
||||
int b_size;
|
||||
int b_errs;
|
||||
int b_flags;
|
||||
union {
|
||||
char *b_buf; /* buffer space */
|
||||
daddr_t *b_indir; /* indirect block */
|
||||
struct fs *b_fs; /* super block */
|
||||
struct cg *b_cg; /* cylinder group */
|
||||
struct dinode *b_dinode; /* inode block */
|
||||
} b_un;
|
||||
char b_dirty;
|
||||
};
|
||||
|
||||
#define B_INUSE 1
|
||||
|
||||
#define MINBUFS 5 /* minimum number of buffers required */
|
||||
struct bufarea bufhead; /* head of list of other blks in filesys */
|
||||
struct bufarea sblk; /* file system superblock */
|
||||
struct bufarea cgblk; /* cylinder group blocks */
|
||||
struct bufarea *pdirbp; /* current directory contents */
|
||||
struct bufarea *pbp; /* current inode block */
|
||||
struct bufarea *getdatablk();
|
||||
|
||||
#define dirty(bp) (bp)->b_dirty = 1
|
||||
#define initbarea(bp) \
|
||||
(bp)->b_dirty = 0; \
|
||||
(bp)->b_bno = (daddr_t)-1; \
|
||||
(bp)->b_flags = 0;
|
||||
|
||||
#define sbdirty() sblk.b_dirty = 1
|
||||
#define cgdirty() cgblk.b_dirty = 1
|
||||
#define sblock (*sblk.b_un.b_fs)
|
||||
#define cgrp (*cgblk.b_un.b_cg)
|
||||
|
||||
enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
|
||||
|
||||
struct inodesc {
|
||||
enum fixstate id_fix; /* policy on fixing errors */
|
||||
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 */
|
||||
quad_t 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 */
|
||||
struct direct *id_dirp; /* for DATA nodes, ptr to current entry */
|
||||
char *id_name; /* for DATA nodes, name to find or enter */
|
||||
char id_type; /* type of descriptor, DATA or ADDR */
|
||||
};
|
||||
/* file types */
|
||||
#define DATA 1
|
||||
#define ADDR 2
|
||||
|
||||
/*
|
||||
* Linked list of duplicate blocks.
|
||||
*
|
||||
* The list is composed of two parts. The first part of the
|
||||
* list (from duplist through the node pointed to by muldup)
|
||||
* contains a single copy of each duplicate block that has been
|
||||
* found. The second part of the list (from muldup to the end)
|
||||
* contains duplicate blocks that have been found more than once.
|
||||
* To check if a block has been found as a duplicate it is only
|
||||
* necessary to search from duplist through muldup. To find the
|
||||
* total number of times that a block has been found as a duplicate
|
||||
* the entire list must be searched for occurences of the block
|
||||
* in question. The following diagram shows a sample list where
|
||||
* w (found twice), x (found once), y (found three times), and z
|
||||
* (found once) are duplicate block numbers:
|
||||
*
|
||||
* w -> y -> x -> z -> y -> w -> y
|
||||
* ^ ^
|
||||
* | |
|
||||
* duplist muldup
|
||||
*/
|
||||
struct dups {
|
||||
struct dups *next;
|
||||
daddr_t dup;
|
||||
};
|
||||
struct dups *duplist; /* head of dup list */
|
||||
struct dups *muldup; /* end of unique duplicate dup block numbers */
|
||||
|
||||
/*
|
||||
* Linked list of inodes with zero link counts.
|
||||
*/
|
||||
struct zlncnt {
|
||||
struct zlncnt *next;
|
||||
ino_t zlncnt;
|
||||
};
|
||||
struct zlncnt *zlnhead; /* head of zero link count list */
|
||||
|
||||
/*
|
||||
* Inode cache data structures.
|
||||
*/
|
||||
struct inoinfo {
|
||||
struct inoinfo *i_nexthash; /* next entry in hash chain */
|
||||
ino_t i_number; /* inode number of this entry */
|
||||
ino_t i_parent; /* inode number of parent */
|
||||
ino_t i_dotdot; /* inode number of `..' */
|
||||
size_t i_isize; /* size of inode */
|
||||
u_int i_numblks; /* size of block array in bytes */
|
||||
daddr_t i_blks[1]; /* actually longer */
|
||||
} **inphead, **inpsort;
|
||||
long numdirs, listmax, inplast;
|
||||
|
||||
char *cdevname; /* name of device being checked */
|
||||
long dev_bsize; /* computed value of DEV_BSIZE */
|
||||
long secsize; /* actual disk sector size */
|
||||
char nflag; /* assume a no response */
|
||||
char yflag; /* assume a yes response */
|
||||
int bflag; /* location of alternate super block */
|
||||
int debug; /* output debugging info */
|
||||
int cvtlevel; /* convert to newer file system format */
|
||||
int doinglevel1; /* converting to new cylinder group format */
|
||||
int doinglevel2; /* converting to new inode format */
|
||||
int newinofmt; /* filesystem has new inode format */
|
||||
char preen; /* just fix normal inconsistencies */
|
||||
char hotroot; /* checking root device */
|
||||
char havesb; /* superblock has been read */
|
||||
int fsmodified; /* 1 => write done to file system */
|
||||
int fsreadfd; /* file descriptor for reading file system */
|
||||
int fswritefd; /* file descriptor for writing file system */
|
||||
|
||||
daddr_t maxfsblock; /* number of blocks in the file system */
|
||||
char *blockmap; /* ptr to primary blk allocation map */
|
||||
ino_t maxino; /* number of inodes in file system */
|
||||
ino_t lastino; /* last inode in use */
|
||||
char *statemap; /* ptr to inode state table */
|
||||
char *typemap; /* ptr to inode type table */
|
||||
short *lncntp; /* ptr to link count table */
|
||||
|
||||
ino_t lfdir; /* lost & found directory inode number */
|
||||
char *lfname; /* lost & found directory name */
|
||||
int lfmode; /* lost & found directory creation mode */
|
||||
|
||||
daddr_t n_blks; /* number of blocks in use */
|
||||
daddr_t n_files; /* number of files in use */
|
||||
|
||||
#define clearinode(dp) (*(dp) = zino)
|
||||
struct dinode zino;
|
||||
|
||||
#define setbmap(blkno) setbit(blockmap, blkno)
|
||||
#define testbmap(blkno) isset(blockmap, blkno)
|
||||
#define clrbmap(blkno) clrbit(blockmap, blkno)
|
||||
|
||||
#define STOP 0x01
|
||||
#define SKIP 0x02
|
||||
#define KEEPON 0x04
|
||||
#define ALTERED 0x08
|
||||
#define FOUND 0x10
|
||||
|
||||
time_t time();
|
||||
struct dinode *ginode();
|
||||
struct inoinfo *getinoinfo();
|
||||
void getblk();
|
||||
ino_t allocino();
|
||||
int findino();
|
||||
291
sbin/fsck_ffs/fsck_ffs.8
Normal file
291
sbin/fsck_ffs/fsck_ffs.8
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
.\" Copyright (c) 1980, 1989, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)fsck.8 8.2 (Berkeley) 12/11/93
|
||||
.\"
|
||||
.Dd December 11, 1993
|
||||
.Dt FSCK 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm fsck
|
||||
.Nd filesystem consistency check and interactive repair
|
||||
.Sh SYNOPSIS
|
||||
.Nm fsck
|
||||
.Fl p
|
||||
.Op Fl m Ar mode
|
||||
.Nm fsck
|
||||
.Op Fl b Ar block#
|
||||
.Op Fl c Ar level
|
||||
.Op Fl l Ar maxparallel
|
||||
.Op Fl y
|
||||
.Op Fl n
|
||||
.Op Fl m Ar mode
|
||||
.Op Ar filesystem
|
||||
.Ar ...
|
||||
.Sh DESCRIPTION
|
||||
The first form of
|
||||
.Nm fsck
|
||||
preens a standard set of filesystems or the specified filesystems.
|
||||
It is normally used in the script
|
||||
.Pa /etc/rc
|
||||
during automatic reboot.
|
||||
Here
|
||||
.Nm fsck
|
||||
reads the table
|
||||
.Pa /etc/fstab
|
||||
to determine which filesystems to check.
|
||||
Only partitions in fstab that are mounted ``rw,'' ``rq'' or ``ro''
|
||||
and that have non-zero pass number are checked.
|
||||
Filesystems with pass number 1 (normally just the root filesystem)
|
||||
are checked one at a time.
|
||||
When pass 1 completes, all remaining filesystems are checked,
|
||||
running one process per disk drive.
|
||||
The disk drive containing each filesystem is inferred from the longest prefix
|
||||
of the device name that ends in a digit; the remaining characters are assumed
|
||||
to be the partition designator.
|
||||
.Pp
|
||||
The kernel takes care that only a restricted class of innocuous filesystem
|
||||
inconsistencies can happen unless hardware or software failures intervene.
|
||||
These are limited to the following:
|
||||
.Bl -item -compact
|
||||
.It
|
||||
Unreferenced inodes
|
||||
.It
|
||||
Link counts in inodes too large
|
||||
.It
|
||||
Missing blocks in the free map
|
||||
.It
|
||||
Blocks in the free map also in files
|
||||
.It
|
||||
Counts in the super-block wrong
|
||||
.El
|
||||
.Pp
|
||||
These are the only inconsistencies that
|
||||
.Nm fsck
|
||||
with the
|
||||
.Fl p
|
||||
option will correct; if it encounters other inconsistencies, it exits
|
||||
with an abnormal return status and an automatic reboot will then fail.
|
||||
For each corrected inconsistency one or more lines will be printed
|
||||
identifying the filesystem on which the correction will take place,
|
||||
and the nature of the correction. After successfully correcting a filesystem,
|
||||
.Nm fsck
|
||||
will print the number of files on that filesystem,
|
||||
the number of used and free blocks,
|
||||
and the percentage of fragmentation.
|
||||
.Pp
|
||||
If sent a
|
||||
.Dv QUIT
|
||||
signal,
|
||||
.Nm fsck
|
||||
will finish the filesystem checks, then exit with an abnormal
|
||||
return status that causes an automatic reboot to fail.
|
||||
This is useful when you want to finish the filesystem checks during an
|
||||
automatic reboot,
|
||||
but do not want the machine to come up multiuser after the checks complete.
|
||||
.Pp
|
||||
Without the
|
||||
.Fl p
|
||||
option,
|
||||
.Nm fsck
|
||||
audits and interactively repairs inconsistent conditions for filesystems.
|
||||
If the filesystem is inconsistent the operator is prompted for concurrence
|
||||
before each correction is attempted.
|
||||
It should be noted that some of the corrective actions which are not
|
||||
correctable under the
|
||||
.Fl p
|
||||
option will result in some loss of data.
|
||||
The amount and severity of data lost may be determined from the diagnostic
|
||||
output.
|
||||
The default action for each consistency correction
|
||||
is to wait for the operator to respond
|
||||
.Li yes
|
||||
or
|
||||
.Li no .
|
||||
If the operator does not have write permission on the filesystem
|
||||
.Nm fsck
|
||||
will default to a
|
||||
.Fl n
|
||||
action.
|
||||
.Pp
|
||||
.Nm Fsck
|
||||
has more consistency checks than
|
||||
its predecessors
|
||||
.Em check , dcheck , fcheck ,
|
||||
and
|
||||
.Em icheck
|
||||
combined.
|
||||
.Pp
|
||||
The following flags are interpreted by
|
||||
.Nm fsck .
|
||||
.Bl -tag -width indent
|
||||
.It Fl b
|
||||
Use the block specified immediately after the flag as
|
||||
the super block for the filesystem. Block 32 is usually
|
||||
an alternate super block.
|
||||
.It Fl l
|
||||
Limit the number of parallel checks to the number specified in the following
|
||||
argument.
|
||||
By default, the limit is the number of disks, running one process per disk.
|
||||
If a smaller limit is given, the disks are checked round-robin, one filesystem
|
||||
at a time.
|
||||
.It Fl m
|
||||
Use the mode specified in octal immediately after the flag as the
|
||||
permission bits to use when creating the
|
||||
.Pa lost+found
|
||||
directory rather than the default 1777.
|
||||
In particular, systems that do not wish to have lost files accessible
|
||||
by all users on the system should use a more restrictive
|
||||
set of permissions such as 700.
|
||||
.It Fl y
|
||||
Assume a yes response to all questions asked by
|
||||
.Nm fsck ;
|
||||
this should be used with great caution as this is a free license
|
||||
to continue after essentially unlimited trouble has been encountered.
|
||||
.It Fl n
|
||||
Assume a no response to all questions asked by
|
||||
.Nm fsck
|
||||
except for
|
||||
.Ql CONTINUE? ,
|
||||
which is assumed to be affirmative;
|
||||
do not open the filesystem for writing.
|
||||
.It Fl c
|
||||
Convert the filesystem to the specified level.
|
||||
Note that the level of a filesystem can only be raised.
|
||||
.Bl -tag -width indent
|
||||
There are currently three levels defined:
|
||||
.It 0
|
||||
The filesystem is in the old (static table) format.
|
||||
.It 1
|
||||
The filesystem is in the new (dynamic table) format.
|
||||
.It 2
|
||||
The filesystem supports 32-bit uid's and gid's,
|
||||
short symbolic links are stored in the inode,
|
||||
and directories have an added field showing the file type.
|
||||
.El
|
||||
.Pp
|
||||
In interactive mode,
|
||||
.Nm fsck
|
||||
will list the conversion to be made
|
||||
and ask whether the conversion should be done.
|
||||
If a negative answer is given,
|
||||
no further operations are done on the filesystem.
|
||||
In preen mode,
|
||||
the conversion is listed and done if
|
||||
possible without user interaction.
|
||||
Conversion in preen mode is best used when all the filesystems
|
||||
are being converted at once.
|
||||
The format of a filesystem can be determined from the
|
||||
first line of output from
|
||||
.Xr dumpfs 8 .
|
||||
.El
|
||||
.Pp
|
||||
If no filesystems are given to
|
||||
.Nm fsck
|
||||
then a default list of filesystems is read from
|
||||
the file
|
||||
.Pa /etc/fstab .
|
||||
.Pp
|
||||
.Bl -enum -indent indent -compact
|
||||
Inconsistencies checked are as follows:
|
||||
.It
|
||||
Blocks claimed by more than one inode or the free map.
|
||||
.It
|
||||
Blocks claimed by an inode outside the range of the filesystem.
|
||||
.It
|
||||
Incorrect link counts.
|
||||
.It
|
||||
Size checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
Directory size not a multiple of DIRBLKSIZ.
|
||||
.It
|
||||
Partially truncated file.
|
||||
.El
|
||||
.It
|
||||
Bad inode format.
|
||||
.It
|
||||
Blocks not accounted for anywhere.
|
||||
.It
|
||||
Directory checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
File pointing to unallocated inode.
|
||||
.It
|
||||
Inode number out of range.
|
||||
.It
|
||||
Dot or dot-dot not the first two entries of a directory
|
||||
or having the wrong inode number.
|
||||
.El
|
||||
.It
|
||||
Super Block checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
More blocks for inodes than there are in the filesystem.
|
||||
.It
|
||||
Bad free block map format.
|
||||
.It
|
||||
Total free block and/or free inode count incorrect.
|
||||
.El
|
||||
.El
|
||||
.Pp
|
||||
Orphaned files and directories (allocated but unreferenced) are,
|
||||
with the operator's concurrence, reconnected by
|
||||
placing them in the
|
||||
.Pa lost+found
|
||||
directory.
|
||||
The name assigned is the inode number.
|
||||
If the
|
||||
.Pa lost+found
|
||||
directory does not exist, it is created.
|
||||
If there is insufficient space its size is increased.
|
||||
.Pp
|
||||
Because of inconsistencies between the block device and the buffer cache,
|
||||
the raw device should always be used.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/fstab -compact
|
||||
.It Pa /etc/fstab
|
||||
contains default list of filesystems to check.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
The diagnostics produced by
|
||||
.Nm fsck
|
||||
are fully enumerated and explained in Appendix A of
|
||||
.Rs
|
||||
.%T "Fsck \- The UNIX File System Check Program"
|
||||
.Re
|
||||
.Sh SEE ALSO
|
||||
.Xr fstab 5 ,
|
||||
.Xr fs 5 ,
|
||||
.Xr fsdb 8 ,
|
||||
.Xr newfs 8 ,
|
||||
.Xr mkfs 8 ,
|
||||
.Xr reboot 8
|
||||
543
sbin/fsck_ffs/inode.c
Normal file
543
sbin/fsck_ffs/inode.c
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)inode.c 8.4 (Berkeley) 4/18/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
static ino_t startinum;
|
||||
|
||||
ckinode(dp, idesc)
|
||||
struct dinode *dp;
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register daddr_t *ap;
|
||||
long ret, n, ndb, offset;
|
||||
struct dinode dino;
|
||||
quad_t remsize, sizepb;
|
||||
mode_t mode;
|
||||
|
||||
if (idesc->id_fix != IGNORE)
|
||||
idesc->id_fix = DONTKNOW;
|
||||
idesc->id_entryno = 0;
|
||||
idesc->id_filesize = dp->di_size;
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
|
||||
dp->di_size < sblock.fs_maxsymlinklen))
|
||||
return (KEEPON);
|
||||
dino = *dp;
|
||||
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)
|
||||
idesc->id_numfrags =
|
||||
numfrags(&sblock, fragroundup(&sblock, offset));
|
||||
else
|
||||
idesc->id_numfrags = sblock.fs_frag;
|
||||
if (*ap == 0)
|
||||
continue;
|
||||
idesc->id_blkno = *ap;
|
||||
if (idesc->id_type == ADDR)
|
||||
ret = (*idesc->id_func)(idesc);
|
||||
else
|
||||
ret = dirscan(idesc);
|
||||
if (ret & STOP)
|
||||
return (ret);
|
||||
}
|
||||
idesc->id_numfrags = sblock.fs_frag;
|
||||
remsize = dino.di_size - sblock.fs_bsize * NDADDR;
|
||||
sizepb = sblock.fs_bsize;
|
||||
for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
|
||||
if (*ap) {
|
||||
idesc->id_blkno = *ap;
|
||||
ret = iblock(idesc, n, remsize);
|
||||
if (ret & STOP)
|
||||
return (ret);
|
||||
}
|
||||
sizepb *= NINDIR(&sblock);
|
||||
remsize -= sizepb;
|
||||
}
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
iblock(idesc, ilevel, isize)
|
||||
struct inodesc *idesc;
|
||||
long ilevel;
|
||||
quad_t isize;
|
||||
{
|
||||
register daddr_t *ap;
|
||||
register daddr_t *aplim;
|
||||
register struct bufarea *bp;
|
||||
int i, n, (*func)(), nif;
|
||||
quad_t sizepb;
|
||||
char buf[BUFSIZ];
|
||||
extern int dirscan(), pass1check();
|
||||
|
||||
if (idesc->id_type == ADDR) {
|
||||
func = idesc->id_func;
|
||||
if (((n = (*func)(idesc)) & KEEPON) == 0)
|
||||
return (n);
|
||||
} else
|
||||
func = dirscan;
|
||||
if (chkrange(idesc->id_blkno, idesc->id_numfrags))
|
||||
return (SKIP);
|
||||
bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
|
||||
ilevel--;
|
||||
for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
|
||||
sizepb *= NINDIR(&sblock);
|
||||
nif = howmany(isize , sizepb);
|
||||
if (nif > NINDIR(&sblock))
|
||||
nif = NINDIR(&sblock);
|
||||
if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
|
||||
aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
|
||||
for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
|
||||
if (*ap == 0)
|
||||
continue;
|
||||
(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
|
||||
idesc->id_number);
|
||||
if (dofix(idesc, buf)) {
|
||||
*ap = 0;
|
||||
dirty(bp);
|
||||
}
|
||||
}
|
||||
flush(fswritefd, bp);
|
||||
}
|
||||
aplim = &bp->b_un.b_indir[nif];
|
||||
for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
|
||||
if (*ap) {
|
||||
idesc->id_blkno = *ap;
|
||||
if (ilevel == 0)
|
||||
n = (*func)(idesc);
|
||||
else
|
||||
n = iblock(idesc, ilevel, isize);
|
||||
if (n & STOP) {
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return (n);
|
||||
}
|
||||
}
|
||||
isize -= sizepb;
|
||||
}
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that a block in a legal block number.
|
||||
* Return 0 if in range, 1 if out of range.
|
||||
*/
|
||||
chkrange(blk, cnt)
|
||||
daddr_t blk;
|
||||
int cnt;
|
||||
{
|
||||
register int c;
|
||||
|
||||
if ((unsigned)(blk + cnt) > maxfsblock)
|
||||
return (1);
|
||||
c = dtog(&sblock, blk);
|
||||
if (blk < cgdmin(&sblock, c)) {
|
||||
if ((blk + cnt) > cgsblock(&sblock, c)) {
|
||||
if (debug) {
|
||||
printf("blk %ld < cgdmin %ld;",
|
||||
blk, cgdmin(&sblock, c));
|
||||
printf(" blk + cnt %ld > cgsbase %ld\n",
|
||||
blk + cnt, cgsblock(&sblock, c));
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
if ((blk + cnt) > cgbase(&sblock, c+1)) {
|
||||
if (debug) {
|
||||
printf("blk %ld >= cgdmin %ld;",
|
||||
blk, cgdmin(&sblock, c));
|
||||
printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
|
||||
blk+cnt, sblock.fs_fpg);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* General purpose interface for reading inodes.
|
||||
*/
|
||||
struct dinode *
|
||||
ginode(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
daddr_t iblk;
|
||||
|
||||
if (inumber < ROOTINO || inumber > maxino)
|
||||
errexit("bad inode number %d to ginode\n", inumber);
|
||||
if (startinum == 0 ||
|
||||
inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
|
||||
iblk = ino_to_fsba(&sblock, inumber);
|
||||
if (pbp != 0)
|
||||
pbp->b_flags &= ~B_INUSE;
|
||||
pbp = getdatablk(iblk, sblock.fs_bsize);
|
||||
startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
|
||||
}
|
||||
return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special purpose version of ginode used to optimize first pass
|
||||
* over all the inodes in numerical order.
|
||||
*/
|
||||
ino_t nextino, lastinum;
|
||||
long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
|
||||
struct dinode *inodebuf;
|
||||
|
||||
struct dinode *
|
||||
getnextinode(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
long size;
|
||||
daddr_t dblk;
|
||||
static struct dinode *dp;
|
||||
|
||||
if (inumber != nextino++ || inumber > maxino)
|
||||
errexit("bad inode number %d to nextinode\n", inumber);
|
||||
if (inumber >= lastinum) {
|
||||
readcnt++;
|
||||
dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
|
||||
if (readcnt % readpercg == 0) {
|
||||
size = partialsize;
|
||||
lastinum += partialcnt;
|
||||
} else {
|
||||
size = inobufsize;
|
||||
lastinum += fullcnt;
|
||||
}
|
||||
(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
|
||||
dp = inodebuf;
|
||||
}
|
||||
return (dp++);
|
||||
}
|
||||
|
||||
resetinodebuf()
|
||||
{
|
||||
|
||||
startinum = 0;
|
||||
nextino = 0;
|
||||
lastinum = 0;
|
||||
readcnt = 0;
|
||||
inobufsize = blkroundup(&sblock, INOBUFSIZE);
|
||||
fullcnt = inobufsize / sizeof(struct dinode);
|
||||
readpercg = sblock.fs_ipg / fullcnt;
|
||||
partialcnt = sblock.fs_ipg % fullcnt;
|
||||
partialsize = partialcnt * sizeof(struct dinode);
|
||||
if (partialcnt != 0) {
|
||||
readpercg++;
|
||||
} else {
|
||||
partialcnt = fullcnt;
|
||||
partialsize = inobufsize;
|
||||
}
|
||||
if (inodebuf == NULL &&
|
||||
(inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
|
||||
errexit("Cannot allocate space for inode buffer\n");
|
||||
while (nextino < ROOTINO)
|
||||
(void)getnextinode(nextino);
|
||||
}
|
||||
|
||||
freeinodebuf()
|
||||
{
|
||||
|
||||
if (inodebuf != NULL)
|
||||
free((char *)inodebuf);
|
||||
inodebuf = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines to maintain information about directory inodes.
|
||||
* This is built during the first pass and used during the
|
||||
* second and third passes.
|
||||
*
|
||||
* Enter inodes into the cache.
|
||||
*/
|
||||
cacheino(dp, inumber)
|
||||
register struct dinode *dp;
|
||||
ino_t inumber;
|
||||
{
|
||||
register struct inoinfo *inp;
|
||||
struct inoinfo **inpp;
|
||||
unsigned int blks;
|
||||
|
||||
blks = howmany(dp->di_size, sblock.fs_bsize);
|
||||
if (blks > NDADDR)
|
||||
blks = NDADDR + NIADDR;
|
||||
inp = (struct inoinfo *)
|
||||
malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
|
||||
if (inp == NULL)
|
||||
return;
|
||||
inpp = &inphead[inumber % numdirs];
|
||||
inp->i_nexthash = *inpp;
|
||||
*inpp = inp;
|
||||
inp->i_parent = (ino_t)0;
|
||||
inp->i_dotdot = (ino_t)0;
|
||||
inp->i_number = inumber;
|
||||
inp->i_isize = dp->di_size;
|
||||
inp->i_numblks = blks * sizeof(daddr_t);
|
||||
bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
|
||||
(size_t)inp->i_numblks);
|
||||
if (inplast == listmax) {
|
||||
listmax += 100;
|
||||
inpsort = (struct inoinfo **)realloc((char *)inpsort,
|
||||
(unsigned)listmax * sizeof(struct inoinfo *));
|
||||
if (inpsort == NULL)
|
||||
errexit("cannot increase directory list");
|
||||
}
|
||||
inpsort[inplast++] = inp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an inode cache structure.
|
||||
*/
|
||||
struct inoinfo *
|
||||
getinoinfo(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
register struct inoinfo *inp;
|
||||
|
||||
for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
|
||||
if (inp->i_number != inumber)
|
||||
continue;
|
||||
return (inp);
|
||||
}
|
||||
errexit("cannot find inode %d\n", inumber);
|
||||
return ((struct inoinfo *)0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up all the inode cache structure.
|
||||
*/
|
||||
inocleanup()
|
||||
{
|
||||
register struct inoinfo **inpp;
|
||||
|
||||
if (inphead == NULL)
|
||||
return;
|
||||
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
|
||||
free((char *)(*inpp));
|
||||
free((char *)inphead);
|
||||
free((char *)inpsort);
|
||||
inphead = inpsort = NULL;
|
||||
}
|
||||
|
||||
inodirty()
|
||||
{
|
||||
|
||||
dirty(pbp);
|
||||
}
|
||||
|
||||
clri(idesc, type, flag)
|
||||
register struct inodesc *idesc;
|
||||
char *type;
|
||||
int flag;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
|
||||
dp = ginode(idesc->id_number);
|
||||
if (flag == 1) {
|
||||
pwarn("%s %s", type,
|
||||
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
|
||||
pinode(idesc->id_number);
|
||||
}
|
||||
if (preen || reply("CLEAR") == 1) {
|
||||
if (preen)
|
||||
printf(" (CLEARED)\n");
|
||||
n_files--;
|
||||
(void)ckinode(dp, idesc);
|
||||
clearinode(dp);
|
||||
statemap[idesc->id_number] = USTATE;
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
|
||||
findname(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (dirp->d_ino != idesc->id_parent)
|
||||
return (KEEPON);
|
||||
bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
|
||||
return (STOP|FOUND);
|
||||
}
|
||||
|
||||
findino(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (dirp->d_ino == 0)
|
||||
return (KEEPON);
|
||||
if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
|
||||
dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
|
||||
idesc->id_parent = dirp->d_ino;
|
||||
return (STOP|FOUND);
|
||||
}
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
pinode(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register char *p;
|
||||
struct passwd *pw;
|
||||
char *ctime();
|
||||
|
||||
printf(" I=%lu ", ino);
|
||||
if (ino < ROOTINO || ino > maxino)
|
||||
return;
|
||||
dp = ginode(ino);
|
||||
printf(" OWNER=");
|
||||
if ((pw = getpwuid((int)dp->di_uid)) != 0)
|
||||
printf("%s ", pw->pw_name);
|
||||
else
|
||||
printf("%u ", (unsigned)dp->di_uid);
|
||||
printf("MODE=%o\n", dp->di_mode);
|
||||
if (preen)
|
||||
printf("%s: ", cdevname);
|
||||
printf("SIZE=%qu ", dp->di_size);
|
||||
p = ctime(&dp->di_mtime.ts_sec);
|
||||
printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
|
||||
}
|
||||
|
||||
blkerror(ino, type, blk)
|
||||
ino_t ino;
|
||||
char *type;
|
||||
daddr_t blk;
|
||||
{
|
||||
|
||||
pfatal("%ld %s I=%lu", blk, type, ino);
|
||||
printf("\n");
|
||||
switch (statemap[ino]) {
|
||||
|
||||
case FSTATE:
|
||||
statemap[ino] = FCLEAR;
|
||||
return;
|
||||
|
||||
case DSTATE:
|
||||
statemap[ino] = DCLEAR;
|
||||
return;
|
||||
|
||||
case FCLEAR:
|
||||
case DCLEAR:
|
||||
return;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d TO BLKERR", statemap[ino]);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate an unused inode
|
||||
*/
|
||||
ino_t
|
||||
allocino(request, type)
|
||||
ino_t request;
|
||||
int type;
|
||||
{
|
||||
register ino_t ino;
|
||||
register struct dinode *dp;
|
||||
|
||||
if (request == 0)
|
||||
request = ROOTINO;
|
||||
else if (statemap[request] != USTATE)
|
||||
return (0);
|
||||
for (ino = request; ino < maxino; ino++)
|
||||
if (statemap[ino] == USTATE)
|
||||
break;
|
||||
if (ino == maxino)
|
||||
return (0);
|
||||
switch (type & IFMT) {
|
||||
case IFDIR:
|
||||
statemap[ino] = DSTATE;
|
||||
break;
|
||||
case IFREG:
|
||||
case IFLNK:
|
||||
statemap[ino] = FSTATE;
|
||||
break;
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
dp = ginode(ino);
|
||||
dp->di_db[0] = allocblk((long)1);
|
||||
if (dp->di_db[0] == 0) {
|
||||
statemap[ino] = USTATE;
|
||||
return (0);
|
||||
}
|
||||
dp->di_mode = type;
|
||||
(void)time(&dp->di_atime.ts_sec);
|
||||
dp->di_mtime = dp->di_ctime = dp->di_atime;
|
||||
dp->di_size = sblock.fs_fsize;
|
||||
dp->di_blocks = btodb(sblock.fs_fsize);
|
||||
n_files++;
|
||||
inodirty();
|
||||
if (newinofmt)
|
||||
typemap[ino] = IFTODT(type);
|
||||
return (ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* deallocate an inode
|
||||
*/
|
||||
freeino(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
extern int pass4check();
|
||||
struct dinode *dp;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
idesc.id_number = ino;
|
||||
dp = ginode(ino);
|
||||
(void)ckinode(dp, &idesc);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
statemap[ino] = USTATE;
|
||||
n_files--;
|
||||
}
|
||||
318
sbin/fsck_ffs/main.c
Normal file
318
sbin/fsck_ffs/main.c
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1980, 1986, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mount.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <fstab.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "fsck.h"
|
||||
|
||||
void catch(), catchquit(), voidquit();
|
||||
int returntosingle;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch;
|
||||
int ret, maxrun = 0;
|
||||
extern int docheck(), checkfilesys();
|
||||
extern char *optarg, *blockcheck();
|
||||
extern int optind;
|
||||
|
||||
sync();
|
||||
while ((ch = getopt(argc, argv, "dpnNyYb:c:l:m:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
preen++;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
bflag = argtoi('b', "number", optarg, 10);
|
||||
printf("Alternate super block location: %d\n", bflag);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
cvtlevel = argtoi('c', "conversion level", optarg, 10);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
maxrun = argtoi('l', "number", optarg, 10);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
lfmode = argtoi('m', "mode", optarg, 8);
|
||||
if (lfmode &~ 07777)
|
||||
errexit("bad mode to -m: %o\n", lfmode);
|
||||
printf("** lost+found creation mode %o\n", lfmode);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
nflag++;
|
||||
yflag = 0;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
case 'Y':
|
||||
yflag++;
|
||||
nflag = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("%c option?\n", ch);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
(void)signal(SIGINT, catch);
|
||||
if (preen)
|
||||
(void)signal(SIGQUIT, catchquit);
|
||||
if (argc) {
|
||||
while (argc-- > 0)
|
||||
(void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
|
||||
exit(0);
|
||||
}
|
||||
ret = checkfstab(preen, maxrun, docheck, checkfilesys);
|
||||
if (returntosingle)
|
||||
exit(2);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
argtoi(flag, req, str, base)
|
||||
int flag;
|
||||
char *req, *str;
|
||||
int base;
|
||||
{
|
||||
char *cp;
|
||||
int ret;
|
||||
|
||||
ret = (int)strtol(str, &cp, base);
|
||||
if (cp == str || *cp)
|
||||
errexit("-%c flag requires a %s\n", flag, req);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether a filesystem should be checked.
|
||||
*/
|
||||
docheck(fsp)
|
||||
register struct fstab *fsp;
|
||||
{
|
||||
|
||||
if (strcmp(fsp->fs_vfstype, "ufs") ||
|
||||
(strcmp(fsp->fs_type, FSTAB_RW) &&
|
||||
strcmp(fsp->fs_type, FSTAB_RO)) ||
|
||||
fsp->fs_passno == 0)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the specified filesystem.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
checkfilesys(filesys, mntpt, auxdata, child)
|
||||
char *filesys, *mntpt;
|
||||
long auxdata;
|
||||
{
|
||||
daddr_t n_ffree, n_bfree;
|
||||
struct dups *dp;
|
||||
struct zlncnt *zlnp;
|
||||
int cylno;
|
||||
|
||||
if (preen && child)
|
||||
(void)signal(SIGQUIT, voidquit);
|
||||
cdevname = filesys;
|
||||
if (debug && preen)
|
||||
pwarn("starting\n");
|
||||
if (setup(filesys) == 0) {
|
||||
if (preen)
|
||||
pfatal("CAN'T CHECK FILE SYSTEM.");
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* 1: scan inodes tallying blocks used
|
||||
*/
|
||||
if (preen == 0) {
|
||||
printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
|
||||
if (hotroot)
|
||||
printf("** Root file system\n");
|
||||
printf("** Phase 1 - Check Blocks and Sizes\n");
|
||||
}
|
||||
pass1();
|
||||
|
||||
/*
|
||||
* 1b: locate first references to duplicates, if any
|
||||
*/
|
||||
if (duplist) {
|
||||
if (preen)
|
||||
pfatal("INTERNAL ERROR: dups with -p");
|
||||
printf("** Phase 1b - Rescan For More DUPS\n");
|
||||
pass1b();
|
||||
}
|
||||
|
||||
/*
|
||||
* 2: traverse directories from root to mark all connected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 2 - Check Pathnames\n");
|
||||
pass2();
|
||||
|
||||
/*
|
||||
* 3: scan inodes looking for disconnected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 3 - Check Connectivity\n");
|
||||
pass3();
|
||||
|
||||
/*
|
||||
* 4: scan inodes looking for disconnected files; check reference counts
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 4 - Check Reference Counts\n");
|
||||
pass4();
|
||||
|
||||
/*
|
||||
* 5: check and repair resource counts in cylinder groups
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 5 - Check Cyl groups\n");
|
||||
pass5();
|
||||
|
||||
/*
|
||||
* print out summary statistics
|
||||
*/
|
||||
n_ffree = sblock.fs_cstotal.cs_nffree;
|
||||
n_bfree = sblock.fs_cstotal.cs_nbfree;
|
||||
pwarn("%ld files, %ld used, %ld free ",
|
||||
n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
|
||||
printf("(%ld frags, %ld blocks, %d.%d%% fragmentation)\n",
|
||||
n_ffree, n_bfree, (n_ffree * 100) / sblock.fs_dsize,
|
||||
((n_ffree * 1000 + sblock.fs_dsize / 2) / sblock.fs_dsize) % 10);
|
||||
if (debug &&
|
||||
(n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
|
||||
printf("%ld files missing\n", n_files);
|
||||
if (debug) {
|
||||
n_blks += sblock.fs_ncg *
|
||||
(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
|
||||
n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
|
||||
n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
|
||||
printf("%ld blocks missing\n", n_blks);
|
||||
if (duplist != NULL) {
|
||||
printf("The following duplicate blocks remain:");
|
||||
for (dp = duplist; dp; dp = dp->next)
|
||||
printf(" %ld,", dp->dup);
|
||||
printf("\n");
|
||||
}
|
||||
if (zlnhead != NULL) {
|
||||
printf("The following zero link count inodes remain:");
|
||||
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
|
||||
printf(" %lu,", zlnp->zlncnt);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
zlnhead = (struct zlncnt *)0;
|
||||
duplist = (struct dups *)0;
|
||||
muldup = (struct dups *)0;
|
||||
inocleanup();
|
||||
if (fsmodified) {
|
||||
(void)time(&sblock.fs_time);
|
||||
sbdirty();
|
||||
}
|
||||
if (cvtlevel && sblk.b_dirty) {
|
||||
/*
|
||||
* Write out the duplicate super blocks
|
||||
*/
|
||||
for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
|
||||
bwrite(fswritefd, (char *)&sblock,
|
||||
fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE);
|
||||
}
|
||||
ckfini();
|
||||
free(blockmap);
|
||||
free(statemap);
|
||||
free((char *)lncntp);
|
||||
if (!fsmodified)
|
||||
return (0);
|
||||
if (!preen)
|
||||
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
|
||||
if (hotroot) {
|
||||
struct statfs stfs_buf;
|
||||
/*
|
||||
* We modified the root. Do a mount update on
|
||||
* it, unless it is read-write, so we can continue.
|
||||
*/
|
||||
if (statfs("/", &stfs_buf) == 0) {
|
||||
long flags = stfs_buf.f_flags;
|
||||
struct ufs_args args;
|
||||
int ret;
|
||||
|
||||
if (flags & MNT_RDONLY) {
|
||||
args.fspec = 0;
|
||||
args.export.ex_flags = 0;
|
||||
args.export.ex_root = 0;
|
||||
flags |= MNT_UPDATE | MNT_RELOAD;
|
||||
ret = mount(MOUNT_UFS, "/", flags, &args);
|
||||
if (ret == 0)
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (!preen)
|
||||
printf("\n***** REBOOT NOW *****\n");
|
||||
sync();
|
||||
return (4);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
314
sbin/fsck_ffs/pass1.c
Normal file
314
sbin/fsck_ffs/pass1.c
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
static daddr_t badblk;
|
||||
static daddr_t dupblk;
|
||||
int pass1check();
|
||||
struct dinode *getnextinode();
|
||||
|
||||
pass1()
|
||||
{
|
||||
ino_t inumber;
|
||||
int c, i, cgd;
|
||||
struct inodesc idesc;
|
||||
|
||||
/*
|
||||
* Set file system reserved blocks in used block map.
|
||||
*/
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
cgd = cgdmin(&sblock, c);
|
||||
if (c == 0) {
|
||||
i = cgbase(&sblock, c);
|
||||
cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
} else
|
||||
i = cgsblock(&sblock, c);
|
||||
for (; i < cgd; i++)
|
||||
setbmap(i);
|
||||
}
|
||||
/*
|
||||
* Find all allocated blocks.
|
||||
*/
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass1check;
|
||||
inumber = 0;
|
||||
n_files = n_blks = 0;
|
||||
resetinodebuf();
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
|
||||
if (inumber < ROOTINO)
|
||||
continue;
|
||||
checkinode(inumber, &idesc);
|
||||
}
|
||||
}
|
||||
freeinodebuf();
|
||||
}
|
||||
|
||||
checkinode(inumber, idesc)
|
||||
ino_t inumber;
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
struct zlncnt *zlnp;
|
||||
int ndb, j;
|
||||
mode_t mode;
|
||||
char symbuf[MAXSYMLINKLEN];
|
||||
|
||||
dp = getnextinode(inumber);
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == 0) {
|
||||
if (bcmp((char *)dp->di_db, (char *)zino.di_db,
|
||||
NDADDR * sizeof(daddr_t)) ||
|
||||
bcmp((char *)dp->di_ib, (char *)zino.di_ib,
|
||||
NIADDR * sizeof(daddr_t)) ||
|
||||
dp->di_mode || dp->di_size) {
|
||||
pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
|
||||
if (reply("CLEAR") == 1) {
|
||||
dp = ginode(inumber);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
statemap[inumber] = USTATE;
|
||||
return;
|
||||
}
|
||||
lastino = inumber;
|
||||
if (/* dp->di_size < 0 || */
|
||||
dp->di_size + sblock.fs_bsize - 1 < dp->di_size) {
|
||||
if (debug)
|
||||
printf("bad size %qu:", dp->di_size);
|
||||
goto unknown;
|
||||
}
|
||||
if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
|
||||
dp = ginode(inumber);
|
||||
dp->di_size = sblock.fs_fsize;
|
||||
dp->di_mode = IFREG|0600;
|
||||
inodirty();
|
||||
}
|
||||
ndb = howmany(dp->di_size, sblock.fs_bsize);
|
||||
if (ndb < 0) {
|
||||
if (debug)
|
||||
printf("bad size %qu ndb %d:",
|
||||
dp->di_size, ndb);
|
||||
goto unknown;
|
||||
}
|
||||
if (mode == IFBLK || mode == IFCHR)
|
||||
ndb++;
|
||||
if (mode == IFLNK) {
|
||||
if (doinglevel2 &&
|
||||
dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
|
||||
dp->di_blocks != 0) {
|
||||
if (bread(fsreadfd, symbuf,
|
||||
fsbtodb(&sblock, dp->di_db[0]),
|
||||
(long)dp->di_size) != 0)
|
||||
errexit("cannot read symlink");
|
||||
if (debug) {
|
||||
symbuf[dp->di_size] = 0;
|
||||
printf("convert symlink %d(%s) of size %d\n",
|
||||
inumber, symbuf, (long)dp->di_size);
|
||||
}
|
||||
dp = ginode(inumber);
|
||||
bcopy(symbuf, (caddr_t)dp->di_shortlink,
|
||||
(long)dp->di_size);
|
||||
dp->di_blocks = 0;
|
||||
inodirty();
|
||||
}
|
||||
/*
|
||||
* Fake ndb value so direct/indirect block checks below
|
||||
* will detect any garbage after symlink string.
|
||||
*/
|
||||
if (dp->di_size < sblock.fs_maxsymlinklen) {
|
||||
ndb = howmany(dp->di_size, sizeof(daddr_t));
|
||||
if (ndb > NDADDR) {
|
||||
j = ndb - NDADDR;
|
||||
for (ndb = 1; j > 1; j--)
|
||||
ndb *= NINDIR(&sblock);
|
||||
ndb += NDADDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = ndb; j < NDADDR; j++)
|
||||
if (dp->di_db[j] != 0) {
|
||||
if (debug)
|
||||
printf("bad direct addr: %ld\n", dp->di_db[j]);
|
||||
goto unknown;
|
||||
}
|
||||
for (j = 0, ndb -= NDADDR; ndb > 0; j++)
|
||||
ndb /= NINDIR(&sblock);
|
||||
for (; j < NIADDR; j++)
|
||||
if (dp->di_ib[j] != 0) {
|
||||
if (debug)
|
||||
printf("bad indirect addr: %ld\n",
|
||||
dp->di_ib[j]);
|
||||
goto unknown;
|
||||
}
|
||||
if (ftypeok(dp) == 0)
|
||||
goto unknown;
|
||||
n_files++;
|
||||
lncntp[inumber] = dp->di_nlink;
|
||||
if (dp->di_nlink <= 0) {
|
||||
zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
|
||||
if (zlnp == NULL) {
|
||||
pfatal("LINK COUNT TABLE OVERFLOW");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
} else {
|
||||
zlnp->zlncnt = inumber;
|
||||
zlnp->next = zlnhead;
|
||||
zlnhead = zlnp;
|
||||
}
|
||||
}
|
||||
if (mode == IFDIR) {
|
||||
if (dp->di_size == 0)
|
||||
statemap[inumber] = DCLEAR;
|
||||
else
|
||||
statemap[inumber] = DSTATE;
|
||||
cacheino(dp, inumber);
|
||||
} else
|
||||
statemap[inumber] = FSTATE;
|
||||
typemap[inumber] = IFTODT(mode);
|
||||
if (doinglevel2 &&
|
||||
(dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
|
||||
dp = ginode(inumber);
|
||||
dp->di_uid = dp->di_ouid;
|
||||
dp->di_ouid = -1;
|
||||
dp->di_gid = dp->di_ogid;
|
||||
dp->di_ogid = -1;
|
||||
inodirty();
|
||||
}
|
||||
badblk = dupblk = 0;
|
||||
idesc->id_number = inumber;
|
||||
(void)ckinode(dp, idesc);
|
||||
idesc->id_entryno *= btodb(sblock.fs_fsize);
|
||||
if (dp->di_blocks != idesc->id_entryno) {
|
||||
pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
|
||||
inumber, dp->di_blocks, idesc->id_entryno);
|
||||
if (preen)
|
||||
printf(" (CORRECTED)\n");
|
||||
else if (reply("CORRECT") == 0)
|
||||
return;
|
||||
dp = ginode(inumber);
|
||||
dp->di_blocks = idesc->id_entryno;
|
||||
inodirty();
|
||||
}
|
||||
return;
|
||||
unknown:
|
||||
pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
|
||||
statemap[inumber] = FCLEAR;
|
||||
if (reply("CLEAR") == 1) {
|
||||
statemap[inumber] = USTATE;
|
||||
dp = ginode(inumber);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
|
||||
pass1check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
int res = KEEPON;
|
||||
int anyout, nfrags;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
register struct dups *dlp;
|
||||
struct dups *new;
|
||||
|
||||
if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
|
||||
blkerror(idesc->id_number, "BAD", blkno);
|
||||
if (badblk++ >= MAXBAD) {
|
||||
pwarn("EXCESSIVE BAD BLKS I=%lu",
|
||||
idesc->id_number);
|
||||
if (preen)
|
||||
printf(" (SKIPPING)\n");
|
||||
else if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
}
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (anyout && chkrange(blkno, 1)) {
|
||||
res = SKIP;
|
||||
} else if (!testbmap(blkno)) {
|
||||
n_blks++;
|
||||
setbmap(blkno);
|
||||
} else {
|
||||
blkerror(idesc->id_number, "DUP", blkno);
|
||||
if (dupblk++ >= MAXDUP) {
|
||||
pwarn("EXCESSIVE DUP BLKS I=%lu",
|
||||
idesc->id_number);
|
||||
if (preen)
|
||||
printf(" (SKIPPING)\n");
|
||||
else if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
new = (struct dups *)malloc(sizeof(struct dups));
|
||||
if (new == NULL) {
|
||||
pfatal("DUP TABLE OVERFLOW.");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
new->dup = blkno;
|
||||
if (muldup == 0) {
|
||||
duplist = muldup = new;
|
||||
new->next = 0;
|
||||
} else {
|
||||
new->next = muldup->next;
|
||||
muldup->next = new;
|
||||
}
|
||||
for (dlp = duplist; dlp != muldup; dlp = dlp->next)
|
||||
if (dlp->dup == blkno)
|
||||
break;
|
||||
if (dlp == muldup && dlp->dup != blkno)
|
||||
muldup = new;
|
||||
}
|
||||
/*
|
||||
* count the number of blocks found in id_entryno
|
||||
*/
|
||||
idesc->id_entryno++;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
99
sbin/fsck_ffs/pass1b.c
Normal file
99
sbin/fsck_ffs/pass1b.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass1b.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
int pass1bcheck();
|
||||
static struct dups *duphead;
|
||||
|
||||
pass1b()
|
||||
{
|
||||
register int c, i;
|
||||
register struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
ino_t inumber;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass1bcheck;
|
||||
duphead = duplist;
|
||||
inumber = 0;
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
|
||||
if (inumber < ROOTINO)
|
||||
continue;
|
||||
dp = ginode(inumber);
|
||||
if (dp == NULL)
|
||||
continue;
|
||||
idesc.id_number = inumber;
|
||||
if (statemap[inumber] != USTATE &&
|
||||
(ckinode(dp, &idesc) & STOP))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass1bcheck(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (chkrange(blkno, 1))
|
||||
res = SKIP;
|
||||
for (dlp = duphead; dlp; dlp = dlp->next) {
|
||||
if (dlp->dup == blkno) {
|
||||
blkerror(idesc->id_number, "DUP", blkno);
|
||||
dlp->dup = duphead->dup;
|
||||
duphead->dup = blkno;
|
||||
duphead = duphead->next;
|
||||
}
|
||||
if (dlp == muldup)
|
||||
break;
|
||||
}
|
||||
if (muldup == 0 || duphead == muldup->next)
|
||||
return (STOP);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
430
sbin/fsck_ffs/pass2.c
Normal file
430
sbin/fsck_ffs/pass2.c
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass2.c 8.2 (Berkeley) 2/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
#define MINDIRSIZE (sizeof (struct dirtemplate))
|
||||
|
||||
int pass2check(), blksort();
|
||||
|
||||
pass2()
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpend;
|
||||
struct inodesc curino;
|
||||
struct dinode dino;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
switch (statemap[ROOTINO]) {
|
||||
|
||||
case USTATE:
|
||||
pfatal("ROOT INODE UNALLOCATED");
|
||||
if (reply("ALLOCATE") == 0)
|
||||
errexit("");
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
pfatal("DUPS/BAD IN ROOT INODE");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
}
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
break;
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
pfatal("ROOT INODE NOT DIRECTORY");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
}
|
||||
if (reply("FIX") == 0)
|
||||
errexit("");
|
||||
dp = ginode(ROOTINO);
|
||||
dp->di_mode &= ~IFMT;
|
||||
dp->di_mode |= IFDIR;
|
||||
inodirty();
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
|
||||
}
|
||||
statemap[ROOTINO] = DFOUND;
|
||||
/*
|
||||
* Sort the directory list into disk block order.
|
||||
*/
|
||||
qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
|
||||
/*
|
||||
* Check the integrity of each directory.
|
||||
*/
|
||||
bzero((char *)&curino, sizeof(struct inodesc));
|
||||
curino.id_type = DATA;
|
||||
curino.id_func = pass2check;
|
||||
dp = &dino;
|
||||
inpend = &inpsort[inplast];
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_isize == 0)
|
||||
continue;
|
||||
if (inp->i_isize < MINDIRSIZE) {
|
||||
direrror(inp->i_number, "DIRECTORY TOO SHORT");
|
||||
inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
|
||||
if (reply("FIX") == 1) {
|
||||
dp = ginode(inp->i_number);
|
||||
dp->di_size = inp->i_isize;
|
||||
inodirty();
|
||||
dp = &dino;
|
||||
}
|
||||
} else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
|
||||
getpathname(pathbuf, inp->i_number, inp->i_number);
|
||||
pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
|
||||
pathbuf, inp->i_isize, DIRBLKSIZ);
|
||||
if (preen)
|
||||
printf(" (ADJUSTED)\n");
|
||||
inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
|
||||
if (preen || reply("ADJUST") == 1) {
|
||||
dp = ginode(inp->i_number);
|
||||
dp->di_size = roundup(inp->i_isize, DIRBLKSIZ);
|
||||
inodirty();
|
||||
dp = &dino;
|
||||
}
|
||||
}
|
||||
bzero((char *)&dino, sizeof(struct dinode));
|
||||
dino.di_mode = IFDIR;
|
||||
dp->di_size = inp->i_isize;
|
||||
bcopy((char *)&inp->i_blks[0], (char *)&dp->di_db[0],
|
||||
(size_t)inp->i_numblks);
|
||||
curino.id_number = inp->i_number;
|
||||
curino.id_parent = inp->i_parent;
|
||||
(void)ckinode(dp, &curino);
|
||||
}
|
||||
/*
|
||||
* Now that the parents of all directories have been found,
|
||||
* make another pass to verify the value of `..'
|
||||
*/
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0 || inp->i_isize == 0)
|
||||
continue;
|
||||
if (statemap[inp->i_parent] == DFOUND &&
|
||||
statemap[inp->i_number] == DSTATE)
|
||||
statemap[inp->i_number] = DFOUND;
|
||||
if (inp->i_dotdot == inp->i_parent ||
|
||||
inp->i_dotdot == (ino_t)-1)
|
||||
continue;
|
||||
if (inp->i_dotdot == 0) {
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
|
||||
if (reply("FIX") == 0)
|
||||
continue;
|
||||
(void)makeentry(inp->i_number, inp->i_parent, "..");
|
||||
lncntp[inp->i_parent]--;
|
||||
continue;
|
||||
}
|
||||
fileerror(inp->i_parent, inp->i_number,
|
||||
"BAD INODE NUMBER FOR '..'");
|
||||
if (reply("FIX") == 0)
|
||||
continue;
|
||||
lncntp[inp->i_dotdot]++;
|
||||
lncntp[inp->i_parent]--;
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
(void)changeino(inp->i_number, "..", inp->i_parent);
|
||||
}
|
||||
/*
|
||||
* Mark all the directories that can be found from the root.
|
||||
*/
|
||||
propagate();
|
||||
}
|
||||
|
||||
pass2check(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
register struct inoinfo *inp;
|
||||
int n, entrysize, ret = 0;
|
||||
struct dinode *dp;
|
||||
char *errmsg;
|
||||
struct direct proto;
|
||||
char namebuf[MAXPATHLEN + 1];
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
/*
|
||||
* If converting, set directory entry type.
|
||||
*/
|
||||
if (doinglevel2 && dirp->d_ino > 0 && dirp->d_ino < maxino) {
|
||||
dirp->d_type = typemap[dirp->d_ino];
|
||||
ret |= ALTERED;
|
||||
}
|
||||
/*
|
||||
* check for "."
|
||||
*/
|
||||
if (idesc->id_entryno != 0)
|
||||
goto chk1;
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
|
||||
if (dirp->d_ino != idesc->id_number) {
|
||||
direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
|
||||
dirp->d_ino = idesc->id_number;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
if (newinofmt && dirp->d_type != DT_DIR) {
|
||||
direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
|
||||
dirp->d_type = DT_DIR;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
goto chk1;
|
||||
}
|
||||
direrror(idesc->id_number, "MISSING '.'");
|
||||
proto.d_ino = idesc->id_number;
|
||||
if (newinofmt)
|
||||
proto.d_type = DT_DIR;
|
||||
else
|
||||
proto.d_type = 0;
|
||||
proto.d_namlen = 1;
|
||||
(void)strcpy(proto.d_name, ".");
|
||||
entrysize = DIRSIZ(0, &proto);
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
|
||||
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||
dirp->d_name);
|
||||
} 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, (size_t)entrysize);
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
} else {
|
||||
n = dirp->d_reclen - entrysize;
|
||||
proto.d_reclen = entrysize;
|
||||
bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
|
||||
idesc->id_entryno++;
|
||||
lncntp[dirp->d_ino]--;
|
||||
dirp = (struct direct *)((char *)(dirp) + entrysize);
|
||||
bzero((char *)dirp, (size_t)n);
|
||||
dirp->d_reclen = n;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
chk1:
|
||||
if (idesc->id_entryno > 1)
|
||||
goto chk2;
|
||||
inp = getinoinfo(idesc->id_number);
|
||||
proto.d_ino = inp->i_parent;
|
||||
if (newinofmt)
|
||||
proto.d_type = DT_DIR;
|
||||
else
|
||||
proto.d_type = 0;
|
||||
proto.d_namlen = 2;
|
||||
(void)strcpy(proto.d_name, "..");
|
||||
entrysize = DIRSIZ(0, &proto);
|
||||
if (idesc->id_entryno == 0) {
|
||||
n = DIRSIZ(0, dirp);
|
||||
if (dirp->d_reclen < n + entrysize)
|
||||
goto chk2;
|
||||
proto.d_reclen = dirp->d_reclen - n;
|
||||
dirp->d_reclen = n;
|
||||
idesc->id_entryno++;
|
||||
lncntp[dirp->d_ino]--;
|
||||
dirp = (struct direct *)((char *)(dirp) + n);
|
||||
bzero((char *)dirp, (size_t)proto.d_reclen);
|
||||
dirp->d_reclen = proto.d_reclen;
|
||||
}
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
|
||||
inp->i_dotdot = dirp->d_ino;
|
||||
if (newinofmt && dirp->d_type != DT_DIR) {
|
||||
direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
|
||||
dirp->d_type = DT_DIR;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
goto chk2;
|
||||
}
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||
dirp->d_name);
|
||||
inp->i_dotdot = (ino_t)-1;
|
||||
} else if (dirp->d_reclen < entrysize) {
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
|
||||
inp->i_dotdot = (ino_t)-1;
|
||||
} else if (inp->i_parent != 0) {
|
||||
/*
|
||||
* We know the parent, so fix now.
|
||||
*/
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
proto.d_reclen = dirp->d_reclen;
|
||||
bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
idesc->id_entryno++;
|
||||
if (dirp->d_ino != 0)
|
||||
lncntp[dirp->d_ino]--;
|
||||
return (ret|KEEPON);
|
||||
chk2:
|
||||
if (dirp->d_ino == 0)
|
||||
return (ret|KEEPON);
|
||||
if (dirp->d_namlen <= 2 &&
|
||||
dirp->d_name[0] == '.' &&
|
||||
idesc->id_entryno >= 2) {
|
||||
if (dirp->d_namlen == 1) {
|
||||
direrror(idesc->id_number, "EXTRA '.' ENTRY");
|
||||
dirp->d_ino = 0;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
return (KEEPON | ret);
|
||||
}
|
||||
if (dirp->d_name[1] == '.') {
|
||||
direrror(idesc->id_number, "EXTRA '..' ENTRY");
|
||||
dirp->d_ino = 0;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
return (KEEPON | ret);
|
||||
}
|
||||
}
|
||||
idesc->id_entryno++;
|
||||
n = 0;
|
||||
if (dirp->d_ino > maxino) {
|
||||
fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
|
||||
n = reply("REMOVE");
|
||||
} else {
|
||||
again:
|
||||
switch (statemap[dirp->d_ino]) {
|
||||
case USTATE:
|
||||
if (idesc->id_entryno <= 2)
|
||||
break;
|
||||
fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
|
||||
n = reply("REMOVE");
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
case FCLEAR:
|
||||
if (idesc->id_entryno <= 2)
|
||||
break;
|
||||
if (statemap[dirp->d_ino] == FCLEAR)
|
||||
errmsg = "DUP/BAD";
|
||||
else if (!preen)
|
||||
errmsg = "ZERO LENGTH DIRECTORY";
|
||||
else {
|
||||
n = 1;
|
||||
break;
|
||||
}
|
||||
fileerror(idesc->id_number, dirp->d_ino, errmsg);
|
||||
if ((n = reply("REMOVE")) == 1)
|
||||
break;
|
||||
dp = ginode(dirp->d_ino);
|
||||
statemap[dirp->d_ino] =
|
||||
(dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
|
||||
lncntp[dirp->d_ino] = dp->di_nlink;
|
||||
goto again;
|
||||
|
||||
case DSTATE:
|
||||
if (statemap[idesc->id_number] == DFOUND)
|
||||
statemap[dirp->d_ino] = DFOUND;
|
||||
/* fall through */
|
||||
|
||||
case DFOUND:
|
||||
inp = getinoinfo(dirp->d_ino);
|
||||
if (inp->i_parent != 0 && idesc->id_entryno > 2) {
|
||||
getpathname(pathbuf, idesc->id_number,
|
||||
idesc->id_number);
|
||||
getpathname(namebuf, dirp->d_ino, dirp->d_ino);
|
||||
pwarn("%s %s %s\n", pathbuf,
|
||||
"IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
|
||||
namebuf);
|
||||
if (preen)
|
||||
printf(" (IGNORED)\n");
|
||||
else if ((n = reply("REMOVE")) == 1)
|
||||
break;
|
||||
}
|
||||
if (idesc->id_entryno > 2)
|
||||
inp->i_parent = idesc->id_number;
|
||||
/* fall through */
|
||||
|
||||
case FSTATE:
|
||||
if (newinofmt && dirp->d_type != typemap[dirp->d_ino]) {
|
||||
fileerror(idesc->id_number, dirp->d_ino,
|
||||
"BAD TYPE VALUE");
|
||||
dirp->d_type = typemap[dirp->d_ino];
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
lncntp[dirp->d_ino]--;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[dirp->d_ino], dirp->d_ino);
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
return (ret|KEEPON);
|
||||
dirp->d_ino = 0;
|
||||
return (ret|KEEPON|ALTERED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to sort disk blocks.
|
||||
*/
|
||||
blksort(inpp1, inpp2)
|
||||
struct inoinfo **inpp1, **inpp2;
|
||||
{
|
||||
|
||||
return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]);
|
||||
}
|
||||
71
sbin/fsck_ffs/pass3.c
Normal file
71
sbin/fsck_ffs/pass3.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass3.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include "fsck.h"
|
||||
|
||||
pass3()
|
||||
{
|
||||
register struct inoinfo **inpp, *inp;
|
||||
ino_t orphan;
|
||||
int loopcnt;
|
||||
|
||||
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
|
||||
inp = *inpp;
|
||||
if (inp->i_number == ROOTINO ||
|
||||
!(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE))
|
||||
continue;
|
||||
if (statemap[inp->i_number] == DCLEAR)
|
||||
continue;
|
||||
for (loopcnt = 0; ; loopcnt++) {
|
||||
orphan = inp->i_number;
|
||||
if (inp->i_parent == 0 ||
|
||||
statemap[inp->i_parent] != DSTATE ||
|
||||
loopcnt > numdirs)
|
||||
break;
|
||||
inp = getinoinfo(inp->i_parent);
|
||||
}
|
||||
(void)linkup(orphan, inp->i_dotdot);
|
||||
inp->i_parent = inp->i_dotdot = lfdir;
|
||||
lncntp[lfdir]--;
|
||||
statemap[orphan] = DFOUND;
|
||||
propagate();
|
||||
}
|
||||
}
|
||||
133
sbin/fsck_ffs/pass4.c
Normal file
133
sbin/fsck_ffs/pass4.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass4.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
int pass4check();
|
||||
|
||||
pass4()
|
||||
{
|
||||
register ino_t inumber;
|
||||
register struct zlncnt *zlnp;
|
||||
struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
int n;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
for (inumber = ROOTINO; inumber <= lastino; inumber++) {
|
||||
idesc.id_number = inumber;
|
||||
switch (statemap[inumber]) {
|
||||
|
||||
case FSTATE:
|
||||
case DFOUND:
|
||||
n = lncntp[inumber];
|
||||
if (n)
|
||||
adjust(&idesc, (short)n);
|
||||
else {
|
||||
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
|
||||
if (zlnp->zlncnt == inumber) {
|
||||
zlnp->zlncnt = zlnhead->zlncnt;
|
||||
zlnp = zlnhead;
|
||||
zlnhead = zlnhead->next;
|
||||
free((char *)zlnp);
|
||||
clri(&idesc, "UNREF", 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
clri(&idesc, "UNREF", 1);
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
dp = ginode(inumber);
|
||||
if (dp->di_size == 0) {
|
||||
clri(&idesc, "ZERO LENGTH", 1);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case FCLEAR:
|
||||
clri(&idesc, "BAD/DUP", 1);
|
||||
break;
|
||||
|
||||
case USTATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[inumber], inumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass4check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (chkrange(blkno, 1)) {
|
||||
res = SKIP;
|
||||
} else if (testbmap(blkno)) {
|
||||
for (dlp = duplist; dlp; dlp = dlp->next) {
|
||||
if (dlp->dup != blkno)
|
||||
continue;
|
||||
dlp->dup = duplist->dup;
|
||||
dlp = duplist;
|
||||
duplist = duplist->next;
|
||||
free((char *)dlp);
|
||||
break;
|
||||
}
|
||||
if (dlp == 0) {
|
||||
clrbmap(blkno);
|
||||
n_blks--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
319
sbin/fsck_ffs/pass5.c
Normal file
319
sbin/fsck_ffs/pass5.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass5.c 8.2 (Berkeley) 2/2/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
pass5()
|
||||
{
|
||||
int c, blk, frags, basesize, sumsize, mapsize, savednrpos;
|
||||
register struct fs *fs = &sblock;
|
||||
register struct cg *cg = &cgrp;
|
||||
daddr_t dbase, dmax;
|
||||
register daddr_t d;
|
||||
register long i, j;
|
||||
struct csum *cs;
|
||||
struct csum cstotal;
|
||||
struct inodesc idesc[3];
|
||||
char buf[MAXBSIZE];
|
||||
register struct cg *newcg = (struct cg *)buf;
|
||||
struct ocg *ocg = (struct ocg *)buf;
|
||||
|
||||
bzero((char *)newcg, (size_t)fs->fs_cgsize);
|
||||
newcg->cg_niblk = fs->fs_ipg;
|
||||
if (cvtlevel > 3) {
|
||||
if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) {
|
||||
if (preen)
|
||||
pwarn("DELETING CLUSTERING MAPS\n");
|
||||
if (preen || reply("DELETE CLUSTERING MAPS")) {
|
||||
fs->fs_contigsumsize = 0;
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_maxcontig > 1) {
|
||||
char *doit = 0;
|
||||
|
||||
if (fs->fs_contigsumsize < 1) {
|
||||
doit = "CREAT";
|
||||
} else if (fs->fs_contigsumsize < fs->fs_maxcontig &&
|
||||
fs->fs_contigsumsize < FS_MAXCONTIG) {
|
||||
doit = "EXPAND";
|
||||
}
|
||||
if (doit) {
|
||||
i = fs->fs_contigsumsize;
|
||||
fs->fs_contigsumsize =
|
||||
MIN(fs->fs_maxcontig, FS_MAXCONTIG);
|
||||
if (CGSIZE(fs) > fs->fs_bsize) {
|
||||
pwarn("CANNOT %s CLUSTER MAPS\n", doit);
|
||||
fs->fs_contigsumsize = i;
|
||||
} else if (preen ||
|
||||
reply("CREATE CLUSTER MAPS")) {
|
||||
if (preen)
|
||||
pwarn("%sING CLUSTER MAPS\n",
|
||||
doit);
|
||||
fs->fs_cgsize =
|
||||
fragroundup(fs, CGSIZE(fs));
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch ((int)fs->fs_postblformat) {
|
||||
|
||||
case FS_42POSTBLFMT:
|
||||
basesize = (char *)(&ocg->cg_btot[0]) - (char *)(&ocg->cg_link);
|
||||
sumsize = &ocg->cg_iused[0] - (char *)(&ocg->cg_btot[0]);
|
||||
mapsize = &ocg->cg_free[howmany(fs->fs_fpg, NBBY)] -
|
||||
(u_char *)&ocg->cg_iused[0];
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
savednrpos = fs->fs_nrpos;
|
||||
fs->fs_nrpos = 8;
|
||||
break;
|
||||
|
||||
case FS_DYNAMICPOSTBLFMT:
|
||||
newcg->cg_btotoff =
|
||||
&newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
|
||||
newcg->cg_boff =
|
||||
newcg->cg_btotoff + fs->fs_cpg * sizeof(long);
|
||||
newcg->cg_iusedoff = newcg->cg_boff +
|
||||
fs->fs_cpg * fs->fs_nrpos * sizeof(short);
|
||||
newcg->cg_freeoff =
|
||||
newcg->cg_iusedoff + howmany(fs->fs_ipg, NBBY);
|
||||
if (fs->fs_contigsumsize <= 0) {
|
||||
newcg->cg_nextfreeoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY);
|
||||
} else {
|
||||
newcg->cg_clustersumoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY) -
|
||||
sizeof(long);
|
||||
newcg->cg_clustersumoff =
|
||||
roundup(newcg->cg_clustersumoff, sizeof(long));
|
||||
newcg->cg_clusteroff = newcg->cg_clustersumoff +
|
||||
(fs->fs_contigsumsize + 1) * sizeof(long);
|
||||
newcg->cg_nextfreeoff = newcg->cg_clusteroff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPB(fs), NBBY);
|
||||
}
|
||||
newcg->cg_magic = CG_MAGIC;
|
||||
basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
|
||||
sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
|
||||
mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("UNKNOWN ROTATIONAL TABLE FORMAT %d\n",
|
||||
fs->fs_postblformat);
|
||||
}
|
||||
bzero((char *)&idesc[0], sizeof idesc);
|
||||
for (i = 0; i < 3; i++) {
|
||||
idesc[i].id_type = ADDR;
|
||||
if (doinglevel2)
|
||||
idesc[i].id_fix = FIX;
|
||||
}
|
||||
bzero((char *)&cstotal, sizeof(struct csum));
|
||||
j = blknum(fs, fs->fs_size + fs->fs_frag - 1);
|
||||
for (i = fs->fs_size; i < j; i++)
|
||||
setbmap(i);
|
||||
for (c = 0; c < fs->fs_ncg; c++) {
|
||||
getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize);
|
||||
if (!cg_chkmagic(cg))
|
||||
pfatal("CG %d: BAD MAGIC NUMBER\n", c);
|
||||
dbase = cgbase(fs, c);
|
||||
dmax = dbase + fs->fs_fpg;
|
||||
if (dmax > fs->fs_size)
|
||||
dmax = fs->fs_size;
|
||||
newcg->cg_time = cg->cg_time;
|
||||
newcg->cg_cgx = c;
|
||||
if (c == fs->fs_ncg - 1)
|
||||
newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg;
|
||||
else
|
||||
newcg->cg_ncyl = fs->fs_cpg;
|
||||
newcg->cg_ndblk = dmax - dbase;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
|
||||
newcg->cg_cs.cs_ndir = 0;
|
||||
newcg->cg_cs.cs_nffree = 0;
|
||||
newcg->cg_cs.cs_nbfree = 0;
|
||||
newcg->cg_cs.cs_nifree = fs->fs_ipg;
|
||||
if (cg->cg_rotor < newcg->cg_ndblk)
|
||||
newcg->cg_rotor = cg->cg_rotor;
|
||||
else
|
||||
newcg->cg_rotor = 0;
|
||||
if (cg->cg_frotor < newcg->cg_ndblk)
|
||||
newcg->cg_frotor = cg->cg_frotor;
|
||||
else
|
||||
newcg->cg_frotor = 0;
|
||||
if (cg->cg_irotor < newcg->cg_niblk)
|
||||
newcg->cg_irotor = cg->cg_irotor;
|
||||
else
|
||||
newcg->cg_irotor = 0;
|
||||
bzero((char *)&newcg->cg_frsum[0], sizeof newcg->cg_frsum);
|
||||
bzero((char *)&cg_blktot(newcg)[0],
|
||||
(size_t)(sumsize + mapsize));
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
j = fs->fs_ipg * c;
|
||||
for (i = 0; i < fs->fs_ipg; j++, i++) {
|
||||
switch (statemap[j]) {
|
||||
|
||||
case USTATE:
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
case DCLEAR:
|
||||
case DFOUND:
|
||||
newcg->cg_cs.cs_ndir++;
|
||||
/* fall through */
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
setbit(cg_inosused(newcg), i);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (j < ROOTINO)
|
||||
break;
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[j], j);
|
||||
}
|
||||
}
|
||||
if (c == 0)
|
||||
for (i = 0; i < ROOTINO; i++) {
|
||||
setbit(cg_inosused(newcg), i);
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
}
|
||||
for (i = 0, d = dbase;
|
||||
d < dmax;
|
||||
d += fs->fs_frag, i += fs->fs_frag) {
|
||||
frags = 0;
|
||||
for (j = 0; j < fs->fs_frag; j++) {
|
||||
if (testbmap(d + j))
|
||||
continue;
|
||||
setbit(cg_blksfree(newcg), i + j);
|
||||
frags++;
|
||||
}
|
||||
if (frags == fs->fs_frag) {
|
||||
newcg->cg_cs.cs_nbfree++;
|
||||
j = cbtocylno(fs, i);
|
||||
cg_blktot(newcg)[j]++;
|
||||
cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
setbit(cg_clustersfree(newcg),
|
||||
i / fs->fs_frag);
|
||||
} else if (frags > 0) {
|
||||
newcg->cg_cs.cs_nffree += frags;
|
||||
blk = blkmap(fs, cg_blksfree(newcg), i);
|
||||
ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
|
||||
}
|
||||
}
|
||||
if (fs->fs_contigsumsize > 0) {
|
||||
long *sump = cg_clustersum(newcg);
|
||||
u_char *mapp = cg_clustersfree(newcg);
|
||||
int map = *mapp++;
|
||||
int bit = 1;
|
||||
int run = 0;
|
||||
|
||||
for (i = 0; i < newcg->cg_nclusterblks; i++) {
|
||||
if ((map & bit) != 0) {
|
||||
run++;
|
||||
} else if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
run = 0;
|
||||
}
|
||||
if ((i & (NBBY - 1)) != (NBBY - 1)) {
|
||||
bit <<= 1;
|
||||
} else {
|
||||
map = *mapp++;
|
||||
bit = 1;
|
||||
}
|
||||
}
|
||||
if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
}
|
||||
}
|
||||
cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
|
||||
cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
|
||||
cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
|
||||
cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
|
||||
cs = &fs->fs_cs(fs, c);
|
||||
if (bcmp((char *)&newcg->cg_cs, (char *)cs, sizeof *cs) != 0 &&
|
||||
dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
bcopy((char *)&newcg->cg_cs, (char *)cs, sizeof *cs);
|
||||
sbdirty();
|
||||
}
|
||||
if (doinglevel1) {
|
||||
bcopy((char *)newcg, (char *)cg, (size_t)fs->fs_cgsize);
|
||||
cgdirty();
|
||||
continue;
|
||||
}
|
||||
if (bcmp(cg_inosused(newcg),
|
||||
cg_inosused(cg), mapsize) != 0 &&
|
||||
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
|
||||
bcopy(cg_inosused(newcg), cg_inosused(cg),
|
||||
(size_t)mapsize);
|
||||
cgdirty();
|
||||
}
|
||||
if ((bcmp((char *)newcg, (char *)cg, basesize) != 0 ||
|
||||
bcmp((char *)&cg_blktot(newcg)[0],
|
||||
(char *)&cg_blktot(cg)[0], sumsize) != 0) &&
|
||||
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
|
||||
bcopy((char *)newcg, (char *)cg, (size_t)basesize);
|
||||
bcopy((char *)&cg_blktot(newcg)[0],
|
||||
(char *)&cg_blktot(cg)[0], (size_t)sumsize);
|
||||
cgdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
fs->fs_nrpos = savednrpos;
|
||||
if (bcmp((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs) != 0
|
||||
&& dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
bcopy((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs);
|
||||
fs->fs_ronly = 0;
|
||||
fs->fs_fmod = 0;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
354
sbin/fsck_ffs/preen.c
Normal file
354
sbin/fsck_ffs/preen.c
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)preen.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fstab.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
char *rawname(), *unrawname(), *blockcheck();
|
||||
|
||||
struct part {
|
||||
struct part *next; /* forward link of partitions on disk */
|
||||
char *name; /* device name */
|
||||
char *fsname; /* mounted filesystem name */
|
||||
long auxdata; /* auxillary data for application */
|
||||
} *badlist, **badnext = &badlist;
|
||||
|
||||
struct disk {
|
||||
char *name; /* disk base name */
|
||||
struct disk *next; /* forward link for list of disks */
|
||||
struct part *part; /* head of list of partitions on disk */
|
||||
int pid; /* If != 0, pid of proc working on */
|
||||
} *disks;
|
||||
|
||||
int nrun, ndisks;
|
||||
char hotroot;
|
||||
|
||||
checkfstab(preen, maxrun, docheck, chkit)
|
||||
int preen, maxrun;
|
||||
int (*docheck)(), (*chkit)();
|
||||
{
|
||||
register struct fstab *fsp;
|
||||
register struct disk *dk, *nextdisk;
|
||||
register struct part *pt;
|
||||
int ret, pid, retcode, passno, sumstatus, status;
|
||||
long auxdata;
|
||||
char *name;
|
||||
|
||||
sumstatus = 0;
|
||||
for (passno = 1; passno <= 2; passno++) {
|
||||
if (setfsent() == 0) {
|
||||
fprintf(stderr, "Can't open checklist file: %s\n",
|
||||
_PATH_FSTAB);
|
||||
return (8);
|
||||
}
|
||||
while ((fsp = getfsent()) != 0) {
|
||||
if ((auxdata = (*docheck)(fsp)) == 0)
|
||||
continue;
|
||||
if (preen == 0 || passno == 1 && fsp->fs_passno == 1) {
|
||||
if (name = blockcheck(fsp->fs_spec)) {
|
||||
if (sumstatus = (*chkit)(name,
|
||||
fsp->fs_file, auxdata, 0))
|
||||
return (sumstatus);
|
||||
} else if (preen)
|
||||
return (8);
|
||||
} else if (passno == 2 && fsp->fs_passno > 1) {
|
||||
if ((name = blockcheck(fsp->fs_spec)) == NULL) {
|
||||
fprintf(stderr, "BAD DISK NAME %s\n",
|
||||
fsp->fs_spec);
|
||||
sumstatus |= 8;
|
||||
continue;
|
||||
}
|
||||
addpart(name, fsp->fs_file, auxdata);
|
||||
}
|
||||
}
|
||||
if (preen == 0)
|
||||
return (0);
|
||||
}
|
||||
if (preen) {
|
||||
if (maxrun == 0)
|
||||
maxrun = ndisks;
|
||||
if (maxrun > ndisks)
|
||||
maxrun = ndisks;
|
||||
nextdisk = disks;
|
||||
for (passno = 0; passno < maxrun; ++passno) {
|
||||
while (ret = startdisk(nextdisk, chkit) && nrun > 0)
|
||||
sleep(10);
|
||||
if (ret)
|
||||
return (ret);
|
||||
nextdisk = nextdisk->next;
|
||||
}
|
||||
while ((pid = wait(&status)) != -1) {
|
||||
for (dk = disks; dk; dk = dk->next)
|
||||
if (dk->pid == pid)
|
||||
break;
|
||||
if (dk == 0) {
|
||||
printf("Unknown pid %d\n", pid);
|
||||
continue;
|
||||
}
|
||||
if (WIFEXITED(status))
|
||||
retcode = WEXITSTATUS(status);
|
||||
else
|
||||
retcode = 0;
|
||||
if (WIFSIGNALED(status)) {
|
||||
printf("%s (%s): EXITED WITH SIGNAL %d\n",
|
||||
dk->part->name, dk->part->fsname,
|
||||
WTERMSIG(status));
|
||||
retcode = 8;
|
||||
}
|
||||
if (retcode != 0) {
|
||||
sumstatus |= retcode;
|
||||
*badnext = dk->part;
|
||||
badnext = &dk->part->next;
|
||||
dk->part = dk->part->next;
|
||||
*badnext = NULL;
|
||||
} else
|
||||
dk->part = dk->part->next;
|
||||
dk->pid = 0;
|
||||
nrun--;
|
||||
if (dk->part == NULL)
|
||||
ndisks--;
|
||||
|
||||
if (nextdisk == NULL) {
|
||||
if (dk->part) {
|
||||
while (ret = startdisk(dk, chkit) &&
|
||||
nrun > 0)
|
||||
sleep(10);
|
||||
if (ret)
|
||||
return (ret);
|
||||
}
|
||||
} else if (nrun < maxrun && nrun < ndisks) {
|
||||
for ( ;; ) {
|
||||
if ((nextdisk = nextdisk->next) == NULL)
|
||||
nextdisk = disks;
|
||||
if (nextdisk->part != NULL &&
|
||||
nextdisk->pid == 0)
|
||||
break;
|
||||
}
|
||||
while (ret = startdisk(nextdisk, chkit) &&
|
||||
nrun > 0)
|
||||
sleep(10);
|
||||
if (ret)
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sumstatus) {
|
||||
if (badlist == 0)
|
||||
return (sumstatus);
|
||||
fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
|
||||
badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
|
||||
for (pt = badlist; pt; pt = pt->next)
|
||||
fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname,
|
||||
pt->next ? ", " : "\n");
|
||||
return (sumstatus);
|
||||
}
|
||||
(void)endfsent();
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct disk *
|
||||
finddisk(name)
|
||||
char *name;
|
||||
{
|
||||
register struct disk *dk, **dkp;
|
||||
register char *p;
|
||||
size_t len;
|
||||
|
||||
for (p = name + strlen(name) - 1; p >= name; --p)
|
||||
if (isdigit(*p)) {
|
||||
len = p - name + 1;
|
||||
break;
|
||||
}
|
||||
if (p < name)
|
||||
len = strlen(name);
|
||||
|
||||
for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
|
||||
if (strncmp(dk->name, name, len) == 0 &&
|
||||
dk->name[len] == 0)
|
||||
return (dk);
|
||||
}
|
||||
if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
dk = *dkp;
|
||||
if ((dk->name = malloc(len + 1)) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
(void)strncpy(dk->name, name, len);
|
||||
dk->name[len] = '\0';
|
||||
dk->part = NULL;
|
||||
dk->next = NULL;
|
||||
dk->pid = 0;
|
||||
ndisks++;
|
||||
return (dk);
|
||||
}
|
||||
|
||||
addpart(name, fsname, auxdata)
|
||||
char *name, *fsname;
|
||||
long auxdata;
|
||||
{
|
||||
struct disk *dk = finddisk(name);
|
||||
register struct part *pt, **ppt = &dk->part;
|
||||
|
||||
for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
|
||||
if (strcmp(pt->name, name) == 0) {
|
||||
printf("%s in fstab more than once!\n", name);
|
||||
return;
|
||||
}
|
||||
if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
pt = *ppt;
|
||||
if ((pt->name = malloc(strlen(name) + 1)) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
(void)strcpy(pt->name, name);
|
||||
if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit (8);
|
||||
}
|
||||
(void)strcpy(pt->fsname, fsname);
|
||||
pt->next = NULL;
|
||||
pt->auxdata = auxdata;
|
||||
}
|
||||
|
||||
startdisk(dk, checkit)
|
||||
register struct disk *dk;
|
||||
int (*checkit)();
|
||||
{
|
||||
register struct part *pt = dk->part;
|
||||
|
||||
dk->pid = fork();
|
||||
if (dk->pid < 0) {
|
||||
perror("fork");
|
||||
return (8);
|
||||
}
|
||||
if (dk->pid == 0)
|
||||
exit((*checkit)(pt->name, pt->fsname, pt->auxdata, 1));
|
||||
nrun++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
blockcheck(name)
|
||||
char *name;
|
||||
{
|
||||
struct stat stslash, stblock, stchar;
|
||||
char *raw;
|
||||
int retried = 0;
|
||||
|
||||
hotroot = 0;
|
||||
if (stat("/", &stslash) < 0) {
|
||||
perror("/");
|
||||
printf("Can't stat root\n");
|
||||
return (0);
|
||||
}
|
||||
retry:
|
||||
if (stat(name, &stblock) < 0) {
|
||||
perror(name);
|
||||
printf("Can't stat %s\n", name);
|
||||
return (0);
|
||||
}
|
||||
if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
|
||||
if (stslash.st_dev == stblock.st_rdev)
|
||||
hotroot++;
|
||||
raw = rawname(name);
|
||||
if (stat(raw, &stchar) < 0) {
|
||||
perror(raw);
|
||||
printf("Can't stat %s\n", raw);
|
||||
return (name);
|
||||
}
|
||||
if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
|
||||
return (raw);
|
||||
} else {
|
||||
printf("%s is not a character device\n", raw);
|
||||
return (name);
|
||||
}
|
||||
} else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
|
||||
name = unrawname(name);
|
||||
retried++;
|
||||
goto retry;
|
||||
}
|
||||
printf("Can't make sense out of name %s\n", name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
unrawname(name)
|
||||
char *name;
|
||||
{
|
||||
char *dp;
|
||||
struct stat stb;
|
||||
|
||||
if ((dp = rindex(name, '/')) == 0)
|
||||
return (name);
|
||||
if (stat(name, &stb) < 0)
|
||||
return (name);
|
||||
if ((stb.st_mode & S_IFMT) != S_IFCHR)
|
||||
return (name);
|
||||
if (dp[1] != 'r')
|
||||
return (name);
|
||||
(void)strcpy(&dp[1], &dp[2]);
|
||||
return (name);
|
||||
}
|
||||
|
||||
char *
|
||||
rawname(name)
|
||||
char *name;
|
||||
{
|
||||
static char rawbuf[32];
|
||||
char *dp;
|
||||
|
||||
if ((dp = rindex(name, '/')) == 0)
|
||||
return (0);
|
||||
*dp = 0;
|
||||
(void)strcpy(rawbuf, name);
|
||||
*dp = '/';
|
||||
(void)strcat(rawbuf, "/r");
|
||||
(void)strcat(rawbuf, &dp[1]);
|
||||
return (rawbuf);
|
||||
}
|
||||
466
sbin/fsck_ffs/setup.c
Normal file
466
sbin/fsck_ffs/setup.c
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)setup.c 8.2 (Berkeley) 2/21/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#define DKTYPENAMES
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/file.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "fsck.h"
|
||||
|
||||
struct bufarea asblk;
|
||||
#define altsblock (*asblk.b_un.b_fs)
|
||||
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
|
||||
|
||||
struct disklabel *getdisklabel();
|
||||
|
||||
setup(dev)
|
||||
char *dev;
|
||||
{
|
||||
long cg, size, asked, i, j;
|
||||
long bmapsize;
|
||||
struct disklabel *lp;
|
||||
off_t sizepb;
|
||||
struct stat statb;
|
||||
struct fs proto;
|
||||
|
||||
havesb = 0;
|
||||
fswritefd = -1;
|
||||
if (stat(dev, &statb) < 0) {
|
||||
printf("Can't stat %s: %s\n", dev, strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
if ((statb.st_mode & S_IFMT) != S_IFCHR) {
|
||||
pfatal("%s is not a character device", dev);
|
||||
if (reply("CONTINUE") == 0)
|
||||
return (0);
|
||||
}
|
||||
if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
|
||||
printf("Can't open %s: %s\n", dev, strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("** %s", dev);
|
||||
if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
|
||||
fswritefd = -1;
|
||||
if (preen)
|
||||
pfatal("NO WRITE ACCESS");
|
||||
printf(" (NO WRITE)");
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
fsmodified = 0;
|
||||
lfdir = 0;
|
||||
initbarea(&sblk);
|
||||
initbarea(&asblk);
|
||||
sblk.b_un.b_buf = malloc(SBSIZE);
|
||||
asblk.b_un.b_buf = malloc(SBSIZE);
|
||||
if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
|
||||
errexit("cannot allocate space for superblock\n");
|
||||
if (lp = getdisklabel((char *)NULL, fsreadfd))
|
||||
dev_bsize = secsize = lp->d_secsize;
|
||||
else
|
||||
dev_bsize = secsize = DEV_BSIZE;
|
||||
/*
|
||||
* Read in the superblock, looking for alternates if necessary
|
||||
*/
|
||||
if (readsb(1) == 0) {
|
||||
if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
|
||||
return(0);
|
||||
if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
|
||||
return (0);
|
||||
for (cg = 0; cg < proto.fs_ncg; cg++) {
|
||||
bflag = fsbtodb(&proto, cgsblock(&proto, cg));
|
||||
if (readsb(0) != 0)
|
||||
break;
|
||||
}
|
||||
if (cg >= proto.fs_ncg) {
|
||||
printf("%s %s\n%s %s\n%s %s\n",
|
||||
"SEARCH FOR ALTERNATE SUPER-BLOCK",
|
||||
"FAILED. YOU MUST USE THE",
|
||||
"-b OPTION TO FSCK TO SPECIFY THE",
|
||||
"LOCATION OF AN ALTERNATE",
|
||||
"SUPER-BLOCK TO SUPPLY NEEDED",
|
||||
"INFORMATION; SEE fsck(8).");
|
||||
return(0);
|
||||
}
|
||||
pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
|
||||
}
|
||||
maxfsblock = sblock.fs_size;
|
||||
maxino = sblock.fs_ncg * sblock.fs_ipg;
|
||||
/*
|
||||
* Check and potentially fix certain fields in the super block.
|
||||
*/
|
||||
if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
|
||||
pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
|
||||
if (reply("SET TO DEFAULT") == 1) {
|
||||
sblock.fs_optim = FS_OPTTIME;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
|
||||
pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
|
||||
sblock.fs_minfree);
|
||||
if (reply("SET TO DEFAULT") == 1) {
|
||||
sblock.fs_minfree = 10;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
if (sblock.fs_interleave < 1 ||
|
||||
sblock.fs_interleave > sblock.fs_nsect) {
|
||||
pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
|
||||
sblock.fs_interleave);
|
||||
sblock.fs_interleave = 1;
|
||||
if (preen)
|
||||
printf(" (FIXED)\n");
|
||||
if (preen || reply("SET TO DEFAULT") == 1) {
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
}
|
||||
if (sblock.fs_npsect < sblock.fs_nsect ||
|
||||
sblock.fs_npsect > sblock.fs_nsect*2) {
|
||||
pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
|
||||
sblock.fs_npsect);
|
||||
sblock.fs_npsect = sblock.fs_nsect;
|
||||
if (preen)
|
||||
printf(" (FIXED)\n");
|
||||
if (preen || reply("SET TO DEFAULT") == 1) {
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
}
|
||||
if (sblock.fs_inodefmt >= FS_44INODEFMT) {
|
||||
newinofmt = 1;
|
||||
} else {
|
||||
sblock.fs_qbmask = ~sblock.fs_bmask;
|
||||
sblock.fs_qfmask = ~sblock.fs_fmask;
|
||||
newinofmt = 0;
|
||||
}
|
||||
/*
|
||||
* Convert to new inode format.
|
||||
*/
|
||||
if (cvtlevel >= 2 && sblock.fs_inodefmt < FS_44INODEFMT) {
|
||||
if (preen)
|
||||
pwarn("CONVERTING TO NEW INODE FORMAT\n");
|
||||
else if (!reply("CONVERT TO NEW INODE FORMAT"))
|
||||
return(0);
|
||||
doinglevel2++;
|
||||
sblock.fs_inodefmt = FS_44INODEFMT;
|
||||
sizepb = sblock.fs_bsize;
|
||||
sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
|
||||
for (i = 0; i < NIADDR; i++) {
|
||||
sizepb *= NINDIR(&sblock);
|
||||
sblock.fs_maxfilesize += sizepb;
|
||||
}
|
||||
sblock.fs_maxsymlinklen = MAXSYMLINKLEN;
|
||||
sblock.fs_qbmask = ~sblock.fs_bmask;
|
||||
sblock.fs_qfmask = ~sblock.fs_fmask;
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
/*
|
||||
* Convert to new cylinder group format.
|
||||
*/
|
||||
if (cvtlevel >= 1 && sblock.fs_postblformat == FS_42POSTBLFMT) {
|
||||
if (preen)
|
||||
pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
|
||||
else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
|
||||
return(0);
|
||||
doinglevel1++;
|
||||
sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
|
||||
sblock.fs_nrpos = 8;
|
||||
sblock.fs_postbloff =
|
||||
(char *)(&sblock.fs_opostbl[0][0]) -
|
||||
(char *)(&sblock.fs_link);
|
||||
sblock.fs_rotbloff = &sblock.fs_space[0] -
|
||||
(u_char *)(&sblock.fs_link);
|
||||
sblock.fs_cgsize =
|
||||
fragroundup(&sblock, CGSIZE(&sblock));
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
if (asblk.b_dirty) {
|
||||
bcopy((char *)&sblock, (char *)&altsblock,
|
||||
(size_t)sblock.fs_sbsize);
|
||||
flush(fswritefd, &asblk);
|
||||
}
|
||||
/*
|
||||
* read in the summary info.
|
||||
*/
|
||||
asked = 0;
|
||||
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(fsreadfd, (char *)sblock.fs_csp[j],
|
||||
fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
|
||||
size) != 0 && !asked) {
|
||||
pfatal("BAD SUMMARY INFORMATION");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
asked++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* allocate and initialize the necessary maps
|
||||
*/
|
||||
bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short));
|
||||
blockmap = calloc((unsigned)bmapsize, sizeof (char));
|
||||
if (blockmap == NULL) {
|
||||
printf("cannot alloc %u bytes for blockmap\n",
|
||||
(unsigned)bmapsize);
|
||||
goto badsb;
|
||||
}
|
||||
statemap = calloc((unsigned)(maxino + 1), sizeof(char));
|
||||
if (statemap == NULL) {
|
||||
printf("cannot alloc %u bytes for statemap\n",
|
||||
(unsigned)(maxino + 1));
|
||||
goto badsb;
|
||||
}
|
||||
typemap = calloc((unsigned)(maxino + 1), sizeof(char));
|
||||
if (typemap == NULL) {
|
||||
printf("cannot alloc %u bytes for typemap\n",
|
||||
(unsigned)(maxino + 1));
|
||||
goto badsb;
|
||||
}
|
||||
lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short));
|
||||
if (lncntp == NULL) {
|
||||
printf("cannot alloc %u bytes for lncntp\n",
|
||||
(unsigned)(maxino + 1) * sizeof(short));
|
||||
goto badsb;
|
||||
}
|
||||
numdirs = sblock.fs_cstotal.cs_ndir;
|
||||
inplast = 0;
|
||||
listmax = numdirs + 10;
|
||||
inpsort = (struct inoinfo **)calloc((unsigned)listmax,
|
||||
sizeof(struct inoinfo *));
|
||||
inphead = (struct inoinfo **)calloc((unsigned)numdirs,
|
||||
sizeof(struct inoinfo *));
|
||||
if (inpsort == NULL || inphead == NULL) {
|
||||
printf("cannot alloc %u bytes for inphead\n",
|
||||
(unsigned)numdirs * sizeof(struct inoinfo *));
|
||||
goto badsb;
|
||||
}
|
||||
bufinit();
|
||||
return (1);
|
||||
|
||||
badsb:
|
||||
ckfini();
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in the super block and its summary info.
|
||||
*/
|
||||
readsb(listerr)
|
||||
int listerr;
|
||||
{
|
||||
daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
|
||||
|
||||
if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
|
||||
return (0);
|
||||
sblk.b_bno = super;
|
||||
sblk.b_size = SBSIZE;
|
||||
/*
|
||||
* run a few consistency checks of the super block
|
||||
*/
|
||||
if (sblock.fs_magic != FS_MAGIC)
|
||||
{ badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
|
||||
if (sblock.fs_ncg < 1)
|
||||
{ badsb(listerr, "NCG OUT OF RANGE"); return (0); }
|
||||
if (sblock.fs_cpg < 1)
|
||||
{ badsb(listerr, "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(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
|
||||
if (sblock.fs_sbsize > SBSIZE)
|
||||
{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
|
||||
/*
|
||||
* Compute block size that the filesystem is based on,
|
||||
* according to fsbtodb, and adjust superblock block number
|
||||
* so we can tell if this is an alternate later.
|
||||
*/
|
||||
super *= dev_bsize;
|
||||
dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
|
||||
sblk.b_bno = super / dev_bsize;
|
||||
if (bflag) {
|
||||
havesb = 1;
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
|
||||
if (asblk.b_errs)
|
||||
return (0);
|
||||
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_optim = sblock.fs_optim;
|
||||
altsblock.fs_rotdelay = sblock.fs_rotdelay;
|
||||
altsblock.fs_maxbpg = sblock.fs_maxbpg;
|
||||
bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
|
||||
sizeof sblock.fs_csp);
|
||||
bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
|
||||
sizeof sblock.fs_fsmnt);
|
||||
bcopy((char *)sblock.fs_sparecon, (char *)altsblock.fs_sparecon,
|
||||
sizeof sblock.fs_sparecon);
|
||||
/*
|
||||
* The following should not have to be copied.
|
||||
*/
|
||||
altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
|
||||
altsblock.fs_interleave = sblock.fs_interleave;
|
||||
altsblock.fs_npsect = sblock.fs_npsect;
|
||||
altsblock.fs_nrpos = sblock.fs_nrpos;
|
||||
altsblock.fs_qbmask = sblock.fs_qbmask;
|
||||
altsblock.fs_qfmask = sblock.fs_qfmask;
|
||||
altsblock.fs_state = sblock.fs_state;
|
||||
altsblock.fs_maxfilesize = sblock.fs_maxfilesize;
|
||||
if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) {
|
||||
badsb(listerr,
|
||||
"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
|
||||
return (0);
|
||||
}
|
||||
havesb = 1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
badsb(listerr, s)
|
||||
int listerr;
|
||||
char *s;
|
||||
{
|
||||
|
||||
if (!listerr)
|
||||
return;
|
||||
if (preen)
|
||||
printf("%s: ", cdevname);
|
||||
pfatal("BAD SUPER BLOCK: %s\n", s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate a prototype superblock based on information in the disk label.
|
||||
* When done the cgsblock macro can be calculated and the fs_ncg field
|
||||
* can be used. Do NOT attempt to use other macros without verifying that
|
||||
* their needed information is available!
|
||||
*/
|
||||
calcsb(dev, devfd, fs)
|
||||
char *dev;
|
||||
int devfd;
|
||||
register struct fs *fs;
|
||||
{
|
||||
register struct disklabel *lp;
|
||||
register struct partition *pp;
|
||||
register char *cp;
|
||||
int i;
|
||||
|
||||
cp = index(dev, '\0') - 1;
|
||||
if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) {
|
||||
pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
|
||||
return (0);
|
||||
}
|
||||
lp = getdisklabel(dev, devfd);
|
||||
if (isdigit(*cp))
|
||||
pp = &lp->d_partitions[0];
|
||||
else
|
||||
pp = &lp->d_partitions[*cp - 'a'];
|
||||
if (pp->p_fstype != FS_BSDFFS) {
|
||||
pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
|
||||
dev, pp->p_fstype < FSMAXTYPES ?
|
||||
fstypenames[pp->p_fstype] : "unknown");
|
||||
return (0);
|
||||
}
|
||||
bzero((char *)fs, sizeof(struct fs));
|
||||
fs->fs_fsize = pp->p_fsize;
|
||||
fs->fs_frag = pp->p_frag;
|
||||
fs->fs_cpg = pp->p_cpg;
|
||||
fs->fs_size = pp->p_size;
|
||||
fs->fs_ntrak = lp->d_ntracks;
|
||||
fs->fs_nsect = lp->d_nsectors;
|
||||
fs->fs_spc = lp->d_secpercyl;
|
||||
fs->fs_nspf = fs->fs_fsize / lp->d_secsize;
|
||||
fs->fs_sblkno = roundup(
|
||||
howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
|
||||
fs->fs_frag);
|
||||
fs->fs_cgmask = 0xffffffff;
|
||||
for (i = fs->fs_ntrak; i > 1; i >>= 1)
|
||||
fs->fs_cgmask <<= 1;
|
||||
if (!POWEROF2(fs->fs_ntrak))
|
||||
fs->fs_cgmask <<= 1;
|
||||
fs->fs_cgoffset = roundup(
|
||||
howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
|
||||
fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
|
||||
fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
|
||||
for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
|
||||
fs->fs_fsbtodb++;
|
||||
dev_bsize = lp->d_secsize;
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct disklabel *
|
||||
getdisklabel(s, fd)
|
||||
char *s;
|
||||
int fd;
|
||||
{
|
||||
static struct disklabel lab;
|
||||
|
||||
if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
|
||||
if (s == NULL)
|
||||
return ((struct disklabel *)NULL);
|
||||
pwarn("ioctl (GCINFO): %s\n", strerror(errno));
|
||||
errexit("%s: can't read disk label\n", s);
|
||||
}
|
||||
return (&lab);
|
||||
}
|
||||
566
sbin/fsck_ffs/utilities.c
Normal file
566
sbin/fsck_ffs/utilities.c
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)utilities.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "fsck.h"
|
||||
|
||||
long diskreads, totalreads; /* Disk cache statistics */
|
||||
|
||||
ftypeok(dp)
|
||||
struct dinode *dp;
|
||||
{
|
||||
switch (dp->di_mode & IFMT) {
|
||||
|
||||
case IFDIR:
|
||||
case IFREG:
|
||||
case IFBLK:
|
||||
case IFCHR:
|
||||
case IFLNK:
|
||||
case IFSOCK:
|
||||
case IFIFO:
|
||||
return (1);
|
||||
|
||||
default:
|
||||
if (debug)
|
||||
printf("bad file type 0%o\n", dp->di_mode);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
reply(question)
|
||||
char *question;
|
||||
{
|
||||
int persevere;
|
||||
char c;
|
||||
|
||||
if (preen)
|
||||
pfatal("INTERNAL ERROR: GOT TO reply()");
|
||||
persevere = !strcmp(question, "CONTINUE");
|
||||
printf("\n");
|
||||
if (!persevere && (nflag || fswritefd < 0)) {
|
||||
printf("%s? no\n\n", question);
|
||||
return (0);
|
||||
}
|
||||
if (yflag || (persevere && nflag)) {
|
||||
printf("%s? yes\n\n", question);
|
||||
return (1);
|
||||
}
|
||||
do {
|
||||
printf("%s? [yn] ", question);
|
||||
(void) fflush(stdout);
|
||||
c = getc(stdin);
|
||||
while (c != '\n' && getc(stdin) != '\n')
|
||||
if (feof(stdin))
|
||||
return (0);
|
||||
} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
|
||||
printf("\n");
|
||||
if (c == 'y' || c == 'Y')
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Malloc buffers and set up cache.
|
||||
*/
|
||||
bufinit()
|
||||
{
|
||||
register struct bufarea *bp;
|
||||
long bufcnt, i;
|
||||
char *bufp;
|
||||
|
||||
pbp = pdirbp = (struct bufarea *)0;
|
||||
bufp = malloc((unsigned int)sblock.fs_bsize);
|
||||
if (bufp == 0)
|
||||
errexit("cannot allocate buffer pool\n");
|
||||
cgblk.b_un.b_buf = bufp;
|
||||
initbarea(&cgblk);
|
||||
bufhead.b_next = bufhead.b_prev = &bufhead;
|
||||
bufcnt = MAXBUFSPACE / sblock.fs_bsize;
|
||||
if (bufcnt < MINBUFS)
|
||||
bufcnt = MINBUFS;
|
||||
for (i = 0; i < bufcnt; i++) {
|
||||
bp = (struct bufarea *)malloc(sizeof(struct bufarea));
|
||||
bufp = malloc((unsigned int)sblock.fs_bsize);
|
||||
if (bp == NULL || bufp == NULL) {
|
||||
if (i >= MINBUFS)
|
||||
break;
|
||||
errexit("cannot allocate buffer pool\n");
|
||||
}
|
||||
bp->b_un.b_buf = bufp;
|
||||
bp->b_prev = &bufhead;
|
||||
bp->b_next = bufhead.b_next;
|
||||
bufhead.b_next->b_prev = bp;
|
||||
bufhead.b_next = bp;
|
||||
initbarea(bp);
|
||||
}
|
||||
bufhead.b_size = i; /* save number of buffers */
|
||||
}
|
||||
|
||||
/*
|
||||
* Manage a cache of directory blocks.
|
||||
*/
|
||||
struct bufarea *
|
||||
getdatablk(blkno, size)
|
||||
daddr_t blkno;
|
||||
long size;
|
||||
{
|
||||
register struct bufarea *bp;
|
||||
|
||||
for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
|
||||
if (bp->b_bno == fsbtodb(&sblock, blkno))
|
||||
goto foundit;
|
||||
for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
|
||||
if ((bp->b_flags & B_INUSE) == 0)
|
||||
break;
|
||||
if (bp == &bufhead)
|
||||
errexit("deadlocked buffer pool\n");
|
||||
getblk(bp, blkno, size);
|
||||
/* fall through */
|
||||
foundit:
|
||||
totalreads++;
|
||||
bp->b_prev->b_next = bp->b_next;
|
||||
bp->b_next->b_prev = bp->b_prev;
|
||||
bp->b_prev = &bufhead;
|
||||
bp->b_next = bufhead.b_next;
|
||||
bufhead.b_next->b_prev = bp;
|
||||
bufhead.b_next = bp;
|
||||
bp->b_flags |= B_INUSE;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
void
|
||||
getblk(bp, blk, size)
|
||||
register struct bufarea *bp;
|
||||
daddr_t blk;
|
||||
long size;
|
||||
{
|
||||
daddr_t dblk;
|
||||
|
||||
dblk = fsbtodb(&sblock, blk);
|
||||
if (bp->b_bno != dblk) {
|
||||
flush(fswritefd, bp);
|
||||
diskreads++;
|
||||
bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
|
||||
bp->b_bno = dblk;
|
||||
bp->b_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
flush(fd, bp)
|
||||
int fd;
|
||||
register struct bufarea *bp;
|
||||
{
|
||||
register int i, j;
|
||||
|
||||
if (!bp->b_dirty)
|
||||
return;
|
||||
if (bp->b_errs != 0)
|
||||
pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
|
||||
(bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
|
||||
bp->b_bno);
|
||||
bp->b_dirty = 0;
|
||||
bp->b_errs = 0;
|
||||
bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
|
||||
if (bp != &sblk)
|
||||
return;
|
||||
for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
|
||||
bwrite(fswritefd, (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);
|
||||
}
|
||||
}
|
||||
|
||||
rwerror(mesg, blk)
|
||||
char *mesg;
|
||||
daddr_t blk;
|
||||
{
|
||||
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
pfatal("CANNOT %s: BLK %ld", mesg, blk);
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("Program terminated\n");
|
||||
}
|
||||
|
||||
ckfini()
|
||||
{
|
||||
register struct bufarea *bp, *nbp;
|
||||
int cnt = 0;
|
||||
|
||||
if (fswritefd < 0) {
|
||||
(void)close(fsreadfd);
|
||||
return;
|
||||
}
|
||||
flush(fswritefd, &sblk);
|
||||
if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
|
||||
!preen && reply("UPDATE STANDARD SUPERBLOCK")) {
|
||||
sblk.b_bno = SBOFF / dev_bsize;
|
||||
sbdirty();
|
||||
flush(fswritefd, &sblk);
|
||||
}
|
||||
flush(fswritefd, &cgblk);
|
||||
free(cgblk.b_un.b_buf);
|
||||
for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
|
||||
cnt++;
|
||||
flush(fswritefd, bp);
|
||||
nbp = bp->b_prev;
|
||||
free(bp->b_un.b_buf);
|
||||
free((char *)bp);
|
||||
}
|
||||
if (bufhead.b_size != cnt)
|
||||
errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
|
||||
pbp = pdirbp = (struct bufarea *)0;
|
||||
if (debug)
|
||||
printf("cache missed %ld of %ld (%d%%)\n", diskreads,
|
||||
totalreads, (int)(diskreads * 100 / totalreads));
|
||||
(void)close(fsreadfd);
|
||||
(void)close(fswritefd);
|
||||
}
|
||||
|
||||
bread(fd, buf, blk, size)
|
||||
int fd;
|
||||
char *buf;
|
||||
daddr_t blk;
|
||||
long size;
|
||||
{
|
||||
char *cp;
|
||||
int i, errs;
|
||||
off_t offset;
|
||||
|
||||
offset = blk;
|
||||
offset *= dev_bsize;
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
else if (read(fd, buf, (int)size) == size)
|
||||
return (0);
|
||||
rwerror("READ", blk);
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
errs = 0;
|
||||
bzero(buf, (size_t)size);
|
||||
printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
|
||||
for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
|
||||
if (read(fd, cp, (int)secsize) != secsize) {
|
||||
(void)lseek(fd, offset + i + secsize, 0);
|
||||
if (secsize != dev_bsize && dev_bsize != 1)
|
||||
printf(" %ld (%ld),",
|
||||
(blk * dev_bsize + i) / secsize,
|
||||
blk + i / dev_bsize);
|
||||
else
|
||||
printf(" %ld,", blk + i / dev_bsize);
|
||||
errs++;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
return (errs);
|
||||
}
|
||||
|
||||
bwrite(fd, buf, blk, size)
|
||||
int fd;
|
||||
char *buf;
|
||||
daddr_t blk;
|
||||
long size;
|
||||
{
|
||||
int i;
|
||||
char *cp;
|
||||
off_t offset;
|
||||
|
||||
if (fd < 0)
|
||||
return;
|
||||
offset = blk;
|
||||
offset *= dev_bsize;
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
else if (write(fd, buf, (int)size) == size) {
|
||||
fsmodified = 1;
|
||||
return;
|
||||
}
|
||||
rwerror("WRITE", blk);
|
||||
if (lseek(fd, offset, 0) < 0)
|
||||
rwerror("SEEK", blk);
|
||||
printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
|
||||
for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
|
||||
if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
|
||||
(void)lseek(fd, offset + i + dev_bsize, 0);
|
||||
printf(" %ld,", blk + i / dev_bsize);
|
||||
}
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a data block with the specified number of fragments
|
||||
*/
|
||||
allocblk(frags)
|
||||
long frags;
|
||||
{
|
||||
register int i, j, k;
|
||||
|
||||
if (frags <= 0 || frags > sblock.fs_frag)
|
||||
return (0);
|
||||
for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
|
||||
for (j = 0; j <= sblock.fs_frag - frags; j++) {
|
||||
if (testbmap(i + j))
|
||||
continue;
|
||||
for (k = 1; k < frags; k++)
|
||||
if (testbmap(i + j + k))
|
||||
break;
|
||||
if (k < frags) {
|
||||
j += k;
|
||||
continue;
|
||||
}
|
||||
for (k = 0; k < frags; k++)
|
||||
setbmap(i + j + k);
|
||||
n_blks += frags;
|
||||
return (i + j);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a previously allocated block
|
||||
*/
|
||||
freeblk(blkno, frags)
|
||||
daddr_t blkno;
|
||||
long frags;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
|
||||
idesc.id_blkno = blkno;
|
||||
idesc.id_numfrags = frags;
|
||||
(void)pass4check(&idesc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a pathname
|
||||
*/
|
||||
getpathname(namebuf, curdir, ino)
|
||||
char *namebuf;
|
||||
ino_t curdir, ino;
|
||||
{
|
||||
int len;
|
||||
register char *cp;
|
||||
struct inodesc idesc;
|
||||
static int busy = 0;
|
||||
extern int findname();
|
||||
|
||||
if (curdir == ino && ino == ROOTINO) {
|
||||
(void)strcpy(namebuf, "/");
|
||||
return;
|
||||
}
|
||||
if (busy ||
|
||||
(statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
|
||||
(void)strcpy(namebuf, "?");
|
||||
return;
|
||||
}
|
||||
busy = 1;
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_fix = IGNORE;
|
||||
cp = &namebuf[MAXPATHLEN - 1];
|
||||
*cp = '\0';
|
||||
if (curdir != ino) {
|
||||
idesc.id_parent = curdir;
|
||||
goto namelookup;
|
||||
}
|
||||
while (ino != ROOTINO) {
|
||||
idesc.id_number = ino;
|
||||
idesc.id_func = findino;
|
||||
idesc.id_name = "..";
|
||||
if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
|
||||
break;
|
||||
namelookup:
|
||||
idesc.id_number = idesc.id_parent;
|
||||
idesc.id_parent = ino;
|
||||
idesc.id_func = findname;
|
||||
idesc.id_name = namebuf;
|
||||
if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
|
||||
break;
|
||||
len = strlen(namebuf);
|
||||
cp -= len;
|
||||
bcopy(namebuf, cp, (size_t)len);
|
||||
*--cp = '/';
|
||||
if (cp < &namebuf[MAXNAMLEN])
|
||||
break;
|
||||
ino = idesc.id_number;
|
||||
}
|
||||
busy = 0;
|
||||
if (ino != ROOTINO)
|
||||
*--cp = '?';
|
||||
bcopy(cp, namebuf, (size_t)(&namebuf[MAXPATHLEN] - cp));
|
||||
}
|
||||
|
||||
void
|
||||
catch()
|
||||
{
|
||||
if (!doinglevel2)
|
||||
ckfini();
|
||||
exit(12);
|
||||
}
|
||||
|
||||
/*
|
||||
* When preening, allow a single quit to signal
|
||||
* a special exit after filesystem checks complete
|
||||
* so that reboot sequence may be interrupted.
|
||||
*/
|
||||
void
|
||||
catchquit()
|
||||
{
|
||||
extern returntosingle;
|
||||
|
||||
printf("returning to single-user after filesystem check\n");
|
||||
returntosingle = 1;
|
||||
(void)signal(SIGQUIT, SIG_DFL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore a single quit signal; wait and flush just in case.
|
||||
* Used by child processes in preen.
|
||||
*/
|
||||
void
|
||||
voidquit()
|
||||
{
|
||||
|
||||
sleep(1);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_DFL);
|
||||
}
|
||||
|
||||
/*
|
||||
* determine whether an inode should be fixed.
|
||||
*/
|
||||
dofix(idesc, msg)
|
||||
register struct inodesc *idesc;
|
||||
char *msg;
|
||||
{
|
||||
|
||||
switch (idesc->id_fix) {
|
||||
|
||||
case DONTKNOW:
|
||||
if (idesc->id_type == DATA)
|
||||
direrror(idesc->id_number, msg);
|
||||
else
|
||||
pwarn(msg);
|
||||
if (preen) {
|
||||
printf(" (SALVAGED)\n");
|
||||
idesc->id_fix = FIX;
|
||||
return (ALTERED);
|
||||
}
|
||||
if (reply("SALVAGE") == 0) {
|
||||
idesc->id_fix = NOFIX;
|
||||
return (0);
|
||||
}
|
||||
idesc->id_fix = FIX;
|
||||
return (ALTERED);
|
||||
|
||||
case FIX:
|
||||
return (ALTERED);
|
||||
|
||||
case NOFIX:
|
||||
case IGNORE:
|
||||
return (0);
|
||||
|
||||
default:
|
||||
errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* VARARGS1 */
|
||||
errexit(s1, s2, s3, s4)
|
||||
char *s1;
|
||||
{
|
||||
printf(s1, s2, s3, s4);
|
||||
exit(8);
|
||||
}
|
||||
|
||||
/*
|
||||
* An unexpected inconsistency occured.
|
||||
* Die if preening, otherwise just print message and continue.
|
||||
*/
|
||||
/* VARARGS1 */
|
||||
pfatal(s, a1, a2, a3)
|
||||
char *s;
|
||||
{
|
||||
|
||||
if (preen) {
|
||||
printf("%s: ", cdevname);
|
||||
printf(s, a1, a2, a3);
|
||||
printf("\n");
|
||||
printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
|
||||
cdevname);
|
||||
exit(8);
|
||||
}
|
||||
printf(s, a1, a2, a3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pwarn just prints a message when not preening,
|
||||
* or a warning (preceded by filename) when preening.
|
||||
*/
|
||||
/* VARARGS1 */
|
||||
pwarn(s, a1, a2, a3, a4, a5, a6)
|
||||
char *s;
|
||||
{
|
||||
|
||||
if (preen)
|
||||
printf("%s: ", cdevname);
|
||||
printf(s, a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
|
||||
#ifndef lint
|
||||
/*
|
||||
* Stub for routines from kernel.
|
||||
*/
|
||||
panic(s)
|
||||
char *s;
|
||||
{
|
||||
|
||||
pfatal("INTERNAL INCONSISTENCY:");
|
||||
errexit(s);
|
||||
}
|
||||
#endif
|
||||
9
sbin/fsck_ifs/Makefile
Normal file
9
sbin/fsck_ifs/Makefile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= fsck
|
||||
MAN8= fsck.0
|
||||
SRCS= dir.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
|
||||
pass5.c preen.c setup.c utilities.c ffs_subr.c ffs_tables.c
|
||||
.PATH: ${.CURDIR}/../../sys/ufs/ffs
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
681
sbin/fsck_ifs/dir.c
Normal file
681
sbin/fsck_ifs/dir.c
Normal file
|
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dir.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
char *lfname = "lost+found";
|
||||
int lfmode = 01777;
|
||||
struct dirtemplate emptydir = { 0, DIRBLKSIZ };
|
||||
struct dirtemplate dirhead = {
|
||||
0, 12, DT_DIR, 1, ".",
|
||||
0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
|
||||
};
|
||||
struct odirtemplate odirhead = {
|
||||
0, 12, 1, ".",
|
||||
0, DIRBLKSIZ - 12, 2, ".."
|
||||
};
|
||||
|
||||
struct direct *fsck_readdir();
|
||||
struct bufarea *getdirblk();
|
||||
|
||||
/*
|
||||
* Propagate connected state through the tree.
|
||||
*/
|
||||
propagate()
|
||||
{
|
||||
register struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpend;
|
||||
long change;
|
||||
|
||||
inpend = &inpsort[inplast];
|
||||
do {
|
||||
change = 0;
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0)
|
||||
continue;
|
||||
if (statemap[inp->i_parent] == DFOUND &&
|
||||
statemap[inp->i_number] == DSTATE) {
|
||||
statemap[inp->i_number] = DFOUND;
|
||||
change++;
|
||||
}
|
||||
}
|
||||
} while (change > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan each entry in a directory block.
|
||||
*/
|
||||
dirscan(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dp;
|
||||
register struct bufarea *bp;
|
||||
int dsize, n;
|
||||
long blksiz;
|
||||
char dbuf[DIRBLKSIZ];
|
||||
|
||||
if (idesc->id_type != DATA)
|
||||
errexit("wrong type to dirscan %d\n", idesc->id_type);
|
||||
if (idesc->id_entryno == 0 &&
|
||||
(idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
|
||||
idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
|
||||
blksiz = idesc->id_numfrags * sblock.fs_fsize;
|
||||
if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
|
||||
idesc->id_filesize -= blksiz;
|
||||
return (SKIP);
|
||||
}
|
||||
idesc->id_loc = 0;
|
||||
for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
|
||||
dsize = dp->d_reclen;
|
||||
bcopy((char *)dp, dbuf, (size_t)dsize);
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt) {
|
||||
struct direct *tdp = (struct direct *)dbuf;
|
||||
u_char tmp;
|
||||
|
||||
tmp = tdp->d_namlen;
|
||||
tdp->d_namlen = tdp->d_type;
|
||||
tdp->d_type = tmp;
|
||||
}
|
||||
# endif
|
||||
idesc->id_dirp = (struct direct *)dbuf;
|
||||
if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt && !doinglevel2) {
|
||||
struct direct *tdp;
|
||||
u_char tmp;
|
||||
|
||||
tdp = (struct direct *)dbuf;
|
||||
tmp = tdp->d_namlen;
|
||||
tdp->d_namlen = tdp->d_type;
|
||||
tdp->d_type = tmp;
|
||||
}
|
||||
# endif
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
bcopy(dbuf, bp->b_un.b_buf + idesc->id_loc - dsize,
|
||||
(size_t)dsize);
|
||||
dirty(bp);
|
||||
sbdirty();
|
||||
}
|
||||
if (n & STOP)
|
||||
return (n);
|
||||
}
|
||||
return (idesc->id_filesize > 0 ? KEEPON : STOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* get next entry in a directory.
|
||||
*/
|
||||
struct direct *
|
||||
fsck_readdir(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dp, *ndp;
|
||||
register struct bufarea *bp;
|
||||
long size, blksiz, fix, dploc;
|
||||
|
||||
blksiz = idesc->id_numfrags * sblock.fs_fsize;
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
|
||||
idesc->id_loc < blksiz) {
|
||||
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
if (dircheck(idesc, dp))
|
||||
goto dpok;
|
||||
fix = dofix(idesc, "DIRECTORY CORRUPTED");
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
dp->d_reclen = DIRBLKSIZ;
|
||||
dp->d_ino = 0;
|
||||
dp->d_type = 0;
|
||||
dp->d_namlen = 0;
|
||||
dp->d_name[0] = '\0';
|
||||
if (fix)
|
||||
dirty(bp);
|
||||
idesc->id_loc += DIRBLKSIZ;
|
||||
idesc->id_filesize -= DIRBLKSIZ;
|
||||
return (dp);
|
||||
}
|
||||
dpok:
|
||||
if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
|
||||
return NULL;
|
||||
dploc = idesc->id_loc;
|
||||
dp = (struct direct *)(bp->b_un.b_buf + dploc);
|
||||
idesc->id_loc += dp->d_reclen;
|
||||
idesc->id_filesize -= dp->d_reclen;
|
||||
if ((idesc->id_loc % DIRBLKSIZ) == 0)
|
||||
return (dp);
|
||||
ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
|
||||
if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
|
||||
dircheck(idesc, ndp) == 0) {
|
||||
size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
|
||||
idesc->id_loc += size;
|
||||
idesc->id_filesize -= size;
|
||||
fix = dofix(idesc, "DIRECTORY CORRUPTED");
|
||||
bp = getdirblk(idesc->id_blkno, blksiz);
|
||||
dp = (struct direct *)(bp->b_un.b_buf + dploc);
|
||||
dp->d_reclen += size;
|
||||
if (fix)
|
||||
dirty(bp);
|
||||
}
|
||||
return (dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that a directory entry is valid.
|
||||
* This is a superset of the checks made in the kernel.
|
||||
*/
|
||||
dircheck(idesc, dp)
|
||||
struct inodesc *idesc;
|
||||
register struct direct *dp;
|
||||
{
|
||||
register int size;
|
||||
register char *cp;
|
||||
u_char namlen, type;
|
||||
int spaceleft;
|
||||
|
||||
size = DIRSIZ(!newinofmt, dp);
|
||||
spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
if (!newinofmt) {
|
||||
type = dp->d_namlen;
|
||||
namlen = dp->d_type;
|
||||
} else {
|
||||
namlen = dp->d_namlen;
|
||||
type = dp->d_type;
|
||||
}
|
||||
# else
|
||||
namlen = dp->d_namlen;
|
||||
type = dp->d_type;
|
||||
# endif
|
||||
if (dp->d_ino < maxino &&
|
||||
dp->d_reclen != 0 &&
|
||||
dp->d_reclen <= spaceleft &&
|
||||
(dp->d_reclen & 0x3) == 0 &&
|
||||
dp->d_reclen >= size &&
|
||||
idesc->id_filesize >= size &&
|
||||
namlen <= MAXNAMLEN &&
|
||||
type <= 15) {
|
||||
if (dp->d_ino == 0)
|
||||
return (1);
|
||||
for (cp = dp->d_name, size = 0; size < namlen; size++)
|
||||
if (*cp == 0 || (*cp++ == '/'))
|
||||
return (0);
|
||||
if (*cp == 0)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
direrror(ino, errmesg)
|
||||
ino_t ino;
|
||||
char *errmesg;
|
||||
{
|
||||
|
||||
fileerror(ino, ino, errmesg);
|
||||
}
|
||||
|
||||
fileerror(cwd, ino, errmesg)
|
||||
ino_t cwd, ino;
|
||||
char *errmesg;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
pwarn("%s ", errmesg);
|
||||
pinode(ino);
|
||||
printf("\n");
|
||||
getpathname(pathbuf, cwd, ino);
|
||||
if (ino < ROOTINO || ino > maxino) {
|
||||
pfatal("NAME=%s\n", pathbuf);
|
||||
return;
|
||||
}
|
||||
dp = ginode(ino);
|
||||
if (ftypeok(dp))
|
||||
pfatal("%s=%s\n",
|
||||
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
|
||||
else
|
||||
pfatal("NAME=%s\n", pathbuf);
|
||||
}
|
||||
|
||||
adjust(idesc, lcnt)
|
||||
register struct inodesc *idesc;
|
||||
short lcnt;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
|
||||
dp = ginode(idesc->id_number);
|
||||
if (dp->di_nlink == lcnt) {
|
||||
if (linkup(idesc->id_number, (ino_t)0) == 0)
|
||||
clri(idesc, "UNREF", 0);
|
||||
} else {
|
||||
pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
|
||||
((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
|
||||
pinode(idesc->id_number);
|
||||
printf(" COUNT %d SHOULD BE %d",
|
||||
dp->di_nlink, dp->di_nlink - lcnt);
|
||||
if (preen) {
|
||||
if (lcnt < 0) {
|
||||
printf("\n");
|
||||
pfatal("LINK COUNT INCREASING");
|
||||
}
|
||||
printf(" (ADJUSTED)\n");
|
||||
}
|
||||
if (preen || reply("ADJUST") == 1) {
|
||||
dp->di_nlink -= lcnt;
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mkentry(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
struct direct newent;
|
||||
int newlen, oldlen;
|
||||
|
||||
newent.d_namlen = strlen(idesc->id_name);
|
||||
newlen = DIRSIZ(0, &newent);
|
||||
if (dirp->d_ino != 0)
|
||||
oldlen = DIRSIZ(0, dirp);
|
||||
else
|
||||
oldlen = 0;
|
||||
if (dirp->d_reclen - oldlen < newlen)
|
||||
return (KEEPON);
|
||||
newent.d_reclen = dirp->d_reclen - oldlen;
|
||||
dirp->d_reclen = oldlen;
|
||||
dirp = (struct direct *)(((char *)dirp) + oldlen);
|
||||
dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
|
||||
if (newinofmt)
|
||||
dirp->d_type = typemap[idesc->id_parent];
|
||||
else
|
||||
dirp->d_type = 0;
|
||||
dirp->d_reclen = newent.d_reclen;
|
||||
dirp->d_namlen = newent.d_namlen;
|
||||
bcopy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
|
||||
return (ALTERED|STOP);
|
||||
}
|
||||
|
||||
chgino(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (bcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
|
||||
return (KEEPON);
|
||||
dirp->d_ino = idesc->id_parent;
|
||||
if (newinofmt)
|
||||
dirp->d_type = typemap[idesc->id_parent];
|
||||
else
|
||||
dirp->d_type = 0;
|
||||
return (ALTERED|STOP);
|
||||
}
|
||||
|
||||
linkup(orphan, parentdir)
|
||||
ino_t orphan;
|
||||
ino_t parentdir;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
int lostdir;
|
||||
ino_t oldlfdir;
|
||||
struct inodesc idesc;
|
||||
char tempname[BUFSIZ];
|
||||
extern int pass4check();
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
dp = ginode(orphan);
|
||||
lostdir = (dp->di_mode & IFMT) == IFDIR;
|
||||
pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
|
||||
pinode(orphan);
|
||||
if (preen && dp->di_size == 0)
|
||||
return (0);
|
||||
if (preen)
|
||||
printf(" (RECONNECTED)\n");
|
||||
else
|
||||
if (reply("RECONNECT") == 0)
|
||||
return (0);
|
||||
if (lfdir == 0) {
|
||||
dp = ginode(ROOTINO);
|
||||
idesc.id_name = lfname;
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = findino;
|
||||
idesc.id_number = ROOTINO;
|
||||
if ((ckinode(dp, &idesc) & FOUND) != 0) {
|
||||
lfdir = idesc.id_parent;
|
||||
} else {
|
||||
pwarn("NO lost+found DIRECTORY");
|
||||
if (preen || reply("CREATE")) {
|
||||
lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
|
||||
if (lfdir != 0) {
|
||||
if (makeentry(ROOTINO, lfdir, lfname) != 0) {
|
||||
if (preen)
|
||||
printf(" (CREATED)\n");
|
||||
} else {
|
||||
freedir(lfdir, ROOTINO);
|
||||
lfdir = 0;
|
||||
if (preen)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lfdir == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
|
||||
printf("\n\n");
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
dp = ginode(lfdir);
|
||||
if ((dp->di_mode & IFMT) != IFDIR) {
|
||||
pfatal("lost+found IS NOT A DIRECTORY");
|
||||
if (reply("REALLOCATE") == 0)
|
||||
return (0);
|
||||
oldlfdir = lfdir;
|
||||
if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
|
||||
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
inodirty();
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
idesc.id_number = oldlfdir;
|
||||
adjust(&idesc, lncntp[oldlfdir] + 1);
|
||||
lncntp[oldlfdir] = 0;
|
||||
dp = ginode(lfdir);
|
||||
}
|
||||
if (statemap[lfdir] != DFOUND) {
|
||||
pfatal("SORRY. NO lost+found DIRECTORY\n\n");
|
||||
return (0);
|
||||
}
|
||||
(void)lftempname(tempname, orphan);
|
||||
if (makeentry(lfdir, orphan, tempname) == 0) {
|
||||
pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
|
||||
printf("\n\n");
|
||||
return (0);
|
||||
}
|
||||
lncntp[orphan]--;
|
||||
if (lostdir) {
|
||||
if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
|
||||
parentdir != (ino_t)-1)
|
||||
(void)makeentry(orphan, lfdir, "..");
|
||||
dp = ginode(lfdir);
|
||||
dp->di_nlink++;
|
||||
inodirty();
|
||||
lncntp[lfdir]++;
|
||||
pwarn("DIR I=%lu CONNECTED. ", orphan);
|
||||
if (parentdir != (ino_t)-1)
|
||||
printf("PARENT WAS I=%lu\n", parentdir);
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* fix an entry in a directory.
|
||||
*/
|
||||
changeino(dir, name, newnum)
|
||||
ino_t dir;
|
||||
char *name;
|
||||
ino_t newnum;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = chgino;
|
||||
idesc.id_number = dir;
|
||||
idesc.id_fix = DONTKNOW;
|
||||
idesc.id_name = name;
|
||||
idesc.id_parent = newnum; /* new value for name */
|
||||
return (ckinode(ginode(dir), &idesc));
|
||||
}
|
||||
|
||||
/*
|
||||
* make an entry in a directory
|
||||
*/
|
||||
makeentry(parent, ino, name)
|
||||
ino_t parent, ino;
|
||||
char *name;
|
||||
{
|
||||
struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
if (parent < ROOTINO || parent >= maxino ||
|
||||
ino < ROOTINO || ino >= maxino)
|
||||
return (0);
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = DATA;
|
||||
idesc.id_func = mkentry;
|
||||
idesc.id_number = parent;
|
||||
idesc.id_parent = ino; /* this is the inode to enter */
|
||||
idesc.id_fix = DONTKNOW;
|
||||
idesc.id_name = name;
|
||||
dp = ginode(parent);
|
||||
if (dp->di_size % DIRBLKSIZ) {
|
||||
dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
|
||||
inodirty();
|
||||
}
|
||||
if ((ckinode(dp, &idesc) & ALTERED) != 0)
|
||||
return (1);
|
||||
getpathname(pathbuf, parent, parent);
|
||||
dp = ginode(parent);
|
||||
if (expanddir(dp, pathbuf) == 0)
|
||||
return (0);
|
||||
return (ckinode(dp, &idesc) & ALTERED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to expand the size of a directory
|
||||
*/
|
||||
expanddir(dp, name)
|
||||
register struct dinode *dp;
|
||||
char *name;
|
||||
{
|
||||
daddr_t lastbn, newblk;
|
||||
register struct bufarea *bp;
|
||||
char *cp, firstblk[DIRBLKSIZ];
|
||||
|
||||
lastbn = lblkno(&sblock, dp->di_size);
|
||||
if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
|
||||
return (0);
|
||||
if ((newblk = allocblk(sblock.fs_frag)) == 0)
|
||||
return (0);
|
||||
dp->di_db[lastbn + 1] = dp->di_db[lastbn];
|
||||
dp->di_db[lastbn] = newblk;
|
||||
dp->di_size += sblock.fs_bsize;
|
||||
dp->di_blocks += btodb(sblock.fs_bsize);
|
||||
bp = getdirblk(dp->di_db[lastbn + 1],
|
||||
(long)dblksize(&sblock, dp, lastbn + 1));
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
|
||||
bp = getdirblk(newblk, sblock.fs_bsize);
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_bsize];
|
||||
cp += DIRBLKSIZ)
|
||||
bcopy((char *)&emptydir, cp, sizeof emptydir);
|
||||
dirty(bp);
|
||||
bp = getdirblk(dp->di_db[lastbn + 1],
|
||||
(long)dblksize(&sblock, dp, lastbn + 1));
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
bcopy((char *)&emptydir, bp->b_un.b_buf, sizeof emptydir);
|
||||
pwarn("NO SPACE LEFT IN %s", name);
|
||||
if (preen)
|
||||
printf(" (EXPANDED)\n");
|
||||
else if (reply("EXPAND") == 0)
|
||||
goto bad;
|
||||
dirty(bp);
|
||||
inodirty();
|
||||
return (1);
|
||||
bad:
|
||||
dp->di_db[lastbn] = dp->di_db[lastbn + 1];
|
||||
dp->di_db[lastbn + 1] = 0;
|
||||
dp->di_size -= sblock.fs_bsize;
|
||||
dp->di_blocks -= btodb(sblock.fs_bsize);
|
||||
freeblk(newblk, sblock.fs_frag);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a new directory
|
||||
*/
|
||||
allocdir(parent, request, mode)
|
||||
ino_t parent, request;
|
||||
int mode;
|
||||
{
|
||||
ino_t ino;
|
||||
char *cp;
|
||||
struct dinode *dp;
|
||||
register struct bufarea *bp;
|
||||
struct dirtemplate *dirp;
|
||||
|
||||
ino = allocino(request, IFDIR|mode);
|
||||
if (newinofmt)
|
||||
dirp = &dirhead;
|
||||
else
|
||||
dirp = (struct dirtemplate *)&odirhead;
|
||||
dirp->dot_ino = ino;
|
||||
dirp->dotdot_ino = parent;
|
||||
dp = ginode(ino);
|
||||
bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
|
||||
if (bp->b_errs) {
|
||||
freeino(ino);
|
||||
return (0);
|
||||
}
|
||||
bcopy((char *)dirp, bp->b_un.b_buf, sizeof(struct dirtemplate));
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_fsize];
|
||||
cp += DIRBLKSIZ)
|
||||
bcopy((char *)&emptydir, cp, sizeof emptydir);
|
||||
dirty(bp);
|
||||
dp->di_nlink = 2;
|
||||
inodirty();
|
||||
if (ino == ROOTINO) {
|
||||
lncntp[ino] = dp->di_nlink;
|
||||
cacheino(dp, ino);
|
||||
return(ino);
|
||||
}
|
||||
if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
|
||||
freeino(ino);
|
||||
return (0);
|
||||
}
|
||||
cacheino(dp, ino);
|
||||
statemap[ino] = statemap[parent];
|
||||
if (statemap[ino] == DSTATE) {
|
||||
lncntp[ino] = dp->di_nlink;
|
||||
lncntp[parent]++;
|
||||
}
|
||||
dp = ginode(parent);
|
||||
dp->di_nlink++;
|
||||
inodirty();
|
||||
return (ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* free a directory inode
|
||||
*/
|
||||
freedir(ino, parent)
|
||||
ino_t ino, parent;
|
||||
{
|
||||
struct dinode *dp;
|
||||
|
||||
if (ino != parent) {
|
||||
dp = ginode(parent);
|
||||
dp->di_nlink--;
|
||||
inodirty();
|
||||
}
|
||||
freeino(ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a temporary name for the lost+found directory.
|
||||
*/
|
||||
lftempname(bufp, ino)
|
||||
char *bufp;
|
||||
ino_t ino;
|
||||
{
|
||||
register ino_t in;
|
||||
register char *cp;
|
||||
int namlen;
|
||||
|
||||
cp = bufp + 2;
|
||||
for (in = maxino; in > 0; in /= 10)
|
||||
cp++;
|
||||
*--cp = 0;
|
||||
namlen = cp - bufp;
|
||||
in = ino;
|
||||
while (cp > bufp) {
|
||||
*--cp = (in % 10) + '0';
|
||||
in /= 10;
|
||||
}
|
||||
*cp = '#';
|
||||
return (namlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a directory block.
|
||||
* Insure that it is held until another is requested.
|
||||
*/
|
||||
struct bufarea *
|
||||
getdirblk(blkno, size)
|
||||
daddr_t blkno;
|
||||
long size;
|
||||
{
|
||||
|
||||
if (pdirbp != 0)
|
||||
pdirbp->b_flags &= ~B_INUSE;
|
||||
pdirbp = getdatablk(blkno, size);
|
||||
return (pdirbp);
|
||||
}
|
||||
215
sbin/fsck_ifs/fsck.h
Normal file
215
sbin/fsck_ifs/fsck.h
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fsck.h 8.1 (Berkeley) 6/5/93
|
||||
*/
|
||||
|
||||
#define MAXDUP 10 /* limit on dup blks (per inode) */
|
||||
#define MAXBAD 10 /* limit on bad blks (per inode) */
|
||||
#define MAXBUFSPACE 40*1024 /* maximum space to allocate to buffers */
|
||||
#define INOBUFSIZE 56*1024 /* size of buffer to read inodes in pass1 */
|
||||
|
||||
#ifndef BUFSIZ
|
||||
#define BUFSIZ 1024
|
||||
#endif
|
||||
|
||||
#define USTATE 01 /* inode not allocated */
|
||||
#define FSTATE 02 /* inode is file */
|
||||
#define DSTATE 03 /* inode is directory */
|
||||
#define DFOUND 04 /* directory found during descent */
|
||||
#define DCLEAR 05 /* directory is to be cleared */
|
||||
#define FCLEAR 06 /* file is to be cleared */
|
||||
|
||||
/*
|
||||
* buffer cache structure.
|
||||
*/
|
||||
struct bufarea {
|
||||
struct bufarea *b_next; /* free list queue */
|
||||
struct bufarea *b_prev; /* free list queue */
|
||||
daddr_t b_bno;
|
||||
int b_size;
|
||||
int b_errs;
|
||||
int b_flags;
|
||||
union {
|
||||
char *b_buf; /* buffer space */
|
||||
daddr_t *b_indir; /* indirect block */
|
||||
struct fs *b_fs; /* super block */
|
||||
struct cg *b_cg; /* cylinder group */
|
||||
struct dinode *b_dinode; /* inode block */
|
||||
} b_un;
|
||||
char b_dirty;
|
||||
};
|
||||
|
||||
#define B_INUSE 1
|
||||
|
||||
#define MINBUFS 5 /* minimum number of buffers required */
|
||||
struct bufarea bufhead; /* head of list of other blks in filesys */
|
||||
struct bufarea sblk; /* file system superblock */
|
||||
struct bufarea cgblk; /* cylinder group blocks */
|
||||
struct bufarea *pdirbp; /* current directory contents */
|
||||
struct bufarea *pbp; /* current inode block */
|
||||
struct bufarea *getdatablk();
|
||||
|
||||
#define dirty(bp) (bp)->b_dirty = 1
|
||||
#define initbarea(bp) \
|
||||
(bp)->b_dirty = 0; \
|
||||
(bp)->b_bno = (daddr_t)-1; \
|
||||
(bp)->b_flags = 0;
|
||||
|
||||
#define sbdirty() sblk.b_dirty = 1
|
||||
#define cgdirty() cgblk.b_dirty = 1
|
||||
#define sblock (*sblk.b_un.b_fs)
|
||||
#define cgrp (*cgblk.b_un.b_cg)
|
||||
|
||||
enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
|
||||
|
||||
struct inodesc {
|
||||
enum fixstate id_fix; /* policy on fixing errors */
|
||||
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 */
|
||||
quad_t 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 */
|
||||
struct direct *id_dirp; /* for DATA nodes, ptr to current entry */
|
||||
char *id_name; /* for DATA nodes, name to find or enter */
|
||||
char id_type; /* type of descriptor, DATA or ADDR */
|
||||
};
|
||||
/* file types */
|
||||
#define DATA 1
|
||||
#define ADDR 2
|
||||
|
||||
/*
|
||||
* Linked list of duplicate blocks.
|
||||
*
|
||||
* The list is composed of two parts. The first part of the
|
||||
* list (from duplist through the node pointed to by muldup)
|
||||
* contains a single copy of each duplicate block that has been
|
||||
* found. The second part of the list (from muldup to the end)
|
||||
* contains duplicate blocks that have been found more than once.
|
||||
* To check if a block has been found as a duplicate it is only
|
||||
* necessary to search from duplist through muldup. To find the
|
||||
* total number of times that a block has been found as a duplicate
|
||||
* the entire list must be searched for occurences of the block
|
||||
* in question. The following diagram shows a sample list where
|
||||
* w (found twice), x (found once), y (found three times), and z
|
||||
* (found once) are duplicate block numbers:
|
||||
*
|
||||
* w -> y -> x -> z -> y -> w -> y
|
||||
* ^ ^
|
||||
* | |
|
||||
* duplist muldup
|
||||
*/
|
||||
struct dups {
|
||||
struct dups *next;
|
||||
daddr_t dup;
|
||||
};
|
||||
struct dups *duplist; /* head of dup list */
|
||||
struct dups *muldup; /* end of unique duplicate dup block numbers */
|
||||
|
||||
/*
|
||||
* Linked list of inodes with zero link counts.
|
||||
*/
|
||||
struct zlncnt {
|
||||
struct zlncnt *next;
|
||||
ino_t zlncnt;
|
||||
};
|
||||
struct zlncnt *zlnhead; /* head of zero link count list */
|
||||
|
||||
/*
|
||||
* Inode cache data structures.
|
||||
*/
|
||||
struct inoinfo {
|
||||
struct inoinfo *i_nexthash; /* next entry in hash chain */
|
||||
ino_t i_number; /* inode number of this entry */
|
||||
ino_t i_parent; /* inode number of parent */
|
||||
ino_t i_dotdot; /* inode number of `..' */
|
||||
size_t i_isize; /* size of inode */
|
||||
u_int i_numblks; /* size of block array in bytes */
|
||||
daddr_t i_blks[1]; /* actually longer */
|
||||
} **inphead, **inpsort;
|
||||
long numdirs, listmax, inplast;
|
||||
|
||||
char *cdevname; /* name of device being checked */
|
||||
long dev_bsize; /* computed value of DEV_BSIZE */
|
||||
long secsize; /* actual disk sector size */
|
||||
char nflag; /* assume a no response */
|
||||
char yflag; /* assume a yes response */
|
||||
int bflag; /* location of alternate super block */
|
||||
int debug; /* output debugging info */
|
||||
int cvtlevel; /* convert to newer file system format */
|
||||
int doinglevel1; /* converting to new cylinder group format */
|
||||
int doinglevel2; /* converting to new inode format */
|
||||
int newinofmt; /* filesystem has new inode format */
|
||||
char preen; /* just fix normal inconsistencies */
|
||||
char hotroot; /* checking root device */
|
||||
char havesb; /* superblock has been read */
|
||||
int fsmodified; /* 1 => write done to file system */
|
||||
int fsreadfd; /* file descriptor for reading file system */
|
||||
int fswritefd; /* file descriptor for writing file system */
|
||||
|
||||
daddr_t maxfsblock; /* number of blocks in the file system */
|
||||
char *blockmap; /* ptr to primary blk allocation map */
|
||||
ino_t maxino; /* number of inodes in file system */
|
||||
ino_t lastino; /* last inode in use */
|
||||
char *statemap; /* ptr to inode state table */
|
||||
char *typemap; /* ptr to inode type table */
|
||||
short *lncntp; /* ptr to link count table */
|
||||
|
||||
ino_t lfdir; /* lost & found directory inode number */
|
||||
char *lfname; /* lost & found directory name */
|
||||
int lfmode; /* lost & found directory creation mode */
|
||||
|
||||
daddr_t n_blks; /* number of blocks in use */
|
||||
daddr_t n_files; /* number of files in use */
|
||||
|
||||
#define clearinode(dp) (*(dp) = zino)
|
||||
struct dinode zino;
|
||||
|
||||
#define setbmap(blkno) setbit(blockmap, blkno)
|
||||
#define testbmap(blkno) isset(blockmap, blkno)
|
||||
#define clrbmap(blkno) clrbit(blockmap, blkno)
|
||||
|
||||
#define STOP 0x01
|
||||
#define SKIP 0x02
|
||||
#define KEEPON 0x04
|
||||
#define ALTERED 0x08
|
||||
#define FOUND 0x10
|
||||
|
||||
time_t time();
|
||||
struct dinode *ginode();
|
||||
struct inoinfo *getinoinfo();
|
||||
void getblk();
|
||||
ino_t allocino();
|
||||
int findino();
|
||||
291
sbin/fsck_ifs/fsck_ifs.8
Normal file
291
sbin/fsck_ifs/fsck_ifs.8
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
.\" Copyright (c) 1980, 1989, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)fsck.8 8.2 (Berkeley) 12/11/93
|
||||
.\"
|
||||
.Dd December 11, 1993
|
||||
.Dt FSCK 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm fsck
|
||||
.Nd filesystem consistency check and interactive repair
|
||||
.Sh SYNOPSIS
|
||||
.Nm fsck
|
||||
.Fl p
|
||||
.Op Fl m Ar mode
|
||||
.Nm fsck
|
||||
.Op Fl b Ar block#
|
||||
.Op Fl c Ar level
|
||||
.Op Fl l Ar maxparallel
|
||||
.Op Fl y
|
||||
.Op Fl n
|
||||
.Op Fl m Ar mode
|
||||
.Op Ar filesystem
|
||||
.Ar ...
|
||||
.Sh DESCRIPTION
|
||||
The first form of
|
||||
.Nm fsck
|
||||
preens a standard set of filesystems or the specified filesystems.
|
||||
It is normally used in the script
|
||||
.Pa /etc/rc
|
||||
during automatic reboot.
|
||||
Here
|
||||
.Nm fsck
|
||||
reads the table
|
||||
.Pa /etc/fstab
|
||||
to determine which filesystems to check.
|
||||
Only partitions in fstab that are mounted ``rw,'' ``rq'' or ``ro''
|
||||
and that have non-zero pass number are checked.
|
||||
Filesystems with pass number 1 (normally just the root filesystem)
|
||||
are checked one at a time.
|
||||
When pass 1 completes, all remaining filesystems are checked,
|
||||
running one process per disk drive.
|
||||
The disk drive containing each filesystem is inferred from the longest prefix
|
||||
of the device name that ends in a digit; the remaining characters are assumed
|
||||
to be the partition designator.
|
||||
.Pp
|
||||
The kernel takes care that only a restricted class of innocuous filesystem
|
||||
inconsistencies can happen unless hardware or software failures intervene.
|
||||
These are limited to the following:
|
||||
.Bl -item -compact
|
||||
.It
|
||||
Unreferenced inodes
|
||||
.It
|
||||
Link counts in inodes too large
|
||||
.It
|
||||
Missing blocks in the free map
|
||||
.It
|
||||
Blocks in the free map also in files
|
||||
.It
|
||||
Counts in the super-block wrong
|
||||
.El
|
||||
.Pp
|
||||
These are the only inconsistencies that
|
||||
.Nm fsck
|
||||
with the
|
||||
.Fl p
|
||||
option will correct; if it encounters other inconsistencies, it exits
|
||||
with an abnormal return status and an automatic reboot will then fail.
|
||||
For each corrected inconsistency one or more lines will be printed
|
||||
identifying the filesystem on which the correction will take place,
|
||||
and the nature of the correction. After successfully correcting a filesystem,
|
||||
.Nm fsck
|
||||
will print the number of files on that filesystem,
|
||||
the number of used and free blocks,
|
||||
and the percentage of fragmentation.
|
||||
.Pp
|
||||
If sent a
|
||||
.Dv QUIT
|
||||
signal,
|
||||
.Nm fsck
|
||||
will finish the filesystem checks, then exit with an abnormal
|
||||
return status that causes an automatic reboot to fail.
|
||||
This is useful when you want to finish the filesystem checks during an
|
||||
automatic reboot,
|
||||
but do not want the machine to come up multiuser after the checks complete.
|
||||
.Pp
|
||||
Without the
|
||||
.Fl p
|
||||
option,
|
||||
.Nm fsck
|
||||
audits and interactively repairs inconsistent conditions for filesystems.
|
||||
If the filesystem is inconsistent the operator is prompted for concurrence
|
||||
before each correction is attempted.
|
||||
It should be noted that some of the corrective actions which are not
|
||||
correctable under the
|
||||
.Fl p
|
||||
option will result in some loss of data.
|
||||
The amount and severity of data lost may be determined from the diagnostic
|
||||
output.
|
||||
The default action for each consistency correction
|
||||
is to wait for the operator to respond
|
||||
.Li yes
|
||||
or
|
||||
.Li no .
|
||||
If the operator does not have write permission on the filesystem
|
||||
.Nm fsck
|
||||
will default to a
|
||||
.Fl n
|
||||
action.
|
||||
.Pp
|
||||
.Nm Fsck
|
||||
has more consistency checks than
|
||||
its predecessors
|
||||
.Em check , dcheck , fcheck ,
|
||||
and
|
||||
.Em icheck
|
||||
combined.
|
||||
.Pp
|
||||
The following flags are interpreted by
|
||||
.Nm fsck .
|
||||
.Bl -tag -width indent
|
||||
.It Fl b
|
||||
Use the block specified immediately after the flag as
|
||||
the super block for the filesystem. Block 32 is usually
|
||||
an alternate super block.
|
||||
.It Fl l
|
||||
Limit the number of parallel checks to the number specified in the following
|
||||
argument.
|
||||
By default, the limit is the number of disks, running one process per disk.
|
||||
If a smaller limit is given, the disks are checked round-robin, one filesystem
|
||||
at a time.
|
||||
.It Fl m
|
||||
Use the mode specified in octal immediately after the flag as the
|
||||
permission bits to use when creating the
|
||||
.Pa lost+found
|
||||
directory rather than the default 1777.
|
||||
In particular, systems that do not wish to have lost files accessible
|
||||
by all users on the system should use a more restrictive
|
||||
set of permissions such as 700.
|
||||
.It Fl y
|
||||
Assume a yes response to all questions asked by
|
||||
.Nm fsck ;
|
||||
this should be used with great caution as this is a free license
|
||||
to continue after essentially unlimited trouble has been encountered.
|
||||
.It Fl n
|
||||
Assume a no response to all questions asked by
|
||||
.Nm fsck
|
||||
except for
|
||||
.Ql CONTINUE? ,
|
||||
which is assumed to be affirmative;
|
||||
do not open the filesystem for writing.
|
||||
.It Fl c
|
||||
Convert the filesystem to the specified level.
|
||||
Note that the level of a filesystem can only be raised.
|
||||
.Bl -tag -width indent
|
||||
There are currently three levels defined:
|
||||
.It 0
|
||||
The filesystem is in the old (static table) format.
|
||||
.It 1
|
||||
The filesystem is in the new (dynamic table) format.
|
||||
.It 2
|
||||
The filesystem supports 32-bit uid's and gid's,
|
||||
short symbolic links are stored in the inode,
|
||||
and directories have an added field showing the file type.
|
||||
.El
|
||||
.Pp
|
||||
In interactive mode,
|
||||
.Nm fsck
|
||||
will list the conversion to be made
|
||||
and ask whether the conversion should be done.
|
||||
If a negative answer is given,
|
||||
no further operations are done on the filesystem.
|
||||
In preen mode,
|
||||
the conversion is listed and done if
|
||||
possible without user interaction.
|
||||
Conversion in preen mode is best used when all the filesystems
|
||||
are being converted at once.
|
||||
The format of a filesystem can be determined from the
|
||||
first line of output from
|
||||
.Xr dumpfs 8 .
|
||||
.El
|
||||
.Pp
|
||||
If no filesystems are given to
|
||||
.Nm fsck
|
||||
then a default list of filesystems is read from
|
||||
the file
|
||||
.Pa /etc/fstab .
|
||||
.Pp
|
||||
.Bl -enum -indent indent -compact
|
||||
Inconsistencies checked are as follows:
|
||||
.It
|
||||
Blocks claimed by more than one inode or the free map.
|
||||
.It
|
||||
Blocks claimed by an inode outside the range of the filesystem.
|
||||
.It
|
||||
Incorrect link counts.
|
||||
.It
|
||||
Size checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
Directory size not a multiple of DIRBLKSIZ.
|
||||
.It
|
||||
Partially truncated file.
|
||||
.El
|
||||
.It
|
||||
Bad inode format.
|
||||
.It
|
||||
Blocks not accounted for anywhere.
|
||||
.It
|
||||
Directory checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
File pointing to unallocated inode.
|
||||
.It
|
||||
Inode number out of range.
|
||||
.It
|
||||
Dot or dot-dot not the first two entries of a directory
|
||||
or having the wrong inode number.
|
||||
.El
|
||||
.It
|
||||
Super Block checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
More blocks for inodes than there are in the filesystem.
|
||||
.It
|
||||
Bad free block map format.
|
||||
.It
|
||||
Total free block and/or free inode count incorrect.
|
||||
.El
|
||||
.El
|
||||
.Pp
|
||||
Orphaned files and directories (allocated but unreferenced) are,
|
||||
with the operator's concurrence, reconnected by
|
||||
placing them in the
|
||||
.Pa lost+found
|
||||
directory.
|
||||
The name assigned is the inode number.
|
||||
If the
|
||||
.Pa lost+found
|
||||
directory does not exist, it is created.
|
||||
If there is insufficient space its size is increased.
|
||||
.Pp
|
||||
Because of inconsistencies between the block device and the buffer cache,
|
||||
the raw device should always be used.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/fstab -compact
|
||||
.It Pa /etc/fstab
|
||||
contains default list of filesystems to check.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
The diagnostics produced by
|
||||
.Nm fsck
|
||||
are fully enumerated and explained in Appendix A of
|
||||
.Rs
|
||||
.%T "Fsck \- The UNIX File System Check Program"
|
||||
.Re
|
||||
.Sh SEE ALSO
|
||||
.Xr fstab 5 ,
|
||||
.Xr fs 5 ,
|
||||
.Xr fsdb 8 ,
|
||||
.Xr newfs 8 ,
|
||||
.Xr mkfs 8 ,
|
||||
.Xr reboot 8
|
||||
543
sbin/fsck_ifs/inode.c
Normal file
543
sbin/fsck_ifs/inode.c
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)inode.c 8.4 (Berkeley) 4/18/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
static ino_t startinum;
|
||||
|
||||
ckinode(dp, idesc)
|
||||
struct dinode *dp;
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register daddr_t *ap;
|
||||
long ret, n, ndb, offset;
|
||||
struct dinode dino;
|
||||
quad_t remsize, sizepb;
|
||||
mode_t mode;
|
||||
|
||||
if (idesc->id_fix != IGNORE)
|
||||
idesc->id_fix = DONTKNOW;
|
||||
idesc->id_entryno = 0;
|
||||
idesc->id_filesize = dp->di_size;
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
|
||||
dp->di_size < sblock.fs_maxsymlinklen))
|
||||
return (KEEPON);
|
||||
dino = *dp;
|
||||
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)
|
||||
idesc->id_numfrags =
|
||||
numfrags(&sblock, fragroundup(&sblock, offset));
|
||||
else
|
||||
idesc->id_numfrags = sblock.fs_frag;
|
||||
if (*ap == 0)
|
||||
continue;
|
||||
idesc->id_blkno = *ap;
|
||||
if (idesc->id_type == ADDR)
|
||||
ret = (*idesc->id_func)(idesc);
|
||||
else
|
||||
ret = dirscan(idesc);
|
||||
if (ret & STOP)
|
||||
return (ret);
|
||||
}
|
||||
idesc->id_numfrags = sblock.fs_frag;
|
||||
remsize = dino.di_size - sblock.fs_bsize * NDADDR;
|
||||
sizepb = sblock.fs_bsize;
|
||||
for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
|
||||
if (*ap) {
|
||||
idesc->id_blkno = *ap;
|
||||
ret = iblock(idesc, n, remsize);
|
||||
if (ret & STOP)
|
||||
return (ret);
|
||||
}
|
||||
sizepb *= NINDIR(&sblock);
|
||||
remsize -= sizepb;
|
||||
}
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
iblock(idesc, ilevel, isize)
|
||||
struct inodesc *idesc;
|
||||
long ilevel;
|
||||
quad_t isize;
|
||||
{
|
||||
register daddr_t *ap;
|
||||
register daddr_t *aplim;
|
||||
register struct bufarea *bp;
|
||||
int i, n, (*func)(), nif;
|
||||
quad_t sizepb;
|
||||
char buf[BUFSIZ];
|
||||
extern int dirscan(), pass1check();
|
||||
|
||||
if (idesc->id_type == ADDR) {
|
||||
func = idesc->id_func;
|
||||
if (((n = (*func)(idesc)) & KEEPON) == 0)
|
||||
return (n);
|
||||
} else
|
||||
func = dirscan;
|
||||
if (chkrange(idesc->id_blkno, idesc->id_numfrags))
|
||||
return (SKIP);
|
||||
bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
|
||||
ilevel--;
|
||||
for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
|
||||
sizepb *= NINDIR(&sblock);
|
||||
nif = howmany(isize , sizepb);
|
||||
if (nif > NINDIR(&sblock))
|
||||
nif = NINDIR(&sblock);
|
||||
if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
|
||||
aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
|
||||
for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
|
||||
if (*ap == 0)
|
||||
continue;
|
||||
(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
|
||||
idesc->id_number);
|
||||
if (dofix(idesc, buf)) {
|
||||
*ap = 0;
|
||||
dirty(bp);
|
||||
}
|
||||
}
|
||||
flush(fswritefd, bp);
|
||||
}
|
||||
aplim = &bp->b_un.b_indir[nif];
|
||||
for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
|
||||
if (*ap) {
|
||||
idesc->id_blkno = *ap;
|
||||
if (ilevel == 0)
|
||||
n = (*func)(idesc);
|
||||
else
|
||||
n = iblock(idesc, ilevel, isize);
|
||||
if (n & STOP) {
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return (n);
|
||||
}
|
||||
}
|
||||
isize -= sizepb;
|
||||
}
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that a block in a legal block number.
|
||||
* Return 0 if in range, 1 if out of range.
|
||||
*/
|
||||
chkrange(blk, cnt)
|
||||
daddr_t blk;
|
||||
int cnt;
|
||||
{
|
||||
register int c;
|
||||
|
||||
if ((unsigned)(blk + cnt) > maxfsblock)
|
||||
return (1);
|
||||
c = dtog(&sblock, blk);
|
||||
if (blk < cgdmin(&sblock, c)) {
|
||||
if ((blk + cnt) > cgsblock(&sblock, c)) {
|
||||
if (debug) {
|
||||
printf("blk %ld < cgdmin %ld;",
|
||||
blk, cgdmin(&sblock, c));
|
||||
printf(" blk + cnt %ld > cgsbase %ld\n",
|
||||
blk + cnt, cgsblock(&sblock, c));
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
if ((blk + cnt) > cgbase(&sblock, c+1)) {
|
||||
if (debug) {
|
||||
printf("blk %ld >= cgdmin %ld;",
|
||||
blk, cgdmin(&sblock, c));
|
||||
printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
|
||||
blk+cnt, sblock.fs_fpg);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* General purpose interface for reading inodes.
|
||||
*/
|
||||
struct dinode *
|
||||
ginode(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
daddr_t iblk;
|
||||
|
||||
if (inumber < ROOTINO || inumber > maxino)
|
||||
errexit("bad inode number %d to ginode\n", inumber);
|
||||
if (startinum == 0 ||
|
||||
inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
|
||||
iblk = ino_to_fsba(&sblock, inumber);
|
||||
if (pbp != 0)
|
||||
pbp->b_flags &= ~B_INUSE;
|
||||
pbp = getdatablk(iblk, sblock.fs_bsize);
|
||||
startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
|
||||
}
|
||||
return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special purpose version of ginode used to optimize first pass
|
||||
* over all the inodes in numerical order.
|
||||
*/
|
||||
ino_t nextino, lastinum;
|
||||
long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
|
||||
struct dinode *inodebuf;
|
||||
|
||||
struct dinode *
|
||||
getnextinode(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
long size;
|
||||
daddr_t dblk;
|
||||
static struct dinode *dp;
|
||||
|
||||
if (inumber != nextino++ || inumber > maxino)
|
||||
errexit("bad inode number %d to nextinode\n", inumber);
|
||||
if (inumber >= lastinum) {
|
||||
readcnt++;
|
||||
dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
|
||||
if (readcnt % readpercg == 0) {
|
||||
size = partialsize;
|
||||
lastinum += partialcnt;
|
||||
} else {
|
||||
size = inobufsize;
|
||||
lastinum += fullcnt;
|
||||
}
|
||||
(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
|
||||
dp = inodebuf;
|
||||
}
|
||||
return (dp++);
|
||||
}
|
||||
|
||||
resetinodebuf()
|
||||
{
|
||||
|
||||
startinum = 0;
|
||||
nextino = 0;
|
||||
lastinum = 0;
|
||||
readcnt = 0;
|
||||
inobufsize = blkroundup(&sblock, INOBUFSIZE);
|
||||
fullcnt = inobufsize / sizeof(struct dinode);
|
||||
readpercg = sblock.fs_ipg / fullcnt;
|
||||
partialcnt = sblock.fs_ipg % fullcnt;
|
||||
partialsize = partialcnt * sizeof(struct dinode);
|
||||
if (partialcnt != 0) {
|
||||
readpercg++;
|
||||
} else {
|
||||
partialcnt = fullcnt;
|
||||
partialsize = inobufsize;
|
||||
}
|
||||
if (inodebuf == NULL &&
|
||||
(inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
|
||||
errexit("Cannot allocate space for inode buffer\n");
|
||||
while (nextino < ROOTINO)
|
||||
(void)getnextinode(nextino);
|
||||
}
|
||||
|
||||
freeinodebuf()
|
||||
{
|
||||
|
||||
if (inodebuf != NULL)
|
||||
free((char *)inodebuf);
|
||||
inodebuf = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines to maintain information about directory inodes.
|
||||
* This is built during the first pass and used during the
|
||||
* second and third passes.
|
||||
*
|
||||
* Enter inodes into the cache.
|
||||
*/
|
||||
cacheino(dp, inumber)
|
||||
register struct dinode *dp;
|
||||
ino_t inumber;
|
||||
{
|
||||
register struct inoinfo *inp;
|
||||
struct inoinfo **inpp;
|
||||
unsigned int blks;
|
||||
|
||||
blks = howmany(dp->di_size, sblock.fs_bsize);
|
||||
if (blks > NDADDR)
|
||||
blks = NDADDR + NIADDR;
|
||||
inp = (struct inoinfo *)
|
||||
malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
|
||||
if (inp == NULL)
|
||||
return;
|
||||
inpp = &inphead[inumber % numdirs];
|
||||
inp->i_nexthash = *inpp;
|
||||
*inpp = inp;
|
||||
inp->i_parent = (ino_t)0;
|
||||
inp->i_dotdot = (ino_t)0;
|
||||
inp->i_number = inumber;
|
||||
inp->i_isize = dp->di_size;
|
||||
inp->i_numblks = blks * sizeof(daddr_t);
|
||||
bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
|
||||
(size_t)inp->i_numblks);
|
||||
if (inplast == listmax) {
|
||||
listmax += 100;
|
||||
inpsort = (struct inoinfo **)realloc((char *)inpsort,
|
||||
(unsigned)listmax * sizeof(struct inoinfo *));
|
||||
if (inpsort == NULL)
|
||||
errexit("cannot increase directory list");
|
||||
}
|
||||
inpsort[inplast++] = inp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an inode cache structure.
|
||||
*/
|
||||
struct inoinfo *
|
||||
getinoinfo(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
register struct inoinfo *inp;
|
||||
|
||||
for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
|
||||
if (inp->i_number != inumber)
|
||||
continue;
|
||||
return (inp);
|
||||
}
|
||||
errexit("cannot find inode %d\n", inumber);
|
||||
return ((struct inoinfo *)0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up all the inode cache structure.
|
||||
*/
|
||||
inocleanup()
|
||||
{
|
||||
register struct inoinfo **inpp;
|
||||
|
||||
if (inphead == NULL)
|
||||
return;
|
||||
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
|
||||
free((char *)(*inpp));
|
||||
free((char *)inphead);
|
||||
free((char *)inpsort);
|
||||
inphead = inpsort = NULL;
|
||||
}
|
||||
|
||||
inodirty()
|
||||
{
|
||||
|
||||
dirty(pbp);
|
||||
}
|
||||
|
||||
clri(idesc, type, flag)
|
||||
register struct inodesc *idesc;
|
||||
char *type;
|
||||
int flag;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
|
||||
dp = ginode(idesc->id_number);
|
||||
if (flag == 1) {
|
||||
pwarn("%s %s", type,
|
||||
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
|
||||
pinode(idesc->id_number);
|
||||
}
|
||||
if (preen || reply("CLEAR") == 1) {
|
||||
if (preen)
|
||||
printf(" (CLEARED)\n");
|
||||
n_files--;
|
||||
(void)ckinode(dp, idesc);
|
||||
clearinode(dp);
|
||||
statemap[idesc->id_number] = USTATE;
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
|
||||
findname(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (dirp->d_ino != idesc->id_parent)
|
||||
return (KEEPON);
|
||||
bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
|
||||
return (STOP|FOUND);
|
||||
}
|
||||
|
||||
findino(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (dirp->d_ino == 0)
|
||||
return (KEEPON);
|
||||
if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
|
||||
dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
|
||||
idesc->id_parent = dirp->d_ino;
|
||||
return (STOP|FOUND);
|
||||
}
|
||||
return (KEEPON);
|
||||
}
|
||||
|
||||
pinode(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register char *p;
|
||||
struct passwd *pw;
|
||||
char *ctime();
|
||||
|
||||
printf(" I=%lu ", ino);
|
||||
if (ino < ROOTINO || ino > maxino)
|
||||
return;
|
||||
dp = ginode(ino);
|
||||
printf(" OWNER=");
|
||||
if ((pw = getpwuid((int)dp->di_uid)) != 0)
|
||||
printf("%s ", pw->pw_name);
|
||||
else
|
||||
printf("%u ", (unsigned)dp->di_uid);
|
||||
printf("MODE=%o\n", dp->di_mode);
|
||||
if (preen)
|
||||
printf("%s: ", cdevname);
|
||||
printf("SIZE=%qu ", dp->di_size);
|
||||
p = ctime(&dp->di_mtime.ts_sec);
|
||||
printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
|
||||
}
|
||||
|
||||
blkerror(ino, type, blk)
|
||||
ino_t ino;
|
||||
char *type;
|
||||
daddr_t blk;
|
||||
{
|
||||
|
||||
pfatal("%ld %s I=%lu", blk, type, ino);
|
||||
printf("\n");
|
||||
switch (statemap[ino]) {
|
||||
|
||||
case FSTATE:
|
||||
statemap[ino] = FCLEAR;
|
||||
return;
|
||||
|
||||
case DSTATE:
|
||||
statemap[ino] = DCLEAR;
|
||||
return;
|
||||
|
||||
case FCLEAR:
|
||||
case DCLEAR:
|
||||
return;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d TO BLKERR", statemap[ino]);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate an unused inode
|
||||
*/
|
||||
ino_t
|
||||
allocino(request, type)
|
||||
ino_t request;
|
||||
int type;
|
||||
{
|
||||
register ino_t ino;
|
||||
register struct dinode *dp;
|
||||
|
||||
if (request == 0)
|
||||
request = ROOTINO;
|
||||
else if (statemap[request] != USTATE)
|
||||
return (0);
|
||||
for (ino = request; ino < maxino; ino++)
|
||||
if (statemap[ino] == USTATE)
|
||||
break;
|
||||
if (ino == maxino)
|
||||
return (0);
|
||||
switch (type & IFMT) {
|
||||
case IFDIR:
|
||||
statemap[ino] = DSTATE;
|
||||
break;
|
||||
case IFREG:
|
||||
case IFLNK:
|
||||
statemap[ino] = FSTATE;
|
||||
break;
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
dp = ginode(ino);
|
||||
dp->di_db[0] = allocblk((long)1);
|
||||
if (dp->di_db[0] == 0) {
|
||||
statemap[ino] = USTATE;
|
||||
return (0);
|
||||
}
|
||||
dp->di_mode = type;
|
||||
(void)time(&dp->di_atime.ts_sec);
|
||||
dp->di_mtime = dp->di_ctime = dp->di_atime;
|
||||
dp->di_size = sblock.fs_fsize;
|
||||
dp->di_blocks = btodb(sblock.fs_fsize);
|
||||
n_files++;
|
||||
inodirty();
|
||||
if (newinofmt)
|
||||
typemap[ino] = IFTODT(type);
|
||||
return (ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* deallocate an inode
|
||||
*/
|
||||
freeino(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
extern int pass4check();
|
||||
struct dinode *dp;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
idesc.id_number = ino;
|
||||
dp = ginode(ino);
|
||||
(void)ckinode(dp, &idesc);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
statemap[ino] = USTATE;
|
||||
n_files--;
|
||||
}
|
||||
318
sbin/fsck_ifs/main.c
Normal file
318
sbin/fsck_ifs/main.c
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1980, 1986, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/23/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mount.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <fstab.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "fsck.h"
|
||||
|
||||
void catch(), catchquit(), voidquit();
|
||||
int returntosingle;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch;
|
||||
int ret, maxrun = 0;
|
||||
extern int docheck(), checkfilesys();
|
||||
extern char *optarg, *blockcheck();
|
||||
extern int optind;
|
||||
|
||||
sync();
|
||||
while ((ch = getopt(argc, argv, "dpnNyYb:c:l:m:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
preen++;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
bflag = argtoi('b', "number", optarg, 10);
|
||||
printf("Alternate super block location: %d\n", bflag);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
cvtlevel = argtoi('c', "conversion level", optarg, 10);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
maxrun = argtoi('l', "number", optarg, 10);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
lfmode = argtoi('m', "mode", optarg, 8);
|
||||
if (lfmode &~ 07777)
|
||||
errexit("bad mode to -m: %o\n", lfmode);
|
||||
printf("** lost+found creation mode %o\n", lfmode);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
nflag++;
|
||||
yflag = 0;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
case 'Y':
|
||||
yflag++;
|
||||
nflag = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("%c option?\n", ch);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
(void)signal(SIGINT, catch);
|
||||
if (preen)
|
||||
(void)signal(SIGQUIT, catchquit);
|
||||
if (argc) {
|
||||
while (argc-- > 0)
|
||||
(void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
|
||||
exit(0);
|
||||
}
|
||||
ret = checkfstab(preen, maxrun, docheck, checkfilesys);
|
||||
if (returntosingle)
|
||||
exit(2);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
argtoi(flag, req, str, base)
|
||||
int flag;
|
||||
char *req, *str;
|
||||
int base;
|
||||
{
|
||||
char *cp;
|
||||
int ret;
|
||||
|
||||
ret = (int)strtol(str, &cp, base);
|
||||
if (cp == str || *cp)
|
||||
errexit("-%c flag requires a %s\n", flag, req);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether a filesystem should be checked.
|
||||
*/
|
||||
docheck(fsp)
|
||||
register struct fstab *fsp;
|
||||
{
|
||||
|
||||
if (strcmp(fsp->fs_vfstype, "ufs") ||
|
||||
(strcmp(fsp->fs_type, FSTAB_RW) &&
|
||||
strcmp(fsp->fs_type, FSTAB_RO)) ||
|
||||
fsp->fs_passno == 0)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the specified filesystem.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
checkfilesys(filesys, mntpt, auxdata, child)
|
||||
char *filesys, *mntpt;
|
||||
long auxdata;
|
||||
{
|
||||
daddr_t n_ffree, n_bfree;
|
||||
struct dups *dp;
|
||||
struct zlncnt *zlnp;
|
||||
int cylno;
|
||||
|
||||
if (preen && child)
|
||||
(void)signal(SIGQUIT, voidquit);
|
||||
cdevname = filesys;
|
||||
if (debug && preen)
|
||||
pwarn("starting\n");
|
||||
if (setup(filesys) == 0) {
|
||||
if (preen)
|
||||
pfatal("CAN'T CHECK FILE SYSTEM.");
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* 1: scan inodes tallying blocks used
|
||||
*/
|
||||
if (preen == 0) {
|
||||
printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
|
||||
if (hotroot)
|
||||
printf("** Root file system\n");
|
||||
printf("** Phase 1 - Check Blocks and Sizes\n");
|
||||
}
|
||||
pass1();
|
||||
|
||||
/*
|
||||
* 1b: locate first references to duplicates, if any
|
||||
*/
|
||||
if (duplist) {
|
||||
if (preen)
|
||||
pfatal("INTERNAL ERROR: dups with -p");
|
||||
printf("** Phase 1b - Rescan For More DUPS\n");
|
||||
pass1b();
|
||||
}
|
||||
|
||||
/*
|
||||
* 2: traverse directories from root to mark all connected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 2 - Check Pathnames\n");
|
||||
pass2();
|
||||
|
||||
/*
|
||||
* 3: scan inodes looking for disconnected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 3 - Check Connectivity\n");
|
||||
pass3();
|
||||
|
||||
/*
|
||||
* 4: scan inodes looking for disconnected files; check reference counts
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 4 - Check Reference Counts\n");
|
||||
pass4();
|
||||
|
||||
/*
|
||||
* 5: check and repair resource counts in cylinder groups
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 5 - Check Cyl groups\n");
|
||||
pass5();
|
||||
|
||||
/*
|
||||
* print out summary statistics
|
||||
*/
|
||||
n_ffree = sblock.fs_cstotal.cs_nffree;
|
||||
n_bfree = sblock.fs_cstotal.cs_nbfree;
|
||||
pwarn("%ld files, %ld used, %ld free ",
|
||||
n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
|
||||
printf("(%ld frags, %ld blocks, %d.%d%% fragmentation)\n",
|
||||
n_ffree, n_bfree, (n_ffree * 100) / sblock.fs_dsize,
|
||||
((n_ffree * 1000 + sblock.fs_dsize / 2) / sblock.fs_dsize) % 10);
|
||||
if (debug &&
|
||||
(n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
|
||||
printf("%ld files missing\n", n_files);
|
||||
if (debug) {
|
||||
n_blks += sblock.fs_ncg *
|
||||
(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
|
||||
n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
|
||||
n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
|
||||
printf("%ld blocks missing\n", n_blks);
|
||||
if (duplist != NULL) {
|
||||
printf("The following duplicate blocks remain:");
|
||||
for (dp = duplist; dp; dp = dp->next)
|
||||
printf(" %ld,", dp->dup);
|
||||
printf("\n");
|
||||
}
|
||||
if (zlnhead != NULL) {
|
||||
printf("The following zero link count inodes remain:");
|
||||
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
|
||||
printf(" %lu,", zlnp->zlncnt);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
zlnhead = (struct zlncnt *)0;
|
||||
duplist = (struct dups *)0;
|
||||
muldup = (struct dups *)0;
|
||||
inocleanup();
|
||||
if (fsmodified) {
|
||||
(void)time(&sblock.fs_time);
|
||||
sbdirty();
|
||||
}
|
||||
if (cvtlevel && sblk.b_dirty) {
|
||||
/*
|
||||
* Write out the duplicate super blocks
|
||||
*/
|
||||
for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
|
||||
bwrite(fswritefd, (char *)&sblock,
|
||||
fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE);
|
||||
}
|
||||
ckfini();
|
||||
free(blockmap);
|
||||
free(statemap);
|
||||
free((char *)lncntp);
|
||||
if (!fsmodified)
|
||||
return (0);
|
||||
if (!preen)
|
||||
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
|
||||
if (hotroot) {
|
||||
struct statfs stfs_buf;
|
||||
/*
|
||||
* We modified the root. Do a mount update on
|
||||
* it, unless it is read-write, so we can continue.
|
||||
*/
|
||||
if (statfs("/", &stfs_buf) == 0) {
|
||||
long flags = stfs_buf.f_flags;
|
||||
struct ufs_args args;
|
||||
int ret;
|
||||
|
||||
if (flags & MNT_RDONLY) {
|
||||
args.fspec = 0;
|
||||
args.export.ex_flags = 0;
|
||||
args.export.ex_root = 0;
|
||||
flags |= MNT_UPDATE | MNT_RELOAD;
|
||||
ret = mount(MOUNT_UFS, "/", flags, &args);
|
||||
if (ret == 0)
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (!preen)
|
||||
printf("\n***** REBOOT NOW *****\n");
|
||||
sync();
|
||||
return (4);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
314
sbin/fsck_ifs/pass1.c
Normal file
314
sbin/fsck_ifs/pass1.c
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
static daddr_t badblk;
|
||||
static daddr_t dupblk;
|
||||
int pass1check();
|
||||
struct dinode *getnextinode();
|
||||
|
||||
pass1()
|
||||
{
|
||||
ino_t inumber;
|
||||
int c, i, cgd;
|
||||
struct inodesc idesc;
|
||||
|
||||
/*
|
||||
* Set file system reserved blocks in used block map.
|
||||
*/
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
cgd = cgdmin(&sblock, c);
|
||||
if (c == 0) {
|
||||
i = cgbase(&sblock, c);
|
||||
cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
|
||||
} else
|
||||
i = cgsblock(&sblock, c);
|
||||
for (; i < cgd; i++)
|
||||
setbmap(i);
|
||||
}
|
||||
/*
|
||||
* Find all allocated blocks.
|
||||
*/
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass1check;
|
||||
inumber = 0;
|
||||
n_files = n_blks = 0;
|
||||
resetinodebuf();
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
|
||||
if (inumber < ROOTINO)
|
||||
continue;
|
||||
checkinode(inumber, &idesc);
|
||||
}
|
||||
}
|
||||
freeinodebuf();
|
||||
}
|
||||
|
||||
checkinode(inumber, idesc)
|
||||
ino_t inumber;
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
struct zlncnt *zlnp;
|
||||
int ndb, j;
|
||||
mode_t mode;
|
||||
char symbuf[MAXSYMLINKLEN];
|
||||
|
||||
dp = getnextinode(inumber);
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == 0) {
|
||||
if (bcmp((char *)dp->di_db, (char *)zino.di_db,
|
||||
NDADDR * sizeof(daddr_t)) ||
|
||||
bcmp((char *)dp->di_ib, (char *)zino.di_ib,
|
||||
NIADDR * sizeof(daddr_t)) ||
|
||||
dp->di_mode || dp->di_size) {
|
||||
pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
|
||||
if (reply("CLEAR") == 1) {
|
||||
dp = ginode(inumber);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
statemap[inumber] = USTATE;
|
||||
return;
|
||||
}
|
||||
lastino = inumber;
|
||||
if (/* dp->di_size < 0 || */
|
||||
dp->di_size + sblock.fs_bsize - 1 < dp->di_size) {
|
||||
if (debug)
|
||||
printf("bad size %qu:", dp->di_size);
|
||||
goto unknown;
|
||||
}
|
||||
if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
|
||||
dp = ginode(inumber);
|
||||
dp->di_size = sblock.fs_fsize;
|
||||
dp->di_mode = IFREG|0600;
|
||||
inodirty();
|
||||
}
|
||||
ndb = howmany(dp->di_size, sblock.fs_bsize);
|
||||
if (ndb < 0) {
|
||||
if (debug)
|
||||
printf("bad size %qu ndb %d:",
|
||||
dp->di_size, ndb);
|
||||
goto unknown;
|
||||
}
|
||||
if (mode == IFBLK || mode == IFCHR)
|
||||
ndb++;
|
||||
if (mode == IFLNK) {
|
||||
if (doinglevel2 &&
|
||||
dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
|
||||
dp->di_blocks != 0) {
|
||||
if (bread(fsreadfd, symbuf,
|
||||
fsbtodb(&sblock, dp->di_db[0]),
|
||||
(long)dp->di_size) != 0)
|
||||
errexit("cannot read symlink");
|
||||
if (debug) {
|
||||
symbuf[dp->di_size] = 0;
|
||||
printf("convert symlink %d(%s) of size %d\n",
|
||||
inumber, symbuf, (long)dp->di_size);
|
||||
}
|
||||
dp = ginode(inumber);
|
||||
bcopy(symbuf, (caddr_t)dp->di_shortlink,
|
||||
(long)dp->di_size);
|
||||
dp->di_blocks = 0;
|
||||
inodirty();
|
||||
}
|
||||
/*
|
||||
* Fake ndb value so direct/indirect block checks below
|
||||
* will detect any garbage after symlink string.
|
||||
*/
|
||||
if (dp->di_size < sblock.fs_maxsymlinklen) {
|
||||
ndb = howmany(dp->di_size, sizeof(daddr_t));
|
||||
if (ndb > NDADDR) {
|
||||
j = ndb - NDADDR;
|
||||
for (ndb = 1; j > 1; j--)
|
||||
ndb *= NINDIR(&sblock);
|
||||
ndb += NDADDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = ndb; j < NDADDR; j++)
|
||||
if (dp->di_db[j] != 0) {
|
||||
if (debug)
|
||||
printf("bad direct addr: %ld\n", dp->di_db[j]);
|
||||
goto unknown;
|
||||
}
|
||||
for (j = 0, ndb -= NDADDR; ndb > 0; j++)
|
||||
ndb /= NINDIR(&sblock);
|
||||
for (; j < NIADDR; j++)
|
||||
if (dp->di_ib[j] != 0) {
|
||||
if (debug)
|
||||
printf("bad indirect addr: %ld\n",
|
||||
dp->di_ib[j]);
|
||||
goto unknown;
|
||||
}
|
||||
if (ftypeok(dp) == 0)
|
||||
goto unknown;
|
||||
n_files++;
|
||||
lncntp[inumber] = dp->di_nlink;
|
||||
if (dp->di_nlink <= 0) {
|
||||
zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
|
||||
if (zlnp == NULL) {
|
||||
pfatal("LINK COUNT TABLE OVERFLOW");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
} else {
|
||||
zlnp->zlncnt = inumber;
|
||||
zlnp->next = zlnhead;
|
||||
zlnhead = zlnp;
|
||||
}
|
||||
}
|
||||
if (mode == IFDIR) {
|
||||
if (dp->di_size == 0)
|
||||
statemap[inumber] = DCLEAR;
|
||||
else
|
||||
statemap[inumber] = DSTATE;
|
||||
cacheino(dp, inumber);
|
||||
} else
|
||||
statemap[inumber] = FSTATE;
|
||||
typemap[inumber] = IFTODT(mode);
|
||||
if (doinglevel2 &&
|
||||
(dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
|
||||
dp = ginode(inumber);
|
||||
dp->di_uid = dp->di_ouid;
|
||||
dp->di_ouid = -1;
|
||||
dp->di_gid = dp->di_ogid;
|
||||
dp->di_ogid = -1;
|
||||
inodirty();
|
||||
}
|
||||
badblk = dupblk = 0;
|
||||
idesc->id_number = inumber;
|
||||
(void)ckinode(dp, idesc);
|
||||
idesc->id_entryno *= btodb(sblock.fs_fsize);
|
||||
if (dp->di_blocks != idesc->id_entryno) {
|
||||
pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
|
||||
inumber, dp->di_blocks, idesc->id_entryno);
|
||||
if (preen)
|
||||
printf(" (CORRECTED)\n");
|
||||
else if (reply("CORRECT") == 0)
|
||||
return;
|
||||
dp = ginode(inumber);
|
||||
dp->di_blocks = idesc->id_entryno;
|
||||
inodirty();
|
||||
}
|
||||
return;
|
||||
unknown:
|
||||
pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
|
||||
statemap[inumber] = FCLEAR;
|
||||
if (reply("CLEAR") == 1) {
|
||||
statemap[inumber] = USTATE;
|
||||
dp = ginode(inumber);
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
}
|
||||
}
|
||||
|
||||
pass1check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
int res = KEEPON;
|
||||
int anyout, nfrags;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
register struct dups *dlp;
|
||||
struct dups *new;
|
||||
|
||||
if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
|
||||
blkerror(idesc->id_number, "BAD", blkno);
|
||||
if (badblk++ >= MAXBAD) {
|
||||
pwarn("EXCESSIVE BAD BLKS I=%lu",
|
||||
idesc->id_number);
|
||||
if (preen)
|
||||
printf(" (SKIPPING)\n");
|
||||
else if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
}
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (anyout && chkrange(blkno, 1)) {
|
||||
res = SKIP;
|
||||
} else if (!testbmap(blkno)) {
|
||||
n_blks++;
|
||||
setbmap(blkno);
|
||||
} else {
|
||||
blkerror(idesc->id_number, "DUP", blkno);
|
||||
if (dupblk++ >= MAXDUP) {
|
||||
pwarn("EXCESSIVE DUP BLKS I=%lu",
|
||||
idesc->id_number);
|
||||
if (preen)
|
||||
printf(" (SKIPPING)\n");
|
||||
else if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
new = (struct dups *)malloc(sizeof(struct dups));
|
||||
if (new == NULL) {
|
||||
pfatal("DUP TABLE OVERFLOW.");
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
return (STOP);
|
||||
}
|
||||
new->dup = blkno;
|
||||
if (muldup == 0) {
|
||||
duplist = muldup = new;
|
||||
new->next = 0;
|
||||
} else {
|
||||
new->next = muldup->next;
|
||||
muldup->next = new;
|
||||
}
|
||||
for (dlp = duplist; dlp != muldup; dlp = dlp->next)
|
||||
if (dlp->dup == blkno)
|
||||
break;
|
||||
if (dlp == muldup && dlp->dup != blkno)
|
||||
muldup = new;
|
||||
}
|
||||
/*
|
||||
* count the number of blocks found in id_entryno
|
||||
*/
|
||||
idesc->id_entryno++;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
99
sbin/fsck_ifs/pass1b.c
Normal file
99
sbin/fsck_ifs/pass1b.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass1b.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
int pass1bcheck();
|
||||
static struct dups *duphead;
|
||||
|
||||
pass1b()
|
||||
{
|
||||
register int c, i;
|
||||
register struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
ino_t inumber;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass1bcheck;
|
||||
duphead = duplist;
|
||||
inumber = 0;
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
|
||||
if (inumber < ROOTINO)
|
||||
continue;
|
||||
dp = ginode(inumber);
|
||||
if (dp == NULL)
|
||||
continue;
|
||||
idesc.id_number = inumber;
|
||||
if (statemap[inumber] != USTATE &&
|
||||
(ckinode(dp, &idesc) & STOP))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass1bcheck(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (chkrange(blkno, 1))
|
||||
res = SKIP;
|
||||
for (dlp = duphead; dlp; dlp = dlp->next) {
|
||||
if (dlp->dup == blkno) {
|
||||
blkerror(idesc->id_number, "DUP", blkno);
|
||||
dlp->dup = duphead->dup;
|
||||
duphead->dup = blkno;
|
||||
duphead = duphead->next;
|
||||
}
|
||||
if (dlp == muldup)
|
||||
break;
|
||||
}
|
||||
if (muldup == 0 || duphead == muldup->next)
|
||||
return (STOP);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
430
sbin/fsck_ifs/pass2.c
Normal file
430
sbin/fsck_ifs/pass2.c
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass2.c 8.2 (Berkeley) 2/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
#define MINDIRSIZE (sizeof (struct dirtemplate))
|
||||
|
||||
int pass2check(), blksort();
|
||||
|
||||
pass2()
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpend;
|
||||
struct inodesc curino;
|
||||
struct dinode dino;
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
switch (statemap[ROOTINO]) {
|
||||
|
||||
case USTATE:
|
||||
pfatal("ROOT INODE UNALLOCATED");
|
||||
if (reply("ALLOCATE") == 0)
|
||||
errexit("");
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
pfatal("DUPS/BAD IN ROOT INODE");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
}
|
||||
if (reply("CONTINUE") == 0)
|
||||
errexit("");
|
||||
break;
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
pfatal("ROOT INODE NOT DIRECTORY");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errexit("CANNOT ALLOCATE ROOT INODE\n");
|
||||
break;
|
||||
}
|
||||
if (reply("FIX") == 0)
|
||||
errexit("");
|
||||
dp = ginode(ROOTINO);
|
||||
dp->di_mode &= ~IFMT;
|
||||
dp->di_mode |= IFDIR;
|
||||
inodirty();
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
|
||||
}
|
||||
statemap[ROOTINO] = DFOUND;
|
||||
/*
|
||||
* Sort the directory list into disk block order.
|
||||
*/
|
||||
qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
|
||||
/*
|
||||
* Check the integrity of each directory.
|
||||
*/
|
||||
bzero((char *)&curino, sizeof(struct inodesc));
|
||||
curino.id_type = DATA;
|
||||
curino.id_func = pass2check;
|
||||
dp = &dino;
|
||||
inpend = &inpsort[inplast];
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_isize == 0)
|
||||
continue;
|
||||
if (inp->i_isize < MINDIRSIZE) {
|
||||
direrror(inp->i_number, "DIRECTORY TOO SHORT");
|
||||
inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
|
||||
if (reply("FIX") == 1) {
|
||||
dp = ginode(inp->i_number);
|
||||
dp->di_size = inp->i_isize;
|
||||
inodirty();
|
||||
dp = &dino;
|
||||
}
|
||||
} else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
|
||||
getpathname(pathbuf, inp->i_number, inp->i_number);
|
||||
pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
|
||||
pathbuf, inp->i_isize, DIRBLKSIZ);
|
||||
if (preen)
|
||||
printf(" (ADJUSTED)\n");
|
||||
inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
|
||||
if (preen || reply("ADJUST") == 1) {
|
||||
dp = ginode(inp->i_number);
|
||||
dp->di_size = roundup(inp->i_isize, DIRBLKSIZ);
|
||||
inodirty();
|
||||
dp = &dino;
|
||||
}
|
||||
}
|
||||
bzero((char *)&dino, sizeof(struct dinode));
|
||||
dino.di_mode = IFDIR;
|
||||
dp->di_size = inp->i_isize;
|
||||
bcopy((char *)&inp->i_blks[0], (char *)&dp->di_db[0],
|
||||
(size_t)inp->i_numblks);
|
||||
curino.id_number = inp->i_number;
|
||||
curino.id_parent = inp->i_parent;
|
||||
(void)ckinode(dp, &curino);
|
||||
}
|
||||
/*
|
||||
* Now that the parents of all directories have been found,
|
||||
* make another pass to verify the value of `..'
|
||||
*/
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0 || inp->i_isize == 0)
|
||||
continue;
|
||||
if (statemap[inp->i_parent] == DFOUND &&
|
||||
statemap[inp->i_number] == DSTATE)
|
||||
statemap[inp->i_number] = DFOUND;
|
||||
if (inp->i_dotdot == inp->i_parent ||
|
||||
inp->i_dotdot == (ino_t)-1)
|
||||
continue;
|
||||
if (inp->i_dotdot == 0) {
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
|
||||
if (reply("FIX") == 0)
|
||||
continue;
|
||||
(void)makeentry(inp->i_number, inp->i_parent, "..");
|
||||
lncntp[inp->i_parent]--;
|
||||
continue;
|
||||
}
|
||||
fileerror(inp->i_parent, inp->i_number,
|
||||
"BAD INODE NUMBER FOR '..'");
|
||||
if (reply("FIX") == 0)
|
||||
continue;
|
||||
lncntp[inp->i_dotdot]++;
|
||||
lncntp[inp->i_parent]--;
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
(void)changeino(inp->i_number, "..", inp->i_parent);
|
||||
}
|
||||
/*
|
||||
* Mark all the directories that can be found from the root.
|
||||
*/
|
||||
propagate();
|
||||
}
|
||||
|
||||
pass2check(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
register struct inoinfo *inp;
|
||||
int n, entrysize, ret = 0;
|
||||
struct dinode *dp;
|
||||
char *errmsg;
|
||||
struct direct proto;
|
||||
char namebuf[MAXPATHLEN + 1];
|
||||
char pathbuf[MAXPATHLEN + 1];
|
||||
|
||||
/*
|
||||
* If converting, set directory entry type.
|
||||
*/
|
||||
if (doinglevel2 && dirp->d_ino > 0 && dirp->d_ino < maxino) {
|
||||
dirp->d_type = typemap[dirp->d_ino];
|
||||
ret |= ALTERED;
|
||||
}
|
||||
/*
|
||||
* check for "."
|
||||
*/
|
||||
if (idesc->id_entryno != 0)
|
||||
goto chk1;
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
|
||||
if (dirp->d_ino != idesc->id_number) {
|
||||
direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
|
||||
dirp->d_ino = idesc->id_number;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
if (newinofmt && dirp->d_type != DT_DIR) {
|
||||
direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
|
||||
dirp->d_type = DT_DIR;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
goto chk1;
|
||||
}
|
||||
direrror(idesc->id_number, "MISSING '.'");
|
||||
proto.d_ino = idesc->id_number;
|
||||
if (newinofmt)
|
||||
proto.d_type = DT_DIR;
|
||||
else
|
||||
proto.d_type = 0;
|
||||
proto.d_namlen = 1;
|
||||
(void)strcpy(proto.d_name, ".");
|
||||
entrysize = DIRSIZ(0, &proto);
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
|
||||
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||
dirp->d_name);
|
||||
} 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, (size_t)entrysize);
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
} else {
|
||||
n = dirp->d_reclen - entrysize;
|
||||
proto.d_reclen = entrysize;
|
||||
bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
|
||||
idesc->id_entryno++;
|
||||
lncntp[dirp->d_ino]--;
|
||||
dirp = (struct direct *)((char *)(dirp) + entrysize);
|
||||
bzero((char *)dirp, (size_t)n);
|
||||
dirp->d_reclen = n;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
chk1:
|
||||
if (idesc->id_entryno > 1)
|
||||
goto chk2;
|
||||
inp = getinoinfo(idesc->id_number);
|
||||
proto.d_ino = inp->i_parent;
|
||||
if (newinofmt)
|
||||
proto.d_type = DT_DIR;
|
||||
else
|
||||
proto.d_type = 0;
|
||||
proto.d_namlen = 2;
|
||||
(void)strcpy(proto.d_name, "..");
|
||||
entrysize = DIRSIZ(0, &proto);
|
||||
if (idesc->id_entryno == 0) {
|
||||
n = DIRSIZ(0, dirp);
|
||||
if (dirp->d_reclen < n + entrysize)
|
||||
goto chk2;
|
||||
proto.d_reclen = dirp->d_reclen - n;
|
||||
dirp->d_reclen = n;
|
||||
idesc->id_entryno++;
|
||||
lncntp[dirp->d_ino]--;
|
||||
dirp = (struct direct *)((char *)(dirp) + n);
|
||||
bzero((char *)dirp, (size_t)proto.d_reclen);
|
||||
dirp->d_reclen = proto.d_reclen;
|
||||
}
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
|
||||
inp->i_dotdot = dirp->d_ino;
|
||||
if (newinofmt && dirp->d_type != DT_DIR) {
|
||||
direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
|
||||
dirp->d_type = DT_DIR;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
goto chk2;
|
||||
}
|
||||
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
|
||||
dirp->d_name);
|
||||
inp->i_dotdot = (ino_t)-1;
|
||||
} else if (dirp->d_reclen < entrysize) {
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
|
||||
inp->i_dotdot = (ino_t)-1;
|
||||
} else if (inp->i_parent != 0) {
|
||||
/*
|
||||
* We know the parent, so fix now.
|
||||
*/
|
||||
inp->i_dotdot = inp->i_parent;
|
||||
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
|
||||
proto.d_reclen = dirp->d_reclen;
|
||||
bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
idesc->id_entryno++;
|
||||
if (dirp->d_ino != 0)
|
||||
lncntp[dirp->d_ino]--;
|
||||
return (ret|KEEPON);
|
||||
chk2:
|
||||
if (dirp->d_ino == 0)
|
||||
return (ret|KEEPON);
|
||||
if (dirp->d_namlen <= 2 &&
|
||||
dirp->d_name[0] == '.' &&
|
||||
idesc->id_entryno >= 2) {
|
||||
if (dirp->d_namlen == 1) {
|
||||
direrror(idesc->id_number, "EXTRA '.' ENTRY");
|
||||
dirp->d_ino = 0;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
return (KEEPON | ret);
|
||||
}
|
||||
if (dirp->d_name[1] == '.') {
|
||||
direrror(idesc->id_number, "EXTRA '..' ENTRY");
|
||||
dirp->d_ino = 0;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
return (KEEPON | ret);
|
||||
}
|
||||
}
|
||||
idesc->id_entryno++;
|
||||
n = 0;
|
||||
if (dirp->d_ino > maxino) {
|
||||
fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
|
||||
n = reply("REMOVE");
|
||||
} else {
|
||||
again:
|
||||
switch (statemap[dirp->d_ino]) {
|
||||
case USTATE:
|
||||
if (idesc->id_entryno <= 2)
|
||||
break;
|
||||
fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
|
||||
n = reply("REMOVE");
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
case FCLEAR:
|
||||
if (idesc->id_entryno <= 2)
|
||||
break;
|
||||
if (statemap[dirp->d_ino] == FCLEAR)
|
||||
errmsg = "DUP/BAD";
|
||||
else if (!preen)
|
||||
errmsg = "ZERO LENGTH DIRECTORY";
|
||||
else {
|
||||
n = 1;
|
||||
break;
|
||||
}
|
||||
fileerror(idesc->id_number, dirp->d_ino, errmsg);
|
||||
if ((n = reply("REMOVE")) == 1)
|
||||
break;
|
||||
dp = ginode(dirp->d_ino);
|
||||
statemap[dirp->d_ino] =
|
||||
(dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
|
||||
lncntp[dirp->d_ino] = dp->di_nlink;
|
||||
goto again;
|
||||
|
||||
case DSTATE:
|
||||
if (statemap[idesc->id_number] == DFOUND)
|
||||
statemap[dirp->d_ino] = DFOUND;
|
||||
/* fall through */
|
||||
|
||||
case DFOUND:
|
||||
inp = getinoinfo(dirp->d_ino);
|
||||
if (inp->i_parent != 0 && idesc->id_entryno > 2) {
|
||||
getpathname(pathbuf, idesc->id_number,
|
||||
idesc->id_number);
|
||||
getpathname(namebuf, dirp->d_ino, dirp->d_ino);
|
||||
pwarn("%s %s %s\n", pathbuf,
|
||||
"IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
|
||||
namebuf);
|
||||
if (preen)
|
||||
printf(" (IGNORED)\n");
|
||||
else if ((n = reply("REMOVE")) == 1)
|
||||
break;
|
||||
}
|
||||
if (idesc->id_entryno > 2)
|
||||
inp->i_parent = idesc->id_number;
|
||||
/* fall through */
|
||||
|
||||
case FSTATE:
|
||||
if (newinofmt && dirp->d_type != typemap[dirp->d_ino]) {
|
||||
fileerror(idesc->id_number, dirp->d_ino,
|
||||
"BAD TYPE VALUE");
|
||||
dirp->d_type = typemap[dirp->d_ino];
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
}
|
||||
lncntp[dirp->d_ino]--;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[dirp->d_ino], dirp->d_ino);
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
return (ret|KEEPON);
|
||||
dirp->d_ino = 0;
|
||||
return (ret|KEEPON|ALTERED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to sort disk blocks.
|
||||
*/
|
||||
blksort(inpp1, inpp2)
|
||||
struct inoinfo **inpp1, **inpp2;
|
||||
{
|
||||
|
||||
return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]);
|
||||
}
|
||||
71
sbin/fsck_ifs/pass3.c
Normal file
71
sbin/fsck_ifs/pass3.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass3.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include "fsck.h"
|
||||
|
||||
pass3()
|
||||
{
|
||||
register struct inoinfo **inpp, *inp;
|
||||
ino_t orphan;
|
||||
int loopcnt;
|
||||
|
||||
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
|
||||
inp = *inpp;
|
||||
if (inp->i_number == ROOTINO ||
|
||||
!(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE))
|
||||
continue;
|
||||
if (statemap[inp->i_number] == DCLEAR)
|
||||
continue;
|
||||
for (loopcnt = 0; ; loopcnt++) {
|
||||
orphan = inp->i_number;
|
||||
if (inp->i_parent == 0 ||
|
||||
statemap[inp->i_parent] != DSTATE ||
|
||||
loopcnt > numdirs)
|
||||
break;
|
||||
inp = getinoinfo(inp->i_parent);
|
||||
}
|
||||
(void)linkup(orphan, inp->i_dotdot);
|
||||
inp->i_parent = inp->i_dotdot = lfdir;
|
||||
lncntp[lfdir]--;
|
||||
statemap[orphan] = DFOUND;
|
||||
propagate();
|
||||
}
|
||||
}
|
||||
133
sbin/fsck_ifs/pass4.c
Normal file
133
sbin/fsck_ifs/pass4.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass4.c 8.1 (Berkeley) 6/5/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
int pass4check();
|
||||
|
||||
pass4()
|
||||
{
|
||||
register ino_t inumber;
|
||||
register struct zlncnt *zlnp;
|
||||
struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
int n;
|
||||
|
||||
bzero((char *)&idesc, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass4check;
|
||||
for (inumber = ROOTINO; inumber <= lastino; inumber++) {
|
||||
idesc.id_number = inumber;
|
||||
switch (statemap[inumber]) {
|
||||
|
||||
case FSTATE:
|
||||
case DFOUND:
|
||||
n = lncntp[inumber];
|
||||
if (n)
|
||||
adjust(&idesc, (short)n);
|
||||
else {
|
||||
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
|
||||
if (zlnp->zlncnt == inumber) {
|
||||
zlnp->zlncnt = zlnhead->zlncnt;
|
||||
zlnp = zlnhead;
|
||||
zlnhead = zlnhead->next;
|
||||
free((char *)zlnp);
|
||||
clri(&idesc, "UNREF", 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
clri(&idesc, "UNREF", 1);
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
dp = ginode(inumber);
|
||||
if (dp->di_size == 0) {
|
||||
clri(&idesc, "ZERO LENGTH", 1);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case FCLEAR:
|
||||
clri(&idesc, "BAD/DUP", 1);
|
||||
break;
|
||||
|
||||
case USTATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[inumber], inumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pass4check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (chkrange(blkno, 1)) {
|
||||
res = SKIP;
|
||||
} else if (testbmap(blkno)) {
|
||||
for (dlp = duplist; dlp; dlp = dlp->next) {
|
||||
if (dlp->dup != blkno)
|
||||
continue;
|
||||
dlp->dup = duplist->dup;
|
||||
dlp = duplist;
|
||||
duplist = duplist->next;
|
||||
free((char *)dlp);
|
||||
break;
|
||||
}
|
||||
if (dlp == 0) {
|
||||
clrbmap(blkno);
|
||||
n_blks--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
319
sbin/fsck_ifs/pass5.c
Normal file
319
sbin/fsck_ifs/pass5.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)pass5.c 8.2 (Berkeley) 2/2/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
|
||||
pass5()
|
||||
{
|
||||
int c, blk, frags, basesize, sumsize, mapsize, savednrpos;
|
||||
register struct fs *fs = &sblock;
|
||||
register struct cg *cg = &cgrp;
|
||||
daddr_t dbase, dmax;
|
||||
register daddr_t d;
|
||||
register long i, j;
|
||||
struct csum *cs;
|
||||
struct csum cstotal;
|
||||
struct inodesc idesc[3];
|
||||
char buf[MAXBSIZE];
|
||||
register struct cg *newcg = (struct cg *)buf;
|
||||
struct ocg *ocg = (struct ocg *)buf;
|
||||
|
||||
bzero((char *)newcg, (size_t)fs->fs_cgsize);
|
||||
newcg->cg_niblk = fs->fs_ipg;
|
||||
if (cvtlevel > 3) {
|
||||
if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) {
|
||||
if (preen)
|
||||
pwarn("DELETING CLUSTERING MAPS\n");
|
||||
if (preen || reply("DELETE CLUSTERING MAPS")) {
|
||||
fs->fs_contigsumsize = 0;
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_maxcontig > 1) {
|
||||
char *doit = 0;
|
||||
|
||||
if (fs->fs_contigsumsize < 1) {
|
||||
doit = "CREAT";
|
||||
} else if (fs->fs_contigsumsize < fs->fs_maxcontig &&
|
||||
fs->fs_contigsumsize < FS_MAXCONTIG) {
|
||||
doit = "EXPAND";
|
||||
}
|
||||
if (doit) {
|
||||
i = fs->fs_contigsumsize;
|
||||
fs->fs_contigsumsize =
|
||||
MIN(fs->fs_maxcontig, FS_MAXCONTIG);
|
||||
if (CGSIZE(fs) > fs->fs_bsize) {
|
||||
pwarn("CANNOT %s CLUSTER MAPS\n", doit);
|
||||
fs->fs_contigsumsize = i;
|
||||
} else if (preen ||
|
||||
reply("CREATE CLUSTER MAPS")) {
|
||||
if (preen)
|
||||
pwarn("%sING CLUSTER MAPS\n",
|
||||
doit);
|
||||
fs->fs_cgsize =
|
||||
fragroundup(fs, CGSIZE(fs));
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch ((int)fs->fs_postblformat) {
|
||||
|
||||
case FS_42POSTBLFMT:
|
||||
basesize = (char *)(&ocg->cg_btot[0]) - (char *)(&ocg->cg_link);
|
||||
sumsize = &ocg->cg_iused[0] - (char *)(&ocg->cg_btot[0]);
|
||||
mapsize = &ocg->cg_free[howmany(fs->fs_fpg, NBBY)] -
|
||||
(u_char *)&ocg->cg_iused[0];
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
savednrpos = fs->fs_nrpos;
|
||||
fs->fs_nrpos = 8;
|
||||
break;
|
||||
|
||||
case FS_DYNAMICPOSTBLFMT:
|
||||
newcg->cg_btotoff =
|
||||
&newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
|
||||
newcg->cg_boff =
|
||||
newcg->cg_btotoff + fs->fs_cpg * sizeof(long);
|
||||
newcg->cg_iusedoff = newcg->cg_boff +
|
||||
fs->fs_cpg * fs->fs_nrpos * sizeof(short);
|
||||
newcg->cg_freeoff =
|
||||
newcg->cg_iusedoff + howmany(fs->fs_ipg, NBBY);
|
||||
if (fs->fs_contigsumsize <= 0) {
|
||||
newcg->cg_nextfreeoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY);
|
||||
} else {
|
||||
newcg->cg_clustersumoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY) -
|
||||
sizeof(long);
|
||||
newcg->cg_clustersumoff =
|
||||
roundup(newcg->cg_clustersumoff, sizeof(long));
|
||||
newcg->cg_clusteroff = newcg->cg_clustersumoff +
|
||||
(fs->fs_contigsumsize + 1) * sizeof(long);
|
||||
newcg->cg_nextfreeoff = newcg->cg_clusteroff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPB(fs), NBBY);
|
||||
}
|
||||
newcg->cg_magic = CG_MAGIC;
|
||||
basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
|
||||
sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
|
||||
mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("UNKNOWN ROTATIONAL TABLE FORMAT %d\n",
|
||||
fs->fs_postblformat);
|
||||
}
|
||||
bzero((char *)&idesc[0], sizeof idesc);
|
||||
for (i = 0; i < 3; i++) {
|
||||
idesc[i].id_type = ADDR;
|
||||
if (doinglevel2)
|
||||
idesc[i].id_fix = FIX;
|
||||
}
|
||||
bzero((char *)&cstotal, sizeof(struct csum));
|
||||
j = blknum(fs, fs->fs_size + fs->fs_frag - 1);
|
||||
for (i = fs->fs_size; i < j; i++)
|
||||
setbmap(i);
|
||||
for (c = 0; c < fs->fs_ncg; c++) {
|
||||
getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize);
|
||||
if (!cg_chkmagic(cg))
|
||||
pfatal("CG %d: BAD MAGIC NUMBER\n", c);
|
||||
dbase = cgbase(fs, c);
|
||||
dmax = dbase + fs->fs_fpg;
|
||||
if (dmax > fs->fs_size)
|
||||
dmax = fs->fs_size;
|
||||
newcg->cg_time = cg->cg_time;
|
||||
newcg->cg_cgx = c;
|
||||
if (c == fs->fs_ncg - 1)
|
||||
newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg;
|
||||
else
|
||||
newcg->cg_ncyl = fs->fs_cpg;
|
||||
newcg->cg_ndblk = dmax - dbase;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
|
||||
newcg->cg_cs.cs_ndir = 0;
|
||||
newcg->cg_cs.cs_nffree = 0;
|
||||
newcg->cg_cs.cs_nbfree = 0;
|
||||
newcg->cg_cs.cs_nifree = fs->fs_ipg;
|
||||
if (cg->cg_rotor < newcg->cg_ndblk)
|
||||
newcg->cg_rotor = cg->cg_rotor;
|
||||
else
|
||||
newcg->cg_rotor = 0;
|
||||
if (cg->cg_frotor < newcg->cg_ndblk)
|
||||
newcg->cg_frotor = cg->cg_frotor;
|
||||
else
|
||||
newcg->cg_frotor = 0;
|
||||
if (cg->cg_irotor < newcg->cg_niblk)
|
||||
newcg->cg_irotor = cg->cg_irotor;
|
||||
else
|
||||
newcg->cg_irotor = 0;
|
||||
bzero((char *)&newcg->cg_frsum[0], sizeof newcg->cg_frsum);
|
||||
bzero((char *)&cg_blktot(newcg)[0],
|
||||
(size_t)(sumsize + mapsize));
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
j = fs->fs_ipg * c;
|
||||
for (i = 0; i < fs->fs_ipg; j++, i++) {
|
||||
switch (statemap[j]) {
|
||||
|
||||
case USTATE:
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
case DCLEAR:
|
||||
case DFOUND:
|
||||
newcg->cg_cs.cs_ndir++;
|
||||
/* fall through */
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
setbit(cg_inosused(newcg), i);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (j < ROOTINO)
|
||||
break;
|
||||
errexit("BAD STATE %d FOR INODE I=%d",
|
||||
statemap[j], j);
|
||||
}
|
||||
}
|
||||
if (c == 0)
|
||||
for (i = 0; i < ROOTINO; i++) {
|
||||
setbit(cg_inosused(newcg), i);
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
}
|
||||
for (i = 0, d = dbase;
|
||||
d < dmax;
|
||||
d += fs->fs_frag, i += fs->fs_frag) {
|
||||
frags = 0;
|
||||
for (j = 0; j < fs->fs_frag; j++) {
|
||||
if (testbmap(d + j))
|
||||
continue;
|
||||
setbit(cg_blksfree(newcg), i + j);
|
||||
frags++;
|
||||
}
|
||||
if (frags == fs->fs_frag) {
|
||||
newcg->cg_cs.cs_nbfree++;
|
||||
j = cbtocylno(fs, i);
|
||||
cg_blktot(newcg)[j]++;
|
||||
cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
setbit(cg_clustersfree(newcg),
|
||||
i / fs->fs_frag);
|
||||
} else if (frags > 0) {
|
||||
newcg->cg_cs.cs_nffree += frags;
|
||||
blk = blkmap(fs, cg_blksfree(newcg), i);
|
||||
ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
|
||||
}
|
||||
}
|
||||
if (fs->fs_contigsumsize > 0) {
|
||||
long *sump = cg_clustersum(newcg);
|
||||
u_char *mapp = cg_clustersfree(newcg);
|
||||
int map = *mapp++;
|
||||
int bit = 1;
|
||||
int run = 0;
|
||||
|
||||
for (i = 0; i < newcg->cg_nclusterblks; i++) {
|
||||
if ((map & bit) != 0) {
|
||||
run++;
|
||||
} else if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
run = 0;
|
||||
}
|
||||
if ((i & (NBBY - 1)) != (NBBY - 1)) {
|
||||
bit <<= 1;
|
||||
} else {
|
||||
map = *mapp++;
|
||||
bit = 1;
|
||||
}
|
||||
}
|
||||
if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
}
|
||||
}
|
||||
cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
|
||||
cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
|
||||
cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
|
||||
cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
|
||||
cs = &fs->fs_cs(fs, c);
|
||||
if (bcmp((char *)&newcg->cg_cs, (char *)cs, sizeof *cs) != 0 &&
|
||||
dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
bcopy((char *)&newcg->cg_cs, (char *)cs, sizeof *cs);
|
||||
sbdirty();
|
||||
}
|
||||
if (doinglevel1) {
|
||||
bcopy((char *)newcg, (char *)cg, (size_t)fs->fs_cgsize);
|
||||
cgdirty();
|
||||
continue;
|
||||
}
|
||||
if (bcmp(cg_inosused(newcg),
|
||||
cg_inosused(cg), mapsize) != 0 &&
|
||||
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
|
||||
bcopy(cg_inosused(newcg), cg_inosused(cg),
|
||||
(size_t)mapsize);
|
||||
cgdirty();
|
||||
}
|
||||
if ((bcmp((char *)newcg, (char *)cg, basesize) != 0 ||
|
||||
bcmp((char *)&cg_blktot(newcg)[0],
|
||||
(char *)&cg_blktot(cg)[0], sumsize) != 0) &&
|
||||
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
|
||||
bcopy((char *)newcg, (char *)cg, (size_t)basesize);
|
||||
bcopy((char *)&cg_blktot(newcg)[0],
|
||||
(char *)&cg_blktot(cg)[0], (size_t)sumsize);
|
||||
cgdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
fs->fs_nrpos = savednrpos;
|
||||
if (bcmp((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs) != 0
|
||||
&& dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
bcopy((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs);
|
||||
fs->fs_ronly = 0;
|
||||
fs->fs_fmod = 0;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue