chiark / gitweb /
exec: introduce ControlGroupPersistant= to make cgroups persistant
[elogind.git] / src / 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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <stdlib.h>
27
28 #include "conf-parser.h"
29 #include "util.h"
30 #include "macro.h"
31 #include "strv.h"
32 #include "log.h"
33
34 int config_item_table_lookup(
35                 void *table,
36                 const char *section,
37                 const char *lvalue,
38                 ConfigParserCallback *func,
39                 int *ltype,
40                 void **data,
41                 void *userdata) {
42
43         ConfigTableItem *t;
44
45         assert(table);
46         assert(lvalue);
47         assert(func);
48         assert(ltype);
49         assert(data);
50
51         for (t = table; t->lvalue; t++) {
52
53                 if (!streq(lvalue, t->lvalue))
54                         continue;
55
56                 if (!streq_ptr(section, t->section))
57                         continue;
58
59                 *func = t->parse;
60                 *ltype = t->ltype;
61                 *data = t->data;
62                 return 1;
63         }
64
65         return 0;
66 }
67
68 int config_item_perf_lookup(
69                 void *table,
70                 const char *section,
71                 const char *lvalue,
72                 ConfigParserCallback *func,
73                 int *ltype,
74                 void **data,
75                 void *userdata) {
76
77         ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
78         const ConfigPerfItem *p;
79
80         assert(table);
81         assert(lvalue);
82         assert(func);
83         assert(ltype);
84         assert(data);
85
86         if (!section)
87                 p = lookup(lvalue, strlen(lvalue));
88         else {
89                 char *key;
90
91                 key = join(section, ".", lvalue, NULL);
92                 if (!key)
93                         return -ENOMEM;
94
95                 p = lookup(key, strlen(key));
96                 free(key);
97         }
98
99         if (!p)
100                 return 0;
101
102         *func = p->parse;
103         *ltype = p->ltype;
104         *data = (uint8_t*) userdata + p->offset;
105         return 1;
106 }
107
108 /* Run the user supplied parser for an assignment */
109 static int next_assignment(
110                 const char *filename,
111                 unsigned line,
112                 ConfigItemLookup lookup,
113                 void *table,
114                 const char *section,
115                 const char *lvalue,
116                 const char *rvalue,
117                 bool relaxed,
118                 void *userdata) {
119
120         ConfigParserCallback func = NULL;
121         int ltype = 0;
122         void *data = NULL;
123         int r;
124
125         assert(filename);
126         assert(line > 0);
127         assert(lookup);
128         assert(lvalue);
129         assert(rvalue);
130
131         r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
132         if (r < 0)
133                 return r;
134
135         if (r > 0) {
136                 if (func)
137                         return func(filename, line, section, lvalue, ltype, rvalue, data, userdata);
138
139                 return 0;
140         }
141
142         /* Warn about unknown non-extension fields. */
143         if (!relaxed && !startswith(lvalue, "X-"))
144                 log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section);
145
146         return 0;
147 }
148
149 /* Parse a variable assignment line */
150 static int parse_line(
151                 const char *filename,
152                 unsigned line,
153                 const char *sections,
154                 ConfigItemLookup lookup,
155                 void *table,
156                 bool relaxed,
157                 char **section,
158                 char *l,
159                 void *userdata) {
160
161         char *e;
162
163         assert(filename);
164         assert(line > 0);
165         assert(lookup);
166         assert(l);
167
168         l = strstrip(l);
169
170         if (!*l)
171                 return 0;
172
173         if (strchr(COMMENTS, *l))
174                 return 0;
175
176         if (startswith(l, ".include ")) {
177                 char *fn;
178                 int r;
179
180                 fn = file_in_same_dir(filename, strstrip(l+9));
181                 if (!fn)
182                         return -ENOMEM;
183
184                 r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata);
185                 free(fn);
186
187                 return r;
188         }
189
190         if (*l == '[') {
191                 size_t k;
192                 char *n;
193
194                 k = strlen(l);
195                 assert(k > 0);
196
197                 if (l[k-1] != ']') {
198                         log_error("[%s:%u] Invalid section header.", filename, line);
199                         return -EBADMSG;
200                 }
201
202                 n = strndup(l+1, k-2);
203                 if (!n)
204                         return -ENOMEM;
205
206                 if (sections && !nulstr_contains(sections, n)) {
207
208                         if (!relaxed)
209                                 log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n);
210
211                         free(n);
212                         *section = NULL;
213                 } else {
214                         free(*section);
215                         *section = n;
216                 }
217
218                 return 0;
219         }
220
221         if (sections && !*section)
222                 return 0;
223
224         e = strchr(l, '=');
225         if (!e) {
226                 log_error("[%s:%u] Missing '='.", filename, line);
227                 return -EBADMSG;
228         }
229
230         *e = 0;
231         e++;
232
233         return next_assignment(
234                         filename,
235                         line,
236                         lookup,
237                         table,
238                         *section,
239                         strstrip(l),
240                         strstrip(e),
241                         relaxed,
242                         userdata);
243 }
244
245 /* Go through the file and parse each line */
246 int config_parse(
247                 const char *filename,
248                 FILE *f,
249                 const char *sections,
250                 ConfigItemLookup lookup,
251                 void *table,
252                 bool relaxed,
253                 void *userdata) {
254
255         unsigned line = 0;
256         char *section = NULL;
257         int r;
258         bool ours = false;
259         char *continuation = NULL;
260
261         assert(filename);
262         assert(lookup);
263
264         if (!f) {
265                 f = fopen(filename, "re");
266                 if (!f) {
267                         r = -errno;
268                         log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
269                         goto finish;
270                 }
271
272                 ours = true;
273         }
274
275         while (!feof(f)) {
276                 char l[LINE_MAX], *p, *c = NULL, *e;
277                 bool escaped = false;
278
279                 if (!fgets(l, sizeof(l), f)) {
280                         if (feof(f))
281                                 break;
282
283                         r = -errno;
284                         log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
285                         goto finish;
286                 }
287
288                 truncate_nl(l);
289
290                 if (continuation) {
291                         c = strappend(continuation, l);
292                         if (!c) {
293                                 r = -ENOMEM;
294                                 goto finish;
295                         }
296
297                         free(continuation);
298                         continuation = NULL;
299                         p = c;
300                 } else
301                         p = l;
302
303                 for (e = p; *e; e++) {
304                         if (escaped)
305                                 escaped = false;
306                         else if (*e == '\\')
307                                 escaped = true;
308                 }
309
310                 if (escaped) {
311                         *(e-1) = ' ';
312
313                         if (c)
314                                 continuation = c;
315                         else {
316                                 continuation = strdup(l);
317                                 if (!continuation) {
318                                         r = -ENOMEM;
319                                         goto finish;
320                                 }
321                         }
322
323                         continue;
324                 }
325
326                 r = parse_line(filename,
327                                 ++line,
328                                 sections,
329                                 lookup,
330                                 table,
331                                 relaxed,
332                                 &section,
333                                 p,
334                                 userdata);
335                 free(c);
336
337                 if (r < 0)
338                         goto finish;
339         }
340
341         r = 0;
342
343 finish:
344         free(section);
345         free(continuation);
346
347         if (f && ours)
348                 fclose(f);
349
350         return r;
351 }
352
353 int config_parse_int(
354                 const char *filename,
355                 unsigned line,
356                 const char *section,
357                 const char *lvalue,
358                 int ltype,
359                 const char *rvalue,
360                 void *data,
361                 void *userdata) {
362
363         int *i = data;
364         int r;
365
366         assert(filename);
367         assert(lvalue);
368         assert(rvalue);
369         assert(data);
370
371         if ((r = safe_atoi(rvalue, i)) < 0) {
372                 log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue);
373                 return 0;
374         }
375
376         return 0;
377 }
378
379 int config_parse_long(
380                 const char *filename,
381                 unsigned line,
382                 const char *section,
383                 const char *lvalue,
384                 int ltype,
385                 const char *rvalue,
386                 void *data,
387                 void *userdata) {
388
389         long *i = data;
390         int r;
391
392         assert(filename);
393         assert(lvalue);
394         assert(rvalue);
395         assert(data);
396
397         if ((r = safe_atoli(rvalue, i)) < 0) {
398                 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
399                 return 0;
400         }
401
402         return 0;
403 }
404
405 int config_parse_uint64(
406                 const char *filename,
407                 unsigned line,
408                 const char *section,
409                 const char *lvalue,
410                 int ltype,
411                 const char *rvalue,
412                 void *data,
413                 void *userdata) {
414
415         uint64_t *u = data;
416         int r;
417
418         assert(filename);
419         assert(lvalue);
420         assert(rvalue);
421         assert(data);
422
423         if ((r = safe_atou64(rvalue, u)) < 0) {
424                 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
425                 return 0;
426         }
427
428         return 0;
429 }
430
431 int config_parse_unsigned(
432                 const char *filename,
433                 unsigned line,
434                 const char *section,
435                 const char *lvalue,
436                 int ltype,
437                 const char *rvalue,
438                 void *data,
439                 void *userdata) {
440
441         unsigned *u = data;
442         int r;
443
444         assert(filename);
445         assert(lvalue);
446         assert(rvalue);
447         assert(data);
448
449         if ((r = safe_atou(rvalue, u)) < 0) {
450                 log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
451                 return r;
452         }
453
454         return 0;
455 }
456
457 int config_parse_size(
458                 const char *filename,
459                 unsigned line,
460                 const char *section,
461                 const char *lvalue,
462                 int ltype,
463                 const char *rvalue,
464                 void *data,
465                 void *userdata) {
466
467         size_t *sz = data;
468         unsigned u;
469         int r;
470
471         assert(filename);
472         assert(lvalue);
473         assert(rvalue);
474         assert(data);
475
476         if ((r = safe_atou(rvalue, &u)) < 0) {
477                 log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
478                 return 0;
479         }
480
481         *sz = (size_t) u;
482         return 0;
483 }
484
485 int config_parse_bool(
486                 const char *filename,
487                 unsigned line,
488                 const char *section,
489                 const char *lvalue,
490                 int ltype,
491                 const char *rvalue,
492                 void *data,
493                 void *userdata) {
494
495         int k;
496         bool *b = data;
497
498         assert(filename);
499         assert(lvalue);
500         assert(rvalue);
501         assert(data);
502
503         if ((k = parse_boolean(rvalue)) < 0) {
504                 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
505                 return 0;
506         }
507
508         *b = !!k;
509         return 0;
510 }
511
512 int config_parse_tristate(
513                 const char *filename,
514                 unsigned line,
515                 const char *section,
516                 const char *lvalue,
517                 int ltype,
518                 const char *rvalue,
519                 void *data,
520                 void *userdata) {
521
522         int k;
523         int *b = data;
524
525         assert(filename);
526         assert(lvalue);
527         assert(rvalue);
528         assert(data);
529
530         /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */
531
532         k = parse_boolean(rvalue);
533         if (k < 0) {
534                 log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue);
535                 return 0;
536         }
537
538         *b = !!k;
539         return 0;
540 }
541
542 int config_parse_string(
543                 const char *filename,
544                 unsigned line,
545                 const char *section,
546                 const char *lvalue,
547                 int ltype,
548                 const char *rvalue,
549                 void *data,
550                 void *userdata) {
551
552         char **s = data;
553         char *n;
554
555         assert(filename);
556         assert(lvalue);
557         assert(rvalue);
558         assert(data);
559
560         if (*rvalue) {
561                 if (!(n = strdup(rvalue)))
562                         return -ENOMEM;
563         } else
564                 n = NULL;
565
566         free(*s);
567         *s = n;
568
569         return 0;
570 }
571
572 int config_parse_path(
573                 const char *filename,
574                 unsigned line,
575                 const char *section,
576                 const char *lvalue,
577                 int ltype,
578                 const char *rvalue,
579                 void *data,
580                 void *userdata) {
581
582         char **s = data;
583         char *n;
584
585         assert(filename);
586         assert(lvalue);
587         assert(rvalue);
588         assert(data);
589
590         if (!path_is_absolute(rvalue)) {
591                 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
592                 return 0;
593         }
594
595         if (!(n = strdup(rvalue)))
596                 return -ENOMEM;
597
598         path_kill_slashes(n);
599
600         free(*s);
601         *s = n;
602
603         return 0;
604 }
605
606 int config_parse_strv(
607                 const char *filename,
608                 unsigned line,
609                 const char *section,
610                 const char *lvalue,
611                 int ltype,
612                 const char *rvalue,
613                 void *data,
614                 void *userdata) {
615
616         char*** sv = data;
617         char **n;
618         char *w;
619         unsigned k;
620         size_t l;
621         char *state;
622
623         assert(filename);
624         assert(lvalue);
625         assert(rvalue);
626         assert(data);
627
628         k = strv_length(*sv);
629         FOREACH_WORD_QUOTED(w, l, rvalue, state)
630                 k++;
631
632         if (!(n = new(char*, k+1)))
633                 return -ENOMEM;
634
635         if (*sv)
636                 for (k = 0; (*sv)[k]; k++)
637                         n[k] = (*sv)[k];
638         else
639                 k = 0;
640
641         FOREACH_WORD_QUOTED(w, l, rvalue, state)
642                 if (!(n[k++] = cunescape_length(w, l)))
643                         goto fail;
644
645         n[k] = NULL;
646         free(*sv);
647         *sv = n;
648
649         return 0;
650
651 fail:
652         for (; k > 0; k--)
653                 free(n[k-1]);
654         free(n);
655
656         return -ENOMEM;
657 }
658
659 int config_parse_path_strv(
660                 const char *filename,
661                 unsigned line,
662                 const char *section,
663                 const char *lvalue,
664                 int ltype,
665                 const char *rvalue,
666                 void *data,
667                 void *userdata) {
668
669         char*** sv = data;
670         char **n;
671         char *w;
672         unsigned k;
673         size_t l;
674         char *state;
675         int r;
676
677         assert(filename);
678         assert(lvalue);
679         assert(rvalue);
680         assert(data);
681
682         k = strv_length(*sv);
683         FOREACH_WORD_QUOTED(w, l, rvalue, state)
684                 k++;
685
686         if (!(n = new(char*, k+1)))
687                 return -ENOMEM;
688
689         k = 0;
690         if (*sv)
691                 for (; (*sv)[k]; k++)
692                         n[k] = (*sv)[k];
693
694         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
695                 if (!(n[k] = cunescape_length(w, l))) {
696                         r = -ENOMEM;
697                         goto fail;
698                 }
699
700                 if (!path_is_absolute(n[k])) {
701                         log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
702                         free(n[k]);
703                         continue;
704                 }
705
706                 path_kill_slashes(n[k]);
707
708                 k++;
709         }
710
711         n[k] = NULL;
712         free(*sv);
713         *sv = n;
714
715         return 0;
716
717 fail:
718         free(n[k]);
719         for (; k > 0; k--)
720                 free(n[k-1]);
721         free(n);
722
723         return r;
724 }
725
726 int config_parse_usec(
727                 const char *filename,
728                 unsigned line,
729                 const char *section,
730                 const char *lvalue,
731                 int ltype,
732                 const char *rvalue,
733                 void *data,
734                 void *userdata) {
735
736         usec_t *usec = data;
737
738         assert(filename);
739         assert(lvalue);
740         assert(rvalue);
741         assert(data);
742
743         if (parse_usec(rvalue, usec) < 0) {
744                 log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
745                 return 0;
746         }
747
748         return 0;
749 }
750
751 int config_parse_mode(
752                 const char *filename,
753                 unsigned line,
754                 const char *section,
755                 const char *lvalue,
756                 int ltype,
757                 const char *rvalue,
758                 void *data,
759                 void *userdata) {
760
761         mode_t *m = data;
762         long l;
763         char *x = NULL;
764
765         assert(filename);
766         assert(lvalue);
767         assert(rvalue);
768         assert(data);
769
770         errno = 0;
771         l = strtol(rvalue, &x, 8);
772         if (!x || *x || errno) {
773                 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
774                 return 0;
775         }
776
777         if (l < 0000 || l > 07777) {
778                 log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
779                 return 0;
780         }
781
782         *m = (mode_t) l;
783         return 0;
784 }
785
786 int config_parse_bytes(
787                 const char *filename,
788                 unsigned line,
789                 const char *section,
790                 const char *lvalue,
791                 int ltype,
792                 const char *rvalue,
793                 void *data,
794                 void *userdata) {
795
796         off_t *bytes = data;
797
798         assert(filename);
799         assert(lvalue);
800         assert(rvalue);
801         assert(data);
802
803         assert_cc(sizeof(off_t) == sizeof(uint64_t));
804
805         if (parse_bytes(rvalue, bytes) < 0) {
806                 log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue);
807                 return 0;
808         }
809
810         return 0;
811 }