diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml index 38b749cf15e..c0d8a1682a8 100644 --- a/man/sysusers.d.xml +++ b/man/sysusers.d.xml @@ -191,7 +191,10 @@ u root 0 "Superuser" /root in the file system. In this case, the UID/GID is read from the path's owner/group. This is useful to create users whose UID/GID match the owners of pre-existing files (such as SUID or SGID - binaries). + binaries). + The syntax uid:gid is also supported to + allow creating user and group pairs with different numeric UID and GID values. The group with the indicated GID must get created explicitly before or it must already exist. + For m lines, this field should contain the group name to add to a user to. diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index d8009458ee3..e06b4b6d5b5 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -64,6 +64,7 @@ typedef struct Item { uid_t uid; bool gid_set:1; + bool gid_must_exist:1; bool uid_set:1; bool todo_user:1; @@ -74,9 +75,9 @@ static char *arg_root = NULL; static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysusers.d"); -static Hashmap *users = NULL, *groups = NULL; -static Hashmap *todo_uids = NULL, *todo_gids = NULL; -static Hashmap *members = NULL; +static OrderedHashmap *users = NULL, *groups = NULL; +static OrderedHashmap *todo_uids = NULL, *todo_gids = NULL; +static OrderedHashmap *members = NULL; static Hashmap *database_uid = NULL, *database_user = NULL; static Hashmap *database_gid = NULL, *database_group = NULL; @@ -256,7 +257,7 @@ static int putgrent_with_members(const struct group *gr, FILE *group) { assert(gr); assert(group); - a = hashmap_get(members, gr->gr_name); + a = ordered_hashmap_get(members, gr->gr_name); if (a) { _cleanup_strv_free_ char **l = NULL; bool added = false; @@ -307,7 +308,7 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) { assert(sg); assert(gshadow); - a = hashmap_get(members, sg->sg_namp); + a = ordered_hashmap_get(members, sg->sg_namp); if (a) { _cleanup_strv_free_ char **l = NULL; bool added = false; @@ -387,7 +388,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char Item *i; int r; - if (hashmap_size(todo_uids) == 0) + if (ordered_hashmap_size(todo_uids) == 0) return 0; r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp); @@ -405,13 +406,13 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char errno = 0; while ((pw = fgetpwent(original))) { - i = hashmap_get(users, pw->pw_name); + i = ordered_hashmap_get(users, pw->pw_name); if (i && i->todo_user) { log_error("%s: User \"%s\" already exists.", passwd_path, pw->pw_name); return -EEXIST; } - if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) { + if (ordered_hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) { log_error("%s: Detected collision for UID " UID_FMT ".", passwd_path, pw->pw_uid); return -EEXIST; } @@ -432,7 +433,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char return -errno; } - HASHMAP_FOREACH(i, todo_uids, iterator) { + ORDERED_HASHMAP_FOREACH(i, todo_uids, iterator) { struct passwd n = { .pw_name = i->name, .pw_uid = i->uid, @@ -474,7 +475,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char Item *i; int r; - if (hashmap_size(todo_uids) == 0) + if (ordered_hashmap_size(todo_uids) == 0) return 0; r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp); @@ -494,7 +495,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char errno = 0; while ((sp = fgetspent(original))) { - i = hashmap_get(users, sp->sp_namp); + i = ordered_hashmap_get(users, sp->sp_namp); if (i && i->todo_user) { /* we will update the existing entry */ sp->sp_lstchg = lstchg; @@ -502,7 +503,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char /* only the /etc/shadow stage is left, so we can * safely remove the item from the todo set */ i->todo_user = false; - hashmap_remove(todo_uids, UID_TO_PTR(i->uid)); + ordered_hashmap_remove(todo_uids, UID_TO_PTR(i->uid)); } errno = 0; @@ -521,7 +522,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char return -errno; } - HASHMAP_FOREACH(i, todo_uids, iterator) { + ORDERED_HASHMAP_FOREACH(i, todo_uids, iterator) { struct spwd n = { .sp_namp = i->name, .sp_pwdp = (char*) "!!", @@ -558,7 +559,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** Item *i; int r; - if (hashmap_size(todo_gids) == 0 && hashmap_size(members) == 0) + if (ordered_hashmap_size(todo_gids) == 0 && ordered_hashmap_size(members) == 0) return 0; r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp); @@ -580,13 +581,13 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** * entries anyway here, let's make an extra verification * step that we don't generate duplicate entries. */ - i = hashmap_get(groups, gr->gr_name); + i = ordered_hashmap_get(groups, gr->gr_name); if (i && i->todo_group) { log_error("%s: Group \"%s\" already exists.", group_path, gr->gr_name); return -EEXIST; } - if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) { + if (ordered_hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) { log_error("%s: Detected collision for GID " GID_FMT ".", group_path, gr->gr_gid); return -EEXIST; } @@ -609,7 +610,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** return -errno; } - HASHMAP_FOREACH(i, todo_gids, iterator) { + ORDERED_HASHMAP_FOREACH(i, todo_gids, iterator) { struct group n = { .gr_name = i->name, .gr_gid = i->gid, @@ -645,7 +646,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch Item *i; int r; - if (hashmap_size(todo_gids) == 0 && hashmap_size(members) == 0) + if (ordered_hashmap_size(todo_gids) == 0 && ordered_hashmap_size(members) == 0) return 0; r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp); @@ -663,7 +664,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch errno = 0; while ((sg = fgetsgent(original))) { - i = hashmap_get(groups, sg->sg_namp); + i = ordered_hashmap_get(groups, sg->sg_namp); if (i && i->todo_group) { log_error("%s: Group \"%s\" already exists.", gshadow_path, sg->sg_namp); return -EEXIST; @@ -687,7 +688,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch return -errno; } - HASHMAP_FOREACH(i, todo_gids, iterator) { + ORDERED_HASHMAP_FOREACH(i, todo_gids, iterator) { struct sgrp n = { .sg_namp = i->name, .sg_passwd = (char*) "!!", @@ -807,12 +808,12 @@ static int uid_is_ok(uid_t uid, const char *name) { Item *i; /* Let's see if we already have assigned the UID a second time */ - if (hashmap_get(todo_uids, UID_TO_PTR(uid))) + if (ordered_hashmap_get(todo_uids, UID_TO_PTR(uid))) return 0; /* Try to avoid using uids that are already used by a group * that doesn't have the same name as our new user. */ - i = hashmap_get(todo_gids, GID_TO_PTR(uid)); + i = ordered_hashmap_get(todo_gids, GID_TO_PTR(uid)); if (i && !streq(i->name, name)) return 0; @@ -1012,11 +1013,11 @@ static int add_user(Item *i) { i->uid = search_uid; } - r = hashmap_ensure_allocated(&todo_uids, NULL); + r = ordered_hashmap_ensure_allocated(&todo_uids, NULL); if (r < 0) return log_oom(); - r = hashmap_put(todo_uids, UID_TO_PTR(i->uid), i); + r = ordered_hashmap_put(todo_uids, UID_TO_PTR(i->uid), i); if (r < 0) return log_oom(); @@ -1030,11 +1031,11 @@ static int gid_is_ok(gid_t gid) { struct group *g; struct passwd *p; - if (hashmap_get(todo_gids, GID_TO_PTR(gid))) + if (ordered_hashmap_get(todo_gids, GID_TO_PTR(gid))) return 0; /* Avoid reusing gids that are already used by a different user */ - if (hashmap_get(todo_uids, UID_TO_PTR(gid))) + if (ordered_hashmap_get(todo_uids, UID_TO_PTR(gid))) return 0; if (hashmap_contains(database_gid, GID_TO_PTR(gid))) @@ -1098,6 +1099,18 @@ static int add_group(Item *i) { r = gid_is_ok(i->gid); if (r < 0) return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid); + if (i->gid_must_exist) { + /* If we require the gid to already exist we can return here: + * r > 0: means the gid does not exist -> fail + * r == 0: means the gid exists -> nothing more to do. + */ + if (r > 0) { + log_error("Failed to create %s: please create GID %d", i->name, i->gid); + return -EINVAL; + } + if (r == 0) + return 0; + } if (r == 0) { log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name); i->gid_set = false; @@ -1157,11 +1170,11 @@ static int add_group(Item *i) { i->gid = search_uid; } - r = hashmap_ensure_allocated(&todo_gids, NULL); + r = ordered_hashmap_ensure_allocated(&todo_gids, NULL); if (r < 0) return log_oom(); - r = hashmap_put(todo_gids, GID_TO_PTR(i->gid), i); + r = ordered_hashmap_put(todo_gids, GID_TO_PTR(i->gid), i); if (r < 0) return log_oom(); @@ -1185,30 +1198,8 @@ static int process_item(Item *i) { return add_user(i); - case ADD_GROUP: { - Item *j; - - j = hashmap_get(users, i->name); - if (j) { - /* There's already user to be created for this - * name, let's process that in one step */ - - if (i->gid_set) { - j->gid = i->gid; - j->gid_set = true; - } - - if (i->gid_path) { - r = free_and_strdup(&j->gid_path, i->gid_path); - if (r < 0) - return log_oom(); - } - - return 0; - } - + case ADD_GROUP: return add_group(i); - } default: assert_not_reached("Unknown item type"); @@ -1237,15 +1228,15 @@ static int add_implicit(void) { /* Implicitly create additional users and groups, if they were listed in "m" lines */ - HASHMAP_FOREACH_KEY(l, g, members, iterator) { + ORDERED_HASHMAP_FOREACH_KEY(l, g, members, iterator) { Item *i; char **m; - i = hashmap_get(groups, g); + i = ordered_hashmap_get(groups, g); if (!i) { _cleanup_(item_freep) Item *j = NULL; - r = hashmap_ensure_allocated(&groups, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops); if (r < 0) return log_oom(); @@ -1258,7 +1249,7 @@ static int add_implicit(void) { if (!j->name) return log_oom(); - r = hashmap_put(groups, j->name, j); + r = ordered_hashmap_put(groups, j->name, j); if (r < 0) return log_oom(); @@ -1268,11 +1259,11 @@ static int add_implicit(void) { STRV_FOREACH(m, l) { - i = hashmap_get(users, *m); + i = ordered_hashmap_get(users, *m); if (!i) { _cleanup_(item_freep) Item *j = NULL; - r = hashmap_ensure_allocated(&users, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops); if (r < 0) return log_oom(); @@ -1285,7 +1276,7 @@ static int add_implicit(void) { if (!j->name) return log_oom(); - r = hashmap_put(users, j->name, j); + r = ordered_hashmap_put(users, j->name, j); if (r < 0) return log_oom(); @@ -1348,7 +1339,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { _cleanup_free_ char *action = NULL, *name = NULL, *id = NULL, *resolved_name = NULL, *resolved_id = NULL, *description = NULL, *home = NULL; _cleanup_(item_freep) Item *i = NULL; Item *existing; - Hashmap *h; + OrderedHashmap *h; int r; const char *p; @@ -1494,11 +1485,11 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - r = hashmap_ensure_allocated(&members, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&members, &string_hash_ops); if (r < 0) return log_oom(); - l = hashmap_get(members, resolved_id); + l = ordered_hashmap_get(members, resolved_id); if (l) { /* A list for this group name already exists, let's append to it */ r = strv_push(&l, resolved_name); @@ -1507,7 +1498,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { resolved_name = NULL; - assert_se(hashmap_update(members, resolved_id, l) >= 0); + assert_se(ordered_hashmap_update(members, resolved_id, l) >= 0); } else { /* No list for this group name exists yet, create one */ @@ -1518,7 +1509,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { l[0] = resolved_name; l[1] = NULL; - r = hashmap_put(members, resolved_id, l); + r = ordered_hashmap_put(members, resolved_id, l); if (r < 0) { free(l); return log_oom(); @@ -1536,7 +1527,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - r = hashmap_ensure_allocated(&users, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&users, &string_hash_ops); if (r < 0) return log_oom(); @@ -1551,11 +1542,18 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { path_kill_slashes(i->uid_path); } else { - r = parse_uid(resolved_id, &i->uid); - if (r < 0) { - log_error("Failed to parse UID: %s", id); - return -EBADMSG; + _cleanup_free_ char *uid = NULL, *gid = NULL; + if (split_pair(resolved_id, ":", &uid, &gid) == 0) { + r = parse_gid(gid, &i->gid); + if (r < 0) + return log_error_errno(r, "Failed to parse GID: '%s': %m", id); + i->gid_set = true; + i->gid_must_exist = true; + free_and_replace(resolved_id, uid); } + r = parse_uid(resolved_id, &i->uid); + if (r < 0) + return log_error_errno(r, "Failed to parse UID: '%s': %m", id); i->uid_set = true; } @@ -1586,7 +1584,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return -EINVAL; } - r = hashmap_ensure_allocated(&groups, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&groups, &string_hash_ops); if (r < 0) return log_oom(); @@ -1602,10 +1600,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { path_kill_slashes(i->gid_path); } else { r = parse_gid(resolved_id, &i->gid); - if (r < 0) { - log_error("Failed to parse GID: %s", id); - return -EBADMSG; - } + if (r < 0) + return log_error_errno(r, "Failed to parse GID: '%s': %m", id); i->gid_set = true; } @@ -1622,7 +1618,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { i->name = resolved_name; resolved_name = NULL; - existing = hashmap_get(h, i->name); + existing = ordered_hashmap_get(h, i->name); if (existing) { /* Two identical items are fine */ @@ -1632,7 +1628,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { return 0; } - r = hashmap_put(h, i->name, i); + r = ordered_hashmap_put(h, i->name, i); if (r < 0) return log_oom(); @@ -1853,10 +1849,10 @@ int main(int argc, char *argv[]) { goto finish; } - HASHMAP_FOREACH(i, groups, iterator) + ORDERED_HASHMAP_FOREACH(i, groups, iterator) process_item(i); - HASHMAP_FOREACH(i, users, iterator) + ORDERED_HASHMAP_FOREACH(i, users, iterator) process_item(i); r = write_files(); @@ -1864,17 +1860,17 @@ int main(int argc, char *argv[]) { log_error_errno(r, "Failed to write files: %m"); finish: - hashmap_free_with_destructor(groups, item_free); - hashmap_free_with_destructor(users, item_free); + ordered_hashmap_free_with_destructor(groups, item_free); + ordered_hashmap_free_with_destructor(users, item_free); - while ((n = hashmap_first_key(members))) { - strv_free(hashmap_steal_first(members)); + while ((n = ordered_hashmap_first_key(members))) { + strv_free(ordered_hashmap_steal_first(members)); free(n); } - hashmap_free(members); + ordered_hashmap_free(members); - hashmap_free(todo_uids); - hashmap_free(todo_gids); + ordered_hashmap_free(todo_uids); + ordered_hashmap_free(todo_gids); free_database(database_user, database_uid); free_database(database_group, database_gid); diff --git a/test/TEST-21-SYSUSERS/Makefile b/test/TEST-21-SYSUSERS/Makefile new file mode 100644 index 00000000000..34d7cc6cdf7 --- /dev/null +++ b/test/TEST-21-SYSUSERS/Makefile @@ -0,0 +1,4 @@ +BUILD_DIR=$(shell ../../tools/find-build-dir.sh) + +all setup clean run: + @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@ diff --git a/test/TEST-21-SYSUSERS/test-1.expected-group b/test/TEST-21-SYSUSERS/test-1.expected-group new file mode 100644 index 00000000000..cc9093f8079 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-1.expected-group @@ -0,0 +1,2 @@ +g1:x:111: +u1:x:222: diff --git a/test/TEST-21-SYSUSERS/test-1.expected-passwd b/test/TEST-21-SYSUSERS/test-1.expected-passwd new file mode 100644 index 00000000000..8d0bfff319c --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-1.expected-passwd @@ -0,0 +1 @@ +u1:x:222:222::/:/sbin/nologin diff --git a/test/TEST-21-SYSUSERS/test-1.input b/test/TEST-21-SYSUSERS/test-1.input new file mode 100644 index 00000000000..bffc2cd7eae --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-1.input @@ -0,0 +1,3 @@ +#Type Name ID GECOS HOMEDIR +u u1 222 - - +g g1 111 - - diff --git a/test/TEST-21-SYSUSERS/test-2.expected-group b/test/TEST-21-SYSUSERS/test-2.expected-group new file mode 100644 index 00000000000..f98e85fcf49 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-2.expected-group @@ -0,0 +1 @@ +u1:x:999: diff --git a/test/TEST-21-SYSUSERS/test-2.expected-passwd b/test/TEST-21-SYSUSERS/test-2.expected-passwd new file mode 100644 index 00000000000..d907e483f7b --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-2.expected-passwd @@ -0,0 +1 @@ +u1:x:999:999:some gecos:/random/dir:/sbin/nologin diff --git a/test/TEST-21-SYSUSERS/test-2.input b/test/TEST-21-SYSUSERS/test-2.input new file mode 100644 index 00000000000..d8f31347a13 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-2.input @@ -0,0 +1,2 @@ +#Type Name ID GECOS HOMEDIR +u u1 - "some gecos" /random/dir diff --git a/test/TEST-21-SYSUSERS/test-3.expected-group b/test/TEST-21-SYSUSERS/test-3.expected-group new file mode 100644 index 00000000000..c3a63285c60 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-3.expected-group @@ -0,0 +1,4 @@ +hoge:x:300: +baz:x:302: +foo:x:301: +ccc:x:305: diff --git a/test/TEST-21-SYSUSERS/test-3.expected-passwd b/test/TEST-21-SYSUSERS/test-3.expected-passwd new file mode 100644 index 00000000000..a86954f8b33 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-3.expected-passwd @@ -0,0 +1,4 @@ +foo:x:301:301::/:/sbin/nologin +aaa:x:303:302::/:/sbin/nologin +bbb:x:304:302::/:/sbin/nologin +ccc:x:305:305::/:/sbin/nologin diff --git a/test/TEST-21-SYSUSERS/test-3.input b/test/TEST-21-SYSUSERS/test-3.input new file mode 100644 index 00000000000..b4f86a69f1f --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-3.input @@ -0,0 +1,7 @@ +g hoge 300 - - +u foo 301 - - + +g baz 302 - - +u aaa 303:302 - - +u bbb 304:302 - - +u ccc 305 - - diff --git a/test/TEST-21-SYSUSERS/test-4.expected-group b/test/TEST-21-SYSUSERS/test-4.expected-group new file mode 100644 index 00000000000..64913a5f500 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-4.expected-group @@ -0,0 +1 @@ +xxx:x:310: diff --git a/test/TEST-21-SYSUSERS/test-4.expected-passwd b/test/TEST-21-SYSUSERS/test-4.expected-passwd new file mode 100644 index 00000000000..e0370a40235 --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-4.expected-passwd @@ -0,0 +1,2 @@ +yyy:x:311:310::/:/sbin/nologin +xxx:x:312:310::/:/sbin/nologin diff --git a/test/TEST-21-SYSUSERS/test-4.input b/test/TEST-21-SYSUSERS/test-4.input new file mode 100644 index 00000000000..620423eab4f --- /dev/null +++ b/test/TEST-21-SYSUSERS/test-4.input @@ -0,0 +1,3 @@ +g xxx 310 +u yyy 311:310 +u xxx 312:310 diff --git a/test/TEST-21-SYSUSERS/test.sh b/test/TEST-21-SYSUSERS/test.sh new file mode 100755 index 00000000000..14f2b4ae07b --- /dev/null +++ b/test/TEST-21-SYSUSERS/test.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +set -e +TEST_DESCRIPTION="Sysuser-related tests" + +. $TEST_BASE_DIR/test-functions + +test_setup() { + mkdir -p $TESTDIR/etc $TESTDIR/usr/lib/sysusers.d $TESTDIR/tmp +} + +test_run() { + # ensure our build of systemd-sysusers is run + PATH=${BUILD_DIR}:$PATH + + # happy tests + for f in test-*.input; do + echo "*** Running $f" + rm -f $TESTDIR/etc/* + cp $f $TESTDIR/usr/lib/sysusers.d/test.conf + systemd-sysusers --root=$TESTDIR + + if ! diff -u $TESTDIR/etc/passwd ${f%.*}.expected-passwd; then + echo "**** Unexpected output for $f" + exit 1 + fi + if ! diff -u $TESTDIR/etc/group ${f%.*}.expected-group; then + echo "**** Unexpected output for $f" + exit 1 + fi + done + + # tests for error conditions + for f in unhappy-*.input; do + echo "*** Running test $f" + rm -f $TESTDIR/etc/* + cp $f $TESTDIR/usr/lib/sysusers.d/test.conf + systemd-sysusers --root=$TESTDIR 2> /dev/null + journalctl -t systemd-sysusers -o cat | tail -n1 > $TESTDIR/tmp/err + if ! diff -u $TESTDIR/tmp/err ${f%.*}.expected-err; then + echo "**** Unexpected error output for $f" + cat $TESTDIR/tmp/err + exit 1 + fi + done +} + +do_test "$@" diff --git a/test/TEST-21-SYSUSERS/unhappy-1.expected-err b/test/TEST-21-SYSUSERS/unhappy-1.expected-err new file mode 100644 index 00000000000..d3342402e98 --- /dev/null +++ b/test/TEST-21-SYSUSERS/unhappy-1.expected-err @@ -0,0 +1 @@ +Failed to parse UID: '9999999999': Numerical result out of range diff --git a/test/TEST-21-SYSUSERS/unhappy-1.input b/test/TEST-21-SYSUSERS/unhappy-1.input new file mode 100644 index 00000000000..77390371de3 --- /dev/null +++ b/test/TEST-21-SYSUSERS/unhappy-1.input @@ -0,0 +1 @@ +u u1 9999999999 - - \ No newline at end of file diff --git a/test/TEST-21-SYSUSERS/unhappy-2.expected-err b/test/TEST-21-SYSUSERS/unhappy-2.expected-err new file mode 100644 index 00000000000..5db5c202141 --- /dev/null +++ b/test/TEST-21-SYSUSERS/unhappy-2.expected-err @@ -0,0 +1 @@ +Failed to create u1: please create GID 100 diff --git a/test/TEST-21-SYSUSERS/unhappy-2.input b/test/TEST-21-SYSUSERS/unhappy-2.input new file mode 100644 index 00000000000..521c741cb56 --- /dev/null +++ b/test/TEST-21-SYSUSERS/unhappy-2.input @@ -0,0 +1,2 @@ +# it is not allowed to create groups implicitely in the uid:gid syntax +u u1 100:100 - \ No newline at end of file