16.4. Boot Scripts

 <  Day Day Up  >  

During a system boot, shell scripts are run to perform tasks such as starting daemons and network services, starting database engines, mounting disks, and so on. They are also run during system shutdown. These scripts are known as boot scripts, startup and shutdown scripts, init scripts, or run control scripts, depending on which documentation you are reading and to whom you are talking. They are frequently called boot scripts , and that term will be used to refer to these scripts for the rest of the chapter. On almost all UNIX/Linux systems, the boot scripts are written in Bourne or Bash shells . A UNIX installation will come with a starter set of boot scripts so that administrators are not required to write the scripts themselves , but they should be able to debug and modify scripts when required.

For those familiar with the differences between System V and BSD-style UNIX systems, this section will focus on the System V-style boot scripts, mainly because they are the most commonly used.

16.4.1 A Little Terminology

Throughout this text, we have used the terms such as the kernel, init, processes, PIDs, deamons, and initialization scripts in relation to the shell. This section provides some further clarification of these terms as they relate to the boot-up process and the scripts that are started during system initialization.

The Kernel and init

When the system boots, the UNIX/Linux kernel is loaded from disk. It is the program that manages the operating system from boot-up to shutdown. Initially it initializes device drivers, starts the swapper , and mounts the root filesystem ( / ). The kernel then creates the first process, called init , the parent of all processes, with a PID (process identification number) number 1. When init starts, it reads from an initialization file called /etc/inittab . This file defines what processes to start during boot-up as well as during normal operation, supervises logins on serial ports, and defines run levels to determine what processes or groups of processes should be started.

What Is a Run Level?

A run level, also called a system state, determines which set of processes are currently available on a system. Usually there are eight run levels: 0 “6 and s or S. The run levels fit into three general categories: halted, single- user , and multiuser. In the halted system state, UNIX is not running ”it is halted. Moving to a halted state shuts down the system. Run level 0 is a halted state. On some versions of UNIX, notably Solaris, run level 5 is also a halted state and unlike run level 0, the machine is automatically powered off after UNIX is halted. The single-user run level is either S or 1. In single-user mode, the system console is opened, and only root is logged on. (See "Single-User Mode" on page 1033.) The multiuser run levels are 2 “5. The multiuser mode allows users to log into the system. The run level numbers for multiuser vary quite a bit from one version of UNIX/Linux to another. To complicate things even more, there may be more than one multiuser run level on a particular system. For example, under SuSE Linux, run levels 2 and 5 are both multiuser levels. Level 2 allows users to log in, but they will log into a text-only, single-screen session. Level 5 allows login, and additional processes are started including window managers such as KDE (the K Desktop Environment). As superuser, you can change to a different run level with the init (or telinit ) command. For example init 0 would move the system into run level 0, thus shutting it down.

The run level numbers can be frustrating since each vendor has a different definition of what the run levels will do. The only consistent values seem to be 0 for halted and 2 and 3 for multiuser. The who “r command lists the current run level. See Table 16.1.

Table 16.1. Run Levels

Run Level

What It Signifies

Solaris

S, s

Single-user mode. Filesystems required for basic system operation are mounted.

Halt.

1

System administrator mode. All local filesystems are mounted. Small set of essential system processes are running. Also a single-user mode.

2

Put the system in multiuser mode. All multiuser environment terminal processes and daemons are spawned.

3

Extend multiuser mode by making local resources available over the network.

4

Is available to be defined as an alternative multiuser environment configuration. It is not necessary for system operation and is usually not used.

5

Shut the machine down so that it is safe to remove the power. Have the machine remove power, if possible.

6

Reboot.

a, b, c

Process only those /etc/inittab entries having the a, b, or c run level set. These are pseudo-states, which may be defined to run certain commands, but which do not cause the current run level to change.

Q, q

Re-examine /etc/inittab .

HP-UX

System is completely shut down.

1, s, S

Single-user mode. All system services and daemons are terminated and all filesystems are unmounted.

2

Multiuser mode, except NFS is not enabled.

3, 4

Multiuser mode. NFS is enabled.

4

Multiuser mode with NFS and HP's desktop.

6

Reboot.

OpenBSD

“1

Permanently insecure mode ” always run system in level 0 mode.

Insecure mode ” All devices may be read or written subject to permissions.

1

Secure mode ” disks for mounted filesystems, /dev/mem , and /dev/kmem are read-only.

2

Highly secure mode ” same as secure mode, plus disks are always read-only whether mounted or not and the settimeofday system call can only advance the time.

Linux

Halt the system.

1

Single-user mode.

2, 3

Multiuser modes. Usually identical. Level 2 or 3 is default.

4

Unused.

5

Multiuser with graphical environment (X Windows).

6

Reboot the system.


Example 16.7.
 $  who -r   .    run-level  3  Mar 18 14:24    3        0  S  

EXPLANATION

The who “r command displays the current run level of the init process, which in this case is run level 3, multiuser mode (Solaris).

Single-User Mode

In the single-user states, UNIX is running, but users cannot log in. Either init 1 or init s will bring your system into a single-user state. The only interaction with the system is through a root-owned shell that is started automatically on a particular window or workstation. Single-user states are for maintenance and not all system processes will be started. For example, networking and database processes will usually not be running. Generally, the system administrator will change the machine to a single-user state to fix a serious software problem, install software, or perform any other task where logged in users might see a partially functioning system (and be confused ) or might interfere with system performance (e.g., you don't want users to access files while you're trying to upgrade the operating system).

