Remove IFS from 5.0-CURRENT. This facilitates introducing UFS2 as

IFS had its fingers deep in the belly of the UFS/FFS split.  IFS
will be reimplemented by the maintainer at a later date once the UFS
implementation is in place.

Requested by:	adrian (maintainer)
This commit is contained in:
Robert Watson 2002-05-19 00:09:30 +00:00
parent d5caaf02c1
commit 8b1febe499
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=96884
21 changed files with 0 additions and 6442 deletions

View File

@ -21,7 +21,6 @@ SUBDIR= adjkerntz \
ffsinfo \
fsck \
fsck_ffs \
fsck_ifs \
fsck_msdosfs \
fsdb \
fsirand \
@ -42,7 +41,6 @@ SUBDIR= adjkerntz \
mount \
mount_cd9660 \
mount_ext2fs \
mount_ifs \
mount_msdosfs \
mount_nfs \
mount_ntfs \

View File

@ -1,12 +0,0 @@
# $FreeBSD$
# @(#)Makefile 8.2 (Berkeley) 4/27/95
PROG= fsck_ifs
NOMAN= true
SRCS= dir.c fsutil.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
pass5.c setup.c utilities.c ffs_subr.c ffs_tables.c
WARNS= 0
.PATH: ${.CURDIR}/../../sys/ufs/ffs
.include <bsd.prog.mk>

View File

