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
main(int argc,char * argv[])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.
cper_to_json(char * in_file,char * out_file,int is_single_section)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.
json_to_cper(char * in_file,char * out_file,char * specification_file,char * program_dir,int no_validate,int debug)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.
print_help(void)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