Boot Scripts

Each of the run levels defined on a system should contain a directory of scripts that are run for a particular run level. These scripts manage such services as mail , cron , network services, lpd , and more. The directory name reflects the run level: The rc5.d directory contains scripts for run level 5, the rc3.d directory contains scripts for run level 3, and so on. These directories are located in different places depending upon your UNIX/Linux version. For example, the scripts for run level 3 are usually stored in one of the following directories: /etc/rc3.d , /sbin/rc3.d , /etc/init.d/rc3.d , or /etc/rc.d/rc3.d . Once you find the correct directory, almost all versions of UNIX/Linux use the same general scheme for the names of the scripts within those directories. The script names start with one of the letters S or K, followed by a number, and then a name describing what the script does. The scripts take an argument of either start or stop . A start argument asks the script to start services; a stop argument asks it to shut down services. If a script name starts with an S, that script will be run with a start argument. If the script name starts with a K, the script is run with a stop argument. The K scripts are useful when the system is brought to a lower run level, stopping processes, as the machine is brought down. The scripts are run in the order they are listed with the ls command.

Example 16.8.
 $  cd rc3.d  $  ls   README          S34dhcp      S77dmi        S89sshd       s15nfs.server   S13kdc.master   S50apache    S80mipagent   S90samba      s99idled   S14kdc          S52imq       S81volmgt     S99fixkde   S16boot.server  S76snmpdx    S84appserv    S99snpslmd  

EXPLANATION

This example was taken from a system running Solaris 5.9. The contents of the rc3.d directory (run level 3) are displayed. Check the documentation on your system.

Example 16.9.
 $  cd rc3.d  $  ls   K001inuxconf   K25squid      K55routed   K92iptables     S55sshd   K03rhusd       K28ams        K61dap      K95kudzu        S56rawdevices   K05anacron     K30mcserv     K65identd   K95reconfig ig  S56xinetd   K05innd        K30sendmail   K65kadmin   K96irda         S60lpd   <not all output is shown>  

EXPLANATION

This example was taken from a system running Red Hat Linux. The partial contents of the rc3.d directory (run level 3) are displayed. Check the documentation on your system.

What Is a Daemon?

A daemon [1] is a process that runs in the background and performs one or more tasks on a user's behalf . For example, the printer daemon, lpsched , sends files one at a time to a printer. If the lpsched daemon is not running on systems that use it for printing, then files will not be sent to the printer. A Web server, such as Apache, is a daemon; it stays dormant until it is asked for a Web page. The cron (called crond on some systems) program is also a daemon. It checks the cron instruction files (called crontab files) once a minute to see if it is time to run any commands specified there. When the correct time comes, the cron daemon automatically runs the program specified in the crontab file. For a complete discussion on the cron utility, see "An Example Boot Script ”The cron Utility," below. Many daemon programs, such as cron , are started during the boot process and run the whole time the system is booted . Other daemons, such as telnet , are under the control of a master daemon and are only started when they are needed (the master daemon does need to run all the time).

[1] The term comes from Greek mythology, where daemons were guardian spirits, not to be confused with a demon, associated with a devil .

16.4.2 An Example Boot Script ”The cron Utility

In this section, we will look at a sample boot script from Red Hat Linux. This script starts the cron daemon during the system boot. The script can also be run manually to control the daemon. The cron boot script is a good example because it is relatively easy to understand and the cron program exists on virtually every UNIX version. Before we look at the boot script for cron , it's helpful to know what cron does. The cron utility allows root and other users to schedule system commands, shell scripts, programs, and more to run at preset times. The user does not need to be present to interact with the system; cron will run commands from the user's crontab file, a file that contains a table specifying a list of commands and specified dates and times when the commands should be executed. The following example shows that the Solaris cron daemon is running as root .

Example 16.10.
 $  ps -ef  grep cron  grep -v grep   root   202     1  0   Mar 18 ?        0:03 /usr/sbin/cron  

Red Hat Linux starts the crond daemon at boot-up.

 $  ps aux   grep cron  grep -v grep   root    436 0.0  0.5 1552  700   ?     S  06:13  0:0   crond  

Creating a cron Instruction File ( crontab File)

The cron daemon reads the crontab files that have been submitted by system users. Each line in the crontab file consists of six fields separated by spaces. The first five fields tell the cron daemon when to run the command that is contained in the sixth field. The values in the first five fields are: minutes (00 “59), hours of the day (00 “23), day of the month (1 “31) and months of the year (1 “12), and weekday (0 “6). The sixth field is the command that will be executed at the time specified in the first five fields. See Table 16.2.

Table 16.2. Crontab Field Values

Field

Values

minute

00 to 59

hour

00 to 23

day

1 to 31

month

1 to 12

weekday

0 to 6, where 0 = Sunday (Linux uses sun , mon , etc.)


The first five fields can also use any one of the following formats.

  • An asterisk ( * ) matches all values for that field.

  • A single integer matches that exact value.

  • A comma-separated list of integers (e.g., 1,3,5 ) to match one of the listed values. A range of integers separated by a dash (e.g., 4 “6 ) matches values within the range.

The sample below shows a crontab file submitted to cron using the crontab command.

