chiark / gitweb /
df4e961ea03925c474dd86e7e1dddc2297f59385
[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                 if (!allow_include) {
229                         log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
230                                    ".include not allowed here. Ignoring.");
231                         return 0;
232                 }
233
234                 fn = file_in_same_dir(filename, strstrip(l+9));
235                 if (!fn)
236                         return -ENOMEM;
237
238                 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata);
239         }
240
241         if (*l == '[') {
242                 size_t k;
243                 char *n;
244
245                 k = strlen(l);
246                 assert(k > 0);
247
248                 if (l[k-1] != ']') {
249                         log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
250                                    "Invalid section header '%s'", l);
251                         return -EBADMSG;
252                 }
253
254                 n = strndup(l+1, k-2);
255                 if (!n)
256                         return -ENOMEM;
257
258                 if (sections && !nulstr_contains(sections, n)) {
259
260                         if (!relaxed)
261                                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
262                                            "Unknown section '%s'. Ignoring.", n);
263
264                         free(n);
265                         free(*section);
266                         *section = NULL;
267                         *section_line = 0;
268                 } else {
269                         free(*section);
270                         *section = n;
271                         *section_line = line;
272                 }
273
274                 return 0;
275         }
276
277         if (sections && !*section) {
278
279                 if (!relaxed)
280                         log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
281                                    "Assignment outside of section. Ignoring.");
282
283                 return 0;
284         }
285
286         e = strchr(l, '=');
287         if (!e) {
288                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
289                 return -EBADMSG;
290         }
291
292         *e = 0;
293         e++;
294
295         return next_assignment(unit,
296                                filename,
297                                line,
298                                lookup,
299                                table,
300                                *section,
301                                *section_line,
302                                strstrip(l),
303                                strstrip(e),
304                                relaxed,
305                                userdata);
306 }
307
308 /* Go through the file and parse each line */
309 int config_parse(const char *unit,
310                  const char *filename,
311                  FILE *f,
312                  const char *sections,
313                  ConfigItemLookup lookup,
314                  void *table,
315                  bool relaxed,
316                  bool allow_include,
317                  void *userdata) {
318
319         _cleanup_free_ char *section = NULL, *continuation = NULL;
320         _cleanup_fclose_ FILE *ours = NULL;
321         unsigned line = 0, section_line = 0;
322         int r;
323
324         assert(filename);
325         assert(lookup);
326
327         if (!f) {
328                 f = ours = fopen(filename, "re");
329                 if (!f) {
330                         log_error("Failed to open configuration file '%s': %m", filename);
331                         return -errno;
332                 }
333         }
334
335         while (!feof(f)) {
336                 char l[LINE_MAX], *p, *c = NULL, *e;
337                 bool escaped = false;
338
339                 if (!fgets(l, sizeof(l), f)) {
340                         if (feof(f))
341                                 break;
342
343                         log_error("Failed to read configuration file '%s': %m", filename);
344                         return -errno;
345                 }
346
347                 truncate_nl(l);
348
349                 if (continuation) {
350                         c = strappend(continuation, l);
351                         if (!c)
352                                 return -ENOMEM;
353
354                         free(continuation);
355                         continuation = NULL;
356                         p = c;
357                 } else
358                         p = l;
359
360                 for (e = p; *e; e++) {
361                         if (escaped)
362                                 escaped = false;
363                         else if (*e == '\\')
364                                 escaped = true;
365                 }
366
367                 if (escaped) {
368                         *(e-1) = ' ';
369
370                         if (c)
371                                 continuation = c;
372                         else {
373                                 continuation = strdup(l);
374                                 if (!continuation)
375                                         return -ENOMEM;
376                         }
377
378                         continue;
379                 }
380
381                 r = parse_line(unit,
382                                filename,
383                                ++line,
384                                sections,
385                                lookup,
386                                table,
387                                relaxed,
388                                allow_include,
389                                &section,
390                                &section_line,
391                                p,
392                                userdata);
393                 free(c);
394
395                 if (r < 0)
396                         return r;
397         }
398
399         return 0;
400 }
401
402 #define DEFINE_PARSER(type, vartype, conv_func)                         \
403         int config_parse_##type(const char *unit,                       \
404                                 const char *filename,                   \
405                                 unsigned line,                          \
406                                 const char *section,                    \
407                                 unsigned section_line,                  \
408                                 const char *lvalue,                     \
409                                 int ltype,                              \
410                                 const char *rvalue,                     \
411                                 void *data,                             \
412                                 void *userdata) {                       \
413                                                                         \
414                 vartype *i = data;                                      \
415                 int r;                                                  \
416                                                                         \
417                 assert(filename);                                       \
418                 assert(lvalue);                                         \
419                 assert(rvalue);                                         \
420                 assert(data);                                           \
421                                                                         \
422                 r = conv_func(rvalue, i);                               \
423                 if (r < 0)                                              \
424                         log_syntax(unit, LOG_ERR, filename, line, -r,   \
425                                    "Failed to parse %s value, ignoring: %s", \
426                                    #vartype, rvalue);                   \
427                                                                         \
428                 return 0;                                               \
429         }
430
431 DEFINE_PARSER(int, int, safe_atoi)
432 DEFINE_PARSER(long, long, safe_atoli)
433 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
434 DEFINE_PARSER(unsigned, unsigned, safe_atou)
435 DEFINE_PARSER(double, double, safe_atod)
436 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
437 DEFINE_PARSER(sec, usec_t, parse_sec)
438
439
440 int config_parse_bytes_size(const char* unit,
441                             const char *filename,
442                             unsigned line,
443                             const char *section,
444                             unsigned section_line,
445                             const char *lvalue,
446                             int ltype,
447                             const char *rvalue,
448                             void *data,
449                             void *userdata) {
450
451         size_t *sz = data;
452         off_t o;
453         int r;
454
455         assert(filename);
456         assert(lvalue);
457         assert(rvalue);
458         assert(data);
459
460         r = parse_bytes(rvalue, &o);
461         if (r < 0 || (off_t) (size_t) o != o) {
462                 log_syntax(unit, LOG_ERR, filename, line, -r,
463                            "Failed to parse byte value, ignoring: %s", rvalue);
464                 return 0;
465         }
466
467         *sz = (size_t) o;
468         return 0;
469 }
470
471
472 int config_parse_bytes_off(const char* unit,
473                            const char *filename,
474                            unsigned line,
475                            const char *section,
476                            unsigned section_line,
477                            const char *lvalue,
478                            int ltype,
479                            const char *rvalue,
480                            void *data,
481                            void *userdata) {
482
483         off_t *bytes = data;
484         int r;
485
486         assert(filename);
487         assert(lvalue);
488         assert(rvalue);
489         assert(data);
490
491         assert_cc(sizeof(off_t) == sizeof(uint64_t));
492
493         r = parse_bytes(rvalue, bytes);
494         if (r < 0)
495                 log_syntax(unit, LOG_ERR, filename, line, -r,
496                            "Failed to parse bytes value, ignoring: %s", rvalue);
497
498         return 0;
499 }
500
501 int config_parse_bool(const char* unit,
502                       const char *filename,
503                       unsigned line,
504                       const char *section,
505                       unsigned section_line,
506                       const char *lvalue,
507                       int ltype,
508                       const char *rvalue,
509                       void *data,
510                       void *userdata) {
511
512         int k;
513         bool *b = data;
514
515         assert(filename);
516         assert(lvalue);
517         assert(rvalue);
518         assert(data);
519
520         k = parse_boolean(rvalue);
521         if (k < 0) {
522                 log_syntax(unit, LOG_ERR, filename, line, -k,
523                            "Failed to parse boolean value, ignoring: %s", rvalue);
524                 return 0;
525         }
526
527         *b = !!k;
528         return 0;
529 }
530
531 int config_parse_show_status(const char* unit,
532                              const char *filename,
533                              unsigned line,
534                              const char *section,
535                              unsigned section_line,
536                              const char *lvalue,
537                              int ltype,
538                              const char *rvalue,
539                              void *data,
540                              void *userdata) {
541
542         int k;
543         ShowStatus *b = data;
544
545         assert(filename);
546         assert(lvalue);
547         assert(rvalue);
548         assert(data);
549
550         k = parse_show_status(rvalue, b);
551         if (k < 0) {
552                 log_syntax(unit, LOG_ERR, filename, line, -k,
553                            "Failed to parse show status setting, ignoring: %s", rvalue);
554                 return 0;
555         }
556
557         return 0;
558 }
559
560 int config_parse_string(const char *unit,
561                         const char *filename,
562                         unsigned line,
563                         const char *section,
564                         unsigned section_line,
565                         const char *lvalue,
566                         int ltype,
567                         const char *rvalue,
568                         void *data,
569                         void *userdata) {
570
571         char **s = data;
572         char *n;
573
574         assert(filename);
575         assert(lvalue);
576         assert(rvalue);
577         assert(data);
578
579         n = strdup(rvalue);
580         if (!n)
581                 return log_oom();
582
583         if (!utf8_is_valid(n)) {
584                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
585                            "String is not UTF-8 clean, ignoring assignment: %s", rvalue);
586                 free(n);
587                 return 0;
588         }
589
590         free(*s);
591         if (*n)
592                 *s = n;
593         else {
594                 free(n);
595                 *s = NULL;
596         }
597
598         return 0;
599 }
600
601 int config_parse_path(const char *unit,
602                       const char *filename,
603                       unsigned line,
604                       const char *section,
605                       unsigned section_line,
606                       const char *lvalue,
607                       int ltype,
608                       const char *rvalue,
609                       void *data,
610                       void *userdata) {
611
612         char **s = data;
613         char *n;
614         int offset;
615
616         assert(filename);
617         assert(lvalue);
618         assert(rvalue);
619         assert(data);
620
621         if (!utf8_is_valid(rvalue)) {
622                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
623                            "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
624                 return 0;
625         }
626
627         offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
628                                       streq(lvalue, "ReadOnlyDirectories"));
629         if (!path_is_absolute(rvalue + offset)) {
630                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
631                            "Not an absolute path, ignoring: %s", rvalue);
632                 return 0;
633         }
634
635         n = strdup(rvalue);
636         if (!n)
637                 return log_oom();
638
639         path_kill_slashes(n);
640
641         free(*s);
642         *s = n;
643
644         return 0;
645 }
646
647 int config_parse_strv(const char *unit,
648                       const char *filename,
649                       unsigned line,
650                       const char *section,
651                       unsigned section_line,
652                       const char *lvalue,
653                       int ltype,
654                       const char *rvalue,
655                       void *data,
656                       void *userdata) {
657
658         char *** sv = data, *w, *state;
659         size_t l;
660         int r;
661
662         assert(filename);
663         assert(lvalue);
664         assert(rvalue);
665         assert(data);
666
667         if (isempty(rvalue)) {
668                 char **empty;
669
670                 /* Empty assignment resets the list. As a special rule
671                  * we actually fill in a real empty array here rather
672                  * than NULL, since some code wants to know if
673                  * something was set at all... */
674                 empty = strv_new(NULL, NULL);
675                 if (!empty)
676                         return log_oom();
677
678                 strv_free(*sv);
679                 *sv = empty;
680                 return 0;
681         }
682
683         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
684                 _cleanup_free_ char *n;
685
686                 n = cunescape_length(w, l);
687                 if (!n)
688                         return log_oom();
689
690                 if (!utf8_is_valid(n)) {
691                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
692                                    "String is not UTF-8 clean, ignoring: %s", rvalue);
693                         continue;
694                 }
695
696                 r = strv_extend(sv, n);
697                 if (r < 0)
698                         return log_oom();
699         }
700
701         return 0;
702 }
703
704 int config_parse_path_strv(const char *unit,
705                            const char *filename,
706                            unsigned line,
707                            const char *section,
708                            unsigned section_line,
709                            const char *lvalue,
710                            int ltype,
711                            const char *rvalue,
712                            void *data,
713                            void *userdata) {
714
715         char*** sv = data, *w, *state;
716         size_t l;
717         int r;
718
719         assert(filename);
720         assert(lvalue);
721         assert(rvalue);
722         assert(data);
723
724         if (isempty(rvalue)) {
725                 /* Empty assignment resets the list */
726                 strv_free(*sv);
727                 *sv = NULL;
728                 return 0;
729         }
730
731         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
732                 _cleanup_free_ char *n;
733                 int offset;
734
735                 n = strndup(w, l);
736                 if (!n)
737                         return log_oom();
738
739                 if (!utf8_is_valid(n)) {
740                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
741                                    "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
742                         continue;
743                 }
744
745                 offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") ||
746                                          streq(lvalue, "ReadOnlyDirectories"));
747                 if (!path_is_absolute(n + offset)) {
748                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
749                                    "Not an absolute path, ignoring: %s", rvalue);
750                         continue;
751                 }
752
753                 path_kill_slashes(n);
754                 r = strv_extend(sv, n);
755                 if (r < 0)
756                         return log_oom();
757         }
758
759         return 0;
760 }
761
762 int config_parse_mode(const char *unit,
763                       const char *filename,
764                       unsigned line,
765                       const char *section,
766                       unsigned section_line,
767                       const char *lvalue,
768                       int ltype,
769                       const char *rvalue,
770                       void *data,
771                       void *userdata) {
772
773         mode_t *m = data;
774         long l;
775         char *x = NULL;
776
777         assert(filename);
778         assert(lvalue);
779         assert(rvalue);
780         assert(data);
781
782         errno = 0;
783         l = strtol(rvalue, &x, 8);
784         if (!x || x == rvalue || *x || errno) {
785                 log_syntax(unit, LOG_ERR, filename, line, errno,
786                            "Failed to parse mode value, ignoring: %s", rvalue);
787                 return 0;
788         }
789
790         if (l < 0000 || l > 07777) {
791                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
792                            "Mode value out of range, ignoring: %s", rvalue);
793                 return 0;
794         }
795
796         *m = (mode_t) l;
797         return 0;
798 }
799
800 int config_parse_facility(const char *unit,
801                           const char *filename,
802                           unsigned line,
803                           const char *section,
804                           unsigned section_line,
805                           const char *lvalue,
806                           int ltype,
807                           const char *rvalue,
808                           void *data,
809                           void *userdata) {
810
811
812         int *o = data, x;
813
814         assert(filename);
815         assert(lvalue);
816         assert(rvalue);
817         assert(data);
818
819         x = log_facility_unshifted_from_string(rvalue);
820         if (x < 0) {
821                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
822                            "Failed to parse log facility, ignoring: %s", rvalue);
823                 return 0;
824         }
825
826         *o = (x << 3) | LOG_PRI(*o);
827
828         return 0;
829 }
830
831 int config_parse_level(const char *unit,
832                        const char *filename,
833                        unsigned line,
834                        const char *section,
835                        unsigned section_line,
836                        const char *lvalue,
837                        int ltype,
838                        const char *rvalue,
839                        void *data,
840                        void *userdata) {
841
842
843         int *o = data, x;
844
845         assert(filename);
846         assert(lvalue);
847         assert(rvalue);
848         assert(data);
849
850         x = log_level_from_string(rvalue);
851         if (x < 0) {
852                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
853                            "Failed to parse log level, ignoring: %s", rvalue);
854                 return 0;
855         }
856
857         *o = (*o & LOG_FACMASK) | x;
858         return 0;
859 }
860
861 int config_parse_set_status(const char *unit,
862                             const char *filename,
863                             unsigned line,
864                             const char *section,
865                             unsigned section_line,
866                             const char *lvalue,
867                             int ltype,
868                             const char *rvalue,
869                             void *data,
870                             void *userdata) {
871
872         char *w;
873         size_t l;
874         char *state;
875         int r;
876         ExitStatusSet *status_set = data;
877
878         assert(filename);
879         assert(lvalue);
880         assert(rvalue);
881         assert(data);
882
883         if (isempty(rvalue)) {
884                 /* Empty assignment resets the list */
885
886                 set_free(status_set->signal);
887                 set_free(status_set->code);
888
889                 status_set->signal = status_set->code = NULL;
890                 return 0;
891         }
892
893         FOREACH_WORD(w, l, rvalue, state) {
894                 int val;
895                 char *temp;
896
897                 temp = strndup(w, l);
898                 if (!temp)
899                         return log_oom();
900
901                 r = safe_atoi(temp, &val);
902                 if (r < 0) {
903                         val = signal_from_string_try_harder(temp);
904                         free(temp);
905
906                         if (val > 0) {
907                                 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
908                                 if (r < 0)
909                                         return log_oom();
910
911                                 r = set_put(status_set->signal, INT_TO_PTR(val));
912                                 if (r < 0) {
913                                         log_syntax(unit, LOG_ERR, filename, line, -r,
914                                                    "Unable to store: %s", w);
915                                         return r;
916                                 }
917                         } else {
918                                 log_syntax(unit, LOG_ERR, filename, line, -val,
919                                            "Failed to parse value, ignoring: %s", w);
920                                 return 0;
921                         }
922                 } else {
923                         free(temp);
924
925                         if (val < 0 || val > 255)
926                                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
927                                            "Value %d is outside range 0-255, ignoring", val);
928                         else {
929                                 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
930                                 if (r < 0)
931                                         return log_oom();
932
933                                 r = set_put(status_set->code, INT_TO_PTR(val));
934                                 if (r < 0) {
935                                         log_syntax(unit, LOG_ERR, filename, line, -r,
936                                                    "Unable to store: %s", w);
937                                         return r;
938                                 }
939                         }
940                 }
941         }
942
943         return 0;
944 }