chiark / gitweb /
unit-name: fix escaping logic in unit_name_mangle_with_suffix()
[elogind.git] / src / shared / conf-parser.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <netinet/ether.h>
28
29 #include "conf-parser.h"
30 #include "conf-files.h"
31 #include "util.h"
32 #include "macro.h"
33 #include "strv.h"
34 #include "log.h"
35 #include "utf8.h"
36 #include "path-util.h"
37 #include "set.h"
38 #include "exit-status.h"
39 #include "sd-messages.h"
40
41 int log_syntax_internal(const char *unit, int level,
42                         const char *file, unsigned line, const char *func,
43                         const char *config_file, unsigned config_line,
44                         int error, const char *format, ...) {
45
46         _cleanup_free_ char *msg = NULL;
47         int r;
48         va_list ap;
49
50         va_start(ap, format);
51         r = vasprintf(&msg, format, ap);
52         va_end(ap);
53         if (r < 0)
54                 return log_oom();
55
56         if (unit)
57                 r = log_struct_internal(level,
58                                         file, line, func,
59                                         getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
60                                         MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
61                                         "CONFIG_FILE=%s", config_file,
62                                         "CONFIG_LINE=%u", config_line,
63                                         "ERRNO=%d", error > 0 ? error : EINVAL,
64                                         "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
65                                         NULL);
66         else
67                 r = log_struct_internal(level,
68                                         file, line, func,
69                                         MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
70                                         "CONFIG_FILE=%s", config_file,
71                                         "CONFIG_LINE=%u", config_line,
72                                         "ERRNO=%d", error > 0 ? error : EINVAL,
73                                         "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
74                                         NULL);
75
76         return r;
77 }
78
79 int config_item_table_lookup(
80                 const void *table,
81                 const char *section,
82                 const char *lvalue,
83                 ConfigParserCallback *func,
84                 int *ltype,
85                 void **data,
86                 void *userdata) {
87
88         const ConfigTableItem *t;
89
90         assert(table);
91         assert(lvalue);
92         assert(func);
93         assert(ltype);
94         assert(data);
95
96         for (t = table; t->lvalue; t++) {
97
98                 if (!streq(lvalue, t->lvalue))
99                         continue;
100
101                 if (!streq_ptr(section, t->section))
102                         continue;
103
104                 *func = t->parse;
105                 *ltype = t->ltype;
106                 *data = t->data;
107                 return 1;
108         }
109
110         return 0;
111 }
112
113 int config_item_perf_lookup(
114                 const void *table,
115                 const char *section,
116                 const char *lvalue,
117                 ConfigParserCallback *func,
118                 int *ltype,
119                 void **data,
120                 void *userdata) {
121
122         ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
123         const ConfigPerfItem *p;
124
125         assert(table);
126         assert(lvalue);
127         assert(func);
128         assert(ltype);
129         assert(data);
130
131         if (!section)
132                 p = lookup(lvalue, strlen(lvalue));
133         else {
134                 char *key;
135
136                 key = strjoin(section, ".", lvalue, NULL);
137                 if (!key)
138                         return -ENOMEM;
139
140                 p = lookup(key, strlen(key));
141                 free(key);
142         }
143
144         if (!p)
145                 return 0;
146
147         *func = p->parse;
148         *ltype = p->ltype;
149         *data = (uint8_t*) userdata + p->offset;
150         return 1;
151 }
152
153 /* Run the user supplied parser for an assignment */
154 static int next_assignment(const char *unit,
155                            const char *filename,
156                            unsigned line,
157                            ConfigItemLookup lookup,
158                            const void *table,
159                            const char *section,
160                            unsigned section_line,
161                            const char *lvalue,
162                            const char *rvalue,
163                            bool relaxed,
164                            void *userdata) {
165
166         ConfigParserCallback func = NULL;
167         int ltype = 0;
168         void *data = NULL;
169         int r;
170
171         assert(filename);
172         assert(line > 0);
173         assert(lookup);
174         assert(lvalue);
175         assert(rvalue);
176
177         r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
178         if (r < 0)
179                 return r;
180
181         if (r > 0) {
182                 if (func)
183                         return func(unit, filename, line, section, section_line,
184                                     lvalue, ltype, rvalue, data, userdata);
185
186                 return 0;
187         }
188
189         /* Warn about unknown non-extension fields. */
190         if (!relaxed && !startswith(lvalue, "X-"))
191                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
192                            "Unknown lvalue '%s' in section '%s'", lvalue, section);
193
194         return 0;
195 }
196
197 /* Parse a variable assignment line */
198 static int parse_line(const char* unit,
199                       const char *filename,
200                       unsigned line,
201                       const char *sections,
202                       ConfigItemLookup lookup,
203                       const void *table,
204                       bool relaxed,
205                       bool allow_include,
206                       char **section,
207                       unsigned *section_line,
208                       bool *section_ignored,
209                       char *l,
210                       void *userdata) {
211
212         char *e;
213
214         assert(filename);
215         assert(line > 0);
216         assert(lookup);
217         assert(l);
218
219         l = strstrip(l);
220
221         if (!*l)
222                 return 0;
223
224         if (strchr(COMMENTS "\n", *l))
225                 return 0;
226
227         if (startswith(l, ".include ")) {
228                 _cleanup_free_ char *fn = NULL;
229
230                 /* .includes are a bad idea, we only support them here
231                  * for historical reasons. They create cyclic include
232                  * problems and make it difficult to detect
233                  * configuration file changes with an easy
234                  * stat(). Better approaches, such as .d/ drop-in
235                  * snippets exist.
236                  *
237                  * Support for them should be eventually removed. */
238
239                 if (!allow_include) {
240                         log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
241                                    ".include not allowed here. Ignoring.");
242                         return 0;
243                 }
244
245                 fn = file_in_same_dir(filename, strstrip(l+9));
246                 if (!fn)
247                         return -ENOMEM;
248
249                 return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
250         }
251
252         if (*l == '[') {
253                 size_t k;
254                 char *n;
255
256                 k = strlen(l);
257                 assert(k > 0);
258
259                 if (l[k-1] != ']') {
260                         log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
261                                    "Invalid section header '%s'", l);
262                         return -EBADMSG;
263                 }
264
265                 n = strndup(l+1, k-2);
266                 if (!n)
267                         return -ENOMEM;
268
269                 if (sections && !nulstr_contains(sections, n)) {
270
271                         if (!relaxed && !startswith(n, "X-"))
272                                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
273                                            "Unknown section '%s'. Ignoring.", n);
274
275                         free(n);
276                         free(*section);
277                         *section = NULL;
278                         *section_line = 0;
279                         *section_ignored = true;
280                 } else {
281                         free(*section);
282                         *section = n;
283                         *section_line = line;
284                         *section_ignored = false;
285                 }
286
287                 return 0;
288         }
289
290         if (sections && !*section) {
291
292                 if (!relaxed && !*section_ignored)
293                         log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
294                                    "Assignment outside of section. Ignoring.");
295
296                 return 0;
297         }
298
299         e = strchr(l, '=');
300         if (!e) {
301                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
302                 return -EBADMSG;
303         }
304
305         *e = 0;
306         e++;
307
308         return next_assignment(unit,
309                                filename,
310                                line,
311                                lookup,
312                                table,
313                                *section,
314                                *section_line,
315                                strstrip(l),
316                                strstrip(e),
317                                relaxed,
318                                userdata);
319 }
320
321 /* Go through the file and parse each line */
322 int config_parse(const char *unit,
323                  const char *filename,
324                  FILE *f,
325                  const char *sections,
326                  ConfigItemLookup lookup,
327                  const void *table,
328                  bool relaxed,
329                  bool allow_include,
330                  bool warn,
331                  void *userdata) {
332
333         _cleanup_free_ char *section = NULL, *continuation = NULL;
334         _cleanup_fclose_ FILE *ours = NULL;
335         unsigned line = 0, section_line = 0;
336         bool section_ignored = false;
337         int r;
338
339         assert(filename);
340         assert(lookup);
341
342         if (!f) {
343                 f = ours = fopen(filename, "re");
344                 if (!f) {
345                         /* Only log on request, except for ENOENT,
346                          * since we return 0 to the caller. */
347                         if (warn || errno == ENOENT)
348                                 log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
349                                          "Failed to open configuration file '%s': %m", filename);
350                         return errno == ENOENT ? 0 : -errno;
351                 }
352         }
353
354         fd_warn_permissions(filename, fileno(f));
355
356         while (!feof(f)) {
357                 char l[LINE_MAX], *p, *c = NULL, *e;
358                 bool escaped = false;
359
360                 if (!fgets(l, sizeof(l), f)) {
361                         if (feof(f))
362                                 break;
363
364                         log_error("Failed to read configuration file '%s': %m", filename);
365                         return -errno;
366                 }
367
368                 truncate_nl(l);
369
370                 if (continuation) {
371                         c = strappend(continuation, l);
372                         if (!c) {
373                                 if (warn)
374                                         log_oom();
375                                 return -ENOMEM;
376                         }
377
378                         free(continuation);
379                         continuation = NULL;
380                         p = c;
381                 } else
382                         p = l;
383
384                 for (e = p; *e; e++) {
385                         if (escaped)
386                                 escaped = false;
387                         else if (*e == '\\')
388                                 escaped = true;
389                 }
390
391                 if (escaped) {
392                         *(e-1) = ' ';
393
394                         if (c)
395                                 continuation = c;
396                         else {
397                                 continuation = strdup(l);
398                                 if (!continuation) {
399                                         if (warn)
400                                                 log_oom();
401                                         return -ENOMEM;
402                                 }
403                         }
404
405                         continue;
406                 }
407
408                 r = parse_line(unit,
409                                filename,
410                                ++line,
411                                sections,
412                                lookup,
413                                table,
414                                relaxed,
415                                allow_include,
416                                &section,
417                                &section_line,
418                                &section_ignored,
419                                p,
420                                userdata);
421                 free(c);
422
423                 if (r < 0) {
424                         if (warn)
425                                 log_warning("Failed to parse file '%s': %s",
426                                             filename, strerror(-r));
427                         return r;
428                 }
429         }
430
431         return 0;
432 }
433
434 /* Parse each config file in the specified directories. */
435 int config_parse_many(const char *conf_file,
436                       const char *conf_file_dirs,
437                       const char *sections,
438                       ConfigItemLookup lookup,
439                       const void *table,
440                       bool relaxed,
441                       void *userdata) {
442         _cleanup_strv_free_ char **files = NULL;
443         char **fn;
444         int r;
445
446         r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
447         if (r < 0)
448                 return r;
449
450         if (conf_file) {
451                 r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
452                 if (r < 0)
453                         return r;
454         }
455
456         STRV_FOREACH(fn, files) {
457                 r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
458                 if (r < 0)
459                         return r;
460         }
461
462         return 0;
463 }
464
465 #define DEFINE_PARSER(type, vartype, conv_func)                         \
466         int config_parse_##type(const char *unit,                       \
467                                 const char *filename,                   \
468                                 unsigned line,                          \
469                                 const char *section,                    \
470                                 unsigned section_line,                  \
471                                 const char *lvalue,                     \
472                                 int ltype,                              \
473                                 const char *rvalue,                     \
474                                 void *data,                             \
475                                 void *userdata) {                       \
476                                                                         \
477                 vartype *i = data;                                      \
478                 int r;                                                  \
479                                                                         \
480                 assert(filename);                                       \
481                 assert(lvalue);                                         \
482                 assert(rvalue);                                         \
483                 assert(data);                                           \
484                                                                         \
485                 r = conv_func(rvalue, i);                               \
486                 if (r < 0)                                              \
487                         log_syntax(unit, LOG_ERR, filename, line, -r,   \
488                                    "Failed to parse %s value, ignoring: %s", \
489                                    #vartype, rvalue);                   \
490                                                                         \
491                 return 0;                                               \
492         }
493
494 DEFINE_PARSER(int, int, safe_atoi)
495 DEFINE_PARSER(long, long, safe_atoli)
496 DEFINE_PARSER(uint64, uint64_t, safe_atou64)
497 DEFINE_PARSER(unsigned, unsigned, safe_atou)
498 DEFINE_PARSER(double, double, safe_atod)
499 DEFINE_PARSER(nsec, nsec_t, parse_nsec)
500 DEFINE_PARSER(sec, usec_t, parse_sec)
501
502 int config_parse_iec_size(const char* unit,
503                             const char *filename,
504                             unsigned line,
505                             const char *section,
506                             unsigned section_line,
507                             const char *lvalue,
508                             int ltype,
509                             const char *rvalue,
510                             void *data,
511                             void *userdata) {
512
513         size_t *sz = data;
514         off_t o;
515         int r;
516
517         assert(filename);
518         assert(lvalue);
519         assert(rvalue);
520         assert(data);
521
522         r = parse_size(rvalue, 1024, &o);
523         if (r < 0 || (off_t) (size_t) o != o) {
524                 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
525                 return 0;
526         }
527
528         *sz = (size_t) o;
529         return 0;
530 }
531
532 int config_parse_si_size(const char* unit,
533                             const char *filename,
534                             unsigned line,
535                             const char *section,
536                             unsigned section_line,
537                             const char *lvalue,
538                             int ltype,
539                             const char *rvalue,
540                             void *data,
541                             void *userdata) {
542
543         size_t *sz = data;
544         off_t o;
545         int r;
546
547         assert(filename);
548         assert(lvalue);
549         assert(rvalue);
550         assert(data);
551
552         r = parse_size(rvalue, 1000, &o);
553         if (r < 0 || (off_t) (size_t) o != o) {
554                 log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
555                 return 0;
556         }
557
558         *sz = (size_t) o;
559         return 0;
560 }
561
562 int config_parse_iec_off(const char* unit,
563                            const char *filename,
564                            unsigned line,
565                            const char *section,
566                            unsigned section_line,
567                            const char *lvalue,
568                            int ltype,
569                            const char *rvalue,
570                            void *data,
571                            void *userdata) {
572
573         off_t *bytes = data;
574         int r;
575
576         assert(filename);
577         assert(lvalue);
578         assert(rvalue);
579         assert(data);
580
581         assert_cc(sizeof(off_t) == sizeof(uint64_t));
582
583         r = parse_size(rvalue, 1024, bytes);
584         if (r < 0)
585                 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
586
587         return 0;
588 }
589
590 int config_parse_bool(const char* unit,
591                       const char *filename,
592                       unsigned line,
593                       const char *section,
594                       unsigned section_line,
595                       const char *lvalue,
596                       int ltype,
597                       const char *rvalue,
598                       void *data,
599                       void *userdata) {
600
601         int k;
602         bool *b = data;
603
604         assert(filename);
605         assert(lvalue);
606         assert(rvalue);
607         assert(data);
608
609         k = parse_boolean(rvalue);
610         if (k < 0) {
611                 log_syntax(unit, LOG_ERR, filename, line, -k,
612                            "Failed to parse boolean value, ignoring: %s", rvalue);
613                 return 0;
614         }
615
616         *b = !!k;
617         return 0;
618 }
619
620 int config_parse_string(
621                 const char *unit,
622                 const char *filename,
623                 unsigned line,
624                 const char *section,
625                 unsigned section_line,
626                 const char *lvalue,
627                 int ltype,
628                 const char *rvalue,
629                 void *data,
630                 void *userdata) {
631
632         char **s = data, *n;
633
634         assert(filename);
635         assert(lvalue);
636         assert(rvalue);
637         assert(data);
638
639         if (!utf8_is_valid(rvalue)) {
640                 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
641                 return 0;
642         }
643
644         if (isempty(rvalue))
645                 n = NULL;
646         else {
647                 n = strdup(rvalue);
648                 if (!n)
649                         return log_oom();
650         }
651
652         free(*s);
653         *s = n;
654
655         return 0;
656 }
657
658 int config_parse_path(
659                 const char *unit,
660                 const char *filename,
661                 unsigned line,
662                 const char *section,
663                 unsigned section_line,
664                 const char *lvalue,
665                 int ltype,
666                 const char *rvalue,
667                 void *data,
668                 void *userdata) {
669
670         char **s = data, *n;
671
672         assert(filename);
673         assert(lvalue);
674         assert(rvalue);
675         assert(data);
676
677         if (!utf8_is_valid(rvalue)) {
678                 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
679                 return 0;
680         }
681
682         if (!path_is_absolute(rvalue)) {
683                 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
684                 return 0;
685         }
686
687         n = strdup(rvalue);
688         if (!n)
689                 return log_oom();
690
691         path_kill_slashes(n);
692
693         free(*s);
694         *s = n;
695
696         return 0;
697 }
698
699 int config_parse_strv(const char *unit,
700                       const char *filename,
701                       unsigned line,
702                       const char *section,
703                       unsigned section_line,
704                       const char *lvalue,
705                       int ltype,
706                       const char *rvalue,
707                       void *data,
708                       void *userdata) {
709
710         char ***sv = data;
711         const char *word, *state;
712         size_t l;
713         int r;
714
715         assert(filename);
716         assert(lvalue);
717         assert(rvalue);
718         assert(data);
719
720         if (isempty(rvalue)) {
721                 char **empty;
722
723                 /* Empty assignment resets the list. As a special rule
724                  * we actually fill in a real empty array here rather
725                  * than NULL, since some code wants to know if
726                  * something was set at all... */
727                 empty = strv_new(NULL, NULL);
728                 if (!empty)
729                         return log_oom();
730
731                 strv_free(*sv);
732                 *sv = empty;
733                 return 0;
734         }
735
736         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
737                 char *n;
738
739                 n = strndup(word, l);
740                 if (!n)
741                         return log_oom();
742
743                 if (!utf8_is_valid(n)) {
744                         log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
745                         free(n);
746                         continue;
747                 }
748
749                 r = strv_consume(sv, n);
750                 if (r < 0)
751                         return log_oom();
752         }
753         if (!isempty(state))
754                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
755                            "Trailing garbage, ignoring.");
756
757         return 0;
758 }
759
760 int config_parse_mode(const char *unit,
761                       const char *filename,
762                       unsigned line,
763                       const char *section,
764                       unsigned section_line,
765                       const char *lvalue,
766                       int ltype,
767                       const char *rvalue,
768                       void *data,
769                       void *userdata) {
770
771         mode_t *m = data;
772         long l;
773         char *x = NULL;
774
775         assert(filename);
776         assert(lvalue);
777         assert(rvalue);
778         assert(data);
779
780         errno = 0;
781         l = strtol(rvalue, &x, 8);
782         if (!x || x == rvalue || *x || errno) {
783                 log_syntax(unit, LOG_ERR, filename, line, errno,
784                            "Failed to parse mode value, ignoring: %s", rvalue);
785                 return 0;
786         }
787
788         if (l < 0000 || l > 07777) {
789                 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
790                            "Mode value out of range, ignoring: %s", rvalue);
791                 return 0;
792         }
793
794         *m = (mode_t) l;
795         return 0;
796 }
797
798 int config_parse_log_facility(
799                 const char *unit,
800                 const char *filename,
801                 unsigned line,
802                 const char *section,
803                 unsigned section_line,
804                 const char *lvalue,
805                 int ltype,
806                 const char *rvalue,
807                 void *data,
808                 void *userdata) {
809
810
811         int *o = data, x;
812
813         assert(filename);
814         assert(lvalue);
815         assert(rvalue);
816         assert(data);
817
818         x = log_facility_unshifted_from_string(rvalue);
819         if (x < 0) {
820                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
821                            "Failed to parse log facility, ignoring: %s", rvalue);
822                 return 0;
823         }
824
825         *o = (x << 3) | LOG_PRI(*o);
826
827         return 0;
828 }
829
830 int config_parse_log_level(
831                 const char *unit,
832                 const char *filename,
833                 unsigned line,
834                 const char *section,
835                 unsigned section_line,
836                 const char *lvalue,
837                 int ltype,
838                 const char *rvalue,
839                 void *data,
840                 void *userdata) {
841
842
843         int *o = data, x;
844
845         assert(filename);
846         assert(lvalue);
847         assert(rvalue);
848         assert(data);
849
850         x = log_level_from_string(rvalue);
851         if (x < 0) {
852                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
853                            "Failed to parse log level, ignoring: %s", rvalue);
854                 return 0;
855         }
856
857         *o = (*o & LOG_FACMASK) | x;
858         return 0;
859 }