build: fix opkg install step for large package selection
authorAlexander Egorenkov <egorenar-dev@posteo.net>
Fri, 9 Apr 2021 23:32:44 +0000 (01:32 +0200)
committerPaul Spooren <mail@aparcar.org>
Wed, 12 May 2021 09:13:53 +0000 (11:13 +0200)
When the list of packages to be installed in a built image exceeds a certain
number, then 'opkg install' executed for target '$(curdir)/install' in
package/Makefile fails with: /usr/bin/env: Argument list too long.

On Linux, the length of a command-line parameter is limited by
MAX_ARG_STRLEN to max 128 kB.

* https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/binfmts.h#L15
* https://www.in-ulm.de/~mascheck/various/argmax/

To solve the problem, store the package list being passed to 'opkg install'
in a temporary file and use the shell command substitution to pass the
content of the file to 'opkg install'. This guarantees that the length of
the command-line parameters passed to the bash shell is short.

The following bash script demonstrates the problem:
----------------------------------------------------------------------------
count=${1:-1000}

FILES=""
a_file="/home/egorenar/Repositories/openwrt-rel/bin/targets/alpine/generic/packages/base-files_1414-r16464+19-e887049fbb_arm_cortex-a15_neon-vfpv4.ipk"

for i in $(seq 1 $count); do
FILES="$FILES $a_file"
done

env bash -c "echo $FILES >/dev/null"
echo "$FILES" | wc -c
----------------------------------------------------------------------------

Test run:
----------------------------------------------------------------------------
$ ./test.sh 916
130989
$ ./test.sh 917
./test.sh: line 14: /bin/env: Argument list too long
131132
----------------------------------------------------------------------------

Signed-off-by: Alexander Egorenkov <egorenar-dev@posteo.net>
[reword commit subject]
Signed-off-by: Paul Spooren <mail@aparcar.org>
package/Makefile

index ec503dc5273d43d6cec3699e50dd654f23ceda99..209be34674747a728606f0c8b2d7dbcd2930ba7b 100644 (file)
@@ -66,8 +66,10 @@ $(curdir)/install: $(TMP_DIR)/.build $(curdir)/merge $(if $(CONFIG_TARGET_PER_DE
        - find $(STAGING_DIR_ROOT) -type d | $(XARGS) chmod 0755
        rm -rf $(TARGET_DIR) $(TARGET_DIR_ORIG)
        mkdir -p $(TARGET_DIR)/tmp
-       $(call opkg,$(TARGET_DIR)) install \
-               $(call opkg_package_files,$(foreach pkg,$(shell cat $(PACKAGE_INSTALL_FILES) 2>/dev/null),$(pkg)$(call GetABISuffix,$(pkg))))
+       $(file >$(TMP_DIR)/opkg_install_list,\
+         $(call opkg_package_files,\
+           $(foreach pkg,$(shell cat $(PACKAGE_INSTALL_FILES) 2>/dev/null),$(pkg)$(call GetABISuffix,$(pkg)))))
+       $(call opkg,$(TARGET_DIR)) install $$(cat $(TMP_DIR)/opkg_install_list)
        @for file in $(PACKAGE_INSTALL_FILES); do \
                [ -s $$file.flags ] || continue; \
                for flag in `cat $$file.flags`; do \