]> git.ozlabs.org Git - yaboot.git/blobdiff - second/file.c
print available ranges under control of linux, yaboot-debug property
[yaboot.git] / second / file.c
index 726f313b1de2672e66f3ecbad69fcfc4a7d844f9..debf7f42b87e8d87244c5623fd736038be24f2bf 100644 (file)
@@ -1,20 +1,28 @@
-/* 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"
 #include "string.h"
 #include "partition.h"
 #include "fs.h"
+#include "errors.h"
+#include "debug.h"
 
-extern char bootdevice[1024];
+extern char bootdevice[];
 
-/* 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
+/* Convert __u32 into std, dotted quad string, leaks like a sive :( */
+static char *
+ipv4_to_str(__u32 ip)
+{
+     char *buf = malloc(sizeof("000.000.000.000"));
+
+     sprintf(buf,"%u.%u.%u.%u",
+             (ip & 0xff000000) >> 24, (ip & 0x00ff0000) >> 16,
+             (ip & 0x0000ff00) >>  8, (ip & 0x000000ff));
+
+     return buf;
+}
+
+/* Ensure the string arg is a plausible IPv4 address */
+static char * is_valid_ipv4_str(char *str)
+{
+     int i;
+     long tmp;
+     __u32 ip = 0;
+     char *ptr=str, *endptr;
+
+     if (str == NULL)
+          return NULL;
+
+     for (i=0; i<4; i++, ptr = ++endptr) {
+          tmp = strtol(ptr, &endptr, 10);
+          if ((tmp & 0xff) != tmp)
+               return NULL;
+
+          /* If we reach the end of the string but we're not in the 4th octet
+           * we have an invalid IP */
+          if (*endptr == '\x0' && i!=3)
+               return NULL;
+
+          /* If we have anything other than a NULL or '.' we have an invlaid
+           * IP */
+          if (*endptr != '\x0' && *endptr != '.')
+               return NULL;
+
+          ip += (tmp << (24-(i*8)));
+     }
+
+     if (ip == 0 || ip == ~0u)
+          return NULL;
+
+     return str;
+}
+
+
+/*
+ * Copy the string from source to dest till newline or comma(,) is seen
+ * in the source.
+ * Move source and dest pointers respectively.
+ * Returns pointer to the start of the string that has just been copied.
+ */
+static char *
+scopy(char **dest, char **source)
+{
+     char *ret = *dest;
+
+     if (!**source)
+         return NULL;
+
+     while (**source != ',' && **source != '\0')
+         *(*dest)++ = *(*source)++;
+     if (**source != '\0')
+         *(*source)++;
+     **dest = '\0';
+     *(*dest)++;
+     return ret;
+}
+
+/*
+ * Extract all the ipv4 arguments from the bootpath provided and fill result
+ * Returns 1 on success, 0 on failure.
+ */
+static int
+extract_ipv4_args(char *imagepath, struct boot_fspec_t *result)
+{
+     char *tmp, *args, *str, *start;
+
+     args = strrchr(imagepath, ':');
+     if (!args)
+         return 1;
+
+     start = args; /* used to see if we read any optional parameters */
+
+     /* 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");
+
+     if (args != start) /* we read some parameters, so go past the next comma(,) */
+         args = strchr(args, ',');
+     if (!args)
+         return 1;
+
+     str = malloc(strlen(args) + 1); /*long enough to hold all strings */
+     if (!str)
+         return 0;
+
+     if (args[-1] != ':')
+         args++; /* If comma(,) is not immediately followed by ':' then go past the , */
+
+     /*
+      * read the arguments in order: siaddr,filename,ciaddr,giaddr,
+      * bootp-retries,tftp-retries,addl_prameters
+      */
+     result->siaddr = is_valid_ipv4_str(scopy(&str, &args));
+     result->file = scopy(&str, &args);
+     result->ciaddr = is_valid_ipv4_str(scopy(&str, &args));
+     result->giaddr = is_valid_ipv4_str(scopy(&str, &args));
+     result->bootp_retries = scopy(&str, &args);
+     result->tftp_retries = scopy(&str, &args);
+     result->subnetmask = is_valid_ipv4_str(scopy(&str, &args));
+     if (*args) {
+         result->addl_params = strdup(args);
+         if (!result->addl_params)
+               return 0;
+     }
+     return 1;
+}
+
+/* DHCP options */
+enum dhcp_options {
+     DHCP_PAD = 0,
+     DHCP_NETMASK = 1,
+     DHCP_ROUTERS = 3,
+     DHCP_DNS = 6,
+     DHCP_END = 255,
+};
+
+#define DHCP_COOKIE        0x63825363
+#define DHCP_COOKIE_SIZE   4
+
+/*
+ * Process the bootp reply packet's vendor extensions.
+ * Vendor extensions are detailed in: http://www.faqs.org/rfcs/rfc1084.html
+ */
+static void
+extract_vendor_options(struct bootp_packet *packet, struct boot_fspec_t *result)
+{
+     int i = 0;
+     __u32 cookie;
+     __u8 *options = &packet->options[0];
+
+     memcpy(&cookie, &options[i], DHCP_COOKIE_SIZE);
+
+     if (cookie != DHCP_COOKIE) {
+          prom_printf("EEEK! cookie is fubar got %08x expected %08x\n",
+                      cookie, DHCP_COOKIE);
+          return;
+     }
+
+     i += DHCP_COOKIE_SIZE;
+
+     /* FIXME: It may be possible to run off the end of a packet here /if/
+      *         it's malformed. :( */
+     while (options[i] != DHCP_END) {
+          __u8 tag = options[i++], len;
+          __u32 value;
+
+          if (tag == DHCP_PAD)
+               continue;
+
+          len = options[i++];
+          memcpy(&value, &options[i], len);
+
+#if DEBUG
+{
+     DEBUG_F("tag=%2d, len=%2d, data=", tag, len);
+     int j;
+     for (j=0; j<len; j++)
+          prom_printf("%02x", options[i+j]);
+     prom_printf("\n");
+}
+#endif
+
+          switch (tag) {
+               case DHCP_NETMASK:
+                    if ((result->subnetmask == NULL ||
+                         *(result->subnetmask) == '\x0') && value != 0) {
+                         result->subnetmask = ipv4_to_str(value);
+                         DEBUG_F("Storing %s as subnetmask from options\n",
+                                 result->subnetmask);
+                    }
+                    break;
+               case DHCP_ROUTERS:
+                    if ((result->giaddr == NULL || *(result->giaddr) == '\x0')
+                        && value != 0) {
+                         result->giaddr = ipv4_to_str(value);
+                         DEBUG_F("Storing %s as gateway from options\n",
+                                 result->giaddr);
+                    }
+                    break;
+               }
+          i += len;
+     }
+}
+
+/*
+ * Check netinfo for ipv4 parameters and add them to the fspec iff the
+ * fspec has no existing value.
+ */
+static void
+extract_netinfo_args(struct boot_fspec_t *result)
+{
+     struct bootp_packet *packet;
+
+     /* Check to see if we can get the [scyg]iaddr fields from netinfo */
+     packet = prom_get_netinfo();
+     if (!packet)
+          return;
+
+     DEBUG_F("We have a boot packet\n");
+     DEBUG_F(" siaddr = <%x>\n", packet->siaddr);
+     DEBUG_F(" ciaddr = <%x>\n", packet->ciaddr);
+     DEBUG_F(" yiaddr = <%x>\n", packet->yiaddr);
+     DEBUG_F(" giaddr = <%x>\n", packet->giaddr);
+
+     /* Try to fallback to yiaddr if ciaddr is empty. Broken? */
+     if (packet->ciaddr == 0 && packet->yiaddr != 0)
+          packet->ciaddr = packet->yiaddr;
+
+     if ((result->siaddr == NULL || *(result->siaddr) == '\x0')
+         && packet->siaddr != 0)
+          result->siaddr = ipv4_to_str(packet->siaddr);
+     if ((result->ciaddr == NULL || *(result->ciaddr) == '\x0')
+         && packet->ciaddr != 0)
+          result->ciaddr = ipv4_to_str(packet->ciaddr);
+     if ((result->giaddr == NULL || *(result->giaddr) == '\x0')
+         && packet->giaddr != 0)
+          result->giaddr = ipv4_to_str(packet->giaddr);
+
+     extract_vendor_options(packet, result);
+
+     /* FIXME: Yck! if we /still/ do not have a gateway then "cheat" and use
+      *        the server.  This will be okay if the client and server are on
+      *        the same IP network, if not then lets hope the server does ICMP
+      *        redirections */
+     if (result->giaddr == NULL) {
+          result->giaddr = ipv4_to_str(packet->siaddr);
+          DEBUG_F("Forcing giaddr to siaddr <%s>\n", result->giaddr);
+     }
+}
+
+/*
+ * Extract all the ipv6 arguments from the bootpath provided and fill result
+ * Syntax: ipv6,[dhcpv6[=diaddr,]]ciaddr=c_iaddr,giaddr=g_iaddr,siaddr=s_iaddr,
+ *      filename=file_name,tftp-retries=tftp_retries,blksize=block_size
+ * Returns 1 on success, 0 on failure.
  */
