diff --git a/.config/niri/config.keyboard.kdl b/.config/niri/config.keyboard.kdl index 48e26e3..4d22501 100644 --- a/.config/niri/config.keyboard.kdl +++ b/.config/niri/config.keyboard.kdl @@ -2,7 +2,7 @@ binds { Mod+F1 { show-hotkey-overlay; } Mod+Return hotkey-overlay-title="Terminal (foot)" { spawn "foot"; } - Mod+F9 hotkey-overlay-title="Browser (chrome)" { spawn "ykrun" "google-chrome-stable"; } + Mod+F9 hotkey-overlay-title="Browser (chrome)" { spawn "google-chrome-stable"; } Mod+E hotkey-overlay-title="Explorer (yazi)" { spawn "foot" "yazi"; } //Shift+Mod+Return hotkey-overlay-title="Steam" { spawn "steam"; } diff --git a/.zshrc b/.zshrc index 9df67bb..3e4ccb4 100644 --- a/.zshrc +++ b/.zshrc @@ -149,14 +149,6 @@ export GPG_TTY=$TTY alias noproxy='env -u http_proxy -u https_proxy' -alias ykls='systemctl --user status YukiLauncher.slice' -alias yksuspend='systemctl --user freeze YukiLauncher.slice' -alias ykcout='systemctl --user thaw YukiLauncher.slice' -alias ykexit='systemctl --user stop YukiLauncher.slice' - -alias susp="systemctl --user freeze" -alias cont="systemctl --user thaw" - export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion diff --git a/bin/fuzzel-vsc-entries.sh b/bin/fuzzel-vsc-entries.sh index 09fc895..bf9a887 100755 --- a/bin/fuzzel-vsc-entries.sh +++ b/bin/fuzzel-vsc-entries.sh @@ -12,4 +12,4 @@ for item in $(ls $desktop); do done fsarg=$(echo -en "$options" | fuzzel --dmenu --prompt="Open Project with VSCode:") -[ -z "$fsarg" ] || ykrun code "$desktop/$fsarg" +[ -z "$fsarg" ] || runbg -- code "$desktop/$fsarg" diff --git a/bin/fuzzel-win+r.sh b/bin/fuzzel-win+r.sh index 6843769..b2ddda2 100755 --- a/bin/fuzzel-win+r.sh +++ b/bin/fuzzel-win+r.sh @@ -1,3 +1,3 @@ #!/bin/bash option=$(fuzzel --dmenu --prompt-only="Command to execute: ") -[ -z "$option" ] || ykrun $option +[ -z "$option" ] || runbg -- $option diff --git a/bin/runbg b/bin/runbg new file mode 100755 index 0000000..614c63e --- /dev/null +++ b/bin/runbg @@ -0,0 +1,210 @@ +#!/bin/bash +#systemd-run --user --scope --slice=YukiLauncher.slice --unit="$1-$$".scope /bin/sh -c '"$@"' _ "$@" + +# goddamn nvm-sh !!! +# have to update PATH before launch +PATH=$(zsh -c -i 'echo $PATH') +export PATH + +# start-bg.sh - robustly start a command in the background and redirect stdout+stderr to a log +# Generated by GitHub Copilot. + +# Features: +# - Uses setsid (preferred) to detach from the controlling terminal. +# - Falls back to nohup if setsid is unavailable. +# - Runs the command with stdin closed, stdout+stderr redirected to a logfile. +# - Sets a safe umask and changes to / to avoid blocking filesystems. +# - Writes a pidfile next to the log for easy management. +# - Uses positional args ($@), script PID ($$) and reports child PID ($!). +# +# Usage: +# start-bg.sh [ -l LOGFILE | -d LOGDIR ] [ -m METHOD ] -- command [args...] +# +# Options: +# -l, --log LOGFILE Path to log file (if omitted an auto name is used) +# -d, --dir LOGDIR Directory for autogenerated logs (default: ./logs) +# -m, --method METHOD Background method: setsid (default) | nohup +# -h, --help Show this help and exit +# +# Examples: +# ./start-bg.sh -- sleep 60 +# ./start-bg.sh -d /var/log/myapp -- /usr/bin/myapp --config /etc/myapp.conf +# ./start-bg.sh -l ./my.log -- /usr/bin/myapp arg1 arg2 + +set -euo pipefail + +progname=$(basename "$0") + +usage() { + cat </..pid<$$>.log + +A pidfile is written as .pid containing the child PID. +EOF + exit 1 +} + +# Defaults +logdir="/tmp/$USER/runner" +logfile="" +method="setsid" + +# Parse options until the `--` separator +while [[ $# -gt 0 ]]; do + case "$1" in + -l|--log) + if [[ $# -lt 2 ]]; then echo "Missing argument for $1"; usage; fi + logfile="$2"; shift 2 ;; + -d|--dir) + if [[ $# -lt 2 ]]; then echo "Missing argument for $1"; usage; fi + logdir="$2"; shift 2 ;; + -m|--method) + if [[ $# -lt 2 ]]; then echo "Missing argument for $1"; usage; fi + method="$2"; shift 2 ;; + -h|--help) + usage ;; + --) + shift; break ;; + -*) + echo "Unknown option: $1"; usage ;; + *) + break ;; + esac +done + +# Remaining args are the command to run +if [[ $# -eq 0 ]]; then + echo "Error: no command specified." + usage +fi + +# Preserve the command and args +cmd=( "$@" ) +cmd_basename=$(basename "${cmd[0]}") +timestamp=$(date +%Y%m%d-%H%M%S) + +mkdir -p -- "${logdir}" + +if [[ -z "${logfile}" ]]; then + logfile="${logdir}/${cmd_basename}.${timestamp}.pid$$.log" +fi + +pidfile="${logfile}.pid" + +# Validate method +case "${method}" in + setsid|nohup) ;; + *) + echo "Invalid method: ${method}. Allowed: setsid|nohup" + exit 2 + ;; +esac + +# Prepare environment for child +# We construct a small wrapper for safe daemonization: +start_with_setsid() { + # Prefer existing setsid binary (coreutils/util-linux) + if ! command -v setsid >/dev/null 2>&1; then + return 1 + fi + + # Use setsid to start the process in a new session. We: + # - set a conservative umask + # - change to / to avoid keeping directories busy + # - close stdin and redirect stdout/stderr to logfile + # + # We run setsid directly with the command array so arguments are preserved. + # + # Note: redirecting >"$logfile" 2>&1 < /dev/null outside ensures the setsid child + # inherits the redirections. + ( + umask 022 + cd / || true + # exec will replace the subshell with the command + exec "${cmd[@]}" + ) >"${logfile}" 2>&1 < /dev/null & + child_pid=$! + + # Detach the job from this shell's job table if possible + disown "$child_pid" 2>/dev/null || true + + # setsid the already-forked child to start a new session. Some systems allow: + # setsid -w + # but that's nonportable; instead we try to re-exec the command under setsid. + # If `setsid` can't be applied to the backgrounded PID, we respawn via setsid: + if setsid true >/dev/null 2>&1; then + # Respawn under setsid to ensure proper session leader if available. + # Kill the previous child (it is still running) and restart under setsid. + # To avoid races: only do this if cmd is still running and the pid we started is a shell wrapper. + if kill -0 "$child_pid" 2>/dev/null; then + # Attempt to terminate wrapper and spawn a true setsid child. + kill "$child_pid" 2>/dev/null || true + # Short sleep to allow process cleanup (best-effort) + sleep 0.05 + fi + + # Now start the real setsid-backed child with same redirections + setsid "${cmd[@]}" >"${logfile}" 2>&1 < /dev/null & + child_pid=$! + disown "$child_pid" 2>/dev/null || true + fi + + printf '%s' "$child_pid" + return 0 +} + +start_with_nohup() { + # Use nohup as fallback; nohup will ignore HUP but doesn't start a new session. + nohup "${cmd[@]}" >"${logfile}" 2>&1 < /dev/null & + child_pid=$! + disown "$child_pid" 2>/dev/null || true + printf '%s' "$child_pid" + return 0 +} + +# Main launcher: pick method and start +echo "Launching command: ${cmd[*]}" +echo "Log file: ${logfile}" +echo "Method: ${method}" + +child_pid="" + +if [[ "${method}" == "setsid" ]]; then + # Try to start via setsid; if setsid not present, fallback to nohup + if child_pid=$(start_with_setsid); then + : # success + else + echo "setsid not available, falling back to nohup" + child_pid=$(start_with_nohup) + fi +else + child_pid=$(start_with_nohup) +fi + +# Write pidfile (best-effort) +if [[ -n "${child_pid}" ]]; then + printf '%s\n' "${child_pid}" > "${pidfile}" 2>/dev/null || true +fi + +# Reporting +echo "Script PID: $$" +if [[ -n "${child_pid}" ]]; then + echo "Child PID: ${child_pid}" +else + echo "Child PID: (unknown)" +fi +echo "Pidfile: ${pidfile}" +echo "Started at: $(date --iso-8601=seconds 2>/dev/null || date +%Y-%m-%dT%H:%M:%S%z)" +echo +echo "To follow the log: tail -F ${logfile}" + +exit 0 diff --git a/bin/ykrun b/bin/ykrun deleted file mode 100755 index 5e7226d..0000000 --- a/bin/ykrun +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -systemd-run --user --scope --slice=YukiLauncher.slice --unit="$1-$$".scope /bin/sh -c '"$@"' _ "$@"