Получить домашний каталог в Linux

#c #linux #linux-kernel #operating-system #filesystems

#c #c #linux

Вопрос:

Мне нужен способ получить домашний каталог пользователя в программе C , работающей в Linux. Если тот же код работает в Unix, было бы неплохо. Я не хочу использовать значение домашней среды.

AFAIK, корневой домашний каталог — /root . Можно ли создавать некоторые файлы / папки в этом каталоге, если моя программа запущена пользователем root?

Комментарии:

1. Текущий домашний каталог пользователя (не назван) ~ , не так ли? Как и в cd ~ , mv some_file ~/some_file и т.д.

2. @NickBedford — ~ реализуется оболочкой, а не ядром или libc. При программировании на C вам необходимо реализовать это самостоятельно.

3. С точки зрения программистов, Linux — это Unix. Он соответствует тем же стандартам. Он просто не был сертифицирован Open Group. С точки зрения пользователей, между Linux и «настоящими» системами Unix не больше разницы, чем между сертифицированными системами.

4. Почему вы не хотите использовать $HOME thru getenv("HOME") ?

5. Переменная среды HOME ненадежна, поскольку ее можно изменить. Ответ Сэмюэля Клатчко более точен. Однако вам следует учитывать вероятность того, что, если пользователь переопределил HOME, возможно, у него была причина для этого, и ваша программа лучше удовлетворит потребности пользователя, используя эту переменную.

Ответ №1:

Вам нужно getuid получить идентификатор пользователя текущего пользователя, а затем getpwuid получить ввод пароля (который включает домашний каталог) этого пользователя:

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

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

const char *homedir = pw->pw_dir;
  

Примечание: если вам это нужно в потоковом приложении, вы захотите использовать getpwuid_r вместо этого.

Комментарии:

1. Обратите внимание, однако, что на getpwuid() справочной странице есть следующее предостережение: приложение, которое хочет определить домашний каталог своего пользователя, должно проверять значение HOME (а не значение getpwuid(getuid())->pw_dir ), поскольку это позволяет пользователю изменять свое представление о «домашнем каталоге» во время сеанса входа в систему.

2. Сначала я проверяю getenv(«HOME»), а затем getpwuid()

3. Это не очень хороший ответ на первоначальный вопрос. Это начальный каталог оболочки, в котором настроен /etc/passwd , который может быть или не быть домашним каталогом пользователя (активным). Это полезная информация, но getenv это правильный ответ.

4. Большинство программ должны предпочесть geteuid() вместо getuid(). В противном случае, если вы запустите команду, например, через sudo, тогда она проверит ваш реальный логин пользователя, а не тот логин, к которому вы подключились.

5. Рассматривая возможность использования seteuid() вместо setuid(), также обратите внимание, что переменная среды НЕ будет изменяться с помощью sudo. Это означает, что если вы предпочитаете переменную $HOME, а не getpwuid(), вы всегда будете получать исходный домашний каталог пользователя, а не эффективный домашний каталог пользователя.

Ответ №2:

Сначала вы должны проверить переменную $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 *resu<
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(), amp;pwd, buf, bufsize, amp;result);
if (result == NULL) {
    if (s == 0)
        printf("Not foundn");
    else {
        errno = s;
        perror("getpwnam_r");
    }
    exit(EXIT_FAILURE);
}
char *homedir = result.pw_dir;
  

Комментарии:

1. Там может понадобиться мьютекс. В противном случае единственный способ getpwuid_r . Я не знаю, почему эта функция зависит от локали.

2. Похоже, что отсутствует free of buf.

3. @ChrisSherlock Я боюсь, что если я free(buf) в своем ответе, то это может ввести в заблуждение и привести к проблемам слишком рано free() , потому что, согласно справочной странице getpwuid_r : «строковые поля, на которые указывают члены структуры passwd, хранятся в буфере buf размера buflen». So buf остается полезным до тех пор, пока pwd это полезно.

4. getenv("HOME") возвращает неправильную вещь для меня в Ubuntu 17.10. он возвращает рабочий каталог приложения.

5. @jcarpenter2 потому что пользователь должен иметь возможность перезаписать домашний каталог, который использует процесс. Если вы просто полагаетесь на getpwuid() , то вы делаете невозможным для пользователя запуск процесса с другим $HOME .

Ответ №3:

вы можете получить домашний каталог в c , используя этот код

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

Комментарии:

1. Чем это отличается от ответа Джоша 8 лет назад?

2. Разница в том, что «std» не пропущен и возвращается std::string тип.

3. Спасибо за совет . Я изменил программу.

Ответ №4:

Если вы запускаете программу от имени root, у вас будет доступ rwx к этому каталогу. Я полагаю, что создание материала внутри него — это нормально.

Комментарии:

1. Нет никакой гарантии, что /root будет домашним каталогом для root в конкретной системе. Как правило, довольно плохая идея вводить жесткие пути кода в приложение, поскольку это делает программное обеспечение намного менее переносимым. Использование /root по умолчанию (когда ДОМАШНИЙ каталог не может быть определен иным образом) кажется разумным, если есть способ переопределить его с помощью конфигурации.

2. @Hypher Все верно, хотя ответ на вопрос «Можно ли создавать некоторые файлы / папки в этом каталоге [/ root], в случае, если моя программа запущена пользователем root?» — «Да».