Hi,

thanks a lot for not considering this bug as out-of-scope. :)

Quoting Gilles Filippini (2020-11-01 14:09:59)
> Gilles Filippini a écrit le 31/10/2020 à 15:11 :
> > Johannes 'josch' Schauer a écrit le 27/10/2020 à 18:45 :
> >> Package: libhdf5-openmpi-dev
> >> Version: 1.10.6+repack-2
> >> Severity: wishlist
> >>
> >> Hi,
> >>
> >> when installing libhdf5-openmpi-dev in a chroot that doesn't have /proc
> >> mounted, one will get the following error:
> >>
> >> Setting up libhdf5-openmpi-dev (1.10.6+repack-2) ...
> >> /var/lib/dpkg/info/libhdf5-openmpi-dev.postinst: line 56: /dev/fd/63: No 
> >> such file or directory
> >> dpkg: error processing package libhdf5-openmpi-dev (--configure):
> >>  installed libhdf5-openmpi-dev package post-installation script subprocess 
> >> returned error exit status 1
> >>
> >> The problem is, that the postinst script uses the bash-feature to write:
> >>
> >>     while read x; do ... done < <(cmd2 args ...)
> >>
> >> Fortunately, these instances can easily be rewritten as:
> >>
> >>     cmd2 args | while read x; do ... done
> >>
> >> Please consider making this change.
> > 
> > Unfortunately it doesn't work this way. Consider this test script:
> > 
> > $ cat test.sh
> > #!/bin/bash
> > declare -A foo bar
> > while read var; do
> >   foo["$var"]="$var"
> > done < <(seq 1 3)
> > seq 1 3 | while read var; do
> >   bar["$var"]="$var"
> > done
> > echo "foo=${foo[@]}"
> > echo "bar=${bar[@]}"
> > 
> > $ ./test.sh
> > foo=3 2 1
> > bar=
> > 
> > Using a pipe makes variable assignments into the while loop inefficient.
> > That's why I had to use the process substitution syntax.
> > 
> > Any other idea?

The problem is, that the while loop is part of the pipeline and each part of a
pipe is executed within its own subshell. This means that every variable that
is assigned inside the while loop is only is only valid for that subshell and
never gets propagated to the parent shell. Since bash 4.2, there is one
workaround:

$ cat test.sh
#!/bin/bash

declare -A arr1 arr2 arr3 arr4
# fill arr1
while read var; do
  arr1["$var"]="$var"
done < <(seq 1 3)
# fill arr2
seq 1 3 | while read var; do
  arr2["$var"]="$var"
done
# fill arr3
set -- $(seq 1 3)
while [ -n "$1" ]; do
  arr3["$1"]="$1"
  shift
done
# fill arr4
shopt -s lastpipe
seq 1 3 | while read var; do
  arr4["$var"]="$var"
done

echo "arr1=${arr1[@]}"
echo "arr2=${arr2[@]}"
echo "arr3=${arr3[@]}"
echo "arr4=${arr4[@]}"

$ ./test.sh
arr1=3 2 1
arr2=
arr3=3 2 1
arr4=3 2 1

Using "shopt -s lastpipe" the last part of the pipe is not run inside a new
subshell but inside the same shell as the parent and thus the variables
survive. I've also put your solution into the mix as a comparison.

> I've come up to this solution:
> 
> function read_alt_slaves () {
>   local -n slaves=$1
>   set -- $(echo "$2" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b
> while;: end;q}')  while [ -n "$1" ]; do
>     slaves["$1"]="$2"
>     shift 2
>   done
> }
> ...
>   declare -A slave_links slave_targets
>   read_alt_slaves slave_links "$mpi_alt_sig"
>   read_alt_slaves slave_targets "$mpi_alt_impl"
> 
> Can you confirm it would work with no /proc?

I think there are some problems with wrong line wrapping in your code. To avoid
any other copypaste mistake, I put a debdiff that worked for me as an
attachment to this mail. With that diff, I can successfully install and remove
libhdf5-openmpi-dev without /proc being mounted.

Thanks!

