diff options
Diffstat (limited to 'modules.d/99fs-lib')
-rwxr-xr-x | modules.d/99fs-lib/fs-lib.sh | 262 | ||||
-rwxr-xr-x | modules.d/99fs-lib/module-setup.sh | 89 |
2 files changed, 351 insertions, 0 deletions
diff --git a/modules.d/99fs-lib/fs-lib.sh b/modules.d/99fs-lib/fs-lib.sh new file mode 100755 index 0000000..c4640fa --- /dev/null +++ b/modules.d/99fs-lib/fs-lib.sh @@ -0,0 +1,262 @@ +#!/bin/sh + +type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh + +fsck_ask_reboot() { + info "note - fsck suggests reboot, if you" + info "leave shell, booting will continue normally" + emergency_shell -n "(reboot ?)" +} + +fsck_ask_err() { + warn "*** An error occurred during the file system check." + warn "*** Dropping you to a shell; the system will try" + warn "*** to mount the filesystem(s), when you leave the shell." + emergency_shell -n "(Repair filesystem)" +} + +# inherits: _ret _drv _out +fsck_tail() { + [ "$_ret" -gt 0 ] && warn "$_drv returned with $_ret" + if [ "$_ret" -ge 4 ]; then + [ -n "$_out" ] && echo "$_out" | vwarn + fsck_ask_err + else + [ -n "$_out" ] && echo "$_out" | vinfo + [ "$_ret" -ge 2 ] && fsck_ask_reboot + fi +} + +# note: this function sets _drv of the caller +fsck_able() { + case "$1" in + xfs) + # { + # type xfs_db && + # type xfs_repair && + # type xfs_check && + # type mount && + # type umount + # } >/dev/null 2>&1 && + # _drv="_drv=none fsck_drv_xfs" && + # return 0 + return 1 + ;; + ext?) + type e2fsck > /dev/null 2>&1 \ + && _drv="fsck_drv_com e2fsck" \ + && return 0 + ;; + f2fs) + type fsck.f2fs > /dev/null 2>&1 \ + && _drv="fsck_drv_com fsck.f2fs" \ + && return 0 + ;; + jfs) + type jfs_fsck > /dev/null 2>&1 \ + && _drv="fsck_drv_com jfs_fsck" \ + && return 0 + ;; + reiserfs) + type reiserfsck > /dev/null 2>&1 \ + && _drv="fsck_drv_com reiserfsck" \ + && return 0 + ;; + btrfs) + # type btrfsck >/dev/null 2>&1 && + # _drv="_drv=none fsck_drv_btrfs" && + # return 0 + return 1 + ;; + nfs*) + # nfs can be a nop, returning success + _drv=":" \ + && return 0 + ;; + *) + type fsck > /dev/null 2>&1 \ + && _drv="fsck_drv_std fsck" \ + && return 0 + ;; + esac + + return 1 +} + +# note: all drivers inherit: _drv _fop _dev + +fsck_drv_xfs() { + # xfs fsck is not necessary... Either it mounts or not + return 0 +} + +fsck_drv_btrfs() { + # btrfs fsck is not necessary... Either it mounts or not + return 0 +} + +# common code for checkers that follow usual subset of options and return codes +fsck_drv_com() { + local _drv="$1" + local _ret + local _out + + if ! strglobin "$_fop" "-[ynap]"; then + _fop="-a${_fop:+ "$_fop"}" + fi + + info "issuing $_drv $_fop $_dev" + # we enforce non-interactive run, so $() is fine + # shellcheck disable=SC2086 + _out=$($_drv $_fop "$_dev") + _ret=$? + fsck_tail + + return $_ret +} + +# code for generic fsck, if the filesystem checked is "unknown" to us +fsck_drv_std() { + local _ret + local _out + unset _out + + info "issuing fsck $_fop $_dev" + # note, we don't enforce -a here, thus fsck is being run (in theory) + # interactively; otherwise some tool might complain about lack of terminal + # (and using -a might not be safe) + # shellcheck disable=SC2086 + fsck $_fop "$_dev" > /dev/console 2>&1 + _ret=$? + fsck_tail + + return $_ret +} + +# checks single filesystem, relying on specific "driver"; we don't rely on +# automatic checking based on fstab, so empty one is passed; +# takes 4 arguments - device, filesystem, filesystem options, additional fsck options; +# first 2 arguments are mandatory (fs may be auto or "") +# returns 255 if filesystem wasn't checked at all (e.g. due to lack of +# necessary tools or insufficient options) +fsck_single() { + local FSTAB_FILE=/etc/fstab.empty + local _dev="$1" + local _fs="${2:-auto}" + local _fop="$4" + local _drv + + [ $# -lt 2 ] && return 255 + _dev=$(readlink -f "$(label_uuid_to_dev "$_dev")") + [ -e "$_dev" ] || return 255 + _fs=$(det_fs "$_dev" "$_fs") + fsck_able "$_fs" || return 255 + + info "Checking $_fs: $_dev" + export FSTAB_FILE + eval "$_drv" + return $? +} + +# takes list of filesystems to check in parallel; we don't rely on automatic +# checking based on fstab, so empty one is passed +fsck_batch() { + local FSTAB_FILE=/etc/fstab.empty + local _drv=fsck + local _dev + local _ret + local _out + + [ $# -eq 0 ] || ! type fsck > /dev/null 2>&1 && return 255 + + info "Checking filesystems (fsck -M -T -a):" + for _dev in "$@"; do + info " $_dev" + done + + export FSTAB_FILE + _out="$(fsck -M -T "$@" -- -a)" + _ret=$? + + fsck_tail + + return $_ret +} + +# verify supplied filesystem type: +# if user provided the fs and we couldn't find it, assume user is right +# if we found the fs, assume we're right +det_fs() { + local _dev="$1" + local _orig="${2:-auto}" + local _fs + + _fs=$(udevadm info --query=property --name="$_dev" \ + | while read -r line || [ -n "$line" ]; do + if str_starts "$line" "ID_FS_TYPE="; then + echo "${line#ID_FS_TYPE=}" + break + fi + done) + _fs=${_fs:-auto} + + if [ "$_fs" = "auto" ]; then + _fs="$_orig" + fi + echo "$_fs" +} + +write_fs_tab() { + local _o + local _rw + local _root + local _rootfstype + local _rootflags + local _fspassno + + _fspassno="0" + _root="$1" + _rootfstype="$2" + _rootflags="$3" + [ -z "$_rootfstype" ] && _rootfstype=$(getarg rootfstype=) + [ -z "$_rootflags" ] && _rootflags=$(getarg rootflags=) + + [ -z "$_rootfstype" ] && _rootfstype="auto" + + if [ -z "$_rootflags" ]; then + _rootflags="ro,x-initrd.mount" + else + _rootflags="ro,$_rootflags,x-initrd.mount" + fi + + _rw=0 + + CMDLINE=$(getcmdline) + for _o in $CMDLINE; do + case $_o in + rw) + _rw=1 + ;; + ro) + _rw=0 + ;; + esac + done + if [ "$_rw" = "1" ]; then + _rootflags="$_rootflags,rw" + if ! getargbool 0 rd.skipfsck; then + _fspassno="1" + fi + fi + + if grep -q "$_root /sysroot" /etc/fstab; then + echo "$_root /sysroot $_rootfstype $_rootflags $_fspassno 0" >> /etc/fstab + else + return + fi + + if type systemctl > /dev/null 2> /dev/null; then + systemctl daemon-reload + systemctl --no-block start initrd-root-fs.target + fi +} diff --git a/modules.d/99fs-lib/module-setup.sh b/modules.d/99fs-lib/module-setup.sh new file mode 100755 index 0000000..2b81b0c --- /dev/null +++ b/modules.d/99fs-lib/module-setup.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +# called by dracut +check() { + return 0 +} + +# called by dracut +depends() { + return 0 +} + +echo_fs_helper() { + local fs=$2 + case "$fs" in + xfs) + echo -n " xfs_db xfs_repair xfs_check xfs_metadump " + ;; + ext?) + echo -n " e2fsck " + ;; + jfs) + echo -n " jfs_fsck " + ;; + reiserfs) + echo -n " reiserfsck " + ;; + btrfs) + echo -n " btrfsck " + ;; + esac + + echo -n " fsck.$fs " + return 0 +} + +include_fs_helper_modules() { + local fs=$2 + case "$fs" in + xfs | btrfs | ext4 | ext3) + instmods crc32c + ;; + f2fs) + instmods crc32 + ;; + esac +} + +# called by dracut +installkernel() { + # xfs/btrfs/ext4 need crc32c, f2fs needs crc32 + if [[ $hostonly ]]; then + for_each_host_dev_fs include_fs_helper_modules + : + else + instmods crc32c crc32 + fi +} + +# called by dracut +install() { + local _helpers + + inst "$moddir/fs-lib.sh" "/lib/fs-lib.sh" + : > "${initdir}"/etc/fstab.empty + + [[ $nofscks == "yes" ]] && return + + if [[ $fscks == "${fscks#*[^ ]*}" ]]; then + _helpers=( + /sbin/fsck* /usr/sbin/fsck* + xfs_db xfs_check xfs_repair xfs_metadump + e2fsck jfs_fsck reiserfsck btrfsck + ) + if [[ $hostonly ]]; then + read -r -a _helpers < <(for_each_host_dev_fs echo_fs_helper) + fi + else + read -r -a _helpers <<< "$fscks" + fi + + _helpers+=(umount mount) + + if [[ ${_helpers[*]} == *e2fsck* ]] && [[ -e $dracutsysrootdir/etc/e2fsck.conf ]]; then + inst_simple /etc/e2fsck.conf + fi + + inst_multiple -o "${_helpers[@]}" fsck +} |