diff --git a/kiss b/kiss index 6b3e8c0..af887b5 100755 --- a/kiss +++ b/kiss @@ -957,7 +957,7 @@ pkg_install() { log "$pkg_name" "Extracting $tar_file" # The tarball is extracted to a temporary directory where its - # contents are then "installed" to the filesystem using 'rsync'. + # contents are then "installed" to the filesystem. # # Running this step as soon as possible allows us to also check # the validity of the tarball and bail out early if needed. @@ -1002,25 +1002,24 @@ pkg_install() { cp -f "$sys_db/$pkg_name/manifest" "$mak_dir/m" 2>/dev/null ||: cp -f "$sys_db/$pkg_name/etcsums" "$mak_dir/c" 2>/dev/null ||: - # This rsync command is used to install the tarball's contents to the - # filesystem. Your first thought is most probably something along these - # lines; "Why don't you just use tar extraction for installation directly?" + # Ensure that the tarball's manifest is correct by checking that + # each file and directory inside of it actually exists. # - # The tar command has no real standard for available features, command-line - # flags or behavior. This makes satisfying the requirements for installation - # difficult and error-prone across implementations of tar. - # - # We need to exclude /etc from the tarball, ensure permissions are all owned - # by root:root, dump suid/guid permissions from directories and overwrite - # all existing files. - # - # Rsync ticks all boxes here and it being a "single implementation" of itself - # ensures portability everywhere so long as rsync is available. To top it all - # off, rsync is really handy to have around regardless. - pkg_rsync() { rsync --chown=root:root --chmod=Du-s,Dg-s,Do-s \ - -WhHKa --no-compress --exclude /etc "$1" \ - "$tar_dir/$pkg_name/" "$KISS_ROOT/"; } - pkg_rsync --info=progress2 + # The 'awk' command simply reverses the contents of the file so that + # directories are listed first. + awk '{L[n++]=$0}END{while(n--)print L[n]}' \ + "$tar_dir/$pkg_name/$pkg_db/$pkg_name/manifest" | + + while read -r line; do + perms=$(stat -c %a "$tar_dir/$pkg_name/$line") + + case $line in + */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; + *) cp -Pp "$tar_dir/$pkg_name/$line" "${line%/*}" ;; + esac + + chown root:root "$line" + done # Handle /etc/ files in a special way (via a 3-way checksum) to determine # how these files should be installed. Do we overwrite the existing file? @@ -1061,13 +1060,19 @@ pkg_install() { fi done ||: - # Install the package an additional two times. The first being to fix - # any potential issues (rare) with the above removal of old files. - # The second rsync call confirms that nothing else need to be done. - # - # This takes zero time at all if unneeded as rsync is incremental. - # If there is nothing to be done, nothing will be done. - { pkg_rsync --; pkg_rsync --; } ||: + awk '{L[n++]=$0}END{while(n--)print L[n]}' \ + "$tar_dir/$pkg_name/$pkg_db/$pkg_name/manifest" | + + while read -r line; do + perms=$(stat -c %a "$tar_dir/$pkg_name/$line") + + case $line in + */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; + *) [ -e "$line" ] || cp -p "$tar_dir/$pkg_name/$line" "${line%/*}" + esac + + chown root:root "$line" + done # Reset 'trap' to its original value. Installation is done so # we no longer need to block 'Ctrl+C'.