#!/bin/sh # # $NetBSD: fixsb,v 1.6 2004/04/21 17:26:42 dbj Exp $ # # PROVIDE: fixsb # REQUIRE: localswap # BEFORE: fsck . /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 # 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 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() { # 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 # In each of the foo=$(dd | dd | cat -v) pipelines below, 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 with to # read. The data is put through cat -v to avoid having binary data in shell strings. verbose -n "Checking $1 ... " # First we extract the superblock magic number field: magic="$( (dd if="$1" bs=8192 skip=1 count=1 | dd bs=1 count=4 skip=1372 | cat -v) 2> /dev/null)" # First we check if the magic number is valid either swapped or unswapped: if [ "${magic}" = "${fsmagicn}" -o "${magic}" = "${fsmagics}" ]; then # Then we read fs_bsize, fs_maxbsize and fs_old_flags fields from the disk: bsize="$( (dd if="$1" bs=8192 skip=1 count=1 | dd bs=1 count=4 skip=48 | cat -v) 2> /dev/null)" maxbsize="$( (dd if="$1" bs=8192 skip=1 count=1 | dd bs=1 count=4 skip=860 | cat -v) 2> /dev/null)" oldflags="$( (dd if="$1" bs=8192 skip=1 count=1 | dd bs=1 count=1 skip=211 | cat -v) 2> /dev/null)" # Compare the fs_bsize with fs_maxbsize to see if they are the same if [ "${bsize}" = "${maxbsize}" ]; then # Now check to see if the high bit of fs_old_flags is set. 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 ;; # if the high bit of fs_old_flags is not set, then there is a problem *) verbose "file system has botched superblock upgrade." return 0 ;; esac fi # [ "${bsize}" = "${maxbsize}" ] else # ! [ "${magic}" = "${fsmagicn}" -o "${magic}" = "${fsmagics}" ] verbose "does not appear to be an ffs1 filesystem." return 1 fi # ! [ "${magic}" = "${fsmagicn}" -o "${magic}" = "${fsmagics}" ] verbose "file system looks ok at fslevel 3." return 3 } # 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 if [ \( "$t" = "ffs" -o "$t" = "ufs" \) -a "$f" = "$l" ]; then echo "$d" fi 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 echo "Checking for botched superblock upgrades:" for p in $(parse_fstab); do if check_part "$p"; then echo "Repairing partition $p" do_fsck -p -b 16 -c 4 "$p" do_fsck -p -c 3 "$p" fi done fi } load_rc_config $name run_rc_command "$1"