diff mbox series

[v4,3/7] classes-global/package_rpm.bbclass: Remove %pre and %postin for libc6

Message ID 59ba081c8c874065b6cdc050a2897422be4a7a59.1770707181.git.liezhi.yang@windriver.com
State New
Headers show
Series [v4,1/7] package_rpm.bbclass: Drop external dependency generator to support rpm 6 | expand

Commit Message

Robert Yang Feb. 10, 2026, 7:10 a.m. UTC
From: Robert Yang <liezhi.yang@windriver.com>

Fixed:
$ bitbake core-image-full-cmdline:do_testimage
%post(busybox-1.37.0-r0.x86_64_x32): execv(/bin/sh) pid 624
error: failed to exec scriptlet interpreter /bin/sh: No such file or directory

It is because busybox and libc6 depends on each other, busybox' elf files
depends on libc6, and libc6's postin depends on busybox' /bin/sh, the do_rootfs
works well is because dnf-native has set RPM_NO_CHROOT_FOR_SCRIPTS=1, but it
would be failed for a fresh rootfs.

In rpm 4.20.1, it let the installed files' Requires win, so it installed
busybox firstly, but in rpm 6.0.1, it let the postin's Requires win since
postin would run immediately after the files are installed, this does make
sense, so it installed busybox (which provides /bin/sh required by libc6'
postin) firstly, then we got the errors. I couldn't find which commit made this
change because a lot of files and functions are refactored during 4.20.1 and
6.0.0 (not .1), I also tried bisect, but failed because a lot of do_patch or
do_configure/do_compile failures for each build.

For libc6's the postin is:

  #!/bin/sh
  if [ x"$D" = "x" ]; then
      if [ -x /sbin/ldconfig ]; then /sbin/ldconfig ; fi
  fi

This doesn't make sense for lib6 since there is no /bin/sh or ldconfig when
libc6 is not ready yet, so we can just remove libc6's postin to fix the
problem.

And also remove the workarounds in oeqa/runtime/cases/dnf.py, they are not
needed any more since the circular dependency is fixed.

Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
---
 meta/classes-global/package_rpm.bbclass | 6 ++++--
 meta/lib/oeqa/runtime/cases/dnf.py      | 8 --------
 2 files changed, 4 insertions(+), 10 deletions(-)

Comments

