X-Git-Url: http://git.ozlabs.org/?p=yaboot.git;a=blobdiff_plain;f=second%2Ffile.c;h=4054dd18ca24a3746990f3c19bc527a4ee7bfab7;hp=ed70376be542670865c249a52e1086381418acd3;hb=6166753b1295119cfd8f7a5973b0b523098ef263;hpb=15b93b378020b59031b991abe31b130ca105be03 diff --git a/second/file.c b/second/file.c index ed70376..4054dd1 100644 --- a/second/file.c +++ b/second/file.c @@ -36,12 +36,118 @@ #include "errors.h" #include "debug.h" -extern char bootdevice[1024]; +extern char bootdevice[]; + +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 @@ -71,6 +177,7 @@ parse_device_path(char *imagepath, char *defdevice, int defpart, char *ptr; char *ipath = NULL; char *defdev = NULL; + int device_kind = -1; result->dev = NULL; result->part = -1; @@ -78,25 +185,55 @@ parse_device_path(char *imagepath, char *defdevice, int defpart, if (!imagepath) return 0; - else if (!(ipath = strdup(imagepath))) + + /* + * 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) + if (defdevice) { defdev = strdup(defdevice); + device_kind = prom_get_devtype(defdev); + } else if (device_kind == -1) + device_kind = prom_get_devtype(ipath); - if (defdev) { - if (!strstr(defdev, "ethernet") && !strstr(defdev, "enet")) { - if ((ptr = strrchr(defdev, ':')) != NULL) - *ptr = 0; /* remove trailing : from defdevice if necessary */ - } - } else { - return 0; + /* + * 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 */ } - /* 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) { + /* 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 @@ -109,19 +246,22 @@ parse_device_path(char *imagepath, char *defdevice, int defpart, } } - 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) { + 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 (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); + result->dev = strdup(ipath); } else if (strlen(ipath)) { result->file = strdup(ipath); } else { @@ -131,10 +271,10 @@ parse_device_path(char *imagepath, char *defdevice, int defpart, if (!result->dev && defdev) result->dev = strdup(defdev); - + if (result->part < 0) result->part = defpart; - + if (!result->file) result->file = strdup(deffile); @@ -154,10 +294,10 @@ file_block_open( struct boot_file_t* file, 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"); @@ -181,7 +321,7 @@ file_block_open( struct boot_file_t* file, #if DEBUG if (found) prom_printf(" (match)\n"); -#endif +#endif } /* Note: we don't skip when found is NULL since we can, in some @@ -243,7 +383,7 @@ static struct fs_t fs_default = 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; @@ -255,7 +395,7 @@ int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file) file->device_kind = result; else return result; - + switch(file->device_kind) { case FILE_DEVICE_BLOCK: DEBUG_F("device is a block device\n"); @@ -267,7 +407,7 @@ int open_file(const struct boot_fspec_t* spec, struct boot_file_t* file) return 0; } -/* +/* * Local variables: * c-file-style: "k&r" * c-basic-offset: 5