future-install-scripts/genfstab.in
Mike Yuan 7881d7ebce
genfstab: drop ancient vfat quirk
Kernel before 3.18 is unsupported by Arch.
2023-03-03 19:27:04 +08:00

247 lines
6.7 KiB
Bash

#!/bin/bash
# shellcheck disable=SC2154 # optstring_*_option may export variables in runtime
shopt -s extglob
# m4_include() is recognized as a function definition
# shellcheck source=common disable=SC1073,SC1065,SC1064,SC1072
m4_include(common)
bytag=src
pseudofs=0
write_source() {
local src spec comments=()
src="$(mangle "$1")"
local -A sources=([LABEL]="$(mangle "$(lsblk -rno LABEL "$1" 2>/dev/null)")"
[UUID]="$(lsblk -rno UUID "$1" 2>/dev/null)"
[PARTLABEL]="$(mangle "$(lsblk -rno PARTLABEL "$1" 2>/dev/null)")"
[PARTUUID]="$(lsblk -rno PARTUUID "$1" 2>/dev/null)"
)
if [[ ${sources["$bytag"]} ]]; then
spec="$bytag"
comments+=("$src")
else
spec=src
fi
for tag in "${!sources[@]}"; do
if [[ ${sources["$tag"]} && "$tag" != "$spec" ]]; then
comments+=("$tag=${sources["$tag"]}")
fi
done
(( ${#comments[@]} )) && printf '# %s\n' "${comments[*]}"
if [[ "$spec" != "src" ]]; then
printf '%-20s' "$spec=${sources["$spec"]}"
else
printf '%-20s' "$src"
fi
}
optstring_apply_quirks() {
local varname="$1" fstype="$2"
# SELinux displays a 'seclabel' option in /proc/self/mountinfo. We can't know
# if the system we're generating the fstab for has any support for SELinux (as
# one might install Arch from a Fedora environment), so let's remove it.
optstring_remove_option "$varname" seclabel
# Prune 'relatime' option for any pseudofs. This seems to be a rampant
# default which the kernel often exports even if the underlying filesystem
# doesn't support it. Example: https://bugs.archlinux.org/task/54554.
if fstype_is_pseudofs "$fstype"; then
optstring_remove_option "$varname" relatime
fi
case $fstype in
btrfs)
# Having only one of subvol= and subvolid= is enough for mounting a btrfs subvolume
# And having subvolid= set prevents things like 'snapper rollback' to work, as it
# updates the subvolume in-place, leaving subvol= unchanged with a different subvolid.
if optstring_has_option "$varname" subvol; then
optstring_remove_option "$varname" subvolid
fi
;;
f2fs)
# These are Kconfig options for f2fs. Kernels supporting the options will
# only provide the negative versions of these (e.g. noacl), and vice versa
# for kernels without support.
optstring_remove_option "$varname" noacl,acl,nouser_xattr,user_xattr
;;
esac
}
usage() {
cat <<EOF
usage: ${0##*/} [options] root
Options:
-f <filter> Restrict output to mountpoints matching the prefix FILTER
-L Use labels for source identifiers (shortcut for -t LABEL)
-p Exclude pseudofs mounts (default behavior)
-P Include pseudofs mounts
-t <tag> Use TAG for source identifiers (TAG should be one of: LABEL,
UUID, PARTLABEL, PARTUUID)
-U Use UUIDs for source identifiers (shortcut for -t UUID)
-h Print this help message
genfstab generates output suitable for addition to an fstab file based on
the devices mounted under the mountpoint specified by the given root.
EOF
}
if [[ -z $1 || $1 = @(-h|--help) ]]; then
usage
exit $(( $# ? 0 : 1 ))
fi
while getopts ':f:LPpt:U' flag; do
case $flag in
f)
prefixfilter="$OPTARG"
;;
L)
bytag=LABEL
;;
P)
pseudofs=1
;;
p)
pseudofs=0
;;
t)
bytag="${OPTARG^^}"
;;
U)
bytag=UUID
;;
:)
die "%s: option requires an argument -- '%s'" "${0##*/}" "$OPTARG"
;;
?)
die "%s: invalid option -- '%s'" "${0##*/}" "$OPTARG"
;;
esac
done
shift $(( OPTIND - 1 ))
(( $# )) || die 'No root directory specified'
root="$(realpath -mL "$1")"; shift
if ! mountpoint -q "$root"; then
die '%s: not a mountpoint' "$root"
fi
# handle block devices
findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" |
while read -r src target fstype opts fsroot; do
if (( ! pseudofs )) && fstype_is_pseudofs "$fstype"; then
continue
fi
[[ "$target" = "$prefixfilter"* ]] || continue
# default 5th and 6th columns
dump=0 pass=2
src="$(unmangle "$src")"
target="$(unmangle "$target")"
target="${target#"$root/"}"
[[ "$target" != '/'* ]] && target="/$target"
if (( ! foundroot )) && findmnt "$src" "$root" >/dev/null; then
# this is root. we can't possibly have more than one...
pass=1 foundroot=1
fi
# if there's no fsck tool available, then only pass=0 makes sense.
if ! fstype_has_fsck "$fstype"; then
pass=0
fi
if [[ "$fsroot" != "/" && "$fstype" != "btrfs" ]]; then
# it's a bind mount
mapfile -t bind_srcs < <(findmnt -uncevo TARGET "$src")
for bind_src in "${bind_srcs[@]}"; do
if [[ -d "$bind_src$fsroot" ]]; then
src="$bind_src$fsroot"
break
fi
done
src="${src#"$root/"}"
[[ "$src" != '/'* ]] && src="/$src"
if [[ "$src" = "$target" ]]; then
# hrmm, this is weird. we're probably looking at a file or directory
# that was bound into a chroot from the host machine. Ignore it,
# because this won't actually be a valid mount. Worst case, the user
# just re-adds it.
continue
fi
fstype=none
opts+=',bind'
pass=0
fi
# filesystem quirks
case $fstype in
fuseblk)
# well-behaved FUSE filesystems will report themselves as fuse.$fstype.
# this is probably NTFS-3g, but let's just make sure.
if ! newtype="$(lsblk -no FSTYPE "$src")" || [[ -z $newtype ]]; then
# avoid blanking out fstype, leading to an invalid fstab
error 'Failed to derive real filesystem type for FUSE device on %s' "$target"
else
fstype="$newtype"
fi
;;
esac
optstring_apply_quirks opts "$fstype"
# write one line
write_source "$src"
printf '\t%-10s' "$(mangle "$target")" "$fstype" "$opts"
printf '\t%s %s' "$dump" "$pass"
printf '\n\n'
done
# handle swaps devices
{
# ignore header
read -r
while read -r device type _ _ prio; do
options=defaults
if (( prio >= 0 )); then
options+=",pri=$prio"
fi
# skip files marked deleted by the kernel
[[ "$device" = *'\040(deleted)' ]] && continue
if [[ "$type" = "file" ]]; then
printf '%-20s' "${device#"${root%/}"}"
elif [[ "$device" = "/dev/dm-"+([0-9]) ]]; then
# device mapper doesn't allow characters we need to worry
# about being mangled, and it does the escaping of dashes
# for us in sysfs.
write_source "$(dm_name_for_devnode "$device")"
else
write_source "$(unmangle "$device")"
fi
printf '\t%-10s\t%-10s\t%-10s\t0 0\n\n' none swap "$options"
done
} </proc/swaps
# vim: et ts=2 sw=2 ft=sh: