通过telnet登录到单板,然后按ctrl-c会发生什么情况,流程是怎么样的?

在分析之前,先介绍tty的相关知识。
我们可以认为,所有跟输入输出相关的操作,最终都由tty来接管。
举例来说,当我们敲 ls /dev时得到

  1. ls /dev/ -l
  2. total 0
  3. crw-------  1 root root     10, 235  8月 16 13:08 autofs
  4. drwxr-xr-x  2 root root         720  8月 16 13:08 block
  5. drwxr-xr-x  2 root root          80  8月 16 13:08 bsg
  6. crw-rw----  1 root disk     10, 234  8月 16 13:08 btrfs-control
  7. drwxr-xr-x  3 root root          60  8月 16 13:08 bus
  8. lrwxrwxrwx  1 root root           3  8月 16 13:08 cdrom -> sr0
  9. drwxr-xr-x  2 root root        3760  8月 16 13:08 char
  10. crw-------  1 root root      5,   1  8月 16 13:09 console
  11. lrwxrwxrwx  1 root root          11  8月 16 13:08 core -> /proc/kcore
  12. drwxr-xr-x  2 root root          60  8月 16 13:08 cpu
  13. crw-------  1 root root     10,  60  8月 16 13:08 cpu_dma_latency
  14. crw-------  1 root root     10, 203  8月 16 13:08 cuse
  15. drwxr-xr-x  5 root root         100  8月 16 13:08 disk
  16. drwxr-xr-x  2 root root         100  8月 16 13:08 dri
  17. lrwxrwxrwx  1 root root           3  8月 16 13:08 dvd -> sr0
  18. crw-------  1 root root     10,  61  8月 16 13:08 ecryptfs
  19. crw-rw----  1 root video    29,   0  8月 16 13:08 fb0
  20. lrwxrwxrwx  1 root root          13  8月 16 13:08 fd -> /proc/self/fd
  21. crw-rw-rw-  1 root root      1,   7  8月 16 13:08 full
  22. crw-rw-rw-  1 root root     10, 229  8月 16 13:08 fuse
  23. crw-------  1 root root    249,   0  8月 16 13:08 hidraw0
  24. crw-------  1 root root    249,   1  8月 16 13:08 hidraw1
  25. crw-------  1 root root    249,   2  8月 16 13:08 hidraw2
  26. crw-------  1 root root     10, 228  8月 16 13:08 hpet
  27. drwxr-xr-x  2 root root           0  8月 16 13:08 hugepages
  28. crw-------  1 root root     10, 183  8月 16 13:08 hwrng
  29. lrwxrwxrwx  1 root root          25  8月 16 13:08 initctl -> /run/systemd/initctl/fifo
  30. drwxr-xr-x  4 root root         320  8月 16 13:08 input
  31. crw-r--r--  1 root root      1,  11  8月 16 13:08 kmsg
  32. lrwxrwxrwx  1 root root          28  8月 16 13:08 log -> /run/systemd/journal/dev-log
  33. brw-rw----  1 root disk      7,   0  8月 16 13:08 loop0
  34. brw-rw----  1 root disk      7,   1  8月 16 13:08 loop1
  35. brw-rw----  1 root disk      7,   2  8月 16 13:08 loop2
  36. brw-rw----  1 root disk      7,   3  8月 16 13:08 loop3
  37. brw-rw----  1 root disk      7,   4  8月 16 13:08 loop4
  38. brw-rw----  1 root disk      7,   5  8月 16 13:08 loop5
  39. brw-rw----  1 root disk      7,   6  8月 16 13:08 loop6
  40. brw-rw----  1 root disk      7,   7  8月 16 13:08 loop7
  41. crw-rw----  1 root disk     10, 237  8月 16 13:08 loop-control
  42. drwxr-xr-x  2 root root          60  8月 16 13:08 mapper
  43. crw-------  1 root root     10, 227  8月 16 13:08 mcelog
  44. crw-------  1 root root    250,   0  8月 16 13:08 mei0
  45. crw-r-----  1 root kmem      1,   1  8月 16 13:08 mem
  46. crw-------  1 root root     10,  57  8月 16 13:08 memory_bandwidth
  47. drwxrwxrwt  2 root root          40  8月 16 13:08 mqueue
  48. drwxr-xr-x  2 root root          60  8月 16 13:08 net
  49. crw-------  1 root root     10,  59  8月 16 13:08 network_latency
  50. crw-------  1 root root     10,  58  8月 16 13:08 network_throughput
  51. crw-rw-rw-  1 root root      1,   3  8月 16 13:08 null
  52. crw-r-----  1 root kmem      1,   4  8月 16 13:08 port
  53. crw-------  1 root root    108,   0  8月 16 13:08 ppp
  54. crw-------  1 root root     10,   1  8月 16 13:08 psaux
  55. crw-rw-rw-  1 root tty       5,   2  8月 16 13:44 ptmx
  56. drwxr-xr-x  2 root root           0  8月 16 13:08 pts
  57. brw-rw----  1 root disk      1,   0  8月 16 13:08 ram0
  58. brw-rw----  1 root disk      1,   1  8月 16 13:08 ram1
  59. brw-rw----  1 root disk      1,  10  8月 16 13:08 ram10
  60. brw-rw----  1 root disk      1,  11  8月 16 13:08 ram11
  61. brw-rw----  1 root disk      1,  12  8月 16 13:08 ram12
  62. brw-rw----  1 root disk      1,  13  8月 16 13:08 ram13
  63. brw-rw----  1 root disk      1,  14  8月 16 13:08 ram14
  64. brw-rw----  1 root disk      1,  15  8月 16 13:08 ram15
  65. brw-rw----  1 root disk      1,   2  8月 16 13:08 ram2
  66. brw-rw----  1 root disk      1,   3  8月 16 13:08 ram3
  67. brw-rw----  1 root disk      1,   4  8月 16 13:08 ram4
  68. brw-rw----  1 root disk      1,   5  8月 16 13:08 ram5
  69. brw-rw----  1 root disk      1,   6  8月 16 13:08 ram6
  70. brw-rw----  1 root disk      1,   7  8月 16 13:08 ram7
  71. brw-rw----  1 root disk      1,   8  8月 16 13:08 ram8
  72. brw-rw----  1 root disk      1,   9  8月 16 13:08 ram9
  73. crw-rw-rw-  1 root root      1,   8  8月 16 13:08 random
  74. crw-rw-r--+ 1 root root     10,  62  8月 16 13:08 rfkill
  75. lrwxrwxrwx  1 root root           4  8月 16 13:08 rtc -> rtc0
  76. crw-------  1 root root    253,   0  8月 16 13:08 rtc0
  77. brw-rw----  1 root disk      8,   0  8月 16 13:08 sda
  78. brw-rw----  1 root disk      8,   1  8月 16 13:08 sda1
  79. brw-rw----  1 root disk      8,   2  8月 16 13:08 sda2
  80. brw-rw----  1 root disk      8,   3  8月 16 13:08 sda3
  81. brw-rw----  1 root disk      8,   4  8月 16 13:08 sda4
  82. brw-rw----  1 root disk      8,   5  8月 16 13:08 sda5
  83. brw-rw----  1 root disk      8,   6  8月 16 13:08 sda6
  84. brw-rw----  1 root disk      8,   7  8月 16 13:08 sda7
  85. brw-rw----  1 root disk      8,   8  8月 16 13:08 sda8
  86. crw-rw----  1 root disk     21,   0  8月 16 13:08 sg0
  87. crw-rw----+ 1 root cdrom    21,   1  8月 16 13:08 sg1
  88. drwxrwxrwt  2 root root         120  8月 16 13:08 shm
  89. crw-------  1 root root     10, 231  8月 16 13:08 snapshot
  90. drwxr-xr-x  3 root root         200  8月 16 13:08 snd
  91. brw-rw----+ 1 root cdrom    11,   0  8月 16 13:08 sr0
  92. lrwxrwxrwx  1 root root          15  8月 16 13:08 stderr -> /proc/self/fd/2
  93. lrwxrwxrwx  1 root root          15  8月 16 13:08 stdin -> /proc/self/fd/0
  94. lrwxrwxrwx  1 root root          15  8月 16 13:08 stdout -> /proc/self/fd/1
  95. crw-rw-rw-  1 root tty       5,   0  8月 16 13:08 tty
  96. crw--w----  1 root tty       4,   0  8月 16 13:08 tty0
  97. crw--w----  1 root tty       4,   1  8月 16 13:08 tty1
  98. crw--w----  1 root tty       4,  10  8月 16 13:08 tty10
  99. crw--w----  1 root tty       4,  11  8月 16 13:08 tty11
  100. crw--w----  1 root tty       4,  12  8月 16 13:08 tty12
  101. crw--w----  1 root tty       4,  13  8月 16 13:08 tty13
  102. crw--w----  1 root tty       4,  14  8月 16 13:08 tty14
  103. crw--w----  1 root tty       4,  15  8月 16 13:08 tty15
  104. crw--w----  1 root tty       4,  16  8月 16 13:08 tty16
  105. crw--w----  1 root tty       4,  17  8月 16 13:08 tty17
  106. crw--w----  1 root tty       4,  18  8月 16 13:08 tty18
  107. crw--w----  1 root tty       4,  19  8月 16 13:08 tty19
  108. crw--w----  1 root tty       4,   2  8月 16 13:08 tty2
  109. crw--w----  1 root tty       4,  20  8月 16 13:08 tty20
  110. crw--w----  1 root tty       4,  21  8月 16 13:08 tty21
  111. crw--w----  1 root tty       4,  22  8月 16 13:08 tty22
  112. crw--w----  1 root tty       4,  23  8月 16 13:08 tty23
  113. crw--w----  1 root tty       4,  24  8月 16 13:08 tty24
  114. crw--w----  1 root tty       4,  25  8月 16 13:08 tty25
  115. crw--w----  1 root tty       4,  26  8月 16 13:08 tty26
  116. crw--w----  1 root tty       4,  27  8月 16 13:08 tty27
  117. crw--w----  1 root tty       4,  28  8月 16 13:08 tty28
  118. crw--w----  1 root tty       4,  29  8月 16 13:08 tty29
  119. crw--w----  1 root tty       4,   3  8月 16 13:08 tty3
  120. crw--w----  1 root tty       4,  30  8月 16 13:08 tty30
  121. crw--w----  1 root tty       4,  31  8月 16 13:08 tty31
  122. crw--w----  1 root tty       4,  32  8月 16 13:08 tty32
  123. crw--w----  1 root tty       4,  33  8月 16 13:08 tty33
  124. crw--w----  1 root tty       4,  34  8月 16 13:08 tty34
  125. crw--w----  1 root tty       4,  35  8月 16 13:08 tty35
  126. crw--w----  1 root tty       4,  36  8月 16 13:08 tty36
  127. crw--w----  1 root tty       4,  37  8月 16 13:08 tty37
  128. crw--w----  1 root tty       4,  38  8月 16 13:08 tty38
  129. crw--w----  1 root tty       4,  39  8月 16 13:08 tty39
  130. crw--w----  1 root tty       4,   4  8月 16 13:08 tty4
  131. crw--w----  1 root tty       4,  40  8月 16 13:08 tty40
  132. crw--w----  1 root tty       4,  41  8月 16 13:08 tty41
  133. crw--w----  1 root tty       4,  42  8月 16 13:08 tty42
  134. crw--w----  1 root tty       4,  43  8月 16 13:08 tty43
  135. crw--w----  1 root tty       4,  44  8月 16 13:08 tty44
  136. crw--w----  1 root tty       4,  45  8月 16 13:08 tty45
  137. crw--w----  1 root tty       4,  46  8月 16 13:08 tty46
  138. crw--w----  1 root tty       4,  47  8月 16 13:08 tty47
  139. crw--w----  1 root tty       4,  48  8月 16 13:08 tty48
  140. crw--w----  1 root tty       4,  49  8月 16 13:08 tty49
  141. crw--w----  1 root tty       4,   5  8月 16 13:08 tty5
  142. crw--w----  1 root tty       4,  50  8月 16 13:08 tty50
  143. crw--w----  1 root tty       4,  51  8月 16 13:08 tty51
  144. crw--w----  1 root tty       4,  52  8月 16 13:08 tty52
  145. crw--w----  1 root tty       4,  53  8月 16 13:08 tty53
  146. crw--w----  1 root tty       4,  54  8月 16 13:08 tty54
  147. crw--w----  1 root tty       4,  55  8月 16 13:08 tty55
  148. crw--w----  1 root tty       4,  56  8月 16 13:08 tty56
  149. crw--w----  1 root tty       4,  57  8月 16 13:08 tty57
  150. crw--w----  1 root tty       4,  58  8月 16 13:08 tty58
  151. crw--w----  1 root tty       4,  59  8月 16 13:08 tty59
  152. crw--w----  1 root tty       4,   6  8月 16 13:08 tty6
  153. crw--w----  1 root tty       4,  60  8月 16 13:08 tty60
  154. crw--w----  1 root tty       4,  61  8月 16 13:08 tty61
  155. crw--w----  1 root tty       4,  62  8月 16 13:08 tty62
  156. crw--w----  1 root tty       4,  63  8月 16 13:08 tty63
  157. crw--w----  1 root tty       4,   7  8月 16 13:08 tty7
  158. crw--w----  1 root tty       4,   8  8月 16 13:08 tty8
  159. crw--w----  1 root tty       4,   9  8月 16 13:08 tty9
  160. crw-------  1 root root      5,   3  8月 16 13:08 ttyprintk
  161. crw-rw----  1 root dialout   4,  64  8月 16 13:08 ttyS0
  162. crw-rw----  1 root dialout   4,  65  8月 16 13:08 ttyS1
  163. crw-rw----  1 root dialout   4,  74  8月 16 13:08 ttyS10
  164. crw-rw----  1 root dialout   4,  75  8月 16 13:08 ttyS11
  165. crw-rw----  1 root dialout   4,  76  8月 16 13:08 ttyS12
  166. crw-rw----  1 root dialout   4,  77  8月 16 13:08 ttyS13
  167. crw-rw----  1 root dialout   4,  78  8月 16 13:08 ttyS14
  168. crw-rw----  1 root dialout   4,  79  8月 16 13:08 ttyS15
  169. crw-rw----  1 root dialout   4,  80  8月 16 13:08 ttyS16
  170. crw-rw----  1 root dialout   4,  81  8月 16 13:08 ttyS17
  171. crw-rw----  1 root dialout   4,  82  8月 16 13:08 ttyS18
  172. crw-rw----  1 root dialout   4,  83  8月 16 13:08 ttyS19
  173. crw-rw----  1 root dialout   4,  66  8月 16 13:08 ttyS2
  174. crw-rw----  1 root dialout   4,  84  8月 16 13:08 ttyS20
  175. crw-rw----  1 root dialout   4,  85  8月 16 13:08 ttyS21
  176. crw-rw----  1 root dialout   4,  86  8月 16 13:08 ttyS22
  177. crw-rw----  1 root dialout   4,  87  8月 16 13:08 ttyS23
  178. crw-rw----  1 root dialout   4,  88  8月 16 13:08 ttyS24
  179. crw-rw----  1 root dialout   4,  89  8月 16 13:08 ttyS25
  180. crw-rw----  1 root dialout   4,  90  8月 16 13:08 ttyS26
  181. crw-rw----  1 root dialout   4,  91  8月 16 13:08 ttyS27
  182. crw-rw----  1 root dialout   4,  92  8月 16 13:08 ttyS28
  183. crw-rw----  1 root dialout   4,  93  8月 16 13:08 ttyS29
  184. crw-rw----  1 root dialout   4,  67  8月 16 13:08 ttyS3
  185. crw-rw----  1 root dialout   4,  94  8月 16 13:08 ttyS30
  186. crw-rw----  1 root dialout   4,  95  8月 16 13:08 ttyS31
  187. crw-rw----  1 root dialout   4,  68  8月 16 13:08 ttyS4
  188. crw-rw----  1 root dialout   4,  69  8月 16 13:08 ttyS5
  189. crw-rw----  1 root dialout   4,  70  8月 16 13:08 ttyS6
  190. crw-rw----  1 root dialout   4,  71  8月 16 13:08 ttyS7
  191. crw-rw----  1 root dialout   4,  72  8月 16 13:08 ttyS8
  192. crw-rw----  1 root dialout   4,  73  8月 16 13:08 ttyS9
  193. crw-------  1 root root     10, 239  8月 16 13:08 uhid
  194. crw-------  1 root root     10, 223  8月 16 13:08 uinput
  195. crw-rw-rw-  1 root root      1,   9  8月 16 13:08 urandom
  196. crw-rw----  1 root tty       7,   0  8月 16 13:08 vcs
  197. crw-rw----  1 root tty       7,   1  8月 16 13:08 vcs1
  198. crw-rw----  1 root tty       7,   2  8月 16 13:08 vcs2
  199. crw-rw----  1 root tty       7,   3  8月 16 13:08 vcs3
  200. crw-rw----  1 root tty       7,   4  8月 16 13:08 vcs4
  201. crw-rw----  1 root tty       7,   5  8月 16 13:08 vcs5
  202. crw-rw----  1 root tty       7,   6  8月 16 13:08 vcs6
  203. crw-rw----  1 root tty       7,   7  8月 16 13:08 vcs7
  204. crw-rw----  1 root tty       7, 128  8月 16 13:08 vcsa
  205. crw-rw----  1 root tty       7, 129  8月 16 13:08 vcsa1
  206. crw-rw----  1 root tty       7, 130  8月 16 13:08 vcsa2
  207. crw-rw----  1 root tty       7, 131  8月 16 13:08 vcsa3
  208. crw-rw----  1 root tty       7, 132  8月 16 13:08 vcsa4
  209. crw-rw----  1 root tty       7, 133  8月 16 13:08 vcsa5
  210. crw-rw----  1 root tty       7, 134  8月 16 13:08 vcsa6
  211. crw-rw----  1 root tty       7, 135  8月 16 13:08 vcsa7
  212. drwxr-xr-x  2 root root          60  8月 16 13:08 vfio
  213. crw-------  1 root root     10,  63  8月 16 13:08 vga_arbiter
  214. crw-------  1 root root     10, 137  8月 16 13:08 vhci
  215. crw-------  1 root root     10, 238  8月 16 13:08 vhost-net
  216. prw-r-----  1 root adm            0  8月 16 13:08 xconsole
  217. crw-rw-rw-  1 root root      1,   5  8月 16 13:08 zero

