1 /** 2 * A user-space application linking to the CPER-JSON conversion library which allows for easy 3 * conversion between CPER and CPER-JSON formats. 4 * 5 * Author: Lawrence.Tang@arm.com 6 **/ 7 8 #include <stdio.h> 9 #include <string.h> 10 #include <libgen.h> 11 #include <limits.h> 12 #include <json.h> 13 #include "../cper-parse.h" 14 #include "../json-schema.h" 15 16 void cper_to_json(char *in_file, char *out_file, int is_single_section); 17 void json_to_cper(char *in_file, char *out_file, char *specification_file, 18 char *program_dir, int no_validate, int debug); 19 void print_help(void); 20 21 int main(int argc, char *argv[]) 22 { 23 //Print help if requested. 24 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 25 print_help(); 26 return 0; 27 } 28 29 //Ensure at least two arguments are present. 30 if (argc < 3) { 31 printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n"); 32 return -1; 33 } 34 35 //Parse the command line arguments. 36 char *input_file = argv[2]; 37 char *output_file = NULL; 38 char *specification_file = NULL; 39 int no_validate = 0; 40 int debug = 0; 41 for (int i = 3; i < argc; i++) { 42 if (strcmp(argv[i], "--out") == 0 && i < argc - 1) { 43 //Output file. 44 output_file = argv[i + 1]; 45 i++; 46 } else if (strcmp(argv[i], "--specification") == 0 && 47 i < argc - 1) { 48 //Specification file. 49 specification_file = argv[i + 1]; 50 i++; 51 } else if (strcmp(argv[i], "--no-validate") == 0) { 52 //No validation to be used. 53 //Invalidates specification file. 54 specification_file = NULL; 55 no_validate = 1; 56 } else if (strcmp(argv[i], "--debug") == 0) { 57 //Debug output on. 58 debug = 1; 59 } else { 60 printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n", 61 argv[i]); 62 } 63 } 64 65 //Run the requested command. 66 if (strcmp(argv[1], "to-json") == 0) { 67 cper_to_json(input_file, output_file, 0); 68 } else if (strcmp(argv[1], "to-json-section") == 0) { 69 cper_to_json(input_file, output_file, 1); 70 } else if (strcmp(argv[1], "to-cper") == 0) { 71 json_to_cper(input_file, output_file, specification_file, 72 argv[0], no_validate, debug); 73 } else { 74 printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n", 75 argv[1]); 76 return -1; 77 } 78 79 return 0; 80 } 81 82 //Command for converting a provided CPER log file or CPER single section file into JSON. 83 void cper_to_json(char *in_file, char *out_file, int is_single_section) 84 { 85 //Get a handle for the log file. 86 FILE *cper_file = fopen(in_file, "r"); 87 if (cper_file == NULL) { 88 printf("Could not open provided CPER file '%s', file handle returned null.\n", 89 in_file); 90 return; 91 } 92 93 //Convert. 94 json_object *ir; 95 if (is_single_section) 96 ir = cper_single_section_to_ir(cper_file); 97 else 98 ir = cper_to_ir(cper_file); 99 fclose(cper_file); 100 101 //Output to string. 102 const char *json_output = 103 json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY); 104 105 //Check whether there is a "--out" argument, if there is, then output to file instead. 106 //Otherwise, just send to console. 107 if (out_file == NULL) { 108 printf("%s\n", json_output); 109 return; 110 } 111 112 //Try to open a file handle to the desired output file. 113 FILE *json_file = fopen(out_file, "w"); 114 if (json_file == NULL) { 115 printf("Could not get a handle for output file '%s', file handle returned null.\n", 116 out_file); 117 return; 118 } 119 120 //Write out to file. 121 fwrite(json_output, strlen(json_output), 1, json_file); 122 fclose(json_file); 123 } 124 125 //Command for converting a provided CPER-JSON JSON file to CPER binary. 126 void json_to_cper(char *in_file, char *out_file, char *specification_file, 127 char *program_dir, int no_validate, int debug) 128 { 129 //Verify output file exists. 130 if (out_file == NULL) { 131 printf("No output file provided for 'to-cper'. See 'cper-convert --help' for command information.\n"); 132 return; 133 } 134 135 //Read JSON IR from file. 136 json_object *ir = json_object_from_file(in_file); 137 if (ir == NULL) { 138 printf("Could not read JSON from file '%s', import returned null.\n", 139 in_file); 140 return; 141 } 142 143 //Validate the JSON against specification, unless otherwise specified. 144 if (!no_validate) { 145 int using_default_spec_path = 0; 146 147 //Is there a specification file path? 148 if (specification_file == NULL) { 149 using_default_spec_path = 1; 150 151 //Make the specification path the assumed default (application directory + specification/cper-json.json). 152 specification_file = malloc(PATH_MAX); 153 char *dir = dirname(program_dir); 154 strcpy(specification_file, dir); 155 strcat(specification_file, 156 "/specification/cper-json.json"); 157 } 158 159 //Enable debug mode if indicated. 160 if (debug) 161 validate_schema_debug_enable(); 162 163 //Attempt to verify with the the specification. 164 char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN); 165 int success = validate_schema_from_file(specification_file, ir, 166 error_message); 167 168 //Free specification path (if necessary). 169 if (using_default_spec_path) 170 free(specification_file); 171 172 //If failed, early exit before conversion. 173 if (!success) { 174 printf("JSON format validation failed: %s\n", 175 error_message); 176 free(error_message); 177 return; 178 } 179 free(error_message); 180 } 181 182 //Open a read for the output file. 183 FILE *cper_file = fopen(out_file, "w"); 184 if (cper_file == NULL) { 185 printf("Could not open output file '%s', file handle returned null.\n", 186 out_file); 187 return; 188 } 189 190 //Detect the type of CPER (full log, single section) from the IR given. 191 //Run the converter accordingly. 192 if (json_object_object_get(ir, "header") != NULL) 193 ir_to_cper(ir, cper_file); 194 else 195 ir_single_section_to_cper(ir, cper_file); 196 fclose(cper_file); 197 } 198 199 //Command for printing help information. 200 void print_help(void) 201 { 202 printf(":: to-json cper.file [--out file.name]\n"); 203 printf("\tConverts the provided CPER log file into JSON, by default writing to stdout. If '--out' is specified,\n"); 204 printf("\tThe outputted JSON will be written to the provided file name instead.\n"); 205 printf("\n:: to-json-section cper.section.file [--out file.name]\n"); 206 printf("\tConverts the provided single CPER section descriptor & section file into JSON, by default writing to stdout.\n"); 207 printf("\tOtherwise behaves the same as 'to-json'.\n"); 208 printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n"); 209 printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n"); 210 printf("\tWill automatically detect whether the JSON passed is a single section, or a whole file,\n"); 211 printf("\tand output binary accordingly.\n\n"); 212 printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n"); 213 printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n"); 214 printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n"); 215 printf("\tpremature exit/unexpected behaviour in CPER output.\n\n"); 216 printf("\tIf '--debug' is set, then debug output for JSON specification parsing will be printed to stdout.\n"); 217 printf("\n:: --help\n"); 218 printf("\tDisplays help information to the console.\n"); 219 }