[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Automated fsck on boot
Hi Jari,
On Sun, Apr 09, 2006 at 11:14:55AM +0300, Jari Ruusu wrote:
> Your version compared device (or file) names. Comparing names is
> problematic because they may be truncated or they may use relative
> paths (not begin with slash). I changed it to compare device number
> and inode number of the block special file (or normal file) to those
> recorded in loop device.
>
> # losetup /dev/loop6
> /dev/loop6: [0902]:213045 (/dev/md5) offset=4096 encryption=AES128 multi-key-v3
> ^^^^ ^^^^^^
> | |
> | Inode number inside my root file system where static
> | block special node /dev/md5 happens to reside.
> |
> Device number of my root file system where static
> block special node /dev/md5 happens to reside.
Ah, I see. That makes a lot of sense - I suppose someone could also
have replaced a loop file with a different file of the same name, or
udev could have been renaming a device node. In both cases comparing
only filenames would give a wrong result.
> I merged your patch, but now the code looks like this:
>
> int is_loop_active(const char *dev, const char *backdev)
> {
> int fd;
> int ret = 0;
> struct stat statbuf;
> struct loop_info64 loopinfo;
> if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
> fd = open (dev, O_RDONLY);
> if (fd < 0)
> return 0;
> if ((loop_get_status64_ioctl(fd, &loopinfo) == 0)
> && (stat (backdev, &statbuf) == 0)
> && (statbuf.st_dev == loopinfo.lo_device)
> && (statbuf.st_ino == loopinfo.lo_inode))
> ret = 1; /* backing device matches */
> memset(&loopinfo, 0, sizeof(loopinfo));
> close(fd);
> }
> return ret;
> }
Works perfectly for me. Thanks a lot!
I'm attaching a preliminary version of the rcS.d init script I'm
planning to ship in the Debian package loop-aes-utils.
I'm undecided about whether to enable the init script for existing
setups. It is safer for every filesystem to be fscked regularily,
but then someone might have a loop device with a file system on it
that shows uncorrectable errors - this could cause the boot to abort
and drop to sulogin for manual correction. Or there might be an
existing script that does losetup -F and fsck which could break if
this script runs before and leaves the loop allocated.
What do Debian users here think? Other thoughts or experiences?
I currently tend to leave it disabled by default and document in
README.Debian that one needs to enable it manually by editing a
flag in /etc/default/checkfs-loop (or so).
cheers,
Max
#!/bin/sh
### BEGIN INIT INFO
# Provides: checkfs-loop
# Required-Start: checkroot
# Required-Stop:
# Should-Start: udev devfsd raid2 mdadm lvm
# Should-Stop:
# Default-Start: S
# Default-Stop:
# Short-Description: Check loop-encrypted filesystems.
### END INIT INFO
#
# NOTE: This script duplicates much of checkfs.sh as we need to
# work on the decrypted loop devices, which fsck -A doesn't know
# about. The maintainer of this script should track changes in
# checkfs.sh and make sure they are applied.
PATH=/sbin:/bin
FSCK_LOGFILE=/var/log/fsck/loop
[ "$FSCKFIX" ] || FSCKFIX=no
. /lib/init/vars.sh
. /lib/lsb/init-functions
list_fsck_loops () {
grep -v '^#' /etc/fstab |
while read dev mnt fstype opts freq passno; do
fsck=yes
loopdev=
for opt in $(IFS=, && echo $opts)
do
case $opt in
noauto|sw)
fsck=no
;;
loop=/dev/loop*)
loopdev=${opt#loop=}
;;
esac
done
if [ -z "$loopdev" ] || [ "$fsck" = no ]
then
continue
fi
echo $loopdev:$mnt
done
}
retries=3
do_losetup () {
loop=${1%:*}
mnt=${1#*:}
try=0
log_action_msg "Setting up $loop ($mnt)"
while [ $try -lt $retries ]
do
if losetup -F $loop
then
return 0
fi
try=$((try+1))
done
return 1
}
# TODO We can't do anything about FSCKTYPES settings other than "none"
do_fsck () {
loopdevs="$@"
# See if we're on AC Power
# If not, we're not gonna run our check
if which on_ac_power >/dev/null 2>&1
then
on_ac_power >/dev/null 2>&1
if [ $? -eq 1 ]
then
[ "$VERBOSE" = no ] || log_success_msg "Running on battery power, so skipping loop file system check."
BAT=yes
fi
fi
#
# Check loop-encrypted file systems.
#
if [ ! -f /fastboot ] && [ ! "$BAT" ] && [ "$FSCKTYPES" != "none" ]
then
if [ -f /forcefsck ]
then
force="-f"
else
force=""
fi
if [ "$FSCKFIX" = yes ]
then
fix="-y"
else
fix="-a"
fi
spinner="-C"
case "$TERM" in
dumb|network|unknown|"")
spinner=""
;;
esac
[ "$(uname -m)" = s390 ] && spinner="" # This should go away
handle_failed_fsck() {
log_failure_msg "File system check failed.
A log is being saved in ${FSCK_LOGFILE} if that location is writable.
Please repair the file system manually."
log_warning_msg "A maintenance shell will now be started.
CONTROL-D will terminate this shell and resume system boot."
# Start a single user shell on the console
if ! sulogin $CONSOLE
then
log_failure_msg "Attempt to start maintenance shell failed.
Continuing with system boot in 5 seconds."
sleep 5
fi
}
failed=
for device in $loopdevs
do
if [ "$VERBOSE" = no ]
then
logsave -s $FSCK_LOGFILE fsck $spinner $fix $force $device
FSCKCODE=$?
if [ "$FSCKCODE" -gt 1 ]
then
failed=1
fi
else
logsave -s $FSCK_LOGFILE fsck $spinner -V $fix $force $device
FSCKCODE=$?
if [ "$FSCKCODE" -gt 1 ]
then
failed=1
fi
fi
done
if [ "$failed" ]
then
handle_failed_fsck
else
if [ "$VERBOSE" = yes ]
then
log_success_msg "Done checking loop-encrypted file systems.
A log is being saved in ${FSCK_LOGFILE} if that location is writable."
fi
fi
fi
# Do not delete those, we are running before checkfs and it will
# still need them
#rm -f /fastboot /forcefsck
}
do_start () {
log_action_msg "Checking loop-encrypted file systems"
check_loops=
for device in $(list_fsck_loops)
do
if do_losetup $device
then
check_loops="$check_loops ${device%:*}"
fi
done
do_fsck $check_loops
}
case "$1" in
start|"")
do_start
;;
restart|reload|force-reload)
echo "Error: argument '$1' not supported" >&2
exit 3
;;
stop)
# No-op
;;
*)
echo "Usage: checkfs-loop.sh [start|stop]" >&2
exit 3
;;
esac
: