Difference between revisions of "Handbook:Parts/Working/Initscripts"
Winterheart (talk | contribs) (Marked this version for translation) |
(Add improvements from Flexibeast (grammar, improved wording)) |
||
Line 14: | Line 14: | ||
<!--T:6--> | <!--T:6--> | ||
− | First, the boot loader will load the kernel image that is defined in the boot loader configuration. Then, the boot loader instructs the CPU to execute kernel. When the kernel is loaded and run, it initializes all kernel-specific structures and tasks and starts the init process. | + | First, the boot loader will load the kernel image that is defined in the boot loader configuration. Then, the boot loader instructs the CPU to execute the kernel. When the kernel is loaded and run, it initializes all kernel-specific structures and tasks and starts the init process. |
<!--T:7--> | <!--T:7--> | ||
− | + | The init process makes sure that all filesystems (defined in {{Path|/etc/fstab}}) are mounted and ready to be used. Then it executes several scripts located in {{Path|/etc/init.d/}}, which will start the services needed in order to have a successfully booted system. | |
<!--T:8--> | <!--T:8--> | ||
− | Finally, | + | Finally, once all scripts have been executed, init activates the virtual consoles accessible via {{Key|Ctrl}}+{{Key|Alt}}+ {{Key|F1}}, {{Key|Ctrl}}+{{Key|Alt}} + {{Key|F2}}, etc.), attaching to each one a special process called {{c|agetty}}. This process ensures users are able to log on via {{c|login}}. |
=== {{Anchor|Initscripts}} Initscripts === <!--T:9--> | === {{Anchor|Initscripts}} Initscripts === <!--T:9--> | ||
<!--T:10--> | <!--T:10--> | ||
− | + | The scripts in {{Path|/etc/init.d/}} aren't executed randomly. init doesn't run all scripts in {{Path|/etc/init.d/}}, only the scripts it is told to execute, via {{Path|/etc/runlevels/}}. | |
<!--T:11--> | <!--T:11--> | ||
Line 31: | Line 31: | ||
<!--T:12--> | <!--T:12--> | ||
− | + | Once all scripts referenced in {{Path|/etc/runlevels/boot/}} have been executed, init will run the scripts linked in {{Path|/etc/runlevels/default/}}. Again, it will use the alphabetical order to decide what script to run first, unless a script has dependency information in it, in which case the order is changed to provide a valid start-up sequence. This is why commands used during the installation of Gentoo Linux use the <code>default</code> runlevel (e.g. <code>rc-update add sshd default</code>). | |
=== {{Anchor|How init works}} How init works === <!--T:13--> | === {{Anchor|How init works}} How init works === <!--T:13--> | ||
<!--T:14--> | <!--T:14--> | ||
− | Of course init doesn't decide all that by itself. It needs a configuration file that specifies what actions need to be taken. | + | Of course init doesn't decide all that by itself. It needs a configuration file that specifies what actions need to be taken. The {{Path|/etc/inittab}} file is used by init to determine the actions it needs to take. |
<!--T:15--> | <!--T:15--> | ||
− | + | As described above, init's first action is to mount all file systems. This is defined in the following line from {{Path|/etc/inittab}}: | |
<!--T:16--> | <!--T:16--> | ||
Line 83: | Line 83: | ||
<!--T:25--> | <!--T:25--> | ||
− | The line that defines level 3, again | + | The line that defines level 3, again uses the {{c|openrc}} script to start the services (now with argument <code>default</code>). Also note again that the argument to {{c|openrc}} is the same as the subdirectory from {{Path|/etc/runlevels/}}. |
<!--T:26--> | <!--T:26--> | ||
Line 104: | Line 104: | ||
<!--T:30--> | <!--T:30--> | ||
− | In Gentoo, there are seven runlevels defined: three internal runlevels, and four user-defined runlevels. The internal runlevels are called ''sysinit'', ''shutdown'' and ''reboot'' and do exactly what their names imply: | + | In Gentoo, there are seven runlevels defined: three internal runlevels, and four user-defined runlevels. The internal runlevels are called ''sysinit'', ''shutdown'' and ''reboot'' and do exactly what their names imply: initializing the system, powering off the system, and rebooting the system. |
<!--T:31--> | <!--T:31--> | ||
− | The user-defined runlevels are those with an accompanying {{Path|/etc/runlevels/}} subdirectory: ''boot'', ''default'', ''nonetwork'' and ''single''. The boot runlevel starts all system-necessary services | + | The user-defined runlevels are those with an accompanying {{Path|/etc/runlevels/}} subdirectory: ''boot'', ''default'', ''nonetwork'' and ''single''. The ''boot'' runlevel starts all system-necessary services used by all the other runlevels. The remaining three runlevels differ in what services they start: ''default'' is used for day-to-day operations, ''nonetwork'' is used in case no network connectivity is required, and ''single'' is used when the system needs to be fixed. |
=== {{Anchor|Working with initscripts}} Working with initscripts === <!--T:32--> | === {{Anchor|Working with initscripts}} Working with initscripts === <!--T:32--> | ||
<!--T:33--> | <!--T:33--> | ||
− | The scripts that the openrc process starts are called init scripts. Each script in {{Path|/etc/init.d/}} can be executed with the arguments <code>start</code>, <code>stop</code>, <code>restart</code>, <code>zap</code>, <code>status</code>, <code>ineed</code>, <code>iuse</code>, <code>iwant</code>, <code>needsme</code>, <code>usesme</code>, or <code>wantsme</code>. | + | The scripts that the {{c|openrc}} process starts are called ''init scripts''. Each script in {{Path|/etc/init.d/}} can be executed with the arguments <code>start</code>, <code>stop</code>, <code>restart</code>, <code>zap</code>, <code>status</code>, <code>ineed</code>, <code>iuse</code>, <code>iwant</code>, <code>needsme</code>, <code>usesme</code>, or <code>wantsme</code>. |
<!--T:34--> | <!--T:34--> | ||
− | To start, stop, or restart a service (and all | + | To start, stop, or restart a service (and all dependent services), the <code>start</code>, <code>stop</code>, and <code>restart</code> arguments should be used: |
<!--T:35--> | <!--T:35--> | ||
Line 121: | Line 121: | ||
<!--T:36--> | <!--T:36--> | ||
− | {{Note|Only the services that need the given service are stopped or restarted. The other | + | {{Note|Only the services that need the given service are stopped or restarted. The other dependent services (those that use the service but don't need it) are left untouched.}} |
<!--T:37--> | <!--T:37--> | ||
Line 130: | Line 130: | ||
<!--T:39--> | <!--T:39--> | ||
− | To | + | To get the status of a service (started, stopped, ...), use the status argument: |
<!--T:40--> | <!--T:40--> | ||
Line 142: | Line 142: | ||
<!--T:43--> | <!--T:43--> | ||
− | To also ask what dependencies the service has, use <code>iwant</code>, <code>iuse</code> or <code>ineed</code>. With <code>ineed</code> it is possible to see the services that are really necessary for the correct functioning of the service. <code>iwant</code> or <code>iuse</code>, on the other hand, shows the services that can be used by the service, but are not necessary for the correct functioning. | + | To also ask what dependencies the service has, use <code>iwant</code>, <code>iuse</code> or <code>ineed</code>. With <code>ineed</code> it is possible to see the services that are really necessary for the correct functioning of the service. <code>iwant</code> or <code>iuse</code>, on the other hand, shows the services that can be used by the service, but are not necessary for the correct functioning of the service. |
<!--T:44--> | <!--T:44--> | ||
Line 158: | Line 158: | ||
<!--T:51--> | <!--T:51--> | ||
− | Gentoo's init system uses a dependency | + | Gentoo's init system uses a dependency tree to decide what service needs to be started first. As this is a tedious task that we wouldn't want our users to have to do manually, we have created tools that ease the administration of the runlevels and init scripts. |
<!--T:52--> | <!--T:52--> | ||
Line 166: | Line 166: | ||
<!--T:54--> | <!--T:54--> | ||
− | In earlier instructions, init scripts have already been added to the | + | In earlier instructions, init scripts have already been added to the ''default'' runlevel. What ''default'' means has been explained earlier in this document. Next to the runlevel, the {{c|rc-update}} script requires a second argument that defines the action: <code>add</code>, <code>del</code>, or <code>show</code>. |
<!--T:55--> | <!--T:55--> | ||
− | + | In addition to the runlevel, the {{c|rc-update}} script requires a second argument specifying the appropriate action: <code>add</code>, <code>del</code>, or <code>show</code>. For instance: | |
<!--T:56--> | <!--T:56--> | ||
Line 175: | Line 175: | ||
<!--T:57--> | <!--T:57--> | ||
− | The {{c|rc-update -v show}} command will show all the available init scripts and | + | The {{c|rc-update -v show}} command will show all the available init scripts and the runlevels in which they will execute: |
<!--T:58--> | <!--T:58--> | ||
Line 188: | Line 188: | ||
<!--T:62--> | <!--T:62--> | ||
− | Init scripts can be quite complex. It is therefore not | + | Init scripts can be quite complex. It is therefore not desirable to have users edit init scripts directly, as it would make them more error-prone. However, it's important to be able configure services: for instance, users might want to run the service with additional options. |
<!--T:63--> | <!--T:63--> | ||
Line 217: | Line 217: | ||
<!--T:71--> | <!--T:71--> | ||
− | Do not use the init script provided by the service if it isn't explicitly written for Gentoo: Gentoo's init scripts are not compatible with the init scripts used by other distributions | + | Do not use the init script provided by the service if it isn't explicitly written for Gentoo: Gentoo's init scripts are not compatible with the init scripts used by other distributions, unless the other distribution is using OpenRC. |
=== {{Anchor|Layout}} Layout === <!--T:72--> | === {{Anchor|Layout}} Layout === <!--T:72--> | ||
Line 283: | Line 283: | ||
<!--T:77--> | <!--T:77--> | ||
− | There are three dependency- | + | There are three dependency-related settings which can influence the start-up or sequencing of init scripts:: <code>want</code>, <code>use</code> and <code>need</code>. Next to these, there are also two order-influencing methods called <code>before</code> and <code>after</code>. These last two are not dependencies ''per se'' - they don't make the init script fail if the specified dependency isn't scheduled to start (or fails to start). |
<!--T:78--> | <!--T:78--> | ||
− | * The <code>use</code> | + | * The <code>use</code> setting informs the init system that the script uses functionality offered by the selected script, but does not directly depend on it. Some examples are <code>use logger</code> and <code>use dns</code>: if the services are available, they will be used, but if the system does not have a logger or DNS server, the services will still work. If the services exist, then they are started before the script that uses them. |
− | * The <code>want</code> setting is similar to <code>use</code> with one exception. | + | * The <code>want</code> setting is similar to <code>use</code> with one exception. <code>use</code> only considers services which were added to a runlevel; <code>want</code> will try to start any available service even if not added to any runlevel. <code>want</code> will try to start any available service even if not added to an init level. |
− | * The <code>need</code> setting | + | * The <code>need</code> setting indicates a hard dependency: a script that <code>need</code>s another script will not start before the latter script is started successfully. Also, if the <code>need</code>ed script is restarted, the script needing it will be restarted as well. |
− | * | + | * The <code>before</code> setting ensures the script is launched before a specified script, if the latter is part of the runlevel. So an init script {{c|xdm}} that defines <code>before alsasound</code> will start before the {{c|alsasound}} script, but only if {{c|alsasound}} is scheduled to start in the same runlevel. If {{c|alsasound}} is not scheduled to start in that runlevel, then the <code>before</code> has no effect, and {{c|xdm}} will be started when the init system deems it most appropriate. |
− | * Similarly, <code>after</code> informs the init system that the given script should be launched after | + | * Similarly, <code>after</code> informs the init system that the given script should be launched after a specified script if the latter is part of the same runlevel. If not, then the setting has no effect and the script will be launched by the init system when it deems it most appropriate. |
<!--T:79--> | <!--T:79--> | ||
− | It should be clear from the above that <code>need</code> is the only "true" dependency setting as it affects | + | It should be clear from the above that <code>need</code> is the only "true" dependency setting, as it affects whether the script will be started or not. All the others merely tell the init system the order in which scripts can be (or should be) started. |
+ | |||
+ | ==== Virtual dependencies ==== | ||
<!--T:80--> | <!--T:80--> | ||
− | + | Many of Gentoo's init scripts depend on things that are themselves not init scripts: virtual dependencies. | |
<!--T:81--> | <!--T:81--> | ||
Line 302: | Line 304: | ||
<!--T:82--> | <!--T:82--> | ||
− | For instance, | + | For instance, consider the dependency information in the {{c|postfix}} script: |
<!--T:83--> | <!--T:83--> | ||
Line 314: | Line 316: | ||
<!--T:84--> | <!--T:84--> | ||
− | As can be seen, the postfix service: | + | As can be seen, the {{c|postfix}} service: |
<!--T:132--> | <!--T:132--> | ||
− | * Requires the (virtual) net dependency (which is provided by, for instance, {{Path|/etc/init.d/net.eth0}}). | + | * Requires the (virtual) <code>net</code> dependency (which is provided by, for instance, {{Path|/etc/init.d/net.eth0}}). |
− | * Uses the (virtual) logger dependency (which is provided by, for instance, {{Path|/etc/init.d/syslog-ng}}). | + | * Uses the (virtual) <code>logger</code> dependency (which is provided by, for instance, {{Path|/etc/init.d/syslog-ng}}). |
− | * Uses the (virtual) dns dependency (which is provided by, for instance, {{Path|/etc/init.d/named}}). | + | * Uses the (virtual) <code>dns</code> dependency (which is provided by, for instance, {{Path|/etc/init.d/named}}). |
− | * Provides the (virtual) mta dependency (which is common for all mail servers). | + | * Provides the (virtual) <code>mta</code> dependency (which is common for all mail servers). |
=== {{Anchor|Controlling the order}} Controlling the order === <!--T:85--> | === {{Anchor|Controlling the order}} Controlling the order === <!--T:85--> | ||
<!--T:86--> | <!--T:86--> | ||
− | As described in the previous section, it is possible to tell the init system what order it should use for starting (or stopping) scripts. This ordering is handled both through the dependency settings use and need, but also through the order settings before and after. As we have described these earlier already, let's take a look at the portmap service as an example of such init script. | + | As described in the previous section, it is possible to tell the init system what order it should use for starting (or stopping) scripts. This ordering is handled both through the dependency settings <code>use</code> and <code>need</code>, but also through the order settings <code>before</code> and <code>after</code>. As we have described these earlier already, let's take a look at the {{c|portmap}} service as an example of such init script. |
<!--T:87--> | <!--T:87--> | ||
Line 337: | Line 339: | ||
<!--T:88--> | <!--T:88--> | ||
− | It | + | It's possible to use the <code>*</code> glob to refer to all services in the same runlevel, although this isn't advisable. |
<!--T:89--> | <!--T:89--> | ||
Line 347: | Line 349: | ||
<!--T:90--> | <!--T:90--> | ||
− | If the service must write to local disks, it should need localmount. If it places anything in {{Path|/var/run/}} such as a PID file, then it should start after bootmisc: | + | If the service must write to local disks, it should <code>need localmount</code>. If it places anything in {{Path|/var/run/}}, such as a PID file, then it should start <code>after bootmisc</code>: |
<!--T:91--> | <!--T:91--> | ||
Line 360: | Line 362: | ||
<!--T:93--> | <!--T:93--> | ||
− | + | In addition to the <code>depend()</code> functionality, it's also necessary to define the <code>start()</code> function. This function contains all the commands necessary to initialize the service. It's advisable to use the <code>ebegin</code> and <code>eend</code> functions to inform the user about what's happening: | |
<!--T:94--> | <!--T:94--> | ||
Line 378: | Line 380: | ||
<!--T:95--> | <!--T:95--> | ||
− | Both <code>--exec</code> and <code>--pidfile</code> should be used in start and stop functions. If the service | + | Both <code>--exec</code> and <code>--pidfile</code> should be used in <code>start()</code> and <code>stop()</code> functions. If the service doesn't create a PID file, then use <code>--make-pidfile</code> if possible, though it is recommended to test this to be sure. Otherwise, don't use PID files. It is also possible to add <code>--quiet</code> to the start-stop-daemon options, but this is not recommended unless the service is extremely verbose. Using <code>--quiet</code> may hinder debugging if the service fails to start. |
<!--T:96--> | <!--T:96--> | ||
− | + | Note also that the above example check the contents of the <var>RC_CMD</var> variable. OpenRC doesn't support script-specific restart functionality; instead, the script needs to check the contents of the <var>RC_CMD</var> variable to see if a function (e.g. <code>start()</code> or <code>stop()</code>) is being called as part of a restart or not. | |
<!--T:97--> | <!--T:97--> | ||
Line 403: | Line 405: | ||
<!--T:101--> | <!--T:101--> | ||
− | If the service runs some other script (for example, Bash, Python, or Perl), and this script later changes names (for example, | + | If the service runs some other script (for example, Bash, Python, or Perl), and this script later changes names (for example, from <code>foo.py</code> to <code>foo</code>), then it is necessary to add <code>--name</code> as an option to {{c|start-stop-daemon}}. This must specify the name that the script will be changed to. In this example, a service starts {{Path|foo.py}}, which changes names to <code>foo</code>: |
<!--T:102--> | <!--T:102--> | ||
Line 416: | Line 418: | ||
<!--T:103--> | <!--T:103--> | ||
− | start-stop-daemon has an excellent man page available if more information is needed: | + | {{c|start-stop-daemon}} has an excellent man page available if more information is needed: |
<!--T:104--> | <!--T:104--> | ||
Line 422: | Line 424: | ||
<!--T:105--> | <!--T:105--> | ||
− | Gentoo's init script syntax is based on the POSIX | + | Gentoo's init script syntax is based on the POSIX shell ('sh'), so people are free to use sh-compatible constructs inside their init scripts. Keep other constructs, like Bash-specific ones, out of init scripts to ensure that the scripts remain functional regardless of any changes Gentoo might make to its init system. |
=== {{Anchor|Adding custom options}} Adding custom options === <!--T:106--> | === {{Anchor|Adding custom options}} Adding custom options === <!--T:106--> | ||
<!--T:107--> | <!--T:107--> | ||
− | If the initscript needs to support | + | If the initscript needs to support an option other than the ones we've already encountered, add the option to one of the following variables, and create a function with the same name as the option. For instance, to support an option called <code>restartdelay</code>: |
<!--T:141--> | <!--T:141--> | ||
Line 460: | Line 462: | ||
<!--T:112--> | <!--T:112--> | ||
− | Also, if the init script provides a virtual dependency (such as net), the file associated with that dependency (such as {{Path|/etc/conf.d/net}}) will be sourced too. | + | Also, if the init script provides a virtual dependency (such as <code>net</code>), the file associated with that dependency (such as {{Path|/etc/conf.d/net}}) will be sourced too. |
== {{Anchor|Changing runlevel behavior}} Changing runlevel behavior == <!--T:113--> | == {{Anchor|Changing runlevel behavior}} Changing runlevel behavior == <!--T:113--> | ||
Line 470: | Line 472: | ||
<!--T:116--> | <!--T:116--> | ||
− | For instance, a second "default" runlevel can be created | + | For instance, a second "default" runlevel can be created, with other init scripts assigned to it. At boot time, the user can select what "default" runlevel to use. |
=== {{Anchor|Using softlevel}} Using softlevel === <!--T:117--> | === {{Anchor|Using softlevel}} Using softlevel === <!--T:117--> | ||
Line 496: | Line 498: | ||
<!--T:122--> | <!--T:122--> | ||
− | Even though net.eth0 has been removed from the offline runlevel, udev might want to attempt to start any devices it detects and launch the appropriate services, | + | Even though net.eth0 has been removed from the offline runlevel, udev might want to attempt to start any devices it detects and launch the appropriate services, functionality that is called hotplugging. By default, Gentoo does not enable hotplugging. |
<!--T:123--> | <!--T:123--> |
Revision as of 17:46, 19 October 2024
Readers should not try to follow instructions directly from the Handbook:Parts namespace (which is THIS page!). The sections displayed below are used as a skeleton for transcluding information into the computer architecture specific handbooks and are therefore lacking critical information.
Please visit the Handbook list to read instructions for a relevant computer architecture.
The contents of this page do not apply to users that chose a systemd profile in Choosing the right profile.
Runlevels
Booting the system
When the system is booted, lots of text floats by. When paying close attention, one will notice this text is (usually) the same every time the system is rebooted. The sequence of all these actions is called the boot sequence and is (more or less) statically defined.
First, the boot loader will load the kernel image that is defined in the boot loader configuration. Then, the boot loader instructs the CPU to execute the kernel. When the kernel is loaded and run, it initializes all kernel-specific structures and tasks and starts the init process.
The init process makes sure that all filesystems (defined in /etc/fstab) are mounted and ready to be used. Then it executes several scripts located in /etc/init.d/, which will start the services needed in order to have a successfully booted system.
Finally, once all scripts have been executed, init activates the virtual consoles accessible via Ctrl+Alt+ F1, Ctrl+Alt + F2, etc.), attaching to each one a special process called agetty. This process ensures users are able to log on via login.
Initscripts
The scripts in /etc/init.d/ aren't executed randomly. init doesn't run all scripts in /etc/init.d/, only the scripts it is told to execute, via /etc/runlevels/.
First, init runs all scripts from /etc/init.d/ that have symbolic links inside /etc/runlevels/boot/. Usually, it will start the scripts in alphabetical order, but some scripts have dependency information in them, telling the system that another script must be run before they can be started.
Once all scripts referenced in /etc/runlevels/boot/ have been executed, init will run the scripts linked in /etc/runlevels/default/. Again, it will use the alphabetical order to decide what script to run first, unless a script has dependency information in it, in which case the order is changed to provide a valid start-up sequence. This is why commands used during the installation of Gentoo Linux use the default
runlevel (e.g. rc-update add sshd default
).
How init works
Of course init doesn't decide all that by itself. It needs a configuration file that specifies what actions need to be taken. The /etc/inittab file is used by init to determine the actions it needs to take.
As described above, init's first action is to mount all file systems. This is defined in the following line from /etc/inittab:
/etc/inittab
Initialization commandsi::sysinit:/sbin/openrc sysinit
This line tells init that it must run /sbin/openrc sysinit to initialize the system. The /sbin/openrc script takes care of the initialization, so one might say that init doesn't do much - it delegates the task of initializing the system to another process.
Second, init executed all scripts that had symbolic links in /etc/runlevels/boot/. This is defined in the following line:
/etc/inittab
Boot command invocationrc::bootwait:/sbin/openrc boot
Again the OpenRC script performs the necessary tasks. Note that the option given to OpenRC (boot) is the same as the sub-directory of /etc/runlevels/ that is used.
Now init checks its configuration file to see what runlevel it should run. To decide this, it reads the following line from /etc/inittab:
/etc/inittab
Default runlevel selectionid:3:initdefault:
In this case (which the majority of Gentoo users will use), the runlevel id is 3. Using this information, init checks what it must run to start runlevel 3:
/etc/inittab
Runlevel definitionsl0:0:wait:/sbin/openrc shutdown
l1:S1:wait:/sbin/openrc single
l2:2:wait:/sbin/openrc nonetwork
l3:3:wait:/sbin/openrc default
l4:4:wait:/sbin/openrc default
l5:5:wait:/sbin/openrc default
l6:6:wait:/sbin/openrc reboot
The line that defines level 3, again uses the openrc script to start the services (now with argument default
). Also note again that the argument to openrc is the same as the subdirectory from /etc/runlevels/.
When OpenRC has finished, init decides what virtual consoles it should activate and what commands need to be run at each console:
/etc/inittab
Terminal definitionsc1:12345:respawn:/sbin/agetty 38400 tty1 linux
c2:12345:respawn:/sbin/agetty 38400 tty2 linux
c3:12345:respawn:/sbin/agetty 38400 tty3 linux
c4:12345:respawn:/sbin/agetty 38400 tty4 linux
c5:12345:respawn:/sbin/agetty 38400 tty5 linux
c6:12345:respawn:/sbin/agetty 38400 tty6 linux
Available runlevels
In a previous section, we saw that init uses a numbering scheme to decide what runlevel it should activate. A runlevel is a state in which the system is running and contains a collection of scripts (runlevel scripts or initscripts) that must be executed when entering or leaving a runlevel.
In Gentoo, there are seven runlevels defined: three internal runlevels, and four user-defined runlevels. The internal runlevels are called sysinit, shutdown and reboot and do exactly what their names imply: initializing the system, powering off the system, and rebooting the system.
The user-defined runlevels are those with an accompanying /etc/runlevels/ subdirectory: boot, default, nonetwork and single. The boot runlevel starts all system-necessary services used by all the other runlevels. The remaining three runlevels differ in what services they start: default is used for day-to-day operations, nonetwork is used in case no network connectivity is required, and single is used when the system needs to be fixed.
Working with initscripts
The scripts that the openrc process starts are called init scripts. Each script in /etc/init.d/ can be executed with the arguments start
, stop
, restart
, zap
, status
, ineed
, iuse
, iwant
, needsme
, usesme
, or wantsme
.
To start, stop, or restart a service (and all dependent services), the start
, stop
, and restart
arguments should be used:
root #
rc-service postfix start
Only the services that need the given service are stopped or restarted. The other dependent services (those that use the service but don't need it) are left untouched.
To stop a service, but not the services that depend on it, use the --nodeps
option together with the stop
argument:
root #
rc-service --nodeps postfix stop
To get the status of a service (started, stopped, ...), use the status argument:
root #
rc-service postfix status
If the status information shows that the service is running, but in reality it is not, then reset the status information to "stopped" with the zap
argument:
root #
rc-service postfix zap
To also ask what dependencies the service has, use iwant
, iuse
or ineed
. With ineed
it is possible to see the services that are really necessary for the correct functioning of the service. iwant
or iuse
, on the other hand, shows the services that can be used by the service, but are not necessary for the correct functioning of the service.
root #
rc-service postfix ineed
Similarly, it is possible to ask what services require the service (needsme
) or can use it (usesme
or wantsme
):
root #
rc-service postfix needsme
Updating runlevels
rc-update
Gentoo's init system uses a dependency tree to decide what service needs to be started first. As this is a tedious task that we wouldn't want our users to have to do manually, we have created tools that ease the administration of the runlevels and init scripts.
With rc-update it is possible to add and remove init scripts to a runlevel. The rc-update tool will then automatically ask the depscan.sh script to rebuild the dependency tree.
Adding and removing services
In earlier instructions, init scripts have already been added to the default runlevel. What default means has been explained earlier in this document. Next to the runlevel, the rc-update script requires a second argument that defines the action: add
, del
, or show
.
In addition to the runlevel, the rc-update script requires a second argument specifying the appropriate action: add
, del
, or show
. For instance:
root #
rc-update del postfix default
The rc-update -v show command will show all the available init scripts and the runlevels in which they will execute:
root #
rc-update -v show
It is also possible to run rc-update show (without -v
) to just view enabled init scripts and their runlevels.
Configuring services
Why additional configuration is needed
Init scripts can be quite complex. It is therefore not desirable to have users edit init scripts directly, as it would make them more error-prone. However, it's important to be able configure services: for instance, users might want to run the service with additional options.
A second reason to have this configuration outside the init script is to be able to update the init scripts without the fear that the user's configuration changes will be undone.
conf.d directory
Gentoo provides an easy way to configure such a service: every init script that can be configured has a file in /etc/conf.d/. For instance, the apache2 initscript (called /etc/init.d/apache2) has a configuration file called /etc/conf.d/apache2, which can contain the options to give to the Apache 2 server when it is started:
/etc/conf.d/apache2
Example options for apache2 init scriptAPACHE2_OPTS="-D PHP5"
Such a configuration file contains only variables (just like /etc/portage/make.conf does), making it very easy to configure services. It also allows us to provide more information about the variables (as comments).
Writing initscripts
Another useful resource is OpenRC's service script guide.
Is it necessary?
No, writing an init script is usually not necessary as Gentoo provides ready-to-use init scripts for all provided services. However, some users might have installed a service without using Portage, in which case they will most likely have to create an init script.
Do not use the init script provided by the service if it isn't explicitly written for Gentoo: Gentoo's init scripts are not compatible with the init scripts used by other distributions, unless the other distribution is using OpenRC.
Layout
The basic layout of an init script is shown below.
#!/sbin/openrc-run
depend() {
# (Dependency information)
}
start() {
# (Commands necessary to start the service)
}
stop() {
# (Commands necessary to stop the service)
}
#!/sbin/openrc-run
command=/usr/bin/foo
command_args="${foo_args} --bar"
pidfile=/var/run/foo.pid
name="FooBar Daemon"
description="FooBar is a daemon that drinks"
extra_started_commands="drink"
description_drink="Opens mouth and reflexively swallows"
depend() {
# (Dependency information)
}
start_pre() {
# (Commands necessary to prepare to start the service)
# Ensure that our dirs are correct
checkpath --directory --owner foo:foo --mode 0775 \
/var/run/foo /var/cache/foo
}
stop_post() {
# (Commands necessary to clean up after the service)
# Clean any spills
rm -rf /var/cache/foo/*
}
drink() {
ebegin "Starting to drink"
${command} --drink beer
eend $? "Failed to drink any beer :("
}
Every init script requires the start()
function or command
variable to be defined. All other sections are optional.
Dependencies
There are three dependency-related settings which can influence the start-up or sequencing of init scripts:: want
, use
and need
. Next to these, there are also two order-influencing methods called before
and after
. These last two are not dependencies per se - they don't make the init script fail if the specified dependency isn't scheduled to start (or fails to start).
- The
use
setting informs the init system that the script uses functionality offered by the selected script, but does not directly depend on it. Some examples areuse logger
anduse dns
: if the services are available, they will be used, but if the system does not have a logger or DNS server, the services will still work. If the services exist, then they are started before the script that uses them. - The
want
setting is similar touse
with one exception.use
only considers services which were added to a runlevel;want
will try to start any available service even if not added to any runlevel.want
will try to start any available service even if not added to an init level. - The
need
setting indicates a hard dependency: a script thatneed
s another script will not start before the latter script is started successfully. Also, if theneed
ed script is restarted, the script needing it will be restarted as well. - The
before
setting ensures the script is launched before a specified script, if the latter is part of the runlevel. So an init script xdm that definesbefore alsasound
will start before the alsasound script, but only if alsasound is scheduled to start in the same runlevel. If alsasound is not scheduled to start in that runlevel, then thebefore
has no effect, and xdm will be started when the init system deems it most appropriate. - Similarly,
after
informs the init system that the given script should be launched after a specified script if the latter is part of the same runlevel. If not, then the setting has no effect and the script will be launched by the init system when it deems it most appropriate.
It should be clear from the above that need
is the only "true" dependency setting, as it affects whether the script will be started or not. All the others merely tell the init system the order in which scripts can be (or should be) started.
Virtual dependencies
Many of Gentoo's init scripts depend on things that are themselves not init scripts: virtual dependencies.
A virtual dependency is a dependency that a service provides, but that is not provided solely by that service. An init script can depend on a system logger, but there are many system loggers available (metalogd, syslog-ng, sysklogd, ...). As the script cannot need every single one of them (no sensible system has all these system loggers installed and running) we made sure that all these services provide a virtual dependency.
For instance, consider the dependency information in the postfix script:
/etc/init.d/postfix
Dependency information of the postfix servicedepend() {
need net
use logger dns
provide mta
}
As can be seen, the postfix service:
- Requires the (virtual)
net
dependency (which is provided by, for instance, /etc/init.d/net.eth0). - Uses the (virtual)
logger
dependency (which is provided by, for instance, /etc/init.d/syslog-ng). - Uses the (virtual)
dns
dependency (which is provided by, for instance, /etc/init.d/named). - Provides the (virtual)
mta
dependency (which is common for all mail servers).
Controlling the order
As described in the previous section, it is possible to tell the init system what order it should use for starting (or stopping) scripts. This ordering is handled both through the dependency settings use
and need
, but also through the order settings before
and after
. As we have described these earlier already, let's take a look at the portmap service as an example of such init script.
/etc/init.d/portmap
Dependency information of the portmap servicedepend() {
need net
before inetd
before xinetd
}
It's possible to use the *
glob to refer to all services in the same runlevel, although this isn't advisable.
depend() {
before *
}
If the service must write to local disks, it should need localmount
. If it places anything in /var/run/, such as a PID file, then it should start after bootmisc
:
depend() {
need localmount
after bootmisc
}
Standard functions
In addition to the depend()
functionality, it's also necessary to define the start()
function. This function contains all the commands necessary to initialize the service. It's advisable to use the ebegin
and eend
functions to inform the user about what's happening:
start() {
if [ "${RC_CMD}" = "restart" ];
then
# Do something in case a restart requires more than stop, start
fi
ebegin "Starting my_service"
start-stop-daemon --start --exec /path/to/my_service \
--pidfile /path/to/my_pidfile
eend $?
}
Both --exec
and --pidfile
should be used in start()
and stop()
functions. If the service doesn't create a PID file, then use --make-pidfile
if possible, though it is recommended to test this to be sure. Otherwise, don't use PID files. It is also possible to add --quiet
to the start-stop-daemon options, but this is not recommended unless the service is extremely verbose. Using --quiet
may hinder debugging if the service fails to start.
Note also that the above example check the contents of the RC_CMD variable. OpenRC doesn't support script-specific restart functionality; instead, the script needs to check the contents of the RC_CMD variable to see if a function (e.g. start()
or stop()
) is being called as part of a restart or not.
Make sure that
--exec
actually calls a service and not just a shell script that launches services and exits - that's what the init script is supposed to do.For more examples of the start()
function, please read the source code of the available init scripts in the /etc/init.d/ directory.
Another function that can (but does not have to) be defined is stop()
. The init system is intelligent enough to fill in this function by itself if start-stop-daemon is used.
stop() {
ebegin "Stopping my_service"
start-stop-daemon --stop --exec /path/to/my_service \
--pidfile /path/to/my_pidfile
eend $?
}
If the service runs some other script (for example, Bash, Python, or Perl), and this script later changes names (for example, from foo.py
to foo
), then it is necessary to add --name
as an option to start-stop-daemon. This must specify the name that the script will be changed to. In this example, a service starts foo.py, which changes names to foo
:
start() {
ebegin "Starting my_script"
start-stop-daemon --start --exec /path/to/my_script \
--pidfile /path/to/my_pidfile --name foo
eend $?
}
start-stop-daemon has an excellent man page available if more information is needed:
user $
man start-stop-daemon
Gentoo's init script syntax is based on the POSIX shell ('sh'), so people are free to use sh-compatible constructs inside their init scripts. Keep other constructs, like Bash-specific ones, out of init scripts to ensure that the scripts remain functional regardless of any changes Gentoo might make to its init system.
Adding custom options
If the initscript needs to support an option other than the ones we've already encountered, add the option to one of the following variables, and create a function with the same name as the option. For instance, to support an option called restartdelay
:
- extra_commands - Command is available with the service in any state
- extra_started_commands - Command is available when the service is started
- extra_stopped_commands - Command is available when the service is stopped
extra_started_commands="restartdelay"
restartdelay() {
stop
sleep 3 # Wait 3 seconds before starting again
start
}
The
restart()
function cannot be overridden in OpenRC!Service configuration variables
In order to support configuration files in /etc/conf.d/, no specifics need to be implemented: when the init script is executed, the following files are automatically sourced (i.e. the variables are available to use):
- /etc/conf.d/YOUR_INIT_SCRIPT
- /etc/conf.d/basic
- /etc/rc.conf
Also, if the init script provides a virtual dependency (such as net
), the file associated with that dependency (such as /etc/conf.d/net) will be sourced too.
Changing runlevel behavior
Who might benefit
Many laptop users know the situation: at home they need to start net.eth0, but they don't want to start net.eth0 while on the road (as there is no network available). With Gentoo the runlevel behavior can be altered at will.
For instance, a second "default" runlevel can be created, with other init scripts assigned to it. At boot time, the user can select what "default" runlevel to use.
Using softlevel
First of all, create the runlevel directory for the second "default" runlevel. As an example we create the offline runlevel:
root #
mkdir /etc/runlevels/offline
Add the necessary init scripts to the newly created runlevel. For instance, to have an exact copy of the current default runlevel but without net.eth0:
root #
cd /etc/runlevels/default
root #
for service in *; do rc-update add $service offline; done
root #
rc-update del net.eth0 offline
root #
rc-update show offline
(Partial sample Output) acpid | offline domainname | offline local | offline net.eth0 |
Even though net.eth0 has been removed from the offline runlevel, udev might want to attempt to start any devices it detects and launch the appropriate services, functionality that is called hotplugging. By default, Gentoo does not enable hotplugging.
To enable hotplugging, but only for a selected set of scripts, use the rc_hotplug variable in /etc/rc.conf:
/etc/rc.conf
Enable hotplugging of the WLAN interfacerc_hotplug="net.wlan !net.*"
For more information on device initiated services, please see the comments inside /etc/rc.conf.
Edit the bootloader configuration and add a new entry for the offline runlevel. In that entry, add softlevel=offline
as a boot parameter.
Using bootlevel
Using bootlevel is completely analogous to softlevel. The only difference here is that a second "boot" runlevel is defined instead of a second "default" runlevel.