[libvirt] [PATCHv2 6/8] Move functions using iscsiadm to viriscsi.c

Ján Tomko jtomko at redhat.com
Wed Mar 19 15:52:31 UTC 2014


Remove the 'StorageBackend' from names of the functions and fix
indentation.
---
 po/POTFILES.in                      |   1 +
 src/Makefile.am                     |   1 +
 src/libvirt_private.syms            |   9 +
 src/storage/storage_backend_iscsi.c | 498 ++----------------------------------
 src/storage/storage_backend_iscsi.h |   4 -
 src/util/viriscsi.c                 | 498 ++++++++++++++++++++++++++++++++++++
 src/util/viriscsi.h                 |  52 ++++
 7 files changed, 588 insertions(+), 475 deletions(-)
 create mode 100644 src/util/viriscsi.c
 create mode 100644 src/util/viriscsi.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index efac7b2..5a4112a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -168,6 +168,7 @@ src/util/virhostdev.c
 src/util/viridentity.c
 src/util/virinitctl.c
 src/util/viriptables.c
+src/util/viriscsi.c
 src/util/virjson.c
 src/util/virkeyfile.c
 src/util/virlockspace.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 4fdd871..55427ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -113,6 +113,7 @@ UTIL_SOURCES =							\
 		util/viridentity.c util/viridentity.h		\
 		util/virinitctl.c util/virinitctl.h		\
 		util/viriptables.c util/viriptables.h		\
+		util/viriscsi.c util/viriscsi.h			\
 		util/virjson.c util/virjson.h			\
 		util/virkeycode.c util/virkeycode.h		\
 		util/virkeyfile.c util/virkeyfile.h		\
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c7e024d..d72a9af 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1359,6 +1359,15 @@ iptablesRemoveUdpInput;
 iptablesRemoveUdpOutput;
 
 
+# util/viriscsi.h
+virISCSIConnectionLogin;
+virISCSIConnectionLogout;
+virISCSIGetSession;
+virISCSINodeUpdate;
+virISCSIRescanLUNs;
+virISCSIScanTargets;
+
+
 # util/virjson.h
 virJSONValueArrayAppend;
 virJSONValueArrayGet;
diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index b7a0380..7e7ffad 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -26,8 +26,6 @@
 #include <dirent.h>
 #include <sys/wait.h>
 #include <string.h>
-#include <stdio.h>
-#include <regex.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/stat.h>
@@ -40,9 +38,9 @@
 #include "vircommand.h"
 #include "virerror.h"
 #include "virfile.h"
+#include "viriscsi.h"
 #include "virlog.h"
 #include "virobject.h"
-#include "virrandom.h"
 #include "virstring.h"
 #include "viruuid.h"
 
@@ -79,306 +77,14 @@ virStorageBackendISCSIPortal(virStoragePoolSourcePtr source)
     return portal;
 }
 
