Merge pull request #4835 from poettering/unit-name-printf

Various specifier resolution fixes.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2016-12-10 01:29:52 -05:00 committed by GitHub
commit 1ac7a93574
8 changed files with 132 additions and 120 deletions

2
TODO
View File

@ -116,8 +116,6 @@ Features:
* journald: sigbus API via a signal-handler safe function that people may call * journald: sigbus API via a signal-handler safe function that people may call
from the SIGBUS handler from the SIGBUS handler
* move specifier expansion from service_spawn() into load-fragment.c
* optionally, also require WATCHDOG=1 notifications during service start-up and shutdown * optionally, also require WATCHDOG=1 notifications during service start-up and shutdown
* resolved: when routing queries, make sure only look for the *longest* suffix... * resolved: when routing queries, make sure only look for the *longest* suffix...

View File

@ -1246,21 +1246,6 @@
<entry>This is either the unescaped instance name (if applicable) with <filename>/</filename> prepended (if applicable), or the unescaped prefix name prepended with <filename>/</filename>.</entry> <entry>This is either the unescaped instance name (if applicable) with <filename>/</filename> prepended (if applicable), or the unescaped prefix name prepended with <filename>/</filename>.</entry>
</row> </row>
<row> <row>
<entry><literal>%c</literal></entry>
<entry>Control group path of the unit</entry>
<entry>This path does not include the <filename>/sys/fs/cgroup/systemd/</filename> prefix.</entry>
</row>
<row>
<entry><literal>%r</literal></entry>
<entry>Control group path of the slice the unit is placed in</entry>
<entry>This usually maps to the parent control group path of <literal>%c</literal>.</entry>
</row>
<row>
<entry><literal>%R</literal></entry>
<entry>Root control group path below which slices and units are placed</entry>
<entry>For system instances, this resolves to <filename>/</filename>, except in containers, where this maps to the container's root control group path.</entry>
</row>
<row>
<entry><literal>%t</literal></entry> <entry><literal>%t</literal></entry>
<entry>Runtime directory</entry> <entry>Runtime directory</entry>
<entry>This is either <filename>/run</filename> (for the system manager) or the path <literal>$XDG_RUNTIME_DIR</literal> resolves to (for user managers).</entry> <entry>This is either <filename>/run</filename> (for the system manager) or the path <literal>$XDG_RUNTIME_DIR</literal> resolves to (for user managers).</entry>
@ -1314,13 +1299,6 @@
</tgroup> </tgroup>
</table> </table>
<para>Please note that specifiers <literal>%U</literal>,
<literal>%h</literal>, <literal>%s</literal> are mostly useless
when systemd is running in system mode. PID 1 cannot query the
user account database for information, so the specifiers only work
as shortcuts for things which are already specified in a different
way in the unit file. They are fully functional when systemd is
running in <option>--user</option> mode.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -191,13 +191,13 @@ Unit.IgnoreOnIsolate, config_parse_bool, 0,
Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0 Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0
Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout) Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout)
Unit.JobTimeoutAction, config_parse_emergency_action, 0, offsetof(Unit, job_timeout_action) Unit.JobTimeoutAction, config_parse_emergency_action, 0, offsetof(Unit, job_timeout_action)
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) Unit.JobTimeoutRebootArgument, config_parse_unit_string_printf, 0, offsetof(Unit, job_timeout_reboot_arg)
Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
m4_dnl The following is a legacy alias name for compatibility m4_dnl The following is a legacy alias name for compatibility
Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Unit.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action) Unit.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action)
Unit.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg) Unit.RebootArgument, config_parse_unit_string_printf, 0, offsetof(Unit, reboot_arg)
Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions) Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions)
Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions) Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions)
Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions) Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions)
@ -254,7 +254,7 @@ m4_dnl The following three only exist for compatibility, they moved into Unit, s
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Service.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action) Service.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action)
Service.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg) Service.RebootArgument, config_parse_unit_path_printf, 0, offsetof(Unit, reboot_arg)
Service.FailureAction, config_parse_emergency_action, 0, offsetof(Service, emergency_action) Service.FailureAction, config_parse_emergency_action, 0, offsetof(Service, emergency_action)
Service.Type, config_parse_service_type, 0, offsetof(Service, type) Service.Type, config_parse_service_type, 0, offsetof(Service, type)
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
@ -272,8 +272,8 @@ Service.FileDescriptorStoreMax, config_parse_unsigned, 0,
Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access)
Service.Sockets, config_parse_service_sockets, 0, 0 Service.Sockets, config_parse_service_sockets, 0, 0
Service.BusPolicy, config_parse_warn_compat, DISABLED_LEGACY, 0 Service.BusPolicy, config_parse_warn_compat, DISABLED_LEGACY, 0
Service.USBFunctionDescriptors, config_parse_path, 0, offsetof(Service, usb_function_descriptors) Service.USBFunctionDescriptors, config_parse_unit_path_printf, 0, offsetof(Service, usb_function_descriptors)
Service.USBFunctionStrings, config_parse_path, 0, offsetof(Service, usb_function_strings) Service.USBFunctionStrings, config_parse_unit_path_printf, 0, offsetof(Service, usb_function_strings)
EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
@ -332,9 +332,9 @@ Socket.Service, config_parse_socket_service, 0,
Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval) Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval)
Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst) Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst)
m4_ifdef(`HAVE_SMACK', m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) `Socket.SmackLabel, config_parse_unit_string_printf, 0, offsetof(Socket, smack)
Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in) Socket.SmackLabelIPIn, config_parse_unit_string_printf, 0, offsetof(Socket, smack_ip_in)
Socket.SmackLabelIPOut, config_parse_string, 0, offsetof(Socket, smack_ip_out)', Socket.SmackLabelIPOut, config_parse_unit_string_printf, 0, offsetof(Socket, smack_ip_out)',
`Socket.SmackLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 `Socket.SmackLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
Socket.SmackLabelIPIn, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 Socket.SmackLabelIPIn, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
Socket.SmackLabelIPOut, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') Socket.SmackLabelIPOut, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
@ -354,9 +354,9 @@ BusName.AllowWorld, config_parse_bus_policy_world, 0,
BusName.SELinuxContext, config_parse_exec_selinux_context, 0, 0 BusName.SELinuxContext, config_parse_exec_selinux_context, 0, 0
BusName.AcceptFileDescriptors, config_parse_bool, 0, offsetof(BusName, accept_fd) BusName.AcceptFileDescriptors, config_parse_bool, 0, offsetof(BusName, accept_fd)
m4_dnl m4_dnl
Mount.What, config_parse_string, 0, offsetof(Mount, parameters_fragment.what) Mount.What, config_parse_unit_string_printf, 0, offsetof(Mount, parameters_fragment.what)
Mount.Where, config_parse_path, 0, offsetof(Mount, where) Mount.Where, config_parse_path, 0, offsetof(Mount, where)
Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options) Mount.Options, config_parse_unit_string_printf, 0, offsetof(Mount, parameters_fragment.options)
Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype)
Mount.TimeoutSec, config_parse_sec, 0, offsetof(Mount, timeout_usec) Mount.TimeoutSec, config_parse_sec, 0, offsetof(Mount, timeout_usec)
Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode)
@ -373,7 +373,7 @@ Automount.TimeoutIdleSec, config_parse_sec, 0,
m4_dnl m4_dnl
Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what)
Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority)
Swap.Options, config_parse_string, 0, offsetof(Swap, parameters_fragment.options) Swap.Options, config_parse_unit_string_printf, 0, offsetof(Swap, parameters_fragment.options)
Swap.TimeoutSec, config_parse_sec, 0, offsetof(Swap, timeout_usec) Swap.TimeoutSec, config_parse_sec, 0, offsetof(Swap, timeout_usec)
EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl

View File

@ -579,6 +579,7 @@ int config_parse_exec(
void *userdata) { void *userdata) {
ExecCommand **e = data; ExecCommand **e = data;
Unit *u = userdata;
const char *p; const char *p;
bool semicolon; bool semicolon;
int r; int r;
@ -604,7 +605,7 @@ int config_parse_exec(
_cleanup_free_ ExecCommand *nce = NULL; _cleanup_free_ ExecCommand *nce = NULL;
_cleanup_strv_free_ char **n = NULL; _cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0; size_t nlen = 0, nbufsize = 0;
char *f; const char *f;
int i; int i;
semicolon = false; semicolon = false;
@ -631,47 +632,47 @@ int config_parse_exec(
f++; f++;
} }
if (isempty(f)) { r = unit_full_printf(u, f, &path);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", f);
return 0;
}
if (isempty(path)) {
/* First word is either "-" or "@" with no command. */ /* First word is either "-" or "@" with no command. */
log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue); log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
return 0; return 0;
} }
if (!string_is_safe(f)) { if (!string_is_safe(path)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue); log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
return 0; return 0;
} }
if (!path_is_absolute(f)) { if (!path_is_absolute(path)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue); log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
return 0; return 0;
} }
if (endswith(f, "/")) { if (endswith(path, "/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue); log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
return 0; return 0;
} }
if (f == firstword) {
path = firstword;
firstword = NULL;
} else {
path = strdup(f);
if (!path)
return log_oom();
}
if (!separate_argv0) { if (!separate_argv0) {
char *w = NULL;
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom(); return log_oom();
f = strdup(path);
if (!f) w = strdup(path);
if (!w)
return log_oom(); return log_oom();
n[nlen++] = f; n[nlen++] = w;
n[nlen] = NULL; n[nlen] = NULL;
} }
path_kill_slashes(path); path_kill_slashes(path);
while (!isempty(p)) { while (!isempty(p)) {
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL, *resolved = NULL;
/* Check explicitly for an unquoted semicolon as /* Check explicitly for an unquoted semicolon as
* command separator token. */ * command separator token. */
@ -682,18 +683,21 @@ int config_parse_exec(
break; break;
} }
/* Check for \; explicitly, to not confuse it with \\; /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
* or "\;" or "\\;" etc. extract_first_word would * extract_first_word() would return the same for all of those. */
* return the same for all of those. */
if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) { if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
char *w;
p += 2; p += 2;
p += strspn(p, WHITESPACE); p += strspn(p, WHITESPACE);
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom(); return log_oom();
f = strdup(";");
if (!f) w = strdup(";");
if (!w)
return log_oom(); return log_oom();
n[nlen++] = f; n[nlen++] = w;
n[nlen] = NULL; n[nlen] = NULL;
continue; continue;
} }
@ -701,14 +705,20 @@ int config_parse_exec(
r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue); r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
if (r == 0) if (r == 0)
break; break;
else if (r < 0) if (r < 0)
return 0; return 0;
r = unit_full_printf(u, word, &resolved);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to resolve unit specifiers on %s, ignoring: %m", word);
return 0;
}
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom(); return log_oom();
n[nlen++] = word; n[nlen++] = resolved;
n[nlen] = NULL; n[nlen] = NULL;
word = NULL; resolved = NULL;
} }
if (!n || !n[0]) { if (!n || !n[0]) {
@ -1326,7 +1336,7 @@ int config_parse_exec_selinux_context(
} else } else
ignore = false; ignore = false;
r = unit_name_printf(u, rvalue, &k); r = unit_full_printf(u, rvalue, &k);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0; return 0;
@ -1374,7 +1384,7 @@ int config_parse_exec_apparmor_profile(
} else } else
ignore = false; ignore = false;
r = unit_name_printf(u, rvalue, &k); r = unit_full_printf(u, rvalue, &k);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0; return 0;
@ -1422,7 +1432,7 @@ int config_parse_exec_smack_process_label(
} else } else
ignore = false; ignore = false;
r = unit_name_printf(u, rvalue, &k); r = unit_full_printf(u, rvalue, &k);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0; return 0;
@ -1689,7 +1699,7 @@ int config_parse_fdname(
return 0; return 0;
} }
r = unit_name_printf(UNIT(s), rvalue, &p); r = unit_full_printf(UNIT(s), rvalue, &p);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0; return 0;
@ -2555,7 +2565,7 @@ int config_parse_unit_requires_mounts_for(
assert(data); assert(data);
for (p = rvalue;; ) { for (p = rvalue;; ) {
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL, *resolved = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
if (r == 0) if (r == 0)
@ -2573,9 +2583,15 @@ int config_parse_unit_requires_mounts_for(
continue; continue;
} }
r = unit_require_mounts_for(u, word); r = unit_full_printf(u, word, &resolved);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", word); log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit name \"%s\", ignoring: %m", word);
continue;
}
r = unit_require_mounts_for(u, resolved);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", resolved);
continue; continue;
} }
} }
@ -3710,7 +3726,7 @@ int config_parse_runtime_directory(
return 0; return 0;
} }
r = unit_name_printf(u, word, &k); r = unit_full_printf(u, word, &k);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to resolve specifiers in \"%s\", ignoring: %m", word); "Failed to resolve specifiers in \"%s\", ignoring: %m", word);
@ -3812,8 +3828,8 @@ int config_parse_namespace_path_strv(
void *data, void *data,
void *userdata) { void *userdata) {
Unit *u = userdata;
char*** sv = data; char*** sv = data;
const char *prev;
const char *cur; const char *cur;
int r; int r;
@ -3828,10 +3844,10 @@ int config_parse_namespace_path_strv(
return 0; return 0;
} }
prev = cur = rvalue; cur = rvalue;
for (;;) { for (;;) {
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
int offset; bool ignore_enoent;
r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES); r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
if (r == 0) if (r == 0)
@ -3839,31 +3855,37 @@ int config_parse_namespace_path_strv(
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom(); return log_oom();
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev); log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
return 0; return 0;
} }
if (!utf8_is_valid(word)) { if (!utf8_is_valid(word)) {
log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word); log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
prev = cur;
continue; continue;
} }
offset = word[0] == '-'; ignore_enoent = word[0] == '-';
if (!path_is_absolute(word + offset)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word); r = unit_full_printf(u, word + ignore_enoent, &resolved);
prev = cur; if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s: %m", word);
continue; continue;
} }
path_kill_slashes(word + offset); if (!path_is_absolute(resolved)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
continue;
}
r = strv_push(sv, word); path_kill_slashes(resolved);
joined = strjoin(ignore_enoent ? "-" : "", resolved);
r = strv_push(sv, joined);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
prev = cur; joined = NULL;
word = NULL;
} }
return 0; return 0;

