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*f8fc7052SJohn Chung #include <linux/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 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. 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; 95*f8fc7052SJohn Chung if (is_single_section) { 96617949e4SLawrence Tang ir = cper_single_section_to_ir(cper_file); 97*f8fc7052SJohn Chung } else { 98617949e4SLawrence Tang ir = cper_to_ir(cper_file); 99*f8fc7052SJohn 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. 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. 161*f8fc7052SJohn Chung if (debug) { 162d34f2b11SLawrence Tang validate_schema_debug_enable(); 163*f8fc7052SJohn 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). 171*f8fc7052SJohn Chung if (using_default_spec_path) { 1725f388a3fSLawrence Tang free(specification_file); 173*f8fc7052SJohn 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. 195*f8fc7052SJohn Chung if (json_object_object_get(ir, "header") != NULL) { 19602c801a5SLawrence Tang ir_to_cper(ir, cper_file); 197*f8fc7052SJohn Chung } else { 198617949e4SLawrence Tang ir_single_section_to_cper(ir, cper_file); 199*f8fc7052SJohn Chung } 20002c801a5SLawrence Tang fclose(cper_file); 201*f8fc7052SJohn Chung json_object_put(ir); 20202c801a5SLawrence Tang } 20302c801a5SLawrence Tang 20402c801a5SLawrence Tang //Command for printing help information. 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