Compare commits

...

6 commits

Author SHA1 Message Date
74ed7582f9 Small cosmetical changes 2026-03-15 19:11:37 +01:00
10d81b7e5b Added cdz check parameter for use in multicd (normal cd, squash cd and cdz).
Consolidated all squash functionality into a binary (squasher)
Updated the 'cd' alias (multicd).
Added -e to ldrc (to edit the user scripts)
2026-03-15 18:52:13 +01:00
83324dd0f7 After gemini-propoesed fixes 2026-03-13 01:38:34 +01:00
2e31283b61 Pre-refactor 2026-03-13 00:37:28 +01:00
84f55f82b8 Merge branch 'master' of https://git.lea.engineering/natrox/lackadaisical 2026-03-08 21:02:48 +01:00
eb0aab1613 Latest version 2026-03-08 20:54:07 +01:00
11 changed files with 426 additions and 238 deletions

View file

@ -36,8 +36,6 @@ lackadaisical` if you so desire.
To read this notice again, call the function 'daisy_help'. To read this notice again, call the function 'daisy_help'.
=============================================================================== ===============================================================================
These are the included binaries and utilities: These are the included binaries and utilities:
- calm:
Reduce a process 'niceness' to 0.
- cdz: - cdz:
This utility extracts an archive to /tmp and changes This utility extracts an archive to /tmp and changes
directory to it in a new shell instance. Upon exit, directory to it in a new shell instance. Upon exit,
@ -47,6 +45,27 @@ These are the included binaries and utilities:
NO_ARCHIVEMOUNT=1. The standard script supports zip, NO_ARCHIVEMOUNT=1. The standard script supports zip,
tarballs, and rar archives. We recommend relying on tarballs, and rar archives. We recommend relying on
archivemount` if you have it installed. archivemount` if you have it installed.
Use "--check" to only check if a file is an archive.
It returns 0 if it is, 1 otherwise.
- squasher:
These convenient set of tools allow you to easily create
XZ-compressed SquashFS images from existing folders to save
disk space. The resulting folder is still writable since it is
mounted using an 'overlay' system. You can use 'squasher make'
to compresses an existing folder. These folders are automatically
mounted when you use 'cd' to navigate to them (via an alias).
When using 'make-squash-image' on an already mounted folder, it will
instead update the existing image. As of writing, we do not have a
SystemD service to auto-mount, however, you cam easily add auto-mount
as a cron job. Here is a list of tools, they all take the same
folder argument:
> squasher make: Converts the folder into a hidden image
on the same disk as the folder.
> squasher mount: Sets up a mount for the XZ image alongside
directories for changes
> squasher umount: Self-explanatory.
> squasher destroy: Extracts the image and essentially reverts
everything. File changes are kept, however.
- editx: - editx:
Uses your standard CLI editor to create/modify a Uses your standard CLI editor to create/modify a
file and make it executable. file and make it executable.
@ -64,7 +83,7 @@ These are the included binaries and utilities:
Format is <dir> -> .daisy/<dir>/<year>/<month>/<day>. Format is <dir> -> .daisy/<dir>/<year>/<month>/<day>.
Recommended to run via crontab - automatically cleans Recommended to run via crontab - automatically cleans
up empty folders. up empty folders.
A symlink to the base of the folder's tree, ".tree", A symbolic link to the base of the folder's tree, ".tree",
is created in the root of the specified directly. is created in the root of the specified directly.
Can be used for everything you'd like to sort by date. Can be used for everything you'd like to sort by date.
For example; a diary, browser downloads, backups, code. For example; a diary, browser downloads, backups, code.
@ -92,11 +111,11 @@ These are the included binaries and utilities:
This is a tool similar to which and others, the key This is a tool similar to which and others, the key
difference is that it returns partial matches. It can difference is that it returns partial matches. It can
be used to search for binaries. be used to search for binaries.
- binbox: - scripbox:
This tool can be used to pack bash scripts into one This tool can be used to pack bash scripts into one
big megascript, much like how `busybox` works. big megascript, much like how `busybox` works.
You can also make symlinks to it to invoke a specific You can also make symlinks to it to invoke a specific
script (as of writing, 11/25, symlinks do not work well). script.
- bak/unbak: - bak/unbak:
These small utilities make backups of files by making These small utilities make backups of files by making
a copy with a .bak suffix. Unbak reverses the process a copy with a .bak suffix. Unbak reverses the process
@ -137,6 +156,8 @@ These are the included binaries and utilities:
The variable is stored locally in the shell as "LD_CLIP". The variable is stored locally in the shell as "LD_CLIP".
- ldrc: - ldrc:
Edits daisy.source and re-sources it, similarly to shrc. Edits daisy.source and re-sources it, similarly to shrc.
Append "-e" to edit "extra.src", to add custom functions in the
lackadaisical namespace.
- daisy_reload: - daisy_reload:
Re-sources daisy.source. Essentially `ldrc` without Re-sources daisy.source. Essentially `ldrc` without
editing. editing.

12
agenda
View file

@ -28,10 +28,7 @@ root_dir=$(dirname $1)/.daisy/$(basename $1)
today_sym=$1 today_sym=$1
# Present day # Present day
today=$(date -I) read year month day < <(date "+%Y %m %d")
year=$(echo $today | awk -F"-" '{print $1}')
month=$(echo $today | awk -F"-" '{print $2}')
day=$(echo $today | awk -F"-" '{print $3}')
set -e set -e
@ -50,11 +47,10 @@ function errorFn
trap errorFn ERR trap errorFn ERR
# First we clear out empty folders, and remove the symlink if it exists # First we clear out empty folders, and remove the symlink if it exists
test -e "$root_dir" && find "$root_dir" -maxdepth 3 -type d -empty -print | xargs rm -rf test -e "$root_dir" && find "$root_dir" -maxdepth 3 -type d -empty -delete
test -L "$today_sym" && rm -rf "$today_sym"
# Now we can set up today's directory # Now we can set up today's directory
mkdir -p "$root_dir/$year/$month/$day" mkdir -p "$root_dir/$year/$month/$day"
ln -s "$root_dir/$year/$month/$day" "$today_sym" ln -sf "$root_dir/$year/$month/$day" "$today_sym"
ln -s "$root_dir" "$today_sym/.tree" ln -s "$root_dir" "$today_sym/.tree"
exitcode=@? exitcode=$?

41
calm
View file

@ -1,41 +0,0 @@
#!/usr/bin/env bash
# Calm a process down
# NEEDS_WORK: cleanup
# calm <pid> == only one process
# calm <bin> == all processes that match query
# calm * == if used in proc or a folder with just PID files, if not you will get an error
# calm <pid> <bin> .... OK
# set's NICE value to 0
# need sudo
LD_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source
pids=$@
errorFn()
{
echo calm: Invalid operation or no such PID/process \(\"$(echo "$pids" | tr '\n' ' ' | cut -c -20)...\"\)
exit
}
for pid in $pids
do
# Process to PID in elegant way
newpids=$(pidof "$pid")
if [ "$newpids" ]
then
binary=$pid
pid=$newpids
else
newbins=$pid
binary=$(ps -p "$pid" -o comm= 2>/dev/null )
if [ $? != 0 ]
then
errorFn
fi
fi
echo Calming down $pid \("$binary"\)...
sudo renice -n 0 -p $pid;
done

187
cdz
View file

@ -1,118 +1,151 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Usage: cdz [--check] <archive>
if [[ $LD_INTERNAL -ne 1 ]]; if [[ $LD_INTERNAL -ne 1 ]]
then then
LD_INTERNAL=1 LD_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source . $(dirname $(realpath $0))/daisy.source
fi fi
target=$1 is_archive()
{
local file="$1"
local mime_type=$(file --mime-type -b "$file")
# Check if file exists if [[ $mime_type == *"tar"* || $file == *.tar* || $mime_type == "application/zip" || $mime_type == "application/x-rar" ]]
if [[ -z "$target" ]]; then
return 0
fi
if command -v archivemount >/dev/null 2>&1
then
local test_dir=$(mktemp -d /tmp/cdz_check.XXXXXXXX)
local result=1
if archivemount -o readonly "$file" "$test_dir" >/dev/null 2>&1
then
result=0
umount "$test_dir"
fi
rmdir "$test_dir"
return $result
fi
return 1
}
check_mode=0
if [[ "$1" == "--check" ]]
then then
check_mode=1
shift
fi
target=$1
if [[ -z "$target" ]]
then
if [[ $check_mode -eq 0 ]]
then
echo "No target specified." echo "No target specified."
fi
exit 1 exit 1
fi fi
if ! test -f "$target"; if [[ ! -f "$target" ]]
then then
if [[ $check_mode -eq 0 ]]
then
echo "File not found: \"$target\"" echo "File not found: \"$target\""
fi
exit 2 exit 2
fi fi
# Check if archivemount is present target_abs=$(realpath "$target")
which archivemount 1>/dev/null 2>/dev/null name=$(basename "$target")
hasmounter=$?
file "$target" 1>/dev/null if is_archive "$target_abs"
exitcode=$? then
report=$(file "$target") if [[ $check_mode -eq 1 ]]
name=$(echo $@ | sed 's/:.*//' | sed 's|.*/||') then
exit 0
fi
else
if [[ $check_mode -eq 1 ]]
then
exit 1
fi
mime_type=$(file --mime-type -b "$target_abs")
echo "Unsupported archive type: $mime_type"
exit 1
fi
# Check for archive type, supported types are zip/tar/rar # Proceed with extraction
has_archivemount=$(command -v archivemount >/dev/null 2>&1; echo $?)
if [[ $has_archivemount -eq 0 && $NO_ARCHIVEMOUNT -ne 1 ]]
then
use_mounter=1
else
use_mounter=0
fi
mime_type=$(file --mime-type -b "$target_abs")
comm1=(:) comm1=(:)
comm2=(echo "Unsupported archive type$add: \"$target\"") comm2=(echo "Unsupported archive type: $mime_type")
comm3=(:) comm3=(:)
comm4=(:) comm4=(:)
comm5=(:) comm5=(:)
echo $report | grep "tar archive" 1>/dev/null if [[ $use_mounter -eq 1 ]]
istar=$?
echo $report | grep "Zip archive" 1>/dev/null
iszip=$?
echo $report | grep "Android" 1>/dev/null
iszip=$?
echo $report | grep "RAR archive" 1>/dev/null
israr=$?
# TAR archives come in many forms, if none of our tests say it's tar
# ...but it looks like tar and barks like tar, let's take the shot.
# Seems to work fairly well for the record.
res=$(echo "$target" | grep ".tar")
if [[ $res != "" ]];
then then
istar=0 echo "Using archivemount..."
fi comm2=(archivemount -o allow_root,use_ino "$target_abs")
if [[ $NO_ARCHIVEMOUNT -eq 1 ]]; then
hasmounter=1
fi
if (( $hasmounter == 0 )); then
echo "We have \`archivemount\`, so we'll use that!"
echo "If you'd prefer we not use it, please specify NO_ARCHIVEMOUNT=1"
istar=1
iszip=1
israr=1
fi
# Now we set the right command
if (( $istar == 0 )); then
comm2=(tar xvf "$target" -C)
elif (( $iszip == 0 )); then
which unzip 1>/dev/null
exitcode=$?
if (( $exitcode == 0 )); then
comm2=(unzip -q "$target" -d)
else
comm1=(echo "The utility 'unzip' is missing, please install it")
comm3=(exit 1)
fi
elif (( $israr == 0 )); then
which unrar 1>/dev/null
exitcode=$?
if (( exitcode == 0 )); then
comm2=(unrar -i nul "$target")
else
comm1=(echo "The utility 'unrar' is missing, please install it")
comm3=(exit 1)
fi
elif (( $hasmounter == 0 )); then
comm2=(archivemount -o allow_root -o use_ino "$target")
comm4=(cd ..) comm4=(cd ..)
comm5=(umount) comm5=(umount)
elif [[ $mime_type == *"tar"* || $target_abs == *.tar* ]]
then
comm2=(tar xvf "$target_abs" -C)
elif [[ $mime_type == "application/zip" ]]
then
if command -v unzip >/dev/null 2>&1
then
comm2=(unzip -q "$target_abs" -d)
else
comm1=(echo "unzip is missing")
comm3=(exit 1)
fi
elif [[ $mime_type == "application/x-rar" ]]
then
if command -v unrar >/dev/null 2>&1
then
# unrar needs the directory as the last argument
comm2=(unrar x -idq "$target_abs")
else
comm1=(echo "unrar is missing")
comm3=(exit 1)
fi
fi fi
# Create the temp dir, usually
dir=$(mktemp -d /tmp/extracted.XXXXXXXX) dir=$(mktemp -d /tmp/extracted.XXXXXXXX)
# And the rest of the commands
"${comm1[@]}" "${comm1[@]}"
"${comm2[@]}" $dir if [[ ${comm2[0]} == "unrar" ]]
then
"${comm2[@]}" "$dir"
else
"${comm2[@]}" "$dir"
fi
"${comm3[@]}" "${comm3[@]}"
currentpath=$(pwd) sym="$(pwd)/$name.tmp"
sym="$currentpath/$name.tmp" ln -sf "$dir" "$sym"
ln -f -s "$dir" "$sym"
cd "$sym" cd "$sym"
echo "A symlink has been made under the name \"$sym\"." echo "Extracted to $dir (linked via $sym)"
echo "This symlink points to the data directory \"$dir\"." echo "Type exit to finish."
echo "Type 'exit' to exit the extracted archive's folder and auto-delete it."
eval $SHELL eval $SHELL
"${comm4[@]}" "${comm4[@]}"
"${comm5[@]}" $dir "${comm5[@]}" "$dir"
rm -rf $dir rm -rf "$dir"
rm "$sym" rm "$sym"

View file

@ -24,7 +24,6 @@ function ld_dbg
then then
$@ $@
fi fi
echo
} }
# Variables for use in other utilities # Variables for use in other utilities
@ -38,10 +37,11 @@ fi
# Check for dependencies # Check for dependencies
function _daisy_dependency_check function _daisy_dependency_check
{ {
BIN=$(command -v $1 2>/dev/null) if command -v "$1" >/dev/null 2>&1; then
res=$? echo 1
else
echo $(($res ^ 1)) echo 0
fi
} }
LD_HAS_fzf=$(_daisy_dependency_check fzf) LD_HAS_fzf=$(_daisy_dependency_check fzf)
@ -77,20 +77,22 @@ fi
# [LEA.TODO] Turn these into arrays # [LEA.TODO] Turn these into arrays
LD_ALIASFILE="$LD_CONFIG_FOLDER/aliases.src" LD_ALIASFILE="$LD_CONFIG_FOLDER/aliases.src"
LD_EDITORFILE="$LD_CONFIG_FOLDER/editor.src" LD_EDITORFILE="$LD_CONFIG_FOLDER/editor.src"
LD_ESOURCEFILE="$LD_CONFIG_FOLDER/extra.src"
touch $LD_ALIASFILE touch $LD_ALIASFILE
touch $LD_EDITORFILE touch $LD_EDITORFILE
touch $LD_ESOURCEFILE
ld_dbg echo "Sourced config contents:" ld_dbg echo "Sourced config contents:"
ld_dbg cat $LD_ALIASFILE ld_dbg cat $LD_ALIASFILE
ld_dbg cat $LD_EDITORFILE ld_dbg cat $LD_EDITORFILE
ld_dbg cat $LD_ESOURCEFILE
# Source everything in the config folder # Source everything in the config folder
function _daisy_source_configs function _daisy_source_configs
{ {
for f in `find "$LD_CONFIG_FOLDER" -name "*.src" -type f`; while IFS= read -r -d '' f; do
do
source "$f" source "$f"
done done < <(find "$LD_CONFIG_FOLDER" -name "*.src" -type f -print0)
} }
# Installation into PATH # Installation into PATH
@ -123,7 +125,7 @@ function daisy_wait_for_editor
while true; while true;
do do
alive=$(ps aux | grep $fname | grep $pname) alive=$(pgrep -f "$pname.*$fname")
if [[ $alive == "" ]] if [[ $alive == "" ]]
then then
break break
@ -132,12 +134,37 @@ function daisy_wait_for_editor
done done
} }
function multicd
{
cdpath="$@"
if [[ $cdpath == '' ]]
then
\cd
return
fi
if cdz --check "$cdpath" >/dev/null 2>&1
then
cdz "$cdpath"
return
fi
if [[ -f "$cdpath/.needs_mount" ]]
then
squasher mount "$cdpath"
fi
\cd "$cdpath"
}
alias cd=multicd
# Undocumented but internally used # Undocumented but internally used
function daisy_editor function daisy_editor
{ {
editor=${LD_EDITOR:-$EDITOR}; editor=${LD_EDITOR:-$EDITOR};
ld_dbg echo Opening $editor to edit file: $1 ld_dbg echo Opening $editor to edit file: $1
$editor "$1" $editor "$1"
sleep 1
daisy_wait_for_editor $editor "$1" daisy_wait_for_editor $editor "$1"
} }
@ -248,7 +275,7 @@ function ched
for editor in "${editors[@]}"; for editor in "${editors[@]}";
do do
editor_real=$(command -v "$editor") editor_real=$(command -v "$editor")
if command -v "$editor_rmeal" >/dev/null 2>&1; if command -v "$editor_real" >/dev/null 2>&1;
then then
if [[ $(realpath "$EDITOR") == "$editor_real" ]]; if [[ $(realpath "$EDITOR") == "$editor_real" ]];
then then
@ -299,8 +326,12 @@ function daisy_reload
function ldrc function ldrc
{ {
daisy_editor "$LD_SOURCE_FILE" ARG=$1
LD_INTERNAL=0 source "$LD_SOURCE_FILE" SOURCE="$LD_SOURCE_FILE"
[[ "$ARG" == "-e" ]] && SOURCE="$LD_ESOURCEFILE"
daisy_editor "$SOURCE"
LD_INTERNAL=0 source "$SOURCE"
} }
enc_is_folder=0 enc_is_folder=0
@ -483,7 +514,7 @@ function daisy_unalias
# Remove from aliases list # Remove from aliases list
newdata=$(cat "$LD_ALIASFILE" | grep -v "alias $unalias_param") newdata=$(cat "$LD_ALIASFILE" | grep -v "alias $unalias_param")
bak "$LD_ALIASFILE" 1>/dev/null [[ NO_BAK -lt 1 ]] && bak "$LD_ALIASFILE" 1>/dev/null
echo -e $newdata > "$LD_ALIASFILE" echo -e $newdata > "$LD_ALIASFILE"
} }

11
editx
View file

@ -16,15 +16,12 @@ then
ched "EDITOR env variable not set! You will have to set it yourself in the next screen." ched "EDITOR env variable not set! You will have to set it yourself in the next screen."
fi fi
exists=$(file "$1" >/dev/null && echo $?) [[ -e "$1" ]] && existed=1 || existed=0
touch "$1" touch "$1"
chmod +x "$1" chmod +x "$1"
$EDITOR "$1" daisy_editor "$1"
wait $!
size=$(du "$1" | cut -f 1)
if [[ $size -eq 0 && $exists -ne 0 ]]; if [[ ! -s "$1" && $existed -eq 0 ]]; then
then rm -f "$1"
rm -rf "$1"
fi fi

18
own
View file

@ -5,13 +5,19 @@
LD_INTERNAL=1 LD_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source . $(dirname $(realpath $0))/daisy.source
if [[ $@ == '' ]]; if [[ -z "$1" ]]; then
then echo "$LD_BIN: Quickly take ownership of files/folders."
echo "$LD_BIN: Used to quickly take ownership of files/folders."
echo "Requires sudo. If sudo is not installed, this tool will fai."
echo "Usage: $LD_BIN <folders or files>" echo "Usage: $LD_BIN <folders or files>"
echo "Means: chown -R <youruser>:<youruser> <folders or files>" echo "Requires sudo. If sudo is not installed, this tool will fail."
exit 2 exit 2
fi fi
sudo chown -R $(whoami):$(whoami) $@ # Ensure all arguments exist before attempting chown
for target in "$@"; do
if [[ ! -e "$target" ]]; then
echo "Error: \"$target\" does not exist."
exit 1
fi
done
sudo chown -R "$(whoami):$(whoami)" "$@"

View file

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# binbox: Creates a multi-binary script that self-contains the input scripts. # scriptbox: Creates a multi-binary script that self-contains the input scripts.
# Symlinking to the resulting binary with the name of one of the original scripts will trigger # Symlinking to the resulting binary with the name of one of the original scripts will trigger
# said script. The idea is similar to `busybox`. # said script. The idea is similar to `busybox`.

179
squasher Executable file
View file

@ -0,0 +1,179 @@
#!/bin/bash
# Lackadaisical squashfs tools - Squasher
# Combined utility for make, mount, umount, and destroy operations.
BIN_DIR=$(dirname "$(readlink -f "$0")")
COMMAND="$1"
DIR="$2"
usage() {
echo "Usage: $0 {make|mount|umount|destroy} <directory>"
exit 1
}
if [[ -z "$COMMAND" || -z "$DIR" ]]; then
usage
fi
DIR=$(readlink -f "$DIR")
DIR_SHORT=$(basename "$DIR")
OVERLAY_ROOT="$(dirname "$DIR")/.squashfs/$DIR_SHORT"
OVERLAY_UPPER="$OVERLAY_ROOT/upper"
OVERLAY_LOWER="$OVERLAY_ROOT/lower"
OVERLAY_WORK="$OVERLAY_ROOT/work"
OVERLAY_TARG="$DIR"
case "$COMMAND" in
make)
if [[ ! -d "$DIR" ]]; then
echo "Error: Directory \"$DIR\" does not exist!"
exit 1
fi
echo "Checking system requirements (FUSE, SquashFS, OverlayFS)..."
for fs in fuse squashfs overlay; do
if ! grep -q "$fs" /proc/filesystems; then
echo "Attempting to load $fs module..."
sudo modprobe "$fs" || { echo "Error: $fs is not supported."; exit 1; }
fi
done
DIRSIZE=$(du -sh "$DIR" | cut -f1)
RECREATE=false
mkdir -p "$OVERLAY_ROOT"
if [[ -f "${OVERLAY_ROOT}.img" ]]; then
echo "Existing image found, updating..."
"$0" mount "$DIR"
DIRSIZE=$(du -sh "$DIR" | cut -f1)
RECREATE=true
fi
echo "Compressing \"$DIR\"..."
sudo mksquashfs "$DIR" "${OVERLAY_ROOT}.img.1" -noappend -comp xz || exit 1
if [[ "$RECREATE" == "true" ]]; then
echo "Cleaning up old layers..."
"$0" umount "$DIR"
if [[ -n "$OVERLAY_ROOT" && "$OVERLAY_ROOT" != "/" ]]; then
sudo rm -rf "$OVERLAY_UPPER" "$OVERLAY_LOWER" "$OVERLAY_WORK"
rm -f "${OVERLAY_ROOT}.img"
fi
fi
mv "${OVERLAY_ROOT}.img.1" "${OVERLAY_ROOT}.img"
mkdir -p "$OVERLAY_UPPER" "$OVERLAY_LOWER" "$OVERLAY_WORK" "$OVERLAY_TARG"
sudo rm -rf "$DIR"
mkdir -p "$DIR"
touch "$DIR/.needs_mount"
echo "-------------------------------------------------------------------------"
echo "Storage Stats:"
echo " Original size: $DIRSIZE"
echo " Compressed: $(du -sh "${OVERLAY_ROOT}.img" | cut -f1)"
echo "-------------------------------------------------------------------------"
SERVICE_CONTENT="[Unit]
Description=SquashFS Mount for %I
After=local-fs.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=${BIN_DIR}/squasher mount %I
ExecStop=${BIN_DIR}/squasher umount %I
[Install]
WantedBy=multi-user.target"
echo "$SERVICE_CONTENT" | sudo tee /etc/systemd/system/squash-mount@.service > /dev/null
sudo systemctl daemon-reload
ESC_PATH=$(systemd-escape -p "$DIR")
SERVICE_NAME="squash-mount@$ESC_PATH.service"
read -p "Enable auto-mount service ($SERVICE_NAME)? [y/N] " yn
if [[ "$yn" =~ ^[Yy]$ ]]; then
sudo systemctl enable --now "$SERVICE_NAME"
sudo systemctl stop "$SERVICE_NAME"
sudo systemctl start "$SERVICE_NAME"
else
echo "Manual mount command: sudo systemctl start $SERVICE_NAME"
fi
;;
mount)
if [[ ! -f "${OVERLAY_ROOT}.img" ]]; then
echo "Error: SquashFS image \"${OVERLAY_ROOT}.img\" not found." >&2
exit 1
fi
"$0" umount "$DIR" 2>/dev/null
mkdir -p "$OVERLAY_LOWER"
sudo mount "${OVERLAY_ROOT}.img" "$OVERLAY_LOWER" -t squashfs -o loop
if [[ $? -ne 0 ]]; then
echo "Error: Failed to mount squashfs image." >&2
exit 1
fi
sudo mount -t overlay none "$OVERLAY_TARG" \
-o lowerdir="$OVERLAY_LOWER",upperdir="$OVERLAY_UPPER",workdir="$OVERLAY_WORK"
if [[ $? -ne 0 ]]; then
echo "Error: Failed to mount overlay." >&2
sudo umount "$OVERLAY_LOWER" 2>/dev/null
exit 1
fi
echo "SquashFS filesystem is mounted and ready."
;;
umount)
sudo umount -l -R "$OVERLAY_TARG" 2>/dev/null
sudo umount -l -R "$OVERLAY_LOWER" 2>/dev/null
if mountpoint -q "$OVERLAY_TARG" || mountpoint -q "$OVERLAY_LOWER"; then
echo "Warning: Filesystem is still mounted. Check for open processes."
exit 1
fi
echo "SquashFS filesystem has been unmounted."
;;
destroy)
if [[ ! -f "$DIR/.needs_mount" ]]; then
if ! mountpoint -q "$DIR"; then
echo "Error: $DIR is not a SquashFS directory."
exit 1
fi
fi
ESC_PATH=$(systemd-escape -p "$DIR")
SERVICE_NAME="squash-mount@$ESC_PATH.service"
echo "Disabling service ($SERVICE_NAME)..."
sudo systemctl stop "$SERVICE_NAME" 2>/dev/null
sudo systemctl disable "$SERVICE_NAME" 2>/dev/null
echo "Ensuring image is mounted to preserve data..."
"$0" mount "$DIR" 1>/dev/null 2>/dev/null
echo "Destroying image and restoring data..."
TEMP_DIR=$(mktemp -d /tmp/squash-dest.XXXXXXXX)
sudo rsync -aX "$DIR/" "$TEMP_DIR/" || { echo "Error: Failed to copy data."; exit 1; }
"$0" umount "$DIR"
sudo rm -rf "$DIR"
sudo mv "$TEMP_DIR" "$DIR"
sudo rm -rf "$OVERLAY_ROOT" "${OVERLAY_ROOT}.img"
echo "Success: SquashFS image destroyed and data restored to \"$DIR\"."
;;
*)
usage
;;
esac

59
sshp
View file

@ -1,28 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# sshp ("SSH PLUS") from lackadaisical
mounts=() mounts=()
ssh_args=() ssh_args=()
remote_port=$((10000 + RANDOM % 10000)) remote_port=$((10000 + RANDOM % 10000))
local_user=$(whoami) local_user=$(whoami)
usage() usage() {
{
echo "sshp (\"SSH PLUS\") from lackadaisical."
echo "Accepts all standard SSH options (see man ssh)."
echo "Additionally, supports SSHFS mounts using a Docker-style syntax (-m)."
echo "Usage: sshp -m <local>:<remote> [user@]host [ssh_options]" echo "Usage: sshp -m <local>:<remote> [user@]host [ssh_options]"
echo "Example: sshp -m /home/juli:/home/juli juli@juli.pyon"
exit 1 exit 1
} }
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
-m) -m)
if [[ -z "$2" ]] if [[ -z "$2" ]]; then echo "Error: -m requires argument"; exit 1; fi
then
echo "Error: -m requires argument"
exit 1
fi
mounts+=("$2") mounts+=("$2")
shift 2 shift 2
;; ;;
@ -33,10 +25,7 @@ while [[ $# -gt 0 ]]; do
esac esac
done done
if [[ ${#ssh_args[@]} -eq 0 ]] [[ ${#ssh_args[@]} -eq 0 ]] && usage
then
usage
fi
mount_logic="" mount_logic=""
unmount_logic="" unmount_logic=""
@ -44,52 +33,26 @@ unmount_logic=""
for map in "${mounts[@]}"; do for map in "${mounts[@]}"; do
local_path="${map%%:*}" local_path="${map%%:*}"
remote_path="${map##*:}" remote_path="${map##*:}"
[[ "$local_path" != /* ]] && local_path="$PWD/$local_path"
if [[ "$local_path" != /* ]]
then
local_path="$PWD/$local_path"
fi
mount_logic+=" mount_logic+="
echo '>> Preparing mount: ${remote_path}'; echo '>> Preparing mount: ${remote_path}';
if ! mkdir -p \"${remote_path}\" 2>/dev/null mkdir -p \"${remote_path}\" 2>/dev/null || sudo mkdir -p \"${remote_path}\"
then
sudo mkdir -p \"${remote_path}\"
fi
if ! sshfs -p ${remote_port} -o StrictHostKeyChecking=no,idmap=user ${local_user}@localhost:\"${local_path}\" \"${remote_path}\" 2>/dev/null sshfs -p ${remote_port} -o StrictHostKeyChecking=no,idmap=user ${local_user}@localhost:\"${local_path}\" \"${remote_path}\" 2>/dev/null || \
then sudo sshfs -p ${remote_port} -o StrictHostKeyChecking=no,idmap=user,allow_other ${local_user}@localhost:\"${local_path}\" \"${remote_path}\"
echo ' (User mount failed, attempting escalation...)';
if ! sudo sshfs -p ${remote_port} -o StrictHostKeyChecking=no,idmap=user,allow_other ${local_user}@localhost:\"${local_path}\" \"${remote_path}\"
then
echo ' ! Mount failed completely. Check permissions or keys.';
fi
else
echo ' > Mounted successfully.';
fi
"
unmount_logic+="
fusermount -u -z \"${remote_path}\" 2>/dev/null || sudo fusermount -u -z \"${remote_path}\" 2>/dev/null;
" "
unmount_logic+="fusermount -u -z \"${remote_path}\" 2>/dev/null || sudo fusermount -u -z \"${remote_path}\" 2>/dev/null;"
done done
remote_script=" remote_script="
if ! command -v sshfs >/dev/null 2>&1 if ! command -v sshfs >/dev/null 2>&1; then
then
echo 'WARNING: \"sshfs\" not found on remote host.' echo 'WARNING: \"sshfs\" not found on remote host.'
echo '>> Skipping mounts, proceeding with shell only...';
echo '----------------------------------------------';
else else
${mount_logic} ${mount_logic}
fi fi
\${SHELL:-bash};
${SHELL:-bash};
if command -v sshfs >/dev/null 2>&1
then
${unmount_logic} ${unmount_logic}
fi
" "
ssh -t -R ${remote_port}:localhost:22 "${ssh_args[@]}" "$remote_script" ssh -t -R ${remote_port}:localhost:22 "${ssh_args[@]}" "$remote_script"

11
what
View file

@ -26,7 +26,10 @@
LD_INTERNAL=1 LD_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source . $(dirname $(realpath $0))/daisy.source
pwd=/ all_bins=$(compgen -c | sort -u)
all_bins=$(cd / && echo $PATH | sed 's/[:]/ /g' | xargs ls -A | grep -v ":" | sort | uniq)
output=$(printf '%s\n' "-n" $all_bins | grep -i "$1") if [[ -n "$1" ]]; then
echo "$output" echo "$all_bins" | grep -i "$1"
else
echo "$all_bins"
fi