xref: /openbmc/libcper/cli-app/cper-convert.c (revision 71c70a3d)
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(int argc, char *argv[]);
17 void json_to_cper(int argc, char *argv[]);
18 void print_help(void);
19 
20 int main(int argc, char *argv[])
21 {
22 	//Ensure at least one argument is present.
23 	if (argc < 2) {
24 		printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n");
25 		return -1;
26 	}
27 
28 	//Parse the command line arguments.
29 	char* input_file = NULL;
30 	char* output_file = NULL;
31 
32 	//Run the requested command.
33 	if (strcmp(argv[1], "to-json") == 0)
34 		cper_to_json(argc, argv);
35 	else if (strcmp(argv[1], "to-cper") == 0)
36 		json_to_cper(argc, argv);
37 	else if (strcmp(argv[1], "--help") == 0)
38 		print_help();
39 	else {
40 		printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
41 		       argv[1]);
42 		return -1;
43 	}
44 
45 	return 0;
46 }
47 
48 //Command for converting a provided CPER log file into JSON.
49 void cper_to_json(int argc, char *argv[])
50 {
51 	if (argc < 3) {
52 		printf("Insufficient number of arguments for 'to-json'. See 'cper-convert --help' for command information.\n");
53 		return;
54 	}
55 
56 	//Get a handle for the log file.
57 	FILE *cper_file = fopen(argv[2], "r");
58 	if (cper_file == NULL) {
59 		printf("Could not open provided CPER file '%s', file handle returned null.\n",
60 		       argv[2]);
61 		return;
62 	}
63 
64 	//Convert.
65 	json_object *ir = cper_to_ir(cper_file);
66 	fclose(cper_file);
67 	const char *json_output =
68 		json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
69 
70 	//Check whether there is a "--out" argument, if there is, then output to file instead.
71 	//Otherwise, just send to console.
72 	if (argc != 5) {
73 		printf("%s\n", json_output);
74 		return;
75 	}
76 
77 	//File out argument exists. Argument valid?
78 	if (strcmp(argv[3], "--out") != 0) {
79 		printf("Invalid argument '%s' for command 'to-json'. See 'cper-convert --help' for command information.\n",
80 		       argv[3]);
81 		return;
82 	}
83 
84 	//Try to open a file handle to the desired output file.
85 	FILE *json_file = fopen(argv[4], "w");
86 	if (json_file == NULL) {
87 		printf("Could not get a handle for output file '%s', file handle returned null.\n",
88 		       argv[4]);
89 		return;
90 	}
91 
92 	//Write out to file.
93 	fwrite(json_output, strlen(json_output), 1, json_file);
94 	fclose(json_file);
95 }
96 
97 //Command for converting a provided CPER-JSON JSON file to CPER binary.
98 void json_to_cper(int argc, char *argv[])
99 {
100 	if (argc < 5) {
101 		printf("Insufficient number of arguments for 'to-cper'. See 'cper-convert --help' for command information.\n");
102 		return;
103 	}
104 
105 	//Read JSON IR from file.
106 	json_object *ir = json_object_from_file(argv[2]);
107 	if (ir == NULL) {
108 		printf("Could not read JSON from file '%s', import returned null.\n",
109 		       argv[2]);
110 		return;
111 	}
112 
113 	//Are we skipping validation?
114 	int do_validate = 1;
115 	if (argc >= 6 && argc < 8) {
116 		if (strcmp(argv[5], "--no-validate") == 0) {
117 			do_validate = 0;
118 		}
119 	}
120 
121 	//Validate the JSON against specification, unless otherwise specified.
122 	if (do_validate) {
123 		char *specification_path = NULL;
124 
125 		//Is there a specification file path?
126 		if (argc >= 7 &&
127 		    strcmp(argv[argc - 2], "--specification") == 0) {
128 			specification_path = argv[argc - 1];
129 		} else {
130 			//Make the specification path the assumed default (application directory + specification/cper-json.json).
131 			specification_path = malloc(PATH_MAX);
132 			char *dir = dirname(argv[0]);
133 			strcpy(specification_path, dir);
134 			strcat(specification_path,
135 			       "/specification/cper-json.json");
136 		}
137 
138 		//Enable debug mode if indicated.
139 		for (int i = 5; i < argc; i++) {
140 			if (strcmp(argv[i], "--debug") == 0) {
141 				validate_schema_debug_enable();
142 				printf("debug enabled.\n");
143 				break;
144 			}
145 		}
146 
147 		//Attempt to verify with the the specification.
148 		char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN);
149 		int success = validate_schema_from_file(specification_path, ir,
150 							error_message);
151 
152 		//Free specification path (if necessary).
153 		if (argc == 5)
154 			free(specification_path);
155 
156 		//If failed, early exit before conversion.
157 		if (!success) {
158 			printf("JSON format validation failed: %s\n",
159 			       error_message);
160 			free(error_message);
161 			return;
162 		}
163 		free(error_message);
164 	}
165 
166 	//Attempt a conversion.
167 	//Open a read for the output file.
168 	FILE *cper_file = fopen(argv[4], "w");
169 	if (cper_file == NULL) {
170 		printf("Could not open output file '%s', file handle returned null.\n",
171 		       argv[4]);
172 		return;
173 	}
174 
175 	//Run the converter.
176 	ir_to_cper(ir, cper_file);
177 	fclose(cper_file);
178 }
179 
180 //Command for printing help information.
181 void print_help(void)
182 {
183 	printf(":: to-json cper.file [--out file.name]\n");
184 	printf("\tConverts the provided CPER log file into JSON, by default outputting to console. If '--out' is specified,\n");
185 	printf("\tThe outputted JSON will be written to the provided file name instead.\n");
186 	printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
187 	printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
188 	printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
189 	printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
190 	printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
191 	printf("\tpremature exit/unexpected behaviour in CPER output.\n");
192 	printf("\n:: --help\n");
193 	printf("\tDisplays help information to the console.\n");
194 }