@ -1,750 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#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(struct inodesc *);
static int dircheck(struct inodesc *, struct direct *);
static int expanddir(struct dinode *dp, char *name);
static void freedir(ino_t ino, ino_t parent);
static struct direct *fsck_readdir(struct inodesc *);
static struct bufarea *getdirblk(ufs_daddr_t blkno, long size);
static int lftempname(char *bufp, ino_t ino);
static int mkentry(struct inodesc *);
/*
* Propagate connected state through the tree.
*/
void
propagate(void)
{
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 (inoinfo(inp->i_parent)->ino_state == DFOUND &&
inoinfo(inp->i_number)->ino_state == DSTATE) {
inoinfo(inp->i_number)->ino_state = DFOUND;
change++;
}
}
} while (change > 0);
}
/*
* Scan each entry in a directory block.
*/
int
dirscan(struct inodesc *idesc)
{
struct direct *dp;
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;
if (dsize > sizeof(dbuf))
dsize = sizeof(dbuf);
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(struct inodesc *idesc)
{
struct direct *dp, *ndp;
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(struct inodesc *idesc, struct direct *dp)
{
int size;
char *cp;
u_char namlen, type;
int spaceleft;
spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
if (dp->d_reclen == 0 ||
dp->d_reclen > spaceleft ||
(dp->d_reclen & 0x3) != 0)
goto bad;
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)
goto bad;
for (cp = dp->d_name, size = 0; size < namlen; size++)
if (*cp == '\0' || (*cp++ == '/'))
goto bad;
if (*cp != '\0')
goto bad;
return (1);
bad:
if (debug)
printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n",
dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type,
dp->d_name);
return (0);
}
void
direrror(ino_t ino, char *errmesg)
{
fileerror(ino, ino, errmesg);
}
void
fileerror(ino_t cwd, ino_t ino, char *errmesg)
{
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(struct inodesc *idesc, int lcnt)
{
struct dinode *dp;
int saveresolved;
dp = ginode(idesc->id_number);
if (dp->di_nlink == lcnt) {
/*
* If we have not hit any unresolved problems, are running
* in preen mode, and are on a filesystem using soft updates,
* then just toss any partially allocated files.
*/
if (resolved && preen && usedsoftdep) {
clri(idesc, "UNREF", 1);
return;
} else {
/*
* The filesystem can be marked clean even if
* a file is not linked up, but is cleared.
* Hence, resolved should not be cleared when
* linkup is answered no, but clri is answered yes.
*/
saveresolved = resolved;
if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) {
resolved = saveresolved;
clri(idesc, "UNREF", 0);
return;
}
/*
* Account for the new reference created by linkup().
*/
dp = ginode(idesc->id_number);
lcnt--;
}
}
if (lcnt != 0) {
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 || usedsoftdep) {
if (lcnt < 0) {
printf("\n");
pfatal("LINK COUNT INCREASING");
}
if (preen)
printf(" (ADJUSTED)\n");
}
if (preen || reply("ADJUST") == 1) {
dp->di_nlink -= lcnt;
inodirty();
}
}
}
static int
mkentry(struct inodesc *idesc)
{
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 = inoinfo(idesc->id_parent)->ino_type;
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(struct inodesc *idesc)
{
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 = inoinfo(idesc->id_parent)->ino_type;
else
dirp->d_type = 0;
return (ALTERED|STOP);
}
int
linkup(ino_t orphan, ino_t parentdir, char *name)
{
struct dinode *dp;
int lostdir;
ino_t oldlfdir;
struct inodesc idesc;
char tempname[BUFSIZ];
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) {
numdirs++;
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, inoinfo(oldlfdir)->ino_linkcnt + 1);
inoinfo(oldlfdir)->ino_linkcnt = 0;
dp = ginode(lfdir);
}
if (inoinfo(lfdir)->ino_state != DFOUND) {
pfatal("SORRY. NO lost+found DIRECTORY\n\n");
return (0);
}
(void)lftempname(tempname, orphan);
if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) {
pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
printf("\n\n");
return (0);
}
inoinfo(orphan)->ino_linkcnt--;
if (lostdir) {
if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
parentdir != (ino_t)-1)
(void)makeentry(orphan, lfdir, "..");
dp = ginode(lfdir);
dp->di_nlink++;
inodirty();
inoinfo(lfdir)->ino_linkcnt++;
pwarn("DIR I=%lu CONNECTED. ", orphan);
if (parentdir != (ino_t)-1) {
printf("PARENT WAS I=%lu\n", (u_long)parentdir);
/*
* The parent directory, because of the ordering
* guarantees, has had the link count incremented
* for the child, but no entry was made. This
* fixes the parent link count so that fsck does
* not need to be rerun.
*/
inoinfo(parentdir)->ino_linkcnt++;
}
if (preen == 0)
printf("\n");
}
return (1);
}
/*
* fix an entry in a directory.
*/
int
changeino(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(ino_t parent, ino_t 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(struct dinode *dp, char *name)
{
ufs_daddr_t lastbn, newblk;
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(ino_t parent, ino_t request, int mode)
{
ino_t ino;
char *cp;
struct dinode *dp;
struct bufarea *bp;
struct inoinfo *inp;
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) {
inoinfo(ino)->ino_linkcnt = dp->di_nlink;
cacheino(dp, ino);
return(ino);
}
if (inoinfo(parent)->ino_state != DSTATE &&
inoinfo(parent)->ino_state != DFOUND) {
freeino(ino);
return (0);
}
cacheino(dp, ino);
inp = getinoinfo(ino);
inp->i_parent = parent;
inp->i_dotdot = parent;
inoinfo(ino)->ino_state = inoinfo(parent)->ino_state;
if (inoinfo(ino)->ino_state == DSTATE) {
inoinfo(ino)->ino_linkcnt = dp->di_nlink;
inoinfo(parent)->ino_linkcnt++;
}
dp = ginode(parent);
dp->di_nlink++;
inodirty();
return (ino);
}
/*
* free a directory inode
*/
static void
freedir(ino_t ino, ino_t 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(char *bufp, ino_t ino)
{
ino_t in;
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(ufs_daddr_t blkno, long size)
{
if (pdirbp != 0)
pdirbp->b_flags &= ~B_INUSE;
pdirbp = getdatablk(blkno, size);
return (pdirbp);
}

View File

@ -1,304 +0,0 @@
/*
* 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
* $FreeBSD$
*/
#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 */
/*
* Each inode on the filesystem is described by the following structure.
* The linkcnt is initially set to the value in the inode. Each time it
* is found during the descent in passes 2, 3, and 4 the count is
* decremented. Any inodes whose count is non-zero after pass 4 needs to
* have its link count adjusted by the value remaining in ino_linkcnt.
*/
struct inostat {
char ino_state; /* state of inode, see below */
char ino_type; /* type of inode */
short ino_linkcnt; /* number of links not found */
};
/*
* Inode states.
*/
#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 */
/*
* Inode state information is contained on per cylinder group lists
* which are described by the following structure.
*/
struct inostatlist {
long il_numalloced; /* number of inodes allocated in this cg */
struct inostat *il_stat;/* inostat info for this cylinder group */
} *inostathead;
/*
* 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; /* filesystem 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};
ino_t cursnapshot;
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 */
int id_lbn; /* logical block number of current block */
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 /* a directory */
#define SNAP 2 /* a snapshot */
#define ADDR 3 /* anything but a directory or a snapshot */
/*
* 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, dirhash, listmax, inplast;
long countdirs; /* number of directories we actually found */
char *cdevname; /* name of device being checked */
long dev_bsize; /* computed value of DEV_BSIZE */
long secsize; /* actual disk sector size */
char fflag; /* force check, ignore clean flag */
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 filesystem format */
int doinglevel1; /* converting to new cylinder group format */
int doinglevel2; /* converting to new inode format */
int newinofmt; /* filesystem has new inode format */
char usedsoftdep; /* just fix soft dependency inconsistencies */
char preen; /* just fix normal inconsistencies */
char rerun; /* rerun fsck. Only used in non-preen mode */
int returntosingle; /* 1 => return to single user mode on exit */
char resolved; /* cleared if unresolved changes => not clean */
int markclean; /* mark filesystem clean when done */
char havesb; /* superblock has been read */
char skipclean; /* skip clean filesystems if preening */
int fsmodified; /* 1 => write done to filesystem */
int fsreadfd; /* file descriptor for reading filesystem */
int fswritefd; /* file descriptor for writing filesystem */
ufs_daddr_t maxfsblock; /* number of blocks in the filesystem */
char *blockmap; /* ptr to primary blk allocation map */
ino_t maxino; /* number of inodes in filesystem */
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(struct inodesc *, int lcnt);
ufs_daddr_t allocblk(long frags);
ino_t allocdir(ino_t parent, ino_t request, int mode);
ino_t allocino(ino_t request, int type);
void blkerror(ino_t ino, char *type, ufs_daddr_t blk);
char *blockcheck(char *name);
int bread(int fd, char *buf, ufs_daddr_t blk, long size);
void bufinit(void);
void bwrite(int fd, char *buf, ufs_daddr_t blk, long size);
void cacheino(struct dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
int changeino(ino_t dir, char *name, ino_t newnum);
int chkrange(ufs_daddr_t blk, int cnt);
void ckfini(int markclean);
int ckinode(struct dinode *dp, struct inodesc *);
void clri(struct inodesc *, char *type, int flag);
int clearentry(struct inodesc *);
void direrror(ino_t ino, char *errmesg);
int dirscan(struct inodesc *);
int dofix(struct inodesc *, char *msg);
void ffs_clrblock(struct fs *, u_char *, ufs_daddr_t);
void ffs_fragacct(struct fs *, int, int32_t [], int);
int ffs_isblock(struct fs *, u_char *, ufs_daddr_t);
void ffs_setblock(struct fs *, u_char *, ufs_daddr_t);
void fileerror(ino_t cwd, ino_t ino, char *errmesg);
int findino(struct inodesc *);
int findname(struct inodesc *);
void flush(int fd, struct bufarea *bp);
void freeblk(ufs_daddr_t blkno, long frags);
void freeino(ino_t ino);
void freeinodebuf(void);
int ftypeok(struct dinode *dp);
void getblk(struct bufarea *bp, ufs_daddr_t blk, long size);
struct bufarea *getdatablk(ufs_daddr_t blkno, long size);
struct inoinfo *getinoinfo(ino_t inumber);
struct dinode *getnextinode(ino_t inumber);
void getpathname(char *namebuf, ino_t curdir, ino_t ino);
struct dinode *ginode(ino_t inumber);
void inocleanup(void);
void inodirty(void);
struct inostat *inoinfo(ino_t inum);
int linkup(ino_t orphan, ino_t parentdir, char *name);
int makeentry(ino_t parent, ino_t ino, char *name);
void panic(const char *fmt, ...) __printflike(1, 2);
void pass1(void);
void pass1b(void);
int pass1check(struct inodesc *);
void pass2(void);
void pass3(void);
void pass4(void);
int pass4check(struct inodesc *);
void pass5(void);
void pfatal(const char *fmt, ...) __printflike(1, 2);
void pinode(ino_t ino);
void propagate(void);
void pwarn(const char *fmt, ...) __printflike(1, 2);
int reply(char *question);
void setinodebuf(ino_t);
int setup(char *dev);
void voidquit(int);

View File

@ -1,322 +0,0 @@
.\"
.\" 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 acknowledgment:
.\" 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
.\" $FreeBSD$
.\"
.Dd November 15, 1996
.Dt FSCK 8
.Os
.Sh NAME
.Nm fsck
.Nd filesystem consistency check and interactive repair
.Sh SYNOPSIS
.Nm
.Fl p
.Op Fl f
.Op Fl m Ar mode
.Op Ar filesystem
.Ar ...
.Nm
.Op Fl ny
.Op Fl b Ar block#
.Op Fl c Ar level
.Op Fl l Ar maxparallel
.Op Fl m Ar mode
.Op Ar filesystem
.Ar ...
.Sh DESCRIPTION
The first form of
.Nm
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
reads the table
.Pa /etc/fstab
to determine which filesystems to check.
Only partitions in fstab that are mounted ``rw,'' ``rq'' or ``ro''
and that have non-zero pass number are checked.
Filesystems with pass number 1 (normally just the root filesystem)
are checked one at a time.
When pass 1 completes, all remaining filesystems are checked,
running one process per disk drive.
The disk drive containing each filesystem is inferred from the longest prefix
of the device name that ends in a digit; the remaining characters are assumed
to be the partition designator.
.Pp
In "preen" mode the clean flag of each filesystem's superblock is examined
and only those filesystems that
are not marked clean are checked.
Filesystems are marked clean when they are unmounted,
when they have been mounted read-only, or when
.Nm
runs on them successfully.
If the
.Fl f
option is specified, the filesystems
will be checked regardless of the state of their clean flag.
.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:
.Pp
.Bl -item -compact -offset indent
.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
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
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
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
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
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 .
.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 c
Convert the filesystem to the specified level.
Note that the level of a filesystem can only be raised.
There are currently four levels defined:
.Bl -tag -width indent
.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
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 .
.It Fl f
Force
.Nm
to check
.Sq clean
filesystems when preening.
.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 n
Assume a no response to all questions asked by
.Nm
except for
.Ql CONTINUE? ,
which is assumed to be affirmative;
do not open the filesystem for writing.
.It Fl p
Preen filesystems (see above).
.It Fl y
Assume a yes response to all questions asked by
.Nm ;
this should be used with great caution as this is a free license
to continue after essentially unlimited trouble has been encountered.
.El
.Pp
If no filesystems are given to
.Nm
then a default list of filesystems is read from
the file
.Pa /etc/fstab .
.Pp
Inconsistencies checked are as follows:
.Pp
.Bl -enum -compact
.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 -offset 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 -offset indent -compact
.It
File pointing to unallocated inode.
.It
Inode number out of range.
.It
Directories with unallocated blocks (holes).
.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 -offset 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
are fully enumerated and explained in Appendix A of
.Rs
.%T "Fsck \- The UNIX File System Check Program"
.Re
.Sh SEE ALSO
.Xr fs 5 ,
.Xr fstab 5 ,
.Xr fsdb 8 ,
.Xr newfs 8 ,
.Xr reboot 8

View File

@ -1,627 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/disklabel.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <fstab.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "fsck.h"
long diskreads, totalreads; /* Disk cache statistics */
static void rwerror(char *mesg, ufs_daddr_t blk);
int
ftypeok(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(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);
resolved = 0;
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)) {
resolved = 0;
return (0);
}
}
} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
printf("\n");
if (c == 'y' || c == 'Y')
return (1);
resolved = 0;
return (0);
}
/*
* Look up state information for an inode.
*/
struct inostat *
inoinfo(ino_t inum)
{
static struct inostat unallocated = { USTATE, 0, 0 };
struct inostatlist *ilp;
int iloff;
if (inum > maxino)
errx(EEXIT, "inoinfo: inumber %d out of range", inum);
ilp = &inostathead[inum / sblock.fs_ipg];
iloff = inum % sblock.fs_ipg;
if (iloff >= ilp->il_numalloced)
return (&unallocated);
return (&ilp->il_stat[iloff]);
}
/*
* Malloc buffers and set up cache.
*/
void
bufinit(void)
{
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(ufs_daddr_t blkno, long size)
{
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(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(int fd, struct bufarea *bp)
{
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 + i,
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(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(int markclean)
{
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 (sblock.fs_clean != markclean) {
sblock.fs_clean = markclean;
sbdirty();
ofsmodified = fsmodified;
flush(fswritefd, &sblk);
fsmodified = ofsmodified;
if (!preen) {
printf("\n***** FILE SYSTEM MARKED %s *****\n",
markclean ? "CLEAN" : "DIRTY");
if (!markclean)
rerun = 1;
}
} else if (!preen && !markclean) {
printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
rerun = 1;
}
if (debug)
printf("cache missed %ld of %ld (%d%%)\n", diskreads,
totalreads, (int)(diskreads * 100 / totalreads));
(void)close(fsreadfd);
(void)close(fswritefd);
}
int
bread(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");
if (errs)
resolved = 0;
return (errs);
}
void
bwrite(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;
}
resolved = 0;
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(long frags)
{
int i, j, k, cg, baseblk;
struct cg *cgp = &cgrp;
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;
}
cg = dtog(&sblock, i + j);
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
if (!cg_chkmagic(cgp))
pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
baseblk = dtogd(&sblock, i + j);
for (k = 0; k < frags; k++) {
setbmap(i + j + k);
clrbit(cg_blksfree(cgp), baseblk + k);
}
n_blks += frags;
if (frags == sblock.fs_frag)
cgp->cg_cs.cs_nbfree--;
else
cgp->cg_cs.cs_nffree -= frags;
cgdirty();
return (i + j);
}
}
return (0);
}
/*
* Free a previously allocated block
*/
void
freeblk(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(char *namebuf, ino_t curdir, ino_t ino)
{
int len;
char *cp;
struct inodesc idesc;
static int busy = 0;
if (curdir == ino && ino == ROOTINO) {
(void)strcpy(namebuf, "/");
return;
}
if (busy ||
(inoinfo(curdir)->ino_state != DSTATE &&
inoinfo(curdir)->ino_state != 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(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(int sig)
{
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(int sig)
{
sleep(1);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGQUIT, SIG_DFL);
}
/*
* determine whether an inode should be fixed.
*/
int
dofix(struct inodesc *idesc, char *msg)
{
switch (idesc->id_fix) {
case DONTKNOW:
if (idesc->id_type == DATA)
direrror(idesc->id_number, msg);
else
pwarn("%s", 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);
}
#include <stdarg.h>
/*
* An unexpected inconsistency occured.
* Die if preening or filesystem is running with soft dependency protocol,
* otherwise just print message and continue.
*/
void
pfatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (!preen) {
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
if (usedsoftdep)
(void)fprintf(stderr,
"\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n");
return;
}
if (cdevname == NULL)
cdevname = "fsck";
(void)fprintf(stderr, "%s: ", cdevname);
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr,
"\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n",
cdevname, usedsoftdep ? " SOFT UPDATE " : " ");
ckfini(0);
exit(EEXIT);
}
/*
* Pwarn just prints a message when not preening or running soft dependency
* protocol, or a warning (preceded by filename) when preening.
*/
void
pwarn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (preen)
(void)fprintf(stderr, "%s: ", cdevname);
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
}
/*
* Stub for routines from kernel.
*/
void
panic(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
pfatal("INTERNAL INCONSISTENCY:");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
exit(EEXIT);
}

View File

@ -1,646 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#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(struct inodesc *, long ilevel, quad_t isize);
int
ckinode(struct dinode *dp, struct inodesc *idesc)
{
ufs_daddr_t *ap;
int ret;
long n, ndb, offset;
struct dinode dino;
quad_t remsize, sizepb;
mode_t mode;
char pathbuf[MAXPATHLEN + 1];
if (idesc->id_fix != IGNORE)
idesc->id_fix = DONTKNOW;
idesc->id_lbn = -1;
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 < (unsigned)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++) {
idesc->id_lbn++;
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) {
if (idesc->id_type == DATA && ndb >= 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
dp->di_size = (ap - &dino.di_db[0]) *
sblock.fs_bsize;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
}
}
continue;
}
idesc->id_blkno = *ap;
if (idesc->id_type != DATA)
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++) {
sizepb *= NINDIR(&sblock);
if (*ap) {
idesc->id_blkno = *ap;
ret = iblock(idesc, n, remsize);
if (ret & STOP)
return (ret);
} else {
idesc->id_lbn += sizepb / sblock.fs_bsize;
if (idesc->id_type == DATA && remsize > 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
dp->di_size -= remsize;
remsize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
break;
}
}
}
remsize -= sizepb;
}
return (KEEPON);
}
static int
iblock(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];
char pathbuf[MAXPATHLEN + 1];
struct dinode *dp;
if (idesc->id_type != DATA) {
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",
(u_long)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 (ilevel == 0)
idesc->id_lbn++;
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);
}
} else {
if (idesc->id_type == DATA && isize > 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
dp->di_size -= isize;
isize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
bp->b_flags &= ~B_INUSE;
return(STOP);
}
}
}
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(ufs_daddr_t blk, int cnt)
{
int c;
if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
cnt - 1 > maxfsblock - blk)
return (1);
if (cnt > sblock.fs_frag ||
fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
if (debug)
printf("bad size: blk %ld, offset %ld, size %ld\n",
blk, fragnum(&sblock, blk), cnt);
return (1);
}
c = dtog(&sblock, blk);
if (blk < cgdmin(&sblock, c)) {
if ((blk + cnt) > cgsblock(&sblock, c)) {
if (debug) {
printf("blk %ld < cgdmin %ld;",
(long)blk, (long)cgdmin(&sblock, c));
printf(" blk + cnt %ld > cgsbase %ld\n",
(long)(blk + cnt),
(long)cgsblock(&sblock, c));
}
return (1);
}
} else {
if ((blk + cnt) > cgbase(&sblock, c+1)) {
if (debug) {
printf("blk %ld >= cgdmin %ld;",
(long)blk, (long)cgdmin(&sblock, c));
printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
(long)(blk + cnt), (long)sblock.fs_fpg);
}
return (1);
}
}
return (0);
}
/*
* General purpose interface for reading inodes.
*/
struct dinode *
ginode(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, lastvalidinum;
long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
struct dinode *inodebuf;
struct dinode *
getnextinode(ino_t inumber)
{
long size;
ufs_daddr_t dblk;
static struct dinode *dp;
if (inumber != nextino++ || inumber > lastvalidinum)
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;
}
/*
* If bread returns an error, it will already have zeroed
* out the buffer, so we do not need to do so here.
*/
(void)bread(fsreadfd, (char *)inodebuf, dblk, size);
dp = inodebuf;
}
return (dp++);
}
void
setinodebuf(ino_t inum)
{
if (inum % sblock.fs_ipg != 0)
errx(EEXIT, "bad inode number %d to setinodebuf", inum);
lastvalidinum = inum + sblock.fs_ipg - 1;
startinum = 0;
nextino = inum;
lastinum = inum;
readcnt = 0;
if (inodebuf != NULL)
return;
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 = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
errx(EEXIT, "cannot allocate space for inode buffer");
}
void
freeinodebuf(void)
{
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(struct dinode *dp, ino_t inumber)
{
struct inoinfo *inp;
struct inoinfo **inpp;
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)
errx(EEXIT, "cannot increase directory list");
inpp = &inphead[inumber % dirhash];
inp->i_nexthash = *inpp;
*inpp = inp;
inp->i_parent = inumber == ROOTINO ? ROOTINO : (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(ino_t inumber)
{
struct inoinfo *inp;
for (inp = inphead[inumber % dirhash]; 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(void)
{
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(void)
{
dirty(pbp);
}
void
clri(struct inodesc *idesc, char *type, int flag)
{
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);
inoinfo(idesc->id_number)->ino_state = USTATE;
inodirty();
}
}
int
findname(struct inodesc *idesc)
{
struct direct *dirp = idesc->id_dirp;
if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
idesc->id_entryno++;
return (KEEPON);
}
memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
return (STOP|FOUND);
}
int
findino(struct inodesc *idesc)
{
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);
}
int
clearentry(struct inodesc *idesc)
{
struct direct *dirp = idesc->id_dirp;
if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
idesc->id_entryno++;
return (KEEPON);
}
dirp->d_ino = 0;
return (STOP|FOUND|ALTERED);
}
void
pinode(ino_t ino)
{
struct dinode *dp;
char *p;
struct passwd *pw;
time_t t;
printf(" I=%lu ", (u_long)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);
t = dp->di_mtime;
p = ctime(&t);
printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
}
void
blkerror(ino_t ino, char *type, ufs_daddr_t blk)
{
pfatal("%ld %s I=%lu", blk, type, ino);
printf("\n");
switch (inoinfo(ino)->ino_state) {
case FSTATE:
inoinfo(ino)->ino_state = FCLEAR;
return;
case DSTATE:
inoinfo(ino)->ino_state = DCLEAR;
return;
case FCLEAR:
case DCLEAR:
return;
default:
errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
/* NOTREACHED */
}
}
/*
* allocate an unused inode
*/
ino_t
allocino(ino_t request, int type)
{
ino_t ino;
struct dinode *dp;
struct cg *cgp = &cgrp;
int cg;
if (request == 0)
request = ROOTINO;
else if (inoinfo(request)->ino_state != USTATE)
return (0);
for (ino = request; ino < maxino; ino++)
if (inoinfo(ino)->ino_state == USTATE)
break;
if (ino == maxino)
return (0);
cg = ino_to_cg(&sblock, ino);
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
if (!cg_chkmagic(cgp))
pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
cgp->cg_cs.cs_nifree--;
switch (type & IFMT) {
case IFDIR:
inoinfo(ino)->ino_state = DSTATE;
cgp->cg_cs.cs_ndir++;
break;
case IFREG:
case IFLNK:
inoinfo(ino)->ino_state = FSTATE;
break;
default:
return (0);
}
cgdirty();
dp = ginode(ino);
dp->di_db[0] = allocblk((long)1);
if (dp->di_db[0] == 0) {
inoinfo(ino)->ino_state = USTATE;
return (0);
}
dp->di_mode = type;
dp->di_flags = 0;
dp->di_atime = time(NULL);
dp->di_mtime = dp->di_ctime = dp->di_atime;
dp->di_mtimensec = dp->di_ctimensec = dp->di_atimensec = 0;
dp->di_size = sblock.fs_fsize;
dp->di_blocks = btodb(sblock.fs_fsize);
n_files++;
inodirty();
if (newinofmt)
inoinfo(ino)->ino_type = IFTODT(type);
return (ino);
}
/*
* deallocate an inode
*/
void
freeino(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();
inoinfo(ino)->ino_state = USTATE;
n_files--;
}

