#!/bin/sh # # Copyright © 2020 Helmut Grohne # Copyright © 2020 Guillem Jover # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set -e PROGNAME=$(basename "$0") version="unknown" EOL="\n" PKGDATADIR_DEFAULT=src PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}" # shellcheck source=src/sh/dpkg-error.sh . "$PKGDATADIR/sh/dpkg-error.sh" show_version() { cat <...] Options: -z, --zero end output line with NUL, not newline. --instdir set the root directory. --root set the root directory. --version show the version. -?, --help show this help message. END } canonicalize() { local src="$1" local root="$DPKG_ROOT" local loop=0 local result="$root" local dst # Check whether the path is relative and make it absolute otherwise. if [ "$src" = "${src#/}" ]; then src="$(pwd)/$src" src="${src#"$root"}" fi # Remove prefixed slashes. while [ "$src" != "${src#/}" ]; do src=${src#/} done while [ -n "$src" ]; do # Get the first directory component. prefix=${src%%/*} # Remove the first directory component from src. src=${src#"$prefix"} # Remove prefixed slashes. while [ "$src" != "${src#/}" ]; do src=${src#/} done # Resolve the first directory component. if [ "$prefix" = . ]; then # Ignore, stay at the same directory. : elif [ "$prefix" = .. ]; then # Go up one directory. result=${result%/*} if [ -n "$root" ] && [ "${result#"$root"}" = "$result" ]; then result="$root" fi elif [ -h "$result/$prefix" ]; then loop=$((loop + 1)) if [ "$loop" -gt 25 ]; then error "too many levels of symbolic links" fi # Resolve the symlink within $result. dst=$(readlink "$result/$prefix") case "$dst" in /*) # Absolute pathname, reset result back to $root. result=$root src="$dst${src:+/$src}" # Remove prefixed slashes. while [ "$src" != "${src#/}" ]; do src=${src#/} done ;; *) # Relative pathname. src="$dst${src:+/$src}" ;; esac else # Otherwise append the prefix. result="$result/$prefix" fi done # We are done, print the resolved pathname, w/o $root. result="${result#"$root"}" printf "%s$EOL" "${result:-/}" } setup_colors DPKG_ROOT="${DPKG_ROOT:-}" export DPKG_ROOT while [ $# -ne 0 ]; do case "$1" in -z|--zero) EOL="\0" ;; --instdir|--root) shift DPKG_ROOT=$1 ;; --instdir=*) DPKG_ROOT="${1#--instdir=}" ;; --root=*) DPKG_ROOT="${1#--root=}" ;; --version) show_version exit 0 ;; --help|-\?) show_usage exit 0 ;; --) shift pathname="$1" ;; -*) badusage "unknown option: $1" ;; *) pathname="$1" ;; esac shift done # Normalize root directory. DPKG_ROOT="${DPKG_ROOT:+$(realpath "$DPKG_ROOT")}" # Remove default root dir. if [ "$DPKG_ROOT" = "/" ]; then DPKG_ROOT="" fi [ -n "$pathname" ] || badusage "missing pathname" if [ "${pathname#"$DPKG_ROOT"}" != "$pathname" ]; then error "link '$pathname' includes root prefix '$DPKG_ROOT'" fi canonicalize "$pathname" exit 0