Linux Init Service管理服务

Published on 2016 - 07 - 19

Checking the Status of Services

SysVinit systems

To see all the services that are being offered by a Linux server using the classic SysVinit daemon, use the chkconfig command. The example that follows shows the services available on a classic SysVinit Linux server. Note that each runlevel (0–6) is shown for each service with a status of on or off. The status denotes whether a particular service is started (on) or not (off) for that runlevel.

# chkconfig --list
ConsoleKit      0:off  1:off  2:off  3:on   4:on   5:on   6:off
NetworkManager  0:off  1:off  2:off  3:off  4:off  5:off  6:off
...
crond           0:off  1:off  2:on   3:on   4:on   5:on   6:off
cups            0:off  1:off  2:on   3:on   4:on   5:on   6:off
...
sshd            0:off  1:off  2:on   3:on   4:on   5:on   6:off
syslog          0:off  1:off  2:on   3:on   4:on   5:on   6:off
tux             0:off  1:off  2:off  3:off  4:off  5:off  6:off
udev-post       0:off  1:off  2:off  3:on   4:on   5:on   6:off

Using the chkconfig command, you cannot tell if a service is currently running. To do that, you need to use the service command. To help isolate only those services that are currently running, the service command is piped into the grep command and then sorted, as follows.

# service --status-all | grep running...| sort
anacron (pid 2162) is running...
atd (pid 2172) is running...
auditd (pid 1653) is running...
automount (pid 1952) is running...
console-kit-daemon (pid 2046) is running...
crond (pid 2118) is running...
cupsd (pid 1988) is running...
...
sshd (pid 2002) is running...
syslogd (pid 1681) is running...
xfs (pid 2151) is running...
yum-updatesd (pid 2205) is running...

You can also use both the chkconfig and the service commands to view an individual service's settings. Using both commands in the example that follows, you can view the cups daemon's settings.

# chkconfig --list cups
cups            0:off   1:off   2:on    3:on    4:on    5:on    6:off
# service cups status
cupsd (pid 1988) is running...

You can see that the cupsd daemon is set to start on every runlevel but 0, 1, and 6, and from the service command, you can see that it is currently running. Also, the process ID (PID) number is given for the daemon.

Upstart systems

To see all the services running on a Linux server using the Upstart init daemon, use the following command:

# initctl list | grep start/running
tty (/dev/tty3) start/running, process 1163
...
system-setup-keyboard start/running, process 656
prefdm start/running, process 1154

Keep in mind that there may still be services that have not been ported to the Upstart init daemon. Therefore, you also need to use the classic SysVinit command, service, to check for any leftover SysVinit services. Note that on some distributions, you may see a few services in both the initctl and the service command output.

# service --status-all | grep running
abrtd (pid  1118) is running...
acpid (pid  996) is running...
atd (pid  1146) is running...
...
rsyslogd (pid  752) is running...
sendmail (pid  1099) is running...
...

To show the status of a single service, use initctl if the service has been ported to Upstart and the service command if it has not been ported yet. The following example shows two service statuses—one that has been ported to Upstart and one that has not.

# initctl status vpnc-cleanup
vpnc-cleanup stop/waiting
# service ssh status
sshd (pid  970) is running...

In this example, the ssh daemon had not yet been ported to Upstart. Therefore, ssh needs the service command with the status option to be used to check its status. The vpnc-cleanup service is an Upstart service. Thus, it needed the initctl status command to be used. In some distributions, such as Ubuntu, you can also use the initctl status command for services that have not yet been migrated to Upstart.

systemd systems

To see all the services that are being offered by a Linux server using systemd, use the following command:

# systemctl list-unit-files --type=service | grep -v disabled
UNIT FILE                                   STATE
abrt-ccpp.service                           enabled
abrt-oops.service                           enabled
abrt-vmcore.service                         enabled
abrtd.service                               enabled
alsa-restore.service                        static
alsa-store.service                          static
anaconda-shell@.service                     static
arp-ethers.service                          enabled
atd.service                                 enabled
auditd.service                              enabled
avahi-daemon.service                        enabled
bluetooth.service                           enabled
console-kit-log-system-restart.service      static
console-kit-log-system-start.service        static
console-kit-log-system-stop.service         static
crond.service                               enabled
cups.service                                enabled
...
sshd-keygen.service                         enabled
sshd.service                                enabled
system-setup-keyboard.service               enabled
...
134 unit files listed.

