#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
thrugetenv("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». Sobuf
остается полезным до тех пор, пока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?» — «Да».