Busybox init manager: proposal for install scripts, like update-rc.d

Rémi SUBRA <[email protected]>
Newsgroups org.yoctoproject.lists.yocto
Message-ID <CAHThLsnSD1yn7d02JEU82EQuffWjwYfPVtse1oXWp88OURhhtQ@mail.gmail.com>
Hello,

I'm trying to build a "minimal" system and want to use the busybox
init manager, by setting INIT_MANAGER="mdev-busybox" in my DISTRO.
The busybox recipe automatically installs the inittab, with
corresponding rcS and rcK scripts which handle start/stop scripts in
the /etc/rcX.d directory. Unfortunately there is no way currently in
OpenEmbedded to automatically install the service script from a
package as expected by the busybox init manager configuration (like
with sysvinit or systemd) :/

So I wrote a new class to handle these use case, deeply inspired by
the update-rc.d class. But I didn't use it directly as update-rc.d
handles the runlevels, as sysvinit, and they are completely ignored by
busybox init. But I think that the INITSCRIPT_PACKAGES,
INITSCRIPT_NAME and INITSCRIPT_PARAMS defined in recipes for sysvinit
support could be re-used.
By using the same variables, I think that all packages supporting
sysvinit could also support busybox init without modification in their
recipes (by inheriting my new class inside update-rc.d.bbclass).

I choose to install a symlink to the service init script in
/etc/rcS.d/SXXname if start is found in the INITSCRIPT_PARAMS, and
stop symlink in /etc/rcK.d/KXXname if stop is in parameters. I also
respect the defaults params like in update-rc.d.
I mainly choose the directory name to be like sysvinit, but slightly
different to avoid confusion.

Now I would like to propose a patch for this feature, but I don't know
if my current approach is good. I'm especially not sure if creating a
new class is the better approach, or if it's better to "merge" it
inside the update-rc.d class?
So, I really appreciate your opinion, as yocto core developers.

Kind regards
    Rémi SUBRA, Smile


FIY, there is my current implementation (is a WIP and my first class,
so please be patient with me):

