~ubuntu-branches/ubuntu/trusty/grub2/trusty

« back to all changes in this revision

Viewing changes to grub-core/lib/syslinux_parse.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-01-16 15:18:04 UTC
  • mfrom: (17.6.38 experimental)
  • Revision ID: package-import@ubuntu.com-20140116151804-3foouk7fpqcq3sxx
Tags: 2.02~beta2-2
* Convert patch handling to git-dpm.
* Add bi-endian support to ELF parser (Tomohiro B Berry).
* Adjust restore_mkdevicemap.patch to mark get_kfreebsd_version as static,
  to appease "gcc -Werror=missing-prototypes".
* Cherry-pick from upstream:
  - Change grub-macbless' manual page section to 8.
* Install grub-glue-efi, grub-macbless, grub-render-label, and
  grub-syslinux2cfg.
* grub-shell: Pass -no-pad to xorriso when building floppy images.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2013 Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <grub/mm.h>
 
20
#include <grub/file.h>
 
21
#include <grub/normal.h>
 
22
#include <grub/syslinux_parse.h>
 
23
 
 
24
struct syslinux_say
 
25
{
 
26
  struct syslinux_say *next;
 
27
  struct syslinux_say *prev;
 
28
  char msg[0];
 
29
};
 
30
 
 
31
struct initrd_list
 
32
{
 
33
  struct initrd_list *next;
 
34
  char *file;
 
35
};
 
36
 
 
37
struct syslinux_menuentry
 
38
{
 
39
  struct syslinux_menuentry *next;
 
40
  struct syslinux_menuentry *prev;
 
41
  char *label;
 
42
  char *extlabel;
 
43
  char *kernel_file;
 
44
  struct initrd_list *initrds;
 
45
  struct initrd_list *initrds_last;
 
46
  char *append;
 
47
  char *argument;
 
48
  char *help;
 
49
  char *comments;
 
50
  grub_size_t commentslen;
 
51
  char hotkey;
 
52
  int make_default;
 
53
  struct syslinux_say *say;
 
54
  
 
55
  enum { KERNEL_NO_KERNEL, KERNEL_LINUX, KERNEL_CHAINLOADER, 
 
56
         KERNEL_BIN, KERNEL_PXE, KERNEL_CHAINLOADER_BPB,
 
57
         KERNEL_COM32, KERNEL_COM, KERNEL_IMG, KERNEL_CONFIG, LOCALBOOT }
 
58
    entry_type;
 
59
};
 
60
 
 
61
struct syslinux_menu
 
62
{
 
63
  struct syslinux_menu *parent;
 
64
  struct syslinux_menuentry *entries;
 
65
  char *def;
 
66
  char *comments;
 
67
  char *background;
 
68
  const char *root_read_directory;
 
69
  const char *root_target_directory;
 
70
  const char *current_read_directory;
 
71
  const char *current_target_directory;
 
72
  const char *filename;
 
73
  grub_size_t commentslen;
 
74
  unsigned long timeout;
 
75
  struct syslinux_say *say;
 
76
  grub_syslinux_flavour_t flavour;
 
77
};
 
78
 
 
79
struct output_buffer
 
80
{
 
81
  grub_size_t alloc;
 
82
  grub_size_t ptr;
 
83
  char *buf;
 
84
};
 
85
 
 
86
static grub_err_t
 
87
syslinux_parse_real (struct syslinux_menu *menu);
 
88
static grub_err_t
 
89
config_file (struct output_buffer *outbuf,
 
90
             const char *root, const char *target_root,
 
91
             const char *cwd, const char *target_cwd,
 
92
             const char *fname, struct syslinux_menu *parent,
 
93
             grub_syslinux_flavour_t flav);
 
94
static grub_err_t
 
95
print_entry (struct output_buffer *outbuf,
 
96
             struct syslinux_menu *menu,
 
97
             const char *str);
 
98
 
 
99
static grub_err_t
 
100
ensure_space (struct output_buffer *outbuf, grub_size_t len)
 
101
{
 
102
  grub_size_t newlen;
 
103
  char *newbuf;
 
104
  if (len < outbuf->alloc - outbuf->ptr)
 
105
    return GRUB_ERR_NONE;
 
106
  newlen = (outbuf->ptr + len + 10) * 2;
 
107
  newbuf = grub_realloc (outbuf->buf, newlen);
 
108
  if (!newbuf)
 
109
    return grub_errno;
 
110
  outbuf->alloc = newlen;
 
111
  outbuf->buf = newbuf;
 
112
  return GRUB_ERR_NONE;
 
113
}
 
114
 
 
115
static grub_err_t
 
116
print (struct output_buffer *outbuf, const char *str, grub_size_t len)
 
117
{
 
118
  grub_err_t err;
 
119
  err = ensure_space (outbuf, len);
 
120
  if (err)
 
121
    return err;
 
122
  grub_memcpy (&outbuf->buf[outbuf->ptr], str, len);
 
123
  outbuf->ptr += len;
 
124
  return GRUB_ERR_NONE;
 
125
}
 
126
 
 
127
static grub_err_t
 
128
add_comment (struct syslinux_menu *menu, const char *comment, int nl)
 
129
{
 
130
  if (menu->entries)
 
131
    {
 
132
      if (menu->entries->commentslen == 0 && *comment == 0)
 
133
        return GRUB_ERR_NONE;
 
134
      menu->entries->comments = grub_realloc (menu->entries->comments,
 
135
                                              menu->entries->commentslen
 
136
                                              + 2 + grub_strlen (comment));
 
137
      if (!menu->entries->comments)
 
138
        return grub_errno;
 
139
      menu->entries->commentslen
 
140
        += grub_stpcpy (menu->entries->comments + menu->entries->commentslen,
 
141
                        comment)
 
142
        - (menu->entries->comments + menu->entries->commentslen);
 
143
      if (nl)
 
144
        menu->entries->comments[menu->entries->commentslen++] = '\n';
 
145
      menu->entries->comments[menu->entries->commentslen] = '\0';
 
146
    }
 
147
  else
 
148
    {
 
149
      if (menu->commentslen == 0 && *comment == 0)
 
150
        return GRUB_ERR_NONE;
 
151
      menu->comments = grub_realloc (menu->comments, menu->commentslen
 
152
                                     + 2 + grub_strlen (comment));
 
153
      if (!menu->comments)
 
154
        return grub_errno;
 
155
      menu->commentslen += grub_stpcpy (menu->comments + menu->commentslen,
 
156
                                        comment)
 
157
        - (menu->comments + menu->commentslen);
 
158
      if (nl)
 
159
        menu->comments[menu->commentslen++] = '\n';
 
160
      menu->comments[menu->commentslen] = '\0';
 
161
    }
 
162
  return GRUB_ERR_NONE;
 
163
}
 
164
 
 
165
 
 
166
#define print_string(x) do { err = print (outbuf, x, sizeof (x) - 1); if (err) return err; } while (0)
 
167
 
 
168
static grub_err_t
 
169
print_num (struct output_buffer *outbuf, int n)
 
170
{
 
171
  char buf[20];
 
172
  grub_snprintf (buf, sizeof (buf), "%d", n);
 
173
  return print (outbuf, buf, grub_strlen (buf)); 
 
174
}
 
175
 
 
176
static grub_err_t
 
177
label (const char *line, struct syslinux_menu *menu)
 
178
{
 
179
  struct syslinux_menuentry *entry;
 
180
 
 
181
  entry = grub_malloc (sizeof (*entry));
 
182
  if (!entry)
 
183
    return grub_errno;
 
184
  grub_memset (entry, 0, sizeof (*entry));
 
185
  entry->label = grub_strdup (line);
 
186
  if (!entry->label)
 
187
    {
 
188
      grub_free (entry);
 
189
      return grub_errno;
 
190
    }
 
191
  entry->next = menu->entries;
 
192
  entry->prev = NULL;
 
193
  if (menu->entries)
 
194
    menu->entries->prev = entry;
 
195
  menu->entries = entry;
 
196
  return GRUB_ERR_NONE;
 
197
}
 