-struct virStorageBackendISCSISessionData {
-    char *session;
-    const char *devpath;
-};
-
-static int
-virStorageBackendISCSIExtractSession(char **const groups,
-                                     void *opaque)
-{
-    struct virStorageBackendISCSISessionData *data = opaque;
-
-    if (STREQ(groups[1], data->devpath))
-        return VIR_STRDUP(data->session, groups[0]);
-    return 0;
-}
-
-static char *
-virStorageBackendISCSIGetSession(const char *devpath,
-                                 bool probe)
-{
-    /*
-     * # iscsiadm --mode session
-     * tcp: [1] 192.168.122.170:3260,1 demo-tgt-b
-     * tcp: [2] 192.168.122.170:3260,1 demo-tgt-a
-     *
-     * Pull out 2nd and 4th fields
-     */
-    const char *regexes[] = {
-        "^tcp:\\s+\\[(\\S+)\\]\\s+\\S+\\s+(\\S+).*$"
-    };
-    int vars[] = {
-        2,
-    };
-    struct virStorageBackendISCSISessionData cbdata = {
-        .session = NULL,
-        .devpath = devpath,
-    };
-
-    virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL);
-
-    if (virCommandRunRegex(cmd,
-                           1,
-                           regexes,
-                           vars,
-                           virStorageBackendISCSIExtractSession,
-                           &cbdata, NULL) < 0)
-        goto cleanup;
-
-    if (cbdata.session == NULL && !probe) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       "%s", _("cannot find session"));
-        goto cleanup;
-    }
-
-cleanup:
-    virCommandFree(cmd);
-    return cbdata.session;
-}
 
 static char *
 virStorageBackendISCSISession(virStoragePoolObjPtr pool,
                               bool probe)
 {
-    return virStorageBackendISCSIGetSession(pool->def->source.devices[0].path, probe);
-}
-
-
-#define LINE_SIZE 4096
-
-static int
-virStorageBackendIQNFound(const char *initiatoriqn,
-                          char **ifacename)
-{
-    int ret = IQN_MISSING, fd = -1;
-    char ebuf[64];
-    FILE *fp = NULL;
-    char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL;
-    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
-                                             "--mode", "iface", NULL);
-
-    if (VIR_ALLOC_N(line, LINE_SIZE) != 0) {
-        ret = IQN_ERROR;
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Could not allocate memory for output of '%s'"),
-                       ISCSIADM);
-        goto out;
-    }
-
-    memset(line, 0, LINE_SIZE);
-
-    virCommandSetOutputFD(cmd, &fd);
-    if (virCommandRunAsync(cmd, NULL) < 0) {
-        ret = IQN_ERROR;
-        goto out;
-    }
-
-    if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to open stream for file descriptor "
-                         "when reading output from '%s': '%s'"),
-                       ISCSIADM, virStrerror(errno, ebuf, sizeof(ebuf)));
-        ret = IQN_ERROR;
-        goto out;
-    }
-
-    while (fgets(line, LINE_SIZE, fp) != NULL) {
-        newline = strrchr(line, '\n');
-        if (newline == NULL) {
-            ret = IQN_ERROR;
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Unexpected line > %d characters "
-                             "when parsing output of '%s'"),
-                           LINE_SIZE, ISCSIADM);
-            goto out;
-        }
-        *newline = '\0';
-
-        iqn = strrchr(line, ',');
-        if (iqn == NULL) {
-            continue;
-        }
-        iqn++;
-
-        if (STREQ(iqn, initiatoriqn)) {
-            token = strchr(line, ' ');
-            if (!token) {
-                ret = IQN_ERROR;
-                virReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("Missing space when parsing output "
-                                 "of '%s'"), ISCSIADM);
-                goto out;
-            }
-            if (VIR_STRNDUP(*ifacename, line, token - line) < 0) {
-                ret = IQN_ERROR;
-                goto out;
-            }
-            VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn);
-            ret = IQN_FOUND;
-            break;
-        }
-    }
-
-    if (virCommandWait(cmd, NULL) < 0)
-        ret = IQN_ERROR;
-
-out:
-    if (ret == IQN_MISSING) {
-        VIR_DEBUG("Could not find interface with IQN '%s'", iqn);
-    }
-
-    VIR_FREE(line);
-    VIR_FORCE_FCLOSE(fp);
-    VIR_FORCE_CLOSE(fd);
-    virCommandFree(cmd);
-
-    return ret;
-}
-
-
-static int
-virStorageBackendCreateIfaceIQN(const char *initiatoriqn,
-                                char **ifacename)
-{
-    int ret = -1, exitstatus = -1;
-    char *temp_ifacename;
-    virCommandPtr cmd = NULL;
-
-    if (virAsprintf(&temp_ifacename,
-                    "libvirt-iface-%08llx",
-                    (unsigned long long)virRandomBits(30)) < 0)
-        return -1;
-
-    VIR_DEBUG("Attempting to create interface '%s' with IQN '%s'",
-              temp_ifacename, initiatoriqn);
-
-    cmd = virCommandNewArgList(ISCSIADM,
-                               "--mode", "iface",
-                               "--interface", temp_ifacename,
-                               "--op", "new",
-                               NULL);
-    /* Note that we ignore the exitstatus.  Older versions of iscsiadm
-     * tools returned an exit status of > 0, even if they succeeded.
-     * We will just rely on whether the interface got created
-     * properly. */
-    if (virCommandRun(cmd, &exitstatus) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to run command '%s' to create new iscsi interface"),
-                       ISCSIADM);
-        goto cleanup;
-    }
-    virCommandFree(cmd);
-
-    cmd = virCommandNewArgList(ISCSIADM,
-                               "--mode", "iface",
-                               "--interface", temp_ifacename,
-                               "--op", "update",
-                               "--name", "iface.initiatorname",
-                               "--value",
-                               initiatoriqn,
-                               NULL);
-    /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
-     * returned an exit status of > 0, even if they succeeded.  We will just
-     * rely on whether iface file got updated properly. */
-    if (virCommandRun(cmd, &exitstatus) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to run command '%s' to update iscsi interface with IQN '%s'"),
-                       ISCSIADM, initiatoriqn);
-        goto cleanup;
-    }
-
-    /* Check again to make sure the interface was created. */
-    if (virStorageBackendIQNFound(initiatoriqn, ifacename) != IQN_FOUND) {
-        VIR_DEBUG("Failed to find interface '%s' with IQN '%s' "
-                  "after attempting to create it",
-                  &temp_ifacename[0], initiatoriqn);
-        goto cleanup;
-    } else {
-        VIR_DEBUG("Interface '%s' with IQN '%s' was created successfully",
-                  *ifacename, initiatoriqn);
-    }
-
-    ret = 0;
-
-cleanup:
-    virCommandFree(cmd);
-    VIR_FREE(temp_ifacename);
-    if (ret != 0)
-        VIR_FREE(*ifacename);
-    return ret;
-}
-
-
-
-static int
-virStorageBackendISCSIConnection(const char *portal,
-                                 const char *initiatoriqn,
-                                 const char *target,
-                                 const char **extraargv)
-{
-    int ret = -1;
-    const char *const baseargv[] = {
-        ISCSIADM,
-        "--mode", "node",
-        "--portal", portal,
-        "--targetname", target,
-        NULL
-    };
-    virCommandPtr cmd;
-    char *ifacename = NULL;
-
-    cmd = virCommandNewArgs(baseargv);
-    virCommandAddArgSet(cmd, extraargv);
-
-    if (initiatoriqn) {
-        switch (virStorageBackendIQNFound(initiatoriqn, &ifacename)) {
-        case IQN_FOUND:
-            VIR_DEBUG("ifacename: '%s'", ifacename);
-            break;
-        case IQN_MISSING:
-            if (virStorageBackendCreateIfaceIQN(initiatoriqn,
-                                                &ifacename) != 0) {
-                goto cleanup;
-            }
-            break;
-        case IQN_ERROR:
-        default:
-            goto cleanup;
-        }
-        virCommandAddArgList(cmd, "--interface", ifacename, NULL);
-    }
-
-    if (virCommandRun(cmd, NULL) < 0)
-        goto cleanup;
-
-    ret = 0;
-
-cleanup:
-    virCommandFree(cmd);
-    VIR_FREE(ifacename);
-
-    return ret;
-}
-
-static int
-virStorageBackendISCSIConnectionLogin(const char *portal,
-                                      const char *initiatoriqn,
-                                      const char *target)
-{
-    const char *extraargv[] = { "--login", NULL };
-    return virStorageBackendISCSIConnection(portal, initiatoriqn, target, extraargv);
+    return virISCSIGetSession(pool->def->source.devices[0].path, probe);
 }
 
