| Both sides previous revision Previous revision Next revision | Previous revision |
| docs:techref:initscripts [2019/04/11 11:24] – Warn of the mess around default_postinst(), and initscripts being run while building ROM images in the host system hmh | docs:techref:initscripts [2020/12/23 07:03] (current) – detly |
|---|
| |
| ====== Init Scripts ====== | ====== Init Scripts ====== |
| [[wp>Init]] scripts configure the [[wp>Daemon_(computing)|daemons]] of the Linux system. Init scripts are run to start required processes as part of the [[docs:techref:process.boot|boot process]]. In OpenWrt init is implemented with init.d. The init process that calls the scripts at boot time is provided by [[docs:techref:process.boot#busybox.init|Busybox]]. This article explains how init.d scripts work and how to create them. Note that this is mostly equivalent to other init.d implementations and in-depth documentation can be found elsewhere. | [[wp>Init]] scripts configure the [[wp>Daemon_(computing)|daemons]] of the Linux system. Init scripts are run to start required processes as part of the [[docs:techref:process.boot|boot process]]. In OpenWrt init is implemented with init.d. The init process that calls the scripts at boot time is provided by [[docs:techref:process.boot#busybox_init|Busybox]]. This article explains how init.d scripts work and how to create them. Note that this is mostly equivalent to other init.d implementations and in-depth documentation can be found elsewhere. You could also take a look at the set of [[commit>?p=openwrt/openwrt.git;a=blob;f=package/base-files/files/etc/rc.common;hb=HEAD|shell functions in /etc/rc.common]] to see how the building blocks of the init scripts are implemented. |
| | |
| ===== Example Init Script ===== | ===== Example Init Script ===== |
| Init scripts are explained best by example. Suppose we have a daemon we want to handle by init.d. We create a file ''/etc/init.d/example'', which as a bare minimum looks as follows: | Init scripts are explained best by example. Suppose we have a daemon we want to handle by init.d. We create a file ''/etc/init.d/example'', which as a bare minimum looks as follows: |
| This init script is just a shell script. The first line is a [[wp>Shebang_(Unix)|shebang line]] that uses ''[[docs:guide-user:base-system:notuci.config#etcrc.common|/etc/rc.common]]'' as a wrapper to provide its main and default functionality and to check the script prior to execution. | This init script is just a shell script. The first line is a [[wp>Shebang_(Unix)|shebang line]] that uses ''[[docs:guide-user:base-system:notuci.config#etcrc.common|/etc/rc.common]]'' as a wrapper to provide its main and default functionality and to check the script prior to execution. |
| |
| :!: Look inside ''rc.common'' to understand its functionality. | :!: Look inside ''[[commit>?p=openwrt/openwrt.git;a=blob;f=package/base-files/files/etc/rc.common;hb=HEAD|rc.common]]'' to understand its functionality. |
| |
| By this ''rc.common'' template, the available commands for an init scripts are as follows: | By this ''rc.common'' template, the available commands for an init scripts are as follows: |
| * **stop()** - these commands will be run when it is called with 'stop' as its parameter. | * **stop()** - these commands will be run when it is called with 'stop' as its parameter. |
| |
| The ''START='' and ''STOP='' lines determine at which point in the [[docs:techref:process.boot#init|init sequence]] this script gets executed. At boot time ''init.d'' just starts executing scripts it finds in ''/etc/rc.d'' according to their file names. The init scripts can be placed here as symbolic links to the ''init.d'' scripts in ''/etc/init.d/''. Using [[#enable.and.disable|the enable and disable commands]] this is done automatically. In this case: | The ''START='' and ''STOP='' lines determine at which point in the [[docs:techref:process.boot#init|init sequence]] this script gets executed. At boot time ''init.d'' just starts executing scripts it finds in ''/etc/rc.d'' according to their file names. The init scripts can be placed here as symbolic links to the ''init.d'' scripts in ''/etc/init.d/''. Using [[#enable_and_disable|the enable and disable commands]] this is done automatically. In this case: |
| * ''**START=10**'' - this means the file will be symlinked as /etc/rc.d/S10example - in other words, it will start after the init scripts with START=9 and below, but before START=11 and above. | * ''**START=10**'' - this means the file will be symlinked as /etc/rc.d/S10example - in other words, it will start after the init scripts with START=9 and below, but before START=11 and above. |
| * ''**STOP=15**'' - this means the file will be symlinked as /etc/rc.d/K15example - this means it will be stopped after the init scripts with STOP=14 and below, but before STOP=16 and above. This is optional. | * ''**STOP=15**'' - this means the file will be symlinked as /etc/rc.d/K15example - this means it will be stopped after the init scripts with STOP=14 and below, but before STOP=16 and above. This is optional. |
| :!: START and STOP values should fall in the range 1-99 as they are run alphabetically meaning 100 would execute after 10. | :!: START and STOP values should fall in the range 1-99 as they are run alphabetically meaning 100 would execute after 10. |
| |
| :!: OpenWRT will run the initscript **in the host system during build** (currently using actions "enable" or "disable"), and it must correctly deal with that special case without undue side-effects. Refer to the "enable and disable" section below for more on this pitfall. | :!: OpenWrt will run the initscript **in the host system during build** (currently using actions "enable" or "disable"), and it must correctly deal with that special case without undue side-effects. Refer to the "enable and disable" section below for more on this pitfall. |
| |
| If you add a section like the one below: | ==== Other functions ==== |
| | |
| | The ''rc.common'' script defines other functions that you can override if you need to, eg: |
| | |
| | * ''boot()'' - called once each time the system starts up. By default this function calls ''start $@'', so if your service has a "one-off" component (eg. turn on some hardware) and an ongoing component (eg. use the hardware), you will almost certainly want to call ''start "$@"'' at the end of your own ''boot()'' function too. If there is no ongoing component, you can leave it out. |
| | * ''shutdown()'' - called once each time the system is shut down (whether for reboot or poweroff). Like the ''boot()'' function, this function calls ''stop'' by default (note no arguments), so if your service has an ongoing component like above, and a one-off shutdown command (eg. turn off some hardware), you will want to call ''stop'' first, and then your one-off command. |
| | |
| | These functions can be called by procd init scripts too. |
| | |
| | For example: |
| |
| ^ Code ^ | ^ Code ^ |
| |<code bash>boot() { | |<code> |
| echo boot | boot() { |
| # commands to run on boot | echo "Turning on extra comms device" |
| }</code>| | # This is a made up command to illustrate the point |
| | comms2_power --on |
| | start "$@" |
| | } |
| | |
| | start() { |
| | # Service that uses the device we turned on in boot() |
| | my_service |
| | } |
| | |
| | shutdown() { |
| | # The service is finished, so turn off the hardware |
| | stop |
| | echo "Turning off extra comms device" |
| | comms2_power --off |
| | } |
| | </code>| |
| |
| In that case these commands will be run on boot, instead of those in the ''start()'' section, which is normally run at boot when '' boot()'' is not defined. This is handy for things that need to be done on boot, but not every time the program it calls has to restart. | ==== Custom commands ==== |
| |
| You can add your own custom commands by using the EXTRA_COMMANDS variable, and provide help for those commands with the EXTRA_HELP variable, then adding sections for each of your custom commands: | You can add your own custom commands by using the EXTRA_COMMANDS variable, and provide help for those commands with the EXTRA_HELP variable, then adding sections for each of your custom commands: |
| ===== Enable and disable ===== | ===== Enable and disable ===== |
| |
| In order to automatically start the init script on boot, it must be installed into /etc/rc.d/ (see above). On recent versions of OpenWRT, the build system will attempt to "enable" and/or "disable" initscripts during package install and removal by itself (refer to default_postinst() and default_prerm() in /lib/functions.sh from package base-files -- this thing is utterly undocumented, including how to AVOID the automatic behavior where unwanted), and it will "enable" the initscripts on packages *included* in the ROM images during build, see below. | In order to automatically start the init script on boot, it must be installed into /etc/rc.d/ (see above). On recent versions of OpenWrt, the build system will attempt to "enable" and/or "disable" initscripts during package install and removal by itself (refer to default_postinst() and default_prerm() in /lib/functions.sh from package base-files -- this thing is utterly undocumented, including how to AVOID the automatic behavior where unwanted), and it will "enable" the initscripts on packages *included* in the ROM images during build, see below. |
| |
| :!: WARNING :!: OpenWRT initscripts **will be run** while building OpenWRT images (when installing packages in what will become a ROM image) in the **host system** (right now, for actions "//enable//" and "//disable//"). **They must not fail, or have undesired side-effects in that situation.** When being run by the build system, environment variable **${IPKG_INSTROOT}** will be set to the working directory being used. On the "target system", that environment variable will be empty/unset. Refer to "/lib/functions.sh" and also to "/etc/rc.common" in package "base-files" for the nasty details. | :!: WARNING :!: OpenWrt initscripts **will be run** while building OpenWrt images (when installing packages in what will become a ROM image) in the **host system** (right now, for actions "//enable//" and "//disable//"). **They must not fail, or have undesired side-effects in that situation.** When being run by the build system, environment variable **${IPKG_INSTROOT}** will be set to the working directory being used. On the "target system", that environment variable will be empty/unset. Refer to "/lib/functions.sh" and also to "/etc/rc.common" in package "base-files" for the nasty details. |
| |
| Invoke the "enable" command to run the initscript on boot: | Invoke the "enable" command to run the initscript on boot: |