2013-12-18 04:28:05 +00:00
|
|
|
/*
|
|
|
|
* GRUB -- GRand Unified Bootloader
|
|
|
|
* Copyright (C) 2013 Free Software Foundation, Inc.
|
|
|
|
*
|
|
|
|
* GRUB is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* GRUB is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <grub/mm.h>
|
|
|
|
#include <grub/file.h>
|
|
|
|
#include <grub/normal.h>
|
|
|
|
#include <grub/syslinux_parse.h>
|
|
|
|
|
|
|
|
struct syslinux_say
|
|
|
|
{
|
|
|
|
struct syslinux_say *next;
|
|
|
|
struct syslinux_say *prev;
|
|
|
|
char msg[0];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct initrd_list
|
|
|
|
{
|
|
|
|
struct initrd_list *next;
|
|
|
|
char *file;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct syslinux_menuentry
|
|
|
|
{
|
|
|
|
struct syslinux_menuentry *next;
|
|
|
|
struct syslinux_menuentry *prev;
|
|
|
|
char *label;
|
|
|
|
char *extlabel;
|
|
|
|
char *kernel_file;
|
|
|
|
struct initrd_list *initrds;
|
|
|
|
struct initrd_list *initrds_last;
|
|
|
|
char *append;
|
|
|
|
char *argument;
|
|
|
|
char *help;
|
|
|
|
char *comments;
|
|
|
|
grub_size_t commentslen;
|
|
|
|
char hotkey;
|
|
|
|
int make_default;
|
|
|
|
struct syslinux_say *say;
|
|
|
|
|
|
|
|
enum { KERNEL_NO_KERNEL, KERNEL_LINUX, KERNEL_CHAINLOADER,
|
|
|
|
KERNEL_BIN, KERNEL_PXE, KERNEL_CHAINLOADER_BPB,
|
|
|
|
KERNEL_COM32, KERNEL_COM, KERNEL_IMG, KERNEL_CONFIG, LOCALBOOT }
|
|
|
|
entry_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct syslinux_menu
|
|
|
|
{
|
|
|
|
struct syslinux_menu *parent;
|
|
|
|
struct syslinux_menuentry *entries;
|
|
|
|
char *def;
|
|
|
|
char *comments;
|
|
|
|
char *background;
|
|
|
|
const char *root_read_directory;
|
|
|
|
const char *root_target_directory;
|
|
|
|
const char *current_read_directory;
|
|
|
|
const char *current_target_directory;
|
|
|
|
const char *filename;
|
|
|
|
grub_size_t commentslen;
|
2013-12-18 11:29:30 +00:00
|
|
|
unsigned long timeout;
|
2013-12-18 04:28:05 +00:00
|
|
|
struct syslinux_say *say;
|
|
|
|
grub_syslinux_flavour_t flavour;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct output_buffer
|
|
|
|
{
|
|
|
|
grub_size_t alloc;
|
|
|
|
grub_size_t ptr;
|
|
|
|
char *buf;
|
|
|
|
};
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
syslinux_parse_real (struct syslinux_menu *menu);
|
|
|
|
static grub_err_t
|
|
|
|
config_file (struct output_buffer *outbuf,
|
|
|
|
const char *root, const char *target_root,
|
|
|
|
const char *cwd, const char *target_cwd,
|
|
|
|
const char *fname, struct syslinux_menu *parent,
|
|
|
|
grub_syslinux_flavour_t flav);
|
|
|
|
static grub_err_t
|
|
|
|
print_entry (struct output_buffer *outbuf,
|
|
|
|
struct syslinux_menu *menu,
|
|
|
|
const char *str);
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
ensure_space (struct output_buffer *outbuf, grub_size_t len)
|
|
|
|
{
|
|
|
|
grub_size_t newlen;
|
|
|
|
char *newbuf;
|
|
|
|
if (len < outbuf->alloc - outbuf->ptr)
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
newlen = (outbuf->ptr + len + 10) * 2;
|
|
|
|
newbuf = grub_realloc (outbuf->buf, newlen);
|
|
|
|
if (!newbuf)
|
|
|
|
return grub_errno;
|
|
|
|
outbuf->alloc = newlen;
|
|
|
|
outbuf->buf = newbuf;
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
print (struct output_buffer *outbuf, const char *str, grub_size_t len)
|
|
|
|
{
|
|
|
|
grub_err_t err;
|
|
|
|
err = ensure_space (outbuf, len);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
grub_memcpy (&outbuf->buf[outbuf->ptr], str, len);
|
|
|
|
outbuf->ptr += len;
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
add_comment (struct syslinux_menu *menu, const char *comment, int nl)
|
|
|
|
{
|
|
|
|
if (menu->entries)
|
|
|
|
{
|
|
|
|
if (menu->entries->commentslen == 0 && *comment == 0)
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
menu->entries->comments = grub_realloc (menu->entries->comments,
|
|
|
|
menu->entries->commentslen
|
|
|
|
+ 2 + grub_strlen (comment));
|
|
|
|
if (!menu->entries->comments)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->commentslen
|
|
|
|
+= grub_stpcpy (menu->entries->comments + menu->entries->commentslen,
|
|
|
|
comment)
|
|
|
|
- (menu->entries->comments + menu->entries->commentslen);
|
|
|
|
if (nl)
|
|
|
|
menu->entries->comments[menu->entries->commentslen++] = '\n';
|
|
|
|
menu->entries->comments[menu->entries->commentslen] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (menu->commentslen == 0 && *comment == 0)
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
menu->comments = grub_realloc (menu->comments, menu->commentslen
|
|
|
|
+ 2 + grub_strlen (comment));
|
|
|
|
if (!menu->comments)
|
|
|
|
return grub_errno;
|
|
|
|
menu->commentslen += grub_stpcpy (menu->comments + menu->commentslen,
|
|
|
|
comment)
|
|
|
|
- (menu->comments + menu->commentslen);
|
|
|
|
if (nl)
|
|
|
|
menu->comments[menu->commentslen++] = '\n';
|
|
|
|
menu->comments[menu->commentslen] = '\0';
|
|
|
|
}
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define print_string(x) do { err = print (outbuf, x, sizeof (x) - 1); if (err) return err; } while (0)
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
print_num (struct output_buffer *outbuf, int n)
|
|
|
|
{
|
|
|
|
char buf[20];
|
|
|
|
grub_snprintf (buf, sizeof (buf), "%d", n);
|
|
|
|
return print (outbuf, buf, grub_strlen (buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
label (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
struct syslinux_menuentry *entry;
|
|
|
|
|
|
|
|
entry = grub_malloc (sizeof (*entry));
|
|
|
|
if (!entry)
|
|
|
|
return grub_errno;
|
|
|
|
grub_memset (entry, 0, sizeof (*entry));
|
|
|
|
entry->label = grub_strdup (line);
|
|
|
|
if (!entry->label)
|
|
|
|
{
|
|
|
|
grub_free (entry);
|
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
entry->next = menu->entries;
|
|
|
|
entry->prev = NULL;
|
|
|
|
if (menu->entries)
|
|
|
|
menu->entries->prev = entry;
|
|
|
|
menu->entries = entry;
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
kernel (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
const char *end = line + grub_strlen (line);
|
|
|
|
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
|
|
|
|
menu->entries->entry_type = KERNEL_LINUX;
|
|
|
|
|
|
|
|
if (end - line >= 2 && grub_strcmp (end - 2, ".0") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_PXE;
|
|
|
|
|
|
|
|
if (end - line >= 4 && grub_strcasecmp (end - 4, ".bin") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_BIN;
|
|
|
|
|
|
|
|
if (end - line >= 3 && grub_strcasecmp (end - 3, ".bs") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_CHAINLOADER;
|
|
|
|
|
|
|
|
if (end - line >= 4 && grub_strcasecmp (end - 4, ".bss") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_CHAINLOADER_BPB;
|
|
|
|
|
|
|
|
if (end - line >= 4 && grub_strcasecmp (end - 4, ".c32") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_COM32;
|
|
|
|
|
|
|
|
if (end - line >= 4 && grub_strcasecmp (end - 4, ".cbt") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_COM;
|
|
|
|
|
|
|
|
if (end - line >= 4 && grub_strcasecmp (end - 4, ".com") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_COM;
|
|
|
|
|
|
|
|
if (end - line >= 4 && grub_strcasecmp (end - 4, ".img") == 0)
|
|
|
|
menu->entries->entry_type = KERNEL_IMG;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_linux (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = KERNEL_LINUX;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_boot (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = KERNEL_CHAINLOADER;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_bss (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = KERNEL_CHAINLOADER_BPB;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_pxe (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = KERNEL_PXE;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_fdimage (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = KERNEL_IMG;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_comboot (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = KERNEL_COM;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_com32 (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = KERNEL_COM32;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_config (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
const char *space;
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
for (space = line; *space && !grub_isspace (*space); space++);
|
|
|
|
menu->entries->kernel_file = grub_strndup (line, space - line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
for (; *space && grub_isspace (*space); space++);
|
|
|
|
if (*space)
|
|
|
|
{
|
|
|
|
menu->entries->argument = grub_strdup (space);
|
|
|
|
if (!menu->entries->argument)
|
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
menu->entries->entry_type = KERNEL_CONFIG;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_append (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->append = grub_strdup (line);
|
|
|
|
if (!menu->entries->append)
|
|
|
|
return grub_errno;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_initrd (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
struct initrd_list *ninitrd;
|
|
|
|
const char *comma;
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
while (*line)
|
|
|
|
{
|
|
|
|
for (comma = line; *comma && *comma != ','; comma++);
|
|
|
|
|
|
|
|
ninitrd = grub_malloc (sizeof (*ninitrd));
|
|
|
|
if (!ninitrd)
|
|
|
|
return grub_errno;
|
|
|
|
ninitrd->file = grub_strndup (line, comma - line);
|
|
|
|
if (!ninitrd->file)
|
|
|
|
{
|
|
|
|
grub_free (ninitrd);
|
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
ninitrd->next = NULL;
|
|
|
|
if (menu->entries->initrds_last)
|
|
|
|
menu->entries->initrds_last->next = ninitrd;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
menu->entries->initrds_last = ninitrd;
|
|
|
|
menu->entries->initrds = ninitrd;
|
|
|
|
}
|
|
|
|
|
|
|
|
line = comma;
|
|
|
|
while (*line == ',')
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_default (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
menu->def = grub_strdup (line);
|
|
|
|
if (!menu->def)
|
|
|
|
return grub_errno;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_timeout (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
menu->timeout = grub_strtoul (line, NULL, 0);
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_menudefault (const char *line __attribute__ ((unused)),
|
|
|
|
struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->make_default = 1;
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_menubackground (const char *line,
|
|
|
|
struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
menu->background = grub_strdup (line);
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_localboot (const char *line,
|
|
|
|
struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->kernel_file = grub_strdup (line);
|
|
|
|
if (!menu->entries->kernel_file)
|
|
|
|
return grub_errno;
|
|
|
|
menu->entries->entry_type = LOCALBOOT;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_extlabel (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
const char *in;
|
|
|
|
char *out;
|
|
|
|
|
|
|
|
if (!menu->entries)
|
|
|
|
return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label");
|
|
|
|
|
|
|
|
menu->entries->extlabel = grub_malloc (grub_strlen (line) + 1);
|
|
|
|
if (!menu->entries->extlabel)
|
|
|
|
return grub_errno;
|
|
|
|
in = line;
|
|
|
|
out = menu->entries->extlabel;
|
|
|
|
while (*in)
|
|
|
|
{
|
|
|
|
if (in[0] == '^' && in[1])
|
|
|
|
{
|
|
|
|
menu->entries->hotkey = grub_tolower (in[1]);
|
|
|
|
in++;
|
|
|
|
}
|
|
|
|
*out++ = *in++;
|
|
|
|
}
|
|
|
|
*out = 0;
|
|
|
|
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
cmd_say (const char *line, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
struct syslinux_say *nsay;
|
|
|
|
nsay = grub_malloc (sizeof (*nsay) + grub_strlen (line) + 1);
|
|
|
|
if (!nsay)
|
|
|
|
return grub_errno;
|
|
|
|
nsay->prev = NULL;
|
|
|
|
if (menu->entries)
|
|
|
|
{
|
|
|
|
nsay->next = menu->entries->say;
|
|
|
|
menu->entries->say = nsay;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nsay->next = menu->say;
|
|
|
|
menu->say = nsay;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsay->next)
|
|
|
|
nsay->next->prev = nsay;
|
|
|
|
|
|
|
|
grub_memcpy (nsay->msg, line, grub_strlen (line) + 1);
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_read_filename (struct syslinux_menu *menu,
|
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
return grub_xasprintf ("%s/%s",
|
|
|
|
filename[0] == '/' ? menu->root_read_directory
|
|
|
|
: menu->current_read_directory, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_target_filename (struct syslinux_menu *menu,
|
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
return grub_xasprintf ("%s/%s",
|
|
|
|
filename[0] == '/' ? menu->root_target_directory
|
|
|
|
: menu->current_target_directory, filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
syslinux_parse (const char *filename,
|
|
|
|
struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
const char *old_filename = menu->filename;
|
|
|
|
grub_err_t ret;
|
|
|
|
char *nf;
|
|
|
|
nf = get_read_filename (menu, filename);
|
|
|
|
if (!nf)
|
|
|
|
return grub_errno;
|
|
|
|
menu->filename = nf;
|
|
|
|
ret = syslinux_parse_real (menu);
|
|
|
|
if (ret == GRUB_ERR_FILE_NOT_FOUND
|
|
|
|
|| ret == GRUB_ERR_BAD_FILENAME)
|
|
|
|
{
|
|
|
|
grub_errno = ret = GRUB_ERR_NONE;
|
|
|
|
add_comment (menu, "# File ", 0);
|
|
|
|
add_comment (menu, nf, 0);
|
|
|
|
add_comment (menu, " not found", 1);
|
|
|
|
}
|
|
|
|
grub_free (nf);
|
|
|
|
menu->filename = old_filename;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
const char *name1;
|
|
|
|
const char *name2;
|
|
|
|
grub_err_t (*parse) (const char *line, struct syslinux_menu *menu);
|
|
|
|
} commands[] = {
|
|
|
|
/* FIXME: support tagname. */
|
|
|
|
{"include", NULL, syslinux_parse},
|
|
|
|
{"menu", "include", syslinux_parse},
|
|
|
|
{"label", NULL, label},
|
|
|
|
{"kernel", NULL, kernel},
|
|
|
|
{"linux", NULL, cmd_linux},
|
|
|
|
{"boot", NULL, cmd_boot},
|
|
|
|
{"bss", NULL, cmd_bss},
|
|
|
|
{"pxe", NULL, cmd_pxe},
|
|
|
|
{"fdimage", NULL, cmd_fdimage},
|
|
|
|
{"comboot", NULL, cmd_comboot},
|
|
|
|
{"com32", NULL, cmd_com32},
|
|
|
|
{"config", NULL, cmd_config},
|
|
|
|
{"append", NULL, cmd_append},
|
|
|
|
/* FIXME: ipappend not supported. */
|
|
|
|
{"localboot", NULL, cmd_localboot},
|
|
|
|
{"initrd", NULL, cmd_initrd},
|
|
|
|
{"default", NULL, cmd_default},
|
|
|
|
{"menu", "label", cmd_extlabel},
|
|
|
|
/* FIXME: MENU LABEL not supported. */
|
|
|
|
/* FIXME: MENU HIDDEN not supported. */
|
|
|
|
/* FIXME: MENU SEPARATOR not supported. */
|
|
|
|
/* FIXME: MENU INDENT not supported. */
|
|
|
|
/* FIXME: MENU DISABLE not supported. */
|
|
|
|
/* FIXME: MENU HIDE not supported. */
|
|
|
|
{"menu", "default", cmd_menudefault},
|
|
|
|
/* FIXME: MENU PASSWD not supported. */
|
|
|
|
/* FIXME: MENU MASTER PASSWD not supported. */
|
|
|
|
{"menu", "background", cmd_menubackground},
|
|
|
|
/* FIXME: MENU BEGIN not supported. */
|
|
|
|
/* FIXME: MENU GOTO not supported. */
|
|
|
|
/* FIXME: MENU EXIT not supported. */
|
|
|
|
/* FIXME: MENU QUIT not supported. */
|
|
|
|
/* FIXME: MENU START not supported. */
|
|
|
|
/* FIXME: MENU AUTOBOOT not supported. */
|
|
|
|
/* FIXME: MENU TABMSG not supported. */
|
|
|
|
/* FIXME: MENU NOTABMSG not supported. */
|
|
|
|
/* FIXME: MENU PASSPROMPT not supported. */
|
|
|
|
/* FIXME: MENU COLOR not supported. */
|
|
|
|
/* FIXME: MENU MSGCOLOR not supported. */
|
|
|
|
/* FIXME: MENU WIDTH not supported. */
|
|
|
|
/* FIXME: MENU MARGIN not supported. */
|
|
|
|
/* FIXME: MENU PASSWORDMARGIN not supported. */
|
|
|
|
/* FIXME: MENU ROWS not supported. */
|
|
|
|
/* FIXME: MENU TABMSGROW not supported. */
|
|
|
|
/* FIXME: MENU CMDLINEROW not supported. */
|
|
|
|
/* FIXME: MENU ENDROW not supported. */
|
|
|
|
/* FIXME: MENU PASSWORDROW not supported. */
|
|
|
|
/* FIXME: MENU TIMEOUTROW not supported. */
|
|
|
|
/* FIXME: MENU HELPMSGROW not supported. */
|
|
|
|
/* FIXME: MENU HELPMSGENDROW not supported. */
|
|
|
|
/* FIXME: MENU HIDDENROW not supported. */
|
|
|
|
/* FIXME: MENU HSHIFT not supported. */
|
|
|
|
/* FIXME: MENU VSHIFT not supported. */
|
|
|
|
{"timeout", NULL, cmd_timeout},
|
|
|
|
/* FIXME: TOTALTIMEOUT not supported. */
|
|
|
|
/* FIXME: ONTIMEOUT not supported. */
|
|
|
|
/* FIXME: ONERROR not supported. */
|
|
|
|
/* FIXME: SERIAL not supported. */
|
|
|
|
/* FIXME: CONSOLE not supported. */
|
|
|
|
/* FIXME: FONT not supported. */
|
|
|
|
/* FIXME: KBDMAP not supported. */
|
|
|
|
{"say", NULL, cmd_say},
|
|
|
|
/* FIXME: DISPLAY not supported. */
|
|
|
|
/* FIXME: F* not supported. */
|
|
|
|
|
|
|
|
/* Commands to control interface behaviour which aren't needed with GRUB.
|
|
|
|
If they are important in your environment please contact GRUB team.
|
|
|
|
*/
|
|
|
|
{"prompt", NULL, NULL},
|
|
|
|
{"nocomplete", NULL, NULL},
|
|
|
|
{"noescape", NULL, NULL},
|
|
|
|
{"implicit", NULL, NULL},
|
|
|
|
{"allowoptions", NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
helptext (const char *line, grub_file_t file, struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
char *help;
|
|
|
|
char *buf = NULL;
|
|
|
|
grub_size_t helplen, alloclen = 0;
|
|
|
|
|
|
|
|
help = grub_strdup (line);
|
2015-01-26 08:40:42 +00:00
|
|
|
if (!help)
|
|
|
|
return grub_errno;
|
2013-12-18 04:28:05 +00:00
|
|
|
helplen = grub_strlen (line);
|
|
|
|
while ((grub_free (buf), buf = grub_file_getline (file)))
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
grub_size_t needlen;
|
|
|
|
for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
|
|
|
|
if (grub_strncasecmp (ptr, "endtext", sizeof ("endtext") - 1) == 0)
|
|
|
|
{
|
|
|
|
ptr += sizeof ("endtext") - 1;
|
|
|
|
for (; *ptr && (grub_isspace (*ptr) || *ptr == '\n' || *ptr == '\r');
|
|
|
|
ptr++);
|
|
|
|
if (!*ptr)
|
|
|
|
{
|
|
|
|
menu->entries->help = help;
|
|
|
|
grub_free (buf);
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
needlen = helplen + 1 + grub_strlen (buf);
|
|
|
|
if (alloclen < needlen)
|
|
|
|
{
|
|
|
|
alloclen = 2 * needlen;
|
|
|
|
help = grub_realloc (help, alloclen);
|
|
|
|
if (!help)
|
|
|
|
{
|
|
|
|
grub_free (buf);
|
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
helplen += grub_stpcpy (help + helplen, buf) - (help + helplen);
|
|
|
|
}
|
|
|
|
|
|
|
|
grub_free (buf);
|
2015-01-26 08:41:24 +00:00
|
|
|
grub_free (help);
|
2013-12-18 04:28:05 +00:00
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
syslinux_parse_real (struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
grub_file_t file;
|
|
|
|
char *buf = NULL;
|
|
|
|
grub_err_t err = GRUB_ERR_NONE;
|
|
|
|
|
2013-11-20 01:28:29 +00:00
|
|
|
file = grub_file_open (menu->filename, GRUB_FILE_TYPE_CONFIG);
|
2013-12-18 04:28:05 +00:00
|
|
|
if (!file)
|
|
|
|
return grub_errno;
|
|
|
|
while ((grub_free (buf), buf = grub_file_getline (file)))
|
|
|
|
{
|
|
|
|
const char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
|
|
|
char *end;
|
|
|
|
unsigned i;
|
|
|
|
end = buf + grub_strlen (buf);
|
|
|
|
while (end > buf && (end[-1] == '\n' || end[-1] == '\r'))
|
|
|
|
end--;
|
|
|
|
*end = 0;
|
|
|
|
for (ptr1 = buf; *ptr1 && grub_isspace (*ptr1); ptr1++);
|
|
|
|
if (*ptr1 == '#' || *ptr1 == 0)
|
|
|
|
{
|
|
|
|
err = add_comment (menu, ptr1, 1);
|
|
|
|
if (err)
|
|
|
|
goto fail;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (ptr2 = ptr1; !grub_isspace (*ptr2) && *ptr2; ptr2++);
|
|
|
|
for (ptr3 = ptr2; grub_isspace (*ptr3) && *ptr3; ptr3++);
|
|
|
|
for (ptr4 = ptr3; !grub_isspace (*ptr4) && *ptr4; ptr4++);
|
|
|
|
for (ptr5 = ptr4; grub_isspace (*ptr5) && *ptr5; ptr5++);
|
2015-01-20 11:45:45 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++)
|
2013-12-18 04:28:05 +00:00
|
|
|
if (grub_strlen (commands[i].name1) == (grub_size_t) (ptr2 - ptr1)
|
|
|
|
&& grub_strncasecmp (commands[i].name1, ptr1, ptr2 - ptr1) == 0
|
|
|
|
&& (commands[i].name2 == NULL
|
|
|
|
|| (grub_strlen (commands[i].name2)
|
|
|
|
== (grub_size_t) (ptr4 - ptr3)
|
|
|
|
&& grub_strncasecmp (commands[i].name2, ptr3, ptr4 - ptr3)
|
|
|
|
== 0)))
|
|
|
|
break;
|
2015-01-20 11:45:45 +00:00
|
|
|
if (i == ARRAY_SIZE(commands))
|
2013-12-18 04:28:05 +00:00
|
|
|
{
|
|
|
|
if (sizeof ("text") - 1 == ptr2 - ptr1
|
|
|
|
&& grub_strncasecmp ("text", ptr1, ptr2 - ptr1) == 0
|
|
|
|
&& (sizeof ("help") - 1 == ptr4 - ptr3
|
|
|
|
&& grub_strncasecmp ("help", ptr3, ptr4 - ptr3) == 0))
|
|
|
|
{
|
|
|
|
if (helptext (ptr5, file, menu))
|
|
|
|
return 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_comment (menu, " # UNSUPPORTED command '", 0);
|
|
|
|
add_comment (menu, ptr1, 0);
|
|
|
|
add_comment (menu, "'", 1);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (commands[i].parse)
|
|
|
|
{
|
|
|
|
err = commands[i].parse (commands[i].name2
|
|
|
|
? ptr5 : ptr3, menu);
|
|
|
|
if (err)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fail:
|
|
|
|
grub_file_close (file);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
print_escaped (struct output_buffer *outbuf,
|
|
|
|
const char *from, const char *to)
|
|
|
|
{
|
|
|
|
const char *ptr;
|
|
|
|
grub_err_t err;
|
|
|
|
if (!to)
|
|
|
|
to = from + grub_strlen (from);
|
|
|
|
err = ensure_space (outbuf, (to - from) * 4 + 2);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
outbuf->buf[outbuf->ptr++] = '\'';
|
2015-06-19 14:35:17 +00:00
|
|
|
for (ptr = from; *ptr && ptr < to; ptr++)
|
2013-12-18 04:28:05 +00:00
|
|
|
{
|
|
|
|
if (*ptr == '\'')
|
|
|
|
{
|
|
|
|
outbuf->buf[outbuf->ptr++] = '\'';
|
|
|
|
outbuf->buf[outbuf->ptr++] = '\\';
|
|
|
|
outbuf->buf[outbuf->ptr++] = '\'';
|
|
|
|
outbuf->buf[outbuf->ptr++] = '\'';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
outbuf->buf[outbuf->ptr++] = *ptr;
|
|
|
|
}
|
|
|
|
outbuf->buf[outbuf->ptr++] = '\'';
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
print_file (struct output_buffer *outbuf,
|
|
|
|
struct syslinux_menu *menu, const char *from, const char *to)
|
|
|
|
{
|
|
|
|
grub_err_t err;
|
|
|
|
if (!to)
|
|
|
|
to = from + grub_strlen (from);
|
|
|
|
err = print_escaped (outbuf, from[0] == '/'
|
|
|
|
? menu->root_target_directory
|
|
|
|
: menu->current_target_directory, NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = print (outbuf, "/", 1);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
return print_escaped (outbuf, from, to);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
simplify_filename (char *str)
|
|
|
|
{
|
|
|
|
char *iptr, *optr = str;
|
|
|
|
for (iptr = str; *iptr; iptr++)
|
|
|
|
{
|
|
|
|
if (*iptr == '/' && optr != str && optr[-1] == '/')
|
|
|
|
continue;
|
|
|
|
if (iptr[0] == '/' && iptr[1] == '.' && iptr[2] == '/')
|
|
|
|
{
|
|
|
|
iptr += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iptr[0] == '/' && iptr[1] == '.' && iptr[2] == '.'
|
|
|
|
&& iptr[3] == '/')
|
|
|
|
{
|
|
|
|
iptr += 3;
|
|
|
|
while (optr >= str && *optr != '/')
|
|
|
|
optr--;
|
|
|
|
if (optr < str)
|
|
|
|
{
|
|
|
|
str[0] = '/';
|
|
|
|
optr = str;
|
|
|
|
}
|
|
|
|
optr++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*optr++ = *iptr;
|
|
|
|
}
|
|
|
|
*optr = '\0';
|
|
|
|
}
|
|
|
|
|
2015-03-27 14:15:13 +00:00
|
|
|
static grub_err_t
|
|
|
|
print_config (struct output_buffer *outbuf,
|
|
|
|
struct syslinux_menu *menu,
|
|
|
|
const char *filename, const char *basedir)
|
|
|
|
{
|
|
|
|
struct syslinux_menu *menuptr;
|
|
|
|
grub_err_t err = GRUB_ERR_NONE;
|
|
|
|
char *new_cwd = NULL;
|
|
|
|
char *new_target_cwd = NULL;
|
|
|
|
char *newname = NULL;
|
|
|
|
int depth = 0;
|
|
|
|
|
|
|
|
new_cwd = get_read_filename (menu, basedir);
|
|
|
|
if (!new_cwd)
|
|
|
|
{
|
|
|
|
err = grub_errno;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
new_target_cwd = get_target_filename (menu, basedir);
|
|
|
|
if (!new_target_cwd)
|
|
|
|
{
|
|
|
|
err = grub_errno;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
newname = get_read_filename (menu, filename);
|
|
|
|
if (!newname)
|
|
|
|
{
|
|
|
|
err = grub_errno;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
simplify_filename (newname);
|
|
|
|
|
|
|
|
print_string ("#");
|
|
|
|
print_file (outbuf, menu, filename, NULL);
|
|
|
|
print_string (" ");
|
2015-06-19 15:38:25 +00:00
|
|
|
err = print (outbuf, newname, grub_strlen (newname));
|
|
|
|
if (err)
|
|
|
|
return err;
|
2015-03-27 14:15:13 +00:00
|
|
|
print_string (":\n");
|
|
|
|
|
|
|
|
for (menuptr = menu; menuptr; menuptr = menuptr->parent, depth++)
|
|
|
|
if (grub_strcmp (menuptr->filename, newname) == 0
|
|
|
|
|| depth > 20)
|
|
|
|
break;
|
|
|
|
if (menuptr)
|
|
|
|
{
|
|
|
|
print_string (" syslinux_configfile -r ");
|
|
|
|
print_file (outbuf, menu, "/", NULL);
|
|
|
|
print_string (" -c ");
|
|
|
|
print_file (outbuf, menu, basedir, NULL);
|
|
|
|
print_string (" ");
|
|
|
|
print_file (outbuf, menu, filename, NULL);
|
|
|
|
print_string ("\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
err = config_file (outbuf, menu->root_read_directory,
|
|
|
|
menu->root_target_directory, new_cwd, new_target_cwd,
|
|
|
|
newname, menu, menu->flavour);
|
|
|
|
if (err == GRUB_ERR_FILE_NOT_FOUND
|
|
|
|
|| err == GRUB_ERR_BAD_FILENAME)
|
|
|
|
{
|
|
|
|
grub_errno = err = GRUB_ERR_NONE;
|
|
|
|
print_string ("# File ");
|
|
|
|
err = print (outbuf, newname, grub_strlen (newname));
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
print_string (" not found\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
grub_free (newname);
|
|
|
|
grub_free (new_cwd);
|
|
|
|
grub_free (new_target_cwd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2013-12-18 04:28:05 +00:00
|
|
|
static grub_err_t
|
|
|
|
write_entry (struct output_buffer *outbuf,
|
|
|
|
struct syslinux_menu *menu,
|
|
|
|
struct syslinux_menuentry *curentry)
|
|
|
|
{
|
|
|
|
grub_err_t err;
|
|
|
|
if (curentry->comments)
|
2015-01-26 08:42:04 +00:00
|
|
|
{
|
|
|
|
err = print (outbuf, curentry->comments,
|
|
|
|
grub_strlen (curentry->comments));
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2013-12-18 04:28:05 +00:00
|
|
|
{
|
|
|
|
struct syslinux_say *say;
|
|
|
|
for (say = curentry->say; say && say->next; say = say->next);
|
|
|
|
for (; say && say->prev; say = say->prev)
|
|
|
|
{
|
|
|
|
print_string ("echo ");
|
|
|
|
if (print_escaped (outbuf, say->msg, NULL)) return grub_errno;
|
|
|
|
print_string ("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: support help text. */
|
|
|
|
switch (curentry->entry_type)
|
|
|
|
{
|
|
|
|
case KERNEL_LINUX:
|
|
|
|
{
|
2015-06-19 15:38:25 +00:00
|
|
|
const char *ptr;
|
|
|
|
const char *initrd = NULL, *initrde= NULL;
|
2013-12-18 04:28:05 +00:00
|
|
|
for (ptr = curentry->append; ptr && *ptr; ptr++)
|
|
|
|
if ((ptr == curentry->append || grub_isspace (ptr[-1]))
|
|
|
|
&& grub_strncasecmp (ptr, "initrd=", sizeof ("initrd=") - 1)
|
|
|
|
== 0)
|
|
|
|
break;
|
|
|
|
if (ptr && *ptr)
|
|
|
|
{
|
2015-06-19 15:38:25 +00:00
|
|
|
initrd = ptr + sizeof ("initrd=") - 1;
|
|
|
|
for (initrde = initrd; *initrde && !grub_isspace (*initrde); initrde++);
|
2013-12-18 04:28:05 +00:00
|
|
|
}
|
|
|
|
print_string (" if test x$grub_platform = xpc; then "
|
|
|
|
"linux_suffix=16; else linux_suffix= ; fi\n");
|
|
|
|
print_string (" linux$linux_suffix ");
|
|
|
|
print_file (outbuf, menu, curentry->kernel_file, NULL);
|
|
|
|
print_string (" ");
|
2015-02-16 14:56:26 +00:00
|
|
|
if (curentry->append)
|
2015-06-19 15:38:25 +00:00
|
|
|
{
|
|
|
|
err = print (outbuf, curentry->append, grub_strlen (curentry->append));
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2013-12-18 04:28:05 +00:00
|
|
|
print_string ("\n");
|
|
|
|
if (initrd || curentry->initrds)
|
|
|
|
{
|
|
|
|
struct initrd_list *lst;
|
|
|
|
print_string (" initrd$linux_suffix ");
|
|
|
|
if (initrd)
|
|
|
|
{
|
2015-06-19 15:38:25 +00:00
|
|
|
print_file (outbuf, menu, initrd, initrde);
|
2013-12-18 04:28:05 +00:00
|
|
|
print_string (" ");
|
|
|
|
}
|
|
|
|
for (lst = curentry->initrds; lst; lst = lst->next)
|
|
|
|
{
|
|
|
|
print_file (outbuf, menu, lst->file, NULL);
|
|
|
|
print_string (" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
print_string ("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KERNEL_CHAINLOADER:
|
|
|
|
print_string (" chainloader ");
|
|
|
|
print_file (outbuf, menu, curentry->kernel_file, NULL);
|
|
|
|
print_string ("\n");
|
|
|
|
break;
|
|
|
|
case KERNEL_CHAINLOADER_BPB:
|
|
|
|
print_string (" chainloader --bpb ");
|
|
|
|
print_file (outbuf, menu, curentry->kernel_file, NULL);
|
|
|
|
print_string ("\n");
|
|
|
|
break;
|
|
|
|
case LOCALBOOT:
|
|
|
|
/* FIXME: support -1. */
|
|
|
|
/* FIXME: PXELINUX. */
|
|
|
|
{
|
|
|
|
int n = grub_strtol (curentry->kernel_file, NULL, 0);
|
|
|
|
if (n >= 0 && n <= 0x02)
|
|
|
|
{
|
|
|
|
print_string (" root=fd");
|
|
|
|
if (print_num (outbuf, n))
|
|
|
|
return grub_errno;
|
|
|
|
print_string (";\n chainloader +1;\n");
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (n >= 0x80 && n < 0x8a)
|
|
|
|
{
|
|
|
|
print_string (" root=hd");
|
|
|
|
if (print_num (outbuf, n - 0x80))
|
|
|
|
return grub_errno;
|
|
|
|
print_string (";\n chainloader +1;\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
print_string (" # UNSUPPORTED localboot type ");
|
2015-03-04 13:19:29 +00:00
|
|
|
print_string ("\ntrue;\n");
|
2013-12-18 04:28:05 +00:00
|
|
|
if (print_num (outbuf, n))
|
|
|
|
return grub_errno;
|
|
|
|
print_string ("\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case KERNEL_COM32:
|
|
|
|
case KERNEL_COM:
|
|
|
|
{
|
|
|
|
char *basename = NULL;
|
|
|
|
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
for (ptr = curentry->kernel_file; *ptr; ptr++)
|
|
|
|
if (*ptr == '/' || *ptr == '\\')
|
|
|
|
basename = ptr;
|
|
|
|
}
|
|
|
|
if (!basename)
|
|
|
|
basename = curentry->kernel_file;
|
|
|
|
else
|
|
|
|
basename++;
|
|
|
|
if (grub_strcasecmp (basename, "chain.c32") == 0)
|
|
|
|
{
|
|
|
|
char *file = NULL;
|
2013-12-18 05:19:16 +00:00
|
|
|
int is_fd = -1, devn = 0;
|
2013-12-18 04:28:05 +00:00
|
|
|
int part = -1;
|
|
|
|
int swap = 0;
|
|
|
|
char *ptr;
|
|
|
|
for (ptr = curentry->append; *ptr; )
|
|
|
|
{
|
|
|
|
while (grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
/* FIXME: support mbr: and boot. */
|
|
|
|
if (ptr[0] == 'h' && ptr[1] == 'd')
|
|
|
|
{
|
|
|
|
is_fd = 0;
|
|
|
|
devn = grub_strtoul (ptr + 2, &ptr, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (grub_strncasecmp (ptr, "file=", 5) == 0)
|
|
|
|
{
|
|
|
|
file = ptr + 5;
|
|
|
|
for (ptr = file; *ptr && !grub_isspace (*ptr); ptr++);
|
|
|
|
if (*ptr)
|
|
|
|
{
|
|
|
|
*ptr = 0;
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (grub_strncasecmp (ptr, "swap", sizeof ("swap") - 1) == 0)
|
|
|
|
{
|
|
|
|
swap = 1;
|
|
|
|
ptr += sizeof ("swap") - 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr[0] == 'f' && ptr[1] == 'd')
|
|
|
|
{
|
|
|
|
is_fd = 1;
|
|
|
|
devn = grub_strtoul (ptr + 2, &ptr, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (grub_isdigit (ptr[0]))
|
|
|
|
{
|
|
|
|
part = grub_strtoul (ptr, &ptr, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* FIXME: isolinux, ntldr, cmldr, *dos, seg, hide
|
|
|
|
FIXME: sethidden. */
|
|
|
|
print_string (" # UNSUPPORTED option ");
|
|
|
|
if (print (outbuf, ptr, grub_strlen (ptr)))
|
|
|
|
return 0;
|
|
|
|
print_string ("\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (is_fd == -1)
|
|
|
|
{
|
|
|
|
print_string (" # no drive specified\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!*ptr)
|
|
|
|
{
|
|
|
|
print_string (is_fd ? " root=fd": " root=hd");
|
|
|
|
if (print_num (outbuf, devn))
|
|
|
|
return grub_errno;
|
|
|
|
if (part != -1)
|
|
|
|
{
|
|
|
|
print_string (",");
|
|
|
|
if (print_num (outbuf, part + 1))
|
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
print_string (";\n");
|
|
|
|
if (file)
|
|
|
|
{
|
|
|
|
print_string (" chainloader ");
|
|
|
|
print_file (outbuf, menu, file, NULL);
|
|
|
|
print_string (";\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
print_string (" chainloader +1;\n");
|
|
|
|
if (swap)
|
|
|
|
print_string (" drivemap -s hd0 \"root\";\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grub_strcasecmp (basename, "mboot.c32") == 0)
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
int first = 1;
|
|
|
|
int is_kernel = 1;
|
|
|
|
for (ptr = curentry->append; *ptr; )
|
|
|
|
{
|
|
|
|
char *ptrr = ptr;
|
|
|
|
while (*ptr && !grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
if (ptrr + 2 == ptr && ptrr[0] == '-' && ptrr[1] == '-')
|
|
|
|
{
|
|
|
|
print_string ("\n");
|
|
|
|
first = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (first)
|
|
|
|
{
|
|
|
|
if (is_kernel)
|
|
|
|
print_string (" multiboot ");
|
|
|
|
else
|
|
|
|
print_string (" module ");
|
|
|
|
first = 0;
|
|
|
|
is_kernel = 0;
|
|
|
|
if (print_file (outbuf, menu, ptrr, ptr))
|
|
|
|
return grub_errno;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (print_escaped (outbuf, ptrr, ptr))
|
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grub_strcasecmp (basename, "ifcpu64.c32") == 0)
|
|
|
|
{
|
|
|
|
char *lm, *lme, *pae = 0, *paee = 0, *i386s = 0, *i386e = 0;
|
|
|
|
char *ptr;
|
|
|
|
ptr = curentry->append;
|
|
|
|
while (grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
lm = ptr;
|
|
|
|
while (*ptr && !grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
lme = ptr;
|
|
|
|
while (grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
if (ptr[0] == '-' && ptr[1] == '-')
|
|
|
|
{
|
|
|
|
ptr += 2;
|
|
|
|
while (grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
pae = ptr;
|
|
|
|
while (*ptr && !grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
paee = ptr;
|
|
|
|
}
|
|
|
|
while (grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
if (ptr[0] == '-' && ptr[1] == '-')
|
|
|
|
{
|
|
|
|
ptr += 2;
|
|
|
|
while (grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
i386s = ptr;
|
|
|
|
while (*ptr && !grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
i386e = ptr;
|
|
|
|
}
|
2015-06-19 15:38:25 +00:00
|
|
|
*lme = '\0';
|
2013-12-18 04:28:05 +00:00
|
|
|
if (paee)
|
|
|
|
*paee = '\0';
|
|
|
|
if (i386e)
|
|
|
|
*i386e = '\0';
|
|
|
|
if (!i386s)
|
|
|
|
{
|
|
|
|
i386s = pae;
|
|
|
|
pae = 0;
|
|
|
|
}
|
|
|
|
print_string ("if cpuid --long-mode; then true;\n");
|
|
|
|
if (print_entry (outbuf, menu, lm))
|
|
|
|
return grub_errno;
|
|
|
|
if (pae)
|
|
|
|
{
|
|
|
|
print_string ("elif cpuid --pae; then true;\n");
|
|
|
|
if (print_entry (outbuf, menu, pae))
|
|
|
|
return grub_errno;
|
|
|
|
}
|
|
|
|
print_string ("else\n");
|
|
|
|
if (print_entry (outbuf, menu, i386s))
|
|
|
|
return grub_errno;
|
|
|
|
print_string ("fi\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grub_strcasecmp (basename, "reboot.c32") == 0)
|
|
|
|
{
|
|
|
|
print_string (" reboot\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grub_strcasecmp (basename, "poweroff.com") == 0)
|
|
|
|
{
|
|
|
|
print_string (" halt\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grub_strcasecmp (basename, "whichsys.c32") == 0)
|
|
|
|
{
|
|
|
|
grub_syslinux_flavour_t flavour = GRUB_SYSLINUX_ISOLINUX;
|
|
|
|
const char *flav[] =
|
|
|
|
{
|
|
|
|
[GRUB_SYSLINUX_ISOLINUX] = "iso",
|
|
|
|
[GRUB_SYSLINUX_PXELINUX] = "pxe",
|
|
|
|
[GRUB_SYSLINUX_SYSLINUX] = "sys"
|
|
|
|
};
|
|
|
|
char *ptr;
|
|
|
|
for (ptr = curentry->append; *ptr; )
|
|
|
|
{
|
|
|
|
char *bptr, c;
|
|
|
|
while (grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
if (grub_strncasecmp (ptr, "-iso-", 5) == 0)
|
|
|
|
{
|
|
|
|
ptr += sizeof ("-iso-") - 1;
|
|
|
|
flavour = GRUB_SYSLINUX_ISOLINUX;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (grub_strncasecmp (ptr, "-pxe-", 5) == 0)
|
|
|
|
{
|
|
|
|
ptr += sizeof ("-pxe-") - 1;
|
|
|
|
flavour = GRUB_SYSLINUX_PXELINUX;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (grub_strncasecmp (ptr, "-sys-", 5) == 0)
|
|
|
|
{
|
|
|
|
ptr += sizeof ("-sys-") - 1;
|
|
|
|
flavour = GRUB_SYSLINUX_SYSLINUX;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bptr = ptr;
|
|
|
|
while (*ptr && !grub_isspace (*ptr))
|
|
|
|
ptr++;
|
|
|
|
c = *ptr;
|
|
|
|
*ptr = '\0';
|
|
|
|
if (menu->flavour == GRUB_SYSLINUX_UNKNOWN
|
|
|
|
&& flavour == GRUB_SYSLINUX_ISOLINUX)
|
|
|
|
{
|
|
|
|
print_string ("if [ x$syslinux_flavour = xiso -o x$syslinux_flavour = x ]; then true;\n");
|
|
|
|
menu->flavour = GRUB_SYSLINUX_ISOLINUX;
|
|
|
|
print_entry (outbuf, menu, bptr);
|
|
|
|
menu->flavour = GRUB_SYSLINUX_UNKNOWN;
|
|
|
|
print_string ("fi\n");
|
|
|
|
}
|
|
|
|
else if (menu->flavour == GRUB_SYSLINUX_UNKNOWN)
|
|
|
|
{
|
|
|
|
print_string ("if [ x$syslinux_flavour = x");
|
|
|
|
err = print (outbuf, flav[flavour], grub_strlen (flav[flavour]));
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
print_string (" ]; then true;\n");
|
|
|
|
menu->flavour = flavour;
|
|
|
|
print_entry (outbuf, menu, bptr);
|
|
|
|
menu->flavour = GRUB_SYSLINUX_UNKNOWN;
|
|
|
|
print_string ("fi\n");
|
|
|
|
}
|
|
|
|
if (menu->flavour != GRUB_SYSLINUX_UNKNOWN
|
|
|
|
&& menu->flavour == flavour)
|
|
|
|
print_entry (outbuf, menu, bptr);
|
|
|
|
*ptr = c;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-03-27 14:15:13 +00:00
|
|
|
if (grub_strcasecmp (basename, "menu.c32") == 0 ||
|
|
|
|
grub_strcasecmp (basename, "vesamenu.c32") == 0)
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
ptr = curentry->append;
|
|
|
|
if (!ptr)
|
|
|
|
return grub_errno;
|
|
|
|
|
|
|
|
while (*ptr)
|
|
|
|
{
|
|
|
|
end = ptr;
|
|
|
|
for (end = ptr; *end && !grub_isspace (*end); end++);
|
|
|
|
if (*end)
|
|
|
|
*end++ = '\0';
|
|
|
|
|
|
|
|
/* "~" is supposed to be current file, so let's skip it */
|
|
|
|
if (grub_strcmp (ptr, "~") != 0)
|
|
|
|
{
|
|
|
|
err = print_config (outbuf, menu, ptr, "");
|
|
|
|
if (err != GRUB_ERR_NONE)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (ptr = end; *ptr && grub_isspace (*ptr); ptr++);
|
|
|
|
}
|
|
|
|
err = GRUB_ERR_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-12-18 04:28:05 +00:00
|
|
|
/* FIXME: gdb, GFXBoot, Hdt, Ifcpu, Ifplop, Kbdmap,
|
|
|
|
FIXME: Linux, Lua, Meminfo, rosh, Sanbboot */
|
|
|
|
|
|
|
|
print_string (" # UNSUPPORTED com(32) ");
|
|
|
|
err = print (outbuf, basename, grub_strlen (basename));
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
print_string ("\ntrue;\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case KERNEL_CONFIG:
|
|
|
|
{
|
|
|
|
const char *ap;
|
|
|
|
ap = curentry->append;
|
|
|
|
if (!ap)
|
|
|
|
ap = curentry->argument;
|
|
|
|
if (!ap)
|
|
|
|
ap = "";
|
2015-03-27 14:15:13 +00:00
|
|
|
print_config (outbuf, menu, curentry->kernel_file, ap);
|
2013-12-18 04:28:05 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KERNEL_NO_KERNEL:
|
|
|
|
/* FIXME: support this. */
|
|
|
|
case KERNEL_BIN:
|
|
|
|
case KERNEL_PXE:
|
|
|
|
case KERNEL_IMG:
|
|
|
|
print_string (" # UNSUPPORTED entry type ");
|
|
|
|
if (print_num (outbuf, curentry->entry_type))
|
|
|
|
return grub_errno;
|
|
|
|
print_string ("\ntrue;\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
print_entry (struct output_buffer *outbuf,
|
|
|
|
struct syslinux_menu *menu,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
struct syslinux_menuentry *curentry;
|
|
|
|
for (curentry = menu->entries; curentry; curentry = curentry->next)
|
|
|
|
if (grub_strcasecmp (curentry->label, str) == 0)
|
|
|
|
{
|
|
|
|
grub_err_t err;
|
|
|
|
err = write_entry (outbuf, menu, curentry);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_menu (struct syslinux_menu *menu)
|
|
|
|
{
|
|
|
|
struct syslinux_say *say, *nsay;
|
|
|
|
struct syslinux_menuentry *entry, *nentry;
|
|
|
|
|
|
|
|
grub_free (menu->def);
|
|
|
|
grub_free (menu->comments);
|
|
|
|
grub_free (menu->background);
|
|
|
|
for (say = menu->say; say ; say = nsay)
|
|
|
|
{
|
|
|
|
nsay = say->next;
|
|
|
|
grub_free (say);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (entry = menu->entries; entry ; entry = nentry)
|
|
|
|
{
|
|
|
|
nentry = entry->next;
|
|
|
|
struct initrd_list *initrd, *ninitrd;
|
|
|
|
|
|
|
|
for (initrd = entry->initrds; initrd ; initrd = ninitrd)
|
|
|
|
{
|
|
|
|
ninitrd = initrd->next;
|
|
|
|
grub_free (initrd->file);
|
|
|
|
grub_free (initrd);
|
|
|
|
}
|
|
|
|
|
|
|
|
grub_free (entry->comments);
|
|
|
|
grub_free (entry->kernel_file);
|
|
|
|
grub_free (entry->label);
|
|
|
|
grub_free (entry->extlabel);
|
|
|
|
grub_free (entry->append);
|
|
|
|
grub_free (entry->help);
|
|
|
|
grub_free (entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static grub_err_t
|
|
|
|
config_file (struct output_buffer *outbuf,
|
|
|
|
const char *root, const char *target_root,
|
|
|
|
const char *cwd, const char *target_cwd,
|
|
|
|
const char *fname, struct syslinux_menu *parent,
|
|
|
|
grub_syslinux_flavour_t flav)
|
|
|
|
{
|
|
|
|
grub_err_t err;
|
|
|
|
struct syslinux_menu menu;
|
|
|
|
struct syslinux_menuentry *curentry, *lentry;
|
|
|
|
struct syslinux_say *say;
|
|
|
|
|
|
|
|
grub_memset (&menu, 0, sizeof (menu));
|
|
|
|
menu.flavour = flav;
|
|
|
|
menu.root_read_directory = root;
|
|
|
|
menu.root_target_directory = target_root;
|
|
|
|
menu.current_read_directory = cwd;
|
|
|
|
menu.current_target_directory = target_cwd;
|
|
|
|
|
|
|
|
menu.filename = fname;
|
|
|
|
menu.parent = parent;
|
|
|
|
err = syslinux_parse_real (&menu);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
for (say = menu.say; say && say->next; say = say->next);
|
|
|
|
for (; say && say->prev; say = say->prev)
|
|
|
|
{
|
|
|
|
print_string ("echo ");
|
|
|
|
err = print_escaped (outbuf, say->msg, NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
print_string ("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (menu.background)
|
|
|
|
{
|
|
|
|
print_string (" background_image ");
|
|
|
|
err = print_file (outbuf, &menu, menu.background, NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
print_string ("\n");
|
|
|
|
}
|
|
|
|
|
2015-02-16 09:54:20 +00:00
|
|
|
if (menu.comments)
|
|
|
|
{
|
|
|
|
err = print (outbuf, menu.comments, grub_strlen (menu.comments));
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2013-12-18 04:28:05 +00:00
|
|
|
if (menu.timeout == 0 && menu.entries && menu.def)
|
|
|
|
{
|
|
|
|
err = print_entry (outbuf, &menu, menu.def);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
else if (menu.entries)
|
|
|
|
{
|
|
|
|
for (curentry = menu.entries; curentry->next; curentry = curentry->next);
|
|
|
|
lentry = curentry;
|
|
|
|
|
2014-04-05 22:44:44 +00:00
|
|
|
print_string ("set timeout=");
|
2013-12-18 04:28:05 +00:00
|
|
|
err = print_num (outbuf, (menu.timeout + 9) / 10);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
print_string ("\n");
|
|
|
|
|
|
|
|
if (menu.def)
|
|
|
|
{
|
|
|
|
print_string (" default=");
|
|
|
|
err = print_escaped (outbuf, menu.def, NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
print_string ("\n");
|
|
|
|
}
|
|
|
|
for (curentry = lentry; curentry; curentry = curentry->prev)
|
|
|
|
{
|
|
|
|
print_string ("menuentry ");
|
|
|
|
err = print_escaped (outbuf,
|
|
|
|
curentry->extlabel ? : curentry->label, NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
if (curentry->hotkey)
|
|
|
|
{
|
|
|
|
char hk[] = { curentry->hotkey, '\0' };
|
|
|
|
print_string (" --hotkey '");
|
|
|
|
print_string (hk);
|
|
|
|
print_string ("'");
|
|
|
|
}
|
|
|
|
print_string (" --id ");
|
|
|
|
err = print_escaped (outbuf, curentry->label, NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
print_string (" {\n");
|
|
|
|
|
|
|
|
err = write_entry (outbuf, &menu, curentry);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
print_string ("}\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free_menu (&menu);
|
|
|
|
return GRUB_ERR_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
grub_syslinux_config_file (const char *base, const char *target_base,
|
|
|
|
const char *cwd, const char *target_cwd,
|
|
|
|
const char *fname, grub_syslinux_flavour_t flav)
|
|
|
|
{
|
|
|
|
struct output_buffer outbuf = { 0, 0, 0 };
|
|
|
|
grub_err_t err;
|
|
|
|
err = config_file (&outbuf, base, target_base, cwd, target_cwd,
|
|
|
|
fname, NULL, flav);
|
|
|
|
if (err)
|
|
|
|
return NULL;
|
|
|
|
err = print (&outbuf, "\0", 1);
|
|
|
|
if (err)
|
|
|
|
return NULL;
|
|
|
|
return outbuf.buf;
|
|
|
|
}
|