System Startup Scripts

 < Free Open Study > 



Chapter 1 covered the origins and history of Linux, including a brief history of Unix systems. Chapter 3 discussed the basic components of a Linux distribution, including a brief mention of the startup scripts run by the init superprocess. In this section, you will learn about the startup script architecture used by Red Hat Linux, and you will also learn how to customize a system's startup behavior, both manually and by using the provided tools.

One of the two archetypical Unix systems was AT&T's System V (SysV) Unix. This system introduced a particular technique for laying out the scripts that get run by init on startup. The other major approach was introduced by Berkeley Software Distribution (BSD). These two models serve the same ultimate purpose but differ significantly in how they accomplish it. The SysV approach is a more complicated framework that is fairly easy to automate (but harder for humans to modify), whereas the BSD approach is comparatively simpler and easier for humans to manage (though harder to automate). Red Hat Linux uses the SysV approach, and the remainder of this section describes the details of this mechanism.

Red Hat Linux is not the only Unix-like system to use the SysV init scripts model; some commercial Unix flavors use it as well. Once you've read this section, you'll have a working knowledge of the SysV init model in general, so you should be able to apply your knowledge to any system that uses that model, not just Red Hat Linux. Conversely, if you've used one of these other systems previously, you may already be familiar with the SysV init model. In this case, you may wish to skim or skip this chapter; however, the "Using Red Hat's Tools" section is worth reading as it may offer you some additional information.

Understanding Init Runlevels

The init process is the parent of all other processes—it is the superprocess. Consequently, you can think of init as the master process governing the system. As this master process, init controls the lifecycle of all other processes and therefore of the system itself.

Generally, however, init is not directly involved in the activities of its child processes. Instead, after doing its work, init generally sits idle in the background, only waking up when the user requests certain actions or when a crucial process (such as a tty console used for logging in to the system) needs to be "respawned."

At any given time, init is one of seven general states; these states are the system runlevels. The runlevels are numbered 0 through 6, and each level typically corresponds to a certain mode of usage of the system (such as maintenance mode, single-user mode, or even system reboot mode). Init can be configured to perform different actions based on which runlevel it is entering, and the root user can instruct it to switch between runlevels.

The POSIX standard defines the general behavior of init, but it does not specify what states the seven runlevels represent. Traditionally, Unix systems use runlevel 0 for system halt, runlevel 1 for single user, and runlevel 6 for system reboot. The remaining runlevels (2 through 5) are generally multiuser runlevels, but what actually happens in these runlevels is up to the operating system vendor. Table 4-5 summarizes the meanings Red Hat Linux assigns to these runlevels; this information is from the file /etc/inittab.

Table 4-5: Red Hat Linux Runlevels

RUNLEVEL

MEANING

BEHAVIOR

0

System halt

Terminates all processes, flushes the filesystem caches, and shuts down the system.

1

Single-user mode

Opens only a root console; used for system maintenance.

2

Multiuser, no NFS

Normal multiuser mode, except that the Network Filesystem (NFS) is disabled. Typically used for servers or workstations that have only local users.

3

Normal multiuser

The typical mode for systems (such as servers) that do not normally need a graphical desktop.

4

Unused

 

5

Multiuser with X11

Normal multiuser mode with an X11 graphical login screen. The only difference between this runlevel and runlevel 3 is that the X11 login manager is started automatically.

6

Reboot

Like runlevel 0, but reboots the system instead of shutting it down.

Init can be instructed to switch between runlevels on a running system via the init or telinit commands. For example, the canonical way to reboot a Unix system passed down from antiquity is via the command sequence

 sync; sync; sync; init 6 

which manually flushes the filesystem cache and then instructs init to reboot the system. Whenever init switches runlevels, it first terminates or kills all processes that do not belong in the new runlevel, and then it starts all processes that should be running. Through this behavior, shutting down and rebooting the system via runlevels 0 and 6 is actually accomplished by simply defining no processes that may run in those runlevels. Init then terminates everything and starts nothing, except a simple reboot or halt script.

Using init to switch system runlevels actually solves only half the problem of managing the system's running software. The actions that init actually takes (which mostly amount to which processes init runs) must also be established. This is where the shell scripts mentioned in Chapter 3 come in. For each runlevel, init can be configured to execute a corresponding program or take some other action. The next section covers the important files in Red Hat's init scripts package.

