| File: | .build-ci/../libnvme/src/nvme/json.c |
| Warning: | line 211, column 10 Potential leak of memory pointed to by 'ptr' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | ||||
| 25 | static 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 | ||||
| 82 | static 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, ¶ms, 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 | ||||
| 129 | static 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 | ||||
| 155 | static 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 | ||||
| 188 | static 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 | ||||
| 191 | static 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) { | |||
| 202 | str = realloc(ptr, len + ret); | |||
| 203 | if (!str) | |||
| 204 | return NULL((void*)0); | |||
| 205 | memcpy(&str[len], buf, ret); | |||
| 206 | len += ret; | |||
| 207 | ptr = str; | |||
| 208 | } | |||
| 209 | ||||
| 210 | if (ret < 0 || !len) | |||
| 211 | return NULL((void*)0); | |||
| ||||
| 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 | ||||
| 228 | int 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
| |||
| ||||
| 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); | |||
| 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 | ||||
| 270 | static 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 | ||||
| 348 | static 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 | ||||
| 375 | int 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 | ||||
| 434 | static 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 | ||||
| 513 | static 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 | ||||
| 559 | static 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 | ||||
| 585 | static 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 | ||||
| 607 | int 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 | } |