206 lines
4.5 KiB
Bash
Executable File
206 lines
4.5 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# $NetBSD: fixsb,v 1.12 2004/12/30 09:32:13 dsainty Exp $
|
|
#
|
|
|
|
# PROVIDE: fixsb
|
|
# REQUIRE: localswap
|
|
# BEFORE: fsck
|
|
|
|
$_rc_subr_loaded . /etc/rc.subr
|
|
|
|
name="fixsb"
|
|
rcvar=$name
|
|
start_cmd="fsck_start"
|
|
stop_cmd=":"
|
|
|
|
# This rc.d script attempts to correct problems with ffs1 filesystems
|
|
# which may have been introduced by booting a netbsd-current kernel
|
|
# from between April of 2003 and January 2004. For more information
|
|
# see <http://mail-index.NetBSD.org/current-users/2004/01/11/0022.html>
|
|
# This script was developed as a response to NetBSD pr install/25138
|
|
# Additional prs regarding the original issue include:
|
|
# bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926
|
|
#
|
|
|
|
fstab=/etc/fstab
|
|
#verbose=1
|
|
|
|
verbose()
|
|
{
|
|
if [ -n "${verbose}" ]; then
|
|
echo "$@" 1>&2
|
|
fi
|
|
}
|
|
|
|
# This reads a field from the ffs superblock
|
|
# at the specified offset and length in bytes
|
|
# from the start of the superblock
|
|
readsbfield()
|
|
{
|
|
# The first dd command reads in the superblock using block aligned i/o
|
|
# so that it works on a raw character device. The second dd extracts
|
|
# the exact field from the superblock that we wish to read.
|
|
(dd if="$1" bs=8192 count=1 skip=1 |
|
|
dd bs=1 skip="$2" count="$3" | cat -v) 2> /dev/null
|
|
}
|
|
|
|
# This shell function extracts the `ffs superblock' of the file
|
|
# provided as its argument and tests for the following condition:
|
|
# ((fs_magic == FS_UFS1_MAGIC) || fs_magic == FS_UFS1_MAGIC_SWAPPED) &&
|
|
# (fs_sbsize == fs_maxbsize) && !(fs_old_flags & FS_FLAGS_UPDATED)
|
|
#
|
|
# return status is based on status of last filesystem checked:
|
|
# 0 for botched superblock
|
|
# 1 for filesystem does not appear to be ffs1 filesystem
|
|
# 3 for ok fslevel 3 filesystem
|
|
# 4 for ok fslevel 4 filesystem
|
|
#
|
|
# dbj@NetBSD.org 2004-04-12T18:15:06-0400
|
|
check_part()
|
|
{
|
|
verbose -n "Checking $1 ... "
|
|
|
|
# The following are 'cat -v' representations of the ffs1 magic number:
|
|
fsmagicn="^@^A^YT" # 0x00011954 FS_UFS1_MAGIC
|
|
fsmagics="T^Y^A^@" # 0x54190100 FS_UFS1_MAGIC_SWAPPED
|
|
|
|
# First we extract the superblock magic number field.
|
|
# We use cat -v to avoid having binary data in shell strings.
|
|
magic="$(readsbfield "$1" 1372 4)"
|
|
|
|
# Then we check if the magic number is valid (swapped or unswapped):
|
|
if [ "${magic}" != "${fsmagicn}" -a "${magic}" != "${fsmagics}" ]; then
|
|
verbose "does not appear to be an ffs1 filesystem."
|
|
return 1
|
|
fi
|
|
|
|
# Then we read fs_old_flags fields from disk
|
|
# And check the value of its high bit.
|
|
oldflags="$(readsbfield "$1" 211 1)"
|
|
|
|
case "${oldflags}" in
|
|
# Since the shell variable is the cat -v output, the
|
|
# high bit is indicated in the variable with the prefix M-
|
|
M-*)
|
|
verbose "file system looks ok at fslevel 4."
|
|
return 4
|
|
;;
|
|
esac
|
|
|
|
# Then we read fs_bsize, fs_maxbsize fields from the disk:
|
|
bsize="$(readsbfield "$1" 48 4)"
|
|
maxbsize="$(readsbfield "$1" 860 4)"
|
|
|
|
# Compare the fs_bsize with fs_maxbsize to see if they are the same
|
|
if [ "${bsize}" != "${maxbsize}" ]; then
|
|
verbose "file system looks ok at fslevel 3."
|
|
return 3
|
|
fi
|
|
|
|
verbose "file system has botched superblock upgrade."
|
|
return 0
|
|
}
|
|
|
|
# This extracts raw ufs partitions to be fsck'ed from the file ${fstab}
|
|
parse_fstab()
|
|
{
|
|
for l in 1 2; do
|
|
cat "${fstab}" 2> /dev/null |
|
|
while read d m t o b f err; do
|
|
case "$d" in
|
|
\#*)
|
|
continue
|
|
;;
|
|
/dev/*)
|
|
d="/dev/r${d#/dev/}"
|
|
;;
|
|
esac
|
|
case "$t" in
|
|
ffs|ufs)
|
|
if [ "$f" = "$l" ]; then
|
|
echo "$d"
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
done
|
|
}
|
|
|
|
stop_boot()
|
|
{
|
|
# Terminate the process (which may include the parent /etc/rc)
|
|
# if booting directly to multiuser mode.
|
|
if [ "$autoboot" = "yes" ]; then
|
|
kill -TERM $$
|
|
fi
|
|
exit 1
|
|
}
|
|
|
|
do_fsck()
|
|
{
|
|
# During fsck ignore SIGQUIT
|
|
|
|
fsck_ffs "$@"
|
|
case $? in
|
|
0)
|
|
;;
|
|
2)
|
|
stop_boot
|
|
;;
|
|
4)
|
|
echo "Rebooting..."
|
|
reboot
|
|
echo "Reboot failed; help!"
|
|
stop_boot
|
|
;;
|
|
8)
|
|
echo "Automatic file system check failed; help!"
|
|
stop_boot
|
|
;;
|
|
12)
|
|
echo "Boot interrupted."
|
|
stop_boot
|
|
;;
|
|
130)
|
|
stop_boot
|
|
;;
|
|
*)
|
|
echo "Unknown error; help!"
|
|
stop_boot
|
|
;;
|
|
esac
|
|
}
|
|
|
|
fsck_start()
|
|
{
|
|
if [ -e /fastboot ]; then
|
|
echo "Fast boot: skipping disk checks."
|
|
else
|
|
# During fsck ignore SIGQUIT
|
|
trap : 3
|
|
okfs=true
|
|
|
|
echo -n "Checking for botched superblock upgrades:"
|
|
for p in $(parse_fstab); do
|
|
if check_part "$p"; then
|
|
if $okfs; then
|
|
echo
|
|
okfs=false
|
|
fi
|
|
echo "Repairing partition $p"
|
|
do_fsck -p -b 16 -c 4 "$p"
|
|
do_fsck -p -c 3 "$p"
|
|
fi
|
|
done
|
|
if $okfs; then
|
|
echo " done."
|
|
else
|
|
echo "Superblock(s) updated successfully."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
load_rc_config $name
|
|
run_rc_command "$1"
|