Bug Summary

File:.build-ci/../plugins/solidigm/solidigm-telemetry.c
Warning:line 139, column 11
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name solidigm-telemetry.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -std=gnu99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-06-24-175442-590-1 -x c ../plugins/solidigm/solidigm-telemetry.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2022 Solidigm.
4 *
5 * Author: leonardo.da.cunha@solidigm.com
6 */
7
8#include <fcntl.h>
9#include <errno(*__errno_location ()).h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13
14#include <libnvme.h>
15
16#include "common.h"
17#include "nvme.h"
18#include "plugin.h"
19#include "nvme-print.h"
20#include "solidigm-telemetry.h"
21#include "solidigm-telemetry/telemetry-log.h"
22#include "solidigm-telemetry/cod.h"
23#include "solidigm-telemetry/header.h"
24#include "solidigm-telemetry/config.h"
25#include "solidigm-telemetry/data-area.h"
26#include "solidigm-util.h"
27
28static int read_file2buffer(char *file_name, char **buffer, size_t *length)
29{
30 FILE *fd = fopen(file_name, "rb");
31
32 if (!fd
11.1
'fd' is non-null
)
12
Taking false branch
33 return -errno(*__errno_location ());
34
35 fseek(fd, 0, SEEK_END2);
36 size_t length_bytes = ftell(fd);
37
38 fseek(fd, 0, SEEK_SET0);
39
40 *buffer = malloc(length_bytes);
13
Memory is allocated
41 if (!*buffer) {
14
Assuming the condition is false
15
Taking false branch
42 fclose(fd);
43 return -errno(*__errno_location ());
44 }
45 *length = fread(*buffer, 1, length_bytes, fd);
46 fclose(fd);
47 return 0;
48}
49
50struct config {
51 __u32 host_gen;
52 bool_Bool ctrl_init;
53 __u8 data_area;
54 char *cfg_file;
55 char *binary_file;
56 char *jq_filter;
57};
58
59static void cleanup_json_object(struct json_object **jobj_ptr)
60{
61 json_free_object(*jobj_ptr)json_object_put(*jobj_ptr);
62 *jobj_ptr = NULL((void*)0);
63}
64
65int solidigm_get_telemetry_log(int argc, char **argv, struct command *acmd, struct plugin *plugin)
66{
67 const char *desc = "Parse Solidigm Telemetry log";
68 const char *hgen = "Controls when to generate new host initiated report. Default value '1' generates new host initiated report, value '0' causes retrieval of existing log.";
69 const char *cgen = "Gather report generated by the controller.";
70 const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4.";
71 const char *cfile = "JSON configuration file";
72 const char *sfile = "binary file containing log dump";
73 const char *jqfilt = "JSON config entry name containing jq filter";
74 bool_Bool has_binary_file = false0;
75 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
76 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
77 __cleanup_free__attribute__((cleanup(freep))) struct nvme_telemetry_log *tlog = NULL((void*)0);
78
79 __attribute__((cleanup(cleanup_json_object))) struct json_object *configuration = NULL((void*)0);
80
81 __attribute__((cleanup(cleanup_json_object))) struct json_object *root =
82 json_create_object()json_object_new_object();
83
84 struct telemetry_log tl = {
85 .root = root,
86 };
87
88 struct config cfg = {
89 .host_gen = 1,
90 .ctrl_init = false0,
91 };
92
93 NVME_ARGS(opts,struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"host-generate", 'g', "NUM", CFG_POSITIVE, &cfg.host_gen
, 1, hgen, 0, }, {"controller-init", 'c', ((void*)0), CFG_FLAG
, &cfg.ctrl_init, 0, cgen, 0, }, {"data-area", 'd', "NUM"
, CFG_BYTE, &cfg.data_area, 1, dgen, 0, }, {"config-file"
, 'j', "FILE", CFG_STRING, &cfg.cfg_file, 1, cfile, 0, },
{"source-file", 's', "FILE", CFG_STRING, &cfg.binary_file
, 1, sfile, 0, }, {"jq-filter", 'q', "STRING", CFG_STRING, &
cfg.jq_filter, 1, jqfilt, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary|tabular"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, { ((void*)0) } }
94 OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen),struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"host-generate", 'g', "NUM", CFG_POSITIVE, &cfg.host_gen
, 1, hgen, 0, }, {"controller-init", 'c', ((void*)0), CFG_FLAG
, &cfg.ctrl_init, 0, cgen, 0, }, {"data-area", 'd', "NUM"
, CFG_BYTE, &cfg.data_area, 1, dgen, 0, }, {"config-file"
, 'j', "FILE", CFG_STRING, &cfg.cfg_file, 1, cfile, 0, },
{"source-file", 's', "FILE", CFG_STRING, &cfg.binary_file
, 1, sfile, 0, }, {"jq-filter", 'q', "STRING", CFG_STRING, &
cfg.jq_filter, 1, jqfilt, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary|tabular"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, { ((void*)0) } }
95 OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen),struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"host-generate", 'g', "NUM", CFG_POSITIVE, &cfg.host_gen
, 1, hgen, 0, }, {"controller-init", 'c', ((void*)0), CFG_FLAG
, &cfg.ctrl_init, 0, cgen, 0, }, {"data-area", 'd', "NUM"
, CFG_BYTE, &cfg.data_area, 1, dgen, 0, }, {"config-file"
, 'j', "FILE", CFG_STRING, &cfg.cfg_file, 1, cfile, 0, },
{"source-file", 's', "FILE", CFG_STRING, &cfg.binary_file
, 1, sfile, 0, }, {"jq-filter", 'q', "STRING", CFG_STRING, &
cfg.jq_filter, 1, jqfilt, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary|tabular"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, { ((void*)0) } }
96 OPT_BYTE("data-area", 'd', &cfg.data_area, dgen),struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"host-generate", 'g', "NUM", CFG_POSITIVE, &cfg.host_gen
, 1, hgen, 0, }, {"controller-init", 'c', ((void*)0), CFG_FLAG
, &cfg.ctrl_init, 0, cgen, 0, }, {"data-area", 'd', "NUM"
, CFG_BYTE, &cfg.data_area, 1, dgen, 0, }, {"config-file"
, 'j', "FILE", CFG_STRING, &cfg.cfg_file, 1, cfile, 0, },
{"source-file", 's', "FILE", CFG_STRING, &cfg.binary_file
, 1, sfile, 0, }, {"jq-filter", 'q', "STRING", CFG_STRING, &
cfg.jq_filter, 1, jqfilt, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary|tabular"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, { ((void*)0) } }
97 OPT_FILE("config-file", 'j', &cfg.cfg_file, cfile),struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"host-generate", 'g', "NUM", CFG_POSITIVE, &cfg.host_gen
, 1, hgen, 0, }, {"controller-init", 'c', ((void*)0), CFG_FLAG
, &cfg.ctrl_init, 0, cgen, 0, }, {"data-area", 'd', "NUM"
, CFG_BYTE, &cfg.data_area, 1, dgen, 0, }, {"config-file"
, 'j', "FILE", CFG_STRING, &cfg.cfg_file, 1, cfile, 0, },
{"source-file", 's', "FILE", CFG_STRING, &cfg.binary_file
, 1, sfile, 0, }, {"jq-filter", 'q', "STRING", CFG_STRING, &
cfg.jq_filter, 1, jqfilt, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary|tabular"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, { ((void*)0) } }
98 OPT_FILE("source-file", 's', &cfg.binary_file, sfile),struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"host-generate", 'g', "NUM", CFG_POSITIVE, &cfg.host_gen
, 1, hgen, 0, }, {"controller-init", 'c', ((void*)0), CFG_FLAG
, &cfg.ctrl_init, 0, cgen, 0, }, {"data-area", 'd', "NUM"
, CFG_BYTE, &cfg.data_area, 1, dgen, 0, }, {"config-file"
, 'j', "FILE", CFG_STRING, &cfg.cfg_file, 1, cfile, 0, },
{"source-file", 's', "FILE", CFG_STRING, &cfg.binary_file
, 1, sfile, 0, }, {"jq-filter", 'q', "STRING", CFG_STRING, &
cfg.jq_filter, 1, jqfilt, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary|tabular"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, { ((void*)0) } }
99 OPT_STR("jq-filter", 'q', &cfg.jq_filter, jqfilt))struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"host-generate", 'g', "NUM", CFG_POSITIVE, &cfg.host_gen
, 1, hgen, 0, }, {"controller-init", 'c', ((void*)0), CFG_FLAG
, &cfg.ctrl_init, 0, cgen, 0, }, {"data-area", 'd', "NUM"
, CFG_BYTE, &cfg.data_area, 1, dgen, 0, }, {"config-file"
, 'j', "FILE", CFG_STRING, &cfg.cfg_file, 1, cfile, 0, },
{"source-file", 's', "FILE", CFG_STRING, &cfg.binary_file
, 1, sfile, 0, }, {"jq-filter", 'q', "STRING", CFG_STRING, &
cfg.jq_filter, 1, jqfilt, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"output-format", 'o', "FMT", CFG_STRING, &nvme_args
.output_format, 1, "Output format: normal|json|binary|tabular"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, { ((void*)0) } }
;
100
101 int err = argconfig_parse(argc, argv, desc, opts);
102
103 if (err) {
1
Assuming 'err' is 0
2
Taking false branch
104 return err;
105 }
106 /* When not selected on the command line, get minimum data area required */
107 if (!argconfig_parse_seen(opts, "data-area"))
3
Assuming the condition is false
108 cfg.data_area = argconfig_parse_seen(opts, "config-file") ? 3 : 1;
109
110 if (cfg.data_area < 1 || cfg.data_area > 4) {
4
Assuming field 'data_area' is >= 1
5
Assuming field 'data_area' is <= 4
6
Taking false branch
111 errno(*__errno_location ()) = EINVAL22;
112 nvme_show_perror("data-area = '%d'", cfg.data_area);
113 return -errno(*__errno_location ());
114 }
115
116 has_binary_file = argconfig_parse_seen(opts, "source-file");
117 if (has_binary_file) {
7
Assuming 'has_binary_file' is true
8
Taking true branch
118 // If a binary file is provided, we don't want to open a device.
119 // GNU getopt() permutes the contents of argv as it scans,
120 // so that eventually all the nonoptions are at the end.
121 if (argc > optind) {
9
Assuming 'argc' is <= 'optind'
10
Taking false branch
122 errno(*__errno_location ()) = EINVAL22;
123 nvme_show_perror(
124 "Device path not allowed when using --source-file");
125 return -errno(*__errno_location ());
126 }
127 err = read_file2buffer(cfg.binary_file, (char **)&tlog, &tl.log_size);
11
Calling 'read_file2buffer'
16
Returned allocated memory via 2nd parameter
128 } else {
129 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
130 }
131 if (err
16.1
'err' is >= 0
< 0) {
17
Taking false branch
132 errno(*__errno_location ()) = -err;
133 nvme_show_perror("Error");
134 }
135 if (err
17.1
'err' is 0
)
18
Taking false branch
136 return err;
137
138 if (cfg.host_gen > 1) {
19
Assuming field 'host_gen' is > 1
20
Taking true branch
139 errno(*__errno_location ()) = EINVAL22;
21
Potential memory leak
140 nvme_show_perror("host-generate = '%d'", cfg.host_gen);
141 return -errno(*__errno_location ());
142 }
143
144 if (argconfig_parse_seen(opts, "config-file")) {
145 __cleanup_free__attribute__((cleanup(freep))) char *conf_str = NULL((void*)0);
146 size_t length = 0;
147 enum json_tokener_error jerr;
148
149 err = read_file2buffer(cfg.cfg_file, &conf_str, &length);
150 if (err) {
151 nvme_show_perror("config-file %s", cfg.cfg_file);
152 return err;
153 }
154 configuration = json_tokener_parse_verbose(conf_str, &jerr);
155 if (!configuration) {
156 nvme_show_error(nvme_show_message(1, "Failed to parse JSON file %s: %s", cfg.
cfg_file, json_tokener_error_desc(jerr))
157 "Failed to parse JSON file %s: %s",nvme_show_message(1, "Failed to parse JSON file %s: %s", cfg.
cfg_file, json_tokener_error_desc(jerr))
158 cfg.cfg_file,nvme_show_message(1, "Failed to parse JSON file %s: %s", cfg.
cfg_file, json_tokener_error_desc(jerr))
159 json_tokener_error_desc(jerr))nvme_show_message(1, "Failed to parse JSON file %s: %s", cfg.
cfg_file, json_tokener_error_desc(jerr))
;
160 return -EINVAL22;
161 }
162 tl.configuration = configuration;
163 }
164
165 if (!has_binary_file) {
166 size_t max_data_tx;
167 size_t power2;
168 __u8 mdts = 0;
169
170 err = libnvme_get_telemetry_max(hdl, NULL((void*)0), &max_data_tx);
171 if (err) {
172 nvme_show_err(err, "identify_ctrl");
173 return err;
174 }
175 power2 = max_data_tx / NVME_LOG_PAGE_PDU_SIZE4096;
176 while (power2 && !(1 & power2)) {
177 power2 >>= 1;
178 mdts++;
179 }
180
181 err = sldgm_dynamic_telemetry(hdl, cfg.host_gen, cfg.ctrl_init, true1,
182 mdts, cfg.data_area, &tlog, &tl.log_size);
183 if (err) {
184 nvme_show_err(err, "get-telemetry-log");
185 return err;
186 }
187 }
188 tl.log = tlog;
189 solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area);
190
191 /* Check if jq filter is requested and available */
192 if (cfg.jq_filter && configuration) {
193 struct json_object *jq_filter_obj = NULL((void*)0);
194
195 if (json_object_object_get_ex(configuration, cfg.jq_filter,
196 &jq_filter_obj)) {
197 const char *jq_filter_str;
198
199 jq_filter_str = json_object_get_string(jq_filter_obj);
200 if (jq_filter_str) {
201 /* Get JSON string representation */
202 const char *json_str;
203 char cmd[1024];
204 FILE *jq_pipe;
205
206 json_str = json_object_to_json_string(tl.root);
207
208 /* Create jq command and pipe JSON through it */
209 snprintf(cmd, sizeof(cmd), "jq -r '%s'",
210 jq_filter_str);
211 jq_pipe = popen(cmd, "w");
212 if (jq_pipe) {
213 fprintf(jq_pipe, "%s", json_str);
214 err = pclose(jq_pipe);
215 if (err != 0)
216 err = -EINVAL22;
217 } else {
218 errno(*__errno_location ()) = ENOENT2;
219 nvme_show_perror(
220 "Failed to execute jq command");
221 err = -ENOENT2;
222 }
223 } else {
224 errno(*__errno_location ()) = EINVAL22;
225 nvme_show_perror(
226 "jq filter entry '%s' is not a valid string",
227 cfg.jq_filter);
228 err = -EINVAL22;
229 }
230 } else {
231 errno(*__errno_location ()) = ENOENT2;
232 nvme_show_perror(
233 "jq filter entry '%s' not found in configuration file",
234 cfg.jq_filter);
235 err = -ENOENT2;
236 }
237 } else {
238 /*
239 * No jq filter requested or no config file,
240 * use normal JSON output
241 */
242 json_print_object(tl.root, NULL)printf("%s", json_object_to_json_string_ext(tl.root, (1 <<
1) | (1 << 4)))
;
243 }
244 printf("\n");
245
246 return err;
247}