summaryrefslogtreecommitdiffstats
path: root/fpart/src
diff options
context:
space:
mode:
Diffstat (limited to 'fpart/src')
-rw-r--r--fpart/src/cmd_add.c102
-rw-r--r--fpart/src/cmd_compare.c231
-rw-r--r--fpart/src/cmd_copy.c282
-rw-r--r--fpart/src/cmd_create.c113
-rw-r--r--fpart/src/cmd_delete.c78
-rw-r--r--fpart/src/cmd_erase.c206
-rw-r--r--fpart/src/cmd_hexdump.c153
-rw-r--r--fpart/src/cmd_list.c168
-rw-r--r--fpart/src/cmd_read.c166
-rw-r--r--fpart/src/cmd_trunc.c134
-rw-r--r--fpart/src/cmd_user.c156
-rw-r--r--fpart/src/cmd_write.c229
-rw-r--r--fpart/src/command.c296
-rw-r--r--fpart/src/main.c597
-rw-r--r--fpart/src/main.h125
15 files changed, 3036 insertions, 0 deletions
diff --git a/fpart/src/cmd_add.c b/fpart/src/cmd_add.c
new file mode 100644
index 0000000..342df05
--- /dev/null
+++ b/fpart/src/cmd_add.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: add.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --add implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/exception.h>
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_add(args_t * args)
+{
+ assert(args != NULL);
+
+ /* ========================= */
+
+ int add(args_t * args, off_t poffset)
+ {
+ int rc = 0;
+
+ off_t offset = 0;
+ size_t size = 0;
+ uint32_t flags = 0;
+
+ rc = parse_offset(args->offset, &offset);
+ if (rc < 0)
+ return rc;
+ rc = parse_size(args->size, &size);
+ if (rc < 0)
+ return rc;
+ rc = parse_size(args->flags, &flags);
+ if (rc < 0)
+ return rc;
+
+ ffs_type_t type = FFS_TYPE_DATA;
+ if (args->logical == f_LOGICAL)
+ type = FFS_TYPE_LOGICAL;
+
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE *, file, fopen_generic(target, "r+", debug), fclose);
+ RAII(ffs_t *, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+
+ rc = __ffs_entry_add(ffs, args->name, offset, size,
+ type, flags);
+ if (rc < 0)
+ return rc;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: add partition at offset '%llx' size "
+ "'%x' type '%d' flags '%x'\n", poffset,
+ args->name, offset, size, type, flags);
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ return command(args, add);
+}
diff --git a/fpart/src/cmd_compare.c b/fpart/src/cmd_compare.c
new file mode 100644
index 0000000..95b64d0
--- /dev/null
+++ b/fpart/src/cmd_compare.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: compare.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --compare implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_compare(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ char full_name[page_size];
+ regex_t rx;
+
+ off_t __poffset;
+ ffs_t * __in, * __out;
+
+ list_t list;
+ list_init(&list);
+
+ list_iter_t it;
+ ffs_entry_node_t * node;
+
+ /* ========================= */
+
+ int compare_entry(ffs_entry_t * src)
+ {
+ if (__ffs_entry_name(__in, src, full_name,
+ sizeof full_name) < 0)
+ return -1;
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ if (src->flags & FFS_FLAGS_PROTECTED &&
+ args->force != f_FORCE) {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: protected, skipping "
+ "compare\n", __poffset, full_name);
+ return 0;
+ }
+
+ list_iter_init(&it, &list, LI_FLAG_FWD);
+ list_for_each(&it, node, node) {
+ if (node->entry.base == src->base &&
+ node->entry.size == src->size)
+ return 0;
+ }
+
+ node = (ffs_entry_node_t *)malloc(sizeof(*node));
+ assert(node != NULL);
+
+ memcpy(&node->entry, src, sizeof(node->entry));
+ list_add_tail(&list, &node->node);
+
+ ffs_entry_t dst;
+ if (__ffs_entry_find(__out, full_name, &dst) == false) {
+ UNEXPECTED("'%s' entry not found '%s'",
+ args->target, args->name);
+ return -1;
+ }
+
+ if (verify_operation(full_name, __in, src, __out, &dst) < 0)
+ return -1;
+
+ size_t block_size = __in->hdr->block_size;
+
+ if (args->block != NULL) {
+ if (parse_size(args->block, &block_size) < 0)
+ return -1;
+ if (block_size & (__in->hdr->block_size-1)) {
+ UNEXPECTED("'%x' block size must be multiple "
+ "of target block size '%x'",
+ block_size, __in->hdr->block_size);
+ return -1;
+ }
+ }
+
+ if (__ffs_buffer(__in, block_size) < 0)
+ return -1;
+ if (__ffs_buffer(__out, block_size) < 0)
+ return -1;
+
+ RAII(void*, src_block, malloc(block_size), free);
+ if (src_block == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+ RAII(void*, dst_block, malloc(block_size), free);
+ if (dst_block == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ size_t data_size = src->actual;
+ off_t data_offset = 0;
+
+ while (0 < data_size) {
+ ssize_t rc;
+
+ rc = __ffs_entry_read(__in, full_name, src_block,
+ data_offset,
+ min(block_size, data_size));
+ if (rc < 0)
+ return -1;
+
+ rc = __ffs_entry_read(__out, full_name, dst_block,
+ data_offset, rc);
+ if (rc < 0)
+ return -1;
+
+ if (memcmp(src_block, dst_block, block_size) != 0) {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: miscompare at offset"
+ "'%llx'\n", __poffset, full_name,
+ data_offset);
+ UNEXPECTED("data miscompare at offset range "
+ "[%llx..%llx]", data_offset,
+ data_offset + block_size - 1);
+ return -1;
+ }
+
+
+ data_offset += rc;
+ data_size -= rc;
+ }
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: compare to '%s'\n", __poffset,
+ full_name, args->path);
+
+ return 0;
+ }
+
+ int compare(args_t * args, off_t poffset)
+ {
+ __poffset = poffset;
+
+ const char * path = args->path;
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, inf, fopen_generic(path, "r", debug), fclose);
+ if (inf == NULL)
+ return -1;
+ RAII(FILE*, outf, fopen_generic(target, "r", debug), fclose);
+ if (outf == NULL)
+ return -1;
+
+ RAII(ffs_t*, in, __ffs_fopen(inf, poffset), __ffs_fclose);
+ if (in == NULL)
+ return -1;
+ RAII(ffs_t*, out, __ffs_fopen(outf, poffset), __ffs_fclose);
+ if (out == NULL)
+ return -1;
+
+ __in = in;
+ __out = out;
+
+ int rc = __ffs_iterate_entries(in, compare_entry);
+ if (rc == 1)
+ rc = -1;
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ int rc = command(args, compare);
+
+ regfree(&rx);
+
+ while (!list_empty(&list))
+ free(container_of(list_remove_head(&list),
+ ffs_entry_node_t, node));
+
+ return rc;
+}
diff --git a/fpart/src/cmd_copy.c b/fpart/src/cmd_copy.c
new file mode 100644
index 0000000..9bbb8bf
--- /dev/null
+++ b/fpart/src/cmd_copy.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: copy.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --copy implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_copy(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ char full_name[page_size];
+ regex_t rx;
+
+ ffs_t *__in, *__out;
+ off_t __poffset;
+
+ list_t list;
+ list_init(&list);
+
+ list_iter_t it;
+ ffs_entry_node_t * node;
+
+ /* ========================= */
+
+ int copy_entry(ffs_entry_t * src)
+ {
+ if (__ffs_entry_name(__in, src, full_name, sizeof full_name)< 0)
+ return -1;
+
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ if (src->flags & FFS_FLAGS_PROTECTED &&
+ args->force != f_FORCE) {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: protected, skipping copy\n",
+ __poffset, full_name);
+ return 0;
+ }
+
+ __ffs_entry_truncate(__out, full_name, src->actual);
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: truncate size '%x'\n",
+ __poffset, full_name, src->actual);
+
+ uint32_t src_val, dst_val;
+ for (uint32_t i=0; i<FFS_USER_WORDS; i++) {
+ __ffs_entry_user_get(__in, full_name, i, &src_val);
+ __ffs_entry_user_get(__out, full_name, i, &dst_val);
+ if (src_val != dst_val)
+ if (__ffs_entry_user_put(__out, full_name,
+ i, src_val) < 0)
+ return -1;
+ }
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: user[] copy from '%s'\n", __poffset,
+ full_name, args->path);
+
+ list_iter_init(&it, &list, LI_FLAG_FWD);
+ list_for_each(&it, node, node) {
+ ffs_entry_t * e = &node->entry;
+ if (e->base == src->base && e->size == src->size) {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: skipping copy from "
+ "'%s'\n", __poffset, full_name,
+ args->path);
+ return 0;
+ }
+ }
+
+ node = (ffs_entry_node_t *)malloc(sizeof(*node));
+ assert(node != NULL);
+
+ memcpy(&node->entry, src, sizeof(node->entry));
+ list_add_tail(&list, &node->node);
+
+ ffs_entry_t dst;
+ if (__ffs_entry_find(__out, full_name, &dst) == false) {
+ UNEXPECTED("'%s' entry not found '%s'",
+ args->target, args->name);
+ return -1;
+ }
+
+ if (verify_operation(full_name, __in, src, __out, &dst) < 0)
+ return -1;
+
+ size_t block_size = __in->hdr->block_size;
+
+ if (args->block != NULL) {
+ if (parse_size(args->block, &block_size) < 0)
+ return -1;
+ if (block_size & (__in->hdr->block_size-1)) {
+ UNEXPECTED("'%x' block size must be multiple "
+ "of target block size '%x'",
+ block_size, __in->hdr->block_size);
+ return -1;
+ }
+ }
+
+ if (__ffs_buffer(__in, block_size) < 0)
+ return -1;
+ if (__ffs_buffer(__out, block_size) < 0)
+ return -1;
+
+ RAII(void*, block, malloc(block_size), free);
+ if (block == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ size_t data_size = src->actual;
+ off_t data_offset = 0;
+
+ while (0 < data_size) {
+ ssize_t rc;
+
+ rc = __ffs_entry_read(__in, full_name, block,
+ data_offset,
+ min(block_size, data_size));
+ if (rc < 0)
+ return -1;
+
+ rc = __ffs_entry_write(__out, full_name, block,
+ data_offset, rc);
+ if (rc < 0)
+ return -1;
+
+ data_offset += rc;
+ data_size -= rc;
+ }
+
+ __ffs_fsync(__out);
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: copy from '%s'\n", __poffset,
+ full_name, args->path);
+
+ return 0;
+ }
+
+ int copy(args_t * args, off_t poffset)
+ {
+ __poffset = poffset;
+
+ const char * path = args->path;
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, inf, fopen_generic(path, "r", debug), fclose);
+ if (inf == NULL)
+ return -1;
+
+ RAII(ffs_t*, in, __ffs_fopen(inf, poffset), __ffs_fclose);
+ if (in == NULL)
+ return -1;
+
+ if (args->force == f_FORCE) {
+ size_t block_size = in->hdr->block_size;
+ char block[block_size];
+
+ size_t rc;
+ rc = __ffs_entry_read(in, FFS_PARTITION_NAME, block,
+ 0, block_size);
+ if (rc != block_size) {
+ UNEXPECTED("'%s' unable to read '%s' from "
+ "offset '%llx'", args->path,
+ FFS_PARTITION_NAME, poffset);
+ return -1;
+ }
+
+ RAII(FILE*, outf,
+ fopen_generic(target, "r+", debug), fclose);
+ if (outf == NULL)
+ return -1;
+
+ if (fseeko(outf, poffset, SEEK_SET) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ rc = fwrite(block, 1, block_size, outf);
+ if (rc <= 0) {
+ if (ferror(outf)) {
+ ERRNO(errno);
+ return -1;
+ }
+ }
+
+ fflush(outf);
+ if (fileno(outf) != -1)
+ fsync(fileno(outf));
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: force partition table\n",
+ poffset, FFS_PARTITION_NAME);
+ }
+
+ RAII(FILE*, outf, fopen_generic(target, "r+", debug), fclose);
+ if (outf == NULL)
+ return -1;
+ RAII(ffs_t*, out, __ffs_fopen(outf, poffset), __ffs_fclose);
+ if (in == NULL)
+ return -1;
+
+ __in = in;
+ __out = out;
+
+ int rc = __ffs_iterate_entries(in, copy_entry);
+ if (rc == 1)
+ rc = -1;
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ int rc = command(args, copy);
+
+ regfree(&rx);
+
+ while (!list_empty(&list))
+ free(container_of(list_remove_head(&list),
+ ffs_entry_node_t, node));
+
+ return rc;
+}
diff --git a/fpart/src/cmd_create.c b/fpart/src/cmd_create.c
new file mode 100644
index 0000000..f7448ec
--- /dev/null
+++ b/fpart/src/cmd_create.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: create.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --create implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_create(args_t * args)
+{
+ assert(args != NULL);
+
+ size_t block = 0;
+ size_t size = 0;
+ size_t pad = 0xff;
+
+ if (parse_size(args->block, &block) < 0)
+ return -1;
+ if (parse_size(args->size, &size) < 0)
+ return -1;
+ if (args->pad != NULL)
+ if (parse_size(args->pad, &pad) < 0)
+ return -1;
+
+ struct stat st;
+ if (stat(args->target, &st) < 0) {
+ if (errno == ENOENT) {
+ create_regular_file(args->target, size, (uint8_t)pad);
+ } else {
+ ERRNO(errno);
+ return -1;
+ }
+ } else {
+ if (st.st_size != size) {
+ create_regular_file(args->target, size, (uint8_t)pad);
+ } else {
+ if (args->force != f_FORCE && st.st_size != size) {
+ UNEXPECTED("--size '%d' differs from actual "
+ "size '%lld', use --force to "
+ "override", size, st.st_size);
+ return -1;
+ }
+ }
+ }
+
+ /* ========================= */
+
+ int create(args_t * args, off_t poffset)
+ {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: create partition table\n", poffset);
+
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r+", debug), fclose);
+ if (file == NULL)
+ return -1;
+ RAII(ffs_t*, ffs, __ffs_fcreate(file, poffset, block,
+ size / block), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ return 0;
+ }
+
+ /* ========================= */
+
+ return command(args, create);
+}
diff --git a/fpart/src/cmd_delete.c b/fpart/src/cmd_delete.c
new file mode 100644
index 0000000..26033da
--- /dev/null
+++ b/fpart/src/cmd_delete.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: delete.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --delete implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_delete(args_t * args)
+{
+ assert(args != NULL);
+
+ /* ========================= */
+
+ int delete(args_t * args, off_t poffset)
+ {
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r+", debug), fclose);
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+
+ if (__ffs_entry_delete(ffs, args->name) < 0)
+ return -1;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: delete\n", poffset, args->name);
+
+ return 0;
+ }
+
+ /* ========================= */
+
+ return command(args, delete);
+}
diff --git a/fpart/src/cmd_erase.c b/fpart/src/cmd_erase.c
new file mode 100644
index 0000000..aac75fb
--- /dev/null
+++ b/fpart/src/cmd_erase.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: erase.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --erase implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_erase(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ size_t pad = 0xff;
+ if (args->pad != NULL)
+ if (parse_size(args->pad, &pad) < 0)
+ return -1;
+
+ char full_name[page_size];
+ regex_t rx;
+
+ ffs_t * __ffs;
+ off_t __poffset;
+
+ list_t list;
+ list_init(&list);
+
+ list_iter_t it;
+ ffs_entry_node_t * node;
+
+ /* ========================= */
+
+ int erase_entry(ffs_entry_t * entry)
+ {
+ if (__ffs_entry_name(__ffs, entry, full_name,
+ sizeof full_name) < 0)
+ return -1;
+
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ if (entry->flags & FFS_FLAGS_PROTECTED &&
+ args->force != f_FORCE) {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: protected, skipping erase\n",
+ __poffset, full_name);
+ return 0;
+ }
+
+ if (__ffs_entry_truncate(__ffs, full_name, 0) < 0)
+ return -1;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: truncate size '%x'\n", __poffset,
+ full_name, 0);
+
+ for (uint32_t i=0; i<FFS_USER_WORDS; i++)
+ if (__ffs_entry_user_put(__ffs, full_name, i, 0) < 0)
+ return -1;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: user[] zero\n", __poffset, full_name);
+
+ list_iter_init(&it, &list, LI_FLAG_FWD);
+ list_for_each(&it, node, node) {
+ if (node->entry.base == entry->base) {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: skipping fill with "
+ "'%x'\n", __poffset, full_name,
+ (uint8_t)pad);
+ return 0;
+ }
+ }
+
+ node = (ffs_entry_node_t *)malloc(sizeof(*node));
+ assert(node != NULL);
+
+ memcpy(&node->entry, entry, sizeof(node->entry));
+ list_add_tail(&list, &node->node);
+
+ uint32_t block_size = __ffs->hdr->block_size;
+
+ if (args->block != NULL) {
+ if (parse_size(args->block, &block_size) < 0)
+ return -1;
+ if (block_size & (__ffs->hdr->block_size-1)) {
+ UNEXPECTED("'%x' block size must be multiple "
+ "of target block size '%x'",
+ block_size, __ffs->hdr->block_size);
+ return -1;
+ }
+ }
+
+ if (__ffs_buffer(__ffs, block_size) < 0)
+ return -1;
+
+ RAII(void*, block, malloc(block_size), free);
+ if (block == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+ memset(block, pad, block_size);
+
+ for (uint32_t i = 0; i < entry->size; i++)
+ if(__ffs_entry_write(__ffs, full_name, block, i * block_size, block_size) < 0)
+ return -1;
+
+ __ffs_fsync(__ffs);
+
+ if (__ffs_entry_truncate(__ffs, full_name, 0) < 0)
+ return -1;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: filled with '%x'\n", __poffset,
+ full_name, (uint8_t)pad);
+
+ return 0;
+ }
+
+ int erase(args_t * args, off_t poffset)
+ {
+ __poffset = poffset;
+
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r+", debug), fclose);
+ if (file == NULL)
+ return -1;
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ __ffs = ffs;
+
+ int rc = __ffs_iterate_entries(ffs, erase_entry);
+ if (rc == 1)
+ rc = -1;
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ int rc = command(args, erase);
+
+ regfree(&rx);
+
+ while (!list_empty(&list))
+ free(container_of(list_remove_head(&list),
+ ffs_entry_node_t, node));
+
+ return rc;
+}
diff --git a/fpart/src/cmd_hexdump.c b/fpart/src/cmd_hexdump.c
new file mode 100644
index 0000000..1a0086e
--- /dev/null
+++ b/fpart/src/cmd_hexdump.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: hexdump.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --hexdump implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_hexdump(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ char full_name[page_size];
+ regex_t rx;
+
+ off_t __poffset;
+ ffs_t * __ffs;
+
+ list_t list;
+ list_init(&list);
+
+ list_iter_t it;
+ ffs_entry_node_t * node;
+
+ /* ========================= */
+
+ int hexdump_entry(ffs_entry_t * entry)
+ {
+ if (__ffs_entry_name(__ffs, entry, full_name,
+ sizeof full_name) < 0)
+ return -1;
+
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ if (entry->flags & FFS_FLAGS_PROTECTED &&
+ args->force != f_FORCE) {
+ printf("%llx: %s: protected, skipping hexdump\n",
+ __poffset, full_name);
+ return 0;
+ }
+
+ list_iter_init(&it, &list, LI_FLAG_FWD);
+ list_for_each(&it, node, node) {
+ if (node->entry.base == entry->base &&
+ node->entry.size == entry->size)
+ return 0;
+ }
+
+ node = (ffs_entry_node_t *)malloc(sizeof(*node));
+ assert(node != NULL);
+
+ memcpy(&node->entry, entry, sizeof(node->entry));
+ list_add_tail(&list, &node->node);
+
+ if (__ffs_entry_hexdump(__ffs, full_name, stdout) < 0)
+ return -1;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: partition actual '%x'\n",
+ __poffset, full_name, entry->actual);
+
+ return 0;
+ }
+
+ int hexdump(args_t * args, off_t poffset)
+ {
+ __poffset = poffset;
+
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r", debug), fclose);
+ if (file == NULL)
+ return -1;
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ __ffs = ffs;
+
+ int rc = __ffs_iterate_entries(ffs, hexdump_entry);
+ if (rc == 1)
+ rc = -1;
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ int rc = command(args, hexdump);
+
+ regfree(&rx);
+
+ while (!list_empty(&list))
+ free(container_of(list_remove_head(&list),
+ ffs_entry_node_t, node));
+
+ return rc;
+}
diff --git a/fpart/src/cmd_list.c b/fpart/src/cmd_list.c
new file mode 100644
index 0000000..b9a4cbd
--- /dev/null
+++ b/fpart/src/cmd_list.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: list.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --list implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_list(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ ffs_t *__ffs;
+
+ char full_name[page_size];
+ regex_t rx;
+
+ /* ========================= */
+
+ int __list_entry(ffs_entry_t * entry)
+ {
+
+ size_t offset = entry->base * __ffs->hdr->block_size;
+ size_t size = entry->size * __ffs->hdr->block_size;
+
+ if (__ffs_entry_name(__ffs, entry, full_name,
+ sizeof full_name) < 0)
+ return -1;
+
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ char type;
+ if (entry->type == FFS_TYPE_LOGICAL) {
+ type ='l';
+ } else if (entry->type == FFS_TYPE_DATA) {
+ type ='d';
+ } else if (entry->type == FFS_TYPE_PARTITION) {
+ type ='p';
+ }
+ fprintf(stdout, "%3d [%08x-%08x] [%8x:%8x] ",
+ entry->id, offset, offset+size-1,
+ size, entry->actual);
+
+ fprintf(stdout, "[%c%c%c%c%c%c] %s\n",
+ type, '-', '-', '-',
+ entry->flags & FFS_FLAGS_U_BOOT_ENV ? 'b' : '-',
+ entry->flags & FFS_FLAGS_PROTECTED ? 'p' : '-',
+ full_name);
+
+ if (args->verbose == f_VERBOSE) {
+ for (int i=0; i<FFS_USER_WORDS; i++) {
+ fprintf(stdout, "[%2d] %8x ", i,
+ entry->user.data[i]);
+ if ((i+1) % 4 == 0)
+ fprintf(stdout, "\n");
+ }
+ }
+
+ return 0;
+ }
+
+ int list(args_t * args, off_t poffset)
+ {
+ const char * target = args->target;
+ int debug = args->debug;
+ int rc = 0;
+
+ RAII(FILE*, file, fopen_generic(target, "r", debug), fclose);
+ if (file == NULL)
+ return -1;
+
+ if (__ffs_fcheck(file, poffset) < 0)
+ return -1;
+
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ if (0 < ffs->count) {
+ printf("========================[ PARTITION TABLE"
+ " 0x%llx ]=======================\n",
+ ffs->offset);
+ printf("vers:%04x size:%04x * blk:%06x blk(s):"
+ "%06x * entsz:%06x ent(s):%06x\n",
+ ffs->hdr->version,
+ ffs->hdr->size,
+ ffs->hdr->block_size,
+ ffs->hdr->block_count,
+ ffs->hdr->entry_size,
+ ffs->hdr->entry_count);
+ printf("----------------------------------"
+ "----------------------------------"
+ "-------\n");
+
+ __ffs = ffs;
+
+ rc = __ffs_iterate_entries(ffs, __list_entry);
+ if (rc == 1)
+ rc = -1;
+
+ printf("\n");
+ }
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ int rc = command(args, list);
+
+ regfree(&rx);
+
+ return rc;
+}
diff --git a/fpart/src/cmd_read.c b/fpart/src/cmd_read.c
new file mode 100644
index 0000000..e058377
--- /dev/null
+++ b/fpart/src/cmd_read.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: read.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --read implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_read(args_t * args)
+{
+ assert(args != NULL);
+
+ if (access(args->path, F_OK) == 0 && args->force != f_FORCE) {
+ UNEXPECTED("output file '%s' already exists, use --force "
+ "to overwrite\n", args->path);
+ return -1;
+ }
+
+ list_t list;
+ list_init(&list);
+
+ list_iter_t it;
+ ffs_entry_node_t * node;
+
+ /* ========================= */
+
+ int read(args_t * args, off_t poffset)
+ {
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r", debug), fclose);
+ if (file == NULL)
+ return -1;
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ size_t block_size = ffs->hdr->block_size;
+
+ if (args->block != NULL) {
+ if (parse_size(args->block, &block_size) < 0)
+ return -1;
+ if (block_size & (ffs->hdr->block_size-1)) {
+ UNEXPECTED("'%x' block size must be multiple "
+ "of target block size '%x'",
+ block_size, ffs->hdr->block_size);
+ return -1;
+ }
+ }
+
+ if (__ffs_buffer(ffs, block_size) < 0)
+ return -1;
+
+ RAII(void*, block, malloc(block_size), free);
+ if (block == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ ffs_entry_t entry;
+ if (__ffs_entry_find(ffs, args->name, &entry) == false) {
+ UNEXPECTED("'%s' partition not found => %s",
+ args->target, args->name);
+ return -1;
+ }
+
+ list_iter_init(&it, &list, LI_FLAG_FWD);
+ list_for_each(&it, node, node) {
+ if (node->entry.base == entry.base &&
+ node->entry.size == entry.size)
+ return 0;
+ }
+
+ node = (ffs_entry_node_t *)malloc(sizeof(*node));
+ assert(node != NULL);
+
+ memcpy(&node->entry, &entry, sizeof(node->entry));
+ list_add_tail(&list, &node->node);
+
+ RAII(FILE*, out, fopen(args->path, "w+"), fclose);
+ if (out == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ size_t data_size = entry.actual;
+ off_t data_offset = 0;
+
+ while (0 < data_size) {
+ ssize_t rc;
+ rc = __ffs_entry_read(ffs, args->name,
+ block, data_offset,
+ min(block_size, data_size));
+
+ rc = fwrite(block, 1, rc, out);
+ if (rc <= 0 && ferror(out)) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ data_size -= rc;
+ data_offset += rc;
+ }
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: wrote '%x' bytes to file '%s'\n",
+ poffset, args->name, entry.actual, args->path);
+
+ return 0;
+ }
+
+ /* ========================= */
+
+ int rc = command(args, read);
+
+ while (!list_empty(&list))
+ free(container_of(list_remove_head(&list),
+ ffs_entry_node_t, node));
+
+ return rc;
+}
+
diff --git a/fpart/src/cmd_trunc.c b/fpart/src/cmd_trunc.c
new file mode 100644
index 0000000..b946bdc
--- /dev/null
+++ b/fpart/src/cmd_trunc.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: trunc.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --trunc implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_trunc(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ off_t __poffset;
+ ffs_t * __ffs;
+
+ char full_name[page_size];
+ regex_t rx;
+
+ /* ========================= */
+
+ int trunc_entry(ffs_entry_t * entry)
+ {
+ if (__ffs_entry_name(__ffs, entry, full_name,
+ sizeof full_name) < 0)
+ return -1;
+
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ if (entry->flags & FFS_FLAGS_PROTECTED &&
+ args->force != f_FORCE) {
+ printf("%llx: %s: protected, skipping truncate\n",
+ __poffset, full_name);
+ return 0;
+ }
+
+ size_t size = entry->size * __ffs->hdr->block_size;
+ if (args->size != NULL)
+ if (parse_size(args->size, &size) < 0)
+ return -1;
+
+ if (__ffs_entry_truncate(__ffs, full_name, size) < 0)
+ return -1;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: truncate size '%x'\n", __poffset,
+ full_name, size);
+
+ return 0;
+ }
+
+ int trunc(args_t * args, off_t poffset)
+ {
+ __poffset = poffset;
+
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r+", debug), fclose);
+ if (file == NULL)
+ return -1;
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ __ffs = ffs;
+
+ int rc = __ffs_iterate_entries(ffs, trunc_entry);
+ if (rc == 1)
+ return -1;
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ int rc = command(args, trunc);
+
+ regfree(&rx);
+
+ return rc;
+}
diff --git a/fpart/src/cmd_user.c b/fpart/src/cmd_user.c
new file mode 100644
index 0000000..67abc50
--- /dev/null
+++ b/fpart/src/cmd_user.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: user.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --user implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_user(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ char full_name[page_size];
+ regex_t rx;
+
+ off_t __poffset;
+ ffs_t * __ffs;
+
+ uint32_t user = 0;
+ if (args->user != NULL)
+ if (parse_size(args->user, &user) < 0)
+ return -1;
+
+ if (FFS_USER_WORDS <= user) {
+ UNEXPECTED("invalid user word '%d', valid range [0..%d]",
+ user, FFS_USER_WORDS);
+ return -1;
+ }
+
+ int user_entry(ffs_entry_t * entry)
+ {
+ assert(entry != NULL);
+
+ if (__ffs_entry_name(__ffs, entry, full_name,
+ sizeof full_name) < 0)
+ return -1;
+
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ if (entry->flags & FFS_FLAGS_PROTECTED &&
+ args->force != f_FORCE) {
+ printf("%llx: %s: protected, skipping user[%d]\n",
+ __poffset, full_name, user);
+ return 0;
+ }
+
+ uint32_t value = 0;
+ if (args->value != NULL) {
+ if (args->value != NULL)
+ if (parse_size(args->value, &value) < 0)
+ return -1;
+
+ if (__ffs_entry_user_put(__ffs, full_name,
+ user, value) < 0)
+ return -1;
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: user[%d] = '%x'\n", __poffset,
+ args->name, user, value);
+ } else {
+ if (__ffs_entry_user_get(__ffs, args->name,
+ user, &value) < 0)
+ return -1;
+
+ printf("%llx: %s: user[%d] = '%x'\n", __poffset,
+ args->name, user, value);
+ }
+
+ return 0;
+ }
+
+ int __user(args_t * args, off_t poffset)
+ {
+ __poffset = poffset;
+
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r+", debug), fclose);
+ if (file == NULL)
+ return -1;
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ __ffs = ffs;
+
+ int rc = __ffs_iterate_entries(ffs, user_entry);
+ if (rc == 1)
+ return -1;
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return-1;
+ }
+
+ int rc = command(args, __user);
+
+ regfree(&rx);
+
+ return rc;
+}
diff --git a/fpart/src/cmd_write.c b/fpart/src/cmd_write.c
new file mode 100644
index 0000000..83f71d3
--- /dev/null
+++ b/fpart/src/cmd_write.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: write.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: --write implementation
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+int command_write(args_t * args)
+{
+ assert(args != NULL);
+
+ char name[strlen(args->name) + 2];
+ strcpy(name, args->name);
+ if (strrchr(name, '$') == NULL)
+ strcat(name, "$");
+
+ char full_name[page_size];
+ struct stat st;
+ regex_t rx;
+
+ off_t __poffset;
+ ffs_t *__ffs;
+
+ RAII(FILE*, in, fopen(args->path, "r"), fclose);
+
+ list_t list;
+ list_init(&list);
+
+ list_iter_t it;
+ ffs_entry_node_t * node;
+
+ /* ========================= */
+
+ int write_entry(ffs_entry_t * entry)
+ {
+ assert(entry != NULL);
+
+ if (__ffs_entry_name(__ffs, entry, full_name,
+ sizeof full_name) < 0)
+ return -1;
+
+ if (regexec(&rx, full_name, 0, NULL, 0) == REG_NOMATCH)
+ return 0;
+
+ if (entry->flags & FFS_FLAGS_PROTECTED &&
+ args->force != f_FORCE) {
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: protected, skipping write\n",
+ __poffset, full_name);
+ return 0;
+ }
+
+ if (entry->actual < st.st_size) {
+ if (__ffs_entry_truncate(__ffs, full_name,
+ st.st_size) < 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: truncate size '%llx'\n",
+ __poffset, full_name, st.st_size);
+ }
+
+ list_iter_init(&it, &list, LI_FLAG_FWD);
+ list_for_each(&it, node, node) {
+ if (node->entry.base == entry->base &&
+ node->entry.size == entry->size)
+ return 0;
+ }
+
+ node = (ffs_entry_node_t *)malloc(sizeof(*node));
+ assert(node != NULL);
+
+ memcpy(&node->entry, entry, sizeof(node->entry));
+ list_add_tail(&list, &node->node);
+
+ size_t block_size = __ffs->hdr->block_size;
+ size_t entry_size = entry->size * block_size;
+ size_t data_size = st.st_size;
+ off_t data_offset = 0;
+
+ if (entry_size < data_size) {
+ UNEXPECTED("'%s' of size '%x' too big for partition "
+ "'%s' of size '%x'", args->path, data_size,
+ args->name, entry_size);
+ return -1;
+ }
+
+ if (args->block != NULL) {
+ if (parse_size(args->block, &block_size) < 0)
+ return -1;
+ if (block_size & (__ffs->hdr->block_size-1)) {
+ UNEXPECTED("'%x' block size must be multiple "
+ "of target block size '%x'",
+ block_size, __ffs->hdr->block_size);
+ return -1;
+ }
+ }
+
+ if (__ffs_buffer(__ffs, block_size) < 0)
+ return -1;
+
+ RAII(void*, block, malloc(block_size), free);
+ if (block == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ if (fseeko(in, 0, SEEK_SET) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ while (0 < data_size) {
+ ssize_t rc = fread(block, 1,
+ min(block_size, data_size), in);
+ if (rc <= 0 && ferror(in)) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ rc = __ffs_entry_write(__ffs, full_name, block,
+ data_offset, rc);
+ if (rc < 0)
+ return -1;
+
+ __ffs_fsync(__ffs);
+
+ data_offset += rc;
+ data_size -= rc;
+ }
+
+ if (args->verbose == f_VERBOSE)
+ printf("%llx: %s: read '%llx' bytes from file '%s'\n",
+ __poffset, full_name, st.st_size, args->path);
+
+ return 0;
+ }
+
+ int write(args_t * args, off_t poffset)
+ {
+ __poffset = poffset;
+
+ const char * target = args->target;
+ int debug = args->debug;
+
+ RAII(FILE*, file, fopen_generic(target, "r+", debug), fclose);
+ if (file == NULL)
+ return -1;
+ RAII(ffs_t*, ffs, __ffs_fopen(file, poffset), __ffs_fclose);
+ if (ffs == NULL)
+ return -1;
+
+ __ffs = ffs;
+
+ int rc = __ffs_iterate_entries(ffs, write_entry);
+ if (rc == 1)
+ rc = -1;
+
+ return rc;
+ }
+
+ /* ========================= */
+
+ if (stat(args->path, &st) < 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ if (regcomp(&rx, name, REG_ICASE | REG_NOSUB) != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ int rc = command(args, write);
+
+ regfree(&rx);
+
+ while (!list_empty(&list))
+ free(container_of(list_remove_head(&list),
+ ffs_entry_node_t, node));
+
+ return rc;
+}
diff --git a/fpart/src/command.c b/fpart/src/command.c
new file mode 100644
index 0000000..9f53bde
--- /dev/null
+++ b/fpart/src/command.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: command.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: generic --<command> wrapper
+ * Date: 01/30/2013
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+//#include <spinor/aaflash.h> // --target aa:
+//#include <dbgx/rwflash.h> // --target rw:
+
+#include "main.h"
+
+int parse_offset(const char *str, off_t *offset)
+{
+ assert(offset != NULL);
+
+ if (str == NULL) {
+ *offset = 0;
+ return 0;
+ }
+
+ char *end = NULL;
+
+ errno = 0;
+ *offset = strtoull(str, &end, 0);
+ if (errno != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ if (*end != '\0') {
+ if (!strcmp(end, "KiB") ||
+ !strcasecmp(end, "KB") ||
+ !strcasecmp(end, "K"))
+ *offset <<= 10;
+ else if (!strcmp(end, "MiB") ||
+ !strcasecmp(end, "MB") ||
+ !strcasecmp(end, "M"))
+ *offset <<= 20;
+ else if (!strcmp(end, "GiB") ||
+ !strcasecmp(end, "GB") ||
+ !strcasecmp(end, "G"))
+ *offset <<= 30;
+ else {
+ UNEXPECTED("invalid offset specified '%s'", end);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int parse_size(const char *str, size_t *size)
+{
+ assert(size != NULL);
+
+ if (str == NULL) {
+ *size = 0;
+ return 0;
+ }
+
+ char *end = NULL;
+
+ errno = 0;
+ *size = strtoul(str, &end, 0);
+ if (errno != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ if (*end != '\0') {
+ if (!strcmp(end, "KiB") || !strcasecmp(end, "K") ||
+ !strcasecmp(end, "KB"))
+ *size <<= 10;
+ else if (!strcmp(end, "MiB") || !strcasecmp(end, "M") ||
+ !strcasecmp(end, "MB"))
+ *size <<= 20;
+ else if (!strcmp(end, "GiB") || !strcasecmp(end, "G") ||
+ !strcasecmp(end, "GB"))
+ *size <<= 30;
+ else {
+ UNEXPECTED("invalid size specified '%s'", end);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int parse_number(const char *str, size_t *num)
+{
+ assert(num != NULL);
+
+ if (str == NULL) {
+ *num = 0;
+ return 0;
+ }
+
+ char *end = NULL;
+
+ errno = 0;
+ *num = strtoul(str, &end, 0);
+ if (errno != 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ if (*end != '\0') {
+ UNEXPECTED("invalid number specified '%s'", end);
+ return -1;
+ }
+
+ return 0;
+}
+
+bool check_extension(const char *path, const char *ext)
+{
+ int len = strlen(path), ext_len = strlen(ext);
+ return (ext_len < len)
+ && (strncasecmp(path + len - ext_len, ext, ext_len) == 0);
+}
+
+int create_regular_file(const char *path, size_t size, char pad)
+{
+ assert(path != NULL);
+
+ RAII(FILE*, file, fopen(path, "w"), fclose);
+ if (file == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ if (ftruncate(fileno(file), size) < 0) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ uint32_t page_size = sysconf(_SC_PAGESIZE);
+ char buf[page_size];
+ memset(buf, pad, page_size);
+
+ while (0 < size) {
+ ssize_t rc = fwrite(buf, 1, min(sizeof(buf), size), file);
+ if (rc <= 0 && ferror(file)) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ size -= rc;
+ }
+
+ return 0;
+}
+
+int command(args_t * args, int (*cmd)(args_t *, off_t))
+{
+ assert(args != NULL);
+ assert(cmd != NULL);
+ int rc = 0;
+
+ char * end = (char *)args->poffset;
+ while (rc == 0 && end != NULL && *end != '\0') {
+ errno = 0;
+ off_t poffset = strtoull(end, &end, 0);
+ if (end == NULL || errno != 0) {
+ UNEXPECTED("invalid --partition-offset specified '%s'",
+ args->poffset);
+ return -1;
+ }
+
+ if (*end != ',' && *end != ':' && *end != '\0') {
+ UNEXPECTED("invalid --partition-offset separator "
+ "character '%c'", *end);
+ return -1;
+ }
+
+ if (cmd != NULL)
+ rc = cmd(args, poffset);
+
+ if (*end == '\0')
+ break;
+ end++;
+ }
+
+ return rc;
+}
+
+FILE *fopen_generic(const char *path, const char *mode, int debug)
+{
+ assert(path != NULL);
+ assert(mode != NULL);
+
+ FILE *file = NULL;
+ size_t port = 0;
+
+ if (strncasecmp(path, "aa:", 3) == 0) {
+ if (parse_number(path + 3, &port) == 0)
+ assert(0);
+ //file = fopen_aaflash(port, mode, debug);
+ } else if (strncasecmp(path, "rw:", 3) == 0) {
+ assert(0);
+ //file = fopen_rwflash(path + 3, mode, debug);
+ } else {
+ file = fopen(path, mode);
+ }
+
+ if (file == NULL)
+ ERRNO(errno);
+
+ return file;
+}
+
+int verify_operation(const char * name, ffs_t * in, ffs_entry_t * in_e,
+ ffs_t * out, ffs_entry_t * out_e)
+{
+ if (in->hdr->block_size != out->hdr->block_size) {
+ UNEXPECTED("block sizes differ '%x' != '%x'",
+ in->hdr->block_size, out->hdr->block_size);
+ return -1;
+ }
+
+ if (in->hdr->block_count != out->hdr->block_count) {
+ UNEXPECTED("block counts differ '%x' != '%x'",
+ in->hdr->block_size, out->hdr->block_size);
+ return -1;
+ }
+
+ if (in->hdr->entry_size != out->hdr->entry_size) {
+ UNEXPECTED("entry sizes differ '%x' != '%x'",
+ in->hdr->entry_size, out->hdr->entry_size);
+ return -1;
+ }
+
+ if (in->hdr->entry_count != out->hdr->entry_count) {
+ UNEXPECTED("entry counts differ '%x' != '%x'",
+ in->hdr->entry_size, out->hdr->entry_size);
+ return -1;
+ }
+
+ if (in_e->base != out_e->base) {
+ UNEXPECTED("partition '%s' offsets differ '%x' != '%x'",
+ name, in_e->base, out_e->base);
+ return -1;
+ }
+
+ if (in_e->size != out_e->size) {
+ UNEXPECTED("partition '%s' sizes differ '%x' != '%x'",
+ name, in_e->size, out_e->size);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/fpart/src/main.c b/fpart/src/main.c
new file mode 100644
index 0000000..a90b5f5
--- /dev/null
+++ b/fpart/src/main.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: main.c
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: FFS partition tool
+ * Date: 05/12/2012
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <regex.h>
+
+#include <clib/attribute.h>
+#include <clib/assert.h>
+#include <clib/list.h>
+#include <clib/list_iter.h>
+#include <clib/misc.h>
+#include <clib/min.h>
+#include <clib/err.h>
+#include <clib/raii.h>
+
+#include "main.h"
+
+args_t args;
+size_t page_size;
+
+static const char copyright[] __unused__ =
+ "Licensed Internal Code - Property of IBM\n"
+ "IBM Support Processor Licensed Internal Code\n"
+ "(c) Copyright IBM Corp 2012 All Rights Reserved\n"
+ "US Government Users Restricted Rights - Use, duplication\n"
+ "or disclosure restricted by GSA ADP Schedule Contract\n"
+ "with IBM Corp.";
+
+static void usage(bool verbose)
+{
+ FILE *e = stderr;
+
+ fprintf(e,
+ "fpart - FFS Partition Tool v%d.%d.%d -- Authors: "
+ "<shaun@us.ibm.com>\n (c) Copyright IBM Corp 2012 All Rights "
+ "Reserved\n", FPART_MAJOR, FPART_MINOR, FPART_PATCH);
+
+ fprintf(e, "\nUsage:\n");
+ fprintf(e, " fpart <command> <options>...\n");
+
+ fprintf(e, "\nExamples:\n");
+ fprintf(e, " fpart -C -t nor -s 64MiB -b 64k -p 0x3f0000,0x7f0000\n");
+ fprintf(e, " fpart -A -t nor -p 0x3f0000,0x7f0000 -s 1Mb -o 0M -g 0 "
+ "-n boot0 -l\n");
+ fprintf(e, " fpart --add --target nor --size 1mb --offset 1MiB "
+ "--flags 0x0 --name boot0/ipl\n");
+ fprintf(e, " fpart --delete --target nor nor --name boot0/ipl\n");
+ fprintf(e, " fpart --target nor --write ipl.bin --name boot1/ipl\n");
+ fprintf(e, " fpart --user 0 -t nor -n boot0/ipl --value 0xFF500FF5\n");
+ fprintf(e, " fpart --copy new_nor -t nor -n ipl\n");
+ fprintf(e, " fpart --compare new_nor -t nor -n bank0\n");
+
+ fprintf(e, "\nCommands:\n");
+ fprintf(e, " -C, --create [options]\n");
+ if (verbose)
+ fprintf(e, "\n Create an empty partition table at each"
+ " specified partition offest.\n\n");
+
+ fprintf(e, " -A, --add [options]\n");
+ if (verbose)
+ fprintf(e, "\n Add partition entry(s) to each specified"
+ " partition offset.\n\n");
+
+ fprintf(e, " -D, --delete [options]\n");
+ if (verbose)
+ fprintf(e, "\n Delete partition entry(s) from each specified"
+ " partition offset.\n\n");
+
+ fprintf(e, " -E, --erase [options]\n");
+ if (verbose)
+ fprintf(e, "\n Fill partition entry(s) from each specified"
+ " partition offset.\n\n");
+
+ fprintf(e, " -L, --list [options]\n");
+ if (verbose)
+ fprintf(e, "\n Display the list of matching partition"
+ " entry(s) of each specified\n"
+ " partition offset.\n\n");
+
+ fprintf(e, " -T, --trunc [options]\n");
+ if (verbose)
+ fprintf(e, "\n Truncate the actual data size of matching"
+ " partition entry(s) of each\n specified partition"
+ " offset.\n\n");
+
+ fprintf(e, " -U, --user <num> [options]\n");
+ if (verbose)
+ fprintf(e, "\n Read or write user words of matching partition"
+ " entry(s) for each\n specified partition offset.\n");
+
+ /* =============================== */
+
+ fprintf(e, "\nOptions:\n");
+ fprintf(e, " -p, --partition-offset <offset[,offset]>\n");
+ if (verbose)
+ fprintf(e, "\n Specifies a comma (,) separated list of"
+ " partition table offsets, in\n bytes from the start"
+ " of the target file (or device).\n\n");
+
+ fprintf(e, " -t, --target <target>\n");
+ if (verbose) {
+ fprintf(e, "\n Specifies the target of the operation.");
+ fprintf(e, " <target> can be one of:\n");
+ fprintf(e, "\t <port> : Aardvard USB port number [0..9]\n");
+ fprintf(e, "\t<hostname> : RISCWatch probe hostname\n");
+ fprintf(e, "\t <path> : SFC device file, e.g. "
+ "/dev/mtdblock/sfc.of\n\n");
+ }
+
+ fprintf(e, " -n, --name <name>\n");
+ if (verbose)
+ fprintf(e, "\n Specifies the name of a partition entry(s)."
+ " For some commands\n (--hexdump, --add)"
+ " <name> must be a fully qualified name.\n For other"
+ " commands, name can specify a regular "
+ "expression.\n\n");
+
+ fprintf(e, " -o, --offset <offset>\n");
+ if (verbose)
+ fprintf(e, "\n Specifies the offset of a partition entry,"
+ " in bytes from the beginning\n of the target file"
+ " (or device).\n\n");
+
+ fprintf(e, " -s, --size <size>\n");
+ if (verbose)
+ fprintf(e, "\n Specifies the size of a partition entry (in"
+ " bytes).\n <size> is a decimal (or hex) number"
+ " (optionally) followed by 'k', 'K',\n 'KB' or 'KiB'"
+ " to specify.\n\n");
+
+ fprintf(e, " -b, --block-size <size>\n");
+ if (verbose)
+ fprintf(e, "\n Specifies the block size, in bytes. <size>"
+ " is a decimal (or hex)\n number (optionally)"
+ " followed by 'k', 'K', 'KB' or 'KiB' to"
+ " specify.\n\n");
+
+ fprintf(e, " -u, --value <value>\n");
+ if (verbose)
+ fprintf(e, "\n Specifies the user word value. <value> is a"
+ " decimal (or hex) number.\n\n");
+
+ fprintf(e, " -g, --flags <value>\n");
+ if (verbose)
+ fprintf(e, "\n Specifies the partition flags value."
+ " <value> is a decimal (or hex)\n number.\n\n");
+
+ fprintf(e, " -a, --pad <value>\n");
+ if (verbose)
+ fprintf(e,
+ "\n Specifies the partition content initial value."
+ " <value> is a decimal\n (or hex) number, default is"
+ " 0xFF.\n\n");
+
+ /* =============================== */
+
+ fprintf(e, "\nFlags:\n");
+ fprintf(e, " -f, --force\n");
+ if (verbose)
+ fprintf(e, "\n Override command safe guards.\n\n");
+
+ fprintf(e, " -l, --logical\n");
+ if (verbose)
+ fprintf(e, "\n Specifies the partition entry is a logical"
+ " partition instead of a\n data partition.\n\n");
+
+ fprintf(e, " -v, --verbose\n");
+ if (verbose)
+ fprintf(e, "\n Write progress messages to stdout\n\n");
+
+ fprintf(e, " -d, --debug\n");
+ if (verbose)
+ fprintf(e, "\n Write debug messages to stdout\n\n");
+
+ fprintf(e, " -h, --help\n");
+ if (verbose)
+ fprintf(e, "\n Write this help text to stdout and exit\n");
+
+ fprintf(e, "\n");
+
+ fprintf(e, "Report bugs to <https://bugzilla.linux.ibm.com/>"
+ " (vendor='MCP for FSP*')\n");
+}
+
+static int process_argument(args_t * args, int opt, const char *optarg)
+{
+ assert(args != NULL);
+
+ switch (opt) {
+ case c_CREATE: /* create */
+ case c_ADD: /* add */
+ case c_DELETE: /* delete */
+ case c_LIST: /* list */
+ case c_TRUNC: /* trunc */
+ case c_ERASE: /* erase */
+ case c_USER: /* user */
+ if (args->cmd != c_ERROR) {
+ UNEXPECTED("commands '%c' and '%c' are mutually "
+ "exclusive", args->cmd, opt);
+ return -1;
+ }
+
+ args->cmd = (cmd_t) opt;
+ if (args->cmd == c_USER)
+ args->user = strdup(optarg);
+ break;
+ case o_POFFSET: /* partition-offset */
+ args->poffset = strdup(optarg);
+ break;
+ case o_TARGET: /* target */
+ args->target = strdup(optarg);
+ break;
+ case o_NAME: /* name */
+ args->name = strdup(optarg);
+ break;
+ case o_OFFSET: /* offset */
+ args->offset = strdup(optarg);
+ break;
+ case o_SIZE: /* size */
+ args->size = strdup(optarg);
+ break;
+ case o_BLOCK: /* block */
+ args->block = strdup(optarg);
+ break;
+ case o_VALUE: /* value */
+ args->value = strdup(optarg);
+ break;
+ case o_FLAGS: /* flags */
+ args->flags = strdup(optarg);
+ break;
+ case o_PAD: /* pad */
+ args->pad = strdup(optarg);
+ break;
+ case f_FORCE: /* force */
+ args->force = (flag_t) opt;
+ break;
+ case f_LOGICAL: /* logical */
+ args->logical = (flag_t) opt;
+ break;
+ case f_VERBOSE: /* verbose */
+ args->verbose = (flag_t) opt;
+ break;
+ case f_DEBUG: /* debug */
+ args->debug = (flag_t) opt;
+ break;
+ case f_HELP: /* help */
+ usage(true);
+ exit(EXIT_SUCCESS);
+ break;
+ case '?': /* error */
+ default:
+ usage(false);
+ UNEXPECTED("unknown option '%c', please see --help for "
+ "details\n", opt);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int process_option(args_t * args, const char *opt)
+{
+ assert(args != NULL);
+ assert(opt != NULL);
+
+ if (args->opt_sz <= args->opt_nr) {
+ size_t size = sizeof(*args->opt);
+
+ args->opt_sz += 5;
+ args->opt = (const char **)realloc(args->opt,
+ size * args->opt_sz);
+ if (args->opt == NULL) {
+ ERRNO(errno);
+ return -1;
+ }
+
+ memset(args->opt + args->opt_nr, 0,
+ size * (args->opt_sz - args->opt_nr));
+ }
+
+ args->opt[args->opt_nr] = strdup(opt);
+ args->opt_nr++;
+
+ return 0;
+}
+
+static int validate_args(args_t * args)
+{
+ assert(args != NULL);
+
+ if (args->cmd == c_ERROR) {
+ usage(false);
+ UNEXPECTED("no command specified, please "
+ "see --help for details\n");
+ return -1;
+ }
+
+ if (args->poffset == NULL) {
+ UNEXPECTED("--partition-offset is required for all '%s' "
+ "commands", args->short_name);
+ return -1;
+ }
+
+ if (args->target == NULL) {
+ UNEXPECTED("--target is required for all '%s' commands",
+ args->short_name);
+ return -1;
+ }
+
+ #define REQUIRED(name,cmd) ({ \
+ if (args->name == NULL) { \
+ UNEXPECTED("--%s is required for the --%s command", \
+ #name, #cmd); \
+ return -1; \
+ } \
+ })
+
+ #define UNSUPPORTED(name,cmd) ({ \
+ if (args->name != NULL) { \
+ UNEXPECTED("--%s is unsupported for the --%s command", \
+ #name, #cmd); \
+ return -1; \
+ } \
+ })
+
+ if (args->cmd == c_CREATE) {
+ REQUIRED(size, create);
+ REQUIRED(block, create);
+ REQUIRED(target, create);
+
+ UNSUPPORTED(offset, create);
+ UNSUPPORTED(flags, create);
+ UNSUPPORTED(value, create);
+ UNSUPPORTED(pad, create);
+ } else if (args->cmd == c_ADD) {
+ REQUIRED(name, add);
+ REQUIRED(flags, add);
+
+ if (args->logical != f_LOGICAL) {
+ REQUIRED(size, add);
+ REQUIRED(offset, add);
+ }
+
+ UNSUPPORTED(block, add);
+ UNSUPPORTED(value, add);
+ } else if (args->cmd == c_DELETE) {
+ REQUIRED(name, delete);
+
+ UNSUPPORTED(size, delete);
+ UNSUPPORTED(offset, delete);
+ UNSUPPORTED(block, delete);
+ UNSUPPORTED(flags, delete);
+ UNSUPPORTED(value, delete);
+ UNSUPPORTED(pad, delete);
+ } else if (args->cmd == c_LIST) {
+ UNSUPPORTED(size, list);
+ UNSUPPORTED(offset, list);
+ UNSUPPORTED(block, list);
+ UNSUPPORTED(flags, list);
+ UNSUPPORTED(value, list);
+ UNSUPPORTED(pad, list);
+ } else if (args->cmd == c_TRUNC) {
+ REQUIRED(name, trunc);
+
+ UNSUPPORTED(offset, trunc);
+ UNSUPPORTED(block, trunc);
+ UNSUPPORTED(flags, trunc);
+ UNSUPPORTED(value, trunc);
+ UNSUPPORTED(pad, trunc);
+ } else if (args->cmd == c_ERASE) {
+ REQUIRED(name, erase);
+
+ UNSUPPORTED(size, erase);
+ UNSUPPORTED(offset, erase);
+ UNSUPPORTED(flags, erase);
+ UNSUPPORTED(value, erase);
+ } else if (args->cmd == c_USER) {
+ REQUIRED(name, user);
+
+ UNSUPPORTED(size, user);
+ UNSUPPORTED(offset, user);
+ UNSUPPORTED(block, user);
+ UNSUPPORTED(flags, user);
+ UNSUPPORTED(pad, user);
+ } else {
+ UNEXPECTED("invalid command '%c'", args->cmd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int process_args(args_t * args)
+{
+ assert(args != NULL);
+ int rc = 0;
+
+ switch (args->cmd) {
+ case c_CREATE:
+ rc = command_create(args);
+ break;
+ case c_ADD:
+ rc = command_add(args);
+ if (rc < 0)
+ break;
+ if (args->pad != NULL)
+ rc = command_erase(args);
+ break;
+ case c_DELETE:
+ rc = command_delete(args);
+ break;
+ case c_LIST:
+ rc = command_list(args);
+ break;
+ case c_TRUNC:
+ rc = command_trunc(args);
+ break;
+ case c_ERASE:
+ rc = command_erase(args);
+ break;
+ case c_USER:
+ rc = command_user(args);
+ break;
+ default:
+ UNEXPECTED("NOT IMPLEMENTED YET => '%c'", args->cmd);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static void args_dump(args_t * args)
+{
+ assert(args != NULL);
+
+ if (args->short_name != NULL)
+ printf("short_name[%s]\n", args->short_name);
+ if (args->cmd != 0)
+ printf("cmd[%c]\n", args->cmd);
+ if (args->path != NULL)
+ printf("path[%s]\n", args->path);
+ if (args->target != NULL)
+ printf("target[%s]\n", args->target);
+ if (args->poffset != NULL)
+ printf("poffset[%s]\n", args->poffset);
+ if (args->name != NULL)
+ printf("name[%s]\n", args->name);
+ if (args->offset != NULL)
+ printf("offset[%s]\n", args->offset);
+ if (args->size != NULL)
+ printf("size[%s]\n", args->size);
+ if (args->block != NULL)
+ printf("block[%s]\n", args->block);
+ if (args->flags != NULL)
+ printf("flags[%s]\n", args->flags);
+ if (args->value != NULL)
+ printf("value[%s]\n", args->value);
+ if (args->pad != NULL)
+ printf("pad[%s]\n", args->pad);
+ for (int i = 0; i < args->opt_nr; i++) {
+ if (args->opt[i] != NULL)
+ printf("opt%d[%s]\n", i, args->opt[i]);
+ }
+ if (args->force != 0)
+ printf("force[%c]\n", args->force);
+ if (args->protected != 0)
+ printf("protected[%c]\n", args->protected);
+ if (args->logical != 0)
+ printf("logical[%c]\n", args->logical);
+ if (args->verbose != 0)
+ printf("verbose[%c]\n", args->verbose);
+ if (args->verbose != 0)
+ printf("debug[%c]\n", args->debug);
+}
+
+int main(int argc, char *argv[])
+{
+ static const struct option long_opt[] = {
+ /* commands */
+ {"create", no_argument, NULL, c_CREATE},
+ {"add", no_argument, NULL, c_ADD},
+ {"delete", no_argument, NULL, c_DELETE},
+ {"list", no_argument, NULL, c_LIST},
+ {"trunc", no_argument, NULL, c_TRUNC},
+ {"erase", no_argument, NULL, c_ERASE},
+ {"user", required_argument, NULL, c_USER},
+ /* options */
+ {"partition-offset", required_argument, NULL, o_POFFSET},
+ {"target", required_argument, NULL, o_TARGET},
+ {"name", required_argument, NULL, o_NAME},
+ {"offset", required_argument, NULL, o_OFFSET},
+ {"size", required_argument, NULL, o_SIZE},
+ {"block-size", required_argument, NULL, o_BLOCK},
+ {"value", required_argument, NULL, o_VALUE},
+ {"flags", required_argument, NULL, o_FLAGS},
+ {"pad", required_argument, NULL, o_PAD},
+ /* flags */
+ {"force", no_argument, NULL, f_FORCE},
+ {"protected", no_argument, NULL, f_PROTECTED},
+ {"logical", no_argument, NULL, f_LOGICAL},
+ {"verbose", no_argument, NULL, f_VERBOSE},
+ {"debug", no_argument, NULL, f_DEBUG},
+ {"help", no_argument, NULL, f_HELP},
+ {0, 0, 0, 0}
+ };
+
+ static const char *short_opt;
+ short_opt = "CADLTEU:p:t:n:o:s:b:u:g:a:frlvdh";
+
+ int rc = EXIT_FAILURE;
+
+ setlinebuf(stdout);
+
+ if (argc == 1)
+ usage(false), exit(rc);
+
+ int opt = 0, idx = 0;
+ while ((opt = getopt_long(argc, argv, short_opt, long_opt, &idx)) != -1)
+ if (process_argument(&args, opt, optarg) < 0)
+ goto error;
+
+ /* getopt_long doesn't know what to do with orphans, */
+ /* so we'll scoop them up here, and deal with them later */
+
+ while (optind < argc)
+ if (process_option(&args, argv[optind++]) < 0)
+ goto error;
+
+ if (args.debug == f_DEBUG)
+ args_dump(&args);
+
+ if (validate_args(&args) < 0)
+ goto error;
+ if (process_args(&args) < 0)
+ goto error;
+
+ rc = EXIT_SUCCESS;
+
+ if (false) {
+ err_t *err;
+error:
+ err = err_get();
+ assert(err != NULL);
+
+ fprintf(stderr, "%s: %s : %s(%d) : (code=%d) %.*s\n",
+ program_invocation_short_name,
+ err_type_name(err), err_file(err), err_line(err),
+ err_code(err), err_size(err), (char *)err_data(err));
+ }
+
+ return rc;
+}
+
+static void __ctor__(void) __constructor;
+static void __ctor__(void)
+{
+ page_size = sysconf(_SC_PAGESIZE);
+
+ args.short_name = program_invocation_short_name;
+ args.poffset = "0x3F0000,0x7F0000";
+ args.target = "/dev/mtdblock/sfc.of";
+ args.name = ".*";
+}
diff --git a/fpart/src/main.h b/fpart/src/main.h
new file mode 100644
index 0000000..eeb3b39
--- /dev/null
+++ b/fpart/src/main.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2012
+ *
+ * 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
+ */
+
+/*
+ * File: main.h
+ * Author: Shaun Wetzstein <shaun@us.ibm.com>
+ * Descr: cmdline tool for libffs.so
+ * Date: 05/12/2012
+ */
+
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include <stdio.h>
+
+#include <ffs/libffs.h>
+
+#define FPART_MAJOR 0x01
+#define FPART_MINOR 0x00
+#define FPART_PATCH 0x00
+
+typedef enum {
+ c_ERROR = 0,
+ c_CREATE = 'C',
+ c_ADD = 'A',
+ c_DELETE = 'D',
+ c_ERASE = 'E',
+ c_LIST = 'L',
+ c_TRUNC = 'T',
+ c_USER = 'U',
+} cmd_t;
+
+typedef enum {
+ o_ERROR = 0,
+ o_POFFSET = 'p',
+ o_TARGET = 't',
+ o_NAME = 'n',
+ o_OFFSET = 'o',
+ o_SIZE = 's',
+ o_BLOCK = 'b',
+ o_VALUE = 'u',
+ o_FLAGS = 'g',
+ o_PAD = 'a',
+} option_t;
+
+typedef enum {
+ f_ERROR = 0,
+ f_FORCE = 'f',
+ f_PROTECTED = 'r',
+ f_LOGICAL = 'l',
+ f_VERBOSE = 'v',
+ f_DEBUG = 'd',
+ f_HELP = 'h',
+} flag_t;
+
+typedef struct {
+ const char *short_name;
+
+ /* target */
+ const char *path;
+
+ /* command */
+ cmd_t cmd;
+
+ /* options */
+ const char *name, *target;
+ const char *offset, *poffset;
+ const char *size, *block;
+ const char *user, *value;
+ const char *flags, *pad;
+
+ /* flags */
+ flag_t force, logical;
+ flag_t verbose, debug;
+ flag_t protected;
+
+ const char **opt;
+ int opt_sz, opt_nr;
+} args_t;
+
+typedef struct ffs_entry_node ffs_entry_node_t;
+struct ffs_entry_node {
+ list_node_t node;
+ ffs_entry_t entry;
+};
+
+extern args_t args;
+extern size_t page_size;
+
+extern int parse_offset(const char *, off_t *);
+extern int parse_size(const char *, size_t *);
+extern int parse_number(const char *, size_t *);
+
+extern bool check_extension(const char *, const char *);
+extern int create_regular_file(const char *, size_t, char);
+extern FILE *fopen_generic(const char *, const char *, int);
+
+extern int command(args_t *, int (*)(args_t *, off_t));
+extern int verify_operation(const char *, ffs_t *, ffs_entry_t *,
+ ffs_t *, ffs_entry_t *);
+
+extern int command_create(args_t *);
+extern int command_add(args_t *);
+extern int command_delete(args_t *);
+extern int command_list(args_t *);
+extern int command_trunc(args_t *);
+extern int command_erase(args_t *);
+extern int command_user(args_t *);
+
+#endif /* __MAIN_H__ */
OpenPOWER on IntegriCloud