198
 
 
199
static grub_err_t
 
200
kernel (const char *line, struct syslinux_menu *menu)
 
201
{
 
202
  const char *end = line + grub_strlen (line);
 
203
 
 
204
  if (!menu->entries)
 
205
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
206
 
 
207
  menu->entries->kernel_file = grub_strdup (line);
 
208
  if (!menu->entries->kernel_file)
 
209
    return grub_errno;
 
210
 
 
211
  menu->entries->entry_type = KERNEL_LINUX;
 
212
 
 
213
  if (end - line >= 2 && grub_strcmp (end - 2, ".0") == 0)
 
214
    menu->entries->entry_type = KERNEL_PXE;
 
215
 
 
216
  if (end - line >= 4 && grub_strcasecmp (end - 4, ".bin") == 0)
 
217
    menu->entries->entry_type = KERNEL_BIN;
 
218
 
 
219
  if (end - line >= 3 && grub_strcasecmp (end - 3, ".bs") == 0)
 
220
    menu->entries->entry_type = KERNEL_CHAINLOADER;
 
221
 
 
222
  if (end - line >= 4 && grub_strcasecmp (end - 4, ".bss") == 0)
 
223
    menu->entries->entry_type = KERNEL_CHAINLOADER_BPB;
 
224
 
 
225
  if (end - line >= 4 && grub_strcasecmp (end - 4, ".c32") == 0)
 
226
    menu->entries->entry_type = KERNEL_COM32;
 
227
 
 
228
  if (end - line >= 4 && grub_strcasecmp (end - 4, ".cbt") == 0)
 
229
    menu->entries->entry_type = KERNEL_COM;
 
230
 
 
231
  if (end - line >= 4 && grub_strcasecmp (end - 4, ".com") == 0)
 
232
    menu->entries->entry_type = KERNEL_COM;
 
233
 
 
234
  if (end - line >= 4 && grub_strcasecmp (end - 4, ".img") == 0)
 
235
    menu->entries->entry_type = KERNEL_IMG;
 
236
  
 
237
  return GRUB_ERR_NONE;
 
238
}
 
239
 
 
240
static grub_err_t
 
241
cmd_linux (const char *line, struct syslinux_menu *menu)
 
242
{
 
243
  if (!menu->entries)
 
244
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
245
 
 
246
  menu->entries->kernel_file = grub_strdup (line);
 
247
  if (!menu->entries->kernel_file)
 
248
    return grub_errno;
 
249
  menu->entries->entry_type = KERNEL_LINUX;
 
250
  
 
251
  return GRUB_ERR_NONE;
 
252
}
 
253
 
 
254
static grub_err_t
 
255
cmd_boot (const char *line, struct syslinux_menu *menu)
 
256
{
 
257
  if (!menu->entries)
 
258
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
259
 
 
260
  menu->entries->kernel_file = grub_strdup (line);
 
261
  if (!menu->entries->kernel_file)
 
262
    return grub_errno;
 
263
  menu->entries->entry_type = KERNEL_CHAINLOADER;
 
264
  
 
265
  return GRUB_ERR_NONE;
 
266
}
 
267
 
 
268
static grub_err_t
 
269
cmd_bss (const char *line, struct syslinux_menu *menu)
 
270
{
 
271
  if (!menu->entries)
 
272
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
273
 
 
274
  menu->entries->kernel_file = grub_strdup (line);
 
275
  if (!menu->entries->kernel_file)
 
276
    return grub_errno;
 
277
  menu->entries->entry_type = KERNEL_CHAINLOADER_BPB;
 
278
  
 
279
  return GRUB_ERR_NONE;
 
280
}
 
281
 
 
282
static grub_err_t
 
283
cmd_pxe (const char *line, struct syslinux_menu *menu)
 
284
{
 
285
  if (!menu->entries)
 
286
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
287
 
 
288
  menu->entries->kernel_file = grub_strdup (line);
 
289
  if (!menu->entries->kernel_file)
 
290
    return grub_errno;
 
291
  menu->entries->entry_type = KERNEL_PXE;
 
292
  
 
293
  return GRUB_ERR_NONE;
 
294
}
 
295
 
 
296
static grub_err_t
 
297
cmd_fdimage (const char *line, struct syslinux_menu *menu)
 
298
{
 
299
  if (!menu->entries)
 
300
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
301
 
 
302
  menu->entries->kernel_file = grub_strdup (line);
 
303
  if (!menu->entries->kernel_file)
 
304
    return grub_errno;
 
305
  menu->entries->entry_type = KERNEL_IMG;
 
306
  
 
307
  return GRUB_ERR_NONE;
 
308
}
 
309
 
 
310
static grub_err_t
 
311
cmd_comboot (const char *line, struct syslinux_menu *menu)
 
312
{
 
313
  if (!menu->entries)
 
314
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
315
 
 
316
  menu->entries->kernel_file = grub_strdup (line);
 
317
  if (!menu->entries->kernel_file)
 
318
    return grub_errno;
 
319
  menu->entries->entry_type = KERNEL_COM;
 
320
  
 
321
  return GRUB_ERR_NONE;
 
322
}
 
323
 
 
324
static grub_err_t
 
325
cmd_com32 (const char *line, struct syslinux_menu *menu)
 
326
{
 
327
  if (!menu->entries)
 
328
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
329
 
 
330
  menu->entries->kernel_file = grub_strdup (line);
 
331
  if (!menu->entries->kernel_file)
 
332
    return grub_errno;
 
333
  menu->entries->entry_type = KERNEL_COM32;
 
334
  
 
335
  return GRUB_ERR_NONE;
 
336
}
 
337
 
 
338
static grub_err_t
 
339
cmd_config (const char *line, struct syslinux_menu *menu)
 
340
{
 
341
  const char *space;
 
342
  if (!menu->entries)
 
343
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
344
 
 
345
  for (space = line; *space && !grub_isspace (*space); space++);
 
346
  menu->entries->kernel_file = grub_strndup (line, space - line);
 
347
  if (!menu->entries->kernel_file)
 
348
    return grub_errno;
 
349
  for (; *space && grub_isspace (*space); space++);
 
350
  if (*space)
 
351
    {
 
352
      menu->entries->argument = grub_strdup (space);
 
353
      if (!menu->entries->argument)
 
354
        return grub_errno;
 
355
    }
 
356
  menu->entries->entry_type = KERNEL_CONFIG;
 
357
  
 
358
  return GRUB_ERR_NONE;
 
359
}
 
360
 
 
361
static grub_err_t
 
362
cmd_append (const char *line, struct syslinux_menu *menu)
 
363
{
 
364
  if (!menu->entries)
 
365
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
366
 
 
367
  menu->entries->append = grub_strdup (line);
 
368
  if (!menu->entries->append)
 
369
    return grub_errno;
 
370
  
 
371
  return GRUB_ERR_NONE;
 
372
}
 
373
 
 
374
static grub_err_t
 
375
cmd_initrd (const char *line, struct syslinux_menu *menu)
 
