/* * * * * bootinfo file loader * * Copyright (C) 2009 Laurent Vivier (Laurent@vivier.eu) * * Original XML parser by Blue Swirl * * 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: Debian/GNU Linux Installation on IBM CHRP hardware Debian/GNU Linux for PowerPC boot &device;:\install\yaboot 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 ); }