blob: d1caeb60e02af64a99420c7b5ecff3c1d2f3ce77 [file] [log] [blame]
Lawrence Tangb8fa2f72022-07-18 10:50:19 +01001/**
2 * A user-space application linking to the CPER-JSON conversion library which allows for easy
Ed Tanousfedd4572024-07-12 13:56:00 -07003 * conversion between CPER and CPER-JSON formats.
4 *
Lawrence Tangb8fa2f72022-07-18 10:50:19 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7
8#include <stdio.h>
9#include <string.h>
10#include <libgen.h>
Andrew Adriance4482c482024-07-02 14:55:11 -070011#include <limits.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +010012#include <json.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070013#include <libcper/log.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000014#include <libcper/cper-parse.h>
15#include <libcper/json-schema.h>
Ed Tanous3e728062025-03-17 20:55:20 -070016#include <libcper/Cper.h>
17#include <libcper/base64.h>
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010018
Lawrence Tang617949e2022-08-08 14:21:42 +010019void cper_to_json(char *in_file, char *out_file, int is_single_section);
Ed Tanousedee0a32025-03-16 17:40:04 -070020void json_to_cper(const char *in_file, const char *out_file);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010021void print_help(void);
22
Lawrence Tange407b4c2022-07-21 13:54:01 +010023int main(int argc, char *argv[])
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010024{
Ed Tanous50b966f2025-03-11 09:06:19 -070025 cper_set_log_stdio();
Lawrence Tang5f388a32022-08-08 10:49:02 +010026 //Print help if requested.
27 if (argc == 2 && strcmp(argv[1], "--help") == 0) {
28 print_help();
29 return 0;
30 }
31
32 //Ensure at least two arguments are present.
33 if (argc < 3) {
Lawrence Tange407b4c2022-07-21 13:54:01 +010034 printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n");
35 return -1;
36 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010037
Lawrence Tang71c70a32022-08-08 09:16:06 +010038 //Parse the command line arguments.
Lawrence Tang5f388a32022-08-08 10:49:02 +010039 char *input_file = argv[2];
40 char *output_file = NULL;
41 char *specification_file = NULL;
42 int no_validate = 0;
43 int debug = 0;
44 for (int i = 3; i < argc; i++) {
45 if (strcmp(argv[i], "--out") == 0 && i < argc - 1) {
46 //Output file.
47 output_file = argv[i + 1];
48 i++;
49 } else if (strcmp(argv[i], "--specification") == 0 &&
50 i < argc - 1) {
51 //Specification file.
52 specification_file = argv[i + 1];
53 i++;
54 } else if (strcmp(argv[i], "--no-validate") == 0) {
55 //No validation to be used.
56 //Invalidates specification file.
57 specification_file = NULL;
58 no_validate = 1;
59 } else if (strcmp(argv[i], "--debug") == 0) {
60 //Debug output on.
61 debug = 1;
62 } else {
63 printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
64 argv[i]);
65 }
66 }
Lawrence Tang71c70a32022-08-08 09:16:06 +010067
Ed Tanous4bdb2262025-03-10 21:13:46 -070068 // Debug is not used at the moment. Leave for compatibility.
69 (void)debug;
70 (void)no_validate;
71 (void)specification_file;
Lawrence Tange407b4c2022-07-21 13:54:01 +010072 //Run the requested command.
Lawrence Tang617949e2022-08-08 14:21:42 +010073 if (strcmp(argv[1], "to-json") == 0) {
74 cper_to_json(input_file, output_file, 0);
75 } else if (strcmp(argv[1], "to-json-section") == 0) {
76 cper_to_json(input_file, output_file, 1);
77 } else if (strcmp(argv[1], "to-cper") == 0) {
Ed Tanous4bdb2262025-03-10 21:13:46 -070078 json_to_cper(input_file, output_file);
Lawrence Tang617949e2022-08-08 14:21:42 +010079 } else {
Lawrence Tange407b4c2022-07-21 13:54:01 +010080 printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
81 argv[1]);
82 return -1;
83 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010084
Lawrence Tange407b4c2022-07-21 13:54:01 +010085 return 0;
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010086}
87
Lawrence Tang617949e2022-08-08 14:21:42 +010088//Command for converting a provided CPER log file or CPER single section file into JSON.
89void cper_to_json(char *in_file, char *out_file, int is_single_section)
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010090{
Lawrence Tange407b4c2022-07-21 13:54:01 +010091 //Get a handle for the log file.
Lawrence Tang5f388a32022-08-08 10:49:02 +010092 FILE *cper_file = fopen(in_file, "r");
Lawrence Tange407b4c2022-07-21 13:54:01 +010093 if (cper_file == NULL) {
94 printf("Could not open provided CPER file '%s', file handle returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +010095 in_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +010096 return;
97 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010098
Ed Tanous3e728062025-03-17 20:55:20 -070099 fseek(cper_file, 0, SEEK_END);
100 long fsize = ftell(cper_file);
101 fseek(cper_file, 0, SEEK_SET);
102
103 char *fbuff = malloc(fsize);
104 size_t readsize = fread(fbuff, 1, (long)fsize, cper_file);
105 if (readsize != (size_t)fsize) {
106 printf("Could not read CPER file '%s', read returned %ld bytes.\n",
107 in_file, readsize);
108 return;
109 }
110
111 if (!header_valid(fbuff, readsize)) {
112 // Check if it's base64 encoded
113 int32_t decoded_len = 0;
114 UINT8 *decoded = base64_decode(fbuff, readsize, &decoded_len);
115 if (decoded == NULL) {
116 printf("base64 decode failed for CPER file '%s'.\n",
117 in_file);
118 free(fbuff);
119 free(decoded);
120 return;
121 }
122 if (!header_valid((const char *)decoded, decoded_len)) {
123 printf("Invalid CPER file '%s'.\n", in_file);
124 free(fbuff);
125 free(decoded);
126 return;
127 }
128 // Swap the buffer to the base64 decoded buffer.
129 free(fbuff);
130 fbuff = (char *)decoded;
131
132 fsize = decoded_len;
133 decoded = NULL;
134 }
135
Lawrence Tange407b4c2022-07-21 13:54:01 +0100136 //Convert.
Lawrence Tang617949e2022-08-08 14:21:42 +0100137 json_object *ir;
John Chungf8fc7052024-05-03 20:05:29 +0800138 if (is_single_section) {
Ed Tanous3e728062025-03-17 20:55:20 -0700139 ir = cper_buf_single_section_to_ir((UINT8 *)fbuff, readsize);
John Chungf8fc7052024-05-03 20:05:29 +0800140 } else {
Ed Tanous3e728062025-03-17 20:55:20 -0700141 ir = cper_buf_to_ir((UINT8 *)fbuff, fsize);
John Chungf8fc7052024-05-03 20:05:29 +0800142 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100143 fclose(cper_file);
Lawrence Tang617949e2022-08-08 14:21:42 +0100144
145 //Output to string.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100146 const char *json_output =
147 json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100148
Lawrence Tange407b4c2022-07-21 13:54:01 +0100149 //Check whether there is a "--out" argument, if there is, then output to file instead.
150 //Otherwise, just send to console.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100151 if (out_file == NULL) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100152 printf("%s\n", json_output);
153 return;
154 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100155
Lawrence Tange407b4c2022-07-21 13:54:01 +0100156 //Try to open a file handle to the desired output file.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100157 FILE *json_file = fopen(out_file, "w");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100158 if (json_file == NULL) {
159 printf("Could not get a handle for output file '%s', file handle returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +0100160 out_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100161 return;
162 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100163
Lawrence Tange407b4c2022-07-21 13:54:01 +0100164 //Write out to file.
165 fwrite(json_output, strlen(json_output), 1, json_file);
166 fclose(json_file);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100167}
168
169//Command for converting a provided CPER-JSON JSON file to CPER binary.
Ed Tanousedee0a32025-03-16 17:40:04 -0700170void json_to_cper(const char *in_file, const char *out_file)
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100171{
Lawrence Tang5f388a32022-08-08 10:49:02 +0100172 //Verify output file exists.
173 if (out_file == NULL) {
174 printf("No output file provided for 'to-cper'. See 'cper-convert --help' for command information.\n");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100175 return;
176 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100177
Lawrence Tange407b4c2022-07-21 13:54:01 +0100178 //Read JSON IR from file.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100179 json_object *ir = json_object_from_file(in_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100180 if (ir == NULL) {
181 printf("Could not read JSON from file '%s', import returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +0100182 in_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100183 return;
184 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100185
Lawrence Tange407b4c2022-07-21 13:54:01 +0100186 //Open a read for the output file.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100187 FILE *cper_file = fopen(out_file, "w");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100188 if (cper_file == NULL) {
189 printf("Could not open output file '%s', file handle returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +0100190 out_file);
Ed Tanousc6aaee02025-04-11 12:16:21 -0700191 json_object_put(ir);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100192 return;
193 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100194
Lawrence Tang617949e2022-08-08 14:21:42 +0100195 //Detect the type of CPER (full log, single section) from the IR given.
196 //Run the converter accordingly.
John Chungf8fc7052024-05-03 20:05:29 +0800197 if (json_object_object_get(ir, "header") != NULL) {
Lawrence Tang617949e2022-08-08 14:21:42 +0100198 ir_to_cper(ir, cper_file);
John Chungf8fc7052024-05-03 20:05:29 +0800199 } else {
Lawrence Tang617949e2022-08-08 14:21:42 +0100200 ir_single_section_to_cper(ir, cper_file);
John Chungf8fc7052024-05-03 20:05:29 +0800201 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100202 fclose(cper_file);
John Chungf8fc7052024-05-03 20:05:29 +0800203 json_object_put(ir);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100204}
205
206//Command for printing help information.
207void print_help(void)
208{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100209 printf(":: to-json cper.file [--out file.name]\n");
Lawrence Tang5f388a32022-08-08 10:49:02 +0100210 printf("\tConverts the provided CPER log file into JSON, by default writing to stdout. If '--out' is specified,\n");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100211 printf("\tThe outputted JSON will be written to the provided file name instead.\n");
Lawrence Tang617949e2022-08-08 14:21:42 +0100212 printf("\n:: to-json-section cper.section.file [--out file.name]\n");
213 printf("\tConverts the provided single CPER section descriptor & section file into JSON, by default writing to stdout.\n");
214 printf("\tOtherwise behaves the same as 'to-json'.\n");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100215 printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
216 printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
Lawrence Tang617949e2022-08-08 14:21:42 +0100217 printf("\tWill automatically detect whether the JSON passed is a single section, or a whole file,\n");
218 printf("\tand output binary accordingly.\n\n");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100219 printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
220 printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
221 printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
Lawrence Tang617949e2022-08-08 14:21:42 +0100222 printf("\tpremature exit/unexpected behaviour in CPER output.\n\n");
Lawrence Tang5f388a32022-08-08 10:49:02 +0100223 printf("\tIf '--debug' is set, then debug output for JSON specification parsing will be printed to stdout.\n");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100224 printf("\n:: --help\n");
225 printf("\tDisplays help information to the console.\n");
John Chungf8fc7052024-05-03 20:05:29 +0800226}