The contents of an existing database file can be extracted in the current working directory with the -E option. The top level of the directory tree is rmc_db_dump and all files corresponding to a given record will be saved in a separate sub-directory. The sub-directory name of each record is the signature corresponding to the fingerprint for that record.
Example: ./src/rmc -E -d rmc.db Successfully extracted rmc.db Signed-off-by: Todor Minchev <todor.minc...@linux.intel.com> --- inc/rmc_api.h | 9 ++++++ src/lib/api.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/lib/common/rmcl.c | 3 +- src/rmc.c | 44 +++++++++++++++++++------- 4 files changed, 126 insertions(+), 15 deletions(-) diff --git a/inc/rmc_api.h b/inc/rmc_api.h index a484389..ce26220 100644 --- a/inc/rmc_api.h +++ b/inc/rmc_api.h @@ -74,6 +74,15 @@ extern int rmc_query_file_by_fp(rmc_fingerprint_t *fp, char *db_pathname, char * */ extern int rmc_gimme_file(char* db_pathname, char *file_name, rmc_file_t *file); + +/* extract the contents of a database file and store the files corresponding to + * each record in a separate directory. The name of each directory is the signature + * of the fingerpring for that record + * (in) db_pathname: The path and file name of a RMC database file generated by RMC tool + * return: 0 on success, non-zero on failure. + */ +int dump_db(char *db_pathname) ; + /* 1.3 - Helper APIs */ /* Free allocated data referred in a fingerprint diff --git a/src/lib/api.c b/src/lib/api.c index 0adb390..aca8d99 100644 --- a/src/lib/api.c +++ b/src/lib/api.c @@ -3,6 +3,7 @@ * RMC API implementation for Linux user space */ +#define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <errno.h> @@ -14,8 +15,11 @@ #include <rmcl.h> #include <rsmp.h> -#define EFI_SYSTAB_PATH "/sys/firmware/efi/systab" -#define SYSTAB_LEN 4096 /* assume 4kb is enough...*/ +#define EFI_SYSTAB_PATH "/sys/firmware/efi/systab" +#define SYSTAB_LEN 4096 /* assume 4kb is enough...*/ +#define DB_DUMP_DIR "./rmc_db_dump" /* directory to store db data dump */ + +extern const rmc_uint8_t rmc_db_signature[RMC_DB_SIG_LEN]; int read_file(const char *pathname, char **data, rmc_size_t* len) { int fd = -1; @@ -325,3 +329,80 @@ int rmc_gimme_file(char* db_pathname, char *file_name, rmc_file_t *file) { return ret; } + +/* + * Dump contents of database file + * (in) rmc_db - input database file to extract + */ +int dump_db(char *db_pathname) { + rmc_meta_header_t meta_header; + rmc_db_header_t *db_header = NULL; + rmc_record_header_t record_header; + rmc_uint64_t record_idx = 0; /* offset of each reacord in db*/ + rmc_uint64_t meta_idx = 0; /* offset of each meta in a record */ + rmc_uint64_t file_idx = 0; /* offset of file in a meta */ + rmc_file_t file; + char *out_dir = NULL, *out_name = NULL; + rmc_size_t db_len = 0; + rmc_uint8_t *rmc_db = NULL; + struct stat s = {0}; + + if (read_file(db_pathname, (char **)&rmc_db, &db_len)) { + fprintf(stderr, "Failed to read database file\n\n"); + return 1; + } + + db_header = (rmc_db_header_t *)rmc_db; + + /* sanity check of db */ + if (strncmp((const char *)db_header->signature, + (const char *)rmc_db_signature, RMC_DB_SIG_LEN)) + return 1; + + /* create the top level directory */ + if (stat(DB_DUMP_DIR, &s) == -1) { + if(mkdir(DB_DUMP_DIR, 0755)) { + fprintf(stderr, "Failed to create %s directory\n\n", out_name); + } + } + + /* query the meta. idx: start of record */ + record_idx = sizeof(rmc_db_header_t); + while (record_idx < db_header->length) { + memcpy(&record_header, rmc_db + record_idx, + sizeof(rmc_record_header_t)); + + /* directory name is fingerprint signature */ + asprintf(&out_dir, "%s/%s/", DB_DUMP_DIR, record_header.signature.raw); + if (stat(out_dir, &s) == -1) { + if(mkdir(out_dir, 0755)) { + fprintf(stderr, "Failed to create %s directory\n\n", out_name); + } + } + + /* find meta */ + for (meta_idx = record_idx + sizeof(rmc_record_header_t); + meta_idx < record_idx + record_header.length;) { + memcpy(&meta_header, rmc_db + meta_idx, sizeof(rmc_meta_header_t)); + file_idx = meta_idx + sizeof(rmc_meta_header_t); + rmc_ssize_t name_len = strlen((char *)&rmc_db[file_idx]) + 1; + file.blob = &rmc_db[file_idx + name_len]; + file.blob_len = meta_header.length - sizeof(rmc_meta_header_t) - + name_len; + file.next = NULL; + file.type = RMC_GENERIC_FILE; + asprintf(&out_name, "%s%s", out_dir, (char *)&rmc_db[file_idx]); + /* write file to dump directory */ + if (write_file((const char *)out_name, file.blob, file.blob_len, 0)) + return 1; + + /* next meta */ + meta_idx += meta_header.length; + free(out_name); + } + /* next record */ + record_idx += record_header.length; + free(out_dir); + } + return 0; +} diff --git a/src/lib/common/rmcl.c b/src/lib/common/rmcl.c index 67622a0..c996577 100644 --- a/src/lib/common/rmcl.c +++ b/src/lib/common/rmcl.c @@ -10,7 +10,7 @@ #include <rmc_util.h> #endif -static const rmc_uint8_t rmc_db_signature[RMC_DB_SIG_LEN] = {'R', 'M', 'C', 'D', 'B'}; +const rmc_uint8_t rmc_db_signature[RMC_DB_SIG_LEN] = {'R', 'M', 'C', 'D', 'B'}; /* compute a finger to signature which is stored in record * (in) fingerprint : of board, usually generated by rmc tool and rsmp @@ -242,7 +242,6 @@ int query_policy_from_db(rmc_fingerprint_t *fingerprint, rmc_uint8_t *rmc_db, rm policy->blob_len = meta_header.length - sizeof(rmc_meta_header_t) - cmd_name_len; policy->next = NULL; policy->type = type; - return 0; } } diff --git a/src/rmc.c b/src/rmc.c index a051ccf..888cbdb 100644 --- a/src/rmc.c +++ b/src/rmc.c @@ -32,6 +32,8 @@ "running on\n" \ "\t-d: database file to be queried\n" \ "\t-o: path and name of output file of a specific command\n\n" \ + "-E: Extract database data to current working directory\n" \ + "\t-d: database file to extract\n\n" \ "Examples (Steps in an order to add board support into rmc):\n\n" \ "1. Generate board fingerprint:\n" \ "\t./rmc -F\n\n" \ @@ -49,11 +51,12 @@ #define RMC_OPT_CAP_R (1 << 1) #define RMC_OPT_CAP_D (1 << 2) #define RMC_OPT_CAP_B (1 << 3) -#define RMC_OPT_F (1 << 4) -#define RMC_OPT_O (1 << 5) -#define RMC_OPT_B (1 << 6) -#define RMC_OPT_D (1 << 7) -#define RMC_OPT_I (1 << 8) +#define RMC_OPT_CAP_E (1 << 4) +#define RMC_OPT_F (1 << 5) +#define RMC_OPT_O (1 << 6) +#define RMC_OPT_B (1 << 7) +#define RMC_OPT_D (1 << 8) +#define RMC_OPT_I (1 << 9) static void usage () { fprintf(stdout, USAGE); @@ -312,7 +315,7 @@ int main(int argc, char **argv){ /* parse options */ opterr = 0; - while ((c = getopt(argc, argv, "FRD:B:b:f:o:i:d:")) != -1) + while ((c = getopt(argc, argv, "FRED:B:b:f:o:i:d:")) != -1) switch (c) { case 'F': options |= RMC_OPT_CAP_F; @@ -320,6 +323,9 @@ int main(int argc, char **argv){ case 'R': options |= RMC_OPT_CAP_R; break; + case 'E': + options |= RMC_OPT_CAP_E; + break; case 'D': /* we don't know number of arguments for this option at this point, * allocate array with argc which is bigger than needed. But we also @@ -393,8 +399,8 @@ int main(int argc, char **argv){ break; case '?': if (optopt == 'F' || optopt == 'R' || optopt == 'D' || optopt == 'B' || \ - optopt == 'b' || optopt == 'f' || optopt == 'o' || optopt == 'd' \ - || optopt == 'i') + optopt == 'E' || optopt == 'b' || optopt == 'f' || \ + optopt == 'o' || optopt == 'd' || optopt == 'i') fprintf(stderr, "\nWRONG USAGE: -%c\n\n", optopt); else if (isprint(optopt)) fprintf(stderr, "Unknown option `-%c'.\n\n", optopt); @@ -436,6 +442,13 @@ int main(int argc, char **argv){ return 1; } + /* sanity check for -E */ + if ((options & RMC_OPT_CAP_E) && (!(options & RMC_OPT_D))) { + fprintf(stderr, "\nERROR: -E requires -d <database file name>\n\n"); + usage(); + return 1; + } + /* sanity check for -B */ if ((options & RMC_OPT_CAP_B) && (!(options & RMC_OPT_D) || !(options & RMC_OPT_O))) { fprintf(stderr, "\nWRONG: -B requires -d and -o\n\n"); @@ -448,7 +461,8 @@ int main(int argc, char **argv){ rmc_file_t file; if (!output_path) { - fprintf(stderr, "-B internal error, with -o but no output pathname specified\n\n"); + fprintf(stderr, "-B internal error, with -o but no output \ + pathname specified\n\n"); goto main_free; } @@ -456,14 +470,22 @@ int main(int argc, char **argv){ goto main_free; if (write_file(output_path, file.blob, file.blob_len, 0)) { - fprintf(stderr, "-B failed to write file %s to %s\n\n", input_blob_name, output_path); + fprintf(stderr, "-B failed to write file %s to %s\n\n", + input_blob_name, output_path); rmc_free_file(&file); goto main_free; } - rmc_free_file(&file); } + /* dump database data */ + if (options & RMC_OPT_CAP_E) { + if(dump_db(input_db_path_d)) + fprintf(stderr, "\nFailed to extract %s\n\n", input_db_path_d); + else + printf("\nSuccessfully extracted %s\n\n", input_db_path_d); + } + /* generate RMC database file */ if (options & RMC_OPT_CAP_D) { int record_idx = 0; -- 2.11.0 -- _______________________________________________ yocto mailing list yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/yocto