Example 16.11.
 1  #   crontab -l > instructions  2  #   vi instructions  .     (There might or might not be lines at the top of this file.      You can ignore any lines except the one added below.) 3  25 1 * * * /root/checkpercent  4  #   crontab instructions  5  #   crontab -l  .     (There may not be lines above the entry that was added in item 3.)     .  25 1 * * * /root/checkpercent  

EXPLANATION

  1. The output of the crontab “l command is redirected to the file named instructions . In this example, because there were not any commands listed in the crontab file, the instructions file will contain only some comments generated by the crontab command.

  2. The instructions file is edited using vi . This file may or may not contain any lines to start. It depends on your version of UNIX/Linux and whether or not root has previously entered instructions for cron .

  3. A new instruction is added to the bottom of the file. This instruction tells cron to run the /root/checkpercent script at 1:25 a.m., every day of every month. Detailed information on specifying the time in this file (the time is indicated by the numbers and asterisks at the beginning of the line) can be found in the crontab man page.

  4. The crontab command is used to submit the instructions file to cron .

  5. The crontab “l command causes cron to display the current set of instructions for the current user, in this case the root user. This verifies that cron has accepted the file from the previous command.

The cron Boot Script

Before we look at the contents of the cron boot script, let's look at the layout of boot scripts in general. The following example displays a partial list of boot scripts for run level 5 on a Red Hat system. Although most other UNIX versions have a similar layout for their boot scripts, some, such as Darwin in Mac OS X, are quite different.

Below is a truncated listing of the directory containing the boot scripts for run level 5 under Red Hat Linux.

Example 16.12.
 1  #   pwd   /etc/rc5.d  2  #   ls   .      K20nfs     K45named      S55sshd       S90crond   ..     K35smb     S12syslog     S80sendmail  3  #   ls -l /etc/rc5.d/*cron*   lrwxrwxrwx 1 root 15   Oct 13 21:19 /etc/rc5.d/   S   90crond ->   ../init.d/crond  4  #   ls -l /etc/init.d/cron*   -rwxr-xr-x 1 root 1316 Feb 19 2004 /etc/init.d/crond  

EXPLANATION

  1. The current directory is /etc/rc5.d , the boot script directory for run level 5 (Red Hat Linux).

  2. The listing shows that some script names begin with S and some begin with K.

  3. This script starts the cron daemon because the filename starts with an S. If the script name had started with a K, the script would stop the cron daemon. The output shows that the file is actually a link ”the letter l in front of the file permissions indicates a link. The “> characters point to the linked file, crond , located in the /etc/init.d directory.

  4. Each script in the run-level directory is normally a link to a master copy in the /etc/init.d directory.

  5. This is a listing for the master copy of the boot script for cron . Notice that the master copies don't start with S or K and don't contain numbers in their names. There are frequently multiple links to the master scripts from the boot directories, and only the link names will contain numbers. This master script can be used to either start or stop the cron daemon. We'll look at the script in detail in the next section.

The cron boot script, called crond , can be run manually to start or stop the cron daemon. On some releases, it can also be used to check the status or restart cron . Other releases allow additional arguments. Traditionally, boot scripts are run by preceding the script name with the shell for which the script was written, followed by the name of the script. The examples below run the master copy of the crond script from the /etc/init.d directory. Because they are linked, you could accomplish the same thing by running the /etc/rc5.d/crond script instead.

Example 16.13.
 1   #  cd /etc/init.d  2   #  ls crond   crond  3   #  sh crond stop   Stopping crond:   [OK]  4   #  sh crond start   Starting crond:   [OK]  5   #  sh crond restart   Stopping crond:   [OK]   Starting crond:   [OK]  

EXPLANATION

  1. The cd command is used to change to the /etc/init.d directory, which contains the master copies of the boot scripts.

  2. The ls command verifies that the cron boot script exists.

  3. The crond script is run with the stop argument to stop the cron daemon. The script is run by preceding the script name with the shell for which it was written because root is the current user.

  4. The script is run again, this time starting the cron daemon.

  5. The script is run a third time. This time the daemon will be stopped , then started again.

Below is a simplified version of the boot script for the cron daemon from Red Hat Linux. This script sources another script called functions , which defines daemon and killproc for the script. The daemon function takes a daemon name as an argument. It attempts to start that daemon and will return a success or failure code depending on what happened .

Example 16.14.
 #! /bin/bash  # crond Start/Stop the cron clock daemon.   #   # chkconfig: 2345 90 60   # description: cron is a standard UNIX program that runs   # user-specified programs at periodic scheduled times.   # config: /etc/crontab   # pidfile: /var/run/crond.pid   # Source function library.  1   . /etc/init.d/functions 2   RETVAL=0 ; prog="crond" 3   start() { 4       echo -n $"Starting $prog: " 5       daemon crond 6       RETVAL=$? 7       echo 8       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/crond 9       return RETVAL     } 10  stop() { 11      echo -n $"Stopping $prog: " 12      killproc crond 13      RETVAL=$? 14      echo 15      [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/crond         return RETVAL     } 16  restart() {  stop ; start } 17  case "" in 18      start)   start           ;; 19      stop)    stop            ;; 20      restart) restart         ;; 21      *)       echo $"Usage: 
 #! /bin/bash  # crond Start/Stop the cron clock daemon.   #   # chkconfig: 2345 90 60   # description: cron is a standard UNIX program that runs   # user-specified programs at periodic scheduled times.   # config: /etc/crontab   # pidfile: /var/run/crond.pid   # Source function library.  1 . /etc/init.d/functions 2 RETVAL=0 ; prog="crond" 3 start() { 4 echo -n $"Starting $prog: " 5 daemon crond 6 RETVAL=$? 7 echo 8 [ $RETVAL -eq 0 ] && touch /var/lock/subsys/crond 9 return RETVAL } 10 stop() { 11 echo -n $"Stopping $prog: " 12 killproc crond 13 RETVAL=$? 14 echo 15 [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/crond return RETVAL } 16 restart() { stop ; start } 17 case "$1" in 18 start) start ;; 19 stop) stop ;; 20 restart) restart ;; 21 *) echo $"Usage: $0 {startstoprestart}" exit 1 ;; esac 
{startstoprestart}" exit 1 ;; esac

