Bug Summary

File:.build-ci/../libnvme/src/nvme/tree-linux.c
Warning:line 600, column 11
Potential leak of memory pointed to by 'blkdev'

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 tree-linux.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/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I libnvme/src/libnvme3.so.1.0.0.p -I libnvme/src -I ../libnvme/src -I ccan -I ../ccan -I . -I .. -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=gnu11 -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 -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-10-24-125112-639-1 -x c ../libnvme/src/nvme/tree-linux.c
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of libnvme.
4 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
5 *
6 * Authors: Keith Busch <keith.busch@wdc.com>
7 * Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
8 */
9#include <errno(*__errno_location ()).h>
10#include <fcntl.h>
11#include <libgen.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <time.h>
18
19#include <sys/stat.h>
20#include <sys/types.h>
21
22#include <ccan/endian/endian.h>
23#include <ccan/list/list.h>
24
25#include <shared/compiler-attributes-util.h>
26
27#include <libnvme.h>
28
29#include "cleanup-linux.h"
30#include "cleanup.h"
31#include "private-fabrics.h"
32#include "private-tree.h"
33#include "private.h"
34#include "util.h"
35
36#define PATH_UUID_IBM"/proc/device-tree/ibm,partition-uuid" "/proc/device-tree/ibm,partition-uuid"
37#define PATH_SYSFS_BLOCK"/sys/block" "/sys/block"
38#define PATH_SYSFS_SLOTS"/sys/bus/pci/slots" "/sys/bus/pci/slots"
39#define PATH_SYSFS_NVME_SUBSYSTEM"/sys/class/nvme-subsystem" "/sys/class/nvme-subsystem"
40#define PATH_SYSFS_NVME"/sys/class/nvme" "/sys/class/nvme"
41#define PATH_DMI_ENTRIES"/sys/firmware/dmi/entries" "/sys/firmware/dmi/entries"
42#define PATH_DMI_PROD_UUID"/sys/class/dmi/id/product_uuid" "/sys/class/dmi/id/product_uuid"
43#define PATH_MACHINE_ID"/etc/machine-id" "/etc/machine-id" /* no SYSCONFDIR */
44
45static const char *make_sysfs_dir(struct libnvme_global_ctx *ctx,
46 const char *path)
47{
48 char *str;
49
50 if (!ctx || !ctx->test_sysfs_dir)
51 return path;
52
53 if (asprintf(&str, "%s%s", ctx->test_sysfs_dir, path) < 0)
54 return NULL((void*)0);
55
56 return str;
57}
58
59const char *libnvme_subsys_sysfs_dir(struct libnvme_global_ctx *ctx)
60{
61 static const char *str;
62
63 if (str)
64 return str;
65
66 return str = make_sysfs_dir(ctx, PATH_SYSFS_NVME_SUBSYSTEM"/sys/class/nvme-subsystem");
67}
68
69const char *libnvme_ctrl_sysfs_dir(struct libnvme_global_ctx *ctx)
70{
71 static const char *str;
72
73 if (str)
74 return str;
75
76 return str = make_sysfs_dir(ctx, PATH_SYSFS_NVME"/sys/class/nvme");
77}
78
79const char *libnvme_ns_sysfs_dir(struct libnvme_global_ctx *ctx)
80{
81 static const char *str;
82
83 if (str)
84 return str;
85
86 return str = make_sysfs_dir(ctx, PATH_SYSFS_BLOCK"/sys/block");
87}
88
89const char *libnvme_slots_sysfs_dir(struct libnvme_global_ctx *ctx)
90{
91 static const char *str;
92
93 if (str)
94 return str;
95
96 return str = make_sysfs_dir(ctx, PATH_SYSFS_SLOTS"/sys/bus/pci/slots");
97}
98
99const char *libnvme_uuid_ibm_filename(struct libnvme_global_ctx *ctx)
100{
101 static const char *str;
102
103 if (str)
104 return str;
105
106 return str = make_sysfs_dir(ctx, PATH_UUID_IBM"/proc/device-tree/ibm,partition-uuid");
107}
108
109const char *libnvme_dmi_entries_dir(struct libnvme_global_ctx *ctx)
110{
111 static const char *str;
112
113 if (str)
114 return str;
115
116 return str = make_sysfs_dir(ctx, PATH_DMI_ENTRIES"/sys/firmware/dmi/entries");
117}
118
119const char *libnvme_dmi_product_uuid_filename(struct libnvme_global_ctx *ctx)
120{
121 static const char *str;
122
123 if (str)
124 return str;
125
126 return str = make_sysfs_dir(ctx, PATH_DMI_PROD_UUID"/sys/class/dmi/id/product_uuid");
127}
128
129const char *libnvme_machine_id_filename(struct libnvme_global_ctx *ctx)
130{
131 static const char *str;
132
133 if (str)
134 return str;
135
136 return str = make_sysfs_dir(ctx, PATH_MACHINE_ID"/etc/machine-id");
137}
138
139static int __nvme_set_attr(const char *path, const char *value)
140{
141 __cleanup_fd__attribute__((cleanup(shr_cleanup_fd))) int fd = -1;
142
143 fd = open(path, O_WRONLY01);
144 if (fd < 0) {
145#if 0
146 libnvme_msg(LIBNVME_LOG_DEBUG, "Failed to open %s: %s\n", path,__libnvme_msg(LIBNVME_LOG_DEBUG, "Failed to open %s: %s\n", (
(void*)0), path, strerror((*__errno_location ())))
147 strerror(errno))__libnvme_msg(LIBNVME_LOG_DEBUG, "Failed to open %s: %s\n", (
(void*)0), path, strerror((*__errno_location ())))
;
148#endif
149 return -errno(*__errno_location ());
150 }
151 return write(fd, value, strlen(value));
152}
153
154int libnvme_set_attr(const char *dir, const char *attr, const char *value)
155{
156 __cleanup_free__attribute__((cleanup(shr_freep))) char *path = NULL((void*)0);
157 int ret;
158
159 ret = asprintf(&path, "%s/%s", dir, attr);
160 if (ret < 0)
161 return -ENOMEM12;
162
163 return __nvme_set_attr(path, value);
164}
165
166static char *__nvme_get_attr(const char *path)
167{
168 char value[4096] = { 0 };
169 int ret, fd;
170 int saved_errno;
171
172 fd = open(path, O_RDONLY00);
173 if (fd < 0)
174 return NULL((void*)0);
175
176 ret = read(fd, value, sizeof(value) - 1);
177 saved_errno = errno(*__errno_location ());
178 close(fd);
179 if (ret < 0) {
180 errno(*__errno_location ()) = saved_errno;
181 return NULL((void*)0);
182 }
183 errno(*__errno_location ()) = 0;
184 if (!strlen(value))
185 return NULL((void*)0);
186
187 if (value[strlen(value) - 1] == '\n')
188 value[strlen(value) - 1] = '\0';
189 while (strlen(value) > 0 && value[strlen(value) - 1] == ' ')
190 value[strlen(value) - 1] = '\0';
191
192 return strlen(value) ? strdup(value) : NULL((void*)0);
193}
194
195__shr_public__attribute__((visibility("default"))) char *libnvme_get_attr(const char *dir, const char *attr)
196{
197 __cleanup_free__attribute__((cleanup(shr_freep))) char *path = NULL((void*)0);
198 int ret;
199
200 ret = asprintf(&path, "%s/%s", dir, attr);
201 if (ret < 0)
202 return NULL((void*)0);
203
204 return __nvme_get_attr(path);
205}
206
207__shr_public__attribute__((visibility("default"))) char *libnvme_get_subsys_attr(
208 struct libnvme_subsystem *s, const char *attr)
209{
210 return libnvme_get_attr(libnvme_subsystem_get_sysfs_dir(s), attr);
211}
212
213__shr_public__attribute__((visibility("default"))) char *libnvme_get_ctrl_attr(struct libnvme_ctrl *c, const char *attr)
214{
215 return libnvme_get_attr(libnvme_ctrl_get_sysfs_dir(c), attr);
216}
217
218__shr_public__attribute__((visibility("default"))) char *libnvme_get_ns_attr(struct libnvme_ns *n, const char *attr)
219{
220 return libnvme_get_attr(libnvme_ns_get_sysfs_dir(n), attr);
221}
222
223__shr_public__attribute__((visibility("default"))) char *libnvme_get_path_attr(struct libnvme_path *p, const char *attr)
224{
225 return libnvme_get_attr(libnvme_path_get_sysfs_dir(p), attr);
226}
227
228__shr_public__attribute__((visibility("default"))) const char *libnvme_ctrl_get_state(struct libnvme_ctrl *c)
229{
230 char *state = c->state;
231
232 c->state = libnvme_get_ctrl_attr(c, "state");
233 free(state);
234 return c->state;
235}
236
237static int libnvme_ctrl_lookup_subsystem_name(struct libnvme_global_ctx *ctx,
238 const char *ctrl_name, char **name)
239{
240 const char *subsys_dir = libnvme_subsys_sysfs_dir(ctx);
241 __cleanup_dirents__attribute__((cleanup(cleanup_dirents))) struct dirents subsys = {};
242 int i;
243
244 subsys.num = libnvme_scan_subsystems(ctx, &subsys.ents);
245 if (subsys.num < 0)
246 return subsys.num;
247
248 for (i = 0; i < subsys.num; i++) {
249 struct stat st;
250 __cleanup_free__attribute__((cleanup(shr_freep))) char *path = NULL((void*)0);
251
252 if (asprintf(&path, "%s/%s/%s", subsys_dir,
253 subsys.ents[i]->d_name, ctrl_name) < 0)
254 return -ENOMEM12;
255 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "lookup subsystem %s\n", path)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "lookup subsystem %s\n"
, path)
;
256 if (stat(path, &st) < 0) {
257 continue;
258 }
259
260 *name = strdup(subsys.ents[i]->d_name);
261 if (!*name)
262 return -ENOMEM12;
263
264 return 0;
265 }
266 return -ENOENT2;
267}
268
269int libnvme_reconfigure_ctrl(struct libnvme_global_ctx *ctx,
270 struct libnvme_ctrl *c, const char *path, const char *name)
271{
272 DIR *d;
273
274 /*
275 * It's necesssary to release any resources first because a ctrl
276 * can be reused.
277 */
278 libnvme_ctrl_release_transport_handle(c);
279 FREE_CTRL_ATTR(c->name)do { free(c->name); (c->name) = ((void*)0); } while (0);
280 FREE_CTRL_ATTR(c->sysfs_dir)do { free(c->sysfs_dir); (c->sysfs_dir) = ((void*)0); }
while (0)
;
281 FREE_CTRL_ATTR(c->state)do { free(c->state); (c->state) = ((void*)0); } while (
0)
;
282 libnvme_ctrl_attrs_reset(c->attrs);
283
284 d = opendir(path);
285 if (!d) {
286 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ctrl dir %s, error %d\n"
, path, (*__errno_location ()))
287 "Failed to open ctrl dir %s, error %d\n", path, errno)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ctrl dir %s, error %d\n"
, path, (*__errno_location ()))
;
288 return -ENODEV19;
289 }
290 closedir(d);
291
292 c->hdl = NULL((void*)0);
293 c->name = shr_xstrdup(name);
294 c->sysfs_dir = shr_xstrdup(path);
295 c->state = libnvme_get_ctrl_attr(c, "state");
296 libnvmf_read_sysfs_fabrics_attrs(ctx, c);
297
298 return 0;
299}
300
301__shr_public__attribute__((visibility("default"))) int libnvme_init_ctrl(
302 struct libnvme_host *h, struct libnvme_ctrl *c, int instance)
303{
304 __cleanup_free__attribute__((cleanup(shr_freep))) char *subsys_name = NULL((void*)0), *name = NULL((void*)0), *path = NULL((void*)0);
305 struct libnvme_subsystem *s;
306 int ret;
307
308 ret = asprintf(&name, "nvme%d", instance);
309 if (ret < 0)
310 return -ENOMEM12;
311
312 ret = asprintf(&path, "%s/%s", libnvme_ctrl_sysfs_dir(h->ctx), name);
313 if (ret < 0)
314 return -ENOMEM12;
315
316 ret = libnvme_reconfigure_ctrl(h->ctx, c, path, name);
317 if (ret < 0)
318 return ret;
319
320 c->address = libnvme_get_attr(path, "address");
321 if (!c->address && strcmp(c->transport, "loop"))
322 return -ENVME_CONNECT_INVAL_TR;
323
324 ret = libnvme_ctrl_lookup_subsystem_name(h->ctx, name, &subsys_name);
325 if (ret) {
326 libnvme_msg(h->ctx, LIBNVME_LOG_ERR,__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem name for %s\n"
, c->name)
327 "Failed to lookup subsystem name for %s\n",__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem name for %s\n"
, c->name)
328 c->name)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem name for %s\n"
, c->name)
;
329 return ENVME_CONNECT_LOOKUP_SUBSYS_NAME;
330 }
331
332 ret = libnvme_get_subsystem(h->ctx, h, subsys_name, c->subsysnqn, &s);
333 if (ret) {
334 libnvme_msg(h->ctx, LIBNVME_LOG_ERR,__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem %s\n"
, subsys_name)
335 "Failed to lookup subsystem %s\n",__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem %s\n"
, subsys_name)
336 subsys_name)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem %s\n"
, subsys_name)
;
337 return -ENVME_CONNECT_LOOKUP_SUBSYS;
338 }
339
340 if (s->subsystype && !strcmp(s->subsystype, "discovery"))
341 c->discovery_ctrl = true1;
342
343 c->s = s;
344 list_add_tail(&s->ctrls, &c->entry)list_add_tail_(&s->ctrls, &c->entry, "../libnvme/src/nvme/tree-linux.c"
":" "344")
;
345
346 return ret;
347}
348
349__shr_public__attribute__((visibility("default"))) int libnvme_scan_ctrl(
350 struct libnvme_global_ctx *ctx, const char *name,
351 struct libnvme_ctrl **cp)
352{
353 __cleanup_free__attribute__((cleanup(shr_freep))) char *subsysnqn = NULL((void*)0), *subsysname = NULL((void*)0);
354 __cleanup_free__attribute__((cleanup(shr_freep))) char *hostnqn = NULL((void*)0), *hostid = NULL((void*)0);
355 __cleanup_free__attribute__((cleanup(shr_freep))) char *path = NULL((void*)0);
356 struct libnvme_host *h;
357 struct libnvme_subsystem *s;
358 struct libnvme_ctrl *c;
359 int ret;
360
361 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "scan controller %s\n", name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan controller %s\n"
, name)
;
362 ret = asprintf(&path, "%s/%s", libnvme_ctrl_sysfs_dir(ctx), name);
363 if (ret < 0)
364 return -ENOMEM12;
365
366 hostnqn = libnvme_get_attr(path, "hostnqn");
367 hostid = libnvme_get_attr(path, "hostid");
368 if (!hostnqn)
369 hostnqn = shr_xstrdup(ctx->hostnqn);
370 if (!hostid)
371 hostid = shr_xstrdup(ctx->hostid);
372 ret = libnvme_get_host(ctx, hostnqn, hostid, &h);
373 if (ret)
374 return ret;
375
376 subsysnqn = libnvme_get_attr(path, "subsysnqn");
377 if (!subsysnqn)
378 return -ENXIO6;
379
380 ret = libnvme_ctrl_lookup_subsystem_name(ctx, name, &subsysname);
381 if (ret) {
382 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to lookup subsystem for controller %s\n"
, name)
383 "failed to lookup subsystem for controller %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to lookup subsystem for controller %s\n"
, name)
384 name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to lookup subsystem for controller %s\n"
, name)
;
385 return ret;
386 }
387
388 ret = libnvme_get_subsystem(h->ctx, h, subsysname, subsysnqn, &s);
389 if (ret)
390 return ret;
391
392 ret = libnvme_ctrl_alloc(ctx, s, path, name, &c);
393 if (ret)
394 return ret;
395
396 ret = libnvme_ctrl_scan_paths(ctx, c);
397 if (ret) {
398 libnvme_free_ctrl(c);
399 return ret;
400 }
401
402 ret = libnvme_ctrl_scan_namespaces(ctx, c);
403 if (ret) {
404 libnvme_free_ctrl(c);
405 return ret;
406 }
407
408 *cp = c;
409 return 0;
410}
411
412static int libnvme_strtou32(const char *str, void *res)
413{
414 char *endptr;
415 __u32 v;
416
417 errno(*__errno_location ()) = 0;
418 v = strtol(str, &endptr, 0);
419
420 if (errno(*__errno_location ()) != 0)
421 return -errno(*__errno_location ());
422
423 if (endptr == str) {
424 /* no digits found */
425 return -EINVAL22;
426 }
427
428 *(__u32 *)res = v;
429 return 0;
430}
431
432struct sysfs_attr_table {
433 void *var;
434 int (*parse)(const char *str, void *res);
435 bool_Bool mandatory;
436 const char *name;
437};
438
439#define ARRAY_SIZE(arr)(sizeof(arr) / sizeof((arr)[0])) (sizeof(arr) / sizeof((arr)[0]))
440
441static int parse_attrs(const char *path, struct sysfs_attr_table *tbl, int size)
442{
443 char *str;
444 int ret, i;
445
446 for (i = 0; i < size; i++) {
447 struct sysfs_attr_table *e = &tbl[i];
448
449 str = libnvme_get_attr(path, e->name);
450 if (!str) {
451 if (!e->mandatory)
452 continue;
453 return -ENOENT2;
454 }
455 ret = e->parse(str, e->var);
456 free(str);
457 if (ret)
458 return ret;
459 }
460
461 return 0;
462}
463
464int libnvme_ns_init(const char *path, struct libnvme_ns *ns)
465{
466 int ret;
467
468 struct sysfs_attr_table base[] = {
469 { &ns->nsid, libnvme_strtou32, true1, "nsid" },
470 };
471
472 ret = parse_attrs(path, base, ARRAY_SIZE(base)(sizeof(base) / sizeof((base)[0])));
473 if (ret)
474 return ret;
475
476 ns->attrs = libnvme_ns_attrs_alloc();
477 if (!ns->attrs)
478 return -ENOMEM12;
479
480 return 0;
481}
482
483static void libnvme_ns_set_generic_name(struct libnvme_ns *n, const char *name)
484{
485 char generic_name[PATH_MAX4096];
486 int instance, head_instance;
487 int ret;
488
489 ret = sscanf(name, "nvme%dn%d", &instance, &head_instance);
490 if (ret != 2)
491 return;
492
493 sprintf(generic_name, "ng%dn%d", instance, head_instance);
494 n->generic_name = strdup(generic_name);
495}
496
497int libnvme_ns_open(struct libnvme_global_ctx *ctx, const char *sys_path,
498 const char *name, struct libnvme_ns **ns)
499{
500 int ret;
501 struct libnvme_ns *n;
502 struct libnvme_ns_head *head;
503 struct stat arg;
504 __cleanup_free__attribute__((cleanup(shr_freep))) char *path = NULL((void*)0);
505
506 n = calloc(1, sizeof(*n));
507 if (!n)
508 return -ENOMEM12;
509
510 head = calloc(1, sizeof(*head));
511 if (!head) {
512 free(n);
513 return -ENOMEM12;
514 }
515
516 head->n = n;
517 list_head_init(&head->paths);
518 ret = asprintf(&path, "%s/%s", sys_path, "multipath");
519 if (ret < 0) {
520 ret = -ENOMEM12;
521 goto free_ns_head;
522 }
523
524 /*
525 * The sysfs-dir "multipath" is available only when nvme multipath
526 * is configured and we're running kernel version >= 6.14.
527 */
528 ret = stat(path, &arg);
529 if (ret == 0) {
530 head->sysfs_dir = path;
531 path = NULL((void*)0);
532 } else
533 head->sysfs_dir = NULL((void*)0);
534
535 n->ctx = ctx;
536 n->head = head;
537 n->hdl = NULL((void*)0);
538 n->name = strdup(name);
539
540 libnvme_ns_set_generic_name(n, name);
541
542 ret = libnvme_ns_init(sys_path, n);
543 if (ret)
544 goto free_ns;
545
546 list_node_init(&n->entry);
547
548 libnvme_ns_release_transport_handle(n);
549
550 *ns = n;
551 return 0;
552
553free_ns:
554 free(n->generic_name);
555 free(n->name);
556free_ns_head:
557 free(head);
558 free(n);
559 return ret;
560}
561
562static inline bool_Bool libnvme_ns_is_generic(const char *name)
563{
564 int instance, head_instance;
565
566 if (sscanf(name, "ng%dn%d", &instance, &head_instance) != 2)
567 return false0;
568 return true1;
569}
570
571static char *libnvme_ns_generic_to_blkdev(const char *generic)
572{
573 int instance, head_instance;
574 char blkdev[PATH_MAX4096];
575
576 if (!libnvme_ns_is_generic(generic))
2
Taking true branch
577 return strdup(generic);
3
Memory is allocated
578
579 if (sscanf(generic, "ng%dn%d", &instance, &head_instance) != 2)
580 return NULL((void*)0);
581 sprintf(blkdev, "nvme%dn%d", instance, head_instance);
582
583 return strdup(blkdev);
584}
585
586int __libnvme_scan_namespace(struct libnvme_global_ctx *ctx,
587 const char *sysfs_dir, const char *name, struct libnvme_ns **ns)
588{
589 __cleanup_free__attribute__((cleanup(shr_freep))) char *blkdev = NULL((void*)0);
590 __cleanup_free__attribute__((cleanup(shr_freep))) char *path = NULL((void*)0);
591 struct libnvme_ns *n = NULL((void*)0);
592 int ret;
593
594 blkdev = libnvme_ns_generic_to_blkdev(name);
1
Calling 'libnvme_ns_generic_to_blkdev'
4
Returned allocated memory
595 if (!blkdev)
5
Assuming 'blkdev' is non-null
6
Taking false branch
596 return -ENOMEM12;
597
598 ret = asprintf(&path, "%s/%s", sysfs_dir, blkdev);
599 if (ret < 0)
7
Assuming 'ret' is < 0
8
Taking true branch
600 return -ENOMEM12;
9
Potential leak of memory pointed to by 'blkdev'
601
602 ret = libnvme_ns_open(ctx, path, blkdev, &n);
603 if (ret)
604 return ret;
605
606 n->sysfs_dir = path;
607 path = NULL((void*)0);
608
609 *ns = n;
610 return 0;
611}
612
613int libnvme_get_ctrl_transport(__shr_unused__attribute__((__unused__)) struct libnvme_global_ctx *ctx,
614 const char *path, const char *name,
615 char **transport, char **traddr, char **addr, char **trsvcid,
616 char **host_traddr, char **host_iface)
617{
618 char *a = NULL((void*)0), *e = NULL((void*)0);
619
620 *transport = libnvme_get_attr(path, "transport");
621 if (!*transport)
622 return -ENXIO6;
623
624 /* Parse 'address' string into components */
625 *addr = libnvme_get_attr(path, "address");
626 if (!*addr) {
627 __cleanup_free__attribute__((cleanup(shr_freep))) char *rpath = NULL((void*)0);
628 char *p = NULL((void*)0), *_a = NULL((void*)0);
629
630 /* loop transport might not have an address */
631 if (!strcmp(*transport, "loop"))
632 goto skip_address;
633
634 /* Older kernels don't support pcie transport addresses */
635 if (strcmp(*transport, "pcie") &&
636 strcmp(*transport, "apple-nvme"))
637 return -ENXIO6;
638 /* Figure out the PCI address from the attribute path */
639 rpath = realpath(path, NULL((void*)0));
640 if (!rpath)
641 return -ENOMEM12;
642 a = strtok_r(rpath, "/", &e);
643 while (a && strlen(a)) {
644 if (_a)
645 p = _a;
646 _a = a;
647 if (!strncmp(a, "nvme", 4))
648 break;
649 a = strtok_r(NULL((void*)0), "/", &e);
650 }
651 if (p)
652 *addr = strdup(p);
653 } else if (!strcmp(*transport, "pcie") ||
654 !strcmp(*transport, "apple-nvme")) {
655 /* The 'address' string is the transport address */
656 *traddr = strdup(*addr);
657 if (!*traddr)
658 return -ENOMEM12;
659 } else {
660 __cleanup_free__attribute__((cleanup(shr_freep))) char *address = strdup(*addr);
661 if (!address)
662 return -ENOMEM12;
663
664 a = strtok_r(address, ",", &e);
665 while (a && strlen(a)) {
666 if (!strncmp(a, "traddr=", 7))
667 *traddr = strdup(a + 7);
668 else if (!strncmp(a, "trsvcid=", 8))
669 *trsvcid = strdup(a + 8);
670 else if (!strncmp(a, "host_traddr=", 12))
671 *host_traddr = strdup(a + 12);
672 else if (!strncmp(a, "host_iface=", 11))
673 *host_iface = strdup(a + 11);
674 a = strtok_r(NULL((void*)0), ",", &e);
675 }
676 }
677skip_address:
678 return 0;
679}
680
681int libnvme_init_subsystem(struct libnvme_subsystem *s, const char *name)
682{
683 char *path;
684
685 if (asprintf(&path, "%s/%s",
686 libnvme_subsys_sysfs_dir(s->h->ctx), name) < 0)
687 return -ENOMEM12;
688
689 s->subsystype = libnvme_get_attr(path, "subsystype");
690 if (!s->subsystype) {
691 if (!strcmp(s->subsysnqn, NVME_DISC_SUBSYS_NAME"nqn.2014-08.org.nvmexpress.discovery"))
692 s->subsystype = strdup("discovery");
693 else
694 s->subsystype = strdup("nvm");
695 }
696 s->name = strdup(name);
697 s->sysfs_dir = (char *)path;
698
699 return 0;
700}