[PATCH 1/3] base-files: sysupgrade: add tar.sh with helpers for building archives
Jo-Philipp Wich
jo at mein.io
Tue Feb 27 13:41:00 PST 2024
Hi Rafał,
thanks for taking are of this. Please find some comments below.
Am 2/26/24 um 15:14 schrieb Rafał Miłecki:
> From: Jo-Philipp Wich <jo at mein.io>
>
> This allows building uncompressed tar archives from shell scripts (and
> compressing them later if needed)
>
> Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
> ---
> package/base-files/files/lib/upgrade/tar.sh | 84 +++++++++++++++++++++
> 1 file changed, 84 insertions(+)
> create mode 100644 package/base-files/files/lib/upgrade/tar.sh
>
> diff --git a/package/base-files/files/lib/upgrade/tar.sh b/package/base-files/files/lib/upgrade/tar.sh
> new file mode 100644
> index 0000000000..00057dd760
> --- /dev/null
> +++ b/package/base-files/files/lib/upgrade/tar.sh
> @@ -0,0 +1,84 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later OR MIT
> +
> +__tar_print_padding() {
> + [ $1 -eq 0 ] || dd if=/dev/zero bs=$1 count=1 2>/dev/null
> +}
> +
> +__tar_make_member() {
> + local name="$1"
> + local content="$2"
> + local username="$3"
> + local groupname="$4"
> + local mtime="$5"
> + local mode=644
I think the uid and gid values should correspond to the given username
and groupname values. Something like this would probably work:
local uid=$(id -u "$username")
local gid=$(sed -rne "s#^$groupname:[^:]*:([0-9]+):.*\$#\1#p" /etc/group)
> + local uid=0
> + local gid=0
> + local size=${#content}
> + local type=0
> + local link=""
> +
> + # 100 byte of padding bytes, using 0x01 since the shell does not tolate null bytes in strings
> + local pad=$'\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1'
> +
> + # validate name
> + if [ "${name:0:1}" = "/" ]; then
> + name="${name:1}"
> + fi
> +
> + # truncate string header values to their maximum length
> + name=${name:0:100}
> + link=${link:0:100}
> + username=${username:0:32}
> + groupname=${groupname:0:32}
> +
> + # construct header part before checksum field
> + local header1="${name}${pad:0:$((100 - ${#name}))}"
> + header1="${header1}$(printf '%07d\1' $mode)"
> + header1="${header1}$(printf '%07o\1' $uid)"
> + header1="${header1}$(printf '%07o\1' $gid)"
> + header1="${header1}$(printf '%011o\1' $size)"
> + header1="${header1}$(printf '%011o\1' $mtime)"
> +
> + # construct header part after checksum field
> + local header2="$(printf '%d' $type)"
> + header2="${header2}${link}${pad:0:$((100 - ${#link}))}"
> + header2="${header2}ustar ${pad:0:1}"
> + header2="${header2}${username}${pad:0:$((32 - ${#username}))}"
> + header2="${header2}${groupname}${pad:0:$((32 - ${#groupname}))}"
> +
> + # calculate checksum over header fields
> + local checksum=0
> + for byte in $(printf '%s%8s%s' "$header1" "" "$header2" | tr '\1' '\0' | hexdump -ve '1/1 "%u "'); do
> + checksum=$((checksum + byte))
> + done
> +
> + # print member header, padded to 512 byte
> + printf '%s%06o\0 %s' "$header1" $checksum "$header2" | tr '\1' '\0'
> + __tar_print_padding 183
I checked and noticed that `dd` accepts a `count` value of 0, so we can
inline `__tar_print_padding()` (whose sole purpose was the != 0 check)
and get rid of the extra function:
dd if=/dev/zero bs=183 count=1 2>/dev/null
> +
> + # print content data, padded to multiple of 512 byte
> + printf "%s" "$content"
> + __tar_print_padding $((512 - (size % 512)))
Inline this `__tar_print_padding()` as (count may be zero):
dd if=/dev/zero bs=1 count=$((512 - (size % 512))) 2>/dev/null
> +}
> +
> +tar_make_member_from_file() {
> + local name="$1"
> + local username="$(ls -l "$1" | tr -s ' ' | cut -d ' ' -f 3)"
> + local groupname="$(ls -l "$1" | tr -s ' ' | cut -d ' ' -f 4)"
> +
> + __tar_make_member "$name" "$(cat $name)" "$username" "$groupname" "$(date +%s -r "$1")"
> +}
> +
> +tar_make_member_inline() {
> + local name="$1"
> + local content="$2"
> + local username="${3:-root}"
> + local groupname="${4:-root}"
> + local mtime="${5:-$(date +%s)}"
> +
> + __tar_make_member "$name" "$content" "$username" "$groupname" "$mtime"
> +}
> +
> +tar_close() {
> + __tar_print_padding 1024
Inline this `__tar_print_padding()` as:
dd if=/dev/zero bs=1024 count=1 2>/dev/null
> +}
~ Jo
More information about the openwrt-devel
mailing list