View File

@ -1,405 +0,0 @@
/*
* 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 const char copyright[] =
"@(#) Copyright (c) 1980, 1986, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/14/95";
#endif
#endif /* not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <sys/resource.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <fstab.h>
#include <paths.h>
#include <stdlib.h>
#include "fsck.h"
int returntosingle;
static void usage(void) __dead2;
static int argtoi(int flag, char *req, char *str, int base);
static int docheck(struct fstab *fsp);
static int checkfilesys(char *filesys, char *mntpt, long auxdata, int child);
static struct statfs *getmntpt(const char *);
int
main(int argc, char *argv[])
{
int ch;
struct rlimit rlimit;
int ret = 0;
sync();
skipclean = 1;
markclean = 1;
while ((ch = getopt(argc, argv, "b:c:dfFm:npy")) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
bflag = argtoi('b', "number", optarg, 10);
printf("Alternate super block location: %d\n", bflag);
break;
case 'c':
skipclean = 0;
cvtlevel = argtoi('c', "conversion level", optarg, 10);
break;
case 'd':
debug++;
break;
case 'f':
skipclean = 0;
break;
case 'F':
/* We can never run in background */
exit(EEXIT);
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':
nflag++;
yflag = 0;
break;
case 'p':
preen++;
break;
case 'y':
yflag++;
nflag = 0;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (!argc)
usage();
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
(void)signal(SIGINT, catch);
if (preen)
(void)signal(SIGQUIT, catchquit);
/*
* Push up our allowed memory limit so we can cope
* with huge filesystems.
*/
if (getrlimit(RLIMIT_DATA, &rlimit) == 0) {
rlimit.rlim_cur = rlimit.rlim_max;
(void)setrlimit(RLIMIT_DATA, &rlimit);
}
while (argc-- > 0)
(void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
if (returntosingle)
ret = 2;
exit(ret);
}
static int
argtoi(int flag, char *req, char *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);
}
/*
* Check the specified filesystem.
*/
/* ARGSUSED */
static int
checkfilesys(char *filesys, char *mntpt, long auxdata, int child)
{
ufs_daddr_t n_ffree, n_bfree;
struct dups *dp;
struct statfs *mntbuf;
struct zlncnt *zlnp;
int cylno;
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.");
return (0);
case -1:
pwarn("clean, %ld free ", sblock.fs_cstotal.cs_nffree +
sblock.fs_frag * sblock.fs_cstotal.cs_nbfree);
printf("(%d frags, %d blocks, %.1f%% fragmentation)\n",
sblock.fs_cstotal.cs_nffree, sblock.fs_cstotal.cs_nbfree,
sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize);
return (0);
}
/*
* Get the mount point information of the filesystem, if
* it is available.
*/
mntbuf = getmntpt(filesys);
/*
* Cleared if any questions answered no. Used to decide if
* the superblock should be marked clean.
*/
resolved = 1;
/*
* 1: scan inodes tallying blocks used
*/
if (preen == 0) {
printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
if (mntbuf != NULL && mntbuf->f_flags & MNT_ROOTFS)
printf("** Root filesystem\n");
printf("** Phase 1 - Check Blocks and Sizes\n");
}
pass1();
/*
* 1b: locate first references to duplicates, if any
*/
if (duplist) {
if (preen || usedsoftdep)
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
*/
#ifdef NOTFORIFS
if (preen == 0)
printf("** Phase 2 - Check Pathnames\n");
pass2();
#endif
printf("** Skipping phase 2 for IFS\n");
/*
* 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("(%d frags, %d blocks, %.1f%% fragmentation)\n",
n_ffree, n_bfree, n_ffree * 100.0 / sblock.fs_dsize);
if (debug &&
(n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
printf("%d 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("%d blocks missing\n", n_blks);
if (duplist != NULL) {
printf("The following duplicate blocks remain:");
for (dp = duplist; dp; dp = dp->next)
printf(" %d,", dp->dup);
printf("\n");
}
if (zlnhead != NULL) {
printf("The following zero link count inodes remain:");
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
printf(" %u,", zlnp->zlncnt);
printf("\n");
}
}
zlnhead = (struct zlncnt *)0;
duplist = (struct dups *)0;
muldup = (struct dups *)0;
inocleanup();
if (fsmodified) {
sblock.fs_time = time(NULL);
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 (rerun)
resolved = 0;
/*
* Check to see if the filesystem is mounted read-write.
*/
if (mntbuf != NULL && (mntbuf->f_flags & MNT_RDONLY) == 0)
resolved = 0;
ckfini(resolved);
for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
if (inostathead[cylno].il_stat != NULL)
free((char *)inostathead[cylno].il_stat);
free((char *)inostathead);
inostathead = NULL;
if (fsmodified && !preen)
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
if (rerun)
printf("\n***** PLEASE RERUN FSCK *****\n");
if (mntbuf != NULL) {
struct ufs_args args;
int ret;
/*
* We modified a mounted filesystem. Do a mount update on
* it unless it is read-write, so we can continue using it
* as safely as possible.
*/
if (mntbuf->f_flags & MNT_RDONLY) {
args.fspec = 0;
args.export.ex_flags = 0;
args.export.ex_root = 0;
ret = mount("ifs", mntbuf->f_mntonname,
mntbuf->f_flags | MNT_UPDATE | MNT_RELOAD, &args);
if (ret == 0)
return (0);
pwarn("mount reload of '%s' failed: %s\n\n",
mntbuf->f_mntonname, strerror(errno));
}
if (!fsmodified)
return (0);
if (!preen)
printf("\n***** REBOOT NOW *****\n");
sync();
return (4);
}
return (0);
}
/*
* Get the directory that the device is mounted on.
*/
static struct statfs *
getmntpt(const char *name)
{
struct stat devstat, mntdevstat;
char device[sizeof(_PATH_DEV) - 1 + MNAMELEN];
char *devname;
struct statfs *mntbuf;
int i, mntsize;
if (stat(name, &devstat) != 0 ||
!(S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)))
return (NULL);
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
for (i = 0; i < mntsize; i++) {
if (strcmp(mntbuf[i].f_fstypename, "ifs") != 0)
continue;
devname = mntbuf[i].f_mntfromname;
if (*devname != '/') {
strcpy(device, _PATH_DEV);
strcat(device, devname);
devname = device;
}
if (stat(devname, &mntdevstat) == 0 &&
mntdevstat.st_rdev == devstat.st_rdev)
return (&mntbuf[i]);
}
return (NULL);
}
static void
usage(void)
{
(void) fprintf(stderr,
"usage: %s [-dfnpy] [-B be|le] [-b block] [-c level] [-m mode] "
"filesystem ...\n",
getprogname());
exit(1);
}

