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