Linux getpwnam()库的依赖关系

3

我有一个程序,在运行时系统调用getpwnam()失败了。为了调试这个问题,我决定使用以下代码(来自论坛)单独运行getpwnam()

#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
struct passwd *pw;

if (argc != 2) {
    printf("usage: %s username\n", argv[0]);
    exit(0);
}
pw = getpwnam(argv[1]);
if (pw == NULL)
    printf("getpwnam failed\n");
else
    printf("home dir = %s\n", pw->pw_dir);
    exit(0);
}

奇怪的是看起来似乎取决于存在 libnss_compat-2.3.5.so

使用 libnss_compat:

./pwnam root home dir = /root

不使用 libnss_compat:

./pwnam root getpwnam 失败

因此我的问题是,为什么 getpwnam() 依赖于 libnss_compat*.so?我用 nm -D 命令发现提供 getpwnam() 的库是 libc-2.3.5.so

readelf -d 显示,libc 只依赖于 ld.so.1。而这又没有依赖关系。那么为什么 libnss_compat 会有影响呢?

感谢大家的帮助!

1个回答

7
NSS是名称服务切换,一种能够在各种来源(传统密码文件,网络信息服务,LDAP)中查找用户信息的库。getpwnam可能在libc中定义,但这将在运行时加载实际的NSS库。在libc内部查找,我发现
$ strings /lib/x86_64-linux-gnu/libc.so.6 | grep libnss
libnss_
libnss_
libnss_%s.so.%d.%d

最后一行显然是一个格式字符串,用于构造实际实现库的名称,该库使用dlopen加载。实现是使用/etc/nsswitch.conf确定的。 编辑我在Glibc源代码中找到了加载库的位置。它不再使用snprintf,但原理仍然相同。

2
还要注意,在Linux上执行查找的方式以及加载哪些模块来执行查找通常是在/etc/nsswitch.conf中配置的。 - nos
谢谢!但是将来如果我的程序出现问题,如果readelf -d没有显示出library-xyz依赖于library-abc,我该怎么知道呢? - Andy J
2
@AndyJ0076 一般来说,你是做不到的。要静态确定由动态链接的C程序加载的库,你必须找出程序是否包含用于加载库的代码 dlopen,然后确定这些库是哪些以及代码是否曾经到达 dlopen 调用。后两个问题是不可判定的。stringsreadelfstrace 是你的好朋友,但它们不能捕捉所有情况。 - Fred Foo
在启动程序之前,您还可以设置环境变量LD_DEBUG=files,以便查看执行过程中动态链接的每个库。如果您有全面的测试套件来自动化该过程,那么这非常方便,但即使您手动使用应用程序时,它仍然很有价值。 - Dalzhim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接