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