chiark / gitweb /
man: don't document ".include" in configuration files anymore as first step to deprec...
[elogind.git] / src / shared / conf-parser.c
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
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <netinet/ether.h>
28
29 #include "conf-parser.h"
30 #include "util.h"
31 #include "macro.h"
32 #include "strv.h"
33 #include "log.h"
34 #include "utf8.h"
35 #include "path-util.h"
36 #include "set.h"
37 #include "exit-status.h"
38 #include "sd-messages.h"
39
40 int log_syntax_internal(const char *unit, int level,
41                         const char *file, unsigned line, const char *func,
42                         const char *config_file, unsigned config_line,
43                         int error, const char *format, ...) {
44
45         _cleanup_free_ char *msg = NULL;
46         int r;
47         va_list ap;
48
49         va_start(ap, format);
50         r = vasprintf(&msg, format, ap);
51         va_end(ap);
52         if (r < 0)
53                 return log_oom();
54
55         if (unit)
56                 r = log_struct_internal(level,
57                                         file, line, func,
58                                         getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
59                                         MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
60                                         "CONFIG_FILE=%s", config_file,
61                                         "CONFIG_LINE=%u", config_line,
62                                         "ERRNO=%d", error > 0 ? error : EINVAL,
63                                         "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
64                                         NULL);
65         else
66                 r = log_struct_internal(level,
67                                         file, line, func,
68                                         MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
69                                         "CONFIG_FILE=%s", config_file,
70                                         "CONFIG_LINE=%u", config_line,
71                                         "ERRNO=%d", error > 0 ? error : EINVAL,
72                                         "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
73                                         NULL);
74
75         return r;
76 }
77
78 int config_item_table_lookup(
79                 void *table,
80                 const char *section,
81                 const char *lvalue,
82                 ConfigParserCallback *func,
83                 int *ltype,
84                 void **data,
85                 void *userdata) {
86
87         ConfigTableItem *t;
88
89         assert(table);
90         assert(lvalue);
91         assert(func);
92         assert(ltype);
93         assert(data);
94
95         for (t = table; t->lvalue; t++) {
96
97                 if (!streq(lvalue, t->lvalue))
98                         continue;
99
100                 if (!streq_ptr(section, t->section))
101                         continue;
102
103                 *func = t->parse;
104                 *ltype = t->ltype;
105                 *data = t->data;
106                 return 1;
107         }
108
109         return 0;
110 }
111
112 int config_item_perf_lookup(
113                 void *table,
114                 const char *section,
115                 const char *lvalue,
116                 ConfigParserCallback *func,
117                 int *ltype,
118                 void **data,
119                 void *userdata) {
120
121         ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
122         const ConfigPerfItem *p;
123
124         assert(table);
125         assert(lvalue);
126         assert(func);
127         assert(ltype);
128         assert(data);
129
130         if (!section)
131                 p = lookup(lvalue, strlen(lvalue));
132         else {
133                 char *key;
134
135                 key = strjoin(section, ".", lvalue, NULL);
136                 if (!key)
137                         return -ENOMEM;
138
139                 p = lookup(key, strlen(key));
140                 free(key);
141         }
142
143         if (!p)
144                 return 0;
145
146         *func = p->parse;
147         *ltype = p->ltype;
148         *data = (uint8_t*) userdata + p->offset;
149         return 1;
150 }
151
152 /* Run the user supplied parser for an assignment */
153 static int next_assignment(const char *unit,
154                            const char *filename,
155                            unsigned line,
156                            ConfigItemLookup lookup,
157                            void *table,
158                            const char *section,
159                            unsigned section_line,
160                            const char *lvalue,
161                            const char *rvalue,
162                            bool relaxed,
163                            void *userdata) {
164
165         ConfigParserCallback func = NULL;
166         int ltype = 0;
167         void *data = NULL;
168         int r;
169
170         assert(filename);
171         assert(line > 0);
172         assert(lookup);
173         assert(lvalue);
174         assert(rvalue);
175
176         r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
177         if (r < 0)
178                 return r;
179
180         if (r > 0) {
181                 if (func)
182                         return func(unit, filename, line, section, section_line,
183                                     lvalue, ltype, rvalue, data, userdata);
184
185                 return 0;
186         }
187
188         /* Warn about unknown non-extension fields. */
189         if (!relaxed && !startswith(lvalue, "X-"))
190                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
191                            "Unknown lvalue '%s' in section '%s'", lvalue, section);
192
193         return 0;
194 }
195
196 /* Parse a variable assignment line */
197 static int parse_line(const char* unit,
198                       const char *filename,
199                       unsigned line,
200                       const char *sections,
201                       ConfigItemLookup lookup,
202                       void *table,
203                       bool relaxed,
204                       bool allow_include,
205                       char **section,
206                       unsigned *section_line,
207                       char *l,
208                       void *userdata) {
209
210         char *e;
211
212         assert(filename);
213         assert(line > 0);
214         assert(lookup);
215         assert(l);
216
217         l = strstrip(l);
218
219         if (!*l)
220                 return 0;
221
222         if (strchr(COMMENTS "\n", *l))
223                 return 0;
224
225         if (startswith(l, ".include ")) {
226                 _cleanup_free_ char *fn = NULL;
227
228                 /* .includes are a bad idea, we only support them here
229                  * for historical reasons. They create cyclic include
230                  * problems and make it difficult to detect
231                  * configuration file changes with an easy
232                  * stat(). Better approaches, such as .d/ drop-in
233                  * snippets exist.
234                  *
235                  * Support for them should be eventually removed. */
236
237                 if (!allow_include) {
238                         log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
239                                    ".include not allowed here. Ignoring.");
240                         return 0;
241                 }
242
243                 fn = file_in_same_dir(filename, strstrip(l+9));
244                 if (!fn)
245                         return -ENOMEM;
246
247                 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
248         }
249
250         if (*l == '[') {
251                 size_t k;
252                 char *n;
253
254                 k = strlen(l);
255                 assert(k > 0);
256
257                 if (l[k-1] != ']') {
258                         log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
259                                    "Invalid section header '%s'", l);
260                         return -EBADMSG;
261                 }
262
263                 n = strndup(l+1, k-2);
264                 if (!n)
265                         return -ENOMEM;
266
267                 if (sections && !nulstr_contains(sections, n)) {
268
269                         if (!relaxed)
270                                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
271                                            "Unknown section '%s'. Ignoring.", n);
272
273                         free(n);
274                         free(*section);
275                         *section = NULL;
276                         *section_line = 0;
277                 } else {
278                         free(*section);
279                         *section = n;
280                         *section_line = line;
281                 }
282
283                 return 0;
284         }
285
286         if (sections && !*section) {
287
288                 if (!relaxed)
289                         log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
290                                    "Assignment outside of section. Ignoring.");
291
292                 return 0;
293         }
294
295         e = strchr(l, '=');
296         if (!e) {
297                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
298                 return -EBADMSG;
299         }
300
301         *e = 0;
302         e++;
303
304         return next_assignment(unit,
305                                filename,
306                                line,
307                                lookup,
308                                table,
309                                *section,
310                                *section_line,
311                                strstrip(l),
312                                strstrip(e),
313                                relaxed,
314                                userdata);
315 }
316
317 /* Go through the file and parse each line */
318 int config_parse(const char *unit,
319                  const char *filename,
320                  FILE *f,
321                  const char *sections,
322                  ConfigItemLookup lookup,
323                  void *table,
324                  bool relaxed,
325                  bool allow_include,
326                  void *userdata) {
327
328         _cleanup_free_ char *section = NULL, *continuation = NULL;
329         _cleanup_fclose_ FILE *ours = NULL;
330         unsigned line = 0, section_line = 0;
331         int r;
332
333         assert(filename);
334         assert(lookup);
335
336         if (!f) {
337                 f = ours = fopen(filename, "re");
338                 if (!f) {
339                         log_error("Failed to open configuration file '%s': %m", filename);
340                         return -errno;
341                 }
342         }
343
344         fd_warn_permissions(filename, fileno(f));
345
346         while (!feof(f)) {
347                 char l[LINE_MAX], *p, *c = NULL, *e;
348                 bool escaped = false;
349
350                 if (!fgets(l, sizeof(l), f)) {
351                         if (feof(f))
352                                 break;
353
354                         log_error("Failed to read configuration file '%s': %m", filename);
355                         return -errno;
356                 }
357
358                 truncate_nl(l);
359
360                 if (continuation) {
361                         c = strappend(continuation, l);
362                         if (!c)
363                                 return -ENOMEM;
364
365                         free(continuation);
366                         continuation = NULL;
367                         p = c;
368                 } else
369                         p = l;
370
371                 for (e = p; *e; e++) {
372                         if (escaped)
373                                 escaped = false;
374                         else if (*e == '\\')
375                                 escaped = true;
376                 }
377
378                 if (escaped) {
379                         *(e-1) = ' ';
380
381                         if (c)
382                                 continuation = c;
383                         else {
384                                 continuation = strdup(l);
385                                 if (!continuation)
386                                         return -ENOMEM;
387                         }
388
389                         continue;
390                 }
391
392                 r = parse_line(unit,
393                                filename,
394                                ++line,
395                                sections,
396                                lookup,
397                                table,
398                                relaxed,
399                                allow_include,
400                                &section,
401                                &section_line,
402                                p,
403                                userdata);
404                 free(c);
405
406                 if (r < 0)
407                         return r;
408         }
409
410         return 0;
411 }
412
413 #define DEFINE_PARSER(type, vartype, conv_func)                         \
414         int config_parse_##type(const char *unit,                       \
415                                 const char *filename,                   \
416                                 unsigned line,                          \
417                                 const char *section,                    \
418                                 unsigned section_line,                  \
419                                 const char *lvalue,                     \
420                                 int ltype,                              \
421                                 const char *rvalue,                     \
422                                 void *data,                             \
423                                 void *userdata) {                       \
424                                                                         \
425                 vartype *i = data;                                      \
426                 int r;                                                  \
427                                                                         \
428                 assert(filename);                                       \
429                 assert(lvalue);                                         \
430                 assert(rvalue);                                         \
431                 assert(data);                                           \
432                                                                         \
433                 r = conv_func(rvalue, i);                               \
434                 if (r < 0)                                              \
435                         log_syntax(unit, LOG_ERR, filename, line, -r,   \
436                                    "Failed to parse %s value, ignoring: %s", \
437                                    #vartype, rvalue);                   \
438                                                                         \
439                 return 0;                                               \
440         }
441
442 DEFINE_PARSER(int, int, safe_atoi)
443 DEFINE_PARSER(long, long, safe_atoli)
444 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
445 DEFINE_PARSER(unsigned, unsigned, safe_atou)
446 DEFINE_PARSER(double, double, safe_atod)
447 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
448 DEFINE_PARSER(sec, usec_t, parse_sec)
449
450
451 int config_parse_bytes_size(const char* unit,
452                             const char *filename,
453                             unsigned line,
454                             const char *section,
455                             unsigned section_line,
456                             const char *lvalue,
457                             int ltype,
458                             const char *rvalue,
459                             void *data,
460                             void *userdata) {
461
462         size_t *sz = data;
463         off_t o;
464         int r;
465
466         assert(filename);
467         assert(lvalue);
468         assert(rvalue);
469         assert(data);
470
471         r = parse_bytes(rvalue, &o);
472         if (r < 0 || (off_t) (size_t) o != o) {
473                 log_syntax(unit, LOG_ERR, filename, line, -r,
474                            "Failed to parse byte value, ignoring: %s", rvalue);
475                 return 0;
476         }
477
478         *sz = (size_t) o;
479         return 0;
480 }
481
482
483 int config_parse_bytes_off(const char* unit,
484                            const char *filename,
485                            unsigned line,
486                            const char *section,
487                            unsigned section_line,
488                            const char *lvalue,
489                            int ltype,
490                            const char *rvalue,
491                            void *data,
492                            void *userdata) {
493
494         off_t *bytes = data;
495         int r;
496
497         assert(filename);
498         assert(lvalue);
499         assert(rvalue);
500         assert(data);
501
502         assert_cc(sizeof(off_t) == sizeof(uint64_t));
503
504         r = parse_bytes(rvalue, bytes);
505         if (r < 0)
506                 log_syntax(unit, LOG_ERR, filename, line, -r,
507                            "Failed to parse bytes value, ignoring: %s", rvalue);
508
509         return 0;
510 }
511
512 int config_parse_bool(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         int k;
524         bool *b = data;
525
526         assert(filename);
527         assert(lvalue);
528         assert(rvalue);
529         assert(data);
530
531         k = parse_boolean(rvalue);
532         if (k < 0) {
533                 log_syntax(unit, LOG_ERR, filename, line, -k,
534                            "Failed to parse boolean value, ignoring: %s", rvalue);
535                 return 0;
536         }
537
538         *b = !!k;
539         return 0;
540 }
541
542 int config_parse_show_status(const char* unit,
543                              const char *filename,
544                              unsigned line,
545                              const char *section,
546                              unsigned section_line,
547                              const char *lvalue,
548                              int ltype,
549                              const char *rvalue,
550                              void *data,
551                              void *userdata) {
552
553         int k;
554         ShowStatus *b = data;
555
556         assert(filename);
557         assert(lvalue);
558         assert(rvalue);
559         assert(data);
560
561         k = parse_show_status(rvalue, b);
562         if (k < 0) {
563                 log_syntax(unit, LOG_ERR, filename, line, -k,
564                            "Failed to parse show status setting, ignoring: %s", rvalue);
565                 return 0;
566         }
567
568         return 0;
569 }
570
571 int config_parse_string(const char *unit,
572                         const char *filename,
573                         unsigned line,
574                         const char *section,
575                         unsigned section_line,
576                         const char *lvalue,
577                         int ltype,
578                         const char *rvalue,
579                         void *data,
580                         void *userdata) {
581
582         char **s = data;
583         char *n;
584
585         assert(filename);
586         assert(lvalue);
587         assert(rvalue);
588         assert(data);
589
590         n = strdup(rvalue);
591         if (!n)
592                 return log_oom();
593
594         if (!utf8_is_valid(n)) {
595                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
596                            "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
597                 free(n);
598                 return 0;
599         }
600
601         free(*s);
602         if (*n)
603                 *s = n;
604         else {
605                 free(n);
606                 *s = NULL;
607         }
608
609         return 0;
610 }
611
612 int config_parse_path(const char *unit,
613                       const char *filename,
614                       unsigned line,
615                       const char *section,
616                       unsigned section_line,
617                       const char *lvalue,
618                       int ltype,
619                       const char *rvalue,
620                       void *data,
621                       void *userdata) {
622
623         char **s = data;
624         char *n;
625         int offset;
626
627         assert(filename);
628         assert(lvalue);
629         assert(rvalue);
630         assert(data);
631
632         if (!utf8_is_valid(rvalue)) {
633                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
634                            "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
635                 return 0;
636         }
637
638         offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
639                                       streq(lvalue, "ReadOnlyDirectories"));
640         if (!path_is_absolute(rvalue + offset)) {
641                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
642                            "Not an absolute path, ignoring: %s", rvalue);
643                 return 0;
644         }
645
646         n = strdup(rvalue);
647         if (!n)
648                 return log_oom();
649
650         path_kill_slashes(n);
651
652         free(*s);
653         *s = n;
654
655         return 0;
656 }
657
658 int config_parse_strv(const char *unit,
659                       const char *filename,
660                       unsigned line,
661                       const char *section,
662                       unsigned section_line,
663                       const char *lvalue,
664                       int ltype,
665                       const char *rvalue,
666                       void *data,
667                       void *userdata) {
668
669         char *** sv = data, *w, *state;
670         size_t l;
671         int r;
672
673         assert(filename);
674         assert(lvalue);
675         assert(rvalue);
676         assert(data);
677
678         if (isempty(rvalue)) {
679                 char **empty;
680
681                 /* Empty assignment resets the list. As a special rule
682                  * we actually fill in a real empty array here rather
683                  * than NULL, since some code wants to know if
684                  * something was set at all... */
685                 empty = strv_new(NULL, NULL);
686                 if (!empty)
687                         return log_oom();
688
689                 strv_free(*sv);
690                 *sv = empty;
691                 return 0;
692         }
693
694         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
695                 _cleanup_free_ char *n;
696
697                 n = cunescape_length(w, l);
698                 if (!n)
699                         return log_oom();
700
701                 if (!utf8_is_valid(n)) {
702                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
703                                    "String is not UTF-8 clean, ignoring: %s", rvalue);
704                         continue;
705                 }
706
707                 r = strv_extend(sv, n);
708                 if (r < 0)
709                         return log_oom();
710         }
711
712         return 0;
713 }
714
715 int config_parse_path_strv(const char *unit,
716                            const char *filename,
717                            unsigned line,
718                            const char *section,
719                            unsigned section_line,
720                            const char *lvalue,
721                            int ltype,
722                            const char *rvalue,
723                            void *data,
724                            void *userdata) {
725
726         char*** sv = data, *w, *state;
727         size_t l;
728         int r;
729
730         assert(filename);
731         assert(lvalue);
732         assert(rvalue);
733         assert(data);
734
735         if (isempty(rvalue)) {
736                 /* Empty assignment resets the list */
737                 strv_free(*sv);
738                 *sv = NULL;
739                 return 0;
740         }
741
742         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
743                 _cleanup_free_ char *n;
744                 int offset;
745
746                 n = strndup(w, l);
747                 if (!n)
748                         return log_oom();
749
750                 if (!utf8_is_valid(n)) {
751                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
752                                    "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
753                         continue;
754                 }
755
756                 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
757                                          streq(lvalue, "ReadOnlyDirectories"));
758                 if (!path_is_absolute(n + offset)) {
759                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
760                                    "Not an absolute path, ignoring: %s", rvalue);
761                         continue;
762                 }
763
764                 path_kill_slashes(n);
765                 r = strv_extend(sv, n);
766                 if (r < 0)
767                         return log_oom();
768         }
769
770         return 0;
771 }
772
773 int config_parse_mode(const char *unit,
774                       const char *filename,
775                       unsigned line,
776                       const char *section,
777                       unsigned section_line,
778                       const char *lvalue,
779                       int ltype,
780                       const char *rvalue,
781                       void *data,
782                       void *userdata) {
783
784         mode_t *m = data;
785         long l;
786         char *x = NULL;
787
788         assert(filename);
789         assert(lvalue);
790         assert(rvalue);
791         assert(data);
792
793         errno = 0;
794         l = strtol(rvalue, &x, 8);
795         if (!x || x == rvalue || *x || errno) {
796                 log_syntax(unit, LOG_ERR, filename, line, errno,
797                            "Failed to parse mode value, ignoring: %s", rvalue);
798                 return 0;
799         }
800
801         if (l < 0000 || l > 07777) {
802                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
803                            "Mode value out of range, ignoring: %s", rvalue);
804                 return 0;
805         }
806
807         *m = (mode_t) l;
808         return 0;
809 }
810
811 int config_parse_facility(const char *unit,
812                           const char *filename,
813                           unsigned line,
814                           const char *section,
815                           unsigned section_line,
816                           const char *lvalue,
817                           int ltype,
818                           const char *rvalue,
819                           void *data,
820                           void *userdata) {
821
822
823         int *o = data, x;
824
825         assert(filename);
826         assert(lvalue);
827         assert(rvalue);
828         assert(data);
829
830         x = log_facility_unshifted_from_string(rvalue);
831         if (x < 0) {
832                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
833                            "Failed to parse log facility, ignoring: %s", rvalue);
834                 return 0;
835         }
836
837         *o = (x << 3) | LOG_PRI(*o);
838
839         return 0;
840 }
841
842 int config_parse_level(const char *unit,
843                        const char *filename,
844                        unsigned line,
845                        const char *section,
846                        unsigned section_line,
847                        const char *lvalue,
848                        int ltype,
849                        const char *rvalue,
850                        void *data,
851                        void *userdata) {
852
853
854         int *o = data, x;
855
856         assert(filename);
857         assert(lvalue);
858         assert(rvalue);
859         assert(data);
860
861         x = log_level_from_string(rvalue);
862         if (x < 0) {
863                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
864                            "Failed to parse log level, ignoring: %s", rvalue);
865                 return 0;
866         }
867
868         *o = (*o & LOG_FACMASK) | x;
869         return 0;
870 }
871
872 int config_parse_set_status(const char *unit,
873                             const char *filename,
874                             unsigned line,
875                             const char *section,
876                             unsigned section_line,
877                             const char *lvalue,
878                             int ltype,
879                             const char *rvalue,
880                             void *data,
881                             void *userdata) {
882
883         char *w;
884         size_t l;
885         char *state;
886         int r;
887         ExitStatusSet *status_set = data;
888
889         assert(filename);
890         assert(lvalue);
891         assert(rvalue);
892         assert(data);
893
894         if (isempty(rvalue)) {
895                 /* Empty assignment resets the list */
896
897                 set_free(status_set->signal);
898                 set_free(status_set->code);
899
900                 status_set->signal = status_set->code = NULL;
901                 return 0;
902         }
903
904         FOREACH_WORD(w, l, rvalue, state) {
905                 int val;
906                 char *temp;
907
908                 temp = strndup(w, l);
909                 if (!temp)
910                         return log_oom();
911
912                 r = safe_atoi(temp, &val);
913                 if (r < 0) {
914                         val = signal_from_string_try_harder(temp);
915                         free(temp);
916
917                         if (val > 0) {
918                                 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
919                                 if (r < 0)
920                                         return log_oom();
921
922                                 r = set_put(status_set->signal, INT_TO_PTR(val));
923                                 if (r < 0) {
924                                         log_syntax(unit, LOG_ERR, filename, line, -r,
925                                                    "Unable to store: %s", w);
926                                         return r;
927                                 }
928                         } else {
929                                 log_syntax(unit, LOG_ERR, filename, line, -val,
930                                            "Failed to parse value, ignoring: %s", w);
931                                 return 0;
932                         }
933                 } else {
934                         free(temp);
935
936                         if (val < 0 || val > 255)
937                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
938                                            "Value %d is outside range 0-255, ignoring", val);
939                         else {
940                                 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
941                                 if (r < 0)
942                                         return log_oom();
943
944                                 r = set_put(status_set->code, INT_TO_PTR(val));
945                                 if (r < 0) {
946                                         log_syntax(unit, LOG_ERR, filename, line, -r,
947                                                    "Unable to store: %s", w);
948                                         return r;
949                                 }
950                         }
951                 }
952         }
953
954         return 0;
955 }