1 /* cfg.c - Configuration file parser
3 * Copyright 1992-1997 Werner Almesberger
4 * Copyright 1999-2007 John Coffman
5 * Copyright 2009-2010 Joachim Wiedorn
8 * Licensed under the terms contained in the file 'COPYING'
9 * in the source directory.
27 #define NEW_PARSE !__MSDOS__
29 #define MAX_VAR_NAME MAX_TOKEN
32 extern void do_image(void);
33 extern void do_other(void);
34 extern void do_disk(void);
35 extern void do_partition(void);
37 extern void id_image(void);
38 extern void id_other(void);
40 extern void do_map_drive(void);
41 extern void do_cr(void);
42 extern void do_change(void);
43 extern void do_cr_type(void);
44 extern void do_cr_reset(void);
45 extern void do_cr_part(void);
46 extern void do_cr_auto(void);
50 { cft_strg, "image", do_image, NULL,NULL },
51 { cft_strg, "other", do_other, NULL,NULL },
52 { cft_end, NULL, NULL, NULL,NULL }};
54 CONFIG cf_identify[] = {
55 { cft_strg, "image", id_image, NULL,NULL },
56 { cft_strg, "other", id_other, NULL,NULL },
57 { cft_end, NULL, NULL, NULL,NULL }};
58 #endif /* !__MSDOS__ */
60 CONFIG cf_options[] = {
62 { cft_strg, "append", NULL, NULL,NULL },
63 { cft_strg, "backup", NULL, NULL,NULL },
64 { cft_strg, "bios-passes-dl", NULL, NULL,NULL },
65 { cft_strg, "bitmap", NULL, NULL,NULL },
66 { cft_strg, "bmp-colors", NULL, NULL,NULL },
67 { cft_flag, "bmp-retain", NULL, NULL,NULL },
68 { cft_strg, "bmp-table", NULL, NULL,NULL },
69 { cft_strg, "bmp-timer", NULL, NULL,NULL },
70 { cft_strg, "boot", NULL, NULL,NULL },
71 { cft_strg, "boot-as", NULL, NULL,NULL },
72 { cft_flag, "change-rules", do_cr, NULL,NULL },
73 { cft_flag, "compact", NULL, NULL,NULL },
74 { cft_strg, "default", NULL, NULL,NULL },
75 { cft_strg, "delay", NULL, NULL,NULL },
76 { cft_strg, "disk", do_disk, NULL,NULL },
77 { cft_strg, "disktab", NULL, NULL,NULL },
78 { cft_flag, "el-torito-bootable-cd", NULL, NULL,NULL },
79 { cft_strg, "fallback", NULL, NULL,NULL },
80 { cft_flag, "fix-table", NULL, NULL,NULL },
81 { cft_strg, "force-backup", NULL, NULL,NULL },
82 { cft_flag, "geometric", NULL, NULL,NULL },
83 { cft_flag, "ignore-table", NULL, NULL,NULL },
84 { cft_strg, "initrd", NULL, NULL,NULL },
85 { cft_strg, "install", NULL, NULL,NULL },
86 { cft_strg, "keytable", NULL, NULL,NULL },
87 { cft_flag, "large-memory", NULL, NULL,NULL },
88 { cft_flag, "lba32", NULL, NULL,NULL },
89 { cft_flag, "linear", NULL, NULL,NULL },
90 { cft_strg, "loader", NULL, NULL,NULL },
91 { cft_flag, "lock", NULL, NULL,NULL },
92 { cft_flag, "mandatory", NULL, NULL,NULL },
93 #endif /* !__MSDOS__ */
94 { cft_strg, "map", NULL, NULL,NULL },
96 { cft_flag, "master-boot", NULL, NULL,NULL },
97 { cft_strg, "menu-scheme", NULL, NULL,NULL },
98 { cft_strg, "menu-title", NULL, NULL,NULL },
99 { cft_strg, "message", NULL, NULL,NULL },
100 { cft_flag, "nodevcache", NULL, NULL,NULL },
101 #ifdef LCF_NOKEYBOARD
102 { cft_strg, "nokbdefault", NULL, NULL,NULL },
104 { cft_flag, "noraid", NULL, NULL,NULL },
105 { cft_flag, "nowarn", NULL, NULL,NULL },
106 { cft_flag, "optional", NULL, NULL,NULL },
107 { cft_strg, "password", NULL, NULL,NULL },
108 { cft_flag, "prompt", NULL, NULL,NULL },
109 { cft_strg, RAID_EXTRA_BOOT, NULL, NULL,NULL },
110 { cft_strg, "ramdisk", NULL, NULL,NULL },
111 { cft_flag, "read-only", NULL, NULL,NULL },
112 { cft_flag, "read-write", NULL, NULL,NULL },
113 { cft_flag, "restricted", NULL, NULL,NULL },
114 { cft_strg, "root", NULL, NULL,NULL },
115 { cft_strg, "serial", NULL, NULL,NULL },
116 { cft_flag, "single-key", NULL, NULL,NULL },
117 { cft_flag, "small-memory", NULL, NULL,NULL },
118 { cft_flag, "static-bios-codes", NULL, NULL,NULL },
119 { cft_flag, "suppress-boot-time-BIOS-data", NULL, NULL,NULL },
120 { cft_strg, "timeout", NULL, NULL,NULL },
121 { cft_flag, "unattended", NULL, NULL,NULL },
122 { cft_strg, "verbose", NULL, NULL,NULL },
123 { cft_strg, "vga", NULL, NULL,NULL },
125 { cft_strg, "vmdefault", NULL, NULL,NULL },
127 #endif /* !__MSDOS__ */
128 { cft_end, NULL, NULL, NULL,NULL }};
132 { cft_strg, "alias", NULL, NULL,NULL },
133 { cft_flag, "bmp-retain", NULL, NULL,NULL },
134 { cft_flag, "bypass", NULL, NULL,NULL },
135 { cft_strg, "fallback", NULL, NULL,NULL },
136 { cft_strg, "label", NULL, NULL,NULL },
137 { cft_strg, "literal", NULL, NULL,NULL },
138 { cft_flag, "lock", NULL, NULL,NULL },
139 { cft_flag, "mandatory", NULL, NULL,NULL },
140 #ifdef LCF_NOKEYBOARD
141 { cft_flag, "nokbdisable", NULL, NULL,NULL },
143 { cft_flag, "optional", NULL, NULL,NULL },
144 { cft_strg, "password", NULL, NULL,NULL },
145 { cft_flag, "restricted", NULL, NULL,NULL },
146 { cft_flag, "single-key", NULL, NULL,NULL },
148 { cft_flag, "vmdisable", NULL, NULL,NULL },
149 { cft_flag, "vmwarn", NULL, NULL,NULL },
151 { cft_end, NULL, NULL, NULL,NULL }};
153 CONFIG cf_kernel[] = {
154 { cft_strg, "addappend", NULL, NULL,NULL },
155 { cft_strg, "append", NULL, NULL,NULL },
156 { cft_strg, "initrd", NULL, NULL,NULL },
157 { cft_strg, "ramdisk", NULL, NULL,NULL },
158 { cft_flag, "read-only", NULL, NULL,NULL },
159 { cft_flag, "read-write", NULL, NULL,NULL },
160 { cft_strg, "root", NULL, NULL,NULL },
161 { cft_strg, "vga", NULL, NULL,NULL },
162 { cft_link, NULL, &cf_all, NULL,NULL }};
164 CONFIG cf_image[] = {
165 { cft_strg, "range", NULL, NULL,NULL },
166 { cft_link, NULL, &cf_kernel, NULL,NULL }};
168 CONFIG cf_other[] = {
169 { cft_strg, "boot-as", NULL, NULL,NULL },
170 { cft_flag, "change", do_change, NULL,NULL },
171 { cft_strg, "loader", NULL, NULL,NULL },
172 { cft_strg, "map-drive", do_map_drive, NULL,NULL },
173 { cft_flag, "master-boot", NULL, NULL,NULL },
174 { cft_strg, "table", NULL, NULL,NULL },
175 { cft_flag, "unsafe", NULL, NULL,NULL },
176 { cft_link, NULL, &cf_all, NULL,NULL }};
179 { cft_strg, "bios", NULL, NULL,NULL },
180 { cft_strg, "cylinders", NULL, NULL,NULL },
181 { cft_strg, "heads", NULL, NULL,NULL },
182 { cft_flag, "inaccessible", NULL, NULL,NULL },
183 { cft_strg, "max-partitions", NULL, NULL,NULL },
184 { cft_strg, "sectors", NULL, NULL,NULL },
185 { cft_end, NULL, NULL, NULL,NULL }};
187 CONFIG cf_partitions[] = {
188 { cft_strg, "partition", do_partition, NULL,NULL },
189 { cft_end, NULL, NULL, NULL,NULL }};
191 CONFIG cf_partition[] = {
192 { cft_strg, "start", NULL, NULL,NULL },
193 { cft_end, NULL, NULL, NULL,NULL }};
195 CONFIG cf_map_drive[] = {
196 { cft_strg, "to", NULL, NULL,NULL },
197 { cft_end, NULL, NULL, NULL,NULL }};
199 CONFIG cf_change_rules[] = {
200 { cft_flag, "reset", do_cr_reset, NULL,NULL },
201 { cft_strg, "type", do_cr_type, NULL,NULL },
202 { cft_end, NULL, NULL, NULL,NULL }};
204 CONFIG cf_change_rule[] = {
205 { cft_strg, "hidden", NULL, NULL,NULL },
206 { cft_strg, "normal", NULL, NULL,NULL },
207 { cft_end, NULL, NULL, NULL,NULL }};
209 CONFIG cf_change[] = {
210 { cft_flag, "automatic", do_cr_auto, NULL,NULL },
211 { cft_strg, "partition", do_cr_part, NULL,NULL },
212 { cft_end, NULL, NULL, NULL,NULL }};
214 CONFIG cf_change_dsc[] = {
215 { cft_flag, "activate", NULL, NULL,NULL },
216 { cft_flag, "deactivate", NULL, NULL,NULL },
217 { cft_strg, "set", NULL, NULL,NULL },
218 { cft_end, NULL, NULL, NULL,NULL }};
220 CONFIG cf_bitmap[] = {
221 { cft_strg, "bitmap", NULL, NULL,NULL },
222 { cft_strg, "bmp-colors", NULL, NULL,NULL },
223 { cft_strg, "bmp-table", NULL, NULL,NULL },
224 { cft_strg, "bmp-timer", NULL, NULL,NULL },
225 { cft_end, NULL, NULL, NULL,NULL }};
226 #endif /* !__MSDOS__ */
230 static CONFIG *keywords[] = {cf_top, cf_identify, cf_options, cf_all,
231 cf_kernel, cf_image, cf_other, cf_disk, cf_partitions, cf_partition,
232 cf_map_drive, cf_change_rules, cf_change_rule, cf_change,
233 cf_change_dsc, cf_bitmap, NULL };
238 static char flag_set;
239 static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
241 static char *file_name = NULL;
242 static int back = 0; /* can go back by one char */
245 int cfg_open(char *name)
248 if (!strcmp(name,"-")) file = stdin;
251 else if (!strcasecmp(name,"none")) return -1;
252 #endif /* __MSDOS__ */
254 else if (!(file = fopen(file_name = name,"r"))) {
256 die("Cannot open: %s", name);
257 #else /* __MSDOS__ */
258 warn("No configuration file: %s\n", name);
260 #endif /* __MSDOS__ */
267 void cfg_error(char *msg,...)
273 vfprintf(errstd,msg,ap);
275 if (!file_name) fputc('\n',errstd);
276 else fprintf(errstd," at or above line %d in file '%s'\n",line_num,file_name);
281 static int next_raw(void)
285 if (!back) return getc(file);
292 static int next(void)
295 char buffer[MAX_VAR_NAME+1];
304 if (var && *var) return *var++;
306 if (ch == '\r') /* strip DOS <cr> */
310 if (ch == '$') return ch;
314 if (ch != '$') return ch;
318 if (!braced) *put++ = ch;
322 if (!braced && ch < ' ') {
327 if (ch == EOF) cfg_error("EOF in variable name");
328 if (ch < ' ') cfg_error("control character in variable name");
329 if (braced && ch == '}') break;
330 if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
334 if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
339 if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
340 #endif /* !__MSDOS__ */
345 static void again(int ch)
347 if (back) die("internal error: again invoked twice");
352 static char *cfg_get_token(void)
354 char buf[MAX_TOKEN+1];
364 while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
365 if (ch == '\n') line_num++;
366 if (ch == EOF) return NULL;
367 if (ch != '#') break;
368 while ((ch = next_raw()), ch != '\n')
369 if (ch == EOF) return NULL;
372 if (ch == '=') return stralloc("=");
375 while (here-buf < MAX_TOKEN) {
376 if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
379 return stralloc(buf);
383 if (ch != '"' && ch != '\\' && ch != '\n')
384 cfg_error("Bad use of \\ in quoted string");
386 while ((ch = next()), ch == ' ' || ch == '\t');
392 if (ch == '\n' || ch == '\t')
393 cfg_error("\\n and \\t are not allowed in quoted strings");
396 cfg_error("Quoted string is too long");
397 return 0; /* not reached */
401 while (here-buf < MAX_TOKEN) {
403 if (ch == EOF) cfg_error("\\ precedes EOF");
404 if (ch == '\n') line_num++;
405 else *here++ = ch == '\t' ? ' ' : ch;
409 if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
410 ch == '=' || ch == EOF) {
413 return stralloc(buf);
416 if (!(escaped = (ch == '\\')))
417 #endif /* !__MSDOS__ */
422 cfg_error("Token is too long");
423 return 0; /* not reached */
427 static void cfg_return_token(char *token)
433 static int cfg_next(char **item,char **value)
444 if (!(*item = cfg_get_token())) return 0;
445 if (!strcmp(*item,"=")) cfg_error("Syntax error");
446 if (!(this = cfg_get_token())) return 1;
447 if (strcmp(this,"=")) {
448 cfg_return_token(this);
451 if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
452 if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
457 static void cfg_return(char *item,char *value)
464 void cfg_init(CONFIG *table)
466 while (table->type != cft_end) {
467 switch (table->type) {
469 if (table->data) free(table->data);
474 table = ((CONFIG *) table->action)-1;
477 die("Unknown syntax code %d",table->type);
484 static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
489 for (walk = table; walk->type != cft_end; walk++) {
490 if (walk->name && !strcasecmp(walk->name,item)) {
491 if (value && walk->type != cft_strg)
492 cfg_error("'%s' doesn't have a value",walk->name);
493 if (!value && walk->type == cft_strg)
494 cfg_error("Value expected for '%s'",walk->name);
496 if (walk->context == context)
497 cfg_error("Duplicate entry '%s'",walk->name);
499 warn("Ignoring entry '%s'",walk->name);
500 if (!copy) free(value);
504 if (walk->type == cft_flag) walk->data = &flag_set;
505 else if (walk->type == cft_strg)
506 walk->data = copy ? stralloc(value) : value;
507 walk->context = context;
508 if (walk->action) ((void (*)(void)) walk->action)();
511 if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
513 if (walk->type != cft_end) return 1;
514 cfg_return(item,value);
519 void cfg_set(CONFIG *table,char *item,char *value,void *context)
521 if (cfg_do_set(table,item,value,1,context) != 1)
522 cfg_error("cfg_set: Can't set %s",item);
526 void cfg_unset(CONFIG *table,char *item)
530 for (walk = table; walk->type != cft_end; walk++)
531 if (walk->name && !strcasecmp(walk->name,item)) {
532 if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
533 if (walk->type == cft_strg) free(walk->data);
537 die("internal error (cfg_unset %s, unknown",item);
542 static int cfg_end (char *item)
548 while ((c = *key++)) {
550 if (!strcasecmp(c->name, item)) return 1;
559 int cfg_parse(CONFIG *table)
564 if (!cfg_next(&item,&value)) return 0;
565 if(verbose>=6) printf("cfg_parse: item=\"%s\" value=\"%s\"\n", item, value);
566 if (!cfg_do_set(table,item,value,0,table)) {
570 if (cfg_end(item)) return 1;
571 else cfg_error("Unrecognized token \"%s\"", item);
579 int cfg_get_flag(CONFIG *table,char *item)
583 for (walk = table; walk->type != cft_end; walk++) {
584 if (walk->name && !strcasecmp(walk->name,item)) {
585 if (walk->type != cft_flag)
586 die("cfg_get_flag: operating on non-flag %s",item);
589 if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
591 die("cfg_get_flag: unknown item %s",item);
592 return 0; /* not reached */
596 char *cfg_get_strg(CONFIG *table,char *item)
600 for (walk = table; walk->type != cft_end; walk++) {
601 if (walk->name && !strcasecmp(walk->name,item)) {
602 if (walk->type != cft_strg)
603 die("cfg_get_strg: operating on non-string %s",item);
606 if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
608 die("cfg_get_strg: unknown item %s",item);
609 return 0; /* not reached */
614 /* open the password file, passw=1 forces a new file to be created */
616 static char *pw_file_name;
617 FILE *pw_file = NULL;
619 FILE *cfg_pw_open(void)
621 char name[MAX_TOKEN+1];
626 strcpy(name, file_name); /* copy name of config file '/etc/lilo.conf' */
627 strcat(name, PW_FILE_SUFFIX);
628 pw_file_name = stralloc(name);
630 if (stat(file_name, &buf)) die("Cannot stat '%s'", file_name);
632 if (!stat(pw_file_name, &buf) && conf>buf.st_mtime && !passw) {
633 warn("'%s' more recent than '%s'\n"
634 " Running 'lilo -p' is recommended.",
635 file_name, pw_file_name);
640 if (unlink(pw_file_name) && errno != ENOENT) die("Could not delete '%s'", pw_file_name);
641 if ((fd = creat(pw_file_name, 0600)) < 0) die("Could not create '%s'", pw_file_name);
643 pw_file = fopen(pw_file_name, "w+");
645 else if (passw) return (pw_file=NULL);
647 if (!(pw_file = fopen(pw_file_name, "r"))) {
649 passw = 1; /* force writing */
650 if ((fd = creat(pw_file_name, 0600)) < 0) die("Could not create '%s'", pw_file_name);
652 pw_file = fopen(pw_file_name, "w+");
654 else return (pw_file=NULL);
657 if (!pw_file) die("Could not create '%s'", pw_file_name);
659 if (!stat(pw_file_name, &buf) && (buf.st_mode&0044) ) {
660 warn("'%s' readable by other than 'root'", pw_file_name);
667 /* allow only the "bitmap" keywords */
669 void cfg_bitmap_only(void)
671 keywords[0] = cf_bitmap;
676 void cfg_alpha_check(void)
678 CONFIG **kw = keywords;
682 while (cfg[1].name) {
683 if (strcmp(cfg[0].name, cfg[1].name) >= 0) {
684 die("cfg_alpha_check: failure at '%s', '%s'", cfg[0].name, cfg[1].name);
693 #endif /* !__MSDOS__ */