From 62f653f4b8742c52f48e8fdbba4e61fbbc207592 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 07 2019 04:32:14 +0000 Subject: import iscsi-initiator-utils-6.2.0.876-7.gitf3c8e90.el8 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba87e71 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/open-iscsi-f3c8e90.tar.gz diff --git a/.iscsi-initiator-utils.metadata b/.iscsi-initiator-utils.metadata new file mode 100644 index 0000000..a0fef4e --- /dev/null +++ b/.iscsi-initiator-utils.metadata @@ -0,0 +1 @@ +fdf8ac2fc45f493bdc005bb6739406b65126b31f SOURCES/open-iscsi-f3c8e90.tar.gz diff --git a/SOURCES/0001-idmb_rec_write-check-for-tpgt-first.patch b/SOURCES/0001-idmb_rec_write-check-for-tpgt-first.patch new file mode 100644 index 0000000..220f693 --- /dev/null +++ b/SOURCES/0001-idmb_rec_write-check-for-tpgt-first.patch @@ -0,0 +1,54 @@ +From dbec0a5b7737142f8a1462cdf826c35a78e899b2 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 10:59:44 -0700 +Subject: [PATCH 01/32] idmb_rec_write, check for tpgt first + +Factor out the check for a tpgt to a single place, before going crazy on +the rec files. Makes flow of this function easier to follow, and preps +for splitting it up. +--- + usr/idbm.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/usr/idbm.c b/usr/idbm.c +index 830189f571ea..ab3577878e86 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2042,6 +2042,10 @@ static int idbm_rec_write(node_rec_t *rec) + if (rc) + goto free_portal; + ++ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ /* drop down to old style portal as config */ ++ goto open_conf; ++ + rc = stat(portal, &statb); + if (rc) { + rc = 0; +@@ -2050,22 +2054,10 @@ static int idbm_rec_write(node_rec_t *rec) + * set the tgpt. In new versions you must pass all the info in + * from the start + */ +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; +- else +- goto mkdir_portal; ++ goto mkdir_portal; + } + + if (!S_ISDIR(statb.st_mode)) { +- /* +- * older iscsiadm versions had you create the config then set +- * set the tgpt. In new versions you must pass all the info in +- * from the start +- */ +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; + /* + * Old style portal as a file, but with tpgt. Let's update it. + */ +-- +2.14.4 + diff --git a/SOURCES/0002-idbm_rec_write-seperate-old-and-new-style-writes.patch b/SOURCES/0002-idbm_rec_write-seperate-old-and-new-style-writes.patch new file mode 100644 index 0000000..fb96724 --- /dev/null +++ b/SOURCES/0002-idbm_rec_write-seperate-old-and-new-style-writes.patch @@ -0,0 +1,180 @@ +From b9d89091daab823eb2dc72c6c568af7897f83137 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 11:34:31 -0700 +Subject: [PATCH 02/32] idbm_rec_write, seperate old and new style writes + +Duplicates a small bit of code, but easier to understand and extened. +--- + usr/idbm.c | 116 +++++++++++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 79 insertions(+), 37 deletions(-) + +diff --git a/usr/idbm.c b/usr/idbm.c +index ab3577878e86..21ff61ab2bd8 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2001,7 +2001,7 @@ mkdir_portal: + return f; + } + +-static int idbm_rec_write(node_rec_t *rec) ++static int idbm_rec_write_new(node_rec_t *rec) + { + struct stat statb; + FILE *f; +@@ -2013,38 +2013,8 @@ static int idbm_rec_write(node_rec_t *rec) + log_error("Could not alloc portal"); + return ISCSI_ERR_NOMEM; + } +- +- snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); +- if (access(portal, F_OK) != 0) { +- if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s", portal, +- strerror(errno)); +- rc = ISCSI_ERR_IDBM; +- goto free_portal; +- } +- } +- +- snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); +- if (access(portal, F_OK) != 0) { +- if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s", portal, +- strerror(errno)); +- rc = ISCSI_ERR_IDBM; +- goto free_portal; +- } +- } +- + snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port); +- log_debug(5, "Looking for config file %s", portal); +- +- rc = idbm_lock(); +- if (rc) +- goto free_portal; +- +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; + + rc = stat(portal, &statb); + if (rc) { +@@ -2065,11 +2035,11 @@ static int idbm_rec_write(node_rec_t *rec) + log_error("Could not convert %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + } else { + rc = ISCSI_ERR_INVAL; +- goto unlock; ++ goto free_portal; + } + + mkdir_portal: +@@ -2080,24 +2050,96 @@ mkdir_portal: + log_error("Could not make dir %s: %s", + portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + } + + snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt, + rec->iface.name); +-open_conf: ++/* open_conf: */ + f = fopen(portal, "w"); + if (!f) { + log_error("Could not open %s: %s", portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + + idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); + fclose(f); +-unlock: ++free_portal: ++ free(portal); ++ return rc; ++} ++ ++static int idbm_rec_write_old(node_rec_t *rec) ++{ ++ FILE *f; ++ char *portal; ++ int rc = 0; ++ ++ portal = malloc(PATH_MAX); ++ if (!portal) { ++ log_error("Could not alloc portal"); ++ return ISCSI_ERR_NOMEM; ++ } ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ ++ f = fopen(portal, "w"); ++ if (!f) { ++ log_error("Could not open %s: %sd", portal, strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); ++ fclose(f); ++free_portal: ++ free(portal); ++ return rc; ++} ++ ++static int idbm_rec_write(node_rec_t *rec) ++{ ++ char *portal; ++ int rc = 0; ++ ++ portal = malloc(PATH_MAX); ++ if (!portal) { ++ log_error("Could not alloc portal"); ++ return ISCSI_ERR_NOMEM; ++ } ++ ++ snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); ++ if (access(portal, F_OK) != 0) { ++ if (mkdir(portal, 0660) != 0) { ++ log_error("Could not make %s: %s", portal, ++ strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ } ++ ++ snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); ++ if (access(portal, F_OK) != 0) { ++ if (mkdir(portal, 0660) != 0) { ++ log_error("Could not make %s: %s", portal, ++ strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ } ++ ++ rc = idbm_lock(); ++ if (rc) ++ goto free_portal; ++ ++ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ /* old style portal as config */ ++ rc = idbm_rec_write_old(rec); ++ else ++ rc = idbm_rec_write_new(rec); ++ + idbm_unlock(); + free_portal: + free(portal); +-- +2.14.4 + diff --git a/SOURCES/0003-idbw_rec_write-pick-tpgt-from-existing-record.patch b/SOURCES/0003-idbw_rec_write-pick-tpgt-from-existing-record.patch new file mode 100644 index 0000000..5e2469f --- /dev/null +++ b/SOURCES/0003-idbw_rec_write-pick-tpgt-from-existing-record.patch @@ -0,0 +1,87 @@ +From 7ba6464018daac1b150335bb73d272761d2cbfe5 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 12:39:07 -0700 +Subject: [PATCH 03/32] idbw_rec_write, pick tpgt from existing record + +On a static add (-m node -o new) without a user specified tpgt, looks +for existing new style records with tpgt before creating an old style +record without. If one exists, take the tpgt from it an write an +updated new style record instead. +--- + usr/idbm.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/usr/idbm.c b/usr/idbm.c +index 21ff61ab2bd8..cd705fa2b033 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -163,6 +164,8 @@ static struct idbm *db; + _n++; \ + } while(0) + ++static int idbm_remove_disc_to_node_link(node_rec_t *rec, char *portal); ++ + static void + idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) + { +@@ -2077,12 +2080,49 @@ static int idbm_rec_write_old(node_rec_t *rec) + FILE *f; + char *portal; + int rc = 0; ++ glob_t globbuf; ++ int i; ++ int tpgt = PORTAL_GROUP_TAG_UNKNOWN; + + portal = malloc(PATH_MAX); + if (!portal) { + log_error("Could not alloc portal"); + return ISCSI_ERR_NOMEM; + } ++ ++ /* check for newer portal dir with tpgt */ ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,*", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ rc = glob(portal, GLOB_ONLYDIR, NULL, &globbuf); ++ if (!rc) { ++ if (globbuf.gl_pathc > 1) ++ log_warning("multiple tpg records for portal " ++ "%s/%s:%d found", rec->name, ++ rec->conn[0].address, rec->conn[0].port); ++ /* set pattern for sscanf matching of tpgt */ ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%%u", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ for (i = 0; i < globbuf.gl_pathc; i++) { ++ rc = sscanf(globbuf.gl_pathv[i], portal, &tpgt); ++ if (rc == 1) ++ break; ++ } ++ if (tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ log_warning("glob match on existing records, " ++ "but no valid tpgt found"); ++ } ++ globfree(&globbuf); ++ rc = 0; ++ ++ /* if a tpgt was selected from an old record, write entry in new format */ ++ if (tpgt != PORTAL_GROUP_TAG_UNKNOWN) { ++ log_warning("using tpgt %u from existing record", tpgt); ++ rec->tpgt = tpgt; ++ rc = idbm_remove_disc_to_node_link(rec, portal); ++ free(portal); ++ return idbm_rec_write_new(rec); ++ } ++ + snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port); + +-- +2.14.4 + diff --git a/SOURCES/0004-update-systemd-service-files-add-iscsi.service-for-s.patch b/SOURCES/0004-update-systemd-service-files-add-iscsi.service-for-s.patch new file mode 100644 index 0000000..ebe1650 --- /dev/null +++ b/SOURCES/0004-update-systemd-service-files-add-iscsi.service-for-s.patch @@ -0,0 +1,93 @@ +From 33076c9c1e975ea3225923d66ae24648c0c82a7f Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 19 Dec 2012 15:07:36 -0800 +Subject: [PATCH 04/32] update systemd service files, add iscsi.service for + starting sessions on boot + +Signed-off-by: Chris Leech +--- + etc/systemd/iscsi.service | 19 +++++++++++++++++++ + etc/systemd/iscsi_mark_root_nodes | 14 ++++++++++++++ + etc/systemd/iscsid.service | 7 +++++-- + etc/systemd/iscsid.socket | 2 +- + 4 files changed, 39 insertions(+), 3 deletions(-) + create mode 100644 etc/systemd/iscsi.service + create mode 100755 etc/systemd/iscsi_mark_root_nodes + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +new file mode 100644 +index 000000000000..bbd52fd66890 +--- /dev/null ++++ b/etc/systemd/iscsi.service +@@ -0,0 +1,19 @@ ++[Unit] ++Description=Login and scanning of iSCSI devices ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++ConditionPathExists=/etc/iscsi/initiatorname.iscsi ++ ++[Service] ++Type=oneshot ++RemainAfterExit=true ++ExecStart=/usr/libexec/iscsi_mark_root_nodes ++ExecStart=/sbin/iscsiadm -m node --loginall=automatic ++ExecStop=/bin/sync ++ExecStop=/sbin/iscsiadm -m node --logoutall=automatic ++ ++[Install] ++WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes +new file mode 100755 +index 000000000000..c68475c44de5 +--- /dev/null ++++ b/etc/systemd/iscsi_mark_root_nodes +@@ -0,0 +1,14 @@ ++#!/bin/bash ++ ++ISCSIADM=/sbin/iscsiadm ++SESSION_FILE=/run/initramfs/iscsi.sessions ++ ++if [ ! -f $SESSION_FILE ] ; then ++ exit 0 ++fi ++ ++while read t num i target; do ++ ip=${i%:*} ++ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot ++done < $SESSION_FILE ++ +diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service +index 028e0b3f4e59..653dd085bbdd 100644 +--- a/etc/systemd/iscsid.service ++++ b/etc/systemd/iscsid.service +@@ -1,7 +1,10 @@ + [Unit] + Description=Open-iSCSI +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) +-After=network.target NetworkManager-wait-online.service iscsiuio.service tgtd.service targetcli.service ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=network.target iscsiuio.service ++Before=remote-fs-pre.target + + [Service] + Type=forking +diff --git a/etc/systemd/iscsid.socket b/etc/systemd/iscsid.socket +index 832451d7a0ce..58a8d1239996 100644 +--- a/etc/systemd/iscsid.socket ++++ b/etc/systemd/iscsid.socket +@@ -1,6 +1,6 @@ + [Unit] + Description=Open-iSCSI iscsid Socket +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) ++Documentation=man:iscsid(8) man:iscsiadm(8) + + [Socket] + ListenStream=@ISCSIADM_ABSTRACT_NAMESPACE +-- +2.14.4 + diff --git a/SOURCES/0005-iscsi-boot-related-service-file-updates.patch b/SOURCES/0005-iscsi-boot-related-service-file-updates.patch new file mode 100644 index 0000000..bf39a76 --- /dev/null +++ b/SOURCES/0005-iscsi-boot-related-service-file-updates.patch @@ -0,0 +1,75 @@ +From 5dd8fc7d27204a3461b33defed1e0bb4331c7663 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Aug 2013 07:18:25 -0700 +Subject: [PATCH 05/32] iscsi boot related service file updates + +make sure iscsid gets started if there are any boot sessions running +add reload target to fix double session problem when restarting from NM +don't rely on session list passed from initrd, never got fully implemented +--- + etc/systemd/iscsi-mark-root-nodes | 13 +++++++++++++ + etc/systemd/iscsi.service | 3 ++- + etc/systemd/iscsi_mark_root_nodes | 14 -------------- + 3 files changed, 15 insertions(+), 15 deletions(-) + create mode 100644 etc/systemd/iscsi-mark-root-nodes + delete mode 100755 etc/systemd/iscsi_mark_root_nodes + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +new file mode 100644 +index 000000000000..157be62b4041 +--- /dev/null ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -0,0 +1,13 @@ ++#!/bin/bash ++ ++ISCSIADM=/sbin/iscsiadm ++ ++$ISCSIADM -m session >/dev/null 2>&1 || exit 0 ++ ++$ISCSIADM -m session | while read t num i target; do ++ ip=${i%:*} ++ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot ++done ++ ++systemctl start iscsid.service ++ +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index bbd52fd66890..0309e2fc9892 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -10,10 +10,11 @@ ConditionPathExists=/etc/iscsi/initiatorname.iscsi + [Service] + Type=oneshot + RemainAfterExit=true +-ExecStart=/usr/libexec/iscsi_mark_root_nodes ++ExecStart=/usr/libexec/iscsi-mark-root-nodes + ExecStart=/sbin/iscsiadm -m node --loginall=automatic + ExecStop=/bin/sync + ExecStop=/sbin/iscsiadm -m node --logoutall=automatic ++ExecReload=/sbin/iscsiadm -m node --loginall=automatic + + [Install] + WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes +deleted file mode 100755 +index c68475c44de5..000000000000 +--- a/etc/systemd/iscsi_mark_root_nodes ++++ /dev/null +@@ -1,14 +0,0 @@ +-#!/bin/bash +- +-ISCSIADM=/sbin/iscsiadm +-SESSION_FILE=/run/initramfs/iscsi.sessions +- +-if [ ! -f $SESSION_FILE ] ; then +- exit 0 +-fi +- +-while read t num i target; do +- ip=${i%:*} +- $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot +-done < $SESSION_FILE +- +-- +2.14.4 + diff --git a/SOURCES/0006-update-initscripts-and-docs.patch b/SOURCES/0006-update-initscripts-and-docs.patch new file mode 100644 index 0000000..9abcf52 --- /dev/null +++ b/SOURCES/0006-update-initscripts-and-docs.patch @@ -0,0 +1,127 @@ +From 2e6f564ebb3c85cb9a457d282b845374776a54ae Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:37:13 -0800 +Subject: [PATCH 06/32] update initscripts and docs + +--- + README | 10 ++++------ + etc/iscsid.conf | 21 ++++++++++----------- + usr/idbm.c | 4 ++++ + 3 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/README b/README +index 2499d9a7b638..c05814a2593b 100644 +--- a/README ++++ b/README +@@ -77,11 +77,6 @@ the cache sync command will fail. + - iscsiadm's -P 3 option will not print out scsi devices. + - iscsid will not automatically online devices. + +-You need to enable "Cryptographic API" under "Cryptographic options" in the +-kernel config. And you must enable "CRC32c CRC algorithm" even if +-you do not use header or data digests. They are the kernel options +-CONFIG_CRYPTO and CONFIG_CRYPTO_CRC32C, respectively. +- + The userspace components iscsid, iscsiadm and iscsistart require the + open-isns library, which can be found here: + https://github.com/gonzoleeman/open-isns/releases +@@ -1151,7 +1146,7 @@ Red Hat or Fedora: + ----------------- + To start open-iscsi in Red Hat/Fedora you can do: + +- service open-iscsi start ++ service iscsi start + + To get open-iscsi to automatically start at run time you may have to + run: +@@ -1353,6 +1348,9 @@ iscsid will only perform rediscovery when it gets a SCN from the server. + # linux-isns (SLES's iSNS server) where it sometimes does not send SCN + # events in the proper format, so they may not get handled. + ++To set the startup value, so that nodes are not logged into automatically ++use the value "manual". ++ + Examples + -------- + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index fee11482a09b..3539ac4cd578 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -19,7 +19,7 @@ + # the time then leave this attribute commented out. + # + # Default for Fedora and RHEL. (uncomment to activate). +-# iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.soccket ++iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket + # + # Default if you are not using systemd (uncomment to activate) + # iscsid.startup = /usr/bin/service start iscsid +@@ -41,8 +41,8 @@ + # To request that the iscsi initd scripts startup a session set to "automatic". + # node.startup = automatic + # +-# To manually startup the session set to "manual". The default is manual. +-node.startup = manual ++# To manually startup the session set to "manual". The default is automatic. ++node.startup = automatic + + # For "automatic" startup nodes, setting this to "Yes" will try logins on each + # available iface until one succeeds, and then stop. The default "No" will try +@@ -264,28 +264,27 @@ node.conn[0].iscsi.MaxXmitDataSegmentLength = 0 + discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 + + # To allow the targets to control the setting of the digest checking, +-# with the initiator requesting a preference of enabling the checking, uncomment# one or both of the following lines: ++# with the initiator requesting a preference of enabling the checking, uncomment ++# the following lines (Data digests are not supported.): + #node.conn[0].iscsi.HeaderDigest = CRC32C,None +-#node.conn[0].iscsi.DataDigest = CRC32C,None ++ + # + # To allow the targets to control the setting of the digest checking, + # with the initiator requesting a preference of disabling the checking, +-# uncomment one or both of the following lines: ++# uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = None,CRC32C +-#node.conn[0].iscsi.DataDigest = None,CRC32C + # + # To enable CRC32C digest checking for the header and/or data part of +-# iSCSI PDUs, uncomment one or both of the following lines: ++# iSCSI PDUs, uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = CRC32C +-#node.conn[0].iscsi.DataDigest = CRC32C + # + # To disable digest checking for the header and/or data part of +-# iSCSI PDUs, uncomment one or both of the following lines: ++# iSCSI PDUs, uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = None +-#node.conn[0].iscsi.DataDigest = None + # + # The default is to never use DataDigests or HeaderDigests. + # ++node.conn[0].iscsi.HeaderDigest = None + + # For multipath configurations, you may want more than one session to be + # created on each iface record. If node.session.nr_sessions is greater +diff --git a/usr/idbm.c b/usr/idbm.c +index cd705fa2b033..0aa3870a76fd 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -518,9 +518,13 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + IDBM_SHOW, "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); + sprintf(key, CONN_DATA_DIGEST, i); ++ ++#if 0 ++We do not support data digests + __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW, + "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); ++#endif + sprintf(key, CONN_IFMARKER, i); + __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW, + "No", "Yes", num, 1); +-- +2.14.4 + diff --git a/SOURCES/0007-use-var-for-config.patch b/SOURCES/0007-use-var-for-config.patch new file mode 100644 index 0000000..1690126 --- /dev/null +++ b/SOURCES/0007-use-var-for-config.patch @@ -0,0 +1,241 @@ +From 478527833bdb8ebc9f4523c54e544b244bfe76f1 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:38:45 -0800 +Subject: [PATCH 07/32] use var for config + +--- + README | 33 ++++++++++++++++----------------- + doc/iscsiadm.8 | 8 ++++---- + usr/idbm.c | 6 +++--- + usr/idbm.h | 13 +++++++------ + usr/iface.h | 3 ++- + 5 files changed, 32 insertions(+), 31 deletions(-) + +diff --git a/README b/README +index c05814a2593b..326c3b01e608 100644 +--- a/README ++++ b/README +@@ -172,8 +172,7 @@ Usage: iscsid [OPTION] + + Open-iSCSI persistent configuration is stored in a number of + directories under a configuration root directory, using a flat-file +-format. This configuration root directory is /etc/iscsi by default, +-but may also commonly be in /var/lib/iscsi. ++format. This configuration root directory is /var/lib/iscsi by default. + + Configuration is contained in directories for: + +@@ -561,7 +560,7 @@ a scsi_host per HBA port). + To manage both types of initiator stacks, iscsiadm uses the interface (iface) + structure. For each HBA port or for software iscsi for each network + device (ethX) or NIC, that you wish to bind sessions to you must create +-a iface config /etc/iscsi/ifaces. ++a iface config /var/lib/iscsi/ifaces. + + Prep + ---- +@@ -594,7 +593,7 @@ Running + The command + iscsiadm -m iface + +-will report iface configurations that are setup in /etc/iscsi/ifaces: ++will report iface configurations that are setup in /var/lib/iscsi/ifaces: + + iface0 qla4xxx,00:c0:dd:08:63:e8,20.15.0.7,default,iqn.2005-06.com.redhat:madmax + iface1 qla4xxx,00:c0:dd:08:63:ea,20.15.0.9,default,iqn.2005-06.com.redhat:madmax +@@ -604,10 +603,10 @@ The format is: + + For software iscsi, you can create the iface configs by hand, but it is + recommended that you use iscsiadm's iface mode. There is an iface.example in +-/etc/iscsi/ifaces which can be used as a template for the daring. ++/var/lib/iscsi/ifaces which can be used as a template for the daring. + + For each network object you wish to bind a session to, you must create +-a separate iface config in /etc/iscsi/ifaces and each iface config file ++a separate iface config in /var/lib/iscsi/ifaces and each iface config file + must have a unique name which is less than or equal to 64 characters. + + Example +@@ -615,12 +614,12 @@ Example + + If you have NIC1 with MAC address 00:0F:1F:92:6B:BF and NIC2 with + MAC address 00:C0:DD:08:63:E7, and you wanted to do software iscsi over +-TCP/IP, then in /etc/iscsi/ifaces/iface0 you would enter: ++TCP/IP, then in /var/lib/iscsi/ifaces/iface0 you would enter: + + iface.transport_name = tcp + iface.hwaddress = 00:0F:1F:92:6B:BF + +-and in /etc/iscsi/ifaces/iface1 you would enter: ++and in /var/lib/iscsi/ifaces/iface1 you would enter: + + iface.transport_name = tcp + iface.hwaddress = 00:C0:DD:08:63:E7 +@@ -662,7 +661,7 @@ port. The iface name will be of the form: + Running the following command: + iscsiadm -m iface + +-will report iface configurations that are setup in /etc/iscsi/ifaces: ++will report iface configurations that are setup in /var/lib/iscsi/ifaces: + + default tcp,,,, + iser iser,,,, +@@ -742,7 +741,7 @@ need a separate network connection to the target for discovery purposes. + *This will be fixed in the next version of open-iscsi* + + For compatibility reasons, when you run iscsiadm to do discovery, it +-will check for interfaces in /etc/iscsi/iscsi/ifaces that are using ++will check for interfaces in /var/lib/iscsi/iscsi/ifaces that are using + tcp for the iface.transport, and it will bind the portals that are discovered + so that they will be logged in through those ifaces. This behavior can also + be overridden by passing in the interfaces you want to use. For the case +@@ -757,7 +756,7 @@ If you had defined interfaces but wanted the old behavior, where we do not + bind a session to an iface, then you can use the special iface "default": + iscsiadm -m discoverydb -t st -p ip:port -I default --discover -P 1 + +-And if you did not define any interfaces in /etc/iscsi/ifaces and do ++And if you did not define any interfaces in /var/lib/iscsi/ifaces and do + not pass anything into iscsiadm, running iscsiadm will do the default + behavior, allowing the network subsystem to decide which device to use. + +@@ -793,7 +792,7 @@ Discovery mode + ID [192.168.1.1:3260]: + iscsiadm -m discoverydb -t st -p 192.168.1.1:3260 --discover + +- This will search /etc/iscsi/send_targets for a record with the ++ This will search /var/lib/iscsi/send_targets for a record with the + ID [portal = 192.168.1.1:3260 and type = sendtargets. If found it + will perform discovery using the settings stored in the record. + If a record does not exist, it will be created using the iscsid.conf +@@ -802,7 +801,7 @@ Discovery mode + The argument to -p may also be a hostname instead of an address: + iscsiadm -m discoverydb -t st -p somehost --discover + +- For the ifaces, iscsiadm will first search /etc/iscsi/ifaces for ++ For the ifaces, iscsiadm will first search /var/lib/iscsi/ifaces for + interfaces using software iscsi. If any are found then nodes found + during discovery will be setup so that they can logged in through + those interfaces. To specify a specific iface, pass the +@@ -853,7 +852,7 @@ Discovery mode + + - SendTargets iSCSI Discovery with a specific interface. + If you wish to only use a subset of the interfaces in +- /etc/iscsi/ifaces, then you can pass them in during discovery: ++ /var/lib/iscsi/ifaces, then you can pass them in during discovery: + iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \ + --interface=iface0 --interface=iface1 --discover + +@@ -1223,8 +1222,8 @@ where targetname is the name of the target and ip_address:port is the address + and port of the portal. tpgt is the Target Portal Group Tag of + the portal, and is not used in iscsiadm commands except for static + record creation. ifacename is the name of the iscsi interface +-defined in /etc/iscsi/ifaces. If no interface was defined in +-/etc/iscsi/ifaces or passed in, the default behavior is used. ++defined in /var/lib/iscsi/ifaces. If no interface was defined in ++/var/lib/iscsi/ifaces or passed in, the default behavior is used. + Default here is iscsi_tcp/tcp to be used over whichever NIC the + network layer decides is best. + +@@ -1336,7 +1335,7 @@ If set, iscsid will perform discovery to the address every + discovery.isns.discoveryd_poll_inval or + discovery.sendtargets.discoveryd_poll_inval seconds, + and it will log into any portals found from the discovery source using +-the ifaces in /etc/iscsi/ifaces. ++the ifaces in /var/lib/iscsi/ifaces. + + Note that for iSNS the poll_interval does not have to be set. If not set, + iscsid will only perform rediscovery when it gets a SCN from the server. +diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 +index a82805e28fb9..758a47c2d1fe 100644 +--- a/doc/iscsiadm.8 ++++ b/doc/iscsiadm.8 +@@ -241,7 +241,7 @@ This option is only valid for ping submode. + .TP + \fB\-I\fR, \fB\-\-interface=\fI[iface]\fR + The interface argument specifies the iSCSI interface to use for the operation. +-iSCSI interfaces (iface) are defined in /etc/iscsi/ifaces. For hardware ++iSCSI interfaces (iface) are defined in /var/lib/iscsi/ifaces. For hardware + iSCSI (qla4xxx) the iface config must have the hardware address + (iface.hwaddress = port's MAC address) + and the driver/transport_name (iface.transport_name). The iface's name is +@@ -318,7 +318,7 @@ If no other options are specified: for \fIdiscovery\fR, \fIdiscoverydb\fR and + \fInode\fR, all of their respective records are displayed; for \fIsession\fR, + all active sessions and connections are displayed; for \fIfw\fR, all boot + firmware values are displayed; for \fIhost\fR, all iSCSI hosts are displayed; +-and for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed. ++and for \fIiface\fR, all ifaces setup in /var/lib/iscsi/ifaces are displayed. + + .TP + \fB\-n\fR, \fB\-\-name=\fIname\fR +@@ -703,10 +703,10 @@ The configuration file read by \fBiscsid\fR and \fBiscsiadm\fR on startup. + The file containing the iSCSI InitiatorName and InitiatorAlias read by + \fBiscsid\fR and \fBiscsiadm\fR on startup. + .TP +-/etc/iscsi/nodes/ ++/var/lib/iscsi/nodes/ + This directory contains the nodes with their targets. + .TP +-/etc/iscsi/send_targets ++/var/lib/iscsi/send_targets + This directory contains the portals. + + .SH "SEE ALSO" +diff --git a/usr/idbm.c b/usr/idbm.c +index 0aa3870a76fd..ec33ce905dc1 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2926,9 +2926,9 @@ free_info: + int idbm_init(idbm_get_config_file_fn *fn) + { + /* make sure root db dir is there */ +- if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) { +- if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) { +- log_error("Could not make %s %d", ISCSI_CONFIG_ROOT, ++ if (access(ISCSIVAR, F_OK) != 0) { ++ if (mkdir(ISCSIVAR, 0660) != 0) { ++ log_error("Could not make %s %d", ISCSIVAR, + errno); + return errno; + } +diff --git a/usr/idbm.h b/usr/idbm.h +index b83c0bb1cca8..2b05d7871be9 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -29,12 +29,13 @@ + #include "list.h" + #include "flashnode.h" + +-#define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" +-#define SLP_CONFIG_DIR ISCSI_CONFIG_ROOT"slp" +-#define ISNS_CONFIG_DIR ISCSI_CONFIG_ROOT"isns" +-#define STATIC_CONFIG_DIR ISCSI_CONFIG_ROOT"static" +-#define FW_CONFIG_DIR ISCSI_CONFIG_ROOT"fw" +-#define ST_CONFIG_DIR ISCSI_CONFIG_ROOT"send_targets" ++#define ISCSIVAR "/var/lib/iscsi/" ++#define NODE_CONFIG_DIR ISCSIVAR"nodes" ++#define SLP_CONFIG_DIR ISCSIVAR"slp" ++#define ISNS_CONFIG_DIR ISCSIVAR"isns" ++#define STATIC_CONFIG_DIR ISCSIVAR"static" ++#define FW_CONFIG_DIR ISCSIVAR"fw" ++#define ST_CONFIG_DIR ISCSIVAR"send_targets" + #define ST_CONFIG_NAME "st_config" + #define ISNS_CONFIG_NAME "isns_config" + +diff --git a/usr/iface.h b/usr/iface.h +index 6c06f7f7d450..c8b9de9a7c3a 100644 +--- a/usr/iface.h ++++ b/usr/iface.h +@@ -21,8 +21,9 @@ + #define ISCSI_IFACE_H + + #include ++#include "idbm.h" + +-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" ++#define IFACE_CONFIG_DIR ISCSIVAR"ifaces" + + struct iface_rec; + struct list_head; +-- +2.14.4 + diff --git a/SOURCES/0008-use-red-hat-for-name.patch b/SOURCES/0008-use-red-hat-for-name.patch new file mode 100644 index 0000000..dc9b853 --- /dev/null +++ b/SOURCES/0008-use-red-hat-for-name.patch @@ -0,0 +1,39 @@ +From ea35362504329e7fe86f4af17a88bed009c5069c Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:40:04 -0800 +Subject: [PATCH 08/32] use red hat for name + +--- + doc/iscsi-iname.8 | 2 +- + utils/iscsi-iname.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/doc/iscsi-iname.8 b/doc/iscsi-iname.8 +index a55d666d1af3..dd77ed9f3165 100644 +--- a/doc/iscsi-iname.8 ++++ b/doc/iscsi-iname.8 +@@ -14,7 +14,7 @@ generates a unique iSCSI node name on every invocation. + Display help + .TP + .BI [-p=]\fIprefix\fP +-Use the prefix passed in instead of the default "iqn.2005-03.org.open-iscsi" ++Use the prefix passed in instead of the default "iqn.1994-05.com.redhat" + + .SH AUTHORS + Open-iSCSI project +diff --git a/utils/iscsi-iname.c b/utils/iscsi-iname.c +index 6347edc46293..cb2f6c8b8651 100644 +--- a/utils/iscsi-iname.c ++++ b/utils/iscsi-iname.c +@@ -73,7 +73,7 @@ main(int argc, char *argv[]) + exit(0); + } + } else { +- prefix = "iqn.2005-03.org.open-iscsi"; ++ prefix = "iqn.1994-05.com.redhat"; + } + + /* try to feed some entropy from the pool to MD5 in order to get +-- +2.14.4 + diff --git a/SOURCES/0009-libiscsi.patch b/SOURCES/0009-libiscsi.patch new file mode 100644 index 0000000..b90686b --- /dev/null +++ b/SOURCES/0009-libiscsi.patch @@ -0,0 +1,4014 @@ +From ef17e73261b386a21e231aa702c65e58ee8f65cc Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Mon, 26 Jan 2015 12:57:11 -0800 +Subject: [PATCH 09/32] libiscsi + +--- + Makefile | 2 + + libiscsi/Makefile | 61 ++ + libiscsi/libiscsi.c | 617 +++++++++++ + libiscsi/libiscsi.doxy | 1473 +++++++++++++++++++++++++++ + libiscsi/libiscsi.h | 344 +++++++ + libiscsi/no_date_footer.html | 6 + + libiscsi/pylibiscsi.c | 709 +++++++++++++ + libiscsi/setup.py | 9 + + libiscsi/tests/test_discovery_firmware.c | 53 + + libiscsi/tests/test_discovery_sendtargets.c | 60 ++ + libiscsi/tests/test_get_auth.c | 70 ++ + libiscsi/tests/test_get_initiator_name.c | 38 + + libiscsi/tests/test_get_network_config.c | 45 + + libiscsi/tests/test_login.c | 52 + + libiscsi/tests/test_logout.c | 51 + + libiscsi/tests/test_params.c | 103 ++ + libiscsi/tests/test_set_auth.c | 58 ++ + usr/Makefile | 2 +- + usr/discovery.c | 5 + + usr/idbm.c | 6 +- + usr/idbm.h | 3 + + usr/iscsi_ipc.h | 2 + + 22 files changed, 3765 insertions(+), 4 deletions(-) + create mode 100644 libiscsi/Makefile + create mode 100644 libiscsi/libiscsi.c + create mode 100644 libiscsi/libiscsi.doxy + create mode 100644 libiscsi/libiscsi.h + create mode 100644 libiscsi/no_date_footer.html + create mode 100644 libiscsi/pylibiscsi.c + create mode 100644 libiscsi/setup.py + create mode 100644 libiscsi/tests/test_discovery_firmware.c + create mode 100644 libiscsi/tests/test_discovery_sendtargets.c + create mode 100644 libiscsi/tests/test_get_auth.c + create mode 100644 libiscsi/tests/test_get_initiator_name.c + create mode 100644 libiscsi/tests/test_get_network_config.c + create mode 100644 libiscsi/tests/test_login.c + create mode 100644 libiscsi/tests/test_logout.c + create mode 100644 libiscsi/tests/test_params.c + create mode 100644 libiscsi/tests/test_set_auth.c + +diff --git a/Makefile b/Makefile +index c533e9d0d016..80afe86d6558 100644 +--- a/Makefile ++++ b/Makefile +@@ -52,6 +52,7 @@ user: iscsiuio/Makefile + $(MAKE) -C usr + $(MAKE) -C utils + $(MAKE) -C iscsiuio ++ $(MAKE) -C libiscsi + @echo + @echo "Compilation complete Output file" + @echo "----------------------------------- ----------------" +@@ -72,6 +73,7 @@ iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile + force: ; + + clean: ++ $(MAKE) -C libiscsi clean + $(MAKE) -C utils/sysdeps clean + $(MAKE) -C utils/fwparam_ibft clean + $(MAKE) -C utils clean +diff --git a/libiscsi/Makefile b/libiscsi/Makefile +new file mode 100644 +index 000000000000..317a7ec4db30 +--- /dev/null ++++ b/libiscsi/Makefile +@@ -0,0 +1,65 @@ ++# This Makefile will work only with GNU make. ++ ++ifeq ($(TOPDIR),) ++ TOPDIR = .. ++endif ++ ++OSNAME=$(shell uname -s) ++OPTFLAGS ?= -O2 -g ++WARNFLAGS ?= -Wall -Wstrict-prototypes ++CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \ ++ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden ++LIB = libiscsi.so.0 ++TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware ++TESTS += tests/test_login tests/test_logout tests/test_params ++TESTS += tests/test_get_network_config tests/test_get_initiator_name ++TESTS += tests/test_set_auth tests/test_get_auth ++ ++COMMON_SRCS = sysdeps.o ++# sources shared between iscsid, iscsiadm and iscsistart ++ISCSI_LIB_SRCS = netlink.o transport.o cxgbi.o be2iscsi.o iscsi_timer.o initiator_common.o iscsi_err.o session_info.o iscsi_util.o io.o auth.o discovery.o login.o log.o md5.o sha1.o iface.o idbm.o sysfs.o iscsi_sysfs.o iscsi_net_util.o iscsid_req.o iser.o uip_mgmt_ipc.o ++FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sysfs.o ++ ++# sources shared with the userspace utils, note we build these separately ++# to get PIC versions. ++COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS)) ++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o) ++FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS)) ++ ++# Flags for the tests ++tests/% : CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I. ++ ++all: lib tests html ++ ++lib: $(LIB) ++tests: $(TESTS) ++ ++common-objs/%.o: ../utils/sysdeps/%.c ++ mkdir -p common-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++usr-objs/%.o: ../usr/%.c ++ mkdir -p usr-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++fw-objs/%.o: ../utils/fwparam_ibft/%.c ++ mkdir -p fw-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++$(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o ++ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr ++ ln -s -f $(LIB) libiscsi.so ++ ++$(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB) ++ ++html: libiscsi.h libiscsi.doxy ++ doxygen libiscsi.doxy ++ ++clean: ++ rm -rf *.o common-objs usr-objs fw-objs libuip-objs libiscsi.so* \ ++ .depend *~ html $(TESTS) tests/*~ ++ ++depend: ++ gcc $(CFLAGS) -M `ls *.c` > .depend ++ ++-include .depend ../usr/.depend +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +new file mode 100644 +index 000000000000..064e4b570d0b +--- /dev/null ++++ b/libiscsi/libiscsi.c +@@ -0,0 +1,617 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++#include "idbm.h" ++#include "discovery.h" ++#include "log.h" ++#include "sysfs.h" ++#include "iscsi_sysfs.h" ++#include "session_info.h" ++#include "iscsi_util.h" ++#include "sysdeps.h" ++#include "iface.h" ++#include "iscsi_proto.h" ++#include "fw_context.h" ++#include "iscsid_req.h" ++#include "iscsi_err.h" ++ ++#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; } ++ ++/* UGLY, not thread safe :( */ ++static int sysfs_initialized = 0; ++ ++struct libiscsi_context { ++ char error_str[256]; ++ /* For get_parameter_helper() */ ++ const char *parameter; ++ char *value; ++}; ++ ++static void libiscsi_log(int prio, void *priv, const char *fmt, va_list ap) ++{ ++ struct libiscsi_context *context = priv; ++ ++ if (prio > LOG_ERR) /* We are only interested in errors (or worse) */ ++ return; ++ ++ vsnprintf(context->error_str, sizeof(context->error_str), fmt, ap); ++} ++ ++struct libiscsi_context *libiscsi_init(void) ++{ ++ struct libiscsi_context *context; ++ ++ context = calloc(1, sizeof *context); ++ if (!context) ++ return NULL; ++ ++ log_init("libiscsi", 1024, libiscsi_log, context); ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ increase_max_files(); ++ if (idbm_init(NULL)) { ++ sysfs_cleanup(); ++ free(context); ++ return NULL; ++ } ++ ++ iface_setup_host_bindings(); ++ ++ return context; ++} ++ ++void libiscsi_cleanup(struct libiscsi_context *context) ++{ ++ idbm_terminate(); ++ free_transports(); ++ sysfs_cleanup(); ++ free(context); ++} ++ ++static void free_iface_list(struct list_head *ifaces) ++{ ++ struct iface_rec *iface, *tmp_iface; ++ ++ list_for_each_entry_safe(iface, tmp_iface, ifaces, list) { ++ list_del(&iface->list); ++ free(iface); ++ } ++} ++ ++static void free_rec_list(struct list_head *rec_list) ++{ ++ struct node_rec *rec, *tmp; ++ ++ list_for_each_entry_safe(rec, tmp, rec_list, list) { ++ list_del(&rec->list); ++ free(rec); ++ } ++} ++ ++int libiscsi_discover_sendtargets(struct libiscsi_context *context, ++ const char *address, int port, ++ const struct libiscsi_auth_info *auth_info, ++ int *nr_found, struct libiscsi_node **found_nodes) ++{ ++ struct discovery_rec drec; ++ LIST_HEAD(bound_rec_list); ++ struct node_rec *rec; ++ int rc = 0, found = 0; ++ ++ INIT_LIST_HEAD(&bound_rec_list); ++ ++ if (nr_found) ++ *nr_found = 0; ++ if (found_nodes) ++ *found_nodes = NULL; ++ ++ CHECK(libiscsi_verify_auth_info(context, auth_info)) ++ ++ /* Fill the drec struct with all needed info */ ++ memset(&drec, 0, sizeof drec); ++ idbm_sendtargets_defaults(&drec.u.sendtargets); ++ drec.type = DISCOVERY_TYPE_SENDTARGETS; ++ strlcpy(drec.address, address, sizeof(drec.address)); ++ drec.port = port ? port : ISCSI_LISTEN_PORT; ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_chap: ++ drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP; ++ strlcpy(drec.u.sendtargets.auth.username, ++ auth_info->chap.username, AUTH_STR_MAX_LEN); ++ strlcpy((char *)drec.u.sendtargets.auth.password, ++ auth_info->chap.password, AUTH_STR_MAX_LEN); ++ drec.u.sendtargets.auth.password_length = ++ strlen((char *)drec.u.sendtargets.auth.password); ++ strlcpy(drec.u.sendtargets.auth.username_in, ++ auth_info->chap.reverse_username, AUTH_STR_MAX_LEN); ++ strlcpy((char *)drec.u.sendtargets.auth.password_in, ++ auth_info->chap.reverse_password, AUTH_STR_MAX_LEN); ++ drec.u.sendtargets.auth.password_in_length = ++ strlen((char *)drec.u.sendtargets.auth.password_in); ++ break; ++ } ++ ++ CHECK(idbm_add_discovery(&drec)) ++ ++ CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets, ++ &drec, NULL, &bound_rec_list)) ++ ++ /* now add/update records */ ++ list_for_each_entry(rec, &bound_rec_list, list) { ++ CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */)) ++ found++; ++ } ++ ++ if (nr_found) ++ *nr_found = found; ++ ++ if (found_nodes && found) { ++ *found_nodes = calloc(found, sizeof **found_nodes); ++ if (*found_nodes == NULL) { ++ snprintf(context->error_str, ++ sizeof(context->error_str), strerror(ENOMEM)); ++ rc = ENOMEM; ++ goto leave; ++ } ++ found = 0; ++ list_for_each_entry(rec, &bound_rec_list, list) { ++ strlcpy((*found_nodes)[found].name, rec->name, ++ LIBISCSI_VALUE_MAXLEN); ++ (*found_nodes)[found].tpgt = rec->tpgt; ++ strlcpy((*found_nodes)[found].address, ++ rec->conn[0].address, NI_MAXHOST); ++ (*found_nodes)[found].port = rec->conn[0].port; ++ strlcpy((*found_nodes)[found].iface, ++ rec->iface.name, LIBISCSI_VALUE_MAXLEN); ++ found++; ++ } ++ } ++ ++leave: ++ free_rec_list(&bound_rec_list); ++ return rc; ++} ++ ++int libiscsi_discover_firmware(struct libiscsi_context *context, ++ int *nr_found, struct libiscsi_node **found_nodes) ++{ ++ struct list_head targets, ifaces, rec_list; ++ discovery_rec_t drec; ++ int rc = 0; ++ ++ INIT_LIST_HEAD(&targets); ++ INIT_LIST_HEAD(&ifaces); ++ INIT_LIST_HEAD(&rec_list); ++ ++ if (nr_found) { ++ *nr_found = 0; ++ } ++ ++ if (found_nodes) { ++ *found_nodes = NULL; ++ } ++ ++ rc = fw_get_targets(&targets); ++ if (rc) { ++ log_error("%s: Could not get list of targets from firmware " ++ "(err %d).\n", __func__, rc); ++ return rc; ++ } ++ ++ CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets)); ++ ++ memset(&drec, 0, sizeof(drec)); ++ drec.type = DISCOVERY_TYPE_FW; ++ rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list); ++ if (rc) { ++ log_error("%s: Could not determine target nodes from firmware " ++ "(err %d).\n", __func__, rc); ++ goto leave; ++ } ++ ++ int node_count = 0; ++ struct list_head *pos; ++ list_for_each(pos, &rec_list) { ++ ++node_count; ++ } ++ ++ struct libiscsi_node* new_nodes; ++ /* allocate enough space for all the nodes */ ++ new_nodes = calloc(node_count, sizeof *new_nodes); ++ if (new_nodes == NULL) { ++ rc = ENOMEM; ++ log_error("%s: %s.\n", __func__, strerror(ENOMEM)); ++ goto leave; ++ } ++ ++ struct node_rec *rec; ++ struct libiscsi_node *new_node = new_nodes; ++ /* in one loop, add nodes to idbm and create libiscsi_node entries */ ++ list_for_each_entry(rec, &rec_list, list) { ++ CHECK(idbm_add_node(rec, NULL, 1 /* overwrite */)); ++ ++ strlcpy(new_node->name, rec->name, LIBISCSI_VALUE_MAXLEN); ++ new_node->tpgt = rec->tpgt; ++ strlcpy(new_node->address, rec->conn[0].address, NI_MAXHOST); ++ new_node->port = rec->conn[0].port; ++ strlcpy(new_node->iface, rec->iface.name, LIBISCSI_VALUE_MAXLEN); ++ ++ ++new_node; ++ } ++ ++ /* update output parameters */ ++ if (nr_found) { ++ *nr_found = node_count; ++ } ++ if (found_nodes) { ++ *found_nodes = new_nodes; ++ } ++ ++leave: ++ fw_free_targets(&targets); ++ ++ free_iface_list(&ifaces); ++ free_rec_list(&rec_list); ++ ++ return rc; ++} ++ ++int libiscsi_verify_auth_info(struct libiscsi_context *context, ++ const struct libiscsi_auth_info *auth_info) ++{ ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_none: ++ break; ++ case libiscsi_auth_chap: ++ if (!auth_info->chap.username[0]) { ++ strcpy(context->error_str, "Empty username"); ++ return EINVAL; ++ } ++ if (!auth_info->chap.password[0]) { ++ strcpy(context->error_str, "Empty password"); ++ return EINVAL; ++ } ++ if (auth_info->chap.reverse_username[0] && ++ !auth_info->chap.reverse_password[0]) { ++ strcpy(context->error_str, "Empty reverse password"); ++ return EINVAL; ++ } ++ break; ++ default: ++ sprintf(context->error_str, ++ "Invalid authentication method: %d", ++ (int)auth_info->method); ++ return EINVAL; ++ } ++ return 0; ++} ++ ++int libiscsi_node_set_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const struct libiscsi_auth_info *auth_info) ++{ ++ int rc = 0; ++ ++ CHECK(libiscsi_verify_auth_info(context, auth_info)) ++ ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_none: ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.authmethod", "None")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username_in", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password_in", "")) ++ break; ++ ++ case libiscsi_auth_chap: ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.authmethod", "CHAP")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username", ++ auth_info->chap.username)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password", ++ auth_info->chap.password)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username_in", ++ auth_info->chap.reverse_username)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password_in", ++ auth_info->chap.reverse_password)) ++ break; ++ } ++leave: ++ return rc; ++} ++ ++int libiscsi_node_get_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ struct libiscsi_auth_info *auth_info) ++{ ++ int rc = 0; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ memset(auth_info, 0, sizeof *auth_info); ++ ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.authmethod", value)) ++ ++ if (!strcmp(value, "None")) { ++ auth_info->method = libiscsi_auth_none; ++ } else if (!strcmp(value, "CHAP")) { ++ auth_info->method = libiscsi_auth_chap; ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.username", ++ auth_info->chap.username)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.password", ++ auth_info->chap.password)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.username_in", ++ auth_info->chap.reverse_username)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.password_in", ++ auth_info->chap.reverse_password)) ++ } else { ++ snprintf(context->error_str, sizeof(context->error_str), ++ "unknown authentication method: %s", value); ++ rc = EINVAL; ++ } ++leave: ++ return rc; ++} ++ ++static void node_to_rec(const struct libiscsi_node *node, ++ struct node_rec *rec) ++{ ++ memset(rec, 0, sizeof *rec); ++ idbm_node_setup_defaults(rec); ++ strlcpy(rec->name, node->name, TARGET_NAME_MAXLEN); ++ rec->tpgt = node->tpgt; ++ strlcpy(rec->conn[0].address, node->address, NI_MAXHOST); ++ rec->conn[0].port = node->port; ++} ++ ++int login_helper(void *data, node_rec_t *rec) ++{ ++ char *iface = (char*)data; ++ if (strcmp(iface, rec->iface.name)) ++ /* different iface, skip it */ ++ return -1; ++ ++ int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec); ++ if (rc) { ++ iscsi_err_print_msg(rc); ++ rc = ENOTCONN; ++ } ++ return rc; ++} ++ ++int libiscsi_node_login(struct libiscsi_context *context, ++ const struct libiscsi_node *node) ++{ ++ int nr_found = 0, rc; ++ ++ CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++static int logout_helper(void *data, struct session_info *info) ++{ ++ int rc; ++ struct node_rec *rec = data; ++ ++ if (!iscsi_match_session(rec, info)) ++ /* Tell iscsi_sysfs_for_each_session this session was not a ++ match so that it will not increase nr_found. */ ++ return -1; ++ ++ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid); ++ if (rc) { ++ iscsi_err_print_msg(rc); ++ rc = EIO; ++ } ++ ++ return rc; ++} ++ ++int libiscsi_node_logout(struct libiscsi_context *context, ++ const struct libiscsi_node *node) ++{ ++ int nr_found = 0, rc; ++ struct node_rec rec; ++ ++ node_to_rec(node, &rec); ++ CHECK(iscsi_sysfs_for_each_session(&rec, &nr_found, logout_helper,0)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No matching session"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++int libiscsi_node_set_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const char *parameter, const char *value) ++{ ++ int nr_found = 0, rc; ++ struct user_param *param; ++ struct list_head params; ++ ++ INIT_LIST_HEAD(¶ms); ++ param = idbm_alloc_user_param(parameter, value); ++ if (!param) { ++ rc = ENOMEM; ++ goto leave; ++ } ++ list_add_tail(¶ms, ¶m->list); ++ ++ CHECK(idbm_for_each_iface(&nr_found, ¶ms, idbm_node_set_param, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++ free(param->name); ++ free(param); ++leave: ++ return rc; ++} ++ ++static int get_parameter_helper(void *data, node_rec_t *rec) ++{ ++ struct libiscsi_context *context = data; ++ recinfo_t *info; ++ int i; ++ ++ info = idbm_recinfo_alloc(MAX_KEYS); ++ if (!info) { ++ snprintf(context->error_str, sizeof(context->error_str), ++ strerror(ENOMEM)); ++ return ENOMEM; ++ } ++ ++ idbm_recinfo_node(rec, info); ++ ++ for (i = 0; i < MAX_KEYS; i++) { ++ if (!info[i].visible) ++ continue; ++ ++ if (strcmp(context->parameter, info[i].name)) ++ continue; ++ ++ strlcpy(context->value, info[i].value, LIBISCSI_VALUE_MAXLEN); ++ break; ++ } ++ ++ free(info); ++ ++ if (i == MAX_KEYS) { ++ strcpy(context->error_str, "No such parameter"); ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ ++int libiscsi_node_get_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, const char *parameter, char *value) ++{ ++ int nr_found = 0, rc = 0; ++ ++ context->parameter = parameter; ++ context->value = value; ++ ++ /* Note we assume there is only one interface, if not we will get ++ the value from the last interface iterated over! ++ This (multiple interfaces) can only happen if someone explicitly ++ created ones using iscsiadm. Even then this should not be a problem ++ as most settings should be the same independent of the iface. */ ++ CHECK(idbm_for_each_iface(&nr_found, context, get_parameter_helper, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++const char *libiscsi_get_error_string(struct libiscsi_context *context) ++{ ++ /* Sometimes the core open-iscsi code does not give us an error ++ message */ ++ if (!context->error_str[0]) ++ return "Unknown error"; ++ ++ return context->error_str; ++} ++ ++ ++/************************** Utility functions *******************************/ ++ ++int libiscsi_get_firmware_network_config( ++ struct libiscsi_network_config *config) ++{ ++ struct boot_context fw_entry; ++ ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ ++ memset(config, 0, sizeof *config); ++ memset(&fw_entry, 0, sizeof fw_entry); ++ if (fw_get_entry(&fw_entry)) ++ return ENODEV; ++ ++ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0; ++ strlcpy(config->iface_name, fw_entry.iface, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->mac_address, fw_entry.mac, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->ip_address, fw_entry.ipaddr, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->netmask, fw_entry.mask, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->gateway, fw_entry.gateway, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->primary_dns, fw_entry.primary_dns, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->secondary_dns, fw_entry.secondary_dns, LIBISCSI_VALUE_MAXLEN); ++ return 0; ++} ++ ++int libiscsi_get_firmware_initiator_name(char *initiatorname) ++{ ++ struct boot_context fw_entry; ++ ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ ++ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN); ++ memset(&fw_entry, 0, sizeof fw_entry); ++ if (fw_get_entry(&fw_entry)) ++ return ENODEV; ++ ++ strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN); ++ ++ return 0; ++} +diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy +new file mode 100644 +index 000000000000..7a5ff7f7cd5a +--- /dev/null ++++ b/libiscsi/libiscsi.doxy +@@ -0,0 +1,1473 @@ ++# Doxyfile 1.5.7.1 ++ ++# This file describes the settings to be used by the documentation system ++# doxygen (www.doxygen.org) for a project ++# ++# All text after a hash (#) is considered a comment and will be ignored ++# The format is: ++# TAG = value [value, ...] ++# For lists items can also be appended using: ++# TAG += value [value, ...] ++# Values that contain spaces should be placed between quotes (" ") ++ ++#--------------------------------------------------------------------------- ++# Project related configuration options ++#--------------------------------------------------------------------------- ++ ++# This tag specifies the encoding used for all characters in the config file ++# that follow. The default is UTF-8 which is also the encoding used for all ++# text before the first occurrence of this tag. Doxygen uses libiconv (or the ++# iconv built into libc) for the transcoding. See ++# http://www.gnu.org/software/libiconv for the list of possible encodings. ++ ++DOXYFILE_ENCODING = UTF-8 ++ ++# The PROJECT_NAME tag is a single word (or a sequence of words surrounded ++# by quotes) that should identify the project. ++ ++PROJECT_NAME = libiscsi ++ ++# The PROJECT_NUMBER tag can be used to enter a project or revision number. ++# This could be handy for archiving the generated documentation or ++# if some version control system is used. ++ ++PROJECT_NUMBER = ++ ++# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) ++# base path where the generated documentation will be put. ++# If a relative path is entered, it will be relative to the location ++# where doxygen was started. If left blank the current directory will be used. ++ ++OUTPUT_DIRECTORY = ++ ++# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create ++# 4096 sub-directories (in 2 levels) under the output directory of each output ++# format and will distribute the generated files over these directories. ++# Enabling this option can be useful when feeding doxygen a huge amount of ++# source files, where putting all generated files in the same directory would ++# otherwise cause performance problems for the file system. ++ ++CREATE_SUBDIRS = NO ++ ++# The OUTPUT_LANGUAGE tag is used to specify the language in which all ++# documentation generated by doxygen is written. Doxygen will use this ++# information to generate all constant output in the proper language. ++# The default language is English, other supported languages are: ++# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, ++# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, ++# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), ++# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, ++# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, ++# Spanish, Swedish, and Ukrainian. ++ ++OUTPUT_LANGUAGE = English ++ ++# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will ++# include brief member descriptions after the members that are listed in ++# the file and class documentation (similar to JavaDoc). ++# Set to NO to disable this. ++ ++BRIEF_MEMBER_DESC = YES ++ ++# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend ++# the brief description of a member or function before the detailed description. ++# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the ++# brief descriptions will be completely suppressed. ++ ++REPEAT_BRIEF = NO ++ ++# This tag implements a quasi-intelligent brief description abbreviator ++# that is used to form the text in various listings. Each string ++# in this list, if found as the leading text of the brief description, will be ++# stripped from the text and the result after processing the whole list, is ++# used as the annotated text. Otherwise, the brief description is used as-is. ++# If left blank, the following values are used ("$name" is automatically ++# replaced with the name of the entity): "The $name class" "The $name widget" ++# "The $name file" "is" "provides" "specifies" "contains" ++# "represents" "a" "an" "the" ++ ++ABBREVIATE_BRIEF = ++ ++# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then ++# Doxygen will generate a detailed section even if there is only a brief ++# description. ++ ++ALWAYS_DETAILED_SEC = YES ++ ++# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all ++# inherited members of a class in the documentation of that class as if those ++# members were ordinary class members. Constructors, destructors and assignment ++# operators of the base classes will not be shown. ++ ++INLINE_INHERITED_MEMB = NO ++ ++# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full ++# path before files name in the file list and in the header files. If set ++# to NO the shortest path that makes the file name unique will be used. ++ ++FULL_PATH_NAMES = YES ++ ++# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag ++# can be used to strip a user-defined part of the path. Stripping is ++# only done if one of the specified strings matches the left-hand part of ++# the path. The tag can be used to show relative paths in the file list. ++# If left blank the directory from which doxygen is run is used as the ++# path to strip. ++ ++STRIP_FROM_PATH = ++ ++# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of ++# the path mentioned in the documentation of a class, which tells ++# the reader which header file to include in order to use a class. ++# If left blank only the name of the header file containing the class ++# definition is used. Otherwise one should specify the include paths that ++# are normally passed to the compiler using the -I flag. ++ ++STRIP_FROM_INC_PATH = ++ ++# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter ++# (but less readable) file names. This can be useful is your file systems ++# doesn't support long names like on DOS, Mac, or CD-ROM. ++ ++SHORT_NAMES = NO ++ ++# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen ++# will interpret the first line (until the first dot) of a JavaDoc-style ++# comment as the brief description. If set to NO, the JavaDoc ++# comments will behave just like regular Qt-style comments ++# (thus requiring an explicit @brief command for a brief description.) ++ ++JAVADOC_AUTOBRIEF = NO ++ ++# If the QT_AUTOBRIEF tag is set to YES then Doxygen will ++# interpret the first line (until the first dot) of a Qt-style ++# comment as the brief description. If set to NO, the comments ++# will behave just like regular Qt-style comments (thus requiring ++# an explicit \brief command for a brief description.) ++ ++QT_AUTOBRIEF = NO ++ ++# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen ++# treat a multi-line C++ special comment block (i.e. a block of //! or /// ++# comments) as a brief description. This used to be the default behaviour. ++# The new default is to treat a multi-line C++ comment block as a detailed ++# description. Set this tag to YES if you prefer the old behaviour instead. ++ ++MULTILINE_CPP_IS_BRIEF = NO ++ ++# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented ++# member inherits the documentation from any documented member that it ++# re-implements. ++ ++INHERIT_DOCS = YES ++ ++# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce ++# a new page for each member. If set to NO, the documentation of a member will ++# be part of the file/class/namespace that contains it. ++ ++SEPARATE_MEMBER_PAGES = NO ++ ++# The TAB_SIZE tag can be used to set the number of spaces in a tab. ++# Doxygen uses this value to replace tabs by spaces in code fragments. ++ ++TAB_SIZE = 8 ++ ++# This tag can be used to specify a number of aliases that acts ++# as commands in the documentation. An alias has the form "name=value". ++# For example adding "sideeffect=\par Side Effects:\n" will allow you to ++# put the command \sideeffect (or @sideeffect) in the documentation, which ++# will result in a user-defined paragraph with heading "Side Effects:". ++# You can put \n's in the value part of an alias to insert newlines. ++ ++ALIASES = ++ ++# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C ++# sources only. Doxygen will then generate output that is more tailored for C. ++# For instance, some of the names that are used will be different. The list ++# of all members will be omitted, etc. ++ ++OPTIMIZE_OUTPUT_FOR_C = YES ++ ++# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java ++# sources only. Doxygen will then generate output that is more tailored for ++# Java. For instance, namespaces will be presented as packages, qualified ++# scopes will look different, etc. ++ ++OPTIMIZE_OUTPUT_JAVA = NO ++ ++# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran ++# sources only. Doxygen will then generate output that is more tailored for ++# Fortran. ++ ++OPTIMIZE_FOR_FORTRAN = NO ++ ++# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL ++# sources. Doxygen will then generate output that is tailored for ++# VHDL. ++ ++OPTIMIZE_OUTPUT_VHDL = NO ++ ++# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want ++# to include (a tag file for) the STL sources as input, then you should ++# set this tag to YES in order to let doxygen match functions declarations and ++# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. ++# func(std::string) {}). This also make the inheritance and collaboration ++# diagrams that involve STL classes more complete and accurate. ++ ++BUILTIN_STL_SUPPORT = NO ++ ++# If you use Microsoft's C++/CLI language, you should set this option to YES to ++# enable parsing support. ++ ++CPP_CLI_SUPPORT = NO ++ ++# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. ++# Doxygen will parse them like normal C++ but will assume all classes use public ++# instead of private inheritance when no explicit protection keyword is present. ++ ++SIP_SUPPORT = NO ++ ++# For Microsoft's IDL there are propget and propput attributes to indicate getter ++# and setter methods for a property. Setting this option to YES (the default) ++# will make doxygen to replace the get and set methods by a property in the ++# documentation. This will only work if the methods are indeed getting or ++# setting a simple type. If this is not the case, or you want to show the ++# methods anyway, you should set this option to NO. ++ ++IDL_PROPERTY_SUPPORT = YES ++ ++# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC ++# tag is set to YES, then doxygen will reuse the documentation of the first ++# member in the group (if any) for the other members of the group. By default ++# all members of a group must be documented explicitly. ++ ++DISTRIBUTE_GROUP_DOC = NO ++ ++# Set the SUBGROUPING tag to YES (the default) to allow class member groups of ++# the same type (for instance a group of public functions) to be put as a ++# subgroup of that type (e.g. under the Public Functions section). Set it to ++# NO to prevent subgrouping. Alternatively, this can be done per class using ++# the \nosubgrouping command. ++ ++SUBGROUPING = YES ++ ++# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum ++# is documented as struct, union, or enum with the name of the typedef. So ++# typedef struct TypeS {} TypeT, will appear in the documentation as a struct ++# with name TypeT. When disabled the typedef will appear as a member of a file, ++# namespace, or class. And the struct will be named TypeS. This can typically ++# be useful for C code in case the coding convention dictates that all compound ++# types are typedef'ed and only the typedef is referenced, never the tag name. ++ ++TYPEDEF_HIDES_STRUCT = NO ++ ++# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to ++# determine which symbols to keep in memory and which to flush to disk. ++# When the cache is full, less often used symbols will be written to disk. ++# For small to medium size projects (<1000 input files) the default value is ++# probably good enough. For larger projects a too small cache size can cause ++# doxygen to be busy swapping symbols to and from disk most of the time ++# causing a significant performance penality. ++# If the system has enough physical memory increasing the cache will improve the ++# performance by keeping more symbols in memory. Note that the value works on ++# a logarithmic scale so increasing the size by one will rougly double the ++# memory usage. The cache size is given by this formula: ++# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, ++# corresponding to a cache size of 2^16 = 65536 symbols ++ ++SYMBOL_CACHE_SIZE = 0 ++ ++#--------------------------------------------------------------------------- ++# Build related configuration options ++#--------------------------------------------------------------------------- ++ ++# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in ++# documentation are documented, even if no documentation was available. ++# Private class members and static file members will be hidden unless ++# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES ++ ++EXTRACT_ALL = YES ++ ++# If the EXTRACT_PRIVATE tag is set to YES all private members of a class ++# will be included in the documentation. ++ ++EXTRACT_PRIVATE = NO ++ ++# If the EXTRACT_STATIC tag is set to YES all static members of a file ++# will be included in the documentation. ++ ++EXTRACT_STATIC = NO ++ ++# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) ++# defined locally in source files will be included in the documentation. ++# If set to NO only classes defined in header files are included. ++ ++EXTRACT_LOCAL_CLASSES = YES ++ ++# This flag is only useful for Objective-C code. When set to YES local ++# methods, which are defined in the implementation section but not in ++# the interface are included in the documentation. ++# If set to NO (the default) only methods in the interface are included. ++ ++EXTRACT_LOCAL_METHODS = NO ++ ++# If this flag is set to YES, the members of anonymous namespaces will be ++# extracted and appear in the documentation as a namespace called ++# 'anonymous_namespace{file}', where file will be replaced with the base ++# name of the file that contains the anonymous namespace. By default ++# anonymous namespace are hidden. ++ ++EXTRACT_ANON_NSPACES = NO ++ ++# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all ++# undocumented members of documented classes, files or namespaces. ++# If set to NO (the default) these members will be included in the ++# various overviews, but no documentation section is generated. ++# This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_MEMBERS = NO ++ ++# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all ++# undocumented classes that are normally visible in the class hierarchy. ++# If set to NO (the default) these classes will be included in the various ++# overviews. This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_CLASSES = NO ++ ++# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all ++# friend (class|struct|union) declarations. ++# If set to NO (the default) these declarations will be included in the ++# documentation. ++ ++HIDE_FRIEND_COMPOUNDS = NO ++ ++# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any ++# documentation blocks found inside the body of a function. ++# If set to NO (the default) these blocks will be appended to the ++# function's detailed documentation block. ++ ++HIDE_IN_BODY_DOCS = NO ++ ++# The INTERNAL_DOCS tag determines if documentation ++# that is typed after a \internal command is included. If the tag is set ++# to NO (the default) then the documentation will be excluded. ++# Set it to YES to include the internal documentation. ++ ++INTERNAL_DOCS = NO ++ ++# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate ++# file names in lower-case letters. If set to YES upper-case letters are also ++# allowed. This is useful if you have classes or files whose names only differ ++# in case and if your file system supports case sensitive file names. Windows ++# and Mac users are advised to set this option to NO. ++ ++CASE_SENSE_NAMES = YES ++ ++# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen ++# will show members with their full class and namespace scopes in the ++# documentation. If set to YES the scope will be hidden. ++ ++HIDE_SCOPE_NAMES = NO ++ ++# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen ++# will put a list of the files that are included by a file in the documentation ++# of that file. ++ ++SHOW_INCLUDE_FILES = YES ++ ++# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] ++# is inserted in the documentation for inline members. ++ ++INLINE_INFO = YES ++ ++# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen ++# will sort the (detailed) documentation of file and class members ++# alphabetically by member name. If set to NO the members will appear in ++# declaration order. ++ ++SORT_MEMBER_DOCS = YES ++ ++# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the ++# brief documentation of file, namespace and class members alphabetically ++# by member name. If set to NO (the default) the members will appear in ++# declaration order. ++ ++SORT_BRIEF_DOCS = NO ++ ++# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the ++# hierarchy of group names into alphabetical order. If set to NO (the default) ++# the group names will appear in their defined order. ++ ++SORT_GROUP_NAMES = NO ++ ++# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be ++# sorted by fully-qualified names, including namespaces. If set to ++# NO (the default), the class list will be sorted only by class name, ++# not including the namespace part. ++# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. ++# Note: This option applies only to the class list, not to the ++# alphabetical list. ++ ++SORT_BY_SCOPE_NAME = NO ++ ++# The GENERATE_TODOLIST tag can be used to enable (YES) or ++# disable (NO) the todo list. This list is created by putting \todo ++# commands in the documentation. ++ ++GENERATE_TODOLIST = YES ++ ++# The GENERATE_TESTLIST tag can be used to enable (YES) or ++# disable (NO) the test list. This list is created by putting \test ++# commands in the documentation. ++ ++GENERATE_TESTLIST = YES ++ ++# The GENERATE_BUGLIST tag can be used to enable (YES) or ++# disable (NO) the bug list. This list is created by putting \bug ++# commands in the documentation. ++ ++GENERATE_BUGLIST = YES ++ ++# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or ++# disable (NO) the deprecated list. This list is created by putting ++# \deprecated commands in the documentation. ++ ++GENERATE_DEPRECATEDLIST= YES ++ ++# The ENABLED_SECTIONS tag can be used to enable conditional ++# documentation sections, marked by \if sectionname ... \endif. ++ ++ENABLED_SECTIONS = ++ ++# The MAX_INITIALIZER_LINES tag determines the maximum number of lines ++# the initial value of a variable or define consists of for it to appear in ++# the documentation. If the initializer consists of more lines than specified ++# here it will be hidden. Use a value of 0 to hide initializers completely. ++# The appearance of the initializer of individual variables and defines in the ++# documentation can be controlled using \showinitializer or \hideinitializer ++# command in the documentation regardless of this setting. ++ ++MAX_INITIALIZER_LINES = 30 ++ ++# Set the SHOW_USED_FILES tag to NO to disable the list of files generated ++# at the bottom of the documentation of classes and structs. If set to YES the ++# list will mention the files that were used to generate the documentation. ++ ++SHOW_USED_FILES = YES ++ ++# If the sources in your project are distributed over multiple directories ++# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy ++# in the documentation. The default is NO. ++ ++SHOW_DIRECTORIES = NO ++ ++# Set the SHOW_FILES tag to NO to disable the generation of the Files page. ++# This will remove the Files entry from the Quick Index and from the ++# Folder Tree View (if specified). The default is YES. ++ ++SHOW_FILES = YES ++ ++# Set the SHOW_NAMESPACES tag to NO to disable the generation of the ++# Namespaces page. This will remove the Namespaces entry from the Quick Index ++# and from the Folder Tree View (if specified). The default is YES. ++ ++SHOW_NAMESPACES = YES ++ ++# The FILE_VERSION_FILTER tag can be used to specify a program or script that ++# doxygen should invoke to get the current version for each file (typically from ++# the version control system). Doxygen will invoke the program by executing (via ++# popen()) the command , where is the value of ++# the FILE_VERSION_FILTER tag, and is the name of an input file ++# provided by doxygen. Whatever the program writes to standard output ++# is used as the file version. See the manual for examples. ++ ++FILE_VERSION_FILTER = ++ ++# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by ++# doxygen. The layout file controls the global structure of the generated output files ++# in an output format independent way. The create the layout file that represents ++# doxygen's defaults, run doxygen with the -l option. You can optionally specify a ++# file name after the option, if omitted DoxygenLayout.xml will be used as the name ++# of the layout file. ++ ++LAYOUT_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to warning and progress messages ++#--------------------------------------------------------------------------- ++ ++# The QUIET tag can be used to turn on/off the messages that are generated ++# by doxygen. Possible values are YES and NO. If left blank NO is used. ++ ++QUIET = YES ++ ++# The WARNINGS tag can be used to turn on/off the warning messages that are ++# generated by doxygen. Possible values are YES and NO. If left blank ++# NO is used. ++ ++WARNINGS = YES ++ ++# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings ++# for undocumented members. If EXTRACT_ALL is set to YES then this flag will ++# automatically be disabled. ++ ++WARN_IF_UNDOCUMENTED = YES ++ ++# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for ++# potential errors in the documentation, such as not documenting some ++# parameters in a documented function, or documenting parameters that ++# don't exist or using markup commands wrongly. ++ ++WARN_IF_DOC_ERROR = YES ++ ++# This WARN_NO_PARAMDOC option can be abled to get warnings for ++# functions that are documented, but have no documentation for their parameters ++# or return value. If set to NO (the default) doxygen will only warn about ++# wrong or incomplete parameter documentation, but not about the absence of ++# documentation. ++ ++WARN_NO_PARAMDOC = NO ++ ++# The WARN_FORMAT tag determines the format of the warning messages that ++# doxygen can produce. The string should contain the $file, $line, and $text ++# tags, which will be replaced by the file and line number from which the ++# warning originated and the warning text. Optionally the format may contain ++# $version, which will be replaced by the version of the file (if it could ++# be obtained via FILE_VERSION_FILTER) ++ ++WARN_FORMAT = "$file:$line: $text" ++ ++# The WARN_LOGFILE tag can be used to specify a file to which warning ++# and error messages should be written. If left blank the output is written ++# to stderr. ++ ++WARN_LOGFILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the input files ++#--------------------------------------------------------------------------- ++ ++# The INPUT tag can be used to specify the files and/or directories that contain ++# documented source files. You may enter file names like "myfile.cpp" or ++# directories like "/usr/src/myproject". Separate the files or directories ++# with spaces. ++ ++INPUT = ++ ++# This tag can be used to specify the character encoding of the source files ++# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is ++# also the default input encoding. Doxygen uses libiconv (or the iconv built ++# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for ++# the list of possible encodings. ++ ++INPUT_ENCODING = UTF-8 ++ ++# If the value of the INPUT tag contains directories, you can use the ++# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank the following patterns are tested: ++# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx ++# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 ++ ++FILE_PATTERNS = ++ ++# The RECURSIVE tag can be used to turn specify whether or not subdirectories ++# should be searched for input files as well. Possible values are YES and NO. ++# If left blank NO is used. ++ ++RECURSIVE = NO ++ ++# The EXCLUDE tag can be used to specify files and/or directories that should ++# excluded from the INPUT source files. This way you can easily exclude a ++# subdirectory from a directory tree whose root is specified with the INPUT tag. ++ ++EXCLUDE = ++ ++# The EXCLUDE_SYMLINKS tag can be used select whether or not files or ++# directories that are symbolic links (a Unix filesystem feature) are excluded ++# from the input. ++ ++EXCLUDE_SYMLINKS = NO ++ ++# If the value of the INPUT tag contains directories, you can use the ++# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude ++# certain files from those directories. Note that the wildcards are matched ++# against the file with absolute path, so to exclude all test directories ++# for example use the pattern */test/* ++ ++EXCLUDE_PATTERNS = ++ ++# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names ++# (namespaces, classes, functions, etc.) that should be excluded from the ++# output. The symbol name can be a fully qualified name, a word, or if the ++# wildcard * is used, a substring. Examples: ANamespace, AClass, ++# AClass::ANamespace, ANamespace::*Test ++ ++EXCLUDE_SYMBOLS = ++ ++# The EXAMPLE_PATH tag can be used to specify one or more files or ++# directories that contain example code fragments that are included (see ++# the \include command). ++ ++EXAMPLE_PATH = ++ ++# If the value of the EXAMPLE_PATH tag contains directories, you can use the ++# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank all files are included. ++ ++EXAMPLE_PATTERNS = ++ ++# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be ++# searched for input files to be used with the \include or \dontinclude ++# commands irrespective of the value of the RECURSIVE tag. ++# Possible values are YES and NO. If left blank NO is used. ++ ++EXAMPLE_RECURSIVE = NO ++ ++# The IMAGE_PATH tag can be used to specify one or more files or ++# directories that contain image that are included in the documentation (see ++# the \image command). ++ ++IMAGE_PATH = ++ ++# The INPUT_FILTER tag can be used to specify a program that doxygen should ++# invoke to filter for each input file. Doxygen will invoke the filter program ++# by executing (via popen()) the command , where ++# is the value of the INPUT_FILTER tag, and is the name of an ++# input file. Doxygen will then use the output that the filter program writes ++# to standard output. If FILTER_PATTERNS is specified, this tag will be ++# ignored. ++ ++INPUT_FILTER = ++ ++# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern ++# basis. Doxygen will compare the file name with each pattern and apply the ++# filter if there is a match. The filters are a list of the form: ++# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further ++# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER ++# is applied to all files. ++ ++FILTER_PATTERNS = ++ ++# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using ++# INPUT_FILTER) will be used to filter the input files when producing source ++# files to browse (i.e. when SOURCE_BROWSER is set to YES). ++ ++FILTER_SOURCE_FILES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to source browsing ++#--------------------------------------------------------------------------- ++ ++# If the SOURCE_BROWSER tag is set to YES then a list of source files will ++# be generated. Documented entities will be cross-referenced with these sources. ++# Note: To get rid of all source code in the generated output, make sure also ++# VERBATIM_HEADERS is set to NO. ++ ++SOURCE_BROWSER = NO ++ ++# Setting the INLINE_SOURCES tag to YES will include the body ++# of functions and classes directly in the documentation. ++ ++INLINE_SOURCES = NO ++ ++# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct ++# doxygen to hide any special comment blocks from generated source code ++# fragments. Normal C and C++ comments will always remain visible. ++ ++STRIP_CODE_COMMENTS = YES ++ ++# If the REFERENCED_BY_RELATION tag is set to YES ++# then for each documented function all documented ++# functions referencing it will be listed. ++ ++REFERENCED_BY_RELATION = NO ++ ++# If the REFERENCES_RELATION tag is set to YES ++# then for each documented function all documented entities ++# called/used by that function will be listed. ++ ++REFERENCES_RELATION = NO ++ ++# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) ++# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from ++# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will ++# link to the source code. Otherwise they will link to the documentstion. ++ ++REFERENCES_LINK_SOURCE = YES ++ ++# If the USE_HTAGS tag is set to YES then the references to source code ++# will point to the HTML generated by the htags(1) tool instead of doxygen ++# built-in source browser. The htags tool is part of GNU's global source ++# tagging system (see http://www.gnu.org/software/global/global.html). You ++# will need version 4.8.6 or higher. ++ ++USE_HTAGS = NO ++ ++# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen ++# will generate a verbatim copy of the header file for each class for ++# which an include is specified. Set to NO to disable this. ++ ++VERBATIM_HEADERS = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the alphabetical class index ++#--------------------------------------------------------------------------- ++ ++# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index ++# of all compounds will be generated. Enable this if the project ++# contains a lot of classes, structs, unions or interfaces. ++ ++ALPHABETICAL_INDEX = NO ++ ++# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then ++# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns ++# in which this list will be split (can be a number in the range [1..20]) ++ ++COLS_IN_ALPHA_INDEX = 5 ++ ++# In case all classes in a project start with a common prefix, all ++# classes will be put under the same header in the alphabetical index. ++# The IGNORE_PREFIX tag can be used to specify one or more prefixes that ++# should be ignored while generating the index headers. ++ ++IGNORE_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the HTML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_HTML tag is set to YES (the default) Doxygen will ++# generate HTML output. ++ ++GENERATE_HTML = YES ++ ++# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `html' will be used as the default path. ++ ++HTML_OUTPUT = html ++ ++# The HTML_FILE_EXTENSION tag can be used to specify the file extension for ++# each generated HTML page (for example: .htm,.php,.asp). If it is left blank ++# doxygen will generate files with .html extension. ++ ++HTML_FILE_EXTENSION = .html ++ ++# The HTML_HEADER tag can be used to specify a personal HTML header for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard header. ++ ++HTML_HEADER = ++ ++# The HTML_FOOTER tag can be used to specify a personal HTML footer for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard footer. ++ ++HTML_FOOTER = no_date_footer.html ++ ++# The HTML_STYLESHEET tag can be used to specify a user-defined cascading ++# style sheet that is used by each HTML page. It can be used to ++# fine-tune the look of the HTML output. If the tag is left blank doxygen ++# will generate a default style sheet. Note that doxygen will try to copy ++# the style sheet file to the HTML output directory, so don't put your own ++# stylesheet in the HTML output directory as well, or it will be erased! ++ ++HTML_STYLESHEET = ++ ++# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, ++# files or namespaces will be aligned in HTML using tables. If set to ++# NO a bullet list will be used. ++ ++HTML_ALIGN_MEMBERS = YES ++ ++# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML ++# documentation will contain sections that can be hidden and shown after the ++# page has loaded. For this to work a browser that supports ++# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox ++# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). ++ ++HTML_DYNAMIC_SECTIONS = NO ++ ++# If the GENERATE_DOCSET tag is set to YES, additional index files ++# will be generated that can be used as input for Apple's Xcode 3 ++# integrated development environment, introduced with OSX 10.5 (Leopard). ++# To create a documentation set, doxygen will generate a Makefile in the ++# HTML output directory. Running make will produce the docset in that ++# directory and running "make install" will install the docset in ++# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find ++# it at startup. ++# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. ++ ++GENERATE_DOCSET = NO ++ ++# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the ++# feed. A documentation feed provides an umbrella under which multiple ++# documentation sets from a single provider (such as a company or product suite) ++# can be grouped. ++ ++DOCSET_FEEDNAME = "Doxygen generated docs" ++ ++# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that ++# should uniquely identify the documentation set bundle. This should be a ++# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen ++# will append .docset to the name. ++ ++DOCSET_BUNDLE_ID = org.doxygen.Project ++ ++# If the GENERATE_HTMLHELP tag is set to YES, additional index files ++# will be generated that can be used as input for tools like the ++# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) ++# of the generated HTML documentation. ++ ++GENERATE_HTMLHELP = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can ++# be used to specify the file name of the resulting .chm file. You ++# can add a path in front of the file if the result should not be ++# written to the html output directory. ++ ++CHM_FILE = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can ++# be used to specify the location (absolute path including file name) of ++# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run ++# the HTML help compiler on the generated index.hhp. ++ ++HHC_LOCATION = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag ++# controls if a separate .chi index file is generated (YES) or that ++# it should be included in the master .chm file (NO). ++ ++GENERATE_CHI = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING ++# is used to encode HtmlHelp index (hhk), content (hhc) and project file ++# content. ++ ++CHM_INDEX_ENCODING = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag ++# controls whether a binary table of contents is generated (YES) or a ++# normal table of contents (NO) in the .chm file. ++ ++BINARY_TOC = NO ++ ++# The TOC_EXPAND flag can be set to YES to add extra items for group members ++# to the contents of the HTML help documentation and to the tree view. ++ ++TOC_EXPAND = NO ++ ++# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER ++# are set, an additional index file will be generated that can be used as input for ++# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated ++# HTML documentation. ++ ++GENERATE_QHP = NO ++ ++# If the QHG_LOCATION tag is specified, the QCH_FILE tag can ++# be used to specify the file name of the resulting .qch file. ++# The path specified is relative to the HTML output folder. ++ ++QCH_FILE = ++ ++# The QHP_NAMESPACE tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Namespace. ++ ++QHP_NAMESPACE = org.doxygen.Project ++ ++# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Virtual Folders. ++ ++QHP_VIRTUAL_FOLDER = doc ++ ++# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can ++# be used to specify the location of Qt's qhelpgenerator. ++# If non-empty doxygen will try to run qhelpgenerator on the generated ++# .qhp file . ++ ++QHG_LOCATION = ++ ++# The DISABLE_INDEX tag can be used to turn on/off the condensed index at ++# top of each HTML page. The value NO (the default) enables the index and ++# the value YES disables it. ++ ++DISABLE_INDEX = NO ++ ++# This tag can be used to set the number of enum values (range [1..20]) ++# that doxygen will group on one line in the generated HTML documentation. ++ ++ENUM_VALUES_PER_LINE = 4 ++ ++# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index ++# structure should be generated to display hierarchical information. ++# If the tag value is set to FRAME, a side panel will be generated ++# containing a tree-like index structure (just like the one that ++# is generated for HTML Help). For this to work a browser that supports ++# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, ++# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are ++# probably better off using the HTML help feature. Other possible values ++# for this tag are: HIERARCHIES, which will generate the Groups, Directories, ++# and Class Hierarchy pages using a tree view instead of an ordered list; ++# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which ++# disables this behavior completely. For backwards compatibility with previous ++# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE ++# respectively. ++ ++GENERATE_TREEVIEW = NONE ++ ++# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be ++# used to set the initial width (in pixels) of the frame in which the tree ++# is shown. ++ ++TREEVIEW_WIDTH = 250 ++ ++# Use this tag to change the font size of Latex formulas included ++# as images in the HTML documentation. The default is 10. Note that ++# when you change the font size after a successful doxygen run you need ++# to manually remove any form_*.png images from the HTML output directory ++# to force them to be regenerated. ++ ++FORMULA_FONTSIZE = 10 ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the LaTeX output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will ++# generate Latex output. ++ ++GENERATE_LATEX = NO ++ ++# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `latex' will be used as the default path. ++ ++LATEX_OUTPUT = latex ++ ++# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be ++# invoked. If left blank `latex' will be used as the default command name. ++ ++LATEX_CMD_NAME = latex ++ ++# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to ++# generate index for LaTeX. If left blank `makeindex' will be used as the ++# default command name. ++ ++MAKEINDEX_CMD_NAME = makeindex ++ ++# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact ++# LaTeX documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_LATEX = NO ++ ++# The PAPER_TYPE tag can be used to set the paper type that is used ++# by the printer. Possible values are: a4, a4wide, letter, legal and ++# executive. If left blank a4wide will be used. ++ ++PAPER_TYPE = a4wide ++ ++# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX ++# packages that should be included in the LaTeX output. ++ ++EXTRA_PACKAGES = ++ ++# The LATEX_HEADER tag can be used to specify a personal LaTeX header for ++# the generated latex document. The header should contain everything until ++# the first chapter. If it is left blank doxygen will generate a ++# standard header. Notice: only use this tag if you know what you are doing! ++ ++LATEX_HEADER = ++ ++# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated ++# is prepared for conversion to pdf (using ps2pdf). The pdf file will ++# contain links (just like the HTML output) instead of page references ++# This makes the output suitable for online browsing using a pdf viewer. ++ ++PDF_HYPERLINKS = YES ++ ++# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of ++# plain latex in the generated Makefile. Set this option to YES to get a ++# higher quality PDF documentation. ++ ++USE_PDFLATEX = YES ++ ++# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. ++# command to the generated LaTeX files. This will instruct LaTeX to keep ++# running if errors occur, instead of asking the user for help. ++# This option is also used when generating formulas in HTML. ++ ++LATEX_BATCHMODE = NO ++ ++# If LATEX_HIDE_INDICES is set to YES then doxygen will not ++# include the index chapters (such as File Index, Compound Index, etc.) ++# in the output. ++ ++LATEX_HIDE_INDICES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the RTF output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output ++# The RTF output is optimized for Word 97 and may not look very pretty with ++# other RTF readers or editors. ++ ++GENERATE_RTF = NO ++ ++# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `rtf' will be used as the default path. ++ ++RTF_OUTPUT = rtf ++ ++# If the COMPACT_RTF tag is set to YES Doxygen generates more compact ++# RTF documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_RTF = NO ++ ++# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated ++# will contain hyperlink fields. The RTF file will ++# contain links (just like the HTML output) instead of page references. ++# This makes the output suitable for online browsing using WORD or other ++# programs which support those fields. ++# Note: wordpad (write) and others do not support links. ++ ++RTF_HYPERLINKS = NO ++ ++# Load stylesheet definitions from file. Syntax is similar to doxygen's ++# config file, i.e. a series of assignments. You only have to provide ++# replacements, missing definitions are set to their default value. ++ ++RTF_STYLESHEET_FILE = ++ ++# Set optional variables used in the generation of an rtf document. ++# Syntax is similar to doxygen's config file. ++ ++RTF_EXTENSIONS_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the man page output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_MAN tag is set to YES (the default) Doxygen will ++# generate man pages ++ ++GENERATE_MAN = NO ++ ++# The MAN_OUTPUT tag is used to specify where the man pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `man' will be used as the default path. ++ ++MAN_OUTPUT = man ++ ++# The MAN_EXTENSION tag determines the extension that is added to ++# the generated man pages (default is the subroutine's section .3) ++ ++MAN_EXTENSION = .3 ++ ++# If the MAN_LINKS tag is set to YES and Doxygen generates man output, ++# then it will generate one additional man file for each entity ++# documented in the real man page(s). These additional files ++# only source the real man page, but without them the man command ++# would be unable to find the correct page. The default is NO. ++ ++MAN_LINKS = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the XML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_XML tag is set to YES Doxygen will ++# generate an XML file that captures the structure of ++# the code including all documentation. ++ ++GENERATE_XML = NO ++ ++# The XML_OUTPUT tag is used to specify where the XML pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `xml' will be used as the default path. ++ ++XML_OUTPUT = xml ++ ++# The XML_SCHEMA tag can be used to specify an XML schema, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_SCHEMA = ++ ++# The XML_DTD tag can be used to specify an XML DTD, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_DTD = ++ ++# If the XML_PROGRAMLISTING tag is set to YES Doxygen will ++# dump the program listings (including syntax highlighting ++# and cross-referencing information) to the XML output. Note that ++# enabling this will significantly increase the size of the XML output. ++ ++XML_PROGRAMLISTING = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options for the AutoGen Definitions output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will ++# generate an AutoGen Definitions (see autogen.sf.net) file ++# that captures the structure of the code including all ++# documentation. Note that this feature is still experimental ++# and incomplete at the moment. ++ ++GENERATE_AUTOGEN_DEF = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the Perl module output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_PERLMOD tag is set to YES Doxygen will ++# generate a Perl module file that captures the structure of ++# the code including all documentation. Note that this ++# feature is still experimental and incomplete at the ++# moment. ++ ++GENERATE_PERLMOD = NO ++ ++# If the PERLMOD_LATEX tag is set to YES Doxygen will generate ++# the necessary Makefile rules, Perl scripts and LaTeX code to be able ++# to generate PDF and DVI output from the Perl module output. ++ ++PERLMOD_LATEX = NO ++ ++# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be ++# nicely formatted so it can be parsed by a human reader. This is useful ++# if you want to understand what is going on. On the other hand, if this ++# tag is set to NO the size of the Perl module output will be much smaller ++# and Perl will parse it just the same. ++ ++PERLMOD_PRETTY = YES ++ ++# The names of the make variables in the generated doxyrules.make file ++# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. ++# This is useful so different doxyrules.make files included by the same ++# Makefile don't overwrite each other's variables. ++ ++PERLMOD_MAKEVAR_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the preprocessor ++#--------------------------------------------------------------------------- ++ ++# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will ++# evaluate all C-preprocessor directives found in the sources and include ++# files. ++ ++ENABLE_PREPROCESSING = YES ++ ++# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro ++# names in the source code. If set to NO (the default) only conditional ++# compilation will be performed. Macro expansion can be done in a controlled ++# way by setting EXPAND_ONLY_PREDEF to YES. ++ ++MACRO_EXPANSION = NO ++ ++# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES ++# then the macro expansion is limited to the macros specified with the ++# PREDEFINED and EXPAND_AS_DEFINED tags. ++ ++EXPAND_ONLY_PREDEF = NO ++ ++# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files ++# in the INCLUDE_PATH (see below) will be search if a #include is found. ++ ++SEARCH_INCLUDES = YES ++ ++# The INCLUDE_PATH tag can be used to specify one or more directories that ++# contain include files that are not input files but should be processed by ++# the preprocessor. ++ ++INCLUDE_PATH = ++ ++# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard ++# patterns (like *.h and *.hpp) to filter out the header-files in the ++# directories. If left blank, the patterns specified with FILE_PATTERNS will ++# be used. ++ ++INCLUDE_FILE_PATTERNS = ++ ++# The PREDEFINED tag can be used to specify one or more macro names that ++# are defined before the preprocessor is started (similar to the -D option of ++# gcc). The argument of the tag is a list of macros of the form: name ++# or name=definition (no spaces). If the definition and the = are ++# omitted =1 is assumed. To prevent a macro definition from being ++# undefined via #undef or recursively expanded use the := operator ++# instead of the = operator. ++ ++PREDEFINED = ++ ++# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then ++# this tag can be used to specify a list of macro names that should be expanded. ++# The macro definition that is found in the sources will be used. ++# Use the PREDEFINED tag if you want to use a different macro definition. ++ ++EXPAND_AS_DEFINED = ++ ++# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then ++# doxygen's preprocessor will remove all function-like macros that are alone ++# on a line, have an all uppercase name, and do not end with a semicolon. Such ++# function macros are typically used for boiler-plate code, and will confuse ++# the parser if not removed. ++ ++SKIP_FUNCTION_MACROS = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to external references ++#--------------------------------------------------------------------------- ++ ++# The TAGFILES option can be used to specify one or more tagfiles. ++# Optionally an initial location of the external documentation ++# can be added for each tagfile. The format of a tag file without ++# this location is as follows: ++# TAGFILES = file1 file2 ... ++# Adding location for the tag files is done as follows: ++# TAGFILES = file1=loc1 "file2 = loc2" ... ++# where "loc1" and "loc2" can be relative or absolute paths or ++# URLs. If a location is present for each tag, the installdox tool ++# does not have to be run to correct the links. ++# Note that each tag file must have a unique name ++# (where the name does NOT include the path) ++# If a tag file is not located in the directory in which doxygen ++# is run, you must also specify the path to the tagfile here. ++ ++TAGFILES = ++ ++# When a file name is specified after GENERATE_TAGFILE, doxygen will create ++# a tag file that is based on the input files it reads. ++ ++GENERATE_TAGFILE = ++ ++# If the ALLEXTERNALS tag is set to YES all external classes will be listed ++# in the class index. If set to NO only the inherited external classes ++# will be listed. ++ ++ALLEXTERNALS = NO ++ ++# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed ++# in the modules index. If set to NO, only the current project's groups will ++# be listed. ++ ++EXTERNAL_GROUPS = YES ++ ++# The PERL_PATH should be the absolute path and name of the perl script ++# interpreter (i.e. the result of `which perl'). ++ ++PERL_PATH = /usr/bin/perl ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the dot tool ++#--------------------------------------------------------------------------- ++ ++# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will ++# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base ++# or super classes. Setting the tag to NO turns the diagrams off. Note that ++# this option is superseded by the HAVE_DOT option below. This is only a ++# fallback. It is recommended to install and use dot, since it yields more ++# powerful graphs. ++ ++CLASS_DIAGRAMS = YES ++ ++# You can define message sequence charts within doxygen comments using the \msc ++# command. Doxygen will then run the mscgen tool (see ++# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the ++# documentation. The MSCGEN_PATH tag allows you to specify the directory where ++# the mscgen tool resides. If left empty the tool is assumed to be found in the ++# default search path. ++ ++MSCGEN_PATH = ++ ++# If set to YES, the inheritance and collaboration graphs will hide ++# inheritance and usage relations if the target is undocumented ++# or is not a class. ++ ++HIDE_UNDOC_RELATIONS = YES ++ ++# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is ++# available from the path. This tool is part of Graphviz, a graph visualization ++# toolkit from AT&T and Lucent Bell Labs. The other options in this section ++# have no effect if this option is set to NO (the default) ++ ++HAVE_DOT = NO ++ ++# By default doxygen will write a font called FreeSans.ttf to the output ++# directory and reference it in all dot files that doxygen generates. This ++# font does not include all possible unicode characters however, so when you need ++# these (or just want a differently looking font) you can specify the font name ++# using DOT_FONTNAME. You need need to make sure dot is able to find the font, ++# which can be done by putting it in a standard location or by setting the ++# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory ++# containing the font. ++ ++DOT_FONTNAME = FreeSans ++ ++# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. ++# The default size is 10pt. ++ ++DOT_FONTSIZE = 10 ++ ++# By default doxygen will tell dot to use the output directory to look for the ++# FreeSans.ttf font (which doxygen will put there itself). If you specify a ++# different font using DOT_FONTNAME you can set the path where dot ++# can find it using this tag. ++ ++DOT_FONTPATH = ++ ++# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect inheritance relations. Setting this tag to YES will force the ++# the CLASS_DIAGRAMS tag to NO. ++ ++CLASS_GRAPH = YES ++ ++# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect implementation dependencies (inheritance, containment, and ++# class references variables) of the class with other documented classes. ++ ++COLLABORATION_GRAPH = YES ++ ++# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for groups, showing the direct groups dependencies ++ ++GROUP_GRAPHS = YES ++ ++# If the UML_LOOK tag is set to YES doxygen will generate inheritance and ++# collaboration diagrams in a style similar to the OMG's Unified Modeling ++# Language. ++ ++UML_LOOK = NO ++ ++# If set to YES, the inheritance and collaboration graphs will show the ++# relations between templates and their instances. ++ ++TEMPLATE_RELATIONS = NO ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT ++# tags are set to YES then doxygen will generate a graph for each documented ++# file showing the direct and indirect include dependencies of the file with ++# other documented files. ++ ++INCLUDE_GRAPH = YES ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and ++# HAVE_DOT tags are set to YES then doxygen will generate a graph for each ++# documented header file showing the documented files that directly or ++# indirectly include this file. ++ ++INCLUDED_BY_GRAPH = YES ++ ++# If the CALL_GRAPH and HAVE_DOT options are set to YES then ++# doxygen will generate a call dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable call graphs ++# for selected functions only using the \callgraph command. ++ ++CALL_GRAPH = NO ++ ++# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then ++# doxygen will generate a caller dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable caller ++# graphs for selected functions only using the \callergraph command. ++ ++CALLER_GRAPH = NO ++ ++# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen ++# will graphical hierarchy of all classes instead of a textual one. ++ ++GRAPHICAL_HIERARCHY = YES ++ ++# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES ++# then doxygen will show the dependencies a directory has on other directories ++# in a graphical way. The dependency relations are determined by the #include ++# relations between the files in the directories. ++ ++DIRECTORY_GRAPH = YES ++ ++# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images ++# generated by dot. Possible values are png, jpg, or gif ++# If left blank png will be used. ++ ++DOT_IMAGE_FORMAT = png ++ ++# The tag DOT_PATH can be used to specify the path where the dot tool can be ++# found. If left blank, it is assumed the dot tool can be found in the path. ++ ++DOT_PATH = ++ ++# The DOTFILE_DIRS tag can be used to specify one or more directories that ++# contain dot files that are included in the documentation (see the ++# \dotfile command). ++ ++DOTFILE_DIRS = ++ ++# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of ++# nodes that will be shown in the graph. If the number of nodes in a graph ++# becomes larger than this value, doxygen will truncate the graph, which is ++# visualized by representing a node as a red box. Note that doxygen if the ++# number of direct children of the root node in a graph is already larger than ++# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note ++# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. ++ ++DOT_GRAPH_MAX_NODES = 50 ++ ++# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the ++# graphs generated by dot. A depth value of 3 means that only nodes reachable ++# from the root by following a path via at most 3 edges will be shown. Nodes ++# that lay further from the root node will be omitted. Note that setting this ++# option to 1 or 2 may greatly reduce the computation time needed for large ++# code bases. Also note that the size of a graph can be further restricted by ++# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. ++ ++MAX_DOT_GRAPH_DEPTH = 0 ++ ++# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent ++# background. This is disabled by default, because dot on Windows does not ++# seem to support this out of the box. Warning: Depending on the platform used, ++# enabling this option may lead to badly anti-aliased labels on the edges of ++# a graph (i.e. they become hard to read). ++ ++DOT_TRANSPARENT = NO ++ ++# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output ++# files in one run (i.e. multiple -o and -T options on the command line). This ++# makes dot run faster, but since only newer versions of dot (>1.8.10) ++# support this, this feature is disabled by default. ++ ++DOT_MULTI_TARGETS = NO ++ ++# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will ++# generate a legend page explaining the meaning of the various boxes and ++# arrows in the dot generated graphs. ++ ++GENERATE_LEGEND = YES ++ ++# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will ++# remove the intermediate dot files that are used to generate ++# the various graphs. ++ ++DOT_CLEANUP = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to the search engine ++#--------------------------------------------------------------------------- ++ ++# The SEARCHENGINE tag specifies whether or not a search engine should be ++# used. If set to NO the values of all tags below this one will be ignored. ++ ++SEARCHENGINE = NO +diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h +new file mode 100644 +index 000000000000..756590e14d8b +--- /dev/null ++++ b/libiscsi/libiscsi.h +@@ -0,0 +1,344 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#ifndef __LIBISCSI_H ++#define __LIBISCSI_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++#if __GNUC__ >= 4 ++#define PUBLIC __attribute__ ((visibility("default"))) ++#else ++#define PUBLIC ++#endif ++ ++/** \brief Maximum length for iSCSI values. ++ * ++ * Maximum length for iSCSI values such as hostnames and parameter values. ++ */ ++#define LIBISCSI_VALUE_MAXLEN 256 ++ ++/** \brief supported authentication methods ++ * ++ * This enum lists all supported authentication methods. ++ */ ++enum libiscsi_auth_t { ++ libiscsi_auth_none /** No authentication */, ++ libiscsi_auth_chap /** CHAP authentication */, ++}; ++ ++/** \brief libiscsi context struct ++ * ++ * Note: even though libiscsi uses a context struct, the underlying open-iscsi ++ * code does not, so libiscsi is not thread safe, not even when using one ++ * context per thread! ++ */ ++struct libiscsi_context; ++ ++/** \brief iSCSI node record ++ * ++ * Struct holding data uniquely identifying an iSCSI node. ++ */ ++struct libiscsi_node { ++ char name[LIBISCSI_VALUE_MAXLEN] /** iSCSI iqn for the node. */; ++ int tpgt /** Portal group number. */; ++ /* Note open-iscsi has some code in place for multiple connections in one ++ node record and thus multiple address / port combi's, but this does not ++ get used anywhere, so we keep things simple and assume one connection */ ++ char address[NI_MAXHOST] /** Portal hostname or IP-address. */; ++ int port /** Portal port number. */; ++ char iface[LIBISCSI_VALUE_MAXLEN] /** Interface to connect through. */; ++}; ++ ++/** \brief libiscsi CHAP authentication information struct ++ * ++ * Struct holding all data needed for CHAP login / authentication. Note that ++ * \e reverse_username may be a 0 length string in which case only forward ++ * authentication will be done. ++ */ ++struct libiscsi_chap_auth_info { ++ char username[LIBISCSI_VALUE_MAXLEN] /** Username */; ++ char password[LIBISCSI_VALUE_MAXLEN] /** Password */; ++ char reverse_username[LIBISCSI_VALUE_MAXLEN] /** Reverse Username */; ++ char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */; ++}; ++ ++/** \brief generic libiscsi authentication information struct ++ * ++ * Struct holding authentication information for discovery and login. ++ */ ++struct libiscsi_auth_info { ++ enum libiscsi_auth_t method /** Authentication method to use */; ++ union { ++ struct libiscsi_chap_auth_info chap /** Chap specific info */; ++ } /** Union holding method depenend info */; ++}; ++ ++/** \brief Initalize libiscsi ++ * ++ * This function creates a libiscsi context and initalizes it. This context ++ * is need to use other libiscsi funtions. ++ * ++ * \return A pointer to the created context, or NULL in case of an error. ++ */ ++PUBLIC struct libiscsi_context *libiscsi_init(void); ++ ++/** \brief Cleanup libiscsi used resource ++ * ++ * This function cleanups any used resources and then destroys the passed ++ * context. After this the passed in context may no longer be used! ++ * ++ * \param context libiscsi context to operate on. ++ */ ++PUBLIC void libiscsi_cleanup(struct libiscsi_context *context); ++ ++/** \brief Discover iSCSI nodes using sendtargets and add them to the node db. ++ * ++ * This function connects to the given address and port and then tries to ++ * discover iSCSI nodes using the sendtargets protocol. Any found nodes are ++ * added to the local iSCSI node database and are returned in a dynamically ++ * allocated array. ++ * ++ * Note that the (optional) authentication info is for authenticating the ++ * discovery, and is not for the found nodes! If the connection(s) to the ++ * node(s) need authentication too, you can set the username / password for ++ * those (which can be different!) using the libiscsi_node_set_auth() function. ++ * ++ * \param context libiscsi context to operate on. ++ * \param address Hostname or IP-address to connect to. ++ * \param port Port to connect to, or 0 for the default port. ++ * \param auth_info Authentication information, or NULL. ++ * \param nr_found The number of found nodes will be returned ++ * through this pointer if not NULL. ++ * \param found_nodes The address of the dynamically allocated array ++ * of found nodes will be returned through this ++ * pointer if not NULL. The caller must free this ++ * array using free(). ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context, ++ const char *address, int port, const struct libiscsi_auth_info *auth_info, ++ int *nr_found, struct libiscsi_node **found_nodes); ++ ++/** \brief Read iSCSI node info from firmware and add them to the node db. ++ * ++ * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found ++ * nodes are added to the local iSCSI node database and are returned in a ++ * dynamically allocated array. ++ * ++ * Note that unlike sendtargets discovery, this function will also read ++ * authentication info and store that in the database too. ++ * ++ * Note this function currently is a stub which will always return -EINVAL ++ * (IOW it is not yet implemented) ++ * ++ * \param context libiscsi context to operate on. ++ * \param nr_found The number of found nodes will be returned ++ * through this pointer if not NULL. ++ * \param found_nodes The address of the dynamically allocated array ++ * of found nodes will be returned through this ++ * pointer if not NULL. The caller must free this ++ * array using free(). ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_discover_firmware(struct libiscsi_context *context, ++ int *nr_found, struct libiscsi_node **found_nodes); ++ ++/** \brief Check validity of the given authentication info. ++ * ++ * This function checks the validity of the given authentication info. For ++ * example in case of CHAP, if the username and password are not empty. ++ * ++ * This function is mainly intended for use by language bindings. ++ * ++ * \param context libiscsi context to operate on. ++ * \param auth_info Authentication information to check. ++ * \return 0 on success, otherwise EINVAL. ++ */ ++PUBLIC int libiscsi_verify_auth_info(struct libiscsi_context *context, ++ const struct libiscsi_auth_info *auth_info); ++ ++/** \brief Set the authentication info for the given node. ++ * ++ * This function sets the authentication information for the node described by ++ * the given node record. This will overwrite any existing authentication ++ * information. ++ * ++ * This is the way to specify authentication information for nodes found ++ * through sendtargets discovery. ++ * ++ * Note: ++ * 1) This is a convience wrapper around libiscsi_node_set_parameter(), ++ * setting the node.session.auth.* parameters. ++ * 2) For nodes found through firmware discovery the authentication information ++ * has already been set from the firmware. ++ * 3) \e auth_info may be NULL in which case any existing authinfo will be ++ * cleared. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to set auth information of ++ * \param auth_info Authentication information, or NULL. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_set_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const struct libiscsi_auth_info *auth_info); ++ ++/** \brief Get the authentication info for the given node. ++ * ++ * This function gets the authentication information for the node described by ++ * the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to set auth information of ++ * \param auth_info Pointer to a libiscsi_auth_info struct where ++ * the retreived information will be stored. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_get_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ struct libiscsi_auth_info *auth_info); ++ ++/** \brief Login to an iSCSI node. ++ * ++ * Login to the iSCSI node described by the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to login to. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_login(struct libiscsi_context *context, ++ const struct libiscsi_node *node); ++ ++/** \brief Logout of an iSCSI node. ++ * ++ * Logout of the iSCSI node described by the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to logout from. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_logout(struct libiscsi_context *context, ++ const struct libiscsi_node *node); ++ ++/** \brief Set an iSCSI parameter for the given node ++ * ++ * Set the given nodes iSCSI parameter named by \e parameter to value \e value. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to change a parameter from. ++ * \param parameter Name of the parameter to set. ++ * \param value Value to set the parameter too. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_set_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const char *parameter, const char *value); ++ ++/** \brief Get the value of an iSCSI parameter for the given node ++ * ++ * Get the value of the given nodes iSCSI parameter named by \e parameter. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to change a parameter from. ++ * \param parameter Name of the parameter to get. ++ * \param value The retreived value is stored here, this buffer must be ++ * atleast LIBISCSI_VALUE_MAXLEN bytes large. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_get_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, const char *parameter, char *value); ++ ++/** \brief Get human readable string describing the last libiscsi error. ++ * ++ * This function can be called to get a human readable error string when a ++ * libiscsi function has returned an error. This function uses a single buffer ++ * per context, thus the result is only valid as long as no other libiscsi ++ * calls are made on the same context after the failing function call. ++ * ++ * \param context libiscsi context to operate on. ++ * ++ * \return human readable string describing the last libiscsi error. ++ */ ++PUBLIC const char *libiscsi_get_error_string(struct libiscsi_context *context); ++ ++ ++/************************** Utility functions *******************************/ ++ ++/** \brief libiscsi network config struct ++ * ++ * libiscsi network config struct. ++ */ ++struct libiscsi_network_config { ++ int dhcp /** Using DHCP? (boolean). */; ++ char iface_name[LIBISCSI_VALUE_MAXLEN] /** Interface name. */; ++ char mac_address[LIBISCSI_VALUE_MAXLEN] /** MAC address. */; ++ char ip_address[LIBISCSI_VALUE_MAXLEN] /** IP address. */; ++ char netmask[LIBISCSI_VALUE_MAXLEN] /** Netmask. */; ++ char gateway[LIBISCSI_VALUE_MAXLEN] /** IP of Default gateway. */; ++ char primary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Primary DNS. */; ++ char secondary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Secondary DNS. */; ++}; ++ ++/** \brief Get network configuration information from iscsi firmware ++ * ++ * Function can be called to get the network configuration information ++ * (like dhcp, ip, netmask, default gateway, etc.) from the firmware of a ++ * network adapter with iscsi boot firmware. ++ * ++ * Note that not all fields of the returned struct are necessarilly filled, ++ * unset fields contain a 0 length string. ++ * ++ * \param config pointer to a libiscsi_network_config struct to fill. ++ * ++ * \return 0 on success, ENODEV when no iscsi firmware was found. ++ */ ++PUBLIC int libiscsi_get_firmware_network_config( ++ struct libiscsi_network_config *config); ++ ++/** \brief Get the initiator name (iqn) from the iscsi firmware ++ * ++ * Get the initiator name (iqn) from the iscsi firmware. ++ * ++ * \param initiatorname The initiator name is stored here, this buffer must be ++ * atleast LIBISCSI_VALUE_MAXLEN bytes large. ++ * \return 0 on success, ENODEV when no iscsi firmware was found. ++ */ ++PUBLIC int libiscsi_get_firmware_initiator_name(char *initiatorname); ++ ++#undef PUBLIC ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif +diff --git a/libiscsi/no_date_footer.html b/libiscsi/no_date_footer.html +new file mode 100644 +index 000000000000..1e0c6c4ab49e +--- /dev/null ++++ b/libiscsi/no_date_footer.html +@@ -0,0 +1,6 @@ ++
++Generated for $projectname by doxygen ++$doxygenversion
++ ++ +diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c +new file mode 100644 +index 000000000000..88008538f04f +--- /dev/null ++++ b/libiscsi/pylibiscsi.c +@@ -0,0 +1,709 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include "libiscsi.h" ++ ++#if PY_MAJOR_VERSION >= 3 ++#define IS_PY3K ++#define MODINITERROR return NULL ++#define PYNUM_FROMLONG PyLong_FromLong ++#define PYSTR_FROMSTRING PyUnicode_FromString ++#else ++#define MODINITERROR return ++#define PYNUM_FROMLONG PyInt_FromLong ++#define PYSTR_FROMSTRING PyString_FromString ++#endif ++ ++#define RET_TRUE_ELSE_FALSE { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } ++#define CMP_TO_RICHCMP(cmpfunc) \ ++ int comp_res = cmpfunc(self, other); \ ++ switch (op) { \ ++ case Py_LT: \ ++ if (comp_res < 0) RET_TRUE_ELSE_FALSE \ ++ case Py_LE: \ ++ if (comp_res <= 0) RET_TRUE_ELSE_FALSE \ ++ case Py_EQ: \ ++ if (comp_res == 0) RET_TRUE_ELSE_FALSE \ ++ case Py_NE: \ ++ if (comp_res != 0) RET_TRUE_ELSE_FALSE \ ++ case Py_GT: \ ++ if (comp_res > 0) RET_TRUE_ELSE_FALSE \ ++ default: \ ++ if (comp_res >= 0) RET_TRUE_ELSE_FALSE \ ++ } ++ ++static struct libiscsi_context *context = NULL; ++ ++/****************************** helpers ***********************************/ ++static int check_string(const char *string) ++{ ++ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) { ++ PyErr_SetString(PyExc_ValueError, "string too long"); ++ return -1; ++ } ++ return 0; ++} ++ ++/********************** PyIscsiChapAuthInfo ***************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_auth_info info; ++} PyIscsiChapAuthInfo; ++ ++static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ int i; ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char *kwlist[] = {"username", "password", "reverse_username", ++ "reverse_password", NULL}; ++ const char *string[4] = { NULL, NULL, NULL, NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, ++ "zz|zz:chapAuthInfo.__init__", ++ kwlist, &string[0], &string[1], ++ &string[2], &string[3])) ++ return -1; ++ ++ for (i = 0; i < 4; i++) ++ if (string[i] && check_string(string[i])) ++ return -1; ++ ++ memset (&chap->info, 0, sizeof(chap->info)); ++ chap->info.method = libiscsi_auth_chap; ++ if (string[0]) ++ strcpy(chap->info.chap.username, string[0]); ++ if (string[1]) ++ strcpy(chap->info.chap.password, string[1]); ++ if (string[2]) ++ strcpy(chap->info.chap.reverse_username, string[2]); ++ if (string[3]) ++ strcpy(chap->info.chap.reverse_password, string[3]); ++ ++ if (libiscsi_verify_auth_info(context, &chap->info)) { ++ PyErr_SetString(PyExc_ValueError, ++ libiscsi_get_error_string(context)); ++ return -1; ++ } ++ return 0; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "username")) { ++ return PYSTR_FROMSTRING(chap->info.chap.username); ++ } else if (!strcmp(attr, "password")) { ++ return PYSTR_FROMSTRING(chap->info.chap.password); ++ } else if (!strcmp(attr, "reverse_username")) { ++ return PYSTR_FROMSTRING(chap->info.chap.reverse_username); ++ } else if (!strcmp(attr, "reverse_password")) { ++ return PYSTR_FROMSTRING(chap->info.chap.reverse_password); ++ } ++ return NULL; ++} ++ ++static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ ++ if (!strcmp(attr, "username")) { ++ strcpy(chap->info.chap.username, str); ++ } else if (!strcmp(attr, "password")) { ++ strcpy(chap->info.chap.password, str); ++ } else if (!strcmp(attr, "reverse_username")) { ++ strcpy(chap->info.chap.reverse_username, str); ++ } else if (!strcmp(attr, "reverse_password")) { ++ strcpy(chap->info.chap.reverse_password, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self, ++ PyIscsiChapAuthInfo *other) ++{ ++ int r; ++ ++ r = strcmp(self->info.chap.username, other->info.chap.username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.password, other->info.chap.password); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_username, ++ other->info.chap.reverse_username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_password, ++ other->info.chap.reverse_password); ++ return r; ++} ++ ++PyObject *PyIscsiChapAuthInfo_richcompare(PyIscsiChapAuthInfo *self, ++ PyIscsiChapAuthInfo *other, ++ int op) ++{ ++ CMP_TO_RICHCMP(PyIscsiChapAuthInfo_compare) ++} ++ ++static PyObject *PyIscsiChapAuthInfo_str(PyObject *self) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char s[1024], reverse[512] = ""; ++ ++ if (chap->info.chap.reverse_username[0]) ++ snprintf(reverse, sizeof(reverse), ", %s:%s", ++ chap->info.chap.reverse_username, ++ chap->info.chap.reverse_password); ++ ++ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username, ++ chap->info.chap.password, reverse); ++ ++ return PYSTR_FROMSTRING(s); ++} ++ ++static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = { ++ {"username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "username", "username"}, ++ {"password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "password", "password"}, ++ {"reverse_username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_username", "reverse_username"}, ++ {"reverse_password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_password", "reverse_password"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiChapAuthInfo_Type = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ .tp_name = "libiscsi.chapAuthInfo", ++ .tp_basicsize = sizeof (PyIscsiChapAuthInfo), ++ .tp_getset = PyIscsiChapAuthInfo_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ++#ifndef IS_PY3K ++ // Py_TPFLAGS_CHECKTYPES is only needed on Python 2 ++ | Py_TPFLAGS_CHECKTYPES ++#endif ++ , ++ .tp_richcompare = (richcmpfunc)PyIscsiChapAuthInfo_compare, ++ .tp_init = PyIscsiChapAuthInfo_init, ++ .tp_str = PyIscsiChapAuthInfo_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "iscsi chap authentication information.", ++}; ++ ++/***************************** PyIscsiNode ********************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_node node; ++} PyIscsiNode; ++ ++static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char *kwlist[] = {"name", "tpgt", "address", "port", "iface", NULL}; ++ const char *name = NULL, *address = NULL, *iface = NULL; ++ int tpgt = -1, port = 3260; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isis:node.__init__", ++ kwlist, &name, &tpgt, &address, ++ &port, &iface)) ++ return -1; ++ if (address == NULL) { ++ PyErr_SetString(PyExc_ValueError, "address not set"); ++ return -1; ++ } ++ if (check_string(name) || check_string(address) || check_string(iface)) ++ return -1; ++ ++ strcpy(node->node.name, name); ++ node->node.tpgt = tpgt; ++ strcpy(node->node.address, address); ++ node->node.port = port; ++ strcpy(node->node.iface, iface); ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_get(PyObject *self, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "name")) { ++ return PYSTR_FROMSTRING(node->node.name); ++ } else if (!strcmp(attr, "tpgt")) { ++ return PYNUM_FROMLONG(node->node.tpgt); ++ } else if (!strcmp(attr, "address")) { ++ return PYSTR_FROMSTRING(node->node.address); ++ } else if (!strcmp(attr, "port")) { ++ return PYNUM_FROMLONG(node->node.port); ++ } else if (!strcmp(attr, "iface")) { ++ return PYSTR_FROMSTRING(node->node.iface); ++ } ++ return NULL; ++} ++ ++static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ int i; ++ ++ if (!strcmp(attr, "name")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.name, str); ++ } else if (!strcmp(attr, "tpgt")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.tpgt = i; ++ } else if (!strcmp(attr, "address")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.address, str); ++ } else if (!strcmp(attr, "port")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.port = i; ++ } else if (!strcmp(attr, "iface")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.iface, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other) ++{ ++ int res; ++ ++ res = strcmp(self->node.name, other->node.name); ++ if (res) ++ return res; ++ ++ if (self->node.tpgt < other->node.tpgt) ++ return -1; ++ if (self->node.tpgt > other->node.tpgt) ++ return -1; ++ ++ res = strcmp(self->node.address, other->node.address); ++ if (res) ++ return res; ++ ++ if (self->node.port < other->node.port) ++ return -1; ++ if (self->node.port > other->node.port) ++ return -1; ++ ++ res = strcmp(self->node.iface, other->node.iface); ++ if (res) ++ return res; ++ ++ return 0; ++} ++ ++PyObject *PyIscsiNode_richcompare(PyIscsiNode *self, PyIscsiNode *other, int op) ++{ ++ CMP_TO_RICHCMP(PyIscsiNode_compare) ++} ++ ++static PyObject *PyIscsiNode_str(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char s[1024], tpgt[16] = ""; ++ ++ if (node->node.tpgt != -1) ++ sprintf(tpgt, ",%d", node->node.tpgt); ++ ++ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address, ++ node->node.port, tpgt, node->node.name); ++ ++ return PYSTR_FROMSTRING(s); ++} ++ ++static PyObject *PyIscsiNode_login(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_login(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_logout(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_logout(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"authinfo", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyObject *arg; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) ++ return NULL; ++ ++ if (arg == Py_None) { ++ authinfo = NULL; ++ } else if (PyObject_IsInstance(arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg; ++ authinfo = &pyauthinfo->info; ++ } else { ++ PyErr_SetString(PyExc_ValueError, "invalid authinfo type"); ++ return NULL; ++ } ++ ++ if (libiscsi_node_set_auth(context, &node->node, authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getAuth(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyIscsiChapAuthInfo *pyauthinfo; ++ struct libiscsi_auth_info authinfo; ++ ++ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ switch (authinfo.method) { ++ case libiscsi_auth_chap: ++ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo, ++ &PyIscsiChapAuthInfo_Type); ++ if (!pyauthinfo) ++ return NULL; ++ ++ pyauthinfo->info = authinfo; ++ ++ return (PyObject *)pyauthinfo; ++ ++ case libiscsi_auth_none: ++ default: ++ Py_RETURN_NONE; ++ } ++} ++ ++static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", "value", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter, *value; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, ++ ¶meter, &value)) ++ return NULL; ++ if (check_string(parameter) || check_string(value)) ++ return NULL; ++ ++ if (libiscsi_node_set_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, ¶meter)) ++ return NULL; ++ if (check_string(parameter)) ++ return NULL; ++ ++ if (libiscsi_node_get_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ return Py_BuildValue("s", value); ++} ++ ++static struct PyGetSetDef PyIscsiNode_getseters[] = { ++ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "name", "name"}, ++ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "tpgt", "tpgt"}, ++ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "address", "address"}, ++ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "port", "port"}, ++ {"iface", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "iface", "iface"}, ++ {NULL} ++}; ++ ++static struct PyMethodDef PyIscsiNode_methods[] = { ++ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS, ++ "Log in to the node"}, ++ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS, ++ "Log out of the node"}, ++ {"setAuth", (PyCFunction) PyIscsiNode_setAuth, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set authentication information"}, ++ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS, ++ "Get authentication information"}, ++ {"setParameter", (PyCFunction) PyIscsiNode_setParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set an iscsi node parameter"}, ++ {"getParameter", (PyCFunction) PyIscsiNode_getParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Get an iscsi node parameter"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiNode_Type = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ .tp_name = "libiscsi.node", ++ .tp_basicsize = sizeof (PyIscsiNode), ++ .tp_getset = PyIscsiNode_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ++#ifndef IS_PY3K ++ | Py_TPFLAGS_CHECKTYPES ++#endif ++ , ++ .tp_methods = PyIscsiNode_methods, ++ .tp_richcompare = (richcmpfunc)PyIscsiNode_richcompare, ++ .tp_init = PyIscsiNode_init, ++ .tp_str = PyIscsiNode_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "The iscsi node contains iscsi node information.", ++}; ++ ++/***************************************************************************/ ++ ++static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, ++ PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"address", "port", "authinfo", NULL}; ++ const char *address = NULL; ++ int i, nr_found, port = 3260; ++ PyObject *authinfo_arg = NULL; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO", ++ kwlist, &address, &port, ++ &authinfo_arg)) ++ return NULL; ++ ++ if (authinfo_arg) { ++ if (PyObject_IsInstance(authinfo_arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = ++ (PyIscsiChapAuthInfo *)authinfo_arg; ++ authinfo = &pyauthinfo->info; ++ } else if (authinfo_arg != Py_None) { ++ PyErr_SetString(PyExc_ValueError, ++ "invalid authinfo type"); ++ return NULL; ++ } ++ } ++ ++ if (libiscsi_discover_sendtargets(context, address, port, authinfo, ++ &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_discover_firmware(PyObject *self) ++{ ++ int i, nr_found; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (libiscsi_discover_firmware(context, &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_get_firmware_initiator_name(PyObject *self) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ return PYSTR_FROMSTRING(initiatorname); ++} ++ ++static PyMethodDef pylibiscsi_functions[] = { ++ { "discover_sendtargets", ++ (PyCFunction)pylibiscsi_discover_sendtargets, ++ METH_VARARGS|METH_KEYWORDS, ++ "Do sendtargets discovery and return a list of found nodes)"}, ++ { "discover_firmware", ++ (PyCFunction)pylibiscsi_discover_firmware, METH_NOARGS, ++ "Do firmware discovery and return a list of found nodes)"}, ++ { "get_firmware_initiator_name", ++ (PyCFunction)pylibiscsi_get_firmware_initiator_name, ++ METH_NOARGS, ++ "Get initator name (iqn) from firmware"}, ++ {NULL, NULL} ++}; ++ ++#ifdef IS_PY3K ++static struct PyModuleDef libiscsi_def = { ++ PyModuleDef_HEAD_INIT, ++ "libiscsi", ++ NULL, ++ -1, ++ pylibiscsi_functions, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ ++PyMODINIT_FUNC PyInit_libiscsi(void) ++#else ++PyMODINIT_FUNC initlibiscsi(void) ++#endif ++{ ++ PyObject *m; ++ ++ if (!context) /* We may be called more then once */ ++ context = libiscsi_init(); ++ if (!context) ++ MODINITERROR; ++ ++ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0) ++ MODINITERROR; ++ ++ if (PyType_Ready(&PyIscsiNode_Type) < 0) ++ MODINITERROR; ++ ++#ifdef IS_PY3K ++ m = PyModule_Create(&libiscsi_def); ++#else ++ m = Py_InitModule("libiscsi", pylibiscsi_functions); ++#endif ++ Py_INCREF(&PyIscsiChapAuthInfo_Type); ++ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type); ++ Py_INCREF(&PyIscsiNode_Type); ++ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type); ++#ifdef IS_PY3K ++ return m; ++#endif ++} +diff --git a/libiscsi/setup.py b/libiscsi/setup.py +new file mode 100644 +index 000000000000..caa4e66ca906 +--- /dev/null ++++ b/libiscsi/setup.py +@@ -0,0 +1,9 @@ ++from distutils.core import setup, Extension ++ ++module1 = Extension('libiscsi', ++ sources = ['pylibiscsi.c'], ++ libraries = ['iscsi'], ++ library_dirs = ['.']) ++ ++setup (name = 'PyIscsi',version = '1.0', ++ description = 'libiscsi python bindings', ext_modules = [module1]) +diff --git a/libiscsi/tests/test_discovery_firmware.c b/libiscsi/tests/test_discovery_firmware.c +new file mode 100644 +index 000000000000..76e852a37019 +--- /dev/null ++++ b/libiscsi/tests/test_discovery_firmware.c +@@ -0,0 +1,53 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_discover_firmware(context, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_discovery_sendtargets.c b/libiscsi/tests/test_discovery_sendtargets.c +new file mode 100644 +index 000000000000..1a3c12ef684b +--- /dev/null ++++ b/libiscsi/tests/test_discovery_sendtargets.c +@@ -0,0 +1,60 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ rc = libiscsi_discover_sendtargets(context, "127.0.0.1", 3260, ++ &auth_info, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_get_auth.c b/libiscsi/tests/test_get_auth.c +new file mode 100644 +index 000000000000..5e234dadd0de +--- /dev/null ++++ b/libiscsi/tests/test_get_auth.c +@@ -0,0 +1,70 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_auth(context, &node, &auth_info); ++ if (rc) { ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ switch (auth_info.method) { ++ case libiscsi_auth_none: ++ printf("Method: \"None\"\n"); ++ break; ++ case libiscsi_auth_chap: ++ printf("Method: \"CHAP\"\n"); ++ printf("User: \"%s\"\n", auth_info.chap.username); ++ printf("Pass: \"%s\"\n", auth_info.chap.password); ++ printf("RevUser: \"%s\"\n", ++ auth_info.chap.reverse_username); ++ printf("RevPass: \"%s\"\n", ++ auth_info.chap.reverse_password); ++ break; ++ } ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_get_initiator_name.c b/libiscsi/tests/test_get_initiator_name.c +new file mode 100644 +index 000000000000..997c053e5bf6 +--- /dev/null ++++ b/libiscsi/tests/test_get_initiator_name.c +@@ -0,0 +1,38 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("iqn:\t%s\n", initiatorname); ++ ++ return 0; ++} +diff --git a/libiscsi/tests/test_get_network_config.c b/libiscsi/tests/test_get_network_config.c +new file mode 100644 +index 000000000000..2dedd6102858 +--- /dev/null ++++ b/libiscsi/tests/test_get_network_config.c +@@ -0,0 +1,45 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_network_config config; ++ ++ if (libiscsi_get_firmware_network_config(&config)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("dhcp:\t%d\n", config.dhcp); ++ printf("iface:\t%s\n", config.iface_name); ++ printf("mac:\t%s\n", config.mac_address); ++ printf("ipaddr:\t%s\n", config.ip_address); ++ printf("mask:\t%s\n", config.netmask); ++ printf("gate:\t%s\n", config.gateway); ++ printf("dns1:\t%s\n", config.primary_dns); ++ printf("dns2:\t%s\n", config.secondary_dns); ++ ++ return 0; ++} +diff --git a/libiscsi/tests/test_login.c b/libiscsi/tests/test_login.c +new file mode 100644 +index 000000000000..3eb70d63e111 +--- /dev/null ++++ b/libiscsi/tests/test_login.c +@@ -0,0 +1,52 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_login(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging in: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_logout.c b/libiscsi/tests/test_logout.c +new file mode 100644 +index 000000000000..b734dca58773 +--- /dev/null ++++ b/libiscsi/tests/test_logout.c +@@ -0,0 +1,51 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_logout(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging out: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_params.c b/libiscsi/tests/test_params.c +new file mode 100644 +index 000000000000..d3223be1e894 +--- /dev/null ++++ b/libiscsi/tests/test_params.c +@@ -0,0 +1,103 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ char orig_value[LIBISCSI_VALUE_MAXLEN], value[LIBISCSI_VALUE_MAXLEN]; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ "automatic"); ++ if (rc) { ++ fprintf(stderr, "Error setting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error getting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, "automatic")) { ++ fprintf(stderr, "Error set and get values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error setting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error re-getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, orig_value)) { ++ fprintf(stderr, ++ "Error set and get original values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_set_auth.c b/libiscsi/tests/test_set_auth.c +new file mode 100644 +index 000000000000..a21f88806ab9 +--- /dev/null ++++ b/libiscsi/tests/test_set_auth.c +@@ -0,0 +1,58 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_set_auth(context, &node, &auth_info); ++ if (rc) ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/usr/Makefile b/usr/Makefile +index f9445adabbb0..8751d0d05468 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -35,7 +35,7 @@ endif + CFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wstrict-prototypes + CFLAGS += $(WARNFLAGS) -I../include -I. -D_GNU_SOURCE \ +- -I$(TOPDIR)/libopeniscsiusr ++ -I$(TOPDIR)/libopeniscsiusr -DISNS_ENABLE + ISCSI_LIB = -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr + PROGRAMS = iscsid iscsiadm iscsistart + +diff --git a/usr/discovery.c b/usr/discovery.c +index 8001af6fe452..02b77f02b644 100644 +--- a/usr/discovery.c ++++ b/usr/discovery.c +@@ -36,6 +36,7 @@ + #include "types.h" + #include "iscsi_proto.h" + #include "initiator.h" ++#include "config.h" + #include "log.h" + #include "idbm.h" + #include "iscsi_settings.h" +@@ -49,10 +50,12 @@ + #include "iface.h" + #include "iscsi_timer.h" + #include "iscsi_err.h" ++#ifdef ISNS_ENABLE + /* libisns includes */ + #include + #include + #include ++#endif + + #ifdef SLP_ENABLE + #include "iscsi-slp-discovery.h" +@@ -98,6 +101,7 @@ static int request_initiator_name(int tmo) + return 0; + } + ++#ifdef ISNS_ENABLE + void discovery_isns_free_servername(void) + { + if (isns_config.ic_server_name) +@@ -377,6 +381,7 @@ retry: + discovery_isns_free_servername(); + return rc; + } ++#endif + + int discovery_fw(void *data, struct iface_rec *iface, + struct list_head *rec_list) +diff --git a/usr/idbm.c b/usr/idbm.c +index ec33ce905dc1..6b651765f19e 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1709,9 +1709,9 @@ int idbm_print_all_discovery(int info_level) + * fn should return -1 if it skipped the rec, an ISCSI_ERR error code if + * the operation failed or 0 if fn was run successfully. + */ +-static int idbm_for_each_iface(int *found, void *data, +- idbm_iface_op_fn *fn, +- char *targetname, int tpgt, char *ip, int port) ++int idbm_for_each_iface(int *found, void *data, ++ idbm_iface_op_fn *fn, ++ char *targetname, int tpgt, char *ip, int port) + { + DIR *iface_dirfd; + struct dirent *iface_dent; +diff --git a/usr/idbm.h b/usr/idbm.h +index 2b05d7871be9..b9b1810f78f2 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -102,6 +102,9 @@ struct rec_op_data { + node_rec_t *match_rec; + idbm_iface_op_fn *fn; + }; ++extern int idbm_for_each_iface(int *found, void *data, ++ idbm_iface_op_fn *fn, ++ char *targetname, int tpgt, char *ip, int port); + extern int idbm_for_each_portal(int *found, void *data, + idbm_portal_op_fn *fn, char *targetname); + extern int idbm_for_each_node(int *found, void *data, +diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h +index 47857dd9b0ca..fb8e96552551 100644 +--- a/usr/iscsi_ipc.h ++++ b/usr/iscsi_ipc.h +@@ -162,4 +162,6 @@ struct iscsi_ipc { + char *host_stats); + }; + ++struct iscsi_ipc *ipc; ++ + #endif /* ISCSI_IPC_H */ +-- +2.14.4 + diff --git a/SOURCES/0010-remove-the-offload-boot-supported-ifdef.patch b/SOURCES/0010-remove-the-offload-boot-supported-ifdef.patch new file mode 100644 index 0000000..3fe3789 --- /dev/null +++ b/SOURCES/0010-remove-the-offload-boot-supported-ifdef.patch @@ -0,0 +1,45 @@ +From 71b576b10a03651f67173d19883a929e91a3423a Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 17:09:24 -0800 +Subject: [PATCH 10/32] remove the offload boot supported ifdef + +--- + usr/iface.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/usr/iface.c b/usr/iface.c +index 137138f5af67..889fe8cd8202 100644 +--- a/usr/iface.c ++++ b/usr/iface.c +@@ -993,6 +993,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + { + struct iscsi_transport *t = NULL; + uint32_t hostno; ++ int rc; + + if (strlen(context->initiatorname)) + strlcpy(iface->iname, context->initiatorname, +@@ -1006,10 +1007,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + return 0; + } + } else if (strlen(context->iface)) { +-/* this ifdef is only temp until distros and firmwares are updated */ +-#ifdef OFFLOAD_BOOT_SUPPORTED + char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; +- int rc; + + memset(transport_name, 0, ISCSI_TRANSPORT_NAME_MAXLEN); + /* make sure offload driver is loaded */ +@@ -1035,9 +1033,6 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + } + + strlcpy(iface->netdev, context->iface, sizeof(iface->netdev)); +-#else +- return 0; +-#endif + } else + return 0; + +-- +2.14.4 + diff --git a/SOURCES/0011-iscsiuio-systemd-unit-files.patch b/SOURCES/0011-iscsiuio-systemd-unit-files.patch new file mode 100644 index 0000000..da97e01 --- /dev/null +++ b/SOURCES/0011-iscsiuio-systemd-unit-files.patch @@ -0,0 +1,53 @@ +From f16f7f90721c9d6965e48c7338a600d23b58e19d Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 22 Jan 2013 14:27:12 -0800 +Subject: [PATCH 11/32] iscsiuio systemd unit files + +--- + etc/systemd/iscsiuio.service | 17 +++++++++++++++++ + etc/systemd/iscsiuio.socket | 9 +++++++++ + 2 files changed, 26 insertions(+) + create mode 100644 etc/systemd/iscsiuio.service + create mode 100644 etc/systemd/iscsiuio.socket + +diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service +new file mode 100644 +index 000000000000..f0410b76b80e +--- /dev/null ++++ b/etc/systemd/iscsiuio.service +@@ -0,0 +1,17 @@ ++[Unit] ++Description=iSCSI UserSpace I/O driver ++Documentation=man:iscsiuio(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++Requires=iscsid.service ++BindTo=iscsid.service ++After=network.target ++Before=remote-fs-pre.target iscsid.service ++ ++[Service] ++Type=forking ++PIDFile=/var/run/iscsiuio.pid ++ExecStart=/usr/sbin/iscsiuio ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/etc/systemd/iscsiuio.socket b/etc/systemd/iscsiuio.socket +new file mode 100644 +index 000000000000..d42cedc161a3 +--- /dev/null ++++ b/etc/systemd/iscsiuio.socket +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Open-iSCSI iscsiuio Socket ++Documentation=man:iscsiuio(8) ++ ++[Socket] ++ListenStream=@ISCSID_UIP_ABSTRACT_NAMESPACE ++ ++[Install] ++WantedBy=sockets.target +-- +2.14.4 + diff --git a/SOURCES/0012-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch b/SOURCES/0012-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch new file mode 100644 index 0000000..9980d61 --- /dev/null +++ b/SOURCES/0012-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch @@ -0,0 +1,30 @@ +From 9807bf0a042238891f2008a5a6d70acfd6724b12 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 28 May 2013 13:12:27 -0700 +Subject: [PATCH 12/32] Don't check for autostart sessions if iscsi is not used + (bug #951951) + +Change conditional startup in iscsi.service to check for a non-empty +nodes directory, instead of initiator-name. This fits better with what +it's doing, as there's no need to scan for autostart node records if +there are no node records at all. +--- + etc/systemd/iscsi.service | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index 0309e2fc9892..d5712bd3779b 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,7 +5,7 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target +-ConditionPathExists=/etc/iscsi/initiatorname.iscsi ++ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes + + [Service] + Type=oneshot +-- +2.14.4 + diff --git a/SOURCES/0013-Revert-iscsiadm-return-error-when-login-fails.patch b/SOURCES/0013-Revert-iscsiadm-return-error-when-login-fails.patch new file mode 100644 index 0000000..23e5e7d --- /dev/null +++ b/SOURCES/0013-Revert-iscsiadm-return-error-when-login-fails.patch @@ -0,0 +1,34 @@ +From 6629618e3581cbe632b7408a49437270bc04a8d4 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 24 Feb 2014 09:33:33 -0800 +Subject: [PATCH 13/32] Revert "iscsiadm: return error when login fails" + +This reverts commit fc2a8e9a2911bc76f961fe3e4a159fab9b8b9691. + +Done to address RHBZ #1015563 +--- + usr/session_mgmt.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c +index 596085b1f640..07f587d2bafb 100644 +--- a/usr/session_mgmt.c ++++ b/usr/session_mgmt.c +@@ -178,12 +178,12 @@ int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec) + goto done; + } + if (session_count >= rec->session.nr_sessions) { +- log_warning("%s: %d session%s requested, but %d " ++ log_debug(1, "%s: %d session%s requested, but %d " + "already present.", + rec->iface.name, rec->session.nr_sessions, + rec->session.nr_sessions == 1 ? "" : "s", + session_count); +- rc = ISCSI_ERR_SESS_EXISTS; ++ rc = 0; + goto done; + } + +-- +2.14.4 + diff --git a/SOURCES/0014-update-handling-of-boot-sessions.patch b/SOURCES/0014-update-handling-of-boot-sessions.patch new file mode 100644 index 0000000..953bef9 --- /dev/null +++ b/SOURCES/0014-update-handling-of-boot-sessions.patch @@ -0,0 +1,55 @@ +From c7b743486c6a499a037744760846abdb42959808 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 26 Feb 2014 16:33:48 -0800 +Subject: [PATCH 14/32] update handling of boot sessions + +force start iscsiuio if needed, socket activation does not seem to be +working for recovery +--- + etc/systemd/iscsi-mark-root-nodes | 29 +++++++++++++++++++++++------ + 1 file changed, 23 insertions(+), 6 deletions(-) + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +index 157be62b4041..6bddf6c5ccc1 100644 +--- a/etc/systemd/iscsi-mark-root-nodes ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -1,13 +1,30 @@ + #!/bin/bash + + ISCSIADM=/sbin/iscsiadm ++start_iscsid=0 ++start_iscsiuio=0 + +-$ISCSIADM -m session >/dev/null 2>&1 || exit 0 ++while read t num p target flash; do ++ # strip tag number from portal, keep "ip:port" ++ portal=${p%,*} ++ transport=${t%:} + +-$ISCSIADM -m session | while read t num i target; do +- ip=${i%:*} +- $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot +-done ++ $ISCSIADM -m node -p $portal -T $target -o update -n node.startup -v onboot + +-systemctl start iscsid.service ++ start_iscsid=1 ++ ++ if [ "$transport" = bnx2i ] || [ "$transport" = qedi ]; then ++ start_iscsiuio=1 ++ fi ++done < <( $ISCSIADM -m session ) ++ ++# force iscsid and iscsiuio to start if needed for ++# recovering sessions created in the initrd ++ ++if [ "$start_iscsid" -eq 1 ]; then ++ systemctl --no-block start iscsid.service ++fi ++if [ "$start_iscsiuio" -eq 1 ]; then ++ systemctl --no-block start iscsiuio.service ++fi + +-- +2.14.4 + diff --git a/SOURCES/0015-update-iscsi.service-for-boot-session-recovery.patch b/SOURCES/0015-update-iscsi.service-for-boot-session-recovery.patch new file mode 100644 index 0000000..96454d2 --- /dev/null +++ b/SOURCES/0015-update-iscsi.service-for-boot-session-recovery.patch @@ -0,0 +1,34 @@ +From f349a706ec083574fbf7ed1e479fdfebde7023b8 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Fri, 14 Mar 2014 09:22:21 -0700 +Subject: [PATCH 15/32] update iscsi.service for boot session recovery + +--- + etc/systemd/iscsi.service | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index d5712bd3779b..3de76c5b07ec 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,14 +5,15 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target +-ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes ++ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes ++ConditionDirectoryNotEmpty=|/sys/class/iscsi_session + + [Service] + Type=oneshot + RemainAfterExit=true + ExecStart=/usr/libexec/iscsi-mark-root-nodes ++SuccessExitStatus=21 + ExecStart=/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=/bin/sync + ExecStop=/sbin/iscsiadm -m node --logoutall=automatic + ExecReload=/sbin/iscsiadm -m node --loginall=automatic + +-- +2.14.4 + diff --git a/SOURCES/0016-updates-to-iscsi.service.patch b/SOURCES/0016-updates-to-iscsi.service.patch new file mode 100644 index 0000000..edb9005 --- /dev/null +++ b/SOURCES/0016-updates-to-iscsi.service.patch @@ -0,0 +1,41 @@ +From 954ab51516734aaeed01a195a6e70b825b0bf10a Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 17 Sep 2014 09:58:39 -0700 +Subject: [PATCH 16/32] updates to iscsi.service + +Resolves: #1126524 +Resolves: #1111925 +--- + etc/systemd/iscsi.service | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index 3de76c5b07ec..ad7be34d5918 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,17 +5,17 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target ++Wants=remote-fs-pre.target + ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes + ConditionDirectoryNotEmpty=|/sys/class/iscsi_session + + [Service] + Type=oneshot + RemainAfterExit=true +-ExecStart=/usr/libexec/iscsi-mark-root-nodes +-SuccessExitStatus=21 +-ExecStart=/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=/sbin/iscsiadm -m node --logoutall=automatic +-ExecReload=/sbin/iscsiadm -m node --loginall=automatic ++ExecStart=-/usr/libexec/iscsi-mark-root-nodes ++ExecStart=-/sbin/iscsiadm -m node --loginall=automatic ++ExecStop=-/sbin/iscsiadm -m node --logoutall=automatic ++ExecReload=-/sbin/iscsiadm -m node --loginall=automatic + + [Install] + WantedBy=sysinit.target +-- +2.14.4 + diff --git a/SOURCES/0017-make-session-shutdown-a-seperate-service.patch.patch b/SOURCES/0017-make-session-shutdown-a-seperate-service.patch.patch new file mode 100644 index 0000000..e1ae024 --- /dev/null +++ b/SOURCES/0017-make-session-shutdown-a-seperate-service.patch.patch @@ -0,0 +1,55 @@ +From 3815643d7db65487fa2b7058dd612ddf2549f85a Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 13 Jan 2015 16:30:01 -0800 +Subject: [PATCH 17/32] make-session-shutdown-a-seperate-service.patch + +--- + etc/systemd/iscsi-shutdown.service | 14 ++++++++++++++ + etc/systemd/iscsi.service | 3 +-- + 2 files changed, 15 insertions(+), 2 deletions(-) + create mode 100644 etc/systemd/iscsi-shutdown.service + +diff --git a/etc/systemd/iscsi-shutdown.service b/etc/systemd/iscsi-shutdown.service +new file mode 100644 +index 000000000000..23758e959ff2 +--- /dev/null ++++ b/etc/systemd/iscsi-shutdown.service +@@ -0,0 +1,14 @@ ++[Unit] ++Description=Logout off all iSCSI sessions on shutdown ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++Wants=remote-fs-pre.target ++RefuseManualStop=yes ++ ++[Service] ++Type=oneshot ++RemainAfterExit=true ++ExecStop=-/sbin/iscsiadm -m node --logoutall=all +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index ad7be34d5918..27369568bf35 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,7 +5,7 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target +-Wants=remote-fs-pre.target ++Wants=remote-fs-pre.target iscsi-shutdown.service + ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes + ConditionDirectoryNotEmpty=|/sys/class/iscsi_session + +@@ -14,7 +14,6 @@ Type=oneshot + RemainAfterExit=true + ExecStart=-/usr/libexec/iscsi-mark-root-nodes + ExecStart=-/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=-/sbin/iscsiadm -m node --logoutall=automatic + ExecReload=-/sbin/iscsiadm -m node --loginall=automatic + + [Install] +-- +2.14.4 + diff --git a/SOURCES/0018-Add-macros-to-release-GIL-lock.patch b/SOURCES/0018-Add-macros-to-release-GIL-lock.patch new file mode 100644 index 0000000..37a5d01 --- /dev/null +++ b/SOURCES/0018-Add-macros-to-release-GIL-lock.patch @@ -0,0 +1,56 @@ +From bd26fd7e7f91e5c4c6903c3d7e1a375a14261a48 Mon Sep 17 00:00:00 2001 +From: Jiri Konecny +Date: Mon, 11 May 2015 13:16:26 +0200 +Subject: [PATCH 18/32] Add macros to release GIL lock + +Other threads are blocked when GIL is not released before the time consuming +functions. +--- + libiscsi/pylibiscsi.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c +index 88008538f04f..40b59553a28e 100644 +--- a/libiscsi/pylibiscsi.c ++++ b/libiscsi/pylibiscsi.c +@@ -364,8 +364,13 @@ static PyObject *PyIscsiNode_str(PyObject *self) + static PyObject *PyIscsiNode_login(PyObject *self) + { + PyIscsiNode *node = (PyIscsiNode *)self; ++ int ret; + +- if (libiscsi_node_login(context, &node->node)) { ++ Py_BEGIN_ALLOW_THREADS ++ ret = libiscsi_node_login(context, &node->node); ++ Py_END_ALLOW_THREADS ++ ++ if (ret) { + PyErr_SetString(PyExc_IOError, + libiscsi_get_error_string(context)); + return NULL; +@@ -551,6 +556,7 @@ static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, + const struct libiscsi_auth_info *authinfo = NULL; + struct libiscsi_node *found_nodes; + PyObject* found_node_list; ++ int ret; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO", + kwlist, &address, &port, +@@ -570,8 +576,12 @@ static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, + } + } + +- if (libiscsi_discover_sendtargets(context, address, port, authinfo, +- &nr_found, &found_nodes)) { ++ Py_BEGIN_ALLOW_THREADS ++ ret = libiscsi_discover_sendtargets(context, address, port, authinfo, ++ &nr_found, &found_nodes); ++ Py_END_ALLOW_THREADS ++ ++ if (ret) { + PyErr_SetString(PyExc_IOError, + libiscsi_get_error_string(context)); + return NULL; +-- +2.14.4 + diff --git a/SOURCES/0019-libiscsi-introduce-sessions-API.patch b/SOURCES/0019-libiscsi-introduce-sessions-API.patch new file mode 100644 index 0000000..5bc1b38 --- /dev/null +++ b/SOURCES/0019-libiscsi-introduce-sessions-API.patch @@ -0,0 +1,290 @@ +From 7671cd56d36a76e954318cbdce3f08fc40aa3fe4 Mon Sep 17 00:00:00 2001 +From: Peter Hatina +Date: Mon, 5 Oct 2015 16:50:36 -0700 +Subject: [PATCH 19/32] libiscsi introduce sessions API + +--- + libiscsi/libiscsi.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + libiscsi/libiscsi.h | 56 +++++++++++++++++++++++ + usr/iscsi_sysfs.c | 6 +++ + usr/iscsi_sysfs.h | 2 + + 4 files changed, 189 insertions(+) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index 064e4b570d0b..755c18ca8e3b 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. + * Copyright (C) 2008-2009 Hans de Goede ++ * Copyright (C) 2015 Peter Hatina + * maintained by open-iscsi@googlegroups.com + * + * This program is free software; you can redistribute it and/or modify +@@ -469,6 +470,130 @@ leave: + return rc; + } + ++struct libiscsi_session_array { ++ int cnt; ++ int size; ++ struct libiscsi_session_info *data; ++}; ++ ++static void libiscsi_session_array_init(struct libiscsi_session_array *arr) ++{ ++ arr->cnt = 0; ++ arr->size = 0; ++ arr->data = NULL; ++} ++ ++static int libiscsi_session_array_grow(struct libiscsi_session_array *arr) ++{ ++ if (arr->size == 0) ++ arr->size = 4; ++ else ++ arr->size *= 2; ++ ++ arr->data = (struct libiscsi_session_info *) realloc( ++ arr->data, ++ arr->size * sizeof(struct libiscsi_session_info)); ++ ++ return arr->data ? 0 : 1; ++} ++ ++static int libiscsi_session_array_grow_ondemand(struct libiscsi_session_array *arr) ++{ ++ if (arr->size == arr->cnt) ++ return libiscsi_session_array_grow(arr); ++ return 0; ++} ++ ++static int libiscsi_session_array_resize_precize(struct libiscsi_session_array *arr) ++{ ++ arr->data = (struct libiscsi_session_info *) realloc( ++ arr->data, ++ arr->cnt * sizeof(struct libiscsi_session_info)); ++ arr->size = arr->cnt; ++ ++ return arr->data ? 0 : 1; ++} ++ ++static void copy_session_info_to_libiscsi_session_info( ++ struct libiscsi_session_info *info, ++ struct session_info *s_info) ++{ ++ /* Copy session info to public struct. */ ++ info->sid = s_info->sid; ++ /* Timeouts */ ++ memcpy(&info->tmo, &s_info->tmo, sizeof(struct libiscsi_session_timeout)); ++ /* CHAP authentication information */ ++ memcpy(&info->chap, &s_info->chap, sizeof(struct libiscsi_chap_auth_info)); ++ /* Target information */ ++ strncpy(info->targetname, s_info->targetname, LIBISCSI_VALUE_MAXLEN); ++ strncpy(info->address, s_info->address, NI_MAXHOST); ++ strncpy(info->persistent_address, s_info->persistent_address, NI_MAXHOST); ++ info->tpgt = s_info->tpgt; ++ info->persistent_port = s_info->persistent_port; ++} ++ ++static int get_sessions_helper(void *data, struct session_info *s_info) ++{ ++ struct libiscsi_session_array *arr = (struct libiscsi_session_array *) data; ++ ++ if (libiscsi_session_array_grow_ondemand(arr) != 0) ++ return 1; ++ ++ copy_session_info_to_libiscsi_session_info(&arr->data[arr->cnt++], s_info); ++ ++ return 0; ++} ++ ++int libiscsi_get_session_infos(struct libiscsi_context *context, ++ struct libiscsi_session_info **infos, ++ int *nr_sessions) ++{ ++ int rc = 0; ++ int nr_found = 0; ++ struct libiscsi_session_array arr; ++ ++ if (!context || !infos || !nr_sessions) ++ return 1; ++ ++ libiscsi_session_array_init(&arr); ++ ++ rc = iscsi_sysfs_for_each_session((void *) &arr, &nr_found, ++ get_sessions_helper, 0); ++ if (rc != 0 || nr_found == 0) { ++ strcpy(context->error_str, "No matching session"); ++ return ENODEV; ++ } ++ ++ if (libiscsi_session_array_resize_precize(&arr) != 0) { ++ strcpy(context->error_str, "Can't allocate memory for session infos"); ++ return ENOMEM; ++ } ++ ++ *infos = arr.data; ++ *nr_sessions = nr_found; ++ ++ return 0; ++} ++ ++int libiscsi_get_session_info_by_id(struct libiscsi_context *context, ++ struct libiscsi_session_info *info, ++ const char *session) ++{ ++ struct session_info s_info; ++ ++ if (!context || !info || !session) ++ return 1; ++ ++ if (iscsi_sysfs_get_sessioninfo_by_id(&s_info, (char*) session) != 0) { ++ strcpy(context->error_str, "No matching session"); ++ return ENODEV; ++ } ++ ++ copy_session_info_to_libiscsi_session_info(info, &s_info); ++ ++ return 0; ++} ++ + int libiscsi_node_set_parameter(struct libiscsi_context *context, + const struct libiscsi_node *node, + const char *parameter, const char *value) +diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h +index 756590e14d8b..a9891f48b7d6 100644 +--- a/libiscsi/libiscsi.h ++++ b/libiscsi/libiscsi.h +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. + * Copyright (C) 2008-2009 Hans de Goede ++ * Copyright (C) 2015 Peter Hatina + * maintained by open-iscsi@googlegroups.com + * + * This program is free software; you can redistribute it and/or modify +@@ -56,6 +57,17 @@ enum libiscsi_auth_t { + */ + struct libiscsi_context; + ++/** \brief iSCSI session timeouts ++ * ++ * Struct holding session timeouts. ++ */ ++struct libiscsi_session_timeout { ++ int abort_tmo; ++ int lu_reset_tmo; ++ int recovery_tmo; ++ int tgt_reset_tmo; ++}; ++ + /** \brief iSCSI node record + * + * Struct holding data uniquely identifying an iSCSI node. +@@ -84,6 +96,24 @@ struct libiscsi_chap_auth_info { + char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */; + }; + ++/** \brief iSCSI session ++ * ++ * Struct hoding iSCSI session information. ++ */ ++struct libiscsi_session_info { ++ int sid; ++ ++ struct libiscsi_session_timeout tmo; ++ struct libiscsi_chap_auth_info chap; ++ ++ char targetname[LIBISCSI_VALUE_MAXLEN]; ++ int tpgt; ++ char address[NI_MAXHOST]; ++ int port; ++ char persistent_address[NI_MAXHOST]; ++ int persistent_port; ++}; ++ + /** \brief generic libiscsi authentication information struct + * + * Struct holding authentication information for discovery and login. +@@ -248,6 +278,32 @@ PUBLIC int libiscsi_node_login(struct libiscsi_context *context, + PUBLIC int libiscsi_node_logout(struct libiscsi_context *context, + const struct libiscsi_node *node); + ++/** \brief Get an array of iSCSI sessions. ++ * ++ * Get the array containing iSCSI sessions' information. ++ * ++ * \param context libiscsi context to operate on. ++ * \param infos Array of iSCSI sessions' information. ++ * Release with free(). ++ * \param nr_sessions The number of elements in \e infos. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_get_session_infos(struct libiscsi_context *context, ++ struct libiscsi_session_info **infos, int *nr_sessions); ++ ++/** \brief Get session information by session ID. ++ * ++ * \param context libiscsi context to operate on. ++ * \param info iSCSI session information. ++ * \param session Session name. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h) ++ */ ++PUBLIC int libiscsi_get_session_info_by_id(struct libiscsi_context *context, ++ struct libiscsi_session_info *info, ++ const char *session); ++ + /** \brief Set an iSCSI parameter for the given node + * + * Set the given nodes iSCSI parameter named by \e parameter to value \e value. +diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c +index fdc26c7bd9ba..80b7b0210fd1 100644 +--- a/usr/iscsi_sysfs.c ++++ b/usr/iscsi_sysfs.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2006 Mike Christie + * Copyright (C) 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2015 Peter Hatina + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published +@@ -1146,6 +1147,11 @@ free_info: + return rc; + } + ++const char *iscsi_sysfs_get_session_path(void) ++{ ++ return ISCSI_SESSION_DIR; ++} ++ + int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no, + int *nr_found, + iscsi_sysfs_iface_op_fn *fn) +diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h +index cdcefa65f683..12ad87f96c8c 100644 +--- a/usr/iscsi_sysfs.h ++++ b/usr/iscsi_sysfs.h +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2006 Mike Christie + * Copyright (C) 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2015 Peter Hatina + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published +@@ -47,6 +48,7 @@ typedef int (iscsi_sysfs_flashnode_op_fn)(void *, struct flashnode_rec *, + uint32_t, uint32_t); + typedef int (iscsi_sysfs_iface_op_fn)(void *, struct iface_rec *); + ++extern const char *iscsi_sysfs_get_session_path(void); + extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no, + int *nr_found, + iscsi_sysfs_iface_op_fn *fn); +-- +2.14.4 + diff --git a/SOURCES/0020-use-Red-Hat-version-string-to-match-RPM-package-vers.patch b/SOURCES/0020-use-Red-Hat-version-string-to-match-RPM-package-vers.patch new file mode 100644 index 0000000..44278a3 --- /dev/null +++ b/SOURCES/0020-use-Red-Hat-version-string-to-match-RPM-package-vers.patch @@ -0,0 +1,25 @@ +From 92aac85cf423d1c566d324255a86de0116d33015 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 21 Jan 2013 15:43:36 -0800 +Subject: [PATCH 20/32] use Red Hat version string to match RPM package version + +--- + usr/version.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/usr/version.h b/usr/version.h +index 4dfef4ccfb77..1334d47c6bb3 100644 +--- a/usr/version.h ++++ b/usr/version.h +@@ -6,7 +6,7 @@ + * This may not be the same value as the kernel versions because + * some other maintainer could merge a patch without going through us + */ +-#define ISCSI_VERSION_STR "2.0-876" ++#define ISCSI_VERSION_STR "6.2.0.876-5" + #define ISCSI_VERSION_FILE "/sys/module/scsi_transport_iscsi/version" + + #endif +-- +2.14.4 + diff --git a/SOURCES/0021-libiscsi-fix-discovery-request-timeout-regression.patch b/SOURCES/0021-libiscsi-fix-discovery-request-timeout-regression.patch new file mode 100644 index 0000000..9be3ff1 --- /dev/null +++ b/SOURCES/0021-libiscsi-fix-discovery-request-timeout-regression.patch @@ -0,0 +1,32 @@ +From 1aa35262d566d829d711bc746f944dee5c2d9e7a Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 28 Feb 2017 09:00:41 -0800 +Subject: [PATCH 21/32] libiscsi: fix discovery request timeout regression + +--- + libiscsi/libiscsi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index 755c18ca8e3b..bb17dfcafded 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -136,6 +136,7 @@ int libiscsi_discover_sendtargets(struct libiscsi_context *context, + + /* Fill the drec struct with all needed info */ + memset(&drec, 0, sizeof drec); ++ drec.iscsid_req_tmo = -1; + idbm_sendtargets_defaults(&drec.u.sendtargets); + drec.type = DISCOVERY_TYPE_SENDTARGETS; + strlcpy(drec.address, address, sizeof(drec.address)); +@@ -228,6 +229,7 @@ int libiscsi_discover_firmware(struct libiscsi_context *context, + CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets)); + + memset(&drec, 0, sizeof(drec)); ++ drec.iscsid_req_tmo = -1; + drec.type = DISCOVERY_TYPE_FW; + rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list); + if (rc) { +-- +2.14.4 + diff --git a/SOURCES/0022-libiscsi-format-security-build-errors.patch b/SOURCES/0022-libiscsi-format-security-build-errors.patch new file mode 100644 index 0000000..87dd812 --- /dev/null +++ b/SOURCES/0022-libiscsi-format-security-build-errors.patch @@ -0,0 +1,35 @@ +From 1b2b6b683bd7ca3a7030889daf8c326dda797319 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 28 Feb 2017 10:06:42 -0800 +Subject: [PATCH 22/32] libiscsi format-security build errors + +--- + libiscsi/libiscsi.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index bb17dfcafded..7003388e3346 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -177,7 +177,8 @@ int libiscsi_discover_sendtargets(struct libiscsi_context *context, + *found_nodes = calloc(found, sizeof **found_nodes); + if (*found_nodes == NULL) { + snprintf(context->error_str, +- sizeof(context->error_str), strerror(ENOMEM)); ++ sizeof(context->error_str), ++ "%s", strerror(ENOMEM)); + rc = ENOMEM; + goto leave; + } +@@ -634,7 +635,7 @@ static int get_parameter_helper(void *data, node_rec_t *rec) + info = idbm_recinfo_alloc(MAX_KEYS); + if (!info) { + snprintf(context->error_str, sizeof(context->error_str), +- strerror(ENOMEM)); ++ "%s", strerror(ENOMEM)); + return ENOMEM; + } + +-- +2.14.4 + diff --git a/SOURCES/0023-libiscsi-fix-build-to-use-libopeniscsiusr.patch b/SOURCES/0023-libiscsi-fix-build-to-use-libopeniscsiusr.patch new file mode 100644 index 0000000..92667f2 --- /dev/null +++ b/SOURCES/0023-libiscsi-fix-build-to-use-libopeniscsiusr.patch @@ -0,0 +1,36 @@ +From b0d26441cebf6f1d78a2b4523ee9c348578b3d91 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Thu, 24 May 2018 15:17:05 -0700 +Subject: [PATCH 23/32] libiscsi fix build to use libopeniscsiusr + +--- + libiscsi/Makefile | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libiscsi/Makefile b/libiscsi/Makefile +index 317a7ec4db30..1196bb5c0cf4 100644 +--- a/libiscsi/Makefile ++++ b/libiscsi/Makefile +@@ -4,7 +4,9 @@ OSNAME=$(shell uname -s) + OPTFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wstrict-prototypes + CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \ +- -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden ++ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden \ ++ -I../libopeniscsiusr ++LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr + LIB = libiscsi.so.0 + TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware + TESTS += tests/test_login tests/test_logout tests/test_params +@@ -19,7 +21,7 @@ FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sys + # sources shared with the userspace utils, note we build these separately + # to get PIC versions. + COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS)) +-USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o) ++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) local_strings.o) + FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS)) + + # Flags for the tests +-- +2.14.4 + diff --git a/SOURCES/0024-dont-install-scripts.patch b/SOURCES/0024-dont-install-scripts.patch new file mode 100644 index 0000000..c4fc227 --- /dev/null +++ b/SOURCES/0024-dont-install-scripts.patch @@ -0,0 +1,25 @@ +From 09485b397990aca06d5e98a855bab2444c9ec572 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 25 May 2018 09:39:07 -0700 +Subject: [PATCH 24/32] dont install scripts + +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 80afe86d6558..a35082daa9f9 100644 +--- a/Makefile ++++ b/Makefile +@@ -99,7 +99,7 @@ install_udev_rules: + $(INSTALL) -d $(DESTDIR)$(rulesdir) + $(INSTALL) -m 644 $(RULESFILES) $(DESTDIR)/$(rulesdir) + +-install_programs: $(PROGRAMS) $(SCRIPTS) ++install_programs: $(PROGRAMS) # $(SCRIPTS) + $(INSTALL) -d $(DESTDIR)$(sbindir) + $(INSTALL) -m 755 $^ $(DESTDIR)$(sbindir) + +-- +2.14.4 + diff --git a/SOURCES/0028-use-var-lib-iscsi-in-libopeniscsiusr.patch b/SOURCES/0028-use-var-lib-iscsi-in-libopeniscsiusr.patch new file mode 100644 index 0000000..fb1917d --- /dev/null +++ b/SOURCES/0028-use-var-lib-iscsi-in-libopeniscsiusr.patch @@ -0,0 +1,109 @@ +From 089cd6910d9f0d1e459e1d8d00b754843437526d Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Wed, 30 May 2018 16:08:30 -0700 +Subject: [PATCH 28/28] use /var/lib/iscsi in libopeniscsiusr + +--- + libopeniscsiusr/idbm.h | 3 ++- + libopeniscsiusr/iface.c | 2 +- + libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h | 8 ++++---- + libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h | 2 +- + libopeniscsiusr/node.h | 2 +- + 5 files changed, 9 insertions(+), 8 deletions(-) + +diff --git a/libopeniscsiusr/idbm.h b/libopeniscsiusr/idbm.h +index 3fd0864a797d..c84d332ff949 100644 +--- a/libopeniscsiusr/idbm.h ++++ b/libopeniscsiusr/idbm.h +@@ -31,7 +31,8 @@ + #include "libopeniscsiusr/libopeniscsiusr_common.h" + + #define ISCSI_CONFIG_ROOT "/etc/iscsi/" +-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" ++#define ISCSI_VAR_LIB "/var/lib/iscsi/" ++#define IFACE_CONFIG_DIR ISCSI_VAR_LIB"ifaces" + #define AUTH_STR_MAX_LEN 256 + #define BOOT_NAME_MAXLEN 256 + #define IDBM_DUMP_SIZE 8192 +diff --git a/libopeniscsiusr/iface.c b/libopeniscsiusr/iface.c +index e2355bc0fff0..cd9dd7326ae6 100644 +--- a/libopeniscsiusr/iface.c ++++ b/libopeniscsiusr/iface.c +@@ -383,7 +383,7 @@ int iscsi_default_iface_setup(struct iscsi_context *ctx) + + _good(_iscsi_hids_get(ctx, &hids, &hid_count), rc, out); + for (i = 0; i < hid_count; ++i) { +- /* Create /etc/iscsi/ifaces/ file if not found ++ /* Create /var/lib/iscsi/ifaces/ file if not found + */ + _good(_iscsi_ifaces_get_from_sysfs(ctx, hids[i], &ifaces, &iface_count), + rc, out); +diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h +index 439590249212..81582da9e1e6 100644 +--- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h ++++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h +@@ -339,7 +339,7 @@ __DLL_EXPORT void iscsi_session_free(struct iscsi_session *se); + * * bnx2i + * + * It will also create configuration files for iSCSI hardware offload cards in +- * /etc/iscsi/ifaces/. ++ * /var/lib/iscsi/ifaces/. + * + * @ctx: + * Pointer of 'struct iscsi_context'. +@@ -369,7 +369,7 @@ __DLL_EXPORT int iscsi_default_iface_setup(struct iscsi_context *ctx); + * Retrieves all iSCSI interfaces. For the properties of 'struct iscsi_iface', + * please refer to the functions defined in 'libopeniscsiusr_iface.h' file. + * The returned results contains default iSCSI interfaces(iser and iscsi_tcp) +- * and iSCSI interfaces configured in "/etc/iscsi/ifaces/". ++ * and iSCSI interfaces configured in "/var/lib/iscsi/ifaces/". + * Illegal configuration file will be skipped and warned. + * To generate iSCSI interface configuration when new card installed, please + * use iscsi_default_iface_setup(). +@@ -427,7 +427,7 @@ __DLL_EXPORT void iscsi_ifaces_free(struct iscsi_iface **ifaces, + * iscsi_iface_get() - Retrieve specified iSCSI interface. + * + * Retrieves specified iSCSI interfaces by reading configuration from +- * "/etc/iscsi/iface/". ++ * "/var/lib/iscsi/iface/". + * To generate iSCSI interface configuration when new card installed, please + * use iscsi_default_iface_setup(). + * Illegal configuration file will be treated as error LIBISCSI_ERR_IDBM. +@@ -438,7 +438,7 @@ __DLL_EXPORT void iscsi_ifaces_free(struct iscsi_iface **ifaces, + * If this pointer is NULL, your program will be terminated by assert. + * @iface_name: + * String. Name of iSCSI interface. Also the file name of configuration +- * file "/etc/iscsi/iface/". ++ * file "/var/lib/iscsi/iface/". + * If this pointer is NULL or empty string, your program will be terminated + * by assert. + * @iface: +diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h +index a1a255246d20..95b01602fb37 100644 +--- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h ++++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h +@@ -182,7 +182,7 @@ __DLL_EXPORT const char *iscsi_iface_name_get(struct iscsi_iface *iface); + * + * Dump all configurations of specified iSCSI interface. Will skip empty + * configuration so that output string could be saved directly to +- * /etc/iscsi/ifaces/ file. ++ * /var/lib/iscsi/ifaces/ file. + * + * @iface: + * Pointer of 'struct iscsi_iface'. +diff --git a/libopeniscsiusr/node.h b/libopeniscsiusr/node.h +index 39e07b3befae..9eba7fa6077c 100644 +--- a/libopeniscsiusr/node.h ++++ b/libopeniscsiusr/node.h +@@ -44,7 +44,7 @@ struct iscsi_node { + char portal[NI_MAXHOST * 2]; + }; + +-#define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" ++#define NODE_CONFIG_DIR ISCSI_VAR_LIB"nodes" + + /* Might be public in the future */ + __DLL_LOCAL void iscsi_node_free(struct iscsi_node *node); +-- +2.14.4 + diff --git a/SOURCES/04-iscsi b/SOURCES/04-iscsi new file mode 100755 index 0000000..864ade7 --- /dev/null +++ b/SOURCES/04-iscsi @@ -0,0 +1,7 @@ +#!/bin/sh + +case "$2" in + up|vpn-up) + /bin/systemctl --no-block reload iscsi.service || : + ;; +esac diff --git a/SOURCES/iscsi-tmpfiles.conf b/SOURCES/iscsi-tmpfiles.conf new file mode 100644 index 0000000..eab4fb2 --- /dev/null +++ b/SOURCES/iscsi-tmpfiles.conf @@ -0,0 +1,2 @@ +d /run/lock/iscsi 0700 root root - +f /run/lock/iscsi/lock 0600 root root - diff --git a/SOURCES/open-iscsi-2.0.876-66-Allow-reading-sysfs-port-to-fail-gracefully.patch b/SOURCES/open-iscsi-2.0.876-66-Allow-reading-sysfs-port-to-fail-gracefully.patch new file mode 100644 index 0000000..454ce6d --- /dev/null +++ b/SOURCES/open-iscsi-2.0.876-66-Allow-reading-sysfs-port-to-fail-gracefully.patch @@ -0,0 +1,27 @@ +commit d8298fc54eb69d3989878be46e9c7d6ec2055650 +Author: Lee Duncan +Date: Mon Sep 24 16:22:18 2018 -0700 + + Allow reading sysfs "port" to fail gracefully. + + Do not consider it a fatal error if reading sysfs value + for "port" fails, since we allow failure for "address". +--- + libopeniscsiusr/session.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libopeniscsiusr/session.c b/libopeniscsiusr/session.c +index a8339395fc03..f8c89c323afb 100644 +--- a/libopeniscsiusr/session.c ++++ b/libopeniscsiusr/session.c +@@ -205,8 +205,8 @@ int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid, + _sysfs_prop_get_str(ctx, sysfs_con_dir_path, "address", (*se)->address, + sizeof((*se)->address) / sizeof(char), ""); + +- _good(_sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "port", +- &((*se)->port), -1, false), rc, out); ++ _sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "port", ++ &((*se)->port), -1, true); + + if ((strcmp((*se)->address, "") == 0) && + (strcmp((*se)->persistent_address, "") != 0)) diff --git a/SOURCES/open-iscsi-2.0.876-67-Fix-incorrect-sysfs-logic-for-port-and-ip-address.patch b/SOURCES/open-iscsi-2.0.876-67-Fix-incorrect-sysfs-logic-for-port-and-ip-address.patch new file mode 100644 index 0000000..1efe3ab --- /dev/null +++ b/SOURCES/open-iscsi-2.0.876-67-Fix-incorrect-sysfs-logic-for-port-and-ip-address.patch @@ -0,0 +1,48 @@ +commit 7df5edbb427c79337bdd651c2bcdda8eb05f077b +Author: Lee Duncan +Date: Mon Sep 24 16:30:34 2018 -0700 + + Fix incorrect sysfs logic for port and ip address. + + If "port" is available and "persistent_port" is not, then + correctly use the one that is present for both values. + Likewise for "address" and "persistent_address". +--- + libopeniscsiusr/session.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/libopeniscsiusr/session.c b/libopeniscsiusr/session.c +index f8c89c323afb..98601dcf807e 100644 +--- a/libopeniscsiusr/session.c ++++ b/libopeniscsiusr/session.c +@@ -208,22 +208,20 @@ int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid, + _sysfs_prop_get_i32(ctx, sysfs_con_dir_path, "port", + &((*se)->port), -1, true); + +- if ((strcmp((*se)->address, "") == 0) && +- (strcmp((*se)->persistent_address, "") != 0)) +- _strncpy((*se)->persistent_address, (*se)->address, +- sizeof((*se)->persistent_address) / sizeof(char)); +- + if ((strcmp((*se)->address, "") != 0) && + (strcmp((*se)->persistent_address, "") == 0)) ++ _strncpy((*se)->persistent_address, (*se)->address, ++ sizeof((*se)->persistent_address) / sizeof(char)); ++ else if ((strcmp((*se)->address, "") == 0) && ++ (strcmp((*se)->persistent_address, "") != 0)) + _strncpy((*se)->address, (*se)->persistent_address, + sizeof((*se)->address) / sizeof(char)); + +- if (((*se)->persistent_port != -1) && +- ((*se)->port == -1)) ++ if (((*se)->persistent_port == -1) && ++ ((*se)->port != -1)) + (*se)->persistent_port = (*se)->port; +- +- if (((*se)->persistent_port != -1) && +- ((*se)->port == -1)) ++ else if (((*se)->persistent_port != -1) && ++ ((*se)->port == -1)) + (*se)->port = (*se)->persistent_port; + + _good(_iscsi_host_id_of_session(ctx, sid, &host_id), rc, out); diff --git a/SOURCES/open-iscsi-2.0.876-68-Fix-reading-of-sysfs-signed-integers-when-negative.patch b/SOURCES/open-iscsi-2.0.876-68-Fix-reading-of-sysfs-signed-integers-when-negative.patch new file mode 100644 index 0000000..23d7ef8 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.876-68-Fix-reading-of-sysfs-signed-integers-when-negative.patch @@ -0,0 +1,73 @@ +commit 09d7031cb462889392090e71991a89c522d387bc +Author: Lee Duncan +Date: Mon Sep 24 16:37:19 2018 -0700 + + Fix reading of sysfs signed integers when negative. + + The code for reading all sysfs integer types (of all + sizes) did not work when reading signed integers and + the return value was negative. So when the default was -1 + and the value was not present, the code tried to return -1. + But the logic for checking against "max value" was + incorrect, causing INT_MAX to be returned instead of -1. +--- + libopeniscsiusr/sysfs.c | 32 +++++++++++++++++++++++++++----- + 1 file changed, 27 insertions(+), 5 deletions(-) + +diff --git a/libopeniscsiusr/sysfs.c b/libopeniscsiusr/sysfs.c +index 08f71b317c55..c4f89a31aca0 100644 +--- a/libopeniscsiusr/sysfs.c ++++ b/libopeniscsiusr/sysfs.c +@@ -47,7 +47,7 @@ + + #define _SYS_NULL_STR "(null)" + +-#define _sysfs_prop_get_int_func_gen(func_name, out_type, type_max_value) \ ++#define _sysfs_prop_get_uint_func_gen(func_name, out_type, type_max_value) \ + int func_name(struct iscsi_context *ctx, const char *dir_path, \ + const char *prop_name, out_type *val, \ + out_type default_value, bool ignore_error) \ +@@ -63,6 +63,28 @@ + return rc; \ + } + ++#define _sysfs_prop_get_int_func_gen(func_name, out_type, type_min_value, type_max_value) \ ++ int func_name(struct iscsi_context *ctx, const char *dir_path, \ ++ const char *prop_name, out_type *val, \ ++ out_type default_value, bool ignore_error) \ ++ { \ ++ long long int tmp_val = 0; \ ++ int rc = LIBISCSI_OK; \ ++ long long int dv = default_value; \ ++ rc = iscsi_sysfs_prop_get_ll(ctx, dir_path, prop_name, \ ++ &tmp_val, (long long int) dv, \ ++ ignore_error); \ ++ if (rc == LIBISCSI_OK) { \ ++ if (tmp_val > type_max_value) \ ++ *val = type_max_value; \ ++ else if (tmp_val < type_min_value) \ ++ *val = type_min_value; \ ++ else \ ++ *val = tmp_val; \ ++ } \ ++ return rc; \ ++ } ++ + + enum _sysfs_dev_class { + _SYSFS_DEV_CLASS_ISCSI_SESSION, +@@ -82,10 +104,10 @@ static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx, + static int sysfs_get_dev_path(struct iscsi_context *ctx, const char *path, + enum _sysfs_dev_class class, char **dev_path); + +-_sysfs_prop_get_int_func_gen(_sysfs_prop_get_u8, uint8_t, UINT8_MAX); +-_sysfs_prop_get_int_func_gen(_sysfs_prop_get_u16, uint16_t, UINT16_MAX); +-_sysfs_prop_get_int_func_gen(_sysfs_prop_get_i32, int32_t, INT32_MAX); +-_sysfs_prop_get_int_func_gen(_sysfs_prop_get_u32, uint32_t, UINT32_MAX); ++_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u8, uint8_t, UINT8_MAX); ++_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u16, uint16_t, UINT16_MAX); ++_sysfs_prop_get_int_func_gen(_sysfs_prop_get_i32, int32_t, INT32_MIN, INT32_MAX); ++_sysfs_prop_get_uint_func_gen(_sysfs_prop_get_u32, uint32_t, UINT32_MAX); + + static int sysfs_read_file(const char *path, uint8_t *buff, size_t buff_size) + { diff --git a/SOURCES/open-iscsi-2.0.876-69-Create-a-new-error-for-target-not-connected.patch b/SOURCES/open-iscsi-2.0.876-69-Create-a-new-error-for-target-not-connected.patch new file mode 100644 index 0000000..c0cb989 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.876-69-Create-a-new-error-for-target-not-connected.patch @@ -0,0 +1,69 @@ +commit 7d121d12ad6ba7783308c25ffd338a9fa0cc402b +Author: Lee Duncan +Date: Tue Sep 25 09:48:53 2018 -0700 + + Create a new error for "target not connected". + + The session_logout_qtask() function now recognizes + a new state of "target likely not connected" if + syncing up, in connection wait state, and re-opening + the connection. +--- + include/iscsi_err.h | 2 ++ + usr/initiator.c | 16 +++++++++++++++- + usr/iscsi_err.c | 1 + + 3 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/include/iscsi_err.h b/include/iscsi_err.h +index 506bd8c9bd27..ed000dd00baf 100644 +--- a/include/iscsi_err.h ++++ b/include/iscsi_err.h +@@ -68,6 +68,8 @@ enum { + ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE = 30, + /* child process terminated */ + ISCSI_ERR_CHILD_TERMINATED = 31, ++ /* session likely not connected */ ++ ISCSI_ERR_SESSION_NOT_CONNECTED = 32, + + /* Always last. Indicates end of error code space */ + ISCSI_MAX_ERR_VAL, +diff --git a/usr/initiator.c b/usr/initiator.c +index a86d1e6dee90..935056a3abde 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -2056,8 +2056,22 @@ int session_logout_task(int sid, queue_task_t *qtask) + return ISCSI_ERR_SESS_NOT_FOUND; + } + conn = &session->conn[0]; ++ + /* +- * If syncing up or if this is the initial login and mgmt_ipc ++ * If syncing up, in XPT_WAIT, and REOPENing, then return ++ * an informative error, since the target for this session ++ * is likely not connected ++ */ ++ if (session->notify_qtask && ++ (conn->state == ISCSI_CONN_STATE_XPT_WAIT) && ++ (session->r_stage == R_STAGE_SESSION_REOPEN)) { ++ log_warning("session cannot be terminted because it's trying to reconnect: try again later"); ++ return ISCSI_ERR_SESSION_NOT_CONNECTED; ++ } ++ ++ /* ++ * If syncing up and not reconnecting, ++ * or if this is the initial login and mgmt_ipc + * has not been notified of that result fail the logout request + */ + if (session->notify_qtask || +diff --git a/usr/iscsi_err.c b/usr/iscsi_err.c +index 1ba9e648d7c1..23c61fc3574e 100644 +--- a/usr/iscsi_err.c ++++ b/usr/iscsi_err.c +@@ -54,6 +54,7 @@ static char *iscsi_err_msgs[] = { + /* 29 */ "operation failed but retry may succeed", + /* 30 */ "unknown discovery type", + /* 31 */ "child process terminated", ++ /* 32 */ "target likely not connected", + }; + + char *iscsi_err_to_str(int err) diff --git a/SOURCES/open-iscsi-2.0.876-70-Fix-bug-in-error-message-when-reading-sysfs-numbers.patch b/SOURCES/open-iscsi-2.0.876-70-Fix-bug-in-error-message-when-reading-sysfs-numbers.patch new file mode 100644 index 0000000..3f5c001 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.876-70-Fix-bug-in-error-message-when-reading-sysfs-numbers.patch @@ -0,0 +1,26 @@ +commit 8bf04a094e572c56d4f8bd30ff064c84c75a0247 +Author: Lee Duncan +Date: Tue Sep 25 09:53:55 2018 -0700 + + Fix bug in error message when reading sysfs numbers. + + The message printed when ENOENT was returned for + a number-type sysfs value was missing the attribute + name parameter. +--- + libopeniscsiusr/sysfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libopeniscsiusr/sysfs.c b/libopeniscsiusr/sysfs.c +index c4f89a31aca0..5e6532e7746f 100644 +--- a/libopeniscsiusr/sysfs.c ++++ b/libopeniscsiusr/sysfs.c +@@ -237,7 +237,7 @@ static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx, + "Failed to read '%s': " + "File '%s' does not exists, using ", + "default value %lld", +- file_path, default_value); ++ prop_name, file_path, default_value); + *val = default_value; + goto out; + } diff --git a/SOURCES/open-iscsi-2.0.876-71-Handle-ENOTCONN-error-separately-when-reading-sysfs-values.patch b/SOURCES/open-iscsi-2.0.876-71-Handle-ENOTCONN-error-separately-when-reading-sysfs-values.patch new file mode 100644 index 0000000..916cccc --- /dev/null +++ b/SOURCES/open-iscsi-2.0.876-71-Handle-ENOTCONN-error-separately-when-reading-sysfs-values.patch @@ -0,0 +1,62 @@ +commit ae0b2ceb620e2bf527c06d21c110791d1e0e8bf4 +Author: Lee Duncan +Date: Tue Sep 25 09:57:46 2018 -0700 + + Handle ENOTCONN error separately when reading sysfs values. + + This error happens when the daemon is attempting to + reconnect a session when starting up, so should not + be considered an internal error. +--- + libopeniscsiusr/sysfs.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/libopeniscsiusr/sysfs.c b/libopeniscsiusr/sysfs.c +index 5e6532e7746f..2c3f077bf3fa 100644 +--- a/libopeniscsiusr/sysfs.c ++++ b/libopeniscsiusr/sysfs.c +@@ -184,6 +184,21 @@ int _sysfs_prop_get_str(struct iscsi_context *ctx, const char *dir_path, + _error(ctx, "Failed to read '%s': " + "permission deny when reading '%s'", prop_name, + file_path); ++ } else if (errno_save == ENOTCONN) { ++ if (default_value == NULL) { ++ rc = LIBISCSI_ERR_SYSFS_LOOKUP; ++ _error(ctx, "Failed to read '%s': " ++ "error when reading '%s': " ++ "Target unavailable", ++ prop_name, file_path); ++ } else { ++ _info(ctx, "Failed to read '%s': " ++ "error when reading '%s': " ++ "Target unavailable, using default value '%s'", ++ prop_name, file_path, default_value); ++ memcpy(buff, (void *) default_value, ++ strlen(default_value) + 1); ++ } + } else { + rc = LIBISCSI_ERR_BUG; + _error(ctx, "Failed to read '%s': " +@@ -246,6 +261,22 @@ static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx, + _error(ctx, "Permission deny when reading '%s'", + file_path); + goto out; ++ } else if (errno_save == ENOTCONN) { ++ if (!ignore_error) { ++ rc = LIBISCSI_ERR_SYSFS_LOOKUP; ++ _error(ctx, "Failed to read '%s': " ++ "error when reading '%s': " ++ "Target unavailable", ++ prop_name, file_path); ++ goto out; ++ } else { ++ _info(ctx, "Failed to read '%s': " ++ "error when reading '%s': " ++ "Target unavailable, using default value %lld", ++ prop_name, file_path, default_value); ++ *val = default_value; ++ goto out; ++ } + } else { + rc = LIBISCSI_ERR_BUG; + _error(ctx, "Error when reading '%s': %d", file_path, diff --git a/SOURCES/open-iscsi-2.0.876-93-Restore-space-in-node-mode-level-0-output.patch b/SOURCES/open-iscsi-2.0.876-93-Restore-space-in-node-mode-level-0-output.patch new file mode 100644 index 0000000..bf8ecde --- /dev/null +++ b/SOURCES/open-iscsi-2.0.876-93-Restore-space-in-node-mode-level-0-output.patch @@ -0,0 +1,26 @@ +commit baa0cb45cfcf10a81283c191b0b236cd1a2f66ee +Author: Lee Duncan +Date: Fri Oct 12 09:57:20 2018 -0700 + + Restore space in node-mode level 0 output + + As part of the libopeniscsiusr update, the output + of "iscsiadm -m node" dropped a space that needs to + be between the portal and the target, for proper + parsing. + + Fixes: 87ea50a1c3a97 + +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index e3ba03c838f3..25c6cdc0ff12 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -683,7 +683,7 @@ static int login_portals(struct node_rec *pattern_rec) + + static void print_node_flat(struct iscsi_node *node) + { +- printf("%s,%" PRIu16 "%s\n", ++ printf("%s,%" PRIu16 " %s\n", + iscsi_node_portal_get(node), + iscsi_node_tpgt_get(node), + iscsi_node_target_name_get(node)); diff --git a/SPECS/iscsi-initiator-utils.spec b/SPECS/iscsi-initiator-utils.spec new file mode 100644 index 0000000..5563910 --- /dev/null +++ b/SPECS/iscsi-initiator-utils.spec @@ -0,0 +1,589 @@ +%global open_iscsi_version 2.0 +%global open_iscsi_build 876 +%global commit0 f3c8e90fc0894c088950a15ee6618b427f9e2457 +%global shortcommit0 %(c=%{commit0}; echo ${c:0:7}) + +%if 0%{?rhel} > 7 +# Disable python2 build by default +%bcond_with python2 +%else +%bcond_without python2 +%endif + +Summary: iSCSI daemon and utility programs +Name: iscsi-initiator-utils +Version: 6.%{open_iscsi_version}.%{open_iscsi_build} +Release: 7.git%{shortcommit0}%{?dist} +Group: System Environment/Daemons +License: GPLv2+ +URL: http://www.open-iscsi.org +Source0: https://github.com/open-iscsi/open-iscsi/archive/%{commit0}.tar.gz#/open-iscsi-%{shortcommit0}.tar.gz +Source4: 04-iscsi +Source5: iscsi-tmpfiles.conf + +Patch0001: 0001-idmb_rec_write-check-for-tpgt-first.patch +Patch0002: 0002-idbm_rec_write-seperate-old-and-new-style-writes.patch +Patch0003: 0003-idbw_rec_write-pick-tpgt-from-existing-record.patch +Patch0004: 0004-update-systemd-service-files-add-iscsi.service-for-s.patch +Patch0005: 0005-iscsi-boot-related-service-file-updates.patch +Patch0006: 0006-update-initscripts-and-docs.patch +Patch0007: 0007-use-var-for-config.patch +Patch0008: 0008-use-red-hat-for-name.patch +Patch0009: 0009-libiscsi.patch +Patch0010: 0010-remove-the-offload-boot-supported-ifdef.patch +Patch0011: 0011-iscsiuio-systemd-unit-files.patch +Patch0012: 0012-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch +Patch0013: 0013-Revert-iscsiadm-return-error-when-login-fails.patch +Patch0014: 0014-update-handling-of-boot-sessions.patch +Patch0015: 0015-update-iscsi.service-for-boot-session-recovery.patch +Patch0016: 0016-updates-to-iscsi.service.patch +Patch0017: 0017-make-session-shutdown-a-seperate-service.patch.patch +Patch0018: 0018-Add-macros-to-release-GIL-lock.patch +Patch0019: 0019-libiscsi-introduce-sessions-API.patch +Patch0020: 0020-use-Red-Hat-version-string-to-match-RPM-package-vers.patch +Patch0021: 0021-libiscsi-fix-discovery-request-timeout-regression.patch +Patch0022: 0022-libiscsi-format-security-build-errors.patch +Patch0023: 0023-libiscsi-fix-build-to-use-libopeniscsiusr.patch +Patch0024: 0024-dont-install-scripts.patch +Patch0028: 0028-use-var-lib-iscsi-in-libopeniscsiusr.patch +Patch0029: open-iscsi-2.0.876-66-Allow-reading-sysfs-port-to-fail-gracefully.patch +Patch0030: open-iscsi-2.0.876-67-Fix-incorrect-sysfs-logic-for-port-and-ip-address.patch +Patch0031: open-iscsi-2.0.876-68-Fix-reading-of-sysfs-signed-integers-when-negative.patch +Patch0032: open-iscsi-2.0.876-69-Create-a-new-error-for-target-not-connected.patch +Patch0033: open-iscsi-2.0.876-70-Fix-bug-in-error-message-when-reading-sysfs-numbers.patch +Patch0034: open-iscsi-2.0.876-71-Handle-ENOTCONN-error-separately-when-reading-sysfs-values.patch +Patch0035: open-iscsi-2.0.876-93-Restore-space-in-node-mode-level-0-output.patch + +BuildRequires: flex bison doxygen kmod-devel systemd-units +BuildRequires: autoconf automake libtool libmount-devel openssl-devel +BuildRequires: isns-utils-devel +# For dir ownership +Requires: %{name}-iscsiuio >= %{version}-%{release} +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%global _hardened_build 1 +%global __provides_exclude_from ^(%{python2_sitearch}/.*\\.so|%{python3_sitearch}/.*\\.so)$ + +%description +The iscsi package provides the server daemon for the iSCSI protocol, +as well as the utility programs used to manage it. iSCSI is a protocol +for distributed disk access using SCSI commands sent over Internet +Protocol networks. + +# I don't think we're ready to expose these just yet +# For now just add the needed library to the base package + +#%package -n libopeniscsiusr +#Summary: library providing access to Open-iSCSI initiator functionality +#Group: Development/Libraries +#License: BSD + +#%description -n libopeniscsiusr +#The libopeniscsiusr library provides a C API for access to the Open-iSCSI +#initiator. It is used by the Open-iSCSI command line tools. + +#%package -n libopeniscsiusr-devel +#Summary: Development files for libopeniscsiusr +#Group: Development/Libraries +#Requires: libopeniscsiusr = %{version}-%{release} + +#%description -n libopeniscsiusr-devel +#The libopeniscsiusr-devel package contains libraries and header files for +#developing applications that use libopeniscsiusr. + +%package iscsiuio +Summary: Userspace configuration daemon required for some iSCSI hardware +Group: System Environment/Daemons +License: BSD +Requires: %{name} = %{version}-%{release} + +%description iscsiuio +The iscsiuio configuration daemon provides network configuration help +for some iSCSI offload hardware. + +%package devel +Summary: Development files for %{name} +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + +%if %{with python2} +%package -n python2-%{name} +%{?python_provide:%python_provide python2-%{name}} +Summary: Python %{python2_version} bindings to %{name} +Group: Development/Libraries + +BuildRequires: python2-devel +BuildRequires: python2-setuptools + +%description -n python2-%{name} +The %{name}-python2 package contains Python %{python2_version} bindings to the +libiscsi interface for interacting with %{name} +%endif # with python2 + +%package -n python3-%{name} +%{?python_provide:%python_provide python3-%{name}} +Summary: Python %{python3_version} bindings to %{name} +Group: Development/Libraries + +BuildRequires: python3-devel +BuildRequires: python3-setuptools + +%description -n python3-%{name} +The %{name}-python3 package contains Python %{python3_version} bindings to the +libiscsi interface for interacting with %{name} + +%prep +%autosetup -p1 -n open-iscsi-%{commit0} + +# change exec_prefix, there's no easy way to override +%{__sed} -i -e 's|^exec_prefix = /$|exec_prefix = %{_exec_prefix}|' Makefile + +%build + +# configure sub-packages from here +# letting the top level Makefile do it will lose setting from rpm +cd iscsiuio +autoreconf --install +%{configure} +cd .. + +%{__make} OPTFLAGS="%{optflags} %{?__global_ldflags} -DUSE_KMOD -lkmod" +pushd libiscsi +%if %{with python2} +%py2_build +%endif # with python2 +%py3_build +touch -r libiscsi.doxy html/* +popd + + +%install +%{__make} DESTDIR=%{?buildroot} install_programs install_doc install_etc install_libopeniscsiusr +# upstream makefile doesn't get everything the way we like it +#rm $RPM_BUILD_ROOT%{_sbindir}/iscsi_discovery +rm $RPM_BUILD_ROOT%{_mandir}/man8/iscsi_discovery.8 +rm $RPM_BUILD_ROOT%{_mandir}/man8/iscsi_fw_login.8 +%{__install} -pm 755 usr/iscsistart $RPM_BUILD_ROOT%{_sbindir} +%{__install} -pm 644 doc/iscsistart.8 $RPM_BUILD_ROOT%{_mandir}/man8 +%{__install} -pm 644 doc/iscsi-iname.8 $RPM_BUILD_ROOT%{_mandir}/man8 +%{__install} -d $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d +%{__install} -pm 644 iscsiuio/iscsiuiolog $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d + +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/nodes +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/send_targets +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/static +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/isns +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/slp +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/ifaces + +# for %%ghost +%{__install} -d $RPM_BUILD_ROOT/var/lock/iscsi +touch $RPM_BUILD_ROOT/var/lock/iscsi/lock + + +%{__install} -d $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsi.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsi-shutdown.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsid.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsid.socket $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsiuio.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsiuio.socket $RPM_BUILD_ROOT%{_unitdir} + +%{__install} -d $RPM_BUILD_ROOT%{_libexecdir} +%{__install} -pm 755 etc/systemd/iscsi-mark-root-nodes $RPM_BUILD_ROOT%{_libexecdir} + +%{__install} -d $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d +%{__install} -pm 755 %{SOURCE4} $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d + +%{__install} -d $RPM_BUILD_ROOT%{_tmpfilesdir} +%{__install} -pm 644 %{SOURCE5} $RPM_BUILD_ROOT%{_tmpfilesdir}/iscsi.conf + +%{__install} -d $RPM_BUILD_ROOT%{_libdir} +%{__install} -pm 755 libiscsi/libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir} +%{__ln_s} libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir}/libiscsi.so +%{__install} -d $RPM_BUILD_ROOT%{_includedir} +%{__install} -pm 644 libiscsi/libiscsi.h $RPM_BUILD_ROOT%{_includedir} + +%if %{with python2} +%{__install} -d $RPM_BUILD_ROOT%{python2_sitearch} +%endif # with python2 +%{__install} -d $RPM_BUILD_ROOT%{python3_sitearch} +pushd libiscsi +%if %{with python2} +%py2_install +%endif # with python2 +%py3_install +popd + + +%post +/sbin/ldconfig + +%systemd_post iscsi.service iscsi-shutdown.service iscsid.service iscsid.socket + +if [ $1 -eq 1 ]; then + if [ ! -f %{_sysconfdir}/iscsi/initiatorname.iscsi ]; then + echo "InitiatorName=`/usr/sbin/iscsi-iname`" > %{_sysconfdir}/iscsi/initiatorname.iscsi + fi + # enable socket activation and persistant session startup by default + /bin/systemctl enable iscsi.service >/dev/null 2>&1 || : + /bin/systemctl enable iscsid.socket >/dev/null 2>&1 || : +fi + +%post iscsiuio +%systemd_post iscsiuio.service iscsiuio.socket + +if [ $1 -eq 1 ]; then + /bin/systemctl enable iscsiuio.socket >/dev/null 2>&1 || : +fi + +%preun +%systemd_preun iscsi.service iscsi-shutdown.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket + +%preun iscsiuio +%systemd_preun iscsiuio.service iscsiuio.socket + +%postun +/sbin/ldconfig +%systemd_postun + +%postun iscsiuio +%systemd_postun + +%triggerun -- iscsi-initiator-utils < 6.2.0.873-25 +# prior to 6.2.0.873-24 iscsi.service was missing a Wants=remote-fs-pre.target +# this forces remote-fs-pre.target active if needed for a clean shutdown/reboot +# after upgrading this package +if [ $1 -gt 0 ]; then + /usr/bin/systemctl -q is-active iscsi.service + if [ $? -eq 0 ]; then + /usr/bin/systemctl -q is-active remote-fs-pre.target + if [ $? -ne 0 ]; then + SRC=`/usr/bin/systemctl show --property FragmentPath remote-fs-pre.target | cut -d= -f2` + DST=/run/systemd/system/remote-fs-pre.target + if [ $SRC != $DST ]; then + cp $SRC $DST + fi + sed -i 's/RefuseManualStart=yes/RefuseManualStart=no/' $DST + /usr/bin/systemctl daemon-reload >/dev/null 2>&1 || : + /usr/bin/systemctl start remote-fs-pre.target >/dev/null 2>&1 || : + fi + fi +fi +# added in 6.2.0.873-25 +if [ $1 -gt 0 ]; then + systemctl start iscsi-shutdown.service >/dev/null 2>&1 || : +fi + + +%files +%doc README +%dir %{_sharedstatedir}/iscsi +%dir %{_sharedstatedir}/iscsi/nodes +%dir %{_sharedstatedir}/iscsi/isns +%dir %{_sharedstatedir}/iscsi/static +%dir %{_sharedstatedir}/iscsi/slp +%dir %{_sharedstatedir}/iscsi/ifaces +%dir %{_sharedstatedir}/iscsi/send_targets +%ghost %{_var}/lock/iscsi +%ghost %{_var}/lock/iscsi/lock +%{_unitdir}/iscsi.service +%{_unitdir}/iscsi-shutdown.service +%{_unitdir}/iscsid.service +%{_unitdir}/iscsid.socket +%{_libexecdir}/iscsi-mark-root-nodes +%{_sysconfdir}/NetworkManager/dispatcher.d/04-iscsi +%{_tmpfilesdir}/iscsi.conf +%dir %{_sysconfdir}/iscsi +%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/iscsi/iscsid.conf +%{_sbindir}/iscsi-iname +%{_sbindir}/iscsiadm +%{_sbindir}/iscsid +%{_sbindir}/iscsistart +%{_libdir}/libiscsi.so.0 +%{_mandir}/man8/iscsi-iname.8.gz +%{_mandir}/man8/iscsiadm.8.gz +%{_mandir}/man8/iscsid.8.gz +%{_mandir}/man8/iscsistart.8.gz +# until we decide to setup libopeniscsiusr as a subpkg for real +%{_libdir}/libopeniscsiusr.so.* +%exclude %{_libdir}/libopeniscsiusr.so +%exclude %{_includedir}/libopeniscsiusr.h +%exclude %{_includedir}/libopeniscsiusr_common.h +%exclude %{_includedir}/libopeniscsiusr_iface.h +%exclude %{_includedir}/libopeniscsiusr_session.h +%exclude %{_libdir}/pkgconfig/libopeniscsiusr.pc + +# %files -n libopeniscsiusr +# %{_libdir}/libopeniscsiusr.so.* +# +# %files -n libopeniscsiusr-devel +# %{_libdir}/libopeniscsiusr.so +# %{_includedir}/libopeniscsiusr.h +# %{_includedir}/libopeniscsiusr_common.h +# %{_includedir}/libopeniscsiusr_iface.h +# %{_includedir}/libopeniscsiusr_session.h +# %{_libdir}/pkgconfig/libopeniscsiusr.pc + +%files iscsiuio +%{_sbindir}/iscsiuio +%{_unitdir}/iscsiuio.service +%{_unitdir}/iscsiuio.socket +%config(noreplace) %{_sysconfdir}/logrotate.d/iscsiuiolog +%{_mandir}/man8/iscsiuio.8.gz + +%files devel +%doc libiscsi/html +%{_libdir}/libiscsi.so +%{_includedir}/libiscsi.h + +%if %{with python2} +%files -n python2-%{name} +%{python2_sitearch}/* +%endif # with python2 + +%files -n python3-%{name} +%{python3_sitearch}/* + +%changelog +* Thu Feb 21 2019 Chris Leech - 6.2.0.876-7.gitf3c8e90 +- 1647826: fix sysfs and output format regressions in libopeniscsi code + +* Thu Jan 03 2019 Chris Leech - 6.2.0.876-6.gitf3c8e90 +- 1650402: fix missing space in node display output + +* Tue Jul 10 2018 Chris Leech - 6.2.0.876-5.gitf3c8e90 +- iscsiuio: add mutex to protect netlink buffer for pass-through xmit +- iscsid: get gateway information from sysfs when recovering sessions +- enabled MaxOustandingR2T negotiation during login + +* Mon Jun 25 2018 Adam Williamson - 6.2.0.876-4.git4ef9261 +- Rebuilt for Python 3.7, again + +* Mon Jun 25 2018 Adam Williamson - 6.2.0.876-3.git4ef9261 +- Link libiscsi against libopeniscsiusr (bz #1594946) (python 3.6 build) + +* Wed Jun 20 2018 Miro Hrončok - 6.2.0.876-2.git4ef9261 +- Rebuilt for Python 3.7 + +* Tue Jun 19 2018 Chris Leech - 6.2.0.876-1.git4ef9261 +- pull in post 2.0.876 tagged fixes from upstream git +- minimal packaging of libopeniscsiusr (internal use only, no dev package yet) + +* Tue Jun 19 2018 Chris Leech - 6.2.0.876-1.git24580ad +- rebase to upstream 2.0.876 + +* Tue Jun 19 2018 Miro Hrončok - 6.2.0.874-10.git86e8892 +- Rebuilt for Python 3.7 + +* Mon May 28 2018 Charalampos Stratakis - 6.2.0.874-10.git86e8892 +- Conditionalize the python2 subpackage + +* Wed Feb 07 2018 Fedora Release Engineering - 6.2.0.874-9.git86e8892 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Fri Jan 05 2018 Iryna Shcherbina - 6.2.0.874-8.git86e8892 +- Update Python 2 dependency declarations to new packaging standards + (See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3) + +* Sat Aug 19 2017 Zbigniew Jędrzejewski-Szmek - 6.2.0.874-7.git86e8892 +- Python 2 binary package renamed to python2-iscsi-initiator-utils + See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3 + +* Wed Aug 02 2017 Fedora Release Engineering - 6.2.0.874-6.git86e8892 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 6.2.0.874-5.git86e8892 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Apr 12 2017 Chris Leech - 6.2.0.874-4.git86e8892 +- rebuild to use shared libisns + +* Tue Feb 28 2017 Chris Leech - 6.2.0.874-3.git86e8892 +- libiscsi: fix discovery command timeout regression +- libiscsi: fix format security build errors + +* Thu Feb 16 2017 Chris Leech - 6.2.0.874-2.git86e8892 +- fix regression with iscsiadm discoverydb commands having a 0 timeout + +* Thu Feb 09 2017 Chris Leech - 6.2.0.874-1 +- update to 2.0.874 + +* Mon Dec 12 2016 Charalampos Stratakis - 6.2.0.873-35.git4c1f2d9 +- Rebuild for Python 3.6 + +* Tue Jul 19 2016 Fedora Release Engineering - 6.2.0.873-34.git4c1f2d9 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Fri Feb 19 2016 Chris Leech - 6.2.0.873-33.git4c1f2d9 +- sync with upstream +- sysfs handling changes to speed up operations over large number of sessions + +* Thu Feb 04 2016 Fedora Release Engineering - 6.2.0.873-32.git4c9d6f9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Feb 3 2016 Michael Schwendt - 6.2.0.873-31.git4c9d6f9 +- BuildRequires: isns-utils-static for -lisns (bz #1291913) + +* Tue Nov 03 2015 Robert Kuska - 6.2.0.873-30.git4c9d6f9 +- Rebuilt for Python3.5 rebuild + +* Tue Oct 06 2015 Chris Leech - 6.2.0.873-29.git4c9d6f9 +- rebase with upstream, change Source0 url to github +- build with external isns-utils + +* Mon Oct 05 2015 Chris Leech - 6.2.0.873-28.git6aa2c9b +- fixed broken multiple trigger scripts, removed old pre-systemd migration triggers +- added libiscsi session API patch (bz #1262279) + +* Wed Jun 17 2015 Fedora Release Engineering - 6.2.0.873-27.git6aa2c9b +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Jun 10 2015 Chris Leech - 6.2.0.873-26.git6aa2c9b +- rebase to upstream snapshot +- add patch to improve GIL lock performance in libiscsi +- Split Python 2 and Python 3 bindings out into subpackages + +* Wed Jan 28 2015 Chris Leech - 6.2.0.873-25.gitc9d830b +- split out session logout on shutdown to a separate service +- 985321 roll up libiscsi patches, update python bindings to support python3 +- scriptlets were never split out properly for the iscsiuio subpackage +- fix regression in network interface binding +- created iscsi-shutdown.service to ensure that session cleanup happens +- Add --with-slp=no +- segfault from unexpected netlink event during discovery +- inhibit strict aliasing optimizations in iscsiuio, rpmdiff error + +* Thu Oct 23 2014 Chris Leech - 6.2.0.873-24.gitc9d830b +- sync with upstream v2.0.873-84-gc9d830b +- ignore iscsiadm return in iscsi.service +- make sure systemd order against remote mounts is correct +- add discovery as a valid mode in iscsiadm.8 +- make sure to pass --with-security=no to isns configure + +* Sat Aug 16 2014 Fedora Release Engineering - 6.2.0.873-23 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 6.2.0.873-22 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Mon Apr 14 2014 Chris Leech - 6.2.0.873-21 +- boot session handling improvements +- split out iscsiuio into a seperate sub-package +- sync with new upstream additions +- revert change to return code when calling login_portal for sessions + that already exist, as it impacts users scripting around iscsiadm + +* Tue Dec 10 2013 Chris Leech - 6.2.0.873-17 +- fix regression in glob use, inappropriate error code escape +- clean up dead node links from discovery when reusing tpgt + +* Mon Nov 25 2013 Chris Leech - 6.2.0.873-16 +- fix iscsiuio socket activation +- have systemd start socket units on iscsiadm use, if not already listening + +* Sun Sep 15 2013 Chris Leech - 6.2.0.873-15 +- move /sbin to /usr/sbin +- use rpm macros in install rules + +* Fri Sep 13 2013 Chris Leech - 6.2.0.873-14 +- fix iscsiuio hardened build and other compiler flags + +* Fri Aug 23 2013 Andy Grover - 6.2.0.873-13 +- Fix patch 0041 to check session != NULL before calling iscsi_sysfs_read_boot() + +* Tue Aug 20 2013 Chris Leech - 6.2.0.873-12 +- fix regression in last build, database records can't be accessed + +* Mon Aug 19 2013 Chris Leech - 6.2.0.873-11 +- iscsi boot related fixes + make sure iscsid gets started if there are any boot sessions running + add reload target to fix double session problem when restarting from NM + don't rely on session list passed from initrd, never got fully implemented + remove patches related to running iscsid from initrd, possible to revisit later + +* Sun Aug 18 2013 Chris Leech - 6.2.0.873-10 +- sync with upstream git, minor context fixes after rebase of out-of-tree patches +- iscsiuio is merged upstream, remove old source archive and patches +- spec cleanups to fix rpmlint issues + +* Sun Aug 4 2013 Peter Robinson 6.2.0.873-9 +- Fix FTBFS, cleanup spec + +* Sat Aug 03 2013 Fedora Release Engineering - 6.2.0.873-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Tue Jun 11 2013 Chris Leech - 6.2.0.873-7 +- Use the systemd tmpfiles service to recreate lockfiles in /var/lock +- 955167 build as a position independent executable +- 894576 fix order of setuid/setgid and drop additional groups + +* Tue May 28 2013 Chris Leech - 6.2.0.873-6 +- Don't have iscsiadm scan for autostart record if node db is empty (bug #951951) + +* Tue Apr 30 2013 Orion Poplawski - 6.2.0.873-5 +- Fix typo in NM dispatcher script (bug #917058) + +* Thu Feb 21 2013 Chris Leech - 6.2.0.873-4 +- build with libkmod support, instead of calling out to modprobe +- enable socket activation by default + +* Thu Jan 24 2013 Kalev Lember - 6.2.0.873-3 +- Fix the postun script to not use ldconfig as the interpreter + +* Wed Jan 23 2013 Chris Leech - 6.2.0.873-2 +- package iscsi_mark_root_nodes script, it's being referenced by the unit files + +* Tue Jan 22 2013 Chris Leech - 6.2.0.873-1 +- rebase to new upstream code +- systemd conversion +- 565245 Fix multilib issues caused by timestamp in doxygen footers + +* Thu Jul 19 2012 Fedora Release Engineering - 6.2.0.872-19 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Feb 14 2012 Mike Christie 6.2.0.872.18 +- 789683 Fix boot slow down when the iscsi service is started + (regression added in 6.2.0.872.16 when the nm wait was added). + +* Mon Feb 6 2012 Mike Christie 6.2.0.872.17 +- 786174 Change iscsid/iscsi service startup, so it always starts + when called. + +* Sat Feb 4 2012 Mike Christie 6.2.0.872.16 +- 747479 Fix iscsidevs handling of network requirement + +* Fri Jan 13 2012 Fedora Release Engineering - 6.2.0.872-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Nov 30 2011 Mike Christie 6.2.0.872.14 +- Fix version string to reflect fedora and not rhel. + +* Tue Oct 18 2011 Mike Christie 6.2.0.872.13 +- Update iscsi tools. + +* Sat Apr 30 2011 Hans de Goede - 6.2.0.872-12 +- Change iscsi init scripts to check for networking being actually up, rather + then for NetworkManager being started (#692230) + +* Tue Apr 26 2011 Hans de Goede - 6.2.0.872-11 +- Fix iscsid autostarting when upgrading from an older version + (add iscsid.startup key to iscsid.conf on upgrade) +- Fix printing of [ OK ] when successfully stopping iscsid +- systemd related fixes: + - Add Should-Start/Stop tgtd to iscsi init script to fix (re)boot from + hanging when using locally hosted targets + - %%ghost /var/lock/iscsi and contents (#656605) + +* Mon Apr 25 2011 Mike Christie 6.2.0.872-10 +- Fix iscsi init scripts check for networking being up (#692230) + +* Wed Feb 09 2011 Fedora Release Engineering - 6.2.0.872-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild