This is useful, for example, to create system accounts on an initramfs using the host's configuration. --- src/sysusers/sysusers.c | 97 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 31 deletions(-)
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 0b5668a..9d39bd4 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -64,7 +64,7 @@ typedef struct Item { bool todo_group:1; } Item; -static char *arg_root = NULL; +static char *arg_root_config = NULL, *arg_root_dest = NULL; static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysusers"); @@ -79,7 +79,7 @@ static uid_t search_uid = UID_INVALID; static UidRange *uid_range = NULL; static unsigned n_uid_range = 0; -#define fix_root(x) (arg_root ? strjoina(arg_root, x) : x) +#define fix_root_dest(x) (arg_root_dest ? strjoina(arg_root_dest, x) : x) static int load_user_database(void) { _cleanup_fclose_ FILE *f = NULL; @@ -87,7 +87,7 @@ static int load_user_database(void) { struct passwd *pw; int r; - passwd_path = fix_root("/etc/passwd"); + passwd_path = fix_root_dest("/etc/passwd"); f = fopen(passwd_path, "re"); if (!f) return errno == ENOENT ? 0 : -errno; @@ -139,7 +139,7 @@ static int load_group_database(void) { struct group *gr; int r; - group_path = fix_root("/etc/group"); + group_path = fix_root_dest("/etc/group"); f = fopen(group_path, "re"); if (!f) return errno == ENOENT ? 0 : -errno; @@ -368,7 +368,7 @@ static int write_files(void) { _cleanup_fclose_ FILE *original = NULL; /* First we update the actual group list file */ - group_path = fix_root("/etc/group"); + group_path = fix_root_dest("/etc/group"); r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp); if (r < 0) goto finish; @@ -447,7 +447,7 @@ static int write_files(void) { } /* OK, now also update the shadow file for the group list */ - gshadow_path = fix_root("/etc/gshadow"); + gshadow_path = fix_root_dest("/etc/gshadow"); r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp); if (r < 0) goto finish; @@ -513,7 +513,7 @@ static int write_files(void) { long lstchg; /* First we update the user database itself */ - passwd_path = fix_root("/etc/passwd"); + passwd_path = fix_root_dest("/etc/passwd"); r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp); if (r < 0) goto finish; @@ -598,7 +598,7 @@ static int write_files(void) { } /* The we update the shadow database */ - shadow_path = fix_root("/etc/shadow"); + shadow_path = fix_root_dest("/etc/shadow"); r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp); if (r < 0) goto finish; @@ -772,7 +772,7 @@ static int uid_is_ok(uid_t uid, const char *name) { return 0; /* Let's also check via NSS, to avoid UID clashes over LDAP and such, just in case */ - if (!arg_root) { + if (!arg_root_dest) { errno = 0; p = getpwuid(uid); if (p) @@ -792,10 +792,10 @@ static int uid_is_ok(uid_t uid, const char *name) { return 1; } -static int root_stat(const char *p, struct stat *st) { +static int root_dest_stat(const char *p, struct stat *st) { const char *fix; - fix = fix_root(p); + fix = fix_root_dest(p); if (stat(fix, st) < 0) return -errno; @@ -811,7 +811,7 @@ static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) { assert(i); /* First, try to get the gid directly */ - if (_gid && i->gid_path && root_stat(i->gid_path, &st) >= 0) { + if (_gid && i->gid_path && root_dest_stat(i->gid_path, &st) >= 0) { gid = st.st_gid; found_gid = true; } @@ -819,7 +819,7 @@ static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) { /* Then, try to get the uid directly */ if ((_uid || (_gid && !found_gid)) && i->uid_path - && root_stat(i->uid_path, &st) >= 0) { + && root_dest_stat(i->uid_path, &st) >= 0) { uid = st.st_uid; found_uid = true; @@ -837,7 +837,7 @@ static int read_id_from_file(Item *i, uid_t *_uid, gid_t *_gid) { if (found_gid) { uid = (uid_t) gid; found_uid = true; - } else if (root_stat(i->gid_path, &st) >= 0) { + } else if (root_dest_stat(i->gid_path, &st) >= 0) { uid = (uid_t) st.st_gid; found_uid = true; } @@ -875,7 +875,7 @@ static int add_user(Item *i) { return 0; } - if (!arg_root) { + if (!arg_root_dest) { struct passwd *p; struct spwd *sp; @@ -999,7 +999,7 @@ static int gid_is_ok(gid_t gid) { if (hashmap_contains(database_uid, UID_TO_PTR(gid))) return 0; - if (!arg_root) { + if (!arg_root_dest) { errno = 0; g = getgrgid(gid); if (g) @@ -1034,7 +1034,7 @@ static int add_group(Item *i) { } /* Also check NSS */ - if (!arg_root) { + if (!arg_root_dest) { struct group *g; errno = 0; @@ -1691,7 +1691,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) { if (streq(fn, "-")) f = stdin; else { - r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &rf); + r = search_and_fopen_nulstr(fn, "re", arg_root_config, conf_file_dirs, &rf); if (r < 0) { if (ignore_enoent && r == -ENOENT) return 0; @@ -1752,25 +1752,46 @@ static void help(void) { "Creates system user accounts.\n\n" " -h --help Show this help\n" " --version Show package version\n" - " --root=PATH Operate on an alternate filesystem root\n" + " --root=PATH Operate on an alternate filesystem root (equivalent to a combination of --dest-root and --config-root)\n" + " --dest-root=PATH Create user accounts on an alternate filesystem root\n" + " --config-root=PATH Search for the configuration files on an alternate filesystem root\n" , program_invocation_short_name); } +static int set_arg_root(char **arg_root, const char *option) +{ + assert(arg_root); + assert(option); + + free(*arg_root); + *arg_root = path_make_absolute_cwd(option); + if(!*arg_root) + return log_oom(); + + path_kill_slashes(*arg_root); + + return 0; +} + static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_ROOT, + ARG_ROOT_CONFIG, + ARG_ROOT_DEST }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "root", required_argument, NULL, ARG_ROOT }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "root", required_argument, NULL, ARG_ROOT }, + { "dest-root", required_argument, NULL, ARG_ROOT_DEST }, + { "config-root", required_argument, NULL, ARG_ROOT_CONFIG }, {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -1789,12 +1810,25 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_ROOT: - free(arg_root); - arg_root = path_make_absolute_cwd(optarg); - if (!arg_root) - return log_oom(); + r = set_arg_root(&arg_root_config, optarg); + if (r < 0) + return r; - path_kill_slashes(arg_root); + r = set_arg_root(&arg_root_dest, optarg); + if (r < 0) + return r; + break; + + case ARG_ROOT_CONFIG: + r = set_arg_root(&arg_root_config, optarg); + if (r < 0) + return r; + break; + + case ARG_ROOT_DEST: + r = set_arg_root(&arg_root_dest, optarg); + if (r < 0) + return r; break; case '?': @@ -1843,7 +1877,7 @@ int main(int argc, char *argv[]) { _cleanup_strv_free_ char **files = NULL; char **f; - r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs); + r = conf_files_list_nulstr(&files, ".conf", arg_root_config, conf_file_dirs); if (r < 0) { log_error_errno(r, "Failed to enumerate sysusers.d files: %m"); goto finish; @@ -1869,7 +1903,7 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - lock = take_password_lock(arg_root); + lock = take_password_lock(arg_root_dest); if (lock < 0) { log_error_errno(lock, "Failed to take lock: %m"); goto finish; @@ -1918,7 +1952,8 @@ finish: free_database(database_user, database_uid); free_database(database_group, database_gid); - free(arg_root); + free(arg_root_config); + free(arg_root_dest); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } -- 2.3.0 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel