From 250e9fadbcc0ca90e697d7efb40855b054ed3b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 23 Apr 2018 22:43:20 +0200 Subject: [PATCH] Add %j/%J unit specifiers Those are quite similar to %i/%I, but refer to the last dash-separated component of the name prefix. The new functionality of dash-dropins could largely supersede the template functionality, so it would be tempting to overload %i/%I. But that would not be backwards compatible. So let's add the two new letters instead. --- man/systemd.unit.xml | 12 +++++- src/core/unit-printf.c | 77 ++++++++++++++++++++++++++----------- src/shared/install-printf.c | 22 +++++++++++ src/test/test-unit-file.c | 1 + src/test/test-unit-name.c | 56 ++++++++++++++++++--------- 5 files changed, 127 insertions(+), 41 deletions(-) diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index d66b6aad08..02e0f499e8 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1508,7 +1508,7 @@ The following specifiers are interpreted in the Install - section: %n, %N, %p, %i, %U, %u, %m, %H, %b, %v. For their meaning + section: %n, %N, %p, %i, %j, %U, %u, %m, %H, %b, %v. For their meaning see the next section. @@ -1566,6 +1566,16 @@ Unescaped instance name Same as %i, but with escaping undone. + + %j + Final component of the prefix + This is the string between the last - and the end of the prefix name. If there is no -, this is the same as %p. + + + %J + Unescaped final component of the prefix + Same as %j, but with escaping undone. + %f Unescaped filename diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 1e260dd9bc..d2948ab6aa 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -55,6 +55,37 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda return unit_name_unescape(strempty(u->instance), ret); } +static int specifier_last_component(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + _cleanup_free_ char *prefix = NULL; + char *dash; + int r; + + assert(u); + + r = unit_name_to_prefix(u->id, &prefix); + if (r < 0) + return r; + + dash = strrchr(prefix, '-'); + if (dash) + return specifier_string(specifier, dash + 1, userdata, ret); + + *ret = TAKE_PTR(prefix); + return 0; +} + +static int specifier_last_component_unescaped(char specifier, void *data, void *userdata, char **ret) { + _cleanup_free_ char *p = NULL; + int r; + + r = specifier_last_component(specifier, data, userdata, &p); + if (r < 0) + return r; + + return unit_name_unescape(p, ret); +} + static int specifier_filename(char specifier, void *data, void *userdata, char **ret) { Unit *u = userdata; @@ -213,31 +244,33 @@ int unit_full_printf(Unit *u, const char *format, char **ret) { */ const Specifier table[] = { - { 'n', specifier_string, u->id }, - { 'N', specifier_prefix_and_instance, NULL }, - { 'p', specifier_prefix, NULL }, - { 'P', specifier_prefix_unescaped, NULL }, - { 'i', specifier_string, u->instance }, - { 'I', specifier_instance_unescaped, NULL }, + { 'n', specifier_string, u->id }, + { 'N', specifier_prefix_and_instance, NULL }, + { 'p', specifier_prefix, NULL }, + { 'P', specifier_prefix_unescaped, NULL }, + { 'i', specifier_string, u->instance }, + { 'I', specifier_instance_unescaped, NULL }, + { 'j', specifier_last_component, NULL }, + { 'J', specifier_last_component_unescaped, NULL }, - { 'f', specifier_filename, NULL }, - { 'c', specifier_cgroup, NULL }, - { 'r', specifier_cgroup_slice, NULL }, - { 'R', specifier_cgroup_root, NULL }, - { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) }, - { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) }, - { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) }, - { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) }, + { 'f', specifier_filename, NULL }, + { 'c', specifier_cgroup, NULL }, + { 'r', specifier_cgroup_slice, NULL }, + { 'R', specifier_cgroup_root, NULL }, + { 't', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_RUNTIME) }, + { 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) }, + { 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) }, + { 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) }, - { 'U', specifier_user_id, NULL }, - { 'u', specifier_user_name, NULL }, - { 'h', specifier_user_home, NULL }, - { 's', specifier_user_shell, NULL }, + { 'U', specifier_user_id, NULL }, + { 'u', specifier_user_name, NULL }, + { 'h', specifier_user_home, NULL }, + { 's', specifier_user_shell, NULL }, - { 'm', specifier_machine_id, NULL }, - { 'H', specifier_host_name, NULL }, - { 'b', specifier_boot_id, NULL }, - { 'v', specifier_kernel_release, NULL }, + { 'm', specifier_machine_id, NULL }, + { 'H', specifier_host_name, NULL }, + { 'b', specifier_boot_id, NULL }, + { 'v', specifier_kernel_release, NULL }, {} }; diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index c2cbf348e2..599300ceb4 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -88,6 +88,27 @@ static int specifier_instance(char specifier, void *data, void *userdata, char * return 0; } +static int specifier_last_component(char specifier, void *data, void *userdata, char **ret) { + _cleanup_free_ char *prefix = NULL; + char *dash; + int r; + + r = specifier_prefix(specifier, data, userdata, &prefix); + if (r < 0) + return r; + + dash = strrchr(prefix, '-'); + if (dash) { + dash = strdup(dash + 1); + if (!dash) + return -ENOMEM; + *ret = dash; + } else + *ret = TAKE_PTR(prefix); + + return 0; +} + int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) { /* This is similar to unit_full_printf() but does not support @@ -111,6 +132,7 @@ int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) { 'N', specifier_prefix_and_instance, NULL }, { 'p', specifier_prefix, NULL }, { 'i', specifier_instance, NULL }, + { 'j', specifier_last_component, NULL }, { 'U', specifier_user_id, NULL }, { 'u', specifier_user_name, NULL }, diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 6b72fc90fd..3fd4ac9e5d 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -662,6 +662,7 @@ static void test_install_printf(void) { expect(i, "%N", "name"); expect(i, "%p", "name"); expect(i, "%i", ""); + expect(i, "%j", "name"); expect(i, "%u", user); expect(i, "%U", uid); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 347c586663..300a1c5a82 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -198,7 +198,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_(manager_freep) Manager *m = NULL; - Unit *u, *u2; + Unit *u; int r; assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); @@ -245,6 +245,9 @@ static int test_unit_printf(void) { expect(u, "%p", "blah"); expect(u, "%P", "blah"); expect(u, "%i", ""); + expect(u, "%I", ""); + expect(u, "%j", "blah"); + expect(u, "%J", "blah"); expect(u, "%u", user); expect(u, "%U", uid); expect(u, "%h", home); @@ -254,24 +257,41 @@ static int test_unit_printf(void) { expect(u, "%t", "/run/user/*"); /* templated */ - assert_se(u2 = unit_new(m, sizeof(Service))); - assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0); - assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0); + assert_se(u = unit_new(m, sizeof(Service))); + assert_se(unit_add_name(u, "blah@foo-foo.service") == 0); + assert_se(unit_add_name(u, "blah@foo-foo.service") == 0); + + expect(u, "%n", "blah@foo-foo.service"); + expect(u, "%N", "blah@foo-foo"); + expect(u, "%f", "/foo/foo"); + expect(u, "%p", "blah"); + expect(u, "%P", "blah"); + expect(u, "%i", "foo-foo"); + expect(u, "%I", "foo/foo"); + expect(u, "%j", "blah"); + expect(u, "%J", "blah"); + expect(u, "%u", user); + expect(u, "%U", uid); + expect(u, "%h", home); + expect(u, "%m", mid); + expect(u, "%b", bid); + expect(u, "%H", host); + expect(u, "%t", "/run/user/*"); + + /* templated with components */ + assert_se(u = unit_new(m, sizeof(Slice))); + assert_se(unit_add_name(u, "blah-blah\\x2d.slice") == 0); + + expect(u, "%n", "blah-blah\\x2d.slice"); + expect(u, "%N", "blah-blah\\x2d"); + expect(u, "%f", "/blah/blah-"); + expect(u, "%p", "blah-blah\\x2d"); + expect(u, "%P", "blah/blah-"); + expect(u, "%i", ""); + expect(u, "%I", ""); + expect(u, "%j", "blah\\x2d"); + expect(u, "%J", "blah-"); - expect(u2, "%n", "blah@foo-foo.service"); - expect(u2, "%N", "blah@foo-foo"); - expect(u2, "%f", "/foo/foo"); - expect(u2, "%p", "blah"); - expect(u2, "%P", "blah"); - expect(u2, "%i", "foo-foo"); - expect(u2, "%I", "foo/foo"); - expect(u2, "%u", user); - expect(u2, "%U", uid); - expect(u2, "%h", home); - expect(u2, "%m", mid); - expect(u2, "%b", bid); - expect(u2, "%H", host); - expect(u2, "%t", "/run/user/*"); #undef expect return 0;