Richard Purdie Feb. 10, 2026, 8:52 a.m. UTC | #1
On Mon, 2026-02-09 at 23:10 -0800, Robert Yang via lists.openembedded.org wrote:
> From: Robert Yang <liezhi.yang@windriver.com>
> 
> Fixed:
> $ bitbake core-image-full-cmdline:do_testimage
> %post(busybox-1.37.0-r0.x86_64_x32): execv(/bin/sh) pid 624
> error: failed to exec scriptlet interpreter /bin/sh: No such file or directory
> 
> It is because busybox and libc6 depends on each other, busybox' elf files
> depends on libc6, and libc6's postin depends on busybox' /bin/sh, the do_rootfs
> works well is because dnf-native has set RPM_NO_CHROOT_FOR_SCRIPTS=1, but it
> would be failed for a fresh rootfs.
> 
> In rpm 4.20.1, it let the installed files' Requires win, so it installed
> busybox firstly, but in rpm 6.0.1, it let the postin's Requires win since
> postin would run immediately after the files are installed, this does make
> sense, so it installed busybox (which provides /bin/sh required by libc6'
> postin) firstly, then we got the errors. I couldn't find which commit made this
> change because a lot of files and functions are refactored during 4.20.1 and
> 6.0.0 (not .1), I also tried bisect, but failed because a lot of do_patch or
> do_configure/do_compile failures for each build.
> 
> For libc6's the postin is:
> 
>   #!/bin/sh
>   if [ x"$D" = "x" ]; then
>       if [ -x /sbin/ldconfig ]; then /sbin/ldconfig ; fi
>   fi
> 
> This doesn't make sense for lib6 since there is no /bin/sh or ldconfig when
> libc6 is not ready yet, so we can just remove libc6's postin to fix the
> problem.
> 
> And also remove the workarounds in oeqa/runtime/cases/dnf.py, they are not
> needed any more since the circular dependency is fixed.
> 
> Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
> ---
>  meta/classes-global/package_rpm.bbclass | 6 ++++--
>  meta/lib/oeqa/runtime/cases/dnf.py      | 8 --------
>  2 files changed, 4 insertions(+), 10 deletions(-)
> 
> diff --git a/meta/classes-global/package_rpm.bbclass b/meta/classes-global/package_rpm.bbclass
> index f4dd779a52..526ac57982 100644
> --- a/meta/classes-global/package_rpm.bbclass
> +++ b/meta/classes-global/package_rpm.bbclass
> @@ -421,12 +421,14 @@ python write_specfile () {
>          spec_preamble_bottom.append('')
>  
>          # Now process scriptlets
> -        if splitrpreinst:
> +        # The libc6 shouldn't have %pre or %post to avoid circular dependency
> +        libc6 = '%slibc6' % (d.getVar('MLPREFIX') or '')
> +        if splitrpreinst and splitname != libc6:
>              spec_scriptlets_bottom.append('%%pre -n %s' % splitname)
>              spec_scriptlets_bottom.append('# %s - preinst' % splitname)
>              spec_scriptlets_bottom.append(splitrpreinst)
>              spec_scriptlets_bottom.append('')
> -        if splitrpostinst:
> +        if splitrpostinst and splitname != libc6:
>              spec_scriptlets_bottom.append('%%post -n %s' % splitname)
>              spec_scriptlets_bottom.append('# %s - postinst' % splitname)
>              spec_scriptlets_bottom.append(splitrpostinst)

I'm not happy about coding a "libc6" reference into the generic package
class. It does make me wonder if there is a similar issue with musl for
example and we'd end up with a longer hardcoded list.

Could/shouldn't we just not add that postinst for libc6? You could for
example force the value of pkg_postinst:libc6 during the packaging
process and empty the postinst instead.

Also the commit message explains the problem with the postinst but not
really why the preinst is a problem? What does that contain which is
problematic?

Cheers,

Richard
Robert Yang Feb. 10, 2026, 10:08 a.m. UTC | #2
Hi RP,

On 2/10/26 16:52, Richard Purdie wrote:
> On Mon, 2026-02-09 at 23:10 -0800, Robert Yang via lists.openembedded.org wrote:
>> From: Robert Yang <liezhi.yang@windriver.com>
>>
>> Fixed:
>> $ bitbake core-image-full-cmdline:do_testimage
>> %post(busybox-1.37.0-r0.x86_64_x32): execv(/bin/sh) pid 624
>> error: failed to exec scriptlet interpreter /bin/sh: No such file or directory
>>
>> It is because busybox and libc6 depends on each other, busybox' elf files
>> depends on libc6, and libc6's postin depends on busybox' /bin/sh, the do_rootfs
>> works well is because dnf-native has set RPM_NO_CHROOT_FOR_SCRIPTS=1, but it
>> would be failed for a fresh rootfs.
>>
>> In rpm 4.20.1, it let the installed files' Requires win, so it installed
>> busybox firstly, but in rpm 6.0.1, it let the postin's Requires win since
>> postin would run immediately after the files are installed, this does make
>> sense, so it installed busybox (which provides /bin/sh required by libc6'
>> postin) firstly, then we got the errors. I couldn't find which commit made this
>> change because a lot of files and functions are refactored during 4.20.1 and
>> 6.0.0 (not .1), I also tried bisect, but failed because a lot of do_patch or
>> do_configure/do_compile failures for each build.
>>
>> For libc6's the postin is:
>>
>>    #!/bin/sh
>>    if [ x"$D" = "x" ]; then
>>        if [ -x /sbin/ldconfig ]; then /sbin/ldconfig ; fi
>>    fi
>>
>> This doesn't make sense for lib6 since there is no /bin/sh or ldconfig when
>> libc6 is not ready yet, so we can just remove libc6's postin to fix the
>> problem.
>>
>> And also remove the workarounds in oeqa/runtime/cases/dnf.py, they are not
>> needed any more since the circular dependency is fixed.
>>
>> Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
>> ---
>>   meta/classes-global/package_rpm.bbclass | 6 ++++--
>>   meta/lib/oeqa/runtime/cases/dnf.py      | 8 --------
>>   2 files changed, 4 insertions(+), 10 deletions(-)
>>
>> diff --git a/meta/classes-global/package_rpm.bbclass b/meta/classes-global/package_rpm.bbclass
>> index f4dd779a52..526ac57982 100644
>> --- a/meta/classes-global/package_rpm.bbclass
>> +++ b/meta/classes-global/package_rpm.bbclass
>> @@ -421,12 +421,14 @@ python write_specfile () {
>>           spec_preamble_bottom.append('')
>>   
>>           # Now process scriptlets
>> -        if splitrpreinst:
>> +        # The libc6 shouldn't have %pre or %post to avoid circular dependency
>> +        libc6 = '%slibc6' % (d.getVar('MLPREFIX') or '')
>> +        if splitrpreinst and splitname != libc6:
>>               spec_scriptlets_bottom.append('%%pre -n %s' % splitname)
>>               spec_scriptlets_bottom.append('# %s - preinst' % splitname)
>>               spec_scriptlets_bottom.append(splitrpreinst)
>>               spec_scriptlets_bottom.append('')
>> -        if splitrpostinst:
>> +        if splitrpostinst and splitname != libc6:
>>               spec_scriptlets_bottom.append('%%post -n %s' % splitname)
>>               spec_scriptlets_bottom.append('# %s - postinst' % splitname)
>>               spec_scriptlets_bottom.append(splitrpostinst)
> 
> I'm not happy about coding a "libc6" reference into the generic package
> class. It does make me wonder if there is a similar issue with musl for
> example and we'd end up with a longer hardcoded list.
> 
> Could/shouldn't we just not add that postinst for libc6? You could for
> example force the value of pkg_postinst:libc6 during the packaging
> process and empty the postinst instead.

I think you meant add the following lines in glibc-package.inc:

pkg_postinst:glibc () {
     echo
}

We need an "echo" here, otherwise, meta/lib/oe/package.py would add the
"#!/bin/sh" to the postinst:

         if needs_ldconfig:
             bb.debug(1, 'adding ldconfig call to postinst for %s' % pkg)
             postinst = d.getVar('pkg_postinst:%s' % pkg)
             if not postinst:
                 postinst = '#!/bin/sh\n'
             postinst += d.getVar('ldconfig_postinst_fragment')
             d.setVar('pkg_postinst:%s' % pkg, postinst)

But this still doesn't work, because rpm will add the /bin/sh as the default
interpreter when not specified. And currently, meta/lib/oe/package.py
add the ldconfig_postinst_fragment automatically when find so files,
that the root cause, so how about we add a value like:

NEEDS_LDCONFIG:<pkg> = "0" or "1"

Then we can add the following line to glibc-package.inc to skip that.
NEEDS_LDCONFIG:libc6 = "0"

And also we need update meta/lib/oe/package.py to check the
NEEDS_LDCONFIG:pkg.

> 
> Also the commit message explains the problem with the postinst but not
> really why the preinst is a problem? What does that contain which is
> problematic?
> 

It is similar to posint, the prinst has a harder situation than postinst.

// Robert


> Cheers,
> 
> Richard
Robert Yang Feb. 10, 2026, 10:54 a.m. UTC | #3
On 2/10/26 18:08, Robert Yang wrote:
> Hi RP,
> 
> On 2/10/26 16:52, Richard Purdie wrote:
>> On Mon, 2026-02-09 at 23:10 -0800, Robert Yang via lists.openembedded.org wrote:
>>> From: Robert Yang <liezhi.yang@windriver.com>
>>>
>>> Fixed:
>>> $ bitbake core-image-full-cmdline:do_testimage
>>> %post(busybox-1.37.0-r0.x86_64_x32): execv(/bin/sh) pid 624
>>> error: failed to exec scriptlet interpreter /bin/sh: No such file or directory
>>>
>>> It is because busybox and libc6 depends on each other, busybox' elf files
>>> depends on libc6, and libc6's postin depends on busybox' /bin/sh, the do_rootfs
>>> works well is because dnf-native has set RPM_NO_CHROOT_FOR_SCRIPTS=1, but it
>>> would be failed for a fresh rootfs.
>>>
>>> In rpm 4.20.1, it let the installed files' Requires win, so it installed
>>> busybox firstly, but in rpm 6.0.1, it let the postin's Requires win since
>>> postin would run immediately after the files are installed, this does make
>>> sense, so it installed busybox (which provides /bin/sh required by libc6'
>>> postin) firstly, then we got the errors. I couldn't find which commit made this
>>> change because a lot of files and functions are refactored during 4.20.1 and
>>> 6.0.0 (not .1), I also tried bisect, but failed because a lot of do_patch or
>>> do_configure/do_compile failures for each build.
>>>
>>> For libc6's the postin is:
>>>
>>>    #!/bin/sh
>>>    if [ x"$D" = "x" ]; then
>>>        if [ -x /sbin/ldconfig ]; then /sbin/ldconfig ; fi
>>>    fi
>>>
>>> This doesn't make sense for lib6 since there is no /bin/sh or ldconfig when
>>> libc6 is not ready yet, so we can just remove libc6's postin to fix the
>>> problem.
>>>
>>> And also remove the workarounds in oeqa/runtime/cases/dnf.py, they are not
>>> needed any more since the circular dependency is fixed.
>>>
>>> Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
>>> ---
>>>   meta/classes-global/package_rpm.bbclass | 6 ++++--
>>>   meta/lib/oeqa/runtime/cases/dnf.py      | 8 --------
>>>   2 files changed, 4 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/meta/classes-global/package_rpm.bbclass b/meta/classes-global/ 
>>> package_rpm.bbclass
>>> index f4dd779a52..526ac57982 100644
>>> --- a/meta/classes-global/package_rpm.bbclass
>>> +++ b/meta/classes-global/package_rpm.bbclass
>>> @@ -421,12 +421,14 @@ python write_specfile () {
>>>           spec_preamble_bottom.append('')
>>>           # Now process scriptlets
>>> -        if splitrpreinst:
>>> +        # The libc6 shouldn't have %pre or %post to avoid circular dependency
>>> +        libc6 = '%slibc6' % (d.getVar('MLPREFIX') or '')
>>> +        if splitrpreinst and splitname != libc6:
>>>               spec_scriptlets_bottom.append('%%pre -n %s' % splitname)
>>>               spec_scriptlets_bottom.append('# %s - preinst' % splitname)
>>>               spec_scriptlets_bottom.append(splitrpreinst)
>>>               spec_scriptlets_bottom.append('')
>>> -        if splitrpostinst:
>>> +        if splitrpostinst and splitname != libc6:
>>>               spec_scriptlets_bottom.append('%%post -n %s' % splitname)
>>>               spec_scriptlets_bottom.append('# %s - postinst' % splitname)
>>>               spec_scriptlets_bottom.append(splitrpostinst)
>>
>> I'm not happy about coding a "libc6" reference into the generic package
>> class. It does make me wonder if there is a similar issue with musl for
>> example and we'd end up with a longer hardcoded list.
>>
>> Could/shouldn't we just not add that postinst for libc6? You could for
>> example force the value of pkg_postinst:libc6 during the packaging
>> process and empty the postinst instead.
> 
> I think you meant add the following lines in glibc-package.inc:
> 
> pkg_postinst:glibc () {
>      echo
> }
> 
> We need an "echo" here, otherwise, meta/lib/oe/package.py would add the
> "#!/bin/sh" to the postinst:
> 
>          if needs_ldconfig:
>              bb.debug(1, 'adding ldconfig call to postinst for %s' % pkg)
>              postinst = d.getVar('pkg_postinst:%s' % pkg)
>              if not postinst:
>                  postinst = '#!/bin/sh\n'
>              postinst += d.getVar('ldconfig_postinst_fragment')
>              d.setVar('pkg_postinst:%s' % pkg, postinst)
> 
> But this still doesn't work, because rpm will add the /bin/sh as the default
> interpreter when not specified. And currently, meta/lib/oe/package.py
> add the ldconfig_postinst_fragment automatically when find so files,
> that the root cause, so how about we add a value like:
> 
> NEEDS_LDCONFIG:<pkg> = "0" or "1"
> 
> Then we can add the following line to glibc-package.inc to skip that.
> NEEDS_LDCONFIG:libc6 = "0"
> 
> And also we need update meta/lib/oe/package.py to check the
> NEEDS_LDCONFIG:pkg.

A easier way should be like this:

lyang1@ala-lpggp3:glibc$ git diff
diff --git a/meta/lib/oe/package.py b/meta/lib/oe/package.py
index 17535ebd6d..f97eae104f 100644
--- a/meta/lib/oe/package.py
+++ b/meta/lib/oe/package.py
@@ -1824,7 +1824,8 @@ def process_shlibs(pkgfiles, d):
                      if s[0] not in shlib_provider:
                          shlib_provider[s[0]] = {}
                      shlib_provider[s[0]][s[1]] = (pkg, pkgver)
-        if needs_ldconfig:
+        if needs_ldconfig and \
+                not 
bb.utils.to_boolean(d.getVar('SKIP_LDCONFIG_POSTINST_FRAGMENT:%s' % pkg)):
              bb.debug(1, 'adding ldconfig call to postinst for %s' % pkg)
              postinst = d.getVar('pkg_postinst:%s' % pkg)
              if not postinst:
diff --git a/meta/recipes-core/glibc/glibc-package.inc 
b/meta/recipes-core/glibc/glibc-package.inc
index 21f2200d19..df0dd6720f 100644
--- a/meta/recipes-core/glibc/glibc-package.inc
+++ b/meta/recipes-core/glibc/glibc-package.inc
@@ -293,7 +293,10 @@ pkg_postinst:nscd () {
                 fi
         fi
  }
+
  CONFFILES:nscd = "${sysconfdir}/nscd.conf"
+SKIP_LDCONFIG_POSTINST_FRAGMENT:${PN} = "1"
+do_package[vardeps] += "SKIP_LDCONFIG_POSTINST_FRAGMENT"

  SYSTEMD_PACKAGES = "nscd"
  SYSTEMD_SERVICE:nscd = "nscd.service"


And also set the value for musl.

I will send the updated patches after more testing.


// Robert

> 
>>
>> Also the commit message explains the problem with the postinst but not
>> really why the preinst is a problem? What does that contain which is
>> problematic?
>>
> 
> It is similar to posint, the prinst has a harder situation than postinst.
> 
> // Robert
> 
> 
>> Cheers,
>>
>> Richard
>
diff mbox series

Patch

diff --git a/meta/classes-global/package_rpm.bbclass b/meta/classes-global/package_rpm.bbclass
index f4dd779a52..526ac57982 100644
--- a/meta/classes-global/package_rpm.bbclass
+++ b/meta/classes-global/package_rpm.bbclass
@@ -421,12 +421,14 @@  python write_specfile () {
         spec_preamble_bottom.append('')
 
         # Now process scriptlets
-        if splitrpreinst:
+        # The libc6 shouldn't have %pre or %post to avoid circular dependency
+        libc6 = '%slibc6' % (d.getVar('MLPREFIX') or '')
+        if splitrpreinst and splitname != libc6:
             spec_scriptlets_bottom.append('%%pre -n %s' % splitname)
             spec_scriptlets_bottom.append('# %s - preinst' % splitname)
             spec_scriptlets_bottom.append(splitrpreinst)
             spec_scriptlets_bottom.append('')
-        if splitrpostinst:
+        if splitrpostinst and splitname != libc6:
             spec_scriptlets_bottom.append('%%post -n %s' % splitname)
             spec_scriptlets_bottom.append('# %s - postinst' % splitname)
             spec_scriptlets_bottom.append(splitrpostinst)
diff --git a/meta/lib/oeqa/runtime/cases/dnf.py b/meta/lib/oeqa/runtime/cases/dnf.py
index 3ccb18ce83..029651c571 100644
--- a/meta/lib/oeqa/runtime/cases/dnf.py
+++ b/meta/lib/oeqa/runtime/cases/dnf.py
@@ -124,15 +124,8 @@  class DnfRepoTest(DnfTest):
         self.target.run('mkdir -p %s/bin %s/sbin %s/usr/bin %s/usr/sbin' % (rootpath, rootpath, rootpath, rootpath), 1500)
         self.target.run('mkdir -p %s/dev' % rootpath, 1500)
         #Handle different architectures lib dirs
-        self.target.run('mkdir -p %s/lib' % rootpath, 1500)
-        self.target.run('mkdir -p %s/libx32' % rootpath, 1500)
-        self.target.run('mkdir -p %s/lib64' % rootpath, 1500)
-        self.target.run('cp /lib/libtinfo.so.5 %s/lib' % rootpath, 1500)
-        self.target.run('cp /libx32/libtinfo.so.5 %s/libx32' % rootpath, 1500)
-        self.target.run('cp /lib64/libtinfo.so.5 %s/lib64' % rootpath, 1500)
         self.target.run('cp -r /etc/rpm %s/etc' % rootpath, 1500)
         self.target.run('cp -r /etc/dnf %s/etc' % rootpath, 1500)
-        self.target.run('cp /bin/sh %s/bin' % rootpath, 1500)
         self.target.run('mount -o bind /dev %s/dev/' % rootpath, 1500)
         self.dnf_with_repo('install --installroot=%s -v -y --rpmverbosity=debug busybox' % rootpath)
         status, output = self.target.run('test -e %s/var/cache/dnf' % rootpath, 1500)
@@ -156,7 +149,6 @@  class DnfRepoTest(DnfTest):
         self.target.run("for l in /lib*; do mkdir -p %s/usr/$l; ln -s usr/$l %s/$l; done" % (rootpath, rootpath))
         self.target.run('cp -r /etc/rpm %s/etc' % rootpath)
         self.target.run('cp -r /etc/dnf %s/etc' % rootpath)
-        self.target.run('cp /bin/busybox %s/bin/sh' % rootpath)
         self.target.run('mount -o bind /dev %s/dev/' % rootpath)
         self.dnf_with_repo('install --installroot=%s -v -y --rpmverbosity=debug busybox' % rootpath)
         status, output = self.target.run('test -e %s/var/cache/dnf' % rootpath)