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

Reply via email to