From 9b7d253ca07b80fbc201c5cf5b7f14a49bd09b3f Mon Sep 17 00:00:00 2001 From: Slatian Date: Tue, 23 Jan 2024 06:14:06 +0000 Subject: Add xdg-realpath to better handle Canonicalizing filenames This replaces calls to `realpath -f` which isn't available on all shells. (fix #66) --- README.md | 3 +- scripts/.gitignore | 1 + scripts/desc/xdg-realpath.xml | 208 ++++++++++++++++++++++++++++++++++++++++++ scripts/html/.gitignore | 1 + scripts/man/.gitignore | 2 + scripts/xdg-desktop-icon.in | 4 +- scripts/xdg-desktop-menu.in | 2 +- scripts/xdg-email.in | 2 +- scripts/xdg-icon-resource.in | 4 +- scripts/xdg-mime.in | 4 +- scripts/xdg-realpath.in | 60 ++++++++++++ scripts/xdg-utils-common.in | 66 +++++++++++++- 12 files changed, 345 insertions(+), 12 deletions(-) create mode 100644 scripts/desc/xdg-realpath.xml create mode 100644 scripts/xdg-realpath.in diff --git a/README.md b/README.md index b514cb7..e5b44de 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Documentation is mostly in the maual pages and on the [freedesktop.org wiki](htt ## Overview -The following tools are included in xdg-utils 1.0: +The following tools are included in xdg-utils 1.2: * `xdg-desktop-menu` - Install desktop menu items * `xdg-desktop-icon` - Install icons to the desktop @@ -40,6 +40,7 @@ The following tools are included in xdg-utils 1.0: * `xdg-mime` - Query information about file type handling and install descriptions for new file types * `xdg-open` - Open a file or URL in the user's preferred application * `xdg-email` - Send mail using the user's preferred e-mail composer +* `xdg-realpath` - Canonicalize filenames (new in 1.2) * `xdg-screensaver` - Control the screensaver diff --git a/scripts/.gitignore b/scripts/.gitignore index 261d5ce..3b51bac 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -8,3 +8,4 @@ xdg-mime xdg-open xdg-screensaver xdg-settings +xdg-realpath diff --git a/scripts/desc/xdg-realpath.xml b/scripts/desc/xdg-realpath.xml new file mode 100644 index 0000000..60a5b22 --- /dev/null +++ b/scripts/desc/xdg-realpath.xml @@ -0,0 +1,208 @@ + + + + + + xdg-realpath Manual + + 2023 + + + Slatian +
+ baschdel+xdg-utils@disroot.org +
+
+ + Kevin + Krammer +
+ +
+
+ + Jeremy + White +
+ +
+
+ xdg-utils 1.2 +
+ + xdg-realpath + 1 + + + xdg-realpath + Canonicalizes filepaths in a consistent way. + + + + xdg-realpath + + + + + + + xdg-realpath + + + + xdg-realpath + + + + + + + + + Description + + xdg-realpath canonicalizes filepaths using the installed realpath or readlink -f implementation, automatically choosing the right calling conventions so you don't have to worry about it. + + + Canonicalization happens by resolving relative paths and symbolic links resulting in an absolute path to a file. It fails if the path does not lead to any kind file or directory. + + + It is strongly recommended to call xdg-realpath using the option. + + + + Options + + + + + + + + Show command synopsis. + + + + + + + + + + Show this manual page. + + + + + + + + + + Show the xdg-utils version information. + + + + + + + Exit Codes + + An exit code of 0 indicates success while a non-zero exit code + indicates failure. The following failure codes can be returned: + + + + + + + + + Error in command line syntax. + + + + + + + + + + One of the files passed on the command line did not exist. + + + + + + + + + + A required tool could not be found. + + + + + + + + + + The action failed. + + + + + + + Environment Variables + + xdg-realpath honours the following environment variables: + + + + XDG_UTILS_REALPATH_BACKEND + + + When left empty (recommended) xdg-realpath automatically chooses an appropriate backend. Possible values are realpath, busybox-realpath and readlink. + This is also used by other scripts from the xdg-utils family. + + + Setting this variable has the possibility to break a lot of things. It is primarily intended for testing and quick-fixing. If you are not the local system administrator or a distribution maintainer leave it alone! + + + The option will print the used backend. + + + + + + + See Also + realpath1, + readlink1, + + + + Examples + + +xdg-realpath -- /./bin + + Canonicalizes the path to /./bin, on most systems the output will be /bin or /usr/bin. + + + +xdg-realpath -- foo.txt + + Will print the absolute path of the file foo.txt or inform you that foo.txt doesn't exist. + + + +xdg-realpath -- . + + Will print the present working directory path with symbolic links resolved. + + +
diff --git a/scripts/html/.gitignore b/scripts/html/.gitignore index 0be5f9a..b373b67 100644 --- a/scripts/html/.gitignore +++ b/scripts/html/.gitignore @@ -5,5 +5,6 @@ xdg-email.html xdg-icon-resource.html xdg-mime.html xdg-open.html +xdg-realpath.html xdg-screensaver.html xdg-settings.html diff --git a/scripts/man/.gitignore b/scripts/man/.gitignore index 43c7914..82d9456 100644 --- a/scripts/man/.gitignore +++ b/scripts/man/.gitignore @@ -4,5 +4,7 @@ xdg-email.1 xdg-icon-resource.1 xdg-mime.1 xdg-open.1 +xdg-realpath.1 xdg-screensaver.1 xdg-settings.1 + diff --git a/scripts/xdg-desktop-icon.in b/scripts/xdg-desktop-icon.in index 6417181..21dc64b 100644 --- a/scripts/xdg-desktop-icon.in +++ b/scripts/xdg-desktop-icon.in @@ -108,7 +108,7 @@ if gconftool-2 -g /apps/nautilus/preferences/desktop_is_home_dir 2> /dev/null | desktop_dir_gnome="$HOME" # Don't create $HOME/Desktop if it doesn't exist [ -w "$desktop_dir" ] || desktop_dir= -fi +fi if [ -n "$desktop_dir_kde" ]; then if [ ! -d "$desktop_dir_kde" ]; then save_umask=`umask` @@ -117,7 +117,7 @@ if [ -n "$desktop_dir_kde" ]; then umask $save_umask fi # Is the KDE desktop dir != $HOME/Desktop ? - if [ "x`readlink -f "$desktop_dir"`" != "x`readlink -f "$desktop_dir_kde"`" ]; then + if [ "x$(xdg_realpath "$desktop_dir")" != "x$(xdg_realpath "$desktop_dir_kde")" ]; then # If so, don't create $HOME/Desktop if it doesn't exist [ -w "$desktop_dir" ] || desktop_dir= else diff --git a/scripts/xdg-desktop-menu.in b/scripts/xdg-desktop-menu.in index 8025676..08fe2a6 100644 --- a/scripts/xdg-desktop-menu.in +++ b/scripts/xdg-desktop-menu.in @@ -88,7 +88,7 @@ make_lazy_default() # App already listed as default continue; fi - default_file="$(readlink -f "$1/defaults.list")" + default_file="$(xdg_realpath "$1/defaults.list")" if [ -f "$default_file" ] ; then DEBUG 1 "Updating $default_file" grep -v "$MIME=" $default_file > ${default_file}.new 2> /dev/null diff --git a/scripts/xdg-email.in b/scripts/xdg-email.in index fc24886..ca9323a 100644 --- a/scripts/xdg-email.in +++ b/scripts/xdg-email.in @@ -377,7 +377,7 @@ while [ $# -gt 0 ] ; do exit_failure_syntax "file argument missing for --attach option" fi check_input_file "$1" - file="$(readlink -f "$1")" # Normalize path + file="$(xdg_realpath "$1")" # Normalize path if [ -z "$file" ] || [ ! -f "$file" ] ; then exit_failure_file_missing "file '$1' does not exist" fi diff --git a/scripts/xdg-icon-resource.in b/scripts/xdg-icon-resource.in index ac17ae6..0bfa26b 100644 --- a/scripts/xdg-icon-resource.in +++ b/scripts/xdg-icon-resource.in @@ -306,7 +306,7 @@ fi need_kde_icon_path() { local path - path=`readlink -f "$1" 2> /dev/null` # Normalize path + path="$(xdg_realpath "$1")" 2> /dev/null` # Normalize path DEBUG 2 "need_kde_icon_path $path" if [ -z "$path" ] ; then DEBUG 2 "need_kde_icon_path RETURN 1 (not needed, no xdg icon dir)" @@ -323,7 +323,7 @@ need_kde_icon_path() fi needed=0 # Needed for y in $kde_icon_dirs ; do - x=`readlink -f "$y"` # Normalize path + x="$(xdg_realpath "$y")" # Normalize path DEBUG 3 "Normalize $y --> $x" if [ -n "$x" ] ; then if [ "$x" = "$path" ] ; then diff --git a/scripts/xdg-mime.in b/scripts/xdg-mime.in index d1b4226..bfb088b 100644 --- a/scripts/xdg-mime.in +++ b/scripts/xdg-mime.in @@ -299,7 +299,7 @@ make_default_generic() [ -n "$xdg_config_home" ] || xdg_config_home="$HOME/.config" default_file="$xdg_config_home/mimeapps.list" if [ -L "$default_file" ]; then - out_file=$(readlink -f "$default_file") + out_file="$(xdg_realpath "$default_file")" else out_file="$default_file" fi @@ -587,7 +587,7 @@ case $1 in ;; esac check_input_file "$filename" - filename="$(readlink -f -- "$filename")" + filename="$(xdg_realpath "$filename")" ;; default) diff --git a/scripts/xdg-realpath.in b/scripts/xdg-realpath.in new file mode 100644 index 0000000..87733da --- /dev/null +++ b/scripts/xdg-realpath.in @@ -0,0 +1,60 @@ +#!/bin/sh +#--------------------------------------------- +# xdg-realpath +# +# Utility script to canonicalize filepaths. +# +# Copyright 2023, Slatian +# +# LICENSE: +# +#--------------------------------------------- + +manualpage() +{ +cat << _MANUALPAGE +_MANUALPAGE +} + +usage() +{ +cat << _USAGE +_USAGE +} + +XDG_UTILS_ENABLE_DOUBLE_HYPEN="y" + +#@xdg-utils-common@ + +set -e + +[ -n "$1" ] || exit_failure_syntax + +past_double_hyphen="" +exit_with_missing_status="" + +while [ $# -gt 0 ] ; do + if [ -n "$past_double_hyphen" ] ; then + [ -e "$1" ] || echo "@NAME@: $1: No such file or directory" >&2 + xdg_realpath "$1" + else + case "$1" in + --) + past_double_hyphen="y" + ;; + --get-backend) + xdg_realpath || true + echo "$XDG_UTILS_REALPATH_BACKEND" + ;; + -*) + exit_failure_syntax "Unknown option: '$1'" + ;; + *) + xdg_realpath "$1" + ;; + esac + fi + shift +done + +[ -z "$exit_with_missing_status" ] || exit_failure_file_missing diff --git a/scripts/xdg-utils-common.in b/scripts/xdg-utils-common.in index 5135c86..bba3d8a 100644 --- a/scripts/xdg-utils-common.in +++ b/scripts/xdg-utils-common.in @@ -27,7 +27,7 @@ binary_to_desktop_file() { search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" binary="$(command -v "$1")" - binary="$(readlink -f "$binary")" + binary="$(xdg_realpath "$binary")" base="$(basename "$binary")" IFS=: for dir in $search; do @@ -42,7 +42,7 @@ binary_to_desktop_file() grep -Eq "^(NoDisplay|Hidden)=true" "$file" && continue command="$(grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word)" command="$(command -v "$command")" - if [ x"$(readlink -f "$command")" = x"$binary" ]; then + if [ x"$(xdg_realpath "$command")" = x"$binary" ]; then # Fix any double slashes that got added path composition echo "$file" | tr -s / return @@ -84,7 +84,7 @@ desktop_file_to_binary() # Remove any arguments (%F, %f, %U, %u, etc.). command="$(grep -E "^Exec(\[[^]=]*])?=" "$file_path" | cut -d= -f 2- | first_word)" command="$(command -v "$command")" - readlink -f "$command" + xdg_realpath "$command" return fi done @@ -252,6 +252,10 @@ check_common_commands() echo "@NAME@ 1.2.0-beta1" exit_success ;; + + --) + [ -z "$XDG_UTILS_ENABLE_DOUBLE_HYPEN" ] || break + ;; esac done } @@ -402,3 +406,59 @@ has_display() return 1 fi } + +#---------------------------------------------------------------------------- +# Prefixes a path with a "./" if it starts with a "-". +# This is useful for programs to not confuse paths with options. + +unoption_path() +{ + case "$1" in + -*) + printf "./%s" "$1" ;; + *) + printf "%s" "$1" ;; + esac +} + +#---------------------------------------------------------------------------- +# Performs a symlink and relative path resolving for a single argument. +# This will always fail if the given file does not exist! + +xdg_realpath() +{ + # allow caching and external configuration + if [ -z "$XDG_UTILS_REALPATH_BACKEND" ] ; then + if command -v realpath >/dev/null 2>/dev/null ; then + lines="$(realpath -- / 2>&1)" + if [ $? = 0 ] && [ "$lines" = "/" ] ; then + XDG_UTILS_REALPATH_BACKEND="realpath" + else + # The realpath took the -- literally, probably the busybox implementation + XDG_UTILS_REALPATH_BACKEND="busybox-realpath" + fi + unset lines + elif command -v readlink >/dev/null 2>/dev/null ; then + XDG_UTILS_REALPATH_BACKEND="readlink" + else + exit_failure_operation_failed "No usable realpath backend found. Have a realpath binary or a readlink -f that canonicalizes paths." + fi + fi + # Always fail if the file doesn't exist (busybox realpath does that for example) + [ -e "$1" ] || return 1 + case "$XDG_UTILS_REALPATH_BACKEND" in + realpath) + realpath -- "$1" + ;; + busybox-realpath) + # busybox style realpath implementations have options too + realpath "$(unoption_path "$1")" + ;; + readlink) + readlink -f "$(unoption_path "$1")" + ;; + *) + exit_failure_operation_impossible "Realpath backend '$XDG_UTILS_REALPATH_BACKEND' not recognized." + ;; + esac +} -- cgit v1.2.3