View File

@ -1,428 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.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 ino_t lastino; /* last inode in use */
static void checkinode(ino_t inumber, struct inodesc *);
void
pass1(void)
{
u_int8_t *cp;
ino_t inumber;
int c, i, cgd, inosused;
struct inostat *info;
struct inodesc idesc;
/*
* Set filesystem 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_func = pass1check;
n_files = n_blks = 0;
for (c = 0; c < sblock.fs_ncg; c++) {
inumber = c * sblock.fs_ipg;
setinodebuf(inumber);
inosused = sblock.fs_ipg;
/*
* If we are using soft updates, then we can trust the
* cylinder group inode allocation maps to tell us which
* inodes are allocated. We will scan the used inode map
* to find the inodes that are really in use, and then
* read only those inodes in from disk.
*/
if (preen && usedsoftdep) {
getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
if (!cg_chkmagic(&cgrp))
pfatal("CG %d: BAD MAGIC NUMBER\n", c);
cp = &cg_inosused(&cgrp)[(sblock.fs_ipg - 1) / NBBY];
for ( ; inosused > 0; inosused -= NBBY, cp--) {
if (*cp == 0)
continue;
for (i = 1 << (NBBY - 1); i > 0; i >>= 1) {
if (*cp & i)
break;
inosused--;
}
break;
}
if (inosused < 0)
inosused = 0;
}
/*
* Allocate inoinfo structures for the allocated inodes.
*/
inostathead[c].il_numalloced = inosused;
if (inosused == 0) {
inostathead[c].il_stat = 0;
continue;
}
info = calloc((unsigned)inosused, sizeof(struct inostat));
if (info == NULL)
pfatal("cannot alloc %u bytes for inoinfo\n",
(unsigned)(sizeof(struct inostat) * inosused));
inostathead[c].il_stat = info;
/*
* Scan the allocated inodes.
*/
for (i = 0; i < inosused; i++, inumber++) {
if (inumber < ROOTINO) {
(void)getnextinode(inumber);
continue;
}
checkinode(inumber, &idesc);
}
lastino += 1;
if (inosused < sblock.fs_ipg || inumber == lastino)
continue;
/*
* If we were not able to determine in advance which inodes
* were in use, then reduce the size of the inoinfo structure
* to the size necessary to describe the inodes that we
* really found.
*/
inosused = lastino - (c * sblock.fs_ipg);
if (inosused < 0)
inosused = 0;
inostathead[c].il_numalloced = inosused;
if (inosused == 0) {
free(inostathead[c].il_stat);
inostathead[c].il_stat = 0;
continue;
}
info = calloc((unsigned)inosused, sizeof(struct inostat));
if (info == NULL)
pfatal("cannot alloc %u bytes for inoinfo\n",
(unsigned)(sizeof(struct inostat) * inosused));
memmove(info, inostathead[c].il_stat, inosused * sizeof(*info));
free(inostathead[c].il_stat);
inostathead[c].il_stat = info;
}
freeinodebuf();
}
static void
checkinode(ino_t inumber, struct inodesc *idesc)
{
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();
}
}
inoinfo(inumber)->ino_state = 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();
}
if ((mode == IFBLK || mode == IFCHR || mode == IFIFO ||
mode == IFSOCK) && dp->di_size != 0) {
if (debug)
printf("bad special-file size %qu:", dp->di_size);
goto unknown;
}
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 %lu(%s) of size %ld\n",
(u_long)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",
(long)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",
(long)dp->di_ib[j]);
goto unknown;
}
if (ftypeok(dp) == 0)
goto unknown;
n_files++;
inoinfo(inumber)->ino_linkcnt = 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) {
ckfini(0);
exit(EEXIT);
}
} else {
zlnp->zlncnt = inumber;
zlnp->next = zlnhead;
zlnhead = zlnp;
}
}
if (mode == IFDIR) {
if (dp->di_size == 0)
inoinfo(inumber)->ino_state = DCLEAR;
else
inoinfo(inumber)->ino_state = DSTATE;
cacheino(dp, inumber);
countdirs++;
} else
inoinfo(inumber)->ino_state = FSTATE;
inoinfo(inumber)->ino_type = 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;
if (dp->di_flags & SF_SNAPSHOT)
idesc->id_type = SNAP;
else
idesc->id_type = ADDR;
(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);
inoinfo(inumber)->ino_state = FCLEAR;
if (reply("CLEAR") == 1) {
inoinfo(inumber)->ino_state = USTATE;
dp = ginode(inumber);
clearinode(dp);
inodirty();
}
}
int
pass1check(struct inodesc *idesc)
{
int res = KEEPON;
int anyout, nfrags;
ufs_daddr_t blkno = idesc->id_blkno;
struct dups *dlp;
struct dups *new;
if (idesc->id_type == SNAP) {
if (blkno == BLK_NOCOPY)
return (KEEPON);
if (idesc->id_number == cursnapshot) {
if (blkno == blkstofrags(&sblock, idesc->id_lbn))
return (KEEPON);
if (blkno == BLK_SNAP) {
blkno = blkstofrags(&sblock, idesc->id_lbn);
idesc->id_entryno -= idesc->id_numfrags;
}
} else {
if (blkno == BLK_SNAP)
return (KEEPON);
}
}
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) {
ckfini(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) {
ckfini(0);
exit(EEXIT);
}
return (STOP);
}
new = (struct dups *)malloc(sizeof(struct dups));
if (new == NULL) {
pfatal("DUP TABLE OVERFLOW.");
if (reply("CONTINUE") == 0) {
ckfini(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);
}

View File

@ -1,106 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)pass1b.c 8.4 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <string.h>
#include "fsck.h"
static struct dups *duphead;
static int pass1bcheck(struct inodesc *);
void
pass1b(void)
{
int c, i;
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 (inoinfo(inumber)->ino_state != USTATE &&
(ckinode(dp, &idesc) & STOP))
return;
}
}
}
static int
pass1bcheck(struct inodesc *idesc)
{
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);
}

