ls /dev/ -l total 0 crw------- 1 root root 10, 235 8月 16 13:08 autofs drwxr-xr-x 2 root root 720 8月 16 13:08 block drwxr-xr-x 2 root root 80 8月 16 13:08 bsg crw-rw---- 1 root disk 10, 234 8月 16 13:08 btrfs-control drwxr-xr-x 3 root root 60 8月 16 13:08 bus lrwxrwxrwx 1 root root 3 8月 16 13:08 cdrom -> sr0 drwxr-xr-x 2 root root 3760 8月 16 13:08 char crw------- 1 root root 5, 1 8月 16 13:09 console lrwxrwxrwx 1 root root 11 8月 16 13:08 core -> /proc/kcore drwxr-xr-x 2 root root 60 8月 16 13:08 cpu crw------- 1 root root 10, 60 8月 16 13:08 cpu_dma_latency crw------- 1 root root 10, 203 8月 16 13:08 cuse drwxr-xr-x 5 root root 100 8月 16 13:08 disk drwxr-xr-x 2 root root 100 8月 16 13:08 dri lrwxrwxrwx 1 root root 3 8月 16 13:08 dvd -> sr0 crw------- 1 root root 10, 61 8月 16 13:08 ecryptfs crw-rw---- 1 root video 29, 0 8月 16 13:08 fb0 lrwxrwxrwx 1 root root 13 8月 16 13:08 fd -> /proc/self/fd crw-rw-rw- 1 root root 1, 7 8月 16 13:08 full crw-rw-rw- 1 root root 10, 229 8月 16 13:08 fuse crw------- 1 root root 249, 0 8月 16 13:08 hidraw0 crw------- 1 root root 249, 1 8月 16 13:08 hidraw1 crw------- 1 root root 249, 2 8月 16 13:08 hidraw2 crw------- 1 root root 10, 228 8月 16 13:08 hpet drwxr-xr-x 2 root root 0 8月 16 13:08 hugepages crw------- 1 root root 10, 183 8月 16 13:08 hwrng lrwxrwxrwx 1 root root 25 8月 16 13:08 initctl -> /run/systemd/initctl/fifo drwxr-xr-x 4 root root 320 8月 16 13:08 input crw-r--r-- 1 root root 1, 11 8月 16 13:08 kmsg lrwxrwxrwx 1 root root 28 8月 16 13:08 log -> /run/systemd/journal/dev-log brw-rw---- 1 root disk 7, 0 8月 16 13:08 loop0 brw-rw---- 1 root disk 7, 1 8月 16 13:08 loop1 brw-rw---- 1 root disk 7, 2 8月 16 13:08 loop2 brw-rw---- 1 root disk 7, 3 8月 16 13:08 loop3 brw-rw---- 1 root disk 7, 4 8月 16 13:08 loop4 brw-rw---- 1 root disk 7, 5 8月 16 13:08 loop5 brw-rw---- 1 root disk 7, 6 8月 16 13:08 loop6 brw-rw---- 1 root disk 7, 7 8月 16 13:08 loop7 crw-rw---- 1 root disk 10, 237 8月 16 13:08 loop-control drwxr-xr-x 2 root root 60 8月 16 13:08 mapper crw------- 1 root root 10, 227 8月 16 13:08 mcelog crw------- 1 root root 250, 0 8月 16 13:08 mei0 crw-r----- 1 root kmem 1, 1 8月 16 13:08 mem crw------- 1 root root 10, 57 8月 16 13:08 memory_bandwidth drwxrwxrwt 2 root root 40 8月 16 13:08 mqueue drwxr-xr-x 2 root root 60 8月 16 13:08 net crw------- 1 root root 10, 59 8月 16 13:08 network_latency crw------- 1 root root 10, 58 8月 16 13:08 network_throughput crw-rw-rw- 1 root root 1, 3 8月 16 13:08 null crw-r----- 1 root kmem 1, 4 8月 16 13:08 port crw------- 1 root root 108, 0 8月 16 13:08 ppp crw------- 1 root root 10, 1 8月 16 13:08 psaux crw-rw-rw- 1 root tty 5, 2 8月 16 13:44 ptmx drwxr-xr-x 2 root root 0 8月 16 13:08 pts brw-rw---- 1 root disk 1, 0 8月 16 13:08 ram0 brw-rw---- 1 root disk 1, 1 8月 16 13:08 ram1 brw-rw---- 1 root disk 1, 10 8月 16 13:08 ram10 brw-rw---- 1 root disk 1, 11 8月 16 13:08 ram11 brw-rw---- 1 root disk 1, 12 8月 16 13:08 ram12 brw-rw---- 1 root disk 1, 13 8月 16 13:08 ram13 brw-rw---- 1 root disk 1, 14 8月 16 13:08 ram14 brw-rw---- 1 root disk 1, 15 8月 16 13:08 ram15 brw-rw---- 1 root disk 1, 2 8月 16 13:08 ram2 brw-rw---- 1 root disk 1, 3 8月 16 13:08 ram3 brw-rw---- 1 root disk 1, 4 8月 16 13:08 ram4 brw-rw---- 1 root disk 1, 5 8月 16 13:08 ram5 brw-rw---- 1 root disk 1, 6 8月 16 13:08 ram6 brw-rw---- 1 root disk 1, 7 8月 16 13:08 ram7 brw-rw---- 1 root disk 1, 8 8月 16 13:08 ram8 brw-rw---- 1 root disk 1, 9 8月 16 13:08 ram9 crw-rw-rw- 1 root root 1, 8 8月 16 13:08 random crw-rw-r--+ 1 root root 10, 62 8月 16 13:08 rfkill lrwxrwxrwx 1 root root 4 8月 16 13:08 rtc -> rtc0 crw------- 1 root root 253, 0 8月 16 13:08 rtc0 brw-rw---- 1 root disk 8, 0 8月 16 13:08 sda brw-rw---- 1 root disk 8, 1 8月 16 13:08 sda1 brw-rw---- 1 root disk 8, 2 8月 16 13:08 sda2 brw-rw---- 1 root disk 8, 3 8月 16 13:08 sda3 brw-rw---- 1 root disk 8, 4 8月 16 13:08 sda4 brw-rw---- 1 root disk 8, 5 8月 16 13:08 sda5 brw-rw---- 1 root disk 8, 6 8月 16 13:08 sda6 brw-rw---- 1 root disk 8, 7 8月 16 13:08 sda7 brw-rw---- 1 root disk 8, 8 8月 16 13:08 sda8 crw-rw---- 1 root disk 21, 0 8月 16 13:08 sg0 crw-rw----+ 1 root cdrom 21, 1 8月 16 13:08 sg1 drwxrwxrwt 2 root root 120 8月 16 13:08 shm crw------- 1 root root 10, 231 8月 16 13:08 snapshot drwxr-xr-x 3 root root 200 8月 16 13:08 snd brw-rw----+ 1 root cdrom 11, 0 8月 16 13:08 sr0 lrwxrwxrwx 1 root root 15 8月 16 13:08 stderr -> /proc/self/fd/2 lrwxrwxrwx 1 root root 15 8月 16 13:08 stdin -> /proc/self/fd/0 lrwxrwxrwx 1 root root 15 8月 16 13:08 stdout -> /proc/self/fd/1 crw-rw-rw- 1 root tty 5, 0 8月 16 13:08 tty crw--w---- 1 root tty 4, 0 8月 16 13:08 tty0 crw--w---- 1 root tty 4, 1 8月 16 13:08 tty1 crw--w---- 1 root tty 4, 10 8月 16 13:08 tty10 crw--w---- 1 root tty 4, 11 8月 16 13:08 tty11 crw--w---- 1 root tty 4, 12 8月 16 13:08 tty12 crw--w---- 1 root tty 4, 13 8月 16 13:08 tty13 crw--w---- 1 root tty 4, 14 8月 16 13:08 tty14 crw--w---- 1 root tty 4, 15 8月 16 13:08 tty15 crw--w---- 1 root tty 4, 16 8月 16 13:08 tty16 crw--w---- 1 root tty 4, 17 8月 16 13:08 tty17 crw--w---- 1 root tty 4, 18 8月 16 13:08 tty18 crw--w---- 1 root tty 4, 19 8月 16 13:08 tty19 crw--w---- 1 root tty 4, 2 8月 16 13:08 tty2 crw--w---- 1 root tty 4, 20 8月 16 13:08 tty20 crw--w---- 1 root tty 4, 21 8月 16 13:08 tty21 crw--w---- 1 root tty 4, 22 8月 16 13:08 tty22 crw--w---- 1 root tty 4, 23 8月 16 13:08 tty23 crw--w---- 1 root tty 4, 24 8月 16 13:08 tty24 crw--w---- 1 root tty 4, 25 8月 16 13:08 tty25 crw--w---- 1 root tty 4, 26 8月 16 13:08 tty26 crw--w---- 1 root tty 4, 27 8月 16 13:08 tty27 crw--w---- 1 root tty 4, 28 8月 16 13:08 tty28 crw--w---- 1 root tty 4, 29 8月 16 13:08 tty29 crw--w---- 1 root tty 4, 3 8月 16 13:08 tty3 crw--w---- 1 root tty 4, 30 8月 16 13:08 tty30 crw--w---- 1 root tty 4, 31 8月 16 13:08 tty31 crw--w---- 1 root tty 4, 32 8月 16 13:08 tty32 crw--w---- 1 root tty 4, 33 8月 16 13:08 tty33 crw--w---- 1 root tty 4, 34 8月 16 13:08 tty34 crw--w---- 1 root tty 4, 35 8月 16 13:08 tty35 crw--w---- 1 root tty 4, 36 8月 16 13:08 tty36 crw--w---- 1 root tty 4, 37 8月 16 13:08 tty37 crw--w---- 1 root tty 4, 38 8月 16 13:08 tty38 crw--w---- 1 root tty 4, 39 8月 16 13:08 tty39 crw--w---- 1 root tty 4, 4 8月 16 13:08 tty4 crw--w---- 1 root tty 4, 40 8月 16 13:08 tty40 crw--w---- 1 root tty 4, 41 8月 16 13:08 tty41 crw--w---- 1 root tty 4, 42 8月 16 13:08 tty42 crw--w---- 1 root tty 4, 43 8月 16 13:08 tty43 crw--w---- 1 root tty 4, 44 8月 16 13:08 tty44 crw--w---- 1 root tty 4, 45 8月 16 13:08 tty45 crw--w---- 1 root tty 4, 46 8月 16 13:08 tty46 crw--w---- 1 root tty 4, 47 8月 16 13:08 tty47 crw--w---- 1 root tty 4, 48 8月 16 13:08 tty48 crw--w---- 1 root tty 4, 49 8月 16 13:08 tty49 crw--w---- 1 root tty 4, 5 8月 16 13:08 tty5 crw--w---- 1 root tty 4, 50 8月 16 13:08 tty50 crw--w---- 1 root tty 4, 51 8月 16 13:08 tty51 crw--w---- 1 root tty 4, 52 8月 16 13:08 tty52 crw--w---- 1 root tty 4, 53 8月 16 13:08 tty53 crw--w---- 1 root tty 4, 54 8月 16 13:08 tty54 crw--w---- 1 root tty 4, 55 8月 16 13:08 tty55 crw--w---- 1 root tty 4, 56 8月 16 13:08 tty56 crw--w---- 1 root tty 4, 57 8月 16 13:08 tty57 crw--w---- 1 root tty 4, 58 8月 16 13:08 tty58 crw--w---- 1 root tty 4, 59 8月 16 13:08 tty59 crw--w---- 1 root tty 4, 6 8月 16 13:08 tty6 crw--w---- 1 root tty 4, 60 8月 16 13:08 tty60 crw--w---- 1 root tty 4, 61 8月 16 13:08 tty61 crw--w---- 1 root tty 4, 62 8月 16 13:08 tty62 crw--w---- 1 root tty 4, 63 8月 16 13:08 tty63 crw--w---- 1 root tty 4, 7 8月 16 13:08 tty7 crw--w---- 1 root tty 4, 8 8月 16 13:08 tty8 crw--w---- 1 root tty 4, 9 8月 16 13:08 tty9 crw------- 1 root root 5, 3 8月 16 13:08 ttyprintk crw-rw---- 1 root dialout 4, 64 8月 16 13:08 ttyS0 crw-rw---- 1 root dialout 4, 65 8月 16 13:08 ttyS1 crw-rw---- 1 root dialout 4, 74 8月 16 13:08 ttyS10 crw-rw---- 1 root dialout 4, 75 8月 16 13:08 ttyS11 crw-rw---- 1 root dialout 4, 76 8月 16 13:08 ttyS12 crw-rw---- 1 root dialout 4, 77 8月 16 13:08 ttyS13 crw-rw---- 1 root dialout 4, 78 8月 16 13:08 ttyS14 crw-rw---- 1 root dialout 4, 79 8月 16 13:08 ttyS15 crw-rw---- 1 root dialout 4, 80 8月 16 13:08 ttyS16 crw-rw---- 1 root dialout 4, 81 8月 16 13:08 ttyS17 crw-rw---- 1 root dialout 4, 82 8月 16 13:08 ttyS18 crw-rw---- 1 root dialout 4, 83 8月 16 13:08 ttyS19 crw-rw---- 1 root dialout 4, 66 8月 16 13:08 ttyS2 crw-rw---- 1 root dialout 4, 84 8月 16 13:08 ttyS20 crw-rw---- 1 root dialout 4, 85 8月 16 13:08 ttyS21 crw-rw---- 1 root dialout 4, 86 8月 16 13:08 ttyS22 crw-rw---- 1 root dialout 4, 87 8月 16 13:08 ttyS23 crw-rw---- 1 root dialout 4, 88 8月 16 13:08 ttyS24 crw-rw---- 1 root dialout 4, 89 8月 16 13:08 ttyS25 crw-rw---- 1 root dialout 4, 90 8月 16 13:08 ttyS26 crw-rw---- 1 root dialout 4, 91 8月 16 13:08 ttyS27 crw-rw---- 1 root dialout 4, 92 8月 16 13:08 ttyS28 crw-rw---- 1 root dialout 4, 93 8月 16 13:08 ttyS29 crw-rw---- 1 root dialout 4, 67 8月 16 13:08 ttyS3 crw-rw---- 1 root dialout 4, 94 8月 16 13:08 ttyS30 crw-rw---- 1 root dialout 4, 95 8月 16 13:08 ttyS31 crw-rw---- 1 root dialout 4, 68 8月 16 13:08 ttyS4 crw-rw---- 1 root dialout 4, 69 8月 16 13:08 ttyS5 crw-rw---- 1 root dialout 4, 70 8月 16 13:08 ttyS6 crw-rw---- 1 root dialout 4, 71 8月 16 13:08 ttyS7 crw-rw---- 1 root dialout 4, 72 8月 16 13:08 ttyS8 crw-rw---- 1 root dialout 4, 73 8月 16 13:08 ttyS9 crw------- 1 root root 10, 239 8月 16 13:08 uhid crw------- 1 root root 10, 223 8月 16 13:08 uinput crw-rw-rw- 1 root root 1, 9 8月 16 13:08 urandom crw-rw---- 1 root tty 7, 0 8月 16 13:08 vcs crw-rw---- 1 root tty 7, 1 8月 16 13:08 vcs1 crw-rw---- 1 root tty 7, 2 8月 16 13:08 vcs2 crw-rw---- 1 root tty 7, 3 8月 16 13:08 vcs3 crw-rw---- 1 root tty 7, 4 8月 16 13:08 vcs4 crw-rw---- 1 root tty 7, 5 8月 16 13:08 vcs5 crw-rw---- 1 root tty 7, 6 8月 16 13:08 vcs6 crw-rw---- 1 root tty 7, 7 8月 16 13:08 vcs7 crw-rw---- 1 root tty 7, 128 8月 16 13:08 vcsa crw-rw---- 1 root tty 7, 129 8月 16 13:08 vcsa1 crw-rw---- 1 root tty 7, 130 8月 16 13:08 vcsa2 crw-rw---- 1 root tty 7, 131 8月 16 13:08 vcsa3 crw-rw---- 1 root tty 7, 132 8月 16 13:08 vcsa4 crw-rw---- 1 root tty 7, 133 8月 16 13:08 vcsa5 crw-rw---- 1 root tty 7, 134 8月 16 13:08 vcsa6 crw-rw---- 1 root tty 7, 135 8月 16 13:08 vcsa7 drwxr-xr-x 2 root root 60 8月 16 13:08 vfio crw------- 1 root root 10, 63 8月 16 13:08 vga_arbiter crw------- 1 root root 10, 137 8月 16 13:08 vhci crw------- 1 root root 10, 238 8月 16 13:08 vhost-net prw-r----- 1 root adm 0 8月 16 13:08 xconsole crw-rw-rw- 1 root root 1, 5 8月 16 13:08 zero
cat /proc/tty/drivers /dev/tty /dev/tty 5 0 system:/dev/tty /dev/console /dev/console 5 1 system:console /dev/ptmx /dev/ptmx 5 2 system /dev/vc/0 /dev/vc/0 4 0 system:vtmaster ttyprintk /dev/ttyprintk 5 3 console serial /dev/ttyS 4 64-111 serial pty_slave /dev/pts 136 0-1048575 pty:slave pty_master /dev/ptm 128 0-1048575 pty:master unknown /dev/tty 4 1-63 console
tty 控制终端,control terminal 这个是跟进程相关的,可以理解为一个指针,指向具体的tty终端设备。
进程可以通过open /dev/tty来获取当前进程使用的tty终端具体是哪个,例如是ptmx,还是pts/2,还是另外通过ps -ax可以查看系统所有进程的控制终端,如:
root 781 0.0 0.0 20052 2088 tty1 Ss+ 13:08 0:00 /sbin/agetty --noclear tty1 linux
刚才说到,/proc/pid/stat的第7个字段是进程控制终端的设备号,可以根据此设备号得到具体的设备名。
tty_nr = new_encode_dev(tty_devnum(sig->tty)); seq_put_decimal_ll(m, ' ', tty_nr);例如:
cat /proc/781/stat 781 (agetty) S 1 781 781 1025 781 4194560 180 35 0 0 0 0 0 0 20 0 1 0 2778 20533248 522 18446744073709551615 4194304 4227700 140728752939200 140728752928472 139843305755776 0 0 6 0 18446744071579591276 0 0 17 2 0 0 0 0 0 6327824 6329216 20836352 140728752942807 140728752942841 140728752942841 140728752943083 0即1025,十六进为0x401 ,主设备号为高4字节4,次设备号为低字节1,
对照/proc/tty/drivers得到
unknown /dev/tty 4 1-63 console
即tty1。再根据ps -ax | grep 781得到
/# ps -ax | grep 781 781 tty1 Ss+ 0:00 /sbin/agetty --noclear tty1 linux
扯远了,下面来看telnet的流程
26912 ? Ss 0:00 busybox telnetd可以看出telnetd先fork出gettty并执行login,登录成功后则再fork出实际的bash,
这个bash用的是伪终端pts/6,
以下数据的PPid字段可以证明:实际上我们可以这么理解,在直接登录shell时,没有telnetd这一层,
应该是shell进程本身被ctrl-c键盘中断打断,
然后再驱动里通过tty收到了此特殊字符,然后在接收流程里,决定是否给当前进程shell发SIG信号。即向进程组发送INT信号。
有了上面的知识铺垫,我们来看一个实际的问题。
我们先说明,这是一个busybox 1.13版本的bug,后来已经在高版本修复。
故障现象是这样的:
mips32&64 busybox 1.13 kernel 2.6.32
在串口终端执行如下脚本:
./tftp -r file_256M -g 192.168.1.1
'echo 1'
然后在tftp下载过程中,按ctrl-c
那么tftp进程将变成Z
故障的场景:
1)# ./test.sh之后 ash fork生成一个sh, 这个sh尝试按行解析test.sh,每读取一行就fork一个新进程并exec去执行。
然后sh通过waitpid等待子进程的完成。
正常情况下,两条命令顺序执行完,一切都结束的很好。
2)如果sh在waitpid过程中,即等待tftp完成的过程中,正好收到了SIGINT信号,那么sh就被人从阻塞状态里唤醒。
do_wait继续进入轮询检查到tftp不是为Z(因为这个时候tftp还没得到调度),所以不会回收tftp,然后退出系统调用返回用户态
时检查到有pending的SIGINT,于是get_signal_to_deliever,
由于sh注册了SIGINT信号的处理函数onsig,因此不会do_group_exit
3)onsig执行完之后,再解析下一条命令`echo 1` , 由于sh发现这条命令是引号包起来的,
说明是一个子命令,因此sh再次fork一个进程sh_2,去执行echo 1,并且通过管道pipe_wait等待
sh_2的echo 1的结果
4)sh_2在解析echo 1的过程中,需要获取tty串口的信息,由于这个时候控制终端tty串口已经被sh占有,所以sh_2
就会一直阻塞在tty_read,造成与sh的互锁。
因此问题出在,第3步sh如果收到了SIGINT信号,就不应该继续执行下一条echo 1指令了,而是整个进程退出
后面的一系列问题都是错误的流程导致的错误的结果。
附出问题时的阻塞现场
941 root 3840 S -/bin/ash
955 root 3840 S /bin/sh
969 root 3792 S /bin/sh ./test.sh //即上文的sh
970 root 0 Z [tftp]
971 root 3792 S /bin/sh ./test.sh //sh收到ctrl-c后不做处理,继续fork,尝试解析echo 1字符
972 root 3856 R ps
(gdb) attach 969
The target endianness is set automatically (currently big endian)
[New Thread 969]
0x0000000120013370 in read ()
(gdb) bt
#0 0x0000000120013370 in read ()
#1 0x00000001200fe9d4 in safe_read (fd=3, buf=0xffffa53bf8, count=128)
at libbb/read.c:27
#2 0x00000001200fea68 in nonblock_safe_read (fd=3, buf=0xffffa53bf8,
count=128) at libbb/read.c:75
#3 0x000000012018fd3c in expbackq (cmd=0x120341b48, quoted=0, quotes=0)
at shell/ash.c:5557
#4 0x0000000120190580 in argstr (p=0x120341b6b "", flag=68, var_str_list=0x0)
at shell/ash.c:5783
#5 0x0000000120193574 in expandarg (arg=0x120341b70, arglist=0xffffa53e40,
flag=4) at shell/ash.c:6829
#6 0x0000000120198304 in evalcommand (cmd=0x120341b90, flags=0)
at shell/ash.c:8813
#7 0x0000000120196474 in evaltree (n=0x120341b90, flags=0)
at shell/ash.c:8005
#8 0x000000012019fd6c in cmdloop (top=1) at shell/ash.c:11739
#9 0x00000001201a46e8 in ash_main (argc=2, argv=0xffffa54408)
at shell/ash.c:13743
#10 0x00000001200fa098 in run_applet_no_and_exit (applet_no=219,
argv=0xffffa54408) at libbb/appletlib.c:747
#11 0x00000001200fa10c in run_applet_and_exit (name=0xffffa57f61 "sh",
argv=0xffffa54408) at libbb/appletlib.c:754
#12 0x00000001200fa24c in main (argc=2, argv=0xffffa54408)
at libbb/appletlib.c:791
(gdb) detach
Ending debugging.
(gdb) attach 971
[New Thread 971]
0x0000000120013370 in read ()
(gdb) bt
#0 0x0000000120013370 in read ()
#1 0x00000001200fe9d4 in safe_read (fd=0, buf=0x12031cd08, count=8191)
at libbb/read.c:27
#2 0x00000001200fea68 in nonblock_safe_read (fd=0, buf=0x12031cd08,
count=8191) at libbb/read.c:75
#3 0x0000000120199148 in preadfd () at shell/ash.c:9139
#4 0x00000001201994d8 in preadbuffer () at shell/ash.c:9258
#5 0x000000012019972c in pgetc () at shell/ash.c:9314
#6 0x000000012019f078 in xxreadtoken () at shell/ash.c:11365
#7 0x000000012019f3a8 in readtoken () at shell/ash.c:11499
#8 0x000000012019f64c in parsecmd (interact=0) at shell/ash.c:11576
#9 0x000000012019fc80 in cmdloop (top=1) at shell/ash.c:11724
#10 0x00000001201a46e8 in ash_main (argc=2, argv=0xffffa54408)
at shell/ash.c:13743
#11 0x00000001200fa098 in run_applet_no_and_exit (applet_no=219,
argv=0xffffa54408) at libbb/appletlib.c:747
#12 0x00000001200fa10c in run_applet_and_exit (name=0xffffa57f61 "sh",
argv=0xffffa54408) at libbb/appletlib.c:754
#13 0x00000001200fa24c in main (argc=2, argv=0xffffa54408)
at libbb/appletlib.c:791
(gdb)