[packages/open-iscsi] - updated to 2.1.4 + current Fedora patch set - updated systemd patch - removed obsolete git,build p
qboosh
qboosh at pld-linux.org
Mon May 16 21:49:45 CEST 2022
commit 3de50fc5e99b5643efe9c051d2892c3800666e04
Author: Jakub Bogusz <qboosh at pld-linux.org>
Date: Mon May 16 21:50:10 2022 +0200
- updated to 2.1.4 + current Fedora patch set
- updated systemd patch
- removed obsolete git,build patches
- added libscsi patch, rename Fedora-provided libiscsi to libopeniscsi to resolve conflict with libiscsi.spec
...emove-dependences-from-iscsi-init.service.patch | 28 +
0001-unit-file-tweaks.patch | 175 +
0005-update-initscripts-and-docs.patch | 134 +
0008-libiscsi.patch | 4014 +++
0009-Add-macros-to-release-GIL-lock.patch | 56 +
0010-libiscsi-introduce-sessions-API.patch | 290 +
...-fix-discovery-request-timeout-regression.patch | 32 +
0012-libiscsi-format-security-build-errors.patch | 35 +
...libiscsi-fix-build-to-use-libopeniscsiusr.patch | 36 +
...i-fix-build-against-latest-upstream-again.patch | 66 +
0015-remove-the-offload-boot-supported-ifdef.patch | 45 +
...rt-iscsiadm-return-error-when-login-fails.patch | 34 +
0019-Coverity-scan-fixes.patch | 100 +
...stream-build-breakage-of-iscsiuio-LDFLAGS.patch | 25 +
...replace-zero-length-array-with-flexible-a.patch | 44 +
0023-stop-using-Werror-for-now.patch | 56 +
0024-minor-service-file-updates.patch | 68 +
...initrd-option-to-set-run-from-initrd-hint.patch | 61 -
...csid-newroot-command-to-survive-switch_ro.patch | 158 -
...scsiuio-systemd-socket-activation-support.patch | 58 -
...-param-parsing-for-advanced-node-creation.patch | 337 -
...emd-service-files-add-iscsi.service-for-s.patch | 93 -
0050-iscsi-boot-related-service-file-updates.patch | 75 -
0058-iscsiuio-IPC-newroot-command.patch | 122 -
0059-iscsiuio-systemd-unit-files.patch | 53 -
...-for-autostart-sessions-if-iscsi-is-not-u.patch | 30 -
...f-setting-uid-gid-and-drop-supplementary-.patch | 68 -
0065-fix-hardened-build-of-iscsiuio.patch | 31 -
...tart-socket-listeners-on-iscsiadm-command.patch | 28 -
open-iscsi-build.patch | 30 -
open-iscsi-git.patch | 35445 -------------------
open-iscsi-libiscsi.patch | 20 +
open-iscsi-systemd.patch | 110 +-
open-iscsi.spec | 261 +-
34 files changed, 5507 insertions(+), 36711 deletions(-)
---
diff --git a/open-iscsi.spec b/open-iscsi.spec
index f0637fc..1bc271d 100644
--- a/open-iscsi.spec
+++ b/open-iscsi.spec
@@ -1,50 +1,58 @@
-# Conditional build:
-%bcond_without dynamic # link utilities dynamically
#
-%define ver 2.0
-%define subver 873
+# Conditional build:
+%bcond_without python2 # CPython 2.x module
+%bcond_without python3 # CPython 3.x module
+
Summary: iSCSI - SCSI over IP
Summary(pl.UTF-8): iSCSI - SCSI po IP
Name: open-iscsi
-Version: %{ver}.%{subver}
-Release: 5
+Version: 2.1.4
+Release: 1
License: GPL v2
Group: Networking/Daemons
-Source0: http://www.open-iscsi.org/bits/%{name}-%{ver}-%{subver}.tar.gz
-# Source0-md5: 8b8316d7c9469149a6cc6234478347f7
+#Source0Download: https://github.com/open-iscsi/open-iscsi/releases
+Source0: https://github.com/open-iscsi/open-iscsi/archive/%{version}/%{name}-%{version}.tar.gz
+# Source0-md5: e17f1924c1d64342773eae630e15c519
Source1: %{name}.init
Source2: %{name}.sysconfig
Source3: %{name}-devices.init
Source4: iscsiuio.logrotate
-Patch0: %{name}-git.patch
-Patch1: %{name}-build.patch
-Patch2: %{name}-systemd.patch
-Patch32: 0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch
-Patch35: 0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch
-Patch36: 0047-iscsiuio-systemd-socket-activation-support.patch
-Patch37: 0048-iscsiadm-param-parsing-for-advanced-node-creation.patch
-Patch38: 0049-update-systemd-service-files-add-iscsi.service-for-s.patch
-Patch39: 0050-iscsi-boot-related-service-file-updates.patch
-Patch40: 0058-iscsiuio-IPC-newroot-command.patch
-Patch41: 0059-iscsiuio-systemd-unit-files.patch
-Patch42: 0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch
-Patch43: 0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch
-Patch44: 0065-fix-hardened-build-of-iscsiuio.patch
-Patch45: 0066-start-socket-listeners-on-iscsiadm-command.patch
-URL: http://www.open-iscsi.org/
+# Fedora patches
+Patch1: 0001-unit-file-tweaks.patch
+# idmb_rec_write refactoring skipped, see 75c46b011d7485a4b5676d824c7f3cdea2076f49
+Patch5: 0005-update-initscripts-and-docs.patch
+# use-var-for-config, use-red-hat-for-name skipped
+Patch8: 0008-libiscsi.patch
+Patch9: 0009-Add-macros-to-release-GIL-lock.patch
+Patch10: 0010-libiscsi-introduce-sessions-API.patch
+Patch11: 0011-libiscsi-fix-discovery-request-timeout-regression.patch
+Patch12: 0012-libiscsi-format-security-build-errors.patch
+Patch13: 0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch
+Patch14: 0014-libiscsi-fix-build-against-latest-upstream-again.patch
+Patch15: 0015-remove-the-offload-boot-supported-ifdef.patch
+Patch16: 0016-Revert-iscsiadm-return-error-when-login-fails.patch
+# dont-install-scripts, use-var-lib-iscsi-in-libopeniscsiusr skipped
+Patch19: 0019-Coverity-scan-fixes.patch
+Patch20: 0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch
+# use-Red-Hat-version-string-to-match-RPM-package-vers skipped
+Patch22: 0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch
+Patch23: 0023-stop-using-Werror-for-now.patch
+Patch24: 0024-minor-service-file-updates.patch
+Patch25: 0001-Remove-dependences-from-iscsi-init.service.patch
+# PLD specific
+Patch100: %{name}-systemd.patch
+Patch101: %{name}-libiscsi.patch
+URL: https://www.open-iscsi.com/
BuildRequires: kmod-devel
+BuildRequires: open-isns-devel
BuildRequires: openssl-devel
-BuildRequires: rpmbuild(macros) >= 1.671
-%if %{with dynamic}
-BuildRequires: openslp-devel
-BuildRequires: sed >= 4.0
-Requires: openslp >= 2.0.0
-%else
-BuildRequires: glibc-static
-BuildRequires: openslp-static
-%endif
+%{?with_python2:BuildRequires: python-devel >= 1:2.5}
+%{?with_python3:BuildRequires: python3-devel >= 1:3.2}
+BuildRequires: rpm-pythonprov
+BuildRequires: rpmbuild(macros) >= 1.714
Requires(post,preun): /sbin/chkconfig
Requires(post,preun,postun): systemd-units >= 38
+Requires: %{name}-libs = %{version}-%{release}
Requires: rc-scripts
Requires: systemd-units >= 38
Suggests: multipath-tools
@@ -70,27 +78,74 @@ Protokół iSCSI jest zdefiniowany przez IETF do składowania IP. Więcej
informacji o protokole iSCSI znajduje się w standardach IETF na
<http://www.ietf.org/>.
+%package libs
+Summary: Open-iSCSI shared libraries
+Summary(pl.UTF-8): Biblioteki współdzielone Open-iSCSI
+Group: Libraries
+
+%description libs
+Open-iSCSI shared libraries.
+
+%description libs -l pl.UTF-8
+Biblioteki współdzielone Open-iSCSI.
+
+%package devel
+Summary: Header files for Open-iSCSI libraries
+Summary(pl.UTF-8): Pliki nagłówkowe bibliotek Open-iSCSI
+Group: Development/Libraries
+Requires: %{name}-libs = %{version}-%{release}
+
+%description devel
+Header files for Open-iSCSI libraries.
+
+%description devel -l pl.UTF-8
+Pliki nagłówkowe bibliotek Open-iSCSI.
+
+%package -n python-pyiscsi
+Summary: Python 2 interface to Open-iSCSI library
+Summary(pl.UTF-8): Interfejs Pythona 2 do biblioteki Open-iSCSI
+Group: Libraries/Python
+Requires: %{name}-libs = %{version}-%{release}
+
+%description -n python-pyiscsi
+Python 2 interface to Open-iSCSI library.
+
+%description -n python-pyiscsi -l pl.UTF-8
+Interfejs Pythona 2 do biblioteki Open-iSCSI.
+
+%package -n python3-pyiscsi
+Summary: Python 3 interface to Open-iSCSI library
+Summary(pl.UTF-8): Interfejs Pythona 3 do biblioteki Open-iSCSI
+Group: Libraries/Python
+Requires: %{name}-libs = %{version}-%{release}
+
+%description -n python3-pyiscsi
+Python 3 interface to Open-iSCSI library.
+
+%description -n python3-pyiscsi -l pl.UTF-8
+Interfejs Pythona 3 do biblioteki Open-iSCSI.
+
%prep
-%setup -q -n %{name}-%{ver}-%{subver}
-%patch0 -p1
-%patch32 -p1
-%patch35 -p1
-%patch36 -p1
-%patch37 -p1
-%patch38 -p1
-%patch39 -p1
-%patch40 -p1
-%patch41 -p1
-%patch42 -p1
-%patch43 -p1
-%patch44 -p1
-%patch45 -p1
+%setup -q
%patch1 -p1
-%patch2 -p1
-
-%if %{with dynamic}
-sed -i -e 's/-static //' usr/Makefile
-%endif
+%patch5 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch19 -p1
+%patch20 -p1
+%patch22 -p1
+%patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch100 -p1
+%patch101 -p1
%build
cd iscsiuio
@@ -100,47 +155,67 @@ cd iscsiuio
%{__autoheader}
%{__automake}
%configure
+cd ..
-cd ../utils/open-isns
-%configure \
- --with-slp \
- --without-security
-cd ../..
%{__make} \
CC="%{__cc}" \
- OPTFLAGS="%{rpmcflags} %{rpmcppflags} -DUSE_KMOD -lkmod" \
- IPC_FLAGS="-DNETLINK_ISCSI=8 -D_GNU_SOURCE" \
+ OPTFLAGS="%{rpmcflags} %{rpmcppflags}" \
+ SED=sed \
KSUBLEVEL=0
+cd libiscsi
+%if %{with python2}
+%py_build
+%endif
+%if %{with python3}
+%py3_build
+%endif
+
%install
rm -rf $RPM_BUILD_ROOT
install -d $RPM_BUILD_ROOT%{_sysconfdir}/iscsi/{nodes,send_targets,static,isns,slp,ifaces} \
$RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d} \
$RPM_BUILD_ROOT%{systemdunitdir} \
- $RPM_BUILD_ROOT/lib/systemd/pld-helpers.d
+ $RPM_BUILD_ROOT{/sbin,/lib/systemd/pld-helpers.d}
-%{__make} install_programs install_doc install_etc \
+%{__make} -j1 install_programs install_doc install_etc install_libopeniscsiusr \
DESTDIR=$RPM_BUILD_ROOT
:> $RPM_BUILD_ROOT%{_sysconfdir}/iscsi/initiatorname.iscsi
install %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/iscsid
-install %{SOURCE2} $RPM_BUILD_ROOT/etc/sysconfig/iscsi
+cp -p %{SOURCE2} $RPM_BUILD_ROOT/etc/sysconfig/iscsi
install %{SOURCE3} $RPM_BUILD_ROOT/etc/rc.d/init.d/iscsi
-install %{SOURCE4} $RPM_BUILD_ROOT/etc/logrotate.d/iscsiuio
+cp -p %{SOURCE4} $RPM_BUILD_ROOT/etc/logrotate.d/iscsiuio
install usr/iscsistart $RPM_BUILD_ROOT%{_sbindir}
-install doc/iscsistart.8 $RPM_BUILD_ROOT%{_mandir}/man8
-install doc/iscsi-iname.8 $RPM_BUILD_ROOT%{_mandir}/man8
+cp -p doc/iscsistart.8 $RPM_BUILD_ROOT%{_mandir}/man8
+#install doc/iscsi-iname.8 $RPM_BUILD_ROOT%{_mandir}/man8
-install etc/systemd/iscsi.service $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsid.service $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsid.socket $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsiuio.service $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsiuio.socket $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi-init.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi-onboot.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi-shutdown.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsid.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsid.socket $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsiuio.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsiuio.socket $RPM_BUILD_ROOT%{systemdunitdir}
install etc/systemd/iscsi-mark-root-nodes $RPM_BUILD_ROOT/lib/systemd/pld-helpers.d
+# rename to resolve conflict with already existing libiscsi from libiscsi.spec
+install -p libiscsi/libopeniscsi.so.0 $RPM_BUILD_ROOT%{_libdir}
+ln -sf libopeniscsi.so.0 $RPM_BUILD_ROOT%{_libdir}/libopeniscsi.so
+cp -p libiscsi/libiscsi.h $RPM_BUILD_ROOT%{_includedir}/libopeniscsi.h
+
+cd libiscsi
+%if %{with python2}
+%py_install
+%endif
+%if %{with python3}
+%py3_install
+%endif
+
%clean
rm -rf $RPM_BUILD_ROOT
@@ -155,7 +230,7 @@ fi
/sbin/chkconfig --add iscsi
/sbin/chkconfig --add iscsid
NORESTART=1
-%systemd_post iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket
+%systemd_post iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket iscsi-onboot.service iscsi-init.service iscsi-shutdown.service
%preun
if [ "$1" = "0" ]; then
@@ -164,7 +239,7 @@ if [ "$1" = "0" ]; then
/sbin/chkconfig --del iscsid
/sbin/chkconfig --del iscsi
fi
-%systemd_preun iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket
+%systemd_preun iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket iscsi-onboot.service iscsi-init.service iscsi-shutdown.service
%postun
if [ "$1" = "0" ]; then
@@ -178,9 +253,12 @@ fi
/bin/systemctl --quiet enable iscsid.socket || :
/bin/systemctl --quiet enable iscsiuio.socket || :
+%post libs -p /sbin/ldconfig
+%postun libs -p /sbin/ldconfig
+
%files
%defattr(644,root,root,755)
-%doc Changelog README THANKS
+%doc Changelog README THANKS TODO
%dir %{_sysconfdir}/iscsi
%dir %{_sysconfdir}/iscsi/ifaces
%dir %{_sysconfdir}/iscsi/isns
@@ -195,20 +273,55 @@ fi
%attr(754,root,root) /etc/rc.d/init.d/iscsi
%attr(754,root,root) /etc/rc.d/init.d/iscsid
%{systemdunitdir}/iscsi.service
+%{systemdunitdir}/iscsi-init.service
+%{systemdunitdir}/iscsi-onboot.service
+%{systemdunitdir}/iscsi-shutdown.service
%{systemdunitdir}/iscsid.service
%{systemdunitdir}/iscsid.socket
%{systemdunitdir}/iscsiuio.service
%{systemdunitdir}/iscsiuio.socket
%attr(755,root,root) /lib/systemd/pld-helpers.d/iscsi-mark-root-nodes
+%attr(755,root,root) %{_sbindir}/iscsi-gen-initiatorname
%attr(755,root,root) %{_sbindir}/iscsi-iname
+%attr(755,root,root) %{_sbindir}/iscsi_discovery
+%attr(755,root,root) %{_sbindir}/iscsi_fw_login
+%attr(755,root,root) %{_sbindir}/iscsi_offload
%attr(755,root,root) %{_sbindir}/iscsiadm
%attr(755,root,root) %{_sbindir}/iscsid
%attr(755,root,root) %{_sbindir}/iscsistart
-%attr(755,root,root) %{_sbindir}/iscsi_discovery
%attr(755,root,root) %{_sbindir}/iscsiuio
%{_mandir}/man8/iscsi-iname.8*
%{_mandir}/man8/iscsi_discovery.8*
+%{_mandir}/man8/iscsi_fw_login.8*
%{_mandir}/man8/iscsiadm.8*
%{_mandir}/man8/iscsid.8*
%{_mandir}/man8/iscsistart.8*
%{_mandir}/man8/iscsiuio.8*
+
+%files libs
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libopeniscsi.so.0
+%attr(755,root,root) %{_libdir}/libopeniscsiusr.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libopeniscsiusr.so.0
+
+%files devel
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libopeniscsi.so
+%attr(755,root,root) %{_libdir}/libopeniscsiusr.so
+%{_includedir}/libopeniscsi.h
+%{_includedir}/libopeniscsiusr*.h
+%{_pkgconfigdir}/libopeniscsiusr.pc
+
+%if %{with python2}
+%files -n python-pyiscsi
+%defattr(644,root,root,755)
+%attr(755,root,root) %{py_sitedir}/libiscsi.so
+%{py_sitedir}/PyIscsi-1.0-py*.egg-info
+%endif
+
+%if %{with python3}
+%files -n python3-pyiscsi
+%defattr(644,root,root,755)
+%attr(755,root,root) %{py3_sitedir}/libiscsi.cpython-*.so
+%{py3_sitedir}/PyIscsi-1.0-py*.egg-info
+%endif
diff --git a/0001-Remove-dependences-from-iscsi-init.service.patch b/0001-Remove-dependences-from-iscsi-init.service.patch
new file mode 100644
index 0000000..66c4cc4
--- /dev/null
+++ b/0001-Remove-dependences-from-iscsi-init.service.patch
@@ -0,0 +1,28 @@
+From 432bbf979ee66ee29bb92e35fd6e3ffb948563e3 Mon Sep 17 00:00:00 2001
+From: Lee Duncan <lduncan at suse.com>
+Date: Wed, 29 Sep 2021 11:48:16 -0700
+Subject: [PATCH] Remove dependences from iscsi-init.service
+
+Since iscsid.service depends on it but disables
+default dependencies, iscsi-init.service must
+also disable default dependencies, or a dependency
+loop can be created.
+---
+ etc/systemd/iscsi-init.service | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/etc/systemd/iscsi-init.service b/etc/systemd/iscsi-init.service
+index e058ff0..eab4ff2 100644
+--- a/etc/systemd/iscsi-init.service
++++ b/etc/systemd/iscsi-init.service
+@@ -1,6 +1,7 @@
+ [Unit]
+ Description=One time configuration for iscsi.service
+ ConditionPathExists=!/etc/iscsi/initiatorname.iscsi
++DefaultDependencies=no
+ Before=iscsid.service
+
+ [Service]
+--
+2.33.0
+
diff --git a/0001-unit-file-tweaks.patch b/0001-unit-file-tweaks.patch
new file mode 100644
index 0000000..743dccd
--- /dev/null
+++ b/0001-unit-file-tweaks.patch
@@ -0,0 +1,175 @@
+From fd538429be486d057b092e3b9c148add2c5ea9c2 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Tue, 4 Jun 2019 13:23:32 -0700
+Subject: [PATCH 1/1] unit file tweaks
+
+---
+ etc/systemd/iscsi-mark-root-nodes | 34 ++++++++++++++++++++++++++++++
+ etc/systemd/iscsi-onboot.service | 15 +++++++++++++
+ etc/systemd/iscsi-shutdown.service | 15 +++++++++++++
+ etc/systemd/iscsi.service | 16 +++++++-------
+ etc/systemd/iscsid.service | 3 +--
+ etc/systemd/iscsiuio.service | 4 +---
+ 6 files changed, 74 insertions(+), 13 deletions(-)
+ create mode 100755 etc/systemd/iscsi-mark-root-nodes
+ create mode 100644 etc/systemd/iscsi-onboot.service
+ create mode 100644 etc/systemd/iscsi-shutdown.service
+
+diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes
+new file mode 100755
+index 0000000..9d48805
+--- /dev/null
++++ b/etc/systemd/iscsi-mark-root-nodes
+@@ -0,0 +1,34 @@
++#!/bin/bash
++
++ISCSIADM=/usr/sbin/iscsiadm
++start_iscsid=0
++start_iscsiuio=0
++
++while read t num p target flash; do
++ # strip tag number from portal, keep "ip:port"
++ portal=${p%,*}
++ transport=${t%:}
++
++ # use session number to find the iface name in use
++ num=${num#[}; num=${num%]}
++ iface=$(iscsiadm -m session -r $num | grep iface.iscsi_ifacename | cut -d= -f2)
++
++ $ISCSIADM -m node -p $portal -T $target -I $iface -o update -n node.startup -v onboot
++
++ start_iscsid=1
++
++ if [ "$transport" = bnx2i ] || [ "$transport" = qedi ]; then
++ start_iscsiuio=1
++ fi
++done < <( $ISCSIADM -m session )
++
++# force iscsid and iscsiuio to start if needed for
++# recovering sessions created in the initrd
++
++if [ "$start_iscsid" -eq 1 ]; then
++ systemctl --no-block start iscsid.service
++fi
++if [ "$start_iscsiuio" -eq 1 ]; then
++ systemctl --no-block start iscsiuio.service
++fi
++
+diff --git a/etc/systemd/iscsi-onboot.service b/etc/systemd/iscsi-onboot.service
+new file mode 100644
+index 0000000..42ced68
+--- /dev/null
++++ b/etc/systemd/iscsi-onboot.service
+@@ -0,0 +1,15 @@
++[Unit]
++Description=Special handling of early boot iSCSI sessions
++Documentation=man:iscsiadm(8) man:iscsid(8)
++DefaultDependencies=no
++RefuseManualStart=true
++Before=iscsi.service
++After=systemd-remount-fs.service
++ConditionDirectoryNotEmpty=/sys/class/iscsi_session
++
++[Service]
++Type=oneshot
++ExecStart=-/usr/libexec/iscsi-mark-root-nodes
++
++[Install]
++WantedBy=sysinit.target
+diff --git a/etc/systemd/iscsi-shutdown.service b/etc/systemd/iscsi-shutdown.service
+new file mode 100644
+index 0000000..caee933
+--- /dev/null
++++ b/etc/systemd/iscsi-shutdown.service
+@@ -0,0 +1,15 @@
++[Unit]
++Description=Logout off all iSCSI sessions on shutdown
++Documentation=man:iscsid(8) man:iscsiadm(8)
++DefaultDependencies=no
++Conflicts=shutdown.target
++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service
++Before=remote-fs-pre.target
++Wants=remote-fs-pre.target
++RefuseManualStop=yes
++
++[Service]
++Type=oneshot
++RemainAfterExit=true
++ExecStart=-/usr/bin/true
++ExecStop=-/usr/sbin/iscsiadm -m node --logoutall=all
+diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service
+index 5e394b9..175cb2c 100644
+--- a/etc/systemd/iscsi.service
++++ b/etc/systemd/iscsi.service
+@@ -1,18 +1,18 @@
+ [Unit]
+ Description=Login and scanning of iSCSI devices
+ Documentation=man:iscsiadm(8) man:iscsid(8)
+-Before=remote-fs.target
+-After=network-online.target iscsid.service
+-Requires=iscsid.socket iscsi-init.service
+-Wants=network-online.target
++DefaultDependencies=no
++Before=remote-fs-pre.target
++After=network.target network-online.target iscsid.service iscsiuio.service systemd-remount-fs.service
++Wants=remote-fs-pre.target iscsi-shutdown.service
++ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes
+
+ [Service]
+ Type=oneshot
+-ExecStart=/sbin/iscsiadm -m node --loginall=automatic -W
+-ExecStop=/sbin/iscsiadm -m node --logoutall=automatic
+-ExecStop=/sbin/iscsiadm -m node --logoutall=manual
+-SuccessExitStatus=21 15
+ RemainAfterExit=true
++ExecStart=-/usr/sbin/iscsiadm -m node --loginall=automatic
++ExecReload=-/usr/sbin/iscsiadm -m node --loginall=automatic
++SuccessExitStatus=21
+
+ [Install]
+ WantedBy=remote-fs.target
+diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service
+index 3fd7dd3..324c593 100644
+--- a/etc/systemd/iscsid.service
++++ b/etc/systemd/iscsid.service
+@@ -4,13 +4,12 @@ Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8)
+ DefaultDependencies=no
+ After=network-online.target iscsiuio.service iscsi-init.service
+ Before=remote-fs-pre.target
+-Wants=remote-fs-pre.target
+ Requires=iscsi-init.service
+
+ [Service]
+ Type=notify
+ NotifyAccess=main
+-ExecStart=/sbin/iscsid -f
++ExecStart=/usr/sbin/iscsid -f
+ KillMode=mixed
+ Restart=on-failure
+
+diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service
+index 923e019..fc0be93 100644
+--- a/etc/systemd/iscsiuio.service
++++ b/etc/systemd/iscsiuio.service
+@@ -2,17 +2,15 @@
+ Description=iSCSI UserSpace I/O driver
+ Documentation=man:iscsiuio(8)
+ DefaultDependencies=no
+-Conflicts=shutdown.target
+ Requires=iscsid.service
+ BindTo=iscsid.service
+ After=network.target
+ Before=remote-fs-pre.target iscsid.service
+-Wants=remote-fs-pre.target
+
+ [Service]
+ Type=notify
+ NotifyAccess=main
+-ExecStart=/sbin/iscsiuio -f
++ExecStart=/usr/sbin/iscsiuio -f
+ KillMode=mixed
+ Restart=on-failure
+
+--
+2.26.3
+
diff --git a/0005-update-initscripts-and-docs.patch b/0005-update-initscripts-and-docs.patch
new file mode 100644
index 0000000..7d487a5
--- /dev/null
+++ b/0005-update-initscripts-and-docs.patch
@@ -0,0 +1,134 @@
+From 97b1242450df25648d203acf7cc297cd46d10e8c Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech at redhat.com>
+Date: Mon, 19 Nov 2012 16:37:13 -0800
+Subject: [PATCH] update initscripts and docs
+
+---
+ README | 12 +++++-------
+ etc/iscsid.conf | 23 +++++++++++------------
+ usr/idbm.c | 4 ++++
+ 3 files changed, 20 insertions(+), 19 deletions(-)
+
+diff --git a/README b/README
+index 508c9d7..b62a14e 100644
+--- a/README
++++ b/README
+@@ -77,11 +77,6 @@ the cache sync command will fail.
+ - iscsiadm's -P 3 option will not print out scsi devices.
+ - iscsid will not automatically online devices.
+
+-You need to enable "Cryptographic API" under "Cryptographic options" in the
+-kernel config. And you must enable "CRC32c CRC algorithm" even if
+-you do not use header or data digests. They are the kernel options
+-CONFIG_CRYPTO and CONFIG_CRYPTO_CRC32C, respectively.
+-
+ The userspace components iscsid, iscsiadm and iscsistart require the
+ open-isns library, which can be found here:
+ https://github.com/gonzoleeman/open-isns/releases
+@@ -1163,11 +1158,11 @@ Red Hat or Fedora:
+ -----------------
+ To start open-iscsi in Red Hat/Fedora you can do:
+
+- systemctl start open-iscsi
++ systemctl start iscsi
+
+ To get open-iscsi to automatically start at run time you may have to
+ run:
+- systemctl enable open-iscsi
++ systemctl enable iscsi
+
+ And, to automatically mount a file system during startup
+ you must have the partition entry in /etc/fstab marked with the "_netdev"
+@@ -1370,6 +1365,9 @@ iscsid will only perform rediscovery when it gets a SCN from the server.
+ # linux-isns (SLES's iSNS server) where it sometimes does not send SCN
+ # events in the proper format, so they may not get handled.
+
++To set the startup value, so that nodes are not logged into automatically
++use the value "manual".
++
+ Examples
+ --------
+
+diff --git a/etc/iscsid.conf b/etc/iscsid.conf
+index f21ed3d..420145b 100644
+--- a/etc/iscsid.conf
++++ b/etc/iscsid.conf
+@@ -19,8 +19,8 @@
+ # the time then leave this attribute commented out.
+ #
+ # Default for Fedora and RHEL. (uncomment to activate).
+-# iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
+-#
++iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
++#
+ # Default if you are not using systemd (uncomment to activate)
+ # iscsid.startup = /usr/bin/service start iscsid
+
+@@ -41,8 +41,8 @@
+ # To request that the iscsi initd scripts startup a session set to "automatic".
+ # node.startup = automatic
+ #
+-# To manually startup the session set to "manual". The default is manual.
+-node.startup = manual
++# To manually startup the session set to "manual". The default is automatic.
++node.startup = automatic
+
+ # For "automatic" startup nodes, setting this to "Yes" will try logins on each
+ # available iface until one succeeds, and then stop. The default "No" will try
+@@ -271,28 +271,27 @@ node.conn[0].iscsi.MaxXmitDataSegmentLength = 0
+ discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768
+
+ # To allow the targets to control the setting of the digest checking,
+-# with the initiator requesting a preference of enabling the checking, uncomment# one or both of the following lines:
++# with the initiator requesting a preference of enabling the checking, uncomment
++# the following lines (Data digests are not supported.):
+ #node.conn[0].iscsi.HeaderDigest = CRC32C,None
+-#node.conn[0].iscsi.DataDigest = CRC32C,None
++
+ #
+ # To allow the targets to control the setting of the digest checking,
+ # with the initiator requesting a preference of disabling the checking,
+-# uncomment one or both of the following lines:
++# uncomment the following line:
+ #node.conn[0].iscsi.HeaderDigest = None,CRC32C
+-#node.conn[0].iscsi.DataDigest = None,CRC32C
+ #
+ # To enable CRC32C digest checking for the header and/or data part of
+-# iSCSI PDUs, uncomment one or both of the following lines:
++# iSCSI PDUs, uncomment the following line:
+ #node.conn[0].iscsi.HeaderDigest = CRC32C
+-#node.conn[0].iscsi.DataDigest = CRC32C
+ #
+ # To disable digest checking for the header and/or data part of
+-# iSCSI PDUs, uncomment one or both of the following lines:
++# iSCSI PDUs, uncomment the following line:
+ #node.conn[0].iscsi.HeaderDigest = None
+-#node.conn[0].iscsi.DataDigest = None
+ #
+ # The default is to never use DataDigests or HeaderDigests.
+ #
++node.conn[0].iscsi.HeaderDigest = None
+
+ # For multipath configurations, you may want more than one session to be
+ # created on each iface record. If node.session.nr_sessions is greater
+diff --git a/usr/idbm.c b/usr/idbm.c
+index f1e5c88..0f0f17a 100644
+--- a/usr/idbm.c
++++ b/usr/idbm.c
+@@ -566,9 +566,13 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
+ IDBM_SHOW, "None", "CRC32C", "CRC32C,None",
+ "None,CRC32C", num, 1);
+ sprintf(key, CONN_DATA_DIGEST, i);
++
++#if 0
++We do not support data digests
+ __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW,
+ "None", "CRC32C", "CRC32C,None",
+ "None,CRC32C", num, 1);
++#endif
+ sprintf(key, CONN_IFMARKER, i);
+ __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW,
+ "No", "Yes", num, 1);
+--
+2.26.2
+
diff --git a/0008-libiscsi.patch b/0008-libiscsi.patch
new file mode 100644
index 0000000..39d1a84
--- /dev/null
+++ b/0008-libiscsi.patch
@@ -0,0 +1,4014 @@
+From 8b4da8007ef59bbc833fed882ddae57bbcd51f1c Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Mon, 26 Jan 2015 12:57:11 -0800
+Subject: [PATCH] libiscsi
+
+---
+ Makefile | 2 +
+ libiscsi/Makefile | 65 +
+ libiscsi/libiscsi.c | 617 ++++++++
+ libiscsi/libiscsi.doxy | 1473 +++++++++++++++++++
+ libiscsi/libiscsi.h | 344 +++++
+ libiscsi/no_date_footer.html | 6 +
+ libiscsi/pylibiscsi.c | 709 +++++++++
+ libiscsi/setup.py | 9 +
+ libiscsi/tests/test_discovery_firmware.c | 53 +
+ libiscsi/tests/test_discovery_sendtargets.c | 60 +
+ libiscsi/tests/test_get_auth.c | 70 +
+ libiscsi/tests/test_get_initiator_name.c | 38 +
+ libiscsi/tests/test_get_network_config.c | 45 +
+ libiscsi/tests/test_login.c | 52 +
+ libiscsi/tests/test_logout.c | 51 +
+ libiscsi/tests/test_params.c | 103 ++
+ libiscsi/tests/test_set_auth.c | 58 +
+ usr/Makefile | 2 +-
+ usr/discovery.c | 5 +
+ usr/idbm.c | 6 +-
+ usr/idbm.h | 3 +
+ usr/iscsi_ipc.h | 2 +
+ 22 files changed, 3769 insertions(+), 4 deletions(-)
+ create mode 100644 libiscsi/Makefile
+ create mode 100644 libiscsi/libiscsi.c
+ create mode 100644 libiscsi/libiscsi.doxy
+ create mode 100644 libiscsi/libiscsi.h
+ create mode 100644 libiscsi/no_date_footer.html
+ create mode 100644 libiscsi/pylibiscsi.c
+ create mode 100644 libiscsi/setup.py
+ create mode 100644 libiscsi/tests/test_discovery_firmware.c
+ create mode 100644 libiscsi/tests/test_discovery_sendtargets.c
+ create mode 100644 libiscsi/tests/test_get_auth.c
+ create mode 100644 libiscsi/tests/test_get_initiator_name.c
+ create mode 100644 libiscsi/tests/test_get_network_config.c
+ create mode 100644 libiscsi/tests/test_login.c
+ create mode 100644 libiscsi/tests/test_logout.c
+ create mode 100644 libiscsi/tests/test_params.c
+ create mode 100644 libiscsi/tests/test_set_auth.c
+
+diff --git a/Makefile b/Makefile
+index 7b445a5..4ab091f 100644
+--- a/Makefile
++++ b/Makefile
+@@ -65,6 +65,7 @@ user: iscsiuio/Makefile
+ $(MAKE) -C usr
+ $(MAKE) -C utils
+ $(MAKE) -C iscsiuio
++ $(MAKE) -C libiscsi
+ @echo
+ @echo "Compilation complete Output file"
+ @echo "----------------------------------- ----------------"
+@@ -85,6 +86,7 @@ iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile
+ force: ;
+
+ clean:
++ $(MAKE) -C libiscsi clean
+ $(MAKE) -C utils/sysdeps clean
+ $(MAKE) -C utils/fwparam_ibft clean
+ $(MAKE) -C utils clean
+diff --git a/libiscsi/Makefile b/libiscsi/Makefile
+new file mode 100644
+index 0000000..53f9746
+--- /dev/null
++++ b/libiscsi/Makefile
+@@ -0,0 +1,65 @@
++# This Makefile will work only with GNU make.
++
++ifeq ($(TOPDIR),)
++ TOPDIR = ..
++endif
++
++OSNAME=$(shell uname -s)
++OPTFLAGS ?= -O2 -g
++WARNFLAGS ?= -Wall -Wstrict-prototypes
++CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \
++ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden
++LIB = libiscsi.so.0
++TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware
++TESTS += tests/test_login tests/test_logout tests/test_params
++TESTS += tests/test_get_network_config tests/test_get_initiator_name
++TESTS += tests/test_set_auth tests/test_get_auth
++
++COMMON_SRCS = sysdeps.o
++# sources shared between iscsid, iscsiadm and iscsistart
++ISCSI_LIB_SRCS = netlink.o transport.o cxgbi.o be2iscsi.o iscsi_timer.o initiator_common.o iscsi_err.o session_info.o iscsi_util.o io.o auth.o discovery.o login.o log.o md5.o sha1.o iface.o idbm.o sysfs.o iscsi_sysfs.o iscsi_net_util.o iscsid_req.o iser.o uip_mgmt_ipc.o
++FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sysfs.o
++
++# sources shared with the userspace utils, note we build these separately
++# to get PIC versions.
++COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS))
++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o)
++FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS))
++
++# Flags for the tests
++tests/% : CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I.
++
++all: lib tests html
++
++lib: $(LIB)
++tests: $(TESTS)
++
++common-objs/%.o: ../utils/sysdeps/%.c
++ mkdir -p common-objs
++ $(CC) $(CFLAGS) -c $< -o $@
++
++usr-objs/%.o: ../usr/%.c
++ mkdir -p usr-objs
++ $(CC) $(CFLAGS) -c $< -o $@
++
++fw-objs/%.o: ../utils/fwparam_ibft/%.c
++ mkdir -p fw-objs
++ $(CC) $(CFLAGS) -c $< -o $@
++
++$(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o
++ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr
++ ln -s -f $(LIB) libiscsi.so
++
++$(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB)
++
++html: libiscsi.h libiscsi.doxy
++ doxygen libiscsi.doxy
++
++clean:
++ rm -rf *.o common-objs usr-objs fw-objs libuip-objs libiscsi.so* \
++ .depend *~ html $(TESTS) tests/*~
++
++depend:
++ gcc $(CFLAGS) -M `ls *.c` > .depend
++
++-include .depend ../usr/.depend
+diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c
+new file mode 100644
+index 0000000..064e4b5
+--- /dev/null
++++ b/libiscsi/libiscsi.c
+@@ -0,0 +1,617 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at googlegroups.com
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published
++ * by the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * See the file COPYING included with this distribution for more details.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <sys/syslog.h>
++#include "libiscsi.h"
++#include "idbm.h"
++#include "discovery.h"
++#include "log.h"
++#include "sysfs.h"
++#include "iscsi_sysfs.h"
++#include "session_info.h"
++#include "iscsi_util.h"
++#include "sysdeps.h"
++#include "iface.h"
++#include "iscsi_proto.h"
++#include "fw_context.h"
++#include "iscsid_req.h"
++#include "iscsi_err.h"
++
++#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; }
++
++/* UGLY, not thread safe :( */
++static int sysfs_initialized = 0;
++
++struct libiscsi_context {
++ char error_str[256];
++ /* For get_parameter_helper() */
++ const char *parameter;
++ char *value;
++};
++
++static void libiscsi_log(int prio, void *priv, const char *fmt, va_list ap)
++{
++ struct libiscsi_context *context = priv;
++
++ if (prio > LOG_ERR) /* We are only interested in errors (or worse) */
++ return;
++
++ vsnprintf(context->error_str, sizeof(context->error_str), fmt, ap);
++}
++
++struct libiscsi_context *libiscsi_init(void)
++{
++ struct libiscsi_context *context;
++
++ context = calloc(1, sizeof *context);
++ if (!context)
++ return NULL;
++
++ log_init("libiscsi", 1024, libiscsi_log, context);
++ if (!sysfs_initialized) {
++ sysfs_init();
++ sysfs_initialized = 1;
++ }
++ increase_max_files();
++ if (idbm_init(NULL)) {
++ sysfs_cleanup();
++ free(context);
++ return NULL;
++ }
++
++ iface_setup_host_bindings();
++
++ return context;
++}
++
++void libiscsi_cleanup(struct libiscsi_context *context)
++{
++ idbm_terminate();
++ free_transports();
++ sysfs_cleanup();
++ free(context);
++}
++
++static void free_iface_list(struct list_head *ifaces)
++{
++ struct iface_rec *iface, *tmp_iface;
++
++ list_for_each_entry_safe(iface, tmp_iface, ifaces, list) {
++ list_del(&iface->list);
++ free(iface);
++ }
++}
++
++static void free_rec_list(struct list_head *rec_list)
++{
++ struct node_rec *rec, *tmp;
++
++ list_for_each_entry_safe(rec, tmp, rec_list, list) {
++ list_del(&rec->list);
++ free(rec);
++ }
++}
++
++int libiscsi_discover_sendtargets(struct libiscsi_context *context,
++ const char *address, int port,
++ const struct libiscsi_auth_info *auth_info,
++ int *nr_found, struct libiscsi_node **found_nodes)
++{
++ struct discovery_rec drec;
++ LIST_HEAD(bound_rec_list);
++ struct node_rec *rec;
++ int rc = 0, found = 0;
++
++ INIT_LIST_HEAD(&bound_rec_list);
++
++ if (nr_found)
++ *nr_found = 0;
++ if (found_nodes)
++ *found_nodes = NULL;
++
++ CHECK(libiscsi_verify_auth_info(context, auth_info))
++
++ /* Fill the drec struct with all needed info */
++ memset(&drec, 0, sizeof drec);
++ idbm_sendtargets_defaults(&drec.u.sendtargets);
++ drec.type = DISCOVERY_TYPE_SENDTARGETS;
++ strlcpy(drec.address, address, sizeof(drec.address));
++ drec.port = port ? port : ISCSI_LISTEN_PORT;
++ switch(auth_info ? auth_info->method : libiscsi_auth_none) {
++ case libiscsi_auth_chap:
++ drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP;
++ strlcpy(drec.u.sendtargets.auth.username,
++ auth_info->chap.username, AUTH_STR_MAX_LEN);
++ strlcpy((char *)drec.u.sendtargets.auth.password,
++ auth_info->chap.password, AUTH_STR_MAX_LEN);
++ drec.u.sendtargets.auth.password_length =
++ strlen((char *)drec.u.sendtargets.auth.password);
++ strlcpy(drec.u.sendtargets.auth.username_in,
++ auth_info->chap.reverse_username, AUTH_STR_MAX_LEN);
++ strlcpy((char *)drec.u.sendtargets.auth.password_in,
++ auth_info->chap.reverse_password, AUTH_STR_MAX_LEN);
++ drec.u.sendtargets.auth.password_in_length =
++ strlen((char *)drec.u.sendtargets.auth.password_in);
++ break;
++ }
++
++ CHECK(idbm_add_discovery(&drec))
++
++ CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets,
++ &drec, NULL, &bound_rec_list))
++
++ /* now add/update records */
++ list_for_each_entry(rec, &bound_rec_list, list) {
++ CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */))
++ found++;
++ }
++
++ if (nr_found)
++ *nr_found = found;
++
++ if (found_nodes && found) {
++ *found_nodes = calloc(found, sizeof **found_nodes);
++ if (*found_nodes == NULL) {
++ snprintf(context->error_str,
++ sizeof(context->error_str), strerror(ENOMEM));
++ rc = ENOMEM;
++ goto leave;
++ }
++ found = 0;
++ list_for_each_entry(rec, &bound_rec_list, list) {
++ strlcpy((*found_nodes)[found].name, rec->name,
++ LIBISCSI_VALUE_MAXLEN);
++ (*found_nodes)[found].tpgt = rec->tpgt;
++ strlcpy((*found_nodes)[found].address,
++ rec->conn[0].address, NI_MAXHOST);
++ (*found_nodes)[found].port = rec->conn[0].port;
++ strlcpy((*found_nodes)[found].iface,
++ rec->iface.name, LIBISCSI_VALUE_MAXLEN);
++ found++;
++ }
++ }
++
++leave:
++ free_rec_list(&bound_rec_list);
++ return rc;
++}
++
++int libiscsi_discover_firmware(struct libiscsi_context *context,
++ int *nr_found, struct libiscsi_node **found_nodes)
++{
++ struct list_head targets, ifaces, rec_list;
++ discovery_rec_t drec;
++ int rc = 0;
++
++ INIT_LIST_HEAD(&targets);
++ INIT_LIST_HEAD(&ifaces);
++ INIT_LIST_HEAD(&rec_list);
++
++ if (nr_found) {
++ *nr_found = 0;
++ }
++
++ if (found_nodes) {
++ *found_nodes = NULL;
++ }
++
++ rc = fw_get_targets(&targets);
++ if (rc) {
++ log_error("%s: Could not get list of targets from firmware "
++ "(err %d).\n", __func__, rc);
++ return rc;
++ }
++
++ CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets));
++
++ memset(&drec, 0, sizeof(drec));
++ drec.type = DISCOVERY_TYPE_FW;
++ rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list);
++ if (rc) {
++ log_error("%s: Could not determine target nodes from firmware "
++ "(err %d).\n", __func__, rc);
++ goto leave;
++ }
++
++ int node_count = 0;
++ struct list_head *pos;
++ list_for_each(pos, &rec_list) {
++ ++node_count;
++ }
++
++ struct libiscsi_node* new_nodes;
++ /* allocate enough space for all the nodes */
++ new_nodes = calloc(node_count, sizeof *new_nodes);
++ if (new_nodes == NULL) {
++ rc = ENOMEM;
++ log_error("%s: %s.\n", __func__, strerror(ENOMEM));
++ goto leave;
++ }
++
++ struct node_rec *rec;
++ struct libiscsi_node *new_node = new_nodes;
++ /* in one loop, add nodes to idbm and create libiscsi_node entries */
++ list_for_each_entry(rec, &rec_list, list) {
++ CHECK(idbm_add_node(rec, NULL, 1 /* overwrite */));
++
++ strlcpy(new_node->name, rec->name, LIBISCSI_VALUE_MAXLEN);
++ new_node->tpgt = rec->tpgt;
++ strlcpy(new_node->address, rec->conn[0].address, NI_MAXHOST);
++ new_node->port = rec->conn[0].port;
++ strlcpy(new_node->iface, rec->iface.name, LIBISCSI_VALUE_MAXLEN);
++
++ ++new_node;
++ }
++
++ /* update output parameters */
++ if (nr_found) {
++ *nr_found = node_count;
++ }
++ if (found_nodes) {
++ *found_nodes = new_nodes;
++ }
++
++leave:
++ fw_free_targets(&targets);
++
++ free_iface_list(&ifaces);
++ free_rec_list(&rec_list);
++
++ return rc;
++}
++
++int libiscsi_verify_auth_info(struct libiscsi_context *context,
++ const struct libiscsi_auth_info *auth_info)
++{
++ switch(auth_info ? auth_info->method : libiscsi_auth_none) {
++ case libiscsi_auth_none:
++ break;
++ case libiscsi_auth_chap:
++ if (!auth_info->chap.username[0]) {
++ strcpy(context->error_str, "Empty username");
++ return EINVAL;
++ }
++ if (!auth_info->chap.password[0]) {
++ strcpy(context->error_str, "Empty password");
++ return EINVAL;
++ }
++ if (auth_info->chap.reverse_username[0] &&
++ !auth_info->chap.reverse_password[0]) {
++ strcpy(context->error_str, "Empty reverse password");
++ return EINVAL;
++ }
++ break;
++ default:
++ sprintf(context->error_str,
++ "Invalid authentication method: %d",
++ (int)auth_info->method);
++ return EINVAL;
++ }
++ return 0;
++}
++
++int libiscsi_node_set_auth(struct libiscsi_context *context,
++ const struct libiscsi_node *node,
++ const struct libiscsi_auth_info *auth_info)
++{
++ int rc = 0;
++
++ CHECK(libiscsi_verify_auth_info(context, auth_info))
++
++ switch(auth_info ? auth_info->method : libiscsi_auth_none) {
++ case libiscsi_auth_none:
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.authmethod", "None"))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.username", ""))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.password", ""))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.username_in", ""))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.password_in", ""))
++ break;
++
++ case libiscsi_auth_chap:
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.authmethod", "CHAP"))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.username",
++ auth_info->chap.username))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.password",
++ auth_info->chap.password))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.username_in",
++ auth_info->chap.reverse_username))
++ CHECK(libiscsi_node_set_parameter(context, node,
++ "node.session.auth.password_in",
++ auth_info->chap.reverse_password))
++ break;
++ }
++leave:
++ return rc;
++}
++
++int libiscsi_node_get_auth(struct libiscsi_context *context,
++ const struct libiscsi_node *node,
++ struct libiscsi_auth_info *auth_info)
++{
++ int rc = 0;
++ char value[LIBISCSI_VALUE_MAXLEN];
++
++ memset(auth_info, 0, sizeof *auth_info);
++
++ CHECK(libiscsi_node_get_parameter(context, node,
++ "node.session.auth.authmethod", value))
++
++ if (!strcmp(value, "None")) {
++ auth_info->method = libiscsi_auth_none;
++ } else if (!strcmp(value, "CHAP")) {
++ auth_info->method = libiscsi_auth_chap;
++ CHECK(libiscsi_node_get_parameter(context, node,
++ "node.session.auth.username",
++ auth_info->chap.username))
++ CHECK(libiscsi_node_get_parameter(context, node,
++ "node.session.auth.password",
++ auth_info->chap.password))
++ CHECK(libiscsi_node_get_parameter(context, node,
++ "node.session.auth.username_in",
++ auth_info->chap.reverse_username))
++ CHECK(libiscsi_node_get_parameter(context, node,
++ "node.session.auth.password_in",
++ auth_info->chap.reverse_password))
++ } else {
++ snprintf(context->error_str, sizeof(context->error_str),
++ "unknown authentication method: %s", value);
++ rc = EINVAL;
++ }
++leave:
++ return rc;
++}
++
++static void node_to_rec(const struct libiscsi_node *node,
++ struct node_rec *rec)
++{
++ memset(rec, 0, sizeof *rec);
++ idbm_node_setup_defaults(rec);
++ strlcpy(rec->name, node->name, TARGET_NAME_MAXLEN);
++ rec->tpgt = node->tpgt;
++ strlcpy(rec->conn[0].address, node->address, NI_MAXHOST);
++ rec->conn[0].port = node->port;
++}
++
++int login_helper(void *data, node_rec_t *rec)
++{
++ char *iface = (char*)data;
++ if (strcmp(iface, rec->iface.name))
++ /* different iface, skip it */
++ return -1;
++
++ int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
++ if (rc) {
++ iscsi_err_print_msg(rc);
++ rc = ENOTCONN;
++ }
++ return rc;
++}
++
++int libiscsi_node_login(struct libiscsi_context *context,
++ const struct libiscsi_node *node)
++{
++ int nr_found = 0, rc;
++
++ CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper,
++ (char *)node->name, node->tpgt,
++ (char *)node->address, node->port))
++ if (nr_found == 0) {
++ strcpy(context->error_str, "No such node");
++ rc = ENODEV;
++ }
++leave:
++ return rc;
++}
++
++static int logout_helper(void *data, struct session_info *info)
++{
++ int rc;
++ struct node_rec *rec = data;
++
++ if (!iscsi_match_session(rec, info))
++ /* Tell iscsi_sysfs_for_each_session this session was not a
++ match so that it will not increase nr_found. */
++ return -1;
++
++ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
++ if (rc) {
++ iscsi_err_print_msg(rc);
++ rc = EIO;
++ }
++
++ return rc;
++}
++
++int libiscsi_node_logout(struct libiscsi_context *context,
++ const struct libiscsi_node *node)
++{
++ int nr_found = 0, rc;
++ struct node_rec rec;
++
++ node_to_rec(node, &rec);
++ CHECK(iscsi_sysfs_for_each_session(&rec, &nr_found, logout_helper,0))
++ if (nr_found == 0) {
++ strcpy(context->error_str, "No matching session");
++ rc = ENODEV;
++ }
++leave:
++ return rc;
++}
++
++int libiscsi_node_set_parameter(struct libiscsi_context *context,
++ const struct libiscsi_node *node,
++ const char *parameter, const char *value)
++{
++ int nr_found = 0, rc;
++ struct user_param *param;
++ struct list_head params;
++
++ INIT_LIST_HEAD(¶ms);
++ param = idbm_alloc_user_param(parameter, value);
++ if (!param) {
++ rc = ENOMEM;
++ goto leave;
++ }
++ list_add_tail(¶ms, ¶m->list);
++
++ CHECK(idbm_for_each_iface(&nr_found, ¶ms, idbm_node_set_param,
++ (char *)node->name, node->tpgt,
++ (char *)node->address, node->port))
++ if (nr_found == 0) {
++ strcpy(context->error_str, "No such node");
++ rc = ENODEV;
++ }
++ free(param->name);
++ free(param);
++leave:
++ return rc;
++}
++
++static int get_parameter_helper(void *data, node_rec_t *rec)
++{
++ struct libiscsi_context *context = data;
++ recinfo_t *info;
++ int i;
++
++ info = idbm_recinfo_alloc(MAX_KEYS);
++ if (!info) {
++ snprintf(context->error_str, sizeof(context->error_str),
++ strerror(ENOMEM));
++ return ENOMEM;
++ }
++
++ idbm_recinfo_node(rec, info);
++
++ for (i = 0; i < MAX_KEYS; i++) {
++ if (!info[i].visible)
++ continue;
++
++ if (strcmp(context->parameter, info[i].name))
++ continue;
++
++ strlcpy(context->value, info[i].value, LIBISCSI_VALUE_MAXLEN);
++ break;
++ }
++
++ free(info);
++
++ if (i == MAX_KEYS) {
++ strcpy(context->error_str, "No such parameter");
++ return EINVAL;
++ }
++
++ return 0;
++}
++
++int libiscsi_node_get_parameter(struct libiscsi_context *context,
++ const struct libiscsi_node *node, const char *parameter, char *value)
++{
++ int nr_found = 0, rc = 0;
++
++ context->parameter = parameter;
++ context->value = value;
++
++ /* Note we assume there is only one interface, if not we will get
++ the value from the last interface iterated over!
++ This (multiple interfaces) can only happen if someone explicitly
++ created ones using iscsiadm. Even then this should not be a problem
++ as most settings should be the same independent of the iface. */
++ CHECK(idbm_for_each_iface(&nr_found, context, get_parameter_helper,
++ (char *)node->name, node->tpgt,
++ (char *)node->address, node->port))
++ if (nr_found == 0) {
++ strcpy(context->error_str, "No such node");
++ rc = ENODEV;
++ }
++leave:
++ return rc;
++}
++
++const char *libiscsi_get_error_string(struct libiscsi_context *context)
++{
++ /* Sometimes the core open-iscsi code does not give us an error
++ message */
++ if (!context->error_str[0])
++ return "Unknown error";
++
++ return context->error_str;
++}
++
++
++/************************** Utility functions *******************************/
++
++int libiscsi_get_firmware_network_config(
++ struct libiscsi_network_config *config)
++{
++ struct boot_context fw_entry;
++
++ if (!sysfs_initialized) {
++ sysfs_init();
++ sysfs_initialized = 1;
++ }
++
++ memset(config, 0, sizeof *config);
++ memset(&fw_entry, 0, sizeof fw_entry);
++ if (fw_get_entry(&fw_entry))
++ return ENODEV;
++
++ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0;
++ strlcpy(config->iface_name, fw_entry.iface, LIBISCSI_VALUE_MAXLEN);
++ strlcpy(config->mac_address, fw_entry.mac, LIBISCSI_VALUE_MAXLEN);
++ strlcpy(config->ip_address, fw_entry.ipaddr, LIBISCSI_VALUE_MAXLEN);
++ strlcpy(config->netmask, fw_entry.mask, LIBISCSI_VALUE_MAXLEN);
++ strlcpy(config->gateway, fw_entry.gateway, LIBISCSI_VALUE_MAXLEN);
++ strlcpy(config->primary_dns, fw_entry.primary_dns, LIBISCSI_VALUE_MAXLEN);
++ strlcpy(config->secondary_dns, fw_entry.secondary_dns, LIBISCSI_VALUE_MAXLEN);
++ return 0;
++}
++
++int libiscsi_get_firmware_initiator_name(char *initiatorname)
++{
++ struct boot_context fw_entry;
++
++ if (!sysfs_initialized) {
++ sysfs_init();
++ sysfs_initialized = 1;
++ }
++
++ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN);
++ memset(&fw_entry, 0, sizeof fw_entry);
++ if (fw_get_entry(&fw_entry))
++ return ENODEV;
++
++ strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN);
++
++ return 0;
++}
+diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy
+new file mode 100644
+index 0000000..7a5ff7f
+--- /dev/null
++++ b/libiscsi/libiscsi.doxy
+@@ -0,0 +1,1473 @@
++# Doxyfile 1.5.7.1
++
++# This file describes the settings to be used by the documentation system
++# doxygen (www.doxygen.org) for a project
++#
++# All text after a hash (#) is considered a comment and will be ignored
++# The format is:
++# TAG = value [value, ...]
++# For lists items can also be appended using:
++# TAG += value [value, ...]
++# Values that contain spaces should be placed between quotes (" ")
++
++#---------------------------------------------------------------------------
++# Project related configuration options
++#---------------------------------------------------------------------------
++
++# This tag specifies the encoding used for all characters in the config file
++# that follow. The default is UTF-8 which is also the encoding used for all
++# text before the first occurrence of this tag. Doxygen uses libiconv (or the
++# iconv built into libc) for the transcoding. See
++# http://www.gnu.org/software/libiconv for the list of possible encodings.
++
++DOXYFILE_ENCODING = UTF-8
++
++# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
++# by quotes) that should identify the project.
++
++PROJECT_NAME = libiscsi
++
++# The PROJECT_NUMBER tag can be used to enter a project or revision number.
++# This could be handy for archiving the generated documentation or
++# if some version control system is used.
++
++PROJECT_NUMBER =
++
++# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
++# base path where the generated documentation will be put.
++# If a relative path is entered, it will be relative to the location
++# where doxygen was started. If left blank the current directory will be used.
++
++OUTPUT_DIRECTORY =
++
++# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
++# 4096 sub-directories (in 2 levels) under the output directory of each output
++# format and will distribute the generated files over these directories.
++# Enabling this option can be useful when feeding doxygen a huge amount of
++# source files, where putting all generated files in the same directory would
++# otherwise cause performance problems for the file system.
++
++CREATE_SUBDIRS = NO
++
++# The OUTPUT_LANGUAGE tag is used to specify the language in which all
++# documentation generated by doxygen is written. Doxygen will use this
++# information to generate all constant output in the proper language.
++# The default language is English, other supported languages are:
++# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
++# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
++# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
++# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
++# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,
++# Spanish, Swedish, and Ukrainian.
++
++OUTPUT_LANGUAGE = English
++
++# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
++# include brief member descriptions after the members that are listed in
++# the file and class documentation (similar to JavaDoc).
++# Set to NO to disable this.
++
++BRIEF_MEMBER_DESC = YES
++
++# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
++# the brief description of a member or function before the detailed description.
++# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
++# brief descriptions will be completely suppressed.
++
++REPEAT_BRIEF = NO
++
++# This tag implements a quasi-intelligent brief description abbreviator
++# that is used to form the text in various listings. Each string
++# in this list, if found as the leading text of the brief description, will be
++# stripped from the text and the result after processing the whole list, is
++# used as the annotated text. Otherwise, the brief description is used as-is.
++# If left blank, the following values are used ("$name" is automatically
++# replaced with the name of the entity): "The $name class" "The $name widget"
++# "The $name file" "is" "provides" "specifies" "contains"
++# "represents" "a" "an" "the"
++
++ABBREVIATE_BRIEF =
++
++# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
++# Doxygen will generate a detailed section even if there is only a brief
++# description.
++
++ALWAYS_DETAILED_SEC = YES
++
++# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
++# inherited members of a class in the documentation of that class as if those
++# members were ordinary class members. Constructors, destructors and assignment
++# operators of the base classes will not be shown.
++
++INLINE_INHERITED_MEMB = NO
++
++# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
++# path before files name in the file list and in the header files. If set
++# to NO the shortest path that makes the file name unique will be used.
++
++FULL_PATH_NAMES = YES
++
++# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
++# can be used to strip a user-defined part of the path. Stripping is
++# only done if one of the specified strings matches the left-hand part of
++# the path. The tag can be used to show relative paths in the file list.
++# If left blank the directory from which doxygen is run is used as the
++# path to strip.
++
++STRIP_FROM_PATH =
++
++# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
++# the path mentioned in the documentation of a class, which tells
++# the reader which header file to include in order to use a class.
++# If left blank only the name of the header file containing the class
++# definition is used. Otherwise one should specify the include paths that
++# are normally passed to the compiler using the -I flag.
++
++STRIP_FROM_INC_PATH =
++
++# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
++# (but less readable) file names. This can be useful is your file systems
++# doesn't support long names like on DOS, Mac, or CD-ROM.
++
++SHORT_NAMES = NO
++
++# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
++# will interpret the first line (until the first dot) of a JavaDoc-style
++# comment as the brief description. If set to NO, the JavaDoc
++# comments will behave just like regular Qt-style comments
++# (thus requiring an explicit @brief command for a brief description.)
++
++JAVADOC_AUTOBRIEF = NO
++
++# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
++# interpret the first line (until the first dot) of a Qt-style
++# comment as the brief description. If set to NO, the comments
++# will behave just like regular Qt-style comments (thus requiring
++# an explicit \brief command for a brief description.)
++
++QT_AUTOBRIEF = NO
++
++# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
++# treat a multi-line C++ special comment block (i.e. a block of //! or ///
++# comments) as a brief description. This used to be the default behaviour.
++# The new default is to treat a multi-line C++ comment block as a detailed
++# description. Set this tag to YES if you prefer the old behaviour instead.
++
++MULTILINE_CPP_IS_BRIEF = NO
++
++# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
++# member inherits the documentation from any documented member that it
++# re-implements.
++
++INHERIT_DOCS = YES
++
++# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
++# a new page for each member. If set to NO, the documentation of a member will
++# be part of the file/class/namespace that contains it.
++
++SEPARATE_MEMBER_PAGES = NO
++
++# The TAB_SIZE tag can be used to set the number of spaces in a tab.
++# Doxygen uses this value to replace tabs by spaces in code fragments.
++
++TAB_SIZE = 8
++
++# This tag can be used to specify a number of aliases that acts
++# as commands in the documentation. An alias has the form "name=value".
++# For example adding "sideeffect=\par Side Effects:\n" will allow you to
++# put the command \sideeffect (or @sideeffect) in the documentation, which
++# will result in a user-defined paragraph with heading "Side Effects:".
++# You can put \n's in the value part of an alias to insert newlines.
++
++ALIASES =
++
++# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
++# sources only. Doxygen will then generate output that is more tailored for C.
++# For instance, some of the names that are used will be different. The list
++# of all members will be omitted, etc.
++
++OPTIMIZE_OUTPUT_FOR_C = YES
++
++# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
++# sources only. Doxygen will then generate output that is more tailored for
++# Java. For instance, namespaces will be presented as packages, qualified
++# scopes will look different, etc.
++
++OPTIMIZE_OUTPUT_JAVA = NO
++
++# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
++# sources only. Doxygen will then generate output that is more tailored for
++# Fortran.
++
++OPTIMIZE_FOR_FORTRAN = NO
++
++# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
++# sources. Doxygen will then generate output that is tailored for
++# VHDL.
++
++OPTIMIZE_OUTPUT_VHDL = NO
++
++# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
++# to include (a tag file for) the STL sources as input, then you should
++# set this tag to YES in order to let doxygen match functions declarations and
++# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
++# func(std::string) {}). This also make the inheritance and collaboration
++# diagrams that involve STL classes more complete and accurate.
++
++BUILTIN_STL_SUPPORT = NO
++
++# If you use Microsoft's C++/CLI language, you should set this option to YES to
++# enable parsing support.
++
++CPP_CLI_SUPPORT = NO
++
++# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
++# Doxygen will parse them like normal C++ but will assume all classes use public
++# instead of private inheritance when no explicit protection keyword is present.
++
++SIP_SUPPORT = NO
++
++# For Microsoft's IDL there are propget and propput attributes to indicate getter
++# and setter methods for a property. Setting this option to YES (the default)
++# will make doxygen to replace the get and set methods by a property in the
++# documentation. This will only work if the methods are indeed getting or
++# setting a simple type. If this is not the case, or you want to show the
++# methods anyway, you should set this option to NO.
++
++IDL_PROPERTY_SUPPORT = YES
++
++# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
++# tag is set to YES, then doxygen will reuse the documentation of the first
++# member in the group (if any) for the other members of the group. By default
++# all members of a group must be documented explicitly.
++
++DISTRIBUTE_GROUP_DOC = NO
++
++# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
++# the same type (for instance a group of public functions) to be put as a
++# subgroup of that type (e.g. under the Public Functions section). Set it to
++# NO to prevent subgrouping. Alternatively, this can be done per class using
++# the \nosubgrouping command.
++
++SUBGROUPING = YES
++
++# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
++# is documented as struct, union, or enum with the name of the typedef. So
++# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
++# with name TypeT. When disabled the typedef will appear as a member of a file,
++# namespace, or class. And the struct will be named TypeS. This can typically
++# be useful for C code in case the coding convention dictates that all compound
++# types are typedef'ed and only the typedef is referenced, never the tag name.
++
++TYPEDEF_HIDES_STRUCT = NO
++
++# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
++# determine which symbols to keep in memory and which to flush to disk.
++# When the cache is full, less often used symbols will be written to disk.
++# For small to medium size projects (<1000 input files) the default value is
++# probably good enough. For larger projects a too small cache size can cause
++# doxygen to be busy swapping symbols to and from disk most of the time
++# causing a significant performance penality.
++# If the system has enough physical memory increasing the cache will improve the
++# performance by keeping more symbols in memory. Note that the value works on
++# a logarithmic scale so increasing the size by one will rougly double the
++# memory usage. The cache size is given by this formula:
++# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
++# corresponding to a cache size of 2^16 = 65536 symbols
++
++SYMBOL_CACHE_SIZE = 0
++
++#---------------------------------------------------------------------------
++# Build related configuration options
++#---------------------------------------------------------------------------
++
++# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
++# documentation are documented, even if no documentation was available.
++# Private class members and static file members will be hidden unless
++# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
++
++EXTRACT_ALL = YES
++
++# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
++# will be included in the documentation.
++
++EXTRACT_PRIVATE = NO
++
++# If the EXTRACT_STATIC tag is set to YES all static members of a file
++# will be included in the documentation.
++
++EXTRACT_STATIC = NO
++
++# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
++# defined locally in source files will be included in the documentation.
++# If set to NO only classes defined in header files are included.
++
++EXTRACT_LOCAL_CLASSES = YES
++
++# This flag is only useful for Objective-C code. When set to YES local
++# methods, which are defined in the implementation section but not in
++# the interface are included in the documentation.
++# If set to NO (the default) only methods in the interface are included.
++
++EXTRACT_LOCAL_METHODS = NO
++
++# If this flag is set to YES, the members of anonymous namespaces will be
++# extracted and appear in the documentation as a namespace called
++# 'anonymous_namespace{file}', where file will be replaced with the base
++# name of the file that contains the anonymous namespace. By default
++# anonymous namespace are hidden.
++
++EXTRACT_ANON_NSPACES = NO
++
++# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
++# undocumented members of documented classes, files or namespaces.
++# If set to NO (the default) these members will be included in the
++# various overviews, but no documentation section is generated.
++# This option has no effect if EXTRACT_ALL is enabled.
++
++HIDE_UNDOC_MEMBERS = NO
++
++# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
++# undocumented classes that are normally visible in the class hierarchy.
++# If set to NO (the default) these classes will be included in the various
++# overviews. This option has no effect if EXTRACT_ALL is enabled.
++
++HIDE_UNDOC_CLASSES = NO
++
++# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
++# friend (class|struct|union) declarations.
++# If set to NO (the default) these declarations will be included in the
++# documentation.
++
++HIDE_FRIEND_COMPOUNDS = NO
++
++# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
++# documentation blocks found inside the body of a function.
++# If set to NO (the default) these blocks will be appended to the
++# function's detailed documentation block.
++
++HIDE_IN_BODY_DOCS = NO
++
++# The INTERNAL_DOCS tag determines if documentation
++# that is typed after a \internal command is included. If the tag is set
++# to NO (the default) then the documentation will be excluded.
++# Set it to YES to include the internal documentation.
++
++INTERNAL_DOCS = NO
++
++# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
++# file names in lower-case letters. If set to YES upper-case letters are also
++# allowed. This is useful if you have classes or files whose names only differ
++# in case and if your file system supports case sensitive file names. Windows
++# and Mac users are advised to set this option to NO.
++
++CASE_SENSE_NAMES = YES
++
++# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
++# will show members with their full class and namespace scopes in the
++# documentation. If set to YES the scope will be hidden.
++
++HIDE_SCOPE_NAMES = NO
++
++# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
++# will put a list of the files that are included by a file in the documentation
++# of that file.
++
++SHOW_INCLUDE_FILES = YES
++
++# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
++# is inserted in the documentation for inline members.
++
++INLINE_INFO = YES
++
++# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
++# will sort the (detailed) documentation of file and class members
++# alphabetically by member name. If set to NO the members will appear in
++# declaration order.
++
++SORT_MEMBER_DOCS = YES
++
++# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
++# brief documentation of file, namespace and class members alphabetically
++# by member name. If set to NO (the default) the members will appear in
++# declaration order.
++
++SORT_BRIEF_DOCS = NO
++
++# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
++# hierarchy of group names into alphabetical order. If set to NO (the default)
++# the group names will appear in their defined order.
++
++SORT_GROUP_NAMES = NO
++
++# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
++# sorted by fully-qualified names, including namespaces. If set to
++# NO (the default), the class list will be sorted only by class name,
++# not including the namespace part.
++# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
++# Note: This option applies only to the class list, not to the
++# alphabetical list.
++
++SORT_BY_SCOPE_NAME = NO
++
++# The GENERATE_TODOLIST tag can be used to enable (YES) or
++# disable (NO) the todo list. This list is created by putting \todo
++# commands in the documentation.
++
++GENERATE_TODOLIST = YES
++
++# The GENERATE_TESTLIST tag can be used to enable (YES) or
++# disable (NO) the test list. This list is created by putting \test
++# commands in the documentation.
++
++GENERATE_TESTLIST = YES
++
++# The GENERATE_BUGLIST tag can be used to enable (YES) or
++# disable (NO) the bug list. This list is created by putting \bug
++# commands in the documentation.
++
++GENERATE_BUGLIST = YES
++
++# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
++# disable (NO) the deprecated list. This list is created by putting
++# \deprecated commands in the documentation.
++
++GENERATE_DEPRECATEDLIST= YES
++
++# The ENABLED_SECTIONS tag can be used to enable conditional
++# documentation sections, marked by \if sectionname ... \endif.
++
++ENABLED_SECTIONS =
++
++# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
++# the initial value of a variable or define consists of for it to appear in
++# the documentation. If the initializer consists of more lines than specified
++# here it will be hidden. Use a value of 0 to hide initializers completely.
++# The appearance of the initializer of individual variables and defines in the
++# documentation can be controlled using \showinitializer or \hideinitializer
++# command in the documentation regardless of this setting.
++
++MAX_INITIALIZER_LINES = 30
++
++# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
++# at the bottom of the documentation of classes and structs. If set to YES the
++# list will mention the files that were used to generate the documentation.
++
++SHOW_USED_FILES = YES
++
++# If the sources in your project are distributed over multiple directories
++# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
++# in the documentation. The default is NO.
++
++SHOW_DIRECTORIES = NO
++
++# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
++# This will remove the Files entry from the Quick Index and from the
++# Folder Tree View (if specified). The default is YES.
++
++SHOW_FILES = YES
++
++# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
++# Namespaces page. This will remove the Namespaces entry from the Quick Index
++# and from the Folder Tree View (if specified). The default is YES.
++
++SHOW_NAMESPACES = YES
++
++# The FILE_VERSION_FILTER tag can be used to specify a program or script that
++# doxygen should invoke to get the current version for each file (typically from
++# the version control system). Doxygen will invoke the program by executing (via
++# popen()) the command <command> <input-file>, where <command> is the value of
++# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
++# provided by doxygen. Whatever the program writes to standard output
++# is used as the file version. See the manual for examples.
++
++FILE_VERSION_FILTER =
++
++# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
++# doxygen. The layout file controls the global structure of the generated output files
++# in an output format independent way. The create the layout file that represents
++# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
++# file name after the option, if omitted DoxygenLayout.xml will be used as the name
++# of the layout file.
++
++LAYOUT_FILE =
++
++#---------------------------------------------------------------------------
++# configuration options related to warning and progress messages
++#---------------------------------------------------------------------------
++
++# The QUIET tag can be used to turn on/off the messages that are generated
++# by doxygen. Possible values are YES and NO. If left blank NO is used.
++
++QUIET = YES
++
++# The WARNINGS tag can be used to turn on/off the warning messages that are
++# generated by doxygen. Possible values are YES and NO. If left blank
++# NO is used.
++
++WARNINGS = YES
++
++# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
++# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
++# automatically be disabled.
++
++WARN_IF_UNDOCUMENTED = YES
++
++# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
++# potential errors in the documentation, such as not documenting some
++# parameters in a documented function, or documenting parameters that
++# don't exist or using markup commands wrongly.
++
++WARN_IF_DOC_ERROR = YES
++
++# This WARN_NO_PARAMDOC option can be abled to get warnings for
++# functions that are documented, but have no documentation for their parameters
++# or return value. If set to NO (the default) doxygen will only warn about
++# wrong or incomplete parameter documentation, but not about the absence of
++# documentation.
++
++WARN_NO_PARAMDOC = NO
++
++# The WARN_FORMAT tag determines the format of the warning messages that
++# doxygen can produce. The string should contain the $file, $line, and $text
++# tags, which will be replaced by the file and line number from which the
++# warning originated and the warning text. Optionally the format may contain
++# $version, which will be replaced by the version of the file (if it could
++# be obtained via FILE_VERSION_FILTER)
++
++WARN_FORMAT = "$file:$line: $text"
++
++# The WARN_LOGFILE tag can be used to specify a file to which warning
++# and error messages should be written. If left blank the output is written
++# to stderr.
++
++WARN_LOGFILE =
++
++#---------------------------------------------------------------------------
++# configuration options related to the input files
++#---------------------------------------------------------------------------
++
++# The INPUT tag can be used to specify the files and/or directories that contain
++# documented source files. You may enter file names like "myfile.cpp" or
++# directories like "/usr/src/myproject". Separate the files or directories
++# with spaces.
++
++INPUT =
++
++# This tag can be used to specify the character encoding of the source files
++# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
++# also the default input encoding. Doxygen uses libiconv (or the iconv built
++# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
++# the list of possible encodings.
++
++INPUT_ENCODING = UTF-8
++
++# If the value of the INPUT tag contains directories, you can use the
++# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
++# and *.h) to filter out the source-files in the directories. If left
++# blank the following patterns are tested:
++# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
++# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
++
++FILE_PATTERNS =
++
++# The RECURSIVE tag can be used to turn specify whether or not subdirectories
++# should be searched for input files as well. Possible values are YES and NO.
++# If left blank NO is used.
++
++RECURSIVE = NO
++
++# The EXCLUDE tag can be used to specify files and/or directories that should
++# excluded from the INPUT source files. This way you can easily exclude a
++# subdirectory from a directory tree whose root is specified with the INPUT tag.
++
++EXCLUDE =
++
++# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
++# directories that are symbolic links (a Unix filesystem feature) are excluded
++# from the input.
++
++EXCLUDE_SYMLINKS = NO
++
++# If the value of the INPUT tag contains directories, you can use the
++# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
++# certain files from those directories. Note that the wildcards are matched
++# against the file with absolute path, so to exclude all test directories
++# for example use the pattern */test/*
++
++EXCLUDE_PATTERNS =
++
++# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
++# (namespaces, classes, functions, etc.) that should be excluded from the
++# output. The symbol name can be a fully qualified name, a word, or if the
++# wildcard * is used, a substring. Examples: ANamespace, AClass,
++# AClass::ANamespace, ANamespace::*Test
++
++EXCLUDE_SYMBOLS =
++
++# The EXAMPLE_PATH tag can be used to specify one or more files or
++# directories that contain example code fragments that are included (see
++# the \include command).
++
++EXAMPLE_PATH =
++
++# If the value of the EXAMPLE_PATH tag contains directories, you can use the
++# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
++# and *.h) to filter out the source-files in the directories. If left
++# blank all files are included.
++
++EXAMPLE_PATTERNS =
++
++# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
++# searched for input files to be used with the \include or \dontinclude
++# commands irrespective of the value of the RECURSIVE tag.
++# Possible values are YES and NO. If left blank NO is used.
++
++EXAMPLE_RECURSIVE = NO
++
++# The IMAGE_PATH tag can be used to specify one or more files or
++# directories that contain image that are included in the documentation (see
++# the \image command).
++
++IMAGE_PATH =
++
++# The INPUT_FILTER tag can be used to specify a program that doxygen should
++# invoke to filter for each input file. Doxygen will invoke the filter program
++# by executing (via popen()) the command <filter> <input-file>, where <filter>
++# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
++# input file. Doxygen will then use the output that the filter program writes
++# to standard output. If FILTER_PATTERNS is specified, this tag will be
++# ignored.
++
++INPUT_FILTER =
++
++# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
++# basis. Doxygen will compare the file name with each pattern and apply the
++# filter if there is a match. The filters are a list of the form:
++# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
++# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
++# is applied to all files.
++
++FILTER_PATTERNS =
++
++# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
++# INPUT_FILTER) will be used to filter the input files when producing source
++# files to browse (i.e. when SOURCE_BROWSER is set to YES).
++
++FILTER_SOURCE_FILES = NO
++
++#---------------------------------------------------------------------------
++# configuration options related to source browsing
++#---------------------------------------------------------------------------
++
++# If the SOURCE_BROWSER tag is set to YES then a list of source files will
++# be generated. Documented entities will be cross-referenced with these sources.
++# Note: To get rid of all source code in the generated output, make sure also
++# VERBATIM_HEADERS is set to NO.
++
++SOURCE_BROWSER = NO
++
++# Setting the INLINE_SOURCES tag to YES will include the body
++# of functions and classes directly in the documentation.
++
++INLINE_SOURCES = NO
++
++# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
++# doxygen to hide any special comment blocks from generated source code
++# fragments. Normal C and C++ comments will always remain visible.
++
++STRIP_CODE_COMMENTS = YES
++
++# If the REFERENCED_BY_RELATION tag is set to YES
++# then for each documented function all documented
++# functions referencing it will be listed.
++
++REFERENCED_BY_RELATION = NO
++
++# If the REFERENCES_RELATION tag is set to YES
++# then for each documented function all documented entities
++# called/used by that function will be listed.
++
++REFERENCES_RELATION = NO
++
++# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
++# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
++# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
++# link to the source code. Otherwise they will link to the documentstion.
++
++REFERENCES_LINK_SOURCE = YES
++
++# If the USE_HTAGS tag is set to YES then the references to source code
++# will point to the HTML generated by the htags(1) tool instead of doxygen
++# built-in source browser. The htags tool is part of GNU's global source
++# tagging system (see http://www.gnu.org/software/global/global.html). You
++# will need version 4.8.6 or higher.
++
++USE_HTAGS = NO
++
++# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
++# will generate a verbatim copy of the header file for each class for
++# which an include is specified. Set to NO to disable this.
++
++VERBATIM_HEADERS = YES
++
++#---------------------------------------------------------------------------
++# configuration options related to the alphabetical class index
++#---------------------------------------------------------------------------
++
++# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
++# of all compounds will be generated. Enable this if the project
++# contains a lot of classes, structs, unions or interfaces.
++
++ALPHABETICAL_INDEX = NO
++
++# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
++# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
++# in which this list will be split (can be a number in the range [1..20])
++
++COLS_IN_ALPHA_INDEX = 5
++
++# In case all classes in a project start with a common prefix, all
++# classes will be put under the same header in the alphabetical index.
++# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
++# should be ignored while generating the index headers.
++
++IGNORE_PREFIX =
++
++#---------------------------------------------------------------------------
++# configuration options related to the HTML output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
++# generate HTML output.
++
++GENERATE_HTML = YES
++
++# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
++# If a relative path is entered the value of OUTPUT_DIRECTORY will be
++# put in front of it. If left blank `html' will be used as the default path.
++
++HTML_OUTPUT = html
++
++# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
++# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
++# doxygen will generate files with .html extension.
++
++HTML_FILE_EXTENSION = .html
++
++# The HTML_HEADER tag can be used to specify a personal HTML header for
++# each generated HTML page. If it is left blank doxygen will generate a
++# standard header.
++
++HTML_HEADER =
++
++# The HTML_FOOTER tag can be used to specify a personal HTML footer for
++# each generated HTML page. If it is left blank doxygen will generate a
++# standard footer.
++
++HTML_FOOTER = no_date_footer.html
++
++# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
++# style sheet that is used by each HTML page. It can be used to
++# fine-tune the look of the HTML output. If the tag is left blank doxygen
++# will generate a default style sheet. Note that doxygen will try to copy
++# the style sheet file to the HTML output directory, so don't put your own
++# stylesheet in the HTML output directory as well, or it will be erased!
++
++HTML_STYLESHEET =
++
++# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
++# files or namespaces will be aligned in HTML using tables. If set to
++# NO a bullet list will be used.
++
++HTML_ALIGN_MEMBERS = YES
++
++# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
++# documentation will contain sections that can be hidden and shown after the
++# page has loaded. For this to work a browser that supports
++# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
++# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
++
++HTML_DYNAMIC_SECTIONS = NO
++
++# If the GENERATE_DOCSET tag is set to YES, additional index files
++# will be generated that can be used as input for Apple's Xcode 3
++# integrated development environment, introduced with OSX 10.5 (Leopard).
++# To create a documentation set, doxygen will generate a Makefile in the
++# HTML output directory. Running make will produce the docset in that
++# directory and running "make install" will install the docset in
++# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
++# it at startup.
++# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
++
++GENERATE_DOCSET = NO
++
++# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
++# feed. A documentation feed provides an umbrella under which multiple
++# documentation sets from a single provider (such as a company or product suite)
++# can be grouped.
++
++DOCSET_FEEDNAME = "Doxygen generated docs"
++
++# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
++# should uniquely identify the documentation set bundle. This should be a
++# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
++# will append .docset to the name.
++
++DOCSET_BUNDLE_ID = org.doxygen.Project
++
++# If the GENERATE_HTMLHELP tag is set to YES, additional index files
++# will be generated that can be used as input for tools like the
++# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
++# of the generated HTML documentation.
++
++GENERATE_HTMLHELP = NO
++
++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
++# be used to specify the file name of the resulting .chm file. You
++# can add a path in front of the file if the result should not be
++# written to the html output directory.
++
++CHM_FILE =
++
++# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
++# be used to specify the location (absolute path including file name) of
++# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
++# the HTML help compiler on the generated index.hhp.
++
++HHC_LOCATION =
++
++# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
++# controls if a separate .chi index file is generated (YES) or that
++# it should be included in the master .chm file (NO).
++
++GENERATE_CHI = NO
++
++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
++# is used to encode HtmlHelp index (hhk), content (hhc) and project file
++# content.
++
++CHM_INDEX_ENCODING =
++
++# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
++# controls whether a binary table of contents is generated (YES) or a
++# normal table of contents (NO) in the .chm file.
++
++BINARY_TOC = NO
++
++# The TOC_EXPAND flag can be set to YES to add extra items for group members
++# to the contents of the HTML help documentation and to the tree view.
++
++TOC_EXPAND = NO
++
++# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
++# are set, an additional index file will be generated that can be used as input for
++# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
++# HTML documentation.
++
++GENERATE_QHP = NO
++
++# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
++# be used to specify the file name of the resulting .qch file.
++# The path specified is relative to the HTML output folder.
++
++QCH_FILE =
++
++# The QHP_NAMESPACE tag specifies the namespace to use when generating
++# Qt Help Project output. For more information please see
++# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
++
++QHP_NAMESPACE = org.doxygen.Project
++
++# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
++# Qt Help Project output. For more information please see
++# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
++
++QHP_VIRTUAL_FOLDER = doc
++
++# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
++# be used to specify the location of Qt's qhelpgenerator.
++# If non-empty doxygen will try to run qhelpgenerator on the generated
++# .qhp file .
++
++QHG_LOCATION =
++
++# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
++# top of each HTML page. The value NO (the default) enables the index and
++# the value YES disables it.
++
++DISABLE_INDEX = NO
++
++# This tag can be used to set the number of enum values (range [1..20])
++# that doxygen will group on one line in the generated HTML documentation.
++
++ENUM_VALUES_PER_LINE = 4
++
++# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
++# structure should be generated to display hierarchical information.
++# If the tag value is set to FRAME, a side panel will be generated
++# containing a tree-like index structure (just like the one that
++# is generated for HTML Help). For this to work a browser that supports
++# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
++# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
++# probably better off using the HTML help feature. Other possible values
++# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
++# and Class Hierarchy pages using a tree view instead of an ordered list;
++# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
++# disables this behavior completely. For backwards compatibility with previous
++# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
++# respectively.
++
++GENERATE_TREEVIEW = NONE
++
++# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
++# used to set the initial width (in pixels) of the frame in which the tree
++# is shown.
++
++TREEVIEW_WIDTH = 250
++
++# Use this tag to change the font size of Latex formulas included
++# as images in the HTML documentation. The default is 10. Note that
++# when you change the font size after a successful doxygen run you need
++# to manually remove any form_*.png images from the HTML output directory
++# to force them to be regenerated.
++
++FORMULA_FONTSIZE = 10
++
++#---------------------------------------------------------------------------
++# configuration options related to the LaTeX output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
++# generate Latex output.
++
++GENERATE_LATEX = NO
++
++# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
++# If a relative path is entered the value of OUTPUT_DIRECTORY will be
++# put in front of it. If left blank `latex' will be used as the default path.
++
++LATEX_OUTPUT = latex
++
++# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
++# invoked. If left blank `latex' will be used as the default command name.
++
++LATEX_CMD_NAME = latex
++
++# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
++# generate index for LaTeX. If left blank `makeindex' will be used as the
++# default command name.
++
++MAKEINDEX_CMD_NAME = makeindex
++
++# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
++# LaTeX documents. This may be useful for small projects and may help to
++# save some trees in general.
++
++COMPACT_LATEX = NO
++
++# The PAPER_TYPE tag can be used to set the paper type that is used
++# by the printer. Possible values are: a4, a4wide, letter, legal and
++# executive. If left blank a4wide will be used.
++
++PAPER_TYPE = a4wide
++
++# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
++# packages that should be included in the LaTeX output.
++
++EXTRA_PACKAGES =
++
++# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
++# the generated latex document. The header should contain everything until
++# the first chapter. If it is left blank doxygen will generate a
++# standard header. Notice: only use this tag if you know what you are doing!
++
++LATEX_HEADER =
++
++# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
++# is prepared for conversion to pdf (using ps2pdf). The pdf file will
++# contain links (just like the HTML output) instead of page references
++# This makes the output suitable for online browsing using a pdf viewer.
++
++PDF_HYPERLINKS = YES
++
++# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
++# plain latex in the generated Makefile. Set this option to YES to get a
++# higher quality PDF documentation.
++
++USE_PDFLATEX = YES
++
++# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
++# command to the generated LaTeX files. This will instruct LaTeX to keep
++# running if errors occur, instead of asking the user for help.
++# This option is also used when generating formulas in HTML.
++
++LATEX_BATCHMODE = NO
++
++# If LATEX_HIDE_INDICES is set to YES then doxygen will not
++# include the index chapters (such as File Index, Compound Index, etc.)
++# in the output.
++
++LATEX_HIDE_INDICES = NO
++
++#---------------------------------------------------------------------------
++# configuration options related to the RTF output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
++# The RTF output is optimized for Word 97 and may not look very pretty with
++# other RTF readers or editors.
++
++GENERATE_RTF = NO
++
++# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
++# If a relative path is entered the value of OUTPUT_DIRECTORY will be
++# put in front of it. If left blank `rtf' will be used as the default path.
++
++RTF_OUTPUT = rtf
++
++# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
++# RTF documents. This may be useful for small projects and may help to
++# save some trees in general.
++
++COMPACT_RTF = NO
++
++# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
++# will contain hyperlink fields. The RTF file will
++# contain links (just like the HTML output) instead of page references.
++# This makes the output suitable for online browsing using WORD or other
++# programs which support those fields.
++# Note: wordpad (write) and others do not support links.
++
++RTF_HYPERLINKS = NO
++
++# Load stylesheet definitions from file. Syntax is similar to doxygen's
++# config file, i.e. a series of assignments. You only have to provide
++# replacements, missing definitions are set to their default value.
++
++RTF_STYLESHEET_FILE =
++
++# Set optional variables used in the generation of an rtf document.
++# Syntax is similar to doxygen's config file.
++
++RTF_EXTENSIONS_FILE =
++
++#---------------------------------------------------------------------------
++# configuration options related to the man page output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
++# generate man pages
++
++GENERATE_MAN = NO
++
++# The MAN_OUTPUT tag is used to specify where the man pages will be put.
++# If a relative path is entered the value of OUTPUT_DIRECTORY will be
++# put in front of it. If left blank `man' will be used as the default path.
++
++MAN_OUTPUT = man
++
++# The MAN_EXTENSION tag determines the extension that is added to
++# the generated man pages (default is the subroutine's section .3)
++
++MAN_EXTENSION = .3
++
++# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
++# then it will generate one additional man file for each entity
++# documented in the real man page(s). These additional files
++# only source the real man page, but without them the man command
++# would be unable to find the correct page. The default is NO.
++
++MAN_LINKS = NO
++
++#---------------------------------------------------------------------------
++# configuration options related to the XML output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_XML tag is set to YES Doxygen will
++# generate an XML file that captures the structure of
++# the code including all documentation.
++
++GENERATE_XML = NO
++
++# The XML_OUTPUT tag is used to specify where the XML pages will be put.
++# If a relative path is entered the value of OUTPUT_DIRECTORY will be
++# put in front of it. If left blank `xml' will be used as the default path.
++
++XML_OUTPUT = xml
++
++# The XML_SCHEMA tag can be used to specify an XML schema,
++# which can be used by a validating XML parser to check the
++# syntax of the XML files.
++
++XML_SCHEMA =
++
++# The XML_DTD tag can be used to specify an XML DTD,
++# which can be used by a validating XML parser to check the
++# syntax of the XML files.
++
++XML_DTD =
++
++# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
++# dump the program listings (including syntax highlighting
++# and cross-referencing information) to the XML output. Note that
++# enabling this will significantly increase the size of the XML output.
++
++XML_PROGRAMLISTING = YES
++
++#---------------------------------------------------------------------------
++# configuration options for the AutoGen Definitions output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
++# generate an AutoGen Definitions (see autogen.sf.net) file
++# that captures the structure of the code including all
++# documentation. Note that this feature is still experimental
++# and incomplete at the moment.
++
++GENERATE_AUTOGEN_DEF = NO
++
++#---------------------------------------------------------------------------
++# configuration options related to the Perl module output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_PERLMOD tag is set to YES Doxygen will
++# generate a Perl module file that captures the structure of
++# the code including all documentation. Note that this
++# feature is still experimental and incomplete at the
++# moment.
++
++GENERATE_PERLMOD = NO
++
++# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
++# the necessary Makefile rules, Perl scripts and LaTeX code to be able
++# to generate PDF and DVI output from the Perl module output.
++
++PERLMOD_LATEX = NO
++
++# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
++# nicely formatted so it can be parsed by a human reader. This is useful
++# if you want to understand what is going on. On the other hand, if this
++# tag is set to NO the size of the Perl module output will be much smaller
++# and Perl will parse it just the same.
++
++PERLMOD_PRETTY = YES
++
++# The names of the make variables in the generated doxyrules.make file
++# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
++# This is useful so different doxyrules.make files included by the same
++# Makefile don't overwrite each other's variables.
++
++PERLMOD_MAKEVAR_PREFIX =
++
++#---------------------------------------------------------------------------
++# Configuration options related to the preprocessor
++#---------------------------------------------------------------------------
++
++# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
++# evaluate all C-preprocessor directives found in the sources and include
++# files.
++
++ENABLE_PREPROCESSING = YES
++
++# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
++# names in the source code. If set to NO (the default) only conditional
++# compilation will be performed. Macro expansion can be done in a controlled
++# way by setting EXPAND_ONLY_PREDEF to YES.
++
++MACRO_EXPANSION = NO
++
++# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
++# then the macro expansion is limited to the macros specified with the
++# PREDEFINED and EXPAND_AS_DEFINED tags.
++
++EXPAND_ONLY_PREDEF = NO
++
++# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
++# in the INCLUDE_PATH (see below) will be search if a #include is found.
++
++SEARCH_INCLUDES = YES
++
++# The INCLUDE_PATH tag can be used to specify one or more directories that
++# contain include files that are not input files but should be processed by
++# the preprocessor.
++
++INCLUDE_PATH =
++
++# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
++# patterns (like *.h and *.hpp) to filter out the header-files in the
++# directories. If left blank, the patterns specified with FILE_PATTERNS will
++# be used.
++
++INCLUDE_FILE_PATTERNS =
++
++# The PREDEFINED tag can be used to specify one or more macro names that
++# are defined before the preprocessor is started (similar to the -D option of
++# gcc). The argument of the tag is a list of macros of the form: name
++# or name=definition (no spaces). If the definition and the = are
++# omitted =1 is assumed. To prevent a macro definition from being
++# undefined via #undef or recursively expanded use the := operator
++# instead of the = operator.
++
++PREDEFINED =
++
++# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
++# this tag can be used to specify a list of macro names that should be expanded.
++# The macro definition that is found in the sources will be used.
++# Use the PREDEFINED tag if you want to use a different macro definition.
++
++EXPAND_AS_DEFINED =
++
++# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
++# doxygen's preprocessor will remove all function-like macros that are alone
++# on a line, have an all uppercase name, and do not end with a semicolon. Such
++# function macros are typically used for boiler-plate code, and will confuse
++# the parser if not removed.
++
++SKIP_FUNCTION_MACROS = YES
++
++#---------------------------------------------------------------------------
++# Configuration::additions related to external references
++#---------------------------------------------------------------------------
++
++# The TAGFILES option can be used to specify one or more tagfiles.
++# Optionally an initial location of the external documentation
++# can be added for each tagfile. The format of a tag file without
++# this location is as follows:
++# TAGFILES = file1 file2 ...
++# Adding location for the tag files is done as follows:
++# TAGFILES = file1=loc1 "file2 = loc2" ...
++# where "loc1" and "loc2" can be relative or absolute paths or
++# URLs. If a location is present for each tag, the installdox tool
++# does not have to be run to correct the links.
++# Note that each tag file must have a unique name
++# (where the name does NOT include the path)
++# If a tag file is not located in the directory in which doxygen
++# is run, you must also specify the path to the tagfile here.
++
++TAGFILES =
++
++# When a file name is specified after GENERATE_TAGFILE, doxygen will create
++# a tag file that is based on the input files it reads.
++
++GENERATE_TAGFILE =
++
++# If the ALLEXTERNALS tag is set to YES all external classes will be listed
++# in the class index. If set to NO only the inherited external classes
++# will be listed.
++
++ALLEXTERNALS = NO
++
++# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
++# in the modules index. If set to NO, only the current project's groups will
++# be listed.
++
++EXTERNAL_GROUPS = YES
++
++# The PERL_PATH should be the absolute path and name of the perl script
++# interpreter (i.e. the result of `which perl').
++
++PERL_PATH = /usr/bin/perl
++
++#---------------------------------------------------------------------------
++# Configuration options related to the dot tool
++#---------------------------------------------------------------------------
++
++# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
++# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
++# or super classes. Setting the tag to NO turns the diagrams off. Note that
++# this option is superseded by the HAVE_DOT option below. This is only a
++# fallback. It is recommended to install and use dot, since it yields more
++# powerful graphs.
++
++CLASS_DIAGRAMS = YES
++
++# You can define message sequence charts within doxygen comments using the \msc
++# command. Doxygen will then run the mscgen tool (see
++# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
++# documentation. The MSCGEN_PATH tag allows you to specify the directory where
++# the mscgen tool resides. If left empty the tool is assumed to be found in the
++# default search path.
++
++MSCGEN_PATH =
++
++# If set to YES, the inheritance and collaboration graphs will hide
++# inheritance and usage relations if the target is undocumented
++# or is not a class.
++
++HIDE_UNDOC_RELATIONS = YES
++
++# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
++# available from the path. This tool is part of Graphviz, a graph visualization
++# toolkit from AT&T and Lucent Bell Labs. The other options in this section
++# have no effect if this option is set to NO (the default)
++
++HAVE_DOT = NO
++
++# By default doxygen will write a font called FreeSans.ttf to the output
++# directory and reference it in all dot files that doxygen generates. This
++# font does not include all possible unicode characters however, so when you need
++# these (or just want a differently looking font) you can specify the font name
++# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
++# which can be done by putting it in a standard location or by setting the
++# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
++# containing the font.
++
++DOT_FONTNAME = FreeSans
++
++# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
++# The default size is 10pt.
++
++DOT_FONTSIZE = 10
++
++# By default doxygen will tell dot to use the output directory to look for the
++# FreeSans.ttf font (which doxygen will put there itself). If you specify a
++# different font using DOT_FONTNAME you can set the path where dot
++# can find it using this tag.
++
++DOT_FONTPATH =
++
++# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
++# will generate a graph for each documented class showing the direct and
++# indirect inheritance relations. Setting this tag to YES will force the
++# the CLASS_DIAGRAMS tag to NO.
++
++CLASS_GRAPH = YES
++
++# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
++# will generate a graph for each documented class showing the direct and
++# indirect implementation dependencies (inheritance, containment, and
++# class references variables) of the class with other documented classes.
++
++COLLABORATION_GRAPH = YES
++
++# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
++# will generate a graph for groups, showing the direct groups dependencies
++
++GROUP_GRAPHS = YES
++
++# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
++# collaboration diagrams in a style similar to the OMG's Unified Modeling
++# Language.
++
++UML_LOOK = NO
++
++# If set to YES, the inheritance and collaboration graphs will show the
++# relations between templates and their instances.
++
++TEMPLATE_RELATIONS = NO
++
++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
++# tags are set to YES then doxygen will generate a graph for each documented
++# file showing the direct and indirect include dependencies of the file with
++# other documented files.
++
++INCLUDE_GRAPH = YES
++
++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
++# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
++# documented header file showing the documented files that directly or
++# indirectly include this file.
++
++INCLUDED_BY_GRAPH = YES
++
++# If the CALL_GRAPH and HAVE_DOT options are set to YES then
++# doxygen will generate a call dependency graph for every global function
++# or class method. Note that enabling this option will significantly increase
++# the time of a run. So in most cases it will be better to enable call graphs
++# for selected functions only using the \callgraph command.
++
++CALL_GRAPH = NO
++
++# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
++# doxygen will generate a caller dependency graph for every global function
++# or class method. Note that enabling this option will significantly increase
++# the time of a run. So in most cases it will be better to enable caller
++# graphs for selected functions only using the \callergraph command.
++
++CALLER_GRAPH = NO
++
++# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
++# will graphical hierarchy of all classes instead of a textual one.
++
++GRAPHICAL_HIERARCHY = YES
++
++# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
++# then doxygen will show the dependencies a directory has on other directories
++# in a graphical way. The dependency relations are determined by the #include
++# relations between the files in the directories.
++
++DIRECTORY_GRAPH = YES
++
++# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
++# generated by dot. Possible values are png, jpg, or gif
++# If left blank png will be used.
++
++DOT_IMAGE_FORMAT = png
++
++# The tag DOT_PATH can be used to specify the path where the dot tool can be
++# found. If left blank, it is assumed the dot tool can be found in the path.
++
++DOT_PATH =
++
++# The DOTFILE_DIRS tag can be used to specify one or more directories that
++# contain dot files that are included in the documentation (see the
++# \dotfile command).
++
++DOTFILE_DIRS =
++
++# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
++# nodes that will be shown in the graph. If the number of nodes in a graph
++# becomes larger than this value, doxygen will truncate the graph, which is
++# visualized by representing a node as a red box. Note that doxygen if the
++# number of direct children of the root node in a graph is already larger than
++# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
++# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
++
++DOT_GRAPH_MAX_NODES = 50
++
++# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
++# graphs generated by dot. A depth value of 3 means that only nodes reachable
++# from the root by following a path via at most 3 edges will be shown. Nodes
++# that lay further from the root node will be omitted. Note that setting this
++# option to 1 or 2 may greatly reduce the computation time needed for large
++# code bases. Also note that the size of a graph can be further restricted by
++# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
++
++MAX_DOT_GRAPH_DEPTH = 0
++
++# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
++# background. This is disabled by default, because dot on Windows does not
++# seem to support this out of the box. Warning: Depending on the platform used,
++# enabling this option may lead to badly anti-aliased labels on the edges of
++# a graph (i.e. they become hard to read).
++
++DOT_TRANSPARENT = NO
++
++# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
++# files in one run (i.e. multiple -o and -T options on the command line). This
++# makes dot run faster, but since only newer versions of dot (>1.8.10)
++# support this, this feature is disabled by default.
++
++DOT_MULTI_TARGETS = NO
++
++# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
++# generate a legend page explaining the meaning of the various boxes and
++# arrows in the dot generated graphs.
++
++GENERATE_LEGEND = YES
++
++# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
++# remove the intermediate dot files that are used to generate
++# the various graphs.
++
++DOT_CLEANUP = YES
++
++#---------------------------------------------------------------------------
++# Configuration::additions related to the search engine
++#---------------------------------------------------------------------------
++
++# The SEARCHENGINE tag specifies whether or not a search engine should be
++# used. If set to NO the values of all tags below this one will be ignored.
++
++SEARCHENGINE = NO
+diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h
+new file mode 100644
+index 0000000..756590e
+--- /dev/null
++++ b/libiscsi/libiscsi.h
+@@ -0,0 +1,344 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at googlegroups.com
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published
++ * by the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * See the file COPYING included with this distribution for more details.
++ */
++
++#ifndef __LIBISCSI_H
++#define __LIBISCSI_H
++
++#include <netdb.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++
++#if __GNUC__ >= 4
++#define PUBLIC __attribute__ ((visibility("default")))
++#else
++#define PUBLIC
++#endif
++
++/** \brief Maximum length for iSCSI values.
++ *
++ * Maximum length for iSCSI values such as hostnames and parameter values.
++ */
++#define LIBISCSI_VALUE_MAXLEN 256
++
++/** \brief supported authentication methods
++ *
++ * This enum lists all supported authentication methods.
++ */
++enum libiscsi_auth_t {
++ libiscsi_auth_none /** No authentication */,
++ libiscsi_auth_chap /** CHAP authentication */,
++};
++
++/** \brief libiscsi context struct
++ *
++ * Note: even though libiscsi uses a context struct, the underlying open-iscsi
++ * code does not, so libiscsi is not thread safe, not even when using one
++ * context per thread!
++ */
++struct libiscsi_context;
++
++/** \brief iSCSI node record
++ *
++ * Struct holding data uniquely identifying an iSCSI node.
++ */
++struct libiscsi_node {
++ char name[LIBISCSI_VALUE_MAXLEN] /** iSCSI iqn for the node. */;
++ int tpgt /** Portal group number. */;
++ /* Note open-iscsi has some code in place for multiple connections in one
++ node record and thus multiple address / port combi's, but this does not
++ get used anywhere, so we keep things simple and assume one connection */
++ char address[NI_MAXHOST] /** Portal hostname or IP-address. */;
++ int port /** Portal port number. */;
++ char iface[LIBISCSI_VALUE_MAXLEN] /** Interface to connect through. */;
++};
++
++/** \brief libiscsi CHAP authentication information struct
++ *
++ * Struct holding all data needed for CHAP login / authentication. Note that
++ * \e reverse_username may be a 0 length string in which case only forward
++ * authentication will be done.
++ */
++struct libiscsi_chap_auth_info {
++ char username[LIBISCSI_VALUE_MAXLEN] /** Username */;
++ char password[LIBISCSI_VALUE_MAXLEN] /** Password */;
++ char reverse_username[LIBISCSI_VALUE_MAXLEN] /** Reverse Username */;
++ char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */;
++};
++
++/** \brief generic libiscsi authentication information struct
++ *
++ * Struct holding authentication information for discovery and login.
++ */
++struct libiscsi_auth_info {
++ enum libiscsi_auth_t method /** Authentication method to use */;
++ union {
++ struct libiscsi_chap_auth_info chap /** Chap specific info */;
++ } /** Union holding method depenend info */;
++};
++
++/** \brief Initalize libiscsi
++ *
++ * This function creates a libiscsi context and initalizes it. This context
++ * is need to use other libiscsi funtions.
++ *
++ * \return A pointer to the created context, or NULL in case of an error.
++ */
++PUBLIC struct libiscsi_context *libiscsi_init(void);
++
++/** \brief Cleanup libiscsi used resource
++ *
++ * This function cleanups any used resources and then destroys the passed
++ * context. After this the passed in context may no longer be used!
++ *
++ * \param context libiscsi context to operate on.
++ */
++PUBLIC void libiscsi_cleanup(struct libiscsi_context *context);
++
++/** \brief Discover iSCSI nodes using sendtargets and add them to the node db.
++ *
++ * This function connects to the given address and port and then tries to
++ * discover iSCSI nodes using the sendtargets protocol. Any found nodes are
++ * added to the local iSCSI node database and are returned in a dynamically
++ * allocated array.
++ *
++ * Note that the (optional) authentication info is for authenticating the
++ * discovery, and is not for the found nodes! If the connection(s) to the
++ * node(s) need authentication too, you can set the username / password for
++ * those (which can be different!) using the libiscsi_node_set_auth() function.
++ *
++ * \param context libiscsi context to operate on.
++ * \param address Hostname or IP-address to connect to.
++ * \param port Port to connect to, or 0 for the default port.
++ * \param auth_info Authentication information, or NULL.
++ * \param nr_found The number of found nodes will be returned
++ * through this pointer if not NULL.
++ * \param found_nodes The address of the dynamically allocated array
++ * of found nodes will be returned through this
++ * pointer if not NULL. The caller must free this
++ * array using free().
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context,
++ const char *address, int port, const struct libiscsi_auth_info *auth_info,
++ int *nr_found, struct libiscsi_node **found_nodes);
++
++/** \brief Read iSCSI node info from firmware and add them to the node db.
++ *
++ * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found
++ * nodes are added to the local iSCSI node database and are returned in a
++ * dynamically allocated array.
++ *
++ * Note that unlike sendtargets discovery, this function will also read
++ * authentication info and store that in the database too.
++ *
++ * Note this function currently is a stub which will always return -EINVAL
++ * (IOW it is not yet implemented)
++ *
++ * \param context libiscsi context to operate on.
++ * \param nr_found The number of found nodes will be returned
++ * through this pointer if not NULL.
++ * \param found_nodes The address of the dynamically allocated array
++ * of found nodes will be returned through this
++ * pointer if not NULL. The caller must free this
++ * array using free().
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_discover_firmware(struct libiscsi_context *context,
++ int *nr_found, struct libiscsi_node **found_nodes);
++
++/** \brief Check validity of the given authentication info.
++ *
++ * This function checks the validity of the given authentication info. For
++ * example in case of CHAP, if the username and password are not empty.
++ *
++ * This function is mainly intended for use by language bindings.
++ *
++ * \param context libiscsi context to operate on.
++ * \param auth_info Authentication information to check.
++ * \return 0 on success, otherwise EINVAL.
++ */
++PUBLIC int libiscsi_verify_auth_info(struct libiscsi_context *context,
++ const struct libiscsi_auth_info *auth_info);
++
++/** \brief Set the authentication info for the given node.
++ *
++ * This function sets the authentication information for the node described by
++ * the given node record. This will overwrite any existing authentication
++ * information.
++ *
++ * This is the way to specify authentication information for nodes found
++ * through sendtargets discovery.
++ *
++ * Note:
++ * 1) This is a convience wrapper around libiscsi_node_set_parameter(),
++ * setting the node.session.auth.* parameters.
++ * 2) For nodes found through firmware discovery the authentication information
++ * has already been set from the firmware.
++ * 3) \e auth_info may be NULL in which case any existing authinfo will be
++ * cleared.
++ *
++ * \param context libiscsi context to operate on.
++ * \param node iSCSI node to set auth information of
++ * \param auth_info Authentication information, or NULL.
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_node_set_auth(struct libiscsi_context *context,
++ const struct libiscsi_node *node,
++ const struct libiscsi_auth_info *auth_info);
++
++/** \brief Get the authentication info for the given node.
++ *
++ * This function gets the authentication information for the node described by
++ * the given node record.
++ *
++ * \param context libiscsi context to operate on.
++ * \param node iSCSI node to set auth information of
++ * \param auth_info Pointer to a libiscsi_auth_info struct where
++ * the retreived information will be stored.
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_node_get_auth(struct libiscsi_context *context,
++ const struct libiscsi_node *node,
++ struct libiscsi_auth_info *auth_info);
++
++/** \brief Login to an iSCSI node.
++ *
++ * Login to the iSCSI node described by the given node record.
++ *
++ * \param context libiscsi context to operate on.
++ * \param node iSCSI node to login to.
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_node_login(struct libiscsi_context *context,
++ const struct libiscsi_node *node);
++
++/** \brief Logout of an iSCSI node.
++ *
++ * Logout of the iSCSI node described by the given node record.
++ *
++ * \param context libiscsi context to operate on.
++ * \param node iSCSI node to logout from.
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_node_logout(struct libiscsi_context *context,
++ const struct libiscsi_node *node);
++
++/** \brief Set an iSCSI parameter for the given node
++ *
++ * Set the given nodes iSCSI parameter named by \e parameter to value \e value.
++ *
++ * \param context libiscsi context to operate on.
++ * \param node iSCSI node to change a parameter from.
++ * \param parameter Name of the parameter to set.
++ * \param value Value to set the parameter too.
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_node_set_parameter(struct libiscsi_context *context,
++ const struct libiscsi_node *node,
++ const char *parameter, const char *value);
++
++/** \brief Get the value of an iSCSI parameter for the given node
++ *
++ * Get the value of the given nodes iSCSI parameter named by \e parameter.
++ *
++ * \param context libiscsi context to operate on.
++ * \param node iSCSI node to change a parameter from.
++ * \param parameter Name of the parameter to get.
++ * \param value The retreived value is stored here, this buffer must be
++ * atleast LIBISCSI_VALUE_MAXLEN bytes large.
++ * \return 0 on success, otherwise a standard error code
++ * (from errno.h).
++ */
++PUBLIC int libiscsi_node_get_parameter(struct libiscsi_context *context,
++ const struct libiscsi_node *node, const char *parameter, char *value);
++
++/** \brief Get human readable string describing the last libiscsi error.
++ *
++ * This function can be called to get a human readable error string when a
++ * libiscsi function has returned an error. This function uses a single buffer
++ * per context, thus the result is only valid as long as no other libiscsi
++ * calls are made on the same context after the failing function call.
++ *
++ * \param context libiscsi context to operate on.
++ *
++ * \return human readable string describing the last libiscsi error.
++ */
++PUBLIC const char *libiscsi_get_error_string(struct libiscsi_context *context);
++
++
++/************************** Utility functions *******************************/
++
++/** \brief libiscsi network config struct
++ *
++ * libiscsi network config struct.
++ */
++struct libiscsi_network_config {
++ int dhcp /** Using DHCP? (boolean). */;
++ char iface_name[LIBISCSI_VALUE_MAXLEN] /** Interface name. */;
++ char mac_address[LIBISCSI_VALUE_MAXLEN] /** MAC address. */;
++ char ip_address[LIBISCSI_VALUE_MAXLEN] /** IP address. */;
++ char netmask[LIBISCSI_VALUE_MAXLEN] /** Netmask. */;
++ char gateway[LIBISCSI_VALUE_MAXLEN] /** IP of Default gateway. */;
++ char primary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Primary DNS. */;
++ char secondary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Secondary DNS. */;
++};
++
++/** \brief Get network configuration information from iscsi firmware
++ *
++ * Function can be called to get the network configuration information
++ * (like dhcp, ip, netmask, default gateway, etc.) from the firmware of a
++ * network adapter with iscsi boot firmware.
++ *
++ * Note that not all fields of the returned struct are necessarilly filled,
++ * unset fields contain a 0 length string.
++ *
++ * \param config pointer to a libiscsi_network_config struct to fill.
++ *
++ * \return 0 on success, ENODEV when no iscsi firmware was found.
++ */
++PUBLIC int libiscsi_get_firmware_network_config(
++ struct libiscsi_network_config *config);
++
++/** \brief Get the initiator name (iqn) from the iscsi firmware
++ *
++ * Get the initiator name (iqn) from the iscsi firmware.
++ *
++ * \param initiatorname The initiator name is stored here, this buffer must be
++ * atleast LIBISCSI_VALUE_MAXLEN bytes large.
++ * \return 0 on success, ENODEV when no iscsi firmware was found.
++ */
++PUBLIC int libiscsi_get_firmware_initiator_name(char *initiatorname);
++
++#undef PUBLIC
++
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#endif
+diff --git a/libiscsi/no_date_footer.html b/libiscsi/no_date_footer.html
+new file mode 100644
+index 0000000..1e0c6c4
+--- /dev/null
++++ b/libiscsi/no_date_footer.html
+@@ -0,0 +1,6 @@
++<hr size="1"><address style="text-align: right;"><small>
++Generated for $projectname by <a href="http://www.doxygen.org/
++index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a>
++$doxygenversion</small></address>
++</body>
++</html>
+diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c
+new file mode 100644
+index 0000000..8800853
+--- /dev/null
++++ b/libiscsi/pylibiscsi.c
+@@ -0,0 +1,709 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede at redhat.com>
++ * maintained by open-iscsi at googlegroups.com
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published
++ * by the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * See the file COPYING included with this distribution for more details.
++ */
++
++#include <Python.h>
++#include "libiscsi.h"
++
++#if PY_MAJOR_VERSION >= 3
++#define IS_PY3K
++#define MODINITERROR return NULL
++#define PYNUM_FROMLONG PyLong_FromLong
++#define PYSTR_FROMSTRING PyUnicode_FromString
++#else
++#define MODINITERROR return
++#define PYNUM_FROMLONG PyInt_FromLong
++#define PYSTR_FROMSTRING PyString_FromString
++#endif
++
++#define RET_TRUE_ELSE_FALSE { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; }
++#define CMP_TO_RICHCMP(cmpfunc) \
++ int comp_res = cmpfunc(self, other); \
++ switch (op) { \
++ case Py_LT: \
++ if (comp_res < 0) RET_TRUE_ELSE_FALSE \
++ case Py_LE: \
++ if (comp_res <= 0) RET_TRUE_ELSE_FALSE \
++ case Py_EQ: \
++ if (comp_res == 0) RET_TRUE_ELSE_FALSE \
++ case Py_NE: \
++ if (comp_res != 0) RET_TRUE_ELSE_FALSE \
++ case Py_GT: \
++ if (comp_res > 0) RET_TRUE_ELSE_FALSE \
++ default: \
++ if (comp_res >= 0) RET_TRUE_ELSE_FALSE \
++ }
++
++static struct libiscsi_context *context = NULL;
++
++/****************************** helpers ***********************************/
++static int check_string(const char *string)
++{
++ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) {
++ PyErr_SetString(PyExc_ValueError, "string too long");
++ return -1;
++ }
++ return 0;
++}
++
++/********************** PyIscsiChapAuthInfo ***************************/
++
++typedef struct {
++ PyObject_HEAD
++
++ struct libiscsi_auth_info info;
++} PyIscsiChapAuthInfo;
++
++static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args,
++ PyObject *kwds)
++{
++ int i;
++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
++ char *kwlist[] = {"username", "password", "reverse_username",
++ "reverse_password", NULL};
++ const char *string[4] = { NULL, NULL, NULL, NULL };
++
++ if (!PyArg_ParseTupleAndKeywords(args, kwds,
++ "zz|zz:chapAuthInfo.__init__",
++ kwlist, &string[0], &string[1],
++ &string[2], &string[3]))
++ return -1;
++
++ for (i = 0; i < 4; i++)
++ if (string[i] && check_string(string[i]))
++ return -1;
++
++ memset (&chap->info, 0, sizeof(chap->info));
++ chap->info.method = libiscsi_auth_chap;
++ if (string[0])
++ strcpy(chap->info.chap.username, string[0]);
++ if (string[1])
++ strcpy(chap->info.chap.password, string[1]);
++ if (string[2])
++ strcpy(chap->info.chap.reverse_username, string[2]);
++ if (string[3])
++ strcpy(chap->info.chap.reverse_password, string[3]);
++
++ if (libiscsi_verify_auth_info(context, &chap->info)) {
++ PyErr_SetString(PyExc_ValueError,
++ libiscsi_get_error_string(context));
++ return -1;
++ }
++ return 0;
++}
++
++static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data)
++{
++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
++ const char *attr = (const char *)data;
++
++ if (!strcmp(attr, "username")) {
++ return PYSTR_FROMSTRING(chap->info.chap.username);
++ } else if (!strcmp(attr, "password")) {
++ return PYSTR_FROMSTRING(chap->info.chap.password);
++ } else if (!strcmp(attr, "reverse_username")) {
++ return PYSTR_FROMSTRING(chap->info.chap.reverse_username);
++ } else if (!strcmp(attr, "reverse_password")) {
++ return PYSTR_FROMSTRING(chap->info.chap.reverse_password);
++ }
++ return NULL;
++}
++
++static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data)
++{
++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
++ const char *attr = (const char *)data;
++ const char *str;
++
++ if (!PyArg_Parse(value, "s", &str) || check_string(str))
++ return -1;
++
++ if (!strcmp(attr, "username")) {
++ strcpy(chap->info.chap.username, str);
++ } else if (!strcmp(attr, "password")) {
++ strcpy(chap->info.chap.password, str);
++ } else if (!strcmp(attr, "reverse_username")) {
++ strcpy(chap->info.chap.reverse_username, str);
++ } else if (!strcmp(attr, "reverse_password")) {
++ strcpy(chap->info.chap.reverse_password, str);
++ }
++
++ return 0;
++}
++
++static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self,
++ PyIscsiChapAuthInfo *other)
++{
++ int r;
++
++ r = strcmp(self->info.chap.username, other->info.chap.username);
++ if (r)
++ return r;
++
++ r = strcmp(self->info.chap.password, other->info.chap.password);
++ if (r)
++ return r;
++
++ r = strcmp(self->info.chap.reverse_username,
++ other->info.chap.reverse_username);
++ if (r)
++ return r;
++
++ r = strcmp(self->info.chap.reverse_password,
++ other->info.chap.reverse_password);
++ return r;
++}
++
++PyObject *PyIscsiChapAuthInfo_richcompare(PyIscsiChapAuthInfo *self,
++ PyIscsiChapAuthInfo *other,
++ int op)
++{
++ CMP_TO_RICHCMP(PyIscsiChapAuthInfo_compare)
++}
++
++static PyObject *PyIscsiChapAuthInfo_str(PyObject *self)
++{
++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
++ char s[1024], reverse[512] = "";
++
++ if (chap->info.chap.reverse_username[0])
++ snprintf(reverse, sizeof(reverse), ", %s:%s",
++ chap->info.chap.reverse_username,
++ chap->info.chap.reverse_password);
++
++ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username,
++ chap->info.chap.password, reverse);
++
++ return PYSTR_FROMSTRING(s);
++}
++
++static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = {
++ {"username", (getter)PyIscsiChapAuthInfo_get,
++ (setter)PyIscsiChapAuthInfo_set,
++ "username", "username"},
++ {"password", (getter)PyIscsiChapAuthInfo_get,
++ (setter)PyIscsiChapAuthInfo_set,
++ "password", "password"},
++ {"reverse_username", (getter)PyIscsiChapAuthInfo_get,
++ (setter)PyIscsiChapAuthInfo_set,
++ "reverse_username", "reverse_username"},
++ {"reverse_password", (getter)PyIscsiChapAuthInfo_get,
++ (setter)PyIscsiChapAuthInfo_set,
++ "reverse_password", "reverse_password"},
++ {NULL}
++};
++
++PyTypeObject PyIscsiChapAuthInfo_Type = {
++ PyVarObject_HEAD_INIT(NULL, 0)
++ .tp_name = "libiscsi.chapAuthInfo",
++ .tp_basicsize = sizeof (PyIscsiChapAuthInfo),
++ .tp_getset = PyIscsiChapAuthInfo_getseters,
++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
++#ifndef IS_PY3K
++ // Py_TPFLAGS_CHECKTYPES is only needed on Python 2
++ | Py_TPFLAGS_CHECKTYPES
++#endif
++ ,
++ .tp_richcompare = (richcmpfunc)PyIscsiChapAuthInfo_compare,
++ .tp_init = PyIscsiChapAuthInfo_init,
++ .tp_str = PyIscsiChapAuthInfo_str,
++ .tp_new = PyType_GenericNew,
++ .tp_doc = "iscsi chap authentication information.",
++};
++
++/***************************** PyIscsiNode ********************************/
++
++typedef struct {
++ PyObject_HEAD
++
++ struct libiscsi_node node;
++} PyIscsiNode;
++
++static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds)
++{
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ char *kwlist[] = {"name", "tpgt", "address", "port", "iface", NULL};
++ const char *name = NULL, *address = NULL, *iface = NULL;
++ int tpgt = -1, port = 3260;
++
++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isis:node.__init__",
++ kwlist, &name, &tpgt, &address,
++ &port, &iface))
++ return -1;
++ if (address == NULL) {
++ PyErr_SetString(PyExc_ValueError, "address not set");
++ return -1;
++ }
++ if (check_string(name) || check_string(address) || check_string(iface))
++ return -1;
++
++ strcpy(node->node.name, name);
++ node->node.tpgt = tpgt;
++ strcpy(node->node.address, address);
++ node->node.port = port;
++ strcpy(node->node.iface, iface);
++
++ return 0;
++}
++
++static PyObject *PyIscsiNode_get(PyObject *self, void *data)
++{
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ const char *attr = (const char *)data;
++
++ if (!strcmp(attr, "name")) {
++ return PYSTR_FROMSTRING(node->node.name);
++ } else if (!strcmp(attr, "tpgt")) {
++ return PYNUM_FROMLONG(node->node.tpgt);
++ } else if (!strcmp(attr, "address")) {
++ return PYSTR_FROMSTRING(node->node.address);
++ } else if (!strcmp(attr, "port")) {
++ return PYNUM_FROMLONG(node->node.port);
++ } else if (!strcmp(attr, "iface")) {
++ return PYSTR_FROMSTRING(node->node.iface);
++ }
++ return NULL;
++}
++
++static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data)
++{
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ const char *attr = (const char *)data;
++ const char *str;
++ int i;
++
++ if (!strcmp(attr, "name")) {
++ if (!PyArg_Parse(value, "s", &str) || check_string(str))
++ return -1;
++ strcpy(node->node.name, str);
++ } else if (!strcmp(attr, "tpgt")) {
++ if (!PyArg_Parse(value, "i", &i))
++ return -1;
++ node->node.tpgt = i;
++ } else if (!strcmp(attr, "address")) {
++ if (!PyArg_Parse(value, "s", &str) || check_string(str))
++ return -1;
++ strcpy(node->node.address, str);
++ } else if (!strcmp(attr, "port")) {
++ if (!PyArg_Parse(value, "i", &i))
++ return -1;
++ node->node.port = i;
++ } else if (!strcmp(attr, "iface")) {
++ if (!PyArg_Parse(value, "s", &str) || check_string(str))
++ return -1;
++ strcpy(node->node.iface, str);
++ }
++
++ return 0;
++}
++
++static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other)
++{
++ int res;
++
++ res = strcmp(self->node.name, other->node.name);
++ if (res)
++ return res;
++
++ if (self->node.tpgt < other->node.tpgt)
++ return -1;
++ if (self->node.tpgt > other->node.tpgt)
++ return -1;
++
++ res = strcmp(self->node.address, other->node.address);
++ if (res)
++ return res;
++
++ if (self->node.port < other->node.port)
++ return -1;
++ if (self->node.port > other->node.port)
++ return -1;
++
++ res = strcmp(self->node.iface, other->node.iface);
++ if (res)
++ return res;
++
++ return 0;
++}
++
++PyObject *PyIscsiNode_richcompare(PyIscsiNode *self, PyIscsiNode *other, int op)
++{
++ CMP_TO_RICHCMP(PyIscsiNode_compare)
++}
++
++static PyObject *PyIscsiNode_str(PyObject *self)
++{
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ char s[1024], tpgt[16] = "";
++
++ if (node->node.tpgt != -1)
++ sprintf(tpgt, ",%d", node->node.tpgt);
++
++ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address,
++ node->node.port, tpgt, node->node.name);
++
++ return PYSTR_FROMSTRING(s);
++}
++
++static PyObject *PyIscsiNode_login(PyObject *self)
++{
++ PyIscsiNode *node = (PyIscsiNode *)self;
++
++ if (libiscsi_node_login(context, &node->node)) {
++ PyErr_SetString(PyExc_IOError,
++ libiscsi_get_error_string(context));
++ return NULL;
++ }
++ Py_RETURN_NONE;
++}
++
++static PyObject *PyIscsiNode_logout(PyObject *self)
++{
++ PyIscsiNode *node = (PyIscsiNode *)self;
++
++ if (libiscsi_node_logout(context, &node->node)) {
++ PyErr_SetString(PyExc_IOError,
++ libiscsi_get_error_string(context));
++ return NULL;
++ }
++ Py_RETURN_NONE;
++}
++
++static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args,
++ PyObject *kwds)
++{
++ char *kwlist[] = {"authinfo", NULL};
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ PyObject *arg;
++ const struct libiscsi_auth_info *authinfo = NULL;
++
++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg))
++ return NULL;
++
++ if (arg == Py_None) {
++ authinfo = NULL;
++ } else if (PyObject_IsInstance(arg, (PyObject *)
++ &PyIscsiChapAuthInfo_Type)) {
++ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg;
++ authinfo = &pyauthinfo->info;
++ } else {
++ PyErr_SetString(PyExc_ValueError, "invalid authinfo type");
++ return NULL;
++ }
++
++ if (libiscsi_node_set_auth(context, &node->node, authinfo)) {
++ PyErr_SetString(PyExc_IOError,
++ libiscsi_get_error_string(context));
++ return NULL;
++ }
++ Py_RETURN_NONE;
++}
++
++static PyObject *PyIscsiNode_getAuth(PyObject *self)
++{
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ PyIscsiChapAuthInfo *pyauthinfo;
++ struct libiscsi_auth_info authinfo;
++
++ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) {
++ PyErr_SetString(PyExc_IOError,
++ libiscsi_get_error_string(context));
++ return NULL;
++ }
++
++ switch (authinfo.method) {
++ case libiscsi_auth_chap:
++ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo,
++ &PyIscsiChapAuthInfo_Type);
++ if (!pyauthinfo)
++ return NULL;
++
++ pyauthinfo->info = authinfo;
++
++ return (PyObject *)pyauthinfo;
++
++ case libiscsi_auth_none:
++ default:
++ Py_RETURN_NONE;
++ }
++}
++
++static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args,
++ PyObject *kwds)
++{
++ char *kwlist[] = {"parameter", "value", NULL};
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ const char *parameter, *value;
++
++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
++ ¶meter, &value))
++ return NULL;
++ if (check_string(parameter) || check_string(value))
++ return NULL;
++
++ if (libiscsi_node_set_parameter(context, &node->node, parameter,
++ value)) {
++ PyErr_SetString(PyExc_IOError,
++ libiscsi_get_error_string(context));
++ return NULL;
++ }
++ Py_RETURN_NONE;
++}
++
++static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args,
++ PyObject *kwds)
++{
++ char *kwlist[] = {"parameter", NULL};
++ PyIscsiNode *node = (PyIscsiNode *)self;
++ const char *parameter;
++ char value[LIBISCSI_VALUE_MAXLEN];
++
++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, ¶meter))
++ return NULL;
++ if (check_string(parameter))
++ return NULL;
++
++ if (libiscsi_node_get_parameter(context, &node->node, parameter,
++ value)) {
++ PyErr_SetString(PyExc_IOError,
++ libiscsi_get_error_string(context));
++ return NULL;
++ }
++ return Py_BuildValue("s", value);
++}
++
++static struct PyGetSetDef PyIscsiNode_getseters[] = {
++ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
++ "name", "name"},
++ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
++ "tpgt", "tpgt"},
++ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
++ "address", "address"},
++ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
++ "port", "port"},
++ {"iface", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
++ "iface", "iface"},
++ {NULL}
++};
++
++static struct PyMethodDef PyIscsiNode_methods[] = {
++ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS,
++ "Log in to the node"},
++ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS,
++ "Log out of the node"},
++ {"setAuth", (PyCFunction) PyIscsiNode_setAuth,
++ METH_VARARGS|METH_KEYWORDS,
++ "Set authentication information"},
++ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS,
++ "Get authentication information"},
++ {"setParameter", (PyCFunction) PyIscsiNode_setParameter,
++ METH_VARARGS|METH_KEYWORDS,
++ "Set an iscsi node parameter"},
++ {"getParameter", (PyCFunction) PyIscsiNode_getParameter,
++ METH_VARARGS|METH_KEYWORDS,
++ "Get an iscsi node parameter"},
++ {NULL}
++};
++
++PyTypeObject PyIscsiNode_Type = {
++ PyVarObject_HEAD_INIT(NULL, 0)
++ .tp_name = "libiscsi.node",
++ .tp_basicsize = sizeof (PyIscsiNode),
++ .tp_getset = PyIscsiNode_getseters,
++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
++#ifndef IS_PY3K
++ | Py_TPFLAGS_CHECKTYPES
++#endif
++ ,
++ .tp_methods = PyIscsiNode_methods,
++ .tp_richcompare = (richcmpfunc)PyIscsiNode_richcompare,
++ .tp_init = PyIscsiNode_init,
++ .tp_str = PyIscsiNode_str,
++ .tp_new = PyType_GenericNew,
++ .tp_doc = "The iscsi node contains iscsi node information.",
++};
++
++/***************************************************************************/
++
++static PyObject *pylibiscsi_discover_sendtargets(PyObject *self,
++ PyObject *args, PyObject *kwds)
++{
++ char *kwlist[] = {"address", "port", "authinfo", NULL};
++ const char *address = NULL;
++ int i, nr_found, port = 3260;
++ PyObject *authinfo_arg = NULL;
++ const struct libiscsi_auth_info *authinfo = NULL;
++ struct libiscsi_node *found_nodes;
++ PyObject* found_node_list;
++
++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO",
++ kwlist, &address, &port,
++ &authinfo_arg))
++ return NULL;
++
++ if (authinfo_arg) {
++ if (PyObject_IsInstance(authinfo_arg, (PyObject *)
++ &PyIscsiChapAuthInfo_Type)) {
++ PyIscsiChapAuthInfo *pyauthinfo =
++ (PyIscsiChapAuthInfo *)authinfo_arg;
++ authinfo = &pyauthinfo->info;
++ } else if (authinfo_arg != Py_None) {
++ PyErr_SetString(PyExc_ValueError,
++ "invalid authinfo type");
++ return NULL;
++ }
++ }
++
++ if (libiscsi_discover_sendtargets(context, address, port, authinfo,
++ &nr_found, &found_nodes)) {
++ PyErr_SetString(PyExc_IOError,
++ libiscsi_get_error_string(context));
++ return NULL;
++ }
++
++ if (nr_found == 0)
++ Py_RETURN_NONE;
++
++ found_node_list = PyList_New(nr_found);
++ if (!found_node_list)
++ return NULL;
++
++ for(i = 0; i < nr_found; i++) {
++ PyIscsiNode *pynode;
++
++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type);
++ if (!pynode) {
++ /* This will deref already added nodes for us */
++ Py_DECREF(found_node_list);
++ return NULL;
++ }
++ pynode->node = found_nodes[i];
++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode);
++ }
++
++ return found_node_list;
++}
++
++static PyObject *pylibiscsi_discover_firmware(PyObject *self)
++{
++ int i, nr_found;
++ struct libiscsi_node *found_nodes;
<Skipped 38590 lines>
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/open-iscsi.git/commitdiff/3de50fc5e99b5643efe9c051d2892c3800666e04
More information about the pld-cvs-commit
mailing list