-char *
-parse_device_path(char *of_device, char **file_spec, int *partition)
+static int
+extract_ipv6_args(char *imagepath, struct boot_fspec_t *result)
 {
-       char *p, *last;
-
-       if (file_spec)
-               *file_spec = NULL;
-       if (partition)
-               *partition = -1;
-
-       p = strchr(of_device, ':');
-       if (p)
-               *p = 0;
-       else
-               return of_device;
-       
-       last = ++p;
-       while(*p && *p != ',') {
-        if (!isdigit (*p)) {
-                       p = last;
-                       break;
-               }
-               ++p;
-       }
-       if (p != last) {
-               *(p++) = 0;
-               if (partition)
-            *partition = simple_strtol(last, NULL, 10);
-       }
-       if (*p && file_spec)
-               *file_spec = p;
-               
-       return of_device;
+     char *str, *tmp;
+     int total_len;
+
+     result->is_ipv6 = 1;
+
+     /* Just allocate the max required size */
+     total_len = strlen(imagepath) + 1;
+     str = malloc(total_len);
+     if (!str)
+       return 0;
+
+     if ((tmp = strstr(imagepath, "dhcpv6=")) != NULL)
+       result->dhcpv6 = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "ciaddr=")) != NULL)
+       result->ciaddr = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "giaddr=")) != NULL)
+       result->giaddr = scopy(&str, &tmp);
 
