From 590e715613a26398857d45525aa6fd3798feeeca Mon Sep 17 00:00:00 2001 From: pagedmov Date: Tue, 19 Nov 2024 16:28:32 -0500 Subject: [PATCH] added a new script 'mntstack' for easily handling storage volumes that require binding --- docs/scripts.md | 14 ++ modules/home/environment/userpkgs.nix | 1 + overlay/overlay.nix | 1 + overlay/scripts/misc/mntstack.nix | 199 ++++++++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 overlay/scripts/misc/mntstack.nix diff --git a/docs/scripts.md b/docs/scripts.md index 05e9b2c..84309f3 100644 --- a/docs/scripts.md +++ b/docs/scripts.md @@ -224,3 +224,17 @@ included in my nixpkgs overlay as custom packages, and these packages are declar - *Usage*: - `git commit -m "message" | color-commit` - *Defined in*: `overlay/scripts/misc/color-commit.nix` + +--- + +- **mntstack** + - *Description*: + - Keeps mounts in a stack and allows you to easily mount and then unmount volumes in the same order that they were mounted. Useful for quickly setting up and tearing down chroot environments. + - *Usage*: + - `mntstack push ` -Push an entry into the stack + - `mntstack push --bind ` -Use bind to mount directories + - `mntstack pop` -Unmounts and removes the most recently mounted volume + - `mntstack pop -c #` -Pops a given number of mounts + - `mntstack pop -a` -Pops the entire stack + - `mntstack list` -Shows the current stack, and the order which they will be popped in + - *Defined in*: `overlay/scripts/misc/mntstack.nix` diff --git a/modules/home/environment/userpkgs.nix b/modules/home/environment/userpkgs.nix index 0a2e8a5..567c396 100755 --- a/modules/home/environment/userpkgs.nix +++ b/modules/home/environment/userpkgs.nix @@ -23,6 +23,7 @@ let myScripts.git-compose myScripts.playshellsound myScripts.color-commit + myScripts.mntstack ]; in { options = { diff --git a/overlay/overlay.nix b/overlay/overlay.nix index 5e90924..e763da1 100644 --- a/overlay/overlay.nix +++ b/overlay/overlay.nix @@ -47,5 +47,6 @@ in s_check = super.callPackage ./scripts/wm-controls/s_check.nix {}; switchmon = super.callPackage ./scripts/wm-controls/switchmon.nix {}; color-commit = super.callPackage ./scripts/misc/color-commit.nix {}; + mntstack = super.callPackage ./scripts/misc/mntstack.nix {}; }; } diff --git a/overlay/scripts/misc/mntstack.nix b/overlay/scripts/misc/mntstack.nix new file mode 100644 index 0000000..8cdfa01 --- /dev/null +++ b/overlay/scripts/misc/mntstack.nix @@ -0,0 +1,199 @@ +{ pkgs }: + +pkgs.writeShellApplication { + name = "mntstack"; + runtimeInputs = []; + text = '' + set -e + + # File to store the stack + STACK_FILE="/tmp/mntstack.txt" + + validate_entry() { + local entry_dev entry_mntpoint test_mntpoint + IFS=' ' read -r entry_dev entry_mntpoint <<< "$1" + [ -n "$(findmnt -no SOURCE,TARGET "$entry_mntpoint" | cut -d' ' -f1-)" ] + } + + # Function to push a path onto the stack + push_path() { + local device="$1" + local mount_point="$2" + local bind_flag="$3" + + if [ ! -f "$STACK_FILE" ]; then + touch "$STACK_FILE" + fi + + # Validate the paths + if [[ ! -e "$device" || ! -d "$mount_point" ]]; then + echo "Error: Invalid device or mount point." + exit 1 + fi + + # Check if the device is a normal directory + if [[ -d "$device" && "$bind_flag" != "--bind" ]]; then + echo "Error: Cannot mount a normal directory without --bind flag." + exit 1 + fi + + # Check for duplicate entries + if grep -q "^$device $mount_point\$" "$STACK_FILE"; then + echo "Error: Duplicate entry detected." + exit 1 + fi + + # Mount the device to the mount point + if [[ "$bind_flag" == "--bind" ]]; then + sudo mount --bind "$device" "$mount_point" + else + sudo mount "$device" "$mount_point" + fi + + # Append the path to the stack file + echo "$device $mount_point" >> "$STACK_FILE" + echo "Pushed and mounted: $device $mount_point" + } + + # Function to pop a path from the stack + pop_path() { + + + if [[ ! -f "$STACK_FILE" || ''${#stack[@]} -eq 0 ]]; then + echo "Warning: Stack is empty. Nothing to pop." + exit 0 + fi + + mapfile -t stack < "$STACK_FILE" + + # Get the last entry + last_path="${stack[-1]}" + if ! validate_entry "$last_path"; then + echo "Warning: Invalid stack entry '${stack[-1]}'" + sed -i '$d' "$STACK_FILE" + return 0 + fi + + IFS=' ' read -r device mount_point <<< "$last_path" + + # Unmount the device + sudo umount "$mount_point" + sed -i '$d' "$STACK_FILE" + + echo "Popped and unmounted: $device" + } + + # Function to list the current stack + list_stack() { + # Check if the stack file exists + if [[ ! -f "$STACK_FILE" ]]; then + echo "Stack is empty." + exit 0 + fi + + # Read the stack file into an array + mapfile -t stack < "$STACK_FILE" + + # Check if the stack is empty + if [[ ''${#stack[@]} -eq 0 ]]; then + echo "Stack is empty." + exit 0 + fi + + # Display the stack elements + for ((i=0; i<''${#stack[@]}; i++)); do + IFS=' ' read -r device mount_point <<< "''${stack[i]}" + echo "$((i+1)). $mount_point -> $device" + done + } + + pop_num=1 + all=false + bind=false + pos_args=() + + # Early check for help + if [[ "$1" == "help" ]]; then + echo "Usage: $0 {push|pop|list} [--bind] [ ]" + echo "Flags:" + echo "pop -c,--count: specify a number of mounts to pop" + echo "pop -a,--all: pop the entire stack" + echo "push -b,--bind: use --bind when mounting" + exit 0 + fi + + # Process flags + while [[ $# -gt 0 ]]; do + case "$1" in + -a|--all) + all=true + shift + ;; + -c|--count) + if [[ "$2" =~ ^-?[0-9]+$ ]]; then + pop_num="$2" + shift 2 + else + echo "Invalid count: please give an integer like -c 5" + exit 1 + fi + ;; + -b|--bind) + bind=true + shift + ;; + *) + pos_args+=("$1") + shift + ;; + esac + done + + # Main command processing + case "''${pos_args[0]}" in + push) + if [[ ''${#pos_args[@]} -lt 3 || ''${#pos_args[@]} -gt 4 ]]; then + echo "Usage: $0 push [--bind] " + exit 1 + fi + push_path "''${pos_args[1]}" "''${pos_args[2]}" "$([[ $bind == true ]] && echo "--bind")" + ;; + pop) + if [[ ''${#pos_args[@]} -ne 1 ]]; then + echo "Usage: $0 pop" + exit 1 + fi + if [[ ! -f "$STACK_FILE" ]]; then + echo "Stack file does not exist. Nothing to pop." + fi + if [[ $all == false ]]; then + mapfile -t stack < "$STACK_FILE" + while [[ $pop_num -gt 0 ]]; do + pop_path || break + mapfile -t stack < "$STACK_FILE" + ((pop_num--)) + done + else + mapfile -t stack < "$STACK_FILE" + while [[ ''${#stack[@]} -gt 0 ]]; do + if ! pop_path; then + break + fi + mapfile -t stack < "$STACK_FILE" + done + fi + ;; + list) + if [[ ''${#pos_args[@]} -ne 1 ]]; then + echo "Usage: $0 list" + exit 1 + fi + list_stack + ;; + *) + echo "Usage: $0 {push|pop|list} [--bind] [ ]" + exit 1 + ;; + esac + ''; +}