9.1 Introduction
This chapter describes in detail the process group and the concepts of sessions introduced by posix.1. It also describes the relationship between the login shell (called at login) and all processes started from the login shell.
9.1 terminal Login
The system administrator creates a file named/etc/TTYs. Each terminal device has a row, indicating that the device name is passed to the Getty program. During system self-lifting, the process whose kernel creation process ID is 1 is still the INIT process. The INIT process enters the multi-user State. The INIT process reads the file/etc/TTYs. For each terminal device that is allowed to log on, init calls fork once, And the generated sub-process executes the (EXEC) Getty program. (Init executes the Getty program in an empty environment)
Getty calls the OPEN function for the terminal device and opens the terminal in Read and Write mode. If the device is a modem, open may be stranded in the device driver, knowing that the user is dialing the modem and the call is answered. Once the device is opened, file descriptors 0, 1, and 2 are set to the device. Then, Getty outputs information such as "login:" And waits for the user to type the user name. If the terminal supports multiple speeds, Getty can test special characters to properly change the speed (baud rate) of the terminal)
After you enter the user name, the Getty operation is complete. Then, call the login program. Init calls Getty in an empty environment. Getty creates an environment for login using the terminal name and the environment string described in gettytab.
Login can perform multiple tasks. Because it obtains the user name, it can call getpwnam to obtain the login entry of the password file of the corresponding user. Then, call getpass to display the prompt "Password:", and then read the password entered by the user. It calls crypt to encrypt the password entered by the user and compares it with the pw_passwd field that the user wants to log on to the shadow password file. If the password you typed several times is invalid, login calls exit with parameter 1 to indicate that the login process failed. After the parent process understands the termination of the child process, it will call fork here, and then execute Getty. This terminal repeats the above process.
If the user logs in correctly, login performs the following operations:
-Change the current working directory to the starting directory of the user.
-Call chown to change the ownership of the terminal. The Login User becomes its owner.
-Change the access permission for the terminal device to user read and write.
-Call setgid and initgroups to set the group ID of the process
-Use all information obtained by login to initialize the environment: Start directory, Shell, user name, and a default system path.
-The login process changes to the user ID of the login user and calls the Login Shell of the user.
So far, the login user's login shell starts to run.
9.3 network login
During network login, the connection between the terminal and the computer is not a point-to-point link. In this case, login is only an available service, which is of the same nature as other network services.
In the case of network login, all logins are implemented through the kernel's network interface driver, and you do not know how many such logins will be made. Instead of waiting for every possible login, we must wait for the arrival of a network connection request.
To enable the same software to process both the terminal login and the network login, the system uses a software driver called a Pseudo Terminal, which simulates the running behavior of the serial terminal, map terminal operations to network operations
As part of system startup, init calls a shell to execute the shell script/etc/rc. This shell script starts a daemon process inetd. Once the shell script is terminated, the parent process of inetd becomes init. Inetd waits for the TCP/IP connection request to arrive at the host. When a connection request arrives, it executes a fork once and then the generated sub-process executes the appropriate program.
Assume that a TCP connection request is sent to the Telnet service. Telnet is a remote login application using the TCP protocol. Start the login process by starting the Telnet client process on another host (which is connected to the host of the service process through a certain network) or on the same host:
Telnet hostname
The client process opens a TCP connection to the hostname host. The program started on the host is called the telnet service process. Then, the client process and the service process exchange data through the TCP connection using the Telnet application protocol. What happened was that the user who started the customer process now logged on to the host where the service process is located.
Then, the telnetd process opens a pseudo-terminal device and uses fork to divide it into two processes. The parent process processes communications over network connections, and the child process executes the login program. The Parent and Child processes are connected through pseudo terminals. Before exec is called, the sub-process connects the file descriptors 0, 1 and 2 to the Pseudo Terminal. If the logon is correct, login will execute: change the current working directory to the starting directory, set the login Group ID and user ID, and log on to the user's initial environment. Then login calls exec to replace itself with the Login Shell of the login user.
(When logging on through a terminal or network, we get a login shell, which connects to a terminal device or Pseudo Terminal Device with standard input, output, and standard errors.
9.4 Process Group
The getpgrp function returns the ID of the Process Group of the calling process.
# Include <unistd. h> pid_t getpgrp (void); // return value: ID of the process group that calls the process
A process can join an existing group or create a new process group by calling setpgid.
# Include <unistd. h> int setpgid (pid_t PID, pid_t pgid); // return value: 0 if successful,-1 if an error occurs
9.5 sessions
A session is a collection of one or more Process Groups.
Usually, several processes are programmed in a shell pipeline. The process calls the setsid function to create a new session.
# Include <unistd. h> pid_t setsid (void); // return value: if the result is successful, the ID of the Process Group is returned. If an error occurs, the value-1 is returned.
If the process that calls this function is not the leader of a process group, the function creates a new session and the following three events occur:
(1) This process is used to program the first process of a new session (the first process is the process that creates the session). At this time, this process is the only process in the new session.
(2) This process is called the leader process of a new process group. The new process group ID is the process ID of the called process.
(3) The process has no control terminal. If the process has a control terminal before calling setsid, this connection will also be interrupted.
If the called process is already the leader of a process group, this function returns an error. To ensure that this is not the case, fork is usually called first, then the parent process is terminated, and the child process continues. Because a child process inherits the process group ID of the parent process, and its process ID is newly allocated, the two cannot be equal, so this ensures that the child process is not the leader of a process group.
9.6 control terminal
Sessions and Process Groups have some other features:
-A session can have a control terminal. This is usually a terminal device that is logged on to it (in the case of terminal login) or a Pseudo Terminal Device (in the case of network login)
-The first process of a session established to connect to the control terminal is called a control process.
-Several process groups in a session can be divided into one foreground process group and one or more background process groups.
-If a session has a control terminal, it has a foreground process group, and other process groups in the session are background process groups.
-Whenever you type the terminal interrupt key, the interrupt signal is sent to all processes in the foreground process group.
-Whenever you type the terminal's return key, the exit signal is sent to all processes in the foreground process group.
-If the terminal interface detects that the modem is disconnected, it will send the hanging signal to the control process.
9.7 tcgetpgrp, tcsetpgrp, and tcgetsid Functions
A method is required to notify the kernel of which process group is the foreground process group, so that the terminal device driver can know where to send terminal input and terminal signals.
# Include <unistd. h> pid_t tcgetpgrp (INT filedes); // return value: the ID of the front-end process group if the process is successful, and-1int tcsetpgrp (INT filedes, pid_t pgrpid) if an error occurs ); // return value: if the request succeeds, 0 is returned. If the request fails,-1 is returned.
9.8 job control
Job control requires support in the following three forms:
(1) shell supporting job control
(2) The Terminal Driver in the kernel must support job control.
(3) The kernel must support some job control signals.
9.9 shell execution Program
The last process in the MPs queue is the sub-process of the shell, and the first process in the MPs queue is the sub-process of the last process. The shell is notified when the last process is terminated.
9.10 orphan Process Group
We have mentioned that a process whose parent process has terminated is called an orphan process, which is "adopted" by The INIT process ". Now we need to explain that the entire process group can also be called an orphan"
Instance: 9_1 create an orphan Process Group
1 #include"apue.h" 2 #include<errno.h> 3 4 static void sig_hup(int signo) 5 { 6 printf("SIGHUP received,pid=%d\n",getpid()); 7 } 8 static void pr_ids(char *name) 9 {10 printf("%s:pid=%d,ppid=%d,pgrp=%d,tpgrp=%d\n",name,getpid(),getppid(),11 getpgrp(),tcgetpgrp(STDIN_FILENO));12 fflush(stdout);13 }14 int main()15 {16 char c;17 pid_t pid;18 pr_ids("parent");19 if((pid=fork())<0){20 err_sys("fork error");21 }else if(pid>0){22 sleep(5);23 exit(0);24 }25 else{26 pr_ids("child");27 signal(SIGHUP,sig_hup);28 kill(getpid(),SIGTSTP);29 pr_ids("child");30 if(read(STDIN_FILENO,&c,1)!=1)31 printf("read error from controlling TTY,errno=%d\n",errno);32 exit(0);33 }}