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 <libcper/cper-parse.h> 14 #include <libcper/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 } 100 fclose(cper_file); 101 102 //Output to string. 103 const char *json_output = 104 json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY); 105 106 //Check whether there is a "--out" argument, if there is, then output to file instead. 107 //Otherwise, just send to console. 108 if (out_file == NULL) { 109 printf("%s\n", json_output); 110 return; 111 } 112 113 //Try to open a file handle to the desired output file. 114 FILE *json_file = fopen(out_file, "w"); 115 if (json_file == NULL) { 116 printf("Could not get a handle for output file '%s', file handle returned null.\n", 117 out_file); 118 return; 119 } 120 121 //Write out to file. 122 fwrite(json_output, strlen(json_output), 1, json_file); 123 fclose(json_file); 124 } 125 126 //Command for converting a provided CPER-JSON JSON file to CPER binary. 127 void json_to_cper(char *in_file, char *out_file, char *specification_file, 128 char *program_dir, int no_validate, int debug) 129 { 130 //Verify output file exists. 131 if (out_file == NULL) { 132 printf("No output file provided for 'to-cper'. See 'cper-convert --help' for command information.\n"); 133 return; 134 } 135 136 //Read JSON IR from file. 137 json_object *ir = json_object_from_file(in_file); 138 if (ir == NULL) { 139 printf("Could not read JSON from file '%s', import returned null.\n", 140 in_file); 141 return; 142 } 143 144 //Validate the JSON against specification, unless otherwise specified. 145 if (!no_validate) { 146 int using_default_spec_path = 0; 147 148 //Is there a specification file path? 149 if (specification_file == NULL) { 150 using_default_spec_path = 1; 151 152 //Make the specification path the assumed default (application directory + specification/cper-json.json). 153 specification_file = malloc(PATH_MAX); 154 char *dir = dirname(program_dir); 155 strcpy(specification_file, dir); 156 strcat(specification_file, 157 "/specification/cper-json.json"); 158 } 159 160 //Enable debug mode if indicated. 161 if (debug) { 162 validate_schema_debug_enable(); 163 } 164 165 //Attempt to verify with the the specification. 166 char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN); 167 int success = validate_schema_from_file(specification_file, ir, 168 error_message); 169 170 //Free specification path (if necessary). 171 if (using_default_spec_path) { 172 free(specification_file); 173 } 174 175 //If failed, early exit before conversion. 176 if (!success) { 177 printf("JSON format validation failed: %s\n", 178 error_message); 179 free(error_message); 180 return; 181 } 182 free(error_message); 183 } 184 185 //Open a read for the output file. 186 FILE *cper_file = fopen(out_file, "w"); 187 if (cper_file == NULL) { 188 printf("Could not open output file '%s', file handle returned null.\n", 189 out_file); 190 return; 191 } 192 193 //Detect the type of CPER (full log, single section) from the IR given. 194 //Run the converter accordingly. 195 if (json_object_object_get(ir, "header") != NULL) { 196 ir_to_cper(ir, cper_file); 197 } else { 198 ir_single_section_to_cper(ir, cper_file); 199 } 200 fclose(cper_file); 201 json_object_put(ir); 202 } 203 204 //Command for printing help information. 205 void print_help(void) 206 { 207 printf(":: to-json cper.file [--out file.name]\n"); 208 printf("\tConverts the provided CPER log file into JSON, by default writing to stdout. If '--out' is specified,\n"); 209 printf("\tThe outputted JSON will be written to the provided file name instead.\n"); 210 printf("\n:: to-json-section cper.section.file [--out file.name]\n"); 211 printf("\tConverts the provided single CPER section descriptor & section file into JSON, by default writing to stdout.\n"); 212 printf("\tOtherwise behaves the same as 'to-json'.\n"); 213 printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n"); 214 printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n"); 215 printf("\tWill automatically detect whether the JSON passed is a single section, or a whole file,\n"); 216 printf("\tand output binary accordingly.\n\n"); 217 printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n"); 218 printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n"); 219 printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n"); 220 printf("\tpremature exit/unexpected behaviour in CPER output.\n\n"); 221 printf("\tIf '--debug' is set, then debug output for JSON specification parsing will be printed to stdout.\n"); 222 printf("\n:: --help\n"); 223 printf("\tDisplays help information to the console.\n"); 224 } 225