376
{
 
377
  struct initrd_list *ninitrd;
 
378
  const char *comma;
 
379
  if (!menu->entries)
 
380
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
381
 
 
382
  while (*line)
 
383
    {
 
384
      for (comma = line; *comma && *comma != ','; comma++);
 
385
 
 
386
      ninitrd = grub_malloc (sizeof (*ninitrd));
 
387
      if (!ninitrd)
 
388
        return grub_errno;
 
389
      ninitrd->file = grub_strndup (line, comma - line);
 
390
      if (!ninitrd->file)
 
391
        {
 
392
          grub_free (ninitrd);
 
393
          return grub_errno;
 
394
        }
 
395
      ninitrd->next = NULL;
 
396
      if (menu->entries->initrds_last)
 
397
        menu->entries->initrds_last->next = ninitrd;
 
398
      else
 
399
        {
 
400
          menu->entries->initrds_last = ninitrd;
 
401
          menu->entries->initrds = ninitrd;
 
402
        }
 
403
 
 
404
      line = comma;
 
405
      while (*line == ',')
 
406
        line++;
 
407
    }
 
408
  
 
409
  return GRUB_ERR_NONE;
 
410
}
 
411
 
 
412
static grub_err_t
 
413
cmd_default (const char *line, struct syslinux_menu *menu)
 
414
{
 
415
  menu->def = grub_strdup (line);
 
416
  if (!menu->def)
 
417
    return grub_errno;
 
418
  
 
419
  return GRUB_ERR_NONE;
 
420
}
 
421
 
 
422
static grub_err_t
 
423
cmd_timeout (const char *line, struct syslinux_menu *menu)
 
424
{
 
425
  menu->timeout = grub_strtoul (line, NULL, 0);
 
426
  
 
427
  return GRUB_ERR_NONE;
 
428
}
 
429
 
 
430
static grub_err_t
 
431
cmd_menudefault (const char *line __attribute__ ((unused)),
 
432
                 struct syslinux_menu *menu)
 
433
{
 
434
  if (!menu->entries)
 
435
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
436
 
 
437
  menu->entries->make_default = 1; 
 
438
  return GRUB_ERR_NONE;
 
439
}
 
440
 
 
441
static grub_err_t
 
442
cmd_menubackground (const char *line,
 
443
                    struct syslinux_menu *menu)
 
444
{
 
445
  menu->background = grub_strdup (line);
 
446
  return GRUB_ERR_NONE;
 
447
}
 
448
 
 
449
static grub_err_t
 
450
cmd_localboot (const char *line,
 
451
               struct syslinux_menu *menu)
 
452
{
 
453
  if (!menu->entries)
 
454
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
455
 
 
456
  menu->entries->kernel_file = grub_strdup (line);
 
457
  if (!menu->entries->kernel_file)
 
458
    return grub_errno;
 
459
  menu->entries->entry_type = LOCALBOOT;
 
460
  
 
461
  return GRUB_ERR_NONE;
 
462
}
 
463
 
 
464
static grub_err_t
 
465
cmd_extlabel (const char *line, struct syslinux_menu *menu)
 
466
{
 
467
  const char *in;
 
468
  char *out;
 
469
 
 
470
  if (!menu->entries)
 
471
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
 
472
 
 
473
  menu->entries->extlabel = grub_malloc (grub_strlen (line) + 1);
 
474
  if (!menu->entries->extlabel)
 
475
    return grub_errno;
 
476
  in = line;
 
477
  out = menu->entries->extlabel;
 
478
  while (*in)
 
479
    {
 
480
      if (in[0] == '^' && in[1])
 
481
        {
 
482
          menu->entries->hotkey = grub_tolower (in[1]);
 
483
          in++;
 
484
        }
 
485
      *out++ = *in++;
 
486
    }
 
487
  *out = 0;
 
488
  
 
489
  return GRUB_ERR_NONE;
 
490
}
 
491
 
 
492
 
 
493
static grub_err_t
 
494
cmd_say (const char *line, struct syslinux_menu *menu)
 
495
{
 
496
  struct syslinux_say *nsay;
 
497
  nsay = grub_malloc (sizeof (*nsay) + grub_strlen (line) + 1);
 
498
  if (!nsay)
 
499
    return grub_errno;
 
500
  nsay->prev = NULL;
 
501
  if (menu->entries)
 
502
    {
 
503
      nsay->next = menu->entries->say;
 
504
      menu->entries->say = nsay;
 
505
    }
 
506
  else
 
507
    {
 
508
      nsay->next = menu->say;
 
509
      menu->say = nsay;
 
510
    }
 
511
 
 
512
  if (nsay->next)
 
513
    nsay->next->prev = nsay;
 
514
 
 
515
  grub_memcpy (nsay->msg, line, grub_strlen (line) + 1);
 
516
  return GRUB_ERR_NONE;
 
517
}
 
518
 
 
519
static char *
 
520
get_read_filename (struct syslinux_menu *menu,
 
521
                   const char *filename)
 
522
{
 
523
  return grub_xasprintf ("%s/%s",
 
524
                         filename[0] == '/' ? menu->root_read_directory
 
525
                         : menu->current_read_directory, filename);
 
526
}
 
527
 
 
528
static char *
 
529
get_target_filename (struct syslinux_menu *menu,
 
530
                   const char *filename)
 
531
{
 
532
  return grub_xasprintf ("%s/%s",
 
533
                         filename[0] == '/' ? menu->root_target_directory
 
534
                         : menu->current_target_directory, filename);
 
535
}
 
536
 
 
537
static grub_err_t
 
538
syslinux_parse (const char *filename,
 
539
                struct syslinux_menu *menu)
 
540
{
 
541
  const char *old_filename = menu->filename;
 
542
  grub_err_t ret;
 
543
  char *nf;
 
544
  nf = get_read_filename (menu, filename);
 
545
  if (!nf)
 
546
    return grub_errno;
 
547
  menu->filename = nf;
 
548
  ret = syslinux_parse_real (menu);
 
549
  if (ret == GRUB_ERR_FILE_NOT_FOUND
 
550
      || ret == GRUB_ERR_BAD_FILENAME)
 
551
    {   
 
552
      grub_errno = ret = GRUB_ERR_NONE;
 
553
      add_comment (menu, "# File ", 0);
 
554
      add_comment (menu, nf, 0);
 
555
      add_comment (menu, " not found", 1);
 
556
    }
 
557
  grub_free (nf);
 
558
  menu->filename = old_filename;
 
559
  return ret;
 
560
}
 
561
 
 
562
struct
 
