92

I need a way to get user home directory in C++ program running on Linux. If the same code works on Unix, it would be nice. I don't want to use HOME environment value.

AFAIK, root home directory is /root. Is it OK to create some files/folders in this directory, in the case my program is running by root user?

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Alex F
  • 42,307
  • 41
  • 144
  • 212
  • 2
    Current home directory of user (not named) is `~` is it not? As in `cd ~`, `mv some_file ~/some_file` etc. – Nick Bedford May 26 '10 at 05:59
  • 28
    @NickBedford - `~` is implemented by the shell, not the kernel or libc. When programming in C++, you need to implement that yourself. – R Samuel Klatchko May 26 '10 at 06:01
  • 3
    From a programmers point of view, Linux is Unix. It follows the same standards. It just hasn't been certified by The Open Group. From a users point of view, there is no more difference between Linux and "real" Unix systems, than there is among certified systems. – KeithB May 26 '10 at 11:29
  • 3
    Why don't you want to use `$HOME` thru `getenv("HOME")`? – Basile Starynkevitch Jul 31 '16 at 15:25
  • 2
    The HOME environment variable isn't reliable because it could be changed. R Samuel Klatchko's answer is more precise. *However*, you should consider the likelihood that if the user has redefined HOME, maybe they had a reason to do so, and your program would better serve the user's needs by using that variable. – Edward Falk Jul 23 '17 at 02:33

4 Answers4

113

You need getuid to get the user id of the current user and then getpwuid to get the password entry (which includes the home directory) of that user:

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

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

const char *homedir = pw->pw_dir;

Note: if you need this in a threaded application, you'll want to use getpwuid_r instead.

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
  • 54
    Note though that the `getpwuid()` man page has this caveat: *An application that wants to determine its user's home directory should inspect the value of `HOME` (rather than the value `getpwuid(getuid())->pw_dir` ) since this allows the user to modify their notion of "the home directory" during a login session.* – caf May 26 '10 at 06:50
  • 29
    I first check getenv("HOME") and then getpwuid() – Prof. Falken Nov 16 '11 at 07:32
  • 2
    This isn't a good answer to the original question. This is the shell starting directory set up in `/etc/passwd`, which may or may not be the user's (active) home directory. This is useful information, but `getenv` is the right answer. – lmat - Reinstate Monica May 16 '17 at 19:06
  • 1
    Most programs should prefer geteuid() over getuid(). Otherwise, if you run a command through sudo, for example, then it will examine your real user login rather than whichever login to which you sudo'ed. – jschultz410 Oct 02 '17 at 20:03
  • 1
    While considering using seteuid() instead of setuid(), also notice that environment variable will NOT change by sudo. That means if you favor $HOME variable than getpwuid(), you will always get the original user home directory, not the effective user home directoy. – Suyuan Chang Aug 07 '18 at 20:26
  • Does this have any chance of working under mingw on windows? I get that this comment might be off-topic since the question has a linux tag, but... – Steven Lu Jun 14 '19 at 23:12
  • I think it's arguable that `$HOME` is not really the user's *true* home directory. E.g. if you're looking for the home directory of another user there's no way to access their `$HOME`. `pw_dir` is the only option. If you do `cd ~other_user` it will use `pw_dir`, not `$HOME`. So `$HOME` may not be appropriate in every situation. – Timmmm Jan 22 '22 at 19:43
101

You should first check the $HOME environment variable, and if that does not exist, use getpwuid.

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

const char *homedir;

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

Also note, that if you want the home directory to store configuration or cache data as part of a program you write and want to distribute to users, you should consider following the XDG Base Directory Specification. For example if you want to create a configuration directory for your application, you should first check $XDG_CONFIG_HOME using getenv as shown above and only fall back to the code above if the variable is not set.

If you require multi-thread safety, you should use getpwuid_r instead of getpwuid like this (from the getpwnam(3) man page):

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;
9999years
  • 1,561
  • 13
  • 14
josch
  • 6,716
  • 3
  • 41
  • 49
  • 1
    You may need a mutex there. Otherwise the only way is `getpwuid_r`. Why that function fiddles with the locale, I do not know. – user877329 Jul 28 '16 at 09:39
  • That seems to be missing a free of buf. – Chris Sherlock May 20 '17 at 10:27
  • 1
    @ChrisSherlock I fear that if I `free(buf)` in my answer, then that might be misleading and lead to problems of a too early `free()` because according to the man page of `getpwuid_r`: "string fields pointed to by the members of the passwd structure are stored in the buffer buf of size buflen." So `buf` remains useful for as long as `pwd` is useful. – josch May 22 '17 at 13:44
  • `getenv("HOME")` returns the wrong thing for me on Ubuntu 17.10. it returns the application's working directory. – Violet Giraffe Nov 28 '17 at 21:36
  • @VioletGiraffe which might be equal to the home directory of the user running that program. – josch Dec 03 '17 at 21:51
  • @josch: no, that does not seem to be the case, unless each application gets its own user on startup. – Violet Giraffe Dec 03 '17 at 22:11
  • @VioletGiraffe how are you starting your application then? Most daemons for example are given their own user on startup. If you are starting the program from the command line, you can inspect what `echo $HOME` outputs. – josch Dec 04 '17 at 09:57
  • Why should you first check if `$HOME` exists? – jcarpenter2 Apr 12 '18 at 08:37
  • 1
    @jcarpenter2 because the user should be able to overwrite the home directory that a process is using. If you just rely on `getpwuid()` then you are making it impossible for a user to run the process with a different `$HOME`. – josch Apr 18 '18 at 13:57
  • `(homedir = getenv("HOME")) == NULL` Generates a warning for me – Casey Jul 07 '19 at 21:07
  • @Casey it would be useful to know the warning that you see plus your platform and compiler and so on... – josch Jul 09 '19 at 03:41
2

you can get home dir in c++ use this code

std::string home_dir = getenv("HOME");
0

If you're running the program as root then you'll have rwx access to this directory. Creating stuff inside it is fine, i suppose.

Anthony
  • 12,177
  • 9
  • 69
  • 105
  • 1
    There is no guarantee that /root will be the home directory for root on a particular system. It is generally a pretty bad idea to hard code paths into an application, as it makes the software much less portable. Using /root as a default (when the HOMEDIR cannot otherwise be determined) seems reasonable so long as there is a way to override it through configuration. – Yona Appletree May 15 '14 at 20:23
  • @Hypher All true, although the answer to the question "Is it OK to create some files/folders in this directory [/root], in the case my program is running by root user?" is "Yes". – Anthony May 18 '14 at 05:53