diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 3522133532..f418f5b5ee 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1486,8 +1486,8 @@ The following specifiers are interpreted in the Install - section: %n, %N, %p, %i, %j, %U, %u, %m, %H, %b, %v. For their meaning - see the next section. + section: %n, %N, %p, %i, %j, %g, %G, %U, %u, %m, %H, %b, %v. For their + meaning see the next section. @@ -1614,6 +1614,16 @@ Directory for temporary files This is either /tmp or the path $TMPDIR, $TEMP or $TMP are set to. + + %g + User group + This is the name of the group running the service manager instance. In case of the system manager this resolves to root. + + + %G + User GID + This is the numeric GID of the user running the service manager instance. In case of the system manager this resolves to 0. + %u User name diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 814a01240a..49a5bdd166 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -628,6 +628,16 @@ w- /proc/sys/vm/swappiness - - - - 10 Directory for temporary files This is either /tmp or the path $TMPDIR, $TEMP or $TMP are set to. + + %g + User group + This is the name of the group running the command. In case of the system instance this resolves to root. + + + %G + User GID + This is the numeric GID of the group running the command. In case of the system instance this resolves to 0. + %u User name diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 046e937e92..547d9d8852 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -196,6 +196,8 @@ int unit_name_printf(Unit *u, const char* format, char **ret) { { 'p', specifier_prefix, NULL }, { 'i', specifier_string, u->instance }, + { 'g', specifier_group_name, NULL }, + { 'G', specifier_group_id, NULL }, { 'U', specifier_user_id, NULL }, { 'u', specifier_user_name, NULL }, @@ -264,6 +266,8 @@ int unit_full_printf(Unit *u, const char *format, char **ret) { { 'T', specifier_tmp_dir, NULL }, { 'V', specifier_var_tmp_dir, NULL }, + { 'g', specifier_group_name, NULL }, + { 'G', specifier_group_id, NULL }, { 'U', specifier_user_id, NULL }, { 'u', specifier_user_name, NULL }, { 'h', specifier_user_home, NULL }, diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index 078d5734be..b87d6b9d55 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -129,6 +129,8 @@ int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) { 'i', specifier_instance, NULL }, { 'j', specifier_last_component, NULL }, + { 'g', specifier_group_name, NULL }, + { 'G', specifier_group_id, NULL }, { 'U', specifier_user_id, NULL }, { 'u', specifier_user_name, NULL }, diff --git a/src/shared/specifier.c b/src/shared/specifier.c index b5f22c8d1e..78dda05b48 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -175,6 +175,24 @@ int specifier_kernel_release(char specifier, void *data, void *userdata, char ** return 0; } +int specifier_group_name(char specifier, void *data, void *userdata, char **ret) { + char *t; + + t = gid_to_name(getgid()); + if (!t) + return -ENOMEM; + + *ret = t; + return 0; +} + +int specifier_group_id(char specifier, void *data, void *userdata, char **ret) { + if (asprintf(ret, UID_FMT, getgid()) < 0) + return -ENOMEM; + + return 0; +} + int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { char *t; diff --git a/src/shared/specifier.h b/src/shared/specifier.h index e1895129d7..722200b998 100644 --- a/src/shared/specifier.h +++ b/src/shared/specifier.h @@ -20,6 +20,8 @@ int specifier_boot_id(char specifier, void *data, void *userdata, char **ret); int specifier_host_name(char specifier, void *data, void *userdata, char **ret); int specifier_kernel_release(char specifier, void *data, void *userdata, char **ret); +int specifier_group_name(char specifier, void *data, void *userdata, char **ret); +int specifier_group_id(char specifier, void *data, void *userdata, char **ret); int specifier_user_name(char specifier, void *data, void *userdata, char **ret); int specifier_user_id(char specifier, void *data, void *userdata, char **ret); int specifier_user_home(char specifier, void *data, void *userdata, char **ret); diff --git a/src/test/test-systemd-tmpfiles.py b/src/test/test-systemd-tmpfiles.py index 13a44f3c4a..28dadd0c5b 100755 --- a/src/test/test-systemd-tmpfiles.py +++ b/src/test/test-systemd-tmpfiles.py @@ -12,6 +12,7 @@ import socket import subprocess import tempfile import pwd +import grp try: from systemd import id128 @@ -95,9 +96,13 @@ def test_valid_specifiers(*, user): test_content('f {} - - - - %H', '{}'.format(socket.gethostname()), user=user) test_content('f {} - - - - %v', '{}'.format(os.uname().release), user=user) test_content('f {} - - - - %U', '{}'.format(os.getuid()), user=user) + test_content('f {} - - - - %G', '{}'.format(os.getgid()), user=user) - user = pwd.getpwuid(os.getuid()) - test_content('f {} - - - - %u', '{}'.format(user.pw_name), user=user) + puser = pwd.getpwuid(os.getuid()) + test_content('f {} - - - - %u', '{}'.format(puser.pw_name), user=user) + + pgroup = grp.getgrgid(os.getgid()) + test_content('f {} - - - - %g', '{}'.format(pgroup.gr_name), user=user) # Note that %h is the only specifier in which we look the environment, # because we check $HOME. Should we even be doing that? diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index cb074aaa4d..fe6da4fe2d 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -621,11 +621,13 @@ static void test_install_printf(void) { UnitFileInstallInfo i3 = { .name = name3, .path = path3, }; UnitFileInstallInfo i4 = { .name = name3, .path = path3, }; - _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL; assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); assert_se(host = gethostname_malloc()); + assert_se(group = gid_to_name(getgid())); + assert_se(asprintf(&gid, UID_FMT, getgid()) >= 0); assert_se(user = uid_to_name(getuid())); assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); @@ -652,6 +654,8 @@ static void test_install_printf(void) { expect(i, "%p", "name"); expect(i, "%i", ""); expect(i, "%j", "name"); + expect(i, "%g", group); + expect(i, "%G", gid); expect(i, "%u", user); expect(i, "%U", uid); @@ -659,12 +663,16 @@ static void test_install_printf(void) { expect(i, "%b", bid); expect(i, "%H", host); + expect(i2, "%g", group); + expect(i2, "%G", gid); expect(i2, "%u", user); expect(i2, "%U", uid); expect(i3, "%n", "name@inst.service"); expect(i3, "%N", "name@inst"); expect(i3, "%p", "name"); + expect(i3, "%g", group); + expect(i3, "%G", gid); expect(i3, "%u", user); expect(i3, "%U", uid); @@ -672,6 +680,8 @@ static void test_install_printf(void) { expect(i3, "%b", bid); expect(i3, "%H", host); + expect(i4, "%g", group); + expect(i4, "%G", gid); expect(i4, "%u", user); expect(i4, "%U", uid); } diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 157c900276..0d3674cff8 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -191,7 +191,7 @@ static void test_unit_name_mangle(void) { } static int test_unit_printf(void) { - _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL; _cleanup_(manager_freep) Manager *m = NULL; Unit *u; int r; @@ -200,7 +200,9 @@ static int test_unit_printf(void) { assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); assert_se(host = gethostname_malloc()); assert_se(user = uid_to_name(getuid())); + assert_se(group = gid_to_name(getgid())); assert_se(asprintf(&uid, UID_FMT, getuid())); + assert_se(asprintf(&gid, UID_FMT, getgid())); assert_se(get_home_dir(&home) >= 0); assert_se(get_shell(&shell) >= 0); @@ -241,6 +243,8 @@ static int test_unit_printf(void) { expect(u, "%I", ""); expect(u, "%j", "blah"); expect(u, "%J", "blah"); + expect(u, "%g", group); + expect(u, "%G", gid); expect(u, "%u", user); expect(u, "%U", uid); expect(u, "%h", home); @@ -263,6 +267,8 @@ static int test_unit_printf(void) { expect(u, "%I", "foo/foo"); expect(u, "%j", "blah"); expect(u, "%J", "blah"); + expect(u, "%g", group); + expect(u, "%G", gid); expect(u, "%u", user); expect(u, "%U", uid); expect(u, "%h", home); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 1b3cb5fbd3..d7e02c400e 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -174,6 +174,8 @@ static const Specifier specifier_table[] = { { 'H', specifier_host_name, NULL }, { 'v', specifier_kernel_release, NULL }, + { 'g', specifier_group_name, NULL }, + { 'G', specifier_group_id, NULL }, { 'U', specifier_user_id, NULL }, { 'u', specifier_user_name, NULL }, { 'h', specifier_user_home, NULL }, diff --git a/test/test-execute/exec-specifier.service b/test/test-execute/exec-specifier.service index 13ba859879..7c3f81f2b5 100644 --- a/test/test-execute/exec-specifier.service +++ b/test/test-execute/exec-specifier.service @@ -19,9 +19,11 @@ ExecStart=test %L = /var/log ExecStart=test %E = /etc ExecStart=test %T = /tmp ExecStart=test %V = /var/tmp -ExecStart=sh -c 'test %u = $$(id -un 0)' -ExecStart=test %U = 0 -ExecStart=sh -c 'test %h = $$(getent passwd 0 | cut -d: -f 6)' +ExecStart=sh -c 'test %u = $$(id -un)' +ExecStart=sh -c 'test %U = $$(id -u)' +ExecStart=sh -c 'test %g = $$(id -gn)' +ExecStart=sh -c 'test %G = $$(id -g)' +ExecStart=test %h = /root ExecStart=sh -c 'test %s = /bin/sh' ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)' ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')' diff --git a/test/test-execute/exec-specifier@.service b/test/test-execute/exec-specifier@.service index 174559dbd1..a388926846 100644 --- a/test/test-execute/exec-specifier@.service +++ b/test/test-execute/exec-specifier@.service @@ -17,9 +17,11 @@ ExecStart=test %S = /var/lib ExecStart=test %C = /var/cache ExecStart=test %L = /var/log ExecStart=test %E = /etc -ExecStart=sh -c 'test %u = $$(id -un 0)' -ExecStart=test %U = 0 -ExecStart=sh -c 'test %h = $$(getent passwd 0 | cut -d: -f 6)' +ExecStart=sh -c 'test %u = $$(id -un)' +ExecStart=sh -c 'test %U = $$(id -u)' +ExecStart=sh -c 'test %g = $$(id -gn)' +ExecStart=sh -c 'test %G = $$(id -g)' +ExecStart=test %h = /root ExecStart=sh -c 'test %s = /bin/sh' ExecStart=sh -c 'test %m = $$(cat /etc/machine-id)' ExecStart=sh -c 'test %b = $$(cat /proc/sys/kernel/random/boot_id | sed -e 's/-//g')' diff --git a/test/test-execute/exec-supplementarygroups-multiple-groups-default-group-user.service b/test/test-execute/exec-supplementarygroups-multiple-groups-default-group-user.service index 3b8cf2445b..2a7ce87bb4 100644 --- a/test/test-execute/exec-supplementarygroups-multiple-groups-default-group-user.service +++ b/test/test-execute/exec-supplementarygroups-multiple-groups-default-group-user.service @@ -2,10 +2,10 @@ Description=Test for Supplementary Group with multiple groups without Group and User [Service] -ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "0" && HAVE=1; done; test "$$HAVE" -eq 1' +ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "%G" && HAVE=1; done; test "$$HAVE" -eq 1' ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1' ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "2" && HAVE=1; done; test "$$HAVE" -eq 1' ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "3" && HAVE=1; done; test "$$HAVE" -eq 1' -ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "0" && test "$$(id -u)" = "0"' +ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "%G" && test "$$(id -u)" = "%U"' Type=oneshot SupplementaryGroups=1 2 3 diff --git a/test/test-execute/exec-supplementarygroups-multiple-groups-withgid.service b/test/test-execute/exec-supplementarygroups-multiple-groups-withgid.service index b7feedff61..aae20fbf95 100644 --- a/test/test-execute/exec-supplementarygroups-multiple-groups-withgid.service +++ b/test/test-execute/exec-supplementarygroups-multiple-groups-withgid.service @@ -5,7 +5,7 @@ Description=Test for Supplementary Group with multiple groups and Group=1 ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1' ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "2" && HAVE=1; done; test "$$HAVE" -eq 1' ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "3" && HAVE=1; done; test "$$HAVE" -eq 1' -ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "0"' +ExecStart=/bin/sh -x -c 'test "$$(id -g)" = "1" && test "$$(id -u)" = "%U"' Type=oneshot Group=1 SupplementaryGroups=1 2 3 diff --git a/test/test-execute/exec-supplementarygroups.service b/test/test-execute/exec-supplementarygroups.service index 5822c6b870..6f6e2ba822 100644 --- a/test/test-execute/exec-supplementarygroups.service +++ b/test/test-execute/exec-supplementarygroups.service @@ -2,7 +2,7 @@ Description=Test for Supplementary Group [Service] -ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "0" && HAVE=1; done; test "$$HAVE" -eq 1' +ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "%G" && HAVE=1; done; test "$$HAVE" -eq 1' ExecStart=/bin/sh -x -c 'HAVE=0; for g in $$(id -G); do test "$$g" = "1" && HAVE=1; done; test "$$HAVE" -eq 1' Type=oneshot SupplementaryGroups=1