563
{
 
564
  const char *name1;
 
565
  const char *name2;
 
566
  grub_err_t (*parse) (const char *line, struct syslinux_menu *menu);
 
567
} commands[] = {
 
568
  /* FIXME: support tagname.  */
 
569
  {"include", NULL, syslinux_parse},
 
570
  {"menu", "include", syslinux_parse},
 
571
  {"label",   NULL, label},
 
572
  {"kernel",  NULL, kernel},
 
573
  {"linux",  NULL, cmd_linux},
 
574
  {"boot",  NULL, cmd_boot},
 
575
  {"bss",  NULL, cmd_bss},
 
576
  {"pxe",  NULL, cmd_pxe},
 
577
  {"fdimage",  NULL, cmd_fdimage},
 
578
  {"comboot",  NULL, cmd_comboot},
 
579
  {"com32",  NULL, cmd_com32},
 
580
  {"config",  NULL, cmd_config},
 
581
  {"append",  NULL, cmd_append},
 
582
  /* FIXME: ipappend not supported.  */
 
583
  {"localboot",  NULL, cmd_localboot},
 
584
  {"initrd",  NULL, cmd_initrd},
 
585
  {"default",  NULL, cmd_default},
 
586
  {"menu", "label", cmd_extlabel},
 
587
  /* FIXME: MENU LABEL not supported.  */
 
588
  /* FIXME: MENU HIDDEN not supported.  */
 
589
  /* FIXME: MENU SEPARATOR not supported.  */
 
590
  /* FIXME: MENU INDENT not supported.  */
 
591
  /* FIXME: MENU DISABLE not supported.  */
 
592
  /* FIXME: MENU HIDE not supported.  */
 
593
  {"menu", "default", cmd_menudefault},
 
594
  /* FIXME: MENU PASSWD not supported.  */
 
595
  /* FIXME: MENU MASTER PASSWD not supported.  */
 
596
  {"menu", "background", cmd_menubackground},
 
597
  /* FIXME: MENU BEGIN not supported.  */
 
598
  /* FIXME: MENU GOTO not supported.  */
 
599
  /* FIXME: MENU EXIT not supported.  */
 
600
  /* FIXME: MENU QUIT not supported.  */
 
601
  /* FIXME: MENU START not supported.  */
 
602
  /* FIXME: MENU AUTOBOOT not supported.  */
 
603
  /* FIXME: MENU TABMSG not supported.  */
 
604
  /* FIXME: MENU NOTABMSG not supported.  */
 
605
  /* FIXME: MENU PASSPROMPT not supported.  */
 
606
  /* FIXME: MENU COLOR not supported.  */
 
607
  /* FIXME: MENU MSGCOLOR not supported.  */
 
608
  /* FIXME: MENU WIDTH not supported.  */
 
609
  /* FIXME: MENU MARGIN not supported.  */
 
610
  /* FIXME: MENU PASSWORDMARGIN not supported.  */
 
611
  /* FIXME: MENU ROWS not supported.  */
 
612
  /* FIXME: MENU TABMSGROW not supported.  */
 
613
  /* FIXME: MENU CMDLINEROW not supported.  */
 
614
  /* FIXME: MENU ENDROW not supported.  */
 
615
  /* FIXME: MENU PASSWORDROW not supported.  */
 
616
  /* FIXME: MENU TIMEOUTROW not supported.  */
 
617
  /* FIXME: MENU HELPMSGROW not supported.  */
 
618
  /* FIXME: MENU HELPMSGENDROW not supported.  */
 
619
  /* FIXME: MENU HIDDENROW not supported.  */
 
620
  /* FIXME: MENU HSHIFT not supported.  */
 
621
  /* FIXME: MENU VSHIFT not supported.  */
 
622
  {"timeout", NULL, cmd_timeout},
 
623
  /* FIXME: TOTALTIMEOUT not supported.  */
 
624
  /* FIXME: ONTIMEOUT not supported.  */
 
625
  /* FIXME: ONERROR not supported.  */
 
626
  /* FIXME: SERIAL not supported.  */
 
627
  /* FIXME: CONSOLE not supported.  */
 
628
  /* FIXME: FONT not supported.  */
 
629
  /* FIXME: KBDMAP not supported.  */
 
630
  {"say", NULL, cmd_say},
 
631
  /* FIXME: DISPLAY not supported.  */
 
632
  /* FIXME: F* not supported.  */
 
633
 
 
634
  /* Commands to control interface behaviour which aren't needed with GRUB.
 
635
     If they are important in your environment please contact GRUB team.
 
636
   */
 
637
  {"prompt",       NULL, NULL},
 
638
  {"nocomplete",   NULL, NULL},
 
639
  {"noescape",     NULL, NULL},
 
640
  {"implicit",     NULL, NULL},
 
641
  {"allowoptions", NULL, NULL}
 
642
};
 
643
 
 
644
static grub_err_t
 
645
helptext (const char *line, grub_file_t file, struct syslinux_menu *menu)
 
646
{
 
647
  char *help;
 
648
  char *buf = NULL;
 
649
  grub_size_t helplen, alloclen = 0;
 
650
 
 
651
  help = grub_strdup (line);
 
652
  helplen = grub_strlen (line);
 
653
  while ((grub_free (buf), buf = grub_file_getline (file)))
 
654
    {
 
655
      char *ptr;
 
656
      grub_size_t needlen;
 
657
      for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
 
658
      if (grub_strncasecmp (ptr, "endtext", sizeof ("endtext") - 1) == 0)
 
659
        {
 
660
          ptr += sizeof ("endtext") - 1;
 
661
          for (; *ptr && (grub_isspace (*ptr) || *ptr == '\n' || *ptr == '\r');
 
662
               ptr++);
 
663
          if (!*ptr)
 
664
            {
 
665
              menu->entries->help = help;
 
666
              grub_free (buf);
 
667
              return GRUB_ERR_NONE;
 
668
            }
 
669
        }
 
670
      needlen = helplen + 1 + grub_strlen (buf);
 
671
      if (alloclen < needlen)
 
672
        {
 
673
          alloclen = 2 * needlen;
 
674
          help = grub_realloc (help, alloclen);
 
675
          if (!help)
 
676
            {
 
677
              grub_free (buf);
 
678
              return grub_errno;
 
679
            }
 
680
        }
 
681
      helplen += grub_stpcpy (help + helplen, buf) - (help + helplen);
 
682
    }
 
683
 
 
684
  grub_free (buf);
 
685
  return grub_errno;
 
686
}
 
687
 
 
688
 
 
689
static grub_err_t
 
690
syslinux_parse_real (struct syslinux_menu *menu)
 
691
{
 
692
  grub_file_t file;
 
693
  char *buf = NULL;
 
694
  grub_err_t err = GRUB_ERR_NONE;
 
695
 
 
696
  file = grub_file_open (menu->filename);
 
697
  if (!file)
 
698
    return grub_errno;
 
699
  while ((grub_free (buf), buf = grub_file_getline (file)))
 
700
    {
 
701
      const char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
 
702
      char *end;
 
703
      unsigned i;
 
704
      end = buf + grub_strlen (buf);
 
705
      while (end > buf && (end[-1] == '\n' || end[-1] == '\r'))
 
706
        end--;
 
707
      *end = 0;
 
708
      for (ptr1 = buf; *ptr1 && grub_isspace (*ptr1); ptr1++);
 
709
      if (*ptr1 == '#' || *ptr1 == 0)
 
710
        {
 
711
          err = add_comment (menu, ptr1, 1);
 
712
          if (err)
 
713
            goto fail;
 
714
          continue;
 
715
        }
 
716
      for (ptr2 = ptr1; !grub_isspace (*ptr2) && *ptr2; ptr2++);
 
717
      for (ptr3 = ptr2;  grub_isspace (*ptr3) && *ptr3; ptr3++);
 
718
      for (ptr4 = ptr3; !grub_isspace (*ptr4) && *ptr4; ptr4++);
 
719
      for (ptr5 = ptr4;  grub_isspace (*ptr5) && *ptr5; ptr5++);
 
720
      for (i = 0; i < sizeof (commands) / sizeof (commands[0]); i++)
 
721
        if (grub_strlen (commands[i].name1) == (grub_size_t) (ptr2 - ptr1)
 
722
            && grub_strncasecmp (commands[i].name1, ptr1, ptr2 - ptr1) == 0
 
723
            && (commands[i].name2 == NULL
 
724
                || (grub_strlen (commands[i].name2)
 
725
                    == (grub_size_t) (ptr4 - ptr3)
 
726
                    && grub_strncasecmp (commands[i].name2, ptr3, ptr4 - ptr3)
 
727
                    == 0)))
 
728
          break;
 
729
      if (i == sizeof (commands) / sizeof (commands[0]))
 
730
        {
 
731
          if (sizeof ("text") - 1 == ptr2 - ptr1
 
732
              && grub_strncasecmp ("text", ptr1, ptr2 - ptr1) == 0
 
733
              && (sizeof ("help") - 1 == ptr4 - ptr3
 
734
                  && grub_strncasecmp ("help", ptr3, ptr4 - ptr3) == 0))
 
735
            {
 
736
              if (helptext (ptr5, file, menu))
 
737
                return 1;
 
738
              continue;
 
739
            }
 
740
 
 
741
          add_comment (menu, "  # UNSUPPORTED command '", 0);
 
742
          add_comment (menu, ptr1, 0);
 
743
          add_comment (menu, "'", 1);
 
744
 
 
745
          continue;
 
746
        }
 
747
      if (commands[i].parse)
 
748
        {
 
749
          err = commands[i].parse (commands[i].name2
 
750
                                   ? ptr5 : ptr3, menu);
 
751
          if (err)
 
752
            goto fail;
 
753
        }
 
754
    }
 
755
 fail:
 
756
  grub_file_close (file);
 
757
  return err;
 
758
}
 
