|
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(®ex,
|
|
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(®ex,
|
|
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(®ex, *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(®ex);
|
|
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 |
}
|