File and Directory Layout

Red Hat's installation of init and the scripts comes in two RPM packages: SysVinit and initscripts. In Red Hat 7.3, the actual RPMs (for i386 systems) are SysVinit-2.84-2.i386.rpm and initscripts-6.67-1.i386.rpm. SysVinit installs the init program itself and the related support programs; initscripts installs the actual shell scripts invoked by init.

The SysVinit Package

SysVinit is just an implementation of the init program and doesn't dictate anything about how the actual shell scripts must look—it's the initscripts package that establishes the actual framework used by Red Hat Linux. In fact, most Linux distributions use SysVinit for the init program, whether their actual shell scripts are SysV-like or BSD-like. Table 4-6 lists files installed by SysVinit. This list is not complete; you should use the rpm -ql command to obtain a complete list.

Table 4-6: Important Files from the SysVinit Package

FILE

PURPOSE

/sbin/init

The init program itself

/sbin/telinit

Used to instruct init to change runlevels

/usr/bin/wall

Used to send warning messages to all users on a system when init changes runlevels

/sbin/pidof

Useful tool used to retrieve the process ID (PID) of a program by name; try pidof init

Most of the files in the SysVinit package can be found on any Unix-like system that uses a SysV-compatible init program. The major exception is probably the pidof program, which is used to retrieve the process ID (PID) of a process by name. For example, the command

 pidof init 

will return 1 because init always has the PID of 1. This program is useful in any script that needs to retrieve the PID for a particular process, and it is a bit more convenient to use than a pipeline of commands. pidof myprocess is easier to type than ps aux | grep myprocess | cut -f 1 -d ' ' and quite a bit less error-prone as well, since the latter command will return any process with "myprocess" in its name (such as "notmyprocess"). The pidof command is obviously not required for the system to operate correctly, but it is a typical example of the incremental improvements that open source software makes on the quality of an overall package—init in this case.

Generally, users will not interact directly with most of the files in SysVinit; if you need more information than is contained in Table 4-6, you should consult the man page for the command you need. However, the initscripts package contains the actual scripts that control the system and so bears some discussion.

The initscripts Package

Table 4-7 lists files installed by initscripts. This list is not complete; you should use the rpm -ql command to obtain a complete list.

Table 4-7: Important Files from the initscripts Package

FILE

PURPOSE

/etc/inittab

Configures init; specifies which shell scripts init invokes for each runlevel.

/etc/sysconfig

Contains files that specify values for configuration variables in the scripts. Each file sets values for a particular aspect of the system, such as the network.

/etc/rc.d/rc.sysinit

Invoked by init once when the system boots up.

/etc/rc.d/rc

Invoked by init when switching runlevels.

/etc/rc.d/rc.local

A script invoked last in the process; configures machine-specific details.

/etc/rc.d/rc{X}.d

Contains links to service control scripts used to start the services for a given runlevel X (e.g., /etc/rc.d/rc5.d).

/etc/rc.d/init.d

Contains the actual shell scripts referenced by the rc.{X} directories.

/sbin/service

A utility used for conveniently starting and stopping services manually while the system is running.

/etc/X11/prefdm

Used to indicate which X11 desktop manager to use; specific to runlevel 5 on Red Hat systems.

Note 

With version 8, Red Hat will probably move the /etc/rc.d/rc{X}.d directories to simply /etc/rc{X}.d; in fact, the symbolic links to these directories are already present. You should be aware of this impending change for forward compatibility.

/etc/inittab

The file /etc/inittab contains the init table (inittab) for the system. This file specifies which scripts get invoked for which runlevels. It also specifies scripts that get invoked globally, such when the system boots up or when a user signals a reboot via the "three-fingered salute" Ctrl-Alt-Delete combination. The /etc/inittab file also sets the default runlevel that init enters on startup.

/etc/sysconfig

The /etc/sysconfig directory contains basic configuration data specific to a system. The scripts for a given runlevel are configuring the services and system itself for operation. These scripts must be generic since they are written to run on any system; however, many services require specific values to function correctly. For example, the script for configuring the network should be generic so that it can be reused on any system. However, the IP address of a system is obviously specific to that system. To keep the scripts reusable, data such as IP addresses are placed in the /etc/sysconfig directory and are read by the scripts. The file /etc/sysconfig/network contains data for the network script, for example.

