| File: | .build-ci/../libnvme/src/nvme/util-fabrics.c |
| Warning: | line 62, column 4 Opened stream never closed. Potential resource leak |
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) 2026, Dell Technologies Inc. or its subsidiaries. | |||
| 5 | * | |||
| 6 | * Authors: Martin Belanger <Martin.Belanger@dell.com> | |||
| 7 | */ | |||
| 8 | ||||
| 9 | #include <unistd.h> | |||
| 10 | ||||
| 11 | #include <ccan/endian/endian.h> | |||
| 12 | #include <ccan/minmax/minmax.h> | |||
| 13 | ||||
| 14 | #include <libnvme.h> | |||
| 15 | ||||
| 16 | #include "cleanup-linux.h" | |||
| 17 | #include "private-fabrics.h" | |||
| 18 | #include "util.h" | |||
| 19 | ||||
| 20 | #include "compiler-attributes.h" | |||
| 21 | ||||
| 22 | __libnvme_public__attribute__((visibility("default"))) struct nvmf_ext_attr *libnvmf_exat_ptr_next( | |||
| 23 | struct nvmf_ext_attr *p) | |||
| 24 | { | |||
| 25 | __u16 size = libnvmf_exat_size(le16_to_cpu(p->exatlen)); | |||
| 26 | ||||
| 27 | return (struct nvmf_ext_attr *)((uintptr_t)p + (ptrdiff_t)size); | |||
| 28 | } | |||
| 29 | ||||
| 30 | const struct ifaddrs *libnvmf_getifaddrs(struct libnvme_global_ctx *ctx) | |||
| 31 | { | |||
| 32 | if (!ctx->ifaddrs_cache) { | |||
| 33 | struct ifaddrs *p; | |||
| 34 | ||||
| 35 | if (!getifaddrs(&p)) | |||
| 36 | ctx->ifaddrs_cache = p; | |||
| 37 | } | |||
| 38 | ||||
| 39 | return ctx->ifaddrs_cache; | |||
| 40 | } | |||
| 41 | ||||
| 42 | /** | |||
| 43 | * read_file - read contents of file into @buffer. | |||
| 44 | * @fname: File name | |||
| 45 | * @buffer: Where to save file's contents | |||
| 46 | * @bufsz: Size of @buffer. On success, @bufsz gets decremented by the | |||
| 47 | * number of characters that were writtent to @buffer. | |||
| 48 | * | |||
| 49 | * Return: The number of characters read. If the file cannot be opened or | |||
| 50 | * nothing is read from the file, then this function returns 0. | |||
| 51 | */ | |||
| 52 | static size_t read_file(const char * fname, char *buffer, size_t *bufsz) | |||
| 53 | { | |||
| 54 | char *p; | |||
| 55 | __cleanup_file__attribute__((cleanup(cleanup_file))) FILE *file = NULL((void*)0); | |||
| 56 | size_t len; | |||
| 57 | ||||
| 58 | file = fopen(fname, "re"); | |||
| 59 | if (!file
| |||
| 60 | return 0; | |||
| 61 | ||||
| 62 | p = fgets(buffer, *bufsz, file); | |||
| ||||
| 63 | ||||
| 64 | if (!p) | |||
| 65 | return 0; | |||
| 66 | ||||
| 67 | /* Strip unwanted trailing chars */ | |||
| 68 | len = strcspn(buffer, " \t\n\r"); | |||
| 69 | *bufsz -= len; | |||
| 70 | ||||
| 71 | return len; | |||
| 72 | } | |||
| 73 | ||||
| 74 | static size_t copy_value(char *buf, size_t buflen, const char *value) | |||
| 75 | { | |||
| 76 | size_t val_len; | |||
| 77 | ||||
| 78 | memset(buf, 0, buflen); | |||
| 79 | ||||
| 80 | /* Remove leading " */ | |||
| 81 | if (value[0] == '"') | |||
| 82 | value++; | |||
| 83 | ||||
| 84 | /* Remove trailing " */ | |||
| 85 | val_len = strcspn(value, "\""); | |||
| 86 | ||||
| 87 | memcpy(buf, value, min(val_len, buflen-1)({ typeof(val_len) _a = (val_len); typeof(buflen-1) _b = (buflen -1); do { } while (0); _a < _b ? _a : _b; })); | |||
| 88 | ||||
| 89 | return val_len; | |||
| 90 | } | |||
| 91 | ||||
| 92 | size_t libnvmf_get_entity_name(char *buffer, size_t bufsz) | |||
| 93 | { | |||
| 94 | size_t len = !gethostname(buffer, bufsz) ? strlen(buffer) : 0; | |||
| 95 | ||||
| 96 | /* Fill the rest of buffer with zeros */ | |||
| 97 | memset(&buffer[len], '\0', bufsz-len); | |||
| 98 | ||||
| 99 | return len; | |||
| 100 | } | |||
| 101 | ||||
| 102 | size_t libnvmf_get_entity_version(char *buffer, size_t bufsz) | |||
| 103 | { | |||
| 104 | __cleanup_file__attribute__((cleanup(cleanup_file))) FILE *file = NULL((void*)0); | |||
| 105 | size_t num_bytes = 0; | |||
| 106 | ||||
| 107 | /* /proc/sys/kernel/ostype typically contains the string "Linux" */ | |||
| 108 | num_bytes += read_file("/proc/sys/kernel/ostype", | |||
| ||||
| 109 | &buffer[num_bytes], &bufsz); | |||
| 110 | ||||
| 111 | /* /proc/sys/kernel/osrelease contains the Linux | |||
| 112 | * version (e.g. 5.8.0-63-generic) | |||
| 113 | */ | |||
| 114 | buffer[num_bytes++] = ' '; /* Append a space */ | |||
| 115 | num_bytes += read_file("/proc/sys/kernel/osrelease", | |||
| 116 | &buffer[num_bytes], &bufsz); | |||
| 117 | ||||
| 118 | /* /etc/os-release contains Key-Value pairs. We only care about the key | |||
| 119 | * PRETTY_NAME, which contains the Distro's version. For example: | |||
| 120 | * "SUSE Linux Enterprise Server 15 SP4", "Ubuntu 20.04.3 LTS", or | |||
| 121 | * "Fedora Linux 35 (Server Edition)" | |||
| 122 | */ | |||
| 123 | file = fopen("/etc/os-release", "re"); | |||
| 124 | if (file) { | |||
| 125 | char name[64] = {0}; | |||
| 126 | size_t name_len = 0; | |||
| 127 | char ver_id[64] = {0}; | |||
| 128 | size_t ver_id_len = 0; | |||
| 129 | char line[LINE_MAX2048]; | |||
| 130 | char *p; | |||
| 131 | char *s; | |||
| 132 | ||||
| 133 | /* Read key-value pairs one line at a time */ | |||
| 134 | while ((!name_len || !ver_id_len) && | |||
| 135 | (p = fgets(line, sizeof(line), file)) != NULL((void*)0)) { | |||
| 136 | /* Clean up string by removing leading/trailing blanks | |||
| 137 | * and new line characters. Also eliminate trailing | |||
| 138 | * comments, if any. | |||
| 139 | */ | |||
| 140 | p = kv_strip(p); | |||
| 141 | ||||
| 142 | /* Empty string? */ | |||
| 143 | if (*p == '\0') | |||
| 144 | continue; | |||
| 145 | ||||
| 146 | s = kv_keymatch(p, "NAME"); | |||
| 147 | if (s) | |||
| 148 | name_len = copy_value(name, sizeof(name), s); | |||
| 149 | ||||
| 150 | s = kv_keymatch(p, "VERSION_ID"); | |||
| 151 | if (s) | |||
| 152 | ver_id_len = copy_value(ver_id, sizeof(ver_id), s); | |||
| 153 | } | |||
| 154 | ||||
| 155 | if (name_len) { | |||
| 156 | /* Append a space */ | |||
| 157 | buffer[num_bytes++] = ' '; | |||
| 158 | name_len = min(name_len, bufsz)({ typeof(name_len) _a = (name_len); typeof(bufsz) _b = (bufsz ); do { } while (0); _a < _b ? _a : _b; }); | |||
| 159 | memcpy(&buffer[num_bytes], name, name_len); | |||
| 160 | bufsz -= name_len; | |||
| 161 | num_bytes += name_len; | |||
| 162 | } | |||
| 163 | ||||
| 164 | if (ver_id_len) { | |||
| 165 | /* Append a space */ | |||
| 166 | buffer[num_bytes++] = ' '; | |||
| 167 | ver_id_len = min(ver_id_len, bufsz)({ typeof(ver_id_len) _a = (ver_id_len); typeof(bufsz) _b = ( bufsz); do { } while (0); _a < _b ? _a : _b; }); | |||
| 168 | memcpy(&buffer[num_bytes], ver_id, ver_id_len); | |||
| 169 | bufsz -= ver_id_len; | |||
| 170 | num_bytes += ver_id_len; | |||
| 171 | } | |||
| 172 | } | |||
| 173 | ||||
| 174 | /* Fill the rest of buffer with zeros */ | |||
| 175 | memset(&buffer[num_bytes], '\0', bufsz); | |||
| 176 | ||||
| 177 | return num_bytes; | |||
| 178 | } |