blob: 09993f8ac40182a064ed622f8a28e6e4b7983e49 [file] [log] [blame]
/*
*
* <bootinfo-loader.c>
*
* bootinfo file loader
*
* Copyright (C) 2009 Laurent Vivier (Laurent@vivier.eu)
*
* Original XML parser by Blue Swirl <blauwirbel@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2
*
*/
#include "config.h"
#include "libopenbios/bindings.h"
#include "packages.h"
#include "libopenbios/ofmem.h"
#include "libc/vsprintf.h"
//#define DEBUG_BOOTINFO
#ifdef DEBUG_BOOTINFO
#define DPRINTF(fmt, args...) \
do { printk("%s: " fmt, __func__ , ##args); } while (0)
#else
#define DPRINTF(fmt, args...) \
do { } while (0)
#endif
DECLARE_NODE(bootinfo_loader, INSTALL_OPEN, 0, "+/packages/bootinfo-loader" );
static char *
get_device( const char *path )
{
int i;
static char buf[1024];
for (i = 0; i < sizeof(buf) && path[i] && path[i] != ':'; i++)
buf[i] = path[i];
buf[i] = 0;
return buf;
}
static int
get_partition( const char *path )
{
while ( *path && *path != ':' )
path++;
if (!*path)
return -1;
path++;
if (!strchr(path, ',')) /* check if there is a ',' */
return -1;
return atol(path);
}
static char *
get_filename( const char * path , char **dirname)
{
static char buf[1024];
char *filename;
while ( *path && *path != ':' )
path++;
if (!*path) {
*dirname = NULL;
return NULL;
}
path++;
while ( *path && isdigit(*path) )
path++;
if (*path == ',')
path++;
strncpy(buf, path, sizeof(buf));
buf[sizeof(buf) - 1] = 0;
filename = strrchr(buf, '\\');
if (filename) {
*dirname = buf;
(*filename++) = 0;
} else {
*dirname = NULL;
filename = buf;
}
return filename;
}
/*
Parse SGML structure like:
<chrp-boot>
<description>Debian/GNU Linux Installation on IBM CHRP hardware</description>
<os-name>Debian/GNU Linux for PowerPC</os-name>
<boot-script>boot &device;:\install\yaboot</boot-script>
<icon size=64,64 color-space=3,3,2>
CHRP system bindings are described at:
http://playground.sun.com/1275/bindings/chrp/chrp1_7a.ps
*/
static void
bootinfo_loader_init_program( void *dummy )
{
char *base;
int proplen;
phandle_t chosen;
int tag, taglen, script, scriptlen, entity, chrp;
char tagbuf[128], c;
char *device, *filename, *directory;
int partition;
int current, size;
char *bootscript;
char *tmp;
char bootpath[1024];
feval("0 state-valid !");
chosen = find_dev("/chosen");
tmp = get_property(chosen, "bootpath", &proplen);
memcpy(bootpath, tmp, proplen);
bootpath[proplen] = 0;
DPRINTF("bootpath %s\n", bootpath);
device = get_device(bootpath);
partition = get_partition(bootpath);
filename = get_filename(bootpath, &directory);
feval("load-base");
base = (char*)POP();
feval("load-size");
size = POP();
bootscript = malloc(size);
if (bootscript == NULL) {
DPRINTF("Can't malloc %d bytes\n", size);
return;
}
chrp = 0;
tag = 0;
taglen = 0;
script = 0;
scriptlen = 0;
entity = 0;
current = 0;
while (current < size) {
c = base[current++];
if (c == '<') {
script = 0;
tag = 1;
taglen = 0;
} else if (c == '>') {
tag = 0;
tagbuf[taglen] = '\0';
if (strcasecmp(tagbuf, "chrp-boot") == 0) {
chrp = 1;
} else if (chrp == 1) {
if (strcasecmp(tagbuf, "boot-script") == 0) {
script = 1;
scriptlen = 0;
} else if (strcasecmp(tagbuf, "/boot-script") == 0) {
script = 0;
bootscript[scriptlen] = '\0';
DPRINTF("got bootscript %s\n",
bootscript);
feval("-1 state-valid !");
break;
} else if (strcasecmp(tagbuf, "/chrp-boot") == 0)
break;
}
} else if (tag && taglen < sizeof(tagbuf)) {
tagbuf[taglen++] = c;
} else if (script && c == '&') {
entity = 1;
taglen = 0;
} else if (entity && c ==';') {
entity = 0;
tagbuf[taglen] = '\0';
if (strcasecmp(tagbuf, "lt") == 0) {
bootscript[scriptlen++] = '<';
} else if (strcasecmp(tagbuf, "gt") == 0) {
bootscript[scriptlen++] = '>';
} else if (strcasecmp(tagbuf, "device") == 0) {
strcpy(bootscript + scriptlen, device);
scriptlen += strlen(device);
} else if (strcasecmp(tagbuf, "partition") == 0) {
if (partition != -1)
sprintf(bootscript + scriptlen, "%d", partition);
else
*(bootscript + scriptlen) = 0;
scriptlen = strlen(bootscript);
} else if (strcasecmp(tagbuf, "directory") == 0) {
strcpy(bootscript + scriptlen, directory);
scriptlen += strlen(directory);
} else if (strcasecmp(tagbuf, "filename") == 0) {
strcpy(bootscript + scriptlen, filename);
scriptlen += strlen(filename);
} else if (strcasecmp(tagbuf, "full-path") == 0) {
strcpy(bootscript + scriptlen, bootpath);
scriptlen += strlen(bootpath);
} else { /* unknown, keep it */
bootscript[scriptlen] = '&';
strcpy(bootscript + scriptlen + 1, tagbuf);
scriptlen += taglen + 1;
bootscript[scriptlen] = ';';
scriptlen++;
}
} else if (entity && taglen < sizeof(tagbuf)) {
tagbuf[taglen++] = c;
} else if (script && scriptlen < size) {
bootscript[scriptlen++] = c;
}
}
/* FIXME: should initialize saved-program-state. */
push_str(bootscript);
feval("bootinfo-size ! bootinfo-entry !");
}
NODE_METHODS( bootinfo_loader ) = {
{ "init-program", bootinfo_loader_init_program },
};
void bootinfo_loader_init( void )
{
REGISTER_NODE( bootinfo_loader );
}