| /* |
| * Creation Date: <2003/12/03 22:10:45 samuel> |
| * Time-stamp: <2004/01/07 19:17:45 samuel> |
| * |
| * <disk-label.c> |
| * |
| * Partition support |
| * |
| * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) |
| * |
| * 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 "libopenbios/load.h" |
| #include "libc/diskio.h" |
| #include "libc/vsprintf.h" |
| #include "packages.h" |
| |
| //#define DEBUG_DISK_LABEL |
| |
| #ifdef DEBUG_DISK_LABEL |
| #define DPRINTF(fmt, args...) \ |
| do { printk("DISK-LABEL - %s: " fmt, __func__ , ##args); } while (0) |
| #else |
| #define DPRINTF(fmt, args...) do { } while (0) |
| #endif |
| |
| typedef struct { |
| xt_t parent_seek_xt; |
| xt_t parent_tell_xt; |
| xt_t parent_read_xt; |
| |
| ucell offs_hi, offs_lo; |
| ucell size_hi, size_lo; |
| int block_size; |
| int type; /* partition type or -1 */ |
| |
| ihandle_t part_ih; |
| phandle_t filesystem_ph; |
| } dlabel_info_t; |
| |
| DECLARE_NODE( dlabel, 0, sizeof(dlabel_info_t), "/packages/disk-label" ); |
| |
| |
| /* ( -- ) */ |
| static void |
| dlabel_close( __attribute__((unused))dlabel_info_t *di ) |
| { |
| } |
| |
| /* ( -- success? ) */ |
| static void |
| dlabel_open( dlabel_info_t *di ) |
| { |
| char *path; |
| char block0[512]; |
| phandle_t ph; |
| int success=0; |
| cell status; |
| |
| path = my_args_copy(); |
| |
| DPRINTF("dlabel-open '%s'\n", path ); |
| |
| di->part_ih = 0; |
| |
| /* Find parent methods */ |
| di->filesystem_ph = 0; |
| di->parent_seek_xt = find_parent_method("seek"); |
| di->parent_tell_xt = find_parent_method("tell"); |
| di->parent_read_xt = find_parent_method("read"); |
| |
| /* If arguments have been passed, determine the partition/filesystem type */ |
| if (path && strlen(path)) { |
| |
| /* Read first block from parent device */ |
| DPUSH(0); |
| call_package(di->parent_seek_xt, my_parent()); |
| POP(); |
| |
| PUSH(pointer2cell(block0)); |
| PUSH(sizeof(block0)); |
| call_package(di->parent_read_xt, my_parent()); |
| status = POP(); |
| if (status != sizeof(block0)) |
| goto out; |
| |
| /* Find partition handler */ |
| PUSH( pointer2cell(block0) ); |
| selfword("find-part-handler"); |
| ph = POP_ph(); |
| if( ph ) { |
| /* We found a suitable partition handler, so interpose it */ |
| DPRINTF("Partition found on disk - scheduling interpose with ph " FMT_ucellx "\n", ph); |
| |
| push_str(path); |
| PUSH_ph(ph); |
| fword("interpose"); |
| |
| success = 1; |
| } else { |
| /* unknown (or missing) partition map, |
| * try the whole disk |
| */ |
| |
| DPRINTF("Unknown or missing partition map; trying whole disk\n"); |
| |
| /* Probe for filesystem from start of device */ |
| DPUSH ( 0 ); |
| PUSH_ih( my_self() ); |
| selfword("find-filesystem"); |
| ph = POP_ph(); |
| if( ph ) { |
| /* If we have been asked to open a particular file, interpose the filesystem package with the passed filename as an argument */ |
| di->filesystem_ph = ph; |
| |
| DPRINTF("Located filesystem with ph " FMT_ucellx "\n", ph); |
| DPRINTF("path: %s length: %d\n", path, strlen(path)); |
| |
| if (path && strlen(path)) { |
| DPRINTF("INTERPOSE!\n"); |
| |
| push_str( path ); |
| PUSH_ph( ph ); |
| fword("interpose"); |
| } |
| } else if (path && strcmp(path, "%BOOT") != 0) { |
| goto out; |
| } |
| |
| success = 1; |
| } |
| } else { |
| /* No arguments were passed, so we just use the parent raw device directly */ |
| success = 1; |
| } |
| |
| out: |
| if( path ) |
| free( path ); |
| if( !success ) { |
| dlabel_close( di ); |
| RET(0); |
| } |
| PUSH(-1); |
| } |
| |
| /* ( addr len -- actual ) */ |
| static void |
| dlabel_read( dlabel_info_t *di ) |
| { |
| /* Call back up to parent */ |
| call_package(di->parent_read_xt, my_parent()); |
| } |
| |
| /* ( pos.d -- status ) */ |
| static void |
| dlabel_seek( dlabel_info_t *di ) |
| { |
| /* Call back up to parent */ |
| call_package(di->parent_seek_xt, my_parent()); |
| } |
| |
| /* ( -- filepos.d ) */ |
| static void |
| dlabel_tell( dlabel_info_t *di ) |
| { |
| /* Call back up to parent */ |
| call_package(di->parent_tell_xt, my_parent()); |
| } |
| |
| /* ( addr len -- actual ) */ |
| static void |
| dlabel_write( __attribute__((unused)) dlabel_info_t *di ) |
| { |
| DDROP(); |
| PUSH( -1 ); |
| } |
| |
| /* ( addr -- size ) */ |
| static void |
| dlabel_load( __attribute__((unused)) dlabel_info_t *di ) |
| { |
| /* Try the load method of the part package */ |
| xt_t xt; |
| |
| /* If we have a partition handle, invoke the load word on it */ |
| if (di->part_ih) { |
| xt = find_ih_method("load", di->part_ih); |
| if (!xt) { |
| forth_printf("load currently not implemented for ihandle " FMT_ucellx "\n", di->part_ih); |
| PUSH(0); |
| return; |
| } |
| |
| DPRINTF("calling load on ihandle " FMT_ucellx "\n", di->part_ih); |
| |
| call_package(xt, di->part_ih); |
| } else { |
| /* Otherwise attempt load directly on the raw disk */ |
| DPRINTF("calling load on raw disk ihandle " FMT_ucellx "\n", my_self()); |
| |
| load(my_self()); |
| } |
| } |
| |
| /* ( pathstr len -- ) */ |
| static void |
| dlabel_dir( dlabel_info_t *di ) |
| { |
| if ( di->filesystem_ph ) { |
| PUSH( my_self() ); |
| push_str("dir"); |
| PUSH( di->filesystem_ph ); |
| fword("find-method"); |
| POP(); |
| fword("execute"); |
| } else { |
| forth_printf("disk-label: Unable to determine filesystem\n"); |
| POP(); |
| POP(); |
| } |
| } |
| |
| NODE_METHODS( dlabel ) = { |
| { "open", dlabel_open }, |
| { "close", dlabel_close }, |
| { "load", dlabel_load }, |
| { "read", dlabel_read }, |
| { "write", dlabel_write }, |
| { "seek", dlabel_seek }, |
| { "tell", dlabel_tell }, |
| { "dir", dlabel_dir }, |
| }; |
| |
| void |
| disklabel_init( void ) |
| { |
| REGISTER_NODE( dlabel ); |
| } |