View File

@ -1,484 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <err.h>
#include <string.h>
#include "fsck.h"
#define MINDIRSIZE (sizeof (struct dirtemplate))
static int blksort(const void *, const void *);
static int pass2check(struct inodesc *);
void
pass2(void)
{
struct dinode *dp;
struct inoinfo **inpp, *inp;
struct inoinfo **inpend;
struct inodesc curino;
struct dinode dino;
char pathbuf[MAXPATHLEN + 1];
switch (inoinfo(ROOTINO)->ino_state) {
case USTATE:
pfatal("ROOT INODE UNALLOCATED");
if (reply("ALLOCATE") == 0) {
ckfini(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) {
ckfini(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) {
ckfini(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",
inoinfo(ROOTINO)->ino_state);
}
inoinfo(ROOTINO)->ino_state = DFOUND;
if (newinofmt) {
inoinfo(WINO)->ino_state = FSTATE;
inoinfo(WINO)->ino_type = 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);
if (usedsoftdep)
pfatal("%s %s: LENGTH %d NOT MULTIPLE OF %d",
"DIRECTORY", pathbuf, inp->i_isize,
DIRBLKSIZ);
else
pwarn("%s %s: LENGTH %d NOT MULTIPLE OF %d",
"DIRECTORY", 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 (inoinfo(inp->i_parent)->ino_state == DFOUND &&
inoinfo(inp->i_number)->ino_state == DSTATE)
inoinfo(inp->i_number)->ino_state = 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, "..");
inoinfo(inp->i_parent)->ino_linkcnt--;
continue;
}
fileerror(inp->i_parent, inp->i_number,
"BAD INODE NUMBER FOR '..'");
if (reply("FIX") == 0)
continue;
inoinfo(inp->i_dotdot)->ino_linkcnt++;
inoinfo(inp->i_parent)->ino_linkcnt--;
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(struct inodesc *idesc)
{
struct direct *dirp = idesc->id_dirp;
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 = inoinfo(dirp->d_ino)->ino_type;
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++;
inoinfo(dirp->d_ino)->ino_linkcnt--;
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++;
inoinfo(dirp->d_ino)->ino_linkcnt--;
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)
inoinfo(dirp->d_ino)->ino_linkcnt--;
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 (inoinfo(dirp->d_ino)->ino_state) {
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 (inoinfo(dirp->d_ino)->ino_state == FCLEAR)
errmsg = "DUP/BAD";
else if (!preen && !usedsoftdep)
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);
inoinfo(dirp->d_ino)->ino_state =
(dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
inoinfo(dirp->d_ino)->ino_linkcnt = dp->di_nlink;
goto again;
case DSTATE:
if (inoinfo(idesc->id_number)->ino_state == DFOUND)
inoinfo(dirp->d_ino)->ino_state = 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(" (REMOVED)\n");
n = 1;
break;
}
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 != inoinfo(dirp->d_ino)->ino_type) {
fileerror(idesc->id_number, dirp->d_ino,
"BAD TYPE VALUE");
dirp->d_type = inoinfo(dirp->d_ino)->ino_type;
if (reply("FIX") == 1)
ret |= ALTERED;
}
inoinfo(dirp->d_ino)->ino_linkcnt--;
break;
default:
errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
inoinfo(dirp->d_ino)->ino_state, 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(const void *arg1, const void *arg2)
{
return ((*(struct inoinfo **)arg1)->i_blks[0] -
(*(struct inoinfo **)arg2)->i_blks[0]);
}

View File

@ -1,118 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)pass3.c 8.2 (Berkeley) 4/27/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ffs/fs.h>
#include <string.h>
#include "fsck.h"
void
pass3(void)
{
struct inoinfo *inp;
int loopcnt, inpindex, state;
ino_t orphan;
struct inodesc idesc;
char namebuf[MAXNAMLEN+1];
for (inpindex = inplast - 1; inpindex >= 0; inpindex--) {
inp = inpsort[inpindex];
state = inoinfo(inp->i_number)->ino_state;
if (inp->i_number == ROOTINO ||
(inp->i_parent != 0 && state != DSTATE))
continue;
if (state == DCLEAR)
continue;
/*
* If we are running with soft updates and we come
* across unreferenced directories, we just leave
* them in DSTATE which will cause them to be pitched
* in pass 4.
*/
if (preen && resolved && usedsoftdep && state == DSTATE) {
if (inp->i_dotdot >= ROOTINO)
inoinfo(inp->i_dotdot)->ino_linkcnt++;
continue;
}
for (loopcnt = 0; ; loopcnt++) {
orphan = inp->i_number;
if (inp->i_parent == 0 ||
inoinfo(inp->i_parent)->ino_state != DSTATE ||
loopcnt > countdirs)
break;
inp = getinoinfo(inp->i_parent);
}
if (loopcnt <= countdirs) {
if (linkup(orphan, inp->i_dotdot, NULL)) {
inp->i_parent = inp->i_dotdot = lfdir;
inoinfo(lfdir)->ino_linkcnt--;
}
inoinfo(orphan)->ino_state = DFOUND;
propagate();
continue;
}
pfatal("ORPHANED DIRECTORY LOOP DETECTED I=%lu", orphan);
if (reply("RECONNECT") == 0)
continue;
memset(&idesc, 0, sizeof(struct inodesc));
idesc.id_type = DATA;
idesc.id_number = inp->i_parent;
idesc.id_parent = orphan;
idesc.id_func = findname;
idesc.id_name = namebuf;
if ((ckinode(ginode(inp->i_parent), &idesc) & FOUND) == 0)
pfatal("COULD NOT FIND NAME IN PARENT DIRECTORY");
if (linkup(orphan, inp->i_parent, namebuf)) {
idesc.id_func = clearentry;
if (ckinode(ginode(inp->i_parent), &idesc) & FOUND)
inoinfo(orphan)->ino_linkcnt++;
inp->i_parent = inp->i_dotdot = lfdir;
inoinfo(lfdir)->ino_linkcnt--;
}
inoinfo(orphan)->ino_state = DFOUND;
propagate();
}
}

View File

@ -1,147 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)pass4.c 8.4 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <string.h>
#include "fsck.h"
void
pass4(void)
{
ino_t inumber;
struct zlncnt *zlnp;
struct dinode *dp;
struct inodesc idesc;
int i, n, cg;
memset(&idesc, 0, sizeof(struct inodesc));
idesc.id_type = ADDR;
idesc.id_func = pass4check;
for (cg = 0; cg < sblock.fs_ncg; cg++) {
inumber = cg * sblock.fs_ipg;
for (i = 0; i < inostathead[cg].il_numalloced; i++, inumber++) {
if (inumber < ROOTINO)
continue;
idesc.id_number = inumber;
switch (inoinfo(inumber)->ino_state) {
case FSTATE:
case DFOUND:
n = inoinfo(inumber)->ino_linkcnt;
if (n) {
#if NOTFORIFS
adjust(&idesc, (short)n);
#endif
break;
}
#if NOTFORIFS
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;
}
}
#endif
break;
case DSTATE:
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",
inoinfo(inumber)->ino_state, inumber);
}
}
}
}
int
pass4check(struct inodesc *idesc)
{
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);
}

View File

@ -1,431 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)pass5.c 8.9 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <string.h>
#include "fsck.h"
void
pass5(void)
{
int c, blk, frags, basesize, sumsize, mapsize, savednrpos = 0;
int inomapsize, blkmapsize, astart, aend, ustart, uend;
struct fs *fs = &sblock;
struct cg *cg = &cgrp;
ufs_daddr_t dbase, dmax;
ufs_daddr_t d;
long i, j, k, l, m, n;
struct csum *cs;
struct csum cstotal;
struct inodesc idesc[3];
char buf[MAXBSIZE];
struct cg *newcg = (struct cg *)buf;
struct ocg *ocg = (struct ocg *)buf;
inoinfo(WINO)->ino_state = USTATE;
memset(newcg, 0, (size_t)fs->fs_cgsize);
/*
* Note: cg_niblk is 16 bits and may overflow, so it must never
* be used except for comparing with the old value.
*/
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];
blkmapsize = howmany(fs->fs_fpg, NBBY);
inomapsize = &ocg->cg_free[0] - (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(int32_t);
newcg->cg_iusedoff = newcg->cg_boff +
fs->fs_cpg * fs->fs_nrpos * sizeof(u_int16_t);
newcg->cg_freeoff =
newcg->cg_iusedoff + howmany(fs->fs_ipg, NBBY);
inomapsize = newcg->cg_freeoff - newcg->cg_iusedoff;
newcg->cg_nextfreeoff = newcg->cg_freeoff +
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY);
blkmapsize = newcg->cg_nextfreeoff - newcg->cg_freeoff;
if (fs->fs_contigsumsize > 0) {
newcg->cg_clustersumoff = newcg->cg_nextfreeoff -
sizeof(u_int32_t);
newcg->cg_clustersumoff =
roundup(newcg->cg_clustersumoff, sizeof(u_int32_t));
newcg->cg_clusteroff = newcg->cg_clustersumoff +
(fs->fs_contigsumsize + 1) * sizeof(u_int32_t);
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:
inomapsize = blkmapsize = 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 < fs->fs_ipg)
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 < inostathead[c].il_numalloced; j++, i++) {
switch (inoinfo(j)->ino_state) {
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=%ld",
inoinfo(j)->ino_state, 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(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 (debug) {
for (i = 0; i < inomapsize; i++) {
j = cg_inosused(newcg)[i];
k = cg_inosused(cg)[i];
if (j == k)
continue;
for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
if ((j & l) == (k & l))
continue;
n = c * fs->fs_ipg + i * NBBY + m;
if ((j & l) != 0)
pwarn("%s INODE %d MARKED %s\n",
"ALLOCATED", n, "FREE");
else
pwarn("%s INODE %d MARKED %s\n",
"UNALLOCATED", n, "USED");
}
}
astart = ustart = -1;
for (i = 0; i < blkmapsize; i++) {
j = cg_blksfree(cg)[i];
k = cg_blksfree(newcg)[i];
if (j == k)
continue;
for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
if ((j & l) == (k & l))
continue;
n = c * fs->fs_fpg + i * NBBY + m;
if ((j & l) != 0) {
if (astart == -1) {
astart = aend = n;
continue;
}
if (aend + 1 == n) {
aend = n;
continue;
}
pwarn("%s FRAGS %d-%d %s\n",
"ALLOCATED", astart, aend,
"MARKED FREE");
astart = aend = n;
} else {
if (ustart == -1) {
ustart = uend = n;
continue;
}
if (uend + 1 == n) {
uend = n;
continue;
}
pwarn("%s FRAGS %d-%d %s\n",
"UNALLOCATED", ustart, uend,
"MARKED USED");
ustart = uend = n;
}
}
}
if (astart != -1)
pwarn("%s FRAGS %d-%d %s\n",
"ALLOCATED", astart, aend,
"MARKED FREE");
if (ustart != -1)
pwarn("%s FRAGS %d-%d %s\n",
"UNALLOCATED", ustart, uend,
"MARKED USED");
}
if (usedsoftdep) {
for (i = 0; i < inomapsize; i++) {
j = cg_inosused(newcg)[i];
if ((cg_inosused(cg)[i] & j) == j)
continue;
for (k = 0; k < NBBY; k++) {
if ((j & (1 << k)) == 0)
continue;
if (cg_inosused(cg)[i] & (1 << k))
continue;
pwarn("ALLOCATED INODE %d MARKED FREE\n",
c * fs->fs_ipg + i * NBBY + k);
}
}
for (i = 0; i < blkmapsize; i++) {
j = cg_blksfree(cg)[i];
if ((cg_blksfree(newcg)[i] & j) == j)
continue;
for (k = 0; k < NBBY; k++) {
if ((j & (1 << k)) == 0)
continue;
if (cg_blksfree(newcg)[i] & (1 << k))
continue;
pwarn("ALLOCATED FRAG %d MARKED FREE\n",
c * fs->fs_fpg + i * NBBY + k);
}
}
}
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 (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();
}
}

View File

@ -1,281 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ufs/ufs/dinode.h>
#include <ctype.h>
#include <errno.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; /* auxiliary 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;
static void addpart(char *name, char *fsname, long auxdata);
static struct disk *finddisk(char *name);
static int startdisk(struct disk *dk, int (*checkit)(char *, char *, long, int));
int
checkfstab(int preen, int maxrun, int (*docheck)(struct fstab *),
int (*chkit)(char *, char *, long, int))
{
struct fstab *fsp;
struct disk *dk, *nextdisk;
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(char *name)
{
struct disk *dk, **dkp;
char *p;
size_t len;
p = strrchr(name, '/');
p = p == NULL ? name : p + 1;
while (*p != '\0' && !isdigit((u_char)*p))
p++;
while (isdigit((u_char)*p))
p++;
len = (size_t)(p - name);
for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
if (strncmp(dk->name, name, len) == 0 &&
dk->name[len] == 0)
return (dk);
}
if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
fprintf(stderr, "out of memory");
exit (8);
}
dk = *dkp;
if ((dk->name = malloc(len + 1)) == NULL) {
fprintf(stderr, "out of memory");
exit (8);
}
(void)strncpy(dk->name, name, len);
dk->name[len] = '\0';
dk->part = NULL;
dk->next = NULL;
dk->pid = 0;
ndisks++;
return (dk);
}
static void
addpart(char *name, char *fsname, long auxdata)
{
struct disk *dk = finddisk(name);
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(struct disk *dk, int (*checkit)(char *, char *, long, int))
{
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);
}

View File

