From bf4630076762d9c20c16c80c1c791f352b046dd1 Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Mon, 30 Jun 2014 22:10:16 -0500 Subject: Port FFS tools over from Building Block repository. --- fpart/src/cmd_add.c | 102 +++++++++ fpart/src/cmd_compare.c | 231 +++++++++++++++++++ fpart/src/cmd_copy.c | 282 +++++++++++++++++++++++ fpart/src/cmd_create.c | 113 +++++++++ fpart/src/cmd_delete.c | 78 +++++++ fpart/src/cmd_erase.c | 206 +++++++++++++++++ fpart/src/cmd_hexdump.c | 153 +++++++++++++ fpart/src/cmd_list.c | 168 ++++++++++++++ fpart/src/cmd_read.c | 166 ++++++++++++++ fpart/src/cmd_trunc.c | 134 +++++++++++ fpart/src/cmd_user.c | 156 +++++++++++++ fpart/src/cmd_write.c | 229 +++++++++++++++++++ fpart/src/command.c | 296 ++++++++++++++++++++++++ fpart/src/main.c | 597 ++++++++++++++++++++++++++++++++++++++++++++++++ fpart/src/main.h | 125 ++++++++++ 15 files changed, 3036 insertions(+) create mode 100644 fpart/src/cmd_add.c create mode 100644 fpart/src/cmd_compare.c create mode 100644 fpart/src/cmd_copy.c create mode 100644 fpart/src/cmd_create.c create mode 100644 fpart/src/cmd_delete.c create mode 100644 fpart/src/cmd_erase.c create mode 100644 fpart/src/cmd_hexdump.c create mode 100644 fpart/src/cmd_list.c create mode 100644 fpart/src/cmd_read.c create mode 100644 fpart/src/cmd_trunc.c create mode 100644 fpart/src/cmd_user.c create mode 100644 fpart/src/cmd_write.c create mode 100644 fpart/src/command.c create mode 100644 fpart/src/main.c create mode 100644 fpart/src/main.h (limited to 'fpart/src') 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 + * Descr: --add implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --compare implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --copy implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; iverbose == 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 + * Descr: --create implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --delete implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --erase implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; iverbose == 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 + * Descr: --hexdump implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --list implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; iuser.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 + * Descr: --read implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --trunc implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --user implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: --write implementation + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Descr: generic -- wrapper + * Date: 01/30/2013 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//#include // --target aa: +//#include // --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 + * Descr: FFS partition tool + * Date: 05/12/2012 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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: " + "\n (c) Copyright IBM Corp 2012 All Rights " + "Reserved\n", FPART_MAJOR, FPART_MINOR, FPART_PATCH); + + fprintf(e, "\nUsage:\n"); + fprintf(e, " fpart ...\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 [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 \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 \n"); + if (verbose) { + fprintf(e, "\n Specifies the target of the operation."); + fprintf(e, " can be one of:\n"); + fprintf(e, "\t : Aardvard USB port number [0..9]\n"); + fprintf(e, "\t : RISCWatch probe hostname\n"); + fprintf(e, "\t : SFC device file, e.g. " + "/dev/mtdblock/sfc.of\n\n"); + } + + fprintf(e, " -n, --name \n"); + if (verbose) + fprintf(e, "\n Specifies the name of a partition entry(s)." + " For some commands\n (--hexdump, --add)" + " must be a fully qualified name.\n For other" + " commands, name can specify a regular " + "expression.\n\n"); + + fprintf(e, " -o, --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 \n"); + if (verbose) + fprintf(e, "\n Specifies the size of a partition entry (in" + " bytes).\n is a decimal (or hex) number" + " (optionally) followed by 'k', 'K',\n 'KB' or 'KiB'" + " to specify.\n\n"); + + fprintf(e, " -b, --block-size \n"); + if (verbose) + fprintf(e, "\n Specifies the block size, in bytes. " + " is a decimal (or hex)\n number (optionally)" + " followed by 'k', 'K', 'KB' or 'KiB' to" + " specify.\n\n"); + + fprintf(e, " -u, --value \n"); + if (verbose) + fprintf(e, "\n Specifies the user word value. is a" + " decimal (or hex) number.\n\n"); + + fprintf(e, " -g, --flags \n"); + if (verbose) + fprintf(e, "\n Specifies the partition flags value." + " is a decimal (or hex)\n number.\n\n"); + + fprintf(e, " -a, --pad \n"); + if (verbose) + fprintf(e, + "\n Specifies the partition content initial 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 " + " (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 + * Descr: cmdline tool for libffs.so + * Date: 05/12/2012 + */ + +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include + +#include + +#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__ */ -- cgit v1.2.1