在Linux中获取主目录


69

我需要一种在Linux上运行的C ++程序中获取用户主目录的方法。如果相同的代码可以在Unix上运行,那就太好了。我不想使用HOME环境值。

AFAIK,根主目录是/ root。如果我的程序由root用户运行,可以在此目录中创建一些文件/文件夹吗?


2
用户(未命名)的当前主目录~不是吗?如cd ~mv some_file ~/some_file等等
尼克·贝德福德

20
@NickBedford-~由外壳而不是内核或libc实现。使用C ++编程时,您需要自己实现。
R Samuel Klatchko

3
从程序员的角度来看,Linux是Unix。它遵循相同的标准。它只是尚未获得The Open Group的认证。从用户的角度来看,Linux和“真实” Unix系统之间的区别没有经过认证的系统之间的区别更多。
KeithB 2010年

2
您为什么不想使用$HOME直通车getenv("HOME")
Basile Starynkevitch 2016年

2
HOME环境变量不可靠,因为可以对其进行更改。R Samuel Klatchko的答案更为精确。但是,您应该考虑以下可能性:如果用户重新定义了HOME,也许他们有理由这样做,并且您的程序可以通过使用该变量更好地满足用户的需求。
爱德华·福尔克

Answers:


96

您需要getuid获取当前用户的用户ID,然后getpwuid获取该用户的密码条目(包括主目录):

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>

struct passwd *pw = getpwuid(getuid());

const char *homedir = pw->pw_dir;

注意:如果您在线程化应用程序中需要此功能,则可以getpwuid_r改用。


48
请注意,尽管getpwuid()手册页有以下警告:想要确定其用户主目录的应用程序应检查HOME(而不是value getpwuid(getuid())->pw_dir)的值,因为这允许用户在登录会话期间修改其“主目录”的概念。
caf 2010年

25
我先检查getenv(“ HOME”),然后再检查getpwuid()
Falken教授,

1
这不是对原始问题的好答案。这是在中设置的shell起始目录/etc/passwd,它可能是也可能不是用户的(活动)主目录。这是有用的信息,但是getenv正确的答案。
lmat-恢复莫妮卡

1
大多数程序应该比getuid()更喜欢geteuid()。否则,例如,如果您通过sudo运行命令,则它将检查您的真实用户登录名,而不是您sudo所登录的任何登录名。
jschultz410

1
在考虑使用seteuid()而不是setuid()时,还要注意环境变量不会因sudo而改变。这意味着,如果您更喜欢$ HOME变量而不是getpwuid(),则将始终获得原始用户主目录,而不是有效用户主目录。
苏元Chang

83

您应该首先检查$HOME环境变量,如果该变量不存在,请使用getpwuid。

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>

const char *homedir;

if ((homedir = getenv("HOME")) == NULL) {
    homedir = getpwuid(getuid())->pw_dir;
}

还要注意,如果您希望主目录将配置或缓存数据作为编写的程序的一部分并希望分发给用户,则应考虑遵循XDG基本目录规范。例如,如果要为应用程序创建配置目录,则应首先检查$XDG_CONFIG_HOME使用getenv如上所示,如果未设置变量,则仅使用上面的代码。

如果您需要多线程安全性,则应使用getpwuid_r而不是getpwuid这样(在getpwnam(3)手册页中):

struct passwd pwd;
struct passwd *result;
char *buf;
size_t bufsize;
int s;
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1)
    bufsize = 0x4000; // = all zeroes with the 14th bit set (1 << 14)
buf = malloc(bufsize);
if (buf == NULL) {
    perror("malloc");
    exit(EXIT_FAILURE);
}
s = getpwuid_r(getuid(), &pwd, buf, bufsize, &result);
if (result == NULL) {
    if (s == 0)
        printf("Not found\n");
    else {
        errno = s;
        perror("getpwnam_r");
    }
    exit(EXIT_FAILURE);
}
char *homedir = result.pw_dir;

您可能需要一个互斥锁。否则,唯一的方法是getpwuid_r。我不知道为什么该功能在语言环境中摆弄。
user877329 '16

似乎缺少了一点buf。
克里斯·夏洛克

1
@ChrisSherlock我担心,如果free(buf)我回答我,那可能会误导人,并导致问题为时过早,free()因为根据手册页getpwuid_r:“ passwd结构的成员指向的字符串字段存储在缓冲区buf中大小为buflen。” 因此buf,只要有用就保持pwd有用。
josch

getenv("HOME")在Ubuntu 17.10上为我返回错误的内容。它返回应用程序的工作目录。
紫罗兰色长颈鹿

1
@ jcarpenter2,因为用户应该能够覆盖进程正在使用的主目录。如果您仅依赖于此,getpwuid()则将使用户无法使用其他命令运行该过程$HOME
josch

0

如果您以root用户身份运行程序,那么您将具有rwx访问此目录的权限。我想在里面创建东西很好。


1
不能保证/ root将是特定系统上root的主目录。将路径硬编码到应用程序中通常是一个非常糟糕的主意,因为它使软件的可移植性大大降低。只要有一种方法可以通过配置覆盖它,那么将/ root用作默认值(当无法确定HOMEDIR时)似乎是合理的。
Yona Appletree,2014年

@Hypher全部正确,尽管问题的答案是“如果我的程序由root用户运行,可以在此目录[/ root]中创建一些文件/文件夹吗?” 是是的”。
安东尼
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.