/etc/rc.d

The /etc/rc.d directory contains all of the shell scripts and the directory tree used by init. There is a subdirectory for each runlevel under /etc/rc.d, named according to the level number. For example, the "rc directory" for runlevel 5 is /etc/rc.d/rc5.d. There is also an additional directory named /etc/rc.d/init.d that contains the physical shell script files; the contents of the individual rc directories are symbolic links to scripts in the init.d directory. Note that there are symbolic links to each of these directories from the base /etc directory; however, those links point to the corresponding directories in /etc/rc.d, and are present for convenience and forward compatibility. (A later version of Red Hat will probably move the rc directories to /etc permanently.)

rc.sysinit

The rc.sysinit file is a script that is run once when the system boots up, before any runlevel is entered. This script is specified in /etc/inittab and performs tasks such as checking the disks and filesystems for errors, loading any kernel modules or drivers that are required, restoring the system clock and random number seeds, and other work that is required by the system, regardless of which runlevel is going to be entered. If you watch a recent Red Hat Linux system as it boots, it has two "phases": one phase that always proceeds the same regardless of what the default runlevel is and a second phase where the actual services are started. The first phase (where you are prompted to "Press I to enter interactive mode") corresponds to when rc.sysinit is executing; the next phase begins when rc.sysinit completes, and init enters the default runlevel.

When init enters a particular runlevel, it executes the script matched to that runlevel in /etc/inittab. (In fact, init could be configured to execute more than one script in a particular sequence, but Red Hat has a different approach.) This script is then responsible for starting any services that are appropriate for that runlevel. The next section describes this process in more detail.

Tracing an Execution

Perhaps the best way to illustrate the Red Hat initscripts behavior is to examine the copy of /etc/inittab that comes with Red Hat Linux and track it through a sample boot-up sequence. The remainder of this section dissects the inittab file and maps its contents to the individual events that occur as a Red Hat Linux system starts up. For full documentation on the inittab file, you should consult the man page. All that you need to know for the purposes of this discussion is that the first column (before the first colon) in the lines that follow is simply an identifier and can be arbitrary.

The first noncommented line in inittab specifies the default runlevel. In the case of Red Hat Linux, this is normally 3 or 5. It is 5 if the user selected the Graphical Login option during installation and 3 otherwise. In Table 4-5 (and in the /etc/inittab file itself), runlevel 3 is indicated to be normal multiuser mode, while runlevel 5 is multiuser mode with graphical login. The difference is in the services that get started in each runlevel. The line setting the default runlevel is this one:

 id:5:initdefault: 

The next line specifies the rc.sysinit global script to be invoked by init before entering the default runlevel. This script, as described in the previous section, is responsible for checking the disks for errors, cleaning up the /tmp directory, loading any required kernel modules or drivers, and other similar administrivia. This file is also the one that generates the "Press I to enter interactive mode" prompt during startup. This file is not too complicated, so readers interested in the details should simply scan through this script. It is actually possible to define more than one of these global scripts to execute; however, Red Hat chose to use only one such script. The line specifying this global startup script is this:

 si::sysinit:/etc/rc.d/rc.sysinit 

The next group of lines maps runlevels (in the second column) to scripts (in the last column). As is immediately obvious, Red Hat Linux uses the same script for all runlevels and simply passes the script a different argument depending on which runlevel was entered. The behavior of this script is rather simple: It looks in the corresponding rc directory for the runlevel it was passed as its argument, and then it invokes any programs it finds in that directory. The /etc/rc.d/rc script is covered in a bit more detail in the "Runlevel Configuration Script" section, so for now here are the relevant lines:

 l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 ... l6:6:wait:/etc/rc.d/rc 6 

The next few lines configure init's behavior when it changes runlevels or when it receives certain significant events. The first line starts the kernel's update daemon to periodically synchronize memory cache with the disk, the second line tells init to execute the shutdown command whenever the user presses Ctrl-Alt-Delete, and the last two lines specify commands to run if the system is notified of a power failure. (These last two events can only be triggered if the system is connected to a properly configured uninterruptible power supply [UPS].)

 ud::once:/sbin/update ca::ctrlaltdel:/sbin/shutdown -t3 -r now pf::powerfail:/sbin/shutdown -f -h +2 'Power Failure; System Shutting Down' pr:12345:powerokwait:/sbin/shutdown -c 'Power Restored; Shutdown Cancelled' 

