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.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-04-23 22:43:20 +02:00
parent e1a7f622e7
commit 250e9fadbc
5 changed files with 127 additions and 41 deletions

View File

@ -1508,7 +1508,7 @@
</variablelist>
<para>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.
</para>
</refsect1>
@ -1566,6 +1566,16 @@
<entry>Unescaped instance name</entry>
<entry>Same as <literal>%i</literal>, but with escaping undone.</entry>
</row>
<row>
<entry><literal>%j</literal></entry>
<entry>Final component of the prefix</entry>
<entry>This is the string between the last <literal>-</literal> and the end of the prefix name. If there is no <literal>-</literal>, this is the same as <literal>%p</literal>.</entry>
</row>
<row>
<entry><literal>%J</literal></entry>
<entry>Unescaped final component of the prefix</entry>
<entry>Same as <literal>%j</literal>, but with escaping undone.</entry>
</row>
<row>
<entry><literal>%f</literal></entry>
<entry>Unescaped filename</entry>

View File

@ -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 },
{}
};

View File

@ -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 },

View File

@ -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);

View File

@ -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;