View File

@ -49,7 +49,6 @@
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "unit-name.h" #include "unit-name.h"
#include "unit-printf.h"
#include "unit.h" #include "unit.h"
#include "utf8.h" #include "utf8.h"
#include "util.h" #include "util.h"
@ -1205,7 +1204,7 @@ static int service_spawn(
ExecFlags flags, ExecFlags flags,
pid_t *_pid) { pid_t *_pid) {
_cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL; _cleanup_strv_free_ char **final_env = NULL, **our_env = NULL, **fd_names = NULL;
_cleanup_free_ int *fds = NULL; _cleanup_free_ int *fds = NULL;
unsigned n_fds = 0, n_env = 0; unsigned n_fds = 0, n_env = 0;
const char *path; const char *path;
@ -1263,10 +1262,6 @@ static int service_spawn(
if (r < 0) if (r < 0)
return r; return r;
r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
if (r < 0)
return r;
our_env = new0(char*, 9); our_env = new0(char*, 9);
if (!our_env) if (!our_env)
return -ENOMEM; return -ENOMEM;
@ -1349,7 +1344,7 @@ static int service_spawn(
} else } else
path = UNIT(s)->cgroup_path; path = UNIT(s)->cgroup_path;
exec_params.argv = argv; exec_params.argv = c->argv;
exec_params.environment = final_env; exec_params.environment = final_env;
exec_params.fds = fds; exec_params.fds = fds;
exec_params.fd_names = fd_names; exec_params.fd_names = fd_names;

View File

@ -54,7 +54,6 @@
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "unit-name.h" #include "unit-name.h"
#include "unit-printf.h"
#include "unit.h" #include "unit.h"
#include "user-util.h" #include "user-util.h"
#include "in-addr-util.h" #include "in-addr-util.h"
@ -1740,7 +1739,6 @@ static int socket_coldplug(Unit *u) {
} }
static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
_cleanup_free_ char **argv = NULL;
pid_t pid; pid_t pid;
int r; int r;
ExecParameters exec_params = { ExecParameters exec_params = {
@ -1772,11 +1770,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
if (r < 0) if (r < 0)
return r; return r;
r = unit_full_printf_strv(UNIT(s), c->argv, &argv); exec_params.argv = c->argv;
if (r < 0)
return r;
exec_params.argv = argv;
exec_params.environment = UNIT(s)->manager->environment; exec_params.environment = UNIT(s)->manager->environment;
exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager); exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;

View File

@ -78,12 +78,18 @@ static int specifier_filename(char specifier, void *data, void *userdata, char *
return unit_name_to_path(u->id, ret); return unit_name_to_path(u->id, ret);
} }
static void bad_specifier(Unit *u, char specifier) {
log_unit_warning(u, "Specifier '%%%c' used in unit configuration, which is deprecated. Please update your unit file, as it does not work as intended.", specifier);
}
static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) { static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata; Unit *u = userdata;
char *n; char *n;
assert(u); assert(u);
bad_specifier(u, specifier);
if (u->cgroup_path) if (u->cgroup_path)
n = strdup(u->cgroup_path); n = strdup(u->cgroup_path);
else else
@ -101,6 +107,8 @@ static int specifier_cgroup_root(char specifier, void *data, void *userdata, cha
assert(u); assert(u);
bad_specifier(u, specifier);
n = strdup(u->manager->cgroup_root); n = strdup(u->manager->cgroup_root);
if (!n) if (!n)
return -ENOMEM; return -ENOMEM;
@ -115,6 +123,8 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch
assert(u); assert(u);
bad_specifier(u, specifier);
if (UNIT_ISSET(u->slice)) { if (UNIT_ISSET(u->slice)) {
Unit *slice; Unit *slice;
@ -194,13 +204,20 @@ static int specifier_user_shell(char specifier, void *data, void *userdata, char
int unit_name_printf(Unit *u, const char* format, char **ret) { int unit_name_printf(Unit *u, const char* format, char **ret) {
/* /*
* This will use the passed string as format string and * This will use the passed string as format string and replace the following specifiers (which should all be
* replace the following specifiers: * safe for inclusion in unit names):
* *
* %n: the full id of the unit (foo@bar.waldo) * %n: the full id of the unit (foo@bar.waldo)
* %N: the id of the unit without the suffix (foo@bar) * %N: the id of the unit without the suffix (foo@bar)
* %p: the prefix (foo) * %p: the prefix (foo)
* %i: the instance (bar) * %i: the instance (bar)
*
* %U: the UID of the running user
* %u: the username of the running user
*
* %m: the machine ID of the running system
* %H: the host name of the running system
* %b: the boot ID of the running system
*/ */
const Specifier table[] = { const Specifier table[] = {
@ -208,7 +225,14 @@ int unit_name_printf(Unit *u, const char* format, char **ret) {
{ 'N', specifier_prefix_and_instance, NULL }, { 'N', specifier_prefix_and_instance, NULL },
{ 'p', specifier_prefix, NULL }, { 'p', specifier_prefix, NULL },
{ 'i', specifier_string, u->instance }, { 'i', specifier_string, u->instance },
{ 0, NULL, NULL }
{ 'U', specifier_user_id, NULL },
{ 'u', specifier_user_name, NULL },
{ 'm', specifier_machine_id, NULL },
{ 'H', specifier_host_name, NULL },
{ 'b', specifier_boot_id, NULL },
{}
}; };
assert(u); assert(u);
@ -220,22 +244,23 @@ int unit_name_printf(Unit *u, const char* format, char **ret) {
int unit_full_printf(Unit *u, const char *format, char **ret) { int unit_full_printf(Unit *u, const char *format, char **ret) {
/* This is similar to unit_name_printf() but also supports /* This is similar to unit_name_printf() but also supports unescaping. Also, adds a couple of additional codes
* unescaping. Also, adds a couple of additional codes: * (which are likely not suitable for unescaped inclusion in unit names):
* *
* %f the instance if set, otherwise the id * %f: the unescaped instance if set, otherwise the id unescaped as path
* %c cgroup path of unit * %c: cgroup path of unit (deprecated)
* %r where units in this slice are placed in the cgroup tree * %r: where units in this slice are placed in the cgroup tree (deprecated)
* %R the root of this systemd's instance tree * %R: the root of this systemd's instance tree (deprecated)
* %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) * %t: the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
* %U the UID of the running user *
* %u the username of the running user * %h: the homedir of the running user
* %h the homedir of the running user * %s: the shell of the running user
* %s the shell of the running user *
* %m the machine ID of the running system * %v: `uname -r` of the running system
* %H the host name of the running system *
* %b the boot ID of the running system * NOTICE: When you add new entries here, please be careful: specifiers which depend on settings of the unit
* %v `uname -r` of the running system * file itself are broken by design, as they would resolve differently depending on whether they are used
* before or after the relevant configuration setting. Hence: don't add them.
*/ */
const Specifier table[] = { const Specifier table[] = {

View File

@ -409,8 +409,8 @@ static void test_exec_spec_interpolation(Manager *m) {
test(m, "exec-spec-interpolation.service", 0, CLD_EXITED); test(m, "exec-spec-interpolation.service", 0, CLD_EXITED);
} }
static int run_tests(UnitFileScope scope, test_function_t *tests) { static int run_tests(UnitFileScope scope, const test_function_t *tests) {
test_function_t *test = NULL; const test_function_t *test = NULL;
Manager *m = NULL; Manager *m = NULL;
int r; int r;
@ -433,7 +433,7 @@ static int run_tests(UnitFileScope scope, test_function_t *tests) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
test_function_t user_tests[] = { static const test_function_t user_tests[] = {
test_exec_workingdirectory, test_exec_workingdirectory,
test_exec_personality, test_exec_personality,
test_exec_ignoresigpipe, test_exec_ignoresigpipe,
@ -464,7 +464,7 @@ int main(int argc, char *argv[]) {
test_exec_spec_interpolation, test_exec_spec_interpolation,
NULL, NULL,
}; };
test_function_t system_tests[] = { static const test_function_t system_tests[] = {
test_exec_systemcall_system_mode_with_user, test_exec_systemcall_system_mode_with_user,
NULL, NULL,
}; };