如何获得控制终端的真实名称?


13

如何获得控制终端的真实名称(如果存在,否则为错误)作为路径名?

所谓“实名”,是指not /dev/tty,其他任意进程都不能使用它来指代同一终端。如果可能,我更倾向于将答案作为简单的shell代码(如下面的示例),否则作为C函数。

请注意,即使重定向了标准输入,此操作也必须起作用,以使该tty实用程序无法使用:not a tty在这种情况下,可能会出现错误,因为tty仅打印连接到标准输入的终端的文件名。

在Linux下,可以使用:

echo "/dev/`ps -p $$ -o tty | tail -n 1`"

但这不是可移植的,因为根据POSIX,终端名称的格式未指定

关于C函数,ctermid (NULL)return /dev/tty,在这里没有用。

注意:根据zsh文档,一个应该可以

zsh -c 'echo $TTY'

但是当同时重定向标准输入和标准输出时,当前(版本5.0.7)失败:

$ zsh -c 'echo $TTY > /dev/tty' < /dev/null
/dev/pts/9
$ zsh -c 'echo $TTY > /dev/tty' < /dev/null > /dev/null
/dev/tty

@mikeserv我认为该ps解决方案涵盖了大多数系统(并who没有提供更多帮助ps),可能包含更多的代码来单独处理标识符(例如“ 04”)。我想知道是否有更便携的解决方案。
vinc17

可能与预配对的集有关- 也许也是旧的bsd -style pty对。并非所有的pty都是UNIX 98类型。无论如何,from man xterm-Sccn 此选项允许xterm用作现有程序的I / O通道...该选项的值是在从属模式下使用的pty名称的几个字母,以及继承的fd编号。如果该选项包含“ /”字符,则它将从fd分隔pty名称。
mikeserv

@mikeserv请注意,即使在GNU / Linux下,该解决方案也无法psbusybox(由Android,BTW使用)使用。“ xterm可以处理04” 是什么意思?
vinc17

busybox不符合POSIX。toybox但是,效果很好。
mikeserv

Answers:


8

又称“控制终端”。ctty,不同于“ 进程正在与之交互终端”。

获取ctty路径的标准方法是ctermid(3)。调用此命令后, 从版本10开始的freebsd中,将查找实际路径 [1],而较早的freebsd和glibc实现 [2]将无条件返回“ / dev / tty”。

linux procps 3.2.8程序包中的ps(1),读取/ proc / * / stat [3]中的数字条目,然后由于缺乏系统支持通过猜测 [4,5] 部分扣除路径名 [6] 。

但是,如果我们对ctty并不是严格感兴趣,而是与stdio关联的任何终端,则tty(1)会输出连接到stdin的终端路径,该路径与ttyname(fileno(stdin))c中的相同,而替代方法是 readlink /proc/self/fd/0


关于无条件“ / dev / tty”行为的不太重要的想法:规范仅说ctermid返回的字符串“当用作路径名时,指的是当前控制终端”,而不是一些简单的“是当前路径名”控制终端”。可以将其解释为“ / dev / tty”不是控制终端,而是仅在同一进程open(3)时才引用控制终端。因此,不违反 “一个终端最多一个会话可能是ctty”规则 [7]。

另一个后果是,当我没有任何控制终端时,ctermid不会失败- 规范 [8] 允许这种失败 -因此,只有在随后的open(3)失败之前,我才能意识到我的ctty'lessless,没关系,因为规范还说对它调用open(3)不能保证成功。


这并不是ps我在问题中给出的解决方案的可移植性,因为并非所有操作系统都具有/proc文件系统。请注意,ps它本身使用了readlink /proc/self/fd/2(即使重定向标准错误也可以使用)。
vinc17

1
编辑。和/ proc / * / fd / 2上的ps readlink不是要查找ctty,而是要查找补充信息以将数字终端映射到路径,请参见link [4] [5]。
把友情留在无盐2015年

1
出色的编辑。关于ctty;我不能说vinc17,但是尽管您可能总是可以写到某个地方,但只有一个文件必须保持打开状态才能使您的进程组保持活动状态。
mikeserv

1
@ vinc17-如果您在ctty上打开了任何文件描述符,则可以使用读取它们ttystderr可能是最好的,因为它被指定为开放式读/写。所以tty <&2
mikeserv

1
给定的终端最多一个会话可能是ctty,这并不会使glibc ctermid()始终返回不合格"/dev/tty"。该名称始终指访问它的进程的控制终端,该终端随会话而变化。该终端是特定于会话的,但是不需要使用其名称。
PellMel

