Bug Summary

File:.build-ci/../libnvme/src/nvme/json.c
Warning:line 211, column 10
Potential leak of memory pointed to by 'ptr'

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 json.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 -fhalf-no-semantic-interposition -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 libnvme/src/libnvme3.so.3.0.0.p -I libnvme/src -I ../libnvme/src -I ccan -I ../ccan -I . -I .. -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 -fvisibility=hidden -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 ../libnvme/src/nvme/json.c
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of libnvme.
4 * Copyright (c) 2021 SUSE Software Solutions
5 *
6 * Authors: Hannes Reinecke <hare@suse.de>
7 */
8
9#include <fcntl.h>
10#include <string.h>
11#include <unistd.h>
12
13#include <json.h>
14
15#include <libnvme.h>
16
17#include "cleanup.h"
18#include "private.h"
19
20#define JSON_UPDATE_INT_OPTION(c, k, a, o)if (!strcmp("a", k ) && !c->a) c->a = json_object_get_int
(o);
\
21 if (!strcmp(# a, k ) && !c->a) c->a = json_object_get_int(o);
22#define JSON_UPDATE_BOOL_OPTION(c, k, a, o)if (!strcmp("a", k ) && !c->a) c->a = json_object_get_boolean
(o);
\
23 if (!strcmp(# a, k ) && !c->a) c->a = json_object_get_boolean(o);
24
25static void json_update_attributes(libnvme_ctrl_t c,
26 struct json_object *ctrl_obj)
27{
28 struct libnvme_fabrics_config *cfg = &c->cfg;
29
30 json_object_object_foreach(ctrl_obj, key_str, val_obj)char *key_str = ((void*)0); struct json_object *val_obj __attribute__
((__unused__)) = ((void*)0); for (struct lh_entry *entrykey_str
= lh_table_head(json_object_get_object(ctrl_obj)), *entry_nextkey_str
= ((void*)0); ({ if (entrykey_str) { key_str = (char *)lh_entry_k
(entrykey_str); val_obj = (struct json_object *)lh_entry_v(entrykey_str
); entry_nextkey_str = lh_entry_next(entrykey_str); }; entrykey_str
; }); entrykey_str = entry_nextkey_str)
{
31 JSON_UPDATE_INT_OPTION(cfg, key_str,if (!strcmp("nr_io_queues", key_str ) && !cfg->nr_io_queues
) cfg->nr_io_queues = json_object_get_int(val_obj);
32 nr_io_queues, val_obj)if (!strcmp("nr_io_queues", key_str ) && !cfg->nr_io_queues
) cfg->nr_io_queues = json_object_get_int(val_obj);
;
33 JSON_UPDATE_INT_OPTION(cfg, key_str,if (!strcmp("nr_write_queues", key_str ) && !cfg->
nr_write_queues) cfg->nr_write_queues = json_object_get_int
(val_obj);
34 nr_write_queues, val_obj)if (!strcmp("nr_write_queues", key_str ) && !cfg->
nr_write_queues) cfg->nr_write_queues = json_object_get_int
(val_obj);
;
35 JSON_UPDATE_INT_OPTION(cfg, key_str,if (!strcmp("nr_poll_queues", key_str ) && !cfg->nr_poll_queues
) cfg->nr_poll_queues = json_object_get_int(val_obj);
36 nr_poll_queues, val_obj)if (!strcmp("nr_poll_queues", key_str ) && !cfg->nr_poll_queues
) cfg->nr_poll_queues = json_object_get_int(val_obj);
;
37 JSON_UPDATE_INT_OPTION(cfg, key_str,if (!strcmp("queue_size", key_str ) && !cfg->queue_size
) cfg->queue_size = json_object_get_int(val_obj);
38 queue_size, val_obj)if (!strcmp("queue_size", key_str ) && !cfg->queue_size
) cfg->queue_size = json_object_get_int(val_obj);
;
39 JSON_UPDATE_INT_OPTION(cfg, key_str,if (!strcmp("keep_alive_tmo", key_str ) && !cfg->keep_alive_tmo
) cfg->keep_alive_tmo = json_object_get_int(val_obj);
40 keep_alive_tmo, val_obj)if (!strcmp("keep_alive_tmo", key_str ) && !cfg->keep_alive_tmo
) cfg->keep_alive_tmo = json_object_get_int(val_obj);
;
41 JSON_UPDATE_INT_OPTION(cfg, key_str,if (!strcmp("reconnect_delay", key_str ) && !cfg->
reconnect_delay) cfg->reconnect_delay = json_object_get_int
(val_obj);
42 reconnect_delay, val_obj)if (!strcmp("reconnect_delay", key_str ) && !cfg->
reconnect_delay) cfg->reconnect_delay = json_object_get_int
(val_obj);
;
43 if (!strcmp("ctrl_loss_tmo", key_str) &&
44 cfg->ctrl_loss_tmo != NVMF_DEF_CTRL_LOSS_TMO600)
45 cfg->ctrl_loss_tmo = json_object_get_int(val_obj);
46 JSON_UPDATE_INT_OPTION(cfg, key_str,if (!strcmp("fast_io_fail_tmo", key_str ) && !cfg->
fast_io_fail_tmo) cfg->fast_io_fail_tmo = json_object_get_int
(val_obj);
47 fast_io_fail_tmo, val_obj)if (!strcmp("fast_io_fail_tmo", key_str ) && !cfg->
fast_io_fail_tmo) cfg->fast_io_fail_tmo = json_object_get_int
(val_obj);
;
48 if (!strcmp("tos", key_str) && cfg->tos != -1)
49 cfg->tos = json_object_get_int(val_obj);
50 JSON_UPDATE_BOOL_OPTION(cfg, key_str,if (!strcmp("duplicate_connect", key_str ) && !cfg->
duplicate_connect) cfg->duplicate_connect = json_object_get_boolean
(val_obj);
51 duplicate_connect, val_obj)if (!strcmp("duplicate_connect", key_str ) && !cfg->
duplicate_connect) cfg->duplicate_connect = json_object_get_boolean
(val_obj);
;
52 JSON_UPDATE_BOOL_OPTION(cfg, key_str,if (!strcmp("disable_sqflow", key_str ) && !cfg->disable_sqflow
) cfg->disable_sqflow = json_object_get_boolean(val_obj);
53 disable_sqflow, val_obj)if (!strcmp("disable_sqflow", key_str ) && !cfg->disable_sqflow
) cfg->disable_sqflow = json_object_get_boolean(val_obj);
;
54 JSON_UPDATE_BOOL_OPTION(cfg, key_str,if (!strcmp("hdr_digest", key_str ) && !cfg->hdr_digest
) cfg->hdr_digest = json_object_get_boolean(val_obj);
55 hdr_digest, val_obj)if (!strcmp("hdr_digest", key_str ) && !cfg->hdr_digest
) cfg->hdr_digest = json_object_get_boolean(val_obj);
;
56 JSON_UPDATE_BOOL_OPTION(cfg, key_str,if (!strcmp("data_digest", key_str ) && !cfg->data_digest
) cfg->data_digest = json_object_get_boolean(val_obj);
57 data_digest, val_obj)if (!strcmp("data_digest", key_str ) && !cfg->data_digest
) cfg->data_digest = json_object_get_boolean(val_obj);
;
58 JSON_UPDATE_BOOL_OPTION(cfg, key_str,if (!strcmp("tls", key_str ) && !cfg->tls) cfg->
tls = json_object_get_boolean(val_obj);
59 tls, val_obj)if (!strcmp("tls", key_str ) && !cfg->tls) cfg->
tls = json_object_get_boolean(val_obj);
;
60 JSON_UPDATE_BOOL_OPTION(cfg, key_str,if (!strcmp("concat", key_str ) && !cfg->concat) cfg
->concat = json_object_get_boolean(val_obj);
61 concat, val_obj)if (!strcmp("concat", key_str ) && !cfg->concat) cfg
->concat = json_object_get_boolean(val_obj);
;
62 if (!strcmp("persistent", key_str) &&
63 !libnvme_ctrl_get_persistent(c))
64 libnvme_ctrl_set_persistent(c, true1);
65 if (!strcmp("discovery", key_str) &&
66 !libnvme_ctrl_get_discovery_ctrl(c))
67 libnvme_ctrl_set_discovery_ctrl(c, true1);
68 if (!strcmp("keyring", key_str))
69 libnvme_ctrl_set_keyring(c,
70 json_object_get_string(val_obj));
71 if (!strcmp("tls_key_identity", key_str)) {
72 libnvme_ctrl_set_tls_key_identity(c,
73 json_object_get_string(val_obj));
74 }
75 if (!strcmp("tls_key", key_str)) {
76 libnvme_ctrl_set_tls_key(c,
77 json_object_get_string(val_obj));
78 }
79 }
80}
81
82static void json_parse_port(libnvme_subsystem_t s, struct json_object *port_obj)
83{
84 libnvme_ctrl_t c;
85 struct json_object *attr_obj;
86 struct libnvme_ctrl_params params = {};
87
88 attr_obj = json_object_object_get(port_obj, "transport");
89 if (!attr_obj)
90 return;
91 params.transport = json_object_get_string(attr_obj);
92 attr_obj = json_object_object_get(port_obj, "traddr");
93 if (attr_obj)
94 params.traddr = json_object_get_string(attr_obj);
95 attr_obj = json_object_object_get(port_obj, "host_traddr");
96 if (attr_obj)
97 params.host_traddr = json_object_get_string(attr_obj);
98 attr_obj = json_object_object_get(port_obj, "host_iface");
99 if (attr_obj)
100 params.host_iface = json_object_get_string(attr_obj);
101 attr_obj = json_object_object_get(port_obj, "trsvcid");
102 if (attr_obj)
103 params.trsvcid = json_object_get_string(attr_obj);
104 c = libnvme_lookup_ctrl(s, &params, NULL((void*)0));
105 if (!c)
106 return;
107 json_update_attributes(c, port_obj);
108 attr_obj = json_object_object_get(port_obj, "dhchap_key");
109 if (attr_obj)
110 libnvme_ctrl_set_dhchap_host_key(c, json_object_get_string(attr_obj));
111 attr_obj = json_object_object_get(port_obj, "dhchap_ctrl_key");
112 if (attr_obj)
113 libnvme_ctrl_set_dhchap_ctrl_key(c, json_object_get_string(attr_obj));
114 attr_obj = json_object_object_get(port_obj, "keyring");
115 if (attr_obj)
116 libnvme_ctrl_set_keyring(c, json_object_get_string(attr_obj));
117 attr_obj = json_object_object_get(port_obj, "tls_key_identity");
118 if (attr_obj) {
119 libnvme_ctrl_set_tls_key_identity(c,
120 json_object_get_string(attr_obj));
121 }
122 attr_obj = json_object_object_get(port_obj, "tls_key");
123 if (attr_obj) {
124 libnvme_ctrl_set_tls_key(c,
125 json_object_get_string(attr_obj));
126 }
127}
128
129static void json_parse_subsys(libnvme_host_t h, struct json_object *subsys_obj)
130{
131 struct json_object *nqn_obj, *port_array;
132 libnvme_subsystem_t s;
133 const char *nqn = "";
134 int p;
135
136 nqn_obj = json_object_object_get(subsys_obj, "nqn");
137 if (nqn_obj)
138 nqn = json_object_get_string(nqn_obj);
139 s = libnvme_lookup_subsystem(h, NULL((void*)0), nqn);
140 if (!s)
141 return;
142
143 port_array = json_object_object_get(subsys_obj, "ports");
144 if (!port_array)
145 return;
146 for (p = 0; p < json_object_array_length(port_array); p++) {
147 struct json_object *port_obj;
148
149 port_obj = json_object_array_get_idx(port_array, p);
150 if (port_obj)
151 json_parse_port(s, port_obj);
152 }
153}
154
155static void json_parse_host(struct libnvme_global_ctx *ctx, struct json_object *host_obj)
156{
157 struct json_object *attr_obj, *subsys_array, *subsys_obj;
158 libnvme_host_t h;
159 const char *hostnqn = NULL((void*)0), *hostid = NULL((void*)0);
160 int s;
161
162 attr_obj = json_object_object_get(host_obj, "hostnqn");
163 if (attr_obj)
164 hostnqn = json_object_get_string(attr_obj);
165 attr_obj = json_object_object_get(host_obj, "hostid");
166 if (attr_obj)
167 hostid = json_object_get_string(attr_obj);
168 libnvme_get_host(ctx, hostnqn, hostid, &h);
169 attr_obj = json_object_object_get(host_obj, "dhchap_key");
170 if (attr_obj)
171 libnvme_host_set_dhchap_host_key(h, json_object_get_string(attr_obj));
172 attr_obj = json_object_object_get(host_obj, "hostsymname");
173 if (attr_obj)
174 libnvme_host_set_hostsymname(h, json_object_get_string(attr_obj));
175 attr_obj = json_object_object_get(host_obj, "persistent_discovery_ctrl");
176 if (attr_obj)
177 libnvme_host_set_pdc_enabled(h, json_object_get_boolean(attr_obj));
178 subsys_array = json_object_object_get(host_obj, "subsystems");
179 if (!subsys_array)
180 return;
181 for (s = 0; s < json_object_array_length(subsys_array); s++) {
182 subsys_obj = json_object_array_get_idx(subsys_array, s);
183 if (subsys_obj)
184 json_parse_subsys(h, subsys_obj);
185 }
186}
187
188static DEFINE_CLEANUP_FUNC(cleanup_tokener, json_tokener *, json_tokener_free)void cleanup_tokener(json_tokener * *__p) { if (*__p) json_tokener_free
(*__p); }
189#define __cleanup_tokener__attribute__((cleanup(cleanup_tokener))) __cleanup(cleanup_tokener)__attribute__((cleanup(cleanup_tokener)))
190
191static struct json_object *parse_json(struct libnvme_global_ctx *ctx, int fd)
192{
193 char buf[JSON_FILE_BUF_SIZE4096];
194 struct json_object *obj;
195 char *str = NULL((void*)0);
196 __cleanup_tokener__attribute__((cleanup(cleanup_tokener))) json_tokener *tok = NULL((void*)0);
197 int ret;
198 __cleanup_free__attribute__((cleanup(freep))) void *ptr = NULL((void*)0);
199 int len = 0;
200
201 while ((ret = read(fd, buf, JSON_FILE_BUF_SIZE4096)) > 0) {
3
Assuming the condition is true
4
Loop condition is true. Entering loop body
8
Assuming the condition is false
202 str = realloc(ptr, len + ret);
5
Memory is allocated
203 if (!str)
6
Assuming 'str' is non-null
7
Taking false branch
204 return NULL((void*)0);
205 memcpy(&str[len], buf, ret);
206 len += ret;
207 ptr = str;
208 }
209
210 if (ret < 0 || !len)
9
Assuming 'ret' is < 0
211 return NULL((void*)0);
10
Potential leak of memory pointed to by 'ptr'
212
213 tok = json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH32);
214 if (!tok)
215 return NULL((void*)0);
216
217 /* Enforce correctly formatted JSON */
218 tok->flags = JSON_TOKENER_STRICT0x01;
219
220 obj = json_tokener_parse_ex(tok, str, len);
221 if (!obj)
222 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "JSON parsing failed: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "JSON parsing failed: %s\n"
, json_util_get_last_err())
223 json_util_get_last_err())__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "JSON parsing failed: %s\n"
, json_util_get_last_err())
;
224
225 return obj;
226}
227
228int json_read_config(struct libnvme_global_ctx *ctx, const char *config_file)
229{
230 struct json_object *json_root, *host_obj;
231 int fd, h;
232
233 fd = open(config_file, O_RDONLY00);
234 if (fd
0.1
'fd' is >= 0
< 0) {
1
Taking false branch
235 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "Error opening %s, %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "Error opening %s, %s\n"
, config_file, libnvme_strerror((*__errno_location ())))
236 config_file, libnvme_strerror(errno))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "Error opening %s, %s\n"
, config_file, libnvme_strerror((*__errno_location ())))
;
237 return fd;
238 }
239 json_root = parse_json(ctx, fd);
2
Calling 'parse_json'
240 close(fd);
241 if (!json_root)
242 return -EPROTO71;
243 if (!json_object_is_type(json_root, json_type_array)) {
244 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "Wrong format, expected array\n")__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "Wrong format, expected array\n"
)
;
245 json_object_put(json_root);
246 return -EPROTO71;
247 }
248 for (h = 0; h < json_object_array_length(json_root); h++) {
249 host_obj = json_object_array_get_idx(json_root, h);
250 if (host_obj)
251 json_parse_host(ctx, host_obj);
252 }
253 json_object_put(json_root);
254 return 0;
255}
256
257#define JSON_STRING_OPTION(c, p, o)if ((c)->o && strcmp((c)->o, "none")) json_object_object_add
((p), "o" , json_object_new_string((c)->o))
\
258 if ((c)->o && strcmp((c)->o, "none")) \
259 json_object_object_add((p), # o , \
260 json_object_new_string((c)->o))
261#define JSON_INT_OPTION(c, p, o, d)if ((c)->o != d) json_object_object_add((p), "o" , json_object_new_int
((c)->o))
\
262 if ((c)->o != d) \
263 json_object_object_add((p), # o , \
264 json_object_new_int((c)->o))
265#define JSON_BOOL_OPTION(c, p, o)if ((c)->o) json_object_object_add((p), "o" , json_object_new_boolean
((c)->o))
\
266 if ((c)->o) \
267 json_object_object_add((p), # o , \
268 json_object_new_boolean((c)->o))
269
270static void json_update_port(struct json_object *ctrl_array, libnvme_ctrl_t c)
271{
272 struct libnvme_fabrics_config *cfg = &c->cfg;
273 struct json_object *port_obj = json_object_new_object();
274 const char *transport, *value;
275
276 transport = libnvme_ctrl_get_transport(c);
277 if (!strcmp(transport, "pcie")) {
278 json_object_put(port_obj);
279 return;
280 }
281
282 json_object_object_add(port_obj, "transport",
283 json_object_new_string(transport));
284 value = libnvme_ctrl_get_traddr(c);
285 if (value)
286 json_object_object_add(port_obj, "traddr",
287 json_object_new_string(value));
288 value = libnvme_ctrl_get_host_traddr(c);
289 if (value)
290 json_object_object_add(port_obj, "host_traddr",
291 json_object_new_string(value));
292 value = libnvme_ctrl_get_host_iface(c);
293 if (value)
294 json_object_object_add(port_obj, "host_iface",
295 json_object_new_string(value));
296 value = libnvme_ctrl_get_trsvcid(c);
297 if (value)
298 json_object_object_add(port_obj, "trsvcid",
299 json_object_new_string(value));
300 value = libnvme_ctrl_get_dhchap_host_key(c);
301 if (value)
302 json_object_object_add(port_obj, "dhchap_key",
303 json_object_new_string(value));
304 value = libnvme_ctrl_get_dhchap_ctrl_key(c);
305 if (value)
306 json_object_object_add(port_obj, "dhchap_ctrl_key",
307 json_object_new_string(value));
308 JSON_BOOL_OPTION(cfg, port_obj, tls)if ((cfg)->tls) json_object_object_add((port_obj), "tls" ,
json_object_new_boolean((cfg)->tls))
;
309 value = libnvme_ctrl_get_keyring(c);
310 if (value)
311 json_object_object_add(port_obj, "keyring",
312 json_object_new_string(value));
313 value = libnvme_ctrl_get_tls_key_identity(c);
314 if (value)
315 json_object_object_add(port_obj, "tls_key_identity",
316 json_object_new_string(value));
317 value = libnvme_ctrl_get_tls_key(c);
318 if (value)
319 json_object_object_add(port_obj, "tls_key",
320 json_object_new_string(value));
321 JSON_INT_OPTION(cfg, port_obj, nr_io_queues, 0)if ((cfg)->nr_io_queues != 0) json_object_object_add((port_obj
), "nr_io_queues" , json_object_new_int((cfg)->nr_io_queues
))
;
322 JSON_INT_OPTION(cfg, port_obj, nr_write_queues, 0)if ((cfg)->nr_write_queues != 0) json_object_object_add((port_obj
), "nr_write_queues" , json_object_new_int((cfg)->nr_write_queues
))
;
323 JSON_INT_OPTION(cfg, port_obj, nr_poll_queues, 0)if ((cfg)->nr_poll_queues != 0) json_object_object_add((port_obj
), "nr_poll_queues" , json_object_new_int((cfg)->nr_poll_queues
))
;
324 JSON_INT_OPTION(cfg, port_obj, queue_size, 0)if ((cfg)->queue_size != 0) json_object_object_add((port_obj
), "queue_size" , json_object_new_int((cfg)->queue_size))
;
325 JSON_INT_OPTION(cfg, port_obj, keep_alive_tmo, 0)if ((cfg)->keep_alive_tmo != 0) json_object_object_add((port_obj
), "keep_alive_tmo" , json_object_new_int((cfg)->keep_alive_tmo
))
;
326 JSON_INT_OPTION(cfg, port_obj, reconnect_delay, 0)if ((cfg)->reconnect_delay != 0) json_object_object_add((port_obj
), "reconnect_delay" , json_object_new_int((cfg)->reconnect_delay
))
;
327 if (strcmp(transport, "loop")) {
328 JSON_INT_OPTION(cfg, port_obj, ctrl_loss_tmo,if ((cfg)->ctrl_loss_tmo != 600) json_object_object_add((port_obj
), "ctrl_loss_tmo" , json_object_new_int((cfg)->ctrl_loss_tmo
))
329 NVMF_DEF_CTRL_LOSS_TMO)if ((cfg)->ctrl_loss_tmo != 600) json_object_object_add((port_obj
), "ctrl_loss_tmo" , json_object_new_int((cfg)->ctrl_loss_tmo
))
;
330 JSON_INT_OPTION(cfg, port_obj, fast_io_fail_tmo, 0)if ((cfg)->fast_io_fail_tmo != 0) json_object_object_add((
port_obj), "fast_io_fail_tmo" , json_object_new_int((cfg)->
fast_io_fail_tmo))
;
331 }
332 JSON_INT_OPTION(cfg, port_obj, tos, -1)if ((cfg)->tos != -1) json_object_object_add((port_obj), "tos"
, json_object_new_int((cfg)->tos))
;
333 JSON_BOOL_OPTION(cfg, port_obj, duplicate_connect)if ((cfg)->duplicate_connect) json_object_object_add((port_obj
), "duplicate_connect" , json_object_new_boolean((cfg)->duplicate_connect
))
;
334 JSON_BOOL_OPTION(cfg, port_obj, disable_sqflow)if ((cfg)->disable_sqflow) json_object_object_add((port_obj
), "disable_sqflow" , json_object_new_boolean((cfg)->disable_sqflow
))
;
335 JSON_BOOL_OPTION(cfg, port_obj, hdr_digest)if ((cfg)->hdr_digest) json_object_object_add((port_obj), "hdr_digest"
, json_object_new_boolean((cfg)->hdr_digest))
;
336 JSON_BOOL_OPTION(cfg, port_obj, data_digest)if ((cfg)->data_digest) json_object_object_add((port_obj),
"data_digest" , json_object_new_boolean((cfg)->data_digest
))
;
337 JSON_BOOL_OPTION(cfg, port_obj, concat)if ((cfg)->concat) json_object_object_add((port_obj), "concat"
, json_object_new_boolean((cfg)->concat))
;
338 if (libnvme_ctrl_get_persistent(c))
339 json_object_object_add(port_obj, "persistent",
340 json_object_new_boolean(true1));
341 if (libnvme_ctrl_get_discovery_ctrl(c))
342 json_object_object_add(port_obj, "discovery",
343 json_object_new_boolean(true1));
344
345 json_object_array_add(ctrl_array, port_obj);
346}
347
348static void json_update_subsys(struct json_object *subsys_array,
349 libnvme_subsystem_t s)
350{
351 libnvme_ctrl_t c;
352 const char *subsysnqn = libnvme_subsystem_get_subsysnqn(s);
353 struct json_object *subsys_obj = json_object_new_object();
354 struct json_object *port_array;
355
356 /* Skip discovery subsystems as the nqn is not unique */
357 if (!strcmp(subsysnqn, NVME_DISC_SUBSYS_NAME"nqn.2014-08.org.nvmexpress.discovery"))
358 return;
359
360 json_object_object_add(subsys_obj, "nqn",
361 json_object_new_string(subsysnqn));
362 port_array = json_object_new_array();
363 libnvme_subsystem_for_each_ctrl(s, c)for (c = libnvme_subsystem_first_ctrl(s); c != ((void*)0); c =
libnvme_subsystem_next_ctrl(s, c))
{
364 json_update_port(port_array, c);
365 }
366 if (json_object_array_length(port_array)) {
367 json_object_object_add(subsys_obj, "ports", port_array);
368 json_object_array_add(subsys_array, subsys_obj);
369 } else {
370 json_object_put(port_array);
371 json_object_put(subsys_obj);
372 }
373}
374
375int json_update_config(struct libnvme_global_ctx *ctx, int fd)
376{
377 libnvme_host_t h;
378 struct json_object *json_root, *host_obj;
379 struct json_object *subsys_array;
380 int ret = 0;
381
382 json_root = json_object_new_array();
383 libnvme_for_each_host(ctx, h)for (h = libnvme_first_host(ctx); h != ((void*)0); h = libnvme_next_host
(ctx, h))
{
384 libnvme_subsystem_t s;
385 const char *hostnqn, *hostid, *dhchap_key, *hostsymname;
386
387 host_obj = json_object_new_object();
388 if (!host_obj)
389 continue;
390 hostnqn = libnvme_host_get_hostnqn(h);
391 json_object_object_add(host_obj, "hostnqn",
392 json_object_new_string(hostnqn));
393 hostid = libnvme_host_get_hostid(h);
394 if (hostid)
395 json_object_object_add(host_obj, "hostid",
396 json_object_new_string(hostid));
397 dhchap_key = libnvme_host_get_dhchap_host_key(h);
398 if (dhchap_key)
399 json_object_object_add(host_obj, "dhchap_key",
400 json_object_new_string(dhchap_key));
401 hostsymname = libnvme_host_get_hostsymname(h);
402 if (hostsymname)
403 json_object_object_add(host_obj, "hostsymname",
404 json_object_new_string(hostsymname));
405 if (h->pdc_enabled_valid)
406 json_object_object_add(host_obj, "persistent_discovery_ctrl",
407 json_object_new_boolean(h->pdc_enabled));
408 subsys_array = json_object_new_array();
409 libnvme_for_each_subsystem(h, s)for (s = libnvme_first_subsystem(h); s != ((void*)0); s = libnvme_next_subsystem
(h, s))
{
410 json_update_subsys(subsys_array, s);
411 }
412 if (json_object_array_length(subsys_array)) {
413 json_object_object_add(host_obj, "subsystems",
414 subsys_array);
415 json_object_array_add(json_root, host_obj);
416 } else {
417 json_object_put(subsys_array);
418 json_object_put(host_obj);
419 }
420 }
421 ret = json_object_to_fd(fd, json_root,
422 JSON_C_TO_STRING_PRETTY(1 << 1) |
423 JSON_C_TO_STRING_NOSLASHESCAPE(1 << 4));
424 if (ret < 0 || write(fd, "\n", 1) < 0) {
425 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Failed to write JSON config file: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to write JSON config file: %s\n"
, ret ? json_util_get_last_err() : strerror((*__errno_location
())))
426 ret ? json_util_get_last_err() : strerror(errno))__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to write JSON config file: %s\n"
, ret ? json_util_get_last_err() : strerror((*__errno_location
())))
;
427 ret = -EIO5;
428 }
429 json_object_put(json_root);
430
431 return ret;
432}
433
434static void json_dump_ctrl(struct json_object *ctrl_array, libnvme_ctrl_t c)
435{
436 struct libnvme_fabrics_config *cfg = &c->cfg;
437 struct json_object *ctrl_obj = json_object_new_object();
438 const char *name, *transport, *value;
439
440 name = libnvme_ctrl_get_name(c);
441 if (name && strlen(name))
442 json_object_object_add(ctrl_obj, "name",
443 json_object_new_string(name));
444 transport = libnvme_ctrl_get_transport(c);
445 json_object_object_add(ctrl_obj, "transport",
446 json_object_new_string(transport));
447 value = libnvme_ctrl_get_traddr(c);
448 if (value)
449 json_object_object_add(ctrl_obj, "traddr",
450 json_object_new_string(value));
451 value = libnvme_ctrl_get_host_traddr(c);
452 if (value)
453 json_object_object_add(ctrl_obj, "host_traddr",
454 json_object_new_string(value));
455 value = libnvme_ctrl_get_host_iface(c);
456 if (value)
457 json_object_object_add(ctrl_obj, "host_iface",
458 json_object_new_string(value));
459 value = libnvme_ctrl_get_trsvcid(c);
460 if (value)
461 json_object_object_add(ctrl_obj, "trsvcid",
462 json_object_new_string(value));
463 value = libnvme_ctrl_get_dhchap_host_key(c);
464 if (value)
465 json_object_object_add(ctrl_obj, "dhchap_key",
466 json_object_new_string(value));
467 value = libnvme_ctrl_get_dhchap_ctrl_key(c);
468 if (value)
469 json_object_object_add(ctrl_obj, "dhchap_ctrl_key",
470 json_object_new_string(value));
471 JSON_INT_OPTION(cfg, ctrl_obj, nr_io_queues, 0)if ((cfg)->nr_io_queues != 0) json_object_object_add((ctrl_obj
), "nr_io_queues" , json_object_new_int((cfg)->nr_io_queues
))
;
472 JSON_INT_OPTION(cfg, ctrl_obj, nr_write_queues, 0)if ((cfg)->nr_write_queues != 0) json_object_object_add((ctrl_obj
), "nr_write_queues" , json_object_new_int((cfg)->nr_write_queues
))
;
473 JSON_INT_OPTION(cfg, ctrl_obj, nr_poll_queues, 0)if ((cfg)->nr_poll_queues != 0) json_object_object_add((ctrl_obj
), "nr_poll_queues" , json_object_new_int((cfg)->nr_poll_queues
))
;
474 JSON_INT_OPTION(cfg, ctrl_obj, queue_size, 0)if ((cfg)->queue_size != 0) json_object_object_add((ctrl_obj
), "queue_size" , json_object_new_int((cfg)->queue_size))
;
475 JSON_INT_OPTION(cfg, ctrl_obj, keep_alive_tmo, 0)if ((cfg)->keep_alive_tmo != 0) json_object_object_add((ctrl_obj
), "keep_alive_tmo" , json_object_new_int((cfg)->keep_alive_tmo
))
;
476 JSON_INT_OPTION(cfg, ctrl_obj, reconnect_delay, 0)if ((cfg)->reconnect_delay != 0) json_object_object_add((ctrl_obj
), "reconnect_delay" , json_object_new_int((cfg)->reconnect_delay
))
;
477 if (strcmp(transport, "loop")) {
478 JSON_INT_OPTION(cfg, ctrl_obj, ctrl_loss_tmo,if ((cfg)->ctrl_loss_tmo != 600) json_object_object_add((ctrl_obj
), "ctrl_loss_tmo" , json_object_new_int((cfg)->ctrl_loss_tmo
))
479 NVMF_DEF_CTRL_LOSS_TMO)if ((cfg)->ctrl_loss_tmo != 600) json_object_object_add((ctrl_obj
), "ctrl_loss_tmo" , json_object_new_int((cfg)->ctrl_loss_tmo
))
;
480 JSON_INT_OPTION(cfg, ctrl_obj, fast_io_fail_tmo, 0)if ((cfg)->fast_io_fail_tmo != 0) json_object_object_add((
ctrl_obj), "fast_io_fail_tmo" , json_object_new_int((cfg)->
fast_io_fail_tmo))
;
481 }
482 JSON_INT_OPTION(cfg, ctrl_obj, tos, -1)if ((cfg)->tos != -1) json_object_object_add((ctrl_obj), "tos"
, json_object_new_int((cfg)->tos))
;
483 JSON_BOOL_OPTION(cfg, ctrl_obj, duplicate_connect)if ((cfg)->duplicate_connect) json_object_object_add((ctrl_obj
), "duplicate_connect" , json_object_new_boolean((cfg)->duplicate_connect
))
;
484 JSON_BOOL_OPTION(cfg, ctrl_obj, disable_sqflow)if ((cfg)->disable_sqflow) json_object_object_add((ctrl_obj
), "disable_sqflow" , json_object_new_boolean((cfg)->disable_sqflow
))
;
485 JSON_BOOL_OPTION(cfg, ctrl_obj, hdr_digest)if ((cfg)->hdr_digest) json_object_object_add((ctrl_obj), "hdr_digest"
, json_object_new_boolean((cfg)->hdr_digest))
;
486 JSON_BOOL_OPTION(cfg, ctrl_obj, data_digest)if ((cfg)->data_digest) json_object_object_add((ctrl_obj),
"data_digest" , json_object_new_boolean((cfg)->data_digest
))
;
487 if (!strcmp(transport, "tcp")) {
488 JSON_BOOL_OPTION(cfg, ctrl_obj, tls)if ((cfg)->tls) json_object_object_add((ctrl_obj), "tls" ,
json_object_new_boolean((cfg)->tls))
;
489
490 value = libnvme_ctrl_get_keyring(c);
491 if (value)
492 json_object_object_add(ctrl_obj, "keyring",
493 json_object_new_string(value));
494 value = libnvme_ctrl_get_tls_key_identity(c);
495 if (value)
496 json_object_object_add(ctrl_obj, "tls_key_identity",
497 json_object_new_string(value));
498 value = libnvme_ctrl_get_tls_key(c);
499 if (value)
500 json_object_object_add(ctrl_obj, "tls_key",
501 json_object_new_string(value));
502 }
503 JSON_BOOL_OPTION(cfg, ctrl_obj, concat)if ((cfg)->concat) json_object_object_add((ctrl_obj), "concat"
, json_object_new_boolean((cfg)->concat))
;
504 if (libnvme_ctrl_get_persistent(c))
505 json_object_object_add(ctrl_obj, "persistent",
506 json_object_new_boolean(true1));
507 if (libnvme_ctrl_get_discovery_ctrl(c))
508 json_object_object_add(ctrl_obj, "discovery",
509 json_object_new_boolean(true1));
510 json_object_array_add(ctrl_array, ctrl_obj);
511}
512
513static unsigned int json_dump_subsys_multipath(libnvme_subsystem_t s,
514 struct json_object *ns_array)
515{
516 libnvme_ns_t n;
517 libnvme_path_t p;
518 unsigned int i = 0;
519
520 libnvme_subsystem_for_each_ns(s, n)for (n = libnvme_subsystem_first_ns(s); n != ((void*)0); n = libnvme_subsystem_next_ns
(s, n))
{
521 struct json_object *ns_obj;
522 struct json_object *path_array;
523
524 ns_obj = json_object_new_object();
525 json_object_object_add(ns_obj, "nsid",
526 json_object_new_int(libnvme_ns_get_nsid(n)));
527 json_object_object_add(ns_obj, "name",
528 json_object_new_string(libnvme_ns_get_name(n)));
529
530 path_array = json_object_new_array();
531 libnvme_namespace_for_each_path(n, p)for (p = libnvme_namespace_first_path(n); p != ((void*)0); p =
libnvme_namespace_next_path(n, p))
{
532 struct json_object *path_obj;
533 struct json_object *ctrl_array;
534 libnvme_ctrl_t c;
535
536 path_obj = json_object_new_object();
537 json_object_object_add(path_obj, "path",
538 json_object_new_string(libnvme_path_get_name(p)));
539 json_object_object_add(path_obj, "ANAState",
540 json_object_new_string(libnvme_path_get_ana_state(p)));
541 json_object_object_add(path_obj, "NUMANodes",
542 json_object_new_string(libnvme_path_get_numa_nodes(p)));
543 json_object_object_add(path_obj, "qdepth",
544 json_object_new_int(libnvme_path_get_queue_depth(p)));
545
546 c = libnvme_path_get_ctrl(p);
547 ctrl_array = json_object_new_array();
548 json_dump_ctrl(ctrl_array, c);
549 json_object_object_add(path_obj, "controller", ctrl_array);
550 json_object_array_add(path_array, path_obj);
551 }
552 json_object_object_add(ns_obj, "paths", path_array);
553 json_object_array_add(ns_array, ns_obj);
554 i++;
555 }
556 return i;
557}
558
559static void json_dump_subsys_non_multipath(libnvme_subsystem_t s,
560 struct json_object *ns_array)
561{
562 libnvme_ctrl_t c;
563 libnvme_ns_t n;
564
565 libnvme_subsystem_for_each_ctrl(s, c)for (c = libnvme_subsystem_first_ctrl(s); c != ((void*)0); c =
libnvme_subsystem_next_ctrl(s, c))
{
566 libnvme_ctrl_for_each_ns(c, n)for (n = libnvme_ctrl_first_ns(c); n != ((void*)0); n = libnvme_ctrl_next_ns
(c, n))
{
567 struct json_object *ctrl_array;
568 struct json_object *ns_obj;
569
570 ns_obj = json_object_new_object();
571 json_object_object_add(ns_obj, "nsid",
572 json_object_new_int(libnvme_ns_get_nsid(n)));
573 json_object_object_add(ns_obj, "name",
574 json_object_new_string(libnvme_ns_get_name(n)));
575
576 ctrl_array = json_object_new_array();
577 json_dump_ctrl(ctrl_array, c);
578 json_object_object_add(ns_obj, "controller", ctrl_array);
579
580 json_object_array_add(ns_array, ns_obj);
581 }
582 }
583}
584
585static void json_dump_subsys(struct json_object *subsys_array,
586 libnvme_subsystem_t s)
587{
588 struct json_object *subsys_obj = json_object_new_object();
589 struct json_object *ns_array;
590
591 json_object_object_add(subsys_obj, "name",
592 json_object_new_string(libnvme_subsystem_get_name(s)));
593 json_object_object_add(subsys_obj, "nqn",
594 json_object_new_string(libnvme_subsystem_get_subsysnqn(s)));
595
596 ns_array = json_object_new_array();
597 if (!json_dump_subsys_multipath(s, ns_array))
598 json_dump_subsys_non_multipath(s, ns_array);
599
600 if (json_object_array_length(ns_array))
601 json_object_object_add(subsys_obj, "namespaces", ns_array);
602 else
603 json_object_put(ns_array);
604 json_object_array_add(subsys_array, subsys_obj);
605}
606
607int json_dump_tree(struct libnvme_global_ctx *ctx)
608{
609 libnvme_host_t h;
610 struct json_object *json_root, *host_obj;
611 struct json_object *host_array, *subsys_array;
612 int ret = 0;
613
614 json_root = json_object_new_object();
615 host_array = json_object_new_array();
616 libnvme_for_each_host(ctx, h)for (h = libnvme_first_host(ctx); h != ((void*)0); h = libnvme_next_host
(ctx, h))
{
617 libnvme_subsystem_t s;
618 const char *hostid, *dhchap_key;
619
620 host_obj = json_object_new_object();
621 json_object_object_add(host_obj, "hostnqn",
622 json_object_new_string(libnvme_host_get_hostnqn(h)));
623 hostid = libnvme_host_get_hostid(h);
624 if (hostid)
625 json_object_object_add(host_obj, "hostid",
626 json_object_new_string(hostid));
627 dhchap_key = libnvme_host_get_dhchap_host_key(h);
628 if (dhchap_key)
629 json_object_object_add(host_obj, "dhchap_key",
630 json_object_new_string(dhchap_key));
631 if (h->pdc_enabled_valid)
632 json_object_object_add(host_obj, "persistent_discovery_ctrl",
633 json_object_new_boolean(h->pdc_enabled));
634 subsys_array = json_object_new_array();
635 libnvme_for_each_subsystem(h, s)for (s = libnvme_first_subsystem(h); s != ((void*)0); s = libnvme_next_subsystem
(h, s))
{
636 json_dump_subsys(subsys_array, s);
637 }
638 if (json_object_array_length(subsys_array))
639 json_object_object_add(host_obj, "subsystems",
640 subsys_array);
641 else
642 json_object_put(subsys_array);
643 json_object_array_add(host_array, host_obj);
644 }
645 json_object_object_add(json_root, "hosts", host_array);
646
647 ret = json_object_to_fd(ctx->log.fd, json_root,
648 JSON_C_TO_STRING_PRETTY(1 << 1) |
649 JSON_C_TO_STRING_NOSLASHESCAPE(1 << 4));
650 if (ret < 0) {
651 libnvme_msg(ctx, LIBNVME_LOG_ERR, "Failed to write, %s\n",__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to write, %s\n"
, json_util_get_last_err())
652 json_util_get_last_err())__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to write, %s\n"
, json_util_get_last_err())
;
653 ret = -EIO5;
654 }
655 json_object_put(json_root);
656
657 return ret;
658}