impermanence/create-directories.bash
talyz b4160ba71d
nixos: Rewrite directory creation for saner default permissions
Construct directory items for all parent directories of the user
specified files and directories, assigning better default permissions
and ownership to each and removing this responsibility from the
create-directories script.

This means that all parent directories of root directories will now
have the default permissions and ownership, not inherit them from the
child. User directories are assigned default user ownership. The home
directory itself is handled specially to make sure it is owned by the
user, not readable by anyone else and its parent gets default root
ownership.

To illustrate this with an example, here is a directory specification
and the ownership and permissions that could potentially be assigned
to the parent directories, given none of them yet exist in persistent
storage:

environment.persistence."/persistent" = {
  users.talyz = {
    directories = [
      { directory = ".local/share/secret"; mode = "0500"; }
    ];
  };
};

Before:
/home                            talyz:talyz   0500
/home/talyz                      talyz:talyz   0500
/home/talyz/.local               talyz:talyz   0500
/home/talyz/.local/share         talyz:talyz   0500
/home/talyz/.local/share/secret  talyz:talyz   0500

After:
/home                            root:root     0755
/home/talyz                      talyz:talyz   0700
/home/talyz/.local               talyz:talyz   0755
/home/talyz/.local/share         talyz:talyz   0755
/home/talyz/.local/share/secret  talyz:talyz   0500
2023-04-23 08:16:07 +02:00

63 lines
2.4 KiB
Bash
Executable file

#!/usr/bin/env bash
set -o nounset # Fail on use of unset variable.
set -o errexit # Exit on command failure.
set -o pipefail # Exit on failure of any command in a pipeline.
set -o errtrace # Trap errors in functions and subshells.
set -o noglob # Disable filename expansion (globbing),
# since it could otherwise happen during
# path splitting.
shopt -s inherit_errexit # Inherit the errexit option status in subshells.
# Print a useful trace when an error occurs
trap 'echo Error when executing ${BASH_COMMAND} at line ${LINENO}! >&2' ERR
# Given a source directory, /source, and a target directory,
# /target/foo/bar/bazz, we want to "clone" the target structure
# from source into the target. Essentially, we want both
# /source/target/foo/bar/bazz and /target/foo/bar/bazz to exist
# on the filesystem. More concretely, we'd like to map
# /state/etc/ssh/example.key to /etc/ssh/example.key
#
# To achieve this, we split the target's path into parts -- target, foo,
# bar, bazz -- and iterate over them while accumulating the path
# (/target/, /target/foo/, /target/foo/bar, and so on); then, for each of
# these increasingly qualified paths we:
# 1. Ensure both /source/qualifiedPath and qualifiedPath exist
# 2. Copy the ownership of the source path to the target path
# 3. Copy the mode of the source path to the target path
# Get inputs from command line arguments
if [[ "$#" != 6 ]]; then
printf "Error: 'create-directories.bash' requires *six* args.\n" >&2
exit 1
fi
sourceBase="$1"
target="$2"
user="$3"
group="$4"
mode="$5"
debug="$6"
if (( "$debug" )); then
set -o xtrace
fi
# trim trailing slashes the root of all evil
sourceBase="${sourceBase%/}"
target="${target%/}"
# check that the source exists and warn the user if it doesn't, then
# create them with the specified permissions
realSource="$(realpath -m "$sourceBase$target")"
if [[ ! -d "$realSource" ]]; then
printf "Warning: Source directory '%s' does not exist; it will be created for you with the following permissions: owner: '%s:%s', mode: '%s'.\n" "$realSource" "$user" "$group" "$mode"
mkdir --mode="$mode" "$realSource"
chown "$user:$group" "$realSource"
fi
[[ -d "$target" ]] || mkdir "$target"
# synchronize perms between source and target
chown --reference="$realSource" "$target"
chmod --reference="$realSource" "$target"