5

POSIX规范确实对控制终端所涉及的赌注进行了对冲,因此它定义了:

  • 控制终端
    • POSIX.1中未解决涉及终端的几个特殊文件中的哪个的问题。路径名/dev/tty是与进程关联的控制终端的同义词。

这在“定义”列表中-一切就在那里。但是在“ 通用终端接口”中,还有更多内容:

  • 终端可以作为其控制终端属于进程。具有控制终端的会话的每个进程都具有相同的控制终端。终端可以是最多一个会话的控制终端。会话的控制终端由会话负责人以实现定义的方式分配。如果会话负责人没有控制终端,并且在不使用O_NOCTTY选项的情况下打开了尚未与会话关联的终端设备文件(请参见open()),则实现定义为该终端是否成为会话的控制终端领导。

  • 控制终端在fork()函数调用期间被子进程继承。进程与新的会话创建会话时,将放弃其控制终端setsid()功能; 保留在旧会话中的其他进程(将其作为控制终端)继续拥有该终端。在与控制终端关联的系统中的最后一个文件描述符关闭时(无论它是否在当前会话中),都不确定是否以该终端作为其控制终端的所有进程都停止拥有任何控制终端。在以这种方式放弃控制终端之后,会话负责人是否以及如何能够重新获取控制终端,这是不确定的。如果其他进程继续将其打开,则进程不会仅通过关闭与控制终端关联的所有文件描述符来放弃其控制终端。

还有很多未指定的地方 -老实说,我认为这是有道理的。尽管终端是关键的用户界面,但在某些情况下它还是各种各样的东西,例如实际的硬件,甚至是打印机,但是在很多情况下,它几乎一无所获-就像xterm一个模拟器。在那里很难具体说明-而且我认为无论如何都不会对Unix有利,因为终端比Unix做得多。

无论如何,POSIX ps还很担心ctty的行为。

-a开关:

  • 编写与终端关联的所有过程的信息。实现可能会从此列表中省略会议负责人。

大。会议负责人可以省略。那不是很有帮助。

-t

  • 编写与术语表中给出的与终端相关的过程的信息。应用程序应确保术语列表是单个参数,形式为<blank>逗号分隔的列表。终端标识符应以实现定义的格式给出。

...这是另一个令人失望的地方。但这确实是关于XSI系统的说法:

  • 在符合XSI的系统上,应以以下两种形式之一给出:设备的文件名(例如tty04),或者,如果设备的文件名以开头tty,则仅在字符后面加上标识符tty (例如04

那好一点,但不是一条路。同样在XSI系统上,还有-d开关:

  • 编写所有过程的信息,但会议负责人除外。

...至少是清楚的。您也可以使用格式字符串指定-output开关tty,但是,正如您已经注意到的,其输出格式是实现定义的。尽管如此,我认为它仍然是最好的。我认为-通过大量工作,上述开关与其他一些实用程序的结合可以为您提供一个不错的选择。不过,老实说,我不知道它何时/如何为您带来麻烦-而且我也无法想象会发生什么情况。但是,我认为如果我们添加fuser并且find可以验证路径的话。

exec 2<>/dev/null
ctty=$(sh -c 'ps -p "$$" -o tty=' <&2)
sid=$(sh -c 'ps -Ao pid= -o tty=|
      grep '"$ctty$"' | 
      grep -Fv "$(ps -do pid=)"'  <&2)
find / -type c -name "*${ctty##*/}*" \
       -exec fuser -uv {} \; 2>&1  |
grep ".*$ctty.*${sid%%"$ctty"*}"

这些/dev/null内容只是为了表明当所有搜索子外壳都没有与ctty连接的0,1,2时,它可以工作。无论如何,打印:

/dev/pts/3:          mikeserv   3342 F.... (mikeserv)zsh

现在,上面的代码可以在我的机器上获得完整的路径,我想对于大多数人来说,大多数情况下都是如此。我也可以想象它可能会失败。这只是粗略的试探法。

这可能会由于其他许多原因而失败,但是,如果您使用的系统允许会话负责人将所有描述符都放弃给ctty,但仍然保留sid,那么在规范允许的范围内,那么这绝对不会有帮助。就是说,我认为在大多数情况下可以得到很好的估计。

当然,如果将任何描述符连接到您的ctty ,最简单的操作就是...

tty <&2

...或类似。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.