EXPLANATION

  1. A script called functions is sourced to make functions defined there available to this script.

  2. The RETVAL variable (which holds the function return value) is initialized to and the prog variable is initialized to crond .

  3. This line begins the definition for the start() function.

  4. A message is displayed saying that the cron daemon is starting.

  5. The daemon function is called with crond as its argument. (The function was defined in the functions script sourced at the beginning of the script.) The function attempts to start the crond daemon and returns a value of success (0) or failure (1).

  6. The RETVAL variable is assigned the value of the status variable ? . It contains the value returned by the daemon() function. This value is used by the operating system to print an OK or FAILED message to the screen during the boot process.

  7. The echo command prints a blank line to the screen.

  8. If the return value indicates success (0 mean success) then a lock file for the cron daemon, /var/lock/subsys/crond , is created with the touch command.

  9. The RETVAL variable is returned from the function.

  10. This line begins the definition for the stop() function.

  11. A message is displayed saying that the cron daemon is being stopped.

  12. This calls the killproc() function, which is defined in the functions script sourced on line 1. It sends an argument of crond to this function. The function attempts to stop the daemon process and sends a return value based on its success or failure.

  13. The RETVAL variable is assigned the value returned by the killproc() function, which is stored in $? .

  14. A blank line is printed.

  15. If the return value indicates success, the lock file for the cron daemon, /var/lock/ subsys/crond , is deleted.

  16. This defines the restart() function, which stops then starts the cron daemon.

  17. The case command evaluates $1 and holds the value of the first argument sent to this script, either start or stop .

  18. If the value of $1 is start , then the start() function is run.

  19. If the value of $1 is stop , then the stop() function is run.

  20. If the value of $1 is restart , then the restart() function is run.

  21. Otherwise, a usage message is printed and the script will exit with status 1, failure.

16.4.3 Writing a Portable Script

System administrators often write shell scripts that work on multiple UNIX versions. Because commands change from UNIX to UNIX, your script will need to determine the UNIX version on which it is being run. This can be done using the uname command. Listed below are some popular versions of UNIX and the output of the uname command from each version. To create a script that will port to these different UNIX versions, your script should check the uname output and modify commands accordingly .

UNIX Version:

uname Output:

AIX

AIX

FreeBSD

FreeBSD

HP-UX

HP-UX

IRIX

IRIX

Linux

Linux

Mac OS X

Darwin

NetBSD

NetBSD

OpenBSD

OpenBSD

SCO OpenServer

5 SCO_SV

Solaris

SunOS


A case command is commonly used to check for the operating system you are using. Example 16.15 checks for Linux (any brand), HP-UX, Solaris, FreeBSD, and Mac OS X UNIX.

Example 16.15.
 1   uname_out=`uname` 2   case "$uname_out" in 3   HP-UX)  echo "You are running HP-UX"         ;; 4   SunOS) echo "You are running Solaris"         ;;     FreeBSD) echo "You are running FreeBSD"         ;;     Linux) echo "You are running Linux"         ;;     Darwin) echo "You are running Mac OS X"         ;; 5       *)  echo "Sorry, $uname_out UNIX "             echo "is not supported by this script"         ;; 6   esac 

EXPLANATION

  1. The variable uname_out is assigned the output of the uname command. This assigns the name of the current version of UNIX to the variable.

  2. The case statement will evaluate the uname_out variable.

  3. If the uname_out variable evaluates to HP-UX, this is Hewlett-Packard's version of UNIX and You are running HP-UX will be printed.

  4. If uname_out evaluates to SunOS, the message is printed. The case statement checks for other versions of UNIX in subsequent statements.

  5. If uname_out contains a value not listed in the above choices, then it will match the default pattern, an asterisk. In this case, a generic message is printed telling the user that the operating system is not supported by this script.

  6. The case statement is ended using the esac statement.

Example 16.16 is a sample script to tell the administrator when any of a machine's filesystems are getting full. This script does not check for all versions of UNIX, although you can modify the script for any version of UNIX. The sample script changes the form of the df command to accommodate four types of UNIX.

