Blame libopeniscsiusr/sysfs.c

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
Packit eace71
#ifndef _GNU_SOURCE
Packit eace71
#define _GNU_SOURCE
Packit eace71
#endif
Packit eace71
Packit eace71
#include <stdint.h>
Packit eace71
#include <stdlib.h>
Packit eace71
#include <stdio.h>
Packit eace71
#include <string.h>
Packit eace71
#include <limits.h>
Packit eace71
#include <assert.h>
Packit eace71
#include <sys/stat.h>
Packit eace71
#include <sys/types.h>
Packit eace71
#include <fcntl.h>
Packit eace71
#include <unistd.h>
Packit eace71
#include <inttypes.h>
Packit eace71
#include <regex.h>
Packit eace71
#include <dirent.h>
Packit eace71
#include <errno.h>
Packit eace71
Packit eace71
#include "libopeniscsiusr/libopeniscsiusr_common.h"
Packit eace71
#include "sysfs.h"
Packit eace71
#include "misc.h"
Packit eace71
Packit eace71
#define _INT32_STR_MAX_LEN		12
Packit eace71
/* ^ The max uint32_t is 4294967296 which requires 11 bytes for string.
Packit eace71
 *   The max/min in32_t is 2147483647 or -2147483646 which requires 12 bytes.
Packit eace71
 */
Packit eace71
Packit eace71
#define _SYS_NULL_STR			"(null)"
Packit eace71
Packit eace71
#define _sysfs_prop_get_uint_func_gen(func_name, out_type, type_max_value) \
Packit eace71
	int func_name(struct iscsi_context *ctx, const char *dir_path, \
Packit eace71
		      const char *prop_name, out_type *val, \
Packit eace71
		      out_type default_value, bool ignore_error) \
Packit eace71
	{ \
Packit eace71
		long long int tmp_val = 0; \
Packit eace71
		int rc = LIBISCSI_OK; \
Packit eace71
		long long int dv = default_value; \
Packit eace71
		rc = iscsi_sysfs_prop_get_ll(ctx, dir_path, prop_name, \
Packit eace71
					     &tmp_val, (long long int) dv, \
Packit eace71
					     ignore_error); \
Packit eace71
		if (rc == LIBISCSI_OK) \
Packit eace71
			*val = tmp_val & type_max_value; \
Packit eace71
		return rc; \
Packit eace71
	}
Packit eace71
Packit eace71
#define _sysfs_prop_get_int_func_gen(func_name, out_type, type_min_value, type_max_value) \
Packit eace71
	int func_name(struct iscsi_context *ctx, const char *dir_path, \
Packit eace71
		      const char *prop_name, out_type *val, \
Packit eace71
		      out_type default_value, bool ignore_error) \
Packit eace71
	{ \
Packit eace71
		long long int tmp_val = 0; \
Packit eace71
		int rc = LIBISCSI_OK; \
Packit eace71
		long long int dv = default_value; \
Packit eace71
		rc = iscsi_sysfs_prop_get_ll(ctx, dir_path, prop_name, \
Packit eace71
					     &tmp_val, (long long int) dv, \
Packit eace71
					     ignore_error); \
Packit eace71
		if (rc == LIBISCSI_OK) { \
Packit eace71
			if (tmp_val > type_max_value) \
Packit eace71
				*val = type_max_value; \
Packit eace71
			else if (tmp_val < type_min_value) \
Packit eace71
				*val = type_min_value; \
Packit eace71
			else \
Packit eace71
				*val = tmp_val; \
Packit eace71
		} \
Packit eace71
		return rc; \
Packit eace71
	}
Packit eace71
Packit eace71
Packit eace71
enum _sysfs_dev_class {
Packit eace71
	_SYSFS_DEV_CLASS_ISCSI_SESSION,
Packit eace71
	_SYSFS_DEV_CLASS_ISCSI_HOST,
Packit eace71
};
Packit eace71
Packit eace71
static int sysfs_read_file(const char *path, uint8_t *buff, size_t buff_size);
Packit eace71
static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx,
Packit eace71
				   const char *dir_path, const char *prop_name,
Packit eace71
				   long long int *val,
Packit eace71
				   long long int default_value,
Packit eace71
				   bool ignore_error);
Packit eace71
Packit eace71
/*
Packit eace71
 * dev_path needs to be freed by the caller on success
Packit eace71
 */
