3.26. /dev and /proc

A Linux or UNIX machine typically has two special-purpose directories, /dev and /proc. The /dev directory contains entries for the physical devices that may or may not be present in the hardware. [1] The /proc directory is actually a pseudo-filesystem. The files in the /proc directory mirror currently running system and kernel processes and contain information and statistics about them.

 bash$ cat /proc/devices
 Character devices:
   1 mem
   2 pty
   3 ttyp
   4 ttyS
   5 cua
   7 vcs
  10 misc
  14 sound
  29 fb
  36 netlink
 128 ptm
 136 pts
 162 raw
 254 pcmcia

 Block devices:
   1 ramdisk
   2 fd
   3 ide0
   9 md
 
 bash$ cat /dev/sndstat | grep Audio
 Audio devices:
 0: ESS ES1688 AudioDrive (rev 11) (3.01)
          

Note

As of the 2.3 (and 2.4) kernel, /dev/sndstat has been deprecated.

The /dev directory contains loopback devices, such as /dev/loop0. A loopback device is a gimmick allows an ordinary file to be accessed as if it were a block device. [2] This enables mounting an entire filesystem within a single large file. See Example 3-116 and Example 3-114.

Shell scripts may extract data from certain of the files in /dev and /proc. [3]

   1 kernel_version=$( awk '{ print $3 }' /proc/version )

   1 CPU=$( awk '/model name/ {print $4}' < /proc/cpuinfo )
   2 
   3 if [ $CPU = Pentium ]
   4 then
   5   run_some_commands
   6   ...
   7 else
   8   run_different_commands
   9   ...
  10 fi

A few of the pseudo-devices in /dev have other specialized uses, such as /dev/zero.

The /proc directory contains subdirectories with unusual numerical names. Every one of these names maps to the process ID of a currently running process. Within each of these subdirectories, there are a number of files that hold useful information about the corresponding process. The stat and status files keep running statistics on the process, the cmdline file holds the command-line arguments the process was invoked with, and the exe file is a symbolic link to the complete path name of the invoking process. There are a few more such files, but these seem to be the most interesting from a scripting standpoint.


Example 3-156. Finding the process associated with a PID

   1 #!/bin/bash
   2 # Process id identifier:
   3 # gives complete path name to process associated with pid.
   4 
   5 ARGNO=1  # Number of arguments the script expects.
   6 E_WRONGARGS=65
   7 E_BADPID=66
   8 E_NOSUCHPROCESS=67
   9 E_NOPERMISSION=68
  10 PROCFILE=exe
  11 
  12 if [ $# -ne $ARGNO ]
  13 then
  14   echo "Usage: `basename $0` PID-number" >&2  # Error message >stderr.
  15   exit $E_WRONGARGS
  16 fi  
  17 
  18 pidno=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 )
  19 # Checks for pid in "ps" listing, field #1.
  20 # Then makes sure it is the actual process, not the process invoked by this script.
  21 # The last "grep $1" filters out this possibility.
  22 if [ -z "$pidno" ]  # If, after all the filtering, the result is a zero-length string,
  23 then                # no running process corresponds to the pid given.
  24   echo "No such process running."
  25   exit $E_NOSUCHPROCESS
  26 fi  
  27 
  28 # Alternatively:
  29 #   if ! ps $1 > /dev/null 2>&1
  30 #   then                # no running process corresponds to the pid given.
  31 #     echo "No such process running."
  32 #     exit $E_NOSUCHPROCESS
  33 #    fi
  34 
  35 
  36 if [ ! -r "/proc/$1/$PROCFILE" ]  # Check for read permission.
  37 then
  38   echo "Process $1 running, but..."
  39   echo "Can't get read permission on /proc/$1/$PROCFILE."
  40   exit $E_NOPERMISSION  # Ordinary user can't access some files in /proc.
  41 fi  
  42 
  43 # The last two tests may be replaced by:
  44 #    if ! kill -0 $1 > /dev/null 2>&1 # '0' is not a signal, but
  45                                       # this will test whether it is possible
  46                                       # to send a signal to the process.
  47 #    then echo "PID doesn't exist or you're not its owner" >&2
  48 #    exit $E_BADPID
  49 #    fi
  50 
  51 
  52 
  53 exe_file=$( ls -l /proc/$1 | grep "exe" | awk '{ print $11 }' )
  54 # Or       exe_file=$( ls -l /proc/$1/exe | awk '{print $11}' )
  55 #
  56 # /proc/pid-number/exe is a symbolic link
  57 # to the complete path name of the invoking process.
  58 
  59 if [ -e "$exe_file" ]  # If /proc/pid-number/exe exists...
  60 then                 # the corresponding process exists.
  61   echo "Process #$1 invoked by $exe_file."
  62 else
  63   echo "No such process running."
  64 fi  
  65 
  66 
  67 # This elaborate script can *almost* be replaced by
  68 # ps ax | grep $1 | awk '{ print $5 }'
  69 # However, this will not work...
  70 # because the fifth field of 'ps' is argv[0] of the process,
  71 # not the executable file path.
  72 #
  73 # However, either of the following would work.
  74 #       find /proc/$1/exe -printf '%l\n'
  75 #       lsof -aFn -p $1 -d txt | sed -ne 's/^n//p'
  76 
  77 # Additional commentary by Stephane Chazelas.
  78 
  79 exit 0


Example 3-157. On-line connect status

   1 #!/bin/bash
   2 
   3 PROCNAME=pppd        # ppp daemon
   4 PROCFILENAME=status  # Where to look.
   5 NOTCONNECTED=65
   6 INTERVAL=2  # Update every 2 seconds.
   7 
   8 pidno=$( ps ax | grep -v "ps ax" | grep -v grep | grep $PROCNAME | awk '{ print $1 }' )
   9 # Finding the process number of 'pppd', the 'ppp daemon'.
  10 # Have to filter out the process lines generated by the search itself.
  11 
  12 
  13 if [ -z "$pidno" ]  # If no pid, then process is not running.
  14 then
  15   echo "Not connected."
  16   exit $NOTCONNECTED
  17 else
  18   echo "Connected."; echo
  19 fi
  20 
  21 while [ true ]  # Endless loop, script can be improved here.
  22 do
  23 
  24   if [ ! -e "/proc/$pidno/$PROCFILENAME" ]
  25   # While process running, then "status" file exists.
  26   then
  27     echo "Disconnected."
  28     exit $NOTCONNECTED
  29   fi
  30 
  31 netstat -s | grep "packets received"  # Get some connect statistics.
  32 netstat -s | grep "packets delivered"
  33 
  34 
  35   sleep $INTERVAL
  36   echo; echo
  37 
  38 done
  39 
  40 exit 0
  41 
  42 # As it stands, this script must be terminated with a Control-C.
  43 # Exercises for the reader:
  44 #    Improve the script so it exits on a "q" keystroke.
  45 #    Make the script more user-friendly in other ways.

Warning

In general, it is dangerous to write to the files in /proc, as this can corrupt the filesystem or crash the machine.

Notes

[1]

The entries in /dev provide mount points for physical and virtual devices. These entries use very little drive space.

Some devices, such as /dev/null, /dev/zero, and /dev/urandom are virtual. They are not actual physical devices and exist only in software.

[2]

A block device reads and/or writes data in chunks, or blocks, in contrast to a character device, which acesses data in character units. Examples of block devices are a hard drive and CD ROM drive. An example of a character device is a keyboard.

[3]

Certain system commands, such as procinfo, free, and uptime do this as well.