xref: /openbmc/libcper/cli-app/cper-convert.c (revision 5f388a3f)
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>
1102c801a5SLawrence Tang #include <limits.h>
1202c801a5SLawrence Tang #include "json.h"
1302c801a5SLawrence Tang #include "../cper-parse.h"
1402c801a5SLawrence Tang #include "../json-schema.h"
1502c801a5SLawrence Tang 
16*5f388a3fSLawrence Tang void cper_to_json(char *in_file, char *out_file);
17*5f388a3fSLawrence Tang void json_to_cper(char *in_file, char *out_file, char *specification_file,
18*5f388a3fSLawrence 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 {
23*5f388a3fSLawrence Tang 	//Print help if requested.
24*5f388a3fSLawrence Tang 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
25*5f388a3fSLawrence Tang 		print_help();
26*5f388a3fSLawrence Tang 		return 0;
27*5f388a3fSLawrence Tang 	}
28*5f388a3fSLawrence Tang 
29*5f388a3fSLawrence Tang 	//Ensure at least two arguments are present.
30*5f388a3fSLawrence 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.
36*5f388a3fSLawrence Tang 	char *input_file = argv[2];
3771c70a3dSLawrence Tang 	char *output_file = NULL;
38*5f388a3fSLawrence Tang 	char *specification_file = NULL;
39*5f388a3fSLawrence Tang 	int no_validate = 0;
40*5f388a3fSLawrence Tang 	int debug = 0;
41*5f388a3fSLawrence Tang 	for (int i = 3; i < argc; i++) {
42*5f388a3fSLawrence Tang 		if (strcmp(argv[i], "--out") == 0 && i < argc - 1) {
43*5f388a3fSLawrence Tang 			//Output file.
44*5f388a3fSLawrence Tang 			output_file = argv[i + 1];
45*5f388a3fSLawrence Tang 			i++;
46*5f388a3fSLawrence Tang 		} else if (strcmp(argv[i], "--specification") == 0 &&
47*5f388a3fSLawrence Tang 			   i < argc - 1) {
48*5f388a3fSLawrence Tang 			//Specification file.
49*5f388a3fSLawrence Tang 			specification_file = argv[i + 1];
50*5f388a3fSLawrence Tang 			i++;
51*5f388a3fSLawrence Tang 		} else if (strcmp(argv[i], "--no-validate") == 0) {
52*5f388a3fSLawrence Tang 			//No validation to be used.
53*5f388a3fSLawrence Tang 			//Invalidates specification file.
54*5f388a3fSLawrence Tang 			specification_file = NULL;
55*5f388a3fSLawrence Tang 			no_validate = 1;
56*5f388a3fSLawrence Tang 		} else if (strcmp(argv[i], "--debug") == 0) {
57*5f388a3fSLawrence Tang 			//Debug output on.
58*5f388a3fSLawrence Tang 			debug = 1;
59*5f388a3fSLawrence Tang 		} else {
60*5f388a3fSLawrence Tang 			printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
61*5f388a3fSLawrence Tang 			       argv[i]);
62*5f388a3fSLawrence Tang 		}
63*5f388a3fSLawrence Tang 	}
6471c70a3dSLawrence Tang 
6502c801a5SLawrence Tang 	//Run the requested command.
6602c801a5SLawrence Tang 	if (strcmp(argv[1], "to-json") == 0)
67*5f388a3fSLawrence Tang 		cper_to_json(input_file, output_file);
6802c801a5SLawrence Tang 	else if (strcmp(argv[1], "to-cper") == 0)
69*5f388a3fSLawrence Tang 		json_to_cper(input_file, output_file, specification_file,
70*5f388a3fSLawrence Tang 			     argv[0], no_validate, debug);
71e407b4c8SLawrence Tang 	else {
72e407b4c8SLawrence Tang 		printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
73e407b4c8SLawrence Tang 		       argv[1]);
7402c801a5SLawrence Tang 		return -1;
7502c801a5SLawrence Tang 	}
7602c801a5SLawrence Tang 
7702c801a5SLawrence Tang 	return 0;
7802c801a5SLawrence Tang }
7902c801a5SLawrence Tang 
8002c801a5SLawrence Tang //Command for converting a provided CPER log file into JSON.
81*5f388a3fSLawrence Tang void cper_to_json(char *in_file, char *out_file)
8202c801a5SLawrence Tang {
8302c801a5SLawrence Tang 	//Get a handle for the log file.
84*5f388a3fSLawrence Tang 	FILE *cper_file = fopen(in_file, "r");
85e407b4c8SLawrence Tang 	if (cper_file == NULL) {
86e407b4c8SLawrence Tang 		printf("Could not open provided CPER file '%s', file handle returned null.\n",
87*5f388a3fSLawrence Tang 		       in_file);
8802c801a5SLawrence Tang 		return;
8902c801a5SLawrence Tang 	}
9002c801a5SLawrence Tang 
9102c801a5SLawrence Tang 	//Convert.
9202c801a5SLawrence Tang 	json_object *ir = cper_to_ir(cper_file);
9302c801a5SLawrence Tang 	fclose(cper_file);
94e407b4c8SLawrence Tang 	const char *json_output =
95e407b4c8SLawrence Tang 		json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
9602c801a5SLawrence Tang 
9702c801a5SLawrence Tang 	//Check whether there is a "--out" argument, if there is, then output to file instead.
9802c801a5SLawrence Tang 	//Otherwise, just send to console.
99*5f388a3fSLawrence Tang 	if (out_file == NULL) {
10002c801a5SLawrence Tang 		printf("%s\n", json_output);
10102c801a5SLawrence Tang 		return;
10202c801a5SLawrence Tang 	}
10302c801a5SLawrence Tang 
10402c801a5SLawrence Tang 	//Try to open a file handle to the desired output file.
105*5f388a3fSLawrence Tang 	FILE *json_file = fopen(out_file, "w");
106e407b4c8SLawrence Tang 	if (json_file == NULL) {
107e407b4c8SLawrence Tang 		printf("Could not get a handle for output file '%s', file handle returned null.\n",
108*5f388a3fSLawrence Tang 		       out_file);
10902c801a5SLawrence Tang 		return;
11002c801a5SLawrence Tang 	}
11102c801a5SLawrence Tang 
11202c801a5SLawrence Tang 	//Write out to file.
11302c801a5SLawrence Tang 	fwrite(json_output, strlen(json_output), 1, json_file);
11402c801a5SLawrence Tang 	fclose(json_file);
11502c801a5SLawrence Tang }
11602c801a5SLawrence Tang 
11702c801a5SLawrence Tang //Command for converting a provided CPER-JSON JSON file to CPER binary.
118*5f388a3fSLawrence Tang void json_to_cper(char *in_file, char *out_file, char *specification_file,
119*5f388a3fSLawrence Tang 		  char *program_dir, int no_validate, int debug)
12002c801a5SLawrence Tang {
121*5f388a3fSLawrence Tang 	//Verify output file exists.
122*5f388a3fSLawrence Tang 	if (out_file == NULL) {
123*5f388a3fSLawrence Tang 		printf("No output file provided for 'to-cper'. See 'cper-convert --help' for command information.\n");
12402c801a5SLawrence Tang 		return;
12502c801a5SLawrence Tang 	}
12602c801a5SLawrence Tang 
12702c801a5SLawrence Tang 	//Read JSON IR from file.
128*5f388a3fSLawrence Tang 	json_object *ir = json_object_from_file(in_file);
129e407b4c8SLawrence Tang 	if (ir == NULL) {
130e407b4c8SLawrence Tang 		printf("Could not read JSON from file '%s', import returned null.\n",
131*5f388a3fSLawrence Tang 		       in_file);
13202c801a5SLawrence Tang 		return;
13302c801a5SLawrence Tang 	}
13402c801a5SLawrence Tang 
13502c801a5SLawrence Tang 	//Validate the JSON against specification, unless otherwise specified.
136*5f388a3fSLawrence Tang 	if (!no_validate) {
137*5f388a3fSLawrence Tang 		int using_default_spec_path = 0;
13802c801a5SLawrence Tang 
139d34f2b11SLawrence Tang 		//Is there a specification file path?
140*5f388a3fSLawrence Tang 		if (specification_file == NULL) {
141*5f388a3fSLawrence Tang 			using_default_spec_path = 1;
142*5f388a3fSLawrence Tang 
14302c801a5SLawrence Tang 			//Make the specification path the assumed default (application directory + specification/cper-json.json).
144*5f388a3fSLawrence Tang 			specification_file = malloc(PATH_MAX);
145*5f388a3fSLawrence Tang 			char *dir = dirname(program_dir);
146*5f388a3fSLawrence Tang 			strcpy(specification_file, dir);
147*5f388a3fSLawrence Tang 			strcat(specification_file,
148e407b4c8SLawrence Tang 			       "/specification/cper-json.json");
14902c801a5SLawrence Tang 		}
150d34f2b11SLawrence Tang 
151d34f2b11SLawrence Tang 		//Enable debug mode if indicated.
152*5f388a3fSLawrence Tang 		if (debug)
153d34f2b11SLawrence Tang 			validate_schema_debug_enable();
15402c801a5SLawrence Tang 
15502c801a5SLawrence Tang 		//Attempt to verify with the the specification.
15602c801a5SLawrence Tang 		char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN);
157*5f388a3fSLawrence Tang 		int success = validate_schema_from_file(specification_file, ir,
158e407b4c8SLawrence Tang 							error_message);
15902c801a5SLawrence Tang 
16002c801a5SLawrence Tang 		//Free specification path (if necessary).
161*5f388a3fSLawrence Tang 		if (using_default_spec_path)
162*5f388a3fSLawrence Tang 			free(specification_file);
16302c801a5SLawrence Tang 
16402c801a5SLawrence Tang 		//If failed, early exit before conversion.
165e407b4c8SLawrence Tang 		if (!success) {
166e407b4c8SLawrence Tang 			printf("JSON format validation failed: %s\n",
167e407b4c8SLawrence Tang 			       error_message);
16802c801a5SLawrence Tang 			free(error_message);
16902c801a5SLawrence Tang 			return;
17002c801a5SLawrence Tang 		}
17102c801a5SLawrence Tang 		free(error_message);
17202c801a5SLawrence Tang 	}
17302c801a5SLawrence Tang 
17402c801a5SLawrence Tang 	//Attempt a conversion.
17502c801a5SLawrence Tang 	//Open a read for the output file.
176*5f388a3fSLawrence Tang 	FILE *cper_file = fopen(out_file, "w");
177e407b4c8SLawrence Tang 	if (cper_file == NULL) {
178e407b4c8SLawrence Tang 		printf("Could not open output file '%s', file handle returned null.\n",
179*5f388a3fSLawrence Tang 		       out_file);
18002c801a5SLawrence Tang 		return;
18102c801a5SLawrence Tang 	}
18202c801a5SLawrence Tang 
18302c801a5SLawrence Tang 	//Run the converter.
18402c801a5SLawrence Tang 	ir_to_cper(ir, cper_file);
18502c801a5SLawrence Tang 	fclose(cper_file);
18602c801a5SLawrence Tang }
18702c801a5SLawrence Tang 
18802c801a5SLawrence Tang //Command for printing help information.
18902c801a5SLawrence Tang void print_help(void)
19002c801a5SLawrence Tang {
19102c801a5SLawrence Tang 	printf(":: to-json cper.file [--out file.name]\n");
192*5f388a3fSLawrence Tang 	printf("\tConverts the provided CPER log file into JSON, by default writing to stdout. If '--out' is specified,\n");
19302c801a5SLawrence Tang 	printf("\tThe outputted JSON will be written to the provided file name instead.\n");
194d34f2b11SLawrence Tang 	printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
19502c801a5SLawrence Tang 	printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
19602c801a5SLawrence Tang 	printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
19702c801a5SLawrence Tang 	printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
19802c801a5SLawrence Tang 	printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
19902c801a5SLawrence Tang 	printf("\tpremature exit/unexpected behaviour in CPER output.\n");
200*5f388a3fSLawrence Tang 	printf("\tIf '--debug' is set, then debug output for JSON specification parsing will be printed to stdout.\n");
20102c801a5SLawrence Tang 	printf("\n:: --help\n");
20202c801a5SLawrence Tang 	printf("\tDisplays help information to the console.\n");
20302c801a5SLawrence Tang }