From 776c3f5590d75337271a9f88c8150d70b24b0600 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Wed, 22 Apr 2020 08:41:59 +0300 Subject: [PATCH 1/7] kiss: Drop rsync --- kiss | 57 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) 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'. From 8a49cd6911c767cae448add04eea12cce912802c Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Wed, 22 Apr 2020 08:48:16 +0300 Subject: [PATCH 2/7] kiss: Skip /etc/ --- kiss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kiss b/kiss index af887b5..c7ecdcc 100755 --- a/kiss +++ b/kiss @@ -1013,7 +1013,7 @@ pkg_install() { while read -r line; do perms=$(stat -c %a "$tar_dir/$pkg_name/$line") - case $line in + case $line in /etc/*) ;; */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; *) cp -Pp "$tar_dir/$pkg_name/$line" "${line%/*}" ;; esac @@ -1066,7 +1066,7 @@ pkg_install() { while read -r line; do perms=$(stat -c %a "$tar_dir/$pkg_name/$line") - case $line in + case $line in /etc/*) ;; */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; *) [ -e "$line" ] || cp -p "$tar_dir/$pkg_name/$line" "${line%/*}" esac From c8029d6a71bdf256b23a9dc8d4c1755cdd16b02f Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Wed, 22 Apr 2020 09:06:43 +0300 Subject: [PATCH 3/7] kiss: Move new install method to function --- kiss | 51 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/kiss b/kiss index c7ecdcc..b581651 100755 --- a/kiss +++ b/kiss @@ -813,6 +813,21 @@ pkg_swap() { sed -i "$(esc "$PWD/$alt" "$2")" "../installed/$1/manifest" } +pkg_install_files() ( + awk '{L[n++]=$0}END{while(n--)print L[n]}' "$2/$pkg_db/${2##*/}/manifest" | + + while read -r line; do + perms=$(stat -c %a "$2/$line") + + case $line in /etc/*) ;; + */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; + *) test "$1" "$line" || cp -fPp "$2/$line" "${line%/*}" ;; + esac + + chown -h root:root "$line" + done +) + pkg_etc() { [ -d "$tar_dir/$pkg_name/etc" ] || return 0 @@ -1002,24 +1017,8 @@ 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 ||: - # Ensure that the tarball's manifest is correct by checking that - # each file and directory inside of it actually exists. - # - # 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 /etc/*) ;; - */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; - *) cp -Pp "$tar_dir/$pkg_name/$line" "${line%/*}" ;; - esac - - chown root:root "$line" - done + # Install the package's files by iterating over its manifest. + pkg_install_files -z "$tar_dir/$pkg_name" # 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? @@ -1060,19 +1059,9 @@ pkg_install() { fi done ||: - 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 /etc/*) ;; - */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; - *) [ -e "$line" ] || cp -p "$tar_dir/$pkg_name/$line" "${line%/*}" - esac - - chown root:root "$line" - done + # Install the package's files a second time to fix any mess caused by the + # above removal of the previous version of the package. + pkg_install_files -e "$tar_dir/$pkg_name" # Reset 'trap' to its original value. Installation is done so # we no longer need to block 'Ctrl+C'. From 6e3064d0f870eafc4bacbcbd223e002b39d5b0f6 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Wed, 22 Apr 2020 09:18:12 +0300 Subject: [PATCH 4/7] kiss: Remove func subshell use --- kiss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kiss b/kiss index b581651..d130919 100755 --- a/kiss +++ b/kiss @@ -813,7 +813,7 @@ pkg_swap() { sed -i "$(esc "$PWD/$alt" "$2")" "../installed/$1/manifest" } -pkg_install_files() ( +pkg_install_files() { awk '{L[n++]=$0}END{while(n--)print L[n]}' "$2/$pkg_db/${2##*/}/manifest" | while read -r line; do @@ -826,7 +826,7 @@ pkg_install_files() ( chown -h root:root "$line" done -) +} pkg_etc() { [ -d "$tar_dir/$pkg_name/etc" ] || return 0 From 33cdc648037b40e57138b6e006a2141a39bbe924 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Wed, 22 Apr 2020 09:23:19 +0300 Subject: [PATCH 5/7] kiss: Add comments to new install function --- kiss | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/kiss b/kiss index d130919..1eb0370 100755 --- a/kiss +++ b/kiss @@ -814,16 +814,28 @@ pkg_swap() { } pkg_install_files() { + # Reverse the manifest file so that we start shallow and go + # deeper as we iterate over each item. This is needed so that + # directories are created going down the tree. awk '{L[n++]=$0}END{while(n--)print L[n]}' "$2/$pkg_db/${2##*/}/manifest" | while read -r line; do + # Grab the octal permissions so that directory creation + # preserves permissions. perms=$(stat -c %a "$2/$line") + # Copy files and create directories (preserving permissions), + # skipping anything located in /etc/. + # + # The 'test' will run with '-e' for no-overwrite and '-z' + # for overwrite. case $line in /etc/*) ;; */) [ -d "$line" ] || mkdir -m "$perms" "$line" ;; *) test "$1" "$line" || cp -fPp "$2/$line" "${line%/*}" ;; esac + # Set the ownership of the result to root:root. This is + # KISS' method to avoid the whole fakeroot mess. chown -h root:root "$line" done } From c5421699973a6520ad3f302efebd068aa70c3a82 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Wed, 22 Apr 2020 09:37:46 +0300 Subject: [PATCH 6/7] kiss: Add install output --- kiss | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/kiss b/kiss index 1eb0370..f610274 100755 --- a/kiss +++ b/kiss @@ -814,12 +814,16 @@ pkg_swap() { } pkg_install_files() { + # Store the total lines in the manifest file for use in the + # installation counter output. + man_tot=$(wc -l < "$2/$pkg_db/${2##*/}/manifest") + # Reverse the manifest file so that we start shallow and go # deeper as we iterate over each item. This is needed so that # directories are created going down the tree. awk '{L[n++]=$0}END{while(n--)print L[n]}' "$2/$pkg_db/${2##*/}/manifest" | - while read -r line; do + while read -r line; do i=$((i+1)) # Grab the octal permissions so that directory creation # preserves permissions. perms=$(stat -c %a "$2/$line") @@ -837,7 +841,11 @@ pkg_install_files() { # Set the ownership of the result to root:root. This is # KISS' method to avoid the whole fakeroot mess. chown -h root:root "$line" + + printf '%s %s (%s)\e[K\r' "$3" "$i/$man_tot" "$line" done + + printf '\n' } pkg_etc() { @@ -1030,7 +1038,7 @@ pkg_install() { cp -f "$sys_db/$pkg_name/etcsums" "$mak_dir/c" 2>/dev/null ||: # Install the package's files by iterating over its manifest. - pkg_install_files -z "$tar_dir/$pkg_name" + pkg_install_files -z "$tar_dir/$pkg_name" "Installing file" # 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? @@ -1073,7 +1081,7 @@ pkg_install() { # Install the package's files a second time to fix any mess caused by the # above removal of the previous version of the package. - pkg_install_files -e "$tar_dir/$pkg_name" + pkg_install_files -e "$tar_dir/$pkg_name" " Checking file" # Reset 'trap' to its original value. Installation is done so # we no longer need to block 'Ctrl+C'. From 57e27f73cc94ae4cf49faf482b09cf5a300e43d9 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Wed, 22 Apr 2020 13:50:02 +0300 Subject: [PATCH 7/7] kiss: Set permissions for all non dirs --- kiss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kiss b/kiss index f610274..98dc600 100755 --- a/kiss +++ b/kiss @@ -842,6 +842,13 @@ pkg_install_files() { # KISS' method to avoid the whole fakeroot mess. chown -h root:root "$line" + # Preserve permissions by using chmod. This runs after + # chown as chown will reset suid/guid when ownership changes. + # + # This only runs on non-directories as we desire the reset + # behavior mentioned above. + [ -d "$line" ] || chmod "$perms" "$line" + printf '%s %s (%s)\e[K\r' "$3" "$i/$man_tot" "$line" done