uboot/common/cmd_gpt.c
<<
>>
Prefs
   1/*
   2 * cmd_gpt.c -- GPT (GUID Partition Table) handling command
   3 *
   4 * Copyright (C) 2012 Samsung Electronics
   5 * author: Lukasz Majewski <l.majewski@samsung.com>
   6 * author: Piotr Wilczek <p.wilczek@samsung.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21 */
  22
  23#include <common.h>
  24#include <malloc.h>
  25#include <command.h>
  26#include <mmc.h>
  27#include <part_efi.h>
  28#include <exports.h>
  29#include <linux/ctype.h>
  30
  31#ifndef CONFIG_PARTITION_UUIDS
  32#error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled
  33#endif
  34
  35/**
  36 * extract_env(): Expand env name from string format '&{env_name}'
  37 *                and return pointer to the env (if the env is set)
  38 *
  39 * @param str - pointer to string
  40 * @param env - pointer to pointer to extracted env
  41 *
  42 * @return - zero on successful expand and env is set
  43 */
  44static char extract_env(const char *str, char **env)
  45{
  46        char *e, *s;
  47
  48        if (!str || strlen(str) < 4)
  49                return -1;
  50
  51        if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) {
  52                s = strdup(str);
  53                if (s == NULL)
  54                        return -1;
  55                memset(s + strlen(s) - 1, '\0', 1);
  56                memmove(s, s + 2, strlen(s) - 1);
  57                e = getenv(s);
  58                free(s);
  59                if (e == NULL) {
  60                        printf("Environmental '%s' not set\n", str);
  61                        return -1; /* env not set */
  62                }
  63                *env = e;
  64                return 0;
  65        }
  66
  67        return -1;
  68}
  69
  70/**
  71 * extract_val(): Extract value from a key=value pair list (comma separated).
  72 *                Only value for the given key is returend.
  73 *                Function allocates memory for the value, remember to free!
  74 *
  75 * @param str - pointer to string with key=values pairs
  76 * @param key - pointer to the key to search for
  77 *
  78 * @return - pointer to allocated string with the value
  79 */
  80static char *extract_val(const char *str, const char *key)
  81{
  82        char *v, *k;
  83        char *s, *strcopy;
  84        char *new = NULL;
  85
  86        strcopy = strdup(str);
  87        if (strcopy == NULL)
  88                return NULL;
  89
  90        s = strcopy;
  91        while (s) {
  92                v = strsep(&s, ",");
  93                if (!v)
  94                        break;
  95                k = strsep(&v, "=");
  96                if (!k)
  97                        break;
  98                if  (strcmp(k, key) == 0) {
  99                        new = strdup(v);
 100                        break;
 101                }
 102        }
 103
 104        free(strcopy);
 105
 106        return new;
 107}
 108
 109/**
 110 * set_gpt_info(): Fill partition information from string
 111 *              function allocates memory, remember to free!
 112 *
 113 * @param dev_desc - pointer block device descriptor
 114 * @param str_part - pointer to string with partition information
 115 * @param str_disk_guid - pointer to pointer to allocated string with disk guid
 116 * @param partitions - pointer to pointer to allocated partitions array
 117 * @param parts_count - number of partitions
 118 *
 119 * @return - zero on success, otherwise error
 120 *
 121 */
 122static int set_gpt_info(block_dev_desc_t *dev_desc,
 123                        const char *str_part,
 124                        char **str_disk_guid,
 125                        disk_partition_t **partitions,
 126                        u8 *parts_count)
 127{
 128        char *tok, *str, *s;
 129        int i;
 130        char *val, *p;
 131        int p_count;
 132        disk_partition_t *parts;
 133        int errno = 0;
 134
 135        debug("%s: MMC lba num: 0x%x %d\n", __func__,
 136              (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
 137
 138        if (str_part == NULL)
 139                return -1;
 140
 141        str = strdup(str_part);
 142
 143        /* extract disk guid */
 144        s = str;
 145        tok = strsep(&s, ";");
 146        val = extract_val(tok, "uuid_disk");
 147        if (!val) {
 148                free(str);
 149                return -2;
 150        }
 151        if (extract_env(val, &p))
 152                p = val;
 153        *str_disk_guid = strdup(p);
 154        free(val);
 155
 156        if (strlen(s) == 0)
 157                return -3;
 158
 159        i = strlen(s) - 1;
 160        if (s[i] == ';')
 161                s[i] = '\0';
 162
 163        /* calculate expected number of partitions */
 164        p_count = 1;
 165        p = s;
 166        while (*p) {
 167                if (*p++ == ';')
 168                        p_count++;
 169        }
 170
 171        /* allocate memory for partitions */
 172        parts = calloc(sizeof(disk_partition_t), p_count);
 173
 174        /* retrive partions data from string */
 175        for (i = 0; i < p_count; i++) {
 176                tok = strsep(&s, ";");
 177
 178                if (tok == NULL)
 179                        break;
 180
 181                /* uuid */
 182                val = extract_val(tok, "uuid");
 183                if (!val) { /* 'uuid' is mandatory */
 184                        errno = -4;
 185                        goto err;
 186                }
 187                if (extract_env(val, &p))
 188                        p = val;
 189                if (strlen(p) >= sizeof(parts[i].uuid)) {
 190                        printf("Wrong uuid format for partition %d\n", i);
 191                        errno = -4;
 192                        goto err;
 193                }
 194                strcpy((char *)parts[i].uuid, p);
 195                free(val);
 196
 197                /* name */
 198                val = extract_val(tok, "name");
 199                if (!val) { /* name is mandatory */
 200                        errno = -4;
 201                        goto err;
 202                }
 203                if (extract_env(val, &p))
 204                        p = val;
 205                if (strlen(p) >= sizeof(parts[i].name)) {
 206                        errno = -4;
 207                        goto err;
 208                }
 209                strcpy((char *)parts[i].name, p);
 210                free(val);
 211
 212                /* size */
 213                val = extract_val(tok, "size");
 214                if (!val) { /* 'size' is mandatory */
 215                        errno = -4;
 216                        goto err;
 217                }
 218                if (extract_env(val, &p))
 219                        p = val;
 220                parts[i].size = ustrtoul(p, &p, 0);
 221                parts[i].size /= dev_desc->blksz;
 222                free(val);
 223
 224                /* start address */
 225                val = extract_val(tok, "start");
 226                if (val) { /* start address is optional */
 227                        if (extract_env(val, &p))
 228                                p = val;
 229                        parts[i].start = ustrtoul(p, &p, 0);
 230                        parts[i].start /= dev_desc->blksz;
 231                        free(val);
 232                }
 233        }
 234
 235        *parts_count = p_count;
 236        *partitions = parts;
 237        free(str);
 238
 239        return 0;
 240err:
 241        free(str);
 242        free(*str_disk_guid);
 243        free(parts);
 244
 245        return errno;
 246}
 247
 248static int gpt_mmc_default(int dev, const char *str_part)
 249{
 250        int ret;
 251        char *str_disk_guid;
 252        u8 part_count = 0;
 253        disk_partition_t *partitions = NULL;
 254
 255        struct mmc *mmc = find_mmc_device(dev);
 256
 257        if (mmc == NULL) {
 258                printf("%s: mmc dev %d NOT available\n", __func__, dev);
 259                return CMD_RET_FAILURE;
 260        }
 261
 262        if (!str_part)
 263                return -1;
 264
 265        /* fill partitions */
 266        ret = set_gpt_info(&mmc->block_dev, str_part,
 267                        &str_disk_guid, &partitions, &part_count);
 268        if (ret) {
 269                if (ret == -1)
 270                        printf("No partition list provided\n");
 271                if (ret == -2)
 272                        printf("Missing disk guid\n");
 273                if ((ret == -3) || (ret == -4))
 274                        printf("Partition list incomplete\n");
 275                return -1;
 276        }
 277
 278        /* save partitions layout to disk */
 279        gpt_restore(&mmc->block_dev, str_disk_guid, partitions, part_count);
 280        free(str_disk_guid);
 281        free(partitions);
 282
 283        return 0;
 284}
 285
 286/**
 287 * do_gpt(): Perform GPT operations
 288 *
 289 * @param cmdtp - command name
 290 * @param flag
 291 * @param argc
 292 * @param argv
 293 *
 294 * @return zero on success; otherwise error
 295 */
 296static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 297{
 298        int ret = CMD_RET_SUCCESS;
 299        int dev = 0;
 300        char *pstr;
 301
 302        if (argc < 5)
 303                return CMD_RET_USAGE;
 304
 305        /* command: 'write' */
 306        if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
 307                /* device: 'mmc' */
 308                if (strcmp(argv[2], "mmc") == 0) {
 309                        /* check if 'dev' is a number */
 310                        for (pstr = argv[3]; *pstr != '\0'; pstr++)
 311                                if (!isdigit(*pstr)) {
 312                                        printf("'%s' is not a number\n",
 313                                                argv[3]);
 314                                        return CMD_RET_USAGE;
 315                                }
 316                        dev = (int)simple_strtoul(argv[3], NULL, 10);
 317                        /* write to mmc */
 318                        if (gpt_mmc_default(dev, argv[4]))
 319                                return CMD_RET_FAILURE;
 320                }
 321        } else {
 322                return CMD_RET_USAGE;
 323        }
 324        return ret;
 325}
 326
 327U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 328        "GUID Partition Table",
 329        "<command> <interface> <dev> <partions_list>\n"
 330        " - GUID partition table restoration\n"
 331        " Restore GPT information on a device connected\n"
 332        " to interface\n"
 333);
 334