759
 
 
760
static grub_err_t
 
761
print_escaped (struct output_buffer *outbuf, 
 
762
               const char *from, const char *to)
 
763
{
 
764
  const char *ptr;
 
765
  grub_err_t err;
 
766
  if (!to)
 
767
    to = from + grub_strlen (from);
 
768
  err = ensure_space (outbuf, (to - from) * 4 + 2);
 
769
  if (err)
 
770
    return err;
 
771
  outbuf->buf[outbuf->ptr++] = '\'';
 
772
  for (ptr = from; *ptr; ptr++)
 
773
    {
 
774
      if (*ptr == '\'')
 
775
        {
 
776
          outbuf->buf[outbuf->ptr++] = '\'';
 
777
          outbuf->buf[outbuf->ptr++] = '\\';
 
778
          outbuf->buf[outbuf->ptr++] = '\'';
 
779
          outbuf->buf[outbuf->ptr++] = '\'';
 
780
        }
 
781
      else
 
782
        outbuf->buf[outbuf->ptr++] = *ptr;
 
783
    }
 
784
  outbuf->buf[outbuf->ptr++] = '\'';
 
785
  return GRUB_ERR_NONE;
 
786
}
 
787
 
 
788
static grub_err_t
 
789
print_file (struct output_buffer *outbuf,
 
790
            struct syslinux_menu *menu, const char *from, const char *to)
 
791
{
 
792
  grub_err_t err;
 
793
  if (!to)
 
794
    to = from + grub_strlen (from);
 
795
  err = print_escaped (outbuf, from[0] == '/'
 
796
                       ? menu->root_target_directory
 
797
                       : menu->current_target_directory, NULL);
 
798
  if (err)
 
799
    return err;
 
800
 
 
801
  err = print (outbuf, "/", 1);
 
802
  if (err)
 
803
    return err;
 
804
  return print_escaped (outbuf, from, to);
 
805
}
 
806
 
 
807
static void
 
808
simplify_filename (char *str)
 
809
{
 
810
  char *iptr, *optr = str;
 
811
  for (iptr = str; *iptr; iptr++)
 
812
    {
 
813
      if (*iptr == '/' && optr != str && optr[-1] == '/')
 
814
        continue;
 
815
      if (iptr[0] == '/' && iptr[1] == '.' && iptr[2] == '/')
 
816
        {
 
817
          iptr += 2;
 
818
          continue;
 
819
        }
 
820
      if (iptr[0] == '/' && iptr[1] == '.' && iptr[2] == '.'
 
821
          && iptr[3] == '/')
 
822
        {
 
823
          iptr += 3;
 
824
          while (optr >= str && *optr != '/')
 
825
            optr--;
 
826
          if (optr < str)
 
827
            {
 
828
              str[0] = '/';
 
829
              optr = str;
 
830
            }
 
831
          optr++;
 
832
          continue;
 
833
        }
 
834
      *optr++ = *iptr;
 
835
    }
 
836
  *optr = '\0';
 
837
}
 
838
 
 
839
static grub_err_t
 
840
write_entry (struct output_buffer *outbuf,
 
841
             struct syslinux_menu *menu,
 
842
             struct syslinux_menuentry *curentry)
 
