chiark / gitweb /
systemd: fix uninitialized memory access in selinux
[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
28 #include "conf-parser.h"
29 #include "util.h"
30 #include "macro.h"
31 #include "strv.h"
32 #include "log.h"
33 #include "utf8.h"
34 #include "path-util.h"
35 #include "set.h"
36 #include "exit-status.h"
37
38 int config_item_table_lookup(
39                 void *table,
40                 const char *section,
41                 const char *lvalue,
42                 ConfigParserCallback *func,
43                 int *ltype,
44                 void **data,
45                 void *userdata) {
46
47         ConfigTableItem *t;
48
49         assert(table);
50         assert(lvalue);
51         assert(func);
52         assert(ltype);
53         assert(data);
54
55         for (t = table; t->lvalue; t++) {
56
57                 if (!streq(lvalue, t->lvalue))
58                         continue;
59
60                 if (!streq_ptr(section, t->section))
61                         continue;
62
63                 *func = t->parse;
64                 *ltype = t->ltype;
65                 *data = t->data;
66                 return 1;
67         }
68
69         return 0;
70 }
71
72 int config_item_perf_lookup(
73                 void *table,
74                 const char *section,
75                 const char *lvalue,
76                 ConfigParserCallback *func,
77                 int *ltype,
78                 void **data,
79                 void *userdata) {
80
81         ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
82         const ConfigPerfItem *p;
83
84         assert(table);
85         assert(lvalue);
86         assert(func);
87         assert(ltype);
88         assert(data);
89
90         if (!section)
91                 p = lookup(lvalue, strlen(lvalue));
92         else {
93                 char *key;
94
95                 key = strjoin(section, ".", lvalue, NULL);
96                 if (!key)
97                         return -ENOMEM;
98
99                 p = lookup(key, strlen(key));
100                 free(key);
101         }
102
103         if (!p)
104                 return 0;
105
106         *func = p->parse;
107         *ltype = p->ltype;
108         *data = (uint8_t*) userdata + p->offset;
109         return 1;
110 }
111
112 /* Run the user supplied parser for an assignment */
113 static int next_assignment(
114                 const char *filename,
115                 unsigned line,
116                 ConfigItemLookup lookup,
117                 void *table,
118                 const char *section,
119                 const char *lvalue,
120                 const char *rvalue,
121                 bool relaxed,
122                 void *userdata) {
123
124         ConfigParserCallback func = NULL;
125         int ltype = 0;
126         void *data = NULL;
127         int r;
128
129         assert(filename);
130         assert(line > 0);
131         assert(lookup);
132         assert(lvalue);
133         assert(rvalue);
134
135         r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
136         if (r < 0)
137                 return r;
138
139         if (r > 0) {
140                 if (func)
141                         return func(filename, line, section, lvalue, ltype, rvalue, data, userdata);
142
143                 return 0;
144         }
145
146         /* Warn about unknown non-extension fields. */
147         if (!relaxed && !startswith(lvalue, "X-"))
148                 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section);
149
150         return 0;
151 }
152
153 /* Parse a variable assignment line */
154 static int parse_line(
155                 const char *filename,
156                 unsigned line,
157                 const char *sections,
158                 ConfigItemLookup lookup,
159                 void *table,
160                 bool relaxed,
161                 char **section,
162                 char *l,
163                 void *userdata) {
164
165         char *e;
166
167         assert(filename);
168         assert(line > 0);
169         assert(lookup);
170         assert(l);
171
172         l = strstrip(l);
173
174         if (!*l)
175                 return 0;
176
177         if (strchr(COMMENTS, *l))
178                 return 0;
179
180         if (startswith(l, ".include ")) {
181                 char *fn;
182                 int r;
183
184                 fn = file_in_same_dir(filename, strstrip(l+9));
185                 if (!fn)
186                         return -ENOMEM;
187
188                 r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata);
189                 free(fn);
190
191                 return r;
192         }
193
194         if (*l == '[') {
195                 size_t k;
196                 char *n;
197
198                 k = strlen(l);
199                 assert(k > 0);
200
201                 if (l[k-1] != ']') {
202                         log_error("[%s:%u] Invalid section header.", filename, line);
203                         return -EBADMSG;
204                 }
205
206                 n = strndup(l+1, k-2);
207                 if (!n)
208                         return -ENOMEM;
209
210                 if (sections && !nulstr_contains(sections, n)) {
211
212                         if (!relaxed)
213                                 log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
214
215                         free(n);
216                         *section = NULL;
217                 } else {
218                         free(*section);
219                         *section = n;
220                 }
221
222                 return 0;
223         }
224
225         if (sections && !*section) {
226
227                 if (!relaxed)
228                         log_info("[%s:%u] Assignment outside of section. Ignoring.", filename, line);
229
230                 return 0;
231         }
232
233         e = strchr(l, '=');
234         if (!e) {
235                 log_error("[%s:%u] Missing '='.", filename, line);
236                 return -EBADMSG;
237         }
238
239         *e = 0;
240         e++;
241
242         return next_assignment(
243                         filename,
244                         line,
245                         lookup,
246                         table,
247                         *section,
248                         strstrip(l),
249                         strstrip(e),
250                         relaxed,
251                         userdata);
252 }
253
254 /* Go through the file and parse each line */
255 int config_parse(
256                 const char *filename,
257                 FILE *f,
258                 const char *sections,
259                 ConfigItemLookup lookup,
260                 void *table,
261                 bool relaxed,
262                 void *userdata) {
263
264         unsigned line = 0;
265         char *section = NULL;
266         int r;
267         bool ours = false;
268         char *continuation = NULL;
269
270         assert(filename);
271         assert(lookup);
272
273         if (!f) {
274                 f = fopen(filename, "re");
275                 if (!f) {
276                         r = -errno;
277                         log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
278                         goto finish;
279                 }
280
281                 ours = true;
282         }
283
284         while (!feof(f)) {
285                 char l[LINE_MAX], *p, *c = NULL, *e;
286                 bool escaped = false;
287
288                 if (!fgets(l, sizeof(l), f)) {
289                         if (feof(f))
290                                 break;
291
292                         r = -errno;
293                         log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
294                         goto finish;
295                 }
296
297                 truncate_nl(l);
298
299                 if (continuation) {
300                         c = strappend(continuation, l);
301                         if (!c) {
302                                 r = -ENOMEM;
303                                 goto finish;
304                         }
305
306                         free(continuation);
307                         continuation = NULL;
308                         p = c;
309                 } else
310                         p = l;
311
312                 for (e = p; *e; e++) {
313                         if (escaped)
314                                 escaped = false;
315                         else if (*e == '\\')
316                                 escaped = true;
317                 }
318
319                 if (escaped) {
320                         *(e-1) = ' ';
321
322                         if (c)
323                                 continuation = c;
324                         else {
325                                 continuation = strdup(l);
326                                 if (!continuation) {
327                                         r = -ENOMEM;
328                                         goto finish;
329                                 }
330                         }
331
332                         continue;
333                 }
334
335                 r = parse_line(filename,
336                                 ++line,
337                                 sections,
338                                 lookup,
339                                 table,
340                                 relaxed,
341                                 &section,
342                                 p,
343                                 userdata);
344                 free(c);
345
346                 if (r < 0)
347                         goto finish;
348         }
349
350         r = 0;
351
352 finish:
353         free(section);
354         free(continuation);
355
356         if (f && ours)
357                 fclose(f);
358
359         return r;
360 }
361
362 int config_parse_int(
363                 const char *filename,
364                 unsigned line,
365                 const char *section,
366                 const char *lvalue,
367                 int ltype,
368                 const char *rvalue,
369                 void *data,
370                 void *userdata) {
371
372         int *i = data;
373         int r;
374
375         assert(filename);
376         assert(lvalue);
377         assert(rvalue);
378         assert(data);
379
380         r = safe_atoi(rvalue, i);
381         if (r < 0) {
382                 log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue);
383                 return 0;
384         }
385
386         return 0;
387 }
388
389 int config_parse_long(
390                 const char *filename,
391                 unsigned line,
392                 const char *section,
393                 const char *lvalue,
394                 int ltype,
395                 const char *rvalue,
396                 void *data,
397                 void *userdata) {
398
399         long *i = data;
400         int r;
401
402         assert(filename);
403         assert(lvalue);
404         assert(rvalue);
405         assert(data);
406
407         r = safe_atoli(rvalue, i);
408         if (r < 0) {
409                 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
410                 return 0;
411         }
412
413         return 0;
414 }
415
416 int config_parse_uint64(
417                 const char *filename,
418                 unsigned line,
419                 const char *section,
420                 const char *lvalue,
421                 int ltype,
422                 const char *rvalue,
423                 void *data,
424                 void *userdata) {
425
426         uint64_t *u = data;
427         int r;
428
429         assert(filename);
430         assert(lvalue);
431         assert(rvalue);
432         assert(data);
433
434         r = safe_atou64(rvalue, u);
435         if (r < 0) {
436                 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
437                 return 0;
438         }
439
440         return 0;
441 }
442
443 int config_parse_unsigned(
444                 const char *filename,
445                 unsigned line,
446                 const char *section,
447                 const char *lvalue,
448                 int ltype,
449                 const char *rvalue,
450                 void *data,
451                 void *userdata) {
452
453         unsigned *u = data;
454         int r;
455
456         assert(filename);
457         assert(lvalue);
458         assert(rvalue);
459         assert(data);
460
461         r = safe_atou(rvalue, u);
462         if (r < 0) {
463                 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
464                 return r;
465         }
466
467         return 0;
468 }
469
470 int config_parse_bytes_size(
471                 const char *filename,
472                 unsigned line,
473                 const char *section,
474                 const char *lvalue,
475                 int ltype,
476                 const char *rvalue,
477                 void *data,
478                 void *userdata) {
479
480         size_t *sz = data;
481         off_t o;
482
483         assert(filename);
484         assert(lvalue);
485         assert(rvalue);
486         assert(data);
487
488         if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) {
489                 log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue);
490                 return 0;
491         }
492
493         *sz = (size_t) o;
494         return 0;
495 }
496
497
498 int config_parse_bytes_off(
499                 const char *filename,
500                 unsigned line,
501                 const char *section,
502                 const char *lvalue,
503                 int ltype,
504                 const char *rvalue,
505                 void *data,
506                 void *userdata) {
507
508         off_t *bytes = data;
509
510         assert(filename);
511         assert(lvalue);
512         assert(rvalue);
513         assert(data);
514
515         assert_cc(sizeof(off_t) == sizeof(uint64_t));
516
517         if (parse_bytes(rvalue, bytes) < 0) {
518                 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
519                 return 0;
520         }
521
522         return 0;
523 }
524
525 int config_parse_bool(
526                 const char *filename,
527                 unsigned line,
528                 const char *section,
529                 const char *lvalue,
530                 int ltype,
531                 const char *rvalue,
532                 void *data,
533                 void *userdata) {
534
535         int k;
536         bool *b = data;
537
538         assert(filename);
539         assert(lvalue);
540         assert(rvalue);
541         assert(data);
542
543         if ((k = parse_boolean(rvalue)) < 0) {
544                 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
545                 return 0;
546         }
547
548         *b = !!k;
549         return 0;
550 }
551
552 int config_parse_tristate(
553                 const char *filename,
554                 unsigned line,
555                 const char *section,
556                 const char *lvalue,
557                 int ltype,
558                 const char *rvalue,
559                 void *data,
560                 void *userdata) {
561
562         int k;
563         int *b = data;
564
565         assert(filename);
566         assert(lvalue);
567         assert(rvalue);
568         assert(data);
569
570         /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
571
572         k = parse_boolean(rvalue);
573         if (k < 0) {
574                 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
575                 return 0;
576         }
577
578         *b = !!k;
579         return 0;
580 }
581
582 int config_parse_string(
583                 const char *filename,
584                 unsigned line,
585                 const char *section,
586                 const char *lvalue,
587                 int ltype,
588                 const char *rvalue,
589                 void *data,
590                 void *userdata) {
591
592         char **s = data;
593         char *n;
594
595         assert(filename);
596         assert(lvalue);
597         assert(rvalue);
598         assert(data);
599
600         n = strdup(rvalue);
601         if (!n)
602                 return log_oom();
603
604         if (!utf8_is_valid(n)) {
605                 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
606                 free(n);
607                 return 0;
608         }
609
610         free(*s);
611         if (*n)
612                 *s = n;
613         else {
614                 free(n);
615                 *s = NULL;
616         }
617
618         return 0;
619 }
620
621 int config_parse_path(
622                 const char *filename,
623                 unsigned line,
624                 const char *section,
625                 const char *lvalue,
626                 int ltype,
627                 const char *rvalue,
628                 void *data,
629                 void *userdata) {
630
631         char **s = data;
632         char *n;
633
634         assert(filename);
635         assert(lvalue);
636         assert(rvalue);
637         assert(data);
638
639         if (!utf8_is_valid(rvalue)) {
640                 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
641                 return 0;
642         }
643
644         if (!path_is_absolute(rvalue)) {
645                 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
646                 return 0;
647         }
648
649         n = strdup(rvalue);
650         if (!n)
651                 return log_oom();
652
653         path_kill_slashes(n);
654
655         free(*s);
656         *s = n;
657
658         return 0;
659 }
660
661 int config_parse_strv(
662                 const char *filename,
663                 unsigned line,
664                 const char *section,
665                 const char *lvalue,
666                 int ltype,
667                 const char *rvalue,
668                 void *data,
669                 void *userdata) {
670
671         char*** sv = data;
672         char **n;
673         char *w;
674         unsigned k;
675         size_t l;
676         char *state;
677         int r;
678
679         assert(filename);
680         assert(lvalue);
681         assert(rvalue);
682         assert(data);
683
684         if (isempty(rvalue)) {
685                 /* Empty assignment resets the list */
686                 strv_free(*sv);
687                 *sv = NULL;
688         }
689
690         k = strv_length(*sv);
691         FOREACH_WORD_QUOTED(w, l, rvalue, state)
692                 k++;
693
694         n = new(char*, k+1);
695         if (!n)
696                 return log_oom();
697
698         if (*sv)
699                 for (k = 0; (*sv)[k]; k++)
700                         n[k] = (*sv)[k];
701         else
702                 k = 0;
703
704         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
705                 n[k] = cunescape_length(w, l);
706                 if (!n[k]) {
707                         r = log_oom();
708                         goto fail;
709                 }
710
711                 if (!utf8_is_valid(n[k])) {
712                         log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
713                         free(n[k]);
714                         continue;
715                 }
716
717                 k++;
718         }
719
720         n[k] = NULL;
721         free(*sv);
722         *sv = n;
723
724         return 0;
725
726 fail:
727         for (; k > 0; k--)
728                 free(n[k-1]);
729         free(n);
730
731         return r;
732 }
733
734 int config_parse_path_strv(
735                 const char *filename,
736                 unsigned line,
737                 const char *section,
738                 const char *lvalue,
739                 int ltype,
740                 const char *rvalue,
741                 void *data,
742                 void *userdata) {
743
744         char*** sv = data;
745         char **n;
746         char *w;
747         unsigned k;
748         size_t l;
749         char *state;
750         int r;
751
752         assert(filename);
753         assert(lvalue);
754         assert(rvalue);
755         assert(data);
756
757         if (isempty(rvalue)) {
758                 /* Empty assignment resets the list */
759                 strv_free(*sv);
760                 *sv = NULL;
761         }
762
763         k = strv_length(*sv);
764         FOREACH_WORD_QUOTED(w, l, rvalue, state)
765                 k++;
766
767         n = new(char*, k+1);
768         if (!n)
769                 return log_oom();
770
771         k = 0;
772         if (*sv)
773                 for (; (*sv)[k]; k++)
774                         n[k] = (*sv)[k];
775
776         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
777                 n[k] = strndup(w, l);
778                 if (!n[k]) {
779                         r = log_oom();
780                         goto fail;
781                 }
782
783                 if (!utf8_is_valid(n[k])) {
784                         log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
785                         free(n[k]);
786                         continue;
787                 }
788
789                 if (!path_is_absolute(n[k])) {
790                         log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
791                         free(n[k]);
792                         continue;
793                 }
794
795                 path_kill_slashes(n[k]);
796                 k++;
797         }
798
799         n[k] = NULL;
800         free(*sv);
801         *sv = n;
802
803         return 0;
804
805 fail:
806         for (; k > 0; k--)
807                 free(n[k-1]);
808         free(n);
809
810         return r;
811 }
812
813 int config_parse_usec(
814                 const char *filename,
815                 unsigned line,
816                 const char *section,
817                 const char *lvalue,
818                 int ltype,
819                 const char *rvalue,
820                 void *data,
821                 void *userdata) {
822
823         usec_t *usec = data;
824
825         assert(filename);
826         assert(lvalue);
827         assert(rvalue);
828         assert(data);
829
830         if (parse_usec(rvalue, usec) < 0) {
831                 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
832                 return 0;
833         }
834
835         return 0;
836 }
837
838 int config_parse_nsec(
839                 const char *filename,
840                 unsigned line,
841                 const char *section,
842                 const char *lvalue,
843                 int ltype,
844                 const char *rvalue,
845                 void *data,
846                 void *userdata) {
847
848         nsec_t *nsec = data;
849
850         assert(filename);
851         assert(lvalue);
852         assert(rvalue);
853         assert(data);
854
855         if (parse_nsec(rvalue, nsec) < 0) {
856                 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
857                 return 0;
858         }
859
860         return 0;
861 }
862
863 int config_parse_mode(
864                 const char *filename,
865                 unsigned line,
866                 const char *section,
867                 const char *lvalue,
868                 int ltype,
869                 const char *rvalue,
870                 void *data,
871                 void *userdata) {
872
873         mode_t *m = data;
874         long l;
875         char *x = NULL;
876
877         assert(filename);
878         assert(lvalue);
879         assert(rvalue);
880         assert(data);
881
882         errno = 0;
883         l = strtol(rvalue, &x, 8);
884         if (!x || x == rvalue || *x || errno) {
885                 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
886                 return 0;
887         }
888
889         if (l < 0000 || l > 07777) {
890                 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
891                 return 0;
892         }
893
894         *m = (mode_t) l;
895         return 0;
896 }
897
898 int config_parse_facility(
899                 const char *filename,
900                 unsigned line,
901                 const char *section,
902                 const char *lvalue,
903                 int ltype,
904                 const char *rvalue,
905                 void *data,
906                 void *userdata) {
907
908
909         int *o = data, x;
910
911         assert(filename);
912         assert(lvalue);
913         assert(rvalue);
914         assert(data);
915
916         x = log_facility_unshifted_from_string(rvalue);
917         if (x < 0) {
918                 log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
919                 return 0;
920         }
921
922         *o = (x << 3) | LOG_PRI(*o);
923
924         return 0;
925 }
926
927 int config_parse_level(
928                 const char *filename,
929                 unsigned line,
930                 const char *section,
931                 const char *lvalue,
932                 int ltype,
933                 const char *rvalue,
934                 void *data,
935                 void *userdata) {
936
937
938         int *o = data, x;
939
940         assert(filename);
941         assert(lvalue);
942         assert(rvalue);
943         assert(data);
944
945         x = log_level_from_string(rvalue);
946         if (x < 0) {
947                 log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
948                 return 0;
949         }
950
951         *o = (*o & LOG_FACMASK) | x;
952         return 0;
953 }
954
955 int config_parse_set_status(
956                 const char *filename,
957                 unsigned line,
958                 const char *section,
959                 const char *lvalue,
960                 int ltype,
961                 const char *rvalue,
962                 void *data,
963                 void *userdata) {
964
965         char *w;
966         size_t l;
967         char *state;
968         int r;
969         ExitStatusSet *status_set = data;
970
971         assert(filename);
972         assert(lvalue);
973         assert(rvalue);
974         assert(data);
975
976         if (isempty(rvalue)) {
977                 /* Empty assignment resets the list */
978
979                 set_free(status_set->signal);
980                 set_free(status_set->code);
981
982                 status_set->signal = status_set->code = NULL;
983                 return 0;
984         }
985
986         FOREACH_WORD(w, l, rvalue, state) {
987                 int val;
988                 char *temp;
989
990                 temp = strndup(w, l);
991                 if (!temp)
992                         return log_oom();
993
994                 r = safe_atoi(temp, &val);
995                 if (r < 0) {
996                         val = signal_from_string_try_harder(temp);
997                         free(temp);
998
999                         if (val > 0) {
1000                                 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
1001                                 if (r < 0)
1002                                         return log_oom();
1003
1004                                 r = set_put(status_set->signal, INT_TO_PTR(val));
1005                                 if (r < 0) {
1006                                         log_error("[%s:%u] Unable to store: %s", filename, line, w);
1007                                         return r;
1008                                 }
1009                         } else {
1010                                 log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
1011                                 return 0;
1012                         }
1013                 } else {
1014                         free(temp);
1015
1016                         if (val < 0 || val > 255)
1017                                 log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
1018                         else {
1019                                 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
1020                                 if (r < 0)
1021                                         return log_oom();
1022
1023                                 r = set_put(status_set->code, INT_TO_PTR(val));
1024                                 if (r < 0) {
1025                                         log_error("[%s:%u] Unable to store: %s", filename, line, w);
1026                                         return r;
1027                                 }
1028                         }
1029                 }
1030         }
1031
1032         return 0;
1033 }