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
fd10fe931b
commit
9079938dd1
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"
|
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();
|
||||
}
|
||||
}
|
354
sbin/fsck_ifs/preen.c
Normal file
354
sbin/fsck_ifs/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_ifs/setup.c
Normal file
466
sbin/fsck_ifs/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_ifs/utilities.c
Normal file
566
sbin/fsck_ifs/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
|
8
sbin/mount_ifs/Makefile
Normal file
8
sbin/mount_ifs/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# @(#)Makefile 8.5 (Berkeley) 3/27/94
|
||||
|
||||
PROG= mount
|
||||
SRCS= mount.c mount_ufs.c getmntopts.c
|
||||
MAN8= mount.0
|
||||
# We do NOT install the getmntopts.3 man page.
|
||||
|
||||
.include <bsd.prog.mk>
|
163
sbin/mount_ifs/getmntopts.3
Normal file
163
sbin/mount_ifs/getmntopts.3
Normal file
@ -0,0 +1,163 @@
|
||||
.\" Copyright (c) 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.
|
||||
.\"
|
||||
.\" @(#)getmntopts.3 8.1 (Berkeley) 3/27/94
|
||||
.\"
|
||||
.Dd March 27, 1994
|
||||
.Dt GETMNTOPTS 3
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm getmntopts
|
||||
.Nd scan mount options
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <mntopts.h>
|
||||
.Ft void
|
||||
.Fn getmntopts "char *options" "struct mntopt *mopts" "int *flagp"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm getmntopts
|
||||
function takes a comma separated option list and a list
|
||||
of valid option names, and computes the bitmask
|
||||
corresponding to the requested set of options.
|
||||
.Pp
|
||||
The string
|
||||
.Dv options
|
||||
is broken down into a sequence of comma separated tokens.
|
||||
Each token is looked up in the table described by
|
||||
.Dv mopts
|
||||
and the bits in
|
||||
the word referenced by
|
||||
.Dv flagp
|
||||
are updated.
|
||||
The flag word is not initialized by
|
||||
.Nm getmntopt .
|
||||
The table,
|
||||
.Dv mopts ,
|
||||
has the following format:
|
||||
.Bd -literal
|
||||
struct mntopt {
|
||||
char *m_option; /* option name */
|
||||
int m_inverse; /* is this a negative option, eg "dev" */
|
||||
int m_flag; /* bit to set, eg MNT_RDONLY */
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The members of this structure are:
|
||||
.Bl -tag -width m_inverse
|
||||
.It Fa m_option
|
||||
the option name,
|
||||
for example
|
||||
.Dq suid .
|
||||
.It Fa m_inverse
|
||||
tells
|
||||
.Nm getmntopts
|
||||
that the name has the inverse meaning of the
|
||||
bit.
|
||||
For example,
|
||||
.Dq suid
|
||||
is the string, whereas the
|
||||
mount flag is
|
||||
.Dv MNT_NOSUID .
|
||||
In this case, the sense of the string and the flag
|
||||
are inverted, so the
|
||||
.Dv m_inverse
|
||||
flag should be set.
|
||||
.It Fa m_flag
|
||||
the value of the bit to be set or cleared in
|
||||
the flag word when the option is recognized.
|
||||
The bit is set when the option is discovered,
|
||||
but cleared if the option name was preceded
|
||||
by the letters
|
||||
.Dq no .
|
||||
The
|
||||
.Dv m_inverse
|
||||
flag causes these two operations to be reversed.
|
||||
.El
|
||||
.Pp
|
||||
Each of the user visible
|
||||
.Dv MNT_
|
||||
flags has a corresponding
|
||||
.Dv MOPT_
|
||||
macro which defines an appropriate
|
||||
.Li "struct mntopt"
|
||||
entry.
|
||||
To simplify the program interface and ensure consistency across all
|
||||
programs, a general purpose macro,
|
||||
.Dv MOPT_STDOPTS ,
|
||||
is defined which
|
||||
contains an entry for all the generic VFS options.
|
||||
In addition, the macros
|
||||
.Dv MOPT_FORCE
|
||||
and
|
||||
.Dv MOPT_UPDATE
|
||||
exist to enable the
|
||||
.Dv MNT_FORCE
|
||||
and
|
||||
.Dv MNT_UPDATE
|
||||
flags to be set.
|
||||
Finally, the table must be terminated by an entry with a NULL
|
||||
first element.
|
||||
.Sh EXAMPLES
|
||||
Most commands will use the standard option set.
|
||||
Local filesystems which support the
|
||||
.Dv MNT_UPDATE
|
||||
flag, would also have an
|
||||
.Dv MOPT_UPDATE
|
||||
entry.
|
||||
This can be declared and used as follows:
|
||||
.Bd -literal
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
MOPT_UPDATE,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
...
|
||||
mntflags = 0;
|
||||
...
|
||||
getmntopts(options, mopts, &mntflags)
|
||||
...
|
||||
.Ed
|
||||
.Sh DIAGNOSTICS
|
||||
The
|
||||
.Nm getmntopts
|
||||
function displays an error message and exits if an
|
||||
unrecognized option is encountered.
|
||||
.Sh SEE ALSO
|
||||
.Xr err 3 ,
|
||||
.Xr mount 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn getmntopts
|
||||
function appeared in
|
||||
.Bx 4.4 .
|
87
sbin/mount_ifs/getmntopts.c
Normal file
87
sbin/mount_ifs/getmntopts.c
Normal file
@ -0,0 +1,87 @@
|
||||
/*-
|
||||
* Copyright (c) 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 sccsid[] = "@(#)getmntopts.c 8.1 (Berkeley) 3/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fstab.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
void
|
||||
getmntopts(options, m0, flagp)
|
||||
const char *options;
|
||||
const struct mntopt *m0;
|
||||
int *flagp;
|
||||
{
|
||||
const struct mntopt *m;
|
||||
int negative;
|
||||
char *opt, *optbuf;
|
||||
|
||||
/* Copy option string, since it is about to be torn asunder... */
|
||||
if ((optbuf = strdup(options)) == NULL)
|
||||
err(1, NULL);
|
||||
|
||||
for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
|
||||
/* Check for "no" prefix. */
|
||||
if (opt[0] == 'n' && opt[1] == 'o') {
|
||||
negative = 1;
|
||||
opt += 2;
|
||||
} else
|
||||
negative = 0;
|
||||
|
||||
/* Scan option table. */
|
||||
for (m = m0; m->m_option != NULL; ++m)
|
||||
if (strcasecmp(opt, m->m_option) == 0)
|
||||
break;
|
||||
|
||||
/* Save flag, or fail if option is not recognised. */
|
||||
if (m->m_option) {
|
||||
if (negative == m->m_inverse)
|
||||
*flagp |= m->m_flag;
|
||||
else
|
||||
*flagp &= ~m->m_flag;
|
||||
} else
|
||||
errx(1, "-o %s: option not supported", opt);
|
||||
}
|
||||
|
||||
free(optbuf);
|
||||
}
|
72
sbin/mount_ifs/mntopts.h
Normal file
72
sbin/mount_ifs/mntopts.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*-
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* @(#)mntopts.h 8.3 (Berkeley) 3/27/94
|
||||
*/
|
||||
|
||||
struct mntopt {
|
||||
const char *m_option; /* option name */
|
||||
int m_inverse; /* if a negative option, eg "dev" */
|
||||
int m_flag; /* bit to set, eg. MNT_RDONLY */
|
||||
};
|
||||
|
||||
/* User-visible MNT_ flags. */
|
||||
#define MOPT_ASYNC { "async", 0, MNT_ASYNC }
|
||||
#define MOPT_NODEV { "dev", 1, MNT_NODEV }
|
||||
#define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC }
|
||||
#define MOPT_NOSUID { "suid", 1, MNT_NOSUID }
|
||||
#define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY }
|
||||
#define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS }
|
||||
#define MOPT_UNION { "union", 0, MNT_UNION }
|
||||
|
||||
/* Control flags. */
|
||||
#define MOPT_FORCE { "force", 1, MNT_FORCE }
|
||||
#define MOPT_UPDATE { "update", 0, MNT_UPDATE }
|
||||
|
||||
/* Support for old-style "ro", "rw" flags. */
|
||||
#define MOPT_RO { "ro", 0, MNT_RDONLY }
|
||||
#define MOPT_RW { "rw", 1, MNT_RDONLY }
|
||||
|
||||
#define MOPT_FSTAB_COMPAT \
|
||||
MOPT_RO, \
|
||||
MOPT_RW
|
||||
|
||||
/* Standard options which all mounts can understand. */
|
||||
#define MOPT_STDOPTS \
|
||||
MOPT_FSTAB_COMPAT, \
|
||||
MOPT_NODEV, \
|
||||
MOPT_NOEXEC, \
|
||||
MOPT_NOSUID, \
|
||||
MOPT_RDONLY, \
|
||||
MOPT_UNION
|
||||
|
||||
void getmntopts __P((const char *, const struct mntopt *, int *));
|
264
sbin/mount_ifs/mount.8
Normal file
264
sbin/mount_ifs/mount.8
Normal file
@ -0,0 +1,264 @@
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)mount.8 8.7 (Berkeley) 3/27/94
|
||||
.\"
|
||||
.Dd March 27, 1994
|
||||
.Dt MOUNT 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm mount
|
||||
.Nd mount file systems
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount
|
||||
.Op Fl adfruvw
|
||||
.Op Fl t Ar ufs | lfs | external_type
|
||||
.Nm mount
|
||||
.Op Fl dfruvw
|
||||
.Ar special | node
|
||||
.Nm mount
|
||||
.Op Fl dfruvw
|
||||
.Op Fl o Ar options
|
||||
.Op Fl t Ar ufs | lfs | external_type
|
||||
.Ar special node
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount
|
||||
command
|
||||
calls the
|
||||
.Xr mount 2
|
||||
system call to prepare and graft a
|
||||
.Ar "special device"
|
||||
or the remote node (rhost:path) on to the file system tree at the point
|
||||
.Ar node .
|
||||
If either
|
||||
.Ar special
|
||||
or
|
||||
.Ar node
|
||||
are not provided, the appropriate information is taken from the
|
||||
.Xr fstab 5
|
||||
file.
|
||||
.Pp
|
||||
The system maintains a list of currently mounted file systems.
|
||||
If no arguments are given to
|
||||
.Nm mount,
|
||||
this list is printed.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl d
|
||||
Causes everything to be done except for the actual system call.
|
||||
This option is useful in conjunction with the
|
||||
.Fl v
|
||||
flag to
|
||||
determine what the
|
||||
.Nm mount
|
||||
command is trying to do.
|
||||
.It Fl f
|
||||
Forces the revocation of write access when trying to downgrade
|
||||
a filesystem mount status from read-write to read-only.
|
||||
.It Fl o
|
||||
Options are specified with a
|
||||
.Fl o
|
||||
flag followed by a comma separated string of options.
|
||||
The following options are available:
|
||||
.Bl -tag -width indent
|
||||
.It async
|
||||
All
|
||||
.Tn I/O
|
||||
to the file system should be done asynchronously.
|
||||
This is a
|
||||
.Em dangerous
|
||||
flag to set,
|
||||
and should not be used unless you are prepared to recreate the file
|
||||
system should your system crash.
|
||||
.It force
|
||||
The same as
|
||||
.Fl f ;
|
||||
forces the revocation of write access when trying to downgrade
|
||||
a filesystem mount status from read-write to read-only.
|
||||
.It nodev
|
||||
Do not interpret character or block special devices on the file system.
|
||||
This option is useful for a server that has file systems containing
|
||||
special devices for architectures other than its own.
|
||||
.It noexec
|
||||
Do not allow execution of any binaries on the mounted file system.
|
||||
This option is useful for a server that has file systems containing
|
||||
binaries for architectures other than its own.
|
||||
.It nosuid
|
||||
Do not allow set-user-identifier or set-group-identifier bits to take effect.
|
||||
.It rdonly
|
||||
The same as
|
||||
.Fl r ;
|
||||
mount the file system read-only (even the super-user may not write it).
|
||||
.It sync
|
||||
All
|
||||
.Tn I/O
|
||||
to the file system should be done synchronously.
|
||||
.It update
|
||||
The same as
|
||||
.Fl u ;
|
||||
indicate that the status of an already mounted file system should be changed.
|
||||
.It union
|
||||
Causes the namespace at the mount point to appear as the union
|
||||
of the mounted filesystem root and the existing directory.
|
||||
Lookups will be done in the mounted filesystem first.
|
||||
If those operations fail due to a non-existent file the underlying
|
||||
directory is then accessed.
|
||||
All creates are done in the mounted filesystem.
|
||||
.El
|
||||
.Pp
|
||||
Any additional options specific to a filesystem type that is not
|
||||
one of the internally known types (see the
|
||||
.Fl t
|
||||
option) may be passed as a comma separated list; these options are
|
||||
distinguished by a leading
|
||||
.Dq \&-
|
||||
(dash).
|
||||
Options that take a value are specified using the syntax -option=value.
|
||||
For example, the mount command:
|
||||
.Bd -literal -offset indent
|
||||
mount -t mfs -o nosuid,-N,-s=4000 /dev/dk0b /tmp
|
||||
.Ed
|
||||
.Pp
|
||||
causes
|
||||
.Nm mount
|
||||
to execute the equivalent of:
|
||||
.Bd -literal -offset indent
|
||||
/sbin/mount_mfs -o nosuid -N -s 4000 /dev/dk0b /tmp
|
||||
.Ed
|
||||
.It Fl r
|
||||
The file system is to be mounted read-only.
|
||||
Mount the file system read-only (even the super-user may not write it).
|
||||
The same as the
|
||||
.Dq rdonly
|
||||
argument to the
|
||||
.Fl o
|
||||
option.
|
||||
.It Fl t Ar "ufs \\*(Ba lfs \\*(Ba external type"
|
||||
The argument following the
|
||||
.Fl t
|
||||
is used to indicate the file system type.
|
||||
The type
|
||||
.Ar ufs
|
||||
is the default.
|
||||
The \fI-t\fP option can be used
|
||||
to indicate that the actions should only be taken on
|
||||
filesystems of the specified type.
|
||||
More than one type may be specified in a comma separated list.
|
||||
The list of filesystem types can be prefixed with
|
||||
.Dq no
|
||||
to specify the filesystem types for which action should
|
||||
.Em not
|
||||
be taken.
|
||||
For example, the
|
||||
.Nm mount
|
||||
command:
|
||||
.Bd -literal -offset indent
|
||||
mount -a -t nonfs,mfs
|
||||
.Ed
|
||||
.Pp
|
||||
mounts all filesystems except those of type
|
||||
.Tn NFS
|
||||
and
|
||||
.Tn MFS .
|
||||
.Pp
|
||||
If the type is not one of the internally known types,
|
||||
mount will attempt to execute a program in
|
||||
.Pa /sbin/mount_ Ns Em XXX
|
||||
where
|
||||
.Em XXX
|
||||
is replaced by the type name.
|
||||
For example, nfs filesystems are mounted by the program
|
||||
.Pa /sbin/mount_nfs .
|
||||
.It Fl u
|
||||
The
|
||||
.Fl u
|
||||
flag indicates that the status of an already mounted file
|
||||
system should be changed.
|
||||
Any of the options discussed above (the
|
||||
.Fl o
|
||||
option)
|
||||
may be changed;
|
||||
also a file system can be changed from read-only to read-write
|
||||
or vice versa.
|
||||
An attempt to change from read-write to read-only will fail if any
|
||||
files on the filesystem are currently open for writing unless the
|
||||
.Fl f
|
||||
flag is also specified.
|
||||
The set of options is determined by first extracting the options
|
||||
for the file system from the
|
||||
.Xr fstab
|
||||
table,
|
||||
then applying any options specified by the
|
||||
.Fl o
|
||||
argument,
|
||||
and finally applying the
|
||||
.Fl r
|
||||
or
|
||||
.Fl w
|
||||
option.
|
||||
.It Fl v
|
||||
Verbose mode.
|
||||
.It Fl w
|
||||
The file system object is to be read and write.
|
||||
.Pp
|
||||
The options specific to NFS filesystems are described in the
|
||||
.Xr mount_nfs 8
|
||||
manual page.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/fstab -compact
|
||||
.It Pa /etc/fstab
|
||||
file system table
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mount 2 ,
|
||||
.Xr fstab 5 ,
|
||||
.Xr mount_cd9660 8 ,
|
||||
.Xr mount_fdesc 8 ,
|
||||
.Xr mount_kernfs 8 ,
|
||||
.Xr mount_lfs 8 ,
|
||||
.Xr mount_lofs 8 ,
|
||||
.Xr mount_mfs 8 ,
|
||||
.Xr mount_nfs 8 ,
|
||||
.Xr mount_null 8 ,
|
||||
.Xr mount_portal 8 ,
|
||||
.Xr mount_procfs 8 ,
|
||||
.Xr mount_umap 8 ,
|
||||
.Xr mount_union 8 ,
|
||||
.Xr umount 8
|
||||
.Sh BUGS
|
||||
It is possible for a corrupted file system to cause a crash.
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm mount
|
||||
command appeared in
|
||||
.At v6 .
|
512
sbin/mount_ifs/mount.c
Normal file
512
sbin/mount_ifs/mount.c
Normal file
@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Copyright (c) 1980, 1989, 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, 1989, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount.c 8.19 (Berkeley) 4/19/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fstab.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
|
||||
int debug, verbose, skipvfs;
|
||||
|
||||
int badvfsname __P((const char *, const char **));
|
||||
int badvfstype __P((int, const char **));
|
||||
char *catopt __P((char *, const char *));
|
||||
struct statfs
|
||||
*getmntpt __P((const char *));
|
||||
const char
|
||||
**makevfslist __P((char *));
|
||||
void mangle __P((char *, int *, const char **));
|
||||
int mountfs __P((const char *, const char *, const char *,
|
||||
int, const char *, const char *));
|
||||
void prmount __P((const char *, const char *, int));
|
||||
void usage __P((void));
|
||||
|
||||
/* From mount_ufs.c. */
|
||||
int mount_ufs __P((int, char * const *));
|
||||
|
||||
/* Map from mount otions to printable formats. */
|
||||
static struct opt {
|
||||
int o_opt;
|
||||
const char *o_name;
|
||||
} optnames[] = {
|
||||
{ MNT_ASYNC, "asynchronous" },
|
||||
{ MNT_EXPORTED, "NFS exported" },
|
||||
{ MNT_LOCAL, "local" },
|
||||
{ MNT_NODEV, "nodev" },
|
||||
{ MNT_NOEXEC, "noexec" },
|
||||
{ MNT_NOSUID, "nosuid" },
|
||||
{ MNT_QUOTA, "with quotas" },
|
||||
{ MNT_RDONLY, "read-only" },
|
||||
{ MNT_SYNCHRONOUS, "synchronous" },
|
||||
{ MNT_UNION, "union" },
|
||||
{ MNT_USER, "user mount" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char * const argv[];
|
||||
{
|
||||
const char *mntonname, **vfslist, *vfstype;
|
||||
struct fstab *fs;
|
||||
struct statfs *mntbuf;
|
||||
FILE *mountdfp;
|
||||
pid_t pid;
|
||||
int all, ch, i, init_flags, mntsize, rval;
|
||||
char *options;
|
||||
|
||||
all = init_flags = 0;
|
||||
options = NULL;
|
||||
vfslist = NULL;
|
||||
vfstype = "ufs";
|
||||
while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF)
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
all = 1;
|
||||
break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'f':
|
||||
init_flags |= MNT_FORCE;
|
||||
break;
|
||||
case 'o':
|
||||
if (*optarg)
|
||||
options = catopt(options, optarg);
|
||||
break;
|
||||
case 'r':
|
||||
init_flags |= MNT_RDONLY;
|
||||
break;
|
||||
case 't':
|
||||
if (vfslist != NULL)
|
||||
errx(1, "only one -t option may be specified.");
|
||||
vfslist = makevfslist(optarg);
|
||||
vfstype = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
init_flags |= MNT_UPDATE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'w':
|
||||
init_flags &= ~MNT_RDONLY;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
#define BADTYPE(type) \
|
||||
(strcmp(type, FSTAB_RO) && \
|
||||
strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
|
||||
|
||||
rval = 0;
|
||||
switch (argc) {
|
||||
case 0:
|
||||
if (all)
|
||||
while ((fs = getfsent()) != NULL) {
|
||||
if (BADTYPE(fs->fs_type))
|
||||
continue;
|
||||
if (badvfsname(fs->fs_vfstype, vfslist))
|
||||
continue;
|
||||
if (mountfs(fs->fs_vfstype, fs->fs_spec,
|
||||
fs->fs_file, init_flags, options,
|
||||
fs->fs_mntops))
|
||||
rval = 1;
|
||||
}
|
||||
else {
|
||||
if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
|
||||
err(1, "getmntinfo");
|
||||
for (i = 0; i < mntsize; i++) {
|
||||
if (badvfstype(mntbuf[i].f_type, vfslist))
|
||||
continue;
|
||||
prmount(mntbuf[i].f_mntfromname,
|
||||
mntbuf[i].f_mntonname, mntbuf[i].f_flags);
|
||||
}
|
||||
}
|
||||
exit(rval);
|
||||
case 1:
|
||||
if (vfslist != NULL)
|
||||
usage();
|
||||
|
||||
if (init_flags & MNT_UPDATE) {
|
||||
if ((mntbuf = getmntpt(*argv)) == NULL)
|
||||
errx(1,
|
||||
"unknown special file or file system %s.",
|
||||
*argv);
|
||||
if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL)
|
||||
errx(1, "can't find fstab entry for %s.",
|
||||
*argv);
|
||||
/* If it's an update, ignore the fstab file options. */
|
||||
fs->fs_mntops = NULL;
|
||||
mntonname = mntbuf->f_mntonname;
|
||||
} else {
|
||||
if ((fs = getfsfile(*argv)) == NULL &&
|
||||
(fs = getfsspec(*argv)) == NULL)
|
||||
errx(1,
|
||||
"%s: unknown special file or file system.",
|
||||
*argv);
|
||||
if (BADTYPE(fs->fs_type))
|
||||
errx(1, "%s has unknown file system type.",
|
||||
*argv);
|
||||
mntonname = fs->fs_file;
|
||||
}
|
||||
rval = mountfs(fs->fs_vfstype, fs->fs_spec,
|
||||
mntonname, init_flags, options, fs->fs_mntops);
|
||||
break;
|
||||
case 2:
|
||||
/*
|
||||
* If -t flag has not been specified, and spec contains either
|
||||
* a ':' or a '@' then assume that an NFS filesystem is being
|
||||
* specified ala Sun.
|
||||
*/
|
||||
if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL)
|
||||
vfstype = "nfs";
|
||||
rval = mountfs(vfstype,
|
||||
argv[0], argv[1], init_flags, options, NULL);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* If the mount was successfully, and done by root, tell mountd the
|
||||
* good news. Pid checks are probably unnecessary, but don't hurt.
|
||||
*/
|
||||
if (rval == 0 && getuid() == 0 &&
|
||||
(mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
|
||||
if (fscanf(mountdfp, "%ld", &pid) == 1 &&
|
||||
pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
|
||||
err(1, "signal mountd");
|
||||
(void)fclose(mountdfp);
|
||||
}
|
||||
|
||||
exit(rval);
|
||||
}
|
||||
|
||||
int
|
||||
mountfs(vfstype, spec, name, flags, options, mntopts)
|
||||
const char *vfstype, *spec, *name, *options, *mntopts;
|
||||
int flags;
|
||||
{
|
||||
/* List of directories containing mount_xxx subcommands. */
|
||||
static const char *edirs[] = {
|
||||
_PATH_SBIN,
|
||||
_PATH_USRSBIN,
|
||||
NULL
|
||||
};
|
||||
const char *argv[100], **edir;
|
||||
struct statfs sf;
|
||||
pid_t pid;
|
||||
int argc, i, status;
|
||||
char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
|
||||
|
||||
if (realpath(name, mntpath) == NULL) {
|
||||
warn("%s", mntpath);
|
||||
return (1);
|
||||
}
|
||||
|
||||
name = mntpath;
|
||||
|
||||
if (options == NULL) {
|
||||
if (mntopts == NULL || *mntopts == '\0')
|
||||
options = "rw";
|
||||
else
|
||||
options = mntopts;
|
||||
mntopts = "";
|
||||
}
|
||||
optbuf = catopt(strdup(mntopts), options);
|
||||
|
||||
if (strcmp(name, "/") == 0)
|
||||
flags |= MNT_UPDATE;
|
||||
if (flags & MNT_FORCE)
|
||||
optbuf = catopt(optbuf, "force");
|
||||
if (flags & MNT_RDONLY)
|
||||
optbuf = catopt(optbuf, "ro");
|
||||
/*
|
||||
* XXX
|
||||
* The mount_mfs (newfs) command uses -o to select the
|
||||
* optimisation mode. We don't pass the default "-o rw"
|
||||
* for that reason.
|
||||
*/
|
||||
if (flags & MNT_UPDATE)
|
||||
optbuf = catopt(optbuf, "update");
|
||||
|
||||
argc = 0;
|
||||
argv[argc++] = vfstype;
|
||||
mangle(optbuf, &argc, argv);
|
||||
argv[argc++] = spec;
|
||||
argv[argc++] = name;
|
||||
argv[argc] = NULL;
|
||||
|
||||
if (debug) {
|
||||
(void)printf("exec: mount_%s", vfstype);
|
||||
for (i = 1; i < argc; i++)
|
||||
(void)printf(" %s", argv[i]);
|
||||
(void)printf("\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
switch (pid = vfork()) {
|
||||
case -1: /* Error. */
|
||||
warn("vfork");
|
||||
free(optbuf);
|
||||
return (1);
|
||||
case 0: /* Child. */
|
||||
if (strcmp(vfstype, "ufs") == 0)
|
||||
exit(mount_ufs(argc, (char * const *) argv));
|
||||
|
||||
/* Go find an executable. */
|
||||
edir = edirs;
|
||||
do {
|
||||
(void)snprintf(execname,
|
||||
sizeof(execname), "%s/mount_%s", *edir, vfstype);
|
||||
execv(execname, (char * const *)argv);
|
||||
if (errno != ENOENT)
|
||||
warn("exec %s for %s", execname, name);
|
||||
} while (*++edir != NULL);
|
||||
|
||||
if (errno == ENOENT)
|
||||
warn("exec %s for %s", execname, name);
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
default: /* Parent. */
|
||||
free(optbuf);
|
||||
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
warn("waitpid");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0)
|
||||
return (WEXITSTATUS(status));
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (statfs(name, &sf) < 0) {
|
||||
warn("%s", name);
|
||||
return (1);
|
||||
}
|
||||
prmount(sf.f_mntfromname, sf.f_mntonname, sf.f_flags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
prmount(spec, name, flags)
|
||||
const char *spec, *name;
|
||||
int flags;
|
||||
{
|
||||
struct opt *o;
|
||||
int f;
|
||||
|
||||
(void)printf("%s on %s", spec, name);
|
||||
|
||||
flags &= MNT_VISFLAGMASK;
|
||||
for (f = 0, o = optnames; flags && o->o_opt; o++)
|
||||
if (flags & o->o_opt) {
|
||||
(void)printf("%s%s", !f++ ? " (" : ", ", o->o_name);
|
||||
flags &= ~o->o_opt;
|
||||
}
|
||||
(void)printf(f ? ")\n" : "\n");
|
||||
}
|
||||
|
||||
struct statfs *
|
||||
getmntpt(name)
|
||||
const char *name;
|
||||
{
|
||||
struct statfs *mntbuf;
|
||||
int i, mntsize;
|
||||
|
||||
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
|
||||
for (i = 0; i < mntsize; i++)
|
||||
if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
|
||||
strcmp(mntbuf[i].f_mntonname, name) == 0)
|
||||
return (&mntbuf[i]);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
badvfsname(vfsname, vfslist)
|
||||
const char *vfsname;
|
||||
const char **vfslist;
|
||||
{
|
||||
|
||||
if (vfslist == NULL)
|
||||
return (0);
|
||||
while (*vfslist != NULL) {
|
||||
if (strcmp(vfsname, *vfslist) == 0)
|
||||
return (skipvfs);
|
||||
++vfslist;
|
||||
}
|
||||
return (!skipvfs);
|
||||
}
|
||||
|
||||
int
|
||||
badvfstype(vfstype, vfslist)
|
||||
int vfstype;
|
||||
const char **vfslist;
|
||||
{
|
||||
static const char *vfsnames[] = INITMOUNTNAMES;
|
||||
|
||||
if ((vfstype < 0) || (vfstype > MOUNT_MAXTYPE))
|
||||
return (0);
|
||||
|
||||
return (badvfsname(vfsnames[vfstype], vfslist));
|
||||
}
|
||||
|
||||
const char **
|
||||
makevfslist(fslist)
|
||||
char *fslist;
|
||||
{
|
||||
const char **av;
|
||||
int i;
|
||||
char *nextcp;
|
||||
|
||||
if (fslist == NULL)
|
||||
return (NULL);
|
||||
if (fslist[0] == 'n' && fslist[1] == 'o') {
|
||||
fslist += 2;
|
||||
skipvfs = 1;
|
||||
}
|
||||
for (i = 0, nextcp = fslist; *nextcp; nextcp++)
|
||||
if (*nextcp == ',')
|
||||
i++;
|
||||
if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
|
||||
warn(NULL);
|
||||
return (NULL);
|
||||
}
|
||||
nextcp = fslist;
|
||||
i = 0;
|
||||
av[i++] = nextcp;
|
||||
while ((nextcp = strchr(nextcp, ',')) != NULL) {
|
||||
*nextcp++ = '\0';
|
||||
av[i++] = nextcp;
|
||||
}
|
||||
av[i++] = NULL;
|
||||
return (av);
|
||||
}
|
||||
|
||||
char *
|
||||
catopt(s0, s1)
|
||||
char *s0;
|
||||
const char *s1;
|
||||
{
|
||||
size_t i;
|
||||
char *cp;
|
||||
|
||||
if (s0 && *s0) {
|
||||
i = strlen(s0) + strlen(s1) + 1 + 1;
|
||||
if ((cp = malloc(i)) == NULL)
|
||||
err(1, NULL);
|
||||
(void)snprintf(cp, i, "%s,%s", s0, s1);
|
||||
} else
|
||||
cp = strdup(s1);
|
||||
|
||||
if (s0)
|
||||
free(s0);
|
||||
return (cp);
|
||||
}
|
||||
|
||||
void
|
||||
mangle(options, argcp, argv)
|
||||
char *options;
|
||||
int *argcp;
|
||||
const char **argv;
|
||||
{
|
||||
char *p, *s;
|
||||
int argc;
|
||||
|
||||
argc = *argcp;
|
||||
for (s = options; (p = strsep(&s, ",")) != NULL;)
|
||||
if (*p != '\0')
|
||||
if (*p == '-') {
|
||||
argv[argc++] = p;
|
||||
p = strchr(p, '=');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
argv[argc++] = p+1;
|
||||
}
|
||||
} else if (strcmp(p, "rw") != 0) {
|
||||
argv[argc++] = "-o";
|
||||
argv[argc++] = p;
|
||||
}
|
||||
|
||||
*argcp = argc;
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount %s %s\n mount %s\n mount %s\n",
|
||||
"[-dfruvw] [-o options] [-t ufs | external_type]",
|
||||
"special node",
|
||||
"[-adfruvw] [-t ufs | external_type]",
|
||||
"[-dfruvw] special | node");
|
||||
exit(1);
|
||||
}
|
131
sbin/mount_ifs/mount_ufs.c
Normal file
131
sbin/mount_ifs/mount_ufs.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*-
|
||||
* Copyright (c) 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) 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount_ufs.c 8.2 (Berkeley) 3/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
void ufs_usage __P((void));
|
||||
|
||||
static struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
MOPT_ASYNC,
|
||||
MOPT_SYNC,
|
||||
MOPT_UPDATE,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int
|
||||
mount_ufs(argc, argv)
|
||||
int argc;
|
||||
char * const argv[];
|
||||
{
|
||||
extern int optreset;
|
||||
struct ufs_args args;
|
||||
int ch, mntflags;
|
||||
char *fs_name;
|
||||
|
||||
mntflags = 0;
|
||||
optind = optreset = 1; /* Reset for parse of new argv. */
|
||||
while ((ch = getopt(argc, argv, "o:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
ufs_usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
ufs_usage();
|
||||
|
||||
args.fspec = argv[0]; /* The name of the device file. */
|
||||
fs_name = argv[1]; /* The mount point. */
|
||||
|
||||
#define DEFAULT_ROOTUID -2
|
||||
args.export.ex_root = DEFAULT_ROOTUID;
|
||||
if (mntflags & MNT_RDONLY)
|
||||
args.export.ex_flags = MNT_EXRDONLY;
|
||||
else
|
||||
args.export.ex_flags = 0;
|
||||
|
||||
if (mount(MOUNT_UFS, fs_name, mntflags, &args) < 0) {
|
||||
(void)fprintf(stderr, "%s on %s: ", args.fspec, fs_name);
|
||||
switch (errno) {
|
||||
case EMFILE:
|
||||
(void)fprintf(stderr, "mount table full.\n");
|
||||
break;
|
||||
case EINVAL:
|
||||
if (mntflags & MNT_UPDATE)
|
||||
(void)fprintf(stderr,
|
||||
"Specified device does not match mounted device.\n");
|
||||
else
|
||||
(void)fprintf(stderr,
|
||||
"Incorrect super block.\n");
|
||||
break;
|
||||
default:
|
||||
(void)fprintf(stderr, "%s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ufs_usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage: mount_ufs [-o options] special node\n");
|
||||
exit(1);
|
||||
}
|
38
sbin/mount_ifs/pathnames.h
Normal file
38
sbin/mount_ifs/pathnames.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 1989, 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.
|
||||
*
|
||||
* @(#)pathnames.h 8.2 (Berkeley) 3/27/94
|
||||
*/
|
||||
|
||||
#define _PATH_SBIN "/sbin"
|
||||
#define _PATH_USRSBIN "/usr/sbin"
|
||||
#define _PATH_MOUNTDPID "/var/run/mountd.pid"
|
11
sbin/mount_nullfs/Makefile
Normal file
11
sbin/mount_nullfs/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# @(#)Makefile 8.3 (Berkeley) 3/27/94
|
||||
|
||||
PROG= mount_null
|
||||
SRCS= mount_null.c getmntopts.c
|
||||
MAN8= mount_null.0
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I/sys -I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
220
sbin/mount_nullfs/mount_nullfs.8
Normal file
220
sbin/mount_nullfs/mount_nullfs.8
Normal file
@ -0,0 +1,220 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1992, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software donated to Berkeley by
|
||||
.\" John Heidemann of the UCLA Ficus project.
|
||||
.\"
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)mount_null.8 8.4 (Berkeley) 4/19/94
|
||||
.\"
|
||||
.\"
|
||||
.Dd April 19, 1994
|
||||
.Dt MOUNT_NULL 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_null
|
||||
.Nd demonstrate the use of a null file system layer
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount_null
|
||||
.Op Fl o Ar options
|
||||
.Ar target
|
||||
.Ar mount-point
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount_null
|
||||
command creates a
|
||||
null layer, duplicating a sub-tree of the file system
|
||||
name space under another part of the global file system namespace.
|
||||
In this respect, it is
|
||||
similar to the loopback file system (see
|
||||
.Xr mount_lofs 8 ) .
|
||||
It differs from
|
||||
the loopback file system in two respects: it is implemented using
|
||||
a stackable layers techniques, and it's
|
||||
.Do
|
||||
null-node
|
||||
.Dc s
|
||||
stack above
|
||||
all lower-layer vnodes, not just over directory vnodes.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl o
|
||||
Options are specified with a
|
||||
.Fl o
|
||||
flag followed by a comma separated string of options.
|
||||
See the
|
||||
.Xr mount 8
|
||||
man page for possible options and their meanings.
|
||||
.El
|
||||
.Pp
|
||||
The null layer has two purposes.
|
||||
First, it serves as a demonstration of layering by proving a layer
|
||||
which does nothing.
|
||||
(It actually does everything the loopback file system does,
|
||||
which is slightly more than nothing.)
|
||||
Second, the null layer can serve as a prototype layer.
|
||||
Since it provides all necessary layer framework,
|
||||
new file system layers can be created very easily be starting
|
||||
with a null layer.
|
||||
.Pp
|
||||
The remainder of this man page examines the null layer as a basis
|
||||
for constructing new layers.
|
||||
.\"
|
||||
.\"
|
||||
.Sh INSTANTIATING NEW NULL LAYERS
|
||||
New null layers are created with
|
||||
.Xr mount_null 8 .
|
||||
.Xr Mount_null 8
|
||||
takes two arguments, the pathname
|
||||
of the lower vfs (target-pn) and the pathname where the null
|
||||
layer will appear in the namespace (mount-point-pn). After
|
||||
the null layer is put into place, the contents
|
||||
of target-pn subtree will be aliased under mount-point-pn.
|
||||
.\"
|
||||
.\"
|
||||
.Sh OPERATION OF A NULL LAYER
|
||||
The null layer is the minimum file system layer,
|
||||
simply bypassing all possible operations to the lower layer
|
||||
for processing there. The majority of its activity centers
|
||||
on the bypass routine, though which nearly all vnode operations
|
||||
pass.
|
||||
.Pp
|
||||
The bypass routine accepts arbitrary vnode operations for
|
||||
handling by the lower layer. It begins by examing vnode
|
||||
operation arguments and replacing any null-nodes by their
|
||||
lower-layer equivalents. It then invokes the operation
|
||||
on the lower layer. Finally, it replaces the null-nodes
|
||||
in the arguments and, if a vnode is returned by the operation,
|
||||
stacks a null-node on top of the returned vnode.
|
||||
.Pp
|
||||
Although bypass handles most operations,
|
||||
.Em vop_getattr ,
|
||||
.Em vop_inactive ,
|
||||
.Em vop_reclaim ,
|
||||
and
|
||||
.Em vop_print
|
||||
are not bypassed.
|
||||
.Em Vop_getattr
|
||||
must change the fsid being returned.
|
||||
.Em Vop_inactive
|
||||
and vop_reclaim are not bypassed so that
|
||||
they can handle freeing null-layer specific data.
|
||||
.Em Vop_print
|
||||
is not bypassed to avoid excessive debugging
|
||||
information.
|
||||
.\"
|
||||
.\"
|
||||
.Sh INSTANTIATING VNODE STACKS
|
||||
Mounting associates the null layer with a lower layer,
|
||||
in effect stacking two VFSes. Vnode stacks are instead
|
||||
created on demand as files are accessed.
|
||||
.Pp
|
||||
The initial mount creates a single vnode stack for the
|
||||
root of the new null layer. All other vnode stacks
|
||||
are created as a result of vnode operations on
|
||||
this or other null vnode stacks.
|
||||
.Pp
|
||||
New vnode stacks come into existence as a result of
|
||||
an operation which returns a vnode.
|
||||
The bypass routine stacks a null-node above the new
|
||||
vnode before returning it to the caller.
|
||||
.Pp
|
||||
For example, imagine mounting a null layer with
|
||||
.Bd -literal -offset indent
|
||||
mount_null /usr/include /dev/layer/null
|
||||
.Ed
|
||||
Changing directory to
|
||||
.Pa /dev/layer/null
|
||||
will assign
|
||||
the root null-node (which was created when the null layer was mounted).
|
||||
Now consider opening
|
||||
.Pa sys .
|
||||
A vop_lookup would be
|
||||
done on the root null-node. This operation would bypass through
|
||||
to the lower layer which would return a vnode representing
|
||||
the UFS
|
||||
.Pa sys .
|
||||
Null_bypass then builds a null-node
|
||||
aliasing the UFS
|
||||
.Pa sys
|
||||
and returns this to the caller.
|
||||
Later operations on the null-node
|
||||
.Pa sys
|
||||
will repeat this
|
||||
process when constructing other vnode stacks.
|
||||
.\"
|
||||
.\"
|
||||
.Sh CREATING OTHER FILE SYSTEM LAYERS
|
||||
One of the easiest ways to construct new file system layers is to make
|
||||
a copy of the null layer, rename all files and variables, and
|
||||
then begin modifyng the copy. Sed can be used to easily rename
|
||||
all variables.
|
||||
.Pp
|
||||
The umap layer is an example of a layer descended from the
|
||||
null layer.
|
||||
.\"
|
||||
.\"
|
||||
.Sh INVOKING OPERATIONS ON LOWER LAYERS
|
||||
There are two techniques to invoke operations on a lower layer
|
||||
when the operation cannot be completely bypassed. Each method
|
||||
is appropriate in different situations. In both cases,
|
||||
it is the responsibility of the aliasing layer to make
|
||||
the operation arguments "correct" for the lower layer
|
||||
by mapping an vnode arguments to the lower layer.
|
||||
.Pp
|
||||
The first approach is to call the aliasing layer's bypass routine.
|
||||
This method is most suitable when you wish to invoke the operation
|
||||
currently being handled on the lower layer. It has the advantage
|
||||
the the bypass routine already must do argument mapping.
|
||||
An example of this is
|
||||
.Em null_getattrs
|
||||
in the null layer.
|
||||
.Pp
|
||||
A second approach is to directly invoked vnode operations on
|
||||
the lower layer with the
|
||||
.Em VOP_OPERATIONNAME
|
||||
interface.
|
||||
The advantage of this method is that it is easy to invoke
|
||||
arbitrary operations on the lower layer. The disadvantage
|
||||
is that vnodes arguments must be manually mapped.
|
||||
.\"
|
||||
.\"
|
||||
.Sh SEE ALSO
|
||||
.Xr mount 8
|
||||
.sp
|
||||
UCLA Technical Report CSD-910056,
|
||||
.Em "Stackable Layers: an Architecture for File System Development" .
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mount_null
|
||||
utility first appeared in 4.4BSD.
|
129
sbin/mount_nullfs/mount_nullfs.c
Normal file
129
sbin/mount_nullfs/mount_nullfs.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount_null.c 8.5 (Berkeley) 3/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int subdir __P((const char *, const char *));
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct null_args args;
|
||||
int ch, mntflags;
|
||||
char target[MAXPATHLEN];
|
||||
|
||||
mntflags = 0;
|
||||
while ((ch = getopt(argc, argv, "o:")) != EOF)
|
||||
switch(ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
if (realpath(argv[0], target) == 0)
|
||||
err(1, "%s", target);
|
||||
|
||||
if (subdir(target, argv[1]) || subdir(argv[1], target))
|
||||
errx(1, "%s (%s) and %s are not distinct paths",
|
||||
argv[0], target, argv[1]);
|
||||
|
||||
args.target = target;
|
||||
|
||||
if (mount(MOUNT_NULL, argv[1], mntflags, &args))
|
||||
err(1, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
subdir(p, dir)
|
||||
const char *p;
|
||||
const char *dir;
|
||||
{
|
||||
int l;
|
||||
|
||||
l = strlen(dir);
|
||||
if (l <= 1)
|
||||
return (1);
|
||||
|
||||
if ((strncmp(p, dir, l) == 0) && (p[l] == '/' || p[l] == '\0'))
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_null [-o options] target_fs mount_point\n");
|
||||
exit(1);
|
||||
}
|
15
sbin/mount_portalfs/Makefile
Normal file
15
sbin/mount_portalfs/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
# @(#)Makefile 8.3 (Berkeley) 3/27/94
|
||||
|
||||
PROG= mount_portal
|
||||
SRCS= mount_portal.c activate.c conf.c getmntopts.c pt_conf.c \
|
||||
pt_exec.c pt_file.c pt_tcp.c
|
||||
MAN8= mount_portal.0
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I/sys -I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
DPADD= $(LIBCOMPAT)
|
||||
LDADD= -lcompat
|
||||
|
||||
.include <bsd.prog.mk>
|
215
sbin/mount_portalfs/activate.c
Normal file
215
sbin/mount_portalfs/activate.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)activate.c 8.2 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: activate.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
/*
|
||||
* Scan the providers list and call the
|
||||
* appropriate function.
|
||||
*/
|
||||
static int activate_argv(pcr, key, v, so, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int so;
|
||||
int *fdp;
|
||||
{
|
||||
provider *pr;
|
||||
|
||||
for (pr = providers; pr->pr_match; pr++)
|
||||
if (strcmp(v[0], pr->pr_match) == 0)
|
||||
return ((*pr->pr_func)(pcr, key, v, so, fdp));
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static int get_request(so, pcr, key, klen)
|
||||
int so;
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
int klen;
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
int n;
|
||||
|
||||
iov[0].iov_base = (caddr_t) pcr;
|
||||
iov[0].iov_len = sizeof(*pcr);
|
||||
iov[1].iov_base = key;
|
||||
iov[1].iov_len = klen;
|
||||
|
||||
bzero((char *) &msg, sizeof(msg));
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 2;
|
||||
|
||||
n = recvmsg(so, &msg, 0);
|
||||
if (n < 0)
|
||||
return (errno);
|
||||
|
||||
if (n <= sizeof(*pcr))
|
||||
return (EINVAL);
|
||||
|
||||
n -= sizeof(*pcr);
|
||||
key[n] = '\0';
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void send_reply(so, fd, error)
|
||||
int so;
|
||||
int fd;
|
||||
int error;
|
||||
{
|
||||
int n;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
struct {
|
||||
struct cmsghdr cmsg;
|
||||
int fd;
|
||||
} ctl;
|
||||
|
||||
/*
|
||||
* Line up error code. Don't worry about byte ordering
|
||||
* because we must be sending to the local machine.
|
||||
*/
|
||||
iov.iov_base = (caddr_t) &error;
|
||||
iov.iov_len = sizeof(error);
|
||||
|
||||
/*
|
||||
* Build a msghdr
|
||||
*/
|
||||
bzero((char *) &msg, sizeof(msg));
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
/*
|
||||
* If there is a file descriptor to send then
|
||||
* construct a suitable rights control message.
|
||||
*/
|
||||
if (fd >= 0) {
|
||||
ctl.fd = fd;
|
||||
ctl.cmsg.cmsg_len = sizeof(ctl);
|
||||
ctl.cmsg.cmsg_level = SOL_SOCKET;
|
||||
ctl.cmsg.cmsg_type = SCM_RIGHTS;
|
||||
msg.msg_control = (caddr_t) &ctl;
|
||||
msg.msg_controllen = ctl.cmsg.cmsg_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send to kernel...
|
||||
*/
|
||||
if ((n = sendmsg(so, &msg, MSG_EOR)) < 0)
|
||||
syslog(LOG_ERR, "send: %s", strerror(errno));
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "sent %d bytes\n", n);
|
||||
#endif
|
||||
sleep(1); /*XXX*/
|
||||
#ifdef notdef
|
||||
if (shutdown(so, 2) < 0)
|
||||
syslog(LOG_ERR, "shutdown: %s", strerror(errno));
|
||||
#endif
|
||||
/*
|
||||
* Throw away the open file descriptor
|
||||
*/
|
||||
(void) close(fd);
|
||||
}
|
||||
|
||||
void activate(q, so)
|
||||
qelem *q;
|
||||
int so;
|
||||
{
|
||||
struct portal_cred pcred;
|
||||
char key[MAXPATHLEN+1];
|
||||
int error;
|
||||
char **v;
|
||||
int fd = -1;
|
||||
|
||||
/*
|
||||
* Read the key from the socket
|
||||
*/
|
||||
error = get_request(so, &pcred, key, sizeof(key));
|
||||
if (error) {
|
||||
syslog(LOG_ERR, "activate: recvmsg: %s", strerror(error));
|
||||
goto drop;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "lookup key %s\n", key);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find a match in the configuration file
|
||||
*/
|
||||
v = conf_match(q, key);
|
||||
|
||||
/*
|
||||
* If a match existed, then find an appropriate portal
|
||||
* otherwise simply return ENOENT.
|
||||
*/
|
||||
if (v) {
|
||||
error = activate_argv(&pcred, key, v, so, &fd);
|
||||
if (error)
|
||||
fd = -1;
|
||||
else if (fd < 0)
|
||||
error = -1;
|
||||
} else {
|
||||
error = ENOENT;
|
||||
}
|
||||
|
||||
if (error >= 0)
|
||||
send_reply(so, fd, error);
|
||||
|
||||
drop:;
|
||||
close(so);
|
||||
}
|
329
sbin/mount_portalfs/conf.c
Normal file
329
sbin/mount_portalfs/conf.c
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)conf.c 8.2 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <regexp.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
#define ALLOC(ty) (xmalloc(sizeof(ty)))
|
||||
|
||||
typedef struct path path;
|
||||
struct path {
|
||||
qelem p_q; /* 2-way linked list */
|
||||
int p_lno; /* Line number of this record */
|
||||
char *p_args; /* copy of arg string (malloc) */
|
||||
char *p_key; /* Pathname to match (also p_argv[0]) */
|
||||
regexp *p_re; /* RE to match against pathname (malloc) */
|
||||
int p_argc; /* number of elements in arg string */
|
||||
char **p_argv; /* argv[] pointers into arg string (malloc) */
|
||||
};
|
||||
|
||||
static char *conf_file; /* XXX for regerror */
|
||||
static path *curp; /* XXX for regerror */
|
||||
|
||||
/*
|
||||
* Add an element to a 2-way list,
|
||||
* just after (pred)
|
||||
*/
|
||||
static void ins_que(elem, pred)
|
||||
qelem *elem, *pred;
|
||||
{
|
||||
qelem *p = pred->q_forw;
|
||||
elem->q_back = pred;
|
||||
elem->q_forw = p;
|
||||
pred->q_forw = elem;
|
||||
p->q_back = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an element from a 2-way list
|
||||
*/
|
||||
static void rem_que(elem)
|
||||
qelem *elem;
|
||||
{
|
||||
qelem *p = elem->q_forw;
|
||||
qelem *p2 = elem->q_back;
|
||||
p2->q_forw = p;
|
||||
p->q_back = p2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Error checking malloc
|
||||
*/
|
||||
static void *xmalloc(siz)
|
||||
unsigned siz;
|
||||
{
|
||||
void *p = malloc(siz);
|
||||
if (p)
|
||||
return (p);
|
||||
syslog(LOG_ALERT, "malloc: failed to get %d bytes", siz);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the path in the list.
|
||||
* If there is already an element with the same key then
|
||||
* the *second* one is ignored (return 0). If the key is
|
||||
* not found then the path is added to the end of the list
|
||||
* and 1 is returned.
|
||||
*/
|
||||
static int pinsert(p0, q0)
|
||||
path *p0;
|
||||
qelem *q0;
|
||||
{
|
||||
qelem *q;
|
||||
|
||||
if (p0->p_argc == 0)
|
||||
return (0);
|
||||
|
||||
for (q = q0->q_forw; q != q0; q = q->q_forw) {
|
||||
path *p = (path *) q;
|
||||
if (strcmp(p->p_key, p0->p_key) == 0)
|
||||
return (0);
|
||||
}
|
||||
ins_que(&p0->p_q, q0->q_back);
|
||||
return (1);
|
||||
|
||||
}
|
||||
|
||||
void regerror(s)
|
||||
const char *s;
|
||||
{
|
||||
syslog(LOG_ERR, "%s:%s: regcomp %s: %s",
|
||||
conf_file, curp->p_lno, curp->p_key, s);
|
||||
}
|
||||
|
||||
static path *palloc(cline, lno)
|
||||
char *cline;
|
||||
int lno;
|
||||
{
|
||||
int c;
|
||||
char *s;
|
||||
char *key;
|
||||
path *p;
|
||||
char **ap;
|
||||
|
||||
/*
|
||||
* Implement comment chars
|
||||
*/
|
||||
s = strchr(cline, '#');
|
||||
if (s)
|
||||
*s = 0;
|
||||
|
||||
/*
|
||||
* Do a pass through the string to count the number
|
||||
* of arguments
|
||||
*/
|
||||
c = 0;
|
||||
key = strdup(cline);
|
||||
for (s = key; s != NULL; ) {
|
||||
char *val;
|
||||
while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
|
||||
;
|
||||
if (val)
|
||||
c++;
|
||||
}
|
||||
c++;
|
||||
free(key);
|
||||
|
||||
if (c <= 1)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Now do another pass and generate a new path structure
|
||||
*/
|
||||
p = ALLOC(path);
|
||||
p->p_argc = 0;
|
||||
p->p_argv = xmalloc(c * sizeof(char *));
|
||||
p->p_args = strdup(cline);
|
||||
ap = p->p_argv;
|
||||
for (s = p->p_args; s != NULL; ) {
|
||||
char *val;
|
||||
while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
|
||||
;
|
||||
if (val) {
|
||||
*ap++ = val;
|
||||
p->p_argc++;
|
||||
}
|
||||
}
|
||||
*ap = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (c = 0; c < p->p_argc; c++)
|
||||
printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]);
|
||||
#endif
|
||||
|
||||
p->p_key = p->p_argv[0];
|
||||
if (strpbrk(p->p_key, RE_CHARS)) {
|
||||
curp = p; /* XXX */
|
||||
p->p_re = regcomp(p->p_key);
|
||||
curp = 0; /* XXX */
|
||||
} else {
|
||||
p->p_re = 0;
|
||||
}
|
||||
p->p_lno = lno;
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a path structure
|
||||
*/
|
||||
static void pfree(p)
|
||||
path *p;
|
||||
{
|
||||
free(p->p_args);
|
||||
if (p->p_re)
|
||||
free((char *) p->p_re);
|
||||
free((char *) p->p_argv);
|
||||
free((char *) p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Discard all currently held path structures on q0.
|
||||
* and add all the ones on xq.
|
||||
*/
|
||||
static void preplace(q0, xq)
|
||||
qelem *q0;
|
||||
qelem *xq;
|
||||
{
|
||||
/*
|
||||
* While the list is not empty,
|
||||
* take the first element off the list
|
||||
* and free it.
|
||||
*/
|
||||
while (q0->q_forw != q0) {
|
||||
qelem *q = q0->q_forw;
|
||||
rem_que(q);
|
||||
pfree((path *) q);
|
||||
}
|
||||
while (xq->q_forw != xq) {
|
||||
qelem *q = xq->q_forw;
|
||||
rem_que(q);
|
||||
ins_que(q, q0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the lines from the configuration file and
|
||||
* add them to the list of paths.
|
||||
*/
|
||||
static void readfp(q0, fp)
|
||||
qelem *q0;
|
||||
FILE *fp;
|
||||
{
|
||||
char cline[LINE_MAX];
|
||||
int nread = 0;
|
||||
qelem q;
|
||||
|
||||
/*
|
||||
* Make a new empty list.
|
||||
*/
|
||||
q.q_forw = q.q_back = &q;
|
||||
|
||||
/*
|
||||
* Read the lines from the configuration file.
|
||||
*/
|
||||
while (fgets(cline, sizeof(cline), fp)) {
|
||||
path *p = palloc(cline, nread+1);
|
||||
if (p && !pinsert(p, &q))
|
||||
pfree(p);
|
||||
nread++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If some records were read, then throw
|
||||
* away the old list and replace with the
|
||||
* new one.
|
||||
*/
|
||||
if (nread)
|
||||
preplace(q0, &q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the configuration file (conf) and replace
|
||||
* the existing path list with the new version.
|
||||
* If the file is not readable, then no changes take place
|
||||
*/
|
||||
void conf_read(q, conf)
|
||||
qelem *q;
|
||||
char *conf;
|
||||
{
|
||||
FILE *fp = fopen(conf, "r");
|
||||
if (fp) {
|
||||
conf_file = conf; /* XXX */
|
||||
readfp(q, fp);
|
||||
conf_file = 0; /* XXX */
|
||||
(void) fclose(fp);
|
||||
} else {
|
||||
syslog(LOG_ERR, "open config file \"%s\": %s", conf, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char **conf_match(q0, key)
|
||||
qelem *q0;
|
||||
char *key;
|
||||
{
|
||||
qelem *q;
|
||||
|
||||
for (q = q0->q_forw; q != q0; q = q->q_forw) {
|
||||
path *p = (path *) q;
|
||||
if (p->p_re) {
|
||||
if (regexec(p->p_re, key))
|
||||
return (p->p_argv+1);
|
||||
} else {
|
||||
if (strncmp(p->p_key, key, strlen(p->p_key)) == 0)
|
||||
return (p->p_argv+1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
136
sbin/mount_portalfs/mount_portalfs.8
Normal file
136
sbin/mount_portalfs/mount_portalfs.8
Normal file
@ -0,0 +1,136 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software donated to Berkeley by
|
||||
.\" Jan-Simon Pendry.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)mount_portal.8 8.3 (Berkeley) 3/27/94
|
||||
.\"
|
||||
.\"
|
||||
.Dd March 27, 1994
|
||||
.Dt MOUNT_PORTAL 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_portal
|
||||
.Nd mount the portal daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount_portal
|
||||
.Op Fl o Ar options
|
||||
.Ar /etc/portal.conf
|
||||
.Ar mount_point
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount_portal
|
||||
command attaches an instance of the portal daemon
|
||||
to the global filesystem namespace.
|
||||
The conventional mount point is
|
||||
.Pa /p .
|
||||
.PA /dev .
|
||||
This command is normally executed by
|
||||
.Xr mount 8
|
||||
at boot time.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl o
|
||||
Options are specified with a
|
||||
.Fl o
|
||||
flag followed by a comma separated string of options.
|
||||
See the
|
||||
.Xr mount 8
|
||||
man page for possible options and their meanings.
|
||||
.El
|
||||
.Pp
|
||||
The portal daemon provides an
|
||||
.Em open
|
||||
service.
|
||||
Objects opened under the portal mount point are
|
||||
dynamically created by the portal daemon according
|
||||
to rules specified in the named configuration file.
|
||||
Using this mechanism allows descriptors such as sockets
|
||||
to be made available in the filesystem namespace.
|
||||
.Pp
|
||||
The portal daemon works by being passed the full pathname
|
||||
of the object being opened.
|
||||
The daemon creates an appropriate descriptor according
|
||||
to the rules in the configuration file, and then passes the descriptor back
|
||||
to the calling process as the result of the open system call.
|
||||
.Sh NAMESPACE
|
||||
By convention, the portal daemon divides the namespace into sub-namespaces,
|
||||
each of which handles objects of a particular type.
|
||||
.Pp
|
||||
Currently, two sub-namespaces are implemented:
|
||||
.Pa tcp
|
||||
and
|
||||
.Pa fs .
|
||||
The
|
||||
.Pa tcp
|
||||
namespace takes a hostname and a port (slash separated) and
|
||||
creates an open TCP/IP connection.
|
||||
The
|
||||
.Pa fs
|
||||
namespace opens the named file, starting back at the root directory.
|
||||
This can be used to provide a controlled escape path from
|
||||
a chrooted environment.
|
||||
.Sh "CONFIGURATION FILE"
|
||||
The configuration file contains a list of rules.
|
||||
Each rule takes one line and consists of two or more
|
||||
whitespace separated fields.
|
||||
A hash (``#'') character causes the remainder of a line to
|
||||
be ignored. Blank lines are ignored.
|
||||
.Pp
|
||||
The first field is a pathname prefix to match
|
||||
against the requested pathname.
|
||||
If a match is found, the second field
|
||||
tells the daemon what type of object to create.
|
||||
Subsequent fields are passed to the creation function.
|
||||
.Bd -literal
|
||||
# @(#)portal.conf 5.1 (Berkeley) 7/13/92
|
||||
tcp/ tcp tcp/
|
||||
fs/ file fs/
|
||||
.Ed
|
||||
.Sh FILES
|
||||
.Bl -tag -width /p/* -compact
|
||||
.It Pa /p/*
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mount 2 ,
|
||||
.Xr unmount 2 ,
|
||||
.Xr fstab 5 ,
|
||||
.Xr mount 8
|
||||
.Sh CAVEATS
|
||||
This filesystem may not be NFS-exported.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mount_portal
|
||||
utility first appeared in 4.4BSD.
|
261
sbin/mount_portalfs/mount_portalfs.c
Normal file
261
sbin/mount_portalfs/mount_portalfs.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount_portal.c 8.4 (Berkeley) 3/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
#include "pathnames.h"
|
||||
#include "portald.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void usage __P((void));
|
||||
|
||||
static sig_atomic_t readcf; /* Set when SIGHUP received */
|
||||
|
||||
static void sigchld(sig)
|
||||
int sig;
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0)
|
||||
;
|
||||
if (pid < 0)
|
||||
syslog(LOG_WARNING, "waitpid: %s", strerror(errno));
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct portal_args args;
|
||||
struct sockaddr_un un;
|
||||
char *conf;
|
||||
char *mountpt;
|
||||
int mntflags = 0;
|
||||
char tag[32];
|
||||
|
||||
qelem q;
|
||||
int rc;
|
||||
int so;
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Crack command line args
|
||||
*/
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "o:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags);
|
||||
break;
|
||||
default:
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != (argc - 2))
|
||||
error = 1;
|
||||
|
||||
if (error)
|
||||
usage();
|
||||
|
||||
/*
|
||||
* Get config file and mount point
|
||||
*/
|
||||
conf = argv[optind];
|
||||
mountpt = argv[optind+1];
|
||||
|
||||
/*
|
||||
* Construct the listening socket
|
||||
*/
|
||||
un.sun_family = AF_UNIX;
|
||||
if (sizeof(_PATH_TMPPORTAL) >= sizeof(un.sun_path)) {
|
||||
fprintf(stderr, "mount_portal: portal socket name too long\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(un.sun_path, _PATH_TMPPORTAL);
|
||||
mktemp(un.sun_path);
|
||||
un.sun_len = strlen(un.sun_path);
|
||||
|
||||
so = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (so < 0) {
|
||||
fprintf(stderr, "mount_portal: socket: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
(void) unlink(un.sun_path);
|
||||
if (bind(so, (struct sockaddr *) &un, sizeof(un)) < 0)
|
||||
err(1, NULL);
|
||||
(void) unlink(un.sun_path);
|
||||
|
||||
(void) listen(so, 5);
|
||||
|
||||
args.pa_socket = so;
|
||||
sprintf(tag, "portal:%d", getpid());
|
||||
args.pa_config = tag;
|
||||
|
||||
rc = mount(MOUNT_PORTAL, mountpt, mntflags, &args);
|
||||
if (rc < 0)
|
||||
err(1, NULL);
|
||||
|
||||
#ifdef notdef
|
||||
/*
|
||||
* Everything is ready to go - now is a good time to fork
|
||||
*/
|
||||
daemon(0, 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start logging (and change name)
|
||||
*/
|
||||
openlog("portald", LOG_CONS|LOG_PID, LOG_DAEMON);
|
||||
|
||||
q.q_forw = q.q_back = &q;
|
||||
readcf = 1;
|
||||
|
||||
signal(SIGCHLD, sigchld);
|
||||
|
||||
/*
|
||||
* Just loop waiting for new connections and activating them
|
||||
*/
|
||||
for (;;) {
|
||||
struct sockaddr_un un2;
|
||||
int len2 = sizeof(un2);
|
||||
int so2;
|
||||
pid_t pid;
|
||||
fd_set fdset;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Check whether we need to re-read the configuration file
|
||||
*/
|
||||
if (readcf) {
|
||||
readcf = 0;
|
||||
conf_read(&q, conf);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept a new connection
|
||||
* Will get EINTR if a signal has arrived, so just
|
||||
* ignore that error code
|
||||
*/
|
||||
FD_SET(so, &fdset);
|
||||
rc = select(so+1, &fdset, (void *) 0, (void *) 0, (void *) 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
syslog(LOG_ERR, "select: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (rc == 0)
|
||||
break;
|
||||
so2 = accept(so, (struct sockaddr *) &un2, &len2);
|
||||
if (so2 < 0) {
|
||||
/*
|
||||
* The unmount function does a shutdown on the socket
|
||||
* which will generated ECONNABORTED on the accept.
|
||||
*/
|
||||
if (errno == ECONNABORTED)
|
||||
break;
|
||||
if (errno != EINTR) {
|
||||
syslog(LOG_ERR, "accept: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now fork a new child to deal with the connection
|
||||
*/
|
||||
eagain:;
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
if (errno == EAGAIN) {
|
||||
sleep(1);
|
||||
goto eagain;
|
||||
}
|
||||
syslog(LOG_ERR, "fork: %s", strerror(errno));
|
||||
break;
|
||||
case 0:
|
||||
(void) close(so);
|
||||
activate(&q, so2);
|
||||
break;
|
||||
default:
|
||||
(void) close(so2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
syslog(LOG_INFO, "%s unmounted", mountpt);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_portal [-o options] config mount-point\n");
|
||||
exit(1);
|
||||
}
|
44
sbin/mount_portalfs/pathnames.h
Normal file
44
sbin/mount_portalfs/pathnames.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* $Id: pathnames.h,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_TMPPORTAL "/tmp/portalXXXXXX" /* Scratch socket name */
|
7
sbin/mount_portalfs/portal.conf
Normal file
7
sbin/mount_portalfs/portal.conf
Normal file
@ -0,0 +1,7 @@
|
||||
# @(#)portal.conf 8.1 (Berkeley) 6/5/93
|
||||
# $Id: portal.conf,v 1.1 1992/05/27 06:50:13 jsp Exp jsp $
|
||||
tcplisten/ tcplisten tcplisten/
|
||||
tcp/ tcp tcp/
|
||||
fs/ file fs/
|
||||
pipe/ pipe
|
||||
foo/ exec ./bar bar baz
|
82
sbin/mount_portalfs/portald.h
Normal file
82
sbin/mount_portalfs/portald.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)portald.h 8.1 (Berkeley) 6/5/93
|
||||
*
|
||||
* $Id: portald.h,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
|
||||
/*
|
||||
* Meta-chars in an RE. Paths in the config file containing
|
||||
* any of these characters will be matched using regexec, other
|
||||
* paths will be prefix-matched.
|
||||
*/
|
||||
#define RE_CHARS ".|()[]*+?\\^$"
|
||||
|
||||
typedef struct qelem qelem;
|
||||
|
||||
struct qelem {
|
||||
qelem *q_forw;
|
||||
qelem *q_back;
|
||||
};
|
||||
|
||||
typedef struct provider provider;
|
||||
struct provider {
|
||||
char *pr_match;
|
||||
int (*pr_func) __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
};
|
||||
extern provider providers[];
|
||||
|
||||
/*
|
||||
* Portal providers
|
||||
*/
|
||||
extern int portal_exec __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
extern int portal_file __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
extern int portal_tcp __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
|
||||
/*
|
||||
* Global functions
|
||||
*/
|
||||
extern void activate __P((qelem *q, int so));
|
||||
extern char **conf_match __P((qelem *q, char *key));
|
||||
extern void conf_read __P((qelem *q, char *conf));
|
51
sbin/mount_portalfs/pt_conf.c
Normal file
51
sbin/mount_portalfs/pt_conf.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_conf.c 8.1 (Berkeley) 6/5/93
|
||||
*
|
||||
* $Id: pt_conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include "portald.h"
|
||||
|
||||
provider providers[] = {
|
||||
{ "exec", portal_exec },
|
||||
{ "file", portal_file },
|
||||
{ "tcp", portal_tcp },
|
||||
{ 0, 0 }
|
||||
};
|
61
sbin/mount_portalfs/pt_exec.c
Normal file
61
sbin/mount_portalfs/pt_exec.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_exec.c 8.1 (Berkeley) 6/5/93
|
||||
*
|
||||
* $Id: pt_exec.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
int portal_exec(pcr, key, v, so, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int so;
|
||||
int *fdp;
|
||||
{
|
||||
return (ENOEXEC);
|
||||
}
|
||||
|
106
sbin/mount_portalfs/pt_file.c
Normal file
106
sbin/mount_portalfs/pt_file.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_file.c 8.2 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: pt_file.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
int portal_file(pcr, key, v, so, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int so;
|
||||
int *fdp;
|
||||
{
|
||||
int fd;
|
||||
char pbuf[MAXPATHLEN];
|
||||
int error;
|
||||
int gidset[NGROUPS];
|
||||
int i;
|
||||
|
||||
pbuf[0] = '/';
|
||||
strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("path = %s, uid = %d, gid = %d\n", pbuf, pcr->pcr_uid, pcr->pcr_groups[0]);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < pcr->pcr_ngroups; i++)
|
||||
gidset[i] = pcr->pcr_groups[i];
|
||||
|
||||
if (setgroups(pcr->pcr_ngroups, gidset) < 0)
|
||||
return (errno);
|
||||
|
||||
if (seteuid(pcr->pcr_uid) < 0)
|
||||
return (errno);
|
||||
|
||||
fd = open(pbuf, O_RDWR|O_CREAT, 0666);
|
||||
if (fd < 0)
|
||||
error = errno;
|
||||
else
|
||||
error = 0;
|
||||
|
||||
if (seteuid((uid_t) 0) < 0) { /* XXX - should reset gidset too */
|
||||
error = errno;
|
||||
syslog(LOG_ERR, "setcred: %s", strerror(error));
|
||||
if (fd >= 0) {
|
||||
(void) close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
*fdp = fd;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "pt_file returns *fdp = %d, error = %d\n", *fdp, error);
|
||||
#endif
|
||||
|
||||
return (error);
|
||||
}
|
158
sbin/mount_portalfs/pt_tcp.c
Normal file
158
sbin/mount_portalfs/pt_tcp.c
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_tcp.c 8.3 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: pt_tcp.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
/*
|
||||
* Key will be tcp/host/port[/"priv"]
|
||||
* Create a TCP socket connected to the
|
||||
* requested host and port.
|
||||
* Some trailing suffix values have special meanings.
|
||||
* An unrecognised suffix is an error.
|
||||
*/
|
||||
int portal_tcp(pcr, key, v, kso, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int kso;
|
||||
int *fdp;
|
||||
{
|
||||
char host[MAXHOSTNAMELEN];
|
||||
char port[MAXHOSTNAMELEN];
|
||||
char *p = key + (v[1] ? strlen(v[1]) : 0);
|
||||
char *q;
|
||||
struct hostent *hp;
|
||||
struct servent *sp;
|
||||
struct in_addr **ipp;
|
||||
struct in_addr *ip[2];
|
||||
struct in_addr ina;
|
||||
int s_port;
|
||||
int priv = 0;
|
||||
struct sockaddr_in sain;
|
||||
|
||||
q = strchr(p, '/');
|
||||
if (q == 0 || q - p >= sizeof(host))
|
||||
return (EINVAL);
|
||||
*q = '\0';
|
||||
strcpy(host, p);
|
||||
p = q + 1;
|
||||
|
||||
q = strchr(p, '/');
|
||||
if (q)
|
||||
*q = '\0';
|
||||
if (strlen(p) >= sizeof(port))
|
||||
return (EINVAL);
|
||||
strcpy(port, p);
|
||||
if (q) {
|
||||
p = q + 1;
|
||||
if (strcmp(p, "priv") == 0) {
|
||||
if (pcr->pcr_uid == 0)
|
||||
priv = 1;
|
||||
else
|
||||
return (EPERM);
|
||||
} else {
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
hp = gethostbyname(host);
|
||||
if (hp != 0) {
|
||||
ipp = (struct in_addr **) hp->h_addr_list;
|
||||
} else {
|
||||
ina.s_addr = inet_addr(host);
|
||||
if (ina.s_addr == INADDR_NONE)
|
||||
return (EINVAL);
|
||||
ip[0] = &ina;
|
||||
ip[1] = 0;
|
||||
ipp = ip;
|
||||
}
|
||||
|
||||
sp = getservbyname(port, "tcp");
|
||||
if (sp != 0)
|
||||
s_port = sp->s_port;
|
||||
else {
|
||||
s_port = atoi(port);
|
||||
if (s_port == 0)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
bzero(&sain, sizeof(sain));
|
||||
sain.sin_len = sizeof(sain);
|
||||
sain.sin_family = AF_INET;
|
||||
sain.sin_port = s_port;
|
||||
|
||||
while (ipp[0]) {
|
||||
int so;
|
||||
|
||||
if (priv)
|
||||
so = rresvport((int *) 0);
|
||||
else
|
||||
so = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (so < 0) {
|
||||
syslog(LOG_ERR, "socket: %m");
|
||||
return (errno);
|
||||
}
|
||||
|
||||
sain.sin_addr = *ipp[0];
|
||||
if (connect(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
|
||||
*fdp = so;
|
||||
return (0);
|
||||
}
|
||||
(void) close(so);
|
||||
|
||||
ipp++;
|
||||
}
|
||||
|
||||
return (errno);
|
||||
}
|
11
sbin/mount_umapfs/Makefile
Normal file
11
sbin/mount_umapfs/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# @(#)Makefile 8.3 (Berkeley) 3/27/94
|
||||
|
||||
PROG= mount_umap
|
||||
SRCS= mount_umap.c getmntopts.c
|
||||
MAN8= mount_umap.0
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I/sys -I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
131
sbin/mount_umapfs/mount_umapfs.8
Normal file
131
sbin/mount_umapfs/mount_umapfs.8
Normal file
@ -0,0 +1,131 @@
|
||||
.\" Copyright (c) 1992, 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software donated to Berkeley by
|
||||
.\" Jan-Simon Pendry and from John Heidemann of the UCLA Ficus project.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)mount_umap.8 8.3 (Berkeley) 3/27/94
|
||||
.\"
|
||||
.Dd "March 27, 1994"
|
||||
.Dt MOUNT_UMAP 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_umap
|
||||
.Nd sample file system layer
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount_umap
|
||||
.Op Fl o Ar options
|
||||
.Ar target
|
||||
.Ar mount-point
|
||||
.Ar uid-mapfile
|
||||
.Ar gid-mapfile
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount_umap
|
||||
command is used to mount a sub-tree of an existing file system
|
||||
that uses a different set of uids and gids than the local system.
|
||||
Such a file system could be mounted from a remote site via NFS or
|
||||
it could be a file system on removable media brought from some
|
||||
foreign location that uses a different password file.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl o
|
||||
Options are specified with a
|
||||
.Fl o
|
||||
flag followed by a comma separated string of options.
|
||||
See the
|
||||
.Xr mount 8
|
||||
man page for possible options and their meanings.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Nm mount_umap
|
||||
command uses a set of files provided by the user to make correspondences
|
||||
between uids and gids in the sub-tree's original environment and
|
||||
some other set of ids in the local environment. For instance, user
|
||||
smith might have uid 1000 in the original environment, while having
|
||||
uid 2000 in the local environment. The
|
||||
.Nm mount_umap
|
||||
command allows the subtree from smith's original environment to be
|
||||
mapped in such a way that all files with owning uid 1000 look like
|
||||
they are actually owned by uid 2000.
|
||||
.Pp
|
||||
.Em target
|
||||
should be the current location of the sub-tree in the
|
||||
local system's name space.
|
||||
.Em mount-point
|
||||
should be a directory
|
||||
where the mapped subtree is to be placed.
|
||||
.Em uid-mapfile
|
||||
and
|
||||
.Em gid-mapfile
|
||||
describe the mappings to be made between identifiers.
|
||||
Briefly, the format of these files is a count of the number of
|
||||
mappings on the first line, with each subsequent line containing
|
||||
a single mapping. Each of these mappings consists of an id from
|
||||
the original environment and the corresponding id in the local environment,
|
||||
separated by white space.
|
||||
.Em uid-mapfile
|
||||
should contain all uid
|
||||
mappings, and
|
||||
.Em gid-mapfile
|
||||
should contain all gid mappings.
|
||||
Any uids not mapped in
|
||||
.Em uid-mapfile
|
||||
will be treated as user NOBODY,
|
||||
and any gids not mapped in
|
||||
.Em gid-mapfile
|
||||
will be treated as group
|
||||
NULLGROUP. At most 64 uids can be mapped for a given subtree, and
|
||||
at most 16 groups can be mapped by a given subtree.
|
||||
.Pp
|
||||
The mapfiles can be located anywhere in the file hierarchy, but they
|
||||
must be owned by root, and they must be writable only by root.
|
||||
.Nm mount_umap
|
||||
will refuse to map the sub-tree if the ownership or permissions on
|
||||
these files are improper. It will also balk if the count of mappings
|
||||
in the first line of the map files is not correct.
|
||||
.Pp
|
||||
The layer created by the
|
||||
.Nm mount_umap
|
||||
command is meant to serve as a simple example of file system layering.
|
||||
It is not meant for production use. The implementation is not very
|
||||
sophisticated.
|
||||
.Sh SEE ALSO
|
||||
.Xr mount 8 ,
|
||||
.Xr mount_null 8 ,
|
||||
.Xr mount_lofs 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mount_umap
|
||||
utility first appeared in 4.4BSD.
|
232
sbin/mount_umapfs/mount_umapfs.c
Normal file
232
sbin/mount_umapfs/mount_umapfs.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount_umap.c 8.3 (Berkeley) 3/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
#define ROOTUSER 0
|
||||
/*
|
||||
* This define controls whether any user but the superuser can own and
|
||||
* write mapfiles. If other users can, system security can be gravely
|
||||
* compromised. If this is not a concern, undefine SECURITY.
|
||||
*/
|
||||
#define MAPSECURITY 1
|
||||
|
||||
/*
|
||||
* This routine provides the user interface to mounting a umap layer.
|
||||
* It takes 4 mandatory parameters. The mandatory arguments are the place
|
||||
* where the next lower level is mounted, the place where the umap layer is to
|
||||
* be mounted, the name of the user mapfile, and the name of the group
|
||||
* mapfile. The routine checks the ownerships and permissions on the
|
||||
* mapfiles, then opens and reads them. Then it calls mount(), which
|
||||
* will, in turn, call the umap version of mount.
|
||||
*/
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
static char not[] = "; not mounted.";
|
||||
struct stat statbuf;
|
||||
struct umap_args args;
|
||||
FILE *fp, *gfp;
|
||||
u_long gmapdata[GMAPFILEENTRIES][2], mapdata[MAPFILEENTRIES][2];
|
||||
int ch, count, gnentries, mntflags, nentries;
|
||||
char *gmapfile, *mapfile, *source, *target, buf[20];
|
||||
|
||||
mntflags = 0;
|
||||
mapfile = gmapfile = NULL;
|
||||
while ((ch = getopt(argc, argv, "g:o:u:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'g':
|
||||
gmapfile = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags);
|
||||
break;
|
||||
case 'u':
|
||||
mapfile = optarg;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2 || mapfile == NULL || gmapfile == NULL)
|
||||
usage();
|
||||
|
||||
source = argv[0];
|
||||
target = argv[1];
|
||||
|
||||
/* Read in uid mapping data. */
|
||||
if ((fp = fopen(mapfile, "r")) == NULL)
|
||||
err(1, "%s%s", mapfile, not);
|
||||
|
||||
#ifdef MAPSECURITY
|
||||
/*
|
||||
* Check that group and other don't have write permissions on
|
||||
* this mapfile, and that the mapfile belongs to root.
|
||||
*/
|
||||
if (fstat(fileno(fp), &statbuf))
|
||||
err(1, "%s%s", mapfile, not);
|
||||
if (statbuf.st_mode & S_IWGRP || statbuf.st_mode & S_IWOTH) {
|
||||
strmode(statbuf.st_mode, buf);
|
||||
err(1, "%s: improper write permissions (%s)%s",
|
||||
mapfile, buf, not);
|
||||
}
|
||||
if (statbuf.st_uid != ROOTUSER)
|
||||
errx(1, "%s does not belong to root%s", mapfile, not);
|
||||
#endif /* MAPSECURITY */
|
||||
|
||||
if ((fscanf(fp, "%d\n", &nentries)) != 1)
|
||||
errx(1, "%s: nentries not found%s", mapfile, not);
|
||||
if (nentries > MAPFILEENTRIES)
|
||||
errx(1,
|
||||
"maximum number of entries is %d%s", MAPFILEENTRIES, not);
|
||||
#if 0
|
||||
(void)printf("reading %d entries\n", nentries);
|
||||
#endif
|
||||
for (count = 0; count < nentries; ++count) {
|
||||
if ((fscanf(fp, "%lu %lu\n",
|
||||
&(mapdata[count][0]), &(mapdata[count][1]))) != 2) {
|
||||
if (ferror(fp))
|
||||
err(1, "%s%s", mapfile, not);
|
||||
if (feof(fp))
|
||||
errx(1, "%s: unexpected end-of-file%s",
|
||||
mapfile, not);
|
||||
errx(1, "%s: illegal format (line %d)%s",
|
||||
mapfile, count + 2, not);
|
||||
}
|
||||
#if 0
|
||||
/* Fix a security hole. */
|
||||
if (mapdata[count][1] == 0)
|
||||
errx(1, "mapping id 0 not permitted (line %d)%s",
|
||||
count + 2, not);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Read in gid mapping data. */
|
||||
if ((gfp = fopen(gmapfile, "r")) == NULL)
|
||||
err(1, "%s%s", gmapfile, not);
|
||||
|
||||
#ifdef MAPSECURITY
|
||||
/*
|
||||
* Check that group and other don't have write permissions on
|
||||
* this group mapfile, and that the file belongs to root.
|
||||
*/
|
||||
if (fstat(fileno(gfp), &statbuf))
|
||||
err(1, "%s%s", gmapfile, not);
|
||||
if (statbuf.st_mode & S_IWGRP || statbuf.st_mode & S_IWOTH) {
|
||||
strmode(statbuf.st_mode, buf);
|
||||
err(1, "%s: improper write permissions (%s)%s",
|
||||
gmapfile, buf, not);
|
||||
}
|
||||
if (statbuf.st_uid != ROOTUSER)
|
||||
errx(1, "%s does not belong to root%s", gmapfile, not);
|
||||
#endif /* MAPSECURITY */
|
||||
|
||||
if ((fscanf(fp, "%d\n", &gnentries)) != 1)
|
||||
errx(1, "nentries not found%s", gmapfile, not);
|
||||
if (gnentries > MAPFILEENTRIES)
|
||||
errx(1,
|
||||
"maximum number of entries is %d%s", GMAPFILEENTRIES, not);
|
||||
#if 0
|
||||
(void)printf("reading %d group entries\n", gnentries);
|
||||
#endif
|
||||
|
||||
for (count = 0; count < gnentries; ++count)
|
||||
if ((fscanf(fp, "%lu %lu\n",
|
||||
&(gmapdata[count][0]), &(gmapdata[count][1]))) != 2) {
|
||||
if (ferror(fp))
|
||||
err(1, "%s%s", gmapfile, not);
|
||||
if (feof(fp))
|
||||
errx(1, "%s: unexpected end-of-file%s",
|
||||
gmapfile, not);
|
||||
errx(1, "%s: illegal format (line %d)%s",
|
||||
gmapfile, count + 2, not);
|
||||
}
|
||||
|
||||
|
||||
/* Setup mount call args. */
|
||||
args.target = source;
|
||||
args.nentries = nentries;
|
||||
args.mapdata = mapdata;
|
||||
args.gnentries = gnentries;
|
||||
args.gmapdata = gmapdata;
|
||||
|
||||
if (mount(MOUNT_UMAP, argv[1], mntflags, &args))
|
||||
err(1, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_umap [-o options] -u usermap -g groupmap target_fs mount_point\n");
|
||||
exit(1);
|
||||
}
|
175
sbin/mount_umapfs/umap_manual
Normal file
175
sbin/mount_umapfs/umap_manual
Normal file
@ -0,0 +1,175 @@
|
||||
|
||||
\appendix
|
||||
\section{The umap Layer} \label{sect:umap}
|
||||
|
||||
\subsection{Introduction}
|
||||
|
||||
Normally, the file system is expected to span a single administrative domain.
|
||||
An administrative domain, for these purposes, is a machine or set of
|
||||
machines that share common password file information, usually through
|
||||
the yellow pages mechanism. File hierarchies that span more
|
||||
than one domain leads to certain problems, since the same numerical
|
||||
UID in one domain may correspond to a different user in another domain.
|
||||
If the system administrator is very careful to ensure that both domains
|
||||
contain identical user ID information, The umap layer can be used to
|
||||
run between those domains without changes
|
||||
|
||||
The umap layer is a file system layer that sits on top of the normal
|
||||
file layer. The umap layer maps Unix-style UIDs from
|
||||
one domain into the UIDs in the other domain. By setting up the mappings
|
||||
properly, the same user with different UIDs in two domains can be seen
|
||||
as the same user, from the system point of view, or, conversely, two
|
||||
different users with the same UID in the two domains can be distinguished.
|
||||
|
||||
First, we define some terms. ``User'' refers to the human (or daemon) that
|
||||
has privileges to login, run programs, and access files. ``UID''refers to
|
||||
the numerical identifier that uniquely identifies the user within a
|
||||
single domain. ``Login name'' refers to the character string the user
|
||||
types to log into the system. ``GID'' refers to the numerical group
|
||||
identifier used by Unix systems to identify groups of users. ``Group
|
||||
name'' is the character string name attached to a particular GID in the
|
||||
local {\sf /etc/groups} file or the yellow pages groups file.
|
||||
|
||||
In order for the umap layer to work properly, all users
|
||||
in either domain must have password file entries in both domains.
|
||||
They do not, however, have to have the same numerical UID, nor even the
|
||||
same character string login name (the latter is highly recommended,
|
||||
if possible, however). Any user not having a UID in one domain will be
|
||||
treated as the special user NOBODY by the other domain, probably with
|
||||
undesirable consequences. Any user not owning any files in the shared
|
||||
sub-trees need not be given a UID in the other domain.
|
||||
|
||||
Groups work similarly. The umap layer can translate group ID's between
|
||||
domains in the same manner as UID's. Again, any group that wishes to
|
||||
participate must have a group ID in both domains,
|
||||
though it need not be the same GID in both. If a group in one domain is not
|
||||
known in the other domain, that group will be treated as being NULLGROUP.
|
||||
The umap layer has no provisions for enrolling UID's from other domains
|
||||
as group members, but, since each user from each domain must have some
|
||||
UID in every domain, the UID in the local domain can be used to enroll
|
||||
the user in the local groups.
|
||||
|
||||
NOBODY and NULLGROUP are special reserved UID's and GID's, respectively.
|
||||
NOBODY is user 32767. NULLGROUP is group 65534. If the system administrator
|
||||
wants to have an appropriate text string appear when these UID's are
|
||||
encountered by programs like {\sf ls -l}, he should add these values to
|
||||
the password and {\sf /etc/groups} file, or to the appropriate yellow pages.
|
||||
If these IDs are already in use in that domain, different values can be
|
||||
used for NOBODY and NULLGROUP, but that will require a recompilation of
|
||||
the umap layer code and, as a result, the entire kernel. These
|
||||
values are defined in the {\sf umap\_info.h} file, kept with the rest of the
|
||||
umap source code.
|
||||
|
||||
When the umap layer is in use, one of the participating domains is declared
|
||||
to be the master. All UID and GID information stored for participating files
|
||||
will be stored in vnodes using its mappings, no matter what site the copies of
|
||||
the files are stored at. The master domain therefore need not run a copy
|
||||
of the umap layer, as it already has all of the correct mappings. All
|
||||
other domains must run a umap layer on top of any other layers they use.
|
||||
|
||||
\subsection{Setting Up a umap Layer}
|
||||
|
||||
The system administrator of a system needing to use the umap layer
|
||||
must take several actions.
|
||||
First, he must create files containing the necessary UID
|
||||
and GID mappings. There is a separate file for user and group IDs. The
|
||||
format of the files is the same. The first line contains the total number
|
||||
of entries in the file. Each subsequent line contains one mapping. A
|
||||
mapping line consists of two numerical UIDs, separated by white space.
|
||||
The first is the UID of a user on the local machine. The second is the
|
||||
UID for the same user on the master machine. The maximum number of users
|
||||
that can be mapped for a single shared sub-tree is 64. The maximum number of
|
||||
groups that can be mapped for a single sub-tree is 16. These constants
|
||||
are set in the {\sf umap\_info.h} file, and can be changed, but changing them
|
||||
requires recompilation. Separate mapping files can be used for each shared
|
||||
subtree, or the same mapping files can be shared by several sub-trees.
|
||||
|
||||
Below is a sample UID mapping file. There are four entries. UID 5 is mapped
|
||||
to 5, 521 to 521, and 7000 to 7000. UID 2002 is mapped to 604. On this
|
||||
machine, the UID's for users 5, 521, and 7000 are the same as on the master,
|
||||
but UID 2002 is for a user whose UID on the master machine is 604. All
|
||||
files in the sub-tree belonging to that user have UID 604 in their inodes,
|
||||
even on this machine, but the umap layer will ensure that anyone running
|
||||
under UID 2002 will have all files in this sub-tree owned by 604 treated as if
|
||||
they were owned by 2002. An {\sf ls -l} on a file owned by 604 in this sub-tree
|
||||
will show the login name associated with UID 2002 as the owner.
|
||||
|
||||
\noindent4\newline
|
||||
5 5\newline
|
||||
521 521\newline
|
||||
2002 604\newline
|
||||
7000 7000\newline
|
||||
|
||||
The user and group mapping files should be owned by the root user, and
|
||||
should be writable only by that user. If they are not owned by root, or
|
||||
are writable by some other user, the umap mounting command will abort.
|
||||
|
||||
Normally, the sub-treeis grafted directly into the place in
|
||||
the file hierarchy where the it should appear to users.Using the umap
|
||||
layer requires that the sub-tree be grafted somewhere else, and
|
||||
the umap layer be mounted in the desired position in the file hierarchy.
|
||||
Depending on the situation, the underlying sub-tree can be wherever is
|
||||
convenient.
|
||||
|
||||
\subsection{Troubleshooting umap Layer Problems}
|
||||
|
||||
The umap layer code was not built with special convenience or
|
||||
robustness in mind, as it is expected to be superseded with a better
|
||||
user ID mapping strategy in the near future. As a result, it is not
|
||||
very forgiving of errors in being set up. Here are some possible
|
||||
problems, and what to do about them.
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
|
||||
\item{Problem: A file belongs to NOBODY, or group NULLGROUP.
|
||||
|
||||
Fixes: The mapping files don't know about this file's real user or group.
|
||||
Either they are not in the mapping files, or the counts on the number of
|
||||
entries in the mapping files are too low, so entries at the end (including
|
||||
these) are being ignored. Add the entries or fix the counts, and either
|
||||
unmount and remount the sub-tree, or reboot.}
|
||||
|
||||
\item{Problem: A normal operation does not work.
|
||||
|
||||
Fixes: Possibly, some mapping has not been set properly. Check to
|
||||
see which files are used by the operation and who they appear to be
|
||||
owned by. If they are owned by NOBODY or some other suspicious user,
|
||||
there may be a problem in the mapping files. Be sure to check groups,
|
||||
too. As above, if the counts of mappings in the mapping files are lower
|
||||
than the actual numbers of pairs, pairs at the end of the file will be
|
||||
ignored. If any changes are made in the mapping files, you will need to
|
||||
either unmount and remount or reboot before they will take effect.
|
||||
|
||||
Another possible problem can arise because not all Unix utilities
|
||||
rely exclusively on numeric UID for identification. For instance,
|
||||
SCCS saves the login name in files. If a user's login name on two machines
|
||||
isn't the same, SCCS may veto an operation even though Unix file permissions,
|
||||
as checked by the umap layer, may say it's OK. There's not much to be
|
||||
done in such cases, unless the login name can be changed or one fiddles
|
||||
improperly with SCCS information. There may be other, undiscovered cases
|
||||
where similar problems arise, some of which may be even harder to handle.}
|
||||
|
||||
\item{Problem: Someone has access permissions he should not have.
|
||||
|
||||
Fixes: This is probably caused by a mistake in the mapping files. Check
|
||||
both user and group mapping files. If any changes are made in the mapping
|
||||
files, you will need to unmount and remount the sub-tree or reboot before they
|
||||
will take effect.}
|
||||
|
||||
\item{Problem: {\sf ls -l} (or a similar program) shows the wrong user for a file.
|
||||
|
||||
Fixes: Probably a mistake in the mapping files. In particular, if
|
||||
two local UIDs are mapped to a single master UID, stat calls will assign
|
||||
ownership to the first local UID occurring in the file, which may or may
|
||||
not be what was intended. (Generally speaking, mapping two local UIDs to
|
||||
a single master UID is a bad idea, but the software will not prevent it.
|
||||
Similarly, mapping a single local UID to two master UIDs is a bad idea,
|
||||
but will not be prevented. In this case, only the first mapping of the
|
||||
local UID will be done. The second, and all subsequent ones, will be
|
||||
ignored.) If any changes are made in the mapping files, you will need to
|
||||
unmount and remount the sub-tree or reboot before they will take effect.}
|
||||
|
||||
\end{itemize}
|
||||
|
||||
\end{document}
|
14
sbin/mount_unionfs/Makefile
Normal file
14
sbin/mount_unionfs/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# @(#)Makefile 8.3 (Berkeley) 3/27/94
|
||||
|
||||
PROG= mount_union
|
||||
SRCS= mount_union.c getmntopts.c
|
||||
MAN8= mount_union.0
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I/sys -I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
BINOWN= root
|
||||
BINMODE=4555
|
||||
|
||||
.include <bsd.prog.mk>
|
204
sbin/mount_unionfs/mount_unionfs.8
Normal file
204
sbin/mount_unionfs/mount_unionfs.8
Normal file
@ -0,0 +1,204 @@
|
||||
.\" Copyright (c) 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software donated to Berkeley by
|
||||
.\" Jan-Simon Pendry.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)mount_union.8 8.6 (Berkeley) 3/27/94
|
||||
.\"
|
||||
.Dd March 27, 1994
|
||||
.Dt MOUNT_UNION 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_union
|
||||
.Nd mount union filesystems
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount_union
|
||||
.Op Fl br
|
||||
.Op Fl o Ar options
|
||||
.Ar directory
|
||||
.Ar uniondir
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount_union
|
||||
command
|
||||
attaches
|
||||
.Ar directory
|
||||
above
|
||||
.Ar uniondir
|
||||
in such a way that the contents of both directory trees remain visible.
|
||||
By default,
|
||||
.Ar directory
|
||||
becomes the
|
||||
.Em upper
|
||||
layer and
|
||||
.Ar uniondir
|
||||
becomes the
|
||||
.Em lower
|
||||
layer.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl b
|
||||
Invert the default position, so that
|
||||
.Ar directory
|
||||
becomes the lower layer and
|
||||
.Ar uniondir
|
||||
becomes the upper layer.
|
||||
However,
|
||||
.Ar uniondir
|
||||
remains the mount point.
|
||||
.It Fl o
|
||||
Options are specified with a
|
||||
.Fl o
|
||||
flag followed by a comma separated string of options.
|
||||
See the
|
||||
.Xr mount 8
|
||||
man page for possible options and their meanings.
|
||||
.It Fl r
|
||||
Hide the lower layer completely in the same way as mounting with
|
||||
.Xr mount_lofs 8
|
||||
or
|
||||
.Xr mount_null 8 .
|
||||
.El
|
||||
.Pp
|
||||
To enforce filesystem security, the user mounting the filesystem
|
||||
must be superuser or else have write permission on the mounted-on
|
||||
directory.
|
||||
.Pp
|
||||
Filenames are looked up in the upper layer and then in the
|
||||
lower layer.
|
||||
If a directory is found in the lower layer, and there is no entry
|
||||
in the upper layer, then a
|
||||
.Em shadow
|
||||
directory will be created in the upper layer.
|
||||
It will be owned by the user who originally did the union mount,
|
||||
with mode
|
||||
.Dq rwxrwxrwx
|
||||
(0777) modified by the umask in effect at that time.
|
||||
.Pp
|
||||
If a file exists in the upper layer then there is no way to access
|
||||
a file with the same name in the lower layer.
|
||||
If necessary, a combination of loopback and union mounts can be made
|
||||
which will still allow the lower files to be accessed by a different
|
||||
pathname.
|
||||
.Pp
|
||||
Except in the case of a directory,
|
||||
access to an object is granted via the normal filesystem access checks.
|
||||
For directories, the current user must have access to both the upper
|
||||
and lower directories (should they both exist).
|
||||
.Pp
|
||||
Requests to create or modify objects in
|
||||
.Ar uniondir
|
||||
are passed to the upper layer with the exception of a few special cases.
|
||||
An attempt to open for writing a file which exists in the lower layer
|
||||
causes a copy of the
|
||||
.Em entire
|
||||
file to be made to the upper layer, and then for the upper layer copy
|
||||
to be opened.
|
||||
Similarly, an attempt to truncate a lower layer file to zero length
|
||||
causes an empty file to be created in the upper layer.
|
||||
Any other operation which would ultimately require modification to
|
||||
the lower layer fails with
|
||||
.Dv EROFS .
|
||||
.Pp
|
||||
The union filesystem manipulates the namespace, rather than
|
||||
individual filesystems.
|
||||
The union operation applies recursively down the directory tree
|
||||
now rooted at
|
||||
.Ar uniondir .
|
||||
Thus any filesystems which are mounted under
|
||||
.Ar uniondir
|
||||
will take part in the union operation.
|
||||
This differs from the
|
||||
.Em union
|
||||
option to
|
||||
.Xr mount 8
|
||||
which only applies the union operation to the mount point itself,
|
||||
and then only for lookups.
|
||||
.Sh EXAMPLES
|
||||
The commands
|
||||
.Bd -literal -offset indent
|
||||
mount -t cd9660 -o ro /dev/cd0a /usr/src
|
||||
mount -t union -o /var/obj /usr/src
|
||||
.Ed
|
||||
.Pp
|
||||
mount the CD-ROM drive
|
||||
.Pa /dev/cd0a
|
||||
on
|
||||
.Pa /usr/src
|
||||
and then attaches
|
||||
.Pa /var/obj
|
||||
on top.
|
||||
For most purposes the effect of this is to make the
|
||||
source tree appear writable
|
||||
even though it is stored on a CD-ROM.
|
||||
.Pp
|
||||
The command
|
||||
.Bd -literal -offset indent
|
||||
mount -t union -o -b /sys $HOME/sys
|
||||
.Ed
|
||||
.Pp
|
||||
attaches the system source tree below the
|
||||
.Pa sys
|
||||
directory in the user's home directory.
|
||||
This allows individual users to make private changes
|
||||
to the source, and build new kernels, without those
|
||||
changes becoming visible to other users.
|
||||
Note that the files in the lower layer remain
|
||||
accessible via
|
||||
.Pa /sys .
|
||||
.Sh SEE ALSO
|
||||
.Xr intro 2 ,
|
||||
.Xr mount 2 ,
|
||||
.Xr unmount 2 ,
|
||||
.Xr fstab 5 ,
|
||||
.Xr mount 8 ,
|
||||
.Xr mount_lofs 8 ,
|
||||
.Xr mount_null 8
|
||||
.Sh BUGS
|
||||
Without whiteout support from the filesystem backing the upper layer,
|
||||
there is no way that delete and rename operations on lower layer
|
||||
objects can be done.
|
||||
.Dv EROFS
|
||||
is returned for this kind of operations along with any others
|
||||
which would make modifications to the lower layer, such as
|
||||
.Xr chmod 1 .
|
||||
.Pp
|
||||
Running
|
||||
.Xr find 1
|
||||
over a union tree has the side-effect of creating
|
||||
a tree of shadow directories in the upper layer.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mount_union
|
||||
command first appeared in
|
||||
.Bx 4.4 .
|
140
sbin/mount_unionfs/mount_unionfs.c
Normal file
140
sbin/mount_unionfs/mount_unionfs.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount_union.c 8.5 (Berkeley) 3/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <miscfs/union/union.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int subdir __P((const char *, const char *));
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct union_args args;
|
||||
int ch, mntflags;
|
||||
char target[MAXPATHLEN];
|
||||
|
||||
mntflags = 0;
|
||||
args.mntflags = UNMNT_ABOVE;
|
||||
while ((ch = getopt(argc, argv, "bo:r")) != EOF)
|
||||
switch (ch) {
|
||||
case 'b':
|
||||
args.mntflags &= ~UNMNT_OPMASK;
|
||||
args.mntflags |= UNMNT_BELOW;
|
||||
break;
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags);
|
||||
break;
|
||||
case 'r':
|
||||
args.mntflags &= ~UNMNT_OPMASK;
|
||||
args.mntflags |= UNMNT_REPLACE;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
if (realpath(argv[0], target) == 0)
|
||||
err(1, "%s", target);
|
||||
|
||||
if (subdir(target, argv[1]) || subdir(argv[1], target))
|
||||
errx(1, "%s (%s) and %s are not distinct paths",
|
||||
argv[0], target, argv[1]);
|
||||
|
||||
args.target = target;
|
||||
|
||||
if (mount(MOUNT_UNION, argv[1], mntflags, &args))
|
||||
err(1, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
subdir(p, dir)
|
||||
const char *p;
|
||||
const char *dir;
|
||||
{
|
||||
int l;
|
||||
|
||||
l = strlen(dir);
|
||||
if (l <= 1)
|
||||
return (1);
|
||||
|
||||
if ((strncmp(p, dir, l) == 0) && (p[l] == '/' || p[l] == '\0'))
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_union [-br] [-o options] target_fs mount_point\n");
|
||||
exit(1);
|
||||
}
|
354
sbin/quotacheck/preen.c
Normal file
354
sbin/quotacheck/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);
|
||||
}
|
15
usr.sbin/mount_portalfs/Makefile
Normal file
15
usr.sbin/mount_portalfs/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
# @(#)Makefile 8.3 (Berkeley) 3/27/94
|
||||
|
||||
PROG= mount_portal
|
||||
SRCS= mount_portal.c activate.c conf.c getmntopts.c pt_conf.c \
|
||||
pt_exec.c pt_file.c pt_tcp.c
|
||||
MAN8= mount_portal.0
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I/sys -I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
DPADD= $(LIBCOMPAT)
|
||||
LDADD= -lcompat
|
||||
|
||||
.include <bsd.prog.mk>
|
215
usr.sbin/mount_portalfs/activate.c
Normal file
215
usr.sbin/mount_portalfs/activate.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)activate.c 8.2 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: activate.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
/*
|
||||
* Scan the providers list and call the
|
||||
* appropriate function.
|
||||
*/
|
||||
static int activate_argv(pcr, key, v, so, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int so;
|
||||
int *fdp;
|
||||
{
|
||||
provider *pr;
|
||||
|
||||
for (pr = providers; pr->pr_match; pr++)
|
||||
if (strcmp(v[0], pr->pr_match) == 0)
|
||||
return ((*pr->pr_func)(pcr, key, v, so, fdp));
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static int get_request(so, pcr, key, klen)
|
||||
int so;
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
int klen;
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
int n;
|
||||
|
||||
iov[0].iov_base = (caddr_t) pcr;
|
||||
iov[0].iov_len = sizeof(*pcr);
|
||||
iov[1].iov_base = key;
|
||||
iov[1].iov_len = klen;
|
||||
|
||||
bzero((char *) &msg, sizeof(msg));
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 2;
|
||||
|
||||
n = recvmsg(so, &msg, 0);
|
||||
if (n < 0)
|
||||
return (errno);
|
||||
|
||||
if (n <= sizeof(*pcr))
|
||||
return (EINVAL);
|
||||
|
||||
n -= sizeof(*pcr);
|
||||
key[n] = '\0';
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void send_reply(so, fd, error)
|
||||
int so;
|
||||
int fd;
|
||||
int error;
|
||||
{
|
||||
int n;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
struct {
|
||||
struct cmsghdr cmsg;
|
||||
int fd;
|
||||
} ctl;
|
||||
|
||||
/*
|
||||
* Line up error code. Don't worry about byte ordering
|
||||
* because we must be sending to the local machine.
|
||||
*/
|
||||
iov.iov_base = (caddr_t) &error;
|
||||
iov.iov_len = sizeof(error);
|
||||
|
||||
/*
|
||||
* Build a msghdr
|
||||
*/
|
||||
bzero((char *) &msg, sizeof(msg));
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
/*
|
||||
* If there is a file descriptor to send then
|
||||
* construct a suitable rights control message.
|
||||
*/
|
||||
if (fd >= 0) {
|
||||
ctl.fd = fd;
|
||||
ctl.cmsg.cmsg_len = sizeof(ctl);
|
||||
ctl.cmsg.cmsg_level = SOL_SOCKET;
|
||||
ctl.cmsg.cmsg_type = SCM_RIGHTS;
|
||||
msg.msg_control = (caddr_t) &ctl;
|
||||
msg.msg_controllen = ctl.cmsg.cmsg_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send to kernel...
|
||||
*/
|
||||
if ((n = sendmsg(so, &msg, MSG_EOR)) < 0)
|
||||
syslog(LOG_ERR, "send: %s", strerror(errno));
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "sent %d bytes\n", n);
|
||||
#endif
|
||||
sleep(1); /*XXX*/
|
||||
#ifdef notdef
|
||||
if (shutdown(so, 2) < 0)
|
||||
syslog(LOG_ERR, "shutdown: %s", strerror(errno));
|
||||
#endif
|
||||
/*
|
||||
* Throw away the open file descriptor
|
||||
*/
|
||||
(void) close(fd);
|
||||
}
|
||||
|
||||
void activate(q, so)
|
||||
qelem *q;
|
||||
int so;
|
||||
{
|
||||
struct portal_cred pcred;
|
||||
char key[MAXPATHLEN+1];
|
||||
int error;
|
||||
char **v;
|
||||
int fd = -1;
|
||||
|
||||
/*
|
||||
* Read the key from the socket
|
||||
*/
|
||||
error = get_request(so, &pcred, key, sizeof(key));
|
||||
if (error) {
|
||||
syslog(LOG_ERR, "activate: recvmsg: %s", strerror(error));
|
||||
goto drop;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "lookup key %s\n", key);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find a match in the configuration file
|
||||
*/
|
||||
v = conf_match(q, key);
|
||||
|
||||
/*
|
||||
* If a match existed, then find an appropriate portal
|
||||
* otherwise simply return ENOENT.
|
||||
*/
|
||||
if (v) {
|
||||
error = activate_argv(&pcred, key, v, so, &fd);
|
||||
if (error)
|
||||
fd = -1;
|
||||
else if (fd < 0)
|
||||
error = -1;
|
||||
} else {
|
||||
error = ENOENT;
|
||||
}
|
||||
|
||||
if (error >= 0)
|
||||
send_reply(so, fd, error);
|
||||
|
||||
drop:;
|
||||
close(so);
|
||||
}
|
329
usr.sbin/mount_portalfs/conf.c
Normal file
329
usr.sbin/mount_portalfs/conf.c
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)conf.c 8.2 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <regexp.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
#define ALLOC(ty) (xmalloc(sizeof(ty)))
|
||||
|
||||
typedef struct path path;
|
||||
struct path {
|
||||
qelem p_q; /* 2-way linked list */
|
||||
int p_lno; /* Line number of this record */
|
||||
char *p_args; /* copy of arg string (malloc) */
|
||||
char *p_key; /* Pathname to match (also p_argv[0]) */
|
||||
regexp *p_re; /* RE to match against pathname (malloc) */
|
||||
int p_argc; /* number of elements in arg string */
|
||||
char **p_argv; /* argv[] pointers into arg string (malloc) */
|
||||
};
|
||||
|
||||
static char *conf_file; /* XXX for regerror */
|
||||
static path *curp; /* XXX for regerror */
|
||||
|
||||
/*
|
||||
* Add an element to a 2-way list,
|
||||
* just after (pred)
|
||||
*/
|
||||
static void ins_que(elem, pred)
|
||||
qelem *elem, *pred;
|
||||
{
|
||||
qelem *p = pred->q_forw;
|
||||
elem->q_back = pred;
|
||||
elem->q_forw = p;
|
||||
pred->q_forw = elem;
|
||||
p->q_back = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an element from a 2-way list
|
||||
*/
|
||||
static void rem_que(elem)
|
||||
qelem *elem;
|
||||
{
|
||||
qelem *p = elem->q_forw;
|
||||
qelem *p2 = elem->q_back;
|
||||
p2->q_forw = p;
|
||||
p->q_back = p2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Error checking malloc
|
||||
*/
|
||||
static void *xmalloc(siz)
|
||||
unsigned siz;
|
||||
{
|
||||
void *p = malloc(siz);
|
||||
if (p)
|
||||
return (p);
|
||||
syslog(LOG_ALERT, "malloc: failed to get %d bytes", siz);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the path in the list.
|
||||
* If there is already an element with the same key then
|
||||
* the *second* one is ignored (return 0). If the key is
|
||||
* not found then the path is added to the end of the list
|
||||
* and 1 is returned.
|
||||
*/
|
||||
static int pinsert(p0, q0)
|
||||
path *p0;
|
||||
qelem *q0;
|
||||
{
|
||||
qelem *q;
|
||||
|
||||
if (p0->p_argc == 0)
|
||||
return (0);
|
||||
|
||||
for (q = q0->q_forw; q != q0; q = q->q_forw) {
|
||||
path *p = (path *) q;
|
||||
if (strcmp(p->p_key, p0->p_key) == 0)
|
||||
return (0);
|
||||
}
|
||||
ins_que(&p0->p_q, q0->q_back);
|
||||
return (1);
|
||||
|
||||
}
|
||||
|
||||
void regerror(s)
|
||||
const char *s;
|
||||
{
|
||||
syslog(LOG_ERR, "%s:%s: regcomp %s: %s",
|
||||
conf_file, curp->p_lno, curp->p_key, s);
|
||||
}
|
||||
|
||||
static path *palloc(cline, lno)
|
||||
char *cline;
|
||||
int lno;
|
||||
{
|
||||
int c;
|
||||
char *s;
|
||||
char *key;
|
||||
path *p;
|
||||
char **ap;
|
||||
|
||||
/*
|
||||
* Implement comment chars
|
||||
*/
|
||||
s = strchr(cline, '#');
|
||||
if (s)
|
||||
*s = 0;
|
||||
|
||||
/*
|
||||
* Do a pass through the string to count the number
|
||||
* of arguments
|
||||
*/
|
||||
c = 0;
|
||||
key = strdup(cline);
|
||||
for (s = key; s != NULL; ) {
|
||||
char *val;
|
||||
while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
|
||||
;
|
||||
if (val)
|
||||
c++;
|
||||
}
|
||||
c++;
|
||||
free(key);
|
||||
|
||||
if (c <= 1)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Now do another pass and generate a new path structure
|
||||
*/
|
||||
p = ALLOC(path);
|
||||
p->p_argc = 0;
|
||||
p->p_argv = xmalloc(c * sizeof(char *));
|
||||
p->p_args = strdup(cline);
|
||||
ap = p->p_argv;
|
||||
for (s = p->p_args; s != NULL; ) {
|
||||
char *val;
|
||||
while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
|
||||
;
|
||||
if (val) {
|
||||
*ap++ = val;
|
||||
p->p_argc++;
|
||||
}
|
||||
}
|
||||
*ap = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (c = 0; c < p->p_argc; c++)
|
||||
printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]);
|
||||
#endif
|
||||
|
||||
p->p_key = p->p_argv[0];
|
||||
if (strpbrk(p->p_key, RE_CHARS)) {
|
||||
curp = p; /* XXX */
|
||||
p->p_re = regcomp(p->p_key);
|
||||
curp = 0; /* XXX */
|
||||
} else {
|
||||
p->p_re = 0;
|
||||
}
|
||||
p->p_lno = lno;
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a path structure
|
||||
*/
|
||||
static void pfree(p)
|
||||
path *p;
|
||||
{
|
||||
free(p->p_args);
|
||||
if (p->p_re)
|
||||
free((char *) p->p_re);
|
||||
free((char *) p->p_argv);
|
||||
free((char *) p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Discard all currently held path structures on q0.
|
||||
* and add all the ones on xq.
|
||||
*/
|
||||
static void preplace(q0, xq)
|
||||
qelem *q0;
|
||||
qelem *xq;
|
||||
{
|
||||
/*
|
||||
* While the list is not empty,
|
||||
* take the first element off the list
|
||||
* and free it.
|
||||
*/
|
||||
while (q0->q_forw != q0) {
|
||||
qelem *q = q0->q_forw;
|
||||
rem_que(q);
|
||||
pfree((path *) q);
|
||||
}
|
||||
while (xq->q_forw != xq) {
|
||||
qelem *q = xq->q_forw;
|
||||
rem_que(q);
|
||||
ins_que(q, q0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the lines from the configuration file and
|
||||
* add them to the list of paths.
|
||||
*/
|
||||
static void readfp(q0, fp)
|
||||
qelem *q0;
|
||||
FILE *fp;
|
||||
{
|
||||
char cline[LINE_MAX];
|
||||
int nread = 0;
|
||||
qelem q;
|
||||
|
||||
/*
|
||||
* Make a new empty list.
|
||||
*/
|
||||
q.q_forw = q.q_back = &q;
|
||||
|
||||
/*
|
||||
* Read the lines from the configuration file.
|
||||
*/
|
||||
while (fgets(cline, sizeof(cline), fp)) {
|
||||
path *p = palloc(cline, nread+1);
|
||||
if (p && !pinsert(p, &q))
|
||||
pfree(p);
|
||||
nread++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If some records were read, then throw
|
||||
* away the old list and replace with the
|
||||
* new one.
|
||||
*/
|
||||
if (nread)
|
||||
preplace(q0, &q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the configuration file (conf) and replace
|
||||
* the existing path list with the new version.
|
||||
* If the file is not readable, then no changes take place
|
||||
*/
|
||||
void conf_read(q, conf)
|
||||
qelem *q;
|
||||
char *conf;
|
||||
{
|
||||
FILE *fp = fopen(conf, "r");
|
||||
if (fp) {
|
||||
conf_file = conf; /* XXX */
|
||||
readfp(q, fp);
|
||||
conf_file = 0; /* XXX */
|
||||
(void) fclose(fp);
|
||||
} else {
|
||||
syslog(LOG_ERR, "open config file \"%s\": %s", conf, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char **conf_match(q0, key)
|
||||
qelem *q0;
|
||||
char *key;
|
||||
{
|
||||
qelem *q;
|
||||
|
||||
for (q = q0->q_forw; q != q0; q = q->q_forw) {
|
||||
path *p = (path *) q;
|
||||
if (p->p_re) {
|
||||
if (regexec(p->p_re, key))
|
||||
return (p->p_argv+1);
|
||||
} else {
|
||||
if (strncmp(p->p_key, key, strlen(p->p_key)) == 0)
|
||||
return (p->p_argv+1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
136
usr.sbin/mount_portalfs/mount_portalfs.8
Normal file
136
usr.sbin/mount_portalfs/mount_portalfs.8
Normal file
@ -0,0 +1,136 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1993, 1994
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software donated to Berkeley by
|
||||
.\" Jan-Simon Pendry.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)mount_portal.8 8.3 (Berkeley) 3/27/94
|
||||
.\"
|
||||
.\"
|
||||
.Dd March 27, 1994
|
||||
.Dt MOUNT_PORTAL 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_portal
|
||||
.Nd mount the portal daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount_portal
|
||||
.Op Fl o Ar options
|
||||
.Ar /etc/portal.conf
|
||||
.Ar mount_point
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount_portal
|
||||
command attaches an instance of the portal daemon
|
||||
to the global filesystem namespace.
|
||||
The conventional mount point is
|
||||
.Pa /p .
|
||||
.PA /dev .
|
||||
This command is normally executed by
|
||||
.Xr mount 8
|
||||
at boot time.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl o
|
||||
Options are specified with a
|
||||
.Fl o
|
||||
flag followed by a comma separated string of options.
|
||||
See the
|
||||
.Xr mount 8
|
||||
man page for possible options and their meanings.
|
||||
.El
|
||||
.Pp
|
||||
The portal daemon provides an
|
||||
.Em open
|
||||
service.
|
||||
Objects opened under the portal mount point are
|
||||
dynamically created by the portal daemon according
|
||||
to rules specified in the named configuration file.
|
||||
Using this mechanism allows descriptors such as sockets
|
||||
to be made available in the filesystem namespace.
|
||||
.Pp
|
||||
The portal daemon works by being passed the full pathname
|
||||
of the object being opened.
|
||||
The daemon creates an appropriate descriptor according
|
||||
to the rules in the configuration file, and then passes the descriptor back
|
||||
to the calling process as the result of the open system call.
|
||||
.Sh NAMESPACE
|
||||
By convention, the portal daemon divides the namespace into sub-namespaces,
|
||||
each of which handles objects of a particular type.
|
||||
.Pp
|
||||
Currently, two sub-namespaces are implemented:
|
||||
.Pa tcp
|
||||
and
|
||||
.Pa fs .
|
||||
The
|
||||
.Pa tcp
|
||||
namespace takes a hostname and a port (slash separated) and
|
||||
creates an open TCP/IP connection.
|
||||
The
|
||||
.Pa fs
|
||||
namespace opens the named file, starting back at the root directory.
|
||||
This can be used to provide a controlled escape path from
|
||||
a chrooted environment.
|
||||
.Sh "CONFIGURATION FILE"
|
||||
The configuration file contains a list of rules.
|
||||
Each rule takes one line and consists of two or more
|
||||
whitespace separated fields.
|
||||
A hash (``#'') character causes the remainder of a line to
|
||||
be ignored. Blank lines are ignored.
|
||||
.Pp
|
||||
The first field is a pathname prefix to match
|
||||
against the requested pathname.
|
||||
If a match is found, the second field
|
||||
tells the daemon what type of object to create.
|
||||
Subsequent fields are passed to the creation function.
|
||||
.Bd -literal
|
||||
# @(#)portal.conf 5.1 (Berkeley) 7/13/92
|
||||
tcp/ tcp tcp/
|
||||
fs/ file fs/
|
||||
.Ed
|
||||
.Sh FILES
|
||||
.Bl -tag -width /p/* -compact
|
||||
.It Pa /p/*
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mount 2 ,
|
||||
.Xr unmount 2 ,
|
||||
.Xr fstab 5 ,
|
||||
.Xr mount 8
|
||||
.Sh CAVEATS
|
||||
This filesystem may not be NFS-exported.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mount_portal
|
||||
utility first appeared in 4.4BSD.
|
261
usr.sbin/mount_portalfs/mount_portalfs.c
Normal file
261
usr.sbin/mount_portalfs/mount_portalfs.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount_portal.c 8.4 (Berkeley) 3/27/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
#include "pathnames.h"
|
||||
#include "portald.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void usage __P((void));
|
||||
|
||||
static sig_atomic_t readcf; /* Set when SIGHUP received */
|
||||
|
||||
static void sigchld(sig)
|
||||
int sig;
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0)
|
||||
;
|
||||
if (pid < 0)
|
||||
syslog(LOG_WARNING, "waitpid: %s", strerror(errno));
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct portal_args args;
|
||||
struct sockaddr_un un;
|
||||
char *conf;
|
||||
char *mountpt;
|
||||
int mntflags = 0;
|
||||
char tag[32];
|
||||
|
||||
qelem q;
|
||||
int rc;
|
||||
int so;
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Crack command line args
|
||||
*/
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "o:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags);
|
||||
break;
|
||||
default:
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != (argc - 2))
|
||||
error = 1;
|
||||
|
||||
if (error)
|
||||
usage();
|
||||
|
||||
/*
|
||||
* Get config file and mount point
|
||||
*/
|
||||
conf = argv[optind];
|
||||
mountpt = argv[optind+1];
|
||||
|
||||
/*
|
||||
* Construct the listening socket
|
||||
*/
|
||||
un.sun_family = AF_UNIX;
|
||||
if (sizeof(_PATH_TMPPORTAL) >= sizeof(un.sun_path)) {
|
||||
fprintf(stderr, "mount_portal: portal socket name too long\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(un.sun_path, _PATH_TMPPORTAL);
|
||||
mktemp(un.sun_path);
|
||||
un.sun_len = strlen(un.sun_path);
|
||||
|
||||
so = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (so < 0) {
|
||||
fprintf(stderr, "mount_portal: socket: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
(void) unlink(un.sun_path);
|
||||
if (bind(so, (struct sockaddr *) &un, sizeof(un)) < 0)
|
||||
err(1, NULL);
|
||||
(void) unlink(un.sun_path);
|
||||
|
||||
(void) listen(so, 5);
|
||||
|
||||
args.pa_socket = so;
|
||||
sprintf(tag, "portal:%d", getpid());
|
||||
args.pa_config = tag;
|
||||
|
||||
rc = mount(MOUNT_PORTAL, mountpt, mntflags, &args);
|
||||
if (rc < 0)
|
||||
err(1, NULL);
|
||||
|
||||
#ifdef notdef
|
||||
/*
|
||||
* Everything is ready to go - now is a good time to fork
|
||||
*/
|
||||
daemon(0, 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start logging (and change name)
|
||||
*/
|
||||
openlog("portald", LOG_CONS|LOG_PID, LOG_DAEMON);
|
||||
|
||||
q.q_forw = q.q_back = &q;
|
||||
readcf = 1;
|
||||
|
||||
signal(SIGCHLD, sigchld);
|
||||
|
||||
/*
|
||||
* Just loop waiting for new connections and activating them
|
||||
*/
|
||||
for (;;) {
|
||||
struct sockaddr_un un2;
|
||||
int len2 = sizeof(un2);
|
||||
int so2;
|
||||
pid_t pid;
|
||||
fd_set fdset;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Check whether we need to re-read the configuration file
|
||||
*/
|
||||
if (readcf) {
|
||||
readcf = 0;
|
||||
conf_read(&q, conf);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept a new connection
|
||||
* Will get EINTR if a signal has arrived, so just
|
||||
* ignore that error code
|
||||
*/
|
||||
FD_SET(so, &fdset);
|
||||
rc = select(so+1, &fdset, (void *) 0, (void *) 0, (void *) 0);
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
syslog(LOG_ERR, "select: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (rc == 0)
|
||||
break;
|
||||
so2 = accept(so, (struct sockaddr *) &un2, &len2);
|
||||
if (so2 < 0) {
|
||||
/*
|
||||
* The unmount function does a shutdown on the socket
|
||||
* which will generated ECONNABORTED on the accept.
|
||||
*/
|
||||
if (errno == ECONNABORTED)
|
||||
break;
|
||||
if (errno != EINTR) {
|
||||
syslog(LOG_ERR, "accept: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now fork a new child to deal with the connection
|
||||
*/
|
||||
eagain:;
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
if (errno == EAGAIN) {
|
||||
sleep(1);
|
||||
goto eagain;
|
||||
}
|
||||
syslog(LOG_ERR, "fork: %s", strerror(errno));
|
||||
break;
|
||||
case 0:
|
||||
(void) close(so);
|
||||
activate(&q, so2);
|
||||
break;
|
||||
default:
|
||||
(void) close(so2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
syslog(LOG_INFO, "%s unmounted", mountpt);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_portal [-o options] config mount-point\n");
|
||||
exit(1);
|
||||
}
|
44
usr.sbin/mount_portalfs/pathnames.h
Normal file
44
usr.sbin/mount_portalfs/pathnames.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* $Id: pathnames.h,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_TMPPORTAL "/tmp/portalXXXXXX" /* Scratch socket name */
|
7
usr.sbin/mount_portalfs/portal.conf
Normal file
7
usr.sbin/mount_portalfs/portal.conf
Normal file
@ -0,0 +1,7 @@
|
||||
# @(#)portal.conf 8.1 (Berkeley) 6/5/93
|
||||
# $Id: portal.conf,v 1.1 1992/05/27 06:50:13 jsp Exp jsp $
|
||||
tcplisten/ tcplisten tcplisten/
|
||||
tcp/ tcp tcp/
|
||||
fs/ file fs/
|
||||
pipe/ pipe
|
||||
foo/ exec ./bar bar baz
|
82
usr.sbin/mount_portalfs/portald.h
Normal file
82
usr.sbin/mount_portalfs/portald.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)portald.h 8.1 (Berkeley) 6/5/93
|
||||
*
|
||||
* $Id: portald.h,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
|
||||
/*
|
||||
* Meta-chars in an RE. Paths in the config file containing
|
||||
* any of these characters will be matched using regexec, other
|
||||
* paths will be prefix-matched.
|
||||
*/
|
||||
#define RE_CHARS ".|()[]*+?\\^$"
|
||||
|
||||
typedef struct qelem qelem;
|
||||
|
||||
struct qelem {
|
||||
qelem *q_forw;
|
||||
qelem *q_back;
|
||||
};
|
||||
|
||||
typedef struct provider provider;
|
||||
struct provider {
|
||||
char *pr_match;
|
||||
int (*pr_func) __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
};
|
||||
extern provider providers[];
|
||||
|
||||
/*
|
||||
* Portal providers
|
||||
*/
|
||||
extern int portal_exec __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
extern int portal_file __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
extern int portal_tcp __P((struct portal_cred *,
|
||||
char *key, char **v, int so, int *fdp));
|
||||
|
||||
/*
|
||||
* Global functions
|
||||
*/
|
||||
extern void activate __P((qelem *q, int so));
|
||||
extern char **conf_match __P((qelem *q, char *key));
|
||||
extern void conf_read __P((qelem *q, char *conf));
|
51
usr.sbin/mount_portalfs/pt_conf.c
Normal file
51
usr.sbin/mount_portalfs/pt_conf.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_conf.c 8.1 (Berkeley) 6/5/93
|
||||
*
|
||||
* $Id: pt_conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include "portald.h"
|
||||
|
||||
provider providers[] = {
|
||||
{ "exec", portal_exec },
|
||||
{ "file", portal_file },
|
||||
{ "tcp", portal_tcp },
|
||||
{ 0, 0 }
|
||||
};
|
61
usr.sbin/mount_portalfs/pt_exec.c
Normal file
61
usr.sbin/mount_portalfs/pt_exec.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_exec.c 8.1 (Berkeley) 6/5/93
|
||||
*
|
||||
* $Id: pt_exec.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
int portal_exec(pcr, key, v, so, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int so;
|
||||
int *fdp;
|
||||
{
|
||||
return (ENOEXEC);
|
||||
}
|
||||
|
106
usr.sbin/mount_portalfs/pt_file.c
Normal file
106
usr.sbin/mount_portalfs/pt_file.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_file.c 8.2 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: pt_file.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
int portal_file(pcr, key, v, so, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int so;
|
||||
int *fdp;
|
||||
{
|
||||
int fd;
|
||||
char pbuf[MAXPATHLEN];
|
||||
int error;
|
||||
int gidset[NGROUPS];
|
||||
int i;
|
||||
|
||||
pbuf[0] = '/';
|
||||
strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("path = %s, uid = %d, gid = %d\n", pbuf, pcr->pcr_uid, pcr->pcr_groups[0]);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < pcr->pcr_ngroups; i++)
|
||||
gidset[i] = pcr->pcr_groups[i];
|
||||
|
||||
if (setgroups(pcr->pcr_ngroups, gidset) < 0)
|
||||
return (errno);
|
||||
|
||||
if (seteuid(pcr->pcr_uid) < 0)
|
||||
return (errno);
|
||||
|
||||
fd = open(pbuf, O_RDWR|O_CREAT, 0666);
|
||||
if (fd < 0)
|
||||
error = errno;
|
||||
else
|
||||
error = 0;
|
||||
|
||||
if (seteuid((uid_t) 0) < 0) { /* XXX - should reset gidset too */
|
||||
error = errno;
|
||||
syslog(LOG_ERR, "setcred: %s", strerror(error));
|
||||
if (fd >= 0) {
|
||||
(void) close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
*fdp = fd;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "pt_file returns *fdp = %d, error = %d\n", *fdp, error);
|
||||
#endif
|
||||
|
||||
return (error);
|
||||
}
|
158
usr.sbin/mount_portalfs/pt_tcp.c
Normal file
158
usr.sbin/mount_portalfs/pt_tcp.c
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)pt_tcp.c 8.3 (Berkeley) 3/27/94
|
||||
*
|
||||
* $Id: pt_tcp.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "portald.h"
|
||||
|
||||
/*
|
||||
* Key will be tcp/host/port[/"priv"]
|
||||
* Create a TCP socket connected to the
|
||||
* requested host and port.
|
||||
* Some trailing suffix values have special meanings.
|
||||
* An unrecognised suffix is an error.
|
||||
*/
|
||||
int portal_tcp(pcr, key, v, kso, fdp)
|
||||
struct portal_cred *pcr;
|
||||
char *key;
|
||||
char **v;
|
||||
int kso;
|
||||
int *fdp;
|
||||
{
|
||||
char host[MAXHOSTNAMELEN];
|
||||
char port[MAXHOSTNAMELEN];
|
||||
char *p = key + (v[1] ? strlen(v[1]) : 0);
|
||||
char *q;
|
||||
struct hostent *hp;
|
||||
struct servent *sp;
|
||||
struct in_addr **ipp;
|
||||
struct in_addr *ip[2];
|
||||
struct in_addr ina;
|
||||
int s_port;
|
||||
int priv = 0;
|
||||
struct sockaddr_in sain;
|
||||
|
||||
q = strchr(p, '/');
|
||||
if (q == 0 || q - p >= sizeof(host))
|
||||
return (EINVAL);
|
||||
*q = '\0';
|
||||
strcpy(host, p);
|
||||
p = q + 1;
|
||||
|
||||
q = strchr(p, '/');
|
||||
if (q)
|
||||
*q = '\0';
|
||||
if (strlen(p) >= sizeof(port))
|
||||
return (EINVAL);
|
||||
strcpy(port, p);
|
||||
if (q) {
|
||||
p = q + 1;
|
||||
if (strcmp(p, "priv") == 0) {
|
||||
if (pcr->pcr_uid == 0)
|
||||
priv = 1;
|
||||
else
|
||||
return (EPERM);
|
||||
} else {
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
hp = gethostbyname(host);
|
||||
if (hp != 0) {
|
||||
ipp = (struct in_addr **) hp->h_addr_list;
|
||||
} else {
|
||||
ina.s_addr = inet_addr(host);
|
||||
if (ina.s_addr == INADDR_NONE)
|
||||
return (EINVAL);
|
||||
ip[0] = &ina;
|
||||
ip[1] = 0;
|
||||
ipp = ip;
|
||||
}
|
||||
|
||||
sp = getservbyname(port, "tcp");
|
||||
if (sp != 0)
|
||||
s_port = sp->s_port;
|
||||
else {
|
||||
s_port = atoi(port);
|
||||
if (s_port == 0)
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
bzero(&sain, sizeof(sain));
|
||||
sain.sin_len = sizeof(sain);
|
||||
sain.sin_family = AF_INET;
|
||||
sain.sin_port = s_port;
|
||||
|
||||
while (ipp[0]) {
|
||||
int so;
|
||||
|
||||
if (priv)
|
||||
so = rresvport((int *) 0);
|
||||
else
|
||||
so = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (so < 0) {
|
||||
syslog(LOG_ERR, "socket: %m");
|
||||
return (errno);
|
||||
}
|
||||
|
||||
sain.sin_addr = *ipp[0];
|
||||
if (connect(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
|
||||
*fdp = so;
|
||||
return (0);
|
||||
}
|
||||
(void) close(so);
|
||||
|
||||
ipp++;
|
||||
}
|
||||
|
||||
return (errno);
|
||||
}
|
10
usr.sbin/mountd/Makefile
Normal file
10
usr.sbin/mountd/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
# @(#)Makefile 8.3 (Berkeley) 1/25/94
|
||||
|
||||
PROG= mountd
|
||||
CFLAGS+=-DNFS -DMFS -DCD9660
|
||||
MAN5= exports.0 netgroup.0
|
||||
MAN8= mountd.0
|
||||
DPADD= ${LIBRPC}
|
||||
LDADD= -lrpc
|
||||
|
||||
.include <bsd.prog.mk>
|
250
usr.sbin/mountd/exports.5
Normal file
250
usr.sbin/mountd/exports.5
Normal file
@ -0,0 +1,250 @@
|
||||
.\" Copyright (c) 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.
|
||||
.\"
|
||||
.\" @(#)exports.5 8.2 (Berkeley) 1/28/94
|
||||
.\"
|
||||
.Dd January 28, 1994
|
||||
.Dt EXPORTS 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm exports
|
||||
.Nd define remote mount points for
|
||||
.Tn NFS
|
||||
mount requests
|
||||
.Sh SYNOPSIS
|
||||
.Nm exports
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm exports
|
||||
file specifies remote mount points for the
|
||||
.Tn NFS
|
||||
mount protocol per the
|
||||
.Tn NFS
|
||||
server specification; see
|
||||
.%T "Network File System Protocol Specification \\*(tNRFC\\*(sP 1094, Appendix A" .
|
||||
.Pp
|
||||
Each line in the file
|
||||
(other than comment lines that begin with a #)
|
||||
specifies the mount point(s) and export flags within one local server
|
||||
filesystem for one or more hosts.
|
||||
A host may be specified only once for each local filesystem on the
|
||||
server and there may be only one default entry for each server
|
||||
filesystem that applies to all other hosts.
|
||||
The latter exports the filesystem to the ``world'' and should
|
||||
be used only when the filesystem contains public information.
|
||||
.Pp
|
||||
In a mount entry,
|
||||
the first field(s) specify the directory path(s) within a server filesystem
|
||||
that can be mounted on by the corresponding client(s).
|
||||
There are two forms of this specification.
|
||||
The first is to list all mount points as absolute
|
||||
directory paths separated by whitespace.
|
||||
The second is to specify the pathname of the root of the filesystem
|
||||
followed by the
|
||||
.Fl alldirs
|
||||
flag;
|
||||
this form allows the host(s) to mount any directory within the filesystem.
|
||||
The pathnames must not have any symbolic links in them and should not have
|
||||
any "." or ".." components.
|
||||
Mount points for a filesystem may appear on multiple lines each with
|
||||
different sets of hosts and export options.
|
||||
.Pp
|
||||
The second component of a line specifies how the filesystem is to be
|
||||
exported to the host set.
|
||||
The option flags specify whether the filesystem
|
||||
is exported read-only or read-write and how the client uid is mapped to
|
||||
user credentials on the server.
|
||||
.Pp
|
||||
Export options are specified as follows:
|
||||
.Pp
|
||||
.Sm off
|
||||
.Fl maproot No = Sy user
|
||||
.Sm on
|
||||
The credential of the specified user is used for remote access by root.
|
||||
The credential includes all the groups to which the user is a member
|
||||
on the local machine (see
|
||||
.Xr id 1 ).
|
||||
The user may be specified by name or number.
|
||||
.Pp
|
||||
.Sm off
|
||||
.Fl maproot No = Sy user:group1:group2:...
|
||||
.Sm on
|
||||
The colon separated list is used to specify the precise credential
|
||||
to be used for remote access by root.
|
||||
The elements of the list may be either names or numbers.
|
||||
Note that user: should be used to distinguish a credential containing
|
||||
no groups from a complete credential for that user.
|
||||
.Pp
|
||||
.Sm off
|
||||
.Fl mapall No = Sy user
|
||||
.Sm on
|
||||
or
|
||||
.Sm off
|
||||
.Fl mapall No = Sy user:group1:group2:...
|
||||
.Sm on
|
||||
specifies a mapping for all client uids (including root)
|
||||
using the same semantics as
|
||||
.Fl maproot .
|
||||
.Pp
|
||||
The option
|
||||
.Fl r
|
||||
is a synonym for
|
||||
.Fl maproot
|
||||
in an effort to be backward compatible with older export file formats.
|
||||
.Pp
|
||||
In the absence of
|
||||
.Fl maproot
|
||||
and
|
||||
.Fl mapall
|
||||
options, remote accesses by root will result in using a credential of -2:-2.
|
||||
All other users will be mapped to their remote credential.
|
||||
If a
|
||||
.Fl maproot
|
||||
option is given,
|
||||
remote access by root will be mapped to that credential instead of -2:-2.
|
||||
If a
|
||||
.Fl mapall
|
||||
option is given,
|
||||
all users (including root) will be mapped to that credential in
|
||||
place of their own.
|
||||
.Pp
|
||||
The
|
||||
.Fl kerb
|
||||
option specifies that the Kerberos authentication server should be
|
||||
used to authenticate and map client credentials.
|
||||
(Note that this is NOT Sun NFS compatible and
|
||||
is supported for TCP transport only.)
|
||||
.Pp
|
||||
The
|
||||
.Fl ro
|
||||
option specifies that the filesystem should be exported read-only
|
||||
(default read/write).
|
||||
The option
|
||||
.Fl o
|
||||
is a synonym for
|
||||
.Fl ro
|
||||
in an effort to be backward compatible with older export file formats.
|
||||
.Pp
|
||||
The third component of a line specifies the host set to which the line applies.
|
||||
The set may be specified in three ways.
|
||||
The first way is to list the host name(s) separated by white space.
|
||||
(Standard internet ``dot'' addresses may be used in place of names.)
|
||||
The second way is to specify a ``netgroup'' as defined in the netgroup file (see
|
||||
.Xr netgroup 5 ).
|
||||
The third way is to specify an internet subnetwork using a network and
|
||||
network mask that is defined as the set of all hosts with addresses within
|
||||
the subnetwork.
|
||||
This latter approach requires less overhead within the
|
||||
kernel and is recommended for cases where the export line refers to a
|
||||
large number of clients within an administrative subnet.
|
||||
.Pp
|
||||
The first two cases are specified by simply listing the name(s) separated
|
||||
by whitespace.
|
||||
All names are checked to see if they are ``netgroup'' names
|
||||
first and are assumed to be hostnames otherwise.
|
||||
Using the full domain specification for a hostname can normally
|
||||
circumvent the problem of a host that has the same name as a netgroup.
|
||||
The third case is specified by the flag
|
||||
.Sm off
|
||||
.Fl network No = Sy netname
|
||||
.Sm on
|
||||
and optionally
|
||||
.Sm off
|
||||
.Fl mask No = Sy netmask .
|
||||
.Sm on
|
||||
If the mask is not specified, it will default to the mask for that network
|
||||
class (A, B or C; see
|
||||
.Xr inet 5 ).
|
||||
.Pp
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
/usr /usr/local -maproot=0:10 friends
|
||||
/usr -maproot=daemon grumpy.cis.uoguelph.ca 131.104.48.16
|
||||
/usr -ro -mapall=nobody
|
||||
/u -maproot=bin: -network 131.104.48 -mask 255.255.255.0
|
||||
/u2 -maproot=root friends
|
||||
/u2 -alldirs -kerb -network cis-net -mask cis-mask
|
||||
.Ed
|
||||
.Pp
|
||||
Given that
|
||||
.Sy /usr ,
|
||||
.Sy /u
|
||||
and
|
||||
.Sy /u2
|
||||
are
|
||||
local filesystem mount points, the above example specifies the following:
|
||||
.Sy /usr
|
||||
is exported to hosts
|
||||
.Em friends
|
||||
where friends is specified in the netgroup file
|
||||
with users mapped to their remote credentials and
|
||||
root mapped to uid 0 and group 10.
|
||||
It is exported read-write and the hosts in ``friends'' can mount either /usr
|
||||
or /usr/local.
|
||||
It is exported to
|
||||
.Em 131.104.48.16
|
||||
and
|
||||
.Em grumpy.cis.uoguelph.ca
|
||||
with users mapped to their remote credentials and
|
||||
root mapped to the user and groups associated with ``daemon'';
|
||||
it is exported to the rest of the world as read-only with
|
||||
all users mapped to the user and groups associated with ``nobody''.
|
||||
.Pp
|
||||
.Sy /u
|
||||
is exported to all hosts on the subnetwork
|
||||
.Em 131.104.48
|
||||
with root mapped to the uid for ``bin'' and with no group access.
|
||||
.Pp
|
||||
.Sy /u2
|
||||
is exported to the hosts in ``friends'' with root mapped to uid and groups
|
||||
associated with ``root'';
|
||||
it is exported to all hosts on network ``cis-net'' allowing mounts at any
|
||||
directory within /u2 and mapping all uids to credentials for the principal
|
||||
that is authenticated by a Kerberos ticket.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/exports -compact
|
||||
.It Pa /etc/exports
|
||||
The default remote mount-point file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr netgroup 5 ,
|
||||
.Xr mountd 8 ,
|
||||
.Xr nfsd 8 ,
|
||||
.Xr showmount 8
|
||||
.Sh BUGS
|
||||
The export options are tied to the local mount points in the kernel and
|
||||
must be non-contradictory for any exported subdirectory of the local
|
||||
server mount point.
|
||||
It is recommended that all exported directories within the same server
|
||||
filesystem be specified on adjacent lines going down the tree.
|
||||
You cannot specify a hostname that is also the name of a netgroup.
|
||||
Specifying the full domain specification for a hostname can normally
|
||||
circumvent the problem.
|
100
usr.sbin/mountd/mountd.8
Normal file
100
usr.sbin/mountd/mountd.8
Normal file
@ -0,0 +1,100 @@
|
||||
.\" Copyright (c) 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.
|
||||
.\"
|
||||
.\" @(#)mountd.8 8.1 (Berkeley) 6/9/93
|
||||
.\"
|
||||
.Dd June 9, 1993
|
||||
.Dt MOUNTD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mountd
|
||||
.Nd service remote
|
||||
.Tn NFS
|
||||
mount requests
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/mountd
|
||||
.Op Fl n
|
||||
.Op Ar exportsfile
|
||||
.Sh DESCRIPTION
|
||||
.Xr Mountd
|
||||
is the server for
|
||||
.Tn NFS
|
||||
mount requests from other client machines.
|
||||
.Xr Mountd
|
||||
listens for service requests at the port indicated in the
|
||||
.Tn NFS
|
||||
server specification; see
|
||||
.%T "Network File System Protocol Specification" ,
|
||||
RFC1094.
|
||||
.Pp
|
||||
Options and operands available for
|
||||
.Nm mountd :
|
||||
.Bl -tag -width Ds
|
||||
.It Fl n
|
||||
The
|
||||
.Fl n
|
||||
option allows non-root mount requests to be served.
|
||||
This should only be specified if there are clients such as PC's,
|
||||
that require it.
|
||||
.It Ar exportsfile
|
||||
The
|
||||
.Ar exportsfile
|
||||
argument specifies an alternate location
|
||||
for the exports file.
|
||||
.El
|
||||
.Pp
|
||||
When mountd is started,
|
||||
it loads the export host addresses and options into the kernel
|
||||
using the mount(2) system call.
|
||||
After changing the exports file,
|
||||
a hangup signal should be sent to the mountd daemon
|
||||
to get it to reload the export information.
|
||||
After sending the SIGHUP
|
||||
(kill -HUP `cat /var/run/mountd.pid`),
|
||||
check the syslog output to see if mountd logged any parsing
|
||||
errors in the exports file.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /var/run/mountd.pid -compact
|
||||
.It Pa /etc/exports
|
||||
the list of exported filesystems
|
||||
.It Pa /var/run/mountd.pid
|
||||
the pid of the currently running mountd
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr nfsstat 1 ,
|
||||
.Xr exports 5 ,
|
||||
.Xr nfsd 8 ,
|
||||
.Xr portmap 8 ,
|
||||
.Xr showmount 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mountd
|
||||
utility first appeared in 4.4BSD.
|
2005
usr.sbin/mountd/mountd.c
Normal file
2005
usr.sbin/mountd/mountd.c
Normal file
File diff suppressed because it is too large
Load Diff
91
usr.sbin/mountd/netgroup.5
Normal file
91
usr.sbin/mountd/netgroup.5
Normal file
@ -0,0 +1,91 @@
|
||||
.\" Copyright (c) 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.
|
||||
.\"
|
||||
.\" @(#)netgroup.5 8.2 (Berkeley) 12/11/93
|
||||
.\"
|
||||
.Dd December 11, 1993
|
||||
.Dt NETGROUP 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm netgroup
|
||||
.Nd defines network groups
|
||||
.Sh SYNOPSIS
|
||||
.Nm netgroup
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm netgroup
|
||||
file
|
||||
specifies ``netgroups'', which are sets of
|
||||
.Sy (host, user, domain)
|
||||
tuples that are to be given similar network access.
|
||||
.Pp
|
||||
Each line in the file
|
||||
consists of a netgroup name followed by a list of the members of the
|
||||
netgroup.
|
||||
Each member can be either the name of another netgroup or a specification
|
||||
of a tuple as follows:
|
||||
.Bd -literal -offset indent
|
||||
(host, user, domain)
|
||||
.Ed
|
||||
where the
|
||||
.Sy host ,
|
||||
.Sy user ,
|
||||
and
|
||||
.Sy domain
|
||||
are character string names for the corresponding component.
|
||||
Any of the comma separated fields may be empty to specify a ``wildcard'' value
|
||||
or may consist of the string ``-'' to specify ``no valid value''.
|
||||
The members of the list may be separated by whitespace and/or commas;
|
||||
the ``\e'' character may be used at the end of a line to specify
|
||||
line continuation.
|
||||
The functions specified in
|
||||
.Xr getnetgrent 3
|
||||
should normally be used to access the
|
||||
.Nm netgroup
|
||||
database.
|
||||
.Pp
|
||||
Lines that begin with a # are treated as comments.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/netgroup -compact
|
||||
.It Pa /etc/netgroup
|
||||
the netgroup database.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr getnetgrent 3 ,
|
||||
.Xr exports 5
|
||||
.Sh COMPATIBILITY
|
||||
The file format is compatible with that of various vendors, however it
|
||||
appears that not all vendors use an identical format.
|
||||
.Sh BUGS
|
||||
The interpretation of access restrictions based on the member tuples of a
|
||||
netgroup is left up to the various network applications.
|
||||
Also, it is not obvious how the domain specification
|
||||
applies to the BSD environment.
|
9
usr.sbin/nfsd/Makefile
Normal file
9
usr.sbin/nfsd/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= nfsd
|
||||
CFLAGS+=-DNFS
|
||||
MAN8= nfsd.0
|
||||
DPADD= ${LIBRPC}
|
||||
LDADD= -lrpc
|
||||
|
||||
.include <bsd.prog.mk>
|
114
usr.sbin/nfsd/nfsd.8
Normal file
114
usr.sbin/nfsd/nfsd.8
Normal file
@ -0,0 +1,114 @@
|
||||
.\" Copyright (c) 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.
|
||||
.\"
|
||||
.\" @(#)nfsd.8 8.3 (Berkeley) 2/22/94
|
||||
.\"
|
||||
.Dd February 22, 1994
|
||||
.Dt NFSD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm nfsd
|
||||
.Nd remote
|
||||
.Tn NFS
|
||||
server
|
||||
.Sh SYNOPSIS
|
||||
.Nm nfsd
|
||||
.Op Fl rut
|
||||
.Op Fl n Ar num_servers
|
||||
.Sh DESCRIPTION
|
||||
.Nm Nfsd
|
||||
runs on a server machine to service
|
||||
.Tn NFS
|
||||
requests from client machines.
|
||||
At least one
|
||||
.Nm nfsd
|
||||
must be running for a machine to operate as a server.
|
||||
.Pp
|
||||
Unless otherwise specified, four servers for
|
||||
.Tn UDP
|
||||
transport are started.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl r
|
||||
Register the
|
||||
.Tn NFS
|
||||
service with
|
||||
.Xr portmap 8
|
||||
without creating any servers.
|
||||
This option can be used along with the
|
||||
.Fl u
|
||||
or
|
||||
.Fl t
|
||||
options to re-register NFS if the portmap server is restarted.
|
||||
.It Fl n
|
||||
Specifies how many servers to create.
|
||||
.It Fl t
|
||||
Serve
|
||||
.Tn TCP NFS
|
||||
clients.
|
||||
.It Fl u
|
||||
Serve
|
||||
.Tn UDP NFS
|
||||
clients.
|
||||
.El
|
||||
.Pp
|
||||
For example,
|
||||
.Dq Li "nfsd -u -t 6"
|
||||
serves
|
||||
.Tn UDP
|
||||
and
|
||||
.Tn TCP
|
||||
transports using six daemons.
|
||||
.Pp
|
||||
A server should run enough daemons to handle
|
||||
the maximum level of concurrency from its clients,
|
||||
typically four to six.
|
||||
.Pp
|
||||
.Nm Nfsd
|
||||
listens for service requests at the port indicated in the
|
||||
.Tn NFS
|
||||
server specification; see
|
||||
.%T "Network File System Protocol Specification" ,
|
||||
RFC1094.
|
||||
.Pp
|
||||
The
|
||||
.Nm nfsd
|
||||
utility exits 0 on success, and >0 if an error occurs.
|
||||
.Sh SEE ALSO
|
||||
.Xr nfsstat 1 ,
|
||||
.Xr nfssvc 2 ,
|
||||
.Xr mountd 8 ,
|
||||
.Xr portmap 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm nfsd
|
||||
utility first appeared in 4.4BSD.
|
589
usr.sbin/nfsd/nfsd.c
Normal file
589
usr.sbin/nfsd/nfsd.c
Normal file
@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (c) 1989, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Rick Macklem at The University of Guelph.
|
||||
*
|
||||
* 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) 1989, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif not lint
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)nfsd.c 8.7 (Berkeley) 2/22/94";
|
||||
#endif not lint
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpc/pmap_clnt.h>
|
||||
#include <rpc/pmap_prot.h>
|
||||
|
||||
#ifdef ISO
|
||||
#include <netiso/iso.h>
|
||||
#endif
|
||||
#include <nfs/rpcv2.h>
|
||||
#include <nfs/nfsv2.h>
|
||||
#include <nfs/nfs.h>
|
||||
|
||||
#ifdef KERBEROS
|
||||
#include <kerberosIV/des.h>
|
||||
#include <kerberosIV/krb.h>
|
||||
#endif
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Global defs */
|
||||
#ifdef DEBUG
|
||||
#define syslog(e, s) fprintf(stderr,(s))
|
||||
int debug = 1;
|
||||
#else
|
||||
int debug = 0;
|
||||
#endif
|
||||
|
||||
struct nfsd_srvargs nsd;
|
||||
char **Argv = NULL; /* pointer to argument vector */
|
||||
char *LastArg = NULL; /* end of argv */
|
||||
|
||||
#ifdef KERBEROS
|
||||
char lnam[ANAME_SZ];
|
||||
KTEXT_ST kt;
|
||||
AUTH_DAT auth;
|
||||
char inst[INST_SZ];
|
||||
#endif
|
||||
|
||||
void nonfs __P((int));
|
||||
void reapchild __P((int));
|
||||
void setproctitle __P((char *));
|
||||
void usage __P((void));
|
||||
|
||||
/*
|
||||
* Nfs server daemon mostly just a user context for nfssvc()
|
||||
*
|
||||
* 1 - do file descriptor and signal cleanup
|
||||
* 2 - fork the nfsd(s)
|
||||
* 3 - create server socket(s)
|
||||
* 4 - register socket with portmap
|
||||
*
|
||||
* For connectionless protocols, just pass the socket into the kernel via.
|
||||
* nfssvc().
|
||||
* For connection based sockets, loop doing accepts. When you get a new
|
||||
* socket from accept, pass the msgsock into the kernel via. nfssvc().
|
||||
* The arguments are:
|
||||
* -c - support iso cltp clients
|
||||
* -r - reregister with portmapper
|
||||
* -t - support tcp nfs clients
|
||||
* -u - support udp nfs clients
|
||||
* followed by "n" which is the number of nfsds' to fork off
|
||||
*/
|
||||
int
|
||||
main(argc, argv, envp)
|
||||
int argc;
|
||||
char *argv[], *envp[];
|
||||
{
|
||||
extern int optind;
|
||||
struct group *grp;
|
||||
struct nfsd_args nfsdargs;
|
||||
struct passwd *pwd;
|
||||
struct ucred *cr;
|
||||
struct sockaddr_in inetaddr, inetpeer;
|
||||
#ifdef ISO
|
||||
struct sockaddr_iso isoaddr, isopeer;
|
||||
#endif
|
||||
fd_set ready, sockbits;
|
||||
int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
|
||||
int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
|
||||
int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag;
|
||||
char *cp, **cpp;
|
||||
|
||||
/* Save start and extent of argv for setproctitle. */
|
||||
Argv = argv;
|
||||
if (envp == 0 || *envp == 0)
|
||||
envp = argv;
|
||||
while (*envp)
|
||||
envp++;
|
||||
LastArg = envp[-1] + strlen(envp[-1]);
|
||||
|
||||
#define MAXNFSDCNT 20
|
||||
#define DEFNFSDCNT 4
|
||||
nfsdcnt = DEFNFSDCNT;
|
||||
cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
|
||||
tpipflag = udpflag = 0;
|
||||
#ifdef ISO
|
||||
#define GETOPT "cn:rtu"
|
||||
#define USAGE "[-crtu] [-n num_servers]"
|
||||
#else
|
||||
#define GETOPT "n:rtu"
|
||||
#define USAGE "[-rtu] [-n num_servers]"
|
||||
#endif
|
||||
while ((ch = getopt(argc, argv, GETOPT)) != EOF)
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
nfsdcnt = atoi(optarg);
|
||||
if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
|
||||
warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
|
||||
nfsdcnt = DEFNFSDCNT;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
reregister = 1;
|
||||
break;
|
||||
case 't':
|
||||
tcpflag = 1;
|
||||
break;
|
||||
case 'u':
|
||||
udpflag = 1;
|
||||
break;
|
||||
#ifdef ISO
|
||||
case 'c':
|
||||
cltpflag = 1;
|
||||
break;
|
||||
#ifdef notyet
|
||||
case 'i':
|
||||
tp4cnt = 1;
|
||||
break;
|
||||
case 'p':
|
||||
tpipcnt = 1;
|
||||
break;
|
||||
#endif /* notyet */
|
||||
#endif /* ISO */
|
||||
default:
|
||||
case '?':
|
||||
usage();
|
||||
};
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Backward compatibility, trailing number is the count of daemons.
|
||||
*/
|
||||
if (argc > 1)
|
||||
usage();
|
||||
if (argc == 1) {
|
||||
nfsdcnt = atoi(argv[0]);
|
||||
if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
|
||||
warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
|
||||
nfsdcnt = DEFNFSDCNT;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug == 0) {
|
||||
daemon(0, 0);
|
||||
(void)signal(SIGHUP, SIG_IGN);
|
||||
(void)signal(SIGINT, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
(void)signal(SIGSYS, nonfs);
|
||||
(void)signal(SIGTERM, SIG_IGN);
|
||||
}
|
||||
(void)signal(SIGCHLD, reapchild);
|
||||
|
||||
if (reregister) {
|
||||
if (udpflag &&
|
||||
!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT))
|
||||
err(1, "can't register with portmap for UDP.");
|
||||
if (tcpflag &&
|
||||
!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT))
|
||||
err(1, "can't register with portmap for TCP.");
|
||||
exit(0);
|
||||
}
|
||||
openlog("nfsd:", LOG_PID, LOG_DAEMON);
|
||||
|
||||
for (i = 0; i < nfsdcnt; i++) {
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
syslog(LOG_ERR, "fork: %m");
|
||||
exit (1);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
setproctitle("nfsd-srv");
|
||||
nfssvc_flag = NFSSVC_NFSD;
|
||||
nsd.nsd_nfsd = NULL;
|
||||
#ifdef KERBEROS
|
||||
nsd.nsd_authstr = (char *)kt.dat;
|
||||
#endif
|
||||
while (nfssvc(nfssvc_flag, &nsd) < 0) {
|
||||
if (errno != ENEEDAUTH) {
|
||||
syslog(LOG_ERR, "nfssvc: %m");
|
||||
exit(1);
|
||||
}
|
||||
nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
|
||||
#ifdef KERBEROS
|
||||
kt.length = nsd.nsd_authlen;
|
||||
kt.mbz = 0;
|
||||
(void)strcpy(inst, "*");
|
||||
if (krb_rd_req(&kt, "rcmd",
|
||||
inst, nsd.nsd_haddr, &auth, "") == RD_AP_OK &&
|
||||
krb_kntoln(&auth, lnam) == KSUCCESS &&
|
||||
(pwd = getpwnam(lnam)) != NULL) {
|
||||
cr = &nsd.nsd_cr;
|
||||
cr->cr_uid = pwd->pw_uid;
|
||||
cr->cr_groups[0] = pwd->pw_gid;
|
||||
cr->cr_ngroups = 1;
|
||||
setgrent();
|
||||
while ((grp = getgrent()) != NULL) {
|
||||
if (grp->gr_gid == cr->cr_groups[0])
|
||||
continue;
|
||||
for (cpp = grp->gr_mem;
|
||||
*cpp != NULL; ++cpp)
|
||||
if (!strcmp(*cpp, lnam))
|
||||
break;
|
||||
if (*cpp == NULL)
|
||||
continue;
|
||||
cr->cr_groups[cr->cr_ngroups++]
|
||||
= grp->gr_gid;
|
||||
if (cr->cr_ngroups == NGROUPS)
|
||||
break;
|
||||
}
|
||||
endgrent();
|
||||
nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
|
||||
}
|
||||
#endif /* KERBEROS */
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* If we are serving udp, set up the socket. */
|
||||
if (udpflag) {
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
syslog(LOG_ERR, "can't create udp socket");
|
||||
exit(1);
|
||||
}
|
||||
inetaddr.sin_family = AF_INET;
|
||||
inetaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
inetaddr.sin_port = htons(NFS_PORT);
|
||||
inetaddr.sin_len = sizeof(inetaddr);
|
||||
if (bind(sock,
|
||||
(struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
|
||||
syslog(LOG_ERR, "can't bind udp addr");
|
||||
exit(1);
|
||||
}
|
||||
if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
|
||||
syslog(LOG_ERR, "can't register with udp portmap");
|
||||
exit(1);
|
||||
}
|
||||
nfsdargs.sock = sock;
|
||||
nfsdargs.name = NULL;
|
||||
nfsdargs.namelen = 0;
|
||||
if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
|
||||
syslog(LOG_ERR, "can't Add UDP socket");
|
||||
exit(1);
|
||||
}
|
||||
(void)close(sock);
|
||||
}
|
||||
|
||||
#ifdef ISO
|
||||
/* If we are serving cltp, set up the socket. */
|
||||
if (cltpflag) {
|
||||
if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
|
||||
syslog(LOG_ERR, "can't create cltp socket");
|
||||
exit(1);
|
||||
}
|
||||
memset(&isoaddr, 0, sizeof(isoaddr));
|
||||
isoaddr.siso_family = AF_ISO;
|
||||
isoaddr.siso_tlen = 2;
|
||||
cp = TSEL(&isoaddr);
|
||||
*cp++ = (NFS_PORT >> 8);
|
||||
*cp = (NFS_PORT & 0xff);
|
||||
isoaddr.siso_len = sizeof(isoaddr);
|
||||
if (bind(sock,
|
||||
(struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
|
||||
syslog(LOG_ERR, "can't bind cltp addr");
|
||||
exit(1);
|
||||
}
|
||||
#ifdef notyet
|
||||
/*
|
||||
* XXX
|
||||
* Someday this should probably use "rpcbind", the son of
|
||||
* portmap.
|
||||
*/
|
||||
if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
|
||||
syslog(LOG_ERR, "can't register with udp portmap");
|
||||
exit(1);
|
||||
}
|
||||
#endif /* notyet */
|
||||
nfsdargs.sock = sock;
|
||||
nfsdargs.name = NULL;
|
||||
nfsdargs.namelen = 0;
|
||||
if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
|
||||
syslog(LOG_ERR, "can't add UDP socket");
|
||||
exit(1);
|
||||
}
|
||||
close(sock);
|
||||
}
|
||||
#endif /* ISO */
|
||||
|
||||
/* Now set up the master server socket waiting for tcp connections. */
|
||||
on = 1;
|
||||
FD_ZERO(&sockbits);
|
||||
connect_type_cnt = 0;
|
||||
if (tcpflag) {
|
||||
if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
syslog(LOG_ERR, "can't create tcp socket");
|
||||
exit(1);
|
||||
}
|
||||
if (setsockopt(tcpsock,
|
||||
SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
|
||||
inetaddr.sin_family = AF_INET;
|
||||
inetaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
inetaddr.sin_port = htons(NFS_PORT);
|
||||
inetaddr.sin_len = sizeof(inetaddr);
|
||||
if (bind(tcpsock,
|
||||
(struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
|
||||
syslog(LOG_ERR, "can't bind tcp addr");
|
||||
exit(1);
|
||||
}
|
||||
if (listen(tcpsock, 5) < 0) {
|
||||
syslog(LOG_ERR, "listen failed");
|
||||
exit(1);
|
||||
}
|
||||
if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
|
||||
syslog(LOG_ERR, "can't register tcp with portmap");
|
||||
exit(1);
|
||||
}
|
||||
FD_SET(tcpsock, &sockbits);
|
||||
maxsock = tcpsock;
|
||||
connect_type_cnt++;
|
||||
}
|
||||
|
||||
#ifdef notyet
|
||||
/* Now set up the master server socket waiting for tp4 connections. */
|
||||
if (tp4flag) {
|
||||
if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
|
||||
syslog(LOG_ERR, "can't create tp4 socket");
|
||||
exit(1);
|
||||
}
|
||||
if (setsockopt(tp4sock,
|
||||
SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
|
||||
memset(&isoaddr, 0, sizeof(isoaddr));
|
||||
isoaddr.siso_family = AF_ISO;
|
||||
isoaddr.siso_tlen = 2;
|
||||
cp = TSEL(&isoaddr);
|
||||
*cp++ = (NFS_PORT >> 8);
|
||||
*cp = (NFS_PORT & 0xff);
|
||||
isoaddr.siso_len = sizeof(isoaddr);
|
||||
if (bind(tp4sock,
|
||||
(struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
|
||||
syslog(LOG_ERR, "can't bind tp4 addr");
|
||||
exit(1);
|
||||
}
|
||||
if (listen(tp4sock, 5) < 0) {
|
||||
syslog(LOG_ERR, "listen failed");
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* XXX
|
||||
* Someday this should probably use "rpcbind", the son of
|
||||
* portmap.
|
||||
*/
|
||||
if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
|
||||
syslog(LOG_ERR, "can't register tcp with portmap");
|
||||
exit(1);
|
||||
}
|
||||
FD_SET(tp4sock, &sockbits);
|
||||
maxsock = tp4sock;
|
||||
connect_type_cnt++;
|
||||
}
|
||||
|
||||
/* Now set up the master server socket waiting for tpip connections. */
|
||||
if (tpipflag) {
|
||||
if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
|
||||
syslog(LOG_ERR, "can't create tpip socket");
|
||||
exit(1);
|
||||
}
|
||||
if (setsockopt(tpipsock,
|
||||
SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
|
||||
inetaddr.sin_family = AF_INET;
|
||||
inetaddr.sin_addr.s_addr = INADDR_ANY;
|
||||
inetaddr.sin_port = htons(NFS_PORT);
|
||||
inetaddr.sin_len = sizeof(inetaddr);
|
||||
if (bind(tpipsock,
|
||||
(struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
|
||||
syslog(LOG_ERR, "can't bind tcp addr");
|
||||
exit(1);
|
||||
}
|
||||
if (listen(tpipsock, 5) < 0) {
|
||||
syslog(LOG_ERR, "listen failed");
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* XXX
|
||||
* Someday this should probably use "rpcbind", the son of
|
||||
* portmap.
|
||||
*/
|
||||
if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
|
||||
syslog(LOG_ERR, "can't register tcp with portmap");
|
||||
exit(1);
|
||||
}
|
||||
FD_SET(tpipsock, &sockbits);
|
||||
maxsock = tpipsock;
|
||||
connect_type_cnt++;
|
||||
}
|
||||
#endif /* notyet */
|
||||
|
||||
if (connect_type_cnt == 0)
|
||||
exit(0);
|
||||
|
||||
setproctitle("nfsd-master");
|
||||
|
||||
/*
|
||||
* Loop forever accepting connections and passing the sockets
|
||||
* into the kernel for the mounts.
|
||||
*/
|
||||
for (;;) {
|
||||
ready = sockbits;
|
||||
if (connect_type_cnt > 1) {
|
||||
if (select(maxsock + 1,
|
||||
&ready, NULL, NULL, NULL) < 1) {
|
||||
syslog(LOG_ERR, "select failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (tcpflag && FD_ISSET(tcpsock, &ready)) {
|
||||
len = sizeof(inetpeer);
|
||||
if ((msgsock = accept(tcpsock,
|
||||
(struct sockaddr *)&inetpeer, &len)) < 0) {
|
||||
syslog(LOG_ERR, "accept failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
|
||||
if (setsockopt(msgsock, SOL_SOCKET,
|
||||
SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR,
|
||||
"setsockopt SO_KEEPALIVE: %m");
|
||||
nfsdargs.sock = msgsock;
|
||||
nfsdargs.name = (caddr_t)&inetpeer;
|
||||
nfsdargs.namelen = sizeof(inetpeer);
|
||||
nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
|
||||
(void)close(msgsock);
|
||||
}
|
||||
#ifdef notyet
|
||||
if (tp4flag && FD_ISSET(tp4sock, &ready)) {
|
||||
len = sizeof(isopeer);
|
||||
if ((msgsock = accept(tp4sock,
|
||||
(struct sockaddr *)&isopeer, &len)) < 0) {
|
||||
syslog(LOG_ERR, "accept failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (setsockopt(msgsock, SOL_SOCKET,
|
||||
SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR,
|
||||
"setsockopt SO_KEEPALIVE: %m");
|
||||
nfsdargs.sock = msgsock;
|
||||
nfsdargs.name = (caddr_t)&isopeer;
|
||||
nfsdargs.namelen = len;
|
||||
nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
|
||||
(void)close(msgsock);
|
||||
}
|
||||
if (tpipflag && FD_ISSET(tpipsock, &ready)) {
|
||||
len = sizeof(inetpeer);
|
||||
if ((msgsock = accept(tpipsock,
|
||||
(struct sockaddr *)&inetpeer, &len)) < 0) {
|
||||
syslog(LOG_ERR, "Accept failed: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (setsockopt(msgsock, SOL_SOCKET,
|
||||
SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
|
||||
syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
|
||||
nfsdargs.sock = msgsock;
|
||||
nfsdargs.name = (caddr_t)&inetpeer;
|
||||
nfsdargs.namelen = len;
|
||||
nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
|
||||
(void)close(msgsock);
|
||||
}
|
||||
#endif /* notyet */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "nfsd %s\n", USAGE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
nonfs(signo)
|
||||
int signo;
|
||||
{
|
||||
syslog(LOG_ERR, "missing system call: NFS not available.");
|
||||
}
|
||||
|
||||
void
|
||||
reapchild(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
while (wait3(NULL, WNOHANG, NULL));
|
||||
}
|
||||
|
||||
void
|
||||
setproctitle(a)
|
||||
char *a;
|
||||
{
|
||||
register char *cp;
|
||||
char buf[80];
|
||||
|
||||
cp = Argv[0];
|
||||
(void)snprintf(buf, sizeof(buf), "%s", a);
|
||||
(void)strncpy(cp, buf, LastArg - cp);
|
||||
cp += strlen(cp);
|
||||
while (cp < LastArg)
|
||||
*cp++ = ' ';
|
||||
}
|
14
usr.sbin/nologin/Makefile
Normal file
14
usr.sbin/nologin/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# @(#)Makefile 8.2 (Berkeley) 4/22/94
|
||||
|
||||
MAN8= nologin.0
|
||||
|
||||
nologin clean depend lint tags:
|
||||
|
||||
beforeinstall:
|
||||
install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
|
||||
${.CURDIR}/nologin.sh ${DESTDIR}/sbin/nologin
|
||||
|
||||
cleandir:
|
||||
rm -f nologin.0
|
||||
|
||||
.include <bsd.prog.mk>
|
54
usr.sbin/nologin/nologin.8
Normal file
54
usr.sbin/nologin/nologin.8
Normal file
@ -0,0 +1,54 @@
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
|
||||
.\"
|
||||
.Dd June 19, 1993
|
||||
.Dt NOLOGIN 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm nologin
|
||||
.Nd politely refuse a login
|
||||
.Sh SYNOPSIS
|
||||
.Nm nologin
|
||||
.Sh DESCRIPTION
|
||||
.Nm Nologin
|
||||
displays a message that an account is not available and
|
||||
exits non-zero.
|
||||
It is intended as a replacement shell field for accounts that
|
||||
have been disabled.
|
||||
.Sh SEE ALSO
|
||||
.Xr login 1
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm nologin
|
||||
command appeared in
|
||||
.Bx 4.4 .
|
38
usr.sbin/nologin/nologin.sh
Normal file
38
usr.sbin/nologin/nologin.sh
Normal file
@ -0,0 +1,38 @@
|
||||
#!/bin/sh -
|
||||
#
|
||||
# Copyright (c) 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.
|
||||
#
|
||||
# @(#)nologin.sh 8.1 (Berkeley) 6/5/93
|
||||
#
|
||||
|
||||
echo 'This account is currently not available.'
|
||||
exit 1
|
Loading…
Reference in New Issue
Block a user