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