c - `getlogin()` 是通过读取`/var/run/utmp` 来实现的吗?
问题描述
来自https://unix.stackexchange.com/a/268388/674
logname
上升拥有 的用户tty
(通过从 中读取/var/run/utmp
)
在coreutils 的源代码中,我发现它logname.c
是基于 Linux API 函数实现的getlogin
:
#include <unistd.h>
char *getlogin(void);
我/var/run/tmp
在logname.c
.
是getlogin()
通过读取来实现的/var/run/utmp
吗?
谢谢。
在我的 Lubuntu 18.04 上,strace logname
是否输出:
openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3
解决方案
找出是否logname
查看的最简单方法/var/run/utmp
是在 下运行它strace
,如下所示:
$ strace -e trace=open,openat logname 2>&1 | grep -Ev '\.so\.[0-9]+", O_RD'
该-e trace=open,openat
部分使其仅打印对open
(和openat
,glibc 真正喜欢在内部使用)的调用,并grep
过滤掉共享库的打开。这足以减少输出,以至于我实际上可以连贯地解释它:
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/self/loginuid", O_RDONLY) = 3
openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
zack
+++ exited with 0 +++
因此,在我的系统上,它打开的文件是/etc/ld.so.cache
和/usr/lib/locale/locale-archive
,它们都包含与 ; 无关的通用数据getlogin
;/proc/self/loginuid
,其中似乎包含我的用户 ID,我不知道记录在哪里;/etc/nsswitch.conf
,它告诉 C 库在哪里查找用户 ID 到名称的映射;和/etc/passwd
,其中(在我的系统上)包含该映射。它根本没有往里看/var/run/utmp
。
(例如,如果您用来模拟另一个用户,则 in 的值/proc/self/loginuid
将与返回的值不同;仍然为我打印“zack”。)getuid
su
su root -c logname
但是,如果我无法logname
查看/proc/self/loginuid
(通过临时绑定挂载一个空目录/proc
),那么我会得到一些不同的东西。(我在这里有点作弊:我strace
没有任何-e
选择就跑了,以找出哪些系统调用是相关的。我还手动进一步编辑了输出。)
$ strace -e trace=access,fstat,ioctl,open,openat,readlink,stat logname 2>&1 |
grep -Ev '\.so\.[0-9]+", O_RD'
...
openat(AT_FDCWD, "/proc/self/loginuid", O_RDONLY) = -1 ENOENT
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
readlink("/proc/self/fd/0", 0x7ffd2adfb030, 511) = -1 ENOENT
stat("/dev/pts/", {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0
openat(AT_FDCWD, "/dev/pts/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=0, ...}) = 0
stat("/dev/pts/1", {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
close(3) = 0
access("/var/run/utmpx", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3
...
logname: no login name
+++ exited with 1 +++
如果它无法打开/proc/self/loginuid
,那么它会花费一定的时间来查找与其自己的标准输入相关联的终端名称(简单的方法,readlink("/proc/self/fd/0")
不起作用,因为我为这个测试全部涂白了)/proc
然后它看起来在/var/run/utmp
首先确定 /var/run/utmpx
不存在之后。(这是一个错误;测试您要打开的文件是否已经存在具有固有的TOCTOU 竞赛。它应该打开它并检查是否打开失败。)它没有找到条目,所以它失败了。这是因为我使用的 Linux 发行版(sp。Debian 不稳定)已经决定每个终端窗口都有自己的 utmp 条目是愚蠢的,我的整个 X 会话应该只有一个,无论我是否打开任何终端:
$ who
zack :0 2018-05-30 17:37 (:0)
我认为这是一种与传统的决裂,但也是一种明智的做法。
推荐阅读
- c++ - Steamworks 和 SFML 程序退出时的访问冲突
- grails - 编译项目时出现类重复错误 - Grails 2.3.11
- android - 新的应用程序更新后,带有用户信息的 sqlite 数据库是否会被删除或重置
- c++ - 可转换类型的 C++ 括号运算符
- powershell - [System.IO.File]::ReadAllText 上的内存不足异常与大 CSV
- python - 在 GUI 中向嵌入式终端输入终端命令
- wordpress - 所有没有模板的帖子和页面都重定向到索引
- node.js - 节点:SerialPort 不是构造函数
- windows - STR_TO_DATE 不能在 mysql 中使用命令行
- java - 如何提取字符串的特定部分并用相同的提取值替换但在不同的情况下 - 使用java