Example 16.16.
 #  cat /root/checkpercent  1   #! /bin/sh 2   rm $HOME/df_output $HOME/message 2> /dev/null 3   uname_out=`uname` 4   case "$uname_out" in 5       HP-UX) 6           bdf  awk  '{print ,}'  awk -F% '>90 {print 
 #  cat /root/checkpercent  1 #! /bin/sh 2 rm $HOME/df_output $HOME/message 2> /dev/null 3 uname_out=`uname` 4 case "$uname_out" in 5 HP-UX) 6 bdf  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 7 SunOS) 8 df -k  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 9 Linux) 10 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 11 Darwin) 12 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 13 *) echo "Sorry, $uname_out UNIX not supported by this script" ;; esac 14 if [ -s $HOME/df_output ] then 15 echo "** WARNING **" > $HOME/message echo "The following file systems are filling up." >> $HOME/message echo "You may want to look into the situation." >> $HOME/message cat $HOME/df_output >> $HOME/message 16 cat $HOME/message 17 echo "This warning message is stored in the file $HOME/message" echo "You should create a copy of the file now if you would" echo "like to save this message." fi 18 rm $HOME/df_output 
}' \ > $HOME/df_output ;; 7 SunOS) 8 df -k awk '{print ,}' awk -F% '>90 {print
 #  cat /root/checkpercent  1 #! /bin/sh 2 rm $HOME/df_output $HOME/message 2> /dev/null 3 uname_out=`uname` 4 case "$uname_out" in 5 HP-UX) 6 bdf  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 7 SunOS) 8 df -k  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 9 Linux) 10 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 11 Darwin) 12 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 13 *) echo "Sorry, $uname_out UNIX not supported by this script" ;; esac 14 if [ -s $HOME/df_output ] then 15 echo "** WARNING **" > $HOME/message echo "The following file systems are filling up." >> $HOME/message echo "You may want to look into the situation." >> $HOME/message cat $HOME/df_output >> $HOME/message 16 cat $HOME/message 17 echo "This warning message is stored in the file $HOME/message" echo "You should create a copy of the file now if you would" echo "like to save this message." fi 18 rm $HOME/df_output 
}' \ > $HOME/df_output ;; 9 Linux) 10 df awk '{print ,}' awk -F% '>90 {print
 #  cat /root/checkpercent  1 #! /bin/sh 2 rm $HOME/df_output $HOME/message 2> /dev/null 3 uname_out=`uname` 4 case "$uname_out" in 5 HP-UX) 6 bdf  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 7 SunOS) 8 df -k  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 9 Linux) 10 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 11 Darwin) 12 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 13 *) echo "Sorry, $uname_out UNIX not supported by this script" ;; esac 14 if [ -s $HOME/df_output ] then 15 echo "** WARNING **" > $HOME/message echo "The following file systems are filling up." >> $HOME/message echo "You may want to look into the situation." >> $HOME/message cat $HOME/df_output >> $HOME/message 16 cat $HOME/message 17 echo "This warning message is stored in the file $HOME/message" echo "You should create a copy of the file now if you would" echo "like to save this message." fi 18 rm $HOME/df_output 
}' \ > $HOME/df_output ;; 11 Darwin) 12 df awk '{print ,}' awk -F% '>90 {print
 #  cat /root/checkpercent  1 #! /bin/sh 2 rm $HOME/df_output $HOME/message 2> /dev/null 3 uname_out=`uname` 4 case "$uname_out" in 5 HP-UX) 6 bdf  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 7 SunOS) 8 df -k  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 9 Linux) 10 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 11 Darwin) 12 df  awk '{print $5,$6}'  awk -F% '$1>90 {print $0}' \ > $HOME/df_output ;; 13 *) echo "Sorry, $uname_out UNIX not supported by this script" ;; esac 14 if [ -s $HOME/df_output ] then 15 echo "** WARNING **" > $HOME/message echo "The following file systems are filling up." >> $HOME/message echo "You may want to look into the situation." >> $HOME/message cat $HOME/df_output >> $HOME/message 16 cat $HOME/message 17 echo "This warning message is stored in the file $HOME/message" echo "You should create a copy of the file now if you would" echo "like to save this message." fi 18 rm $HOME/df_output 
}' \ > $HOME/df_output ;; 13 *) echo "Sorry, $uname_out UNIX not supported by this script" ;; esac 14 if [ -s $HOME/df_output ] then 15 echo "** WARNING **" > $HOME/message echo "The following file systems are filling up." >> $HOME/message echo "You may want to look into the situation." >> $HOME/message cat $HOME/df_output >> $HOME/message 16 cat $HOME/message 17 echo "This warning message is stored in the file $HOME/message" echo "You should create a copy of the file now if you would" echo "like to save this message." fi 18 rm $HOME/df_output

