Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting
Prev |  | Next

# Chapter 17. System and Administrative Commands

The startup and shutdown scripts in `/etc/rc.d` illustrate the uses (and usefulness) of many of these comands. These are usually invoked by root and used for system maintenance or emergency filesystem repairs. Use with caution, as some of these commands may damage your system if misused.

Users and Groups

users

  Show all logged on users. This is the approximate equivalent of who -q.

groups

  Lists the current user and the groups she belongs to. This corresponds to the $GROUPS internal variable, but gives the group names, rather than the numbers.

       bash$ groups
       bozita cdrom cdwriter audio xgrp

       bash$ echo $GROUPS
       501

chown, chgrp

  The chown command changes the ownership of a file or files. This command is a useful method that root can use to shift file ownership from one user to another. An ordinary user may not change the ownership of files, not even her own files. [1]

       root# chown bozo *.txt

  The chgrp command changes the `group` ownership of a file or files. You must be owner of the file(s) as well as a member of the destination group (or root) to use this operation.

         1 chgrp --recursive dunderheads *.data
         2 #  The "dunderheads" group will now own all the "*.data" files
         3 #+ all the way down the $PWD directory tree (that's what "recursive" means).

useradd, userdel

  The useradd administrative command adds a user account to the system and creates a home directory for that particular user, if so specified. The corresponding userdel command removes a user account from the system [2] and deletes associated files.

  | The adduser command is a synonym for useradd and is usually a symbolic link to it.

usermod

  Modify a user account. Changes may be made to the password, group membership, expiration date, and other attributes of a given user's account. With this command, a user's password may be locked, which has the effect of disabling the account.

groupmod

  Modify a given group. The group name and/or ID number may be changed using this command.

id

  The id command lists the real and effective user IDs and the group IDs of the user associated with the current process. This is the counterpart to the $UID, $EUID, and $GROUPS internal Bash variables.

       bash$ id
       uid=501(bozo) gid=501(bozo) groups=501(bozo),22(cdrom),80(cdwriter),81(audio)

       bash$ echo $UID
       501

  | The id command shows the effective IDs only when they differ from the real ones.

  Also see Example 9-5.

lid

  The lid (list ID) command shows the group(s) that a given user belongs to, or alternately, the users belonging to a given group. May be invoked only by root.

       root# lid bozo
        bozo(gid=500)

       root# lid daemon
        bin(gid=1)
        daemon(gid=2)
        adm(gid=4)
        lp(gid=7)

who

  Show all users logged on to the system.

       bash$ who
       bozo  tty1     Apr 27 17:45
       bozo  pts/0    Apr 27 17:46
       bozo  pts/1    Apr 27 17:47
       bozo  pts/2    Apr 27 17:49

  The `-m` gives detailed information about only the current user. Passing any two arguments to who is the equivalent of who -m, as in who am i or who The Man.

       bash$ who -m
       localhost.localdomain!bozo  pts/2    Apr 27 17:49

  whoami is similar to who -m, but only lists the user name.

       bash$ whoami
       bozo

w

  Show all logged on users and the processes belonging to them. This is an extended version of who. The output of w may be piped to grep to find a specific user and/or process.

       bash$ w | grep startx
       bozo  tty1     -                 4:22pm  6:41   4.47s  0.45s  startx

logname

  Show current user's login name (as found in `/var/run/utmp`). This is a near-equivalent to whoami, above.

       bash$ logname
       bozo

       bash$ whoami
       bozo

  However . . .

       bash$ su
       Password: ......

       bash# whoami
       root
       bash# logname
       bozo

  | While logname prints the name of the logged in user, whoami gives the name of the user attached to the current process. As we have just seen, sometimes these are not the same.

su

  Runs a program or script as a substitute user. su rjones starts a shell as user rjones. A naked su defaults to root. See Example A-14.

sudo

  Runs a command as root (or another user). This may be used in a script, thus permitting a regular user to run the script.

         1 #!/bin/bash
         2
         3 # Some commands.
         4 sudo cp /root/secretfile /home/bozo/secret
         5 # Some more commands.

  The file `/etc/sudoers` holds the names of users permitted to invoke sudo.

passwd

  Sets, changes, or manages a user's password.

  The passwd command can be used in a script, but probably should not be.

  Example 17-1. Setting a new password

         1 #!/bin/bash
         2 #  setnew-password.sh: For demonstration purposes only.
         3 #                      Not a good idea to actually run this script.
         4 #  This script must be run as root.
         5
         6 ROOT_UID=0         # Root has $UID 0.
         7 E_WRONG_USER=65    # Not root?
         8
         9 E_NOSUCHUSER=70
        10 SUCCESS=0
        11
        12
        13 if [ "$UID" -ne "$ROOT_UID" ]
        14 then
        15   echo; echo "Only root can run this script."; echo
        16   exit $E_WRONG_USER
        17 else
        18   echo
        19   echo "You should know better than to run this script, root."
        20   echo "Even root users get the blues... "
        21   echo
        22 fi
        23
        24
        25 username=bozo
        26 NEWPASSWORD=security_violation
        27
        28 # Check if bozo lives here.
        29 grep -q "$username" /etc/passwd
        30 if [ $? -ne $SUCCESS ]
        31 then
        32   echo "User $username does not exist."
        33   echo "No password changed."
        34   exit $E_NOSUCHUSER
        35 fi
        36
        37 echo "$NEWPASSWORD" | passwd --stdin "$username"
        38 #  The '--stdin' option to 'passwd' permits
        39 #+ getting a new password from stdin (or a pipe).
        40
        41 echo; echo "User $username's password changed!"
        42
        43 # Using the 'passwd' command in a script is dangerous.
        44
        45 exit 0

  The passwd command's `-l`, `-u`, and `-d` options permit locking, unlocking, and deleting a user's password. Only root may use these options.

ac

  Show users' logged in time, as read from `/var/log/wtmp`. This is one of the GNU accounting utilities.

       bash$ ac
               total       68.08

last

  List last logged in users, as read from `/var/log/wtmp`. This command can also show remote logins.

  For example, to show the last few times the system rebooted:

       bash$ last reboot
       reboot   system boot  2.6.9-1.667      Fri Feb  4 18:18          (00:02)
       reboot   system boot  2.6.9-1.667      Fri Feb  4 15:20          (01:27)
       reboot   system boot  2.6.9-1.667      Fri Feb  4 12:56          (00:49)
       reboot   system boot  2.6.9-1.667      Thu Feb  3 21:08          (02:17)
       . . .

       wtmp begins Tue Feb  1 12:50:09 2005

newgrp

  Change user's group ID without logging out. This permits access to the new group's files. Since users may be members of multiple groups simultaneously, this command finds only limited use.

  | Kurt Glaesemann points out that the newgrp command could prove helpful in setting the default group permissions for files a user writes. However, the chgrp command might be more convenient for this purpose.

Terminals

tty

  Echoes the name (filename) of the current user's terminal. Note that each separate xterm window counts as a different terminal.

       bash$ tty
       /dev/pts/1

stty

  Shows and/or changes terminal settings. This complex command, used in a script, can control terminal behavior and the way output displays. See the info page, and study it carefully.

  Example 17-2. Setting an erase character

         1 #!/bin/bash
         2 # erase.sh: Using "stty" to set an erase character when reading input.
         3
         4 echo -n "What is your name? "
         5 read name                      #  Try to backspace
         6                                #+ to erase characters of input.
         7                                #  Problems?
         8 echo "Your name is $name."
         9
        10 stty erase '#'                 #  Set "hashmark" (#) as erase character.
        11 echo -n "What is your name? "
        12 read name                      #  Use # to erase last character typed.
        13 echo "Your name is $name."
        14
        15 exit 0
        16
        17 # Even after the script exits, the new key value remains set.
        18 # Exercise: How would you reset the erase character to the default value?

  Example 17-3. secret password: Turning off terminal echoing

         1 #!/bin/bash
         2 # secret-pw.sh: secret password
         3
         4 echo
         5 echo -n "Enter password "
         6 read passwd
         7 echo "password is $passwd"
         8 echo -n "If someone had been looking over your shoulder, "
         9 echo "your password would have been compromised."
        10
        11 echo && echo  # Two line-feeds in an "and list."
        12
        13
        14 stty -echo    # Turns off screen echo.
        15 #   May also be done with
        16 #   read -sp passwd
        17 #   A big Thank You to Leigh James for pointing this out.
        18
        19 echo -n "Enter password again "
        20 read passwd
        21 echo
        22 echo "password is $passwd"
        23 echo
        24
        25 stty echo     # Restores screen echo.
        26
        27 exit 0
        28
        29 # Do an 'info stty' for more on this useful-but-tricky command.

  A creative use of stty is detecting a user keypress (without hitting ENTER).

  Example 17-4. Keypress detection

         1 #!/bin/bash
         2 # keypress.sh: Detect a user keypress ("hot keys").
         3
         4 echo
         5
         6 old_tty_settings=$(stty -g)   # Save old settings (why?).
         7 stty -icanon
         8 Keypress=$(head -c1)          # or $(dd bs=1 count=1 2> /dev/null)
         9                               # on non-GNU systems
        10
        11 echo
        12 echo "Key pressed was \""$Keypress"\"."
        13 echo
        14
        15 stty "$old_tty_settings"      # Restore old settings.
        16
        17 # Thanks, Stephane Chazelas.
        18
        19 exit 0

  Also see Example 9-3 and Example A-43.

