mirror of
https://github.com/systemd/systemd.git
synced 2025-02-02 13:47:27 +03:00
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:
parent
e1a7f622e7
commit
250e9fadbc
@ -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>
|
||||
|
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user