另外还可以通过 /proc/tty/drivers得到tty相关驱动信息

  1. cat /proc/tty/drivers
  2. /dev/tty             /dev/tty        5       0 system:/dev/tty
  3. /dev/console         /dev/console    5       1 system:console
  4. /dev/ptmx            /dev/ptmx       5       2 system
  5. /dev/vc/0            /dev/vc/0       4       0 system:vtmaster
  6. ttyprintk            /dev/ttyprintk   5       3 console
  7. serial               /dev/ttyS       4 64-111 serial
  8. pty_slave            /dev/pts      136 0-1048575 pty:slave
  9. pty_master           /dev/ptm      128 0-1048575 pty:master
  10. unknown              /dev/tty        4 1-63 console

tty  控制终端,control terminal 这个是跟进程相关的,可以理解为一个指针,指向具体的tty终端设备。

进程可以通过open /dev/tty来获取当前进程使用的tty终端具体是哪个,例如是ptmx,还是pts/2,还是

tty2,或者是ttyS0
     linux shell下tty命令的可以查看当前进程的控制终端。例如:
     [root@ dev]# tty
     /dev/pts/10
     具体的实现是靠ttyname(0)
     即返回当前进程的标准输入,对应的tty终端设备是哪个。

另外通过ps -ax可以查看系统所有进程的控制终端,如:

  1. root       781  0.0  0.0  20052  2088 tty1     Ss+  13:08   0:00 /sbin/agetty --noclear tty1 linux