setterm

  Set certain terminal attributes. This command writes to its terminal's `stdout` a string that changes the behavior of that terminal.

       bash$ setterm -cursor off
       bash$

  The setterm command can be used within a script to change the appearance of text written to `stdout`, although there are certainly better tools available for this purpose.

         1 setterm -bold on
         2 echo bold hello
         3
         4 setterm -bold off
         5 echo normal hello

tset

  Show or initialize terminal settings. This is a less capable version of stty.

       bash$ tset -r
       Terminal type is xterm-xfree86.
       Kill is control-U (^U).
       Interrupt is control-C (^C).

setserial

  Set or display serial port parameters. This command must be run by root and is usually found in a system setup script.

         1 # From /etc/pcmcia/serial script:
         2
         3 IRQ=`setserial /dev/$DEVICE | sed -e 's/.*IRQ: //'`
         4 setserial /dev/$DEVICE irq 0 ; setserial /dev/$DEVICE irq $IRQ

getty, agetty

  The initialization process for a terminal uses getty or agetty to set it up for login by a user. These commands are not used within user shell scripts. Their scripting counterpart is stty.

mesg

  Enables or disables write access to the current user's terminal. Disabling access would prevent another user on the network to write to the terminal.

  | It can be quite annoying to have a message about ordering pizza suddenly appear in the middle of the text file you are editing. On a multi-user network, you might therefore wish to disable write access to your terminal when you need to avoid interruptions.

wall

  This is an acronym for "write all," i.e., sending a message to all users at every terminal logged into the network. It is primarily a system administrator's tool, useful, for example, when warning everyone that the system will shortly go down due to a problem (see Example 19-1).

       bash$ wall System going down for maintenance in 5 minutes!
       Broadcast message from bozo (pts/1) Sun Jul  8 13:53:27 2001...

       System going down for maintenance in 5 minutes!

  | If write access to a particular terminal has been disabled with mesg, then wall cannot send a message to that terminal.

Information and Statistics

uname

  Output system specifications (OS, kernel version, etc.) to `stdout`. Invoked with the `-a` option, gives verbose system info (see Example 16-5). The `-s` option shows only the OS type.

       bash$ uname
       Linux

       bash$ uname -s
       Linux

       bash$ uname -a
       Linux iron.bozo 2.6.15-1.2054_FC5 #1 Tue Mar 14 15:48:33 EST 2006
       i686 i686 i386 GNU/Linux

arch

  Show system architecture. Equivalent to uname -m. See Example 11-27.

       bash$ arch
       i686

       bash$ uname -m
       i686

lastcomm

  Gives information about previous commands, as stored in the `/var/account/pacct` file. Command name and user name can be specified by options. This is one of the GNU accounting utilities.

lastlog

  List the last login time of all system users. This references the `/var/log/lastlog` file.

       bash$ lastlog
       root          tty1                      Fri Dec  7 18:43:21 -0700 2001
       bin                                     **Never logged in**
       daemon                                  **Never logged in**
       ...
       bozo          tty1                      Sat Dec  8 21:14:29 -0700 2001

       bash$ lastlog | grep root
       root          tty1                      Fri Dec  7 18:43:21 -0700 2001

  | This command will fail if the user invoking it does not have read permission for the `/var/log/lastlog` file.

lsof

  List open files. This command outputs a detailed table of all currently open files and gives information about their owner, size, the processes associated with them, and more. Of course, lsof may be piped to grep and/or awk to parse and analyze its results.

       bash$ lsof
       COMMAND    PID    USER   FD   TYPE     DEVICE    SIZE     NODE NAME
       init         1    root  mem    REG        3,5   30748    30303 /sbin/init
       init         1    root  mem    REG        3,5   73120     8069 /lib/ld-2.1.3.so
       init         1    root  mem    REG        3,5  931668     8075 /lib/libc-2.1.3.so
       cardmgr    213    root  mem    REG        3,5   36956    30357 /sbin/cardmgr
       ...

  The lsof command is a useful, if complex administrative tool. If you are unable to dismount a filesystem and get an error message that it is still in use, then running lsof helps determine which files are still open on that filesystem. The `-i` option lists open network socket files, and this can help trace intrusion or hack attempts.

       bash$ lsof -an -i tcp
       COMMAND  PID USER  FD  TYPE DEVICE SIZE NODE NAME
       firefox 2330 bozo  32u IPv4   9956       TCP 66.0.118.137:57596->67.112.7.104:http ...
       firefox 2330 bozo  38u IPv4  10535       TCP 66.0.118.137:57708->216.79.48.24:http ...

  See Example 30-2 for an effective use of lsof.

strace

  System trace: diagnostic and debugging tool for tracing system calls and signals. This command and ltrace, following, are useful for diagnosing why a given program or package fails to run . . . perhaps due to missing libraries or related causes.

       bash$ strace df
       execve("/bin/df", ["df"], [/* 45 vars */]) = 0
       uname({sys="Linux", node="bozo.localdomain", ...}) = 0
       brk(0)                                  = 0x804f5e4

       ...

  This is the Linux equivalent of the Solaris truss command.

ltrace

  Library trace: diagnostic and debugging tool that traces library calls invoked by a given command.

       bash$ ltrace df
       __libc_start_main(0x804a910, 1, 0xbfb589a4, 0x804fb70, 0x804fb68 <unfinished ...>:
       setlocale(6, "")                                 = "en_US.UTF-8"
      bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"
      textdomain("coreutils")                          = "coreutils"
      __cxa_atexit(0x804b650, 0, 0, 0x8052bf0, 0xbfb58908) = 0
      getenv("DF_BLOCK_SIZE")                          = NULL

       ...

nc

  The nc (netcat) utility is a complete toolkit for connecting to and listening to TCP and UDP ports. It is useful as a diagnostic and testing tool and as a component in simple script-based HTTP clients and servers.

       bash$ nc localhost.localdomain 25
       220 localhost.localdomain ESMTP Sendmail 8.13.1/8.13.1;
       Thu, 31 Mar 2005 15:41:35 -0700

  A real-life usage example.

  Example 17-5. Checking a remote server for identd

         1 #! /bin/sh
         2 ## Duplicate DaveG's ident-scan thingie using netcat. Oooh, he'll be p*ssed.
         3 ## Args: target port [port port port ...]
         4 ## Hose stdout _and_ stderr together.
         5 ##
         6 ##  Advantages: runs slower than ident-scan, giving remote inetd less cause
         7 ##+ for alarm, and only hits the few known daemon ports you specify.
         8 ##  Disadvantages: requires numeric-only port args, the output sleazitude,
         9 ##+ and won't work for r-services when coming from high source ports.
        10 # Script author: Hobbit <hobbit@avian.org>
        11 # Used in ABS Guide with permission.
        12
        13 # ---------------------------------------------------
        14 E_BADARGS=65       # Need at least two args.
        15 TWO_WINKS=2        # How long to sleep.
        16 THREE_WINKS=3
        17 IDPORT=113         # Authentication "tap ident" port.
        18 RAND1=999
        19 RAND2=31337
        20 TIMEOUT0=9
        21 TIMEOUT1=8
        22 TIMEOUT2=4
        23 # ---------------------------------------------------
        24
        25 case "${2}" in
        26   "" ) echo "Need HOST and at least one PORT." ; exit $E_BADARGS ;;
        27 esac
        28
        29 # Ping 'em once and see if they *are* running identd.
        30 nc -z -w $TIMEOUT0 "$1" $IDPORT || \
        31 { echo "Oops, $1 isn't running identd." ; exit 0 ; }
        32 #  -z scans for listening daemons.
        33 #     -w $TIMEOUT = How long to try to connect.
        34
        35 # Generate a randomish base port.
        36 RP=`expr $$ % $RAND1 + $RAND2`
        37
        38 TRG="$1"
        39 shift
        40
        41 while test "$1" ; do
        42   nc -v -w $TIMEOUT1 -p ${RP} "$TRG" ${1} < /dev/null > /dev/null &
        43   PROC=$!
        44   sleep $THREE_WINKS
        45   echo "${1},${RP}" | nc -w $TIMEOUT2 -r "$TRG" $IDPORT 2>&1
        46   sleep $TWO_WINKS
        47
        48 # Does this look like a lamer script or what . . . ?
        49 # ABS Guide author comments: "Ain't really all that bad . . .
        50 #+                            kinda clever, actually."
        51
        52   kill -HUP $PROC
        53   RP=`expr ${RP} + 1`
        54   shift
        55 done
        56
        57 exit $?
        58
        59 #  Notes:
        60 #  -----
        61
        62 #  Try commenting out line 30 and running this script
        63 #+ with "localhost.localdomain 25" as arguments.
        64
        65 #  For more of Hobbit's 'nc' example scripts,
        66 #+ look in the documentation:
        67 #+ the /usr/share/doc/nc-X.XX/scripts directory.

  And, of course, there's Dr. Andrew Tridgell's notorious one-line script in the BitKeeper Affair:

         1 echo clone | nc thunk.org 5000 > e2fsprogs.dat

