[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,
++					 &parameter, &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, &parameter))
++		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