843
{
 
844
  grub_err_t err;
 
845
  if (curentry->comments)
 
846
    print (outbuf, curentry->comments, grub_strlen (curentry->comments));
 
847
  {
 
848
    struct syslinux_say *say;
 
849
    for (say = curentry->say; say && say->next; say = say->next);
 
850
    for (; say && say->prev; say = say->prev)
 
851
      {
 
852
        print_string ("echo ");
 
853
        if (print_escaped (outbuf, say->msg, NULL)) return grub_errno;
 
854
        print_string ("\n");
 
855
      }
 
856
  }
 
857
 
 
858
  /* FIXME: support help text.  */
 
859
  switch (curentry->entry_type)
 
860
    {
 
861
    case KERNEL_LINUX:
 
862
      {
 
863
        char *ptr;
 
864
        char *cmdline;
 
865
        char *initrd = NULL;
 
866
        for (ptr = curentry->append; ptr && *ptr; ptr++)
 
867
          if ((ptr == curentry->append || grub_isspace (ptr[-1]))
 
868
              && grub_strncasecmp (ptr, "initrd=", sizeof ("initrd=") - 1)
 
869
              == 0)
 
870
            break;
 
871
        if (ptr && *ptr)
 
872
          {
 
873
            char *ptr2;
 
874
            grub_size_t totlen = grub_strlen (curentry->append);
 
875
            initrd = ptr + sizeof ("initrd=") - 1;
 
876
            for (ptr2 = ptr; *ptr2 && !grub_isspace (*ptr2); ptr2++);
 
877
            if (*ptr2)
 
878
              {
 
879
                *ptr2 = 0;
 
880
                ptr2++;
 
881
              }
 
882
            cmdline = grub_malloc (totlen + 1 - (ptr2 - ptr));
 
883
            if (!cmdline)
 
884
              return grub_errno;
 
885
            grub_memcpy (cmdline, curentry->append, ptr - curentry->append);
 
886
            grub_memcpy (cmdline + (ptr - curentry->append),
 
887
                         ptr2, totlen - (ptr2 - curentry->append));
 
888
            *(cmdline + totlen - (ptr2 - ptr)) = 0;
 
889
          }
 
890
        else
 
891
          cmdline = curentry->append;
 
892
        print_string (" if test x$grub_platform = xpc; then "
 
893
                      "linux_suffix=16; else linux_suffix= ; fi\n");
 
894
        print_string ("  linux$linux_suffix ");
 
895
        print_file (outbuf, menu, curentry->kernel_file, NULL);
 
896
        print_string (" ");
 
897
        if (cmdline)
 
898
          print (outbuf, cmdline, grub_strlen (cmdline));
 
899
        print_string ("\n");
 
900
        if (initrd || curentry->initrds)
 
901
          {
 
902
            struct initrd_list *lst;
 
903
            print_string ("  initrd$linux_suffix ");
 
904
            if (initrd)
 
905
              {
 
906
                print_file (outbuf, menu, initrd, NULL);
 
907
                print_string (" ");
 
908
              }
 
909
            for (lst = curentry->initrds; lst; lst = lst->next)
 
910
              {
 
911
                print_file (outbuf, menu, lst->file, NULL);
 
912
                print_string (" ");
 
913
              }
 
914
 
 
915
            print_string ("\n");
 
916
          }
 
917
      }
 
918
      break;
 
919
    case KERNEL_CHAINLOADER:
 
920
      print_string ("  chainloader ");
 
921
      print_file (outbuf, menu, curentry->kernel_file, NULL);
 
922
      print_string ("\n");
 
923
      break;
 
924
    case KERNEL_CHAINLOADER_BPB:
 
925
      print_string ("  chainloader --bpb ");
 
926
      print_file (outbuf, menu, curentry->kernel_file, NULL);
 
927
      print_string ("\n");
 
928
      break;
 
929
    case LOCALBOOT:
 
930
      /* FIXME: support -1.  */
 
931
      /* FIXME: PXELINUX.  */
 
932
      {
 
933
        int n = grub_strtol (curentry->kernel_file, NULL, 0);
 
934
        if (n >= 0 && n <= 0x02)
 
935
          {
 
936
            print_string ("  root=fd");
 
937
            if (print_num (outbuf, n))
 
938
              return grub_errno;
 
939
            print_string (";\n  chainloader +1;\n");
 
940
 
 
941
            break;
 
942
          }
 
943
        if (n >= 0x80 && n < 0x8a)
 
944
          {
 
945
            print_string ("  root=hd");
 
946
            if (print_num (outbuf, n - 0x80))
 
947
              return grub_errno;
 
948
            print_string (";\n  chainloader +1;\n");
 
949
            break;
 
950
          }
 
951
        print_string ("  # UNSUPPORTED localboot type ");
 
952
        if (print_num (outbuf, n))
 
953
          return grub_errno;
 
954
        print_string ("\n");
 
955
        break;
 
956
      }
 
957
    case KERNEL_COM32:
 
958
    case KERNEL_COM:
 
959
      {
 
960
        char *basename = NULL;
 
961
        
 
962
        {
 
963
          char *ptr;
 
964
          for (ptr = curentry->kernel_file; *ptr; ptr++)
 
965
            if (*ptr == '/' || *ptr == '\\')
 
966
              basename = ptr;
 
967
        }
 
968
        if (!basename)
 
969
          basename = curentry->kernel_file;
 
970
        else
 
971
          basename++;
 
972
        if (grub_strcasecmp (basename, "chain.c32") == 0)
 
973
          {
 
974
            char *file = NULL;
 
975
            int is_fd = -1, devn = 0;
 
976
            int part = -1;
 
977
            int swap = 0;
 
978
            char *ptr;
 
979
            for (ptr = curentry->append; *ptr; )
 
980
              {
 
981
                while (grub_isspace (*ptr))
 
982
                  ptr++;
 
983
                /* FIXME: support mbr: and boot.  */
 
984
                if (ptr[0] == 'h' && ptr[1] == 'd')
 
985
                  {
 
986
                    is_fd = 0;
 
987
                    devn = grub_strtoul (ptr + 2, &ptr, 0);
 
988
                    continue;
 
989
                  }
 
990
                if (grub_strncasecmp (ptr, "file=", 5) == 0)
 
991
                  {
 
992
                    file = ptr + 5;
 
993
                    for (ptr = file; *ptr && !grub_isspace (*ptr); ptr++);
 
994
                    if (*ptr)
 
995
                      {
 
996
                        *ptr = 0;
 
997
                        ptr++;
 
998
                      }
 
999
                    continue;
 
1000
                  }
 
1001
                if (grub_strncasecmp (ptr, "swap", sizeof ("swap") - 1) == 0)
 
1002
                  {
 
1003
                    swap = 1;
 
1004
                    ptr += sizeof ("swap") - 1;
 
1005
                    continue;
 
1006
                  }
 
1007
 
 
1008
                if (ptr[0] == 'f' && ptr[1] == 'd')
 
1009
                  {
 
1010
                    is_fd = 1;
 
1011
                    devn = grub_strtoul (ptr + 2, &ptr, 0);
 
1012
                    continue;
 
1013
                  }
 
1014
                if (grub_isdigit (ptr[0]))
 
1015
                  {
 
1016
                    part = grub_strtoul (ptr, &ptr, 0);
 
1017
                    continue;
 
1018
                  }
 
1019
                /* FIXME: isolinux, ntldr, cmldr, *dos, seg, hide
 
1020
                   FIXME: sethidden.  */
 
1021
                print_string ("  # UNSUPPORTED option ");
 
1022
                if (print (outbuf, ptr, grub_strlen (ptr)))
 
1023
                  return 0;
 
1024
                print_string ("\n");
 
1025
                break;
 
1026
              }
 
1027
            if (is_fd == -1)
 
1028
              {
 
1029
                print_string ("  # no drive specified\n");
 
1030
                break;
 
1031
              }
 
1032
            if (!*ptr)
 
1033
              {
 
1034
                print_string (is_fd ? " root=fd": " root=hd");
 
1035
                if (print_num (outbuf, devn))
 
1036
                  return grub_errno;
 
1037
                if (part != -1)
 
1038
                  {
 
1039
                    print_string (",");
 
1040
                    if (print_num (outbuf, part + 1))
 
1041
                      return grub_errno;
 
1042
                  }
 
1043
                print_string (";\n");
 
1044
                if (file)
 
1045
                  {
 
1046
                    print_string ("  chainloader ");
 
1047
                    print_file (outbuf, menu, file, NULL);
 
1048
                    print_string (";\n");
 
1049
                  }
 
1050
                else
 
1051
                  print_string (" chainloader +1;\n");
 
1052
                if (swap)
 
1053
                  print_string (" drivemap -s hd0 \"root\";\n");
 
1054
              }
 
1055
            break;
 
1056
          }
 
1057
 
 
1058
        if (grub_strcasecmp (basename, "mboot.c32") == 0)
 
1059
          {
 
1060
            char *ptr;
 
1061
            int first = 1;
 
1062
            int is_kernel = 1;
 
1063
            for (ptr = curentry->append; *ptr; )
 
1064
              {
 
1065
                char *ptrr = ptr;
 
1066
                while (*ptr && !grub_isspace (*ptr))
 
1067
                  ptr++;
 
1068
                if (ptrr + 2 == ptr && ptrr[0] == '-' && ptrr[1] == '-')
 
1069
                  {
 
1070
                    print_string ("\n");
 
1071
                    first = 1;
 
1072
                    continue;
 
1073
                  }
 
1074
                if (first)
 
1075
                  {
 
1076
                    if (is_kernel)
 
1077
                      print_string ("  multiboot ");
 
1078
                    else
 
1079
                      print_string ("  module ");
 
1080
                    first = 0;
 
1081
                    is_kernel = 0;
 
1082
                    if (print_file (outbuf, menu, ptrr, ptr))
 
1083
                      return grub_errno;
 
1084
                    continue;
 
1085
                  }
 
1086
                if (print_escaped (outbuf, ptrr, ptr))
 
1087
                  return grub_errno;
 
1088
              }
 
1089
            break;
 
1090
          }
 
1091
 
 
1092
        if (grub_strcasecmp (basename, "ifcpu64.c32") == 0)
 
1093
          {
 
1094
            char *lm, *lme, *pae = 0, *paee = 0, *i386s = 0, *i386e = 0;
 
1095
            char *ptr;
 
1096
            ptr = curentry->append;
 
1097
            while (grub_isspace (*ptr))
 
1098
              ptr++;
 
1099
            lm = ptr;
 
1100
            while (*ptr && !grub_isspace (*ptr))
 
1101
              ptr++;
 
1102
            lme = ptr;
 
1103
            while (grub_isspace (*ptr))
 
1104
              ptr++;
 
1105
            if (ptr[0] == '-' && ptr[1] == '-')
 
1106
              {
 
1107
                ptr += 2;
 
1108
                while (grub_isspace (*ptr))
 
1109
                  ptr++;
 
1110
                pae = ptr;
 
1111
                while (*ptr && !grub_isspace (*ptr))
 
1112
                  ptr++;
 
1113
                paee = ptr;
 
1114
              }
 
1115
            while (grub_isspace (*ptr))
 
1116
              ptr++;
 
1117
            if (ptr[0] == '-' && ptr[1] == '-')
 
1118
              {
 
1119
                ptr += 2;
 
1120
                while (grub_isspace (*ptr))
 
1121
                  ptr++;
 
1122
                i386s = ptr;
 
1123
                while (*ptr && !grub_isspace (*ptr))
 
1124
                  ptr++;
 
1125
                i386e = ptr;
 
1126
              }
 
1127
            if (lme)
 
1128
              *lme = '\0';
 
1129
            if (paee)
 
1130
              *paee = '\0';
 
1131
            if (i386e)
 
1132
              *i386e = '\0';
 
1133
            if (!i386s)
 
1134
              {
 
1135
                i386s = pae;
 
1136
                pae = 0;
 
1137
              }
 
1138
            print_string ("if cpuid --long-mode; then true;\n");
 
1139
            if (print_entry (outbuf, menu, lm))
 
1140
              return grub_errno;
 
1141
            if (pae)
 
1142
              {
 
1143
                print_string ("elif cpuid --pae; then true;\n");
 
1144
                if (print_entry (outbuf, menu, pae))
 
1145
                  return grub_errno;
 
1146
              }
 
1147
            print_string ("else\n");
 
1148
            if (print_entry (outbuf, menu, i386s))
 
1149
              return grub_errno;
 
1150
            print_string ("fi\n");
 
1151
            break;
 
1152
          }
 
1153
 
 
1154
        if (grub_strcasecmp (basename, "reboot.c32") == 0)
 
1155
          {
 
1156
            print_string ("  reboot\n");
 
1157
            break;
 
1158
          }
 
1159
 
 
1160
        if (grub_strcasecmp (basename, "poweroff.com") == 0)
 
1161
          {
 
1162
            print_string ("  halt\n");
 
1163
            break;
 
1164
          }
 
1165
 
 
1166
        if (grub_strcasecmp (basename, "whichsys.c32") == 0)
 
1167
          {
 
1168
            grub_syslinux_flavour_t flavour = GRUB_SYSLINUX_ISOLINUX;
 
1169
            const char *flav[] = 
 
1170
              { 
 
1171
                [GRUB_SYSLINUX_ISOLINUX] = "iso",
 
1172
                [GRUB_SYSLINUX_PXELINUX] = "pxe",
 
1173
                [GRUB_SYSLINUX_SYSLINUX] = "sys"
 
1174
              };
 
1175
            char *ptr;
 
1176
            for (ptr = curentry->append; *ptr; )
 
1177
              {
 
1178
                char *bptr, c;
 
1179
                while (grub_isspace (*ptr))
 
1180
                  ptr++;
 
1181
                if (grub_strncasecmp (ptr, "-iso-", 5) == 0)
 
1182
                  {
 
1183
                    ptr += sizeof ("-iso-") - 1;
 
1184
                    flavour = GRUB_SYSLINUX_ISOLINUX;
 
1185
                    continue;
 
1186
                  }
 
1187
                if (grub_strncasecmp (ptr, "-pxe-", 5) == 0)
 
1188
                  {
 
1189
                    ptr += sizeof ("-pxe-") - 1;
 
1190
                    flavour = GRUB_SYSLINUX_PXELINUX;
 
1191
                    continue;
 
1192
                  }
 
1193
                if (grub_strncasecmp (ptr, "-sys-", 5) == 0)
 
1194
                  {
 
1195
                    ptr += sizeof ("-sys-") - 1;
 
1196
                    flavour = GRUB_SYSLINUX_SYSLINUX;
 
1197
                    continue;
 
1198
                  }
 
1199
                bptr = ptr;
 
1200
                while (*ptr && !grub_isspace (*ptr))
 
1201
                  ptr++;
 
1202
                c = *ptr;
 
1203
                *ptr = '\0';
 
1204
                if (menu->flavour == GRUB_SYSLINUX_UNKNOWN
 
1205
                    && flavour == GRUB_SYSLINUX_ISOLINUX)
 
1206
                  {
 
1207
                    print_string ("if [ x$syslinux_flavour = xiso -o x$syslinux_flavour = x ]; then true;\n");
 
1208
                    menu->flavour = GRUB_SYSLINUX_ISOLINUX;
 
1209
                    print_entry (outbuf, menu, bptr);
 
1210
                    menu->flavour = GRUB_SYSLINUX_UNKNOWN;
 
1211
                    print_string ("fi\n");
 
1212
                  }
 
1213
                else if (menu->flavour == GRUB_SYSLINUX_UNKNOWN)
 
1214
                  {
 
1215
                    print_string ("if [ x$syslinux_flavour = x");
 
1216
                    err = print (outbuf, flav[flavour], grub_strlen (flav[flavour]));
 
1217
                    if (err)
 
1218
                      return err;
 
1219
                    print_string (" ]; then true;\n");
 
1220
                    menu->flavour = flavour;
 
1221
                    print_entry (outbuf, menu, bptr);
 
1222
                    menu->flavour = GRUB_SYSLINUX_UNKNOWN;
 
1223
                    print_string ("fi\n");
 
1224
                  }
 
1225
                if (menu->flavour != GRUB_SYSLINUX_UNKNOWN
 
1226
                    && menu->flavour == flavour)
 
1227
                  print_entry (outbuf, menu, bptr);
 
1228
                *ptr = c;
 
1229
              }
 
1230
            break;
 
1231
          }
 
1232
 
 
1233
        /* FIXME: gdb, GFXBoot, Hdt, Ifcpu, Ifplop, Kbdmap,
 
1234
           FIXME: Linux, Lua, Meminfo, rosh, Sanbboot  */
 
1235
 
 
1236
        print_string ("  # UNSUPPORTED com(32) ");
 
1237
        err = print (outbuf, basename, grub_strlen (basename));
 
1238
        if (err)
 
1239
          return err;
 
1240
        print_string ("\ntrue;\n");
 
1241
        break;
 
1242
      }
 
1243
    case KERNEL_CONFIG:
 
1244
      {
 
1245
        char *new_cwd, *new_target_cwd;
 
1246
        const char *ap;
 
1247
        ap = curentry->append;
 
1248
        if (!ap)
 
1249
          ap = curentry->argument;
 
1250
        if (!ap)
 
1251
          ap = "";
 
1252
        new_cwd = get_read_filename (menu, ap);
 
1253
        if (!new_cwd)
 
1254
          return grub_errno;
 
1255
        new_target_cwd = get_target_filename (menu, ap);
 
1256
        if (!new_target_cwd)
 
1257
          return grub_errno;
 
1258
 
 
1259
        struct syslinux_menu *menuptr;
 
1260
        char *newname;
 
1261
        int depth = 0;
 
1262
        
 
1263
        newname = get_read_filename (menu, curentry->kernel_file);
 
1264
        if (!newname)
 
1265
          return grub_errno;
 
1266
        simplify_filename (newname);
 
1267
 
 
1268
        print_string ("#");
 
1269
        print_file (outbuf, menu, curentry->kernel_file, NULL);
 
1270
        print_string (" ");
 
1271
        print (outbuf, newname, grub_strlen (newname));
 
1272
        print_string (":\n");
 
1273
 
 
1274
        for (menuptr = menu; menuptr; menuptr = menuptr->parent, depth++)
 
1275
          if (grub_strcmp (menuptr->filename, newname) == 0
 
1276
              || depth > 20)
 
1277
            break;
 
1278
        if (menuptr)
 
1279
          {
 
1280
            print_string ("  syslinux_configfile -r ");
 
1281
            print_file (outbuf, menu, "/", NULL);
 
1282
            print_string (" -c ");
 
1283
            print_file (outbuf, menu, ap, NULL);
 
1284
            print_string (" ");
 
1285
            print_file (outbuf, menu, curentry->kernel_file, NULL);
 
1286
            print_string ("\n");
 
1287
          }
 
1288
        else
 
1289
          {
 
1290
            err = config_file (outbuf, menu->root_read_directory,
 
1291
                               menu->root_target_directory, new_cwd, new_target_cwd,
 
1292
                               newname, menu, menu->flavour);
 
1293
            if (err == GRUB_ERR_FILE_NOT_FOUND
 
1294
                || err == GRUB_ERR_BAD_FILENAME)
 
1295
              {
 
1296
                grub_errno = err = GRUB_ERR_NONE;
 
1297
                print_string ("# File ");
 
1298
                err = print (outbuf, newname, grub_strlen (newname));
 
1299
                if (err)
 
1300
                  return err;
 
1301
                print_string (" not found\n");
 
1302
              }
 
1303
            if (err)
 
1304
              return err;
 
1305
          }
 
1306
        grub_free (newname);
 
1307
        grub_free (new_cwd);
 
1308
        grub_free (new_target_cwd);
 
1309
      }
 
1310
      break;
 
1311
    case KERNEL_NO_KERNEL:
 
1312
      /* FIXME: support this.  */
 
1313
    case KERNEL_BIN:
 
1314
    case KERNEL_PXE:
 
1315
    case KERNEL_IMG:
 
1316
      print_string ("  # UNSUPPORTED entry type ");
 
1317
      if (print_num (outbuf, curentry->entry_type))
 
1318
        return grub_errno;
 
1319
      print_string ("\ntrue;\n");
 
1320
      break;
 
1321
    }
 
1322
  return GRUB_ERR_NONE;
 
1323
}
 
