LCOV - code coverage report
Current view: top level - core - load-fragment.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 457 2387 19.1 %
Date: 2019-08-22 15:41:25 Functions: 22 111 19.8 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : /***
       3             :   Copyright © 2012 Holger Hans Peter Freyther
       4             : ***/
       5             : 
       6             : #include <errno.h>
       7             : #include <fcntl.h>
       8             : #include <linux/fs.h>
       9             : #include <linux/oom.h>
      10             : #if HAVE_SECCOMP
      11             : #include <seccomp.h>
      12             : #endif
      13             : #include <sched.h>
      14             : #include <string.h>
      15             : #include <sys/resource.h>
      16             : #include <sys/stat.h>
      17             : 
      18             : #include "af-list.h"
      19             : #include "alloc-util.h"
      20             : #include "all-units.h"
      21             : #include "bpf-firewall.h"
      22             : #include "bus-error.h"
      23             : #include "bus-internal.h"
      24             : #include "bus-util.h"
      25             : #include "cap-list.h"
      26             : #include "capability-util.h"
      27             : #include "cgroup.h"
      28             : #include "conf-parser.h"
      29             : #include "cpu-set-util.h"
      30             : #include "env-util.h"
      31             : #include "errno-list.h"
      32             : #include "escape.h"
      33             : #include "fd-util.h"
      34             : #include "fs-util.h"
      35             : #include "hexdecoct.h"
      36             : #include "io-util.h"
      37             : #include "ioprio.h"
      38             : #include "ip-protocol-list.h"
      39             : #include "journal-util.h"
      40             : #include "limits-util.h"
      41             : #include "load-fragment.h"
      42             : #include "log.h"
      43             : #include "missing.h"
      44             : #include "mountpoint-util.h"
      45             : #include "nulstr-util.h"
      46             : #include "parse-util.h"
      47             : #include "path-util.h"
      48             : #include "process-util.h"
      49             : #if HAVE_SECCOMP
      50             : #include "seccomp-util.h"
      51             : #endif
      52             : #include "securebits-util.h"
      53             : #include "signal-util.h"
      54             : #include "stat-util.h"
      55             : #include "string-util.h"
      56             : #include "strv.h"
      57             : #include "unit-name.h"
      58             : #include "unit-printf.h"
      59             : #include "user-util.h"
      60             : #include "time-util.h"
      61             : #include "web-util.h"
      62             : 
      63           0 : static int parse_socket_protocol(const char *s) {
      64             :         int r;
      65             : 
      66           0 :         r = parse_ip_protocol(s);
      67           0 :         if (r < 0)
      68           0 :                 return r;
      69           0 :         if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP))
      70           0 :                 return -EPROTONOSUPPORT;
      71             : 
      72           0 :         return r;
      73             : }
      74             : 
      75           0 : int parse_crash_chvt(const char *value, int *data) {
      76             :         int b;
      77             : 
      78           0 :         if (safe_atoi(value, data) >= 0)
      79           0 :                 return 0;
      80             : 
      81           0 :         b = parse_boolean(value);
      82           0 :         if (b < 0)
      83           0 :                 return b;
      84             : 
      85           0 :         if (b > 0)
      86           0 :                 *data = 0; /* switch to where kmsg goes */
      87             :         else
      88           0 :                 *data = -1; /* turn off switching */
      89             : 
      90           0 :         return 0;
      91             : }
      92             : 
      93           0 : int parse_confirm_spawn(const char *value, char **console) {
      94             :         char *s;
      95             :         int r;
      96             : 
      97           0 :         r = value ? parse_boolean(value) : 1;
      98           0 :         if (r == 0) {
      99           0 :                 *console = NULL;
     100           0 :                 return 0;
     101           0 :         } else if (r > 0) /* on with default tty */
     102           0 :                 s = strdup("/dev/console");
     103           0 :         else if (is_path(value)) /* on with fully qualified path */
     104           0 :                 s = strdup(value);
     105             :         else /* on with only a tty file name, not a fully qualified path */
     106           0 :                 s = path_join("/dev/", value);
     107           0 :         if (!s)
     108           0 :                 return -ENOMEM;
     109             : 
     110           0 :         *console = s;
     111           0 :         return 0;
     112             : }
     113             : 
     114           0 : DEFINE_CONFIG_PARSE(config_parse_socket_protocol, parse_socket_protocol, "Failed to parse socket protocol");
     115           0 : DEFINE_CONFIG_PARSE(config_parse_exec_secure_bits, secure_bits_from_string, "Failed to parse secure bits");
     116           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode");
     117           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
     118           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
     119           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
     120           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
     121           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
     122           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
     123           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_home, protect_home, ProtectHome, "Failed to parse protect home value");
     124           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSystem, "Failed to parse protect system value");
     125           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
     126          17 : DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
     127           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
     128           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
     129           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
     130           0 : DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
     131           0 : DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
     132           2 : DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
     133           1 : DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
     134           0 : DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
     135           0 : DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
     136             : 
     137          99 : int config_parse_unit_deps(
     138             :                 const char *unit,
     139             :                 const char *filename,
     140             :                 unsigned line,
     141             :                 const char *section,
     142             :                 unsigned section_line,
     143             :                 const char *lvalue,
     144             :                 int ltype,
     145             :                 const char *rvalue,
     146             :                 void *data,
     147             :                 void *userdata) {
     148             : 
     149          99 :         UnitDependency d = ltype;
     150          99 :         Unit *u = userdata;
     151             :         const char *p;
     152             : 
     153          99 :         assert(filename);
     154          99 :         assert(lvalue);
     155          99 :         assert(rvalue);
     156             : 
     157          99 :         p = rvalue;
     158         232 :         for (;;) {
     159         430 :                 _cleanup_free_ char *word = NULL, *k = NULL;
     160             :                 int r;
     161             : 
     162         331 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
     163         331 :                 if (r == 0)
     164          99 :                         break;
     165         232 :                 if (r == -ENOMEM)
     166           0 :                         return log_oom();
     167         232 :                 if (r < 0) {
     168           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
     169           0 :                         break;
     170             :                 }
     171             : 
     172         232 :                 r = unit_name_printf(u, word, &k);
     173         232 :                 if (r < 0) {
     174           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
     175           0 :                         continue;
     176             :                 }
     177             : 
     178         232 :                 r = unit_add_dependency_by_name(u, d, k, true, UNIT_DEPENDENCY_FILE);
     179         232 :                 if (r < 0)
     180           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
     181             :         }
     182             : 
     183          99 :         return 0;
     184             : }
     185             : 
     186           0 : int config_parse_obsolete_unit_deps(
     187             :                 const char *unit,
     188             :                 const char *filename,
     189             :                 unsigned line,
     190             :                 const char *section,
     191             :                 unsigned section_line,
     192             :                 const char *lvalue,
     193             :                 int ltype,
     194             :                 const char *rvalue,
     195             :                 void *data,
     196             :                 void *userdata) {
     197             : 
     198           0 :         log_syntax(unit, LOG_WARNING, filename, line, 0,
     199             :                    "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
     200             : 
     201           0 :         return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
     202             : }
     203             : 
     204          89 : int config_parse_unit_string_printf(
     205             :                 const char *unit,
     206             :                 const char *filename,
     207             :                 unsigned line,
     208             :                 const char *section,
     209             :                 unsigned section_line,
     210             :                 const char *lvalue,
     211             :                 int ltype,
     212             :                 const char *rvalue,
     213             :                 void *data,
     214             :                 void *userdata) {
     215             : 
     216          89 :         _cleanup_free_ char *k = NULL;
     217          89 :         Unit *u = userdata;
     218             :         int r;
     219             : 
     220          89 :         assert(filename);
     221          89 :         assert(lvalue);
     222          89 :         assert(rvalue);
     223          89 :         assert(u);
     224             : 
     225          89 :         r = unit_full_printf(u, rvalue, &k);
     226          89 :         if (r < 0) {
     227           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
     228           0 :                 return 0;
     229             :         }
     230             : 
     231          89 :         return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
     232             : }
     233             : 
     234          44 : int config_parse_unit_strv_printf(
     235             :                 const char *unit,
     236             :                 const char *filename,
     237             :                 unsigned line,
     238             :                 const char *section,
     239             :                 unsigned section_line,
     240             :                 const char *lvalue,
     241             :                 int ltype,
     242             :                 const char *rvalue,
     243             :                 void *data,
     244             :                 void *userdata) {
     245             : 
     246          44 :         Unit *u = userdata;
     247          44 :         _cleanup_free_ char *k = NULL;
     248             :         int r;
     249             : 
     250          44 :         assert(filename);
     251          44 :         assert(lvalue);
     252          44 :         assert(rvalue);
     253          44 :         assert(u);
     254             : 
     255          44 :         r = unit_full_printf(u, rvalue, &k);
     256          44 :         if (r < 0) {
     257           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
     258           0 :                 return 0;
     259             :         }
     260             : 
     261          44 :         return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
     262             : }
     263             : 
     264           0 : int config_parse_unit_path_printf(
     265             :                 const char *unit,
     266             :                 const char *filename,
     267             :                 unsigned line,
     268             :                 const char *section,
     269             :                 unsigned section_line,
     270             :                 const char *lvalue,
     271             :                 int ltype,
     272             :                 const char *rvalue,
     273             :                 void *data,
     274             :                 void *userdata) {
     275             : 
     276           0 :         _cleanup_free_ char *k = NULL;
     277           0 :         Unit *u = userdata;
     278             :         int r;
     279           0 :         bool fatal = ltype;
     280             : 
     281           0 :         assert(filename);
     282           0 :         assert(lvalue);
     283           0 :         assert(rvalue);
     284           0 :         assert(u);
     285             : 
     286             :         /* Let's not bother with anything that is too long */
     287           0 :         if (strlen(rvalue) >= PATH_MAX) {
     288           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0,
     289             :                            "%s value too long%s.",
     290             :                            lvalue, fatal ? "" : ", ignoring");
     291           0 :                 return fatal ? -ENAMETOOLONG : 0;
     292             :         }
     293             : 
     294           0 :         r = unit_full_printf(u, rvalue, &k);
     295           0 :         if (r < 0) {
     296           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
     297             :                            "Failed to resolve unit specifiers in '%s'%s: %m",
     298             :                            rvalue, fatal ? "" : ", ignoring");
     299           0 :                 return fatal ? -ENOEXEC : 0;
     300             :         }
     301             : 
     302           0 :         return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
     303             : }
     304             : 
     305           0 : int config_parse_unit_path_strv_printf(
     306             :                 const char *unit,
     307             :                 const char *filename,
     308             :                 unsigned line,
     309             :                 const char *section,
     310             :                 unsigned section_line,
     311             :                 const char *lvalue,
     312             :                 int ltype,
     313             :                 const char *rvalue,
     314             :                 void *data,
     315             :                 void *userdata) {
     316             : 
     317           0 :         char ***x = data;
     318           0 :         Unit *u = userdata;
     319             :         int r;
     320             :         const char *p;
     321             : 
     322           0 :         assert(filename);
     323           0 :         assert(lvalue);
     324           0 :         assert(rvalue);
     325           0 :         assert(u);
     326             : 
     327           0 :         if (isempty(rvalue)) {
     328           0 :                 *x = strv_free(*x);
     329           0 :                 return 0;
     330             :         }
     331             : 
     332           0 :         for (p = rvalue;;) {
     333           0 :                 _cleanup_free_ char *word = NULL, *k = NULL;
     334             : 
     335           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
     336           0 :                 if (r == 0)
     337           0 :                         return 0;
     338           0 :                 if (r == -ENOMEM)
     339           0 :                         return log_oom();
     340           0 :                 if (r < 0) {
     341           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r,
     342             :                                    "Invalid syntax, ignoring: %s", rvalue);
     343           0 :                         return 0;
     344             :                 }
     345             : 
     346           0 :                 r = unit_full_printf(u, word, &k);
     347           0 :                 if (r < 0) {
     348           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     349             :                                    "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
     350           0 :                         return 0;
     351             :                 }
     352             : 
     353           0 :                 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
     354           0 :                 if (r < 0)
     355           0 :                         return 0;
     356             : 
     357           0 :                 r = strv_consume(x, TAKE_PTR(k));
     358           0 :                 if (r < 0)
     359           0 :                         return log_oom();
     360             :         }
     361             : }
     362             : 
     363           0 : static int patch_var_run(
     364             :                 const char *unit,
     365             :                 const char *filename,
     366             :                 unsigned line,
     367             :                 const char *lvalue,
     368             :                 char **path) {
     369             : 
     370             :         const char *e;
     371             :         char *z;
     372             : 
     373           0 :         e = path_startswith(*path, "/var/run/");
     374           0 :         if (!e)
     375           0 :                 return 0;
     376             : 
     377           0 :         z = path_join("/run/", e);
     378           0 :         if (!z)
     379           0 :                 return log_oom();
     380             : 
     381           0 :         log_syntax(unit, LOG_NOTICE, filename, line, 0,
     382             :                    "%s= references a path below legacy directory /var/run/, updating %s → %s; "
     383             :                    "please update the unit file accordingly.", lvalue, *path, z);
     384             : 
     385           0 :         free_and_replace(*path, z);
     386             : 
     387           0 :         return 1;
     388             : }
     389             : 
     390           0 : int config_parse_socket_listen(
     391             :                 const char *unit,
     392             :                 const char *filename,
     393             :                 unsigned line,
     394             :                 const char *section,
     395             :                 unsigned section_line,
     396             :                 const char *lvalue,
     397             :                 int ltype,
     398             :                 const char *rvalue,
     399             :                 void *data,
     400             :                 void *userdata) {
     401             : 
     402           0 :         _cleanup_free_ SocketPort *p = NULL;
     403             :         SocketPort *tail;
     404             :         Socket *s;
     405             :         int r;
     406             : 
     407           0 :         assert(filename);
     408           0 :         assert(lvalue);
     409           0 :         assert(rvalue);
     410           0 :         assert(data);
     411             : 
     412           0 :         s = SOCKET(data);
     413             : 
     414           0 :         if (isempty(rvalue)) {
     415             :                 /* An empty assignment removes all ports */
     416           0 :                 socket_free_ports(s);
     417           0 :                 return 0;
     418             :         }
     419             : 
     420           0 :         p = new0(SocketPort, 1);
     421           0 :         if (!p)
     422           0 :                 return log_oom();
     423             : 
     424           0 :         if (ltype != SOCKET_SOCKET) {
     425           0 :                 _cleanup_free_ char *k = NULL;
     426             : 
     427           0 :                 r = unit_full_printf(UNIT(s), rvalue, &k);
     428           0 :                 if (r < 0) {
     429           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
     430           0 :                         return 0;
     431             :                 }
     432             : 
     433           0 :                 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
     434           0 :                 if (r < 0)
     435           0 :                         return 0;
     436             : 
     437           0 :                 if (ltype == SOCKET_FIFO) {
     438           0 :                         r = patch_var_run(unit, filename, line, lvalue, &k);
     439           0 :                         if (r < 0)
     440           0 :                                 return r;
     441             :                 }
     442             : 
     443           0 :                 free_and_replace(p->path, k);
     444           0 :                 p->type = ltype;
     445             : 
     446           0 :         } else if (streq(lvalue, "ListenNetlink")) {
     447           0 :                 _cleanup_free_ char  *k = NULL;
     448             : 
     449           0 :                 r = unit_full_printf(UNIT(s), rvalue, &k);
     450           0 :                 if (r < 0) {
     451           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
     452           0 :                         return 0;
     453             :                 }
     454             : 
     455           0 :                 r = socket_address_parse_netlink(&p->address, k);
     456           0 :                 if (r < 0) {
     457           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
     458           0 :                         return 0;
     459             :                 }
     460             : 
     461           0 :                 p->type = SOCKET_SOCKET;
     462             : 
     463             :         } else {
     464           0 :                 _cleanup_free_ char *k = NULL;
     465             : 
     466           0 :                 r = unit_full_printf(UNIT(s), rvalue, &k);
     467           0 :                 if (r < 0) {
     468           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
     469           0 :                         return 0;
     470             :                 }
     471             : 
     472           0 :                 if (k[0] == '/') { /* Only for AF_UNIX file system sockets… */
     473           0 :                         r = patch_var_run(unit, filename, line, lvalue, &k);
     474           0 :                         if (r < 0)
     475           0 :                                 return r;
     476             :                 }
     477             : 
     478           0 :                 r = socket_address_parse_and_warn(&p->address, k);
     479           0 :                 if (r < 0) {
     480           0 :                         if (r != -EAFNOSUPPORT)
     481           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value in '%s', ignoring: %m", k);
     482           0 :                         return 0;
     483             :                 }
     484             : 
     485           0 :                 if (streq(lvalue, "ListenStream"))
     486           0 :                         p->address.type = SOCK_STREAM;
     487           0 :                 else if (streq(lvalue, "ListenDatagram"))
     488           0 :                         p->address.type = SOCK_DGRAM;
     489             :                 else {
     490           0 :                         assert(streq(lvalue, "ListenSequentialPacket"));
     491           0 :                         p->address.type = SOCK_SEQPACKET;
     492             :                 }
     493             : 
     494           0 :                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
     495           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
     496           0 :                         return 0;
     497             :                 }
     498             : 
     499           0 :                 p->type = SOCKET_SOCKET;
     500             :         }
     501             : 
     502           0 :         p->fd = -1;
     503           0 :         p->auxiliary_fds = NULL;
     504           0 :         p->n_auxiliary_fds = 0;
     505           0 :         p->socket = s;
     506             : 
     507           0 :         LIST_FIND_TAIL(port, s->ports, tail);
     508           0 :         LIST_INSERT_AFTER(port, s->ports, tail, p);
     509             : 
     510           0 :         p = NULL;
     511             : 
     512           0 :         return 0;
     513             : }
     514             : 
     515           0 : int config_parse_exec_nice(
     516             :                 const char *unit,
     517             :                 const char *filename,
     518             :                 unsigned line,
     519             :                 const char *section,
     520             :                 unsigned section_line,
     521             :                 const char *lvalue,
     522             :                 int ltype,
     523             :                 const char *rvalue,
     524             :                 void *data,
     525             :                 void *userdata) {
     526             : 
     527           0 :         ExecContext *c = data;
     528             :         int priority, r;
     529             : 
     530           0 :         assert(filename);
     531           0 :         assert(lvalue);
     532           0 :         assert(rvalue);
     533           0 :         assert(data);
     534             : 
     535           0 :         if (isempty(rvalue)) {
     536           0 :                 c->nice_set = false;
     537           0 :                 return 0;
     538             :         }
     539             : 
     540           0 :         r = parse_nice(rvalue, &priority);
     541           0 :         if (r < 0) {
     542           0 :                 if (r == -ERANGE)
     543           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
     544             :                 else
     545           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority '%s', ignoring: %m", rvalue);
     546           0 :                 return 0;
     547             :         }
     548             : 
     549           0 :         c->nice = priority;
     550           0 :         c->nice_set = true;
     551             : 
     552           0 :         return 0;
     553             : }
     554             : 
     555           0 : int config_parse_exec_oom_score_adjust(
     556             :                 const char* unit,
     557             :                 const char *filename,
     558             :                 unsigned line,
     559             :                 const char *section,
     560             :                 unsigned section_line,
     561             :                 const char *lvalue,
     562             :                 int ltype,
     563             :                 const char *rvalue,
     564             :                 void *data,
     565             :                 void *userdata) {
     566             : 
     567           0 :         ExecContext *c = data;
     568             :         int oa, r;
     569             : 
     570           0 :         assert(filename);
     571           0 :         assert(lvalue);
     572           0 :         assert(rvalue);
     573           0 :         assert(data);
     574             : 
     575           0 :         if (isempty(rvalue)) {
     576           0 :                 c->oom_score_adjust_set = false;
     577           0 :                 return 0;
     578             :         }
     579             : 
     580           0 :         r = parse_oom_score_adjust(rvalue, &oa);
     581           0 :         if (r < 0) {
     582           0 :                 if (r == -ERANGE)
     583           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
     584             :                 else
     585           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value '%s', ignoring: %m", rvalue);
     586           0 :                 return 0;
     587             :         }
     588             : 
     589           0 :         c->oom_score_adjust = oa;
     590           0 :         c->oom_score_adjust_set = true;
     591             : 
     592           0 :         return 0;
     593             : }
     594             : 
     595          78 : int config_parse_exec(
     596             :                 const char *unit,
     597             :                 const char *filename,
     598             :                 unsigned line,
     599             :                 const char *section,
     600             :                 unsigned section_line,
     601             :                 const char *lvalue,
     602             :                 int ltype,
     603             :                 const char *rvalue,
     604             :                 void *data,
     605             :                 void *userdata) {
     606             : 
     607          78 :         ExecCommand **e = data;
     608          78 :         Unit *u = userdata;
     609             :         const char *p;
     610             :         bool semicolon;
     611             :         int r;
     612             : 
     613          78 :         assert(filename);
     614          78 :         assert(lvalue);
     615          78 :         assert(rvalue);
     616          78 :         assert(e);
     617             : 
     618          78 :         e += ltype;
     619          78 :         rvalue += strspn(rvalue, WHITESPACE);
     620             : 
     621          78 :         if (isempty(rvalue)) {
     622             :                 /* An empty assignment resets the list */
     623           2 :                 *e = exec_command_free_list(*e);
     624           2 :                 return 0;
     625             :         }
     626             : 
     627          76 :         p = rvalue;
     628             :         do {
     629         103 :                 _cleanup_free_ char *path = NULL, *firstword = NULL;
     630          80 :                 ExecCommandFlags flags = 0;
     631          80 :                 bool ignore = false, separate_argv0 = false;
     632          80 :                 _cleanup_free_ ExecCommand *nce = NULL;
     633          80 :                 _cleanup_strv_free_ char **n = NULL;
     634          80 :                 size_t nlen = 0, nbufsize = 0;
     635             :                 const char *f;
     636             : 
     637          80 :                 semicolon = false;
     638             : 
     639          80 :                 r = extract_first_word_and_warn(&p, &firstword, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
     640          80 :                 if (r <= 0)
     641           2 :                         return 0;
     642             : 
     643          78 :                 f = firstword;
     644             :                 for (;;) {
     645             :                         /* We accept an absolute path as first argument.  If it's prefixed with - and the path doesn't
     646             :                          * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
     647             :                          * argv[0]; if it's prefixed with :, we will not do environment variable substitution;
     648             :                          * if it's prefixed with +, it will be run with full privileges and no sandboxing; if
     649             :                          * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
     650             :                          * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
     651             :                          * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
     652             :                          * other sandboxing, with some special exceptions for changing UID.
     653             :                          *
     654             :                          * The idea is that '!!' may be used to write services that can take benefit of systemd's
     655             :                          * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
     656             :                          * privilege dropping within the daemon if the kernel does not offer that. */
     657             : 
     658          99 :                         if (*f == '-' && !(flags & EXEC_COMMAND_IGNORE_FAILURE)) {
     659          11 :                                 flags |= EXEC_COMMAND_IGNORE_FAILURE;
     660          11 :                                 ignore = true;
     661          88 :                         } else if (*f == '@' && !separate_argv0)
     662          10 :                                 separate_argv0 = true;
     663          78 :                         else if (*f == ':' && !(flags & EXEC_COMMAND_NO_ENV_EXPAND))
     664           0 :                                 flags |= EXEC_COMMAND_NO_ENV_EXPAND;
     665          78 :                         else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
     666           0 :                                 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
     667          78 :                         else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
     668           0 :                                 flags |= EXEC_COMMAND_NO_SETUID;
     669          78 :                         else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))) {
     670           0 :                                 flags &= ~EXEC_COMMAND_NO_SETUID;
     671           0 :                                 flags |= EXEC_COMMAND_AMBIENT_MAGIC;
     672             :                         } else
     673             :                                 break;
     674          21 :                         f++;
     675             :                 }
     676             : 
     677          78 :                 r = unit_full_printf(u, f, &path);
     678          78 :                 if (r < 0) {
     679           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     680             :                                    "Failed to resolve unit specifiers in '%s'%s: %m",
     681             :                                    f, ignore ? ", ignoring" : "");
     682           0 :                         return ignore ? 0 : -ENOEXEC;
     683             :                 }
     684             : 
     685          78 :                 if (isempty(path)) {
     686             :                         /* First word is either "-" or "@" with no command. */
     687           2 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     688             :                                    "Empty path in command line%s: '%s'",
     689             :                                    ignore ? ", ignoring" : "", rvalue);
     690           2 :                         return ignore ? 0 : -ENOEXEC;
     691             :                 }
     692          76 :                 if (!string_is_safe(path)) {
     693          12 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     694             :                                    "Executable name contains special characters%s: %s",
     695             :                                    ignore ? ", ignoring" : "", path);
     696          12 :                         return ignore ? 0 : -ENOEXEC;
     697             :                 }
     698          64 :                 if (endswith(path, "/")) {
     699           1 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     700             :                                    "Executable path specifies a directory%s: %s",
     701             :                                    ignore ? ", ignoring" : "", path);
     702           1 :                         return ignore ? 0 : -ENOEXEC;
     703             :                 }
     704             : 
     705          63 :                 if (!path_is_absolute(path)) {
     706             :                         const char *prefix;
     707           3 :                         bool found = false;
     708             : 
     709           3 :                         if (!filename_is_valid(path)) {
     710           2 :                                 log_syntax(unit, LOG_ERR, filename, line, 0,
     711             :                                            "Neither a valid executable name nor an absolute path%s: %s",
     712             :                                            ignore ? ", ignoring" : "", path);
     713           2 :                                 return ignore ? 0 : -ENOEXEC;
     714             :                         }
     715             : 
     716             :                         /* Resolve a single-component name to a full path */
     717           5 :                         NULSTR_FOREACH(prefix, DEFAULT_PATH_NULSTR) {
     718           4 :                                 _cleanup_free_ char *fullpath = NULL;
     719             : 
     720           4 :                                 fullpath = path_join(prefix, path);
     721           4 :                                 if (!fullpath)
     722           0 :                                         return log_oom();
     723             : 
     724           4 :                                 if (access(fullpath, F_OK) >= 0) {
     725           0 :                                         free_and_replace(path, fullpath);
     726           0 :                                         found = true;
     727           0 :                                         break;
     728             :                                 }
     729             :                         }
     730             : 
     731           1 :                         if (!found) {
     732           1 :                                 log_syntax(unit, LOG_ERR, filename, line, 0,
     733             :                                            "Executable \"%s\" not found in path \"%s\"%s",
     734             :                                            path, DEFAULT_PATH, ignore ? ", ignoring" : "");
     735           1 :                                 return ignore ? 0 : -ENOEXEC;
     736             :                         }
     737             :                 }
     738             : 
     739          60 :                 if (!separate_argv0) {
     740          51 :                         char *w = NULL;
     741             : 
     742          51 :                         if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
     743           0 :                                 return log_oom();
     744             : 
     745          51 :                         w = strdup(path);
     746          51 :                         if (!w)
     747           0 :                                 return log_oom();
     748          51 :                         n[nlen++] = w;
     749          51 :                         n[nlen] = NULL;
     750             :                 }
     751             : 
     752          60 :                 path_simplify(path, false);
     753             : 
     754          95 :                 while (!isempty(p)) {
     755          49 :                         _cleanup_free_ char *word = NULL, *resolved = NULL;
     756             : 
     757             :                         /* Check explicitly for an unquoted semicolon as
     758             :                          * command separator token.  */
     759          41 :                         if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
     760           4 :                                 p++;
     761           4 :                                 p += strspn(p, WHITESPACE);
     762           4 :                                 semicolon = true;
     763           4 :                                 break;
     764             :                         }
     765             : 
     766             :                         /* Check for \; explicitly, to not confuse it with \\; or "\;" or "\\;" etc.
     767             :                          * extract_first_word() would return the same for all of those.  */
     768          37 :                         if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
     769             :                                 char *w;
     770             : 
     771           2 :                                 p += 2;
     772           2 :                                 p += strspn(p, WHITESPACE);
     773             : 
     774           2 :                                 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
     775           0 :                                         return log_oom();
     776             : 
     777           2 :                                 w = strdup(";");
     778           2 :                                 if (!w)
     779           0 :                                         return log_oom();
     780           2 :                                 n[nlen++] = w;
     781           2 :                                 n[nlen] = NULL;
     782           2 :                                 continue;
     783             :                         }
     784             : 
     785          35 :                         r = extract_first_word_and_warn(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
     786          35 :                         if (r == 0)
     787           0 :                                 break;
     788          35 :                         if (r < 0)
     789           2 :                                 return ignore ? 0 : -ENOEXEC;
     790             : 
     791          33 :                         r = unit_full_printf(u, word, &resolved);
     792          33 :                         if (r < 0) {
     793           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r,
     794             :                                            "Failed to resolve unit specifiers in %s%s: %m",
     795             :                                            word, ignore ? ", ignoring" : "");
     796           0 :                                 return ignore ? 0 : -ENOEXEC;
     797             :                         }
     798             : 
     799          33 :                         if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
     800           0 :                                 return log_oom();
     801             : 
     802          33 :                         n[nlen++] = TAKE_PTR(resolved);
     803          33 :                         n[nlen] = NULL;
     804             :                 }
     805             : 
     806          58 :                 if (!n || !n[0]) {
     807           1 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
     808             :                                    "Empty executable name or zeroeth argument%s: %s",
     809             :                                    ignore ? ", ignoring" : "", rvalue);
     810           1 :                         return ignore ? 0 : -ENOEXEC;
     811             :                 }
     812             : 
     813          57 :                 nce = new0(ExecCommand, 1);
     814          57 :                 if (!nce)
     815           0 :                         return log_oom();
     816             : 
     817          57 :                 nce->argv = TAKE_PTR(n);
     818          57 :                 nce->path = TAKE_PTR(path);
     819          57 :                 nce->flags = flags;
     820             : 
     821          57 :                 exec_command_append_list(e, nce);
     822             : 
     823             :                 /* Do not _cleanup_free_ these. */
     824          57 :                 nce = NULL;
     825             : 
     826          57 :                 rvalue = p;
     827          57 :         } while (semicolon);
     828             : 
     829          53 :         return 0;
     830             : }
     831             : 
     832           0 : int config_parse_socket_bindtodevice(
     833             :                 const char* unit,
     834             :                 const char *filename,
     835             :                 unsigned line,
     836             :                 const char *section,
     837             :                 unsigned section_line,
     838             :                 const char *lvalue,
     839             :                 int ltype,
     840             :                 const char *rvalue,
     841             :                 void *data,
     842             :                 void *userdata) {
     843             : 
     844           0 :         Socket *s = data;
     845             : 
     846           0 :         assert(filename);
     847           0 :         assert(lvalue);
     848           0 :         assert(rvalue);
     849           0 :         assert(data);
     850             : 
     851           0 :         if (isempty(rvalue) || streq(rvalue, "*")) {
     852           0 :                 s->bind_to_device = mfree(s->bind_to_device);
     853           0 :                 return 0;
     854             :         }
     855             : 
     856           0 :         if (!ifname_valid(rvalue)) {
     857           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid interface name, ignoring: %s", rvalue);
     858           0 :                 return 0;
     859             :         }
     860             : 
     861           0 :         if (free_and_strdup(&s->bind_to_device, rvalue) < 0)
     862           0 :                 return log_oom();
     863             : 
     864           0 :         return 0;
     865             : }
     866             : 
     867           0 : int config_parse_exec_input(
     868             :                 const char *unit,
     869             :                 const char *filename,
     870             :                 unsigned line,
     871             :                 const char *section,
     872             :                 unsigned section_line,
     873             :                 const char *lvalue,
     874             :                 int ltype,
     875             :                 const char *rvalue,
     876             :                 void *data,
     877             :                 void *userdata) {
     878             : 
     879           0 :         ExecContext *c = data;
     880           0 :         Unit *u = userdata;
     881             :         const char *n;
     882             :         ExecInput ei;
     883             :         int r;
     884             : 
     885           0 :         assert(data);
     886           0 :         assert(filename);
     887           0 :         assert(line);
     888           0 :         assert(rvalue);
     889             : 
     890           0 :         n = startswith(rvalue, "fd:");
     891           0 :         if (n) {
     892           0 :                 _cleanup_free_ char *resolved = NULL;
     893             : 
     894           0 :                 r = unit_full_printf(u, n, &resolved);
     895           0 :                 if (r < 0)
     896           0 :                         return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", n);
     897             : 
     898           0 :                 if (isempty(resolved))
     899           0 :                         resolved = mfree(resolved);
     900           0 :                 else if (!fdname_is_valid(resolved)) {
     901           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
     902           0 :                         return -ENOEXEC;
     903             :                 }
     904             : 
     905           0 :                 free_and_replace(c->stdio_fdname[STDIN_FILENO], resolved);
     906             : 
     907           0 :                 ei = EXEC_INPUT_NAMED_FD;
     908             : 
     909           0 :         } else if ((n = startswith(rvalue, "file:"))) {
     910           0 :                 _cleanup_free_ char *resolved = NULL;
     911             : 
     912           0 :                 r = unit_full_printf(u, n, &resolved);
     913           0 :                 if (r < 0)
     914           0 :                         return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", n);
     915             : 
     916           0 :                 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
     917           0 :                 if (r < 0)
     918           0 :                         return -ENOEXEC;
     919             : 
     920           0 :                 free_and_replace(c->stdio_file[STDIN_FILENO], resolved);
     921             : 
     922           0 :                 ei = EXEC_INPUT_FILE;
     923             : 
     924             :         } else {
     925           0 :                 ei = exec_input_from_string(rvalue);
     926           0 :                 if (ei < 0) {
     927           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue);
     928           0 :                         return 0;
     929             :                 }
     930             :         }
     931             : 
     932           0 :         c->std_input = ei;
     933           0 :         return 0;
     934             : }
     935             : 
     936           0 : int config_parse_exec_input_text(
     937             :                 const char *unit,
     938             :                 const char *filename,
     939             :                 unsigned line,
     940             :                 const char *section,
     941             :                 unsigned section_line,
     942             :                 const char *lvalue,
     943             :                 int ltype,
     944             :                 const char *rvalue,
     945             :                 void *data,
     946             :                 void *userdata) {
     947             : 
     948           0 :         _cleanup_free_ char *unescaped = NULL, *resolved = NULL;
     949           0 :         ExecContext *c = data;
     950           0 :         Unit *u = userdata;
     951             :         size_t sz;
     952             :         void *p;
     953             :         int r;
     954             : 
     955           0 :         assert(data);
     956           0 :         assert(filename);
     957           0 :         assert(line);
     958           0 :         assert(rvalue);
     959             : 
     960           0 :         if (isempty(rvalue)) {
     961             :                 /* Reset if the empty string is assigned */
     962           0 :                 c->stdin_data = mfree(c->stdin_data);
     963           0 :                 c->stdin_data_size = 0;
     964           0 :                 return 0;
     965             :         }
     966             : 
     967           0 :         r = cunescape(rvalue, 0, &unescaped);
     968           0 :         if (r < 0)
     969           0 :                 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode C escaped text '%s': %m", rvalue);
     970             : 
     971           0 :         r = unit_full_printf(u, unescaped, &resolved);
     972           0 :         if (r < 0)
     973           0 :                 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s': %m", unescaped);
     974             : 
     975           0 :         sz = strlen(resolved);
     976           0 :         if (c->stdin_data_size + sz + 1 < c->stdin_data_size || /* check for overflow */
     977           0 :             c->stdin_data_size + sz + 1 > EXEC_STDIN_DATA_MAX) {
     978           0 :                 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);
     979           0 :                 return -E2BIG;
     980             :         }
     981             : 
     982           0 :         p = realloc(c->stdin_data, c->stdin_data_size + sz + 1);
     983           0 :         if (!p)
     984           0 :                 return log_oom();
     985             : 
     986           0 :         *((char*) mempcpy((char*) p + c->stdin_data_size, resolved, sz)) = '\n';
     987             : 
     988           0 :         c->stdin_data = p;
     989           0 :         c->stdin_data_size += sz + 1;
     990             : 
     991           0 :         return 0;
     992             : }
     993             : 
     994           0 : int config_parse_exec_input_data(
     995             :                 const char *unit,
     996             :                 const char *filename,
     997             :                 unsigned line,
     998             :                 const char *section,
     999             :                 unsigned section_line,
    1000             :                 const char *lvalue,
    1001             :                 int ltype,
    1002             :                 const char *rvalue,
    1003             :                 void *data,
    1004             :                 void *userdata) {
    1005             : 
    1006           0 :         _cleanup_free_ void *p = NULL;
    1007           0 :         ExecContext *c = data;
    1008             :         size_t sz;
    1009             :         void *q;
    1010             :         int r;
    1011             : 
    1012           0 :         assert(data);
    1013           0 :         assert(filename);
    1014           0 :         assert(line);
    1015           0 :         assert(rvalue);
    1016             : 
    1017           0 :         if (isempty(rvalue)) {
    1018             :                 /* Reset if the empty string is assigned */
    1019           0 :                 c->stdin_data = mfree(c->stdin_data);
    1020           0 :                 c->stdin_data_size = 0;
    1021           0 :                 return 0;
    1022             :         }
    1023             : 
    1024           0 :         r = unbase64mem(rvalue, (size_t) -1, &p, &sz);
    1025           0 :         if (r < 0)
    1026           0 :                 return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode base64 data, ignoring: %s", rvalue);
    1027             : 
    1028           0 :         assert(sz > 0);
    1029             : 
    1030           0 :         if (c->stdin_data_size + sz < c->stdin_data_size || /* check for overflow */
    1031           0 :             c->stdin_data_size + sz > EXEC_STDIN_DATA_MAX) {
    1032           0 :                 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);
    1033           0 :                 return -E2BIG;
    1034             :         }
    1035             : 
    1036           0 :         q = realloc(c->stdin_data, c->stdin_data_size + sz);
    1037           0 :         if (!q)
    1038           0 :                 return log_oom();
    1039             : 
    1040           0 :         memcpy((uint8_t*) q + c->stdin_data_size, p, sz);
    1041             : 
    1042           0 :         c->stdin_data = q;
    1043           0 :         c->stdin_data_size += sz;
    1044             : 
    1045           0 :         return 0;
    1046             : }
    1047             : 
    1048           0 : int config_parse_exec_output(
    1049             :                 const char *unit,
    1050             :                 const char *filename,
    1051             :                 unsigned line,
    1052             :                 const char *section,
    1053             :                 unsigned section_line,
    1054             :                 const char *lvalue,
    1055             :                 int ltype,
    1056             :                 const char *rvalue,
    1057             :                 void *data,
    1058             :                 void *userdata) {
    1059             : 
    1060           0 :         _cleanup_free_ char *resolved = NULL;
    1061             :         const char *n;
    1062           0 :         ExecContext *c = data;
    1063           0 :         Unit *u = userdata;
    1064             :         ExecOutput eo;
    1065             :         int r;
    1066             : 
    1067           0 :         assert(data);
    1068           0 :         assert(filename);
    1069           0 :         assert(line);
    1070           0 :         assert(lvalue);
    1071           0 :         assert(rvalue);
    1072             : 
    1073           0 :         n = startswith(rvalue, "fd:");
    1074           0 :         if (n) {
    1075           0 :                 r = unit_full_printf(u, n, &resolved);
    1076           0 :                 if (r < 0)
    1077           0 :                         return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
    1078             : 
    1079           0 :                 if (isempty(resolved))
    1080           0 :                         resolved = mfree(resolved);
    1081           0 :                 else if (!fdname_is_valid(resolved)) {
    1082           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name: %s", resolved);
    1083           0 :                         return -ENOEXEC;
    1084             :                 }
    1085             : 
    1086           0 :                 eo = EXEC_OUTPUT_NAMED_FD;
    1087             : 
    1088           0 :         } else if ((n = startswith(rvalue, "file:"))) {
    1089             : 
    1090           0 :                 r = unit_full_printf(u, n, &resolved);
    1091           0 :                 if (r < 0)
    1092           0 :                         return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
    1093             : 
    1094           0 :                 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
    1095           0 :                 if (r < 0)
    1096           0 :                         return -ENOEXEC;
    1097             : 
    1098           0 :                 eo = EXEC_OUTPUT_FILE;
    1099             : 
    1100           0 :         } else if ((n = startswith(rvalue, "append:"))) {
    1101             : 
    1102           0 :                 r = unit_full_printf(u, n, &resolved);
    1103           0 :                 if (r < 0)
    1104           0 :                         return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n);
    1105             : 
    1106           0 :                 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue);
    1107           0 :                 if (r < 0)
    1108           0 :                         return -ENOEXEC;
    1109             : 
    1110           0 :                 eo = EXEC_OUTPUT_FILE_APPEND;
    1111             :         } else {
    1112           0 :                 eo = exec_output_from_string(rvalue);
    1113           0 :                 if (eo < 0) {
    1114           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue);
    1115           0 :                         return 0;
    1116             :                 }
    1117             :         }
    1118             : 
    1119           0 :         if (streq(lvalue, "StandardOutput")) {
    1120           0 :                 if (eo == EXEC_OUTPUT_NAMED_FD)
    1121           0 :                         free_and_replace(c->stdio_fdname[STDOUT_FILENO], resolved);
    1122             :                 else
    1123           0 :                         free_and_replace(c->stdio_file[STDOUT_FILENO], resolved);
    1124             : 
    1125           0 :                 c->std_output = eo;
    1126             : 
    1127             :         } else {
    1128           0 :                 assert(streq(lvalue, "StandardError"));
    1129             : 
    1130           0 :                 if (eo == EXEC_OUTPUT_NAMED_FD)
    1131           0 :                         free_and_replace(c->stdio_fdname[STDERR_FILENO], resolved);
    1132             :                 else
    1133           0 :                         free_and_replace(c->stdio_file[STDERR_FILENO], resolved);
    1134             : 
    1135           0 :                 c->std_error = eo;
    1136             :         }
    1137             : 
    1138           0 :         return 0;
    1139             : }
    1140             : 
    1141           0 : int config_parse_exec_io_class(const char *unit,
    1142             :                                const char *filename,
    1143             :                                unsigned line,
    1144             :                                const char *section,
    1145             :                                unsigned section_line,
    1146             :                                const char *lvalue,
    1147             :                                int ltype,
    1148             :                                const char *rvalue,
    1149             :                                void *data,
    1150             :                                void *userdata) {
    1151             : 
    1152           0 :         ExecContext *c = data;
    1153             :         int x;
    1154             : 
    1155           0 :         assert(filename);
    1156           0 :         assert(lvalue);
    1157           0 :         assert(rvalue);
    1158           0 :         assert(data);
    1159             : 
    1160           0 :         if (isempty(rvalue)) {
    1161           0 :                 c->ioprio_set = false;
    1162           0 :                 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
    1163           0 :                 return 0;
    1164             :         }
    1165             : 
    1166           0 :         x = ioprio_class_from_string(rvalue);
    1167           0 :         if (x < 0) {
    1168           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
    1169           0 :                 return 0;
    1170             :         }
    1171             : 
    1172           0 :         c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
    1173           0 :         c->ioprio_set = true;
    1174             : 
    1175           0 :         return 0;
    1176             : }
    1177             : 
    1178           0 : int config_parse_exec_io_priority(const char *unit,
    1179             :                                   const char *filename,
    1180             :                                   unsigned line,
    1181             :                                   const char *section,
    1182             :                                   unsigned section_line,
    1183             :                                   const char *lvalue,
    1184             :                                   int ltype,
    1185             :                                   const char *rvalue,
    1186             :                                   void *data,
    1187             :                                   void *userdata) {
    1188             : 
    1189           0 :         ExecContext *c = data;
    1190             :         int i, r;
    1191             : 
    1192           0 :         assert(filename);
    1193           0 :         assert(lvalue);
    1194           0 :         assert(rvalue);
    1195           0 :         assert(data);
    1196             : 
    1197           0 :         if (isempty(rvalue)) {
    1198           0 :                 c->ioprio_set = false;
    1199           0 :                 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
    1200           0 :                 return 0;
    1201             :         }
    1202             : 
    1203           0 :         r = ioprio_parse_priority(rvalue, &i);
    1204           0 :         if (r < 0) {
    1205           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
    1206           0 :                 return 0;
    1207             :         }
    1208             : 
    1209           0 :         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
    1210           0 :         c->ioprio_set = true;
    1211             : 
    1212           0 :         return 0;
    1213             : }
    1214             : 
    1215           3 : int config_parse_exec_cpu_sched_policy(const char *unit,
    1216             :                                        const char *filename,
    1217             :                                        unsigned line,
    1218             :                                        const char *section,
    1219             :                                        unsigned section_line,
    1220             :                                        const char *lvalue,
    1221             :                                        int ltype,
    1222             :                                        const char *rvalue,
    1223             :                                        void *data,
    1224             :                                        void *userdata) {
    1225             : 
    1226           3 :         ExecContext *c = data;
    1227             :         int x;
    1228             : 
    1229           3 :         assert(filename);
    1230           3 :         assert(lvalue);
    1231           3 :         assert(rvalue);
    1232           3 :         assert(data);
    1233             : 
    1234           3 :         if (isempty(rvalue)) {
    1235           0 :                 c->cpu_sched_set = false;
    1236           0 :                 c->cpu_sched_policy = SCHED_OTHER;
    1237           0 :                 c->cpu_sched_priority = 0;
    1238           0 :                 return 0;
    1239             :         }
    1240             : 
    1241           3 :         x = sched_policy_from_string(rvalue);
    1242           3 :         if (x < 0) {
    1243           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
    1244           0 :                 return 0;
    1245             :         }
    1246             : 
    1247           3 :         c->cpu_sched_policy = x;
    1248             :         /* Moving to or from real-time policy? We need to adjust the priority */
    1249           3 :         c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
    1250           3 :         c->cpu_sched_set = true;
    1251             : 
    1252           3 :         return 0;
    1253             : }
    1254             : 
    1255           0 : int config_parse_numa_mask(const char *unit,
    1256             :                            const char *filename,
    1257             :                            unsigned line,
    1258             :                            const char *section,
    1259             :                            unsigned section_line,
    1260             :                            const char *lvalue,
    1261             :                            int ltype,
    1262             :                            const char *rvalue,
    1263             :                            void *data,
    1264             :                            void *userdata) {
    1265             :         int r;
    1266           0 :         NUMAPolicy *p = data;
    1267             : 
    1268           0 :         assert(filename);
    1269           0 :         assert(lvalue);
    1270           0 :         assert(rvalue);
    1271           0 :         assert(data);
    1272             : 
    1273           0 :         r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue);
    1274           0 :         if (r < 0) {
    1275           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue);
    1276           0 :                 return 0;
    1277             :         }
    1278             : 
    1279           0 :         return r;
    1280             : }
    1281             : 
    1282           7 : int config_parse_exec_cpu_sched_prio(const char *unit,
    1283             :                                      const char *filename,
    1284             :                                      unsigned line,
    1285             :                                      const char *section,
    1286             :                                      unsigned section_line,
    1287             :                                      const char *lvalue,
    1288             :                                      int ltype,
    1289             :                                      const char *rvalue,
    1290             :                                      void *data,
    1291             :                                      void *userdata) {
    1292             : 
    1293           7 :         ExecContext *c = data;
    1294             :         int i, min, max, r;
    1295             : 
    1296           7 :         assert(filename);
    1297           7 :         assert(lvalue);
    1298           7 :         assert(rvalue);
    1299           7 :         assert(data);
    1300             : 
    1301           7 :         r = safe_atoi(rvalue, &i);
    1302           7 :         if (r < 0) {
    1303           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling priority, ignoring: %s", rvalue);
    1304           0 :                 return 0;
    1305             :         }
    1306             : 
    1307             :         /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
    1308           7 :         min = sched_get_priority_min(c->cpu_sched_policy);
    1309           7 :         max = sched_get_priority_max(c->cpu_sched_policy);
    1310             : 
    1311           7 :         if (i < min || i > max) {
    1312           3 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
    1313           3 :                 return 0;
    1314             :         }
    1315             : 
    1316           4 :         c->cpu_sched_priority = i;
    1317           4 :         c->cpu_sched_set = true;
    1318             : 
    1319           4 :         return 0;
    1320             : }
    1321             : 
    1322           0 : int config_parse_exec_cpu_affinity(const char *unit,
    1323             :                                    const char *filename,
    1324             :                                    unsigned line,
    1325             :                                    const char *section,
    1326             :                                    unsigned section_line,
    1327             :                                    const char *lvalue,
    1328             :                                    int ltype,
    1329             :                                    const char *rvalue,
    1330             :                                    void *data,
    1331             :                                    void *userdata) {
    1332             : 
    1333           0 :         ExecContext *c = data;
    1334             : 
    1335           0 :         assert(filename);
    1336           0 :         assert(lvalue);
    1337           0 :         assert(rvalue);
    1338           0 :         assert(data);
    1339             : 
    1340           0 :         return parse_cpu_set_extend(rvalue, &c->cpu_set, true, unit, filename, line, lvalue);
    1341             : }
    1342             : 
    1343           6 : int config_parse_capability_set(
    1344             :                 const char *unit,
    1345             :                 const char *filename,
    1346             :                 unsigned line,
    1347             :                 const char *section,
    1348             :                 unsigned section_line,
    1349             :                 const char *lvalue,
    1350             :                 int ltype,
    1351             :                 const char *rvalue,
    1352             :                 void *data,
    1353             :                 void *userdata) {
    1354             : 
    1355           6 :         uint64_t *capability_set = data;
    1356           6 :         uint64_t sum = 0, initial = 0;
    1357           6 :         bool invert = false;
    1358             :         int r;
    1359             : 
    1360           6 :         assert(filename);
    1361           6 :         assert(lvalue);
    1362           6 :         assert(rvalue);
    1363           6 :         assert(data);
    1364             : 
    1365           6 :         if (rvalue[0] == '~') {
    1366           2 :                 invert = true;
    1367           2 :                 rvalue++;
    1368             :         }
    1369             : 
    1370           6 :         if (streq(lvalue, "CapabilityBoundingSet"))
    1371           6 :                 initial = CAP_ALL; /* initialized to all bits on */
    1372             :         /* else "AmbientCapabilities" initialized to all bits off */
    1373             : 
    1374           6 :         r = capability_set_from_string(rvalue, &sum);
    1375           6 :         if (r < 0) {
    1376           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= specifier '%s', ignoring: %m", lvalue, rvalue);
    1377           0 :                 return 0;
    1378             :         }
    1379             : 
    1380           6 :         if (sum == 0 || *capability_set == initial)
    1381             :                 /* "", "~" or uninitialized data -> replace */
    1382           2 :                 *capability_set = invert ? ~sum : sum;
    1383             :         else {
    1384             :                 /* previous data -> merge */
    1385           4 :                 if (invert)
    1386           1 :                         *capability_set &= ~sum;
    1387             :                 else
    1388           3 :                         *capability_set |= sum;
    1389             :         }
    1390             : 
    1391           6 :         return 0;
    1392             : }
    1393             : 
    1394           0 : int config_parse_exec_selinux_context(
    1395             :                 const char *unit,
    1396             :                 const char *filename,
    1397             :                 unsigned line,
    1398             :                 const char *section,
    1399             :                 unsigned section_line,
    1400             :                 const char *lvalue,
    1401             :                 int ltype,
    1402             :                 const char *rvalue,
    1403             :                 void *data,
    1404             :                 void *userdata) {
    1405             : 
    1406           0 :         ExecContext *c = data;
    1407           0 :         Unit *u = userdata;
    1408             :         bool ignore;
    1409             :         char *k;
    1410             :         int r;
    1411             : 
    1412           0 :         assert(filename);
    1413           0 :         assert(lvalue);
    1414           0 :         assert(rvalue);
    1415           0 :         assert(data);
    1416             : 
    1417           0 :         if (isempty(rvalue)) {
    1418           0 :                 c->selinux_context = mfree(c->selinux_context);
    1419           0 :                 c->selinux_context_ignore = false;
    1420           0 :                 return 0;
    1421             :         }
    1422             : 
    1423           0 :         if (rvalue[0] == '-') {
    1424           0 :                 ignore = true;
    1425           0 :                 rvalue++;
    1426             :         } else
    1427           0 :                 ignore = false;
    1428             : 
    1429           0 :         r = unit_full_printf(u, rvalue, &k);
    1430           0 :         if (r < 0) {
    1431           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
    1432             :                            "Failed to resolve unit specifiers in '%s'%s: %m",
    1433             :                            rvalue, ignore ? ", ignoring" : "");
    1434           0 :                 return ignore ? 0 : -ENOEXEC;
    1435             :         }
    1436             : 
    1437           0 :         free_and_replace(c->selinux_context, k);
    1438           0 :         c->selinux_context_ignore = ignore;
    1439             : 
    1440           0 :         return 0;
    1441             : }
    1442             : 
    1443           0 : int config_parse_exec_apparmor_profile(
    1444             :                 const char *unit,
    1445             :                 const char *filename,
    1446             :                 unsigned line,
    1447             :                 const char *section,
    1448             :                 unsigned section_line,
    1449             :                 const char *lvalue,
    1450             :                 int ltype,
    1451             :                 const char *rvalue,
    1452             :                 void *data,
    1453             :                 void *userdata) {
    1454             : 
    1455           0 :         ExecContext *c = data;
    1456           0 :         Unit *u = userdata;
    1457             :         bool ignore;
    1458             :         char *k;
    1459             :         int r;
    1460             : 
    1461           0 :         assert(filename);
    1462           0 :         assert(lvalue);
    1463           0 :         assert(rvalue);
    1464           0 :         assert(data);
    1465             : 
    1466           0 :         if (isempty(rvalue)) {
    1467           0 :                 c->apparmor_profile = mfree(c->apparmor_profile);
    1468           0 :                 c->apparmor_profile_ignore = false;
    1469           0 :                 return 0;
    1470             :         }
    1471             : 
    1472           0 :         if (rvalue[0] == '-') {
    1473           0 :                 ignore = true;
    1474           0 :                 rvalue++;
    1475             :         } else
    1476           0 :                 ignore = false;
    1477             : 
    1478           0 :         r = unit_full_printf(u, rvalue, &k);
    1479           0 :         if (r < 0) {
    1480           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
    1481             :                            "Failed to resolve unit specifiers in '%s'%s: %m",
    1482             :                            rvalue, ignore ? ", ignoring" : "");
    1483           0 :                 return ignore ? 0 : -ENOEXEC;
    1484             :         }
    1485             : 
    1486           0 :         free_and_replace(c->apparmor_profile, k);
    1487           0 :         c->apparmor_profile_ignore = ignore;
    1488             : 
    1489           0 :         return 0;
    1490             : }
    1491             : 
    1492           0 : int config_parse_exec_smack_process_label(
    1493             :                 const char *unit,
    1494             :                 const char *filename,
    1495             :                 unsigned line,
    1496             :                 const char *section,
    1497             :                 unsigned section_line,
    1498             :                 const char *lvalue,
    1499             :                 int ltype,
    1500             :                 const char *rvalue,
    1501             :                 void *data,
    1502             :                 void *userdata) {
    1503             : 
    1504           0 :         ExecContext *c = data;
    1505           0 :         Unit *u = userdata;
    1506             :         bool ignore;
    1507             :         char *k;
    1508             :         int r;
    1509             : 
    1510           0 :         assert(filename);
    1511           0 :         assert(lvalue);
    1512           0 :         assert(rvalue);
    1513           0 :         assert(data);
    1514             : 
    1515           0 :         if (isempty(rvalue)) {
    1516           0 :                 c->smack_process_label = mfree(c->smack_process_label);
    1517           0 :                 c->smack_process_label_ignore = false;
    1518           0 :                 return 0;
    1519             :         }
    1520             : 
    1521           0 :         if (rvalue[0] == '-') {
    1522           0 :                 ignore = true;
    1523           0 :                 rvalue++;
    1524             :         } else
    1525           0 :                 ignore = false;
    1526             : 
    1527           0 :         r = unit_full_printf(u, rvalue, &k);
    1528           0 :         if (r < 0) {
    1529           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
    1530             :                            "Failed to resolve unit specifiers in '%s'%s: %m",
    1531             :                            rvalue, ignore ? ", ignoring" : "");
    1532           0 :                 return ignore ? 0 : -ENOEXEC;
    1533             :         }
    1534             : 
    1535           0 :         free_and_replace(c->smack_process_label, k);
    1536           0 :         c->smack_process_label_ignore = ignore;
    1537             : 
    1538           0 :         return 0;
    1539             : }
    1540             : 
    1541           0 : int config_parse_timer(
    1542             :                 const char *unit,
    1543             :                 const char *filename,
    1544             :                 unsigned line,
    1545             :                 const char *section,
    1546             :                 unsigned section_line,
    1547             :                 const char *lvalue,
    1548             :                 int ltype,
    1549             :                 const char *rvalue,
    1550             :                 void *data,
    1551             :                 void *userdata) {
    1552             : 
    1553           0 :         _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
    1554           0 :         _cleanup_free_ char *k = NULL;
    1555           0 :         Unit *u = userdata;
    1556           0 :         Timer *t = data;
    1557           0 :         usec_t usec = 0;
    1558             :         TimerValue *v;
    1559             :         int r;
    1560             : 
    1561           0 :         assert(filename);
    1562           0 :         assert(lvalue);
    1563           0 :         assert(rvalue);
    1564           0 :         assert(data);
    1565             : 
    1566           0 :         if (isempty(rvalue)) {
    1567             :                 /* Empty assignment resets list */
    1568           0 :                 timer_free_values(t);
    1569           0 :                 return 0;
    1570             :         }
    1571             : 
    1572           0 :         r = unit_full_printf(u, rvalue, &k);
    1573           0 :         if (r < 0) {
    1574           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
    1575           0 :                 return 0;
    1576             :         }
    1577             : 
    1578           0 :         if (ltype == TIMER_CALENDAR) {
    1579           0 :                 r = calendar_spec_from_string(k, &c);
    1580           0 :                 if (r < 0) {
    1581           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse calendar specification, ignoring: %s", k);
    1582           0 :                         return 0;
    1583             :                 }
    1584             :         } else {
    1585           0 :                 r = parse_sec(k, &usec);
    1586           0 :                 if (r < 0) {
    1587           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse timer value, ignoring: %s", k);
    1588           0 :                         return 0;
    1589             :                 }
    1590             :         }
    1591             : 
    1592           0 :         v = new(TimerValue, 1);
    1593           0 :         if (!v)
    1594           0 :                 return log_oom();
    1595             : 
    1596           0 :         *v = (TimerValue) {
    1597             :                 .base = ltype,
    1598             :                 .value = usec,
    1599           0 :                 .calendar_spec = TAKE_PTR(c),
    1600             :         };
    1601             : 
    1602           0 :         LIST_PREPEND(value, t->values, v);
    1603             : 
    1604           0 :         return 0;
    1605             : }
    1606             : 
    1607           1 : int config_parse_trigger_unit(
    1608             :                 const char *unit,
    1609             :                 const char *filename,
    1610             :                 unsigned line,
    1611             :                 const char *section,
    1612             :                 unsigned section_line,
    1613             :                 const char *lvalue,
    1614             :                 int ltype,
    1615             :                 const char *rvalue,
    1616             :                 void *data,
    1617             :                 void *userdata) {
    1618             : 
    1619           1 :         _cleanup_free_ char *p = NULL;
    1620           1 :         Unit *u = data;
    1621             :         UnitType type;
    1622             :         int r;
    1623             : 
    1624           1 :         assert(filename);
    1625           1 :         assert(lvalue);
    1626           1 :         assert(rvalue);
    1627           1 :         assert(data);
    1628             : 
    1629           1 :         if (!hashmap_isempty(u->dependencies[UNIT_TRIGGERS])) {
    1630           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
    1631           0 :                 return 0;
    1632             :         }
    1633             : 
    1634           1 :         r = unit_name_printf(u, rvalue, &p);
    1635           1 :         if (r < 0) {
    1636           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
    1637           0 :                 return 0;
    1638             :         }
    1639             : 
    1640           1 :         type = unit_name_to_type(p);
    1641           1 :         if (type < 0) {
    1642           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
    1643           0 :                 return 0;
    1644             :         }
    1645           1 :         if (unit_has_name(u, p)) {
    1646           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Units cannot trigger themselves, ignoring: %s", rvalue);
    1647           0 :                 return 0;
    1648             :         }
    1649             : 
    1650           1 :         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, true, UNIT_DEPENDENCY_FILE);
    1651           1 :         if (r < 0) {
    1652           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
    1653           0 :                 return 0;
    1654             :         }
    1655             : 
    1656           1 :         return 0;
    1657             : }
    1658             : 
    1659           7 : int config_parse_path_spec(const char *unit,
    1660             :                            const char *filename,
    1661             :                            unsigned line,
    1662             :                            const char *section,
    1663             :                            unsigned section_line,
    1664             :                            const char *lvalue,
    1665             :                            int ltype,
    1666             :                            const char *rvalue,
    1667             :                            void *data,
    1668             :                            void *userdata) {
    1669             : 
    1670           7 :         Path *p = data;
    1671             :         PathSpec *s;
    1672             :         PathType b;
    1673           7 :         _cleanup_free_ char *k = NULL;
    1674             :         int r;
    1675             : 
    1676           7 :         assert(filename);
    1677           7 :         assert(lvalue);
    1678           7 :         assert(rvalue);
    1679           7 :         assert(data);
    1680             : 
    1681           7 :         if (isempty(rvalue)) {
    1682             :                 /* Empty assignment clears list */
    1683           0 :                 path_free_specs(p);
    1684           0 :                 return 0;
    1685             :         }
    1686             : 
    1687           7 :         b = path_type_from_string(lvalue);
    1688           7 :         if (b < 0) {
    1689           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
    1690           0 :                 return 0;
    1691             :         }
    1692             : 
    1693           7 :         r = unit_full_printf(UNIT(p), rvalue, &k);
    1694           7 :         if (r < 0) {
    1695           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
    1696           0 :                 return 0;
    1697             :         }
    1698             : 
    1699           7 :         r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    1700           7 :         if (r < 0)
    1701           0 :                 return 0;
    1702             : 
    1703           7 :         s = new0(PathSpec, 1);
    1704           7 :         if (!s)
    1705           0 :                 return log_oom();
    1706             : 
    1707           7 :         s->unit = UNIT(p);
    1708           7 :         s->path = TAKE_PTR(k);
    1709           7 :         s->type = b;
    1710           7 :         s->inotify_fd = -1;
    1711             : 
    1712           7 :         LIST_PREPEND(spec, p->specs, s);
    1713             : 
    1714           7 :         return 0;
    1715             : }
    1716             : 
    1717           0 : int config_parse_socket_service(
    1718             :                 const char *unit,
    1719             :                 const char *filename,
    1720             :                 unsigned line,
    1721             :                 const char *section,
    1722             :                 unsigned section_line,
    1723             :                 const char *lvalue,
    1724             :                 int ltype,
    1725             :                 const char *rvalue,
    1726             :                 void *data,
    1727             :                 void *userdata) {
    1728             : 
    1729           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1730           0 :         _cleanup_free_ char *p = NULL;
    1731           0 :         Socket *s = data;
    1732             :         Unit *x;
    1733             :         int r;
    1734             : 
    1735           0 :         assert(filename);
    1736           0 :         assert(lvalue);
    1737           0 :         assert(rvalue);
    1738           0 :         assert(data);
    1739             : 
    1740           0 :         r = unit_name_printf(UNIT(s), rvalue, &p);
    1741           0 :         if (r < 0) {
    1742           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
    1743           0 :                 return -ENOEXEC;
    1744             :         }
    1745             : 
    1746           0 :         if (!endswith(p, ".service")) {
    1747           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service: %s", rvalue);
    1748           0 :                 return -ENOEXEC;
    1749             :         }
    1750             : 
    1751           0 :         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
    1752           0 :         if (r < 0) {
    1753           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s: %s", rvalue, bus_error_message(&error, r));
    1754           0 :                 return -ENOEXEC;
    1755             :         }
    1756             : 
    1757           0 :         unit_ref_set(&s->service, UNIT(s), x);
    1758             : 
    1759           0 :         return 0;
    1760             : }
    1761             : 
    1762           0 : int config_parse_fdname(
    1763             :                 const char *unit,
    1764             :                 const char *filename,
    1765             :                 unsigned line,
    1766             :                 const char *section,
    1767             :                 unsigned section_line,
    1768             :                 const char *lvalue,
    1769             :                 int ltype,
    1770             :                 const char *rvalue,
    1771             :                 void *data,
    1772             :                 void *userdata) {
    1773             : 
    1774           0 :         _cleanup_free_ char *p = NULL;
    1775           0 :         Socket *s = data;
    1776             :         int r;
    1777             : 
    1778           0 :         assert(filename);
    1779           0 :         assert(lvalue);
    1780           0 :         assert(rvalue);
    1781           0 :         assert(data);
    1782             : 
    1783           0 :         if (isempty(rvalue)) {
    1784           0 :                 s->fdname = mfree(s->fdname);
    1785           0 :                 return 0;
    1786             :         }
    1787             : 
    1788           0 :         r = unit_full_printf(UNIT(s), rvalue, &p);
    1789           0 :         if (r < 0) {
    1790           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
    1791           0 :                 return 0;
    1792             :         }
    1793             : 
    1794           0 :         if (!fdname_is_valid(p)) {
    1795           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
    1796           0 :                 return 0;
    1797             :         }
    1798             : 
    1799           0 :         return free_and_replace(s->fdname, p);
    1800             : }
    1801             : 
    1802           0 : int config_parse_service_sockets(
    1803             :                 const char *unit,
    1804             :                 const char *filename,
    1805             :                 unsigned line,
    1806             :                 const char *section,
    1807             :                 unsigned section_line,
    1808             :                 const char *lvalue,
    1809             :                 int ltype,
    1810             :                 const char *rvalue,
    1811             :                 void *data,
    1812             :                 void *userdata) {
    1813             : 
    1814           0 :         Service *s = data;
    1815             :         const char *p;
    1816             :         int r;
    1817             : 
    1818           0 :         assert(filename);
    1819           0 :         assert(lvalue);
    1820           0 :         assert(rvalue);
    1821           0 :         assert(data);
    1822             : 
    1823           0 :         p = rvalue;
    1824           0 :         for (;;) {
    1825           0 :                 _cleanup_free_ char *word = NULL, *k = NULL;
    1826             : 
    1827           0 :                 r = extract_first_word(&p, &word, NULL, 0);
    1828           0 :                 if (r == 0)
    1829           0 :                         break;
    1830           0 :                 if (r == -ENOMEM)
    1831           0 :                         return log_oom();
    1832           0 :                 if (r < 0) {
    1833           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
    1834           0 :                         break;
    1835             :                 }
    1836             : 
    1837           0 :                 r = unit_name_printf(UNIT(s), word, &k);
    1838           0 :                 if (r < 0) {
    1839           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
    1840           0 :                         continue;
    1841             :                 }
    1842             : 
    1843           0 :                 if (!endswith(k, ".socket")) {
    1844           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
    1845           0 :                         continue;
    1846             :                 }
    1847             : 
    1848           0 :                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, true, UNIT_DEPENDENCY_FILE);
    1849           0 :                 if (r < 0)
    1850           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
    1851             : 
    1852           0 :                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, true, UNIT_DEPENDENCY_FILE);
    1853           0 :                 if (r < 0)
    1854           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
    1855             :         }
    1856             : 
    1857           0 :         return 0;
    1858             : }
    1859             : 
    1860           0 : int config_parse_bus_name(
    1861             :                 const char *unit,
    1862             :                 const char *filename,
    1863             :                 unsigned line,
    1864             :                 const char *section,
    1865             :                 unsigned section_line,
    1866             :                 const char *lvalue,
    1867             :                 int ltype,
    1868             :                 const char *rvalue,
    1869             :                 void *data,
    1870             :                 void *userdata) {
    1871             : 
    1872           0 :         _cleanup_free_ char *k = NULL;
    1873           0 :         Unit *u = userdata;
    1874             :         int r;
    1875             : 
    1876           0 :         assert(filename);
    1877           0 :         assert(lvalue);
    1878           0 :         assert(rvalue);
    1879           0 :         assert(u);
    1880             : 
    1881           0 :         r = unit_full_printf(u, rvalue, &k);
    1882           0 :         if (r < 0) {
    1883           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
    1884           0 :                 return 0;
    1885             :         }
    1886             : 
    1887           0 :         if (!service_name_is_valid(k)) {
    1888           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name, ignoring: %s", k);
    1889           0 :                 return 0;
    1890             :         }
    1891             : 
    1892           0 :         return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
    1893             : }
    1894             : 
    1895           0 : int config_parse_service_timeout(
    1896             :                 const char *unit,
    1897             :                 const char *filename,
    1898             :                 unsigned line,
    1899             :                 const char *section,
    1900             :                 unsigned section_line,
    1901             :                 const char *lvalue,
    1902             :                 int ltype,
    1903             :                 const char *rvalue,
    1904             :                 void *data,
    1905             :                 void *userdata) {
    1906             : 
    1907           0 :         Service *s = userdata;
    1908             :         usec_t usec;
    1909             :         int r;
    1910             : 
    1911           0 :         assert(filename);
    1912           0 :         assert(lvalue);
    1913           0 :         assert(rvalue);
    1914           0 :         assert(s);
    1915             : 
    1916             :         /* This is called for two cases: TimeoutSec= and TimeoutStartSec=. */
    1917             : 
    1918             :         /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
    1919             :          * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
    1920             :          * all other timeouts. */
    1921           0 :         r = parse_sec_fix_0(rvalue, &usec);
    1922           0 :         if (r < 0) {
    1923           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
    1924           0 :                 return 0;
    1925             :         }
    1926             : 
    1927           0 :         s->start_timeout_defined = true;
    1928           0 :         s->timeout_start_usec = usec;
    1929             : 
    1930           0 :         if (streq(lvalue, "TimeoutSec"))
    1931           0 :                 s->timeout_stop_usec = usec;
    1932             : 
    1933           0 :         return 0;
    1934             : }
    1935             : 
    1936           0 : int config_parse_service_timeout_abort(
    1937             :                 const char *unit,
    1938             :                 const char *filename,
    1939             :                 unsigned line,
    1940             :                 const char *section,
    1941             :                 unsigned section_line,
    1942             :                 const char *lvalue,
    1943             :                 int ltype,
    1944             :                 const char *rvalue,
    1945             :                 void *data,
    1946             :                 void *userdata) {
    1947             : 
    1948           0 :         Service *s = userdata;
    1949             :         int r;
    1950             : 
    1951           0 :         assert(filename);
    1952           0 :         assert(lvalue);
    1953           0 :         assert(rvalue);
    1954           0 :         assert(s);
    1955             : 
    1956           0 :         rvalue += strspn(rvalue, WHITESPACE);
    1957           0 :         if (isempty(rvalue)) {
    1958           0 :                 s->timeout_abort_set = false;
    1959           0 :                 return 0;
    1960             :         }
    1961             : 
    1962           0 :         r = parse_sec(rvalue, &s->timeout_abort_usec);
    1963           0 :         if (r < 0) {
    1964           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse TimeoutAbortSec= setting, ignoring: %s", rvalue);
    1965           0 :                 return 0;
    1966             :         }
    1967             : 
    1968           0 :         s->timeout_abort_set = true;
    1969           0 :         return 0;
    1970             : }
    1971             : 
    1972           0 : int config_parse_sec_fix_0(
    1973             :                 const char *unit,
    1974             :                 const char *filename,
    1975             :                 unsigned line,
    1976             :                 const char *section,
    1977             :                 unsigned section_line,
    1978             :                 const char *lvalue,
    1979             :                 int ltype,
    1980             :                 const char *rvalue,
    1981             :                 void *data,
    1982             :                 void *userdata) {
    1983             : 
    1984           0 :         usec_t *usec = data;
    1985             :         int r;
    1986             : 
    1987           0 :         assert(filename);
    1988           0 :         assert(lvalue);
    1989           0 :         assert(rvalue);
    1990           0 :         assert(usec);
    1991             : 
    1992             :         /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
    1993             :          * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
    1994             :          * timeout. */
    1995             : 
    1996           0 :         r = parse_sec_fix_0(rvalue, usec);
    1997           0 :         if (r < 0) {
    1998           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
    1999           0 :                 return 0;
    2000             :         }
    2001             : 
    2002           0 :         return 0;
    2003             : }
    2004             : 
    2005           0 : int config_parse_user_group(
    2006             :                 const char *unit,
    2007             :                 const char *filename,
    2008             :                 unsigned line,
    2009             :                 const char *section,
    2010             :                 unsigned section_line,
    2011             :                 const char *lvalue,
    2012             :                 int ltype,
    2013             :                 const char *rvalue,
    2014             :                 void *data,
    2015             :                 void *userdata) {
    2016             : 
    2017           0 :         _cleanup_free_ char *k = NULL;
    2018           0 :         char **user = data;
    2019           0 :         Unit *u = userdata;
    2020             :         int r;
    2021             : 
    2022           0 :         assert(filename);
    2023           0 :         assert(lvalue);
    2024           0 :         assert(rvalue);
    2025           0 :         assert(u);
    2026             : 
    2027           0 :         if (isempty(rvalue)) {
    2028           0 :                 *user = mfree(*user);
    2029           0 :                 return 0;
    2030             :         }
    2031             : 
    2032           0 :         r = unit_full_printf(u, rvalue, &k);
    2033           0 :         if (r < 0) {
    2034           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", rvalue);
    2035           0 :                 return -ENOEXEC;
    2036             :         }
    2037             : 
    2038           0 :         if (!valid_user_group_name_or_id(k)) {
    2039           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
    2040           0 :                 return -ENOEXEC;
    2041             :         }
    2042             : 
    2043           0 :         return free_and_replace(*user, k);
    2044             : }
    2045             : 
    2046           0 : int config_parse_user_group_strv(
    2047             :                 const char *unit,
    2048             :                 const char *filename,
    2049             :                 unsigned line,
    2050             :                 const char *section,
    2051             :                 unsigned section_line,
    2052             :                 const char *lvalue,
    2053             :                 int ltype,
    2054             :                 const char *rvalue,
    2055             :                 void *data,
    2056             :                 void *userdata) {
    2057             : 
    2058           0 :         char ***users = data;
    2059           0 :         Unit *u = userdata;
    2060           0 :         const char *p = rvalue;
    2061             :         int r;
    2062             : 
    2063           0 :         assert(filename);
    2064           0 :         assert(lvalue);
    2065           0 :         assert(rvalue);
    2066           0 :         assert(u);
    2067             : 
    2068           0 :         if (isempty(rvalue)) {
    2069           0 :                 *users = strv_free(*users);
    2070           0 :                 return 0;
    2071             :         }
    2072             : 
    2073           0 :         for (;;) {
    2074           0 :                 _cleanup_free_ char *word = NULL, *k = NULL;
    2075             : 
    2076           0 :                 r = extract_first_word(&p, &word, NULL, 0);
    2077           0 :                 if (r == 0)
    2078           0 :                         break;
    2079           0 :                 if (r == -ENOMEM)
    2080           0 :                         return log_oom();
    2081           0 :                 if (r < 0) {
    2082           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax: %s", rvalue);
    2083           0 :                         return -ENOEXEC;
    2084             :                 }
    2085             : 
    2086           0 :                 r = unit_full_printf(u, word, &k);
    2087           0 :                 if (r < 0) {
    2088           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", word);
    2089           0 :                         return -ENOEXEC;
    2090             :                 }
    2091             : 
    2092           0 :                 if (!valid_user_group_name_or_id(k)) {
    2093           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
    2094           0 :                         return -ENOEXEC;
    2095             :                 }
    2096             : 
    2097           0 :                 r = strv_push(users, k);
    2098           0 :                 if (r < 0)
    2099           0 :                         return log_oom();
    2100             : 
    2101           0 :                 k = NULL;
    2102             :         }
    2103             : 
    2104           0 :         return 0;
    2105             : }
    2106             : 
    2107           0 : int config_parse_working_directory(
    2108             :                 const char *unit,
    2109             :                 const char *filename,
    2110             :                 unsigned line,
    2111             :                 const char *section,
    2112             :                 unsigned section_line,
    2113             :                 const char *lvalue,
    2114             :                 int ltype,
    2115             :                 const char *rvalue,
    2116             :                 void *data,
    2117             :                 void *userdata) {
    2118             : 
    2119           0 :         ExecContext *c = data;
    2120           0 :         Unit *u = userdata;
    2121             :         bool missing_ok;
    2122             :         int r;
    2123             : 
    2124           0 :         assert(filename);
    2125           0 :         assert(lvalue);
    2126           0 :         assert(rvalue);
    2127           0 :         assert(c);
    2128           0 :         assert(u);
    2129             : 
    2130           0 :         if (isempty(rvalue)) {
    2131           0 :                 c->working_directory_home = false;
    2132           0 :                 c->working_directory = mfree(c->working_directory);
    2133           0 :                 return 0;
    2134             :         }
    2135             : 
    2136           0 :         if (rvalue[0] == '-') {
    2137           0 :                 missing_ok = true;
    2138           0 :                 rvalue++;
    2139             :         } else
    2140           0 :                 missing_ok = false;
    2141             : 
    2142           0 :         if (streq(rvalue, "~")) {
    2143           0 :                 c->working_directory_home = true;
    2144           0 :                 c->working_directory = mfree(c->working_directory);
    2145             :         } else {
    2146           0 :                 _cleanup_free_ char *k = NULL;
    2147             : 
    2148           0 :                 r = unit_full_printf(u, rvalue, &k);
    2149           0 :                 if (r < 0) {
    2150           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    2151             :                                    "Failed to resolve unit specifiers in working directory path '%s'%s: %m",
    2152             :                                    rvalue, missing_ok ? ", ignoring" : "");
    2153           0 :                         return missing_ok ? 0 : -ENOEXEC;
    2154             :                 }
    2155             : 
    2156           0 :                 r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE | (missing_ok ? 0 : PATH_CHECK_FATAL), unit, filename, line, lvalue);
    2157           0 :                 if (r < 0)
    2158           0 :                         return missing_ok ? 0 : -ENOEXEC;
    2159             : 
    2160           0 :                 c->working_directory_home = false;
    2161           0 :                 free_and_replace(c->working_directory, k);
    2162             :         }
    2163             : 
    2164           0 :         c->working_directory_missing_ok = missing_ok;
    2165           0 :         return 0;
    2166             : }
    2167             : 
    2168           0 : int config_parse_unit_env_file(const char *unit,
    2169             :                                const char *filename,
    2170             :                                unsigned line,
    2171             :                                const char *section,
    2172             :                                unsigned section_line,
    2173             :                                const char *lvalue,
    2174             :                                int ltype,
    2175             :                                const char *rvalue,
    2176             :                                void *data,
    2177             :                                void *userdata) {
    2178             : 
    2179           0 :         char ***env = data;
    2180           0 :         Unit *u = userdata;
    2181           0 :         _cleanup_free_ char *n = NULL;
    2182             :         int r;
    2183             : 
    2184           0 :         assert(filename);
    2185           0 :         assert(lvalue);
    2186           0 :         assert(rvalue);
    2187           0 :         assert(data);
    2188             : 
    2189           0 :         if (isempty(rvalue)) {
    2190             :                 /* Empty assignment frees the list */
    2191           0 :                 *env = strv_free(*env);
    2192           0 :                 return 0;
    2193             :         }
    2194             : 
    2195           0 :         r = unit_full_printf(u, rvalue, &n);
    2196           0 :         if (r < 0) {
    2197           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
    2198           0 :                 return 0;
    2199             :         }
    2200             : 
    2201           0 :         r = path_simplify_and_warn(n[0] == '-' ? n + 1 : n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    2202           0 :         if (r < 0)
    2203           0 :                 return 0;
    2204             : 
    2205           0 :         r = strv_push(env, n);
    2206           0 :         if (r < 0)
    2207           0 :                 return log_oom();
    2208             : 
    2209           0 :         n = NULL;
    2210             : 
    2211           0 :         return 0;
    2212             : }
    2213             : 
    2214           0 : int config_parse_environ(
    2215             :                 const char *unit,
    2216             :                 const char *filename,
    2217             :                 unsigned line,
    2218             :                 const char *section,
    2219             :                 unsigned section_line,
    2220             :                 const char *lvalue,
    2221             :                 int ltype,
    2222             :                 const char *rvalue,
    2223             :                 void *data,
    2224             :                 void *userdata) {
    2225             : 
    2226           0 :         Unit *u = userdata;
    2227           0 :         char ***env = data;
    2228             :         const char *p;
    2229             :         int r;
    2230             : 
    2231           0 :         assert(filename);
    2232           0 :         assert(lvalue);
    2233           0 :         assert(rvalue);
    2234           0 :         assert(data);
    2235             : 
    2236           0 :         if (isempty(rvalue)) {
    2237             :                 /* Empty assignment resets the list */
    2238           0 :                 *env = strv_free(*env);
    2239           0 :                 return 0;
    2240             :         }
    2241             : 
    2242           0 :         for (p = rvalue;; ) {
    2243           0 :                 _cleanup_free_ char *word = NULL, *k = NULL;
    2244             : 
    2245           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
    2246           0 :                 if (r == 0)
    2247           0 :                         return 0;
    2248           0 :                 if (r == -ENOMEM)
    2249           0 :                         return log_oom();
    2250           0 :                 if (r < 0) {
    2251           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r,
    2252             :                                    "Invalid syntax, ignoring: %s", rvalue);
    2253           0 :                         return 0;
    2254             :                 }
    2255             : 
    2256           0 :                 if (u) {
    2257           0 :                         r = unit_full_printf(u, word, &k);
    2258           0 :                         if (r < 0) {
    2259           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r,
    2260             :                                            "Failed to resolve unit specifiers in %s, ignoring: %m", word);
    2261           0 :                                 continue;
    2262             :                         }
    2263             :                 } else
    2264           0 :                         k = TAKE_PTR(word);
    2265             : 
    2266           0 :                 if (!env_assignment_is_valid(k)) {
    2267           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
    2268             :                                    "Invalid environment assignment, ignoring: %s", k);
    2269           0 :                         continue;
    2270             :                 }
    2271             : 
    2272           0 :                 r = strv_env_replace(env, k);
    2273           0 :                 if (r < 0)
    2274           0 :                         return log_oom();
    2275             : 
    2276           0 :                 k = NULL;
    2277             :         }
    2278             : }
    2279             : 
    2280           3 : int config_parse_pass_environ(
    2281             :                 const char *unit,
    2282             :                 const char *filename,
    2283             :                 unsigned line,
    2284             :                 const char *section,
    2285             :                 unsigned section_line,
    2286             :                 const char *lvalue,
    2287             :                 int ltype,
    2288             :                 const char *rvalue,
    2289             :                 void *data,
    2290             :                 void *userdata) {
    2291             : 
    2292           3 :         _cleanup_strv_free_ char **n = NULL;
    2293           3 :         size_t nlen = 0, nbufsize = 0;
    2294           3 :         char*** passenv = data;
    2295           3 :         const char *p = rvalue;
    2296           3 :         Unit *u = userdata;
    2297             :         int r;
    2298             : 
    2299           3 :         assert(filename);
    2300           3 :         assert(lvalue);
    2301           3 :         assert(rvalue);
    2302           3 :         assert(data);
    2303             : 
    2304           3 :         if (isempty(rvalue)) {
    2305             :                 /* Empty assignment resets the list */
    2306           1 :                 *passenv = strv_free(*passenv);
    2307           1 :                 return 0;
    2308             :         }
    2309             : 
    2310           5 :         for (;;) {
    2311          11 :                 _cleanup_free_ char *word = NULL, *k = NULL;
    2312             : 
    2313           7 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    2314           7 :                 if (r == 0)
    2315           1 :                         break;
    2316           6 :                 if (r == -ENOMEM)
    2317           0 :                         return log_oom();
    2318           6 :                 if (r < 0) {
    2319           1 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    2320             :                                    "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
    2321           1 :                         break;
    2322             :                 }
    2323             : 
    2324           5 :                 if (u) {
    2325           0 :                         r = unit_full_printf(u, word, &k);
    2326           0 :                         if (r < 0) {
    2327           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r,
    2328             :                                            "Failed to resolve specifiers in %s, ignoring: %m", word);
    2329           0 :                                 continue;
    2330             :                         }
    2331             :                 } else
    2332           5 :                         k = TAKE_PTR(word);
    2333             : 
    2334           5 :                 if (!env_name_is_valid(k)) {
    2335           2 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
    2336             :                                    "Invalid environment name for %s, ignoring: %s", lvalue, k);
    2337           2 :                         continue;
    2338             :                 }
    2339             : 
    2340           3 :                 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
    2341           0 :                         return log_oom();
    2342             : 
    2343           3 :                 n[nlen++] = TAKE_PTR(k);
    2344           3 :                 n[nlen] = NULL;
    2345             :         }
    2346             : 
    2347           2 :         if (n) {
    2348           2 :                 r = strv_extend_strv(passenv, n, true);
    2349           2 :                 if (r < 0)
    2350           0 :                         return r;
    2351             :         }
    2352             : 
    2353           2 :         return 0;
    2354             : }
    2355             : 
    2356           0 : int config_parse_unset_environ(
    2357             :                 const char *unit,
    2358             :                 const char *filename,
    2359             :                 unsigned line,
    2360             :                 const char *section,
    2361             :                 unsigned section_line,
    2362             :                 const char *lvalue,
    2363             :                 int ltype,
    2364             :                 const char *rvalue,
    2365             :                 void *data,
    2366             :                 void *userdata) {
    2367             : 
    2368           0 :         _cleanup_strv_free_ char **n = NULL;
    2369           0 :         size_t nlen = 0, nbufsize = 0;
    2370           0 :         char*** unsetenv = data;
    2371           0 :         const char *p = rvalue;
    2372           0 :         Unit *u = userdata;
    2373             :         int r;
    2374             : 
    2375           0 :         assert(filename);
    2376           0 :         assert(lvalue);
    2377           0 :         assert(rvalue);
    2378           0 :         assert(data);
    2379             : 
    2380           0 :         if (isempty(rvalue)) {
    2381             :                 /* Empty assignment resets the list */
    2382           0 :                 *unsetenv = strv_free(*unsetenv);
    2383           0 :                 return 0;
    2384             :         }
    2385             : 
    2386           0 :         for (;;) {
    2387           0 :                 _cleanup_free_ char *word = NULL, *k = NULL;
    2388             : 
    2389           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
    2390           0 :                 if (r == 0)
    2391           0 :                         break;
    2392           0 :                 if (r == -ENOMEM)
    2393           0 :                         return log_oom();
    2394           0 :                 if (r < 0) {
    2395           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    2396             :                                    "Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
    2397           0 :                         break;
    2398             :                 }
    2399             : 
    2400           0 :                 if (u) {
    2401           0 :                         r = unit_full_printf(u, word, &k);
    2402           0 :                         if (r < 0) {
    2403           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r,
    2404             :                                            "Failed to resolve unit specifiers in %s, ignoring: %m", word);
    2405           0 :                                 continue;
    2406             :                         }
    2407             :                 } else
    2408           0 :                         k = TAKE_PTR(word);
    2409             : 
    2410           0 :                 if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
    2411           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
    2412             :                                    "Invalid environment name or assignment %s, ignoring: %s", lvalue, k);
    2413           0 :                         continue;
    2414             :                 }
    2415             : 
    2416           0 :                 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
    2417           0 :                         return log_oom();
    2418             : 
    2419           0 :                 n[nlen++] = TAKE_PTR(k);
    2420           0 :                 n[nlen] = NULL;
    2421             :         }
    2422             : 
    2423           0 :         if (n) {
    2424           0 :                 r = strv_extend_strv(unsetenv, n, true);
    2425           0 :                 if (r < 0)
    2426           0 :                         return r;
    2427             :         }
    2428             : 
    2429           0 :         return 0;
    2430             : }
    2431             : 
    2432           3 : int config_parse_log_extra_fields(
    2433             :                 const char *unit,
    2434             :                 const char *filename,
    2435             :                 unsigned line,
    2436             :                 const char *section,
    2437             :                 unsigned section_line,
    2438             :                 const char *lvalue,
    2439             :                 int ltype,
    2440             :                 const char *rvalue,
    2441             :                 void *data,
    2442             :                 void *userdata) {
    2443             : 
    2444           3 :         ExecContext *c = data;
    2445           3 :         Unit *u = userdata;
    2446           3 :         const char *p = rvalue;
    2447             :         int r;
    2448             : 
    2449           3 :         assert(filename);
    2450           3 :         assert(lvalue);
    2451           3 :         assert(rvalue);
    2452           3 :         assert(c);
    2453             : 
    2454           3 :         if (isempty(rvalue)) {
    2455           1 :                 exec_context_free_log_extra_fields(c);
    2456           1 :                 return 0;
    2457             :         }
    2458             : 
    2459           5 :         for (;;) {
    2460          10 :                 _cleanup_free_ char *word = NULL, *k = NULL;
    2461             :                 struct iovec *t;
    2462             :                 const char *eq;
    2463             : 
    2464           7 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
    2465           7 :                 if (r == 0)
    2466           2 :                         return 0;
    2467           5 :                 if (r == -ENOMEM)
    2468           0 :                         return log_oom();
    2469           5 :                 if (r < 0) {
    2470           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
    2471           0 :                         return 0;
    2472             :                 }
    2473             : 
    2474           5 :                 r = unit_full_printf(u, word, &k);
    2475           5 :                 if (r < 0) {
    2476           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
    2477           0 :                         continue;
    2478             :                 }
    2479             : 
    2480           5 :                 eq = strchr(k, '=');
    2481           5 :                 if (!eq) {
    2482           1 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Log field lacks '=' character, ignoring: %s", k);
    2483           1 :                         continue;
    2484             :                 }
    2485             : 
    2486           4 :                 if (!journal_field_valid(k, eq-k, false)) {
    2487           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Log field name is invalid, ignoring: %s", k);
    2488           0 :                         continue;
    2489             :                 }
    2490             : 
    2491           4 :                 t = reallocarray(c->log_extra_fields, c->n_log_extra_fields+1, sizeof(struct iovec));
    2492           4 :                 if (!t)
    2493           0 :                         return log_oom();
    2494             : 
    2495           4 :                 c->log_extra_fields = t;
    2496           4 :                 c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE_STRING(k);
    2497             : 
    2498           4 :                 k = NULL;
    2499             :         }
    2500             : }
    2501             : 
    2502           0 : int config_parse_unit_condition_path(
    2503             :                 const char *unit,
    2504             :                 const char *filename,
    2505             :                 unsigned line,
    2506             :                 const char *section,
    2507             :                 unsigned section_line,
    2508             :                 const char *lvalue,
    2509             :                 int ltype,
    2510             :                 const char *rvalue,
    2511             :                 void *data,
    2512             :                 void *userdata) {
    2513             : 
    2514           0 :         _cleanup_free_ char *p = NULL;
    2515           0 :         Condition **list = data, *c;
    2516           0 :         ConditionType t = ltype;
    2517             :         bool trigger, negate;
    2518           0 :         Unit *u = userdata;
    2519             :         int r;
    2520             : 
    2521           0 :         assert(filename);
    2522           0 :         assert(lvalue);
    2523           0 :         assert(rvalue);
    2524           0 :         assert(data);
    2525             : 
    2526           0 :         if (isempty(rvalue)) {
    2527             :                 /* Empty assignment resets the list */
    2528           0 :                 *list = condition_free_list(*list);
    2529           0 :                 return 0;
    2530             :         }
    2531             : 
    2532           0 :         trigger = rvalue[0] == '|';
    2533           0 :         if (trigger)
    2534           0 :                 rvalue++;
    2535             : 
    2536           0 :         negate = rvalue[0] == '!';
    2537           0 :         if (negate)
    2538           0 :                 rvalue++;
    2539             : 
    2540           0 :         r = unit_full_printf(u, rvalue, &p);
    2541           0 :         if (r < 0) {
    2542           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
    2543           0 :                 return 0;
    2544             :         }
    2545             : 
    2546           0 :         r = path_simplify_and_warn(p, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    2547           0 :         if (r < 0)
    2548           0 :                 return 0;
    2549             : 
    2550           0 :         c = condition_new(t, p, trigger, negate);
    2551           0 :         if (!c)
    2552           0 :                 return log_oom();
    2553             : 
    2554           0 :         LIST_PREPEND(conditions, *list, c);
    2555           0 :         return 0;
    2556             : }
    2557             : 
    2558           0 : int config_parse_unit_condition_string(
    2559             :                 const char *unit,
    2560             :                 const char *filename,
    2561             :                 unsigned line,
    2562             :                 const char *section,
    2563             :                 unsigned section_line,
    2564             :                 const char *lvalue,
    2565             :                 int ltype,
    2566             :                 const char *rvalue,
    2567             :                 void *data,
    2568             :                 void *userdata) {
    2569             : 
    2570           0 :         _cleanup_free_ char *s = NULL;
    2571           0 :         Condition **list = data, *c;
    2572           0 :         ConditionType t = ltype;
    2573             :         bool trigger, negate;
    2574           0 :         Unit *u = userdata;
    2575             :         int r;
    2576             : 
    2577           0 :         assert(filename);
    2578           0 :         assert(lvalue);
    2579           0 :         assert(rvalue);
    2580           0 :         assert(data);
    2581             : 
    2582           0 :         if (isempty(rvalue)) {
    2583             :                 /* Empty assignment resets the list */
    2584           0 :                 *list = condition_free_list(*list);
    2585           0 :                 return 0;
    2586             :         }
    2587             : 
    2588           0 :         trigger = *rvalue == '|';
    2589           0 :         if (trigger)
    2590           0 :                 rvalue += 1 + strspn(rvalue + 1, WHITESPACE);
    2591             : 
    2592           0 :         negate = *rvalue == '!';
    2593           0 :         if (negate)
    2594           0 :                 rvalue += 1 + strspn(rvalue + 1, WHITESPACE);
    2595             : 
    2596           0 :         r = unit_full_printf(u, rvalue, &s);
    2597           0 :         if (r < 0) {
    2598           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
    2599             :                            "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
    2600           0 :                 return 0;
    2601             :         }
    2602             : 
    2603           0 :         c = condition_new(t, s, trigger, negate);
    2604           0 :         if (!c)
    2605           0 :                 return log_oom();
    2606             : 
    2607           0 :         LIST_PREPEND(conditions, *list, c);
    2608           0 :         return 0;
    2609             : }
    2610             : 
    2611           0 : int config_parse_unit_condition_null(
    2612             :                 const char *unit,
    2613             :                 const char *filename,
    2614             :                 unsigned line,
    2615             :                 const char *section,
    2616             :                 unsigned section_line,
    2617             :                 const char *lvalue,
    2618             :                 int ltype,
    2619             :                 const char *rvalue,
    2620             :                 void *data,
    2621             :                 void *userdata) {
    2622             : 
    2623           0 :         Condition **list = data, *c;
    2624             :         bool trigger, negate;
    2625             :         int b;
    2626             : 
    2627           0 :         assert(filename);
    2628           0 :         assert(lvalue);
    2629           0 :         assert(rvalue);
    2630           0 :         assert(data);
    2631             : 
    2632           0 :         log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is deprecated, please do not use.", lvalue);
    2633             : 
    2634           0 :         if (isempty(rvalue)) {
    2635             :                 /* Empty assignment resets the list */
    2636           0 :                 *list = condition_free_list(*list);
    2637           0 :                 return 0;
    2638             :         }
    2639             : 
    2640           0 :         trigger = rvalue[0] == '|';
    2641           0 :         if (trigger)
    2642           0 :                 rvalue++;
    2643             : 
    2644           0 :         negate = rvalue[0] == '!';
    2645           0 :         if (negate)
    2646           0 :                 rvalue++;
    2647             : 
    2648           0 :         b = parse_boolean(rvalue);
    2649           0 :         if (b < 0) {
    2650           0 :                 log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
    2651           0 :                 return 0;
    2652             :         }
    2653             : 
    2654           0 :         if (!b)
    2655           0 :                 negate = !negate;
    2656             : 
    2657           0 :         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
    2658           0 :         if (!c)
    2659           0 :                 return log_oom();
    2660             : 
    2661           0 :         LIST_PREPEND(conditions, *list, c);
    2662           0 :         return 0;
    2663             : }
    2664             : 
    2665          11 : int config_parse_unit_requires_mounts_for(
    2666             :                 const char *unit,
    2667             :                 const char *filename,
    2668             :                 unsigned line,
    2669             :                 const char *section,
    2670             :                 unsigned section_line,
    2671             :                 const char *lvalue,
    2672             :                 int ltype,
    2673             :                 const char *rvalue,
    2674             :                 void *data,
    2675             :                 void *userdata) {
    2676             : 
    2677          11 :         const char *p = rvalue;
    2678          11 :         Unit *u = userdata;
    2679             :         int r;
    2680             : 
    2681          11 :         assert(filename);
    2682          11 :         assert(lvalue);
    2683          11 :         assert(rvalue);
    2684          11 :         assert(data);
    2685             : 
    2686          22 :         for (;;) {
    2687          44 :                 _cleanup_free_ char *word = NULL, *resolved = NULL;
    2688             : 
    2689          33 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    2690          33 :                 if (r == 0)
    2691          11 :                         return 0;
    2692          22 :                 if (r == -ENOMEM)
    2693           0 :                         return log_oom();
    2694          22 :                 if (r < 0) {
    2695           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r,
    2696             :                                    "Invalid syntax, ignoring: %s", rvalue);
    2697           0 :                         return 0;
    2698             :                 }
    2699             : 
    2700          22 :                 r = unit_full_printf(u, word, &resolved);
    2701          22 :                 if (r < 0) {
    2702           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", word);
    2703           0 :                         continue;
    2704             :                 }
    2705             : 
    2706          22 :                 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    2707          22 :                 if (r < 0)
    2708           0 :                         continue;
    2709             : 
    2710          22 :                 r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
    2711          22 :                 if (r < 0) {
    2712           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount '%s', ignoring: %m", resolved);
    2713           0 :                         continue;
    2714             :                 }
    2715             :         }
    2716             : }
    2717             : 
    2718          44 : int config_parse_documentation(const char *unit,
    2719             :                                const char *filename,
    2720             :                                unsigned line,
    2721             :                                const char *section,
    2722             :                                unsigned section_line,
    2723             :                                const char *lvalue,
    2724             :                                int ltype,
    2725             :                                const char *rvalue,
    2726             :                                void *data,
    2727             :                                void *userdata) {
    2728             : 
    2729          44 :         Unit *u = userdata;
    2730             :         int r;
    2731             :         char **a, **b;
    2732             : 
    2733          44 :         assert(filename);
    2734          44 :         assert(lvalue);
    2735          44 :         assert(rvalue);
    2736          44 :         assert(u);
    2737             : 
    2738          44 :         if (isempty(rvalue)) {
    2739             :                 /* Empty assignment resets the list */
    2740           0 :                 u->documentation = strv_free(u->documentation);
    2741           0 :                 return 0;
    2742             :         }
    2743             : 
    2744          44 :         r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
    2745             :                                           rvalue, data, userdata);
    2746          44 :         if (r < 0)
    2747           0 :                 return r;
    2748             : 
    2749          91 :         for (a = b = u->documentation; a && *a; a++) {
    2750             : 
    2751          47 :                 if (documentation_url_is_valid(*a))
    2752          47 :                         *(b++) = *a;
    2753             :                 else {
    2754           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
    2755           0 :                         free(*a);
    2756             :                 }
    2757             :         }
    2758          44 :         if (b)
    2759          44 :                 *b = NULL;
    2760             : 
    2761          44 :         return r;
    2762             : }
    2763             : 
    2764             : #if HAVE_SECCOMP
    2765           0 : int config_parse_syscall_filter(
    2766             :                 const char *unit,
    2767             :                 const char *filename,
    2768             :                 unsigned line,
    2769             :                 const char *section,
    2770             :                 unsigned section_line,
    2771             :                 const char *lvalue,
    2772             :                 int ltype,
    2773             :                 const char *rvalue,
    2774             :                 void *data,
    2775             :                 void *userdata) {
    2776             : 
    2777           0 :         ExecContext *c = data;
    2778           0 :         Unit *u = userdata;
    2779           0 :         bool invert = false;
    2780             :         const char *p;
    2781             :         int r;
    2782             : 
    2783           0 :         assert(filename);
    2784           0 :         assert(lvalue);
    2785           0 :         assert(rvalue);
    2786           0 :         assert(u);
    2787             : 
    2788           0 :         if (isempty(rvalue)) {
    2789             :                 /* Empty assignment resets the list */
    2790           0 :                 c->syscall_filter = hashmap_free(c->syscall_filter);
    2791           0 :                 c->syscall_whitelist = false;
    2792           0 :                 return 0;
    2793             :         }
    2794             : 
    2795           0 :         if (rvalue[0] == '~') {
    2796           0 :                 invert = true;
    2797           0 :                 rvalue++;
    2798             :         }
    2799             : 
    2800           0 :         if (!c->syscall_filter) {
    2801           0 :                 c->syscall_filter = hashmap_new(NULL);
    2802           0 :                 if (!c->syscall_filter)
    2803           0 :                         return log_oom();
    2804             : 
    2805           0 :                 if (invert)
    2806             :                         /* Allow everything but the ones listed */
    2807           0 :                         c->syscall_whitelist = false;
    2808             :                 else {
    2809             :                         /* Allow nothing but the ones listed */
    2810           0 :                         c->syscall_whitelist = true;
    2811             : 
    2812             :                         /* Accept default syscalls if we are on a whitelist */
    2813           0 :                         r = seccomp_parse_syscall_filter(
    2814             :                                         "@default", -1, c->syscall_filter,
    2815             :                                         SECCOMP_PARSE_PERMISSIVE|SECCOMP_PARSE_WHITELIST,
    2816             :                                         unit,
    2817             :                                         NULL, 0);
    2818           0 :                         if (r < 0)
    2819           0 :                                 return r;
    2820             :                 }
    2821             :         }
    2822             : 
    2823           0 :         p = rvalue;
    2824           0 :         for (;;) {
    2825           0 :                 _cleanup_free_ char *word = NULL, *name = NULL;
    2826             :                 int num;
    2827             : 
    2828           0 :                 r = extract_first_word(&p, &word, NULL, 0);
    2829           0 :                 if (r == 0)
    2830           0 :                         return 0;
    2831           0 :                 if (r == -ENOMEM)
    2832           0 :                         return log_oom();
    2833           0 :                 if (r < 0) {
    2834           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
    2835           0 :                         return 0;
    2836             :                 }
    2837             : 
    2838           0 :                 r = parse_syscall_and_errno(word, &name, &num);
    2839           0 :                 if (r < 0) {
    2840           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall:errno, ignoring: %s", word);
    2841           0 :                         continue;
    2842             :                 }
    2843             : 
    2844           0 :                 r = seccomp_parse_syscall_filter(
    2845             :                                 name, num, c->syscall_filter,
    2846           0 :                                 SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
    2847           0 :                                 (invert ? SECCOMP_PARSE_INVERT : 0)|
    2848           0 :                                 (c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0),
    2849             :                                 unit, filename, line);
    2850           0 :                 if (r < 0)
    2851           0 :                         return r;
    2852             :         }
    2853             : }
    2854             : 
    2855           0 : int config_parse_syscall_archs(
    2856             :                 const char *unit,
    2857             :                 const char *filename,
    2858             :                 unsigned line,
    2859             :                 const char *section,
    2860             :                 unsigned section_line,
    2861             :                 const char *lvalue,
    2862             :                 int ltype,
    2863             :                 const char *rvalue,
    2864             :                 void *data,
    2865             :                 void *userdata) {
    2866             : 
    2867           0 :         const char *p = rvalue;
    2868           0 :         Set **archs = data;
    2869             :         int r;
    2870             : 
    2871           0 :         if (isempty(rvalue)) {
    2872           0 :                 *archs = set_free(*archs);
    2873           0 :                 return 0;
    2874             :         }
    2875             : 
    2876           0 :         r = set_ensure_allocated(archs, NULL);
    2877           0 :         if (r < 0)
    2878           0 :                 return log_oom();
    2879             : 
    2880           0 :         for (;;) {
    2881           0 :                 _cleanup_free_ char *word = NULL;
    2882             :                 uint32_t a;
    2883             : 
    2884           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    2885           0 :                 if (r == 0)
    2886           0 :                         return 0;
    2887           0 :                 if (r == -ENOMEM)
    2888           0 :                         return log_oom();
    2889           0 :                 if (r < 0) {
    2890           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r,
    2891             :                                    "Invalid syntax, ignoring: %s", rvalue);
    2892           0 :                         return 0;
    2893             :                 }
    2894             : 
    2895           0 :                 r = seccomp_arch_from_string(word, &a);
    2896           0 :                 if (r < 0) {
    2897           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    2898             :                                    "Failed to parse system call architecture \"%s\", ignoring: %m", word);
    2899           0 :                         continue;
    2900             :                 }
    2901             : 
    2902           0 :                 r = set_put(*archs, UINT32_TO_PTR(a + 1));
    2903           0 :                 if (r < 0)
    2904           0 :                         return log_oom();
    2905             :         }
    2906             : }
    2907             : 
    2908           0 : int config_parse_syscall_errno(
    2909             :                 const char *unit,
    2910             :                 const char *filename,
    2911             :                 unsigned line,
    2912             :                 const char *section,
    2913             :                 unsigned section_line,
    2914             :                 const char *lvalue,
    2915             :                 int ltype,
    2916             :                 const char *rvalue,
    2917             :                 void *data,
    2918             :                 void *userdata) {
    2919             : 
    2920           0 :         ExecContext *c = data;
    2921             :         int e;
    2922             : 
    2923           0 :         assert(filename);
    2924           0 :         assert(lvalue);
    2925           0 :         assert(rvalue);
    2926             : 
    2927           0 :         if (isempty(rvalue)) {
    2928             :                 /* Empty assignment resets to KILL */
    2929           0 :                 c->syscall_errno = 0;
    2930           0 :                 return 0;
    2931             :         }
    2932             : 
    2933           0 :         e = parse_errno(rvalue);
    2934           0 :         if (e <= 0) {
    2935           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
    2936           0 :                 return 0;
    2937             :         }
    2938             : 
    2939           0 :         c->syscall_errno = e;
    2940           0 :         return 0;
    2941             : }
    2942             : 
    2943           0 : int config_parse_address_families(
    2944             :                 const char *unit,
    2945             :                 const char *filename,
    2946             :                 unsigned line,
    2947             :                 const char *section,
    2948             :                 unsigned section_line,
    2949             :                 const char *lvalue,
    2950             :                 int ltype,
    2951             :                 const char *rvalue,
    2952             :                 void *data,
    2953             :                 void *userdata) {
    2954             : 
    2955           0 :         ExecContext *c = data;
    2956           0 :         bool invert = false;
    2957             :         const char *p;
    2958             :         int r;
    2959             : 
    2960           0 :         assert(filename);
    2961           0 :         assert(lvalue);
    2962           0 :         assert(rvalue);
    2963             : 
    2964           0 :         if (isempty(rvalue)) {
    2965             :                 /* Empty assignment resets the list */
    2966           0 :                 c->address_families = set_free(c->address_families);
    2967           0 :                 c->address_families_whitelist = false;
    2968           0 :                 return 0;
    2969             :         }
    2970             : 
    2971           0 :         if (rvalue[0] == '~') {
    2972           0 :                 invert = true;
    2973           0 :                 rvalue++;
    2974             :         }
    2975             : 
    2976           0 :         if (!c->address_families) {
    2977           0 :                 c->address_families = set_new(NULL);
    2978           0 :                 if (!c->address_families)
    2979           0 :                         return log_oom();
    2980             : 
    2981           0 :                 c->address_families_whitelist = !invert;
    2982             :         }
    2983             : 
    2984           0 :         for (p = rvalue;;) {
    2985           0 :                 _cleanup_free_ char *word = NULL;
    2986             :                 int af;
    2987             : 
    2988           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    2989           0 :                 if (r == 0)
    2990           0 :                         return 0;
    2991           0 :                 if (r == -ENOMEM)
    2992           0 :                         return log_oom();
    2993           0 :                 if (r < 0) {
    2994           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r,
    2995             :                                    "Invalid syntax, ignoring: %s", rvalue);
    2996           0 :                         return 0;
    2997             :                 }
    2998             : 
    2999           0 :                 af = af_from_name(word);
    3000           0 :                 if (af < 0) {
    3001           0 :                         log_syntax(unit, LOG_ERR, filename, line, af,
    3002             :                                    "Failed to parse address family, ignoring: %s", word);
    3003           0 :                         continue;
    3004             :                 }
    3005             : 
    3006             :                 /* If we previously wanted to forbid an address family and now
    3007             :                  * we want to allow it, then just remove it from the list.
    3008             :                  */
    3009           0 :                 if (!invert == c->address_families_whitelist)  {
    3010           0 :                         r = set_put(c->address_families, INT_TO_PTR(af));
    3011           0 :                         if (r < 0)
    3012           0 :                                 return log_oom();
    3013             :                 } else
    3014           0 :                         set_remove(c->address_families, INT_TO_PTR(af));
    3015             :         }
    3016             : }
    3017             : 
    3018           0 : int config_parse_restrict_namespaces(
    3019             :                 const char *unit,
    3020             :                 const char *filename,
    3021             :                 unsigned line,
    3022             :                 const char *section,
    3023             :                 unsigned section_line,
    3024             :                 const char *lvalue,
    3025             :                 int ltype,
    3026             :                 const char *rvalue,
    3027             :                 void *data,
    3028             :                 void *userdata) {
    3029             : 
    3030           0 :         ExecContext *c = data;
    3031             :         unsigned long flags;
    3032           0 :         bool invert = false;
    3033             :         int r;
    3034             : 
    3035           0 :         if (isempty(rvalue)) {
    3036             :                 /* Reset to the default. */
    3037           0 :                 c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
    3038           0 :                 return 0;
    3039             :         }
    3040             : 
    3041             :         /* Boolean parameter ignores the previous settings */
    3042           0 :         r = parse_boolean(rvalue);
    3043           0 :         if (r > 0) {
    3044           0 :                 c->restrict_namespaces = 0;
    3045           0 :                 return 0;
    3046           0 :         } else if (r == 0) {
    3047           0 :                 c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
    3048           0 :                 return 0;
    3049             :         }
    3050             : 
    3051           0 :         if (rvalue[0] == '~') {
    3052           0 :                 invert = true;
    3053           0 :                 rvalue++;
    3054             :         }
    3055             : 
    3056             :         /* Not a boolean argument, in this case it's a list of namespace types. */
    3057           0 :         r = namespace_flags_from_string(rvalue, &flags);
    3058           0 :         if (r < 0) {
    3059           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
    3060           0 :                 return 0;
    3061             :         }
    3062             : 
    3063           0 :         if (c->restrict_namespaces == NAMESPACE_FLAGS_INITIAL)
    3064             :                 /* Initial assignment. Just set the value. */
    3065           0 :                 c->restrict_namespaces = invert ? (~flags) & NAMESPACE_FLAGS_ALL : flags;
    3066             :         else
    3067             :                 /* Merge the value with the previous one. */
    3068           0 :                 SET_FLAG(c->restrict_namespaces, flags, !invert);
    3069             : 
    3070           0 :         return 0;
    3071             : }
    3072             : #endif
    3073             : 
    3074          10 : int config_parse_unit_slice(
    3075             :                 const char *unit,
    3076             :                 const char *filename,
    3077             :                 unsigned line,
    3078             :                 const char *section,
    3079             :                 unsigned section_line,
    3080             :                 const char *lvalue,
    3081             :                 int ltype,
    3082             :                 const char *rvalue,
    3083             :                 void *data,
    3084             :                 void *userdata) {
    3085             : 
    3086          10 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    3087          10 :         _cleanup_free_ char *k = NULL;
    3088          10 :         Unit *u = userdata, *slice = NULL;
    3089             :         int r;
    3090             : 
    3091          10 :         assert(filename);
    3092          10 :         assert(lvalue);
    3093          10 :         assert(rvalue);
    3094          10 :         assert(u);
    3095             : 
    3096          10 :         r = unit_name_printf(u, rvalue, &k);
    3097          10 :         if (r < 0) {
    3098           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
    3099           0 :                 return 0;
    3100             :         }
    3101             : 
    3102          10 :         r = manager_load_unit(u->manager, k, NULL, &error, &slice);
    3103          10 :         if (r < 0) {
    3104           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s, ignoring: %s", k, bus_error_message(&error, r));
    3105           0 :                 return 0;
    3106             :         }
    3107             : 
    3108          10 :         r = unit_set_slice(u, slice);
    3109          10 :         if (r < 0) {
    3110           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s, ignoring: %m", slice->id, u->id);
    3111           0 :                 return 0;
    3112             :         }
    3113             : 
    3114          10 :         return 0;
    3115             : }
    3116             : 
    3117           0 : int config_parse_cpu_quota(
    3118             :                 const char *unit,
    3119             :                 const char *filename,
    3120             :                 unsigned line,
    3121             :                 const char *section,
    3122             :                 unsigned section_line,
    3123             :                 const char *lvalue,
    3124             :                 int ltype,
    3125             :                 const char *rvalue,
    3126             :                 void *data,
    3127             :                 void *userdata) {
    3128             : 
    3129           0 :         CGroupContext *c = data;
    3130             :         int r;
    3131             : 
    3132           0 :         assert(filename);
    3133           0 :         assert(lvalue);
    3134           0 :         assert(rvalue);
    3135             : 
    3136           0 :         if (isempty(rvalue)) {
    3137           0 :                 c->cpu_quota_per_sec_usec = USEC_INFINITY;
    3138           0 :                 return 0;
    3139             :         }
    3140             : 
    3141           0 :         r = parse_permille_unbounded(rvalue);
    3142           0 :         if (r <= 0) {
    3143           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
    3144           0 :                 return 0;
    3145             :         }
    3146             : 
    3147           0 :         c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U;
    3148           0 :         return 0;
    3149             : }
    3150             : 
    3151           8 : int config_parse_memory_limit(
    3152             :                 const char *unit,
    3153             :                 const char *filename,
    3154             :                 unsigned line,
    3155             :                 const char *section,
    3156             :                 unsigned section_line,
    3157             :                 const char *lvalue,
    3158             :                 int ltype,
    3159             :                 const char *rvalue,
    3160             :                 void *data,
    3161             :                 void *userdata) {
    3162             : 
    3163           8 :         CGroupContext *c = data;
    3164           8 :         uint64_t bytes = CGROUP_LIMIT_MAX;
    3165             :         int r;
    3166             : 
    3167           8 :         if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
    3168             : 
    3169           7 :                 r = parse_permille(rvalue);
    3170           7 :                 if (r < 0) {
    3171           7 :                         r = parse_size(rvalue, 1024, &bytes);
    3172           7 :                         if (r < 0) {
    3173           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid memory limit '%s', ignoring: %m", rvalue);
    3174           0 :                                 return 0;
    3175             :                         }
    3176             :                 } else
    3177           0 :                         bytes = physical_memory_scale(r, 1000U);
    3178             : 
    3179           7 :                 if (bytes >= UINT64_MAX ||
    3180           7 :                     (bytes <= 0 && !STR_IN_SET(lvalue, "MemorySwapMax", "MemoryLow", "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin"))) {
    3181           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range, ignoring.", rvalue);
    3182           0 :                         return 0;
    3183             :                 }
    3184             :         }
    3185             : 
    3186           8 :         if (streq(lvalue, "DefaultMemoryLow")) {
    3187           4 :                 c->default_memory_low_set = true;
    3188           4 :                 if (isempty(rvalue))
    3189           1 :                         c->default_memory_low = CGROUP_LIMIT_MIN;
    3190             :                 else
    3191           3 :                         c->default_memory_low = bytes;
    3192           4 :         } else if (streq(lvalue, "DefaultMemoryMin")) {
    3193           0 :                 c->default_memory_min_set = true;
    3194           0 :                 if (isempty(rvalue))
    3195           0 :                         c->default_memory_min = CGROUP_LIMIT_MIN;
    3196             :                 else
    3197           0 :                         c->default_memory_min = bytes;
    3198           4 :         } else if (streq(lvalue, "MemoryMin")) {
    3199           0 :                 c->memory_min = bytes;
    3200           0 :                 c->memory_min_set = true;
    3201           4 :         } else if (streq(lvalue, "MemoryLow")) {
    3202           3 :                 c->memory_low = bytes;
    3203           3 :                 c->memory_low_set = true;
    3204           1 :         } else if (streq(lvalue, "MemoryHigh"))
    3205           0 :                 c->memory_high = bytes;
    3206           1 :         else if (streq(lvalue, "MemoryMax"))
    3207           0 :                 c->memory_max = bytes;
    3208           1 :         else if (streq(lvalue, "MemorySwapMax"))
    3209           0 :                 c->memory_swap_max = bytes;
    3210           1 :         else if (streq(lvalue, "MemoryLimit"))
    3211           1 :                 c->memory_limit = bytes;
    3212             :         else
    3213           0 :                 return -EINVAL;
    3214             : 
    3215           8 :         return 0;
    3216             : }
    3217             : 
    3218           0 : int config_parse_tasks_max(
    3219             :                 const char *unit,
    3220             :                 const char *filename,
    3221             :                 unsigned line,
    3222             :                 const char *section,
    3223             :                 unsigned section_line,
    3224             :                 const char *lvalue,
    3225             :                 int ltype,
    3226             :                 const char *rvalue,
    3227             :                 void *data,
    3228             :                 void *userdata) {
    3229             : 
    3230           0 :         uint64_t *tasks_max = data, v;
    3231           0 :         Unit *u = userdata;
    3232             :         int r;
    3233             : 
    3234           0 :         if (isempty(rvalue)) {
    3235           0 :                 *tasks_max = u ? u->manager->default_tasks_max : UINT64_MAX;
    3236           0 :                 return 0;
    3237             :         }
    3238             : 
    3239           0 :         if (streq(rvalue, "infinity")) {
    3240           0 :                 *tasks_max = CGROUP_LIMIT_MAX;
    3241           0 :                 return 0;
    3242             :         }
    3243             : 
    3244           0 :         r = parse_permille(rvalue);
    3245           0 :         if (r < 0) {
    3246           0 :                 r = safe_atou64(rvalue, &v);
    3247           0 :                 if (r < 0) {
    3248           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Invalid maximum tasks value '%s', ignoring: %m", rvalue);
    3249           0 :                         return 0;
    3250             :                 }
    3251             :         } else
    3252           0 :                 v = system_tasks_max_scale(r, 1000U);
    3253             : 
    3254           0 :         if (v <= 0 || v >= UINT64_MAX) {
    3255           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range, ignoring.", rvalue);
    3256           0 :                 return 0;
    3257             :         }
    3258             : 
    3259           0 :         *tasks_max = v;
    3260           0 :         return 0;
    3261             : }
    3262             : 
    3263           0 : int config_parse_delegate(
    3264             :                 const char *unit,
    3265             :                 const char *filename,
    3266             :                 unsigned line,
    3267             :                 const char *section,
    3268             :                 unsigned section_line,
    3269             :                 const char *lvalue,
    3270             :                 int ltype,
    3271             :                 const char *rvalue,
    3272             :                 void *data,
    3273             :                 void *userdata) {
    3274             : 
    3275           0 :         CGroupContext *c = data;
    3276             :         UnitType t;
    3277             :         int r;
    3278             : 
    3279           0 :         t = unit_name_to_type(unit);
    3280           0 :         assert(t != _UNIT_TYPE_INVALID);
    3281             : 
    3282           0 :         if (!unit_vtable[t]->can_delegate) {
    3283           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Delegate= setting not supported for this unit type, ignoring.");
    3284           0 :                 return 0;
    3285             :         }
    3286             : 
    3287             :         /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
    3288             :          * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
    3289             :          * mask to delegate. */
    3290             : 
    3291           0 :         if (isempty(rvalue)) {
    3292             :                 /* An empty string resets controllers and set Delegate=yes. */
    3293           0 :                 c->delegate = true;
    3294           0 :                 c->delegate_controllers = 0;
    3295           0 :                 return 0;
    3296             :         }
    3297             : 
    3298           0 :         r = parse_boolean(rvalue);
    3299           0 :         if (r < 0) {
    3300           0 :                 const char *p = rvalue;
    3301           0 :                 CGroupMask mask = 0;
    3302             : 
    3303           0 :                 for (;;) {
    3304           0 :                         _cleanup_free_ char *word = NULL;
    3305             :                         CGroupController cc;
    3306             : 
    3307           0 :                         r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    3308           0 :                         if (r == 0)
    3309           0 :                                 break;
    3310           0 :                         if (r == -ENOMEM)
    3311           0 :                                 return log_oom();
    3312           0 :                         if (r < 0) {
    3313           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
    3314           0 :                                 return 0;
    3315             :                         }
    3316             : 
    3317           0 :                         cc = cgroup_controller_from_string(word);
    3318           0 :                         if (cc < 0) {
    3319           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", word);
    3320           0 :                                 continue;
    3321             :                         }
    3322             : 
    3323           0 :                         mask |= CGROUP_CONTROLLER_TO_MASK(cc);
    3324             :                 }
    3325             : 
    3326           0 :                 c->delegate = true;
    3327           0 :                 c->delegate_controllers |= mask;
    3328             : 
    3329           0 :         } else if (r > 0) {
    3330           0 :                 c->delegate = true;
    3331           0 :                 c->delegate_controllers = _CGROUP_MASK_ALL;
    3332             :         } else {
    3333           0 :                 c->delegate = false;
    3334           0 :                 c->delegate_controllers = 0;
    3335             :         }
    3336             : 
    3337           0 :         return 0;
    3338             : }
    3339             : 
    3340           0 : int config_parse_device_allow(
    3341             :                 const char *unit,
    3342             :                 const char *filename,
    3343             :                 unsigned line,
    3344             :                 const char *section,
    3345             :                 unsigned section_line,
    3346             :                 const char *lvalue,
    3347             :                 int ltype,
    3348             :                 const char *rvalue,
    3349             :                 void *data,
    3350             :                 void *userdata) {
    3351             : 
    3352           0 :         _cleanup_free_ char *path = NULL, *resolved = NULL;
    3353           0 :         CGroupContext *c = data;
    3354           0 :         const char *p = rvalue;
    3355             :         int r;
    3356             : 
    3357           0 :         if (isempty(rvalue)) {
    3358           0 :                 while (c->device_allow)
    3359           0 :                         cgroup_context_free_device_allow(c, c->device_allow);
    3360             : 
    3361           0 :                 return 0;
    3362             :         }
    3363             : 
    3364           0 :         r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
    3365           0 :         if (r == -ENOMEM)
    3366           0 :                 return log_oom();
    3367           0 :         if (r < 0) {
    3368           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3369             :                            "Invalid syntax, ignoring: %s", rvalue);
    3370           0 :                 return 0;
    3371             :         }
    3372           0 :         if (r == 0) {
    3373           0 :                 log_syntax(unit, LOG_WARNING, filename, line, 0,
    3374             :                            "Failed to extract device path and rights from '%s', ignoring.", rvalue);
    3375           0 :                 return 0;
    3376             :         }
    3377             : 
    3378           0 :         r = unit_full_printf(userdata, path, &resolved);
    3379           0 :         if (r < 0) {
    3380           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3381             :                            "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
    3382           0 :                 return 0;
    3383             :         }
    3384             : 
    3385           0 :         if (!STARTSWITH_SET(resolved, "block-", "char-")) {
    3386             : 
    3387           0 :                 r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
    3388           0 :                 if (r < 0)
    3389           0 :                         return 0;
    3390             : 
    3391           0 :                 if (!valid_device_node_path(resolved)) {
    3392           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s', ignoring.", resolved);
    3393           0 :                         return 0;
    3394             :                 }
    3395             :         }
    3396             : 
    3397           0 :         if (!isempty(p) && !in_charset(p, "rwm")) {
    3398           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s', ignoring.", p);
    3399           0 :                 return 0;
    3400             :         }
    3401             : 
    3402           0 :         return cgroup_add_device_allow(c, resolved, p);
    3403             : }
    3404             : 
    3405           0 : int config_parse_io_device_weight(
    3406             :                 const char *unit,
    3407             :                 const char *filename,
    3408             :                 unsigned line,
    3409             :                 const char *section,
    3410             :                 unsigned section_line,
    3411             :                 const char *lvalue,
    3412             :                 int ltype,
    3413             :                 const char *rvalue,
    3414             :                 void *data,
    3415             :                 void *userdata) {
    3416             : 
    3417           0 :         _cleanup_free_ char *path = NULL, *resolved = NULL;
    3418             :         CGroupIODeviceWeight *w;
    3419           0 :         CGroupContext *c = data;
    3420           0 :         const char *p = rvalue;
    3421             :         uint64_t u;
    3422             :         int r;
    3423             : 
    3424           0 :         assert(filename);
    3425           0 :         assert(lvalue);
    3426           0 :         assert(rvalue);
    3427             : 
    3428           0 :         if (isempty(rvalue)) {
    3429           0 :                 while (c->io_device_weights)
    3430           0 :                         cgroup_context_free_io_device_weight(c, c->io_device_weights);
    3431             : 
    3432           0 :                 return 0;
    3433             :         }
    3434             : 
    3435           0 :         r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
    3436           0 :         if (r == -ENOMEM)
    3437           0 :                 return log_oom();
    3438           0 :         if (r < 0) {
    3439           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3440             :                            "Invalid syntax, ignoring: %s", rvalue);
    3441           0 :                 return 0;
    3442             :         }
    3443           0 :         if (r == 0 || isempty(p)) {
    3444           0 :                 log_syntax(unit, LOG_WARNING, filename, line, 0,
    3445             :                            "Failed to extract device path and weight from '%s', ignoring.", rvalue);
    3446           0 :                 return 0;
    3447             :         }
    3448             : 
    3449           0 :         r = unit_full_printf(userdata, path, &resolved);
    3450           0 :         if (r < 0) {
    3451           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3452             :                            "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
    3453           0 :                 return 0;
    3454             :         }
    3455             : 
    3456           0 :         r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
    3457           0 :         if (r < 0)
    3458           0 :                 return 0;
    3459             : 
    3460           0 :         r = cg_weight_parse(p, &u);
    3461           0 :         if (r < 0) {
    3462           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid, ignoring: %m", p);
    3463           0 :                 return 0;
    3464             :         }
    3465             : 
    3466           0 :         assert(u != CGROUP_WEIGHT_INVALID);
    3467             : 
    3468           0 :         w = new0(CGroupIODeviceWeight, 1);
    3469           0 :         if (!w)
    3470           0 :                 return log_oom();
    3471             : 
    3472           0 :         w->path = TAKE_PTR(resolved);
    3473           0 :         w->weight = u;
    3474             : 
    3475           0 :         LIST_PREPEND(device_weights, c->io_device_weights, w);
    3476           0 :         return 0;
    3477             : }
    3478             : 
    3479           0 : int config_parse_io_device_latency(
    3480             :                 const char *unit,
    3481             :                 const char *filename,
    3482             :                 unsigned line,
    3483             :                 const char *section,
    3484             :                 unsigned section_line,
    3485             :                 const char *lvalue,
    3486             :                 int ltype,
    3487             :                 const char *rvalue,
    3488             :                 void *data,
    3489             :                 void *userdata) {
    3490             : 
    3491           0 :         _cleanup_free_ char *path = NULL, *resolved = NULL;
    3492             :         CGroupIODeviceLatency *l;
    3493           0 :         CGroupContext *c = data;
    3494           0 :         const char *p = rvalue;
    3495             :         usec_t usec;
    3496             :         int r;
    3497             : 
    3498           0 :         assert(filename);
    3499           0 :         assert(lvalue);
    3500           0 :         assert(rvalue);
    3501             : 
    3502           0 :         if (isempty(rvalue)) {
    3503           0 :                 while (c->io_device_latencies)
    3504           0 :                         cgroup_context_free_io_device_latency(c, c->io_device_latencies);
    3505             : 
    3506           0 :                 return 0;
    3507             :         }
    3508             : 
    3509           0 :         r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
    3510           0 :         if (r == -ENOMEM)
    3511           0 :                 return log_oom();
    3512           0 :         if (r < 0) {
    3513           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3514             :                            "Invalid syntax, ignoring: %s", rvalue);
    3515           0 :                 return 0;
    3516             :         }
    3517           0 :         if (r == 0 || isempty(p)) {
    3518           0 :                 log_syntax(unit, LOG_WARNING, filename, line, 0,
    3519             :                            "Failed to extract device path and latency from '%s', ignoring.", rvalue);
    3520           0 :                 return 0;
    3521             :         }
    3522             : 
    3523           0 :         r = unit_full_printf(userdata, path, &resolved);
    3524           0 :         if (r < 0) {
    3525           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3526             :                            "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
    3527           0 :                 return 0;
    3528             :         }
    3529             : 
    3530           0 :         r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
    3531           0 :         if (r < 0)
    3532           0 :                 return 0;
    3533             : 
    3534           0 :         if (parse_sec(p, &usec) < 0) {
    3535           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", p);
    3536           0 :                 return 0;
    3537             :         }
    3538             : 
    3539           0 :         l = new0(CGroupIODeviceLatency, 1);
    3540           0 :         if (!l)
    3541           0 :                 return log_oom();
    3542             : 
    3543           0 :         l->path = TAKE_PTR(resolved);
    3544           0 :         l->target_usec = usec;
    3545             : 
    3546           0 :         LIST_PREPEND(device_latencies, c->io_device_latencies, l);
    3547           0 :         return 0;
    3548             : }
    3549             : 
    3550           0 : int config_parse_io_limit(
    3551             :                 const char *unit,
    3552             :                 const char *filename,
    3553             :                 unsigned line,
    3554             :                 const char *section,
    3555             :                 unsigned section_line,
    3556             :                 const char *lvalue,
    3557             :                 int ltype,
    3558             :                 const char *rvalue,
    3559             :                 void *data,
    3560             :                 void *userdata) {
    3561             : 
    3562           0 :         _cleanup_free_ char *path = NULL, *resolved = NULL;
    3563           0 :         CGroupIODeviceLimit *l = NULL, *t;
    3564           0 :         CGroupContext *c = data;
    3565             :         CGroupIOLimitType type;
    3566           0 :         const char *p = rvalue;
    3567             :         uint64_t num;
    3568             :         int r;
    3569             : 
    3570           0 :         assert(filename);
    3571           0 :         assert(lvalue);
    3572           0 :         assert(rvalue);
    3573             : 
    3574           0 :         type = cgroup_io_limit_type_from_string(lvalue);
    3575           0 :         assert(type >= 0);
    3576             : 
    3577           0 :         if (isempty(rvalue)) {
    3578           0 :                 LIST_FOREACH(device_limits, l, c->io_device_limits)
    3579           0 :                         l->limits[type] = cgroup_io_limit_defaults[type];
    3580           0 :                 return 0;
    3581             :         }
    3582             : 
    3583           0 :         r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
    3584           0 :         if (r == -ENOMEM)
    3585           0 :                 return log_oom();
    3586           0 :         if (r < 0) {
    3587           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3588             :                            "Invalid syntax, ignoring: %s", rvalue);
    3589           0 :                 return 0;
    3590             :         }
    3591           0 :         if (r == 0 || isempty(p)) {
    3592           0 :                 log_syntax(unit, LOG_WARNING, filename, line, 0,
    3593             :                            "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue);
    3594           0 :                 return 0;
    3595             :         }
    3596             : 
    3597           0 :         r = unit_full_printf(userdata, path, &resolved);
    3598           0 :         if (r < 0) {
    3599           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3600             :                            "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
    3601           0 :                 return 0;
    3602             :         }
    3603             : 
    3604           0 :         r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
    3605           0 :         if (r < 0)
    3606           0 :                 return 0;
    3607             : 
    3608           0 :         if (streq("infinity", p))
    3609           0 :                 num = CGROUP_LIMIT_MAX;
    3610             :         else {
    3611           0 :                 r = parse_size(p, 1000, &num);
    3612           0 :                 if (r < 0 || num <= 0) {
    3613           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid IO limit '%s', ignoring.", p);
    3614           0 :                         return 0;
    3615             :                 }
    3616             :         }
    3617             : 
    3618           0 :         LIST_FOREACH(device_limits, t, c->io_device_limits) {
    3619           0 :                 if (path_equal(resolved, t->path)) {
    3620           0 :                         l = t;
    3621           0 :                         break;
    3622             :                 }
    3623             :         }
    3624             : 
    3625           0 :         if (!l) {
    3626             :                 CGroupIOLimitType ttype;
    3627             : 
    3628           0 :                 l = new0(CGroupIODeviceLimit, 1);
    3629           0 :                 if (!l)
    3630           0 :                         return log_oom();
    3631             : 
    3632           0 :                 l->path = TAKE_PTR(resolved);
    3633           0 :                 for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
    3634           0 :                         l->limits[ttype] = cgroup_io_limit_defaults[ttype];
    3635             : 
    3636           0 :                 LIST_PREPEND(device_limits, c->io_device_limits, l);
    3637             :         }
    3638             : 
    3639           0 :         l->limits[type] = num;
    3640             : 
    3641           0 :         return 0;
    3642             : }
    3643             : 
    3644           0 : int config_parse_blockio_device_weight(
    3645             :                 const char *unit,
    3646             :                 const char *filename,
    3647             :                 unsigned line,
    3648             :                 const char *section,
    3649             :                 unsigned section_line,
    3650             :                 const char *lvalue,
    3651             :                 int ltype,
    3652             :                 const char *rvalue,
    3653             :                 void *data,
    3654             :                 void *userdata) {
    3655             : 
    3656           0 :         _cleanup_free_ char *path = NULL, *resolved = NULL;
    3657             :         CGroupBlockIODeviceWeight *w;
    3658           0 :         CGroupContext *c = data;
    3659           0 :         const char *p = rvalue;
    3660             :         uint64_t u;
    3661             :         int r;
    3662             : 
    3663           0 :         assert(filename);
    3664           0 :         assert(lvalue);
    3665           0 :         assert(rvalue);
    3666             : 
    3667           0 :         if (isempty(rvalue)) {
    3668           0 :                 while (c->blockio_device_weights)
    3669           0 :                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
    3670             : 
    3671           0 :                 return 0;
    3672             :         }
    3673             : 
    3674           0 :         r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
    3675           0 :         if (r == -ENOMEM)
    3676           0 :                 return log_oom();
    3677           0 :         if (r < 0) {
    3678           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3679             :                            "Invalid syntax, ignoring: %s", rvalue);
    3680           0 :                 return 0;
    3681             :         }
    3682           0 :         if (r == 0 || isempty(p)) {
    3683           0 :                 log_syntax(unit, LOG_WARNING, filename, line, 0,
    3684             :                            "Failed to extract device node and weight from '%s', ignoring.", rvalue);
    3685           0 :                 return 0;
    3686             :         }
    3687             : 
    3688           0 :         r = unit_full_printf(userdata, path, &resolved);
    3689           0 :         if (r < 0) {
    3690           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3691             :                            "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
    3692           0 :                 return 0;
    3693             :         }
    3694             : 
    3695           0 :         r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
    3696           0 :         if (r < 0)
    3697           0 :                 return 0;
    3698             : 
    3699           0 :         r = cg_blkio_weight_parse(p, &u);
    3700           0 :         if (r < 0) {
    3701           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid block IO weight '%s', ignoring: %m", p);
    3702           0 :                 return 0;
    3703             :         }
    3704             : 
    3705           0 :         assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
    3706             : 
    3707           0 :         w = new0(CGroupBlockIODeviceWeight, 1);
    3708           0 :         if (!w)
    3709           0 :                 return log_oom();
    3710             : 
    3711           0 :         w->path = TAKE_PTR(resolved);
    3712           0 :         w->weight = u;
    3713             : 
    3714           0 :         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
    3715           0 :         return 0;
    3716             : }
    3717             : 
    3718           0 : int config_parse_blockio_bandwidth(
    3719             :                 const char *unit,
    3720             :                 const char *filename,
    3721             :                 unsigned line,
    3722             :                 const char *section,
    3723             :                 unsigned section_line,
    3724             :                 const char *lvalue,
    3725             :                 int ltype,
    3726             :                 const char *rvalue,
    3727             :                 void *data,
    3728             :                 void *userdata) {
    3729             : 
    3730           0 :         _cleanup_free_ char *path = NULL, *resolved = NULL;
    3731           0 :         CGroupBlockIODeviceBandwidth *b = NULL, *t;
    3732           0 :         CGroupContext *c = data;
    3733           0 :         const char *p = rvalue;
    3734             :         uint64_t bytes;
    3735             :         bool read;
    3736             :         int r;
    3737             : 
    3738           0 :         assert(filename);
    3739           0 :         assert(lvalue);
    3740           0 :         assert(rvalue);
    3741             : 
    3742           0 :         read = streq("BlockIOReadBandwidth", lvalue);
    3743             : 
    3744           0 :         if (isempty(rvalue)) {
    3745           0 :                 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
    3746           0 :                         b->rbps = CGROUP_LIMIT_MAX;
    3747           0 :                         b->wbps = CGROUP_LIMIT_MAX;
    3748             :                 }
    3749           0 :                 return 0;
    3750             :         }
    3751             : 
    3752           0 :         r = extract_first_word(&p, &path, NULL, EXTRACT_UNQUOTE);
    3753           0 :         if (r == -ENOMEM)
    3754           0 :                 return log_oom();
    3755           0 :         if (r < 0) {
    3756           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3757             :                            "Invalid syntax, ignoring: %s", rvalue);
    3758           0 :                 return 0;
    3759             :         }
    3760           0 :         if (r == 0 || isempty(p)) {
    3761           0 :                 log_syntax(unit, LOG_WARNING, filename, line, 0,
    3762             :                            "Failed to extract device node and bandwidth from '%s', ignoring.", rvalue);
    3763           0 :                 return 0;
    3764             :         }
    3765             : 
    3766           0 :         r = unit_full_printf(userdata, path, &resolved);
    3767           0 :         if (r < 0) {
    3768           0 :                 log_syntax(unit, LOG_WARNING, filename, line, r,
    3769             :                            "Failed to resolve unit specifiers in '%s', ignoring: %m", path);
    3770           0 :                 return 0;
    3771             :         }
    3772             : 
    3773           0 :         r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue);
    3774           0 :         if (r < 0)
    3775           0 :                 return 0;
    3776             : 
    3777           0 :         r = parse_size(p, 1000, &bytes);
    3778           0 :         if (r < 0 || bytes <= 0) {
    3779           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid Block IO Bandwidth '%s', ignoring.", p);
    3780           0 :                 return 0;
    3781             :         }
    3782             : 
    3783           0 :         LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
    3784           0 :                 if (path_equal(resolved, t->path)) {
    3785           0 :                         b = t;
    3786           0 :                         break;
    3787             :                 }
    3788             :         }
    3789             : 
    3790           0 :         if (!t) {
    3791           0 :                 b = new0(CGroupBlockIODeviceBandwidth, 1);
    3792           0 :                 if (!b)
    3793           0 :                         return log_oom();
    3794             : 
    3795           0 :                 b->path = TAKE_PTR(resolved);
    3796           0 :                 b->rbps = CGROUP_LIMIT_MAX;
    3797           0 :                 b->wbps = CGROUP_LIMIT_MAX;
    3798             : 
    3799           0 :                 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
    3800             :         }
    3801             : 
    3802           0 :         if (read)
    3803           0 :                 b->rbps = bytes;
    3804             :         else
    3805           0 :                 b->wbps = bytes;
    3806             : 
    3807           0 :         return 0;
    3808             : }
    3809             : 
    3810           0 : int config_parse_job_mode_isolate(
    3811             :                 const char *unit,
    3812             :                 const char *filename,
    3813             :                 unsigned line,
    3814             :                 const char *section,
    3815             :                 unsigned section_line,
    3816             :                 const char *lvalue,
    3817             :                 int ltype,
    3818             :                 const char *rvalue,
    3819             :                 void *data,
    3820             :                 void *userdata) {
    3821             : 
    3822           0 :         JobMode *m = data;
    3823             :         int r;
    3824             : 
    3825           0 :         assert(filename);
    3826           0 :         assert(lvalue);
    3827           0 :         assert(rvalue);
    3828             : 
    3829           0 :         r = parse_boolean(rvalue);
    3830           0 :         if (r < 0) {
    3831           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
    3832           0 :                 return 0;
    3833             :         }
    3834             : 
    3835           0 :         log_notice("%s is deprecated. Please use OnFailureJobMode= instead", lvalue);
    3836             : 
    3837           0 :         *m = r ? JOB_ISOLATE : JOB_REPLACE;
    3838           0 :         return 0;
    3839             : }
    3840             : 
    3841           0 : int config_parse_exec_directories(
    3842             :                 const char *unit,
    3843             :                 const char *filename,
    3844             :                 unsigned line,
    3845             :                 const char *section,
    3846             :                 unsigned section_line,
    3847             :                 const char *lvalue,
    3848             :                 int ltype,
    3849             :                 const char *rvalue,
    3850             :                 void *data,
    3851             :                 void *userdata) {
    3852             : 
    3853           0 :         char***rt = data;
    3854           0 :         Unit *u = userdata;
    3855             :         const char *p;
    3856             :         int r;
    3857             : 
    3858           0 :         assert(filename);
    3859           0 :         assert(lvalue);
    3860           0 :         assert(rvalue);
    3861           0 :         assert(data);
    3862             : 
    3863           0 :         if (isempty(rvalue)) {
    3864             :                 /* Empty assignment resets the list */
    3865           0 :                 *rt = strv_free(*rt);
    3866           0 :                 return 0;
    3867             :         }
    3868             : 
    3869           0 :         for (p = rvalue;;) {
    3870           0 :                 _cleanup_free_ char *word = NULL, *k = NULL;
    3871             : 
    3872           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    3873           0 :                 if (r == -ENOMEM)
    3874           0 :                         return log_oom();
    3875           0 :                 if (r < 0) {
    3876           0 :                         log_syntax(unit, LOG_WARNING, filename, line, r,
    3877             :                                    "Invalid syntax, ignoring: %s", rvalue);
    3878           0 :                         return 0;
    3879             :                 }
    3880           0 :                 if (r == 0)
    3881           0 :                         return 0;
    3882             : 
    3883           0 :                 r = unit_full_printf(u, word, &k);
    3884           0 :                 if (r < 0) {
    3885           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    3886             :                                    "Failed to resolve unit specifiers in \"%s\", ignoring: %m", word);
    3887           0 :                         continue;
    3888             :                 }
    3889             : 
    3890           0 :                 r = path_simplify_and_warn(k, PATH_CHECK_RELATIVE, unit, filename, line, lvalue);
    3891           0 :                 if (r < 0)
    3892           0 :                         continue;
    3893             : 
    3894           0 :                 if (path_startswith(k, "private")) {
    3895           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
    3896             :                                    "%s= path can't be 'private', ignoring assignment: %s", lvalue, word);
    3897           0 :                         continue;
    3898             :                 }
    3899             : 
    3900           0 :                 r = strv_push(rt, k);
    3901           0 :                 if (r < 0)
    3902           0 :                         return log_oom();
    3903           0 :                 k = NULL;
    3904             :         }
    3905             : }
    3906             : 
    3907           0 : int config_parse_set_status(
    3908             :                 const char *unit,
    3909             :                 const char *filename,
    3910             :                 unsigned line,
    3911             :                 const char *section,
    3912             :                 unsigned section_line,
    3913             :                 const char *lvalue,
    3914             :                 int ltype,
    3915             :                 const char *rvalue,
    3916             :                 void *data,
    3917             :                 void *userdata) {
    3918             : 
    3919             :         size_t l;
    3920             :         const char *word, *state;
    3921             :         int r;
    3922           0 :         ExitStatusSet *status_set = data;
    3923             : 
    3924           0 :         assert(filename);
    3925           0 :         assert(lvalue);
    3926           0 :         assert(rvalue);
    3927           0 :         assert(data);
    3928             : 
    3929             :         /* Empty assignment resets the list */
    3930           0 :         if (isempty(rvalue)) {
    3931           0 :                 exit_status_set_free(status_set);
    3932           0 :                 return 0;
    3933             :         }
    3934             : 
    3935           0 :         FOREACH_WORD(word, l, rvalue, state) {
    3936           0 :                 _cleanup_free_ char *temp;
    3937             :                 Bitmap *bitmap;
    3938             : 
    3939           0 :                 temp = strndup(word, l);
    3940           0 :                 if (!temp)
    3941           0 :                         return log_oom();
    3942             : 
    3943             :                 /* We need to call exit_status_from_string() first, because we want
    3944             :                  * to parse numbers as exit statuses, not signals. */
    3945             : 
    3946           0 :                 r = exit_status_from_string(temp);
    3947           0 :                 if (r >= 0) {
    3948           0 :                         assert(r >= 0 && r < 256);
    3949           0 :                         bitmap = &status_set->status;
    3950             :                 } else {
    3951           0 :                         r = signal_from_string(temp);
    3952             : 
    3953           0 :                         if (r <= 0) {
    3954           0 :                                 log_syntax(unit, LOG_ERR, filename, line, 0,
    3955             :                                            "Failed to parse value, ignoring: %s", word);
    3956           0 :                                 continue;
    3957             :                         }
    3958           0 :                         bitmap = &status_set->signal;
    3959             :                 }
    3960             : 
    3961           0 :                 r = bitmap_set(bitmap, r);
    3962           0 :                 if (r < 0)
    3963           0 :                         return log_error_errno(r, "Failed to set signal or status %s: %m", word);
    3964             :         }
    3965           0 :         if (!isempty(state))
    3966           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
    3967             : 
    3968           0 :         return 0;
    3969             : }
    3970             : 
    3971           0 : int config_parse_namespace_path_strv(
    3972             :                 const char *unit,
    3973             :                 const char *filename,
    3974             :                 unsigned line,
    3975             :                 const char *section,
    3976             :                 unsigned section_line,
    3977             :                 const char *lvalue,
    3978             :                 int ltype,
    3979             :                 const char *rvalue,
    3980             :                 void *data,
    3981             :                 void *userdata) {
    3982             : 
    3983           0 :         Unit *u = userdata;
    3984           0 :         char*** sv = data;
    3985           0 :         const char *p = rvalue;
    3986             :         int r;
    3987             : 
    3988           0 :         assert(filename);
    3989           0 :         assert(lvalue);
    3990           0 :         assert(rvalue);
    3991           0 :         assert(data);
    3992             : 
    3993           0 :         if (isempty(rvalue)) {
    3994             :                 /* Empty assignment resets the list */
    3995           0 :                 *sv = strv_free(*sv);
    3996           0 :                 return 0;
    3997             :         }
    3998             : 
    3999           0 :         for (;;) {
    4000           0 :                 _cleanup_free_ char *word = NULL, *resolved = NULL, *joined = NULL;
    4001             :                 const char *w;
    4002           0 :                 bool ignore_enoent = false, shall_prefix = false;
    4003             : 
    4004           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    4005           0 :                 if (r == 0)
    4006           0 :                         break;
    4007           0 :                 if (r == -ENOMEM)
    4008           0 :                         return log_oom();
    4009           0 :                 if (r < 0) {
    4010           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
    4011           0 :                         return 0;
    4012             :                 }
    4013             : 
    4014           0 :                 w = word;
    4015           0 :                 if (startswith(w, "-")) {
    4016           0 :                         ignore_enoent = true;
    4017           0 :                         w++;
    4018             :                 }
    4019           0 :                 if (startswith(w, "+")) {
    4020           0 :                         shall_prefix = true;
    4021           0 :                         w++;
    4022             :                 }
    4023             : 
    4024           0 :                 r = unit_full_printf(u, w, &resolved);
    4025           0 :                 if (r < 0) {
    4026           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", w);
    4027           0 :                         continue;
    4028             :                 }
    4029             : 
    4030           0 :                 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    4031           0 :                 if (r < 0)
    4032           0 :                         continue;
    4033             : 
    4034           0 :                 joined = strjoin(ignore_enoent ? "-" : "",
    4035             :                                  shall_prefix ? "+" : "",
    4036             :                                  resolved);
    4037             : 
    4038           0 :                 r = strv_push(sv, joined);
    4039           0 :                 if (r < 0)
    4040           0 :                         return log_oom();
    4041             : 
    4042           0 :                 joined = NULL;
    4043             :         }
    4044             : 
    4045           0 :         return 0;
    4046             : }
    4047             : 
    4048           0 : int config_parse_temporary_filesystems(
    4049             :                 const char *unit,
    4050             :                 const char *filename,
    4051             :                 unsigned line,
    4052             :                 const char *section,
    4053             :                 unsigned section_line,
    4054             :                 const char *lvalue,
    4055             :                 int ltype,
    4056             :                 const char *rvalue,
    4057             :                 void *data,
    4058             :                 void *userdata) {
    4059             : 
    4060           0 :         Unit *u = userdata;
    4061           0 :         ExecContext *c = data;
    4062           0 :         const char *p = rvalue;
    4063             :         int r;
    4064             : 
    4065           0 :         assert(filename);
    4066           0 :         assert(lvalue);
    4067           0 :         assert(rvalue);
    4068           0 :         assert(data);
    4069             : 
    4070           0 :         if (isempty(rvalue)) {
    4071             :                 /* Empty assignment resets the list */
    4072           0 :                 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
    4073           0 :                 c->temporary_filesystems = NULL;
    4074           0 :                 c->n_temporary_filesystems = 0;
    4075           0 :                 return 0;
    4076             :         }
    4077             : 
    4078           0 :         for (;;) {
    4079           0 :                 _cleanup_free_ char *word = NULL, *path = NULL, *resolved = NULL;
    4080             :                 const char *w;
    4081             : 
    4082           0 :                 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
    4083           0 :                 if (r == 0)
    4084           0 :                         return 0;
    4085           0 :                 if (r == -ENOMEM)
    4086           0 :                         return log_oom();
    4087           0 :                 if (r < 0) {
    4088           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
    4089           0 :                         return 0;
    4090             :                 }
    4091             : 
    4092           0 :                 w = word;
    4093           0 :                 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
    4094           0 :                 if (r == -ENOMEM)
    4095           0 :                         return log_oom();
    4096           0 :                 if (r < 0) {
    4097           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract first word, ignoring: %s", word);
    4098           0 :                         continue;
    4099             :                 }
    4100           0 :                 if (r == 0) {
    4101           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", word);
    4102           0 :                         continue;
    4103             :                 }
    4104             : 
    4105           0 :                 r = unit_full_printf(u, path, &resolved);
    4106           0 :                 if (r < 0) {
    4107           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", path);
    4108           0 :                         continue;
    4109             :                 }
    4110             : 
    4111           0 :                 r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    4112           0 :                 if (r < 0)
    4113           0 :                         continue;
    4114             : 
    4115           0 :                 r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, resolved, w);
    4116           0 :                 if (r < 0)
    4117           0 :                         return log_oom();
    4118             :         }
    4119             : }
    4120             : 
    4121           0 : int config_parse_bind_paths(
    4122             :                 const char *unit,
    4123             :                 const char *filename,
    4124             :                 unsigned line,
    4125             :                 const char *section,
    4126             :                 unsigned section_line,
    4127             :                 const char *lvalue,
    4128             :                 int ltype,
    4129             :                 const char *rvalue,
    4130             :                 void *data,
    4131             :                 void *userdata) {
    4132             : 
    4133           0 :         ExecContext *c = data;
    4134           0 :         Unit *u = userdata;
    4135             :         const char *p;
    4136             :         int r;
    4137             : 
    4138           0 :         assert(filename);
    4139           0 :         assert(lvalue);
    4140           0 :         assert(rvalue);
    4141           0 :         assert(data);
    4142             : 
    4143           0 :         if (isempty(rvalue)) {
    4144             :                 /* Empty assignment resets the list */
    4145           0 :                 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
    4146           0 :                 c->bind_mounts = NULL;
    4147           0 :                 c->n_bind_mounts = 0;
    4148           0 :                 return 0;
    4149             :         }
    4150             : 
    4151           0 :         p = rvalue;
    4152           0 :         for (;;) {
    4153           0 :                 _cleanup_free_ char *source = NULL, *destination = NULL;
    4154           0 :                 _cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
    4155           0 :                 char *s = NULL, *d = NULL;
    4156           0 :                 bool rbind = true, ignore_enoent = false;
    4157             : 
    4158           0 :                 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
    4159           0 :                 if (r == 0)
    4160           0 :                         break;
    4161           0 :                 if (r == -ENOMEM)
    4162           0 :                         return log_oom();
    4163           0 :                 if (r < 0) {
    4164           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
    4165           0 :                         return 0;
    4166             :                 }
    4167             : 
    4168           0 :                 r = unit_full_printf(u, source, &sresolved);
    4169           0 :                 if (r < 0) {
    4170           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    4171             :                                    "Failed to resolved unit specifiers in \"%s\", ignoring: %m", source);
    4172           0 :                         continue;
    4173             :                 }
    4174             : 
    4175           0 :                 s = sresolved;
    4176           0 :                 if (s[0] == '-') {
    4177           0 :                         ignore_enoent = true;
    4178           0 :                         s++;
    4179             :                 }
    4180             : 
    4181           0 :                 r = path_simplify_and_warn(s, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    4182           0 :                 if (r < 0)
    4183           0 :                         continue;
    4184             : 
    4185             :                 /* Optionally, the destination is specified. */
    4186           0 :                 if (p && p[-1] == ':') {
    4187           0 :                         r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
    4188           0 :                         if (r == -ENOMEM)
    4189           0 :                                 return log_oom();
    4190           0 :                         if (r < 0) {
    4191           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
    4192           0 :                                 return 0;
    4193             :                         }
    4194           0 :                         if (r == 0) {
    4195           0 :                                 log_syntax(unit, LOG_ERR, filename, line, 0, "Missing argument after ':', ignoring: %s", s);
    4196           0 :                                 continue;
    4197             :                         }
    4198             : 
    4199           0 :                         r = unit_full_printf(u, destination, &dresolved);
    4200           0 :                         if (r < 0) {
    4201           0 :                                 log_syntax(unit, LOG_ERR, filename, line, r,
    4202             :                                            "Failed to resolved specifiers in \"%s\", ignoring: %m", destination);
    4203           0 :                                 continue;
    4204             :                         }
    4205             : 
    4206           0 :                         r = path_simplify_and_warn(dresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    4207           0 :                         if (r < 0)
    4208           0 :                                 continue;
    4209             : 
    4210           0 :                         d = dresolved;
    4211             : 
    4212             :                         /* Optionally, there's also a short option string specified */
    4213           0 :                         if (p && p[-1] == ':') {
    4214           0 :                                 _cleanup_free_ char *options = NULL;
    4215             : 
    4216           0 :                                 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
    4217           0 :                                 if (r == -ENOMEM)
    4218           0 :                                         return log_oom();
    4219           0 :                                 if (r < 0) {
    4220           0 :                                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
    4221           0 :                                         return 0;
    4222             :                                 }
    4223             : 
    4224           0 :                                 if (isempty(options) || streq(options, "rbind"))
    4225           0 :                                         rbind = true;
    4226           0 :                                 else if (streq(options, "norbind"))
    4227           0 :                                         rbind = false;
    4228             :                                 else {
    4229           0 :                                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid option string, ignoring setting: %s", options);
    4230           0 :                                         continue;
    4231             :                                 }
    4232             :                         }
    4233             :                 } else
    4234           0 :                         d = s;
    4235             : 
    4236           0 :                 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
    4237           0 :                                    &(BindMount) {
    4238             :                                            .source = s,
    4239             :                                            .destination = d,
    4240           0 :                                            .read_only = !!strstr(lvalue, "ReadOnly"),
    4241             :                                            .recursive = rbind,
    4242             :                                            .ignore_enoent = ignore_enoent,
    4243             :                                    });
    4244           0 :                 if (r < 0)
    4245           0 :                         return log_oom();
    4246             :         }
    4247             : 
    4248           0 :         return 0;
    4249             : }
    4250             : 
    4251           0 : int config_parse_job_timeout_sec(
    4252             :                 const char* unit,
    4253             :                 const char *filename,
    4254             :                 unsigned line,
    4255             :                 const char *section,
    4256             :                 unsigned section_line,
    4257             :                 const char *lvalue,
    4258             :                 int ltype,
    4259             :                 const char *rvalue,
    4260             :                 void *data,
    4261             :                 void *userdata) {
    4262             : 
    4263           0 :         Unit *u = data;
    4264             :         usec_t usec;
    4265             :         int r;
    4266             : 
    4267           0 :         assert(filename);
    4268           0 :         assert(lvalue);
    4269           0 :         assert(rvalue);
    4270           0 :         assert(u);
    4271             : 
    4272           0 :         r = parse_sec_fix_0(rvalue, &usec);
    4273           0 :         if (r < 0) {
    4274           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
    4275           0 :                 return 0;
    4276             :         }
    4277             : 
    4278             :         /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
    4279             :          * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
    4280             :          * count. */
    4281             : 
    4282           0 :         if (!u->job_running_timeout_set)
    4283           0 :                 u->job_running_timeout = usec;
    4284             : 
    4285           0 :         u->job_timeout = usec;
    4286             : 
    4287           0 :         return 0;
    4288             : }
    4289             : 
    4290           0 : int config_parse_job_running_timeout_sec(
    4291             :                 const char* unit,
    4292             :                 const char *filename,
    4293             :                 unsigned line,
    4294             :                 const char *section,
    4295             :                 unsigned section_line,
    4296             :                 const char *lvalue,
    4297             :                 int ltype,
    4298             :                 const char *rvalue,
    4299             :                 void *data,
    4300             :                 void *userdata) {
    4301             : 
    4302           0 :         Unit *u = data;
    4303             :         usec_t usec;
    4304             :         int r;
    4305             : 
    4306           0 :         assert(filename);
    4307           0 :         assert(lvalue);
    4308           0 :         assert(rvalue);
    4309           0 :         assert(u);
    4310             : 
    4311           0 :         r = parse_sec_fix_0(rvalue, &usec);
    4312           0 :         if (r < 0) {
    4313           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
    4314           0 :                 return 0;
    4315             :         }
    4316             : 
    4317           0 :         u->job_running_timeout = usec;
    4318           0 :         u->job_running_timeout_set = true;
    4319             : 
    4320           0 :         return 0;
    4321             : }
    4322             : 
    4323           0 : int config_parse_emergency_action(
    4324             :                 const char* unit,
    4325             :                 const char *filename,
    4326             :                 unsigned line,
    4327             :                 const char *section,
    4328             :                 unsigned section_line,
    4329             :                 const char *lvalue,
    4330             :                 int ltype,
    4331             :                 const char *rvalue,
    4332             :                 void *data,
    4333             :                 void *userdata) {
    4334             : 
    4335           0 :         Manager *m = NULL;
    4336           0 :         EmergencyAction *x = data;
    4337             :         int r;
    4338             : 
    4339           0 :         assert(filename);
    4340           0 :         assert(lvalue);
    4341           0 :         assert(rvalue);
    4342           0 :         assert(data);
    4343             : 
    4344           0 :         if (unit)
    4345           0 :                 m = ((Unit*) userdata)->manager;
    4346             :         else
    4347           0 :                 m = data;
    4348             : 
    4349           0 :         r = parse_emergency_action(rvalue, MANAGER_IS_SYSTEM(m), x);
    4350           0 :         if (r < 0) {
    4351           0 :                 if (r == -EOPNOTSUPP && MANAGER_IS_USER(m)) {
    4352             :                         /* Compat mode: remove for systemd 241. */
    4353             : 
    4354           0 :                         log_syntax(unit, LOG_INFO, filename, line, r,
    4355             :                                    "%s= in user mode specified as \"%s\", using \"exit-force\" instead.",
    4356             :                                    lvalue, rvalue);
    4357           0 :                         *x = EMERGENCY_ACTION_EXIT_FORCE;
    4358           0 :                         return 0;
    4359             :                 }
    4360             : 
    4361           0 :                 if (r == -EOPNOTSUPP)
    4362           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    4363             :                                    "%s= specified as %s mode action, ignoring: %s",
    4364             :                                    lvalue, MANAGER_IS_SYSTEM(m) ? "user" : "system", rvalue);
    4365             :                 else
    4366           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    4367             :                                    "Failed to parse %s=, ignoring: %s", lvalue, rvalue);
    4368           0 :                 return 0;
    4369             :         }
    4370             : 
    4371           0 :         return 0;
    4372             : }
    4373             : 
    4374           0 : int config_parse_pid_file(
    4375             :                 const char *unit,
    4376             :                 const char *filename,
    4377             :                 unsigned line,
    4378             :                 const char *section,
    4379             :                 unsigned section_line,
    4380             :                 const char *lvalue,
    4381             :                 int ltype,
    4382             :                 const char *rvalue,
    4383             :                 void *data,
    4384             :                 void *userdata) {
    4385             : 
    4386           0 :         _cleanup_free_ char *k = NULL, *n = NULL;
    4387           0 :         Unit *u = userdata;
    4388           0 :         char **s = data;
    4389             :         int r;
    4390             : 
    4391           0 :         assert(filename);
    4392           0 :         assert(lvalue);
    4393           0 :         assert(rvalue);
    4394           0 :         assert(u);
    4395             : 
    4396           0 :         if (isempty(rvalue)) {
    4397             :                 /* An empty assignment removes already set value. */
    4398           0 :                 *s = mfree(*s);
    4399           0 :                 return 0;
    4400             :         }
    4401             : 
    4402           0 :         r = unit_full_printf(u, rvalue, &k);
    4403           0 :         if (r < 0) {
    4404           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
    4405           0 :                 return 0;
    4406             :         }
    4407             : 
    4408             :         /* If this is a relative path make it absolute by prefixing the /run */
    4409           0 :         n = path_make_absolute(k, u->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
    4410           0 :         if (!n)
    4411           0 :                 return log_oom();
    4412             : 
    4413             :         /* Check that the result is a sensible path */
    4414           0 :         r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    4415           0 :         if (r < 0)
    4416           0 :                 return r;
    4417             : 
    4418           0 :         r = patch_var_run(unit, filename, line, lvalue, &n);
    4419           0 :         if (r < 0)
    4420           0 :                 return r;
    4421             : 
    4422           0 :         free_and_replace(*s, n);
    4423           0 :         return 0;
    4424             : }
    4425             : 
    4426           0 : int config_parse_exit_status(
    4427             :                 const char *unit,
    4428             :                 const char *filename,
    4429             :                 unsigned line,
    4430             :                 const char *section,
    4431             :                 unsigned section_line,
    4432             :                 const char *lvalue,
    4433             :                 int ltype,
    4434             :                 const char *rvalue,
    4435             :                 void *data,
    4436             :                 void *userdata) {
    4437             : 
    4438           0 :         int *exit_status = data, r;
    4439             :         uint8_t u;
    4440             : 
    4441           0 :         assert(filename);
    4442           0 :         assert(lvalue);
    4443           0 :         assert(rvalue);
    4444           0 :         assert(exit_status);
    4445             : 
    4446           0 :         if (isempty(rvalue)) {
    4447           0 :                 *exit_status = -1;
    4448           0 :                 return 0;
    4449             :         }
    4450             : 
    4451           0 :         r = safe_atou8(rvalue, &u);
    4452           0 :         if (r < 0) {
    4453           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse exit status '%s', ignoring: %m", rvalue);
    4454           0 :                 return 0;
    4455             :         }
    4456             : 
    4457           0 :         *exit_status = u;
    4458           0 :         return 0;
    4459             : }
    4460             : 
    4461           1 : int config_parse_disable_controllers(
    4462             :                 const char *unit,
    4463             :                 const char *filename,
    4464             :                 unsigned line,
    4465             :                 const char *section,
    4466             :                 unsigned section_line,
    4467             :                 const char *lvalue,
    4468             :                 int ltype,
    4469             :                 const char *rvalue,
    4470             :                 void *data,
    4471             :                 void *userdata) {
    4472             : 
    4473             :         int r;
    4474           1 :         CGroupContext *c = data;
    4475             :         CGroupMask disabled_mask;
    4476             : 
    4477             :         /* 1. If empty, make all controllers eligible for use again.
    4478             :          * 2. If non-empty, merge all listed controllers, space separated. */
    4479             : 
    4480           1 :         if (isempty(rvalue)) {
    4481           0 :                 c->disable_controllers = 0;
    4482           0 :                 return 0;
    4483             :         }
    4484             : 
    4485           1 :         r = cg_mask_from_string(rvalue, &disabled_mask);
    4486           1 :         if (r < 0 || disabled_mask <= 0) {
    4487           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid cgroup string: %s, ignoring", rvalue);
    4488           0 :                 return 0;
    4489             :         }
    4490             : 
    4491           1 :         c->disable_controllers |= disabled_mask;
    4492             : 
    4493           1 :         return 0;
    4494             : }
    4495             : 
    4496           0 : int config_parse_ip_filter_bpf_progs(
    4497             :                 const char *unit,
    4498             :                 const char *filename,
    4499             :                 unsigned line,
    4500             :                 const char *section,
    4501             :                 unsigned section_line,
    4502             :                 const char *lvalue,
    4503             :                 int ltype,
    4504             :                 const char *rvalue,
    4505             :                 void *data,
    4506             :                 void *userdata) {
    4507             : 
    4508           0 :         _cleanup_free_ char *resolved = NULL;
    4509           0 :         Unit *u = userdata;
    4510           0 :         char ***paths = data;
    4511             :         int r;
    4512             : 
    4513           0 :         assert(filename);
    4514           0 :         assert(lvalue);
    4515           0 :         assert(rvalue);
    4516           0 :         assert(paths);
    4517             : 
    4518           0 :         if (isempty(rvalue)) {
    4519           0 :                 *paths = strv_free(*paths);
    4520           0 :                 return 0;
    4521             :         }
    4522             : 
    4523           0 :         r = unit_full_printf(u, rvalue, &resolved);
    4524           0 :         if (r < 0) {
    4525           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
    4526           0 :                 return 0;
    4527             :         }
    4528             : 
    4529           0 :         r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
    4530           0 :         if (r < 0)
    4531           0 :                 return 0;
    4532             : 
    4533           0 :         if (strv_contains(*paths, resolved))
    4534           0 :                 return 0;
    4535             : 
    4536           0 :         r = strv_extend(paths, resolved);
    4537           0 :         if (r < 0)
    4538           0 :                 return log_oom();
    4539             : 
    4540           0 :         r = bpf_firewall_supported();
    4541           0 :         if (r < 0)
    4542           0 :                 return r;
    4543           0 :         if (r != BPF_FIREWALL_SUPPORTED_WITH_MULTI) {
    4544             :                 static bool warned = false;
    4545             : 
    4546           0 :                 log_full(warned ? LOG_DEBUG : LOG_WARNING,
    4547             :                          "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"
    4548             :                          "Starting this unit will fail! (This warning is only shown for the first loaded unit using IP firewalling.)", filename, line, lvalue, rvalue);
    4549             : 
    4550           0 :                 warned = true;
    4551             :         }
    4552             : 
    4553           0 :         return 0;
    4554             : }
    4555             : 
    4556        2144 : static int merge_by_names(Unit **u, Set *names, const char *id) {
    4557             :         char *k;
    4558             :         int r;
    4559             : 
    4560        2144 :         assert(u);
    4561        2144 :         assert(*u);
    4562             : 
    4563             :         /* Let's try to add in all names that are aliases of this unit */
    4564        4324 :         while ((k = set_steal_first(names))) {
    4565        2180 :                 _cleanup_free_ _unused_ char *free_k = k;
    4566             : 
    4567             :                 /* First try to merge in the other name into our unit */
    4568        2180 :                 r = unit_merge_by_name(*u, k);
    4569        2180 :                 if (r < 0) {
    4570             :                         Unit *other;
    4571             : 
    4572             :                         /* Hmm, we couldn't merge the other unit into ours? Then let's try it the other way
    4573             :                          * round. */
    4574             : 
    4575           0 :                         other = manager_get_unit((*u)->manager, k);
    4576           0 :                         if (!other)
    4577           0 :                                 return r; /* return previous failure */
    4578             : 
    4579           0 :                         r = unit_merge(other, *u);
    4580           0 :                         if (r < 0)
    4581           0 :                                 return r;
    4582             : 
    4583           0 :                         *u = other;
    4584           0 :                         return merge_by_names(u, names, NULL);
    4585             :                 }
    4586             : 
    4587        2180 :                 if (streq_ptr(id, k))
    4588        2144 :                         unit_choose_id(*u, id);
    4589             :         }
    4590             : 
    4591        2144 :         return 0;
    4592             : }
    4593             : 
    4594        2155 : int unit_load_fragment(Unit *u) {
    4595             :         const char *fragment;
    4596        2155 :         _cleanup_set_free_free_ Set *names = NULL;
    4597             :         int r;
    4598             : 
    4599        2155 :         assert(u);
    4600        2155 :         assert(u->load_state == UNIT_STUB);
    4601        2155 :         assert(u->id);
    4602             : 
    4603        2155 :         if (u->transient) {
    4604          11 :                 u->load_state = UNIT_LOADED;
    4605          11 :                 return 0;
    4606             :         }
    4607             : 
    4608             :         /* Possibly rebuild the fragment map to catch new units */
    4609        8576 :         r = unit_file_build_name_map(&u->manager->lookup_paths,
    4610        2144 :                                      &u->manager->unit_cache_mtime,
    4611        2144 :                                      &u->manager->unit_id_map,
    4612        2144 :                                      &u->manager->unit_name_map,
    4613        2144 :                                      &u->manager->unit_path_cache);
    4614        2144 :         if (r < 0)
    4615           0 :                 log_error_errno(r, "Failed to rebuild name map: %m");
    4616             : 
    4617        2144 :         r = unit_file_find_fragment(u->manager->unit_id_map,
    4618        2144 :                                     u->manager->unit_name_map,
    4619        2144 :                                     u->id,
    4620             :                                     &fragment,
    4621             :                                     &names);
    4622        2144 :         if (r < 0 && r != -ENOENT)
    4623           0 :                 return r;
    4624             : 
    4625        2144 :         if (fragment) {
    4626             :                 /* Open the file, check if this is a mask, otherwise read. */
    4627          88 :                 _cleanup_fclose_ FILE *f = NULL;
    4628             :                 struct stat st;
    4629             : 
    4630             :                 /* Try to open the file name. A symlink is OK, for example for linked files or masks. We
    4631             :                  * expect that all symlinks within the lookup paths have been already resolved, but we don't
    4632             :                  * verify this here. */
    4633          88 :                 f = fopen(fragment, "re");
    4634          88 :                 if (!f)
    4635           0 :                         return log_unit_notice_errno(u, errno, "Failed to open %s: %m", fragment);
    4636             : 
    4637          88 :                 if (fstat(fileno(f), &st) < 0)
    4638           0 :                         return -errno;
    4639             : 
    4640          88 :                 r = free_and_strdup(&u->fragment_path, fragment);
    4641          88 :                 if (r < 0)
    4642           0 :                         return r;
    4643             : 
    4644          88 :                 if (null_or_empty(&st)) {
    4645           0 :                         u->load_state = UNIT_MASKED;
    4646           0 :                         u->fragment_mtime = 0;
    4647             :                 } else {
    4648          88 :                         u->load_state = UNIT_LOADED;
    4649          88 :                         u->fragment_mtime = timespec_load(&st.st_mtim);
    4650             : 
    4651             :                         /* Now, parse the file contents */
    4652          88 :                         r = config_parse(u->id, fragment, f,
    4653          88 :                                          UNIT_VTABLE(u)->sections,
    4654             :                                          config_item_perf_lookup, load_fragment_gperf_lookup,
    4655             :                                          CONFIG_PARSE_ALLOW_INCLUDE, u);
    4656          88 :                         if (r == -ENOEXEC)
    4657           0 :                                 log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started.");
    4658          88 :                         if (r < 0)
    4659           0 :                                 return r;
    4660             :                 }
    4661             :         }
    4662             : 
    4663             :         /* We do the merge dance here because for some unit types, the unit might have aliases which are not
    4664             :          * declared in the file system. In particular, this is true (and frequent) for device and swap units.
    4665             :          */
    4666             :         Unit *merged;
    4667        2144 :         const char *id = u->id;
    4668        2144 :         _cleanup_free_ char *free_id = NULL;
    4669             : 
    4670        2144 :         if (fragment) {
    4671          88 :                 id = basename(fragment);
    4672          88 :                 if (unit_name_is_valid(id, UNIT_NAME_TEMPLATE)) {
    4673           0 :                         assert(u->instance); /* If we're not trying to use a template for non-instanced unit,
    4674             :                                               * this must be set. */
    4675             : 
    4676           0 :                         r = unit_name_replace_instance(id, u->instance, &free_id);
    4677           0 :                         if (r < 0)
    4678           0 :                                 return log_debug_errno(r, "Failed to build id (%s + %s): %m", id, u->instance);
    4679           0 :                         id = free_id;
    4680             :                 }
    4681             :         }
    4682             : 
    4683        2144 :         merged = u;
    4684        2144 :         r = merge_by_names(&merged, names, id);
    4685        2144 :         if (r < 0)
    4686           0 :                 return r;
    4687             : 
    4688        2144 :         if (merged != u)
    4689           0 :                 u->load_state = UNIT_MERGED;
    4690             : 
    4691        2144 :         return 0;
    4692             : }
    4693             : 
    4694           1 : void unit_dump_config_items(FILE *f) {
    4695             :         static const struct {
    4696             :                 const ConfigParserCallback callback;
    4697             :                 const char *rvalue;
    4698             :         } table[] = {
    4699             :                 { config_parse_warn_compat,           "NOTSUPPORTED" },
    4700             :                 { config_parse_int,                   "INTEGER" },
    4701             :                 { config_parse_unsigned,              "UNSIGNED" },
    4702             :                 { config_parse_iec_size,              "SIZE" },
    4703             :                 { config_parse_iec_uint64,            "SIZE" },
    4704             :                 { config_parse_si_size,               "SIZE" },
    4705             :                 { config_parse_bool,                  "BOOLEAN" },
    4706             :                 { config_parse_string,                "STRING" },
    4707             :                 { config_parse_path,                  "PATH" },
    4708             :                 { config_parse_unit_path_printf,      "PATH" },
    4709             :                 { config_parse_strv,                  "STRING [...]" },
    4710             :                 { config_parse_exec_nice,             "NICE" },
    4711             :                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
    4712             :                 { config_parse_exec_io_class,         "IOCLASS" },
    4713             :                 { config_parse_exec_io_priority,      "IOPRIORITY" },
    4714             :                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
    4715             :                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
    4716             :                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
    4717             :                 { config_parse_mode,                  "MODE" },
    4718             :                 { config_parse_unit_env_file,         "FILE" },
    4719             :                 { config_parse_exec_output,           "OUTPUT" },
    4720             :                 { config_parse_exec_input,            "INPUT" },
    4721             :                 { config_parse_log_facility,          "FACILITY" },
    4722             :                 { config_parse_log_level,             "LEVEL" },
    4723             :                 { config_parse_exec_secure_bits,      "SECUREBITS" },
    4724             :                 { config_parse_capability_set,        "BOUNDINGSET" },
    4725             :                 { config_parse_rlimit,                "LIMIT" },
    4726             :                 { config_parse_unit_deps,             "UNIT [...]" },
    4727             :                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
    4728             :                 { config_parse_service_type,          "SERVICETYPE" },
    4729             :                 { config_parse_service_restart,       "SERVICERESTART" },
    4730             :                 { config_parse_kill_mode,             "KILLMODE" },
    4731             :                 { config_parse_signal,                "SIGNAL" },
    4732             :                 { config_parse_socket_listen,         "SOCKET [...]" },
    4733             :                 { config_parse_socket_bind,           "SOCKETBIND" },
    4734             :                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
    4735             :                 { config_parse_sec,                   "SECONDS" },
    4736             :                 { config_parse_nsec,                  "NANOSECONDS" },
    4737             :                 { config_parse_namespace_path_strv,   "PATH [...]" },
    4738             :                 { config_parse_bind_paths,            "PATH[:PATH[:OPTIONS]] [...]" },
    4739             :                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
    4740             :                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
    4741             :                 { config_parse_unit_string_printf,    "STRING" },
    4742             :                 { config_parse_trigger_unit,          "UNIT" },
    4743             :                 { config_parse_timer,                 "TIMER" },
    4744             :                 { config_parse_path_spec,             "PATH" },
    4745             :                 { config_parse_notify_access,         "ACCESS" },
    4746             :                 { config_parse_ip_tos,                "TOS" },
    4747             :                 { config_parse_unit_condition_path,   "CONDITION" },
    4748             :                 { config_parse_unit_condition_string, "CONDITION" },
    4749             :                 { config_parse_unit_condition_null,   "CONDITION" },
    4750             :                 { config_parse_unit_slice,            "SLICE" },
    4751             :                 { config_parse_documentation,         "URL" },
    4752             :                 { config_parse_service_timeout,       "SECONDS" },
    4753             :                 { config_parse_emergency_action,      "ACTION" },
    4754             :                 { config_parse_set_status,            "STATUS" },
    4755             :                 { config_parse_service_sockets,       "SOCKETS" },
    4756             :                 { config_parse_environ,               "ENVIRON" },
    4757             : #if HAVE_SECCOMP
    4758             :                 { config_parse_syscall_filter,        "SYSCALLS" },
    4759             :                 { config_parse_syscall_archs,         "ARCHS" },
    4760             :                 { config_parse_syscall_errno,         "ERRNO" },
    4761             :                 { config_parse_address_families,      "FAMILIES" },
    4762             :                 { config_parse_restrict_namespaces,   "NAMESPACES"  },
    4763             : #endif
    4764             :                 { config_parse_cpu_shares,            "SHARES" },
    4765             :                 { config_parse_cg_weight,             "WEIGHT" },
    4766             :                 { config_parse_memory_limit,          "LIMIT" },
    4767             :                 { config_parse_device_allow,          "DEVICE" },
    4768             :                 { config_parse_device_policy,         "POLICY" },
    4769             :                 { config_parse_io_limit,              "LIMIT" },
    4770             :                 { config_parse_io_device_weight,      "DEVICEWEIGHT" },
    4771             :                 { config_parse_io_device_latency,     "DEVICELATENCY" },
    4772             :                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
    4773             :                 { config_parse_blockio_weight,        "WEIGHT" },
    4774             :                 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
    4775             :                 { config_parse_long,                  "LONG" },
    4776             :                 { config_parse_socket_service,        "SERVICE" },
    4777             : #if HAVE_SELINUX
    4778             :                 { config_parse_exec_selinux_context,  "LABEL" },
    4779             : #endif
    4780             :                 { config_parse_job_mode,              "MODE" },
    4781             :                 { config_parse_job_mode_isolate,      "BOOLEAN" },
    4782             :                 { config_parse_personality,           "PERSONALITY" },
    4783             :         };
    4784             : 
    4785           1 :         const char *prev = NULL;
    4786             :         const char *i;
    4787             : 
    4788           1 :         assert(f);
    4789             : 
    4790         982 :         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
    4791         981 :                 const char *rvalue = "OTHER", *lvalue;
    4792             :                 const ConfigPerfItem *p;
    4793             :                 size_t prefix_len;
    4794             :                 const char *dot;
    4795             :                 unsigned j;
    4796             : 
    4797         981 :                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
    4798             : 
    4799             :                 /* Hide legacy settings */
    4800         981 :                 if (p->parse == config_parse_warn_compat &&
    4801          17 :                     p->ltype == DISABLED_LEGACY)
    4802          13 :                         continue;
    4803             : 
    4804       41555 :                 for (j = 0; j < ELEMENTSOF(table); j++)
    4805       41383 :                         if (p->parse == table[j].callback) {
    4806         796 :                                 rvalue = table[j].rvalue;
    4807         796 :                                 break;
    4808             :                         }
    4809             : 
    4810         968 :                 dot = strchr(i, '.');
    4811         968 :                 lvalue = dot ? dot + 1 : i;
    4812         968 :                 prefix_len = dot-i;
    4813             : 
    4814         968 :                 if (dot)
    4815         968 :                         if (!prev || !strneq(prev, i, prefix_len+1)) {
    4816          11 :                                 if (prev)
    4817          10 :                                         fputc('\n', f);
    4818             : 
    4819          11 :                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
    4820             :                         }
    4821             : 
    4822         968 :                 fprintf(f, "%s=%s\n", lvalue, rvalue);
    4823         968 :                 prev = i;
    4824             :         }
    4825           1 : }
    4826             : 
    4827           0 : int config_parse_cpu_affinity2(
    4828             :                 const char *unit,
    4829             :                 const char *filename,
    4830             :                 unsigned line,
    4831             :                 const char *section,
    4832             :                 unsigned section_line,
    4833             :                 const char *lvalue,
    4834             :                 int ltype,
    4835             :                 const char *rvalue,
    4836             :                 void *data,
    4837             :                 void *userdata) {
    4838             : 
    4839           0 :         CPUSet *affinity = data;
    4840             : 
    4841           0 :         assert(affinity);
    4842             : 
    4843           0 :         (void) parse_cpu_set_extend(rvalue, affinity, true, unit, filename, line, lvalue);
    4844             : 
    4845           0 :         return 0;
    4846             : }
    4847             : 
    4848           0 : int config_parse_show_status(
    4849             :                 const char* unit,
    4850             :                 const char *filename,
    4851             :                 unsigned line,
    4852             :                 const char *section,
    4853             :                 unsigned section_line,
    4854             :                 const char *lvalue,
    4855             :                 int ltype,
    4856             :                 const char *rvalue,
    4857             :                 void *data,
    4858             :                 void *userdata) {
    4859             : 
    4860             :         int k;
    4861           0 :         ShowStatus *b = data;
    4862             : 
    4863           0 :         assert(filename);
    4864           0 :         assert(lvalue);
    4865           0 :         assert(rvalue);
    4866           0 :         assert(data);
    4867             : 
    4868           0 :         k = parse_show_status(rvalue, b);
    4869           0 :         if (k < 0) {
    4870           0 :                 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue);
    4871           0 :                 return 0;
    4872             :         }
    4873             : 
    4874           0 :         return 0;
    4875             : }
    4876             : 
    4877           0 : int config_parse_output_restricted(
    4878             :                 const char* unit,
    4879             :                 const char *filename,
    4880             :                 unsigned line,
    4881             :                 const char *section,
    4882             :                 unsigned section_line,
    4883             :                 const char *lvalue,
    4884             :                 int ltype,
    4885             :                 const char *rvalue,
    4886             :                 void *data,
    4887             :                 void *userdata) {
    4888             : 
    4889           0 :         ExecOutput t, *eo = data;
    4890             : 
    4891           0 :         assert(filename);
    4892           0 :         assert(lvalue);
    4893           0 :         assert(rvalue);
    4894           0 :         assert(data);
    4895             : 
    4896           0 :         t = exec_output_from_string(rvalue);
    4897           0 :         if (t < 0) {
    4898           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output type, ignoring: %s", rvalue);
    4899           0 :                 return 0;
    4900             :         }
    4901             : 
    4902           0 :         if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
    4903           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
    4904           0 :                 return 0;
    4905             :         }
    4906             : 
    4907           0 :         *eo = t;
    4908           0 :         return 0;
    4909             : }
    4910             : 
    4911           0 : int config_parse_crash_chvt(
    4912             :                 const char* unit,
    4913             :                 const char *filename,
    4914             :                 unsigned line,
    4915             :                 const char *section,
    4916             :                 unsigned section_line,
    4917             :                 const char *lvalue,
    4918             :                 int ltype,
    4919             :                 const char *rvalue,
    4920             :                 void *data,
    4921             :                 void *userdata) {
    4922             : 
    4923             :         int r;
    4924             : 
    4925           0 :         assert(filename);
    4926           0 :         assert(lvalue);
    4927           0 :         assert(rvalue);
    4928           0 :         assert(data);
    4929             : 
    4930           0 :         r = parse_crash_chvt(rvalue, data);
    4931           0 :         if (r < 0) {
    4932           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue);
    4933           0 :                 return 0;
    4934             :         }
    4935             : 
    4936           0 :         return 0;
    4937             : }
    4938             : 
    4939           0 : int config_parse_timeout_abort(
    4940             :                 const char* unit,
    4941             :                 const char *filename,
    4942             :                 unsigned line,
    4943             :                 const char *section,
    4944             :                 unsigned section_line,
    4945             :                 const char *lvalue,
    4946             :                 int ltype,
    4947             :                 const char *rvalue,
    4948             :                 void *data,
    4949             :                 void *userdata) {
    4950             : 
    4951           0 :         usec_t *timeout_usec = data;
    4952             :         int r;
    4953             : 
    4954           0 :         assert(filename);
    4955           0 :         assert(lvalue);
    4956           0 :         assert(rvalue);
    4957           0 :         assert(timeout_usec);
    4958             : 
    4959           0 :         rvalue += strspn(rvalue, WHITESPACE);
    4960           0 :         if (isempty(rvalue)) {
    4961           0 :                 *timeout_usec = false;
    4962           0 :                 return 0;
    4963             :         }
    4964             : 
    4965           0 :         r = parse_sec(rvalue, timeout_usec);
    4966           0 :         if (r < 0) {
    4967           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DefaultTimeoutAbortSec= setting, ignoring: %s", rvalue);
    4968           0 :                 return 0;
    4969             :         }
    4970             : 
    4971           0 :         *timeout_usec = true;
    4972           0 :         return 0;
    4973             : }

Generated by: LCOV version 1.14