关于 backspace 是密码的一部分
在使用 hexo deploy 输入用户名/密码, 或其他特殊需要输入密码的场合, backspace 总是被当作密码的一部分.
这可以理解, 因为这个本身就是一种按键, 只不过大多数时候被赋予了删除字符的功能.
处于好奇, 搜索了一下相关资料
Backspace is traded as part of password when I use ‘hexo’ and other spacial situation that I need to enter password.
I can understand this because ‘backspace’ is also a normal key that traded as a function in some special situation .
solution
from stackExchange
Characters like Ctrl+L are handled by the application. In the case of entering input into the shell, like bash
, it clears the screen. Some applications, like emacs
, use it to redraw the screen and/or recenter the cursor.
C+L 都被应用所管理. 在输入时, 比如 bash. 将会清屏.
Characters like Ctrl+U at a password prompt are handled by the TTY line discipline. They’ll work any time the input terminal is in the “canonical” line-editing mode, which is what mode your programs are in while you’re entering a password. In this mode, it’s the Linux kernel itself that is interpreting these characters. You can see what functions are assigned to which keys in the output of stty -a
:
C+U被当作密码提示, 由 TTY line discipline 管理. 当输入密码, 进入行编辑模式时, 就会被其管理. linux 内核解释这些字符, 可以通过 stty -a
指令查看一些特殊的键被赋予的功能.
1 | speed 38400 baud; rows 45; columns 128; line = 0; |
Here, you can see that Ctrl+U is tied to kill
, which (according to the stty man page) will “erase the current line”. You could also use stty
to change this mapping:
通过 stty 的 man 手册可以查看这些指令的意义(看到里面的C+S了吧, 有时候 windows 习惯性保存带到 linux 的下场就是 ‘死机’ 📴) (我理解 stty 中的 s 可能是 soft 的意思)
1 | stty kill ^E # make ctrl-e erase the line |
This page has a lot of great information about the TTY layer if you’re interested.
other
关于 line discipline
from wiki
A line discipline (LDISC) is a layer in the terminal subsystem in some Unix-like systems.[1] The terminal subsystem consists of three layers: the upper layer to provide the character device interface, the lower hardware driver to communicate with the hardware or pseudo terminal, and the middle line discipline to implement behavior common to terminal devices.
LDISC 时一个类 UNIX 系统终端的子系统中的一层. 其完整为三层, 顶层提供一个字符设备界面. 下层硬件驱动与硬件/伪终端交互. 中层 ‘line discipline’ 实现常见的行为给终端设备(我理解这个行为可能是普通字符的回显以及特殊字符的解释)
The line discipline glues the low level device driver code with the high level generic interface routines (such as read(2), write(2) and ioctl(2)), and is responsible for implementing the semantics associated with the device.[2] The policy is separated from the device driver so that the same serial hardware driver can be used by devices that require different data handling.
‘line discipline’ 将底层驱动设备代码和高层泛型界面理解粘合在一起. 其实现了与设备相关的语义. 不同的设备驱动有不同的策略. 以用于同样的硬件驱动能被需要不同数据管理的设备所使用.
For example, the standard line discipline processes the data it receives from the hardware driver and from applications writing to the device according to the requirements of a terminal on a Unix-like system. On input, it handles special characters such as the interrupt character (typically Control-C) and the erase and kill characters (typically backspace or delete, and Control-U, respectively) and, on output, it replaces all the LF characters with a CR/LF sequence.
比如: 标准 ‘line discipline’ 程序处理来自硬件驱动和引用的数据. 根据系统终端的需求写入到设备. 在输入中, 其管理如中断字符的特殊字符, 实现响应功能. 在输入中, 将换行符表现为换行.
Some Unix-like systems use STREAMS to implement line disciplines.
(这里提到了流, 关于 wiki 中对于 流的解释: a stream is a chain of coroutines that pass messages between a program and a device driver (or between a pair of programs). 流是两者间传递信息的协同链.)
关于 character device
from wiki
In Unix-like operating systems, a device file or special file is an interface to a device driver that appears in a file system as if it were an ordinary file.
设备文件又称特殊文件, 是一个设备驱动的接口, 他能被当作一个普通文件一样执行.
Character devices
Character special files or character devices provide unbuffered, direct access to the hardware device. They do not necessarily allow programs to read or write single characters at a time; that is up to the device in question. The character device for a hard disk, for example, will normally require that all reads and writes are aligned to block boundaries and most certainly will not allow reading a single byte.
字符特殊文件/字符设备提供了无缓冲, 直接访问硬件设备. 硬盘上的字符设备, 通常需要所有的读取和写入对其块边界. 不允许读取单个字节.
Character devices are sometimes known as raw devices to avoid the confusion surrounding the fact that a character device for a piece of block-based hardware will typically require programs to read and write aligned blocks.
Block devices
Block special files or block devices provide buffered access to hardware devices, and provide some abstraction from their specifics.[5] Unlike character devices, block devices will always allow the programmer to read or write a block of any size (including single characters/bytes) and any alignment. The downside is that because block devices are buffered, the programmer does not know how long it will take before written data is passed from the kernel’s buffers to the actual device, or indeed in what order two separate writes will arrive at the physical device. Additionally, if the same hardware exposes both character and block devices, there is a risk of data corruption due to clients using the character device being unaware of changes made in the buffers of the block device.
块特殊文件/块设备提供了带缓冲的硬件设备访问. 同时还提供了一些抽象. 与字符设备不同的是, 块设备总是允许程序读取/写入任意大小任意对其的块 ( 这不坑👨🐎… 这不是应该是上面那种的定义么, 所以说, 历史错误啊… ). 因为块设备是带缓冲的, 不知何时数据会被写入. 也不知多个不同的写入者谁先写入.
Most systems create both block and character devices to represent hardware like hard disks. FreeBSD and Linux notably do not; the former has removed support for block devices,[6] while the latter creates only block devices. In Linux, to get a character device for a disk one must use the “raw” driver, though one can get the same effect as opening a character device by opening the block device with the Linux-specific O_DIRECT
flag.
linux 中可以通过打开块设备时指定 O_DIRECT 标识来模拟字符设备.
Pseudo-devices
Device nodes on Unix-like systems do not necessarily have to correspond to physical devices. Nodes that lack this correspondence form the group of pseudo-devices. They provide various functions handled by the operating system. Some of the most commonly used (character-based) pseudo-devices include:
类 Unix 系统的设备节点不必符合物理设备, 缺失这样条件的设备组成了伪设备. 它们提供了由操作系统管理的各种功能.
- /dev/null – accepts and discards all input written to it; provides an end-of-file indication when read from.
- /dev/zero – accepts and discards all input written to it; produces a continuous stream of null characters (zero-value bytes) as output when read from.
- /dev/full – produces a continuous stream of null characters (zero-value bytes) as output when read from, and generates an ENOSPC (“disk full”) error when attempting to write to it.
- /dev/random – produces bytes generated by the kernel’s cryptographically secure pseudorandom number generator. Its exact behavior varies by implementation, and sometimes variants such as /dev/urandom or /dev/arandom are also provided.
Additionally, BSD-specific pseudo-devices with an ioctl interface may also include:
- /dev/pf – allows userland processes to control PF through an ioctl interface.
- /dev/bio – provides ioctl access to devices otherwise not found as /dev nodes, used by bioctl to implement RAID management in OpenBSD and NetBSD.
- /dev/sysmon – used by NetBSD’s sysmon_envsys framework for hardware monitoring, accessed in the userland through proplib(3) by the envstat utility.[7]
(PS: 当我看到 /dev/full 的时候, 突然有了 ( ‵▽′)ψ😈 想法, /dev/null 是空文件, 经常用于清空文件, 比如 “cat /dev/null > file”. 那么 full 呢? 那当然是来填充文件的吧? 欸 是不是能和某个东西联系在一起? 是的, 删库😱… 如果我把东西删了之后, 再使用这个东西来填充无用数据, 那么是否意味着如果我把磁盘弄满, 至少通过磁盘自身恢复数据的方法无法使用了呢?
对此我进行了小测试(当然在我的主机上…), 它首先似乎受最大文件大小限制, 可以通过 ‘getconf FILESIZEBITS’ 获得. 获得的单位因该是以 GB 计算的. 我使用的主机是 64GB, 假设磁盘是 1TB, 那么至少需要 20 个并发的指令才能填满, 似乎不太难😊. 好了, 就先研究到这里)
关于 TTY
from document
The use cases
A user types at a terminal (a physical teletype). This terminal is connected through a pair of wires to a UART (Universal Asynchronous Receiver and Transmitter) on the computer. The operating system contains a UART driver which manages the physical transmission of bytes, including parity checks and flow control. In a naive system, the UART driver would then deliver the incoming bytes directly to some application process. But such an approach would lack the following essential features:
用户在终端(一个物理电传打字机)输入. 终端和 UART(通用异步接收传递)驱动(管理物理字节传输, 包括 parity 检测和流控制) 由一对电线连接. 在原始的系统中, UART 会直接将输入输入递送到应用程序中. 这会缺失一些重要的特性.
Line editing. Most users make mistakes while typing, so a backspace key is often useful. This could of course be implemented by the applications themselves, but in accordance with the UNIX design philosophy, applications should be kept as simple as possible. So as a convenience, the operating system provides an editing buffer and some rudimentary editing commands (backspace, erase word, clear line, reprint), which are enabled by default inside the line discipline. Advanced applications may disable these features by putting the line discipline in raw mode instead of the default cooked (or canonical) mode. Most interactive applications (editors, mail user agents, shells, all programs relying on curses
or readline
) run in raw mode, and handle all the line editing commands themselves. The line discipline also contains options for character echoing and automatic conversion between carriage returns and linefeeds. Think of it as a primitive kernel-level sed(1)
, if you like.
输入数据错误时, 经常需要使用 backspace 键. 这当然可以由应用自身实现. 但是根据 UNIX 设计的理念, 应用应该尽可能简洁. 所以为了简便起见, 操作系统提供了编辑缓冲和一些基本的编辑命令(backspace, ease word, clear line, reprint) 在 line discipline 中默认启用. 其他高级应用可能通过将其置于原始模式取消这些特性. 大多交互应用(编辑器, 用户邮件代理, shell, 所有依赖于 curses/ readline 的应用程序) 运行于原始模式. 自行管理行编辑命令. line discipline 还包含字符回显和自动转换回车和换行.
Session management. The user probably wants to run several programs simultaneously, and interact with them one at a time. If a program goes into an endless loop, the user may want to kill it or suspend it. Programs that are started in the background should be able to execute until they try to write to the terminal, at which point they should be suspended. Likewise, user input should be directed to the foreground program only. The operating system implements these features in the TTY driver (drivers/char/tty_io.c
).
用户当然希望同时运行多个程序并可以与其交互. 如果程序陷入死循环. 用户希望能暂停/关闭它. 程序在进入后台后应当依旧能运行, 直到它尝试向终端写入. 用户输入应当仅直接发送给前端程序. 操作系统将这些特性实现在了 TTY 驱动中.
An operating system process is “alive” (has an execution context), which means that it can perform actions. The TTY driver is not alive; in object oriented terminology, the TTY driver is a passive object. It has some data fields and some methods, but the only way it can actually do something is when one of its methods gets called from the context of a process or a kernel interrupt handler. The line discipline is likewise a passive entity.
一个程序是’活跃的’ 意味着它能执行操作. TTY 驱动并不是, 它是被动对象. 它拥有一些数据字段和方法. 仅当其方法被进程/内核中处理程序的上下文调用的时候才能做事. (就像一个库一样)
Together, a particular triplet of UART driver, line discipline instance and TTY driver may be referred to as a TTY device, or sometimes just TTY. A user process can affect the behaviour of any TTY device by manipulating the corresponding device file under /dev
. Write permissions to the device file are required, so when a user logs in on a particular TTY, that user must become the owner of the device file. This is traditionally done by the login(1)
program, which runs with root privileges.
合在一起, 一个特定的三重: UART 驱动, line discipline 实例, 和 TTY 驱动. 统称为 TTY 驱动. 或者有时直接称为 TTY. 用户进程可以通过对 /dev 下的设备文件的管理来改变任意 TTY 设备的行为. 这需要对于设备文件的写权限, 所以当用户登录特定的 TTY 时, 用户必须称为这个设备文件的所有者. 这通常由运行时带有 root 权限 login 程序来实现.
The physical line in the previous diagram could of course be a long-distance phone line:
This does not change much, except that the system now has to handle a modem hangup situation as well.
Let’s move on to a typical desktop system. This is how the Linux console works:
The TTY driver and line discipline behave just like in the previous examples, but there is no UART or physical terminal involved anymore. Instead, a video terminal (a complex state machine including a frame buffer of characters and graphical character attributes) is emulated in software, and rendered to a VGA display.
当数据输入时, 会通过一系列的交换最终由 TTY 发给进程, 而当数据输出时, 会原路 (但从 terminal emulator 开始分开) 发送给输出设备 (显示屏…)
The console subsystem is somewhat rigid. Things get more flexible (and abstract) if we move the terminal emulation into userland. This is how xterm(1)
and its clones work:
To facilitate moving the terminal emulation into userland, while still keeping the TTY subsystem (session management and line discipline) intact, the pseudo terminal or pty was invented. And as you may have guessed, things get even more complicated when you start running pseudo terminals inside pseudo terminals, à la screen(1)
or ssh(1)
.
这里有主从 TTY, 伪终端. 这里作者提到了 ssh. 我查了一下 PTY 相关的东西, 发现了 关于 ssh ‘-t’ 和 ‘-T’ 选项的说明. 就有了 stackExchange 和 stackOverflow 的解释.
-T: 这个选项不生产 PTY, 终端运行于本地, 这或许就是 PTY(pseudo) 为什么叫 PTY 的原因. github 的 ssh 也是带 -T 选项的, 因为如果为每个用户提供一个 tty 的话…
Now let’s take a step back and see how all of this fits into the process model.
Processes
A Linux process can be in one of the following states:
R | Running or runnable (on run queue) |
---|---|
D | Uninterruptible sleep (waiting for some event) |
S | Interruptible sleep (waiting for some event or signal) |
T | Stopped, either by a job control signal or because it is being traced by a debugger. |
Z | Zombie process, terminated but not yet reaped by its parent. |
(PS: 看到这里的时候, 我有点遗忘 ps 的细节了, 去看了看 ps 的说明. 然后明白了之前有次面试的事情了. 当时我还很好奇为什么会有人在我回答了查看所有进程的命令行后再问我一次. 我当时答的时 ps -axu (-aux?) 都是不对的. 而后者更是大错特错. 我最初需要这条指令时, 仅仅只是在网上查了下(误导我, 可恶啊…) 然后就全信了, 之后就只是瞄了一眼 man 手册. 并未过多在意. 这态度非常有问题, 包括之前的一个 C++ 空对象, 我给它赋值时依旧会出错, 我还好奇为什么, 因为我根本没仔细想过析构的问题. 作为一个技术人员, 我感觉很羞愧. 包括这次的笔记, 如果不是处于好奇, 也不会牵扯出这么多东西来, 学习是一个越学越少的过程. 我应当时刻这样警醒自己.)
By running ps l
, you can see which processes are running, and which are sleeping. If a process is sleeping, the WCHAN
column (“wait channel”, the name of the wait queue) will tell you what kernel event the process is waiting for.
1 | $ ps l |
The “wait
“ wait queue corresponds to the wait(2)
syscall, so these processes will be moved to the running state whenever there’s a state change in one of their child processes. There are two sleeping states: Interruptible sleep and uninterruptible sleep. Interruptible sleep (the most common case) means that while the process is part of a wait queue, it may actually also be moved to the running state when a signal is sent to it. If you look inside the kernel source code, you will find that any kernel code which is waiting for an event must check if a signal is pending after schedule() returns, and abort the syscall in that case.
有可中断和不可中断睡眠. 中断睡眠意味着如果进程在等待队列中, 那么其可以在信号发送给它时更新为运行态. 任何等待事件的内核代码都必须在调度返回后检查信号挂起.
In the ps
listing above, the STAT
column displays the current state of each process. The same column may also contain one or more attributes, or flags:
s | This process is a session leader. |
---|---|
+ | This process is part of a foreground process group. |
These attributes are used for job control.
Jobs and sessions
Job control is what happens when you press ^Z
to suspend a program, or when you start a program in the background using &
. A job is the same as a process group. Internal shell commands like jobs
, fg
and bg
can be used to manipulate the existing jobs within a session. Each session is managed by a session leader, the shell, which is cooperating tightly with the kernel using a complex protocol of signals and system calls.
The following example illustrates the relationship between processes, jobs and sessions:
工作管理在按下 C+Z 挂起程序或使用 & 使程序后台执行时发生. 一个工作就是一个经进程组. linux 提供了 jobs, fg, bg 在会话中管理现有工作. 每个绘画都由一个会话 leader 管理. shell , 和内核经由复杂的信号和系统调用协议密切合作.
(PS: 关于 process group , 简单来说就是一组进程, 而会话是一组进程组)
The following shell interactions…
…correspond to these processes…
…and these kernel structures.
TTY Driver (/dev/pts/0).
1
2
3
4
5
6
7
8
9
10
11Size: 45x13
Controlling process group: (101)
Foreground process group: (103)
UART configuration (ignored, since this is an xterm):
Baud rate, parity, word length and much more.
Line discipline configuration:
cooked/raw mode, linefeed correction,
meaning of interrupt characters etc.
Line discipline state:
edit buffer (currently empty),
cursor position within buffer etc.pipe0
1
2
3Readable end (connected to PID 104 as file descriptor 0)
Writable end (connected to PID 103 as file descriptor 1)
Buffer
The basic idea is that every pipeline is a job, because every process in a pipeline should be manipulated (stopped, resumed, killed) simultaneously. That’s why kill(2)
allows you to send signals to entire process groups. By default, fork(2)
places a newly created child process in the same process group as its parent, so that e.g. a ^C
from the keyboard will affect both parent and child. But the shell, as part of its session leader duties, creates a new process group every time it launches a pipeline.
基础的想法是每个管道都是一个工作. 因为每个管道中的进程都需要被同时管理. 默认在使用 fork 时会创建一个新子程序到同样的进程组中, 就和它的父进程一样. 所以 C+C 会影响父子进程, 但是 shell 作为会话 leader, 当创建一个新的管道的时候, 将会创建一个新的进程组.
The TTY driver keeps track of the foreground process group id, but only in a passive way. The session leader has to update this information explicitly when necessary. Similarly, the TTY driver keeps track of the size of the connected terminal, but this information has to be updated explicitly, by the terminal emulator or even by the user.
TTY 被动持续跟踪前台程序组 id. 会话 leader 必须在必要时更新这些信息(调用?). 同样的, TTY 驱动持续跟踪已连接终端大小.
As you can see in the diagram above, several processes have /dev/pts/0
attached to their standard input. But only the foreground job (the ls | sort
pipeline) will receive input from the TTY. Likewise, only the foreground job will be allowed to write to the TTY device (in the default configuration). If the cat process were to attempt to write to the TTY, the kernel would suspend it using a signal.
(我也没想到因为一个好奇能牵扯这些东西出来…)