专家, 我有一个客户端通过ssh连接到服务器(它获得tty分配)。我有一个在服务器上运行的进程A.现在,每当客户端断开连接时,我需要A来了解消失的tty。
我在想,因为SSHD知道会话死亡(超时或简单退出后),它可以生成一个信号来处理A.
有没有其他方法可以获得有关tty的信息,就像收听TIGHUP的tty一样消失了?我在Linux上用C编写代码。
感谢您的帮助。
答案 0 :(得分:2)
POSIX.1提供了一个工具utmpx,它列出了当前登录的用户,他们的终端和其他信息。在Linux中,这与utmp相同;有关详细信息,请参阅man 5 utmp
。
OpenSSH确实保持了非常好的记录。
这是一个简单的示例,列出了当前从远程计算机登录的所有用户,他们使用的终端以及用户拥有的初始进程组:
#define _POSIX_C_SOURCE 200809L
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <utmpx.h>
int main(void)
{
struct utmpx *entry;
setutxent();
while ((entry = getutxent()))
if (entry->ut_type == USER_PROCESS && entry->ut_host[0] != '\0')
printf("%s is logged in on /dev/%s from %s and owns process group %d\n",
entry->ut_user, entry->ut_line, entry->ut_host,
(int)getpgid(entry->ut_pid));
return 0;
}
在您的情况下,我希望进程A维护远程连接用户的列表,并定期执行与上述类似的循环以更新已知条目的状态并添加新条目;并删除不再看到的条目。
新条目然后匹配“登录”事件,不再看到“注销”事件的条目(并在循环后删除),所有其他事件“仍然登录”用户。
上面的循环在使用的CPU时间和使用的I / O方面非常轻量级。 utmp记录(大多数Linux机器中的/var/run/utmp
)是二进制形式,如果频繁访问,通常在页面缓存中。条目相对较小,即使在拥有大量用户的服务器上,文件读取的大小也远低于兆字节。不过,我不会紧紧地做这件事。
就个人而言,我会使用inotify
在CLOSE_WRITE
文件上等待UTMPX_FILE
个事件(大多数Linux机器上为/var/run/utmp
),并在每次事件后重新读取记录。这样,服务将在大多数时间阻塞inotify文件描述符上的read()
(不浪费任何CPU时间),并且几乎立即对任何登录/注销事件作出反应。
答案 1 :(得分:1)
你面临两个问题,既困难又困难。简洁的答案是“你做不到”;更长的答案是“你不能不做出重大修改”。
除了事件发生之外,信号传递的信息非常少。如果您使用sigaction()
和SA_SIGINFO
,则可以找到发送信号的流程的进程ID,但在您的方案下,这将是sshd
,这不是非常有用。因此,通过信号获得关于哪个终端的信息将很难(几乎不可能)。显然,可以定义其他方案,但是您必须将信息写入文件或类似文件。
您必须修改sshd
以记录有关它为子进程分配(或分配)的终端的信息,然后安排它将该信息发送到您的进程A.一个孩子终止。这充其量是棘手的。
仅这两个因素使其变得相当困难。如果你仍然想要这样做,那么我尝试的方法是让sshd
运行你设计的特殊过程,然后分叉,并且孩子运行sshd
将要执行的过程否则跑。父母(a)记录孩子所连接的终端,以及(b)等待孩子终止。当它发生时,它将终端信息写入进程A将找到它的某个地方,然后退出。你仍然需要修改sshd
,你必须设计一种机制,让父进程知道作为子进程运行的内容(但这可能不是很难;你保持参数列表不变,但只是{{} 1}}执行您的监视进程而不是指定为sshd
的任何内容...父进程使用argv[0]
作为argv[0]
的文件参数。
此方案最小化对execvp()
的更改(但仍需要非标准版本)。而且你必须仔细编写父代码,并且它必须与进程A合作。所有这些都是非常重要的。