1324
 
 
1325
static grub_err_t
 
1326
print_entry (struct output_buffer *outbuf,
 
1327
             struct syslinux_menu *menu,
 
1328
             const char *str)
 
1329
{
 
1330
  struct syslinux_menuentry *curentry;
 
1331
  for (curentry = menu->entries; curentry; curentry = curentry->next)
 
1332
    if (grub_strcasecmp (curentry->label, str) == 0)
 
1333
      {
 
1334
        grub_err_t err;
 
1335
        err = write_entry (outbuf, menu, curentry);
 
1336
        if (err)
 
1337
          return err;
 
1338
      }
 
1339
  return GRUB_ERR_NONE;
 
1340
}
 
1341
 
 
1342
static void
 
1343
free_menu (struct syslinux_menu *menu)
 
1344
{
 
1345
  struct syslinux_say *say, *nsay;
 
1346
  struct syslinux_menuentry *entry, *nentry;
 
1347
 
 
1348
  grub_free (menu->def);
 
1349
  grub_free (menu->comments);
 
1350
  grub_free (menu->background);
 
1351
  for (say = menu->say; say ; say = nsay)
 
1352
    {
 
1353
      nsay = say->next;
 
1354
      grub_free (say->msg);
 
1355
      grub_free (say);
 
1356
    }
 
1357
 
 
1358
  for (entry = menu->entries; entry ; entry = nentry)
 
1359
    {
 
1360
      nentry = entry->next;
 
1361
      struct initrd_list *initrd, *ninitrd;
 
1362
 
 
1363
      for (initrd = entry->initrds; initrd ; initrd = ninitrd)
 
1364
        {
 
1365
          ninitrd = initrd->next;
 
1366
          grub_free (initrd->file);
 
1367
          grub_free (initrd);
 
1368
        }
 
1369
 
 
1370
      grub_free (entry->comments);
 
1371
      grub_free (entry->kernel_file);
 
1372
      grub_free (entry->label);
 
1373
      grub_free (entry->extlabel);
 
1374
      grub_free (entry->append);
 
1375
      grub_free (entry->help);
 
1376
      grub_free (entry);
 
1377
    }
 
1378
}
 
