-/* File related stuff
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/*
+ * 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"
extern char bootdevice[1024];
+static char *netdev_path_to_filename(const char *path)
+{
+ char *tmp, *args, *filename;
+ size_t len;
+
+ DEBUG_F("path = %s\n", path);
+
+ if (!path)
+ return NULL;
+
+ args = strrchr(path, ':');
+ if (!args)
+ return NULL;
+
+ /* The obp-tftp device arguments should be at the end of
+ * the argument list. Skip over any extra arguments (promiscuous,
+ * speed, duplex, bootp, rarp).
+ */
+
+ tmp = strstr(args, "promiscuous");
+ if (tmp && tmp > args)
+ args = tmp + strlen("promiscuous");
+
+ tmp = strstr(args, "speed=");
+ if (tmp && tmp > args)
+ args = tmp + strlen("speed=");
+
+ tmp = strstr(args, "duplex=");
+ if (tmp && tmp > args)
+ args = tmp + strlen("duplex=");
+
+ tmp = strstr(args, "bootp");
+ if (tmp && tmp > args)
+ args = tmp + strlen("bootp");
+
+ tmp = strstr(args, "rarp");
+ if (tmp && tmp > args)
+ args = tmp + strlen("rarp");
+
+ args = strchr(args, ',');
+ if (!args)
+ return NULL;
+
+ tmp = args;
+ tmp--;
+ /* If the preceding character is ':' then there were no
+ * non-obp-tftp arguments and we know we're right up to the
+ * filename. Otherwise, we must advance args once more.
+ */
+ args++;
+ if (*tmp != ':') {
+ args = strchr(args, ',');
+ if (!args)
+ return NULL;
+ args++;
+ }
+
+ /* filename may be empty; e.g. enet:192.168.1.1,,192.168.1.2 */
+ if (*args == ',') {
+ DEBUG_F("null filename\n");
+ return NULL;
+ }
+
+ /* Now see whether there are more args following the filename. */
+ tmp = strchr(args, ',');
+ if (!tmp)
+ len = strlen(args) + 1;
+ else
+ len = tmp - args + 1;
+
+ filename = malloc(len);
+ if (!filename)
+ return NULL;
+
+ strncpy(filename, args, len);
+ filename[len - 1] = '\0';
+
+ DEBUG_F("filename = %s\n", filename);
+ return filename;
+}
+
+static char *netdev_path_to_dev(const char *path)
+{
+ char *dev, *tmp;
+ size_t len;
+
+ DEBUG_F("path = %s\n", path);
+
+ if (!path)
+ return NULL;
+
+ tmp = strchr(path, ':');
+ if (!tmp)
+ return strdup(path);
+ tmp++;
+
+ len = tmp - path + 1;
+
+ dev = malloc(len);
+ if (dev) {
+ strncpy(dev, path, len);
+ dev[len - 1] = '\0';
+ }
+ return dev;
+}
+
/* 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
- */
+ 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 = strdup(imagepath);
- char *defdev = strdup(defdevice);
+ char *ipath = NULL;
+ char *defdev = NULL;
+ int device_kind;
result->dev = NULL;
result->part = -1;
result->file = NULL;
- if (!strstr(defdev, "ethernet") && !strstr(defdev, "enet")) {
- if ((ptr = strrchr(defdev, ':')) != NULL)
- *ptr = 0; /* remove trailing : from defdevice if necessary */
- }
-
if (!imagepath)
- goto punt;
+ return 0;
+ else if (!(ipath = strdup(imagepath)))
+ return 0;
- if ((ptr = strrchr(ipath, ',')) != NULL) {
- result->file = strdup(ptr+1);
- /* Trim the filename off */
- *ptr = 0;
+ if (defdevice) {
+ defdev = strdup(defdevice);
+ device_kind = prom_get_devtype(defdev);
+ } else
+ device_kind = prom_get_devtype(ipath);
+
+ if (device_kind != FILE_DEVICE_NET && strchr(defdev, ':') != NULL) {
+ if ((ptr = strrchr(defdev, ':')) != NULL)
+ *ptr = 0; /* remove trailing : from defdevice if necessary */
}
- 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) {
+ /* This will not properly handle an obp-tftp argument list
+ * with elements after the filename; that is handled below.
+ */
+ if (device_kind != FILE_DEVICE_NET && 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 (device_kind == FILE_DEVICE_NET) {
+ if (strchr(ipath, ':'))
+ result->file = netdev_path_to_filename(ipath);
+ else
+ result->file = strdup(ipath);
+
+ if (!defdev)
+ result->dev = netdev_path_to_dev(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 {
+ free(defdev);
return 0;
}
-
-punt:
- if (!result->dev)
+
+ 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;
}
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");
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)
- goto bail;
+ 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
+#endif
}
/* Note: we don't skip when found is NULL since we can, in some
DEBUG_F( "Using OF defaults.. (found = %p)\n", found );
file->fs = fs_open( file, dev_name, found, file_name );
-bail:
+done:
if (parts)
partitions_free(parts);
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;
file->device_kind = result;
else
return result;
-
+
switch(file->device_kind) {
case FILE_DEVICE_BLOCK:
DEBUG_F("device is a block device\n");
return 0;
}
-/*
+/*
* Local variables:
* c-file-style: "k&r"
* c-basic-offset: 5