apk-tools: implement compression of on-device scripts.tar

Default behavior for apk was to create an uncompressed scripts.tar
file.  Due to the structure of tar files, with fixed block
size and null padding, this file becomes very large on OpenWrt
installations where there are typically two scripts per package.
This could cause the raw tar file to easily grow to over 500KB,
whereas the compressed file is generally around 20-30KB.

When stored in the /rom partition of a squashfs device, the file
is compressed and this is not an issue.  But, as soon as you add
or delete a package, the scripts.tar file is fully expanded into
the /overlay partition and can cause issues on small-flash devices.

This issue was addressed in an upstream commit by detecting
whether the scripts.tar file is compressed (its name must be
exactly 'scripts.tar.gz'), and then retaining that compression by
reading/writing the file using a compressed stream.

This commit applies a cherrypicked patch for the upstream commit, and
compresses the scripts.tar during construction of the device rootfs.

Fixes: https://github.com/openwrt/openwrt/issues/17108
Link: 012cdcfdf9
Signed-off-by: Eric Fahlgren <ericfahlgren@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/20795
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
Eric Fahlgren 2025-11-15 08:32:00 -08:00 committed by Robert Marko
parent dc420acc77
commit 5d85657f6d
3 changed files with 58 additions and 3 deletions

View file

@ -78,7 +78,7 @@ define prepare_rootfs
cd $(1); \
if [ -n "$(CONFIG_USE_APK)" ]; then \
IPKG_POSTINST_PATH=./lib/apk/db/*.post-install; \
$(STAGING_DIR_HOST)/bin/tar -C ./lib/apk/db/ -xf ./lib/apk/db/scripts.tar --wildcards "*.post-install"; \
$(STAGING_DIR_HOST)/bin/tar -C ./lib/apk/db/ -xzf ./lib/apk/db/scripts.tar.gz --wildcards "*.post-install"; \
else \
IPKG_POSTINST_PATH=./usr/lib/opkg/info/*.postinst; \
fi; \
@ -89,7 +89,7 @@ define prepare_rootfs
echo "postinst script $$script has failed with exit code $$ret" >&2; \
exit 1; \
fi; \
[ -n "$(CONFIG_USE_APK)" ] && $(STAGING_DIR_HOST)/bin/tar --delete -f ./lib/apk/db/scripts.tar $$(basename $$script); \
[ -n "$(CONFIG_USE_APK)" ] && $(STAGING_DIR_HOST)/bin/tar --delete -zf ./lib/apk/db/scripts.tar.gz $$(basename $$script); \
done; \
if [ -z "$(CONFIG_USE_APK)" ]; then \
$(if $(IB),,awk -i inplace \

View file

@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=apk
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_SOURCE_URL=https://gitlab.alpinelinux.org/alpine/apk-tools.git
PKG_SOURCE_PROTO:=git

View file

@ -0,0 +1,55 @@
diff --git a/doc/apk.8.scd b/doc/apk.8.scd
index bd15fe75d7a4..cbac8c6c8b7b 100644
--- a/doc/apk.8.scd
+++ b/doc/apk.8.scd
@@ -461,7 +461,8 @@ timeout 120
*/lib/apk/db/installed*
Database of installed packages and their contents.
-*/lib/apk/db/scripts.tar*
+*/lib/apk/db/scripts.tar*++
+*/lib/apk/db/scripts.tar.gz*
Collection of all package scripts from currently installed packages.
*/lib/apk/db/triggers*
diff --git a/src/apk_database.h b/src/apk_database.h
index 9f8670ac8ebb..10f1414c9e06 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -202,6 +202,7 @@ struct apk_database {
unsigned int compat_depversions : 1;
unsigned int sorted_names : 1;
unsigned int sorted_installed_packages : 1;
+ unsigned int scripts_tar : 1;
struct apk_dependency_array *world;
struct apk_id_cache *id_cache;
diff --git a/src/database.c b/src/database.c
index cbe58ebbf885..cb1b709140af 100644
--- a/src/database.c
+++ b/src/database.c
@@ -1255,8 +1255,11 @@ static int apk_db_read_layer(struct apk_database *db, unsigned layer)
}
if (!(flags & APK_OPENF_NO_SCRIPTS)) {
- r = apk_tar_parse(apk_istream_from_file(fd, "scripts.tar"),
- apk_read_script_archive_entry, db, db->id_cache);
+ struct apk_istream *is = apk_istream_from_file(fd, "scripts.tar");
+ if (!IS_ERR(is) || PTR_ERR(is) != -ENOENT) db->scripts_tar = 1;
+ else is = apk_istream_gunzip(apk_istream_from_file(fd, "scripts.tar.gz"));
+
+ r = apk_tar_parse(is, apk_read_script_archive_entry, db, db->id_cache);
if (!ret && r != -ENOENT) ret = r;
}
@@ -2128,8 +2131,9 @@ static int apk_db_write_layers(struct apk_database *db)
continue;
}
ld->installed = apk_ostream_to_file(ld->fd, "installed", 0644);
- ld->scripts = apk_ostream_to_file(ld->fd, "scripts.tar", 0644);
ld->triggers = apk_ostream_to_file(ld->fd, "triggers", 0644);
+ if (db->scripts_tar) ld->scripts = apk_ostream_to_file(ld->fd, "scripts.tar", 0644);
+ else ld->scripts = apk_ostream_gzip(apk_ostream_to_file(ld->fd, "scripts.tar.gz", 0644));
if (i == APK_DB_LAYER_ROOT)
os = apk_ostream_to_file(db->root_fd, apk_world_file, 0644);