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:
parent
d5caaf02c1
commit
8b1febe499
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=96884
@ -21,7 +21,6 @@ SUBDIR= adjkerntz \
|
|||||||
ffsinfo \
|
ffsinfo \
|
||||||
fsck \
|
fsck \
|
||||||
fsck_ffs \
|
fsck_ffs \
|
||||||
fsck_ifs \
|
|
||||||
fsck_msdosfs \
|
fsck_msdosfs \
|
||||||
fsdb \
|
fsdb \
|
||||||
fsirand \
|
fsirand \
|
||||||
@ -42,7 +41,6 @@ SUBDIR= adjkerntz \
|
|||||||
mount \
|
mount \
|
||||||
mount_cd9660 \
|
mount_cd9660 \
|
||||||
mount_ext2fs \
|
mount_ext2fs \
|
||||||
mount_ifs \
|
|
||||||
mount_msdosfs \
|
mount_msdosfs \
|
||||||
mount_nfs \
|
mount_nfs \
|
||||||
mount_ntfs \
|
mount_ntfs \
|
||||||
|
@ -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>
|
|
@ -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);
|
|
||||||
}
|
|
@ -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);
|
|
@ -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
|
|
@ -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);
|
|
||||||
}
|
|
@ -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--;
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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]);
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
@ -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>
|
|
@ -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 *);
|
|
@ -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;
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user