@ -1,511 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#define DKTYPENAMES
#include <sys/param.h>
#include <sys/stat.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(int listerr, char *s);
static int calcsb(char *dev, int devfd, struct fs *fs);
static struct disklabel *getdisklabel(char *s, int fd);
static int readsb(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(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;
cursnapshot = 0;
skipclean = fflag ? 0 : 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 &&
(statb.st_mode & S_IFMT) != S_IFBLK) {
if ((statb.st_flags & SF_SNAPSHOT) != 0) {
cursnapshot = statb.st_ino;
} else {
pfatal("%s is not a disk 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).");
bflag = 0;
return(0);
}
pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
bflag = 0;
}
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;
sblock.fs_csp = calloc(1, sblock.fs_cssize);
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;
if (bread(fsreadfd, (char *)sblock.fs_csp + i,
fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
size) != 0 && !asked) {
pfatal("BAD SUMMARY INFORMATION");
if (reply("CONTINUE") == 0) {
ckfini(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;
}
inostathead = calloc((unsigned)(sblock.fs_ncg),
sizeof(struct inostatlist));
if (inostathead == NULL) {
printf("cannot alloc %u bytes for inostathead\n",
(unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg)));
goto badsb;
}
numdirs = sblock.fs_cstotal.cs_ndir;
dirhash = numdirs;
#if NOTFORIFS
if (numdirs == 0) {
printf("numdirs is zero, try using an alternate superblock\n");
goto badsb;
}
#endif
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();
if (sblock.fs_flags & FS_DOSOFTDEP)
usedsoftdep = 1;
else
usedsoftdep = 0;
return (1);
badsb:
ckfini(0);
return (0);
}
/*
* Read in the super block and its summary info.
*/
static int
readsb(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_ocsp, sblock.fs_ocsp, sizeof sblock.fs_ocsp);
altsblock.fs_csp = sblock.fs_csp;
altsblock.fs_maxcluster = sblock.fs_maxcluster;
memmove(altsblock.fs_fsmnt, sblock.fs_fsmnt, sizeof sblock.fs_fsmnt);
memmove(altsblock.fs_snapinum, sblock.fs_snapinum,
sizeof sblock.fs_snapinum);
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 %ld, alternate %ld\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(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(char *dev, int devfd, struct fs *fs)
{
struct disklabel *lp;
struct partition *pp;
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);
}
if (pp->p_fsize == 0 || pp->p_frag == 0 ||
pp->p_cpg == 0 || pp->p_size == 0) {
pfatal("%s: %s: type %s fsize %d, frag %d, cpg %d, size %d\n",
dev, "INCOMPLETE LABEL", fstypenames[pp->p_fstype],
pp->p_fsize, pp->p_frag, pp->p_cpg, pp->p_size);
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_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(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);
}

View File

@ -1,102 +0,0 @@
/*
* 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
#if 0
static const char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <fstab.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "fsck.h"
char *
blockcheck(char *origname)
{
struct stat stslash, stblock, stchar;
char *newname, *raw;
struct fstab *fsinfo;
int retried = 0, len;
newname = origname;
retry:
if (stat(newname, &stblock) < 0) {
printf("Can't stat %s: %s\n", newname, strerror(errno));
return (origname);
}
switch(stblock.st_mode & S_IFMT) {
case S_IFCHR:
case S_IFBLK:
return(newname);
case S_IFDIR:
if (retried)
break;
len = strlen(origname) - 1;
if (len > 0 && origname[len] == '/')
/* remove trailing slash */
origname[len] = '\0';
if ((fsinfo = getfsfile(origname)) == NULL) {
printf("Can't resolve %s to character special device",
origname);
return (0);
}
newname = fsinfo->fs_spec;
retried++;
goto retry;
}
/*
* Not a block or character device, just return name and
* let the user decide whether to use it.
*/
return (origname);
}

View File

@ -1,14 +0,0 @@
# @(#)Makefile 8.6 (Berkeley) 5/8/95
# $FreeBSD$
PROG= mount_ifs
SRCS= mount.c mount_ufs.c getmntopts.c
NOMAN= noman
MOUNT= ${.CURDIR}/../mount
CFLAGS+= -I${MOUNT}
WARNS= 0
.PATH: ${MOUNT}
.include <bsd.prog.mk>

View File

@ -1,30 +0,0 @@
/*-
* Copyright (c) 1997 FreeBSD Inc.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
/* mount_ufs.c */
int mount_ifs(int, char *const *);

View File

