blob: 26194b7a9af41259371a7ebd5992acc25030b603 [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
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
Lawrence Tang5f388a32022-08-08 10:49:02 +010016void cper_to_json(char *in_file, char *out_file);
17void json_to_cper(char *in_file, char *out_file, char *specification_file,
18 char *program_dir, int no_validate, int debug);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010019void print_help(void);
20
Lawrence Tange407b4c2022-07-21 13:54:01 +010021int main(int argc, char *argv[])
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010022{
Lawrence Tang5f388a32022-08-08 10:49:02 +010023 //Print help if requested.
24 if (argc == 2 && strcmp(argv[1], "--help") == 0) {
25 print_help();
26 return 0;
27 }
28
29 //Ensure at least two arguments are present.
30 if (argc < 3) {
Lawrence Tange407b4c2022-07-21 13:54:01 +010031 printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n");
32 return -1;
33 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010034
Lawrence Tang71c70a32022-08-08 09:16:06 +010035 //Parse the command line arguments.
Lawrence Tang5f388a32022-08-08 10:49:02 +010036 char *input_file = argv[2];
37 char *output_file = NULL;
38 char *specification_file = NULL;
39 int no_validate = 0;
40 int debug = 0;
41 for (int i = 3; i < argc; i++) {
42 if (strcmp(argv[i], "--out") == 0 && i < argc - 1) {
43 //Output file.
44 output_file = argv[i + 1];
45 i++;
46 } else if (strcmp(argv[i], "--specification") == 0 &&
47 i < argc - 1) {
48 //Specification file.
49 specification_file = argv[i + 1];
50 i++;
51 } else if (strcmp(argv[i], "--no-validate") == 0) {
52 //No validation to be used.
53 //Invalidates specification file.
54 specification_file = NULL;
55 no_validate = 1;
56 } else if (strcmp(argv[i], "--debug") == 0) {
57 //Debug output on.
58 debug = 1;
59 } else {
60 printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
61 argv[i]);
62 }
63 }
Lawrence Tang71c70a32022-08-08 09:16:06 +010064
Lawrence Tange407b4c2022-07-21 13:54:01 +010065 //Run the requested command.
66 if (strcmp(argv[1], "to-json") == 0)
Lawrence Tang5f388a32022-08-08 10:49:02 +010067 cper_to_json(input_file, output_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +010068 else if (strcmp(argv[1], "to-cper") == 0)
Lawrence Tang5f388a32022-08-08 10:49:02 +010069 json_to_cper(input_file, output_file, specification_file,
70 argv[0], no_validate, debug);
Lawrence Tange407b4c2022-07-21 13:54:01 +010071 else {
72 printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n",
73 argv[1]);
74 return -1;
75 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010076
Lawrence Tange407b4c2022-07-21 13:54:01 +010077 return 0;
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010078}
79
80//Command for converting a provided CPER log file into JSON.
Lawrence Tang5f388a32022-08-08 10:49:02 +010081void cper_to_json(char *in_file, char *out_file)
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010082{
Lawrence Tange407b4c2022-07-21 13:54:01 +010083 //Get a handle for the log file.
Lawrence Tang5f388a32022-08-08 10:49:02 +010084 FILE *cper_file = fopen(in_file, "r");
Lawrence Tange407b4c2022-07-21 13:54:01 +010085 if (cper_file == NULL) {
86 printf("Could not open provided CPER file '%s', file handle returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +010087 in_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +010088 return;
89 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010090
Lawrence Tange407b4c2022-07-21 13:54:01 +010091 //Convert.
92 json_object *ir = cper_to_ir(cper_file);
93 fclose(cper_file);
94 const char *json_output =
95 json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +010096
Lawrence Tange407b4c2022-07-21 13:54:01 +010097 //Check whether there is a "--out" argument, if there is, then output to file instead.
98 //Otherwise, just send to console.
Lawrence Tang5f388a32022-08-08 10:49:02 +010099 if (out_file == NULL) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100100 printf("%s\n", json_output);
101 return;
102 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100103
Lawrence Tange407b4c2022-07-21 13:54:01 +0100104 //Try to open a file handle to the desired output file.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100105 FILE *json_file = fopen(out_file, "w");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100106 if (json_file == NULL) {
107 printf("Could not get a handle for output file '%s', file handle returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +0100108 out_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100109 return;
110 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100111
Lawrence Tange407b4c2022-07-21 13:54:01 +0100112 //Write out to file.
113 fwrite(json_output, strlen(json_output), 1, json_file);
114 fclose(json_file);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100115}
116
117//Command for converting a provided CPER-JSON JSON file to CPER binary.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100118void json_to_cper(char *in_file, char *out_file, char *specification_file,
119 char *program_dir, int no_validate, int debug)
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100120{
Lawrence Tang5f388a32022-08-08 10:49:02 +0100121 //Verify output file exists.
122 if (out_file == NULL) {
123 printf("No output file provided for 'to-cper'. See 'cper-convert --help' for command information.\n");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100124 return;
125 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100126
Lawrence Tange407b4c2022-07-21 13:54:01 +0100127 //Read JSON IR from file.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100128 json_object *ir = json_object_from_file(in_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100129 if (ir == NULL) {
130 printf("Could not read JSON from file '%s', import returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +0100131 in_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100132 return;
133 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100134
Lawrence Tange407b4c2022-07-21 13:54:01 +0100135 //Validate the JSON against specification, unless otherwise specified.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100136 if (!no_validate) {
137 int using_default_spec_path = 0;
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100138
Lawrence Tange407b4c2022-07-21 13:54:01 +0100139 //Is there a specification file path?
Lawrence Tang5f388a32022-08-08 10:49:02 +0100140 if (specification_file == NULL) {
141 using_default_spec_path = 1;
142
Lawrence Tange407b4c2022-07-21 13:54:01 +0100143 //Make the specification path the assumed default (application directory + specification/cper-json.json).
Lawrence Tang5f388a32022-08-08 10:49:02 +0100144 specification_file = malloc(PATH_MAX);
145 char *dir = dirname(program_dir);
146 strcpy(specification_file, dir);
147 strcat(specification_file,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100148 "/specification/cper-json.json");
149 }
Lawrence Tangd34f2b12022-07-19 15:36:31 +0100150
Lawrence Tange407b4c2022-07-21 13:54:01 +0100151 //Enable debug mode if indicated.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100152 if (debug)
153 validate_schema_debug_enable();
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100154
Lawrence Tange407b4c2022-07-21 13:54:01 +0100155 //Attempt to verify with the the specification.
156 char *error_message = malloc(JSON_ERROR_MSG_MAX_LEN);
Lawrence Tang5f388a32022-08-08 10:49:02 +0100157 int success = validate_schema_from_file(specification_file, ir,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100158 error_message);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100159
Lawrence Tange407b4c2022-07-21 13:54:01 +0100160 //Free specification path (if necessary).
Lawrence Tang5f388a32022-08-08 10:49:02 +0100161 if (using_default_spec_path)
162 free(specification_file);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100163
Lawrence Tange407b4c2022-07-21 13:54:01 +0100164 //If failed, early exit before conversion.
165 if (!success) {
166 printf("JSON format validation failed: %s\n",
167 error_message);
168 free(error_message);
169 return;
170 }
171 free(error_message);
172 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100173
Lawrence Tange407b4c2022-07-21 13:54:01 +0100174 //Attempt a conversion.
175 //Open a read for the output file.
Lawrence Tang5f388a32022-08-08 10:49:02 +0100176 FILE *cper_file = fopen(out_file, "w");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100177 if (cper_file == NULL) {
178 printf("Could not open output file '%s', file handle returned null.\n",
Lawrence Tang5f388a32022-08-08 10:49:02 +0100179 out_file);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100180 return;
181 }
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100182
Lawrence Tange407b4c2022-07-21 13:54:01 +0100183 //Run the converter.
184 ir_to_cper(ir, cper_file);
185 fclose(cper_file);
Lawrence Tangb8fa2f72022-07-18 10:50:19 +0100186}
187
188//Command for printing help information.
189void print_help(void)
190{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100191 printf(":: to-json cper.file [--out file.name]\n");
Lawrence Tang5f388a32022-08-08 10:49:02 +0100192 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 +0100193 printf("\tThe outputted JSON will be written to the provided file name instead.\n");
194 printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
195 printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
196 printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
197 printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
198 printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
199 printf("\tpremature exit/unexpected behaviour in CPER output.\n");
Lawrence Tang5f388a32022-08-08 10:49:02 +0100200 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 +0100201 printf("\n:: --help\n");
202 printf("\tDisplays help information to the console.\n");
Lawrence Tang4ef0a0a2022-07-18 10:50:58 +0100203}