free

  Shows memory and cache usage in tabular form. The output of this command lends itself to parsing, using grep, awk or Perl. The procinfo command shows all the information that free does, and much more.

       bash$ free
                       total       used       free     shared    buffers     cached
         Mem:         30504      28624       1880      15820       1608       16376
         -/+ buffers/cache:      10640      19864
         Swap:        68540       3128      65412

  To show unused RAM memory:

       bash$ free | grep Mem | awk '{ print $4 }'
       1880

procinfo

  Extract and list information and statistics from the `/proc` pseudo-filesystem. This gives a very extensive and detailed listing.

       bash$ procinfo | grep Bootup
       Bootup: Wed Mar 21 15:15:50 2001    Load average: 0.04 0.21 0.34 3/47 6829

lsdev

  List devices, that is, show installed hardware.

       bash$ lsdev
       Device            DMA   IRQ  I/O Ports
       ------------------------------------------------
       cascade             4     2
       dma                          0080-008f
       dma1                         0000-001f
       dma2                         00c0-00df
       fpu                          00f0-00ff
       ide0                     14  01f0-01f7 03f6-03f6
       ...

du

  Show (disk) file usage, recursively. Defaults to current working directory, unless otherwise specified.

       bash$ du -ach
       1.0k    ./wi.sh
       1.0k    ./tst.sh
       1.0k    ./random.file
       6.0k    .
       6.0k    total

df

  Shows filesystem usage in tabular form.

       bash$ df
       Filesystem           1k-blocks      Used Available Use% Mounted on
       /dev/hda5               273262     92607    166547  36% /
       /dev/hda8               222525    123951     87085  59% /home
       /dev/hda7              1408796   1075744    261488  80% /usr

dmesg

  Lists all system bootup messages to `stdout`. Handy for debugging and ascertaining which device drivers were installed and which system interrupts in use. The output of dmesg may, of course, be parsed with grep, sed, or awk from within a script.

       bash$ dmesg | grep hda
       Kernel command line: ro root=/dev/hda2
       hda: IBM-DLGA-23080, ATA DISK drive
       hda: 6015744 sectors (3080 MB) w/96KiB Cache, CHS=746/128/63
       hda: hda1 hda2 hda3 < hda5 hda6 hda7 > hda4

stat

  Gives detailed and verbose statistics on a given file (even a directory or device file) or set of files.

       bash$ stat test.cru
         File: "test.cru"
         Size: 49970        Allocated Blocks: 100          Filetype: Regular File
         Mode: (0664/-rw-rw-r--)         Uid: (  501/ bozo)  Gid: (  501/ bozo)
       Device:  3,8   Inode: 18185     Links: 1
       Access: Sat Jun  2 16:40:24 2001
       Modify: Sat Jun  2 16:40:24 2001
       Change: Sat Jun  2 16:40:24 2001

  If the target file does not exist, stat returns an error message.

       bash$ stat nonexistent-file
       nonexistent-file: No such file or directory

  In a script, you can use stat to extract information about files (and filesystems) and set variables accordingly.

         1 #!/bin/bash
         2 # fileinfo2.sh
         3
         4 # Per suggestion of Joël Bourquard and . . .
         5 # http://www.linuxquestions.org/questions/showthread.php?t=410766
         6
         7
         8 FILENAME=testfile.txt
         9 file_name=$(stat -c%n "$FILENAME")   # Same as "$FILENAME" of course.
        10 file_owner=$(stat -c%U "$FILENAME")
        11 file_size=$(stat -c%s "$FILENAME")
        12 #  Certainly easier than using "ls -l $FILENAME"
        13 #+ and then parsing with sed.
        14 file_inode=$(stat -c%i "$FILENAME")
        15 file_type=$(stat -c%F "$FILENAME")
        16 file_access_rights=$(stat -c%A "$FILENAME")
        17
        18 echo "File name:          $file_name"
        19 echo "File owner:         $file_owner"
        20 echo "File size:          $file_size"
        21 echo "File inode:         $file_inode"
        22 echo "File type:          $file_type"
        23 echo "File access rights: $file_access_rights"
        24
        25 exit 0
        26
        27 sh fileinfo2.sh
        28
        29 File name:          testfile.txt
        30 File owner:         bozo
        31 File size:          418
        32 File inode:         1730378
        33 File type:          regular file
        34 File access rights: -rw-rw-r--

vmstat

  Display virtual memory statistics.

       bash$ vmstat
          procs                      memory    swap          io system         cpu
       r  b  w   swpd   free   buff  cache  si  so    bi    bo   in    cs  us  sy id
       0  0  0      0  11040   2636  38952   0   0    33     7  271    88   8   3 89

uptime

  Shows how long the system has been running, along with associated statistics.

       bash$ uptime
       10:28pm  up  1:57,  3 users,  load average: 0.17, 0.34, 0.27

  | A load average of 1 or less indicates that the system handles processes immediately. A load average greater than 1 means that processes are being queued. When the load average gets above 3 (on a single-core processor), then system performance is significantly degraded.

hostname

  Lists the system's host name. This command sets the host name in an `/etc/rc.d` setup script (`/etc/rc.d/rc.sysinit` or similar). It is equivalent to uname -n, and a counterpart to the $HOSTNAME internal variable.

       bash$ hostname
       localhost.localdomain

       bash$ echo $HOSTNAME
       localhost.localdomain

  Similar to the hostname command are the domainname, dnsdomainname, nisdomainname, and ypdomainname commands. Use these to display or set the system DNS or NIS/YP domain name. Various options to hostname also perform these functions.

hostid

  Echo a 32-bit hexadecimal numerical identifier for the host machine.

       bash$ hostid
       7f0100

  This command allegedly fetches a "unique" serial number for a particular system. Certain product registration procedures use this number to brand a particular user license. Unfortunately, hostid only returns the machine network address in hexadecimal, with pairs of bytes transposed.

  The network address of a typical non-networked Linux machine, is found in `/etc/hosts`.

       bash$ cat /etc/hosts
       127.0.0.1               localhost.localdomain localhost

  As it happens, transposing the bytes of `127.0.0.1`, we get `0.127.1.0`, which translates in hex to `007f0100`, the exact equivalent of what hostid returns, above. There exist only a few million other Linux machines with this identical hostid.

