LCOV - code coverage report
Current view: top level - core - load-fragment.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 365 1722 21.2 %
Date: 2015-07-29 18:47:03 Functions: 19 80 23.8 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             :   Copyright 2012 Holger Hans Peter Freyther
       8             : 
       9             :   systemd is free software; you can redistribute it and/or modify it
      10             :   under the terms of the GNU Lesser General Public License as published by
      11             :   the Free Software Foundation; either version 2.1 of the License, or
      12             :   (at your option) any later version.
      13             : 
      14             :   systemd is distributed in the hope that it will be useful, but
      15             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      17             :   Lesser General Public License for more details.
      18             : 
      19             :   You should have received a copy of the GNU Lesser General Public License
      20             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      21             : ***/
      22             : 
      23             : #include <linux/oom.h>
      24             : #include <errno.h>
      25             : #include <string.h>
      26             : #include <fcntl.h>
      27             : #include <sched.h>
      28             : #include <linux/fs.h>
      29             : #include <sys/stat.h>
      30             : #include <sys/resource.h>
      31             : 
      32             : #ifdef HAVE_SECCOMP
      33             : #include <seccomp.h>
      34             : #endif
      35             : 
      36             : #include "unit.h"
      37             : #include "strv.h"
      38             : #include "conf-parser.h"
      39             : #include "load-fragment.h"
      40             : #include "log.h"
      41             : #include "ioprio.h"
      42             : #include "securebits.h"
      43             : #include "missing.h"
      44             : #include "unit-name.h"
      45             : #include "unit-printf.h"
      46             : #include "utf8.h"
      47             : #include "path-util.h"
      48             : #include "env-util.h"
      49             : #include "cgroup.h"
      50             : #include "bus-util.h"
      51             : #include "bus-error.h"
      52             : #include "errno-list.h"
      53             : #include "af-list.h"
      54             : #include "cap-list.h"
      55             : #include "signal-util.h"
      56             : #include "bus-internal.h"
      57             : 
      58             : #ifdef HAVE_SECCOMP
      59             : #include "seccomp-util.h"
      60             : #endif
      61             : 
      62           0 : int config_parse_warn_compat(
      63             :                 const char *unit,
      64             :                 const char *filename,
      65             :                 unsigned line,
      66             :                 const char *section,
      67             :                 unsigned section_line,
      68             :                 const char *lvalue,
      69             :                 int ltype,
      70             :                 const char *rvalue,
      71             :                 void *data,
      72             :                 void *userdata) {
      73           0 :         Disabled reason = ltype;
      74             : 
      75           0 :         switch(reason) {
      76             :         case DISABLED_CONFIGURATION:
      77           0 :                 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
      78             :                            "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
      79           0 :                 break;
      80             :         case DISABLED_LEGACY:
      81           0 :                 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
      82             :                            "Support for option %s= has been removed and it is ignored", lvalue);
      83           0 :                 break;
      84             :         case DISABLED_EXPERIMENTAL:
      85           0 :                 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
      86             :                            "Support for option %s= has not yet been enabled and it is ignored", lvalue);
      87           0 :                 break;
      88             :         };
      89             : 
      90           0 :         return 0;
      91             : }
      92             : 
      93          82 : int config_parse_unit_deps(const char *unit,
      94             :                            const char *filename,
      95             :                            unsigned line,
      96             :                            const char *section,
      97             :                            unsigned section_line,
      98             :                            const char *lvalue,
      99             :                            int ltype,
     100             :                            const char *rvalue,
     101             :                            void *data,
     102             :                            void *userdata) {
     103             : 
     104          82 :         UnitDependency d = ltype;
     105          82 :         Unit *u = userdata;
     106             :         const char *word, *state;
     107             :         size_t l;
     108             : 
     109          82 :         assert(filename);
     110          82 :         assert(lvalue);
     111          82 :         assert(rvalue);
     112             : 
     113         274 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
     114         384 :                 _cleanup_free_ char *t = NULL, *k = NULL;
     115             :                 int r;
     116             : 
     117         192 :                 t = strndup(word, l);
     118         192 :                 if (!t)
     119           0 :                         return log_oom();
     120             : 
     121         192 :                 r = unit_name_printf(u, t, &k);
     122         192 :                 if (r < 0) {
     123           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
     124             :                                    "Failed to resolve specifiers, ignoring: %s", strerror(-r));
     125           0 :                         continue;
     126             :                 }
     127             : 
     128         192 :                 r = unit_add_dependency_by_name(u, d, k, NULL, true);
     129         192 :                 if (r < 0)
     130           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
     131             :                                    "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
     132             :         }
     133          82 :         if (!isempty(state))
     134           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
     135             : 
     136          82 :         return 0;
     137             : }
     138             : 
     139          92 : int config_parse_unit_string_printf(
     140             :                 const char *unit,
     141             :                 const char *filename,
     142             :                 unsigned line,
     143             :                 const char *section,
     144             :                 unsigned section_line,
     145             :                 const char *lvalue,
     146             :                 int ltype,
     147             :                 const char *rvalue,
     148             :                 void *data,
     149             :                 void *userdata) {
     150             : 
     151         184 :         _cleanup_free_ char *k = NULL;
     152          92 :         Unit *u = userdata;
     153             :         int r;
     154             : 
     155          92 :         assert(filename);
     156          92 :         assert(lvalue);
     157          92 :         assert(rvalue);
     158          92 :         assert(u);
     159             : 
     160          92 :         r = unit_full_printf(u, rvalue, &k);
     161          92 :         if (r < 0) {
     162           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
     163           0 :                 return 0;
     164             :         }
     165             : 
     166          92 :         return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
     167             : }
     168             : 
     169          60 : int config_parse_unit_strv_printf(const char *unit,
     170             :                                   const char *filename,
     171             :                                   unsigned line,
     172             :                                   const char *section,
     173             :                                   unsigned section_line,
     174             :                                   const char *lvalue,
     175             :                                   int ltype,
     176             :                                   const char *rvalue,
     177             :                                   void *data,
     178             :                                   void *userdata) {
     179             : 
     180          60 :         Unit *u = userdata;
     181         120 :         _cleanup_free_ char *k = NULL;
     182             :         int r;
     183             : 
     184          60 :         assert(filename);
     185          60 :         assert(lvalue);
     186          60 :         assert(rvalue);
     187          60 :         assert(u);
     188             : 
     189          60 :         r = unit_full_printf(u, rvalue, &k);
     190          60 :         if (r < 0)
     191           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
     192             :                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
     193             : 
     194         120 :         return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
     195          60 :                                  k ? k : rvalue, data, userdata);
     196             : }
     197             : 
     198           0 : int config_parse_unit_path_printf(const char *unit,
     199             :                                   const char *filename,
     200             :                                   unsigned line,
     201             :                                   const char *section,
     202             :                                   unsigned section_line,
     203             :                                   const char *lvalue,
     204             :                                   int ltype,
     205             :                                   const char *rvalue,
     206             :                                   void *data,
     207             :                                   void *userdata) {
     208             : 
     209           0 :         _cleanup_free_ char *k = NULL;
     210           0 :         Unit *u = userdata;
     211             :         int r;
     212             : 
     213           0 :         assert(filename);
     214           0 :         assert(lvalue);
     215           0 :         assert(rvalue);
     216           0 :         assert(u);
     217             : 
     218           0 :         r = unit_full_printf(u, rvalue, &k);
     219           0 :         if (r < 0) {
     220           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
     221           0 :                 return 0;
     222             :         }
     223             : 
     224           0 :         return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
     225             : }
     226             : 
     227           0 : int config_parse_unit_path_strv_printf(
     228             :                 const char *unit,
     229             :                 const char *filename,
     230             :                 unsigned line,
     231             :                 const char *section,
     232             :                 unsigned section_line,
     233             :                 const char *lvalue,
     234             :                 int ltype,
     235             :                 const char *rvalue,
     236             :                 void *data,
     237             :                 void *userdata) {
     238             : 
     239           0 :         char ***x = data;
     240             :         const char *word, *state;
     241           0 :         Unit *u = userdata;
     242             :         size_t l;
     243             :         int r;
     244             : 
     245           0 :         assert(filename);
     246           0 :         assert(lvalue);
     247           0 :         assert(rvalue);
     248           0 :         assert(u);
     249             : 
     250           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
     251           0 :                 _cleanup_free_ char *k = NULL;
     252           0 :                 char t[l+1];
     253             : 
     254           0 :                 memcpy(t, word, l);
     255           0 :                 t[l] = 0;
     256             : 
     257           0 :                 r = unit_full_printf(u, t, &k);
     258           0 :                 if (r < 0) {
     259           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
     260           0 :                         return 0;
     261             :                 }
     262             : 
     263           0 :                 if (!utf8_is_valid(k)) {
     264           0 :                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
     265           0 :                         return 0;
     266             :                 }
     267             : 
     268           0 :                 if (!path_is_absolute(k)) {
     269           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
     270           0 :                         return 0;
     271             :                 }
     272             : 
     273           0 :                 path_kill_slashes(k);
     274             : 
     275           0 :                 r = strv_push(x, k);
     276           0 :                 if (r < 0)
     277           0 :                         return log_oom();
     278             : 
     279           0 :                 k = NULL;
     280             :         }
     281           0 :         if (!isempty(state))
     282           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
     283             : 
     284           0 :         return 0;
     285             : }
     286             : 
     287           0 : int config_parse_socket_listen(const char *unit,
     288             :                                const char *filename,
     289             :                                unsigned line,
     290             :                                const char *section,
     291             :                                unsigned section_line,
     292             :                                const char *lvalue,
     293             :                                int ltype,
     294             :                                const char *rvalue,
     295             :                                void *data,
     296             :                                void *userdata) {
     297             : 
     298           0 :         _cleanup_free_ SocketPort *p = NULL;
     299             :         SocketPort *tail;
     300             :         Socket *s;
     301             :         int r;
     302             : 
     303           0 :         assert(filename);
     304           0 :         assert(lvalue);
     305           0 :         assert(rvalue);
     306           0 :         assert(data);
     307             : 
     308           0 :         s = SOCKET(data);
     309             : 
     310           0 :         if (isempty(rvalue)) {
     311             :                 /* An empty assignment removes all ports */
     312           0 :                 socket_free_ports(s);
     313           0 :                 return 0;
     314             :         }
     315             : 
     316           0 :         p = new0(SocketPort, 1);
     317           0 :         if (!p)
     318           0 :                 return log_oom();
     319             : 
     320           0 :         if (ltype != SOCKET_SOCKET) {
     321             : 
     322           0 :                 p->type = ltype;
     323           0 :                 r = unit_full_printf(UNIT(s), rvalue, &p->path);
     324           0 :                 if (r < 0) {
     325           0 :                         p->path = strdup(rvalue);
     326           0 :                         if (!p->path)
     327           0 :                                 return log_oom();
     328             :                         else
     329           0 :                                 log_syntax(unit, LOG_ERR, filename, line, -r,
     330             :                                            "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
     331             :                 }
     332             : 
     333           0 :                 path_kill_slashes(p->path);
     334             : 
     335           0 :         } else if (streq(lvalue, "ListenNetlink")) {
     336           0 :                 _cleanup_free_ char  *k = NULL;
     337             : 
     338           0 :                 p->type = SOCKET_SOCKET;
     339           0 :                 r = unit_full_printf(UNIT(s), rvalue, &k);
     340           0 :                 if (r < 0)
     341           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
     342             :                                    "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
     343             : 
     344           0 :                 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
     345           0 :                 if (r < 0) {
     346           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
     347             :                                    "Failed to parse address value, ignoring: %s", rvalue);
     348           0 :                         return 0;
     349             :                 }
     350             : 
     351             :         } else {
     352           0 :                 _cleanup_free_ char *k = NULL;
     353             : 
     354           0 :                 p->type = SOCKET_SOCKET;
     355           0 :                 r = unit_full_printf(UNIT(s), rvalue, &k);
     356           0 :                 if (r < 0)
     357           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
     358             :                                    "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
     359             : 
     360           0 :                 r = socket_address_parse_and_warn(&p->address, k ? k : rvalue);
     361           0 :                 if (r < 0) {
     362           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
     363             :                                    "Failed to parse address value, ignoring: %s", rvalue);
     364           0 :                         return 0;
     365             :                 }
     366             : 
     367           0 :                 if (streq(lvalue, "ListenStream"))
     368           0 :                         p->address.type = SOCK_STREAM;
     369           0 :                 else if (streq(lvalue, "ListenDatagram"))
     370           0 :                         p->address.type = SOCK_DGRAM;
     371             :                 else {
     372           0 :                         assert(streq(lvalue, "ListenSequentialPacket"));
     373           0 :                         p->address.type = SOCK_SEQPACKET;
     374             :                 }
     375             : 
     376           0 :                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
     377           0 :                         log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
     378             :                                    "Address family not supported, ignoring: %s", rvalue);
     379           0 :                         return 0;
     380             :                 }
     381             :         }
     382             : 
     383           0 :         p->fd = -1;
     384           0 :         p->socket = s;
     385             : 
     386           0 :         if (s->ports) {
     387           0 :                 LIST_FIND_TAIL(port, s->ports, tail);
     388           0 :                 LIST_INSERT_AFTER(port, s->ports, tail, p);
     389             :         } else
     390           0 :                 LIST_PREPEND(port, s->ports, p);
     391           0 :         p = NULL;
     392             : 
     393           0 :         return 0;
     394             : }
     395             : 
     396           0 : int config_parse_socket_bind(const char *unit,
     397             :                              const char *filename,
     398             :                              unsigned line,
     399             :                              const char *section,
     400             :                              unsigned section_line,
     401             :                              const char *lvalue,
     402             :                              int ltype,
     403             :                              const char *rvalue,
     404             :                              void *data,
     405             :                              void *userdata) {
     406             : 
     407             :         Socket *s;
     408             :         SocketAddressBindIPv6Only b;
     409             : 
     410           0 :         assert(filename);
     411           0 :         assert(lvalue);
     412           0 :         assert(rvalue);
     413           0 :         assert(data);
     414             : 
     415           0 :         s = SOCKET(data);
     416             : 
     417           0 :         b = socket_address_bind_ipv6_only_from_string(rvalue);
     418           0 :         if (b < 0) {
     419             :                 int r;
     420             : 
     421           0 :                 r = parse_boolean(rvalue);
     422           0 :                 if (r < 0) {
     423           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     424             :                                    "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
     425           0 :                         return 0;
     426             :                 }
     427             : 
     428           0 :                 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
     429             :         } else
     430           0 :                 s->bind_ipv6_only = b;
     431             : 
     432           0 :         return 0;
     433             : }
     434             : 
     435           0 : int config_parse_exec_nice(const char *unit,
     436             :                            const char *filename,
     437             :                            unsigned line,
     438             :                            const char *section,
     439             :                            unsigned section_line,
     440             :                            const char *lvalue,
     441             :                            int ltype,
     442             :                            const char *rvalue,
     443             :                            void *data,
     444             :                            void *userdata) {
     445             : 
     446           0 :         ExecContext *c = data;
     447             :         int priority, r;
     448             : 
     449           0 :         assert(filename);
     450           0 :         assert(lvalue);
     451           0 :         assert(rvalue);
     452           0 :         assert(data);
     453             : 
     454           0 :         r = safe_atoi(rvalue, &priority);
     455           0 :         if (r < 0) {
     456           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
     457             :                            "Failed to parse nice priority, ignoring: %s. ", rvalue);
     458           0 :                 return 0;
     459             :         }
     460             : 
     461           0 :         if (priority < PRIO_MIN || priority >= PRIO_MAX) {
     462           0 :                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
     463             :                            "Nice priority out of range, ignoring: %s", rvalue);
     464           0 :                 return 0;
     465             :         }
     466             : 
     467           0 :         c->nice = priority;
     468           0 :         c->nice_set = true;
     469             : 
     470           0 :         return 0;
     471             : }
     472             : 
     473           0 : int config_parse_exec_oom_score_adjust(const char* unit,
     474             :                                        const char *filename,
     475             :                                        unsigned line,
     476             :                                        const char *section,
     477             :                                        unsigned section_line,
     478             :                                        const char *lvalue,
     479             :                                        int ltype,
     480             :                                        const char *rvalue,
     481             :                                        void *data,
     482             :                                        void *userdata) {
     483             : 
     484           0 :         ExecContext *c = data;
     485             :         int oa, r;
     486             : 
     487           0 :         assert(filename);
     488           0 :         assert(lvalue);
     489           0 :         assert(rvalue);
     490           0 :         assert(data);
     491             : 
     492           0 :         r = safe_atoi(rvalue, &oa);
     493           0 :         if (r < 0) {
     494           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
     495             :                            "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
     496           0 :                 return 0;
     497             :         }
     498             : 
     499           0 :         if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
     500           0 :                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
     501             :                            "OOM score adjust value out of range, ignoring: %s", rvalue);
     502           0 :                 return 0;
     503             :         }
     504             : 
     505           0 :         c->oom_score_adjust = oa;
     506           0 :         c->oom_score_adjust_set = true;
     507             : 
     508           0 :         return 0;
     509             : }
     510             : 
     511          68 : int config_parse_exec(
     512             :                 const char *unit,
     513             :                 const char *filename,
     514             :                 unsigned line,
     515             :                 const char *section,
     516             :                 unsigned section_line,
     517             :                 const char *lvalue,
     518             :                 int ltype,
     519             :                 const char *rvalue,
     520             :                 void *data,
     521             :                 void *userdata) {
     522             : 
     523          68 :         ExecCommand **e = data;
     524             :         const char *p;
     525             :         bool semicolon;
     526             :         int r;
     527             : 
     528          68 :         assert(filename);
     529          68 :         assert(lvalue);
     530          68 :         assert(rvalue);
     531          68 :         assert(e);
     532             : 
     533          68 :         e += ltype;
     534             : 
     535          68 :         rvalue += strspn(rvalue, WHITESPACE);
     536          68 :         p = rvalue;
     537             : 
     538          68 :         if (isempty(rvalue)) {
     539             :                 /* An empty assignment resets the list */
     540           2 :                 *e = exec_command_free_list(*e);
     541           2 :                 return 0;
     542             :         }
     543             : 
     544             :         do {
     545             :                 int i;
     546         140 :                 _cleanup_strv_free_ char **n = NULL;
     547          70 :                 size_t nlen = 0, nbufsize = 0;
     548         140 :                 _cleanup_free_ ExecCommand *nce = NULL;
     549         140 :                 _cleanup_free_ char *path = NULL, *firstword = NULL;
     550             :                 char *f;
     551          70 :                 bool separate_argv0 = false, ignore = false;
     552             : 
     553          70 :                 semicolon = false;
     554             : 
     555          70 :                 r = unquote_first_word_and_warn(&p, &firstword, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
     556          70 :                 if (r <= 0)
     557           2 :                         return 0;
     558             : 
     559          68 :                 f = firstword;
     560          89 :                 for (i = 0; i < 2; i++) {
     561             :                         /* We accept an absolute path as first argument, or
     562             :                          * alternatively an absolute prefixed with @ to allow
     563             :                          * overriding of argv[0]. */
     564          81 :                         if (*f == '-' && !ignore)
     565          11 :                                 ignore = true;
     566          70 :                         else if (*f == '@' && !separate_argv0)
     567          10 :                                 separate_argv0 = true;
     568             :                         else
     569             :                                 break;
     570          21 :                         f ++;
     571             :                 }
     572             : 
     573          68 :                 if (isempty(f)) {
     574             :                         /* First word is either "-" or "@" with no command. */
     575           2 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     576             :                                    "Empty path in command line, ignoring: \"%s\"", rvalue);
     577           2 :                         return 0;
     578             :                 }
     579             : 
     580          66 :                 if (!string_is_safe(f)) {
     581          12 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     582             :                                         "Executable path contains special characters, ignoring: %s", rvalue);
     583          12 :                         return 0;
     584             :                 }
     585          54 :                 if (!path_is_absolute(f)) {
     586           3 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     587             :                                         "Executable path is not absolute, ignoring: %s", rvalue);
     588           3 :                         return 0;
     589             :                 }
     590          51 :                 if (endswith(f, "/")) {
     591           1 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     592             :                                         "Executable path specifies a directory, ignoring: %s", rvalue);
     593           1 :                         return 0;
     594             :                 }
     595             : 
     596          50 :                 if (f == firstword) {
     597          41 :                         path = firstword;
     598          41 :                         firstword = NULL;
     599             :                 } else {
     600           9 :                         path = strdup(f);
     601           9 :                         if (!path)
     602           0 :                                 return log_oom();
     603             :                 }
     604             : 
     605          50 :                 if (!separate_argv0) {
     606          41 :                         if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
     607           0 :                                 return log_oom();
     608          41 :                         f = strdup(path);
     609          41 :                         if (!f)
     610           0 :                                 return log_oom();
     611          41 :                         n[nlen++] = f;
     612          41 :                         n[nlen] = NULL;
     613             :                 }
     614             : 
     615          50 :                 path_kill_slashes(path);
     616             : 
     617             :                 for (;;) {
     618         170 :                         _cleanup_free_ char *word = NULL;
     619             : 
     620             :                         /* Check explicitly for an unquoted semicolon as
     621             :                          * command separator token.  */
     622          85 :                         if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
     623           4 :                                 p ++;
     624           4 :                                 p += strspn(p, WHITESPACE);
     625           4 :                                 semicolon = true;
     626           4 :                                 break;
     627             :                         }
     628             : 
     629             :                         /* Check for \; explicitly, to not confuse it with \\;
     630             :                          * or "\;" or "\\;" etc.  unquote_first_word would
     631             :                          * return the same for all of those.  */
     632          81 :                         if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
     633           2 :                                 p += 2;
     634           2 :                                 p += strspn(p, WHITESPACE);
     635           2 :                                 if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
     636           0 :                                         return log_oom();
     637           2 :                                 f = strdup(";");
     638           2 :                                 if (!f)
     639           0 :                                         return log_oom();
     640           2 :                                 n[nlen++] = f;
     641           2 :                                 n[nlen] = NULL;
     642           2 :                                 continue;
     643             :                         }
     644             : 
     645          79 :                         r = unquote_first_word_and_warn(&p, &word, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
     646          79 :                         if (r == 0)
     647          44 :                                 break;
     648          35 :                         else if (r < 0)
     649           2 :                                 return 0;
     650             : 
     651          33 :                         if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
     652           0 :                                 return log_oom();
     653          33 :                         n[nlen++] = word;
     654          33 :                         n[nlen] = NULL;
     655          33 :                         word = NULL;
     656          35 :                 }
     657             : 
     658          95 :                 if (!n || !n[0]) {
     659           1 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     660             :                                         "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
     661           1 :                         return 0;
     662             :                 }
     663             : 
     664          47 :                 nce = new0(ExecCommand, 1);
     665          47 :                 if (!nce)
     666           0 :                         return log_oom();
     667             : 
     668          47 :                 nce->argv = n;
     669          47 :                 nce->path = path;
     670          47 :                 nce->ignore = ignore;
     671             : 
     672          47 :                 exec_command_append_list(e, nce);
     673             : 
     674             :                 /* Do not _cleanup_free_ these. */
     675          47 :                 n = NULL;
     676          47 :                 path = NULL;
     677          47 :                 nce = NULL;
     678             : 
     679          47 :                 rvalue = p;
     680          47 :         } while (semicolon);
     681             : 
     682          43 :         return 0;
     683             : }
     684             : 
     685          10 : DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
     686           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
     687             : 
     688           0 : int config_parse_socket_bindtodevice(const char* unit,
     689             :                                      const char *filename,
     690             :                                      unsigned line,
     691             :                                      const char *section,
     692             :                                      unsigned section_line,
     693             :                                      const char *lvalue,
     694             :                                      int ltype,
     695             :                                      const char *rvalue,
     696             :                                      void *data,
     697             :                                      void *userdata) {
     698             : 
     699           0 :         Socket *s = data;
     700             :         char *n;
     701             : 
     702           0 :         assert(filename);
     703           0 :         assert(lvalue);
     704           0 :         assert(rvalue);
     705           0 :         assert(data);
     706             : 
     707           0 :         if (rvalue[0] && !streq(rvalue, "*")) {
     708           0 :                 n = strdup(rvalue);
     709           0 :                 if (!n)
     710           0 :                         return log_oom();
     711             :         } else
     712           0 :                 n = NULL;
     713             : 
     714           0 :         free(s->bind_to_device);
     715           0 :         s->bind_to_device = n;
     716             : 
     717           0 :         return 0;
     718             : }
     719             : 
     720           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
     721           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
     722             : 
     723           0 : int config_parse_exec_io_class(const char *unit,
     724             :                                const char *filename,
     725             :                                unsigned line,
     726             :                                const char *section,
     727             :                                unsigned section_line,
     728             :                                const char *lvalue,
     729             :                                int ltype,
     730             :                                const char *rvalue,
     731             :                                void *data,
     732             :                                void *userdata) {
     733             : 
     734           0 :         ExecContext *c = data;
     735             :         int x;
     736             : 
     737           0 :         assert(filename);
     738           0 :         assert(lvalue);
     739           0 :         assert(rvalue);
     740           0 :         assert(data);
     741             : 
     742           0 :         x = ioprio_class_from_string(rvalue);
     743           0 :         if (x < 0) {
     744           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     745             :                            "Failed to parse IO scheduling class, ignoring: %s", rvalue);
     746           0 :                 return 0;
     747             :         }
     748             : 
     749           0 :         c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
     750           0 :         c->ioprio_set = true;
     751             : 
     752           0 :         return 0;
     753             : }
     754             : 
     755           0 : int config_parse_exec_io_priority(const char *unit,
     756             :                                   const char *filename,
     757             :                                   unsigned line,
     758             :                                   const char *section,
     759             :                                   unsigned section_line,
     760             :                                   const char *lvalue,
     761             :                                   int ltype,
     762             :                                   const char *rvalue,
     763             :                                   void *data,
     764             :                                   void *userdata) {
     765             : 
     766           0 :         ExecContext *c = data;
     767             :         int i, r;
     768             : 
     769           0 :         assert(filename);
     770           0 :         assert(lvalue);
     771           0 :         assert(rvalue);
     772           0 :         assert(data);
     773             : 
     774           0 :         r = safe_atoi(rvalue, &i);
     775           0 :         if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
     776           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
     777             :                            "Failed to parse IO priority, ignoring: %s", rvalue);
     778           0 :                 return 0;
     779             :         }
     780             : 
     781           0 :         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
     782           0 :         c->ioprio_set = true;
     783             : 
     784           0 :         return 0;
     785             : }
     786             : 
     787           3 : int config_parse_exec_cpu_sched_policy(const char *unit,
     788             :                                        const char *filename,
     789             :                                        unsigned line,
     790             :                                        const char *section,
     791             :                                        unsigned section_line,
     792             :                                        const char *lvalue,
     793             :                                        int ltype,
     794             :                                        const char *rvalue,
     795             :                                        void *data,
     796             :                                        void *userdata) {
     797             : 
     798             : 
     799           3 :         ExecContext *c = data;
     800             :         int x;
     801             : 
     802           3 :         assert(filename);
     803           3 :         assert(lvalue);
     804           3 :         assert(rvalue);
     805           3 :         assert(data);
     806             : 
     807           3 :         x = sched_policy_from_string(rvalue);
     808           3 :         if (x < 0) {
     809           0 :                 log_syntax(unit, LOG_ERR, filename, line, -x,
     810             :                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
     811           0 :                 return 0;
     812             :         }
     813             : 
     814           3 :         c->cpu_sched_policy = x;
     815             :         /* Moving to or from real-time policy? We need to adjust the priority */
     816           3 :         c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
     817           3 :         c->cpu_sched_set = true;
     818             : 
     819           3 :         return 0;
     820             : }
     821             : 
     822           7 : int config_parse_exec_cpu_sched_prio(const char *unit,
     823             :                                      const char *filename,
     824             :                                      unsigned line,
     825             :                                      const char *section,
     826             :                                      unsigned section_line,
     827             :                                      const char *lvalue,
     828             :                                      int ltype,
     829             :                                      const char *rvalue,
     830             :                                      void *data,
     831             :                                      void *userdata) {
     832             : 
     833           7 :         ExecContext *c = data;
     834             :         int i, min, max, r;
     835             : 
     836           7 :         assert(filename);
     837           7 :         assert(lvalue);
     838           7 :         assert(rvalue);
     839           7 :         assert(data);
     840             : 
     841           7 :         r = safe_atoi(rvalue, &i);
     842           7 :         if (r < 0) {
     843           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
     844             :                            "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
     845           0 :                 return 0;
     846             :         }
     847             : 
     848             :         /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
     849           7 :         min = sched_get_priority_min(c->cpu_sched_policy);
     850           7 :         max = sched_get_priority_max(c->cpu_sched_policy);
     851             : 
     852           7 :         if (i < min || i > max) {
     853           3 :                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
     854             :                            "CPU scheduling priority is out of range, ignoring: %s", rvalue);
     855           3 :                 return 0;
     856             :         }
     857             : 
     858           4 :         c->cpu_sched_priority = i;
     859           4 :         c->cpu_sched_set = true;
     860             : 
     861           4 :         return 0;
     862             : }
     863             : 
     864           0 : int config_parse_exec_cpu_affinity(const char *unit,
     865             :                                    const char *filename,
     866             :                                    unsigned line,
     867             :                                    const char *section,
     868             :                                    unsigned section_line,
     869             :                                    const char *lvalue,
     870             :                                    int ltype,
     871             :                                    const char *rvalue,
     872             :                                    void *data,
     873             :                                    void *userdata) {
     874             : 
     875           0 :         ExecContext *c = data;
     876             :         const char *word, *state;
     877             :         size_t l;
     878             : 
     879           0 :         assert(filename);
     880           0 :         assert(lvalue);
     881           0 :         assert(rvalue);
     882           0 :         assert(data);
     883             : 
     884           0 :         if (isempty(rvalue)) {
     885             :                 /* An empty assignment resets the CPU list */
     886           0 :                 if (c->cpuset)
     887           0 :                         CPU_FREE(c->cpuset);
     888           0 :                 c->cpuset = NULL;
     889           0 :                 return 0;
     890             :         }
     891             : 
     892           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
     893           0 :                 _cleanup_free_ char *t = NULL;
     894             :                 int r;
     895             :                 unsigned cpu;
     896             : 
     897           0 :                 t = strndup(word, l);
     898           0 :                 if (!t)
     899           0 :                         return log_oom();
     900             : 
     901           0 :                 r = safe_atou(t, &cpu);
     902             : 
     903           0 :                 if (!c->cpuset) {
     904           0 :                         c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
     905           0 :                         if (!c->cpuset)
     906           0 :                                 return log_oom();
     907             :                 }
     908             : 
     909           0 :                 if (r < 0 || cpu >= c->cpuset_ncpus) {
     910           0 :                         log_syntax(unit, LOG_ERR, filename, line, ERANGE,
     911             :                                    "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
     912           0 :                         return 0;
     913             :                 }
     914             : 
     915           0 :                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
     916             :         }
     917           0 :         if (!isempty(state))
     918           0 :                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
     919             :                            "Trailing garbage, ignoring.");
     920             : 
     921           0 :         return 0;
     922             : }
     923             : 
     924           0 : int config_parse_exec_capabilities(const char *unit,
     925             :                                    const char *filename,
     926             :                                    unsigned line,
     927             :                                    const char *section,
     928             :                                    unsigned section_line,
     929             :                                    const char *lvalue,
     930             :                                    int ltype,
     931             :                                    const char *rvalue,
     932             :                                    void *data,
     933             :                                    void *userdata) {
     934             : 
     935           0 :         ExecContext *c = data;
     936             :         cap_t cap;
     937             : 
     938           0 :         assert(filename);
     939           0 :         assert(lvalue);
     940           0 :         assert(rvalue);
     941           0 :         assert(data);
     942             : 
     943           0 :         cap = cap_from_text(rvalue);
     944           0 :         if (!cap) {
     945           0 :                 log_syntax(unit, LOG_ERR, filename, line, errno,
     946             :                            "Failed to parse capabilities, ignoring: %s", rvalue);
     947           0 :                 return 0;
     948             :         }
     949             : 
     950           0 :         if (c->capabilities)
     951           0 :                 cap_free(c->capabilities);
     952           0 :         c->capabilities = cap;
     953             : 
     954           0 :         return 0;
     955             : }
     956             : 
     957           0 : int config_parse_exec_secure_bits(const char *unit,
     958             :                                   const char *filename,
     959             :                                   unsigned line,
     960             :                                   const char *section,
     961             :                                   unsigned section_line,
     962             :                                   const char *lvalue,
     963             :                                   int ltype,
     964             :                                   const char *rvalue,
     965             :                                   void *data,
     966             :                                   void *userdata) {
     967             : 
     968           0 :         ExecContext *c = data;
     969             :         size_t l;
     970             :         const char *word, *state;
     971             : 
     972           0 :         assert(filename);
     973           0 :         assert(lvalue);
     974           0 :         assert(rvalue);
     975           0 :         assert(data);
     976             : 
     977           0 :         if (isempty(rvalue)) {
     978             :                 /* An empty assignment resets the field */
     979           0 :                 c->secure_bits = 0;
     980           0 :                 return 0;
     981             :         }
     982             : 
     983           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
     984           0 :                 if (first_word(word, "keep-caps"))
     985           0 :                         c->secure_bits |= 1<<SECURE_KEEP_CAPS;
     986           0 :                 else if (first_word(word, "keep-caps-locked"))
     987           0 :                         c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
     988           0 :                 else if (first_word(word, "no-setuid-fixup"))
     989           0 :                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
     990           0 :                 else if (first_word(word, "no-setuid-fixup-locked"))
     991           0 :                         c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
     992           0 :                 else if (first_word(word, "noroot"))
     993           0 :                         c->secure_bits |= 1<<SECURE_NOROOT;
     994           0 :                 else if (first_word(word, "noroot-locked"))
     995           0 :                         c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
     996             :                 else {
     997           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
     998             :                                    "Failed to parse secure bits, ignoring: %s", rvalue);
     999           0 :                         return 0;
    1000             :                 }
    1001             :         }
    1002           0 :         if (!isempty(state))
    1003           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1004             :                            "Invalid syntax, garbage at the end, ignoring.");
    1005             : 
    1006           0 :         return 0;
    1007             : }
    1008             : 
    1009           0 : int config_parse_bounding_set(const char *unit,
    1010             :                               const char *filename,
    1011             :                               unsigned line,
    1012             :                               const char *section,
    1013             :                               unsigned section_line,
    1014             :                               const char *lvalue,
    1015             :                               int ltype,
    1016             :                               const char *rvalue,
    1017             :                               void *data,
    1018             :                               void *userdata) {
    1019             : 
    1020           0 :         uint64_t *capability_bounding_set_drop = data;
    1021             :         const char *word, *state;
    1022             :         size_t l;
    1023           0 :         bool invert = false;
    1024           0 :         uint64_t sum = 0;
    1025             : 
    1026           0 :         assert(filename);
    1027           0 :         assert(lvalue);
    1028           0 :         assert(rvalue);
    1029           0 :         assert(data);
    1030             : 
    1031           0 :         if (rvalue[0] == '~') {
    1032           0 :                 invert = true;
    1033           0 :                 rvalue++;
    1034             :         }
    1035             : 
    1036             :         /* Note that we store this inverted internally, since the
    1037             :          * kernel wants it like this. But we actually expose it
    1038             :          * non-inverted everywhere to have a fully normalized
    1039             :          * interface. */
    1040             : 
    1041           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    1042           0 :                 _cleanup_free_ char *t = NULL;
    1043             :                 int cap;
    1044             : 
    1045           0 :                 t = strndup(word, l);
    1046           0 :                 if (!t)
    1047           0 :                         return log_oom();
    1048             : 
    1049           0 :                 cap = capability_from_name(t);
    1050           0 :                 if (cap < 0) {
    1051           0 :                         log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
    1052           0 :                         continue;
    1053             :                 }
    1054             : 
    1055           0 :                 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
    1056             :         }
    1057           0 :         if (!isempty(state))
    1058           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1059             :                            "Trailing garbage, ignoring.");
    1060             : 
    1061           0 :         if (invert)
    1062           0 :                 *capability_bounding_set_drop |= sum;
    1063             :         else
    1064           0 :                 *capability_bounding_set_drop |= ~sum;
    1065             : 
    1066           0 :         return 0;
    1067             : }
    1068             : 
    1069           0 : int config_parse_limit(const char *unit,
    1070             :                        const char *filename,
    1071             :                        unsigned line,
    1072             :                        const char *section,
    1073             :                        unsigned section_line,
    1074             :                        const char *lvalue,
    1075             :                        int ltype,
    1076             :                        const char *rvalue,
    1077             :                        void *data,
    1078             :                        void *userdata) {
    1079             : 
    1080           0 :         struct rlimit **rl = data;
    1081             :         unsigned long long u;
    1082             : 
    1083           0 :         assert(filename);
    1084           0 :         assert(lvalue);
    1085           0 :         assert(rvalue);
    1086           0 :         assert(data);
    1087             : 
    1088           0 :         rl += ltype;
    1089             : 
    1090           0 :         if (streq(rvalue, "infinity"))
    1091           0 :                 u = (unsigned long long) RLIM_INFINITY;
    1092             :         else {
    1093             :                 int r;
    1094             : 
    1095           0 :                 r = safe_atollu(rvalue, &u);
    1096           0 :                 if (r < 0) {
    1097           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
    1098             :                                    "Failed to parse resource value, ignoring: %s", rvalue);
    1099           0 :                         return 0;
    1100             :                 }
    1101             :         }
    1102             : 
    1103           0 :         if (!*rl) {
    1104           0 :                 *rl = new(struct rlimit, 1);
    1105           0 :                 if (!*rl)
    1106           0 :                         return log_oom();
    1107             :         }
    1108             : 
    1109           0 :         (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
    1110           0 :         return 0;
    1111             : }
    1112             : 
    1113             : #ifdef HAVE_SYSV_COMPAT
    1114           0 : int config_parse_sysv_priority(const char *unit,
    1115             :                                const char *filename,
    1116             :                                unsigned line,
    1117             :                                const char *section,
    1118             :                                unsigned section_line,
    1119             :                                const char *lvalue,
    1120             :                                int ltype,
    1121             :                                const char *rvalue,
    1122             :                                void *data,
    1123             :                                void *userdata) {
    1124             : 
    1125           0 :         int *priority = data;
    1126             :         int i, r;
    1127             : 
    1128           0 :         assert(filename);
    1129           0 :         assert(lvalue);
    1130           0 :         assert(rvalue);
    1131           0 :         assert(data);
    1132             : 
    1133           0 :         r = safe_atoi(rvalue, &i);
    1134           0 :         if (r < 0 || i < 0) {
    1135           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1136             :                            "Failed to parse SysV start priority, ignoring: %s", rvalue);
    1137           0 :                 return 0;
    1138             :         }
    1139             : 
    1140           0 :         *priority = (int) i;
    1141           0 :         return 0;
    1142             : }
    1143             : #endif
    1144             : 
    1145           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
    1146             : 
    1147           0 : int config_parse_kill_signal(const char *unit,
    1148             :                              const char *filename,
    1149             :                              unsigned line,
    1150             :                              const char *section,
    1151             :                              unsigned section_line,
    1152             :                              const char *lvalue,
    1153             :                              int ltype,
    1154             :                              const char *rvalue,
    1155             :                              void *data,
    1156             :                              void *userdata) {
    1157             : 
    1158           0 :         int *sig = data;
    1159             :         int r;
    1160             : 
    1161           0 :         assert(filename);
    1162           0 :         assert(lvalue);
    1163           0 :         assert(rvalue);
    1164           0 :         assert(sig);
    1165             : 
    1166           0 :         r = signal_from_string_try_harder(rvalue);
    1167           0 :         if (r <= 0) {
    1168           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1169             :                            "Failed to parse kill signal, ignoring: %s", rvalue);
    1170           0 :                 return 0;
    1171             :         }
    1172             : 
    1173           0 :         *sig = r;
    1174           0 :         return 0;
    1175             : }
    1176             : 
    1177           0 : int config_parse_exec_mount_flags(const char *unit,
    1178             :                                   const char *filename,
    1179             :                                   unsigned line,
    1180             :                                   const char *section,
    1181             :                                   unsigned section_line,
    1182             :                                   const char *lvalue,
    1183             :                                   int ltype,
    1184             :                                   const char *rvalue,
    1185             :                                   void *data,
    1186             :                                   void *userdata) {
    1187             : 
    1188           0 :         ExecContext *c = data;
    1189             :         const char *word, *state;
    1190             :         size_t l;
    1191           0 :         unsigned long flags = 0;
    1192             : 
    1193           0 :         assert(filename);
    1194           0 :         assert(lvalue);
    1195           0 :         assert(rvalue);
    1196           0 :         assert(data);
    1197             : 
    1198           0 :         FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
    1199           0 :                 _cleanup_free_ char *t;
    1200             : 
    1201           0 :                 t = strndup(word, l);
    1202           0 :                 if (!t)
    1203           0 :                         return log_oom();
    1204             : 
    1205           0 :                 if (streq(t, "shared"))
    1206           0 :                         flags = MS_SHARED;
    1207           0 :                 else if (streq(t, "slave"))
    1208           0 :                         flags = MS_SLAVE;
    1209           0 :                 else if (streq(t, "private"))
    1210           0 :                         flags = MS_PRIVATE;
    1211             :                 else {
    1212           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
    1213           0 :                         return 0;
    1214             :                 }
    1215             :         }
    1216           0 :         if (!isempty(state))
    1217           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
    1218             : 
    1219           0 :         c->mount_flags = flags;
    1220           0 :         return 0;
    1221             : }
    1222             : 
    1223           0 : int config_parse_exec_selinux_context(
    1224             :                 const char *unit,
    1225             :                 const char *filename,
    1226             :                 unsigned line,
    1227             :                 const char *section,
    1228             :                 unsigned section_line,
    1229             :                 const char *lvalue,
    1230             :                 int ltype,
    1231             :                 const char *rvalue,
    1232             :                 void *data,
    1233             :                 void *userdata) {
    1234             : 
    1235           0 :         ExecContext *c = data;
    1236           0 :         Unit *u = userdata;
    1237             :         bool ignore;
    1238             :         char *k;
    1239             :         int r;
    1240             : 
    1241           0 :         assert(filename);
    1242           0 :         assert(lvalue);
    1243           0 :         assert(rvalue);
    1244           0 :         assert(data);
    1245             : 
    1246           0 :         if (isempty(rvalue)) {
    1247           0 :                 free(c->selinux_context);
    1248           0 :                 c->selinux_context = NULL;
    1249           0 :                 c->selinux_context_ignore = false;
    1250           0 :                 return 0;
    1251             :         }
    1252             : 
    1253           0 :         if (rvalue[0] == '-') {
    1254           0 :                 ignore = true;
    1255           0 :                 rvalue++;
    1256             :         } else
    1257           0 :                 ignore = false;
    1258             : 
    1259           0 :         r = unit_name_printf(u, rvalue, &k);
    1260           0 :         if (r < 0) {
    1261           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1262             :                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
    1263           0 :                 return 0;
    1264             :         }
    1265             : 
    1266           0 :         free(c->selinux_context);
    1267           0 :         c->selinux_context = k;
    1268           0 :         c->selinux_context_ignore = ignore;
    1269             : 
    1270           0 :         return 0;
    1271             : }
    1272             : 
    1273           0 : int config_parse_exec_apparmor_profile(
    1274             :                 const char *unit,
    1275             :                 const char *filename,
    1276             :                 unsigned line,
    1277             :                 const char *section,
    1278             :                 unsigned section_line,
    1279             :                 const char *lvalue,
    1280             :                 int ltype,
    1281             :                 const char *rvalue,
    1282             :                 void *data,
    1283             :                 void *userdata) {
    1284             : 
    1285           0 :         ExecContext *c = data;
    1286           0 :         Unit *u = userdata;
    1287             :         bool ignore;
    1288             :         char *k;
    1289             :         int r;
    1290             : 
    1291           0 :         assert(filename);
    1292           0 :         assert(lvalue);
    1293           0 :         assert(rvalue);
    1294           0 :         assert(data);
    1295             : 
    1296           0 :         if (isempty(rvalue)) {
    1297           0 :                 free(c->apparmor_profile);
    1298           0 :                 c->apparmor_profile = NULL;
    1299           0 :                 c->apparmor_profile_ignore = false;
    1300           0 :                 return 0;
    1301             :         }
    1302             : 
    1303           0 :         if (rvalue[0] == '-') {
    1304           0 :                 ignore = true;
    1305           0 :                 rvalue++;
    1306             :         } else
    1307           0 :                 ignore = false;
    1308             : 
    1309           0 :         r = unit_name_printf(u, rvalue, &k);
    1310           0 :         if (r < 0) {
    1311           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1312             :                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
    1313           0 :                 return 0;
    1314             :         }
    1315             : 
    1316           0 :         free(c->apparmor_profile);
    1317           0 :         c->apparmor_profile = k;
    1318           0 :         c->apparmor_profile_ignore = ignore;
    1319             : 
    1320           0 :         return 0;
    1321             : }
    1322             : 
    1323           0 : int config_parse_exec_smack_process_label(
    1324             :                 const char *unit,
    1325             :                 const char *filename,
    1326             :                 unsigned line,
    1327             :                 const char *section,
    1328             :                 unsigned section_line,
    1329             :                 const char *lvalue,
    1330             :                 int ltype,
    1331             :                 const char *rvalue,
    1332             :                 void *data,
    1333             :                 void *userdata) {
    1334             : 
    1335           0 :         ExecContext *c = data;
    1336           0 :         Unit *u = userdata;
    1337             :         bool ignore;
    1338             :         char *k;
    1339             :         int r;
    1340             : 
    1341           0 :         assert(filename);
    1342           0 :         assert(lvalue);
    1343           0 :         assert(rvalue);
    1344           0 :         assert(data);
    1345             : 
    1346           0 :         if (isempty(rvalue)) {
    1347           0 :                 free(c->smack_process_label);
    1348           0 :                 c->smack_process_label = NULL;
    1349           0 :                 c->smack_process_label_ignore = false;
    1350           0 :                 return 0;
    1351             :         }
    1352             : 
    1353           0 :         if (rvalue[0] == '-') {
    1354           0 :                 ignore = true;
    1355           0 :                 rvalue++;
    1356             :         } else
    1357           0 :                 ignore = false;
    1358             : 
    1359           0 :         r = unit_name_printf(u, rvalue, &k);
    1360           0 :         if (r < 0) {
    1361           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1362             :                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
    1363           0 :                 return 0;
    1364             :         }
    1365             : 
    1366           0 :         free(c->smack_process_label);
    1367           0 :         c->smack_process_label = k;
    1368           0 :         c->smack_process_label_ignore = ignore;
    1369             : 
    1370           0 :         return 0;
    1371             : }
    1372             : 
    1373           0 : int config_parse_timer(const char *unit,
    1374             :                        const char *filename,
    1375             :                        unsigned line,
    1376             :                        const char *section,
    1377             :                        unsigned section_line,
    1378             :                        const char *lvalue,
    1379             :                        int ltype,
    1380             :                        const char *rvalue,
    1381             :                        void *data,
    1382             :                        void *userdata) {
    1383             : 
    1384           0 :         Timer *t = data;
    1385           0 :         usec_t u = 0;
    1386             :         TimerValue *v;
    1387             :         TimerBase b;
    1388           0 :         CalendarSpec *c = NULL;
    1389             : 
    1390           0 :         assert(filename);
    1391           0 :         assert(lvalue);
    1392           0 :         assert(rvalue);
    1393           0 :         assert(data);
    1394             : 
    1395           0 :         if (isempty(rvalue)) {
    1396             :                 /* Empty assignment resets list */
    1397           0 :                 timer_free_values(t);
    1398           0 :                 return 0;
    1399             :         }
    1400             : 
    1401           0 :         b = timer_base_from_string(lvalue);
    1402           0 :         if (b < 0) {
    1403           0 :                 log_syntax(unit, LOG_ERR, filename, line, -b,
    1404             :                            "Failed to parse timer base, ignoring: %s", lvalue);
    1405           0 :                 return 0;
    1406             :         }
    1407             : 
    1408           0 :         if (b == TIMER_CALENDAR) {
    1409           0 :                 if (calendar_spec_from_string(rvalue, &c) < 0) {
    1410           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1411             :                                    "Failed to parse calendar specification, ignoring: %s",
    1412             :                                    rvalue);
    1413           0 :                         return 0;
    1414             :                 }
    1415             :         } else {
    1416           0 :                 if (parse_sec(rvalue, &u) < 0) {
    1417           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1418             :                                    "Failed to parse timer value, ignoring: %s",
    1419             :                                    rvalue);
    1420           0 :                         return 0;
    1421             :                 }
    1422             :         }
    1423             : 
    1424           0 :         v = new0(TimerValue, 1);
    1425           0 :         if (!v) {
    1426           0 :                 calendar_spec_free(c);
    1427           0 :                 return log_oom();
    1428             :         }
    1429             : 
    1430           0 :         v->base = b;
    1431           0 :         v->value = u;
    1432           0 :         v->calendar_spec = c;
    1433             : 
    1434           0 :         LIST_PREPEND(value, t->values, v);
    1435             : 
    1436           0 :         return 0;
    1437             : }
    1438             : 
    1439           1 : int config_parse_trigger_unit(
    1440             :                 const char *unit,
    1441             :                 const char *filename,
    1442             :                 unsigned line,
    1443             :                 const char *section,
    1444             :                 unsigned section_line,
    1445             :                 const char *lvalue,
    1446             :                 int ltype,
    1447             :                 const char *rvalue,
    1448             :                 void *data,
    1449             :                 void *userdata) {
    1450             : 
    1451           2 :         _cleanup_free_ char *p = NULL;
    1452           1 :         Unit *u = data;
    1453             :         UnitType type;
    1454             :         int r;
    1455             : 
    1456           1 :         assert(filename);
    1457           1 :         assert(lvalue);
    1458           1 :         assert(rvalue);
    1459           1 :         assert(data);
    1460             : 
    1461           1 :         if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
    1462           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1463             :                            "Multiple units to trigger specified, ignoring: %s", rvalue);
    1464           0 :                 return 0;
    1465             :         }
    1466             : 
    1467           1 :         r = unit_name_printf(u, rvalue, &p);
    1468           1 :         if (r < 0)
    1469           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1470             :                            "Failed to resolve specifiers, ignoring: %s", strerror(-r));
    1471             : 
    1472           1 :         type = unit_name_to_type(p ?: rvalue);
    1473           1 :         if (type < 0) {
    1474           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1475             :                            "Unit type not valid, ignoring: %s", rvalue);
    1476           0 :                 return 0;
    1477             :         }
    1478             : 
    1479           1 :         if (type == u->type) {
    1480           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1481             :                            "Trigger cannot be of same type, ignoring: %s", rvalue);
    1482           0 :                 return 0;
    1483             :         }
    1484             : 
    1485           1 :         r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
    1486           1 :         if (r < 0) {
    1487           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1488             :                            "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
    1489           0 :                 return 0;
    1490             :         }
    1491             : 
    1492           1 :         return 0;
    1493             : }
    1494             : 
    1495           7 : int config_parse_path_spec(const char *unit,
    1496             :                            const char *filename,
    1497             :                            unsigned line,
    1498             :                            const char *section,
    1499             :                            unsigned section_line,
    1500             :                            const char *lvalue,
    1501             :                            int ltype,
    1502             :                            const char *rvalue,
    1503             :                            void *data,
    1504             :                            void *userdata) {
    1505             : 
    1506           7 :         Path *p = data;
    1507             :         PathSpec *s;
    1508             :         PathType b;
    1509          14 :         _cleanup_free_ char *k = NULL;
    1510             :         int r;
    1511             : 
    1512           7 :         assert(filename);
    1513           7 :         assert(lvalue);
    1514           7 :         assert(rvalue);
    1515           7 :         assert(data);
    1516             : 
    1517           7 :         if (isempty(rvalue)) {
    1518             :                 /* Empty assignment clears list */
    1519           0 :                 path_free_specs(p);
    1520           0 :                 return 0;
    1521             :         }
    1522             : 
    1523           7 :         b = path_type_from_string(lvalue);
    1524           7 :         if (b < 0) {
    1525           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1526             :                            "Failed to parse path type, ignoring: %s", lvalue);
    1527           0 :                 return 0;
    1528             :         }
    1529             : 
    1530           7 :         r = unit_full_printf(UNIT(p), rvalue, &k);
    1531           7 :         if (r < 0) {
    1532           0 :                 k = strdup(rvalue);
    1533           0 :                 if (!k)
    1534           0 :                         return log_oom();
    1535             :                 else
    1536           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
    1537             :                                    "Failed to resolve unit specifiers on %s. Ignoring.",
    1538             :                                    rvalue);
    1539             :         }
    1540             : 
    1541           7 :         if (!path_is_absolute(k)) {
    1542           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1543             :                            "Path is not absolute, ignoring: %s", k);
    1544           0 :                 return 0;
    1545             :         }
    1546             : 
    1547           7 :         s = new0(PathSpec, 1);
    1548           7 :         if (!s)
    1549           0 :                 return log_oom();
    1550             : 
    1551           7 :         s->unit = UNIT(p);
    1552           7 :         s->path = path_kill_slashes(k);
    1553           7 :         k = NULL;
    1554           7 :         s->type = b;
    1555           7 :         s->inotify_fd = -1;
    1556             : 
    1557           7 :         LIST_PREPEND(spec, p->specs, s);
    1558             : 
    1559           7 :         return 0;
    1560             : }
    1561             : 
    1562           0 : int config_parse_socket_service(
    1563             :                 const char *unit,
    1564             :                 const char *filename,
    1565             :                 unsigned line,
    1566             :                 const char *section,
    1567             :                 unsigned section_line,
    1568             :                 const char *lvalue,
    1569             :                 int ltype,
    1570             :                 const char *rvalue,
    1571             :                 void *data,
    1572             :                 void *userdata) {
    1573             : 
    1574           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1575           0 :         Socket *s = data;
    1576             :         int r;
    1577             :         Unit *x;
    1578           0 :         _cleanup_free_ char *p = NULL;
    1579             : 
    1580           0 :         assert(filename);
    1581           0 :         assert(lvalue);
    1582           0 :         assert(rvalue);
    1583           0 :         assert(data);
    1584             : 
    1585           0 :         r = unit_name_printf(UNIT(s), rvalue, &p);
    1586           0 :         if (r < 0) {
    1587           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
    1588           0 :                 return 0;
    1589             :         }
    1590             : 
    1591           0 :         if (!endswith(p, ".service")) {
    1592           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
    1593           0 :                 return 0;
    1594             :         }
    1595             : 
    1596           0 :         r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
    1597           0 :         if (r < 0) {
    1598           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
    1599           0 :                 return 0;
    1600             :         }
    1601             : 
    1602           0 :         unit_ref_set(&s->service, x);
    1603             : 
    1604           0 :         return 0;
    1605             : }
    1606             : 
    1607           0 : int config_parse_service_sockets(
    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           0 :         Service *s = data;
    1620             :         const char *word, *state;
    1621             :         size_t l;
    1622             :         int r;
    1623             : 
    1624           0 :         assert(filename);
    1625           0 :         assert(lvalue);
    1626           0 :         assert(rvalue);
    1627           0 :         assert(data);
    1628             : 
    1629           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    1630           0 :                 _cleanup_free_ char *t = NULL, *k = NULL;
    1631             : 
    1632           0 :                 t = strndup(word, l);
    1633           0 :                 if (!t)
    1634           0 :                         return log_oom();
    1635             : 
    1636           0 :                 r = unit_name_printf(UNIT(s), t, &k);
    1637           0 :                 if (r < 0) {
    1638           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
    1639           0 :                         continue;
    1640             :                 }
    1641             : 
    1642           0 :                 if (!endswith(k, ".socket")) {
    1643           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
    1644           0 :                         continue;
    1645             :                 }
    1646             : 
    1647           0 :                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
    1648           0 :                 if (r < 0)
    1649           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
    1650             : 
    1651           0 :                 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
    1652           0 :                 if (r < 0)
    1653           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
    1654             :         }
    1655           0 :         if (!isempty(state))
    1656           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
    1657             : 
    1658           0 :         return 0;
    1659             : }
    1660             : 
    1661           0 : int config_parse_bus_name(
    1662             :                 const char *unit,
    1663             :                 const char *filename,
    1664             :                 unsigned line,
    1665             :                 const char *section,
    1666             :                 unsigned section_line,
    1667             :                 const char *lvalue,
    1668             :                 int ltype,
    1669             :                 const char *rvalue,
    1670             :                 void *data,
    1671             :                 void *userdata) {
    1672             : 
    1673           0 :         _cleanup_free_ char *k = NULL;
    1674           0 :         Unit *u = userdata;
    1675             :         int r;
    1676             : 
    1677           0 :         assert(filename);
    1678           0 :         assert(lvalue);
    1679           0 :         assert(rvalue);
    1680           0 :         assert(u);
    1681             : 
    1682           0 :         r = unit_full_printf(u, rvalue, &k);
    1683           0 :         if (r < 0) {
    1684           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
    1685           0 :                 return 0;
    1686             :         }
    1687             : 
    1688           0 :         if (!service_name_is_valid(k)) {
    1689           0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
    1690           0 :                 return 0;
    1691             :         }
    1692             : 
    1693           0 :         return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
    1694             : }
    1695             : 
    1696           0 : int config_parse_service_timeout(const char *unit,
    1697             :                                  const char *filename,
    1698             :                                  unsigned line,
    1699             :                                  const char *section,
    1700             :                                  unsigned section_line,
    1701             :                                  const char *lvalue,
    1702             :                                  int ltype,
    1703             :                                  const char *rvalue,
    1704             :                                  void *data,
    1705             :                                  void *userdata) {
    1706             : 
    1707           0 :         Service *s = userdata;
    1708             :         int r;
    1709             : 
    1710           0 :         assert(filename);
    1711           0 :         assert(lvalue);
    1712           0 :         assert(rvalue);
    1713           0 :         assert(s);
    1714             : 
    1715           0 :         r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
    1716             :                              rvalue, data, userdata);
    1717           0 :         if (r < 0)
    1718           0 :                 return r;
    1719             : 
    1720           0 :         if (streq(lvalue, "TimeoutSec")) {
    1721           0 :                 s->start_timeout_defined = true;
    1722           0 :                 s->timeout_stop_usec = s->timeout_start_usec;
    1723           0 :         } else if (streq(lvalue, "TimeoutStartSec"))
    1724           0 :                 s->start_timeout_defined = true;
    1725             : 
    1726           0 :         return 0;
    1727             : }
    1728             : 
    1729           0 : int config_parse_busname_service(
    1730             :                 const char *unit,
    1731             :                 const char *filename,
    1732             :                 unsigned line,
    1733             :                 const char *section,
    1734             :                 unsigned section_line,
    1735             :                 const char *lvalue,
    1736             :                 int ltype,
    1737             :                 const char *rvalue,
    1738             :                 void *data,
    1739             :                 void *userdata) {
    1740             : 
    1741           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1742           0 :         BusName *n = data;
    1743             :         int r;
    1744             :         Unit *x;
    1745           0 :         _cleanup_free_ char *p = NULL;
    1746             : 
    1747           0 :         assert(filename);
    1748           0 :         assert(lvalue);
    1749           0 :         assert(rvalue);
    1750           0 :         assert(data);
    1751             : 
    1752           0 :         r = unit_name_printf(UNIT(n), rvalue, &p);
    1753           0 :         if (r < 0) {
    1754           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1755             :                            "Failed to resolve specifiers, ignoring: %s", rvalue);
    1756           0 :                 return 0;
    1757             :         }
    1758             : 
    1759           0 :         if (!endswith(p, ".service")) {
    1760           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1761             :                            "Unit must be of type service, ignoring: %s", rvalue);
    1762           0 :                 return 0;
    1763             :         }
    1764             : 
    1765           0 :         r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
    1766           0 :         if (r < 0) {
    1767           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1768             :                            "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
    1769           0 :                 return 0;
    1770             :         }
    1771             : 
    1772           0 :         unit_ref_set(&n->service, x);
    1773             : 
    1774           0 :         return 0;
    1775             : }
    1776             : 
    1777           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
    1778             : 
    1779           0 : int config_parse_bus_policy(
    1780             :                 const char *unit,
    1781             :                 const char *filename,
    1782             :                 unsigned line,
    1783             :                 const char *section,
    1784             :                 unsigned section_line,
    1785             :                 const char *lvalue,
    1786             :                 int ltype,
    1787             :                 const char *rvalue,
    1788             :                 void *data,
    1789             :                 void *userdata) {
    1790             : 
    1791           0 :         _cleanup_free_ BusNamePolicy *p = NULL;
    1792           0 :         _cleanup_free_ char *id_str = NULL;
    1793           0 :         BusName *busname = data;
    1794             :         char *access_str;
    1795             : 
    1796           0 :         assert(filename);
    1797           0 :         assert(lvalue);
    1798           0 :         assert(rvalue);
    1799           0 :         assert(data);
    1800             : 
    1801           0 :         p = new0(BusNamePolicy, 1);
    1802           0 :         if (!p)
    1803           0 :                 return log_oom();
    1804             : 
    1805           0 :         if (streq(lvalue, "AllowUser"))
    1806           0 :                 p->type = BUSNAME_POLICY_TYPE_USER;
    1807           0 :         else if (streq(lvalue, "AllowGroup"))
    1808           0 :                 p->type = BUSNAME_POLICY_TYPE_GROUP;
    1809             :         else
    1810           0 :                 assert_not_reached("Unknown lvalue");
    1811             : 
    1812           0 :         id_str = strdup(rvalue);
    1813           0 :         if (!id_str)
    1814           0 :                 return log_oom();
    1815             : 
    1816           0 :         access_str = strpbrk(id_str, WHITESPACE);
    1817           0 :         if (!access_str) {
    1818           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1819             :                            "Invalid busname policy value '%s'", rvalue);
    1820           0 :                 return 0;
    1821             :         }
    1822             : 
    1823           0 :         *access_str = '\0';
    1824           0 :         access_str++;
    1825           0 :         access_str += strspn(access_str, WHITESPACE);
    1826             : 
    1827           0 :         p->access = bus_policy_access_from_string(access_str);
    1828           0 :         if (p->access < 0) {
    1829           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1830             :                            "Invalid busname policy access type '%s'", access_str);
    1831           0 :                 return 0;
    1832             :         }
    1833             : 
    1834           0 :         p->name = id_str;
    1835           0 :         id_str = NULL;
    1836             : 
    1837           0 :         LIST_PREPEND(policy, busname->policy, p);
    1838           0 :         p = NULL;
    1839             : 
    1840           0 :         return 0;
    1841             : }
    1842             : 
    1843           0 : int config_parse_bus_endpoint_policy(
    1844             :                 const char *unit,
    1845             :                 const char *filename,
    1846             :                 unsigned line,
    1847             :                 const char *section,
    1848             :                 unsigned section_line,
    1849             :                 const char *lvalue,
    1850             :                 int ltype,
    1851             :                 const char *rvalue,
    1852             :                 void *data,
    1853             :                 void *userdata) {
    1854             : 
    1855           0 :         _cleanup_free_ char *name = NULL;
    1856             :         BusPolicyAccess access;
    1857           0 :         ExecContext *c = data;
    1858             :         char *access_str;
    1859             :         int r;
    1860             : 
    1861           0 :         assert(filename);
    1862           0 :         assert(lvalue);
    1863           0 :         assert(rvalue);
    1864           0 :         assert(data);
    1865             : 
    1866           0 :         name = strdup(rvalue);
    1867           0 :         if (!name)
    1868           0 :                 return log_oom();
    1869             : 
    1870           0 :         access_str = strpbrk(name, WHITESPACE);
    1871           0 :         if (!access_str) {
    1872           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1873             :                            "Invalid endpoint policy value '%s'", rvalue);
    1874           0 :                 return 0;
    1875             :         }
    1876             : 
    1877           0 :         *access_str = '\0';
    1878           0 :         access_str++;
    1879           0 :         access_str += strspn(access_str, WHITESPACE);
    1880             : 
    1881           0 :         access = bus_policy_access_from_string(access_str);
    1882           0 :         if (access <= _BUS_POLICY_ACCESS_INVALID ||
    1883             :             access >= _BUS_POLICY_ACCESS_MAX) {
    1884           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1885             :                            "Invalid endpoint policy access type '%s'", access_str);
    1886           0 :                 return 0;
    1887             :         }
    1888             : 
    1889           0 :         if (!c->bus_endpoint) {
    1890           0 :                 r = bus_endpoint_new(&c->bus_endpoint);
    1891             : 
    1892           0 :                 if (r < 0)
    1893           0 :                         return r;
    1894             :         }
    1895             : 
    1896           0 :         return bus_endpoint_add_policy(c->bus_endpoint, name, access);
    1897             : }
    1898             : 
    1899           0 : int config_parse_unit_env_file(const char *unit,
    1900             :                                const char *filename,
    1901             :                                unsigned line,
    1902             :                                const char *section,
    1903             :                                unsigned section_line,
    1904             :                                const char *lvalue,
    1905             :                                int ltype,
    1906             :                                const char *rvalue,
    1907             :                                void *data,
    1908             :                                void *userdata) {
    1909             : 
    1910           0 :         char ***env = data;
    1911           0 :         Unit *u = userdata;
    1912           0 :         _cleanup_free_ char *n = NULL;
    1913             :         const char *s;
    1914             :         int r;
    1915             : 
    1916           0 :         assert(filename);
    1917           0 :         assert(lvalue);
    1918           0 :         assert(rvalue);
    1919           0 :         assert(data);
    1920             : 
    1921           0 :         if (isempty(rvalue)) {
    1922             :                 /* Empty assignment frees the list */
    1923           0 :                 strv_free(*env);
    1924           0 :                 *env = NULL;
    1925           0 :                 return 0;
    1926             :         }
    1927             : 
    1928           0 :         r = unit_full_printf(u, rvalue, &n);
    1929           0 :         if (r < 0)
    1930           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    1931             :                            "Failed to resolve specifiers, ignoring: %s", rvalue);
    1932             : 
    1933           0 :         s = n ?: rvalue;
    1934           0 :         if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
    1935           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    1936             :                            "Path '%s' is not absolute, ignoring.", s);
    1937           0 :                 return 0;
    1938             :         }
    1939             : 
    1940           0 :         r = strv_extend(env, s);
    1941           0 :         if (r < 0)
    1942           0 :                 return log_oom();
    1943             : 
    1944           0 :         return 0;
    1945             : }
    1946             : 
    1947           0 : int config_parse_environ(const char *unit,
    1948             :                          const char *filename,
    1949             :                          unsigned line,
    1950             :                          const char *section,
    1951             :                          unsigned section_line,
    1952             :                          const char *lvalue,
    1953             :                          int ltype,
    1954             :                          const char *rvalue,
    1955             :                          void *data,
    1956             :                          void *userdata) {
    1957             : 
    1958           0 :         Unit *u = userdata;
    1959           0 :         char*** env = data;
    1960             :         const char *word, *state;
    1961             :         size_t l;
    1962           0 :         _cleanup_free_ char *k = NULL;
    1963             :         int r;
    1964             : 
    1965           0 :         assert(filename);
    1966           0 :         assert(lvalue);
    1967           0 :         assert(rvalue);
    1968           0 :         assert(data);
    1969             : 
    1970           0 :         if (isempty(rvalue)) {
    1971             :                 /* Empty assignment resets the list */
    1972           0 :                 strv_free(*env);
    1973           0 :                 *env = NULL;
    1974           0 :                 return 0;
    1975             :         }
    1976             : 
    1977           0 :         if (u) {
    1978           0 :                 r = unit_full_printf(u, rvalue, &k);
    1979           0 :                 if (r < 0)
    1980           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
    1981             :         }
    1982             : 
    1983           0 :         if (!k)
    1984           0 :                 k = strdup(rvalue);
    1985           0 :         if (!k)
    1986           0 :                 return log_oom();
    1987             : 
    1988           0 :         FOREACH_WORD_QUOTED(word, l, k, state) {
    1989           0 :                 _cleanup_free_ char *n;
    1990             :                 char **x;
    1991             : 
    1992           0 :                 r = cunescape_length(word, l, 0, &n);
    1993           0 :                 if (r < 0) {
    1994           0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
    1995           0 :                         continue;
    1996             :                 }
    1997             : 
    1998           0 :                 if (!env_assignment_is_valid(n)) {
    1999           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue);
    2000           0 :                         continue;
    2001             :                 }
    2002             : 
    2003           0 :                 x = strv_env_set(*env, n);
    2004           0 :                 if (!x)
    2005           0 :                         return log_oom();
    2006             : 
    2007           0 :                 strv_free(*env);
    2008           0 :                 *env = x;
    2009             :         }
    2010           0 :         if (!isempty(state))
    2011           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2012             :                            "Trailing garbage, ignoring.");
    2013             : 
    2014           0 :         return 0;
    2015             : }
    2016             : 
    2017           0 : int config_parse_ip_tos(const char *unit,
    2018             :                         const char *filename,
    2019             :                         unsigned line,
    2020             :                         const char *section,
    2021             :                         unsigned section_line,
    2022             :                         const char *lvalue,
    2023             :                         int ltype,
    2024             :                         const char *rvalue,
    2025             :                         void *data,
    2026             :                         void *userdata) {
    2027             : 
    2028           0 :         int *ip_tos = data, x;
    2029             : 
    2030           0 :         assert(filename);
    2031           0 :         assert(lvalue);
    2032           0 :         assert(rvalue);
    2033           0 :         assert(data);
    2034             : 
    2035           0 :         x = ip_tos_from_string(rvalue);
    2036           0 :         if (x < 0) {
    2037           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2038             :                            "Failed to parse IP TOS value, ignoring: %s", rvalue);
    2039           0 :                 return 0;
    2040             :         }
    2041             : 
    2042           0 :         *ip_tos = x;
    2043           0 :         return 0;
    2044             : }
    2045             : 
    2046           0 : int config_parse_unit_condition_path(
    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 :         _cleanup_free_ char *p = NULL;
    2059           0 :         Condition **list = data, *c;
    2060           0 :         ConditionType t = ltype;
    2061             :         bool trigger, negate;
    2062           0 :         Unit *u = userdata;
    2063             :         int r;
    2064             : 
    2065           0 :         assert(filename);
    2066           0 :         assert(lvalue);
    2067           0 :         assert(rvalue);
    2068           0 :         assert(data);
    2069             : 
    2070           0 :         if (isempty(rvalue)) {
    2071             :                 /* Empty assignment resets the list */
    2072           0 :                 *list = condition_free_list(*list);
    2073           0 :                 return 0;
    2074             :         }
    2075             : 
    2076           0 :         trigger = rvalue[0] == '|';
    2077           0 :         if (trigger)
    2078           0 :                 rvalue++;
    2079             : 
    2080           0 :         negate = rvalue[0] == '!';
    2081           0 :         if (negate)
    2082           0 :                 rvalue++;
    2083             : 
    2084           0 :         r = unit_full_printf(u, rvalue, &p);
    2085           0 :         if (r < 0) {
    2086           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
    2087           0 :                 return 0;
    2088             :         }
    2089             : 
    2090           0 :         if (!path_is_absolute(p)) {
    2091           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
    2092           0 :                 return 0;
    2093             :         }
    2094             : 
    2095           0 :         c = condition_new(t, p, trigger, negate);
    2096           0 :         if (!c)
    2097           0 :                 return log_oom();
    2098             : 
    2099           0 :         LIST_PREPEND(conditions, *list, c);
    2100           0 :         return 0;
    2101             : }
    2102             : 
    2103           0 : int config_parse_unit_condition_string(
    2104             :                 const char *unit,
    2105             :                 const char *filename,
    2106             :                 unsigned line,
    2107             :                 const char *section,
    2108             :                 unsigned section_line,
    2109             :                 const char *lvalue,
    2110             :                 int ltype,
    2111             :                 const char *rvalue,
    2112             :                 void *data,
    2113             :                 void *userdata) {
    2114             : 
    2115           0 :         _cleanup_free_ char *s = NULL;
    2116           0 :         Condition **list = data, *c;
    2117           0 :         ConditionType t = ltype;
    2118             :         bool trigger, negate;
    2119           0 :         Unit *u = userdata;
    2120             :         int r;
    2121             : 
    2122           0 :         assert(filename);
    2123           0 :         assert(lvalue);
    2124           0 :         assert(rvalue);
    2125           0 :         assert(data);
    2126             : 
    2127           0 :         if (isempty(rvalue)) {
    2128             :                 /* Empty assignment resets the list */
    2129           0 :                 *list = condition_free_list(*list);
    2130           0 :                 return 0;
    2131             :         }
    2132             : 
    2133           0 :         trigger = rvalue[0] == '|';
    2134           0 :         if (trigger)
    2135           0 :                 rvalue++;
    2136             : 
    2137           0 :         negate = rvalue[0] == '!';
    2138           0 :         if (negate)
    2139           0 :                 rvalue++;
    2140             : 
    2141           0 :         r = unit_full_printf(u, rvalue, &s);
    2142           0 :         if (r < 0) {
    2143           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
    2144           0 :                 return 0;
    2145             :         }
    2146             : 
    2147           0 :         c = condition_new(t, s, trigger, negate);
    2148           0 :         if (!c)
    2149           0 :                 return log_oom();
    2150             : 
    2151           0 :         LIST_PREPEND(conditions, *list, c);
    2152           0 :         return 0;
    2153             : }
    2154             : 
    2155           0 : int config_parse_unit_condition_null(
    2156             :                 const char *unit,
    2157             :                 const char *filename,
    2158             :                 unsigned line,
    2159             :                 const char *section,
    2160             :                 unsigned section_line,
    2161             :                 const char *lvalue,
    2162             :                 int ltype,
    2163             :                 const char *rvalue,
    2164             :                 void *data,
    2165             :                 void *userdata) {
    2166             : 
    2167           0 :         Condition **list = data, *c;
    2168             :         bool trigger, negate;
    2169             :         int b;
    2170             : 
    2171           0 :         assert(filename);
    2172           0 :         assert(lvalue);
    2173           0 :         assert(rvalue);
    2174           0 :         assert(data);
    2175             : 
    2176           0 :         if (isempty(rvalue)) {
    2177             :                 /* Empty assignment resets the list */
    2178           0 :                 *list = condition_free_list(*list);
    2179           0 :                 return 0;
    2180             :         }
    2181             : 
    2182           0 :         trigger = rvalue[0] == '|';
    2183           0 :         if (trigger)
    2184           0 :                 rvalue++;
    2185             : 
    2186           0 :         negate = rvalue[0] == '!';
    2187           0 :         if (negate)
    2188           0 :                 rvalue++;
    2189             : 
    2190           0 :         b = parse_boolean(rvalue);
    2191           0 :         if (b < 0) {
    2192           0 :                 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
    2193           0 :                 return 0;
    2194             :         }
    2195             : 
    2196           0 :         if (!b)
    2197           0 :                 negate = !negate;
    2198             : 
    2199           0 :         c = condition_new(CONDITION_NULL, NULL, trigger, negate);
    2200           0 :         if (!c)
    2201           0 :                 return log_oom();
    2202             : 
    2203           0 :         LIST_PREPEND(conditions, *list, c);
    2204           0 :         return 0;
    2205             : }
    2206             : 
    2207           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
    2208           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
    2209             : 
    2210          10 : int config_parse_unit_requires_mounts_for(
    2211             :                 const char *unit,
    2212             :                 const char *filename,
    2213             :                 unsigned line,
    2214             :                 const char *section,
    2215             :                 unsigned section_line,
    2216             :                 const char *lvalue,
    2217             :                 int ltype,
    2218             :                 const char *rvalue,
    2219             :                 void *data,
    2220             :                 void *userdata) {
    2221             : 
    2222          10 :         Unit *u = userdata;
    2223             :         const char *word, *state;
    2224             :         size_t l;
    2225             : 
    2226          10 :         assert(filename);
    2227          10 :         assert(lvalue);
    2228          10 :         assert(rvalue);
    2229          10 :         assert(data);
    2230             : 
    2231          40 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    2232             :                 int r;
    2233          30 :                 _cleanup_free_ char *n;
    2234             : 
    2235          30 :                 n = strndup(word, l);
    2236          30 :                 if (!n)
    2237           0 :                         return log_oom();
    2238             : 
    2239          30 :                 if (!utf8_is_valid(n)) {
    2240           0 :                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
    2241           0 :                         continue;
    2242             :                 }
    2243             : 
    2244          30 :                 r = unit_require_mounts_for(u, n);
    2245          30 :                 if (r < 0) {
    2246           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
    2247             :                                    "Failed to add required mount for, ignoring: %s", rvalue);
    2248           0 :                         continue;
    2249             :                 }
    2250             :         }
    2251          10 :         if (!isempty(state))
    2252           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2253             :                            "Trailing garbage, ignoring.");
    2254             : 
    2255          10 :         return 0;
    2256             : }
    2257             : 
    2258          60 : int config_parse_documentation(const char *unit,
    2259             :                                const char *filename,
    2260             :                                unsigned line,
    2261             :                                const char *section,
    2262             :                                unsigned section_line,
    2263             :                                const char *lvalue,
    2264             :                                int ltype,
    2265             :                                const char *rvalue,
    2266             :                                void *data,
    2267             :                                void *userdata) {
    2268             : 
    2269          60 :         Unit *u = userdata;
    2270             :         int r;
    2271             :         char **a, **b;
    2272             : 
    2273          60 :         assert(filename);
    2274          60 :         assert(lvalue);
    2275          60 :         assert(rvalue);
    2276          60 :         assert(u);
    2277             : 
    2278          60 :         if (isempty(rvalue)) {
    2279             :                 /* Empty assignment resets the list */
    2280           0 :                 strv_free(u->documentation);
    2281           0 :                 u->documentation = NULL;
    2282           0 :                 return 0;
    2283             :         }
    2284             : 
    2285          60 :         r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
    2286             :                                           rvalue, data, userdata);
    2287          60 :         if (r < 0)
    2288           0 :                 return r;
    2289             : 
    2290         120 :         for (a = b = u->documentation; a && *a; a++) {
    2291             : 
    2292          60 :                 if (documentation_url_is_valid(*a))
    2293          60 :                         *(b++) = *a;
    2294             :                 else {
    2295           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2296             :                                    "Invalid URL, ignoring: %s", *a);
    2297           0 :                         free(*a);
    2298             :                 }
    2299             :         }
    2300          60 :         if (b)
    2301          60 :                 *b = NULL;
    2302             : 
    2303          60 :         return r;
    2304             : }
    2305             : 
    2306             : #ifdef HAVE_SECCOMP
    2307           0 : int config_parse_syscall_filter(
    2308             :                 const char *unit,
    2309             :                 const char *filename,
    2310             :                 unsigned line,
    2311             :                 const char *section,
    2312             :                 unsigned section_line,
    2313             :                 const char *lvalue,
    2314             :                 int ltype,
    2315             :                 const char *rvalue,
    2316             :                 void *data,
    2317             :                 void *userdata) {
    2318             : 
    2319             :         static const char default_syscalls[] =
    2320             :                 "execve\0"
    2321             :                 "exit\0"
    2322             :                 "exit_group\0"
    2323             :                 "rt_sigreturn\0"
    2324             :                 "sigreturn\0";
    2325             : 
    2326           0 :         ExecContext *c = data;
    2327           0 :         Unit *u = userdata;
    2328           0 :         bool invert = false;
    2329             :         const char *word, *state;
    2330             :         size_t l;
    2331             :         int r;
    2332             : 
    2333           0 :         assert(filename);
    2334           0 :         assert(lvalue);
    2335           0 :         assert(rvalue);
    2336           0 :         assert(u);
    2337             : 
    2338           0 :         if (isempty(rvalue)) {
    2339             :                 /* Empty assignment resets the list */
    2340           0 :                 set_free(c->syscall_filter);
    2341           0 :                 c->syscall_filter = NULL;
    2342           0 :                 c->syscall_whitelist = false;
    2343           0 :                 return 0;
    2344             :         }
    2345             : 
    2346           0 :         if (rvalue[0] == '~') {
    2347           0 :                 invert = true;
    2348           0 :                 rvalue++;
    2349             :         }
    2350             : 
    2351           0 :         if (!c->syscall_filter) {
    2352           0 :                 c->syscall_filter = set_new(NULL);
    2353           0 :                 if (!c->syscall_filter)
    2354           0 :                         return log_oom();
    2355             : 
    2356           0 :                 if (invert)
    2357             :                         /* Allow everything but the ones listed */
    2358           0 :                         c->syscall_whitelist = false;
    2359             :                 else {
    2360             :                         const char *i;
    2361             : 
    2362             :                         /* Allow nothing but the ones listed */
    2363           0 :                         c->syscall_whitelist = true;
    2364             : 
    2365             :                         /* Accept default syscalls if we are on a whitelist */
    2366           0 :                         NULSTR_FOREACH(i, default_syscalls)  {
    2367             :                                 int id;
    2368             : 
    2369           0 :                                 id = seccomp_syscall_resolve_name(i);
    2370           0 :                                 if (id < 0)
    2371           0 :                                         continue;
    2372             : 
    2373           0 :                                 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
    2374           0 :                                 if (r == 0)
    2375           0 :                                         continue;
    2376           0 :                                 if (r < 0)
    2377           0 :                                         return log_oom();
    2378             :                         }
    2379             :                 }
    2380             :         }
    2381             : 
    2382           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    2383           0 :                 _cleanup_free_ char *t = NULL;
    2384             :                 int id;
    2385             : 
    2386           0 :                 t = strndup(word, l);
    2387           0 :                 if (!t)
    2388           0 :                         return log_oom();
    2389             : 
    2390           0 :                 id = seccomp_syscall_resolve_name(t);
    2391           0 :                 if (id < 0)  {
    2392           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2393             :                                    "Failed to parse system call, ignoring: %s", t);
    2394           0 :                         continue;
    2395             :                 }
    2396             : 
    2397             :                 /* If we previously wanted to forbid a syscall and now
    2398             :                  * we want to allow it, then remove it from the list
    2399             :                  */
    2400           0 :                 if (!invert == c->syscall_whitelist)  {
    2401           0 :                         r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
    2402           0 :                         if (r == 0)
    2403           0 :                                 continue;
    2404           0 :                         if (r < 0)
    2405           0 :                                 return log_oom();
    2406             :                 } else
    2407           0 :                         set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
    2408             :         }
    2409           0 :         if (!isempty(state))
    2410           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2411             :                            "Trailing garbage, ignoring.");
    2412             : 
    2413             :         /* Turn on NNP, but only if it wasn't configured explicitly
    2414             :          * before, and only if we are in user mode. */
    2415           0 :         if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
    2416           0 :                 c->no_new_privileges = true;
    2417             : 
    2418           0 :         return 0;
    2419             : }
    2420             : 
    2421           0 : int config_parse_syscall_archs(
    2422             :                 const char *unit,
    2423             :                 const char *filename,
    2424             :                 unsigned line,
    2425             :                 const char *section,
    2426             :                 unsigned section_line,
    2427             :                 const char *lvalue,
    2428             :                 int ltype,
    2429             :                 const char *rvalue,
    2430             :                 void *data,
    2431             :                 void *userdata) {
    2432             : 
    2433           0 :         Set **archs = data;
    2434             :         const char *word, *state;
    2435             :         size_t l;
    2436             :         int r;
    2437             : 
    2438           0 :         if (isempty(rvalue)) {
    2439           0 :                 set_free(*archs);
    2440           0 :                 *archs = NULL;
    2441           0 :                 return 0;
    2442             :         }
    2443             : 
    2444           0 :         r = set_ensure_allocated(archs, NULL);
    2445           0 :         if (r < 0)
    2446           0 :                 return log_oom();
    2447             : 
    2448           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    2449           0 :                 _cleanup_free_ char *t = NULL;
    2450             :                 uint32_t a;
    2451             : 
    2452           0 :                 t = strndup(word, l);
    2453           0 :                 if (!t)
    2454           0 :                         return log_oom();
    2455             : 
    2456           0 :                 r = seccomp_arch_from_string(t, &a);
    2457           0 :                 if (r < 0) {
    2458           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2459             :                                    "Failed to parse system call architecture, ignoring: %s", t);
    2460           0 :                         continue;
    2461             :                 }
    2462             : 
    2463           0 :                 r = set_put(*archs, UINT32_TO_PTR(a + 1));
    2464           0 :                 if (r == 0)
    2465           0 :                         continue;
    2466           0 :                 if (r < 0)
    2467           0 :                         return log_oom();
    2468             :         }
    2469           0 :         if (!isempty(state))
    2470           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2471             :                            "Trailing garbage, ignoring.");
    2472             : 
    2473           0 :         return 0;
    2474             : }
    2475             : 
    2476           0 : int config_parse_syscall_errno(
    2477             :                 const char *unit,
    2478             :                 const char *filename,
    2479             :                 unsigned line,
    2480             :                 const char *section,
    2481             :                 unsigned section_line,
    2482             :                 const char *lvalue,
    2483             :                 int ltype,
    2484             :                 const char *rvalue,
    2485             :                 void *data,
    2486             :                 void *userdata) {
    2487             : 
    2488           0 :         ExecContext *c = data;
    2489             :         int e;
    2490             : 
    2491           0 :         assert(filename);
    2492           0 :         assert(lvalue);
    2493           0 :         assert(rvalue);
    2494             : 
    2495           0 :         if (isempty(rvalue)) {
    2496             :                 /* Empty assignment resets to KILL */
    2497           0 :                 c->syscall_errno = 0;
    2498           0 :                 return 0;
    2499             :         }
    2500             : 
    2501           0 :         e = errno_from_name(rvalue);
    2502           0 :         if (e < 0) {
    2503           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2504             :                            "Failed to parse error number, ignoring: %s", rvalue);
    2505           0 :                 return 0;
    2506             :         }
    2507             : 
    2508           0 :         c->syscall_errno = e;
    2509           0 :         return 0;
    2510             : }
    2511             : 
    2512           0 : int config_parse_address_families(
    2513             :                 const char *unit,
    2514             :                 const char *filename,
    2515             :                 unsigned line,
    2516             :                 const char *section,
    2517             :                 unsigned section_line,
    2518             :                 const char *lvalue,
    2519             :                 int ltype,
    2520             :                 const char *rvalue,
    2521             :                 void *data,
    2522             :                 void *userdata) {
    2523             : 
    2524           0 :         ExecContext *c = data;
    2525           0 :         bool invert = false;
    2526             :         const char *word, *state;
    2527             :         size_t l;
    2528             :         int r;
    2529             : 
    2530           0 :         assert(filename);
    2531           0 :         assert(lvalue);
    2532           0 :         assert(rvalue);
    2533             : 
    2534           0 :         if (isempty(rvalue)) {
    2535             :                 /* Empty assignment resets the list */
    2536           0 :                 set_free(c->address_families);
    2537           0 :                 c->address_families = NULL;
    2538           0 :                 c->address_families_whitelist = false;
    2539           0 :                 return 0;
    2540             :         }
    2541             : 
    2542           0 :         if (rvalue[0] == '~') {
    2543           0 :                 invert = true;
    2544           0 :                 rvalue++;
    2545             :         }
    2546             : 
    2547           0 :         if (!c->address_families) {
    2548           0 :                 c->address_families = set_new(NULL);
    2549           0 :                 if (!c->address_families)
    2550           0 :                         return log_oom();
    2551             : 
    2552           0 :                 c->address_families_whitelist = !invert;
    2553             :         }
    2554             : 
    2555           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    2556           0 :                 _cleanup_free_ char *t = NULL;
    2557             :                 int af;
    2558             : 
    2559           0 :                 t = strndup(word, l);
    2560           0 :                 if (!t)
    2561           0 :                         return log_oom();
    2562             : 
    2563           0 :                 af = af_from_name(t);
    2564           0 :                 if (af <= 0)  {
    2565           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2566             :                                    "Failed to parse address family, ignoring: %s", t);
    2567           0 :                         continue;
    2568             :                 }
    2569             : 
    2570             :                 /* If we previously wanted to forbid an address family and now
    2571             :                  * we want to allow it, then remove it from the list
    2572             :                  */
    2573           0 :                 if (!invert == c->address_families_whitelist)  {
    2574           0 :                         r = set_put(c->address_families, INT_TO_PTR(af));
    2575           0 :                         if (r == 0)
    2576           0 :                                 continue;
    2577           0 :                         if (r < 0)
    2578           0 :                                 return log_oom();
    2579             :                 } else
    2580           0 :                         set_remove(c->address_families, INT_TO_PTR(af));
    2581             :         }
    2582           0 :         if (!isempty(state))
    2583           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2584             :                            "Trailing garbage, ignoring.");
    2585             : 
    2586           0 :         return 0;
    2587             : }
    2588             : #endif
    2589             : 
    2590           3 : int config_parse_unit_slice(
    2591             :                 const char *unit,
    2592             :                 const char *filename,
    2593             :                 unsigned line,
    2594             :                 const char *section,
    2595             :                 unsigned section_line,
    2596             :                 const char *lvalue,
    2597             :                 int ltype,
    2598             :                 const char *rvalue,
    2599             :                 void *data,
    2600             :                 void *userdata) {
    2601             : 
    2602           6 :         _cleanup_free_ char *k = NULL;
    2603           3 :         Unit *u = userdata, *slice;
    2604             :         int r;
    2605             : 
    2606           3 :         assert(filename);
    2607           3 :         assert(lvalue);
    2608           3 :         assert(rvalue);
    2609           3 :         assert(u);
    2610             : 
    2611           3 :         r = unit_name_printf(u, rvalue, &k);
    2612           3 :         if (r < 0)
    2613           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    2614             :                            "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
    2615           3 :         if (!k) {
    2616           0 :                 k = strdup(rvalue);
    2617           0 :                 if (!k)
    2618           0 :                         return log_oom();
    2619             :         }
    2620             : 
    2621           3 :         r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
    2622           3 :         if (r < 0) {
    2623           0 :                 log_syntax(unit, LOG_ERR, filename, line, -r,
    2624             :                            "Failed to load slice unit %s. Ignoring.", k);
    2625           0 :                 return 0;
    2626             :         }
    2627             : 
    2628           3 :         if (slice->type != UNIT_SLICE) {
    2629           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2630             :                            "Slice unit %s is not a slice. Ignoring.", k);
    2631           0 :                 return 0;
    2632             :         }
    2633             : 
    2634           3 :         unit_ref_set(&u->slice, slice);
    2635           3 :         return 0;
    2636             : }
    2637             : 
    2638           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
    2639             : 
    2640           1 : int config_parse_cpu_shares(
    2641             :                 const char *unit,
    2642             :                 const char *filename,
    2643             :                 unsigned line,
    2644             :                 const char *section,
    2645             :                 unsigned section_line,
    2646             :                 const char *lvalue,
    2647             :                 int ltype,
    2648             :                 const char *rvalue,
    2649             :                 void *data,
    2650             :                 void *userdata) {
    2651             : 
    2652           1 :         unsigned long *shares = data, lu;
    2653             :         int r;
    2654             : 
    2655           1 :         assert(filename);
    2656           1 :         assert(lvalue);
    2657           1 :         assert(rvalue);
    2658             : 
    2659           1 :         if (isempty(rvalue)) {
    2660           0 :                 *shares = (unsigned long) -1;
    2661           0 :                 return 0;
    2662             :         }
    2663             : 
    2664           1 :         r = safe_atolu(rvalue, &lu);
    2665           1 :         if (r < 0 || lu <= 0) {
    2666           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2667             :                            "CPU shares '%s' invalid. Ignoring.", rvalue);
    2668           0 :                 return 0;
    2669             :         }
    2670             : 
    2671           1 :         *shares = lu;
    2672           1 :         return 0;
    2673             : }
    2674             : 
    2675           0 : int config_parse_cpu_quota(
    2676             :                 const char *unit,
    2677             :                 const char *filename,
    2678             :                 unsigned line,
    2679             :                 const char *section,
    2680             :                 unsigned section_line,
    2681             :                 const char *lvalue,
    2682             :                 int ltype,
    2683             :                 const char *rvalue,
    2684             :                 void *data,
    2685             :                 void *userdata) {
    2686             : 
    2687           0 :         CGroupContext *c = data;
    2688             :         double percent;
    2689             : 
    2690           0 :         assert(filename);
    2691           0 :         assert(lvalue);
    2692           0 :         assert(rvalue);
    2693             : 
    2694           0 :         if (isempty(rvalue)) {
    2695           0 :                 c->cpu_quota_per_sec_usec = USEC_INFINITY;
    2696           0 :                 return 0;
    2697             :         }
    2698             : 
    2699           0 :         if (!endswith(rvalue, "%")) {
    2700             : 
    2701           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2702             :                            "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
    2703           0 :                 return 0;
    2704             :         }
    2705             : 
    2706           0 :         if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
    2707           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2708             :                            "CPU quota '%s' invalid. Ignoring.", rvalue);
    2709           0 :                 return 0;
    2710             :         }
    2711             : 
    2712           0 :         c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
    2713             : 
    2714           0 :         return 0;
    2715             : }
    2716             : 
    2717           1 : int config_parse_memory_limit(
    2718             :                 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           1 :         CGroupContext *c = data;
    2730             :         off_t bytes;
    2731             :         int r;
    2732             : 
    2733           1 :         if (isempty(rvalue)) {
    2734           0 :                 c->memory_limit = (uint64_t) -1;
    2735           0 :                 return 0;
    2736             :         }
    2737             : 
    2738             :         assert_cc(sizeof(uint64_t) == sizeof(off_t));
    2739             : 
    2740           1 :         r = parse_size(rvalue, 1024, &bytes);
    2741           1 :         if (r < 0) {
    2742           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2743             :                            "Memory limit '%s' invalid. Ignoring.", rvalue);
    2744           0 :                 return 0;
    2745             :         }
    2746             : 
    2747           1 :         c->memory_limit = (uint64_t) bytes;
    2748           1 :         return 0;
    2749             : }
    2750             : 
    2751           0 : int config_parse_device_allow(
    2752             :                 const char *unit,
    2753             :                 const char *filename,
    2754             :                 unsigned line,
    2755             :                 const char *section,
    2756             :                 unsigned section_line,
    2757             :                 const char *lvalue,
    2758             :                 int ltype,
    2759             :                 const char *rvalue,
    2760             :                 void *data,
    2761             :                 void *userdata) {
    2762             : 
    2763           0 :         _cleanup_free_ char *path = NULL;
    2764           0 :         CGroupContext *c = data;
    2765             :         CGroupDeviceAllow *a;
    2766             :         const char *m;
    2767             :         size_t n;
    2768             : 
    2769           0 :         if (isempty(rvalue)) {
    2770           0 :                 while (c->device_allow)
    2771           0 :                         cgroup_context_free_device_allow(c, c->device_allow);
    2772             : 
    2773           0 :                 return 0;
    2774             :         }
    2775             : 
    2776           0 :         n = strcspn(rvalue, WHITESPACE);
    2777           0 :         path = strndup(rvalue, n);
    2778           0 :         if (!path)
    2779           0 :                 return log_oom();
    2780             : 
    2781           0 :         if (!startswith(path, "/dev/") &&
    2782           0 :             !startswith(path, "block-") &&
    2783           0 :             !startswith(path, "char-")) {
    2784           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2785             :                            "Invalid device node path '%s'. Ignoring.", path);
    2786           0 :                 return 0;
    2787             :         }
    2788             : 
    2789           0 :         m = rvalue + n + strspn(rvalue + n, WHITESPACE);
    2790           0 :         if (isempty(m))
    2791           0 :                 m = "rwm";
    2792             : 
    2793           0 :         if (!in_charset(m, "rwm")) {
    2794           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2795             :                            "Invalid device rights '%s'. Ignoring.", m);
    2796           0 :                 return 0;
    2797             :         }
    2798             : 
    2799           0 :         a = new0(CGroupDeviceAllow, 1);
    2800           0 :         if (!a)
    2801           0 :                 return log_oom();
    2802             : 
    2803           0 :         a->path = path;
    2804           0 :         path = NULL;
    2805           0 :         a->r = !!strchr(m, 'r');
    2806           0 :         a->w = !!strchr(m, 'w');
    2807           0 :         a->m = !!strchr(m, 'm');
    2808             : 
    2809           0 :         LIST_PREPEND(device_allow, c->device_allow, a);
    2810           0 :         return 0;
    2811             : }
    2812             : 
    2813           1 : int config_parse_blockio_weight(
    2814             :                 const char *unit,
    2815             :                 const char *filename,
    2816             :                 unsigned line,
    2817             :                 const char *section,
    2818             :                 unsigned section_line,
    2819             :                 const char *lvalue,
    2820             :                 int ltype,
    2821             :                 const char *rvalue,
    2822             :                 void *data,
    2823             :                 void *userdata) {
    2824             : 
    2825           1 :         unsigned long *weight = data, lu;
    2826             :         int r;
    2827             : 
    2828           1 :         assert(filename);
    2829           1 :         assert(lvalue);
    2830           1 :         assert(rvalue);
    2831             : 
    2832           1 :         if (isempty(rvalue)) {
    2833           0 :                 *weight = (unsigned long) -1;
    2834           0 :                 return 0;
    2835             :         }
    2836             : 
    2837           1 :         r = safe_atolu(rvalue, &lu);
    2838           1 :         if (r < 0 || lu < 10 || lu > 1000) {
    2839           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2840             :                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
    2841           0 :                 return 0;
    2842             :         }
    2843             : 
    2844           1 :         *weight = lu;
    2845           1 :         return 0;
    2846             : }
    2847             : 
    2848           0 : int config_parse_blockio_device_weight(
    2849             :                 const char *unit,
    2850             :                 const char *filename,
    2851             :                 unsigned line,
    2852             :                 const char *section,
    2853             :                 unsigned section_line,
    2854             :                 const char *lvalue,
    2855             :                 int ltype,
    2856             :                 const char *rvalue,
    2857             :                 void *data,
    2858             :                 void *userdata) {
    2859             : 
    2860           0 :         _cleanup_free_ char *path = NULL;
    2861             :         CGroupBlockIODeviceWeight *w;
    2862           0 :         CGroupContext *c = data;
    2863             :         unsigned long lu;
    2864             :         const char *weight;
    2865             :         size_t n;
    2866             :         int r;
    2867             : 
    2868           0 :         assert(filename);
    2869           0 :         assert(lvalue);
    2870           0 :         assert(rvalue);
    2871             : 
    2872           0 :         if (isempty(rvalue)) {
    2873           0 :                 while (c->blockio_device_weights)
    2874           0 :                         cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
    2875             : 
    2876           0 :                 return 0;
    2877             :         }
    2878             : 
    2879           0 :         n = strcspn(rvalue, WHITESPACE);
    2880           0 :         weight = rvalue + n;
    2881           0 :         if (!*weight) {
    2882           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2883             :                            "Expected block device and device weight. Ignoring.");
    2884           0 :                 return 0;
    2885             :         }
    2886             : 
    2887           0 :         path = strndup(rvalue, n);
    2888           0 :         if (!path)
    2889           0 :                 return log_oom();
    2890             : 
    2891           0 :         if (!path_startswith(path, "/dev")) {
    2892           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2893             :                            "Invalid device node path '%s'. Ignoring.", path);
    2894           0 :                 return 0;
    2895             :         }
    2896             : 
    2897           0 :         weight += strspn(weight, WHITESPACE);
    2898           0 :         r = safe_atolu(weight, &lu);
    2899           0 :         if (r < 0 || lu < 10 || lu > 1000) {
    2900           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2901             :                            "Block IO weight '%s' invalid. Ignoring.", rvalue);
    2902           0 :                 return 0;
    2903             :         }
    2904             : 
    2905           0 :         w = new0(CGroupBlockIODeviceWeight, 1);
    2906           0 :         if (!w)
    2907           0 :                 return log_oom();
    2908             : 
    2909           0 :         w->path = path;
    2910           0 :         path = NULL;
    2911             : 
    2912           0 :         w->weight = lu;
    2913             : 
    2914           0 :         LIST_PREPEND(device_weights, c->blockio_device_weights, w);
    2915           0 :         return 0;
    2916             : }
    2917             : 
    2918           0 : int config_parse_blockio_bandwidth(
    2919             :                 const char *unit,
    2920             :                 const char *filename,
    2921             :                 unsigned line,
    2922             :                 const char *section,
    2923             :                 unsigned section_line,
    2924             :                 const char *lvalue,
    2925             :                 int ltype,
    2926             :                 const char *rvalue,
    2927             :                 void *data,
    2928             :                 void *userdata) {
    2929             : 
    2930           0 :         _cleanup_free_ char *path = NULL;
    2931             :         CGroupBlockIODeviceBandwidth *b;
    2932           0 :         CGroupContext *c = data;
    2933             :         const char *bandwidth;
    2934             :         off_t bytes;
    2935             :         bool read;
    2936             :         size_t n;
    2937             :         int r;
    2938             : 
    2939           0 :         assert(filename);
    2940           0 :         assert(lvalue);
    2941           0 :         assert(rvalue);
    2942             : 
    2943           0 :         read = streq("BlockIOReadBandwidth", lvalue);
    2944             : 
    2945           0 :         if (isempty(rvalue)) {
    2946             :                 CGroupBlockIODeviceBandwidth *next;
    2947             : 
    2948           0 :                 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
    2949           0 :                         if (b->read == read)
    2950           0 :                                 cgroup_context_free_blockio_device_bandwidth(c, b);
    2951             : 
    2952           0 :                 return 0;
    2953             :         }
    2954             : 
    2955           0 :         n = strcspn(rvalue, WHITESPACE);
    2956           0 :         bandwidth = rvalue + n;
    2957           0 :         bandwidth += strspn(bandwidth, WHITESPACE);
    2958             : 
    2959           0 :         if (!*bandwidth) {
    2960           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2961             :                            "Expected space separated pair of device node and bandwidth. Ignoring.");
    2962           0 :                 return 0;
    2963             :         }
    2964             : 
    2965           0 :         path = strndup(rvalue, n);
    2966           0 :         if (!path)
    2967           0 :                 return log_oom();
    2968             : 
    2969           0 :         if (!path_startswith(path, "/dev")) {
    2970           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2971             :                            "Invalid device node path '%s'. Ignoring.", path);
    2972           0 :                 return 0;
    2973             :         }
    2974             : 
    2975           0 :         r = parse_size(bandwidth, 1000, &bytes);
    2976           0 :         if (r < 0 || bytes <= 0) {
    2977           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    2978             :                            "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
    2979           0 :                 return 0;
    2980             :         }
    2981             : 
    2982           0 :         b = new0(CGroupBlockIODeviceBandwidth, 1);
    2983           0 :         if (!b)
    2984           0 :                 return log_oom();
    2985             : 
    2986           0 :         b->path = path;
    2987           0 :         path = NULL;
    2988           0 :         b->bandwidth = (uint64_t) bytes;
    2989           0 :         b->read = read;
    2990             : 
    2991           0 :         LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
    2992             : 
    2993           0 :         return 0;
    2994             : }
    2995             : 
    2996           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
    2997             : 
    2998           0 : int config_parse_job_mode_isolate(
    2999             :                 const char *unit,
    3000             :                 const char *filename,
    3001             :                 unsigned line,
    3002             :                 const char *section,
    3003             :                 unsigned section_line,
    3004             :                 const char *lvalue,
    3005             :                 int ltype,
    3006             :                 const char *rvalue,
    3007             :                 void *data,
    3008             :                 void *userdata) {
    3009             : 
    3010           0 :         JobMode *m = data;
    3011             :         int r;
    3012             : 
    3013           0 :         assert(filename);
    3014           0 :         assert(lvalue);
    3015           0 :         assert(rvalue);
    3016             : 
    3017           0 :         r = parse_boolean(rvalue);
    3018           0 :         if (r < 0) {
    3019           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    3020             :                            "Failed to parse boolean, ignoring: %s", rvalue);
    3021           0 :                 return 0;
    3022             :         }
    3023             : 
    3024           0 :         *m = r ? JOB_ISOLATE : JOB_REPLACE;
    3025           0 :         return 0;
    3026             : }
    3027             : 
    3028           0 : int config_parse_personality(
    3029             :                 const char *unit,
    3030             :                 const char *filename,
    3031             :                 unsigned line,
    3032             :                 const char *section,
    3033             :                 unsigned section_line,
    3034             :                 const char *lvalue,
    3035             :                 int ltype,
    3036             :                 const char *rvalue,
    3037             :                 void *data,
    3038             :                 void *userdata) {
    3039             : 
    3040           0 :         unsigned long *personality = data, p;
    3041             : 
    3042           0 :         assert(filename);
    3043           0 :         assert(lvalue);
    3044           0 :         assert(rvalue);
    3045           0 :         assert(personality);
    3046             : 
    3047           0 :         p = personality_from_string(rvalue);
    3048           0 :         if (p == PERSONALITY_INVALID) {
    3049           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    3050             :                            "Failed to parse personality, ignoring: %s", rvalue);
    3051           0 :                 return 0;
    3052             :         }
    3053             : 
    3054           0 :         *personality = p;
    3055           0 :         return 0;
    3056             : }
    3057             : 
    3058           0 : int config_parse_runtime_directory(
    3059             :                 const char *unit,
    3060             :                 const char *filename,
    3061             :                 unsigned line,
    3062             :                 const char *section,
    3063             :                 unsigned section_line,
    3064             :                 const char *lvalue,
    3065             :                 int ltype,
    3066             :                 const char *rvalue,
    3067             :                 void *data,
    3068             :                 void *userdata) {
    3069             : 
    3070           0 :         char***rt = data;
    3071             :         const char *word, *state;
    3072             :         size_t l;
    3073             :         int r;
    3074             : 
    3075           0 :         assert(filename);
    3076           0 :         assert(lvalue);
    3077           0 :         assert(rvalue);
    3078           0 :         assert(data);
    3079             : 
    3080           0 :         if (isempty(rvalue)) {
    3081             :                 /* Empty assignment resets the list */
    3082           0 :                 strv_free(*rt);
    3083           0 :                 *rt = NULL;
    3084           0 :                 return 0;
    3085             :         }
    3086             : 
    3087           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    3088           0 :                 _cleanup_free_ char *n;
    3089             : 
    3090           0 :                 n = strndup(word, l);
    3091           0 :                 if (!n)
    3092           0 :                         return log_oom();
    3093             : 
    3094           0 :                 if (!filename_is_valid(n)) {
    3095           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    3096             :                                    "Runtime directory is not valid, ignoring assignment: %s", rvalue);
    3097           0 :                         continue;
    3098             :                 }
    3099             : 
    3100           0 :                 r = strv_push(rt, n);
    3101           0 :                 if (r < 0)
    3102           0 :                         return log_oom();
    3103             : 
    3104           0 :                 n = NULL;
    3105             :         }
    3106           0 :         if (!isempty(state))
    3107           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    3108             :                            "Trailing garbage, ignoring.");
    3109             : 
    3110           0 :         return 0;
    3111             : }
    3112             : 
    3113           0 : int config_parse_set_status(
    3114             :                 const char *unit,
    3115             :                 const char *filename,
    3116             :                 unsigned line,
    3117             :                 const char *section,
    3118             :                 unsigned section_line,
    3119             :                 const char *lvalue,
    3120             :                 int ltype,
    3121             :                 const char *rvalue,
    3122             :                 void *data,
    3123             :                 void *userdata) {
    3124             : 
    3125             :         size_t l;
    3126             :         const char *word, *state;
    3127             :         int r;
    3128           0 :         ExitStatusSet *status_set = data;
    3129             : 
    3130           0 :         assert(filename);
    3131           0 :         assert(lvalue);
    3132           0 :         assert(rvalue);
    3133           0 :         assert(data);
    3134             : 
    3135             :         /* Empty assignment resets the list */
    3136           0 :         if (isempty(rvalue)) {
    3137           0 :                 exit_status_set_free(status_set);
    3138           0 :                 return 0;
    3139             :         }
    3140             : 
    3141           0 :         FOREACH_WORD(word, l, rvalue, state) {
    3142           0 :                 _cleanup_free_ char *temp;
    3143             :                 int val;
    3144             :                 Set **set;
    3145             : 
    3146           0 :                 temp = strndup(word, l);
    3147           0 :                 if (!temp)
    3148           0 :                         return log_oom();
    3149             : 
    3150           0 :                 r = safe_atoi(temp, &val);
    3151           0 :                 if (r < 0) {
    3152           0 :                         val = signal_from_string_try_harder(temp);
    3153             : 
    3154           0 :                         if (val <= 0) {
    3155           0 :                                 log_syntax(unit, LOG_ERR, filename, line, -val,
    3156             :                                            "Failed to parse value, ignoring: %s", word);
    3157           0 :                                 continue;
    3158             :                         }
    3159           0 :                         set = &status_set->signal;
    3160             :                 } else {
    3161           0 :                         if (val < 0 || val > 255) {
    3162           0 :                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
    3163             :                                            "Value %d is outside range 0-255, ignoring", val);
    3164           0 :                                 continue;
    3165             :                         }
    3166           0 :                         set = &status_set->status;
    3167             :                 }
    3168             : 
    3169           0 :                 r = set_ensure_allocated(set, NULL);
    3170           0 :                 if (r < 0)
    3171           0 :                         return log_oom();
    3172             : 
    3173           0 :                 r = set_put(*set, INT_TO_PTR(val));
    3174           0 :                 if (r < 0) {
    3175           0 :                         log_syntax(unit, LOG_ERR, filename, line, -r,
    3176             :                                    "Unable to store: %s", word);
    3177           0 :                         return r;
    3178             :                 }
    3179             :         }
    3180           0 :         if (!isempty(state))
    3181           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    3182             :                            "Trailing garbage, ignoring.");
    3183             : 
    3184           0 :         return 0;
    3185             : }
    3186             : 
    3187           0 : int config_parse_namespace_path_strv(
    3188             :                 const char *unit,
    3189             :                 const char *filename,
    3190             :                 unsigned line,
    3191             :                 const char *section,
    3192             :                 unsigned section_line,
    3193             :                 const char *lvalue,
    3194             :                 int ltype,
    3195             :                 const char *rvalue,
    3196             :                 void *data,
    3197             :                 void *userdata) {
    3198             : 
    3199           0 :         char*** sv = data;
    3200             :         const char *word, *state;
    3201             :         size_t l;
    3202             :         int r;
    3203             : 
    3204           0 :         assert(filename);
    3205           0 :         assert(lvalue);
    3206           0 :         assert(rvalue);
    3207           0 :         assert(data);
    3208             : 
    3209           0 :         if (isempty(rvalue)) {
    3210             :                 /* Empty assignment resets the list */
    3211           0 :                 strv_free(*sv);
    3212           0 :                 *sv = NULL;
    3213           0 :                 return 0;
    3214             :         }
    3215             : 
    3216           0 :         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
    3217           0 :                 _cleanup_free_ char *n;
    3218             :                 int offset;
    3219             : 
    3220           0 :                 n = strndup(word, l);
    3221           0 :                 if (!n)
    3222           0 :                         return log_oom();
    3223             : 
    3224           0 :                 if (!utf8_is_valid(n)) {
    3225           0 :                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
    3226           0 :                         continue;
    3227             :                 }
    3228             : 
    3229           0 :                 offset = n[0] == '-';
    3230           0 :                 if (!path_is_absolute(n + offset)) {
    3231           0 :                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    3232             :                                    "Not an absolute path, ignoring: %s", rvalue);
    3233           0 :                         continue;
    3234             :                 }
    3235             : 
    3236           0 :                 path_kill_slashes(n);
    3237             : 
    3238           0 :                 r = strv_push(sv, n);
    3239           0 :                 if (r < 0)
    3240           0 :                         return log_oom();
    3241             : 
    3242           0 :                 n = NULL;
    3243             :         }
    3244           0 :         if (!isempty(state))
    3245           0 :                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
    3246             :                            "Trailing garbage, ignoring.");
    3247             : 
    3248           0 :         return 0;
    3249             : }
    3250             : 
    3251           0 : int config_parse_no_new_privileges(
    3252             :                 const char* unit,
    3253             :                 const char *filename,
    3254             :                 unsigned line,
    3255             :                 const char *section,
    3256             :                 unsigned section_line,
    3257             :                 const char *lvalue,
    3258             :                 int ltype,
    3259             :                 const char *rvalue,
    3260             :                 void *data,
    3261             :                 void *userdata) {
    3262             : 
    3263           0 :         ExecContext *c = data;
    3264             :         int k;
    3265             : 
    3266           0 :         assert(filename);
    3267           0 :         assert(lvalue);
    3268           0 :         assert(rvalue);
    3269           0 :         assert(data);
    3270             : 
    3271           0 :         k = parse_boolean(rvalue);
    3272           0 :         if (k < 0) {
    3273           0 :                 log_syntax(unit, LOG_ERR, filename, line, -k,
    3274             :                            "Failed to parse boolean value, ignoring: %s", rvalue);
    3275           0 :                 return 0;
    3276             :         }
    3277             : 
    3278           0 :         c->no_new_privileges = !!k;
    3279           0 :         c->no_new_privileges_set = true;
    3280             : 
    3281           0 :         return 0;
    3282             : }
    3283             : 
    3284           0 : int config_parse_protect_home(
    3285             :                 const char* unit,
    3286             :                 const char *filename,
    3287             :                 unsigned line,
    3288             :                 const char *section,
    3289             :                 unsigned section_line,
    3290             :                 const char *lvalue,
    3291             :                 int ltype,
    3292             :                 const char *rvalue,
    3293             :                 void *data,
    3294             :                 void *userdata) {
    3295             : 
    3296           0 :         ExecContext *c = data;
    3297             :         int k;
    3298             : 
    3299           0 :         assert(filename);
    3300           0 :         assert(lvalue);
    3301           0 :         assert(rvalue);
    3302           0 :         assert(data);
    3303             : 
    3304             :         /* Our enum shall be a superset of booleans, hence first try
    3305             :          * to parse as as boolean, and then as enum */
    3306             : 
    3307           0 :         k = parse_boolean(rvalue);
    3308           0 :         if (k > 0)
    3309           0 :                 c->protect_home = PROTECT_HOME_YES;
    3310           0 :         else if (k == 0)
    3311           0 :                 c->protect_home = PROTECT_HOME_NO;
    3312             :         else {
    3313             :                 ProtectHome h;
    3314             : 
    3315           0 :                 h = protect_home_from_string(rvalue);
    3316           0 :                 if (h < 0){
    3317           0 :                         log_syntax(unit, LOG_ERR, filename, line, -h,
    3318             :                                    "Failed to parse protect home value, ignoring: %s", rvalue);
    3319           0 :                         return 0;
    3320             :                 }
    3321             : 
    3322           0 :                 c->protect_home = h;
    3323             :         }
    3324             : 
    3325           0 :         return 0;
    3326             : }
    3327             : 
    3328           0 : int config_parse_protect_system(
    3329             :                 const char* unit,
    3330             :                 const char *filename,
    3331             :                 unsigned line,
    3332             :                 const char *section,
    3333             :                 unsigned section_line,
    3334             :                 const char *lvalue,
    3335             :                 int ltype,
    3336             :                 const char *rvalue,
    3337             :                 void *data,
    3338             :                 void *userdata) {
    3339             : 
    3340           0 :         ExecContext *c = data;
    3341             :         int k;
    3342             : 
    3343           0 :         assert(filename);
    3344           0 :         assert(lvalue);
    3345           0 :         assert(rvalue);
    3346           0 :         assert(data);
    3347             : 
    3348             :         /* Our enum shall be a superset of booleans, hence first try
    3349             :          * to parse as as boolean, and then as enum */
    3350             : 
    3351           0 :         k = parse_boolean(rvalue);
    3352           0 :         if (k > 0)
    3353           0 :                 c->protect_system = PROTECT_SYSTEM_YES;
    3354           0 :         else if (k == 0)
    3355           0 :                 c->protect_system = PROTECT_SYSTEM_NO;
    3356             :         else {
    3357             :                 ProtectSystem s;
    3358             : 
    3359           0 :                 s = protect_system_from_string(rvalue);
    3360           0 :                 if (s < 0){
    3361           0 :                         log_syntax(unit, LOG_ERR, filename, line, -s,
    3362             :                                    "Failed to parse protect system value, ignoring: %s", rvalue);
    3363           0 :                         return 0;
    3364             :                 }
    3365             : 
    3366           0 :                 c->protect_system = s;
    3367             :         }
    3368             : 
    3369           0 :         return 0;
    3370             : }
    3371             : 
    3372             : #define FOLLOW_MAX 8
    3373             : 
    3374          92 : static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
    3375          92 :         unsigned c = 0;
    3376             :         int fd, r;
    3377             :         FILE *f;
    3378          92 :         char *id = NULL;
    3379             : 
    3380          92 :         assert(filename);
    3381          92 :         assert(*filename);
    3382          92 :         assert(_f);
    3383          92 :         assert(names);
    3384             : 
    3385             :         /* This will update the filename pointer if the loaded file is
    3386             :          * reached by a symlink. The old string will be freed. */
    3387             : 
    3388             :         for (;;) {
    3389             :                 char *target, *name;
    3390             : 
    3391         158 :                 if (c++ >= FOLLOW_MAX)
    3392           0 :                         return -ELOOP;
    3393             : 
    3394         158 :                 path_kill_slashes(*filename);
    3395             : 
    3396             :                 /* Add the file name we are currently looking at to
    3397             :                  * the names of this unit, but only if it is a valid
    3398             :                  * unit name. */
    3399         158 :                 name = basename(*filename);
    3400             : 
    3401         158 :                 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
    3402             : 
    3403         158 :                         id = set_get(names, name);
    3404         158 :                         if (!id) {
    3405          98 :                                 id = strdup(name);
    3406          98 :                                 if (!id)
    3407           0 :                                         return -ENOMEM;
    3408             : 
    3409          98 :                                 r = set_consume(names, id);
    3410          98 :                                 if (r < 0)
    3411           0 :                                         return r;
    3412             :                         }
    3413             :                 }
    3414             : 
    3415             :                 /* Try to open the file name, but don't if its a symlink */
    3416         158 :                 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
    3417         158 :                 if (fd >= 0)
    3418          92 :                         break;
    3419             : 
    3420          66 :                 if (errno != ELOOP)
    3421           0 :                         return -errno;
    3422             : 
    3423             :                 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
    3424          66 :                 r = readlink_and_make_absolute(*filename, &target);
    3425          66 :                 if (r < 0)
    3426           0 :                         return r;
    3427             : 
    3428          66 :                 free(*filename);
    3429          66 :                 *filename = target;
    3430          66 :         }
    3431             : 
    3432          92 :         f = fdopen(fd, "re");
    3433          92 :         if (!f) {
    3434           0 :                 safe_close(fd);
    3435           0 :                 return -errno;
    3436             :         }
    3437             : 
    3438          92 :         *_f = f;
    3439          92 :         *_final = id;
    3440          92 :         return 0;
    3441             : }
    3442             : 
    3443          92 : static int merge_by_names(Unit **u, Set *names, const char *id) {
    3444             :         char *k;
    3445             :         int r;
    3446             : 
    3447          92 :         assert(u);
    3448          92 :         assert(*u);
    3449          92 :         assert(names);
    3450             : 
    3451             :         /* Let's try to add in all symlink names we found */
    3452         282 :         while ((k = set_steal_first(names))) {
    3453             : 
    3454             :                 /* First try to merge in the other name into our
    3455             :                  * unit */
    3456          98 :                 r = unit_merge_by_name(*u, k);
    3457          98 :                 if (r < 0) {
    3458             :                         Unit *other;
    3459             : 
    3460             :                         /* Hmm, we couldn't merge the other unit into
    3461             :                          * ours? Then let's try it the other way
    3462             :                          * round */
    3463             : 
    3464           0 :                         other = manager_get_unit((*u)->manager, k);
    3465           0 :                         free(k);
    3466             : 
    3467           0 :                         if (other) {
    3468           0 :                                 r = unit_merge(other, *u);
    3469           0 :                                 if (r >= 0) {
    3470           0 :                                         *u = other;
    3471           0 :                                         return merge_by_names(u, names, NULL);
    3472             :                                 }
    3473             :                         }
    3474             : 
    3475           0 :                         return r;
    3476             :                 }
    3477             : 
    3478          98 :                 if (id == k)
    3479          92 :                         unit_choose_id(*u, id);
    3480             : 
    3481          98 :                 free(k);
    3482             :         }
    3483             : 
    3484          92 :         return 0;
    3485             : }
    3486             : 
    3487         782 : static int load_from_path(Unit *u, const char *path) {
    3488             :         int r;
    3489        1564 :         _cleanup_set_free_free_ Set *symlink_names = NULL;
    3490        1564 :         _cleanup_fclose_ FILE *f = NULL;
    3491        1564 :         _cleanup_free_ char *filename = NULL;
    3492         782 :         char *id = NULL;
    3493             :         Unit *merged;
    3494             :         struct stat st;
    3495             : 
    3496         782 :         assert(u);
    3497         782 :         assert(path);
    3498             : 
    3499         782 :         symlink_names = set_new(&string_hash_ops);
    3500         782 :         if (!symlink_names)
    3501           0 :                 return -ENOMEM;
    3502             : 
    3503         782 :         if (path_is_absolute(path)) {
    3504             : 
    3505           0 :                 filename = strdup(path);
    3506           0 :                 if (!filename)
    3507           0 :                         return -ENOMEM;
    3508             : 
    3509           0 :                 r = open_follow(&filename, &f, symlink_names, &id);
    3510           0 :                 if (r < 0) {
    3511           0 :                         free(filename);
    3512           0 :                         filename = NULL;
    3513             : 
    3514           0 :                         if (r != -ENOENT)
    3515           0 :                                 return r;
    3516             :                 }
    3517             : 
    3518             :         } else  {
    3519             :                 char **p;
    3520             : 
    3521        2944 :                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
    3522             : 
    3523             :                         /* Instead of opening the path right away, we manually
    3524             :                          * follow all symlinks and add their name to our unit
    3525             :                          * name set while doing so */
    3526         782 :                         filename = path_make_absolute(path, *p);
    3527         782 :                         if (!filename)
    3528           0 :                                 return -ENOMEM;
    3529             : 
    3530        1564 :                         if (u->manager->unit_path_cache &&
    3531         782 :                             !set_get(u->manager->unit_path_cache, filename))
    3532         690 :                                 r = -ENOENT;
    3533             :                         else
    3534          92 :                                 r = open_follow(&filename, &f, symlink_names, &id);
    3535             : 
    3536         782 :                         if (r < 0) {
    3537         690 :                                 free(filename);
    3538         690 :                                 filename = NULL;
    3539             : 
    3540         690 :                                 if (r != -ENOENT)
    3541           0 :                                         return r;
    3542             : 
    3543             :                                 /* Empty the symlink names for the next run */
    3544         690 :                                 set_clear_free(symlink_names);
    3545         690 :                                 continue;
    3546             :                         }
    3547             : 
    3548          92 :                         break;
    3549             :                 }
    3550             :         }
    3551             : 
    3552         782 :         if (!filename)
    3553             :                 /* Hmm, no suitable file found? */
    3554         690 :                 return 0;
    3555             : 
    3556          92 :         merged = u;
    3557          92 :         r = merge_by_names(&merged, symlink_names, id);
    3558          92 :         if (r < 0)
    3559           0 :                 return r;
    3560             : 
    3561          92 :         if (merged != u) {
    3562           0 :                 u->load_state = UNIT_MERGED;
    3563           0 :                 return 0;
    3564             :         }
    3565             : 
    3566          92 :         if (fstat(fileno(f), &st) < 0)
    3567           0 :                 return -errno;
    3568             : 
    3569          92 :         if (null_or_empty(&st))
    3570           0 :                 u->load_state = UNIT_MASKED;
    3571             :         else {
    3572          92 :                 u->load_state = UNIT_LOADED;
    3573             : 
    3574             :                 /* Now, parse the file contents */
    3575          92 :                 r = config_parse(u->id, filename, f,
    3576          92 :                                  UNIT_VTABLE(u)->sections,
    3577             :                                  config_item_perf_lookup, load_fragment_gperf_lookup,
    3578             :                                  false, true, false, u);
    3579          92 :                 if (r < 0)
    3580           0 :                         return r;
    3581             :         }
    3582             : 
    3583          92 :         free(u->fragment_path);
    3584          92 :         u->fragment_path = filename;
    3585          92 :         filename = NULL;
    3586             : 
    3587          92 :         u->fragment_mtime = timespec_load(&st.st_mtim);
    3588             : 
    3589          92 :         if (u->source_path) {
    3590           0 :                 if (stat(u->source_path, &st) >= 0)
    3591           0 :                         u->source_mtime = timespec_load(&st.st_mtim);
    3592             :                 else
    3593           0 :                         u->source_mtime = 0;
    3594             :         }
    3595             : 
    3596          92 :         return 0;
    3597             : }
    3598             : 
    3599         782 : int unit_load_fragment(Unit *u) {
    3600             :         int r;
    3601             :         Iterator i;
    3602             :         const char *t;
    3603             : 
    3604         782 :         assert(u);
    3605         782 :         assert(u->load_state == UNIT_STUB);
    3606         782 :         assert(u->id);
    3607             : 
    3608             :         /* First, try to find the unit under its id. We always look
    3609             :          * for unit files in the default directories, to make it easy
    3610             :          * to override things by placing things in /etc/systemd/system */
    3611         782 :         r = load_from_path(u, u->id);
    3612         782 :         if (r < 0)
    3613           0 :                 return r;
    3614             : 
    3615             :         /* Try to find an alias we can load this with */
    3616         782 :         if (u->load_state == UNIT_STUB) {
    3617        2070 :                 SET_FOREACH(t, u->names, i) {
    3618             : 
    3619         690 :                         if (t == u->id)
    3620         690 :                                 continue;
    3621             : 
    3622           0 :                         r = load_from_path(u, t);
    3623           0 :                         if (r < 0)
    3624           0 :                                 return r;
    3625             : 
    3626           0 :                         if (u->load_state != UNIT_STUB)
    3627           0 :                                 break;
    3628             :                 }
    3629             :         }
    3630             : 
    3631             :         /* And now, try looking for it under the suggested (originally linked) path */
    3632         782 :         if (u->load_state == UNIT_STUB && u->fragment_path) {
    3633             : 
    3634           0 :                 r = load_from_path(u, u->fragment_path);
    3635           0 :                 if (r < 0)
    3636           0 :                         return r;
    3637             : 
    3638           0 :                 if (u->load_state == UNIT_STUB) {
    3639             :                         /* Hmm, this didn't work? Then let's get rid
    3640             :                          * of the fragment path stored for us, so that
    3641             :                          * we don't point to an invalid location. */
    3642           0 :                         free(u->fragment_path);
    3643           0 :                         u->fragment_path = NULL;
    3644             :                 }
    3645             :         }
    3646             : 
    3647             :         /* Look for a template */
    3648         782 :         if (u->load_state == UNIT_STUB && u->instance) {
    3649           0 :                 _cleanup_free_ char *k = NULL;
    3650             : 
    3651           0 :                 r = unit_name_template(u->id, &k);
    3652           0 :                 if (r < 0)
    3653           0 :                         return r;
    3654             : 
    3655           0 :                 r = load_from_path(u, k);
    3656           0 :                 if (r < 0)
    3657           0 :                         return r;
    3658             : 
    3659           0 :                 if (u->load_state == UNIT_STUB) {
    3660           0 :                         SET_FOREACH(t, u->names, i) {
    3661           0 :                                 _cleanup_free_ char *z = NULL;
    3662             : 
    3663           0 :                                 if (t == u->id)
    3664           0 :                                         continue;
    3665             : 
    3666           0 :                                 r = unit_name_template(t, &z);
    3667           0 :                                 if (r < 0)
    3668           0 :                                         return r;
    3669             : 
    3670           0 :                                 r = load_from_path(u, z);
    3671           0 :                                 if (r < 0)
    3672           0 :                                         return r;
    3673             : 
    3674           0 :                                 if (u->load_state != UNIT_STUB)
    3675           0 :                                         break;
    3676             :                         }
    3677             :                 }
    3678             :         }
    3679             : 
    3680         782 :         return 0;
    3681             : }
    3682             : 
    3683           0 : void unit_dump_config_items(FILE *f) {
    3684             :         static const struct {
    3685             :                 const ConfigParserCallback callback;
    3686             :                 const char *rvalue;
    3687             :         } table[] = {
    3688             : #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
    3689             :                 { config_parse_warn_compat,           "NOTSUPPORTED" },
    3690             : #endif
    3691             :                 { config_parse_int,                   "INTEGER" },
    3692             :                 { config_parse_unsigned,              "UNSIGNED" },
    3693             :                 { config_parse_iec_size,              "SIZE" },
    3694             :                 { config_parse_iec_off,               "SIZE" },
    3695             :                 { config_parse_si_size,               "SIZE" },
    3696             :                 { config_parse_bool,                  "BOOLEAN" },
    3697             :                 { config_parse_string,                "STRING" },
    3698             :                 { config_parse_path,                  "PATH" },
    3699             :                 { config_parse_unit_path_printf,      "PATH" },
    3700             :                 { config_parse_strv,                  "STRING [...]" },
    3701             :                 { config_parse_exec_nice,             "NICE" },
    3702             :                 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
    3703             :                 { config_parse_exec_io_class,         "IOCLASS" },
    3704             :                 { config_parse_exec_io_priority,      "IOPRIORITY" },
    3705             :                 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
    3706             :                 { config_parse_exec_cpu_sched_prio,   "CPUSCHEDPRIO" },
    3707             :                 { config_parse_exec_cpu_affinity,     "CPUAFFINITY" },
    3708             :                 { config_parse_mode,                  "MODE" },
    3709             :                 { config_parse_unit_env_file,         "FILE" },
    3710             :                 { config_parse_output,                "OUTPUT" },
    3711             :                 { config_parse_input,                 "INPUT" },
    3712             :                 { config_parse_log_facility,          "FACILITY" },
    3713             :                 { config_parse_log_level,             "LEVEL" },
    3714             :                 { config_parse_exec_capabilities,     "CAPABILITIES" },
    3715             :                 { config_parse_exec_secure_bits,      "SECUREBITS" },
    3716             :                 { config_parse_bounding_set,          "BOUNDINGSET" },
    3717             :                 { config_parse_limit,                 "LIMIT" },
    3718             :                 { config_parse_unit_deps,             "UNIT [...]" },
    3719             :                 { config_parse_exec,                  "PATH [ARGUMENT [...]]" },
    3720             :                 { config_parse_service_type,          "SERVICETYPE" },
    3721             :                 { config_parse_service_restart,       "SERVICERESTART" },
    3722             : #ifdef HAVE_SYSV_COMPAT
    3723             :                 { config_parse_sysv_priority,         "SYSVPRIORITY" },
    3724             : #endif
    3725             :                 { config_parse_kill_mode,             "KILLMODE" },
    3726             :                 { config_parse_kill_signal,           "SIGNAL" },
    3727             :                 { config_parse_socket_listen,         "SOCKET [...]" },
    3728             :                 { config_parse_socket_bind,           "SOCKETBIND" },
    3729             :                 { config_parse_socket_bindtodevice,   "NETWORKINTERFACE" },
    3730             :                 { config_parse_sec,                   "SECONDS" },
    3731             :                 { config_parse_nsec,                  "NANOSECONDS" },
    3732             :                 { config_parse_namespace_path_strv,   "PATH [...]" },
    3733             :                 { config_parse_unit_requires_mounts_for, "PATH [...]" },
    3734             :                 { config_parse_exec_mount_flags,      "MOUNTFLAG [...]" },
    3735             :                 { config_parse_unit_string_printf,    "STRING" },
    3736             :                 { config_parse_trigger_unit,          "UNIT" },
    3737             :                 { config_parse_timer,                 "TIMER" },
    3738             :                 { config_parse_path_spec,             "PATH" },
    3739             :                 { config_parse_notify_access,         "ACCESS" },
    3740             :                 { config_parse_ip_tos,                "TOS" },
    3741             :                 { config_parse_unit_condition_path,   "CONDITION" },
    3742             :                 { config_parse_unit_condition_string, "CONDITION" },
    3743             :                 { config_parse_unit_condition_null,   "CONDITION" },
    3744             :                 { config_parse_unit_slice,            "SLICE" },
    3745             :                 { config_parse_documentation,         "URL" },
    3746             :                 { config_parse_service_timeout,       "SECONDS" },
    3747             :                 { config_parse_failure_action,        "ACTION" },
    3748             :                 { config_parse_set_status,            "STATUS" },
    3749             :                 { config_parse_service_sockets,       "SOCKETS" },
    3750             :                 { config_parse_environ,               "ENVIRON" },
    3751             : #ifdef HAVE_SECCOMP
    3752             :                 { config_parse_syscall_filter,        "SYSCALLS" },
    3753             :                 { config_parse_syscall_archs,         "ARCHS" },
    3754             :                 { config_parse_syscall_errno,         "ERRNO" },
    3755             :                 { config_parse_address_families,      "FAMILIES" },
    3756             : #endif
    3757             :                 { config_parse_cpu_shares,            "SHARES" },
    3758             :                 { config_parse_memory_limit,          "LIMIT" },
    3759             :                 { config_parse_device_allow,          "DEVICE" },
    3760             :                 { config_parse_device_policy,         "POLICY" },
    3761             :                 { config_parse_blockio_bandwidth,     "BANDWIDTH" },
    3762             :                 { config_parse_blockio_weight,        "WEIGHT" },
    3763             :                 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
    3764             :                 { config_parse_long,                  "LONG" },
    3765             :                 { config_parse_socket_service,        "SERVICE" },
    3766             : #ifdef HAVE_SELINUX
    3767             :                 { config_parse_exec_selinux_context,  "LABEL" },
    3768             : #endif
    3769             :                 { config_parse_job_mode,              "MODE" },
    3770             :                 { config_parse_job_mode_isolate,      "BOOLEAN" },
    3771             :                 { config_parse_personality,           "PERSONALITY" },
    3772             :         };
    3773             : 
    3774           0 :         const char *prev = NULL;
    3775             :         const char *i;
    3776             : 
    3777           0 :         assert(f);
    3778             : 
    3779           0 :         NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
    3780           0 :                 const char *rvalue = "OTHER", *lvalue;
    3781             :                 unsigned j;
    3782             :                 size_t prefix_len;
    3783             :                 const char *dot;
    3784             :                 const ConfigPerfItem *p;
    3785             : 
    3786           0 :                 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
    3787             : 
    3788           0 :                 dot = strchr(i, '.');
    3789           0 :                 lvalue = dot ? dot + 1 : i;
    3790           0 :                 prefix_len = dot-i;
    3791             : 
    3792           0 :                 if (dot)
    3793           0 :                         if (!prev || !strneq(prev, i, prefix_len+1)) {
    3794           0 :                                 if (prev)
    3795           0 :                                         fputc('\n', f);
    3796             : 
    3797           0 :                                 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
    3798             :                         }
    3799             : 
    3800           0 :                 for (j = 0; j < ELEMENTSOF(table); j++)
    3801           0 :                         if (p->parse == table[j].callback) {
    3802           0 :                                 rvalue = table[j].rvalue;
    3803           0 :                                 break;
    3804             :                         }
    3805             : 
    3806           0 :                 fprintf(f, "%s=%s\n", lvalue, rvalue);
    3807           0 :                 prev = i;
    3808             :         }
    3809           0 : }

Generated by: LCOV version 1.11