我正在尝试设置 getty 通过串行登录(主要作为实验)。
几乎任何配置都会发生同样的事情。如果我的默认 shell 是bash
,我在登录后会收到以下消息:
-bash: cannot set terminal process group (15297): Inappropriate ioctl for device
-bash: no job control in this shell
然后为了证明它不起作用,我不能使用ctrl+C来停止程序:
$ sleep 30
^C
而且似乎没有发出信号。
这些是我尝试过的配置:
我已经尝试过这两个命令
# copied from raspberry pi:
sudo /sbin/agetty --keep-baud 115200,38400,9600 ttyUSB0 vt220
# something else I read somewhere
sudo getty -L ttyUSB0 9600 vt100
# (I know I'm mixing and matching a lot of differences but the result is the same)
我作为客户端尝试过 screen 和 picocom。
我尝试过使用 rasberry pi 作为服务器,以及两台不同的 ubuntu 笔记本电脑。
我尝试过两个 FTDI、两个 RS-485 USB 适配器,以及 getty 端的内置 RS232 和客户端的 USB RS232。
我还尝试将默认 shell 更改为 sh 和 dash。我没有收到消息,但 ctrl+C 仍然无法按预期工作
有趣的是 - 当树莓派自动配置/dev/ttyAMA0
,并且它完全使用我放置的 getty 命令时,作业控制起作用了!
并且终端设置几乎相同。(实际上除了-iutf8)
以下是 FTDI 连接和 picocom 运行的终端设置:
$ stty -a -F /dev/ttyUSB0
speed 9600 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D;
eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q;
stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = <undef>; discard = <undef>; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal
-crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr
-icrnl ixon ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0
tab0 bs0 vt0 ff0
isig -icanon -iexten -echo echoe echok -echonl -noflsh -xcase
-tostop -echoprt echoctl echoke -flusho -extproc
$ stty -a -F /dev/ttyUSB1
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D;
eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q;
stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal
-crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr
-icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0
cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo echoe echok -echonl -noflsh -xcase
-tostop -echoprt echoctl echoke -flusho -extproc
我究竟做错了什么?为什么它可以与树莓派上内置串口的内置配置一起使用?
区别不在于命令,而在于它们运行的环境。
通常 getty 直接从系统服务管理器 (init) 生成 - 在 systemd 中它是一个 .service,在 SysV 世界中它有一个 inittab 条目(而不是 init.d 脚本!)。这与从另一个终端生成的有几个不同之处。
首先,从终端启动的进程会继承该终端作为其控制终端,这是 shell 作业控制最重要的参数。
ps aux
您可以在or – 服务进程中看到这一点,ps -ef
一开始没有 ctty,因此当 getty 打开指示的终端时,一旦 shell 运行,该终端就会成为其用于作业控制的控制终端。但是从 xterm 启动的 getty 将继续将 xterm pty 作为其控制 tty,尽管它的输入/输出现在被路由到串行端口。控制终端定义/dev/tty;它定义了作业控制信号被发送到哪些进程;它定义了终端关闭后哪些进程将被终止(SIGHUP)。如果您的 shell 继承了与其 stdin/out tty 不同的控制 tty,则可能会发生各种奇怪的事情。
有多种方法可以使进程与其先前的终端分离,例如调用setsid(),但 getty 不会自动使用它们,因为它不希望以这种方式运行。(有一个
setsid
可以使用的工具,但您也不应该在这里使用它。)理想情况下你应该只是
systemctl start serial-getty@ttyAMA0
让 getty 在一个干净的环境中运行。如果需要自定义选项,请使用常规“systemctl edit”编辑该服务,但切勿直接运行 getty。(如果未使用 systemd,则编辑/etc/inittab
;它通常包含一个示例。)从 shell 启动的进程与通过服务管理器启动的进程之间还有许多其他相对较小的差异:
该进程将继承您的终端作为 stdin/stdout/err。Getty 只会关闭它们并重新开放它所需要的内容,但许多其他程序不会,我什至看到基于此改变行为的服务(......根本没有充分的理由,但仍然如此)。
该进程将继承各种可能相关或无用的环境变量。例如,因为您通过 sudo 启动它,所以它的环境中将具有 SUDO_USER (并且某些工具在看到通过 sudo 调用它们时实际上会更改其行为)。
该进程将继承您的 SELinux 上下文(如果有)(例如在 Fedora/RHEL 上),并且可能不允许再次更改它。它还继承了 /proc/PID/loginuid 中找到的“登录 UID”之类的内容,并且一旦设置就无法重置(用于审核日志记录)。在某些发行版中,它还可能继承 AppArmor 配置文件、SMACK 标签等。
即使不同的用户登录,该进程也将位于您原来的“用户”cgroup 中。Systemd-logind 向 Linux 添加了“用户会话”的概念,并且它以 Linux cgroup 为基础:当服务进程(例如 sshd 或agetty,通过 PAM 处理您的登录,它使用 systemd-logind 注册自己,并从其“服务”cgroup 移动到“用户”cgroup,例如 .agetty
user-1002.slice
。然而,已经在这样的“用户”cgroup 中运行的进程不允许再次执行相同的操作 – 即使它具有 root 权限。所有这些都表明存在许多看不见的差异,并且在 Linux 上您不应该像一般做法那样通过 sudo 启动服务;特别是接受用户登录的服务。