Bug Summary

File:.build-ci/../src/config-convert.c
Warning:line 376, column 9
Opened stream never closed. Potential resource leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name config-convert.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 static -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/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I shared -I ../shared -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -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 -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-08-08-045408-589-1 -x c ../src/config-convert.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2026, Dell Technologies Inc. or its subsidiaries.
4 *
5 * Authors: Martin Belanger <Martin.Belanger@dell.com>
6 */
7
8#include <errno(*__errno_location ()).h>
9#include <stdio.h>
10#include <string.h>
11#include <unistd.h>
12
13#include <libnvme.h>
14
15#include "common.h"
16#include "config-convert.h"
17#include "fabrics.h"
18#include "logging.h"
19#include "nvme-print.h"
20#include "argconfig.h"
21#include "cleanup.h"
22
23#ifdef CONFIG_JSONC
24#include "nvme-json.h"
25
26struct legacy_key {
27 const char *json_key;
28 const char *ini_key;
29};
30
31/* Map config.json keys from underscore to hyphen notation. */
32static const struct legacy_key int_keys[] = {
33 { "nr_io_queues", "nr-io-queues" },
34 { "nr_write_queues", "nr-write-queues" },
35 { "nr_poll_queues", "nr-poll-queues" },
36 { "queue_size", "queue-size" },
37 { "keep_alive_tmo", "keep-alive-tmo" },
38 { "reconnect_delay", "reconnect-delay" },
39 { "ctrl_loss_tmo", "ctrl-loss-tmo" },
40 { "fast_io_fail_tmo", "fast-io-fail-tmo" },
41 { "tos", "tos" },
42};
43
44static const struct legacy_key bool_keys[] = {
45 { "duplicate_connect", "duplicate-connect" },
46 { "disable_sqflow", "disable-sqflow" },
47 { "hdr_digest", "hdr-digest" },
48 { "data_digest", "data-digest" },
49 { "tls", "tls" },
50 { "concat", "concat" },
51};
52
53static const struct legacy_key string_keys[] = {
54 { "tls_key", "tls-key" },
55 { "tls_key_identity", "tls-key-identity" },
56 { "keyring", "keyring" },
57 { "dhchap_key", "dhchap-secret" },
58 { "dhchap_ctrl_key", "dhchap-ctrl-secret" },
59};
60
61static const char *map_key(const struct legacy_key *table, size_t n,
62 const char *json_key)
63{
64 size_t i;
65
66 for (i = 0; i < n; i++)
67 if (!strcmp(table[i].json_key, json_key))
68 return table[i].ini_key;
69
70 return NULL((void*)0);
71}
72
73#define MAP_KEY(table, json_key)map_key(table, (sizeof(table) / sizeof((table)[0])), json_key
)
map_key(table, ARRAY_SIZE(table)(sizeof(table) / sizeof((table)[0])), json_key)
74
75static const char *json_get_string(struct json_object *obj, const char *key)
76{
77 struct json_object *val = json_object_object_get(obj, key);
78
79 return val ? json_object_get_string(val) : NULL((void*)0);
80}
81
82static bool_Bool json_get_bool(struct json_object *obj, const char *key)
83{
84 struct json_object *val = json_object_object_get(obj, key);
85
86 return val && json_object_get_boolean(val);
87}
88
89/* Copy supported tunable and security parameters into @params. */
90static void apply_port_params(struct libnvmf_params *params,
91 struct json_object *port_obj)
92{
93 json_object_object_foreach(port_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(port_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)
{
94 const char *ini_key;
95 char buf[32];
96
97 ini_key = MAP_KEY(int_keys, key_str)map_key(int_keys, (sizeof(int_keys) / sizeof((int_keys)[0])),
key_str)
;
98 if (ini_key) {
99 snprintf(buf, sizeof(buf), "%d",
100 json_object_get_int(val_obj));
101 libnvmf_params_set(params, ini_key, buf);
102 continue;
103 }
104 ini_key = MAP_KEY(bool_keys, key_str)map_key(bool_keys, (sizeof(bool_keys) / sizeof((bool_keys)[0]
)), key_str)
;
105 if (ini_key) {
106 libnvmf_params_set(params, ini_key,
107 json_object_get_boolean(val_obj) ?
108 "true" : "false");
109 continue;
110 }
111 ini_key = MAP_KEY(string_keys, key_str)map_key(string_keys, (sizeof(string_keys) / sizeof((string_keys
)[0])), key_str)
;
112 if (ini_key)
113 libnvmf_params_set(params, ini_key,
114 json_object_get_string(val_obj));
115 }
116}
117
118/*
119 * The DH-HMAC-CHAP secret is defined per (hostnqn, subsysnqn), not per path
120 * (NVMe Base Specification 2.3, section 8.3.5.5.7). If a port does not
121 * specify a secret, inherit the host-level default. If both are present but
122 * differ, keep the port-specific value and log the mismatch.
123 */
124static void apply_dhchap_default(struct libnvmf_params *params,
125 struct json_object *port_obj, const char *host_default)
126{
127 const char *port_value = json_get_string(port_obj, "dhchap_key");
128
129 if (!host_default)
130 return;
131
132 if (!port_value) {
133 libnvmf_params_set(params, "dhchap-secret", host_default);
134 } else if (strcmp(port_value, host_default)) {
135 nvme_show_verbose_info(nvme_show_verbose_message("config convert: dhchap_key differs between host default and one connection; keeping the connection's own value"
)
136 "config convert: dhchap_key differs between host default and one connection; keeping the connection's own value")nvme_show_verbose_message("config convert: dhchap_key differs between host default and one connection; keeping the connection's own value"
)
;
137 }
138}
139
140static void apply_dc_persistent(struct libnvmf_params *params,
141 struct json_object *port_obj)
142{
143 struct json_object *val = json_object_object_get(port_obj, "persistent");
144
145 if (val)
146 libnvmf_params_set(params, "persistent",
147 json_object_get_boolean(val) ? "true" : "false");
148}
149
150static int convert_port(struct libnvmf_config_emitter *emitter,
151 const char *hostnqn, const char *hostid,
152 const char *hostsymname, const char *host_dhchap_key,
153 const char *subsysnqn, struct json_object *port_obj)
154{
155 struct libnvmf_params *params;
156 bool_Bool is_dc = json_get_bool(port_obj, "discovery");
157 int ret;
158
159 params = libnvmf_params_new();
160 if (!params)
161 return -ENOMEM12;
162
163 apply_port_params(params, port_obj);
164 apply_dhchap_default(params, port_obj, host_dhchap_key);
165 if (is_dc)
166 apply_dc_persistent(params, port_obj);
167
168 ret = libnvmf_config_emit_add(emitter, is_dc,
169 json_get_string(port_obj, "transport"),
170 json_get_string(port_obj, "traddr"),
171 json_get_string(port_obj, "trsvcid"),
172 subsysnqn,
173 json_get_string(port_obj, "host_traddr"),
174 json_get_string(port_obj, "host_iface"),
175 hostnqn, hostid, params, hostsymname);
176
177 libnvmf_params_free(params);
178
179 /*
180 * A rejected entry (for example, invalid addressing or a conflicting
181 * persona) affects only that entry. Log the error and continue
182 * converting, matching json_parse_port()'s own tolerance. Stop only
183 * if memory allocation fails.
184 */
185 if (ret == -ENOMEM12)
186 return ret;
187 if (ret)
188 nvme_show_error(nvme_show_message(1, "config convert: skipping an entry that could not be added: %s"
, libnvme_strerror(-ret))
189 "config convert: skipping an entry that could not be added: %s",nvme_show_message(1, "config convert: skipping an entry that could not be added: %s"
, libnvme_strerror(-ret))
190 libnvme_strerror(-ret))nvme_show_message(1, "config convert: skipping an entry that could not be added: %s"
, libnvme_strerror(-ret))
;
191
192 return 0;
193}
194
195static int convert_subsys(struct libnvmf_config_emitter *emitter,
196 const char *hostnqn, const char *hostid,
197 const char *hostsymname, const char *host_dhchap_key,
198 struct json_object *subsys_obj)
199{
200 struct json_object *port_array;
201 const char *nqn = json_get_string(subsys_obj, "nqn");
202 int p, ret;
203
204 /* The well-known discovery NQN is the emitter's default value. */
205 if (nqn && (!*nqn || !strcmp(nqn, NVME_DISC_SUBSYS_NAME"nqn.2014-08.org.nvmexpress.discovery")))
206 nqn = NULL((void*)0);
207
208 port_array = json_object_object_get(subsys_obj, "ports");
209 if (!port_array)
210 return 0;
211
212 for (p = 0; p < json_object_array_length(port_array); p++) {
213 struct json_object *port_obj =
214 json_object_array_get_idx(port_array, p);
215
216 if (!port_obj)
217 continue;
218 ret = convert_port(emitter, hostnqn, hostid, hostsymname,
219 host_dhchap_key, nqn, port_obj);
220 if (ret)
221 return ret;
222 }
223
224 return 0;
225}
226
227static int convert_host(struct libnvmf_config_emitter *emitter,
228 struct json_object *host_obj)
229{
230 struct json_object *subsys_array;
231 const char *hostnqn = json_get_string(host_obj, "hostnqn");
232 const char *hostid = json_get_string(host_obj, "hostid");
233 const char *hostsymname = json_get_string(host_obj, "hostsymname");
234 const char *host_dhchap_key = json_get_string(host_obj, "dhchap_key");
235 int s, ret;
236
237 subsys_array = json_object_object_get(host_obj, "subsystems");
238 if (!subsys_array)
239 return 0;
240
241 for (s = 0; s < json_object_array_length(subsys_array); s++) {
242 struct json_object *subsys_obj =
243 json_object_array_get_idx(subsys_array, s);
244
245 if (!subsys_obj)
246 continue;
247 ret = convert_subsys(emitter, hostnqn, hostid, hostsymname,
248 host_dhchap_key, subsys_obj);
249 if (ret)
250 return ret;
251 }
252
253 return 0;
254}
255
256int nvme_config_convert_json(struct libnvmf_config_emitter *emitter,
257 const char *json_file)
258{
259 struct json_object *json_root, *host_array, *host_obj;
260 int h, ret;
261
262 json_root = json_object_from_file(json_file);
263 if (!json_root) {
264 nvme_show_error("failed to parse %s: %s", json_file,nvme_show_message(1, "failed to parse %s: %s", json_file, json_util_get_last_err
())
265 json_util_get_last_err())nvme_show_message(1, "failed to parse %s: %s", json_file, json_util_get_last_err
())
;
266 return -EPROTO71;
267 }
268
269 if (json_object_is_type(json_root, json_type_object)) {
270 /* Current format: { "hosts": [ ... ] } */
271 host_array = json_object_object_get(json_root, "hosts");
272 if (!host_array ||
273 !json_object_is_type(host_array, json_type_array)) {
274 nvme_show_error("%s: expected a 'hosts' array",nvme_show_message(1, "%s: expected a 'hosts' array", json_file
)
275 json_file)nvme_show_message(1, "%s: expected a 'hosts' array", json_file
)
;
276 json_object_put(json_root);
277 return -EPROTO71;
278 }
279 } else if (json_object_is_type(json_root, json_type_array)) {
280 /* Legacy pre-3.0 format: a bare top-level array of hosts. */
281 host_array = json_root;
282 } else {
283 nvme_show_error("%s: expected a JSON object or array",nvme_show_message(1, "%s: expected a JSON object or array", json_file
)
284 json_file)nvme_show_message(1, "%s: expected a JSON object or array", json_file
)
;
285 json_object_put(json_root);
286 return -EPROTO71;
287 }
288
289 for (h = 0; h < json_object_array_length(host_array); h++) {
290 host_obj = json_object_array_get_idx(host_array, h);
291 if (!host_obj)
292 continue;
293 ret = convert_host(emitter, host_obj);
294 if (ret) {
295 json_object_put(json_root);
296 return ret;
297 }
298 }
299
300 json_object_put(json_root);
301
302 return 0;
303}
304
305#else /* CONFIG_JSONC */
306
307int nvme_config_convert_json(struct libnvmf_config_emitter *emitter,
308 const char *json_file)
309{
310 nvme_show_error(nvme_show_message(1, "built without json-c; config.json conversion unavailable"
)
311 "built without json-c; config.json conversion unavailable")nvme_show_message(1, "built without json-c; config.json conversion unavailable"
)
;
312 return -ENOTSUP95;
313}
314
315#endif /* CONFIG_JSONC */
316
317int nvme_config_convert_discovery_args(struct libnvmf_config_emitter *emitter,
318 const struct nvmf_args *fa, enum libnvmf_tristate persistent,
319 enum libnvmf_tristate epcsd)
320{
321 struct libnvmf_params *params;
322 int ret;
323
324 params = libnvmf_params_new();
325 if (!params)
326 return -ENOMEM12;
327
328 nvmf_args_to_params(params, fa);
329 if (persistent != LIBNVMF_TRISTATE_UNSET)
330 libnvmf_params_set(params, "persistent",
331 persistent == LIBNVMF_TRISTATE_TRUE ? "true" : "false");
332 if (epcsd != LIBNVMF_TRISTATE_UNSET)
333 libnvmf_params_set(params, "epcsd",
334 epcsd == LIBNVMF_TRISTATE_TRUE ? "true" : "false");
335
336 ret = libnvmf_config_emit_add(emitter, true1, fa->transport, fa->traddr,
337 fa->trsvcid, fa->subsysnqn, fa->host_traddr,
338 fa->host_iface, fa->hostnqn, fa->hostid, params, NULL((void*)0));
339
340 libnvmf_params_free(params);
341
342 /*
343 * A rejected entry affects only that entry. Log the error and
344 * continue converting. Stop only if memory allocation fails.
345 */
346 if (ret == -ENOMEM12)
347 return ret;
348 if (ret)
349 nvme_show_error(nvme_show_message(1, "discovery.conf: skipping a line that could not be added: %s"
, libnvme_strerror(-ret))
350 "discovery.conf: skipping a line that could not be added: %s",nvme_show_message(1, "discovery.conf: skipping a line that could not be added: %s"
, libnvme_strerror(-ret))
351 libnvme_strerror(-ret))nvme_show_message(1, "discovery.conf: skipping a line that could not be added: %s"
, libnvme_strerror(-ret))
;
352
353 return 0;
354}
355
356int nvme_config_convert_discovery(struct libnvmf_config_emitter *emitter,
357 const char *disc_file)
358{
359 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *f = NULL((void*)0);
360 static char line[4096];
361 int ret;
362
363 f = fopen(disc_file, "r");
1
Stream opened here
2
Assuming that 'fopen' is successful
364 if (!f
2.1
'f' is non-null
) {
3
Taking false branch
365 nvme_show_error("failed to open %s: %s", disc_file,nvme_show_message(1, "failed to open %s: %s", disc_file, strerror
((*__errno_location ())))
366 strerror(errno))nvme_show_message(1, "failed to open %s: %s", disc_file, strerror
((*__errno_location ())))
;
367 return -errno(*__errno_location ());
368 }
369
370 while (fgets(line, sizeof(line), f)) {
4
Loop condition is false. Execution jumps to the end of the function
371 ret = nvmf_convert_discovery_line(emitter, line);
372 if (ret)
373 return ret;
374 }
375
376 return 0;
5
Opened stream never closed. Potential resource leak
377}
378
379/*
380 * Best effort. The configuration has already been installed. @path is
381 * left untouched so a rollback to a pre-INI version still finds it; the
382 * symlink marks it as already converted.
383 */
384static void mark_converted(const char *path)
385{
386 __cleanup_free__attribute__((cleanup(shr_freep))) char *dst = NULL((void*)0);
387
388 if (asprintf(&dst, "%s.converted", path) < 0)
389 return;
390
391 if (symlink(path, dst))
392 nvme_show_error(nvme_show_message(1, "converted %s but failed to mark it as converted (%s): %s"
, path, dst, strerror((*__errno_location ())))
393 "converted %s but failed to mark it as converted (%s): %s",nvme_show_message(1, "converted %s but failed to mark it as converted (%s): %s"
, path, dst, strerror((*__errno_location ())))
394 path, dst, strerror(errno))nvme_show_message(1, "converted %s but failed to mark it as converted (%s): %s"
, path, dst, strerror((*__errno_location ())))
;
395}
396
397/*
398 * True if the @path.converted symlink exists and resolves. A dangling
399 * symlink (its target since removed) makes this return false, but that
400 * alone does not mean @path needs converting -- callers must also check
401 * whether @path itself exists.
402 */
403static bool_Bool already_converted(const char *path)
404{
405 __cleanup_free__attribute__((cleanup(shr_freep))) char *converted = NULL((void*)0);
406
407 if (asprintf(&converted, "%s.converted", path) < 0)
408 return false0;
409
410 return !access(converted, F_OK0);
411}
412
413static int install_converted(struct libnvmf_config_emitter *emitter,
414 const char *output_file, const char *json_path,
415 const char *disc_path, bool_Bool converted_json,
416 bool_Bool converted_disc, bool_Bool force)
417{
418 int ret;
419
420 ret = libnvmf_config_emit_install(emitter, output_file, force);
421 if (ret == -EEXIST17) {
422 nvme_show_error("%s already exists; refusing to overwrite",nvme_show_message(1, "%s already exists; refusing to overwrite"
, output_file)
423 output_file)nvme_show_message(1, "%s already exists; refusing to overwrite"
, output_file)
;
424 return ret;
425 }
426 if (ret) {
427 nvme_show_error("failed to write %s: %s", output_file,nvme_show_message(1, "failed to write %s: %s", output_file, libnvme_strerror
(-ret))
428 libnvme_strerror(-ret))nvme_show_message(1, "failed to write %s: %s", output_file, libnvme_strerror
(-ret))
;
429 return ret;
430 }
431
432 if (converted_json)
433 mark_converted(json_path);
434 if (converted_disc)
435 mark_converted(disc_path);
436
437 return 0;
438}
439
440int nvme_config_convert_auto(struct libnvme_global_ctx *ctx,
441 const char *config_file, char **ini_path)
442{
443 struct libnvmf_config_emitter *emitter;
444 const char *json_path = config_file;
445 const char *ext;
446 bool_Bool is_default;
447 bool_Bool json_exists, json_done;
448 bool_Bool disc_exists, disc_done;
449 bool_Bool have_json, have_disc;
450 bool_Bool converted_json = false0, converted_disc = false0;
451 int ret;
452
453 *ini_path = NULL((void*)0);
454
455 is_default = !strcmp(config_file, PATH_NVMF_INI"/usr/local/etc" "/nvme/nvme-fabrics.conf") ||
456 !strcmp(config_file, PATH_NVMF_CONFIG"/usr/local/etc" "/nvme/config.json");
457 if (is_default) {
458 json_path = PATH_NVMF_CONFIG"/usr/local/etc" "/nvme/config.json";
459 *ini_path = strdup(PATH_NVMF_INI"/usr/local/etc" "/nvme/nvme-fabrics.conf");
460 } else {
461 ext = strrchr(config_file, '.')_Generic (0 ? (config_file) : (void *) 1, const void *: (const
char *) (strrchr (config_file, '.')), default: strrchr (config_file
, '.'))
;
462 if (!ext || strcmp(ext, ".json")) {
463 *ini_path = strdup(config_file);
464 return *ini_path ? 0 : -ENOMEM12;
465 }
466
467 if (asprintf(ini_path, "%.*s.conf",
468 (int)(ext - config_file), config_file) < 0)
469 return -ENOMEM12;
470 }
471 if (!*ini_path)
472 return -ENOMEM12;
473
474 if (!access(*ini_path, F_OK0))
475 return 0;
476
477 json_exists = !access(json_path, F_OK0);
478 json_done = already_converted(json_path);
479 have_json = json_exists && !json_done;
480
481 disc_exists = is_default && !access(PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf", F_OK0);
482 disc_done = is_default && already_converted(PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf");
483 have_disc = disc_exists && !disc_done;
484
485 if (!have_json && !have_disc) {
486 /* Default path: nothing to convert is fine, proceed empty.
487 * Custom path: never existed and never converted is a
488 * real error, not silent-empty.
489 */
490 if (!is_default && !json_exists && !json_done) {
491 nvme_show_error("%s: no such file", json_path)nvme_show_message(1, "%s: no such file", json_path);
492 return -ENOENT2;
493 }
494 return 0;
495 }
496
497 emitter = libnvmf_config_emit_new(ctx);
498 if (!emitter)
499 return -ENOMEM12;
500
501 if (have_json) {
502 ret = nvme_config_convert_json(emitter, json_path);
503 if (ret)
504 goto out;
505 converted_json = true1;
506 }
507
508 if (have_disc) {
509 ret = nvme_config_convert_discovery(emitter, PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf");
510 if (ret)
511 goto out;
512 converted_disc = true1;
513 }
514
515 ret = install_converted(emitter, *ini_path, json_path, PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf",
516 converted_json, converted_disc, false0);
517 if (ret)
518 goto out;
519
520 nvme_show_error(nvme_show_message(1, "no %s found; converted legacy %s%s%s to it -- the original is preserved for rollback, marked converted by a *.converted symlink; use %s from now on"
, *ini_path, converted_json ? json_path : "", (converted_json
&& converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", *ini_path)
521 "no %s found; converted legacy %s%s%s to it -- the original is preserved for rollback, marked converted by a *.converted symlink; use %s from now on",nvme_show_message(1, "no %s found; converted legacy %s%s%s to it -- the original is preserved for rollback, marked converted by a *.converted symlink; use %s from now on"
, *ini_path, converted_json ? json_path : "", (converted_json
&& converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", *ini_path)
522 *ini_path, converted_json ? json_path : "",nvme_show_message(1, "no %s found; converted legacy %s%s%s to it -- the original is preserved for rollback, marked converted by a *.converted symlink; use %s from now on"
, *ini_path, converted_json ? json_path : "", (converted_json
&& converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", *ini_path)
523 (converted_json && converted_disc) ? " and " : "",nvme_show_message(1, "no %s found; converted legacy %s%s%s to it -- the original is preserved for rollback, marked converted by a *.converted symlink; use %s from now on"
, *ini_path, converted_json ? json_path : "", (converted_json
&& converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", *ini_path)
524 converted_disc ? PATH_NVMF_DISC : "", *ini_path)nvme_show_message(1, "no %s found; converted legacy %s%s%s to it -- the original is preserved for rollback, marked converted by a *.converted symlink; use %s from now on"
, *ini_path, converted_json ? json_path : "", (converted_json
&& converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", *ini_path)
;
525
526out:
527 libnvmf_config_emit_free(emitter);
528
529 return ret;
530}
531
532int nvme_config_convert(const char *desc, int argc, char **argv)
533{
534 char *config_file = NULL((void*)0);
535 char *output_file = NULL((void*)0);
536 const char *target;
537 const char *json_path;
538 bool_Bool force = false0;
539 bool_Bool converted_json = false0, converted_disc = false0;
540 bool_Bool json_already_done = false0, disc_already_done = false0;
541 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
542 struct libnvmf_config_emitter *emitter = NULL((void*)0);
543 int ret;
544
545 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
546 OPT_STRING("config", 'J', "FILE", &config_file,{"config", 'J', "FILE", CFG_STRING, &config_file, 1, "convert this JSON file (default: config.json)"
, 0, }
547 "convert this JSON file (default: config.json)"){"config", 'J', "FILE", CFG_STRING, &config_file, 1, "convert this JSON file (default: config.json)"
, 0, }
,
548 OPT_STRING("output", 'o', "FILE", &output_file,{"output", 'o', "FILE", CFG_STRING, &output_file, 1, "write result here (default: nvme-fabrics.conf)"
, 0, }
549 "write result here (default: nvme-fabrics.conf)"){"output", 'o', "FILE", CFG_STRING, &output_file, 1, "write result here (default: nvme-fabrics.conf)"
, 0, }
,
550 OPT_FLAG("force", 0, &force,{"force", 0, ((void*)0), CFG_FLAG, &force, 0, "overwrite an existing target"
, 0, }
551 "overwrite an existing target"){"force", 0, ((void*)0), CFG_FLAG, &force, 0, "overwrite an existing target"
, 0, }
,
552 OPT_END(){ ((void*)0) }
553 };
554
555 ret = parse_args(argc, argv, desc, opts);
556 if (ret)
557 return ret;
558
559 ret = nvme_create_global_ctx(&ctx);
560 if (ret)
561 return ret;
562
563 emitter = libnvmf_config_emit_new(ctx);
564 if (!emitter)
565 return -ENOMEM12;
566
567 json_path = config_file ? config_file : PATH_NVMF_CONFIG"/usr/local/etc" "/nvme/config.json";
568 if (already_converted(json_path)) {
569 json_already_done = true1;
570 } else if (!access(json_path, F_OK0)) {
571 ret = nvme_config_convert_json(emitter, json_path);
572 if (ret)
573 goto out;
574 converted_json = true1;
575 } else if (config_file) {
576 /*
577 * An explicit --config to a file that neither exists nor was
578 * ever converted: let the JSON parser produce its own
579 * "failed to parse" error instead of silently no-op'ing,
580 * since this was an explicit ask.
581 */
582 ret = nvme_config_convert_json(emitter, json_path);
583 if (ret)
584 goto out;
585 converted_json = true1;
586 }
587
588 if (already_converted(PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf")) {
589 disc_already_done = true1;
590 } else if (!access(PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf", F_OK0)) {
591 ret = nvme_config_convert_discovery(emitter, PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf");
592 if (ret)
593 goto out;
594 converted_disc = true1;
595 }
596
597 if (!converted_json && !converted_disc) {
598 if (json_already_done || disc_already_done) {
599 nvme_show_result("already converted; nothing to do")nvme_show_message(0, "already converted; nothing to do");
600 ret = 0;
601 goto out;
602 }
603 nvme_show_error("nothing to convert: neither %s nor %s exists",nvme_show_message(1, "nothing to convert: neither %s nor %s exists"
, json_path, "/usr/local/etc" "/nvme/discovery.conf")
604 json_path, PATH_NVMF_DISC)nvme_show_message(1, "nothing to convert: neither %s nor %s exists"
, json_path, "/usr/local/etc" "/nvme/discovery.conf")
;
605 ret = -ENOENT2;
606 goto out;
607 }
608
609 target = output_file ? output_file : PATH_NVMF_INI"/usr/local/etc" "/nvme/nvme-fabrics.conf";
610 ret = install_converted(emitter, target, json_path, PATH_NVMF_DISC"/usr/local/etc" "/nvme/discovery.conf",
611 converted_json, converted_disc, force);
612 if (!ret) {
613 nvme_show_result(nvme_show_message(0, "converted legacy %s%s%s to %s -- the original is preserved for rollback, marked converted by a *.converted symlink"
, converted_json ? json_path : "", (converted_json &&
converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", target)
614 "converted legacy %s%s%s to %s -- the original is preserved for rollback, marked converted by a *.converted symlink",nvme_show_message(0, "converted legacy %s%s%s to %s -- the original is preserved for rollback, marked converted by a *.converted symlink"
, converted_json ? json_path : "", (converted_json &&
converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", target)
615 converted_json ? json_path : "",nvme_show_message(0, "converted legacy %s%s%s to %s -- the original is preserved for rollback, marked converted by a *.converted symlink"
, converted_json ? json_path : "", (converted_json &&
converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", target)
616 (converted_json && converted_disc) ? " and " : "",nvme_show_message(0, "converted legacy %s%s%s to %s -- the original is preserved for rollback, marked converted by a *.converted symlink"
, converted_json ? json_path : "", (converted_json &&
converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", target)
617 converted_disc ? PATH_NVMF_DISC : "", target)nvme_show_message(0, "converted legacy %s%s%s to %s -- the original is preserved for rollback, marked converted by a *.converted symlink"
, converted_json ? json_path : "", (converted_json &&
converted_disc) ? " and " : "", converted_disc ? "/usr/local/etc"
"/nvme/discovery.conf" : "", target)
;
618 }
619
620out:
621 libnvmf_config_emit_free(emitter);
622
623 return ret;
624}