Remember that the three status possibilities for a systemd service are enabled, disabled, or static. There's no need to include disabled to see which services are set to be active, which is effectively accomplished by using the -v option on the grep command, as shown in the preceding example. The state of static is essentially enabled, and thus should be included.

To see if a particular service is running, use the following command:

# systemctl status cups.service
cups.service - CUPS Printing Service
  Loaded: loaded (/lib/systemd/system/cups.service; enabled)
  Active: active (running) since Mon, 30 Apr 12:36:31 -0400; 13h ago
  Main PID: 1315 (cupsd)
   CGroup: name=systemd:/system/cups.service
            1315 /usr/sbin/cupsd -f

The systemctl command can be used to show the status of a single service. In the preceding example, the printing service was chosen. Notice that the name of the service is cups.service. A great deal of helpful information about the service is given here, such as the fact that it is enabled and active, its start time, and its process ID (PID) as well.

Stopping and Starting Services

SysVinit services

The primary command for stopping and starting SysVinit services is the service command. With the service command, the name of the service you want to control comes second in the command line. The last option is what you want to do to the service, stop, start, restart, and so on. The following example shows how to stop the cups service. Notice that an OK is given, which lets you know that cupsd has been successfully stopped.

# service cups status
cupsd (pid 5857) is running...
# service cups stop
Stopping cups:        [  OK  ]
# service cups status
cupsd is stopped

To start a service, you simply use a start option instead of a stop option on the end of the service command as follows.

# service cups start
Starting cups:         [  OK  ]
# service cups status
cupsd (pid 6860) is running...

To restart a SysVinit service, the restart option is used. This option stops the service and then immediately starts it again.

# service cups restart
Stopping cups:          [  OK  ]
Starting cups:          [  OK  ]
# service cups status
cupsd (pid 7955) is running...

When a service is already stopped, a restart generates a FAILED status on the attempt to stop it. However, as shown in the example that follows, the service is successfully started when a restart is attempted.

# service cups stop
Stopping cups:           [  OK  ]
# service cups restart
Stopping cups:           [FAILED]
Starting cups:           [  OK  ]
# service cups status
cupsd (pid 8236) is running...

Reloading a service is different from restarting a service. When you reload a service, the service itself is not stopped. Only the service's configuration files are loaded again. The following example shows how to reload the cups daemon.

# service cups status
cupsd (pid 8236) is running...
# service cups reload
Reloading cups:            [  OK  ]
# service cups status
cupsd (pid 8236) is running...

If a SysVinit service is stopped when you attempt to reload it, you get a FAILED status. This is shown in the following example:

# service cups status
cupsd is stopped
# service cups reload
Reloading cups:             [FAILED]

Upstart services

The primary command for stopping and starting Upstart init services is the initctl command. The options are very similar to SysVinit's service command:

  • Stopping a service with Upstart — In the following example, the status of the cups daemon is checked and then stopped using the initctl stop cups command.

    # initctl status cups
    cups start/running, process 2390
    # initctl stop cups
    cups stop/waiting
    # initctl status cups
    cups stop/waiting
    
  • Starting a service with Upstart — In the following example, the cups daemon is started using the initctl start cups command.

    # initctl start cups
    cups start/running, process 2408
    # initctl status cups
    cups start/running, process 2408
    
  • Restarting a service with Upstart — Restarting a service with Upstart stops and then starts the service. However, the configuration file is not reloaded.

    # initctl restart cups
    cups start/running, process 2430
    # initctl status cups
    cups start/running, process 2490
    
  • Reloading a service with Upstart — Reloading does not stop and start the service. It only loads the configuration file again. This is the option to use when you have made changes to the configuration file. The following example illustrates how to reload the cups daemon with initctl. Notice that the process ID (PID) is still 2490, which is the same as it was in the example for restarting the cups daemon because the process was not stopped and started in the reload process.

    # initctl reload cups
    # initctl status cups
    cups start/running, process 2490
    

systemd services

For the systemd daemon, the systemctl command works for stopping, starting, reloading, and restarting services. The options to the systemctl command should look familiar.

Stopping a service with systemd

In the example that follows, the status of the cups daemon is checked and then stopped using the systemctl stop cups.service command:

# systemctl status cups.service
cups.service - CUPS Printing Service
    Loaded: loaded (/lib/systemd/system/cups.service; enabled)
    Active: active (running) since Mon, 30 Apr 2018 12:36:3...
  Main PID: 1315 (cupsd)
    CGroup: name=systemd:/system/cups.service
            1315 /usr/sbin/cupsd -f
