blob: b5763a235f6d5db62ad5fb1b4c92254b89775270 [file] [log] [blame] [raw]
/*
* file.c - Filesystem related interfaces
*
* Copyright (C) 2001, 2002 Ethan Benson
*
* parse_device_path()
*
* Copyright (C) 2001 Colin Walters
*
* Copyright (C) 1999 Benjamin Herrenschmidt
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ctype.h"
#include "types.h"
#include "stddef.h"
#include "stdlib.h"
#include "file.h"
#include "prom.h"
#include "string.h"
#include "partition.h"
#include "fs.h"
#include "errors.h"
#include "debug.h"
extern char bootdevice[1024];
/* This function follows the device path in the devtree and separates
the device name, partition number, and other datas (mostly file name)
the string passed in parameters is changed since 0 are put in place
of some separators to terminate the various strings.
when a default device is supplied imagepath will be assumed to be a
plain filename unless it contains a : otherwise if defaultdev is
NULL imagepath will be assumed to be a device path.
returns 1 on success 0 on failure.
Supported examples:
- /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4
- /pci@80000000/pci-bridge@d/ADPT,2930CU@2/@1:4,/boot/vmlinux
- hd:3,/boot/vmlinux
- enet:10.0.0.1,/tftpboot/vmlinux
- enet:,/tftpboot/vmlinux
- enet:bootp
- enet:0
Supported only if defdevice == NULL
- disc
- any other device path lacking a :
Unsupported examples:
- hd:2,\\:tbxi <- no filename will be detected due to the extra :
- enet:192.168.2.1,bootme,c-iaddr,g-iaddr,subnet-mask,bootp-retries,tftp-retries */
int
parse_device_path(char *imagepath, char *defdevice, int defpart,
char *deffile, struct boot_fspec_t *result)
{
char *ptr;
char *ipath = NULL;
char *defdev = NULL;
result->dev = NULL;
result->part = -1;
result->file = NULL;
if (!imagepath)
return 0;
else
ipath = strdup(imagepath);
if (defdevice)
defdev = strdup(defdevice);
if (defdev) {
if (!strstr(defdev, "ethernet") && !strstr(defdev, "enet")) {
if ((ptr = strrchr(defdev, ':')) != NULL)
*ptr = 0; /* remove trailing : from defdevice if necessary */
}
}
/* if there is no : then there is no filename or partition. must
use strrchr() since enet:,10.0.0.1,file is legal */
if (strchr(ipath, ':') != NULL) {
if ((ptr = strrchr(ipath, ',')) != NULL) {
char *colon = strrchr(ipath, ':');
/* If a ':' occurs *after* a ',', then we assume that there is
no filename */
if (!colon || colon < ptr) {
result->file = strdup(ptr+1);
/* Trim the filename off */
*ptr = 0;
}
}
}
if (strstr(ipath, "ethernet") || strstr(ipath, "enet"))
if ((ptr = strstr(ipath, "bootp")) != NULL) { /* `n' key booting boots enet:bootp */
*ptr = 0;
result->dev = strdup(ipath);
} else
result->dev = strdup(ipath);
else if ((ptr = strchr(ipath, ':')) != NULL) {
*ptr = 0;
result->dev = strdup(ipath);
if (*(ptr+1))
result->part = simple_strtol(ptr+1, NULL, 10);
} else if (!defdev) {
result->dev = strdup(ipath);
} else if (strlen(ipath)) {
result->file = strdup(ipath);
} else {
return 0;
}
if (!result->dev && defdev)
result->dev = strdup(defdev);
if (result->part < 0)
result->part = defpart;
if (!result->file)
result->file = strdup(deffile);
free(ipath);
if (defdev)
free(defdev);
return 1;
}
static int
file_block_open( struct boot_file_t* file,
const char* dev_name,
const char* file_name,
int partition)
{
struct partition_t* parts;
struct partition_t* p;
struct partition_t* found;
parts = partitions_lookup(dev_name);
found = NULL;
#if DEBUG
if (parts)
prom_printf("partitions:\n");
else
prom_printf("no partitions found.\n");
#endif
for (p = parts; p && !found; p=p->next) {
DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
p->part_number, p->part_start, p->part_size );
if (partition == -1) {
file->fs = fs_open( file, dev_name, p, file_name );
if (file->fs == NULL || fserrorno != FILE_ERR_OK)
continue;
else {
partition = p->part_number;
goto done;
}
}
if ((partition >= 0) && (partition == p->part_number))
found = p;
#if DEBUG
if (found)
prom_printf(" (match)\n");
#endif
}
/* Note: we don't skip when found is NULL since we can, in some
* cases, let OF figure out a default partition.
*/
DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
file->fs = fs_open( file, dev_name, found, file_name );
done:
if (parts)
partitions_free(parts);
return fserrorno;
}
static int
file_net_open( struct boot_file_t* file,
const char* dev_name,
const char* file_name)
{
file->fs = fs_of_netboot;
return fs_of_netboot->open(file, dev_name, NULL, file_name);
}
static int
default_read( struct boot_file_t* file,
unsigned int size,
void* buffer)
{
prom_printf("WARNING ! default_read called !\n");
return FILE_ERR_EOF;
}
static int
default_seek( struct boot_file_t* file,
unsigned int newpos)
{
prom_printf("WARNING ! default_seek called !\n");
return FILE_ERR_EOF;
}
static int
default_close( struct boot_file_t* file)
{
prom_printf("WARNING ! default_close called !\n");
return FILE_ERR_OK;
}
static struct fs_t fs_default =
{
"defaults",
NULL,
default_read,
default_seek,
default_close
};
int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file)
{
int result;
memset(file, 0, sizeof(struct boot_file_t*));
file->fs = &fs_default;
DEBUG_F("dev_path = %s\nfile_name = %s\npartition = %d\n",
spec->dev, spec->file, spec->part);
result = prom_get_devtype(spec->dev);
if (result > 0)
file->device_kind = result;
else
return result;
switch(file->device_kind) {
case FILE_DEVICE_BLOCK:
DEBUG_F("device is a block device\n");
return file_block_open(file, spec->dev, spec->file, spec->part);
case FILE_DEVICE_NET:
DEBUG_F("device is a network device\n");
return file_net_open(file, spec->dev, spec->file);
}
return 0;
}
/*
* Local variables:
* c-file-style: "k&r"
* c-basic-offset: 5
* End:
*/