EXPLANATION

  1. The shell name is /bin/sh . On some systems, /bin/sh is Bourne, on others it is bash , or the POSIX shell ”all of these shells are compatible with the Bourne shell. To make sure this is a portable script, use Bourne shell syntax.

  2. This command will remove the $HOME/df_output and $HOME/message files if they exist. Any error messages generated by this command are discarded by redirecting them to the /dev/null file. Removing the files is a precaution ”if either of these files exist, they might cause a problem with this script. Remember that $HOME is a variable that stores a user's home directory, so $HOME/message indicates a file called message in the home directory of the person running the script. $HOME/df_output indicates a file called df_output in the user's home directory.

  3. The output of the uname command is assigned to a variable called uname_out . As in the previous example, note that this command is using backward single quotes (backquotes) and not regular single quotes.

  4. This case statement evaluates the variable, uname_out , which contains the name of the operating system.

  5. If the variable evaluates to HP-UX , the case statement on line 6 is executed.

  6. The HP-UX version of the df command, bdf , is run. The output of the bdf command is piped through awk to select fields 5 and 6, which are the percent full and the filesystem name. These two values are then piped through a second awk , which will print lines that have a percent full of greater than 90. (The $0 prints the whole line as long as the first field is greater than 90.) The output is then stored in the $HOME/df_output file.

  7. If this is a Sun system . . .

  8. . . . then run the Solaris version of the df command, df “k . The rest of the command is the same as the HP-UX version.

  9. If this is a Linux system . . .

  10. . . . then the plain df command is run for Linux. The rest of the command is the same as the HP-UX version.

  11. If this is an OS X system . . .

  12. . . . the df command is run. Notice that this is the same command used for Linux. These two could be combined into one case statement.

  13. If the variable uname_out contains any other value, the error message shown is printed.

  14. This if statement checks to see if the file $HOME/df_output contains any text. This true/false test results in a true value if the file $HOME/df_output contains any text and a false value if the file is empty or does not exist. If the $HOME/df_output file does exist . . .

  15. . . . then a message is generated and stored in the $HOME/message file. The three echo commands print a warning message and then the $HOME/df_output file is appended to the $HOME/message file.

  16. The contents of the $HOME/message file are displayed. This will display the warning message with a list of full filesystems.

  17. The script prints a reminder that the information is in the $HOME/message file.

  18. The $HOME/df_output is removed because it is no longer needed.

16.4.4 User-Specific Initialization Files

When user accounts are initially created, the administrator normally places login files, such as .profile and .login , in the user's home directory. The administrator must understand the syntax of the shells in order to write a version of these files that will be suitable for their users.

Each shell has one or more initialization files that can be placed in a user's home directory. As administrator, you may wish to place a starter copy of these initialization files in your user's home directory when it is first created. Most versions of UNIX help you automate this process through the /etc/skel directory, although sometimes the directory name is slightly different. When creating a new account using the useradd command, all files from /etc/skel are copied to a user's home directory.

Example 16.17.
 1  #   ls -a /etc/skel   . .. .profile .cshrc  2  #   useradd -m newguy1  3  #   ls -a /home/newguy1   . .. .profile .cshrc  4  #   useradd newguy2  5  #   ls -a /home/newguy2   ls: /home/newguy2: No such file or directory  

EXPLANATION

  1. This particular /etc/skel directory contains the two files, .profile and .cshrc .

  2. The “m option tells useradd to create the home directory for the new account. By default the directory will be /home/newguy1 . The useradd program automatically copies the files from /etc/skel . Both .profile and .cshrc will be copied to /home/newguy1 .

  3. The ls command verifies that the /home/newguy1 directory contains the .profile and .cshrc files.

  4. Without the “m option, the useradd command does not create a home directory for this account. The /etc/skel files are not copied.

  5. The ls command shows that newguy2 does not have a home directory.

Possible Files for /etc/skel

You should put a set of starter initialization files in the home directory of a new user when you create his or her home directory. A chart of the initialization files used by the five major UNIX shells is listed in Table 16.3. You might want to create a generic version of all of these files and place them in the /etc/skel directory. These files will be copied into a user's home directory whenever a new account is created, giving the user a starter copy of the initialization files needed for his or her login shell. See the other chapters for individual shells for more details on the initialization files.

Table 16.3. Initialization Files Used by the Five Shells
 

Bourne

Bash

Korn

C

TC

.profile

   

. kshrc

   

   

.bash_profile

 

     

.bash_login

 

     

.bashrc

 

     

.bash_logout

 

     

.login

     

.cshrc

     

.tcshrc

       

.logout

     


16.4.5 System-Wide Initialization Files

The system administrator is responsible for maintaining a set of system-wide initialization files used by various login shells. The administrator will often perform tasks such as setting an initial value for the PATH and MANPATH variables in these files. For a login shell, /etc/profile is the system-wide intialization file for the Bourne, Korn, and Bash shells and /etc/.cshrc or /etc/csh.login are system-wide initialization files for the C and TC shells (filenames vary on different systems). See Table 16.4. Most UNIX installations come with a starter set of these files that can be customized for a particular system.

Table 16.4. System-Wide Initialization Files

Shell

Filename

Versions Implemented On

Notes

/bin/sh

/etc/profile

Most versions

Run at login only.

 

/etc/profile.local

SuSE Linux

Run at login only in addition to /etc/profile . Used for local settings. The SuSE /etc/profile contains a comment asking you not to modify /etc/profile , but instead to modify /etc/profile.local .

 

/etc/login.conf

FreeBSD

Run at login only.

/bin/ksh

/etc/profile

Most versions

Run at login only.

 

/etc/profile.local

SuSE Linux

Run at login only in addition to /etc/profile . Used for local settings. The SuSE /etc/profile contains a comment asking you not to modify /etc/profile , but instead to modify /etc/profile .local.

/bin/bash

/etc/profile

Most versions

Run at login only.

 

/etc/profile.local

SuSE Linux

Run at login only in addition to /etc/profile . Used for local settings. The SuSE /etc/profile contains a comment asking you not to modify /etc/profile , but instead to modify /etc/profile.local .

 

/etc/bash.bashrc

SuSE Linux

Run each shell invocation.

 

/etc/bashrc