# systemctl stop cups.service
# systemctl status cups.service
cups.service - CUPS Printing Service
    Loaded: loaded (/lib/systemd/system/cups.service; enabled)
    Active: inactive (dead) since Tue, 01 May 2018 04:43:4...
    Process: 1315 ExecStart=/usr/sbin/cupsd -f
 (code=exited, status=0/SUCCESS)
    CGroup: name=systemd:/system/cups.service

Notice that when the status is taken, after stopping the cups daemon, the service is inactive (dead) but still considered enabled. This means that the cups daemon is still started upon server boot.

Starting a service with systemd

Starting the cups daemon is just as easy as stopping it. The example that follows demonstrates this ease.

# systemctl start cups.service
# systemctl status cups.service
cups.service - CUPS Printing Service
    Loaded: loaded (/lib/systemd/system/cups.service; enabled)
    Active: active (running) since Tue, 01 May 2018 04:43:5...
  Main PID: 17003 (cupsd)
    CGroup: name=systemd:/system/cups.service
             17003 /usr/sbin/cupsd -f

After the cups daemon is started, using systemctl with the status option shows that the service is active (running). Also, its process ID (PID) number, 17003, is shown.

Restarting a service with systemd

Restarting a service means that a service is stopped and then started again. If the service was not currently running, restarting it simply starts the service.

# systemctl restart cups.service
# systemctl status cups.service
cups.service - CUPS Printing Service
   Loaded: loaded (/lib/systemd/system/cups.service; enabled)
   Active: active (running) since Tue, 01 May 2018 04:45:2...
  Main PID: 17015 (cupsd)
   CGroup: name=systemd:/system/cups.service
            17015 /usr/sbin/cupsd -f

You can also perform a conditional restart of a service using systemctl. A conditional restart only restarts a service if it is currently running. Any service in an inactive state is not started.

# systemctl status cups.service
cups.service - CUPS Printing Service
  Loaded: loaded (/lib/systemd/system/cups.service; enabled)
  Active: inactive (dead) since Tue, 01 May 2015 06:03:32...
 Process: 17108 ExecStart=/usr/sbin/cupsd -f
 (code=exited, status=0/SUCCESS)
  CGroup: name=systemd:/system/cups.service
# systemctl condrestart cups.service
# systemctl status cups.service
cups.service - CUPS Printing Service
  Loaded: loaded (/lib/systemd/system/cups.service; enabled)
  Active: inactive (dead) since Tue, 01 May 2015 06:03:32...
 Process: 17108 ExecStart=/usr/sbin/cupsd -f
 (code=exited, status=0/SUCCESS)
  CGroup: name=systemd:/system/cups.service

Notice in the example that the cups daemon was in an inactive state. When the conditional restart was issued, no error messages were generated! The cups daemon was not started because conditional restarts affects active services. Thus, it is always a good practice to check the status of a service, after stopping, starting, conditionally restarting, and so on.

Reloading a service with systemd

Reloading a service is different from restarting a service. When you reload a service, the service itself is not stopped. Only the service's configuration files are loaded again.

# systemctl status sshd.service
sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled)
   Active: active (running) since Fri 2018-11-24 14:06:57 EST...
 Main PID: 1675 (sshd)
   CGroup: /system.slice/sshd.service
           1675 /usr/sbin/sshd -D
# systemctl reload sshd.service
# systemctl status sshd.service
sshd.service - OpenSSH server daemon
   Loaded: loaded (/lib/systemd/system/sshd.service; enabled)
   Active: active (running) since Fri 2018-11-24 14:06:57 EST...
  Process: 2149 ExecReload=/bin/kill -HUP $MAINPID
       (code=exited, status=0/SUCCESSd)
 Main PID: 1675 (sshd)
   CGroup: /system.slice/sshd.service
           1675 /usr/sbin/sshd -D

Doing a reload of a service, instead of a restart, prevents any pending service operations from being aborted. A reload is a better method for a busy Linux server.

Enabling Persistent Services

A persistent service is one that is started at server boot time or at a particular runlevel. Services that need to be set as persistent are typically new services that the Linux server is offering.

Configuring SysVinit

One of the nice features of the classic SysVinit daemon is that making a particular service persistent or removing its persistence is very easy to do.

Consider the following example:

# chkconfig --list cups
cups            0:off  1:off  2:off  3:off  4:off  5:off  6:off

