2017-11-18 17:09:20 +01:00
/* SPDX-License-Identifier: LGPL-2.1+ */
2010-02-03 13:03:47 +01:00
/***
2018-06-12 19:00:24 +02:00
Copyright © 2012 Holger Hans Peter Freyther
2010-02-03 13:03:47 +01:00
* * */
2009-11-19 23:13:20 +01:00
# include <errno.h>
2010-01-26 21:39:06 +01:00
# include <fcntl.h>
2010-04-24 05:05:01 +02:00
# include <linux/fs.h>
2015-09-23 19:46:23 +02:00
# include <linux/oom.h>
2017-10-03 10:41:51 +02:00
# if HAVE_SECCOMP
2015-09-30 21:50:22 +02:00
# include <seccomp.h>
# endif
2015-09-23 19:46:23 +02:00
# include <sched.h>
2011-04-04 18:15:13 +02:00
# include <sys/resource.h>
2009-11-19 23:13:20 +01:00
2015-09-23 19:46:23 +02:00
# include "af-list.h"
2015-11-16 22:09:36 +01:00
# include "alloc-util.h"
2018-05-15 20:17:34 +02:00
# include "all-units.h"
2019-04-23 12:14:20 +02:00
# include "bpf-firewall.h"
2015-09-23 19:46:23 +02:00
# include "bus-error.h"
# include "bus-internal.h"
# include "bus-util.h"
# include "cap-list.h"
2016-01-07 23:00:04 +01:00
# include "capability-util.h"
2019-08-01 13:14:45 +02:00
# include "cgroup-setup.h"
2009-11-19 23:13:20 +01:00
# include "conf-parser.h"
2015-09-30 21:50:22 +02:00
# include "cpu-set-util.h"
2015-09-23 19:46:23 +02:00
# include "env-util.h"
# include "errno-list.h"
2015-10-23 18:52:53 +02:00
# include "escape.h"
2015-10-25 13:14:12 +01:00
# include "fd-util.h"
2015-10-26 21:16:26 +01:00
# include "fs-util.h"
2017-10-27 11:33:05 +02:00
# include "hexdecoct.h"
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
# include "io-util.h"
2010-01-29 20:46:22 +01:00
# include "ioprio.h"
2018-11-29 15:58:43 +01:00
# include "ip-protocol-list.h"
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
# include "journal-util.h"
2019-03-13 11:35:47 +01:00
# include "limits-util.h"
2015-10-25 13:14:12 +01:00
# include "load-fragment.h"
2015-09-23 19:46:23 +02:00
# include "log.h"
2018-11-29 10:24:39 +01:00
# include "mountpoint-util.h"
2019-03-14 13:14:33 +01:00
# include "nulstr-util.h"
2015-10-26 16:18:16 +01:00
# include "parse-util.h"
2012-05-07 21:36:12 +02:00
# include "path-util.h"
2015-10-27 14:24:58 +01:00
# include "process-util.h"
2017-10-03 10:41:51 +02:00
# if HAVE_SECCOMP
2014-02-13 00:24:00 +01:00
# include "seccomp-util.h"
# endif
2017-08-07 16:40:25 +02:00
# include "securebits-util.h"
2015-09-23 19:46:23 +02:00
# include "signal-util.h"
2020-01-10 17:22:37 +01:00
# include "socket-netlink.h"
2015-10-26 22:01:44 +01:00
# include "stat-util.h"
2015-10-24 22:58:24 +02:00
# include "string-util.h"
2015-09-23 19:46:23 +02:00
# include "strv.h"
2019-11-25 16:22:45 +01:00
# include "syslog-util.h"
# include "time-util.h"
2015-09-23 19:46:23 +02:00
# include "unit-name.h"
# include "unit-printf.h"
2016-07-14 12:28:06 +02:00
# include "user-util.h"
2015-10-27 00:41:29 +01:00
# include "web-util.h"
2014-02-13 00:24:00 +01:00
2018-11-30 04:57:03 +01:00
static int parse_socket_protocol ( const char * s ) {
2018-05-31 04:04:52 +02:00
int r ;
2018-11-30 04:57:03 +01:00
r = parse_ip_protocol ( s ) ;
2018-05-31 04:04:52 +02:00
if ( r < 0 )
2018-11-28 09:54:04 +01:00
return r ;
2018-05-31 04:04:52 +02:00
if ( ! IN_SET ( r , IPPROTO_UDPLITE , IPPROTO_SCTP ) )
return - EPROTONOSUPPORT ;
return r ;
}
2019-06-20 18:51:42 +02:00
int parse_crash_chvt ( const char * value , int * data ) {
int b ;
if ( safe_atoi ( value , data ) > = 0 )
return 0 ;
b = parse_boolean ( value ) ;
if ( b < 0 )
return b ;
if ( b > 0 )
* data = 0 ; /* switch to where kmsg goes */
else
* data = - 1 ; /* turn off switching */
return 0 ;
}
int parse_confirm_spawn ( const char * value , char * * console ) {
char * s ;
int r ;
r = value ? parse_boolean ( value ) : 1 ;
if ( r = = 0 ) {
* console = NULL ;
return 0 ;
2019-08-20 17:32:34 +02:00
} else if ( r > 0 ) /* on with default tty */
2019-06-20 18:51:42 +02:00
s = strdup ( " /dev/console " ) ;
else if ( is_path ( value ) ) /* on with fully qualified path */
s = strdup ( value ) ;
else /* on with only a tty file name, not a fully qualified path */
2019-08-20 17:32:34 +02:00
s = path_join ( " /dev/ " , value ) ;
2019-06-20 18:51:42 +02:00
if ( ! s )
return - ENOMEM ;
* console = s ;
return 0 ;
}
2018-11-30 04:57:03 +01:00
DEFINE_CONFIG_PARSE ( config_parse_socket_protocol , parse_socket_protocol , " Failed to parse socket protocol " ) ;
2018-05-31 04:04:52 +02:00
DEFINE_CONFIG_PARSE ( config_parse_exec_secure_bits , secure_bits_from_string , " Failed to parse secure bits " ) ;
2017-11-13 17:14:07 +01:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_collect_mode , collect_mode , CollectMode , " Failed to parse garbage collection mode " ) ;
2018-05-31 04:04:52 +02:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_device_policy , cgroup_device_policy , CGroupDevicePolicy , " Failed to parse device policy " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_exec_keyring_mode , exec_keyring_mode , ExecKeyringMode , " Failed to parse keyring mode " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_exec_utmp_mode , exec_utmp_mode , ExecUtmpMode , " Failed to parse utmp mode " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_job_mode , job_mode , JobMode , " Failed to parse job mode " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_notify_access , notify_access , NotifyAccess , " Failed to parse notify access specifier " ) ;
2018-06-15 05:29:29 +02:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_protect_home , protect_home , ProtectHome , " Failed to parse protect home value " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_protect_system , protect_system , ProtectSystem , " Failed to parse protect system value " ) ;
2018-05-31 04:04:52 +02:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_runtime_preserve_mode , exec_preserve_mode , ExecPreserveMode , " Failed to parse runtime directory preserve mode " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_service_type , service_type , ServiceType , " Failed to parse service type " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_service_restart , service_restart , ServiceRestart , " Failed to parse service restart specifier " ) ;
2019-04-16 16:45:20 +02:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_service_timeout_failure_mode , service_timeout_failure_mode , ServiceTimeoutFailureMode , " Failed to parse timeout failure mode " ) ;
2018-05-31 04:04:52 +02:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_socket_bind , socket_address_bind_ipv6_only_or_bool , SocketAddressBindIPv6Only , " Failed to parse bind IPv6 only value " ) ;
2019-03-19 19:05:19 +01:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_oom_policy , oom_policy , OOMPolicy , " Failed to parse OOM policy " ) ;
2018-05-31 04:04:52 +02:00
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT ( config_parse_ip_tos , ip_tos , int , - 1 , " Failed to parse IP TOS value " ) ;
DEFINE_CONFIG_PARSE_PTR ( config_parse_blockio_weight , cg_blkio_weight_parse , uint64_t , " Invalid block IO weight " ) ;
DEFINE_CONFIG_PARSE_PTR ( config_parse_cg_weight , cg_weight_parse , uint64_t , " Invalid weight " ) ;
DEFINE_CONFIG_PARSE_PTR ( config_parse_cpu_shares , cg_cpu_shares_parse , uint64_t , " Invalid CPU shares " ) ;
DEFINE_CONFIG_PARSE_PTR ( config_parse_exec_mount_flags , mount_propagation_flags_from_string , unsigned long , " Failed to parse mount flag " ) ;
2019-03-12 18:58:26 +01:00
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT ( config_parse_numa_policy , mpol , int , - 1 , " Invalid NUMA policy type " ) ;
2019-09-16 02:09:35 +02:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_status_unit_format , status_unit_format , StatusUnitFormat , " Failed to parse status unit format " ) ;
2017-11-13 17:14:07 +01:00
2015-11-12 19:21:47 +01:00
int config_parse_unit_deps (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2009-11-19 23:13:20 +01:00
2011-08-01 00:43:05 +02:00
UnitDependency d = ltype ;
2010-01-26 21:39:06 +01:00
Unit * u = userdata ;
2015-11-05 06:26:13 +01:00
const char * p ;
2009-11-19 23:13:20 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2015-11-05 06:26:13 +01:00
p = rvalue ;
2016-02-23 18:52:52 +01:00
for ( ; ; ) {
2015-11-05 06:26:13 +01:00
_cleanup_free_ char * word = NULL , * k = NULL ;
2009-11-19 23:13:20 +01:00
int r ;
2015-11-11 22:53:05 +01:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_RETAIN_ESCAPE ) ;
2015-11-05 06:26:13 +01:00
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
2013-01-17 02:27:06 +01:00
return log_oom ( ) ;
2015-11-05 06:26:13 +01:00
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid syntax, ignoring: %s " , rvalue ) ;
break ;
}
2009-11-19 23:13:20 +01:00
2015-11-05 06:26:13 +01:00
r = unit_name_printf ( u , word , & k ) ;
2013-09-17 17:03:46 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , word ) ;
2013-09-17 17:03:46 +02:00
continue ;
}
2010-04-15 03:11:11 +02:00
2018-09-15 19:57:52 +02:00
r = unit_add_dependency_by_name ( u , d , k , true , UNIT_DEPENDENCY_FILE ) ;
2012-01-06 23:08:54 +01:00
if ( r < 0 )
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to add dependency on %s, ignoring: %m " , k ) ;
2009-11-19 23:13:20 +01:00
}
return 0 ;
}
2015-11-12 19:21:47 +01:00
int config_parse_obsolete_unit_deps (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file " , lvalue , unit_dependency_to_string ( ltype ) ) ;
return config_parse_unit_deps ( unit , filename , line , section , section_line , lvalue , ltype , rvalue , data , userdata ) ;
}
2015-01-07 22:07:09 +01:00
int config_parse_unit_string_printf (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-04-24 03:11:01 +02:00
2013-01-17 02:27:06 +01:00
_cleanup_free_ char * k = NULL ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2013-09-17 17:03:46 +02:00
int r ;
2010-04-24 03:11:01 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2010-06-18 23:25:19 +02:00
assert ( u ) ;
2010-04-24 03:11:01 +02:00
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( u , rvalue , & k ) ;
2015-01-07 22:07:09 +01:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2015-01-07 22:07:09 +01:00
return 0 ;
}
2010-04-24 03:11:01 +02:00
2015-01-07 22:07:09 +01:00
return config_parse_string ( unit , filename , line , section , section_line , lvalue , ltype , k , data , userdata ) ;
2010-04-24 03:11:01 +02:00
}
2015-09-30 18:22:42 +02:00
int config_parse_unit_strv_printf (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2011-07-01 01:13:47 +02:00
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2013-01-17 02:27:06 +01:00
_cleanup_free_ char * k = NULL ;
2013-09-17 17:03:46 +02:00
int r ;
2011-07-01 01:13:47 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( u , rvalue , & k ) ;
2015-09-30 18:22:42 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
}
2011-07-01 01:13:47 +02:00
2015-09-30 18:22:42 +02:00
return config_parse_strv ( unit , filename , line , section , section_line , lvalue , ltype , k , data , userdata ) ;
2011-07-01 01:13:47 +02:00
}
2015-09-23 19:46:23 +02:00
int config_parse_unit_path_printf (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2011-05-18 01:07:31 +02:00
2013-01-17 02:27:06 +01:00
_cleanup_free_ char * k = NULL ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2013-09-17 17:03:46 +02:00
int r ;
2017-07-06 19:54:42 +02:00
bool fatal = ltype ;
2011-05-18 01:07:31 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
core/load-fragment: reject overly long paths early
No need to go through the specifier_printf() if the path is already too long in
the unexpanded form (since specifiers increase the length of the string in all
practical cases).
In the oss-fuzz test case, valgrind reports:
total heap usage: 179,044 allocs, 179,044 frees, 72,687,755,703 bytes allocated
and the original config file is ~500kb. This isn't really a security issue,
since the config file has to be trusted any way, but just a matter of
preventing accidental resource exhaustion.
https://oss-fuzz.com/v2/issue/4651449704251392/6977
While at it, fix order of arguments in the neighbouring log_syntax() call.
2018-03-19 15:43:35 +01:00
/* Let's not bother with anything that is too long */
if ( strlen ( rvalue ) > = PATH_MAX ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" %s value too long%s. " ,
lvalue , fatal ? " " : " , ignoring " ) ;
return fatal ? - ENAMETOOLONG : 0 ;
}
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( u , rvalue , & k ) ;
2014-06-04 16:19:00 +02:00
if ( r < 0 ) {
2017-07-06 19:54:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in '%s'%s: %m " ,
core/load-fragment: reject overly long paths early
No need to go through the specifier_printf() if the path is already too long in
the unexpanded form (since specifiers increase the length of the string in all
practical cases).
In the oss-fuzz test case, valgrind reports:
total heap usage: 179,044 allocs, 179,044 frees, 72,687,755,703 bytes allocated
and the original config file is ~500kb. This isn't really a security issue,
since the config file has to be trusted any way, but just a matter of
preventing accidental resource exhaustion.
https://oss-fuzz.com/v2/issue/4651449704251392/6977
While at it, fix order of arguments in the neighbouring log_syntax() call.
2018-03-19 15:43:35 +01:00
rvalue , fatal ? " " : " , ignoring " ) ;
2017-07-06 19:54:42 +02:00
return fatal ? - ENOEXEC : 0 ;
2014-06-04 16:19:00 +02:00
}
2011-05-18 01:07:31 +02:00
2014-06-04 16:19:00 +02:00
return config_parse_path ( unit , filename , line , section , section_line , lvalue , ltype , k , data , userdata ) ;
}
int config_parse_unit_path_strv_printf (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2014-07-30 04:01:36 +02:00
char * * * x = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2014-06-04 16:19:00 +02:00
int r ;
2016-10-28 02:15:22 +02:00
const char * p ;
2014-06-04 16:19:00 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
2017-09-05 08:08:59 +02:00
if ( isempty ( rvalue ) ) {
2017-10-04 08:21:12 +02:00
* x = strv_free ( * x ) ;
2017-09-05 08:08:59 +02:00
return 0 ;
}
2016-10-28 02:15:22 +02:00
for ( p = rvalue ; ; ) {
_cleanup_free_ char * word = NULL , * k = NULL ;
2014-06-04 16:19:00 +02:00
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2016-10-28 02:15:22 +02:00
if ( r = = 0 )
return 0 ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
2014-06-04 16:19:00 +02:00
2016-10-28 02:15:22 +02:00
r = unit_full_printf ( u , word , & k ) ;
2014-06-04 16:19:00 +02:00
if ( r < 0 ) {
2016-10-28 02:15:22 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in '%s', ignoring: %m " , word ) ;
2014-06-04 16:19:00 +02:00
return 0 ;
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( k , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
2014-06-04 16:19:00 +02:00
return 0 ;
2019-03-28 16:46:27 +01:00
r = strv_consume ( x , TAKE_PTR ( k ) ) ;
2014-06-04 16:19:00 +02:00
if ( r < 0 )
return log_oom ( ) ;
}
2011-05-18 01:07:31 +02:00
}
2019-03-28 16:59:57 +01:00
static int patch_var_run (
const char * unit ,
const char * filename ,
unsigned line ,
const char * lvalue ,
char * * path ) {
const char * e ;
char * z ;
e = path_startswith ( * path , " /var/run/ " ) ;
if ( ! e )
return 0 ;
z = path_join ( " /run/ " , e ) ;
if ( ! z )
return log_oom ( ) ;
log_syntax ( unit , LOG_NOTICE , filename , line , 0 ,
" %s= references a path below legacy directory /var/run/, updating %s → %s; "
" please update the unit file accordingly. " , lvalue , * path , z ) ;
free_and_replace ( * path , z ) ;
return 1 ;
}
int config_parse_socket_listen (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-19 02:56:37 +01:00
2014-10-11 17:37:37 +02:00
_cleanup_free_ SocketPort * p = NULL ;
SocketPort * tail ;
2010-01-23 03:35:54 +01:00
Socket * s ;
2013-09-17 17:03:46 +02:00
int r ;
2010-01-20 19:19:53 +01:00
2010-01-19 02:56:37 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2012-01-15 12:37:16 +01:00
s = SOCKET ( data ) ;
2010-01-23 03:35:54 +01:00
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* An empty assignment removes all ports */
socket_free_ports ( s ) ;
return 0 ;
}
2012-03-12 22:22:16 +01:00
p = new0 ( SocketPort , 1 ) ;
if ( ! p )
2013-01-17 02:27:06 +01:00
return log_oom ( ) ;
2011-05-17 19:37:03 +02:00
2013-01-17 02:27:06 +01:00
if ( ltype ! = SOCKET_SOCKET ) {
2018-06-03 16:59:02 +02:00
_cleanup_free_ char * k = NULL ;
2011-05-17 19:37:03 +02:00
2018-06-03 16:59:02 +02:00
r = unit_full_printf ( UNIT ( s ) , rvalue , & k ) ;
2013-09-17 17:03:46 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
2011-05-17 19:37:03 +02:00
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( k , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
2019-03-28 16:59:57 +01:00
if ( ltype = = SOCKET_FIFO ) {
r = patch_var_run ( unit , filename , line , lvalue , & k ) ;
if ( r < 0 )
return r ;
}
2018-06-03 16:59:02 +02:00
free_and_replace ( p - > path , k ) ;
p - > type = ltype ;
2011-05-17 19:37:03 +02:00
2011-04-10 03:27:00 +02:00
} else if ( streq ( lvalue , " ListenNetlink " ) ) {
2013-01-17 02:27:06 +01:00
_cleanup_free_ char * k = NULL ;
2011-07-01 00:55:34 +02:00
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( UNIT ( s ) , rvalue , & k ) ;
2015-09-30 18:22:42 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
}
2011-04-10 03:27:00 +02:00
2015-09-30 18:22:42 +02:00
r = socket_address_parse_netlink ( & p - > address , k ) ;
2011-07-01 00:55:34 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse address value in '%s', ignoring: %m " , k ) ;
2011-04-10 03:27:00 +02:00
return 0 ;
}
2018-06-03 16:59:02 +02:00
p - > type = SOCKET_SOCKET ;
2010-01-23 03:35:54 +01:00
} else {
2013-01-17 02:27:06 +01:00
_cleanup_free_ char * k = NULL ;
2011-07-01 00:55:34 +02:00
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( UNIT ( s ) , rvalue , & k ) ;
2015-09-30 18:22:42 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
}
2010-01-23 03:35:54 +01:00
2019-03-28 16:59:57 +01:00
if ( k [ 0 ] = = ' / ' ) { /* Only for AF_UNIX file system sockets… */
r = patch_var_run ( unit , filename , line , lvalue , & k ) ;
if ( r < 0 )
return r ;
}
2015-09-30 18:22:42 +02:00
r = socket_address_parse_and_warn ( & p - > address , k ) ;
2011-07-01 00:55:34 +02:00
if ( r < 0 ) {
2017-04-25 09:31:52 +02:00
if ( r ! = - EAFNOSUPPORT )
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse address value in '%s', ignoring: %m " , k ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-01-23 03:35:54 +01:00
}
if ( streq ( lvalue , " ListenStream " ) )
p - > address . type = SOCK_STREAM ;
else if ( streq ( lvalue , " ListenDatagram " ) )
p - > address . type = SOCK_DGRAM ;
else {
assert ( streq ( lvalue , " ListenSequentialPacket " ) ) ;
p - > address . type = SOCK_SEQPACKET ;
}
if ( socket_address_family ( & p - > address ) ! = AF_LOCAL & & p - > address . type = = SOCK_SEQPACKET ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Address family not supported, ignoring: %s " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-01-23 03:35:54 +01:00
}
2018-06-03 16:59:02 +02:00
p - > type = SOCKET_SOCKET ;
2010-01-20 19:19:53 +01:00
}
2010-01-23 03:35:54 +01:00
p - > fd = - 1 ;
2015-09-21 16:30:41 +02:00
p - > auxiliary_fds = NULL ;
p - > n_auxiliary_fds = 0 ;
2013-11-21 00:06:11 +01:00
p - > socket = s ;
2011-04-16 03:42:18 +02:00
2017-12-23 11:16:49 +01:00
LIST_FIND_TAIL ( port , s - > ports , tail ) ;
LIST_INSERT_AFTER ( port , s - > ports , tail , p ) ;
2014-10-11 17:37:37 +02:00
p = NULL ;
2010-01-23 03:35:54 +01:00
2010-01-20 19:19:53 +01:00
return 0 ;
2010-01-19 02:56:37 +01:00
}
2016-08-05 11:17:08 +02:00
int config_parse_exec_nice (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-26 04:18:44 +01:00
2010-01-28 02:53:56 +01:00
ExecContext * c = data ;
2013-04-16 04:25:58 +02:00
int priority , r ;
2010-01-26 04:18:44 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2018-05-25 03:52:47 +02:00
if ( isempty ( rvalue ) ) {
c - > nice_set = false ;
return 0 ;
}
2016-08-05 11:17:08 +02:00
r = parse_nice ( rvalue , & priority ) ;
2013-04-16 04:25:58 +02:00
if ( r < 0 ) {
2016-08-05 11:17:08 +02:00
if ( r = = - ERANGE )
log_syntax ( unit , LOG_ERR , filename , line , r , " Nice priority out of range, ignoring: %s " , rvalue ) ;
else
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse nice priority '%s', ignoring: %m " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-01-26 04:18:44 +01:00
}
2010-01-28 02:53:56 +01:00
c - > nice = priority ;
2011-02-02 14:57:52 +01:00
c - > nice_set = true ;
2010-01-28 02:53:56 +01:00
2010-01-26 04:18:44 +01:00
return 0 ;
}
2018-05-07 20:26:38 +02:00
int config_parse_exec_oom_score_adjust (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-26 04:18:44 +01:00
2010-01-28 02:53:56 +01:00
ExecContext * c = data ;
2013-04-16 04:25:58 +02:00
int oa , r ;
2010-01-26 04:18:44 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2018-05-07 20:26:38 +02:00
if ( isempty ( rvalue ) ) {
c - > oom_score_adjust_set = false ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-01-26 04:18:44 +01:00
}
2018-05-07 20:26:38 +02:00
r = parse_oom_score_adjust ( rvalue , & oa ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
if ( r = = - ERANGE )
log_syntax ( unit , LOG_ERR , filename , line , r , " OOM score adjust value out of range, ignoring: %s " , rvalue ) ;
else
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse the OOM score adjust value '%s', ignoring: %m " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-01-26 04:18:44 +01:00
}
2010-08-31 01:33:39 +02:00
c - > oom_score_adjust = oa ;
c - > oom_score_adjust_set = true ;
2010-01-28 02:53:56 +01:00
2010-01-26 04:18:44 +01:00
return 0 ;
}
2020-04-04 16:43:25 +02:00
int config_parse_exec_coredump_filter (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
c - > coredump_filter = 0 ;
c - > coredump_filter_set = false ;
return 0 ;
}
uint64_t f ;
r = coredump_filter_mask_from_string ( rvalue , & f ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Failed to parse the CoredumpFilter=%s, ignoring: %m " , rvalue ) ;
return 0 ;
}
c - > coredump_filter | = f ;
c - > oom_score_adjust_set = true ;
return 0 ;
}
2020-05-26 13:59:04 +02:00
int config_parse_kill_mode (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
KillMode * k = data , m ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
* k = KILL_CONTROL_GROUP ;
return 0 ;
}
m = kill_mode_from_string ( rvalue ) ;
if ( m < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Failed to parse kill mode specification, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( m = = KILL_NONE )
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Unit configured to use KillMode=none. "
" This is unsafe, as it disables systemd's process life-cycle management for the service. "
" Please update your service to use a safer KillMode=, such as 'mixed' or 'control-group'. "
" Support for KillMode=none is deprecated and will eventually be removed. " ) ;
* k = m ;
return 0 ;
}
2015-04-06 20:11:41 +02:00
int config_parse_exec (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-26 04:18:44 +01:00
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
ExecCommand * * e = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
const char * p ;
bool semicolon ;
2012-03-12 22:22:16 +01:00
int r ;
2010-01-26 04:18:44 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2010-07-07 20:59:20 +02:00
assert ( e ) ;
2010-01-26 04:18:44 +01:00
2013-01-17 02:27:06 +01:00
e + = ltype ;
2015-06-06 08:12:25 +02:00
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* An empty assignment resets the list */
2014-12-18 18:29:24 +01:00
* e = exec_command_free_list ( * e ) ;
2013-01-17 02:27:06 +01:00
return 0 ;
}
2016-02-17 23:32:36 +01:00
p = rvalue ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
do {
2015-10-23 18:20:54 +02:00
_cleanup_free_ char * path = NULL , * firstword = NULL ;
2017-08-09 16:09:04 +02:00
ExecCommandFlags flags = 0 ;
bool ignore = false , separate_argv0 = false ;
2015-10-23 18:20:54 +02:00
_cleanup_free_ ExecCommand * nce = NULL ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
_cleanup_strv_free_ char * * n = NULL ;
size_t nlen = 0 , nbufsize = 0 ;
2016-12-05 18:56:25 +01:00
const char * f ;
2010-05-19 21:51:53 +02:00
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
semicolon = false ;
2019-06-28 11:15:05 +02:00
r = extract_first_word_and_warn ( & p , & firstword , NULL , EXTRACT_UNQUOTE | EXTRACT_CUNESCAPE , unit , filename , line , rvalue ) ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( r < = 0 )
return 0 ;
2010-05-19 21:51:53 +02:00
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
f = firstword ;
2016-12-11 05:07:46 +01:00
for ( ; ; ) {
2017-08-09 16:09:04 +02:00
/* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
* exist , we ignore it instead of erroring out ; if it ' s prefixed with @ , we allow overriding of
2019-02-08 00:25:37 +01:00
* argv [ 0 ] ; if it ' s prefixed with : , we will not do environment variable substitution ;
* if it ' s prefixed with + , it will be run with full privileges and no sandboxing ; if
2017-08-09 16:09:04 +02:00
* it ' s prefixed with ' ! ' we apply sandboxing , but do not change user / group credentials ; if
* it ' s prefixed with ' ! ! ' , then we apply user / group credentials if the kernel supports ambient
* capabilities - - if it doesn ' t we don ' t apply the credentials themselves , but do apply most
* other sandboxing , with some special exceptions for changing UID .
*
* The idea is that ' ! ! ' may be used to write services that can take benefit of systemd ' s
* UID / GID dropping if the kernel supports ambient creds , but provide an automatic fallback to
* privilege dropping within the daemon if the kernel does not offer that . */
if ( * f = = ' - ' & & ! ( flags & EXEC_COMMAND_IGNORE_FAILURE ) ) {
flags | = EXEC_COMMAND_IGNORE_FAILURE ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
ignore = true ;
2017-08-09 16:09:04 +02:00
} else if ( * f = = ' @ ' & & ! separate_argv0 )
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
separate_argv0 = true ;
2019-02-08 00:25:37 +01:00
else if ( * f = = ' : ' & & ! ( flags & EXEC_COMMAND_NO_ENV_EXPAND ) )
flags | = EXEC_COMMAND_NO_ENV_EXPAND ;
2017-08-09 16:09:04 +02:00
else if ( * f = = ' + ' & & ! ( flags & ( EXEC_COMMAND_FULLY_PRIVILEGED | EXEC_COMMAND_NO_SETUID | EXEC_COMMAND_AMBIENT_MAGIC ) ) )
flags | = EXEC_COMMAND_FULLY_PRIVILEGED ;
else if ( * f = = ' ! ' & & ! ( flags & ( EXEC_COMMAND_FULLY_PRIVILEGED | EXEC_COMMAND_NO_SETUID | EXEC_COMMAND_AMBIENT_MAGIC ) ) )
flags | = EXEC_COMMAND_NO_SETUID ;
else if ( * f = = ' ! ' & & ! ( flags & ( EXEC_COMMAND_FULLY_PRIVILEGED | EXEC_COMMAND_AMBIENT_MAGIC ) ) ) {
flags & = ~ EXEC_COMMAND_NO_SETUID ;
flags | = EXEC_COMMAND_AMBIENT_MAGIC ;
} else
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
break ;
2016-02-23 05:32:04 +01:00
f + + ;
2010-07-07 20:59:20 +02:00
}
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
2016-12-05 18:56:25 +01:00
r = unit_full_printf ( u , f , & path ) ;
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in '%s'%s: %m " ,
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
f , ignore ? " , ignoring " : " " ) ;
return ignore ? 0 : - ENOEXEC ;
2016-12-05 18:56:25 +01:00
}
if ( isempty ( path ) ) {
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
/* First word is either "-" or "@" with no command. */
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
2018-05-20 16:08:29 +02:00
" Empty path in command line%s: '%s' " ,
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
ignore ? " , ignoring " : " " , rvalue ) ;
return ignore ? 0 : - ENOEXEC ;
2014-07-31 09:28:37 +02:00
}
2016-12-05 18:56:25 +01:00
if ( ! string_is_safe ( path ) ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
2018-03-25 20:50:15 +02:00
" Executable name contains special characters%s: %s " ,
ignore ? " , ignoring " : " " , path ) ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return ignore ? 0 : - ENOEXEC ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
}
2016-12-05 18:56:25 +01:00
if ( endswith ( path , " / " ) ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Executable path specifies a directory%s: %s " ,
2018-03-25 20:50:15 +02:00
ignore ? " , ignoring " : " " , path ) ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return ignore ? 0 : - ENOEXEC ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
}
2010-07-07 20:59:20 +02:00
2018-03-25 20:50:15 +02:00
if ( ! path_is_absolute ( path ) ) {
const char * prefix ;
bool found = false ;
if ( ! filename_is_valid ( path ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Neither a valid executable name nor an absolute path%s: %s " ,
ignore ? " , ignoring " : " " , path ) ;
return ignore ? 0 : - ENOEXEC ;
}
/* Resolve a single-component name to a full path */
NULSTR_FOREACH ( prefix , DEFAULT_PATH_NULSTR ) {
_cleanup_free_ char * fullpath = NULL ;
2019-06-20 20:07:01 +02:00
fullpath = path_join ( prefix , path ) ;
2018-03-25 20:50:15 +02:00
if ( ! fullpath )
return log_oom ( ) ;
if ( access ( fullpath , F_OK ) > = 0 ) {
free_and_replace ( path , fullpath ) ;
found = true ;
break ;
}
}
if ( ! found ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Executable \" %s \" not found in path \" %s \" %s " ,
path , DEFAULT_PATH , ignore ? " , ignoring " : " " ) ;
return ignore ? 0 : - ENOEXEC ;
}
}
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( ! separate_argv0 ) {
2016-12-05 18:56:25 +01:00
char * w = NULL ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( ! GREEDY_REALLOC ( n , nbufsize , nlen + 2 ) )
return log_oom ( ) ;
2016-12-05 18:56:25 +01:00
w = strdup ( path ) ;
if ( ! w )
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
return log_oom ( ) ;
2016-12-05 18:56:25 +01:00
n [ nlen + + ] = w ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
n [ nlen ] = NULL ;
}
2012-03-12 22:22:16 +01:00
2018-05-31 16:39:31 +02:00
path_simplify ( path , false ) ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
2015-06-19 17:24:29 +02:00
while ( ! isempty ( p ) ) {
2016-12-05 18:56:25 +01:00
_cleanup_free_ char * word = NULL , * resolved = NULL ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
/* Check explicitly for an unquoted semicolon as
* command separator token . */
if ( p [ 0 ] = = ' ; ' & & ( ! p [ 1 ] | | strchr ( WHITESPACE , p [ 1 ] ) ) ) {
2016-02-23 05:32:04 +01:00
p + + ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
p + = strspn ( p , WHITESPACE ) ;
semicolon = true ;
break ;
2014-12-19 00:08:13 +01:00
}
2012-03-12 22:22:16 +01:00
2016-12-05 18:56:25 +01:00
/* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
* extract_first_word ( ) would return the same for all of those . */
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( p [ 0 ] = = ' \\ ' & & p [ 1 ] = = ' ; ' & & ( ! p [ 2 ] | | strchr ( WHITESPACE , p [ 2 ] ) ) ) {
2016-12-05 18:56:25 +01:00
char * w ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
p + = 2 ;
p + = strspn ( p , WHITESPACE ) ;
2016-12-05 18:56:25 +01:00
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( ! GREEDY_REALLOC ( n , nbufsize , nlen + 2 ) )
return log_oom ( ) ;
2016-12-05 18:56:25 +01:00
w = strdup ( " ; " ) ;
if ( ! w )
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
return log_oom ( ) ;
2016-12-05 18:56:25 +01:00
n [ nlen + + ] = w ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
n [ nlen ] = NULL ;
continue ;
2010-07-07 20:59:20 +02:00
}
2014-12-19 00:08:13 +01:00
2019-06-28 11:15:05 +02:00
r = extract_first_word_and_warn ( & p , & word , NULL , EXTRACT_UNQUOTE | EXTRACT_CUNESCAPE , unit , filename , line , rvalue ) ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( r = = 0 )
break ;
2016-12-05 18:56:25 +01:00
if ( r < 0 )
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return ignore ? 0 : - ENOEXEC ;
2016-12-05 18:56:25 +01:00
r = unit_full_printf ( u , word , & resolved ) ;
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in %s%s: %m " ,
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
word , ignore ? " , ignoring " : " " ) ;
return ignore ? 0 : - ENOEXEC ;
2016-12-05 18:56:25 +01:00
}
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( ! GREEDY_REALLOC ( n , nbufsize , nlen + 2 ) )
return log_oom ( ) ;
2018-04-05 07:26:26 +02:00
n [ nlen + + ] = TAKE_PTR ( resolved ) ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
n [ nlen ] = NULL ;
2010-07-07 20:59:20 +02:00
}
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( ! n | | ! n [ 0 ] ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Empty executable name or zeroeth argument%s: %s " ,
ignore ? " , ignoring " : " " , rvalue ) ;
return ignore ? 0 : - ENOEXEC ;
2012-03-12 22:22:16 +01:00
}
2010-05-19 21:51:53 +02:00
2012-03-12 22:22:16 +01:00
nce = new0 ( ExecCommand , 1 ) ;
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
if ( ! nce )
return log_oom ( ) ;
2010-07-07 20:59:20 +02:00
2018-04-05 07:26:26 +02:00
nce - > argv = TAKE_PTR ( n ) ;
nce - > path = TAKE_PTR ( path ) ;
2017-08-09 16:09:04 +02:00
nce - > flags = flags ;
2010-01-26 04:18:44 +01:00
2010-07-07 20:59:20 +02:00
exec_command_append_list ( e , nce ) ;
2010-05-24 05:25:33 +02:00
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
/* Do not _cleanup_free_ these. */
nce = NULL ;
2010-01-26 04:18:44 +01:00
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
rvalue = p ;
} while ( semicolon ) ;
2010-01-26 04:18:44 +01:00
load-fragment: use unquote_first_word in config_parse_exec
Convert config_parse_exec() from using FOREACH_WORD_QUOTED into a loop
of unquote_first_word.
Loop through the arguments only once (the FOREACH_WORD_QUOTED
implementation did it twice, once to count them and another time to
process and store them.)
Use newly introduced flag UNQUOTE_UNESCAPE_RELAX to preserve
unrecognized escape sequences such as regexps matches such as "\w",
"\d", etc. (Valid escape sequences such as "\s" or "\b" still need an
extra backslash if literals are desired for regexps.)
Differences in behavior:
- Handle ; (command separator) in special, so that only ; on its own is
valid for that purpose, an quoted semicolon ";" or ';' will now behave
as a literal semicolon. This is probably what was initially intended.
- Handle \; (to introduce a literal semicolon) in special, so that only \;
is turned into a semicolon but not \\; or "\\;" or "\;" which are kept
as a literal \; in the output. This is probably what was initially
intended.
Known issues:
- Using an empty string (for example, ExecStartPre=<empty>) will empty
the list and remove the existing commands, but using whitespace only
(for example, ExecStartPre=<spaces>) will not. This is a pre-existing
issue and will be dealt with in a follow up commit.
Tested:
- Unit tests passing. Also `make distcheck` still works as expected.
- Installed it on a local machine and booted with it, checked console
output, systemctl and journalctl output, did not notice any issues
running the patched systemd binaries.
Relevant bug: https://bugs.freedesktop.org/show_bug.cgi?id=90794
2015-05-31 07:48:52 +02:00
return 0 ;
2010-01-26 04:18:44 +01:00
}
2016-05-06 21:20:59 +02:00
int config_parse_socket_bindtodevice (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-27 04:31:52 +01:00
Socket * s = data ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2018-05-20 16:08:29 +02:00
if ( isempty ( rvalue ) | | streq ( rvalue , " * " ) ) {
s - > bind_to_device = mfree ( s - > bind_to_device ) ;
return 0 ;
}
2016-05-06 21:20:59 +02:00
2018-05-20 16:08:29 +02:00
if ( ! ifname_valid ( rvalue ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid interface name, ignoring: %s " , rvalue ) ;
return 0 ;
}
2010-01-27 04:31:52 +01:00
2018-05-31 06:26:24 +02:00
if ( free_and_strdup ( & s - > bind_to_device , rvalue ) < 0 )
return log_oom ( ) ;
2010-01-27 04:31:52 +01:00
return 0 ;
}
2017-10-26 20:06:42 +02:00
int config_parse_exec_input (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2016-10-18 02:05:49 +02:00
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2017-10-27 16:09:57 +02:00
const char * n ;
ExecInput ei ;
2016-10-18 02:05:49 +02:00
int r ;
assert ( data ) ;
assert ( filename ) ;
assert ( line ) ;
assert ( rvalue ) ;
2017-10-27 16:09:57 +02:00
n = startswith ( rvalue , " fd: " ) ;
if ( n ) {
_cleanup_free_ char * resolved = NULL ;
r = unit_full_printf ( u , n , & resolved ) ;
if ( r < 0 )
2018-05-20 16:08:29 +02:00
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s': %m " , n ) ;
2017-10-27 16:09:57 +02:00
if ( isempty ( resolved ) )
resolved = mfree ( resolved ) ;
else if ( ! fdname_is_valid ( resolved ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid file descriptor name: %s " , resolved ) ;
2018-06-01 18:06:54 +02:00
return - ENOEXEC ;
2016-10-18 02:05:49 +02:00
}
2017-10-26 20:06:42 +02:00
2017-10-27 16:09:57 +02:00
free_and_replace ( c - > stdio_fdname [ STDIN_FILENO ] , resolved ) ;
ei = EXEC_INPUT_NAMED_FD ;
} else if ( ( n = startswith ( rvalue , " file: " ) ) ) {
_cleanup_free_ char * resolved = NULL ;
r = unit_full_printf ( u , n , & resolved ) ;
2016-10-18 02:05:49 +02:00
if ( r < 0 )
2018-05-20 16:08:29 +02:00
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s': %m " , n ) ;
2017-10-26 20:06:42 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL , unit , filename , line , lvalue ) ;
if ( r < 0 )
2018-06-01 18:06:54 +02:00
return - ENOEXEC ;
2017-10-27 16:09:57 +02:00
free_and_replace ( c - > stdio_file [ STDIN_FILENO ] , resolved ) ;
ei = EXEC_INPUT_FILE ;
2017-10-26 20:06:42 +02:00
2016-10-18 02:05:49 +02:00
} else {
2017-10-26 20:06:42 +02:00
ei = exec_input_from_string ( rvalue ) ;
if ( ei < 0 ) {
2016-10-18 02:05:49 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse input specifier, ignoring: %s " , rvalue ) ;
2017-10-26 20:06:42 +02:00
return 0 ;
}
2016-10-18 02:05:49 +02:00
}
2017-10-26 20:06:42 +02:00
2017-10-27 16:09:57 +02:00
c - > std_input = ei ;
2017-10-26 20:06:42 +02:00
return 0 ;
2016-10-18 02:05:49 +02:00
}
2017-10-27 11:33:05 +02:00
int config_parse_exec_input_text (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * unescaped = NULL , * resolved = NULL ;
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2017-10-27 11:33:05 +02:00
size_t sz ;
void * p ;
int r ;
assert ( data ) ;
assert ( filename ) ;
assert ( line ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
/* Reset if the empty string is assigned */
c - > stdin_data = mfree ( c - > stdin_data ) ;
c - > stdin_data_size = 0 ;
2016-10-18 02:05:49 +02:00
return 0 ;
}
2017-10-27 11:33:05 +02:00
r = cunescape ( rvalue , 0 , & unescaped ) ;
2017-10-27 16:09:57 +02:00
if ( r < 0 )
2018-05-20 16:08:29 +02:00
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to decode C escaped text '%s': %m " , rvalue ) ;
2017-10-27 11:33:05 +02:00
r = unit_full_printf ( u , unescaped , & resolved ) ;
2017-10-27 16:09:57 +02:00
if ( r < 0 )
2018-05-20 16:08:29 +02:00
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s': %m " , unescaped ) ;
2017-10-27 11:33:05 +02:00
sz = strlen ( resolved ) ;
if ( c - > stdin_data_size + sz + 1 < c - > stdin_data_size | | /* check for overflow */
c - > stdin_data_size + sz + 1 > EXEC_STDIN_DATA_MAX ) {
2017-10-27 16:09:57 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Standard input data too large (%zu), maximum of %zu permitted, ignoring. " , c - > stdin_data_size + sz , ( size_t ) EXEC_STDIN_DATA_MAX ) ;
return - E2BIG ;
2017-10-27 11:33:05 +02:00
}
p = realloc ( c - > stdin_data , c - > stdin_data_size + sz + 1 ) ;
if ( ! p )
return log_oom ( ) ;
* ( ( char * ) mempcpy ( ( char * ) p + c - > stdin_data_size , resolved , sz ) ) = ' \n ' ;
c - > stdin_data = p ;
c - > stdin_data_size + = sz + 1 ;
return 0 ;
2016-10-18 02:05:49 +02:00
}
2017-10-27 11:33:05 +02:00
int config_parse_exec_input_data (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ void * p = NULL ;
ExecContext * c = data ;
size_t sz ;
void * q ;
int r ;
assert ( data ) ;
assert ( filename ) ;
assert ( line ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
/* Reset if the empty string is assigned */
c - > stdin_data = mfree ( c - > stdin_data ) ;
c - > stdin_data_size = 0 ;
return 0 ;
}
2017-12-03 20:57:24 +01:00
r = unbase64mem ( rvalue , ( size_t ) - 1 , & p , & sz ) ;
2017-10-27 16:09:57 +02:00
if ( r < 0 )
2017-12-03 20:57:24 +01:00
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to decode base64 data, ignoring: %s " , rvalue ) ;
2017-10-27 11:33:05 +02:00
assert ( sz > 0 ) ;
if ( c - > stdin_data_size + sz < c - > stdin_data_size | | /* check for overflow */
c - > stdin_data_size + sz > EXEC_STDIN_DATA_MAX ) {
2017-10-27 16:09:57 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Standard input data too large (%zu), maximum of %zu permitted, ignoring. " , c - > stdin_data_size + sz , ( size_t ) EXEC_STDIN_DATA_MAX ) ;
return - E2BIG ;
2017-10-27 11:33:05 +02:00
}
q = realloc ( c - > stdin_data , c - > stdin_data_size + sz ) ;
if ( ! q )
return log_oom ( ) ;
memcpy ( ( uint8_t * ) q + c - > stdin_data_size , p , sz ) ;
c - > stdin_data = q ;
c - > stdin_data_size + = sz ;
return 0 ;
}
2017-10-27 16:09:57 +02:00
int config_parse_exec_output (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * resolved = NULL ;
const char * n ;
2016-10-18 02:05:49 +02:00
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2020-05-14 12:20:39 +02:00
bool obsolete = false ;
2016-10-18 02:05:49 +02:00
ExecOutput eo ;
int r ;
assert ( data ) ;
assert ( filename ) ;
assert ( line ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2017-10-27 16:09:57 +02:00
n = startswith ( rvalue , " fd: " ) ;
if ( n ) {
r = unit_full_printf ( u , n , & resolved ) ;
if ( r < 0 )
2018-05-20 16:08:29 +02:00
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s: %m " , n ) ;
2017-10-27 16:09:57 +02:00
if ( isempty ( resolved ) )
resolved = mfree ( resolved ) ;
else if ( ! fdname_is_valid ( resolved ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid file descriptor name: %s " , resolved ) ;
2018-06-01 18:06:54 +02:00
return - ENOEXEC ;
2016-10-18 02:05:49 +02:00
}
2017-10-27 16:09:57 +02:00
2016-10-18 02:05:49 +02:00
eo = EXEC_OUTPUT_NAMED_FD ;
2017-10-27 16:09:57 +02:00
2020-05-14 12:20:39 +02:00
} else if ( streq ( rvalue , " syslog " ) ) {
eo = EXEC_OUTPUT_JOURNAL ;
obsolete = true ;
} else if ( streq ( rvalue , " syslog+console " ) ) {
eo = EXEC_OUTPUT_JOURNAL_AND_CONSOLE ;
obsolete = true ;
2017-10-27 16:09:57 +02:00
} else if ( ( n = startswith ( rvalue , " file: " ) ) ) {
r = unit_full_printf ( u , n , & resolved ) ;
if ( r < 0 )
2018-05-20 16:08:29 +02:00
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s: %m " , n ) ;
2017-10-27 16:09:57 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL , unit , filename , line , lvalue ) ;
if ( r < 0 )
2018-06-01 18:06:54 +02:00
return - ENOEXEC ;
2017-10-27 16:09:57 +02:00
eo = EXEC_OUTPUT_FILE ;
2018-07-03 21:22:29 +02:00
} else if ( ( n = startswith ( rvalue , " append: " ) ) ) {
r = unit_full_printf ( u , n , & resolved ) ;
if ( r < 0 )
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s: %m " , n ) ;
r = path_simplify_and_warn ( resolved , PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL , unit , filename , line , lvalue ) ;
if ( r < 0 )
return - ENOEXEC ;
eo = EXEC_OUTPUT_FILE_APPEND ;
2016-10-18 02:05:49 +02:00
} else {
eo = exec_output_from_string ( rvalue ) ;
2017-10-27 16:09:57 +02:00
if ( eo < 0 ) {
2016-10-18 02:05:49 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse output specifier, ignoring: %s " , rvalue ) ;
return 0 ;
}
}
2020-05-14 12:20:39 +02:00
if ( obsolete )
log_syntax ( unit , LOG_NOTICE , filename , line , 0 ,
" Standard output type %s is obsolete, automatically updating to %s. Please update your unit file, and consider removing the setting altogether. " ,
rvalue , exec_output_to_string ( eo ) ) ;
2016-10-18 02:05:49 +02:00
if ( streq ( lvalue , " StandardOutput " ) ) {
2017-10-27 16:09:57 +02:00
if ( eo = = EXEC_OUTPUT_NAMED_FD )
free_and_replace ( c - > stdio_fdname [ STDOUT_FILENO ] , resolved ) ;
else
free_and_replace ( c - > stdio_file [ STDOUT_FILENO ] , resolved ) ;
2016-10-18 02:05:49 +02:00
c - > std_output = eo ;
2017-10-27 16:09:57 +02:00
2016-10-18 02:05:49 +02:00
} else {
2017-10-27 16:09:57 +02:00
assert ( streq ( lvalue , " StandardError " ) ) ;
if ( eo = = EXEC_OUTPUT_NAMED_FD )
free_and_replace ( c - > stdio_fdname [ STDERR_FILENO ] , resolved ) ;
else
free_and_replace ( c - > stdio_file [ STDERR_FILENO ] , resolved ) ;
c - > std_error = eo ;
2016-10-18 02:05:49 +02:00
}
2017-10-27 16:09:57 +02:00
return 0 ;
2016-10-18 02:05:49 +02:00
}
2010-01-26 21:39:06 +01:00
2013-04-16 04:25:58 +02:00
int config_parse_exec_io_class ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-30 01:55:42 +01:00
ExecContext * c = data ;
int x ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2018-05-25 04:25:43 +02:00
if ( isempty ( rvalue ) ) {
c - > ioprio_set = false ;
c - > ioprio = IOPRIO_PRIO_VALUE ( IOPRIO_CLASS_BE , 0 ) ;
return 0 ;
}
2012-10-30 14:29:38 +01:00
x = ioprio_class_from_string ( rvalue ) ;
if ( x < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse IO scheduling class, ignoring: %s " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-04-13 02:22:41 +02:00
}
2010-01-30 01:55:42 +01:00
c - > ioprio = IOPRIO_PRIO_VALUE ( x , IOPRIO_PRIO_DATA ( c - > ioprio ) ) ;
c - > ioprio_set = true ;
return 0 ;
}
2013-04-16 04:25:58 +02:00
int config_parse_exec_io_priority ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-30 01:55:42 +01:00
ExecContext * c = data ;
2013-04-16 04:25:58 +02:00
int i , r ;
2010-01-30 01:55:42 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2018-05-25 04:25:43 +02:00
if ( isempty ( rvalue ) ) {
c - > ioprio_set = false ;
c - > ioprio = IOPRIO_PRIO_VALUE ( IOPRIO_CLASS_BE , 0 ) ;
return 0 ;
}
2017-06-26 17:40:08 +02:00
r = ioprio_parse_priority ( rvalue , & i ) ;
if ( r < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse IO priority, ignoring: %s " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-01-28 02:06:20 +01:00
}
2010-01-30 01:55:42 +01:00
c - > ioprio = IOPRIO_PRIO_VALUE ( IOPRIO_PRIO_CLASS ( c - > ioprio ) , i ) ;
c - > ioprio_set = true ;
2010-01-28 02:06:20 +01:00
return 0 ;
}
2013-04-16 04:25:58 +02:00
int config_parse_exec_cpu_sched_policy ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-29 20:46:22 +01:00
2010-01-30 01:55:42 +01:00
ExecContext * c = data ;
int x ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2018-05-25 04:36:10 +02:00
if ( isempty ( rvalue ) ) {
c - > cpu_sched_set = false ;
c - > cpu_sched_policy = SCHED_OTHER ;
c - > cpu_sched_priority = 0 ;
return 0 ;
}
2012-10-30 14:29:38 +01:00
x = sched_policy_from_string ( rvalue ) ;
if ( x < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse CPU scheduling policy, ignoring: %s " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-04-13 02:22:41 +02:00
}
2010-01-30 01:55:42 +01:00
c - > cpu_sched_policy = x ;
2012-11-01 18:48:11 +01:00
/* Moving to or from real-time policy? We need to adjust the priority */
c - > cpu_sched_priority = CLAMP ( c - > cpu_sched_priority , sched_get_priority_min ( x ) , sched_get_priority_max ( x ) ) ;
2010-01-30 01:55:42 +01:00
c - > cpu_sched_set = true ;
return 0 ;
}
2019-03-12 18:58:26 +01:00
int config_parse_numa_mask ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
int r ;
NUMAPolicy * p = data ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
r = parse_cpu_set_extend ( rvalue , & p - > nodes , true , unit , filename , line , lvalue ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse NUMA node mask, ignoring: %s " , rvalue ) ;
return 0 ;
}
return r ;
}
2013-04-16 04:25:58 +02:00
int config_parse_exec_cpu_sched_prio ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-29 20:46:22 +01:00
ExecContext * c = data ;
2013-04-16 04:25:58 +02:00
int i , min , max , r ;
2010-01-29 20:46:22 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2013-04-16 04:25:58 +02:00
r = safe_atoi ( rvalue , & i ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse CPU scheduling priority, ignoring: %s " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-01-30 01:55:42 +01:00
}
2010-01-29 20:46:22 +01:00
2012-11-01 18:48:11 +01:00
/* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
min = sched_get_priority_min ( c - > cpu_sched_policy ) ;
max = sched_get_priority_max ( c - > cpu_sched_policy ) ;
if ( i < min | | i > max ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " CPU scheduling priority is out of range, ignoring: %s " , rvalue ) ;
2012-11-01 18:48:11 +01:00
return 0 ;
}
2010-01-30 01:55:42 +01:00
c - > cpu_sched_priority = i ;
c - > cpu_sched_set = true ;
return 0 ;
}
2013-04-16 04:25:58 +02:00
int config_parse_exec_cpu_affinity ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-30 01:55:42 +01:00
ExecContext * c = data ;
2020-02-17 13:50:31 +01:00
int r ;
2010-01-30 01:55:42 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2020-02-17 13:50:31 +01:00
if ( streq ( rvalue , " numa " ) ) {
c - > cpu_affinity_from_numa = true ;
cpu_set_reset ( & c - > cpu_set ) ;
return 0 ;
}
r = parse_cpu_set_extend ( rvalue , & c - > cpu_set , true , unit , filename , line , lvalue ) ;
if ( r > = 0 )
c - > cpu_affinity_from_numa = false ;
return r ;
2010-01-30 01:55:42 +01:00
}
2016-01-07 23:00:04 +01:00
int config_parse_capability_set (
2015-11-10 16:08:03 +01:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-30 01:55:42 +01:00
2016-01-07 23:00:04 +01:00
uint64_t * capability_set = data ;
uint64_t sum = 0 , initial = 0 ;
2011-03-18 03:13:15 +01:00
bool invert = false ;
2017-08-07 16:25:11 +02:00
int r ;
2010-01-30 01:55:42 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2011-03-18 03:13:15 +01:00
if ( rvalue [ 0 ] = = ' ~ ' ) {
invert = true ;
rvalue + + ;
}
2017-08-01 01:55:15 +02:00
if ( streq ( lvalue , " CapabilityBoundingSet " ) )
2016-01-07 23:00:04 +01:00
initial = CAP_ALL ; /* initialized to all bits on */
2015-12-31 13:54:44 +01:00
/* else "AmbientCapabilities" initialized to all bits off */
2011-03-18 03:13:15 +01:00
2017-08-07 16:25:11 +02:00
r = capability_set_from_string ( rvalue , & sum ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse %s= specifier '%s', ignoring: %m " , lvalue , rvalue ) ;
2017-08-07 16:25:11 +02:00
return 0 ;
2010-01-30 01:55:42 +01:00
}
2010-01-29 20:46:22 +01:00
2016-01-07 23:00:04 +01:00
if ( sum = = 0 | | * capability_set = = initial )
2017-09-04 05:12:27 +02:00
/* "", "~" or uninitialized data -> replace */
* capability_set = invert ? ~ sum : sum ;
else {
2016-01-07 23:00:04 +01:00
/* previous data -> merge */
2017-09-04 05:12:27 +02:00
if ( invert )
* capability_set & = ~ sum ;
else
* capability_set | = sum ;
}
2011-03-18 03:13:15 +01:00
2010-01-29 20:46:22 +01:00
return 0 ;
}
2014-02-17 16:52:52 +01:00
int config_parse_exec_selinux_context (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2014-02-17 16:52:52 +01:00
bool ignore ;
char * k ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
2015-09-08 18:43:11 +02:00
c - > selinux_context = mfree ( c - > selinux_context ) ;
2014-02-17 16:52:52 +01:00
c - > selinux_context_ignore = false ;
return 0 ;
}
if ( rvalue [ 0 ] = = ' - ' ) {
ignore = true ;
rvalue + + ;
} else
ignore = false ;
2016-12-05 19:25:44 +01:00
r = unit_full_printf ( u , rvalue , & k ) ;
2014-02-17 16:52:52 +01:00
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in '%s'%s: %m " ,
rvalue , ignore ? " , ignoring " : " " ) ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return ignore ? 0 : - ENOEXEC ;
2014-02-17 16:52:52 +01:00
}
2018-05-20 16:08:29 +02:00
free_and_replace ( c - > selinux_context , k ) ;
2014-02-17 16:52:52 +01:00
c - > selinux_context_ignore = ignore ;
return 0 ;
}
2014-02-20 16:19:44 +01:00
int config_parse_exec_apparmor_profile (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2014-02-20 16:19:44 +01:00
bool ignore ;
char * k ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
2015-09-08 18:43:11 +02:00
c - > apparmor_profile = mfree ( c - > apparmor_profile ) ;
2014-02-20 16:19:44 +01:00
c - > apparmor_profile_ignore = false ;
return 0 ;
}
if ( rvalue [ 0 ] = = ' - ' ) {
ignore = true ;
rvalue + + ;
} else
ignore = false ;
2016-12-05 19:25:44 +01:00
r = unit_full_printf ( u , rvalue , & k ) ;
2014-02-20 16:19:44 +01:00
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in '%s'%s: %m " ,
rvalue , ignore ? " , ignoring " : " " ) ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return ignore ? 0 : - ENOEXEC ;
2014-02-20 16:19:44 +01:00
}
2018-05-20 16:08:29 +02:00
free_and_replace ( c - > apparmor_profile , k ) ;
2014-02-20 16:19:44 +01:00
c - > apparmor_profile_ignore = ignore ;
return 0 ;
}
2014-11-24 12:46:20 +01:00
int config_parse_exec_smack_process_label (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2014-11-24 12:46:20 +01:00
bool ignore ;
char * k ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
2015-09-08 18:43:11 +02:00
c - > smack_process_label = mfree ( c - > smack_process_label ) ;
2014-11-24 12:46:20 +01:00
c - > smack_process_label_ignore = false ;
return 0 ;
}
if ( rvalue [ 0 ] = = ' - ' ) {
ignore = true ;
rvalue + + ;
} else
ignore = false ;
2016-12-05 19:25:44 +01:00
r = unit_full_printf ( u , rvalue , & k ) ;
2014-11-24 12:46:20 +01:00
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in '%s'%s: %m " ,
rvalue , ignore ? " , ignoring " : " " ) ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return ignore ? 0 : - ENOEXEC ;
2014-11-24 12:46:20 +01:00
}
2018-05-20 16:08:29 +02:00
free_and_replace ( c - > smack_process_label , k ) ;
2014-11-24 12:46:20 +01:00
c - > smack_process_label_ignore = ignore ;
return 0 ;
}
2019-04-01 17:39:11 +02:00
int config_parse_timer (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-05-24 01:45:54 +02:00
2019-04-01 17:39:11 +02:00
_cleanup_ ( calendar_spec_freep ) CalendarSpec * c = NULL ;
_cleanup_free_ char * k = NULL ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2010-05-24 01:45:54 +02:00
Timer * t = data ;
2016-08-26 18:13:16 +02:00
usec_t usec = 0 ;
2010-05-24 01:45:54 +02:00
TimerValue * v ;
2016-08-26 18:13:16 +02:00
int r ;
2010-05-24 01:45:54 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment resets list */
timer_free_values ( t ) ;
return 0 ;
}
2016-08-26 18:13:16 +02:00
r = unit_full_printf ( u , rvalue , & k ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2016-08-26 18:13:16 +02:00
return 0 ;
}
2019-04-01 17:39:11 +02:00
if ( ltype = = TIMER_CALENDAR ) {
2019-04-01 17:43:29 +02:00
r = calendar_spec_from_string ( k , & c ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse calendar specification, ignoring: %s " , k ) ;
2012-11-23 21:37:58 +01:00
return 0 ;
}
2019-04-01 17:43:29 +02:00
} else {
r = parse_sec ( k , & usec ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse timer value, ignoring: %s " , k ) ;
2012-11-23 21:37:58 +01:00
return 0 ;
}
2019-04-01 17:43:29 +02:00
}
2010-05-24 01:45:54 +02:00
2019-04-01 17:39:11 +02:00
v = new ( TimerValue , 1 ) ;
2018-05-10 14:04:30 +02:00
if ( ! v )
2013-01-17 02:27:06 +01:00
return log_oom ( ) ;
2010-05-24 01:45:54 +02:00
2019-04-01 17:39:11 +02:00
* v = ( TimerValue ) {
. base = ltype ,
. value = usec ,
. calendar_spec = TAKE_PTR ( c ) ,
} ;
2010-05-24 01:45:54 +02:00
2013-10-14 06:10:14 +02:00
LIST_PREPEND ( value , t - > values , v ) ;
2010-05-24 01:45:54 +02:00
return 0 ;
}
2013-04-23 20:53:16 +02:00
int config_parse_trigger_unit (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-23 20:53:16 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-05-24 01:45:54 +02:00
2013-01-17 02:27:06 +01:00
_cleanup_free_ char * p = NULL ;
2013-04-23 20:53:16 +02:00
Unit * u = data ;
UnitType type ;
int r ;
2010-07-08 02:43:18 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
if ( ! hashmap_isempty ( u - > dependencies [ UNIT_TRIGGERS ] ) ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Multiple units to trigger specified, ignoring: %s " , rvalue ) ;
2013-04-23 20:53:16 +02:00
return 0 ;
}
2010-05-24 01:45:54 +02:00
2013-09-17 17:03:46 +02:00
r = unit_name_printf ( u , rvalue , & p ) ;
2015-09-30 18:22:42 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
}
2013-01-17 02:27:06 +01:00
2015-09-30 18:22:42 +02:00
type = unit_name_to_type ( p ) ;
2013-04-23 20:53:16 +02:00
if ( type < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Unit type not valid, ignoring: %s " , rvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-05-24 01:45:54 +02:00
}
2018-02-14 14:10:07 +01:00
if ( unit_has_name ( u , p ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Units cannot trigger themselves, ignoring: %s " , rvalue ) ;
2013-04-23 20:53:16 +02:00
return 0 ;
}
2018-09-15 20:02:00 +02:00
r = unit_add_two_dependencies_by_name ( u , UNIT_BEFORE , UNIT_TRIGGERS , p , true , UNIT_DEPENDENCY_FILE ) ;
2012-01-06 23:08:54 +01:00
if ( r < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to add trigger on %s, ignoring: %m " , p ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-05-24 01:45:54 +02:00
}
return 0 ;
}
2013-04-16 04:25:58 +02:00
int config_parse_path_spec ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-05-24 05:25:33 +02:00
Path * p = data ;
PathSpec * s ;
PathType b ;
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * k = NULL ;
2013-09-17 17:03:46 +02:00
int r ;
2010-05-24 05:25:33 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment clears list */
path_free_specs ( p ) ;
return 0 ;
}
2012-09-19 20:09:27 +02:00
b = path_type_from_string ( lvalue ) ;
if ( b < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse path type, ignoring: %s " , lvalue ) ;
2010-08-17 03:30:53 +02:00
return 0 ;
2010-05-24 05:25:33 +02:00
}
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( UNIT ( p ) , rvalue , & k ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
2013-03-01 14:54:55 +01:00
}
2012-09-19 20:09:27 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( k , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
2010-08-17 03:30:53 +02:00
return 0 ;
2010-05-24 05:25:33 +02:00
2012-09-19 20:09:27 +02:00
s = new0 ( PathSpec , 1 ) ;
2013-04-16 03:58:22 +02:00
if ( ! s )
2012-09-19 20:09:27 +02:00
return log_oom ( ) ;
2010-05-24 05:25:33 +02:00
2013-11-19 21:12:59 +01:00
s - > unit = UNIT ( p ) ;
2018-05-20 16:08:29 +02:00
s - > path = TAKE_PTR ( k ) ;
2010-05-24 05:25:33 +02:00
s - > type = b ;
s - > inotify_fd = - 1 ;
2013-10-14 06:10:14 +02:00
LIST_PREPEND ( spec , p - > specs , s ) ;
2010-05-24 05:25:33 +02:00
return 0 ;
}
2015-01-07 22:07:09 +01:00
int config_parse_socket_service (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-09-30 02:19:12 +02:00
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
2015-10-04 17:36:19 +02:00
_cleanup_free_ char * p = NULL ;
2010-09-30 02:19:12 +02:00
Socket * s = data ;
2012-01-07 01:21:40 +01:00
Unit * x ;
2015-10-04 17:36:19 +02:00
int r ;
2010-09-30 02:19:12 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2013-09-17 17:03:46 +02:00
r = unit_name_printf ( UNIT ( s ) , rvalue , & p ) ;
2013-11-27 20:23:18 +01:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s: %m " , rvalue ) ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return - ENOEXEC ;
2013-11-27 20:23:18 +01:00
}
2013-01-17 02:27:06 +01:00
2013-11-27 20:23:18 +01:00
if ( ! endswith ( p , " .service " ) ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Unit must be of type service: %s " , rvalue ) ;
return - ENOEXEC ;
2010-09-30 02:19:12 +02:00
}
2013-11-27 20:23:18 +01:00
r = manager_load_unit ( UNIT ( s ) - > manager , p , NULL , & error , & x ) ;
2012-01-07 01:21:40 +01:00
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to load unit %s: %s " , rvalue , bus_error_message ( & error , r ) ) ;
return - ENOEXEC ;
2010-09-30 02:19:12 +02:00
}
2018-02-13 13:12:43 +01:00
unit_ref_set ( & s - > service , UNIT ( s ) , x ) ;
2012-01-07 01:21:40 +01:00
2010-09-30 02:19:12 +02:00
return 0 ;
}
2015-10-04 17:36:19 +02:00
int config_parse_fdname (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * p = NULL ;
Socket * s = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
s - > fdname = mfree ( s - > fdname ) ;
return 0 ;
}
2016-12-05 19:25:44 +01:00
r = unit_full_printf ( UNIT ( s ) , rvalue , & p ) ;
2015-10-04 17:36:19 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2015-10-04 17:36:19 +02:00
return 0 ;
}
if ( ! fdname_is_valid ( p ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid file descriptor name, ignoring: %s " , p ) ;
return 0 ;
}
2016-10-17 01:23:35 +02:00
return free_and_replace ( s - > fdname , p ) ;
2015-10-04 17:36:19 +02:00
}
2015-01-07 22:07:09 +01:00
int config_parse_service_sockets (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-10-05 19:49:15 +02:00
Service * s = data ;
2015-11-03 18:19:05 +01:00
const char * p ;
2015-01-07 22:07:09 +01:00
int r ;
2010-10-05 19:49:15 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2015-11-03 18:19:05 +01:00
p = rvalue ;
2016-02-23 18:52:52 +01:00
for ( ; ; ) {
2015-11-07 11:03:11 +01:00
_cleanup_free_ char * word = NULL , * k = NULL ;
2010-10-05 19:49:15 +02:00
2015-11-03 18:19:05 +01:00
r = extract_first_word ( & p , & word , NULL , 0 ) ;
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
2013-01-17 02:27:06 +01:00
return log_oom ( ) ;
2015-11-03 18:19:05 +01:00
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Trailing garbage in sockets, ignoring: %s " , rvalue ) ;
break ;
}
2010-10-05 19:49:15 +02:00
2015-11-03 18:19:05 +01:00
r = unit_name_printf ( UNIT ( s ) , word , & k ) ;
2015-01-07 22:07:09 +01:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , word ) ;
2015-01-07 22:07:09 +01:00
continue ;
}
2012-01-06 23:08:54 +01:00
2015-01-07 22:07:09 +01:00
if ( ! endswith ( k , " .socket " ) ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Unit must be of type socket, ignoring: %s " , k ) ;
2010-10-05 19:49:15 +02:00
continue ;
}
2018-09-15 20:02:00 +02:00
r = unit_add_two_dependencies_by_name ( UNIT ( s ) , UNIT_WANTS , UNIT_AFTER , k , true , UNIT_DEPENDENCY_FILE ) ;
2012-01-06 23:08:54 +01:00
if ( r < 0 )
2015-01-07 22:07:09 +01:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to add dependency on %s, ignoring: %m " , k ) ;
2010-10-05 19:49:15 +02:00
2018-09-15 19:57:52 +02:00
r = unit_add_dependency_by_name ( UNIT ( s ) , UNIT_TRIGGERED_BY , k , true , UNIT_DEPENDENCY_FILE ) ;
2012-01-06 23:08:54 +01:00
if ( r < 0 )
2015-01-07 22:07:09 +01:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to add dependency on %s, ignoring: %m " , k ) ;
2010-10-05 19:49:15 +02:00
}
return 0 ;
}
2015-01-07 22:07:09 +01:00
int config_parse_bus_name (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * k = NULL ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2015-01-07 22:07:09 +01:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
r = unit_full_printf ( u , rvalue , & k ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , rvalue ) ;
2015-01-07 22:07:09 +01:00
return 0 ;
}
2020-05-24 13:39:25 +02:00
if ( ! sd_bus_service_name_is_valid ( k ) ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid bus name, ignoring: %s " , k ) ;
2015-01-07 22:07:09 +01:00
return 0 ;
}
return config_parse_string ( unit , filename , line , section , section_line , lvalue , ltype , k , data , userdata ) ;
}
2016-02-08 23:54:54 +01:00
int config_parse_service_timeout (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2012-06-14 17:07:07 +02:00
Service * s = userdata ;
2016-02-08 23:54:54 +01:00
usec_t usec ;
2012-06-14 17:07:07 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( s ) ;
2018-05-25 05:16:24 +02:00
/* This is called for two cases: TimeoutSec= and TimeoutStartSec=. */
2012-06-14 17:07:07 +02:00
2018-05-25 05:17:52 +02:00
/* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
* immediately , hence fix this to become USEC_INFINITY instead . This is in - line with how we internally handle
* all other timeouts . */
r = parse_sec_fix_0 ( rvalue , & usec ) ;
2016-02-08 23:54:54 +01:00
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse %s= parameter, ignoring: %s " , lvalue , rvalue ) ;
return 0 ;
}
2012-08-07 14:41:48 +02:00
2018-05-25 05:16:24 +02:00
s - > start_timeout_defined = true ;
s - > timeout_start_usec = usec ;
core: rework unit timeout handling, and add new setting RuntimeMaxSec=
This clean-ups timeout handling in PID 1. Specifically, instead of storing 0 in internal timeout variables as
indication for a disabled timeout, use USEC_INFINITY which is in-line with how we do this in the rest of our code
(following the logic that 0 means "no", and USEC_INFINITY means "never").
This also replace all usec_t additions with invocations to usec_add(), so that USEC_INFINITY is properly propagated,
and sd-event considers it has indication for turning off the event source.
This also alters the deserialization of the units to restart timeouts from the time they were originally started from.
Before this patch timeouts would be restarted beginning with the time of the deserialization, which could lead to
artificially prolonged timeouts if a daemon reload took place.
Finally, a new RuntimeMaxSec= setting is introduced for service units, that specifies a maximum runtime after which a
specific service is forcibly terminated. This is useful to put time limits on time-intensive processing jobs.
This also simplifies the various xyz_spawn() calls of the various types in that explicit distruction of the timers is
removed, as that is done anyway by the state change handlers, and a state change is always done when the xyz_spawn()
calls fail.
Fixes: #2249
2016-02-01 21:48:10 +01:00
2018-05-25 05:16:24 +02:00
if ( streq ( lvalue , " TimeoutSec " ) )
2016-02-08 23:54:54 +01:00
s - > timeout_stop_usec = usec ;
core: rework unit timeout handling, and add new setting RuntimeMaxSec=
This clean-ups timeout handling in PID 1. Specifically, instead of storing 0 in internal timeout variables as
indication for a disabled timeout, use USEC_INFINITY which is in-line with how we do this in the rest of our code
(following the logic that 0 means "no", and USEC_INFINITY means "never").
This also replace all usec_t additions with invocations to usec_add(), so that USEC_INFINITY is properly propagated,
and sd-event considers it has indication for turning off the event source.
This also alters the deserialization of the units to restart timeouts from the time they were originally started from.
Before this patch timeouts would be restarted beginning with the time of the deserialization, which could lead to
artificially prolonged timeouts if a daemon reload took place.
Finally, a new RuntimeMaxSec= setting is introduced for service units, that specifies a maximum runtime after which a
specific service is forcibly terminated. This is useful to put time limits on time-intensive processing jobs.
This also simplifies the various xyz_spawn() calls of the various types in that explicit distruction of the timers is
removed, as that is done anyway by the state change handlers, and a state change is always done when the xyz_spawn()
calls fail.
Fixes: #2249
2016-02-01 21:48:10 +01:00
2012-08-07 14:41:48 +02:00
return 0 ;
2012-06-14 17:07:07 +02:00
}
2019-11-27 13:13:17 +01:00
int config_parse_timeout_abort (
2017-11-29 07:43:44 +01:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2019-11-27 13:13:17 +01:00
usec_t * ret = data ;
2017-11-29 07:43:44 +01:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2019-11-27 13:13:17 +01:00
assert ( ret ) ;
/* Note: apart from setting the arg, this returns an extra bit of information in the return value. */
2017-11-29 07:43:44 +01:00
if ( isempty ( rvalue ) ) {
2019-11-27 13:13:17 +01:00
* ret = 0 ;
return 0 ; /* "not set" */
2017-11-29 07:43:44 +01:00
}
2019-11-27 13:13:17 +01:00
r = parse_sec ( rvalue , ret ) ;
if ( r < 0 )
return log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse %s= setting, ignoring: %s " , lvalue , rvalue ) ;
return 1 ; /* "set" */
}
int config_parse_service_timeout_abort (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
Service * s = userdata ;
int r ;
2017-11-29 07:43:44 +01:00
2019-11-27 13:13:17 +01:00
assert ( s ) ;
r = config_parse_timeout_abort ( unit , filename , line , section , section_line , lvalue , ltype , rvalue ,
& s - > timeout_abort_usec , s ) ;
if ( r > = 0 )
s - > timeout_abort_set = r ;
2017-11-29 07:43:44 +01:00
return 0 ;
}
2016-02-08 23:56:30 +01:00
int config_parse_sec_fix_0 (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
usec_t * usec = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( usec ) ;
/* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
* compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
* timeout . */
2017-07-03 14:29:32 +02:00
r = parse_sec_fix_0 ( rvalue , usec ) ;
2016-02-08 23:56:30 +01:00
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse %s= parameter, ignoring: %s " , lvalue , rvalue ) ;
return 0 ;
}
return 0 ;
}
2019-08-01 09:58:27 +02:00
int config_parse_user_group_compat (
2016-07-14 12:28:06 +02:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-20 16:08:29 +02:00
_cleanup_free_ char * k = NULL ;
char * * user = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2016-07-14 12:28:06 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
2018-05-20 16:08:29 +02:00
if ( isempty ( rvalue ) ) {
* user = mfree ( * user ) ;
return 0 ;
}
2016-07-14 12:28:06 +02:00
2018-05-20 16:08:29 +02:00
r = unit_full_printf ( u , rvalue , & k ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s: %m " , rvalue ) ;
return - ENOEXEC ;
2016-07-14 12:28:06 +02:00
}
2020-04-04 12:23:02 +02:00
if ( ! valid_user_group_name ( k , VALID_USER_ALLOW_NUMERIC | VALID_USER_RELAX | VALID_USER_WARN ) ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid user/group name or numeric ID: %s " , k ) ;
return - ENOEXEC ;
}
2016-07-14 12:28:06 +02:00
2018-05-20 16:08:29 +02:00
return free_and_replace ( * user , k ) ;
2016-07-14 12:28:06 +02:00
}
2019-08-01 09:58:27 +02:00
int config_parse_user_group_strv_compat (
2016-07-14 12:28:06 +02:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
char * * * users = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
2016-07-14 12:28:06 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
if ( isempty ( rvalue ) ) {
2017-10-04 08:21:12 +02:00
* users = strv_free ( * users ) ;
2016-07-14 12:28:06 +02:00
return 0 ;
}
for ( ; ; ) {
_cleanup_free_ char * word = NULL , * k = NULL ;
2016-10-28 02:06:44 +02:00
r = extract_first_word ( & p , & word , NULL , 0 ) ;
2016-07-14 12:28:06 +02:00
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid syntax: %s " , rvalue ) ;
return - ENOEXEC ;
2016-07-14 12:28:06 +02:00
}
r = unit_full_printf ( u , word , & k ) ;
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s: %m " , word ) ;
return - ENOEXEC ;
2016-07-14 12:28:06 +02:00
}
2020-04-04 12:23:02 +02:00
if ( ! valid_user_group_name ( k , VALID_USER_ALLOW_NUMERIC | VALID_USER_RELAX | VALID_USER_WARN ) ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid user/group name or numeric ID: %s " , k ) ;
return - ENOEXEC ;
2016-07-14 12:28:06 +02:00
}
r = strv_push ( users , k ) ;
if ( r < 0 )
return log_oom ( ) ;
k = NULL ;
}
return 0 ;
}
2015-09-23 19:46:23 +02:00
int config_parse_working_directory (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2015-09-23 19:46:23 +02:00
bool missing_ok ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( c ) ;
assert ( u ) ;
2018-05-25 05:25:41 +02:00
if ( isempty ( rvalue ) ) {
c - > working_directory_home = false ;
c - > working_directory = mfree ( c - > working_directory ) ;
return 0 ;
}
2015-09-23 19:46:23 +02:00
if ( rvalue [ 0 ] = = ' - ' ) {
missing_ok = true ;
rvalue + + ;
} else
missing_ok = false ;
if ( streq ( rvalue , " ~ " ) ) {
c - > working_directory_home = true ;
c - > working_directory = mfree ( c - > working_directory ) ;
} else {
_cleanup_free_ char * k = NULL ;
r = unit_full_printf ( u , rvalue , & k ) ;
if ( r < 0 ) {
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
" Failed to resolve unit specifiers in working directory path '%s'%s: %m " ,
rvalue , missing_ok ? " , ignoring " : " " ) ;
return missing_ok ? 0 : - ENOEXEC ;
2015-09-23 19:46:23 +02:00
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( k , PATH_CHECK_ABSOLUTE | ( missing_ok ? 0 : PATH_CHECK_FATAL ) , unit , filename , line , lvalue ) ;
if ( r < 0 )
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
return missing_ok ? 0 : - ENOEXEC ;
2015-09-23 19:46:23 +02:00
c - > working_directory_home = false ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
free_and_replace ( c - > working_directory , k ) ;
2015-09-23 19:46:23 +02:00
}
c - > working_directory_missing_ok = missing_ok ;
return 0 ;
}
2013-04-16 04:25:58 +02:00
int config_parse_unit_env_file ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-06-18 06:06:24 +02:00
2013-02-11 23:45:59 +01:00
char * * * env = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2013-09-17 17:03:46 +02:00
_cleanup_free_ char * n = NULL ;
2013-02-11 23:45:59 +01:00
int r ;
2010-06-18 06:06:24 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment frees the list */
2015-09-09 23:05:10 +02:00
* env = strv_free ( * env ) ;
2013-01-17 02:27:06 +01:00
return 0 ;
}
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( u , rvalue , & n ) ;
2015-09-30 18:22:42 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
}
2011-07-01 01:13:47 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( n [ 0 ] = = ' - ' ? n + 1 : n , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
2011-01-06 01:39:08 +01:00
return 0 ;
2018-06-03 16:59:02 +02:00
r = strv_push ( env , n ) ;
2013-02-11 23:45:59 +01:00
if ( r < 0 )
return log_oom ( ) ;
2018-06-03 16:59:02 +02:00
n = NULL ;
2013-02-11 23:45:59 +01:00
return 0 ;
}
2017-09-12 19:47:58 +02:00
int config_parse_environ (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2013-02-11 23:45:59 +01:00
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2016-10-28 02:15:22 +02:00
char * * * env = data ;
const char * p ;
2013-09-17 17:03:46 +02:00
int r ;
2013-02-11 23:45:59 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2013-06-09 07:08:46 +02:00
assert ( data ) ;
2013-02-11 23:45:59 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2015-09-09 23:05:10 +02:00
* env = strv_free ( * env ) ;
2013-02-11 23:45:59 +01:00
return 0 ;
}
2016-10-28 02:15:22 +02:00
for ( p = rvalue ; ; ) {
_cleanup_free_ char * word = NULL , * k = NULL ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_CUNESCAPE | EXTRACT_UNQUOTE ) ;
2016-10-28 02:15:22 +02:00
if ( r = = 0 )
return 0 ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
2015-09-30 18:22:42 +02:00
if ( r < 0 ) {
2016-10-28 02:15:22 +02:00
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
2015-09-30 18:22:42 +02:00
return 0 ;
}
2013-06-09 07:08:46 +02:00
2016-10-28 02:15:22 +02:00
if ( u ) {
r = unit_full_printf ( u , word , & k ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in %s, ignoring: %m " , word ) ;
2016-10-28 02:15:22 +02:00
continue ;
}
2018-03-22 16:53:26 +01:00
} else
k = TAKE_PTR ( word ) ;
2013-02-11 23:45:59 +01:00
2016-10-28 02:15:22 +02:00
if ( ! env_assignment_is_valid ( k ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Invalid environment assignment, ignoring: %s " , k ) ;
2013-02-11 23:45:59 +01:00
continue ;
}
2016-10-28 03:15:59 +02:00
r = strv_env_replace ( env , k ) ;
if ( r < 0 )
2013-02-11 23:45:59 +01:00
return log_oom ( ) ;
2017-09-12 19:47:58 +02:00
2016-10-28 03:15:59 +02:00
k = NULL ;
2013-02-11 23:45:59 +01:00
}
2010-06-18 06:06:24 +02:00
}
2017-09-10 12:16:44 +02:00
int config_parse_pass_environ (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2015-09-07 08:06:53 +02:00
_cleanup_strv_free_ char * * n = NULL ;
size_t nlen = 0 , nbufsize = 0 ;
2017-09-12 19:48:29 +02:00
char * * * passenv = data ;
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2015-09-07 08:06:53 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
* passenv = strv_free ( * passenv ) ;
return 0 ;
}
for ( ; ; ) {
2017-09-12 19:48:29 +02:00
_cleanup_free_ char * word = NULL , * k = NULL ;
2015-09-07 08:06:53 +02:00
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2015-09-07 08:06:53 +02:00
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Trailing garbage in %s, ignoring: %s " , lvalue , rvalue ) ;
2015-09-07 08:06:53 +02:00
break ;
}
2017-09-12 19:48:29 +02:00
if ( u ) {
r = unit_full_printf ( u , word , & k ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve specifiers in %s, ignoring: %m " , word ) ;
2017-09-12 19:48:29 +02:00
continue ;
}
2018-03-22 16:53:26 +01:00
} else
k = TAKE_PTR ( word ) ;
2017-09-12 19:48:29 +02:00
if ( ! env_name_is_valid ( k ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Invalid environment name for %s, ignoring: %s " , lvalue , k ) ;
2015-09-07 08:06:53 +02:00
continue ;
}
if ( ! GREEDY_REALLOC ( n , nbufsize , nlen + 2 ) )
return log_oom ( ) ;
2017-09-12 19:48:29 +02:00
2018-04-05 07:26:26 +02:00
n [ nlen + + ] = TAKE_PTR ( k ) ;
2015-09-07 08:06:53 +02:00
n [ nlen ] = NULL ;
}
if ( n ) {
r = strv_extend_strv ( passenv , n , true ) ;
if ( r < 0 )
return r ;
}
return 0 ;
}
2017-09-10 12:16:44 +02:00
int config_parse_unset_environ (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_strv_free_ char * * n = NULL ;
size_t nlen = 0 , nbufsize = 0 ;
char * * * unsetenv = data ;
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2017-09-10 12:16:44 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
* unsetenv = strv_free ( * unsetenv ) ;
return 0 ;
}
for ( ; ; ) {
_cleanup_free_ char * word = NULL , * k = NULL ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_CUNESCAPE | EXTRACT_UNQUOTE ) ;
2017-09-10 12:16:44 +02:00
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Trailing garbage in %s, ignoring: %s " , lvalue , rvalue ) ;
2017-09-10 12:16:44 +02:00
break ;
}
if ( u ) {
r = unit_full_printf ( u , word , & k ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in %s, ignoring: %m " , word ) ;
2017-09-10 12:16:44 +02:00
continue ;
}
2018-03-22 16:53:26 +01:00
} else
k = TAKE_PTR ( word ) ;
2017-09-10 12:16:44 +02:00
if ( ! env_assignment_is_valid ( k ) & & ! env_name_is_valid ( k ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Invalid environment name or assignment %s, ignoring: %s " , lvalue , k ) ;
continue ;
}
if ( ! GREEDY_REALLOC ( n , nbufsize , nlen + 2 ) )
return log_oom ( ) ;
2018-04-05 07:26:26 +02:00
n [ nlen + + ] = TAKE_PTR ( k ) ;
2017-09-10 12:16:44 +02:00
n [ nlen ] = NULL ;
}
if ( n ) {
r = strv_extend_strv ( unsetenv , n , true ) ;
if ( r < 0 )
return r ;
}
return 0 ;
}
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
int config_parse_log_extra_fields (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( c ) ;
if ( isempty ( rvalue ) ) {
exec_context_free_log_extra_fields ( c ) ;
return 0 ;
}
2018-05-20 16:08:29 +02:00
for ( ; ; ) {
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
_cleanup_free_ char * word = NULL , * k = NULL ;
struct iovec * t ;
const char * eq ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_CUNESCAPE | EXTRACT_UNQUOTE ) ;
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
if ( r = = 0 )
2018-05-20 16:08:29 +02:00
return 0 ;
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r , " Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
r = unit_full_printf ( u , word , & k ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , word ) ;
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
continue ;
}
eq = strchr ( k , ' = ' ) ;
if ( ! eq ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Log field lacks '=' character, ignoring: %s " , k ) ;
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
continue ;
}
if ( ! journal_field_valid ( k , eq - k , false ) ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Log field name is invalid, ignoring: %s " , k ) ;
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
continue ;
}
2018-02-26 21:20:00 +01:00
t = reallocarray ( c - > log_extra_fields , c - > n_log_extra_fields + 1 , sizeof ( struct iovec ) ) ;
core: implement /run/systemd/units/-based path for passing unit info from PID 1 to journald
And let's make use of it to implement two new unit settings with it:
1. LogLevelMax= is a new per-unit setting that may be used to configure
log priority filtering: set it to LogLevelMax=notice and only
messages of level "notice" and lower (i.e. more important) will be
processed, all others are dropped.
2. LogExtraFields= is a new per-unit setting for configuring per-unit
journal fields, that are implicitly included in every log record
generated by the unit's processes. It takes field/value pairs in the
form of FOO=BAR.
Also, related to this, one exisiting unit setting is ported to this new
facility:
3. The invocation ID is now pulled from /run/systemd/units/ instead of
cgroupfs xattrs. This substantially relaxes requirements of systemd
on the kernel version and the privileges it runs with (specifically,
cgroupfs xattrs are not available in containers, since they are
stored in kernel memory, and hence are unsafe to permit to lesser
privileged code).
/run/systemd/units/ is a new directory, which contains a number of files
and symlinks encoding the above information. PID 1 creates and manages
these files, and journald reads them from there.
Note that this is supposed to be a direct path between PID 1 and the
journal only, due to the special runtime environment the journal runs
in. Normally, today we shouldn't introduce new interfaces that (mis-)use
a file system as IPC framework, and instead just an IPC system, but this
is very hard to do between the journal and PID 1, as long as the IPC
system is a subject PID 1 manages, and itself a client to the journal.
This patch cleans up a couple of types used in journal code:
specifically we switch to size_t for a couple of memory-sizing values,
as size_t is the right choice for everything that is memory.
Fixes: #4089
Fixes: #3041
Fixes: #4441
2017-11-02 19:43:32 +01:00
if ( ! t )
return log_oom ( ) ;
c - > log_extra_fields = t ;
c - > log_extra_fields [ c - > n_log_extra_fields + + ] = IOVEC_MAKE_STRING ( k ) ;
k = NULL ;
}
}
2019-11-25 16:22:45 +01:00
int config_parse_log_namespace (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * k = NULL ;
ExecContext * c = data ;
const Unit * u = userdata ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( c ) ;
if ( isempty ( rvalue ) ) {
c - > log_namespace = mfree ( c - > log_namespace ) ;
return 0 ;
}
r = unit_full_printf ( u , rvalue , & k ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , rvalue ) ;
return 0 ;
}
if ( ! log_namespace_name_valid ( k ) ) {
log_syntax ( unit , LOG_ERR , filename , line , SYNTHETIC_ERRNO ( EINVAL ) , " Specified log namespace name is not valid: %s " , k ) ;
return 0 ;
}
free_and_replace ( c - > log_namespace , k ) ;
return 0 ;
}
2014-11-06 13:43:45 +01:00
int config_parse_unit_condition_path (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-10-13 02:15:41 +02:00
2012-09-13 22:30:26 +02:00
_cleanup_free_ char * p = NULL ;
2014-11-06 13:43:45 +01:00
Condition * * list = data , * c ;
ConditionType t = ltype ;
bool trigger , negate ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2013-09-17 17:03:46 +02:00
int r ;
2010-10-13 02:15:41 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2014-12-18 18:33:05 +01:00
* list = condition_free_list ( * list ) ;
2013-01-17 02:27:06 +01:00
return 0 ;
}
2011-09-21 00:44:51 +02:00
trigger = rvalue [ 0 ] = = ' | ' ;
if ( trigger )
2011-03-08 03:04:47 +01:00
rvalue + + ;
2011-09-21 00:44:51 +02:00
negate = rvalue [ 0 ] = = ' ! ' ;
if ( negate )
2010-10-13 02:15:41 +02:00
rvalue + + ;
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( u , rvalue , & p ) ;
2014-11-06 13:43:45 +01:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , rvalue ) ;
2014-11-06 13:43:45 +01:00
return 0 ;
2013-09-17 17:03:46 +02:00
}
2012-09-13 21:34:25 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( p , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
2010-10-13 02:15:41 +02:00
return 0 ;
2014-11-06 13:43:45 +01:00
c = condition_new ( t , p , trigger , negate ) ;
2011-09-21 00:44:51 +02:00
if ( ! c )
2013-01-17 02:27:06 +01:00
return log_oom ( ) ;
2010-10-13 02:15:41 +02:00
2014-11-06 13:43:45 +01:00
LIST_PREPEND ( conditions , * list , c ) ;
2010-10-13 02:15:41 +02:00
return 0 ;
}
2014-11-06 13:43:45 +01:00
int config_parse_unit_condition_string (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2011-02-21 22:07:55 +01:00
2012-09-13 22:30:26 +02:00
_cleanup_free_ char * s = NULL ;
2014-11-06 13:43:45 +01:00
Condition * * list = data , * c ;
ConditionType t = ltype ;
bool trigger , negate ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2013-09-17 17:03:46 +02:00
int r ;
2011-02-21 22:07:55 +01:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2014-12-18 18:33:05 +01:00
* list = condition_free_list ( * list ) ;
2013-01-17 02:27:06 +01:00
return 0 ;
}
2019-06-26 16:23:18 +02:00
trigger = * rvalue = = ' | ' ;
2012-08-22 01:51:53 +02:00
if ( trigger )
2019-06-26 16:23:18 +02:00
rvalue + = 1 + strspn ( rvalue + 1 , WHITESPACE ) ;
2011-03-08 03:04:47 +01:00
2019-06-26 16:23:18 +02:00
negate = * rvalue = = ' ! ' ;
2012-08-22 01:51:53 +02:00
if ( negate )
2019-06-26 16:23:18 +02:00
rvalue + = 1 + strspn ( rvalue + 1 , WHITESPACE ) ;
2011-02-21 22:07:55 +01:00
2013-09-17 17:03:46 +02:00
r = unit_full_printf ( u , rvalue , & s ) ;
2014-11-06 13:43:45 +01:00
if ( r < 0 ) {
2019-06-28 10:56:28 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
" Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
2014-11-06 13:43:45 +01:00
return 0 ;
2013-09-17 17:03:46 +02:00
}
2012-09-13 21:34:25 +02:00
2014-11-06 13:43:45 +01:00
c = condition_new ( t , s , trigger , negate ) ;
2012-08-22 01:51:53 +02:00
if ( ! c )
return log_oom ( ) ;
2011-02-21 22:07:55 +01:00
2014-11-06 13:43:45 +01:00
LIST_PREPEND ( conditions , * list , c ) ;
2011-02-21 22:07:55 +01:00
return 0 ;
}
2014-11-06 13:43:45 +01:00
int config_parse_unit_condition_null (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-11-10 22:28:19 +01:00
2014-11-06 13:43:45 +01:00
Condition * * list = data , * c ;
2011-03-08 03:04:47 +01:00
bool trigger , negate ;
2010-11-10 22:28:19 +01:00
int b ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2019-03-04 17:51:54 +01:00
log_syntax ( unit , LOG_WARNING , filename , line , 0 , " %s= is deprecated, please do not use. " , lvalue ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2014-12-18 18:33:05 +01:00
* list = condition_free_list ( * list ) ;
2013-01-17 02:27:06 +01:00
return 0 ;
}
trigger = rvalue [ 0 ] = = ' | ' ;
if ( trigger )
2011-03-08 03:04:47 +01:00
rvalue + + ;
2013-01-17 02:27:06 +01:00
negate = rvalue [ 0 ] = = ' ! ' ;
if ( negate )
2010-11-10 22:28:19 +01:00
rvalue + + ;
2013-01-17 02:27:06 +01:00
b = parse_boolean ( rvalue ) ;
if ( b < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , b , " Failed to parse boolean value in condition, ignoring: %s " , rvalue ) ;
2010-11-10 22:28:19 +01:00
return 0 ;
}
if ( ! b )
negate = ! negate ;
2013-01-17 02:27:06 +01:00
c = condition_new ( CONDITION_NULL , NULL , trigger , negate ) ;
if ( ! c )
return log_oom ( ) ;
2010-11-10 22:28:19 +01:00
2014-11-06 13:43:45 +01:00
LIST_PREPEND ( conditions , * list , c ) ;
2010-11-10 22:28:19 +01:00
return 0 ;
}
2013-09-26 20:14:24 +02:00
int config_parse_unit_requires_mounts_for (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-09-26 20:14:24 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2012-04-29 14:26:07 +02:00
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
2012-04-29 14:26:07 +02:00
Unit * u = userdata ;
2016-10-28 02:15:22 +02:00
int r ;
2012-04-29 14:26:07 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2018-05-20 16:08:29 +02:00
for ( ; ; ) {
2016-12-05 19:40:13 +01:00
_cleanup_free_ char * word = NULL , * resolved = NULL ;
2013-09-26 20:14:24 +02:00
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2016-10-28 02:15:22 +02:00
if ( r = = 0 )
return 0 ;
if ( r = = - ENOMEM )
2013-09-26 20:14:24 +02:00
return log_oom ( ) ;
2016-10-28 02:15:22 +02:00
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
2012-04-29 14:26:07 +02:00
2016-12-05 19:40:13 +01:00
r = unit_full_printf ( u , word , & resolved ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , word ) ;
2016-12-05 19:40:13 +01:00
continue ;
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
continue ;
core: track why unit dependencies came to be
This replaces the dependencies Set* objects by Hashmap* objects, where
the key is the depending Unit, and the value is a bitmask encoding why
the specific dependency was created.
The bitmask contains a number of different, defined bits, that indicate
why dependencies exist, for example whether they are created due to
explicitly configured deps in files, by udev rules or implicitly.
Note that memory usage is not increased by this change, even though we
store more information, as we manage to encode the bit mask inside the
value pointer each Hashmap entry contains.
Why this all? When we know how a dependency came to be, we can update
dependencies correctly when a configuration source changes but others
are left unaltered. Specifically:
1. We can fix UDEV_WANTS dependency generation: so far we kept adding
dependencies configured that way, but if a device lost such a
dependency we couldn't them again as there was no scheme for removing
of dependencies in place.
2. We can implement "pin-pointed" reload of unit files. If we know what
dependencies were created as result of configuration in a unit file,
then we know what to flush out when we want to reload it.
3. It's useful for debugging: "systemd-analyze dump" now shows
this information, helping substantially with understanding how
systemd's dependency tree came to be the way it came to be.
2017-10-25 20:46:01 +02:00
r = unit_require_mounts_for ( u , resolved , UNIT_DEPENDENCY_FILE ) ;
2013-09-26 20:14:24 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to add required mount '%s', ignoring: %m " , resolved ) ;
2013-09-26 20:14:24 +02:00
continue ;
}
}
2012-04-29 14:26:07 +02:00
}
2011-08-20 01:38:10 +02:00
2013-04-16 04:25:58 +02:00
int config_parse_documentation ( const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-04-16 04:25:58 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2012-05-21 15:12:18 +02:00
Unit * u = userdata ;
int r ;
char * * a , * * b ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2015-09-09 23:05:10 +02:00
u - > documentation = strv_free ( u - > documentation ) ;
2013-01-17 02:27:06 +01:00
return 0 ;
}
2013-11-19 16:17:55 +01:00
r = config_parse_unit_strv_printf ( unit , filename , line , section , section_line , lvalue , ltype ,
2013-04-16 04:25:58 +02:00
rvalue , data , userdata ) ;
2012-05-21 15:12:18 +02:00
if ( r < 0 )
return r ;
for ( a = b = u - > documentation ; a & & * a ; a + + ) {
2015-01-19 20:45:27 +01:00
if ( documentation_url_is_valid ( * a ) )
2012-05-21 15:12:18 +02:00
* ( b + + ) = * a ;
else {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid URL, ignoring: %s " , * a ) ;
2012-05-21 15:12:18 +02:00
free ( * a ) ;
}
}
2013-10-12 19:43:07 +02:00
if ( b )
* b = NULL ;
2012-05-21 15:12:18 +02:00
return r ;
}
2017-10-03 10:41:51 +02:00
# if HAVE_SECCOMP
2014-02-12 18:28:21 +01:00
int config_parse_syscall_filter (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2012-07-17 04:17:53 +02:00
ExecContext * c = data ;
2020-05-06 20:29:31 +02:00
_unused_ const Unit * u = userdata ;
2012-08-20 14:33:21 +02:00
bool invert = false ;
2016-10-21 21:50:05 +02:00
const char * p ;
2014-02-12 18:28:21 +01:00
int r ;
2012-07-17 04:17:53 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
2013-01-17 02:27:06 +01:00
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2017-11-11 13:35:49 +01:00
c - > syscall_filter = hashmap_free ( c - > syscall_filter ) ;
2014-02-12 18:28:21 +01:00
c - > syscall_whitelist = false ;
2013-01-17 02:27:06 +01:00
return 0 ;
}
2012-07-17 04:17:53 +02:00
if ( rvalue [ 0 ] = = ' ~ ' ) {
invert = true ;
rvalue + + ;
}
2014-02-12 18:28:21 +01:00
if ( ! c - > syscall_filter ) {
2017-11-11 13:35:49 +01:00
c - > syscall_filter = hashmap_new ( NULL ) ;
2014-02-12 18:28:21 +01:00
if ( ! c - > syscall_filter )
return log_oom ( ) ;
2014-02-12 01:29:54 +01:00
if ( invert )
2014-02-12 18:28:21 +01:00
/* Allow everything but the ones listed */
c - > syscall_whitelist = false ;
2014-02-12 01:29:54 +01:00
else {
2014-02-12 18:28:21 +01:00
/* Allow nothing but the ones listed */
c - > syscall_whitelist = true ;
2012-07-17 04:17:53 +02:00
2014-02-12 18:28:21 +01:00
/* Accept default syscalls if we are on a whitelist */
2019-03-28 12:00:56 +01:00
r = seccomp_parse_syscall_filter (
" @default " , - 1 , c - > syscall_filter ,
2019-04-03 09:17:42 +02:00
SECCOMP_PARSE_PERMISSIVE | SECCOMP_PARSE_WHITELIST ,
unit ,
NULL , 0 ) ;
2016-06-01 11:56:01 +02:00
if ( r < 0 )
return r ;
2014-02-12 01:29:54 +01:00
}
2012-07-17 04:17:53 +02:00
}
2016-10-21 21:50:05 +02:00
p = rvalue ;
for ( ; ; ) {
2017-11-11 13:35:49 +01:00
_cleanup_free_ char * word = NULL , * name = NULL ;
int num ;
2012-07-17 04:17:53 +02:00
2016-10-21 21:50:05 +02:00
r = extract_first_word ( & p , & word , NULL , 0 ) ;
if ( r = = 0 )
2018-05-20 16:08:29 +02:00
return 0 ;
2016-10-21 21:50:05 +02:00
if ( r = = - ENOMEM )
2013-01-17 02:27:06 +01:00
return log_oom ( ) ;
2016-10-21 21:50:05 +02:00
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r , " Invalid syntax, ignoring: %s " , rvalue ) ;
2018-05-20 16:08:29 +02:00
return 0 ;
2016-10-21 21:50:05 +02:00
}
2012-07-17 04:17:53 +02:00
2017-11-11 13:35:49 +01:00
r = parse_syscall_and_errno ( word , & name , & num ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r , " Failed to parse syscall:errno, ignoring: %s " , word ) ;
continue ;
}
2019-04-03 09:17:42 +02:00
r = seccomp_parse_syscall_filter (
2019-03-28 12:09:23 +01:00
name , num , c - > syscall_filter ,
SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
( invert ? SECCOMP_PARSE_INVERT : 0 ) |
( c - > syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0 ) ,
unit , filename , line ) ;
2016-06-01 11:56:01 +02:00
if ( r < 0 )
return r ;
2014-02-12 01:29:54 +01:00
}
2014-02-12 18:28:21 +01:00
}
2014-02-13 00:24:00 +01:00
int config_parse_syscall_archs (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
2014-02-13 01:35:27 +01:00
Set * * archs = data ;
2014-02-13 00:24:00 +01:00
int r ;
if ( isempty ( rvalue ) ) {
2015-09-09 23:12:07 +02:00
* archs = set_free ( * archs ) ;
2014-02-13 00:24:00 +01:00
return 0 ;
}
2014-08-13 01:00:18 +02:00
r = set_ensure_allocated ( archs , NULL ) ;
2014-02-13 00:24:00 +01:00
if ( r < 0 )
return log_oom ( ) ;
2018-05-20 16:08:29 +02:00
for ( ; ; ) {
2016-10-28 02:15:22 +02:00
_cleanup_free_ char * word = NULL ;
2014-02-13 00:24:00 +01:00
uint32_t a ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2016-10-28 02:15:22 +02:00
if ( r = = 0 )
return 0 ;
if ( r = = - ENOMEM )
2014-02-13 00:24:00 +01:00
return log_oom ( ) ;
2016-10-28 02:15:22 +02:00
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
2014-02-13 00:24:00 +01:00
2016-10-28 02:15:22 +02:00
r = seccomp_arch_from_string ( word , & a ) ;
2014-02-13 00:24:00 +01:00
if ( r < 0 ) {
2016-10-28 02:15:22 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
" Failed to parse system call architecture \" %s \" , ignoring: %m " , word ) ;
2014-02-13 00:24:00 +01:00
continue ;
}
2014-02-13 01:35:27 +01:00
r = set_put ( * archs , UINT32_TO_PTR ( a + 1 ) ) ;
2014-02-13 00:24:00 +01:00
if ( r < 0 )
return log_oom ( ) ;
}
}
2014-02-12 18:28:21 +01:00
int config_parse_syscall_errno (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
int e ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets to KILL */
c - > syscall_errno = 0 ;
return 0 ;
2012-07-17 04:17:53 +02:00
}
2017-11-11 13:40:20 +01:00
e = parse_errno ( rvalue ) ;
if ( e < = 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse error number, ignoring: %s " , rvalue ) ;
2014-02-12 18:28:21 +01:00
return 0 ;
}
2012-07-17 04:17:53 +02:00
2014-02-12 18:28:21 +01:00
c - > syscall_errno = e ;
2012-07-17 04:17:53 +02:00
return 0 ;
}
2014-02-25 20:37:03 +01:00
int config_parse_address_families (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
bool invert = false ;
2016-10-28 02:15:22 +02:00
const char * p ;
2014-02-25 20:37:03 +01:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2015-09-09 23:12:07 +02:00
c - > address_families = set_free ( c - > address_families ) ;
2014-02-25 20:37:03 +01:00
c - > address_families_whitelist = false ;
return 0 ;
}
if ( rvalue [ 0 ] = = ' ~ ' ) {
invert = true ;
rvalue + + ;
}
if ( ! c - > address_families ) {
2014-08-13 01:00:18 +02:00
c - > address_families = set_new ( NULL ) ;
2014-02-25 20:37:03 +01:00
if ( ! c - > address_families )
return log_oom ( ) ;
c - > address_families_whitelist = ! invert ;
}
2016-10-28 02:15:22 +02:00
for ( p = rvalue ; ; ) {
_cleanup_free_ char * word = NULL ;
2014-02-25 20:37:03 +01:00
int af ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2016-10-28 02:15:22 +02:00
if ( r = = 0 )
return 0 ;
if ( r = = - ENOMEM )
2014-02-25 20:37:03 +01:00
return log_oom ( ) ;
2016-10-28 02:15:22 +02:00
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
2014-02-25 20:37:03 +01:00
2016-10-28 02:15:22 +02:00
af = af_from_name ( word ) ;
2018-11-28 09:54:04 +01:00
if ( af < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , af ,
2018-05-20 16:08:29 +02:00
" Failed to parse address family, ignoring: %s " , word ) ;
2014-02-25 20:37:03 +01:00
continue ;
}
/* If we previously wanted to forbid an address family and now
2016-10-28 02:15:22 +02:00
* we want to allow it , then just remove it from the list .
2014-02-25 20:37:03 +01:00
*/
if ( ! invert = = c - > address_families_whitelist ) {
r = set_put ( c - > address_families , INT_TO_PTR ( af ) ) ;
if ( r < 0 )
return log_oom ( ) ;
} else
set_remove ( c - > address_families , INT_TO_PTR ( af ) ) ;
}
}
2016-11-02 03:25:19 +01:00
int config_parse_restrict_namespaces (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2018-05-01 03:36:39 +02:00
unsigned long flags ;
2016-11-02 03:25:19 +01:00
bool invert = false ;
int r ;
if ( isempty ( rvalue ) ) {
/* Reset to the default. */
2018-05-01 03:36:39 +02:00
c - > restrict_namespaces = NAMESPACE_FLAGS_INITIAL ;
return 0 ;
}
/* Boolean parameter ignores the previous settings */
r = parse_boolean ( rvalue ) ;
if ( r > 0 ) {
c - > restrict_namespaces = 0 ;
return 0 ;
} else if ( r = = 0 ) {
2016-11-02 03:25:19 +01:00
c - > restrict_namespaces = NAMESPACE_FLAGS_ALL ;
return 0 ;
}
if ( rvalue [ 0 ] = = ' ~ ' ) {
invert = true ;
rvalue + + ;
}
2018-05-01 03:36:39 +02:00
/* Not a boolean argument, in this case it's a list of namespace types. */
r = namespace_flags_from_string ( rvalue , & flags ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse namespace type string, ignoring: %s " , rvalue ) ;
return 0 ;
2016-11-02 03:25:19 +01:00
}
2018-05-01 03:36:39 +02:00
if ( c - > restrict_namespaces = = NAMESPACE_FLAGS_INITIAL )
/* Initial assignment. Just set the value. */
c - > restrict_namespaces = invert ? ( ~ flags ) & NAMESPACE_FLAGS_ALL : flags ;
else
/* Merge the value with the previous one. */
SET_FLAG ( c - > restrict_namespaces , flags , ! invert ) ;
2016-11-02 03:25:19 +01:00
return 0 ;
}
2014-02-12 01:29:54 +01:00
# endif
2012-07-17 04:17:53 +02:00
2013-06-17 21:33:26 +02:00
int config_parse_unit_slice (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-06-17 21:33:26 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-20 16:08:29 +02:00
_cleanup_ ( sd_bus_error_free ) sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-06-17 21:33:26 +02:00
_cleanup_free_ char * k = NULL ;
2019-10-16 16:33:54 +02:00
Unit * u = userdata , * slice ;
2013-06-17 21:33:26 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
2013-09-17 17:03:46 +02:00
r = unit_name_printf ( u , rvalue , & k ) ;
2015-08-28 17:36:39 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , rvalue ) ;
2015-08-28 17:36:39 +02:00
return 0 ;
2013-09-17 17:03:46 +02:00
}
2013-06-17 21:33:26 +02:00
2018-05-20 16:08:29 +02:00
r = manager_load_unit ( u - > manager , k , NULL , & error , & slice ) ;
2013-06-17 21:33:26 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to load slice unit %s, ignoring: %s " , k , bus_error_message ( & error , r ) ) ;
2013-06-17 21:33:26 +02:00
return 0 ;
}
2015-08-28 17:36:39 +02:00
r = unit_set_slice ( u , slice ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to assign slice %s to unit %s, ignoring: %m " , slice - > id , u - > id ) ;
2013-06-17 21:33:26 +02:00
return 0 ;
}
return 0 ;
}
2014-04-25 13:27:25 +02:00
int config_parse_cpu_quota (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
CGroupContext * c = data ;
2016-06-08 19:25:38 +02:00
int r ;
2014-04-25 13:27:25 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
2014-07-29 12:23:31 +02:00
c - > cpu_quota_per_sec_usec = USEC_INFINITY ;
2014-04-25 13:27:25 +02:00
return 0 ;
}
2018-07-02 18:52:42 +02:00
r = parse_permille_unbounded ( rvalue ) ;
2016-06-08 19:25:38 +02:00
if ( r < = 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid CPU quota '%s', ignoring. " , rvalue ) ;
2014-05-22 04:53:12 +02:00
return 0 ;
2014-04-25 13:27:25 +02:00
}
2018-07-02 18:52:42 +02:00
c - > cpu_quota_per_sec_usec = ( ( usec_t ) r * USEC_PER_SEC ) / 1000U ;
2014-04-25 13:27:25 +02:00
return 0 ;
}
2019-11-24 14:14:43 +01:00
int config_parse_allowed_cpus (
2019-07-29 17:50:05 +02:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
CGroupContext * c = data ;
( void ) parse_cpu_set_extend ( rvalue , & c - > cpuset_cpus , true , unit , filename , line , lvalue ) ;
return 0 ;
}
2019-11-24 14:14:43 +01:00
int config_parse_allowed_mems (
2019-07-29 17:50:05 +02:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
CGroupContext * c = data ;
( void ) parse_cpu_set_extend ( rvalue , & c - > cpuset_mems , true , unit , filename , line , lvalue ) ;
return 0 ;
}
2013-06-27 04:14:27 +02:00
int config_parse_memory_limit (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-06-27 04:14:27 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
CGroupContext * c = data ;
2016-05-27 18:10:18 +02:00
uint64_t bytes = CGROUP_LIMIT_MAX ;
2013-06-27 04:14:27 +02:00
int r ;
2016-06-03 17:49:05 +02:00
if ( ! isempty ( rvalue ) & & ! streq ( rvalue , " infinity " ) ) {
2016-06-08 19:36:09 +02:00
2018-07-02 18:52:42 +02:00
r = parse_permille ( rvalue ) ;
2016-06-08 19:36:09 +02:00
if ( r < 0 ) {
r = parse_size ( rvalue , 1024 , & bytes ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid memory limit '%s', ignoring: %m " , rvalue ) ;
2016-06-08 19:36:09 +02:00
return 0 ;
}
} else
2018-07-02 18:52:42 +02:00
bytes = physical_memory_scale ( r , 1000U ) ;
2016-06-08 19:36:09 +02:00
2018-03-09 11:34:50 +01:00
if ( bytes > = UINT64_MAX | |
2019-05-03 14:32:41 +02:00
( bytes < = 0 & & ! STR_IN_SET ( lvalue , " MemorySwapMax " , " MemoryLow " , " MemoryMin " , " DefaultMemoryLow " , " DefaultMemoryMin " ) ) ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Memory limit '%s' out of range, ignoring. " , rvalue ) ;
2016-05-27 18:10:18 +02:00
return 0 ;
}
2013-06-27 04:14:27 +02:00
}
cgroup: Implement default propagation of MemoryLow with DefaultMemoryLow
In cgroup v2 we have protection tunables -- currently MemoryLow and
MemoryMin (there will be more in future for other resources, too). The
design of these protection tunables requires not only intermediate
cgroups to propagate protections, but also the units at the leaf of that
resource's operation to accept it (by setting MemoryLow or MemoryMin).
This makes sense from an low-level API design perspective, but it's a
good idea to also have a higher-level abstraction that can, by default,
propagate these resources to children recursively. In this patch, this
happens by having descendants set memory.low to N if their ancestor has
DefaultMemoryLow=N -- assuming they don't set a separate MemoryLow
value.
Any affected unit can opt out of this propagation by manually setting
`MemoryLow` to some value in its unit configuration. A unit can also
stop further propagation by setting `DefaultMemoryLow=` with no
argument. This removes further propagation in the subtree, but has no
effect on the unit itself (for that, use `MemoryLow=0`).
Our use case in production is simplifying the configuration of machines
which heavily rely on memory protection tunables, but currently require
tweaking a huge number of unit files to make that a reality. This
directive makes that significantly less fragile, and decreases the risk
of misconfiguration.
After this patch is merged, I will implement DefaultMemoryMin= using the
same principles.
2019-03-28 13:50:50 +01:00
if ( streq ( lvalue , " DefaultMemoryLow " ) ) {
c - > default_memory_low_set = true ;
if ( isempty ( rvalue ) )
c - > default_memory_low = CGROUP_LIMIT_MIN ;
else
c - > default_memory_low = bytes ;
2019-04-16 19:44:05 +02:00
} else if ( streq ( lvalue , " DefaultMemoryMin " ) ) {
c - > default_memory_min_set = true ;
if ( isempty ( rvalue ) )
c - > default_memory_min = CGROUP_LIMIT_MIN ;
else
c - > default_memory_min = bytes ;
} else if ( streq ( lvalue , " MemoryMin " ) ) {
2018-06-09 02:33:14 +02:00
c - > memory_min = bytes ;
2019-04-16 19:44:05 +02:00
c - > memory_min_set = true ;
} else if ( streq ( lvalue , " MemoryLow " ) ) {
2016-05-27 18:10:18 +02:00
c - > memory_low = bytes ;
cgroup: Implement default propagation of MemoryLow with DefaultMemoryLow
In cgroup v2 we have protection tunables -- currently MemoryLow and
MemoryMin (there will be more in future for other resources, too). The
design of these protection tunables requires not only intermediate
cgroups to propagate protections, but also the units at the leaf of that
resource's operation to accept it (by setting MemoryLow or MemoryMin).
This makes sense from an low-level API design perspective, but it's a
good idea to also have a higher-level abstraction that can, by default,
propagate these resources to children recursively. In this patch, this
happens by having descendants set memory.low to N if their ancestor has
DefaultMemoryLow=N -- assuming they don't set a separate MemoryLow
value.
Any affected unit can opt out of this propagation by manually setting
`MemoryLow` to some value in its unit configuration. A unit can also
stop further propagation by setting `DefaultMemoryLow=` with no
argument. This removes further propagation in the subtree, but has no
effect on the unit itself (for that, use `MemoryLow=0`).
Our use case in production is simplifying the configuration of machines
which heavily rely on memory protection tunables, but currently require
tweaking a huge number of unit files to make that a reality. This
directive makes that significantly less fragile, and decreases the risk
of misconfiguration.
After this patch is merged, I will implement DefaultMemoryMin= using the
same principles.
2019-03-28 13:50:50 +01:00
c - > memory_low_set = true ;
} else if ( streq ( lvalue , " MemoryHigh " ) )
2016-05-27 18:10:18 +02:00
c - > memory_high = bytes ;
else if ( streq ( lvalue , " MemoryMax " ) )
c - > memory_max = bytes ;
2016-07-04 09:03:54 +02:00
else if ( streq ( lvalue , " MemorySwapMax " ) )
c - > memory_swap_max = bytes ;
else if ( streq ( lvalue , " MemoryLimit " ) )
2016-05-27 18:10:18 +02:00
c - > memory_limit = bytes ;
2016-07-04 09:03:54 +02:00
else
return - EINVAL ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
2015-09-10 12:32:16 +02:00
int config_parse_tasks_max (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2019-11-05 13:50:28 +01:00
TasksMax * tasks_max = data ;
uint64_t v ;
2015-09-10 12:32:16 +02:00
int r ;
2016-08-19 04:57:53 +02:00
if ( isempty ( rvalue ) ) {
2019-11-05 13:50:28 +01:00
* tasks_max = u ? u - > manager - > default_tasks_max : TASKS_MAX_UNSET ;
2016-08-19 04:57:53 +02:00
return 0 ;
}
if ( streq ( rvalue , " infinity " ) ) {
2019-11-05 13:50:28 +01:00
* tasks_max = TASKS_MAX_UNSET ;
2015-09-10 12:32:16 +02:00
return 0 ;
}
2018-07-02 18:52:42 +02:00
r = parse_permille ( rvalue ) ;
2019-11-05 13:50:28 +01:00
if ( r > = 0 )
* tasks_max = ( TasksMax ) { r , 1000U } ; /* r‰ */
else {
2016-08-19 04:57:53 +02:00
r = safe_atou64 ( rvalue , & v ) ;
2016-07-19 15:58:49 +02:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid maximum tasks value '%s', ignoring: %m " , rvalue ) ;
2016-07-19 15:58:49 +02:00
return 0 ;
}
2019-11-05 13:50:28 +01:00
if ( v < = 0 | | v > = UINT64_MAX ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Maximum tasks value '%s' out of range, ignoring. " , rvalue ) ;
return 0 ;
}
* tasks_max = ( TasksMax ) { v } ;
2015-09-10 12:32:16 +02:00
}
return 0 ;
}
2017-11-09 15:29:34 +01:00
int config_parse_delegate (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
CGroupContext * c = data ;
2018-04-18 20:06:56 +02:00
UnitType t ;
2017-11-09 15:29:34 +01:00
int r ;
2018-04-18 20:06:56 +02:00
t = unit_name_to_type ( unit ) ;
assert ( t ! = _UNIT_TYPE_INVALID ) ;
if ( ! unit_vtable [ t ] - > can_delegate ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Delegate= setting not supported for this unit type, ignoring. " ) ;
return 0 ;
}
2017-11-09 15:29:34 +01:00
/* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
* off for all . Or it takes a list of controller names , in which case we add the specified controllers to the
* mask to delegate . */
2017-11-17 10:04:25 +01:00
if ( isempty ( rvalue ) ) {
2018-04-26 15:40:45 +02:00
/* An empty string resets controllers and set Delegate=yes. */
c - > delegate = true ;
2017-11-17 10:04:25 +01:00
c - > delegate_controllers = 0 ;
return 0 ;
}
2017-11-09 15:29:34 +01:00
r = parse_boolean ( rvalue ) ;
if ( r < 0 ) {
const char * p = rvalue ;
CGroupMask mask = 0 ;
for ( ; ; ) {
_cleanup_free_ char * word = NULL ;
CGroupController cc ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2017-11-09 15:29:34 +01:00
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid syntax, ignoring: %s " , rvalue ) ;
2018-04-18 19:50:07 +02:00
return 0 ;
2017-11-09 15:29:34 +01:00
}
cc = cgroup_controller_from_string ( word ) ;
if ( cc < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid controller name '%s', ignoring " , word ) ;
2017-11-09 15:29:34 +01:00
continue ;
}
mask | = CGROUP_CONTROLLER_TO_MASK ( cc ) ;
}
c - > delegate = true ;
c - > delegate_controllers | = mask ;
} else if ( r > 0 ) {
c - > delegate = true ;
c - > delegate_controllers = _CGROUP_MASK_ALL ;
} else {
c - > delegate = false ;
c - > delegate_controllers = 0 ;
}
return 0 ;
}
2013-06-27 04:14:27 +02:00
int config_parse_device_allow (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-06-27 04:14:27 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-19 16:59:02 +02:00
_cleanup_free_ char * path = NULL , * resolved = NULL ;
2013-06-27 04:14:27 +02:00
CGroupContext * c = data ;
2018-05-19 16:59:02 +02:00
const char * p = rvalue ;
2016-04-12 18:00:19 +02:00
int r ;
2013-06-27 04:14:27 +02:00
if ( isempty ( rvalue ) ) {
while ( c - > device_allow )
cgroup_context_free_device_allow ( c , c - > device_allow ) ;
return 0 ;
}
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & path , NULL , EXTRACT_UNQUOTE ) ;
2018-05-19 16:59:02 +02:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
2017-12-02 01:49:52 +01:00
if ( r < 0 ) {
2016-04-12 18:00:19 +02:00
log_syntax ( unit , LOG_WARNING , filename , line , r ,
2018-05-19 16:59:02 +02:00
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( r = = 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Failed to extract device path and rights from '%s', ignoring. " , rvalue ) ;
2018-03-13 12:25:06 +01:00
return 0 ;
2016-04-12 18:00:19 +02:00
}
2018-05-19 16:59:02 +02:00
r = unit_full_printf ( userdata , path , & resolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Failed to resolve unit specifiers in '%s', ignoring: %m " , path ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
2018-11-23 16:30:23 +01:00
if ( ! STARTSWITH_SET ( resolved , " block- " , " char- " ) ) {
2018-06-03 16:59:02 +02:00
2018-06-11 12:22:58 +02:00
r = path_simplify_and_warn ( resolved , 0 , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
if ( ! valid_device_node_path ( resolved ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid device node path '%s', ignoring. " , resolved ) ;
return 0 ;
}
2018-05-19 16:59:02 +02:00
}
2013-06-27 04:14:27 +02:00
2018-05-19 16:59:02 +02:00
if ( ! isempty ( p ) & & ! in_charset ( p , " rwm " ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid device rights '%s', ignoring. " , p ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
2018-08-06 06:42:14 +02:00
return cgroup_add_device_allow ( c , resolved , p ) ;
2013-06-27 04:14:27 +02:00
}
2016-05-05 22:42:55 +02:00
int config_parse_io_device_weight (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-19 16:59:02 +02:00
_cleanup_free_ char * path = NULL , * resolved = NULL ;
2016-05-05 22:42:55 +02:00
CGroupIODeviceWeight * w ;
CGroupContext * c = data ;
2018-05-19 16:59:02 +02:00
const char * p = rvalue ;
2016-05-05 22:42:55 +02:00
uint64_t u ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
while ( c - > io_device_weights )
cgroup_context_free_io_device_weight ( c , c - > io_device_weights ) ;
return 0 ;
}
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & path , NULL , EXTRACT_UNQUOTE ) ;
2018-05-19 16:59:02 +02:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( r = = 0 | | isempty ( p ) ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Failed to extract device path and weight from '%s', ignoring. " , rvalue ) ;
2016-05-05 22:42:55 +02:00
return 0 ;
}
2018-05-19 16:59:02 +02:00
r = unit_full_printf ( userdata , path , & resolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Failed to resolve unit specifiers in '%s', ignoring: %m " , path ) ;
return 0 ;
}
2016-05-05 22:42:55 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , 0 , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
2018-05-19 16:59:02 +02:00
r = cg_weight_parse ( p , & u ) ;
2016-05-05 22:42:55 +02:00
if ( r < 0 ) {
2018-05-19 16:59:02 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " IO weight '%s' invalid, ignoring: %m " , p ) ;
2016-05-05 22:42:55 +02:00
return 0 ;
}
assert ( u ! = CGROUP_WEIGHT_INVALID ) ;
w = new0 ( CGroupIODeviceWeight , 1 ) ;
if ( ! w )
return log_oom ( ) ;
2018-05-19 16:59:02 +02:00
w - > path = TAKE_PTR ( resolved ) ;
2016-05-05 22:42:55 +02:00
w - > weight = u ;
LIST_PREPEND ( device_weights , c - > io_device_weights , w ) ;
return 0 ;
}
2018-06-13 23:16:35 +02:00
int config_parse_io_device_latency (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * path = NULL , * resolved = NULL ;
CGroupIODeviceLatency * l ;
CGroupContext * c = data ;
const char * p = rvalue ;
usec_t usec ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
while ( c - > io_device_latencies )
cgroup_context_free_io_device_latency ( c , c - > io_device_latencies ) ;
return 0 ;
}
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & path , NULL , EXTRACT_UNQUOTE ) ;
2018-06-13 23:16:35 +02:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( r = = 0 | | isempty ( p ) ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Failed to extract device path and latency from '%s', ignoring. " , rvalue ) ;
return 0 ;
}
r = unit_full_printf ( userdata , path , & resolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Failed to resolve unit specifiers in '%s', ignoring: %m " , path ) ;
return 0 ;
}
r = path_simplify_and_warn ( resolved , 0 , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
if ( parse_sec ( p , & usec ) < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse timer value, ignoring: %s " , p ) ;
return 0 ;
}
l = new0 ( CGroupIODeviceLatency , 1 ) ;
if ( ! l )
return log_oom ( ) ;
l - > path = TAKE_PTR ( resolved ) ;
l - > target_usec = usec ;
LIST_PREPEND ( device_latencies , c - > io_device_latencies , l ) ;
return 0 ;
}
2016-05-05 22:42:55 +02:00
int config_parse_io_limit (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-19 16:59:02 +02:00
_cleanup_free_ char * path = NULL , * resolved = NULL ;
2016-05-05 22:42:55 +02:00
CGroupIODeviceLimit * l = NULL , * t ;
CGroupContext * c = data ;
2016-05-18 22:50:56 +02:00
CGroupIOLimitType type ;
2018-05-19 16:59:02 +02:00
const char * p = rvalue ;
2016-05-05 22:42:55 +02:00
uint64_t num ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2016-05-18 22:50:56 +02:00
type = cgroup_io_limit_type_from_string ( lvalue ) ;
assert ( type > = 0 ) ;
2016-05-05 22:42:55 +02:00
if ( isempty ( rvalue ) ) {
LIST_FOREACH ( device_limits , l , c - > io_device_limits )
2016-05-18 22:50:56 +02:00
l - > limits [ type ] = cgroup_io_limit_defaults [ type ] ;
2016-05-05 22:42:55 +02:00
return 0 ;
}
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & path , NULL , EXTRACT_UNQUOTE ) ;
2018-05-19 16:59:02 +02:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( r = = 0 | | isempty ( p ) ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Failed to extract device node and bandwidth from '%s', ignoring. " , rvalue ) ;
2016-05-05 22:42:55 +02:00
return 0 ;
}
2018-05-19 16:59:02 +02:00
r = unit_full_printf ( userdata , path , & resolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Failed to resolve unit specifiers in '%s', ignoring: %m " , path ) ;
return 0 ;
}
2016-05-05 22:42:55 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , 0 , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
2018-06-11 12:19:01 +02:00
if ( streq ( " infinity " , p ) )
2016-05-05 22:42:55 +02:00
num = CGROUP_LIMIT_MAX ;
2018-06-11 12:19:01 +02:00
else {
2018-05-19 16:59:02 +02:00
r = parse_size ( p , 1000 , & num ) ;
2016-05-05 22:42:55 +02:00
if ( r < 0 | | num < = 0 ) {
2018-05-19 16:59:02 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid IO limit '%s', ignoring. " , p ) ;
2016-05-05 22:42:55 +02:00
return 0 ;
}
}
LIST_FOREACH ( device_limits , t , c - > io_device_limits ) {
2018-05-19 16:59:02 +02:00
if ( path_equal ( resolved , t - > path ) ) {
2016-05-05 22:42:55 +02:00
l = t ;
break ;
}
}
if ( ! l ) {
2016-05-18 22:50:56 +02:00
CGroupIOLimitType ttype ;
2016-05-05 22:42:55 +02:00
l = new0 ( CGroupIODeviceLimit , 1 ) ;
if ( ! l )
return log_oom ( ) ;
2018-05-19 16:59:02 +02:00
l - > path = TAKE_PTR ( resolved ) ;
2016-05-18 22:50:56 +02:00
for ( ttype = 0 ; ttype < _CGROUP_IO_LIMIT_TYPE_MAX ; ttype + + )
l - > limits [ ttype ] = cgroup_io_limit_defaults [ ttype ] ;
2016-05-05 22:42:55 +02:00
LIST_PREPEND ( device_limits , c - > io_device_limits , l ) ;
}
2016-05-18 22:50:56 +02:00
l - > limits [ type ] = num ;
2016-05-05 22:42:55 +02:00
return 0 ;
}
2013-07-11 20:40:18 +02:00
int config_parse_blockio_device_weight (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-07-11 20:40:18 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-19 16:59:02 +02:00
_cleanup_free_ char * path = NULL , * resolved = NULL ;
2013-07-11 20:40:18 +02:00
CGroupBlockIODeviceWeight * w ;
2013-06-27 04:14:27 +02:00
CGroupContext * c = data ;
2018-05-19 16:59:02 +02:00
const char * p = rvalue ;
2015-09-11 16:48:24 +02:00
uint64_t u ;
2013-06-27 04:14:27 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
if ( isempty ( rvalue ) ) {
while ( c - > blockio_device_weights )
cgroup_context_free_blockio_device_weight ( c , c - > blockio_device_weights ) ;
return 0 ;
}
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & path , NULL , EXTRACT_UNQUOTE ) ;
2018-05-19 16:59:02 +02:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( r = = 0 | | isempty ( p ) ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Failed to extract device node and weight from '%s', ignoring. " , rvalue ) ;
2013-07-11 20:40:18 +02:00
return 0 ;
}
2013-06-27 04:14:27 +02:00
2018-05-19 16:59:02 +02:00
r = unit_full_printf ( userdata , path , & resolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Failed to resolve unit specifiers in '%s', ignoring: %m " , path ) ;
return 0 ;
}
2013-06-27 04:14:27 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , 0 , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
2018-05-19 16:59:02 +02:00
r = cg_blkio_weight_parse ( p , & u ) ;
2015-09-11 16:48:24 +02:00
if ( r < 0 ) {
2018-05-19 16:59:02 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid block IO weight '%s', ignoring: %m " , p ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
2015-09-11 16:48:24 +02:00
assert ( u ! = CGROUP_BLKIO_WEIGHT_INVALID ) ;
2013-07-11 20:40:18 +02:00
w = new0 ( CGroupBlockIODeviceWeight , 1 ) ;
if ( ! w )
return log_oom ( ) ;
2013-06-27 04:14:27 +02:00
2018-05-19 16:59:02 +02:00
w - > path = TAKE_PTR ( resolved ) ;
2015-09-11 16:48:24 +02:00
w - > weight = u ;
2013-06-27 04:14:27 +02:00
2013-10-14 06:10:14 +02:00
LIST_PREPEND ( device_weights , c - > blockio_device_weights , w ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
int config_parse_blockio_bandwidth (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
2013-11-19 16:17:55 +01:00
unsigned section_line ,
2013-06-27 04:14:27 +02:00
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2018-05-19 16:59:02 +02:00
_cleanup_free_ char * path = NULL , * resolved = NULL ;
2016-05-18 22:51:46 +02:00
CGroupBlockIODeviceBandwidth * b = NULL , * t ;
2013-06-27 04:14:27 +02:00
CGroupContext * c = data ;
2018-05-19 16:59:02 +02:00
const char * p = rvalue ;
2015-09-10 18:16:18 +02:00
uint64_t bytes ;
2013-08-30 04:56:00 +02:00
bool read ;
2013-06-27 04:14:27 +02:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2013-08-30 04:56:00 +02:00
read = streq ( " BlockIOReadBandwidth " , lvalue ) ;
2013-06-27 04:14:27 +02:00
if ( isempty ( rvalue ) ) {
2016-05-18 22:51:46 +02:00
LIST_FOREACH ( device_bandwidths , b , c - > blockio_device_bandwidths ) {
b - > rbps = CGROUP_LIMIT_MAX ;
b - > wbps = CGROUP_LIMIT_MAX ;
}
2013-06-27 04:14:27 +02:00
return 0 ;
}
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & path , NULL , EXTRACT_UNQUOTE ) ;
2018-05-19 16:59:02 +02:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( r = = 0 | | isempty ( p ) ) {
log_syntax ( unit , LOG_WARNING , filename , line , 0 ,
" Failed to extract device node and bandwidth from '%s', ignoring. " , rvalue ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
2018-05-19 16:59:02 +02:00
r = unit_full_printf ( userdata , path , & resolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Failed to resolve unit specifiers in '%s', ignoring: %m " , path ) ;
return 0 ;
}
2013-06-27 04:14:27 +02:00
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , 0 , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
2018-05-19 16:59:02 +02:00
r = parse_size ( p , 1000 , & bytes ) ;
2013-06-27 04:14:27 +02:00
if ( r < 0 | | bytes < = 0 ) {
2018-05-19 16:59:02 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid Block IO Bandwidth '%s', ignoring. " , p ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
2016-05-18 22:51:46 +02:00
LIST_FOREACH ( device_bandwidths , t , c - > blockio_device_bandwidths ) {
2018-05-19 16:59:02 +02:00
if ( path_equal ( resolved , t - > path ) ) {
2016-05-18 22:51:46 +02:00
b = t ;
break ;
}
}
2013-06-27 04:14:27 +02:00
2016-05-18 22:51:46 +02:00
if ( ! t ) {
b = new0 ( CGroupBlockIODeviceBandwidth , 1 ) ;
if ( ! b )
return log_oom ( ) ;
2018-05-19 16:59:02 +02:00
b - > path = TAKE_PTR ( resolved ) ;
2016-05-18 22:51:46 +02:00
b - > rbps = CGROUP_LIMIT_MAX ;
b - > wbps = CGROUP_LIMIT_MAX ;
LIST_PREPEND ( device_bandwidths , c - > blockio_device_bandwidths , b ) ;
}
2013-06-27 04:14:27 +02:00
2016-05-18 22:51:46 +02:00
if ( read )
b - > rbps = bytes ;
else
b - > wbps = bytes ;
2013-06-27 04:14:27 +02:00
return 0 ;
}
2013-11-26 01:39:53 +01:00
int config_parse_job_mode_isolate (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
JobMode * m = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
r = parse_boolean ( rvalue ) ;
if ( r < 0 ) {
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse boolean, ignoring: %s " , rvalue ) ;
2013-11-26 01:39:53 +01:00
return 0 ;
}
2017-12-29 09:00:40 +01:00
log_notice ( " %s is deprecated. Please use OnFailureJobMode= instead " , lvalue ) ;
2013-11-26 01:39:53 +01:00
* m = r ? JOB_ISOLATE : JOB_REPLACE ;
return 0 ;
}
core: add {State,Cache,Log,Configuration}Directory= (#6384)
This introduces {State,Cache,Log,Configuration}Directory= those are
similar to RuntimeDirectory=. They create the directories under
/var/lib, /var/cache/, /var/log, or /etc, respectively, with the mode
specified in {State,Cache,Log,Configuration}DirectoryMode=.
This also fixes #6391.
2017-07-18 14:34:52 +02:00
int config_parse_exec_directories (
2014-03-03 17:14:07 +01:00
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2014-07-30 04:01:36 +02:00
char * * * rt = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2016-10-28 02:15:22 +02:00
const char * p ;
2014-03-03 17:14:07 +01:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2015-09-09 23:05:10 +02:00
* rt = strv_free ( * rt ) ;
2014-03-03 17:14:07 +01:00
return 0 ;
}
2016-10-28 02:15:22 +02:00
for ( p = rvalue ; ; ) {
_cleanup_free_ char * word = NULL , * k = NULL ;
2014-03-03 17:14:07 +01:00
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2016-10-28 02:15:22 +02:00
if ( r = = - ENOMEM )
2014-03-03 17:14:07 +01:00
return log_oom ( ) ;
2016-10-28 02:15:22 +02:00
if ( r < 0 ) {
log_syntax ( unit , LOG_WARNING , filename , line , r ,
" Invalid syntax, ignoring: %s " , rvalue ) ;
return 0 ;
}
2017-10-02 10:50:07 +02:00
if ( r = = 0 )
return 0 ;
2014-03-03 17:14:07 +01:00
2016-12-05 19:25:44 +01:00
r = unit_full_printf ( u , word , & k ) ;
2015-09-17 22:54:13 +02:00
if ( r < 0 ) {
2016-10-28 02:15:22 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolve unit specifiers in \" %s \" , ignoring: %m " , word ) ;
2015-09-17 22:54:13 +02:00
continue ;
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( k , PATH_CHECK_RELATIVE , unit , filename , line , lvalue ) ;
if ( r < 0 )
2018-05-17 04:25:12 +02:00
continue ;
if ( path_startswith ( k , " private " ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
2019-01-23 22:33:29 +01:00
" %s= path can't be 'private', ignoring assignment: %s " , lvalue , word ) ;
2014-03-03 17:14:07 +01:00
continue ;
}
2016-10-28 02:15:22 +02:00
r = strv_push ( rt , k ) ;
2014-03-03 17:14:07 +01:00
if ( r < 0 )
return log_oom ( ) ;
2016-10-28 02:15:22 +02:00
k = NULL ;
2014-03-03 17:14:07 +01:00
}
}
2014-03-03 21:26:53 +01:00
int config_parse_set_status (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
size_t l ;
2014-07-30 04:01:36 +02:00
const char * word , * state ;
2014-03-03 21:26:53 +01:00
int r ;
ExitStatusSet * status_set = data ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2014-07-03 15:36:50 +02:00
/* Empty assignment resets the list */
2014-03-03 21:26:53 +01:00
if ( isempty ( rvalue ) ) {
2014-07-03 15:36:50 +02:00
exit_status_set_free ( status_set ) ;
2014-03-03 21:26:53 +01:00
return 0 ;
}
2014-07-30 04:01:36 +02:00
FOREACH_WORD ( word , l , rvalue , state ) {
2014-03-03 21:26:53 +01:00
_cleanup_free_ char * temp ;
shared/exit-status: use Bitmap instead of Sets
I opted to embed the Bitmap structure directly in the ExitStatusSet.
This means that memory usage is a bit higher for units which don't define
this setting:
Service changes:
/* size: 2720, cachelines: 43, members: 73 */
/* sum members: 2680, holes: 9, sum holes: 39 */
/* sum bitfield members: 7 bits, bit holes: 1, sum bit holes: 1 bits */
/* last cacheline: 32 bytes */
/* size: 2816, cachelines: 44, members: 73 */
/* sum members: 2776, holes: 9, sum holes: 39 */
/* sum bitfield members: 7 bits, bit holes: 1, sum bit holes: 1 bits */
But this way the code is simpler and we do less pointer chasing.
2019-07-28 11:14:46 +02:00
Bitmap * bitmap ;
2014-03-03 21:26:53 +01:00
2014-07-30 04:01:36 +02:00
temp = strndup ( word , l ) ;
2014-03-03 21:26:53 +01:00
if ( ! temp )
return log_oom ( ) ;
2019-07-28 12:37:31 +02:00
/* We need to call exit_status_from_string() first, because we want
* to parse numbers as exit statuses , not signals . */
2014-03-03 21:26:53 +01:00
2019-07-28 12:37:31 +02:00
r = exit_status_from_string ( temp ) ;
if ( r > = 0 ) {
assert ( r > = 0 & & r < 256 ) ;
bitmap = & status_set - > status ;
2014-03-03 21:26:53 +01:00
} else {
2019-07-28 12:37:31 +02:00
r = signal_from_string ( temp ) ;
if ( r < = 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 ,
" Failed to parse value, ignoring: %s " , word ) ;
2014-07-31 09:38:05 +02:00
continue ;
2014-03-03 21:26:53 +01:00
}
2019-07-28 12:37:31 +02:00
bitmap = & status_set - > signal ;
2014-03-03 21:26:53 +01:00
}
2014-07-31 09:38:05 +02:00
2019-07-28 12:37:31 +02:00
r = bitmap_set ( bitmap , r ) ;
2018-05-20 16:08:29 +02:00
if ( r < 0 )
2019-07-28 12:37:31 +02:00
return log_error_errno ( r , " Failed to set signal or status %s: %m " , word ) ;
2014-03-03 21:26:53 +01:00
}
2014-07-31 09:28:37 +02:00
if ( ! isempty ( state ) )
2015-09-30 18:22:42 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Trailing garbage, ignoring. " ) ;
2014-03-03 21:26:53 +01:00
return 0 ;
}
2014-03-03 21:40:55 +01:00
int config_parse_namespace_path_strv (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2014-07-30 04:01:36 +02:00
char * * * sv = data ;
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
2014-03-03 21:40:55 +01:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
2015-09-09 23:05:10 +02:00
* sv = strv_free ( * sv ) ;
2014-03-03 21:40:55 +01:00
return 0 ;
}
2015-10-22 22:28:28 +02:00
for ( ; ; ) {
2016-12-05 19:42:25 +01:00
_cleanup_free_ char * word = NULL , * resolved = NULL , * joined = NULL ;
2016-12-23 01:16:43 +01:00
const char * w ;
bool ignore_enoent = false , shall_prefix = false ;
2014-03-03 21:40:55 +01:00
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2015-11-03 22:32:34 +01:00
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
2015-10-22 22:28:28 +02:00
if ( r < 0 ) {
2016-12-05 19:42:25 +01:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to extract first word, ignoring: %s " , rvalue ) ;
2015-10-22 22:28:28 +02:00
return 0 ;
}
2014-03-03 21:40:55 +01:00
2016-12-23 01:16:43 +01:00
w = word ;
if ( startswith ( w , " - " ) ) {
ignore_enoent = true ;
w + + ;
}
if ( startswith ( w , " + " ) ) {
shall_prefix = true ;
w + + ;
}
2016-12-05 19:42:25 +01:00
2016-12-23 01:16:43 +01:00
r = unit_full_printf ( u , w , & resolved ) ;
2016-12-05 19:42:25 +01:00
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s: %m " , w ) ;
2014-03-03 21:40:55 +01:00
continue ;
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
2016-12-05 19:42:25 +01:00
continue ;
2014-03-03 21:40:55 +01:00
2016-12-23 01:16:43 +01:00
joined = strjoin ( ignore_enoent ? " - " : " " ,
shall_prefix ? " + " : " " ,
resolved ) ;
2016-12-05 19:42:25 +01:00
r = strv_push ( sv , joined ) ;
2014-03-03 21:40:55 +01:00
if ( r < 0 )
return log_oom ( ) ;
2016-12-05 19:42:25 +01:00
joined = NULL ;
2014-03-03 21:40:55 +01:00
}
return 0 ;
}
2018-02-21 01:17:52 +01:00
int config_parse_temporary_filesystems (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2018-02-21 01:17:52 +01:00
ExecContext * c = data ;
2018-05-20 16:08:29 +02:00
const char * p = rvalue ;
2018-02-21 01:17:52 +01:00
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
temporary_filesystem_free_many ( c - > temporary_filesystems , c - > n_temporary_filesystems ) ;
c - > temporary_filesystems = NULL ;
c - > n_temporary_filesystems = 0 ;
return 0 ;
}
for ( ; ; ) {
_cleanup_free_ char * word = NULL , * path = NULL , * resolved = NULL ;
const char * w ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & word , NULL , EXTRACT_UNQUOTE ) ;
2018-02-21 01:17:52 +01:00
if ( r = = 0 )
2018-05-20 16:08:29 +02:00
return 0 ;
2018-02-21 01:17:52 +01:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to extract first word, ignoring: %s " , rvalue ) ;
return 0 ;
}
w = word ;
r = extract_first_word ( & w , & path , " : " , EXTRACT_DONT_COALESCE_SEPARATORS ) ;
2018-05-20 16:08:29 +02:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to extract first word, ignoring: %s " , word ) ;
continue ;
}
if ( r = = 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid syntax, ignoring: %s " , word ) ;
continue ;
}
2018-02-21 01:17:52 +01:00
r = unit_full_printf ( u , path , & resolved ) ;
if ( r < 0 ) {
2018-05-20 16:08:29 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in %s, ignoring: %m " , path ) ;
2018-02-21 01:17:52 +01:00
continue ;
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( resolved , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
2018-02-21 01:17:52 +01:00
continue ;
2018-06-23 01:17:07 +02:00
r = temporary_filesystem_add ( & c - > temporary_filesystems , & c - > n_temporary_filesystems , resolved , w ) ;
2018-06-22 23:39:19 +02:00
if ( r < 0 )
2018-02-21 01:17:52 +01:00
return log_oom ( ) ;
}
}
2016-11-23 22:21:40 +01:00
int config_parse_bind_paths (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2016-11-23 22:21:40 +01:00
const char * p ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
/* Empty assignment resets the list */
bind_mount_free_many ( c - > bind_mounts , c - > n_bind_mounts ) ;
c - > bind_mounts = NULL ;
c - > n_bind_mounts = 0 ;
return 0 ;
}
p = rvalue ;
for ( ; ; ) {
_cleanup_free_ char * source = NULL , * destination = NULL ;
2017-04-24 18:23:35 +02:00
_cleanup_free_ char * sresolved = NULL , * dresolved = NULL ;
2016-11-23 22:21:40 +01:00
char * s = NULL , * d = NULL ;
bool rbind = true , ignore_enoent = false ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & source , " : " WHITESPACE , EXTRACT_UNQUOTE | EXTRACT_DONT_COALESCE_SEPARATORS ) ;
2016-11-23 22:21:40 +01:00
if ( r = = 0 )
break ;
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
2018-06-03 16:59:02 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse %s, ignoring: %s " , lvalue , rvalue ) ;
2016-11-23 22:21:40 +01:00
return 0 ;
}
2017-04-24 18:23:35 +02:00
r = unit_full_printf ( u , source , & sresolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r ,
2018-05-20 16:08:29 +02:00
" Failed to resolved unit specifiers in \" %s \" , ignoring: %m " , source ) ;
2018-06-03 16:59:02 +02:00
continue ;
2017-04-24 18:23:35 +02:00
}
s = sresolved ;
2016-11-23 22:21:40 +01:00
if ( s [ 0 ] = = ' - ' ) {
ignore_enoent = true ;
s + + ;
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( s , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
continue ;
2016-11-23 22:21:40 +01:00
/* Optionally, the destination is specified. */
if ( p & & p [ - 1 ] = = ' : ' ) {
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & destination , " : " WHITESPACE , EXTRACT_UNQUOTE | EXTRACT_DONT_COALESCE_SEPARATORS ) ;
2016-11-23 22:21:40 +01:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
2018-06-03 16:59:02 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse %s, ignoring: %s " , lvalue , rvalue ) ;
2016-11-23 22:21:40 +01:00
return 0 ;
}
if ( r = = 0 ) {
2018-06-03 16:59:02 +02:00
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Missing argument after ':', ignoring: %s " , s ) ;
continue ;
2016-11-23 22:21:40 +01:00
}
2017-04-24 18:23:35 +02:00
r = unit_full_printf ( u , destination , & dresolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r ,
" Failed to resolved specifiers in \" %s \" , ignoring: %m " , destination ) ;
2018-06-03 16:59:02 +02:00
continue ;
2017-04-24 18:23:35 +02:00
}
2018-06-03 16:59:02 +02:00
r = path_simplify_and_warn ( dresolved , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
continue ;
2016-11-23 22:21:40 +01:00
2018-06-03 16:59:02 +02:00
d = dresolved ;
2016-11-23 22:21:40 +01:00
/* Optionally, there's also a short option string specified */
if ( p & & p [ - 1 ] = = ' : ' ) {
_cleanup_free_ char * options = NULL ;
2019-06-28 11:15:05 +02:00
r = extract_first_word ( & p , & options , NULL , EXTRACT_UNQUOTE ) ;
2016-11-23 22:21:40 +01:00
if ( r = = - ENOMEM )
return log_oom ( ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse %s: %s " , lvalue , rvalue ) ;
return 0 ;
}
if ( isempty ( options ) | | streq ( options , " rbind " ) )
rbind = true ;
else if ( streq ( options , " norbind " ) )
rbind = false ;
else {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Invalid option string, ignoring setting: %s " , options ) ;
2018-06-03 16:59:02 +02:00
continue ;
2016-11-23 22:21:40 +01:00
}
}
} else
d = s ;
r = bind_mount_add ( & c - > bind_mounts , & c - > n_bind_mounts ,
& ( BindMount ) {
. source = s ,
. destination = d ,
. read_only = ! ! strstr ( lvalue , " ReadOnly " ) ,
. recursive = rbind ,
. ignore_enoent = ignore_enoent ,
} ) ;
if ( r < 0 )
return log_oom ( ) ;
}
return 0 ;
}
2017-09-27 17:30:50 +02:00
int config_parse_job_timeout_sec (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
Unit * u = data ;
usec_t usec ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
r = parse_sec_fix_0 ( rvalue , & usec ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse JobTimeoutSec= parameter, ignoring: %s " , rvalue ) ;
return 0 ;
}
/* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
2017-10-05 14:42:29 +02:00
* versions . If JobRunningTimeoutSec = was explicitly set , avoid this however as whatever the user picked should
2017-09-27 17:30:50 +02:00
* count . */
if ( ! u - > job_running_timeout_set )
u - > job_running_timeout = usec ;
u - > job_timeout = usec ;
return 0 ;
}
int config_parse_job_running_timeout_sec (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
Unit * u = data ;
usec_t usec ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
r = parse_sec_fix_0 ( rvalue , & usec ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s " , rvalue ) ;
return 0 ;
}
u - > job_running_timeout = usec ;
u - > job_running_timeout_set = true ;
return 0 ;
}
2018-10-16 13:28:39 +02:00
int config_parse_emergency_action (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
Manager * m = NULL ;
EmergencyAction * x = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( unit )
m = ( ( Unit * ) userdata ) - > manager ;
else
m = data ;
r = parse_emergency_action ( rvalue , MANAGER_IS_SYSTEM ( m ) , x ) ;
if ( r < 0 ) {
2018-10-16 14:49:36 +02:00
if ( r = = - EOPNOTSUPP & & MANAGER_IS_USER ( m ) ) {
/* Compat mode: remove for systemd 241. */
log_syntax ( unit , LOG_INFO , filename , line , r ,
" %s= in user mode specified as \" %s \" , using \" exit-force \" instead. " ,
lvalue , rvalue ) ;
* x = EMERGENCY_ACTION_EXIT_FORCE ;
return 0 ;
}
2018-10-16 13:28:39 +02:00
if ( r = = - EOPNOTSUPP )
log_syntax ( unit , LOG_ERR , filename , line , r ,
" %s= specified as %s mode action, ignoring: %s " ,
lvalue , MANAGER_IS_SYSTEM ( m ) ? " user " : " system " , rvalue ) ;
else
log_syntax ( unit , LOG_ERR , filename , line , r ,
" Failed to parse %s=, ignoring: %s " , lvalue , rvalue ) ;
return 0 ;
}
return 0 ;
}
2018-11-09 18:19:40 +01:00
int config_parse_pid_file (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * k = NULL , * n = NULL ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2018-11-09 18:19:40 +01:00
char * * s = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( u ) ;
2019-02-06 17:41:26 +01:00
if ( isempty ( rvalue ) ) {
/* An empty assignment removes already set value. */
* s = mfree ( * s ) ;
return 0 ;
}
2018-11-09 18:19:40 +01:00
r = unit_full_printf ( u , rvalue , & k ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
return 0 ;
}
/* If this is a relative path make it absolute by prefixing the /run */
n = path_make_absolute ( k , u - > manager - > prefix [ EXEC_DIRECTORY_RUNTIME ] ) ;
if ( ! n )
return log_oom ( ) ;
/* Check that the result is a sensible path */
r = path_simplify_and_warn ( n , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
return r ;
2019-03-28 16:59:57 +01:00
r = patch_var_run ( unit , filename , line , lvalue , & n ) ;
if ( r < 0 )
return r ;
2018-11-09 18:19:40 +01:00
2019-03-28 16:59:57 +01:00
free_and_replace ( * s , n ) ;
2018-11-09 18:19:40 +01:00
return 0 ;
}
2018-11-16 11:41:18 +01:00
int config_parse_exit_status (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
int * exit_status = data , r ;
uint8_t u ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( exit_status ) ;
if ( isempty ( rvalue ) ) {
* exit_status = - 1 ;
return 0 ;
}
r = safe_atou8 ( rvalue , & u ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse exit status '%s', ignoring: %m " , rvalue ) ;
return 0 ;
}
* exit_status = u ;
return 0 ;
}
cgroup: Add DisableControllers= directive to disable controller in subtree
Some controllers (like the CPU controller) have a performance cost that
is non-trivial on certain workloads. While this can be mitigated and
improved to an extent, there will for some controllers always be some
overheads associated with the benefits gained from the controller.
Inside Facebook, the fix applied has been to disable the CPU controller
forcibly with `cgroup_disable=cpu` on the kernel command line.
This presents a problem: to disable or reenable the controller, a reboot
is required, but this is quite cumbersome and slow to do for many
thousands of machines, especially machines where disabling/enabling a
stateful service on a machine is a matter of several minutes.
Currently systemd provides some configuration knobs for these in the
form of `[Default]CPUAccounting`, `[Default]MemoryAccounting`, and the
like. The limitation of these is that Default*Accounting is overrideable
by individual services, of which any one could decide to reenable a
controller within the hierarchy at any point just by using a controller
feature implicitly (eg. `CPUWeight`), even if the use of that CPU
feature could just be opportunistic. Since many services are provided by
the distribution, or by upstream teams at a particular organisation,
it's not a sustainable solution to simply try to find and remove
offending directives from these units.
This commit presents a more direct solution -- a DisableControllers=
directive that forcibly disallows a controller from being enabled within
a subtree.
2018-12-03 15:38:06 +01:00
int config_parse_disable_controllers (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
int r ;
CGroupContext * c = data ;
CGroupMask disabled_mask ;
/* 1. If empty, make all controllers eligible for use again.
* 2. If non - empty , merge all listed controllers , space separated . */
if ( isempty ( rvalue ) ) {
c - > disable_controllers = 0 ;
return 0 ;
}
r = cg_mask_from_string ( rvalue , & disabled_mask ) ;
if ( r < 0 | | disabled_mask < = 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid cgroup string: %s, ignoring " , rvalue ) ;
return 0 ;
}
c - > disable_controllers | = disabled_mask ;
return 0 ;
}
2019-04-23 12:14:20 +02:00
int config_parse_ip_filter_bpf_progs (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
_cleanup_free_ char * resolved = NULL ;
2019-10-16 16:32:45 +02:00
const Unit * u = userdata ;
2019-04-23 12:14:20 +02:00
char * * * paths = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( paths ) ;
if ( isempty ( rvalue ) ) {
* paths = strv_free ( * paths ) ;
return 0 ;
}
r = unit_full_printf ( u , rvalue , & resolved ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to resolve unit specifiers in '%s', ignoring: %m " , rvalue ) ;
return 0 ;
}
r = path_simplify_and_warn ( resolved , PATH_CHECK_ABSOLUTE , unit , filename , line , lvalue ) ;
if ( r < 0 )
return 0 ;
if ( strv_contains ( * paths , resolved ) )
return 0 ;
r = strv_extend ( paths , resolved ) ;
if ( r < 0 )
return log_oom ( ) ;
r = bpf_firewall_supported ( ) ;
if ( r < 0 )
return r ;
if ( r ! = BPF_FIREWALL_SUPPORTED_WITH_MULTI ) {
static bool warned = false ;
log_full ( warned ? LOG_DEBUG : LOG_WARNING ,
" File %s:%u configures an IP firewall with BPF programs (%s=%s), but the local system does not support BPF/cgroup based firewalling with multiple filters. \n "
" Starting this unit will fail! (This warning is only shown for the first loaded unit using IP firewalling.) " , filename , line , lvalue , rvalue ) ;
warned = true ;
}
return 0 ;
}
2010-04-06 02:43:58 +02:00
static int merge_by_names ( Unit * * u , Set * names , const char * id ) {
char * k ;
int r ;
assert ( u ) ;
assert ( * u ) ;
2019-07-18 13:11:28 +02:00
/* Let's try to add in all names that are aliases of this unit */
2010-04-06 02:43:58 +02:00
while ( ( k = set_steal_first ( names ) ) ) {
2019-07-18 13:11:28 +02:00
_cleanup_free_ _unused_ char * free_k = k ;
2010-04-06 02:43:58 +02:00
2019-07-18 13:11:28 +02:00
/* First try to merge in the other name into our unit */
2012-07-03 16:09:36 +02:00
r = unit_merge_by_name ( * u , k ) ;
if ( r < 0 ) {
2010-04-06 02:43:58 +02:00
Unit * other ;
2019-07-18 13:11:28 +02:00
/* Hmm, we couldn't merge the other unit into ours? Then let's try it the other way
* round . */
2010-02-13 01:07:02 +01:00
2019-07-18 13:11:28 +02:00
other = manager_get_unit ( ( * u ) - > manager , k ) ;
if ( ! other )
return r ; /* return previous failure */
2010-02-13 01:07:02 +01:00
2019-07-18 13:11:28 +02:00
r = unit_merge ( other , * u ) ;
if ( r < 0 )
2016-04-29 17:37:33 +02:00
return r ;
2010-07-11 00:52:00 +02:00
2019-07-18 13:11:28 +02:00
* u = other ;
return merge_by_names ( u , names , NULL ) ;
2010-02-13 01:07:02 +01:00
}
2010-01-26 04:18:44 +01:00
2019-07-18 13:11:28 +02:00
if ( streq_ptr ( id , k ) )
unit_choose_id ( * u , id ) ;
2012-05-22 23:08:24 +02:00
}
2013-10-22 01:54:10 +02:00
return 0 ;
2010-01-27 00:15:56 +01:00
}
2010-04-10 17:53:17 +02:00
int unit_load_fragment ( Unit * u ) {
2019-07-18 13:11:28 +02:00
const char * fragment ;
_cleanup_set_free_free_ Set * names = NULL ;
2010-04-06 02:43:58 +02:00
int r ;
2010-01-27 00:15:56 +01:00
assert ( u ) ;
2012-01-15 12:04:08 +01:00
assert ( u - > load_state = = UNIT_STUB ) ;
assert ( u - > id ) ;
2010-04-06 02:43:58 +02:00
2015-08-28 16:05:32 +02:00
if ( u - > transient ) {
u - > load_state = UNIT_LOADED ;
return 0 ;
}
2019-07-10 18:01:13 +02:00
/* Possibly rebuild the fragment map to catch new units */
r = unit_file_build_name_map ( & u - > manager - > lookup_paths ,
& u - > manager - > unit_cache_mtime ,
& u - > manager - > unit_id_map ,
& u - > manager - > unit_name_map ,
& u - > manager - > unit_path_cache ) ;
2012-07-03 16:09:36 +02:00
if ( r < 0 )
2020-05-26 16:07:30 +02:00
return log_error_errno ( r , " Failed to rebuild name map: %m " ) ;
2019-07-10 18:01:13 +02:00
2019-07-18 13:11:28 +02:00
r = unit_file_find_fragment ( u - > manager - > unit_id_map ,
u - > manager - > unit_name_map ,
u - > id ,
& fragment ,
& names ) ;
if ( r < 0 & & r ! = - ENOENT )
2010-07-21 03:28:10 +02:00
return r ;
2019-07-18 13:11:28 +02:00
if ( fragment ) {
/* Open the file, check if this is a mask, otherwise read. */
_cleanup_fclose_ FILE * f = NULL ;
2020-05-31 14:35:40 +02:00
struct stat st ;
2010-01-27 00:15:56 +01:00
2019-07-18 13:11:28 +02:00
/* Try to open the file name. A symlink is OK, for example for linked files or masks. We
* expect that all symlinks within the lookup paths have been already resolved , but we don ' t
* verify this here . */
f = fopen ( fragment , " re " ) ;
if ( ! f )
return log_unit_notice_errno ( u , errno , " Failed to open %s: %m " , fragment ) ;
2010-09-27 20:31:23 +02:00
2019-07-18 13:11:28 +02:00
if ( fstat ( fileno ( f ) , & st ) < 0 )
return - errno ;
2010-07-21 03:28:10 +02:00
2019-07-18 13:11:28 +02:00
r = free_and_strdup ( & u - > fragment_path , fragment ) ;
2015-04-30 20:21:00 +02:00
if ( r < 0 )
return r ;
2010-07-21 03:28:10 +02:00
2019-07-18 13:11:28 +02:00
if ( null_or_empty ( & st ) ) {
2020-01-17 15:02:13 +01:00
/* Unit file is masked */
u - > load_state = u - > perpetual ? UNIT_LOADED : UNIT_MASKED ; /* don't allow perpetual units to ever be masked */
2019-07-18 13:11:28 +02:00
u - > fragment_mtime = 0 ;
} else {
u - > load_state = UNIT_LOADED ;
u - > fragment_mtime = timespec_load ( & st . st_mtim ) ;
/* Now, parse the file contents */
r = config_parse ( u - > id , fragment , f ,
UNIT_VTABLE ( u ) - > sections ,
config_item_perf_lookup , load_fragment_gperf_lookup ,
2020-06-02 12:06:22 +02:00
0 ,
2020-06-02 14:55:12 +02:00
u ,
NULL ) ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
if ( r = = - ENOEXEC )
2019-07-18 13:11:28 +02:00
log_unit_notice_errno ( u , r , " Unit configuration has fatal error, unit will not be started. " ) ;
if ( r < 0 )
return r ;
core/load-fragment: refuse units with errors in certain directives
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.
For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.
Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.
Fixes #6237, #6277.
2017-07-06 19:28:19 +02:00
}
2019-07-18 13:11:28 +02:00
}
2010-02-14 01:08:20 +01:00
2019-07-18 13:11:28 +02:00
/* We do the merge dance here because for some unit types, the unit might have aliases which are not
* declared in the file system . In particular , this is true ( and frequent ) for device and swap units .
*/
Unit * merged ;
const char * id = u - > id ;
_cleanup_free_ char * free_id = NULL ;
2010-07-21 03:28:10 +02:00
2019-07-18 13:11:28 +02:00
if ( fragment ) {
id = basename ( fragment ) ;
if ( unit_name_is_valid ( id , UNIT_NAME_TEMPLATE ) ) {
assert ( u - > instance ) ; /* If we're not trying to use a template for non-instanced unit,
* this must be set . */
2010-02-14 01:08:20 +01:00
2019-07-18 13:11:28 +02:00
r = unit_name_replace_instance ( id , u - > instance , & free_id ) ;
if ( r < 0 )
return log_debug_errno ( r , " Failed to build id (%s + %s) : % m " , id, u->instance) ;
id = free_id ;
2014-12-12 19:51:41 +01:00
}
2010-01-28 02:06:20 +01:00
}
2019-07-18 13:11:28 +02:00
merged = u ;
r = merge_by_names ( & merged , names , id ) ;
if ( r < 0 )
return r ;
if ( merged ! = u )
u - > load_state = UNIT_MERGED ;
2010-04-06 02:43:58 +02:00
return 0 ;
2009-11-19 23:13:20 +01:00
}
2010-04-10 17:53:17 +02:00
void unit_dump_config_items ( FILE * f ) {
2011-08-01 00:43:05 +02:00
static const struct {
const ConfigParserCallback callback ;
const char * rvalue ;
} table [ ] = {
2014-02-12 18:28:21 +01:00
{ config_parse_warn_compat , " NOTSUPPORTED " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_int , " INTEGER " } ,
{ config_parse_unsigned , " UNSIGNED " } ,
2014-02-23 03:13:54 +01:00
{ config_parse_iec_size , " SIZE " } ,
2015-09-10 18:16:18 +02:00
{ config_parse_iec_uint64 , " SIZE " } ,
2020-01-21 12:06:40 +01:00
{ config_parse_si_uint64 , " SIZE " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_bool , " BOOLEAN " } ,
{ config_parse_string , " STRING " } ,
{ config_parse_path , " PATH " } ,
{ config_parse_unit_path_printf , " PATH " } ,
{ config_parse_strv , " STRING [...] " } ,
{ config_parse_exec_nice , " NICE " } ,
{ config_parse_exec_oom_score_adjust , " OOMSCOREADJUST " } ,
{ config_parse_exec_io_class , " IOCLASS " } ,
{ config_parse_exec_io_priority , " IOPRIORITY " } ,
{ config_parse_exec_cpu_sched_policy , " CPUSCHEDPOLICY " } ,
{ config_parse_exec_cpu_sched_prio , " CPUSCHEDPRIO " } ,
{ config_parse_exec_cpu_affinity , " CPUAFFINITY " } ,
{ config_parse_mode , " MODE " } ,
{ config_parse_unit_env_file , " FILE " } ,
2016-10-18 02:05:49 +02:00
{ config_parse_exec_output , " OUTPUT " } ,
{ config_parse_exec_input , " INPUT " } ,
2014-03-03 21:14:07 +01:00
{ config_parse_log_facility , " FACILITY " } ,
{ config_parse_log_level , " LEVEL " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_exec_secure_bits , " SECUREBITS " } ,
2016-01-07 23:00:04 +01:00
{ config_parse_capability_set , " BOUNDINGSET " } ,
2018-05-03 19:01:21 +02:00
{ config_parse_rlimit , " LIMIT " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_unit_deps , " UNIT [...] " } ,
{ config_parse_exec , " PATH [ARGUMENT [...]] " } ,
{ config_parse_service_type , " SERVICETYPE " } ,
{ config_parse_service_restart , " SERVICERESTART " } ,
2019-04-16 16:45:20 +02:00
{ config_parse_service_timeout_failure_mode , " TIMEOUTMODE " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_kill_mode , " KILLMODE " } ,
2015-09-06 01:22:14 +02:00
{ config_parse_signal , " SIGNAL " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_socket_listen , " SOCKET [...] " } ,
{ config_parse_socket_bind , " SOCKETBIND " } ,
{ config_parse_socket_bindtodevice , " NETWORKINTERFACE " } ,
2013-04-02 20:38:16 +02:00
{ config_parse_sec , " SECONDS " } ,
2012-05-31 04:27:03 +02:00
{ config_parse_nsec , " NANOSECONDS " } ,
2014-03-03 21:40:55 +01:00
{ config_parse_namespace_path_strv , " PATH [...] " } ,
2016-11-23 22:21:40 +01:00
{ config_parse_bind_paths , " PATH[:PATH[:OPTIONS]] [...] " } ,
2012-04-29 14:26:07 +02:00
{ config_parse_unit_requires_mounts_for , " PATH [...] " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_exec_mount_flags , " MOUNTFLAG [...] " } ,
{ config_parse_unit_string_printf , " STRING " } ,
2013-04-23 20:53:16 +02:00
{ config_parse_trigger_unit , " UNIT " } ,
2011-08-01 00:43:05 +02:00
{ config_parse_timer , " TIMER " } ,
{ config_parse_path_spec , " PATH " } ,
{ config_parse_notify_access , " ACCESS " } ,
{ config_parse_ip_tos , " TOS " } ,
{ config_parse_unit_condition_path , " CONDITION " } ,
{ config_parse_unit_condition_string , " CONDITION " } ,
{ config_parse_unit_condition_null , " CONDITION " } ,
2013-06-17 21:33:26 +02:00
{ config_parse_unit_slice , " SLICE " } ,
2013-07-19 18:45:11 +02:00
{ config_parse_documentation , " URL " } ,
{ config_parse_service_timeout , " SECONDS " } ,
2016-10-20 15:27:37 +02:00
{ config_parse_emergency_action , " ACTION " } ,
2013-07-19 18:45:11 +02:00
{ config_parse_set_status , " STATUS " } ,
{ config_parse_service_sockets , " SOCKETS " } ,
{ config_parse_environ , " ENVIRON " } ,
2017-10-03 10:41:51 +02:00
# if HAVE_SECCOMP
2014-02-12 18:28:21 +01:00
{ config_parse_syscall_filter , " SYSCALLS " } ,
2014-02-17 17:49:09 +01:00
{ config_parse_syscall_archs , " ARCHS " } ,
2014-02-12 18:28:21 +01:00
{ config_parse_syscall_errno , " ERRNO " } ,
2014-02-25 20:37:03 +01:00
{ config_parse_address_families , " FAMILIES " } ,
2016-11-02 03:25:19 +01:00
{ config_parse_restrict_namespaces , " NAMESPACES " } ,
2014-02-12 01:29:54 +01:00
# endif
2013-07-19 18:45:11 +02:00
{ config_parse_cpu_shares , " SHARES " } ,
2018-05-29 05:57:06 +02:00
{ config_parse_cg_weight , " WEIGHT " } ,
2013-07-19 18:45:11 +02:00
{ config_parse_memory_limit , " LIMIT " } ,
{ config_parse_device_allow , " DEVICE " } ,
{ config_parse_device_policy , " POLICY " } ,
2016-05-05 22:42:55 +02:00
{ config_parse_io_limit , " LIMIT " } ,
{ config_parse_io_device_weight , " DEVICEWEIGHT " } ,
2018-06-13 23:16:35 +02:00
{ config_parse_io_device_latency , " DEVICELATENCY " } ,
2013-07-19 18:45:11 +02:00
{ config_parse_blockio_bandwidth , " BANDWIDTH " } ,
{ config_parse_blockio_weight , " WEIGHT " } ,
{ config_parse_blockio_device_weight , " DEVICEWEIGHT " } ,
{ config_parse_long , " LONG " } ,
{ config_parse_socket_service , " SERVICE " } ,
2017-10-03 10:41:51 +02:00
# if HAVE_SELINUX
2014-02-17 17:49:09 +01:00
{ config_parse_exec_selinux_context , " LABEL " } ,
# endif
{ config_parse_job_mode , " MODE " } ,
{ config_parse_job_mode_isolate , " BOOLEAN " } ,
2014-02-25 20:37:03 +01:00
{ config_parse_personality , " PERSONALITY " } ,
2011-08-01 00:43:05 +02:00
} ;
const char * prev = NULL ;
const char * i ;
assert ( f ) ;
2010-04-10 17:53:17 +02:00
2011-08-01 00:43:05 +02:00
NULSTR_FOREACH ( i , load_fragment_gperf_nulstr ) {
const char * rvalue = " OTHER " , * lvalue ;
2018-05-28 21:47:12 +02:00
const ConfigPerfItem * p ;
2011-08-01 00:43:05 +02:00
size_t prefix_len ;
const char * dot ;
2018-05-28 21:47:12 +02:00
unsigned j ;
2011-08-01 00:43:05 +02:00
assert_se ( p = load_fragment_gperf_lookup ( i , strlen ( i ) ) ) ;
2018-05-28 21:47:12 +02:00
/* Hide legacy settings */
if ( p - > parse = = config_parse_warn_compat & &
p - > ltype = = DISABLED_LEGACY )
continue ;
for ( j = 0 ; j < ELEMENTSOF ( table ) ; j + + )
if ( p - > parse = = table [ j ] . callback ) {
rvalue = table [ j ] . rvalue ;
break ;
}
2011-08-01 00:43:05 +02:00
dot = strchr ( i , ' . ' ) ;
lvalue = dot ? dot + 1 : i ;
prefix_len = dot - i ;
if ( dot )
2013-02-12 21:47:36 +01:00
if ( ! prev | | ! strneq ( prev , i , prefix_len + 1 ) ) {
2011-08-01 00:43:05 +02:00
if ( prev )
fputc ( ' \n ' , f ) ;
fprintf ( f , " [%.*s] \n " , ( int ) prefix_len , i ) ;
}
fprintf ( f , " %s=%s \n " , lvalue , rvalue ) ;
prev = i ;
}
2010-04-10 17:53:17 +02:00
}
2019-06-20 18:51:42 +02:00
int config_parse_cpu_affinity2 (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
CPUSet * affinity = data ;
assert ( affinity ) ;
( void ) parse_cpu_set_extend ( rvalue , affinity , true , unit , filename , line , lvalue ) ;
return 0 ;
}
int config_parse_show_status (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
int k ;
ShowStatus * b = data ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
k = parse_show_status ( rvalue , b ) ;
if ( k < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , k , " Failed to parse show status setting, ignoring: %s " , rvalue ) ;
return 0 ;
}
return 0 ;
}
int config_parse_output_restricted (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecOutput t , * eo = data ;
2020-05-14 12:20:39 +02:00
bool obsolete = false ;
2019-06-20 18:51:42 +02:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2020-05-14 12:20:39 +02:00
if ( streq ( rvalue , " syslog " ) ) {
t = EXEC_OUTPUT_JOURNAL ;
obsolete = true ;
} else if ( streq ( rvalue , " syslog+console " ) ) {
t = EXEC_OUTPUT_JOURNAL_AND_CONSOLE ;
obsolete = true ;
} else {
t = exec_output_from_string ( rvalue ) ;
if ( t < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Failed to parse output type, ignoring: %s " , rvalue ) ;
return 0 ;
}
2019-06-20 18:51:42 +02:00
2020-05-14 12:20:39 +02:00
if ( IN_SET ( t , EXEC_OUTPUT_SOCKET , EXEC_OUTPUT_NAMED_FD , EXEC_OUTPUT_FILE , EXEC_OUTPUT_FILE_APPEND ) ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s " , rvalue ) ;
return 0 ;
}
2019-06-20 18:51:42 +02:00
}
2020-05-14 12:20:39 +02:00
if ( obsolete )
log_syntax ( unit , LOG_NOTICE , filename , line , 0 ,
" Standard output type %s is obsolete, automatically updating to %s. Please update your configuration. " ,
rvalue , exec_output_to_string ( t ) ) ;
2019-06-20 18:51:42 +02:00
* eo = t ;
return 0 ;
}
int config_parse_crash_chvt (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
r = parse_crash_chvt ( rvalue , data ) ;
if ( r < 0 ) {
log_syntax ( unit , LOG_ERR , filename , line , r , " Failed to parse CrashChangeVT= setting, ignoring: %s " , rvalue ) ;
return 0 ;
}
return 0 ;
}
2020-01-09 17:02:56 +01:00
int config_parse_swap_priority (
const char * unit ,
const char * filename ,
unsigned line ,
const char * section ,
unsigned section_line ,
const char * lvalue ,
int ltype ,
const char * rvalue ,
void * data ,
void * userdata ) {
Swap * s = userdata ;
int r , priority ;
assert ( s ) ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( isempty ( rvalue ) ) {
s - > parameters_fragment . priority = - 1 ;
s - > parameters_fragment . priority_set = false ;
return 0 ;
}
r = safe_atoi ( rvalue , & priority ) ;
if ( r < 0 ) {
2020-05-20 10:39:09 +02:00
log_syntax ( unit , LOG_ERR , filename , line , r , " Invalid swap priority '%s', ignoring. " , rvalue ) ;
2020-01-09 17:02:56 +01:00
return 0 ;
}
if ( priority < - 1 ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Sorry, swap priorities smaller than -1 may only be assigned by the kernel itself, ignoring: %s " , rvalue ) ;
return 0 ;
}
if ( priority > 32767 ) {
log_syntax ( unit , LOG_ERR , filename , line , 0 , " Swap priority out of range, ignoring: %s " , rvalue ) ;
return 0 ;
}
s - > parameters_fragment . priority = priority ;
s - > parameters_fragment . priority_set = true ;
return 0 ;
}