cheers, josch
diff -Nru hdf5-1.12.0+repack/debian/changelog hdf5-1.12.0+repack/debian/changelog
--- hdf5-1.12.0+repack/debian/changelog	2020-04-23 19:05:38.000000000 +0200
+++ hdf5-1.12.0+repack/debian/changelog	2020-11-27 11:24:05.000000000 +0100
@@ -1,3 +1,10 @@
+hdf5 (1.12.0+repack-1~exp2.1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * 
+
+ -- Johannes 'josch' Schauer <jo...@debian.org>  Fri, 27 Nov 2020 11:24:05 +0100
+
 hdf5 (1.12.0+repack-1~exp2) experimental; urgency=medium
 
   * Default plugindir per flavor
diff -Nru hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.postinst.in hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.postinst.in
--- hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.postinst.in	2020-03-28 17:10:48.000000000 +0100
+++ hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.postinst.in	2020-11-27 11:24:05.000000000 +0100
@@ -12,6 +12,20 @@
 update-alternatives \
 	--install /usr/lib/@MULTIARCH@/pkgconfig/hdf5.pc hdf5.pc /usr/lib/@MULTIARCH@/pkgconfig/hdf5-@FLAVOR@.pc @UA_PRIORITY_FLAVOR@ \
 
+# we use "set -- $(cmd); while ..." instead of "while ... < <(cmd)" because the
+# latter needs /proc being mounted so that the symlink from /dev/fd to
+# /proc/self/fd works. We use the "set -- $(cmd)" construct instead, so that
+# we do not require /proc being mounted to run the postinst and prerm scripts
+# See https://bugs.debian.org/973261
+function read_alt_slaves () {
+  local -n slaves=$1
+  set -- $(echo "$2" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b while;: end;q}')
+  while [ -n "$1" ]; do
+    slaves["$1"]="$2"
+    shift 2
+  done
+}
+
 # Install hdf5-mpi.pc as a new slave of the 'mpi' alternatives
 # See #953021
 # There is no way to simply add a new slave. We must parse the existing
@@ -23,14 +37,9 @@
   mpi_alt_sig=$(echo "$mpi_alt" | sed '/^$/q')
   mpi_alt_impl=$(echo "$mpi_alt" | sed -n -e '\!^Alternative: /usr/bin/mpicc.@FLAVOR@!p' -e '0,\!^Alternative: /usr/bin/mpicc.@FLAVOR@!d' -e '/^$/q' -e 'p')
   mpi_impl_priority=$(echo "$mpi_alt_impl" | sed -n '/^Priority: /{s/Priority: \(.*\)$/\1/;p}')
-  declare -A slave_links
-  while read slave; do
-    slave_links[${slave%% *}]="${slave#* }"
-  done < <(echo "$mpi_alt_sig" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b while;: end;q}')
-  declare -A slave_targets
-  while read slave; do
-    slave_targets[${slave%% *}]="${slave#* }"
-  done < <(echo "$mpi_alt_impl" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b while;: end;q}')
+  declare -A slave_links slave_targets
+  read_alt_slaves slave_links "$mpi_alt_sig"
+  read_alt_slaves slave_targets "$mpi_alt_impl"
   # At this point:
   # * slave_links holds all the slaves name,link pairs
   # * slave_targets holds all the slaves name,target pairs for our mpi flavor
diff -Nru hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.prerm.in hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.prerm.in
--- hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.prerm.in	2020-03-28 17:10:48.000000000 +0100
+++ hdf5-1.12.0+repack/debian/libhdf5-flavor-dev.prerm.in	2020-11-27 11:24:05.000000000 +0100
@@ -2,6 +2,20 @@
 
 set -e
 
+# we use "set -- $(cmd); while ..." instead of "while ... < <(cmd)" because the
+# latter needs /proc being mounted so that the symlink from /dev/fd to
+# /proc/self/fd works. We use the "set -- $(cmd)" construct instead, so that
+# we do not require /proc being mounted to run the postinst and prerm scripts
+# See https://bugs.debian.org/973261
+function read_alt_slaves () {
+  local -n slaves=$1
+  set -- $(echo "$2" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b while;: end;q}')
+  while [ -n "$1" ]; do
+    slaves["$1"]="$2"
+    shift 2
+  done
+}
+
 if [ "$1" != "upgrade" ]; then
   if [ "@FLAVOR@" != "serial" ]; then
     update-alternatives \
@@ -21,14 +35,9 @@
     mpi_alt_sig=$(echo "$mpi_alt" | sed '/^$/q')
     mpi_alt_impl=$(echo "$mpi_alt" | sed -n -e '\!^Alternative: /usr/bin/mpicc.@FLAVOR@!p' -e '0,\!^Alternative: /usr/bin/mpicc.@FLAVOR@!d' -e '/^$/q' -e 'p')
     mpi_impl_priority=$(echo "$mpi_alt_impl" | sed -n '/^Priority: /{s/Priority: \(.*\)$/\1/;p}')
-    declare -A slave_links
-    while read slave; do
-      slave_links[${slave%% *}]="${slave#* }"
-    done < <(echo "$mpi_alt_sig" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b while;: end;q}')
-    declare -A slave_targets
-    while read slave; do
-      slave_targets[${slave%% *}]="${slave#* }"
-    done < <(echo "$mpi_alt_impl" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b while;: end;q}')
+    declare -A slave_links slave_targets
+    read_alt_slaves slave_links "$mpi_alt_sig"
+    read_alt_slaves slave_targets "$mpi_alt_impl"
     # At this point:
     # * slave_links holds all the slaves name,link pairs
     # * slave_targets holds all the slaves name,target pairs for our mpi flavor
@@ -50,9 +59,7 @@
     mpi_alt=$(update-alternatives --query mpi)
     mpi_alt_sig=$(echo "$mpi_alt" | sed '/^$/q')
     declare -A slave_links_left
-    while read slave; do
-      slave_links_left[${slave%% *}]="${slave#* }"
-    done < <(echo "$mpi_alt_sig" | sed -n '/Slaves:/{: while;n;s/^ //;T end;p;b while;: end;q}')
+    read_alt_slaves slave_links_left "$mpi_alt_sig"
     if [ -z "${slave_links_left[hdf5-mpi.pc]}" ]; then
       update-alternatives --remove hdf5.pc /usr/lib/@MULTIARCH@/pkgconfig/hdf5-mpi.pc
     fi

Attachment: signature.asc
Description: signature

Reply via email to