xref: /openbmc/libcper/cli-app/cper-convert.c (revision d34f2b11)
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.
2302c801a5SLawrence Tang     if (argc < 2)
2402c801a5SLawrence Tang     {
2502c801a5SLawrence Tang         printf("Invalid number of arguments. See 'cper-convert --help' for command information.\n");
2602c801a5SLawrence Tang         return -1;
2702c801a5SLawrence Tang     }
2802c801a5SLawrence Tang 
2902c801a5SLawrence Tang     //Run the requested command.
3002c801a5SLawrence Tang     if (strcmp(argv[1], "to-json") == 0)
3102c801a5SLawrence Tang         cper_to_json(argc, argv);
3202c801a5SLawrence Tang     else if (strcmp(argv[1], "to-cper") == 0)
3302c801a5SLawrence Tang         json_to_cper(argc, argv);
3402c801a5SLawrence Tang     else if (strcmp(argv[1], "--help") == 0)
3502c801a5SLawrence Tang         print_help();
3602c801a5SLawrence Tang     else
3702c801a5SLawrence Tang     {
3802c801a5SLawrence Tang         printf("Unrecognised argument '%s'. See 'cper-convert --help' for command information.\n", argv[1]);
3902c801a5SLawrence Tang         return -1;
4002c801a5SLawrence Tang     }
4102c801a5SLawrence Tang 
4202c801a5SLawrence Tang     return 0;
4302c801a5SLawrence Tang }
4402c801a5SLawrence Tang 
4502c801a5SLawrence Tang //Command for converting a provided CPER log file into JSON.
4602c801a5SLawrence Tang void cper_to_json(int argc, char* argv[])
4702c801a5SLawrence Tang {
4802c801a5SLawrence Tang     if (argc < 3)
4902c801a5SLawrence Tang     {
5002c801a5SLawrence Tang         printf("Insufficient number of arguments for 'to-json'. See 'cper-convert --help' for command information.\n");
5102c801a5SLawrence Tang         return;
5202c801a5SLawrence Tang     }
5302c801a5SLawrence Tang 
5402c801a5SLawrence Tang     //Get a handle for the log file.
5502c801a5SLawrence Tang     FILE* cper_file = fopen(argv[2], "r");
5602c801a5SLawrence Tang     if (cper_file == NULL)
5702c801a5SLawrence Tang     {
5802c801a5SLawrence Tang         printf("Could not open provided CPER file '%s', file handle returned null.\n", argv[2]);
5902c801a5SLawrence Tang         return;
6002c801a5SLawrence Tang     }
6102c801a5SLawrence Tang 
6202c801a5SLawrence Tang     //Convert.
6302c801a5SLawrence Tang     json_object* ir = cper_to_ir(cper_file);
6402c801a5SLawrence Tang     fclose(cper_file);
6502c801a5SLawrence Tang     const char* json_output = json_object_to_json_string_ext(ir, JSON_C_TO_STRING_PRETTY);
6602c801a5SLawrence Tang 
6702c801a5SLawrence Tang     //Check whether there is a "--out" argument, if there is, then output to file instead.
6802c801a5SLawrence Tang     //Otherwise, just send to console.
6902c801a5SLawrence Tang     if (argc != 5)
7002c801a5SLawrence Tang     {
7102c801a5SLawrence Tang         printf("%s\n", json_output);
7202c801a5SLawrence Tang         return;
7302c801a5SLawrence Tang     }
7402c801a5SLawrence Tang 
7502c801a5SLawrence Tang     //File out argument exists. Argument valid?
7602c801a5SLawrence Tang     if (strcmp(argv[3], "--out") != 0)
7702c801a5SLawrence Tang     {
7802c801a5SLawrence Tang         printf("Invalid argument '%s' for command 'to-json'. See 'cper-convert --help' for command information.\n", argv[3]);
7902c801a5SLawrence Tang         return;
8002c801a5SLawrence Tang     }
8102c801a5SLawrence Tang 
8202c801a5SLawrence Tang     //Try to open a file handle to the desired output file.
8302c801a5SLawrence Tang     FILE* json_file = fopen(argv[4], "w");
8402c801a5SLawrence Tang     if (json_file == NULL)
8502c801a5SLawrence Tang     {
8602c801a5SLawrence Tang         printf("Could not get a handle for output file '%s', file handle returned null.\n", argv[4]);
8702c801a5SLawrence Tang         return;
8802c801a5SLawrence Tang     }
8902c801a5SLawrence Tang 
9002c801a5SLawrence Tang     //Write out to file.
9102c801a5SLawrence Tang     fwrite(json_output, strlen(json_output), 1, json_file);
9202c801a5SLawrence Tang     fclose(json_file);
9302c801a5SLawrence Tang }
9402c801a5SLawrence Tang 
9502c801a5SLawrence Tang //Command for converting a provided CPER-JSON JSON file to CPER binary.
9602c801a5SLawrence Tang void json_to_cper(int argc, char* argv[])
9702c801a5SLawrence Tang {
9802c801a5SLawrence Tang     if (argc < 5)
9902c801a5SLawrence Tang     {
10002c801a5SLawrence Tang         printf("Insufficient number of arguments for 'to-cper'. See 'cper-convert --help' for command information.\n");
10102c801a5SLawrence Tang         return;
10202c801a5SLawrence Tang     }
10302c801a5SLawrence Tang 
10402c801a5SLawrence Tang     //Read JSON IR from file.
10502c801a5SLawrence Tang     json_object* ir = json_object_from_file(argv[2]);
10602c801a5SLawrence Tang     if (ir == NULL)
10702c801a5SLawrence Tang     {
10802c801a5SLawrence Tang         printf("Could not read JSON from file '%s', import returned null.\n", argv[2]);
10902c801a5SLawrence Tang         return;
11002c801a5SLawrence Tang     }
11102c801a5SLawrence Tang 
11202c801a5SLawrence Tang     //Are we skipping validation?
11302c801a5SLawrence Tang     int do_validate = 1;
114*d34f2b11SLawrence Tang     if (argc >= 6 && argc < 8)
11502c801a5SLawrence Tang     {
11602c801a5SLawrence Tang         if (strcmp(argv[5], "--no-validate") == 0)
11702c801a5SLawrence Tang         {
11802c801a5SLawrence Tang             do_validate = 0;
11902c801a5SLawrence Tang         }
12002c801a5SLawrence Tang     }
12102c801a5SLawrence Tang 
12202c801a5SLawrence Tang     //Validate the JSON against specification, unless otherwise specified.
12302c801a5SLawrence Tang     if (do_validate)
12402c801a5SLawrence Tang     {
12502c801a5SLawrence Tang         char* specification_path = NULL;
12602c801a5SLawrence Tang 
127*d34f2b11SLawrence Tang         //Is there a specification file path?
128*d34f2b11SLawrence Tang         if (argc >= 7 && strcmp(argv[argc - 2], "--specification") == 0)
12902c801a5SLawrence Tang         {
130*d34f2b11SLawrence Tang             specification_path = argv[argc - 1];
13102c801a5SLawrence Tang         }
132*d34f2b11SLawrence Tang         else
13302c801a5SLawrence Tang         {
13402c801a5SLawrence Tang             //Make the specification path the assumed default (application directory + specification/cper-json.json).
13502c801a5SLawrence Tang             specification_path = malloc(PATH_MAX);
13602c801a5SLawrence Tang             char* dir = dirname(argv[0]);
13702c801a5SLawrence Tang             strcpy(specification_path, dir);
13802c801a5SLawrence Tang             strcat(specification_path, "/specification/cper-json.json");
13902c801a5SLawrence Tang         }
140*d34f2b11SLawrence Tang 
141*d34f2b11SLawrence Tang         //Enable debug mode if indicated.
142*d34f2b11SLawrence Tang         for (int i=5; i<argc; i++)
14302c801a5SLawrence Tang         {
144*d34f2b11SLawrence Tang             if (strcmp(argv[i], "--debug") == 0)
145*d34f2b11SLawrence Tang             {
146*d34f2b11SLawrence Tang                 validate_schema_debug_enable();
147*d34f2b11SLawrence Tang                 printf("debug enabled.\n");
148*d34f2b11SLawrence Tang                 break;
149*d34f2b11SLawrence Tang             }
15002c801a5SLawrence Tang         }
15102c801a5SLawrence Tang 
15202c801a5SLawrence Tang         //Attempt to verify with the the specification.
15302c801a5SLawrence Tang         char* error_message = malloc(JSON_ERROR_MSG_MAX_LEN);
15402c801a5SLawrence Tang         int success = validate_schema_from_file(specification_path, ir, error_message);
15502c801a5SLawrence Tang 
15602c801a5SLawrence Tang         //Free specification path (if necessary).
15702c801a5SLawrence Tang         if (argc == 5)
15802c801a5SLawrence Tang             free(specification_path);
15902c801a5SLawrence Tang 
16002c801a5SLawrence Tang         //If failed, early exit before conversion.
16102c801a5SLawrence Tang         if (!success)
16202c801a5SLawrence Tang         {
16302c801a5SLawrence Tang             printf("JSON format validation failed: %s\n", error_message);
16402c801a5SLawrence Tang             free(error_message);
16502c801a5SLawrence Tang             return;
16602c801a5SLawrence Tang         }
16702c801a5SLawrence Tang         free(error_message);
16802c801a5SLawrence Tang     }
16902c801a5SLawrence Tang 
17002c801a5SLawrence Tang     //Attempt a conversion.
17102c801a5SLawrence Tang     //Open a read for the output file.
17202c801a5SLawrence Tang     FILE* cper_file = fopen(argv[4], "w");
17302c801a5SLawrence Tang     if (cper_file == NULL)
17402c801a5SLawrence Tang     {
17502c801a5SLawrence Tang         printf("Could not open output file '%s', file handle returned null.\n", argv[4]);
17602c801a5SLawrence Tang         return;
17702c801a5SLawrence Tang     }
17802c801a5SLawrence Tang 
17902c801a5SLawrence Tang     //Run the converter.
18002c801a5SLawrence Tang     ir_to_cper(ir, cper_file);
18102c801a5SLawrence Tang     fclose(cper_file);
18202c801a5SLawrence Tang }
18302c801a5SLawrence Tang 
18402c801a5SLawrence Tang //Command for printing help information.
18502c801a5SLawrence Tang void print_help(void)
18602c801a5SLawrence Tang {
18702c801a5SLawrence Tang     printf(":: to-json cper.file [--out file.name]\n");
18802c801a5SLawrence Tang     printf("\tConverts the provided CPER log file into JSON, by default outputting to console. If '--out' is specified,\n");
18902c801a5SLawrence Tang     printf("\tThe outputted JSON will be written to the provided file name instead.\n");
190*d34f2b11SLawrence Tang     printf("\n:: to-cper cper.json --out file.name [--no-validate] [--debug] [--specification some/spec/path.json]\n");
19102c801a5SLawrence Tang     printf("\tConverts the provided CPER-JSON JSON file into CPER binary. An output file must be specified with '--out'.\n");
19202c801a5SLawrence Tang     printf("\tBy default, the provided JSON will try to be validated against a specification. If no specification file path\n");
19302c801a5SLawrence Tang     printf("\tis provided with '--specification', then it will default to 'argv[0] + /specification/cper-json.json'.\n");
19402c801a5SLawrence Tang     printf("\tIf the '--no-validate' argument is set, then the provided JSON will not be validated. Be warned, this may cause\n");
19502c801a5SLawrence Tang     printf("\tpremature exit/unexpected behaviour in CPER output.\n");
19602c801a5SLawrence Tang     printf("\n:: --help\n");
19702c801a5SLawrence Tang     printf("\tDisplays help information to the console.\n");
19802c801a5SLawrence Tang }