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-add-iscsi-iname.patch b/iscsi-initiator-utils-add-iscsi-iname.patch deleted file mode 100644 index cfe2215..0000000 --- a/iscsi-initiator-utils-add-iscsi-iname.patch +++ /dev/null @@ -1,470 +0,0 @@ -diff -Naurp open-iscsi/Makefile open-iscsi-5.0.5.595/Makefile ---- open-iscsi/Makefile 2006-05-30 01:51:42.000000000 -0500 -+++ open-iscsi-5.0.5.595/Makefile 2006-05-30 02:29:46.000000000 -0500 -@@ -26,6 +26,7 @@ ETCFILES = etc/iscsid.conf - all: - $(MAKE) -C usr - $(MAKE) -C kernel -+ $(MAKE) -C utils - @echo - @echo "Compilation complete Output file" - @echo "----------------------------------- ----------------" -@@ -38,6 +39,7 @@ all: - @echo Read README file for detailed information. - - clean: -+ $(MAKE) -C utils clean - $(MAKE) -C usr clean - $(MAKE) -C kernel clean - -diff -Naurp open-iscsi/utils/iscsi-iname.c open-iscsi-5.0.5.595/utils/iscsi-iname.c ---- open-iscsi/utils/iscsi-iname.c 1969-12-31 18:00:00.000000000 -0600 -+++ open-iscsi-5.0.5.595/utils/iscsi-iname.c 2006-05-30 02:28:34.000000000 -0500 -@@ -0,0 +1,140 @@ -+/* -+ * iSCSI InitiatorName creation utility -+ * Copyright (C) 2001 Cisco Systems, Inc. -+ * maintained by linux-iscsi-devel@lists.sourceforge.net -+ * -+ * 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. -+ * -+ * $Id: iscsi-iname.c,v 1.1.2.3 2005/03/15 06:33:44 wysochanski Exp $ -+ * -+ * iscsi-iname.c - Compute an iSCSI InitiatorName for this host. -+ * Note that to ensure uniqueness, the system time is -+ * a factor. This name must be cached and only regenerated -+ * if there is no cached value. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "md5.h" -+ -+#define RANDOM_NUM_GENERATOR "/dev/urandom" -+ -+int -+main(int argc, char *argv[]) -+{ -+ char iname[256]; -+ struct timeval time; -+ struct utsname system_info; -+ long hostid; -+ struct MD5Context context; -+ unsigned char digest[16]; -+ unsigned char *bytes = digest; -+ unsigned char entropy[16]; -+ int e; -+ int fd; -+ char *prefix; -+ -+ /* initialize */ -+ memset(iname, 0, sizeof (iname)); -+ memset(digest, 0, sizeof (digest)); -+ memset(&context, 0, sizeof (context)); -+ MD5Init(&context); -+ -+ /* take a prefix if given, otherwise use a default. */ -+ if (argc > 1 && argv[1]) { -+ prefix = argv[1]; -+ if (( strcmp(prefix, "-h") == 0 ) || -+ ( strcmp(prefix, "--help") == 0 )) { -+ printf("\nDisplays the iSCSI initiator name\n"); -+ exit(0); -+ } else if ( strcmp(prefix, "-p") == 0 ) { -+ prefix = argv[2]; -+ } else { -+ printf("\nUsage: iscsi-iname [-h | --help | " -+ "-p ]\n"); -+ exit(0); -+ } -+ } else { -+ prefix = "iqn.2005-03.com.redhat:01"; -+ } -+ -+ /* try to feed some entropy from the pool to MD5 in order to get -+ * uniqueness properties -+ */ -+ -+ if ((fd = open(RANDOM_NUM_GENERATOR, O_RDONLY))) { -+ e = read(fd, &entropy, 16); -+ if (e >= 1) -+ MD5Update(&context, (md5byte *)entropy, e); -+ close(fd); -+ } -+ -+ /* time the name is created is a factor in order to get -+ * uniqueness properties -+ */ -+ if (gettimeofday(&time, NULL) < 0) { -+ perror("error: gettimeofday failed"); -+ return 1; -+ } -+ MD5Update(&context, (md5byte *) & time.tv_sec, sizeof (time.tv_sec)); -+ MD5Update(&context, (md5byte *) & time.tv_usec, sizeof (time.tv_usec)); -+ -+ /* hostid */ -+ hostid = gethostid(); -+ MD5Update(&context, (md5byte *) & hostid, sizeof (hostid)); -+ -+ /* get the hostname and system name */ -+ if (uname(&system_info) < 0) { -+ perror("error: uname failed"); -+ return 1; -+ } -+ MD5Update(&context, (md5byte *) system_info.sysname, -+ sizeof (system_info.sysname)); -+ MD5Update(&context, (md5byte *) system_info.nodename, -+ sizeof (system_info.nodename)); -+ MD5Update(&context, (md5byte *) system_info.release, -+ sizeof (system_info.release)); -+ MD5Update(&context, (md5byte *) system_info.version, -+ sizeof (system_info.version)); -+ MD5Update(&context, (md5byte *) system_info.machine, -+ sizeof (system_info.machine)); -+ -+ /* compute the md5 hash of all the bits we just collected */ -+ MD5Final(digest, &context); -+ -+ /* vary which md5 bytes we pick (though we probably don't need to do -+ * this, since hopefully MD5 produces results such that each byte is as -+ * good as any other). -+ */ -+ -+ if ((fd = open(RANDOM_NUM_GENERATOR, O_RDONLY))) { -+ if (read(fd, entropy, 1) == 1) -+ bytes = &digest[(entropy[0] % (sizeof(digest) - 6))]; -+ close(fd); -+ } -+ -+ /* print the prefix followed by 6 bytes of the MD5 hash */ -+ sprintf(iname, "%s.%x%x%x%x%x%x", prefix, -+ bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]); -+ -+ iname[sizeof (iname) - 1] = '\0'; -+ printf("%s\n", iname); -+ return 0; -+} -diff -Naurp open-iscsi/utils/Makefile open-iscsi-5.0.5.595/utils/Makefile ---- open-iscsi/utils/Makefile 1969-12-31 18:00:00.000000000 -0600 -+++ open-iscsi-5.0.5.595/utils/Makefile 2006-05-30 02:28:34.000000000 -0500 -@@ -0,0 +1,12 @@ -+# This Makefile will work only with GNU make. -+ -+CFLAGS += $(OPTFLAGS) -O2 -fno-inline -Wall -Wstrict-prototypes -g -+PROGRAMS = iscsi-iname -+ -+all: $(PROGRAMS) -+ -+iscsi-iname: md5.o iscsi-iname.o -+ $(CC) $(CFLAGS) $^ $(DBM_LIB) -o $@ -+ -+clean: -+ rm -f *.o $(PROGRAMS) -diff -Naurp open-iscsi/utils/md5.c open-iscsi-5.0.5.595/utils/md5.c ---- open-iscsi/utils/md5.c 1969-12-31 18:00:00.000000000 -0600 -+++ open-iscsi-5.0.5.595/utils/md5.c 2006-05-30 02:28:34.000000000 -0500 -@@ -0,0 +1,242 @@ -+/* -+ * This code implements the MD5 message-digest algorithm. -+ * The algorithm is due to Ron Rivest. This code was -+ * written by Colin Plumb in 1993, no copyright is claimed. -+ * This code is in the public domain; do with it what you wish. -+ * -+ * Equivalent code is available from RSA Data Security, Inc. -+ * This code has been tested against that, and is equivalent, -+ * except that you don't need to include two pages of legalese -+ * with every copy. -+ * -+ * To compute the message digest of a chunk of bytes, declare an -+ * MD5Context structure, pass it to MD5Init, call MD5Update as -+ * needed on buffers full of bytes, and then call MD5Final, which -+ * will fill a supplied 16-byte array with the digest. -+ * -+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header -+ * definitions; now uses stuff from dpkg's config.h. -+ * - Ian Jackson . -+ * Still in the public domain. -+ */ -+ -+#include -+ -+#include "md5.h" -+ -+#if (__BYTE_ORDER == __BIG_ENDIAN) -+/* -+ * we can compile this away for little endian since -+ * it does not do anything on those archs -+ */ -+void -+byteSwap(uint32_t * buf, unsigned words) -+{ -+ md5byte *p = (md5byte *) buf; -+ -+ do { -+ *buf++ = (uint32_t) ((unsigned) p[3] << 8 | p[2]) << 16 | -+ ((unsigned) p[1] << 8 | p[0]); -+ p += 4; -+ } while (--words); -+} -+#else -+#define byteSwap(buf,words) -+#endif -+ -+/* -+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious -+ * initialization constants. -+ */ -+void -+MD5Init(struct MD5Context *ctx) -+{ -+ ctx->buf[0] = 0x67452301; -+ ctx->buf[1] = 0xefcdab89; -+ ctx->buf[2] = 0x98badcfe; -+ ctx->buf[3] = 0x10325476; -+ -+ ctx->bytes[0] = 0; -+ ctx->bytes[1] = 0; -+} -+ -+/* -+ * Update context to reflect the concatenation of another buffer full -+ * of bytes. -+ */ -+void -+MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) -+{ -+ uint32_t t; -+ -+ /* Update byte count */ -+ -+ t = ctx->bytes[0]; -+ if ((ctx->bytes[0] = t + len) < t) -+ ctx->bytes[1]++; /* Carry from low to high */ -+ -+ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ -+ if (t > len) { -+ memcpy((md5byte *) ctx->in + 64 - t, buf, len); -+ return; -+ } -+ /* First chunk is an odd size */ -+ memcpy((md5byte *) ctx->in + 64 - t, buf, t); -+ byteSwap(ctx->in, 16); -+ MD5Transform(ctx->buf, ctx->in); -+ buf += t; -+ len -= t; -+ -+ /* Process data in 64-byte chunks */ -+ while (len >= 64) { -+ memcpy(ctx->in, buf, 64); -+ byteSwap(ctx->in, 16); -+ MD5Transform(ctx->buf, ctx->in); -+ buf += 64; -+ len -= 64; -+ } -+ -+ /* Handle any remaining bytes of data. */ -+ memcpy(ctx->in, buf, len); -+} -+ -+/* -+ * Final wrapup - pad to 64-byte boundary with the bit pattern -+ * 1 0* (64-bit count of bits processed, MSB-first) -+ */ -+void -+MD5Final(md5byte digest[16], struct MD5Context *ctx) -+{ -+ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ -+ md5byte *p = (md5byte *) ctx->in + count; -+ -+ /* Set the first char of padding to 0x80. There is always room. */ -+ *p++ = 0x80; -+ -+ /* Bytes of padding needed to make 56 bytes (-8..55) */ -+ count = 56 - 1 - count; -+ -+ if (count < 0) { /* Padding forces an extra block */ -+ memset(p, 0, count + 8); -+ byteSwap(ctx->in, 16); -+ MD5Transform(ctx->buf, ctx->in); -+ p = (md5byte *) ctx->in; -+ count = 56; -+ } -+ memset(p, 0, count); -+ byteSwap(ctx->in, 14); -+ -+ /* Append length in bits and transform */ -+ ctx->in[14] = ctx->bytes[0] << 3; -+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; -+ MD5Transform(ctx->buf, ctx->in); -+ -+ byteSwap(ctx->buf, 4); -+ memcpy(digest, ctx->buf, 16); -+ memset(ctx, 0, sizeof (ctx)); /* In case it's sensitive */ -+} -+ -+#ifndef ASM_MD5 -+ -+/* The four core functions - F1 is optimized somewhat */ -+ -+/* #define F1(x, y, z) (x & y | ~x & z) */ -+#define F1(x, y, z) (z ^ (x & (y ^ z))) -+#define F2(x, y, z) F1(z, x, y) -+#define F3(x, y, z) (x ^ y ^ z) -+#define F4(x, y, z) (y ^ (x | ~z)) -+ -+/* This is the central step in the MD5 algorithm. */ -+#define MD5STEP(f,w,x,y,z,in,s) \ -+ (w += f(x,y,z) + in, w = (w<>(32-s)) + x) -+ -+/* -+ * The core of the MD5 algorithm, this alters an existing MD5 hash to -+ * reflect the addition of 16 longwords of new data. MD5Update blocks -+ * the data and converts bytes into longwords for this routine. -+ */ -+void -+MD5Transform(uint32_t buf[4], uint32_t const in[16]) -+{ -+ register uint32_t a, b, c, d; -+ -+ a = buf[0]; -+ b = buf[1]; -+ c = buf[2]; -+ d = buf[3]; -+ -+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); -+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); -+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); -+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); -+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); -+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); -+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); -+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); -+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); -+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); -+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); -+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); -+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); -+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); -+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); -+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); -+ -+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); -+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); -+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); -+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); -+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); -+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); -+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); -+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); -+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); -+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); -+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); -+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); -+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); -+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); -+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); -+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); -+ -+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); -+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); -+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); -+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); -+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); -+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); -+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); -+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); -+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); -+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); -+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); -+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); -+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); -+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); -+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); -+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); -+ -+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); -+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); -+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); -+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); -+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); -+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); -+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); -+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); -+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); -+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); -+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); -+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); -+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); -+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); -+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); -+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); -+ -+ buf[0] += a; -+ buf[1] += b; -+ buf[2] += c; -+ buf[3] += d; -+} -+ -+#endif -diff -Naurp open-iscsi/utils/md5.h open-iscsi-5.0.5.595/utils/md5.h ---- open-iscsi/utils/md5.h 1969-12-31 18:00:00.000000000 -0600 -+++ open-iscsi-5.0.5.595/utils/md5.h 2006-05-30 02:28:34.000000000 -0500 -@@ -0,0 +1,41 @@ -+/* -+ * This is the header file for the MD5 message-digest algorithm. -+ * The algorithm is due to Ron Rivest. This code was -+ * written by Colin Plumb in 1993, no copyright is claimed. -+ * This code is in the public domain; do with it what you wish. -+ * -+ * Equivalent code is available from RSA Data Security, Inc. -+ * This code has been tested against that, and is equivalent, -+ * except that you don't need to include two pages of legalese -+ * with every copy. -+ * -+ * To compute the message digest of a chunk of bytes, declare an -+ * MD5Context structure, pass it to MD5Init, call MD5Update as -+ * needed on buffers full of bytes, and then call MD5Final, which -+ * will fill a supplied 16-byte array with the digest. -+ * -+ * Changed so as no longer to depend on Colin Plumb's `usual.h' -+ * header definitions; now uses stuff from dpkg's config.h -+ * - Ian Jackson . -+ * Still in the public domain. -+ */ -+ -+#ifndef MD5_H -+#define MD5_H -+ -+#include -+ -+#define md5byte unsigned char -+ -+struct MD5Context { -+ uint32_t buf[4]; -+ uint32_t bytes[2]; -+ uint32_t in[16]; -+}; -+ -+void MD5Init(struct MD5Context *context); -+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); -+void MD5Final(unsigned char digest[16], struct MD5Context *context); -+void MD5Transform(uint32_t buf[4], uint32_t const in[16]); -+ -+#endif /* !MD5_H */ 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 ++ * ++ * 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 . ++ */ ++ ++#define _XOPEN_SOURCE 500 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "fwparam_ibft.h" ++#include ++ ++#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 + #include + #include +-#include "fwparam_ibft.h" ++#include + #include ++#include ++ ++#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 +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. - /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" +-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. - -- /etc/init.d/open-iscsi start -- --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: + 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: - modprobe -q iscsi_tcp +- service open-iscsi start ++ service iscsi start -@@ -358,8 +349,6 @@ storage), it is better to automate the l + 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. - 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 - ====== ++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 * +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. - idbm_lock(db); + .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. -- 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; - } + The database contains two tables: -+/* TODO: merged these two functions */ - static int - idbm_discovery_write(idbm_t *db, discovery_rec_t *rec) +-- 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 + +-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" +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 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" +-#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 -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 + +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} + %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 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 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 - 6.2.0.870-6 +- Add glibc-static to buildreq to build in F11 + +* Wed Feb 25 2009 Fedora Release Engineering - 6.2.0.870-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Thu Feb 12 2009 Hans de Goede 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 6.2.0.870-3 +- Fix reading of iBFT firmware with newer kernels + +* Wed Jan 28 2009 Hans de Goede 6.2.0.870-2 +- Add libiscsi iscsi administration library and -devel subpackage + +* Tue Nov 25 2008 Mike Christie 6.2.0.870-1.0 +- Rebase to upstream + +* Thu Nov 6 2008 Hans de Goede 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 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 - 6.2.0.870 +- Rebase to open-iscsi-2-870 +- 453282 Handle sysfs changes. + +* Fri Apr 25 2008 Mike Christie - 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 - 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 - 6.2.0.868-0.3 +- Rebase to upstream and RHEL5. +- 246960 LSB init script changes. + +* Fri Oct 5 2007 Mike Christie - 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 - 6.2.0.754-0.1 +- 225915 From Adrian Reber - Fix up spec and init files for rpmlint. + * Tue Feb 6 2007 Mike Christie - 6.2.0.754-0.0 - Rebase to upstream. - Add back --map functionality but in session mode to match RHEL5 fixes diff --git a/iscsi.init b/iscsi.init deleted file mode 100755 index defebf5..0000000 --- a/iscsi.init +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/sh -# -# chkconfig: 345 13 89 -# description: Starts and stops the iSCSI initiator -# -# processname: iscsid -# pidfile: /etc/iscsi/iscsid.pid -# config: /etc/iscsi/iscsid.conf - -# 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 initiator service: " - modprobe -q iscsi_tcp - modprobe -q ib_iser - daemon iscsid - RETVAL=$? - echo - [ $RETVAL -eq 0 ] || return - - touch /var/lock/subsys/iscsi - - echo -n $"Setting up iSCSI targets: " - TARGETS=`iscsiadm -m node 2>/dev/null | sed 's/ /@/g'` - for node in $TARGETS; do - target=`echo $node | cut -d@ -f2` - port=`echo $node | cut -d@ -f1` - STARTUP=`iscsiadm -m node -T $target -p $port | grep "node.conn\[0\].startup" | cut -d' ' -f3` - if [ "$STARTUP" = "automatic" ]; then - iscsiadm -m node -T $target -p $port -l - fi - done - success - echo - -} - -stop() -{ - echo -n $"Stopping iSCSI initiator service: " - sync -# TARGETS=`iscsiadm -m session | grep "\[*\]" | sed 's@\[\(.*\)\] .*@\1@g'` -# for rec in $TARGETS; do -# iscsiadm -m node -r $rec -u -# done - - killproc iscsid - echo - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/iscsi - - modprobe -r ib_iser 2>/dev/null - modprobe -r iscsi_tcp 2>/dev/null -} - -restart() -{ - stop - start -} - -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 -esac - -exit $RETVAL 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 +. /etc/rc.d/init.d/functions -PATH=/sbin:/bin:/usr/sbin:/usr/bin +exec=/sbin/iscsid +prog=iscsid +config=/etc/iscsi/iscsid.conf +lockfile=/var/lock/subsys/$prog -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 +# 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" ]] } -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 +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 } -restart() -{ - stop - start +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() { + 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 +} + +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 -PATH=/sbin:/bin:/usr/sbin:/usr/bin +exec="/sbin/iscsiadm" +prog="iscsi" +config="/etc/iscsi/initiatorname.iscsi" +lockfile=/var/lock/subsys/$prog +iscsid_lockfile=/var/lock/subsys/${prog}_iscsid -RETVAL=0 +start() { + [ -x $exec ] || exit 5 + [ -f $config ] || exit 6 -start() -{ + # 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 - status iscsid - RETVAL=$? + # if no nodes are setup to startup automatically exit cleanly + grep -qrs "node.startup = automatic" /var/lib/iscsi/nodes + [ $? -eq 0 ] || exit 0 - if [ $RETVAL -ne 0 ]; then - /etc/init.d/iscsid start - fi + # 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 - 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 + # 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 + + success $"Starting $prog" + touch $lockfile + echo + return 0 } -stop() -{ - rm -f /var/lock/subsys/iscsi +stop() { + echo -n $"Stopping $prog: " + $exec -m node --logoutall=automatic 2>&1 > /dev/null | grep iscsiadm - # 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 + # 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 - # 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 + 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/iscsistart-static.patch b/iscsistart-static.patch deleted file mode 100644 index 96e1b7b..0000000 --- a/iscsistart-static.patch +++ /dev/null @@ -1,39 +0,0 @@ -diff -Naurp open-iscsi-6.0.5.595/usr/Makefile open-iscsi-6.0.5.610.work/usr/Makefile ---- open-iscsi-6.0.5.595/usr/Makefile 2006-06-21 12:32:51.000000000 -0500 -+++ open-iscsi-6.0.5.610.work/usr/Makefile 2006-06-21 12:33:55.000000000 -0500 -@@ -50,8 +50,9 @@ iscsid: $(COMMON_SRCS) $(IPC_OBJ) $(INIT - iscsiadm: $(COMMON_SRCS) strings.o discovery.o iscsiadm.o - $(CC) $(CFLAGS) $^ $(DBM_LIB) -o $@ - --iscsistart: $(IPC_OBJ) $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) iscsistart.o -- $(CC) $(CFLAGS) $^ -o $@ -+iscsistart: $(IPC_OBJ) $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) iscsistart.o \ -+ statics.o -+ $(CC) -static $(CFLAGS) $^ -o $@ - - clean: - rm -f *.o $(PROGRAMS) -diff -Naurp open-iscsi-6.0.5.595/usr/statics.c open-iscsi-6.0.5.610.work/usr/statics.c ---- open-iscsi-6.0.5.595/usr/statics.c 1969-12-31 18:00:00.000000000 -0600 -+++ open-iscsi-6.0.5.610.work/usr/statics.c 2006-06-21 12:30:05.000000000 -0500 -@@ -0,0 +1,20 @@ -+#include -+#include -+#include -+#include -+ -+static struct passwd root_pw = { -+ .pw_name = "root", -+}; -+ -+struct passwd* -+getpwuid(uid_t uid) -+{ -+ if (uid == 0) -+ return &root_pw; -+ else { -+ errno = ENOENT; -+ return 0; -+ } -+} -+ 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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++#include "idbm.h" ++#include "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 , where is the value of ++# the FILE_VERSION_FILTER tag, and is the name of an input file ++# provided by doxygen. Whatever the program writes to standard output ++# is used as the file version. See the manual for examples. ++ ++FILE_VERSION_FILTER = ++ ++# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by ++# doxygen. The layout file controls the global structure of the generated output files ++# in an output format independent way. The create the layout file that represents ++# doxygen's defaults, run doxygen with the -l option. You can optionally specify a ++# file name after the option, if omitted DoxygenLayout.xml will be used as the name ++# of the layout file. ++ ++LAYOUT_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to warning and progress messages ++#--------------------------------------------------------------------------- ++ ++# The QUIET tag can be used to turn on/off the messages that are generated ++# by doxygen. Possible values are YES and NO. If left blank NO is used. ++ ++QUIET = YES ++ ++# The WARNINGS tag can be used to turn on/off the warning messages that are ++# generated by doxygen. Possible values are YES and NO. If left blank ++# NO is used. ++ ++WARNINGS = YES ++ ++# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings ++# for undocumented members. If EXTRACT_ALL is set to YES then this flag will ++# automatically be disabled. ++ ++WARN_IF_UNDOCUMENTED = YES ++ ++# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for ++# potential errors in the documentation, such as not documenting some ++# parameters in a documented function, or documenting parameters that ++# don't exist or using markup commands wrongly. ++ ++WARN_IF_DOC_ERROR = YES ++ ++# This WARN_NO_PARAMDOC option can be abled to get warnings for ++# functions that are documented, but have no documentation for their parameters ++# or return value. If set to NO (the default) doxygen will only warn about ++# wrong or incomplete parameter documentation, but not about the absence of ++# documentation. ++ ++WARN_NO_PARAMDOC = NO ++ ++# The WARN_FORMAT tag determines the format of the warning messages that ++# doxygen can produce. The string should contain the $file, $line, and $text ++# tags, which will be replaced by the file and line number from which the ++# warning originated and the warning text. Optionally the format may contain ++# $version, which will be replaced by the version of the file (if it could ++# be obtained via FILE_VERSION_FILTER) ++ ++WARN_FORMAT = "$file:$line: $text" ++ ++# The WARN_LOGFILE tag can be used to specify a file to which warning ++# and error messages should be written. If left blank the output is written ++# to stderr. ++ ++WARN_LOGFILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the input files ++#--------------------------------------------------------------------------- ++ ++# The INPUT tag can be used to specify the files and/or directories that contain ++# documented source files. You may enter file names like "myfile.cpp" or ++# directories like "/usr/src/myproject". Separate the files or directories ++# with spaces. ++ ++INPUT = ++ ++# This tag can be used to specify the character encoding of the source files ++# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is ++# also the default input encoding. Doxygen uses libiconv (or the iconv built ++# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for ++# the list of possible encodings. ++ ++INPUT_ENCODING = UTF-8 ++ ++# If the value of the INPUT tag contains directories, you can use the ++# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank the following patterns are tested: ++# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx ++# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 ++ ++FILE_PATTERNS = ++ ++# The RECURSIVE tag can be used to turn specify whether or not subdirectories ++# should be searched for input files as well. Possible values are YES and NO. ++# If left blank NO is used. ++ ++RECURSIVE = NO ++ ++# The EXCLUDE tag can be used to specify files and/or directories that should ++# excluded from the INPUT source files. This way you can easily exclude a ++# subdirectory from a directory tree whose root is specified with the INPUT tag. ++ ++EXCLUDE = ++ ++# The EXCLUDE_SYMLINKS tag can be used select whether or not files or ++# directories that are symbolic links (a Unix filesystem feature) are excluded ++# from the input. ++ ++EXCLUDE_SYMLINKS = NO ++ ++# If the value of the INPUT tag contains directories, you can use the ++# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude ++# certain files from those directories. Note that the wildcards are matched ++# against the file with absolute path, so to exclude all test directories ++# for example use the pattern */test/* ++ ++EXCLUDE_PATTERNS = ++ ++# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names ++# (namespaces, classes, functions, etc.) that should be excluded from the ++# output. The symbol name can be a fully qualified name, a word, or if the ++# wildcard * is used, a substring. Examples: ANamespace, AClass, ++# AClass::ANamespace, ANamespace::*Test ++ ++EXCLUDE_SYMBOLS = ++ ++# The EXAMPLE_PATH tag can be used to specify one or more files or ++# directories that contain example code fragments that are included (see ++# the \include command). ++ ++EXAMPLE_PATH = ++ ++# If the value of the EXAMPLE_PATH tag contains directories, you can use the ++# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank all files are included. ++ ++EXAMPLE_PATTERNS = ++ ++# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be ++# searched for input files to be used with the \include or \dontinclude ++# commands irrespective of the value of the RECURSIVE tag. ++# Possible values are YES and NO. If left blank NO is used. ++ ++EXAMPLE_RECURSIVE = NO ++ ++# The IMAGE_PATH tag can be used to specify one or more files or ++# directories that contain image that are included in the documentation (see ++# the \image command). ++ ++IMAGE_PATH = ++ ++# The INPUT_FILTER tag can be used to specify a program that doxygen should ++# invoke to filter for each input file. Doxygen will invoke the filter program ++# by executing (via popen()) the command , where ++# is the value of the INPUT_FILTER tag, and is the name of an ++# input file. Doxygen will then use the output that the filter program writes ++# to standard output. If FILTER_PATTERNS is specified, this tag will be ++# ignored. ++ ++INPUT_FILTER = ++ ++# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern ++# basis. Doxygen will compare the file name with each pattern and apply the ++# filter if there is a match. The filters are a list of the form: ++# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further ++# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER ++# is applied to all files. ++ ++FILTER_PATTERNS = ++ ++# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using ++# INPUT_FILTER) will be used to filter the input files when producing source ++# files to browse (i.e. when SOURCE_BROWSER is set to YES). ++ ++FILTER_SOURCE_FILES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to source browsing ++#--------------------------------------------------------------------------- ++ ++# If the SOURCE_BROWSER tag is set to YES then a list of source files will ++# be generated. Documented entities will be cross-referenced with these sources. ++# Note: To get rid of all source code in the generated output, make sure also ++# VERBATIM_HEADERS is set to NO. ++ ++SOURCE_BROWSER = NO ++ ++# Setting the INLINE_SOURCES tag to YES will include the body ++# of functions and classes directly in the documentation. ++ ++INLINE_SOURCES = NO ++ ++# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct ++# doxygen to hide any special comment blocks from generated source code ++# fragments. Normal C and C++ comments will always remain visible. ++ ++STRIP_CODE_COMMENTS = YES ++ ++# If the REFERENCED_BY_RELATION tag is set to YES ++# then for each documented function all documented ++# functions referencing it will be listed. ++ ++REFERENCED_BY_RELATION = NO ++ ++# If the REFERENCES_RELATION tag is set to YES ++# then for each documented function all documented entities ++# called/used by that function will be listed. ++ ++REFERENCES_RELATION = NO ++ ++# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) ++# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from ++# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will ++# link to the source code. Otherwise they will link to the documentstion. ++ ++REFERENCES_LINK_SOURCE = YES ++ ++# If the USE_HTAGS tag is set to YES then the references to source code ++# will point to the HTML generated by the htags(1) tool instead of doxygen ++# built-in source browser. The htags tool is part of GNU's global source ++# tagging system (see http://www.gnu.org/software/global/global.html). You ++# will need version 4.8.6 or higher. ++ ++USE_HTAGS = NO ++ ++# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen ++# will generate a verbatim copy of the header file for each class for ++# which an include is specified. Set to NO to disable this. ++ ++VERBATIM_HEADERS = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the alphabetical class index ++#--------------------------------------------------------------------------- ++ ++# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index ++# of all compounds will be generated. Enable this if the project ++# contains a lot of classes, structs, unions or interfaces. ++ ++ALPHABETICAL_INDEX = NO ++ ++# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then ++# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns ++# in which this list will be split (can be a number in the range [1..20]) ++ ++COLS_IN_ALPHA_INDEX = 5 ++ ++# In case all classes in a project start with a common prefix, all ++# classes will be put under the same header in the alphabetical index. ++# The IGNORE_PREFIX tag can be used to specify one or more prefixes that ++# should be ignored while generating the index headers. ++ ++IGNORE_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the HTML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_HTML tag is set to YES (the default) Doxygen will ++# generate HTML output. ++ ++GENERATE_HTML = YES ++ ++# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `html' will be used as the default path. ++ ++HTML_OUTPUT = html ++ ++# The HTML_FILE_EXTENSION tag can be used to specify the file extension for ++# each generated HTML page (for example: .htm,.php,.asp). If it is left blank ++# doxygen will generate files with .html extension. ++ ++HTML_FILE_EXTENSION = .html ++ ++# The HTML_HEADER tag can be used to specify a personal HTML header for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard header. ++ ++HTML_HEADER = ++ ++# The HTML_FOOTER tag can be used to specify a personal HTML footer for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard footer. ++ ++HTML_FOOTER = ++ ++# The HTML_STYLESHEET tag can be used to specify a user-defined cascading ++# style sheet that is used by each HTML page. It can be used to ++# fine-tune the look of the HTML output. If the tag is left blank doxygen ++# will generate a default style sheet. Note that doxygen will try to copy ++# the style sheet file to the HTML output directory, so don't put your own ++# stylesheet in the HTML output directory as well, or it will be erased! ++ ++HTML_STYLESHEET = ++ ++# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, ++# files or namespaces will be aligned in HTML using tables. If set to ++# NO a bullet list will be used. ++ ++HTML_ALIGN_MEMBERS = YES ++ ++# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML ++# documentation will contain sections that can be hidden and shown after the ++# page has loaded. For this to work a browser that supports ++# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox ++# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). ++ ++HTML_DYNAMIC_SECTIONS = NO ++ ++# If the GENERATE_DOCSET tag is set to YES, additional index files ++# will be generated that can be used as input for Apple's Xcode 3 ++# integrated development environment, introduced with OSX 10.5 (Leopard). ++# To create a documentation set, doxygen will generate a Makefile in the ++# HTML output directory. Running make will produce the docset in that ++# directory and running "make install" will install the docset in ++# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find ++# it at startup. ++# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. ++ ++GENERATE_DOCSET = NO ++ ++# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the ++# feed. A documentation feed provides an umbrella under which multiple ++# documentation sets from a single provider (such as a company or product suite) ++# can be grouped. ++ ++DOCSET_FEEDNAME = "Doxygen generated docs" ++ ++# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that ++# should uniquely identify the documentation set bundle. This should be a ++# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen ++# will append .docset to the name. ++ ++DOCSET_BUNDLE_ID = org.doxygen.Project ++ ++# If the GENERATE_HTMLHELP tag is set to YES, additional index files ++# will be generated that can be used as input for tools like the ++# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) ++# of the generated HTML documentation. ++ ++GENERATE_HTMLHELP = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can ++# be used to specify the file name of the resulting .chm file. You ++# can add a path in front of the file if the result should not be ++# written to the html output directory. ++ ++CHM_FILE = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can ++# be used to specify the location (absolute path including file name) of ++# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run ++# the HTML help compiler on the generated index.hhp. ++ ++HHC_LOCATION = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag ++# controls if a separate .chi index file is generated (YES) or that ++# it should be included in the master .chm file (NO). ++ ++GENERATE_CHI = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING ++# is used to encode HtmlHelp index (hhk), content (hhc) and project file ++# content. ++ ++CHM_INDEX_ENCODING = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag ++# controls whether a binary table of contents is generated (YES) or a ++# normal table of contents (NO) in the .chm file. ++ ++BINARY_TOC = NO ++ ++# The TOC_EXPAND flag can be set to YES to add extra items for group members ++# to the contents of the HTML help documentation and to the tree view. ++ ++TOC_EXPAND = NO ++ ++# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER ++# are set, an additional index file will be generated that can be used as input for ++# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated ++# HTML documentation. ++ ++GENERATE_QHP = NO ++ ++# If the QHG_LOCATION tag is specified, the QCH_FILE tag can ++# be used to specify the file name of the resulting .qch file. ++# The path specified is relative to the HTML output folder. ++ ++QCH_FILE = ++ ++# The QHP_NAMESPACE tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Namespace. ++ ++QHP_NAMESPACE = org.doxygen.Project ++ ++# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Virtual Folders. ++ ++QHP_VIRTUAL_FOLDER = doc ++ ++# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can ++# be used to specify the location of Qt's qhelpgenerator. ++# If non-empty doxygen will try to run qhelpgenerator on the generated ++# .qhp file . ++ ++QHG_LOCATION = ++ ++# The DISABLE_INDEX tag can be used to turn on/off the condensed index at ++# top of each HTML page. The value NO (the default) enables the index and ++# the value YES disables it. ++ ++DISABLE_INDEX = NO ++ ++# This tag can be used to set the number of enum values (range [1..20]) ++# that doxygen will group on one line in the generated HTML documentation. ++ ++ENUM_VALUES_PER_LINE = 4 ++ ++# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index ++# structure should be generated to display hierarchical information. ++# If the tag value is set to FRAME, a side panel will be generated ++# containing a tree-like index structure (just like the one that ++# is generated for HTML Help). For this to work a browser that supports ++# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, ++# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are ++# probably better off using the HTML help feature. Other possible values ++# for this tag are: HIERARCHIES, which will generate the Groups, Directories, ++# and Class Hierarchy pages using a tree view instead of an ordered list; ++# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which ++# disables this behavior completely. For backwards compatibility with previous ++# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE ++# respectively. ++ ++GENERATE_TREEVIEW = NONE ++ ++# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be ++# used to set the initial width (in pixels) of the frame in which the tree ++# is shown. ++ ++TREEVIEW_WIDTH = 250 ++ ++# Use this tag to change the font size of Latex formulas included ++# as images in the HTML documentation. The default is 10. Note that ++# when you change the font size after a successful doxygen run you need ++# to manually remove any form_*.png images from the HTML output directory ++# to force them to be regenerated. ++ ++FORMULA_FONTSIZE = 10 ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the LaTeX output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will ++# generate Latex output. ++ ++GENERATE_LATEX = NO ++ ++# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `latex' will be used as the default path. ++ ++LATEX_OUTPUT = latex ++ ++# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be ++# invoked. If left blank `latex' will be used as the default command name. ++ ++LATEX_CMD_NAME = latex ++ ++# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to ++# generate index for LaTeX. If left blank `makeindex' will be used as the ++# default command name. ++ ++MAKEINDEX_CMD_NAME = makeindex ++ ++# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact ++# LaTeX documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_LATEX = NO ++ ++# The PAPER_TYPE tag can be used to set the paper type that is used ++# by the printer. Possible values are: a4, a4wide, letter, legal and ++# executive. If left blank a4wide will be used. ++ ++PAPER_TYPE = a4wide ++ ++# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX ++# packages that should be included in the LaTeX output. ++ ++EXTRA_PACKAGES = ++ ++# The LATEX_HEADER tag can be used to specify a personal LaTeX header for ++# the generated latex document. The header should contain everything until ++# the first chapter. If it is left blank doxygen will generate a ++# standard header. Notice: only use this tag if you know what you are doing! ++ ++LATEX_HEADER = ++ ++# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated ++# is prepared for conversion to pdf (using ps2pdf). The pdf file will ++# contain links (just like the HTML output) instead of page references ++# This makes the output suitable for online browsing using a pdf viewer. ++ ++PDF_HYPERLINKS = YES ++ ++# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of ++# plain latex in the generated Makefile. Set this option to YES to get a ++# higher quality PDF documentation. ++ ++USE_PDFLATEX = YES ++ ++# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. ++# command to the generated LaTeX files. This will instruct LaTeX to keep ++# running if errors occur, instead of asking the user for help. ++# This option is also used when generating formulas in HTML. ++ ++LATEX_BATCHMODE = NO ++ ++# If LATEX_HIDE_INDICES is set to YES then doxygen will not ++# include the index chapters (such as File Index, Compound Index, etc.) ++# in the output. ++ ++LATEX_HIDE_INDICES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the RTF output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output ++# The RTF output is optimized for Word 97 and may not look very pretty with ++# other RTF readers or editors. ++ ++GENERATE_RTF = NO ++ ++# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `rtf' will be used as the default path. ++ ++RTF_OUTPUT = rtf ++ ++# If the COMPACT_RTF tag is set to YES Doxygen generates more compact ++# RTF documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_RTF = NO ++ ++# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated ++# will contain hyperlink fields. The RTF file will ++# contain links (just like the HTML output) instead of page references. ++# This makes the output suitable for online browsing using WORD or other ++# programs which support those fields. ++# Note: wordpad (write) and others do not support links. ++ ++RTF_HYPERLINKS = NO ++ ++# Load stylesheet definitions from file. Syntax is similar to doxygen's ++# config file, i.e. a series of assignments. You only have to provide ++# replacements, missing definitions are set to their default value. ++ ++RTF_STYLESHEET_FILE = ++ ++# Set optional variables used in the generation of an rtf document. ++# Syntax is similar to doxygen's config file. ++ ++RTF_EXTENSIONS_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the man page output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_MAN tag is set to YES (the default) Doxygen will ++# generate man pages ++ ++GENERATE_MAN = NO ++ ++# The MAN_OUTPUT tag is used to specify where the man pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `man' will be used as the default path. ++ ++MAN_OUTPUT = man ++ ++# The MAN_EXTENSION tag determines the extension that is added to ++# the generated man pages (default is the subroutine's section .3) ++ ++MAN_EXTENSION = .3 ++ ++# If the MAN_LINKS tag is set to YES and Doxygen generates man output, ++# then it will generate one additional man file for each entity ++# documented in the real man page(s). These additional files ++# only source the real man page, but without them the man command ++# would be unable to find the correct page. The default is NO. ++ ++MAN_LINKS = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the XML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_XML tag is set to YES Doxygen will ++# generate an XML file that captures the structure of ++# the code including all documentation. ++ ++GENERATE_XML = NO ++ ++# The XML_OUTPUT tag is used to specify where the XML pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `xml' will be used as the default path. ++ ++XML_OUTPUT = xml ++ ++# The XML_SCHEMA tag can be used to specify an XML schema, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_SCHEMA = ++ ++# The XML_DTD tag can be used to specify an XML DTD, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_DTD = ++ ++# If the XML_PROGRAMLISTING tag is set to YES Doxygen will ++# dump the program listings (including syntax highlighting ++# and cross-referencing information) to the XML output. Note that ++# enabling this will significantly increase the size of the XML output. ++ ++XML_PROGRAMLISTING = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options for the AutoGen Definitions output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will ++# generate an AutoGen Definitions (see autogen.sf.net) file ++# that captures the structure of the code including all ++# documentation. Note that this feature is still experimental ++# and incomplete at the moment. ++ ++GENERATE_AUTOGEN_DEF = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the Perl module output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_PERLMOD tag is set to YES Doxygen will ++# generate a Perl module file that captures the structure of ++# the code including all documentation. Note that this ++# feature is still experimental and incomplete at the ++# moment. ++ ++GENERATE_PERLMOD = NO ++ ++# If the PERLMOD_LATEX tag is set to YES Doxygen will generate ++# the necessary Makefile rules, Perl scripts and LaTeX code to be able ++# to generate PDF and DVI output from the Perl module output. ++ ++PERLMOD_LATEX = NO ++ ++# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be ++# nicely formatted so it can be parsed by a human reader. This is useful ++# if you want to understand what is going on. On the other hand, if this ++# tag is set to NO the size of the Perl module output will be much smaller ++# and Perl will parse it just the same. ++ ++PERLMOD_PRETTY = YES ++ ++# The names of the make variables in the generated doxyrules.make file ++# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. ++# This is useful so different doxyrules.make files included by the same ++# Makefile don't overwrite each other's variables. ++ ++PERLMOD_MAKEVAR_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the preprocessor ++#--------------------------------------------------------------------------- ++ ++# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will ++# evaluate all C-preprocessor directives found in the sources and include ++# files. ++ ++ENABLE_PREPROCESSING = YES ++ ++# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro ++# names in the source code. If set to NO (the default) only conditional ++# compilation will be performed. Macro expansion can be done in a controlled ++# way by setting EXPAND_ONLY_PREDEF to YES. ++ ++MACRO_EXPANSION = NO ++ ++# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES ++# then the macro expansion is limited to the macros specified with the ++# PREDEFINED and EXPAND_AS_DEFINED tags. ++ ++EXPAND_ONLY_PREDEF = NO ++ ++# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files ++# in the INCLUDE_PATH (see below) will be search if a #include is found. ++ ++SEARCH_INCLUDES = YES ++ ++# The INCLUDE_PATH tag can be used to specify one or more directories that ++# contain include files that are not input files but should be processed by ++# the preprocessor. ++ ++INCLUDE_PATH = ++ ++# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard ++# patterns (like *.h and *.hpp) to filter out the header-files in the ++# directories. If left blank, the patterns specified with FILE_PATTERNS will ++# be used. ++ ++INCLUDE_FILE_PATTERNS = ++ ++# The PREDEFINED tag can be used to specify one or more macro names that ++# are defined before the preprocessor is started (similar to the -D option of ++# gcc). The argument of the tag is a list of macros of the form: name ++# or name=definition (no spaces). If the definition and the = are ++# omitted =1 is assumed. To prevent a macro definition from being ++# undefined via #undef or recursively expanded use the := operator ++# instead of the = operator. ++ ++PREDEFINED = ++ ++# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then ++# this tag can be used to specify a list of macro names that should be expanded. ++# The macro definition that is found in the sources will be used. ++# Use the PREDEFINED tag if you want to use a different macro definition. ++ ++EXPAND_AS_DEFINED = ++ ++# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then ++# doxygen's preprocessor will remove all function-like macros that are alone ++# on a line, have an all uppercase name, and do not end with a semicolon. Such ++# function macros are typically used for boiler-plate code, and will confuse ++# the parser if not removed. ++ ++SKIP_FUNCTION_MACROS = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to external references ++#--------------------------------------------------------------------------- ++ ++# The TAGFILES option can be used to specify one or more tagfiles. ++# Optionally an initial location of the external documentation ++# can be added for each tagfile. The format of a tag file without ++# this location is as follows: ++# TAGFILES = file1 file2 ... ++# Adding location for the tag files is done as follows: ++# TAGFILES = file1=loc1 "file2 = loc2" ... ++# where "loc1" and "loc2" can be relative or absolute paths or ++# URLs. If a location is present for each tag, the installdox tool ++# does not have to be run to correct the links. ++# Note that each tag file must have a unique name ++# (where the name does NOT include the path) ++# If a tag file is not located in the directory in which doxygen ++# is run, you must also specify the path to the tagfile here. ++ ++TAGFILES = ++ ++# When a file name is specified after GENERATE_TAGFILE, doxygen will create ++# a tag file that is based on the input files it reads. ++ ++GENERATE_TAGFILE = ++ ++# If the ALLEXTERNALS tag is set to YES all external classes will be listed ++# in the class index. If set to NO only the inherited external classes ++# will be listed. ++ ++ALLEXTERNALS = NO ++ ++# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed ++# in the modules index. If set to NO, only the current project's groups will ++# be listed. ++ ++EXTERNAL_GROUPS = YES ++ ++# The PERL_PATH should be the absolute path and name of the perl script ++# interpreter (i.e. the result of `which perl'). ++ ++PERL_PATH = /usr/bin/perl ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the dot tool ++#--------------------------------------------------------------------------- ++ ++# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will ++# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base ++# or super classes. Setting the tag to NO turns the diagrams off. Note that ++# this option is superseded by the HAVE_DOT option below. This is only a ++# fallback. It is recommended to install and use dot, since it yields more ++# powerful graphs. ++ ++CLASS_DIAGRAMS = YES ++ ++# You can define message sequence charts within doxygen comments using the \msc ++# command. Doxygen will then run the mscgen tool (see ++# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the ++# documentation. The MSCGEN_PATH tag allows you to specify the directory where ++# the mscgen tool resides. If left empty the tool is assumed to be found in the ++# default search path. ++ ++MSCGEN_PATH = ++ ++# If set to YES, the inheritance and collaboration graphs will hide ++# inheritance and usage relations if the target is undocumented ++# or is not a class. ++ ++HIDE_UNDOC_RELATIONS = YES ++ ++# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is ++# available from the path. This tool is part of Graphviz, a graph visualization ++# toolkit from AT&T and Lucent Bell Labs. The other options in this section ++# have no effect if this option is set to NO (the default) ++ ++HAVE_DOT = NO ++ ++# By default doxygen will write a font called FreeSans.ttf to the output ++# directory and reference it in all dot files that doxygen generates. This ++# font does not include all possible unicode characters however, so when you need ++# these (or just want a differently looking font) you can specify the font name ++# using DOT_FONTNAME. You need need to make sure dot is able to find the font, ++# which can be done by putting it in a standard location or by setting the ++# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory ++# containing the font. ++ ++DOT_FONTNAME = FreeSans ++ ++# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. ++# The default size is 10pt. ++ ++DOT_FONTSIZE = 10 ++ ++# By default doxygen will tell dot to use the output directory to look for the ++# FreeSans.ttf font (which doxygen will put there itself). If you specify a ++# different font using DOT_FONTNAME you can set the path where dot ++# can find it using this tag. ++ ++DOT_FONTPATH = ++ ++# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect inheritance relations. Setting this tag to YES will force the ++# the CLASS_DIAGRAMS tag to NO. ++ ++CLASS_GRAPH = YES ++ ++# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect implementation dependencies (inheritance, containment, and ++# class references variables) of the class with other documented classes. ++ ++COLLABORATION_GRAPH = YES ++ ++# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for groups, showing the direct groups dependencies ++ ++GROUP_GRAPHS = YES ++ ++# If the UML_LOOK tag is set to YES doxygen will generate inheritance and ++# collaboration diagrams in a style similar to the OMG's Unified Modeling ++# Language. ++ ++UML_LOOK = NO ++ ++# If set to YES, the inheritance and collaboration graphs will show the ++# relations between templates and their instances. ++ ++TEMPLATE_RELATIONS = NO ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT ++# tags are set to YES then doxygen will generate a graph for each documented ++# file showing the direct and indirect include dependencies of the file with ++# other documented files. ++ ++INCLUDE_GRAPH = YES ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and ++# HAVE_DOT tags are set to YES then doxygen will generate a graph for each ++# documented header file showing the documented files that directly or ++# indirectly include this file. ++ ++INCLUDED_BY_GRAPH = YES ++ ++# If the CALL_GRAPH and HAVE_DOT options are set to YES then ++# doxygen will generate a call dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable call graphs ++# for selected functions only using the \callgraph command. ++ ++CALL_GRAPH = NO ++ ++# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then ++# doxygen will generate a caller dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable caller ++# graphs for selected functions only using the \callergraph command. ++ ++CALLER_GRAPH = NO ++ ++# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen ++# will graphical hierarchy of all classes instead of a textual one. ++ ++GRAPHICAL_HIERARCHY = YES ++ ++# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES ++# then doxygen will show the dependencies a directory has on other directories ++# in a graphical way. The dependency relations are determined by the #include ++# relations between the files in the directories. ++ ++DIRECTORY_GRAPH = YES ++ ++# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images ++# generated by dot. Possible values are png, jpg, or gif ++# If left blank png will be used. ++ ++DOT_IMAGE_FORMAT = png ++ ++# The tag DOT_PATH can be used to specify the path where the dot tool can be ++# found. If left blank, it is assumed the dot tool can be found in the path. ++ ++DOT_PATH = ++ ++# The DOTFILE_DIRS tag can be used to specify one or more directories that ++# contain dot files that are included in the documentation (see the ++# \dotfile command). ++ ++DOTFILE_DIRS = ++ ++# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of ++# nodes that will be shown in the graph. If the number of nodes in a graph ++# becomes larger than this value, doxygen will truncate the graph, which is ++# visualized by representing a node as a red box. Note that doxygen if the ++# number of direct children of the root node in a graph is already larger than ++# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note ++# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. ++ ++DOT_GRAPH_MAX_NODES = 50 ++ ++# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the ++# graphs generated by dot. A depth value of 3 means that only nodes reachable ++# from the root by following a path via at most 3 edges will be shown. Nodes ++# that lay further from the root node will be omitted. Note that setting this ++# option to 1 or 2 may greatly reduce the computation time needed for large ++# code bases. Also note that the size of a graph can be further restricted by ++# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. ++ ++MAX_DOT_GRAPH_DEPTH = 0 ++ ++# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent ++# background. This is disabled by default, because dot on Windows does not ++# seem to support this out of the box. Warning: Depending on the platform used, ++# enabling this option may lead to badly anti-aliased labels on the edges of ++# a graph (i.e. they become hard to read). ++ ++DOT_TRANSPARENT = NO ++ ++# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output ++# files in one run (i.e. multiple -o and -T options on the command line). This ++# makes dot run faster, but since only newer versions of dot (>1.8.10) ++# support this, this feature is disabled by default. ++ ++DOT_MULTI_TARGETS = NO ++ ++# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will ++# generate a legend page explaining the meaning of the various boxes and ++# arrows in the dot generated graphs. ++ ++GENERATE_LEGEND = YES ++ ++# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will ++# remove the intermediate dot files that are used to generate ++# the various graphs. ++ ++DOT_CLEANUP = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to the search engine ++#--------------------------------------------------------------------------- ++ ++# The SEARCHENGINE tag specifies whether or not a search engine should be ++# used. If set to NO the values of all tags below this one will be ignored. ++ ++SEARCHENGINE = NO +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#ifndef __LIBISCSI_H ++#define __LIBISCSI_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++#if __GNUC__ >= 4 ++#define PUBLIC __attribute__ ((visibility("default"))) ++#else ++#define PUBLIC ++#endif ++ ++/** \brief Maximum length for iSCSI values. ++ * ++ * Maximum length for iSCSI values such as hostnames and parameter values. ++ */ ++#define LIBISCSI_VALUE_MAXLEN 256 ++ ++/** \brief supported authentication methods ++ * ++ * This enum lists all supported authentication methods. ++ */ ++enum libiscsi_auth_t { ++ libiscsi_auth_none /** No authentication */, ++ libiscsi_auth_chap /** CHAP authentication */, ++}; ++ ++/** \brief libiscsi context struct ++ * ++ * Note: even though libiscsi uses a context struct, the underlying open-iscsi ++ * code does not, so libiscsi is not thread safe, not even when using one ++ * context per thread! ++ */ ++struct libiscsi_context; ++ ++/** \brief iSCSI node record ++ * ++ * Struct holding data uniquely identifying an iSCSI node. ++ */ ++struct libiscsi_node { ++ char name[LIBISCSI_VALUE_MAXLEN] /** iSCSI iqn for the node. */; ++ int tpgt /** Portal group number. */; ++ /* Note open-iscsi has some code in place for multiple connections in one ++ node record and thus multiple address / port combi's, but this does not ++ get used anywhere, so we keep things simple and assume one connection */ ++ char address[NI_MAXHOST] /** Portal hostname or IP-address. */; ++ int port /** Portal port number. */; ++}; ++ ++/** \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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include "libiscsi.h" ++ ++static struct libiscsi_context *context = NULL; ++ ++/****************************** helpers ***********************************/ ++static int check_string(const char *string) ++{ ++ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) { ++ PyErr_SetString(PyExc_ValueError, "string too long"); ++ return -1; ++ } ++ return 0; ++} ++ ++/********************** PyIscsiChapAuthInfo ***************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_auth_info info; ++} PyIscsiChapAuthInfo; ++ ++static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ int i; ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char *kwlist[] = {"username", "password", "reverse_username", ++ "reverse_password", NULL}; ++ const char *string[4] = { NULL, NULL, NULL, NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, ++ "zz|zz:chapAuthInfo.__init__", ++ kwlist, &string[0], &string[1], ++ &string[2], &string[3])) ++ return -1; ++ ++ for (i = 0; i < 4; i++) ++ if (string[i] && check_string(string[i])) ++ return -1; ++ ++ memset (&chap->info, 0, sizeof(chap->info)); ++ chap->info.method = libiscsi_auth_chap; ++ if (string[0]) ++ strcpy(chap->info.chap.username, string[0]); ++ if (string[1]) ++ strcpy(chap->info.chap.password, string[1]); ++ if (string[2]) ++ strcpy(chap->info.chap.reverse_username, string[2]); ++ if (string[3]) ++ strcpy(chap->info.chap.reverse_password, string[3]); ++ ++ if (libiscsi_verify_auth_info(context, &chap->info)) { ++ PyErr_SetString(PyExc_ValueError, ++ libiscsi_get_error_string(context)); ++ return -1; ++ } ++ return 0; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "username")) { ++ return PyString_FromString(chap->info.chap.username); ++ } else if (!strcmp(attr, "password")) { ++ return PyString_FromString(chap->info.chap.password); ++ } else if (!strcmp(attr, "reverse_username")) { ++ return PyString_FromString(chap->info.chap.reverse_username); ++ } else if (!strcmp(attr, "reverse_password")) { ++ return PyString_FromString(chap->info.chap.reverse_password); ++ } ++ return NULL; ++} ++ ++static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ ++ if (!strcmp(attr, "username")) { ++ strcpy(chap->info.chap.username, str); ++ } else if (!strcmp(attr, "password")) { ++ strcpy(chap->info.chap.password, str); ++ } else if (!strcmp(attr, "reverse_username")) { ++ strcpy(chap->info.chap.reverse_username, str); ++ } else if (!strcmp(attr, "reverse_password")) { ++ strcpy(chap->info.chap.reverse_password, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self, ++ PyIscsiChapAuthInfo *other) ++{ ++ int r; ++ ++ r = strcmp(self->info.chap.username, other->info.chap.username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.password, other->info.chap.password); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_username, ++ other->info.chap.reverse_username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_password, ++ other->info.chap.reverse_password); ++ return r; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_str(PyObject *self) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char s[1024], reverse[512] = ""; ++ ++ if (chap->info.chap.reverse_username[0]) ++ snprintf(reverse, sizeof(reverse), ", %s:%s", ++ chap->info.chap.reverse_username, ++ chap->info.chap.reverse_password); ++ ++ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username, ++ chap->info.chap.password, reverse); ++ ++ return PyString_FromString(s); ++} ++ ++static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = { ++ {"username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "username", "username"}, ++ {"password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "password", "password"}, ++ {"reverse_username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_username", "reverse_username"}, ++ {"reverse_password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_password", "reverse_password"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiChapAuthInfo_Type = { ++ PyObject_HEAD_INIT(NULL) ++ .tp_name = "libiscsi.chapAuthInfo", ++ .tp_basicsize = sizeof (PyIscsiChapAuthInfo), ++ .tp_getset = PyIscsiChapAuthInfo_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | ++ Py_TPFLAGS_BASETYPE, ++ .tp_compare = (cmpfunc)PyIscsiChapAuthInfo_compare, ++ .tp_init = PyIscsiChapAuthInfo_init, ++ .tp_str = PyIscsiChapAuthInfo_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "iscsi chap authentication information.", ++}; ++ ++/***************************** PyIscsiNode ********************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_node node; ++} PyIscsiNode; ++ ++static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char *kwlist[] = {"name", "tpgt", "address", "port", NULL}; ++ const char *name = NULL, *address = NULL; ++ int tpgt = -1, port = 3260; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isi:node.__init__", ++ kwlist, &name, &tpgt, &address, &port)) ++ return -1; ++ if (address == NULL) { ++ PyErr_SetString(PyExc_ValueError, "address not set"); ++ return -1; ++ } ++ if (check_string(name) || check_string(address)) ++ return -1; ++ ++ strcpy(node->node.name, name); ++ node->node.tpgt = tpgt; ++ strcpy(node->node.address, address); ++ node->node.port = port; ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_get(PyObject *self, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "name")) { ++ return PyString_FromString(node->node.name); ++ } else if (!strcmp(attr, "tpgt")) { ++ return PyInt_FromLong(node->node.tpgt); ++ } else if (!strcmp(attr, "address")) { ++ return PyString_FromString(node->node.address); ++ } else if (!strcmp(attr, "port")) { ++ return PyInt_FromLong(node->node.port); ++ } ++ return NULL; ++} ++ ++static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ int i; ++ ++ if (!strcmp(attr, "name")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.name, str); ++ } else if (!strcmp(attr, "tpgt")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.tpgt = i; ++ } else if (!strcmp(attr, "address")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.address, str); ++ } else if (!strcmp(attr, "port")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.port = i; ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other) ++{ ++ int res; ++ ++ res = strcmp(self->node.name, other->node.name); ++ if (res) ++ return res; ++ ++ if (self->node.tpgt < other->node.tpgt) ++ return -1; ++ if (self->node.tpgt > other->node.tpgt) ++ return -1; ++ ++ res = strcmp(self->node.address, other->node.address); ++ if (res) ++ return res; ++ ++ if (self->node.port < other->node.port) ++ return -1; ++ if (self->node.port > other->node.port) ++ return -1; ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_str(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char s[1024], tpgt[16] = ""; ++ ++ if (node->node.tpgt != -1) ++ sprintf(tpgt, ",%d", node->node.tpgt); ++ ++ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address, ++ node->node.port, tpgt, node->node.name); ++ ++ return PyString_FromString(s); ++} ++ ++static PyObject *PyIscsiNode_login(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_login(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_logout(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_logout(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"authinfo", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyObject *arg; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) ++ return NULL; ++ ++ if (arg == Py_None) { ++ authinfo = NULL; ++ } else if (PyObject_IsInstance(arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg; ++ authinfo = &pyauthinfo->info; ++ } else { ++ PyErr_SetString(PyExc_ValueError, "invalid authinfo type"); ++ return NULL; ++ } ++ ++ if (libiscsi_node_set_auth(context, &node->node, authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getAuth(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyIscsiChapAuthInfo *pyauthinfo; ++ struct libiscsi_auth_info authinfo; ++ ++ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ switch (authinfo.method) { ++ case libiscsi_auth_chap: ++ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo, ++ &PyIscsiChapAuthInfo_Type); ++ if (!pyauthinfo) ++ return NULL; ++ ++ pyauthinfo->info = authinfo; ++ ++ return (PyObject *)pyauthinfo; ++ ++ case libiscsi_auth_none: ++ default: ++ Py_RETURN_NONE; ++ } ++} ++ ++static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", "value", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter, *value; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, ++ ¶meter, &value)) ++ return NULL; ++ if (check_string(parameter) || check_string(value)) ++ return NULL; ++ ++ if (libiscsi_node_set_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, ¶meter)) ++ return NULL; ++ if (check_string(parameter)) ++ return NULL; ++ ++ if (libiscsi_node_get_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ return Py_BuildValue("s", value); ++} ++ ++static struct PyGetSetDef PyIscsiNode_getseters[] = { ++ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "name", "name"}, ++ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "tpgt", "tpgt"}, ++ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "address", "address"}, ++ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "port", "port"}, ++ {NULL} ++}; ++ ++static struct PyMethodDef PyIscsiNode_methods[] = { ++ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS, ++ "Log in to the node"}, ++ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS, ++ "Log out of the node"}, ++ {"setAuth", (PyCFunction) PyIscsiNode_setAuth, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set authentication information"}, ++ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS, ++ "Get authentication information"}, ++ {"setParameter", (PyCFunction) PyIscsiNode_setParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set an iscsi node parameter"}, ++ {"getParameter", (PyCFunction) PyIscsiNode_getParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Get an iscsi node parameter"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiNode_Type = { ++ PyObject_HEAD_INIT(NULL) ++ .tp_name = "libiscsi.node", ++ .tp_basicsize = sizeof (PyIscsiNode), ++ .tp_getset = PyIscsiNode_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | ++ Py_TPFLAGS_BASETYPE, ++ .tp_methods = PyIscsiNode_methods, ++ .tp_compare = (cmpfunc)PyIscsiNode_compare, ++ .tp_init = PyIscsiNode_init, ++ .tp_str = PyIscsiNode_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "The iscsi node contains iscsi node information.", ++}; ++ ++/***************************************************************************/ ++ ++static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, ++ PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"address", "port", "authinfo", NULL}; ++ const char *address = NULL; ++ int i, nr_found, port = 3260; ++ PyIscsiChapAuthInfo *pyauthinfo = NULL; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO!", ++ kwlist, &address, &port, ++ &PyIscsiChapAuthInfo_Type, ++ &pyauthinfo)) ++ return NULL; ++ ++ if (pyauthinfo) ++ authinfo = &pyauthinfo->info; ++ ++ if (libiscsi_discover_sendtargets(context, address, port, authinfo, ++ &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_discover_firmware(PyObject *self) ++{ ++ int i, nr_found; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (libiscsi_discover_firmware(context, &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_get_firmware_initiator_name(PyObject *self) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ return PyString_FromString(initiatorname); ++} ++ ++static PyMethodDef pylibiscsi_functions[] = { ++ { "discover_sendtargets", ++ (PyCFunction)pylibiscsi_discover_sendtargets, ++ METH_VARARGS|METH_KEYWORDS, ++ "Do sendtargets discovery and return a list of found nodes)"}, ++ { "discover_firmware", ++ (PyCFunction)pylibiscsi_discover_firmware, METH_NOARGS, ++ "Do firmware discovery and return a list of found nodes)"}, ++ { "get_firmware_initiator_name", ++ (PyCFunction)pylibiscsi_get_firmware_initiator_name, ++ METH_NOARGS, ++ "Get initator name (iqn) from firmware"}, ++ {NULL, NULL} ++}; ++ ++PyMODINIT_FUNC initlibiscsi(void) ++{ ++ PyObject *m; ++ ++ if (!context) /* We may be called more then once */ ++ context = libiscsi_init(); ++ if (!context) ++ return; ++ ++ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0) ++ return; ++ ++ if (PyType_Ready(&PyIscsiNode_Type) < 0) ++ return; ++ ++ m = Py_InitModule("libiscsi", pylibiscsi_functions); ++ Py_INCREF(&PyIscsiChapAuthInfo_Type); ++ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type); ++ Py_INCREF(&PyIscsiNode_Type); ++ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type); ++} +diff -urN open-iscsi-2.0-870.1.orig/libiscsi/setup.py open-iscsi-2.0-870.1/libiscsi/setup.py +--- open-iscsi-2.0-870.1.orig/libiscsi/setup.py 1970-01-01 01:00:00.000000000 +0100 ++++ open-iscsi-2.0-870.1/libiscsi/setup.py 2009-01-28 10:26:36.000000000 +0100 +@@ -0,0 +1,9 @@ ++from distutils.core import setup, Extension ++ ++module1 = Extension('libiscsimodule', ++ sources = ['pylibiscsi.c'], ++ libraries = ['iscsi'], ++ library_dirs = ['.']) ++ ++setup (name = 'PyIscsi',version = '1.0', ++ description = 'libiscsi python bindings', ext_modules = [module1]) +diff -urN open-iscsi-2.0-870.1.orig/libiscsi/tests/test_discovery_firmware.c open-iscsi-2.0-870.1/libiscsi/tests/test_discovery_firmware.c +--- open-iscsi-2.0-870.1.orig/libiscsi/tests/test_discovery_firmware.c 1970-01-01 01:00:00.000000000 +0100 ++++ open-iscsi-2.0-870.1/libiscsi/tests/test_discovery_firmware.c 2009-01-28 10:26:36.000000000 +0100 +@@ -0,0 +1,53 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_discover_firmware(context, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ rc = libiscsi_discover_sendtargets(context, "127.0.0.1", 3260, ++ &auth_info, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_auth(context, &node, &auth_info); ++ if (rc) { ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ switch (auth_info.method) { ++ case libiscsi_auth_none: ++ printf("Method: \"None\"\n"); ++ break; ++ case libiscsi_auth_chap: ++ printf("Method: \"CHAP\"\n"); ++ printf("User: \"%s\"\n", auth_info.chap.username); ++ printf("Pass: \"%s\"\n", auth_info.chap.password); ++ printf("RevUser: \"%s\"\n", ++ auth_info.chap.reverse_username); ++ printf("RevPass: \"%s\"\n", ++ auth_info.chap.reverse_password); ++ break; ++ } ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("iqn:\t%s\n", initiatorname); ++ ++ return 0; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_network_config config; ++ ++ if (libiscsi_get_firmware_network_config(&config)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("dhcp:\t%d\n", config.dhcp); ++ printf("iface:\t%s\n", config.iface_name); ++ printf("mac:\t%s\n", config.mac_address); ++ printf("ipaddr:\t%s\n", config.ip_address); ++ printf("mask:\t%s\n", config.netmask); ++ printf("gate:\t%s\n", config.gateway); ++ printf("dns1:\t%s\n", config.primary_dns); ++ printf("dns2:\t%s\n", config.secondary_dns); ++ ++ return 0; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_login(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging in: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_logout(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging out: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ char orig_value[LIBISCSI_VALUE_MAXLEN], value[LIBISCSI_VALUE_MAXLEN]; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ "automatic"); ++ if (rc) { ++ fprintf(stderr, "Error setting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error getting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, "automatic")) { ++ fprintf(stderr, "Error set and get values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error setting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error re-getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, orig_value)) { ++ fprintf(stderr, ++ "Error set and get original values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff -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 ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_set_auth(context, &node, &auth_info); ++ if (rc) ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff -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 + #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