|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Copyright (C) 2017 Red Hat, Inc.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software: you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
eace71 |
* the Free Software Foundation, either version 3 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
eace71 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
eace71 |
* GNU General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
eace71 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Author: Gris Ge <fge@redhat.com>
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
#ifndef _GNU_SOURCE
|
|
Packit |
eace71 |
#define _GNU_SOURCE /* For NI_MAXHOST */
|
|
Packit |
eace71 |
#endif
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include <stdint.h>
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <assert.h>
|
|
Packit |
eace71 |
#include <dirent.h>
|
|
Packit |
eace71 |
#include <limits.h>
|
|
Packit |
eace71 |
#include <stdint.h>
|
|
Packit |
eace71 |
#include <inttypes.h>
|
|
Packit |
eace71 |
#include <netdb.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "libopeniscsiusr/libopeniscsiusr.h"
|
|
Packit |
eace71 |
#include "misc.h"
|
|
Packit |
eace71 |
#include "sysfs.h"
|
|
Packit |
eace71 |
#include "iface.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define _ISCSI_NAME_MAX_LEN 223
|
|
Packit |
eace71 |
/* ^ RFC 3720:
|
|
Packit |
eace71 |
* Each iSCSI node, whether an initiator or target, MUST have an iSCSI
|
|
Packit |
eace71 |
* name.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Initiators and targets MUST support the receipt of iSCSI names of up
|
|
Packit |
eace71 |
* to the maximum length of 223 bytes.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define _ISCSI_CHAP_AUTH_STR_MAX_LEN 256
|
|
Packit |
eace71 |
/* ^ No official document found for this value, just copy from usr/auth.h
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_session {
|
|
Packit |
eace71 |
uint32_t sid;
|
|
Packit |
eace71 |
/* ^ It's actually a int according to Linux kernel code but
|
|
Packit |
eace71 |
* the dev_set_name() in iscsi_add_session() of scsi_transport_iscsi.c
|
|
Packit |
eace71 |
* are using %u to output this.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
char persistent_address[NI_MAXHOST + 1];
|
|
Packit |
eace71 |
int32_t persistent_port;
|
|
Packit |
eace71 |
char target_name[_ISCSI_NAME_MAX_LEN + 1];
|
|
Packit |
eace71 |
char username[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
|
|
Packit |
eace71 |
char password[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
|
|
Packit |
eace71 |
char username_in[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
|
|
Packit |
eace71 |
char password_in[_ISCSI_CHAP_AUTH_STR_MAX_LEN];
|
|
Packit |
eace71 |
int32_t recovery_tmo;
|
|
Packit |
eace71 |
/* ^ It's actually a int according to Linux kernel code.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int32_t lu_reset_tmo;
|
|
Packit |
eace71 |
/* ^ It's actually a int according to Linux kernel code.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int32_t tgt_reset_tmo;
|
|
Packit |
eace71 |
/* ^ It's actually a int according to Linux kernel code.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int32_t abort_tmo;
|
|
Packit |
eace71 |
/* ^ It's actually a int according to Linux kernel code.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int32_t tpgt;
|
|
Packit |
eace71 |
/* ^ It's actually a int according to Linux kernel code.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
char address[NI_MAXHOST + 1];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int32_t port;
|
|
Packit |
eace71 |
struct iscsi_iface *iface;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, sid, uint32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, persistent_address, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, persistent_port, int32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, target_name, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, username, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, password, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, username_in, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, password_in, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, recovery_tmo, int32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, lu_reset_tmo, int32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, tgt_reset_tmo, int32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, abort_tmo, int32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, tpgt, int32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, address, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, port, int32_t);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_session, iface, struct iscsi_iface *);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid,
|
|
Packit |
eace71 |
struct iscsi_session **se)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
char *sysfs_se_dir_path = NULL;
|
|
Packit |
eace71 |
char *sysfs_con_dir_path = NULL;
|
|
Packit |
eace71 |
uint32_t host_id = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
assert(se != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_debug(ctx, "Querying iSCSI session for sid %" PRIu32, sid);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_asprintf(&sysfs_se_dir_path, "%s/session%" PRIu32,
|
|
Packit |
eace71 |
_ISCSI_SYS_SESSION_DIR, sid), rc, out);
|
|
Packit |
eace71 |
_good(_asprintf(&sysfs_con_dir_path, "%s/connection%" PRIu32 ":0",
|
|
Packit |
eace71 |
_ISCSI_SYS_CONNECTION_DIR, sid), rc, out);
|
|
Packit |
eace71 |
/* ^ BUG(Gris Ge): ':0' here in kernel is referred as connection id.
|
|
Packit |
eace71 |
* but the open-iscsi assuming it's always 0, need
|
|
Packit |
eace71 |
* investigation.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*se = (struct iscsi_session *) calloc(1, sizeof(struct iscsi_session));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, *se , rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (! _file_exists(sysfs_se_dir_path)) {
|
|
Packit |
eace71 |
_info(ctx, "Sysfs path '%s' does not exists",
|
|
Packit |
eace71 |
sysfs_se_dir_path);
|
|
Packit |
eace71 |
rc = LIBISCSI_ERR_SESS_NOT_FOUND;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (! _file_exists(sysfs_con_dir_path)) {
|
|
Packit |
eace71 |
_info(ctx, "Sysfs path '%s' does not exists",
|
|
Packit |
eace71 |
sysfs_se_dir_path);
|
|
Packit |
eace71 |
rc = LIBISCSI_ERR_SESS_NOT_FOUND;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (rc == LIBISCSI_ERR_SESS_NOT_FOUND) {
|
|
Packit |
eace71 |
_error(ctx, "Specified SID %" PRIu32, "does not exists",
|
|
Packit |
eace71 |
sid);
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
(*se)->sid = sid;
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "targetname",
|
|
Packit |
eace71 |
(*se)->target_name,
|
|
Packit |
eace71 |
sizeof((*se)->target_name) / sizeof(char),
|
|
Packit |
eace71 |
NULL), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "username",
|
|
Packit |
eace71 |
(*se)->username,
|
|
Packit |
eace71 |
sizeof((*se)->username) / sizeof(char),
|
|
Packit |
eace71 |
""),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "password",
|
|
Packit |
eace71 |
(*se)->password,
|
|
Packit |
eace71 |
sizeof((*se)->password) / sizeof(char),
|
|
Packit |
eace71 |
""),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "username_in",
|
|
Packit |
eace71 |
(*se)->username_in,
|
|
Packit |
eace71 |
sizeof((*se)->username_in) / sizeof(char),
|
|
Packit |
eace71 |
""),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "password_in",
|
|
Packit |
eace71 |
(*se)->password_in,
|
|
Packit |
eace71 |
sizeof((*se)->password_in) / sizeof(char),
|
|
Packit |
eace71 |
""),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "recovery_tmo",
|
|
Packit |
eace71 |
&((*se)->recovery_tmo), -1, true),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "lu_reset_tmo",
|
|
Packit |
eace71 |
&((*se)->lu_reset_tmo), -1, true),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "tgt_reset_tmo",
|
|
Packit |
eace71 |
&((*se)->tgt_reset_tmo), -1, true),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "abort_tmo",
|
|
Packit |
eace71 |
&((*se)->abort_tmo), -1, true),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "tpgt",
|
|
Packit |
eace71 |
&((*se)->tpgt), -1, true),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_con_dir_path, "persistent_address",
|
|
Packit |
eace71 |
(*se)->persistent_address,
|
|
Packit |
eace71 |
sizeof((*se)->persistent_address) /
|
|
Packit |
eace71 |
sizeof(char), ""),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "persistent_port",
|
|
Packit |
eace71 |
&((*se)->persistent_port), -1, true),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_con_dir_path, "address", (*se)->address,
|
|
Packit |
eace71 |
sizeof((*se)->address) / sizeof(char), "");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "port",
|
|
Packit |
eace71 |
&((*se)->port), -1, true);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((strcmp((*se)->address, "") != 0) &&
|
|
Packit |
eace71 |
(strcmp((*se)->persistent_address, "") == 0))
|
|
Packit |
eace71 |
_strncpy((*se)->persistent_address, (*se)->address,
|
|
Packit |
eace71 |
sizeof((*se)->persistent_address) / sizeof(char));
|
|
Packit |
eace71 |
else if ((strcmp((*se)->address, "") == 0) &&
|
|
Packit |
eace71 |
(strcmp((*se)->persistent_address, "") != 0))
|
|
Packit |
eace71 |
_strncpy((*se)->address, (*se)->persistent_address,
|
|
Packit |
eace71 |
sizeof((*se)->address) / sizeof(char));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (((*se)->persistent_port == -1) &&
|
|
Packit |
eace71 |
((*se)->port != -1))
|
|
Packit |
eace71 |
(*se)->persistent_port = (*se)->port;
|
|
Packit |
eace71 |
else if (((*se)->persistent_port != -1) &&
|
|
Packit |
eace71 |
((*se)->port == -1))
|
|
Packit |
eace71 |
(*se)->port = (*se)->persistent_port;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_iscsi_host_id_of_session(ctx, sid, &host_id), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* does this need to the correct iface_kern_id for the session? */
|
|
Packit |
eace71 |
_good(_iscsi_iface_get_from_sysfs(ctx, host_id, sid, NULL, &((*se)->iface)),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
if (rc != LIBISCSI_OK) {
|
|
Packit |
eace71 |
iscsi_session_free(*se);
|
|
Packit |
eace71 |
*se = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
free(sysfs_se_dir_path);
|
|
Packit |
eace71 |
free(sysfs_con_dir_path);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int iscsi_sessions_get(struct iscsi_context *ctx,
|
|
Packit |
eace71 |
struct iscsi_session ***sessions,
|
|
Packit |
eace71 |
uint32_t *session_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
uint32_t i = 0;
|
|
Packit |
eace71 |
uint32_t *sids = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
assert(sessions != NULL);
|
|
Packit |
eace71 |
assert(session_count != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*sessions = NULL;
|
|
Packit |
eace71 |
*session_count = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_iscsi_sids_get(ctx, &sids, session_count), rc ,out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*sessions = calloc (*session_count, sizeof(struct iscsi_session *));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, *sessions, rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < *session_count; ++i) {
|
|
Packit |
eace71 |
_debug(ctx, "sid %" PRIu32, sids[i]);
|
|
Packit |
eace71 |
_good(iscsi_session_get(ctx, sids[i], &((*sessions)[i])),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
free(sids);
|
|
Packit |
eace71 |
if (rc != LIBISCSI_OK) {
|
|
Packit |
eace71 |
iscsi_sessions_free(*sessions, *session_count);
|
|
Packit |
eace71 |
*sessions = NULL;
|
|
Packit |
eace71 |
*session_count = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void iscsi_session_free(struct iscsi_session *se)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (se != NULL)
|
|
Packit |
eace71 |
iscsi_iface_free(se->iface);
|
|
Packit |
eace71 |
free(se);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void iscsi_sessions_free(struct iscsi_session **ses, uint32_t se_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
uint32_t i = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((ses == NULL) || (se_count == 0))
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < se_count; ++i)
|
|
Packit |
eace71 |
iscsi_session_free(ses[i]);
|
|
Packit |
eace71 |
free (ses);
|
|
Packit |
eace71 |
}
|