102c801a5SLawrence Tang /**
202c801a5SLawrence Tang * A user-space application linking to the CPER-JSON conversion library which allows for easy
302c801a5SLawrence Tang * conversion between CPER and CPER-JSON formats.
402c801a5SLawrence Tang *
502c801a5SLawrence Tang * Author: Lawrence.Tang@arm.com
602c801a5SLawrence Tang **/
702c801a5SLawrence Tang
802c801a5SLawrence Tang #include <stdio.h>
902c801a5SLawrence Tang #include <string.h>
1002c801a5SLawrence Tang #include <libgen.h>
11*4482c48bSAndrew Adriance #include <limits.h>
125202bbb4SLawrence Tang #include <json.h>
1302c801a5SLawrence Tang #include "../cper-parse.h"
1402c801a5SLawrence Tang #include "../json-schema.h"
1502c801a5SLawrence Tang
16617949e4SLawrence Tang void cper_to_json(char *in_file, char *out_file, int is_single_section);
175f388a3fSLawrence Tang void json_to_cper(char *in_file, char *out_file, char *specification_file,
185f388a3fSLawrence Tang char *program_dir, int no_validate, int debug);
1902c801a5SLawrence Tang void print_help(void);
2002c801a5SLawrence Tang
main(int argc,char * argv[])2102c801a5SLawrence Tang int main(int argc, char *argv[])
2202c801a5SLawrence Tang {
235f388a3fSLawrence Tang //Print help if requested.
245f388a3fSLawrence Tang if (argc == 2 && strcmp(argv[1], "--help") == 0) {
255f388a3fSLawrence Tang print_help();
265f388a3fSLawrence Tang return 0;
275f388a3fSLawrence Tang }
285f388a3fSLawrence Tang
295f388a3fSLawrence Tang //Ensure at least two arguments are present.
305f388a3fSLawrence Tang if (argc < 3) {
3102c801a5SLawrence Tang printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n");
3202c801a5SLawrence Tang return -1;
3302c801a5SLawrence Tang }
3402c801a5SLawrence Tang
3571c70a3dSLawrence Tang //Parse the command line arguments.
365f388a3fSLawrence Tang char *input_file = argv[2];
3771c70a3dSLawrence Tang char *output_file = NULL;
385f388a3fSLawrence Tang char *specification_file = NULL;
395f388a3fSLawrence Tang int no_validate = 0;
405f388a3fSLawrence Tang int debug = 0;
415f388a3fSLawrence Tang for (int i = 3; i < argc; i++) {
425f388a3fSLawrence Tang if (strcmp(argv[i], "--out") == 0 && i < argc - 1) {
435f388a3fSLawrence Tang //Output file.
445f388a3fSLawrence Tang output_file = argv[i + 1];
455f388a3fSLawrence Tang i++;
465f388a3fSLawrence Tang } else if (strcmp(argv[i], "--specification") == 0 &&
475f388a3fSLawrence Tang i < argc - 1) {
485f388a3fSLawrence Tang //Specification file.
495f388a3fSLawrence Tang specification_file = argv[i + 1];
505f388a3fSLawrence Tang i++;
515f388a3fSLawrence Tang } else if (strcmp(argv[i], "--no-validate") == 0) {
525f388a3fSLawrence Tang //No validation to be used.
535f388a3fSLawrence Tang //Invalidates specification file.
545f388a3fSLawrence Tang specification_file = NULL;
555f388a3fSLawrence Tang no_validate = 1;
565f388a3fSLawrence Tang } else if (strcmp(argv[i], "--debug") == 0) {
575f388a3fSLawrence Tang //Debug output on.
585f388a3fSLawrence Tang debug = 1;
595f388a3fSLawrence Tang } else {
605f388a3fSLawrence Tang printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
615f388a3fSLawrence Tang argv[i]);
625f388a3fSLawrence Tang }
635f388a3fSLawrence Tang }
6471c70a3dSLawrence Tang
6502c801a5SLawrence Tang //Run the requested command.
66617949e4SLawrence Tang if (strcmp(argv[1], "to-json") == 0) {
67617949e4SLawrence Tang cper_to_json(input_file, output_file, 0);
68617949e4SLawrence Tang } else if (strcmp(argv[1], "to-json-section") == 0) {
69617949e4SLawrence Tang cper_to_json(input_file, output_file, 1);
70617949e4SLawrence Tang } else if (strcmp(argv[1], "to-cper") == 0) {
715f388a3fSLawrence Tang json_to_cper(input_file, output_file, specification_file,
725f388a3fSLawrence Tang argv[0], no_validate, debug);
73617949e4SLawrence Tang } else {
74e407b4c8SLawrence Tang printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
75e407b4c8SLawrence Tang argv[1]);
7602c801a5SLawrence Tang return -1;
7702c801a5SLawrence Tang }
7802c801a5SLawrence Tang
7902c801a5SLawrence Tang return 0;
8002c801a5SLawrence Tang }
8102c801a5SLawrence Tang
82617949e4SLawrence Tang //Command for converting a provided CPER log file or CPER single section file into JSON.
cper_to_json(char * in_file,char * out_file,int is_single_section)83617949e4SLawrence Tang void cper_to_json(char *in_file, char *out_file, int is_single_section)
8402c801a5SLawrence Tang {
8502c801a5SLawrence Tang //Get a handle for the log file.
865f388a3fSLawrence Tang FILE *cper_file = fopen(in_file, "r");
87e407b4c8SLawrence Tang if (cper_file == NULL) {
88e407b4c8SLawrence Tang printf("Could not open provided CPER file '%s', file handle returned null.\n",
895f388a3fSLawrence Tang in_file);
9002c801a5SLawrence Tang return;
9102c801a5SLawrence Tang }
9202c801a5SLawrence Tang
9302c801a5SLawrence Tang //Convert.
94617949e4SLawrence Tang json_object *ir;
95f8fc7052SJohn Chung if (is_single_section) {
96617949e4SLawrence Tang ir = cper_single_section_to_ir(cper_file);
97f8fc7052SJohn Chung } else {
98617949e4SLawrence Tang ir = cper_to_ir(cper_file);
99f8fc7052SJohn Chung }
10002c801a5SLawrence Tang fclose(cper_file);
101617949e4SLawrence Tang
102617949e4SLawrence Tang //Output to string.
103e407b4c8SLawrence Tang const char *json_output =
104e407b4c8SLawrence Tang json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
10502c801a5SLawrence Tang
10602c801a5SLawrence Tang //Check whether there is a "--out" argument, if there is, then output to file instead.
10702c801a5SLawrence Tang //Otherwise, just send to console.
1085f388a3fSLawrence Tang if (out_file == NULL) {
10902c801a5SLawrence Tang printf("%s\n", json_output);
11002c801a5SLawrence Tang return;
11102c801a5SLawrence Tang }
11202c801a5SLawrence Tang
11302c801a5SLawrence Tang //Try to open a file handle to the desired output file.
1145f388a3fSLawrence Tang FILE *json_file = fopen(out_file, "w");
115e407b4c8SLawrence Tang if (json_file == NULL) {
116e407b4c8SLawrence Tang printf("Could not get a handle for output file '%s', file handle returned null.\n",
1175f388a3fSLawrence Tang out_file);
11802c801a5SLawrence Tang return;
11902c801a5SLawrence Tang }
12002c801a5SLawrence Tang
12102c801a5SLawrence Tang //Write out to file.
12202c801a5SLawrence Tang fwrite(json_output, strlen(json_output), 1, json_file);
12302c801a5SLawrence Tang fclose(json_file);
12402c801a5SLawrence Tang }
12502c801a5SLawrence Tang
12602c801a5SLawrence Tang //Command for converting a provided CPER-JSON JSON file to CPER binary.
json_to_cper(char * in_file,char * out_file,char * specification_file,char * program_dir,int no_validate,int debug)1275f388a3fSLawrence Tang void json_to_cper(char *in_file, char *out_file, char *specification_file,
1285f388a3fSLawrence Tang char *program_dir, int no_validate, int debug)
12902c801a5SLawrence Tang {
1305f388a3fSLawrence Tang //Verify output file exists.
1315f388a3fSLawrence Tang if (out_file == NULL) {
1325f388a3fSLawrence Tang printf("No output file provided for 'to-cper'. See 'cper-convert --help' for command information.\n");
13302c801a5SLawrence Tang return;
13402c801a5SLawrence Tang }
13502c801a5SLawrence Tang
13602c801a5SLawrence Tang //Read JSON IR from file.
1375f388a3fSLawrence Tang json_object *ir = json_object_from_file(in_file);
138e407b4c8SLawrence Tang if (ir == NULL) {
139e407b4c8SLawrence Tang printf("Could not read JSON from file '%s', import returned null.\n",
1405f388a3fSLawrence Tang in_file);
14102c801a5SLawrence Tang return;
14202c801a5SLawrence Tang }
14302c801a5SLawrence Tang
14402c801a5SLawrence Tang //Validate the JSON against specification, unless otherwise specified.
1455f388a3fSLawrence Tang if (!no_validate) {
1465f388a3fSLawrence Tang int using_default_spec_path = 0;
14702c801a5SLawrence Tang
148d34f2b11SLawrence Tang //Is there a specification file path?
1495f388a3fSLawrence Tang if (specification_file == NULL) {
1505f388a3fSLawrence Tang using_default_spec_path = 1;
1515f388a3fSLawrence Tang
15202c801a5SLawrence Tang //Make the specification path the assumed default (application directory + specification/cper-json.json).
1535f388a3fSLawrence Tang specification_file = malloc(PATH_MAX);
1545f388a3fSLawrence Tang char *dir = dirname(program_dir);
1555f388a3fSLawrence Tang strcpy(specification_file, dir);
1565f388a3fSLawrence Tang strcat(specification_file,
157e407b4c8SLawrence Tang "/specification/cper-json.json");
15802c801a5SLawrence Tang }
159d34f2b11SLawrence Tang
160d34f2b11SLawrence Tang //Enable debug mode if indicated.
161f8fc7052SJohn Chung if (debug) {
162d34f2b11SLawrence Tang validate_schema_debug_enable();
163f8fc7052SJohn Chung }
16402c801a5SLawrence Tang
16502c801a5SLawrence Tang //Attempt to verify with the the specification.
16602c801a5SLawrence Tang char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN);
1675f388a3fSLawrence Tang int success = validate_schema_from_file(specification_file, ir,
168e407b4c8SLawrence Tang error_message);
16902c801a5SLawrence Tang
17002c801a5SLawrence Tang //Free specification path (if necessary).
171f8fc7052SJohn Chung if (using_default_spec_path) {
1725f388a3fSLawrence Tang free(specification_file);
173f8fc7052SJohn Chung }
17402c801a5SLawrence Tang
17502c801a5SLawrence Tang //If failed, early exit before conversion.
176e407b4c8SLawrence Tang if (!success) {
177e407b4c8SLawrence Tang printf("JSON format validation failed: %s\n",
178e407b4c8SLawrence Tang error_message);
17902c801a5SLawrence Tang free(error_message);
18002c801a5SLawrence Tang return;
18102c801a5SLawrence Tang }
18202c801a5SLawrence Tang free(error_message);
18302c801a5SLawrence Tang }
18402c801a5SLawrence Tang
18502c801a5SLawrence Tang //Open a read for the output file.
1865f388a3fSLawrence Tang FILE *cper_file = fopen(out_file, "w");
187e407b4c8SLawrence Tang if (cper_file == NULL) {
188e407b4c8SLawrence Tang printf("Could not open output file '%s', file handle returned null.\n",
1895f388a3fSLawrence Tang out_file);
19002c801a5SLawrence Tang return;
19102c801a5SLawrence Tang }
19202c801a5SLawrence Tang
193617949e4SLawrence Tang //Detect the type of CPER (full log, single section) from the IR given.
194617949e4SLawrence Tang //Run the converter accordingly.
195f8fc7052SJohn Chung if (json_object_object_get(ir, "header") != NULL) {
19602c801a5SLawrence Tang ir_to_cper(ir, cper_file);
197f8fc7052SJohn Chung } else {
198617949e4SLawrence Tang ir_single_section_to_cper(ir, cper_file);
199f8fc7052SJohn Chung }
20002c801a5SLawrence Tang fclose(cper_file);
201f8fc7052SJohn Chung json_object_put(ir);
20202c801a5SLawrence Tang }
20302c801a5SLawrence Tang
20402c801a5SLawrence Tang //Command for printing help information.
print_help(void)20502c801a5SLawrence Tang void print_help(void)
20602c801a5SLawrence Tang {
20702c801a5SLawrence Tang printf(":: to-json cper.file [--out file.name]\n");
2085f388a3fSLawrence Tang printf("\tConverts the provided CPER log file into JSON, by default writing to stdout. If '--out' is specified,\n");
20902c801a5SLawrence Tang printf("\tThe outputted JSON will be written to the provided file name instead.\n");
210617949e4SLawrence Tang printf("\n:: to-json-section cper.section.file [--out file.name]\n");
211617949e4SLawrence Tang printf("\tConverts the provided single CPER section descriptor & section file into JSON, by default writing to stdout.\n");
212617949e4SLawrence Tang printf("\tOtherwise behaves the same as 'to-json'.\n");
213d34f2b11SLawrence Tang printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
21402c801a5SLawrence Tang printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
215617949e4SLawrence Tang printf("\tWill automatically detect whether the JSON passed is a single section, or a whole file,\n");
216617949e4SLawrence Tang printf("\tand output binary accordingly.\n\n");
21702c801a5SLawrence Tang printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
21802c801a5SLawrence Tang printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
21902c801a5SLawrence Tang printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
220617949e4SLawrence Tang printf("\tpremature exit/unexpected behaviour in CPER output.\n\n");
2215f388a3fSLawrence Tang printf("\tIf '--debug' is set, then debug output for JSON specification parsing will be printed to stdout.\n");
22202c801a5SLawrence Tang printf("\n:: --help\n");
22302c801a5SLawrence Tang printf("\tDisplays help information to the console.\n");
22402c801a5SLawrence Tang }
225