-static int
-virStorageBackendISCSIConnectionLogout(const char *portal,
-                                       const char *initiatoriqn,
-                                       const char *target)
-{
-    const char *extraargv[] = { "--logout", NULL };
-    return virStorageBackendISCSIConnection(portal, initiatoriqn, target, extraargv);
-}
 
 static int
 virStorageBackendISCSIGetHostNumber(const char *sysfs_path,
@@ -448,124 +154,6 @@ virStorageBackendISCSIFindLUs(virStoragePoolObjPtr pool,
     return retval;
 }
 
-static int
-virStorageBackendISCSIRescanLUNs(const char *session)
-{
-    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
-                                             "--mode", "session",
-                                             "-r", session,
-                                             "-R",
-                                             NULL);
-    int ret = virCommandRun(cmd, NULL);
-    virCommandFree(cmd);
-    return ret;
-}
-
-struct virStorageBackendISCSITargetList {
-    size_t ntargets;
-    char **targets;
-};
-
-static int
-virStorageBackendISCSIGetTargets(char **const groups,
-                                 void *data)
-{
-    struct virStorageBackendISCSITargetList *list = data;
-    char *target;
-
-    if (VIR_STRDUP(target, groups[1]) < 0)
-        return -1;
-
-    if (VIR_APPEND_ELEMENT(list->targets, list->ntargets, target) < 0) {
-        VIR_FREE(target);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int
-virStorageBackendISCSITargetAutologin(const char *portal,
-                                      const char *initiatoriqn,
-                                      const char *target,
-                                      bool enable)
-{
-    const char *extraargv[] = { "--op", "update",
-                                "--name", "node.startup",
-                                "--value", enable ? "automatic" : "manual",
-                                NULL };
-
-    return virStorageBackendISCSIConnection(portal, initiatoriqn, target, extraargv);
-}
-
-
-static int
-virStorageBackendISCSIScanTargets(const char *portal,
-                                  const char *initiatoriqn,
-                                  size_t *ntargetsret,
-                                  char ***targetsret)
-{
-    /**
-     *
-     * The output of sendtargets is very simple, just two columns,
-     * portal then target name
-     *
-     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo0.bf6d84
-     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo1.bf6d84
-     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo2.bf6d84
-     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo3.bf6d84
-     */
-    const char *regexes[] = {
-        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
-    };
-    int vars[] = { 2 };
-    struct virStorageBackendISCSITargetList list;
-    size_t i;
-    int ret = -1;
-    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
-                                             "--mode", "discovery",
-                                             "--type", "sendtargets",
-                                             "--portal", portal,
-                                             NULL);
-
-    memset(&list, 0, sizeof(list));
-
-    if (virCommandRunRegex(cmd,
-                           1,
-                           regexes,
-                           vars,
-                           virStorageBackendISCSIGetTargets,
-                           &list, NULL) < 0)
-        goto cleanup;
-
-    for (i = 0; i < list.ntargets; i++) {
-        /* We have to ignore failure, because we can't undo
-         * the results of 'sendtargets', unless we go scrubbing
-         * around in the dirt in /var/lib/iscsi.
-         */
-        if (virStorageBackendISCSITargetAutologin(portal,
-                                                  initiatoriqn,
-                                                  list.targets[i], false) < 0)
-            VIR_WARN("Unable to disable auto-login on iSCSI target %s: %s",
-                     portal, list.targets[i]);
-    }
-
-    if (ntargetsret && targetsret) {
-        *ntargetsret = list.ntargets;
-        *targetsret = list.targets;
-    } else {
-        for (i = 0; i < list.ntargets; i++) {
-            VIR_FREE(list.targets[i]);
-        }
-        VIR_FREE(list.targets);
-    }
-
-    ret = 0;
-cleanup:
-    virCommandFree(cmd);
-    return ret;
-}
-
 
 static char *
 virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -606,9 +194,9 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
     if (!(portal = virStorageBackendISCSIPortal(source)))
         goto cleanup;
 
-    if (virStorageBackendISCSIScanTargets(portal,
-                                          source->initiator.iqn,
-                                          &ntargets, &targets) < 0)
+    if (virISCSIScanTargets(portal,
+                            source->initiator.iqn,
+                            &ntargets, &targets) < 0)
         goto cleanup;
 
     if (VIR_ALLOC_N(list.sources, ntargets) < 0)
@@ -683,38 +271,6 @@ virStorageBackendISCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
     return ret;
 }
 
-static int
-virStorageBackendISCSINodeUpdate(const char *portal,
-                                 const char *target,
-                                 const char *name,
-                                 const char *value)
-{
-     virCommandPtr cmd = NULL;
-     int status;
-     int ret = -1;
-
-     cmd = virCommandNewArgList(ISCSIADM,
-                                "--mode", "node",
-                                "--portal", portal,
-                                "--target", target,
-                                "--op", "update",
-                                "--name", name,
-                                "--value", value,
-                                NULL);
-
-    /* Ignore non-zero status.  */
-    if (virCommandRun(cmd, &status) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to update '%s' of node mode for target '%s'"),
-                       name, target);
-        goto cleanup;
-    }
-
-    ret = 0;
-cleanup:
-    virCommandFree(cmd);
-    return ret;
-}
 
 static int
 virStorageBackendISCSISetAuth(const char *portal,
@@ -784,18 +340,18 @@ virStorageBackendISCSISetAuth(const char *portal,
         goto cleanup;
     }
 
-    if (virStorageBackendISCSINodeUpdate(portal,
-                                         def->source.devices[0].path,
-                                         "node.session.auth.authmethod",
-                                         "CHAP") < 0 ||
-        virStorageBackendISCSINodeUpdate(portal,
-                                         def->source.devices[0].path,
-                                         "node.session.auth.username",
-                                         chap.username) < 0 ||
-        virStorageBackendISCSINodeUpdate(portal,
-                                         def->source.devices[0].path,
-                                         "node.session.auth.password",
-                                         (const char *)secret_value) < 0)
+    if (virISCSINodeUpdate(portal,
+                           def->source.devices[0].path,
+                           "node.session.auth.authmethod",
+                           "CHAP") < 0 ||
+        virISCSINodeUpdate(portal,
+                           def->source.devices[0].path,
+                           "node.session.auth.username",
+                           chap.username) < 0 ||
+        virISCSINodeUpdate(portal,
+                           def->source.devices[0].path,
+                           "node.session.auth.password",
+                           (const char *)secret_value) < 0)
         goto cleanup;
 
     ret = 0;
@@ -840,17 +396,17 @@ virStorageBackendISCSIStartPool(virConnectPtr conn,
          * iscsiadm doesn't let you login to a target, unless you've
          * first issued a 'sendtargets' command to the portal :-(
          */
-        if (virStorageBackendISCSIScanTargets(portal,
-                                              pool->def->source.initiator.iqn,
-                                              NULL, NULL) < 0)
+        if (virISCSIScanTargets(portal,
+                                pool->def->source.initiator.iqn,
+                                NULL, NULL) < 0)
             goto cleanup;
 
         if (virStorageBackendISCSISetAuth(portal, conn, pool->def) < 0)
             goto cleanup;
 
-        if (virStorageBackendISCSIConnectionLogin(portal,
-                                                  pool->def->source.initiator.iqn,
-                                                  pool->def->source.devices[0].path) < 0)
+        if (virISCSIConnectionLogin(portal,
+                                    pool->def->source.initiator.iqn,
+                                    pool->def->source.devices[0].path) < 0)
             goto cleanup;
     }
     ret = 0;
@@ -871,7 +427,7 @@ virStorageBackendISCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     if ((session = virStorageBackendISCSISession(pool, false)) == NULL)
         goto cleanup;
-    if (virStorageBackendISCSIRescanLUNs(session) < 0)
+    if (virISCSIRescanLUNs(session) < 0)
         goto cleanup;
     if (virStorageBackendISCSIFindLUs(pool, session) < 0)
         goto cleanup;
@@ -895,9 +451,9 @@ virStorageBackendISCSIStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
     if ((portal = virStorageBackendISCSIPortal(&pool->def->source)) == NULL)
         return -1;
 
-    if (virStorageBackendISCSIConnectionLogout(portal,
-                                               pool->def->source.initiator.iqn,
-                                               pool->def->source.devices[0].path) < 0)
+    if (virISCSIConnectionLogout(portal,
+                                 pool->def->source.initiator.iqn,
+                                 pool->def->source.devices[0].path) < 0)
         goto cleanup;
     ret = 0;
 
diff --git a/src/storage/storage_backend_iscsi.h b/src/storage/storage_backend_iscsi.h
index 910a795..da3b22c 100644
--- a/src/storage/storage_backend_iscsi.h
+++ b/src/storage/storage_backend_iscsi.h
@@ -28,8 +28,4 @@
 
 extern virStorageBackend virStorageBackendISCSI;
 
-# define IQN_FOUND 1
-# define IQN_MISSING 0
-# define IQN_ERROR -1
-
 #endif /* __VIR_STORAGE_BACKEND_ISCSI_H__ */
diff --git a/src/util/viriscsi.c b/src/util/viriscsi.c
new file mode 100644
index 0000000..18a595f
--- /dev/null
+++ b/src/util/viriscsi.c
@@ -0,0 +1,498 @@
+/*
+ * viriscsi.c: helper APIs for managing iSCSI
+ *
+ * Copyright (C) 2007-2014 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <regex.h>
+#include <stdio.h>
+
+#include "viriscsi.h"
+
+#include "viralloc.h"
+#include "vircommand.h"
+#include "virerror.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virrandom.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_LOG_INIT("util.iscsi");
+
+
+struct virISCSISessionData {
+    char *session;
+    const char *devpath;
+};
+
+
+static int
+virISCSIExtractSession(char **const groups,
+                       void *opaque)
+{
+    struct virISCSISessionData *data = opaque;
+
+    if (STREQ(groups[1], data->devpath))
+        return VIR_STRDUP(data->session, groups[0]);
+    return 0;
+}
+
+
+char *
+virISCSIGetSession(const char *devpath,
+                   bool probe)
+{
+    /*
+     * # iscsiadm --mode session
+     * tcp: [1] 192.168.122.170:3260,1 demo-tgt-b
+     * tcp: [2] 192.168.122.170:3260,1 demo-tgt-a
+     *
+     * Pull out 2nd and 4th fields
+     */
+    const char *regexes[] = {
+        "^tcp:\\s+\\[(\\S+)\\]\\s+\\S+\\s+(\\S+).*$"
+    };
+    int vars[] = {
+        2,
+    };
+    struct virISCSISessionData cbdata = {
+        .session = NULL,
+        .devpath = devpath,
+    };
+
+    virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL);
+
+    if (virCommandRunRegex(cmd,
+                           1,
+                           regexes,
+                           vars,
+                           virISCSIExtractSession,
+                           &cbdata, NULL) < 0)
+        goto cleanup;
+
+    if (cbdata.session == NULL && !probe) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("cannot find session"));
+        goto cleanup;
+    }
+
+cleanup:
+    virCommandFree(cmd);
+    return cbdata.session;
+}
+
+
+
+#define LINE_SIZE 4096
+#define IQN_FOUND 1
+#define IQN_MISSING 0
+#define IQN_ERROR -1
+
+static int
+virStorageBackendIQNFound(const char *initiatoriqn,
+                          char **ifacename)
+{
+    int ret = IQN_MISSING, fd = -1;
+    char ebuf[64];
+    FILE *fp = NULL;
+    char *line = NULL, *newline = NULL, *iqn = NULL, *token = NULL;
+    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
+                                             "--mode", "iface", NULL);
+
+    if (VIR_ALLOC_N(line, LINE_SIZE) != 0) {
+        ret = IQN_ERROR;
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not allocate memory for output of '%s'"),
+                       ISCSIADM);
+        goto out;
+    }
+
+    memset(line, 0, LINE_SIZE);
+
+    virCommandSetOutputFD(cmd, &fd);
+    if (virCommandRunAsync(cmd, NULL) < 0) {
+        ret = IQN_ERROR;
+        goto out;
+    }
+
+    if ((fp = VIR_FDOPEN(fd, "r")) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to open stream for file descriptor "
+                         "when reading output from '%s': '%s'"),
+                       ISCSIADM, virStrerror(errno, ebuf, sizeof(ebuf)));
+        ret = IQN_ERROR;
+        goto out;
+    }
+
+    while (fgets(line, LINE_SIZE, fp) != NULL) {
+        newline = strrchr(line, '\n');
+        if (newline == NULL) {
+            ret = IQN_ERROR;
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Unexpected line > %d characters "
+                             "when parsing output of '%s'"),
+                           LINE_SIZE, ISCSIADM);
+            goto out;
+        }
+        *newline = '\0';
+
+        iqn = strrchr(line, ',');
+        if (iqn == NULL) {
+            continue;
+        }
+        iqn++;
+
+        if (STREQ(iqn, initiatoriqn)) {
+            token = strchr(line, ' ');
+            if (!token) {
+                ret = IQN_ERROR;
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Missing space when parsing output "
+                                 "of '%s'"), ISCSIADM);
+                goto out;
+            }
+            if (VIR_STRNDUP(*ifacename, line, token - line) < 0) {
+                ret = IQN_ERROR;
+                goto out;
+            }
+            VIR_DEBUG("Found interface '%s' with IQN '%s'", *ifacename, iqn);
+            ret = IQN_FOUND;
+            break;
+        }
+    }
+
+    if (virCommandWait(cmd, NULL) < 0)
+        ret = IQN_ERROR;
+
+out:
+    if (ret == IQN_MISSING) {
+        VIR_DEBUG("Could not find interface with IQN '%s'", iqn);
+    }
+
+    VIR_FREE(line);
+    VIR_FORCE_FCLOSE(fp);
+    VIR_FORCE_CLOSE(fd);
+    virCommandFree(cmd);
+
+    return ret;
+}
+
+
+static int
+virStorageBackendCreateIfaceIQN(const char *initiatoriqn,
+                                char **ifacename)
+{
+    int ret = -1, exitstatus = -1;
+    char *temp_ifacename;
+    virCommandPtr cmd = NULL;
+
+    if (virAsprintf(&temp_ifacename,
+                    "libvirt-iface-%08llx",
+                    (unsigned long long)virRandomBits(30)) < 0)
+        return -1;
+
+    VIR_DEBUG("Attempting to create interface '%s' with IQN '%s'",
+              temp_ifacename, initiatoriqn);
+
+    cmd = virCommandNewArgList(ISCSIADM,
+                               "--mode", "iface",
+                               "--interface", temp_ifacename,
+                               "--op", "new",
+                               NULL);
+    /* Note that we ignore the exitstatus.  Older versions of iscsiadm
+     * tools returned an exit status of > 0, even if they succeeded.
+     * We will just rely on whether the interface got created
+     * properly. */
+    if (virCommandRun(cmd, &exitstatus) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to run command '%s' to create new iscsi interface"),
+                       ISCSIADM);
+        goto cleanup;
+    }
+    virCommandFree(cmd);
+
+    cmd = virCommandNewArgList(ISCSIADM,
+                               "--mode", "iface",
+                               "--interface", temp_ifacename,
+                               "--op", "update",
+                               "--name", "iface.initiatorname",
+                               "--value",
+                               initiatoriqn,
+                               NULL);
+    /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
+     * returned an exit status of > 0, even if they succeeded.  We will just
+     * rely on whether iface file got updated properly. */
+    if (virCommandRun(cmd, &exitstatus) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to run command '%s' to update iscsi interface with IQN '%s'"),
+                       ISCSIADM, initiatoriqn);
+        goto cleanup;
+    }
+
+    /* Check again to make sure the interface was created. */
+    if (virStorageBackendIQNFound(initiatoriqn, ifacename) != IQN_FOUND) {
+        VIR_DEBUG("Failed to find interface '%s' with IQN '%s' "
+                  "after attempting to create it",
+                  &temp_ifacename[0], initiatoriqn);
+        goto cleanup;
+    } else {
+        VIR_DEBUG("Interface '%s' with IQN '%s' was created successfully",
+                  *ifacename, initiatoriqn);
+    }
+
+    ret = 0;
+
+cleanup:
+    virCommandFree(cmd);
+    VIR_FREE(temp_ifacename);
+    if (ret != 0)
+        VIR_FREE(*ifacename);
+    return ret;
+}
+
+
+static int
+virISCSIConnection(const char *portal,
+                   const char *initiatoriqn,
+                   const char *target,
+                   const char **extraargv)
+{
+    int ret = -1;
+    const char *const baseargv[] = {
+        ISCSIADM,
+        "--mode", "node",
+        "--portal", portal,
+        "--targetname", target,
+        NULL
+    };
+    virCommandPtr cmd;
+    char *ifacename = NULL;
+
+    cmd = virCommandNewArgs(baseargv);
+    virCommandAddArgSet(cmd, extraargv);
+
+    if (initiatoriqn) {
+        switch (virStorageBackendIQNFound(initiatoriqn, &ifacename)) {
+        case IQN_FOUND:
+            VIR_DEBUG("ifacename: '%s'", ifacename);
+            break;
+        case IQN_MISSING:
+            if (virStorageBackendCreateIfaceIQN(initiatoriqn,
+                                                &ifacename) != 0) {
+                goto cleanup;
+            }
+            break;
+        case IQN_ERROR:
+        default:
+            goto cleanup;
+        }
+        virCommandAddArgList(cmd, "--interface", ifacename, NULL);
+    }
+
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virCommandFree(cmd);
+    VIR_FREE(ifacename);
+
+    return ret;
+}
+
+
+int
+virISCSIConnectionLogin(const char *portal,
+                        const char *initiatoriqn,
+                        const char *target)
+{
+    const char *extraargv[] = { "--login", NULL };
+    return virISCSIConnection(portal, initiatoriqn, target, extraargv);
+}
+
+
+int
+virISCSIConnectionLogout(const char *portal,
+                         const char *initiatoriqn,
+                         const char *target)
+{
+    const char *extraargv[] = { "--logout", NULL };
+    return virISCSIConnection(portal, initiatoriqn, target, extraargv);
+}
+
+
+int
+virISCSIRescanLUNs(const char *session)
+{
+    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
+                                             "--mode", "session",
+                                             "-r", session,
+                                             "-R",
+                                             NULL);
+    int ret = virCommandRun(cmd, NULL);
+    virCommandFree(cmd);
+    return ret;
+}
+
+
+struct virISCSITargetList {
+    size_t ntargets;
+    char **targets;
+};
+
+
+static int
+virISCSIGetTargets(char **const groups,
+                   void *data)
+{
+    struct virISCSITargetList *list = data;
+    char *target;
+
+    if (VIR_STRDUP(target, groups[1]) < 0)
+        return -1;
+
+    if (VIR_APPEND_ELEMENT(list->targets, list->ntargets, target) < 0) {
+        VIR_FREE(target);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+virISCSITargetAutologin(const char *portal,
+                        const char *initiatoriqn,
+                        const char *target,
+                        bool enable)
+{
+    const char *extraargv[] = { "--op", "update",
+                                "--name", "node.startup",
+                                "--value", enable ? "automatic" : "manual",
+                                NULL };
+
+    return virISCSIConnection(portal, initiatoriqn, target, extraargv);
+}
+
+
+int
+virISCSIScanTargets(const char *portal,
+                    const char *initiatoriqn,
+                    size_t *ntargetsret,
+                    char ***targetsret)
+{
+    /**
+     *
+     * The output of sendtargets is very simple, just two columns,
+     * portal then target name
+     *
+     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo0.bf6d84
+     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo1.bf6d84
+     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo2.bf6d84
+     * 192.168.122.185:3260,1 iqn.2004-04.com:fedora14:iscsi.demo3.bf6d84
+     */
+    const char *regexes[] = {
+        "^\\s*(\\S+)\\s+(\\S+)\\s*$"
+    };
+    int vars[] = { 2 };
+    struct virISCSITargetList list;
+    size_t i;
+    int ret = -1;
+    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
+                                             "--mode", "discovery",
+                                             "--type", "sendtargets",
+                                             "--portal", portal,
+                                             NULL);
+
+    memset(&list, 0, sizeof(list));
+
+    if (virCommandRunRegex(cmd,
+                           1,
+                           regexes,
+                           vars,
+                           virISCSIGetTargets,
+                           &list, NULL) < 0)
+        goto cleanup;
+
+    for (i = 0; i < list.ntargets; i++) {
+        /* We have to ignore failure, because we can't undo
+         * the results of 'sendtargets', unless we go scrubbing
+         * around in the dirt in /var/lib/iscsi.
+         */
+        if (virISCSITargetAutologin(portal,
+                                    initiatoriqn,
+                                    list.targets[i], false) < 0)
+            VIR_WARN("Unable to disable auto-login on iSCSI target %s: %s",
+                     portal, list.targets[i]);
+    }
+
+    if (ntargetsret && targetsret) {
+        *ntargetsret = list.ntargets;
+        *targetsret = list.targets;
+    } else {
+        for (i = 0; i < list.ntargets; i++) {
+            VIR_FREE(list.targets[i]);
+        }
+        VIR_FREE(list.targets);
+    }
+
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
+}
+
+
+int
+virISCSINodeUpdate(const char *portal,
+                   const char *target,
+                   const char *name,
+                   const char *value)
+{
+    virCommandPtr cmd = NULL;
+    int status;
+    int ret = -1;
+
+    cmd = virCommandNewArgList(ISCSIADM,
+                               "--mode", "node",
+                               "--portal", portal,
+                               "--target", target,
+                               "--op", "update",
+                               "--name", name,
+                               "--value", value,
+                               NULL);
+
+    /* Ignore non-zero status.  */
+    if (virCommandRun(cmd, &status) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to update '%s' of node mode for target '%s'"),
+                       name, target);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
+}
diff --git a/src/util/viriscsi.h b/src/util/viriscsi.h
new file mode 100644
index 0000000..462e56a
--- /dev/null
+++ b/src/util/viriscsi.h
@@ -0,0 +1,52 @@
+/*
+ * viriscsi.h: helper APIs for managing iSCSI
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_ISCSI_H__
+# define __VIR_ISCSI_H__
+
+# include "internal.h"
+
+char *
+virISCSIGetSession(const char *devpath,
+                   bool probe);
+
+int
+virISCSIConnectionLogin(const char *portal,
+                        const char *initiatoriqn,
+                        const char *target);
+int
+virISCSIConnectionLogout(const char *portal,
+                         const char *initiatoriqn,
+                         const char *target);
+int
+virISCSIRescanLUNs(const char *session);
+
+int
+virISCSIScanTargets(const char *portal,
+                    const char *initiatoriqn,
+                    size_t *ntargetsret,
+                    char ***targetsret);
+int
+virISCSINodeUpdate(const char *portal,
+                   const char *target,
+                   const char *name,
+                   const char *value);
+#endif
-- 
1.8.3.2




More information about the libvir-list mailing list