2 * cfg.c - Handling and parsing of yaboot.conf
4 * Copyright (C) 1995 Werner Almesberger
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /* Imported functions */
30 extern int strcasecmp(const char *s1, const char *s2);
31 extern int strncasecmp(const char *cs, const char *ct, size_t n);
32 extern char bootoncelabel[1024];
35 cft_strg, cft_flag, cft_end
45 #define MAX_VAR_NAME MAX_TOKEN
50 {cft_strg, "device", NULL},
51 {cft_strg, "partition", NULL},
52 {cft_strg, "default", NULL},
53 {cft_strg, "timeout", NULL},
54 {cft_strg, "password", NULL},
55 {cft_flag, "restricted", NULL},
56 {cft_strg, "message", NULL},
57 {cft_strg, "root", NULL},
58 {cft_strg, "ramdisk", NULL},
59 {cft_flag, "read-only", NULL},
60 {cft_flag, "read-write", NULL},
61 {cft_strg, "append", NULL},
62 {cft_strg, "initrd", NULL},
63 {cft_flag, "initrd-prompt", NULL},
64 {cft_strg, "initrd-size", NULL},
65 {cft_flag, "pause-after", NULL},
66 {cft_strg, "pause-message", NULL},
67 {cft_strg, "init-code", NULL},
68 {cft_strg, "init-message", NULL},
69 {cft_strg, "fgcolor", NULL},
70 {cft_strg, "bgcolor", NULL},
71 {cft_strg, "ptypewarning", NULL},
72 {cft_end, NULL, NULL}};
76 {cft_strg, "image", NULL},
77 {cft_strg, "label", NULL},
78 {cft_strg, "alias", NULL},
79 {cft_flag, "single-key", NULL},
80 {cft_flag, "restricted", NULL},
81 {cft_strg, "device", NULL},
82 {cft_strg, "partition", NULL},
83 {cft_strg, "root", NULL},
84 {cft_strg, "ramdisk", NULL},
85 {cft_flag, "read-only", NULL},
86 {cft_flag, "read-write", NULL},
87 {cft_strg, "append", NULL},
88 {cft_strg, "literal", NULL},
89 {cft_strg, "initrd", NULL},
90 {cft_flag, "initrd-prompt", NULL},
91 {cft_strg, "initrd-size", NULL},
92 {cft_flag, "pause-after", NULL},
93 {cft_strg, "pause-message", NULL},
94 {cft_flag, "novideo", NULL},
95 {cft_strg, "sysmap", NULL},
96 {cft_end, NULL, NULL}};
99 static char *last_token = NULL, *last_item = NULL, *last_value = NULL;
101 static int back = 0; /* can go back by one char */
102 static char *currp = NULL;
103 static char *endp = NULL;
104 static char *file_name = NULL;
105 static CONFIG *curr_table = cf_options;
106 static int ignore_entry;
109 static struct IMAGES {
110 CONFIG table[sizeof (cf_image) / sizeof (cf_image[0])];
115 void cfg_error (char *msg,...)
120 prom_printf ("Config file error: ");
121 prom_vprintf (msg, ap);
123 prom_printf (" near line %d in file %s\n", line_num, file_name);
127 void cfg_warn (char *msg,...)
132 prom_printf ("Config file warning: ");
133 prom_vprintf (msg, ap);
135 prom_printf (" near line %d in file %s\n", line_num, file_name);
145 #define next_raw next
146 static int next (void)
157 static void again (int ch)
162 static char *cfg_get_token (void)
164 char buf[MAX_TOKEN + 1];
174 while (ch = next (), ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
175 if (ch == '\n' || ch == '\r')
177 if (ch == EOF || ch == (int)NULL)
181 while (ch = next_raw (), (ch != '\n' && ch != '\r'))
190 while (here - buf < MAX_TOKEN) {
191 if ((ch = next ()) == EOF)
192 cfg_error ("EOF in quoted string");
205 while ((ch = next ()), ch == ' ' || ch == '\t');
215 cfg_error ("Bad use of \\ in quoted string");
217 } else if ((ch == '\n') || (ch == '\r'))
218 cfg_error ("newline is not allowed in quoted strings");
221 cfg_error ("Quoted string is too long");
222 return 0; /* not reached */
226 while (here - buf < MAX_TOKEN) {
229 cfg_error ("\\ precedes EOF");
233 *here++ = ch == '\t' ? ' ' : ch;
236 if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '#' ||
237 ch == '=' || ch == EOF) {
242 if (!(escaped = (ch == '\\')))
247 cfg_error ("Token is too long");
248 return 0; /* not reached */
251 static void cfg_return_token (char *token)
256 static int cfg_next (char **item, char **value)
267 if (!(*item = cfg_get_token ()))
269 if (!strcmp (*item, "="))
270 cfg_error ("Syntax error");
271 if (!(this = cfg_get_token ()))
273 if (strcmp (this, "=")) {
274 cfg_return_token (this);
277 if (!(*value = cfg_get_token ()))
278 cfg_error ("Value expected at EOF");
279 if (!strcmp (*value, "="))
280 cfg_error ("Syntax error after %s", *item);
284 static char *cfg_get_strg_i (CONFIG * table, char *item)
288 for (walk = table; walk->type != cft_end; walk++)
289 if (walk->name && !strcasecmp (walk->name, item))
295 // The one and only call to this procedure is commented out
296 // below, so we don't need this unless we decide to use it again.
297 static void cfg_return (char *item, char *value)
304 static int match_arch(const char *name)
306 static prom_handle root;
307 static char model[256], *p;
310 if (!(root = prom_finddevice("/")))
315 if (!prom_getprop(root, "compatible", model, sizeof(model)))
319 for (p = model; *p; p += strlen(p) + 1) {
320 if (!strcasecmp(p, name))
327 static void check_for_obsolete(const char *label)
332 /* Make sure our current entry isn't obsolete (ignored) */
333 for (p = images; p; p = p->next) {
334 if (curr_table == p->table && p->obsolete)
338 for (p = images; p; p = p->next) {
339 if (curr_table == p->table)
342 cur_label = cfg_get_strg_i (p->table, "label");
344 cur_label = cfg_get_strg_i (p->table, "image");
349 if (!strcasecmp(cur_label, label))
354 static int cfg_set (char *item, char *value)
358 if (!strncasecmp (item, "image", 5)) {
359 struct IMAGES **p = &images;
362 if (item[5] == '[' && item[strlen(item) - 1] == ']') {
365 /* Get rid of braces */
366 item[strlen(item) - 1] = 0;
369 for (s = item + 6; q; s = q) {
377 /* This just creates an unused table. It will get ignored */
385 *p = (struct IMAGES *)malloc (sizeof (struct IMAGES));
387 prom_printf("malloc error in cfg_set\n");
391 (*p)->obsolete = ignore;
392 curr_table = ((*p)->table);
393 memcpy (curr_table, cf_image, sizeof (cf_image));
397 for (walk = curr_table; walk->type != cft_end; walk++) {
398 if (walk->name && !strcasecmp (walk->name, item)) {
399 if (value && walk->type != cft_strg)
400 cfg_warn ("'%s' doesn't have a value", walk->name);
401 else if (!value && walk->type == cft_strg)
402 cfg_warn ("Value expected for '%s'", walk->name);
404 if (!strcasecmp (item, "label"))
405 check_for_obsolete(value);
407 cfg_warn ("Duplicate entry '%s'", walk->name);
408 if (walk->type == cft_flag)
409 walk->data = &flag_set;
410 else if (walk->type == cft_strg)
417 if (walk->type != cft_end)
420 //cfg_return (item, value);
425 static int cfg_reset ()
429 prom_printf("Resetting image table\n");
434 curr_table = cf_options;
435 for (walk = curr_table; walk->type != cft_end; walk++) {
437 prom_printf("ItemA %s = %s\n", walk->name, walk->data);
439 if (walk->data != NULL)
442 prom_printf("ItemB %s = %s\n\n", walk->name, walk->data);
449 int cfg_parse (char *cfg_file, char *buff, int len)
453 file_name = cfg_file;
462 if (!cfg_next (&item, &value))
464 if (!cfg_set (item, value)) {
466 prom_printf("Can't set item %s to value %s\n", item, value);
473 char *cfg_get_strg (char *image, char *item)
480 return cfg_get_strg_i (cf_options, item);
481 for (p = images; p; p = p->next) {
485 label = cfg_get_strg_i (p->table, "label");
487 label = cfg_get_strg_i (p->table, "image");
488 alias = strrchr (label, '/');
492 alias = cfg_get_strg_i (p->table, "alias");
493 if (!strcmp (label, image) || (alias && !strcmp (alias, image))) {
494 ret = cfg_get_strg_i (p->table, item);
496 ret = cfg_get_strg_i (cf_options, item);
503 int cfg_get_flag (char *image, char *item)
505 return !!cfg_get_strg (image, item);
508 static int printl_count = 0;
509 static void printlabel (char *label, int defflag)
511 int len = strlen (label);
517 case 1: a='*'; break;
518 case 2: a='&'; break;
519 default: a=' '; break;
521 prom_printf ("%c %s", a, label);
525 if (printl_count == 3)
529 void cfg_print_images (void)
534 char *ret = cfg_get_strg_i (cf_options, "default");
538 for (p = images; p; p = p->next) {
542 label = cfg_get_strg_i (p->table, "label");
544 label = cfg_get_strg_i (p->table, "image");
545 alias = strrchr (label, '/');
549 if(!strcmp(bootoncelabel,label))
551 else if(!strcmp(ret,label))
555 alias = cfg_get_strg_i (p->table, "alias");
556 printlabel (label, defflag);
558 printlabel (alias, 0);
563 char *cfg_get_default (void)
567 char *ret = cfg_get_strg_i (cf_options, "default");
574 for (p = images; p && p->obsolete; p = p->next);
578 ret = cfg_get_strg_i (p->table, "label");
580 ret = cfg_get_strg_i (p->table, "image");
581 label = strrchr (ret, '/');
589 * cfg_set_default_by_mac ()
590 * return 1 if the default cf_option was changed to label with the MAC addr
591 * return 0 if not changed
593 int cfg_set_default_by_mac (char *mac_addr)
600 /* check if there is an image label equal to mac_addr */
601 for (tmp = images; tmp; tmp = tmp->next) {
602 label = cfg_get_strg_i (tmp->table, "label");
603 if (!strcmp(label,mac_addr)){
612 * if there is an image label equal to mac_addr, change the default
613 * cf_options to this image label
615 for (walk = cf_options; walk->type != cft_end; walk++) {
616 if (!strcasecmp(walk->name,"default")) {
617 walk->data = mac_addr;
627 * c-file-style: "k&r"