[yocto] [PATCH 3/3] rmc: add database extraction functionality
Todor Minchev
todor.minchev at linux.intel.com
Thu Feb 2 14:37:12 PST 2017
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.minchev at 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
More information about the yocto
mailing list