diff options
Diffstat (limited to 'libopeniscsiusr/node.c')
-rw-r--r-- | libopeniscsiusr/node.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/libopeniscsiusr/node.c b/libopeniscsiusr/node.c new file mode 100644 index 0000000..e82bb0d --- /dev/null +++ b/libopeniscsiusr/node.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Gris Ge <fge@redhat.com> + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +/* ^ For strerror_r() */ +#endif + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#include "libopeniscsiusr/libopeniscsiusr.h" +#include "misc.h" +#include "node.h" + +/* ptr is both input and output pointer. + * count is both input and output pointer. + * When success, both count and ptr will be updated. + * If fail, return LIBISCSI_ERR_NOMEM and no touch to old memory. + */ +static int _grow_node_array(struct iscsi_context *ctx, + struct iscsi_node ***nodes, uint32_t *count) +{ + int rc = LIBISCSI_OK; + struct iscsi_node **tmp = NULL; + uint32_t i = 0; + + _debug(ctx, "Growing node array from size %" PRIu32 " to %" PRIu32, + *count, *count * 2); + + tmp = realloc(*nodes, *count * 2 * sizeof(struct iscsi_node *)); + _alloc_null_check(ctx, tmp, rc, out); + for (i = *count; i < *count * 2; ++i) + tmp[i] = NULL; + + *count *= 2; + *nodes = tmp; + +out: + return rc; +} + +static int nodes_append(struct iscsi_context *ctx, struct iscsi_node ***nodes, + uint32_t *real_node_count, uint32_t *array_size, + struct iscsi_node *node) +{ + int rc = LIBISCSI_OK; + if (*real_node_count >= *array_size) + _good(_grow_node_array(ctx, nodes, array_size), rc, out); + + (*nodes)[(*real_node_count)++] = node; + +out: + return rc; +} + +int iscsi_nodes_get(struct iscsi_context *ctx, struct iscsi_node ***nodes, + uint32_t *node_count) +{ + int rc = LIBISCSI_OK; + struct dirent **namelist = NULL; + int n = 0; + int i = 0; + int j = 0; + int k = 0; + struct iscsi_node *node = NULL; + uint32_t real_node_count = 0; + const char *target_name = NULL; + const char *portal = NULL; + const char *iface_name = NULL; + struct dirent **namelist_portals = NULL; + int p = 0; + struct dirent **namelist_ifaces = NULL; + int f = 0; + char path[PATH_MAX]; + struct stat path_stat; + char strerr_buff[_STRERR_BUFF_LEN]; + + assert(ctx != NULL); + assert(nodes != NULL); + assert(node_count != NULL); + + *nodes = NULL; + *node_count = 0; + + _good(_idbm_lock(ctx), rc, out); + + _good(_scandir(ctx, NODE_CONFIG_DIR, &namelist, &n), rc, out); + _debug(ctx, "Got %d target from %s nodes folder", n, NODE_CONFIG_DIR); + *node_count = n & UINT32_MAX; + *nodes = (struct iscsi_node **) calloc(*node_count, + sizeof(struct iscsi_node *)); + _alloc_null_check(ctx, *nodes, rc, out); + + // New style of nodes folder: + // <target_name>/<address>,<port>,<tpgt>/<iface_name> + // Old style of nodes folder: + // <target_name>/<address>,<port> + + for (i = 0; i < n; ++i) { + target_name = namelist[i]->d_name; + snprintf(path, sizeof(path)/sizeof(char), + "%s/%s", NODE_CONFIG_DIR, target_name); + _good(_scandir(ctx, path, &namelist_portals, &p), rc, out); + _debug(ctx, "Got %d portals from %s folder", p, path); + for (j = 0; j < p; ++j) { + portal = namelist_portals[j]->d_name; + snprintf(path, sizeof(path)/sizeof(char), + "%s/%s/%s", NODE_CONFIG_DIR, target_name, + portal); + if (stat(path, &path_stat) != 0) { + _warn(ctx, "Cannot stat path '%s': %d, %s", + path, errno, + _strerror(errno, strerr_buff)); + continue; + } + if (S_ISREG(path_stat.st_mode)) { + // Old style of node + _good(_idbm_node_get(ctx, target_name, portal, + NULL, &node), + rc, out); + _good(nodes_append(ctx, nodes, + &real_node_count, + node_count, node), + rc, out); + continue; + } + if (! S_ISDIR(path_stat.st_mode)) { + _warn(ctx, "Invalid iSCSI node configuration " + "file %s, it should be a file or " + "directory.", path); + rc = LIBISCSI_ERR_IDBM; + goto out; + } + _good(_scandir(ctx, path, &namelist_ifaces, &f), rc, + out); + _debug(ctx, "Got %d ifaces from %s folder", f, path); + for (k = 0; k < f; ++k) { + iface_name = namelist_ifaces[k]->d_name; + _good(_idbm_node_get(ctx, target_name, portal, + iface_name, &node), + rc, out); + _good(nodes_append(ctx, nodes, + &real_node_count, + node_count, node), + rc, out); + } + _scandir_free(namelist_ifaces, f); + namelist_ifaces = NULL; + f = 0; + } + _scandir_free(namelist_portals, p); + namelist_portals = NULL; + p = 0; + } + + *node_count = real_node_count; + +out: + _scandir_free(namelist, n); + _scandir_free(namelist_portals, p); + _scandir_free(namelist_ifaces, f); + _idbm_unlock(ctx); + if (rc != LIBISCSI_OK) { + iscsi_nodes_free(*nodes, *node_count); + *nodes = NULL; + *node_count = 0; + } + return rc; +} + +void iscsi_nodes_free(struct iscsi_node **nodes, uint32_t node_count) +{ + uint32_t i = 0; + + if ((nodes == NULL) || (node_count == 0)) + return; + + for (i = 0; i < node_count; ++i) + iscsi_node_free(nodes[i]); + free (nodes); +} + +void iscsi_node_free(struct iscsi_node *node) +{ + free(node); +} + +const char *iscsi_node_dump_config(struct iscsi_node *node, bool show_secret) +{ + FILE *f = NULL; + char *buff = NULL; + + assert(node != NULL); + + buff = calloc(1, IDBM_DUMP_SIZE); + if (buff == NULL) + return NULL; + + f = fmemopen(buff, IDBM_DUMP_SIZE - 1, "w"); + if (f == NULL) { + free(buff); + return NULL; + } + + _idbm_node_print(node, f, show_secret); + + fclose(f); + + return buff; +} + +void iscsi_node_print_config(struct iscsi_node *node, bool show_secret) +{ + assert(node != NULL); + _idbm_node_print(node, stdout, show_secret); +} + +// TODO(Gris Ge): Convert below duplicated codes to macros. +bool iscsi_node_conn_is_ipv6(struct iscsi_node *node) +{ + assert(node != NULL); + return node->conn.is_ipv6; +} + +const char *iscsi_node_conn_address_get(struct iscsi_node *node) +{ + assert(node != NULL); + return node->conn.address; +} + +uint32_t iscsi_node_conn_port_get(struct iscsi_node *node) +{ + assert(node != NULL); + return node->conn.port; +} + +int32_t iscsi_node_tpgt_get(struct iscsi_node *node) +{ + assert(node != NULL); + return node->tpgt; +} + +const char *iscsi_node_target_name_get(struct iscsi_node *node) +{ + assert(node != NULL); + return node->target_name; +} + +const char *iscsi_node_iface_name_get(struct iscsi_node *node) +{ + assert(node != NULL); + return node->iface.name; +} + +const char *iscsi_node_portal_get(struct iscsi_node *node) +{ + assert(node != NULL); + return node->portal; +} |