From f8795693f1c3caa557b8658ac3d8661b1f84b739 Mon Sep 17 00:00:00 2001 From: Paulo de Rezende Pinatti Date: Tue, 13 Jul 2010 11:22:35 -0300 Subject: [PATCH] Added support to netdisk specified in the form (net,protocol,server_ip,username,password) an to list its information with command ls. * fs/ieee1275/ofnet.c (grub_ofnet_open): parse parameters to determine netdisk data * fs/ieee1275/ofnet.c (grub_ofnet_close): dealloc netdisk data * include/grub/disk.h: added struct grub_netdisk_data * include/grub/ieee1275/ofnet.h: added newline * kern/disk.c (grub_disk_open): ignore partition check for netdisk * normal/misc.c (grub_normal_print_device_info): added support to list netdisk information --- fs/ieee1275/ofnet.c | 159 ++++++++++++++++++++++++++++++++-- include/grub/disk.h | 17 ++++ include/grub/ieee1275/ofnet.h | 1 + kern/disk.c | 4 +- normal/misc.c | 39 +++++++++ 5 files changed, 213 insertions(+), 7 deletions(-) diff --git a/fs/ieee1275/ofnet.c b/fs/ieee1275/ofnet.c index a9d16e7e0..9010317ba 100644 --- a/fs/ieee1275/ofnet.c +++ b/fs/ieee1275/ofnet.c @@ -42,6 +42,85 @@ //static grub_ieee1275_ihandle_t handle = 0; +static const char * +find_sep (const char *name) +{ + const char *p = name; + char c = *p; + + if (c == '\0') + return NULL; + + do + { + if (c == '\\' && *p == ',') + p++; + else if (c == ',') + return p - 1; + } while ((c = *p++) != '\0'); + return p - 1; +} + +static grub_err_t +retrieve_field(const char *src, char **field, const char **rest) +{ + const char *p; + grub_size_t len; + + p = find_sep(src); + if (! p) + { + *field = NULL; + *rest = src; + return 0; + } + + len = p - src; + *field = grub_malloc (len + 1); + if (! *field) + { + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "fail to alloc memory"); + } + + grub_memcpy (*field, src, len); + (*field)[len] = '\0'; + + if (*p == '\0') + *rest = p; + else + *rest = p + 1; + return 0; +} + +static grub_err_t +parse_ip (const char *val, grub_uint32_t *ip, const char **rest) +{ + grub_uint32_t newip = 0; + unsigned long t; + int i; + const char *ptr = val; + + for (i = 0; i < 4; i++) + { + t = grub_strtoul (ptr, (char **) &ptr, 0); + if (grub_errno) + return grub_errno; + if (t & ~0xff) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP."); + newip >>= 8; + newip |= (t << 24); + if (i != 3 && *ptr != '.') + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP."); + ptr++; + } + ptr = ptr - 1; + if ( *ptr != '\0' && *ptr != ',') + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP."); + *ip = newip; + if (rest) + *rest = ptr; + return 0; +} static int grub_ofnet_iterate (int (*hook) (const char *name)) @@ -54,23 +133,93 @@ grub_ofnet_iterate (int (*hook) (const char *name)) static grub_err_t grub_ofnet_open (const char *name, grub_disk_t disk) { - + grub_err_t err; + const char *p1, *p2; + char *user = NULL, *pwd = NULL; + grub_netdisk_data_t data; + grub_netdisk_protocol_t proto; + grub_uint32_t server_ip = 0; if (grub_strcmp (name, "net")) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a net disk"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a net disk"); - disk->total_sectors = U64MAXSIZE; + p1 = find_sep(disk->name); + if (! p1 || *p1 == '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments missing"); + p1++; + + // parse protocol + p2 = find_sep(p1); + if (! p2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no protocol specified"); + if ((p2 - p1 == 4) && (! grub_strncasecmp(p1, "tftp", p2 - p1))) + proto = GRUB_NETDISK_PROTOCOL_TFTP; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid protocol specified"); + + // parse server ip + if ( *p2 == '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no server ip specified"); + p1 = p2 + 1; + err = parse_ip(p1, &server_ip, &p2); + if (err) + return err; + + // parse username (optional) + if ( *p2 == ',') + p2++; + err = retrieve_field(p2, &user, &p1); + if (err) + return err; + if (user) + { + // parse password (optional) + err = retrieve_field(p1, &pwd, &p2); + if (err) + { + grub_free(user); + return err; + } + } + + if (! disk->data) + { + data = grub_malloc (sizeof(*data)); + disk->data = data; + } + else + { + data = disk->data; + if (data->username) + grub_free(data->username); + if (data->password) + grub_free(data->password); + } + data->protocol = proto; + data->server_ip = server_ip; + data->username = user; + data->password = pwd; + + disk->total_sectors = 0; disk->id = (unsigned long) "net"; disk->has_partitions = 0; - disk->data = 0; return GRUB_ERR_NONE; } static void -grub_ofnet_close (grub_disk_t disk __attribute((unused))) +grub_ofnet_close (grub_disk_t disk) { + grub_netdisk_data_t data = disk->data; + if (data) + { + if (data->username) + grub_free(data->username); + if (data->password) + grub_free(data->password); + grub_free(data); + } } static grub_err_t diff --git a/include/grub/disk.h b/include/grub/disk.h index 1bdfb639b..dc8bc5018 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -119,6 +119,23 @@ struct grub_disk }; typedef struct grub_disk *grub_disk_t; +/* Net Disk */ +enum grub_netdisk_protocol +{ + GRUB_NETDISK_PROTOCOL_TFTP +}; +typedef enum grub_netdisk_protocol grub_netdisk_protocol_t; + +struct grub_netdisk_data +{ + grub_netdisk_protocol_t protocol; + grub_uint32_t server_ip; + grub_uint32_t port; + char *username; + char *password; +}; +typedef struct grub_netdisk_data *grub_netdisk_data_t; + #ifdef GRUB_UTIL struct grub_disk_memberlist { diff --git a/include/grub/ieee1275/ofnet.h b/include/grub/ieee1275/ofnet.h index 7daadf61d..a26c22235 100644 --- a/include/grub/ieee1275/ofnet.h +++ b/include/grub/ieee1275/ofnet.h @@ -25,6 +25,7 @@ extern void grub_ofnet_init(void); extern void grub_ofnet_fini(void); + /* struct grub_net; diff --git a/kern/disk.c b/kern/disk.c index ccd5f200f..051e59aca 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -281,7 +281,7 @@ grub_disk_open (const char *name) goto fail; } - if (p && ! disk->has_partitions) + if (p && ! disk->has_partitions && grub_strcmp (raw, "net")) { grub_error (GRUB_ERR_BAD_DEVICE, "no partition on this disk"); goto fail; @@ -289,7 +289,7 @@ grub_disk_open (const char *name) disk->dev = dev; - if (p) + if (p && grub_strcmp (raw, "net")) { disk->partition = grub_partition_probe (disk, p + 1); if (! disk->partition) diff --git a/normal/misc.c b/normal/misc.c index 17ba372ce..d53fe711c 100644 --- a/normal/misc.c +++ b/normal/misc.c @@ -32,8 +32,47 @@ grub_err_t grub_normal_print_device_info (const char *name) { grub_device_t dev; + grub_netdisk_data_t data; char *p; + if ((! grub_strcmp(name, "net")) || (! grub_strncmp(name, "net,", 4))) + { + grub_printf_ (N_("Device network:")); + grub_putchar (' '); + + dev = grub_device_open (name); + if (! dev || ! dev->disk || ! dev->disk->data) + grub_printf ("%s", _("Network information not available")); + else + { + data = dev->disk->data; + grub_putchar ('\n'); + grub_putchar ('\t'); + if (data->protocol == GRUB_NETDISK_PROTOCOL_TFTP) + grub_printf_(N_("Protocol: %s"), "TFTP"); + else + grub_printf_(N_("Protocol: %s"), "Unknown"); + grub_putchar ('\n'); + grub_putchar ('\t'); + grub_printf_(N_("Server IP: %d.%d.%d.%d"), data->server_ip & 0xff, data->server_ip >> 8 & 0xff, data->server_ip >> 16 & 0xff, data->server_ip >> 24 & 0xff); + if (data->username) + { + grub_putchar ('\n'); + grub_putchar ('\t'); + grub_printf_(N_("Username: %s"), data->username); + if (data->password) + { + grub_putchar ('\n'); + grub_putchar ('\t'); + grub_printf_(N_("Password: %s"), data->password); + } + } + } + grub_putchar ('\n'); + + return GRUB_ERR_NONE; + } + p = grub_strchr (name, ','); if (p) {