Use pb_log in the udev-helper.
[petitboot] / devices / yaboot-cfg.c
1 /*
2  *  cfg.c - Handling and parsing of yaboot.conf
3  *
4  *  Copyright (C) 1995 Werner Almesberger
5  *                1996 Jakub Jelinek
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 #include <setjmp.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <libio.h>
29
30 #define prom_printf printf
31 #define prom_putchar putchar
32 #define prom_vprintf vprintf
33
34 /* Imported functions */
35 extern int strcasecmp(const char *s1, const char *s2);
36
37 typedef enum {
38      cft_strg, cft_flag, cft_end
39 } CONFIG_TYPE;
40
41 typedef struct {
42      CONFIG_TYPE type;
43      char *name;
44      void *data;
45 } CONFIG;
46
47 #define MAX_TOKEN 200
48 #define MAX_VAR_NAME MAX_TOKEN
49 char *cfg_get_default (void);
50
51 CONFIG cf_options[] =
52 {
53      {cft_strg, "device", NULL},
54      {cft_strg, "partition", NULL},
55      {cft_strg, "default", NULL},
56      {cft_strg, "timeout", NULL},
57      {cft_strg, "password", NULL},
58      {cft_flag, "restricted", NULL},
59      {cft_strg, "message", NULL},
60      {cft_strg, "root", NULL},
61      {cft_strg, "ramdisk", NULL},
62      {cft_flag, "read-only", NULL},
63      {cft_flag, "read-write", NULL},
64      {cft_strg, "append", NULL},
65      {cft_strg, "initrd", NULL},
66      {cft_flag, "initrd-prompt", NULL},
67      {cft_strg, "initrd-size", NULL},
68      {cft_flag, "pause-after", NULL},
69      {cft_strg, "pause-message", NULL},
70      {cft_strg, "init-code", NULL},
71      {cft_strg, "init-message", NULL},
72      {cft_strg, "fgcolor", NULL},
73      {cft_strg, "bgcolor", NULL},
74      {cft_strg, "ptypewarning", NULL},
75      {cft_end, NULL, NULL}};
76
77 CONFIG cf_image[] =
78 {
79      {cft_strg, "image", NULL},
80      {cft_strg, "label", NULL},
81      {cft_strg, "alias", NULL},
82      {cft_flag, "single-key", NULL},
83      {cft_flag, "restricted", NULL},
84      {cft_strg, "device", NULL},
85      {cft_strg, "partition", NULL},
86      {cft_strg, "root", NULL},
87      {cft_strg, "ramdisk", NULL},
88      {cft_flag, "read-only", NULL},
89      {cft_flag, "read-write", NULL},
90      {cft_strg, "append", NULL},
91      {cft_strg, "literal", NULL},
92      {cft_strg, "initrd", NULL},
93      {cft_flag, "initrd-prompt", NULL},
94      {cft_strg, "initrd-size", NULL},
95      {cft_flag, "pause-after", NULL},
96      {cft_strg, "pause-message", NULL},
97      {cft_flag, "novideo", NULL},
98      {cft_strg, "sysmap", NULL},
99      {cft_end, NULL, NULL}};
100
101 static char flag_set;
102 static char *last_token = NULL, *last_item = NULL, *last_value = NULL;
103 static int line_num;
104 static int back = 0;            /* can go back by one char */
105 static char *currp = NULL;
106 static char *endp = NULL;
107 static char *file_name = NULL;
108 static CONFIG *curr_table = cf_options;
109 static jmp_buf env;
110
111 static struct IMAGES {
112      CONFIG table[sizeof (cf_image) / sizeof (cf_image[0])];
113      struct IMAGES *next;
114 } *images = NULL;
115
116 void cfg_error (char *msg,...)
117 {
118      va_list ap;
119
120      va_start (ap, msg);
121      prom_printf ("Config file error: ");
122      prom_vprintf (msg, ap);
123      va_end (ap);
124      prom_printf (" near line %d in file %s\n", line_num, file_name);
125      longjmp (env, 1);
126 }
127
128 void cfg_warn (char *msg,...)
129 {
130      va_list ap;
131
132      va_start (ap, msg);
133      prom_printf ("Config file warning: ");
134      prom_vprintf (msg, ap);
135      va_end (ap);
136      prom_printf (" near line %d in file %s\n", line_num, file_name);
137 }
138
139 inline int cfg_getc ()
140 {
141      if (currp == endp)
142           return EOF;
143      return *currp++;
144 }
145
146 #define next_raw next
147 static int next (void)
148 {
149      int ch;
150
151      if (!back)
152           return cfg_getc ();
153      ch = back;
154      back = 0;
155      return ch;
156 }
157
158 static void again (int ch)
159 {
160      back = ch;
161 }
162
163 static char *cfg_get_token (void)
164 {
165      char buf[MAX_TOKEN + 1];
166      char *here;
167      int ch, escaped;
168
169      if (last_token) {
170           here = last_token;
171           last_token = NULL;
172           return here;
173      }
174      while (1) {
175           while (ch = next (), ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
176                if (ch == '\n' || ch == '\r')
177                     line_num++;
178           if (ch == EOF || ch == (int)NULL)
179                return NULL;
180           if (ch != '#')
181                break;
182           while (ch = next_raw (), (ch != '\n' && ch != '\r'))
183                if (ch == EOF)
184                     return NULL;
185           line_num++;
186      }
187      if (ch == '=')
188           return strdup ("=");
189      if (ch == '"') {
190           here = buf;
191           while (here - buf < MAX_TOKEN) {
192                if ((ch = next ()) == EOF)
193                     cfg_error ("EOF in quoted string");
194                if (ch == '"') {
195                     *here = 0;
196                     return strdup (buf);
197                }
198                if (ch == '\\') {
199                     ch = next ();
200                     switch (ch) {
201                     case '"':
202                     case '\\':
203                          break;
204                     case '\n':
205                     case '\r':
206                          while ((ch = next ()), ch == ' ' || ch == '\t');
207                          if (!ch)
208                               continue;
209                          again (ch);
210                          ch = ' ';
211                          break;
212                     case 'n':
213                          ch = '\n';
214                          break;
215                     default:
216                          cfg_error ("Bad use of \\ in quoted string");
217                     }
218                } else if ((ch == '\n') || (ch == '\r'))
219                     cfg_error ("newline is not allowed in quoted strings");
220                *here++ = ch;
221           }
222           cfg_error ("Quoted string is too long");
223           return 0;             /* not reached */
224      }
225      here = buf;
226      escaped = 0;
227      while (here - buf < MAX_TOKEN) {
228           if (escaped) {
229                if (ch == EOF)
230                     cfg_error ("\\ precedes EOF");
231                if (ch == '\n')
232                     line_num++;
233                else
234                     *here++ = ch == '\t' ? ' ' : ch;
235                escaped = 0;
236           } else {
237                if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '#' ||
238                    ch == '=' || ch == EOF) {
239                     again (ch);
240                     *here = 0;
241                     return strdup (buf);
242                }
243                if (!(escaped = (ch == '\\')))
244                     *here++ = ch;
245           }
246           ch = next ();
247      }
248      cfg_error ("Token is too long");
249      return 0;                  /* not reached */
250 }
251
252 static void cfg_return_token (char *token)
253 {
254      last_token = token;
255 }
256
257 static int cfg_next (char **item, char **value)
258 {
259      char *this;
260
261      if (last_item) {
262           *item = last_item;
263           *value = last_value;
264           last_item = NULL;
265           return 1;
266      }
267      *value = NULL;
268      if (!(*item = cfg_get_token ()))
269           return 0;
270      if (!strcmp (*item, "="))
271           cfg_error ("Syntax error");
272      if (!(this = cfg_get_token ()))
273           return 1;
274      if (strcmp (this, "=")) {
275           cfg_return_token (this);
276           return 1;
277      }
278      if (!(*value = cfg_get_token ()))
279           cfg_error ("Value expected at EOF");
280      if (!strcmp (*value, "="))
281           cfg_error ("Syntax error after %s", *item);
282      return 1;
283 }
284
285 #if 0
286 // The one and only call to this procedure is commented out
287 // below, so we don't need this unless we decide to use it again.
288 static void cfg_return (char *item, char *value)
289 {
290      last_item = item;
291      last_value = value;
292 }
293 #endif
294
295 static int cfg_set (char *item, char *value)
296 {
297      CONFIG *walk;
298
299      if (!strcasecmp (item, "image")) {
300           struct IMAGES **p = &images;
301
302           while (*p)
303                p = &((*p)->next);
304           *p = (struct IMAGES *)malloc (sizeof (struct IMAGES));
305           if (*p == NULL) {
306                prom_printf("malloc error in cfg_set\n");
307                return -1;
308           }
309           (*p)->next = 0;
310           curr_table = ((*p)->table);
311           memcpy (curr_table, cf_image, sizeof (cf_image));
312      }
313      for (walk = curr_table; walk->type != cft_end; walk++) {
314           if (walk->name && !strcasecmp (walk->name, item)) {
315                if (value && walk->type != cft_strg)
316                     cfg_warn ("'%s' doesn't have a value", walk->name);
317                else if (!value && walk->type == cft_strg)
318                     cfg_warn ("Value expected for '%s'", walk->name);
319                else {
320                     if (walk->data)
321                          cfg_warn ("Duplicate entry '%s'", walk->name);
322                     if (walk->type == cft_flag)
323                          walk->data = &flag_set;
324                     else if (walk->type == cft_strg)
325                          walk->data = value;
326                }
327                break;
328           }
329      }
330      if (walk->type != cft_end)
331           return 1;
332 //    cfg_return (item, value);
333      return 0;
334 }
335
336 int cfg_parse (char *cfg_file, char *buff, int len)
337 {
338      char *item, *value;
339
340      file_name = cfg_file;
341      currp = buff;
342      endp = currp + len;
343
344      if (setjmp (env))
345           return -1;
346      while (1) {
347           if (!cfg_next (&item, &value))
348                return 0;
349           if (!cfg_set (item, value)) {
350 #if DEBUG
351                prom_printf("Can't set item %s to value %s\n", item, value);
352 #endif      
353           }
354           free (item);
355      }
356 }
357
358 static char *cfg_get_strg_i (CONFIG * table, char *item)
359 {
360      CONFIG *walk;
361
362      for (walk = table; walk->type != cft_end; walk++)
363           if (walk->name && !strcasecmp (walk->name, item))
364                return walk->data;
365      return 0;
366 }
367
368 char *cfg_get_strg (char *image, char *item)
369 {
370      struct IMAGES *p;
371      char *label, *alias;
372      char *ret;
373
374      if (!image)
375           return cfg_get_strg_i (cf_options, item);
376      for (p = images; p; p = p->next) {
377           label = cfg_get_strg_i (p->table, "label");
378           if (!label) {
379                label = cfg_get_strg_i (p->table, "image");
380                alias = strrchr (label, '/');
381                if (alias)
382                     label = alias + 1;
383           }
384           alias = cfg_get_strg_i (p->table, "alias");
385           if (!strcmp (label, image) || (alias && !strcmp (alias, image))) {
386                ret = cfg_get_strg_i (p->table, item);
387                if (!ret)
388                     ret = cfg_get_strg_i (cf_options, item);
389                return ret;
390           }
391      }
392      return 0;
393 }
394
395 int cfg_get_flag (char *image, char *item)
396 {
397      return !!cfg_get_strg (image, item);
398 }
399
400 static int printl_count = 0;
401 static void printlabel (char *label, int defflag)
402 {
403      int len = strlen (label);
404
405      if (!printl_count)
406           prom_printf ("\n");
407      prom_printf ("%s %s",defflag?"*":" ", label);
408      while (len++ < 25)
409           prom_putchar (' ');
410      printl_count++;
411      if (printl_count == 3)
412           printl_count = 0;
413 }
414
415 void cfg_print_images (void)
416 {
417      struct IMAGES *p;
418      char *label, *alias;
419
420      char *ret = cfg_get_default();//strg_i (cf_options, "default");
421      int defflag=0;
422
423      printl_count = 0;
424      for (p = images; p; p = p->next) {
425           label = cfg_get_strg_i (p->table, "label");
426           if (!label) {
427                label = cfg_get_strg_i (p->table, "image");
428                alias = strrchr (label, '/');
429                if (alias)
430                     label = alias + 1;
431           }
432           if(!strcmp(ret,label))
433                defflag=1;
434           else
435                defflag=0;
436           alias = cfg_get_strg_i (p->table, "alias");
437           printlabel (label, defflag);
438           if (alias)
439                printlabel (alias, 0);
440      }
441      prom_printf("\n");
442 }
443
444 char *cfg_get_default (void)
445 {
446      char *label;
447      char *ret = cfg_get_strg_i (cf_options, "default");
448
449      if (ret)
450           return ret;
451      if (!images)
452           return 0;
453      ret = cfg_get_strg_i (images->table, "label");
454      if (!ret) {
455           ret = cfg_get_strg_i (images->table, "image");
456           label = strrchr (ret, '/');
457           if (label)
458                ret = label + 1;
459      }
460      return ret;
461 }
462
463 char *cfg_next_image(char *prev)
464 {
465      struct IMAGES *p;
466      char *label, *alias;
467      int wantnext = 0;
468
469      if (!prev)
470           wantnext = 1;
471
472      for (p = images; p; p = p->next) {
473           label = cfg_get_strg_i (p->table, "label");
474           if (!label) {
475                label = cfg_get_strg_i (p->table, "image");
476                alias = strrchr (label, '/');
477                if (alias)
478                     label = alias + 1;
479           }
480           if (wantnext)
481                return label;
482           if (!strcmp(prev, label))
483                wantnext = 1;
484      }
485      return NULL;
486 }
487 /* 
488  * Local variables:
489  * c-file-style: "k&r"
490  * c-basic-offset: 5
491  * End:
492  */