Blame libiscsi/libiscsi.c

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