chiark / gitweb /
conf-parse: remove 4K line length limit
[elogind.git] / src / shared / conf-parser.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27
28 #include "alloc-util.h"
29 #include "conf-files.h"
30 #include "conf-parser.h"
31 #include "def.h"
32 #include "extract-word.h"
33 #include "fd-util.h"
34 #include "fileio.h"
35 #include "fs-util.h"
36 #include "log.h"
37 #include "macro.h"
38 #include "parse-util.h"
39 #include "path-util.h"
40 #include "process-util.h"
41 #include "signal-util.h"
42 #include "string-util.h"
43 #include "strv.h"
44 #include "syslog-util.h"
45 #include "time-util.h"
46 #include "utf8.h"
47
48 int config_item_table_lookup(
49                 const void *table,
50                 const char *section,
51                 const char *lvalue,
52                 ConfigParserCallback *func,
53                 int *ltype,
54                 void **data,
55                 void *userdata) {
56
57         const ConfigTableItem *t;
58
59         assert(table);
60         assert(lvalue);
61         assert(func);
62         assert(ltype);
63         assert(data);
64
65         for (t = table; t->lvalue; t++) {
66
67                 if (!streq(lvalue, t->lvalue))
68                         continue;
69
70                 if (!streq_ptr(section, t->section))
71                         continue;
72
73                 *func = t->parse;
74                 *ltype = t->ltype;
75                 *data = t->data;
76                 return 1;
77         }
78
79         return 0;
80 }
81
82 int config_item_perf_lookup(
83                 const void *table,
84                 const char *section,
85                 const char *lvalue,
86                 ConfigParserCallback *func,
87                 int *ltype,
88                 void **data,
89                 void *userdata) {
90
91         ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
92         const ConfigPerfItem *p;
93
94         assert(table);
95         assert(lvalue);
96         assert(func);
97         assert(ltype);
98         assert(data);
99
100         if (!section)
101                 p = lookup(lvalue, strlen(lvalue));
102         else {
103                 char *key;
104
105                 key = strjoin(section, ".", lvalue);
106                 if (!key)
107                         return -ENOMEM;
108
109                 p = lookup(key, strlen(key));
110                 free(key);
111         }
112
113         if (!p)
114                 return 0;
115
116         *func = p->parse;
117         *ltype = p->ltype;
118         *data = (uint8_t*) userdata + p->offset;
119         return 1;
120 }
121
122 /* Run the user supplied parser for an assignment */
123 static int next_assignment(const char *unit,
124                            const char *filename,
125                            unsigned line,
126                            ConfigItemLookup lookup,
127                            const void *table,
128                            const char *section,
129                            unsigned section_line,
130                            const char *lvalue,
131                            const char *rvalue,
132                            bool relaxed,
133                            void *userdata) {
134
135         ConfigParserCallback func = NULL;
136         int ltype = 0;
137         void *data = NULL;
138         int r;
139
140         assert(filename);
141         assert(line > 0);
142         assert(lookup);
143         assert(lvalue);
144         assert(rvalue);
145
146         r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
147         if (r < 0)
148                 return r;
149
150         if (r > 0) {
151                 if (func)
152                         return func(unit, filename, line, section, section_line,
153                                     lvalue, ltype, rvalue, data, userdata);
154
155                 return 0;
156         }
157
158         /* Warn about unknown non-extension fields. */
159         if (!relaxed && !startswith(lvalue, "X-"))
160                 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
161
162         return 0;
163 }
164
165 /* Parse a variable assignment line */
166 static int parse_line(const char* unit,
167                       const char *filename,
168                       unsigned line,
169                       const char *sections,
170                       ConfigItemLookup lookup,
171                       const void *table,
172                       bool relaxed,
173                       bool allow_include,
174                       char **section,
175                       unsigned *section_line,
176                       bool *section_ignored,
177                       char *l,
178                       void *userdata) {
179
180         char *e;
181
182         assert(filename);
183         assert(line > 0);
184         assert(lookup);
185         assert(l);
186
187         l = strstrip(l);
188
189         if (!*l)
190                 return 0;
191
192         if (strchr(COMMENTS "\n", *l))
193                 return 0;
194
195         if (startswith(l, ".include ")) {
196                 _cleanup_free_ char *fn = NULL;
197
198                 /* .includes are a bad idea, we only support them here
199                  * for historical reasons. They create cyclic include
200                  * problems and make it difficult to detect
201                  * configuration file changes with an easy
202                  * stat(). Better approaches, such as .d/ drop-in
203                  * snippets exist.
204                  *
205                  * Support for them should be eventually removed. */
206
207                 if (!allow_include) {
208                         log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
209                         return 0;
210                 }
211
212                 fn = file_in_same_dir(filename, strstrip(l+9));
213                 if (!fn)
214                         return -ENOMEM;
215
216                 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
217         }
218
219         if (*l == '[') {
220                 size_t k;
221                 char *n;
222
223                 k = strlen(l);
224                 assert(k > 0);
225
226                 if (l[k-1] != ']') {
227                         log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
228                         return -EBADMSG;
229                 }
230
231                 n = strndup(l+1, k-2);
232                 if (!n)
233                         return -ENOMEM;
234
235                 if (sections && !nulstr_contains(sections, n)) {
236
237                         if (!relaxed && !startswith(n, "X-"))
238                                 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
239
240                         free(n);
241                         *section = mfree(*section);
242                         *section_line = 0;
243                         *section_ignored = true;
244                 } else {
245                         free(*section);
246                         *section = n;
247                         *section_line = line;
248                         *section_ignored = false;
249                 }
250
251                 return 0;
252         }
253
254         if (sections && !*section) {
255
256                 if (!relaxed && !*section_ignored)
257                         log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
258
259                 return 0;
260         }
261
262         e = strchr(l, '=');
263         if (!e) {
264                 log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
265                 return -EINVAL;
266         }
267
268         *e = 0;
269         e++;
270
271         return next_assignment(unit,
272                                filename,
273                                line,
274                                lookup,
275                                table,
276                                *section,
277                                *section_line,
278                                strstrip(l),
279                                strstrip(e),
280                                relaxed,
281                                userdata);
282 }
283
284 /* Go through the file and parse each line */
285 int config_parse(const char *unit,
286                  const char *filename,
287                  FILE *f,
288                  const char *sections,
289                  ConfigItemLookup lookup,
290                  const void *table,
291                  bool relaxed,
292                  bool allow_include,
293                  bool warn,
294                  void *userdata) {
295
296         _cleanup_free_ char *section = NULL, *continuation = NULL;
297         _cleanup_fclose_ FILE *ours = NULL;
298         unsigned line = 0, section_line = 0;
299         bool section_ignored = false, allow_bom = true;
300         int r;
301
302         assert(filename);
303         assert(lookup);
304
305         if (!f) {
306                 f = ours = fopen(filename, "re");
307                 if (!f) {
308                         /* Only log on request, except for ENOENT,
309                          * since we return 0 to the caller. */
310                         if (warn || errno == ENOENT)
311                                 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
312                                          "Failed to open configuration file '%s': %m", filename);
313                         return errno == ENOENT ? 0 : -errno;
314                 }
315         }
316
317         fd_warn_permissions(filename, fileno(f));
318
319         for (;;) {
320                 _cleanup_free_ char *buf = NULL;
321                 char *l, *p, *c = NULL, *e;
322                 bool escaped = false;
323
324                 r = read_line(f, LONG_LINE_MAX, &buf);
325                 if (r == 0)
326                         break;
327                 if (r == -ENOBUFS) {
328                         if (warn)
329                                 log_error_errno(r, "%s:%u: Line too long", filename, line);
330
331                         return r;
332                 }
333                 if (r < 0) {
334                         if (warn)
335                                 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
336
337                         return r;
338                 }
339
340                 l = buf;
341                 if (allow_bom) {
342                         char *q;
343
344                         q = startswith(buf, UTF8_BYTE_ORDER_MARK);
345                         if (q) {
346                                 l = q;
347                                 allow_bom = false;
348                         }
349                 }
350
351                 if (continuation) {
352                         if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
353                                 if (warn)
354                                         log_error("%s:%u: Continuation line too long", filename, line);
355                                 return -ENOBUFS;
356                         }
357
358                         c = strappend(continuation, l);
359                         if (!c) {
360                                 if (warn)
361                                         log_oom();
362                                 return -ENOMEM;
363                         }
364
365                         continuation = mfree(continuation);
366                         p = c;
367                 } else
368                         p = l;
369
370                 for (e = p; *e; e++) {
371                         if (escaped)
372                                 escaped = false;
373                         else if (*e == '\\')
374                                 escaped = true;
375                 }
376
377                 if (escaped) {
378                         *(e-1) = ' ';
379
380                         if (c)
381                                 continuation = c;
382                         else {
383                                 continuation = strdup(l);
384                                 if (!continuation) {
385                                         if (warn)
386                                                 log_oom();
387                                         return -ENOMEM;
388                                 }
389                         }
390
391                         continue;
392                 }
393
394                 r = parse_line(unit,
395                                filename,
396                                ++line,
397                                sections,
398                                lookup,
399                                table,
400                                relaxed,
401                                allow_include,
402                                &section,
403                                &section_line,
404                                &section_ignored,
405                                p,
406                                userdata);
407                 free(c);
408
409                 if (r < 0) {
410                         if (warn)
411                                 log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
412                         return r;
413                 }
414         }
415
416         return 0;
417 }
418
419 static int config_parse_many_files(
420                 const char *conf_file,
421                 char **files,
422                 const char *sections,
423                 ConfigItemLookup lookup,
424                 const void *table,
425                 bool relaxed,
426                 void *userdata) {
427
428         char **fn;
429         int r;
430
431         if (conf_file) {
432                 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
433                 if (r < 0)
434                         return r;
435         }
436
437         STRV_FOREACH(fn, files) {
438                 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
439                 if (r < 0)
440                         return r;
441         }
442
443         return 0;
444 }
445
446 /* Parse each config file in the directories specified as nulstr. */
447 int config_parse_many_nulstr(
448                 const char *conf_file,
449                 const char *conf_file_dirs,
450                 const char *sections,
451                 ConfigItemLookup lookup,
452                 const void *table,
453                 bool relaxed,
454                 void *userdata) {
455
456         _cleanup_strv_free_ char **files = NULL;
457         int r;
458
459         r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
460         if (r < 0)
461                 return r;
462
463         return config_parse_many_files(conf_file, files,
464                                        sections, lookup, table, relaxed, userdata);
465 }
466
467 #if 0 /// UNNEEDED by elogind
468 /* Parse each config file in the directories specified as strv. */
469 int config_parse_many(
470                 const char *conf_file,
471                 const char* const* conf_file_dirs,
472                 const char *dropin_dirname,
473                 const char *sections,
474                 ConfigItemLookup lookup,
475                 const void *table,
476                 bool relaxed,
477                 void *userdata) {
478
479         _cleanup_strv_free_ char **dropin_dirs = NULL;
480         _cleanup_strv_free_ char **files = NULL;
481         const char *suffix;
482         int r;
483
484         suffix = strjoina("/", dropin_dirname);
485         r = strv_extend_strv_concat(&dropin_dirs, (char**) conf_file_dirs, suffix);
486         if (r < 0)
487                 return r;
488
489         r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
490         if (r < 0)
491                 return r;
492
493         return config_parse_many_files(conf_file, files,
494                                        sections, lookup, table, relaxed, userdata);
495 }
496 #endif // 0
497
498 #define DEFINE_PARSER(type, vartype, conv_func)                         \
499         int config_parse_##type(                                        \
500                         const char *unit,                               \
501                         const char *filename,                           \
502                         unsigned line,                                  \
503                         const char *section,                            \
504                         unsigned section_line,                          \
505                         const char *lvalue,                             \
506                         int ltype,                                      \
507                         const char *rvalue,                             \
508                         void *data,                                     \
509                         void *userdata) {                               \
510                                                                         \
511                 vartype *i = data;                                      \
512                 int r;                                                  \
513                                                                         \
514                 assert(filename);                                       \
515                 assert(lvalue);                                         \
516                 assert(rvalue);                                         \
517                 assert(data);                                           \
518                                                                         \
519                 r = conv_func(rvalue, i);                               \
520                 if (r < 0)                                              \
521                         log_syntax(unit, LOG_ERR, filename, line, r,    \
522                                    "Failed to parse %s value, ignoring: %s", \
523                                    #type, rvalue);                      \
524                                                                         \
525                 return 0;                                               \
526         }                                                               \
527         struct __useless_struct_to_allow_trailing_semicolon__
528
529 DEFINE_PARSER(int, int, safe_atoi);
530 DEFINE_PARSER(long, long, safe_atoli);
531 #if 0 /// UNNEEDED by elogind
532 DEFINE_PARSER(uint8, uint8_t, safe_atou8);
533 DEFINE_PARSER(uint16, uint16_t, safe_atou16);
534 DEFINE_PARSER(uint32, uint32_t, safe_atou32);
535 #endif // 0
536 DEFINE_PARSER(uint64, uint64_t, safe_atou64);
537 DEFINE_PARSER(unsigned, unsigned, safe_atou);
538 DEFINE_PARSER(double, double, safe_atod);
539 #if 0 /// UNNEEDED by elogind
540 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
541 #endif // 0
542 DEFINE_PARSER(sec, usec_t, parse_sec);
543 DEFINE_PARSER(mode, mode_t, parse_mode);
544
545 int config_parse_iec_size(const char* unit,
546                             const char *filename,
547                             unsigned line,
548                             const char *section,
549                             unsigned section_line,
550                             const char *lvalue,
551                             int ltype,
552                             const char *rvalue,
553                             void *data,
554                             void *userdata) {
555
556         size_t *sz = data;
557         uint64_t v;
558         int r;
559
560         assert(filename);
561         assert(lvalue);
562         assert(rvalue);
563         assert(data);
564
565         r = parse_size(rvalue, 1024, &v);
566         if (r < 0 || (uint64_t) (size_t) v != v) {
567                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
568                 return 0;
569         }
570
571         *sz = (size_t) v;
572         return 0;
573 }
574
575 #if 0 /// UNNEEDED by elogind
576 int config_parse_si_size(const char* unit,
577                             const char *filename,
578                             unsigned line,
579                             const char *section,
580                             unsigned section_line,
581                             const char *lvalue,
582                             int ltype,
583                             const char *rvalue,
584                             void *data,
585                             void *userdata) {
586
587         size_t *sz = data;
588         uint64_t v;
589         int r;
590
591         assert(filename);
592         assert(lvalue);
593         assert(rvalue);
594         assert(data);
595
596         r = parse_size(rvalue, 1000, &v);
597         if (r < 0 || (uint64_t) (size_t) v != v) {
598                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
599                 return 0;
600         }
601
602         *sz = (size_t) v;
603         return 0;
604 }
605
606 int config_parse_iec_uint64(const char* unit,
607                            const char *filename,
608                            unsigned line,
609                            const char *section,
610                            unsigned section_line,
611                            const char *lvalue,
612                            int ltype,
613                            const char *rvalue,
614                            void *data,
615                            void *userdata) {
616
617         uint64_t *bytes = data;
618         int r;
619
620         assert(filename);
621         assert(lvalue);
622         assert(rvalue);
623         assert(data);
624
625         r = parse_size(rvalue, 1024, bytes);
626         if (r < 0)
627                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
628
629         return 0;
630 }
631 #endif // 0
632
633 int config_parse_bool(const char* unit,
634                       const char *filename,
635                       unsigned line,
636                       const char *section,
637                       unsigned section_line,
638                       const char *lvalue,
639                       int ltype,
640                       const char *rvalue,
641                       void *data,
642                       void *userdata) {
643
644         int k;
645         bool *b = data;
646         bool fatal = ltype;
647
648         assert(filename);
649         assert(lvalue);
650         assert(rvalue);
651         assert(data);
652
653         k = parse_boolean(rvalue);
654         if (k < 0) {
655                 log_syntax(unit, LOG_ERR, filename, line, k,
656                            "Failed to parse boolean value%s: %s",
657                            fatal ? "" : ", ignoring", rvalue);
658                 return fatal ? -ENOEXEC : 0;
659         }
660
661         *b = !!k;
662         return 0;
663 }
664
665 #if 0 /// UNNEEDED by elogind
666 int config_parse_tristate(
667                 const char* unit,
668                 const char *filename,
669                 unsigned line,
670                 const char *section,
671                 unsigned section_line,
672                 const char *lvalue,
673                 int ltype,
674                 const char *rvalue,
675                 void *data,
676                 void *userdata) {
677
678         int k, *t = data;
679
680         assert(filename);
681         assert(lvalue);
682         assert(rvalue);
683         assert(data);
684
685         /* A tristate is pretty much a boolean, except that it can
686          * also take the special value -1, indicating "uninitialized",
687          * much like NULL is for a pointer type. */
688
689         k = parse_boolean(rvalue);
690         if (k < 0) {
691                 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
692                 return 0;
693         }
694
695         *t = !!k;
696         return 0;
697 }
698 #endif // 0
699
700 int config_parse_string(
701                 const char *unit,
702                 const char *filename,
703                 unsigned line,
704                 const char *section,
705                 unsigned section_line,
706                 const char *lvalue,
707                 int ltype,
708                 const char *rvalue,
709                 void *data,
710                 void *userdata) {
711
712         char **s = data, *n;
713
714         assert(filename);
715         assert(lvalue);
716         assert(rvalue);
717         assert(data);
718
719         if (!utf8_is_valid(rvalue)) {
720                 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
721                 return 0;
722         }
723
724         if (isempty(rvalue))
725                 n = NULL;
726         else {
727                 n = strdup(rvalue);
728                 if (!n)
729                         return log_oom();
730         }
731
732         free(*s);
733         *s = n;
734
735         return 0;
736 }
737
738 int config_parse_path(
739                 const char *unit,
740                 const char *filename,
741                 unsigned line,
742                 const char *section,
743                 unsigned section_line,
744                 const char *lvalue,
745                 int ltype,
746                 const char *rvalue,
747                 void *data,
748                 void *userdata) {
749
750         char **s = data, *n;
751         bool fatal = ltype;
752
753         assert(filename);
754         assert(lvalue);
755         assert(rvalue);
756         assert(data);
757
758         if (!utf8_is_valid(rvalue)) {
759                 log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
760                 return fatal ? -ENOEXEC : 0;
761         }
762
763         if (!path_is_absolute(rvalue)) {
764                 log_syntax(unit, LOG_ERR, filename, line, 0,
765                            "Not an absolute path%s: %s",
766                            fatal ? "" : ", ignoring", rvalue);
767                 return fatal ? -ENOEXEC : 0;
768         }
769
770         n = strdup(rvalue);
771         if (!n)
772                 return log_oom();
773
774         path_kill_slashes(n);
775
776         free(*s);
777         *s = n;
778
779         return 0;
780 }
781
782 int config_parse_strv(
783                 const char *unit,
784                 const char *filename,
785                 unsigned line,
786                 const char *section,
787                 unsigned section_line,
788                 const char *lvalue,
789                 int ltype,
790                 const char *rvalue,
791                 void *data,
792                 void *userdata) {
793
794         char ***sv = data;
795         int r;
796
797         assert(filename);
798         assert(lvalue);
799         assert(rvalue);
800         assert(data);
801
802         if (isempty(rvalue)) {
803                 *sv = strv_free(*sv);
804                 return 0;
805         }
806
807         for (;;) {
808                 char *word = NULL;
809
810                 r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
811                 if (r == 0)
812                         break;
813                 if (r == -ENOMEM)
814                         return log_oom();
815                 if (r < 0) {
816                         log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
817                         break;
818                 }
819
820                 if (!utf8_is_valid(word)) {
821                         log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
822                         free(word);
823                         continue;
824                 }
825
826                 r = strv_consume(sv, word);
827                 if (r < 0)
828                         return log_oom();
829         }
830
831         return 0;
832 }
833
834 #if 0 /// UNNEEDED by elogind
835 int config_parse_log_facility(
836                 const char *unit,
837                 const char *filename,
838                 unsigned line,
839                 const char *section,
840                 unsigned section_line,
841                 const char *lvalue,
842                 int ltype,
843                 const char *rvalue,
844                 void *data,
845                 void *userdata) {
846
847
848         int *o = data, x;
849
850         assert(filename);
851         assert(lvalue);
852         assert(rvalue);
853         assert(data);
854
855         x = log_facility_unshifted_from_string(rvalue);
856         if (x < 0) {
857                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
858                 return 0;
859         }
860
861         *o = (x << 3) | LOG_PRI(*o);
862
863         return 0;
864 }
865 #endif // 0
866
867 int config_parse_log_level(
868                 const char *unit,
869                 const char *filename,
870                 unsigned line,
871                 const char *section,
872                 unsigned section_line,
873                 const char *lvalue,
874                 int ltype,
875                 const char *rvalue,
876                 void *data,
877                 void *userdata) {
878
879
880         int *o = data, x;
881
882         assert(filename);
883         assert(lvalue);
884         assert(rvalue);
885         assert(data);
886
887         x = log_level_from_string(rvalue);
888         if (x < 0) {
889                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
890                 return 0;
891         }
892
893         *o = (*o & LOG_FACMASK) | x;
894         return 0;
895 }
896
897 int config_parse_signal(
898                 const char *unit,
899                 const char *filename,
900                 unsigned line,
901                 const char *section,
902                 unsigned section_line,
903                 const char *lvalue,
904                 int ltype,
905                 const char *rvalue,
906                 void *data,
907                 void *userdata) {
908
909         int *sig = data, r;
910
911         assert(filename);
912         assert(lvalue);
913         assert(rvalue);
914         assert(sig);
915
916         r = signal_from_string_try_harder(rvalue);
917         if (r <= 0) {
918                 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
919                 return 0;
920         }
921
922         *sig = r;
923         return 0;
924 }
925
926 #if 0 /// UNNEEDED by elogind
927 int config_parse_personality(
928                 const char *unit,
929                 const char *filename,
930                 unsigned line,
931                 const char *section,
932                 unsigned section_line,
933                 const char *lvalue,
934                 int ltype,
935                 const char *rvalue,
936                 void *data,
937                 void *userdata) {
938
939         unsigned long *personality = data, p;
940
941         assert(filename);
942         assert(lvalue);
943         assert(rvalue);
944         assert(personality);
945
946         if (isempty(rvalue))
947                 p = PERSONALITY_INVALID;
948         else {
949                 p = personality_from_string(rvalue);
950                 if (p == PERSONALITY_INVALID) {
951                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
952                         return 0;
953                 }
954         }
955
956         *personality = p;
957         return 0;
958 }
959
960 int config_parse_ifname(
961                 const char *unit,
962                 const char *filename,
963                 unsigned line,
964                 const char *section,
965                 unsigned section_line,
966                 const char *lvalue,
967                 int ltype,
968                 const char *rvalue,
969                 void *data,
970                 void *userdata) {
971
972         char **s = data;
973         int r;
974
975         assert(filename);
976         assert(lvalue);
977         assert(rvalue);
978         assert(data);
979
980         if (isempty(rvalue)) {
981                 *s = mfree(*s);
982                 return 0;
983         }
984
985         if (!ifname_valid(rvalue)) {
986                 log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
987                 return 0;
988         }
989
990         r = free_and_strdup(s, rvalue);
991         if (r < 0)
992                 return log_oom();
993
994         return 0;
995 }
996
997 int config_parse_ip_port(
998                 const char *unit,
999                 const char *filename,
1000                 unsigned line,
1001                 const char *section,
1002                 unsigned section_line,
1003                 const char *lvalue,
1004                 int ltype,
1005                 const char *rvalue,
1006                 void *data,
1007                 void *userdata) {
1008
1009         uint16_t *s = data;
1010         uint16_t port;
1011         int r;
1012
1013         assert(filename);
1014         assert(lvalue);
1015         assert(rvalue);
1016         assert(data);
1017
1018         if (isempty(rvalue)) {
1019                 *s = 0;
1020                 return 0;
1021         }
1022
1023         r = parse_ip_port(rvalue, &port);
1024         if (r < 0) {
1025                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
1026                 return 0;
1027         }
1028
1029         *s = port;
1030
1031         return 0;
1032 }
1033 #endif // 0