diff options
author | Gris Ge <fge@redhat.com> | 2018-01-19 21:27:08 +0800 |
---|---|---|
committer | Gris Ge <fge@redhat.com> | 2018-01-22 18:26:06 +0800 |
commit | 3fa1142dc14f5b15ad2ded32a3c6f34e4457e2af (patch) | |
tree | 99ad23eefa87248695651b6243cea7dfbccbf357 | |
parent | 5e9916b05d0b6404f414410ae080bf51a56047de (diff) | |
download | open-iscsi-3fa1142dc14f5b15ad2ded32a3c6f34e4457e2af.tar.gz |
libopeniscsiusr: Add iSCSI session support.
* iscsi_sessions_get()/iscsi_sessions_free() for query all iSCSI
session.
* iscsi_session_get()/iscsi_session_free() for query specified iSCSI
session id.
* And a lot more functions for property query of
`struct iscsi_session`.
* New unit test case created 'tests/test_session.c'.
Signed-off-by: Gris Ge <fge@redhat.com>
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | libopeniscsiusr/Makefile | 13 | ||||
-rw-r--r-- | libopeniscsiusr/docs/libopeniscsiusr.h.3 | 22 | ||||
-rw-r--r-- | libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h | 121 | ||||
-rw-r--r-- | libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h | 23 | ||||
-rw-r--r-- | libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h | 331 | ||||
-rw-r--r-- | libopeniscsiusr/misc.c | 21 | ||||
-rw-r--r-- | libopeniscsiusr/misc.h | 23 | ||||
-rw-r--r-- | libopeniscsiusr/session.c | 339 | ||||
-rw-r--r-- | libopeniscsiusr/sysfs.c | 242 | ||||
-rw-r--r-- | libopeniscsiusr/sysfs.h | 51 | ||||
-rw-r--r-- | libopeniscsiusr/tests/test_session.c | 107 |
12 files changed, 1281 insertions, 13 deletions
@@ -9,3 +9,4 @@ tags libopeniscsiusr/docs/man/ # ^ This folder is used for kernel-doc generated manpages. libopeniscsiusr/tests/test_context +libopeniscsiusr/tests/test_session diff --git a/libopeniscsiusr/Makefile b/libopeniscsiusr/Makefile index d137167..143a177 100644 --- a/libopeniscsiusr/Makefile +++ b/libopeniscsiusr/Makefile @@ -33,11 +33,12 @@ LIBS = $(DEVLIB).$(SONAME) LIBS_MAJOR = $(DEVLIB).$(LIBISCSI_USR_VERSION_MAJOR) PKGFILE = libopeniscsiusr.pc HEADERS = libopeniscsiusr/libopeniscsiusr.h \ - libopeniscsiusr/libopeniscsiusr_common.h -TESTS = tests/test_context + libopeniscsiusr/libopeniscsiusr_common.h \ + libopeniscsiusr/libopeniscsiusr_session.h +TESTS = tests/test_context tests/test_session EXTRA_MAN_FILES = libopeniscsiusr.h.3 -OBJS = context.o misc.o +OBJS = context.o misc.o session.o sysfs.o CFLAGS ?= -O2 -g CFLAGS += -Wall -Werror -Wextra -fvisibility=hidden -fPIC @@ -50,16 +51,16 @@ $(LIBS): $(OBJS) $(CC) $(LDFLAGS) -shared -Wl,-soname=$@ -o $@ $(OBJS) $(LIBADD) ln -sf $@ $(DEVLIB) -$(LIBS_MAJOR): +$(LIBS_MAJOR): $(LIBS) ln -sf $(LIBS) $@ clean: $(RM) vgcore* core *.a *.o *.gz *.so *.so.* $(TESTS) $(RM) -r docs/man -$(TESTS): CFLAGS = -Wall -Werror -Wextra -I$(TOPDIR)/libopeniscsiusr -g -$(TESTS): LDFLAGS += $(LIBADD) -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr $(TESTS): $(LIBS) +$(TESTS): CFLAGS += -I$(TOPDIR)/libopeniscsiusr -g +$(TESTS): LDFLAGS += $(LIBADD) -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr check: $(LIBS) $(TESTS) sudo env LD_LIBRARY_PATH=$(LIBISCSI_USR_DIR) TESTS="$(TESTS)" \ diff --git a/libopeniscsiusr/docs/libopeniscsiusr.h.3 b/libopeniscsiusr/docs/libopeniscsiusr.h.3 index eb6b483..9aecbb6 100644 --- a/libopeniscsiusr/docs/libopeniscsiusr.h.3 +++ b/libopeniscsiusr/docs/libopeniscsiusr.h.3 @@ -60,7 +60,27 @@ below in case you want to take it as an example to create your own log handler. .SH "SAMPLE CODE" -TODO, will add the sample code once we have real iscsi functions. + struct iscsi_context *ctx = NULL; + struct iscsi_session **ses = NULL; + uint32_t se_count = 0; + uint32_t i = 0; + int rc = EXIT_SUCCESS; + + ctx = iscsi_context_new(); + iscsi_context_log_priority_set(ctx, LIBISCSI_LOG_PRIORITY_DEBUG); + + if (iscsi_sessions_get(ctx, &ses, &se_count) != LIBISCSI_OK) { + printf("FAILED\n"); + rc = EXIT_FAILURE; + } else { + printf("\nGot %" PRIu32 " iSCSI sessions\n", se_count); + for (i = 0; i < se_count; ++i) + printf("SID is %" PRIu32 "\n", + iscsi_session_sid_get(ses[i])); + iscsi_sessions_free(ses, se_count); + } + iscsi_context_free(ctx); + exit(rc); .SH "LICENSE" GPLv3+ diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h index 281e191..45d42c1 100644 --- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h +++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h @@ -27,6 +27,7 @@ extern "C" { #include <stdarg.h> #include "libopeniscsiusr_common.h" +#include "libopeniscsiusr_session.h" /** * iscsi_log_priority_str() - Convert log priority to string. @@ -58,6 +59,16 @@ __DLL_EXPORT const char *iscsi_log_priority_str(int priority); * * * LIBISCSI_OK -- "OK" * + * * LIBISCSI_ERR_BUG -- "BUG of libopeniscsiusr library" + * + * * LIBISCSI_ERR_SESS_NOT_FOUND - "Specified iSCSI session not found" + * + * * LIBISCSI_ERR_ACCESS - "Permission deny" + * + * * LIBISCSI_ERR_NOMEM - "Out of memory" + * + * * LIBISCSI_ERR_SYSFS_LOOKUP - "Could not lookup object in sysfs" + * * * Other invalid error number -- "Invalid argument" * * @rc: @@ -203,6 +214,116 @@ __DLL_EXPORT void iscsi_context_userdata_set(struct iscsi_context *ctx, */ __DLL_EXPORT void *iscsi_context_userdata_get(struct iscsi_context *ctx); +/** + * iscsi_sessions_get() - Retrieve all iSCSI sessions. + * + * Retrieves all iSCSI sessions. For the properties of 'struct iscsi_session', + * please refer to the functions defined in 'libopeniscsiusr_session.h' file. + * + * @ctx: + * Pointer of 'struct iscsi_context'. + * If this pointer is NULL, your program will be terminated by assert. + * @ses: + * Output pointer of 'struct iscsi_session' pointer array. Its memory + * should be freed by iscsi_sessions_free(). + * If this pointer is NULL, your program will be terminated by assert. + * @se_count: + * Output pointer of uint32_t. Will store the size of + * 'struct iscsi_session' pointer array. + * + * Return: + * int. Valid error codes are: + * + * * LIBISCSI_OK + * + * * LIBISCSI_ERR_BUG + * + * * LIBISCSI_ERR_NOMEM + * + * * LIBISCSI_ERR_ACCESS + * + * * LIBISCSI_ERR_SYSFS_LOOKUP + * + * Error number could be converted to string by iscsi_strerror(). + */ +__DLL_EXPORT int iscsi_sessions_get(struct iscsi_context *ctx, + struct iscsi_session ***ses, + uint32_t *se_count); + +/** + * iscsi_sessions_free() - Free the memory of 'struct iscsi_session' pointer + * array + * + * Free the memory of 'iscsi_session' pointer array generated by + * 'iscsi_sessions_get()'. + * If provided 'ses' pointer is NULL or 'session_count' is 0, do nothing. + * + * @ses: + * Pointer of 'struct iscsi_session' pointer array. + * @session_count: + * uint32_t, the size of 'struct iscsi_session' pointer array. + * + * Return: + * void + */ +__DLL_EXPORT void iscsi_sessions_free(struct iscsi_session **ses, + uint32_t session_count); + +/** + * iscsi_session_get() - Retrieve specified iSCSI sessions. + * + * Retrieves specified iSCSI sessions. For the properties of + * 'struct iscsi_session', please refer to the functions defined in + * 'libopeniscsiusr_session.h' file. + * + * @ctx: + * Pointer of 'struct iscsi_context'. + * If this pointer is NULL, your program will be terminated by assert. + * @sid: + * uint32_t, iSCSI session ID. + * @se: + * Output pointer of 'struct iscsi_session' pointer. Its memory + * should be freed by iscsi_session_free(). + * If this pointer is NULL, your program will be terminated by assert. + * If specified iSCSI session does not exists, this pointer will be set to + * NULL with LIBISCSI_OK returned. + * + * Return: + * int. Valid error codes are: + * + * * LIBISCSI_OK + * + * * LIBISCSI_ERR_BUG + * + * * LIBISCSI_ERR_NOMEM + * + * * LIBISCSI_ERR_ACCESS + * + * * LIBISCSI_ERR_SYSFS_LOOKUP + * + * * LIBISCSI_ERR_SESS_NOT_FOUND + * + * Error number could be converted to string by iscsi_strerror(). + */ +__DLL_EXPORT int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid, + struct iscsi_session **se); + +/** + * iscsi_session_free() - Free the memory of 'struct iscsi_session'. + * + * Free the memory of 'iscsi_session' pointer generated by + * 'iscsi_sessions_get()'. + * If provided 'se' pointer is NULL, do nothing. + * + * @se: + * Pointer of 'struct iscsi_session' pointer. + * + * Return: + * void + */ +__DLL_EXPORT void iscsi_session_free(struct iscsi_session *se); + + #ifdef __cplusplus } /* End of extern "C" */ #endif diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h index 7952c59..b001904 100644 --- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h +++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h @@ -21,7 +21,26 @@ #ifndef _LIB_OPEN_ISCSI_USR_COMMON_H_ #define _LIB_OPEN_ISCSI_USR_COMMON_H_ +#include <errno.h> + +/* Below error numbers should align with 'open-iscsi/include/iscsi_err.h' */ #define LIBISCSI_OK 0 +/* ^ No error */ + +#define LIBISCSI_ERR_BUG 1 +/* ^ Bug of library */ + +#define LIBISCSI_ERR_SESS_NOT_FOUND 2 +/* ^ session could not be found */ + +#define LIBISCSI_ERR_NOMEM 3 +/* ^ Could not allocate resource for operation */ + +#define LIBISCSI_ERR_ACCESS 13 +/* ^ Permission denied */ + +#define LIBISCSI_ERR_SYSFS_LOOKUP 22 +/* ^ Could not lookup object in sysfs */ /* * Use the syslog severity level as log priority @@ -33,8 +52,6 @@ #define LIBISCSI_LOG_PRIORITY_DEFAULT LIBISCSI_LOG_PRIORITY_WARNING -/* TODO(Gris Ge): Documentation */ - #define __DLL_EXPORT __attribute__ ((visibility ("default"))) /* ^ Mark function or struct as external use. * Check https://gcc.gnu.org/wiki/Visibility for detail @@ -46,4 +63,6 @@ struct __DLL_EXPORT iscsi_context; +struct __DLL_EXPORT iscsi_session; + #endif /* End of _LIB_OPEN_ISCSI_USR_COMMON_H_ */ diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h new file mode 100644 index 0000000..4397258 --- /dev/null +++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2017 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 _LIB_OPEN_ISCSI_USR_SESSION_H_ +#define _LIB_OPEN_ISCSI_USR_SESSION_H_ + +#include "libopeniscsiusr_common.h" + +#include <stdint.h> + +/** + * iscsi_session_sid_get() - Retrieve iSCSI session ID of specified session. + * + * Retrieve iSCSI session ID. The session ID here is the integer used + * in '/sys/class/iscsi_session/session<session_id>/' + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * uint32_t. + */ +__DLL_EXPORT uint32_t iscsi_session_sid_get(struct iscsi_session *se); + +/** + * iscsi_session_persistent_address_get() - Retrieve iSCSI target persistent + * address of specified session + * + * Retrieve the iSCSI target persistent address of specified iSCSI session. + * The 'persistent address' is the network address where iSCSI initiator send + * initial request. When iSCSI redirection in use, this address might not be + * the network address used for actual iSCSI transaction. + * Please use `iscsi_session_address_get()` for target network address of + * iSCSI transaction. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Empty string if not supported. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_session_persistent_address_get + (struct iscsi_session *se); + +/** + * iscsi_session_persistent_port_get() - Retrieve iSCSI target persistent + * port of specified session + * + * Retrieve the iSCSI target persistent port of specified iSCSI session. + * The 'persistent port' is the network port where iSCSI initiator send + * initial request. When iSCSI redirection in use, this port might not be + * the network port used for actual iSCSI transaction. + * Please use `iscsi_session_port_get()` for target network address of + * iSCSI transaction. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * int32_t. -1 if not supported. + */ +__DLL_EXPORT int32_t iscsi_session_persistent_port_get + (struct iscsi_session *se); + +/** + * iscsi_session_target_name_get() - Retrieve iSCSI target name of specified + * session + * + * Retrieve the iSCSI target name of specified iSCSI session. + * The iSCSI Target Name specifies the worldwide unique name of the target. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_session_target_name_get + (struct iscsi_session *se); + +/** + * iscsi_session_username_get() - Retrieve authentication username of specified + * session. + * + * Retrieve the authentication username of specified iSCSI session. + * Currently open-iscsi only support CHAP authentication method. + * It's controlled this setting in iscsid.conf: + * 'node.session.auth.username' + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Empty string if not using CHAP authentication or failed + * to read authentication information. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_session_username_get(struct iscsi_session *se); + +/** + * iscsi_session_password_get() - Retrieve authentication password of specified + * session. + * + * Retrieve the authentication password of specified iSCSI session. + * Currently open-iscsi only support CHAP authentication method. + * It's controlled this setting in iscsid.conf: + * 'node.session.auth.password' + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Empty string if not using CHAP authentication or failed + * to read authentication information. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_session_password_get(struct iscsi_session *se); + +/** + * iscsi_session_username_in_get() - Retrieve authentication username of + * specified session. + * + * Retrieve the inbound authentication username of specified iSCSI session. + * Currently open-iscsi only support CHAP authentication method. + * The inbound authentication here means the iSCSI initiator authenticates the + * iSCSI target using CHAP. + * It's controlled this setting in iscsid.conf: + * 'node.session.auth.username_in' + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Empty string if not using inbound CHAP authentication or + * failed to read authentication information. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_session_username_in_get + (struct iscsi_session *se); + +/** + * iscsi_session_password_in_get() - Retrieve authentication password of + * specified session. + * + * Retrieve the inbound authentication password of specified iSCSI session. + * Currently open-iscsi only support CHAP authentication method. + * The inbound authentication here means the iSCSI initiator authenticates the + * iSCSI target using CHAP. + * It's controlled this setting in iscsid.conf: + * 'node.session.auth.password_in' + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Empty string if not using inbound CHAP authentication or + * failed to read authentication information. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_session_password_in_get + (struct iscsi_session *se); + +/** + * iscsi_session_recovery_tmo_get() - Retrieve recovery timeout value of + * specified session + * + * Retrieve the recovery timeout value of specified iSCSI session. + * The recovery timeout here means the seconds of time to wait for session + * re-establishment before failing SCSI commands back to the application when + * running the Linux SCSI Layer error handler. + * It could be controlled via this setting in iscsid.conf: + * 'node.session.timeo.replacement_timeout'. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * int32_t. If the value is 0, IO will be failed immediately. If the value + * is less than 0, IO will remain queued until the session is logged back + * in, or until the user runs the logout command. + */ +__DLL_EXPORT int32_t iscsi_session_recovery_tmo_get(struct iscsi_session *se); + +/** + * iscsi_session_lu_reset_tmo_get() - Retrieve logical unit timeout value of + * specified session + * + * Retrieve the logical unit timeout value of specified iSCSI session. + * The logical unit timeout here means the seconds of time to wait for a logical + * unit response before before failing the operation and trying session + * re-establishment. + * It could be controlled via this setting in iscsid.conf: + * 'node.session.err_timeo.lu_reset_timeout' + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * int32_t. -1 if not supported. + */ +__DLL_EXPORT int32_t iscsi_session_lu_reset_tmo_get(struct iscsi_session *se); + +/** + * iscsi_session_tgt_reset_tmo_get() - Retrieve target response timeout value of + * of specified session + * + * Retrieve the target response timeout value of specified iSCSI session. + * The target response timeout here means the seconds of time to wait for a + * target response before before failing the operation and trying session + * re-establishment. + * It could be controlled via this setting in iscsid.conf: + * 'node.session.err_timeo.tgt_reset_timeout'. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * int32_t. -1 if not supported. + */ +__DLL_EXPORT int32_t iscsi_session_tgt_reset_tmo_get(struct iscsi_session *se); + +/** + * iscsi_session_abort_tmo_get() - Retrieve abort response timeout value of + * specified session + * + * Retrieve the abort response timeout value of specified iSCSI session. + * The abort response timeout here means the seconds of time to wait for a + * abort response before before failing the operation and trying session + * re-establishment. + * It could be controlled via this setting in iscsid.conf: + * 'node.session.err_timeo.abort_timeout'. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * int32_t. -1 if not supported. + */ +__DLL_EXPORT int32_t iscsi_session_abort_tmo_get(struct iscsi_session *se); + +/** + * iscsi_session_tpgt_get() - Retrieve target portal group tag of specified + * session + * + * Retrieve the target portal group tag of specified iSCSI session. + * + * The target portal group tag is a value that uniquely identifies a portal + * group within an iSCSI target node. This key carries the value of the tag of + * the portal group that is servicing the Login request. The iSCSI target + * returns this key to the initiator in the Login Response PDU to the first + * Login Request PDU that has the C bit set to 0 when TargetName is given by the + * initiator. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * int32_t. -1 if not supported. + */ +__DLL_EXPORT int32_t iscsi_session_tpgt_get(struct iscsi_session *se); + +/** + * iscsi_session_address_get() - Retrieve iSCSI target address of specified + * session + * + * Retrieve the iSCSI target network address of specified iSCSI session. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Empty string if not supported. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_session_address_get + (struct iscsi_session *se); + +/** + * iscsi_session_port_get() - Retrieve iSCSI target port of specified session + * + * Retrieve the iSCSI target port of specified iSCSI session. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * int32_t. -1 if not supported. + */ +__DLL_EXPORT int32_t iscsi_session_port_get(struct iscsi_session *se); + +#endif /* End of _LIB_OPEN_ISCSI_USR_SESSION_H_ */ diff --git a/libopeniscsiusr/misc.c b/libopeniscsiusr/misc.c index 94d1f23..93db919 100644 --- a/libopeniscsiusr/misc.c +++ b/libopeniscsiusr/misc.c @@ -23,6 +23,7 @@ #include <errno.h> #include <dirent.h> #include <string.h> +#include <unistd.h> #include "libopeniscsiusr/libopeniscsiusr.h" #include "misc.h" @@ -46,7 +47,7 @@ const char *func_name(var_type var) { \ size_t i = 0; \ uint32_t tmp_var = var & UINT32_MAX; \ errno = 0; \ - /* In the whole libiscsi, we don't have negative value */ \ + /* In the whole libopeniscsiusr, we don't have negative value */ \ for (; i < sizeof(conv_array)/sizeof(conv_array[0]); ++i) { \ if ((conv_array[i].value) == tmp_var) \ return conv_array[i].str; \ @@ -57,6 +58,11 @@ const char *func_name(var_type var) { \ static const struct _num_str_conv _ISCSI_RC_MSG_CONV[] = { {LIBISCSI_OK, "OK"}, + {LIBISCSI_ERR_BUG, "BUG of libopeniscsiusr library"}, + {LIBISCSI_ERR_SESS_NOT_FOUND, "Specified iSCSI session not found"}, + {LIBISCSI_ERR_ACCESS, "Permission deny"}, + {LIBISCSI_ERR_NOMEM, "Out of memory"}, + {LIBISCSI_ERR_SYSFS_LOOKUP, "Could not lookup object in sysfs"}, }; _iscsi_str_func_gen(iscsi_strerror, int, rc, _ISCSI_RC_MSG_CONV); @@ -103,3 +109,16 @@ void _iscsi_log(struct iscsi_context *ctx, int priority, const char *file, ctx->log_func(ctx, priority, file, line, func_name, format, args); va_end(args); } + +int _scan_filter_skip_dot(const struct dirent *dir) +{ + return strcmp(dir->d_name, ".") && strcmp(dir->d_name, ".."); +} + +bool _file_exists(const char *path) +{ + if (access(path, F_OK) == 0) + return true; + else + return false; +} diff --git a/libopeniscsiusr/misc.h b/libopeniscsiusr/misc.h index 441b885..1c5d696 100644 --- a/libopeniscsiusr/misc.h +++ b/libopeniscsiusr/misc.h @@ -20,12 +20,12 @@ #define __ISCSI_USR_MISC_H__ #include <stdint.h> -#include <string.h> +#include <stdbool.h> +#include <assert.h> #include <stdarg.h> -#include <stdlib.h> #include <dirent.h> -#include "libopeniscsiusr/libopeniscsiusr_common.h" +#include "libopeniscsiusr/libopeniscsiusr.h" #define _good(rc, rc_val, out) \ do { \ @@ -66,4 +66,21 @@ __DLL_LOCAL void _iscsi_log_stderr(struct iscsi_context *ctx, int priority, return d->prop_name; \ } +/* + * Check pointer returned by malloc() or strdup() or calloc(), if NULL, set + * rc as LIBISCSI_ERR_NO_MEMORY, report error and goto goto_out. + */ +#define _alloc_null_check(ctx, ptr, rc, goto_out) \ + do { \ + if (ptr == NULL) { \ + rc = LIBISCSI_ERR_NOMEM; \ + _error(ctx, iscsi_strerror(rc)); \ + goto goto_out; \ + } \ + } while(0) + +__DLL_LOCAL int _scan_filter_skip_dot(const struct dirent *dir); + +__DLL_LOCAL bool _file_exists(const char *path); + #endif /* End of __ISCSI_USR_MISC_H__ */ diff --git a/libopeniscsiusr/session.c b/libopeniscsiusr/session.c new file mode 100644 index 0000000..b7b39b2 --- /dev/null +++ b/libopeniscsiusr/session.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2017 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 NI_MAXHOST */ +#endif + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <dirent.h> +#include <limits.h> +#include <stdint.h> +#include <inttypes.h> +#include <netdb.h> +#include <string.h> +#include <errno.h> + +#include "libopeniscsiusr/libopeniscsiusr.h" +#include "misc.h" +#include "sysfs.h" + +#define _ISCSI_NAME_MAX_LEN 223 +/* ^ RFC 3720: + * Each iSCSI node, whether an initiator or target, MUST have an iSCSI + * name. + * + * Initiators and targets MUST support the receipt of iSCSI names of up + * to the maximum length of 223 bytes. + */ + +#define _ISCSI_CHAP_AUTH_STR_MAX_LEN 256 +/* ^ No official document found for this value, just copy from usr/auth.h + */ + +struct iscsi_session { + uint32_t sid; + /* ^ It's actually a int according to Linux kernel code but + * the dev_set_name() in iscsi_add_session() of scsi_transport_iscsi.c + * are using %u to output this. + */ + char persistent_address[NI_MAXHOST + 1]; + int32_t persistent_port; + char target_name[_ISCSI_NAME_MAX_LEN + 1]; + char username[_ISCSI_CHAP_AUTH_STR_MAX_LEN]; + char password[_ISCSI_CHAP_AUTH_STR_MAX_LEN]; + char username_in[_ISCSI_CHAP_AUTH_STR_MAX_LEN]; + char password_in[_ISCSI_CHAP_AUTH_STR_MAX_LEN]; + int32_t recovery_tmo; + /* ^ It's actually a int according to Linux kernel code. + */ + int32_t lu_reset_tmo; + /* ^ It's actually a int according to Linux kernel code. + */ + int32_t tgt_reset_tmo; + /* ^ It's actually a int according to Linux kernel code. + */ + int32_t abort_tmo; + /* ^ It's actually a int according to Linux kernel code. + */ + int32_t tpgt; + /* ^ It's actually a int according to Linux kernel code. + */ + char address[NI_MAXHOST + 1]; + + int32_t port; +}; + +static uint32_t session_str_to_sid(const char *session_str); + +_iscsi_getter_func_gen(iscsi_session, sid, uint32_t); +_iscsi_getter_func_gen(iscsi_session, persistent_address, const char *); +_iscsi_getter_func_gen(iscsi_session, persistent_port, int32_t); +_iscsi_getter_func_gen(iscsi_session, target_name, const char *); +_iscsi_getter_func_gen(iscsi_session, username, const char *); +_iscsi_getter_func_gen(iscsi_session, password, const char *); +_iscsi_getter_func_gen(iscsi_session, username_in, const char *); +_iscsi_getter_func_gen(iscsi_session, password_in, const char *); +_iscsi_getter_func_gen(iscsi_session, recovery_tmo, int32_t); +_iscsi_getter_func_gen(iscsi_session, lu_reset_tmo, int32_t); +_iscsi_getter_func_gen(iscsi_session, tgt_reset_tmo, int32_t); +_iscsi_getter_func_gen(iscsi_session, abort_tmo, int32_t); +_iscsi_getter_func_gen(iscsi_session, tpgt, int32_t); +_iscsi_getter_func_gen(iscsi_session, address, const char *); +_iscsi_getter_func_gen(iscsi_session, port, int32_t); + +/* + * The session string is "session%u" used by /sys/class/iscsi_session/session%u. + * Return 0 if error parsing session string. + */ +static uint32_t session_str_to_sid(const char *session_str) +{ + uint32_t sid = 0; + + if (sscanf(session_str, "session%" SCNu32, &sid) != 1) + return 0; /* error */ + return sid; +} + +int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid, + struct iscsi_session **se) +{ + int rc = LIBISCSI_OK; + char sysfs_se_dir_path[PATH_MAX]; + char sysfs_con_dir_path[PATH_MAX]; + + assert(ctx != NULL); + assert(se != NULL); + + _debug(ctx, "Querying iSCSI session for sid %" PRIu32, sid); + + snprintf(sysfs_se_dir_path, PATH_MAX, "%s/session%" PRIu32, + _ISCSI_SYS_SESSION_DIR, sid); + snprintf(sysfs_con_dir_path, PATH_MAX, "%s/connection%" PRIu32 ":0", + _ISCSI_SYS_CONNECTION_DIR, sid); + /* ^ BUG(Gris Ge): ':0' here in kernel is referred as connection id. + * but the open-iscsi assuming it's always 0, need + * investigation. + */ + + *se = (struct iscsi_session *) + calloc(sizeof(struct iscsi_session), 1); + _alloc_null_check(ctx, *se , rc, out); + + if (! _file_exists(sysfs_se_dir_path)) { + _info(ctx, "Sysfs path '%s' does not exists", + sysfs_se_dir_path); + rc = LIBISCSI_ERR_SESS_NOT_FOUND; + } + if (! _file_exists(sysfs_con_dir_path)) { + _info(ctx, "Sysfs path '%s' does not exists", + sysfs_se_dir_path); + rc = LIBISCSI_ERR_SESS_NOT_FOUND; + } + if (rc == LIBISCSI_ERR_SESS_NOT_FOUND) { + _error(ctx, "Specified SID %" PRIu32, "does not exists", + sid); + goto out; + } + + (*se)->sid = sid; + _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "targetname", + (*se)->target_name, + sizeof((*se)->target_name) / sizeof(char), + NULL), rc, out); + + _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "username", + (*se)->username, + sizeof((*se)->username) / sizeof(char), + ""), + rc, out); + + _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "password", + (*se)->password, + sizeof((*se)->password) / sizeof(char), + ""), + rc, out); + + _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "username_in", + (*se)->username_in, + sizeof((*se)->username_in) / sizeof(char), + ""), + rc, out); + + _good(_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "password_in", + (*se)->password_in, + sizeof((*se)->password_in) / sizeof(char), + ""), + rc, out); + + _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "recovery_tmo", + &((*se)->recovery_tmo), + -1), + rc, out); + + _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "lu_reset_tmo", + &((*se)->lu_reset_tmo), -1), + rc, out); + + _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, + "tgt_reset_tmo", &((*se)->tgt_reset_tmo), -1), + rc, out); + + _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "abort_tmo", + &((*se)->abort_tmo), -1), + rc, out); + + _good(_sysfs_prop_get_i32(ctx, sysfs_se_dir_path, "tpgt", + &((*se)->tpgt), + INT32_MAX /* raise error if not found */), + rc, out); + + _good(_sysfs_prop_get_str(ctx, sysfs_con_dir_path, "persistent_address", + (*se)->persistent_address, + sizeof((*se)->persistent_address) / + sizeof(char), ""), + rc, out); + + _good(_sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "persistent_port", + &((*se)->persistent_port), -1), + rc, out); + + _good(_sysfs_prop_get_str(ctx, sysfs_con_dir_path, "address", + (*se)->address, + sizeof((*se)->address) / sizeof(char), + ""), + rc, out); + + _good(_sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "port", + &((*se)->port), -1), rc, out); + + if ((strcmp((*se)->address, "") == 0) && + (strcmp((*se)->persistent_address, "") != 0)) + strncpy((*se)->persistent_address, (*se)->address, + sizeof((*se)->persistent_address) / sizeof(char)); + + if ((strcmp((*se)->address, "") != 0) && + (strcmp((*se)->persistent_address, "") == 0)) + strncpy((*se)->address, (*se)->persistent_address, + sizeof((*se)->address) / sizeof(char)); + + if (((*se)->persistent_port != -1) && + ((*se)->port == -1)) + (*se)->persistent_port = (*se)->port; + + if (((*se)->persistent_port != -1) && + ((*se)->port == -1)) + (*se)->port = (*se)->persistent_port; + +out: + if (rc != LIBISCSI_OK) { + iscsi_session_free(*se); + *se = NULL; + } + return rc; +} + +int iscsi_sessions_get(struct iscsi_context *ctx, + struct iscsi_session ***sessions, + uint32_t *session_count) +{ + struct dirent **namelist = NULL; + int n = 0; + int rc = LIBISCSI_OK; + int errno_save = 0; + uint32_t i = 0; + uint32_t sid = 0; + int j = 0; + + assert(ctx != NULL); + assert(sessions != NULL); + assert(session_count != NULL); + + *sessions = NULL; + *session_count = 0; + + n = scandir(_ISCSI_SYS_SESSION_DIR, &namelist, _scan_filter_skip_dot, + alphasort); + if (n < 0) { + errno_save = errno; + if (errno_save == ENOENT) + goto out; + if (errno_save == ENOMEM) { + rc = LIBISCSI_ERR_NOMEM; + goto out; + } + if (errno_save == ENOTDIR) { + rc = LIBISCSI_ERR_BUG; + _error(ctx, "Got ENOTDIR error when scandir %s", + _ISCSI_SYS_SESSION_DIR); + goto out; + } + rc = LIBISCSI_ERR_BUG; + _error(ctx, "Got unexpected error %d when scandir %s", + errno_save, _ISCSI_SYS_SESSION_DIR); + goto out; + } + _info(ctx, "Got %d iSCSI sessions", n); + *sessions = (struct iscsi_session **) + calloc (sizeof(struct iscsi_session *), n); + _alloc_null_check(ctx, *sessions, rc, out); + + *session_count = n & UINT32_MAX; + + for (i = 0; i < *session_count; ++i) { + sid = session_str_to_sid(namelist[i]->d_name); + if (sid == 0) { + _error(ctx, "Got illegal iscsi session string %s", + namelist[i]->d_name); + rc = LIBISCSI_ERR_BUG; + goto out; + } + _good(iscsi_session_get(ctx, sid, &((*sessions)[i])), rc, out); + } + +out: + for (j = n - 1; j >= 0; --j) + free(namelist[j]); + free(namelist); + if (rc != LIBISCSI_OK) { + iscsi_sessions_free(*sessions, *session_count); + *sessions = NULL; + *session_count = 0; + } + return rc; +} + +void iscsi_session_free(struct iscsi_session *se) +{ + free(se); +} + +void iscsi_sessions_free(struct iscsi_session **ses, uint32_t se_count) +{ + uint32_t i = 0; + + if (ses == NULL) + return; + + for (i = 0; i < se_count; ++i) + iscsi_session_free(ses[i]); + free (ses); +} diff --git a/libopeniscsiusr/sysfs.c b/libopeniscsiusr/sysfs.c new file mode 100644 index 0000000..c1aa576 --- /dev/null +++ b/libopeniscsiusr/sysfs.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2017 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> + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <assert.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <inttypes.h> +#include <regex.h> +#include <dirent.h> +#include <errno.h> + +#include "libopeniscsiusr/libopeniscsiusr_common.h" +#include "sysfs.h" +#include "misc.h" + +#define _INT32_STR_MAX_LEN 12 +/* ^ The max uint32_t is 4294967296 which requires 11 bytes for string. + * The max/min in32_t is 2147483647 or -2147483646 which requires 12 bytes. + */ + +#define _SYS_NULL_STR "(null)" + +static int sysfs_read_file(const char *path, uint8_t *buff, size_t buff_size); +static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx, + const char *dir_path, const char *prop_name, + long long int *val, + long long int default_value); +/* + * dev_path should be char[PATH_MAX]. + */ +static int sysfs_read_file(const char *path, uint8_t *buff, size_t buff_size) +{ + int fd = -1; + int errno_save = 0; + ssize_t readed = 0; + ssize_t i = 0; + + assert(path != NULL); + assert(buff != NULL); + assert(buff_size != 0); + + memset(buff, 0, buff_size); + + fd = open(path, O_RDONLY); + if (fd < 0) + return errno; + readed = read(fd, buff, buff_size); + errno_save = errno; + close(fd); + + if (readed < 0) { + buff[0] = '\0'; + return errno_save; + } + + buff[buff_size - 1] = '\0'; + /* Remove the trailing \n */ + for (i = readed - 1; i >= 0; --i) { + if (buff[i] == '\n') { + buff[i] = '\0'; + break; + } + } + + if (strcmp((char *) buff, _SYS_NULL_STR) == 0) + buff[0] = '\0'; + + return 0; +} + +int _sysfs_prop_get_str(struct iscsi_context *ctx, const char *dir_path, + const char *prop_name, char *buff, size_t buff_size, + const char *default_value) +{ + char file_path[PATH_MAX]; + int rc = LIBISCSI_OK; + int errno_save = 0; + + assert(dir_path != NULL); + assert(prop_name != NULL); + assert(buff != NULL); + + snprintf(file_path, PATH_MAX, "%s/%s", dir_path, prop_name); + + errno_save = sysfs_read_file(file_path, (uint8_t *) buff, buff_size); + if (errno_save != 0) { + if (errno_save == ENOENT) { + if (default_value == NULL) { + rc = LIBISCSI_ERR_SYSFS_LOOKUP; + _error(ctx, "Failed to read '%s': " + "file '%s' does not exists", prop_name, + file_path); + } else { + _info(ctx, "Failed to read '%s': " + "file '%s' does not exists, " + "using default value %s", prop_name, + file_path, default_value); + memcpy(buff, (void *) default_value, + strlen(default_value) + 1); + } + } else if (errno_save == EACCES) { + rc = LIBISCSI_ERR_ACCESS; + _error(ctx, "Failed to read '%s': " + "permission deny when reading '%s'", prop_name, + file_path); + } else { + rc = LIBISCSI_ERR_BUG; + _error(ctx, "Failed to read '%s': " + "error when reading '%s': %d", prop_name, + file_path, errno_save); + } + } else { + _debug(ctx, "Open '%s', got '%s'", file_path, buff); + } + return rc; +} + +static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx, + const char *dir_path, const char *prop_name, + long long int *val, + long long int default_value) +{ + char file_path[PATH_MAX]; + int rc = LIBISCSI_OK; + int errno_save = 0; + uint8_t buff[_INT32_STR_MAX_LEN]; + long long int tmp_val = 0; + + assert(dir_path != NULL); + assert(prop_name != NULL); + assert(val != NULL); + + *val = 0; + + snprintf(file_path, PATH_MAX, "%s/%s", dir_path, prop_name); + + errno_save = sysfs_read_file(file_path, buff, _INT32_STR_MAX_LEN); + if (errno_save != 0) { + if (errno_save == ENOENT) { + if (default_value == LLONG_MAX) { + rc = LIBISCSI_ERR_SYSFS_LOOKUP; + _error(ctx, "Failed to read '%s': " + "file '%s' does not exists", + prop_name, file_path); + return rc; + } else { + _info(ctx, + "Failed to read '%s': " + "File '%s' does not exists, using ", + "default value %lld", + file_path, default_value); + *val = default_value; + return rc; + } + } else if (errno_save == EACCES) { + rc = LIBISCSI_ERR_ACCESS; + _error(ctx, "Permission deny when reading '%s'", + file_path); + return rc; + } else { + rc = LIBISCSI_ERR_BUG; + _error(ctx, "Error when reading '%s': %d", file_path, + errno_save); + return rc; + } + } + + tmp_val = strtoll((const char *) buff, NULL, 10 /* base */); + errno_save = errno; + if ((errno_save != 0) && (tmp_val == LONG_MAX)) { + rc = LIBISCSI_ERR_BUG; + _error(ctx, "Sysfs: %s: Error when converting '%s' " + "to number", file_path, (char *) buff, errno_save); + return rc; + } + + *val = tmp_val; + + _debug(ctx, "Open '%s', got %lld", file_path, tmp_val); + + return rc; +} + +int _sysfs_prop_get_u32(struct iscsi_context *ctx, const char *dir_path, + const char *prop_name, uint32_t *val, + uint32_t default_value) +{ + long long int tmp_val = 0; + int rc = LIBISCSI_OK; + long long int dv = default_value; + + if (default_value == UINT32_MAX) + dv = LLONG_MAX; + + rc = iscsi_sysfs_prop_get_ll(ctx, dir_path, prop_name, &tmp_val, + (long long int) dv); + if (rc == LIBISCSI_OK) + *val = tmp_val & UINT32_MAX; + return rc; +} + +int _sysfs_prop_get_i32(struct iscsi_context *ctx, const char *dir_path, + const char *prop_name, int32_t *val, + int32_t default_value) +{ + long long int tmp_val = 0; + int rc = LIBISCSI_OK; + long long int dv = default_value; + + if (default_value == INT32_MAX) + dv = LLONG_MAX; + + rc = iscsi_sysfs_prop_get_ll(ctx, dir_path, prop_name, &tmp_val, + (long long int) dv); + + if (rc == LIBISCSI_OK) + *val = tmp_val & INT32_MAX; + return rc; +} diff --git a/libopeniscsiusr/sysfs.h b/libopeniscsiusr/sysfs.h new file mode 100644 index 0000000..835c0fe --- /dev/null +++ b/libopeniscsiusr/sysfs.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017 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 __ISCSI_USR_SYSFS_H__ +#define __ISCSI_USR_SYSFS_H__ + +#include <stdint.h> + +#include "libopeniscsiusr/libopeniscsiusr_common.h" + +#define _ISCSI_SYS_SESSION_DIR "/sys/class/iscsi_session" +#define _ISCSI_SYS_CONNECTION_DIR "/sys/class/iscsi_connection" + +/* + * When default_value == NULL, treat no such file as LIB_BUG. + */ +__DLL_LOCAL int _sysfs_prop_get_str(struct iscsi_context *ctx, + const char *dir_path, const char *prop_name, + char *buff, size_t buff_size, + const char *default_value); + +/* + * When default_value == UINT32_MAX, treat no such file as LIB_BUG. + */ +__DLL_LOCAL int _sysfs_prop_get_u32(struct iscsi_context *ctx, + const char *dir_path, const char *prop_name, + uint32_t *val, uint32_t default_value); + +/* + * When default_value == INT32_MAX, treat no such file as LIB_BUG. + */ +__DLL_LOCAL int _sysfs_prop_get_i32(struct iscsi_context *ctx, + const char *dir_path, const char *prop_name, + int32_t *val, int32_t default_value); + +#endif /* End of __ISCSI_USR_SYSFS_H__ */ diff --git a/libopeniscsiusr/tests/test_session.c b/libopeniscsiusr/tests/test_session.c new file mode 100644 index 0000000..f7abc03 --- /dev/null +++ b/libopeniscsiusr/tests/test_session.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 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> + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> +#include <assert.h> + +#include <libopeniscsiusr/libopeniscsiusr.h> + +#define _assert_print_prop_str_can_empty(struct_name, obj, prop_name) \ + do { \ + assert(struct_name##_##prop_name##_get(obj) != NULL); \ + printf("\t" # prop_name ": '%s'\n", \ + struct_name##_##prop_name##_get(obj)); \ + } while(0) + +#define _assert_print_prop_str_not_empty(struct_name, obj, prop_name) \ + do { \ + assert(struct_name##_##prop_name##_get(obj) != NULL); \ + assert(strlen(struct_name##_##prop_name##_get(obj)) != 0); \ + printf("\t" # prop_name ": '%s'\n", \ + struct_name##_##prop_name##_get(obj)); \ + } while(0) + +#define _assert_print_prop_u32_not_zero(struct_name, obj, prop_name) \ + do { \ + assert(struct_name##_##prop_name##_get(obj) != 0); \ + printf("\t" # prop_name ": %" PRIu32 "\n", \ + struct_name##_##prop_name##_get(obj)); \ + } while(0) + +#define _assert_print_prop_i32_not_zero(struct_name, obj, prop_name) \ + do { \ + assert(struct_name##_##prop_name##_get(obj) != 0); \ + printf("\t" # prop_name ": %" PRIi32 "\n", \ + struct_name##_##prop_name##_get(obj)); \ + } while(0) + +static void test_session(struct iscsi_session *se); + +static void test_session(struct iscsi_session *se) +{ + assert(se != NULL); + printf("Session %" PRIu32 ":\n", iscsi_session_sid_get(se)); + + _assert_print_prop_u32_not_zero(iscsi_session, se, sid); + _assert_print_prop_str_not_empty(iscsi_session, se, persistent_address); + _assert_print_prop_i32_not_zero(iscsi_session, se, persistent_port); + _assert_print_prop_str_not_empty(iscsi_session, se, target_name); + _assert_print_prop_str_can_empty(iscsi_session, se, username); + _assert_print_prop_str_can_empty(iscsi_session, se, password); + _assert_print_prop_str_can_empty(iscsi_session, se, username_in); + _assert_print_prop_str_can_empty(iscsi_session, se, password_in); + _assert_print_prop_u32_not_zero(iscsi_session, se, recovery_tmo); + _assert_print_prop_u32_not_zero(iscsi_session, se, lu_reset_tmo); + _assert_print_prop_u32_not_zero(iscsi_session, se, tgt_reset_tmo); + _assert_print_prop_u32_not_zero(iscsi_session, se, abort_tmo); + _assert_print_prop_u32_not_zero(iscsi_session, se, tpgt); + _assert_print_prop_str_not_empty(iscsi_session, se, address); + _assert_print_prop_i32_not_zero(iscsi_session, se, port); +} + +int main() +{ + struct iscsi_context *ctx = NULL; + struct iscsi_session **ses = NULL; + uint32_t se_count = 0; + uint32_t i = 0; + int rc = EXIT_SUCCESS; + + ctx = iscsi_context_new(); + iscsi_context_log_priority_set(ctx, LIBISCSI_LOG_PRIORITY_DEBUG); + + if (iscsi_sessions_get(ctx, &ses, &se_count) != LIBISCSI_OK) { + printf("FAILED\n"); + rc = EXIT_FAILURE; + } else { + printf("\nGot %" PRIu32 " iSCSI sessions\n", se_count); + for (i = 0; i < se_count; ++i) { + test_session(ses[i]); + } + iscsi_sessions_free(ses, se_count); + } + iscsi_context_free(ctx); + exit(rc); +} |