< Day Day Up > |
1.6. The Environment and InheritanceWhen you log on, the shell starts up and inherits a number of variables, I/O streams, and process characteristics from the /bin/login program that started it. In turn, if another shell is spawned (forked) from the login or parent shell, that child shell (subshell) will inherit certain characteristics from its parent. A subshell may be started for a number of reasons: for handling background processing, for handling groups of commands, or for executing scripts. The child shell inherits the environment of its parent. The environment consists of process permissions (who owns the process), the working directory, the file creation mask, special variables, open files, and signals. 1.6.1 Ownership and PermissionsWhen you log on, the shell is given an identity. It has a real user identification (UID), one or more real group identifications (GID), and an effective user identification and effective group identification (EUID and EGID). The EUID and EGID are initially the same as the real UID and GID. These ID numbers are found in the etc/passwd file and are used by the system to identify users and groups. The EUID and EGID determine what permissions a process has access to when reading, writing, or executing files. If the EUID of a process and the real UID of the owner of the file are the same, the process has the owner's access permissions for the file. If the EGID and real GID of a process are the same, the process has the owner's group privileges. The real UID is the third entry in the /etc/passwd file. Its value is a positive integer that is associated with your login name. When you log on, the login shell is assigned the real UID and all processes spawned from the login shell inherit its permissions. Any process running with a UID of zero belongs to root (the superuser) and has root privileges. The real group identification, the GID, associates a group with your login name. It is found in the fourth field of the /etc/passwd file. You can use the id command to see these values, as shown in Example 1.6. Example 1.6.1 $ id uid=502(ellie) gid=502(ellie) The EUID and EGID can be changed to numbers assigned to a different owner. By changing the EUID (or EGID) to another owner, you can become the owner of a process that belongs to someone else. Programs that change the EUID or EGID to another owner are called setuid or setgid programs. The passwd program is an example of a setuid program that gives the user root privileges. This enables an ordinary user to change his password, and update the passwd file (accessible only to root) without calling for a system administrator. The user temporarily becomes the superuser, root, as long as the passwd program is running because his effective user ID is temporarily is set to root. Setuid programs are often sources for security holes. The shell allows you to create setuid scripts, and the shell itself may be a setuid program. (See Chapter 16, "The System Administrator and the Shell." 1.6.2 The File Creation MaskWhen a file is created it is given a set of default permissions. These permissions are determined by the program creating the file. Child processes inherit a default mask from their parents. The user can change the mask for the shell by issuing the umask command at the prompt or by setting it in the shell's initialization files. The umask command is used to remove permissions from the existing mask. Initially, the umask is 000, giving a directory 777 (rwxrwxrwx) permissions and a file 666 (rw-rw-rw-) permissions as the default. On most systems, the umask is assigned a value of 022 by the /bin/login program or the /etc/profile initialization file. The umask value is subtracted from the default settings for both the directory and file permissions as follows: 777 (Directory) 666 (File) –022 (umask value) –022 (umask value) ------- --------- 755 644 Result: drwxr-xr-x -rw-r--r-- After the umask is set, all directories and files created by this process are assigned the new default permissions. In this example, directories will be given read, write, and execute for the owner; read and execute for the group; and read and execute for the rest of the world (others). Any files created will be assigned read and write for the owner, and read for the group and others. To change permissions on individual directories and permissions, the chmod command is used. 1.6.3 Changing Permissions and OwnershipThe chmod CommandThe chmod command changes permissions on files and directories. Every UNIX/Linux file has a set of permissions associated with it to control who can read, write, or execute the file. There is one owner for every UNIX/Linux file and only the owner or the superuser can change the permissions on a file or directory. A group may have a number of members, and the owner of the file may change the group permissions on a file so that the group can enjoy special privileges. To see what permissions a file has, type at the shell prompt:
ls -l filename
A total of nine bits constitutes the permissions on a file. The first set of three bits controls the permissions of the owner of the file, the second set controls the permissions of the group, and the last set controls the permissions for everyone else. The permissions are stored in the mode field of the file's inode. The user must own the files to change permissions on them.[7]
Table 1.1 illustrates the eight possible combinations of numbers used for changing permissions.
Example 1.7.1 $ chmod 755 file $ ls –l file –rwxr–xr–x 1 ellie 0 Mar 7 12:52 file 2 $ chmod g+w file $ ls -l file –rwxrwxr-x 1 ellie 0 Mar 7 12:54 file 3 $ chmod go-rx file $ ls -l file –rwx-w---- 1 ellie 0 Mar 7 12:56 file 4 $ chmod a=r file $ ls -l file –r--r--r-- 1 ellie 0 Mar 7 12:59 file EXPLANATION
The chown CommandThe chown command changes the owner and group on files and directories. If using Linux, only the superuser, root, can change ownership. If using UNIX, the owner of the file or the superuser can change the ownership. To see the usage and options for chown, check the man pages (UNIX) or use the chown command with the – –help (Linux) option as shown in Example 1.8. Example 1.9 demonstrates how to use chown. Example 1.8.
(The Command Line)
# chown --help
Usage: chown [OPTION]... OWNER[.[GROUP]] FILE...
or: chown [OPTION]... .[GROUP] FILE...
Change the owner and/or group of each FILE to OWNER and/or GROUP.
-c, --changes be verbose whenever change occurs
-h, --no-dereference affect symbolic links instead of any referenced file
(available only on systems with lchown system call)
-f, --silent, --quiet suppress most error messages
-R, --recursive operate on files and directories recursively
-v, --verbose explain what is being done
--help display this help and exit
--version output version information and exit
Owner is unchanged if missing. Group is unchanged if missing, but changed to login group
if implied by a period. A colon may replace the period.
Report bugs to fileutils-bugs@gnu.ai.mit.edu
Example 1.9.(The Command Line) 1 $ ls -l filetest -rw-rw-r-- 1 ellie ellie 0 Jan 10 12:19 filetest 2 $ chown root filetest chown: filetest: Operation not permitted 3 $ su root Password: 4 # ls -l filetest -rw-rw-r-- 1 ellie ellie 0 Jan 10 12:19 filetest 5 # chown root filetest 6 # ls -l filetest -rw-rw-r-- 1 root ellie 0 Jan 10 12:19 filetest 7 # chown root:root filetest 8 # ls -l filetest -rw-rw-r-- 1 root root 0 Jan 10 12:19 filetest EXPLANATION
1.6.4 The Working DirectoryWhen you log on, you are given a working directory within the file system, called the home directory. The working directory is inherited by processes spawned from this shell. Any child process of this shell can change its own working directory, but the change will have no effect on the parent shell. The cd command, used to change the working directory, is a shell built-in command. Each shell has its own copy of cd. A built-in command is executed directly by the shell as part of the shell's code; the shell does not perform the fork and exec system calls when executing built-in commands. If another shell (script) is forked from the parent shell, and the cd command is issued in the child shell, the directory will be changed in the child shell. When the child exits, the parent shell will be in the same directory it was in before the child started. Example 1.10.1 > cd / 2 > pwd / 3 > bash 4 $ cd /home 5 $ pwd /home 6 $ exit 7 > pwd / > EXPLANATION
1.6.5 VariablesThe shell can define two types of variables: local and environment. The variables contain information used for customizing the shell, and information required by other processes so that they will function properly. Local variables are private to the shell in which they are created and not passed on to any processes spawned from that shell. The built-in set command will display local variables for C shell and TC shell, and both local and environment variables for Bourne, Bash, and Korn shells. Environment variables, on the other hand, are passed from parent to child process, from child to grandchild, and so on. Some of the environment variables are inherited by the login shell from the /bin/login program. Others are created in the user initialization files, in scripts, or at the command line. If an environment variable is set in the child shell, it is not passed back to the parent. The shell env command will display the environment variables. Example 1.11 lists environment variables for a user running Solaris 5.9 with the Bash shell. Example 1.11.$ env PWD=/home/ellie TZ=US/Pacific PAGER=less HOSTNAME=artemis LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/usr/dt/lib:/usr/openwin/lib MANPATH=/usr/local/man:/usr/man:/usr/openwin/man:/opt/httpd/man USER=ellie MACHTYPE=sparc–sun–solaris2.9 TCL_LIBRARY=/usr/local/lib/tcl8.0 EDITOR=vi LOGNAME=ellie SHLVL=1 SHELL=/bin/bash HOSTTYPE=sparc OSTYPE=solaris2.9 HOME=/home/ellie TERM=xterm TK_LIBRARY=/usr/local/lib/tk8.0 PATH=/bin:/usr/bin:/usr/local/bin:/usr/local/etc:/usr/ccs/bin:/usr/etc:/usr/ucb:/usr/ local/X11:/usr/openwin/bin:/etc:. SSH_TTY=/dev/pts/10 _=/bin/env 1.6.6 Redirection and PipesFile DescriptorsAll I/O, including files, pipes, and sockets, is handled by the kernel via a mechanism called the file descriptor. A file descriptor is a small unsigned integer, an index into a file-descriptor table maintained by the kernel and used by the kernel to reference open files and I/O streams. Each process inherits its own file-descriptor table from its parent. The first three file descriptors, 0, 1, and 2, are assigned to your terminal. File descriptor 0 is standard input (stdin), 1 is standard output (stdout), and 2 is standard error (stderr). When you open a file, the next available descriptor is 3, and it will be assigned to the new file. If all the available file descriptors are in use,[8] a new file cannot be opened.
RedirectionWhen a file descriptor is assigned to something other than a terminal, it is called I/O redirection. The shell performs redirection of output to a file by closing the standard output file descriptor, 1 (the terminal), and then assigning that descriptor to the file (see Figure 1.5). When redirecting standard input, the shell closes file descriptor 0 (the terminal) and assigns that descriptor to a file (see Figure 1.6). The Bourne, Bash, and Korn shells handle errors by assigning a file to file descriptor 2 (see Figure 1.7). The C and TC shells, on the other hand, go through a more complicated process to do the same thing (see Figure 1.8). Example 1.12.1 $ who > file 2 $ cat file1 file2 >> file3 3 $ mail tom < file 4 $ find / -name file -print 2> errors 5 % ( find / -name file -print > /dev/tty) >& errors Figure 1.5. Redirection of standard output.Figure 1.6. Redirection of standard input.Figure 1.7. Redirection of standard error (Bourne, Bash, and Korn shells).Figure 1.8. Redirection of standard error (C and TC shells).EXPLANATION
PipesA pipe is the oldest form of UNIX interprocess communication. A pipe allows processes to communicate with each other. It is a mechanism whereby the output of one command is sent as input to another command, with the limitation that data can only flow in one direction, normally between a parent and a child. The shell implements pipes by closing and opening file descriptors; however, instead of assigning the descriptors to a file, it assigns them to a pipe descriptor created with the pipe system call. After the parent creates the pipe file descriptors, it forks a child process for each command in the pipeline. By having each process manipulate the pipe descriptors, one will write to the pipe and the other will read from it. To simplify things, a pipe is merely a kernel buffer from which both processes can share data, thus eliminating the need for intermediate temporary files. The output of one command is sent to the buffer, and when the buffer is full or the command has terminated, the command on the right-hand side of the pipe reads from the buffer. The kernel synchronizes the activities so that one process waits while the other reads from or writes to the buffer. The syntax of the pipe command is who | wc In order to accomplish the same thing without a pipe, it would take three steps: who > tempfile wc tempfile rm tempfile With the pipe, the shell sends the output of the who command as input to the wc command; that is, the command on the left-hand side of the pipe writes to the pipe and the command on the right-hand side of the pipe reads from it (see Figure 1.9). You can tell if a command is a writer if it normally sends output to the screen when run at the command line. The ls, ps, and date commands are examples of writers. A reader is a command that waits for input from a file or from the keyboard or from a pipe. The sort, wc, and cat commands are examples of readers. Figure 1.9. The pipe.Figures 1.10 through 1.14 illustrate the steps for implementing the pipe. Figure 1.10. The parent calls the pipe system call for setting up a pipeline.Figure 1.14. The output of who is sent to the input of wc.Figure 1.11. The parent forks two child processes, one for each command in the pipeline.Figure 1.12. The first child is prepared to write to the pipe.Figure 1.13. The second child is prepared to read input from the pipe.1.6.7 The Shell and SignalsA signal sends a message to a process and normally causes the process to terminate, usually due to some unexpected event such as a hangup, bus error, or power failure, or by a program error such as illegal division by zero or an invalid memory reference. Signals can also be sent to a process by pressing certain key sequences. For example, you can send or deliver signals to a process by pressing the Break, Delete, Quit, or Stop keys, and all processes sharing the terminal are affected by the signal sent. You can kill a process with the kill command. By default, most signals terminate the program. Each process can take an action in response to a given signal:
The Bourne, Bash, and Korn shells allow you to handle signals coming into your program, (see "Trapping Signals" on page 378 for programming in the Bourne shell; "Trapping Signals" on page 716 for programming in the Korn shell; and "Trapping Signals" on page 935 for programing in the Bash shell) either by ignoring the signal, by specifying some action to be taken when a specified signal arrives, or by resetting the signal back to its default action. The C and TC shells are limited to handling ^C (Ctrl-C), the interrupt character. Table 1.2 lists the standard signals that a process can use.
|