diff options
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | scripts/.gitignore | 1 | ||||
-rw-r--r-- | scripts/desc/xdg-realpath.xml | 208 | ||||
-rw-r--r-- | scripts/html/.gitignore | 1 | ||||
-rw-r--r-- | scripts/man/.gitignore | 2 | ||||
-rw-r--r-- | scripts/xdg-desktop-icon.in | 4 | ||||
-rw-r--r-- | scripts/xdg-desktop-menu.in | 2 | ||||
-rw-r--r-- | scripts/xdg-email.in | 2 | ||||
-rw-r--r-- | scripts/xdg-icon-resource.in | 4 | ||||
-rw-r--r-- | scripts/xdg-mime.in | 4 | ||||
-rw-r--r-- | scripts/xdg-realpath.in | 60 | ||||
-rw-r--r-- | scripts/xdg-utils-common.in | 66 |
12 files changed, 345 insertions, 12 deletions
@@ -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 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/xsl" + href="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"> +<refentry id="xdg-open"> + <refentryinfo> + <title>xdg-realpath Manual</title> + <copyright> + <year>2023</year> + </copyright> + <author> + <firstname>Slatian</firstname> + <address> + <email>baschdel+xdg-utils@disroot.org</email> + </address> + </author> + <author> + <firstname>Kevin</firstname> + <surname>Krammer</surname> + <address> + <!--email>kevin.krammer@gmx.at</email--> + </address> + </author> + <author> + <firstname>Jeremy</firstname> + <surname>White</surname> + <address> + <!--email>jwhite@codeweavers.com</email--> + </address> + </author> + <releaseinfo>xdg-utils 1.2</releaseinfo> + </refentryinfo> + <refmeta> + <refentrytitle>xdg-realpath</refentrytitle> + <manvolnum>1</manvolnum> + </refmeta> + <refnamediv> + <refname>xdg-realpath</refname> + <refpurpose>Canonicalizes filepaths in a consistent way.</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>xdg-realpath</command> + <arg choice="opt"><option>--</option></arg> + <arg choice="plain" rep="repeat"> + <option><replaceable>file</replaceable></option> + </arg> + </cmdsynopsis> + <cmdsynopsis> + <command>xdg-realpath</command> + <arg choice="plain"><option>--get-backend</option></arg> + </cmdsynopsis> + <cmdsynopsis> + <command>xdg-realpath</command> + <group choice="req"> + <arg choice="plain"><option>--help</option></arg> + <arg choice="plain"><option>--manual</option></arg> + <arg choice="plain"><option>--version</option></arg> + </group> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1 id="description"> + <title>Description</title> + <para> + xdg-realpath canonicalizes filepaths using the installed <command>realpath</command> or <command>readlink -f</command> implementation, automatically choosing the right calling conventions so you don't have to worry about it. + </para> + <para> + 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. + </para> + <para> + It is strongly recommended to call xdg-realpath using the <option>--</option> option. + </para> + </refsect1> + <refsect1 id="options"> + <title>Options</title> + <variablelist> + <varlistentry> + <term> + <option>--help</option> + </term> + <listitem> + <simpara> + Show command synopsis. + </simpara> + </listitem> + </varlistentry> + <varlistentry> + <term> + <option>--manual</option> + </term> + <listitem> + <simpara> + Show this manual page. + </simpara> + </listitem> + </varlistentry> + <varlistentry> + <term> + <option>--version</option> + </term> + <listitem> + <simpara> + Show the xdg-utils version information. + </simpara> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1 id="exitcodes"> + <title>Exit Codes</title> + <para> + An exit code of 0 indicates success while a non-zero exit code + indicates failure. The following failure codes can be returned: + </para> + <variablelist> + <varlistentry> + <term> + <option>1</option> + </term> + <listitem> + <simpara> + Error in command line syntax. + </simpara> + </listitem> + </varlistentry> + <varlistentry> + <term> + <option>2</option> + </term> + <listitem> + <simpara> + One of the files passed on the command line did not exist. + </simpara> + </listitem> + </varlistentry> + <varlistentry> + <term> + <option>3</option> + </term> + <listitem> + <simpara> + A required tool could not be found. + </simpara> + </listitem> + </varlistentry> + <varlistentry> + <term> + <option>4</option> + </term> + <listitem> + <simpara> + The action failed. + </simpara> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1 id="env_vars"> + <title>Environment Variables</title> + <para> + xdg-realpath honours the following environment variables: + </para> + <variablelist> + <varlistentry> + <term>XDG_UTILS_REALPATH_BACKEND</term> + <listitem> + <simpara> + When left empty (recommended) xdg-realpath automatically chooses an appropriate backend. Possible values are <code>realpath</code>, <code>busybox-realpath</code> and <code>readlink</code>. + This is also used by other scripts from the xdg-utils family. + </simpara> + <simpara> + Setting this variable has the possibility to break a lot of things. It is primarily intended for testing and quick-fixing. <emphasis>If you are not the local system administrator or a distribution maintainer leave it alone!</emphasis> + </simpara> + <simpara> + The <option>--get-backend</option> option will print the used backend. + </simpara> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1 id="seealso"> + <title>See Also</title> + <para><citerefentry><refentrytitle>realpath</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>readlink</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + </para> + </refsect1> + <refsect1 id="examples"> + <title>Examples</title> + <para> +<programlisting> +xdg-realpath -- /./bin +</programlisting> + Canonicalizes the path to <code>/./bin</code>, on most systems the output will be <code>/bin</code> or <code>/usr/bin</code>. + </para> + <para> +<programlisting> +xdg-realpath -- foo.txt +</programlisting> + Will print the absolute path of the file foo.txt or inform you that foo.txt doesn't exist. + </para> + <para> +<programlisting> +xdg-realpath -- . +</programlisting> + Will print the present working directory path with symbolic links resolved. + </para> + </refsect1> +</refentry> 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 <baschdel@disroot.org> +# +# 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 +} |