Some versions of Linux

Run when bash is started manually. If this script isn't run automatically by your UNIX version, you can call it from the user's local .bashrc file. See "/etc/bashrc" on page 1049 for details on how to do this.

/bin/csh

/etc/csh.login

Linux, FreeBSD, HP-UX,

Same for tcsh .

   

OS X

Run at login only.

 

/etc/.login

Solaris

Run at login only.

 

/etc/csh.cshrc

Linux, FreeBSD, OS X

Run for each shell invocation.

 

/etc/.cshrc

Solaris

Run by tcsh , but not by csh , each time a tcsh is run.


In addition to the system initialization files, the local initialization files are also run when a user logs in. If, for example, a user logs into the TC shell on a Red Hat system, the files listed below will be sourced in the order listed. The first two files are system files and the last two files are local files. The value of the HOME environment variable is the path of the user's home directory.

 /etc/csh.cshrc /etc/csh.login $HOME/.tcshrc $HOME/.login 

/etc/profile

The /etc/profile file contains commands that are automatically run when a user logs into a system using the Bourne, Bash, or Korn shell. A starter copy of /etc/profile will be provided during the installation process. This file is normally modified by the system administrator to accomodate the needs of a particular system.

Example 16.18.
  #   cat /etc/profile   # System-wide environment and startup programs, for login setup   # Functions and aliases go in /etc/bashrc  1   pathmunge () { 2       if ! echo $PATH  /bin/egrep -q "(^:)($:)" ; then 3           if [ "" = "after" ] ; then 4              PATH=$PATH:             else 5              PATH=:$PATH             fi         fi 6   }  # Path manipulation  7   if [ `id -u` = 0 ]; then 8       pathmunge /sbin 9       pathmunge /usr/sbin 10      pathmunge /usr/local/sbin         fi 11  pathmunge /usr/X11R6/bin after 12  unset pathmunge  # No core files by default  13  ulimit -S -c 0 > /dev/null 2>&1 14  USER="`id -un`" 15  LOGNAME=$USER 16  MAIL="/var/spool/mail/$USER" 17  HOSTNAME=`/bin/hostname` 18  HISTSIZE=1000 19  if [ -z "$INPUTRC" -a ! -f "$HOME/.inputrc" ]; then         INPUTRC=/etc/inputrc     fi 20  export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC 21  for i in /etc/profile.d/*.sh ; do 22      if [ -r "$i" ]; then 23          . $i         fi     done     unset i 

EXPLANATION

  1. Starts the definition for the function called pathmunge() . This function takes a directory name as an argument. Its purpose is to prepend the directory, given as an argument, to the PATH variable. The function can optionally take a second argument of after , which will append the directory to the PATH . Note that the function definition simply places the code for pathmunge() into memory; the function will not be activated until it is called.

  2. Checks to see if the directory to be added is already in the user's PATH .

  3. Checks to see if the optional argument after was included in the function call.

  4. Adds the directory (the first argument to the pathmunge function) to the beginning of the PATH . This line is only executed if the optional argument after was not included in the function call.

  5. Adds the directory (the first argument to the pathmunge function) to the end of the PATH . This line is only executed if the optional argument after was included in the function call.

  6. Ends the pathmunge definition.

  7. If the user's UID equals 0 (in other words, if he or she is a superuser), then . . .

  8. . . . calls the pathmunge() function, which adds the /sbin directory to the PATH .

  9. Adds the /usr/sbin directory to the PATH .

  10. Adds the /usr/local/sbin directory to the PATH .

  11. Adds the /usr/X11R6/bin directory to the end of the PATH . Because this line is not inside the if statement, it will always be executed.

  12. Removes the pathmunge() function definition from memory.

  13. Sets the maximum coredump size to 0 ”this effectively stops the user from generating coredump files.

  14. Sets the USER variable to the user's login name.

  15. Sets the LOGNAME variable to the same value as USER .

  16. Sets the MAIL variable to the user's incoming mailbox file.

  17. Sets the HOSTNAME variable to this system's hostname.

  18. Sets the history list size to a maximum of 1,000 commands.

  19. If the INPUTRC variable has no value and $HOME/.inputrc does not exist, then sets the INPUTRC variable to /etc/inputrc .

  20. Exports all variables set in this script.

  21. This for loop will cycle through all the files in the /etc/profile.d directory.

  22. If the user has read permission on the file currently being processed by the for loop . . .

  23. . . . then source the file.

/etc/bashrc

The /etc/bashrc file is used on some UNIX releases, such as Red Hat Linux, to run bash commands whenever a bash shell is run. This file should contain settings that are not passed automatically to child processes, such as command aliases.

Example 16.19.
 1   $  cat /etc/bashrc  2   alias ls="ls -F" 3   alias grep="grep -i" 

EXPLANATION

  1. The contents of the /etc/bashrc file are displayed.

  2. An alias for the ls command is defined as ls “F . When ls is typed, ls “F will be executed, modifying the display of ls .

  3. An alias for the grep command is defined as grep “i . When the grep command is used, it will be case insensitive.

If you wish to use /etc/bashrc and your UNIX doesn't source it automatically, you can include it in the user's personal .bashrc file in his or her home directory.

Example 16.20.
 1   $  cat .bashrc  2   if [ -f /etc/bashrc ]         then 3       . /etc/bashrc     fi 4   alias dir=ls 