On this Linux server, the cups service is not started at any runlevel, as shown with the chkconfig command. You can also check and see if any start (S) symbol links are set up in each of the seven runlevel directories, /etc/rc.d/rc?.d. Remember that SysVinit keeps symbolic links here for starting and stopping various services at certain runlevels. Each directory represents a particular runlevel; for example, rc5.d is for runlevel 5. Notice that only files starting with a K are listed, so there are links for killing off the cups daemon. None are listed with S, which is consistent with chkconfig that the cups daemon does not start at any runlevel on this server.

# ls /etc/rc.d/rc?.d/*cups
/etc/rc.d/rc0.d/K10cups  /etc/rc.d/rc3.d/K10cups
/etc/rc.d/rc1.d/K10cups  /etc/rc.d/rc4.d/K10cups
/etc/rc.d/rc2.d/K10cups  /etc/rc.d/rc5.d/K10cups
/etc/rc.d/rc6.d/K10cups

To make a service persistent at a particular runlevel, the chkconfig command is used again. Instead of the --list option, the --level option is used, as shown in the following code:

# chkconfig --level 3 cups on
# chkconfig --list cups
cups            0:off  1:off  2:off  3:on   4:off  5:off  6:off
# ls /etc/rc.d/rc3.d/S*cups
/etc/rc.d/rc3.d/S56cups

The service's persistence at runlevel 3 is verified by both using the chkconfig --list command and looking at the rc3.d directory for any files starting with the letter S.

To make a service persistent on more than one runlevel, you can do the following:

# chkconfig --level 2345 cups on
# chkconfig --list cups
cups            0:off  1:off  2:on   3:on   4:on   5:on   6:off
# ls /etc/rc.d/rc?.d/S*cups
/etc/rc.d/rc2.d/S56cups  /etc/rc.d/rc4.d/S56cups
/etc/rc.d/rc3.d/S56cups  /etc/rc.d/rc5.d/S56cups

Disabling a service is just as easy as enabling one with SysVinit. You just need to change the on in the chkconfig command to off. The following example demonstrates using the chkconfig command to disable the cups service at runlevel 5.

# chkconfig --level 5 cups off
# chkconfig --list cups
cups            0:off  1:off  2:on   3:on   4:on   5:off   6:off
# ls /etc/rc.d/rc5.d/S*cups
ls: cannot access /etc/rc.d/rc5.d/S*cups: No such file or directory

As expected, there is now no symbolic link, starting with the letter S, for the cups service in the /etc/rc.d/rc5.d directory.

Configuring Upstart

The Upstart init daemon emits the startup signal that triggers the service jobs to start. At server boot time, various jobs may themselves emit signals. These emitted signals then cause other jobs to start. Thus, the key to making a service persistent is to ensure the service's definition file is triggered by one of the signals emitted as the server boots.

Remember that the Upstart init daemon's job definition files are located in the /etc/init directory. Consider the following job definition file for the ssh daemon:

# cat /etc/init/ssh.conf
# ssh - OpenBSD Secure Shell server
# The OpenSSH server provides secure shell access to the system.
description   "OpenSSH server"
start on filesystem or runlevel [2345]
stop on runlevel [!2345]
respawn

To determine what emitted events trigger a service, look for start on in the configuration file. The ssh daemon is triggered by several possible emitted events, filesystem, runlevel 2, runlevel 3, runlevel 4, or runlevel 5. Basically, the ssh daemon starts upon server boot and is set as persistent. The syntax for the runlevel events, runlevel [2345], is used in many of the job files and denotes that the name “runlevel” can end in 2, 3, 4, or 5.