The next group of lines instructs init to create several virtual text consoles (known as ttys), but only for the four multiuser runlevels. These tty consoles are the six text-based consoles that users can use in lieu of an X Window graphical interface; users can switch between them via the Alt-F1 through Alt-F6 key sequences. The ttys are defined to respawn, meaning that init will restart them when they exit. Once the user logs out, the tty exits, and init will start another in its place, which will display the login prompt again. Here are the lines defining the ttys:

 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 ... 6:2345:respawn:/sbin/mingetty tty6 

The last line in the file instructs init to start the prefdm graphical login program. The second column, however, restricts this behavior to runlevel 5, so it won't be invoked for any other runlevel. This is the line that causes the graphical KDE or GNOME login screen to appear after the system boots up. (Because this line occurs after the previous rc script line, it gets invoked after init has entered runlevel 5.)

 x:5:respawn:/etc/X11/prefdm -nodaemon 
Tip 

If you told Red Hat Linux to start the graphical login on startup but have since decided you don't like this (or vice versa), you can fix it by editing /etc/inittab and changing the "initdefault" default runlevel to 3 (to disable the graphical login) or 5 (to enable the graphical login).

All of this information can be brought together into a trace through a Red Hat system startup according to the following steps:

  1. The kernel boots and starts init, which then reads /etc/inittab.

  2. The /etc/inittab file instructs init to invoke /etc/rc.d/rc.sysinit; if that script completes successfully, init proceeds on to the next line. If that script returns an error (due to an error located on disk, for example), then init stops and enters single-user mode.

  3. Once rc.sysinit completes successfully, init checks the default runlevel (which is 5 in this example) and then invokes the script defined for that runlevel.

  4. The rc.sysinit script will start any services that are required by the runlevel. Once it completes, init registers the next few lines of the file, defining how it should react to various events, and then reaches the lines defining the ttys. If the runlevel is one of those defined by these lines (which it will be for any runlevel except single-user, halt, or reboot), init starts /sbin/mingetty on the ttys to let users log in, and then watches for them to exit.

  5. Finally, init does the same check against the last line, which determines whether it should start the "preferred desktop manager" program /etc/X11/prefdm (which in turn invokes either the KDE or GNOME graphical login programs if they are present).

At this point, the system is fully booted up and ready for use. A very similar sequence of events occurs if the root user instructs init to switch to a different runlevel; the only difference is that the rc.sysinit script will not be invoked, since it was defined to be invoked only once, on system startup. The only part of this sequence not yet described in detail is the behavior of the /etc/rc.d/rc script invoked when init enters a runlevel—this script is covered in the next section.

The Runlevel Configuration Script

Everything described in the previous section is automatic on a Red Hat Linux system. End users (and in the majority of cases, system administrators) generally don't need to modify any of the scripts invoked by init when it starts up. In fact, it's one of Red Hat's general design goals for the system: Users should be able to configure the system without having to edit scripts. By far, the most common customization users make to a system is simply changing which services are started for a given runlevel. This section describes the mechanism used to automate this in Red Hat Linux.

Recall that the /etc/inittab configuration file for Red Hat Linux uses the same shell script—/etc/rc.d/rc—to configure all runlevels. This shell script takes the runlevel number as its input and configures the services as appropriate for that runlevel. It accomplishes this by looking for files in the rc directory corresponding to the runlevel—/etc/rc.d/rc5.d in our example. This directory should contain files whose names match a certain pattern; the rc script uses this pattern to start and stop services as appropriate. The files themselves should be, but need not be, symbolic links to physical shell scripts in the /etc/rc.d/init.d directory. Table 4-8 summarizes the naming pattern.

Table 4-8: SysV Init Scripts File Naming Pattern

FORMAT

MEANING

EXAMPLE

KXXfoo

Stop service named "foo", in order XX

etc/rc.d/rc3.d/K87portmap: stops the portmap /service for runlevel 3

SYYbar

