mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Import some CSRG 4.4BSD-Lite2 components for sbin onto vendor branch.
(note that some of these have already been imported, this is a no-op)
This commit is contained in:
parent
662909a780
commit
1811bdf372
65 changed files with 23758 additions and 0 deletions
354
sbin/dump/dump.8
Normal file
354
sbin/dump/dump.8
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
.\" Copyright (c) 1980, 1991, 1993
|
||||
.\" Regents of the University of California.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)dump.8 8.3 (Berkeley) 5/1/95
|
||||
.\"
|
||||
.Dd May 1, 1995
|
||||
.Dt DUMP 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm dump
|
||||
.Nd filesystem backup
|
||||
.Sh SYNOPSIS
|
||||
.Nm dump
|
||||
.Op Fl 0123456789cnu
|
||||
.Op Fl B Ar records
|
||||
.Op Fl b Ar blocksize
|
||||
.Op Fl d Ar density
|
||||
.Op Fl f Ar file
|
||||
.Op Fl h Ar level
|
||||
.Op Fl s Ar feet
|
||||
.Op Fl T Ar date
|
||||
.Ar filesystem
|
||||
.Nm dump
|
||||
.Op Fl W Li \&| Fl w
|
||||
.Pp
|
||||
.in -\\n(iSu
|
||||
(The
|
||||
.Bx 4.3
|
||||
option syntax is implemented for backward compatibility, but
|
||||
is not documented here.)
|
||||
.Sh DESCRIPTION
|
||||
.Nm Dump
|
||||
examines files
|
||||
on a filesystem
|
||||
and determines which files
|
||||
need to be backed up. These files
|
||||
are copied to the given disk, tape or other
|
||||
storage medium for safe keeping (see the
|
||||
.Fl f
|
||||
option below for doing remote backups).
|
||||
A dump that is larger than the output medium is broken into
|
||||
multiple volumes.
|
||||
On most media the size is determined by writing until an
|
||||
end-of-media indication is returned.
|
||||
On media that cannot reliably return an end-of-media indication
|
||||
(such as some cartridge tape drives)
|
||||
each volume is of a fixed size;
|
||||
the actual size is determined by the tape size and density and/or
|
||||
block count options below.
|
||||
By default, the same output file name is used for each volume
|
||||
after prompting the operator to change media.
|
||||
.Pp
|
||||
The following options are supported by
|
||||
.Nm dump :
|
||||
.Bl -tag -width Ds
|
||||
.It Fl 0\-9
|
||||
Dump levels.
|
||||
A level 0, full backup,
|
||||
guarantees the entire file system is copied
|
||||
(but see also the
|
||||
.Fl h
|
||||
option below).
|
||||
A level number above 0,
|
||||
incremental backup,
|
||||
tells dump to
|
||||
copy all files new or modified since the
|
||||
last dump of the same or lower level.
|
||||
The default level is 9.
|
||||
.It Fl B Ar records
|
||||
The number of dump records per volume.
|
||||
This option overrides the calculation of tape size
|
||||
based on length and density.
|
||||
.It Fl b Ar blocksize
|
||||
The number of kilobytes per dump record.
|
||||
.It Fl c
|
||||
Modify the calculation of the default density and tape size to be more
|
||||
appropriate for cartridge tapes.
|
||||
.It Fl d Ar density
|
||||
Set tape density to
|
||||
.Ar density .
|
||||
The default is 1600BPI.
|
||||
.It Fl f Ar file
|
||||
Write the backup to
|
||||
.Ar file ;
|
||||
.Ar file
|
||||
may be a special device file
|
||||
like
|
||||
.Pa /dev/rmt12
|
||||
(a tape drive),
|
||||
.Pa /dev/rsd1c
|
||||
(a disk drive),
|
||||
an ordinary file,
|
||||
or
|
||||
.Ql Fl
|
||||
(the standard output).
|
||||
Multiple file names may be given as a single argument separated by commas.
|
||||
Each file will be used for one dump volume in the order listed;
|
||||
if the dump requires more volumes than the number of names given,
|
||||
the last file name will used for all remaining volumes after prompting
|
||||
for media changes.
|
||||
If the name of the file is of the form
|
||||
.Dq host:file ,
|
||||
or
|
||||
.Dq user@host:file ,
|
||||
.Nm dump
|
||||
writes to the named file on the remote host using
|
||||
.Xr rmt 8 .
|
||||
.It Fl h Ar level
|
||||
Honor the user
|
||||
.Dq nodump
|
||||
flag
|
||||
.Dp Dv UF_NODUMP
|
||||
only for dumps at or above the given
|
||||
.Ar level .
|
||||
The default honor level is 1,
|
||||
so that incremental backups omit such files
|
||||
but full backups retain them.
|
||||
.It Fl n
|
||||
Whenever
|
||||
.Nm dump
|
||||
requires operator attention,
|
||||
notify all operators in the group
|
||||
.Dq operator
|
||||
by means similar to a
|
||||
.Xr wall 1 .
|
||||
.It Fl s Ar feet
|
||||
Attempt to calculate the amount of tape needed
|
||||
at a particular density.
|
||||
If this amount is exceeded,
|
||||
.Nm dump
|
||||
prompts for a new tape.
|
||||
It is recommended to be a bit conservative on this option.
|
||||
The default tape length is 2300 feet.
|
||||
.ne 1i
|
||||
.It Fl T Ar date
|
||||
Use the specified date as the starting time for the dump
|
||||
instead of the time determined from looking in
|
||||
.Pa /etc/dumpdates .
|
||||
The format of date is the same as that of
|
||||
.Xr ctime 3 .
|
||||
This option is useful for automated dump scripts that wish to
|
||||
dump over a specific period of time.
|
||||
The
|
||||
.Fl T
|
||||
option is mutually exclusive from the
|
||||
.Fl u
|
||||
option.
|
||||
.It Fl u
|
||||
Update the file
|
||||
.Pa /etc/dumpdates
|
||||
after a successful dump.
|
||||
The format of
|
||||
.Pa /etc/dumpdates
|
||||
is readable by people, consisting of one
|
||||
free format record per line:
|
||||
filesystem name,
|
||||
increment level
|
||||
and
|
||||
.Xr ctime 3
|
||||
format dump date.
|
||||
There may be only one entry per filesystem at each level.
|
||||
The file
|
||||
.Pa /etc/dumpdates
|
||||
may be edited to change any of the fields,
|
||||
if necessary.
|
||||
.It Fl W
|
||||
.Nm Dump
|
||||
tells the operator what file systems need to be dumped.
|
||||
This information is gleaned from the files
|
||||
.Pa /etc/dumpdates
|
||||
and
|
||||
.Pa /etc/fstab .
|
||||
The
|
||||
.Fl W
|
||||
option causes
|
||||
.Nm dump
|
||||
to print out, for each file system in
|
||||
.Pa /etc/dumpdates
|
||||
the most recent dump date and level,
|
||||
and highlights those file systems that should be dumped.
|
||||
If the
|
||||
.Fl W
|
||||
option is set, all other options are ignored, and
|
||||
.Nm dump
|
||||
exits immediately.
|
||||
.It Fl w
|
||||
Is like W, but prints only those filesystems which need to be dumped.
|
||||
.El
|
||||
.Pp
|
||||
.Nm Dump
|
||||
requires operator intervention on these conditions:
|
||||
end of tape,
|
||||
end of dump,
|
||||
tape write error,
|
||||
tape open error or
|
||||
disk read error (if there are more than a threshold of 32).
|
||||
In addition to alerting all operators implied by the
|
||||
.Fl n
|
||||
key,
|
||||
.Nm dump
|
||||
interacts with the operator on
|
||||
.Em dump's
|
||||
control terminal at times when
|
||||
.Nm dump
|
||||
can no longer proceed,
|
||||
or if something is grossly wrong.
|
||||
All questions
|
||||
.Nm dump
|
||||
poses
|
||||
.Em must
|
||||
be answered by typing
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no ,
|
||||
appropriately.
|
||||
.Pp
|
||||
Since making a dump involves a lot of time and effort for full dumps,
|
||||
.Nm dump
|
||||
checkpoints itself at the start of each tape volume.
|
||||
If writing that volume fails for some reason,
|
||||
.Nm dump
|
||||
will,
|
||||
with operator permission,
|
||||
restart itself from the checkpoint
|
||||
after the old tape has been rewound and removed,
|
||||
and a new tape has been mounted.
|
||||
.Pp
|
||||
.Nm Dump
|
||||
tells the operator what is going on at periodic intervals,
|
||||
including usually low estimates of the number of blocks to write,
|
||||
the number of tapes it will take, the time to completion, and
|
||||
the time to the tape change.
|
||||
The output is verbose,
|
||||
so that others know that the terminal
|
||||
controlling
|
||||
.Nm dump
|
||||
is busy,
|
||||
and will be for some time.
|
||||
.Pp
|
||||
In the event of a catastrophic disk event, the time required
|
||||
to restore all the necessary backup tapes or files to disk
|
||||
can be kept to a minimum by staggering the incremental dumps.
|
||||
An efficient method of staggering incremental dumps
|
||||
to minimize the number of tapes follows:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
Always start with a level 0 backup, for example:
|
||||
.Bd -literal -offset indent
|
||||
/sbin/dump -0u -f /dev/nrst1 /usr/src
|
||||
.Ed
|
||||
.Pp
|
||||
This should be done at set intervals, say once a month or once every two months,
|
||||
and on a set of fresh tapes that is saved forever.
|
||||
.It
|
||||
After a level 0, dumps of active file
|
||||
systems are taken on a daily basis,
|
||||
using a modified Tower of Hanoi algorithm,
|
||||
with this sequence of dump levels:
|
||||
.Bd -literal -offset indent
|
||||
3 2 5 4 7 6 9 8 9 9 ...
|
||||
.Ed
|
||||
.Pp
|
||||
For the daily dumps, it should be possible to use a fixed number of tapes
|
||||
for each day, used on a weekly basis.
|
||||
Each week, a level 1 dump is taken, and
|
||||
the daily Hanoi sequence repeats beginning with 3.
|
||||
For weekly dumps, another fixed set of tapes per dumped file system is
|
||||
used, also on a cyclical basis.
|
||||
.El
|
||||
.Pp
|
||||
After several months or so, the daily and weekly tapes should get
|
||||
rotated out of the dump cycle and fresh tapes brought in.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/dumpdates -compact
|
||||
.It Pa /dev/rmt8
|
||||
default tape unit to dump to
|
||||
.It Pa /etc/dumpdates
|
||||
dump date records
|
||||
.It Pa /etc/fstab
|
||||
dump table: file systems and frequency
|
||||
.It Pa /etc/group
|
||||
to find group
|
||||
.Em operator
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr restore 8 ,
|
||||
.Xr rmt 8 ,
|
||||
.Xr dump 5 ,
|
||||
.Xr fstab 5
|
||||
.Sh DIAGNOSTICS
|
||||
Many, and verbose.
|
||||
.Pp
|
||||
Dump exits with zero status on success.
|
||||
Startup errors are indicated with an exit code of 1;
|
||||
abnormal termination is indicated with an exit code of 3.
|
||||
.Sh BUGS
|
||||
Fewer than 32 read errors on the filesystem are ignored.
|
||||
.Pp
|
||||
Each reel requires a new process, so parent processes for
|
||||
reels already written just hang around until the entire tape
|
||||
is written.
|
||||
.Pp
|
||||
.Nm Dump
|
||||
with the
|
||||
.Fl W
|
||||
or
|
||||
.Fl w
|
||||
options does not report filesystems that have never been recorded
|
||||
in
|
||||
.Pa /etc/dumpdates ,
|
||||
even if listed in
|
||||
.Pa /etc/fstab .
|
||||
.Pp
|
||||
It would be nice if
|
||||
.Nm dump
|
||||
knew about the dump sequence,
|
||||
kept track of the tapes scribbled on,
|
||||
told the operator which tape to mount when,
|
||||
and provided more assistance
|
||||
for the operator running
|
||||
.Xr restore .
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm dump
|
||||
command appeared in Version 6 AT&T UNIX.
|
||||
213
sbin/dump/dump.h
Normal file
213
sbin/dump/dump.h
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)dump.h 8.2 (Berkeley) 4/28/95
|
||||
*/
|
||||
|
||||
#define MAXINOPB (MAXBSIZE / sizeof(struct dinode))
|
||||
#define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
|
||||
|
||||
/*
|
||||
* Dump maps used to describe what is to be dumped.
|
||||
*/
|
||||
int mapsize; /* size of the state maps */
|
||||
char *usedinomap; /* map of allocated inodes */
|
||||
char *dumpdirmap; /* map of directories to be dumped */
|
||||
char *dumpinomap; /* map of files to be dumped */
|
||||
/*
|
||||
* Map manipulation macros.
|
||||
*/
|
||||
#define SETINO(ino, map) \
|
||||
map[(u_int)((ino) - 1) / NBBY] |= 1 << ((u_int)((ino) - 1) % NBBY)
|
||||
#define CLRINO(ino, map) \
|
||||
map[(u_int)((ino) - 1) / NBBY] &= ~(1 << ((u_int)((ino) - 1) % NBBY))
|
||||
#define TSTINO(ino, map) \
|
||||
(map[(u_int)((ino) - 1) / NBBY] & (1 << ((u_int)((ino) - 1) % NBBY)))
|
||||
|
||||
/*
|
||||
* All calculations done in 0.1" units!
|
||||
*/
|
||||
char *disk; /* name of the disk file */
|
||||
char *tape; /* name of the tape file */
|
||||
char *dumpdates; /* name of the file containing dump date information*/
|
||||
char *temp; /* name of the file for doing rewrite of dumpdates */
|
||||
char lastlevel; /* dump level of previous dump */
|
||||
char level; /* dump level of this dump */
|
||||
int uflag; /* update flag */
|
||||
int diskfd; /* disk file descriptor */
|
||||
int tapefd; /* tape file descriptor */
|
||||
int pipeout; /* true => output to standard output */
|
||||
ino_t curino; /* current inumber; used globally */
|
||||
int newtape; /* new tape flag */
|
||||
int density; /* density in 0.1" units */
|
||||
long tapesize; /* estimated tape size, blocks */
|
||||
long tsize; /* tape size in 0.1" units */
|
||||
long asize; /* number of 0.1" units written on current tape */
|
||||
int etapes; /* estimated number of tapes */
|
||||
int nonodump; /* if set, do not honor UF_NODUMP user flags */
|
||||
|
||||
int notify; /* notify operator flag */
|
||||
int blockswritten; /* number of blocks written on current tape */
|
||||
int tapeno; /* current tape number */
|
||||
time_t tstart_writing; /* when started writing the first tape block */
|
||||
struct fs *sblock; /* the file system super block */
|
||||
char sblock_buf[MAXBSIZE];
|
||||
long dev_bsize; /* block size of underlying disk device */
|
||||
int dev_bshift; /* log2(dev_bsize) */
|
||||
int tp_bshift; /* log2(TP_BSIZE) */
|
||||
|
||||
#ifndef __P
|
||||
#include <sys/cdefs.h>
|
||||
#endif
|
||||
|
||||
/* operator interface functions */
|
||||
void broadcast __P((char *message));
|
||||
void lastdump __P((int arg)); /* int should be char */
|
||||
void msg __P((const char *fmt, ...));
|
||||
void msgtail __P((const char *fmt, ...));
|
||||
int query __P((char *question));
|
||||
void quit __P((const char *fmt, ...));
|
||||
void set_operators __P((void));
|
||||
void timeest __P((void));
|
||||
time_t unctime __P((char *str));
|
||||
|
||||
/* mapping rouintes */
|
||||
struct dinode;
|
||||
long blockest __P((struct dinode *dp));
|
||||
int mapfiles __P((ino_t maxino, long *tapesize));
|
||||
int mapdirs __P((ino_t maxino, long *tapesize));
|
||||
|
||||
/* file dumping routines */
|
||||
void blksout __P((daddr_t *blkp, int frags, ino_t ino));
|
||||
void bread __P((daddr_t blkno, char *buf, int size));
|
||||
void dumpino __P((struct dinode *dp, ino_t ino));
|
||||
void dumpmap __P((char *map, int type, ino_t ino));
|
||||
void writeheader __P((ino_t ino));
|
||||
|
||||
/* tape writing routines */
|
||||
int alloctape __P((void));
|
||||
void close_rewind __P((void));
|
||||
void dumpblock __P((daddr_t blkno, int size));
|
||||
void startnewtape __P((int top));
|
||||
void trewind __P((void));
|
||||
void writerec __P((char *dp, int isspcl));
|
||||
|
||||
__dead void Exit __P((int status));
|
||||
void dumpabort __P((int signo));
|
||||
void getfstab __P((void));
|
||||
|
||||
char *rawname __P((char *cp));
|
||||
struct dinode *getino __P((ino_t inum));
|
||||
|
||||
/* rdump routines */
|
||||
#ifdef RDUMP
|
||||
void rmtclose __P((void));
|
||||
int rmthost __P((char *host));
|
||||
int rmtopen __P((char *tape, int mode));
|
||||
int rmtwrite __P((char *buf, int count));
|
||||
#endif /* RDUMP */
|
||||
|
||||
void interrupt __P((int signo)); /* in case operator bangs on console */
|
||||
|
||||
/*
|
||||
* Exit status codes
|
||||
*/
|
||||
#define X_FINOK 0 /* normal exit */
|
||||
#define X_REWRITE 2 /* restart writing from the check point */
|
||||
#define X_ABORT 3 /* abort dump; don't attempt checkpointing */
|
||||
|
||||
#define OPGRENT "operator" /* group entry to notify */
|
||||
#define DIALUP "ttyd" /* prefix for dialups */
|
||||
|
||||
struct fstab *fstabsearch __P((char *key)); /* search fs_file and fs_spec */
|
||||
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX 255
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The contents of the file _PATH_DUMPDATES is maintained both on
|
||||
* a linked list, and then (eventually) arrayified.
|
||||
*/
|
||||
struct dumpdates {
|
||||
char dd_name[NAME_MAX+3];
|
||||
char dd_level;
|
||||
time_t dd_ddate;
|
||||
};
|
||||
struct dumptime {
|
||||
struct dumpdates dt_value;
|
||||
struct dumptime *dt_next;
|
||||
};
|
||||
struct dumptime *dthead; /* head of the list version */
|
||||
int nddates; /* number of records (might be zero) */
|
||||
int ddates_in; /* we have read the increment file */
|
||||
struct dumpdates **ddatev; /* the arrayfied version */
|
||||
void initdumptimes __P((void));
|
||||
void getdumptime __P((void));
|
||||
void putdumptime __P((void));
|
||||
#define ITITERATE(i, ddp) \
|
||||
for (ddp = ddatev[i = 0]; i < nddates; ddp = ddatev[++i])
|
||||
|
||||
void sig __P((int signo));
|
||||
|
||||
/*
|
||||
* Compatibility with old systems.
|
||||
*/
|
||||
#ifdef COMPAT
|
||||
#include <sys/file.h>
|
||||
#define strchr(a,b) index(a,b)
|
||||
#define strrchr(a,b) rindex(a,b)
|
||||
extern char *strdup(), *ctime();
|
||||
extern int read(), write();
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_UTMP
|
||||
#define _PATH_UTMP "/etc/utmp"
|
||||
#endif
|
||||
#ifndef _PATH_FSTAB
|
||||
#define _PATH_FSTAB "/etc/fstab"
|
||||
#endif
|
||||
|
||||
#ifdef sunos
|
||||
extern char *calloc();
|
||||
extern char *malloc();
|
||||
extern long atol();
|
||||
extern char *strcpy();
|
||||
extern char *strncpy();
|
||||
extern char *strcat();
|
||||
extern time_t time();
|
||||
extern void endgrent();
|
||||
extern __dead void exit();
|
||||
extern off_t lseek();
|
||||
extern const char *strerror();
|
||||
#endif
|
||||
374
sbin/dump/dumprmt.c
Normal file
374
sbin/dump/dumprmt.c
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dumprmt.c 8.3 (Berkeley) 4/28/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mtio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/inode.h>
|
||||
#else
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "dump.h"
|
||||
|
||||
#define TS_CLOSED 0
|
||||
#define TS_OPEN 1
|
||||
|
||||
static int rmtstate = TS_CLOSED;
|
||||
static int rmtape;
|
||||
static char *rmtpeer;
|
||||
|
||||
static int okname __P((char *));
|
||||
static int rmtcall __P((char *, char *));
|
||||
static void rmtconnaborted __P((/* int, int */));
|
||||
static int rmtgetb __P((void));
|
||||
static void rmtgetconn __P((void));
|
||||
static void rmtgets __P((char *, int));
|
||||
static int rmtreply __P((char *));
|
||||
|
||||
extern int ntrec; /* blocking factor on tape */
|
||||
|
||||
int
|
||||
rmthost(host)
|
||||
char *host;
|
||||
{
|
||||
|
||||
rmtpeer = malloc(strlen(host) + 1);
|
||||
if (rmtpeer)
|
||||
strcpy(rmtpeer, host);
|
||||
else
|
||||
rmtpeer = host;
|
||||
signal(SIGPIPE, rmtconnaborted);
|
||||
rmtgetconn();
|
||||
if (rmtape < 0)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
rmtconnaborted()
|
||||
{
|
||||
|
||||
errx(1, "Lost connection to remote host.");
|
||||
}
|
||||
|
||||
void
|
||||
rmtgetconn()
|
||||
{
|
||||
register char *cp;
|
||||
static struct servent *sp = NULL;
|
||||
static struct passwd *pwd = NULL;
|
||||
#ifdef notdef
|
||||
static int on = 1;
|
||||
#endif
|
||||
char *tuser;
|
||||
int size;
|
||||
int maxseg;
|
||||
|
||||
if (sp == NULL) {
|
||||
sp = getservbyname("shell", "tcp");
|
||||
if (sp == NULL)
|
||||
errx(1, "shell/tcp: unknown service");
|
||||
pwd = getpwuid(getuid());
|
||||
if (pwd == NULL)
|
||||
errx(1, "who are you?");
|
||||
}
|
||||
if ((cp = strchr(rmtpeer, '@')) != NULL) {
|
||||
tuser = rmtpeer;
|
||||
*cp = '\0';
|
||||
if (!okname(tuser))
|
||||
exit(1);
|
||||
rmtpeer = ++cp;
|
||||
} else
|
||||
tuser = pwd->pw_name;
|
||||
rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name, tuser,
|
||||
_PATH_RMT, (int *)0);
|
||||
size = ntrec * TP_BSIZE;
|
||||
if (size > 60 * 1024) /* XXX */
|
||||
size = 60 * 1024;
|
||||
/* Leave some space for rmt request/response protocol */
|
||||
size += 2 * 1024;
|
||||
while (size > TP_BSIZE &&
|
||||
setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
|
||||
size -= TP_BSIZE;
|
||||
(void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
|
||||
maxseg = 1024;
|
||||
if (setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG,
|
||||
&maxseg, sizeof (maxseg)) < 0)
|
||||
perror("TCP_MAXSEG setsockopt");
|
||||
|
||||
#ifdef notdef
|
||||
if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
|
||||
perror("TCP_NODELAY setsockopt");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
okname(cp0)
|
||||
char *cp0;
|
||||
{
|
||||
register char *cp;
|
||||
register int c;
|
||||
|
||||
for (cp = cp0; *cp; cp++) {
|
||||
c = *cp;
|
||||
if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
|
||||
warnx("invalid user name: %s", cp0);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
rmtopen(tape, mode)
|
||||
char *tape;
|
||||
int mode;
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
(void)sprintf(buf, "O%s\n%d\n", tape, mode);
|
||||
rmtstate = TS_OPEN;
|
||||
return (rmtcall(tape, buf));
|
||||
}
|
||||
|
||||
void
|
||||
rmtclose()
|
||||
{
|
||||
|
||||
if (rmtstate != TS_OPEN)
|
||||
return;
|
||||
rmtcall("close", "C\n");
|
||||
rmtstate = TS_CLOSED;
|
||||
}
|
||||
|
||||
int
|
||||
rmtread(buf, count)
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
char line[30];
|
||||
int n, i, cc;
|
||||
extern errno;
|
||||
|
||||
(void)sprintf(line, "R%d\n", count);
|
||||
n = rmtcall("read", line);
|
||||
if (n < 0) {
|
||||
errno = n;
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < n; i += cc) {
|
||||
cc = read(rmtape, buf+i, n - i);
|
||||
if (cc <= 0) {
|
||||
rmtconnaborted();
|
||||
}
|
||||
}
|
||||
return (n);
|
||||
}
|
||||
|
||||
int
|
||||
rmtwrite(buf, count)
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
char line[30];
|
||||
|
||||
(void)sprintf(line, "W%d\n", count);
|
||||
write(rmtape, line, strlen(line));
|
||||
write(rmtape, buf, count);
|
||||
return (rmtreply("write"));
|
||||
}
|
||||
|
||||
void
|
||||
rmtwrite0(count)
|
||||
int count;
|
||||
{
|
||||
char line[30];
|
||||
|
||||
(void)sprintf(line, "W%d\n", count);
|
||||
write(rmtape, line, strlen(line));
|
||||
}
|
||||
|
||||
void
|
||||
rmtwrite1(buf, count)
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
|
||||
write(rmtape, buf, count);
|
||||
}
|
||||
|
||||
int
|
||||
rmtwrite2()
|
||||
{
|
||||
|
||||
return (rmtreply("write"));
|
||||
}
|
||||
|
||||
int
|
||||
rmtseek(offset, pos)
|
||||
int offset, pos;
|
||||
{
|
||||
char line[80];
|
||||
|
||||
(void)sprintf(line, "L%d\n%d\n", offset, pos);
|
||||
return (rmtcall("seek", line));
|
||||
}
|
||||
|
||||
struct mtget mts;
|
||||
|
||||
struct mtget *
|
||||
rmtstatus()
|
||||
{
|
||||
register int i;
|
||||
register char *cp;
|
||||
|
||||
if (rmtstate != TS_OPEN)
|
||||
return (NULL);
|
||||
rmtcall("status", "S\n");
|
||||
for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
|
||||
*cp++ = rmtgetb();
|
||||
return (&mts);
|
||||
}
|
||||
|
||||
int
|
||||
rmtioctl(cmd, count)
|
||||
int cmd, count;
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
if (count < 0)
|
||||
return (-1);
|
||||
(void)sprintf(buf, "I%d\n%d\n", cmd, count);
|
||||
return (rmtcall("ioctl", buf));
|
||||
}
|
||||
|
||||
static int
|
||||
rmtcall(cmd, buf)
|
||||
char *cmd, *buf;
|
||||
{
|
||||
|
||||
if (write(rmtape, buf, strlen(buf)) != strlen(buf))
|
||||
rmtconnaborted();
|
||||
return (rmtreply(cmd));
|
||||
}
|
||||
|
||||
static int
|
||||
rmtreply(cmd)
|
||||
char *cmd;
|
||||
{
|
||||
register char *cp;
|
||||
char code[30], emsg[BUFSIZ];
|
||||
|
||||
rmtgets(code, sizeof (code));
|
||||
if (*code == 'E' || *code == 'F') {
|
||||
rmtgets(emsg, sizeof (emsg));
|
||||
msg("%s: %s", cmd, emsg);
|
||||
if (*code == 'F') {
|
||||
rmtstate = TS_CLOSED;
|
||||
return (-1);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
if (*code != 'A') {
|
||||
/* Kill trailing newline */
|
||||
cp = code + strlen(code);
|
||||
if (cp > code && *--cp == '\n')
|
||||
*cp = '\0';
|
||||
|
||||
msg("Protocol to remote tape server botched (code \"%s\").\n",
|
||||
code);
|
||||
rmtconnaborted();
|
||||
}
|
||||
return (atoi(code + 1));
|
||||
}
|
||||
|
||||
int
|
||||
rmtgetb()
|
||||
{
|
||||
char c;
|
||||
|
||||
if (read(rmtape, &c, 1) != 1)
|
||||
rmtconnaborted();
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* Get a line (guaranteed to have a trailing newline). */
|
||||
void
|
||||
rmtgets(line, len)
|
||||
char *line;
|
||||
int len;
|
||||
{
|
||||
register char *cp = line;
|
||||
|
||||
while (len > 1) {
|
||||
*cp = rmtgetb();
|
||||
if (*cp == '\n') {
|
||||
cp[1] = '\0';
|
||||
return;
|
||||
}
|
||||
cp++;
|
||||
len--;
|
||||
}
|
||||
*cp = '\0';
|
||||
msg("Protocol to remote tape server botched.\n");
|
||||
msg("(rmtgets got \"%s\").\n", line);
|
||||
rmtconnaborted();
|
||||
}
|
||||
586
sbin/dump/main.c
Normal file
586
sbin/dump/main.c
Normal file
|
|
@ -0,0 +1,586 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/1/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/inode.h>
|
||||
#include <ufs/fs.h>
|
||||
#else
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#endif
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fstab.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dump.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#ifndef SBOFF
|
||||
#define SBOFF (SBLOCK * DEV_BSIZE)
|
||||
#endif
|
||||
|
||||
int notify = 0; /* notify operator flag */
|
||||
int blockswritten = 0; /* number of blocks written on current tape */
|
||||
int tapeno = 0; /* current tape number */
|
||||
int density = 0; /* density in bytes/0.1" */
|
||||
int ntrec = NTREC; /* # tape blocks in each tape record */
|
||||
int cartridge = 0; /* Assume non-cartridge tape */
|
||||
long dev_bsize = 1; /* recalculated below */
|
||||
long blocksperfile; /* output blocks per file */
|
||||
char *host = NULL; /* remote host (if any) */
|
||||
|
||||
static long numarg __P((char *, long, long));
|
||||
static void obsolete __P((int *, char **[]));
|
||||
static void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register ino_t ino;
|
||||
register int dirty;
|
||||
register struct dinode *dp;
|
||||
register struct fstab *dt;
|
||||
register char *map;
|
||||
register int ch;
|
||||
int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1;
|
||||
ino_t maxino;
|
||||
|
||||
spcl.c_date = 0;
|
||||
(void)time((time_t *)&spcl.c_date);
|
||||
|
||||
tsize = 0; /* Default later, based on 'c' option for cart tapes */
|
||||
tape = _PATH_DEFTAPE;
|
||||
dumpdates = _PATH_DUMPDATES;
|
||||
temp = _PATH_DTMP;
|
||||
if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
|
||||
quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
|
||||
level = '0';
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
obsolete(&argc, &argv);
|
||||
while ((ch = getopt(argc, argv, "0123456789B:b:cd:f:h:ns:T:uWw")) != -1)
|
||||
switch (ch) {
|
||||
/* dump level */
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
level = ch;
|
||||
break;
|
||||
|
||||
case 'B': /* blocks per output file */
|
||||
blocksperfile = numarg("blocks per file", 1L, 0L);
|
||||
break;
|
||||
|
||||
case 'b': /* blocks per tape write */
|
||||
ntrec = numarg("blocks per write", 1L, 1000L);
|
||||
break;
|
||||
|
||||
case 'c': /* Tape is cart. not 9-track */
|
||||
cartridge = 1;
|
||||
break;
|
||||
|
||||
case 'd': /* density, in bits per inch */
|
||||
density = numarg("density", 10L, 327670L) / 10;
|
||||
if (density >= 625 && !bflag)
|
||||
ntrec = HIGHDENSITYTREC;
|
||||
break;
|
||||
|
||||
case 'f': /* output file */
|
||||
tape = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
honorlevel = numarg("honor level", 0L, 10L);
|
||||
break;
|
||||
|
||||
case 'n': /* notify operators */
|
||||
notify = 1;
|
||||
break;
|
||||
|
||||
case 's': /* tape size, feet */
|
||||
tsize = numarg("tape size", 1L, 0L) * 12 * 10;
|
||||
break;
|
||||
|
||||
case 'T': /* time of last dump */
|
||||
spcl.c_ddate = unctime(optarg);
|
||||
if (spcl.c_ddate < 0) {
|
||||
(void)fprintf(stderr, "bad time \"%s\"\n",
|
||||
optarg);
|
||||
exit(X_ABORT);
|
||||
}
|
||||
Tflag = 1;
|
||||
lastlevel = '?';
|
||||
break;
|
||||
|
||||
case 'u': /* update /etc/dumpdates */
|
||||
uflag = 1;
|
||||
break;
|
||||
|
||||
case 'W': /* what to do */
|
||||
case 'w':
|
||||
lastdump(ch);
|
||||
exit(0); /* do nothing else */
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
(void)fprintf(stderr, "Must specify disk or filesystem\n");
|
||||
exit(X_ABORT);
|
||||
}
|
||||
disk = *argv++;
|
||||
argc--;
|
||||
if (argc >= 1) {
|
||||
(void)fprintf(stderr, "Unknown arguments to dump:");
|
||||
while (argc--)
|
||||
(void)fprintf(stderr, " %s", *argv++);
|
||||
(void)fprintf(stderr, "\n");
|
||||
exit(X_ABORT);
|
||||
}
|
||||
if (Tflag && uflag) {
|
||||
(void)fprintf(stderr,
|
||||
"You cannot use the T and u flags together.\n");
|
||||
exit(X_ABORT);
|
||||
}
|
||||
if (strcmp(tape, "-") == 0) {
|
||||
pipeout++;
|
||||
tape = "standard output";
|
||||
}
|
||||
|
||||
if (blocksperfile)
|
||||
blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
|
||||
else {
|
||||
/*
|
||||
* Determine how to default tape size and density
|
||||
*
|
||||
* density tape size
|
||||
* 9-track 1600 bpi (160 bytes/.1") 2300 ft.
|
||||
* 9-track 6250 bpi (625 bytes/.1") 2300 ft.
|
||||
* cartridge 8000 bpi (100 bytes/.1") 1700 ft.
|
||||
* (450*4 - slop)
|
||||
*/
|
||||
if (density == 0)
|
||||
density = cartridge ? 100 : 160;
|
||||
if (tsize == 0)
|
||||
tsize = cartridge ? 1700L*120L : 2300L*120L;
|
||||
}
|
||||
|
||||
if (strchr(tape, ':')) {
|
||||
host = tape;
|
||||
tape = strchr(host, ':');
|
||||
*tape++ = '\0';
|
||||
#ifdef RDUMP
|
||||
if (rmthost(host) == 0)
|
||||
exit(X_ABORT);
|
||||
#else
|
||||
(void)fprintf(stderr, "remote dump not enabled\n");
|
||||
exit(X_ABORT);
|
||||
#endif
|
||||
}
|
||||
(void)setuid(getuid()); /* rmthost() is the only reason to be setuid */
|
||||
|
||||
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGHUP, sig);
|
||||
if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGTRAP, sig);
|
||||
if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGFPE, sig);
|
||||
if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGBUS, sig);
|
||||
if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGSEGV, sig);
|
||||
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGTERM, sig);
|
||||
if (signal(SIGINT, interrupt) == SIG_IGN)
|
||||
signal(SIGINT, SIG_IGN);
|
||||
|
||||
set_operators(); /* /etc/group snarfed */
|
||||
getfstab(); /* /etc/fstab snarfed */
|
||||
/*
|
||||
* disk can be either the full special file name,
|
||||
* the suffix of the special file name,
|
||||
* the special name missing the leading '/',
|
||||
* the file system name with or without the leading '/'.
|
||||
*/
|
||||
dt = fstabsearch(disk);
|
||||
if (dt != NULL) {
|
||||
disk = rawname(dt->fs_spec);
|
||||
(void)strncpy(spcl.c_dev, dt->fs_spec, NAMELEN);
|
||||
(void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
|
||||
} else {
|
||||
(void)strncpy(spcl.c_dev, disk, NAMELEN);
|
||||
(void)strncpy(spcl.c_filesys, "an unlisted file system",
|
||||
NAMELEN);
|
||||
}
|
||||
(void)strcpy(spcl.c_label, "none");
|
||||
(void)gethostname(spcl.c_host, NAMELEN);
|
||||
spcl.c_level = level - '0';
|
||||
spcl.c_type = TS_TAPE;
|
||||
if (!Tflag)
|
||||
getdumptime(); /* /etc/dumpdates snarfed */
|
||||
|
||||
msg("Date of this level %c dump: %s", level,
|
||||
spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
|
||||
msg("Date of last level %c dump: %s", lastlevel,
|
||||
spcl.c_ddate == 0 ? "the epoch\n" : ctime(&spcl.c_ddate));
|
||||
msg("Dumping %s ", disk);
|
||||
if (dt != NULL)
|
||||
msgtail("(%s) ", dt->fs_file);
|
||||
if (host)
|
||||
msgtail("to %s on host %s\n", tape, host);
|
||||
else
|
||||
msgtail("to %s\n", tape);
|
||||
|
||||
if ((diskfd = open(disk, O_RDONLY)) < 0) {
|
||||
msg("Cannot open %s\n", disk);
|
||||
exit(X_ABORT);
|
||||
}
|
||||
sync();
|
||||
sblock = (struct fs *)sblock_buf;
|
||||
bread(SBOFF, (char *) sblock, SBSIZE);
|
||||
if (sblock->fs_magic != FS_MAGIC)
|
||||
quit("bad sblock magic number\n");
|
||||
dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
|
||||
dev_bshift = ffs(dev_bsize) - 1;
|
||||
if (dev_bsize != (1 << dev_bshift))
|
||||
quit("dev_bsize (%d) is not a power of 2", dev_bsize);
|
||||
tp_bshift = ffs(TP_BSIZE) - 1;
|
||||
if (TP_BSIZE != (1 << tp_bshift))
|
||||
quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
|
||||
#ifdef FS_44INODEFMT
|
||||
if (sblock->fs_inodefmt >= FS_44INODEFMT)
|
||||
spcl.c_flags |= DR_NEWINODEFMT;
|
||||
#endif
|
||||
maxino = sblock->fs_ipg * sblock->fs_ncg;
|
||||
mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE);
|
||||
usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
|
||||
dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
|
||||
dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
|
||||
tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
|
||||
|
||||
nonodump = spcl.c_level < honorlevel;
|
||||
|
||||
msg("mapping (Pass I) [regular files]\n");
|
||||
anydirskipped = mapfiles(maxino, &tapesize);
|
||||
|
||||
msg("mapping (Pass II) [directories]\n");
|
||||
while (anydirskipped) {
|
||||
anydirskipped = mapdirs(maxino, &tapesize);
|
||||
}
|
||||
|
||||
if (pipeout) {
|
||||
tapesize += 10; /* 10 trailer blocks */
|
||||
msg("estimated %ld tape blocks.\n", tapesize);
|
||||
} else {
|
||||
double fetapes;
|
||||
|
||||
if (blocksperfile)
|
||||
fetapes = (double) tapesize / blocksperfile;
|
||||
else if (cartridge) {
|
||||
/* Estimate number of tapes, assuming streaming stops at
|
||||
the end of each block written, and not in mid-block.
|
||||
Assume no erroneous blocks; this can be compensated
|
||||
for with an artificially low tape size. */
|
||||
fetapes =
|
||||
( tapesize /* blocks */
|
||||
* TP_BSIZE /* bytes/block */
|
||||
* (1.0/density) /* 0.1" / byte */
|
||||
+
|
||||
tapesize /* blocks */
|
||||
* (1.0/ntrec) /* streaming-stops per block */
|
||||
* 15.48 /* 0.1" / streaming-stop */
|
||||
) * (1.0 / tsize ); /* tape / 0.1" */
|
||||
} else {
|
||||
/* Estimate number of tapes, for old fashioned 9-track
|
||||
tape */
|
||||
int tenthsperirg = (density == 625) ? 3 : 7;
|
||||
fetapes =
|
||||
( tapesize /* blocks */
|
||||
* TP_BSIZE /* bytes / block */
|
||||
* (1.0/density) /* 0.1" / byte */
|
||||
+
|
||||
tapesize /* blocks */
|
||||
* (1.0/ntrec) /* IRG's / block */
|
||||
* tenthsperirg /* 0.1" / IRG */
|
||||
) * (1.0 / tsize ); /* tape / 0.1" */
|
||||
}
|
||||
etapes = fetapes; /* truncating assignment */
|
||||
etapes++;
|
||||
/* count the dumped inodes map on each additional tape */
|
||||
tapesize += (etapes - 1) *
|
||||
(howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
|
||||
tapesize += etapes + 10; /* headers + 10 trailer blks */
|
||||
msg("estimated %ld tape blocks on %3.2f tape(s).\n",
|
||||
tapesize, fetapes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate tape buffer.
|
||||
*/
|
||||
if (!alloctape())
|
||||
quit("can't allocate tape buffers - try a smaller blocking factor.\n");
|
||||
|
||||
startnewtape(1);
|
||||
(void)time((time_t *)&(tstart_writing));
|
||||
dumpmap(usedinomap, TS_CLRI, maxino - 1);
|
||||
|
||||
msg("dumping (Pass III) [directories]\n");
|
||||
dirty = 0; /* XXX just to get gcc to shut up */
|
||||
for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
|
||||
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
|
||||
dirty = *map++;
|
||||
else
|
||||
dirty >>= 1;
|
||||
if ((dirty & 1) == 0)
|
||||
continue;
|
||||
/*
|
||||
* Skip directory inodes deleted and maybe reallocated
|
||||
*/
|
||||
dp = getino(ino);
|
||||
if ((dp->di_mode & IFMT) != IFDIR)
|
||||
continue;
|
||||
(void)dumpino(dp, ino);
|
||||
}
|
||||
|
||||
msg("dumping (Pass IV) [regular files]\n");
|
||||
for (map = dumpinomap, ino = 1; ino < maxino; ino++) {
|
||||
int mode;
|
||||
|
||||
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
|
||||
dirty = *map++;
|
||||
else
|
||||
dirty >>= 1;
|
||||
if ((dirty & 1) == 0)
|
||||
continue;
|
||||
/*
|
||||
* Skip inodes deleted and reallocated as directories.
|
||||
*/
|
||||
dp = getino(ino);
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == IFDIR)
|
||||
continue;
|
||||
(void)dumpino(dp, ino);
|
||||
}
|
||||
|
||||
spcl.c_type = TS_END;
|
||||
for (i = 0; i < ntrec; i++)
|
||||
writeheader(maxino - 1);
|
||||
if (pipeout)
|
||||
msg("DUMP: %ld tape blocks\n",spcl.c_tapea);
|
||||
else
|
||||
msg("DUMP: %ld tape blocks on %d volumes(s)\n",
|
||||
spcl.c_tapea, spcl.c_volume);
|
||||
putdumptime();
|
||||
trewind();
|
||||
broadcast("DUMP IS DONE!\7\7\n");
|
||||
msg("DUMP IS DONE\n");
|
||||
Exit(X_FINOK);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "usage: dump [-0123456789cnu] [-B records] [-b blocksize] [-d density] [-f file]\n [-h level] [-s feet] [-T date] filesystem\n");
|
||||
(void)fprintf(stderr, " dump [-W | -w]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pick up a numeric argument. It must be nonnegative and in the given
|
||||
* range (except that a vmax of 0 means unlimited).
|
||||
*/
|
||||
static long
|
||||
numarg(meaning, vmin, vmax)
|
||||
char *meaning;
|
||||
long vmin, vmax;
|
||||
{
|
||||
char *p;
|
||||
long val;
|
||||
|
||||
val = strtol(optarg, &p, 10);
|
||||
if (*p)
|
||||
errx(1, "illegal %s -- %s", meaning, optarg);
|
||||
if (val < vmin || (vmax && val > vmax))
|
||||
errx(1, "%s must be between %ld and %ld", meaning, vmin, vmax);
|
||||
return (val);
|
||||
}
|
||||
|
||||
void
|
||||
sig(signo)
|
||||
int signo;
|
||||
{
|
||||
switch(signo) {
|
||||
case SIGALRM:
|
||||
case SIGBUS:
|
||||
case SIGFPE:
|
||||
case SIGHUP:
|
||||
case SIGTERM:
|
||||
case SIGTRAP:
|
||||
if (pipeout)
|
||||
quit("Signal on pipe: cannot recover\n");
|
||||
msg("Rewriting attempted as response to unknown signal.\n");
|
||||
(void)fflush(stderr);
|
||||
(void)fflush(stdout);
|
||||
close_rewind();
|
||||
exit(X_REWRITE);
|
||||
/* NOTREACHED */
|
||||
case SIGSEGV:
|
||||
msg("SIGSEGV: ABORTING!\n");
|
||||
(void)signal(SIGSEGV, SIG_DFL);
|
||||
(void)kill(0, SIGSEGV);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
rawname(cp)
|
||||
char *cp;
|
||||
{
|
||||
static char rawbuf[MAXPATHLEN];
|
||||
char *dp = strrchr(cp, '/');
|
||||
|
||||
if (dp == NULL)
|
||||
return (NULL);
|
||||
*dp = '\0';
|
||||
(void)strcpy(rawbuf, cp);
|
||||
*dp = '/';
|
||||
(void)strcat(rawbuf, "/r");
|
||||
(void)strcat(rawbuf, dp + 1);
|
||||
return (rawbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* obsolete --
|
||||
* Change set of key letters and ordered arguments into something
|
||||
* getopt(3) will like.
|
||||
*/
|
||||
static void
|
||||
obsolete(argcp, argvp)
|
||||
int *argcp;
|
||||
char **argvp[];
|
||||
{
|
||||
int argc, flags;
|
||||
char *ap, **argv, *flagsp, **nargv, *p;
|
||||
|
||||
/* Setup. */
|
||||
argv = *argvp;
|
||||
argc = *argcp;
|
||||
|
||||
/* Return if no arguments or first argument has leading dash. */
|
||||
ap = argv[1];
|
||||
if (argc == 1 || *ap == '-')
|
||||
return;
|
||||
|
||||
/* Allocate space for new arguments. */
|
||||
if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
|
||||
(p = flagsp = malloc(strlen(ap) + 2)) == NULL)
|
||||
err(1, NULL);
|
||||
|
||||
*nargv++ = *argv;
|
||||
argv += 2;
|
||||
|
||||
for (flags = 0; *ap; ++ap) {
|
||||
switch (*ap) {
|
||||
case 'B':
|
||||
case 'b':
|
||||
case 'd':
|
||||
case 'f':
|
||||
case 'h':
|
||||
case 's':
|
||||
case 'T':
|
||||
if (*argv == NULL) {
|
||||
warnx("option requires an argument -- %c", *ap);
|
||||
usage();
|
||||
}
|
||||
if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
|
||||
err(1, NULL);
|
||||
nargv[0][0] = '-';
|
||||
nargv[0][1] = *ap;
|
||||
(void)strcpy(&nargv[0][2], *argv);
|
||||
++argv;
|
||||
++nargv;
|
||||
break;
|
||||
default:
|
||||
if (!flags) {
|
||||
*p++ = '-';
|
||||
flags = 1;
|
||||
}
|
||||
*p++ = *ap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate flags. */
|
||||
if (flags) {
|
||||
*p = '\0';
|
||||
*nargv++ = flagsp;
|
||||
}
|
||||
|
||||
/* Copy remaining arguments. */
|
||||
while (*nargv++ = *argv++);
|
||||
|
||||
/* Update argument count. */
|
||||
*argcp = nargv - *argvp - 1;
|
||||
}
|
||||
859
sbin/dump/tape.c
Normal file
859
sbin/dump/tape.c
Normal file
|
|
@ -0,0 +1,859 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)tape.c 8.4 (Berkeley) 5/1/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/fs.h>
|
||||
#include <ufs/inode.h>
|
||||
#else
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#endif
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
int write(), read();
|
||||
#endif
|
||||
|
||||
#include "dump.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
int writesize; /* size of malloc()ed buffer for tape */
|
||||
long lastspclrec = -1; /* tape block number of last written header */
|
||||
int trecno = 0; /* next record to write in current block */
|
||||
extern long blocksperfile; /* number of blocks per output file */
|
||||
long blocksthisvol; /* number of blocks on current output file */
|
||||
extern int ntrec; /* blocking factor on tape */
|
||||
extern int cartridge;
|
||||
extern char *host;
|
||||
char *nexttape;
|
||||
|
||||
static int atomic __P((int (*)(), int, char *, int));
|
||||
static void doslave __P((int, int));
|
||||
static void enslave __P((void));
|
||||
static void flushtape __P((void));
|
||||
static void killall __P((void));
|
||||
static void rollforward __P((void));
|
||||
|
||||
/*
|
||||
* Concurrent dump mods (Caltech) - disk block reading and tape writing
|
||||
* are exported to several slave processes. While one slave writes the
|
||||
* tape, the others read disk blocks; they pass control of the tape in
|
||||
* a ring via signals. The parent process traverses the filesystem and
|
||||
* sends writeheader()'s and lists of daddr's to the slaves via pipes.
|
||||
* The following structure defines the instruction packets sent to slaves.
|
||||
*/
|
||||
struct req {
|
||||
daddr_t dblk;
|
||||
int count;
|
||||
};
|
||||
int reqsiz;
|
||||
|
||||
#define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */
|
||||
struct slave {
|
||||
int tapea; /* header number at start of this chunk */
|
||||
int count; /* count to next header (used for TS_TAPE */
|
||||
/* after EOT) */
|
||||
int inode; /* inode that we are currently dealing with */
|
||||
int fd; /* FD for this slave */
|
||||
int pid; /* PID for this slave */
|
||||
int sent; /* 1 == we've sent this slave requests */
|
||||
int firstrec; /* record number of this block */
|
||||
char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
|
||||
struct req *req; /* buffer for requests */
|
||||
} slaves[SLAVES+1];
|
||||
struct slave *slp;
|
||||
|
||||
char (*nextblock)[TP_BSIZE];
|
||||
|
||||
int master; /* pid of master, for sending error signals */
|
||||
int tenths; /* length of tape used per block written */
|
||||
static int caught; /* have we caught the signal to proceed? */
|
||||
static int ready; /* have we reached the lock point without having */
|
||||
/* received the SIGUSR2 signal from the prev slave? */
|
||||
static jmp_buf jmpbuf; /* where to jump to if we are ready when the */
|
||||
/* SIGUSR2 arrives from the previous slave */
|
||||
|
||||
int
|
||||
alloctape()
|
||||
{
|
||||
int pgoff = getpagesize() - 1;
|
||||
char *buf;
|
||||
int i;
|
||||
|
||||
writesize = ntrec * TP_BSIZE;
|
||||
reqsiz = (ntrec + 1) * sizeof(struct req);
|
||||
/*
|
||||
* CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
|
||||
* (see DEC TU80 User's Guide). The shorter gaps of 6250-bpi require
|
||||
* repositioning after stopping, i.e, streaming mode, where the gap is
|
||||
* variable, 0.30" to 0.45". The gap is maximal when the tape stops.
|
||||
*/
|
||||
if (blocksperfile == 0)
|
||||
tenths = writesize / density +
|
||||
(cartridge ? 16 : density == 625 ? 5 : 8);
|
||||
/*
|
||||
* Allocate tape buffer contiguous with the array of instruction
|
||||
* packets, so flushtape() can write them together with one write().
|
||||
* Align tape buffer on page boundary to speed up tape write().
|
||||
*/
|
||||
for (i = 0; i <= SLAVES; i++) {
|
||||
buf = (char *)
|
||||
malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
|
||||
if (buf == NULL)
|
||||
return(0);
|
||||
slaves[i].tblock = (char (*)[TP_BSIZE])
|
||||
(((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
|
||||
slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
|
||||
}
|
||||
slp = &slaves[0];
|
||||
slp->count = 1;
|
||||
slp->tapea = 0;
|
||||
slp->firstrec = 0;
|
||||
nextblock = slp->tblock;
|
||||
return(1);
|
||||
}
|
||||
|
||||
void
|
||||
writerec(dp, isspcl)
|
||||
char *dp;
|
||||
int isspcl;
|
||||
{
|
||||
|
||||
slp->req[trecno].dblk = (daddr_t)0;
|
||||
slp->req[trecno].count = 1;
|
||||
*(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)dp;
|
||||
if (isspcl)
|
||||
lastspclrec = spcl.c_tapea;
|
||||
trecno++;
|
||||
spcl.c_tapea++;
|
||||
if (trecno >= ntrec)
|
||||
flushtape();
|
||||
}
|
||||
|
||||
void
|
||||
dumpblock(blkno, size)
|
||||
daddr_t blkno;
|
||||
int size;
|
||||
{
|
||||
int avail, tpblks, dblkno;
|
||||
|
||||
dblkno = fsbtodb(sblock, blkno);
|
||||
tpblks = size >> tp_bshift;
|
||||
while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
|
||||
slp->req[trecno].dblk = dblkno;
|
||||
slp->req[trecno].count = avail;
|
||||
trecno += avail;
|
||||
spcl.c_tapea += avail;
|
||||
if (trecno >= ntrec)
|
||||
flushtape();
|
||||
dblkno += avail << (tp_bshift - dev_bshift);
|
||||
tpblks -= avail;
|
||||
}
|
||||
}
|
||||
|
||||
int nogripe = 0;
|
||||
|
||||
void
|
||||
tperror(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (pipeout) {
|
||||
msg("write error on %s\n", tape);
|
||||
quit("Cannot recover\n");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
msg("write error %d blocks into volume %d\n", blocksthisvol, tapeno);
|
||||
broadcast("DUMP WRITE ERROR!\n");
|
||||
if (!query("Do you want to restart?"))
|
||||
dumpabort(0);
|
||||
msg("Closing this volume. Prepare to restart with new media;\n");
|
||||
msg("this dump volume will be rewritten.\n");
|
||||
killall();
|
||||
nogripe = 1;
|
||||
close_rewind();
|
||||
Exit(X_REWRITE);
|
||||
}
|
||||
|
||||
void
|
||||
sigpipe(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
quit("Broken pipe\n");
|
||||
}
|
||||
|
||||
static void
|
||||
flushtape()
|
||||
{
|
||||
int i, blks, got;
|
||||
long lastfirstrec;
|
||||
|
||||
int siz = (char *)nextblock - (char *)slp->req;
|
||||
|
||||
slp->req[trecno].count = 0; /* Sentinel */
|
||||
|
||||
if (atomic(write, slp->fd, (char *)slp->req, siz) != siz)
|
||||
quit("error writing command pipe: %s\n", strerror(errno));
|
||||
slp->sent = 1; /* we sent a request, read the response later */
|
||||
|
||||
lastfirstrec = slp->firstrec;
|
||||
|
||||
if (++slp >= &slaves[SLAVES])
|
||||
slp = &slaves[0];
|
||||
|
||||
/* Read results back from next slave */
|
||||
if (slp->sent) {
|
||||
if (atomic(read, slp->fd, (char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slp->sent = 0;
|
||||
|
||||
/* Check for end of tape */
|
||||
if (got < writesize) {
|
||||
msg("End of tape detected\n");
|
||||
|
||||
/*
|
||||
* Drain the results, don't care what the values were.
|
||||
* If we read them here then trewind won't...
|
||||
*/
|
||||
for (i = 0; i < SLAVES; i++) {
|
||||
if (slaves[i].sent) {
|
||||
if (atomic(read, slaves[i].fd,
|
||||
(char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slaves[i].sent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
close_rewind();
|
||||
rollforward();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
blks = 0;
|
||||
if (spcl.c_type != TS_END) {
|
||||
for (i = 0; i < spcl.c_count; i++)
|
||||
if (spcl.c_addr[i] != 0)
|
||||
blks++;
|
||||
}
|
||||
slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
|
||||
slp->tapea = spcl.c_tapea;
|
||||
slp->firstrec = lastfirstrec + ntrec;
|
||||
slp->inode = curino;
|
||||
nextblock = slp->tblock;
|
||||
trecno = 0;
|
||||
asize += tenths;
|
||||
blockswritten += ntrec;
|
||||
blocksthisvol += ntrec;
|
||||
if (!pipeout && (blocksperfile ?
|
||||
(blocksthisvol >= blocksperfile) : (asize > tsize))) {
|
||||
close_rewind();
|
||||
startnewtape(0);
|
||||
}
|
||||
timeest();
|
||||
}
|
||||
|
||||
void
|
||||
trewind()
|
||||
{
|
||||
int f;
|
||||
int got;
|
||||
|
||||
for (f = 0; f < SLAVES; f++) {
|
||||
/*
|
||||
* Drain the results, but unlike EOT we DO (or should) care
|
||||
* what the return values were, since if we detect EOT after
|
||||
* we think we've written the last blocks to the tape anyway,
|
||||
* we have to replay those blocks with rollforward.
|
||||
*
|
||||
* fixme: punt for now.
|
||||
*/
|
||||
if (slaves[f].sent) {
|
||||
if (atomic(read, slaves[f].fd, (char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slaves[f].sent = 0;
|
||||
if (got != writesize) {
|
||||
msg("EOT detected in last 2 tape records!\n");
|
||||
msg("Use a longer tape, decrease the size estimate\n");
|
||||
quit("or use no size estimate at all.\n");
|
||||
}
|
||||
}
|
||||
(void) close(slaves[f].fd);
|
||||
}
|
||||
while (wait((int *)NULL) >= 0) /* wait for any signals from slaves */
|
||||
/* void */;
|
||||
|
||||
if (pipeout)
|
||||
return;
|
||||
|
||||
msg("Closing %s\n", tape);
|
||||
|
||||
#ifdef RDUMP
|
||||
if (host) {
|
||||
rmtclose();
|
||||
while (rmtopen(tape, 0) < 0)
|
||||
sleep(10);
|
||||
rmtclose();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
(void) close(tapefd);
|
||||
while ((f = open(tape, 0)) < 0)
|
||||
sleep (10);
|
||||
(void) close(f);
|
||||
}
|
||||
|
||||
void
|
||||
close_rewind()
|
||||
{
|
||||
trewind();
|
||||
if (nexttape)
|
||||
return;
|
||||
if (!nogripe) {
|
||||
msg("Change Volumes: Mount volume #%d\n", tapeno+1);
|
||||
broadcast("CHANGE DUMP VOLUMES!\7\7\n");
|
||||
}
|
||||
while (!query("Is the new volume mounted and ready to go?"))
|
||||
if (query("Do you want to abort?")) {
|
||||
dumpabort(0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rollforward()
|
||||
{
|
||||
register struct req *p, *q, *prev;
|
||||
register struct slave *tslp;
|
||||
int i, size, savedtapea, got;
|
||||
union u_spcl *ntb, *otb;
|
||||
tslp = &slaves[SLAVES];
|
||||
ntb = (union u_spcl *)tslp->tblock[1];
|
||||
|
||||
/*
|
||||
* Each of the N slaves should have requests that need to
|
||||
* be replayed on the next tape. Use the extra slave buffers
|
||||
* (slaves[SLAVES]) to construct request lists to be sent to
|
||||
* each slave in turn.
|
||||
*/
|
||||
for (i = 0; i < SLAVES; i++) {
|
||||
q = &tslp->req[1];
|
||||
otb = (union u_spcl *)slp->tblock;
|
||||
|
||||
/*
|
||||
* For each request in the current slave, copy it to tslp.
|
||||
*/
|
||||
|
||||
prev = NULL;
|
||||
for (p = slp->req; p->count > 0; p += p->count) {
|
||||
*q = *p;
|
||||
if (p->dblk == 0)
|
||||
*ntb++ = *otb++; /* copy the datablock also */
|
||||
prev = q;
|
||||
q += q->count;
|
||||
}
|
||||
if (prev == NULL)
|
||||
quit("rollforward: protocol botch");
|
||||
if (prev->dblk != 0)
|
||||
prev->count -= 1;
|
||||
else
|
||||
ntb--;
|
||||
q -= 1;
|
||||
q->count = 0;
|
||||
q = &tslp->req[0];
|
||||
if (i == 0) {
|
||||
q->dblk = 0;
|
||||
q->count = 1;
|
||||
trecno = 0;
|
||||
nextblock = tslp->tblock;
|
||||
savedtapea = spcl.c_tapea;
|
||||
spcl.c_tapea = slp->tapea;
|
||||
startnewtape(0);
|
||||
spcl.c_tapea = savedtapea;
|
||||
lastspclrec = savedtapea - 1;
|
||||
}
|
||||
size = (char *)ntb - (char *)q;
|
||||
if (atomic(write, slp->fd, (char *)q, size) != size) {
|
||||
perror(" DUMP: error writing command pipe");
|
||||
dumpabort(0);
|
||||
}
|
||||
slp->sent = 1;
|
||||
if (++slp >= &slaves[SLAVES])
|
||||
slp = &slaves[0];
|
||||
|
||||
q->count = 1;
|
||||
|
||||
if (prev->dblk != 0) {
|
||||
/*
|
||||
* If the last one was a disk block, make the
|
||||
* first of this one be the last bit of that disk
|
||||
* block...
|
||||
*/
|
||||
q->dblk = prev->dblk +
|
||||
prev->count * (TP_BSIZE / DEV_BSIZE);
|
||||
ntb = (union u_spcl *)tslp->tblock;
|
||||
} else {
|
||||
/*
|
||||
* It wasn't a disk block. Copy the data to its
|
||||
* new location in the buffer.
|
||||
*/
|
||||
q->dblk = 0;
|
||||
*((union u_spcl *)tslp->tblock) = *ntb;
|
||||
ntb = (union u_spcl *)tslp->tblock[1];
|
||||
}
|
||||
}
|
||||
slp->req[0] = *q;
|
||||
nextblock = slp->tblock;
|
||||
if (q->dblk == 0)
|
||||
nextblock++;
|
||||
trecno = 1;
|
||||
|
||||
/*
|
||||
* Clear the first slaves' response. One hopes that it
|
||||
* worked ok, otherwise the tape is much too short!
|
||||
*/
|
||||
if (slp->sent) {
|
||||
if (atomic(read, slp->fd, (char *)&got, sizeof got)
|
||||
!= sizeof got) {
|
||||
perror(" DUMP: error reading command pipe in master");
|
||||
dumpabort(0);
|
||||
}
|
||||
slp->sent = 0;
|
||||
|
||||
if (got != writesize) {
|
||||
quit("EOT detected at start of the tape!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We implement taking and restoring checkpoints on the tape level.
|
||||
* When each tape is opened, a new process is created by forking; this
|
||||
* saves all of the necessary context in the parent. The child
|
||||
* continues the dump; the parent waits around, saving the context.
|
||||
* If the child returns X_REWRITE, then it had problems writing that tape;
|
||||
* this causes the parent to fork again, duplicating the context, and
|
||||
* everything continues as if nothing had happened.
|
||||
*/
|
||||
void
|
||||
startnewtape(top)
|
||||
int top;
|
||||
{
|
||||
int parentpid;
|
||||
int childpid;
|
||||
int status;
|
||||
int waitpid;
|
||||
char *p;
|
||||
#ifdef sunos
|
||||
void (*interrupt_save)();
|
||||
#else
|
||||
sig_t interrupt_save;
|
||||
#endif
|
||||
|
||||
interrupt_save = signal(SIGINT, SIG_IGN);
|
||||
parentpid = getpid();
|
||||
|
||||
restore_check_point:
|
||||
(void)signal(SIGINT, interrupt_save);
|
||||
/*
|
||||
* All signals are inherited...
|
||||
*/
|
||||
childpid = fork();
|
||||
if (childpid < 0) {
|
||||
msg("Context save fork fails in parent %d\n", parentpid);
|
||||
Exit(X_ABORT);
|
||||
}
|
||||
if (childpid != 0) {
|
||||
/*
|
||||
* PARENT:
|
||||
* save the context by waiting
|
||||
* until the child doing all of the work returns.
|
||||
* don't catch the interrupt
|
||||
*/
|
||||
signal(SIGINT, SIG_IGN);
|
||||
#ifdef TDEBUG
|
||||
msg("Tape: %d; parent process: %d child process %d\n",
|
||||
tapeno+1, parentpid, childpid);
|
||||
#endif /* TDEBUG */
|
||||
while ((waitpid = wait(&status)) != childpid)
|
||||
msg("Parent %d waiting for child %d has another child %d return\n",
|
||||
parentpid, childpid, waitpid);
|
||||
if (status & 0xFF) {
|
||||
msg("Child %d returns LOB status %o\n",
|
||||
childpid, status&0xFF);
|
||||
}
|
||||
status = (status >> 8) & 0xFF;
|
||||
#ifdef TDEBUG
|
||||
switch(status) {
|
||||
case X_FINOK:
|
||||
msg("Child %d finishes X_FINOK\n", childpid);
|
||||
break;
|
||||
case X_ABORT:
|
||||
msg("Child %d finishes X_ABORT\n", childpid);
|
||||
break;
|
||||
case X_REWRITE:
|
||||
msg("Child %d finishes X_REWRITE\n", childpid);
|
||||
break;
|
||||
default:
|
||||
msg("Child %d finishes unknown %d\n",
|
||||
childpid, status);
|
||||
break;
|
||||
}
|
||||
#endif /* TDEBUG */
|
||||
switch(status) {
|
||||
case X_FINOK:
|
||||
Exit(X_FINOK);
|
||||
case X_ABORT:
|
||||
Exit(X_ABORT);
|
||||
case X_REWRITE:
|
||||
goto restore_check_point;
|
||||
default:
|
||||
msg("Bad return code from dump: %d\n", status);
|
||||
Exit(X_ABORT);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
} else { /* we are the child; just continue */
|
||||
#ifdef TDEBUG
|
||||
sleep(4); /* allow time for parent's message to get out */
|
||||
msg("Child on Tape %d has parent %d, my pid = %d\n",
|
||||
tapeno+1, parentpid, getpid());
|
||||
#endif /* TDEBUG */
|
||||
/*
|
||||
* If we have a name like "/dev/rmt0,/dev/rmt1",
|
||||
* use the name before the comma first, and save
|
||||
* the remaining names for subsequent volumes.
|
||||
*/
|
||||
tapeno++; /* current tape sequence */
|
||||
if (nexttape || strchr(tape, ',')) {
|
||||
if (nexttape && *nexttape)
|
||||
tape = nexttape;
|
||||
if ((p = strchr(tape, ',')) != NULL) {
|
||||
*p = '\0';
|
||||
nexttape = p + 1;
|
||||
} else
|
||||
nexttape = NULL;
|
||||
msg("Dumping volume %d on %s\n", tapeno, tape);
|
||||
}
|
||||
#ifdef RDUMP
|
||||
while ((tapefd = (host ? rmtopen(tape, 2) :
|
||||
pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
|
||||
#else
|
||||
while ((tapefd = (pipeout ? 1 :
|
||||
open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
|
||||
#endif
|
||||
{
|
||||
msg("Cannot open output \"%s\".\n", tape);
|
||||
if (!query("Do you want to retry the open?"))
|
||||
dumpabort(0);
|
||||
}
|
||||
|
||||
enslave(); /* Share open tape file descriptor with slaves */
|
||||
|
||||
asize = 0;
|
||||
blocksthisvol = 0;
|
||||
if (top)
|
||||
newtape++; /* new tape signal */
|
||||
spcl.c_count = slp->count;
|
||||
/*
|
||||
* measure firstrec in TP_BSIZE units since restore doesn't
|
||||
* know the correct ntrec value...
|
||||
*/
|
||||
spcl.c_firstrec = slp->firstrec;
|
||||
spcl.c_volume++;
|
||||
spcl.c_type = TS_TAPE;
|
||||
spcl.c_flags |= DR_NEWHEADER;
|
||||
writeheader((ino_t)slp->inode);
|
||||
spcl.c_flags &=~ DR_NEWHEADER;
|
||||
if (tapeno > 1)
|
||||
msg("Volume %d begins with blocks from inode %d\n",
|
||||
tapeno, slp->inode);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dumpabort(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (master != 0 && master != getpid())
|
||||
/* Signals master to call dumpabort */
|
||||
(void) kill(master, SIGTERM);
|
||||
else {
|
||||
killall();
|
||||
msg("The ENTIRE dump is aborted.\n");
|
||||
}
|
||||
#ifdef RDUMP
|
||||
rmtclose();
|
||||
#endif
|
||||
Exit(X_ABORT);
|
||||
}
|
||||
|
||||
__dead void
|
||||
Exit(status)
|
||||
int status;
|
||||
{
|
||||
|
||||
#ifdef TDEBUG
|
||||
msg("pid = %d exits with status %d\n", getpid(), status);
|
||||
#endif /* TDEBUG */
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
|
||||
*/
|
||||
void
|
||||
proceed(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (ready)
|
||||
longjmp(jmpbuf, 1);
|
||||
caught++;
|
||||
}
|
||||
|
||||
void
|
||||
enslave()
|
||||
{
|
||||
int cmd[2];
|
||||
register int i, j;
|
||||
|
||||
master = getpid();
|
||||
|
||||
signal(SIGTERM, dumpabort); /* Slave sends SIGTERM on dumpabort() */
|
||||
signal(SIGPIPE, sigpipe);
|
||||
signal(SIGUSR1, tperror); /* Slave sends SIGUSR1 on tape errors */
|
||||
signal(SIGUSR2, proceed); /* Slave sends SIGUSR2 to next slave */
|
||||
|
||||
for (i = 0; i < SLAVES; i++) {
|
||||
if (i == slp - &slaves[0]) {
|
||||
caught = 1;
|
||||
} else {
|
||||
caught = 0;
|
||||
}
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
|
||||
(slaves[i].pid = fork()) < 0)
|
||||
quit("too many slaves, %d (recompile smaller): %s\n",
|
||||
i, strerror(errno));
|
||||
|
||||
slaves[i].fd = cmd[1];
|
||||
slaves[i].sent = 0;
|
||||
if (slaves[i].pid == 0) { /* Slave starts up here */
|
||||
for (j = 0; j <= i; j++)
|
||||
(void) close(slaves[j].fd);
|
||||
signal(SIGINT, SIG_IGN); /* Master handles this */
|
||||
doslave(cmd[0], i);
|
||||
Exit(X_FINOK);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < SLAVES; i++)
|
||||
(void) atomic(write, slaves[i].fd,
|
||||
(char *) &slaves[(i + 1) % SLAVES].pid,
|
||||
sizeof slaves[0].pid);
|
||||
|
||||
master = 0;
|
||||
}
|
||||
|
||||
void
|
||||
killall()
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < SLAVES; i++)
|
||||
if (slaves[i].pid > 0)
|
||||
(void) kill(slaves[i].pid, SIGKILL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronization - each process has a lockfile, and shares file
|
||||
* descriptors to the following process's lockfile. When our write
|
||||
* completes, we release our lock on the following process's lock-
|
||||
* file, allowing the following process to lock it and proceed. We
|
||||
* get the lock back for the next cycle by swapping descriptors.
|
||||
*/
|
||||
static void
|
||||
doslave(cmd, slave_number)
|
||||
register int cmd;
|
||||
int slave_number;
|
||||
{
|
||||
register int nread;
|
||||
int nextslave, size, wrote, eot_count;
|
||||
|
||||
/*
|
||||
* Need our own seek pointer.
|
||||
*/
|
||||
(void) close(diskfd);
|
||||
if ((diskfd = open(disk, O_RDONLY)) < 0)
|
||||
quit("slave couldn't reopen disk: %s\n", strerror(errno));
|
||||
|
||||
/*
|
||||
* Need the pid of the next slave in the loop...
|
||||
*/
|
||||
if ((nread = atomic(read, cmd, (char *)&nextslave, sizeof nextslave))
|
||||
!= sizeof nextslave) {
|
||||
quit("master/slave protocol botched - didn't get pid of next slave.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get list of blocks to dump, read the blocks into tape buffer
|
||||
*/
|
||||
while ((nread = atomic(read, cmd, (char *)slp->req, reqsiz)) == reqsiz) {
|
||||
register struct req *p = slp->req;
|
||||
|
||||
for (trecno = 0; trecno < ntrec;
|
||||
trecno += p->count, p += p->count) {
|
||||
if (p->dblk) {
|
||||
bread(p->dblk, slp->tblock[trecno],
|
||||
p->count * TP_BSIZE);
|
||||
} else {
|
||||
if (p->count != 1 || atomic(read, cmd,
|
||||
(char *)slp->tblock[trecno],
|
||||
TP_BSIZE) != TP_BSIZE)
|
||||
quit("master/slave protocol botched.\n");
|
||||
}
|
||||
}
|
||||
if (setjmp(jmpbuf) == 0) {
|
||||
ready = 1;
|
||||
if (!caught)
|
||||
(void) pause();
|
||||
}
|
||||
ready = 0;
|
||||
caught = 0;
|
||||
|
||||
/* Try to write the data... */
|
||||
eot_count = 0;
|
||||
size = 0;
|
||||
|
||||
while (eot_count < 10 && size < writesize) {
|
||||
#ifdef RDUMP
|
||||
if (host)
|
||||
wrote = rmtwrite(slp->tblock[0]+size,
|
||||
writesize-size);
|
||||
else
|
||||
#endif
|
||||
wrote = write(tapefd, slp->tblock[0]+size,
|
||||
writesize-size);
|
||||
#ifdef WRITEDEBUG
|
||||
printf("slave %d wrote %d\n", slave_number, wrote);
|
||||
#endif
|
||||
if (wrote < 0)
|
||||
break;
|
||||
if (wrote == 0)
|
||||
eot_count++;
|
||||
size += wrote;
|
||||
}
|
||||
|
||||
#ifdef WRITEDEBUG
|
||||
if (size != writesize)
|
||||
printf("slave %d only wrote %d out of %d bytes and gave up.\n",
|
||||
slave_number, size, writesize);
|
||||
#endif
|
||||
|
||||
if (eot_count > 0)
|
||||
size = 0;
|
||||
|
||||
/*
|
||||
* fixme: Pyramids running OSx return ENOSPC
|
||||
* at EOT on 1/2 inch drives.
|
||||
*/
|
||||
if (size < 0) {
|
||||
(void) kill(master, SIGUSR1);
|
||||
for (;;)
|
||||
(void) sigpause(0);
|
||||
} else {
|
||||
/*
|
||||
* pass size of write back to master
|
||||
* (for EOT handling)
|
||||
*/
|
||||
(void) atomic(write, cmd, (char *)&size, sizeof size);
|
||||
}
|
||||
|
||||
/*
|
||||
* If partial write, don't want next slave to go.
|
||||
* Also jolts him awake.
|
||||
*/
|
||||
(void) kill(nextslave, SIGUSR2);
|
||||
}
|
||||
if (nread != 0)
|
||||
quit("error reading command pipe: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
* Since a read from a pipe may not return all we asked for,
|
||||
* or a write may not write all we ask if we get a signal,
|
||||
* loop until the count is satisfied (or error).
|
||||
*/
|
||||
static int
|
||||
atomic(func, fd, buf, count)
|
||||
int (*func)(), fd;
|
||||
char *buf;
|
||||
int count;
|
||||
{
|
||||
int got, need = count;
|
||||
|
||||
while ((got = (*func)(fd, buf, need)) > 0 && (need -= got) > 0)
|
||||
buf += got;
|
||||
return (got < 0 ? got : count - need);
|
||||
}
|
||||
607
sbin/dump/traverse.c
Normal file
607
sbin/dump/traverse.c
Normal file
|
|
@ -0,0 +1,607 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1988, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)traverse.c 8.7 (Berkeley) 6/15/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef sunos
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <ufs/fs.h>
|
||||
#include <ufs/fsdir.h>
|
||||
#include <ufs/inode.h>
|
||||
#else
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#endif
|
||||
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#ifdef __STDC__
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "dump.h"
|
||||
|
||||
#define HASDUMPEDFILE 0x1
|
||||
#define HASSUBDIRS 0x2
|
||||
|
||||
#ifdef FS_44INODEFMT
|
||||
typedef quad_t fsizeT;
|
||||
#else
|
||||
typedef long fsizeT;
|
||||
#endif
|
||||
|
||||
static int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size));
|
||||
static void dmpindir __P((ino_t ino, daddr_t blk, int level, fsizeT *size));
|
||||
static int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize));
|
||||
|
||||
/*
|
||||
* This is an estimation of the number of TP_BSIZE blocks in the file.
|
||||
* It estimates the number of blocks in files with holes by assuming
|
||||
* that all of the blocks accounted for by di_blocks are data blocks
|
||||
* (when some of the blocks are usually used for indirect pointers);
|
||||
* hence the estimate may be high.
|
||||
*/
|
||||
long
|
||||
blockest(dp)
|
||||
register struct dinode *dp;
|
||||
{
|
||||
long blkest, sizeest;
|
||||
|
||||
/*
|
||||
* dp->di_size is the size of the file in bytes.
|
||||
* dp->di_blocks stores the number of sectors actually in the file.
|
||||
* If there are more sectors than the size would indicate, this just
|
||||
* means that there are indirect blocks in the file or unused
|
||||
* sectors in the last file block; we can safely ignore these
|
||||
* (blkest = sizeest below).
|
||||
* If the file is bigger than the number of sectors would indicate,
|
||||
* then the file has holes in it. In this case we must use the
|
||||
* block count to estimate the number of data blocks used, but
|
||||
* we use the actual size for estimating the number of indirect
|
||||
* dump blocks (sizeest vs. blkest in the indirect block
|
||||
* calculation).
|
||||
*/
|
||||
blkest = howmany(dbtob(dp->di_blocks), TP_BSIZE);
|
||||
sizeest = howmany(dp->di_size, TP_BSIZE);
|
||||
if (blkest > sizeest)
|
||||
blkest = sizeest;
|
||||
if (dp->di_size > sblock->fs_bsize * NDADDR) {
|
||||
/* calculate the number of indirect blocks on the dump tape */
|
||||
blkest +=
|
||||
howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE,
|
||||
TP_NINDIR);
|
||||
}
|
||||
return (blkest + 1);
|
||||
}
|
||||
|
||||
/* Auxiliary macro to pick up files changed since previous dump. */
|
||||
#define CHANGEDSINCE(dp, t) \
|
||||
((dp)->di_mtime >= (t) || (dp)->di_ctime >= (t))
|
||||
|
||||
/* The WANTTODUMP macro decides whether a file should be dumped. */
|
||||
#ifdef UF_NODUMP
|
||||
#define WANTTODUMP(dp) \
|
||||
(CHANGEDSINCE(dp, spcl.c_ddate) && \
|
||||
(nonodump || ((dp)->di_flags & UF_NODUMP) != UF_NODUMP))
|
||||
#else
|
||||
#define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dump pass 1.
|
||||
*
|
||||
* Walk the inode list for a filesystem to find all allocated inodes
|
||||
* that have been modified since the previous dump time. Also, find all
|
||||
* the directories in the filesystem.
|
||||
*/
|
||||
int
|
||||
mapfiles(maxino, tapesize)
|
||||
ino_t maxino;
|
||||
long *tapesize;
|
||||
{
|
||||
register int mode;
|
||||
register ino_t ino;
|
||||
register struct dinode *dp;
|
||||
int anydirskipped = 0;
|
||||
|
||||
for (ino = ROOTINO; ino < maxino; ino++) {
|
||||
dp = getino(ino);
|
||||
if ((mode = (dp->di_mode & IFMT)) == 0)
|
||||
continue;
|
||||
SETINO(ino, usedinomap);
|
||||
if (mode == IFDIR)
|
||||
SETINO(ino, dumpdirmap);
|
||||
if (WANTTODUMP(dp)) {
|
||||
SETINO(ino, dumpinomap);
|
||||
if (mode != IFREG && mode != IFDIR && mode != IFLNK)
|
||||
*tapesize += 1;
|
||||
else
|
||||
*tapesize += blockest(dp);
|
||||
continue;
|
||||
}
|
||||
if (mode == IFDIR)
|
||||
anydirskipped = 1;
|
||||
}
|
||||
/*
|
||||
* Restore gets very upset if the root is not dumped,
|
||||
* so ensure that it always is dumped.
|
||||
*/
|
||||
SETINO(ROOTINO, dumpinomap);
|
||||
return (anydirskipped);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump pass 2.
|
||||
*
|
||||
* Scan each directory on the filesystem to see if it has any modified
|
||||
* files in it. If it does, and has not already been added to the dump
|
||||
* list (because it was itself modified), then add it. If a directory
|
||||
* has not been modified itself, contains no modified files and has no
|
||||
* subdirectories, then it can be deleted from the dump list and from
|
||||
* the list of directories. By deleting it from the list of directories,
|
||||
* its parent may now qualify for the same treatment on this or a later
|
||||
* pass using this algorithm.
|
||||
*/
|
||||
int
|
||||
mapdirs(maxino, tapesize)
|
||||
ino_t maxino;
|
||||
long *tapesize;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
register int i, isdir;
|
||||
register char *map;
|
||||
register ino_t ino;
|
||||
long filesize;
|
||||
int ret, change = 0;
|
||||
|
||||
isdir = 0; /* XXX just to get gcc to shut up */
|
||||
for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
|
||||
if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
|
||||
isdir = *map++;
|
||||
else
|
||||
isdir >>= 1;
|
||||
if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap))
|
||||
continue;
|
||||
dp = getino(ino);
|
||||
filesize = dp->di_size;
|
||||
for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
|
||||
if (dp->di_db[i] != 0)
|
||||
ret |= searchdir(ino, dp->di_db[i],
|
||||
(long)dblksize(sblock, dp, i),
|
||||
filesize);
|
||||
if (ret & HASDUMPEDFILE)
|
||||
filesize = 0;
|
||||
else
|
||||
filesize -= sblock->fs_bsize;
|
||||
}
|
||||
for (i = 0; filesize > 0 && i < NIADDR; i++) {
|
||||
if (dp->di_ib[i] == 0)
|
||||
continue;
|
||||
ret |= dirindir(ino, dp->di_ib[i], i, &filesize);
|
||||
}
|
||||
if (ret & HASDUMPEDFILE) {
|
||||
SETINO(ino, dumpinomap);
|
||||
*tapesize += blockest(dp);
|
||||
change = 1;
|
||||
continue;
|
||||
}
|
||||
if ((ret & HASSUBDIRS) == 0) {
|
||||
if (!TSTINO(ino, dumpinomap)) {
|
||||
CLRINO(ino, dumpdirmap);
|
||||
change = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (change);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read indirect blocks, and pass the data blocks to be searched
|
||||
* as directories. Quit as soon as any entry is found that will
|
||||
* require the directory to be dumped.
|
||||
*/
|
||||
static int
|
||||
dirindir(ino, blkno, ind_level, filesize)
|
||||
ino_t ino;
|
||||
daddr_t blkno;
|
||||
int ind_level;
|
||||
long *filesize;
|
||||
{
|
||||
int ret = 0;
|
||||
register int i;
|
||||
daddr_t idblk[MAXNINDIR];
|
||||
|
||||
bread(fsbtodb(sblock, blkno), (char *)idblk, (int)sblock->fs_bsize);
|
||||
if (ind_level <= 0) {
|
||||
for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
|
||||
blkno = idblk[i];
|
||||
if (blkno != 0)
|
||||
ret |= searchdir(ino, blkno, sblock->fs_bsize,
|
||||
*filesize);
|
||||
if (ret & HASDUMPEDFILE)
|
||||
*filesize = 0;
|
||||
else
|
||||
*filesize -= sblock->fs_bsize;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
ind_level--;
|
||||
for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
|
||||
blkno = idblk[i];
|
||||
if (blkno != 0)
|
||||
ret |= dirindir(ino, blkno, ind_level, filesize);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan a disk block containing directory information looking to see if
|
||||
* any of the entries are on the dump list and to see if the directory
|
||||
* contains any subdirectories.
|
||||
*/
|
||||
static int
|
||||
searchdir(ino, blkno, size, filesize)
|
||||
ino_t ino;
|
||||
daddr_t blkno;
|
||||
register long size;
|
||||
long filesize;
|
||||
{
|
||||
register struct direct *dp;
|
||||
register long loc, ret = 0;
|
||||
char dblk[MAXBSIZE];
|
||||
|
||||
bread(fsbtodb(sblock, blkno), dblk, (int)size);
|
||||
if (filesize < size)
|
||||
size = filesize;
|
||||
for (loc = 0; loc < size; ) {
|
||||
dp = (struct direct *)(dblk + loc);
|
||||
if (dp->d_reclen == 0) {
|
||||
msg("corrupted directory, inumber %d\n", ino);
|
||||
break;
|
||||
}
|
||||
loc += dp->d_reclen;
|
||||
if (dp->d_ino == 0)
|
||||
continue;
|
||||
if (dp->d_name[0] == '.') {
|
||||
if (dp->d_name[1] == '\0')
|
||||
continue;
|
||||
if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
|
||||
continue;
|
||||
}
|
||||
if (TSTINO(dp->d_ino, dumpinomap)) {
|
||||
ret |= HASDUMPEDFILE;
|
||||
if (ret & HASSUBDIRS)
|
||||
break;
|
||||
}
|
||||
if (TSTINO(dp->d_ino, dumpdirmap)) {
|
||||
ret |= HASSUBDIRS;
|
||||
if (ret & HASDUMPEDFILE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump passes 3 and 4.
|
||||
*
|
||||
* Dump the contents of an inode to tape.
|
||||
*/
|
||||
void
|
||||
dumpino(dp, ino)
|
||||
register struct dinode *dp;
|
||||
ino_t ino;
|
||||
{
|
||||
int ind_level, cnt;
|
||||
fsizeT size;
|
||||
char buf[TP_BSIZE];
|
||||
|
||||
if (newtape) {
|
||||
newtape = 0;
|
||||
dumpmap(dumpinomap, TS_BITS, ino);
|
||||
}
|
||||
CLRINO(ino, dumpinomap);
|
||||
spcl.c_dinode = *dp;
|
||||
spcl.c_type = TS_INODE;
|
||||
spcl.c_count = 0;
|
||||
switch (dp->di_mode & S_IFMT) {
|
||||
|
||||
case 0:
|
||||
/*
|
||||
* Freed inode.
|
||||
*/
|
||||
return;
|
||||
|
||||
case S_IFLNK:
|
||||
/*
|
||||
* Check for short symbolic link.
|
||||
*/
|
||||
#ifdef FS_44INODEFMT
|
||||
if (dp->di_size > 0 &&
|
||||
dp->di_size < sblock->fs_maxsymlinklen) {
|
||||
spcl.c_addr[0] = 1;
|
||||
spcl.c_count = 1;
|
||||
writeheader(ino);
|
||||
memmove(buf, dp->di_shortlink, (u_long)dp->di_size);
|
||||
buf[dp->di_size] = '\0';
|
||||
writerec(buf, 0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* fall through */
|
||||
|
||||
case S_IFDIR:
|
||||
case S_IFREG:
|
||||
if (dp->di_size > 0)
|
||||
break;
|
||||
/* fall through */
|
||||
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
writeheader(ino);
|
||||
return;
|
||||
|
||||
default:
|
||||
msg("Warning: undefined file type 0%o\n", dp->di_mode & IFMT);
|
||||
return;
|
||||
}
|
||||
if (dp->di_size > NDADDR * sblock->fs_bsize)
|
||||
cnt = NDADDR * sblock->fs_frag;
|
||||
else
|
||||
cnt = howmany(dp->di_size, sblock->fs_fsize);
|
||||
blksout(&dp->di_db[0], cnt, ino);
|
||||
if ((size = dp->di_size - NDADDR * sblock->fs_bsize) <= 0)
|
||||
return;
|
||||
for (ind_level = 0; ind_level < NIADDR; ind_level++) {
|
||||
dmpindir(ino, dp->di_ib[ind_level], ind_level, &size);
|
||||
if (size <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read indirect blocks, and pass the data blocks to be dumped.
|
||||
*/
|
||||
static void
|
||||
dmpindir(ino, blk, ind_level, size)
|
||||
ino_t ino;
|
||||
daddr_t blk;
|
||||
int ind_level;
|
||||
fsizeT *size;
|
||||
{
|
||||
int i, cnt;
|
||||
daddr_t idblk[MAXNINDIR];
|
||||
|
||||
if (blk != 0)
|
||||
bread(fsbtodb(sblock, blk), (char *)idblk, (int) sblock->fs_bsize);
|
||||
else
|
||||
memset(idblk, 0, (int)sblock->fs_bsize);
|
||||
if (ind_level <= 0) {
|
||||
if (*size < NINDIR(sblock) * sblock->fs_bsize)
|
||||
cnt = howmany(*size, sblock->fs_fsize);
|
||||
else
|
||||
cnt = NINDIR(sblock) * sblock->fs_frag;
|
||||
*size -= NINDIR(sblock) * sblock->fs_bsize;
|
||||
blksout(&idblk[0], cnt, ino);
|
||||
return;
|
||||
}
|
||||
ind_level--;
|
||||
for (i = 0; i < NINDIR(sblock); i++) {
|
||||
dmpindir(ino, idblk[i], ind_level, size);
|
||||
if (*size <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect up the data into tape record sized buffers and output them.
|
||||
*/
|
||||
void
|
||||
blksout(blkp, frags, ino)
|
||||
daddr_t *blkp;
|
||||
int frags;
|
||||
ino_t ino;
|
||||
{
|
||||
register daddr_t *bp;
|
||||
int i, j, count, blks, tbperdb;
|
||||
|
||||
blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
|
||||
tbperdb = sblock->fs_bsize >> tp_bshift;
|
||||
for (i = 0; i < blks; i += TP_NINDIR) {
|
||||
if (i + TP_NINDIR > blks)
|
||||
count = blks;
|
||||
else
|
||||
count = i + TP_NINDIR;
|
||||
for (j = i; j < count; j++)
|
||||
if (blkp[j / tbperdb] != 0)
|
||||
spcl.c_addr[j - i] = 1;
|
||||
else
|
||||
spcl.c_addr[j - i] = 0;
|
||||
spcl.c_count = count - i;
|
||||
writeheader(ino);
|
||||
bp = &blkp[i / tbperdb];
|
||||
for (j = i; j < count; j += tbperdb, bp++)
|
||||
if (*bp != 0)
|
||||
if (j + tbperdb <= count)
|
||||
dumpblock(*bp, (int)sblock->fs_bsize);
|
||||
else
|
||||
dumpblock(*bp, (count - j) * TP_BSIZE);
|
||||
spcl.c_type = TS_ADDR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump a map to the tape.
|
||||
*/
|
||||
void
|
||||
dumpmap(map, type, ino)
|
||||
char *map;
|
||||
int type;
|
||||
ino_t ino;
|
||||
{
|
||||
register int i;
|
||||
char *cp;
|
||||
|
||||
spcl.c_type = type;
|
||||
spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE);
|
||||
writeheader(ino);
|
||||
for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
|
||||
writerec(cp, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a header record to the dump tape.
|
||||
*/
|
||||
void
|
||||
writeheader(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
register long sum, cnt, *lp;
|
||||
|
||||
spcl.c_inumber = ino;
|
||||
spcl.c_magic = NFS_MAGIC;
|
||||
spcl.c_checksum = 0;
|
||||
lp = (long *)&spcl;
|
||||
sum = 0;
|
||||
cnt = sizeof(union u_spcl) / (4 * sizeof(long));
|
||||
while (--cnt >= 0) {
|
||||
sum += *lp++;
|
||||
sum += *lp++;
|
||||
sum += *lp++;
|
||||
sum += *lp++;
|
||||
}
|
||||
spcl.c_checksum = CHECKSUM - sum;
|
||||
writerec((char *)&spcl, 1);
|
||||
}
|
||||
|
||||
struct dinode *
|
||||
getino(inum)
|
||||
ino_t inum;
|
||||
{
|
||||
static daddr_t minino, maxino;
|
||||
static struct dinode inoblock[MAXINOPB];
|
||||
|
||||
curino = inum;
|
||||
if (inum >= minino && inum < maxino)
|
||||
return (&inoblock[inum - minino]);
|
||||
bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), (char *)inoblock,
|
||||
(int)sblock->fs_bsize);
|
||||
minino = inum - (inum % INOPB(sblock));
|
||||
maxino = minino + INOPB(sblock);
|
||||
return (&inoblock[inum - minino]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a chunk of data from the disk.
|
||||
* Try to recover from hard errors by reading in sector sized pieces.
|
||||
* Error recovery is attempted at most BREADEMAX times before seeking
|
||||
* consent from the operator to continue.
|
||||
*/
|
||||
int breaderrors = 0;
|
||||
#define BREADEMAX 32
|
||||
|
||||
void
|
||||
bread(blkno, buf, size)
|
||||
daddr_t blkno;
|
||||
char *buf;
|
||||
int size;
|
||||
{
|
||||
int cnt, i;
|
||||
extern int errno;
|
||||
|
||||
loop:
|
||||
if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) == -1)
|
||||
msg("bread: lseek fails\n");
|
||||
if ((cnt = read(diskfd, buf, size)) == size)
|
||||
return;
|
||||
if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
|
||||
/*
|
||||
* Trying to read the final fragment.
|
||||
*
|
||||
* NB - dump only works in TP_BSIZE blocks, hence
|
||||
* rounds `dev_bsize' fragments up to TP_BSIZE pieces.
|
||||
* It should be smarter about not actually trying to
|
||||
* read more than it can get, but for the time being
|
||||
* we punt and scale back the read only when it gets
|
||||
* us into trouble. (mkm 9/25/83)
|
||||
*/
|
||||
size -= dev_bsize;
|
||||
goto loop;
|
||||
}
|
||||
if (cnt == -1)
|
||||
msg("read error from %s: %s: [block %d]: count=%d\n",
|
||||
disk, strerror(errno), blkno, size);
|
||||
else
|
||||
msg("short read error from %s: [block %d]: count=%d, got=%d\n",
|
||||
disk, blkno, size, cnt);
|
||||
if (++breaderrors > BREADEMAX) {
|
||||
msg("More than %d block read errors from %d\n",
|
||||
BREADEMAX, disk);
|
||||
broadcast("DUMP IS AILING!\n");
|
||||
msg("This is an unrecoverable error.\n");
|
||||
if (!query("Do you want to attempt to continue?")){
|
||||
dumpabort(0);
|
||||
/*NOTREACHED*/
|
||||
} else
|
||||
breaderrors = 0;
|
||||
}
|
||||
/*
|
||||
* Zero buffer, then try to read each sector of buffer separately.
|
||||
*/
|
||||
memset(buf, 0, size);
|
||||
for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) {
|
||||
if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) == -1)
|
||||
msg("bread: lseek2 fails!\n");
|
||||
if ((cnt = read(diskfd, buf, (int)dev_bsize)) == dev_bsize)
|
||||
continue;
|
||||
if (cnt == -1) {
|
||||
msg("read error from %s: %s: [sector %d]: count=%d\n",
|
||||
disk, strerror(errno), blkno, dev_bsize);
|
||||
continue;
|
||||
}
|
||||
msg("short read error from %s: [sector %d]: count=%d, got=%d\n",
|
||||
disk, blkno, dev_bsize, cnt);
|
||||
}
|
||||
}
|
||||
106
sbin/dump/unctime.c
Normal file
106
sbin/dump/unctime.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)unctime.c 8.2 (Berkeley) 6/14/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#ifdef __STDC__
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifndef __P
|
||||
#include <sys/cdefs.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convert a ctime(3) format string into a system format date.
|
||||
* Return the date thus calculated.
|
||||
*
|
||||
* Return -1 if the string is not in ctime format.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Offsets into the ctime string to various parts.
|
||||
*/
|
||||
|
||||
#define E_MONTH 4
|
||||
#define E_DAY 8
|
||||
#define E_HOUR 11
|
||||
#define E_MINUTE 14
|
||||
#define E_SECOND 17
|
||||
#define E_YEAR 20
|
||||
|
||||
static int lookup __P((char *));
|
||||
|
||||
|
||||
time_t
|
||||
unctime(str)
|
||||
char *str;
|
||||
{
|
||||
struct tm then;
|
||||
char dbuf[26];
|
||||
|
||||
(void) strncpy(dbuf, str, sizeof(dbuf) - 1);
|
||||
dbuf[sizeof(dbuf) - 1] = '\0';
|
||||
dbuf[E_MONTH+3] = '\0';
|
||||
if ((then.tm_mon = lookup(&dbuf[E_MONTH])) < 0)
|
||||
return (-1);
|
||||
then.tm_mday = atoi(&dbuf[E_DAY]);
|
||||
then.tm_hour = atoi(&dbuf[E_HOUR]);
|
||||
then.tm_min = atoi(&dbuf[E_MINUTE]);
|
||||
then.tm_sec = atoi(&dbuf[E_SECOND]);
|
||||
then.tm_year = atoi(&dbuf[E_YEAR]) - 1900;
|
||||
then.tm_isdst = -1;
|
||||
return(mktime(&then));
|
||||
}
|
||||
|
||||
static char months[] =
|
||||
"JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
|
||||
static int
|
||||
lookup(str)
|
||||
char *str;
|
||||
{
|
||||
register char *cp, *cp2;
|
||||
|
||||
for (cp = months, cp2 = str; *cp != '\0'; cp += 3)
|
||||
if (strncmp(cp, cp2, 3) == 0)
|
||||
return((cp-months) / 3);
|
||||
return(-1);
|
||||
}
|
||||
322
sbin/dumpfs/dumpfs.c
Normal file
322
sbin/dumpfs/dumpfs.c
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1992, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dumpfs.c 8.5 (Berkeley) 4/29/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fstab.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
union {
|
||||
struct fs fs;
|
||||
char pad[MAXBSIZE];
|
||||
} fsun;
|
||||
#define afs fsun.fs
|
||||
|
||||
union {
|
||||
struct cg cg;
|
||||
char pad[MAXBSIZE];
|
||||
} cgun;
|
||||
#define acg cgun.cg
|
||||
|
||||
long dev_bsize = 1;
|
||||
|
||||
int dumpfs __P((char *));
|
||||
int dumpcg __P((char *, int, int));
|
||||
void pbits __P((void *, int));
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register struct fstab *fs;
|
||||
int ch, eval;
|
||||
|
||||
while ((ch = getopt(argc, argv, "")) != -1)
|
||||
switch(ch) {
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1)
|
||||
usage();
|
||||
|
||||
for (eval = 0; *argv; ++argv)
|
||||
if ((fs = getfsfile(*argv)) == NULL)
|
||||
eval |= dumpfs(*argv);
|
||||
else
|
||||
eval |= dumpfs(fs->fs_spec);
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
int
|
||||
dumpfs(name)
|
||||
char *name;
|
||||
{
|
||||
int fd, c, i, j, k, size;
|
||||
|
||||
if ((fd = open(name, O_RDONLY, 0)) < 0)
|
||||
goto err;
|
||||
if (lseek(fd, (off_t)SBOFF, SEEK_SET) == (off_t)-1)
|
||||
goto err;
|
||||
if (read(fd, &afs, SBSIZE) != SBSIZE)
|
||||
goto err;
|
||||
|
||||
if (afs.fs_magic != FS_MAGIC) {
|
||||
warnx("%s: superblock has bad magic number, skipped", name);
|
||||
(void)close(fd);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (afs.fs_postblformat == FS_42POSTBLFMT)
|
||||
afs.fs_nrpos = 8;
|
||||
dev_bsize = afs.fs_fsize / fsbtodb(&afs, 1);
|
||||
printf("magic\t%x\ttime\t%s", afs.fs_magic,
|
||||
ctime(&afs.fs_time));
|
||||
printf("cylgrp\t%s\tinodes\t%s\n",
|
||||
afs.fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic",
|
||||
afs.fs_inodefmt < FS_44INODEFMT ? "4.2/4.3BSD" : "4.4BSD");
|
||||
printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
|
||||
afs.fs_cstotal.cs_nbfree, afs.fs_cstotal.cs_ndir,
|
||||
afs.fs_cstotal.cs_nifree, afs.fs_cstotal.cs_nffree);
|
||||
printf("ncg\t%d\tncyl\t%d\tsize\t%d\tblocks\t%d\n",
|
||||
afs.fs_ncg, afs.fs_ncyl, afs.fs_size, afs.fs_dsize);
|
||||
printf("bsize\t%d\tshift\t%d\tmask\t0x%08x\n",
|
||||
afs.fs_bsize, afs.fs_bshift, afs.fs_bmask);
|
||||
printf("fsize\t%d\tshift\t%d\tmask\t0x%08x\n",
|
||||
afs.fs_fsize, afs.fs_fshift, afs.fs_fmask);
|
||||
printf("frag\t%d\tshift\t%d\tfsbtodb\t%d\n",
|
||||
afs.fs_frag, afs.fs_fragshift, afs.fs_fsbtodb);
|
||||
printf("cpg\t%d\tbpg\t%d\tfpg\t%d\tipg\t%d\n",
|
||||
afs.fs_cpg, afs.fs_fpg / afs.fs_frag, afs.fs_fpg, afs.fs_ipg);
|
||||
printf("minfree\t%d%%\toptim\t%s\tmaxcontig %d\tmaxbpg\t%d\n",
|
||||
afs.fs_minfree, afs.fs_optim == FS_OPTSPACE ? "space" : "time",
|
||||
afs.fs_maxcontig, afs.fs_maxbpg);
|
||||
printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
|
||||
afs.fs_rotdelay, afs.fs_headswitch, afs.fs_trkseek, afs.fs_rps);
|
||||
printf("ntrak\t%d\tnsect\t%d\tnpsect\t%d\tspc\t%d\n",
|
||||
afs.fs_ntrak, afs.fs_nsect, afs.fs_npsect, afs.fs_spc);
|
||||
printf("symlinklen %d\ttrackskew %d\tinterleave %d\tcontigsumsize %d\n",
|
||||
afs.fs_maxsymlinklen, afs.fs_trackskew, afs.fs_interleave,
|
||||
afs.fs_contigsumsize);
|
||||
printf("nindir\t%d\tinopb\t%d\tnspf\t%d\n",
|
||||
afs.fs_nindir, afs.fs_inopb, afs.fs_nspf);
|
||||
printf("sblkno\t%d\tcblkno\t%d\tiblkno\t%d\tdblkno\t%d\n",
|
||||
afs.fs_sblkno, afs.fs_cblkno, afs.fs_iblkno, afs.fs_dblkno);
|
||||
printf("sbsize\t%d\tcgsize\t%d\tcgoffset %d\tcgmask\t0x%08x\n",
|
||||
afs.fs_sbsize, afs.fs_cgsize, afs.fs_cgoffset, afs.fs_cgmask);
|
||||
printf("csaddr\t%d\tcssize\t%d\tshift\t%d\tmask\t0x%08x\n",
|
||||
afs.fs_csaddr, afs.fs_cssize, afs.fs_csshift, afs.fs_csmask);
|
||||
printf("cgrotor\t%d\tfmod\t%d\tronly\t%d\tclean\t%d\n",
|
||||
afs.fs_cgrotor, afs.fs_fmod, afs.fs_ronly, afs.fs_clean);
|
||||
if (afs.fs_cpc != 0)
|
||||
printf("blocks available in each of %d rotational positions",
|
||||
afs.fs_nrpos);
|
||||
else
|
||||
printf("(no rotational position table)\n");
|
||||
for (c = 0; c < afs.fs_cpc; c++) {
|
||||
printf("\ncylinder number %d:", c);
|
||||
for (i = 0; i < afs.fs_nrpos; i++) {
|
||||
if (fs_postbl(&afs, c)[i] == -1)
|
||||
continue;
|
||||
printf("\n position %d:\t", i);
|
||||
for (j = fs_postbl(&afs, c)[i], k = 1; ;
|
||||
j += fs_rotbl(&afs)[j], k++) {
|
||||
printf("%5d", j);
|
||||
if (k % 12 == 0)
|
||||
printf("\n\t\t");
|
||||
if (fs_rotbl(&afs)[j] == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t");
|
||||
for (i = 0, j = 0; i < afs.fs_cssize; i += afs.fs_bsize, j++) {
|
||||
size = afs.fs_cssize - i < afs.fs_bsize ?
|
||||
afs.fs_cssize - i : afs.fs_bsize;
|
||||
afs.fs_csp[j] = calloc(1, size);
|
||||
if (lseek(fd,
|
||||
(off_t)(fsbtodb(&afs, (afs.fs_csaddr + j * afs.fs_frag)) *
|
||||
dev_bsize), SEEK_SET) == (off_t)-1)
|
||||
goto err;
|
||||
if (read(fd, afs.fs_csp[j], size) != size)
|
||||
goto err;
|
||||
}
|
||||
for (i = 0; i < afs.fs_ncg; i++) {
|
||||
struct csum *cs = &afs.fs_cs(&afs, i);
|
||||
if (i && i % 4 == 0)
|
||||
printf("\n\t");
|
||||
printf("(%d,%d,%d,%d) ",
|
||||
cs->cs_nbfree, cs->cs_ndir, cs->cs_nifree, cs->cs_nffree);
|
||||
}
|
||||
printf("\n");
|
||||
if (afs.fs_ncyl % afs.fs_cpg) {
|
||||
printf("cylinders in last group %d\n",
|
||||
i = afs.fs_ncyl % afs.fs_cpg);
|
||||
printf("blocks in last group %d\n",
|
||||
i * afs.fs_spc / NSPB(&afs));
|
||||
}
|
||||
printf("\n");
|
||||
for (i = 0; i < afs.fs_ncg; i++)
|
||||
if (dumpcg(name, fd, i))
|
||||
goto err;
|
||||
(void)close(fd);
|
||||
return (0);
|
||||
|
||||
err: if (fd != -1)
|
||||
(void)close(fd);
|
||||
warn("%s", name);
|
||||
return (1);
|
||||
};
|
||||
|
||||
int
|
||||
dumpcg(name, fd, c)
|
||||
char *name;
|
||||
int fd, c;
|
||||
{
|
||||
off_t cur;
|
||||
int i, j;
|
||||
|
||||
printf("\ncg %d:\n", c);
|
||||
if ((cur = lseek(fd, (off_t)(fsbtodb(&afs, cgtod(&afs, c)) * dev_bsize),
|
||||
SEEK_SET)) == (off_t)-1)
|
||||
return (1);
|
||||
if (read(fd, &acg, afs.fs_bsize) != afs.fs_bsize) {
|
||||
warnx("%s: error reading cg", name);
|
||||
return (1);
|
||||
}
|
||||
printf("magic\t%x\ttell\t%qx\ttime\t%s",
|
||||
afs.fs_postblformat == FS_42POSTBLFMT ?
|
||||
((struct ocg *)&acg)->cg_magic : acg.cg_magic,
|
||||
cur, ctime(&acg.cg_time));
|
||||
printf("cgx\t%d\tncyl\t%d\tniblk\t%d\tndblk\t%d\n",
|
||||
acg.cg_cgx, acg.cg_ncyl, acg.cg_niblk, acg.cg_ndblk);
|
||||
printf("nbfree\t%d\tndir\t%d\tnifree\t%d\tnffree\t%d\n",
|
||||
acg.cg_cs.cs_nbfree, acg.cg_cs.cs_ndir,
|
||||
acg.cg_cs.cs_nifree, acg.cg_cs.cs_nffree);
|
||||
printf("rotor\t%d\tirotor\t%d\tfrotor\t%d\nfrsum",
|
||||
acg.cg_rotor, acg.cg_irotor, acg.cg_frotor);
|
||||
for (i = 1, j = 0; i < afs.fs_frag; i++) {
|
||||
printf("\t%d", acg.cg_frsum[i]);
|
||||
j += i * acg.cg_frsum[i];
|
||||
}
|
||||
printf("\nsum of frsum: %d", j);
|
||||
if (afs.fs_contigsumsize > 0) {
|
||||
for (i = 1; i < afs.fs_contigsumsize; i++) {
|
||||
if ((i - 1) % 8 == 0)
|
||||
printf("\nclusters %d-%d:", i,
|
||||
afs.fs_contigsumsize - 1 < i + 7 ?
|
||||
afs.fs_contigsumsize - 1 : i + 7);
|
||||
printf("\t%d", cg_clustersum(&acg)[i]);
|
||||
}
|
||||
printf("\nclusters size %d and over: %d\n",
|
||||
afs.fs_contigsumsize,
|
||||
cg_clustersum(&acg)[afs.fs_contigsumsize]);
|
||||
printf("clusters free:\t");
|
||||
pbits(cg_clustersfree(&acg), acg.cg_nclusterblks);
|
||||
} else
|
||||
printf("\n");
|
||||
printf("iused:\t");
|
||||
pbits(cg_inosused(&acg), afs.fs_ipg);
|
||||
printf("free:\t");
|
||||
pbits(cg_blksfree(&acg), afs.fs_fpg);
|
||||
printf("b:\n");
|
||||
for (i = 0; i < afs.fs_cpg; i++) {
|
||||
if (cg_blktot(&acg)[i] == 0)
|
||||
continue;
|
||||
printf(" c%d:\t(%d)\t", i, cg_blktot(&acg)[i]);
|
||||
for (j = 0; j < afs.fs_nrpos; j++) {
|
||||
if (afs.fs_cpc > 0 &&
|
||||
fs_postbl(&afs, i % afs.fs_cpc)[j] == -1)
|
||||
continue;
|
||||
printf(" %d", cg_blks(&afs, &acg, i)[j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
return (0);
|
||||
};
|
||||
|
||||
void
|
||||
pbits(vp, max)
|
||||
register void *vp;
|
||||
int max;
|
||||
{
|
||||
register int i;
|
||||
register char *p;
|
||||
int count, j;
|
||||
|
||||
for (count = i = 0, p = vp; i < max; i++)
|
||||
if (isset(p, i)) {
|
||||
if (count)
|
||||
printf(",%s", count % 6 ? " " : "\n\t");
|
||||
count++;
|
||||
printf("%d", i);
|
||||
j = i;
|
||||
while ((i+1)<max && isset(p, i+1))
|
||||
i++;
|
||||
if (i != j)
|
||||
printf("-%d", i);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage: dumpfs filesys | device\n");
|
||||
exit(1);
|
||||
}
|
||||
10
sbin/fsck/Makefile
Normal file
10
sbin/fsck/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# @(#)Makefile 8.2 (Berkeley) 4/27/95
|
||||
|
||||
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
|
||||
CFLAGS+=-W
|
||||
.PATH: ${.CURDIR}/../../sys/ufs/ffs
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
725
sbin/fsck/dir.c
Normal file
725
sbin/fsck/dir.c
Normal file
|
|
@ -0,0 +1,725 @@
|
|||
/*
|
||||
* 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.8 (Berkeley) 4/28/95";
|
||||
#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 <err.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, ".."
|
||||
};
|
||||
|
||||
static int chgino __P((struct inodesc *));
|
||||
static int dircheck __P((struct inodesc *, struct direct *));
|
||||
static int expanddir __P((struct dinode *dp, char *name));
|
||||
static void freedir __P((ino_t ino, ino_t parent));
|
||||
static struct direct *fsck_readdir __P((struct inodesc *));
|
||||
static struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size));
|
||||
static int lftempname __P((char *bufp, ino_t ino));
|
||||
static int mkentry __P((struct inodesc *));
|
||||
|
||||
/*
|
||||
* Propagate connected state through the tree.
|
||||
*/
|
||||
void
|
||||
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.
|
||||
*/
|
||||
int
|
||||
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)
|
||||
errx(EEXIT, "wrong type to dirscan %d", 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;
|
||||
memmove(dbuf, dp, (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);
|
||||
memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
|
||||
(size_t)dsize);
|
||||
dirty(bp);
|
||||
sbdirty();
|
||||
}
|
||||
if (n & STOP)
|
||||
return (n);
|
||||
}
|
||||
return (idesc->id_filesize > 0 ? KEEPON : STOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* get next entry in a directory.
|
||||
*/
|
||||
static 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;
|
||||
if (idesc->id_fix == IGNORE)
|
||||
return (0);
|
||||
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;
|
||||
if (idesc->id_fix == IGNORE)
|
||||
return (0);
|
||||
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.
|
||||
*/
|
||||
static int
|
||||
dircheck(idesc, dp)
|
||||
struct inodesc *idesc;
|
||||
register struct direct *dp;
|
||||
{
|
||||
register int size;
|
||||
register char *cp;
|
||||
u_char namlen, type;
|
||||
int spaceleft;
|
||||
|
||||
spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
|
||||
if (dp->d_ino >= maxino ||
|
||||
dp->d_reclen == 0 ||
|
||||
dp->d_reclen > spaceleft ||
|
||||
(dp->d_reclen & 0x3) != 0)
|
||||
return (0);
|
||||
if (dp->d_ino == 0)
|
||||
return (1);
|
||||
size = DIRSIZ(!newinofmt, dp);
|
||||
# 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_reclen < size ||
|
||||
idesc->id_filesize < size ||
|
||||
namlen > MAXNAMLEN ||
|
||||
type > 15)
|
||||
return (0);
|
||||
for (cp = dp->d_name, size = 0; size < namlen; size++)
|
||||
if (*cp == '\0' || (*cp++ == '/'))
|
||||
return (0);
|
||||
if (*cp != '\0')
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
direrror(ino, errmesg)
|
||||
ino_t ino;
|
||||
char *errmesg;
|
||||
{
|
||||
|
||||
fileerror(ino, ino, errmesg);
|
||||
}
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
adjust(idesc, lcnt)
|
||||
register struct inodesc *idesc;
|
||||
int 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
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 */
|
||||
dirp->d_reclen = newent.d_reclen;
|
||||
if (newinofmt)
|
||||
dirp->d_type = typemap[idesc->id_parent];
|
||||
else
|
||||
dirp->d_type = 0;
|
||||
dirp->d_namlen = newent.d_namlen;
|
||||
memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1);
|
||||
# if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
/*
|
||||
* If the entry was split, dirscan() will only reverse the byte
|
||||
* order of the original entry, and not the new one, before
|
||||
* writing it back out. So, we reverse the byte order here if
|
||||
* necessary.
|
||||
*/
|
||||
if (oldlen != 0 && !newinofmt && !doinglevel2) {
|
||||
u_char tmp;
|
||||
|
||||
tmp = dirp->d_namlen;
|
||||
dirp->d_namlen = dirp->d_type;
|
||||
dirp->d_type = tmp;
|
||||
}
|
||||
# endif
|
||||
return (ALTERED|STOP);
|
||||
}
|
||||
|
||||
static int
|
||||
chgino(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (memcmp(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);
|
||||
}
|
||||
|
||||
int
|
||||
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();
|
||||
|
||||
memset(&idesc, 0, 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.
|
||||
*/
|
||||
int
|
||||
changeino(dir, name, newnum)
|
||||
ino_t dir;
|
||||
char *name;
|
||||
ino_t newnum;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
|
||||
memset(&idesc, 0, 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
|
||||
*/
|
||||
int
|
||||
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);
|
||||
memset(&idesc, 0, 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
|
||||
*/
|
||||
static int
|
||||
expanddir(dp, name)
|
||||
register struct dinode *dp;
|
||||
char *name;
|
||||
{
|
||||
ufs_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;
|
||||
memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
|
||||
bp = getdirblk(newblk, sblock.fs_bsize);
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_bsize];
|
||||
cp += DIRBLKSIZ)
|
||||
memmove(cp, &emptydir, sizeof emptydir);
|
||||
dirty(bp);
|
||||
bp = getdirblk(dp->di_db[lastbn + 1],
|
||||
(long)dblksize(&sblock, dp, lastbn + 1));
|
||||
if (bp->b_errs)
|
||||
goto bad;
|
||||
memmove(bp->b_un.b_buf, &emptydir, 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
|
||||
*/
|
||||
ino_t
|
||||
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);
|
||||
}
|
||||
memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
|
||||
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
|
||||
cp < &bp->b_un.b_buf[sblock.fs_fsize];
|
||||
cp += DIRBLKSIZ)
|
||||
memmove(cp, &emptydir, 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
|
||||
*/
|
||||
static void
|
||||
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.
|
||||
*/
|
||||
static int
|
||||
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.
|
||||
*/
|
||||
static struct bufarea *
|
||||
getdirblk(blkno, size)
|
||||
ufs_daddr_t blkno;
|
||||
long size;
|
||||
{
|
||||
|
||||
if (pdirbp != 0)
|
||||
pdirbp->b_flags &= ~B_INUSE;
|
||||
pdirbp = getdatablk(blkno, size);
|
||||
return (pdirbp);
|
||||
}
|
||||
301
sbin/fsck/fsck.8
Normal file
301
sbin/fsck/fsck.8
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
.\" 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.4 (Berkeley) 5/9/95
|
||||
.\"
|
||||
.Dd May 9, 1995
|
||||
.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.
|
||||
In preening mode,
|
||||
filesystems that are marked clean are skipped.
|
||||
Filesystems are marked clean when they are unmounted,
|
||||
when they have been mounted read-only, or when
|
||||
.Nm fsck
|
||||
runs on them successfully.
|
||||
.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 four 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.
|
||||
.It 3
|
||||
If maxcontig is greater than one,
|
||||
build the free segment maps to aid in finding contiguous sets of blocks.
|
||||
If maxcontig is equal to one, delete any existing segment maps.
|
||||
.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
|
||||
278
sbin/fsck/fsck.h
Normal file
278
sbin/fsck/fsck.h
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* 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.4 (Berkeley) 5/9/95
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
||||
ufs_daddr_t b_bno;
|
||||
int b_size;
|
||||
int b_errs;
|
||||
int b_flags;
|
||||
union {
|
||||
char *b_buf; /* buffer space */
|
||||
ufs_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 */
|
||||
|
||||
#define dirty(bp) (bp)->b_dirty = 1
|
||||
#define initbarea(bp) \
|
||||
(bp)->b_dirty = 0; \
|
||||
(bp)->b_bno = (ufs_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 */
|
||||
ufs_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;
|
||||
ufs_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 */
|
||||
ufs_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 */
|
||||
|
||||
ufs_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 */
|
||||
u_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 */
|
||||
|
||||
ufs_daddr_t n_blks; /* number of blocks in use */
|
||||
ufs_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
|
||||
|
||||
#define EEXIT 8 /* Standard error exit. */
|
||||
|
||||
struct fstab;
|
||||
|
||||
void adjust __P((struct inodesc *, int lcnt));
|
||||
ufs_daddr_t allocblk __P((long frags));
|
||||
ino_t allocdir __P((ino_t parent, ino_t request, int mode));
|
||||
ino_t allocino __P((ino_t request, int type));
|
||||
void blkerror __P((ino_t ino, char *type, ufs_daddr_t blk));
|
||||
char *blockcheck __P((char *name));
|
||||
int bread __P((int fd, char *buf, ufs_daddr_t blk, long size));
|
||||
void bufinit __P((void));
|
||||
void bwrite __P((int fd, char *buf, ufs_daddr_t blk, long size));
|
||||
void cacheino __P((struct dinode *dp, ino_t inumber));
|
||||
void catch __P((int));
|
||||
void catchquit __P((int));
|
||||
int changeino __P((ino_t dir, char *name, ino_t newnum));
|
||||
int checkfstab __P((int preen, int maxrun,
|
||||
int (*docheck)(struct fstab *),
|
||||
int (*chkit)(char *, char *, long, int)));
|
||||
int chkrange __P((ufs_daddr_t blk, int cnt));
|
||||
void ckfini __P((int markclean));
|
||||
int ckinode __P((struct dinode *dp, struct inodesc *));
|
||||
void clri __P((struct inodesc *, char *type, int flag));
|
||||
void direrror __P((ino_t ino, char *errmesg));
|
||||
int dirscan __P((struct inodesc *));
|
||||
int dofix __P((struct inodesc *, char *msg));
|
||||
void ffs_clrblock __P((struct fs *, u_char *, ufs_daddr_t));
|
||||
void ffs_fragacct __P((struct fs *, int, int32_t [], int));
|
||||
int ffs_isblock __P((struct fs *, u_char *, ufs_daddr_t));
|
||||
void ffs_setblock __P((struct fs *, u_char *, ufs_daddr_t));
|
||||
void fileerror __P((ino_t cwd, ino_t ino, char *errmesg));
|
||||
int findino __P((struct inodesc *));
|
||||
int findname __P((struct inodesc *));
|
||||
void flush __P((int fd, struct bufarea *bp));
|
||||
void freeblk __P((ufs_daddr_t blkno, long frags));
|
||||
void freeino __P((ino_t ino));
|
||||
void freeinodebuf __P((void));
|
||||
int ftypeok __P((struct dinode *dp));
|
||||
void getblk __P((struct bufarea *bp, ufs_daddr_t blk, long size));
|
||||
struct bufarea *getdatablk __P((ufs_daddr_t blkno, long size));
|
||||
struct inoinfo *getinoinfo __P((ino_t inumber));
|
||||
struct dinode *getnextinode __P((ino_t inumber));
|
||||
void getpathname __P((char *namebuf, ino_t curdir, ino_t ino));
|
||||
struct dinode *ginode __P((ino_t inumber));
|
||||
void inocleanup __P((void));
|
||||
void inodirty __P((void));
|
||||
int linkup __P((ino_t orphan, ino_t parentdir));
|
||||
int makeentry __P((ino_t parent, ino_t ino, char *name));
|
||||
void panic __P((const char *fmt, ...));
|
||||
void pass1 __P((void));
|
||||
void pass1b __P((void));
|
||||
int pass1check __P((struct inodesc *));
|
||||
void pass2 __P((void));
|
||||
void pass3 __P((void));
|
||||
void pass4 __P((void));
|
||||
int pass4check __P((struct inodesc *));
|
||||
void pass5 __P((void));
|
||||
void pfatal __P((const char *fmt, ...));
|
||||
void pinode __P((ino_t ino));
|
||||
void propagate __P((void));
|
||||
void pwarn __P((const char *fmt, ...));
|
||||
int reply __P((char *question));
|
||||
void resetinodebuf __P((void));
|
||||
int setup __P((char *dev));
|
||||
void voidquit __P((int));
|
||||
562
sbin/fsck/inode.c
Normal file
562
sbin/fsck/inode.c
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
* 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.8 (Berkeley) 4/28/95";
|
||||
#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 <err.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
static ino_t startinum;
|
||||
|
||||
static int iblock __P((struct inodesc *, long ilevel, quad_t isize));
|
||||
|
||||
int
|
||||
ckinode(dp, idesc)
|
||||
struct dinode *dp;
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
ufs_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);
|
||||
}
|
||||
|
||||
static int
|
||||
iblock(idesc, ilevel, isize)
|
||||
struct inodesc *idesc;
|
||||
long ilevel;
|
||||
quad_t isize;
|
||||
{
|
||||
ufs_daddr_t *ap;
|
||||
ufs_daddr_t *aplim;
|
||||
struct bufarea *bp;
|
||||
int i, n, (*func)(), nif;
|
||||
quad_t sizepb;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
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.
|
||||
*/
|
||||
int
|
||||
chkrange(blk, cnt)
|
||||
ufs_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;
|
||||
{
|
||||
ufs_daddr_t iblk;
|
||||
|
||||
if (inumber < ROOTINO || inumber > maxino)
|
||||
errx(EEXIT, "bad inode number %d to ginode", 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;
|
||||
ufs_daddr_t dblk;
|
||||
static struct dinode *dp;
|
||||
|
||||
if (inumber != nextino++ || inumber > maxino)
|
||||
errx(EEXIT, "bad inode number %d to nextinode", 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++);
|
||||
}
|
||||
|
||||
void
|
||||
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)
|
||||
errx(EEXIT, "Cannot allocate space for inode buffer");
|
||||
while (nextino < ROOTINO)
|
||||
(void)getnextinode(nextino);
|
||||
}
|
||||
|
||||
void
|
||||
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.
|
||||
*/
|
||||
void
|
||||
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(ufs_daddr_t));
|
||||
if (inp == NULL)
|
||||
return;
|
||||
inpp = &inphead[inumber % numdirs];
|
||||
inp->i_nexthash = *inpp;
|
||||
*inpp = inp;
|
||||
if (inumber == ROOTINO)
|
||||
inp->i_parent = ROOTINO;
|
||||
else
|
||||
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(ufs_daddr_t);
|
||||
memmove(&inp->i_blks[0], &dp->di_db[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)
|
||||
errx(EEXIT, "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);
|
||||
}
|
||||
errx(EEXIT, "cannot find inode %d", inumber);
|
||||
return ((struct inoinfo *)0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up all the inode cache structure.
|
||||
*/
|
||||
void
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
inodirty()
|
||||
{
|
||||
|
||||
dirty(pbp);
|
||||
}
|
||||
|
||||
void
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
findname(idesc)
|
||||
struct inodesc *idesc;
|
||||
{
|
||||
register struct direct *dirp = idesc->id_dirp;
|
||||
|
||||
if (dirp->d_ino != idesc->id_parent)
|
||||
return (KEEPON);
|
||||
memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
|
||||
return (STOP|FOUND);
|
||||
}
|
||||
|
||||
int
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
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);
|
||||
printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
|
||||
}
|
||||
|
||||
void
|
||||
blkerror(ino, type, blk)
|
||||
ino_t ino;
|
||||
char *type;
|
||||
ufs_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:
|
||||
errx(EEXIT, "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);
|
||||
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
|
||||
*/
|
||||
void
|
||||
freeino(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
struct dinode *dp;
|
||||
|
||||
memset(&idesc, 0, 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--;
|
||||
}
|
||||
340
sbin/fsck/main.c
Normal file
340
sbin/fsck/main.c
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* 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.6 (Berkeley) 5/14/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/ufsmount.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <fstab.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
int returntosingle;
|
||||
|
||||
static int argtoi __P((int flag, char *req, char *str, int base));
|
||||
static int docheck __P((struct fstab *fsp));
|
||||
static int checkfilesys __P((char *filesys, char *mntpt, long auxdata,
|
||||
int child));
|
||||
void main __P((int argc, char *argv[]));
|
||||
|
||||
void
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch;
|
||||
int ret, maxrun = 0;
|
||||
extern char *optarg;
|
||||
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)
|
||||
errx(EEXIT, "bad mode to -m: %o", 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:
|
||||
errx(EEXIT, "%c option?", 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);
|
||||
}
|
||||
|
||||
static int
|
||||
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)
|
||||
errx(EEXIT, "-%c flag requires a %s", flag, req);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether a filesystem should be checked.
|
||||
*/
|
||||
static int
|
||||
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 */
|
||||
static int
|
||||
checkfilesys(filesys, mntpt, auxdata, child)
|
||||
char *filesys, *mntpt;
|
||||
long auxdata;
|
||||
int child;
|
||||
{
|
||||
ufs_daddr_t n_ffree, n_bfree;
|
||||
struct dups *dp;
|
||||
struct zlncnt *zlnp;
|
||||
int cylno, flags;
|
||||
|
||||
if (preen && child)
|
||||
(void)signal(SIGQUIT, voidquit);
|
||||
cdevname = filesys;
|
||||
if (debug && preen)
|
||||
pwarn("starting\n");
|
||||
switch (setup(filesys)) {
|
||||
case 0:
|
||||
if (preen)
|
||||
pfatal("CAN'T CHECK FILE SYSTEM.");
|
||||
/* fall through */
|
||||
case -1:
|
||||
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);
|
||||
}
|
||||
if (!hotroot) {
|
||||
ckfini(1);
|
||||
} else {
|
||||
struct statfs stfs_buf;
|
||||
/*
|
||||
* Check to see if root is mounted read-write.
|
||||
*/
|
||||
if (statfs("/", &stfs_buf) == 0)
|
||||
flags = stfs_buf.f_flags;
|
||||
else
|
||||
flags = 0;
|
||||
ckfini(flags & MNT_RDONLY);
|
||||
}
|
||||
free(blockmap);
|
||||
free(statemap);
|
||||
free((char *)lncntp);
|
||||
if (!fsmodified)
|
||||
return (0);
|
||||
if (!preen)
|
||||
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
|
||||
if (hotroot) {
|
||||
struct ufs_args args;
|
||||
int ret;
|
||||
/*
|
||||
* We modified the root. Do a mount update on
|
||||
* it, unless it is read-write, so we can continue.
|
||||
*/
|
||||
if (flags & MNT_RDONLY) {
|
||||
args.fspec = 0;
|
||||
args.export.ex_flags = 0;
|
||||
args.export.ex_root = 0;
|
||||
flags |= MNT_UPDATE | MNT_RELOAD;
|
||||
ret = mount("ufs", "/", flags, &args);
|
||||
if (ret == 0)
|
||||
return (0);
|
||||
}
|
||||
if (!preen)
|
||||
printf("\n***** REBOOT NOW *****\n");
|
||||
sync();
|
||||
return (4);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
320
sbin/fsck/pass1.c
Normal file
320
sbin/fsck/pass1.c
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* 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.6 (Berkeley) 4/28/95";
|
||||
#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 <err.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
static ufs_daddr_t badblk;
|
||||
static ufs_daddr_t dupblk;
|
||||
static void checkinode __P((ino_t inumber, struct inodesc *));
|
||||
|
||||
void
|
||||
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.
|
||||
*/
|
||||
memset(&idesc, 0, 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();
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
|
||||
dp = getnextinode(inumber);
|
||||
mode = dp->di_mode & IFMT;
|
||||
if (mode == 0) {
|
||||
if (memcmp(dp->di_db, zino.di_db,
|
||||
NDADDR * sizeof(ufs_daddr_t)) ||
|
||||
memcmp(dp->di_ib, zino.di_ib,
|
||||
NIADDR * sizeof(ufs_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 ||
|
||||
(mode == IFDIR && dp->di_size > MAXDIRSIZE)) {
|
||||
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) {
|
||||
symbuf = alloca(secsize);
|
||||
if (bread(fsreadfd, symbuf,
|
||||
fsbtodb(&sblock, dp->di_db[0]),
|
||||
(long)secsize) != 0)
|
||||
errx(EEXIT, "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);
|
||||
memmove(dp->di_shortlink, symbuf, (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(ufs_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)
|
||||
exit(EEXIT);
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pass1check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
int res = KEEPON;
|
||||
int anyout, nfrags;
|
||||
ufs_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)
|
||||
exit(EEXIT);
|
||||
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)
|
||||
exit(EEXIT);
|
||||
return (STOP);
|
||||
}
|
||||
new = (struct dups *)malloc(sizeof(struct dups));
|
||||
if (new == NULL) {
|
||||
pfatal("DUP TABLE OVERFLOW.");
|
||||
if (reply("CONTINUE") == 0)
|
||||
exit(EEXIT);
|
||||
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);
|
||||
}
|
||||
104
sbin/fsck/pass1b.c
Normal file
104
sbin/fsck/pass1b.c
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.4 (Berkeley) 4/28/95";
|
||||
#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"
|
||||
|
||||
static struct dups *duphead;
|
||||
static int pass1bcheck __P((struct inodesc *));
|
||||
|
||||
void
|
||||
pass1b()
|
||||
{
|
||||
register int c, i;
|
||||
register struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
ino_t inumber;
|
||||
|
||||
memset(&idesc, 0, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pass1bcheck(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
ufs_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);
|
||||
}
|
||||
467
sbin/fsck/pass2.c
Normal file
467
sbin/fsck/pass2.c
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* 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.9 (Berkeley) 4/28/95";
|
||||
#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 <err.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
#define MINDIRSIZE (sizeof (struct dirtemplate))
|
||||
|
||||
static int blksort __P((const void *, const void *));
|
||||
static int pass2check __P((struct inodesc *));
|
||||
|
||||
void
|
||||
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)
|
||||
exit(EEXIT);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
|
||||
break;
|
||||
|
||||
case DCLEAR:
|
||||
pfatal("DUPS/BAD IN ROOT INODE");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
|
||||
break;
|
||||
}
|
||||
if (reply("CONTINUE") == 0)
|
||||
exit(EEXIT);
|
||||
break;
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
pfatal("ROOT INODE NOT DIRECTORY");
|
||||
if (reply("REALLOCATE")) {
|
||||
freeino(ROOTINO);
|
||||
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
|
||||
errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
|
||||
break;
|
||||
}
|
||||
if (reply("FIX") == 0)
|
||||
exit(EEXIT);
|
||||
dp = ginode(ROOTINO);
|
||||
dp->di_mode &= ~IFMT;
|
||||
dp->di_mode |= IFDIR;
|
||||
inodirty();
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
errx(EEXIT, "BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
|
||||
}
|
||||
statemap[ROOTINO] = DFOUND;
|
||||
if (newinofmt) {
|
||||
statemap[WINO] = FSTATE;
|
||||
typemap[WINO] = DT_WHT;
|
||||
}
|
||||
/*
|
||||
* Sort the directory list into disk block order.
|
||||
*/
|
||||
qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
|
||||
/*
|
||||
* Check the integrity of each directory.
|
||||
*/
|
||||
memset(&curino, 0, 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;
|
||||
}
|
||||
}
|
||||
memset(&dino, 0, sizeof(struct dinode));
|
||||
dino.di_mode = IFDIR;
|
||||
dp->di_size = inp->i_isize;
|
||||
memmove(&dp->di_db[0], &inp->i_blks[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();
|
||||
}
|
||||
|
||||
static int
|
||||
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, ".");
|
||||
# if BYTE_ORDER == LITTLE_ENDIAN
|
||||
if (!newinofmt) {
|
||||
u_char tmp;
|
||||
|
||||
tmp = proto.d_type;
|
||||
proto.d_type = proto.d_namlen;
|
||||
proto.d_namlen = tmp;
|
||||
}
|
||||
# endif
|
||||
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;
|
||||
memmove(dirp, &proto, (size_t)entrysize);
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
} else {
|
||||
n = dirp->d_reclen - entrysize;
|
||||
proto.d_reclen = entrysize;
|
||||
memmove(dirp, &proto, (size_t)entrysize);
|
||||
idesc->id_entryno++;
|
||||
lncntp[dirp->d_ino]--;
|
||||
dirp = (struct direct *)((char *)(dirp) + entrysize);
|
||||
memset(dirp, 0, (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, "..");
|
||||
# if BYTE_ORDER == LITTLE_ENDIAN
|
||||
if (!newinofmt) {
|
||||
u_char tmp;
|
||||
|
||||
tmp = proto.d_type;
|
||||
proto.d_type = proto.d_namlen;
|
||||
proto.d_namlen = tmp;
|
||||
}
|
||||
# endif
|
||||
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);
|
||||
memset(dirp, 0, (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;
|
||||
memmove(dirp, &proto, (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 if (newinofmt &&
|
||||
((dirp->d_ino == WINO && dirp->d_type != DT_WHT) ||
|
||||
(dirp->d_ino != WINO && dirp->d_type == DT_WHT))) {
|
||||
fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
|
||||
dirp->d_ino = WINO;
|
||||
dirp->d_type = DT_WHT;
|
||||
if (reply("FIX") == 1)
|
||||
ret |= ALTERED;
|
||||
} 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:
|
||||
errx(EEXIT, "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.
|
||||
*/
|
||||
static int
|
||||
blksort(arg1, arg2)
|
||||
const void *arg1, *arg2;
|
||||
{
|
||||
|
||||
return ((*(struct inoinfo **)arg1)->i_blks[0] -
|
||||
(*(struct inoinfo **)arg2)->i_blks[0]);
|
||||
}
|
||||
74
sbin/fsck/pass3.c
Normal file
74
sbin/fsck/pass3.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.2 (Berkeley) 4/27/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
void
|
||||
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();
|
||||
}
|
||||
}
|
||||
136
sbin/fsck/pass4.c
Normal file
136
sbin/fsck/pass4.c
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.4 (Berkeley) 4/28/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
void
|
||||
pass4()
|
||||
{
|
||||
register ino_t inumber;
|
||||
register struct zlncnt *zlnp;
|
||||
struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
int n;
|
||||
|
||||
memset(&idesc, 0, 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:
|
||||
errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
|
||||
statemap[inumber], inumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pass4check(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
ufs_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);
|
||||
}
|
||||
328
sbin/fsck/pass5.c
Normal file
328
sbin/fsck/pass5.c
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* 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.9 (Berkeley) 4/28/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
void
|
||||
pass5()
|
||||
{
|
||||
int c, blk, frags, basesize, sumsize, mapsize, savednrpos;
|
||||
struct fs *fs = &sblock;
|
||||
struct cg *cg = &cgrp;
|
||||
ufs_daddr_t dbase, dmax;
|
||||
ufs_daddr_t d;
|
||||
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;
|
||||
|
||||
statemap[WINO] = USTATE;
|
||||
memset(newcg, 0, (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_firstfield);
|
||||
sumsize = &ocg->cg_iused[0] - (u_int8_t *)(&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_firstfield);
|
||||
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_firstfield);
|
||||
sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
|
||||
mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
sumsize = 0; /* keep lint happy */
|
||||
errx(EEXIT, "UNKNOWN ROTATIONAL TABLE FORMAT %d",
|
||||
fs->fs_postblformat);
|
||||
}
|
||||
memset(&idesc[0], 0, sizeof idesc);
|
||||
for (i = 0; i < 3; i++) {
|
||||
idesc[i].id_type = ADDR;
|
||||
if (doinglevel2)
|
||||
idesc[i].id_fix = FIX;
|
||||
}
|
||||
memset(&cstotal, 0, 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;
|
||||
memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum);
|
||||
memset(&cg_blktot(newcg)[0], 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;
|
||||
errx(EEXIT, "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) {
|
||||
int32_t *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 (memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
|
||||
dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
memmove(cs, &newcg->cg_cs, sizeof *cs);
|
||||
sbdirty();
|
||||
}
|
||||
if (doinglevel1) {
|
||||
memmove(cg, newcg, (size_t)fs->fs_cgsize);
|
||||
cgdirty();
|
||||
continue;
|
||||
}
|
||||
if (memcmp(cg_inosused(newcg),
|
||||
cg_inosused(cg), mapsize) != 0 &&
|
||||
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
|
||||
memmove(cg_inosused(cg), cg_inosused(newcg),
|
||||
(size_t)mapsize);
|
||||
cgdirty();
|
||||
}
|
||||
if ((memcmp(newcg, cg, basesize) != 0 ||
|
||||
memcmp(&cg_blktot(newcg)[0],
|
||||
&cg_blktot(cg)[0], sumsize) != 0) &&
|
||||
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
|
||||
memmove(cg, newcg, (size_t)basesize);
|
||||
memmove(&cg_blktot(cg)[0],
|
||||
&cg_blktot(newcg)[0], (size_t)sumsize);
|
||||
cgdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
fs->fs_nrpos = savednrpos;
|
||||
if (memcmp(&cstotal, &fs->fs_cstotal, sizeof *cs) != 0
|
||||
&& dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
memmove(&fs->fs_cstotal, &cstotal, sizeof *cs);
|
||||
fs->fs_ronly = 0;
|
||||
fs->fs_fmod = 0;
|
||||
sbdirty();
|
||||
}
|
||||
}
|
||||
370
sbin/fsck/preen.c
Normal file
370
sbin/fsck/preen.c
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* 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.5 (Berkeley) 4/28/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fstab.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
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;
|
||||
|
||||
static void addpart __P((char *name, char *fsname, long auxdata));
|
||||
static struct disk *finddisk __P((char *name));
|
||||
static char *rawname __P((char *name));
|
||||
static int startdisk __P((struct disk *dk,
|
||||
int (*checkit)(char *, char *, long, int)));
|
||||
static char *unrawname __P((char *name));
|
||||
|
||||
int
|
||||
checkfstab(preen, maxrun, docheck, chkit)
|
||||
int preen;
|
||||
int maxrun;
|
||||
int (*docheck)(struct fstab *);
|
||||
int (*chkit)(char *, char *, long, int);
|
||||
{
|
||||
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)) != 0) {
|
||||
if ((sumstatus = (*chkit)(name,
|
||||
fsp->fs_file, auxdata, 0)) != 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);
|
||||
}
|
||||
|
||||
static struct disk *
|
||||
finddisk(name)
|
||||
char *name;
|
||||
{
|
||||
register struct disk *dk, **dkp;
|
||||
register char *p;
|
||||
size_t len;
|
||||
|
||||
for (len = strlen(name), p = name + len - 1; p >= name; --p)
|
||||
if (isdigit(*p)) {
|
||||
len = p - name + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
startdisk(dk, checkit)
|
||||
register struct disk *dk;
|
||||
int (*checkit)(char *, char *, long, int);
|
||||
{
|
||||
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(origname)
|
||||
char *origname;
|
||||
{
|
||||
struct stat stslash, stblock, stchar;
|
||||
char *newname, *raw;
|
||||
int retried = 0;
|
||||
|
||||
hotroot = 0;
|
||||
if (stat("/", &stslash) < 0) {
|
||||
perror("/");
|
||||
printf("Can't stat root\n");
|
||||
return (origname);
|
||||
}
|
||||
newname = origname;
|
||||
retry:
|
||||
if (stat(newname, &stblock) < 0) {
|
||||
perror(newname);
|
||||
printf("Can't stat %s\n", newname);
|
||||
return (origname);
|
||||
}
|
||||
if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
|
||||
if (stslash.st_dev == stblock.st_rdev)
|
||||
hotroot++;
|
||||
raw = rawname(newname);
|
||||
if (stat(raw, &stchar) < 0) {
|
||||
perror(raw);
|
||||
printf("Can't stat %s\n", raw);
|
||||
return (origname);
|
||||
}
|
||||
if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
|
||||
return (raw);
|
||||
} else {
|
||||
printf("%s is not a character device\n", raw);
|
||||
return (origname);
|
||||
}
|
||||
} else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
|
||||
newname = unrawname(newname);
|
||||
retried++;
|
||||
goto retry;
|
||||
}
|
||||
/*
|
||||
* Not a block or character device, just return name and
|
||||
* let the user decide whether to use it.
|
||||
*/
|
||||
return (origname);
|
||||
}
|
||||
|
||||
static char *
|
||||
unrawname(name)
|
||||
char *name;
|
||||
{
|
||||
char *dp;
|
||||
struct stat stb;
|
||||
|
||||
if ((dp = strrchr(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);
|
||||
}
|
||||
|
||||
static char *
|
||||
rawname(name)
|
||||
char *name;
|
||||
{
|
||||
static char rawbuf[32];
|
||||
char *dp;
|
||||
|
||||
if ((dp = strrchr(name, '/')) == 0)
|
||||
return (0);
|
||||
*dp = 0;
|
||||
(void)strcpy(rawbuf, name);
|
||||
*dp = '/';
|
||||
(void)strcat(rawbuf, "/r");
|
||||
(void)strcat(rawbuf, &dp[1]);
|
||||
return (rawbuf);
|
||||
}
|
||||
500
sbin/fsck/setup.c
Normal file
500
sbin/fsck/setup.c
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* 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.10 (Berkeley) 5/9/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#define DKTYPENAMES
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
struct bufarea asblk;
|
||||
#define altsblock (*asblk.b_un.b_fs)
|
||||
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
|
||||
|
||||
static void badsb __P((int listerr, char *s));
|
||||
static int calcsb __P((char *dev, int devfd, struct fs *fs));
|
||||
static struct disklabel *getdisklabel __P((char *s, int fd));
|
||||
static int readsb __P((int listerr));
|
||||
|
||||
/*
|
||||
* Read in a superblock finding an alternate if necessary.
|
||||
* Return 1 if successful, 0 if unsuccessful, -1 if filesystem
|
||||
* is already clean (preen mode only).
|
||||
*/
|
||||
int
|
||||
setup(dev)
|
||||
char *dev;
|
||||
{
|
||||
long cg, size, asked, i, j;
|
||||
long skipclean, bmapsize;
|
||||
struct disklabel *lp;
|
||||
off_t sizepb;
|
||||
struct stat statb;
|
||||
struct fs proto;
|
||||
|
||||
havesb = 0;
|
||||
fswritefd = -1;
|
||||
skipclean = preen;
|
||||
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)
|
||||
errx(EEXIT, "cannot allocate space for superblock");
|
||||
if (lp = getdisklabel(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) {
|
||||
skipclean = 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);
|
||||
}
|
||||
if (skipclean && sblock.fs_clean) {
|
||||
pwarn("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
|
||||
return (-1);
|
||||
}
|
||||
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_firstfield);
|
||||
sblock.fs_rotbloff = &sblock.fs_space[0] -
|
||||
(u_char *)(&sblock.fs_firstfield);
|
||||
sblock.fs_cgsize =
|
||||
fragroundup(&sblock, CGSIZE(&sblock));
|
||||
sbdirty();
|
||||
dirty(&asblk);
|
||||
}
|
||||
if (asblk.b_dirty && !bflag) {
|
||||
memmove(&altsblock, &sblock, (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)
|
||||
exit(EEXIT);
|
||||
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(0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in the super block and its summary info.
|
||||
*/
|
||||
static int
|
||||
readsb(listerr)
|
||||
int listerr;
|
||||
{
|
||||
ufs_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_firstfield = sblock.fs_firstfield;
|
||||
altsblock.fs_unused_1 = sblock.fs_unused_1;
|
||||
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;
|
||||
memmove(altsblock.fs_csp, sblock.fs_csp, sizeof sblock.fs_csp);
|
||||
altsblock.fs_maxcluster = sblock.fs_maxcluster;
|
||||
memmove(altsblock.fs_fsmnt, sblock.fs_fsmnt, sizeof sblock.fs_fsmnt);
|
||||
memmove(altsblock.fs_sparecon,
|
||||
sblock.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_state = sblock.fs_state;
|
||||
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 (memcmp(&sblock, &altsblock, (int)sblock.fs_sbsize)) {
|
||||
if (debug) {
|
||||
long *nlp, *olp, *endlp;
|
||||
|
||||
printf("superblock mismatches\n");
|
||||
nlp = (long *)&altsblock;
|
||||
olp = (long *)&sblock;
|
||||
endlp = olp + (sblock.fs_sbsize / sizeof *olp);
|
||||
for ( ; olp < endlp; olp++, nlp++) {
|
||||
if (*olp == *nlp)
|
||||
continue;
|
||||
printf("offset %d, original %d, alternate %d\n",
|
||||
olp - (long *)&sblock, *olp, *nlp);
|
||||
}
|
||||
}
|
||||
badsb(listerr,
|
||||
"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
|
||||
return (0);
|
||||
}
|
||||
havesb = 1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
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!
|
||||
*/
|
||||
static int
|
||||
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 = strchr(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);
|
||||
}
|
||||
memset(fs, 0, 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);
|
||||
}
|
||||
|
||||
static 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));
|
||||
errx(EEXIT, "%s: can't read disk label", s);
|
||||
}
|
||||
return (&lab);
|
||||
}
|
||||
628
sbin/fsck/utilities.c
Normal file
628
sbin/fsck/utilities.c
Normal file
|
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
* 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.6 (Berkeley) 5/19/95";
|
||||
#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 <ctype.h>
|
||||
#include <err.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
long diskreads, totalreads; /* Disk cache statistics */
|
||||
|
||||
static void rwerror __P((char *mesg, ufs_daddr_t blk));
|
||||
|
||||
int
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
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.
|
||||
*/
|
||||
void
|
||||
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)
|
||||
errx(EEXIT, "cannot allocate buffer pool");
|
||||
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;
|
||||
errx(EEXIT, "cannot allocate buffer pool");
|
||||
}
|
||||
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)
|
||||
ufs_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)
|
||||
errx(EEXIT, "deadlocked buffer pool");
|
||||
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;
|
||||
ufs_daddr_t blk;
|
||||
long size;
|
||||
{
|
||||
ufs_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;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rwerror(mesg, blk)
|
||||
char *mesg;
|
||||
ufs_daddr_t blk;
|
||||
{
|
||||
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
pfatal("CANNOT %s: BLK %ld", mesg, blk);
|
||||
if (reply("CONTINUE") == 0)
|
||||
exit(EEXIT);
|
||||
}
|
||||
|
||||
void
|
||||
ckfini(markclean)
|
||||
int markclean;
|
||||
{
|
||||
register struct bufarea *bp, *nbp;
|
||||
int ofsmodified, 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)
|
||||
errx(EEXIT, "Panic: lost %d buffers", bufhead.b_size - cnt);
|
||||
pbp = pdirbp = (struct bufarea *)0;
|
||||
if (markclean && sblock.fs_clean == 0) {
|
||||
sblock.fs_clean = 1;
|
||||
sbdirty();
|
||||
ofsmodified = fsmodified;
|
||||
flush(fswritefd, &sblk);
|
||||
fsmodified = ofsmodified;
|
||||
if (!preen)
|
||||
printf("\n***** FILE SYSTEM MARKED CLEAN *****\n");
|
||||
}
|
||||
if (debug)
|
||||
printf("cache missed %ld of %ld (%d%%)\n", diskreads,
|
||||
totalreads, (int)(diskreads * 100 / totalreads));
|
||||
(void)close(fsreadfd);
|
||||
(void)close(fswritefd);
|
||||
}
|
||||
|
||||
int
|
||||
bread(fd, buf, blk, size)
|
||||
int fd;
|
||||
char *buf;
|
||||
ufs_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;
|
||||
memset(buf, 0, (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);
|
||||
}
|
||||
|
||||
void
|
||||
bwrite(fd, buf, blk, size)
|
||||
int fd;
|
||||
char *buf;
|
||||
ufs_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
|
||||
*/
|
||||
ufs_daddr_t
|
||||
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
|
||||
*/
|
||||
void
|
||||
freeblk(blkno, frags)
|
||||
ufs_daddr_t blkno;
|
||||
long frags;
|
||||
{
|
||||
struct inodesc idesc;
|
||||
|
||||
idesc.id_blkno = blkno;
|
||||
idesc.id_numfrags = frags;
|
||||
(void)pass4check(&idesc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a pathname
|
||||
*/
|
||||
void
|
||||
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;
|
||||
memset(&idesc, 0, 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;
|
||||
memmove(cp, namebuf, (size_t)len);
|
||||
*--cp = '/';
|
||||
if (cp < &namebuf[MAXNAMLEN])
|
||||
break;
|
||||
ino = idesc.id_number;
|
||||
}
|
||||
busy = 0;
|
||||
if (ino != ROOTINO)
|
||||
*--cp = '?';
|
||||
memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
|
||||
}
|
||||
|
||||
void
|
||||
catch(sig)
|
||||
int sig;
|
||||
{
|
||||
if (!doinglevel2)
|
||||
ckfini(0);
|
||||
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(sig)
|
||||
int sig;
|
||||
{
|
||||
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(sig)
|
||||
int sig;
|
||||
{
|
||||
|
||||
sleep(1);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_DFL);
|
||||
}
|
||||
|
||||
/*
|
||||
* determine whether an inode should be fixed.
|
||||
*/
|
||||
int
|
||||
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:
|
||||
errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* An unexpected inconsistency occured.
|
||||
* Die if preening, otherwise just print message and continue.
|
||||
*/
|
||||
void
|
||||
#if __STDC__
|
||||
pfatal(const char *fmt, ...)
|
||||
#else
|
||||
pfatal(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
if (!preen) {
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
||||
(void)fprintf(stderr, "%s: ", cdevname);
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
(void)fprintf(stderr,
|
||||
"\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
|
||||
cdevname);
|
||||
exit(EEXIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pwarn just prints a message when not preening,
|
||||
* or a warning (preceded by filename) when preening.
|
||||
*/
|
||||
void
|
||||
#if __STDC__
|
||||
pwarn(const char *fmt, ...)
|
||||
#else
|
||||
pwarn(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
if (preen)
|
||||
(void)fprintf(stderr, "%s: ", cdevname);
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stub for routines from kernel.
|
||||
*/
|
||||
void
|
||||
#if __STDC__
|
||||
panic(const char *fmt, ...)
|
||||
#else
|
||||
panic(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
pfatal("INTERNAL INCONSISTENCY:");
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(EEXIT);
|
||||
}
|
||||
129
sbin/mount_cd9660/mount_cd9660.c
Normal file
129
sbin/mount_cd9660/mount_cd9660.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 contributed to Berkeley
|
||||
* by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
|
||||
* Support code is derived from software contributed to Berkeley
|
||||
* by Atsushi Murai (amurai@spec.co.jp).
|
||||
*
|
||||
* 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_cd9660.c 8.7 (Berkeley) 5/1/95
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static 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_cd9660.c 8.7 (Berkeley) 5/1/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/../isofs/cd9660/cd9660_mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
MOPT_UPDATE,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
struct iso_args args;
|
||||
int ch, mntflags, opts;
|
||||
char *dev, *dir;
|
||||
|
||||
mntflags = opts = 0;
|
||||
while ((ch = getopt(argc, argv, "ego:r")) != EOF)
|
||||
switch (ch) {
|
||||
case 'e':
|
||||
opts |= ISOFSMNT_EXTATT;
|
||||
break;
|
||||
case 'g':
|
||||
opts |= ISOFSMNT_GENS;
|
||||
break;
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags, 0);
|
||||
break;
|
||||
case 'r':
|
||||
opts |= ISOFSMNT_NORRIP;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
dev = argv[0];
|
||||
dir = argv[1];
|
||||
|
||||
#define DEFAULT_ROOTUID -2
|
||||
/*
|
||||
* ISO 9660 filesystems are not writeable.
|
||||
*/
|
||||
mntflags |= MNT_RDONLY;
|
||||
args.export.ex_flags = MNT_EXRDONLY;
|
||||
args.fspec = dev;
|
||||
args.export.ex_root = DEFAULT_ROOTUID;
|
||||
args.flags = opts;
|
||||
|
||||
if (mount("cd9660", dir, mntflags, &args) < 0)
|
||||
err(1, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_cd9660 [-egrt] [-o options] special node\n");
|
||||
exit(1);
|
||||
}
|
||||
100
sbin/mount_fdesc/mount_fdesc.c
Normal file
100
sbin/mount_fdesc/mount_fdesc.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1992 Jan-Simon Pendry
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed 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_fdesc.c 8.3 (Berkeley) 4/26/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch, mntflags;
|
||||
|
||||
mntflags = 0;
|
||||
while ((ch = getopt(argc, argv, "o:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags, 0);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
if (mount("fdesc", argv[1], mntflags, NULL))
|
||||
err(1, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_fdesc [-o options] fdesc mount_point\n");
|
||||
exit(1);
|
||||
}
|
||||
100
sbin/mount_kernfs/mount_kernfs.c
Normal file
100
sbin/mount_kernfs/mount_kernfs.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1992 Jan-Simon Pendry
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed 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_kernfs.c 8.3 (Berkeley) 5/4/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch, mntflags;
|
||||
|
||||
mntflags = 0;
|
||||
while ((ch = getopt(argc, argv, "o:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags, 0);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
if (mount("kernfs", argv[1], mntflags, NULL))
|
||||
err(1, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_kernfs [-o options] /kern mount_point\n");
|
||||
exit(1);
|
||||
}
|
||||
148
sbin/mount_lfs/mount_lfs.c
Normal file
148
sbin/mount_lfs/mount_lfs.c
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*-
|
||||
* 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_lfs.c 8.4 (Berkeley) 4/26/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <ufs/ufs/ufsmount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
MOPT_UPDATE,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void usage __P((void));
|
||||
void invoke_cleaner __P((char *));
|
||||
|
||||
int short_rds, cleaner_debug;
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
struct ufs_args args;
|
||||
int ch, mntflags, noclean;
|
||||
char *fs_name, *options;
|
||||
|
||||
options = NULL;
|
||||
mntflags = noclean = 0;
|
||||
while ((ch = getopt(argc, argv, "dno:s")) != EOF)
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
cleaner_debug = 1;
|
||||
break;
|
||||
case 'n':
|
||||
noclean = 1;
|
||||
break;
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags, 0);
|
||||
break;
|
||||
case 's':
|
||||
short_rds = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
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("lfs", fs_name, mntflags, &args))
|
||||
err(1, NULL);
|
||||
|
||||
if (!noclean)
|
||||
invoke_cleaner(fs_name);
|
||||
/* NOTREACHED */
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
invoke_cleaner(name)
|
||||
char *name;
|
||||
{
|
||||
char *args[6], **ap = args;
|
||||
|
||||
/* Build the argument list. */
|
||||
*ap++ = _PATH_LFS_CLEANERD;
|
||||
if (short_rds)
|
||||
*ap++ = "-s";
|
||||
if (cleaner_debug)
|
||||
*ap++ = "-d";
|
||||
*ap++ = name;
|
||||
*ap = NULL;
|
||||
|
||||
execv(args[0], args);
|
||||
err(1, "exec %s", _PATH_LFS_CLEANERD);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_lfs [-dns] [-o options] special node\n");
|
||||
exit(1);
|
||||
}
|
||||
241
sbin/mount_nfs/mount_nfs.8
Normal file
241
sbin/mount_nfs/mount_nfs.8
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
.\" Copyright (c) 1992, 1993, 1994, 1995
|
||||
.\" 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_nfs.8 8.3 (Berkeley) 3/29/95
|
||||
.\"
|
||||
.Dd March 29, 1995
|
||||
.Dt MOUNT_NFS 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_nfs
|
||||
.Nd mount nfs file systems
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount_nfs
|
||||
.Op Fl 3KPTUbcdilqs
|
||||
.Op Fl D Ar deadthresh
|
||||
.Op Fl I Ar readdirsize
|
||||
.Op Fl L Ar leaseterm
|
||||
.Op Fl R Ar retrycnt
|
||||
.Op Fl a Ar maxreadahead
|
||||
.Op Fl g Ar maxgroups
|
||||
.Op Fl m Ar realm
|
||||
.Op Fl o Ar options
|
||||
.Op Fl r Ar readsize
|
||||
.Op Fl t Ar timeout
|
||||
.Op Fl w Ar writesize
|
||||
.Op Fl x Ar retrans
|
||||
.Ar rhost:path node
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount_nfs
|
||||
command
|
||||
calls the
|
||||
.Xr mount 2
|
||||
system call to prepare and graft a remote nfs file system (rhost:path)
|
||||
on to the file system tree at the point
|
||||
.Ar node.
|
||||
This command is normally executed by
|
||||
.Xr mount 8 .
|
||||
It implements the mount protocol as described in RFC 1094, Appendix A and
|
||||
.%T "NFS: Network File System Version 3 Protocol Specification" ,
|
||||
Appendix I.
|
||||
.Pp
|
||||
The options are:
|
||||
.Bl -tag -width indent
|
||||
.It Fl 3
|
||||
Use the NFS Version 3 protocol (Version 2 is the default).
|
||||
.It Fl D
|
||||
Used with NQNFS to set the
|
||||
.Dq "dead server threshold"
|
||||
to the specified number of round trip timeout intervals.
|
||||
After a
|
||||
.Dq "dead server threshold"
|
||||
of retransmit timeouts,
|
||||
cached data for the unresponsive server is assumed to still be valid.
|
||||
Values may be set in the range of 1 - 9, with 9 referring to an
|
||||
.Dq "infinite dead threshold"
|
||||
(i.e. never assume cached data still valid).
|
||||
This option is not generally recommended and is really an experimental
|
||||
feature.
|
||||
.It Fl I
|
||||
Set the readdir read size to the specified value. The value should normally
|
||||
be a multiple of DIRBLKSIZ that is <= the read size for the mount.
|
||||
.It Fl K
|
||||
Pass Kerberos authenticators to the server for client-to-server
|
||||
user-credential mapping.
|
||||
This requires that the kernel be built with the NFSKERB option.
|
||||
(Refer to the INTERNET-DRAFT titled
|
||||
.%T "Authentication Mechanisms for ONC RPC" ,
|
||||
for more information.)
|
||||
.It Fl L
|
||||
Used with NQNFS to set the lease term to the specified number of seconds.
|
||||
Only use this argument for mounts with a large round trip delay.
|
||||
Values are normally in the 10-30 second range.
|
||||
.It Fl P
|
||||
Use a reserved socket port number.
|
||||
This is useful for mounting servers that require clients to use a
|
||||
reserved port number on the mistaken belief that this makes NFS
|
||||
more secure. (For the rare case where the client has a trusted root account
|
||||
but untrusworthy users and the network cables are in secure areas this does
|
||||
help, but for normal desktop clients this does not apply.)
|
||||
.It Fl R
|
||||
Set the retry count for doing the mount to the specified value.
|
||||
.It Fl T
|
||||
Use TCP transport instead of UDP.
|
||||
This is recommended for servers that are not on the same LAN cable as
|
||||
the client.
|
||||
(NB: This is NOT supported by most non-BSD servers.)
|
||||
.It Fl U
|
||||
Force the mount protocol to use UDP transport, even for TCP NFS mounts.
|
||||
(Necessary for some old BSD servers.)
|
||||
.It Fl a
|
||||
Set the read-ahead count to the specified value.
|
||||
This may be in the range of 0 - 4, and determines how many blocks
|
||||
will be read ahead when a large file is being read sequentially.
|
||||
Trying a value greater than 1 for this is suggested for
|
||||
mounts with a large bandwidth * delay product.
|
||||
.It Fl b
|
||||
If an initial attempt to contact the server fails, fork off a child to keep
|
||||
trying the mount in the background.
|
||||
Useful for
|
||||
.Xr fstab 5 ,
|
||||
where the filesystem mount is not critical to multiuser operation.
|
||||
.It Fl c
|
||||
For UDP mount points, do not do a
|
||||
.Xr connect 2 .
|
||||
This must be used for servers that do not reply to requests from the
|
||||
standard NFS port number 2049.
|
||||
.It Fl d
|
||||
Turn off the dynamic retransmit timeout estimator.
|
||||
This may be useful for UDP mounts that exhibit high retry rates,
|
||||
since it is possible that the dynamically estimated timeout interval is too
|
||||
short.
|
||||
.It Fl g
|
||||
Set the maximum size of the group list for the credentials to the
|
||||
specified value.
|
||||
This should be used for mounts on old servers that cannot handle a
|
||||
group list size of 16, as specified in RFC 1057.
|
||||
Try 8, if users in a lot of groups cannot get response from the mount
|
||||
point.
|
||||
.It Fl i
|
||||
Make the mount interruptible, which implies that file system calls that
|
||||
are delayed due to an unresponsive server will fail with EINTR when a
|
||||
termination signal is posted for the process.
|
||||
.It Fl l
|
||||
Used with NQNFS and NFSV3 to specify that the \fBReaddirPlus\fR RPC should
|
||||
be used.
|
||||
This option reduces RPC traffic for cases such as
|
||||
.Dq "ls -l" ,
|
||||
but tends to flood the attribute and name caches with prefetched entries.
|
||||
Try this option and see whether performance improves or degrades. Probably
|
||||
most useful for client to server network interconnects with a large bandwidth
|
||||
times delay product.
|
||||
.It Fl m
|
||||
Set the Kerberos realm to the string argument.
|
||||
Used with the
|
||||
.Fl K
|
||||
option for mounts to other realms.
|
||||
.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 q
|
||||
Use the leasing extensions to the NFS Version 3 protocol
|
||||
to maintain cache consistency.
|
||||
This protocol version 2 revision to Not Quite Nfs (NQNFS)
|
||||
is only supported by this updated release of NFS code.
|
||||
It is not backwards compatible with the version 1 NQNFS protocol
|
||||
that was part of the first release of 4.4BSD-Lite.
|
||||
To interoperate with a first release 4.4BSD-Lite NFS system you will have to
|
||||
avoid this option until you have had an oppurtunity to upgrade the NFS code
|
||||
to release 2 of 4.4BSD-Lite on all your systems.
|
||||
.It Fl r
|
||||
Set the read data size to the specified value.
|
||||
It should normally be a power of 2 greater than or equal to 1024.
|
||||
This should be used for UDP mounts when the
|
||||
.Dq "fragments dropped due to timeout"
|
||||
value is getting large while actively using a mount point.
|
||||
(Use
|
||||
.Xr netstat 1
|
||||
with the
|
||||
.Fl s
|
||||
option to see what the
|
||||
.Dq "fragments dropped due to timeout"
|
||||
value is.)
|
||||
See the
|
||||
.Fl w
|
||||
option as well.
|
||||
.It Fl s
|
||||
A soft mount, which implies that file system calls will fail
|
||||
after \fBRetry\fR round trip timeout intervals.
|
||||
.It Fl t
|
||||
Set the initial retransmit timeout to the specified value.
|
||||
May be useful for fine tuning UDP mounts over internetworks
|
||||
with high packet loss rates or an overloaded server.
|
||||
Try increasing the interval if
|
||||
.Xr nfsstat 1
|
||||
shows high retransmit rates while the file system is active or reducing the
|
||||
value if there is a low retransmit rate but long response delay observed.
|
||||
(Normally, the -d option should be specified when using this option to manually
|
||||
tune the timeout
|
||||
interval.)
|
||||
.It Fl w
|
||||
Set the write data size to the specified value.
|
||||
Ditto the comments w.r.t. the
|
||||
.Fl r
|
||||
option, but using the
|
||||
.Dq "fragments dropped due to timeout"
|
||||
value on the server instead of the client.
|
||||
Note that both the
|
||||
.Fl r
|
||||
and
|
||||
.Fl w
|
||||
options should only be used as a last ditch effort at improving performance
|
||||
when mounting servers that do not support TCP mounts.
|
||||
.It Fl x
|
||||
Set the retransmit timeout count for soft mounts to the specified value.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr mount 2 ,
|
||||
.Xr unmount 2 ,
|
||||
.Xr fstab 5 ,
|
||||
.Xr mount 8
|
||||
.Sh BUGS
|
||||
Due to the way that Sun RPC is implemented on top of UDP (unreliable datagram)
|
||||
transport, tuning such mounts is really a black art that can only be expected
|
||||
to have limited success.
|
||||
For clients mounting servers that are not on the same
|
||||
LAN cable or that tend to be overloaded,
|
||||
TCP transport is strongly recommended,
|
||||
but unfortunately this is restricted to mostly 4.4BSD servers.
|
||||
745
sbin/mount_nfs/mount_nfs.c
Normal file
745
sbin/mount_nfs/mount_nfs.c
Normal file
|
|
@ -0,0 +1,745 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 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) 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpc/pmap_clnt.h>
|
||||
#include <rpc/pmap_prot.h>
|
||||
|
||||
#ifdef ISO
|
||||
#include <netiso/iso.h>
|
||||
#endif
|
||||
|
||||
#ifdef NFSKERB
|
||||
#include <kerberosIV/des.h>
|
||||
#include <kerberosIV/krb.h>
|
||||
#endif
|
||||
|
||||
#include <nfs/rpcv2.h>
|
||||
#include <nfs/nfsproto.h>
|
||||
#define KERNEL
|
||||
#include <nfs/nfs.h>
|
||||
#undef KERNEL
|
||||
#include <nfs/nqnfs.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
#define ALTF_BG 0x1
|
||||
#define ALTF_NOCONN 0x2
|
||||
#define ALTF_DUMBTIMR 0x4
|
||||
#define ALTF_INTR 0x8
|
||||
#define ALTF_KERB 0x10
|
||||
#define ALTF_NFSV3 0x20
|
||||
#define ALTF_RDIRPLUS 0x40
|
||||
#define ALTF_MNTUDP 0x80
|
||||
#define ALTF_RESVPORT 0x100
|
||||
#define ALTF_SEQPACKET 0x200
|
||||
#define ALTF_NQNFS 0x400
|
||||
#define ALTF_SOFT 0x800
|
||||
#define ALTF_TCP 0x1000
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
MOPT_FORCE,
|
||||
MOPT_UPDATE,
|
||||
{ "bg", 0, ALTF_BG, 1 },
|
||||
{ "conn", 1, ALTF_NOCONN, 1 },
|
||||
{ "dumbtimer", 0, ALTF_DUMBTIMR, 1 },
|
||||
{ "intr", 0, ALTF_INTR, 1 },
|
||||
#ifdef NFSKERB
|
||||
{ "kerb", 0, ALTF_KERB, 1 },
|
||||
#endif
|
||||
{ "nfsv3", 0, ALTF_NFSV3, 1 },
|
||||
{ "rdirplus", 0, ALTF_RDIRPLUS, 1 },
|
||||
{ "mntudp", 0, ALTF_MNTUDP, 1 },
|
||||
{ "resvport", 0, ALTF_RESVPORT, 1 },
|
||||
#ifdef ISO
|
||||
{ "seqpacket", 0, ALTF_SEQPACKET, 1 },
|
||||
#endif
|
||||
{ "nqnfs", 0, ALTF_NQNFS, 1 },
|
||||
{ "soft", 0, ALTF_SOFT, 1 },
|
||||
{ "tcp", 0, ALTF_TCP, 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
struct nfs_args nfsdefargs = {
|
||||
NFS_ARGSVERSION,
|
||||
(struct sockaddr *)0,
|
||||
sizeof (struct sockaddr_in),
|
||||
SOCK_DGRAM,
|
||||
0,
|
||||
(u_char *)0,
|
||||
0,
|
||||
0,
|
||||
NFS_WSIZE,
|
||||
NFS_RSIZE,
|
||||
NFS_READDIRSIZE,
|
||||
10,
|
||||
NFS_RETRANS,
|
||||
NFS_MAXGRPS,
|
||||
NFS_DEFRAHEAD,
|
||||
NQ_DEFLEASE,
|
||||
NQ_DEADTHRESH,
|
||||
(char *)0,
|
||||
};
|
||||
|
||||
struct nfhret {
|
||||
u_long stat;
|
||||
long vers;
|
||||
long auth;
|
||||
long fhsize;
|
||||
u_char nfh[NFSX_V3FHMAX];
|
||||
};
|
||||
#define DEF_RETRY 10000
|
||||
#define BGRND 1
|
||||
#define ISBGRND 2
|
||||
int retrycnt = DEF_RETRY;
|
||||
int opflags = 0;
|
||||
int nfsproto = IPPROTO_UDP;
|
||||
int mnttcp_ok = 1;
|
||||
|
||||
#ifdef NFSKERB
|
||||
char inst[INST_SZ];
|
||||
char realm[REALM_SZ];
|
||||
struct {
|
||||
u_long kind;
|
||||
KTEXT_ST kt;
|
||||
} ktick;
|
||||
struct nfsrpc_nickverf kverf;
|
||||
struct nfsrpc_fullblock kin, kout;
|
||||
NFSKERBKEY_T kivec;
|
||||
CREDENTIALS kcr;
|
||||
struct timeval ktv;
|
||||
NFSKERBKEYSCHED_T kerb_keysched;
|
||||
#endif
|
||||
|
||||
int getnfsargs __P((char *, struct nfs_args *));
|
||||
#ifdef ISO
|
||||
struct iso_addr *iso_addr __P((const char *));
|
||||
#endif
|
||||
void set_rpc_maxgrouplist __P((int));
|
||||
__dead void usage __P((void));
|
||||
int xdr_dir __P((XDR *, char *));
|
||||
int xdr_fh __P((XDR *, struct nfhret *));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register int c;
|
||||
register struct nfs_args *nfsargsp;
|
||||
struct nfs_args nfsargs;
|
||||
struct nfsd_cargs ncd;
|
||||
int mntflags, altflags, i, nfssvc_flag, num;
|
||||
char *name, *p, *spec;
|
||||
int error = 0;
|
||||
#ifdef NFSKERB
|
||||
uid_t last_ruid;
|
||||
|
||||
last_ruid = -1;
|
||||
(void)strcpy(realm, KRB_REALM);
|
||||
if (sizeof (struct nfsrpc_nickverf) != RPCX_NICKVERF ||
|
||||
sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK ||
|
||||
((char *)&ktick.kt) - ((char *)&ktick) != NFSX_UNSIGNED ||
|
||||
((char *)ktick.kt.dat) - ((char *)&ktick) != 2 * NFSX_UNSIGNED)
|
||||
fprintf(stderr, "Yikes! NFSKERB structs not packed!!\n");
|
||||
#endif /* NFSKERB */
|
||||
retrycnt = DEF_RETRY;
|
||||
|
||||
mntflags = 0;
|
||||
altflags = 0;
|
||||
nfsargs = nfsdefargs;
|
||||
nfsargsp = &nfsargs;
|
||||
while ((c = getopt(argc, argv,
|
||||
"3a:bcdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:U")) != EOF)
|
||||
switch (c) {
|
||||
case '3':
|
||||
nfsargsp->flags |= NFSMNT_NFSV3;
|
||||
break;
|
||||
case 'a':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num < 0)
|
||||
errx(1, "illegal -a value -- %s", optarg);
|
||||
nfsargsp->readahead = num;
|
||||
nfsargsp->flags |= NFSMNT_READAHEAD;
|
||||
break;
|
||||
case 'b':
|
||||
opflags |= BGRND;
|
||||
break;
|
||||
case 'c':
|
||||
nfsargsp->flags |= NFSMNT_NOCONN;
|
||||
break;
|
||||
case 'D':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -D value -- %s", optarg);
|
||||
nfsargsp->deadthresh = num;
|
||||
nfsargsp->flags |= NFSMNT_DEADTHRESH;
|
||||
break;
|
||||
case 'd':
|
||||
nfsargsp->flags |= NFSMNT_DUMBTIMR;
|
||||
break;
|
||||
case 'g':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -g value -- %s", optarg);
|
||||
set_rpc_maxgrouplist(num);
|
||||
nfsargsp->maxgrouplist = num;
|
||||
nfsargsp->flags |= NFSMNT_MAXGRPS;
|
||||
break;
|
||||
case 'I':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -I value -- %s", optarg);
|
||||
nfsargsp->readdirsize = num;
|
||||
nfsargsp->flags |= NFSMNT_READDIRSIZE;
|
||||
break;
|
||||
case 'i':
|
||||
nfsargsp->flags |= NFSMNT_INT;
|
||||
break;
|
||||
#ifdef NFSKERB
|
||||
case 'K':
|
||||
nfsargsp->flags |= NFSMNT_KERB;
|
||||
break;
|
||||
#endif
|
||||
case 'L':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num < 2)
|
||||
errx(1, "illegal -L value -- %s", optarg);
|
||||
nfsargsp->leaseterm = num;
|
||||
nfsargsp->flags |= NFSMNT_LEASETERM;
|
||||
break;
|
||||
case 'l':
|
||||
nfsargsp->flags |= NFSMNT_RDIRPLUS;
|
||||
break;
|
||||
#ifdef NFSKERB
|
||||
case 'm':
|
||||
(void)strncpy(realm, optarg, REALM_SZ - 1);
|
||||
realm[REALM_SZ - 1] = '\0';
|
||||
break;
|
||||
#endif
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags, &altflags);
|
||||
if(altflags & ALTF_BG)
|
||||
opflags |= BGRND;
|
||||
if(altflags & ALTF_NOCONN)
|
||||
nfsargsp->flags |= NFSMNT_NOCONN;
|
||||
if(altflags & ALTF_DUMBTIMR)
|
||||
nfsargsp->flags |= NFSMNT_DUMBTIMR;
|
||||
if(altflags & ALTF_INTR)
|
||||
nfsargsp->flags |= NFSMNT_INT;
|
||||
#ifdef NFSKERB
|
||||
if(altflags & ALTF_KERB)
|
||||
nfsargsp->flags |= NFSMNT_KERB;
|
||||
#endif
|
||||
if(altflags & ALTF_NFSV3)
|
||||
nfsargsp->flags |= NFSMNT_NFSV3;
|
||||
if(altflags & ALTF_RDIRPLUS)
|
||||
nfsargsp->flags |= NFSMNT_RDIRPLUS;
|
||||
if(altflags & ALTF_MNTUDP)
|
||||
mnttcp_ok = 0;
|
||||
if(altflags & ALTF_RESVPORT)
|
||||
nfsargsp->flags |= NFSMNT_RESVPORT;
|
||||
#ifdef ISO
|
||||
if(altflags & ALTF_SEQPACKET)
|
||||
nfsargsp->sotype = SOCK_SEQPACKET;
|
||||
#endif
|
||||
if(altflags & ALTF_NQNFS)
|
||||
nfsargsp->flags |= (NFSMNT_NQNFS|NFSMNT_NFSV3);
|
||||
if(altflags & ALTF_SOFT)
|
||||
nfsargsp->flags |= NFSMNT_SOFT;
|
||||
if(altflags & ALTF_TCP) {
|
||||
nfsargsp->sotype = SOCK_STREAM;
|
||||
nfsproto = IPPROTO_TCP;
|
||||
}
|
||||
altflags = 0;
|
||||
break;
|
||||
case 'P':
|
||||
nfsargsp->flags |= NFSMNT_RESVPORT;
|
||||
break;
|
||||
#ifdef ISO
|
||||
case 'p':
|
||||
nfsargsp->sotype = SOCK_SEQPACKET;
|
||||
break;
|
||||
#endif
|
||||
case 'q':
|
||||
nfsargsp->flags |= (NFSMNT_NQNFS | NFSMNT_NFSV3);
|
||||
break;
|
||||
case 'R':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -R value -- %s", optarg);
|
||||
retrycnt = num;
|
||||
break;
|
||||
case 'r':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -r value -- %s", optarg);
|
||||
nfsargsp->rsize = num;
|
||||
nfsargsp->flags |= NFSMNT_RSIZE;
|
||||
break;
|
||||
case 's':
|
||||
nfsargsp->flags |= NFSMNT_SOFT;
|
||||
break;
|
||||
case 'T':
|
||||
nfsargsp->sotype = SOCK_STREAM;
|
||||
nfsproto = IPPROTO_TCP;
|
||||
break;
|
||||
case 't':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -t value -- %s", optarg);
|
||||
nfsargsp->timeo = num;
|
||||
nfsargsp->flags |= NFSMNT_TIMEO;
|
||||
break;
|
||||
case 'w':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -w value -- %s", optarg);
|
||||
nfsargsp->wsize = num;
|
||||
nfsargsp->flags |= NFSMNT_WSIZE;
|
||||
break;
|
||||
case 'x':
|
||||
num = strtol(optarg, &p, 10);
|
||||
if (*p || num <= 0)
|
||||
errx(1, "illegal -x value -- %s", optarg);
|
||||
nfsargsp->retrans = num;
|
||||
nfsargsp->flags |= NFSMNT_RETRANS;
|
||||
break;
|
||||
case 'U':
|
||||
mnttcp_ok = 0;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
spec = *argv++;
|
||||
name = *argv;
|
||||
|
||||
if (!getnfsargs(spec, nfsargsp))
|
||||
exit(1);
|
||||
|
||||
if (mount("nfs", name, mntflags, nfsargsp))
|
||||
err(1, "%s", name);
|
||||
if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
|
||||
if ((opflags & ISBGRND) == 0) {
|
||||
if (i = fork()) {
|
||||
if (i == -1)
|
||||
err(1, "nqnfs 1");
|
||||
exit(0);
|
||||
}
|
||||
(void) setsid();
|
||||
(void) close(STDIN_FILENO);
|
||||
(void) close(STDOUT_FILENO);
|
||||
(void) close(STDERR_FILENO);
|
||||
(void) chdir("/");
|
||||
}
|
||||
openlog("mount_nfs:", LOG_PID, LOG_DAEMON);
|
||||
nfssvc_flag = NFSSVC_MNTD;
|
||||
ncd.ncd_dirp = name;
|
||||
while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) {
|
||||
if (errno != ENEEDAUTH) {
|
||||
syslog(LOG_ERR, "nfssvc err %m");
|
||||
continue;
|
||||
}
|
||||
nfssvc_flag =
|
||||
NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
|
||||
#ifdef NFSKERB
|
||||
/*
|
||||
* Set up as ncd_authuid for the kerberos call.
|
||||
* Must set ruid to ncd_authuid and reset the
|
||||
* ticket name iff ncd_authuid is not the same
|
||||
* as last time, so that the right ticket file
|
||||
* is found.
|
||||
* Get the Kerberos credential structure so that
|
||||
* we have the seesion key and get a ticket for
|
||||
* this uid.
|
||||
* For more info see the IETF Draft "Authentication
|
||||
* in ONC RPC".
|
||||
*/
|
||||
if (ncd.ncd_authuid != last_ruid) {
|
||||
krb_set_tkt_string("");
|
||||
last_ruid = ncd.ncd_authuid;
|
||||
}
|
||||
setreuid(ncd.ncd_authuid, 0);
|
||||
kret = krb_get_cred(NFS_KERBSRV, inst, realm, &kcr);
|
||||
if (kret == RET_NOTKT) {
|
||||
kret = get_ad_tkt(NFS_KERBSRV, inst, realm,
|
||||
DEFAULT_TKT_LIFE);
|
||||
if (kret == KSUCCESS)
|
||||
kret = krb_get_cred(NFS_KERBSRV, inst, realm,
|
||||
&kcr);
|
||||
}
|
||||
if (kret == KSUCCESS)
|
||||
kret = krb_mk_req(&ktick.kt, NFS_KERBSRV, inst,
|
||||
realm, 0);
|
||||
|
||||
/*
|
||||
* Fill in the AKN_FULLNAME authenticator and verfier.
|
||||
* Along with the Kerberos ticket, we need to build
|
||||
* the timestamp verifier and encrypt it in CBC mode.
|
||||
*/
|
||||
if (kret == KSUCCESS &&
|
||||
ktick.kt.length <= (RPCAUTH_MAXSIZ-3*NFSX_UNSIGNED)
|
||||
&& gettimeofday(&ktv, (struct timezone *)0) == 0) {
|
||||
ncd.ncd_authtype = RPCAUTH_KERB4;
|
||||
ncd.ncd_authstr = (u_char *)&ktick;
|
||||
ncd.ncd_authlen = nfsm_rndup(ktick.kt.length) +
|
||||
3 * NFSX_UNSIGNED;
|
||||
ncd.ncd_verfstr = (u_char *)&kverf;
|
||||
ncd.ncd_verflen = sizeof (kverf);
|
||||
memmove(ncd.ncd_key, kcr.session,
|
||||
sizeof (kcr.session));
|
||||
kin.t1 = htonl(ktv.tv_sec);
|
||||
kin.t2 = htonl(ktv.tv_usec);
|
||||
kin.w1 = htonl(NFS_KERBTTL);
|
||||
kin.w2 = htonl(NFS_KERBTTL - 1);
|
||||
bzero((caddr_t)kivec, sizeof (kivec));
|
||||
|
||||
/*
|
||||
* Encrypt kin in CBC mode using the session
|
||||
* key in kcr.
|
||||
*/
|
||||
XXX
|
||||
|
||||
/*
|
||||
* Finally, fill the timestamp verifier into the
|
||||
* authenticator and verifier.
|
||||
*/
|
||||
ktick.kind = htonl(RPCAKN_FULLNAME);
|
||||
kverf.kind = htonl(RPCAKN_FULLNAME);
|
||||
NFS_KERBW1(ktick.kt) = kout.w1;
|
||||
ktick.kt.length = htonl(ktick.kt.length);
|
||||
kverf.verf.t1 = kout.t1;
|
||||
kverf.verf.t2 = kout.t2;
|
||||
kverf.verf.w2 = kout.w2;
|
||||
nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
|
||||
}
|
||||
setreuid(0, 0);
|
||||
#endif /* NFSKERB */
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
getnfsargs(spec, nfsargsp)
|
||||
char *spec;
|
||||
struct nfs_args *nfsargsp;
|
||||
{
|
||||
register CLIENT *clp;
|
||||
struct hostent *hp;
|
||||
static struct sockaddr_in saddr;
|
||||
#ifdef ISO
|
||||
static struct sockaddr_iso isoaddr;
|
||||
struct iso_addr *isop;
|
||||
int isoflag = 0;
|
||||
#endif
|
||||
struct timeval pertry, try;
|
||||
enum clnt_stat clnt_stat;
|
||||
int so = RPC_ANYSOCK, i, nfsvers, mntvers;
|
||||
char *hostp, *delimp;
|
||||
#ifdef NFSKERB
|
||||
char *cp;
|
||||
#endif
|
||||
u_short tport;
|
||||
static struct nfhret nfhret;
|
||||
static char nam[MNAMELEN + 1];
|
||||
|
||||
strncpy(nam, spec, MNAMELEN);
|
||||
nam[MNAMELEN] = '\0';
|
||||
if ((delimp = strchr(spec, '@')) != NULL) {
|
||||
hostp = delimp + 1;
|
||||
} else if ((delimp = strchr(spec, ':')) != NULL) {
|
||||
hostp = spec;
|
||||
spec = delimp + 1;
|
||||
} else {
|
||||
warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
|
||||
return (0);
|
||||
}
|
||||
*delimp = '\0';
|
||||
/*
|
||||
* DUMB!! Until the mount protocol works on iso transport, we must
|
||||
* supply both an iso and an inet address for the host.
|
||||
*/
|
||||
#ifdef ISO
|
||||
if (!strncmp(hostp, "iso=", 4)) {
|
||||
u_short isoport;
|
||||
|
||||
hostp += 4;
|
||||
isoflag++;
|
||||
if ((delimp = strchr(hostp, '+')) == NULL) {
|
||||
warnx("no iso+inet address");
|
||||
return (0);
|
||||
}
|
||||
*delimp = '\0';
|
||||
if ((isop = iso_addr(hostp)) == NULL) {
|
||||
warnx("bad ISO address");
|
||||
return (0);
|
||||
}
|
||||
memset(&isoaddr, 0, sizeof (isoaddr));
|
||||
memmove(&isoaddr.siso_addr, isop, sizeof (struct iso_addr));
|
||||
isoaddr.siso_len = sizeof (isoaddr);
|
||||
isoaddr.siso_family = AF_ISO;
|
||||
isoaddr.siso_tlen = 2;
|
||||
isoport = htons(NFS_PORT);
|
||||
memmove(TSEL(&isoaddr), &isoport, isoaddr.siso_tlen);
|
||||
hostp = delimp + 1;
|
||||
}
|
||||
#endif /* ISO */
|
||||
|
||||
/*
|
||||
* Handle an internet host address and reverse resolve it if
|
||||
* doing Kerberos.
|
||||
*/
|
||||
if (isdigit(*hostp)) {
|
||||
if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
|
||||
warnx("bad net address %s", hostp);
|
||||
return (0);
|
||||
}
|
||||
} else if ((hp = gethostbyname(hostp)) != NULL)
|
||||
memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
|
||||
else {
|
||||
warnx("can't get net id for host");
|
||||
return (0);
|
||||
}
|
||||
#ifdef NFSKERB
|
||||
if ((nfsargsp->flags & NFSMNT_KERB)) {
|
||||
if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
|
||||
sizeof (u_long), AF_INET)) == (struct hostent *)0) {
|
||||
warnx("can't reverse resolve net address");
|
||||
return (0);
|
||||
}
|
||||
memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
|
||||
strncpy(inst, hp->h_name, INST_SZ);
|
||||
inst[INST_SZ - 1] = '\0';
|
||||
if (cp = strchr(inst, '.'))
|
||||
*cp = '\0';
|
||||
}
|
||||
#endif /* NFSKERB */
|
||||
|
||||
if (nfsargsp->flags & NFSMNT_NFSV3) {
|
||||
nfsvers = 3;
|
||||
mntvers = 3;
|
||||
} else {
|
||||
nfsvers = 2;
|
||||
mntvers = 1;
|
||||
}
|
||||
nfhret.stat = EACCES; /* Mark not yet successful */
|
||||
while (retrycnt > 0) {
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(PMAPPORT);
|
||||
if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
|
||||
nfsvers, nfsproto)) == 0) {
|
||||
if ((opflags & ISBGRND) == 0)
|
||||
clnt_pcreateerror("NFS Portmap");
|
||||
} else {
|
||||
saddr.sin_port = 0;
|
||||
pertry.tv_sec = 10;
|
||||
pertry.tv_usec = 0;
|
||||
if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM)
|
||||
clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers,
|
||||
&so, 0, 0);
|
||||
else
|
||||
clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers,
|
||||
pertry, &so);
|
||||
if (clp == NULL) {
|
||||
if ((opflags & ISBGRND) == 0)
|
||||
clnt_pcreateerror("Cannot MNT PRC");
|
||||
} else {
|
||||
clp->cl_auth = authunix_create_default();
|
||||
try.tv_sec = 10;
|
||||
try.tv_usec = 0;
|
||||
if (nfsargsp->flags & NFSMNT_KERB)
|
||||
nfhret.auth = RPCAUTH_KERB4;
|
||||
else
|
||||
nfhret.auth = RPCAUTH_UNIX;
|
||||
nfhret.vers = mntvers;
|
||||
clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
|
||||
xdr_dir, spec, xdr_fh, &nfhret, try);
|
||||
if (clnt_stat != RPC_SUCCESS) {
|
||||
if ((opflags & ISBGRND) == 0)
|
||||
warnx("%s", clnt_sperror(clp,
|
||||
"bad MNT RPC"));
|
||||
} else {
|
||||
auth_destroy(clp->cl_auth);
|
||||
clnt_destroy(clp);
|
||||
retrycnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (--retrycnt > 0) {
|
||||
if (opflags & BGRND) {
|
||||
opflags &= ~BGRND;
|
||||
if (i = fork()) {
|
||||
if (i == -1)
|
||||
err(1, "nqnfs 2");
|
||||
exit(0);
|
||||
}
|
||||
(void) setsid();
|
||||
(void) close(STDIN_FILENO);
|
||||
(void) close(STDOUT_FILENO);
|
||||
(void) close(STDERR_FILENO);
|
||||
(void) chdir("/");
|
||||
opflags |= ISBGRND;
|
||||
}
|
||||
sleep(60);
|
||||
}
|
||||
}
|
||||
if (nfhret.stat) {
|
||||
if (opflags & ISBGRND)
|
||||
exit(1);
|
||||
warnx("can't access %s: %s", spec, strerror(nfhret.stat));
|
||||
return (0);
|
||||
}
|
||||
saddr.sin_port = htons(tport);
|
||||
#ifdef ISO
|
||||
if (isoflag) {
|
||||
nfsargsp->addr = (struct sockaddr *) &isoaddr;
|
||||
nfsargsp->addrlen = sizeof (isoaddr);
|
||||
} else
|
||||
#endif /* ISO */
|
||||
{
|
||||
nfsargsp->addr = (struct sockaddr *) &saddr;
|
||||
nfsargsp->addrlen = sizeof (saddr);
|
||||
}
|
||||
nfsargsp->fh = nfhret.nfh;
|
||||
nfsargsp->fhsize = nfhret.fhsize;
|
||||
nfsargsp->hostname = nam;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* xdr routines for mount rpc's
|
||||
*/
|
||||
int
|
||||
xdr_dir(xdrsp, dirp)
|
||||
XDR *xdrsp;
|
||||
char *dirp;
|
||||
{
|
||||
return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
|
||||
}
|
||||
|
||||
int
|
||||
xdr_fh(xdrsp, np)
|
||||
XDR *xdrsp;
|
||||
register struct nfhret *np;
|
||||
{
|
||||
register int i;
|
||||
long auth, authcnt, authfnd = 0;
|
||||
|
||||
if (!xdr_u_long(xdrsp, &np->stat))
|
||||
return (0);
|
||||
if (np->stat)
|
||||
return (1);
|
||||
switch (np->vers) {
|
||||
case 1:
|
||||
np->fhsize = NFSX_V2FH;
|
||||
return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH));
|
||||
case 3:
|
||||
if (!xdr_long(xdrsp, &np->fhsize))
|
||||
return (0);
|
||||
if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX)
|
||||
return (0);
|
||||
if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
|
||||
return (0);
|
||||
if (!xdr_long(xdrsp, &authcnt))
|
||||
return (0);
|
||||
for (i = 0; i < authcnt; i++) {
|
||||
if (!xdr_long(xdrsp, &auth))
|
||||
return (0);
|
||||
if (auth == np->auth)
|
||||
authfnd++;
|
||||
}
|
||||
/*
|
||||
* Some servers, such as DEC's OSF/1 return a nil authenticator
|
||||
* list to indicate RPCAUTH_UNIX.
|
||||
*/
|
||||
if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX))
|
||||
np->stat = EAUTH;
|
||||
return (1);
|
||||
};
|
||||
return (0);
|
||||
}
|
||||
|
||||
__dead void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
|
||||
"[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
|
||||
"\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
|
||||
"\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
|
||||
"\trhost:path node");
|
||||
exit(1);
|
||||
}
|
||||
232
sbin/mount_null/mount_null.8
Normal file
232
sbin/mount_null/mount_null.8
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
|
||||
.\" 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.6 (Berkeley) 5/1/95
|
||||
.\"
|
||||
.\"
|
||||
.Dd May 1, 1995
|
||||
.Dt MOUNT_NULL 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_null
|
||||
.Nd mount a loopback filesystem sub-tree;
|
||||
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.
|
||||
This allows existing files and directories to be accessed
|
||||
using a different pathname.
|
||||
.Pp
|
||||
The primary differences between a virtual copy of the filesystem
|
||||
and a symbolic link are that
|
||||
.Xr getcwd 3
|
||||
functions correctly in the virtual copy, and that other filesystems
|
||||
may be mounted on the virtual copy without affecting the original.
|
||||
A different device number for the virtual copy is returned by
|
||||
.Xr stat 2 ,
|
||||
but in other respects it is indistinguishable from the original.
|
||||
.Pp
|
||||
The
|
||||
.Nm mount_null
|
||||
filesystem differs from a traditional
|
||||
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_null/mount_null.c
Normal file
129
sbin/mount_null/mount_null.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.6 (Berkeley) 4/26/95";
|
||||
#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, 0);
|
||||
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("loopback", 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);
|
||||
}
|
||||
215
sbin/mount_portal/activate.c
Normal file
215
sbin/mount_portal/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.3 (Berkeley) 4/28/95
|
||||
*
|
||||
* $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;
|
||||
|
||||
memset(&msg, 0, 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
|
||||
*/
|
||||
memset(&msg, 0, 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);
|
||||
}
|
||||
259
sbin/mount_portal/mount_portal.c
Normal file
259
sbin/mount_portal/mount_portal.c
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* 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.6 (Berkeley) 4/26/95";
|
||||
#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 && errno != ECHILD)
|
||||
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, 0);
|
||||
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("portal", mountpt, mntflags, &args);
|
||||
if (rc < 0)
|
||||
err(1, NULL);
|
||||
|
||||
/*
|
||||
* Everything is ready to go - now is a good time to fork
|
||||
*/
|
||||
daemon(0, 0);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
exit(0);
|
||||
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);
|
||||
}
|
||||
106
sbin/mount_portal/pt_file.c
Normal file
106
sbin/mount_portal/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.3 (Berkeley) 7/3/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;
|
||||
gid_t 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);
|
||||
}
|
||||
159
sbin/mount_portal/pt_tcp.c
Normal file
159
sbin/mount_portal/pt_tcp.c
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.5 (Berkeley) 4/28/95
|
||||
*
|
||||
* $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 = strtoul(port, &p, 0);
|
||||
if (s_port == 0 || *p != '\0')
|
||||
return (EINVAL);
|
||||
s_port = htons(s_port);
|
||||
}
|
||||
|
||||
memset(&sain, 0, 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);
|
||||
}
|
||||
254
sbin/mount_procfs/mount_procfs.8
Normal file
254
sbin/mount_procfs/mount_procfs.8
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)mount_procfs.8 8.3 (Berkeley) 6/1/94
|
||||
.\"
|
||||
.\"
|
||||
.Dd June 1, 1994
|
||||
.Dt MOUNT_PROCFS 8
|
||||
.Os BSD 4.4
|
||||
.Sh NAME
|
||||
.Nm mount_procfs
|
||||
.Nd mount the process file system
|
||||
.Sh SYNOPSIS
|
||||
.Nm mount_procfs
|
||||
.Op Fl o Ar options
|
||||
.Pa /proc
|
||||
.Pa mount_point
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mount_procfs
|
||||
command attaches an instance of the process
|
||||
namespace to the global filesystem namespace.
|
||||
The conventional mount point is
|
||||
.Pa /proc .
|
||||
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 root of the process filesystem
|
||||
contains an entry for each active process.
|
||||
These processes are visible as a directory whose
|
||||
name is the process' pid.
|
||||
In addition, the special entry
|
||||
.Pa curproc
|
||||
references the current process.
|
||||
.Pp
|
||||
Each directory contains several files.
|
||||
.Bl -tag -width status
|
||||
.It Pa ctl
|
||||
a writeonly file which supports a variety
|
||||
of control operations.
|
||||
Control commands are written as strings to the
|
||||
.Pa ctl
|
||||
file.
|
||||
The control commands are:
|
||||
.Bl -tag -width detach -compact
|
||||
.It attach
|
||||
stops the target process and arranges for the sending
|
||||
process to become the debug control process.
|
||||
.It detach
|
||||
continue execution of the target process and
|
||||
remove it from control by the debug process (which
|
||||
need not be the sending process).
|
||||
.It run
|
||||
continue running the target process until
|
||||
a signal is delivered, a breakpoint is hit, or the
|
||||
target process exits.
|
||||
.It step
|
||||
single step the target process, with no signal delivery.
|
||||
.It wait
|
||||
wait for the target process to come to a steady
|
||||
state ready for debugging.
|
||||
The target process must be in this state before
|
||||
any of the other commands are allowed.
|
||||
.El
|
||||
.Pp
|
||||
The string can also be the name of a signal, lower case
|
||||
and without the
|
||||
.Dv SIG
|
||||
prefix,
|
||||
in which case that signal is delivered to the process
|
||||
(see
|
||||
.Xr sigaction 2 ).
|
||||
.It Pa file
|
||||
A reference to the vnode from which the process text was read.
|
||||
This can be used to gain access to the process' symbol table,
|
||||
or to start another copy of the process.
|
||||
.It Pa mem
|
||||
The complete virtual memory image of the process.
|
||||
Only those address which exist in the process can be accessed.
|
||||
Reads and writes to this file modify the process.
|
||||
Writes to the text segment remain private to the process.
|
||||
.It Pa note
|
||||
Not implemented.
|
||||
.It Pa notepg
|
||||
Not implemented.
|
||||
.It Pa regs
|
||||
Allows read and write access to the process' register set.
|
||||
This file contains a binary data structure
|
||||
.Dv "struct regs"
|
||||
defined in
|
||||
.Pa <machine/reg.h> .
|
||||
.Pa regs
|
||||
can only be written when the process is stopped.
|
||||
.ne 1i
|
||||
.It Pa fpregs
|
||||
The floating point registers as defined by
|
||||
.Dv "struct fpregs"
|
||||
in
|
||||
.Pa <machine/reg.h> .
|
||||
.Pa fpregs
|
||||
is only implemented on machines which have distinct general
|
||||
purpose and floating point register sets.
|
||||
.It Pa status
|
||||
The process status.
|
||||
This file is readonly and returns a single line containing
|
||||
multiple space-separated fields as follows:
|
||||
.Pp
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
command name
|
||||
.It
|
||||
process id
|
||||
.It
|
||||
parent process id
|
||||
.It
|
||||
process group id
|
||||
.It
|
||||
session id
|
||||
.It
|
||||
.Ar major,minor
|
||||
of the controlling terminal, or
|
||||
.Dv -1,-1
|
||||
if there is no controlling terminal.
|
||||
.It
|
||||
a list of process flags:
|
||||
.Dv ctty
|
||||
if there is a controlling terminal,
|
||||
.Dv sldr
|
||||
if the process is a session leader,
|
||||
.Dv noflags
|
||||
if neither of the other two flags are set.
|
||||
.It
|
||||
the process start time in seconds and microseconds,
|
||||
comma separated.
|
||||
.It
|
||||
the user time in seconds and microseconds,
|
||||
comma separated.
|
||||
.It
|
||||
the system time in seconds and microseconds,
|
||||
comma separated.
|
||||
.It
|
||||
the wait channel message
|
||||
.It
|
||||
the process credentials consisting of
|
||||
the effective user id
|
||||
and the list of groups (whose first member
|
||||
is the effective group id)
|
||||
all comma separated.
|
||||
.El
|
||||
.El
|
||||
.Pp
|
||||
In a normal debugging environment,
|
||||
where the target is fork/exec'd by the debugger,
|
||||
the debugger should fork and the child should stop
|
||||
itself (with a self-inflicted
|
||||
.Dv SIGSTOP
|
||||
for example).
|
||||
The parent should issue a
|
||||
.Dv wait
|
||||
and then an
|
||||
.Dv attach
|
||||
command via the appropriate
|
||||
.Pa ctl
|
||||
file.
|
||||
The child process will receive a
|
||||
.Dv SIGTRAP
|
||||
immediately after the call to exec (see
|
||||
.Xr execve 2 ).
|
||||
.Sh FILES
|
||||
.Bl -tag -width /proc/curproc -compact
|
||||
.It Pa /proc/#
|
||||
.It Pa /proc/curproc
|
||||
.It Pa /proc/curproc/ctl
|
||||
.It Pa /proc/curproc/file
|
||||
.It Pa /proc/curproc/mem
|
||||
.It Pa /proc/curproc/note
|
||||
.It Pa /proc/curproc/notepg
|
||||
.It Pa /proc/curproc/regs
|
||||
.It Pa /proc/curproc/fpregs
|
||||
.It Pa /proc/curproc/status
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr sigaction 2 ,
|
||||
.Xr mount 2 ,
|
||||
.Xr unmount 2 ,
|
||||
.Sh CAVEATS
|
||||
No
|
||||
.Pa .
|
||||
and
|
||||
.Pa ..
|
||||
entries appear when listing the contents of the
|
||||
.Pa /proc
|
||||
directory.
|
||||
This makes sense in the context of this filesystem, but is inconsistent
|
||||
with usual filesystem conventions.
|
||||
However, it is still possible to refer to both
|
||||
.Pa .
|
||||
and
|
||||
.Pa ..
|
||||
in a pathname.
|
||||
.Pp
|
||||
This filesystem may not be NFS-exported
|
||||
since most of the functionality of
|
||||
.Dv procfs
|
||||
requires that state be maintained.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mount_procfs
|
||||
utility first appeared in 4.4BSD.
|
||||
100
sbin/mount_procfs/mount_procfs.c
Normal file
100
sbin/mount_procfs/mount_procfs.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1992, 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed 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_procfs.c 8.4 (Berkeley) 4/26/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mntopts.h"
|
||||
|
||||
struct mntopt mopts[] = {
|
||||
MOPT_STDOPTS,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch, mntflags;
|
||||
|
||||
mntflags = 0;
|
||||
while ((ch = getopt(argc, argv, "o:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'o':
|
||||
getmntopts(optarg, mopts, &mntflags, 0);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
if (mount("procfs", argv[1], mntflags, NULL))
|
||||
err(1, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: mount_procfs [-o options] /proc mount_point\n");
|
||||
exit(1);
|
||||
}
|
||||
130
sbin/mount_umap/mount_umap.8
Normal file
130
sbin/mount_umap/mount_umap.8
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
.\" 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.4 (Berkeley) 5/1/95
|
||||
.\"
|
||||
.Dd "May 1, 1995"
|
||||
.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
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm mount_umap
|
||||
utility first appeared in 4.4BSD.
|
||||
232
sbin/mount_umap/mount_umap.c
Normal file
232
sbin/mount_umap/mount_umap.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.5 (Berkeley) 4/26/95";
|
||||
#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, 0);
|
||||
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(gfp, "%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(gfp, "%lu %lu\n",
|
||||
&(gmapdata[count][0]), &(gmapdata[count][1]))) != 2) {
|
||||
if (ferror(gfp))
|
||||
err(1, "%s%s", gmapfile, not);
|
||||
if (feof(gfp))
|
||||
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("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);
|
||||
}
|
||||
11
sbin/mount_union/Makefile
Normal file
11
sbin/mount_union/Makefile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# @(#)Makefile 8.4 (Berkeley) 7/13/94
|
||||
|
||||
PROG= mount_union
|
||||
SRCS= mount_union.c getmntopts.c
|
||||
MAN8= mount_union.0
|
||||
|
||||
MOUNT= ${.CURDIR}/../mount
|
||||
CFLAGS+= -I/sys -I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
201
sbin/mount_union/mount_union.8
Normal file
201
sbin/mount_union/mount_union.8
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
.\" 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.7 (Berkeley) 5/1/95
|
||||
.\"
|
||||
.Dd May 1, 1995
|
||||
.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_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_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_union/mount_union.c
Normal file
140
sbin/mount_union/mount_union.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.6 (Berkeley) 4/26/95";
|
||||
#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, 0);
|
||||
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("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);
|
||||
}
|
||||
254
sbin/mountd/exports.5
Normal file
254
sbin/mountd/exports.5
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
.\" 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.3 (Berkeley) 3/29/95
|
||||
.\"
|
||||
.Dd March 29, 1995
|
||||
.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"
|
||||
and
|
||||
.%T "NFS: Network File System Version 3 Specification, Appendix I" .
|
||||
.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 at any point within the filesystem,
|
||||
including regular files if the
|
||||
.Fl r
|
||||
option is used on mountd.
|
||||
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.
|
||||
This option requires that the kernel be built with the NFSKERB option.
|
||||
.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.
|
||||
115
sbin/mountd/mountd.8
Normal file
115
sbin/mountd/mountd.8
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
.\" 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.4 (Berkeley) 4/28/95
|
||||
.\"
|
||||
.Dd April 28, 1995
|
||||
.Dt MOUNTD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mountd
|
||||
.Nd service remote
|
||||
.Tn NFS
|
||||
mount requests
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/mountd
|
||||
.Op Fl nr
|
||||
.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, Appendix A and
|
||||
.%T "NFS: Network File System Version 3 Protocol Specification" ,
|
||||
Appendix I.
|
||||
.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 Fl r
|
||||
The
|
||||
.Fl r
|
||||
option allows mount RPCs requests for regular files to be served.
|
||||
Although this seems to violate the mount protocol specification,
|
||||
some diskless workstations do mount requests for
|
||||
their swapfiles and expect them to be regular files.
|
||||
Since a regular file cannot be specified in
|
||||
.Pa /etc/exports ,
|
||||
the entire file system in which the swapfiles resides
|
||||
will have to be exported with the
|
||||
.Fl alldirs
|
||||
flag.
|
||||
.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 \-s 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.
|
||||
2064
sbin/mountd/mountd.c
Normal file
2064
sbin/mountd/mountd.c
Normal file
File diff suppressed because it is too large
Load diff
140
sbin/newlfs/config.h
Normal file
140
sbin/newlfs/config.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*-
|
||||
* 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.
|
||||
*
|
||||
* @(#)config.h 8.3 (Berkeley) 5/24/95
|
||||
*/
|
||||
|
||||
/*
|
||||
* The first boot and super blocks are given in absolute disk addresses.
|
||||
* The byte-offset forms are preferred, as they don't imply a sector size.
|
||||
*/
|
||||
#define BBSIZE 8192
|
||||
#define SBSIZE 8192
|
||||
|
||||
/*
|
||||
* The following two constants set the default block and fragment sizes.
|
||||
* Both constants must be a power of 2 and meet the following constraints:
|
||||
* MINBSIZE <= DESBLKSIZE <= MAXBSIZE
|
||||
* sectorsize <= DESFRAGSIZE <= DESBLKSIZE
|
||||
* DESBLKSIZE / DESFRAGSIZE <= 8
|
||||
*/
|
||||
#define DFL_FRAGSIZE 1024
|
||||
#define DFL_BLKSIZE 8192
|
||||
|
||||
/*
|
||||
* Cylinder groups may have up to many cylinders. The actual
|
||||
* number used depends upon how much information can be stored
|
||||
* on a single cylinder. The default is to use 16 cylinders
|
||||
* per group.
|
||||
*/
|
||||
#define DESCPG 16 /* desired fs_cpg */
|
||||
|
||||
/*
|
||||
* MINFREE gives the minimum acceptable percentage of file system
|
||||
* blocks which may be free. If the freelist drops below this level
|
||||
* only the superuser may continue to allocate blocks. This may
|
||||
* be set to 0 if no reserve of free blocks is deemed necessary,
|
||||
* however throughput drops by fifty percent if the file system
|
||||
* is run at between 90% and 100% full; thus the default value of
|
||||
* fs_minfree is 10%. With 10% free space, fragmentation is not a
|
||||
* problem, so we choose to optimize for time.
|
||||
*/
|
||||
#define MINFREE 10
|
||||
#define DEFAULTOPT FS_OPTTIME
|
||||
|
||||
/*
|
||||
* Preference for optimization.
|
||||
*/
|
||||
#define FS_OPTTIME 0 /* minimize allocation time */
|
||||
#define FS_OPTSPACE 1 /* minimize disk fragmentation */
|
||||
|
||||
|
||||
/*
|
||||
* ROTDELAY gives the minimum number of milliseconds to initiate
|
||||
* another disk transfer on the same cylinder. It is used in
|
||||
* determining the rotationally optimal layout for disk blocks
|
||||
* within a file; the default of fs_rotdelay is 4ms.
|
||||
*/
|
||||
#define ROTDELAY 4
|
||||
|
||||
/*
|
||||
* MAXCONTIG sets the default for the maximum number of blocks
|
||||
* that may be allocated sequentially. Since UNIX drivers are
|
||||
* not capable of scheduling multi-block transfers, this defaults
|
||||
* to 1 (ie no contiguous blocks are allocated).
|
||||
*/
|
||||
#define MAXCONTIG 1
|
||||
|
||||
/*
|
||||
* MAXBLKPG determines the maximum number of data blocks which are
|
||||
* placed in a single cylinder group. The default is one indirect
|
||||
* block worth of data blocks.
|
||||
*/
|
||||
#define MAXBLKPG(bsize) ((bsize) / sizeof(daddr_t))
|
||||
|
||||
/*
|
||||
* Each file system has a number of inodes statically allocated.
|
||||
* We allocate one inode slot per NFPI fragments, expecting this
|
||||
* to be far more than we will ever need.
|
||||
*/
|
||||
#define NFPI 4
|
||||
|
||||
/*
|
||||
* For each cylinder we keep track of the availability of blocks at different
|
||||
* rotational positions, so that we can lay out the data to be picked
|
||||
* up with minimum rotational latency. NRPOS is the default number of
|
||||
* rotational positions that we distinguish. With NRPOS of 8 the resolution
|
||||
* of our summary information is 2ms for a typical 3600 rpm drive.
|
||||
*/
|
||||
#define NRPOS 8 /* number distinct rotational positions */
|
||||
|
||||
/*
|
||||
* The following constants set the default block and segment size for a log
|
||||
* structured file system. Both must be powers of two and the segment size
|
||||
* must be a multiple of the block size. We also set minimum block and segment
|
||||
* sizes.
|
||||
*/
|
||||
#define LFS_MINSEGSIZE (64*1024)
|
||||
#define DFL_LFSSEG (1024 * 1024)
|
||||
#define DFL_LFSSEG_SHIFT 20
|
||||
#define DFL_LFSSEG_MASK 0xFFFFF
|
||||
|
||||
#define LFS_MINBLOCKSIZE 1024
|
||||
#define DFL_LFSBLOCK 4096
|
||||
#define DFL_LFSBLOCK_SHIFT 12
|
||||
#define DFL_LFSBLOCK_MASK 0xFFF
|
||||
|
||||
#define DFL_LFSFRAG 4096
|
||||
#define DFL_LFS_FFMASK DFL_LFSBLOCK_MASK
|
||||
#define DFL_LFS_FFSHIFT DFL_LFSBLOCK_SHIFT
|
||||
#define DFL_LFS_FBMASK 0
|
||||
#define DFL_LFS_FBSHIFT 0
|
||||
45
sbin/newlfs/extern.h
Normal file
45
sbin/newlfs/extern.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)extern.h 8.2 (Berkeley) 5/24/95
|
||||
*/
|
||||
|
||||
u_long cksum __P((void *, size_t));
|
||||
u_short dkcksum __P((struct disklabel *));
|
||||
void fatal __P((const char *fmt, ...));
|
||||
u_int log2 __P((u_int));
|
||||
int make_lfs __P((int, struct disklabel *, struct partition *, int,
|
||||
int, int, int));
|
||||
int mkfs __P((struct partition *, char *, int, int));
|
||||
|
||||
extern char *progname;
|
||||
extern char *special;
|
||||
683
sbin/newlfs/lfs.c
Normal file
683
sbin/newlfs/lfs.c
Normal file
|
|
@ -0,0 +1,683 @@
|
|||
/*-
|
||||
* 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[] = "@(#)lfs.c 8.5 (Berkeley) 5/24/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ufs/quota.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/lfs/lfs.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* This table is indexed by the log base 2 of the block size.
|
||||
* It returns the maximum file size allowed in a file system
|
||||
* with the specified block size. For block sizes smaller than
|
||||
* 8K, the size is limited by tha maximum number of blocks that
|
||||
* can be reached by triply indirect blocks:
|
||||
* NDADDR + INOPB(bsize) + INOPB(bsize)^2 + INOPB(bsize)^3
|
||||
* For block size of 8K or larger, the file size is limited by the
|
||||
* number of blocks that can be represented in the file system. Since
|
||||
* we use negative block numbers to represent indirect blocks, we can
|
||||
* have a maximum of 2^31 blocks.
|
||||
*/
|
||||
|
||||
u_quad_t maxtable[] = {
|
||||
/* 1 */ -1,
|
||||
/* 2 */ -1,
|
||||
/* 4 */ -1,
|
||||
/* 8 */ -1,
|
||||
/* 16 */ -1,
|
||||
/* 32 */ -1,
|
||||
/* 64 */ -1,
|
||||
/* 128 */ -1,
|
||||
/* 256 */ -1,
|
||||
/* 512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128,
|
||||
/* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256,
|
||||
/* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512,
|
||||
/* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024,
|
||||
/* 8192 */ 1 << 31,
|
||||
/* 16 K */ 1 << 31,
|
||||
/* 32 K */ 1 << 31,
|
||||
};
|
||||
|
||||
static struct lfs lfs_default = {
|
||||
/* lfs_magic */ LFS_MAGIC,
|
||||
/* lfs_version */ LFS_VERSION,
|
||||
/* lfs_size */ 0,
|
||||
/* lfs_ssize */ DFL_LFSSEG/DFL_LFSBLOCK,
|
||||
/* lfs_dsize */ 0,
|
||||
/* lfs_bsize */ DFL_LFSBLOCK,
|
||||
/* lfs_fsize */ DFL_LFSFRAG,
|
||||
/* lfs_frag */ 1,
|
||||
/* lfs_free */ LFS_FIRST_INUM,
|
||||
/* lfs_bfree */ 0,
|
||||
/* lfs_nfiles */ 0,
|
||||
/* lfs_avail */ 0,
|
||||
/* lfs_uinodes */ 0,
|
||||
/* lfs_idaddr */ 0,
|
||||
/* lfs_ifile */ LFS_IFILE_INUM,
|
||||
/* lfs_lastseg */ 0,
|
||||
/* lfs_nextseg */ 0,
|
||||
/* lfs_curseg */ 0,
|
||||
/* lfs_offset */ 0,
|
||||
/* lfs_lastpseg */ 0,
|
||||
/* lfs_tstamp */ 0,
|
||||
/* lfs_minfree */ MINFREE,
|
||||
/* lfs_maxfilesize */ 0,
|
||||
/* lfs_dbpseg */ DFL_LFSSEG/DEV_BSIZE,
|
||||
/* lfs_inopb */ DFL_LFSBLOCK/sizeof(struct dinode),
|
||||
/* lfs_ifpb */ DFL_LFSBLOCK/sizeof(IFILE),
|
||||
/* lfs_sepb */ DFL_LFSBLOCK/sizeof(SEGUSE),
|
||||
/* lfs_nindir */ DFL_LFSBLOCK/sizeof(daddr_t),
|
||||
/* lfs_nseg */ 0,
|
||||
/* lfs_nspf */ 0,
|
||||
/* lfs_cleansz */ 0,
|
||||
/* lfs_segtabsz */ 0,
|
||||
/* lfs_segmask */ DFL_LFSSEG_MASK,
|
||||
/* lfs_segshift */ DFL_LFSSEG_SHIFT,
|
||||
/* lfs_bmask */ DFL_LFSBLOCK_MASK,
|
||||
/* lfs_bshift */ DFL_LFSBLOCK_SHIFT,
|
||||
/* lfs_ffmask */ DFL_LFS_FFMASK,
|
||||
/* lfs_ffshift */ DFL_LFS_FFSHIFT,
|
||||
/* lfs_fbmask */ DFL_LFS_FBMASK,
|
||||
/* lfs_fbshift */ DFL_LFS_FBSHIFT,
|
||||
/* lfs_fsbtodb */ 0,
|
||||
/* lfs_sushift */ 0,
|
||||
/* lfs_sboffs */ { 0 },
|
||||
/* lfs_sp */ NULL,
|
||||
/* lfs_ivnode */ NULL,
|
||||
/* lfs_seglock */ 0,
|
||||
/* lfs_lockpid */ 0,
|
||||
/* lfs_iocount */ 0,
|
||||
/* lfs_writer */ 0,
|
||||
/* lfs_dirops */ 0,
|
||||
/* lfs_doifile */ 0,
|
||||
/* lfs_nactive */ 0,
|
||||
/* lfs_fmod */ 0,
|
||||
/* lfs_clean */ 0,
|
||||
/* lfs_ronly */ 0,
|
||||
/* lfs_flags */ 0,
|
||||
/* lfs_fsmnt */ { 0 },
|
||||
/* lfs_pad */ { 0 },
|
||||
/* lfs_cksum */ 0,
|
||||
/* lfs_maxsymlinklen */ MAXSYMLINKLEN
|
||||
};
|
||||
|
||||
|
||||
struct direct lfs_root_dir[] = {
|
||||
{ ROOTINO, sizeof(struct direct), DT_DIR, 1, "."},
|
||||
{ ROOTINO, sizeof(struct direct), DT_DIR, 2, ".."},
|
||||
{ LFS_IFILE_INUM, sizeof(struct direct), DT_REG, 5, "ifile"},
|
||||
{ LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 10, "lost+found"},
|
||||
};
|
||||
|
||||
struct direct lfs_lf_dir[] = {
|
||||
{ LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 1, "." },
|
||||
{ ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." },
|
||||
};
|
||||
|
||||
static daddr_t make_dinode
|
||||
__P((ino_t, struct dinode *, int, daddr_t, struct lfs *));
|
||||
static void make_dir __P(( void *, struct direct *, int));
|
||||
static void put __P((int, off_t, void *, size_t));
|
||||
|
||||
int
|
||||
make_lfs(fd, lp, partp, minfree, block_size, frag_size, seg_size)
|
||||
int fd;
|
||||
struct disklabel *lp;
|
||||
struct partition *partp;
|
||||
int minfree;
|
||||
int block_size;
|
||||
int frag_size;
|
||||
int seg_size;
|
||||
{
|
||||
struct dinode *dip; /* Pointer to a disk inode */
|
||||
struct dinode *dpagep; /* Pointer to page of disk inodes */
|
||||
CLEANERINFO *cleaninfo; /* Segment cleaner information table */
|
||||
FINFO file_info; /* File info structure in summary blocks */
|
||||
IFILE *ifile; /* Pointer to array of ifile structures */
|
||||
IFILE *ip; /* Pointer to array of ifile structures */
|
||||
struct lfs *lfsp; /* Superblock */
|
||||
SEGUSE *segp; /* Segment usage table */
|
||||
SEGUSE *segtable; /* Segment usage table */
|
||||
SEGSUM summary; /* Segment summary structure */
|
||||
SEGSUM *sp; /* Segment summary pointer */
|
||||
daddr_t last_sb_addr; /* Address of superblocks */
|
||||
daddr_t last_addr; /* Previous segment address */
|
||||
daddr_t sb_addr; /* Address of superblocks */
|
||||
daddr_t seg_addr; /* Address of current segment */
|
||||
void *ipagep; /* Pointer to the page we use to write stuff */
|
||||
void *sump; /* Used to copy stuff into segment buffer */
|
||||
u_long *block_array; /* Array of logical block nos to put in sum */
|
||||
u_long blocks_used; /* Number of blocks in first segment */
|
||||
u_long *dp; /* Used to computed checksum on data */
|
||||
u_long *datasump; /* Used to computed checksum on data */
|
||||
int block_array_size; /* How many entries in block array */
|
||||
int bsize; /* Block size */
|
||||
int fsize; /* Fragment size */
|
||||
int db_per_fb; /* Disk blocks per file block */
|
||||
int i, j;
|
||||
int off; /* Offset at which to write */
|
||||
int sb_interval; /* number of segs between super blocks */
|
||||
int seg_seek; /* Seek offset for a segment */
|
||||
int ssize; /* Segment size */
|
||||
int sum_size; /* Size of the summary block */
|
||||
|
||||
lfsp = &lfs_default;
|
||||
|
||||
if (!(bsize = block_size))
|
||||
bsize = DFL_LFSBLOCK;
|
||||
if (!(fsize = frag_size))
|
||||
fsize = DFL_LFSFRAG;
|
||||
if (!(ssize = seg_size))
|
||||
ssize = DFL_LFSSEG;
|
||||
|
||||
/* Modify parts of superblock overridden by command line arguments */
|
||||
if (bsize != DFL_LFSBLOCK || fsize != DFL_LFSFRAG) {
|
||||
lfsp->lfs_bshift = log2(bsize);
|
||||
if (1 << lfsp->lfs_bshift != bsize)
|
||||
fatal("%d: block size not a power of 2", bsize);
|
||||
lfsp->lfs_bsize = bsize;
|
||||
lfsp->lfs_fsize = fsize;
|
||||
lfsp->lfs_bmask = bsize - 1;
|
||||
lfsp->lfs_inopb = bsize / sizeof(struct dinode);
|
||||
lfsp->lfs_ffmask = fsize - 1;
|
||||
lfsp->lfs_ffshift = log2(fsize);
|
||||
if (1 << lfsp->lfs_ffshift != fsize)
|
||||
fatal("%d: frag size not a power of 2", fsize);
|
||||
lfsp->lfs_frag = numfrags(lfsp, bsize);
|
||||
lfsp->lfs_fbmask = lfsp->lfs_frag - 1;
|
||||
lfsp->lfs_fbshift = log2(lfsp->lfs_frag);
|
||||
/* MIS -- should I round to power of 2 */
|
||||
lfsp->lfs_ifpb = bsize / sizeof(IFILE);
|
||||
lfsp->lfs_sepb = bsize / sizeof(SEGUSE);
|
||||
lfsp->lfs_nindir = bsize / sizeof(daddr_t);
|
||||
}
|
||||
|
||||
if (ssize != DFL_LFSSEG) {
|
||||
lfsp->lfs_segshift = log2(ssize);
|
||||
if (1 << lfsp->lfs_segshift != ssize)
|
||||
fatal("%d: segment size not power of 2", ssize);
|
||||
lfsp->lfs_ssize = ssize;
|
||||
lfsp->lfs_segmask = ssize - 1;
|
||||
lfsp->lfs_dbpseg = ssize / DEV_BSIZE;
|
||||
}
|
||||
lfsp->lfs_ssize = ssize >> lfsp->lfs_bshift;
|
||||
|
||||
if (minfree)
|
||||
lfsp->lfs_minfree = minfree;
|
||||
|
||||
/*
|
||||
* Fill in parts of superblock that can be computed from file system
|
||||
* size, disk geometry and current time.
|
||||
*/
|
||||
db_per_fb = bsize/lp->d_secsize;
|
||||
lfsp->lfs_fsbtodb = log2(db_per_fb);
|
||||
lfsp->lfs_sushift = log2(lfsp->lfs_sepb);
|
||||
lfsp->lfs_size = partp->p_size >> lfsp->lfs_fsbtodb;
|
||||
lfsp->lfs_dsize = lfsp->lfs_size - (LFS_LABELPAD >> lfsp->lfs_bshift);
|
||||
lfsp->lfs_nseg = lfsp->lfs_dsize / lfsp->lfs_ssize;
|
||||
lfsp->lfs_maxfilesize = maxtable[lfsp->lfs_bshift] << lfsp->lfs_bshift;
|
||||
|
||||
/*
|
||||
* The number of free blocks is set from the number of segments times
|
||||
* the segment size - 2 (that we never write because we need to make
|
||||
* sure the cleaner can run). Then we'll subtract off the room for the
|
||||
* superblocks ifile entries and segment usage table.
|
||||
*/
|
||||
lfsp->lfs_dsize = fsbtodb(lfsp, (lfsp->lfs_nseg - 2) * lfsp->lfs_ssize);
|
||||
lfsp->lfs_bfree = lfsp->lfs_dsize;
|
||||
lfsp->lfs_segtabsz = SEGTABSIZE_SU(lfsp);
|
||||
lfsp->lfs_cleansz = CLEANSIZE_SU(lfsp);
|
||||
if ((lfsp->lfs_tstamp = time(NULL)) == -1)
|
||||
fatal("time: %s", strerror(errno));
|
||||
if ((sb_interval = lfsp->lfs_nseg / LFS_MAXNUMSB) < LFS_MIN_SBINTERVAL)
|
||||
sb_interval = LFS_MIN_SBINTERVAL;
|
||||
|
||||
/*
|
||||
* Now, lay out the file system. We need to figure out where
|
||||
* the superblocks go, initialize the checkpoint information
|
||||
* for the first two superblocks, initialize the segment usage
|
||||
* information, put the segusage information in the ifile, create
|
||||
* the first block of IFILE structures, and link all the IFILE
|
||||
* structures into a free list.
|
||||
*/
|
||||
|
||||
/* Figure out where the superblocks are going to live */
|
||||
lfsp->lfs_sboffs[0] = LFS_LABELPAD/lp->d_secsize;
|
||||
for (i = 1; i < LFS_MAXNUMSB; i++) {
|
||||
sb_addr = ((i * sb_interval) <<
|
||||
(lfsp->lfs_segshift - lfsp->lfs_bshift + lfsp->lfs_fsbtodb))
|
||||
+ lfsp->lfs_sboffs[0];
|
||||
if (sb_addr > partp->p_size)
|
||||
break;
|
||||
lfsp->lfs_sboffs[i] = sb_addr;
|
||||
}
|
||||
last_sb_addr = lfsp->lfs_sboffs[i - 1];
|
||||
lfsp->lfs_lastseg = lfsp->lfs_sboffs[0];
|
||||
lfsp->lfs_nextseg =
|
||||
lfsp->lfs_sboffs[1] ? lfsp->lfs_sboffs[1] : lfsp->lfs_sboffs[0];
|
||||
lfsp->lfs_curseg = lfsp->lfs_lastseg;
|
||||
|
||||
/*
|
||||
* Initialize the segment usage table. The first segment will
|
||||
* contain the superblock, the cleanerinfo (cleansz), the segusage
|
||||
* table * (segtabsz), 1 block's worth of IFILE entries, the root
|
||||
* directory, the lost+found directory and one block's worth of
|
||||
* inodes (containing the ifile, root, and l+f inodes).
|
||||
*/
|
||||
if (!(cleaninfo = malloc(lfsp->lfs_cleansz << lfsp->lfs_bshift)))
|
||||
fatal("%s", strerror(errno));
|
||||
cleaninfo->clean = lfsp->lfs_nseg - 1;
|
||||
cleaninfo->dirty = 1;
|
||||
|
||||
if (!(segtable = malloc(lfsp->lfs_segtabsz << lfsp->lfs_bshift)))
|
||||
fatal("%s", strerror(errno));
|
||||
segp = segtable;
|
||||
blocks_used = lfsp->lfs_segtabsz + lfsp->lfs_cleansz + 4;
|
||||
segp->su_nbytes = ((blocks_used - 1) << lfsp->lfs_bshift) +
|
||||
3 * sizeof(struct dinode) + LFS_SUMMARY_SIZE;
|
||||
segp->su_lastmod = lfsp->lfs_tstamp;
|
||||
segp->su_nsums = 1; /* 1 summary blocks */
|
||||
segp->su_ninos = 1; /* 1 inode block */
|
||||
segp->su_flags = SEGUSE_SUPERBLOCK | SEGUSE_DIRTY;
|
||||
lfsp->lfs_bfree -= LFS_SUMMARY_SIZE / lp->d_secsize;
|
||||
lfsp->lfs_bfree -=
|
||||
fsbtodb(lfsp, lfsp->lfs_cleansz + lfsp->lfs_segtabsz + 4);
|
||||
|
||||
/*
|
||||
* Now figure out the address of the ifile inode. The inode block
|
||||
* appears immediately after the segment summary.
|
||||
*/
|
||||
lfsp->lfs_idaddr = (LFS_LABELPAD + LFS_SBPAD + LFS_SUMMARY_SIZE) /
|
||||
lp->d_secsize;
|
||||
|
||||
for (segp = segtable + 1, i = 1; i < lfsp->lfs_nseg; i++, segp++) {
|
||||
if ((i % sb_interval) == 0) {
|
||||
segp->su_flags = SEGUSE_SUPERBLOCK;
|
||||
lfsp->lfs_bfree -= (LFS_SBPAD / lp->d_secsize);
|
||||
} else
|
||||
segp->su_flags = 0;
|
||||
segp->su_lastmod = 0;
|
||||
segp->su_nbytes = 0;
|
||||
segp->su_ninos = 0;
|
||||
segp->su_nsums = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize dynamic accounting. The blocks available for
|
||||
* writing are the bfree blocks minus 1 segment summary for
|
||||
* each segment since you can't write any new data without
|
||||
* creating a segment summary - 2 segments that the cleaner
|
||||
* needs.
|
||||
*/
|
||||
lfsp->lfs_avail = lfsp->lfs_bfree - lfsp->lfs_nseg -
|
||||
fsbtodb(lfsp, 2 * lfsp->lfs_ssize);
|
||||
lfsp->lfs_uinodes = 0;
|
||||
/*
|
||||
* Ready to start writing segments. The first segment is different
|
||||
* because it contains the segment usage table and the ifile inode
|
||||
* as well as a superblock. For the rest of the segments, set the
|
||||
* time stamp to be 0 so that the first segment is the most recent.
|
||||
* For each segment that is supposed to contain a copy of the super
|
||||
* block, initialize its first few blocks and its segment summary
|
||||
* to indicate this.
|
||||
*/
|
||||
lfsp->lfs_nfiles = LFS_FIRST_INUM - 1;
|
||||
lfsp->lfs_cksum =
|
||||
cksum(lfsp, sizeof(struct lfs) - sizeof(lfsp->lfs_cksum));
|
||||
|
||||
/* Now create a block of disk inodes */
|
||||
if (!(dpagep = malloc(lfsp->lfs_bsize)))
|
||||
fatal("%s", strerror(errno));
|
||||
dip = (struct dinode *)dpagep;
|
||||
memset(dip, 0, lfsp->lfs_bsize);
|
||||
|
||||
/* Create a block of IFILE structures. */
|
||||
if (!(ipagep = malloc(lfsp->lfs_bsize)))
|
||||
fatal("%s", strerror(errno));
|
||||
ifile = (IFILE *)ipagep;
|
||||
|
||||
/*
|
||||
* Initialize IFILE. It is the next block following the
|
||||
* block of inodes (whose address has been calculated in
|
||||
* lfsp->lfs_idaddr;
|
||||
*/
|
||||
sb_addr = lfsp->lfs_idaddr + lfsp->lfs_bsize / lp->d_secsize;
|
||||
sb_addr = make_dinode(LFS_IFILE_INUM, dip,
|
||||
lfsp->lfs_cleansz + lfsp->lfs_segtabsz+1, sb_addr, lfsp);
|
||||
dip->di_mode = IFREG|IREAD|IWRITE;
|
||||
ip = &ifile[LFS_IFILE_INUM];
|
||||
ip->if_version = 1;
|
||||
ip->if_daddr = lfsp->lfs_idaddr;
|
||||
|
||||
/* Initialize the ROOT Directory */
|
||||
sb_addr = make_dinode(ROOTINO, ++dip, 1, sb_addr, lfsp);
|
||||
dip->di_mode = IFDIR|IREAD|IWRITE|IEXEC;
|
||||
dip->di_size = DIRBLKSIZ;
|
||||
dip->di_nlink = 3;
|
||||
ip = &ifile[ROOTINO];
|
||||
ip->if_version = 1;
|
||||
ip->if_daddr = lfsp->lfs_idaddr;
|
||||
|
||||
/* Initialize the lost+found Directory */
|
||||
sb_addr = make_dinode(LOSTFOUNDINO, ++dip, 1, sb_addr, lfsp);
|
||||
dip->di_mode = IFDIR|IREAD|IWRITE|IEXEC;
|
||||
dip->di_size = DIRBLKSIZ;
|
||||
dip->di_nlink = 2;
|
||||
ip = &ifile[LOSTFOUNDINO];
|
||||
ip->if_version = 1;
|
||||
ip->if_daddr = lfsp->lfs_idaddr;
|
||||
|
||||
/* Make all the other dinodes invalid */
|
||||
for (i = INOPB(lfsp)-3, dip++; i; i--, dip++)
|
||||
dip->di_inumber = LFS_UNUSED_INUM;
|
||||
|
||||
|
||||
/* Link remaining IFILE entries in free list */
|
||||
for (ip = &ifile[LFS_FIRST_INUM], i = LFS_FIRST_INUM;
|
||||
i < lfsp->lfs_ifpb; ++ip) {
|
||||
ip->if_version = 1;
|
||||
ip->if_daddr = LFS_UNUSED_DADDR;
|
||||
ip->if_nextfree = ++i;
|
||||
}
|
||||
ifile[lfsp->lfs_ifpb - 1].if_nextfree = LFS_UNUSED_INUM;
|
||||
|
||||
/* Now, write the segment */
|
||||
|
||||
/* Compute a checksum across all the data you're writing */
|
||||
dp = datasump = malloc (blocks_used * sizeof(u_long));
|
||||
*dp++ = ((u_long *)dpagep)[0]; /* inode block */
|
||||
for (i = 0; i < lfsp->lfs_cleansz; i++)
|
||||
*dp++ = ((u_long *)cleaninfo)[(i << lfsp->lfs_bshift) /
|
||||
sizeof(u_long)]; /* Cleaner info */
|
||||
for (i = 0; i < lfsp->lfs_segtabsz; i++)
|
||||
*dp++ = ((u_long *)segtable)[(i << lfsp->lfs_bshift) /
|
||||
sizeof(u_long)]; /* Segusage table */
|
||||
*dp++ = ((u_long *)ifile)[0]; /* Ifile */
|
||||
|
||||
/* Still need the root and l+f bytes; get them later */
|
||||
|
||||
/* Write out the inode block */
|
||||
off = LFS_LABELPAD + LFS_SBPAD + LFS_SUMMARY_SIZE;
|
||||
put(fd, off, dpagep, lfsp->lfs_bsize);
|
||||
free(dpagep);
|
||||
off += lfsp->lfs_bsize;
|
||||
|
||||
/* Write out the ifile */
|
||||
|
||||
put(fd, off, cleaninfo, lfsp->lfs_cleansz << lfsp->lfs_bshift);
|
||||
off += (lfsp->lfs_cleansz << lfsp->lfs_bshift);
|
||||
(void)free(cleaninfo);
|
||||
|
||||
put(fd, off, segtable, lfsp->lfs_segtabsz << lfsp->lfs_bshift);
|
||||
off += (lfsp->lfs_segtabsz << lfsp->lfs_bshift);
|
||||
(void)free(segtable);
|
||||
|
||||
put(fd, off, ifile, lfsp->lfs_bsize);
|
||||
off += lfsp->lfs_bsize;
|
||||
|
||||
/*
|
||||
* use ipagep for space for writing out other stuff. It used to
|
||||
* contain the ifile, but we're done with it.
|
||||
*/
|
||||
|
||||
/* Write out the root and lost and found directories */
|
||||
memset(ipagep, 0, lfsp->lfs_bsize);
|
||||
make_dir(ipagep, lfs_root_dir,
|
||||
sizeof(lfs_root_dir) / sizeof(struct direct));
|
||||
*dp++ = ((u_long *)ipagep)[0];
|
||||
put(fd, off, ipagep, lfsp->lfs_bsize);
|
||||
off += lfsp->lfs_bsize;
|
||||
|
||||
memset(ipagep, 0, lfsp->lfs_bsize);
|
||||
make_dir(ipagep, lfs_lf_dir,
|
||||
sizeof(lfs_lf_dir) / sizeof(struct direct));
|
||||
*dp++ = ((u_long *)ipagep)[0];
|
||||
put(fd, off, ipagep, lfsp->lfs_bsize);
|
||||
|
||||
/* Write Supberblock */
|
||||
lfsp->lfs_offset = (off + lfsp->lfs_bsize) / lp->d_secsize;
|
||||
put(fd, LFS_LABELPAD, lfsp, sizeof(struct lfs));
|
||||
|
||||
/*
|
||||
* Finally, calculate all the fields for the summary structure
|
||||
* and write it.
|
||||
*/
|
||||
|
||||
summary.ss_next = lfsp->lfs_nextseg;
|
||||
summary.ss_create = lfsp->lfs_tstamp;
|
||||
summary.ss_nfinfo = 3;
|
||||
summary.ss_ninos = 3;
|
||||
summary.ss_magic = SS_MAGIC;
|
||||
summary.ss_datasum = cksum(datasump, sizeof(u_long) * blocks_used);
|
||||
|
||||
/*
|
||||
* Make sure that we don't overflow a summary block. We have to
|
||||
* record: FINFO structures for ifile, root, and l+f. The number
|
||||
* of blocks recorded for the ifile is determined by the size of
|
||||
* the cleaner info and the segments usage table. There is room
|
||||
* for one block included in sizeof(FINFO) so we don't need to add
|
||||
* any extra space for the ROOT and L+F, and one block of the ifile
|
||||
* is already counted. Finally, we leave room for 1 inode block
|
||||
* address.
|
||||
*/
|
||||
sum_size = 3*sizeof(FINFO) + sizeof(SEGSUM) + sizeof(daddr_t) +
|
||||
(lfsp->lfs_cleansz + lfsp->lfs_segtabsz) * sizeof(u_long);
|
||||
#define SUMERR \
|
||||
"Multiple summary blocks in segment 1 not yet implemented\nsummary is %d bytes."
|
||||
if (sum_size > LFS_SUMMARY_SIZE)
|
||||
fatal(SUMERR, sum_size);
|
||||
|
||||
block_array_size = lfsp->lfs_cleansz + lfsp->lfs_segtabsz + 1;
|
||||
|
||||
if (!(block_array = malloc(block_array_size *sizeof(int))))
|
||||
fatal("%s: %s", special, strerror(errno));
|
||||
|
||||
/* fill in the array */
|
||||
for (i = 0; i < block_array_size; i++)
|
||||
block_array[i] = i;
|
||||
|
||||
/* copy into segment */
|
||||
sump = ipagep;
|
||||
memmove(sump, &summary, sizeof(SEGSUM));
|
||||
sump += sizeof(SEGSUM);
|
||||
|
||||
/* Now, add the ifile */
|
||||
file_info.fi_nblocks = block_array_size;
|
||||
file_info.fi_version = 1;
|
||||
file_info.fi_lastlength = lfsp->lfs_bsize;
|
||||
file_info.fi_ino = LFS_IFILE_INUM;
|
||||
|
||||
memmove(sump, &file_info, sizeof(FINFO) - sizeof(u_long));
|
||||
sump += sizeof(FINFO) - sizeof(u_long);
|
||||
memmove(sump, block_array, sizeof(u_long) * file_info.fi_nblocks);
|
||||
sump += sizeof(u_long) * file_info.fi_nblocks;
|
||||
|
||||
/* Now, add the root directory */
|
||||
file_info.fi_nblocks = 1;
|
||||
file_info.fi_version = 1;
|
||||
file_info.fi_lastlength = lfsp->lfs_bsize;
|
||||
file_info.fi_ino = ROOTINO;
|
||||
file_info.fi_blocks[0] = 0;
|
||||
memmove(sump, &file_info, sizeof(FINFO));
|
||||
sump += sizeof(FINFO);
|
||||
|
||||
/* Now, add the lost and found */
|
||||
file_info.fi_ino = LOSTFOUNDINO;
|
||||
memmove(sump, &file_info, sizeof(FINFO));
|
||||
|
||||
((daddr_t *)ipagep)[LFS_SUMMARY_SIZE / sizeof(daddr_t) - 1] =
|
||||
lfsp->lfs_idaddr;
|
||||
((SEGSUM *)ipagep)->ss_sumsum = cksum(ipagep+sizeof(summary.ss_sumsum),
|
||||
LFS_SUMMARY_SIZE - sizeof(summary.ss_sumsum));
|
||||
put(fd, LFS_LABELPAD + LFS_SBPAD, ipagep, LFS_SUMMARY_SIZE);
|
||||
|
||||
sp = (SEGSUM *)ipagep;
|
||||
sp->ss_create = 0;
|
||||
sp->ss_nfinfo = 0;
|
||||
sp->ss_ninos = 0;
|
||||
sp->ss_datasum = 0;
|
||||
sp->ss_magic = SS_MAGIC;
|
||||
|
||||
/* Now write the summary block for the next partial so it's invalid */
|
||||
lfsp->lfs_tstamp = 0;
|
||||
off += lfsp->lfs_bsize;
|
||||
sp->ss_sumsum =
|
||||
cksum(&sp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum));
|
||||
put(fd, off, sp, LFS_SUMMARY_SIZE);
|
||||
|
||||
/* Now, write rest of segments containing superblocks */
|
||||
lfsp->lfs_cksum =
|
||||
cksum(lfsp, sizeof(struct lfs) - sizeof(lfsp->lfs_cksum));
|
||||
for (seg_addr = last_addr = lfsp->lfs_sboffs[0], j = 1, i = 1;
|
||||
i < lfsp->lfs_nseg; i++) {
|
||||
|
||||
seg_addr += lfsp->lfs_ssize << lfsp->lfs_fsbtodb;
|
||||
sp->ss_next = last_addr;
|
||||
last_addr = seg_addr;
|
||||
seg_seek = seg_addr * lp->d_secsize;
|
||||
|
||||
if (seg_addr == lfsp->lfs_sboffs[j]) {
|
||||
if (j < (LFS_MAXNUMSB - 2))
|
||||
j++;
|
||||
put(fd, seg_seek, lfsp, sizeof(struct lfs));
|
||||
seg_seek += LFS_SBPAD;
|
||||
}
|
||||
|
||||
/* Summary */
|
||||
sp->ss_sumsum = cksum(&sp->ss_datasum,
|
||||
LFS_SUMMARY_SIZE - sizeof(sp->ss_sumsum));
|
||||
put(fd, seg_seek, sp, LFS_SUMMARY_SIZE);
|
||||
}
|
||||
free(ipagep);
|
||||
close(fd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
put(fd, off, p, len)
|
||||
int fd;
|
||||
off_t off;
|
||||
void *p;
|
||||
size_t len;
|
||||
{
|
||||
int wbytes;
|
||||
|
||||
if (lseek(fd, off, SEEK_SET) < 0)
|
||||
fatal("%s: %s", special, strerror(errno));
|
||||
if ((wbytes = write(fd, p, len)) < 0)
|
||||
fatal("%s: %s", special, strerror(errno));
|
||||
if (wbytes != len)
|
||||
fatal("%s: short write (%d, not %d)", special, wbytes, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the root directory for this file system and the lost+found
|
||||
* directory.
|
||||
*/
|
||||
|
||||
void
|
||||
lfsinit()
|
||||
{}
|
||||
|
||||
static daddr_t
|
||||
make_dinode(ino, dip, nblocks, saddr, lfsp)
|
||||
ino_t ino; /* inode we're creating */
|
||||
struct dinode *dip; /* disk inode */
|
||||
int nblocks; /* number of blocks in file */
|
||||
daddr_t saddr; /* starting block address */
|
||||
struct lfs *lfsp; /* superblock */
|
||||
{
|
||||
int db_per_fb, i;
|
||||
|
||||
dip->di_nlink = 1;
|
||||
dip->di_blocks = nblocks << lfsp->lfs_fsbtodb;
|
||||
|
||||
dip->di_size = (nblocks << lfsp->lfs_bshift);
|
||||
dip->di_atime = dip->di_mtime = dip->di_ctime = lfsp->lfs_tstamp;
|
||||
dip->di_atimensec = dip->di_mtimensec = dip->di_ctimensec = 0;
|
||||
dip->di_inumber = ino;
|
||||
|
||||
#define SEGERR \
|
||||
"File requires more than the number of direct blocks; increase block or segment size."
|
||||
if (NDADDR < nblocks)
|
||||
fatal("%s", SEGERR);
|
||||
|
||||
/* Assign the block addresses for the ifile */
|
||||
db_per_fb = 1 << lfsp->lfs_fsbtodb;
|
||||
for (i = 0; i < nblocks; i++, saddr += db_per_fb)
|
||||
dip->di_db[i] = saddr;
|
||||
|
||||
return (saddr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Construct a set of directory entries in "bufp". We assume that all the
|
||||
* entries in protodir fir in the first DIRBLKSIZ.
|
||||
*/
|
||||
static void
|
||||
make_dir(bufp, protodir, entries)
|
||||
void *bufp;
|
||||
register struct direct *protodir;
|
||||
int entries;
|
||||
{
|
||||
char *cp;
|
||||
int i, spcleft;
|
||||
|
||||
spcleft = DIRBLKSIZ;
|
||||
for (cp = bufp, i = 0; i < entries - 1; i++) {
|
||||
protodir[i].d_reclen = DIRSIZ(NEWDIRFMT, &protodir[i]);
|
||||
memmove(cp, &protodir[i], protodir[i].d_reclen);
|
||||
cp += protodir[i].d_reclen;
|
||||
if ((spcleft -= protodir[i].d_reclen) < 0)
|
||||
fatal("%s: %s", special, "directory too big");
|
||||
}
|
||||
protodir[i].d_reclen = spcleft;
|
||||
memmove(cp, &protodir[i], DIRSIZ(NEWDIRFMT, &protodir[i]));
|
||||
}
|
||||
466
sbin/newlfs/newfs.c
Normal file
466
sbin/newlfs/newfs.c
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
/*-
|
||||
* Copyright (c) 1989, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1989, 1992, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)newfs.c 8.5 (Berkeley) 5/24/95";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* newfs: friendly front end to mkfs
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <paths.h>
|
||||
#include "config.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define COMPAT /* allow non-labeled disks */
|
||||
|
||||
int mfs; /* run as the memory based filesystem */
|
||||
int Nflag; /* run without writing file system */
|
||||
int fssize; /* file system size */
|
||||
int ntracks; /* # tracks/cylinder */
|
||||
int nsectors; /* # sectors/track */
|
||||
int nphyssectors; /* # sectors/track including spares */
|
||||
int secpercyl; /* sectors per cylinder */
|
||||
int trackspares = -1; /* spare sectors per track */
|
||||
int cylspares = -1; /* spare sectors per cylinder */
|
||||
int sectorsize; /* bytes/sector */
|
||||
#ifdef tahoe
|
||||
int realsectorsize; /* bytes/sector in hardware */
|
||||
#endif
|
||||
int rpm; /* revolutions/minute of drive */
|
||||
int interleave; /* hardware sector interleave */
|
||||
int trackskew = -1; /* sector 0 skew, per track */
|
||||
int headswitch; /* head switch time, usec */
|
||||
int trackseek; /* track-to-track seek, usec */
|
||||
int fsize = 0; /* fragment size */
|
||||
int bsize = 0; /* block size */
|
||||
int cpg = DESCPG; /* cylinders/cylinder group */
|
||||
int cpgflg; /* cylinders/cylinder group flag was given */
|
||||
int minfree = MINFREE; /* free space threshold */
|
||||
int opt = DEFAULTOPT; /* optimization preference (space or time) */
|
||||
int density; /* number of bytes per inode */
|
||||
int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */
|
||||
int rotdelay = ROTDELAY; /* rotational delay between blocks */
|
||||
int maxbpg; /* maximum blocks per file in a cyl group */
|
||||
int nrpos = NRPOS; /* # of distinguished rotational positions */
|
||||
int bbsize = BBSIZE; /* boot block size */
|
||||
int sbsize = SBSIZE; /* superblock size */
|
||||
int mntflags; /* flags to be passed to mount */
|
||||
u_long memleft; /* virtual memory available */
|
||||
caddr_t membase; /* start address of memory based filesystem */
|
||||
#ifdef COMPAT
|
||||
char *disktype;
|
||||
int unlabeled;
|
||||
#endif
|
||||
|
||||
char device[MAXPATHLEN];
|
||||
char *progname, *special;
|
||||
|
||||
static struct disklabel *getdisklabel __P((char *, int));
|
||||
static struct disklabel *debug_readlabel __P((int));
|
||||
static void rewritelabel __P((char *, int, struct disklabel *));
|
||||
static void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register int ch;
|
||||
register struct partition *pp;
|
||||
register struct disklabel *lp;
|
||||
struct partition oldpartition;
|
||||
struct stat st;
|
||||
int debug, lfs, fsi, fso, segsize;
|
||||
char *cp, *opstring;
|
||||
|
||||
if (progname = strrchr(*argv, '/'))
|
||||
++progname;
|
||||
else
|
||||
progname = *argv;
|
||||
|
||||
if (strstr(progname, "mfs")) {
|
||||
mfs = 1;
|
||||
Nflag++;
|
||||
}
|
||||
|
||||
/* -F is mfs only and MUST come first! */
|
||||
opstring = "F:B:DLNS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:";
|
||||
if (!mfs)
|
||||
opstring += 2;
|
||||
|
||||
debug = lfs = segsize = 0;
|
||||
while ((ch = getopt(argc, argv, opstring)) != EOF)
|
||||
switch(ch) {
|
||||
case 'B': /* LFS segment size */
|
||||
if ((segsize = atoi(optarg)) < LFS_MINSEGSIZE)
|
||||
fatal("%s: bad segment size", optarg);
|
||||
break;
|
||||
case 'D':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'F':
|
||||
if ((mntflags = atoi(optarg)) == 0)
|
||||
fatal("%s: bad mount flags", optarg);
|
||||
break;
|
||||
case 'L': /* Create lfs */
|
||||
lfs = 1;
|
||||
break;
|
||||
case 'N':
|
||||
Nflag++;
|
||||
break;
|
||||
case 'S':
|
||||
if ((sectorsize = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad sector size", optarg);
|
||||
break;
|
||||
#ifdef COMPAT
|
||||
case 'T':
|
||||
disktype = optarg;
|
||||
break;
|
||||
#endif
|
||||
case 'a':
|
||||
if ((maxcontig = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad max contiguous blocks\n",
|
||||
optarg);
|
||||
break;
|
||||
case 'b': /* used for LFS */
|
||||
if ((bsize = atoi(optarg)) < LFS_MINBLOCKSIZE)
|
||||
fatal("%s: bad block size", optarg);
|
||||
break;
|
||||
case 'c':
|
||||
if ((cpg = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad cylinders/group", optarg);
|
||||
cpgflg++;
|
||||
break;
|
||||
case 'd':
|
||||
if ((rotdelay = atoi(optarg)) < 0)
|
||||
fatal("%s: bad rotational delay\n", optarg);
|
||||
break;
|
||||
case 'e':
|
||||
if ((maxbpg = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad blocks per file in a cyl group\n",
|
||||
optarg);
|
||||
break;
|
||||
case 'f':
|
||||
if ((fsize = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad frag size", optarg);
|
||||
break;
|
||||
case 'i':
|
||||
if ((density = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad bytes per inode\n", optarg);
|
||||
break;
|
||||
case 'k':
|
||||
if ((trackskew = atoi(optarg)) < 0)
|
||||
fatal("%s: bad track skew", optarg);
|
||||
break;
|
||||
case 'l':
|
||||
if ((interleave = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad interleave", optarg);
|
||||
break;
|
||||
case 'm': /* used for LFS */
|
||||
if ((minfree = atoi(optarg)) < 0 || minfree > 99)
|
||||
fatal("%s: bad free space %%\n", optarg);
|
||||
break;
|
||||
case 'n':
|
||||
if ((nrpos = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad rotational layout count\n",
|
||||
optarg);
|
||||
break;
|
||||
case 'o':
|
||||
if (strcmp(optarg, "space") == 0)
|
||||
opt = FS_OPTSPACE;
|
||||
else if (strcmp(optarg, "time") == 0)
|
||||
opt = FS_OPTTIME;
|
||||
else
|
||||
fatal("%s: bad optimization preference %s",
|
||||
optarg, "(options are `space' or `time')");
|
||||
break;
|
||||
case 'p':
|
||||
if ((trackspares = atoi(optarg)) < 0)
|
||||
fatal("%s: bad spare sectors per track",
|
||||
optarg);
|
||||
break;
|
||||
case 'r':
|
||||
if ((rpm = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad revs/minute\n", optarg);
|
||||
break;
|
||||
case 's': /* used for LFS */
|
||||
if ((fssize = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad file system size", optarg);
|
||||
break;
|
||||
case 't':
|
||||
if ((ntracks = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad total tracks", optarg);
|
||||
break;
|
||||
case 'u':
|
||||
if ((nsectors = atoi(optarg)) <= 0)
|
||||
fatal("%s: bad sectors/track", optarg);
|
||||
break;
|
||||
case 'x':
|
||||
if ((cylspares = atoi(optarg)) < 0)
|
||||
fatal("%s: bad spare sectors per cylinder",
|
||||
optarg);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 2 && (mfs || argc != 1))
|
||||
usage();
|
||||
|
||||
/*
|
||||
* If the -N flag isn't specified, open the output file. If no path
|
||||
* prefix, try /dev/r%s and then /dev/%s.
|
||||
*/
|
||||
special = argv[0];
|
||||
if (strchr(special, '/') == NULL) {
|
||||
(void)sprintf(device, "%sr%s", _PATH_DEV, special);
|
||||
if (stat(device, &st) == -1)
|
||||
(void)sprintf(device, "%s%s", _PATH_DEV, special);
|
||||
special = device;
|
||||
}
|
||||
if (!Nflag) {
|
||||
fso = open(special,
|
||||
(debug ? O_CREAT : 0) | O_WRONLY, DEFFILEMODE);
|
||||
if (fso < 0)
|
||||
fatal("%s: %s", special, strerror(errno));
|
||||
} else
|
||||
fso = -1;
|
||||
|
||||
/* Open the input file. */
|
||||
fsi = open(special, O_RDONLY);
|
||||
if (fsi < 0)
|
||||
fatal("%s: %s", special, strerror(errno));
|
||||
if (fstat(fsi, &st) < 0)
|
||||
fatal("%s: %s", special, strerror(errno));
|
||||
|
||||
if (!debug && !mfs && !S_ISCHR(st.st_mode))
|
||||
(void)printf("%s: %s: not a character-special device\n",
|
||||
progname, special);
|
||||
cp = strchr(argv[0], '\0') - 1;
|
||||
if (!debug && (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)))
|
||||
fatal("%s: can't figure out file system partition", argv[0]);
|
||||
|
||||
#ifdef COMPAT
|
||||
if (!mfs && disktype == NULL)
|
||||
disktype = argv[1];
|
||||
#endif
|
||||
if (debug)
|
||||
lp = debug_readlabel(fsi);
|
||||
else
|
||||
lp = getdisklabel(special, fsi);
|
||||
|
||||
if (isdigit(*cp))
|
||||
pp = &lp->d_partitions[0];
|
||||
else
|
||||
pp = &lp->d_partitions[*cp - 'a'];
|
||||
if (pp->p_size == 0)
|
||||
fatal("%s: `%c' partition is unavailable", argv[0], *cp);
|
||||
|
||||
/* If we're making a LFS, we break out here */
|
||||
exit(make_lfs(fso, lp, pp, minfree, bsize, fsize, segsize));
|
||||
}
|
||||
|
||||
#ifdef COMPAT
|
||||
char lmsg[] = "%s: can't read disk label; disk type must be specified";
|
||||
#else
|
||||
char lmsg[] = "%s: can't read disk label";
|
||||
#endif
|
||||
|
||||
static struct disklabel *
|
||||
getdisklabel(s, fd)
|
||||
char *s;
|
||||
int fd;
|
||||
{
|
||||
static struct disklabel lab;
|
||||
|
||||
if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
|
||||
#ifdef COMPAT
|
||||
if (disktype) {
|
||||
struct disklabel *lp, *getdiskbyname();
|
||||
|
||||
unlabeled++;
|
||||
lp = getdiskbyname(disktype);
|
||||
if (lp == NULL)
|
||||
fatal("%s: unknown disk type", disktype);
|
||||
return (lp);
|
||||
}
|
||||
#endif
|
||||
(void)fprintf(stderr,
|
||||
"%s: ioctl (GDINFO): %s\n", progname, strerror(errno));
|
||||
fatal(lmsg, s);
|
||||
}
|
||||
return (&lab);
|
||||
}
|
||||
|
||||
|
||||
static struct disklabel *
|
||||
debug_readlabel(fd)
|
||||
int fd;
|
||||
{
|
||||
static struct disklabel lab;
|
||||
int n;
|
||||
|
||||
if ((n = read(fd, &lab, sizeof(struct disklabel))) < 0)
|
||||
fatal("unable to read disk label: %s", strerror(errno));
|
||||
else if (n < sizeof(struct disklabel))
|
||||
fatal("short read of disklabel: %d of %d bytes", n,
|
||||
sizeof(struct disklabel));
|
||||
return(&lab);
|
||||
}
|
||||
|
||||
static void
|
||||
rewritelabel(s, fd, lp)
|
||||
char *s;
|
||||
int fd;
|
||||
register struct disklabel *lp;
|
||||
{
|
||||
#ifdef COMPAT
|
||||
if (unlabeled)
|
||||
return;
|
||||
#endif
|
||||
lp->d_checksum = 0;
|
||||
lp->d_checksum = dkcksum(lp);
|
||||
if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
|
||||
(void)fprintf(stderr,
|
||||
"%s: ioctl (WDINFO): %s\n", progname, strerror(errno));
|
||||
fatal("%s: can't rewrite disk label", s);
|
||||
}
|
||||
#if vax
|
||||
if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
|
||||
register i;
|
||||
int cfd;
|
||||
daddr_t alt;
|
||||
char specname[64];
|
||||
char blk[1024];
|
||||
char *cp;
|
||||
|
||||
/*
|
||||
* Make name for 'c' partition.
|
||||
*/
|
||||
strcpy(specname, s);
|
||||
cp = specname + strlen(specname) - 1;
|
||||
if (!isdigit(*cp))
|
||||
*cp = 'c';
|
||||
cfd = open(specname, O_WRONLY);
|
||||
if (cfd < 0)
|
||||
fatal("%s: %s", specname, strerror(errno));
|
||||
memset(blk, 0, sizeof(blk));
|
||||
*(struct disklabel *)(blk + LABELOFFSET) = *lp;
|
||||
alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
|
||||
for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
|
||||
if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize,
|
||||
L_SET) == -1)
|
||||
fatal("lseek to badsector area: %s",
|
||||
strerror(errno));
|
||||
if (write(cfd, blk, lp->d_secsize) < lp->d_secsize)
|
||||
fprintf(stderr,
|
||||
"%s: alternate label %d write: %s\n",
|
||||
progname, i/2, strerror(errno));
|
||||
}
|
||||
close(cfd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
if (mfs) {
|
||||
fprintf(stderr,
|
||||
"usage: mfs [ -fsoptions ] special-device mount-point\n");
|
||||
} else
|
||||
fprintf(stderr,
|
||||
"usage: newlfs [ -fsoptions ] special-device%s\n",
|
||||
#ifdef COMPAT
|
||||
" [device-type]");
|
||||
#else
|
||||
"");
|
||||
#endif
|
||||
fprintf(stderr, "where fsoptions are:\n");
|
||||
fprintf(stderr, "\t-B LFS segment size\n");
|
||||
fprintf(stderr, "\t-D debug\n");
|
||||
fprintf(stderr, "\t-F mount flags\n");
|
||||
fprintf(stderr, "\t-L create LFS file system\n");
|
||||
fprintf(stderr,
|
||||
"\t-N do not create file system, just print out parameters\n");
|
||||
fprintf(stderr, "\t-S sector size\n");
|
||||
#ifdef COMPAT
|
||||
fprintf(stderr, "\t-T disktype\n");
|
||||
#endif
|
||||
fprintf(stderr, "\t-a maximum contiguous blocks\n");
|
||||
fprintf(stderr, "\t-b block size\n");
|
||||
fprintf(stderr, "\t-c cylinders/group\n");
|
||||
fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
|
||||
fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
|
||||
fprintf(stderr, "\t-f frag size\n");
|
||||
fprintf(stderr, "\t-i number of bytes per inode\n");
|
||||
fprintf(stderr, "\t-k sector 0 skew, per track\n");
|
||||
fprintf(stderr, "\t-l hardware sector interleave\n");
|
||||
fprintf(stderr, "\t-m minimum free space %%\n");
|
||||
fprintf(stderr, "\t-n number of distinguished rotational positions\n");
|
||||
fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
|
||||
fprintf(stderr, "\t-p spare sectors per track\n");
|
||||
fprintf(stderr, "\t-r revolutions/minute\n");
|
||||
fprintf(stderr, "\t-s file system size (sectors)\n");
|
||||
fprintf(stderr, "\t-t tracks/cylinder\n");
|
||||
fprintf(stderr, "\t-u sectors/track\n");
|
||||
fprintf(stderr, "\t-x spare sectors per cylinder\n");
|
||||
exit(1);
|
||||
}
|
||||
115
sbin/nfsd/nfsd.8
Normal file
115
sbin/nfsd/nfsd.8
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
.\" 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.4 (Berkeley) 3/29/95
|
||||
.\"
|
||||
.Dd March 29, 1995
|
||||
.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 and
|
||||
.%T "NFS: Network File System Version 3 Protocol Specification" .
|
||||
.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.
|
||||
643
sbin/nfsd/nfsd.c
Normal file
643
sbin/nfsd/nfsd.c
Normal file
|
|
@ -0,0 +1,643 @@
|
|||
/*
|
||||
* 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.9 (Berkeley) 3/29/95";
|
||||
#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/nfsproto.h>
|
||||
#include <nfs/nfs.h>
|
||||
|
||||
#ifdef NFSKERB
|
||||
#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 NFSKERB
|
||||
char lnam[ANAME_SZ];
|
||||
KTEXT_ST kt;
|
||||
AUTH_DAT kauth;
|
||||
char inst[INST_SZ];
|
||||
struct nfsrpc_fullblock kin, kout;
|
||||
struct nfsrpc_fullverf kverf;
|
||||
NFSKERBKEY_T kivec;
|
||||
struct timeval ktv;
|
||||
NFSKERBKEYSCHED_T kerb_keysched;
|
||||
#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
|
||||
struct timeval ktv;
|
||||
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, 2, IPPROTO_UDP, NFS_PORT) ||
|
||||
!pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
|
||||
err(1, "can't register with portmap for UDP.");
|
||||
if (tcpflag &&
|
||||
(!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
|
||||
!pmap_set(RPCPROG_NFS, 3, 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("server");
|
||||
nfssvc_flag = NFSSVC_NFSD;
|
||||
nsd.nsd_nfsd = NULL;
|
||||
#ifdef NFSKERB
|
||||
if (sizeof (struct nfsrpc_fullverf) != RPCX_FULLVERF ||
|
||||
sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK)
|
||||
syslog(LOG_ERR, "Yikes NFSKERB structs not packed!");
|
||||
nsd.nsd_authstr = (u_char *)&kt;
|
||||
nsd.nsd_authlen = sizeof (kt);
|
||||
nsd.nsd_verfstr = (u_char *)&kverf;
|
||||
nsd.nsd_verflen = sizeof (kverf);
|
||||
#endif
|
||||
while (nfssvc(nfssvc_flag, &nsd) < 0) {
|
||||
if (errno != ENEEDAUTH) {
|
||||
syslog(LOG_ERR, "nfssvc: %m");
|
||||
exit(1);
|
||||
}
|
||||
nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
|
||||
#ifdef NFSKERB
|
||||
/*
|
||||
* Get the Kerberos ticket out of the authenticator
|
||||
* verify it and convert the principal name to a user
|
||||
* name. The user name is then converted to a set of
|
||||
* user credentials via the password and group file.
|
||||
* Finally, decrypt the timestamp and validate it.
|
||||
* For more info see the IETF Draft "Authentication
|
||||
* in ONC RPC".
|
||||
*/
|
||||
kt.length = ntohl(kt.length);
|
||||
if (gettimeofday(&ktv, (struct timezone *)0) == 0 &&
|
||||
kt.length > 0 && kt.length <=
|
||||
(RPCAUTH_MAXSIZ - 3 * NFSX_UNSIGNED)) {
|
||||
kin.w1 = NFS_KERBW1(kt);
|
||||
kt.mbz = 0;
|
||||
(void)strcpy(inst, "*");
|
||||
if (krb_rd_req(&kt, NFS_KERBSRV,
|
||||
inst, nsd.nsd_haddr, &kauth, "") == RD_AP_OK &&
|
||||
krb_kntoln(&kauth, 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();
|
||||
|
||||
/*
|
||||
* Get the timestamp verifier out of the
|
||||
* authenticator and verifier strings.
|
||||
*/
|
||||
kin.t1 = kverf.t1;
|
||||
kin.t2 = kverf.t2;
|
||||
kin.w2 = kverf.w2;
|
||||
bzero((caddr_t)kivec, sizeof (kivec));
|
||||
bcopy((caddr_t)kauth.session,
|
||||
(caddr_t)nsd.nsd_key,sizeof(kauth.session));
|
||||
|
||||
/*
|
||||
* Decrypt the timestamp verifier in CBC mode.
|
||||
*/
|
||||
XXX
|
||||
|
||||
/*
|
||||
* Validate the timestamp verifier, to
|
||||
* check that the session key is ok.
|
||||
*/
|
||||
nsd.nsd_timestamp.tv_sec = ntohl(kout.t1);
|
||||
nsd.nsd_timestamp.tv_usec = ntohl(kout.t2);
|
||||
nsd.nsd_ttl = ntohl(kout.w1);
|
||||
if ((nsd.nsd_ttl - 1) == ntohl(kout.w2))
|
||||
nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
|
||||
}
|
||||
#endif /* NFSKERB */
|
||||
}
|
||||
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, 2, IPPROTO_UDP, NFS_PORT) ||
|
||||
!pmap_set(RPCPROG_NFS, 3, 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, 2, IPPROTO_TCP, NFS_PORT) ||
|
||||
!pmap_set(RPCPROG_NFS, 3, 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("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, "usage: 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) > 0);
|
||||
}
|
||||
|
||||
void
|
||||
setproctitle(a)
|
||||
char *a;
|
||||
{
|
||||
register char *cp;
|
||||
char buf[80];
|
||||
|
||||
cp = Argv[0];
|
||||
(void)snprintf(buf, sizeof(buf), "nfsd-%s", a);
|
||||
(void)strncpy(cp, buf, LastArg - cp);
|
||||
cp += strlen(cp);
|
||||
while (cp < LastArg)
|
||||
*cp++ = '\0';
|
||||
}
|
||||
170
sbin/nfsiod/nfsiod.c
Normal file
170
sbin/nfsiod/nfsiod.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* 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\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif not lint
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)nfsiod.c 8.4 (Berkeley) 5/3/95";
|
||||
#endif not lint
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <sys/time.h>
|
||||
#include <nfs/rpcv2.h>
|
||||
#include <nfs/nfsproto.h>
|
||||
#include <nfs/nfs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Global defs */
|
||||
#ifdef DEBUG
|
||||
int debug = 1;
|
||||
#else
|
||||
int debug = 0;
|
||||
#endif
|
||||
|
||||
void nonfs __P((int));
|
||||
void reapchild __P((int));
|
||||
void usage __P((void));
|
||||
|
||||
/*
|
||||
* Nfsiod does asynchronous buffered I/O on behalf of the NFS client.
|
||||
* It does not have to be running for correct operation, but will
|
||||
* improve throughput.
|
||||
*/
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch, num_servers;
|
||||
|
||||
#define MAXNFSDCNT 20
|
||||
#define DEFNFSDCNT 1
|
||||
num_servers = DEFNFSDCNT;
|
||||
while ((ch = getopt(argc, argv, "n:")) != EOF)
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
num_servers = atoi(optarg);
|
||||
if (num_servers < 1 || num_servers > MAXNFSDCNT) {
|
||||
warnx("nfsiod count %d; reset to %d",
|
||||
DEFNFSDCNT);
|
||||
num_servers = DEFNFSDCNT;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Backward compatibility, trailing number is the count of daemons.
|
||||
*/
|
||||
if (argc > 1)
|
||||
usage();
|
||||
if (argc == 1) {
|
||||
num_servers = atoi(argv[0]);
|
||||
if (num_servers < 1 || num_servers > MAXNFSDCNT) {
|
||||
warnx("nfsiod count %d; reset to %d", DEFNFSDCNT);
|
||||
num_servers = 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(SIGCHLD, reapchild);
|
||||
|
||||
openlog("nfsiod:", LOG_PID, LOG_DAEMON);
|
||||
|
||||
while (num_servers--)
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
syslog(LOG_ERR, "fork: %m");
|
||||
exit (1);
|
||||
case 0:
|
||||
if (nfssvc(NFSSVC_BIOD, NULL) < 0) {
|
||||
syslog(LOG_ERR, "nfssvc: %m");
|
||||
exit (1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
|
||||
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
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage: nfsiod [-n num_servers]\n");
|
||||
exit(1);
|
||||
}
|
||||
609
sbin/quotacheck/quotacheck.c
Normal file
609
sbin/quotacheck/quotacheck.c
Normal file
|
|
@ -0,0 +1,609 @@
|
|||
/*
|
||||
* Copyright (c) 1980, 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Robert Elz at The University of Melbourne.
|
||||
*
|
||||
* 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, 1990, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)quotacheck.c 8.6 (Berkeley) 4/28/95";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Fix up / report on disk quotas & usage
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/quota.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fstab.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
|
||||
char *qfname = QUOTAFILENAME;
|
||||
char *qfextension[] = INITQFNAMES;
|
||||
char *quotagroup = QUOTAGROUP;
|
||||
|
||||
union {
|
||||
struct fs sblk;
|
||||
char dummy[MAXBSIZE];
|
||||
} un;
|
||||
#define sblock un.sblk
|
||||
long dev_bsize;
|
||||
long maxino;
|
||||
|
||||
struct quotaname {
|
||||
long flags;
|
||||
char grpqfname[MAXPATHLEN + 1];
|
||||
char usrqfname[MAXPATHLEN + 1];
|
||||
};
|
||||
#define HASUSR 1
|
||||
#define HASGRP 2
|
||||
|
||||
struct fileusage {
|
||||
struct fileusage *fu_next;
|
||||
u_long fu_curinodes;
|
||||
u_long fu_curblocks;
|
||||
u_long fu_id;
|
||||
char fu_name[1];
|
||||
/* actually bigger */
|
||||
};
|
||||
#define FUHASH 1024 /* must be power of two */
|
||||
struct fileusage *fuhead[MAXQUOTAS][FUHASH];
|
||||
|
||||
int aflag; /* all file systems */
|
||||
int gflag; /* check group quotas */
|
||||
int uflag; /* check user quotas */
|
||||
int vflag; /* verbose */
|
||||
int fi; /* open disk file descriptor */
|
||||
u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
|
||||
|
||||
struct fileusage *
|
||||
addid __P((u_long, int, char *));
|
||||
char *blockcheck __P((char *));
|
||||
void bread __P((daddr_t, char *, long));
|
||||
int chkquota __P((char *, char *, struct quotaname *));
|
||||
void freeinodebuf __P((void));
|
||||
struct dinode *
|
||||
getnextinode __P((ino_t));
|
||||
int getquotagid __P((void));
|
||||
int hasquota __P((struct fstab *, int, char **));
|
||||
struct fileusage *
|
||||
lookup __P((u_long, int));
|
||||
void *needchk __P((struct fstab *));
|
||||
int oneof __P((char *, char*[], int));
|
||||
void resetinodebuf __P((void));
|
||||
int update __P((char *, char *, int));
|
||||
void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register struct fstab *fs;
|
||||
register struct passwd *pw;
|
||||
register struct group *gr;
|
||||
struct quotaname *auxdata;
|
||||
int i, argnum, maxrun, errs;
|
||||
long done = 0;
|
||||
char ch, *name;
|
||||
|
||||
errs = maxrun = 0;
|
||||
while ((ch = getopt(argc, argv, "aguvl:")) != EOF) {
|
||||
switch(ch) {
|
||||
case 'a':
|
||||
aflag++;
|
||||
break;
|
||||
case 'g':
|
||||
gflag++;
|
||||
break;
|
||||
case 'u':
|
||||
uflag++;
|
||||
break;
|
||||
case 'v':
|
||||
vflag++;
|
||||
break;
|
||||
case 'l':
|
||||
maxrun = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if ((argc == 0 && !aflag) || (argc > 0 && aflag))
|
||||
usage();
|
||||
if (!gflag && !uflag) {
|
||||
gflag++;
|
||||
uflag++;
|
||||
}
|
||||
if (gflag) {
|
||||
setgrent();
|
||||
while ((gr = getgrent()) != 0)
|
||||
(void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
|
||||
endgrent();
|
||||
}
|
||||
if (uflag) {
|
||||
setpwent();
|
||||
while ((pw = getpwent()) != 0)
|
||||
(void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
|
||||
endpwent();
|
||||
}
|
||||
if (aflag)
|
||||
exit(checkfstab(1, maxrun, needchk, chkquota));
|
||||
if (setfsent() == 0)
|
||||
err(1, "%s: can't open", FSTAB);
|
||||
while ((fs = getfsent()) != NULL) {
|
||||
if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
|
||||
(argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
|
||||
(auxdata = needchk(fs)) &&
|
||||
(name = blockcheck(fs->fs_spec))) {
|
||||
done |= 1 << argnum;
|
||||
errs += chkquota(name, fs->fs_file, auxdata);
|
||||
}
|
||||
}
|
||||
endfsent();
|
||||
for (i = 0; i < argc; i++)
|
||||
if ((done & (1 << i)) == 0)
|
||||
fprintf(stderr, "%s not found in %s\n",
|
||||
argv[i], FSTAB);
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage:\t%s\n\t%s\n",
|
||||
"quotacheck -a [-guv]",
|
||||
"quotacheck [-guv] filesys ...");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void *
|
||||
needchk(fs)
|
||||
register struct fstab *fs;
|
||||
{
|
||||
register struct quotaname *qnp;
|
||||
char *qfnp;
|
||||
|
||||
if (strcmp(fs->fs_vfstype, "ufs") ||
|
||||
strcmp(fs->fs_type, FSTAB_RW))
|
||||
return (NULL);
|
||||
if ((qnp = malloc(sizeof(*qnp))) == NULL)
|
||||
err(1, "%s", strerror(errno));
|
||||
qnp->flags = 0;
|
||||
if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) {
|
||||
strcpy(qnp->grpqfname, qfnp);
|
||||
qnp->flags |= HASGRP;
|
||||
}
|
||||
if (uflag && hasquota(fs, USRQUOTA, &qfnp)) {
|
||||
strcpy(qnp->usrqfname, qfnp);
|
||||
qnp->flags |= HASUSR;
|
||||
}
|
||||
if (qnp->flags)
|
||||
return (qnp);
|
||||
free(qnp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan the specified filesystem to check quota(s) present on it.
|
||||
*/
|
||||
int
|
||||
chkquota(fsname, mntpt, qnp)
|
||||
char *fsname, *mntpt;
|
||||
register struct quotaname *qnp;
|
||||
{
|
||||
register struct fileusage *fup;
|
||||
register struct dinode *dp;
|
||||
int cg, i, mode, errs = 0;
|
||||
ino_t ino;
|
||||
|
||||
if ((fi = open(fsname, O_RDONLY, 0)) < 0) {
|
||||
perror(fsname);
|
||||
return (1);
|
||||
}
|
||||
if (vflag) {
|
||||
(void)printf("*** Checking ");
|
||||
if (qnp->flags & HASUSR)
|
||||
(void)printf("%s%s", qfextension[USRQUOTA],
|
||||
(qnp->flags & HASGRP) ? " and " : "");
|
||||
if (qnp->flags & HASGRP)
|
||||
(void)printf("%s", qfextension[GRPQUOTA]);
|
||||
(void)printf(" quotas for %s (%s)\n", fsname, mntpt);
|
||||
}
|
||||
sync();
|
||||
dev_bsize = 1;
|
||||
bread(SBOFF, (char *)&sblock, (long)SBSIZE);
|
||||
dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
|
||||
maxino = sblock.fs_ncg * sblock.fs_ipg;
|
||||
resetinodebuf();
|
||||
for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, ino++) {
|
||||
if (ino < ROOTINO)
|
||||
continue;
|
||||
if ((dp = getnextinode(ino)) == NULL)
|
||||
continue;
|
||||
if ((mode = dp->di_mode & IFMT) == 0)
|
||||
continue;
|
||||
if (qnp->flags & HASGRP) {
|
||||
fup = addid((u_long)dp->di_gid, GRPQUOTA,
|
||||
(char *)0);
|
||||
fup->fu_curinodes++;
|
||||
if (mode == IFREG || mode == IFDIR ||
|
||||
mode == IFLNK)
|
||||
fup->fu_curblocks += dp->di_blocks;
|
||||
}
|
||||
if (qnp->flags & HASUSR) {
|
||||
fup = addid((u_long)dp->di_uid, USRQUOTA,
|
||||
(char *)0);
|
||||
fup->fu_curinodes++;
|
||||
if (mode == IFREG || mode == IFDIR ||
|
||||
mode == IFLNK)
|
||||
fup->fu_curblocks += dp->di_blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeinodebuf();
|
||||
if (qnp->flags & HASUSR)
|
||||
errs += update(mntpt, qnp->usrqfname, USRQUOTA);
|
||||
if (qnp->flags & HASGRP)
|
||||
errs += update(mntpt, qnp->grpqfname, GRPQUOTA);
|
||||
close(fi);
|
||||
return (errs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update a specified quota file.
|
||||
*/
|
||||
int
|
||||
update(fsname, quotafile, type)
|
||||
char *fsname, *quotafile;
|
||||
register int type;
|
||||
{
|
||||
register struct fileusage *fup;
|
||||
register FILE *qfi, *qfo;
|
||||
register u_long id, lastid;
|
||||
struct dqblk dqbuf;
|
||||
static int warned = 0;
|
||||
static struct dqblk zerodqbuf;
|
||||
static struct fileusage zerofileusage;
|
||||
|
||||
if ((qfo = fopen(quotafile, "r+")) == NULL) {
|
||||
if (errno == ENOENT)
|
||||
qfo = fopen(quotafile, "w+");
|
||||
if (qfo) {
|
||||
(void) fprintf(stderr,
|
||||
"quotacheck: creating quota file %s\n", quotafile);
|
||||
#define MODE (S_IRUSR|S_IWUSR|S_IRGRP)
|
||||
(void) fchown(fileno(qfo), getuid(), getquotagid());
|
||||
(void) fchmod(fileno(qfo), MODE);
|
||||
} else {
|
||||
(void) fprintf(stderr,
|
||||
"quotacheck: %s: %s\n", quotafile, strerror(errno));
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
if ((qfi = fopen(quotafile, "r")) == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
"quotacheck: %s: %s\n", quotafile, strerror(errno));
|
||||
(void) fclose(qfo);
|
||||
return (1);
|
||||
}
|
||||
if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 &&
|
||||
errno == EOPNOTSUPP && !warned && vflag) {
|
||||
warned++;
|
||||
(void)printf("*** Warning: %s\n",
|
||||
"Quotas are not compiled into this kernel");
|
||||
}
|
||||
for (lastid = highid[type], id = 0; id <= lastid; id++) {
|
||||
if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0)
|
||||
dqbuf = zerodqbuf;
|
||||
if ((fup = lookup(id, type)) == 0)
|
||||
fup = &zerofileusage;
|
||||
if (dqbuf.dqb_curinodes == fup->fu_curinodes &&
|
||||
dqbuf.dqb_curblocks == fup->fu_curblocks) {
|
||||
fup->fu_curinodes = 0;
|
||||
fup->fu_curblocks = 0;
|
||||
fseek(qfo, (long)sizeof(struct dqblk), 1);
|
||||
continue;
|
||||
}
|
||||
if (vflag) {
|
||||
if (aflag)
|
||||
printf("%s: ", fsname);
|
||||
printf("%-8s fixed:", fup->fu_name);
|
||||
if (dqbuf.dqb_curinodes != fup->fu_curinodes)
|
||||
(void)printf("\tinodes %d -> %d",
|
||||
dqbuf.dqb_curinodes, fup->fu_curinodes);
|
||||
if (dqbuf.dqb_curblocks != fup->fu_curblocks)
|
||||
(void)printf("\tblocks %d -> %d",
|
||||
dqbuf.dqb_curblocks, fup->fu_curblocks);
|
||||
(void)printf("\n");
|
||||
}
|
||||
/*
|
||||
* Reset time limit if have a soft limit and were
|
||||
* previously under it, but are now over it.
|
||||
*/
|
||||
if (dqbuf.dqb_bsoftlimit &&
|
||||
dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
|
||||
fup->fu_curblocks >= dqbuf.dqb_bsoftlimit)
|
||||
dqbuf.dqb_btime = 0;
|
||||
if (dqbuf.dqb_isoftlimit &&
|
||||
dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit &&
|
||||
fup->fu_curblocks >= dqbuf.dqb_isoftlimit)
|
||||
dqbuf.dqb_itime = 0;
|
||||
dqbuf.dqb_curinodes = fup->fu_curinodes;
|
||||
dqbuf.dqb_curblocks = fup->fu_curblocks;
|
||||
fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
|
||||
(void) quotactl(fsname, QCMD(Q_SETUSE, type), id,
|
||||
(caddr_t)&dqbuf);
|
||||
fup->fu_curinodes = 0;
|
||||
fup->fu_curblocks = 0;
|
||||
}
|
||||
fclose(qfi);
|
||||
fflush(qfo);
|
||||
ftruncate(fileno(qfo),
|
||||
(off_t)((highid[type] + 1) * sizeof(struct dqblk)));
|
||||
fclose(qfo);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if target appears in list of size cnt.
|
||||
*/
|
||||
int
|
||||
oneof(target, list, cnt)
|
||||
register char *target, *list[];
|
||||
int cnt;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < cnt; i++)
|
||||
if (strcmp(target, list[i]) == 0)
|
||||
return (i);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the group identifier for quota files.
|
||||
*/
|
||||
int
|
||||
getquotagid()
|
||||
{
|
||||
struct group *gr;
|
||||
|
||||
if (gr = getgrnam(quotagroup))
|
||||
return (gr->gr_gid);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if a particular quota is to be enabled.
|
||||
*/
|
||||
int
|
||||
hasquota(fs, type, qfnamep)
|
||||
register struct fstab *fs;
|
||||
int type;
|
||||
char **qfnamep;
|
||||
{
|
||||
register char *opt;
|
||||
char *cp;
|
||||
static char initname, usrname[100], grpname[100];
|
||||
static char buf[BUFSIZ];
|
||||
|
||||
if (!initname) {
|
||||
(void)snprintf(usrname, sizeof(usrname),
|
||||
"%s%s", qfextension[USRQUOTA], qfname);
|
||||
(void)snprintf(grpname, sizeof(grpname),
|
||||
"%s%s", qfextension[GRPQUOTA], qfname);
|
||||
initname = 1;
|
||||
}
|
||||
strcpy(buf, fs->fs_mntops);
|
||||
for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
|
||||
if (cp = strchr(opt, '='))
|
||||
*cp++ = '\0';
|
||||
if (type == USRQUOTA && strcmp(opt, usrname) == 0)
|
||||
break;
|
||||
if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
|
||||
break;
|
||||
}
|
||||
if (!opt)
|
||||
return (0);
|
||||
if (cp)
|
||||
*qfnamep = cp;
|
||||
else {
|
||||
(void)snprintf(buf, sizeof(buf),
|
||||
"%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
|
||||
*qfnamep = buf;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines to manage the file usage table.
|
||||
*
|
||||
* Lookup an id of a specific type.
|
||||
*/
|
||||
struct fileusage *
|
||||
lookup(id, type)
|
||||
u_long id;
|
||||
int type;
|
||||
{
|
||||
register struct fileusage *fup;
|
||||
|
||||
for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
|
||||
if (fup->fu_id == id)
|
||||
return (fup);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new file usage id if it does not already exist.
|
||||
*/
|
||||
struct fileusage *
|
||||
addid(id, type, name)
|
||||
u_long id;
|
||||
int type;
|
||||
char *name;
|
||||
{
|
||||
struct fileusage *fup, **fhp;
|
||||
int len;
|
||||
|
||||
if (fup = lookup(id, type))
|
||||
return (fup);
|
||||
if (name)
|
||||
len = strlen(name);
|
||||
else
|
||||
len = 10;
|
||||
if ((fup = calloc(1, sizeof(*fup) + len)) == NULL)
|
||||
err(1, "%s", strerror(errno));
|
||||
fhp = &fuhead[type][id & (FUHASH - 1)];
|
||||
fup->fu_next = *fhp;
|
||||
*fhp = fup;
|
||||
fup->fu_id = id;
|
||||
if (id > highid[type])
|
||||
highid[type] = id;
|
||||
if (name)
|
||||
memmove(fup->fu_name, name, len + 1);
|
||||
else
|
||||
(void)sprintf(fup->fu_name, "%u", id);
|
||||
return (fup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special purpose version of ginode used to optimize pass
|
||||
* over all the inodes in numerical order.
|
||||
*/
|
||||
ino_t nextino, lastinum;
|
||||
long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
|
||||
struct dinode *inodebuf;
|
||||
#define INOBUFSIZE 56*1024 /* size of buffer to read inodes */
|
||||
|
||||
struct dinode *
|
||||
getnextinode(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
long size;
|
||||
daddr_t dblk;
|
||||
static struct dinode *dp;
|
||||
|
||||
if (inumber != nextino++ || inumber > maxino)
|
||||
err(1, "bad inode number %d to nextinode", 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;
|
||||
}
|
||||
bread(dblk, (char *)inodebuf, size);
|
||||
dp = inodebuf;
|
||||
}
|
||||
return (dp++);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare to scan a set of inodes.
|
||||
*/
|
||||
void
|
||||
resetinodebuf()
|
||||
{
|
||||
|
||||
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 = malloc((u_int)inobufsize)) == NULL)
|
||||
err(1, "%s", strerror(errno));
|
||||
while (nextino < ROOTINO)
|
||||
getnextinode(nextino);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up data structures used to scan inodes.
|
||||
*/
|
||||
void
|
||||
freeinodebuf()
|
||||
{
|
||||
|
||||
if (inodebuf != NULL)
|
||||
free(inodebuf);
|
||||
inodebuf = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read specified disk blocks.
|
||||
*/
|
||||
void
|
||||
bread(bno, buf, cnt)
|
||||
daddr_t bno;
|
||||
char *buf;
|
||||
long cnt;
|
||||
{
|
||||
|
||||
if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 ||
|
||||
read(fi, buf, cnt) != cnt)
|
||||
err(1, "block %ld", bno);
|
||||
}
|
||||
753
sbin/restore/dirs.c
Normal file
753
sbin/restore/dirs.c
Normal file
|
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <machine/endian.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "restore.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* Symbol table of directories read from tape.
|
||||
*/
|
||||
#define HASHSIZE 1000
|
||||
#define INOHASH(val) (val % HASHSIZE)
|
||||
struct inotab {
|
||||
struct inotab *t_next;
|
||||
ino_t t_ino;
|
||||
long t_seekpt;
|
||||
long t_size;
|
||||
};
|
||||
static struct inotab *inotab[HASHSIZE];
|
||||
|
||||
/*
|
||||
* Information retained about directories.
|
||||
*/
|
||||
struct modeinfo {
|
||||
ino_t ino;
|
||||
struct timeval timep[2];
|
||||
mode_t mode;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
int flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Definitions for library routines operating on directories.
|
||||
*/
|
||||
#undef DIRBLKSIZ
|
||||
#define DIRBLKSIZ 1024
|
||||
struct rstdirdesc {
|
||||
int dd_fd;
|
||||
long dd_loc;
|
||||
long dd_size;
|
||||
char dd_buf[DIRBLKSIZ];
|
||||
};
|
||||
|
||||
/*
|
||||
* Global variables for this file.
|
||||
*/
|
||||
static long seekpt;
|
||||
static FILE *df, *mf;
|
||||
static RST_DIR *dirp;
|
||||
static char dirfile[32] = "#"; /* No file */
|
||||
static char modefile[32] = "#"; /* No file */
|
||||
static char dot[2] = "."; /* So it can be modified */
|
||||
|
||||
/*
|
||||
* Format of old style directories.
|
||||
*/
|
||||
#define ODIRSIZ 14
|
||||
struct odirect {
|
||||
u_short d_ino;
|
||||
char d_name[ODIRSIZ];
|
||||
};
|
||||
|
||||
static struct inotab *allocinotab __P((ino_t, struct dinode *, long));
|
||||
static void dcvt __P((struct odirect *, struct direct *));
|
||||
static void flushent __P((void));
|
||||
static struct inotab *inotablookup __P((ino_t));
|
||||
static RST_DIR *opendirfile __P((const char *));
|
||||
static void putdir __P((char *, long));
|
||||
static void putent __P((struct direct *));
|
||||
static void rst_seekdir __P((RST_DIR *, long, long));
|
||||
static long rst_telldir __P((RST_DIR *));
|
||||
static struct direct *searchdir __P((ino_t, char *));
|
||||
|
||||
/*
|
||||
* Extract directory contents, building up a directory structure
|
||||
* on disk for extraction by name.
|
||||
* If genmode is requested, save mode, owner, and times for all
|
||||
* directories on the tape.
|
||||
*/
|
||||
void
|
||||
extractdirs(genmode)
|
||||
int genmode;
|
||||
{
|
||||
register int i;
|
||||
register struct dinode *ip;
|
||||
struct inotab *itp;
|
||||
struct direct nulldir;
|
||||
|
||||
vprintf(stdout, "Extract directories from tape\n");
|
||||
(void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate);
|
||||
df = fopen(dirfile, "w");
|
||||
if (df == NULL) {
|
||||
fprintf(stderr,
|
||||
"restore: %s - cannot create directory temporary\n",
|
||||
dirfile);
|
||||
fprintf(stderr, "fopen: %s\n", strerror(errno));
|
||||
done(1);
|
||||
}
|
||||
if (genmode != 0) {
|
||||
(void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
|
||||
mf = fopen(modefile, "w");
|
||||
if (mf == NULL) {
|
||||
fprintf(stderr,
|
||||
"restore: %s - cannot create modefile \n",
|
||||
modefile);
|
||||
fprintf(stderr, "fopen: %s\n", strerror(errno));
|
||||
done(1);
|
||||
}
|
||||
}
|
||||
nulldir.d_ino = 0;
|
||||
nulldir.d_type = DT_DIR;
|
||||
nulldir.d_namlen = 1;
|
||||
(void) strcpy(nulldir.d_name, "/");
|
||||
nulldir.d_reclen = DIRSIZ(0, &nulldir);
|
||||
for (;;) {
|
||||
curfile.name = "<directory file - name unknown>";
|
||||
curfile.action = USING;
|
||||
ip = curfile.dip;
|
||||
if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
|
||||
(void) fclose(df);
|
||||
dirp = opendirfile(dirfile);
|
||||
if (dirp == NULL)
|
||||
fprintf(stderr, "opendirfile: %s\n",
|
||||
strerror(errno));
|
||||
if (mf != NULL)
|
||||
(void) fclose(mf);
|
||||
i = dirlookup(dot);
|
||||
if (i == 0)
|
||||
panic("Root directory is not on tape\n");
|
||||
return;
|
||||
}
|
||||
itp = allocinotab(curfile.ino, ip, seekpt);
|
||||
getfile(putdir, xtrnull);
|
||||
putent(&nulldir);
|
||||
flushent();
|
||||
itp->t_size = seekpt - itp->t_seekpt;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* skip over all the directories on the tape
|
||||
*/
|
||||
void
|
||||
skipdirs()
|
||||
{
|
||||
|
||||
while ((curfile.dip->di_mode & IFMT) == IFDIR) {
|
||||
skipfile();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively find names and inumbers of all files in subtree
|
||||
* pname and pass them off to be processed.
|
||||
*/
|
||||
void
|
||||
treescan(pname, ino, todo)
|
||||
char *pname;
|
||||
ino_t ino;
|
||||
long (*todo) __P((char *, ino_t, int));
|
||||
{
|
||||
register struct inotab *itp;
|
||||
register struct direct *dp;
|
||||
int namelen;
|
||||
long bpt;
|
||||
char locname[MAXPATHLEN + 1];
|
||||
|
||||
itp = inotablookup(ino);
|
||||
if (itp == NULL) {
|
||||
/*
|
||||
* Pname is name of a simple file or an unchanged directory.
|
||||
*/
|
||||
(void) (*todo)(pname, ino, LEAF);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Pname is a dumped directory name.
|
||||
*/
|
||||
if ((*todo)(pname, ino, NODE) == FAIL)
|
||||
return;
|
||||
/*
|
||||
* begin search through the directory
|
||||
* skipping over "." and ".."
|
||||
*/
|
||||
(void) strncpy(locname, pname, MAXPATHLEN);
|
||||
(void) strncat(locname, "/", MAXPATHLEN);
|
||||
namelen = strlen(locname);
|
||||
rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
|
||||
dp = rst_readdir(dirp); /* "." */
|
||||
if (dp != NULL && strcmp(dp->d_name, ".") == 0)
|
||||
dp = rst_readdir(dirp); /* ".." */
|
||||
else
|
||||
fprintf(stderr, "Warning: `.' missing from directory %s\n",
|
||||
pname);
|
||||
if (dp != NULL && strcmp(dp->d_name, "..") == 0)
|
||||
dp = rst_readdir(dirp); /* first real entry */
|
||||
else
|
||||
fprintf(stderr, "Warning: `..' missing from directory %s\n",
|
||||
pname);
|
||||
bpt = rst_telldir(dirp);
|
||||
/*
|
||||
* a zero inode signals end of directory
|
||||
*/
|
||||
while (dp != NULL) {
|
||||
locname[namelen] = '\0';
|
||||
if (namelen + dp->d_namlen >= MAXPATHLEN) {
|
||||
fprintf(stderr, "%s%s: name exceeds %d char\n",
|
||||
locname, dp->d_name, MAXPATHLEN);
|
||||
} else {
|
||||
(void) strncat(locname, dp->d_name, (int)dp->d_namlen);
|
||||
treescan(locname, dp->d_ino, todo);
|
||||
rst_seekdir(dirp, bpt, itp->t_seekpt);
|
||||
}
|
||||
dp = rst_readdir(dirp);
|
||||
bpt = rst_telldir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup a pathname which is always assumed to start from the ROOTINO.
|
||||
*/
|
||||
struct direct *
|
||||
pathsearch(pathname)
|
||||
const char *pathname;
|
||||
{
|
||||
ino_t ino;
|
||||
struct direct *dp;
|
||||
char *path, *name, buffer[MAXPATHLEN];
|
||||
|
||||
strcpy(buffer, pathname);
|
||||
path = buffer;
|
||||
ino = ROOTINO;
|
||||
while (*path == '/')
|
||||
path++;
|
||||
dp = NULL;
|
||||
while ((name = strsep(&path, "/")) != NULL && *name != NULL) {
|
||||
if ((dp = searchdir(ino, name)) == NULL)
|
||||
return (NULL);
|
||||
ino = dp->d_ino;
|
||||
}
|
||||
return (dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup the requested name in directory inum.
|
||||
* Return its inode number if found, zero if it does not exist.
|
||||
*/
|
||||
static struct direct *
|
||||
searchdir(inum, name)
|
||||
ino_t inum;
|
||||
char *name;
|
||||
{
|
||||
register struct direct *dp;
|
||||
register struct inotab *itp;
|
||||
int len;
|
||||
|
||||
itp = inotablookup(inum);
|
||||
if (itp == NULL)
|
||||
return (NULL);
|
||||
rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
|
||||
len = strlen(name);
|
||||
do {
|
||||
dp = rst_readdir(dirp);
|
||||
if (dp == NULL)
|
||||
return (NULL);
|
||||
} while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0);
|
||||
return (dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the directory entries in the directory file
|
||||
*/
|
||||
static void
|
||||
putdir(buf, size)
|
||||
char *buf;
|
||||
long size;
|
||||
{
|
||||
struct direct cvtbuf;
|
||||
register struct odirect *odp;
|
||||
struct odirect *eodp;
|
||||
register struct direct *dp;
|
||||
long loc, i;
|
||||
|
||||
if (cvtflag) {
|
||||
eodp = (struct odirect *)&buf[size];
|
||||
for (odp = (struct odirect *)buf; odp < eodp; odp++)
|
||||
if (odp->d_ino != 0) {
|
||||
dcvt(odp, &cvtbuf);
|
||||
putent(&cvtbuf);
|
||||
}
|
||||
} else {
|
||||
for (loc = 0; loc < size; ) {
|
||||
dp = (struct direct *)(buf + loc);
|
||||
if (Bcvt)
|
||||
swabst((u_char *)"ls", (u_char *) dp);
|
||||
if (oldinofmt && dp->d_ino != 0) {
|
||||
# if BYTE_ORDER == BIG_ENDIAN
|
||||
if (Bcvt)
|
||||
dp->d_namlen = dp->d_type;
|
||||
# else
|
||||
if (!Bcvt)
|
||||
dp->d_namlen = dp->d_type;
|
||||
# endif
|
||||
dp->d_type = DT_UNKNOWN;
|
||||
}
|
||||
i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
|
||||
if ((dp->d_reclen & 0x3) != 0 ||
|
||||
dp->d_reclen > i ||
|
||||
dp->d_reclen < DIRSIZ(0, dp) ||
|
||||
dp->d_namlen > NAME_MAX) {
|
||||
vprintf(stdout, "Mangled directory: ");
|
||||
if ((dp->d_reclen & 0x3) != 0)
|
||||
vprintf(stdout,
|
||||
"reclen not multiple of 4 ");
|
||||
if (dp->d_reclen < DIRSIZ(0, dp))
|
||||
vprintf(stdout,
|
||||
"reclen less than DIRSIZ (%d < %d) ",
|
||||
dp->d_reclen, DIRSIZ(0, dp));
|
||||
if (dp->d_namlen > NAME_MAX)
|
||||
vprintf(stdout,
|
||||
"reclen name too big (%d > %d) ",
|
||||
dp->d_namlen, NAME_MAX);
|
||||
vprintf(stdout, "\n");
|
||||
loc += i;
|
||||
continue;
|
||||
}
|
||||
loc += dp->d_reclen;
|
||||
if (dp->d_ino != 0) {
|
||||
putent(dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* These variables are "local" to the following two functions.
|
||||
*/
|
||||
char dirbuf[DIRBLKSIZ];
|
||||
long dirloc = 0;
|
||||
long prev = 0;
|
||||
|
||||
/*
|
||||
* add a new directory entry to a file.
|
||||
*/
|
||||
static void
|
||||
putent(dp)
|
||||
struct direct *dp;
|
||||
{
|
||||
dp->d_reclen = DIRSIZ(0, dp);
|
||||
if (dirloc + dp->d_reclen > DIRBLKSIZ) {
|
||||
((struct direct *)(dirbuf + prev))->d_reclen =
|
||||
DIRBLKSIZ - prev;
|
||||
(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
|
||||
dirloc = 0;
|
||||
}
|
||||
memmove(dirbuf + dirloc, dp, (long)dp->d_reclen);
|
||||
prev = dirloc;
|
||||
dirloc += dp->d_reclen;
|
||||
}
|
||||
|
||||
/*
|
||||
* flush out a directory that is finished.
|
||||
*/
|
||||
static void
|
||||
flushent()
|
||||
{
|
||||
((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
|
||||
(void) fwrite(dirbuf, (int)dirloc, 1, df);
|
||||
seekpt = ftell(df);
|
||||
dirloc = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dcvt(odp, ndp)
|
||||
register struct odirect *odp;
|
||||
register struct direct *ndp;
|
||||
{
|
||||
|
||||
memset(ndp, 0, (long)(sizeof *ndp));
|
||||
ndp->d_ino = odp->d_ino;
|
||||
ndp->d_type = DT_UNKNOWN;
|
||||
(void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
|
||||
ndp->d_namlen = strlen(ndp->d_name);
|
||||
ndp->d_reclen = DIRSIZ(0, ndp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Seek to an entry in a directory.
|
||||
* Only values returned by rst_telldir should be passed to rst_seekdir.
|
||||
* This routine handles many directories in a single file.
|
||||
* It takes the base of the directory in the file, plus
|
||||
* the desired seek offset into it.
|
||||
*/
|
||||
static void
|
||||
rst_seekdir(dirp, loc, base)
|
||||
register RST_DIR *dirp;
|
||||
long loc, base;
|
||||
{
|
||||
|
||||
if (loc == rst_telldir(dirp))
|
||||
return;
|
||||
loc -= base;
|
||||
if (loc < 0)
|
||||
fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
|
||||
(void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
|
||||
dirp->dd_loc = loc & (DIRBLKSIZ - 1);
|
||||
if (dirp->dd_loc != 0)
|
||||
dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* get next entry in a directory.
|
||||
*/
|
||||
struct direct *
|
||||
rst_readdir(dirp)
|
||||
register RST_DIR *dirp;
|
||||
{
|
||||
register struct direct *dp;
|
||||
|
||||
for (;;) {
|
||||
if (dirp->dd_loc == 0) {
|
||||
dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
|
||||
DIRBLKSIZ);
|
||||
if (dirp->dd_size <= 0) {
|
||||
dprintf(stderr, "error reading directory\n");
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
if (dirp->dd_loc >= dirp->dd_size) {
|
||||
dirp->dd_loc = 0;
|
||||
continue;
|
||||
}
|
||||
dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
|
||||
if (dp->d_reclen == 0 ||
|
||||
dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
|
||||
dprintf(stderr, "corrupted directory: bad reclen %d\n",
|
||||
dp->d_reclen);
|
||||
return (NULL);
|
||||
}
|
||||
dirp->dd_loc += dp->d_reclen;
|
||||
if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0)
|
||||
return (NULL);
|
||||
if (dp->d_ino >= maxino) {
|
||||
dprintf(stderr, "corrupted directory: bad inum %d\n",
|
||||
dp->d_ino);
|
||||
continue;
|
||||
}
|
||||
return (dp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Simulate the opening of a directory
|
||||
*/
|
||||
RST_DIR *
|
||||
rst_opendir(name)
|
||||
const char *name;
|
||||
{
|
||||
struct inotab *itp;
|
||||
RST_DIR *dirp;
|
||||
ino_t ino;
|
||||
|
||||
if ((ino = dirlookup(name)) > 0 &&
|
||||
(itp = inotablookup(ino)) != NULL) {
|
||||
dirp = opendirfile(dirfile);
|
||||
rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
|
||||
return (dirp);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* In our case, there is nothing to do when closing a directory.
|
||||
*/
|
||||
void
|
||||
rst_closedir(dirp)
|
||||
RST_DIR *dirp;
|
||||
{
|
||||
|
||||
(void)close(dirp->dd_fd);
|
||||
free(dirp);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simulate finding the current offset in the directory.
|
||||
*/
|
||||
static long
|
||||
rst_telldir(dirp)
|
||||
RST_DIR *dirp;
|
||||
{
|
||||
return ((long)lseek(dirp->dd_fd,
|
||||
(off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a directory file.
|
||||
*/
|
||||
static RST_DIR *
|
||||
opendirfile(name)
|
||||
const char *name;
|
||||
{
|
||||
register RST_DIR *dirp;
|
||||
register int fd;
|
||||
|
||||
if ((fd = open(name, O_RDONLY)) == -1)
|
||||
return (NULL);
|
||||
if ((dirp = malloc(sizeof(RST_DIR))) == NULL) {
|
||||
(void)close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
dirp->dd_fd = fd;
|
||||
dirp->dd_loc = 0;
|
||||
return (dirp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the mode, owner, and times for all new or changed directories
|
||||
*/
|
||||
void
|
||||
setdirmodes(flags)
|
||||
int flags;
|
||||
{
|
||||
FILE *mf;
|
||||
struct modeinfo node;
|
||||
struct entry *ep;
|
||||
char *cp;
|
||||
|
||||
vprintf(stdout, "Set directory mode, owner, and times.\n");
|
||||
(void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
|
||||
mf = fopen(modefile, "r");
|
||||
if (mf == NULL) {
|
||||
fprintf(stderr, "fopen: %s\n", strerror(errno));
|
||||
fprintf(stderr, "cannot open mode file %s\n", modefile);
|
||||
fprintf(stderr, "directory mode, owner, and times not set\n");
|
||||
return;
|
||||
}
|
||||
clearerr(mf);
|
||||
for (;;) {
|
||||
(void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
|
||||
if (feof(mf))
|
||||
break;
|
||||
ep = lookupino(node.ino);
|
||||
if (command == 'i' || command == 'x') {
|
||||
if (ep == NULL)
|
||||
continue;
|
||||
if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
|
||||
ep->e_flags &= ~NEW;
|
||||
continue;
|
||||
}
|
||||
if (node.ino == ROOTINO &&
|
||||
reply("set owner/mode for '.'") == FAIL)
|
||||
continue;
|
||||
}
|
||||
if (ep == NULL) {
|
||||
panic("cannot find directory inode %d\n", node.ino);
|
||||
} else {
|
||||
cp = myname(ep);
|
||||
(void) chown(cp, node.uid, node.gid);
|
||||
(void) chmod(cp, node.mode);
|
||||
(void) chflags(cp, node.flags);
|
||||
utimes(cp, node.timep);
|
||||
ep->e_flags &= ~NEW;
|
||||
}
|
||||
}
|
||||
if (ferror(mf))
|
||||
panic("error setting directory modes\n");
|
||||
(void) fclose(mf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a literal copy of a directory.
|
||||
*/
|
||||
int
|
||||
genliteraldir(name, ino)
|
||||
char *name;
|
||||
ino_t ino;
|
||||
{
|
||||
register struct inotab *itp;
|
||||
int ofile, dp, i, size;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
itp = inotablookup(ino);
|
||||
if (itp == NULL)
|
||||
panic("Cannot find directory inode %d named %s\n", ino, name);
|
||||
if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
|
||||
fprintf(stderr, "%s: ", name);
|
||||
(void) fflush(stderr);
|
||||
fprintf(stderr, "cannot create file: %s\n", strerror(errno));
|
||||
return (FAIL);
|
||||
}
|
||||
rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
|
||||
dp = dup(dirp->dd_fd);
|
||||
for (i = itp->t_size; i > 0; i -= BUFSIZ) {
|
||||
size = i < BUFSIZ ? i : BUFSIZ;
|
||||
if (read(dp, buf, (int) size) == -1) {
|
||||
fprintf(stderr,
|
||||
"write error extracting inode %d, name %s\n",
|
||||
curfile.ino, curfile.name);
|
||||
fprintf(stderr, "read: %s\n", strerror(errno));
|
||||
done(1);
|
||||
}
|
||||
if (!Nflag && write(ofile, buf, (int) size) == -1) {
|
||||
fprintf(stderr,
|
||||
"write error extracting inode %d, name %s\n",
|
||||
curfile.ino, curfile.name);
|
||||
fprintf(stderr, "write: %s\n", strerror(errno));
|
||||
done(1);
|
||||
}
|
||||
}
|
||||
(void) close(dp);
|
||||
(void) close(ofile);
|
||||
return (GOOD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the type of an inode
|
||||
*/
|
||||
int
|
||||
inodetype(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
struct inotab *itp;
|
||||
|
||||
itp = inotablookup(ino);
|
||||
if (itp == NULL)
|
||||
return (LEAF);
|
||||
return (NODE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and initialize a directory inode entry.
|
||||
* If requested, save its pertinent mode, owner, and time info.
|
||||
*/
|
||||
static struct inotab *
|
||||
allocinotab(ino, dip, seekpt)
|
||||
ino_t ino;
|
||||
struct dinode *dip;
|
||||
long seekpt;
|
||||
{
|
||||
register struct inotab *itp;
|
||||
struct modeinfo node;
|
||||
|
||||
itp = calloc(1, sizeof(struct inotab));
|
||||
if (itp == NULL)
|
||||
panic("no memory directory table\n");
|
||||
itp->t_next = inotab[INOHASH(ino)];
|
||||
inotab[INOHASH(ino)] = itp;
|
||||
itp->t_ino = ino;
|
||||
itp->t_seekpt = seekpt;
|
||||
if (mf == NULL)
|
||||
return (itp);
|
||||
node.ino = ino;
|
||||
node.timep[0].tv_sec = dip->di_atime;
|
||||
node.timep[0].tv_usec = dip->di_atimensec / 1000;
|
||||
node.timep[1].tv_sec = dip->di_mtime;
|
||||
node.timep[1].tv_usec = dip->di_mtimensec / 1000;
|
||||
node.mode = dip->di_mode;
|
||||
node.flags = dip->di_flags;
|
||||
node.uid = dip->di_uid;
|
||||
node.gid = dip->di_gid;
|
||||
(void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
|
||||
return (itp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an inode in the table of directories
|
||||
*/
|
||||
static struct inotab *
|
||||
inotablookup(ino)
|
||||
ino_t ino;
|
||||
{
|
||||
register struct inotab *itp;
|
||||
|
||||
for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
|
||||
if (itp->t_ino == ino)
|
||||
return (itp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up and exit
|
||||
*/
|
||||
__dead void
|
||||
done(exitcode)
|
||||
int exitcode;
|
||||
{
|
||||
|
||||
closemt();
|
||||
if (modefile[0] != '#')
|
||||
(void) unlink(modefile);
|
||||
if (dirfile[0] != '#')
|
||||
(void) unlink(dirfile);
|
||||
exit(exitcode);
|
||||
}
|
||||
774
sbin/restore/interactive.c
Normal file
774
sbin/restore/interactive.c
Normal file
|
|
@ -0,0 +1,774 @@
|
|||
/*
|
||||
* Copyright (c) 1985, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)interactive.c 8.5 (Berkeley) 5/1/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <glob.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "restore.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define round(a, b) (((a) + (b) - 1) / (b) * (b))
|
||||
|
||||
/*
|
||||
* Things to handle interruptions.
|
||||
*/
|
||||
static int runshell;
|
||||
static jmp_buf reset;
|
||||
static char *nextarg = NULL;
|
||||
|
||||
/*
|
||||
* Structure and routines associated with listing directories.
|
||||
*/
|
||||
struct afile {
|
||||
ino_t fnum; /* inode number of file */
|
||||
char *fname; /* file name */
|
||||
short len; /* name length */
|
||||
char prefix; /* prefix character */
|
||||
char postfix; /* postfix character */
|
||||
};
|
||||
struct arglist {
|
||||
int freeglob; /* glob structure needs to be freed */
|
||||
int argcnt; /* next globbed argument to return */
|
||||
glob_t glob; /* globbing information */
|
||||
char *cmd; /* the current command */
|
||||
};
|
||||
|
||||
static char *copynext __P((char *, char *));
|
||||
static int fcmp __P((const void *, const void *));
|
||||
static void formatf __P((struct afile *, int));
|
||||
static void getcmd __P((char *, char *, char *, struct arglist *));
|
||||
struct dirent *glob_readdir __P((RST_DIR *dirp));
|
||||
static int glob_stat __P((const char *, struct stat *));
|
||||
static void mkentry __P((char *, struct direct *, struct afile *));
|
||||
static void printlist __P((char *, char *));
|
||||
|
||||
/*
|
||||
* Read and execute commands from the terminal.
|
||||
*/
|
||||
void
|
||||
runcmdshell()
|
||||
{
|
||||
register struct entry *np;
|
||||
ino_t ino;
|
||||
struct arglist arglist;
|
||||
char curdir[MAXPATHLEN];
|
||||
char name[MAXPATHLEN];
|
||||
char cmd[BUFSIZ];
|
||||
|
||||
arglist.freeglob = 0;
|
||||
arglist.argcnt = 0;
|
||||
arglist.glob.gl_flags = GLOB_ALTDIRFUNC;
|
||||
arglist.glob.gl_opendir = (void *)rst_opendir;
|
||||
arglist.glob.gl_readdir = (void *)glob_readdir;
|
||||
arglist.glob.gl_closedir = (void *)rst_closedir;
|
||||
arglist.glob.gl_lstat = glob_stat;
|
||||
arglist.glob.gl_stat = glob_stat;
|
||||
canon("/", curdir);
|
||||
loop:
|
||||
if (setjmp(reset) != 0) {
|
||||
if (arglist.freeglob != 0) {
|
||||
arglist.freeglob = 0;
|
||||
arglist.argcnt = 0;
|
||||
globfree(&arglist.glob);
|
||||
}
|
||||
nextarg = NULL;
|
||||
volno = 0;
|
||||
}
|
||||
runshell = 1;
|
||||
getcmd(curdir, cmd, name, &arglist);
|
||||
switch (cmd[0]) {
|
||||
/*
|
||||
* Add elements to the extraction list.
|
||||
*/
|
||||
case 'a':
|
||||
if (strncmp(cmd, "add", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
ino = dirlookup(name);
|
||||
if (ino == 0)
|
||||
break;
|
||||
if (mflag)
|
||||
pathcheck(name);
|
||||
treescan(name, ino, addfile);
|
||||
break;
|
||||
/*
|
||||
* Change working directory.
|
||||
*/
|
||||
case 'c':
|
||||
if (strncmp(cmd, "cd", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
ino = dirlookup(name);
|
||||
if (ino == 0)
|
||||
break;
|
||||
if (inodetype(ino) == LEAF) {
|
||||
fprintf(stderr, "%s: not a directory\n", name);
|
||||
break;
|
||||
}
|
||||
(void) strcpy(curdir, name);
|
||||
break;
|
||||
/*
|
||||
* Delete elements from the extraction list.
|
||||
*/
|
||||
case 'd':
|
||||
if (strncmp(cmd, "delete", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
np = lookupname(name);
|
||||
if (np == NULL || (np->e_flags & NEW) == 0) {
|
||||
fprintf(stderr, "%s: not on extraction list\n", name);
|
||||
break;
|
||||
}
|
||||
treescan(name, np->e_ino, deletefile);
|
||||
break;
|
||||
/*
|
||||
* Extract the requested list.
|
||||
*/
|
||||
case 'e':
|
||||
if (strncmp(cmd, "extract", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
createfiles();
|
||||
createlinks();
|
||||
setdirmodes(0);
|
||||
if (dflag)
|
||||
checkrestore();
|
||||
volno = 0;
|
||||
break;
|
||||
/*
|
||||
* List available commands.
|
||||
*/
|
||||
case 'h':
|
||||
if (strncmp(cmd, "help", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
case '?':
|
||||
fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
"Available commands are:\n",
|
||||
"\tls [arg] - list directory\n",
|
||||
"\tcd arg - change directory\n",
|
||||
"\tpwd - print current directory\n",
|
||||
"\tadd [arg] - add `arg' to list of",
|
||||
" files to be extracted\n",
|
||||
"\tdelete [arg] - delete `arg' from",
|
||||
" list of files to be extracted\n",
|
||||
"\textract - extract requested files\n",
|
||||
"\tsetmodes - set modes of requested directories\n",
|
||||
"\tquit - immediately exit program\n",
|
||||
"\twhat - list dump header information\n",
|
||||
"\tverbose - toggle verbose flag",
|
||||
" (useful with ``ls'')\n",
|
||||
"\thelp or `?' - print this list\n",
|
||||
"If no `arg' is supplied, the current",
|
||||
" directory is used\n");
|
||||
break;
|
||||
/*
|
||||
* List a directory.
|
||||
*/
|
||||
case 'l':
|
||||
if (strncmp(cmd, "ls", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
printlist(name, curdir);
|
||||
break;
|
||||
/*
|
||||
* Print current directory.
|
||||
*/
|
||||
case 'p':
|
||||
if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
if (curdir[1] == '\0')
|
||||
fprintf(stderr, "/\n");
|
||||
else
|
||||
fprintf(stderr, "%s\n", &curdir[1]);
|
||||
break;
|
||||
/*
|
||||
* Quit.
|
||||
*/
|
||||
case 'q':
|
||||
if (strncmp(cmd, "quit", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
return;
|
||||
case 'x':
|
||||
if (strncmp(cmd, "xit", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
return;
|
||||
/*
|
||||
* Toggle verbose mode.
|
||||
*/
|
||||
case 'v':
|
||||
if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
if (vflag) {
|
||||
fprintf(stderr, "verbose mode off\n");
|
||||
vflag = 0;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "verbose mode on\n");
|
||||
vflag++;
|
||||
break;
|
||||
/*
|
||||
* Just restore requested directory modes.
|
||||
*/
|
||||
case 's':
|
||||
if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
setdirmodes(FORCE);
|
||||
break;
|
||||
/*
|
||||
* Print out dump header information.
|
||||
*/
|
||||
case 'w':
|
||||
if (strncmp(cmd, "what", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
printdumpinfo();
|
||||
break;
|
||||
/*
|
||||
* Turn on debugging.
|
||||
*/
|
||||
case 'D':
|
||||
if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
|
||||
goto bad;
|
||||
if (dflag) {
|
||||
fprintf(stderr, "debugging mode off\n");
|
||||
dflag = 0;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "debugging mode on\n");
|
||||
dflag++;
|
||||
break;
|
||||
/*
|
||||
* Unknown command.
|
||||
*/
|
||||
default:
|
||||
bad:
|
||||
fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
|
||||
break;
|
||||
}
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and parse an interactive command.
|
||||
* The first word on the line is assigned to "cmd". If
|
||||
* there are no arguments on the command line, then "curdir"
|
||||
* is returned as the argument. If there are arguments
|
||||
* on the line they are returned one at a time on each
|
||||
* successive call to getcmd. Each argument is first assigned
|
||||
* to "name". If it does not start with "/" the pathname in
|
||||
* "curdir" is prepended to it. Finally "canon" is called to
|
||||
* eliminate any embedded ".." components.
|
||||
*/
|
||||
static void
|
||||
getcmd(curdir, cmd, name, ap)
|
||||
char *curdir, *cmd, *name;
|
||||
struct arglist *ap;
|
||||
{
|
||||
register char *cp;
|
||||
static char input[BUFSIZ];
|
||||
char output[BUFSIZ];
|
||||
# define rawname input /* save space by reusing input buffer */
|
||||
|
||||
/*
|
||||
* Check to see if still processing arguments.
|
||||
*/
|
||||
if (ap->argcnt > 0)
|
||||
goto retnext;
|
||||
if (nextarg != NULL)
|
||||
goto getnext;
|
||||
/*
|
||||
* Read a command line and trim off trailing white space.
|
||||
*/
|
||||
do {
|
||||
fprintf(stderr, "restore > ");
|
||||
(void) fflush(stderr);
|
||||
(void) fgets(input, BUFSIZ, terminal);
|
||||
} while (!feof(terminal) && input[0] == '\n');
|
||||
if (feof(terminal)) {
|
||||
(void) strcpy(cmd, "quit");
|
||||
return;
|
||||
}
|
||||
for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
|
||||
/* trim off trailing white space and newline */;
|
||||
*++cp = '\0';
|
||||
/*
|
||||
* Copy the command into "cmd".
|
||||
*/
|
||||
cp = copynext(input, cmd);
|
||||
ap->cmd = cmd;
|
||||
/*
|
||||
* If no argument, use curdir as the default.
|
||||
*/
|
||||
if (*cp == '\0') {
|
||||
(void) strcpy(name, curdir);
|
||||
return;
|
||||
}
|
||||
nextarg = cp;
|
||||
/*
|
||||
* Find the next argument.
|
||||
*/
|
||||
getnext:
|
||||
cp = copynext(nextarg, rawname);
|
||||
if (*cp == '\0')
|
||||
nextarg = NULL;
|
||||
else
|
||||
nextarg = cp;
|
||||
/*
|
||||
* If it is an absolute pathname, canonicalize it and return it.
|
||||
*/
|
||||
if (rawname[0] == '/') {
|
||||
canon(rawname, name);
|
||||
} else {
|
||||
/*
|
||||
* For relative pathnames, prepend the current directory to
|
||||
* it then canonicalize and return it.
|
||||
*/
|
||||
(void) strcpy(output, curdir);
|
||||
(void) strcat(output, "/");
|
||||
(void) strcat(output, rawname);
|
||||
canon(output, name);
|
||||
}
|
||||
if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0)
|
||||
fprintf(stderr, "%s: out of memory\n", ap->cmd);
|
||||
if (ap->glob.gl_pathc == 0)
|
||||
return;
|
||||
ap->freeglob = 1;
|
||||
ap->argcnt = ap->glob.gl_pathc;
|
||||
|
||||
retnext:
|
||||
strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]);
|
||||
if (--ap->argcnt == 0) {
|
||||
ap->freeglob = 0;
|
||||
globfree(&ap->glob);
|
||||
}
|
||||
# undef rawname
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip off the next token of the input.
|
||||
*/
|
||||
static char *
|
||||
copynext(input, output)
|
||||
char *input, *output;
|
||||
{
|
||||
register char *cp, *bp;
|
||||
char quote;
|
||||
|
||||
for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
|
||||
/* skip to argument */;
|
||||
bp = output;
|
||||
while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
|
||||
/*
|
||||
* Handle back slashes.
|
||||
*/
|
||||
if (*cp == '\\') {
|
||||
if (*++cp == '\0') {
|
||||
fprintf(stderr,
|
||||
"command lines cannot be continued\n");
|
||||
continue;
|
||||
}
|
||||
*bp++ = *cp++;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* The usual unquoted case.
|
||||
*/
|
||||
if (*cp != '\'' && *cp != '"') {
|
||||
*bp++ = *cp++;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Handle single and double quotes.
|
||||
*/
|
||||
quote = *cp++;
|
||||
while (*cp != quote && *cp != '\0')
|
||||
*bp++ = *cp++ | 0200;
|
||||
if (*cp++ == '\0') {
|
||||
fprintf(stderr, "missing %c\n", quote);
|
||||
cp--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*bp = '\0';
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Canonicalize file names to always start with ``./'' and
|
||||
* remove any imbedded "." and ".." components.
|
||||
*/
|
||||
void
|
||||
canon(rawname, canonname)
|
||||
char *rawname, *canonname;
|
||||
{
|
||||
register char *cp, *np;
|
||||
|
||||
if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
|
||||
(void) strcpy(canonname, "");
|
||||
else if (rawname[0] == '/')
|
||||
(void) strcpy(canonname, ".");
|
||||
else
|
||||
(void) strcpy(canonname, "./");
|
||||
(void) strcat(canonname, rawname);
|
||||
/*
|
||||
* Eliminate multiple and trailing '/'s
|
||||
*/
|
||||
for (cp = np = canonname; *np != '\0'; cp++) {
|
||||
*cp = *np++;
|
||||
while (*cp == '/' && *np == '/')
|
||||
np++;
|
||||
}
|
||||
*cp = '\0';
|
||||
if (*--cp == '/')
|
||||
*cp = '\0';
|
||||
/*
|
||||
* Eliminate extraneous "." and ".." from pathnames.
|
||||
*/
|
||||
for (np = canonname; *np != '\0'; ) {
|
||||
np++;
|
||||
cp = np;
|
||||
while (*np != '/' && *np != '\0')
|
||||
np++;
|
||||
if (np - cp == 1 && *cp == '.') {
|
||||
cp--;
|
||||
(void) strcpy(cp, np);
|
||||
np = cp;
|
||||
}
|
||||
if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
|
||||
cp--;
|
||||
while (cp > &canonname[1] && *--cp != '/')
|
||||
/* find beginning of name */;
|
||||
(void) strcpy(cp, np);
|
||||
np = cp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do an "ls" style listing of a directory
|
||||
*/
|
||||
static void
|
||||
printlist(name, basename)
|
||||
char *name;
|
||||
char *basename;
|
||||
{
|
||||
register struct afile *fp, *list, *listp;
|
||||
register struct direct *dp;
|
||||
struct afile single;
|
||||
RST_DIR *dirp;
|
||||
int entries, len, namelen;
|
||||
char locname[MAXPATHLEN + 1];
|
||||
|
||||
dp = pathsearch(name);
|
||||
if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
|
||||
(!vflag && dp->d_ino == WINO))
|
||||
return;
|
||||
if ((dirp = rst_opendir(name)) == NULL) {
|
||||
entries = 1;
|
||||
list = &single;
|
||||
mkentry(name, dp, list);
|
||||
len = strlen(basename) + 1;
|
||||
if (strlen(name) - len > single.len) {
|
||||
freename(single.fname);
|
||||
single.fname = savename(&name[len]);
|
||||
single.len = strlen(single.fname);
|
||||
}
|
||||
} else {
|
||||
entries = 0;
|
||||
while (dp = rst_readdir(dirp))
|
||||
entries++;
|
||||
rst_closedir(dirp);
|
||||
list = (struct afile *)malloc(entries * sizeof(struct afile));
|
||||
if (list == NULL) {
|
||||
fprintf(stderr, "ls: out of memory\n");
|
||||
return;
|
||||
}
|
||||
if ((dirp = rst_opendir(name)) == NULL)
|
||||
panic("directory reopen failed\n");
|
||||
fprintf(stderr, "%s:\n", name);
|
||||
entries = 0;
|
||||
listp = list;
|
||||
(void) strncpy(locname, name, MAXPATHLEN);
|
||||
(void) strncat(locname, "/", MAXPATHLEN);
|
||||
namelen = strlen(locname);
|
||||
while (dp = rst_readdir(dirp)) {
|
||||
if (dp == NULL)
|
||||
break;
|
||||
if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
|
||||
continue;
|
||||
if (!vflag && (dp->d_ino == WINO ||
|
||||
strcmp(dp->d_name, ".") == 0 ||
|
||||
strcmp(dp->d_name, "..") == 0))
|
||||
continue;
|
||||
locname[namelen] = '\0';
|
||||
if (namelen + dp->d_namlen >= MAXPATHLEN) {
|
||||
fprintf(stderr, "%s%s: name exceeds %d char\n",
|
||||
locname, dp->d_name, MAXPATHLEN);
|
||||
} else {
|
||||
(void) strncat(locname, dp->d_name,
|
||||
(int)dp->d_namlen);
|
||||
mkentry(locname, dp, listp++);
|
||||
entries++;
|
||||
}
|
||||
}
|
||||
rst_closedir(dirp);
|
||||
if (entries == 0) {
|
||||
fprintf(stderr, "\n");
|
||||
free(list);
|
||||
return;
|
||||
}
|
||||
qsort((char *)list, entries, sizeof(struct afile), fcmp);
|
||||
}
|
||||
formatf(list, entries);
|
||||
if (dirp != NULL) {
|
||||
for (fp = listp - 1; fp >= list; fp--)
|
||||
freename(fp->fname);
|
||||
fprintf(stderr, "\n");
|
||||
free(list);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the contents of a directory.
|
||||
*/
|
||||
static void
|
||||
mkentry(name, dp, fp)
|
||||
char *name;
|
||||
struct direct *dp;
|
||||
register struct afile *fp;
|
||||
{
|
||||
char *cp;
|
||||
struct entry *np;
|
||||
|
||||
fp->fnum = dp->d_ino;
|
||||
fp->fname = savename(dp->d_name);
|
||||
for (cp = fp->fname; *cp; cp++)
|
||||
if (!vflag && (*cp < ' ' || *cp >= 0177))
|
||||
*cp = '?';
|
||||
fp->len = cp - fp->fname;
|
||||
if (dflag && TSTINO(fp->fnum, dumpmap) == 0)
|
||||
fp->prefix = '^';
|
||||
else if ((np = lookupname(name)) != NULL && (np->e_flags & NEW))
|
||||
fp->prefix = '*';
|
||||
else
|
||||
fp->prefix = ' ';
|
||||
switch(dp->d_type) {
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Warning: undefined file type %d\n",
|
||||
dp->d_type);
|
||||
/* fall through */
|
||||
case DT_REG:
|
||||
fp->postfix = ' ';
|
||||
break;
|
||||
|
||||
case DT_LNK:
|
||||
fp->postfix = '@';
|
||||
break;
|
||||
|
||||
case DT_FIFO:
|
||||
case DT_SOCK:
|
||||
fp->postfix = '=';
|
||||
break;
|
||||
|
||||
case DT_CHR:
|
||||
case DT_BLK:
|
||||
fp->postfix = '#';
|
||||
break;
|
||||
|
||||
case DT_WHT:
|
||||
fp->postfix = '%';
|
||||
break;
|
||||
|
||||
case DT_UNKNOWN:
|
||||
case DT_DIR:
|
||||
if (inodetype(dp->d_ino) == NODE)
|
||||
fp->postfix = '/';
|
||||
else
|
||||
fp->postfix = ' ';
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out a pretty listing of a directory
|
||||
*/
|
||||
static void
|
||||
formatf(list, nentry)
|
||||
register struct afile *list;
|
||||
int nentry;
|
||||
{
|
||||
register struct afile *fp, *endlist;
|
||||
int width, bigino, haveprefix, havepostfix;
|
||||
int i, j, w, precision, columns, lines;
|
||||
|
||||
width = 0;
|
||||
haveprefix = 0;
|
||||
havepostfix = 0;
|
||||
bigino = ROOTINO;
|
||||
endlist = &list[nentry];
|
||||
for (fp = &list[0]; fp < endlist; fp++) {
|
||||
if (bigino < fp->fnum)
|
||||
bigino = fp->fnum;
|
||||
if (width < fp->len)
|
||||
width = fp->len;
|
||||
if (fp->prefix != ' ')
|
||||
haveprefix = 1;
|
||||
if (fp->postfix != ' ')
|
||||
havepostfix = 1;
|
||||
}
|
||||
if (haveprefix)
|
||||
width++;
|
||||
if (havepostfix)
|
||||
width++;
|
||||
if (vflag) {
|
||||
for (precision = 0, i = bigino; i > 0; i /= 10)
|
||||
precision++;
|
||||
width += precision + 1;
|
||||
}
|
||||
width++;
|
||||
columns = 81 / width;
|
||||
if (columns == 0)
|
||||
columns = 1;
|
||||
lines = (nentry + columns - 1) / columns;
|
||||
for (i = 0; i < lines; i++) {
|
||||
for (j = 0; j < columns; j++) {
|
||||
fp = &list[j * lines + i];
|
||||
if (vflag) {
|
||||
fprintf(stderr, "%*d ", precision, fp->fnum);
|
||||
fp->len += precision + 1;
|
||||
}
|
||||
if (haveprefix) {
|
||||
putc(fp->prefix, stderr);
|
||||
fp->len++;
|
||||
}
|
||||
fprintf(stderr, "%s", fp->fname);
|
||||
if (havepostfix) {
|
||||
putc(fp->postfix, stderr);
|
||||
fp->len++;
|
||||
}
|
||||
if (fp + lines >= endlist) {
|
||||
fprintf(stderr, "\n");
|
||||
break;
|
||||
}
|
||||
for (w = fp->len; w < width; w++)
|
||||
putc(' ', stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip over directory entries that are not on the tape
|
||||
*
|
||||
* First have to get definition of a dirent.
|
||||
*/
|
||||
#undef DIRBLKSIZ
|
||||
#include <dirent.h>
|
||||
#undef d_ino
|
||||
|
||||
struct dirent *
|
||||
glob_readdir(dirp)
|
||||
RST_DIR *dirp;
|
||||
{
|
||||
struct direct *dp;
|
||||
static struct dirent adirent;
|
||||
|
||||
while ((dp = rst_readdir(dirp)) != NULL) {
|
||||
if (!vflag && dp->d_ino == WINO)
|
||||
continue;
|
||||
if (dflag || TSTINO(dp->d_ino, dumpmap))
|
||||
break;
|
||||
}
|
||||
if (dp == NULL)
|
||||
return (NULL);
|
||||
adirent.d_fileno = dp->d_ino;
|
||||
adirent.d_namlen = dp->d_namlen;
|
||||
memmove(adirent.d_name, dp->d_name, dp->d_namlen + 1);
|
||||
return (&adirent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return st_mode information in response to stat or lstat calls
|
||||
*/
|
||||
static int
|
||||
glob_stat(name, stp)
|
||||
const char *name;
|
||||
struct stat *stp;
|
||||
{
|
||||
register struct direct *dp;
|
||||
|
||||
dp = pathsearch(name);
|
||||
if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
|
||||
(!vflag && dp->d_ino == WINO))
|
||||
return (-1);
|
||||
if (inodetype(dp->d_ino) == NODE)
|
||||
stp->st_mode = IFDIR;
|
||||
else
|
||||
stp->st_mode = IFREG;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison routine for qsort.
|
||||
*/
|
||||
static int
|
||||
fcmp(f1, f2)
|
||||
register const void *f1, *f2;
|
||||
{
|
||||
return (strcmp(((struct afile *)f1)->fname,
|
||||
((struct afile *)f2)->fname));
|
||||
}
|
||||
|
||||
/*
|
||||
* respond to interrupts
|
||||
*/
|
||||
void
|
||||
onintr(signo)
|
||||
int signo;
|
||||
{
|
||||
if (command == 'i' && runshell)
|
||||
longjmp(reset, 1);
|
||||
if (reply("restore interrupted, continue") == FAIL)
|
||||
done(1);
|
||||
}
|
||||
352
sbin/restore/main.c
Normal file
352
sbin/restore/main.c
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/4/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <protocols/dumprestore.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "restore.h"
|
||||
#include "extern.h"
|
||||
|
||||
int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
|
||||
int hflag = 1, mflag = 1, Nflag = 0;
|
||||
char command = '\0';
|
||||
long dumpnum = 1;
|
||||
long volno = 0;
|
||||
long ntrec;
|
||||
char *dumpmap;
|
||||
char *usedinomap;
|
||||
ino_t maxino;
|
||||
time_t dumptime;
|
||||
time_t dumpdate;
|
||||
FILE *terminal;
|
||||
|
||||
static void obsolete __P((int *, char **[]));
|
||||
static void usage __P((void));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int ch;
|
||||
ino_t ino;
|
||||
char *inputdev = _PATH_DEFTAPE;
|
||||
char *symtbl = "./restoresymtable";
|
||||
char *p, name[MAXPATHLEN];
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
obsolete(&argc, &argv);
|
||||
while ((ch = getopt(argc, argv, "b:cdf:himNRrs:tvxy")) != EOF)
|
||||
switch(ch) {
|
||||
case 'b':
|
||||
/* Change default tape blocksize. */
|
||||
bflag = 1;
|
||||
ntrec = strtol(optarg, &p, 10);
|
||||
if (*p)
|
||||
errx(1, "illegal blocksize -- %s", optarg);
|
||||
if (ntrec <= 0)
|
||||
errx(1, "block size must be greater than 0");
|
||||
break;
|
||||
case 'c':
|
||||
cvtflag = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dflag = 1;
|
||||
break;
|
||||
case 'f':
|
||||
inputdev = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
hflag = 0;
|
||||
break;
|
||||
case 'i':
|
||||
case 'R':
|
||||
case 'r':
|
||||
case 't':
|
||||
case 'x':
|
||||
if (command != '\0')
|
||||
errx(1,
|
||||
"%c and %c options are mutually exclusive",
|
||||
ch, command);
|
||||
command = ch;
|
||||
break;
|
||||
case 'm':
|
||||
mflag = 0;
|
||||
break;
|
||||
case 'N':
|
||||
Nflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
/* Dumpnum (skip to) for multifile dump tapes. */
|
||||
dumpnum = strtol(optarg, &p, 10);
|
||||
if (*p)
|
||||
errx(1, "illegal dump number -- %s", optarg);
|
||||
if (dumpnum <= 0)
|
||||
errx(1, "dump number must be greater than 0");
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
case 'y':
|
||||
yflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (command == '\0')
|
||||
errx(1, "none of i, R, r, t or x options specified");
|
||||
|
||||
if (signal(SIGINT, onintr) == SIG_IGN)
|
||||
(void) signal(SIGINT, SIG_IGN);
|
||||
if (signal(SIGTERM, onintr) == SIG_IGN)
|
||||
(void) signal(SIGTERM, SIG_IGN);
|
||||
setlinebuf(stderr);
|
||||
|
||||
setinput(inputdev);
|
||||
|
||||
if (argc == 0) {
|
||||
argc = 1;
|
||||
*--argv = ".";
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
/*
|
||||
* Interactive mode.
|
||||
*/
|
||||
case 'i':
|
||||
setup();
|
||||
extractdirs(1);
|
||||
initsymtable(NULL);
|
||||
runcmdshell();
|
||||
break;
|
||||
/*
|
||||
* Incremental restoration of a file system.
|
||||
*/
|
||||
case 'r':
|
||||
setup();
|
||||
if (dumptime > 0) {
|
||||
/*
|
||||
* This is an incremental dump tape.
|
||||
*/
|
||||
vprintf(stdout, "Begin incremental restore\n");
|
||||
initsymtable(symtbl);
|
||||
extractdirs(1);
|
||||
removeoldleaves();
|
||||
vprintf(stdout, "Calculate node updates.\n");
|
||||
treescan(".", ROOTINO, nodeupdates);
|
||||
findunreflinks();
|
||||
removeoldnodes();
|
||||
} else {
|
||||
/*
|
||||
* This is a level zero dump tape.
|
||||
*/
|
||||
vprintf(stdout, "Begin level 0 restore\n");
|
||||
initsymtable((char *)0);
|
||||
extractdirs(1);
|
||||
vprintf(stdout, "Calculate extraction list.\n");
|
||||
treescan(".", ROOTINO, nodeupdates);
|
||||
}
|
||||
createleaves(symtbl);
|
||||
createlinks();
|
||||
setdirmodes(FORCE);
|
||||
checkrestore();
|
||||
if (dflag) {
|
||||
vprintf(stdout, "Verify the directory structure\n");
|
||||
treescan(".", ROOTINO, verifyfile);
|
||||
}
|
||||
dumpsymtable(symtbl, (long)1);
|
||||
break;
|
||||
/*
|
||||
* Resume an incremental file system restoration.
|
||||
*/
|
||||
case 'R':
|
||||
initsymtable(symtbl);
|
||||
skipmaps();
|
||||
skipdirs();
|
||||
createleaves(symtbl);
|
||||
createlinks();
|
||||
setdirmodes(FORCE);
|
||||
checkrestore();
|
||||
dumpsymtable(symtbl, (long)1);
|
||||
break;
|
||||
/*
|
||||
* List contents of tape.
|
||||
*/
|
||||
case 't':
|
||||
setup();
|
||||
extractdirs(0);
|
||||
initsymtable((char *)0);
|
||||
while (argc--) {
|
||||
canon(*argv++, name);
|
||||
ino = dirlookup(name);
|
||||
if (ino == 0)
|
||||
continue;
|
||||
treescan(name, ino, listfile);
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* Batch extraction of tape contents.
|
||||
*/
|
||||
case 'x':
|
||||
setup();
|
||||
extractdirs(1);
|
||||
initsymtable((char *)0);
|
||||
while (argc--) {
|
||||
canon(*argv++, name);
|
||||
ino = dirlookup(name);
|
||||
if (ino == 0)
|
||||
continue;
|
||||
if (mflag)
|
||||
pathcheck(name);
|
||||
treescan(name, ino, addfile);
|
||||
}
|
||||
createfiles();
|
||||
createlinks();
|
||||
setdirmodes(0);
|
||||
if (dflag)
|
||||
checkrestore();
|
||||
break;
|
||||
}
|
||||
done(0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
|
||||
"restore -i [-chmvy] [-b blocksize] [-f file] [-s fileno]",
|
||||
"restore -r [-cvy] [-b blocksize] [-f file] [-s fileno]",
|
||||
"restore -R [-cvy] [-b blocksize] [-f file] [-s fileno]",
|
||||
"restore -x [-chmvy] [-b blocksize] [-f file] [-s fileno] [file ...]",
|
||||
"restore -t [-chvy] [-b blocksize] [-f file] [-s fileno] [file ...]");
|
||||
done(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* obsolete --
|
||||
* Change set of key letters and ordered arguments into something
|
||||
* getopt(3) will like.
|
||||
*/
|
||||
static void
|
||||
obsolete(argcp, argvp)
|
||||
int *argcp;
|
||||
char **argvp[];
|
||||
{
|
||||
int argc, flags;
|
||||
char *ap, **argv, *flagsp, **nargv, *p;
|
||||
|
||||
/* Setup. */
|
||||
argv = *argvp;
|
||||
argc = *argcp;
|
||||
|
||||
/* Return if no arguments or first argument has leading dash. */
|
||||
ap = argv[1];
|
||||
if (argc == 1 || *ap == '-')
|
||||
return;
|
||||
|
||||
/* Allocate space for new arguments. */
|
||||
if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
|
||||
(p = flagsp = malloc(strlen(ap) + 2)) == NULL)
|
||||
err(1, NULL);
|
||||
|
||||
*nargv++ = *argv;
|
||||
argv += 2;
|
||||
|
||||
for (flags = 0; *ap; ++ap) {
|
||||
switch (*ap) {
|
||||
case 'b':
|
||||
case 'f':
|
||||
case 's':
|
||||
if (*argv == NULL) {
|
||||
warnx("option requires an argument -- %c", *ap);
|
||||
usage();
|
||||
}
|
||||
if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
|
||||
err(1, NULL);
|
||||
nargv[0][0] = '-';
|
||||
nargv[0][1] = *ap;
|
||||
(void)strcpy(&nargv[0][2], *argv);
|
||||
++argv;
|
||||
++nargv;
|
||||
break;
|
||||
default:
|
||||
if (!flags) {
|
||||
*p++ = '-';
|
||||
flags = 1;
|
||||
}
|
||||
*p++ = *ap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate flags. */
|
||||
if (flags) {
|
||||
*p = '\0';
|
||||
*nargv++ = flagsp;
|
||||
}
|
||||
|
||||
/* Copy remaining arguments. */
|
||||
while (*nargv++ = *argv++);
|
||||
|
||||
/* Update argument count. */
|
||||
*argcp = nargv - *argvp - 1;
|
||||
}
|
||||
426
sbin/restore/restore.8
Normal file
426
sbin/restore/restore.8
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
.\" Copyright (c) 1985, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)restore.8 8.4 (Berkeley) 5/1/95
|
||||
.\"
|
||||
.Dd May 1, 1995
|
||||
.Dt RESTORE 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm restore
|
||||
.Nd "restore files or file systems from backups made with dump"
|
||||
.Sh SYNOPSIS
|
||||
.Nm restore
|
||||
.Fl i
|
||||
.Op Fl chmvy
|
||||
.Op Fl b Ar blocksize
|
||||
.Op Fl f Ar file
|
||||
.Op Fl s Ar fileno
|
||||
.Nm restore
|
||||
.Fl R
|
||||
.Op Fl cvy
|
||||
.Op Fl b Ar blocksize
|
||||
.Op Fl f Ar file
|
||||
.Op Fl s Ar fileno
|
||||
.Nm restore
|
||||
.Fl r
|
||||
.Op Fl cvy
|
||||
.Op Fl b Ar blocksize
|
||||
.Op Fl f Ar file
|
||||
.Op Fl s Ar fileno
|
||||
.Nm restore
|
||||
.Fl t
|
||||
.Op Fl chvy
|
||||
.Op Fl b Ar blocksize
|
||||
.Op Fl f Ar file
|
||||
.Op Fl s Ar fileno
|
||||
.Op file ...
|
||||
.Nm restore
|
||||
.Fl x
|
||||
.Op Fl chmvy
|
||||
.Op Fl b Ar blocksize
|
||||
.Op Fl f Ar file
|
||||
.Op Fl s Ar fileno
|
||||
.Op file ...
|
||||
.Pp
|
||||
.in -\\n(iSu
|
||||
(The
|
||||
.Bx 4.3
|
||||
option syntax is implemented for backward compatibility, but
|
||||
is not documented here.)
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm restore
|
||||
command performs the inverse function of
|
||||
.Xr dump 8 .
|
||||
A full backup of a file system may be restored and
|
||||
subsequent incremental backups layered on top of it.
|
||||
Single files and
|
||||
directory subtrees may be restored from full or partial
|
||||
backups.
|
||||
.Nm Restore
|
||||
works across a network;
|
||||
to do this see the
|
||||
.Fl f
|
||||
flag described below.
|
||||
Other arguments to the command are file or directory
|
||||
names specifying the files that are to be restored.
|
||||
Unless the
|
||||
.Fl h
|
||||
flag is specified (see below),
|
||||
the appearance of a directory name refers to
|
||||
the files and (recursively) subdirectories of that directory.
|
||||
.Pp
|
||||
Exactly one of the following flags is required:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl i
|
||||
This mode allows interactive restoration of files from a dump.
|
||||
After reading in the directory information from the dump,
|
||||
.Nm restore
|
||||
provides a shell like interface that allows the user to move
|
||||
around the directory tree selecting files to be extracted.
|
||||
The available commands are given below;
|
||||
for those commands that require an argument,
|
||||
the default is the current directory.
|
||||
.Bl -tag -width Fl
|
||||
.It Ic add Op Ar arg
|
||||
The current directory or specified argument is added to the list of
|
||||
files to be extracted.
|
||||
If a directory is specified, then it and all its descendents are
|
||||
added to the extraction list
|
||||
(unless the
|
||||
.Fl h
|
||||
flag is specified on the command line).
|
||||
Files that are on the extraction list are prepended with a ``*''
|
||||
when they are listed by
|
||||
.Ic ls .
|
||||
.It Ic \&cd Ar arg
|
||||
Change the current working directory to the specified argument.
|
||||
.It Ic delete Op Ar arg
|
||||
The current directory or specified argument is deleted from the list of
|
||||
files to be extracted.
|
||||
If a directory is specified, then it and all its descendents are
|
||||
deleted from the extraction list
|
||||
(unless the
|
||||
.Fl h
|
||||
flag is specified on the command line).
|
||||
The most expedient way to extract most of the files from a directory
|
||||
is to add the directory to the extraction list and then delete
|
||||
those files that are not needed.
|
||||
.It Ic extract
|
||||
All the files that are on the extraction list are extracted
|
||||
from the dump.
|
||||
.Nm Restore
|
||||
will ask which volume the user wishes to mount.
|
||||
The fastest way to extract a few files is to
|
||||
start with the last volume, and work towards the first volume.
|
||||
.It Ic help
|
||||
List a summary of the available commands.
|
||||
.It Ic \&ls Op Ar arg
|
||||
List the current or specified directory.
|
||||
Entries that are directories are appended with a ``/''.
|
||||
Entries that have been marked for extraction are prepended with a ``*''.
|
||||
If the verbose
|
||||
flag is set the inode number of each entry is also listed.
|
||||
.It Ic pwd
|
||||
Print the full pathname of the current working directory.
|
||||
.It Ic quit
|
||||
Restore immediately exits,
|
||||
even if the extraction list is not empty.
|
||||
.It Ic setmodes
|
||||
All the directories that have been added to the extraction list
|
||||
have their owner, modes, and times set;
|
||||
nothing is extracted from the dump.
|
||||
This is useful for cleaning up after a restore has been prematurely aborted.
|
||||
.It Ic verbose
|
||||
The sense of the
|
||||
.Fl v
|
||||
flag is toggled.
|
||||
When set, the verbose flag causes the
|
||||
.Ic ls
|
||||
command to list the inode numbers of all entries.
|
||||
It also causes
|
||||
.Nm restore
|
||||
to print out information about each file as it is extracted.
|
||||
.El
|
||||
.It Fl R
|
||||
.Nm Restore
|
||||
requests a particular tape of a multi volume set on which to restart
|
||||
a full restore
|
||||
(see the
|
||||
.Fl r
|
||||
flag below).
|
||||
This is useful if the restore has been interrupted.
|
||||
.It Fl r
|
||||
Restore (rebuild a file system).
|
||||
The target file system should be made pristine with
|
||||
.Xr newfs 8 ,
|
||||
mounted and the user
|
||||
.Xr cd Ns 'd
|
||||
into the pristine file system
|
||||
before starting the restoration of the initial level 0 backup. If the
|
||||
level 0 restores successfully, the
|
||||
.Fl r
|
||||
flag may be used to restore
|
||||
any necessary incremental backups on top of the level 0.
|
||||
The
|
||||
.Fl r
|
||||
flag precludes an interactive file extraction and can be
|
||||
detrimental to one's health if not used carefully (not to mention
|
||||
the disk). An example:
|
||||
.Bd -literal -offset indent
|
||||
newfs /dev/rrp0g eagle
|
||||
mount /dev/rp0g /mnt
|
||||
cd /mnt
|
||||
|
||||
restore rf /dev/rst8
|
||||
.Ed
|
||||
.Pp
|
||||
Note that
|
||||
.Nm restore
|
||||
leaves a file
|
||||
.Pa restoresymtable
|
||||
in the root directory to pass information between incremental
|
||||
restore passes.
|
||||
This file should be removed when the last incremental has been
|
||||
restored.
|
||||
.Pp
|
||||
.Nm Restore ,
|
||||
in conjunction with
|
||||
.Xr newfs 8
|
||||
and
|
||||
.Xr dump 8 ,
|
||||
may be used to modify file system parameters
|
||||
such as size or block size.
|
||||
.It Fl t
|
||||
The names of the specified files are listed if they occur
|
||||
on the backup.
|
||||
If no file argument is given,
|
||||
then the root directory is listed,
|
||||
which results in the entire content of the
|
||||
backup being listed,
|
||||
unless the
|
||||
.Fl h
|
||||
flag has been specified.
|
||||
Note that the
|
||||
.Fl t
|
||||
flag replaces the function of the old
|
||||
.Xr dumpdir 8
|
||||
program.
|
||||
.ne 1i
|
||||
.It Fl x
|
||||
The named files are read from the given media.
|
||||
If a named file matches a directory whose contents
|
||||
are on the backup
|
||||
and the
|
||||
.Fl h
|
||||
flag is not specified,
|
||||
the directory is recursively extracted.
|
||||
The owner, modification time,
|
||||
and mode are restored (if possible).
|
||||
If no file argument is given,
|
||||
then the root directory is extracted,
|
||||
which results in the entire content of the
|
||||
backup being extracted,
|
||||
unless the
|
||||
.Fl h
|
||||
flag has been specified.
|
||||
.El
|
||||
.Pp
|
||||
The following additional options may be specified:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl b Ar blocksize
|
||||
The number of kilobytes per dump record.
|
||||
If the
|
||||
.Fl b
|
||||
option is not specified,
|
||||
.Nm restore
|
||||
tries to determine the block size dynamically.
|
||||
.It Fl c
|
||||
Normally,
|
||||
.Nm restore
|
||||
will try to determine dynamically whether the dump was made from an
|
||||
old (pre-4.4) or new format file sytem. The
|
||||
.Fl c
|
||||
flag disables this check, and only allows reading a dump in the old
|
||||
format.
|
||||
.It Fl f Ar file
|
||||
Read the backup from
|
||||
.Ar file ;
|
||||
.Ar file
|
||||
may be a special device file
|
||||
like
|
||||
.Pa /dev/rmt12
|
||||
(a tape drive),
|
||||
.Pa /dev/rsd1c
|
||||
(a disk drive),
|
||||
an ordinary file,
|
||||
or
|
||||
.Ql Fl
|
||||
(the standard input).
|
||||
If the name of the file is of the form
|
||||
.Dq host:file ,
|
||||
or
|
||||
.Dq user@host:file ,
|
||||
.Nm restore
|
||||
reads from the named file on the remote host using
|
||||
.Xr rmt 8 .
|
||||
.Pp
|
||||
.It Fl h
|
||||
Extract the actual directory,
|
||||
rather than the files that it references.
|
||||
This prevents hierarchical restoration of complete subtrees
|
||||
from the dump.
|
||||
.It Fl m
|
||||
Extract by inode numbers rather than by file name.
|
||||
This is useful if only a few files are being extracted,
|
||||
and one wants to avoid regenerating the complete pathname
|
||||
to the file.
|
||||
.It Fl s Ar fileno
|
||||
Read from the specified
|
||||
.Ar fileno
|
||||
on a multi-file tape.
|
||||
File numbering starts at 1.
|
||||
.It Fl v
|
||||
Normally
|
||||
.Nm restore
|
||||
does its work silently.
|
||||
The
|
||||
.Fl v
|
||||
(verbose)
|
||||
flag causes it to type the name of each file it treats
|
||||
preceded by its file type.
|
||||
.It Fl y
|
||||
Do not ask the user whether to abort the restore in the event of an error.
|
||||
Always try to skip over the bad block(s) and continue.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
Complaints if it gets a read error.
|
||||
If
|
||||
.Fl y
|
||||
has been specified, or the user responds
|
||||
.Ql y ,
|
||||
.Nm restore
|
||||
will attempt to continue the restore.
|
||||
.Pp
|
||||
If a backup was made using more than one tape volume,
|
||||
.Nm restore
|
||||
will notify the user when it is time to mount the next volume.
|
||||
If the
|
||||
.Fl x
|
||||
or
|
||||
.Fl i
|
||||
flag has been specified,
|
||||
.Nm restore
|
||||
will also ask which volume the user wishes to mount.
|
||||
The fastest way to extract a few files is to
|
||||
start with the last volume, and work towards the first volume.
|
||||
.Pp
|
||||
There are numerous consistency checks that can be listed by
|
||||
.Nm restore .
|
||||
Most checks are self-explanatory or can ``never happen''.
|
||||
Common errors are given below.
|
||||
.Pp
|
||||
.Bl -tag -width Ds -compact
|
||||
.It Converting to new file system format.
|
||||
A dump tape created from the old file system has been loaded.
|
||||
It is automatically converted to the new file system format.
|
||||
.Pp
|
||||
.It <filename>: not found on tape
|
||||
The specified file name was listed in the tape directory,
|
||||
but was not found on the tape.
|
||||
This is caused by tape read errors while looking for the file,
|
||||
and from using a dump tape created on an active file system.
|
||||
.Pp
|
||||
.It expected next file <inumber>, got <inumber>
|
||||
A file that was not listed in the directory showed up.
|
||||
This can occur when using a dump created on an active file system.
|
||||
.Pp
|
||||
.It Incremental dump too low
|
||||
When doing incremental restore,
|
||||
a dump that was written before the previous incremental dump,
|
||||
or that has too low an incremental level has been loaded.
|
||||
.Pp
|
||||
.It Incremental dump too high
|
||||
When doing incremental restore,
|
||||
a dump that does not begin its coverage where the previous incremental
|
||||
dump left off,
|
||||
or that has too high an incremental level has been loaded.
|
||||
.Pp
|
||||
.It Tape read error while restoring <filename>
|
||||
.It Tape read error while skipping over inode <inumber>
|
||||
.It Tape read error while trying to resynchronize
|
||||
A tape (or other media) read error has occurred.
|
||||
If a file name is specified,
|
||||
then its contents are probably partially wrong.
|
||||
If an inode is being skipped or the tape is trying to resynchronize,
|
||||
then no extracted files have been corrupted,
|
||||
though files may not be found on the tape.
|
||||
.Pp
|
||||
.It resync restore, skipped <num> blocks
|
||||
After a dump read error,
|
||||
.Nm restore
|
||||
may have to resynchronize itself.
|
||||
This message lists the number of blocks that were skipped over.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "./restoresymtable" -compact
|
||||
.It Pa /dev/rmt?
|
||||
the default tape drive
|
||||
.It Pa /tmp/rstdir*
|
||||
file containing directories on the tape.
|
||||
.It Pa /tmp/rstmode*
|
||||
owner, mode, and time stamps for directories.
|
||||
.It Pa \&./restoresymtable
|
||||
information passed between incremental restores.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr dump 8 ,
|
||||
.Xr newfs 8 ,
|
||||
.Xr mount 8 ,
|
||||
.Xr mkfs 8 ,
|
||||
.Xr rmt 8
|
||||
.Sh BUGS
|
||||
.Nm Restore
|
||||
can get confused when doing incremental restores from
|
||||
dumps that were made on active file systems.
|
||||
.Pp
|
||||
A level zero dump must be done after a full restore.
|
||||
Because restore runs in user code,
|
||||
it has no control over inode allocation;
|
||||
thus a full dump must be done to get a new set of directories
|
||||
reflecting the new inode numbering,
|
||||
even though the contents of the files is unchanged.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm restore
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
851
sbin/restore/restore.c
Normal file
851
sbin/restore/restore.c
Normal file
|
|
@ -0,0 +1,851 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)restore.c 8.3 (Berkeley) 9/13/94";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "restore.h"
|
||||
#include "extern.h"
|
||||
|
||||
static char *keyval __P((int));
|
||||
|
||||
/*
|
||||
* This implements the 't' option.
|
||||
* List entries on the tape.
|
||||
*/
|
||||
long
|
||||
listfile(name, ino, type)
|
||||
char *name;
|
||||
ino_t ino;
|
||||
int type;
|
||||
{
|
||||
long descend = hflag ? GOOD : FAIL;
|
||||
|
||||
if (TSTINO(ino, dumpmap) == 0)
|
||||
return (descend);
|
||||
vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
|
||||
fprintf(stdout, "%10d\t%s\n", ino, name);
|
||||
return (descend);
|
||||
}
|
||||
|
||||
/*
|
||||
* This implements the 'x' option.
|
||||
* Request that new entries be extracted.
|
||||
*/
|
||||
long
|
||||
addfile(name, ino, type)
|
||||
char *name;
|
||||
ino_t ino;
|
||||
int type;
|
||||
{
|
||||
register struct entry *ep;
|
||||
long descend = hflag ? GOOD : FAIL;
|
||||
char buf[100];
|
||||
|
||||
if (TSTINO(ino, dumpmap) == 0) {
|
||||
dprintf(stdout, "%s: not on the tape\n", name);
|
||||
return (descend);
|
||||
}
|
||||
if (ino == WINO && command == 'i' && !vflag)
|
||||
return (descend);
|
||||
if (!mflag) {
|
||||
(void) sprintf(buf, "./%u", ino);
|
||||
name = buf;
|
||||
if (type == NODE) {
|
||||
(void) genliteraldir(name, ino);
|
||||
return (descend);
|
||||
}
|
||||
}
|
||||
ep = lookupino(ino);
|
||||
if (ep != NULL) {
|
||||
if (strcmp(name, myname(ep)) == 0) {
|
||||
ep->e_flags |= NEW;
|
||||
return (descend);
|
||||
}
|
||||
type |= LINK;
|
||||
}
|
||||
ep = addentry(name, ino, type);
|
||||
if (type == NODE)
|
||||
newnode(ep);
|
||||
ep->e_flags |= NEW;
|
||||
return (descend);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used by the 'i' option to undo previous requests made by addfile.
|
||||
* Delete entries from the request queue.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
long
|
||||
deletefile(name, ino, type)
|
||||
char *name;
|
||||
ino_t ino;
|
||||
int type;
|
||||
{
|
||||
long descend = hflag ? GOOD : FAIL;
|
||||
struct entry *ep;
|
||||
|
||||
if (TSTINO(ino, dumpmap) == 0)
|
||||
return (descend);
|
||||
ep = lookupname(name);
|
||||
if (ep != NULL) {
|
||||
ep->e_flags &= ~NEW;
|
||||
ep->e_flags |= REMOVED;
|
||||
if (ep->e_type != NODE)
|
||||
freeentry(ep);
|
||||
}
|
||||
return (descend);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following four routines implement the incremental
|
||||
* restore algorithm. The first removes old entries, the second
|
||||
* does renames and calculates the extraction list, the third
|
||||
* cleans up link names missed by the first two, and the final
|
||||
* one deletes old directories.
|
||||
*
|
||||
* Directories cannot be immediately deleted, as they may have
|
||||
* other files in them which need to be moved out first. As
|
||||
* directories to be deleted are found, they are put on the
|
||||
* following deletion list. After all deletions and renames
|
||||
* are done, this list is actually deleted.
|
||||
*/
|
||||
static struct entry *removelist;
|
||||
|
||||
/*
|
||||
* Remove invalid whiteouts from the old tree.
|
||||
* Remove unneeded leaves from the old tree.
|
||||
* Remove directories from the lookup chains.
|
||||
*/
|
||||
void
|
||||
removeoldleaves()
|
||||
{
|
||||
register struct entry *ep, *nextep;
|
||||
register ino_t i, mydirino;
|
||||
|
||||
vprintf(stdout, "Mark entries to be removed.\n");
|
||||
if (ep = lookupino(WINO)) {
|
||||
vprintf(stdout, "Delete whiteouts\n");
|
||||
for ( ; ep != NULL; ep = nextep) {
|
||||
nextep = ep->e_links;
|
||||
mydirino = ep->e_parent->e_ino;
|
||||
/*
|
||||
* We remove all whiteouts that are in directories
|
||||
* that have been removed or that have been dumped.
|
||||
*/
|
||||
if (TSTINO(mydirino, usedinomap) &&
|
||||
!TSTINO(mydirino, dumpmap))
|
||||
continue;
|
||||
delwhiteout(ep);
|
||||
freeentry(ep);
|
||||
}
|
||||
}
|
||||
for (i = ROOTINO + 1; i < maxino; i++) {
|
||||
ep = lookupino(i);
|
||||
if (ep == NULL)
|
||||
continue;
|
||||
if (TSTINO(i, usedinomap))
|
||||
continue;
|
||||
for ( ; ep != NULL; ep = ep->e_links) {
|
||||
dprintf(stdout, "%s: REMOVE\n", myname(ep));
|
||||
if (ep->e_type == LEAF) {
|
||||
removeleaf(ep);
|
||||
freeentry(ep);
|
||||
} else {
|
||||
mktempname(ep);
|
||||
deleteino(ep->e_ino);
|
||||
ep->e_next = removelist;
|
||||
removelist = ep;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For each directory entry on the incremental tape, determine which
|
||||
* category it falls into as follows:
|
||||
* KEEP - entries that are to be left alone.
|
||||
* NEW - new entries to be added.
|
||||
* EXTRACT - files that must be updated with new contents.
|
||||
* LINK - new links to be added.
|
||||
* Renames are done at the same time.
|
||||
*/
|
||||
long
|
||||
nodeupdates(name, ino, type)
|
||||
char *name;
|
||||
ino_t ino;
|
||||
int type;
|
||||
{
|
||||
register struct entry *ep, *np, *ip;
|
||||
long descend = GOOD;
|
||||
int lookuptype = 0;
|
||||
int key = 0;
|
||||
/* key values */
|
||||
# define ONTAPE 0x1 /* inode is on the tape */
|
||||
# define INOFND 0x2 /* inode already exists */
|
||||
# define NAMEFND 0x4 /* name already exists */
|
||||
# define MODECHG 0x8 /* mode of inode changed */
|
||||
|
||||
/*
|
||||
* This routine is called once for each element in the
|
||||
* directory hierarchy, with a full path name.
|
||||
* The "type" value is incorrectly specified as LEAF for
|
||||
* directories that are not on the dump tape.
|
||||
*
|
||||
* Check to see if the file is on the tape.
|
||||
*/
|
||||
if (TSTINO(ino, dumpmap))
|
||||
key |= ONTAPE;
|
||||
/*
|
||||
* Check to see if the name exists, and if the name is a link.
|
||||
*/
|
||||
np = lookupname(name);
|
||||
if (np != NULL) {
|
||||
key |= NAMEFND;
|
||||
ip = lookupino(np->e_ino);
|
||||
if (ip == NULL)
|
||||
panic("corrupted symbol table\n");
|
||||
if (ip != np)
|
||||
lookuptype = LINK;
|
||||
}
|
||||
/*
|
||||
* Check to see if the inode exists, and if one of its links
|
||||
* corresponds to the name (if one was found).
|
||||
*/
|
||||
ip = lookupino(ino);
|
||||
if (ip != NULL) {
|
||||
key |= INOFND;
|
||||
for (ep = ip->e_links; ep != NULL; ep = ep->e_links) {
|
||||
if (ep == np) {
|
||||
ip = ep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If both a name and an inode are found, but they do not
|
||||
* correspond to the same file, then both the inode that has
|
||||
* been found and the inode corresponding to the name that
|
||||
* has been found need to be renamed. The current pathname
|
||||
* is the new name for the inode that has been found. Since
|
||||
* all files to be deleted have already been removed, the
|
||||
* named file is either a now unneeded link, or it must live
|
||||
* under a new name in this dump level. If it is a link, it
|
||||
* can be removed. If it is not a link, it is given a
|
||||
* temporary name in anticipation that it will be renamed
|
||||
* when it is later found by inode number.
|
||||
*/
|
||||
if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
|
||||
if (lookuptype == LINK) {
|
||||
removeleaf(np);
|
||||
freeentry(np);
|
||||
} else {
|
||||
dprintf(stdout, "name/inode conflict, mktempname %s\n",
|
||||
myname(np));
|
||||
mktempname(np);
|
||||
}
|
||||
np = NULL;
|
||||
key &= ~NAMEFND;
|
||||
}
|
||||
if ((key & ONTAPE) &&
|
||||
(((key & INOFND) && ip->e_type != type) ||
|
||||
((key & NAMEFND) && np->e_type != type)))
|
||||
key |= MODECHG;
|
||||
|
||||
/*
|
||||
* Decide on the disposition of the file based on its flags.
|
||||
* Note that we have already handled the case in which
|
||||
* a name and inode are found that correspond to different files.
|
||||
* Thus if both NAMEFND and INOFND are set then ip == np.
|
||||
*/
|
||||
switch (key) {
|
||||
|
||||
/*
|
||||
* A previously existing file has been found.
|
||||
* Mark it as KEEP so that other links to the inode can be
|
||||
* detected, and so that it will not be reclaimed by the search
|
||||
* for unreferenced names.
|
||||
*/
|
||||
case INOFND|NAMEFND:
|
||||
ip->e_flags |= KEEP;
|
||||
dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
|
||||
flagvalues(ip));
|
||||
break;
|
||||
|
||||
/*
|
||||
* A file on the tape has a name which is the same as a name
|
||||
* corresponding to a different file in the previous dump.
|
||||
* Since all files to be deleted have already been removed,
|
||||
* this file is either a now unneeded link, or it must live
|
||||
* under a new name in this dump level. If it is a link, it
|
||||
* can simply be removed. If it is not a link, it is given a
|
||||
* temporary name in anticipation that it will be renamed
|
||||
* when it is later found by inode number (see INOFND case
|
||||
* below). The entry is then treated as a new file.
|
||||
*/
|
||||
case ONTAPE|NAMEFND:
|
||||
case ONTAPE|NAMEFND|MODECHG:
|
||||
if (lookuptype == LINK) {
|
||||
removeleaf(np);
|
||||
freeentry(np);
|
||||
} else {
|
||||
mktempname(np);
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
/*
|
||||
* A previously non-existent file.
|
||||
* Add it to the file system, and request its extraction.
|
||||
* If it is a directory, create it immediately.
|
||||
* (Since the name is unused there can be no conflict)
|
||||
*/
|
||||
case ONTAPE:
|
||||
ep = addentry(name, ino, type);
|
||||
if (type == NODE)
|
||||
newnode(ep);
|
||||
ep->e_flags |= NEW|KEEP;
|
||||
dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
|
||||
flagvalues(ep));
|
||||
break;
|
||||
|
||||
/*
|
||||
* A file with the same inode number, but a different
|
||||
* name has been found. If the other name has not already
|
||||
* been found (indicated by the KEEP flag, see above) then
|
||||
* this must be a new name for the file, and it is renamed.
|
||||
* If the other name has been found then this must be a
|
||||
* link to the file. Hard links to directories are not
|
||||
* permitted, and are either deleted or converted to
|
||||
* symbolic links. Finally, if the file is on the tape,
|
||||
* a request is made to extract it.
|
||||
*/
|
||||
case ONTAPE|INOFND:
|
||||
if (type == LEAF && (ip->e_flags & KEEP) == 0)
|
||||
ip->e_flags |= EXTRACT;
|
||||
/* fall through */
|
||||
case INOFND:
|
||||
if ((ip->e_flags & KEEP) == 0) {
|
||||
renameit(myname(ip), name);
|
||||
moveentry(ip, name);
|
||||
ip->e_flags |= KEEP;
|
||||
dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
|
||||
flagvalues(ip));
|
||||
break;
|
||||
}
|
||||
if (ip->e_type == NODE) {
|
||||
descend = FAIL;
|
||||
fprintf(stderr,
|
||||
"deleted hard link %s to directory %s\n",
|
||||
name, myname(ip));
|
||||
break;
|
||||
}
|
||||
ep = addentry(name, ino, type|LINK);
|
||||
ep->e_flags |= NEW;
|
||||
dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
|
||||
flagvalues(ep));
|
||||
break;
|
||||
|
||||
/*
|
||||
* A previously known file which is to be updated. If it is a link,
|
||||
* then all names referring to the previous file must be removed
|
||||
* so that the subset of them that remain can be recreated.
|
||||
*/
|
||||
case ONTAPE|INOFND|NAMEFND:
|
||||
if (lookuptype == LINK) {
|
||||
removeleaf(np);
|
||||
freeentry(np);
|
||||
ep = addentry(name, ino, type|LINK);
|
||||
if (type == NODE)
|
||||
newnode(ep);
|
||||
ep->e_flags |= NEW|KEEP;
|
||||
dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
|
||||
flagvalues(ep));
|
||||
break;
|
||||
}
|
||||
if (type == LEAF && lookuptype != LINK)
|
||||
np->e_flags |= EXTRACT;
|
||||
np->e_flags |= KEEP;
|
||||
dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
|
||||
flagvalues(np));
|
||||
break;
|
||||
|
||||
/*
|
||||
* An inode is being reused in a completely different way.
|
||||
* Normally an extract can simply do an "unlink" followed
|
||||
* by a "creat". Here we must do effectively the same
|
||||
* thing. The complications arise because we cannot really
|
||||
* delete a directory since it may still contain files
|
||||
* that we need to rename, so we delete it from the symbol
|
||||
* table, and put it on the list to be deleted eventually.
|
||||
* Conversely if a directory is to be created, it must be
|
||||
* done immediately, rather than waiting until the
|
||||
* extraction phase.
|
||||
*/
|
||||
case ONTAPE|INOFND|MODECHG:
|
||||
case ONTAPE|INOFND|NAMEFND|MODECHG:
|
||||
if (ip->e_flags & KEEP) {
|
||||
badentry(ip, "cannot KEEP and change modes");
|
||||
break;
|
||||
}
|
||||
if (ip->e_type == LEAF) {
|
||||
/* changing from leaf to node */
|
||||
removeleaf(ip);
|
||||
freeentry(ip);
|
||||
ip = addentry(name, ino, type);
|
||||
newnode(ip);
|
||||
} else {
|
||||
/* changing from node to leaf */
|
||||
if ((ip->e_flags & TMPNAME) == 0)
|
||||
mktempname(ip);
|
||||
deleteino(ip->e_ino);
|
||||
ip->e_next = removelist;
|
||||
removelist = ip;
|
||||
ip = addentry(name, ino, type);
|
||||
}
|
||||
ip->e_flags |= NEW|KEEP;
|
||||
dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
|
||||
flagvalues(ip));
|
||||
break;
|
||||
|
||||
/*
|
||||
* A hard link to a diirectory that has been removed.
|
||||
* Ignore it.
|
||||
*/
|
||||
case NAMEFND:
|
||||
dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
|
||||
name);
|
||||
descend = FAIL;
|
||||
break;
|
||||
|
||||
/*
|
||||
* If we find a directory entry for a file that is not on
|
||||
* the tape, then we must have found a file that was created
|
||||
* while the dump was in progress. Since we have no contents
|
||||
* for it, we discard the name knowing that it will be on the
|
||||
* next incremental tape.
|
||||
*/
|
||||
case NULL:
|
||||
fprintf(stderr, "%s: (inode %d) not found on tape\n",
|
||||
name, ino);
|
||||
break;
|
||||
|
||||
/*
|
||||
* If any of these arise, something is grievously wrong with
|
||||
* the current state of the symbol table.
|
||||
*/
|
||||
case INOFND|NAMEFND|MODECHG:
|
||||
case NAMEFND|MODECHG:
|
||||
case INOFND|MODECHG:
|
||||
fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key),
|
||||
name);
|
||||
break;
|
||||
|
||||
/*
|
||||
* These states "cannot" arise for any state of the symbol table.
|
||||
*/
|
||||
case ONTAPE|MODECHG:
|
||||
case MODECHG:
|
||||
default:
|
||||
panic("[%s] %s: impossible state\n", keyval(key), name);
|
||||
break;
|
||||
}
|
||||
return (descend);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the active flags in a key.
|
||||
*/
|
||||
static char *
|
||||
keyval(key)
|
||||
int key;
|
||||
{
|
||||
static char keybuf[32];
|
||||
|
||||
(void) strcpy(keybuf, "|NIL");
|
||||
keybuf[0] = '\0';
|
||||
if (key & ONTAPE)
|
||||
(void) strcat(keybuf, "|ONTAPE");
|
||||
if (key & INOFND)
|
||||
(void) strcat(keybuf, "|INOFND");
|
||||
if (key & NAMEFND)
|
||||
(void) strcat(keybuf, "|NAMEFND");
|
||||
if (key & MODECHG)
|
||||
(void) strcat(keybuf, "|MODECHG");
|
||||
return (&keybuf[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find unreferenced link names.
|
||||
*/
|
||||
void
|
||||
findunreflinks()
|
||||
{
|
||||
register struct entry *ep, *np;
|
||||
register ino_t i;
|
||||
|
||||
vprintf(stdout, "Find unreferenced names.\n");
|
||||
for (i = ROOTINO; i < maxino; i++) {
|
||||
ep = lookupino(i);
|
||||
if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
|
||||
continue;
|
||||
for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
|
||||
if (np->e_flags == 0) {
|
||||
dprintf(stdout,
|
||||
"%s: remove unreferenced name\n",
|
||||
myname(np));
|
||||
removeleaf(np);
|
||||
freeentry(np);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Any leaves remaining in removed directories is unreferenced.
|
||||
*/
|
||||
for (ep = removelist; ep != NULL; ep = ep->e_next) {
|
||||
for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
|
||||
if (np->e_type == LEAF) {
|
||||
if (np->e_flags != 0)
|
||||
badentry(np, "unreferenced with flags");
|
||||
dprintf(stdout,
|
||||
"%s: remove unreferenced name\n",
|
||||
myname(np));
|
||||
removeleaf(np);
|
||||
freeentry(np);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove old nodes (directories).
|
||||
* Note that this routine runs in O(N*D) where:
|
||||
* N is the number of directory entries to be removed.
|
||||
* D is the maximum depth of the tree.
|
||||
* If N == D this can be quite slow. If the list were
|
||||
* topologically sorted, the deletion could be done in
|
||||
* time O(N).
|
||||
*/
|
||||
void
|
||||
removeoldnodes()
|
||||
{
|
||||
register struct entry *ep, **prev;
|
||||
long change;
|
||||
|
||||
vprintf(stdout, "Remove old nodes (directories).\n");
|
||||
do {
|
||||
change = 0;
|
||||
prev = &removelist;
|
||||
for (ep = removelist; ep != NULL; ep = *prev) {
|
||||
if (ep->e_entries != NULL) {
|
||||
prev = &ep->e_next;
|
||||
continue;
|
||||
}
|
||||
*prev = ep->e_next;
|
||||
removenode(ep);
|
||||
freeentry(ep);
|
||||
change++;
|
||||
}
|
||||
} while (change);
|
||||
for (ep = removelist; ep != NULL; ep = ep->e_next)
|
||||
badentry(ep, "cannot remove, non-empty");
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the routine used to extract files for the 'r' command.
|
||||
* Extract new leaves.
|
||||
*/
|
||||
void
|
||||
createleaves(symtabfile)
|
||||
char *symtabfile;
|
||||
{
|
||||
register struct entry *ep;
|
||||
ino_t first;
|
||||
long curvol;
|
||||
|
||||
if (command == 'R') {
|
||||
vprintf(stdout, "Continue extraction of new leaves\n");
|
||||
} else {
|
||||
vprintf(stdout, "Extract new leaves.\n");
|
||||
dumpsymtable(symtabfile, volno);
|
||||
}
|
||||
first = lowerbnd(ROOTINO);
|
||||
curvol = volno;
|
||||
while (curfile.ino < maxino) {
|
||||
first = lowerbnd(first);
|
||||
/*
|
||||
* If the next available file is not the one which we
|
||||
* expect then we have missed one or more files. Since
|
||||
* we do not request files that were not on the tape,
|
||||
* the lost files must have been due to a tape read error,
|
||||
* or a file that was removed while the dump was in progress.
|
||||
*/
|
||||
while (first < curfile.ino) {
|
||||
ep = lookupino(first);
|
||||
if (ep == NULL)
|
||||
panic("%d: bad first\n", first);
|
||||
fprintf(stderr, "%s: not found on tape\n", myname(ep));
|
||||
ep->e_flags &= ~(NEW|EXTRACT);
|
||||
first = lowerbnd(first);
|
||||
}
|
||||
/*
|
||||
* If we find files on the tape that have no corresponding
|
||||
* directory entries, then we must have found a file that
|
||||
* was created while the dump was in progress. Since we have
|
||||
* no name for it, we discard it knowing that it will be
|
||||
* on the next incremental tape.
|
||||
*/
|
||||
if (first != curfile.ino) {
|
||||
fprintf(stderr, "expected next file %d, got %d\n",
|
||||
first, curfile.ino);
|
||||
skipfile();
|
||||
goto next;
|
||||
}
|
||||
ep = lookupino(curfile.ino);
|
||||
if (ep == NULL)
|
||||
panic("unknown file on tape\n");
|
||||
if ((ep->e_flags & (NEW|EXTRACT)) == 0)
|
||||
badentry(ep, "unexpected file on tape");
|
||||
/*
|
||||
* If the file is to be extracted, then the old file must
|
||||
* be removed since its type may change from one leaf type
|
||||
* to another (eg "file" to "character special").
|
||||
*/
|
||||
if ((ep->e_flags & EXTRACT) != 0) {
|
||||
removeleaf(ep);
|
||||
ep->e_flags &= ~REMOVED;
|
||||
}
|
||||
(void) extractfile(myname(ep));
|
||||
ep->e_flags &= ~(NEW|EXTRACT);
|
||||
/*
|
||||
* We checkpoint the restore after every tape reel, so
|
||||
* as to simplify the amount of work re quired by the
|
||||
* 'R' command.
|
||||
*/
|
||||
next:
|
||||
if (curvol != volno) {
|
||||
dumpsymtable(symtabfile, volno);
|
||||
skipmaps();
|
||||
curvol = volno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the routine used to extract files for the 'x' and 'i' commands.
|
||||
* Efficiently extract a subset of the files on a tape.
|
||||
*/
|
||||
void
|
||||
createfiles()
|
||||
{
|
||||
register ino_t first, next, last;
|
||||
register struct entry *ep;
|
||||
long curvol;
|
||||
|
||||
vprintf(stdout, "Extract requested files\n");
|
||||
curfile.action = SKIP;
|
||||
getvol((long)1);
|
||||
skipmaps();
|
||||
skipdirs();
|
||||
first = lowerbnd(ROOTINO);
|
||||
last = upperbnd(maxino - 1);
|
||||
for (;;) {
|
||||
first = lowerbnd(first);
|
||||
last = upperbnd(last);
|
||||
/*
|
||||
* Check to see if any files remain to be extracted
|
||||
*/
|
||||
if (first > last)
|
||||
return;
|
||||
/*
|
||||
* Reject any volumes with inodes greater
|
||||
* than the last one needed
|
||||
*/
|
||||
while (curfile.ino > last) {
|
||||
curfile.action = SKIP;
|
||||
getvol((long)0);
|
||||
skipmaps();
|
||||
skipdirs();
|
||||
}
|
||||
/*
|
||||
* Decide on the next inode needed.
|
||||
* Skip across the inodes until it is found
|
||||
* or an out of order volume change is encountered
|
||||
*/
|
||||
next = lowerbnd(curfile.ino);
|
||||
do {
|
||||
curvol = volno;
|
||||
while (next > curfile.ino && volno == curvol)
|
||||
skipfile();
|
||||
skipmaps();
|
||||
skipdirs();
|
||||
} while (volno == curvol + 1);
|
||||
/*
|
||||
* If volume change out of order occurred the
|
||||
* current state must be recalculated
|
||||
*/
|
||||
if (volno != curvol)
|
||||
continue;
|
||||
/*
|
||||
* If the current inode is greater than the one we were
|
||||
* looking for then we missed the one we were looking for.
|
||||
* Since we only attempt to extract files listed in the
|
||||
* dump map, the lost files must have been due to a tape
|
||||
* read error, or a file that was removed while the dump
|
||||
* was in progress. Thus we report all requested files
|
||||
* between the one we were looking for, and the one we
|
||||
* found as missing, and delete their request flags.
|
||||
*/
|
||||
while (next < curfile.ino) {
|
||||
ep = lookupino(next);
|
||||
if (ep == NULL)
|
||||
panic("corrupted symbol table\n");
|
||||
fprintf(stderr, "%s: not found on tape\n", myname(ep));
|
||||
ep->e_flags &= ~NEW;
|
||||
next = lowerbnd(next);
|
||||
}
|
||||
/*
|
||||
* The current inode is the one that we are looking for,
|
||||
* so extract it per its requested name.
|
||||
*/
|
||||
if (next == curfile.ino && next <= last) {
|
||||
ep = lookupino(next);
|
||||
if (ep == NULL)
|
||||
panic("corrupted symbol table\n");
|
||||
(void) extractfile(myname(ep));
|
||||
ep->e_flags &= ~NEW;
|
||||
if (volno != curvol)
|
||||
skipmaps();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add links.
|
||||
*/
|
||||
void
|
||||
createlinks()
|
||||
{
|
||||
register struct entry *np, *ep;
|
||||
register ino_t i;
|
||||
char name[BUFSIZ];
|
||||
|
||||
if (ep = lookupino(WINO)) {
|
||||
vprintf(stdout, "Add whiteouts\n");
|
||||
for ( ; ep != NULL; ep = ep->e_links) {
|
||||
if ((ep->e_flags & NEW) == 0)
|
||||
continue;
|
||||
(void) addwhiteout(myname(ep));
|
||||
ep->e_flags &= ~NEW;
|
||||
}
|
||||
}
|
||||
vprintf(stdout, "Add links\n");
|
||||
for (i = ROOTINO; i < maxino; i++) {
|
||||
ep = lookupino(i);
|
||||
if (ep == NULL)
|
||||
continue;
|
||||
for (np = ep->e_links; np != NULL; np = np->e_links) {
|
||||
if ((np->e_flags & NEW) == 0)
|
||||
continue;
|
||||
(void) strcpy(name, myname(ep));
|
||||
if (ep->e_type == NODE) {
|
||||
(void) linkit(name, myname(np), SYMLINK);
|
||||
} else {
|
||||
(void) linkit(name, myname(np), HARDLINK);
|
||||
}
|
||||
np->e_flags &= ~NEW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the symbol table.
|
||||
* We do this to insure that all the requested work was done, and
|
||||
* that no temporary names remain.
|
||||
*/
|
||||
void
|
||||
checkrestore()
|
||||
{
|
||||
register struct entry *ep;
|
||||
register ino_t i;
|
||||
|
||||
vprintf(stdout, "Check the symbol table.\n");
|
||||
for (i = WINO; i < maxino; i++) {
|
||||
for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
|
||||
ep->e_flags &= ~KEEP;
|
||||
if (ep->e_type == NODE)
|
||||
ep->e_flags &= ~(NEW|EXISTED);
|
||||
if (ep->e_flags != NULL)
|
||||
badentry(ep, "incomplete operations");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare with the directory structure on the tape
|
||||
* A paranoid check that things are as they should be.
|
||||
*/
|
||||
long
|
||||
verifyfile(name, ino, type)
|
||||
char *name;
|
||||
ino_t ino;
|
||||
int type;
|
||||
{
|
||||
struct entry *np, *ep;
|
||||
long descend = GOOD;
|
||||
|
||||
ep = lookupname(name);
|
||||
if (ep == NULL) {
|
||||
fprintf(stderr, "Warning: missing name %s\n", name);
|
||||
return (FAIL);
|
||||
}
|
||||
np = lookupino(ino);
|
||||
if (np != ep)
|
||||
descend = FAIL;
|
||||
for ( ; np != NULL; np = np->e_links)
|
||||
if (np == ep)
|
||||
break;
|
||||
if (np == NULL)
|
||||
panic("missing inumber %d\n", ino);
|
||||
if (ep->e_type == LEAF && type != LEAF)
|
||||
badentry(ep, "type should be LEAF");
|
||||
return (descend);
|
||||
}
|
||||
139
sbin/restore/restore.h
Normal file
139
sbin/restore/restore.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* (c) UNIX System Laboratories, Inc.
|
||||
* All or some portions of this file are derived from material licensed
|
||||
* to the University of California by American Telephone and Telegraph
|
||||
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
||||
* the permission of UNIX System Laboratories, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)restore.h 8.3 (Berkeley) 9/13/94
|
||||
*/
|
||||
|
||||
/*
|
||||
* Flags
|
||||
*/
|
||||
extern int cvtflag; /* convert from old to new tape format */
|
||||
extern int bflag; /* set input block size */
|
||||
extern int dflag; /* print out debugging info */
|
||||
extern int hflag; /* restore heirarchies */
|
||||
extern int mflag; /* restore by name instead of inode number */
|
||||
extern int Nflag; /* do not write the disk */
|
||||
extern int vflag; /* print out actions taken */
|
||||
extern int yflag; /* always try to recover from tape errors */
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
extern char *dumpmap; /* map of inodes on this dump tape */
|
||||
extern char *usedinomap; /* map of inodes that are in use on this fs */
|
||||
extern ino_t maxino; /* highest numbered inode in this file system */
|
||||
extern long dumpnum; /* location of the dump on this tape */
|
||||
extern long volno; /* current volume being read */
|
||||
extern long ntrec; /* number of TP_BSIZE records per tape block */
|
||||
extern time_t dumptime; /* time that this dump begins */
|
||||
extern time_t dumpdate; /* time that this dump was made */
|
||||
extern char command; /* opration being performed */
|
||||
extern FILE *terminal; /* file descriptor for the terminal input */
|
||||
extern int oldinofmt; /* reading tape with old format inodes */
|
||||
extern int Bcvt; /* need byte swapping on inodes and dirs */
|
||||
|
||||
/*
|
||||
* Each file in the file system is described by one of these entries
|
||||
*/
|
||||
struct entry {
|
||||
char *e_name; /* the current name of this entry */
|
||||
u_char e_namlen; /* length of this name */
|
||||
char e_type; /* type of this entry, see below */
|
||||
short e_flags; /* status flags, see below */
|
||||
ino_t e_ino; /* inode number in previous file sys */
|
||||
long e_index; /* unique index (for dumpped table) */
|
||||
struct entry *e_parent; /* pointer to parent directory (..) */
|
||||
struct entry *e_sibling; /* next element in this directory (.) */
|
||||
struct entry *e_links; /* hard links to this inode */
|
||||
struct entry *e_entries; /* for directories, their entries */
|
||||
struct entry *e_next; /* hash chain list */
|
||||
};
|
||||
/* types */
|
||||
#define LEAF 1 /* non-directory entry */
|
||||
#define NODE 2 /* directory entry */
|
||||
#define LINK 4 /* synthesized type, stripped by addentry */
|
||||
/* flags */
|
||||
#define EXTRACT 0x0001 /* entry is to be replaced from the tape */
|
||||
#define NEW 0x0002 /* a new entry to be extracted */
|
||||
#define KEEP 0x0004 /* entry is not to change */
|
||||
#define REMOVED 0x0010 /* entry has been removed */
|
||||
#define TMPNAME 0x0020 /* entry has been given a temporary name */
|
||||
#define EXISTED 0x0040 /* directory already existed during extract */
|
||||
|
||||
/*
|
||||
* Constants associated with entry structs
|
||||
*/
|
||||
#define HARDLINK 1
|
||||
#define SYMLINK 2
|
||||
#define TMPHDR "RSTTMP"
|
||||
|
||||
/*
|
||||
* The entry describes the next file available on the tape
|
||||
*/
|
||||
struct context {
|
||||
char *name; /* name of file */
|
||||
ino_t ino; /* inumber of file */
|
||||
struct dinode *dip; /* pointer to inode */
|
||||
char action; /* action being taken on this file */
|
||||
} curfile;
|
||||
/* actions */
|
||||
#define USING 1 /* extracting from the tape */
|
||||
#define SKIP 2 /* skipping */
|
||||
#define UNKNOWN 3 /* disposition or starting point is unknown */
|
||||
|
||||
/*
|
||||
* Definitions for library routines operating on directories.
|
||||
*/
|
||||
typedef struct rstdirdesc RST_DIR;
|
||||
|
||||
/*
|
||||
* Flags to setdirmodes.
|
||||
*/
|
||||
#define FORCE 0x0001
|
||||
|
||||
/*
|
||||
* Useful macros
|
||||
*/
|
||||
#define TSTINO(ino, map) \
|
||||
(map[(u_int)((ino) - 1) / NBBY] & (1 << ((u_int)((ino) - 1) % NBBY)))
|
||||
#define SETINO(ino, map) \
|
||||
map[(u_int)((ino) - 1) / NBBY] |= 1 << ((u_int)((ino) - 1) % NBBY)
|
||||
|
||||
#define dprintf if (dflag) fprintf
|
||||
#define vprintf if (vflag) fprintf
|
||||
|
||||
#define GOOD 1
|
||||
#define FAIL 0
|
||||
628
sbin/restore/symtab.c
Normal file
628
sbin/restore/symtab.c
Normal file
|
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)symtab.c 8.3 (Berkeley) 4/28/95";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* These routines maintain the symbol table which tracks the state
|
||||
* of the file system being restored. They provide lookup by either
|
||||
* name or inode number. They also provide for creation, deletion,
|
||||
* and renaming of entries. Because of the dynamic nature of pathnames,
|
||||
* names should not be saved, but always constructed just before they
|
||||
* are needed, by calling "myname".
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "restore.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* The following variables define the inode symbol table.
|
||||
* The primary hash table is dynamically allocated based on
|
||||
* the number of inodes in the file system (maxino), scaled by
|
||||
* HASHFACTOR. The variable "entry" points to the hash table;
|
||||
* the variable "entrytblsize" indicates its size (in entries).
|
||||
*/
|
||||
#define HASHFACTOR 5
|
||||
static struct entry **entry;
|
||||
static long entrytblsize;
|
||||
|
||||
static void addino __P((ino_t, struct entry *));
|
||||
static struct entry *lookupparent __P((char *));
|
||||
static void removeentry __P((struct entry *));
|
||||
|
||||
/*
|
||||
* Look up an entry by inode number
|
||||
*/
|
||||
struct entry *
|
||||
lookupino(inum)
|
||||
ino_t inum;
|
||||
{
|
||||
register struct entry *ep;
|
||||
|
||||
if (inum < WINO || inum >= maxino)
|
||||
return (NULL);
|
||||
for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next)
|
||||
if (ep->e_ino == inum)
|
||||
return (ep);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an entry into the entry table
|
||||
*/
|
||||
static void
|
||||
addino(inum, np)
|
||||
ino_t inum;
|
||||
struct entry *np;
|
||||
{
|
||||
struct entry **epp;
|
||||
|
||||
if (inum < WINO || inum >= maxino)
|
||||
panic("addino: out of range %d\n", inum);
|
||||
epp = &entry[inum % entrytblsize];
|
||||
np->e_ino = inum;
|
||||
np->e_next = *epp;
|
||||
*epp = np;
|
||||
if (dflag)
|
||||
for (np = np->e_next; np != NULL; np = np->e_next)
|
||||
if (np->e_ino == inum)
|
||||
badentry(np, "duplicate inum");
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete an entry from the entry table
|
||||
*/
|
||||
void
|
||||
deleteino(inum)
|
||||
ino_t inum;
|
||||
{
|
||||
register struct entry *next;
|
||||
struct entry **prev;
|
||||
|
||||
if (inum < WINO || inum >= maxino)
|
||||
panic("deleteino: out of range %d\n", inum);
|
||||
prev = &entry[inum % entrytblsize];
|
||||
for (next = *prev; next != NULL; next = next->e_next) {
|
||||
if (next->e_ino == inum) {
|
||||
next->e_ino = 0;
|
||||
*prev = next->e_next;
|
||||
return;
|
||||
}
|
||||
prev = &next->e_next;
|
||||
}
|
||||
panic("deleteino: %d not found\n", inum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an entry by name
|
||||
*/
|
||||
struct entry *
|
||||
lookupname(name)
|
||||
char *name;
|
||||
{
|
||||
register struct entry *ep;
|
||||
register char *np, *cp;
|
||||
char buf[MAXPATHLEN];
|
||||
|
||||
cp = name;
|
||||
for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) {
|
||||
for (np = buf; *cp != '/' && *cp != '\0'; )
|
||||
*np++ = *cp++;
|
||||
*np = '\0';
|
||||
for ( ; ep != NULL; ep = ep->e_sibling)
|
||||
if (strcmp(ep->e_name, buf) == 0)
|
||||
break;
|
||||
if (ep == NULL)
|
||||
break;
|
||||
if (*cp++ == '\0')
|
||||
return (ep);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the parent of a pathname
|
||||
*/
|
||||
static struct entry *
|
||||
lookupparent(name)
|
||||
char *name;
|
||||
{
|
||||
struct entry *ep;
|
||||
char *tailindex;
|
||||
|
||||
tailindex = strrchr(name, '/');
|
||||
if (tailindex == NULL)
|
||||
return (NULL);
|
||||
*tailindex = '\0';
|
||||
ep = lookupname(name);
|
||||
*tailindex = '/';
|
||||
if (ep == NULL)
|
||||
return (NULL);
|
||||
if (ep->e_type != NODE)
|
||||
panic("%s is not a directory\n", name);
|
||||
return (ep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the current pathname of a node or leaf
|
||||
*/
|
||||
char *
|
||||
myname(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
register char *cp;
|
||||
static char namebuf[MAXPATHLEN];
|
||||
|
||||
for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
|
||||
cp -= ep->e_namlen;
|
||||
memmove(cp, ep->e_name, (long)ep->e_namlen);
|
||||
if (ep == lookupino(ROOTINO))
|
||||
return (cp);
|
||||
*(--cp) = '/';
|
||||
ep = ep->e_parent;
|
||||
}
|
||||
panic("%s: pathname too long\n", cp);
|
||||
return(cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unused symbol table entries are linked together on a freelist
|
||||
* headed by the following pointer.
|
||||
*/
|
||||
static struct entry *freelist = NULL;
|
||||
|
||||
/*
|
||||
* add an entry to the symbol table
|
||||
*/
|
||||
struct entry *
|
||||
addentry(name, inum, type)
|
||||
char *name;
|
||||
ino_t inum;
|
||||
int type;
|
||||
{
|
||||
register struct entry *np, *ep;
|
||||
|
||||
if (freelist != NULL) {
|
||||
np = freelist;
|
||||
freelist = np->e_next;
|
||||
memset(np, 0, (long)sizeof(struct entry));
|
||||
} else {
|
||||
np = (struct entry *)calloc(1, sizeof(struct entry));
|
||||
if (np == NULL)
|
||||
panic("no memory to extend symbol table\n");
|
||||
}
|
||||
np->e_type = type & ~LINK;
|
||||
ep = lookupparent(name);
|
||||
if (ep == NULL) {
|
||||
if (inum != ROOTINO || lookupino(ROOTINO) != NULL)
|
||||
panic("bad name to addentry %s\n", name);
|
||||
np->e_name = savename(name);
|
||||
np->e_namlen = strlen(name);
|
||||
np->e_parent = np;
|
||||
addino(ROOTINO, np);
|
||||
return (np);
|
||||
}
|
||||
np->e_name = savename(strrchr(name, '/') + 1);
|
||||
np->e_namlen = strlen(np->e_name);
|
||||
np->e_parent = ep;
|
||||
np->e_sibling = ep->e_entries;
|
||||
ep->e_entries = np;
|
||||
if (type & LINK) {
|
||||
ep = lookupino(inum);
|
||||
if (ep == NULL)
|
||||
panic("link to non-existant name\n");
|
||||
np->e_ino = inum;
|
||||
np->e_links = ep->e_links;
|
||||
ep->e_links = np;
|
||||
} else if (inum != 0) {
|
||||
if (lookupino(inum) != NULL)
|
||||
panic("duplicate entry\n");
|
||||
addino(inum, np);
|
||||
}
|
||||
return (np);
|
||||
}
|
||||
|
||||
/*
|
||||
* delete an entry from the symbol table
|
||||
*/
|
||||
void
|
||||
freeentry(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
register struct entry *np;
|
||||
ino_t inum;
|
||||
|
||||
if (ep->e_flags != REMOVED)
|
||||
badentry(ep, "not marked REMOVED");
|
||||
if (ep->e_type == NODE) {
|
||||
if (ep->e_links != NULL)
|
||||
badentry(ep, "freeing referenced directory");
|
||||
if (ep->e_entries != NULL)
|
||||
badentry(ep, "freeing non-empty directory");
|
||||
}
|
||||
if (ep->e_ino != 0) {
|
||||
np = lookupino(ep->e_ino);
|
||||
if (np == NULL)
|
||||
badentry(ep, "lookupino failed");
|
||||
if (np == ep) {
|
||||
inum = ep->e_ino;
|
||||
deleteino(inum);
|
||||
if (ep->e_links != NULL)
|
||||
addino(inum, ep->e_links);
|
||||
} else {
|
||||
for (; np != NULL; np = np->e_links) {
|
||||
if (np->e_links == ep) {
|
||||
np->e_links = ep->e_links;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (np == NULL)
|
||||
badentry(ep, "link not found");
|
||||
}
|
||||
}
|
||||
removeentry(ep);
|
||||
freename(ep->e_name);
|
||||
ep->e_next = freelist;
|
||||
freelist = ep;
|
||||
}
|
||||
|
||||
/*
|
||||
* Relocate an entry in the tree structure
|
||||
*/
|
||||
void
|
||||
moveentry(ep, newname)
|
||||
register struct entry *ep;
|
||||
char *newname;
|
||||
{
|
||||
struct entry *np;
|
||||
char *cp;
|
||||
|
||||
np = lookupparent(newname);
|
||||
if (np == NULL)
|
||||
badentry(ep, "cannot move ROOT");
|
||||
if (np != ep->e_parent) {
|
||||
removeentry(ep);
|
||||
ep->e_parent = np;
|
||||
ep->e_sibling = np->e_entries;
|
||||
np->e_entries = ep;
|
||||
}
|
||||
cp = strrchr(newname, '/') + 1;
|
||||
freename(ep->e_name);
|
||||
ep->e_name = savename(cp);
|
||||
ep->e_namlen = strlen(cp);
|
||||
if (strcmp(gentempname(ep), ep->e_name) == 0)
|
||||
ep->e_flags |= TMPNAME;
|
||||
else
|
||||
ep->e_flags &= ~TMPNAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an entry in the tree structure
|
||||
*/
|
||||
static void
|
||||
removeentry(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
register struct entry *np;
|
||||
|
||||
np = ep->e_parent;
|
||||
if (np->e_entries == ep) {
|
||||
np->e_entries = ep->e_sibling;
|
||||
} else {
|
||||
for (np = np->e_entries; np != NULL; np = np->e_sibling) {
|
||||
if (np->e_sibling == ep) {
|
||||
np->e_sibling = ep->e_sibling;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (np == NULL)
|
||||
badentry(ep, "cannot find entry in parent list");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Table of unused string entries, sorted by length.
|
||||
*
|
||||
* Entries are allocated in STRTBLINCR sized pieces so that names
|
||||
* of similar lengths can use the same entry. The value of STRTBLINCR
|
||||
* is chosen so that every entry has at least enough space to hold
|
||||
* a "struct strtbl" header. Thus every entry can be linked onto an
|
||||
* apprpriate free list.
|
||||
*
|
||||
* NB. The macro "allocsize" below assumes that "struct strhdr"
|
||||
* has a size that is a power of two.
|
||||
*/
|
||||
struct strhdr {
|
||||
struct strhdr *next;
|
||||
};
|
||||
|
||||
#define STRTBLINCR (sizeof(struct strhdr))
|
||||
#define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
|
||||
|
||||
static struct strhdr strtblhdr[allocsize(NAME_MAX) / STRTBLINCR];
|
||||
|
||||
/*
|
||||
* Allocate space for a name. It first looks to see if it already
|
||||
* has an appropriate sized entry, and if not allocates a new one.
|
||||
*/
|
||||
char *
|
||||
savename(name)
|
||||
char *name;
|
||||
{
|
||||
struct strhdr *np;
|
||||
long len;
|
||||
char *cp;
|
||||
|
||||
if (name == NULL)
|
||||
panic("bad name\n");
|
||||
len = strlen(name);
|
||||
np = strtblhdr[len / STRTBLINCR].next;
|
||||
if (np != NULL) {
|
||||
strtblhdr[len / STRTBLINCR].next = np->next;
|
||||
cp = (char *)np;
|
||||
} else {
|
||||
cp = malloc((unsigned)allocsize(len));
|
||||
if (cp == NULL)
|
||||
panic("no space for string table\n");
|
||||
}
|
||||
(void) strcpy(cp, name);
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free space for a name. The resulting entry is linked onto the
|
||||
* appropriate free list.
|
||||
*/
|
||||
void
|
||||
freename(name)
|
||||
char *name;
|
||||
{
|
||||
struct strhdr *tp, *np;
|
||||
|
||||
tp = &strtblhdr[strlen(name) / STRTBLINCR];
|
||||
np = (struct strhdr *)name;
|
||||
np->next = tp->next;
|
||||
tp->next = np;
|
||||
}
|
||||
|
||||
/*
|
||||
* Useful quantities placed at the end of a dumped symbol table.
|
||||
*/
|
||||
struct symtableheader {
|
||||
long volno;
|
||||
long stringsize;
|
||||
long entrytblsize;
|
||||
time_t dumptime;
|
||||
time_t dumpdate;
|
||||
ino_t maxino;
|
||||
long ntrec;
|
||||
};
|
||||
|
||||
/*
|
||||
* dump a snapshot of the symbol table
|
||||
*/
|
||||
void
|
||||
dumpsymtable(filename, checkpt)
|
||||
char *filename;
|
||||
long checkpt;
|
||||
{
|
||||
register struct entry *ep, *tep;
|
||||
register ino_t i;
|
||||
struct entry temp, *tentry;
|
||||
long mynum = 1, stroff = 0;
|
||||
FILE *fd;
|
||||
struct symtableheader hdr;
|
||||
|
||||
vprintf(stdout, "Check pointing the restore\n");
|
||||
if (Nflag)
|
||||
return;
|
||||
if ((fd = fopen(filename, "w")) == NULL) {
|
||||
fprintf(stderr, "fopen: %s\n", strerror(errno));
|
||||
panic("cannot create save file %s for symbol table\n",
|
||||
filename);
|
||||
}
|
||||
clearerr(fd);
|
||||
/*
|
||||
* Assign indicies to each entry
|
||||
* Write out the string entries
|
||||
*/
|
||||
for (i = WINO; i <= maxino; i++) {
|
||||
for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
|
||||
ep->e_index = mynum++;
|
||||
(void) fwrite(ep->e_name, sizeof(char),
|
||||
(int)allocsize(ep->e_namlen), fd);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Convert pointers to indexes, and output
|
||||
*/
|
||||
tep = &temp;
|
||||
stroff = 0;
|
||||
for (i = WINO; i <= maxino; i++) {
|
||||
for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
|
||||
memmove(tep, ep, (long)sizeof(struct entry));
|
||||
tep->e_name = (char *)stroff;
|
||||
stroff += allocsize(ep->e_namlen);
|
||||
tep->e_parent = (struct entry *)ep->e_parent->e_index;
|
||||
if (ep->e_links != NULL)
|
||||
tep->e_links =
|
||||
(struct entry *)ep->e_links->e_index;
|
||||
if (ep->e_sibling != NULL)
|
||||
tep->e_sibling =
|
||||
(struct entry *)ep->e_sibling->e_index;
|
||||
if (ep->e_entries != NULL)
|
||||
tep->e_entries =
|
||||
(struct entry *)ep->e_entries->e_index;
|
||||
if (ep->e_next != NULL)
|
||||
tep->e_next =
|
||||
(struct entry *)ep->e_next->e_index;
|
||||
(void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Convert entry pointers to indexes, and output
|
||||
*/
|
||||
for (i = 0; i < entrytblsize; i++) {
|
||||
if (entry[i] == NULL)
|
||||
tentry = NULL;
|
||||
else
|
||||
tentry = (struct entry *)entry[i]->e_index;
|
||||
(void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
|
||||
}
|
||||
hdr.volno = checkpt;
|
||||
hdr.maxino = maxino;
|
||||
hdr.entrytblsize = entrytblsize;
|
||||
hdr.stringsize = stroff;
|
||||
hdr.dumptime = dumptime;
|
||||
hdr.dumpdate = dumpdate;
|
||||
hdr.ntrec = ntrec;
|
||||
(void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
|
||||
if (ferror(fd)) {
|
||||
fprintf(stderr, "fwrite: %s\n", strerror(errno));
|
||||
panic("output error to file %s writing symbol table\n",
|
||||
filename);
|
||||
}
|
||||
(void) fclose(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a symbol table from a file
|
||||
*/
|
||||
void
|
||||
initsymtable(filename)
|
||||
char *filename;
|
||||
{
|
||||
char *base;
|
||||
long tblsize;
|
||||
register struct entry *ep;
|
||||
struct entry *baseep, *lep;
|
||||
struct symtableheader hdr;
|
||||
struct stat stbuf;
|
||||
register long i;
|
||||
int fd;
|
||||
|
||||
vprintf(stdout, "Initialize symbol table.\n");
|
||||
if (filename == NULL) {
|
||||
entrytblsize = maxino / HASHFACTOR;
|
||||
entry = (struct entry **)
|
||||
calloc((unsigned)entrytblsize, sizeof(struct entry *));
|
||||
if (entry == (struct entry **)NULL)
|
||||
panic("no memory for entry table\n");
|
||||
ep = addentry(".", ROOTINO, NODE);
|
||||
ep->e_flags |= NEW;
|
||||
return;
|
||||
}
|
||||
if ((fd = open(filename, O_RDONLY, 0)) < 0) {
|
||||
fprintf(stderr, "open: %s\n", strerror(errno));
|
||||
panic("cannot open symbol table file %s\n", filename);
|
||||
}
|
||||
if (fstat(fd, &stbuf) < 0) {
|
||||
fprintf(stderr, "stat: %s\n", strerror(errno));
|
||||
panic("cannot stat symbol table file %s\n", filename);
|
||||
}
|
||||
tblsize = stbuf.st_size - sizeof(struct symtableheader);
|
||||
base = calloc(sizeof(char), (unsigned)tblsize);
|
||||
if (base == NULL)
|
||||
panic("cannot allocate space for symbol table\n");
|
||||
if (read(fd, base, (int)tblsize) < 0 ||
|
||||
read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
|
||||
fprintf(stderr, "read: %s\n", strerror(errno));
|
||||
panic("cannot read symbol table file %s\n", filename);
|
||||
}
|
||||
switch (command) {
|
||||
case 'r':
|
||||
/*
|
||||
* For normal continuation, insure that we are using
|
||||
* the next incremental tape
|
||||
*/
|
||||
if (hdr.dumpdate != dumptime) {
|
||||
if (hdr.dumpdate < dumptime)
|
||||
fprintf(stderr, "Incremental tape too low\n");
|
||||
else
|
||||
fprintf(stderr, "Incremental tape too high\n");
|
||||
done(1);
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
/*
|
||||
* For restart, insure that we are using the same tape
|
||||
*/
|
||||
curfile.action = SKIP;
|
||||
dumptime = hdr.dumptime;
|
||||
dumpdate = hdr.dumpdate;
|
||||
if (!bflag)
|
||||
newtapebuf(hdr.ntrec);
|
||||
getvol(hdr.volno);
|
||||
break;
|
||||
default:
|
||||
panic("initsymtable called from command %c\n", command);
|
||||
break;
|
||||
}
|
||||
maxino = hdr.maxino;
|
||||
entrytblsize = hdr.entrytblsize;
|
||||
entry = (struct entry **)
|
||||
(base + tblsize - (entrytblsize * sizeof(struct entry *)));
|
||||
baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
|
||||
lep = (struct entry *)entry;
|
||||
for (i = 0; i < entrytblsize; i++) {
|
||||
if (entry[i] == NULL)
|
||||
continue;
|
||||
entry[i] = &baseep[(long)entry[i]];
|
||||
}
|
||||
for (ep = &baseep[1]; ep < lep; ep++) {
|
||||
ep->e_name = base + (long)ep->e_name;
|
||||
ep->e_parent = &baseep[(long)ep->e_parent];
|
||||
if (ep->e_sibling != NULL)
|
||||
ep->e_sibling = &baseep[(long)ep->e_sibling];
|
||||
if (ep->e_links != NULL)
|
||||
ep->e_links = &baseep[(long)ep->e_links];
|
||||
if (ep->e_entries != NULL)
|
||||
ep->e_entries = &baseep[(long)ep->e_entries];
|
||||
if (ep->e_next != NULL)
|
||||
ep->e_next = &baseep[(long)ep->e_next];
|
||||
}
|
||||
}
|
||||
1378
sbin/restore/tape.c
Normal file
1378
sbin/restore/tape.c
Normal file
File diff suppressed because it is too large
Load diff
434
sbin/restore/utilities.c
Normal file
434
sbin/restore/utilities.c
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "restore.h"
|
||||
#include "extern.h"
|
||||
|
||||
/*
|
||||
* Insure that all the components of a pathname exist.
|
||||
*/
|
||||
void
|
||||
pathcheck(name)
|
||||
char *name;
|
||||
{
|
||||
register char *cp;
|
||||
struct entry *ep;
|
||||
char *start;
|
||||
|
||||
start = strchr(name, '/');
|
||||
if (start == 0)
|
||||
return;
|
||||
for (cp = start; *cp != '\0'; cp++) {
|
||||
if (*cp != '/')
|
||||
continue;
|
||||
*cp = '\0';
|
||||
ep = lookupname(name);
|
||||
if (ep == NULL) {
|
||||
/* Safe; we know the pathname exists in the dump. */
|
||||
ep = addentry(name, pathsearch(name)->d_ino, NODE);
|
||||
newnode(ep);
|
||||
}
|
||||
ep->e_flags |= NEW|KEEP;
|
||||
*cp = '/';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change a name to a unique temporary name.
|
||||
*/
|
||||
void
|
||||
mktempname(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
char oldname[MAXPATHLEN];
|
||||
|
||||
if (ep->e_flags & TMPNAME)
|
||||
badentry(ep, "mktempname: called with TMPNAME");
|
||||
ep->e_flags |= TMPNAME;
|
||||
(void) strcpy(oldname, myname(ep));
|
||||
freename(ep->e_name);
|
||||
ep->e_name = savename(gentempname(ep));
|
||||
ep->e_namlen = strlen(ep->e_name);
|
||||
renameit(oldname, myname(ep));
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a temporary name for an entry.
|
||||
*/
|
||||
char *
|
||||
gentempname(ep)
|
||||
struct entry *ep;
|
||||
{
|
||||
static char name[MAXPATHLEN];
|
||||
struct entry *np;
|
||||
long i = 0;
|
||||
|
||||
for (np = lookupino(ep->e_ino);
|
||||
np != NULL && np != ep; np = np->e_links)
|
||||
i++;
|
||||
if (np == NULL)
|
||||
badentry(ep, "not on ino list");
|
||||
(void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino);
|
||||
return (name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename a file or directory.
|
||||
*/
|
||||
void
|
||||
renameit(from, to)
|
||||
char *from, *to;
|
||||
{
|
||||
if (!Nflag && rename(from, to) < 0) {
|
||||
fprintf(stderr, "warning: cannot rename %s to %s: %s\n",
|
||||
from, to, strerror(errno));
|
||||
return;
|
||||
}
|
||||
vprintf(stdout, "rename %s to %s\n", from, to);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new node (directory).
|
||||
*/
|
||||
void
|
||||
newnode(np)
|
||||
struct entry *np;
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (np->e_type != NODE)
|
||||
badentry(np, "newnode: not a node");
|
||||
cp = myname(np);
|
||||
if (!Nflag && mkdir(cp, 0777) < 0) {
|
||||
np->e_flags |= EXISTED;
|
||||
fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
|
||||
return;
|
||||
}
|
||||
vprintf(stdout, "Make node %s\n", cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an old node (directory).
|
||||
*/
|
||||
void
|
||||
removenode(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (ep->e_type != NODE)
|
||||
badentry(ep, "removenode: not a node");
|
||||
if (ep->e_entries != NULL)
|
||||
badentry(ep, "removenode: non-empty directory");
|
||||
ep->e_flags |= REMOVED;
|
||||
ep->e_flags &= ~TMPNAME;
|
||||
cp = myname(ep);
|
||||
if (!Nflag && rmdir(cp) < 0) {
|
||||
fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
|
||||
return;
|
||||
}
|
||||
vprintf(stdout, "Remove node %s\n", cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a leaf.
|
||||
*/
|
||||
void
|
||||
removeleaf(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (ep->e_type != LEAF)
|
||||
badentry(ep, "removeleaf: not a leaf");
|
||||
ep->e_flags |= REMOVED;
|
||||
ep->e_flags &= ~TMPNAME;
|
||||
cp = myname(ep);
|
||||
if (!Nflag && unlink(cp) < 0) {
|
||||
fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
|
||||
return;
|
||||
}
|
||||
vprintf(stdout, "Remove leaf %s\n", cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a link.
|
||||
*/
|
||||
int
|
||||
linkit(existing, new, type)
|
||||
char *existing, *new;
|
||||
int type;
|
||||
{
|
||||
|
||||
if (type == SYMLINK) {
|
||||
if (!Nflag && symlink(existing, new) < 0) {
|
||||
fprintf(stderr,
|
||||
"warning: cannot create symbolic link %s->%s: %s\n",
|
||||
new, existing, strerror(errno));
|
||||
return (FAIL);
|
||||
}
|
||||
} else if (type == HARDLINK) {
|
||||
if (!Nflag && link(existing, new) < 0) {
|
||||
fprintf(stderr,
|
||||
"warning: cannot create hard link %s->%s: %s\n",
|
||||
new, existing, strerror(errno));
|
||||
return (FAIL);
|
||||
}
|
||||
} else {
|
||||
panic("linkit: unknown type %d\n", type);
|
||||
return (FAIL);
|
||||
}
|
||||
vprintf(stdout, "Create %s link %s->%s\n",
|
||||
type == SYMLINK ? "symbolic" : "hard", new, existing);
|
||||
return (GOOD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a whiteout.
|
||||
*/
|
||||
int
|
||||
addwhiteout(name)
|
||||
char *name;
|
||||
{
|
||||
|
||||
if (!Nflag && mknod(name, S_IFWHT, 0) < 0) {
|
||||
fprintf(stderr, "warning: cannot create whiteout %s: %s\n",
|
||||
name, strerror(errno));
|
||||
return (FAIL);
|
||||
}
|
||||
vprintf(stdout, "Create whiteout %s\n", name);
|
||||
return (GOOD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a whiteout.
|
||||
*/
|
||||
void
|
||||
delwhiteout(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (ep->e_type != LEAF)
|
||||
badentry(ep, "delwhiteout: not a leaf");
|
||||
ep->e_flags |= REMOVED;
|
||||
ep->e_flags &= ~TMPNAME;
|
||||
name = myname(ep);
|
||||
if (!Nflag && undelete(name) < 0) {
|
||||
fprintf(stderr, "warning: cannot delete whiteout %s: %s\n",
|
||||
name, strerror(errno));
|
||||
return;
|
||||
}
|
||||
vprintf(stdout, "Delete whiteout %s\n", name);
|
||||
}
|
||||
|
||||
/*
|
||||
* find lowest number file (above "start") that needs to be extracted
|
||||
*/
|
||||
ino_t
|
||||
lowerbnd(start)
|
||||
ino_t start;
|
||||
{
|
||||
register struct entry *ep;
|
||||
|
||||
for ( ; start < maxino; start++) {
|
||||
ep = lookupino(start);
|
||||
if (ep == NULL || ep->e_type == NODE)
|
||||
continue;
|
||||
if (ep->e_flags & (NEW|EXTRACT))
|
||||
return (start);
|
||||
}
|
||||
return (start);
|
||||
}
|
||||
|
||||
/*
|
||||
* find highest number file (below "start") that needs to be extracted
|
||||
*/
|
||||
ino_t
|
||||
upperbnd(start)
|
||||
ino_t start;
|
||||
{
|
||||
register struct entry *ep;
|
||||
|
||||
for ( ; start > ROOTINO; start--) {
|
||||
ep = lookupino(start);
|
||||
if (ep == NULL || ep->e_type == NODE)
|
||||
continue;
|
||||
if (ep->e_flags & (NEW|EXTRACT))
|
||||
return (start);
|
||||
}
|
||||
return (start);
|
||||
}
|
||||
|
||||
/*
|
||||
* report on a badly formed entry
|
||||
*/
|
||||
void
|
||||
badentry(ep, msg)
|
||||
register struct entry *ep;
|
||||
char *msg;
|
||||
{
|
||||
|
||||
fprintf(stderr, "bad entry: %s\n", msg);
|
||||
fprintf(stderr, "name: %s\n", myname(ep));
|
||||
fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
|
||||
if (ep->e_sibling != NULL)
|
||||
fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
|
||||
if (ep->e_entries != NULL)
|
||||
fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
|
||||
if (ep->e_links != NULL)
|
||||
fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
|
||||
if (ep->e_next != NULL)
|
||||
fprintf(stderr,
|
||||
"next hashchain name: %s\n", myname(ep->e_next));
|
||||
fprintf(stderr, "entry type: %s\n",
|
||||
ep->e_type == NODE ? "NODE" : "LEAF");
|
||||
fprintf(stderr, "inode number: %ld\n", ep->e_ino);
|
||||
panic("flags: %s\n", flagvalues(ep));
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a string indicating the active flag bits of an entry.
|
||||
*/
|
||||
char *
|
||||
flagvalues(ep)
|
||||
register struct entry *ep;
|
||||
{
|
||||
static char flagbuf[BUFSIZ];
|
||||
|
||||
(void) strcpy(flagbuf, "|NIL");
|
||||
flagbuf[0] = '\0';
|
||||
if (ep->e_flags & REMOVED)
|
||||
(void) strcat(flagbuf, "|REMOVED");
|
||||
if (ep->e_flags & TMPNAME)
|
||||
(void) strcat(flagbuf, "|TMPNAME");
|
||||
if (ep->e_flags & EXTRACT)
|
||||
(void) strcat(flagbuf, "|EXTRACT");
|
||||
if (ep->e_flags & NEW)
|
||||
(void) strcat(flagbuf, "|NEW");
|
||||
if (ep->e_flags & KEEP)
|
||||
(void) strcat(flagbuf, "|KEEP");
|
||||
if (ep->e_flags & EXISTED)
|
||||
(void) strcat(flagbuf, "|EXISTED");
|
||||
return (&flagbuf[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if a name is on a dump tape.
|
||||
*/
|
||||
ino_t
|
||||
dirlookup(name)
|
||||
const char *name;
|
||||
{
|
||||
struct direct *dp;
|
||||
ino_t ino;
|
||||
|
||||
ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
|
||||
|
||||
if (ino == 0 || TSTINO(ino, dumpmap) == 0)
|
||||
fprintf(stderr, "%s is not on the tape\n", name);
|
||||
return (ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* Elicit a reply.
|
||||
*/
|
||||
int
|
||||
reply(question)
|
||||
char *question;
|
||||
{
|
||||
char c;
|
||||
|
||||
do {
|
||||
fprintf(stderr, "%s? [yn] ", question);
|
||||
(void) fflush(stderr);
|
||||
c = getc(terminal);
|
||||
while (c != '\n' && getc(terminal) != '\n')
|
||||
if (feof(terminal))
|
||||
return (FAIL);
|
||||
} while (c != 'y' && c != 'n');
|
||||
if (c == 'y')
|
||||
return (GOOD);
|
||||
return (FAIL);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle unexpected inconsistencies
|
||||
*/
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
void
|
||||
#if __STDC__
|
||||
panic(const char *fmt, ...)
|
||||
#else
|
||||
panic(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#if __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
|
||||
vfprintf(stderr, fmt, ap);
|
||||
if (yflag)
|
||||
return;
|
||||
if (reply("abort") == GOOD) {
|
||||
if (reply("dump core") == GOOD)
|
||||
abort();
|
||||
done(1);
|
||||
}
|
||||
}
|
||||
13
sbin/umount/Makefile
Normal file
13
sbin/umount/Makefile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# @(#)Makefile 8.4 (Berkeley) 6/22/95
|
||||
|
||||
PROG= umount
|
||||
SRCS= umount.c vfslist.c
|
||||
MAN8= umount.0
|
||||
DPADD= ${LIBRPC}
|
||||
LDADD= -lrpc
|
||||
|
||||
MOUNT= ${.CURDIR}/../../sbin/mount
|
||||
CFLAGS+= -I${MOUNT}
|
||||
.PATH: ${MOUNT}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
126
sbin/umount/umount.8
Normal file
126
sbin/umount/umount.8
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)umount.8 8.2 (Berkeley) 5/8/95
|
||||
.\"
|
||||
.Dd May 8, 1995
|
||||
.Dt UMOUNT 8
|
||||
.Os BSD 4
|
||||
.Sh NAME
|
||||
.Nm umount
|
||||
.Nd unmount filesystems
|
||||
.Sh SYNOPSIS
|
||||
.Nm umount
|
||||
.Op Fl fv
|
||||
.Ar special | node
|
||||
.Nm umount
|
||||
.Fl a | A
|
||||
.Op Fl fv
|
||||
.Op Fl h Ar host
|
||||
.Op Fl t Ar type
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm umount
|
||||
command
|
||||
calls the
|
||||
.Xr unmount 2
|
||||
system call to remove a
|
||||
.Ar "special device"
|
||||
or the remote node (rhost:path) from the filesystem 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 options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a
|
||||
All the filesystems described in
|
||||
.Xr fstab 5
|
||||
are unmounted.
|
||||
.It Fl A
|
||||
All the currently mounted filesystems except
|
||||
the root are unmounted.
|
||||
.It Fl f
|
||||
The filesystem is forcibly unmounted.
|
||||
Active special devices continue to work,
|
||||
but all other files return errors if further accesses are attempted.
|
||||
The root filesystem cannot be forcibly unmounted.
|
||||
.It Fl h Ar host
|
||||
Only filesystems mounted from the specified host will be
|
||||
unmounted.
|
||||
This option is implies the
|
||||
.Fl A
|
||||
option and, unless otherwise specified with the
|
||||
.Fl t
|
||||
option, will only unmount NFS filesystems.
|
||||
.It Fl t Ar type
|
||||
Is used to indicate 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 umount
|
||||
command:
|
||||
.Bd -literal -offset indent
|
||||
umount -a -t nfs,mfs
|
||||
.Ed
|
||||
.Pp
|
||||
umounts all filesystems of the type
|
||||
.Tn NFS
|
||||
and
|
||||
.Tn MFS .
|
||||
.It Fl v
|
||||
Verbose, additional information is printed out as each filesystem
|
||||
is unmounted.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/fstab -compact
|
||||
.It Pa /etc/fstab
|
||||
filesystem table
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr unmount 2 ,
|
||||
.Xr fstab 5 ,
|
||||
.Xr mount 8
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm umount
|
||||
command appeared in
|
||||
.At v6 .
|
||||
385
sbin/umount/umount.c
Normal file
385
sbin/umount/umount.c
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/*-
|
||||
* Copyright (c) 1980, 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"@(#) Copyright (c) 1980, 1989, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpc/pmap_clnt.h>
|
||||
#include <rpc/pmap_prot.h>
|
||||
#include <nfs/rpcv2.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <fstab.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef enum { MNTON, MNTFROM } mntwhat;
|
||||
|
||||
int fake, fflag, vflag;
|
||||
char *nfshost;
|
||||
|
||||
int checkvfsname __P((const char *, char **));
|
||||
char *getmntname __P((char *, mntwhat, char **));
|
||||
char **makevfslist __P((char *));
|
||||
int selected __P((int));
|
||||
int namematch __P((struct hostent *));
|
||||
int umountall __P((char **));
|
||||
int umountfs __P((char *, char **));
|
||||
void usage __P((void));
|
||||
int xdr_dir __P((XDR *, char *));
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int all, ch, errs, mnts;
|
||||
char **typelist = NULL;
|
||||
struct statfs *mntbuf;
|
||||
|
||||
/* Start disks transferring immediately. */
|
||||
sync();
|
||||
|
||||
all = 0;
|
||||
while ((ch = getopt(argc, argv, "AaFfh:t:v")) != EOF)
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
all = 2;
|
||||
break;
|
||||
case 'a':
|
||||
all = 1;
|
||||
break;
|
||||
case 'F':
|
||||
fake = 1;
|
||||
break;
|
||||
case 'f':
|
||||
fflag = MNT_FORCE;
|
||||
break;
|
||||
case 'h': /* -h implies -A. */
|
||||
all = 2;
|
||||
nfshost = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (typelist != NULL)
|
||||
errx(1, "only one -t option may be specified.");
|
||||
typelist = makevfslist(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0 && !all || argc != 0 && all)
|
||||
usage();
|
||||
|
||||
/* -h implies "-t nfs" if no -t flag. */
|
||||
if ((nfshost != NULL) && (typelist == NULL))
|
||||
typelist = makevfslist("nfs");
|
||||
|
||||
switch (all) {
|
||||
case 2:
|
||||
if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
|
||||
warn("getmntinfo");
|
||||
errs = 1;
|
||||
break;
|
||||
}
|
||||
for (errs = 0, mnts--; mnts > 0; mnts--) {
|
||||
if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
|
||||
continue;
|
||||
if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
|
||||
errs = 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (setfsent() == 0)
|
||||
err(1, "%s", _PATH_FSTAB);
|
||||
errs = umountall(typelist);
|
||||
break;
|
||||
case 0:
|
||||
for (errs = 0; *argv != NULL; ++argv)
|
||||
if (umountfs(*argv, typelist) != 0)
|
||||
errs = 1;
|
||||
break;
|
||||
}
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
int
|
||||
umountall(typelist)
|
||||
char **typelist;
|
||||
{
|
||||
struct fstab *fs;
|
||||
int rval, type;
|
||||
char *cp;
|
||||
struct vfsconf vfc;
|
||||
|
||||
while ((fs = getfsent()) != NULL) {
|
||||
/* Ignore the root. */
|
||||
if (strcmp(fs->fs_file, "/") == 0)
|
||||
continue;
|
||||
/*
|
||||
* !!!
|
||||
* Historic practice: ignore unknown FSTAB_* fields.
|
||||
*/
|
||||
if (strcmp(fs->fs_type, FSTAB_RW) &&
|
||||
strcmp(fs->fs_type, FSTAB_RO) &&
|
||||
strcmp(fs->fs_type, FSTAB_RQ))
|
||||
continue;
|
||||
/* If an unknown file system type, complain. */
|
||||
if (getvfsbyname(fs->fs_vfstype, &vfc) < 0) {
|
||||
warnx("%s: unknown mount type", fs->fs_vfstype);
|
||||
continue;
|
||||
}
|
||||
if (checkvfsname(fs->fs_vfstype, typelist))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We want to unmount the file systems in the reverse order
|
||||
* that they were mounted. So, we save off the file name
|
||||
* in some allocated memory, and then call recursively.
|
||||
*/
|
||||
if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL)
|
||||
err(1, NULL);
|
||||
(void)strcpy(cp, fs->fs_file);
|
||||
rval = umountall(typelist);
|
||||
return (umountfs(cp, typelist) || rval);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umountfs(name, typelist)
|
||||
char *name;
|
||||
char **typelist;
|
||||
{
|
||||
enum clnt_stat clnt_stat;
|
||||
struct hostent *hp;
|
||||
struct sockaddr_in saddr;
|
||||
struct stat sb;
|
||||
struct timeval pertry, try;
|
||||
CLIENT *clp;
|
||||
int so;
|
||||
char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
|
||||
|
||||
if (realpath(name, rname) == NULL) {
|
||||
warn("%s", rname);
|
||||
return (1);
|
||||
}
|
||||
|
||||
name = rname;
|
||||
|
||||
if (stat(name, &sb) < 0) {
|
||||
if (((mntpt = getmntname(name, MNTFROM, &type)) == NULL) &&
|
||||
((mntpt = getmntname(name, MNTON, &type)) == NULL)) {
|
||||
warnx("%s: not currently mounted", name);
|
||||
return (1);
|
||||
}
|
||||
} else if (S_ISBLK(sb.st_mode)) {
|
||||
if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
|
||||
warnx("%s: not currently mounted", name);
|
||||
return (1);
|
||||
}
|
||||
} else if (S_ISDIR(sb.st_mode)) {
|
||||
mntpt = name;
|
||||
if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
|
||||
warnx("%s: not currently mounted", mntpt);
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
warnx("%s: not a directory or special device", name);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (checkvfsname(type, typelist))
|
||||
return (1);
|
||||
|
||||
hp = NULL;
|
||||
if (!strcmp(type, "nfs")) {
|
||||
if ((delimp = strchr(name, '@')) != NULL) {
|
||||
hostp = delimp + 1;
|
||||
*delimp = '\0';
|
||||
hp = gethostbyname(hostp);
|
||||
*delimp = '@';
|
||||
} else if ((delimp = strchr(name, ':')) != NULL) {
|
||||
*delimp = '\0';
|
||||
hostp = name;
|
||||
hp = gethostbyname(hostp);
|
||||
name = delimp + 1;
|
||||
*delimp = ':';
|
||||
}
|
||||
}
|
||||
|
||||
if (!namematch(hp))
|
||||
return (1);
|
||||
|
||||
if (vflag)
|
||||
(void)printf("%s: unmount from %s\n", name, mntpt);
|
||||
if (fake)
|
||||
return (0);
|
||||
|
||||
if (unmount(mntpt, fflag) < 0) {
|
||||
warn("%s", mntpt);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if ((hp != NULL) && !(fflag & MNT_FORCE)) {
|
||||
*delimp = '\0';
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = 0;
|
||||
memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
|
||||
pertry.tv_sec = 3;
|
||||
pertry.tv_usec = 0;
|
||||
so = RPC_ANYSOCK;
|
||||
if ((clp = clntudp_create(&saddr,
|
||||
RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
|
||||
clnt_pcreateerror("Cannot MNT PRC");
|
||||
return (1);
|
||||
}
|
||||
clp->cl_auth = authunix_create_default();
|
||||
try.tv_sec = 20;
|
||||
try.tv_usec = 0;
|
||||
clnt_stat = clnt_call(clp,
|
||||
RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
|
||||
if (clnt_stat != RPC_SUCCESS) {
|
||||
clnt_perror(clp, "Bad MNT RPC");
|
||||
return (1);
|
||||
}
|
||||
auth_destroy(clp->cl_auth);
|
||||
clnt_destroy(clp);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
getmntname(name, what, type)
|
||||
char *name;
|
||||
mntwhat what;
|
||||
char **type;
|
||||
{
|
||||
static struct statfs *mntbuf;
|
||||
static int mntsize;
|
||||
int i;
|
||||
|
||||
if (mntbuf == NULL &&
|
||||
(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
|
||||
warn("getmntinfo");
|
||||
return (NULL);
|
||||
}
|
||||
for (i = 0; i < mntsize; i++) {
|
||||
if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
|
||||
if (type)
|
||||
*type = mntbuf[i].f_fstypename;
|
||||
return (mntbuf[i].f_mntonname);
|
||||
}
|
||||
if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
|
||||
if (type)
|
||||
*type = mntbuf[i].f_fstypename;
|
||||
return (mntbuf[i].f_mntfromname);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
namematch(hp)
|
||||
struct hostent *hp;
|
||||
{
|
||||
char *cp, **np;
|
||||
|
||||
if ((hp == NULL) || (nfshost == NULL))
|
||||
return (1);
|
||||
|
||||
if (strcasecmp(nfshost, hp->h_name) == 0)
|
||||
return (1);
|
||||
|
||||
if ((cp = strchr(hp->h_name, '.')) != NULL) {
|
||||
*cp = '\0';
|
||||
if (strcasecmp(nfshost, hp->h_name) == 0)
|
||||
return (1);
|
||||
}
|
||||
for (np = hp->h_aliases; *np; np++) {
|
||||
if (strcasecmp(nfshost, *np) == 0)
|
||||
return (1);
|
||||
if ((cp = strchr(*np, '.')) != NULL) {
|
||||
*cp = '\0';
|
||||
if (strcasecmp(nfshost, *np) == 0)
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* xdr routines for mount rpc's
|
||||
*/
|
||||
int
|
||||
xdr_dir(xdrsp, dirp)
|
||||
XDR *xdrsp;
|
||||
char *dirp;
|
||||
{
|
||||
return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: %s\n %s\n",
|
||||
"umount [-fv] [-t fstypelist] special | node",
|
||||
"umount -a[fv] [-h host] [-t fstypelist]");
|
||||
exit(1);
|
||||
}
|
||||
Loading…
Reference in a new issue