xref: /openbmc/libcper/cli-app/cper-convert.c (revision 54640298880d9478f0eaed21a8d8ab642887b315)
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/log.h>
14 #include <libcper/cper-parse.h>
15 #include <libcper/json-schema.h>
16 
17 void cper_to_json(char *in_file, char *out_file, int is_single_section);
18 void json_to_cper(const char *in_file, const char *out_file);
19 void print_help(void);
20 
21 int main(int argc, char *argv[])
22 {
23 	cper_set_log_stdio();
24 	//Print help if requested.
25 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
26 		print_help();
27 		return 0;
28 	}
29 
30 	//Ensure at least two arguments are present.
31 	if (argc < 3) {
32 		printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n");
33 		return -1;
34 	}
35 
36 	//Parse the command line arguments.
37 	char *input_file = argv[2];
38 	char *output_file = NULL;
39 	char *specification_file = NULL;
40 	int no_validate = 0;
41 	int debug = 0;
42 	for (int i = 3; i < argc; i++) {
43 		if (strcmp(argv[i], "--out") == 0 && i < argc - 1) {
44 			//Output file.
45 			output_file = argv[i + 1];
46 			i++;
47 		} else if (strcmp(argv[i], "--specification") == 0 &&
48 			   i < argc - 1) {
49 			//Specification file.
50 			specification_file = argv[i + 1];
51 			i++;
52 		} else if (strcmp(argv[i], "--no-validate") == 0) {
53 			//No validation to be used.
54 			//Invalidates specification file.
55 			specification_file = NULL;
56 			no_validate = 1;
57 		} else if (strcmp(argv[i], "--debug") == 0) {
58 			//Debug output on.
59 			debug = 1;
60 		} else {
61 			printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
62 			       argv[i]);
63 		}
64 	}
65 
66 	// Debug is not used at the moment.  Leave for compatibility.
67 	(void)debug;
68 	(void)no_validate;
69 	(void)specification_file;
70 	//Run the requested command.
71 	if (strcmp(argv[1], "to-json") == 0) {
72 		cper_to_json(input_file, output_file, 0);
73 	} else if (strcmp(argv[1], "to-json-section") == 0) {
74 		cper_to_json(input_file, output_file, 1);
75 	} else if (strcmp(argv[1], "to-cper") == 0) {
76 		json_to_cper(input_file, output_file);
77 	} else {
78 		printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
79 		       argv[1]);
80 		return -1;
81 	}
82 
83 	return 0;
84 }
85 
86 //Command for converting a provided CPER log file or CPER single section file into JSON.
87 void cper_to_json(char *in_file, char *out_file, int is_single_section)
88 {
89 	//Get a handle for the log file.
90 	FILE *cper_file = fopen(in_file, "r");
91 	if (cper_file == NULL) {
92 		printf("Could not open provided CPER file '%s', file handle returned null.\n",
93 		       in_file);
94 		return;
95 	}
96 
97 	//Convert.
98 	json_object *ir;
99 	if (is_single_section) {
100 		ir = cper_single_section_to_ir(cper_file);
101 	} else {
102 		ir = cper_to_ir(cper_file);
103 	}
104 	fclose(cper_file);
105 
106 	//Output to string.
107 	const char *json_output =
108 		json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
109 
110 	//Check whether there is a "--out" argument, if there is, then output to file instead.
111 	//Otherwise, just send to console.
112 	if (out_file == NULL) {
113 		printf("%s\n", json_output);
114 		return;
115 	}
116 
117 	//Try to open a file handle to the desired output file.
118 	FILE *json_file = fopen(out_file, "w");
119 	if (json_file == NULL) {
120 		printf("Could not get a handle for output file '%s', file handle returned null.\n",
121 		       out_file);
122 		return;
123 	}
124 
125 	//Write out to file.
126 	fwrite(json_output, strlen(json_output), 1, json_file);
127 	fclose(json_file);
128 }
129 
130 //Command for converting a provided CPER-JSON JSON file to CPER binary.
131 void json_to_cper(const char *in_file, const char *out_file)
132 {
133 	//Verify output file exists.
134 	if (out_file == NULL) {
135 		printf("No output file provided for 'to-cper'. See 'cper-convert --help' for command information.\n");
136 		return;
137 	}
138 
139 	//Read JSON IR from file.
140 	json_object *ir = json_object_from_file(in_file);
141 	if (ir == NULL) {
142 		printf("Could not read JSON from file '%s', import returned null.\n",
143 		       in_file);
144 		return;
145 	}
146 
147 	//Open a read for the output file.
148 	FILE *cper_file = fopen(out_file, "w");
149 	if (cper_file == NULL) {
150 		printf("Could not open output file '%s', file handle returned null.\n",
151 		       out_file);
152 		json_object_put(ir);
153 		return;
154 	}
155 
156 	//Detect the type of CPER (full log, single section) from the IR given.
157 	//Run the converter accordingly.
158 	if (json_object_object_get(ir, "header") != NULL) {
159 		ir_to_cper(ir, cper_file);
160 	} else {
161 		ir_single_section_to_cper(ir, cper_file);
162 	}
163 	fclose(cper_file);
164 	json_object_put(ir);
165 }
166 
167 //Command for printing help information.
168 void print_help(void)
169 {
170 	printf(":: to-json cper.file [--out file.name]\n");
171 	printf("\tConverts the provided CPER log file into JSON, by default writing to stdout. If '--out' is specified,\n");
172 	printf("\tThe outputted JSON will be written to the provided file name instead.\n");
173 	printf("\n:: to-json-section cper.section.file [--out file.name]\n");
174 	printf("\tConverts the provided single CPER section descriptor & section file into JSON, by default writing to stdout.\n");
175 	printf("\tOtherwise behaves the same as 'to-json'.\n");
176 	printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
177 	printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
178 	printf("\tWill automatically detect whether the JSON passed is a single section, or a whole file,\n");
179 	printf("\tand output binary accordingly.\n\n");
180 	printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
181 	printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
182 	printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
183 	printf("\tpremature exit/unexpected behaviour in CPER output.\n\n");
184 	printf("\tIf '--debug' is set, then debug output for JSON specification parsing will be printed to stdout.\n");
185 	printf("\n:: --help\n");
186 	printf("\tDisplays help information to the console.\n");
187 }
188