sar

  Invoking sar (System Activity Reporter) gives a very detailed rundown on system statistics. The Santa Cruz Operation ("Old" SCO) released sar as Open Source in June, 1999.

  This command is not part of the base Linux distribution, but may be obtained as part of the sysstat utilities package, written by Sebastien Godard.

       bash$ sar
       Linux 2.4.9 (brooks.seringas.fr) 	09/26/03

      10:30:00          CPU     %user     %nice   %system   %iowait     %idle
      10:40:00          all      2.21     10.90     65.48      0.00     21.41
      10:50:00          all      3.36      0.00     72.36      0.00     24.28
      11:00:00          all      1.12      0.00     80.77      0.00     18.11
      Average:          all      2.23      3.63     72.87      0.00     21.27

      14:32:30          LINUX RESTART

      15:00:00          CPU     %user     %nice   %system   %iowait     %idle
      15:10:00          all      8.59      2.40     17.47      0.00     71.54
      15:20:00          all      4.07      1.00     11.95      0.00     82.98
      15:30:00          all      0.79      2.94      7.56      0.00     88.71
      Average:          all      6.33      1.70     14.71      0.00     77.26

readelf

  Show information and statistics about a designated elf binary. This is part of the binutils package.

       bash$ readelf -h /bin/bash
       ELF Header:
         Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
         Class:                             ELF32
         Data:                              2's complement, little endian
         Version:                           1 (current)
         OS/ABI:                            UNIX - System V
         ABI Version:                       0
         Type:                              EXEC (Executable file)
         . . .

size

  The size [/path/to/binary] command gives the segment sizes of a binary executable or archive file. This is mainly of use to programmers.

       bash$ size /bin/bash
          text    data     bss     dec     hex filename
        495971   22496   17392  535859   82d33 /bin/bash

System Logs

logger

  Appends a user-generated message to the system log (`/var/log/messages`). You do not have to be root to invoke logger.

         1 logger Experiencing instability in network connection at 23:10, 05/21.
         2 # Now, do a 'tail /var/log/messages'.

  By embedding a logger command in a script, it is possible to write debugging information to `/var/log/messages`.

         1 logger -t $0 -i Logging at line "$LINENO".
         2 # The "-t" option specifies the tag for the logger entry.
         3 # The "-i" option records the process ID.
         4
         5 # tail /var/log/message
         6 # ...
         7 # Jul  7 20:48:58 localhost ./test.sh[1712]: Logging at line 3.

logrotate

  This utility manages the system log files, rotating, compressing, deleting, and/or e-mailing them, as appropriate. This keeps the `/var/log` from getting cluttered with old log files. Usually cron runs logrotate on a daily basis.

  Adding an appropriate entry to `/etc/logrotate.conf` makes it possible to manage personal log files, as well as system-wide ones.

  | Stefano Falsetto has created rottlog, which he considers to be an improved version of logrotate.

Job Control

ps

  `P`rocess `S`tatistics: lists currently executing processes by owner and PID (process ID). This is usually invoked with `ax` or `aux` options, and may be piped to grep or sed to search for a specific process (see Example 15-14 and Example 29-3).

       bash$  ps ax | grep sendmail
       295 ?	   S	  0:00 sendmail: accepting connections on port 25

  To display system processes in graphical "tree" format: ps afjx or ps ax --forest.

pgrep, pkill

  Combining the ps command with grep or kill.

       bash$ ps a | grep mingetty
       2212 tty2     Ss+    0:00 /sbin/mingetty tty2
       2213 tty3     Ss+    0:00 /sbin/mingetty tty3
       2214 tty4     Ss+    0:00 /sbin/mingetty tty4
       2215 tty5     Ss+    0:00 /sbin/mingetty tty5
       2216 tty6     Ss+    0:00 /sbin/mingetty tty6
       4849 pts/2    S+     0:00 grep mingetty

       bash$ pgrep mingetty
       2212 mingetty
       2213 mingetty
       2214 mingetty
       2215 mingetty
       2216 mingetty

  Compare the action of pkill with killall.

pstree

  Lists currently executing processes in "tree" format. The `-p` option shows the PIDs, as well as the process names.

top

  Continuously updated display of most cpu-intensive processes. The `-b` option displays in text mode, so that the output may be parsed or accessed from a script.

       bash$ top -b
         8:30pm  up 3 min,  3 users,  load average: 0.49, 0.32, 0.13
       45 processes: 44 sleeping, 1 running, 0 zombie, 0 stopped
       CPU states: 13.6% user,  7.3% system,  0.0% nice, 78.9% idle
       Mem:    78396K av,   65468K used,   12928K free,       0K shrd,    2352K buff
       Swap:  157208K av,       0K used,  157208K free                   37244K cached

         PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND
         848 bozo      17   0   996  996   800 R     5.6  1.2   0:00 top
           1 root       8   0   512  512   444 S     0.0  0.6   0:04 init
           2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd
         ...

nice

  Run a background job with an altered priority. Priorities run from 19 (lowest) to -20 (highest). Only root may set the negative (higher) priorities. Related commands are renice and snice, which change the priority of a running process or processes, and skill, which sends a kill signal to a process or processes.

nohup

  Keeps a command running even after user logs off. The command will run as a foreground process unless followed by &. If you use nohup within a script, consider coupling it with a wait to avoid creating an orphan or zombie process.

pidof

  Identifies process ID (PID) of a running job. Since job control commands, such as kill and renice act on the PID of a process (not its name), it is sometimes necessary to identify that PID. The pidof command is the approximate counterpart to the $PPID internal variable.

       bash$ pidof xclock
       880

  Example 17-6. pidof helps kill a process

         1 #!/bin/bash
         2 # kill-process.sh
         3
         4 NOPROCESS=2
         5
         6 process=xxxyyyzzz  # Use nonexistent process.
         7 # For demo purposes only...
         8 # ... don't want to actually kill any actual process with this script.
         9 #
        10 # If, for example, you wanted to use this script to logoff the Internet,
        11 #     process=pppd
        12
        13 t=`pidof $process`       # Find pid (process id) of $process.
        14 # The pid is needed by 'kill' (can't 'kill' by program name).
        15
        16 if [ -z "$t" ]           # If process not present, 'pidof' returns null.
        17 then
        18   echo "Process $process was not running."
        19   echo "Nothing killed."
        20   exit $NOPROCESS
        21 fi
        22
        23 kill $t                  # May need 'kill -9' for stubborn process.
        24
        25 # Need a check here to see if process allowed itself to be killed.
        26 # Perhaps another " t=`pidof $process` " or ...
        27
        28
        29 # This entire script could be replaced by
        30 #        kill $(pidof -x process_name)
        31 # or
        32 #        killall process_name
        33 # but it would not be as instructive.
        34
        35 exit 0

fuser

  Identifies the processes (by PID) that are accessing a given file, set of files, or directory. May also be invoked with the `-k` option, which kills those processes. This has interesting implications for system security, especially in scripts preventing unauthorized users from accessing system services.

       bash$ fuser -u /usr/bin/vim
       /usr/bin/vim:         3207e(bozo)

       bash$ fuser -u /dev/null
       /dev/null:            3009(bozo)  3010(bozo)  3197(bozo)  3199(bozo)

  One important application for fuser is when physically inserting or removing storage media, such as CD ROM disks or USB flash drives. Sometimes trying a umount fails with a device is busy error message. This means that some user(s) and/or process(es) are accessing the device. An fuser -um /dev/device_name will clear up the mystery, so you can kill any relevant processes.

       bash$ umount /mnt/usbdrive
       umount: /mnt/usbdrive: device is busy

       bash$ fuser -um /dev/usbdrive
       /mnt/usbdrive:        1772c(bozo)

       bash$ kill -9 1772
       bash$ umount /mnt/usbdrive

  The fuser command, invoked with the `-n` option identifies the processes accessing a port. This is especially useful in combination with nmap.

       root# nmap localhost.localdomain
       PORT     STATE SERVICE
       25/tcp   open  smtp

       root# fuser -un tcp 25
       25/tcp:               2095(root)

       root# ps ax | grep 2095 | grep -v grep
       2095 ?        Ss     0:00 sendmail: accepting connections

cron

  Administrative program scheduler, performing such duties as cleaning up and deleting system log files and updating the slocate database. This is the superuser version of at (although each user may have their own `crontab` file which can be changed with the crontab command). It runs as a daemon and executes scheduled entries from `/etc/crontab`.

  | Some flavors of Linux run crond, Matthew Dillon's version of cron.

Process Control and Booting

init

  The init command is the parent of all processes. Called in the final step of a bootup, init determines the runlevel of the system from `/etc/inittab`. Invoked by its alias telinit, and by root only.

telinit

  Symlinked to init, this is a means of changing the system runlevel, usually done for system maintenance or emergency filesystem repairs. Invoked only by root. This command can be dangerous -- be certain you understand it well before using!

