2012-06-18 03:17:10 +08:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
shopt -s extglob
|
|
|
|
|
2012-06-18 17:07:37 +08:00
|
|
|
m4_include(common)
|
2012-06-18 05:52:39 +08:00
|
|
|
|
2012-06-18 03:17:10 +08:00
|
|
|
write_source() {
|
2012-11-12 06:27:41 +08:00
|
|
|
local src=$1 spec= label= uuid= comment=()
|
2012-06-18 05:27:19 +08:00
|
|
|
|
2013-05-24 01:20:56 +08:00
|
|
|
label=$(lsblk -rno LABEL "$1" 2>/dev/null)
|
|
|
|
uuid=$(lsblk -rno UUID "$1" 2>/dev/null)
|
2012-06-18 03:17:10 +08:00
|
|
|
|
2012-11-24 12:35:28 +08:00
|
|
|
# bind mounts do not have a UUID!
|
2012-11-12 12:43:51 +08:00
|
|
|
|
2012-11-12 06:27:41 +08:00
|
|
|
case $bytag in
|
2012-11-12 12:43:51 +08:00
|
|
|
'')
|
|
|
|
[[ $uuid ]] && comment=("UUID=$uuid")
|
2013-12-09 01:59:23 +08:00
|
|
|
[[ $label ]] && comment+=("LABEL=$(mangle "$label")")
|
2012-11-12 12:43:51 +08:00
|
|
|
;;
|
2012-11-12 06:27:41 +08:00
|
|
|
LABEL)
|
|
|
|
spec=$label
|
2012-11-12 12:43:51 +08:00
|
|
|
[[ $uuid ]] && comment=("$src" "UUID=$uuid")
|
2012-11-12 06:27:41 +08:00
|
|
|
;;
|
|
|
|
UUID)
|
|
|
|
spec=$uuid
|
|
|
|
comment=("$src")
|
2013-12-09 01:59:23 +08:00
|
|
|
[[ $label ]] && comment+=("LABEL=$(mangle "$label")")
|
2012-11-12 06:27:41 +08:00
|
|
|
;;
|
|
|
|
*)
|
2012-11-12 12:43:51 +08:00
|
|
|
[[ $uuid ]] && comment=("$1" "UUID=$uuid")
|
2013-12-09 01:59:23 +08:00
|
|
|
[[ $label ]] && comment+=("LABEL=$(mangle "$label")")
|
2013-05-24 01:20:56 +08:00
|
|
|
[[ $bytag ]] && spec=$(lsblk -rno "$bytag" "$1" 2>/dev/null)
|
2012-11-12 06:27:41 +08:00
|
|
|
;;
|
|
|
|
esac
|
2012-06-18 03:17:10 +08:00
|
|
|
|
2012-06-18 04:35:42 +08:00
|
|
|
[[ $comment ]] && printf '# %s\n' "${comment[*]}"
|
2012-06-18 05:27:19 +08:00
|
|
|
|
2012-06-18 03:17:10 +08:00
|
|
|
if [[ $spec ]]; then
|
2013-12-09 01:59:23 +08:00
|
|
|
printf '%-20s' "$bytag=$(mangle "$spec")"
|
2012-06-18 03:17:10 +08:00
|
|
|
else
|
2012-07-23 08:11:54 +08:00
|
|
|
printf '%-20s' "$(mangle "$src")"
|
2012-06-18 03:17:10 +08:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2013-12-09 02:02:29 +08:00
|
|
|
optstring_apply_quirks() {
|
|
|
|
local varname=$1 fstype=$2
|
|
|
|
|
2014-12-27 01:04:05 +08:00
|
|
|
# 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
|
|
|
|
|
2017-06-29 20:18:03 +08:00
|
|
|
# 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 awk -v fstype="$fstype" '$1 == fstype { exit 1 }' /proc/filesystems; then
|
|
|
|
optstring_remove_option "$varname" relatime
|
|
|
|
fi
|
|
|
|
|
2013-12-09 02:02:29 +08:00
|
|
|
case $fstype in
|
|
|
|
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
|
|
|
|
;;
|
2013-12-09 11:38:22 +08:00
|
|
|
vfat)
|
|
|
|
# Before Linux v3.8, "cp" is prepended to the value of the codepage.
|
|
|
|
if optstring_get_option "$varname" codepage && [[ $codepage = cp* ]]; then
|
|
|
|
optstring_remove_option "$varname" codepage
|
|
|
|
optstring_append_option "$varname" "codepage=${codepage#cp}"
|
|
|
|
fi
|
|
|
|
;;
|
2013-12-09 02:02:29 +08:00
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2012-06-18 05:52:39 +08:00
|
|
|
usage() {
|
|
|
|
cat <<EOF
|
2012-10-10 00:06:48 +08:00
|
|
|
usage: ${0##*/} [options] root
|
2012-06-18 05:52:39 +08:00
|
|
|
|
|
|
|
Options:
|
2012-11-12 06:27:41 +08:00
|
|
|
-L Use labels for source identifiers (shortcut for -t LABEL)
|
2014-12-27 00:54:24 +08:00
|
|
|
-p Exclude pseudofs mounts (default behavior)
|
2017-06-29 20:18:03 +08:00
|
|
|
-P Include pseudofs mounts
|
2012-11-12 06:27:41 +08:00
|
|
|
-t TAG Use TAG for source identifiers
|
|
|
|
-U Use UUIDs for source identifiers (shortcut for -t UUID)
|
2012-06-18 05:52:39 +08:00
|
|
|
|
2012-11-13 10:00:09 +08:00
|
|
|
-h Print this help message
|
|
|
|
|
2012-07-15 22:04:49 +08:00
|
|
|
genfstab generates output suitable for addition to an fstab file based on the
|
|
|
|
devices mounted under the mountpoint specified by the given root.
|
|
|
|
|
2012-06-18 05:52:39 +08:00
|
|
|
EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
if [[ -z $1 || $1 = @(-h|--help) ]]; then
|
|
|
|
usage
|
|
|
|
exit $(( $# ? 0 : 1 ))
|
|
|
|
fi
|
|
|
|
|
2014-12-27 00:54:24 +08:00
|
|
|
while getopts ':LPpt:U' flag; do
|
2012-06-18 03:17:10 +08:00
|
|
|
case $flag in
|
|
|
|
L)
|
2012-11-12 06:27:41 +08:00
|
|
|
bytag=LABEL
|
2012-06-18 03:17:10 +08:00
|
|
|
;;
|
|
|
|
U)
|
2012-11-12 06:27:41 +08:00
|
|
|
bytag=UUID
|
2012-06-18 03:17:10 +08:00
|
|
|
;;
|
2014-12-27 00:54:24 +08:00
|
|
|
P)
|
|
|
|
pseudofs=1
|
|
|
|
;;
|
2012-06-18 21:34:29 +08:00
|
|
|
p)
|
2014-12-27 00:54:24 +08:00
|
|
|
pseudofs=0
|
2012-06-18 21:34:29 +08:00
|
|
|
;;
|
2012-11-12 06:27:41 +08:00
|
|
|
t)
|
2012-11-12 12:45:49 +08:00
|
|
|
bytag=${OPTARG^^}
|
2012-11-12 06:27:41 +08:00
|
|
|
;;
|
2012-06-18 22:05:40 +08:00
|
|
|
:)
|
|
|
|
die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG"
|
|
|
|
;;
|
2012-06-18 03:17:10 +08:00
|
|
|
?)
|
|
|
|
die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
shift $(( OPTIND - 1 ))
|
|
|
|
|
2012-07-15 22:04:49 +08:00
|
|
|
(( $# )) || die "No root directory specified"
|
2016-06-12 22:48:26 +08:00
|
|
|
root=$(realpath -mL "$1"); shift
|
2012-07-15 22:04:49 +08:00
|
|
|
|
|
|
|
if ! mountpoint -q "$root"; then
|
|
|
|
die "$root is not a mountpoint"
|
|
|
|
fi
|
|
|
|
|
2012-06-18 03:17:10 +08:00
|
|
|
# handle block devices
|
2012-10-02 23:00:21 +08:00
|
|
|
findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" |
|
|
|
|
while read -r src target fstype opts fsroot; do
|
2014-12-27 00:54:24 +08:00
|
|
|
if (( !pseudofs )) && fstype_is_pseudofs "$fstype"; then
|
2013-07-15 00:24:34 +08:00
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
2012-06-18 03:17:10 +08:00
|
|
|
# default 5th and 6th columns
|
|
|
|
dump=0 pass=2
|
|
|
|
|
2012-08-09 11:15:57 +08:00
|
|
|
src=$(unmangle "$src")
|
2012-06-18 21:25:43 +08:00
|
|
|
target=$(unmangle "$target")
|
2012-06-18 03:17:10 +08:00
|
|
|
target=${target#$root}
|
2012-11-15 08:32:23 +08:00
|
|
|
|
|
|
|
if (( !foundroot )) && findmnt "$src" "$root" >/dev/null; then
|
|
|
|
# this is root. we can't possibly have more than one...
|
|
|
|
pass=1 foundroot=1
|
2012-06-18 03:17:10 +08:00
|
|
|
fi
|
|
|
|
|
2013-05-26 23:21:58 +08:00
|
|
|
# if there's no fsck tool available, then only pass=0 makes sense.
|
|
|
|
if ! fstype_has_fsck "$fstype"; then
|
2012-06-18 03:17:10 +08:00
|
|
|
pass=0
|
|
|
|
fi
|
|
|
|
|
2012-10-02 23:00:21 +08:00
|
|
|
if [[ $fsroot != / ]]; then
|
2012-08-09 11:12:27 +08:00
|
|
|
if [[ $fstype = btrfs ]]; then
|
2012-11-15 08:37:34 +08:00
|
|
|
opts+=,subvol=${fsroot#/}
|
2012-08-09 11:12:27 +08:00
|
|
|
else
|
|
|
|
# it's a bind mount
|
2012-10-02 23:00:21 +08:00
|
|
|
src=$(findmnt -funcevo TARGET "$src")$fsroot
|
2012-10-04 10:46:39 +08:00
|
|
|
if [[ $src -ef $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
|
2012-12-10 03:05:41 +08:00
|
|
|
fstype=none
|
|
|
|
opts+=,bind
|
2012-08-09 11:12:27 +08:00
|
|
|
pass=0
|
|
|
|
fi
|
2012-06-18 10:53:46 +08:00
|
|
|
fi
|
|
|
|
|
2013-05-03 02:09:52 +08:00
|
|
|
# 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
|
|
|
|
|
2013-12-09 02:02:29 +08:00
|
|
|
optstring_apply_quirks "opts" "$fstype"
|
|
|
|
|
2012-06-18 03:17:10 +08:00
|
|
|
# write one line
|
2012-08-09 11:15:57 +08:00
|
|
|
write_source "$src"
|
2012-10-02 22:52:38 +08:00
|
|
|
printf '\t%-10s' "/$(mangle "${target#/}")" "$fstype" "$opts"
|
2012-06-18 03:17:10 +08:00
|
|
|
printf '\t%s %s' "$dump" "$pass"
|
|
|
|
printf '\n\n'
|
|
|
|
done
|
|
|
|
|
|
|
|
# handle swaps devices
|
|
|
|
{
|
|
|
|
# ignore header
|
|
|
|
read
|
|
|
|
|
2012-06-19 02:07:51 +08:00
|
|
|
while read -r device type _ _ prio; do
|
2012-06-18 03:17:10 +08:00
|
|
|
options=defaults
|
|
|
|
if [[ $prio != -1 ]]; then
|
|
|
|
options+=,pri=$prio
|
|
|
|
fi
|
|
|
|
|
2012-12-10 02:59:27 +08:00
|
|
|
# skip files marked deleted by the kernel
|
2013-12-09 11:35:40 +08:00
|
|
|
[[ $device = *'\040(deleted)' ]] && continue
|
2012-12-10 02:59:27 +08:00
|
|
|
|
2012-06-19 02:07:51 +08:00
|
|
|
if [[ $type = file ]]; then
|
|
|
|
printf '%-20s' "$device"
|
2012-11-12 05:57:35 +08:00
|
|
|
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")"
|
2012-06-19 02:07:51 +08:00
|
|
|
else
|
|
|
|
write_source "$(unmangle "$device")"
|
|
|
|
fi
|
2012-06-18 03:17:10 +08:00
|
|
|
|
2012-06-19 02:07:51 +08:00
|
|
|
printf '\t%-10s\t%-10s\t%-10s\t0 0\n\n' 'none' 'swap' "$options"
|
2012-06-18 03:17:10 +08:00
|
|
|
done
|
|
|
|
} </proc/swaps
|
|
|
|
|
2012-06-18 04:05:25 +08:00
|
|
|
# vim: et ts=2 sw=2 ft=sh:
|