summaryrefslogtreecommitdiff
path: root/libopeniscsiusr/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libopeniscsiusr/misc.c')
-rw-r--r--libopeniscsiusr/misc.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/libopeniscsiusr/misc.c b/libopeniscsiusr/misc.c
index 93db919..9111966 100644
--- a/libopeniscsiusr/misc.c
+++ b/libopeniscsiusr/misc.c
@@ -24,6 +24,12 @@
#include <dirent.h>
#include <string.h>
#include <unistd.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <linux/ethtool.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <net/if_arp.h>
#include "libopeniscsiusr/libopeniscsiusr.h"
#include "misc.h"
@@ -63,6 +69,10 @@ static const struct _num_str_conv _ISCSI_RC_MSG_CONV[] = {
{LIBISCSI_ERR_ACCESS, "Permission deny"},
{LIBISCSI_ERR_NOMEM, "Out of memory"},
{LIBISCSI_ERR_SYSFS_LOOKUP, "Could not lookup object in sysfs"},
+ {LIBISCSI_ERR_IDBM, "Error accessing/managing iSCSI DB"},
+ {LIBISCSI_ERR_TRANS_NOT_FOUND,
+ "iSCSI transport module not loaded in kernel or iscsid"},
+ {LIBISCSI_ERR_INVAL, "Invalid argument"},
};
_iscsi_str_func_gen(iscsi_strerror, int, rc, _ISCSI_RC_MSG_CONV);
@@ -122,3 +132,200 @@ bool _file_exists(const char *path)
else
return false;
}
+
+static bool _is_eth(struct iscsi_context *ctx, const char *if_name)
+{
+ struct ifreq ifr;
+ int sockfd = -1;
+ char strerr_buff[_STRERR_BUFF_LEN];
+
+ assert(if_name != NULL);
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ _strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ _warn(ctx, "Failed to create SOCK_DGRAM AF_INET socket: %d %s",
+ errno, _strerror(errno, strerr_buff));
+ return false;
+ }
+
+ if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) != 0) {
+ _warn(ctx, "IOCTL SIOCGIFHWADDR to %s failed: %d %s", if_name,
+ errno, _strerror(errno, strerr_buff));
+ close(sockfd);
+ return false;
+ }
+
+ close(sockfd);
+
+ if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER)
+ return true;
+
+ return false;
+}
+
+/*
+ * driver_name should be char[_ETH_DRIVER_NAME_MAX_LEN]
+ */
+static int _eth_driver_get(struct iscsi_context *ctx, const char *if_name,
+ char *driver_name)
+{
+ int sockfd = -1;
+ struct ethtool_drvinfo drvinfo;
+ struct ifreq ifr;
+ char strerr_buff[_STRERR_BUFF_LEN];
+
+ assert(ctx != NULL);
+ assert(if_name != NULL);
+ assert(driver_name != NULL);
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&drvinfo, 0, sizeof(drvinfo));
+
+ _strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t) &drvinfo;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ _error(ctx, "Failed to create SOCK_DGRAM AF_INET socket: %d %s",
+ errno, _strerror(errno, strerr_buff));
+ return LIBISCSI_ERR_BUG;
+ }
+
+ if (ioctl(sockfd, SIOCETHTOOL, &ifr) != 0) {
+ _warn(ctx, "IOCTL SIOCETHTOOL to %s failed: %d %s", if_name,
+ errno, _strerror(errno, strerr_buff));
+ close(sockfd);
+ return LIBISCSI_ERR_BUG;
+ }
+ close(sockfd);
+ snprintf(driver_name, _ETH_DRIVER_NAME_MAX_LEN, "%s", drvinfo.driver);
+
+ return LIBISCSI_OK;
+}
+
+int _eth_ifs_get(struct iscsi_context *ctx, struct _eth_if ***eifs,
+ uint32_t *eif_count)
+{
+ int rc = LIBISCSI_OK;
+ struct if_nameindex *if_ni = NULL;
+ struct if_nameindex *if_i = NULL;
+ struct _eth_if *eif = NULL;
+ uint32_t tmp_count = 0;
+
+ assert(ctx != NULL);
+ assert(eifs != NULL);
+ assert(eif_count != NULL);
+
+ *eifs = NULL;
+ *eif_count = 0;
+
+ if_ni = if_nameindex();
+ _alloc_null_check(ctx, if_ni, rc, out);
+
+ for (if_i = if_ni; if_i && if_i->if_index && if_i->if_name; ++if_i)
+ tmp_count++;
+
+ if (tmp_count == 0)
+ goto out;
+
+ *eifs = calloc(tmp_count, sizeof(struct _eth_if *));
+ _alloc_null_check(ctx, *eifs, rc, out);
+
+ for (if_i = if_ni; if_i && if_i->if_index && if_i->if_name; ++if_i) {
+ if (! _is_eth(ctx, if_i->if_name))
+ continue;
+ eif = calloc(1, sizeof(struct _eth_if));
+ _alloc_null_check(ctx, eif, rc, out);
+ (*eifs)[(*eif_count)++] = eif;
+ snprintf(eif->if_name, sizeof(eif->if_name)/sizeof(char),
+ "%s", if_i->if_name);
+ _good(_eth_driver_get(ctx, eif->if_name, eif->driver_name),
+ rc, out);
+ }
+
+out:
+ if (rc != LIBISCSI_OK) {
+ _eth_ifs_free(*eifs, *eif_count);
+ *eifs = NULL;
+ *eif_count = 0;
+ }
+ if (if_ni != NULL)
+ if_freenameindex(if_ni);
+ return rc;
+}
+
+void _eth_ifs_free(struct _eth_if **eifs, uint32_t eif_count)
+{
+ uint32_t i = 0;
+
+ if ((eif_count == 0) || (eifs == NULL))
+ return;
+
+ for (; i < eif_count; ++i)
+ free(eifs[i]);
+ free(eifs);
+}
+
+void _scandir_free(struct dirent **namelist, int count)
+{
+ int i = 0;
+
+ if ((namelist == NULL) || (count == 0))
+ return;
+
+ for (i = count - 1; i >= 0; --i)
+ free(namelist[i]);
+ free(namelist);
+}
+
+int _scandir(struct iscsi_context *ctx, const char *dir_path,
+ struct dirent ***namelist, int *count)
+{
+ int rc = LIBISCSI_OK;
+ int errno_save = 0;
+
+ assert(ctx != NULL);
+ assert(dir_path != NULL);
+ assert(namelist != NULL);
+ assert(count != NULL);
+
+ *namelist = NULL;
+ *count = 0;
+
+ *count = scandir(dir_path, namelist, _scan_filter_skip_dot, alphasort);
+ if (*count < 0) {
+ errno_save = errno;
+ if (errno_save == ENOENT) {
+ *count = 0;
+ 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",
+ dir_path);
+ goto out;
+ }
+ rc = LIBISCSI_ERR_BUG;
+ _error(ctx, "Got unexpected error %d when scandir %s",
+ errno_save, dir_path);
+ goto out;
+ }
+
+out:
+ if (rc != LIBISCSI_OK) {
+ _scandir_free(*namelist, *count);
+ *namelist = NULL;
+ *count = 0;
+ }
+
+ return rc;
+}