ptmx 伪终端主
pts  伪终端从
tty0-tty63  虚拟终端,也叫虚拟控制台终端,virtual console ternimal 通常情况下是6个,这里我们查看
的服务器有63个
tty0可以理解为指针
ttyS0-ttyS3 串口终端

刚才说到,/proc/pid/stat的第7个字段是进程控制终端的设备号,可以根据此设备号得到具体的设备名。

  1. tty_nr = new_encode_dev(tty_devnum(sig->tty));
  2. seq_put_decimal_ll(m, ' ', tty_nr);

例如:

  1. cat /proc/781/stat
  2. 81 (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得到

  1. unknown              /dev/tty        4 1-63 console

即tty1。再根据ps -ax | grep 781得到

  1. /# ps -ax | grep 781
  2. 781 tty1     Ss+    0:00 /sbin/agetty --noclear tty1 linux

确实是吻合的。

扯远了,下面来看telnet的流程

26912 ?        Ss     0:00 busybox telnetd
当用户通过telnet客户端连接telnetd后
26912 ?        Ss     0:00 busybox telnetd
27030 ?        Ss     0:00 login -- chenyu
27038 pts/6    Ss+    0:00 -bash

可以看出telnetd先fork出gettty并执行login,登录成功后则再fork出实际的bash,

这个bash用的是伪终端pts/6,

以下数据的PPid字段可以证明:
Name:   busybox
PPid:   1

Name:   login
Pid:    27030
PPid:   26912

Name:   bash
Pid:    27038
PPid:   27030

bash并不知道这个pts/6具体是个什么设备,只知道往里面读写。
每次在telnet客户端,敲一个字符,就会把数据发给telnetd,telnetd再操作ptmx通过
tty displine将数据格式化传递给pts/6,然后bash从pts/6收到数据进行处理,再写回pts/6,
传给ptmx,由telnetd将数据再传递回telnet客户端。 可以通过每次在telnet客户端
敲一个字符,telnetd的调度次数就增加2,来大体验证这个流程(telnetd收到客户端数据被唤醒,bash通过
伪终端把数据写回唤醒telnetd,一共两次唤醒)

具体的telnet流程图如下:

说完了telnetd的原理,再来看看在telnet客户端敲ctrl-c时,系统会发生什么。
首先可以明确的是,ctrl-c传递到telnetd后,会通过写伪终端主设备ptmx的方式传递给从设备进而传给bash。
那么,到底是telnetd,还是bash端会处理这个ctrl-c?

实际上我们可以这么理解,在直接登录shell时,没有telnetd这一层,

应该是shell进程本身被ctrl-c键盘中断打断,

然后再驱动里通过tty收到了此特殊字符,然后在接收流程里,决定是否给当前进程shell发SIG信号。
那么我们就认为telnetd不过是一个中转站,具体的数据处理还是要靠bash来完成。

因此当bash从pts/6收到ctrl-c特殊字符后,会进行特殊处理。来看这段代码:
首先,不管是伪终端,还是串口,亦或是控制台,接收到字符后都要推送给tty displine 的接收函数
n_tty_receive_buf做进一步处理。n_tty_receive_buf的数据来源是tty->buf。
这个tty->buf的来源,要么是伪终端主设备pty_write写入的数据,要么是中断往里面写入的数据。

如果是伪终端pty_write
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
{
     //得到从设备
struct tty_struct *to = tty->link;

if (tty->stopped)
return 0;

if (c > 0) {
/* Stuff the data into the input queue of the other end */
     //让从设备强行收数据,即将buf数据传递给从设备的tty->buf
c = tty_insert_flip_string(to, buf, c);
/* And shovel */
if (c) {
            //将从设备的tty->buf临时缓冲数据提交给displine处理,即提交给tty->read_buf
            //供用户空间使用
             //这个一般是通过schedule_work来完成
tty_flip_buffer_push(to);
tty_wakeup(tty);
}
}
return c;
}

如果是串口中断,则是
serial8250_interrupt->serial8250_handle_port->receive_chars->
uart_insert_char->tty_insert_flip_char 将串口数据拷贝到tty->buf中之后,
再tty_flip_buffer_push(tty);将数据推送给displine处理

因此可以看出,串口和伪终端的不同之处在于,数据来源不同,一个是tty_write写入的,
一个是串口中断接受到的。
所以,我们在串口,或者是在telnet下,敲ctrl-c,实际上都会走到tty_flip_buffer_push,
进行数据的分析和接受。具体的特殊字符解析,应该也是在tty_flip_buffer_push之后的步骤完成。

那下面我们来看tty_flip_buffer_push
* This routine is called out of the software interrupt to flush data
* from the buffer chain to the line discipline.

最终调到到receive_buf->n_tty_receive_buf->n_tty_receive_break->
isig(SIGINT, tty, 1);->
if (tty->pgrp)
kill_pgrp(tty->pgrp, sig, 1);

即向进程组发送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)