Start service named "bar", in order YY

/etc/rc.d/rc5.d/S55sshd: starts the sshd service for runlevel 5

Essentially, if a file name starts with "K", the corresponding service is "killed" (actually, shut down, not really killed) when init enters that runlevel. If the file name starts with "S", it is "started" whenever init enters that runlevel. After the "S" or "K" comes a two-digit number that has no meaning except to order the files with respect to each other, so that the user can control which order services get invoked in. The remainder of the file name is the service name.

The rc script /etc/rc.d/rc simply scans the appropriate directory for the new runlevel, stops any services whose file names start with "K", and starts any services whose file names start with "S". The file names are invoked as shell scripts and are passed either "stop" or "start" as input, depending on whether they are being killed or started, respectively. Thus, to function correctly, any shell scripts in an rc directory must be capable of interpreting these inputs. Actually, there are two more inputs as well: "status", which indicates whether the service is running, and "restart", which is shorthand for a "stop" followed by a "start." If you wish to add a new service to the system, all you need to do is place a shell script honoring these four inputs into the /etc/rc.d/init.d directory and then create symbolic links as appropriate in the other rc directories.

start sidebar
"Dropping in" New Configurations

The notion of configuring the system by placing files in a certain directory is worth a second look. It's one of Red Hat's most common techniques because it makes it easy to install software and connect it into the system.

RPM is the package format for Red Hat Linux, and this format can generally only install files in preordained locations. It quite frequently happens that two programs need to hook themselves into the startup framework to function correctly. Thus, there are two programs that need to modify the system configuration, and meanwhile the system administrator may already have modified the same file while installing a package that doesn't use RPM. It is extremely inconvenient when two separate programs "clobber" each other's changes by modifying the same file. You might be able to solve this problem with extensive use of "intelligent" text processing, but that is a good deal of work to implement, and since Red Hat doesn't write most of the software they ship, they can't enforce a universal use of a single centralized approach anyway.

The SysV init scripts model solves this problem by allowing each program (in this case, system service) to have its own separate configuration file that no other program would need to modify—the shell scripts in /etc/rc.d/init.d. The core framework scripts are untouched and can be managed by the system, and configuration occurs by simply "dropping in" a new configuration file for a new program.

Red Hat engineers took inspiration from this solution and have started using the technique in many other places. This can be considered a pretty successful best practice used fairly rigorously by Red Hat.

end sidebar

The next section presents an example of how to manually configure the services for a Red Hat Linux system.

Manually Configuring the System

At this point, you know enough to customize the list of services started up by your Red Hat Linux system. However, just to drive home the point, this section presents an example of how to hook a new service into the system. The example is based on the following characteristics of the hypothetical software that is being added to the system:

  • Represents a service (i.e., server or daemon) named "myservice" and installed in /usr/local/myservice

  • Includes a script obeying the start/stop/restart/status semantics

  • Runs only in the multiuser runlevels—2 through 5

  • Depends on the portmap service, so it must be started after that service

The first step is to copy the shell script from the installation into the /etc/rc.d/init.d directory. This is actually not required; you could create a symbolic link directly from the various rc directories straight to the installation directory in /usr/local/myservice. However, it is a good practice to have all your shell scripts in a single, centralized location. This becomes especially important if you need the service to be running in single-user mode, since single-user mode may not mount your /usr/local partition at all, depending on how it was installed.

Once the shell script is located in /etc/rc.d/init.d, it must be activated by creating symbolic links to it in the desired multiuser rc directories. Because you are activating the service for these runlevels, the symbolic link name must begin with "S"; thus, "S00myservice" might be a good first try. However, because myservice depends on the portmap service, it must be started afterward. Since portmap is S13portmap on Red Hat Linux 7.3, the link for myservice needs to be something like S15myservice. (Any number will work, as long as it's greater than portmap's 13.) A link of this name must be created for each multiuser runlevel. Listing 4-1 contains a simple bash shell script that can be used.

Listing 4-1: Creating Symbolic Links to Configure a Service

start example
 #!/bin/sh cd /etc/rc.d for i in 2 3 4 5; do    cd rc${i}.d/    ln -s ../init.d/myservice ./S15myservice    cd .. done 
end example

