common init infrastructure
cover common init infrastructure
This series is intended to clean up buildroot init system somewhat, removing the need for extensive sysv and systemd handling code in every package that installs init bits, and allowing alternative init systems to be implemented with reasonable amount of effort.
Overview of the changes:
* drop per-package sysv and systemd files, introduce common format used to generate files for both of them, use a script to do the conversion from common format to sysv or systemd.
* remove sysv and systemd installation code from package .mk files, let pkg-generic handle it.
* remove sysv-specific files from skeleton, and sysv-specific hacks from system/system.mk. Use a dedicated script to write inittab, handling global conditionals (root rw/ro, serial getty and so on)
* remove user definitions from package .mk files, and mkdirs from per-package sysv initscript, use per-package .users and .files instead in a way similar to .hash files.
Expected benefits:
* (almost) all packages get both sysv and systemd files at the same time and without the need to support them separately.
* init-related changes can be introduced without patching all 70+ individual packages that install startup files.
* new init systems can be introduced with only minor effort, including lightweight ones with controlled (foreground) daemons.
This series includes the infrastructure changes, and a couple of package patches to show how it looks like. Complete set of package patches uploaded here: https://github.com/arsv/br/
This series is for reviewing, not for merging.
Signature · 1 line
2.0.3
RFC 1/11 common service startup files
This patch introduces support infrastructure for per-project .run files.
Any .run files in package directory are picked up by pkg-generic code, fed to support/init/install-run script which converts them into either sysv initscripts or systemd unit files and installs those into predefined locations. The package itself provides only the .run files, no code in package .mk file is necessary.
Packages that install some of their services conditionally may set $(PKG)_INIT = list of run files to install. As a side effect, this removes the need to handle S99foo S99bar vs foo.service bar.service with the package .mk file.
Packages that need to substititue some values within their service files may set $(PKG)_INIT = KEY:value KEY:value ..., which will be handled by install-run. The substitutions will be applied to sysv and systemd files.
In case particular init system needs hand-crafted startup files or cannot handle certain services at all, install-run may be told so using special lines in the .run file.
This patch does not remove existing BR2_INIT_{SYSV,SYSTEMD} hooks. Each package should either provide .run files or define hooks, but not both.
--- package/Makefile.in | 10 + package/pkg-generic.mk | 23 +++ support/init/install-run | 457 +++++++++++++++++++++++++++++++++++++++++++ support/init/install-tmpconf | 7 + 4 files changed, 497 insertions(+) create mode 100755 support/init/install-run create mode 100755 support/init/install-tmpconf
package/Makefile.in +10 -0
@@ -408,6 +408,16 @@ ifeq ($(BR2_COMPILER_PARANOID_UNSAFE_PATH),y) export BR_COMPILER_PARANOID_UNSAFE_PATH=enabled endif +ifdef BR2_INIT_SYSV +BR2_INIT = initscripts +else ifdef BR2_INIT_BUSYBOX +BR2_INIT = initscripts +else ifdef BR2_INIT_SYSTEMD +BR2_INIT = systemd +else +BR2_INIT = none +endif + include package/pkg-download.mk include package/pkg-autotools.mk include package/pkg-cmake.mk
package/pkg-generic.mk +23 -0
@@ -762,10 +762,33 @@ ifneq ($$(call suitable-extractor,$$($(2)_SOURCE)),$$(XZCAT)) DL_TOOLS_DEPENDENCIES += $$(firstword $$(call suitable-extractor,$$($(2)_SOURCE))) endif +# Init, users and files are for target image only +ifeq ($4,target) + +$(2)_INIT ?= $$(notdir $$(wildcard package/$1/*.run)) +$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_INSTALL_INIT + +# This will expand to (nothing) if none of the files are present +# in the package directory. +ifndef $(2)_INSTALL_INIT +define $(2)_INSTALL_INIT + $$(call ifargs,support/init/install-run $$(BR2_INIT) \ + $$($$(PKG)_INIT_SUBST),$$(addprefix package/$1/,$$($$(PKG)_INIT))) + $$(call ifargs,support/init/install-tmpconf $$(BR2_INIT),$$(wildcard package/$1/*.tmp.conf)) +endef +endif + +endif # $4 == target + endif # $(2)_KCONFIG_VAR endef # inner-generic-package ################################################################################ +define ifargs + $(if $2,$1 $2) +endef + +################################################################################ # generic-package -- the target generator macro for generic packages ################################################################################
support/init/install-run new file +457 -0
457 lines not on this page · raw message
support/init/install-tmpconf new file +7 -0
@@ -0,0 +1,7 @@ +#!/bin/sh + +test "$1" = 'systemd' && shift || exit +mkdir -p output/target/etc/tmpfiles.d/ +for i in "$@"; do + cp $i output/target/etc/tmpfiles.d/${i/.tmp.conf/.conf} +done
Signature · 1 line
2.0.3
RFC 2/11 per-package .users and .files lists
In reply to Alex SuykovFollowing .run and .hash files, move package-specific users and file permissions from .mk strings into standalone files, to be picked up by pkg-generic code.
No additional code in package .mk is necessary.
This change does not simplify things much at present, but it removes inter-package dependency via make variables. Without this patch, reading all enabled package/*/*.mk files from a single Makefile was necessary to build user and permission lists. With this patch, the data is stored outside of make, possibly allowing one make invocation per package .mk file in the future.
To keep installed per-package .users and .files, a new directory is introduced: output/parts.
The directory is meant for stuff that is installed during build stage but does not belong in the target/ directory, at least not without some processing.
--- Makefile | 1 + fs/common.mk | 21 +++++++++++++-------- package/pkg-generic.mk | 2 ++ support/init/install-parts | 5 +++++ 4 files changed, 21 insertions(+), 8 deletions(-) create mode 100755 support/init/install-parts
Makefile +1 -0
@@ -156,6 +156,7 @@ endif BR_GRAPH_OUT := $(or $(BR2_GRAPH_OUT),pdf) BUILD_DIR := $(BASE_DIR)/build +PARTS_DIR := $(BASE_DIR)/parts BINARIES_DIR := $(BASE_DIR)/images TARGET_DIR := $(BASE_DIR)/target # initial definition so that 'make clean' works for most users, even without
fs/common.mk +13 -8
@@ -28,12 +28,14 @@ # BR2_TARGET_ROOTFS_$(FSTYPE)_LZMA exist and are enabled, then the # macro will automatically generate a compressed filesystem image. -FAKEROOT_SCRIPT = $(BUILD_DIR)/_fakeroot.fs -FULL_DEVICE_TABLE = $(BUILD_DIR)/_device_table.txt +FAKEROOT_SCRIPT = $(PARTS_DIR)/fakeroot.fs +FULL_DEVICE_TABLE = $(PARTS_DIR)/device_table.txt ROOTFS_DEVICE_TABLES = $(call qstrip,$(BR2_ROOTFS_DEVICE_TABLE) \ $(BR2_ROOTFS_STATIC_DEVICE_TABLE)) -USERS_TABLE = $(BUILD_DIR)/_users_table.txt +USERS_TABLE = $(PARTS_DIR)/users_table.txt ROOTFS_USERS_TABLES = $(call qstrip,$(BR2_ROOTFS_USERS_TABLES)) +PARTS_LIST_USERS = $(wildcard $(PARTS_DIR)/users/*.users) +PARTS_LIST_FILES = $(wildcard $(PARTS_DIR)/files/*.files) # Since this function will be called from within an $(eval ...) # all variable references except the arguments must be $$-quoted.
@@ -41,7 +43,7 @@ define ROOTFS_TARGET_INTERNAL # extra deps ROOTFS_$(2)_DEPENDENCIES += host-fakeroot host-makedevs \ - $$(if $$(PACKAGES_USERS),host-mkpasswd) + $$(if $$(PARTS_LIST_USERS),host-mkpasswd) ifeq ($$(BR2_TARGET_ROOTFS_$(2)_GZIP),y) ROOTFS_$(2)_COMPRESS_EXT = .gz
@@ -77,16 +79,19 @@ $$(BINARIES_DIR)/rootfs.$(1): target-finalize $$(ROOTFS_$(2)_DEPENDENCIES) echo "chown -h -R 0:0 $$(TARGET_DIR)" >> $$(FAKEROOT_SCRIPT) ifneq ($$(ROOTFS_DEVICE_TABLES),) cat $$(ROOTFS_DEVICE_TABLES) > $$(FULL_DEVICE_TABLE) -ifeq ($$(BR2_ROOTFS_DEVICE_CREATION_STATIC),y) - printf '$$(subst $$(sep),\n,$$(PACKAGES_DEVICES_TABLE))' >> $$(FULL_DEVICE_TABLE) +ifdef PARTS_LIST_FILES + cat $$(PARTS_LIST_FILES) \ + $$(if $$(BR2_ROOTFS_DEVICE_CREATION_STATIC),,| grep -v ^/dev) \ + >> $$(FULL_DEVICE_TABLE) endif - printf '$$(subst $$(sep),\n,$$(PACKAGES_PERMISSIONS_TABLE))' >> $$(FULL_DEVICE_TABLE) echo "$$(HOST_DIR)/usr/bin/makedevs -d $$(FULL_DEVICE_TABLE) $$(TARGET_DIR)" >> $$(FAKEROOT_SCRIPT) endif ifneq ($$(ROOTFS_USERS_TABLES),) cat $$(ROOTFS_USERS_TABLES) >> $$(USERS_TABLE) endif - printf '$$(subst $$(sep),\n,$$(PACKAGES_USERS))' >> $$(USERS_TABLE) +ifdef PARTS_LIST_USERS + cat $$(PARTS_LIST_USERS) >> $$(USERS_TABLE) +endif PATH=$$(BR_PATH) $$(TOPDIR)/support/scripts/mkusers $$(USERS_TABLE) $$(TARGET_DIR) >> $$(FAKEROOT_SCRIPT) echo "$$(ROOTFS_$(2)_CMD)" >> $$(FAKEROOT_SCRIPT) chmod a+x $$(FAKEROOT_SCRIPT)
package/pkg-generic.mk +2 -0
@@ -774,6 +774,8 @@ ifndef $(2)_INSTALL_INIT define $(2)_INSTALL_INIT $$(call ifargs,support/init/install-run $$(BR2_INIT) \ $$($$(PKG)_INIT_SUBST),$$(addprefix package/$1/,$$($$(PKG)_INIT))) + $$(call ifargs,support/init/install-parts users,$$(wildcard package/$1/*.users)) + $$(call ifargs,support/init/install-parts files,$$(wildcard package/$1/*.files)) $$(call ifargs,support/init/install-tmpconf $$(BR2_INIT),$$(wildcard package/$1/*.tmp.conf)) endef endif
support/init/install-parts new file +5 -0
@@ -0,0 +1,5 @@ +#!/bin/sh + +part="$1"; shift; test -z "$part" && exit 1 +mkdir -p output/parts/$part/ +cp "$@" output/parts/$part/
Signature · 1 line
2.0.3
RFC 3/11 init/finalize script
In reply to Alex SuykovThe patch moves the code that handles non-package parts of init configuration out of packages and out of skeleton, gathering it in a dedicated script.
For sysv init, the script writes /etc/inittab, making filesystems are mounted, udev is handled somehow, syslog is started and network is brought up. For systemd, the script handles target symlinks and aliases.
The idea is that options the configure the system as a whole should be handled outside of individual packages.
So instead of letting eudev to install itself as the udev handler, or maybe letting busybox install mdev, it is decided later and outside of either eudev or busybox.
As a side effect, this patch makes sure sysv-specific files are not installed at all if systemd is chosen for the init.
--- package/busybox/busybox.mk | 8 -- package/busybox/mdev.conf | 35 ------ package/eudev/S10udev | 50 -------- package/eudev/eudev.mk | 4 - support/init/finalize | 207 ++++++++++++++++++++++++++++++++++ support/init/init.d/S10mdev | 21 ++++ support/init/init.d/S10udev | 50 ++++++++ support/init/init.d/rcK | 26 +++++ support/init/init.d/rcS | 26 +++++ support/init/mdev.conf | 35 ++++++ support/init/sysv.fini | 7 ++ support/init/sysv.init | 14 +++ system/skeleton/etc/init.d/S20urandom | 54 --------- system/skeleton/etc/init.d/S40network | 28 ----- system/skeleton/etc/init.d/rcK | 27 ----- system/skeleton/etc/init.d/rcS | 27 ----- system/skeleton/etc/inittab | 35 ------ system/system.mk | 32 +----- 18 files changed, 390 insertions(+), 296 deletions(-) delete mode 100644 package/busybox/mdev.conf delete mode 100755 package/eudev/S10udev create mode 100755 support/init/finalize create mode 100755 support/init/init.d/S10mdev create mode 100755 support/init/init.d/S10udev create mode 100755 support/init/init.d/rcK create mode 100755 support/init/init.d/rcS create mode 100644 support/init/mdev.conf create mode 100644 support/init/sysv.fini create mode 100644 support/init/sysv.init delete mode 100755 system/skeleton/etc/init.d/S20urandom delete mode 100755 system/skeleton/etc/init.d/S40network delete mode 100755 system/skeleton/etc/init.d/rcK delete mode 100755 system/skeleton/etc/init.d/rcS delete mode 100644 system/skeleton/etc/inittab
package/busybox/busybox.mk +0 -8
@@ -56,14 +56,6 @@ endef # If mdev will be used for device creation enable it and copy S10mdev to /etc/init.d ifeq ($(BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV),y) -define BUSYBOX_INSTALL_MDEV_SCRIPT - $(INSTALL) -D -m 0755 package/busybox/S10mdev \ - $(TARGET_DIR)/etc/init.d/S10mdev -endef -define BUSYBOX_INSTALL_MDEV_CONF - $(INSTALL) -D -m 0644 package/busybox/mdev.conf \ - $(TARGET_DIR)/etc/mdev.conf -endef define BUSYBOX_SET_MDEV $(call KCONFIG_ENABLE_OPT,CONFIG_MDEV,$(BUSYBOX_BUILD_CONFIG)) $(call KCONFIG_ENABLE_OPT,CONFIG_FEATURE_MDEV_CONF,$(BUSYBOX_BUILD_CONFIG))
package/busybox/mdev.conf deleted +0 -35
@@ -1,35 +0,0 @@ -# null may already exist; therefore ownership has to be changed with command -null root:root 666 @chmod 666 $MDEV -zero root:root 666 -full root:root 666 -random root:root 444 -urandom root:root 444 -hwrandom root:root 444 -grsec root:root 660 - -kmem root:root 640 -mem root:root 640 -port root:root 640 -# console may already exist; therefore ownership has to be changed with command -console root:tty 600 @chmod 600 $MDEV -ptmx root:tty 666 -pty.* root:tty 660 - -# Typical devices -tty root:tty 666 -tty[0-9]* root:tty 660 -vcsa*[0-9]* root:tty 660 -ttyS[0-9]* root:root 660 - -# alsa sound devices -pcm.* root:audio 660 =snd/ -control.* root:audio 660 =snd/ -midi.* root:audio 660 =snd/ -seq root:audio 660 =snd/ -timer root:audio 660 =snd/ - -# input stuff -event[0-9]+ root:root 640 =input/ -mice root:root 640 =input/ -mouse[0-9] root:root 640 =input/ -ts[0-9] root:root 600 =input/
package/eudev/S10udev deleted +0 -50
50 lines not on this page · raw message
package/eudev/eudev.mk +0 -4
@@ -40,10 +40,6 @@ else EUDEV_CONF_OPTS += --disable-gudev endif -define EUDEV_INSTALL_INIT_SYSV - $(INSTALL) -m 0755 package/eudev/S10udev $(TARGET_DIR)/etc/init.d/S10udev -endef - # Required by default rules for input devices define EUDEV_USERS - - input -1 * - - - Input device group
support/init/finalize new file +207 -0
207 lines not on this page · raw message
support/init/init.d/S10mdev new file +21 -0
@@ -0,0 +1,21 @@ +#!/bin/sh +# +# Start mdev.... +# + +case "$1" in + start) + echo "Starting mdev..." + echo /sbin/mdev >/proc/sys/kernel/hotplug + /sbin/mdev -s + ;; + stop) + ;; + restart|reload) + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 +esac + +exit $?
support/init/init.d/S10udev new file +50 -0
50 lines not on this page · raw message
support/init/init.d/rcK new file +26 -0
@@ -0,0 +1,26 @@ +#!/bin/sh + + +# Stop all init scripts in /etc/init.d +# executing them in reversed numerical order. +# +for i in $(ls -r /etc/init.d/S??*) ;do + + # Ignore dangling symlinks (if any). + [ ! -f "$i" ] && continue + + case "$i" in + *.sh) + # Source shell script for speed. + ( + trap - INT QUIT TSTP + set stop + . $i + ) + ;; + *) + # No sh extension, so fork subprocess. + $i stop + ;; + esac +done
support/init/init.d/rcS new file +26 -0
@@ -0,0 +1,26 @@ +#!/bin/sh + + +# Start all init scripts in /etc/init.d +# executing them in numerical order. +# +for i in /etc/init.d/S??* ;do + + # Ignore dangling symlinks (if any). + [ ! -f "$i" ] && continue + + case "$i" in + *.sh) + # Source shell script for speed. + ( + trap - INT QUIT TSTP + set start + . $i + ) + ;; + *) + # No sh extension, so fork subprocess. + $i start + ;; + esac +done
support/init/mdev.conf new file +35 -0
@@ -0,0 +1,35 @@ +# null may already exist; therefore ownership has to be changed with command +null root:root 666 @chmod 666 $MDEV +zero root:root 666 +full root:root 666 +random root:root 444 +urandom root:root 444 +hwrandom root:root 444 +grsec root:root 660 + +kmem root:root 640 +mem root:root 640 +port root:root 640 +# console may already exist; therefore ownership has to be changed with command +console root:tty 600 @chmod 600 $MDEV +ptmx root:tty 666 +pty.* root:tty 660 + +# Typical devices +tty root:tty 666 +tty[0-9]* root:tty 660 +vcsa*[0-9]* root:tty 660 +ttyS[0-9]* root:root 660 + +# alsa sound devices +pcm.* root:audio 660 =snd/ +control.* root:audio 660 =snd/ +midi.* root:audio 660 =snd/ +seq root:audio 660 =snd/ +timer root:audio 660 =snd/ + +# input stuff +event[0-9]+ root:root 640 =input/ +mice root:root 640 =input/ +mouse[0-9] root:root 640 =input/ +ts[0-9] root:root 600 =input/
support/init/sysv.fini new file +7 -0
@@ -0,0 +1,7 @@ +# Stuff to do for the 3-finger salute +null::ctrlaltdel:/sbin/reboot + +# Stuff to do before rebooting +null::shutdown:/sbin/ifdown -a +null::shutdown:/sbin/swapoff -a +null::shutdown:/bin/umount -a -r
support/init/sysv.init new file +14 -0
@@ -0,0 +1,14 @@ +# /etc/inittab +# +# Copyright (C) 2001 Erik Andersen <[email protected]> +# +# Note: BusyBox init doesn't support runlevels. The runlevels field is +# completely ignored by BusyBox init. If you want runlevels, use +# sysvinit. +# +# Format for each entry: <id>:<runlevels>:<action>:<process> +# +# id == tty to run on, or empty for /dev/console +# runlevels == ignored +# action == one of sysinit, respawn, askfirst, wait, and once +# process == program to run
system/skeleton/etc/init.d/S20urandom deleted +0 -54
54 lines not on this page · raw message
system/skeleton/etc/init.d/S40network deleted +0 -28
@@ -1,28 +0,0 @@ -#!/bin/sh -# -# Start the network.... -# - -# Debian ifupdown needs the /run/network lock directory -mkdir -p /run/network - -case "$1" in - start) - echo "Starting network..." - /sbin/ifup -a - ;; - stop) - echo -n "Stopping network..." - /sbin/ifdown -a - ;; - restart|reload) - "$0" stop - "$0" start - ;; - *) - echo "Usage: $0 {start|stop|restart}" - exit 1 -esac - -exit $? -
system/skeleton/etc/init.d/rcK deleted +0 -27
@@ -1,27 +0,0 @@ -#!/bin/sh - - -# Stop all init scripts in /etc/init.d -# executing them in reversed numerical order. -# -for i in $(ls -r /etc/init.d/S??*) ;do - - # Ignore dangling symlinks (if any). - [ ! -f "$i" ] && continue - - case "$i" in - *.sh) - # Source shell script for speed. - ( - trap - INT QUIT TSTP - set stop - . $i - ) - ;; - *) - # No sh extension, so fork subprocess. - $i stop - ;; - esac -done -
system/skeleton/etc/init.d/rcS deleted +0 -27
@@ -1,27 +0,0 @@ -#!/bin/sh - - -# Start all init scripts in /etc/init.d -# executing them in numerical order. -# -for i in /etc/init.d/S??* ;do - - # Ignore dangling symlinks (if any). - [ ! -f "$i" ] && continue - - case "$i" in - *.sh) - # Source shell script for speed. - ( - trap - INT QUIT TSTP - set start - . $i - ) - ;; - *) - # No sh extension, so fork subprocess. - $i start - ;; - esac -done -
system/skeleton/etc/inittab deleted +0 -35
@@ -1,35 +0,0 @@ -# /etc/inittab -# -# Copyright (C) 2001 Erik Andersen <[email protected]> -# -# Note: BusyBox init doesn't support runlevels. The runlevels field is -# completely ignored by BusyBox init. If you want runlevels, use -# sysvinit. -# -# Format for each entry: <id>:<runlevels>:<action>:<process> -# -# id == tty to run on, or empty for /dev/console -# runlevels == ignored -# action == one of sysinit, respawn, askfirst, wait, and once -# process == program to run - -# Startup the system -null::sysinit:/bin/mount -t proc proc /proc -null::sysinit:/bin/mount -o remount,rw / -null::sysinit:/bin/mkdir -p /dev/pts -null::sysinit:/bin/mkdir -p /dev/shm -null::sysinit:/bin/mount -a -null::sysinit:/bin/hostname -F /etc/hostname -# now run any rc scripts -::sysinit:/etc/init.d/rcS - -# Put a getty on the serial port -#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100 # GENERIC_SERIAL - -# Stuff to do for the 3-finger salute -::ctrlaltdel:/sbin/reboot - -# Stuff to do before rebooting -::shutdown:/etc/init.d/rcK -::shutdown:/sbin/swapoff -a -::shutdown:/bin/umount -a -r
system/system.mk +4 -28
@@ -87,35 +87,11 @@ endef endif TARGET_FINALIZE_HOOKS += SYSTEM_BIN_SH -ifeq ($(BR2_TARGET_GENERIC_GETTY),y) -ifeq ($(BR2_PACKAGE_SYSVINIT),y) -# In sysvinit inittab, the "id" must not be longer than 4 bytes, so we -# skip the "tty" part and keep only the remaining. -define SYSTEM_GETTY - $(SED) '/# GENERIC_SERIAL$$/s~^.*#~$(shell echo $(TARGET_GENERIC_GETTY_PORT) | tail -c+4)::respawn:/sbin/getty -L $(TARGET_GENERIC_GETTY_OPTIONS) $(TARGET_GENERIC_GETTY_PORT) $(TARGET_GENERIC_GETTY_BAUDRATE) $(TARGET_GENERIC_GETTY_TERM) #~' \ - $(TARGET_DIR)/etc/inittab -endef -else -# Add getty to busybox inittab -define SYSTEM_GETTY - $(SED) '/# GENERIC_SERIAL$$/s~^.*#~$(TARGET_GENERIC_GETTY_PORT)::respawn:/sbin/getty -L $(TARGET_GENERIC_GETTY_OPTIONS) $(TARGET_GENERIC_GETTY_PORT) $(TARGET_GENERIC_GETTY_BAUDRATE) $(TARGET_GENERIC_GETTY_TERM) #~' \ - $(TARGET_DIR)/etc/inittab -endef -endif -TARGET_FINALIZE_HOOKS += SYSTEM_GETTY -endif - -ifeq ($(BR2_TARGET_GENERIC_REMOUNT_ROOTFS_RW),y) -# Find commented line, if any, and remove leading '#'s -define SYSTEM_REMOUNT_RW - $(SED) '/^#.*-o remount,rw \/$$/s~^#\+~~' $(TARGET_DIR)/etc/inittab -endef -else -# Find uncommented line, if any, and add a leading '#' -define SYSTEM_REMOUNT_RW - $(SED) '/^[^#].*-o remount,rw \/$$/s~^~#~' $(TARGET_DIR)/etc/inittab +ifneq ($(BR2_INIT),) +define FINALIZE_INIT + support/init/finalize $(BR2_INIT) endef +TARGET_FINALIZE_HOOKS += FINALIZE_INIT endif -TARGET_FINALIZE_HOOKS += SYSTEM_REMOUNT_RW endif # BR2_ROOTFS_SKELETON_DEFAULT
Signature · 1 line
2.0.3
RFC 4/11 help entries for Init system config menu
In reply to Alex SuykovPrimary focus is on (auto-)respawning and runtime control. Background/foreground distinction is not mentioned, since it is not likely to mean much for users making a choice here.
--- system/Config.in | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
system/Config.in +58 -0
@@ -75,15 +75,46 @@ config BR2_TARGET_GENERIC_PASSWD_METHOD choice prompt "Init system" default BR2_INIT_BUSYBOX + help + Upon bootup, kernel spawns init and init is expected + to spawn anything else. + + Buildroot can pre-configure the target filesystem + so that everything necessary to start the system + is done and all installed daemons are started. + + There are several possible configurations providing + varying degrees of control over the spawned processes. config BR2_INIT_BUSYBOX bool "BusyBox" select BR2_PACKAGE_BUSYBOX + help + Minimalistic init implementation from busybox + with systemV-style init scripts. + + No runlevel support. + Daemons can be stopped or restarted at runtime. + Daemons are started in background using scripts + from /etc/init.d, and controlled using pid files. + Failed processes are not respawned. config BR2_INIT_SYSV bool "systemV" select BR2_PACKAGE_BUSYBOX_SHOW_OTHERS # sysvinit select BR2_PACKAGE_SYSVINIT + help + System V init, probably the best-known init + implementation in Linux, with simplified SysV-style + initscripts. + + Supports runlevels, but this particular configuration + does not use them. + + Daemons can be stopped or restarted at runtime. + Daemons are started in background using scripts + from /etc/init.d, and controlled using pid files. + Failed processes are not respawned. config BR2_INIT_SYSTEMD bool "systemd"
@@ -98,6 +129,27 @@ config BR2_INIT_SYSTEMD depends on !BR2_STATIC_LIBS depends on BR2_TOOLCHAIN_HEADERS_AT_LEAST_3_7 select BR2_PACKAGE_SYSTEMD + help + systemd is more that just an init implementation. + It is a composite package handling most aspects + of system initialization and daemon supervision. + + All daemons will be started in foreground mode, + configured to be respawed on failure. + + Systemd uses arbitrary-named "targets" instead + of systemV-style runlevels, and allows stopping and + restarting daemons at runtime using systemctl command. + + Due its pervasiveness and extensive feature range, + choosing systemd shapes the rest of the system. + A systemd-based buildroot will differ little + from any major systemd-based Linux distribution + in pretty much any aspects of the boot process, + initialization, runtime configuration and process + supervision. + + Beware of its large size and numerous dependencies. comment 'systemd needs an (e)glibc toolchain, headers >= 3.7' depends on !(BR2_TOOLCHAIN_USES_GLIBC \
@@ -105,6 +157,12 @@ comment 'systemd needs an (e)glibc toolchain, headers >= 3.7' config BR2_INIT_NONE bool "None" + help + Do not install any kind of init system. + + Make sure your initrd and/or root fs skeleton provide + some executable for kernel to start, otherwise + the system will panic at boot. endchoice
Signature · 1 line
2.0.3
RFC 5/11 bare bb init configuration
In reply to Alex SuykovThis patch introduces a new init system: bb init without system V initscripts.
Busybox init is quite capable of running foreground daemons, with fast startup and auto-restarts but without the overhead of systemd. It lacks telinit and cannot start or stop daemons at runtime, but not every systems needs runtime control.
With the infrastructure mostly in place, implementing this is straightforward. Per-package initlines are installed in output/parts/ and init/finalize script picks them up to form a complete inittab.
Whenever a daemon needs some pre-start initialization and/or can not be started directly from inittab for other reasons, a shell script is created in /etc/rc/.
To keep things organized, initialization scripts (scripts that do not start a long-running foreground process) are put in /etc/rc/sys/ while anything directly in /etc/rc/ is expected to be used for :respawn: lines.
--- package/Makefile.in | 2 ++ support/init/finalize | 44 ++++++++++++++++++++++++- support/init/install-run | 83 ++++++++++++++++++++++++++++++++++++++++++++++-- support/init/rc.sys/mdev | 4 +++ support/init/rc.sys/udev | 8 +++++ system/Config.in | 16 ++++++++-- 6 files changed, 152 insertions(+), 5 deletions(-) create mode 100755 support/init/rc.sys/mdev create mode 100755 support/init/rc.sys/udev
package/Makefile.in +2 -0
@@ -412,6 +412,8 @@ ifdef BR2_INIT_SYSV BR2_INIT = initscripts else ifdef BR2_INIT_BUSYBOX BR2_INIT = initscripts +else ifdef BR2_INIT_BUSYBOX_BARE +BR2_INIT = inittab else ifdef BR2_INIT_SYSTEMD BR2_INIT = systemd else
support/init/finalize +43 -1
56 lines not on this page · raw message
support/init/install-run +81 -2
107 lines not on this page · raw message
support/init/rc.sys/mdev new file +4 -0
@@ -0,0 +1,4 @@ +#!/bin/sh + +echo /sbin/mdev >/proc/sys/kernel/hotplug +exec /sbin/mdev -s
support/init/rc.sys/udev new file +8 -0
@@ -0,0 +1,8 @@ +#!/bin/sh + +# udevd must be running by this point! + +printf '\000\000\000\000' > /proc/sys/kernel/hotplug +udevadm trigger --type=subsystems --action=add +udevadm trigger --type=devices --action=add +udevadm settle --timeout=30
system/Config.in +14 -2
@@ -86,8 +86,20 @@ choice There are several possible configurations providing varying degrees of control over the spawned processes. +config BR2_INIT_BUSYBOX_BARE + bool "BusyBox / inittab" + select BR2_PACKAGE_BUSYBOX + help + Minimalistic init implementation from busybox. + Daemons are written directly to /etc/inittab. + + No runlevel support. + No runtime control over processes. + Daemons are started in foreground mode, + failed processes are respawned. + config BR2_INIT_BUSYBOX - bool "BusyBox" + bool "BusyBox / initscripts" select BR2_PACKAGE_BUSYBOX help Minimalistic init implementation from busybox
@@ -100,7 +112,7 @@ config BR2_INIT_BUSYBOX Failed processes are not respawned. config BR2_INIT_SYSV - bool "systemV" + bool "sysvinit / initscripts" select BR2_PACKAGE_BUSYBOX_SHOW_OTHERS # sysvinit select BR2_PACKAGE_SYSVINIT help
Signature · 1 line
2.0.3
RFC 6/11 ptp: new init infrastructure
In reply to Alex SuykovTypical package: a simple foreground daemon.
--- package/ptpd/S65ptpd | 29 ----------------------------- package/ptpd/ptpd.mk | 5 ----- package/ptpd/ptpd.run | 1 + 3 files changed, 1 insertion(+), 34 deletions(-) delete mode 100755 package/ptpd/S65ptpd create mode 100644 package/ptpd/ptpd.run
package/ptpd/S65ptpd deleted +0 -29
@@ -1,29 +0,0 @@ -#!/bin/sh -# -# Start ptpd -# - -case "$1" in - start) - echo -n "Starting ptpd: " - start-stop-daemon -S -q -x /usr/sbin/ptpd -- -S - if [ $? != 0 ]; then - echo "FAILED" - exit 1 - else - echo "OK" - fi - ;; - stop) - echo -n "Stopping ptpd: " - start-stop-daemon -K -q -x /usr/sbin/ptpd - echo "OK" - ;; - restart|reload) - ;; - *) - echo "Usage: $0 {start|stop|restart}" - exit 1 -esac - -exit $?
package/ptpd/ptpd.mk +0 -5
@@ -17,9 +17,4 @@ define PTPD_INSTALL_TARGET_CMDS $(INSTALL) -m 755 -D $(@D)/src/ptpd $(TARGET_DIR)/usr/sbin/ptpd endef -define PTPD_INSTALL_INIT_SYSV - $(INSTALL) -m 755 -D package/ptpd/S65ptpd \ - $(TARGET_DIR)/etc/init.d/S65ptpd -endef - $(eval $(generic-package))
package/ptpd/ptpd.run new file +1 -0
@@ -0,0 +1 @@ +exec /usr/sbin/ptpd -c -S
Signature · 1 line
2.0.3
RFC 7/11 upmpcli: new init infrastructure
In reply to Alex SuykovTypical package: simple foreground daemon and its effective user entry.
--- package/upmpdcli/S99upmpdcli | 40 ---------------------------------------- package/upmpdcli/upmpdcli.mk | 9 --------- package/upmpdcli/upmpdcli.run | 1 + package/upmpdcli/upmpdcli.users | 1 + 4 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 package/upmpdcli/S99upmpdcli create mode 100644 package/upmpdcli/upmpdcli.run create mode 100644 package/upmpdcli/upmpdcli.users
package/upmpdcli/S99upmpdcli deleted +0 -40
@@ -1,40 +0,0 @@ -#!/bin/sh - -NAME=upmpdcli -DAEMON=/usr/bin/$NAME -CONFFILE=/etc/$NAME.conf -PIDFILE=/var/run/$NAME.pid -DAEMON_ARGS="-D -c $CONFFILE" - -# Sanity checks -test -f $DAEMON || exit 0 - -start() { - echo -n "Starting $NAME: " - start-stop-daemon --start --quiet --background --exec $DAEMON \ - -- $DAEMON_ARGS \ - && echo "OK" || echo "FAIL" -} - -stop() { - echo -n "Stopping $NAME: " - start-stop-daemon --stop --quiet --pidfile $PIDFILE \ - && echo "OK" || echo "FAIL" -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - stop - sleep 1 - start - ;; - *) - echo "Usage: $0 {start|stop|restart}" - exit 1 -esac
package/upmpdcli/upmpdcli.mk +0 -9
@@ -10,15 +10,6 @@ UPMPDCLI_LICENSE = GPLv2+ UPMPDCLI_LICENSE_FILES = COPYING UPMPDCLI_DEPENDENCIES = libmpdclient libupnpp -# Upmpdcli only runs if user upmpdcli exists -define UPMPDCLI_USERS - upmpdcli -1 upmpdcli -1 * - - - Upmpdcli MPD UPnP Renderer Front-End -endef - -define UPMPDCLI_INSTALL_INIT_SYSV - $(INSTALL) -D -m 0755 package/upmpdcli/S99upmpdcli $(TARGET_DIR)/etc/init.d/S99upmpdcli -endef - define UPMPDCLI_INSTALL_CONF_FILE $(INSTALL) -D -m 0755 $(@D)/src/upmpdcli.conf $(TARGET_DIR)/etc/upmpdcli.conf endef
package/upmpdcli/upmpdcli.run new file +1 -0
@@ -0,0 +1 @@ +exec /usr/bin/upmpdcli
package/upmpdcli/upmpdcli.users new file +1 -0
@@ -0,0 +1 @@ +upmpdcli -1 upmpdcli -1 * - - - Upmpdcli MPD UPnP Renderer Front-End
Signature · 1 line
2.0.3
RFC 8/11 acpid: new init infrastructure
In reply to Alex SuykovSystemd has built-in support for acpi events and does not need acpid.
--- package/acpid/S02acpid | 22 ---------------------- package/acpid/acpid.mk | 5 ----- package/acpid/acpid.run | 3 +++ 3 files changed, 3 insertions(+), 27 deletions(-) delete mode 100755 package/acpid/S02acpid create mode 100644 package/acpid/acpid.run
package/acpid/S02acpid deleted +0 -22
@@ -1,22 +0,0 @@ -#!/bin/sh - -case "$1" in - start) - echo -n "Starting acpid: " - start-stop-daemon -S -q -m -b -p /var/run/acpid.pid --exec /usr/sbin/acpid -- -n - [ $? = 0 ] && echo "OK" || echo "FAIL" - ;; - stop) - echo -n "Stopping acpid: " - start-stop-daemon -K -q -p /var/run/acpid.pid - [ $? = 0 ] && echo "OK" || echo "FAIL" - ;; - restart) - "$0" stop - sleep 1 - "$0" start - ;; - *) - echo "Usage: $0 {start|stop|restart}" - ;; -esac
package/acpid/acpid.mk +0 -5
@@ -10,11 +10,6 @@ ACPID_SITE = http://downloads.sourceforge.net/project/acpid2 ACPID_LICENSE = GPLv2+ ACPID_LICENSE_FILES = COPYING -define ACPID_INSTALL_INIT_SYSV - $(INSTALL) -D -m 0755 package/acpid/S02acpid \ - $(TARGET_DIR)/etc/init.d/S02acpid -endef - define ACPID_SET_EVENTS mkdir -p $(TARGET_DIR)/etc/acpi/events printf "event=button[ /]power\naction=/sbin/poweroff\n" \
package/acpid/acpid.run new file +3 -0
@@ -0,0 +1,3 @@ +## ACPI daemon +systemd - +exec /usr/sbin/acpid -f -n
Signature · 1 line
2.0.3
RFC 9/11 am33x-cm3: new init infrastructure
In reply to Alex SuykovNon-daemon entry.
--- package/am33x-cm3/S93-am335x-pm-firmware-load | 6 ------ package/am33x-cm3/am33x-cm3.mk | 5 ----- package/am33x-cm3/am33x-cm3.run | 6 ++++++ 3 files changed, 6 insertions(+), 11 deletions(-) delete mode 100755 package/am33x-cm3/S93-am335x-pm-firmware-load create mode 100644 package/am33x-cm3/am33x-cm3.run
package/am33x-cm3/S93-am335x-pm-firmware-load deleted +0 -6
@@ -1,6 +0,0 @@ -#!/bin/sh - -# Load the PM CM3 firmware -echo 1 > /sys/devices/ocp.2/44d00000.wkup_m3/firmware/am335x-pm-firmware.bin/loading -cat /lib/firmware/am335x-pm-firmware.bin > /sys/devices/ocp.2/44d00000.wkup_m3/firmware/am335x-pm-firmware.bin/data -echo 0 > /sys/devices/ocp.2/44d00000.wkup_m3/firmware/am335x-pm-firmware.bin/loading
package/am33x-cm3/am33x-cm3.mk +0 -5
@@ -23,9 +23,4 @@ define AM33X_CM3_INSTALL_TARGET_CMDS $(TARGET_DIR)/lib/firmware/am335x-pm-firmware.bin endef -define AM33X_CM3_INSTALL_INIT_SYSV - $(INSTALL) -m 0755 -D package/am33x-cm3/S93-am335x-pm-firmware-load \ - $(TARGET_DIR)/etc/init.d/S93-am335x-pm-firmware-load -endef - $(eval $(generic-package))
package/am33x-cm3/am33x-cm3.run new file +5 -0
@@ -0,0 +1,5 @@ +## Load the PM CM3 firmware + +echo 1 > /sys/devices/ocp.2/44d00000.wkup_m3/firmware/am335x-pm-firmware.bin/loading +cat /lib/firmware/am335x-pm-firmware.bin > /sys/devices/ocp.2/44d00000.wkup_m3/firmware/am335x-pm-firmware.bin/data +echo 0 > /sys/devices/ocp.2/44d00000.wkup_m3/firmware/am335x-pm-firmware.bin/loading
Signature · 1 line
2.0.3
RFC 10/11 postgresql: new init infrastructure
In reply to Alex SuykovOne of the most complicated entries. Users, files, and pre-start initialization that must be done with a specific user id.
--- package/postgresql/S50postgresql | 44 ----------------------------------- package/postgresql/postgresql.files | 1 + package/postgresql/postgresql.mk | 17 -------------- package/postgresql/postgresql.run | 6 +++++ package/postgresql/postgresql.service | 24 ------------------- package/postgresql/postgresql.users | 1 + 6 files changed, 8 insertions(+), 85 deletions(-) delete mode 100644 package/postgresql/S50postgresql create mode 100644 package/postgresql/postgresql.files create mode 100644 package/postgresql/postgresql.run delete mode 100644 package/postgresql/postgresql.service create mode 100644 package/postgresql/postgresql.users
package/postgresql/S50postgresql deleted +0 -44
@@ -1,44 +0,0 @@ -#!/bin/sh -# -# start postgresql -# - -umask 077 - -if [ ! -f /var/lib/pgsql/PG_VERSION ]; then - echo "Initializing postgresql data base..." - su - postgres -c '/usr/bin/pg_ctl initdb -D /var/lib/pgsql' - echo "done" -fi - -start() { - echo -n "Starting postgresql: " - su - postgres -c '/usr/bin/pg_ctl start -D /var/lib/pgsql -l logfile' - echo "OK" -} -stop() { - echo -n "Stopping postgresql: " - su - postgres -c '/usr/bin/pg_ctl stop -D /var/lib/pgsql -m fast' - echo "OK" -} -restart() { - stop - start -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart|reload) - restart - ;; - *) - echo "Usage: $0 {start|stop|restart}" - exit 1 -esac - -exit $?
package/postgresql/postgresql.files new file +1 -0
@@ -0,0 +1 @@ +/var/lib/pgsql d 0700 postgresql postgresql - - - - -
package/postgresql/postgresql.mk +0 -17
@@ -60,10 +60,6 @@ ifeq ($(BR2_PACKAGE_OPENSSL),y) POSTGRESQL_CONF_OPTS += --with-openssl endif -define POSTGRESQL_USERS - postgres -1 postgres -1 * /var/lib/pgsql /bin/sh - PostgreSQL Server -endef - define POSTGRESQL_INSTALL_TARGET_FIXUP $(INSTALL) -dm 0700 $(TARGET_DIR)/var/lib/pgsql $(RM) -rf $(TARGET_DIR)/usr/lib/postgresql/pgxs
@@ -78,17 +74,4 @@ endef POSTGRESQL_POST_INSTALL_STAGING_HOOKS += POSTGRESQL_INSTALL_CUSTOM_PG_CONFIG -define POSTGRESQL_INSTALL_INIT_SYSV - $(INSTALL) -m 0755 -D package/postgresql/S50postgresql \ - $(TARGET_DIR)/etc/init.d/S50postgresql -endef - -define POSTGRESQL_INSTALL_INIT_SYSTEMD - $(INSTALL) -D -m 644 package/postgresql/postgresql.service \ - $(TARGET_DIR)/usr/lib/systemd/system/postgresql.service - mkdir -p $(TARGET_DIR)/etc/systemd/system/multi-user.target.wants - ln -fs ../../../../usr/lib/systemd/system/postgresql.service \ - $(TARGET_DIR)/etc/systemd/system/multi-user.target.wants/postgresql.service -endef - $(eval $(autotools-package))
package/postgresql/postgresql.run new file +6 -0
@@ -0,0 +1,6 @@ +## PostgreSQL database server +user postgres +group postgres + +test -f /var/lib/pgsql/PG_VERSION || /usr/bin/initdb -D /var/lib/pgsql +exec /usr/bin/postmaster -D /var/lib/pgsql
package/postgresql/postgresql.service deleted +0 -24
@@ -1,24 +0,0 @@ -[Unit] -Description=PostgreSQL database server -After=network.target - -[Service] -Type=forking - -# start timeout disabled because initdb may run a little -# longer (eg. 5 minutes on RaspberryPi) -TimeoutStartSec=0 - -User=postgres -Group=postgres - -SyslogIdentifier=postgres -PIDFile=/var/lib/pgsql/postmaster.pid - -ExecStartPre=/bin/sh -c "if [ ! -f /var/lib/pgsql/PG_VERSION ]; then /usr/bin/pg_ctl initdb -D /var/lib/pgsql; fi" -ExecStart=/usr/bin/pg_ctl start -D /var/lib/pgsql -w -l /var/lib/pgsql/logfile -ExecReload=/usr/bin/pg_ctl reload -D /var/lib/pgsql -ExecStop=/usr/bin/pg_ctl stop -D /var/lib/pgsql -m fast - -[Install] -WantedBy=multi-user.target
package/postgresql/postgresql.users new file +1 -0
@@ -0,0 +1 @@ +postgres -1 postgres -1 * /var/lib/pgsql /bin/sh - PostgreSQL Server
Signature · 1 line
2.0.3
RFC 11/11 openvpn: new init infrastructure
In reply to Alex SuykovThe only case so far that install-run can not handle. Openvpn initscript spawns several processes, one for each configured tunnel.
Initscripts is the only system that allows this, primarily because it does not need to track spawned processes.
--- package/openvpn/S60openvpn | 103 ------------------------------------------- package/openvpn/openvpn.init | 103 +++++++++++++++++++++++++++++++++++++++++++ package/openvpn/openvpn.mk | 5 --- package/openvpn/openvpn.run | 1 + 4 files changed, 104 insertions(+), 108 deletions(-) delete mode 100755 package/openvpn/S60openvpn create mode 100755 package/openvpn/openvpn.init create mode 100644 package/openvpn/openvpn.run
package/openvpn/S60openvpn deleted +0 -103
@@ -1,103 +0,0 @@ -#!/bin/sh -e -# -# Original version by Robert Leslie -# <[email protected]>, edited by iwj and cs -# Modified for openvpn by Alberto Gonzalez Iniesta <[email protected]> -# Modified for restarting / starting / stopping single tunnels by Richard Mueller <[email protected]> - -test $DEBIAN_SCRIPT_DEBUG && set -v -x - -DAEMON=/usr/sbin/openvpn -CONFIG_DIR=/etc/openvpn -test -x $DAEMON || exit 0 -test -d $CONFIG_DIR || exit 0 - -start_vpn () { - $DAEMON --daemon --writepid /var/run/openvpn.$NAME.pid \ - --config $CONFIG_DIR/$NAME.conf --cd $CONFIG_DIR || echo -n " FAILED->" - echo -n " $NAME" -} -stop_vpn () { - kill `cat $PIDFILE` || true - rm $PIDFILE -} - -case "$1" in -start) - echo -n "Starting openvpn:" - - if test -z $2 ; then - for CONFIG in `cd $CONFIG_DIR; ls *.conf 2> /dev/null`; do - NAME=${CONFIG%%.conf} - start_vpn - done - else - if test -e $CONFIG_DIR/$2.conf ; then - NAME=$2 - start_vpn - else - echo -n " No such VPN: $2" - fi - fi - echo "." - - ;; -stop) - echo -n "Stopping openvpn:" - - if test -z $2 ; then - for PIDFILE in `ls /var/run/openvpn.*.pid 2> /dev/null`; do - NAME=`echo $PIDFILE | cut -c18-` - NAME=${NAME%%.pid} - stop_vpn - echo -n " $NAME" - done - else - if test -e /var/run/openvpn.$2.pid ; then - PIDFILE=`ls /var/run/openvpn.$2.pid 2> /dev/null` - NAME=`echo $PIDFILE | cut -c18-` - NAME=${NAME%%.pid} - stop_vpn - echo -n " $NAME" - else - echo -n " No such VPN: $2" - fi - fi - echo "." - ;; -# We only 'reload' for running VPNs. New ones will only start with 'start' or 'restart'. -reload|force-reload) - echo -n "Reloading openvpn:" - for PIDFILE in `ls /var/run/openvpn.*.pid 2> /dev/null`; do - NAME=`echo $PIDFILE | cut -c18-` - NAME=${NAME%%.pid} -# If openvpn if running under a different user than root we'll need to restart - if egrep '^( |\t)*user' $CONFIG_DIR/$NAME.conf > /dev/null 2>&1 ; then - stop_vpn - sleep 1 - start_vpn - echo -n "(restarted)" - else - kill -HUP `cat $PIDFILE` || true -# start-stop-daemon --stop --signal HUP --quiet --oknodo \ -# --exec $DAEMON --pidfile $PIDFILE - echo -n " $NAME" - fi - done - echo "." - ;; - -restart) - $0 stop $2 - sleep 1 - $0 start $2 - ;; -*) - echo "Usage: $0 {start|stop|reload|restart|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 - -# vim:set ai et sts=2 sw=2 tw=0:
package/openvpn/openvpn.init new file +103 -0
103 lines not on this page · raw message
package/openvpn/openvpn.mk +0 -5
@@ -52,9 +52,4 @@ define OPENVPN_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/sbin/openvpn endef -define OPENVPN_INSTALL_INIT_SYSV - $(INSTALL) -m 755 -D package/openvpn/S60openvpn \ - $(TARGET_DIR)/etc/init.d/S60openvpn -endef - $(eval $(autotools-package))
package/openvpn/openvpn.run new file +1 -0
@@ -0,0 +1 @@ +initscripts 60:openvpn.init
Signature · 1 line
2.0.3
cover common init infrastructure
In reply to Alex SuykovQuoted 4 lines · Alex Suykov
This series is intended to clean up buildroot init system somewhat, removing the need for extensive sysv and systemd handling code in every package that installs init bits, and allowing alternative init systems to be implemented with reasonable amount of effort.
Wow, impressive. I hadn't imagined it would be possible to get this far.
I have a couple of overall remarks before I dive into the individual patches.
- Although we have a dependency on python, we don't currently use python for any of the core functionality (i.e., just building). Personally I like python a lot, but now you already have to know make and shell pretty well in order to touch the buildroot core. Adding python to the mix is making the threshold even higher.
- The generation script looks a bit complicated, while on the other hand the .run files are really terse. I'd prefer a bit more verbosity in the .run files, especially if that can make the generation script a bit simpler.
- The changes for .users and .files are pretty much independent from this series so they could be put in a separate series. And I'm anyway not convinced that they're worthwhile.
Regards,
Arnout
Quoted 35 lines
Overview of the changes:
* drop per-package sysv and systemd files, introduce common format used to generate files for both of them, use a script to do the conversion from common format to sysv or systemd.
* remove sysv and systemd installation code from package .mk files, let pkg-generic handle it.
* remove sysv-specific files from skeleton, and sysv-specific hacks from
system/system.mk. Use a dedicated script to write inittab, handling global conditionals (root rw/ro, serial getty and so on)* remove user definitions from package .mk files, and mkdirs from per-package sysv initscript, use per-package .users and .files instead in a way similar to .hash files.
Expected benefits:
* (almost) all packages get both sysv and systemd files at the same time and without the need to support them separately.
* init-related changes can be introduced without patching all 70+ individual packages that install startup files.
* new init systems can be introduced with only minor effort, including lightweight ones with controlled (foreground) daemons.
This series includes the infrastructure changes, and a couple of package patches to show how it looks like. Complete set of package patches uploaded here: https://github.com/arsv/br/
This series is for reviewing, not for merging.
Signature · 6 lines
Arnout Vandecappelle arnout at mind be Senior Embedded Software Architect +32-16-286500 Essensium/Mind http://www.mind.be G.Geenslaan 9, 3001 Leuven, Belgium BE 872 984 063 RPR Leuven LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle GPG fingerprint: 7CB5 E4CC 6C2E EFD4 6E3D A754 F963 ECAB 2450 2F1F
RFC 1/11 common service startup files
In reply to Alex SuykovQuoted 8 lines · Alex Suykov
This patch introduces support infrastructure for per-project .run files.
Any .run files in package directory are picked up by pkg-generic code, fed to support/init/install-run script which converts them into either sysv initscripts or systemd unit files and installs those into predefined locations. The package itself provides only the .run files, no code in package .mk file is necessary.
Quoted 6 lines
Packages that install some of their services conditionally may set $(PKG)_INIT = list of run files to install. As a side effect, this removes the need to handle S99foo S99bar vs foo.service bar.service with the package .mk file.
Packages that need to substititue some values within their service
substitute
Quoted 3 lines
files may set $(PKG)_INIT = KEY:value KEY:value ..., which will be handled by install-run. The substitutions will be applied to sysv and systemd files.
I don't see why this is needed, and it probably makes the install-run script
more complicated.
Quoted 6 lines
In case particular init system needs hand-crafted startup files or cannot handle certain services at all, install-run may be told so using special lines in the .run file.
This patch does not remove existing BR2_INIT_{SYSV,SYSTEMD} hooks.
Good!
Quoted 2 lines
Each package should either provide .run files or define hooks, but not both.
---
Missing SoB, but perhaps that's intentional because it's not ready for inclusion?
Quoted 15 lines
package/Makefile.in | 10 + package/pkg-generic.mk | 23 +++ support/init/install-run | 457 +++++++++++++++++++++++++++++++++++++++++++ support/init/install-tmpconf | 7 + 4 files changed, 497 insertions(+) create mode 100755 support/init/install-run create mode 100755 support/init/install-tmpconfpackage/Makefile.in +0
-0@@ -408,6 +408,16 @@ ifeq ($(BR2_COMPILER_PARANOID_UNSAFE_PATH),y) export BR_COMPILER_PARANOID_UNSAFE_PATH=enabled endif
package/Makefile.in ifeq ($(BR2_COMPILER_PARANOID_UNSAFE_PATH),y) · line 419
Quoted 10 lines
package/Makefile.in +9
-0+ifdef BR2_INIT_SYSV +BR2_INIT = initscripts +else ifdef BR2_INIT_BUSYBOX +BR2_INIT = initscripts +else ifdef BR2_INIT_SYSTEMD +BR2_INIT = systemd +else +BR2_INIT = none +endif
It's nicer to do this kind of switch in system/Config.in:
config BR2_INIT
string default "initscripts" if BR2_INIT_SYSV || BR2_INIT_BUSYBOX default "systemd" if BR2_INIT_SYSTEMD default "none"
Quoted 9 lines
package/Makefile.in +1
-0+ include package/pkg-download.mk include package/pkg-autotools.mk include package/pkg-cmake.mkpackage/pkg-generic.mk +0
-0
package/pkg-generic.mk ifneq ($$(call suitable-extractor,$$($(2)_SOURCE)),$$(XZCAT)) · line 768
Quoted 7 lines
package/pkg-generic.mk +4
-0@@ -762,10 +762,33 @@ ifneq ($$(call suitable-extractor,$$($(2)_SOURCE)),$$(XZCAT)) DL_TOOLS_DEPENDENCIES += $$(firstword $$(call suitable-extractor,$$($(2)_SOURCE))) endif +# Init, users and files are for target image only +ifeq ($4,target) + +$(2)_INIT ?= $$(notdir $$(wildcard package/$1/*.run))
package/$1/ is not correct, because it could be outside of the package
directory (e.g. external) or in a subdirectory. Use $(pkgdir) instead (note:
only one $!).
package/pkg-generic.mk ifneq ($$(call suitable-extractor,$$($(2)_SOURCE)),$$(XZCAT)) · line 773
Quoted 5 lines
package/pkg-generic.mk +5
-0+$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_INSTALL_INIT + +# This will expand to (nothing) if none of the files are present +# in the package directory. +ifndef $(2)_INSTALL_INIT
There should never be any reason for a package to override _INSTALL_INIT, they
can just avoid adding *.run files or setting _INIT.
Therefore, I'd also move this to the %/.stamp_target_installed rule. That makes
it easier to understand because of less $$. Note that that is also the place where the current init handling is done. With that done, there is also no need to keep the definition of _INIT in the ifeq($4,target) condition.
package/pkg-generic.mk ifneq ($$(call suitable-extractor,$$($(2)_SOURCE)),$$(XZCAT)) · line 776
Quoted 3 lines
package/pkg-generic.mk +3
-0+define $(2)_INSTALL_INIT + $$(call ifargs,support/init/install-run $$(BR2_INIT) \ + $$($$(PKG)_INIT_SUBST),$$(addprefix package/$1/,$$($$(PKG)_INIT)))
The line is split at an inconvenient place here.
I wouldn't do this $(notdir) and $(addprefix) magic. It's OK for the package
.mk file to be required to provide the full path to the .run file.
package/pkg-generic.mk ifneq ($$(call suitable-extractor,$$($(2)_SOURCE)),$$(XZCAT)) · line 777
Quoted 1 line
package/pkg-generic.mk +1
-0+ $$(call ifargs,support/init/install-tmpconf $$(BR2_INIT),$$(wildcard package/$1/*.tmp.conf))
This tmpdir support should probably be in a separate patch.
BTW, shouldn't tmpdirs be handled for sysv as well? Typically, the init script
will create the tmpdir...
package/pkg-generic.mk ifneq ($$(call suitable-extractor,$$($(2)_SOURCE)),$$(XZCAT)) · line 789
Quoted 12 lines
package/pkg-generic.mk +8
-0+endef +endif + +endif # $4 == target + endif # $(2)_KCONFIG_VAR endef # inner-generic-package ################################################################################ +define ifargs + $(if $2,$1 $2) +endef
This should go to pkg-utils instead.
support/init/install-run
Quoted 10 lines
package/pkg-generic.mk +2
-0+ +################################################################################ # generic-package -- the target generator macro for generic packages ################################################################################support/init/install-run new file +0
-0
I've spent about an hour trying to understand this script, and I'm still not
fully there... So this probably falls in the "too complicated" category. I still have a bunch of stylistic remarks below, but here are some overall thoughts.
- The script should do something as simple as possible. The variable
substitution is an example of something that is (probably) adding complexity, and it can be done in a different way, e.g. running a sed script afterwards.
- The script should only handle cases that are actually used. So start with
something extremely simple that covers a few interesting cases, and leave the others to use the old initscripts system.
- There should be a lot more comments to explain what is done and why.
- You should start with the documentation of what it's supposed to do. That
makes it easier for us to understand what it's doing (and to say which things it shouldn't do :-)
- Avoid the getattr() etc. magic. It's easier to understand what's going on if
things are in a simple and explicit dict.
- Use existing infrastructure where possible. For instance, you could change
the .run format into .ini format and use configparser, or you could use the shlex module for parsing.
- Don't make names too short, they should always be descriptive. 'w' is not a
good name for a function. If typing is a problem for you, get an editor that supports completion.
- You should take care of the exit conditions (and document them). If there is
something wrong with a .run file or with the script itself, it should exit fatally and the build should be stopped. But if the .run file contains something that is not supported for this init system, this should be non-fatal.
Quoted 8 lines
support/init/install-run new file +7
-0@@ -0,0 +1,457 @@ +#!/usr/bin/env python + +# Usage: +# +# install-init [-] init-system [VAR1:val1 VAR2:val2 ...] file1.run file2.run ... +# +# init-system is one the values from inits array below.
support/init/install-run line 17
Quoted 10 lines
support/init/install-run new file +10
-0+# +# The script will write relevant configuration files to output/target/etc/..., +# so it should be called from the top Buildroot directory. +# Use - to write all files to the current directory (useful for debugging) + +# Bundling all init systems into a single script, vs having install-init-(system) +# scripts for each system, may look strange, but it turns out most of the code +# below is common for all init systems. + +from sys import stderr, argv
We don't do that. Just
import sys
... sys.argv ...
support/init/install-run line 27
Quoted 10 lines
support/init/install-run new file +10
-0+from re import match, sub +from os.path import dirname, basename +from os import makedirs, fdopen, fstat, fchmod +from os import O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC +from os import open as osopen +from os import read as osread +from os import write as oswrite + +inits = ['initscripts', 'systemd'] +output = None
Don't put this in a global variable. A member of Run would be a good place.
support/init/install-run line 33
Quoted 6 lines
support/init/install-run new file +6
-0+nopath = False + +class Run: + def __init__(self, name, path): + self.path = path # full .run file name, for error reporting + self.name = name # service name = stem(basename(path))
This splitting into path and name should be handled here, in the constructor,
and not in the caller.
support/init/install-run line 43
Quoted 10 lines
support/init/install-run new file +10
-0+ + # This is a bit more complicated than it should be + # to allow reporting incorrect global keys while still + # accepting unadorned commands for pre/post groups. + + for k in ['description', 'user', 'group', 'umask', + 'pidfile', 'priority', + 'after', 'requires', 'wantedby', + 'busname', 'conflicts', 'killwith', 'restart']: + setattr(self, k, None)
This will also be simpler if you just use a dict.
Quoted 22 lines
support/init/install-run new file +22
-0+ + # sequence: + # pre-exec-post + # pre-start-stop-post + # pre (for run-once scripts) + self.pre = [] + self.post = [] + self.acts = ['exec', 'start', 'stop', 'reload'] + for k in self.acts: + setattr(self, k, None) + + for k in inits: + setattr(self, k, None) + + # variable substitutions + # (default values from .run until update() is called) + self.subs = {} + + def has(self, key): + return hasattr(self, key) + + def get(self, key):
support/init/install-run line 75
Quoted 10 lines
support/init/install-run new file +10
-0+ return getattr(self, key) + + def set(self, key, val): + setattr(self, key, val) + + def update(self, values): + self.subs.update(values) + + def isempty(self): + return (not self.exec and not self.start and not self.pre and not self.post)
exec is a reserved word in python2.
Quoted 23 lines
support/init/install-run new file +23
-0+ + def substcmds(self): + for k in ['pre', 'post']: + attr = getattr(self, k) + for i, s in enumerate(attr): + attr[i] = self.substvars(s) + for k in ['exec', 'start', 'stop', 'reload']: + attr = getattr(self, k) + if not attr is None: + setattr(self, k, self.substvars(attr)) + + def substvars(self, value): + def var(m): + k = m.group(1) + if k in self.subs: + return self.subs[k] + else: + return m.group(0) + + ret = sub(r'\$([A-Za-z]+)', var, value) + return ret + +
support/init/install-run line 108
Quoted 10 lines
support/init/install-run new file +10
-0+def die(message, *args): + stderr.write((message+"\n") % tuple(args)) + exit(-1) + + +def openread(filename): + try: + fh = open(filename) + except OSError: + die("Can't open %s" % filename)
This wrapper doesn't make a lot of sense. Such failures should anyway not
occur, because the script is always called with .run files. So it's OK to dump an exception stack on the user.
Quoted 5 lines
support/init/install-run new file +5
-0+ return fh + +def parse(name, path): + run = Run(name, path) + fh = openread(path)
support/init/install-run line 123
Quoted 10 lines
support/init/install-run new file +10
-0+ inscript = False # after the first empty line + pastpre = False # after exec/start/stop + firstline = True + + for line in fh: + line = line.strip() + + # Use ## for description, but only if it is the first line + if firstline and match('^## ', line): + run.description = line[3:]
Why this ## hack? "description = This is program foo" is much more descriptive.
Quoted 39 lines
support/init/install-run new file +39
-0+ else: + firstline = False + + # Skip comments in non-command section, but pass them through + # when inscript + if not inscript and match(r'^#', line): + continue + + # Empty line marks the start of script section + if not inscript and match(r'^\s*$', line): + inscript = True + continue + + m = match(r'^[A-Z_0-9]+=(.*)', line) + if m and not inscript: + run.subs[m.group(1)] = m.group(2) + continue + + m = match(r'^([A-Za-z]+)(\s+(.*))?', line) + if m: + key, val = m.group(1), m.group(3) + else: + key, val = None, None + + if not inscript and not key: + die("%s: bad line", path) + + if (not inscript and key) or (inscript and key in run.acts): + if run.get(key): + die("%s: cannot re-assign %s", path, key) + elif run.has(key): + run.set(key, val if m.group(2) else True) + else: + die("%s: unknown key %s", path, key) + if key in run.acts: + pastpre = True + elif inscript: + if pastpre: + run.post.append(line)
support/init/install-run line 172
Quoted 10 lines
support/init/install-run new file +10
-0+ else: + run.pre.append(line) + + if not run.priority: + if run.exec: + run.priority = '50' + elif run.start: + run.priority = '40' + else: + run.priority = '10'
The reasoning behind these static priorities should be explained somewhere.
Quoted 7 lines
support/init/install-run new file +7
-0+ + return run + +def openwrite(path, mode): + global nopath + + if nopath:
support/init/install-run line 189
Quoted 10 lines
support/init/install-run new file +10
-0+ path = basename(path) + else: + try: + makedirs(dirname(path)) + except OSError: + pass + + fd = osopen(path, O_WRONLY | O_CREAT | O_TRUNC) + fchmod(fd, mode) + return fd
This whole umask thing is useless IMHO. You also don't provide an example for it.
If someone is so paranoid that they think an init script should be
non-readable, they should give it a BR2_ROOTFS_DEVICE_TABLE entry.
And anyway, use chmod instead of fchmod.
So, if the umask is gone, you can just do open(path, 'w')
support/init/install-run line 199
Quoted 10 lines
support/init/install-run new file +10
-0+ +def writeto(path, mode): + global output + fd = openwrite(path, mode) + output = fdopen(fd, 'w') + +# write +def w(fmt, *subst): + global output + output.write((fmt+"\n") % subst)
Making a function for this is really not worth it.
Quoted 7 lines
support/init/install-run new file +7
-0+ +# write newline +def wnl(): w("") + +# write lines +def wl(fmt, array): + for l in array:
support/init/install-run line 216
Quoted 10 lines
support/init/install-run new file +10
-0+ w(fmt, l) + +# write-tab, write-tab-tab +def wt(fmt, *subst): w("\t" + fmt, *subst) +def wtt(fmt, *subst): w("\t\t" + fmt, *subst) + +# ------------------------------------------------------------------------------ + +# return either cmd or su cmd; the caller naturally handles shell commands +def maybesu(r, cmd):
Should be a method of Run.
support/init/install-run line 225
Quoted 9 lines
support/init/install-run new file +9
-0+ if r.user: + return "su - %s -c '%s'" % (r.user, cmd) + else: + return cmd + +# ------------------------------------------------------------------------------ + +def initscripts(r): + writeto('output/target/etc/init.d/S%02d%s' % (int(r.priority), r.name), 0o755)
Ah yes here you need to set the exec bit of course.
output/ is wrong, it could be modified by O=. Instead, you should passTARGET_DIR in the environment or on the commandline and use that.
Quoted 37 lines
support/init/install-run new file +37
-0+ + (start, stop) = initscripts_ssd(r) + + w("#!/bin/sh\n") + if r.description: + w("# %s\n", r.description) + + for k, v in r.subs.items(): + w("%s=%s", k, v) + if r.subs: + wnl() + + if r.umask: + w("umask %s", r.umask) + + w("case \"$1\" in") + w(" start)") + for c in r.pre: + wtt("%s", maybesu(r, c)) + if r.start: + wtt("%s", maybesu(r.start)) + elif start: + wtt("%s", start) + elif not r.pre and not r.post: + die("%s: cannot write initscript without any commands to run", r.path) + wtt(";;") + + wt("stop)") + if r.stop and not r.stop is True: + wtt("%s", r.stop) + elif r.start or r.exec: + wtt("%s", stop) + for c in r.post: + wtt("%s", maybesu(c)) + wtt(";;") + + if r.reload:
support/init/install-run line 272
Quoted 10 lines
support/init/install-run new file +10
-0+ wt("reload)") + wtt("%s", r.reload) + wtt(";;") + + wt("restart)") + wtt("$0 stop") + wtt("$0 start") + wtt(";;") + + w("esac")
A multiline template with %-formatting would be easier to understand. So:
completestart = map(maybesu,r.start).join('\n\t\t') completestart += ...
completestop = ...
output.write("""
#! /bin/sh
%s
case "$1" in
start) %s;; stop) %s;; restart|reload) $0 stop $0 start ;;
esac
""" % (substitions, completestart, completestop)
Quoted 4 lines
support/init/install-run new file +4
-0+ +# generate start-stop-daemon commands from r.exec +# run -> (start, stop) +def initscripts_ssd(r):
support/init/install-run line 286
Quoted 10 lines
support/init/install-run new file +10
-0+ if not r.exec: + return None, None + + if r.pidfile: + pidfile = r.pidfile + else: + pidfile = '/var/run/%s.pid' % r.name + + ssdopts = ['-S'] + sskopts = ['-K']
ssdopts and sskopts are visually too similar to make it easy to distinguish.
What about startopts and stopopts?
Quoted 4 lines
support/init/install-run new file +4
-0+ if r.user: + ssdopts.append('-c') + ssdopts.append(r.user) + if r.group:
support/init/install-run line 300
Quoted 10 lines
support/init/install-run new file +10
-0+ ssdopts.append('-g') + ssdopts.append(r.group) + if not r.pidfile and not r.start: + ssdopts.append('-m') + if pidfile: + ssdopts.append('-p') + ssdopts.append(pidfile) + sskopts.append('-p') + sskopts.append(pidfile) + ssdopts = (" ".join(ssdopts))
It's ugly if a variable is first a list and then a string. But you don't need
to do it here, just do the join below where it's used to construct start/stop.
support/init/install-run line 304
Quoted 4 lines
support/init/install-run new file +4
-0+ sskopts = (" ".join(sskopts)) + + cmd = sub(r'\s.*', '', r.exec) + arg = sub(r'^\S+', ' --', r.exec) if cmd != r.exec else ''
cmd = re.sub(r'\s.*', ' -- ', 1)
start = "start-stop-daemon %s -b %s" % (" ".join(ssdopts), cmd)support/init/install-run line 307
Quoted 3 lines
support/init/install-run new file +3
-0+ + start = "start-stop-daemon %s -b %s%s" % (ssdopts, cmd, arg) + stop = "start-stop-daemon %s" % sskopts
I prefer an explicit /sbin/start-stop-daemon - when manually starting/stopping,
/sbin is not always in the path.
Quoted 4 lines
support/init/install-run new file +4
-0+ + return (start, stop) + +# ------------------------------------------------------------------------------
support/init/install-run line 321
Quoted 10 lines
support/init/install-run new file +10
-0+ +def systemd(r): + writeto("output/target/usr/lib/systemd/system/%s.service" % r.name, 0o644) + r.substcmds() + + if r.after: + after = r.after + elif r.priority and r.priority >= '90': + after = "syslog.service network.service" + elif r.priority and r.priority >= '50':
If that is the meaning of the priorities, perhaps it's better to give them
names rather than numbers.
Quoted 50 lines
support/init/install-run new file +50
-0+ after = "syslog.service" + else: + after = None + + w("[Unit]") + if r.description: + w("Description=%s", r.description) + if after: + w("After=%s", after) + if r.requires: + w("Requires=%s", r.requires) + if r.conflicts: + w("Conflicts=%s", r.conflicts) + wnl() + + w("[Service]") + if r.user: + w("User=%s", r.user) + if r.group: + w("Group=%s", r.group) + if r.pidfile and not r.exec: + w("PIDFile=%s", r.pidfile) + if r.start or r.exec: + for c in r.pre: + w("ExecStartPre=%s", c) + + if r.exec: + w("ExecStart=%s", r.exec) + elif r.start: + w("Type=forking") + w("ExecStart=%s", r.start) + elif r.pre: + w("Type=oneshot") + wl("ExecStart=%s", r.pre) + + if r.stop and not r.exec: + w("ExecStop=%s", r.stop) + + for c in r.post: + w("ExecStartPost=%s", c) + if r.reload: + w("ExecReload=%s", r.reload) + if r.restart: + w("Restart=%s", r.restart) + elif r.exec: + w("Restart=always") + wnl() + + w("[Install]") + if r.wantedby:
support/init/install-run line 381
Quoted 10 lines
support/init/install-run new file +10
-0+ w("WantedBy=%s", r.wantedby) + else: + w("WantedBy=multi-user.target") + +# ------------------------------------------------------------------------------ + +# Usage: +# bypass systemd foo.service +# bypass initscripts foo.init foo.line +# bypass inittab -
This bypass syntax is hard to understand IMHO. Can you find something
simpler/clearer and more verbose? If you would switch to ini format, it could be something like
[initscripts]
cp = package/foo/S10start
/etc/init.d/S10start
[systemd]
cp-ln = package/foo/foo.service
/usr/lib/systemd/system/foo.service /etc/systemd/system/multi-user.target.wants
Quoted 20 lines
support/init/install-run new file +20
-0+ +bypasstable = { + 'initscripts': [ + ('*:*.init', 'output/target/etc/init.d/S$1$2'), + ('*.init', 'output/target/etc/init.d/S50$1'), + ('*.conf', 'output/target/etc/config.d/*'), + ('S*', 'output/target/etc/init.d/*') ], + 'systemd': [ + ('*.service', 'output/target/usr/lib/systemd/system/*.service'), + ('*.tmp.conf', 'output/target/usr/lib/tmpfiles.d/*.conf') ] +} + +def bypass(run, init, arg): + if arg == '-': return + rules = bypasstable[init] + for f in arg.split(): + copied = False + for r in rules: + m = match(r[0].replace('*','(.*)'), basename(f)) + if not m: continue
support/init/install-run line 411
Quoted 10 lines
support/init/install-run new file +10
-0+ copyfile(sub(r'.*:', '', f), + r[1].replace('*', m.group(1)) + .replace('$1', m.group(1)) + .replace('$2', m.group(2))) + copied = True + break + if not copied: + die('no destination for %s', f) + +def copyfile(src, dst):
Use shutil.copyfile instead of inventing your own.
Quoted 52 lines
support/init/install-run new file +46
-0+ f = osopen(src, O_RDONLY) + s = fstat(f) + o = openwrite(dst, s.st_mode) + buf = osread(f, s.st_size) + oswrite(o, buf) + +# ------------------------------------------------------------------------------ + +if len(argv) > 1 and argv[1] == '-': + nopath = True + del argv[1] + +if len(argv) < 2: + die("Usage: install-init [-] init-system file.run file.run ...") + +init = argv[1] + +if not init: + die("Bad call") + +if init in inits: + writer = globals()[init] +else: + die("Unknown init system %s", init) + +subst = [] +files = [] + +for a in argv[2:]: + eq = a.find(':') + if eq >= 0: + subst.append((a[0:eq], a[eq+1:])) + elif a.endswith('.run'): + files.append((basename(a)[:-4], a)) + else: + die("Bad argument: %s", a) + +for f in files: + run = parse(f[0], f[1]) + run.update(subst) + if getattr(run, init): + bypass(run, init, getattr(run, init)) + if r.isempty(): + continue + else: + writer(run)support/init/install-tmpconf new file +0
-0
support/init/install-tmpconf line 7
Quoted 7 lines
support/init/install-tmpconf new file +7
-0@@ -0,0 +1,7 @@ +#!/bin/sh + +test "$1" = 'systemd' && shift || exit +mkdir -p output/target/etc/tmpfiles.d/ +for i in "$@"; do + cp $i output/target/etc/tmpfiles.d/${i/.tmp.conf/.conf} +done
You also didn't give an example of this, but I have the feeling it would make
more sense to put this in the .run script as well. For sysv, the tmpfile should be created in the init script; for systemd, it's done by tmpfiles.
Regards,
Arnout
Quoted 1 line
Signature · 6 lines
Arnout Vandecappelle arnout at mind be Senior Embedded Software Architect +32-16-286500 Essensium/Mind http://www.mind.be G.Geenslaan 9, 3001 Leuven, Belgium BE 872 984 063 RPR Leuven LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle GPG fingerprint: 7CB5 E4CC 6C2E EFD4 6E3D A754 F963 ECAB 2450 2F1F
cover common init infrastructure
In reply to Arnout VandecappelleQuoted 4 lines · Arnout Vandecappelle
- Although we have a dependency on python, we don't currently use python for any of the core functionality (i.e., just building). Personally I like python a lot, but now you already have to know make and shell pretty well in order to touch the buildroot core. Adding python to the mix is making the threshold even higher.
Ah, I see. I decided to go with python specifically to avoid extra dependencies, after looking at the language stats in support/scripts.
Now indeed python scripts there are not build scripts.
Quoted 3 lines
- The generation script looks a bit complicated, while on the other hand the .run files are really terse. I'd prefer a bit more verbosity in the .run files, especially if that can make the generation script a bit simpler.
Makes sense. And it may help to drop python dependency at some point. I need to think on this and maybe try things to see what could work better.
Initially the format was somewhat simplier, with prefixed lines. Definitely easier to parse, but there were some quirks with that approach.
cover common init infrastructure
In reply to Alex SuykovAlex, All,
On 2015-03-21 20:26 +0200, Alex Suykov spake thusly:
Quoted 10 lines
This series is intended to clean up buildroot init system somewhat, removing the need for extensive sysv and systemd handling code in every package that installs init bits, and allowing alternative init systems to be implemented with reasonable amount of effort.
Overview of the changes:
* drop per-package sysv and systemd files, introduce common format used to generate files for both of them, use a script to do the conversion from common format to sysv or systemd.
I have not delve too deep in the implementation (because, Python! ;-) ), but from the examples, it seems it would still be possible to start more than one "daemon" for a service, like is done by samba, right?
Quoted 10 lines
* remove sysv and systemd installation code from package .mk files, let pkg-generic handle it.
* remove sysv-specific files from skeleton, and sysv-specific hacks from
system/system.mk. Use a dedicated script to write inittab, handling global conditionals (root rw/ro, serial getty and so on)* remove user definitions from package .mk files, and mkdirs from per-package sysv initscript, use per-package .users and .files instead in a way similar to .hash files.
How do you handle conditional creation of users/groups? Let's take a supposed package that can install a server and/or a client (like a SQL related package, for example). The server (sqld) needs a specific user+group, but the client (sql-cli) does not. Currently, this is easily done by emclosing the user defintion between a 'if server' block.
Quoted 8 lines
Expected benefits:
* (almost) all packages get both sysv and systemd files at the same time and without the need to support them separately.
* init-related changes can be introduced without patching all 70+ individual packages that install startup files.
Quoted 6 lines
* new init systems can be introduced with only minor effort, including lightweight ones with controlled (foreground) daemons.
This series includes the infrastructure changes, and a couple of package patches to show how it looks like. Complete set of package patches uploaded here: https://github.com/arsv/br/
It would be much nicer if you were to push your branch there, rather than a set of patches. Having a branch would mean we could fetch from it.
Quoted 1 line
This series is for reviewing, not for merging.
One thing that is wrong throughout the series, is that you hard-code the path to "outoput/" and this breaks out-of-tree builds [0]. You should use $(BASE_DIR) instead.
[0] http://buildroot.net/downloads/manual/manual.html#_building_out_of_tree
Also, I think this series is changing a lot of different things at the same time. For example, there is infra changes to handle:
- init script,
- users/groups,
- skeleton /etc/ stuff
This series should be split in simpler sub-series, or at least into much simpler patches. For example, patch 4/11 that adds help entries to init systems could probably sent first (after a bit of rewording to remove references to the new init infra), because it is a valuable addition, and it does not really depend on the new infra.
Otherwise, I have a feeling this is pushing things a bit too far. I'm usually very happy with "abstraction" and I more than once have pushed for such changes. However, in this area, I'm a bit sceptic as to whether we should introduce our own "initscript" format (the '.run' files).
Regards,
Yann E. MORIN.
Signature · 6 lines
.-----------------.--------------------.------------------.--------------------. | Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: | | +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ | | +33 223 225 172 `------------.-------: X AGAINST | \e/ There is no | | http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. | '------------------------------^-------^------------------^--------------------'
RFC 1/11 common service startup files
In reply to Alex SuykovAlex, All,
On 2015-03-21 20:27 +0200, Alex Suykov spake thusly:
Quoted 8 lines
This patch introduces support infrastructure for per-project .run files.
Any .run files in package directory are picked up by pkg-generic code, fed to support/init/install-run script which converts them into either sysv initscripts or systemd unit files and installs those into predefined locations. The package itself provides only the .run files, no code in package .mk file is necessary.
Quoted 4 lines
Packages that install some of their services conditionally may set $(PKG)_INIT = list of run files to install. As a side effect, this removes the need to handle S99foo S99bar vs foo.service bar.service with the package .mk file.
I think this shoule be always set in the .mk, even if not conditional, and that pkg-generic only handles what's been explicitly declared by the package.
Quoted 4 lines
Packages that need to substititue some values within their service files may set $(PKG)_INIT = KEY:value KEY:value ..., which will be handled by install-run. The substitutions will be applied to sysv and systemd files.
What we previously discussed was something like the following (for sysv-init):
/etc/init.d/S??foo <- startup script for package 'foo'
/etc/defaults/foo <- contains default configuration of package
'foo', as installed by Buildroot.
/etc/config/foo <- optional file, contains the user-supplied
override configuration for package 'foo'
Then, the "startup script" would read those files, starting with the one in /etc/defaults/ and then, if present, the one in /etc/config/ . This would allow /etc to be read-only, and /etc/config to be a read-write mountpoint.
Those files would be provided by the packages, like is done for now.
And similarly for systemd, except a lot of packages are now providing systemd unit files, and there is no reason we would provide our own instead, since that would probably bit-rot in the long term, so we probably would prefer to use whatever upstream provides.
So, what we really care about are sysv initscripts, since they are in a very bad shape:
- upstream-provided scripts are too ugly, and often tied to a
particular distro;
- our own scripts are mot very clean either, for some have been around for a looong time.
Quoted 3 lines
In case particular init system needs hand-crafted startup files or cannot handle certain services at all, install-run may be told so using special lines in the .run file.
I'm afraid this would be abused in the long run, becasue .run syntax is too specific to Buildroot.
Quoted 2 lines
This patch does not remove existing BR2_INIT_{SYSV,SYSTEMD} hooks. Each package should either provide .run files or define hooks, but not both.
Right.
Regards,
Yann E. MORIN.
Signature · 6 lines
.-----------------.--------------------.------------------.--------------------. | Yann E. MORIN | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: | | +33 662 376 056 | Software Designer | \ / CAMPAIGN | ___ | | +33 223 225 172 `------------.-------: X AGAINST | \e/ There is no | | http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL | v conspiracy. | '------------------------------^-------^------------------^--------------------'
RFC 1/11 common service startup files
In reply to Arnout VandecappelleSun, Mar 22, 2015 at 12:57:50AM +0100, Arnout Vandecappelle wrote:
Thanks for extensive review, a lot of good points which I skip in this reply because they should go directly into the code.
Quoted 1 line
Missing SoB, but perhaps that's intentional because it's not ready for inclusion?
Well, partially, and partially I just forgot -s when re-splitting commits.
Quoted 7 lines
Quoted 3 lines
files may set $(PKG)_INIT = KEY:value KEY:value ..., which will be handled by install-run. The substitutions will be applied to sysv and systemd files.
I don't see why this is needed, and it probably makes the install-run script
more complicated.
BR2_PACKAGE_GPSD_DEVICES, and keeping it a variable in the resulting initscript. Or maybe in /etc/default.
If sed substitutiions are ok, this can be done much simplier of course:
sed s!DEVICES!/dev/ttyS1! package/gpsd/gpsd.run > build/gpsd-.../gpsd.run support/init/install-run build/gpsd-.../gpsd.run
Quoted 2 lines
BTW, shouldn't tmpdirs be handled for sysv as well? Typically, the init script will create the tmpdir...
I saw this as systemd-specific.
Looking at the packages, yes, makes sense to have some kind of generic tmpdir variable.
Quoted 3 lines
- The script should only handle cases that are actually used. So start with
something extremely simple that covers a few interesting cases, and leave the others to use the old initscripts system.
Why I was trying handle as many packages as possible: I'm pretty sure something like 80% of them will work immediately with only the basic support, but it would be really bad to find a show-stopper among the remaining 20%. Something that would require changing the way the whole thing works.
Perhaps it's ok to drop bad cases for now, leave them as initscripts-only and expect the users do something about the unsupported cases themselves.
Quoted 3 lines
- Use existing infrastructure where possible. For instance, you could change
the .run format into .ini format and use configparser, or you could use the shlex module for parsing.
Regarding ini files, I was thinking about using a kind of extended/simplified .service format. Systemd being systemd, it would cover all cases, and it's got some documentation already.
The problem is that there are pretty long shell scripts that do not fit well within .ini files. Examples: sunxi-mali, ti-gfx, am33-cm3 and maybe some others. That's why I tried to keep .run files looking somewhat like shell scripts.
Well, that and I don't like systemd documentation all that much.
Quoted 4 lines
This bypass syntax is hard to understand IMHO. Can you find something simpler/clearer and more verbose? If you would switch to ini format, it could be something like
Quoted 8 lines
[initscripts]
cp = package/foo/S10start/etc/init.d/S10start[systemd]
cp-ln = package/foo/foo.service
/usr/lib/systemd/system/foo.service/etc/systemd/system/multi-user.target.wants
The primary goal of the whole changeset is to separate package-specific and init-system-specific things, moving the latter out of packages, so that a change in systemd directory layout (for instance) would not require patching all the packages.
This is why I try to specify startup ordering (priority 10 or multi-user.target in this case) indirectly, and why I try to avoid explicit paths.
I see this as a part of init config format, not a part of service configuration.
The package does not need to know where to put those and how to name them. All it needs is to have its process started, at some point.
cover common init infrastructure
In reply to Yann E. MORINQuoted 5 lines · Yann E. MORIN
How do you handle conditional creation of users/groups? Let's take a supposed package that can install a server and/or a client (like a SQL related package, for example). The server (sqld) needs a specific user+group, but the client (sql-cli) does not. Currently, this is easily done by emclosing the user defintion between a 'if server' block.
I think it makes sense to install users unconditionally.
Mostly because not installing them is a minor optimization of the resulting rootfs image and I see no good way to handle it.
If necessary, perhaps listing .users to be included in the project .mk file may be an option, the same way it is done with .run files.
Quoted 4 lines
Otherwise, I have a feeling this is pushing things a bit too far. I'm usually very happy with "abstraction" and I more than once have pushed for such changes. However, in this area, I'm a bit sceptic as to whether we should introduce our own "initscript" format (the '.run' files).
That's a valid point, but I think buildroot already uses its own initscript format, namely its sysv(-style) initscripts.
They are supplied with buildroot, they are non-standard, and they are nearly useless outside of buildroot.
So I see it a choice between different formats for buildroot-specific service description, and the one currently in use does not look like a good data storage format at all.
cover common init infrastructure
Quoted 1 line · Alex Suykov
Sun, Mar 22, 2015 at 12:28:07PM +0100, Yann E. MORIN wrote:
[snip]
Quoted 7 lines
Quoted 4 lines
Otherwise, I have a feeling this is pushing things a bit too far. I'm usually very happy with "abstraction" and I more than once have pushed for such changes. However, in this area, I'm a bit sceptic as to whether we should introduce our own "initscript" format (the '.run' files).
That's a valid point, but I think buildroot already uses its own initscript format, namely its sysv(-style) initscripts.
Quoted 6 lines
They are supplied with buildroot, they are non-standard, and they are nearly useless outside of buildroot.
So I see it a choice between different formats for buildroot-specific service description, and the one currently in use does not look like a good data storage format at all.
The point is that the shell scripts provided by buildroot are just shell, so
"anyone" can understand and modify them. While the .run format is something new that nobody knows, and even if it is documented it will be non-trivial to find the documentation.
That's also why I say that the .run format should be verbose, to make it easy
to read and modify.
Regards,
Arnout
Signature · 6 lines
Arnout Vandecappelle arnout at mind be Senior Embedded Software Architect +32-16-286500 Essensium/Mind http://www.mind.be G.Geenslaan 9, 3001 Leuven, Belgium BE 872 984 063 RPR Leuven LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle GPG fingerprint: 7CB5 E4CC 6C2E EFD4 6E3D A754 F963 ECAB 2450 2F1F
RFC 1/11 common service startup files
In reply to Yann E. MORINQuoted 11 lines · Yann E. MORIN
Alex, All,
On 2015-03-21 20:27 +0200, Alex Suykov spake thusly:
Quoted 8 lines
This patch introduces support infrastructure for per-project .run files.
Any .run files in package directory are picked up by pkg-generic code, fed to support/init/install-run script which converts them into either sysv initscripts or systemd unit files and installs those into predefined locations. The package itself provides only the .run files, no code in package .mk file is necessary.
Quoted 8 lines
Quoted 4 lines
Packages that install some of their services conditionally may set $(PKG)_INIT = list of run files to install. As a side effect, this removes the need to handle S99foo S99bar vs foo.service bar.service with the package .mk file.
I think this shoule be always set in the .mk, even if not conditional, and that pkg-generic only handles what's been explicitly declared by the package.
Well, that's not how we do it for .hash and .patch...
I would rather remove the option of setting _INIT from the package.mk file, if
the goal is to simplify things.
Quoted 7 lines
Quoted 4 lines
Packages that need to substititue some values within their service files may set $(PKG)_INIT = KEY:value KEY:value ..., which will be handled by install-run. The substitutions will be applied to sysv and systemd files.
What we previously discussed was something like the following (for sysv-init):
We discussed it but I didn't agree :-)
I want to keep things simple, and any customisation should go through fs-overlay.
Quoted 6 lines
/etc/init.d/S??foo <- startup script for package 'foo'
/etc/defaults/foo<- contains default configuration of package
'foo', as installed by Buildroot.
Quoted 7 lines
/etc/config/foo<- optional file, contains the user-supplied
override configuration for package 'foo'Then, the "startup script" would read those files, starting with the one in
/etc/defaults/and then, if present, the one in/etc/config/. This would allow /etc to be read-only, and/etc/configto be a read-write mountpoint.
Sounds nice, but you'd still need something like uci to manage /etc/config, and
then it probably wouldn't even work with uci...
Quoted 7 lines
Those files would be provided by the packages, like is done for now.
And similarly for systemd, except a lot of packages are now providing systemd unit files, and there is no reason we would provide our own instead, since that would probably bit-rot in the long term, so we probably would prefer to use whatever upstream provides.
I totally agree with this: if a package provides a systemd unit file, it should
be used and we shouldn't touch it.
However, I believe that a package will normally just install the unit file and
not add the symlink to actually start it, so that's something we still have to take care of.
Quoted 7 lines
So, what we really care about are sysv initscripts, since they are in a very bad shape:
- upstream-provided scripts are too ugly, and often tied to aparticular distro;- our own scripts are mot very clean either, for some have been around for a looong time.
Agreed.
Quoted 7 lines
Quoted 4 lines
In case particular init system needs hand-crafted startup files or cannot handle certain services at all, install-run may be told so using special lines in the .run file.
I'm afraid this would be abused in the long run, becasue .run syntax is too specific to Buildroot.
I'm not sure what you mean with abuse. For downstream packages, we don't really
care if they're using custom scripts or .run, and for patches to buildroot we'll make sure that they use .run if possible.
Regards,
Arnout
Quoted 9 lines
Quoted 3 lines
This patch does not remove existing BR2_INIT_{SYSV,SYSTEMD} hooks. Each package should either provide .run files or define hooks, but not both.
Right.
Regards,
Yann E. MORIN.
Signature · 6 lines
Arnout Vandecappelle arnout at mind be Senior Embedded Software Architect +32-16-286500 Essensium/Mind http://www.mind.be G.Geenslaan 9, 3001 Leuven, Belgium BE 872 984 063 RPR Leuven LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle GPG fingerprint: 7CB5 E4CC 6C2E EFD4 6E3D A754 F963 ECAB 2450 2F1F
RFC 1/11 common service startup files
In reply to Alex SuykovQuoted 10 lines · Alex Suykov
Quoted 3 lines
Quoted 3 lines
- The script should only handle cases that are actually used. So start with
something extremely simple that covers a few interesting cases, and leave the others to use the old initscripts system.Why I was trying handle as many packages as possible: I'm pretty sure something like 80% of them will work immediately with only the basic support, but it would be really bad to find a show-stopper among the remaining 20%. Something that would require changing the way the whole thing works.
Perhaps it's ok to drop bad cases for now, leave them as initscripts-only and expect the users do something about the unsupported cases themselves.
I think it's important that there is always a fallback with custom stuff. And
for me, it's perfectly OK if the infrastructure handles only 50% of the cases and the other 50% have to be custom.
Regards,
Arnout
Signature · 6 lines
Arnout Vandecappelle arnout at mind be Senior Embedded Software Architect +32-16-286500 Essensium/Mind http://www.mind.be G.Geenslaan 9, 3001 Leuven, Belgium BE 872 984 063 RPR Leuven LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle GPG fingerprint: 7CB5 E4CC 6C2E EFD4 6E3D A754 F963 ECAB 2450 2F1F
RFC 1/11 common service startup files
In reply to Alex SuykovQuoted 3 lines · Alex Suykov
The problem is that there are pretty long shell scripts that do not fit well within .ini files. Examples: sunxi-mali, ti-gfx, am33-cm3 and maybe some others. That's why I tried to keep .run files looking somewhat like shell scripts.
Why would it not fit in an ini file? You just have to add some indentation:
startscript =
echo 1 > /sys/devices/...
bla bla bla
and we're done
Regards,
Arnout
Signature · 6 lines
Arnout Vandecappelle arnout at mind be Senior Embedded Software Architect +32-16-286500 Essensium/Mind http://www.mind.be G.Geenslaan 9, 3001 Leuven, Belgium BE 872 984 063 RPR Leuven LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle GPG fingerprint: 7CB5 E4CC 6C2E EFD4 6E3D A754 F963 ECAB 2450 2F1F
RFC 2/11 per-package .users and .files lists
In reply to Alex SuykovQuoted 4 lines · Alex Suykov
This change does not simplify things much at present, but it removes inter-package dependency via make variables. Without this patch, reading all enabled package/*/*.mk files from a single
Makefilewas necessary to build user and permission lists.
But we're not planning to change that... Running a separate make per package
sounds like a terribly bad idea...
Quoted 2 lines
With this patch, the data is stored outside of make, possibly allowing one make invocation per package .mk file in the future.
So, is there any reason left to move USERS and PERMS to a file?
It has one big disadvantage: it spreads out the package logic over different
files. We currently only have a separate file for the hashes, and that was probably a bad idea to begin with (as witnessed by the many version bumps that forget to update the hash file).
Regards,
Arnout
Signature · 6 lines
Arnout Vandecappelle arnout at mind be Senior Embedded Software Architect +32-16-286500 Essensium/Mind http://www.mind.be G.Geenslaan 9, 3001 Leuven, Belgium BE 872 984 063 RPR Leuven LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle GPG fingerprint: 7CB5 E4CC 6C2E EFD4 6E3D A754 F963 ECAB 2450 2F1F
RFC 2/11 per-package .users and .files lists
Quoted 4 lines · Arnout Vandecappelle
Quoted 2 lines
With this patch, the data is stored outside of make, possibly allowing one make invocation per package .mk file in the future.
So, is there any reason left to move USERS and PERMS to a file?
No, none at present, so I'm dropping this idea completely.
Quoted 4 lines
It has one big disadvantage: it spreads out the package logic over different files. We currently only have a separate file for the hashes, and that was probably a bad idea to begin with (as witnessed by the many version bumps that forget to update the hash file).
Ok, that was for the large part to match current .hash handling. I wonder if it makes sense to move hashes into .mk files then, Arch-style.