From 0e14a1a13b5070a030d982aad8d3d64b44aea20c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Thu, 26 Jan 2023 01:46:08 +0800 Subject: [PATCH] genfstab,common: use named reference instead of globals --- common | 132 +++++++++++++++++++++++++++++----------------------- genfstab.in | 14 +++--- 2 files changed, 82 insertions(+), 64 deletions(-) diff --git a/common b/common index c85e7f3..b640415 100644 --- a/common +++ b/common @@ -89,10 +89,12 @@ ignore_error() { in_array() { local i + local -n _arr="$1" - for i in "${@:2}"; do - [[ "$1" = "$i" ]] && return 0 + for i in "${_arr[@]}"; do + [[ "$i" = "$1" ]] && return 0 done + return 1 } @@ -349,83 +351,99 @@ unmangle() { printf '%s' "$out${1:i}" } -optstring_match_option() { - local candidate pat patterns +optstring_match_one_option() { + local options=() target="$2" + local -n _optstring_match="$1" - IFS=, read -ra patterns <<<"$1" - for pat in "${patterns[@]}"; do - if [[ $pat = *'='* ]]; then - # "key=val" will only ever match "key=val" - candidate="$2" - else - # "key" will match "key", but also "key=anyval" - candidate="${2%%=*}" - fi + IFS=, read -ra options <<<"$_optstring_match" + if [[ "$target" != *'='* ]]; then + options=("${options[@]%%=*}") + fi - [[ "$pat" = "$candidate" ]] && return 0 - done - - return 1 + in_array options "$target" } -optstring_remove_option() { - local o _options remove="$2" +optstring_get_options() { + local i options=() + local -n _ret="$1" _optstring_get="$2" + local -i got=0 - IFS=, read -ra _options <<<"${!1}" - for o in "${!_options[@]}"; do - optstring_match_option "$remove" "${_options[o]}" && unset '_options[o]' + IFS=, read -ra options <<<"$_optstring_get" + + shift 2 + for i in "${!options[@]}"; do + if optstring_match_one_option 'options[i]' "$1"; then + _ret+=(["${options[i]%%=*}"]="${options[i]//*=}") + got=1 + fi + shift || break done - declare -g "$1=${_options[*]}" + (( got )) +} + +optstring_from_array() { + local optstring + local -n _optarray="$1" + + optstring="$(printf ',%s' "${_optarray[@]}")" + optstring="${optstring:1}" # Remove the leading comma + + printf '%s' "$optstring" } optstring_normalize() { - local o _options norm + local i options=() + local -n _optstring_norm="$1" + + IFS=, read -ra options <<<"$_optstring_norm" - IFS=, read -ra _options <<<"${!1}" # remove empty fields - for o in "${_options[@]}"; do - [[ $o ]] && norm+=("$o") + for i in "${!options[@]}"; do + [[ ${options[i]} ]] || unset 'options[i]' done # avoid empty strings, reset to "defaults" - declare -g "$1=${norm[*]:-defaults}" -} - -optstring_has_option() { - local o="${2%%=*}" - - optstring_get_option "$1" "$o" -} - -optstring_append_option() { - if ! optstring_has_option "$1" "$2"; then - declare -g "$1=${!1},$2" + if (( ! ${#options[@]} )); then + _optstring_norm="defaults" + else + _optstring_norm="$(optstring_from_array options)" fi - - optstring_normalize "$1" } -optstring_prepend_option() { - if ! optstring_has_option "$1" "$2"; then - declare -g "$1=$2,${!1}" - fi +optstring_remove_options() { + local i options=() target="$2" + local -n _optstring_remove="$1" - optstring_normalize "$1" -} + IFS=, read -ra options <<<"$_optstring_remove" -optstring_get_option() { - local _opts o - - IFS=, read -ra _opts <<<"${!1}" - for o in "${_opts[@]}"; do - if optstring_match_option "$2" "$o"; then - declare -g "$o" - return 0 - fi + for i in "${!options[@]}"; do + optstring_match_one_option 'options[i]' "$target" && unset 'options[i]' done - return 1 + _optstring_remove="$(optstring_from_array options)" +} + +optstring_append_one_option() { + local option="$2" + local -n _optstring_append="$1" + + if ! optstring_match_one_option _optstring_append "$option"; then + _optstring_append+=",$option" + fi + + optstring_normalize _optstring_append +} + +optstring_prepend_one_option() { + local option="$2" + local -n _optstring_prepend="$1" + + if ! optstring_match_one_option _optstring_prepend "$option"; then + _optstring_prepend="$option,$_optstring_prepend" + fi + + optstring_normalize _optstring_prepend } dm_name_for_devnode() { diff --git a/genfstab.in b/genfstab.in index 85f324d..a5d5848 100644 --- a/genfstab.in +++ b/genfstab.in @@ -1,5 +1,4 @@ #!/bin/bash -# shellcheck disable=SC2154 # optstring_*_option may export variables in runtime shopt -s extglob @@ -43,18 +42,19 @@ write_source() { } optstring_apply_quirks() { - local varname="$1" fstype="$2" + local fstype="$2" + local -n _optstring="$1" # 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 + optstring_remove_options _optstring 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 + optstring_remove_options _optstring relatime fi case $fstype in @@ -62,15 +62,15 @@ optstring_apply_quirks() { # 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 + if optstring_match_one_option _optstring subvol; then + optstring_remove_options _optstring 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 + optstring_remove_options _optstring noacl,acl,nouser_xattr,user_xattr ;; esac }