runlevel

  Shows the current and last runlevel, that is, whether the system is halted (runlevel `0`), in single-user mode (`1`), in multi-user mode (`2` or `3`), in X Windows (`5`), or rebooting (`6`). This command accesses the `/var/run/utmp` file.

halt, shutdown, reboot

  Command set to shut the system down, usually just prior to a power down.

  | On some Linux distros, the halt command has 755 permissions, so it can be invoked by a non-root user. A careless halt in a terminal or a script may shut down the system!

service

  Starts or stops a system service. The startup scripts in `/etc/init.d` and `/etc/rc.d` use this command to start services at bootup.

       root# /sbin/service iptables stop
       Flushing firewall rules:                                   [  OK  ]
       Setting chains to policy ACCEPT: filter                    [  OK  ]
       Unloading iptables modules:                                [  OK  ]

Network

nmap

  Network mapper and port scanner. This command scans a server to locate open ports and the services associated with those ports. It can also report information about packet filters and firewalls. This is an important security tool for locking down a network against hacking attempts.

         1 #!/bin/bash
         2
         3 SERVER=$HOST                           # localhost.localdomain (127.0.0.1).
         4 PORT_NUMBER=25                         # SMTP port.
         5
         6 nmap $SERVER | grep -w "$PORT_NUMBER"  # Is that particular port open?
         7 #              grep -w matches whole words only,
         8 #+             so this wouldn't match port 1025, for example.
         9
        10 exit 0
        11
        12 # 25/tcp     open        smtp

ifconfig

  Network interface configuration and tuning utility.

       bash$ ifconfig -a
       lo        Link encap:Local Loopback
                 inet addr:127.0.0.1  Mask:255.0.0.0
                 UP LOOPBACK RUNNING  MTU:16436  Metric:1
                 RX packets:10 errors:0 dropped:0 overruns:0 frame:0
                 TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
                 collisions:0 txqueuelen:0
                 RX bytes:700 (700.0 b)  TX bytes:700 (700.0 b)

  The ifconfig command is most often used at bootup to set up the interfaces, or to shut them down when rebooting.

         1 # Code snippets from /etc/rc.d/init.d/network
         2
         3 # ...
         4
         5 # Check that networking is up.
         6 [ ${NETWORKING} = "no" ] && exit 0
         7
         8 [ -x /sbin/ifconfig ] || exit 0
         9
        10 # ...
        11
        12 for i in $interfaces ; do
        13   if ifconfig $i 2>/dev/null | grep -q "UP" >/dev/null 2>&1 ; then
        14     action "Shutting down interface $i: " ./ifdown $i boot
        15   fi
        16 #  The GNU-specific "-q" option to "grep" means "quiet", i.e.,
        17 #+ producing no output.
        18 #  Redirecting output to /dev/null is therefore not strictly necessary.
        19
        20 # ...
        21
        22 echo "Currently active devices:"
        23 echo `/sbin/ifconfig | grep ^[a-z] | awk '{print $1}'`
        24 #                            ^^^^^  should be quoted to prevent globbing.
        25 #  The following also work.
        26 #    echo $(/sbin/ifconfig | awk '/^[a-z]/ { print $1 })'
        27 #    echo $(/sbin/ifconfig | sed -e 's/ .*//')
        28 #  Thanks, S.C., for additional comments.

  See also Example 32-6.

netstat

  Show current network statistics and information, such as routing tables and active connections. This utility accesses information in `/proc/net` (Chapter 29). See Example 29-4.

  netstat -r is equivalent to route.

       bash$ netstat
       Active Internet connections (w/o servers)
       Proto Recv-Q Send-Q Local Address           Foreign Address         State
       Active UNIX domain sockets (w/o servers)
       Proto RefCnt Flags       Type       State         I-Node Path
       unix  11     [ ]         DGRAM                    906    /dev/log
       unix  3      [ ]         STREAM     CONNECTED     4514   /tmp/.X11-unix/X0
       unix  3      [ ]         STREAM     CONNECTED     4513
       . . .

  | A netstat -lptu shows sockets that are listening to ports, and the associated processes. This can be useful for determining whether a computer has been hacked or compromised.

iwconfig

  This is the command set for configuring a wireless network. It is the wireless equivalent of ifconfig, above.

ip

  General purpose utility for setting up, changing, and analyzing IP (Internet Protocol) networks and attached devices. This command is part of the iproute2 package.

       bash$ ip link show
       1: lo: <LOOPBACK,UP> mtu 16436 qdisc noqueue
           link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
       2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast qlen 1000
           link/ether 00:d0:59:ce:af:da brd ff:ff:ff:ff:ff:ff
       3: sit0: <NOARP> mtu 1480 qdisc noop
           link/sit 0.0.0.0 brd 0.0.0.0

       bash$ ip route list
       169.254.0.0/16 dev lo  scope link

  Or, in a script:

         1 #!/bin/bash
         2 # Script by Juan Nicolas Ruiz
         3 # Used with his kind permission.
         4
         5 # Setting up (and stopping) a GRE tunnel.
         6
         7
         8 # --- start-tunnel.sh ---
         9
        10 LOCAL_IP="192.168.1.17"
        11 REMOTE_IP="10.0.5.33"
        12 OTHER_IFACE="192.168.0.100"
        13 REMOTE_NET="192.168.3.0/24"
        14
        15 /sbin/ip tunnel add netb mode gre remote $REMOTE_IP \
        16   local $LOCAL_IP ttl 255
        17 /sbin/ip addr add $OTHER_IFACE dev netb
        18 /sbin/ip link set netb up
        19 /sbin/ip route add $REMOTE_NET dev netb
        20
        21 exit 0  #############################################
        22
        23 # --- stop-tunnel.sh ---
        24
        25 REMOTE_NET="192.168.3.0/24"
        26
        27 /sbin/ip route del $REMOTE_NET dev netb
        28 /sbin/ip link set netb down
        29 /sbin/ip tunnel del netb
        30
        31 exit 0

route

  Show info about or make changes to the kernel routing table.

       bash$ route
       Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
       pm3-67.bozosisp *               255.255.255.255 UH       40 0          0 ppp0
       127.0.0.0       *               255.0.0.0       U        40 0          0 lo
       default         pm3-67.bozosisp 0.0.0.0         UG       40 0          0 ppp0

iptables

  The iptables command set is a packet filtering tool used mainly for such security purposes as setting up network firewalls. This is a complex tool, and a detailed explanation of its use is beyond the scope of this document. Oskar Andreasson's tutorial is a reasonable starting point.

  See also shutting down iptables and Example 30-2.

chkconfig

  Check network and system configuration. This command lists and manages the network and system services started at bootup in the `/etc/rc?.d` directory.

  Originally a port from IRIX to Red Hat Linux, chkconfig may not be part of the core installation of some Linux flavors.

       bash$ chkconfig --list
       atd             0:off   1:off   2:off   3:on    4:on    5:on    6:off
       rwhod           0:off   1:off   2:off   3:off   4:off   5:off   6:off
       ...

tcpdump

  Network packet "sniffer." This is a tool for analyzing and troubleshooting traffic on a network by dumping packet headers that match specified criteria.

  Dump ip packet traffic between hosts bozoville and caduceus:

       bash$ tcpdump ip host bozoville and caduceus

  Of course, the output of tcpdump can be parsed with certain of the previously discussed text processing utilities.

Filesystem

mount

  Mount a filesystem, usually on an external device, such as a floppy or CDROM. The file `/etc/fstab` provides a handy listing of available filesystems, partitions, and devices, including options, that may be automatically or manually mounted. The file `/etc/mtab` shows the currently mounted filesystems and partitions (including the virtual ones, such as `/proc`).

  mount -a mounts all filesystems and partitions listed in `/etc/fstab`, except those with a `noauto` option. At bootup, a startup script in `/etc/rc.d` (`rc.sysinit` or something similar) invokes this to get everything mounted.

         1 mount -t iso9660 /dev/cdrom /mnt/cdrom
         2 # Mounts CD ROM. ISO 9660 is a standard CD ROM filesystem.
         3 mount /mnt/cdrom
         4 # Shortcut, if /mnt/cdrom listed in /etc/fstab

  The versatile mount command can even mount an ordinary file on a block device, and the file will act as if it were a filesystem. Mount accomplishes that by associating the file with a loopback device. One application of this is to mount and examine an ISO9660 filesystem image before burning it onto a CDR. [3]

  Example 17-7. Checking a CD image

         1 # As root...
         2
         3 mkdir /mnt/cdtest  # Prepare a mount point, if not already there.
         4
         5 mount -r -t iso9660 -o loop cd-image.iso /mnt/cdtest   # Mount the image.
         6 #                  "-o loop" option equivalent to "losetup /dev/loop0"
         7 cd /mnt/cdtest     # Now, check the image.
         8 ls -alR            # List the files in the directory tree there.
         9                    # And so forth.

