xref: /openbmc/libcper/cli-app/cper-convert.c (revision 71c70a3d)
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 
1602c801a5SLawrence Tang void cper_to_json(int argc, char *argv[]);
1702c801a5SLawrence Tang void json_to_cper(int argc, char *argv[]);
1802c801a5SLawrence Tang void print_help(void);
1902c801a5SLawrence Tang 
2002c801a5SLawrence Tang int main(int argc, char *argv[])
2102c801a5SLawrence Tang {
2202c801a5SLawrence Tang 	//Ensure at least one argument is present.
23e407b4c8SLawrence Tang 	if (argc < 2) {
2402c801a5SLawrence Tang 		printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n");
2502c801a5SLawrence Tang 		return -1;
2602c801a5SLawrence Tang 	}
2702c801a5SLawrence Tang 
28*71c70a3dSLawrence Tang 	//Parse the command line arguments.
29*71c70a3dSLawrence Tang 	char* input_file = NULL;
30*71c70a3dSLawrence Tang 	char* output_file = NULL;
31*71c70a3dSLawrence Tang 
3202c801a5SLawrence Tang 	//Run the requested command.
3302c801a5SLawrence Tang 	if (strcmp(argv[1], "to-json") == 0)
3402c801a5SLawrence Tang 		cper_to_json(argc, argv);
3502c801a5SLawrence Tang 	else if (strcmp(argv[1], "to-cper") == 0)
3602c801a5SLawrence Tang 		json_to_cper(argc, argv);
3702c801a5SLawrence Tang 	else if (strcmp(argv[1], "--help") == 0)
3802c801a5SLawrence Tang 		print_help();
39e407b4c8SLawrence Tang 	else {
40e407b4c8SLawrence Tang 		printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
41e407b4c8SLawrence Tang 		       argv[1]);
4202c801a5SLawrence Tang 		return -1;
4302c801a5SLawrence Tang 	}
4402c801a5SLawrence Tang 
4502c801a5SLawrence Tang 	return 0;
4602c801a5SLawrence Tang }
4702c801a5SLawrence Tang 
4802c801a5SLawrence Tang //Command for converting a provided CPER log file into JSON.
4902c801a5SLawrence Tang void cper_to_json(int argc, char *argv[])
5002c801a5SLawrence Tang {
51e407b4c8SLawrence Tang 	if (argc < 3) {
5202c801a5SLawrence Tang 		printf("Insufficient number of arguments for 'to-json'. See 'cper-convert --help' for command information.\n");
5302c801a5SLawrence Tang 		return;
5402c801a5SLawrence Tang 	}
5502c801a5SLawrence Tang 
5602c801a5SLawrence Tang 	//Get a handle for the log file.
5702c801a5SLawrence Tang 	FILE *cper_file = fopen(argv[2], "r");
58e407b4c8SLawrence Tang 	if (cper_file == NULL) {
59e407b4c8SLawrence Tang 		printf("Could not open provided CPER file '%s', file handle returned null.\n",
60e407b4c8SLawrence Tang 		       argv[2]);
6102c801a5SLawrence Tang 		return;
6202c801a5SLawrence Tang 	}
6302c801a5SLawrence Tang 
6402c801a5SLawrence Tang 	//Convert.
6502c801a5SLawrence Tang 	json_object *ir = cper_to_ir(cper_file);
6602c801a5SLawrence Tang 	fclose(cper_file);
67e407b4c8SLawrence Tang 	const char *json_output =
68e407b4c8SLawrence Tang 		json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
6902c801a5SLawrence Tang 
7002c801a5SLawrence Tang 	//Check whether there is a "--out" argument, if there is, then output to file instead.
7102c801a5SLawrence Tang 	//Otherwise, just send to console.
72e407b4c8SLawrence Tang 	if (argc != 5) {
7302c801a5SLawrence Tang 		printf("%s\n", json_output);
7402c801a5SLawrence Tang 		return;
7502c801a5SLawrence Tang 	}
7602c801a5SLawrence Tang 
7702c801a5SLawrence Tang 	//File out argument exists. Argument valid?
78e407b4c8SLawrence Tang 	if (strcmp(argv[3], "--out") != 0) {
79e407b4c8SLawrence Tang 		printf("Invalid argument '%s' for command 'to-json'. See 'cper-convert --help' for command information.\n",
80e407b4c8SLawrence Tang 		       argv[3]);
8102c801a5SLawrence Tang 		return;
8202c801a5SLawrence Tang 	}
8302c801a5SLawrence Tang 
8402c801a5SLawrence Tang 	//Try to open a file handle to the desired output file.
8502c801a5SLawrence Tang 	FILE *json_file = fopen(argv[4], "w");
86e407b4c8SLawrence Tang 	if (json_file == NULL) {
87e407b4c8SLawrence Tang 		printf("Could not get a handle for output file '%s', file handle returned null.\n",
88e407b4c8SLawrence Tang 		       argv[4]);
8902c801a5SLawrence Tang 		return;
9002c801a5SLawrence Tang 	}
9102c801a5SLawrence Tang 
9202c801a5SLawrence Tang 	//Write out to file.
9302c801a5SLawrence Tang 	fwrite(json_output, strlen(json_output), 1, json_file);
9402c801a5SLawrence Tang 	fclose(json_file);
9502c801a5SLawrence Tang }
9602c801a5SLawrence Tang 
9702c801a5SLawrence Tang //Command for converting a provided CPER-JSON JSON file to CPER binary.
9802c801a5SLawrence Tang void json_to_cper(int argc, char *argv[])
9902c801a5SLawrence Tang {
100e407b4c8SLawrence Tang 	if (argc < 5) {
10102c801a5SLawrence Tang 		printf("Insufficient number of arguments for 'to-cper'. See 'cper-convert --help' for command information.\n");
10202c801a5SLawrence Tang 		return;
10302c801a5SLawrence Tang 	}
10402c801a5SLawrence Tang 
10502c801a5SLawrence Tang 	//Read JSON IR from file.
10602c801a5SLawrence Tang 	json_object *ir = json_object_from_file(argv[2]);
107e407b4c8SLawrence Tang 	if (ir == NULL) {
108e407b4c8SLawrence Tang 		printf("Could not read JSON from file '%s', import returned null.\n",
109e407b4c8SLawrence Tang 		       argv[2]);
11002c801a5SLawrence Tang 		return;
11102c801a5SLawrence Tang 	}
11202c801a5SLawrence Tang 
11302c801a5SLawrence Tang 	//Are we skipping validation?
11402c801a5SLawrence Tang 	int do_validate = 1;
115e407b4c8SLawrence Tang 	if (argc >= 6 && argc < 8) {
116e407b4c8SLawrence Tang 		if (strcmp(argv[5], "--no-validate") == 0) {
11702c801a5SLawrence Tang 			do_validate = 0;
11802c801a5SLawrence Tang 		}
11902c801a5SLawrence Tang 	}
12002c801a5SLawrence Tang 
12102c801a5SLawrence Tang 	//Validate the JSON against specification, unless otherwise specified.
122e407b4c8SLawrence Tang 	if (do_validate) {
12302c801a5SLawrence Tang 		char *specification_path = NULL;
12402c801a5SLawrence Tang 
125d34f2b11SLawrence Tang 		//Is there a specification file path?
126e407b4c8SLawrence Tang 		if (argc >= 7 &&
127e407b4c8SLawrence Tang 		    strcmp(argv[argc - 2], "--specification") == 0) {
128d34f2b11SLawrence Tang 			specification_path = argv[argc - 1];
129e407b4c8SLawrence Tang 		} else {
13002c801a5SLawrence Tang 			//Make the specification path the assumed default (application directory + specification/cper-json.json).
13102c801a5SLawrence Tang 			specification_path = malloc(PATH_MAX);
13202c801a5SLawrence Tang 			char *dir = dirname(argv[0]);
13302c801a5SLawrence Tang 			strcpy(specification_path, dir);
134e407b4c8SLawrence Tang 			strcat(specification_path,
135e407b4c8SLawrence Tang 			       "/specification/cper-json.json");
13602c801a5SLawrence Tang 		}
137d34f2b11SLawrence Tang 
138d34f2b11SLawrence Tang 		//Enable debug mode if indicated.
139e407b4c8SLawrence Tang 		for (int i = 5; i < argc; i++) {
140e407b4c8SLawrence Tang 			if (strcmp(argv[i], "--debug") == 0) {
141d34f2b11SLawrence Tang 				validate_schema_debug_enable();
142d34f2b11SLawrence Tang 				printf("debug enabled.\n");
143d34f2b11SLawrence Tang 				break;
144d34f2b11SLawrence Tang 			}
14502c801a5SLawrence Tang 		}
14602c801a5SLawrence Tang 
14702c801a5SLawrence Tang 		//Attempt to verify with the the specification.
14802c801a5SLawrence Tang 		char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN);
149e407b4c8SLawrence Tang 		int success = validate_schema_from_file(specification_path, ir,
150e407b4c8SLawrence Tang 							error_message);
15102c801a5SLawrence Tang 
15202c801a5SLawrence Tang 		//Free specification path (if necessary).
15302c801a5SLawrence Tang 		if (argc == 5)
15402c801a5SLawrence Tang 			free(specification_path);
15502c801a5SLawrence Tang 
15602c801a5SLawrence Tang 		//If failed, early exit before conversion.
157e407b4c8SLawrence Tang 		if (!success) {
158e407b4c8SLawrence Tang 			printf("JSON format validation failed: %s\n",
159e407b4c8SLawrence Tang 			       error_message);
16002c801a5SLawrence Tang 			free(error_message);
16102c801a5SLawrence Tang 			return;
16202c801a5SLawrence Tang 		}
16302c801a5SLawrence Tang 		free(error_message);
16402c801a5SLawrence Tang 	}
16502c801a5SLawrence Tang 
16602c801a5SLawrence Tang 	//Attempt a conversion.
16702c801a5SLawrence Tang 	//Open a read for the output file.
16802c801a5SLawrence Tang 	FILE *cper_file = fopen(argv[4], "w");
169e407b4c8SLawrence Tang 	if (cper_file == NULL) {
170e407b4c8SLawrence Tang 		printf("Could not open output file '%s', file handle returned null.\n",
171e407b4c8SLawrence Tang 		       argv[4]);
17202c801a5SLawrence Tang 		return;
17302c801a5SLawrence Tang 	}
17402c801a5SLawrence Tang 
17502c801a5SLawrence Tang 	//Run the converter.
17602c801a5SLawrence Tang 	ir_to_cper(ir, cper_file);
17702c801a5SLawrence Tang 	fclose(cper_file);
17802c801a5SLawrence Tang }
17902c801a5SLawrence Tang 
18002c801a5SLawrence Tang //Command for printing help information.
18102c801a5SLawrence Tang void print_help(void)
18202c801a5SLawrence Tang {
18302c801a5SLawrence Tang 	printf(":: to-json cper.file [--out file.name]\n");
18402c801a5SLawrence Tang 	printf("\tConverts the provided CPER log file into JSON, by default outputting to console. If '--out' is specified,\n");
18502c801a5SLawrence Tang 	printf("\tThe outputted JSON will be written to the provided file name instead.\n");
186d34f2b11SLawrence Tang 	printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
18702c801a5SLawrence Tang 	printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
18802c801a5SLawrence Tang 	printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
18902c801a5SLawrence Tang 	printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
19002c801a5SLawrence Tang 	printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
19102c801a5SLawrence Tang 	printf("\tpremature exit/unexpected behaviour in CPER output.\n");
19202c801a5SLawrence Tang 	printf("\n:: --help\n");
19302c801a5SLawrence Tang 	printf("\tDisplays help information to the console.\n");
19402c801a5SLawrence Tang }