diff --git a/meta/classes-recipe/busybox-init.bbclass
b/meta/classes-recipe/busybox-init.bbclass
new file mode 100644
index 0000000000..cd508cf325
--- /dev/null
+++ b/meta/classes-recipe/busybox-init.bbclass
@@ -0,0 +1,133 @@
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+INITSCRIPT_PARAMS ?= "defaults"
+
+INIT_D_DIR = "${sysconfdir}/init.d"
+INIT_D_RCS = "${INIT_D_DIR}/rcS"
+INIT_D_RCK = "${INIT_D_DIR}/rcK"
+RCS_DIR = "${sysconfdir}/rcS.d"
+RCK_DIR = "${sysconfdir}/rcK.d"
+
+def initscript_priority(mode:str, d):
+    params = d.getVar('INITSCRIPT_PARAMS').split()
+    priority = 20
+
+    if mode != "start" and mode != "stop":
+        bb.error("invalid mode [start|stop] for init script: %s" % mode)
+        return ""
+
+    if mode in params:
+        idx_mode = params.index(mode)
+        if '.' not in params[idx_mode:]:
+            bb.error("INITSCRIPT_PARAMS missing '.' after %s: %s" %
(mode, params))
+            return ""
+        idx_end = params.index('.', idx_mode)
+
+        mode_params = params[idx_mode:idx_end+1]
+        if (len(mode_params) < 4):
+            bb.error("INITSCRIPT_PARAMS doesn't have a correct format
for %s: %s" % (mode, params))
+            return ""
+        priority = mode_params[1]
+    elif params[0] == "defaults":
+        if mode == "start" and len(params) > 1:
+            priority = params[1]
+        if mode == "stop" and len(params) > 2:
+            priority = params[2]
+    else:
+        bb.note("INITSCRIPT_PARAMS doesn't define the %s priority:
%s" % (mode, params))
+        return ""
+
+    bb.debug(1, "INITSCRIPT_PARAMS: %s -> %s priority %s" % (params,
mode, priority))
+    return f"{priority:02}"
+
+busyboxinit_postinst() {
+if [ -x "$D${INIT_D_RCS}" -a -f "$D${INIT_D_RCS}" ]; then
+    mkdir -p "$D${RCS_DIR}"
+    link_prio=${@initscript_priority('start', d)}
+    if [ "x$link_prio" != "x" ]; then
+        ln -s "../init.d/${INITSCRIPT_NAME}"
"$D${RCS_DIR}/S${link_prio}${INITSCRIPT_NAME}"
+    fi
+fi
+if [ -x "$D${INIT_D_RCK}" -a -f "$D${INIT_D_RCK}" ]; then
+    mkdir -p "$D${RCK_DIR}"
+    link_prio=${@initscript_priority('stop', d)}
+    if [ "x$link_prio" != "x" ]; then
+        ln -s "../init.d/${INITSCRIPT_NAME}"
"$D${RCK_DIR}/K${link_prio}${INITSCRIPT_NAME}"
+    fi
+fi
+}
+
+busyboxinit_prerm() {
+if [ -z "$D" -a -x "${INIT_D_DIR}/${INITSCRIPT_NAME}" ]; then
+ ${INIT_D_DIR}/${INITSCRIPT_NAME} stop || :
+fi
+}
+
+busyboxinit_postrm() {
+if [ -d "$D${RCS_DIR}" ]; then
+    rm -f $D${RCS_DIR}/S??${INITSCRIPT_NAME}
+fi
+if [ -d "$D${RCK_DIR}" ]; then
+    rm -f $D${RCK_DIR}/K??${INITSCRIPT_NAME}
+fi
+}
+
+
+def busyboxinit_after_parse(d):
+    if d.getVar('INITSCRIPT_PACKAGES', False) == None:
+        if d.getVar('INITSCRIPT_NAME', False) == None:
+            bb.fatal("%s inherits busybox-init but doesn't set
INITSCRIPT_NAME" % d.getVar('FILE', False))
+        if d.getVar('INITSCRIPT_PARAMS', False) == None:
+            bb.fatal("%s inherits busybox-init but doesn't set
INITSCRIPT_PARAMS" % d.getVar('FILE', False))
+
+python __anonymous() {
+    busyboxinit_after_parse(d)
+}
+
+PACKAGESPLITFUNCS =+ "${@'populate_packages_busyboxinit' if
d.getVar('INIT_MANAGER') == 'mdev-busybox' else ''}"
+
+populate_packages_busyboxinit[vardeps] += "busyboxinit_prerm
busyboxinit_postrm busyboxinit_postinst"
+populate_packages_busyboxinit[vardepsexclude] += "OVERRIDES"
+
+python populate_packages_busyboxinit () {
+    def busyboxinit_package(pkg):
+        import subprocess
+        import os
+
+        bb.debug(1, 'adding busybox-init links in
postinst/prerm/postrm for %s' % pkg)
+
+        localdata = bb.data.createCopy(d)
+        overrides = localdata.getVar("OVERRIDES")
+        localdata.setVar("OVERRIDES", "%s:%s" % (pkg, overrides))
+
+        postinst = d.getVar('pkg_postinst:%s' % pkg)
+        if not postinst:
+            postinst = '#!/bin/sh\n'
+        postinst += localdata.getVar('busyboxinit_postinst')
+        d.setVar('pkg_postinst:%s' % pkg, postinst)
+
+        prerm = d.getVar('pkg_prerm:%s' % pkg)
+        if not prerm:
+            prerm = '#!/bin/sh\n'
+        prerm += localdata.getVar('busyboxinit_prerm')
+        d.setVar('pkg_prerm:%s' % pkg, prerm)
+
+        postrm = d.getVar('pkg_postrm:%s' % pkg)
+        if not postrm:
+                postrm = '#!/bin/sh\n'
+        postrm += localdata.getVar('busyboxinit_postrm')
+        d.setVar('pkg_postrm:%s' % pkg, postrm)
+
+    pkgs = d.getVar('INITSCRIPT_PACKAGES')
+    if pkgs == None:
+        pkgs = d.getVar('UPDATERCPN')
+        packages = (d.getVar('PACKAGES') or "").split()
+        if not pkgs in packages and packages != []:
+            pkgs = packages[0]
+    for pkg in pkgs.split():
+        busyboxinit_package(pkg)
+}
diff --git a/meta/classes-recipe/update-rc.d.bbclass
b/meta/classes-recipe/update-rc.d.bbclass
index a19e704741..840dede320 100644
--- a/meta/classes-recipe/update-rc.d.bbclass
+++ b/meta/classes-recipe/update-rc.d.bbclass
@@ -4,6 +4,8 @@
 # SPDX-License-Identifier: MIT
 #

+inherit busybox-init
+
 UPDATERCPN ?= "${PN}"

 DEPENDS:append:class-target =
"${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', ' update-rc.d
initscripts', '', d)}"
diff --git a/meta/recipes-core/busybox/files/rcK
b/meta/recipes-core/busybox/files/rcK
index f8a63e1325..b6d97f8fef 100644
--- a/meta/recipes-core/busybox/files/rcK
+++ b/meta/recipes-core/busybox/files/rcK
@@ -1,9 +1,9 @@
 #!/bin/sh

-# Stop all init scripts in /etc/rc6.d
+# Stop all init scripts in /etc/rcK.d and /etc/rc6.d
 # executing them in numerical order.
 #
-for i in /etc/rc6.d/K??*; do
+for i in /etc/rcK.d/K??* /etc/rc6.d/K??*; do

      # Ignore dangling symlinks (if any).
      [ ! -f "$i" ] && continue
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.