umount

  Unmount a currently mounted filesystem. Before physically removing a previously mounted floppy or CDROM disk, the device must be umounted, else filesystem corruption may result.

         1 umount /mnt/cdrom
         2 # You may now press the eject button and safely remove the disk.

  | The automount utility, if properly installed, can mount and unmount floppies or CDROM disks as they are accessed or removed. On "multispindle" laptops with swappable floppy and optical drives, this can cause problems, however.

gnome-mount

  The newer Linux distros have deprecated mount and umount. The successor, for command-line mounting of removable storage devices, is gnome-mount. It can take the `-d` option to mount a device file by its listing in `/dev`.

  For example, to mount a USB flash drive:

       bash$ gnome-mount -d /dev/sda1
       gnome-mount 0.4

       bash$ df
       . . .
       /dev/sda1                63584     12034     51550  19% /media/disk

sync

  Forces an immediate write of all updated data from buffers to hard drive (synchronize drive with buffers). While not strictly necessary, a sync assures the sys admin or user that the data just changed will survive a sudden power failure. In the olden days, a `sync; sync` (twice, just to make absolutely sure) was a useful precautionary measure before a system reboot.

  At times, you may wish to force an immediate buffer flush, as when securely deleting a file (see Example 16-61) or when the lights begin to flicker.

losetup

  Sets up and configures loopback devices.

  Example 17-8. Creating a filesystem in a file

         1 SIZE=1000000  # 1 meg
         2
         3 head -c $SIZE < /dev/zero > file  # Set up file of designated size.
         4 losetup /dev/loop0 file           # Set it up as loopback device.
         5 mke2fs /dev/loop0                 # Create filesystem.
         6 mount -o loop /dev/loop0 /mnt     # Mount it.
         7
         8 # Thanks, S.C.

mkswap

  Creates a swap partition or file. The swap area must subsequently be enabled with swapon.

swapon, swapoff

  Enable / disable swap partitition or file. These commands usually take effect at bootup and shutdown.

mke2fs

  Create a Linux ext2 filesystem. This command must be invoked as root.

  Example 17-9. Adding a new hard drive

         1 #!/bin/bash
         2
         3 # Adding a second hard drive to system.
         4 # Software configuration. Assumes hardware already mounted.
         5 # From an article by the author of the ABS Guide.
         6 # In issue #38 of _Linux Gazette_, http://www.linuxgazette.com.
         7
         8 ROOT_UID=0     # This script must be run as root.
         9 E_NOTROOT=67   # Non-root exit error.
        10
        11 if [ "$UID" -ne "$ROOT_UID" ]
        12 then
        13   echo "Must be root to run this script."
        14   exit $E_NOTROOT
        15 fi
        16
        17 # Use with extreme caution!
        18 # If something goes wrong, you may wipe out your current filesystem.
        19
        20
        21 NEWDISK=/dev/hdb         # Assumes /dev/hdb vacant. Check!
        22 MOUNTPOINT=/mnt/newdisk  # Or choose another mount point.
        23
        24
        25 fdisk $NEWDISK
        26 mke2fs -cv $NEWDISK1   # Check for bad blocks (verbose output).
        27 #  Note:           ^     /dev/hdb1, *not* /dev/hdb!
        28 mkdir $MOUNTPOINT
        29 chmod 777 $MOUNTPOINT  # Makes new drive accessible to all users.
        30
        31
        32 # Now, test ...
        33 # mount -t ext2 /dev/hdb1 /mnt/newdisk
        34 # Try creating a directory.
        35 # If it works, umount it, and proceed.
        36
        37 # Final step:
        38 # Add the following line to /etc/fstab.
        39 # /dev/hdb1  /mnt/newdisk  ext2  defaults  1 1
        40
        41 exit

  See also Example 17-8 and Example 31-3.

mkdosfs

  Create a DOS FAT filesystem.

tune2fs

  Tune ext2 filesystem. May be used to change filesystem parameters, such as maximum mount count. This must be invoked as root.

  | This is an extremely dangerous command. Use it at your own risk, as you may inadvertently destroy your filesystem.

dumpe2fs

  Dump (list to `stdout`) very verbose filesystem info. This must be invoked as root.

       root# dumpe2fs /dev/hda7 | grep 'ount count'
       dumpe2fs 1.19, 13-Jul-2000 for EXT2 FS 0.5b, 95/08/09
       Mount count:              6
       Maximum mount count:      20

hdparm

  List or change hard disk parameters. This command must be invoked as root, and it may be dangerous if misused.

fdisk

  Create or change a partition table on a storage device, usually a hard drive. This command must be invoked as root.

  | Use this command with extreme caution. If something goes wrong, you may destroy an existing filesystem.

fsck, e2fsck, debugfs

  Filesystem check, repair, and debug command set.

  fsck: a front end for checking a UNIX filesystem (may invoke other utilities). The actual filesystem type generally defaults to ext2.

  e2fsck: ext2 filesystem checker.

  debugfs: ext2 filesystem debugger. One of the uses of this versatile, but dangerous command is to (attempt to) recover deleted files. For advanced users only!

  | All of these should be invoked as root, and they can damage or destroy a filesystem if misused.

badblocks

  Checks for bad blocks (physical media flaws) on a storage device. This command finds use when formatting a newly installed hard drive or testing the integrity of backup media. [4] As an example, badblocks /dev/fd0 tests a floppy disk.

  The badblocks command may be invoked destructively (overwrite all data) or in non-destructive read-only mode. If root user owns the device to be tested, as is generally the case, then root must invoke this command.

lsusb, usbmodules

  The lsusb command lists all USB (Universal Serial Bus) buses and the devices hooked up to them.

  The usbmodules command outputs information about the driver modules for connected USB devices.

       bash$ lsusb
       Bus 001 Device 001: ID 0000:0000
       Device Descriptor:
         bLength                18
         bDescriptorType         1
         bcdUSB               1.00
         bDeviceClass            9 Hub
         bDeviceSubClass         0
         bDeviceProtocol         0
         bMaxPacketSize0         8
         idVendor           0x0000
         idProduct          0x0000

         . . .

lspci

  Lists pci busses present.

       bash$ lspci
       00:00.0 Host bridge: Intel Corporation 82845 845
       (Brookdale) Chipset Host Bridge (rev 04)
       00:01.0 PCI bridge: Intel Corporation 82845 845
       (Brookdale) Chipset AGP Bridge (rev 04)
       00:1d.0 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #1) (rev 02)
       00:1d.1 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #2) (rev 02)
       00:1d.2 USB Controller: Intel Corporation 82801CA/CAM USB (Hub #3) (rev 02)
       00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 42)

         . . .

mkbootdisk

  Creates a boot floppy which can be used to bring up the system if, for example, the MBR (master boot record) becomes corrupted. Of special interest is the `--iso` option, which uses mkisofs to create a bootable ISO9660 filesystem image suitable for burning a bootable CDR.

  The mkbootdisk command is actually a Bash script, written by Erik Troan, in the `/sbin` directory.

mkisofs

  Creates an ISO9660 filesystem suitable for a CDR image.

chroot

  CHange ROOT directory. Normally commands are fetched from $PATH, relative to `/`, the default root directory. This changes the root directory to a different one (and also changes the working directory to there). This is useful for security purposes, for instance when the system administrator wishes to restrict certain users, such as those telnetting in, to a secured portion of the filesystem (this is sometimes referred to as confining a guest user to a "chroot jail"). Note that after a chroot, the execution path for system binaries is no longer valid.

  A `chroot /opt` would cause references to `/usr/bin` to be translated to `/opt/usr/bin`. Likewise, `chroot /aaa/bbb /bin/ls` would redirect future instances of ls to `/aaa/bbb` as the base directory, rather than `/` as is normally the case. An alias XX 'chroot /aaa/bbb ls' in a user's `~/.bashrc` effectively restricts which portion of the filesystem she may run command "XX" on.

  The chroot command is also handy when running from an emergency boot floppy (chroot to `/dev/fd0`), or as an option to lilo when recovering from a system crash. Other uses include installation from a different filesystem (an rpm option) or running a readonly filesystem from a CD ROM. Invoke only as root, and use with care.

  | It might be necessary to copy certain system files to a chrooted directory, since the normal `$PATH` can no longer be relied upon.

