在Linux操作系統啟動時,首先加載的進程就是init進程(ID為1),其余進程都是init進程產生的(fork,然后exec金蟬脫殼),因此系統中所有進程都可以看成是init進程的子孫進程。可以通過ps ajx命令查看任意進程的父進程,進行追溯可以發現,任意進程的開頭都是init進程,init進程起源于0號進程,0號進程實際不存在。
文件與I/O中講過,每個進程都可以通過一個特殊的設備文件/dev/tty訪問它的控制終端。事實上每個終端設備都對應一個不同的設備文件(偽文件,不占用磁盤空間),/dev/tty提供了一個通用的接口,一個進程要訪問它的控制終端既可以通過/dev/tty也可以通過該終端設備所對應的設備文件來訪問。ttyname函數可以由文件描述符查出對應的文件名,該文件描述符必須指向一個終端設備而不能是任意文件。
終端的啟動過程。簡單來說,一個Linux系統啟動,大致經歷如下的步驟: init --> fork --> exec --> getty --> 用戶輸入帳號 --> login --> 輸入密碼 --> exec --> bash(文字終端)。init進程通過fork產生子進程,子進程調用exec函數族成為getty進程,即文字終端登陸界面,登陸成功后再調用exec函數族成為bash終端進程,在該終端中產生的任意子進程的控制終端都是該終端。對于設備終端,init進程fork子進程后,exec提供登陸界面,再exec成為桌面終端,再exec成為設備終端(偽終端)。
計算機的整個架構:計算機硬件→硬件驅動程序→系統調用→應用層,數據流的流向也是如此,對于輸入則為硬件流向應用層(用戶空間),對于輸出則相反。硬件驅動程序負責讀寫實際的硬件設備(包括各種文件,磁盤),比如從鍵盤讀入字符和把字符輸出到顯示器,線路規程(line disciline)像一個過濾器(用來過濾鍵盤輸入的內容),對于某些特殊字符并不是讓它直接通過,而是做特殊處理,比如在鍵盤上按下Ctrl-z,對應的字符并不會被用戶程序的read讀到,而是被線路規程截獲,解釋成SIGTSTP信號發給前臺進程,通常會使該進程停止。線路規程應該過濾哪些字符和做哪些特殊處理是可以配置的。
ttyname函數
由文件描述符查出對應的文件名,該文件描述符必須指向一個終端設備而不能是任意文件。
char *ttyname(int fd);???? 成功:終端名;失敗:NULL,設置errno
//下面我們借助ttyname函數,通過實驗看一下各種不同的終端所對應的設備文件名
#include <unistd.h>
#include <stdio.h>
int main(void)
{printf("fd 0: %s\n", ttyname(0));printf("fd 1: %s\n", ttyname(1));printf("fd 2: %s\n", ttyname(2));return 0;
}
[root@localhost 01_session_daemon_test]# ./ttyname
fd 0: /dev/pts/2
fd 1: /dev/pts/2
fd 2: /dev/pts/2?? ?//可以看見標準輸入、輸出和錯誤輸出對應的終端為pts/2