From 8d2f4702950709ca9a6e26f420fac88a811821ca Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Thu, 30 Apr 2020 19:38:37 +0300 Subject: [PATCH] kiss: Various portability fixes. - Added POSIX shell implementation of the 'readlink' utility for use _only_ when the 'readlink' utility is not available. - Made tar usage more portable. All that is left now is the removal of --strip-components 1 for full (presumed) portability. - Swapped from sha256sum to shasum as it's more portable. This is still not a full solution. Here's a checklist of where we currently are: POSIX Core utilities (depends coreutils) - [x] sh (POSIX) - [x] find (POSIX) -type f, -type d, -exec {} [+;], -o, -print, ! - [x] ls (POSIX) -l, -d - [x] sed (POSIX) -n, s///g, //d - [x] grep (POSIX) -l, -F, -x, -f, -q, -v - [x] sort (POSIX) -r, -u, -k - [x] tee (POSIX) - [x] date (POSIX) - [x] mkdir (POSIX) -p - [x] rm (POSIX) -f, -r - [x] rmdir (POSIX) - [x] cp (POSIX) -f, -P, -p, -L, -R - [x] mv (POSIX) -f - [x] chown (POSIX) -h - [x] diff (POSIX) -U BSD utilities - [x] install (BSD, not POSIX) (still portable) -o, -g, -m, -d Misc - [x] readlink (NOT POSIX) (fallback shell implementation) - [x] su* (sudo, doas, su) (in order, optional) - [x] git (downloads from git) (must link to curl) Compiler/libc utilities (depends cc & libc) - [x] readelf (Part of compiler toolchain) (GNU, LLVM or elfutils) - [x] strip (Part of compiler toolchain) (GNU, LLVM or elfutils) - [x] ldd (Part of libc) Tarball compression - [ ] tar (must have --strip-components) (busybox, GNU, libarchive)) - [x] bzip2 (widely used) -d, -z - [x] xz (widely used) -d, -z, -c, -T - [x] gzip (widely used) -d, -6 - [x] zstd (optional) -d, -z, -c - [x] unzip (optional) - [ ] shasum (checksums) (NO standard. Portable across Linux/BSD) --- kiss | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/kiss b/kiss index 8c34eab..086840d 100755 --- a/kiss +++ b/kiss @@ -98,6 +98,51 @@ decompress() { esac < "$1" } +readlink() { + # This is a 'readlink' utility written with POSIX utilities. + # 'ls' is used to obtain the target of the symlink. + # + # This is fine _despite_ the usual gaggle about 'ls' and its + # use in scripting. The POSIX specification states that the + # link target must be the exact contents of the link. + # + # The specification: + # + # > If the file is a symbolic link and the -L option is not + # specified, this information shall be about the link + # itself and the field shall be of the form: + # + # > "%s -> %s", , + + # Ignore '-f' if passed to the function to maintain + # compatibility with regular 'readlink'. + [ "$1" = -f ] && shift + + # Go to the file's directory and follow any symlinks along + # the way. This is fine as we're safe to assume that all + # input is a full path to something. + cd -P "${1%/*}" + + # Grab the file's information from 'ls' and give the fully + # resolved path to the symlink file as input. + lso=$(ls -ld "$PWD/${1##*/}") target= + + # Strip everything before the nearest '->' (arrow) and + # construct the final path. If the file isn't a symlink, just + # print it as-is. + case $lso in *' -> '*) + target=${lso##*" -> "} target=$PWD/${target##*/} + esac + + # If we've failed to resolve to anything, fallback to treating + # the file as if it weren't a symlink. This also handles cases + # where a file may include ' -> ' in its name. + [ -e "$target" ] || target=$PWD/${1##*/} + + cd - >/dev/null + printf '%s\n' "$target" +} + pkg_lint() { log "$1" "Checking repository files" @@ -289,7 +334,7 @@ pkg_extract() { # which allows for manual extraction. *://*.tar|*://*.tar.??|*://*.tar.???|*://*.tar.????|*://*.tgz) decompress "$src_dir/$1/${src##*/}" | - tar xf - --strip-components 1 || + "$tar" xf - --strip-components 1 || die "$1" "Couldn't extract ${src##*/}" ;; @@ -420,7 +465,7 @@ pkg_fixdeps() { # Extract the file path from 'ldd' output. dep=${dep#* => } dep=${dep% *} - dep=$(readlink -f "$dep") + dep=$("$readlink" -f "$dep") # Figure out which package owns the file. own=$("$grep" -lFx "${dep##$KISS_ROOT}" "$@") @@ -477,7 +522,7 @@ pkg_etcsums() ( find etc -type f -exec shasum -a 256 {} + > "$pkg_dir/$1/$pkg_db/$1/etcsums" ) -pkg_tar() { +pkg_tar() ( # Create a tarball from the built package's files. # This tarball also contains the package's database entry. log "$1" "Creating tarball" @@ -485,8 +530,12 @@ pkg_tar() { # Read the version information to name the package. read -r version release < "$(pkg_find "$1")/version" + # Use 'cd' to avoid needing tar's '-C' flag which may not + # be portable across implementations. + cd "$pkg_dir/$1" + # Create a tarball from the contents of the built package. - "$tar" cf - -C "$pkg_dir/$1" . | case ${KISS_COMPRESS:=gz} in + "$tar" cf - . | case ${KISS_COMPRESS:=gz} in bz2) bzip2 -z ;; gz) gzip -6 ;; xz) xz -zT 0 ;; @@ -494,7 +543,7 @@ pkg_tar() { esac > "$bin_dir/$1#$version-$release.tar.${KISS_COMPRESS:=gz}" log "$1" "Successfully created tarball" -} +) pkg_build() { # Build packages and turn them into packaged tarballs. This function @@ -696,7 +745,7 @@ pkg_conflicts() { case $file in */) continue; esac printf '%s/%s\n' \ - "$(readlink -f "$KISS_ROOT/${file%/*}" 2>/dev/null)" \ + "$("$readlink" -f "$KISS_ROOT/${file%/*}" 2>/dev/null)" \ "${file##*/}" done < "$tar_dir/$1/$pkg_db/$1/manifest" > "$cac_dir/$pid-m" @@ -1027,7 +1076,11 @@ pkg_install() { # # Running this step as soon as possible allows us to also check # the validity of the tarball and bail out early if needed. - decompress "$tar_file" | "$tar" pxf - -C "$tar_dir/$pkg_name" + ( + cd "$tar_dir/$pkg_name" + + decompress "$tar_file" | "$tar" pxf - + ) # Naively assume that the existence of a manifest file is all # that determines a valid KISS package from an invalid one. @@ -1474,6 +1527,10 @@ main() { # of the log files the package manager creates uring builds. time=$(date '+%Y-%m-%d-%H:%M') + # Check to see if the readlink command exists in the system. If it does + # not, fallback to a POSIX shell implementation of 'readlink'. + readlink=$(command -v readlink) || readlink=readlink + # Make note of the user's current ID to do root checks later on. # This is used enough to warrant a place here. uid=$(id -u)