Blame libiscsi/libiscsi.c

Packit 55b723
/*
Packit 55b723
 * iSCSI Administration library
Packit 55b723
 *
Packit 55b723
 * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
Packit 55b723
 * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
Packit dfd6cc
 * Copyright (C) 2015      Peter Hatina <phatina@redhat.com>
Packit 55b723
 * maintained by open-iscsi@googlegroups.com
Packit 55b723
 *
Packit 55b723
 * This program is free software; you can redistribute it and/or modify
Packit 55b723
 * it under the terms of the GNU General Public License as published
Packit 55b723
 * by the Free Software Foundation; either version 2 of the License, or
Packit 55b723
 * (at your option) any later version.
Packit 55b723
 *
Packit 55b723
 * This program is distributed in the hope that it will be useful, but
Packit 55b723
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 55b723
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit 55b723
 * General Public License for more details.
Packit 55b723
 *
Packit 55b723
 * See the file COPYING included with this distribution for more details.
Packit 55b723
 */
Packit 55b723
Packit 55b723
#include <stdio.h>
Packit 55b723
#include <stdlib.h>
Packit 55b723
#include <string.h>
Packit 55b723
#include <errno.h>
Packit 55b723
#include <unistd.h>
Packit 55b723
#include <sys/syslog.h>
Packit 55b723
#include "libiscsi.h"
Packit 55b723
#include "idbm.h"
Packit 55b723
#include "discovery.h"
Packit 55b723
#include "log.h"
Packit 55b723
#include "sysfs.h"
Packit 55b723
#include "iscsi_sysfs.h"
Packit 55b723
#include "session_info.h"
Packit 55b723
#include "iscsi_util.h"
Packit 55b723
#include "sysdeps.h"
Packit 55b723
#include "iface.h"
Packit 55b723
#include "iscsi_proto.h"
Packit 55b723
#include "fw_context.h"
Packit 55b723
#include "iscsid_req.h"
Packit 55b723
#include "iscsi_err.h"
Packit 55b723
Packit 55b723
#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; }
Packit 55b723
Packit 55b723
/* UGLY, not thread safe :( */
Packit 55b723
static int sysfs_initialized = 0;
Packit 55b723
Packit 55b723
struct libiscsi_context {
Packit 55b723
	char error_str[256];
Packit 55b723
	/* For get_parameter_helper() */
Packit 55b723
	const char *parameter;
Packit 55b723
	char *value;
Packit 55b723
};
Packit 55b723
Packit 55b723
static void libiscsi_log(int prio, void *priv, const char *fmt, va_list ap)
Packit 55b723
{
Packit 55b723
	struct libiscsi_context *context = priv;
Packit 55b723
Packit 55b723
	if (prio > LOG_ERR) /* We are only interested in errors (or worse) */
Packit 55b723
		return;
Packit 55b723
Packit 55b723
	vsnprintf(context->error_str, sizeof(context->error_str), fmt, ap);
Packit 55b723
}
Packit 55b723
Packit 55b723
struct libiscsi_context *libiscsi_init(void)
Packit 55b723
{
Packit 55b723
	struct libiscsi_context *context;
Packit 55b723
Packit 55b723
	context = calloc(1, sizeof *context);
Packit 55b723
	if (!context)
Packit 55b723
		return NULL;
Packit 55b723
Packit 55b723
	log_init("libiscsi", 1024, libiscsi_log, context);
Packit 55b723
	if (!sysfs_initialized) {
Packit 55b723
		sysfs_init();
Packit 55b723
		sysfs_initialized = 1;
Packit 55b723
	}
Packit 55b723
	increase_max_files();
Packit 55b723
	if (idbm_init(NULL)) {
Packit 55b723
		sysfs_cleanup();
Packit 55b723
		free(context);
Packit 55b723
		return NULL;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	iface_setup_host_bindings();
Packit 55b723
Packit 55b723
	return context;
Packit 55b723
}
Packit 55b723
Packit 55b723
void libiscsi_cleanup(struct libiscsi_context *context)
Packit 55b723
{
Packit 55b723
	idbm_terminate();
Packit 55b723
	free_transports();
Packit 55b723
	sysfs_cleanup();
Packit 55b723
	free(context);
Packit 55b723
}
Packit 55b723
Packit 55b723
static void free_iface_list(struct list_head *ifaces)
Packit 55b723
{
Packit 55b723
	struct iface_rec *iface, *tmp_iface;
Packit 55b723
Packit 55b723
	list_for_each_entry_safe(iface, tmp_iface, ifaces, list) {
Packit 55b723
		list_del(&iface->list);
Packit 55b723
		free(iface);
Packit 55b723
	}
Packit 55b723
}
Packit 55b723
Packit 55b723
static void free_rec_list(struct list_head *rec_list)
Packit 55b723
{
Packit 55b723
	struct node_rec *rec, *tmp;
Packit 55b723
	
Packit 55b723
	list_for_each_entry_safe(rec, tmp, rec_list, list) {
Packit 55b723
		list_del(&rec->list);
Packit 55b723
		free(rec);
Packit 55b723
	}
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_discover_sendtargets(struct libiscsi_context *context,
Packit 55b723
	const char *address, int port,
Packit 55b723
	const struct libiscsi_auth_info *auth_info,
Packit 55b723
	int *nr_found, struct libiscsi_node **found_nodes)
Packit 55b723
{
Packit 55b723
	struct discovery_rec drec;
Packit 55b723
	LIST_HEAD(bound_rec_list);
Packit 55b723
	struct node_rec *rec;
Packit 55b723
	int rc = 0, found = 0;
Packit 55b723
Packit 55b723
	INIT_LIST_HEAD(&bound_rec_list);
Packit 55b723
Packit 55b723
	if (nr_found)
Packit 55b723
		*nr_found = 0;
Packit 55b723
	if (found_nodes)
Packit 55b723
		*found_nodes = NULL;
Packit 55b723
Packit 55b723
	CHECK(libiscsi_verify_auth_info(context, auth_info))
Packit 55b723
Packit 55b723
	/* Fill the drec struct with all needed info */
Packit 55b723
	memset(&drec, 0, sizeof drec);
Packit c1e24c
	drec.iscsid_req_tmo = -1;
Packit 55b723
	idbm_sendtargets_defaults(&drec.u.sendtargets);
Packit 55b723
	drec.type = DISCOVERY_TYPE_SENDTARGETS;
Packit 55b723
	strlcpy(drec.address, address, sizeof(drec.address));
Packit 55b723
	drec.port = port ? port : ISCSI_LISTEN_PORT;
Packit 55b723
	switch(auth_info ? auth_info->method : libiscsi_auth_none) {
Packit 55b723
	case libiscsi_auth_chap:
Packit 55b723
		drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP;
Packit 55b723
		strlcpy(drec.u.sendtargets.auth.username,
Packit 55b723
			auth_info->chap.username, AUTH_STR_MAX_LEN);
Packit 55b723
		strlcpy((char *)drec.u.sendtargets.auth.password,
Packit 55b723
			auth_info->chap.password, AUTH_STR_MAX_LEN);
Packit 55b723
		drec.u.sendtargets.auth.password_length =
Packit 55b723
			strlen((char *)drec.u.sendtargets.auth.password);
Packit 55b723
		strlcpy(drec.u.sendtargets.auth.username_in,
Packit 55b723
			auth_info->chap.reverse_username, AUTH_STR_MAX_LEN);
Packit 55b723
		strlcpy((char *)drec.u.sendtargets.auth.password_in,
Packit 55b723
			auth_info->chap.reverse_password, AUTH_STR_MAX_LEN);
Packit 55b723
		drec.u.sendtargets.auth.password_in_length =
Packit 55b723
			strlen((char *)drec.u.sendtargets.auth.password_in);
Packit 55b723
		break;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	CHECK(idbm_add_discovery(&drec))
Packit 55b723
Packit 55b723
	CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets,
Packit 55b723
					&drec, NULL, &bound_rec_list))
Packit 55b723
Packit 55b723
	/* now add/update records */
Packit 55b723
	list_for_each_entry(rec, &bound_rec_list, list) {
Packit 55b723
		CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */))
Packit 55b723
		found++;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	if (nr_found)
Packit 55b723
		*nr_found = found;
Packit 55b723
Packit 55b723
	if (found_nodes && found) {
Packit 55b723
		*found_nodes = calloc(found, sizeof **found_nodes);
Packit 55b723
		if (*found_nodes == NULL) {
Packit 55b723
			snprintf(context->error_str,
Packit cdf9cf
				 sizeof(context->error_str),
Packit cdf9cf
				 "%s", strerror(ENOMEM));
Packit 55b723
			rc = ENOMEM;
Packit 55b723
			goto leave;
Packit 55b723
		}
Packit 55b723
		found = 0;
Packit 55b723
		list_for_each_entry(rec, &bound_rec_list, list) {
Packit 55b723
			strlcpy((*found_nodes)[found].name, rec->name,
Packit 55b723
				 LIBISCSI_VALUE_MAXLEN);
Packit 55b723
			(*found_nodes)[found].tpgt = rec->tpgt;
Packit 55b723
			strlcpy((*found_nodes)[found].address,
Packit 55b723
				 rec->conn[0].address, NI_MAXHOST);
Packit 55b723
			(*found_nodes)[found].port = rec->conn[0].port;
Packit 55b723
			strlcpy((*found_nodes)[found].iface,
Packit 55b723
				 rec->iface.name, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
			found++;
Packit 55b723
		}
Packit 55b723
	}
Packit 55b723
Packit 55b723
leave:
Packit 55b723
	free_rec_list(&bound_rec_list);
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_discover_firmware(struct libiscsi_context *context,
Packit 55b723
	int *nr_found, struct libiscsi_node **found_nodes)
Packit 55b723
{
Packit 55b723
	struct list_head targets, ifaces, rec_list;
Packit 55b723
	discovery_rec_t drec;
Packit 55b723
	int rc = 0;
Packit 55b723
Packit 55b723
	INIT_LIST_HEAD(&targets;;
Packit 55b723
	INIT_LIST_HEAD(&ifaces);
Packit 55b723
	INIT_LIST_HEAD(&rec_list);
Packit 55b723
Packit 55b723
	if (nr_found) {
Packit 55b723
		*nr_found = 0;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	if (found_nodes) {
Packit 55b723
		*found_nodes = NULL;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	rc = fw_get_targets(&targets;;
Packit 55b723
	if (rc) {
Packit 55b723
		log_error("%s: Could not get list of targets from firmware "
Packit 55b723
			  "(err %d).\n", __func__, rc);
Packit 55b723
		return rc;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets));
Packit 55b723
Packit 55b723
	memset(&drec, 0, sizeof(drec));
Packit c1e24c
	drec.iscsid_req_tmo = -1;
Packit 55b723
	drec.type = DISCOVERY_TYPE_FW;
Packit 55b723
	rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list);
Packit 55b723
	if (rc) {
Packit 55b723
		log_error("%s: Could not determine target nodes from firmware "
Packit 55b723
			  "(err %d).\n", __func__, rc);
Packit 55b723
		goto leave;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	int node_count = 0;
Packit 55b723
	struct list_head *pos;
Packit 55b723
	list_for_each(pos, &rec_list) {
Packit 55b723
		++node_count;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	struct libiscsi_node* new_nodes;
Packit 55b723
	/* allocate enough space for all the nodes */
Packit 55b723
	new_nodes = calloc(node_count, sizeof *new_nodes);
Packit 55b723
	if (new_nodes == NULL) {
Packit 55b723
		rc = ENOMEM;
Packit 55b723
		log_error("%s: %s.\n", __func__, strerror(ENOMEM));
Packit 55b723
		goto leave;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	struct node_rec *rec;
Packit 55b723
	struct libiscsi_node *new_node = new_nodes;
Packit 55b723
	/* in one loop, add nodes to idbm and create libiscsi_node entries */
Packit 55b723
	list_for_each_entry(rec, &rec_list, list) {
Packit 55b723
		CHECK(idbm_add_node(rec, NULL, 1 /* overwrite */));
Packit 55b723
Packit 55b723
		strlcpy(new_node->name, rec->name, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
		new_node->tpgt = rec->tpgt;
Packit 55b723
		strlcpy(new_node->address, rec->conn[0].address, NI_MAXHOST);
Packit 55b723
		new_node->port = rec->conn[0].port;
Packit 55b723
		strlcpy(new_node->iface, rec->iface.name, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
Packit 55b723
		++new_node;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	/* update output parameters */
Packit 55b723
	if (nr_found) {
Packit 55b723
		*nr_found = node_count;
Packit 55b723
	}
Packit 55b723
	if (found_nodes) {
Packit 55b723
		*found_nodes = new_nodes;
Packit 55b723
	}
Packit 55b723
Packit 55b723
leave:
Packit 55b723
	fw_free_targets(&targets;;
Packit 55b723
Packit 55b723
	free_iface_list(&ifaces);
Packit 55b723
	free_rec_list(&rec_list);
Packit 55b723
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_verify_auth_info(struct libiscsi_context *context,
Packit 55b723
	const struct libiscsi_auth_info *auth_info)
Packit 55b723
{
Packit 55b723
	switch(auth_info ? auth_info->method : libiscsi_auth_none) {
Packit 55b723
	case libiscsi_auth_none:
Packit 55b723
		break;
Packit 55b723
	case libiscsi_auth_chap:
Packit 55b723
		if (!auth_info->chap.username[0]) {
Packit 55b723
			strcpy(context->error_str, "Empty username");
Packit 55b723
			return EINVAL;
Packit 55b723
		}
Packit 55b723
		if (!auth_info->chap.password[0]) {
Packit 55b723
			strcpy(context->error_str, "Empty password");
Packit 55b723
			return EINVAL;
Packit 55b723
		}
Packit 55b723
		if (auth_info->chap.reverse_username[0] &&
Packit 55b723
		    !auth_info->chap.reverse_password[0]) {
Packit 55b723
			strcpy(context->error_str, "Empty reverse password");
Packit 55b723
		    	return EINVAL;
Packit 55b723
		}
Packit 55b723
		break;
Packit 55b723
	default:
Packit 55b723
		sprintf(context->error_str,
Packit 55b723
			"Invalid authentication method: %d",
Packit 55b723
			(int)auth_info->method);
Packit 55b723
		return EINVAL;
Packit 55b723
	}
Packit 55b723
	return 0;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_node_set_auth(struct libiscsi_context *context,
Packit 55b723
    const struct libiscsi_node *node,
Packit 55b723
    const struct libiscsi_auth_info *auth_info)
Packit 55b723
{
Packit 55b723
	int rc = 0;
Packit 55b723
Packit 55b723
	CHECK(libiscsi_verify_auth_info(context, auth_info))
Packit 55b723
Packit 55b723
	switch(auth_info ? auth_info->method : libiscsi_auth_none) {
Packit 55b723
	case libiscsi_auth_none:
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.authmethod", "None"))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.username", ""))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.password", ""))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.username_in", ""))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.password_in", ""))
Packit 55b723
		break;
Packit 55b723
Packit 55b723
	case libiscsi_auth_chap:
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.authmethod", "CHAP"))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.username",
Packit 55b723
			auth_info->chap.username))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.password",
Packit 55b723
			auth_info->chap.password))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.username_in",
Packit 55b723
			auth_info->chap.reverse_username))
Packit 55b723
		CHECK(libiscsi_node_set_parameter(context, node,
Packit 55b723
			"node.session.auth.password_in",
Packit 55b723
			auth_info->chap.reverse_password))
Packit 55b723
		break;
Packit 55b723
	}
Packit 55b723
leave:
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_node_get_auth(struct libiscsi_context *context,
Packit 55b723
    const struct libiscsi_node *node,
Packit 55b723
    struct libiscsi_auth_info *auth_info)
Packit 55b723
{
Packit 55b723
	int rc = 0;
Packit 55b723
	char value[LIBISCSI_VALUE_MAXLEN];
Packit 55b723
Packit 55b723
	memset(auth_info, 0, sizeof *auth_info);
Packit 55b723
Packit 55b723
	CHECK(libiscsi_node_get_parameter(context, node,
Packit 55b723
			"node.session.auth.authmethod", value))
Packit 55b723
Packit 55b723
	if (!strcmp(value, "None")) {
Packit 55b723
		auth_info->method = libiscsi_auth_none;
Packit 55b723
	} else if (!strcmp(value, "CHAP")) {
Packit 55b723
		auth_info->method = libiscsi_auth_chap;
Packit 55b723
		CHECK(libiscsi_node_get_parameter(context, node,
Packit 55b723
			"node.session.auth.username",
Packit 55b723
			auth_info->chap.username))
Packit 55b723
		CHECK(libiscsi_node_get_parameter(context, node,
Packit 55b723
			"node.session.auth.password",
Packit 55b723
			auth_info->chap.password))
Packit 55b723
		CHECK(libiscsi_node_get_parameter(context, node,
Packit 55b723
			"node.session.auth.username_in",
Packit 55b723
			auth_info->chap.reverse_username))
Packit 55b723
		CHECK(libiscsi_node_get_parameter(context, node,
Packit 55b723
			"node.session.auth.password_in",
Packit 55b723
			auth_info->chap.reverse_password))
Packit 55b723
	} else {
Packit 55b723
		snprintf(context->error_str, sizeof(context->error_str),
Packit 55b723
			 "unknown authentication method: %s", value);
Packit 55b723
		rc = EINVAL;
Packit 55b723
	}
Packit 55b723
leave:
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
static void node_to_rec(const struct libiscsi_node *node,
Packit 55b723
	struct node_rec *rec)
Packit 55b723
{
Packit 55b723
	memset(rec, 0, sizeof *rec);
Packit 55b723
	idbm_node_setup_defaults(rec);
Packit 55b723
	strlcpy(rec->name, node->name, TARGET_NAME_MAXLEN);
Packit 55b723
	rec->tpgt = node->tpgt;
Packit 55b723
	strlcpy(rec->conn[0].address, node->address, NI_MAXHOST);
Packit 55b723
	rec->conn[0].port = node->port;
Packit 55b723
}
Packit 55b723
Packit 55b723
int login_helper(void *data, node_rec_t *rec)
Packit 55b723
{
Packit 55b723
	char *iface = (char*)data;
Packit 55b723
	if (strcmp(iface, rec->iface.name))
Packit 55b723
		/* different iface, skip it */
Packit 55b723
		return -1;
Packit 55b723
Packit 55b723
	int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
Packit 55b723
	if (rc) {
Packit 55b723
		iscsi_err_print_msg(rc);
Packit 55b723
		rc = ENOTCONN;
Packit 55b723
	}
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_node_login(struct libiscsi_context *context,
Packit 55b723
	const struct libiscsi_node *node)
Packit 55b723
{
Packit 55b723
	int nr_found = 0, rc;
Packit 55b723
Packit 55b723
	CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper,
Packit 55b723
		(char *)node->name, node->tpgt,
Packit 55b723
		(char *)node->address, node->port))
Packit 55b723
	if (nr_found == 0) {
Packit 55b723
		strcpy(context->error_str, "No such node");
Packit 55b723
		rc = ENODEV;
Packit 55b723
	}
Packit 55b723
leave:
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
static int logout_helper(void *data, struct session_info *info)
Packit 55b723
{
Packit 55b723
	int rc;
Packit 55b723
	struct node_rec *rec = data;
Packit 55b723
Packit 55b723
	if (!iscsi_match_session(rec, info))
Packit 55b723
		/* Tell iscsi_sysfs_for_each_session this session was not a
Packit 55b723
		   match so that it will not increase nr_found. */
Packit 55b723
		return -1;
Packit 55b723
Packit 55b723
	rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
Packit 55b723
	if (rc) {
Packit 55b723
		iscsi_err_print_msg(rc);
Packit 55b723
		rc = EIO;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_node_logout(struct libiscsi_context *context,
Packit 55b723
	const struct libiscsi_node *node)
Packit 55b723
{
Packit 55b723
	int nr_found = 0, rc;
Packit 55b723
	struct node_rec rec;
Packit 55b723
Packit 55b723
	node_to_rec(node, &rec);
Packit 55b723
	CHECK(iscsi_sysfs_for_each_session(&rec, &nr_found, logout_helper,0))
Packit 55b723
	if (nr_found == 0) {
Packit 55b723
		strcpy(context->error_str, "No matching session");
Packit 55b723
		rc = ENODEV;
Packit 55b723
	}
Packit 55b723
leave:
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit dfd6cc
struct libiscsi_session_array {
Packit dfd6cc
	int cnt;
Packit dfd6cc
	int size;
Packit dfd6cc
	struct libiscsi_session_info *data;
Packit dfd6cc
};
Packit dfd6cc
Packit dfd6cc
static void libiscsi_session_array_init(struct libiscsi_session_array *arr)
Packit dfd6cc
{
Packit dfd6cc
	arr->cnt = 0;
Packit dfd6cc
	arr->size = 0;
Packit dfd6cc
	arr->data = NULL;
Packit dfd6cc
}
Packit dfd6cc
Packit dfd6cc
static int libiscsi_session_array_grow(struct libiscsi_session_array *arr)
Packit dfd6cc
{
Packit dfd6cc
	if (arr->size == 0)
Packit dfd6cc
		arr->size = 4;
Packit dfd6cc
	else
Packit dfd6cc
		arr->size *= 2;
Packit dfd6cc
Packit dfd6cc
	arr->data = (struct libiscsi_session_info *) realloc(
Packit dfd6cc
		arr->data,
Packit dfd6cc
		arr->size * sizeof(struct libiscsi_session_info));
Packit dfd6cc
Packit dfd6cc
	return arr->data ? 0 : 1;
Packit dfd6cc
}
Packit dfd6cc
Packit dfd6cc
static int libiscsi_session_array_grow_ondemand(struct libiscsi_session_array *arr)
Packit dfd6cc
{
Packit dfd6cc
	if (arr->size == arr->cnt)
Packit dfd6cc
		return libiscsi_session_array_grow(arr);
Packit dfd6cc
	return 0;
Packit dfd6cc
}
Packit dfd6cc
Packit dfd6cc
static int libiscsi_session_array_resize_precize(struct libiscsi_session_array *arr)
Packit dfd6cc
{
Packit dfd6cc
	arr->data = (struct libiscsi_session_info *) realloc(
Packit dfd6cc
		arr->data,
Packit dfd6cc
		arr->cnt * sizeof(struct libiscsi_session_info));
Packit dfd6cc
	arr->size = arr->cnt;
Packit dfd6cc
Packit dfd6cc
	return arr->data ? 0 : 1;
Packit dfd6cc
}
Packit dfd6cc
Packit dfd6cc
static void copy_session_info_to_libiscsi_session_info(
Packit dfd6cc
	struct libiscsi_session_info *info,
Packit dfd6cc
	struct session_info *s_info)
Packit dfd6cc
{
Packit dfd6cc
	/* Copy session info to public struct. */
Packit dfd6cc
	info->sid = s_info->sid;
Packit dfd6cc
	/* Timeouts */
Packit dfd6cc
	memcpy(&info->tmo, &s_info->tmo, sizeof(struct libiscsi_session_timeout));
Packit dfd6cc
	/* CHAP authentication information */
Packit dfd6cc
	memcpy(&info->chap, &s_info->chap, sizeof(struct libiscsi_chap_auth_info));
Packit dfd6cc
	/* Target information */
Packit dfd6cc
	strncpy(info->targetname, s_info->targetname, LIBISCSI_VALUE_MAXLEN);
Packit dfd6cc
	strncpy(info->address, s_info->address, NI_MAXHOST);
Packit dfd6cc
	strncpy(info->persistent_address, s_info->persistent_address, NI_MAXHOST);
Packit dfd6cc
	info->tpgt = s_info->tpgt;
Packit dfd6cc
	info->persistent_port = s_info->persistent_port;
Packit dfd6cc
}
Packit dfd6cc
Packit dfd6cc
static int get_sessions_helper(void *data, struct session_info *s_info)
Packit dfd6cc
{
Packit dfd6cc
	struct libiscsi_session_array *arr = (struct libiscsi_session_array *) data;
Packit dfd6cc
Packit dfd6cc
	if (libiscsi_session_array_grow_ondemand(arr) != 0)
Packit dfd6cc
		return 1;
Packit dfd6cc
Packit dfd6cc
	copy_session_info_to_libiscsi_session_info(&arr->data[arr->cnt++], s_info);
Packit dfd6cc
Packit dfd6cc
	return 0;
Packit dfd6cc
}
Packit dfd6cc
Packit dfd6cc
int libiscsi_get_session_infos(struct libiscsi_context *context,
Packit dfd6cc
	struct libiscsi_session_info **infos,
Packit dfd6cc
	int *nr_sessions)
Packit dfd6cc
{
Packit dfd6cc
	int rc = 0;
Packit dfd6cc
	int nr_found = 0;
Packit dfd6cc
	struct libiscsi_session_array arr;
Packit dfd6cc
Packit dfd6cc
	if (!context || !infos || !nr_sessions)
Packit dfd6cc
		return 1;
Packit dfd6cc
Packit dfd6cc
	libiscsi_session_array_init(&arr;;
Packit dfd6cc
Packit dfd6cc
	rc = iscsi_sysfs_for_each_session((void *) &arr, &nr_found,
Packit dfd6cc
		get_sessions_helper, 0);
Packit dfd6cc
	if (rc != 0 || nr_found == 0) {
Packit dfd6cc
		strcpy(context->error_str, "No matching session");
Packit dfd6cc
		return ENODEV;
Packit dfd6cc
	}
Packit dfd6cc
Packit dfd6cc
	if (libiscsi_session_array_resize_precize(&arr) != 0) {
Packit dfd6cc
		strcpy(context->error_str, "Can't allocate memory for session infos");
Packit dfd6cc
		return ENOMEM;
Packit dfd6cc
	}
Packit dfd6cc
Packit dfd6cc
	*infos = arr.data;
Packit dfd6cc
	*nr_sessions = nr_found;
Packit dfd6cc
Packit dfd6cc
	return 0;
Packit dfd6cc
}
Packit dfd6cc
Packit dfd6cc
int libiscsi_get_session_info_by_id(struct libiscsi_context *context,
Packit dfd6cc
	struct libiscsi_session_info *info,
Packit dfd6cc
	const char *session)
Packit dfd6cc
{
Packit dfd6cc
	struct session_info s_info;
Packit dfd6cc
Packit dfd6cc
	if (!context || !info || !session)
Packit dfd6cc
		return 1;
Packit dfd6cc
Packit dfd6cc
	if (iscsi_sysfs_get_sessioninfo_by_id(&s_info, (char*) session) != 0) {
Packit dfd6cc
		strcpy(context->error_str, "No matching session");
Packit dfd6cc
		return ENODEV;
Packit dfd6cc
	}
Packit dfd6cc
Packit dfd6cc
	copy_session_info_to_libiscsi_session_info(info, &s_info);
Packit dfd6cc
Packit dfd6cc
	return 0;
Packit dfd6cc
}
Packit dfd6cc
Packit 55b723
int libiscsi_node_set_parameter(struct libiscsi_context *context,
Packit 55b723
	const struct libiscsi_node *node,
Packit 55b723
	const char *parameter, const char *value)
Packit 55b723
{
Packit 55b723
	int nr_found = 0, rc;
Packit 55b723
	struct user_param *param;
Packit 55b723
	struct list_head params;
Packit 55b723
Packit 55b723
	INIT_LIST_HEAD(&params);
Packit 55b723
	param = idbm_alloc_user_param(parameter, value);
Packit 55b723
	if (!param) {
Packit 55b723
		rc = ENOMEM;
Packit 55b723
		goto leave;
Packit 55b723
	}
Packit 55b723
	list_add_tail(&params, &param->list);
Packit 55b723
Packit 55b723
	CHECK(idbm_for_each_iface(&nr_found, &params, idbm_node_set_param,
Packit 55b723
		(char *)node->name, node->tpgt,
Packit 55b723
		(char *)node->address, node->port))
Packit 55b723
	if (nr_found == 0) {
Packit 55b723
		strcpy(context->error_str, "No such node");
Packit 55b723
		rc = ENODEV;
Packit 55b723
	}
Packit 55b723
	free(param->name);
Packit 55b723
	free(param);
Packit 55b723
leave:
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
static int get_parameter_helper(void *data, node_rec_t *rec)
Packit 55b723
{
Packit 55b723
	struct libiscsi_context *context = data;
Packit 55b723
	recinfo_t *info;
Packit 55b723
	int i;
Packit 55b723
Packit 55b723
	info = idbm_recinfo_alloc(MAX_KEYS);
Packit 55b723
	if (!info) {
Packit 55b723
		snprintf(context->error_str, sizeof(context->error_str),
Packit cdf9cf
			 "%s", strerror(ENOMEM));
Packit 55b723
		return ENOMEM;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	idbm_recinfo_node(rec, info);
Packit 55b723
Packit 55b723
	for (i = 0; i < MAX_KEYS; i++) {
Packit 55b723
		if (!info[i].visible)
Packit 55b723
			continue;
Packit 55b723
Packit 55b723
		if (strcmp(context->parameter, info[i].name))
Packit 55b723
			continue;
Packit 55b723
Packit 55b723
		strlcpy(context->value, info[i].value, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
		break;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	free(info);
Packit 55b723
Packit 55b723
	if (i == MAX_KEYS) {
Packit 55b723
		strcpy(context->error_str, "No such parameter");
Packit 55b723
		return EINVAL;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	return 0;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_node_get_parameter(struct libiscsi_context *context,
Packit 55b723
	const struct libiscsi_node *node, const char *parameter, char *value)
Packit 55b723
{
Packit 55b723
	int nr_found = 0, rc = 0;
Packit 55b723
Packit 55b723
	context->parameter = parameter;
Packit 55b723
	context->value = value;
Packit 55b723
Packit 55b723
	/* Note we assume there is only one interface, if not we will get
Packit 55b723
	   the value from the last interface iterated over!
Packit 55b723
	   This (multiple interfaces) can only happen if someone explicitly
Packit 55b723
	   created ones using iscsiadm. Even then this should not be a problem
Packit 55b723
	   as most settings should be the same independent of the iface. */
Packit 55b723
	CHECK(idbm_for_each_iface(&nr_found, context, get_parameter_helper,
Packit 55b723
		(char *)node->name, node->tpgt,
Packit 55b723
		(char *)node->address, node->port))
Packit 55b723
	if (nr_found == 0) {
Packit 55b723
		strcpy(context->error_str, "No such node");
Packit 55b723
		rc = ENODEV;
Packit 55b723
	}
Packit 55b723
leave:
Packit 55b723
	return rc;
Packit 55b723
}
Packit 55b723
Packit 55b723
const char *libiscsi_get_error_string(struct libiscsi_context *context)
Packit 55b723
{
Packit 55b723
	/* Sometimes the core open-iscsi code does not give us an error
Packit 55b723
	   message */
Packit 55b723
	if (!context->error_str[0])
Packit 55b723
		return "Unknown error";
Packit 55b723
Packit 55b723
	return context->error_str;
Packit 55b723
}
Packit 55b723
Packit 55b723
Packit 55b723
/************************** Utility functions *******************************/
Packit 55b723
Packit 55b723
int libiscsi_get_firmware_network_config(
Packit 55b723
    struct libiscsi_network_config *config)
Packit 55b723
{
Packit 55b723
	struct boot_context fw_entry;
Packit 55b723
Packit 55b723
	if (!sysfs_initialized) {
Packit 55b723
		sysfs_init();
Packit 55b723
		sysfs_initialized = 1;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	memset(config, 0, sizeof *config);
Packit 55b723
	memset(&fw_entry, 0, sizeof fw_entry);
Packit 55b723
	if (fw_get_entry(&fw_entry))
Packit 55b723
		return ENODEV;
Packit 55b723
Packit 55b723
	config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0;
Packit 55b723
	strlcpy(config->iface_name, fw_entry.iface, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	strlcpy(config->mac_address, fw_entry.mac, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	strlcpy(config->ip_address, fw_entry.ipaddr, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	strlcpy(config->netmask, fw_entry.mask, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	strlcpy(config->gateway, fw_entry.gateway, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	strlcpy(config->primary_dns, fw_entry.primary_dns, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	strlcpy(config->secondary_dns, fw_entry.secondary_dns, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	return 0;
Packit 55b723
}
Packit 55b723
Packit 55b723
int libiscsi_get_firmware_initiator_name(char *initiatorname)
Packit 55b723
{
Packit 55b723
	struct boot_context fw_entry;
Packit 55b723
Packit 55b723
	if (!sysfs_initialized) {
Packit 55b723
		sysfs_init();
Packit 55b723
		sysfs_initialized = 1;
Packit 55b723
	}
Packit 55b723
Packit 55b723
	memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
	memset(&fw_entry, 0, sizeof fw_entry);
Packit 55b723
	if (fw_get_entry(&fw_entry))
Packit 55b723
		return ENODEV;
Packit 55b723
Packit 55b723
	strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN);
Packit 55b723
Packit 55b723
	return 0;
Packit 55b723
}