]> www.infradead.org Git - mtd-utils.git/commitdiff
ubi-utils: save original files in sort-me-out
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Mon, 21 Jan 2008 09:20:21 +0000 (11:20 +0200)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Mon, 21 Jan 2008 09:20:21 +0000 (11:20 +0200)
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
ubi-utils/sort-me-out/list.c [new file with mode: 0644]
ubi-utils/sort-me-out/list.h [new file with mode: 0644]
ubi-utils/sort-me-out/peb.c [new file with mode: 0644]
ubi-utils/sort-me-out/peb.h [new file with mode: 0644]
ubi-utils/sort-me-out/pfi.c [new file with mode: 0644]
ubi-utils/sort-me-out/pfi.h [new file with mode: 0644]
ubi-utils/sort-me-out/pfiflash.h [new file with mode: 0644]
ubi-utils/sort-me-out/reader.c [new file with mode: 0644]
ubi-utils/sort-me-out/reader.h [new file with mode: 0644]

diff --git a/ubi-utils/sort-me-out/list.c b/ubi-utils/sort-me-out/list.c
new file mode 100644 (file)
index 0000000..6eb716b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "list.h"
+
+list_t
+mk_empty(void)
+{
+       return (list_t) NULL;
+}
+
+int
+is_empty(list_t l)
+{
+       return l == NULL;
+}
+
+info_t
+head(list_t l)
+{
+       assert(!is_empty(l));
+       return l->info;
+}
+
+list_t
+tail(list_t l)
+{
+       assert(!is_empty(l));
+       return l->next;
+}
+
+list_t
+remove_head(list_t l)
+{
+       list_t res;
+       assert(!is_empty(l));
+
+       res = l->next;
+       free(l);
+       return res;
+}
+
+list_t
+cons(info_t e, list_t l)
+{
+       list_t res = malloc(sizeof(*l));
+       if (!res)
+               return NULL;
+       res->info = e;
+       res->next = l;
+
+       return res;
+}
+
+list_t
+prepend_elem(info_t e, list_t l)
+{
+       return cons(e,l);
+}
+
+list_t
+append_elem(info_t e, list_t l)
+{
+       if (is_empty(l)) {
+               return cons(e,l);
+       }
+       l->next = append_elem(e, l->next);
+
+       return l;
+}
+
+list_t
+insert_sorted(cmp_func_t cmp, info_t e, list_t l)
+{
+       if (is_empty(l))
+               return cons(e, l);
+
+       switch (cmp(e, l->info)) {
+       case -1:
+       case  0:
+               return l;
+               break;
+       case  1:
+               l->next = insert_sorted(cmp, e, l);
+               break;
+       default:
+               break;
+       }
+
+       /* never reached */
+       return NULL;
+}
+
+list_t
+remove_all(free_func_t free_func, list_t l)
+{
+       if (is_empty(l))
+               return l;
+       list_t lnext = l->next;
+
+       if (free_func && l->info) {
+               free_func(&(l->info));
+       }
+       free(l);
+
+       return remove_all(free_func, lnext);
+}
+
+
+info_t
+is_in(cmp_func_t cmp, info_t e, list_t l)
+{
+       return
+       (is_empty(l))
+       ? NULL
+       : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next);
+}
+
+
+void
+apply(process_func_t process_func, list_t l)
+{
+       list_t ptr;
+       void *i;
+       foreach(i, ptr, l) {
+               process_func(i);
+       }
+}
diff --git a/ubi-utils/sort-me-out/list.h b/ubi-utils/sort-me-out/list.h
new file mode 100644 (file)
index 0000000..e8452a2
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef __LIST_H__
+#define __LIST_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdint.h>
+
+#define foreach(elem, ptr, list)                               \
+       for (elem = list != NULL ? (typeof(elem)) head(list)    \
+                                : NULL, ptr = list;            \
+               ptr != NULL;                                    \
+               ptr = tail(ptr),                                \
+               elem = (typeof(elem)) ptr ? head(ptr) : NULL)
+
+typedef struct node* list_t;
+typedef void* info_t;
+typedef int  (*free_func_t)(info_t*);
+typedef int  (*cmp_func_t)(info_t, info_t);
+typedef void (*process_func_t)(info_t);
+
+struct node {
+       list_t next;
+       info_t  info;
+};
+
+list_t mk_empty(void);
+int    is_empty(list_t l);
+info_t is_in(cmp_func_t cmp, info_t e, list_t l);
+info_t head(list_t l);
+list_t tail(list_t l);
+list_t remove_head(list_t l);
+list_t cons(info_t e, list_t l);
+list_t prepend_elem(info_t e, list_t);
+list_t append_elem(info_t e, list_t);
+list_t remove_all(free_func_t free_func, list_t l);
+list_t insert_sorted(cmp_func_t cmp_func, info_t e, list_t l);
+void   apply(process_func_t process_func, list_t l);
+
+#endif /* __LIST_H__ */
diff --git a/ubi-utils/sort-me-out/peb.c b/ubi-utils/sort-me-out/peb.c
new file mode 100644 (file)
index 0000000..160a463
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "peb.h"
+
+int
+peb_cmp(peb_t eb_1, peb_t eb_2)
+{
+       assert(eb_1);
+       assert(eb_2);
+
+       return eb_1->num == eb_2->num ? 0
+               : eb_1->num > eb_2->num ? 1 : -1;
+}
+
+int
+peb_new(uint32_t eb_num, uint32_t peb_size, peb_t *peb)
+{
+       int rc = 0;
+
+       peb_t res = (peb_t) malloc(sizeof(struct peb));
+       if (!res) {
+               rc = -ENOMEM;
+               goto err;
+       }
+
+       res->num  = eb_num;
+       res->size = peb_size;
+       res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t));
+       if (!res->data) {
+               rc = -ENOMEM;
+               goto err;
+       }
+       memset(res->data, 0xff, res->size);
+
+       *peb = res;
+       return 0;
+err:
+       if (res) {
+               if (res->data)
+                       free(res->data);
+               free(res);
+       }
+       *peb = NULL;
+       return rc;
+}
+
+int
+peb_fill(peb_t peb, uint8_t* buf, size_t buf_size)
+{
+       if (!peb)
+               return -EINVAL;
+
+       if (buf_size > peb->size)
+               return -EINVAL;
+
+       memcpy(peb->data, buf, buf_size);
+       return 0;
+}
+
+int
+peb_write(FILE* fp_out, peb_t peb)
+{
+       size_t written = 0;
+
+       if (peb == NULL)
+               return -EINVAL;
+
+       written = fwrite(peb->data, 1, peb->size, fp_out);
+
+       if (written != peb->size)
+               return -EIO;
+
+       return 0;
+}
+
+int
+peb_free(peb_t* peb)
+{
+       peb_t tmp = *peb;
+       if (tmp) {
+               if (tmp->data)
+                       free(tmp->data);
+               free(tmp);
+       }
+       *peb = NULL;
+
+       return 0;
+}
+
+void peb_dump(FILE* fp_out, peb_t peb)
+{
+       fprintf(fp_out, "num: %08d\tsize: 0x%08x\n", peb->num, peb->size);
+}
diff --git a/ubi-utils/sort-me-out/peb.h b/ubi-utils/sort-me-out/peb.h
new file mode 100644 (file)
index 0000000..246bce8
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __RAW_BLOCK_H__
+#define __RAW_BLOCK_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+typedef struct peb *peb_t;
+struct peb {
+       uint32_t num;           /* Physical eraseblock number
+                                * in the RAW file. */
+       uint32_t size;          /* Data Size (equals physical
+                                * erase block size) */
+       uint8_t* data;          /* Data buffer */
+};
+
+int  peb_new(uint32_t peb_num, uint32_t peb_size, peb_t* peb);
+int  peb_free(peb_t* peb);
+int  peb_cmp(peb_t peb_1, peb_t peb_2);
+int  peb_write(FILE* fp_out, peb_t peb);
+void peb_dump(FILE* fp_out, peb_t peb);
+
+#endif /* __RAW_BLOCK_H__ */
diff --git a/ubi-utils/sort-me-out/pfi.c b/ubi-utils/sort-me-out/pfi.c
new file mode 100644 (file)
index 0000000..fa835e2
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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 pfi.c
+ *
+ * @author Oliver Lohmann
+ *        Andreas Arnez
+ *        Joern Engel
+ *        Frank Haverkamp
+ *
+ * @brief libpfi holds all code to create and process pfi files.
+ *
+ * <oliloh@de.ibm.com> Wed Feb 8 11:38:22 CET 2006: Initial creation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "pfi.h"
+
+#define PFI_MAGIC     "PFI!\n"
+#define PFI_DATA      "DATA\n" /* The same size as PFI_MAGIC */
+#define PFI_MAGIC_LEN 5
+
+static const char copyright [] __attribute__((unused)) =
+       "Copyright (c) International Business Machines Corp., 2006";
+
+enum key_id {
+       /* version 1 */
+       key_version,          /* must be index position 0! */
+       key_mode,
+       key_size,
+       key_crc,
+       key_label,
+       key_flags,
+       key_ubi_ids,
+       key_ubi_size,
+       key_ubi_type,
+       key_ubi_names,
+       key_ubi_alignment,
+       key_raw_starts,
+       key_raw_total_size,
+       num_keys,
+};
+
+struct pfi_header {
+       char defined[num_keys];  /* reserve all possible keys even if
+                                   version does not require this. */
+       int mode_no;             /* current mode no. -> can only increase */
+       union {
+               char *str;
+               uint32_t num;
+       } value[num_keys];
+};
+
+
+#define PFI_MANDATORY      0x0001
+#define PFI_STRING         0x0002
+#define PFI_LISTVALUE      0x0004      /* comma seperated list of nums */
+#define PFI_MANDATORY_UBI   0x0008
+#define PFI_MANDATORY_RAW   0x0010
+
+struct key_descriptor {
+       enum key_id id;
+       const char *name;
+       uint32_t flags;
+};
+
+static const struct key_descriptor key_desc_v1[] = {
+       { key_version, "version", PFI_MANDATORY },
+       { key_mode, "mode", PFI_MANDATORY | PFI_STRING },
+       { key_size, "size", PFI_MANDATORY },
+       { key_crc, "crc", PFI_MANDATORY },
+       { key_label, "label", PFI_MANDATORY | PFI_STRING },
+       { key_flags, "flags", PFI_MANDATORY },
+       { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING },
+       { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI },
+       { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING },
+       { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING },
+       { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI },
+       { key_raw_starts, "raw_starts", PFI_MANDATORY_RAW | PFI_STRING },
+       { key_raw_total_size, "raw_total_size", PFI_MANDATORY_RAW },
+};
+
+static const struct key_descriptor *key_descriptors[] = {
+       NULL,
+       key_desc_v1,                                       /* version 1 */
+};
+
+static const int key_descriptors_max[] = {
+       0,                                                 /* version 0 */
+       sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */
+};
+
+#define ARRAY_SIZE(a)    (sizeof(a) / sizeof((a)[0]))
+
+static const char* modes[] = {"raw", "ubi"}; /* order isn't arbitrary! */
+
+/* latest version contains all possible keys */
+static const struct key_descriptor *key_desc = key_desc_v1;
+
+#define PFI_IS_UBI(mode) \
+       (((mode) != NULL) && (strcmp("ubi", (mode)) == 0))
+
+#define PFI_IS_RAW(mode) \
+       (((mode) != NULL) && (strcmp("raw", (mode)) == 0))
+
+/**
+ * @return      <0     On Error.
+ *             >=0     Mode no.
+ */
+static int
+get_mode_no(const char* mode)
+{
+       int i;
+
+       for (i = 0; i < (int)ARRAY_SIZE(modes); i++)
+               if (strcmp(mode, modes[i]) == 0)
+                       return i;
+       return -1;
+}
+
+static int
+find_key_by_name (const char *name)
+{
+       int i;
+
+       for (i = 0; i < num_keys; i++) {
+               if (strcmp(name, key_desc[i].name) == 0)
+                       return i;
+       }
+       return -1;
+}
+
+static int
+check_valid (pfi_header head)
+{
+       int i;
+       int max_keys;
+       uint32_t version;
+       const char *mode;
+       const struct key_descriptor *desc;
+       uint32_t to_check = PFI_MANDATORY;
+
+       /*
+        * For the validity check the list of possible keys depends on
+        * the version of the PFI file used.
+        */
+       version = head->value[key_version].num;
+       if (version > PFI_HDRVERSION)
+               return PFI_ENOHEADER;
+
+       max_keys = key_descriptors_max[version];
+       desc = key_descriptors[version];
+
+       if (!desc)
+               return PFI_ENOVERSION;
+
+       mode = head->value[key_mode].str;
+       if (PFI_IS_UBI(mode)) {
+               to_check |= PFI_MANDATORY_UBI;
+       }
+       else if (PFI_IS_RAW(mode)) {
+               to_check |= PFI_MANDATORY_RAW;
+       }
+       else { /* neither UBI nor RAW == ERR */
+               return PFI_EINSUFF;
+       }
+
+       for (i = 0; i < max_keys; i++) {
+               if ((desc[i].flags & to_check) && !head->defined[i]) {
+                       fprintf(stderr, "libpfi: %s missing\n", desc[i].name);
+                       return PFI_EINSUFF;
+               }
+       }
+
+       return 0;
+}
+
+int pfi_header_init (pfi_header *head)
+{
+       int i;
+       pfi_header self = (pfi_header) malloc(sizeof(*self));
+
+       *head = self;
+       if (self == NULL)
+               return PFI_ENOMEM;
+
+       /* initialize maximum number of possible keys */
+       for (i = 0; i < num_keys; i++) {
+               memset(self, 0, sizeof(*self));
+               self->defined[i] = 0;
+       }
+
+       return 0;
+}
+
+int pfi_header_destroy (pfi_header *head)
+{
+       int i;
+       pfi_header self = *head;
+
+       for (i = 0; i < num_keys; i++) {
+               if (self->defined[i] && (key_desc[i].flags & PFI_STRING) &&
+                   self->value[i].str) {
+                       free(self->value[i].str);
+               }
+       }
+       free(*head);
+       *head = NULL;
+       return 0;
+}
+
+int pfi_header_setnumber (pfi_header head,
+                          const char *key, uint32_t value)
+{
+       int key_id = find_key_by_name(key);
+
+       if (key_id < 0)
+               return PFI_EUNDEF;
+
+       if (key_desc[key_id].flags & PFI_STRING)
+               return PFI_EBADTYPE;
+
+       head->value[key_id].num = value;
+       head->defined[key_id] = 1;
+       return 0;
+}
+
+int pfi_header_setvalue (pfi_header head,
+                         const char *key, const char *value)
+{
+       int key_id = find_key_by_name(key);
+
+       if (value == NULL)
+               return PFI_EINSUFF;
+
+       if ((key_id < 0) || (key_id >= num_keys))
+               return PFI_EUNDEF;
+
+       if (key_desc[key_id].flags & PFI_STRING) {
+               /*
+                * The value is a string. Copy to a newly allocated
+                * buffer. Delete the old value, if already set.
+                */
+               size_t len = strlen(value) + 1;
+               char *old_str = NULL;
+               char *str;
+
+               old_str = head->value[key_id].str;
+               if (old_str != NULL)
+                       free(old_str);
+
+               str = head->value[key_id].str = (char *) malloc(len);
+               if (str == NULL)
+                       return PFI_ENOMEM;
+
+               strcpy(str, value);
+       } else {
+               int len;
+               int ret;
+               /* FIXME: here we assume that the value is always
+                  given in hex and starts with '0x'. */
+               ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len);
+               if (ret < 1 || value[len] != '\0')
+                       return PFI_EBADTYPE;
+       }
+       head->defined[key_id] = 1;
+       return 0;
+}
+
+int pfi_header_getnumber (pfi_header head,
+                          const char *key, uint32_t *value)
+{
+       int key_id = find_key_by_name(key);
+
+       if (key_id < 0)
+               return PFI_EUNDEF;
+
+       if (key_desc[key_id].flags & PFI_STRING)
+               return PFI_EBADTYPE;
+
+       if (!head->defined[key_id])
+               return PFI_EUNDEF;
+
+       *value = head->value[key_id].num;
+       return 0;
+}
+
+int pfi_header_getstring (pfi_header head,
+                          const char *key, char *value, size_t size)
+{
+       int key_id = find_key_by_name(key);
+
+       if (key_id < 0)
+               return PFI_EUNDEF;
+
+       if (!(key_desc[key_id].flags & PFI_STRING))
+               return PFI_EBADTYPE;
+
+       if (!head->defined[key_id])
+               return PFI_EUNDEF;
+
+       strncpy(value, head->value[key_id].str, size-1);
+       value[size-1] = '\0';
+       return 0;
+}
+
+int pfi_header_write (FILE *out, pfi_header head)
+{
+       int i;
+       int ret;
+
+       pfi_header_setnumber(head, "version", PFI_HDRVERSION);
+
+       if ((ret = check_valid(head)) != 0)
+               return ret;
+
+       /* OK.  Now write the header. */
+
+       ret = fwrite(PFI_MAGIC, 1, PFI_MAGIC_LEN, out);
+       if (ret < PFI_MAGIC_LEN)
+               return ret;
+
+
+       for (i = 0; i < num_keys; i++) {
+               if (!head->defined[i])
+                       continue;
+
+               ret = fprintf(out, "%s=", key_desc[i].name);
+               if (ret < 0)
+                       return PFI_EFILE;
+
+               if (key_desc[i].flags & PFI_STRING) {
+                       ret = fprintf(out, "%s", head->value[i].str);
+                       if (ret < 0)
+                               return PFI_EFILE;
+               } else {
+                       ret = fprintf(out, "0x%8x", head->value[i].num);
+                       if (ret < 0)
+                               return PFI_EFILE;
+
+               }
+               ret = fprintf(out, "\n");
+               if (ret < 0)
+                       return PFI_EFILE;
+       }
+       ret = fprintf(out, "\n");
+       if (ret < 0)
+               return PFI_EFILE;
+
+       ret = fflush(out);
+       if (ret != 0)
+               return PFI_EFILE;
+
+       return 0;
+}
+
+int pfi_header_read (FILE *in, pfi_header head)
+{
+       char magic[PFI_MAGIC_LEN];
+       char mode[PFI_KEYWORD_LEN];
+       char buf[256];
+
+       if (PFI_MAGIC_LEN != fread(magic, 1, PFI_MAGIC_LEN, in))
+               return PFI_EFILE;
+       if (memcmp(magic, PFI_MAGIC, PFI_MAGIC_LEN) != 0)  {
+               if (memcmp(magic, PFI_DATA, PFI_MAGIC_LEN) == 0) {
+                       return PFI_DATA_START;
+               }
+               return PFI_ENOHEADER;
+       }
+
+       while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') {
+               char *value;
+               char *end;
+               value = strchr(buf, '=');
+               if (value == NULL)
+                       return PFI_ENOHEADER;
+
+               *value = '\0';
+               value++;
+               end = strchr(value, '\n');
+               if (end)
+                      *end = '\0';
+
+               if (pfi_header_setvalue(head, buf, value))
+                       return PFI_ENOHEADER;
+       }
+
+       if (check_valid(head) != 0)
+               return PFI_ENOHEADER;
+
+       /* set current mode no. in head */
+       pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN);
+       if (head->mode_no > get_mode_no(mode)) {
+               return PFI_EMODE;
+       }
+       head->mode_no = get_mode_no(mode);
+       return 0;
+}
+
+int pfi_header_dump (FILE *out, pfi_header head __attribute__((__unused__)))
+{
+       fprintf(out, "Sorry not implemented yet. Write mail to "
+               "Andreas Arnez and complain!\n");
+       return 0;
+}
+
+int pfi_read (FILE *in, pfi_read_func func, void *priv_data)
+{
+       int rc;
+       pfi_header header;
+
+       rc = pfi_header_init (&header);
+       if (0 != rc)
+               return rc;
+       if (!func)
+               return PFI_EINVAL;
+
+       while ((0 == rc) && !feof(in)) {
+               /*
+                * Read header and check consistency of the fields.
+                */
+               rc = pfi_header_read( in, header );
+               if (0 != rc)
+                       break;
+               if (func) {
+                       rc = func(in, header, priv_data);
+                       if (rc != 0)
+                               break;
+               }
+       }
+
+       pfi_header_destroy(&header);
+       return rc;
+}
diff --git a/ubi-utils/sort-me-out/pfi.h b/ubi-utils/sort-me-out/pfi.h
new file mode 100644 (file)
index 0000000..8c5cc07
--- /dev/null
@@ -0,0 +1,244 @@
+#ifndef __pfi_h
+#define __pfi_h
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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 pfi.h
+ *
+ * @author Oliver Lohmann <oliloh@de.ibm.com>
+ *         Andreas Arnez <arnez@de.ibm.com>
+ *         Joern Engel <engeljoe@de.ibm.com>
+ *         Frank Haverkamp <haverkam@de.ibm.com>
+ *
+ * @brief libpfi will hold all code to create and process pfi
+ * images. Definitions made in this file are equaly usable for the
+ * development host and the target system.
+ *
+ * @note This header additionally holds the official definitions for
+ * the pfi headers.
+ */
+
+#include <stdio.h>             /* FILE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Definitions. */
+
+#define PFI_HDRVERSION 1       /* current header version */
+
+#define PFI_ENOVERSION 1       /* unknown version */
+#define PFI_ENOHEADER  2       /* not a pfi header */
+#define PFI_EINSUFF    3       /* insufficient information */
+#define PFI_EUNDEF     4       /* key not defined */
+#define PFI_ENOMEM     5       /* out of memory */
+#define PFI_EBADTYPE   6       /* bad data type */
+#define PFI_EFILE      7       /* file I/O error: see errno */
+#define PFI_EFILEINVAL 8       /* file format not valid */
+#define PFI_EINVAL     9       /* invalid parameter */
+#define PFI_ERANGE     10      /* invalid range */
+#define PFI_EMODE      11      /* expecting other mode in this header */
+#define PFI_DATA_START 12      /* data section starts */
+#define PFI_EMAX       13      /* should be always larger as the largest
+                                  error code */
+
+#define PFI_LABEL_LEN  64      /* This is the maximum length for a
+                                  PFI header label */
+#define PFI_KEYWORD_LEN 32     /* This is the maximum length for an
+                                  entry in the mode and type fields */
+
+#define PFI_UBI_MAX_VOLUMES 128
+#define PFI_UBI_VOL_NAME_LEN 127
+
+/**
+ * @brief The pfi header allows to set flags which influence the flashing
+ * behaviour.
+ */
+#define PFI_FLAG_PROTECTED   0x00000001
+
+
+/**
+ * @brief Handle to pfi header. Used in most of the functions associated
+ * with pfi file handling.
+ */
+typedef struct pfi_header *pfi_header;
+
+
+/**
+ * @brief Initialize a pfi header object.
+ *
+ * @param head  Pointer to handle. This function allocates memory
+ *              for this data structure.
+ * @return      0 on success, otherwise:
+ *              PFI_ENOMEM : no memory available for the handle.
+ */
+int pfi_header_init (pfi_header *head);
+
+
+/**
+ * @brief Destroy a pfi header object.
+ *
+ * @param head  handle. head is invalid after calling this function.
+ * @return      0 always.
+ */
+int pfi_header_destroy (pfi_header *head);
+
+
+/**
+ * @brief Add a key/value pair to a pfi header object.
+ *
+ * @param head  handle.
+ * @param key   pointer to key string. Must be 0 terminated.
+ * @param value         pointer to value string. Must be 0 terminated.
+ * @return      0 on success, otherwise:
+ *              PFI_EUNDEF   : key was not found.
+ *              PFI_ENOMEM   : no memory available for the handle.
+ *              PFI_EBADTYPE : value is not an hex string. This happens
+ *                              when the key stores an integer and the
+ *                              new value is not convertable e.g. not in
+ *                              0xXXXXXXXX format.
+ */
+int pfi_header_setvalue (pfi_header head,
+                         const char *key, const char *value);
+
+
+/**
+ * @brief Add a key/value pair to a pfi header object. Provide the
+ * value as a number.
+ *
+ * @param head  handle.
+ * @param key   pointer to key string. Must be 0 terminated.
+ * @param value         value to set.
+ * @return      0 on success, otherwise:
+ *              PFI_EUNDEF   : key was not found.
+ *              PFI_EBADTYPE : value is not a string. This happens
+ *                              when the key stores a string.
+ */
+int pfi_header_setnumber (pfi_header head,
+                          const char *key, uint32_t value);
+
+
+/**
+ * @brief For a given key, return the numerical value stored in a
+ * pfi header object.
+ *
+ * @param head  handle.
+ * @param key   pointer to key string. Must be 0 terminated.
+ * @param value         pointer to value.
+ * @return      0 on success, otherwise:
+ *              PFI_EUNDEF   : key was not found.
+ *              PFI_EBADTYPE : stored value is not an integer but a string.
+ */
+int pfi_header_getnumber (pfi_header head,
+                          const char *key, uint32_t *value);
+
+
+static inline uint32_t
+pfi_getnumber(pfi_header head, const char *key)
+{
+       uint32_t value;
+       pfi_header_getnumber(head, key, &value);
+       return value;
+}
+
+/**
+ * @brief For a given key, return the string value stored in a pfi
+ * header object.
+ *
+ * @param head  handle.
+ * @param key   pointer to key string. Must be 0 terminated.
+ * @param value         pointer to value string. Memory must be allocated by the user.
+ * @return      0 on success, otherwise:
+ *              PFI_EUNDEF   : key was not found.
+ *              PFI_EBADTYPE : stored value is not a string but an integer.
+ */
+int pfi_header_getstring (pfi_header head,
+                          const char *key, char *value, size_t size);
+
+
+/**
+ * @brief Write a pfi header object into a given file.
+ *
+ * @param out   output stream.
+ * @param head  handle.
+ * @return      0 on success, error values otherwise:
+ *              PFI_EINSUFF   : not all mandatory fields are filled.
+ *              PFI_ENOHEADER : wrong header version or magic number.
+ *              -E*            : see <asm/errno.h>.
+ */
+int pfi_header_write (FILE *out, pfi_header head);
+
+
+/**
+ * @brief Read a pfi header object from a given file.
+ *
+ * @param in    input stream.
+ * @param head  handle.
+ * @return      0 on success, error values otherwise:
+ *              PFI_ENOVERSION: unknown header version.
+ *              PFI_EFILE     : cannot read enough data.
+ *              PFI_ENOHEADER : wrong header version or magic number.
+ *              -E*            : see <asm/errno.h>.
+ *
+ * If the header verification returned success the user can assume that
+ * all mandatory fields for a particular version are accessible. Checking
+ * the return code when calling the get-function for those keys is not
+ * required in those cases. For optional fields the checking must still be
+ * done.
+ */
+int pfi_header_read (FILE *in, pfi_header head);
+
+
+/**
+ * @brief Display a pfi header in human-readable form.
+ *
+ * @param out   output stream.
+ * @param head  handle.
+ * @return      always 0.
+ *
+ * @note Prints out that it is not implemented and whom you should
+ * contact if you need it urgently!.
+ */
+int pfi_header_dump (FILE *out, pfi_header head);
+
+
+/*
+ * @brief       Iterates over a stream of pfi files. The iterator function
+ *              must advance the file pointer in FILE *in to the next pfi
+ *              header. Function exists on feof(in).
+ *
+ * @param in    input file descriptor, must be open and valid.
+ * @param func  iterator function called when pfi header could be
+ *              read and was validated. The function must return 0 on
+ *              success.
+ * @return      See pfi_header_init and pfi_header_read.
+ *              PFI_EINVAL       : func is not valid
+ *              0 ok.
+ */
+typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data);
+
+int pfi_read (FILE *in, pfi_read_func func, void *priv_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __pfi_h */
diff --git a/ubi-utils/sort-me-out/pfiflash.h b/ubi-utils/sort-me-out/pfiflash.h
new file mode 100644 (file)
index 0000000..039705d
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef __PFIFLASH_H__
+#define __PFIFLASH_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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 pfi.h
+ *
+ * @author Oliver Lohmann <oliloh@de.ibm.com>
+ *
+ * @brief The pfiflash library offers an interface for using the
+ * pfiflash * utility.
+ */
+
+#include <stdio.h>             /* FILE */
+
+#define PFIFLASH_MAX_ERR_BUF_SIZE 1024
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum pdd_handling_t
+{
+       PDD_KEEP = 0,
+       PDD_MERGE,
+       PDD_OVERWRITE,
+       PDD_HANDLING_NUM, /* always the last item */
+} pdd_handling_t; /**< Possible PDD handle algorithms. */
+
+/**
+ * @brief Flashes a PFI file to UBI Device 0.
+ * @param complete     [0|1] Do a complete system update.
+ * @param seqnum       Index in a redundant group.
+ * @param compare      [0|1] Compare contents.
+ * @param pdd_handling The PDD handling algorithm.
+ * @param rawdev       Device to use for raw flashing
+ * @param err_buf      An error buffer.
+ * @param err_buf_size Size of the error buffer.
+ */
+int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare,
+               pdd_handling_t pdd_handling, const char* rawdev,
+               char *err_buf, size_t err_buf_size);
+
+/**
+ * @brief Flashes a PFI file to UBI Device 0.
+ * @param complete     [0|1] Do a complete system update.
+ * @param seqnum       Index in a redundant group.
+ * @param pdd_handling The PDD handling algorithm.
+ * @param err_buf      An error buffer.
+ * @param err_buf_size Size of the error buffer.
+ */
+int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
+               char *err_buf, size_t err_buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PFIFLASH_H__ */
diff --git a/ubi-utils/sort-me-out/reader.c b/ubi-utils/sort-me-out/reader.c
new file mode 100644 (file)
index 0000000..0ea8c6d
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Read in PFI (partial flash image) data and store it into internal
+ * data structures for further processing. Take also care about
+ * special handling if the data contains PDD (platform description
+ * data/boot-parameters).
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "bootenv.h"
+#include "reader.h"
+
+#define __unused __attribute__((unused))
+
+/* @FIXME hard coded offsets right now - get them from Artem? */
+#define NAND2048_DEFAULT_VID_HDR_OFF 1984
+#define NAND512_DEFAULT_VID_HDR_OFF  448
+#define NOR_DEFAULT_VID_HDR_OFF      64
+
+#define EBUF_PFI(fmt...)                                               \
+       do { int i = snprintf(err_buf, err_buf_size, "%s\n", label);    \
+            snprintf(err_buf + i, err_buf_size - i, fmt);              \
+       } while (0)
+
+#define EBUF(fmt...) \
+       do { snprintf(err_buf, err_buf_size, fmt); } while (0)
+
+
+int
+read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data,
+             char* err_buf, size_t err_buf_size)
+{
+       int rc = 0;
+       bootenv_t pdd = NULL;
+       pdd_data_t res = NULL;
+       const char* value;
+
+       res = (pdd_data_t) malloc(sizeof(struct pdd_data));
+       if (!res) {
+               rc = -ENOMEM;
+               goto err;
+       }
+       rc = bootenv_create(&pdd);
+       if (rc != 0) {
+               goto err;
+       }
+       rc = bootenv_read_txt(fp_pdd, pdd);
+       if (rc != 0) {
+               goto err;
+       }
+       rc = bootenv_get(pdd, "flash_type", &value);
+       if (rc != 0) {
+               goto err;
+       }
+
+       if (strcmp(value, "NAND") == 0) {
+
+               rc = bootenv_get_num(pdd, "flash_page_size",
+                            &(res->flash_page_size));
+               if (rc != 0) {
+                       EBUF("Cannot read 'flash_page_size' from pdd.");
+                       goto err;
+               }
+               res->flash_type = NAND_FLASH;
+
+               switch (res->flash_page_size) {
+               case 512:
+                       res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF;
+                       break;
+               case 2048:
+                       res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF;
+                       break;
+               default:
+                       EBUF("Unsupported  'flash_page_size' %d.",
+                            res->flash_page_size);
+                       goto err;
+               }
+       }
+       else if (strcmp(value, "NOR") == 0){
+               res->flash_type = NOR_FLASH;
+               res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF;
+       }
+       else {
+               snprintf(err_buf, err_buf_size,
+                        "Unkown flash type: %s", value);
+               goto err;
+       }
+
+       rc = bootenv_get_num(pdd, "flash_eraseblock_size",
+                            &(res->eb_size));
+       if (rc != 0) {
+               EBUF("Cannot read 'flash_eraseblock_size' from pdd.");
+               goto err;
+       }
+
+       rc = bootenv_get_num(pdd, "flash_size",
+                            &(res->flash_size));
+       if (rc != 0) {
+               EBUF("Cannot read 'flash_size' from pdd.");
+               goto err;
+       }
+
+       goto out;
+ err:
+       if (res) {
+               free(res);
+               res = NULL;
+       }
+ out:
+       bootenv_destroy(&pdd);
+       *pdd_data = res;
+       return rc;
+}
+
+int
+read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw,
+            const char* label, char* err_buf, size_t err_buf_size)
+{
+       int rc = 0;
+       char tmp_str[PFI_KEYWORD_LEN];
+       bootenv_list_t raw_start_list = NULL;
+       pfi_raw_t res;
+       size_t size;
+
+       res = (pfi_raw_t) malloc(sizeof(struct pfi_raw));
+       if (!res)
+               return -ENOMEM;
+
+       rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'size' from PFI.");
+               goto err;
+       }
+
+       rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'crc' from PFI.");
+               goto err;
+       }
+
+       rc = pfi_header_getstring(pfi_hd, "raw_starts",
+                                 tmp_str, PFI_KEYWORD_LEN);
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'raw_starts' from PFI.");
+               goto err;
+       }
+
+       rc = bootenv_list_create(&raw_start_list);
+       if (rc != 0) {
+               goto err;
+       }
+
+       rc = bootenv_list_import(raw_start_list, tmp_str);
+       if (rc != 0) {
+               EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
+               goto err;
+       }
+
+       rc = bootenv_list_to_num_vector(raw_start_list,
+                                       &size, &(res->starts));
+       res->starts_size = size;
+
+       if (rc != 0) {
+               EBUF_PFI("Cannot create numeric value array: %s", tmp_str);
+               goto err;
+       }
+
+       goto out;
+
+ err:
+       if (res) {
+               free(res);
+               res = NULL;
+       }
+ out:
+       bootenv_list_destroy(&raw_start_list);
+       *pfi_raw = res;
+       return rc;
+}
+
+int
+read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi,
+            const char *label, char* err_buf, size_t err_buf_size)
+{
+       int rc = 0;
+       const char** tmp_names = NULL;
+       char tmp_str[PFI_KEYWORD_LEN];
+       bootenv_list_t ubi_id_list = NULL;
+       bootenv_list_t ubi_name_list = NULL;
+       pfi_ubi_t res;
+       uint32_t i;
+       size_t size;
+
+       res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi));
+       if (!res)
+               return -ENOMEM;
+
+       rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'size' from PFI.");
+               goto err;
+       }
+
+       rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'crc' from PFI.");
+               goto err;
+       }
+
+       rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN);
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'ubi_ids' from PFI.");
+               goto err;
+       }
+
+       rc = bootenv_list_create(&ubi_id_list);
+       if (rc != 0) {
+               goto err;
+       }
+       rc = bootenv_list_create(&ubi_name_list);
+       if (rc != 0) {
+               goto err;
+       }
+
+       rc = bootenv_list_import(ubi_id_list, tmp_str);
+       if (rc != 0) {
+               EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
+               goto err;
+       }
+
+       rc = bootenv_list_to_num_vector(ubi_id_list, &size,
+                                       &(res->ids));
+       res->ids_size = size;
+       if (rc != 0) {
+               EBUF_PFI("Cannot create numeric value array: %s", tmp_str);
+               goto err;
+       }
+
+       if (res->ids_size == 0) {
+               rc = -1;
+               EBUF_PFI("Sanity check failed: No ubi_ids specified.");
+               goto err;
+       }
+
+       rc = pfi_header_getstring(pfi_hd, "ubi_type",
+                                 tmp_str, PFI_KEYWORD_LEN);
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'ubi_type' from PFI.");
+               goto err;
+       }
+       if (strcmp(tmp_str, "static") == 0)
+               res->type = pfi_ubi_static;
+       else if (strcmp(tmp_str, "dynamic") == 0)
+               res->type = pfi_ubi_dynamic;
+       else {
+               EBUF_PFI("Unknown ubi_type in PFI.");
+               goto err;
+       }
+
+       rc = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'ubi_alignment' from PFI.");
+               goto err;
+       }
+
+       rc = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size));
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'ubi_size' from PFI.");
+               goto err;
+       }
+
+       rc = pfi_header_getstring(pfi_hd, "ubi_names",
+                                 tmp_str, PFI_KEYWORD_LEN);
+       if (rc != 0) {
+               EBUF_PFI("Cannot read 'ubi_names' from PFI.");
+               goto err;
+       }
+
+       rc = bootenv_list_import(ubi_name_list, tmp_str);
+       if (rc != 0) {
+               EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
+               goto err;
+       }
+       rc = bootenv_list_to_vector(ubi_name_list, &size,
+                                   &(tmp_names));
+       res->names_size = size;
+       if (rc != 0) {
+               EBUF_PFI("Cannot create string array: %s", tmp_str);
+               goto err;
+       }
+
+       if (res->names_size != res->ids_size) {
+               EBUF_PFI("Sanity check failed: ubi_ids list does not match "
+                        "sizeof ubi_names list.");
+               rc = -1;
+       }
+
+       /* copy tmp_names to own structure */
+       res->names = (char**) calloc(1, res->names_size * sizeof (char*));
+       if (res->names == NULL)
+               goto err;
+
+       for (i = 0; i < res->names_size; i++) {
+               res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char));
+               if (res->names[i] == NULL)
+                       goto err;
+               strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1);
+       }
+
+       goto out;
+
+ err:
+       if (res) {
+               if (res->names) {
+                       for (i = 0; i < res->names_size; i++) {
+                               if (res->names[i]) {
+                                       free(res->names[i]);
+                               }
+                       }
+                       free(res->names);
+               }
+               if (res->ids) {
+                       free(res->ids);
+               }
+               free(res);
+               res = NULL;
+       }
+
+ out:
+       bootenv_list_destroy(&ubi_id_list);
+       bootenv_list_destroy(&ubi_name_list);
+       if (tmp_names != NULL)
+               free(tmp_names);
+       *pfi_ubi = res;
+       return rc;
+}
+
+
+int
+free_pdd_data(pdd_data_t* pdd_data)
+{
+       if (*pdd_data) {
+               free(*pdd_data);
+       }
+       *pdd_data = NULL;
+
+       return 0;
+}
+
+int
+free_pfi_raw(pfi_raw_t* pfi_raw)
+{
+       pfi_raw_t tmp = *pfi_raw;
+       if (tmp) {
+               if (tmp->starts)
+                       free(tmp->starts);
+               free(tmp);
+       }
+       *pfi_raw = NULL;
+
+       return 0;
+}
+
+int
+free_pfi_ubi(pfi_ubi_t* pfi_ubi)
+{
+       size_t i;
+       pfi_ubi_t tmp = *pfi_ubi;
+       if (tmp) {
+               if (tmp->ids)
+                       free(tmp->ids);
+               if (tmp->names) {
+                       for (i = 0; i < tmp->names_size; i++) {
+                               if (tmp->names[i]) {
+                                       free(tmp->names[i]);
+                               }
+                       }
+                       free(tmp->names);
+               }
+               free(tmp);
+       }
+       *pfi_ubi = NULL;
+
+       return 0;
+}
+
+
+int
+read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi,
+                char* err_buf, size_t err_buf_size)
+{
+       int rc = 0;
+       char mode[PFI_KEYWORD_LEN];
+       char label[PFI_LABEL_LEN];
+
+       *pfi_raws = mk_empty(); pfi_raw_t raw = NULL;
+       *pfi_ubis = mk_empty(); pfi_ubi_t ubi = NULL;
+       pfi_header pfi_header = NULL;
+
+       /* read all headers from PFI and store them in lists */
+       rc = pfi_header_init(&pfi_header);
+       if (rc != 0) {
+               EBUF("Cannot initialize pfi header.");
+               goto err;
+       }
+       while ((rc == 0) && !feof(fp_pfi)) {
+               rc = pfi_header_read(fp_pfi, pfi_header);
+               if (rc != 0) {
+                       if (rc == PFI_DATA_START) {
+                               rc = 0;
+                               break; /* data section starts,
+                                         all headers read */
+                       }
+                       else {
+                               goto err;
+                       }
+               }
+               rc = pfi_header_getstring(pfi_header, "label", label,
+                                         PFI_LABEL_LEN);
+               if (rc != 0) {
+                       EBUF("Cannot read 'label' from PFI.");
+                       goto err;
+               }
+               rc = pfi_header_getstring(pfi_header, "mode", mode,
+                                         PFI_KEYWORD_LEN);
+               if (rc != 0) {
+                       EBUF("Cannot read 'mode' from PFI.");
+                       goto err;
+               }
+               if (strcmp(mode, "ubi") == 0) {
+                       rc = read_pfi_ubi(pfi_header, fp_pfi, &ubi, label,
+                                         err_buf, err_buf_size);
+                       if (rc != 0) {
+                               goto err;
+                       }
+                       *pfi_ubis = append_elem(ubi, *pfi_ubis);
+               }
+               else if (strcmp(mode, "raw") == 0) {
+                       rc = read_pfi_raw(pfi_header, fp_pfi, &raw, label,
+                                         err_buf, err_buf_size);
+                       if (rc != 0) {
+                               goto err;
+                       }
+                       *pfi_raws = append_elem(raw, *pfi_raws);
+               }
+               else {
+                       EBUF("Recvieved unknown mode from PFI: %s", mode);
+                       goto err;
+               }
+       }
+       goto out;
+
+ err:
+       *pfi_raws = remove_all((free_func_t)&free_pfi_raw, *pfi_raws);
+       *pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, *pfi_ubis);
+ out:
+       pfi_header_destroy(&pfi_header);
+       return rc;
+
+}
diff --git a/ubi-utils/sort-me-out/reader.h b/ubi-utils/sort-me-out/reader.h
new file mode 100644 (file)
index 0000000..715e464
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef __READER_H__
+#define __READER_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * 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.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Read Platform Description Data (PDD).
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "pfi.h"
+#include "bootenv.h"
+#include "list.h"
+
+typedef enum flash_type_t {
+       NAND_FLASH = 0,
+       NOR_FLASH,
+} flash_type_t;
+
+typedef struct pdd_data *pdd_data_t;
+typedef struct pfi_raw *pfi_raw_t;
+typedef struct pfi_ubi *pfi_ubi_t;
+
+struct pdd_data {
+       uint32_t flash_size;
+       uint32_t flash_page_size;
+       uint32_t eb_size;
+       uint32_t vid_hdr_offset;
+       flash_type_t flash_type;
+};
+
+struct pfi_raw {
+       uint32_t data_size;
+       uint32_t *starts;
+       uint32_t starts_size;
+       uint32_t crc;
+};
+
+struct pfi_ubi {
+       uint32_t data_size;
+       uint32_t alignment;
+       uint32_t *ids;
+       uint32_t ids_size;
+       char     **names;
+       uint32_t names_size;
+       uint32_t size;
+       enum { pfi_ubi_dynamic, pfi_ubi_static } type;
+       int curr_seqnum; /* specifies the seqnum taken in an update,
+                           default: 0 (used by pfiflash, ubimirror) */
+       uint32_t crc;
+};
+
+int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data,
+               char *err_buf, size_t err_buf_size);
+int read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi, pfi_raw_t *pfi_raw,
+               const char *label, char *err_buf, size_t err_buf_size);
+int read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi, pfi_ubi_t *pfi_ubi,
+               const char *label, char *err_buf, size_t err_buf_size);
+
+/**
+ * @brief Reads all pfi headers into list structures, separated by
+ *       RAW and UBI sections.
+ */
+int read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi,
+               char* err_buf, size_t err_buf_size);
+int free_pdd_data(pdd_data_t *pdd_data);
+int free_pfi_raw(pfi_raw_t *raw_pfi);
+int free_pfi_ubi(pfi_ubi_t *pfi_ubi);
+
+#endif /* __READER_H__ */