+     if ((tmp = strstr(imagepath, "siaddr=")) != NULL)
+       result->siaddr = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "filename=")) != NULL)
+       result->file = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "tftp-retries=")) != NULL)
+       result->tftp_retries = scopy(&str, &tmp);
+
+     if ((tmp = strstr(imagepath, "blksize=")) != NULL)
+       result->blksize = scopy(&str, &tmp);
+
+     return 1;
 }
 
+/*
+ * Extract all the arguments provided in the imagepath and fill it in result.
+ * Returns 1 on success, 0 on failure.
+ */
+static int
+extract_netboot_args(char *imagepath, struct boot_fspec_t *result)
+{
+     int ret;
+
+     DEBUG_F("imagepath = %s\n", imagepath);
+
+     if (!imagepath)
+         return 1;
+
+     if (strstr(imagepath, TOK_IPV6))
+         ret = extract_ipv6_args(imagepath, result);
+     else
+         ret = extract_ipv4_args(imagepath, result);
+     extract_netinfo_args(result);
+
+     DEBUG_F("ipv6 = <%d>\n", result->is_ipv6);
+     DEBUG_F("siaddr = <%s>\n", result->siaddr);
+     DEBUG_F("file = <%s>\n", result->file);
+     DEBUG_F("ciaddr = <%s>\n", result->ciaddr);
+     DEBUG_F("giaddr = <%s>\n", result->giaddr);
+     DEBUG_F("bootp_retries = <%s>\n", result->bootp_retries);
+     DEBUG_F("tftp_retries = <%s>\n", result->tftp_retries);
+     DEBUG_F("addl_params = <%s>\n", result->addl_params);
+     DEBUG_F("dhcpv6 = <%s>\n", result->dhcpv6);
+     DEBUG_F("blksize = <%s>\n", result->blksize);
+
+     return ret;
+}
+
+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.
+
+   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
+    - arguments for obp-tftp open as specified in section 4.1 of
+      http://playground.sun.com/1275/practice/obp-tftp/tftp1_0.pdf
+      [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries
+      ex: enet:bootp,10.0.0.11,bootme,10.0.0.12,10.0.0.1,5,5
+   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
-validate_fspec(                struct boot_fspec_t*    spec,
-                       char*                   default_device,
-                       int                     default_part)
+parse_device_path(char *imagepath, char *defdevice, int defpart,
+                 char *deffile, struct boot_fspec_t *result)
 {
-    if (!spec->file) {
-       spec->file = spec->dev;
-       spec->dev = NULL;
-    }
-    if (spec->part == -1)
-       spec->part = default_part;
-    if (!spec->dev)
-       spec->dev = default_device;
-    if (!spec->file)
-       return FILE_BAD_PATH;
-    else if (spec->file[0] == ',')
-       spec->file++;
-
-    return FILE_ERR_OK;
+     char *ptr;
+     char *ipath = NULL;
+     char *defdev = NULL;
+     int device_kind = -1;
+
+     DEBUG_F("imagepath = %s; defdevice %s; defpart %d, deffile %s\n",
+               imagepath, defdevice, defpart, deffile);
+
+     result->dev = NULL;
+     result->part = -1;
+     result->file = NULL;
+
+     if (!imagepath)
+         return 0;
+
+      /*
+       * Do preliminary checking for an iscsi device; it may appear as
+       * pure a network device (device_type == "network") if this is
+       * ISWI.  This is the case on IBM systems doing an iscsi OFW
+       * boot.
+       */
+     if (strstr(imagepath, TOK_ISCSI)) {
+         /*
+          * get the virtual device information from the
+          * "nas-bootdevice" property.
+          */
+         if (prom_get_chosen("nas-bootdevice", bootdevice, BOOTDEVSZ)) {
+              DEBUG_F("reset boot-device to"
+                      " /chosen/nas-bootdevice = %s\n", bootdevice);
+              device_kind = FILE_DEVICE_ISCSI;
+              ipath = strdup(bootdevice);
+              if (!ipath)
+                   return 0;
+         }
+         else
+              return 0;
+     }
+     else if (!(ipath = strdup(imagepath)))
+         return 0;
+
+     if (defdevice) {
+         defdev = strdup(defdevice);
+         device_kind = prom_get_devtype(defdev);
+     } else if (device_kind == -1)
+         device_kind = prom_get_devtype(ipath);
+
+     /*
+      * When an iscsi iqn is present, it may have embedded colons, so
+      * don't parse off anything.
+      */
+     if (device_kind != FILE_DEVICE_NET &&
+        device_kind != FILE_DEVICE_ISCSI &&
+        strchr(defdev, ':') != NULL) {
+           if ((ptr = strrchr(defdev, ':')) != NULL)
+                *ptr = 0; /* remove trailing : from defdevice if necessary */
+     }
+
+     /* 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 &&
+        device_kind != FILE_DEVICE_ISCSI &&
+        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, ':')) {
+              if (extract_netboot_args(ipath, result) == 0)
+                  return 0;
+         } else {
+               /* If we didn't get a ':' then look only in netinfo */
+              extract_netinfo_args(result);
+              result->file = strdup(ipath);
+          }
+
+         if (!defdev)
+              result->dev = netdev_path_to_dev(ipath);
+     } else if (device_kind != FILE_DEVICE_ISCSI &&
+               (ptr = strrchr(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;
+     }
+
+     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,
+                       struct boot_fspec_t*    fspec,
                        int                     partition)
 {
-       struct partition_t*     parts;
-       struct partition_t*     p;
-       struct partition_t*     found;
-       
-       parts = partitions_lookup(dev_name);
-       found = NULL;
-                       
+     struct partition_t*       parts;
+     struct partition_t*       p;
+     struct partition_t*       found;
+
+     parts = partitions_lookup(fspec->dev);
+     found = NULL;
+
 #if DEBUG
-       if (parts)
-               prom_printf("partitions:\n");
-       else
-               prom_printf("no partitions found.\n");
+     if (parts)
+         prom_printf("partitions:\n");
+     else
+         prom_printf("no partitions found.\n");
 #endif
-       for (p = parts; p && !found; p=p->next) {
+     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, p, fspec );
+              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
-               prom_printf("number: %02d, start: 0x%08lx, length: 0x%08lx\n",
-                       p->part_number, p->part_start, p->part_size );
+         if (found)
+              prom_printf(" (match)\n");
 #endif
-               if (partition == -1) {
-                        file->fs = fs_open( file, dev_name, p, file_name );
-                       if (file->fs != NULL)
-                               goto bail;
-               }
-               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 = 0x%x)\n", found );
-        file->fs = fs_open( file, dev_name, found, file_name );
-
-bail:
-       if (parts)
-               partitions_free(parts);
-
-       return file->fs ? FILE_ERR_OK : FILE_ERR_NOTFOUND;
+     }
+
+     /* 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, found, fspec );
+
+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_net_open(struct boot_file_t* file, struct boot_fspec_t *fspec)
 {
-    file->fs = fs_of_netboot;
-    return fs_of_netboot->open(file, dev_name, NULL, file_name);
+     file->fs = fs_of_netboot;
+     return fs_of_netboot->open(file, NULL, fspec);
 }
 
 static int
@@ -154,106 +622,65 @@ default_read(    struct boot_file_t*     file,
                unsigned int            size,
                void*                   buffer)
 {
-       prom_printf("WARNING ! default_read called !\n");
-       return FILE_ERR_EOF;
+     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;
+     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;
+     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
+     "defaults",
+     NULL,
+     default_read,
+     default_seek,
+     default_close
 };
 
 
-int open_file( const struct boot_fspec_t*      spec,
-               struct boot_file_t*             file)
+int open_file(struct boot_fspec_t* spec, struct boot_file_t* file)
 {
-       static char     temp[1024];
-       static char     temps[64];
-       char            *dev_name;
-       char            *file_name = NULL;
-       phandle         dev;
-       int             result;
-       int             partition;
-       
-       memset(file, 0, sizeof(struct boot_file_t*));
-        file->fs        = &fs_default;
-
-       /* Lookup the OF device path */
-       /* First, see if a device was specified for the kernel
-        * if not, we hope that the user wants a kernel on the same
-        * drive and partition as yaboot itself */
-       if (!spec->dev)
-               strcpy(spec->dev, bootdevice);
-       strncpy(temp,spec->dev,1024);
-       dev_name = parse_device_path(temp, &file_name, &partition);
-       if (file_name == NULL)
-               file_name = (char *)spec->file;
-       if (file_name == NULL) {
-               prom_printf("booting without a file name not yet supported !\n");
-               return FILE_ERR_NOTFOUND;
-       }
-       if (partition == -1)
-               partition = spec->part;
+     int result;
 