1379
 
 
1380
static grub_err_t
 
1381
config_file (struct output_buffer *outbuf,
 
1382
             const char *root, const char *target_root,
 
1383
             const char *cwd, const char *target_cwd,
 
1384
             const char *fname, struct syslinux_menu *parent,
 
1385
             grub_syslinux_flavour_t flav)
 
1386
{
 
1387
  grub_err_t err;
 
1388
  struct syslinux_menu menu;
 
1389
  struct syslinux_menuentry *curentry, *lentry;
 
1390
  struct syslinux_say *say;
 
1391
 
 
1392
  grub_memset (&menu, 0, sizeof (menu));
 
1393
  menu.flavour = flav;
 
1394
  menu.root_read_directory = root;
 
1395
  menu.root_target_directory = target_root;
 
1396
  menu.current_read_directory = cwd;
 
1397
  menu.current_target_directory = target_cwd;
 
1398
 
 
1399
  menu.filename = fname;
 
1400
  menu.parent = parent;
 
1401
  err = syslinux_parse_real (&menu);
 
1402
  if (err)
 
1403
    return err;
 
1404
 
 
1405
  for (say = menu.say; say && say->next; say = say->next);
 
1406
  for (; say && say->prev; say = say->prev)
 
1407
    {
 
1408
      print_string ("echo ");
 
1409
      err = print_escaped (outbuf, say->msg, NULL);
 
1410
      if (err)
 
1411
        return err;
 
1412
      print_string ("\n");
 
1413
    }
 
1414
 
 
1415
  if (menu.background)
 
1416
    {
 
1417
      print_string ("  background_image ");
 
1418
      err = print_file (outbuf, &menu, menu.background, NULL);
 
1419
      if (err)
 
1420
        return err;
 
1421
      print_string ("\n");
 
1422
    }
 
1423
 
 
1424
  if (menu.timeout == 0 && menu.entries && menu.def)
 
1425
    {
 
1426
      err = print_entry (outbuf, &menu, menu.def);
 
1427
      if (err)
 
1428
        return err;
 
1429
    }
 
1430
  else if (menu.entries)
 
1431
    {
 
1432
      for (curentry = menu.entries; curentry->next; curentry = curentry->next);
 
1433
      lentry = curentry;
 
1434
 
 
1435
      print_string ("set timeout='");
 
1436
      err = print_num (outbuf, (menu.timeout + 9) / 10);
 
1437
      if (err)
 
1438
        return err;
 
1439
      print_string ("\n");
 
1440
      if (menu.comments)
 
1441
        {
 
1442
          err = print (outbuf, menu.comments, grub_strlen (menu.comments));
 
1443
          if (err)
 
1444
            return err;
 
1445
        }
 
1446
 
 
1447
      if (menu.def)
 
1448
        {
 
1449
          print_string (" default=");
 
1450
          err = print_escaped (outbuf, menu.def, NULL);
 
1451
          if (err)
 
1452
            return err;
 
1453
          print_string ("\n");
 
1454
        }
 
1455
      for (curentry = lentry; curentry; curentry = curentry->prev)
 
1456
        {      
 
1457
          print_string ("menuentry ");
 
1458
          err = print_escaped (outbuf,
 
1459
                               curentry->extlabel ? : curentry->label, NULL);
 
1460
          if (err)
 
1461
            return err;
 
1462
          if (curentry->hotkey)
 
1463
            {
 
1464
              char hk[] = { curentry->hotkey, '\0' };
 
1465
              print_string (" --hotkey '");
 
1466
              print_string (hk);
 
1467
              print_string ("'");
 
1468
            }
 
1469
          print_string (" --id ");
 
1470
          err = print_escaped (outbuf, curentry->label, NULL);
 
1471
          if (err)
 
1472
            return err;
 
1473
          print_string (" {\n");
 
1474
 
 
1475
          err = write_entry (outbuf, &menu, curentry);
 
1476
          if (err)
 
1477
            return err;
 
1478
 
 
1479
          print_string ("}\n");
 
1480
        }
 
1481
    }
 
1482
  free_menu (&menu);
 
1483
  return GRUB_ERR_NONE;
 
1484
}
 
1485
 
 
1486
char *
 
1487
grub_syslinux_config_file (const char *base, const char *target_base,
 
1488
                           const char *cwd, const char *target_cwd,
 
1489
                           const char *fname, grub_syslinux_flavour_t flav)
 
1490
{
 
1491
  struct output_buffer outbuf = { 0, 0, 0 };
 
1492
  grub_err_t err;
 
1493
  err = config_file (&outbuf, base, target_base, cwd, target_cwd,
 
1494
                     fname, NULL, flav);
 
1495
  if (err)
 
1496
    return NULL;
 
1497
  err = print (&outbuf, "\0", 1);
 
1498
  if (err)
 
1499
    return NULL;
 
1500
  return outbuf.buf;
 
1501
}