@ -1,567 +0,0 @@
/*-
* Copyright (c) 1980, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <fstab.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
#include "mntopts.h"
#include "pathnames.h"
/* `meta' options */
#define MOUNT_META_OPTION_FSTAB "fstab"
#define MOUNT_META_OPTION_CURRENT "current"
int debug, fstab_style, verbose;
char *catopt(char *, const char *);
struct statfs
*getmntpt(const char *);
int hasopt(const char *, const char *);
int ismounted(struct fstab *, struct statfs *, int);
int isremountable(const char *);
void mangle(char *, int *, const char **);
char *update_options(char *, char *, int);
int mountfs(const char *, const char *, const char *,
int, const char *, const char *);
void remopt(char *, const char *);
void prmount(struct statfs *);
void putfsent(const struct statfs *);
void usage(void);
char *flags2opts(int);
/* Map from mount options to printable formats. */
static struct opt {
int o_opt;
const char *o_name;
} optnames[] = {
{ MNT_ASYNC, "asynchronous" },
{ MNT_EXPORTED, "NFS exported" },
{ MNT_LOCAL, "local" },
{ MNT_NOATIME, "noatime" },
{ MNT_NODEV, "nodev" },
{ MNT_NOEXEC, "noexec" },
{ MNT_NOSUID, "nosuid" },
{ MNT_NOSYMFOLLOW, "nosymfollow" },
{ MNT_QUOTA, "with quotas" },
{ MNT_RDONLY, "read-only" },
{ MNT_SYNCHRONOUS, "synchronous" },
{ MNT_UNION, "union" },
{ MNT_NOCLUSTERR, "noclusterr" },
{ MNT_NOCLUSTERW, "noclusterw" },
{ MNT_SUIDDIR, "suiddir" },
{ MNT_SOFTDEP, "soft-updates" },
{ 0, NULL }
};
/*
* List of VFS types that can be remounted without becoming mounted on top
* of each other.
* XXX Is this list correct?
*/
static const char *
remountable_fs_names[] = {
"ufs", "ffs", "lfs", "ext2fs",
0
};
int
main(argc, argv)
int argc;
char * const argv[];
{
mount_ifs(argc, argv);
/* NOTREACHED */
}
int
ismounted(fs, mntbuf, mntsize)
struct fstab *fs;
struct statfs *mntbuf;
int mntsize;
{
int i;
if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0')
/* the root filesystem can always be remounted */
return (0);
for (i = mntsize - 1; i >= 0; --i)
if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 &&
(!isremountable(fs->fs_vfstype) ||
strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0))
return (1);
return (0);
}
int
isremountable(vfsname)
const char *vfsname;
{
const char **cp;
for (cp = remountable_fs_names; *cp; cp++)
if (strcmp(*cp, vfsname) == 0)
return (1);
return (0);
}
int
hasopt(mntopts, option)
const char *mntopts, *option;
{
int negative, found;
char *opt, *optbuf;
if (option[0] == 'n' && option[1] == 'o') {
negative = 1;
option += 2;
} else
negative = 0;
optbuf = strdup(mntopts);
found = 0;
for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
if (opt[0] == 'n' && opt[1] == 'o') {
if (!strcasecmp(opt + 2, option))
found = negative;
} else if (!strcasecmp(opt, option))
found = !negative;
}
free(optbuf);
return (found);
}
int
mountfs(vfstype, spec, name, flags, options, mntopts)
const char *vfstype, *spec, *name, *options, *mntopts;
int flags;
{
/* List of directories containing mount_xxx subcommands. */
static const char *edirs[] = {
_PATH_SBIN,
_PATH_USRSBIN,
NULL
};
const char *argv[100], **edir;
struct statfs sf;
pid_t pid;
int argc, i, status;
char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
#if __GNUC__
(void)&optbuf;
(void)&name;
#endif
/* resolve the mountpoint with realpath(3) */
(void)checkpath(name, mntpath);
name = mntpath;
if (mntopts == NULL)
mntopts = "";
if (options == NULL) {
if (*mntopts == '\0') {
options = "rw";
} else {
options = mntopts;
mntopts = "";
}
}
optbuf = catopt(strdup(mntopts), options);
if (strcmp(name, "/") == 0)
flags |= MNT_UPDATE;
if (flags & MNT_FORCE)
optbuf = catopt(optbuf, "force");
if (flags & MNT_RDONLY)
optbuf = catopt(optbuf, "ro");
/*
* XXX
* The mount_mfs (newfs) command uses -o to select the
* optimization mode. We don't pass the default "-o rw"
* for that reason.
*/
if (flags & MNT_UPDATE)
optbuf = catopt(optbuf, "update");
argc = 0;
argv[argc++] = vfstype;
mangle(optbuf, &argc, argv);
argv[argc++] = spec;
argv[argc++] = name;
argv[argc] = NULL;
if (debug) {
(void)printf("exec: mount_%s", vfstype);
for (i = 1; i < argc; i++)
(void)printf(" %s", argv[i]);
(void)printf("\n");
return (0);
}
switch (pid = fork()) {
case -1: /* Error. */
warn("fork");
free(optbuf);
return (1);
case 0: /* Child. */
if (strcmp(vfstype, "ifs") == 0)
exit(mount_ifs(argc, (char * const *) argv));
/* Go find an executable. */
for (edir = edirs; *edir; edir++) {
(void)snprintf(execname,
sizeof(execname), "%s/mount_%s", *edir, vfstype);
execv(execname, (char * const *)argv);
}
if (errno == ENOENT) {
int len = 0;
char *cp;
for (edir = edirs; *edir; edir++)
len += strlen(*edir) + 2; /* ", " */
if ((cp = malloc(len)) == NULL)
errx(1, "malloc failed");
cp[0] = '\0';
for (edir = edirs; *edir; edir++) {
strcat(cp, *edir);
if (edir[1] != NULL)
strcat(cp, ", ");
}
warn("exec mount_%s not found in %s", vfstype, cp);
}
exit(1);
/* NOTREACHED */
default: /* Parent. */
free(optbuf);
if (waitpid(pid, &status, 0) < 0) {
warn("waitpid");
return (1);
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0)
return (WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
return (1);
}
if (verbose) {
if (statfs(name, &sf) < 0) {
warn("statfs %s", name);
return (1);
}
if (fstab_style)
putfsent(&sf);
else
prmount(&sf);
}
break;
}
return (0);
}
void
prmount(sfp)
struct statfs *sfp;
{
int flags;
struct opt *o;
struct passwd *pw;
(void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
sfp->f_fstypename);
flags = sfp->f_flags & MNT_VISFLAGMASK;
for (o = optnames; flags && o->o_opt; o++)
if (flags & o->o_opt) {
(void)printf(", %s", o->o_name);
flags &= ~o->o_opt;
}
if (sfp->f_owner) {
(void)printf(", mounted by ");
if ((pw = getpwuid(sfp->f_owner)) != NULL)
(void)printf("%s", pw->pw_name);
else
(void)printf("%d", sfp->f_owner);
}
if (verbose) {
if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0)
(void)printf(", writes: sync %ld async %ld",
sfp->f_syncwrites, sfp->f_asyncwrites);
if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0)
(void)printf(", reads: sync %ld async %ld",
sfp->f_syncreads, sfp->f_asyncreads);
}
(void)printf(")\n");
}
struct statfs *
getmntpt(name)
const char *name;
{
struct statfs *mntbuf;
int i, mntsize;
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
for (i = mntsize - 1; i >= 0; i--) {
if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
strcmp(mntbuf[i].f_mntonname, name) == 0)
return (&mntbuf[i]);
}
return (NULL);
}
char *
catopt(s0, s1)
char *s0;
const char *s1;
{
size_t i;
char *cp;
if (s1 == NULL || *s1 == '\0')
return s0;
if (s0 && *s0) {
i = strlen(s0) + strlen(s1) + 1 + 1;
if ((cp = malloc(i)) == NULL)
errx(1, "malloc failed");
(void)snprintf(cp, i, "%s,%s", s0, s1);
} else
cp = strdup(s1);
if (s0)
free(s0);
return (cp);
}
void
mangle(options, argcp, argv)
char *options;
int *argcp;
const char **argv;
{
char *p, *s;
int argc;
argc = *argcp;
for (s = options; (p = strsep(&s, ",")) != NULL;)
if (*p != '\0') {
if (*p == '-') {
argv[argc++] = p;
p = strchr(p, '=');
if (p) {
*p = '\0';
argv[argc++] = p+1;
}
} else if (strcmp(p, "rw") != 0) {
argv[argc++] = "-o";
argv[argc++] = p;
}
}
*argcp = argc;
}
char *
update_options(opts, fstab, curflags)
char *opts;
char *fstab;
int curflags;
{
char *o, *p;
char *cur;
char *expopt, *newopt, *tmpopt;
if (opts == NULL)
return strdup("");
/* remove meta options from list */
remopt(fstab, MOUNT_META_OPTION_FSTAB);
remopt(fstab, MOUNT_META_OPTION_CURRENT);
cur = flags2opts(curflags);
/*
* Expand all meta-options passed to us first.
*/
expopt = NULL;
for (p = opts; (o = strsep(&p, ",")) != NULL;) {
if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0)
expopt = catopt(expopt, fstab);
else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0)
expopt = catopt(expopt, cur);
else
expopt = catopt(expopt, o);
}
free(cur);
free(opts);
/*
* Remove previous contradictory arguments. Given option "foo" we
* remove all the "nofoo" options. Given "nofoo" we remove "nonofoo"
* and "foo" - so we can deal with possible options like "notice".
*/
newopt = NULL;
for (p = expopt; (o = strsep(&p, ",")) != NULL;) {
if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL)
errx(1, "malloc failed");
strcpy(tmpopt, "no");
strcat(tmpopt, o);
remopt(newopt, tmpopt);
free(tmpopt);
if (strncmp("no", o, 2) == 0)
remopt(newopt, o+2);
newopt = catopt(newopt, o);
}
free(expopt);
return newopt;
}
void
remopt(string, opt)
char *string;
const char *opt;
{
char *o, *p, *r;
if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0')
return;
r = string;
for (p = string; (o = strsep(&p, ",")) != NULL;) {
if (strcmp(opt, o) != 0) {
if (*r == ',' && *o != '\0')
r++;
while ((*r++ = *o++) != '\0')
;
*--r = ',';
}
}
*r = '\0';
}
void
usage()
{
(void)fprintf(stderr, "%s\n",
"usage: mount [-dfpruvw] [-o options] special node");
exit(1);
}
void
putfsent(ent)
const struct statfs *ent;
{
struct fstab *fst;
char *opts;
opts = flags2opts(ent->f_flags);
printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname,
ent->f_fstypename, opts);
free(opts);
if ((fst = getfsspec(ent->f_mntfromname)))
printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
else if ((fst = getfsfile(ent->f_mntonname)))
printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
else if (strcmp(ent->f_fstypename, "ufs") == 0) {
if (strcmp(ent->f_mntonname, "/") == 0)
printf("\t1 1\n");
else
printf("\t2 2\n");
} else
printf("\t0 0\n");
}
char *
flags2opts(flags)
int flags;
{
char *res;
res = NULL;
res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw");
if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync");
if (flags & MNT_NOEXEC) res = catopt(res, "noexec");
if (flags & MNT_NOSUID) res = catopt(res, "nosuid");
if (flags & MNT_NODEV) res = catopt(res, "nodev");
if (flags & MNT_UNION) res = catopt(res, "union");
if (flags & MNT_ASYNC) res = catopt(res, "async");
if (flags & MNT_NOATIME) res = catopt(res, "noatime");
if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr");
if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw");
if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow");
if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir");
return res;
}

View File

@ -1,155 +0,0 @@
/*-
* 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 const char copyright[] =
"@(#) Copyright (c) 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)mount_ufs.c 8.4 (Berkeley) 4/26/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/mount.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ufs/ufs/ufsmount.h>
#include "extern.h"
#include "mntopts.h"
static void ifs_usage(void);
static struct mntopt mopts[] = {
MOPT_STDOPTS,
MOPT_ASYNC,
MOPT_FORCE,
MOPT_SYNC,
MOPT_UPDATE,
MOPT_SNAPSHOT,
{ NULL }
};
int
mount_ifs(argc, argv)
int argc;
char * const argv[];
{
struct ufs_args args;
int ch, mntflags;
char *fs_name;
struct vfsconf vfc;
int error = 0;
mntflags = 0;
optind = optreset = 1; /* Reset for parse of new argv. */
while ((ch = getopt(argc, argv, "o:")) != -1)
switch (ch) {
case 'o':
getmntopts(optarg, mopts, &mntflags, 0);
break;
case '?':
default:
ifs_usage();
}
argc -= optind;
argv += optind;
if (argc != 2)
ifs_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;
error = getvfsbyname("ifs", &vfc);
if (error && vfsisloadable("ifs")) {
if (vfsload("ifs")) {
warn("vfsload(ifs)");
return (1);
}
endvfsent(); /* flush old table */
error = getvfsbyname("ifs", &vfc);
}
if (error) {
warnx("ifs filesystem is not available");
return (1);
}
if (mount(vfc.vfc_name, fs_name, mntflags, &args) < 0) {
switch (errno) {
case EMFILE:
warnx("%s on %s: mount table full",
args.fspec, fs_name);
break;
case EINVAL:
if (mntflags & MNT_UPDATE)
warnx(
"%s on %s: specified device does not match mounted device",
args.fspec, fs_name);
else
warnx("%s on %s: incorrect super block",
args.fspec, fs_name);
break;
default:
warn(NULL);
break;
}
return (1);
}
return (0);
}
static void
ifs_usage()
{
(void)fprintf(stderr, "usage: mount_ifs [-o options] special node\n");
exit(1);
}