Next, equivalent "kill" links must be created in the rc directories for runlevels 0, 1, and 6. Because portmap is run as K87portmap, the "K value" for myservice must be less than 87 (for example, 85). This can be accomplished by simply modifying the script in Listing 4-1 to use 0, 1, and 6 instead of 2–5 and changing "S15myservice" to "K85myservice". Now the newly installed service will be properly started and stopped by runlevel. If you wish to manually start or stop the service once the system is running, you can do so as you would for any service— for instance, /etc/rc.d/init.d/myservice restart.

Sometimes you need to configure something that isn't a long-running server. In that case, it might be overkill or even inappropriate to treat it as a service and use the preceding approach. For example, you might need to simply run a program on startup that records the data and time, erases a file in /tmp, or so forth. There is a file where these changes can be placed: /etc/rc.d/rc.local. All runlevels invoke this script on startup, which by default sets up the /etc/issue file (whose content gets displayed as part of login prompts). You can add small "miniscripts" to this file if you like; however, be aware of the fact that this file is shared and suffers from the difficulties described in the previous section. Any changes you make to rc.local could potentially get clobbered by an upgrade or another program or user.

This whole "symbolic-link-to-shell-scripts" thing saves a lot of work, but it can still be a bit of a pain in practice. If you find yourself managing these services a lot, you will probably end up writing some shell scripts (similar to Listing 4-1) that automate much of the work. Red Hat engineers recognized this, as well, and included some small programs that make life quite a bit easier. The next section describes these utilities.

Using Red Hat's Tools

Red Hat ships the three following commands with its distribution:

  • /sbin/service

  • /sbin/chkconfig

  • /sbin/shutdown

These commands are targeted toward managing the configuration and usage of init and its scripts. These commands are niceties—the system can be managed without them, and they don't let users do anything they couldn't do already. For this reason, some of the more hard-core Unix hackers scoff at them. However, the beauty of these commands (and Unix systems in general) is that if you don't like them, you don't have to use them; the old-fashioned way works just as well. This section describes what these commands are and what they do.

/sbin/service

The /sbin/service command is included in the initscripts RPM, so it is available on every recent Red Hat Linux installation. This program is essentially a shorthand for manually starting and stopping the services in /etc/rc.d/init.d. Instead of typing /etc/rc.d/init.d/myservice start, for example, you can simply type service myservice start. In other words, service saves you from having to type /etc/rc.d/init.d. The command lets you perform all the standard actions—start, stop, restart, and status.

/sbin/chkconfig

The chkconfig command is included in its own RPM (chkconfig-1.2.22-1) and is installed in /sbin/chkconfig. This program manages the symbolic links in the rc directories; that is, it can manage which services are configured to run in which runlevels. It is essentially a full-featured version of the shell script in Listing 4-1 (except with a lot more sophistication), in that it creates and removes the symbolic links according to user input.

The chkconfig program also provides a way to automate the process of adding in a new shell script by placing a properly formatted comment in your shell script. The format is

 # chkconfig <runlevels> <S value> <K value> 

When run, chkconfig will scan these values and use them when constructing the symbolic links. The line for portmap, for example, is # chkconfig 345 13 87, which shows where the "magical" values of 13 and 87 come from for runlevels 3 through 5. To add in a new service with chkconfig support, you would simply create one of these lines with appropriate values for where in the script sequence your service needs to be run.

/sbin/shutdown

The /sbin/shutdown command is included in the SysVinit package. This program is used to instruct init to go to either runlevel 0, 1, or 6 (i.e., shut down, reboot, or go into single-user mode). Again, this command is really just a shortcut for something longer (such as wall "System is shutting down.";sync;sync;sync; init 0) but it is a convenience that is often overlooked by administrators who are used to dealing with other flavors of Unix.

If you've read this entire section on the init mechanism for Red Hat Linux, then you have taken a huge step toward bringing the system under your control.

After all, once you know how the system is configuring itself, you can use that as a starting point for finding out almost anything else. The rest of this chapter covers other aspects of Red Hat Linux in equivalent detail. Next up is the core system libraries.



 < Free Open Study > 



Tuning and Customizing a Linux System
Tuning and Customizing a Linux System
ISBN: 1893115275
EAN: 2147483647
Year: 2002
Pages: 159

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net