diff options
| author | Louis Burda <dev@sinitax.com> | 2026-02-28 22:40:35 +0100 |
|---|---|---|
| committer | Louis Burda <dev@sinitax.com> | 2026-02-28 22:40:39 +0100 |
| commit | 73595039295794319a86add61662f4226cff6c9b (patch) | |
| tree | 810a5588e83fd91fcbf8453c041f2715197a9bde | |
| parent | 23bf13e06138bec9f5cd2122745adb9397f28d86 (diff) | |
| download | cosu-main.tar.gz cosu-main.zip | |
| -rwxr-xr-x | cosu | 196 | ||||
| -rw-r--r-- | cosu.1 | 7 |
2 files changed, 93 insertions, 110 deletions
@@ -1,8 +1,6 @@ -#!/bin/bash +#!/bin/sh -set -e - -VERSION="1.0.0" +VERSION="1.1.0" usage() { cat <<EOF @@ -12,6 +10,7 @@ Conditionally execute a command with sudo based on file permissions. OPTIONS: -h, --help Show this help message + --version Show version information FLAGS (before each path): -r, --read Check read permission @@ -34,122 +33,103 @@ EOF } needs_sudo=0 -declare -a checks - -parse_args() { - local current_flags=() - - while [[ $# -gt 0 ]]; do - case "$1" in - --help) - usage - ;; - --) - shift - if [[ $# -eq 0 ]]; then - echo "Error: No command specified after '--'" >&2 - exit 1 - fi - command_args=("$@") - return - ;; - --read) - current_flags+=("r") - shift - ;; - --write) - current_flags+=("w") - shift - ;; - --execute) - current_flags+=("x") - shift - ;; - -*) - local flags="${1#-}" - if [[ ! "$flags" =~ ^[rwxh]+$ ]]; then - echo "Error: Unknown flag '$1'" >&2 - echo "Use -h or --help for usage information" >&2 - exit 1 - fi - - if [[ "$flags" == *h* ]]; then - usage - fi - - local i - for (( i=0; i<${#flags}; i++ )); do - local flag="${flags:$i:1}" - case "$flag" in - r|w|x) - current_flags+=("$flag") - ;; - esac - done - shift - ;; - *) - if [[ ${#current_flags[@]} -eq 0 ]]; then - echo "Error: Path '$1' specified without permission flags" >&2 - echo "Use -h or --help for usage information" >&2 - exit 1 - fi - - local path="$1" - for flag in "${current_flags[@]}"; do - checks+=("$flag:$path") - done - current_flags=() - shift - ;; +current_flags="" +found_sep=0 + +expand_short_flags() { + f="$1" + while [ -n "$f" ]; do + c="${f%"${f#?}"}" + f="${f#?}" + case "$c" in + h) usage ;; + r|w|x) current_flags="${current_flags}${c}" ;; esac done - - echo "Error: No '--' separator found" >&2 - echo "Use -h or --help for usage information" >&2 - exit 1 } -check_permissions() { - for check in "${checks[@]}"; do - local perm="${check%%:*}" - local path="${check#*:}" - - case "$perm" in - r) - if [[ ! -r "$path" ]]; then - needs_sudo=1 - return - fi - ;; - w) - if [[ ! -w "$path" ]]; then - needs_sudo=1 - return - fi - ;; - x) - if [[ ! -x "$path" ]]; then - needs_sudo=1 - return - fi - ;; +check_flags_on_path() { + f="$1" + path="$2" + while [ -n "$f" ]; do + c="${f%"${f#?}"}" + f="${f#?}" + case "$c" in + r) if [ ! -r "$path" ]; then needs_sudo=1; fi ;; + w) if [ ! -w "$path" ]; then needs_sudo=1; fi ;; + x) if [ ! -x "$path" ]; then needs_sudo=1; fi ;; esac done } -declare -a command_args - -if [[ $# -eq 0 ]]; then +if [ $# -eq 0 ]; then usage fi -parse_args "$@" +while [ $# -gt 0 ]; do + case "$1" in + --help) + usage + ;; + --version) + echo "cosu $VERSION" + exit 0 + ;; + --read) + current_flags="${current_flags}r" + shift + ;; + --write) + current_flags="${current_flags}w" + shift + ;; + --execute) + current_flags="${current_flags}x" + shift + ;; + --) + shift + found_sep=1 + break + ;; + -*) + flags="${1#-}" + case "$flags" in + *[!rwxh]*) + echo "Error: Unknown flag '$1'" >&2 + echo "Use -h or --help for usage information" >&2 + exit 1 + ;; + esac + expand_short_flags "$flags" + shift + ;; + *) + if [ -z "$current_flags" ]; then + echo "Error: Path '$1' specified without permission flags" >&2 + echo "Use -h or --help for usage information" >&2 + exit 1 + fi + check_flags_on_path "$current_flags" "$1" + current_flags="" + shift + ;; + esac +done + +if [ "$found_sep" -eq 0 ]; then + echo "Error: No '--' separator found" >&2 + echo "Use -h or --help for usage information" >&2 + exit 1 +fi -check_permissions +if [ $# -eq 0 ]; then + echo "Error: No command specified after '--'" >&2 + exit 1 +fi -if [[ $needs_sudo -eq 1 ]]; then - exec sudo "${command_args[@]}" +if [ "$needs_sudo" -eq 1 ]; then + exec sudo "$@" else - exec "${command_args[@]}" + exec "$@" fi @@ -1,4 +1,4 @@ -.TH COSU 1 "February 2026" "cosu 1.0.0" "User Commands" +.TH COSU 1 "February 2026" "cosu 1.1.0" "User Commands" .SH NAME cosu \- conditionally execute commands with sudo based on file permissions .SH SYNOPSIS @@ -18,6 +18,9 @@ If all checks pass, the command runs normally without privilege escalation. .TP .BR \-h ", " \-\-help Display help message and exit. +.TP +.B \-\-version +Print version information and exit. .SH FLAGS The following flags specify which permissions to check on the subsequent path. Multiple flags can be specified before a single path. Short flags can be @@ -159,4 +162,4 @@ There is NO WARRANTY, to the extent permitted by law. .SH SEE ALSO .BR sudo (8), .BR test (1), -.BR bash (1) +.BR sh (1) |