http://blog.csdn.net/chenyu105/article/details/7738388

linux 终端下敲ctrl-c时,到底发生了什么?(转)的更多相关文章

  1. 如何记录linux终端下的操作日志

    如何记录linux终端下的操作日志 在linux终端下,为方便检查操作中可能出现的错误,以及避免屏幕滚屏的限制,我们可以把操作日志记录下来.常用的工具有 screen,script,以及tee等,通过 ...

  2. linux终端下一些“风骚”的按键操作及Linux终端命令

    linux终端下一些"风骚"的按键操作 <backspace>  删除 <ctrl-l>     清空屏幕, 相当于clear tab            ...

  3. Linux终端下安装jdk

    linux 终端下安装jdk(rpm方法) 1.下载jdk对应版本rpm文件(以下称为jdk.rpm) 放在对应文件夹下 2.使用命令给定权限 #chmod +x jdk.rpm 3.解压rpm文件 ...

  4. linux终端下 编译c语言程序

    linux终端下,编译C语言程序步骤为: 采用vi进行源代码编写,编写完成后,:wq存盘退出,如: vi test.c 在命令行下,运行gcc编译程序,生成执行码,如: gcc  -o test te ...

  5. Linux 终端下的颜色

    Linux 终端下颜色的输出 在命令行下也能产生五颜六色的字体和图案,只需要加上一些颜色代码,例如 echo -e "\033[41;36m 红底绿字\033[0m" 其中41的位 ...

  6. 24小时学通Linux内核之电源开和关时都发生了什么

    说实话感觉自己快写不下去了,其一是有些勉强跟不上来,其二是感觉自己越写越差,刚开始可能是新鲜感以及很多读者的鼓励,现在就是想快点完成自己制定的任务,不过总有几个读者给自己鼓励,很欣慰的事情,不多感慨了 ...

  7. 这些孩子在 Ubuntu 的 Linux 终端下玩耍

    导读 我发现了一个孩子们在他们的计算机教室里玩得很开心的视频.我不知道他们在哪里,但我猜测是在印度尼西亚或者马来西亚.视频请自行搭梯子: https://youtu.be/z8taQPomp0Y 在L ...

  8. 在Linux终端下使用代理访问网络(转)

    最近,需要在linux环境下使用脚本进行一些网络访问(主要是HTTP请求与文件下载),于是查阅了一些关于代理的资料. 以下是尝试的几种代理设置方法,以供参考: 一.使用wget命令进行代理访问 wge ...

  9. linux终端下文件不同颜色的含义

    偶然注意到在终端下花花绿绿的目录显示效果,开始以为只是些特效,后来研究了一下,原来其中有些规律性的东西,总结如下: 蓝色表示目录:

随机推荐

  1. session与cookie的差别

    session     session 的工作机制是:为每一个訪客创建一个唯一的 id (UID),并基于这个 UID 来存储变量.UID 存储在 cookie 中,或者通过 URL 进行传导.   ...

  2. Git使用操作指南和GitHub

    本文记录Git的使用操作,把散落的记忆整理到一起.并介绍GitHub的使用. 使用Git代表着一种思想和境地,和SVN相比,不是技术上的差异有多么大,而是代表融入了一种新的生态环境.一种开放开源的心态 ...

  3. C# Windows Phone 8 WP8 开发,将WebClient的DownloadStringCompleted事件改成非同步的awiat方法。

    原文:C# Windows Phone 8 WP8 开发,将WebClient的DownloadStringCompleted事件改成非同步的awiat方法. 一般我们在撰写Windows Phone ...

  4. 玩转web之json(五)---将表单通过serialize()方法获取的值转成json

    form表单有一个serialize()方法,可以序列化表单的值,但是jquery提供的这个方法会把数据序列化为类似下面的形式: a=1&b=2&c=3&d=4 jquery并 ...

  5. 使用crontab创建 linux 系统定时任务#

    任务1: 每隔1分钟,运行一次 /home/sn/yeelink.sh文件 ,用于上传数据到www.yeelink.net 1. 先在当时目录里面创建一个cronfile文件 vim cronfile ...

  6. 判断闰年(go语言版本)

    import "strconv" func IsLeapYear(y string) bool { //y == 2000, 2004 //判断是否为闰年 year, _ := s ...

  7. Java RMI(远程方法调用) 实例与分析

    目的: 通过本文,可以加深对Java RMI的理解,知道它的工作原理,怎么使用等. 也为了加深我自己的理解,故整理成文.不足之处,还望指出. 概念解释: RMI(RemoteMethodInvocat ...

  8. Oracle基于学习3--Oracle创建用户和授权

    Oracleserver端的操作,如以下一般: 1)       安装Oracleserver软件 2)       创建数据库(安装时自己主动创建) 3)       配置监听(安装时自己主动配置) ...

  9. oracle 转让日期格式字符串

    字符串传递日期格式 SELECT trunc(to_date(SALE_MON,'yyyy-mm'),'y'),trunc(to_date(SALE_MON,'yyyy-mm'),'mm')  FRO ...

  10. DSR on Openstack POC

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvbGlwaW5nNDU1bWxwNDU1/font/5a6L5L2T/fontsize/400/fil ...