如何为我正在安装的安装点自动安装先决条件安装点?

如何为我正在安装的安装点自动安装先决条件安装点?

我正在运行 Arch Linux 和 systemd。

/etc/fstab我有这样的东西:

LABEL=XYZ       /mypath       vfat    noauto,[...]
/mypath/main    /newplace     none    bind,noauto    0 0

我目前必须/newplace使用两个命令进行安装:

mount /mypath
mount /newplace

我也必须umount两者兼而有之。

我需要将其简化为一个mount(或umount)命令:

mount /newplace

由于现有脚本,我需要使用上面显示的确切mount(和相关)命令。umount澄清:

单个命令mount /newplace应首先 mount /mypath,然后 mount/newplace/mypath应保持挂载状态。

该命令umount /newplace应该先 umount/newplace然后卸载/mypath

我可以更改/etc/fstab我的设备的一些其他详细信息。但我无法更改调用的脚本mount /newplace。我也无法自动挂载,/newplace因为除非运行脚本,否则它通常需要保持卸载状态。

我一直在阅读有关递归绑定挂载、共享、私有、从属和其他挂载选项的信息,但我还没有找到实现我所寻求的目标的方法。

更新:为了回应评论,这显然不是递归挂载,所以我将其称为“先决条件”挂载。我希望这个词是合适的。我想到了“反向递归安装”这个术语,但这看起来很糟糕。我认为“先决条件”是指必须先发生的事情,并且为必要条件提供持续的基础。一般来说,在继续执行必要条件的同时,不能忘记或删除该先决条件。

在这种情况下,/mypath(prevention) 和/newplace(Required) 在安装时都保持安装状态/newplace,并且在调用 时它们都将被卸载(当然可能以相反的顺序)umount /newplace

理想的解决方案将使用 systemd、Python 3 或 Xonsh。 (Bash 脚本也是可以接受的。我没有安装 zsh 或其他 shell。)

答案1

如果您确实希望将 FS 的“主”子目录LABEL=XYZ挂载在 上/newplace,而不特别需要将整个 FS 挂载在 上/mypath,则可以添加如下行:

LABEL=XYZ /newplace subdir subdir=main,srctype=vfat,noauto,... 0 0

并创建/sbin/mount.subdir助手(由 调用mount /newplace,并不意味着直接调用)作为脚本,如下所示:

#! /bin/zsh -p
(( EUID == 0 )) || exec sudo -- "$0" "$@"
PATH=/bin:/sbin:/usr/bin:/usr/sbin

# mount -t subdir -o subdir=foo -o otheroption source /dest calls us
# as mount.subdir source /dest -o rw,subdir=foo,otheroption
dev=${1?} dest=${2?} opts=( ${(s[,])4?} )

# extract mandatory subdir option
(( i = $opts[(I)subdir=*] )) || exit
subdir=${opts[i]#*=}
opts[i]=()

# extract optional srctype option
if (( i = $opts[(I)srctype=*] )); then
  type=(-t "$opts[i]")
  opts[i]=()
else
  type=()
fi

tmpdir=$(mktemp -d) || exit

mounted()true
if
  mount "$type[@]" -o "${(j[,])opts}" -- "$dev" "$tmpdir"
then
  mount --bind -- "$tmpdir/$subdir" "$dest" || mounted()false
  umount -- "$tmpdir"
fi && rmdir -- "$tmpdir" && mounted

它将整个 FS 挂载到 tmpdir 中,将子目录绑定挂载到目标位置,然后卸载并删除 tmpdir。


如果,正如您稍后的编辑中所阐明的,您确实希望安装/newplace和,而不仅仅是为了在 中安装 FS 子目录的最终目标的一些中间步骤,您可以采取类似的方法,并且这会变得更容易,因为你只需要帮助程序来安装必备的文件系统:/mypath/mypath/myplace

LABEL=XYZ /mypath vfat noauto,[...]
/myplace/main /newplace prereq prereq=/myplace,noauto,... 0 0

并将/sbin/mount.prereq助手创建为脚本,如下所示:

#! /bin/zsh -p
(( EUID == 0 )) || exec sudo -- "$0" "$@"
PATH=/bin:/sbin:/usr/bin:/usr/sbin

src=${1?} dst=${2?} opts=( ${(s[,])4?} )

# extract prereq options
for prereq in ${(M)opts:#prereq=*}; do
  prereq=${prereq#*=}
  mountpoint -q -- $prereq ||
    mount -- $prereq ||
    exit
done
opts=(${opts:#prereq=*})

exec mount --bind -o "${(j[,])opts}" -- "$src" "$dst"

注意卸载/mypath后不会自动卸载。/newplace

与 POSIX shell 语法相同(因此甚至应该在 中工作bash)可能如下所示:

#! /bin/sh -
[ "$(id -u)" -eq 0 ] || exec sudo -- "$0" "$@"
PATH=/bin:/sbin:/usr/bin:/usr/sbin

src="${1?}" dst="${2?}"

set -o noglob
IFS=,
set -- ${4?}

# extract prereq options
for opt do
  case $opt in
    (prereq=*)
      prereq=${opt#*=}
      mountpoint -q -- "$prereq" ||
        mount -- "$prereq" ||
        exit
      ;;
    (*)
      set -- "$@" "$opt"
  esac
  shift
done
opts="$*"

exec mount --bind -o "$opts" -- "$src" "$dst"

(未经测试)。

如果你不能编辑您的脚本,您可以对其进行检测。例如,如果它写成bash,则将其称为:

bash -c '
  mount() {
    if [[ $1 = "/newplace" ]]; then
      command mount /mypath || return
    fi
    command mount "$@"
  }
  export -f mount
  exec "$0" "$@"' your-script its args

或者,如果它是用 编写的zsh,则添加到~/.zshenv(或为该脚本/some/dir/.zshenv设置):ZDOTDIR=/some/dir

if [[ $ZSH_SCRIPT:P = /path/to/your-script ]]; then
  mount() {
    if [[ $1 = /newplace ]]; then
      command mount /mypath || return
    fi
    command mount "$@"
  }
fi

或者对于任何 shell,添加一个执行相同操作的mount脚本:/some/dir

#! /bin/sh -
if [ "$1" = /newplace ]; then
  /bin/mount /mypath || exit
fi
exec /bin/mount "$@"

并将您的脚本称为:

PATH="/some/dir:$PATH" your-script its args

相关内容