# Reading [The Linux Kernel Module Programming Guide](https://sysprog21.github.io/lkmpg/) (9) 這裡要先回顧init script ``` #!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo -e "\n\nWelcome to BusyBox RootFS on RISC-V!" /bin/sh ``` 這一支程式run起來之後可以用`ps -eo pid,ppid,sid,tty,comm`查看現在有哪些process,以及他們的PID,PPID,SID,TTY,COMMAND。可能會像這樣 ``` PID PPID SID TT COMMAND 1 0 0 ? init 2 0 0 ? kthreadd 3 2 0 ? pool_workqueue_ 4 2 0 ? kworker/R-rcu_g ... 68 2 0 ? jbd2/vda-8 69 2 0 ? kworker/R-ext4- 73 1 0 ? sh 74 2 0 ? kworker/u17:1-e ``` 可以看到sh的個process的PID(Process ID)是73,SID(Session ID)是0。一個session只有一個tty,然而session 0的tty是沒有指定的,雖然我們開啟QEMU有設定console=ttyS0,system log跟stdin/out會預設在ttyS0,前面有說過tty是char device,它也有定義自己的tty_operations,只不過它加了很多mutex去管理tty的操作非常複雜,這邊就當作device去操作就可以了。因為stdin/out都指向他,即便sh的tty沒有設定,在只使用到system log和stdin/out的時候看起來就還蠻正常的,但是應該會發現Ctrl-C,Ctrl-D之類的中斷訊號它不會理你。程式出錯就要Ctrl-a/ x,結束QEMU。缺點就是signal沒辦法正常讀取,tty有很大一部份就是在處理同個session不同process間的signal。 在13章講到tty,在這個沒有tty的情況下會跑不動這個範例,最簡單的解法就是改init script讓bin/sh執行再有設定好tty的session上面。 ``` #!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo -e "\n\nWelcome to BusyBox RootFS on RISC-V!" exec setsid sh -c 'exec sh </dev/ttyS0 >/dev/ttyS0 2>&1' ``` 這邊改動了sh的stdio,將他們設定成我們想要的ttyS0,以便我們觀察輸出,但是就邏輯上來說設定stdin...是不會改到session的tty,這邊利用了[tty_open()](https://elixir.bootlin.com/linux/v6.15-rc7/source/drivers/tty/tty_io.c#L2177)的機制,如果tty_open發生的process沒有tty設定,那麼就會將開啟的這個tty自動設定好。在執行sh的io redirect的過程會對ttyS0發出open的syscall,tty_operation對應處理的就是tty_open,所以整件事情就會隱晦的設定完成。這個時候再看`ps -eo pid,ppid,sid,tty,comm`,會發現PID 1的session變成1了(順帶一提session id會是session leader的PID),tty也不再是?了。 ``` ~ # ps -eo pid,ppid,sid,tty,comm PID PPID SID TT COMMAND 1 0 1 4,64 sh 2 0 0 ? kthreadd 3 2 0 ? pool_workqueue_ 4 2 0 ? kworker/R-rcu_g 5 2 0 ? kworker/R-sync_ 6 2 0 ? kworker/R-kvfre ``` 另外之前開啟QEMU時會出現`/bin/sh: can't access tty; job control turned off`,有點討厭的訊息,在正確設定好tty之後也就消失了,所以之後的init就都會改成這樣。