[iscsi-initiator-utils: 34/109] mass-import of iscsi-initiator-utils-6.2.0.870-8.fc11.src.rpm from dist-f11
Chris Leech
cleech at fedoraproject.org
Tue Dec 10 21:22:14 UTC 2013
commit 2628f3092f1e5a70b46a0b6695a3e8424cdbee69
Author: dgregor <dgregor at redhat.com>
Date: Wed May 20 02:32:42 2009 +0000
mass-import of iscsi-initiator-utils-6.2.0.870-8.fc11.src.rpm from dist-f11
.cvsignore | 10 +-
04-iscsi | 17 +
iscsi-initiator-utils-add-iscsi-iname.patch | 470 ---
iscsi-initiator-utils-ibft-sysfs.patch | 312 ++
iscsi-initiator-utils-only-root-use.patch | 16 +
iscsi-initiator-utils-print-ibft-net-info.patch | 219 ++
iscsi-initiator-utils-start-iscsid.patch | 202 +
...itiator-utils-update-initscripts-and-docs.patch | 82 +-
iscsi-initiator-utils-use-red-hat-for-name.patch | 11 +
iscsi-initiator-utils-use-var-for-config.patch | 254 +-
iscsi-initiator-utils.spec | 208 +-
iscsi.init | 98 -
iscsid.init | 203 +-
iscsidevs.init | 189 +-
iscsistart-static.patch | 39 -
open-iscsi-2.0-870.1-485217.patch | 38 +
open-iscsi-2.0-870.1-490515-workaround.patch | 45 +
open-iscsi-2.0-870.1-add-libiscsi.patch | 3974 ++++++++++++++++++++
open-iscsi-2.0-870.1-ibft-newer-kernel.patch | 44 +
open-iscsi-2.0-870.1-no-exit.patch | 221 ++
sources | 2 +-
21 files changed, 5742 insertions(+), 912 deletions(-)
---
diff --git a/.cvsignore b/.cvsignore
index fa2efa9..c77cdb1 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,9 +1 @@
-open-iscsi-5.0.4.446.tar.gz
-open-iscsi-5.0.5.476.tar.bz2
-open-iscsi-5.0.5.595.tar.bz2
-open-iscsi-6.0.5.595.tar.bz2
-open-iscsi-1.1-645.tar.bz2
-open-iscsi-6.1.1.645.tar.bz2
-open-iscsi-6.1.1.685.tar.bz2
-open-iscsi-6.2.0.695.tar.bz2
-open-iscsi-2.0-754.tar.gz
+open-iscsi-2.0-870.1.tar.gz
diff --git a/04-iscsi b/04-iscsi
new file mode 100755
index 0000000..58aa798
--- /dev/null
+++ b/04-iscsi
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+export LC_ALL=C
+
+if [ "$2" = "down" ]; then
+ if ! /sbin/ip route ls | grep -q ^default &&
+ [ -f /var/lock/subsys/iscsi ]; then
+ /etc/rc.d/init.d/iscsi stop
+ fi
+fi
+
+if [ "$2" = "up" ]; then
+ if /sbin/ip -o route show dev "$1" | grep -q '^default' &&
+ /sbin/chkconfig iscsi; then
+ /etc/rc.d/init.d/iscsi start
+ fi
+fi
diff --git a/iscsi-initiator-utils-ibft-sysfs.patch b/iscsi-initiator-utils-ibft-sysfs.patch
new file mode 100644
index 0000000..c1db389
--- /dev/null
+++ b/iscsi-initiator-utils-ibft-sysfs.patch
@@ -0,0 +1,312 @@
+diff -Naurp open-iscsi-2.0-870-rc1/utils/fwparam_ibft/fw_entry.c open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/fw_entry.c
+--- open-iscsi-2.0-870-rc1/utils/fwparam_ibft/fw_entry.c 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/fw_entry.c 2008-06-30 21:21:57.000000000 -0500
+@@ -29,7 +29,8 @@ int fw_get_entry(struct boot_context *co
+
+ ret = fwparam_ppc(context, filepath);
+ if (ret)
+- ret = fwparam_ibft(context, filepath);
++ ret = fwparam_ibft_sysfs(context, filepath);
++
+ return ret;
+ }
+
+diff -Naurp open-iscsi-2.0-870-rc1/utils/fwparam_ibft/fwparam_ibft.h open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/fwparam_ibft.h
+--- open-iscsi-2.0-870-rc1/utils/fwparam_ibft/fwparam_ibft.h 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/fwparam_ibft.h 2008-06-30 21:21:57.000000000 -0500
+@@ -153,6 +153,7 @@ extern int dev_count;
+ #define TARGET "target"
+
+ extern int fwparam_ibft(struct boot_context *context, const char *filepath);
++extern int fwparam_ibft_sysfs(struct boot_context *context,
++ const char *filepath);
+ extern int fwparam_ppc(struct boot_context *context, const char *filepath);
+-
+ #endif /* FWPARAM_IBFT_H_ */
+diff -Naurp open-iscsi-2.0-870-rc1/utils/fwparam_ibft/fwparam_ibft_sysfs.c open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/fwparam_ibft_sysfs.c
+--- open-iscsi-2.0-870-rc1/utils/fwparam_ibft/fwparam_ibft_sysfs.c 1969-12-31 18:00:00.000000000 -0600
++++ open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/fwparam_ibft_sysfs.c 2008-06-30 21:21:57.000000000 -0500
+@@ -0,0 +1,271 @@
++/*
++ * Copyright (C) IBM Corporation. 2007
++ * Author: Konrad Rzeszutek <konradr at linux.vnet.ibm.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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#define _XOPEN_SOURCE 500
++#include <ftw.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <errno.h>
++#include "fwparam_ibft.h"
++#include <fw_context.h>
++
++#define IBFT_MAX 255
++#define IBFT_SYSFS_ROOT "/sys/firmware/ibft/"
++
++static char *target_list[IBFT_MAX];
++static char *nic_list[IBFT_MAX];
++static int nic_cnt;
++static int tgt_cnt;
++
++/*
++ * Helper routines.
++ */
++static int file_exist(const char *file)
++{
++
++ struct stat bootpath_stat;
++
++ return !stat(file, &bootpath_stat);
++}
++
++static int read_file(const char *file, char **contents)
++{
++ int error, fd, bytes_read;
++ struct stat bootpath_stat;
++
++ error = stat(file, &bootpath_stat);
++ if (error < 0) {
++ fprintf(stderr, "(%s:%d) stat %s, %s\n", __FILE__, __LINE__,
++ file, strerror(errno));
++ return error;
++ }
++
++ *contents = malloc(bootpath_stat.st_size);
++ if (!*contents) {
++ error = ENOMEM;
++ fprintf(stderr, "(%s:%d) Could not allocate enough memory for "\
++ "%s: %s (%d)\n",
++ __FILE__, __LINE__, file, strerror(error), error);
++ return errno;
++ }
++
++ fd = open(file, O_RDONLY);
++ if (fd < 0) {
++ fprintf(stderr, "(%s:%d): Could not open %s: %s (%d)\n",
++ __FILE__, __LINE__, file, strerror(errno), errno);
++ free(*contents);
++ return errno;
++ }
++
++ bytes_read = read(fd, *contents, bootpath_stat.st_size);
++ close(fd);
++ if (bytes_read > bootpath_stat.st_size) {
++ fprintf(stderr, "(%s:%d) Read more data in than expected for "\
++ "%s: %s (%d)\n",
++ __FILE__, __LINE__, file, strerror(EIO), EIO);
++ free(*contents);
++ return errno;
++ }
++ /* chop() implementation */
++ if (*(*contents + (ssize_t)(bytes_read - 1)) == '\n')
++ *(*contents + (ssize_t) (bytes_read - 1)) = 0;
++
++ return 0;
++}
++
++static int read_data(const char *dir, const char *name, char *dst, ssize_t size)
++{
++ char *data = NULL;
++ char file[FILENAMESZ];
++ int rc = 0;
++
++ memset(file, 0, FILENAMESZ);
++ strncat(file, dir, FILENAMESZ);
++ strncat(file, name, FILENAMESZ);
++
++ if (file_exist(file)) {
++ rc = read_file(file, &data);
++ if (debug)
++ fprintf(stderr, "(%s:%d) Read from %s:[%s]\n",
++ __FILE__, __LINE__, file, data);
++ if (!rc)
++ memcpy(dst, data, size);
++ free(data);
++ }
++
++ return rc;
++}
++
++static int read_int_data(const char *dir, const char *name, int *dst)
++{
++ int rc = 0;
++ char contents[5]; /* The flag is a 1 byte value */
++
++ rc = read_data(dir, name, (char *)&contents, sizeof(contents));
++ if (!rc)
++ *dst = atoi(contents);
++
++ return rc;
++}
++
++/*
++ * Finds the etherrnetX and targetX under the sysfs directory.
++ */
++static int find_sysfs_dirs(const char *fpath, const struct stat *sb,
++ int tflag, struct FTW *ftw)
++{
++ if (tflag == FTW_D &&
++ (strstr(fpath + ftw->base, "target")))
++ target_list[tgt_cnt++] = strdup(fpath);
++
++ if (tflag == FTW_D &&
++ (strstr(fpath + ftw->base, "ethernet")))
++ nic_list[nic_cnt++] = strdup(fpath);
++
++ return 0;
++}
++
++/*
++ * Routines to fill in the context values.
++ */
++static int fill_nic_context(const char *dir, struct boot_context *context)
++{
++ int rc = 0;
++
++ rc |= read_data(dir, "/mac", context->mac, sizeof(context->mac));
++ rc |= read_data(dir, "/vlan", context->vlan, sizeof(context->vlan));
++ rc |= read_data(dir, "/ip-addr", context->ipaddr,
++ sizeof(context->ipaddr));
++ rc |= read_data(dir, "/mask", context->mask, sizeof(context->mask));
++
++ return rc;
++}
++
++static int fill_initiator_context(const char *dir, struct boot_context *context)
++{
++ int rc = 0;
++
++ rc |= read_data(dir, "/initiator-name", context->initiatorname,
++ sizeof(context->initiatorname));
++ rc |= read_data(dir, "/isns-server", context->isid,
++ sizeof(context->isid));
++
++ return rc;
++}
++static int fill_tgt_context(const char *dir, struct boot_context *context)
++{
++ int rc = 0;
++
++ rc |= read_data(dir, "/target-name", context->targetname,
++ sizeof(context->targetname));
++ rc |= read_data(dir, "/ip-addr", context->target_ipaddr,
++ sizeof(context->target_ipaddr));
++ rc |= read_int_data(dir, "/port", &context->target_port);
++ rc |= read_data(dir, "/lun", context->lun,
++ sizeof(context->lun));
++ rc |= read_data(dir, "/chap-name", context->chap_name,
++ sizeof(context->chap_name));
++ rc |= read_data(dir, "/chap-secret", context->chap_password,
++ sizeof(context->chap_password));
++ rc |= read_data(dir, "/rev-chap-name", context->chap_name_in,
++ sizeof(context->chap_name_in));
++ rc |= read_data(dir, "/rev-chap-name-secret", context->chap_password_in,
++ sizeof(context->chap_password_in));
++
++ return 0;
++}
++
++#define IBFT_SYSFS_FLAG_NAME "/flags"
++#define IBFT_SYSFS_FLAG_FW_SEL_BOOT 2
++
++static int find_boot_flag(char *list[], ssize_t size, int *boot_idx)
++{
++ int rc = -1;
++ int i, flag = -1;
++
++ for (i = 0; i < size; i++, flag = -1) {
++ rc = read_int_data(list[i], IBFT_SYSFS_FLAG_NAME, &flag);
++ if (flag & IBFT_SYSFS_FLAG_FW_SEL_BOOT) {
++ *boot_idx = i;
++ rc = 0;
++ break;
++ }
++
++ }
++
++ return rc;
++}
++
++static void deallocate_lists(void)
++{
++ int i;
++
++ for (i = 0; i < nic_cnt; i++)
++ free(nic_list[i]);
++
++ nic_cnt = 0;
++ for (i = 0; i < tgt_cnt; i++)
++ free(target_list[i]);
++
++ tgt_cnt = 0;
++
++}
++
++int fwparam_ibft_sysfs(struct boot_context *context, const char *filepath)
++{
++ char initiator_dir[FILENAMESZ];
++ char *root_sysfs = NULL;
++ int rc = 1;
++ int nic_idx = -1, tgt_idx = -1;
++
++ if (filepath)
++ root_sysfs = (char *)filepath;
++ else
++ root_sysfs = IBFT_SYSFS_ROOT;
++
++ memset(&initiator_dir, 0 , FILENAMESZ);
++ strncat(initiator_dir, root_sysfs, FILENAMESZ);
++ strncat(initiator_dir, "initiator", FILENAMESZ);
++
++ if (file_exist(initiator_dir)) {
++
++ /* Find the target's and the ethernet's */
++ rc = nftw(root_sysfs, find_sysfs_dirs, 20, 1);
++
++ /* Find wihch target and which ethernet have
++ the boot flag set. */
++ rc = find_boot_flag(nic_list, nic_cnt, &nic_idx);
++ if (rc)
++ goto free;
++
++ rc = find_boot_flag(target_list, tgt_cnt, &tgt_idx);
++ if (rc)
++ goto free;
++
++ /* Fill in the context values */
++ rc = fill_nic_context(nic_list[nic_idx], context);
++ rc |= fill_tgt_context(target_list[tgt_idx], context);
++ rc |= fill_initiator_context(initiator_dir, context);
++ }
++free:
++ deallocate_lists();
++ return rc;
++}
+diff -Naurp open-iscsi-2.0-870-rc1/utils/fwparam_ibft/Makefile open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/Makefile
+--- open-iscsi-2.0-870-rc1/utils/fwparam_ibft/Makefile 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/utils/fwparam_ibft/Makefile 2008-06-30 21:22:44.000000000 -0500
+@@ -22,7 +22,7 @@
+ #
+
+ OBJS := fwparam_ibft.o fw_entry.o
+-OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o
++OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_ibft_sysfs.o
+ CLEANFILES = $(OBJS) *.output *~
+
+ OPTFLAGS ?= -O2 -g -fPIC
diff --git a/iscsi-initiator-utils-only-root-use.patch b/iscsi-initiator-utils-only-root-use.patch
new file mode 100644
index 0000000..b442ba0
--- /dev/null
+++ b/iscsi-initiator-utils-only-root-use.patch
@@ -0,0 +1,16 @@
+diff -up open-iscsi-2.0-870-rc1/usr/iscsiadm.c.error open-iscsi-2.0-870-rc1/usr/iscsiadm.c
+--- open-iscsi-2.0-870-rc1/usr/iscsiadm.c.error 2008-09-30 10:20:15.000000000 +0200
++++ open-iscsi-2.0-870-rc1/usr/iscsiadm.c 2008-09-30 10:20:15.000000000 +0200
+@@ -2141,6 +2141,12 @@ main(int argc, char **argv)
+ if (mode < 0)
+ usage(0);
+
++ if (getuid()) {
++ log_error("Must be run as root.");
++ rc = -1;
++ goto free_ifaces;
++ }
++
+ if (mode == MODE_FW) {
+ if ((rc = verify_mode_params(argc, argv, "ml", 0))) {
+ log_error("fw mode: option '-%c' is not "
diff --git a/iscsi-initiator-utils-print-ibft-net-info.patch b/iscsi-initiator-utils-print-ibft-net-info.patch
new file mode 100644
index 0000000..1285602
--- /dev/null
+++ b/iscsi-initiator-utils-print-ibft-net-info.patch
@@ -0,0 +1,219 @@
+diff -aurp open-iscsi-2.0-870.1/include/fw_context.h open-iscsi-2.0-870.1.work/include/fw_context.h
+--- open-iscsi-2.0-870.1/include/fw_context.h 2008-11-22 11:06:46.000000000 -0600
++++ open-iscsi-2.0-870.1.work/include/fw_context.h 2008-11-25 11:31:09.000000000 -0600
+@@ -23,21 +23,30 @@
+
+ struct boot_context {
+ #define IQNSZ (223+1)
++ /* target settings */
+ int target_port;
+- char initiatorname[IQNSZ];
+ char targetname[IQNSZ];
+ char target_ipaddr[32];
+ char chap_name[127];
+ char chap_password[16];
+ char chap_name_in[127];
+ char chap_password_in[16];
++
++ /* initiator settings */
++ char isid[10];
++ char initiatorname[IQNSZ];
++
++ /* network settings */
++ char dhcp[18];
+ char iface[42];
+ char mac[18];
+ char ipaddr[18];
++ char gateway[18];
++ char primary_dns[18];
++ char secondary_dns[18];
+ char mask[18];
+ char lun[17];
+ char vlan[15];
+- char isid[10];
+ };
+
+ extern int fw_get_entry(struct boot_context *context, const char *filepath);
+diff -aurp open-iscsi-2.0-870.1/utils/fwparam_ibft/fw_entry.c open-iscsi-2.0-870.1.work/utils/fwparam_ibft/fw_entry.c
+--- open-iscsi-2.0-870.1/utils/fwparam_ibft/fw_entry.c 2008-11-25 11:34:56.000000000 -0600
++++ open-iscsi-2.0-870.1.work/utils/fwparam_ibft/fw_entry.c 2008-11-25 11:34:25.000000000 -0600
+@@ -34,22 +34,13 @@ int fw_get_entry(struct boot_context *co
+ return ret;
+ }
+
+-/*
+- * Dump the 8 byte mac address
+- */
+-static void dump_mac(struct boot_context *context)
+-{
+- if (!strlen(context->mac))
+- return;
+-
+- printf("iface.hwaddress = %s\n", context->mac);
+-}
+-
+ static void dump_initiator(struct boot_context *context)
+ {
+- if (!strlen(context->initiatorname))
+- return;
+- printf("iface.initiatorname = %s\n", context->initiatorname);
++ if (strlen(context->initiatorname))
++ printf("iface.initiatorname = %s\n", context->initiatorname);
++
++ if (strlen(context->isid))
++ printf("iface.isid = %s\n", context->isid);
+ }
+
+ static void dump_target(struct boot_context *context)
+@@ -73,11 +64,44 @@ static void dump_target(struct boot_cont
+ if (strlen(context->chap_password_in))
+ printf("node.session.auth.password_in = %s\n",
+ context->chap_password_in);
++
++ if (strlen(context->lun))
++ printf("node.boot_lun = %s\n", context->lun);
++}
++
++/* TODO: add defines for all the idbm strings in this file and add a macro */
++static void dump_network(struct boot_context *context)
++{
++ /* Dump the 8 byte mac address (not iser support) */
++ if (strlen(context->mac))
++ printf("iface.hwaddress = %s\n", context->mac);
++ /*
++ * If this has a valid address then DHCP was used (broadcom sends
++ * 0.0.0.0).
++ */
++ if (strlen(context->dhcp) && strcmp(context->dhcp, "0.0.0.0"))
++ printf("iface.bootproto = DHCP\n");
++ else
++ printf("iface.bootproto = STATIC\n");
++ if (strlen(context->ipaddr))
++ printf("iface.ipaddress = %s\n", context->ipaddr);
++ if (strlen(context->mask))
++ printf("iface.subnet_mask = %s\n", context->mask);
++ if (strlen(context->gateway))
++ printf("iface.gateway = %s\n", context->gateway);
++ if (strlen(context->primary_dns))
++ printf("iface.primary_dns = %s\n", context->primary_dns);
++ if (strlen(context->secondary_dns))
++ printf("iface.secondary_dns = %s\n", context->secondary_dns);
++ if (strlen(context->vlan))
++ printf("iface.vlan = %s\n", context->vlan);
++ if (strlen(context->iface))
++ printf("iface.net_ifacename = %s\n", context->iface);
+ }
+
+ void fw_print_entry(struct boot_context *context)
+ {
+ dump_initiator(context);
+- dump_mac(context);
++ dump_network(context);
+ dump_target(context);
+ }
+diff -aurp open-iscsi-2.0-870.1/utils/fwparam_ibft/fwparam_ibft_sysfs.c open-iscsi-2.0-870.1.work/utils/fwparam_ibft/fwparam_ibft_sysfs.c
+--- open-iscsi-2.0-870.1/utils/fwparam_ibft/fwparam_ibft_sysfs.c 2008-11-25 11:34:56.000000000 -0600
++++ open-iscsi-2.0-870.1.work/utils/fwparam_ibft/fwparam_ibft_sysfs.c 2008-11-25 11:31:09.000000000 -0600
+@@ -24,11 +24,15 @@
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <errno.h>
+-#include "fwparam_ibft.h"
++#include <dirent.h>
+ #include <fw_context.h>
++#include <sys/types.h>
++
++#include "fwparam_ibft.h"
+
+ #define IBFT_MAX 255
+ #define IBFT_SYSFS_ROOT "/sys/firmware/ibft/"
++#define IBFT_SYSFS_DE
+
+ static char *target_list[IBFT_MAX];
+ static char *nic_list[IBFT_MAX];
+@@ -143,6 +147,48 @@ static int find_sysfs_dirs(const char *f
+ return 0;
+ }
+
++static int get_iface_from_device(const char *eth_dir,
++ struct boot_context *context)
++{
++ char dev_dir[FILENAMESZ];
++ int rc = ENODEV;
++ DIR *dirfd;
++ struct dirent *dent;
++
++ memset(dev_dir, 0, FILENAMESZ);
++ strncat(dev_dir, eth_dir, FILENAMESZ);
++ strncat(dev_dir, "/device", FILENAMESZ);
++
++ if (!file_exist(dev_dir))
++ return 0;
++
++ dirfd = opendir(dev_dir);
++ if (!dirfd)
++ return errno;
++
++ while ((dent = readdir(dirfd))) {
++ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
++ continue;
++
++ if (strncmp(dent->d_name, "net:", 4))
++ continue;
++
++ if ((strlen(dent->d_name) - 4) > (sizeof(context->iface) - 1)) {
++ rc = EINVAL;
++ printf("Net device %s too bug for iface buffer.\n",
++ dent->d_name);
++ break;
++ }
++
++ if (sscanf(dent->d_name, "net:%s", context->iface) != 1)
++ rc = EINVAL;
++ rc = 0;
++ break;
++ }
++
++ return rc;
++}
++
+ /*
+ * Routines to fill in the context values.
+ */
+@@ -154,7 +200,17 @@ static int fill_nic_context(const char *
+ rc |= read_data(dir, "/vlan", context->vlan, sizeof(context->vlan));
+ rc |= read_data(dir, "/ip-addr", context->ipaddr,
+ sizeof(context->ipaddr));
+- rc |= read_data(dir, "/mask", context->mask, sizeof(context->mask));
++ rc |= read_data(dir, "/subnet-mask", context->mask,
++ sizeof(context->mask));
++ rc |= read_data(dir, "/gateway", context->gateway,
++ sizeof(context->gateway));
++ rc |= read_data(dir, "/primary-dns", context->primary_dns,
++ sizeof(context->primary_dns));
++ rc |= read_data(dir, "/secondary-dns", context->secondary_dns,
++ sizeof(context->secondary_dns));
++ rc |= read_data(dir, "/dhcp", context->dhcp, sizeof(context->dhcp));
++
++ rc |= get_iface_from_device(dir, context);
+
+ return rc;
+ }
+@@ -199,7 +255,7 @@ static int fill_tgt_context(const char *
+ static int find_boot_flag(char *list[], ssize_t size, int *boot_idx)
+ {
+ int rc = -1;
+- int i, flag = -1;
++ int i, flag = 0;
+
+ for (i = 0; i < size; i++, flag = -1) {
+ rc = read_int_data(list[i], IBFT_SYSFS_FLAG_NAME, &flag);
+@@ -208,6 +264,8 @@ static int find_boot_flag(char *list[],
+ rc = 0;
+ break;
+ }
++ rc = -1;
++ flag = 0;
+
+ }
+
diff --git a/iscsi-initiator-utils-start-iscsid.patch b/iscsi-initiator-utils-start-iscsid.patch
new file mode 100644
index 0000000..859ad5b
--- /dev/null
+++ b/iscsi-initiator-utils-start-iscsid.patch
@@ -0,0 +1,202 @@
+diff -up open-iscsi-2.0-870-rc1/usr/discovery.c.start-iscsid open-iscsi-2.0-870-rc1/usr/discovery.c
+--- open-iscsi-2.0-870-rc1/usr/discovery.c.start-iscsid 2008-07-01 03:14:03.000000000 +0200
++++ open-iscsi-2.0-870-rc1/usr/discovery.c 2008-09-30 10:41:57.000000000 +0200
+@@ -87,7 +87,7 @@ int discovery_offload_sendtargets(int ho
+ * and get back the results. We should do this since it would
+ * allows us to then process the results like software iscsi.
+ */
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 1);
+ if (rc) {
+ log_error("Could not offload sendtargets to %s.\n",
+ drec->address);
+@@ -521,7 +521,7 @@ static int request_initiator_name(void)
+ memset(&req, 0, sizeof(req));
+ req.command = MGMT_IPC_CONFIG_INAME;
+
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 1);
+ if (rc)
+ return EIO;
+
+@@ -531,7 +531,7 @@ static int request_initiator_name(void)
+ memset(&req, 0, sizeof(req));
+ req.command = MGMT_IPC_CONFIG_IALIAS;
+
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 0);
+ if (rc)
+ /* alias is optional so return ok */
+ return 0;
+diff -up open-iscsi-2.0-870-rc1/usr/iscsiadm.c.start-iscsid open-iscsi-2.0-870-rc1/usr/iscsiadm.c
+--- open-iscsi-2.0-870-rc1/usr/iscsiadm.c.start-iscsid 2008-09-30 10:41:57.000000000 +0200
++++ open-iscsi-2.0-870-rc1/usr/iscsiadm.c 2008-09-30 10:41:57.000000000 +0200
+@@ -191,7 +191,7 @@ static void kill_iscsid(int priority)
+
+ memset(&req, 0, sizeof(req));
+ req.command = MGMT_IPC_IMMEDIATE_STOP;
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 0);
+ if (rc) {
+ iscsid_handle_error(rc);
+ log_error("Could not stop iscsid. Trying sending iscsid "
+@@ -823,7 +823,7 @@ static char *get_config_file(void)
+ memset(&req, 0, sizeof(req));
+ req.command = MGMT_IPC_CONFIG_FILE;
+
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 1);
+ if (rc)
+ return NULL;
+
+@@ -883,7 +883,7 @@ static int print_iscsi_state(int sid)
+ req.command = MGMT_IPC_SESSION_INFO;
+ req.u.session.sid = sid;
+
+- err = do_iscsid(&req, &rsp);
++ err = do_iscsid(&req, &rsp, 1);
+ /*
+ * for drivers like qla4xxx, iscsid does not display
+ * anything here since it does not know about it.
+@@ -1151,7 +1151,7 @@ session_stats(void *data, struct session
+ req.command = MGMT_IPC_SESSION_STATS;
+ req.u.session.sid = info->sid;
+
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 1);
+ if (rc)
+ return EIO;
+
+@@ -1617,7 +1617,7 @@ static int isns_dev_attr_query(discovery
+ memset(&req, 0, sizeof(iscsiadm_req_t));
+ req.command = MGMT_IPC_ISNS_DEV_ATTR_QUERY;
+
+- err = do_iscsid(&req, &rsp);
++ err = do_iscsid(&req, &rsp, 1);
+ if (err) {
+ iscsid_handle_error(err);
+ return EIO;
+diff -up open-iscsi-2.0-870-rc1/usr/iscsid.c.start-iscsid open-iscsi-2.0-870-rc1/usr/iscsid.c
+--- open-iscsi-2.0-870-rc1/usr/iscsid.c.start-iscsid 2008-07-01 03:14:03.000000000 +0200
++++ open-iscsi-2.0-870-rc1/usr/iscsid.c 2008-09-30 10:41:57.000000000 +0200
+@@ -252,7 +252,7 @@ static int sync_session(void *data, stru
+ req.u.session.sid = info->sid;
+ memcpy(&req.u.session.rec, &rec, sizeof(node_rec_t));
+
+- do_iscsid(&req, &rsp);
++ do_iscsid(&req, &rsp, 0);
+ return 0;
+ }
+
+diff -up open-iscsi-2.0-870-rc1/usr/iscsistart.c.start-iscsid open-iscsi-2.0-870-rc1/usr/iscsistart.c
+--- open-iscsi-2.0-870-rc1/usr/iscsistart.c.start-iscsid 2008-07-01 03:14:03.000000000 +0200
++++ open-iscsi-2.0-870-rc1/usr/iscsistart.c 2008-09-30 10:41:57.000000000 +0200
+@@ -112,7 +112,7 @@ static int stop_event_loop(void)
+
+ memset(&req, 0, sizeof(req));
+ req.command = MGMT_IPC_IMMEDIATE_STOP;
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 0);
+ if (rc) {
+ iscsid_handle_error(rc);
+ log_error("Could not stop event_loop\n");
+@@ -142,7 +142,7 @@ static int setup_session(void)
+ memset(&req, 0, sizeof(req));
+ req.command = MGMT_IPC_SESSION_LOGIN;
+ memcpy(&req.u.session.rec, &config_rec, sizeof(node_rec_t));
+- rc = do_iscsid(&req, &rsp);
++ rc = do_iscsid(&req, &rsp, 0);
+ if (rc)
+ iscsid_handle_error(rc);
+
+diff -up open-iscsi-2.0-870-rc1/usr/util.c.start-iscsid open-iscsi-2.0-870-rc1/usr/util.c
+--- open-iscsi-2.0-870-rc1/usr/util.c.start-iscsid 2008-07-01 03:14:03.000000000 +0200
++++ open-iscsi-2.0-870-rc1/usr/util.c 2008-09-30 11:25:38.000000000 +0200
+@@ -120,7 +120,7 @@ int increase_max_files(void)
+
+ #define MAXSLEEP 128
+
+-static mgmt_ipc_err_e iscsid_connect(int *fd)
++static mgmt_ipc_err_e iscsid_connect(int *fd, int iscsid_start)
+ {
+ int nsec;
+ struct sockaddr_un addr;
+@@ -145,8 +145,12 @@ static mgmt_ipc_err_e iscsid_connect(int
+
+ /* If iscsid isn't there, there's no sense
+ * in retrying. */
+- if (errno == ECONNREFUSED)
+- break;
++ if (errno == ECONNREFUSED) {
++ if (iscsid_start && nsec == 1)
++ system("/etc/rc.d/init.d/iscsid force-start");
++ else
++ break;
++ }
+
+ /*
+ * Delay before trying again
+@@ -158,11 +162,11 @@ static mgmt_ipc_err_e iscsid_connect(int
+ return MGMT_IPC_ERR_ISCSID_COMM_ERR;
+ }
+
+-mgmt_ipc_err_e iscsid_request(int *fd, iscsiadm_req_t *req)
++mgmt_ipc_err_e iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid)
+ {
+ int err;
+
+- err = iscsid_connect(fd);
++ err = iscsid_connect(fd, start_iscsid);
+ if (err)
+ return err;
+
+@@ -192,12 +196,13 @@ mgmt_ipc_err_e iscsid_response(int fd, i
+ return iscsi_err;
+ }
+
+-mgmt_ipc_err_e do_iscsid(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp)
++mgmt_ipc_err_e do_iscsid(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp,
++ int start_iscsid)
+ {
+ int fd;
+ mgmt_ipc_err_e err;
+
+- err = iscsid_request(&fd, req);
++ err = iscsid_request(&fd, req, start_iscsid);
+ if (err)
+ return err;
+
+@@ -220,7 +225,7 @@ int iscsid_req_by_rec_async(iscsiadm_cmd
+ req.command = cmd;
+ memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
+
+- return iscsid_request(fd, &req);
++ return iscsid_request(fd, &req, 1);
+ }
+
+ int iscsid_req_by_rec(iscsiadm_cmd_e cmd, node_rec_t *rec)
+@@ -241,7 +246,7 @@ int iscsid_req_by_sid_async(iscsiadm_cmd
+ req.command = cmd;
+ req.u.session.sid = sid;
+
+- return iscsid_request(fd, &req);
++ return iscsid_request(fd, &req, 1);
+ }
+
+ int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid)
+diff -up open-iscsi-2.0-870-rc1/usr/util.h.start-iscsid open-iscsi-2.0-870-rc1/usr/util.h
+--- open-iscsi-2.0-870-rc1/usr/util.h.start-iscsid 2008-07-01 03:14:03.000000000 +0200
++++ open-iscsi-2.0-870-rc1/usr/util.h 2008-09-30 10:41:57.000000000 +0200
+@@ -13,9 +13,10 @@ extern int oom_adjust(void);
+ extern void daemon_init(void);
+ extern int increase_max_files(void);
+
+-extern int do_iscsid(struct iscsiadm_req *req, struct iscsiadm_rsp *rsp);
++extern int do_iscsid(struct iscsiadm_req *req, struct iscsiadm_rsp *rsp,
++ int iscsid_start);
+ extern void iscsid_handle_error(int err);
+-extern int iscsid_request(int *fd, struct iscsiadm_req *req);
++extern int iscsid_request(int *fd, struct iscsiadm_req *req, int iscsid_start);
+ extern int iscsid_response(int fd, int cmd, struct iscsiadm_rsp *rsp);
+ extern int iscsid_req_wait(int cmd, int fd);
+ extern int iscsid_req_by_rec_async(int cmd, struct node_rec *rec, int *fd);
diff --git a/iscsi-initiator-utils-update-initscripts-and-docs.patch b/iscsi-initiator-utils-update-initscripts-and-docs.patch
index 8ecf215..35518c1 100644
--- a/iscsi-initiator-utils-update-initscripts-and-docs.patch
+++ b/iscsi-initiator-utils-update-initscripts-and-docs.patch
@@ -1,7 +1,7 @@
-diff -aurp open-iscsi-2.0-737/etc/iscsid.conf open-iscsi-2.0-737.work/etc/iscsid.conf
---- open-iscsi-2.0-737/etc/iscsid.conf 2006-11-22 14:21:17.000000000 -0600
-+++ open-iscsi-2.0-737.work/etc/iscsid.conf 2006-11-24 16:26:17.000000000 -0600
-@@ -14,8 +14,8 @@
+diff -aurp open-iscsi-2.0-870-rc1/etc/iscsid.conf open-iscsi-2.0-870-rc1.work/etc/iscsid.conf
+--- open-iscsi-2.0-870-rc1/etc/iscsid.conf 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/etc/iscsid.conf 2008-06-30 21:08:29.000000000 -0500
+@@ -27,8 +27,8 @@
# To request that the iscsi initd scripts startup a session set to "automatic".
# node.startup = automatic
#
@@ -12,46 +12,36 @@ diff -aurp open-iscsi-2.0-737/etc/iscsid.conf open-iscsi-2.0-737.work/etc/iscsid
# *************
# CHAP Settings
-diff -aurp open-iscsi-2.0-737/README open-iscsi-2.0-737.work/README
---- open-iscsi-2.0-737/README 2006-11-22 14:32:55.000000000 -0600
-+++ open-iscsi-2.0-737.work/README 2006-11-24 16:38:37.000000000 -0600
-@@ -303,19 +303,10 @@ option. For example this would mount a i
-
- /dev/sdb /mnt/iscsi ext3 _netdev 0 0
-
--SUSE or Debian:
-----------------
--Otherwise, if there is a initd script for your distro in etc/initd that
--gets installed with "make install"
--
-- /etc/init.d/open-iscsi start
+diff -aurp open-iscsi-2.0-870-rc1/README open-iscsi-2.0-870-rc1.work/README
+--- open-iscsi-2.0-870-rc1/README 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/README 2008-06-30 21:08:29.000000000 -0500
+@@ -78,11 +78,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.
-
--will usually get you started.
--
--Other:
-+Manual:
- ------
--If there is no initd script, you must start the tools by hand. First load the
--iscsi modules with:
-+If there is no initd script or you wish to run iscsi manually, you must start
-+the tools by hand. First load the iscsi modules with:
-
- modprobe -q iscsi_tcp
-
-@@ -358,8 +349,6 @@ storage), it is better to automate the l
-
- 3. automate target logins for future system reboots
- ---------------------------------------------------
--Note: this may only work for Red Hat, Fedora and SUSE configurations
--
- To automate login to a node, use the following with the record ID of the
- node discovered in the discovery above:
- iscsiadm -m node -T targetname -p ip:port --op update -n node.conn[0].startup -v automatic
-@@ -372,7 +361,6 @@ all sessions add the following to the /e
- To login to all the automated nodes, simply restart the iscsi service
- e.g /etc/init.d/open-iscsi restart
-
--
- 8. TBD
- ======
-
+ By default the kernel source found at
+ /lib/modules/`uname -a`/build
+ will be used to compile the open-iscsi modules. To specify a different
+@@ -694,7 +689,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:
+@@ -873,6 +868,8 @@ To login to all the automated nodes, sim
+ e.g /etc/init.d/open-iscsi restart. On your next startup the nodes will
+ be logged into autmotically.
+
++To set the startup value, so that nodes are not logged into automatically
++use the value "manual".
+
+ 8. Advanced Configuration
+ =========================
diff --git a/iscsi-initiator-utils-use-red-hat-for-name.patch b/iscsi-initiator-utils-use-red-hat-for-name.patch
new file mode 100644
index 0000000..debbceb
--- /dev/null
+++ b/iscsi-initiator-utils-use-red-hat-for-name.patch
@@ -0,0 +1,11 @@
+--- open-iscsi-2.0-865/utils/iscsi-iname.c 2007-02-21 12:20:47.000000000 -0600
++++ open-iscsi-2.0-865.work/utils/iscsi-iname.c 2007-06-20 12:37:10.000000000 -0500
+@@ -72,7 +72,7 @@ main(int argc, char *argv[])
+ exit(0);
+ }
+ } else {
+- prefix = "iqn.2005-03.org.open-iscsi";
++ prefix = "iqn.1994-05.com.fedora";
+ }
+
+ /* try to feed some entropy from the pool to MD5 in order to get
diff --git a/iscsi-initiator-utils-use-var-for-config.patch b/iscsi-initiator-utils-use-var-for-config.patch
index 9b739d4..2091d97 100644
--- a/iscsi-initiator-utils-use-var-for-config.patch
+++ b/iscsi-initiator-utils-use-var-for-config.patch
@@ -1,78 +1,182 @@
-diff -aurp open-iscsi-6.2.0.695/usr/idbm.c open-iscsi-6.2.0.695.work/usr/idbm.c
---- open-iscsi-6.2.0.695/usr/idbm.c 2006-10-03 13:54:51.000000000 -0500
-+++ open-iscsi-6.2.0.695.work/usr/idbm.c 2006-10-03 14:44:56.000000000 -0500
-@@ -831,10 +831,18 @@ idbm_node_write(idbm_t *db, node_rec_t *
-
- idbm_lock(db);
-
-- snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR);
-- if (access(portal, F_OK) != 0) {
-+ /* bah: there has to be a function to make all these subdirs for us */
-+ if (access(CONFIG_DIR, F_OK) != 0) {
- if (mkdir(portal, 0660) != 0) {
-- log_error("Could not make %s\n", portal);
-+ log_error("Could not make %s %d\n", CONFIG_DIR, errno);
-+ rc = errno;
-+ goto free_portal;
-+ }
-+ }
-+
-+ if (access(NODE_CONFIG_DIR, F_OK) != 0) {
-+ if (mkdir(NODE_CONFIG_DIR, 0660) != 0) {
-+ log_error("Could not make %s\n", NODE_CONFIG_DIR);
- rc = errno;
- goto free_portal;
- }
-@@ -869,6 +877,7 @@ free_portal:
- return rc;
- }
+diff -aurp open-iscsi-2.0-870-rc1/doc/iscsiadm.8 open-iscsi-2.0-870-rc1.work/doc/iscsiadm.8
+--- open-iscsi-2.0-870-rc1/doc/iscsiadm.8 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/doc/iscsiadm.8 2008-06-30 21:36:44.000000000 -0500
+@@ -47,7 +47,7 @@ display help text and exit
+ .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
+ or the iface config must have the hardware address (iface.hwaddress)
+ and the driver/transport_name (iface.transport_name). The iface's name is
+ then the filename of the iface config. For software iSCSI, the iface config
+@@ -317,10 +317,10 @@ The configuration file read by \fBiscsid
+ 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 -aurp open-iscsi-2.0-870-rc1/README open-iscsi-2.0-870-rc1.work/README
+--- open-iscsi-2.0-870-rc1/README 2008-06-30 21:37:05.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/README 2008-06-30 21:36:44.000000000 -0500
+@@ -148,10 +148,10 @@ available on all Linux installations.
+
+ The database contains two tables:
+
+-- Discovery table (/etc/iscsi/send_targets);
+-- Node table (/etc/iscsi/nodes).
++- Discovery table (/var/lib/iscsi/send_targets);
++- Node table (/var/lib/iscsi/nodes).
+
+-The regular place for iSCSI database files: /etc/iscsi/nodes
++The regular place for iSCSI database files: /var/lib/iscsi/nodes
+
+ The iscsiadm utility is a command-line tool to manage (update, delete,
+ insert, query) the persistent database.
+@@ -327,7 +327,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.
+
+ When you run iscsiadm the first time a hardware iscsi driver like qla4xxx is
+ loaded, iscsiadm will create default iface configs for you. The config created
+@@ -340,29 +340,29 @@ Running:
+ iface0 qla4xxx,00:c0:dd:08:63:e8,default
+ iface1 qla4xxx,00:c0:dd:08:63:ea,default
+
+-Will report iface configurations that are setup in /etc/iscsi/ifaces.
++Will report iface configurations that are setup in /var/lib/iscsi/ifaces.
+ The format is:
+
+ iface_name transport_name,hwaddress,net_ifacename
+
+ For software iscsi, you can create the iface configs by hand, but it is
+ reccomended that you use iscsiadm's iface mode. There is a 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 seperate iface config in /etc/iscsi/ifaces and each iface config file
++a seperate 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:
+
+ 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
-+/* TODO: merged these two functions */
- static int
- idbm_discovery_write(idbm_t *db, discovery_rec_t *rec)
+-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
+@@ -386,7 +386,7 @@ but you have not logged in then, iscsiad
+ all existing bindings.
+
+ When you then run iscsiadm to do discovery, it will check for interfaces
+-in /etc/iscsi/ifaces and bind the portals that are discovered so that
++in /var/lib/iscsi/ifaces and bind the portals that are discovered so that
+ they will be logged in through each iface. This behavior can also be overriden
+ by passing in the interfaces you want to use. For example if you had defined
+ two interface but only wanted to use one you can use the
+@@ -400,7 +400,7 @@ we do not bind a session to a iface, the
+
+ iscsiadm -m discovery -t st -p ip:port -I default -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, where we allow the network subsystem to decide which
+ device to use.
+@@ -435,7 +435,7 @@ iscsiadm -m node -p ip:port -I iface0 --
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260
+
+- This will first search /etc/iscsi/ifaces for interfaces
++ This 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.
+@@ -483,7 +483,7 @@ iscsiadm -m node -p ip:port -I iface0 --
+ existing portals.
+
+ - SendTargets iSCSI Discovery with a specific interface. If you
+- wish to only use a subset of the interfaces in /etc/iscsi/ifaces
++ wish to only use a subset of the interfaces in /var/lib/iscsi/ifaces
+ then you can pass them in during discovery:
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \
+@@ -768,8 +768,8 @@ where targetname is the name of the targ
+ and port of the portal. tpgt, is the portal group tag of
+ the portal, and is not used in iscsiadm commands except for static
+ record creation. And iface name 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 which ever NIC the
+ network layer decides is best.
+
+diff -aurp open-iscsi-2.0-870-rc1/usr/idbm.c open-iscsi-2.0-870-rc1.work/usr/idbm.c
+--- open-iscsi-2.0-870-rc1/usr/idbm.c 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/usr/idbm.c 2008-06-30 21:36:44.000000000 -0500
+@@ -2137,9 +2137,9 @@ free_info:
+ int idbm_init(idbm_get_config_file_fn *fn)
{
-@@ -883,10 +892,18 @@ idbm_discovery_write(idbm_t *db, discove
- }
-
- idbm_lock(db);
-- snprintf(portal, PATH_MAX, "%s", ST_CONFIG_DIR);
-- if (access(portal, F_OK) != 0) {
-- if (mkdir(portal, 0660) != 0) {
-- log_error("Could not make %s\n", portal);
-+
-+ if (access(CONFIG_DIR, F_OK) != 0) {
-+ if (mkdir(CONFIG_DIR, 0660) != 0) {
-+ log_error("Could not make %s %d\n", CONFIG_DIR, errno);
-+ rc = errno;
-+ goto free_portal;
-+ }
-+ }
-+
-+ if (access(ST_CONFIG_DIR, F_OK) != 0) {
-+ if (mkdir(ST_CONFIG_DIR, 0660) != 0) {
-+ log_error("Could not make %s\n", ST_CONFIG_DIR);
- rc = errno;
- goto free_portal;
+ /* 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\n", ISCSI_CONFIG_ROOT,
++ if (access(ISCSIVAR, F_OK) != 0) {
++ if (mkdir(ISCSIVAR, 0660) != 0) {
++ log_error("Could not make %s %d\n", ISCSIVAR,
+ errno);
+ return errno;
}
-diff -aurp open-iscsi-6.2.0.695/usr/initiator.h open-iscsi-6.2.0.695.work/usr/initiator.h
---- open-iscsi-6.2.0.695/usr/initiator.h 2006-10-03 13:54:51.000000000 -0500
-+++ open-iscsi-6.2.0.695.work/usr/initiator.h 2006-10-03 14:08:09.000000000 -0500
-@@ -31,11 +31,15 @@
- #include "actor.h"
- #include "queue.h"
-
--#define ST_CONFIG_DIR "/etc/iscsi/send_targets"
--#define NODE_CONFIG_DIR "/etc/iscsi/nodes"
-+#define CONFIG_DIR "/var/lib/iscsi"
-+#define ST_CONFIG_DIR "/var/lib/iscsi/send_targets"
-+#define NODE_CONFIG_DIR "/var/lib/iscsi/nodes"
-+
- #define CONFIG_FILE "/etc/iscsi/iscsid.conf"
--#define PID_FILE "/var/run/iscsid.pid"
- #define INITIATOR_NAME_FILE "/etc/iscsi/initiatorname.iscsi"
-+
-+#define PID_FILE "/var/run/iscsid.pid"
-+
- #define LOCK_DIR "/var/lock/iscsi"
- #define LOCK_FILE "/var/lock/iscsi/lock"
- #define LOCK_WRITE_FILE "/var/lock/iscsi/lock.write"
+diff -aurp open-iscsi-2.0-870-rc1/usr/idbm.h open-iscsi-2.0-870-rc1.work/usr/idbm.h
+--- open-iscsi-2.0-870-rc1/usr/idbm.h 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/usr/idbm.h 2008-06-30 21:36:58.000000000 -0500
+@@ -26,11 +26,12 @@
+ #include "initiator.h"
+ #include "config.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 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 ST_CONFIG_DIR ISCSIVAR"send_targets"
+ #define ST_CONFIG_NAME "st_config"
+
+ #define TYPE_INT 0
+diff -aurp open-iscsi-2.0-870-rc1/usr/iface.h open-iscsi-2.0-870-rc1.work/usr/iface.h
+--- open-iscsi-2.0-870-rc1/usr/iface.h 2008-06-30 20:14:03.000000000 -0500
++++ open-iscsi-2.0-870-rc1.work/usr/iface.h 2008-06-30 21:36:44.000000000 -0500
+@@ -20,7 +20,7 @@
+ #ifndef ISCSI_IFACE_H
+ #define ISCSI_IFACE_H
+
+-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces"
++#define IFACE_CONFIG_DIR "/var/lib/iscsi/ifaces"
+
+ struct iface_rec;
+ struct list_head;
diff --git a/iscsi-initiator-utils.spec b/iscsi-initiator-utils.spec
index b405666..bbc4f9d 100644
--- a/iscsi-initiator-utils.spec
+++ b/iscsi-initiator-utils.spec
@@ -1,20 +1,33 @@
+%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
+
Summary: iSCSI daemon and utility programs
Name: iscsi-initiator-utils
-Version: 6.2.0.754
-Release: 0.0%{?dist}
-Source0: http://www.open-iscsi.org/bits/open-iscsi-2.0-754.tar.gz
+Version: 6.2.0.870
+Release: 8%{?dist}
+Source0: http://www.open-iscsi.org/bits/open-iscsi-2.0-870.1.tar.gz
Source1: iscsid.init
Source2: iscsidevs.init
+Source3: 04-iscsi
Patch0: iscsi-initiator-utils-update-initscripts-and-docs.patch
-Patch1: iscsi-initiator-utils-add-iscsi-iname.patch
-Patch2: iscsi-initiator-utils-use-var-for-config.patch
+Patch1: iscsi-initiator-utils-use-var-for-config.patch
+Patch2: iscsi-initiator-utils-use-red-hat-for-name.patch
+Patch3: iscsi-initiator-utils-ibft-sysfs.patch
+Patch4: iscsi-initiator-utils-print-ibft-net-info.patch
+Patch5: iscsi-initiator-utils-only-root-use.patch
+Patch6: iscsi-initiator-utils-start-iscsid.patch
+Patch7: open-iscsi-2.0-870.1-add-libiscsi.patch
+Patch8: open-iscsi-2.0-870.1-no-exit.patch
+Patch9: open-iscsi-2.0-870.1-ibft-newer-kernel.patch
+Patch10: open-iscsi-2.0-870.1-485217.patch
+Patch11: open-iscsi-2.0-870.1-490515-workaround.patch
Group: System Environment/Daemons
-License: GPL
+License: GPLv2+
URL: http://www.open-iscsi.org
-Buildroot: %{_tmppath}/%{name}-root
-BuildRequires: openssl-devel
-Prereq: /sbin/chkconfig
+Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildRequires: openssl-devel flex bison python-devel doxygen glibc-static
+Requires(post): chkconfig
+Requires(preun): chkconfig /sbin/service
ExcludeArch: s390 s390x
%description
@@ -23,15 +36,39 @@ 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.
+%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}.
+
%prep
-%setup -q -n open-iscsi-2.0-754
+%setup -q -n open-iscsi-2.0-870.1
%patch0 -p1 -b .update-initscripts-and-docs
-%patch1 -p1 -b .add-iscsi-iname
-%patch2 -p1 -b .use-var-for-config
+%patch1 -p1 -b .use-var-for-config
+%patch2 -p1 -b .use-red-hat-for-name
+%patch3 -p1 -b .ibft-sysfs
+%patch4 -p1 -b .print-ibft-net-info
+%patch5 -p1 -b .only-root
+%patch6 -p1 -b .start-iscsid
+%patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+
%build
+make OPTFLAGS="%{optflags}" -C utils/fwparam_ibft
make OPTFLAGS="%{optflags}" -C usr
make OPTFLAGS="%{optflags}" -C utils
+make OPTFLAGS="%{optflags}" -C libiscsi
+pushd libiscsi
+python setup.py build
+popd
%install
rm -rf $RPM_BUILD_ROOT
@@ -39,51 +76,158 @@ mkdir -p $RPM_BUILD_ROOT/sbin
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man8
mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
mkdir -p $RPM_BUILD_ROOT/etc/iscsi
-mkdir -p $RPM_BUILD_ROOT/etc/iscsi
-mkdir -p $RPM_BUILD_ROOT/etc/iscsi
+mkdir -p $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d
mkdir -p $RPM_BUILD_ROOT/var/lib/iscsi
mkdir -p $RPM_BUILD_ROOT/var/lib/iscsi/nodes
mkdir -p $RPM_BUILD_ROOT/var/lib/iscsi/send_targets
+mkdir -p $RPM_BUILD_ROOT/var/lib/iscsi/static
+mkdir -p $RPM_BUILD_ROOT/var/lib/iscsi/isns
+mkdir -p $RPM_BUILD_ROOT/var/lib/iscsi/slp
+mkdir -p $RPM_BUILD_ROOT/var/lib/iscsi/ifaces
mkdir -p $RPM_BUILD_ROOT/var/lock/iscsi
+mkdir -p $RPM_BUILD_ROOT%{_libdir}
+mkdir -p $RPM_BUILD_ROOT%{_includedir}
+mkdir -p $RPM_BUILD_ROOT%{python_sitearch}
+
+
-install -s -m 755 usr/iscsid usr/iscsiadm utils/iscsi-iname usr/iscsistart $RPM_BUILD_ROOT/sbin
-install -m 644 doc/iscsiadm.8 $RPM_BUILD_ROOT/%{_mandir}/man8
-install -m 644 doc/iscsid.8 $RPM_BUILD_ROOT/%{_mandir}/man8
-#install -m 755 etc/initd/initd.redhat $RPM_BUILD_ROOT/etc/rc.d/init.d/iscsi
-install -m 644 etc/iscsid.conf $RPM_BUILD_ROOT/etc/iscsi
+install -p -m 755 usr/iscsid usr/iscsiadm utils/iscsi-iname usr/iscsistart $RPM_BUILD_ROOT/sbin
+install -p -m 644 doc/iscsiadm.8 $RPM_BUILD_ROOT/%{_mandir}/man8
+install -p -m 644 doc/iscsid.8 $RPM_BUILD_ROOT/%{_mandir}/man8
+install -p -m 644 etc/iscsid.conf $RPM_BUILD_ROOT%{_sysconfdir}/iscsi
+
+install -p -m 755 %{SOURCE1} $RPM_BUILD_ROOT%{_initrddir}/iscsid
+install -p -m 755 %{SOURCE2} $RPM_BUILD_ROOT%{_initrddir}/iscsi
+install -p -m 755 %{SOURCE3} $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d
+
+install -p -m 755 libiscsi/libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir}
+ln -s libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir}/libiscsi.so
+install -p -m 644 libiscsi/libiscsi.h $RPM_BUILD_ROOT%{_includedir}
+
+install -p -m 755 libiscsi/build/lib.linux-*/libiscsimodule.so \
+ $RPM_BUILD_ROOT%{python_sitearch}
-install -m 755 %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/iscsid
-install -m 755 %{SOURCE2} $RPM_BUILD_ROOT/etc/rc.d/init.d/iscsi
%clean
rm -rf $RPM_BUILD_ROOT
%post
-if [ ! -f /etc/iscsi/initiatorname.iscsi ]; then
- echo "InitiatorName=`/sbin/iscsi-iname`" > /etc/iscsi/initiatorname.iscsi
+/sbin/ldconfig
+if [ "$1" -eq "1" ]; then
+ if [ ! -f %{_sysconfdir}/iscsi/initiatorname.iscsi ]; then
+ echo "InitiatorName=`/sbin/iscsi-iname`" > %{_sysconfdir}/iscsi/initiatorname.iscsi
+ fi
+ /sbin/chkconfig --add iscsid
+ /sbin/chkconfig --add iscsi
fi
-/sbin/chkconfig --add iscsid
-/sbin/chkconfig --add iscsi
+
+%postun -p /sbin/ldconfig
%preun
if [ "$1" = "0" ]; then
+ # stop iscsi
+ /sbin/service iscsi stop > /dev/null 2>&1
+ # delete service
/sbin/chkconfig --del iscsi
+ # stop iscsid
+ /sbin/service iscsid stop > /dev/null 2>&1
+ # delete service
/sbin/chkconfig --del iscsid
fi
%files
%defattr(-,root,root)
%doc README
-%dir /var/lib/iscsi/nodes
-%dir /var/lib/iscsi/send_targets
-%dir /var/lock/iscsi
-%config /etc/rc.d/init.d/iscsi
-%config /etc/rc.d/init.d/iscsid
-%attr(0600,root,root) %config(noreplace) /etc/iscsi/iscsid.conf
+%dir %{_var}/lib/iscsi
+%dir %{_var}/lib/iscsi/nodes
+%dir %{_var}/lib/iscsi/isns
+%dir %{_var}/lib/iscsi/static
+%dir %{_var}/lib/iscsi/slp
+%dir %{_var}/lib/iscsi/ifaces
+%dir %{_var}/lib/iscsi/send_targets
+%dir %{_var}/lock/iscsi
+%{_initrddir}/iscsi
+%{_initrddir}/iscsid
+%{_sysconfdir}/NetworkManager
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/iscsi/iscsid.conf
/sbin/*
-%{_mandir}/*/*
+%{_libdir}/libiscsi.so.0
+%{python_sitearch}/libiscsimodule.so
+%{_mandir}/man8/*
+
+%files devel
+%defattr(-,root,root,-)
+%doc libiscsi/html
+%{_libdir}/libiscsi.so
+%{_includedir}/libiscsi.h
%changelog
+* Fri Apr 3 2009 Hans de Goede <hdegoede at redhat.com> 6.2.0.870-8
+- Stop the NM script from exiting with an error status when it
+ didn't do anything (#493411)
+
+* Fri Mar 20 2009 Hans de Goede <hdegoede at redhat.com> 6.2.0.870-7
+- libiscsi: use fwparam_ibft_sysfs() instead of fw_get_entry(), as
+ the latter causes stack corruption (workaround #490515)
+
+* Sat Mar 14 2009 Terje Rosten <terje.rosten at ntnu.no> - 6.2.0.870-6
+- Add glibc-static to buildreq to build in F11
+
+* Wed Feb 25 2009 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 6.2.0.870-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
+
+* Thu Feb 12 2009 Hans de Goede <hdegoede at redhat.com> 6.2.0.870-4
+- Fix libiscsi.discover_sendtargets python method to accept None as valid
+ authinfo argument (#485217)
+
+* Wed Jan 28 2009 Hans de Goede <hdegoede at redhat.com> 6.2.0.870-3
+- Fix reading of iBFT firmware with newer kernels
+
+* Wed Jan 28 2009 Hans de Goede <hdegoede at redhat.com> 6.2.0.870-2
+- Add libiscsi iscsi administration library and -devel subpackage
+
+* Tue Nov 25 2008 Mike Christie <mchristie at redhat.com> 6.2.0.870-1.0
+- Rebase to upstream
+
+* Thu Nov 6 2008 Hans de Goede <hdegoede at redhat.com> 6.2.0.870-0.2.rc1
+- Add force-start iscsid initscript option and use that in "patch to make
+ iscsiadm start iscsid when needed" so that iscsid will actual be started
+ even if there are no iscsi disks configured yet (rh 470437)
+- Do not start iscsid when not running when iscsiadm -k 0 gets executed
+ (rh 470438)
+
+* Tue Sep 30 2008 Hans de Goede <hdegoede at redhat.com> 6.2.0.870-0.1.rc1
+- Rewrite SysV initscripts, fixes rh 441290, 246960, 282001, 436175, 430791
+- Add patch to make iscsiadm complain and exit when run as user instead
+ of hang spinning for the database lock
+- Add patch to make iscsiadm start iscsid when needed (rh 436175 related)
+- Don't start iscsi service when network not yet up (in case of using NM)
+ add NM dispatcher script to start iscsi service once network is up
+
+* Mon Jun 30 2008 Mike Christie <mchristie at redhat.com> - 6.2.0.870
+- Rebase to open-iscsi-2-870
+- 453282 Handle sysfs changes.
+
+* Fri Apr 25 2008 Mike Christie <mchristie at redhat.com> - 6.2.0.868-0.7
+- 437522 log out sessions that are not used for root during "iscsi stop".
+
+* Fri Apr 4 2008 Mike Christie <mchristie at redhat.com> - 6.2.0.868-0.6
+- Rebase to RHEL5 to bring in bug fixes.
+- 437522 iscsi startup does not need to modify with network startup.
+- 436175 Check for running sessions when stopping service.
+
+* Wed Feb 5 2008 Mike Christie <mchristie at redhat.com> - 6.2.0.868-0.3
+- Rebase to upstream and RHEL5.
+- 246960 LSB init script changes.
+
+* Fri Oct 5 2007 Mike Christie <mchristie at redhat.com> - 6.2.0.865-0.2
+- Rebase to upstream's bug fix release.
+- Revert init script startup changes from 225915 which reviewers did
+ not like.
+
+* Mon Jun 20 2007 Mike Christie <mchristie at redhat.com> - 6.2.0.754-0.1
+- 225915 From Adrian Reber - Fix up spec and init files for rpmlint.
+
* Tue Feb 6 2007 Mike Christie <mchristie at redhat.com> - 6.2.0.754-0.0
- Rebase to upstream.
- Add back --map functionality but in session mode to match RHEL5 fixes
diff --git a/iscsid.init b/iscsid.init
index 1322ca6..035faee 100755
--- a/iscsid.init
+++ b/iscsid.init
@@ -1,5 +1,7 @@
#!/bin/sh
#
+# iscsid iSCSI daemon
+#
# chkconfig: 345 7 89
# description: Starts and stops the iSCSI daemon.
#
@@ -7,94 +9,131 @@
# pidfile: /var/run/iscsid.pid
# config: /etc/iscsi/iscsid.conf
+### BEGIN INIT INFO
+# Provides: iscsid
+# Default-Start: 3 4 5
+# Default-Stop: 0 1 2 6
+# Short-Description: Starts and stops login iSCSI daemon.
+# Description: iscsid provides the iSCSI session and connection state machine
+# for software iscsi/iser (iscsi_tcp/ib_iser) and partialy
+# offloaded hardware (bnx2i).
+### END INIT INFO
+
# Source function library.
-. /etc/init.d/functions
-
-PATH=/sbin:/bin:/usr/sbin:/usr/bin
-
-RETVAL=0
-
-start()
-{
- echo -n $"Turning off network shutdown. "
- # we do not want iscsi or network to run during system shutdown
- # incase there are RAID or multipath devices using
- # iscsi disks
- chkconfig --level 06 network off
- rm /etc/rc0.d/*network
- rm /etc/rc6.d/*network
-
- echo -n $"Starting iSCSI daemon: "
- modprobe -q iscsi_tcp
- modprobe -q ib_iser
- daemon iscsid
- RETVAL=$?
- echo
- [ $RETVAL -eq 0 ] || return
-
- touch /var/lock/subsys/iscsid
-
- success
- echo
+. /etc/rc.d/init.d/functions
+
+exec=/sbin/iscsid
+prog=iscsid
+config=/etc/iscsi/iscsid.conf
+lockfile=/var/lock/subsys/$prog
+
+# FIXME this has a false positive for root on nfs
+root_is_iscsi() {
+ rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab)
+ [[ "$rootopts" =~ "_netdev" ]]
+}
+
+force_start() {
+ echo -n $"Starting $prog: "
+ modprobe -q iscsi_tcp
+ modprobe -q ib_iser
+ daemon $prog
+ retval=$?
+ echo
+ [ $retval -eq 0 ] && touch $lockfile
+ return $retval
+}
+
+start() {
+ [ -x $exec ] || exit 5
+ [ -f $config ] || exit 6
+
+ # only start if nodes are setup to startup automatically or root is iscsi
+ grep -qrs "node.startup = automatic" /var/lib/iscsi/nodes
+ if [ $? -eq 0 ] || root_is_iscsi; then
+ force_start
+ return $?
+ fi
+
+ return 0
}
-stop()
-{
- rm -f /var/lock/subsys/iscsid
-
- # If this is a final shutdown/halt, do nothing since
- # we may need iscsid for as long as possible (halt script kills
- # us at the last second)
- if [ "$RUNLEVEL" = "6" -o "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" ]; then
- success
- return
- fi
-
- # don't turn off iscsi if root is possibly on a iscsi disk
- rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab)
- if [[ "$rootopts" =~ "_netdev" ]] ; then
- echo $"Can not shutdown iSCSI. Root is on a iSCSI disk."
- exit 1
- fi
-
- echo -n $"Stopping iSCSI daemon: "
-
- # iscsid does not have a nice shutdown process.
- # It really should never be stopped
- pkill -KILL iscsid
- echo
-
- modprobe -r ib_iser 2>/dev/null
- modprobe -r iscsi_tcp 2>/dev/null
+stop() {
+ declare -a iparams=( $(iscsiadm -m session 2>/dev/null | egrep "tcp|iser") )
+ if [[ -n "${iparams[*]}" ]]; then
+ # We have active sessions, so don't stop iscsid!!
+ echo -n $"Not stopping $prog: iscsi sessions still active"
+ warning $"Not stopping $prog: iscsi sessions still active"
+ echo
+ return 0
+ fi
+
+ echo -n $"Stopping $prog: "
+ killproc $prog
+ retval=$?
+ echo
+
+ modprobe -r ib_iser 2>/dev/null
+ modprobe -r iscsi_tcp 2>/dev/null
+
+ [ $retval -eq 0 ] && rm -f $lockfile
+ return $retval
}
-restart()
-{
- stop
- start
+restart() {
+ stop
+ start
}
+reload() {
+ return 3
+}
+
+force_reload() {
+ restart
+}
+
+rh_status() {
+ status $prog
+}
+
+rh_status_q() {
+ rh_status >/dev/null 2>&1
+}
+
+
case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- restart)
- stop
- start
- ;;
- status)
- status iscsid
- RETVAL=$?
- ;;
- condrestart)
- [ -f /var/lock/subsys/iscsid ] && restart
- ;;
- *)
- echo $"Usage: $0 {start|stop|restart|status|condrestart}"
- exit 1
+ start)
+ rh_status_q && exit 0
+ $1
+ ;;
+ force-start)
+ force_start
+ ;;
+ stop)
+ rh_status_q || exit 0
+ $1
+ ;;
+ restart)
+ $1
+ ;;
+ reload)
+ rh_status_q || exit 7
+ $1
+ ;;
+ force-reload)
+ force_reload
+ ;;
+ status)
+ rh_status
+ ;;
+ condrestart|try-restart)
+ rh_status_q || exit 0
+ restart
+ ;;
+ *)
+ echo $"Usage: $0
+{start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
+ exit 2
esac
-
-exit $RETVAL
+exit $?
diff --git a/iscsidevs.init b/iscsidevs.init
index 88d82b8..2728b8d 100755
--- a/iscsidevs.init
+++ b/iscsidevs.init
@@ -1,77 +1,146 @@
#!/bin/sh
#
+# iscsi: log into iSCSI targets
+#
# chkconfig: 345 13 89
# description: Logs into iSCSI targets needed at system startup
-#
+
+# Note we should have $network in Required-Start/Stop but we don't because if
+# we would require network chkconfig will put us directly after NetworkManager
+# when using NM, which will make our see if the network is up test succeed
+# while NM is actually still configuring the network. By not requiring network
+# chkconfig will use the chkconfig header to determine our start prio, starting
+# us after the old network service, but before NM (netfs does this the same).
+
+### BEGIN INIT INFO
+# Provides: iscsi
+# Required-Start: iscsid
+# Required-Stop: iscsid
+# Default-Start: 3 4 5
+# Default-Stop: 0 1 2 6
+# Short-Description: Starts and stops login and scanning of iSCSI devices.
+# Description: iscsi provides the iSCSI state machine for software iscsi/iser
+# and partial offloaded hardware. iscsi logs into and scans
+# for iSCSI devices, and shuts them down when stopped.
+### END INIT INFO
+
# Source function library.
-. /etc/init.d/functions
+. /etc/rc.d/init.d/functions
+
+exec="/sbin/iscsiadm"
+prog="iscsi"
+config="/etc/iscsi/initiatorname.iscsi"
+lockfile=/var/lock/subsys/$prog
+iscsid_lockfile=/var/lock/subsys/${prog}_iscsid
-PATH=/sbin:/bin:/usr/sbin:/usr/bin
+start() {
+ [ -x $exec ] || exit 5
+ [ -f $config ] || exit 6
-RETVAL=0
+ # if the network isn't up yet exit cleanly, NetworkManager will call us
+ # again when the network is up
+ [ ! -f /var/lock/subsys/network -a ! -f /var/lock/subsys/NetworkManager ] && exit 0
-start()
-{
+ # if no nodes are setup to startup automatically exit cleanly
+ grep -qrs "node.startup = automatic" /var/lib/iscsi/nodes
+ [ $? -eq 0 ] || exit 0
- status iscsid
- RETVAL=$?
+ # this script is normally called from startup so log into
+ # nodes marked node.startup=automatic
+ echo -n $"Starting $prog: "
+ $exec -m node --loginall=automatic 2>&1 > /dev/null | grep iscsiadm
- if [ $RETVAL -ne 0 ]; then
- /etc/init.d/iscsid start
- fi
+ # <sigh> iscsiadm does not always give a non 0 exit status in case of
+ # error so we grep for any messages to stderr and see those as errors too
+ if [ ${PIPESTATUS[0]} -ne 0 -o ${PIPESTATUS[1]} -eq 0 ]; then
+ failure $"Starting $prog"
+ echo
+ return 1
+ fi
- echo -n $"Setting up iSCSI targets: "
- # this script is normally called from startup so log into
- # nodes marked node.startup=automatic
- iscsiadm -m node --loginall=automatic
- touch /var/lock/subsys/iscsi
- success
- echo
+ success $"Starting $prog"
+ touch $lockfile
+ echo
+ return 0
}
-stop()
-{
- rm -f /var/lock/subsys/iscsi
-
- # If this is a final shutdown/halt, do nothing since
- # lvm/dm, md, power path, etc do not always handle this
- if [ "$RUNLEVEL" = "6" -o "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" ]; then
- success
- return
- fi
-
- # don't turn off iscsi if root is possibly on a iscsi disk
- rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab)
- if [[ "$rootopts" =~ "_netdev" ]] ; then
- echo $"Can not shutdown iSCSI. Root is on a iSCSI disk."
- exit 1
- fi
-
- iscsiadm -m node --logoutall=all
- /etc/init.d/iscsid stop
- success
+stop() {
+ echo -n $"Stopping $prog: "
+ $exec -m node --logoutall=automatic 2>&1 > /dev/null | grep iscsiadm
+
+ # <sigh> iscsiadm does not always give a non 0 exit status in case of
+ # error so we grep for any messages to stderr and see those as errors too
+ if [ ${PIPESTATUS[0]} -ne 0 -o ${PIPESTATUS[1]} -eq 0 ]; then
+ failure $"Stopping $prog"
+ echo
+ return 1
+ fi
+
+ success $"Stopping $prog"
+ rm -f $lockfile
+ echo
+ return 0
}
+restart() {
+ stop
+ start
+}
+
+reload() {
+ return 3
+}
+
+force_reload() {
+ restart
+}
+
+rh_status() {
+ [ -f $lockfile ] || return 3
+
+ declare -a iparams=( $(iscsiadm -m session 2>/dev/null | egrep "tcp|iser") )
+ if [[ -z "${iparams[*]}" ]]; then
+ # no sessions
+ return 2
+ fi
+
+ return 0
+}
+
+rh_status_q() {
+ rh_status >/dev/null 2>&1
+}
+
+
case "$1" in
- start)
- start
- ;;
- stop)
- stop
- ;;
- restart)
- stop
- start
- ;;
- status)
- status iscsid
- RETVAL=$?
- ;;
- condrestart)
- [ -f /var/lock/subsys/iscsi ] && restart
- ;;
- *)
- echo $"Usage: $0 {start|stop|restart|status|condrestart}"
- exit 1
+ start)
+ rh_status_q && exit 0
+ $1
+ ;;
+ stop)
+ rh_status_q || exit 0
+ $1
+ ;;
+ restart)
+ $1
+ ;;
+ reload)
+ rh_status_q || exit 7
+ $1
+ ;;
+ force-reload)
+ force_reload
+ ;;
+ status)
+ rh_status
+ ;;
+ condrestart|try-restart)
+ rh_status_q || exit 0
+ restart
+ ;;
+ *)
+ echo $"Usage: $0
+{start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
+ exit 2
esac
-exit $RETVAL
+exit $?
diff --git a/open-iscsi-2.0-870.1-485217.patch b/open-iscsi-2.0-870.1-485217.patch
new file mode 100644
index 0000000..f80cf27
--- /dev/null
+++ b/open-iscsi-2.0-870.1-485217.patch
@@ -0,0 +1,38 @@
+diff -up open-iscsi-2.0-870.1/libiscsi/pylibiscsi.c~ open-iscsi-2.0-870.1/libiscsi/pylibiscsi.c
+--- open-iscsi-2.0-870.1/libiscsi/pylibiscsi.c~ 2009-02-12 15:30:52.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/pylibiscsi.c 2009-02-12 15:48:30.000000000 +0100
+@@ -485,19 +485,28 @@ static PyObject *pylibiscsi_discover_sen
+ char *kwlist[] = {"address", "port", "authinfo", NULL};
+ const char *address = NULL;
+ int i, nr_found, port = 3260;
+- PyIscsiChapAuthInfo *pyauthinfo = NULL;
++ 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!",
++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO",
+ kwlist, &address, &port,
+- &PyIscsiChapAuthInfo_Type,
+- &pyauthinfo))
++ &authinfo_arg))
+ return NULL;
+
+- if (pyauthinfo)
+- authinfo = &pyauthinfo->info;
++ 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)) {
diff --git a/open-iscsi-2.0-870.1-490515-workaround.patch b/open-iscsi-2.0-870.1-490515-workaround.patch
new file mode 100644
index 0000000..970461d
--- /dev/null
+++ b/open-iscsi-2.0-870.1-490515-workaround.patch
@@ -0,0 +1,45 @@
+diff -up open-iscsi-2.0-870.1/include/fw_context.h.workaround open-iscsi-2.0-870.1/include/fw_context.h
+--- open-iscsi-2.0-870.1/include/fw_context.h.workaround 2009-03-20 15:47:16.000000000 +0100
++++ open-iscsi-2.0-870.1/include/fw_context.h 2009-03-20 15:48:03.000000000 +0100
+@@ -51,5 +51,7 @@ struct boot_context {
+
+ extern int fw_get_entry(struct boot_context *context, const char *filepath);
+ extern void fw_print_entry(struct boot_context *context);
++extern int fwparam_ibft_sysfs(struct boot_context *context,
++ const char *filepath);
+
+ #endif /* FWPARAM_CONTEXT_H_ */
+diff -up open-iscsi-2.0-870.1/libiscsi/libiscsi.c.workaround open-iscsi-2.0-870.1/libiscsi/libiscsi.c
+--- open-iscsi-2.0-870.1/libiscsi/libiscsi.c.workaround 2009-03-20 15:45:28.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/libiscsi.c 2009-03-20 15:47:03.000000000 +0100
+@@ -196,10 +196,10 @@ int libiscsi_discover_firmware(struct li
+ *found_nodes = NULL;
+
+ memset(&fw_entry, 0, sizeof fw_entry);
+- rc = fw_get_entry(&fw_entry, NULL);
++ rc = fwparam_ibft_sysfs(&fw_entry, NULL);
+ if (rc) {
+ strcpy(context->error_str, "Could not read fw values.");
+- return rc;
++ return ENODEV;
+ }
+
+ memset(&rec, 0, sizeof rec);
+@@ -535,7 +535,7 @@ int libiscsi_get_firmware_network_config
+
+ memset(config, 0, sizeof *config);
+ memset(&fw_entry, 0, sizeof fw_entry);
+- if (fw_get_entry(&fw_entry, NULL))
++ if (fwparam_ibft_sysfs(&fw_entry, NULL))
+ return ENODEV;
+
+ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0;
+@@ -557,7 +557,7 @@ int libiscsi_get_firmware_initiator_name
+
+ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN);
+ memset(&fw_entry, 0, sizeof fw_entry);
+- if (fw_get_entry(&fw_entry, NULL))
++ if (fwparam_ibft_sysfs(&fw_entry, NULL))
+ return ENODEV;
+
+ strncpy(initiatorname, fw_entry.initiatorname,
diff --git a/open-iscsi-2.0-870.1-add-libiscsi.patch b/open-iscsi-2.0-870.1-add-libiscsi.patch
new file mode 100644
index 0000000..0bc4628
--- /dev/null
+++ b/open-iscsi-2.0-870.1-add-libiscsi.patch
@@ -0,0 +1,3974 @@
+diff -urN open-iscsi-2.0-870.1.orig/libiscsi/Makefile open-iscsi-2.0-870.1/libiscsi/Makefile
+--- open-iscsi-2.0-870.1.orig/libiscsi/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/Makefile 2009-01-28 14:28:54.000000000 +0100
+@@ -0,0 +1,54 @@
++# This Makefile will work only with GNU make.
++
++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
++
++# sources shared between iscsid, iscsiadm and iscsistart
++ISCSI_LIB_SRCS = util.o io.o auth.o login.o log.o md5.o sha1.o iface.o idbm.o sysdeps.o sysfs.o iscsi_sysfs.o
++FW_PARAM_SRCS = fwparam_ibft.o fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_ibft_sysfs.o
++
++# sources shared with the userspace utils, note we build these separately
++# to get PIC versions.
++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o \
++discovery.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)
++
++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): $(USR_OBJS) $(FW_OBJS) libiscsi.o
++ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@
++ ln -s -f $(LIB) libiscsi.so
++
++$(TESTS): $(USR_OBJS) $(LIB)
++
++html: libiscsi.h libiscsi.doxy
++ doxygen libiscsi.doxy
++
++clean:
++ rm -rf *.o usr-objs fw-objs libiscsi.so* .depend *~ html $(TESTS) tests/*~
++
++depend:
++ gcc $(CFLAGS) -M `ls *.c` > .depend
++
++-include .depend ../usr/.depend
+diff -urN open-iscsi-2.0-870.1.orig/libiscsi/libiscsi.c open-iscsi-2.0-870.1/libiscsi/libiscsi.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/libiscsi.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/libiscsi.c 2009-01-28 14:22:55.000000000 +0100
+@@ -0,0 +1,567 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <sys/syslog.h>
++#include "libiscsi.h"
++#include "idbm.h"
++#include "iscsiadm.h"
++#include "log.h"
++#include "sysfs.h"
++#include "iscsi_sysfs.h"
++#include "util.h"
++#include "sysdeps.h"
++#include "iface.h"
++#include "iscsi_proto.h"
++#include "fw_context.h"
++
++#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; }
++
++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);
++ sysfs_init();
++ 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_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(new_rec_list);
++ LIST_HEAD(bound_rec_list);
++ struct node_rec *rec;
++ int rc = 0, found = 0;
++
++ INIT_LIST_HEAD(&new_rec_list);
++ 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(discovery_sendtargets(&drec, &new_rec_list))
++ CHECK(idbm_add_discovery(&drec, 1 /* overwrite existing records */))
++
++ /* bind ifaces to node recs so we know what we have */
++ list_for_each_entry(rec, &new_rec_list, list)
++ CHECK(idbm_bind_ifaces_to_node(rec, 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;
++ found++;
++ }
++ }
++
++leave:
++ free_rec_list(&bound_rec_list);
++ free_rec_list(&new_rec_list);
++
++ return rc;
++}
++
++int libiscsi_discover_firmware(struct libiscsi_context *context,
++ int *nr_found, struct libiscsi_node **found_nodes)
++{
++ struct boot_context fw_entry;
++ struct node_rec rec;
++ int rc = 0;
++
++ if (nr_found)
++ *nr_found = 0;
++ if (found_nodes)
++ *found_nodes = NULL;
++
++ memset(&fw_entry, 0, sizeof fw_entry);
++ rc = fw_get_entry(&fw_entry, NULL);
++ if (rc) {
++ strcpy(context->error_str, "Could not read fw values.");
++ return rc;
++ }
++
++ memset(&rec, 0, sizeof rec);
++ idbm_node_setup_defaults(&rec);
++
++ strlcpy(rec.name, fw_entry.targetname, TARGET_NAME_MAXLEN);
++ rec.tpgt = 1;
++ strlcpy(rec.conn[0].address, fw_entry.target_ipaddr, NI_MAXHOST);
++ rec.conn[0].port = fw_entry.target_port;
++
++ iface_setup_defaults(&rec.iface);
++ strncpy(rec.iface.iname, fw_entry.initiatorname,
++ sizeof(fw_entry.initiatorname));
++ strncpy(rec.session.auth.username, fw_entry.chap_name,
++ sizeof(fw_entry.chap_name));
++ strncpy((char *)rec.session.auth.password, fw_entry.chap_password,
++ sizeof(fw_entry.chap_password));
++ strncpy(rec.session.auth.username_in, fw_entry.chap_name_in,
++ sizeof(fw_entry.chap_name_in));
++ strncpy((char *)rec.session.auth.password_in,
++ fw_entry.chap_password_in,
++ sizeof(fw_entry.chap_password_in));
++ rec.session.auth.password_length =
++ strlen((char *)fw_entry.chap_password);
++ rec.session.auth.password_in_length =
++ strlen((char *)fw_entry.chap_password_in);
++
++ CHECK(idbm_add_node(&rec, NULL, 1 /* overwrite */))
++
++ if (nr_found)
++ *nr_found = 1;
++
++ if (found_nodes) {
++ *found_nodes = calloc(1, sizeof **found_nodes);
++ if (*found_nodes == NULL) {
++ snprintf(context->error_str,
++ sizeof(context->error_str), strerror(ENOMEM));
++ rc = ENOMEM;
++ goto leave;
++ }
++ strlcpy((*found_nodes)[0].name, rec.name,
++ LIBISCSI_VALUE_MAXLEN);
++ (*found_nodes)[0].tpgt = rec.tpgt;
++ strlcpy((*found_nodes)[0].address,
++ rec.conn[0].address, NI_MAXHOST);
++ (*found_nodes)[0].port = rec.conn[0].port;
++ }
++
++leave:
++ 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)
++{
++ int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
++ if (rc) {
++ iscsid_handle_error(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, NULL, 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) {
++ iscsid_handle_error(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))
++ 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 db_set_param set_param = {
++ .name = (char *)parameter,
++ .value = (char *)value,
++ };
++
++ CHECK(idbm_for_each_iface(&nr_found, &set_param, 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;
++ }
++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;
++
++ memset(config, 0, sizeof *config);
++ memset(&fw_entry, 0, sizeof fw_entry);
++ if (fw_get_entry(&fw_entry, NULL))
++ return ENODEV;
++
++ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0;
++ strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface);
++ strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac);
++ strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr);
++ strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask);
++ strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway);
++ strncpy(config->primary_dns, fw_entry.primary_dns,
++ sizeof fw_entry.primary_dns);
++ strncpy(config->secondary_dns, fw_entry.secondary_dns,
++ sizeof fw_entry.secondary_dns);
++ return 0;
++}
++
++int libiscsi_get_firmware_initiator_name(char *initiatorname)
++{
++ struct boot_context fw_entry;
++
++ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN);
++ memset(&fw_entry, 0, sizeof fw_entry);
++ if (fw_get_entry(&fw_entry, NULL))
++ return ENODEV;
++
++ strncpy(initiatorname, fw_entry.initiatorname,
++ sizeof fw_entry.initiatorname);
++
++ return 0;
++}
+diff -urN open-iscsi-2.0-870.1.orig/libiscsi/libiscsi.doxy open-iscsi-2.0-870.1/libiscsi/libiscsi.doxy
+--- open-iscsi-2.0-870.1.orig/libiscsi/libiscsi.doxy 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/libiscsi.doxy 2009-01-28 10:26:36.000000000 +0100
+@@ -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 <command> <input-file>, where <command> is the value of
++# the FILE_VERSION_FILTER tag, and <input-file> 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 <filter> <input-file>, where <filter>
++# is the value of the INPUT_FILTER tag, and <input-file> 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 =
++
++# 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
++# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
++
++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
++# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
++
++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 -urN open-iscsi-2.0-870.1.orig/libiscsi/libiscsi.h open-iscsi-2.0-870.1/libiscsi/libiscsi.h
+--- open-iscsi-2.0-870.1.orig/libiscsi/libiscsi.h 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/libiscsi.h 2009-01-28 14:16:19.000000000 +0100
+@@ -0,0 +1,343 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <netdb.h>
++
++#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. */;
++};
++
++/** \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 -urN open-iscsi-2.0-870.1.orig/libiscsi/pylibiscsi.c open-iscsi-2.0-870.1/libiscsi/pylibiscsi.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/pylibiscsi.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/pylibiscsi.c 2009-01-28 14:49:03.000000000 +0100
+@@ -0,0 +1,615 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <Python.h>
++#include "libiscsi.h"
++
++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 PyString_FromString(chap->info.chap.username);
++ } else if (!strcmp(attr, "password")) {
++ return PyString_FromString(chap->info.chap.password);
++ } else if (!strcmp(attr, "reverse_username")) {
++ return PyString_FromString(chap->info.chap.reverse_username);
++ } else if (!strcmp(attr, "reverse_password")) {
++ return PyString_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;
++}
++
++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 PyString_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 = {
++ PyObject_HEAD_INIT(NULL)
++ .tp_name = "libiscsi.chapAuthInfo",
++ .tp_basicsize = sizeof (PyIscsiChapAuthInfo),
++ .tp_getset = PyIscsiChapAuthInfo_getseters,
++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
++ Py_TPFLAGS_BASETYPE,
++ .tp_compare = (cmpfunc)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", NULL};
++ const char *name = NULL, *address = NULL;
++ int tpgt = -1, port = 3260;
++
++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isi:node.__init__",
++ kwlist, &name, &tpgt, &address, &port))
++ return -1;
++ if (address == NULL) {
++ PyErr_SetString(PyExc_ValueError, "address not set");
++ return -1;
++ }
++ if (check_string(name) || check_string(address))
++ return -1;
++
++ strcpy(node->node.name, name);
++ node->node.tpgt = tpgt;
++ strcpy(node->node.address, address);
++ node->node.port = port;
++
++ 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 PyString_FromString(node->node.name);
++ } else if (!strcmp(attr, "tpgt")) {
++ return PyInt_FromLong(node->node.tpgt);
++ } else if (!strcmp(attr, "address")) {
++ return PyString_FromString(node->node.address);
++ } else if (!strcmp(attr, "port")) {
++ return PyInt_FromLong(node->node.port);
++ }
++ 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;
++ }
++
++ 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;
++
++ return 0;
++}
++
++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 PyString_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"},
++ {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 = {
++ PyObject_HEAD_INIT(NULL)
++ .tp_name = "libiscsi.node",
++ .tp_basicsize = sizeof (PyIscsiNode),
++ .tp_getset = PyIscsiNode_getseters,
++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
++ Py_TPFLAGS_BASETYPE,
++ .tp_methods = PyIscsiNode_methods,
++ .tp_compare = (cmpfunc)PyIscsiNode_compare,
++ .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;
++ PyIscsiChapAuthInfo *pyauthinfo = 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,
++ &PyIscsiChapAuthInfo_Type,
++ &pyauthinfo))
++ return NULL;
++
++ if (pyauthinfo)
++ authinfo = &pyauthinfo->info;
++
++ 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 PyString_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}
++};
++
++PyMODINIT_FUNC initlibiscsi(void)
++{
++ PyObject *m;
++
++ if (!context) /* We may be called more then once */
++ context = libiscsi_init();
++ if (!context)
++ return;
++
++ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0)
++ return;
++
++ if (PyType_Ready(&PyIscsiNode_Type) < 0)
++ return;
++
++ m = Py_InitModule("libiscsi", pylibiscsi_functions);
++ Py_INCREF(&PyIscsiChapAuthInfo_Type);
++ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type);
++ Py_INCREF(&PyIscsiNode_Type);
++ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type);
++}
+diff -urN open-iscsi-2.0-870.1.orig/libiscsi/setup.py open-iscsi-2.0-870.1/libiscsi/setup.py
+--- open-iscsi-2.0-870.1.orig/libiscsi/setup.py 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/setup.py 2009-01-28 10:26:36.000000000 +0100
+@@ -0,0 +1,9 @@
++from distutils.core import setup, Extension
++
++module1 = Extension('libiscsimodule',
++ sources = ['pylibiscsi.c'],
++ libraries = ['iscsi'],
++ library_dirs = ['.'])
++
++setup (name = 'PyIscsi',version = '1.0',
++ description = 'libiscsi python bindings', ext_modules = [module1])
+diff -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_discovery_firmware.c open-iscsi-2.0-870.1/libiscsi/tests/test_discovery_firmware.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_discovery_firmware.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_discovery_firmware.c 2009-01-28 10:26:36.000000000 +0100
+@@ -0,0 +1,53 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_discovery_sendtargets.c open-iscsi-2.0-870.1/libiscsi/tests/test_discovery_sendtargets.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_discovery_sendtargets.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_discovery_sendtargets.c 2009-01-28 10:26:36.000000000 +0100
+@@ -0,0 +1,60 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_get_auth.c open-iscsi-2.0-870.1/libiscsi/tests/test_get_auth.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_get_auth.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_get_auth.c 2009-01-28 14:30:25.000000000 +0100
+@@ -0,0 +1,70 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_get_initiator_name.c open-iscsi-2.0-870.1/libiscsi/tests/test_get_initiator_name.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_get_initiator_name.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_get_initiator_name.c 2009-01-28 10:26:36.000000000 +0100
+@@ -0,0 +1,38 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_get_network_config.c open-iscsi-2.0-870.1/libiscsi/tests/test_get_network_config.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_get_network_config.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_get_network_config.c 2009-01-28 10:26:36.000000000 +0100
+@@ -0,0 +1,45 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_login.c open-iscsi-2.0-870.1/libiscsi/tests/test_login.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_login.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_login.c 2009-01-28 14:29:13.000000000 +0100
+@@ -0,0 +1,52 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_logout.c open-iscsi-2.0-870.1/libiscsi/tests/test_logout.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_logout.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_logout.c 2009-01-28 10:26:36.000000000 +0100
+@@ -0,0 +1,51 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_params.c open-iscsi-2.0-870.1/libiscsi/tests/test_params.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_params.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_params.c 2009-01-28 10:26:36.000000000 +0100
+@@ -0,0 +1,103 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_set_auth.c open-iscsi-2.0-870.1/libiscsi/tests/test_set_auth.c
+--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_set_auth.c 1970-01-01 01:00:00.000000000 +0100
++++ open-iscsi-2.0-870.1/libiscsi/tests/test_set_auth.c 2009-01-28 14:28:38.000000000 +0100
+@@ -0,0 +1,58 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 -urN open-iscsi-2.0-870.1.orig/usr/idbm.c open-iscsi-2.0-870.1/usr/idbm.c
+--- open-iscsi-2.0-870.1.orig/usr/idbm.c 2009-01-27 21:43:15.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/idbm.c 2009-01-28 13:42:37.000000000 +0100
+@@ -37,6 +37,7 @@
+ #include "transport.h"
+ #include "iscsi_sysfs.h"
+ #include "iface.h"
++#include "sysdeps.h"
+
+ #define IDBM_HIDE 0 /* Hide parameter when print. */
+ #define IDBM_SHOW 1 /* Show parameter when print. */
+@@ -252,7 +253,7 @@
+ }
+ }
+
+-static void
++void
+ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
+ {
+ int num = 0, i;
+@@ -545,6 +546,9 @@
+ "unknown value format '%s' for "
+ "parameter name '%s'",
+ line_number, value, name);
++ } else {
++ log_error("unknown value format '%s' for "
++ "parameter name '%s'", value, name);
+ }
+ break;
+ }
+@@ -553,6 +557,8 @@
+ return 1;
+
+ updated:
++ strlcpy((char*)info[i].value, value, VALUE_MAXVAL);
++
+ #define check_password_param(_param) \
+ if (!passwd_done && !strcmp(#_param, name)) { \
+ passwd_done = 1; \
+@@ -1179,7 +1185,7 @@
+ * This iterates over the ifaces in use in the nodes dir.
+ * It does not iterate over the ifaces setup in /etc/iscsi/ifaces.
+ */
+-static int idbm_for_each_iface(int *found, void *data,
++int idbm_for_each_iface(int *found, void *data,
+ idbm_iface_op_fn *fn,
+ char *targetname, int tpgt, char *ip, int port)
+ {
+@@ -1223,6 +1229,7 @@
+
+ iface_dirfd = opendir(portal);
+ if (!iface_dirfd) {
++ log_error("iface iter could not read dir %s.", portal);
+ rc = errno;
+ goto free_portal;
+ }
+diff -urN open-iscsi-2.0-870.1.orig/usr/idbm.h open-iscsi-2.0-870.1/usr/idbm.h
+--- open-iscsi-2.0-870.1.orig/usr/idbm.h 2009-01-27 21:43:16.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/idbm.h 2009-01-28 10:26:36.000000000 +0100
+@@ -92,6 +92,9 @@
+ 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,
+@@ -143,6 +146,7 @@
+ extern int idbm_verify_param(recinfo_t *info, char *name);
+ extern int idbm_rec_update_param(recinfo_t *info, char *name, char *value,
+ int line_number);
++extern void idbm_recinfo_node(node_rec_t *r, recinfo_t *ri);
+
+ enum {
+ IDBM_PRINT_TYPE_DISCOVERY,
+diff -urN open-iscsi-2.0-870.1.orig/usr/iscsiadm.c open-iscsi-2.0-870.1/usr/iscsiadm.c
+--- open-iscsi-2.0-870.1.orig/usr/iscsiadm.c 2009-01-27 21:43:16.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/iscsiadm.c 2009-01-28 10:26:36.000000000 +0100
+@@ -2017,9 +2017,8 @@
+
+ umask(0177);
+
+- /* enable stdout logging */
+- log_daemon = 0;
+- log_init(program_name, 1024);
++ /* enable stderr logging */
++ log_init(program_name, 1024, log_do_log_stderr, NULL);
+ sysfs_init();
+
+ optopt = 0;
+diff -urN open-iscsi-2.0-870.1.orig/usr/iscsid.c open-iscsi-2.0-870.1/usr/iscsid.c
+--- open-iscsi-2.0-870.1.orig/usr/iscsid.c 2009-01-27 21:43:16.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/iscsid.c 2009-01-28 10:26:36.000000000 +0100
+@@ -48,7 +48,8 @@
+
+ static char program_name[] = "iscsid";
+ int control_fd, mgmt_ipc_fd;
+-static pid_t log_pid;
++static pid_t log_pid = -1;
++static int daemonize = 1;
+
+ extern char sysfs_file[];
+
+@@ -276,7 +277,7 @@
+ static void iscsid_shutdown(void)
+ {
+ log_warning("iscsid shutting down.");
+- if (log_daemon && log_pid >= 0) {
++ if (daemonize && log_pid >= 0) {
+ log_debug(1, "daemon stopping");
+ log_close(log_pid);
+ fprintf(stderr, "done done\n");
+@@ -342,7 +343,7 @@
+ initiatorname_file = optarg;
+ break;
+ case 'f':
+- log_daemon = 0;
++ daemonize = 0;
+ break;
+ case 'd':
+ log_level = atoi(optarg);
+@@ -370,7 +371,8 @@
+ }
+
+ /* initialize logger */
+- log_pid = log_init(program_name, DEFAULT_AREA_SIZE);
++ log_pid = log_init(program_name, DEFAULT_AREA_SIZE,
++ daemonize ? log_do_log_daemon : log_do_log_stderr, NULL);
+ if (log_pid < 0)
+ exit(1);
+
+@@ -402,7 +404,7 @@
+ exit(1);
+ }
+
+- if (log_daemon) {
++ if (daemonize) {
+ char buf[64];
+ int fd;
+
+diff -urN open-iscsi-2.0-870.1.orig/usr/iscsistart.c open-iscsi-2.0-870.1/usr/iscsistart.c
+--- open-iscsi-2.0-870.1.orig/usr/iscsistart.c 2009-01-27 21:43:16.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/iscsistart.c 2009-01-28 10:26:36.000000000 +0100
+@@ -311,8 +311,7 @@
+ }
+
+ /* initialize logger */
+- log_daemon = 0;
+- log_init(program_name, DEFAULT_AREA_SIZE);
++ log_init(program_name, DEFAULT_AREA_SIZE, log_do_log_stderr, NULL);
+
+ sysfs_init();
+ if (iscsi_sysfs_check_class_version())
+diff -urN open-iscsi-2.0-870.1.orig/usr/log.c open-iscsi-2.0-870.1/usr/log.c
+--- open-iscsi-2.0-870.1.orig/usr/log.c 2008-11-22 18:06:46.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/log.c 2009-01-28 10:26:36.000000000 +0100
+@@ -32,10 +32,11 @@
+ #endif
+
+ char *log_name;
+-int log_daemon = 1;
+ int log_level = 0;
+
+ static int log_stop_daemon = 0;
++static void (*log_func)(int prio, void *priv, const char *fmt, va_list ap);
++static void *log_func_priv;
+
+ static void free_logarea (void)
+ {
+@@ -258,35 +259,34 @@
+ syslog(msg->prio, "%s", (char *)&msg->str);
+ }
+
+-static void dolog(int prio, const char *fmt, va_list ap)
++void log_do_log_daemon(int prio, void *priv, const char *fmt, va_list ap)
+ {
+- if (log_daemon) {
+- la->ops[0].sem_op = -1;
+- if (semop(la->semid, la->ops, 1) < 0) {
+- syslog(LOG_ERR, "semop up failed %d", errno);
+- return;
+- }
++ la->ops[0].sem_op = -1;
++ if (semop(la->semid, la->ops, 1) < 0) {
++ syslog(LOG_ERR, "semop up failed %d", errno);
++ return;
++ }
+
+- log_enqueue(prio, fmt, ap);
++ log_enqueue(prio, fmt, ap);
+
+- la->ops[0].sem_op = 1;
+- if (semop(la->semid, la->ops, 1) < 0) {
+- syslog(LOG_ERR, "semop down failed");
+- return;
+- }
+- } else {
+- fprintf(stderr, "%s: ", log_name);
+- vfprintf(stderr, fmt, ap);
+- fprintf(stderr, "\n");
+- fflush(stderr);
+- }
++ la->ops[0].sem_op = 1;
++ if (semop(la->semid, la->ops, 1) < 0)
++ syslog(LOG_ERR, "semop down failed");
++}
++
++void log_do_log_stderr(int prio, void *priv, const char *fmt, va_list ap)
++{
++ fprintf(stderr, "%s: ", log_name);
++ vfprintf(stderr, fmt, ap);
++ fprintf(stderr, "\n");
++ fflush(stderr);
+ }
+
+ void log_warning(const char *fmt, ...)
+ {
+ va_list ap;
+ va_start(ap, fmt);
+- dolog(LOG_WARNING, fmt, ap);
++ log_func(LOG_WARNING, log_func_priv, fmt, ap);
+ va_end(ap);
+ }
+
+@@ -294,7 +294,7 @@
+ {
+ va_list ap;
+ va_start(ap, fmt);
+- dolog(LOG_ERR, fmt, ap);
++ log_func(LOG_ERR, log_func_priv, fmt, ap);
+ va_end(ap);
+ }
+
+@@ -303,7 +303,7 @@
+ if (log_level > level) {
+ va_list ap;
+ va_start(ap, fmt);
+- dolog(LOG_DEBUG, fmt, ap);
++ log_func(LOG_DEBUG, log_func_priv, fmt, ap);
+ va_end(ap);
+ }
+ }
+@@ -379,19 +379,23 @@
+
+ static void __log_close(void)
+ {
+- if (log_daemon) {
++ if (log_func == log_do_log_daemon) {
+ log_flush();
+ closelog();
+ free_logarea();
+ }
+ }
+
+-int log_init(char *program_name, int size)
++int log_init(char *program_name, int size,
++ void (*func)(int prio, void *priv, const char *fmt, va_list ap),
++ void *priv)
+ {
+ logdbg(stderr,"enter log_init\n");
+ log_name = program_name;
++ log_func = func;
++ log_func_priv = priv;
+
+- if (log_daemon) {
++ if (log_func == log_do_log_daemon) {
+ struct sigaction sa_old;
+ struct sigaction sa_new;
+ pid_t pid;
+@@ -437,11 +441,12 @@
+
+ return 0;
+ }
++
+ void log_close(pid_t pid)
+ {
+ int status;
+
+- if (!log_daemon || pid < 0) {
++ if (log_func != log_do_log_daemon || pid < 0) {
+ __log_close();
+ return;
+ }
+diff -urN open-iscsi-2.0-870.1.orig/usr/log.h open-iscsi-2.0-870.1/usr/log.h
+--- open-iscsi-2.0-870.1.orig/usr/log.h 2008-11-22 18:06:46.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/log.h 2009-01-28 10:26:36.000000000 +0100
+@@ -26,6 +26,7 @@
+ #ifndef LOG_H
+ #define LOG_H
+
++#include <stdarg.h>
+ #include "iscsid.h"
+
+ #if defined(Linux)
+@@ -41,7 +42,6 @@
+ #define DEFAULT_AREA_SIZE 16384
+ #define MAX_MSG_SIZE 256
+
+-extern int log_daemon;
+ extern int log_level;
+
+ struct logmsg {
+@@ -67,7 +67,9 @@
+
+ struct logarea *la;
+
+-extern int log_init (char * progname, int size);
++extern int log_init(char *program_name, int size,
++ void (*func)(int prio, void *priv, const char *fmt, va_list ap),
++ void *priv);
+ extern void log_close (pid_t pid);
+ extern void dump_logmsg (void *);
+ extern void log_warning(const char *fmt, ...)
+@@ -77,4 +79,7 @@
+ extern void log_debug(int level, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
++extern void log_do_log_daemon(int prio, void *priv, const char *fmt, va_list ap);
++extern void log_do_log_stderr(int prio, void *priv, const char *fmt, va_list ap);
++
+ #endif /* LOG_H */
diff --git a/open-iscsi-2.0-870.1-ibft-newer-kernel.patch b/open-iscsi-2.0-870.1-ibft-newer-kernel.patch
new file mode 100644
index 0000000..4c54e04
--- /dev/null
+++ b/open-iscsi-2.0-870.1-ibft-newer-kernel.patch
@@ -0,0 +1,44 @@
+diff -up open-iscsi-2.0-870.1/utils/fwparam_ibft/fwparam_ibft_sysfs.c~ open-iscsi-2.0-870.1/utils/fwparam_ibft/fwparam_ibft_sysfs.c
+--- open-iscsi-2.0-870.1/utils/fwparam_ibft/fwparam_ibft_sysfs.c~ 2009-01-28 22:09:21.000000000 +0100
++++ open-iscsi-2.0-870.1/utils/fwparam_ibft/fwparam_ibft_sysfs.c 2009-01-28 22:10:29.000000000 +0100
+@@ -186,6 +186,40 @@ static int get_iface_from_device(const c
+ break;
+ }
+
++ closedir(dirfd);
++
++ if (rc != ENODEV)
++ return rc;
++
++ /* If not found try again with newer kernel networkdev sysfs layout */
++ strncat(dev_dir, "/net", FILENAMESZ);
++
++ if (!file_exist(dev_dir))
++ return rc;
++
++ dirfd = opendir(dev_dir);
++ if (!dirfd)
++ return errno;
++
++ while ((dent = readdir(dirfd))) {
++ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
++ continue;
++
++ /* Take the first "regular" directory entry */
++ if (strlen(dent->d_name) > (sizeof(context->iface) - 1)) {
++ rc = EINVAL;
++ printf("Net device %s too bug for iface buffer.\n",
++ dent->d_name);
++ break;
++ }
++
++ strcpy(context->iface, dent->d_name);
++ rc = 0;
++ break;
++ }
++
++ closedir(dirfd);
++
+ return rc;
+ }
+
diff --git a/open-iscsi-2.0-870.1-no-exit.patch b/open-iscsi-2.0-870.1-no-exit.patch
new file mode 100644
index 0000000..2db2384
--- /dev/null
+++ b/open-iscsi-2.0-870.1-no-exit.patch
@@ -0,0 +1,221 @@
+--- open-iscsi-2.0-870.1/usr/idbm.c~ 2009-01-28 13:23:47.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/idbm.c 2009-01-28 13:25:06.000000000 +0100
+@@ -843,7 +843,7 @@ int idbm_lock(void)
+ if (access(LOCK_DIR, F_OK) != 0) {
+ if (mkdir(LOCK_DIR, 0660) != 0) {
+ log_error("Could not open %s. Exiting\n", LOCK_DIR);
+- exit(-1);
++ return errno;
+ }
+ }
+
+@@ -857,10 +857,10 @@ int idbm_lock(void)
+ break;
+
+ if (errno != EEXIST) {
++ log_error("Maybe you are not root?");
+ log_error("Could not lock discovery DB: %s: %s",
+ LOCK_WRITE_FILE, strerror(errno));
+- log_error("Maybe you are not root?");
+- exit(-1);
++ return errno;
+ } else if (i == 0)
+ log_debug(2, "Waiting for discovery DB lock");
+
+@@ -915,7 +915,10 @@ static int __idbm_rec_read(node_rec_t *o
+ if (!info)
+ return ENOMEM;
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto free_info;
++
+ f = fopen(conf, "r");
+ if (!f) {
+ log_debug(5, "Could not open %s err %d\n", conf, errno);
+@@ -931,6 +934,7 @@ static int __idbm_rec_read(node_rec_t *o
+
+ unlock:
+ idbm_unlock();
++free_info:
+ free(info);
+ return rc;
+ }
+@@ -1386,14 +1390,18 @@ idbm_discovery_read(discovery_rec_t *out
+ return ENOMEM;
+
+ portal = malloc(PATH_MAX);
+- if (!portal)
++ if (!portal) {
++ rc = ENOMEM;
+ goto free_info;
++ }
+
+ snprintf(portal, PATH_MAX, "%s/%s,%d", ST_CONFIG_DIR,
+ addr, port);
+ log_debug(5, "Looking for config file %s\n", portal);
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto free_info;
+
+ f = idbm_open_rec_r(portal, ST_CONFIG_NAME);
+ if (!f) {
+@@ -1494,7 +1502,9 @@ static int idbm_rec_write(node_rec_t *re
+ rec->name, rec->conn[0].address, rec->conn[0].port);
+ log_debug(5, "Looking for config file %s", portal);
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto free_portal;
+
+ rc = stat(portal, &statb);
+ if (rc) {
+@@ -1579,13 +1589,16 @@ idbm_discovery_write(discovery_rec_t *re
+ return ENOMEM;
+ }
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto free_portal;
++
+ snprintf(portal, PATH_MAX, "%s", ST_CONFIG_DIR);
+ if (access(portal, F_OK) != 0) {
+ if (mkdir(portal, 0660) != 0) {
+ log_error("Could not make %s\n", portal);
+ rc = errno;
+- goto free_portal;
++ goto unlock;
+ }
+ }
+
+@@ -1596,13 +1609,14 @@ idbm_discovery_write(discovery_rec_t *re
+ if (!f) {
+ log_error("Could not open %s err %d\n", portal, errno);
+ rc = errno;
+- goto free_portal;
++ goto unlock;
+ }
+
+ idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, 1, f);
+ fclose(f);
+-free_portal:
++unlock:
+ idbm_unlock();
++free_portal:
+ free(portal);
+ return rc;
+ }
+@@ -1722,7 +1736,10 @@ int idbm_add_node(node_rec_t *newrec, di
+ log_debug(7, "node addition making link from %s to %s", node_portal,
+ disc_portal);
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto free_portal;
++
+ if (symlink(node_portal, disc_portal)) {
+ if (errno == EEXIST)
+ log_debug(7, "link from %s to %s exists", node_portal,
+@@ -2009,7 +2026,10 @@ static int idbm_remove_disc_to_node_link
+ if (rc)
+ goto done;
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto done;
++
+ if (!stat(portal, &statb)) {
+ if (unlink(portal)) {
+ log_error("Could not remove link %s err %d\n",
+@@ -2046,7 +2066,10 @@ int idbm_delete_node(node_rec_t *rec)
+ log_debug(5, "Removing config file %s iface id %s\n",
+ portal, rec->iface.name);
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto free_portal;
++
+ if (!stat(portal, &statb))
+ goto rm_conf;
+
+diff -up open-iscsi-2.0-870.1/usr/iface.c~ open-iscsi-2.0-870.1/usr/iface.c
+--- open-iscsi-2.0-870.1/usr/iface.c~ 2009-01-28 13:29:31.000000000 +0100
++++ open-iscsi-2.0-870.1/usr/iface.c 2009-01-28 13:29:31.000000000 +0100
+@@ -208,7 +208,10 @@ int iface_conf_read(struct iface_rec *if
+ return 0;
+ }
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ return rc;
++
+ rc = __iface_conf_read(iface);
+ idbm_unlock();
+ return rc;
+@@ -232,11 +235,15 @@ int iface_conf_delete(struct iface_rec *
+ return ENOMEM;
+
+ sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name);
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto free_conf;
++
+ if (unlink(iface_conf))
+ rc = errno;
+ idbm_unlock();
+
++free_conf:
+ free(iface_conf);
+ return rc;
+ }
+@@ -267,10 +274,14 @@ int iface_conf_write(struct iface_rec *i
+ goto free_conf;
+ }
+
+- idbm_lock();
++ rc = idbm_lock();
++ if (rc)
++ goto close_f;
++
+ idbm_print(IDBM_PRINT_TYPE_IFACE, iface, 1, f);
+ idbm_unlock();
+
++close_f:
+ fclose(f);
+ free_conf:
+ free(iface_conf);
+@@ -471,7 +482,9 @@ void iface_setup_host_bindings(void)
+ {
+ int nr_found = 0;
+
+- idbm_lock();
++ if (idbm_lock())
++ return;
++
+ if (access(IFACE_CONFIG_DIR, F_OK) != 0) {
+ if (mkdir(IFACE_CONFIG_DIR, 0660) != 0) {
+ log_error("Could not make %s. HW/OFFLOAD iscsi "
+@@ -658,7 +671,12 @@ int iface_for_each_iface(void *data, int
+ continue;
+ }
+
+- idbm_lock();
++ err = idbm_lock();
++ if (err) {
++ free(iface);
++ continue;
++ }
++
+ err = __iface_conf_read(iface);
+ idbm_unlock();
+ if (err) {
diff --git a/sources b/sources
index 1055d7d..4d9c3cb 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-2e7ce941ea4e4eda7c82f0b272a33bf9 open-iscsi-2.0-754.tar.gz
+3b7e273ad2696899df2b8e5622fdeb2c open-iscsi-2.0-870.1.tar.gz
More information about the scm-commits
mailing list