lockfile

  This utility is part of the procmail package (www.procmail.org). It creates a lock file, a semaphore that controls access to a file, device, or resource.

  The lock file serves as a flag that this particular file, device, or resource is in use by a process (and is therefore "busy"). The presence of a lock file permits only restricted access (or no access) to other processes.

         1 lockfile /home/bozo/lockfiles/$0.lock
         2 # Creates a write-protected lockfile prefixed with the name of the script.
         3
         4 lockfile /home/bozo/lockfiles/${0##*/}.lock
         5 # A safer version of the above, as pointed out by E. Choroba.

  Lock files are used in such applications as protecting system mail folders from simultaneously being changed by multiple users, indicating that a modem port is being accessed, and showing that an instance of Firefox is using its cache. Scripts may check for the existence of a lock file created by a certain process to check if that process is running. Note that if a script attempts to create a lock file that already exists, the script will likely hang.

  Normally, applications create and check for lock files in the `/var/lock` directory. [5] A script can test for the presence of a lock file by something like the following.

         1 appname=xyzip
         2 # Application "xyzip" created lock file "/var/lock/xyzip.lock".
         3
         4 if [ -e "/var/lock/$appname.lock" ]
         5 then   #+ Prevent other programs & scripts
         6        #  from accessing files/resources used by xyzip.
         7   ...

flock

  Much less useful than the lockfile command is flock. It sets an "advisory" lock on a file and then executes a command while the lock is on. This is to prevent any other process from setting a lock on that file until completion of the specified command.

         1 flock $0 cat $0 > lockfile__$0
         2 #  Set a lock on the script the above line appears in,
         3 #+ while listing the script to stdout.

  | Unlike lockfile, flock does not automatically create a lock file.

mknod

  Creates block or character device files (may be necessary when installing new hardware on the system). The MAKEDEV utility has virtually all of the functionality of mknod, and is easier to use.

MAKEDEV

  Utility for creating device files. It must be run as root, and in the `/dev` directory. It is a sort of advanced version of mknod.

tmpwatch

  Automatically deletes files which have not been accessed within a specified period of time. Usually invoked by cron to remove stale log files.

Backup

dump, restore

  The dump command is an elaborate filesystem backup utility, generally used on larger installations and networks. [6] It reads raw disk partitions and writes a backup file in a binary format. Files to be backed up may be saved to a variety of storage media, including disks and tape drives. The restore command restores backups made with dump.

fdformat

  Perform a low-level format on a floppy disk (`/dev/fd0*`).

System Resources

ulimit

  Sets an upper limit on use of system resources. Usually invoked with the `-f` option, which sets a limit on file size (ulimit -f 1000 limits files to 1 meg maximum). [7] The `-t` option limits the coredump size (ulimit -c 0 eliminates coredumps). Normally, the value of ulimit would be set in `/etc/profile` and/or `~/.bash_profile` (see Appendix H).

  Judicious use of ulimit can protect a system against the dreaded fork bomb.

         1 #!/bin/bash
         2 # This script is for illustrative purposes only.
         3 # Run it at your own peril -- it WILL freeze your system.
         4
         5 while true  #  Endless loop.
         6 do
         7   $0 &      #  This script invokes itself . . .
         8             #+ forks an infinite number of times . . .
         9             #+ until the system freezes up because all resources exhausted.
        10 done        #  This is the notorious "sorcerer's appentice" scenario.
        11
        12 exit 0      #  Will not exit here, because this script will never terminate.

  A ulimit -Hu XX (where XX is the user process limit) in `/etc/profile` would abort this script when it exceeded the preset limit.

quota

  Display user or group disk quotas.

setquota

  Set user or group disk quotas from the command-line.

umask

  User file creation permissions mask. Limit the default file attributes for a particular user. All files created by that user take on the attributes specified by umask. The (octal) value passed to umask defines the file permissions disabled. For example, umask 022 ensures that new files will have at most 755 permissions (777 NAND 022). [8] Of course, the user may later change the attributes of particular files with chmod. The usual practice is to set the value of umask in `/etc/profile` and/or `~/.bash_profile` (see Appendix H).

  Example 17-10. Using umask to hide an output file from prying eyes

         1 #!/bin/bash
         2 # rot13a.sh: Same as "rot13.sh" script, but writes output to "secure" file.
         3
         4 # Usage: ./rot13a.sh filename
         5 # or     ./rot13a.sh <filename
         6 # or     ./rot13a.sh and supply keyboard input (stdin)
         7
         8 umask 177               #  File creation mask.
         9                         #  Files created by this script
        10                         #+ will have 600 permissions.
        11
        12 OUTFILE=decrypted.txt   #  Results output to file "decrypted.txt"
        13                         #+ which can only be read/written
        14                         #  by invoker of script (or root).
        15
        16 cat "$@" | tr 'a-zA-Z' 'n-za-mN-ZA-M' > $OUTFILE
        17 #    ^^ Input from stdin or a file.   ^^^^^^^^^^ Output redirected to file.
        18
        19 exit 0

rdev

  Get info about or make changes to root device, swap space, or video mode. The functionality of rdev has generally been taken over by lilo, but rdev remains useful for setting up a ram disk. This is a dangerous command, if misused.

Modules

lsmod

  List installed kernel modules.

       bash$ lsmod
       Module                  Size  Used by
       autofs                  9456   2 (autoclean)
       opl3                   11376   0
       serial_cs               5456   0 (unused)
       sb                     34752   0
       uart401                 6384   0 [sb]
       sound                  58368   0 [opl3 sb uart401]
       soundlow                 464   0 [sound]
       soundcore               2800   6 [sb sound]
       ds                      6448   2 [serial_cs]
       i82365                 22928   2
       pcmcia_core            45984   0 [serial_cs ds i82365]

  | Doing a cat /proc/modules gives the same information.

insmod

  Force installation of a kernel module (use modprobe instead, when possible). Must be invoked as root.

rmmod

  Force unloading of a kernel module. Must be invoked as root.

modprobe

  Module loader that is normally invoked automatically in a startup script. Must be invoked as root.

depmod

  Creates module dependency file. Usually invoked from a startup script.

modinfo

  Output information about a loadable module.

       bash$ modinfo hid
       filename:    /lib/modules/2.4.20-6/kernel/drivers/usb/hid.o
       description: "USB HID support drivers"
       author:      "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>"
       license:     "GPL"

Miscellaneous

env

  Runs a program or script with certain environmental variables set or changed (without changing the overall system environment). The `[varname=xxx]` permits changing the environmental variable `varname` for the duration of the script. With no options specified, this command lists all the environmental variable settings. [9]

  The first line of a script (the "sha-bang" line) may use env when the path to the shell or interpreter is unknown.

         1 #! /usr/bin/env perl
         2
         3 print "This Perl script will run,\n";
         4 print "even when I don't know where to find Perl.\n";
         5
         6 # Good for portable cross-platform scripts,
         7 # where the Perl binaries may not be in the expected place.
         8 # Thanks, S.C.

  Or even ...

         1 #!/bin/env bash
         2 # Queries the $PATH enviromental variable for the location of bash.
         3 # Therefore ...
         4 # This script will run where Bash is not in its usual place, in /bin.
         5 ...

ldd

  Show shared lib dependencies for an executable file.

       bash$ ldd /bin/ls
       libc.so.6 => /lib/libc.so.6 (0x4000c000)
      /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)

watch

  Run a command repeatedly, at specified time intervals.

  The default is two-second intervals, but this may be changed with the `-n` option.

         1 watch -n 5 tail /var/log/messages
         2 # Shows tail end of system log, /var/log/messages, every five seconds.

  | Unfortunately, piping the output of watch command to grep does not work.

strip

  Remove the debugging symbolic references from an executable binary. This decreases its size, but makes debugging it impossible.

  This command often occurs in a Makefile, but rarely in a shell script.

nm

  List symbols in an unstripped compiled binary.