To make a job persistent (start at boot), you need to modify the start on line in its configuration file so it starts on certain events emitted at server boot. To disable a job at boot, just comment out the start on line with a pound sign (#).

Configuring systemd

For the systemd daemon, again the systemctl command is used. With it, you can disable and enable services on the Linux server.

Enabling a service with systemd

Using the enable option on the systemctl command sets a service to always start at boot (be persistent). The following shows exactly how to accomplish this:

# systemctl status cups.service
cups.service - CUPS Printing Service
   Loaded: loaded (/lib/systemd/system/cups.service; disabled)
   Active: inactive (dead) since Tue, 01 May 2018 06:42:38 ...
 Main PID: 17172 (code=exited, status=0/SUCCESS)
   CGroup: name=systemd:/system/cups.service
# systemctl enable cups.service
ln -s '/lib/systemd/system/cups.service'
   '/etc/systemd/system/printer.target.wants/cups.service'
ln -s '/lib/systemd/system/cups.socket'
   '/etc/systemd/system/sockets.target.wants/cups.socket'
ln -s '/lib/systemd/system/cups.path'
   '/etc/systemd/system/multi-user.target.wants/cups.path'
# systemctl status cups.service
cups.service - CUPS Printing Service
   Loaded: loaded (/lib/systemd/system/cups.service; enabled)
   Active: inactive (dead) since Tue, 01 May 2018 06:42:38...
 Main PID: 17172 (code=exited, status=0/SUCCESS)
   CGroup: name=systemd:/system/cups.service

Notice that the status of cups.service changes from disabled to enabled after using the enable option on systemctl. Also, notice that the enable option simply creates a few symbolic links. You may be tempted to create these links yourself. However, the preferred method is to use the systemctl command to accomplish this.

Disabling a service with systemd

You can use the disable option on the systemctl command to keep a service from starting at boot. However, it does not immediately stop the service. The following example shows how to disable a currently enabled service.

# systemctl disable cups.service
rm '/etc/systemd/system/printer.target.wants/cups.service'
rm '/etc/systemd/system/sockets.target.wants/cups.socket'
rm '/etc/systemd/system/multi-user.target.wants/cups.path'
# systemctl status cups.service
cups.service - CUPS Printing Service
   Loaded: loaded (/lib/systemd/system/cups.service; disabled)
   Active: active (running) since Tue, 01 May 2018 06:06:41...
 Main PID: 17172 (cupsd)
   CGroup: name=systemd:/system/cups.service
            17172 /usr/sbin/cupsd -f

The disable option simply removes a few files via the preferred method of the systemctl command. Notice also in the preceding example that although the cups service is now disabled, the cups daemon is still active (running). With systemd, some services cannot be disabled. These services are static services. Consider the following service, dbus.service:

# systemctl status dbus.service
dbus.service - D-Bus System Message Bus
  Loaded: loaded (/lib/systemd/system/dbus.service; static)
  Active: active (running) since Mon, 30 Apr 2018 12:35:...
 Main PID: 707 (dbus-daemon)
...
# systemctl disable dbus.service
# systemctl status dbus.service
dbus.service - D-Bus System Message Bus
  Loaded: loaded (/lib/systemd/system/dbus.service; static)
  Active: active (running) since Mon, 30 Apr 2018 12:35:...
 Main PID: 707 (dbus-daemon)
...

When the systemctl disable command is issued on dbus.service, it is simply ignored. Remember that static means that the service is enabled by default and cannot be disabled, even by root.

Sometimes, disabling a service is not enough to make sure that it does not run. For example, you might want network.service to replace NetworkManager.service for starting network interfaces on your system. Disabling NetworkManager would keep the service from starting on its own. However, if some other service listed NetworkManager as a dependency, that service would try to start NetworkManager when it started.

To disable a service in a way that prevents it from ever running on your system, you can use the mask option. For example, to set the NetworkManager service so it never runs, type the following:

# systemctl mask NetworkManager.service
ln -s '/dev/null' '/etc/systemd/system/NetworkManager.service”

As the output shows, the NetworkManager.service file in /etc is linked to /dev/null. So even if someone tried to run that service, nothing would happen. To be able to use the service again, you could type systemctl unmask NetworkManager.service.

Configuring a Default Runlevel or Target Unit

Whereas a persistent service is one that is started at server boot time, a persistent (default) runlevel or target unit is a group of services that are started at boot time. Both classic SysVinit and Upstart define these groups of services as runlevels, while systemd calls them target units.

Configuring the SysVinit default runlevel

You set the persistent runlevel for a Linux server using SysVinit in the /etc/inittab file. A portion of this file is shown here:

# cat /etc/inittab
#
# inittab       This file describes how the INIT process should
#               set up the system in a certain run-level.
...
id:5:initdefault:
...

The initdefault line in the example shows that the current default runlevel is runlevel 5. To change this, simply edit the /etc/inittab file using your favorite editor and change the 5 to one of the following runlevels: 2, 3, or 4. Do not use the runlevels 0 or 6 in this file! This would cause your server to either halt or reboot when it is started up.

Configuring the default runlevel in Upstart

Some distributions still use the /etc/inittab file to set the default runlevel, whereas others use the /etc/init/rc-sysinit.conf file.

Earlier Fedora and RHEL's Upstart init daemon still uses the /etc/inittab file. Therefore, just change the default runlevel as you would on a SysVinit system.

Ubuntu's Upstart init daemon uses the /etc/init/rc-sysinit.conf file to set the default runlevel, a portion of which is shown in the code that follows. The code line to change is env DEFAULT_RUNLEVEL=. Simply edit this file and change that number to the runlevel you desire. However, remember that Ubuntu's runlevel 2 is equivalent to runlevels 3, 4, and 5.

$ cat /etc/init/rc-sysinit.conf
# rc-sysinit - System V initialisation compatibility
...
# Default runlevel, this may be overriden on the kernel command-line
# or by faking an old /etc/inittab entry
env DEFAULT_RUNLEVEL=2

Configuring the default target unit for systemd

For systemd, the term target units refers to groups of services to be started. The following shows the various target units you can configure to be persistent and their equivalent backward-compatible, runlevel-specific target units.

multi-user.target =
runlevel2.target
runlevel3.target
runlevel4.target
graphical.target = runlevel5.target

The persistent target unit is set via a symbolic link to the default.target unit file. Consider the following:

# ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 36 Mar 13 17:27
 /etc/systemd/system/default.target ->
 /lib/systemd/system/runlevel5.target
# ls -l /lib/systemd/system/runlevel5.target
lrwxrwxrwx. 1 root root 16 Mar 27 15:39
 /lib/systemd/system/runlevel5.target ->
 graphical.target

The example shows that the current persistent target unit on this server is runlevel5.target because default.target is a symbolic link to the runlevel5.target unit file. However, notice that runlevel5.target is also a symbolic link and it points to graphical.target. Thus, this server's current persistent target unit is graphical.target.

To set a different target unit to be persistent, you simply need to change the symbolic link for default.target. To be consistent, stick with the runlevel target units if they are used on your server.

The following example changes the server's persistent target unit from graphical.target to multi-user.target by changing the default.target symbolic link from runlevel5.target to runlevel3.target. The -f option is used on the ls -s command to force any current symbolic link to be broken and the new designated symbolic link to be enforced.

# ls -l /lib/systemd/system/runlevel3.target
lrwxrwxrwx. 1 root root 17 Mar 27 15:39
 /lib/systemd/system/runlevel3.target ->
 multi-user.target
# ln -sf /lib/systemd/system/runlevel3.target \
 /etc/systemd/system/default.target
# ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 36 May  1 10:06
 /etc/systemd/system/default.target ->
 /lib/systemd/system/runlevel3.target

When the server is rebooted, the multi-user.target is the persistent target unit. Any services in the multi-user.target unit are started (activated) at that time.

Adding New or Customized Services

Occasionally, you need to add a new service to your Linux server. Also, you may have to customize a particular service. When these needs arise, you must follow specific steps for your Linux server's initialization daemon to either take over the management of the service or recognize the customization of it.

Adding new services to SysVinit

When adding a new or customized service to a Linux SysVinit server, you must complete three steps in order to have the service managed by SysVinit.

  1. Create a new or customized service script file.
  2. Move the new or customized service script to the proper location for SysVinit management.
  3. Add the service to a specific runlevel.

Step 1: Create a new or customized service script file
If you are customizing a service script, simply make a copy of the original unit file from/etc/rc.d/init.d and add any desired customizations.

If you are creating a new script, you need to make sure you handle all the various options you want the service command to accept for your service, such as start, stop, restart, and so on.

For a new script, especially if you have never created a service script before, it would be wise to make a copy of a current service script from /etc/rc.d/init.d and modify it to meet your new service's needs. Consider the following partial example of the cupsd service's script:

# cat /etc/rc.d/init.d/cups
#!/bin/sh
...
#   chkconfig: 2345 25 10
...
start () {
        echo -n $"Starting $prog: "
        # start daemon
        daemon $DAEMON
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && touch /var/lock/subsys/cups
        return $RETVAL
}
stop () {
        # stop daemon
        echo -n $"Stopping $prog: "
        killproc $DAEMON
        RETVAL=$?
        echo        [ $RETVAL = 0 ] && rm -f /var/lock/subsys/cups
}
restart() {
        stop
        start
}
case $1 in
...

The cups service script starts out by creating functions for each of the start, stop, and restart options.

One line you should be sure to check and possibly modify in your new script is the chkconfig line that is commented out. For example:

#   chkconfig: 2345 25 10

When you add the service script in a later step, the chkconfig command reads that line to set runlevels at which the service starts (2, 3, 4, and 5), its run order when the script is set to start (25), and its kill order when it is set to stop (10).

Check the boot order in the default runlevel before adding your own script. For example:

# ls /etc/rc5.d
...
/etc/rc5.d/S22messagebus
/etc/rc5.d/S23NetworkManager
/etc/rc5.d/S24nfslock
/etc/rc5.d/S24openct
/etc/rc5.d/S24rpcgssd
/etc/rc5.d/S25blk-availability
/etc/rc5.d/S25cups
/etc/rc5.d/S25netfs
/etc/rc5.d/S26acpid
/etc/rc5.d/S26haldaemon
/etc/rc5.d/S26hypervkvpd
/etc/rc5.d/S26udev-post
...

In this case, the chkconfig line in the S25My_New_Service script will cause the script to be added after S25cups and before S25netfs in the boot order. You can change the chkconfig line in the service script if you want the service to start earlier (use a smaller number) or later (use a larger number) in the list of service scripts.

Step 2: Add the service script to /etc/rc.d/init.d

After you have modified or created and tested your service's script file, you can move it to the proper location: /etc/rc.d/init.d:

# cp My_New_Service /etc/rc.d/init.d
# ls /etc/rc.d/init.d/My_New_Service
/etc/rc.d/init.d/My_New_Service

Step 3: Add the service to runlevel directories

This final step sets up the service script to start and stop at different runlevels and checks that the service script works.

To add the script based on the chkconfig line in the service script, type the following:

# chkconfig --add My_New_Service
# ls /etc/rc?.d/*My_New_Service
/etc/rc0.d/K10My_New_Service  /etc/rc4.d/S25My_New_Service
/etc/rc1.d/K10My_New_Service  /etc/rc5.d/S25My_New_Service
/etc/rc2.d/S25My_New_Service  /etc/rc6.d/K10My_New_Service
/etc/rc3.d/S25My_New_Service

Based on the previous example (chkconfig: 2345 25 10), symbolic links to the script set the service to start in the position 25 (S25) for runlevels 2, 3, 4, and 5. Also, links are set to stop (or not start) at runlevels 0, 1, and 6.

After you have made the symbolic link(s), test that your new or modified service works as expected before performing a server reboot.

# service My_New_Service start
Starting My_New_Service:       [  OK  ]
# service My_New_Service stop
Stopping My_New_Service:       [  OK  ]

After everything is in place, your new or modified service starts at every runlevel you have selected on your system. Also, you can start or stop it manually using the sservice command.

Adding new services to Upstart

You need to complete only one step to add a new service or customize an existing service with Upstart. Just add a new job configuration file or modify an existing one. However, this one step can be rather complicated.

The Upstart service job configuration files are all located in the /etc/init directory. These files are plain text only. They use a special syntax for directing Upstart on how to deal with a particular service. The following example of a configuration file has some very simple syntax:

# cat ck-log-system-restart.conf
# Upstart event
# ck-log-system-restart - write system restart to log
start on runlevel 6
task
exec /usr/sbin/ck-log-system-restart

Any pound sign (#) denotes a comment line and is ignored by Upstart. The other lines are called stanzas and have special syntax for controlling Upstart jobs. The stanzas from the preceding file are as follows:

  • start on—This stanza defines what emitted event starts the service or task. In this particular case, when the runlevel 6 event is emitted, the ck-log-system-restart starts.
  • task—The stanza here defines that this particular job is a task job as opposed to a service.
  • exec—This stanza defines what program runs to start the task. Instead of the exec stanza, you can embed an actual command line script to run here by using the script stanza before the actual code and end script after it.

A slightly more complicated job configuration file is shown next—for the cron daemon. There are some additional stanzas that were not in the previous example. Notice that the task stanza is missing in the file. This indicates that this particular job is a service job instead of a task job.

# cat cron.conf
# cron - regular background program processing daemon
# cron is a standard UNIX program that runs user-specified
# programs at periodic scheduled times
description   "regular background program processing daemon"
start on runlevel [2345]
stop on runlevel [!2345]
expect fork
respawn
exec cron

The additional stanzas in this example are as follows:

  • description—This stanza is optional and simply describes the service.
  • start on—Though the start on portion of this stanza was previously covered, the [2345] syntax was not. Using brackets means that the stanza is valid for any of those numbers. Thus, the service starts on runlevel 2, 3, 4, or 5.
  • stop on—The stanza here defines what emitted events the service stops on. The [!2345] in this stanza means not runlevel 2 or 3 or 4 or 5. In other words, it stops only on runlevel 0, runlevel 1, or runlevel 6.
  • expect—This particular stanza is rather important and a little tricky. The expect fork syntax allows Upstart to track this daemon and any of its child processes (forks).
  • respawn—The stanza here tells Upstart to restart this service if it is ever terminated via a means outside its normal stop on.

To test your new or modified job configuration files, you can set the start on stanza to a non-standard event. In other words, you can make up your own event name. For example, use the event name MyTest. To test the new configuration file, you type initctl emit MyTest at the command line. If your configuration file works correctly, then modify the start on stanza to the correct Upstart event.

Every job configuration file must follow at least three rules. The job configuration file must:

  • Not be empty
  • Be syntactically correct
  • Contain at least one legal stanza

Adding new services to systemd

When adding a new or customized service to a Linux systemd server, you have to complete three steps in order to have the service managed by systemd:

  1. Create a new or customized service configuration unit file for the new or customized service.
  2. Move the new or customized service configuration unit file to the proper location for systemd management.
  3. Add the service to a specific target unit's Wants to have the new or customized service start automatically with other services.

Step 1: Create a new or customized service configuration unit file

If you are customizing a service configuration unit file, simply make a copy of the original unit file from /lib/systemd/system and add any desired customizations.

For new files, obviously, you are creating a service unit configuration file from scratch. Consider the following basic service unit file template. At bare minimum, you need Description and ExecStart options for a service unit configuration file.

# cat My_New_Service.service
[Unit]
Description=My New Service
[Service]
ExecStart=/usr/bin/My_New_Service

For additional help on customizing or creating a new configuration unit file and the various needed options, you can use the man pages. At the command line, type man systemd.service to find out more about the various service unit file options.

Step 2: Move the service configuration unit file

Before you move the new or customized service configuration unit file, you need to be aware that there are two potential locations to store service configuration unit files. The one you choose determines whether the customizations take effect and if they remain persistent through software upgrades.

You can place your system service configuration unit file in one of the following two locations:

  • /etc/systemd/system
    • This location is used to store customized local service configuration unit files.
    • Files in this location are not overwritten by software installations or upgrades.

Files here are used by the system even if there is a file of the same name in the /lib/systemd/system directory.

  • /lib/systemd/system
    • This location is used to store system service configuration unit files.
    • Files in this location are overwritten by software installations and upgrades.

Files here are used by the system only if there is not a file of the same name in the /etc/systemd/system directory.

Thus, the best place to store your new or customized service configuration unit file is in/etc/systemd/system.

When you create a new or customized service, in order for the change to take effect without a server reboot, you need to issue a special command. At the command line, type systemctl daemon-reload.

Step 3: Add the service to the Wants directory

This final step is optional. It needs to be done only if you want your new service to start with a particular systemd target unit. For a service to be activated (started) by a particular target unit, it must be in that target unit's Wants directory.

First, add the line WantedBy=desired.target to the bottom of your service configuration unit file. The following example shows that the desired target unit for this new service is multi-user.target.

# cat /etc/systemd/system/My_New_Service.service
[Unit]
Description=My New Fake Service
[Service]
ExecStart=/usr/bin/My_New_Service
[Install]
WantedBy=multi-user.target

To add a new service unit to a target unit, you need to create a symbolic link. The following example shows the files located in the multi-user.target unit's Wants directory. Previously, in the “Understanding systemd init” section, the systemctl command was used to list Wants, and it is still the preferred method. Notice that in this directory, the files are symbolic links pointing to service unit configuration files in the /lib/systemd/system directory.

# ls /etc/systemd/system/multi-user.target.wants
abrt-ccpp.service     cups.path           remote-fs.target
abrtd.service         fcoe.service        rsyslog.service
abrt-oops.service     irqbalance.service  sendmail.service
abrt-vmcore.service   lldpad.service      sm-client.service
atd.service           mcelog.service      sshd-keygen.service
auditd.service        mdmonitor.service   sshd.service
...
# ls -l /etc/systemd/system/multi-user.target.wants
total 0
lrwxrwxrwx. 1 root root 37 Nov  2 22:29 abrt-ccpp.service ->
    /lib/systemd/system/abrt-ccpp.service
lrwxrwxrwx. 1 root root 33 Nov  2 22:29 abrtd.service ->
    /lib/systemd/system/abrtd.service
...
lrwxrwxrwx. 1 root root 32 Apr 26 20:05 sshd.service ->
    /lib/systemd/system/sshd.service
The following illustrates the process of adding a symbolic link file for My_New_Service:
# ln -s /etc/systemd/system/My_New_Service.service
 /etc/systemd/system/multi-user.target.wants/My_New_Service.service

A symbolic link is created in the multi-user.target.wants directory. Now, the new service, My_New_Service, is activated (started) when the multi-user.target unit is activated.

参考文献