diff --git a/rdlink.sh b/rdlink.sh index 7c85dbf..835e3c2 100755 --- a/rdlink.sh +++ b/rdlink.sh @@ -40,65 +40,25 @@ msg() { echo "$@"; true; } ### Script rl::rdlink() { local subject= - local work= - - info "Processing: $*" - info " with pwd: $(pwd)" - - subject="$(rl::cleanpath "${1:-}")" || true - - # Follow multiple symlinks - while subject="$(rl::quicklink "${subject}")" ; do - : # A link was resolved at least once - info " rl::rdlink - Link found: $subject" - done - - # Special cases handling - { - # If subject is still a link, after rl::quicklink call(s) - # current user has no permission to access the link itself - # (e.g. /proc/**/cwd) - if [ -L "${subject}" ] ; then - info " rl::rdlink exit - can't access link ${subject}" - printf "\n" - return 1 - fi - } - - # Empty output if (dirname $subject) is not a valid path - if ! work="$(rl::canon "${subject}")" ; then - info " rl::rdlink exit - invalid path ${work}" - printf "\n" - return 1 - else - subject="${work}" - fi + subject="${1:-}" + while [[ "${subject:-}" = *"//"* ]]; do subject="${subject/\/\///}"; done + while subject="$(rl::quicklink "${subject}")" ; do : ; done + [ -L "${subject}" ] && printf "\n" && return 1 + subject="$(rl::canon "${subject}")" || { printf "\n"; return 1; } printf "%s\n" "${subject}" } rl::quicklink() { - subject= - work= + local subject= + local work= - info "Quicklink... ${1:-}" - - # Check if current candidate is a symlink - if ! subject=$(readlink -- "${1:-}"); then - printf -- "%s\n" "${1:-}" - return 1 - fi - info " rl::quicklink symlink ${1} -> ${subject}" - - # relative symlink target; prepend its parent direcotry + subject=$(readlink -- "${1:-}") || { printf -- "%s\n" "${1:-}"; return 1; } if [[ "${subject}" != "/"* ]]; then work="$(rl::canon "$(dirname -- "${1:-}")")" subject="${work}/${subject}" - info " rl::quicklink relative link resolved: ${subject}" fi - printf "%s\n" "${subject}" - return 0 } rl::canon() { @@ -110,100 +70,31 @@ rl::canon() { local retval=0 start="${1:-}" - info "Canonicalize path... ${start}" - while (( run )) ; do if work="$(cd "${start}" >/dev/null 2>&1 && pwd -P)" ; then - # Special: `pwd -P` returns with // as root for links starting at / - # e.g. $(readlink /proc/self/root) == "/" - # $(cd /proc/self/root/mnt && pwd -P) == "//mnt" - subject="$(rl::normalize "${work}")" - info " rl::canon valid directory: ${subject}" - run=0 + subject="$(rl::normalize "${work}")"; run=0 elif work="$(cd "$(dirname -- "${start}")" >/dev/null 2>&1 && pwd -P)" ; then bname="$(basename -- "${start}")" - - # Special: / produces // [[ "${work}" == "/" ]] && work= - subject="${work}${bname:+"/${bname}"}" - info " rl::canon valid parent: ${subject}" - - # Special: Succeed with valid element after second run; see special below - # e.g. /root/. - # * /root is valid but not accessible - if (( retval )) && [ -e "${subject}" ] ;then - info " rl::canon valid element" - retval=0 - fi - run=0 + (( retval )) && [ -e "${subject}" ] && retval=0; run=0 else - # Special: Some paths may be resolvable after normalization - # e.g. somedir/.. - # * base "somedir" does not exist - # * but irrelevant because of /.. - # * resolves to pwd but fails by readlink -f work="$(rl::normalize "${start}")" - if [[ "${work}" != "${start}" ]] ; then - info " rl::canon retry with: ${work}" - start="${work}" - retval=1 - continue - fi - info " rl::canon invalid path: ${work}" - subject="${work}" - run=0 && retval=1 + [[ "${work}" != "${start}" ]] && start="${work}" && retval=1 && continue + subject="${work}"; run=0 && retval=1 fi done - - printf -- "%s\n" "${subject}" - return ${retval} -} - -rl::cleanpath() { - local work= - local rex_tmp= - - info "Cleaning path... ${1:-}" - work="${1:-}" - - # Remove multiple / - while [[ "${work:-}" = *"//"* ]]; do - work="${work/\/\///}" - done - - info " rl::cleanpath result: ${work}" - printf -- "%s\n" "${work}" + printf -- "%s\n" "${subject}"; return ${retval} } rl::normalize() { local work= - - info "Normalizing path... ${1:-}" work="${1:-}" - # Remove dir/.. sequences. - local rex_tmp='[^/][^/]*/\.\./*' - while [[ "${work}" =~ $rex_tmp ]] ; do - work="${work/"${BASH_REMATCH[0]}"/}" - done - - # Remove /./ and /.$ sequences. - rex_tmp='/\.(/|$)' - while [[ "$work" =~ $rex_tmp ]]; do - work="${work/${BASH_REMATCH[0]}/${BASH_REMATCH[1]/$//}}" - done - - # Remove leading ./ + while [[ "${work}" =~ [^/][^/]*/\.\./* ]] ; do work="${work/"${BASH_REMATCH[0]}"/}"; done + while [[ "$work" =~ /\.(/|$) ]]; do work="${work/${BASH_REMATCH[0]}/${BASH_REMATCH[1]/$//}}"; done work="${work#./*}" - - # Remove trailing / - rex_tmp='(.*[^/])/$' - if [[ "${work}" =~ $rex_tmp ]] ; then - work="${BASH_REMATCH[1]}" - fi - - info " rl::normalize result: ${work}" + [[ "${work}" =~ (.*[^/])/$ ]] && work="${BASH_REMATCH[1]}" printf -- "%s\n" "${work}" } @@ -213,31 +104,18 @@ rl::main() { for arg in "$@"; do case "$arg" in - --) - shift - break ;; - -d|--debug) - shift - LOG_LEVEL=7 ;; - -dd) - shift - set -o xtrace ;; - -*) - shift ;; + --) shift; break ;; + -d|--debug) shift; LOG_LEVEL=7 ;; + -dd) shift; set -o xtrace ;; + -*) shift ;; esac done - info "BASH rdlink" - - for file in "$@"; do - rl::rdlink "$file" - done + for file in "$@"; do rl::rdlink "$file"; done } # Provide as function to be called when sourced -rdlink() { - rl::main "$@" -} +rdlink() { rl::main "$@"; } ### Check if script is _sourced ### https://stackoverflow.com/a/28776166 @@ -255,9 +133,7 @@ else # All other shells: examine $0 for known shell binary filenames fi ### -if (( ! _sourced )); then - rl::main "$@" -fi +(( ! _sourced )) && rl::main "$@" ### Script EOF