-#if DEBUG
-       prom_printf("dev_path = %s\nfile_name = %s\npartition = %d\n",
-               dev_name, file_name, partition);
-#endif 
-       /* Find OF device phandle */
-       dev = prom_finddevice(dev_name);
-       if (dev == PROM_INVALID_HANDLE) {
-               prom_printf("device not found !\n");
-               return FILE_ERR_NOTFOUND;
-       }
-#if DEBUG
-       prom_printf("dev_phandle = %08lx\n", dev);
-#endif 
-       /* Check the kind of device */
-       result = prom_getprop(dev, "device_type", temps, 63);
-       if (result == -1) {
-               prom_printf("can't get <device_type> for device\n");
-               return FILE_ERR_NOTFOUND;
-       }
-       temps[result] = 0;
-       if (!strcmp(temps, "block"))
-               file->device_kind = FILE_DEVICE_BLOCK;
-       else if (!strcmp(temps, "network"))
-               file->device_kind = FILE_DEVICE_NET;
-       else {
-               prom_printf("Unkown device type <%s>\n", temps);
-               return FILE_ERR_NOTFOUND;
-       }
-       
-       switch(file->device_kind) {
-           case FILE_DEVICE_BLOCK:
-#if DEBUG
-               prom_printf("device is a block device\n");
-#endif
-               return file_block_open(file, dev_name, file_name, partition);
-           case FILE_DEVICE_NET:
-#if DEBUG
-               prom_printf("device is a network device\n");
-#endif
-               return file_net_open(file, dev_name, file_name);
-       }
-       return 0;
+     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, spec->part);
+     case FILE_DEVICE_NET:
+         DEBUG_F("device is a network device\n");
+         return file_net_open(file, spec);
+     }
+     return 0;
 }
+
+/*
+ * Local variables:
+ * c-file-style: "k&r"
+ * c-basic-offset: 5
+ * End:
+ */