From c59ecbba02dfa4f4a5cdbe0d30035f956eb7671e Mon Sep 17 00:00:00 2001 From: Niklas Gollenstede Date: Mon, 31 Jul 2023 02:47:24 +0200 Subject: [PATCH] have new mount points be owned by their parent's owner --- lib/setup-scripts/disk.sh | 9 ++++----- lib/setup-scripts/utils.sh | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/setup-scripts/disk.sh b/lib/setup-scripts/disk.sh index 300463d..9566704 100644 --- a/lib/setup-scripts/disk.sh +++ b/lib/setup-scripts/disk.sh @@ -215,7 +215,6 @@ function fix-grub-install { fi } - ## Mounts all file systems as it would happen during boot, but at path prefix »$mnt« (instead of »/«). function mount-system {( # 1: mnt, 2?: fstabPath, 3?: allowFail # While not generally required for fstab, nixos uses the dependency-sorted »config.system.build.fileSystems« list (instead of plain »builtins.attrValues config.fileSystems«) to generate »/etc/fstab« (provided »config.fileSystems.*.depends« is set correctly, e.g. for overlay mounts). @@ -230,19 +229,19 @@ function mount-system {( # 1: mnt, 2?: fstabPath, 3?: allowFail options=,$options, ; options=${options//,ro,/,} if ! @{native.util-linux}/bin/mountpoint -q "$mnt"/"$target" ; then ( - mkdir -p "$mnt"/"$target" || exit + mkdir-sticky "$mnt"/"$target" || exit [[ $type == tmpfs || $type == auto || $type == */* ]] || @{native.kmod}/bin/modprobe --quiet $type || true # (this does help sometimes) if [[ $type == overlay ]] ; then options=${options//,workdir=/,workdir=$mnt\/} ; options=${options//,upperdir=/,upperdir=$mnt\/} # Work and upper dirs must be in target. - workdir=$( <<<"$options" grep -o -P ',workdir=\K[^,]+' || true ) ; if [[ $workdir ]] ; then mkdir -p "$workdir" ; fi - upperdir=$( <<<"$options" grep -o -P ',upperdir=\K[^,]+' || true ) ; if [[ $upperdir ]] ; then mkdir -p "$upperdir" ; fi + workdir=$( <<<"$options" grep -o -P ',workdir=\K[^,]+' || true ) ; if [[ $workdir ]] ; then mkdir-sticky "$workdir" ; fi + upperdir=$( <<<"$options" grep -o -P ',upperdir=\K[^,]+' || true ) ; if [[ $upperdir ]] ; then mkdir-sticky "$upperdir" ; fi lowerdir=$( <<<"$options" grep -o -P ',lowerdir=\K[^,]+' || true ) options=${options//,lowerdir=$lowerdir,/,lowerdir=$mnt/${lowerdir//:/:$mnt\/},} ; source=overlay # TODO: test the lowerdir stuff elif [[ $options =~ ,r?bind, ]] ; then if [[ $source == /nix/store/* ]] ; then options=,ro$options ; fi - source=$mnt/$source ; if [[ ! -e $source ]] ; then mkdir -p "$source" || exit ; fi + source=$mnt/$source ; if [[ ! -e $source ]] ; then mkdir-sticky "$source" || exit ; fi fi @{native.util-linux}/bin/mount -t $type -o "${options:1:(-1)}" "$source" "$mnt"/"$target" || exit diff --git a/lib/setup-scripts/utils.sh b/lib/setup-scripts/utils.sh index 7a946f5..a71196d 100644 --- a/lib/setup-scripts/utils.sh +++ b/lib/setup-scripts/utils.sh @@ -74,6 +74,24 @@ function copy-function { # 1: existingName, 2: newName eval "${original/$1/${2?newName not provided}}" # run the code declaring the function again, replacing only the first occurrence of the name } +## Ensures that a directory exists, like »mkdir -p«, but for any new path elements created, copies the user/group/mode of the closest existing parent. +# Only uses the fallback user/group/mode when the closest existing parent is already a sticky dir (whose (root-)ownership does not mean much, as it is meant for children owned by any/other user(s), like /tmp). +function mkdir-sticky { # 1: path, 2?: fallbackOwner, 3?: fallbackGroup, 4?: fallbackMode + local path ; path=$1 ; shift + if [[ -d $path ]] ; then return ; fi # existing (symlink to existing) dir + if [[ -L $path || -e $path ]] ; then echo "Can't create (child of) existing file (or broken symlink) '$path'" 1>&2 ; return 1 ; fi + local parent ; parent=$( dirname "$path" ) || return + mkdir-sticky "$parent" "$@" || return + parent=$( realpath "$parent" ) || return + stat=( $( stat --format '%u %g %a' "$parent" ) ) || return + if [[ ${stat[2]} =~ ^1...$ ]] ; then # sticky parent + #echo "Can't infer correct ownership/permissions for child '$( basename "$path" )' of sticky dir '$parent'" 1>&2 ; return 1 + install --directory --owner="${1:-0}" --group="${2:-0}" ${3+--mode="$3"} "$path" || return + else + install --directory --owner=${stat[0]} --group=${stat[1]} --mode=${stat[2]} "$path" || return + fi +} + ## Writes a »$name«d secret from stdin to »$targetDir«, ensuring proper file permissions. function write-secret {( set -u # 1: path, 2?: owner[:[group]], 3?: mode mkdir -p -- "$(dirname "$1")"/ || exit @@ -136,7 +154,7 @@ function build-lazy { # 1: drvPath, 2?: output } ## Tests whether (returns 0/success if) the first version argument is greater/less than (or equal) the second version argument. -function version-gr-eq { printf '%s\n%s' "$1" "$2" | sort -C -V -r; } +function version-gr-eq { printf '%s\n%s' "$1" "$2" | sort -C -V -r ; } function version-lt-eq { printf '%s\n%s' "$1" "$2" | sort -C -V ; } function version-gt { ! version-gt-eq "$2" "$1" ; } function version-lt { ! version-lt-eq "$2" "$1" ; }