Re: [PATCH 1/3] base-files: sysupgrade: add tar.sh with helpers for building archives
On 26.02.2024 22:27, Paul D wrote: 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 00..00057dd760 --- /dev/null +++ b/package/base-files/files/lib/upgrade/tar.sh @@ -0,0 +1,84 @@ No shebang? Files /lib/upgrade/*.sh are for including. +# 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 + local uid=0 + local gid=0 + local size=${#content} + local type=0 + local link="" + recommend that they're ordered here same as struct order: struct posix_header { /* byte offset */ char name[100]; /* 0 */ char mode[8]; /* 100 */ char uid[8]; /* 108 */ char gid[8]; /* 116 */ char size[12]; /* 124 */ char mtime[12]; /* 136 */ char chksum[8]; /* 148 */ char typeflag; /* 156 */ char linkname[100]; /* 157 */ char magic[6]; /* 257 */ char version[2]; /* 263 */ char uname[32]; /* 265 */ char gname[32]; /* 297 */ char devmajor[8]; /* 329 */ char devminor[8]; /* 337 */ char prefix[155]; /* 345 */ /* 500 */ }; I'm not sure about it. In the first place I want code to be easy to understand and maintain. Using some non-natural order (like messing with order of argument variables and local variables) will be confusing. + 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' + maybe try: local pad=$(printf '\1%.0s' $(seq 100)) They produce the same result I believe: # echo $'\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' | md5sum 59c89925a4ef5bee948db1ec5dc9a4c4 - # echo $(printf '\1%.0s' $(seq 100)) | md5sum 59c89925a4ef5bee948db1ec5dc9a4c4 - The first is longer however it avoids two subshell executions. I don't think there's a single winner here. ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel
Re: [PATCH 1/3] base-files: sysupgrade: add tar.sh with helpers for building archives
The sender domain has a DMARC Reject/Quarantine policy which disallows sending mailing list messages using the original "From" header. To mitigate this problem, the original message has been wrapped automatically by the mailing list software.--- Begin Message --- Sent with Proton Mail secure email. On Tuesday, February 27th, 2024 at 15:46, Eric wrote: > On Tuesday, February 27th, 2024 at 13:41, Jo-Philipp Wich j...@mein.io wrote: > > > 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) > > > Does this do the same thing? > > local gid=$(uid -g "$groupname") OOPS typo, 'id -g ...' --- End Message --- ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel
Re: [PATCH 1/3] base-files: sysupgrade: add tar.sh with helpers for building archives
The sender domain has a DMARC Reject/Quarantine policy which disallows sending mailing list messages using the original "From" header. To mitigate this problem, the original message has been wrapped automatically by the mailing list software.--- Begin Message --- On Tuesday, February 27th, 2024 at 13:41, Jo-Philipp Wich wrote: > 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) Does this do the same thing? local gid=$(uid -g "$groupname") Eric --- End Message --- ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel
Re: [PATCH 1/3] base-files: sysupgrade: add tar.sh with helpers for building archives
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 This allows building uncompressed tar archives from shell scripts (and compressing them later if needed) Signed-off-by: Rafał Miłecki --- 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 00..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 ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel
Re: [PATCH 1/3] base-files: sysupgrade: add tar.sh with helpers for building archives
What tar standard are you aiming to adhere to? On 2024-02-26 15:14, Rafał Miłecki wrote: From: Jo-Philipp Wich This allows building uncompressed tar archives from shell scripts (and compressing them later if needed) Signed-off-by: Rafał Miłecki --- 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 00..00057dd760 --- /dev/null +++ b/package/base-files/files/lib/upgrade/tar.sh @@ -0,0 +1,84 @@ No shebang? +# 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 + local uid=0 + local gid=0 + local size=${#content} + local type=0 + local link="" + recommend that they're ordered here same as struct order: struct posix_header { /* byte offset */ char name[100]; /* 0 */ char mode[8]; /* 100 */ char uid[8]; /* 108 */ char gid[8]; /* 116 */ char size[12];/* 124 */ char mtime[12]; /* 136 */ char chksum[8]; /* 148 */ char typeflag;/* 156 */ char linkname[100]; /* 157 */ char magic[6];/* 257 */ char version[2]; /* 263 */ char uname[32]; /* 265 */ char gname[32]; /* 297 */ char devmajor[8]; /* 329 */ char devminor[8]; /* 337 */ char prefix[155]; /* 345 */ /* 500 */ }; + # 100 byte of padding bytes, using 0x01 since the shell does not tolate null bytes in strings tolerate? + 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' + maybe try: local pad=$(printf '\1%.0s' $(seq 100)) + # validate name + if [ "${name:0:1}" = "/" ]; then + name="${name:1}" + fi One liner: name=${name#/} + + # 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 + + # print content data, padded to multiple of 512 byte + printf "%s" "$content" + __tar_print_padding $((512 - (size % 512))) +} + +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 +} ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel
[PATCH 1/3] base-files: sysupgrade: add tar.sh with helpers for building archives
From: Jo-Philipp Wich This allows building uncompressed tar archives from shell scripts (and compressing them later if needed) Signed-off-by: Rafał Miłecki --- 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 00..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 + 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 + + # print content data, padded to multiple of 512 byte + printf "%s" "$content" + __tar_print_padding $((512 - (size % 512))) +} + +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 +} -- 2.35.3 ___ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel