sysusers: some tweaks, mostly around chase() use (#35976)

This commit is contained in:
Lennart Poettering
2025-01-14 14:38:32 +01:00
committed by GitHub
+32 -49
View File
@@ -164,28 +164,16 @@ static void maybe_emit_login_defs_warning(Context *c) {
}
static int load_user_database(Context *c) {
_cleanup_free_ char *passwd_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *passwd_path;
struct passwd *pw;
int r;
assert(c);
passwd_path = prefix_roota(arg_root, "/etc/passwd");
f = fopen(passwd_path, "re");
if (!f)
return errno == ENOENT ? 0 : -errno;
r = hashmap_ensure_allocated(&c->database_by_username, &string_hash_ops);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&c->database_by_uid, NULL);
if (r < 0)
return r;
/* Note that we use NULL, i.e. trivial_hash_ops here, so identical strings can exist in the set. */
r = set_ensure_allocated(&c->names, NULL);
r = chase_and_fopen_unlocked("/etc/passwd", arg_root, CHASE_PREFIX_ROOT, "re", &passwd_path, &f);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
@@ -195,19 +183,21 @@ static int load_user_database(Context *c) {
if (!n)
return -ENOMEM;
r = set_consume(c->names, n);
/* Note that we use NULL hash_ops (i.e. trivial_hash_ops) here, so identical strings can
* exist in the set. */
r = set_ensure_consume(&c->names, /* hash_ops= */ NULL, n);
if (r < 0)
return r;
assert(r > 0); /* The set uses pointer comparisons, so n must not be in the set. */
r = hashmap_put(c->database_by_username, n, UID_TO_PTR(pw->pw_uid));
r = hashmap_ensure_put(&c->database_by_username, &string_hash_ops, n, UID_TO_PTR(pw->pw_uid));
if (r == -EEXIST)
log_debug_errno(r, "%s: user '%s' is listed twice, ignoring duplicate uid.",
passwd_path, n);
else if (r < 0)
return r;
r = hashmap_put(c->database_by_uid, UID_TO_PTR(pw->pw_uid), n);
r = hashmap_ensure_put(&c->database_by_uid, /* hash_ops= */ NULL, UID_TO_PTR(pw->pw_uid), n);
if (r == -EEXIST)
log_debug_errno(r, "%s: uid "UID_FMT" is listed twice, ignoring duplicate name.",
passwd_path, pw->pw_uid);
@@ -218,50 +208,39 @@ static int load_user_database(Context *c) {
}
static int load_group_database(Context *c) {
_cleanup_free_ char *group_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *group_path;
struct group *gr;
int r;
assert(c);
group_path = prefix_roota(arg_root, "/etc/group");
f = fopen(group_path, "re");
if (!f)
return errno == ENOENT ? 0 : -errno;
r = hashmap_ensure_allocated(&c->database_by_groupname, &string_hash_ops);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&c->database_by_gid, NULL);
if (r < 0)
return r;
/* Note that we use NULL, i.e. trivial_hash_ops here, so identical strings can exist in the set. */
r = set_ensure_allocated(&c->names, NULL);
r = chase_and_fopen_unlocked("/etc/group", arg_root, CHASE_PREFIX_ROOT, "re", &group_path, &f);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
while ((r = fgetgrent_sane(f, &gr)) > 0) {
char *n = strdup(gr->gr_name);
if (!n)
return -ENOMEM;
r = set_consume(c->names, n);
/* Note that we use NULL hash_ops (i.e. trivial_hash_ops) here, so identical strings can
* exist in the set. */
r = set_ensure_consume(&c->names, /* hash_ops= */ NULL, n);
if (r < 0)
return r;
assert(r > 0); /* The set uses pointer comparisons, so n must not be in the set. */
r = hashmap_put(c->database_by_groupname, n, GID_TO_PTR(gr->gr_gid));
r = hashmap_ensure_put(&c->database_by_groupname, &string_hash_ops, n, GID_TO_PTR(gr->gr_gid));
if (r == -EEXIST)
log_debug_errno(r, "%s: group '%s' is listed twice, ignoring duplicate gid.",
group_path, n);
else if (r < 0)
return r;
r = hashmap_put(c->database_by_gid, GID_TO_PTR(gr->gr_gid), n);
r = hashmap_ensure_put(&c->database_by_gid, /* hash_ops= */ NULL, GID_TO_PTR(gr->gr_gid), n);
if (r == -EEXIST)
log_debug_errno(r, "%s: gid "GID_FMT" is listed twice, ignoring duplicate name.",
group_path, gr->gr_gid);
@@ -425,6 +404,8 @@ static int putsgent_with_members(
#endif
static const char* pick_shell(const Item *i) {
assert(i);
if (i->type != ADD_USER)
return NULL;
if (i->shell)
@@ -1058,11 +1039,8 @@ static int uid_is_ok(
return 1;
}
static int root_stat(const char *p, struct stat *st) {
const char *fix;
fix = prefix_roota(arg_root, p);
return RET_NERRNO(stat(fix, st));
static int root_stat(const char *p, struct stat *ret_st) {
return chase_and_stat(p, arg_root, CHASE_PREFIX_ROOT, /* ret_path= */ NULL, ret_st);
}
static int read_id_from_file(Item *i, uid_t *ret_uid, gid_t *ret_gid) {
@@ -2014,12 +1992,14 @@ static int help(void) {
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
"Creates system user accounts.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
printf("%1$s [OPTIONS...] [CONFIGURATION FILE...]\n"
"\n%2$sCreates system user and group accounts.%4$s\n"
"\n%3$sCommands:%4$s\n"
" --cat-config Show configuration files\n"
" --tldr Show non-comment parts of configuration\n"
" -h --help Show this help\n"
" --version Show package version\n"
"\n%3$sOptions:%4$s\n"
" --root=PATH Operate on an alternate filesystem root\n"
" --image=PATH Operate on disk image as filesystem root\n"
" --image-policy=POLICY Specify disk image dissection policy\n"
@@ -2027,8 +2007,11 @@ static int help(void) {
" --dry-run Just print what would be done\n"
" --inline Treat arguments as configuration lines\n"
" --no-pager Do not pipe output into a pager\n"
"\nSee the %s for details.\n",
"\nSee the %5$s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ansi_underline(),
ansi_normal(),
link);
return 0;