Packit eace71
static int sysfs_get_dev_path(struct iscsi_context *ctx, const char *path,
Packit eace71
			      enum _sysfs_dev_class class, char **dev_path);
Packit eace71
Packit eace71
_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u8, uint8_t, UINT8_MAX);
Packit eace71
_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u16, uint16_t, UINT16_MAX);
Packit eace71
_sysfs_prop_get_int_func_gen(_sysfs_prop_get_i32, int32_t, INT32_MIN, INT32_MAX);
Packit eace71
_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u32, uint32_t, UINT32_MAX);
Packit eace71
Packit eace71
static int sysfs_read_file(const char *path, uint8_t *buff, size_t buff_size)
Packit eace71
{
Packit eace71
	int fd = -1;
Packit eace71
	int errno_save = 0;
Packit eace71
	ssize_t readed = 0;
Packit eace71
	ssize_t i = 0;
Packit eace71
Packit eace71
	assert(path != NULL);
Packit eace71
	assert(buff != NULL);
Packit eace71
	assert(buff_size != 0);
Packit eace71
Packit eace71
	memset(buff, 0, buff_size);
Packit eace71
Packit eace71
	fd = open(path, O_RDONLY);
Packit eace71
	if (fd < 0)
Packit eace71
		return errno;
Packit eace71
	readed = read(fd, buff, buff_size);
Packit eace71
	errno_save = errno;
Packit eace71
	close(fd);
Packit eace71
Packit eace71
	if (readed < 0) {
Packit eace71
		buff[0] = '\0';
Packit eace71
		return errno_save;
Packit eace71
	}
Packit eace71
Packit eace71
	buff[buff_size - 1] = '\0';
Packit eace71
	/* Remove the trailing \n */
Packit eace71
	for (i = readed - 1; i >= 0; --i) {
Packit eace71
		if (buff[i] == '\n') {
Packit eace71
			buff[i] = '\0';
Packit eace71
			break;
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (strcmp((char *) buff, _SYS_NULL_STR) == 0)
Packit eace71
		buff[0] = '\0';
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
int _sysfs_prop_get_str(struct iscsi_context *ctx, const char *dir_path,
Packit eace71
			const char *prop_name, char *buff, size_t buff_size,
Packit eace71
			const char *default_value)
Packit eace71
{
Packit eace71
	char *file_path = NULL;
Packit eace71
	int rc = LIBISCSI_OK;
Packit eace71
	int errno_save = 0;
Packit eace71
Packit eace71
	assert(dir_path != NULL);
Packit eace71
	assert(prop_name != NULL);
Packit eace71
	assert(buff != NULL);
Packit eace71
Packit eace71
	_good(_asprintf(&file_path, "%s/%s", dir_path, prop_name), rc, out);
Packit eace71
Packit eace71
	errno_save = sysfs_read_file(file_path, (uint8_t *) buff, buff_size);
Packit eace71
	if (errno_save != 0) {
Packit eace71
		if (errno_save == ENOENT) {
Packit eace71
			if (default_value == NULL) {
Packit eace71
				rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
				_error(ctx, "Failed to read '%s': "
Packit eace71
				       "file '%s' does not exists", prop_name,
Packit eace71
				       file_path);
Packit eace71
			} else {
Packit eace71
				_info(ctx, "Failed to read '%s': "
Packit eace71
				      "file '%s' does not exists, "
Packit eace71
				      "using default value %s", prop_name,
Packit eace71
				      file_path, default_value);
Packit eace71
				memcpy(buff, (void *) default_value,
Packit eace71
				       strlen(default_value) + 1);
Packit eace71
			}
Packit eace71
		} else if (errno_save == EACCES) {
Packit eace71
			rc = LIBISCSI_ERR_ACCESS;
Packit eace71
			_error(ctx, "Failed to read '%s': "
Packit eace71
			       "permission deny when reading '%s'", prop_name,
Packit eace71
			       file_path);
Packit eace71
		} else if (errno_save == ENOTCONN) {
Packit eace71
			if (default_value == NULL) {
Packit eace71
				rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
				_error(ctx, "Failed to read '%s': "
Packit eace71
				       "error when reading '%s': "
Packit eace71
				       "Target unavailable",
Packit eace71
				       prop_name, file_path);
Packit eace71
			} else {
Packit eace71
				_info(ctx, "Failed to read '%s': "
Packit eace71
				       "error when reading '%s': "
Packit eace71
				       "Target unavailable, using default value '%s'",
Packit eace71
				       prop_name, file_path, default_value);
Packit eace71
				memcpy(buff, (void *) default_value,
Packit eace71
				       strlen(default_value) + 1);
Packit eace71
			}
Packit eace71
		} else {
Packit eace71
			rc = LIBISCSI_ERR_BUG;
Packit eace71
			_error(ctx, "Failed to read '%s': "
Packit eace71
			       "error when reading '%s': %d", prop_name,
Packit eace71
			       file_path, errno_save);
Packit eace71
		}
Packit eace71
	} else {
Packit eace71
		if ((buff[0] == '\0') && (default_value != NULL)) {
Packit eace71
			memcpy(buff, (void *) default_value,
Packit eace71
			       strlen(default_value) + 1);
Packit eace71
			_debug(ctx, "Open '%s', got NULL, using default value",
Packit eace71
			       file_path, default_value);
Packit eace71
		} else
Packit eace71
			_debug(ctx, "Open '%s', got '%s'", file_path, buff);
Packit eace71
	}
Packit eace71
out:
Packit eace71
	free(file_path);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx,
Packit eace71
				 const char *dir_path, const char *prop_name,
Packit eace71
				 long long int *val,
Packit eace71
				 long long int default_value, bool ignore_error)
Packit eace71
{
Packit eace71
	char *file_path = NULL;
Packit eace71
	int rc = LIBISCSI_OK;
Packit eace71
	int errno_save = 0;
Packit eace71
	uint8_t buff[_INT32_STR_MAX_LEN];
Packit eace71
	long long int tmp_val = 0;
Packit eace71
Packit eace71
	assert(dir_path != NULL);
Packit eace71
	assert(prop_name != NULL);
Packit eace71
	assert(val != NULL);
Packit eace71
Packit eace71
	*val = 0;
Packit eace71
Packit eace71
	_good(_asprintf(&file_path, "%s/%s", dir_path, prop_name), rc, out);
Packit eace71
Packit eace71
	errno_save = sysfs_read_file(file_path, buff, _INT32_STR_MAX_LEN);
Packit eace71
	if (errno_save != 0) {
Packit eace71
		if (errno_save == ENOENT) {
Packit eace71
			if (! ignore_error) {
Packit eace71
				rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
				_error(ctx, "Failed to read '%s': "
Packit eace71
				       "file '%s' does not exists",
Packit eace71
				       prop_name, file_path);
Packit eace71
				goto out;
Packit eace71
			} else {
Packit eace71
				_info(ctx,
Packit eace71
				       "Failed to read '%s': "
Packit eace71
				      "File '%s' does not exists, using ",
Packit eace71
				      "default value %lld",
Packit eace71
				      prop_name, file_path, default_value);
Packit eace71
				*val = default_value;
Packit eace71
				goto out;
Packit eace71
			}
Packit eace71
		} else if (errno_save == EACCES) {
Packit eace71
			rc = LIBISCSI_ERR_ACCESS;
Packit eace71
			_error(ctx, "Permission deny when reading '%s'",
Packit eace71
			       file_path);
Packit eace71
			goto out;
Packit eace71
		} else if (errno_save == ENOTCONN) {
Packit eace71
			if (!ignore_error) {
Packit eace71
				rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
				_error(ctx, "Failed to read '%s': "
Packit eace71
					"error when reading '%s': "
Packit eace71
					"Target unavailable",
Packit eace71
					prop_name, file_path);
Packit eace71
				goto out;
Packit eace71
			} else {
Packit eace71
				_info(ctx, "Failed to read '%s': "
Packit eace71
					"error when reading '%s': "
Packit eace71
					"Target unavailable, using default value %lld",
Packit eace71
					prop_name, file_path, default_value);
Packit eace71
				*val = default_value;
Packit eace71
				goto out;
Packit eace71
			}
Packit eace71
		} else {
Packit eace71
			rc = LIBISCSI_ERR_BUG;
Packit eace71
			_error(ctx, "Error when reading '%s': %d", file_path,
Packit eace71
			       errno_save);
Packit eace71
			goto out;
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	errno = 0;
Packit eace71
	tmp_val = strtoll((const char *) buff, NULL, 10 /* base */);
Packit eace71
	errno_save = errno;
Packit eace71
	if ((errno_save != 0) && (! ignore_error)) {
Packit eace71
		rc = LIBISCSI_ERR_BUG;
Packit eace71
		_error(ctx, "Sysfs: %s: Error when converting '%s' "
Packit eace71
		       "to number", file_path,  (char *) buff, errno_save);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
Packit eace71
	*val = tmp_val;
Packit eace71
Packit eace71
	_debug(ctx, "Open '%s', got %lld", file_path, tmp_val);
Packit eace71
out:
Packit eace71
	free(file_path);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
static int sysfs_get_dev_path(struct iscsi_context *ctx, const char *path,
Packit eace71
			      enum _sysfs_dev_class class, char **dev_path)
Packit eace71
{
Packit eace71
	int rc = LIBISCSI_OK;
Packit eace71
	int errno_save = 0;
Packit eace71
	regex_t regex;
Packit eace71
	regmatch_t reg_match[2];
Packit eace71
	int reg_rc = 0;
Packit eace71
	int need_free_reg = 0;
Packit eace71
Packit eace71
	assert(ctx != NULL);
Packit eace71
	assert(path != NULL);
Packit eace71
	assert(dev_path != NULL);
Packit eace71
Packit eace71
	*dev_path = realpath(path, NULL);
Packit eace71
	if (*dev_path == NULL) {
Packit eace71
		errno_save = errno;
Packit eace71
		rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
		_error(ctx, "realpath() failed on %s with error %d", path,
Packit eace71
		       errno_save);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
Packit eace71
	switch (class) {
Packit eace71
	case _SYSFS_DEV_CLASS_ISCSI_SESSION:
Packit eace71
		reg_rc = regcomp(&regex,
Packit eace71
				 "\\(.\\{1,\\}/devices/.\\{1,\\}/"
Packit eace71
				 "host[0-9]\\{1,\\}\\)/"
Packit eace71
				 "session[0-9]\\{1,\\}/iscsi_session/",
Packit eace71
				 0 /* no flag */);
Packit eace71
		break;
Packit eace71
	case _SYSFS_DEV_CLASS_ISCSI_HOST:
Packit eace71
		reg_rc = regcomp(&regex,
Packit eace71
				 "\\(.\\{1,\\}/devices/.\\{1,\\}/"
Packit eace71
				 "host[0-9]\\{1,\\}\\)/"
Packit eace71
				 "iscsi_host/",
Packit eace71
				 0 /* no flag */);
Packit eace71
		break;
Packit eace71
	default:
Packit eace71
		rc = LIBISCSI_ERR_BUG;
Packit eace71
		_error(ctx, "BUG: sysfs_get_dev_path(): got unknown class %d",
Packit eace71
		       class);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
	if (reg_rc != 0) {
Packit eace71
		rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
		_error(ctx, "regcomp() failed %d", reg_rc);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
	need_free_reg = 1;
Packit eace71
	if (regexec(&regex, *dev_path, 2 /* count of max matches */,
Packit eace71
		    reg_match, 0 /* no flags */) != 0) {
Packit eace71
		rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
		_error(ctx, "regexec() not match for %s", *dev_path);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
Packit eace71
	*(*dev_path + reg_match[1].rm_eo ) = '\0';
Packit eace71
Packit eace71
	_debug(ctx, "Got dev path of '%s': '%s'", path, *dev_path);
Packit eace71
Packit eace71
out:
Packit eace71
	if (need_free_reg)
Packit eace71
		regfree(&regex);
Packit eace71
	if (rc != LIBISCSI_OK) {
Packit eace71
		free(*dev_path);
Packit eace71
		*dev_path = NULL;
Packit eace71
	}
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
int _iscsi_host_id_of_session(struct iscsi_context *ctx, uint32_t sid,
Packit eace71
			      uint32_t *host_id)
Packit eace71
{
Packit eace71
	int rc = LIBISCSI_OK;
Packit eace71
	char *sys_se_dir_path = NULL;
Packit eace71
	char *sys_dev_path = NULL;
Packit eace71
	char *sys_scsi_host_dir_path = NULL;
Packit eace71
	struct dirent **namelist = NULL;
Packit eace71
	int n = 0;
Packit eace71
	const char *host_id_str = NULL;
Packit eace71
	const char iscsi_host_dir_str[] = "/iscsi_host/";
Packit eace71
Packit eace71
	assert(ctx != NULL);
Packit eace71
	assert(sid != 0);
Packit eace71
	assert(host_id != NULL);
Packit eace71
Packit eace71
	_good(_asprintf(&sys_se_dir_path, "%s/session%" PRIu32,
Packit eace71
			_ISCSI_SYS_SESSION_DIR, sid), rc, out);
Packit eace71
Packit eace71
	*host_id = 0;
Packit eace71
Packit eace71
	_good(sysfs_get_dev_path(ctx, sys_se_dir_path,
Packit eace71
				 _SYSFS_DEV_CLASS_ISCSI_SESSION, &sys_dev_path),
Packit eace71
	      rc, out);
Packit eace71
Packit eace71
	_good(_asprintf(&sys_scsi_host_dir_path, "%s%s",
Packit eace71
			sys_dev_path, iscsi_host_dir_str), rc, out);
Packit eace71
Packit eace71
	_good(_scandir(ctx, sys_scsi_host_dir_path, &namelist, &n), rc, out);
Packit eace71
Packit eace71
	if (n != 1) {
Packit eace71
		rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
		_error(ctx, "Got unexpected(should be 1) file in folder %s",
Packit eace71
		       sys_scsi_host_dir_path);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
	host_id_str = namelist[0]->d_name;
Packit eace71
Packit eace71
	if (sscanf(host_id_str, "host%" SCNu32, host_id) != 1) {
Packit eace71
		rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
		_error(ctx, "sscanf() failed on string %s", host_id_str);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
Packit eace71
out:
Packit eace71
	_scandir_free(namelist, n);
Packit eace71
	free(sys_se_dir_path);
Packit eace71
	free(sys_dev_path);
Packit eace71
	free(sys_scsi_host_dir_path);
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
static int _iscsi_ids_get(struct iscsi_context *ctx,
Packit eace71
			  uint32_t **ids, uint32_t *id_count,
Packit eace71
			  const char *dir_path, const char *file_prefix)
Packit eace71
{
Packit eace71
	int rc = LIBISCSI_OK;
Packit eace71
	struct dirent **namelist = NULL;
Packit eace71
	int n = 0;
Packit eace71
	uint32_t i = 0;
Packit eace71
	const char *id_str = NULL;
Packit eace71
	char fmt_buff[128];
Packit eace71
Packit eace71
	assert(ctx != NULL);
Packit eace71
	assert(ids != 0);
Packit eace71
	assert(id_count != NULL);
Packit eace71
Packit eace71
	*ids = NULL;
Packit eace71
	*id_count = 0;
Packit eace71
Packit eace71
	_good(_scandir(ctx, dir_path, &namelist, &n), rc, out);
Packit eace71
	_debug(ctx, "Got %d iSCSI %s", n, file_prefix);
Packit eace71
Packit eace71
	*id_count = n & UINT32_MAX;
Packit eace71
Packit eace71
	*ids = calloc(*id_count, sizeof(uint32_t));
Packit eace71
	_alloc_null_check(ctx, *ids, rc, out);
Packit eace71
Packit eace71
	snprintf(fmt_buff, sizeof(fmt_buff)/sizeof(char), "%s%%" SCNu32,
Packit eace71
		 file_prefix);
Packit eace71
Packit eace71
	for (i = 0; i < *id_count; ++i) {
Packit eace71
		id_str = namelist[i]->d_name;
Packit eace71
		if (sscanf(id_str, fmt_buff, &((*ids)[i])) != 1) {
Packit eace71
			rc = LIBISCSI_ERR_SYSFS_LOOKUP;
Packit eace71
			_error(ctx, "sscanf() failed on string %s",
Packit eace71
			       id_str);
Packit eace71
			goto out;
Packit eace71
		}
Packit eace71
		_debug(ctx, "Got iSCSI %s id %" PRIu32, file_prefix, (*ids)[i]);
Packit eace71
	}
Packit eace71
Packit eace71
out:
Packit eace71
	_scandir_free(namelist, n);
Packit eace71
	if (rc != LIBISCSI_OK) {
Packit eace71
		free(*ids);
Packit eace71
		*ids = NULL;
Packit eace71
		*id_count = 0;
Packit eace71
	}
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
int _iscsi_sids_get(struct iscsi_context *ctx, uint32_t **sids,
Packit eace71
		    uint32_t *sid_count)
Packit eace71
{
Packit eace71
	return _iscsi_ids_get(ctx, sids, sid_count, _ISCSI_SYS_SESSION_DIR,
Packit eace71
			      "session");
Packit eace71
}
Packit eace71
Packit eace71
int _iscsi_hids_get(struct iscsi_context *ctx, uint32_t **hids,
Packit eace71
		    uint32_t *hid_count)
Packit eace71
{
Packit eace71
	return _iscsi_ids_get(ctx, hids, hid_count, _ISCSI_SYS_HOST_DIR,
Packit eace71
			      "host");
Packit eace71
}
Packit eace71
Packit eace71
bool _iscsi_transport_is_loaded(const char *transport_name)
Packit eace71
{
Packit eace71
	int rc = LIBISCSI_OK;
Packit eace71
	char *path = NULL;
Packit eace71
Packit eace71
	if (transport_name == NULL)
Packit eace71
		return false;
Packit eace71
Packit eace71
	_good(_asprintf(&path, "%s/%s", _ISCSI_SYS_TRANSPORT_DIR,
Packit eace71
			transport_name), rc, out);
Packit eace71
Packit eace71
	if (access(path, F_OK) == 0) {
Packit eace71
		free(path);
Packit eace71
		return true;
Packit eace71
	}
Packit eace71
out:
Packit eace71
	free(path);
Packit eace71
	return false;
Packit eace71
}
Packit eace71
Packit eace71
int _iscsi_iface_kern_ids_of_host_id(struct iscsi_context *ctx,
Packit eace71
				    uint32_t host_id,
Packit eace71
				    char ***iface_kern_ids,
Packit eace71
				    uint32_t *iface_count)
Packit eace71
{
Packit eace71
	char *sysfs_sh_path = NULL;
Packit eace71
	char *dev_path = NULL;
Packit eace71
	char *sysfs_iface_path = NULL;
Packit eace71
	int rc = LIBISCSI_OK;
Packit eace71
	struct dirent **namelist = NULL;
Packit eace71
	int n = 0;
Packit eace71
	uint32_t i = 0;
Packit eace71
Packit eace71
	_good(_asprintf(&sysfs_sh_path, "%s/host%" PRIu32,
Packit eace71
			_ISCSI_SYS_HOST_DIR, host_id), rc, out);
Packit eace71
Packit eace71
	_good(sysfs_get_dev_path(ctx, sysfs_sh_path,
Packit eace71
				 _SYSFS_DEV_CLASS_ISCSI_HOST, &dev_path),
Packit eace71
	      rc, out);
Packit eace71
Packit eace71
	_good(_asprintf(&sysfs_iface_path, "%s/iscsi_iface", dev_path),
Packit eace71
	      rc, out);
Packit eace71
Packit eace71
	_good(_scandir(ctx, sysfs_iface_path, &namelist, &n), rc, out);
Packit eace71
Packit eace71
	if (n == 0) {
Packit eace71
		/* this is OK, and needed for transport drivers like
Packit eace71
		 * bnx2i and qedi */
Packit eace71
		rc = LIBISCSI_OK;
Packit eace71
		_debug(ctx, "No iSCSI interface for iSCSI host %" PRIu32,
Packit eace71
		       host_id);
Packit eace71
		goto out;
Packit eace71
	}
Packit eace71
Packit eace71
	*iface_count = n;
Packit eace71
	*iface_kern_ids = calloc(*iface_count, sizeof(char *));
Packit eace71
	_alloc_null_check(ctx, *iface_kern_ids, rc, out);
Packit eace71
	for (i = 0; i < *iface_count; i++) {
Packit eace71
		(*iface_kern_ids)[i] = strdup(namelist[i]->d_name);
Packit eace71
		_alloc_null_check(ctx, (*iface_kern_ids)[i], rc, out);
Packit eace71
		_debug(ctx, "Found iSCSI iface '%s' for iSCSI host %" PRIu32,
Packit eace71
		       (*iface_kern_ids)[i], host_id);
Packit eace71
	}
Packit eace71
out:
Packit eace71
	if (rc != LIBISCSI_OK) {
Packit eace71
		for (i = 0; i < *iface_count; i++ ) {
Packit eace71
			free((*iface_kern_ids)[i]);
Packit eace71
		}
Packit eace71
		free(*iface_kern_ids);
Packit eace71
		*iface_kern_ids = NULL;
Packit eace71
		*iface_count = 0;
Packit eace71
	}
Packit eace71
	_scandir_free(namelist, n);
Packit eace71
	free(sysfs_sh_path);
Packit eace71
	free(dev_path);
Packit eace71
	free(sysfs_iface_path);
Packit eace71
	return rc;
Packit eace71
}