xrandr

  Command-line tool for manipulating the root window of the screen.

  Example 17-11. Backlight: changes the brightness of the (laptop) screen backlight

         1 #!/bin/bash
         2 # backlight.sh
         3 # reldate 02dec2011
         4
         5 #  A bug in Fedora Core 16/17 messes up the keyboard backlight controls.
         6 #  This script is a quick-n-dirty workaround, essentially a shell wrapper
         7 #+ for xrandr. It gives more control than on-screen sliders and widgets.
         8
         9 OUTPUT=$(xrandr | grep LV | awk '{print $1}')   # Get display name!
        10 INCR=.05      # For finer-grained control, set INCR to .03 or .02.
        11
        12 old_brightness=$(xrandr --verbose | grep rightness | awk '{ print $2 }')
        13
        14
        15 if [ -z "$1" ]
        16 then
        17   bright=1    # If no command-line arg, set brightness to 1.0 (default).
        18
        19   else
        20     if [ "$1" = "+" ]
        21     then
        22       bright=$(echo "scale=2; $old_brightness + $INCR" | bc)   # +.05
        23
        24   else
        25     if [ "$1" = "-" ]
        26     then
        27       bright=$(echo "scale=2; $old_brightness - $INCR" | bc)   # -.05
        28
        29   else
        30     if [ "$1" = "#" ]   # Echoes current brightness; does not change it.
        31     then
        32       bright=$old_brightness
        33
        34   else
        35     if [[ "$1" = "h" || "$1" = "H" ]]
        36     then
        37       echo
        38       echo "Usage:"
        39       echo "$0 [No args]    Sets/resets brightness to default (1.0)."
        40       echo "$0 +            Increments brightness by 0.5."
        41       echo "$0 -            Decrements brightness by 0.5."
        42       echo "$0 #            Echoes current brightness without changing it."
        43       echo "$0 N (number)   Sets brightness to N (useful range .7 - 1.2)."
        44       echo "$0 h [H]        Echoes this help message."
        45       echo "$0 any-other    Gives xrandr usage message."
        46
        47       bright=$old_brightness
        48
        49   else
        50     bright="$1"
        51
        52       fi
        53      fi
        54     fi
        55   fi
        56 fi
        57
        58
        59 xrandr --output "$OUTPUT" --brightness "$bright"   # See xrandr manpage.
        60                                                    # As root!
        61 E_CHANGE0=$?
        62 echo "Current brightness = $bright"
        63
        64 exit $E_CHANGE0
        65
        66
        67 # =========== Or, alternately . . . ==================== #
        68
        69 #!/bin/bash
        70 # backlight2.sh
        71 # reldate 20jun2012
        72
        73 #  A bug in Fedora Core 16/17 messes up the keyboard backlight controls.
        74 #  This is a quick-n-dirty workaround, an alternate to backlight.sh.
        75
        76 target_dir=\
        77 /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/backlight/acpi_video0
        78 # Hardware directory.
        79
        80 actual_brightness=$(cat $target_dir/actual_brightness)
        81 max_brightness=$(cat $target_dir/max_brightness)
        82 Brightness=$target_dir/brightness
        83
        84 let "req_brightness = actual_brightness"   # Requested brightness.
        85
        86 if [ "$1" = "-" ]
        87 then     # Decrement brightness 1 notch.
        88   let "req_brightness = $actual_brightness - 1"
        89 else
        90   if [ "$1" = "+" ]
        91   then   # Increment brightness 1 notch.
        92     let "req_brightness = $actual_brightness + 1"
        93    fi
        94 fi
        95
        96 if [ $req_brightness -gt $max_brightness ]
        97 then
        98   req_brightness=$max_brightness
        99 fi   # Do not exceed max. hardware design brightness.
       100
       101 echo
       102
       103 echo "Old brightness = $actual_brightness"
       104 echo "Max brightness = $max_brightness"
       105 echo "Requested brightness = $req_brightness"
       106 echo
       107
       108 # =====================================
       109 echo $req_brightness > $Brightness
       110 # Must be root for this to take effect.
       111 E_CHANGE1=$?   # Successful?
       112 # =====================================
       113
       114 if [ "$?" -eq 0 ]
       115 then
       116   echo "Changed brightness!"
       117 else
       118   echo "Failed to change brightness!"
       119 fi
       120
       121 act_brightness=$(cat $Brightness)
       122 echo "Actual brightness = $act_brightness"
       123
       124 scale0=2
       125 sf=100 # Scale factor.
       126 pct=$(echo "scale=$scale0; $act_brightness / $max_brightness * $sf" | bc)
       127 echo "Percentage brightness = $pct%"
       128
       129 exit $E_CHANGE1

rdist

  Remote distribution client: synchronizes, clones, or backs up a file system on a remote server.

# 17.1. Analyzing a System Script

Using our knowledge of administrative commands, let us examine a system script. One of the shortest and simplest to understand scripts is "killall," [10] used to suspend running processes at system shutdown.

Example 17-12. killall, from `/etc/rc.d/init.d`

       1 #!/bin/sh
       2
       3 # --> Comments added by the author of this document marked by "# -->".
       4
       5 # --> This is part of the 'rc' script package
       6 # --> by Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>.
       7
       8 # --> This particular script seems to be Red Hat / FC specific
       9 # --> (may not be present in other distributions).
      10
      11 #  Bring down all unneeded services that are still running
      12 #+ (there shouldn't be any, so this is just a sanity check)
      13
      14 for i in /var/lock/subsys/*; do
      15         # --> Standard for/in loop, but since "do" is on same line,
      16         # --> it is necessary to add ";".
      17         # Check if the script is there.
      18         [ ! -f $i ] && continue
      19         # --> This is a clever use of an "and list", equivalent to:
      20         # --> if [ ! -f "$i" ]; then continue
      21
      22         # Get the subsystem name.
      23         subsys=${i#/var/lock/subsys/}
      24         # --> Match variable name, which, in this case, is the file name.
      25         # --> This is the exact equivalent of subsys=`basename $i`.
      26
      27         # -->  It gets it from the lock file name
      28         # -->+ (if there is a lock file,
      29         # -->+ that's proof the process has been running).
      30         # -->  See the "lockfile" entry, above.
      31
      32
      33         # Bring the subsystem down.
      34         if [ -f /etc/rc.d/init.d/$subsys.init ]; then
      35            /etc/rc.d/init.d/$subsys.init stop
      36         else
      37            /etc/rc.d/init.d/$subsys stop
      38         # -->  Suspend running jobs and daemons.
      39         # -->  Note that "stop" is a positional parameter,
      40         # -->+ not a shell builtin.
      41         fi
      42 done

That wasn't so bad. Aside from a little fancy footwork with variable matching, there is no new material there.

Exercise 1. In `/etc/rc.d/init.d`, analyze the halt script. It is a bit longer than killall, but similar in concept. Make a copy of this script somewhere in your home directory and experiment with it (do not run it as root). Do a simulated run with the `-vn` flags (`sh -vn scriptname`). Add extensive comments. Change the commands to echos.

Exercise 2. Look at some of the more complex scripts in `/etc/rc.d/init.d`. Try to understand at least portions of them. Follow the above procedure to analyze them. For some additional insight, you might also examine the file `sysvinitfiles` in `/usr/share/doc/initscripts-?.??`, which is part of the "initscripts" documentation.

### Notes

[1] | This is the case on a Linux machine or a UNIX system with disk quotas.
[2] | The userdel command will fail if the particular user being deleted is still logged on.
[3] | For more detail on burning CDRs, see Alex Withers' article, Creating CDs, in the October, 1999 issue of Linux Journal.
[4] | The `-c` option to mke2fs also invokes a check for bad blocks.
[5] | Since only root has write permission in the `/var/lock` directory, a user script cannot set a lock file there.
[6] | Operators of single-user Linux systems generally prefer something simpler for backups, such as tar.
[7] | As of the version 4 update of Bash, the `-f` and `-c` options take a block size of 512 when in POSIX mode. Additionally, there are two new options: `-b` for socket buffer size, and `-T` for the limit on the number of threads.
[8] | NAND is the logical not-and operator. Its effect is somewhat similar to subtraction.

[9]

In Bash and other Bourne shell derivatives, it is possible to set variables in a single command's environment.

       1 var1=value1 var2=value2 commandXXX
       2 # $var1 and $var2 set in the environment of 'commandXXX' only.

[10] | The killall system script should not be confused with the killall command in `/usr/bin`.

Prev | Home | Next
Miscellaneous Commands | Up | Advanced Topics