EXPLANATION

  1. The .bashrc file, found in the user's home directory, is sourced.

  2. If the /etc/bashrc file exists and is a regular file, then go to line 3. Some machines run /etc/bashrc automatically; on those machines this if statement will not be required.

  3. The dot command sources the /etc/bashrc file (runs the commands from the file in context of the current shell process; i.e., does not create a child process).

  4. An alias for the dir command is defined. Notice that this is a personal alias created by the user in his .bashrc file.

/etc/csh.login

The /etc/csh.login file is sourced by the C and TC shells during the login process. Example 16.21 is an /etc/csh.login file from a Red Hat Linux system. Like the .login file, this file is run at login time by the login shell, and not by any child shells spawned thereafter. It is used to set environment variables for the shell and any other commands that will be executed by the login shell.

Example 16.21.
  #   cat /etc/csh.login   # System-wide environment and startup programs, for login setup  1   if ($?PATH) then 2       setenv PATH "${PATH}:/usr/X11R6/bin"     else 3       setenv PATH "/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin"     endif 4   limit coredumpsize unlimited 5   setenv HOSTNAME `/bin/hostname` 6   set history=1000 7   if ( -f $HOME/.inputrc ) then 8       setenv INPUTRC /etc/inputrc     endif 9   if ( $?tcsh ) then 10      bindkey "^[[3~" delete-char     endif 

EXPLANATION

  1. If the PATH variable has been set, the ? evaluates to true.

  2. /usr/X11R6/bin is added to the PATH environment variable.

  3. Otherwise, the PATH is assigned an initial value of /bin:/usr/bin:/usr/local/bin:/ usr/X11R6/bin .

  4. The limit command restricts an upper limit on the size of a coredump.

  5. The HOSTNAME variable is assigned the output of the hostname command, the system's hostname.

  6. The history list size is set to a maximum of 1,000 commands.

  7. The .inputrc file sets editing modes, key bindings, and so forth for the Readline library. This line checks to see if $HOME/.inputrc exists.

  8. If $HOME/.inputrc does exist, then set the INPUTRC variable to /etc/inputrc .

  9. If tcsh is the current shell, ? will return true, and line 10 will be executed.

  10. The bindkey command sets an escape sequence for the Delete key used in command-line editing.

/etc/csh.cshrc

The /etc/csh.cshrc file is sourced by the C and TC shells whenever they are run. C and TC shells can be started at login time (if it has been specified as a user's login shell) when running a C or TC shell script, or when opening a shell window that runs the C or TC shell. The example /etc/csh.cshrc file given below is from a Red Hat Linux system. The /etc/csh.cshrc file should include items that are not exported to child processes, such as setting a umask or setting the prompt. Note that in the C and TC shell the prompt variable is local, which means it will not be passed to child processes.

Example 16.22.
 #  cat /etc/csh.cshrc  1   umask 022 2   if ($?prompt) then 3       if ($?tcsh) then 4           set prompt='[%n@%m %c]$ '         else 5           set prompt=\[`id -nu`@`hostname -s`\]$\         endif     endif 6   if ( -d /etc/profile.d ) then 7       set nonomatch 8       foreach i ( /etc/profile.d/*.csh ) 9           if ( -r $i ) then 10             source $i             endif         end 11      unset i nonomatch     endif 

EXPLANATION

  1. Sets the umask to 022, which will block write permissions from being set on permissions for the group and others on newly created files.

  2. The ? is used to check if the prompt variable has a value. If it does, then this is an interactive shell.

  3. The ? is used to see if the tcsh variable has a value. This variable is set only if we are in the tcsh ; it is not set in the C shell.

  4. If this is a TC shell, then the prompt is set to the username ( %n ), followed by an @ symbol, followed by the host name ( %h ), followed by the current directory ( %c ).

  5. If this is a C shell, then the prompt is set to the username (the output of the id “nu command), followed by an @ symbol, followed by the hostname (the output of the hostname “s command), followed by a dollar sign.

  6. If the /etc/profile.d directory exists, then go to line 7.

  7. The nonomatch is set to suppress any error messages produced if a shell wildcard doesn't match a filename. This setting is in effect until the unset command is run.

  8. This foreach loop will cycle through any files in the /etc/profile.d directory whose name ends in .csh , assigning each name, in turn , to the variable i . Notice that if *.csh does not match any of the filenames in the /etc/profile.d directory, an error message, No match , would normally be displayed. Because of the nonomatch setting, this will not happen.

  9. If the user running this script has read permission on the file, whose name is currently stored in the variable i , then go to line 10.

  10. The file is sourced.

  11. The nonomatch variable is unset. This means that error messages will again be displayed if a shell wildcard doesn't match any filenames. The i variable is also unset, which removes its value from memory. Shell scripts that are run in the regular manner, that is, by typing the script name in at the command line, are run in a subshell, making it uneccessary to unset variables because when the script exits, the subshell also exits, and the variables will be removed from memory automatically. Because this script is sourced, a subshell is not created, and the variables will remain in the memory of the current shell. Because they are no longer needed, the variables should be unset.

 <  Day Day Up  >  


UNIX Shells by Example
UNIX Shells by Example (4th Edition)
ISBN: 013147572X
EAN: 2147483647
Year: 2004
Pages: 454
Authors: Ellie Quigley

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