]> git.ipfire.org Git - people/ms/ipfire-3.x.git/blame - pkgs/iscsi-initiator-utils/patches/iscsi-initiator-utils-add-libiscsi.patch
Move packages to pkgs subdirectory.
[people/ms/ipfire-3.x.git] / pkgs / iscsi-initiator-utils / patches / iscsi-initiator-utils-add-libiscsi.patch
CommitLineData
cdd964e9
MT
1diff --git a/Makefile b/Makefile
2index db460eb..a4d4ce0 100644
3--- a/Makefile
4+++ b/Makefile
5@@ -32,6 +32,7 @@ user: ;
6 $(MAKE) -C utils/fwparam_ibft
7 $(MAKE) -C usr
8 $(MAKE) -C utils
9+ $(MAKE) -C libiscsi
10 @echo
11 @echo "Compilation complete Output file"
12 @echo "----------------------------------- ----------------"
13@@ -53,6 +54,7 @@ kernel: force
14 force: ;
15
16 clean:
17+ $(MAKE) -C libiscsi clean
18 $(MAKE) -C utils/sysdeps clean
19 $(MAKE) -C utils/fwparam_ibft clean
20 $(MAKE) -C utils clean
21diff --git a/libiscsi/Makefile b/libiscsi/Makefile
22new file mode 100644
23index 0000000..4aeb44f
24--- /dev/null
25+++ b/libiscsi/Makefile
26@@ -0,0 +1,62 @@
27+# This Makefile will work only with GNU make.
28+
29+OSNAME=$(shell uname -s)
30+OPTFLAGS ?= -O2 -g
31+WARNFLAGS ?= -Wall -Wstrict-prototypes
32+CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr -I../utils/open-isns \
33+ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden
34+LIB = libiscsi.so.0
35+TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware
36+TESTS += tests/test_login tests/test_logout tests/test_params
37+TESTS += tests/test_get_network_config tests/test_get_initiator_name
38+TESTS += tests/test_set_auth tests/test_get_auth
39+
40+COMMON_SRCS = sysdeps.o
41+# sources shared between iscsid, iscsiadm and iscsistart
42+ISCSI_LIB_SRCS = 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
43+FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sysfs.o
44+
45+# sources shared with the userspace utils, note we build these separately
46+# to get PIC versions.
47+COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS))
48+USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o)
49+FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS))
50+
51+# Flags for the tests
52+tests/% : CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I.
53+
54+all: lib tests html
55+
56+lib: $(LIB)
57+tests: $(TESTS)
58+
59+common-objs/%.o: ../utils/sysdeps/%.c
60+ mkdir -p common-objs
61+ $(CC) $(CFLAGS) -c $< -o $@
62+
63+usr-objs/%.o: ../usr/%.c
64+ mkdir -p usr-objs
65+ $(CC) $(CFLAGS) -c $< -o $@
66+
67+fw-objs/%.o: ../utils/fwparam_ibft/%.c
68+ mkdir -p fw-objs
69+ $(CC) $(CFLAGS) -c $< -o $@
70+
71+$(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o
72+ $(CC) $(CFLAGS) -L../utils/open-isns -lisns -shared -Wl,-soname,$(LIB) $^ -o $@
73+ ln -s -f $(LIB) libiscsi.so
74+
75+$(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB)
76+ $(CC) $(CFLAGS) -L../utils/open-isns -lisns -c $< -o $@
77+
78+html: libiscsi.h libiscsi.doxy
79+ doxygen libiscsi.doxy
80+
81+clean:
82+ rm -rf *.o common-objs usr-objs fw-objs libuip-objs libiscsi.so* \
83+ .depend *~ html $(TESTS) tests/*~
84+
85+depend:
86+ gcc $(CFLAGS) -M `ls *.c` > .depend
87+
88+-include .depend ../usr/.depend
89diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c
90new file mode 100644
91index 0000000..a9eb0a6
92--- /dev/null
93+++ b/libiscsi/libiscsi.c
94@@ -0,0 +1,563 @@
95+/*
96+ * iSCSI Administration library
97+ *
98+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
99+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
100+ * maintained by open-iscsi@googlegroups.com
101+ *
102+ * This program is free software; you can redistribute it and/or modify
103+ * it under the terms of the GNU General Public License as published
104+ * by the Free Software Foundation; either version 2 of the License, or
105+ * (at your option) any later version.
106+ *
107+ * This program is distributed in the hope that it will be useful, but
108+ * WITHOUT ANY WARRANTY; without even the implied warranty of
109+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
110+ * General Public License for more details.
111+ *
112+ * See the file COPYING included with this distribution for more details.
113+ */
114+
115+#include <stdio.h>
116+#include <stdlib.h>
117+#include <string.h>
118+#include <errno.h>
119+#include <unistd.h>
120+#include <sys/syslog.h>
121+#include "libiscsi.h"
122+#include "idbm.h"
123+#include "discovery.h"
124+#include "log.h"
125+#include "sysfs.h"
126+#include "iscsi_sysfs.h"
127+#include "session_info.h"
128+#include "iscsi_util.h"
129+#include "sysdeps.h"
130+#include "iface.h"
131+#include "iscsi_proto.h"
132+#include "fw_context.h"
133+#include "iscsid_req.h"
134+
135+#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; }
136+
137+struct libiscsi_context {
138+ char error_str[256];
139+ /* For get_parameter_helper() */
140+ const char *parameter;
141+ char *value;
142+};
143+
144+static void libiscsi_log(int prio, void *priv, const char *fmt, va_list ap)
145+{
146+ struct libiscsi_context *context = priv;
147+
148+ if (prio > LOG_ERR) /* We are only interested in errors (or worse) */
149+ return;
150+
151+ vsnprintf(context->error_str, sizeof(context->error_str), fmt, ap);
152+}
153+
154+struct libiscsi_context *libiscsi_init(void)
155+{
156+ struct libiscsi_context *context;
157+
158+ context = calloc(1, sizeof *context);
159+ if (!context)
160+ return NULL;
161+
162+ log_init("libiscsi", 1024, libiscsi_log, context);
163+ sysfs_init();
164+ increase_max_files();
165+ if (idbm_init(NULL)) {
166+ sysfs_cleanup();
167+ free(context);
168+ return NULL;
169+ }
170+
171+ iface_setup_host_bindings();
172+
173+ return context;
174+}
175+
176+void libiscsi_cleanup(struct libiscsi_context *context)
177+{
178+ idbm_terminate();
179+ free_transports();
180+ sysfs_cleanup();
181+ free(context);
182+}
183+
184+static void free_rec_list(struct list_head *rec_list)
185+{
186+ struct node_rec *rec, *tmp;
187+
188+ list_for_each_entry_safe(rec, tmp, rec_list, list) {
189+ list_del(&rec->list);
190+ free(rec);
191+ }
192+}
193+
194+int libiscsi_discover_sendtargets(struct libiscsi_context *context,
195+ const char *address, int port,
196+ const struct libiscsi_auth_info *auth_info,
197+ int *nr_found, struct libiscsi_node **found_nodes)
198+{
199+ struct discovery_rec drec;
200+ LIST_HEAD(bound_rec_list);
201+ struct node_rec *rec;
202+ int rc = 0, found = 0;
203+
204+ INIT_LIST_HEAD(&bound_rec_list);
205+
206+ if (nr_found)
207+ *nr_found = 0;
208+ if (found_nodes)
209+ *found_nodes = NULL;
210+
211+ CHECK(libiscsi_verify_auth_info(context, auth_info))
212+
213+ /* Fill the drec struct with all needed info */
214+ memset(&drec, 0, sizeof drec);
215+ idbm_sendtargets_defaults(&drec.u.sendtargets);
216+ drec.type = DISCOVERY_TYPE_SENDTARGETS;
217+ strlcpy(drec.address, address, sizeof(drec.address));
218+ drec.port = port ? port : ISCSI_LISTEN_PORT;
219+ switch(auth_info ? auth_info->method : libiscsi_auth_none) {
220+ case libiscsi_auth_chap:
221+ drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP;
222+ strlcpy(drec.u.sendtargets.auth.username,
223+ auth_info->chap.username, AUTH_STR_MAX_LEN);
224+ strlcpy((char *)drec.u.sendtargets.auth.password,
225+ auth_info->chap.password, AUTH_STR_MAX_LEN);
226+ drec.u.sendtargets.auth.password_length =
227+ strlen((char *)drec.u.sendtargets.auth.password);
228+ strlcpy(drec.u.sendtargets.auth.username_in,
229+ auth_info->chap.reverse_username, AUTH_STR_MAX_LEN);
230+ strlcpy((char *)drec.u.sendtargets.auth.password_in,
231+ auth_info->chap.reverse_password, AUTH_STR_MAX_LEN);
232+ drec.u.sendtargets.auth.password_in_length =
233+ strlen((char *)drec.u.sendtargets.auth.password_in);
234+ break;
235+ }
236+
237+ CHECK(idbm_add_discovery(&drec))
238+
239+ CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets,
240+ &drec, NULL, &bound_rec_list))
241+
242+ /* now add/update records */
243+ list_for_each_entry(rec, &bound_rec_list, list) {
244+ CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */))
245+ found++;
246+ }
247+
248+ if (nr_found)
249+ *nr_found = found;
250+
251+ if (found_nodes && found) {
252+ *found_nodes = calloc(found, sizeof **found_nodes);
253+ if (*found_nodes == NULL) {
254+ snprintf(context->error_str,
255+ sizeof(context->error_str), strerror(ENOMEM));
256+ rc = ENOMEM;
257+ goto leave;
258+ }
259+ found = 0;
260+ list_for_each_entry(rec, &bound_rec_list, list) {
261+ strlcpy((*found_nodes)[found].name, rec->name,
262+ LIBISCSI_VALUE_MAXLEN);
263+ (*found_nodes)[found].tpgt = rec->tpgt;
264+ strlcpy((*found_nodes)[found].address,
265+ rec->conn[0].address, NI_MAXHOST);
266+ (*found_nodes)[found].port = rec->conn[0].port;
267+ found++;
268+ }
269+ }
270+
271+leave:
272+ free_rec_list(&bound_rec_list);
273+ return rc;
274+}
275+
276+int libiscsi_discover_firmware(struct libiscsi_context *context,
277+ int *nr_found, struct libiscsi_node **found_nodes)
278+{
279+ struct boot_context fw_entry;
280+ struct node_rec rec;
281+ int rc = 0;
282+
283+ if (nr_found)
284+ *nr_found = 0;
285+ if (found_nodes)
286+ *found_nodes = NULL;
287+
288+ memset(&fw_entry, 0, sizeof fw_entry);
289+ rc = fw_get_entry(&fw_entry);
290+ if (rc) {
291+ strcpy(context->error_str, "Could not read fw values.");
292+ return rc;
293+ }
294+
295+ memset(&rec, 0, sizeof rec);
296+ idbm_node_setup_defaults(&rec);
297+
298+ strlcpy(rec.name, fw_entry.targetname, TARGET_NAME_MAXLEN);
299+ rec.tpgt = 1;
300+ strlcpy(rec.conn[0].address, fw_entry.target_ipaddr, NI_MAXHOST);
301+ rec.conn[0].port = fw_entry.target_port;
302+
303+ iface_setup_defaults(&rec.iface);
304+ strncpy(rec.iface.iname, fw_entry.initiatorname,
305+ sizeof(fw_entry.initiatorname));
306+ strncpy(rec.session.auth.username, fw_entry.chap_name,
307+ sizeof(fw_entry.chap_name));
308+ strncpy((char *)rec.session.auth.password, fw_entry.chap_password,
309+ sizeof(fw_entry.chap_password));
310+ strncpy(rec.session.auth.username_in, fw_entry.chap_name_in,
311+ sizeof(fw_entry.chap_name_in));
312+ strncpy((char *)rec.session.auth.password_in,
313+ fw_entry.chap_password_in,
314+ sizeof(fw_entry.chap_password_in));
315+ rec.session.auth.password_length =
316+ strlen((char *)fw_entry.chap_password);
317+ rec.session.auth.password_in_length =
318+ strlen((char *)fw_entry.chap_password_in);
319+
320+ CHECK(idbm_add_node(&rec, NULL, 1 /* overwrite */))
321+
322+ if (nr_found)
323+ *nr_found = 1;
324+
325+ if (found_nodes) {
326+ *found_nodes = calloc(1, sizeof **found_nodes);
327+ if (*found_nodes == NULL) {
328+ snprintf(context->error_str,
329+ sizeof(context->error_str), strerror(ENOMEM));
330+ rc = ENOMEM;
331+ goto leave;
332+ }
333+ strlcpy((*found_nodes)[0].name, rec.name,
334+ LIBISCSI_VALUE_MAXLEN);
335+ (*found_nodes)[0].tpgt = rec.tpgt;
336+ strlcpy((*found_nodes)[0].address,
337+ rec.conn[0].address, NI_MAXHOST);
338+ (*found_nodes)[0].port = rec.conn[0].port;
339+ }
340+
341+leave:
342+ return rc;
343+}
344+
345+int libiscsi_verify_auth_info(struct libiscsi_context *context,
346+ const struct libiscsi_auth_info *auth_info)
347+{
348+ switch(auth_info ? auth_info->method : libiscsi_auth_none) {
349+ case libiscsi_auth_none:
350+ break;
351+ case libiscsi_auth_chap:
352+ if (!auth_info->chap.username[0]) {
353+ strcpy(context->error_str, "Empty username");
354+ return EINVAL;
355+ }
356+ if (!auth_info->chap.password[0]) {
357+ strcpy(context->error_str, "Empty password");
358+ return EINVAL;
359+ }
360+ if (auth_info->chap.reverse_username[0] &&
361+ !auth_info->chap.reverse_password[0]) {
362+ strcpy(context->error_str, "Empty reverse password");
363+ return EINVAL;
364+ }
365+ break;
366+ default:
367+ sprintf(context->error_str,
368+ "Invalid authentication method: %d",
369+ (int)auth_info->method);
370+ return EINVAL;
371+ }
372+ return 0;
373+}
374+
375+int libiscsi_node_set_auth(struct libiscsi_context *context,
376+ const struct libiscsi_node *node,
377+ const struct libiscsi_auth_info *auth_info)
378+{
379+ int rc = 0;
380+
381+ CHECK(libiscsi_verify_auth_info(context, auth_info))
382+
383+ switch(auth_info ? auth_info->method : libiscsi_auth_none) {
384+ case libiscsi_auth_none:
385+ CHECK(libiscsi_node_set_parameter(context, node,
386+ "node.session.auth.authmethod", "None"))
387+ CHECK(libiscsi_node_set_parameter(context, node,
388+ "node.session.auth.username", ""))
389+ CHECK(libiscsi_node_set_parameter(context, node,
390+ "node.session.auth.password", ""))
391+ CHECK(libiscsi_node_set_parameter(context, node,
392+ "node.session.auth.username_in", ""))
393+ CHECK(libiscsi_node_set_parameter(context, node,
394+ "node.session.auth.password_in", ""))
395+ break;
396+
397+ case libiscsi_auth_chap:
398+ CHECK(libiscsi_node_set_parameter(context, node,
399+ "node.session.auth.authmethod", "CHAP"))
400+ CHECK(libiscsi_node_set_parameter(context, node,
401+ "node.session.auth.username",
402+ auth_info->chap.username))
403+ CHECK(libiscsi_node_set_parameter(context, node,
404+ "node.session.auth.password",
405+ auth_info->chap.password))
406+ CHECK(libiscsi_node_set_parameter(context, node,
407+ "node.session.auth.username_in",
408+ auth_info->chap.reverse_username))
409+ CHECK(libiscsi_node_set_parameter(context, node,
410+ "node.session.auth.password_in",
411+ auth_info->chap.reverse_password))
412+ break;
413+ }
414+leave:
415+ return rc;
416+}
417+
418+int libiscsi_node_get_auth(struct libiscsi_context *context,
419+ const struct libiscsi_node *node,
420+ struct libiscsi_auth_info *auth_info)
421+{
422+ int rc = 0;
423+ char value[LIBISCSI_VALUE_MAXLEN];
424+
425+ memset(auth_info, 0, sizeof *auth_info);
426+
427+ CHECK(libiscsi_node_get_parameter(context, node,
428+ "node.session.auth.authmethod", value))
429+
430+ if (!strcmp(value, "None")) {
431+ auth_info->method = libiscsi_auth_none;
432+ } else if (!strcmp(value, "CHAP")) {
433+ auth_info->method = libiscsi_auth_chap;
434+ CHECK(libiscsi_node_get_parameter(context, node,
435+ "node.session.auth.username",
436+ auth_info->chap.username))
437+ CHECK(libiscsi_node_get_parameter(context, node,
438+ "node.session.auth.password",
439+ auth_info->chap.password))
440+ CHECK(libiscsi_node_get_parameter(context, node,
441+ "node.session.auth.username_in",
442+ auth_info->chap.reverse_username))
443+ CHECK(libiscsi_node_get_parameter(context, node,
444+ "node.session.auth.password_in",
445+ auth_info->chap.reverse_password))
446+ } else {
447+ snprintf(context->error_str, sizeof(context->error_str),
448+ "unknown authentication method: %s", value);
449+ rc = EINVAL;
450+ }
451+leave:
452+ return rc;
453+}
454+
455+static void node_to_rec(const struct libiscsi_node *node,
456+ struct node_rec *rec)
457+{
458+ memset(rec, 0, sizeof *rec);
459+ idbm_node_setup_defaults(rec);
460+ strlcpy(rec->name, node->name, TARGET_NAME_MAXLEN);
461+ rec->tpgt = node->tpgt;
462+ strlcpy(rec->conn[0].address, node->address, NI_MAXHOST);
463+ rec->conn[0].port = node->port;
464+}
465+
466+int login_helper(void *data, node_rec_t *rec)
467+{
468+ int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
469+ if (rc) {
470+ iscsid_handle_error(rc);
471+ rc = ENOTCONN;
472+ }
473+ return rc;
474+}
475+
476+int libiscsi_node_login(struct libiscsi_context *context,
477+ const struct libiscsi_node *node)
478+{
479+ int nr_found = 0, rc;
480+
481+ CHECK(idbm_for_each_iface(&nr_found, NULL, login_helper,
482+ (char *)node->name, node->tpgt,
483+ (char *)node->address, node->port))
484+ if (nr_found == 0) {
485+ strcpy(context->error_str, "No such node");
486+ rc = ENODEV;
487+ }
488+leave:
489+ return rc;
490+}
491+
492+static int logout_helper(void *data, struct session_info *info)
493+{
494+ int rc;
495+ struct node_rec *rec = data;
496+
497+ if (!iscsi_match_session(rec, info))
498+ /* Tell iscsi_sysfs_for_each_session this session was not a
499+ match so that it will not increase nr_found. */
500+ return -1;
501+
502+ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
503+ if (rc) {
504+ iscsid_handle_error(rc);
505+ rc = EIO;
506+ }
507+
508+ return rc;
509+}
510+
511+int libiscsi_node_logout(struct libiscsi_context *context,
512+ const struct libiscsi_node *node)
513+{
514+ int nr_found = 0, rc;
515+ struct node_rec rec;
516+
517+ node_to_rec(node, &rec);
518+ CHECK(iscsi_sysfs_for_each_session(&rec, &nr_found, logout_helper))
519+ if (nr_found == 0) {
520+ strcpy(context->error_str, "No matching session");
521+ rc = ENODEV;
522+ }
523+leave:
524+ return rc;
525+}
526+
527+int libiscsi_node_set_parameter(struct libiscsi_context *context,
528+ const struct libiscsi_node *node,
529+ const char *parameter, const char *value)
530+{
531+ int nr_found = 0, rc;
532+ struct db_set_param set_param = {
533+ .name = (char *)parameter,
534+ .value = (char *)value,
535+ };
536+
537+ CHECK(idbm_for_each_iface(&nr_found, &set_param, idbm_node_set_param,
538+ (char *)node->name, node->tpgt,
539+ (char *)node->address, node->port))
540+ if (nr_found == 0) {
541+ strcpy(context->error_str, "No such node");
542+ rc = ENODEV;
543+ }
544+leave:
545+ return rc;
546+}
547+
548+static int get_parameter_helper(void *data, node_rec_t *rec)
549+{
550+ struct libiscsi_context *context = data;
551+ recinfo_t *info;
552+ int i;
553+
554+ info = idbm_recinfo_alloc(MAX_KEYS);
555+ if (!info) {
556+ snprintf(context->error_str, sizeof(context->error_str),
557+ strerror(ENOMEM));
558+ return ENOMEM;
559+ }
560+
561+ idbm_recinfo_node(rec, info);
562+
563+ for (i = 0; i < MAX_KEYS; i++) {
564+ if (!info[i].visible)
565+ continue;
566+
567+ if (strcmp(context->parameter, info[i].name))
568+ continue;
569+
570+ strlcpy(context->value, info[i].value, LIBISCSI_VALUE_MAXLEN);
571+ break;
572+ }
573+
574+ free(info);
575+
576+ if (i == MAX_KEYS) {
577+ strcpy(context->error_str, "No such parameter");
578+ return EINVAL;
579+ }
580+
581+ return 0;
582+}
583+
584+int libiscsi_node_get_parameter(struct libiscsi_context *context,
585+ const struct libiscsi_node *node, const char *parameter, char *value)
586+{
587+ int nr_found = 0, rc = 0;
588+
589+ context->parameter = parameter;
590+ context->value = value;
591+
592+ /* Note we assume there is only one interface, if not we will get
593+ the value from the last interface iterated over!
594+ This (multiple interfaces) can only happen if someone explicitly
595+ created ones using iscsiadm. Even then this should not be a problem
596+ as most settings should be the same independent of the iface. */
597+ CHECK(idbm_for_each_iface(&nr_found, context, get_parameter_helper,
598+ (char *)node->name, node->tpgt,
599+ (char *)node->address, node->port))
600+ if (nr_found == 0) {
601+ strcpy(context->error_str, "No such node");
602+ rc = ENODEV;
603+ }
604+leave:
605+ return rc;
606+}
607+
608+const char *libiscsi_get_error_string(struct libiscsi_context *context)
609+{
610+ /* Sometimes the core open-iscsi code does not give us an error
611+ message */
612+ if (!context->error_str[0])
613+ return "Unknown error";
614+
615+ return context->error_str;
616+}
617+
618+
619+/************************** Utility functions *******************************/
620+
621+int libiscsi_get_firmware_network_config(
622+ struct libiscsi_network_config *config)
623+{
624+ struct boot_context fw_entry;
625+
626+ memset(config, 0, sizeof *config);
627+ memset(&fw_entry, 0, sizeof fw_entry);
628+ if (fw_get_entry(&fw_entry))
629+ return ENODEV;
630+
631+ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0;
632+ strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface);
633+ strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac);
634+ strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr);
635+ strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask);
636+ strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway);
637+ strncpy(config->primary_dns, fw_entry.primary_dns,
638+ sizeof fw_entry.primary_dns);
639+ strncpy(config->secondary_dns, fw_entry.secondary_dns,
640+ sizeof fw_entry.secondary_dns);
641+ return 0;
642+}
643+
644+int libiscsi_get_firmware_initiator_name(char *initiatorname)
645+{
646+ struct boot_context fw_entry;
647+
648+ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN);
649+ memset(&fw_entry, 0, sizeof fw_entry);
650+ if (fw_get_entry(&fw_entry))
651+ return ENODEV;
652+
653+ strncpy(initiatorname, fw_entry.initiatorname,
654+ sizeof fw_entry.initiatorname);
655+
656+ return 0;
657+}
658diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy
659new file mode 100644
660index 0000000..663770f
661--- /dev/null
662+++ b/libiscsi/libiscsi.doxy
663@@ -0,0 +1,1473 @@
664+# Doxyfile 1.5.7.1
665+
666+# This file describes the settings to be used by the documentation system
667+# doxygen (www.doxygen.org) for a project
668+#
669+# All text after a hash (#) is considered a comment and will be ignored
670+# The format is:
671+# TAG = value [value, ...]
672+# For lists items can also be appended using:
673+# TAG += value [value, ...]
674+# Values that contain spaces should be placed between quotes (" ")
675+
676+#---------------------------------------------------------------------------
677+# Project related configuration options
678+#---------------------------------------------------------------------------
679+
680+# This tag specifies the encoding used for all characters in the config file
681+# that follow. The default is UTF-8 which is also the encoding used for all
682+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
683+# iconv built into libc) for the transcoding. See
684+# http://www.gnu.org/software/libiconv for the list of possible encodings.
685+
686+DOXYFILE_ENCODING = UTF-8
687+
688+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
689+# by quotes) that should identify the project.
690+
691+PROJECT_NAME = libiscsi
692+
693+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
694+# This could be handy for archiving the generated documentation or
695+# if some version control system is used.
696+
697+PROJECT_NUMBER =
698+
699+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
700+# base path where the generated documentation will be put.
701+# If a relative path is entered, it will be relative to the location
702+# where doxygen was started. If left blank the current directory will be used.
703+
704+OUTPUT_DIRECTORY =
705+
706+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
707+# 4096 sub-directories (in 2 levels) under the output directory of each output
708+# format and will distribute the generated files over these directories.
709+# Enabling this option can be useful when feeding doxygen a huge amount of
710+# source files, where putting all generated files in the same directory would
711+# otherwise cause performance problems for the file system.
712+
713+CREATE_SUBDIRS = NO
714+
715+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
716+# documentation generated by doxygen is written. Doxygen will use this
717+# information to generate all constant output in the proper language.
718+# The default language is English, other supported languages are:
719+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
720+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
721+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
722+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
723+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,
724+# Spanish, Swedish, and Ukrainian.
725+
726+OUTPUT_LANGUAGE = English
727+
728+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
729+# include brief member descriptions after the members that are listed in
730+# the file and class documentation (similar to JavaDoc).
731+# Set to NO to disable this.
732+
733+BRIEF_MEMBER_DESC = YES
734+
735+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
736+# the brief description of a member or function before the detailed description.
737+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
738+# brief descriptions will be completely suppressed.
739+
740+REPEAT_BRIEF = NO
741+
742+# This tag implements a quasi-intelligent brief description abbreviator
743+# that is used to form the text in various listings. Each string
744+# in this list, if found as the leading text of the brief description, will be
745+# stripped from the text and the result after processing the whole list, is
746+# used as the annotated text. Otherwise, the brief description is used as-is.
747+# If left blank, the following values are used ("$name" is automatically
748+# replaced with the name of the entity): "The $name class" "The $name widget"
749+# "The $name file" "is" "provides" "specifies" "contains"
750+# "represents" "a" "an" "the"
751+
752+ABBREVIATE_BRIEF =
753+
754+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
755+# Doxygen will generate a detailed section even if there is only a brief
756+# description.
757+
758+ALWAYS_DETAILED_SEC = YES
759+
760+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
761+# inherited members of a class in the documentation of that class as if those
762+# members were ordinary class members. Constructors, destructors and assignment
763+# operators of the base classes will not be shown.
764+
765+INLINE_INHERITED_MEMB = NO
766+
767+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
768+# path before files name in the file list and in the header files. If set
769+# to NO the shortest path that makes the file name unique will be used.
770+
771+FULL_PATH_NAMES = YES
772+
773+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
774+# can be used to strip a user-defined part of the path. Stripping is
775+# only done if one of the specified strings matches the left-hand part of
776+# the path. The tag can be used to show relative paths in the file list.
777+# If left blank the directory from which doxygen is run is used as the
778+# path to strip.
779+
780+STRIP_FROM_PATH =
781+
782+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
783+# the path mentioned in the documentation of a class, which tells
784+# the reader which header file to include in order to use a class.
785+# If left blank only the name of the header file containing the class
786+# definition is used. Otherwise one should specify the include paths that
787+# are normally passed to the compiler using the -I flag.
788+
789+STRIP_FROM_INC_PATH =
790+
791+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
792+# (but less readable) file names. This can be useful is your file systems
793+# doesn't support long names like on DOS, Mac, or CD-ROM.
794+
795+SHORT_NAMES = NO
796+
797+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
798+# will interpret the first line (until the first dot) of a JavaDoc-style
799+# comment as the brief description. If set to NO, the JavaDoc
800+# comments will behave just like regular Qt-style comments
801+# (thus requiring an explicit @brief command for a brief description.)
802+
803+JAVADOC_AUTOBRIEF = NO
804+
805+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
806+# interpret the first line (until the first dot) of a Qt-style
807+# comment as the brief description. If set to NO, the comments
808+# will behave just like regular Qt-style comments (thus requiring
809+# an explicit \brief command for a brief description.)
810+
811+QT_AUTOBRIEF = NO
812+
813+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
814+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
815+# comments) as a brief description. This used to be the default behaviour.
816+# The new default is to treat a multi-line C++ comment block as a detailed
817+# description. Set this tag to YES if you prefer the old behaviour instead.
818+
819+MULTILINE_CPP_IS_BRIEF = NO
820+
821+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
822+# member inherits the documentation from any documented member that it
823+# re-implements.
824+
825+INHERIT_DOCS = YES
826+
827+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
828+# a new page for each member. If set to NO, the documentation of a member will
829+# be part of the file/class/namespace that contains it.
830+
831+SEPARATE_MEMBER_PAGES = NO
832+
833+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
834+# Doxygen uses this value to replace tabs by spaces in code fragments.
835+
836+TAB_SIZE = 8
837+
838+# This tag can be used to specify a number of aliases that acts
839+# as commands in the documentation. An alias has the form "name=value".
840+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
841+# put the command \sideeffect (or @sideeffect) in the documentation, which
842+# will result in a user-defined paragraph with heading "Side Effects:".
843+# You can put \n's in the value part of an alias to insert newlines.
844+
845+ALIASES =
846+
847+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
848+# sources only. Doxygen will then generate output that is more tailored for C.
849+# For instance, some of the names that are used will be different. The list
850+# of all members will be omitted, etc.
851+
852+OPTIMIZE_OUTPUT_FOR_C = YES
853+
854+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
855+# sources only. Doxygen will then generate output that is more tailored for
856+# Java. For instance, namespaces will be presented as packages, qualified
857+# scopes will look different, etc.
858+
859+OPTIMIZE_OUTPUT_JAVA = NO
860+
861+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
862+# sources only. Doxygen will then generate output that is more tailored for
863+# Fortran.
864+
865+OPTIMIZE_FOR_FORTRAN = NO
866+
867+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
868+# sources. Doxygen will then generate output that is tailored for
869+# VHDL.
870+
871+OPTIMIZE_OUTPUT_VHDL = NO
872+
873+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
874+# to include (a tag file for) the STL sources as input, then you should
875+# set this tag to YES in order to let doxygen match functions declarations and
876+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
877+# func(std::string) {}). This also make the inheritance and collaboration
878+# diagrams that involve STL classes more complete and accurate.
879+
880+BUILTIN_STL_SUPPORT = NO
881+
882+# If you use Microsoft's C++/CLI language, you should set this option to YES to
883+# enable parsing support.
884+
885+CPP_CLI_SUPPORT = NO
886+
887+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
888+# Doxygen will parse them like normal C++ but will assume all classes use public
889+# instead of private inheritance when no explicit protection keyword is present.
890+
891+SIP_SUPPORT = NO
892+
893+# For Microsoft's IDL there are propget and propput attributes to indicate getter
894+# and setter methods for a property. Setting this option to YES (the default)
895+# will make doxygen to replace the get and set methods by a property in the
896+# documentation. This will only work if the methods are indeed getting or
897+# setting a simple type. If this is not the case, or you want to show the
898+# methods anyway, you should set this option to NO.
899+
900+IDL_PROPERTY_SUPPORT = YES
901+
902+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
903+# tag is set to YES, then doxygen will reuse the documentation of the first
904+# member in the group (if any) for the other members of the group. By default
905+# all members of a group must be documented explicitly.
906+
907+DISTRIBUTE_GROUP_DOC = NO
908+
909+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
910+# the same type (for instance a group of public functions) to be put as a
911+# subgroup of that type (e.g. under the Public Functions section). Set it to
912+# NO to prevent subgrouping. Alternatively, this can be done per class using
913+# the \nosubgrouping command.
914+
915+SUBGROUPING = YES
916+
917+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
918+# is documented as struct, union, or enum with the name of the typedef. So
919+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
920+# with name TypeT. When disabled the typedef will appear as a member of a file,
921+# namespace, or class. And the struct will be named TypeS. This can typically
922+# be useful for C code in case the coding convention dictates that all compound
923+# types are typedef'ed and only the typedef is referenced, never the tag name.
924+
925+TYPEDEF_HIDES_STRUCT = NO
926+
927+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
928+# determine which symbols to keep in memory and which to flush to disk.
929+# When the cache is full, less often used symbols will be written to disk.
930+# For small to medium size projects (<1000 input files) the default value is
931+# probably good enough. For larger projects a too small cache size can cause
932+# doxygen to be busy swapping symbols to and from disk most of the time
933+# causing a significant performance penality.
934+# If the system has enough physical memory increasing the cache will improve the
935+# performance by keeping more symbols in memory. Note that the value works on
936+# a logarithmic scale so increasing the size by one will rougly double the
937+# memory usage. The cache size is given by this formula:
938+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
939+# corresponding to a cache size of 2^16 = 65536 symbols
940+
941+SYMBOL_CACHE_SIZE = 0
942+
943+#---------------------------------------------------------------------------
944+# Build related configuration options
945+#---------------------------------------------------------------------------
946+
947+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
948+# documentation are documented, even if no documentation was available.
949+# Private class members and static file members will be hidden unless
950+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
951+
952+EXTRACT_ALL = YES
953+
954+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
955+# will be included in the documentation.
956+
957+EXTRACT_PRIVATE = NO
958+
959+# If the EXTRACT_STATIC tag is set to YES all static members of a file
960+# will be included in the documentation.
961+
962+EXTRACT_STATIC = NO
963+
964+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
965+# defined locally in source files will be included in the documentation.
966+# If set to NO only classes defined in header files are included.
967+
968+EXTRACT_LOCAL_CLASSES = YES
969+
970+# This flag is only useful for Objective-C code. When set to YES local
971+# methods, which are defined in the implementation section but not in
972+# the interface are included in the documentation.
973+# If set to NO (the default) only methods in the interface are included.
974+
975+EXTRACT_LOCAL_METHODS = NO
976+
977+# If this flag is set to YES, the members of anonymous namespaces will be
978+# extracted and appear in the documentation as a namespace called
979+# 'anonymous_namespace{file}', where file will be replaced with the base
980+# name of the file that contains the anonymous namespace. By default
981+# anonymous namespace are hidden.
982+
983+EXTRACT_ANON_NSPACES = NO
984+
985+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
986+# undocumented members of documented classes, files or namespaces.
987+# If set to NO (the default) these members will be included in the
988+# various overviews, but no documentation section is generated.
989+# This option has no effect if EXTRACT_ALL is enabled.
990+
991+HIDE_UNDOC_MEMBERS = NO
992+
993+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
994+# undocumented classes that are normally visible in the class hierarchy.
995+# If set to NO (the default) these classes will be included in the various
996+# overviews. This option has no effect if EXTRACT_ALL is enabled.
997+
998+HIDE_UNDOC_CLASSES = NO
999+
1000+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
1001+# friend (class|struct|union) declarations.
1002+# If set to NO (the default) these declarations will be included in the
1003+# documentation.
1004+
1005+HIDE_FRIEND_COMPOUNDS = NO
1006+
1007+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
1008+# documentation blocks found inside the body of a function.
1009+# If set to NO (the default) these blocks will be appended to the
1010+# function's detailed documentation block.
1011+
1012+HIDE_IN_BODY_DOCS = NO
1013+
1014+# The INTERNAL_DOCS tag determines if documentation
1015+# that is typed after a \internal command is included. If the tag is set
1016+# to NO (the default) then the documentation will be excluded.
1017+# Set it to YES to include the internal documentation.
1018+
1019+INTERNAL_DOCS = NO
1020+
1021+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
1022+# file names in lower-case letters. If set to YES upper-case letters are also
1023+# allowed. This is useful if you have classes or files whose names only differ
1024+# in case and if your file system supports case sensitive file names. Windows
1025+# and Mac users are advised to set this option to NO.
1026+
1027+CASE_SENSE_NAMES = YES
1028+
1029+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
1030+# will show members with their full class and namespace scopes in the
1031+# documentation. If set to YES the scope will be hidden.
1032+
1033+HIDE_SCOPE_NAMES = NO
1034+
1035+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
1036+# will put a list of the files that are included by a file in the documentation
1037+# of that file.
1038+
1039+SHOW_INCLUDE_FILES = YES
1040+
1041+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
1042+# is inserted in the documentation for inline members.
1043+
1044+INLINE_INFO = YES
1045+
1046+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
1047+# will sort the (detailed) documentation of file and class members
1048+# alphabetically by member name. If set to NO the members will appear in
1049+# declaration order.
1050+
1051+SORT_MEMBER_DOCS = YES
1052+
1053+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
1054+# brief documentation of file, namespace and class members alphabetically
1055+# by member name. If set to NO (the default) the members will appear in
1056+# declaration order.
1057+
1058+SORT_BRIEF_DOCS = NO
1059+
1060+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
1061+# hierarchy of group names into alphabetical order. If set to NO (the default)
1062+# the group names will appear in their defined order.
1063+
1064+SORT_GROUP_NAMES = NO
1065+
1066+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
1067+# sorted by fully-qualified names, including namespaces. If set to
1068+# NO (the default), the class list will be sorted only by class name,
1069+# not including the namespace part.
1070+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
1071+# Note: This option applies only to the class list, not to the
1072+# alphabetical list.
1073+
1074+SORT_BY_SCOPE_NAME = NO
1075+
1076+# The GENERATE_TODOLIST tag can be used to enable (YES) or
1077+# disable (NO) the todo list. This list is created by putting \todo
1078+# commands in the documentation.
1079+
1080+GENERATE_TODOLIST = YES
1081+
1082+# The GENERATE_TESTLIST tag can be used to enable (YES) or
1083+# disable (NO) the test list. This list is created by putting \test
1084+# commands in the documentation.
1085+
1086+GENERATE_TESTLIST = YES
1087+
1088+# The GENERATE_BUGLIST tag can be used to enable (YES) or
1089+# disable (NO) the bug list. This list is created by putting \bug
1090+# commands in the documentation.
1091+
1092+GENERATE_BUGLIST = YES
1093+
1094+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
1095+# disable (NO) the deprecated list. This list is created by putting
1096+# \deprecated commands in the documentation.
1097+
1098+GENERATE_DEPRECATEDLIST= YES
1099+
1100+# The ENABLED_SECTIONS tag can be used to enable conditional
1101+# documentation sections, marked by \if sectionname ... \endif.
1102+
1103+ENABLED_SECTIONS =
1104+
1105+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
1106+# the initial value of a variable or define consists of for it to appear in
1107+# the documentation. If the initializer consists of more lines than specified
1108+# here it will be hidden. Use a value of 0 to hide initializers completely.
1109+# The appearance of the initializer of individual variables and defines in the
1110+# documentation can be controlled using \showinitializer or \hideinitializer
1111+# command in the documentation regardless of this setting.
1112+
1113+MAX_INITIALIZER_LINES = 30
1114+
1115+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
1116+# at the bottom of the documentation of classes and structs. If set to YES the
1117+# list will mention the files that were used to generate the documentation.
1118+
1119+SHOW_USED_FILES = YES
1120+
1121+# If the sources in your project are distributed over multiple directories
1122+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
1123+# in the documentation. The default is NO.
1124+
1125+SHOW_DIRECTORIES = NO
1126+
1127+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
1128+# This will remove the Files entry from the Quick Index and from the
1129+# Folder Tree View (if specified). The default is YES.
1130+
1131+SHOW_FILES = YES
1132+
1133+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
1134+# Namespaces page. This will remove the Namespaces entry from the Quick Index
1135+# and from the Folder Tree View (if specified). The default is YES.
1136+
1137+SHOW_NAMESPACES = YES
1138+
1139+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
1140+# doxygen should invoke to get the current version for each file (typically from
1141+# the version control system). Doxygen will invoke the program by executing (via
1142+# popen()) the command <command> <input-file>, where <command> is the value of
1143+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
1144+# provided by doxygen. Whatever the program writes to standard output
1145+# is used as the file version. See the manual for examples.
1146+
1147+FILE_VERSION_FILTER =
1148+
1149+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
1150+# doxygen. The layout file controls the global structure of the generated output files
1151+# in an output format independent way. The create the layout file that represents
1152+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
1153+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
1154+# of the layout file.
1155+
1156+LAYOUT_FILE =
1157+
1158+#---------------------------------------------------------------------------
1159+# configuration options related to warning and progress messages
1160+#---------------------------------------------------------------------------
1161+
1162+# The QUIET tag can be used to turn on/off the messages that are generated
1163+# by doxygen. Possible values are YES and NO. If left blank NO is used.
1164+
1165+QUIET = YES
1166+
1167+# The WARNINGS tag can be used to turn on/off the warning messages that are
1168+# generated by doxygen. Possible values are YES and NO. If left blank
1169+# NO is used.
1170+
1171+WARNINGS = YES
1172+
1173+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
1174+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
1175+# automatically be disabled.
1176+
1177+WARN_IF_UNDOCUMENTED = YES
1178+
1179+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
1180+# potential errors in the documentation, such as not documenting some
1181+# parameters in a documented function, or documenting parameters that
1182+# don't exist or using markup commands wrongly.
1183+
1184+WARN_IF_DOC_ERROR = YES
1185+
1186+# This WARN_NO_PARAMDOC option can be abled to get warnings for
1187+# functions that are documented, but have no documentation for their parameters
1188+# or return value. If set to NO (the default) doxygen will only warn about
1189+# wrong or incomplete parameter documentation, but not about the absence of
1190+# documentation.
1191+
1192+WARN_NO_PARAMDOC = NO
1193+
1194+# The WARN_FORMAT tag determines the format of the warning messages that
1195+# doxygen can produce. The string should contain the $file, $line, and $text
1196+# tags, which will be replaced by the file and line number from which the
1197+# warning originated and the warning text. Optionally the format may contain
1198+# $version, which will be replaced by the version of the file (if it could
1199+# be obtained via FILE_VERSION_FILTER)
1200+
1201+WARN_FORMAT = "$file:$line: $text"
1202+
1203+# The WARN_LOGFILE tag can be used to specify a file to which warning
1204+# and error messages should be written. If left blank the output is written
1205+# to stderr.
1206+
1207+WARN_LOGFILE =
1208+
1209+#---------------------------------------------------------------------------
1210+# configuration options related to the input files
1211+#---------------------------------------------------------------------------
1212+
1213+# The INPUT tag can be used to specify the files and/or directories that contain
1214+# documented source files. You may enter file names like "myfile.cpp" or
1215+# directories like "/usr/src/myproject". Separate the files or directories
1216+# with spaces.
1217+
1218+INPUT =
1219+
1220+# This tag can be used to specify the character encoding of the source files
1221+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
1222+# also the default input encoding. Doxygen uses libiconv (or the iconv built
1223+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
1224+# the list of possible encodings.
1225+
1226+INPUT_ENCODING = UTF-8
1227+
1228+# If the value of the INPUT tag contains directories, you can use the
1229+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
1230+# and *.h) to filter out the source-files in the directories. If left
1231+# blank the following patterns are tested:
1232+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
1233+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
1234+
1235+FILE_PATTERNS =
1236+
1237+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
1238+# should be searched for input files as well. Possible values are YES and NO.
1239+# If left blank NO is used.
1240+
1241+RECURSIVE = NO
1242+
1243+# The EXCLUDE tag can be used to specify files and/or directories that should
1244+# excluded from the INPUT source files. This way you can easily exclude a
1245+# subdirectory from a directory tree whose root is specified with the INPUT tag.
1246+
1247+EXCLUDE =
1248+
1249+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
1250+# directories that are symbolic links (a Unix filesystem feature) are excluded
1251+# from the input.
1252+
1253+EXCLUDE_SYMLINKS = NO
1254+
1255+# If the value of the INPUT tag contains directories, you can use the
1256+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
1257+# certain files from those directories. Note that the wildcards are matched
1258+# against the file with absolute path, so to exclude all test directories
1259+# for example use the pattern */test/*
1260+
1261+EXCLUDE_PATTERNS =
1262+
1263+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
1264+# (namespaces, classes, functions, etc.) that should be excluded from the
1265+# output. The symbol name can be a fully qualified name, a word, or if the
1266+# wildcard * is used, a substring. Examples: ANamespace, AClass,
1267+# AClass::ANamespace, ANamespace::*Test
1268+
1269+EXCLUDE_SYMBOLS =
1270+
1271+# The EXAMPLE_PATH tag can be used to specify one or more files or
1272+# directories that contain example code fragments that are included (see
1273+# the \include command).
1274+
1275+EXAMPLE_PATH =
1276+
1277+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
1278+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
1279+# and *.h) to filter out the source-files in the directories. If left
1280+# blank all files are included.
1281+
1282+EXAMPLE_PATTERNS =
1283+
1284+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
1285+# searched for input files to be used with the \include or \dontinclude
1286+# commands irrespective of the value of the RECURSIVE tag.
1287+# Possible values are YES and NO. If left blank NO is used.
1288+
1289+EXAMPLE_RECURSIVE = NO
1290+
1291+# The IMAGE_PATH tag can be used to specify one or more files or
1292+# directories that contain image that are included in the documentation (see
1293+# the \image command).
1294+
1295+IMAGE_PATH =
1296+
1297+# The INPUT_FILTER tag can be used to specify a program that doxygen should
1298+# invoke to filter for each input file. Doxygen will invoke the filter program
1299+# by executing (via popen()) the command <filter> <input-file>, where <filter>
1300+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
1301+# input file. Doxygen will then use the output that the filter program writes
1302+# to standard output. If FILTER_PATTERNS is specified, this tag will be
1303+# ignored.
1304+
1305+INPUT_FILTER =
1306+
1307+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
1308+# basis. Doxygen will compare the file name with each pattern and apply the
1309+# filter if there is a match. The filters are a list of the form:
1310+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
1311+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
1312+# is applied to all files.
1313+
1314+FILTER_PATTERNS =
1315+
1316+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
1317+# INPUT_FILTER) will be used to filter the input files when producing source
1318+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
1319+
1320+FILTER_SOURCE_FILES = NO
1321+
1322+#---------------------------------------------------------------------------
1323+# configuration options related to source browsing
1324+#---------------------------------------------------------------------------
1325+
1326+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
1327+# be generated. Documented entities will be cross-referenced with these sources.
1328+# Note: To get rid of all source code in the generated output, make sure also
1329+# VERBATIM_HEADERS is set to NO.
1330+
1331+SOURCE_BROWSER = NO
1332+
1333+# Setting the INLINE_SOURCES tag to YES will include the body
1334+# of functions and classes directly in the documentation.
1335+
1336+INLINE_SOURCES = NO
1337+
1338+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
1339+# doxygen to hide any special comment blocks from generated source code
1340+# fragments. Normal C and C++ comments will always remain visible.
1341+
1342+STRIP_CODE_COMMENTS = YES
1343+
1344+# If the REFERENCED_BY_RELATION tag is set to YES
1345+# then for each documented function all documented
1346+# functions referencing it will be listed.
1347+
1348+REFERENCED_BY_RELATION = NO
1349+
1350+# If the REFERENCES_RELATION tag is set to YES
1351+# then for each documented function all documented entities
1352+# called/used by that function will be listed.
1353+
1354+REFERENCES_RELATION = NO
1355+
1356+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
1357+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
1358+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
1359+# link to the source code. Otherwise they will link to the documentstion.
1360+
1361+REFERENCES_LINK_SOURCE = YES
1362+
1363+# If the USE_HTAGS tag is set to YES then the references to source code
1364+# will point to the HTML generated by the htags(1) tool instead of doxygen
1365+# built-in source browser. The htags tool is part of GNU's global source
1366+# tagging system (see http://www.gnu.org/software/global/global.html). You
1367+# will need version 4.8.6 or higher.
1368+
1369+USE_HTAGS = NO
1370+
1371+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
1372+# will generate a verbatim copy of the header file for each class for
1373+# which an include is specified. Set to NO to disable this.
1374+
1375+VERBATIM_HEADERS = YES
1376+
1377+#---------------------------------------------------------------------------
1378+# configuration options related to the alphabetical class index
1379+#---------------------------------------------------------------------------
1380+
1381+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
1382+# of all compounds will be generated. Enable this if the project
1383+# contains a lot of classes, structs, unions or interfaces.
1384+
1385+ALPHABETICAL_INDEX = NO
1386+
1387+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
1388+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
1389+# in which this list will be split (can be a number in the range [1..20])
1390+
1391+COLS_IN_ALPHA_INDEX = 5
1392+
1393+# In case all classes in a project start with a common prefix, all
1394+# classes will be put under the same header in the alphabetical index.
1395+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
1396+# should be ignored while generating the index headers.
1397+
1398+IGNORE_PREFIX =
1399+
1400+#---------------------------------------------------------------------------
1401+# configuration options related to the HTML output
1402+#---------------------------------------------------------------------------
1403+
1404+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
1405+# generate HTML output.
1406+
1407+GENERATE_HTML = YES
1408+
1409+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
1410+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1411+# put in front of it. If left blank `html' will be used as the default path.
1412+
1413+HTML_OUTPUT = html
1414+
1415+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
1416+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
1417+# doxygen will generate files with .html extension.
1418+
1419+HTML_FILE_EXTENSION = .html
1420+
1421+# The HTML_HEADER tag can be used to specify a personal HTML header for
1422+# each generated HTML page. If it is left blank doxygen will generate a
1423+# standard header.
1424+
1425+HTML_HEADER =
1426+
1427+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
1428+# each generated HTML page. If it is left blank doxygen will generate a
1429+# standard footer.
1430+
1431+HTML_FOOTER =
1432+
1433+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
1434+# style sheet that is used by each HTML page. It can be used to
1435+# fine-tune the look of the HTML output. If the tag is left blank doxygen
1436+# will generate a default style sheet. Note that doxygen will try to copy
1437+# the style sheet file to the HTML output directory, so don't put your own
1438+# stylesheet in the HTML output directory as well, or it will be erased!
1439+
1440+HTML_STYLESHEET =
1441+
1442+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
1443+# files or namespaces will be aligned in HTML using tables. If set to
1444+# NO a bullet list will be used.
1445+
1446+HTML_ALIGN_MEMBERS = YES
1447+
1448+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
1449+# documentation will contain sections that can be hidden and shown after the
1450+# page has loaded. For this to work a browser that supports
1451+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
1452+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
1453+
1454+HTML_DYNAMIC_SECTIONS = NO
1455+
1456+# If the GENERATE_DOCSET tag is set to YES, additional index files
1457+# will be generated that can be used as input for Apple's Xcode 3
1458+# integrated development environment, introduced with OSX 10.5 (Leopard).
1459+# To create a documentation set, doxygen will generate a Makefile in the
1460+# HTML output directory. Running make will produce the docset in that
1461+# directory and running "make install" will install the docset in
1462+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
1463+# it at startup.
1464+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
1465+
1466+GENERATE_DOCSET = NO
1467+
1468+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
1469+# feed. A documentation feed provides an umbrella under which multiple
1470+# documentation sets from a single provider (such as a company or product suite)
1471+# can be grouped.
1472+
1473+DOCSET_FEEDNAME = "Doxygen generated docs"
1474+
1475+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
1476+# should uniquely identify the documentation set bundle. This should be a
1477+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
1478+# will append .docset to the name.
1479+
1480+DOCSET_BUNDLE_ID = org.doxygen.Project
1481+
1482+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
1483+# will be generated that can be used as input for tools like the
1484+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
1485+# of the generated HTML documentation.
1486+
1487+GENERATE_HTMLHELP = NO
1488+
1489+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
1490+# be used to specify the file name of the resulting .chm file. You
1491+# can add a path in front of the file if the result should not be
1492+# written to the html output directory.
1493+
1494+CHM_FILE =
1495+
1496+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
1497+# be used to specify the location (absolute path including file name) of
1498+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
1499+# the HTML help compiler on the generated index.hhp.
1500+
1501+HHC_LOCATION =
1502+
1503+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
1504+# controls if a separate .chi index file is generated (YES) or that
1505+# it should be included in the master .chm file (NO).
1506+
1507+GENERATE_CHI = NO
1508+
1509+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
1510+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
1511+# content.
1512+
1513+CHM_INDEX_ENCODING =
1514+
1515+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
1516+# controls whether a binary table of contents is generated (YES) or a
1517+# normal table of contents (NO) in the .chm file.
1518+
1519+BINARY_TOC = NO
1520+
1521+# The TOC_EXPAND flag can be set to YES to add extra items for group members
1522+# to the contents of the HTML help documentation and to the tree view.
1523+
1524+TOC_EXPAND = NO
1525+
1526+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
1527+# are set, an additional index file will be generated that can be used as input for
1528+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
1529+# HTML documentation.
1530+
1531+GENERATE_QHP = NO
1532+
1533+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
1534+# be used to specify the file name of the resulting .qch file.
1535+# The path specified is relative to the HTML output folder.
1536+
1537+QCH_FILE =
1538+
1539+# The QHP_NAMESPACE tag specifies the namespace to use when generating
1540+# Qt Help Project output. For more information please see
1541+# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
1542+
1543+QHP_NAMESPACE = org.doxygen.Project
1544+
1545+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
1546+# Qt Help Project output. For more information please see
1547+# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
1548+
1549+QHP_VIRTUAL_FOLDER = doc
1550+
1551+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
1552+# be used to specify the location of Qt's qhelpgenerator.
1553+# If non-empty doxygen will try to run qhelpgenerator on the generated
1554+# .qhp file .
1555+
1556+QHG_LOCATION =
1557+
1558+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
1559+# top of each HTML page. The value NO (the default) enables the index and
1560+# the value YES disables it.
1561+
1562+DISABLE_INDEX = NO
1563+
1564+# This tag can be used to set the number of enum values (range [1..20])
1565+# that doxygen will group on one line in the generated HTML documentation.
1566+
1567+ENUM_VALUES_PER_LINE = 4
1568+
1569+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
1570+# structure should be generated to display hierarchical information.
1571+# If the tag value is set to FRAME, a side panel will be generated
1572+# containing a tree-like index structure (just like the one that
1573+# is generated for HTML Help). For this to work a browser that supports
1574+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
1575+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
1576+# probably better off using the HTML help feature. Other possible values
1577+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
1578+# and Class Hierarchy pages using a tree view instead of an ordered list;
1579+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
1580+# disables this behavior completely. For backwards compatibility with previous
1581+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
1582+# respectively.
1583+
1584+GENERATE_TREEVIEW = NONE
1585+
1586+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
1587+# used to set the initial width (in pixels) of the frame in which the tree
1588+# is shown.
1589+
1590+TREEVIEW_WIDTH = 250
1591+
1592+# Use this tag to change the font size of Latex formulas included
1593+# as images in the HTML documentation. The default is 10. Note that
1594+# when you change the font size after a successful doxygen run you need
1595+# to manually remove any form_*.png images from the HTML output directory
1596+# to force them to be regenerated.
1597+
1598+FORMULA_FONTSIZE = 10
1599+
1600+#---------------------------------------------------------------------------
1601+# configuration options related to the LaTeX output
1602+#---------------------------------------------------------------------------
1603+
1604+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
1605+# generate Latex output.
1606+
1607+GENERATE_LATEX = NO
1608+
1609+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
1610+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1611+# put in front of it. If left blank `latex' will be used as the default path.
1612+
1613+LATEX_OUTPUT = latex
1614+
1615+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
1616+# invoked. If left blank `latex' will be used as the default command name.
1617+
1618+LATEX_CMD_NAME = latex
1619+
1620+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
1621+# generate index for LaTeX. If left blank `makeindex' will be used as the
1622+# default command name.
1623+
1624+MAKEINDEX_CMD_NAME = makeindex
1625+
1626+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
1627+# LaTeX documents. This may be useful for small projects and may help to
1628+# save some trees in general.
1629+
1630+COMPACT_LATEX = NO
1631+
1632+# The PAPER_TYPE tag can be used to set the paper type that is used
1633+# by the printer. Possible values are: a4, a4wide, letter, legal and
1634+# executive. If left blank a4wide will be used.
1635+
1636+PAPER_TYPE = a4wide
1637+
1638+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
1639+# packages that should be included in the LaTeX output.
1640+
1641+EXTRA_PACKAGES =
1642+
1643+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
1644+# the generated latex document. The header should contain everything until
1645+# the first chapter. If it is left blank doxygen will generate a
1646+# standard header. Notice: only use this tag if you know what you are doing!
1647+
1648+LATEX_HEADER =
1649+
1650+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
1651+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
1652+# contain links (just like the HTML output) instead of page references
1653+# This makes the output suitable for online browsing using a pdf viewer.
1654+
1655+PDF_HYPERLINKS = YES
1656+
1657+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
1658+# plain latex in the generated Makefile. Set this option to YES to get a
1659+# higher quality PDF documentation.
1660+
1661+USE_PDFLATEX = YES
1662+
1663+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
1664+# command to the generated LaTeX files. This will instruct LaTeX to keep
1665+# running if errors occur, instead of asking the user for help.
1666+# This option is also used when generating formulas in HTML.
1667+
1668+LATEX_BATCHMODE = NO
1669+
1670+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
1671+# include the index chapters (such as File Index, Compound Index, etc.)
1672+# in the output.
1673+
1674+LATEX_HIDE_INDICES = NO
1675+
1676+#---------------------------------------------------------------------------
1677+# configuration options related to the RTF output
1678+#---------------------------------------------------------------------------
1679+
1680+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
1681+# The RTF output is optimized for Word 97 and may not look very pretty with
1682+# other RTF readers or editors.
1683+
1684+GENERATE_RTF = NO
1685+
1686+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
1687+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1688+# put in front of it. If left blank `rtf' will be used as the default path.
1689+
1690+RTF_OUTPUT = rtf
1691+
1692+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
1693+# RTF documents. This may be useful for small projects and may help to
1694+# save some trees in general.
1695+
1696+COMPACT_RTF = NO
1697+
1698+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
1699+# will contain hyperlink fields. The RTF file will
1700+# contain links (just like the HTML output) instead of page references.
1701+# This makes the output suitable for online browsing using WORD or other
1702+# programs which support those fields.
1703+# Note: wordpad (write) and others do not support links.
1704+
1705+RTF_HYPERLINKS = NO
1706+
1707+# Load stylesheet definitions from file. Syntax is similar to doxygen's
1708+# config file, i.e. a series of assignments. You only have to provide
1709+# replacements, missing definitions are set to their default value.
1710+
1711+RTF_STYLESHEET_FILE =
1712+
1713+# Set optional variables used in the generation of an rtf document.
1714+# Syntax is similar to doxygen's config file.
1715+
1716+RTF_EXTENSIONS_FILE =
1717+
1718+#---------------------------------------------------------------------------
1719+# configuration options related to the man page output
1720+#---------------------------------------------------------------------------
1721+
1722+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
1723+# generate man pages
1724+
1725+GENERATE_MAN = NO
1726+
1727+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
1728+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1729+# put in front of it. If left blank `man' will be used as the default path.
1730+
1731+MAN_OUTPUT = man
1732+
1733+# The MAN_EXTENSION tag determines the extension that is added to
1734+# the generated man pages (default is the subroutine's section .3)
1735+
1736+MAN_EXTENSION = .3
1737+
1738+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
1739+# then it will generate one additional man file for each entity
1740+# documented in the real man page(s). These additional files
1741+# only source the real man page, but without them the man command
1742+# would be unable to find the correct page. The default is NO.
1743+
1744+MAN_LINKS = NO
1745+
1746+#---------------------------------------------------------------------------
1747+# configuration options related to the XML output
1748+#---------------------------------------------------------------------------
1749+
1750+# If the GENERATE_XML tag is set to YES Doxygen will
1751+# generate an XML file that captures the structure of
1752+# the code including all documentation.
1753+
1754+GENERATE_XML = NO
1755+
1756+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
1757+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1758+# put in front of it. If left blank `xml' will be used as the default path.
1759+
1760+XML_OUTPUT = xml
1761+
1762+# The XML_SCHEMA tag can be used to specify an XML schema,
1763+# which can be used by a validating XML parser to check the
1764+# syntax of the XML files.
1765+
1766+XML_SCHEMA =
1767+
1768+# The XML_DTD tag can be used to specify an XML DTD,
1769+# which can be used by a validating XML parser to check the
1770+# syntax of the XML files.
1771+
1772+XML_DTD =
1773+
1774+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
1775+# dump the program listings (including syntax highlighting
1776+# and cross-referencing information) to the XML output. Note that
1777+# enabling this will significantly increase the size of the XML output.
1778+
1779+XML_PROGRAMLISTING = YES
1780+
1781+#---------------------------------------------------------------------------
1782+# configuration options for the AutoGen Definitions output
1783+#---------------------------------------------------------------------------
1784+
1785+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
1786+# generate an AutoGen Definitions (see autogen.sf.net) file
1787+# that captures the structure of the code including all
1788+# documentation. Note that this feature is still experimental
1789+# and incomplete at the moment.
1790+
1791+GENERATE_AUTOGEN_DEF = NO
1792+
1793+#---------------------------------------------------------------------------
1794+# configuration options related to the Perl module output
1795+#---------------------------------------------------------------------------
1796+
1797+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
1798+# generate a Perl module file that captures the structure of
1799+# the code including all documentation. Note that this
1800+# feature is still experimental and incomplete at the
1801+# moment.
1802+
1803+GENERATE_PERLMOD = NO
1804+
1805+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
1806+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
1807+# to generate PDF and DVI output from the Perl module output.
1808+
1809+PERLMOD_LATEX = NO
1810+
1811+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
1812+# nicely formatted so it can be parsed by a human reader. This is useful
1813+# if you want to understand what is going on. On the other hand, if this
1814+# tag is set to NO the size of the Perl module output will be much smaller
1815+# and Perl will parse it just the same.
1816+
1817+PERLMOD_PRETTY = YES
1818+
1819+# The names of the make variables in the generated doxyrules.make file
1820+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
1821+# This is useful so different doxyrules.make files included by the same
1822+# Makefile don't overwrite each other's variables.
1823+
1824+PERLMOD_MAKEVAR_PREFIX =
1825+
1826+#---------------------------------------------------------------------------
1827+# Configuration options related to the preprocessor
1828+#---------------------------------------------------------------------------
1829+
1830+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
1831+# evaluate all C-preprocessor directives found in the sources and include
1832+# files.
1833+
1834+ENABLE_PREPROCESSING = YES
1835+
1836+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
1837+# names in the source code. If set to NO (the default) only conditional
1838+# compilation will be performed. Macro expansion can be done in a controlled
1839+# way by setting EXPAND_ONLY_PREDEF to YES.
1840+
1841+MACRO_EXPANSION = NO
1842+
1843+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
1844+# then the macro expansion is limited to the macros specified with the
1845+# PREDEFINED and EXPAND_AS_DEFINED tags.
1846+
1847+EXPAND_ONLY_PREDEF = NO
1848+
1849+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
1850+# in the INCLUDE_PATH (see below) will be search if a #include is found.
1851+
1852+SEARCH_INCLUDES = YES
1853+
1854+# The INCLUDE_PATH tag can be used to specify one or more directories that
1855+# contain include files that are not input files but should be processed by
1856+# the preprocessor.
1857+
1858+INCLUDE_PATH =
1859+
1860+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
1861+# patterns (like *.h and *.hpp) to filter out the header-files in the
1862+# directories. If left blank, the patterns specified with FILE_PATTERNS will
1863+# be used.
1864+
1865+INCLUDE_FILE_PATTERNS =
1866+
1867+# The PREDEFINED tag can be used to specify one or more macro names that
1868+# are defined before the preprocessor is started (similar to the -D option of
1869+# gcc). The argument of the tag is a list of macros of the form: name
1870+# or name=definition (no spaces). If the definition and the = are
1871+# omitted =1 is assumed. To prevent a macro definition from being
1872+# undefined via #undef or recursively expanded use the := operator
1873+# instead of the = operator.
1874+
1875+PREDEFINED =
1876+
1877+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
1878+# this tag can be used to specify a list of macro names that should be expanded.
1879+# The macro definition that is found in the sources will be used.
1880+# Use the PREDEFINED tag if you want to use a different macro definition.
1881+
1882+EXPAND_AS_DEFINED =
1883+
1884+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
1885+# doxygen's preprocessor will remove all function-like macros that are alone
1886+# on a line, have an all uppercase name, and do not end with a semicolon. Such
1887+# function macros are typically used for boiler-plate code, and will confuse
1888+# the parser if not removed.
1889+
1890+SKIP_FUNCTION_MACROS = YES
1891+
1892+#---------------------------------------------------------------------------
1893+# Configuration::additions related to external references
1894+#---------------------------------------------------------------------------
1895+
1896+# The TAGFILES option can be used to specify one or more tagfiles.
1897+# Optionally an initial location of the external documentation
1898+# can be added for each tagfile. The format of a tag file without
1899+# this location is as follows:
1900+# TAGFILES = file1 file2 ...
1901+# Adding location for the tag files is done as follows:
1902+# TAGFILES = file1=loc1 "file2 = loc2" ...
1903+# where "loc1" and "loc2" can be relative or absolute paths or
1904+# URLs. If a location is present for each tag, the installdox tool
1905+# does not have to be run to correct the links.
1906+# Note that each tag file must have a unique name
1907+# (where the name does NOT include the path)
1908+# If a tag file is not located in the directory in which doxygen
1909+# is run, you must also specify the path to the tagfile here.
1910+
1911+TAGFILES =
1912+
1913+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
1914+# a tag file that is based on the input files it reads.
1915+
1916+GENERATE_TAGFILE =
1917+
1918+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
1919+# in the class index. If set to NO only the inherited external classes
1920+# will be listed.
1921+
1922+ALLEXTERNALS = NO
1923+
1924+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
1925+# in the modules index. If set to NO, only the current project's groups will
1926+# be listed.
1927+
1928+EXTERNAL_GROUPS = YES
1929+
1930+# The PERL_PATH should be the absolute path and name of the perl script
1931+# interpreter (i.e. the result of `which perl').
1932+
1933+PERL_PATH = /usr/bin/perl
1934+
1935+#---------------------------------------------------------------------------
1936+# Configuration options related to the dot tool
1937+#---------------------------------------------------------------------------
1938+
1939+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
1940+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
1941+# or super classes. Setting the tag to NO turns the diagrams off. Note that
1942+# this option is superseded by the HAVE_DOT option below. This is only a
1943+# fallback. It is recommended to install and use dot, since it yields more
1944+# powerful graphs.
1945+
1946+CLASS_DIAGRAMS = YES
1947+
1948+# You can define message sequence charts within doxygen comments using the \msc
1949+# command. Doxygen will then run the mscgen tool (see
1950+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
1951+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
1952+# the mscgen tool resides. If left empty the tool is assumed to be found in the
1953+# default search path.
1954+
1955+MSCGEN_PATH =
1956+
1957+# If set to YES, the inheritance and collaboration graphs will hide
1958+# inheritance and usage relations if the target is undocumented
1959+# or is not a class.
1960+
1961+HIDE_UNDOC_RELATIONS = YES
1962+
1963+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
1964+# available from the path. This tool is part of Graphviz, a graph visualization
1965+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
1966+# have no effect if this option is set to NO (the default)
1967+
1968+HAVE_DOT = NO
1969+
1970+# By default doxygen will write a font called FreeSans.ttf to the output
1971+# directory and reference it in all dot files that doxygen generates. This
1972+# font does not include all possible unicode characters however, so when you need
1973+# these (or just want a differently looking font) you can specify the font name
1974+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
1975+# which can be done by putting it in a standard location or by setting the
1976+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
1977+# containing the font.
1978+
1979+DOT_FONTNAME = FreeSans
1980+
1981+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
1982+# The default size is 10pt.
1983+
1984+DOT_FONTSIZE = 10
1985+
1986+# By default doxygen will tell dot to use the output directory to look for the
1987+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
1988+# different font using DOT_FONTNAME you can set the path where dot
1989+# can find it using this tag.
1990+
1991+DOT_FONTPATH =
1992+
1993+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
1994+# will generate a graph for each documented class showing the direct and
1995+# indirect inheritance relations. Setting this tag to YES will force the
1996+# the CLASS_DIAGRAMS tag to NO.
1997+
1998+CLASS_GRAPH = YES
1999+
2000+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
2001+# will generate a graph for each documented class showing the direct and
2002+# indirect implementation dependencies (inheritance, containment, and
2003+# class references variables) of the class with other documented classes.
2004+
2005+COLLABORATION_GRAPH = YES
2006+
2007+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
2008+# will generate a graph for groups, showing the direct groups dependencies
2009+
2010+GROUP_GRAPHS = YES
2011+
2012+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
2013+# collaboration diagrams in a style similar to the OMG's Unified Modeling
2014+# Language.
2015+
2016+UML_LOOK = NO
2017+
2018+# If set to YES, the inheritance and collaboration graphs will show the
2019+# relations between templates and their instances.
2020+
2021+TEMPLATE_RELATIONS = NO
2022+
2023+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
2024+# tags are set to YES then doxygen will generate a graph for each documented
2025+# file showing the direct and indirect include dependencies of the file with
2026+# other documented files.
2027+
2028+INCLUDE_GRAPH = YES
2029+
2030+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
2031+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
2032+# documented header file showing the documented files that directly or
2033+# indirectly include this file.
2034+
2035+INCLUDED_BY_GRAPH = YES
2036+
2037+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
2038+# doxygen will generate a call dependency graph for every global function
2039+# or class method. Note that enabling this option will significantly increase
2040+# the time of a run. So in most cases it will be better to enable call graphs
2041+# for selected functions only using the \callgraph command.
2042+
2043+CALL_GRAPH = NO
2044+
2045+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
2046+# doxygen will generate a caller dependency graph for every global function
2047+# or class method. Note that enabling this option will significantly increase
2048+# the time of a run. So in most cases it will be better to enable caller
2049+# graphs for selected functions only using the \callergraph command.
2050+
2051+CALLER_GRAPH = NO
2052+
2053+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
2054+# will graphical hierarchy of all classes instead of a textual one.
2055+
2056+GRAPHICAL_HIERARCHY = YES
2057+
2058+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
2059+# then doxygen will show the dependencies a directory has on other directories
2060+# in a graphical way. The dependency relations are determined by the #include
2061+# relations between the files in the directories.
2062+
2063+DIRECTORY_GRAPH = YES
2064+
2065+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
2066+# generated by dot. Possible values are png, jpg, or gif
2067+# If left blank png will be used.
2068+
2069+DOT_IMAGE_FORMAT = png
2070+
2071+# The tag DOT_PATH can be used to specify the path where the dot tool can be
2072+# found. If left blank, it is assumed the dot tool can be found in the path.
2073+
2074+DOT_PATH =
2075+
2076+# The DOTFILE_DIRS tag can be used to specify one or more directories that
2077+# contain dot files that are included in the documentation (see the
2078+# \dotfile command).
2079+
2080+DOTFILE_DIRS =
2081+
2082+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
2083+# nodes that will be shown in the graph. If the number of nodes in a graph
2084+# becomes larger than this value, doxygen will truncate the graph, which is
2085+# visualized by representing a node as a red box. Note that doxygen if the
2086+# number of direct children of the root node in a graph is already larger than
2087+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
2088+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
2089+
2090+DOT_GRAPH_MAX_NODES = 50
2091+
2092+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
2093+# graphs generated by dot. A depth value of 3 means that only nodes reachable
2094+# from the root by following a path via at most 3 edges will be shown. Nodes
2095+# that lay further from the root node will be omitted. Note that setting this
2096+# option to 1 or 2 may greatly reduce the computation time needed for large
2097+# code bases. Also note that the size of a graph can be further restricted by
2098+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
2099+
2100+MAX_DOT_GRAPH_DEPTH = 0
2101+
2102+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
2103+# background. This is disabled by default, because dot on Windows does not
2104+# seem to support this out of the box. Warning: Depending on the platform used,
2105+# enabling this option may lead to badly anti-aliased labels on the edges of
2106+# a graph (i.e. they become hard to read).
2107+
2108+DOT_TRANSPARENT = NO
2109+
2110+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
2111+# files in one run (i.e. multiple -o and -T options on the command line). This
2112+# makes dot run faster, but since only newer versions of dot (>1.8.10)
2113+# support this, this feature is disabled by default.
2114+
2115+DOT_MULTI_TARGETS = NO
2116+
2117+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
2118+# generate a legend page explaining the meaning of the various boxes and
2119+# arrows in the dot generated graphs.
2120+
2121+GENERATE_LEGEND = YES
2122+
2123+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
2124+# remove the intermediate dot files that are used to generate
2125+# the various graphs.
2126+
2127+DOT_CLEANUP = YES
2128+
2129+#---------------------------------------------------------------------------
2130+# Configuration::additions related to the search engine
2131+#---------------------------------------------------------------------------
2132+
2133+# The SEARCHENGINE tag specifies whether or not a search engine should be
2134+# used. If set to NO the values of all tags below this one will be ignored.
2135+
2136+SEARCHENGINE = NO
2137diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h
2138new file mode 100644
2139index 0000000..a7d05a5
2140--- /dev/null
2141+++ b/libiscsi/libiscsi.h
2142@@ -0,0 +1,343 @@
2143+/*
2144+ * iSCSI Administration library
2145+ *
2146+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
2147+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
2148+ * maintained by open-iscsi@googlegroups.com
2149+ *
2150+ * This program is free software; you can redistribute it and/or modify
2151+ * it under the terms of the GNU General Public License as published
2152+ * by the Free Software Foundation; either version 2 of the License, or
2153+ * (at your option) any later version.
2154+ *
2155+ * This program is distributed in the hope that it will be useful, but
2156+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2157+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2158+ * General Public License for more details.
2159+ *
2160+ * See the file COPYING included with this distribution for more details.
2161+ */
2162+
2163+#ifndef __LIBISCSI_H
2164+#define __LIBISCSI_H
2165+
2166+#include <netdb.h>
2167+
2168+#ifdef __cplusplus
2169+extern "C" {
2170+#endif /* __cplusplus */
2171+
2172+#if __GNUC__ >= 4
2173+#define PUBLIC __attribute__ ((visibility("default")))
2174+#else
2175+#define PUBLIC
2176+#endif
2177+
2178+/** \brief Maximum length for iSCSI values.
2179+ *
2180+ * Maximum length for iSCSI values such as hostnames and parameter values.
2181+ */
2182+#define LIBISCSI_VALUE_MAXLEN 256
2183+
2184+/** \brief supported authentication methods
2185+ *
2186+ * This enum lists all supported authentication methods.
2187+ */
2188+enum libiscsi_auth_t {
2189+ libiscsi_auth_none /** No authentication */,
2190+ libiscsi_auth_chap /** CHAP authentication */,
2191+};
2192+
2193+/** \brief libiscsi context struct
2194+ *
2195+ * Note: even though libiscsi uses a context struct, the underlying open-iscsi
2196+ * code does not, so libiscsi is not thread safe, not even when using one
2197+ * context per thread!
2198+ */
2199+struct libiscsi_context;
2200+
2201+/** \brief iSCSI node record
2202+ *
2203+ * Struct holding data uniquely identifying an iSCSI node.
2204+ */
2205+struct libiscsi_node {
2206+ char name[LIBISCSI_VALUE_MAXLEN] /** iSCSI iqn for the node. */;
2207+ int tpgt /** Portal group number. */;
2208+ /* Note open-iscsi has some code in place for multiple connections in one
2209+ node record and thus multiple address / port combi's, but this does not
2210+ get used anywhere, so we keep things simple and assume one connection */
2211+ char address[NI_MAXHOST] /** Portal hostname or IP-address. */;
2212+ int port /** Portal port number. */;
2213+};
2214+
2215+/** \brief libiscsi CHAP authentication information struct
2216+ *
2217+ * Struct holding all data needed for CHAP login / authentication. Note that
2218+ * \e reverse_username may be a 0 length string in which case only forward
2219+ * authentication will be done.
2220+ */
2221+struct libiscsi_chap_auth_info {
2222+ char username[LIBISCSI_VALUE_MAXLEN] /** Username */;
2223+ char password[LIBISCSI_VALUE_MAXLEN] /** Password */;
2224+ char reverse_username[LIBISCSI_VALUE_MAXLEN] /** Reverse Username */;
2225+ char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */;
2226+};
2227+
2228+/** \brief generic libiscsi authentication information struct
2229+ *
2230+ * Struct holding authentication information for discovery and login.
2231+ */
2232+struct libiscsi_auth_info {
2233+ enum libiscsi_auth_t method /** Authentication method to use */;
2234+ union {
2235+ struct libiscsi_chap_auth_info chap /** Chap specific info */;
2236+ } /** Union holding method depenend info */;
2237+};
2238+
2239+/** \brief Initalize libiscsi
2240+ *
2241+ * This function creates a libiscsi context and initalizes it. This context
2242+ * is need to use other libiscsi funtions.
2243+ *
2244+ * \return A pointer to the created context, or NULL in case of an error.
2245+ */
2246+PUBLIC struct libiscsi_context *libiscsi_init(void);
2247+
2248+/** \brief Cleanup libiscsi used resource
2249+ *
2250+ * This function cleanups any used resources and then destroys the passed
2251+ * context. After this the passed in context may no longer be used!
2252+ *
2253+ * \param context libiscsi context to operate on.
2254+ */
2255+PUBLIC void libiscsi_cleanup(struct libiscsi_context *context);
2256+
2257+/** \brief Discover iSCSI nodes using sendtargets and add them to the node db.
2258+ *
2259+ * This function connects to the given address and port and then tries to
2260+ * discover iSCSI nodes using the sendtargets protocol. Any found nodes are
2261+ * added to the local iSCSI node database and are returned in a dynamically
2262+ * allocated array.
2263+ *
2264+ * Note that the (optional) authentication info is for authenticating the
2265+ * discovery, and is not for the found nodes! If the connection(s) to the
2266+ * node(s) need authentication too, you can set the username / password for
2267+ * those (which can be different!) using the libiscsi_node_set_auth() function.
2268+ *
2269+ * \param context libiscsi context to operate on.
2270+ * \param address Hostname or IP-address to connect to.
2271+ * \param port Port to connect to, or 0 for the default port.
2272+ * \param auth_info Authentication information, or NULL.
2273+ * \param nr_found The number of found nodes will be returned
2274+ * through this pointer if not NULL.
2275+ * \param found_nodes The address of the dynamically allocated array
2276+ * of found nodes will be returned through this
2277+ * pointer if not NULL. The caller must free this
2278+ * array using free().
2279+ * \return 0 on success, otherwise a standard error code
2280+ * (from errno.h).
2281+ */
2282+PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context,
2283+ const char *address, int port, const struct libiscsi_auth_info *auth_info,
2284+ int *nr_found, struct libiscsi_node **found_nodes);
2285+
2286+/** \brief Read iSCSI node info from firmware and add them to the node db.
2287+ *
2288+ * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found
2289+ * nodes are added to the local iSCSI node database and are returned in a
2290+ * dynamically allocated array.
2291+ *
2292+ * Note that unlike sendtargets discovery, this function will also read
2293+ * authentication info and store that in the database too.
2294+ *
2295+ * Note this function currently is a stub which will always return -EINVAL
2296+ * (IOW it is not yet implemented)
2297+ *
2298+ * \param context libiscsi context to operate on.
2299+ * \param nr_found The number of found nodes will be returned
2300+ * through this pointer if not NULL.
2301+ * \param found_nodes The address of the dynamically allocated array
2302+ * of found nodes will be returned through this
2303+ * pointer if not NULL. The caller must free this
2304+ * array using free().
2305+ * \return 0 on success, otherwise a standard error code
2306+ * (from errno.h).
2307+ */
2308+PUBLIC int libiscsi_discover_firmware(struct libiscsi_context *context,
2309+ int *nr_found, struct libiscsi_node **found_nodes);
2310+
2311+/** \brief Check validity of the given authentication info.
2312+ *
2313+ * This function checks the validity of the given authentication info. For
2314+ * example in case of CHAP, if the username and password are not empty.
2315+ *
2316+ * This function is mainly intended for use by language bindings.
2317+ *
2318+ * \param context libiscsi context to operate on.
2319+ * \param auth_info Authentication information to check.
2320+ * \return 0 on success, otherwise EINVAL.
2321+ */
2322+PUBLIC int libiscsi_verify_auth_info(struct libiscsi_context *context,
2323+ const struct libiscsi_auth_info *auth_info);
2324+
2325+/** \brief Set the authentication info for the given node.
2326+ *
2327+ * This function sets the authentication information for the node described by
2328+ * the given node record. This will overwrite any existing authentication
2329+ * information.
2330+ *
2331+ * This is the way to specify authentication information for nodes found
2332+ * through sendtargets discovery.
2333+ *
2334+ * Note:
2335+ * 1) This is a convience wrapper around libiscsi_node_set_parameter(),
2336+ * setting the node.session.auth.* parameters.
2337+ * 2) For nodes found through firmware discovery the authentication information
2338+ * has already been set from the firmware.
2339+ * 3) \e auth_info may be NULL in which case any existing authinfo will be
2340+ * cleared.
2341+ *
2342+ * \param context libiscsi context to operate on.
2343+ * \param node iSCSI node to set auth information of
2344+ * \param auth_info Authentication information, or NULL.
2345+ * \return 0 on success, otherwise a standard error code
2346+ * (from errno.h).
2347+ */
2348+PUBLIC int libiscsi_node_set_auth(struct libiscsi_context *context,
2349+ const struct libiscsi_node *node,
2350+ const struct libiscsi_auth_info *auth_info);
2351+
2352+/** \brief Get the authentication info for the given node.
2353+ *
2354+ * This function gets the authentication information for the node described by
2355+ * the given node record.
2356+ *
2357+ * \param context libiscsi context to operate on.
2358+ * \param node iSCSI node to set auth information of
2359+ * \param auth_info Pointer to a libiscsi_auth_info struct where
2360+ * the retreived information will be stored.
2361+ * \return 0 on success, otherwise a standard error code
2362+ * (from errno.h).
2363+ */
2364+PUBLIC int libiscsi_node_get_auth(struct libiscsi_context *context,
2365+ const struct libiscsi_node *node,
2366+ struct libiscsi_auth_info *auth_info);
2367+
2368+/** \brief Login to an iSCSI node.
2369+ *
2370+ * Login to the iSCSI node described by the given node record.
2371+ *
2372+ * \param context libiscsi context to operate on.
2373+ * \param node iSCSI node to login to.
2374+ * \return 0 on success, otherwise a standard error code
2375+ * (from errno.h).
2376+ */
2377+PUBLIC int libiscsi_node_login(struct libiscsi_context *context,
2378+ const struct libiscsi_node *node);
2379+
2380+/** \brief Logout of an iSCSI node.
2381+ *
2382+ * Logout of the iSCSI node described by the given node record.
2383+ *
2384+ * \param context libiscsi context to operate on.
2385+ * \param node iSCSI node to logout from.
2386+ * \return 0 on success, otherwise a standard error code
2387+ * (from errno.h).
2388+ */
2389+PUBLIC int libiscsi_node_logout(struct libiscsi_context *context,
2390+ const struct libiscsi_node *node);
2391+
2392+/** \brief Set an iSCSI parameter for the given node
2393+ *
2394+ * Set the given nodes iSCSI parameter named by \e parameter to value \e value.
2395+ *
2396+ * \param context libiscsi context to operate on.
2397+ * \param node iSCSI node to change a parameter from.
2398+ * \param parameter Name of the parameter to set.
2399+ * \param value Value to set the parameter too.
2400+ * \return 0 on success, otherwise a standard error code
2401+ * (from errno.h).
2402+ */
2403+PUBLIC int libiscsi_node_set_parameter(struct libiscsi_context *context,
2404+ const struct libiscsi_node *node,
2405+ const char *parameter, const char *value);
2406+
2407+/** \brief Get the value of an iSCSI parameter for the given node
2408+ *
2409+ * Get the value of the given nodes iSCSI parameter named by \e parameter.
2410+ *
2411+ * \param context libiscsi context to operate on.
2412+ * \param node iSCSI node to change a parameter from.
2413+ * \param parameter Name of the parameter to get.
2414+ * \param value The retreived value is stored here, this buffer must be
2415+ * atleast LIBISCSI_VALUE_MAXLEN bytes large.
2416+ * \return 0 on success, otherwise a standard error code
2417+ * (from errno.h).
2418+ */
2419+PUBLIC int libiscsi_node_get_parameter(struct libiscsi_context *context,
2420+ const struct libiscsi_node *node, const char *parameter, char *value);
2421+
2422+/** \brief Get human readable string describing the last libiscsi error.
2423+ *
2424+ * This function can be called to get a human readable error string when a
2425+ * libiscsi function has returned an error. This function uses a single buffer
2426+ * per context, thus the result is only valid as long as no other libiscsi
2427+ * calls are made on the same context after the failing function call.
2428+ *
2429+ * \param context libiscsi context to operate on.
2430+ *
2431+ * \return human readable string describing the last libiscsi error.
2432+ */
2433+PUBLIC const char *libiscsi_get_error_string(struct libiscsi_context *context);
2434+
2435+
2436+/************************** Utility functions *******************************/
2437+
2438+/** \brief libiscsi network config struct
2439+ *
2440+ * libiscsi network config struct.
2441+ */
2442+struct libiscsi_network_config {
2443+ int dhcp /** Using DHCP? (boolean). */;
2444+ char iface_name[LIBISCSI_VALUE_MAXLEN] /** Interface name. */;
2445+ char mac_address[LIBISCSI_VALUE_MAXLEN] /** MAC address. */;
2446+ char ip_address[LIBISCSI_VALUE_MAXLEN] /** IP address. */;
2447+ char netmask[LIBISCSI_VALUE_MAXLEN] /** Netmask. */;
2448+ char gateway[LIBISCSI_VALUE_MAXLEN] /** IP of Default gateway. */;
2449+ char primary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Primary DNS. */;
2450+ char secondary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Secondary DNS. */;
2451+};
2452+
2453+/** \brief Get network configuration information from iscsi firmware
2454+ *
2455+ * Function can be called to get the network configuration information
2456+ * (like dhcp, ip, netmask, default gateway, etc.) from the firmware of a
2457+ * network adapter with iscsi boot firmware.
2458+ *
2459+ * Note that not all fields of the returned struct are necessarilly filled,
2460+ * unset fields contain a 0 length string.
2461+ *
2462+ * \param config pointer to a libiscsi_network_config struct to fill.
2463+ *
2464+ * \return 0 on success, ENODEV when no iscsi firmware was found.
2465+ */
2466+PUBLIC int libiscsi_get_firmware_network_config(
2467+ struct libiscsi_network_config *config);
2468+
2469+/** \brief Get the initiator name (iqn) from the iscsi firmware
2470+ *
2471+ * Get the initiator name (iqn) from the iscsi firmware.
2472+ *
2473+ * \param initiatorname The initiator name is stored here, this buffer must be
2474+ * atleast LIBISCSI_VALUE_MAXLEN bytes large.
2475+ * \return 0 on success, ENODEV when no iscsi firmware was found.
2476+ */
2477+PUBLIC int libiscsi_get_firmware_initiator_name(char *initiatorname);
2478+
2479+#undef PUBLIC
2480+
2481+#ifdef __cplusplus
2482+}
2483+#endif /* __cplusplus */
2484+
2485+#endif
2486diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c
2487new file mode 100644
2488index 0000000..454a26a
2489--- /dev/null
2490+++ b/libiscsi/pylibiscsi.c
2491@@ -0,0 +1,624 @@
2492+/*
2493+ * iSCSI Administration library
2494+ *
2495+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
2496+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
2497+ * maintained by open-iscsi@googlegroups.com
2498+ *
2499+ * This program is free software; you can redistribute it and/or modify
2500+ * it under the terms of the GNU General Public License as published
2501+ * by the Free Software Foundation; either version 2 of the License, or
2502+ * (at your option) any later version.
2503+ *
2504+ * This program is distributed in the hope that it will be useful, but
2505+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2506+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2507+ * General Public License for more details.
2508+ *
2509+ * See the file COPYING included with this distribution for more details.
2510+ */
2511+
2512+#include <Python.h>
2513+#include "libiscsi.h"
2514+
2515+static struct libiscsi_context *context = NULL;
2516+
2517+/****************************** helpers ***********************************/
2518+static int check_string(const char *string)
2519+{
2520+ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) {
2521+ PyErr_SetString(PyExc_ValueError, "string too long");
2522+ return -1;
2523+ }
2524+ return 0;
2525+}
2526+
2527+/********************** PyIscsiChapAuthInfo ***************************/
2528+
2529+typedef struct {
2530+ PyObject_HEAD
2531+
2532+ struct libiscsi_auth_info info;
2533+} PyIscsiChapAuthInfo;
2534+
2535+static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args,
2536+ PyObject *kwds)
2537+{
2538+ int i;
2539+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
2540+ char *kwlist[] = {"username", "password", "reverse_username",
2541+ "reverse_password", NULL};
2542+ const char *string[4] = { NULL, NULL, NULL, NULL };
2543+
2544+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
2545+ "zz|zz:chapAuthInfo.__init__",
2546+ kwlist, &string[0], &string[1],
2547+ &string[2], &string[3]))
2548+ return -1;
2549+
2550+ for (i = 0; i < 4; i++)
2551+ if (string[i] && check_string(string[i]))
2552+ return -1;
2553+
2554+ memset (&chap->info, 0, sizeof(chap->info));
2555+ chap->info.method = libiscsi_auth_chap;
2556+ if (string[0])
2557+ strcpy(chap->info.chap.username, string[0]);
2558+ if (string[1])
2559+ strcpy(chap->info.chap.password, string[1]);
2560+ if (string[2])
2561+ strcpy(chap->info.chap.reverse_username, string[2]);
2562+ if (string[3])
2563+ strcpy(chap->info.chap.reverse_password, string[3]);
2564+
2565+ if (libiscsi_verify_auth_info(context, &chap->info)) {
2566+ PyErr_SetString(PyExc_ValueError,
2567+ libiscsi_get_error_string(context));
2568+ return -1;
2569+ }
2570+ return 0;
2571+}
2572+
2573+static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data)
2574+{
2575+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
2576+ const char *attr = (const char *)data;
2577+
2578+ if (!strcmp(attr, "username")) {
2579+ return PyString_FromString(chap->info.chap.username);
2580+ } else if (!strcmp(attr, "password")) {
2581+ return PyString_FromString(chap->info.chap.password);
2582+ } else if (!strcmp(attr, "reverse_username")) {
2583+ return PyString_FromString(chap->info.chap.reverse_username);
2584+ } else if (!strcmp(attr, "reverse_password")) {
2585+ return PyString_FromString(chap->info.chap.reverse_password);
2586+ }
2587+ return NULL;
2588+}
2589+
2590+static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data)
2591+{
2592+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
2593+ const char *attr = (const char *)data;
2594+ const char *str;
2595+
2596+ if (!PyArg_Parse(value, "s", &str) || check_string(str))
2597+ return -1;
2598+
2599+ if (!strcmp(attr, "username")) {
2600+ strcpy(chap->info.chap.username, str);
2601+ } else if (!strcmp(attr, "password")) {
2602+ strcpy(chap->info.chap.password, str);
2603+ } else if (!strcmp(attr, "reverse_username")) {
2604+ strcpy(chap->info.chap.reverse_username, str);
2605+ } else if (!strcmp(attr, "reverse_password")) {
2606+ strcpy(chap->info.chap.reverse_password, str);
2607+ }
2608+
2609+ return 0;
2610+}
2611+
2612+static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self,
2613+ PyIscsiChapAuthInfo *other)
2614+{
2615+ int r;
2616+
2617+ r = strcmp(self->info.chap.username, other->info.chap.username);
2618+ if (r)
2619+ return r;
2620+
2621+ r = strcmp(self->info.chap.password, other->info.chap.password);
2622+ if (r)
2623+ return r;
2624+
2625+ r = strcmp(self->info.chap.reverse_username,
2626+ other->info.chap.reverse_username);
2627+ if (r)
2628+ return r;
2629+
2630+ r = strcmp(self->info.chap.reverse_password,
2631+ other->info.chap.reverse_password);
2632+ return r;
2633+}
2634+
2635+static PyObject *PyIscsiChapAuthInfo_str(PyObject *self)
2636+{
2637+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self;
2638+ char s[1024], reverse[512] = "";
2639+
2640+ if (chap->info.chap.reverse_username[0])
2641+ snprintf(reverse, sizeof(reverse), ", %s:%s",
2642+ chap->info.chap.reverse_username,
2643+ chap->info.chap.reverse_password);
2644+
2645+ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username,
2646+ chap->info.chap.password, reverse);
2647+
2648+ return PyString_FromString(s);
2649+}
2650+
2651+static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = {
2652+ {"username", (getter)PyIscsiChapAuthInfo_get,
2653+ (setter)PyIscsiChapAuthInfo_set,
2654+ "username", "username"},
2655+ {"password", (getter)PyIscsiChapAuthInfo_get,
2656+ (setter)PyIscsiChapAuthInfo_set,
2657+ "password", "password"},
2658+ {"reverse_username", (getter)PyIscsiChapAuthInfo_get,
2659+ (setter)PyIscsiChapAuthInfo_set,
2660+ "reverse_username", "reverse_username"},
2661+ {"reverse_password", (getter)PyIscsiChapAuthInfo_get,
2662+ (setter)PyIscsiChapAuthInfo_set,
2663+ "reverse_password", "reverse_password"},
2664+ {NULL}
2665+};
2666+
2667+PyTypeObject PyIscsiChapAuthInfo_Type = {
2668+ PyObject_HEAD_INIT(NULL)
2669+ .tp_name = "libiscsi.chapAuthInfo",
2670+ .tp_basicsize = sizeof (PyIscsiChapAuthInfo),
2671+ .tp_getset = PyIscsiChapAuthInfo_getseters,
2672+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
2673+ Py_TPFLAGS_BASETYPE,
2674+ .tp_compare = (cmpfunc)PyIscsiChapAuthInfo_compare,
2675+ .tp_init = PyIscsiChapAuthInfo_init,
2676+ .tp_str = PyIscsiChapAuthInfo_str,
2677+ .tp_new = PyType_GenericNew,
2678+ .tp_doc = "iscsi chap authentication information.",
2679+};
2680+
2681+/***************************** PyIscsiNode ********************************/
2682+
2683+typedef struct {
2684+ PyObject_HEAD
2685+
2686+ struct libiscsi_node node;
2687+} PyIscsiNode;
2688+
2689+static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds)
2690+{
2691+ PyIscsiNode *node = (PyIscsiNode *)self;
2692+ char *kwlist[] = {"name", "tpgt", "address", "port", NULL};
2693+ const char *name = NULL, *address = NULL;
2694+ int tpgt = -1, port = 3260;
2695+
2696+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isi:node.__init__",
2697+ kwlist, &name, &tpgt, &address, &port))
2698+ return -1;
2699+ if (address == NULL) {
2700+ PyErr_SetString(PyExc_ValueError, "address not set");
2701+ return -1;
2702+ }
2703+ if (check_string(name) || check_string(address))
2704+ return -1;
2705+
2706+ strcpy(node->node.name, name);
2707+ node->node.tpgt = tpgt;
2708+ strcpy(node->node.address, address);
2709+ node->node.port = port;
2710+
2711+ return 0;
2712+}
2713+
2714+static PyObject *PyIscsiNode_get(PyObject *self, void *data)
2715+{
2716+ PyIscsiNode *node = (PyIscsiNode *)self;
2717+ const char *attr = (const char *)data;
2718+
2719+ if (!strcmp(attr, "name")) {
2720+ return PyString_FromString(node->node.name);
2721+ } else if (!strcmp(attr, "tpgt")) {
2722+ return PyInt_FromLong(node->node.tpgt);
2723+ } else if (!strcmp(attr, "address")) {
2724+ return PyString_FromString(node->node.address);
2725+ } else if (!strcmp(attr, "port")) {
2726+ return PyInt_FromLong(node->node.port);
2727+ }
2728+ return NULL;
2729+}
2730+
2731+static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data)
2732+{
2733+ PyIscsiNode *node = (PyIscsiNode *)self;
2734+ const char *attr = (const char *)data;
2735+ const char *str;
2736+ int i;
2737+
2738+ if (!strcmp(attr, "name")) {
2739+ if (!PyArg_Parse(value, "s", &str) || check_string(str))
2740+ return -1;
2741+ strcpy(node->node.name, str);
2742+ } else if (!strcmp(attr, "tpgt")) {
2743+ if (!PyArg_Parse(value, "i", &i))
2744+ return -1;
2745+ node->node.tpgt = i;
2746+ } else if (!strcmp(attr, "address")) {
2747+ if (!PyArg_Parse(value, "s", &str) || check_string(str))
2748+ return -1;
2749+ strcpy(node->node.address, str);
2750+ } else if (!strcmp(attr, "port")) {
2751+ if (!PyArg_Parse(value, "i", &i))
2752+ return -1;
2753+ node->node.port = i;
2754+ }
2755+
2756+ return 0;
2757+}
2758+
2759+static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other)
2760+{
2761+ int res;
2762+
2763+ res = strcmp(self->node.name, other->node.name);
2764+ if (res)
2765+ return res;
2766+
2767+ if (self->node.tpgt < other->node.tpgt)
2768+ return -1;
2769+ if (self->node.tpgt > other->node.tpgt)
2770+ return -1;
2771+
2772+ res = strcmp(self->node.address, other->node.address);
2773+ if (res)
2774+ return res;
2775+
2776+ if (self->node.port < other->node.port)
2777+ return -1;
2778+ if (self->node.port > other->node.port)
2779+ return -1;
2780+
2781+ return 0;
2782+}
2783+
2784+static PyObject *PyIscsiNode_str(PyObject *self)
2785+{
2786+ PyIscsiNode *node = (PyIscsiNode *)self;
2787+ char s[1024], tpgt[16] = "";
2788+
2789+ if (node->node.tpgt != -1)
2790+ sprintf(tpgt, ",%d", node->node.tpgt);
2791+
2792+ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address,
2793+ node->node.port, tpgt, node->node.name);
2794+
2795+ return PyString_FromString(s);
2796+}
2797+
2798+static PyObject *PyIscsiNode_login(PyObject *self)
2799+{
2800+ PyIscsiNode *node = (PyIscsiNode *)self;
2801+
2802+ if (libiscsi_node_login(context, &node->node)) {
2803+ PyErr_SetString(PyExc_IOError,
2804+ libiscsi_get_error_string(context));
2805+ return NULL;
2806+ }
2807+ Py_RETURN_NONE;
2808+}
2809+
2810+static PyObject *PyIscsiNode_logout(PyObject *self)
2811+{
2812+ PyIscsiNode *node = (PyIscsiNode *)self;
2813+
2814+ if (libiscsi_node_logout(context, &node->node)) {
2815+ PyErr_SetString(PyExc_IOError,
2816+ libiscsi_get_error_string(context));
2817+ return NULL;
2818+ }
2819+ Py_RETURN_NONE;
2820+}
2821+
2822+static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args,
2823+ PyObject *kwds)
2824+{
2825+ char *kwlist[] = {"authinfo", NULL};
2826+ PyIscsiNode *node = (PyIscsiNode *)self;
2827+ PyObject *arg;
2828+ const struct libiscsi_auth_info *authinfo = NULL;
2829+
2830+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg))
2831+ return NULL;
2832+
2833+ if (arg == Py_None) {
2834+ authinfo = NULL;
2835+ } else if (PyObject_IsInstance(arg, (PyObject *)
2836+ &PyIscsiChapAuthInfo_Type)) {
2837+ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg;
2838+ authinfo = &pyauthinfo->info;
2839+ } else {
2840+ PyErr_SetString(PyExc_ValueError, "invalid authinfo type");
2841+ return NULL;
2842+ }
2843+
2844+ if (libiscsi_node_set_auth(context, &node->node, authinfo)) {
2845+ PyErr_SetString(PyExc_IOError,
2846+ libiscsi_get_error_string(context));
2847+ return NULL;
2848+ }
2849+ Py_RETURN_NONE;
2850+}
2851+
2852+static PyObject *PyIscsiNode_getAuth(PyObject *self)
2853+{
2854+ PyIscsiNode *node = (PyIscsiNode *)self;
2855+ PyIscsiChapAuthInfo *pyauthinfo;
2856+ struct libiscsi_auth_info authinfo;
2857+
2858+ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) {
2859+ PyErr_SetString(PyExc_IOError,
2860+ libiscsi_get_error_string(context));
2861+ return NULL;
2862+ }
2863+
2864+ switch (authinfo.method) {
2865+ case libiscsi_auth_chap:
2866+ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo,
2867+ &PyIscsiChapAuthInfo_Type);
2868+ if (!pyauthinfo)
2869+ return NULL;
2870+
2871+ pyauthinfo->info = authinfo;
2872+
2873+ return (PyObject *)pyauthinfo;
2874+
2875+ case libiscsi_auth_none:
2876+ default:
2877+ Py_RETURN_NONE;
2878+ }
2879+}
2880+
2881+static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args,
2882+ PyObject *kwds)
2883+{
2884+ char *kwlist[] = {"parameter", "value", NULL};
2885+ PyIscsiNode *node = (PyIscsiNode *)self;
2886+ const char *parameter, *value;
2887+
2888+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist,
2889+ &parameter, &value))
2890+ return NULL;
2891+ if (check_string(parameter) || check_string(value))
2892+ return NULL;
2893+
2894+ if (libiscsi_node_set_parameter(context, &node->node, parameter,
2895+ value)) {
2896+ PyErr_SetString(PyExc_IOError,
2897+ libiscsi_get_error_string(context));
2898+ return NULL;
2899+ }
2900+ Py_RETURN_NONE;
2901+}
2902+
2903+static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args,
2904+ PyObject *kwds)
2905+{
2906+ char *kwlist[] = {"parameter", NULL};
2907+ PyIscsiNode *node = (PyIscsiNode *)self;
2908+ const char *parameter;
2909+ char value[LIBISCSI_VALUE_MAXLEN];
2910+
2911+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &parameter))
2912+ return NULL;
2913+ if (check_string(parameter))
2914+ return NULL;
2915+
2916+ if (libiscsi_node_get_parameter(context, &node->node, parameter,
2917+ value)) {
2918+ PyErr_SetString(PyExc_IOError,
2919+ libiscsi_get_error_string(context));
2920+ return NULL;
2921+ }
2922+ return Py_BuildValue("s", value);
2923+}
2924+
2925+static struct PyGetSetDef PyIscsiNode_getseters[] = {
2926+ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
2927+ "name", "name"},
2928+ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
2929+ "tpgt", "tpgt"},
2930+ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
2931+ "address", "address"},
2932+ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set,
2933+ "port", "port"},
2934+ {NULL}
2935+};
2936+
2937+static struct PyMethodDef PyIscsiNode_methods[] = {
2938+ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS,
2939+ "Log in to the node"},
2940+ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS,
2941+ "Log out of the node"},
2942+ {"setAuth", (PyCFunction) PyIscsiNode_setAuth,
2943+ METH_VARARGS|METH_KEYWORDS,
2944+ "Set authentication information"},
2945+ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS,
2946+ "Get authentication information"},
2947+ {"setParameter", (PyCFunction) PyIscsiNode_setParameter,
2948+ METH_VARARGS|METH_KEYWORDS,
2949+ "Set an iscsi node parameter"},
2950+ {"getParameter", (PyCFunction) PyIscsiNode_getParameter,
2951+ METH_VARARGS|METH_KEYWORDS,
2952+ "Get an iscsi node parameter"},
2953+ {NULL}
2954+};
2955+
2956+PyTypeObject PyIscsiNode_Type = {
2957+ PyObject_HEAD_INIT(NULL)
2958+ .tp_name = "libiscsi.node",
2959+ .tp_basicsize = sizeof (PyIscsiNode),
2960+ .tp_getset = PyIscsiNode_getseters,
2961+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
2962+ Py_TPFLAGS_BASETYPE,
2963+ .tp_methods = PyIscsiNode_methods,
2964+ .tp_compare = (cmpfunc)PyIscsiNode_compare,
2965+ .tp_init = PyIscsiNode_init,
2966+ .tp_str = PyIscsiNode_str,
2967+ .tp_new = PyType_GenericNew,
2968+ .tp_doc = "The iscsi node contains iscsi node information.",
2969+};
2970+
2971+/***************************************************************************/
2972+
2973+static PyObject *pylibiscsi_discover_sendtargets(PyObject *self,
2974+ PyObject *args, PyObject *kwds)
2975+{
2976+ char *kwlist[] = {"address", "port", "authinfo", NULL};
2977+ const char *address = NULL;
2978+ int i, nr_found, port = 3260;
2979+ PyObject *authinfo_arg = NULL;
2980+ const struct libiscsi_auth_info *authinfo = NULL;
2981+ struct libiscsi_node *found_nodes;
2982+ PyObject* found_node_list;
2983+
2984+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO",
2985+ kwlist, &address, &port,
2986+ &authinfo_arg))
2987+ return NULL;
2988+
2989+ if (authinfo_arg) {
2990+ if (PyObject_IsInstance(authinfo_arg, (PyObject *)
2991+ &PyIscsiChapAuthInfo_Type)) {
2992+ PyIscsiChapAuthInfo *pyauthinfo =
2993+ (PyIscsiChapAuthInfo *)authinfo_arg;
2994+ authinfo = &pyauthinfo->info;
2995+ } else if (authinfo_arg != Py_None) {
2996+ PyErr_SetString(PyExc_ValueError,
2997+ "invalid authinfo type");
2998+ return NULL;
2999+ }
3000+ }
3001+
3002+ if (libiscsi_discover_sendtargets(context, address, port, authinfo,
3003+ &nr_found, &found_nodes)) {
3004+ PyErr_SetString(PyExc_IOError,
3005+ libiscsi_get_error_string(context));
3006+ return NULL;
3007+ }
3008+
3009+ if (nr_found == 0)
3010+ Py_RETURN_NONE;
3011+
3012+ found_node_list = PyList_New(nr_found);
3013+ if (!found_node_list)
3014+ return NULL;
3015+
3016+ for(i = 0; i < nr_found; i++) {
3017+ PyIscsiNode *pynode;
3018+
3019+ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type);
3020+ if (!pynode) {
3021+ /* This will deref already added nodes for us */
3022+ Py_DECREF(found_node_list);
3023+ return NULL;
3024+ }
3025+ pynode->node = found_nodes[i];
3026+ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode);
3027+ }
3028+
3029+ return found_node_list;
3030+}
3031+
3032+static PyObject *pylibiscsi_discover_firmware(PyObject *self)
3033+{
3034+ int i, nr_found;
3035+ struct libiscsi_node *found_nodes;
3036+ PyObject* found_node_list;
3037+
3038+ if (libiscsi_discover_firmware(context, &nr_found, &found_nodes)) {
3039+ PyErr_SetString(PyExc_IOError,
3040+ libiscsi_get_error_string(context));
3041+ return NULL;
3042+ }
3043+
3044+ if (nr_found == 0)
3045+ Py_RETURN_NONE;
3046+
3047+ found_node_list = PyList_New(nr_found);
3048+ if (!found_node_list)
3049+ return NULL;
3050+
3051+ for(i = 0; i < nr_found; i++) {
3052+ PyIscsiNode *pynode;
3053+
3054+ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type);
3055+ if (!pynode) {
3056+ /* This will deref already added nodes for us */
3057+ Py_DECREF(found_node_list);
3058+ return NULL;
3059+ }
3060+ pynode->node = found_nodes[i];
3061+ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode);
3062+ }
3063+
3064+ return found_node_list;
3065+}
3066+
3067+static PyObject *pylibiscsi_get_firmware_initiator_name(PyObject *self)
3068+{
3069+ char initiatorname[LIBISCSI_VALUE_MAXLEN];
3070+
3071+ if (libiscsi_get_firmware_initiator_name(initiatorname)) {
3072+ PyErr_SetString(PyExc_IOError,
3073+ libiscsi_get_error_string(context));
3074+ return NULL;
3075+ }
3076+
3077+ return PyString_FromString(initiatorname);
3078+}
3079+
3080+static PyMethodDef pylibiscsi_functions[] = {
3081+ { "discover_sendtargets",
3082+ (PyCFunction)pylibiscsi_discover_sendtargets,
3083+ METH_VARARGS|METH_KEYWORDS,
3084+ "Do sendtargets discovery and return a list of found nodes)"},
3085+ { "discover_firmware",
3086+ (PyCFunction)pylibiscsi_discover_firmware, METH_NOARGS,
3087+ "Do firmware discovery and return a list of found nodes)"},
3088+ { "get_firmware_initiator_name",
3089+ (PyCFunction)pylibiscsi_get_firmware_initiator_name,
3090+ METH_NOARGS,
3091+ "Get initator name (iqn) from firmware"},
3092+ {NULL, NULL}
3093+};
3094+
3095+PyMODINIT_FUNC initlibiscsi(void)
3096+{
3097+ PyObject *m;
3098+
3099+ if (!context) /* We may be called more then once */
3100+ context = libiscsi_init();
3101+ if (!context)
3102+ return;
3103+
3104+ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0)
3105+ return;
3106+
3107+ if (PyType_Ready(&PyIscsiNode_Type) < 0)
3108+ return;
3109+
3110+ m = Py_InitModule("libiscsi", pylibiscsi_functions);
3111+ Py_INCREF(&PyIscsiChapAuthInfo_Type);
3112+ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type);
3113+ Py_INCREF(&PyIscsiNode_Type);
3114+ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type);
3115+}
3116diff --git a/libiscsi/setup.py b/libiscsi/setup.py
3117new file mode 100644
3118index 0000000..bb4329b
3119--- /dev/null
3120+++ b/libiscsi/setup.py
3121@@ -0,0 +1,9 @@
3122+from distutils.core import setup, Extension
3123+
3124+module1 = Extension('libiscsimodule',
3125+ sources = ['pylibiscsi.c'],
3126+ libraries = ['iscsi'],
3127+ library_dirs = ['.'])
3128+
3129+setup (name = 'PyIscsi',version = '1.0',
3130+ description = 'libiscsi python bindings', ext_modules = [module1])
3131diff --git a/libiscsi/tests/test_discovery_firmware.c b/libiscsi/tests/test_discovery_firmware.c
3132new file mode 100644
3133index 0000000..76e852a
3134--- /dev/null
3135+++ b/libiscsi/tests/test_discovery_firmware.c
3136@@ -0,0 +1,53 @@
3137+/*
3138+ * iSCSI Administration library
3139+ *
3140+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3141+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3142+ * maintained by open-iscsi@googlegroups.com
3143+ *
3144+ * This program is free software; you can redistribute it and/or modify
3145+ * it under the terms of the GNU General Public License as published
3146+ * by the Free Software Foundation; either version 2 of the License, or
3147+ * (at your option) any later version.
3148+ *
3149+ * This program is distributed in the hope that it will be useful, but
3150+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3151+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3152+ * General Public License for more details.
3153+ *
3154+ * See the file COPYING included with this distribution for more details.
3155+ */
3156+
3157+#include <stdio.h>
3158+#include <stdlib.h>
3159+#include <string.h>
3160+#include "libiscsi.h"
3161+
3162+int main(void)
3163+{
3164+ struct libiscsi_node *found_nodes;
3165+ struct libiscsi_context *context;
3166+ int i, found, rc = 0;
3167+
3168+ context = libiscsi_init();
3169+ if (!context) {
3170+ fprintf(stderr, "Error initializing libiscsi\n");
3171+ return 1;
3172+ }
3173+
3174+ rc = libiscsi_discover_firmware(context, &found, &found_nodes);
3175+ if (rc)
3176+ fprintf(stderr, "Error discovering: %s\n",
3177+ libiscsi_get_error_string(context));
3178+
3179+ for (i = 0; i < found; i++) {
3180+ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n",
3181+ found_nodes[i].name, found_nodes[i].tpgt,
3182+ found_nodes[i].address, found_nodes[i].port);
3183+ }
3184+
3185+ libiscsi_cleanup(context);
3186+ free (found_nodes);
3187+
3188+ return rc;
3189+}
3190diff --git a/libiscsi/tests/test_discovery_sendtargets.c b/libiscsi/tests/test_discovery_sendtargets.c
3191new file mode 100644
3192index 0000000..1a3c12e
3193--- /dev/null
3194+++ b/libiscsi/tests/test_discovery_sendtargets.c
3195@@ -0,0 +1,60 @@
3196+/*
3197+ * iSCSI Administration library
3198+ *
3199+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3200+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3201+ * maintained by open-iscsi@googlegroups.com
3202+ *
3203+ * This program is free software; you can redistribute it and/or modify
3204+ * it under the terms of the GNU General Public License as published
3205+ * by the Free Software Foundation; either version 2 of the License, or
3206+ * (at your option) any later version.
3207+ *
3208+ * This program is distributed in the hope that it will be useful, but
3209+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3210+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3211+ * General Public License for more details.
3212+ *
3213+ * See the file COPYING included with this distribution for more details.
3214+ */
3215+
3216+#include <stdio.h>
3217+#include <stdlib.h>
3218+#include <string.h>
3219+#include "libiscsi.h"
3220+
3221+int main(void)
3222+{
3223+ struct libiscsi_node *found_nodes;
3224+ struct libiscsi_context *context;
3225+ struct libiscsi_auth_info auth_info;
3226+ int i, found, rc = 0;
3227+
3228+ context = libiscsi_init();
3229+ if (!context) {
3230+ fprintf(stderr, "Error initializing libiscsi\n");
3231+ return 1;
3232+ }
3233+
3234+ memset(&auth_info, 0, sizeof(auth_info));
3235+ auth_info.method = libiscsi_auth_chap;
3236+ strcpy(auth_info.chap.username, "joe");
3237+ strcpy(auth_info.chap.password, "secret");
3238+
3239+ rc = libiscsi_discover_sendtargets(context, "127.0.0.1", 3260,
3240+ &auth_info, &found, &found_nodes);
3241+ if (rc)
3242+ fprintf(stderr, "Error discovering: %s\n",
3243+ libiscsi_get_error_string(context));
3244+
3245+ for (i = 0; i < found; i++) {
3246+ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n",
3247+ found_nodes[i].name, found_nodes[i].tpgt,
3248+ found_nodes[i].address, found_nodes[i].port);
3249+ }
3250+
3251+ libiscsi_cleanup(context);
3252+ free (found_nodes);
3253+
3254+ return rc;
3255+}
3256diff --git a/libiscsi/tests/test_get_auth.c b/libiscsi/tests/test_get_auth.c
3257new file mode 100644
3258index 0000000..5e234da
3259--- /dev/null
3260+++ b/libiscsi/tests/test_get_auth.c
3261@@ -0,0 +1,70 @@
3262+/*
3263+ * iSCSI Administration library
3264+ *
3265+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3266+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3267+ * maintained by open-iscsi@googlegroups.com
3268+ *
3269+ * This program is free software; you can redistribute it and/or modify
3270+ * it under the terms of the GNU General Public License as published
3271+ * by the Free Software Foundation; either version 2 of the License, or
3272+ * (at your option) any later version.
3273+ *
3274+ * This program is distributed in the hope that it will be useful, but
3275+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3276+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3277+ * General Public License for more details.
3278+ *
3279+ * See the file COPYING included with this distribution for more details.
3280+ */
3281+
3282+#include <stdio.h>
3283+#include <stdlib.h>
3284+#include <string.h>
3285+#include "libiscsi.h"
3286+
3287+int main(void)
3288+{
3289+ struct libiscsi_node node;
3290+ struct libiscsi_context *context;
3291+ struct libiscsi_auth_info auth_info;
3292+ int rc = 0;
3293+
3294+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s",
3295+ "iqn.2009-01.com.example:testdisk");
3296+ node.tpgt = 1;
3297+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1");
3298+ node.port = 3260;
3299+
3300+ context = libiscsi_init();
3301+ if (!context) {
3302+ fprintf(stderr, "Error initializing libiscsi\n");
3303+ return 1;
3304+ }
3305+
3306+ rc = libiscsi_node_get_auth(context, &node, &auth_info);
3307+ if (rc) {
3308+ fprintf(stderr, "Error setting authinfo: %s\n",
3309+ libiscsi_get_error_string(context));
3310+ goto leave;
3311+ }
3312+
3313+ switch (auth_info.method) {
3314+ case libiscsi_auth_none:
3315+ printf("Method: \"None\"\n");
3316+ break;
3317+ case libiscsi_auth_chap:
3318+ printf("Method: \"CHAP\"\n");
3319+ printf("User: \"%s\"\n", auth_info.chap.username);
3320+ printf("Pass: \"%s\"\n", auth_info.chap.password);
3321+ printf("RevUser: \"%s\"\n",
3322+ auth_info.chap.reverse_username);
3323+ printf("RevPass: \"%s\"\n",
3324+ auth_info.chap.reverse_password);
3325+ break;
3326+ }
3327+leave:
3328+ libiscsi_cleanup(context);
3329+
3330+ return rc;
3331+}
3332diff --git a/libiscsi/tests/test_get_initiator_name.c b/libiscsi/tests/test_get_initiator_name.c
3333new file mode 100644
3334index 0000000..997c053
3335--- /dev/null
3336+++ b/libiscsi/tests/test_get_initiator_name.c
3337@@ -0,0 +1,38 @@
3338+/*
3339+ * iSCSI Administration library
3340+ *
3341+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3342+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3343+ * maintained by open-iscsi@googlegroups.com
3344+ *
3345+ * This program is free software; you can redistribute it and/or modify
3346+ * it under the terms of the GNU General Public License as published
3347+ * by the Free Software Foundation; either version 2 of the License, or
3348+ * (at your option) any later version.
3349+ *
3350+ * This program is distributed in the hope that it will be useful, but
3351+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3352+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3353+ * General Public License for more details.
3354+ *
3355+ * See the file COPYING included with this distribution for more details.
3356+ */
3357+
3358+#include <stdio.h>
3359+#include <stdlib.h>
3360+#include <string.h>
3361+#include "libiscsi.h"
3362+
3363+int main(void)
3364+{
3365+ char initiatorname[LIBISCSI_VALUE_MAXLEN];
3366+
3367+ if (libiscsi_get_firmware_initiator_name(initiatorname)) {
3368+ fprintf(stderr, "No iscsi boot firmware found\n");
3369+ return 1;
3370+ }
3371+
3372+ printf("iqn:\t%s\n", initiatorname);
3373+
3374+ return 0;
3375+}
3376diff --git a/libiscsi/tests/test_get_network_config.c b/libiscsi/tests/test_get_network_config.c
3377new file mode 100644
3378index 0000000..2dedd61
3379--- /dev/null
3380+++ b/libiscsi/tests/test_get_network_config.c
3381@@ -0,0 +1,45 @@
3382+/*
3383+ * iSCSI Administration library
3384+ *
3385+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3386+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3387+ * maintained by open-iscsi@googlegroups.com
3388+ *
3389+ * This program is free software; you can redistribute it and/or modify
3390+ * it under the terms of the GNU General Public License as published
3391+ * by the Free Software Foundation; either version 2 of the License, or
3392+ * (at your option) any later version.
3393+ *
3394+ * This program is distributed in the hope that it will be useful, but
3395+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3396+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3397+ * General Public License for more details.
3398+ *
3399+ * See the file COPYING included with this distribution for more details.
3400+ */
3401+
3402+#include <stdio.h>
3403+#include <stdlib.h>
3404+#include <string.h>
3405+#include "libiscsi.h"
3406+
3407+int main(void)
3408+{
3409+ struct libiscsi_network_config config;
3410+
3411+ if (libiscsi_get_firmware_network_config(&config)) {
3412+ fprintf(stderr, "No iscsi boot firmware found\n");
3413+ return 1;
3414+ }
3415+
3416+ printf("dhcp:\t%d\n", config.dhcp);
3417+ printf("iface:\t%s\n", config.iface_name);
3418+ printf("mac:\t%s\n", config.mac_address);
3419+ printf("ipaddr:\t%s\n", config.ip_address);
3420+ printf("mask:\t%s\n", config.netmask);
3421+ printf("gate:\t%s\n", config.gateway);
3422+ printf("dns1:\t%s\n", config.primary_dns);
3423+ printf("dns2:\t%s\n", config.secondary_dns);
3424+
3425+ return 0;
3426+}
3427diff --git a/libiscsi/tests/test_login.c b/libiscsi/tests/test_login.c
3428new file mode 100644
3429index 0000000..3eb70d6
3430--- /dev/null
3431+++ b/libiscsi/tests/test_login.c
3432@@ -0,0 +1,52 @@
3433+/*
3434+ * iSCSI Administration library
3435+ *
3436+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3437+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3438+ * maintained by open-iscsi@googlegroups.com
3439+ *
3440+ * This program is free software; you can redistribute it and/or modify
3441+ * it under the terms of the GNU General Public License as published
3442+ * by the Free Software Foundation; either version 2 of the License, or
3443+ * (at your option) any later version.
3444+ *
3445+ * This program is distributed in the hope that it will be useful, but
3446+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3447+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3448+ * General Public License for more details.
3449+ *
3450+ * See the file COPYING included with this distribution for more details.
3451+ */
3452+
3453+#include <stdio.h>
3454+#include <stdlib.h>
3455+#include <string.h>
3456+#include "libiscsi.h"
3457+
3458+int main(void)
3459+{
3460+ struct libiscsi_node node;
3461+ struct libiscsi_context *context;
3462+ int rc = 0;
3463+
3464+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s",
3465+ "iqn.2009-01.com.example:testdisk");
3466+ node.tpgt = 1;
3467+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1");
3468+ node.port = 3260;
3469+
3470+ context = libiscsi_init();
3471+ if (!context) {
3472+ fprintf(stderr, "Error initializing libiscsi\n");
3473+ return 1;
3474+ }
3475+
3476+ rc = libiscsi_node_login(context, &node);
3477+ if (rc)
3478+ fprintf(stderr, "Error logging in: %s\n",
3479+ libiscsi_get_error_string(context));
3480+
3481+ libiscsi_cleanup(context);
3482+
3483+ return rc;
3484+}
3485diff --git a/libiscsi/tests/test_logout.c b/libiscsi/tests/test_logout.c
3486new file mode 100644
3487index 0000000..b734dca
3488--- /dev/null
3489+++ b/libiscsi/tests/test_logout.c
3490@@ -0,0 +1,51 @@
3491+/*
3492+ * iSCSI Administration library
3493+ *
3494+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3495+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3496+ * maintained by open-iscsi@googlegroups.com
3497+ *
3498+ * This program is free software; you can redistribute it and/or modify
3499+ * it under the terms of the GNU General Public License as published
3500+ * by the Free Software Foundation; either version 2 of the License, or
3501+ * (at your option) any later version.
3502+ *
3503+ * This program is distributed in the hope that it will be useful, but
3504+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3505+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3506+ * General Public License for more details.
3507+ *
3508+ * See the file COPYING included with this distribution for more details.
3509+ */
3510+
3511+#include <stdio.h>
3512+#include <stdlib.h>
3513+#include "libiscsi.h"
3514+
3515+int main(void)
3516+{
3517+ struct libiscsi_node node;
3518+ struct libiscsi_context *context;
3519+ int rc = 0;
3520+
3521+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s",
3522+ "iqn.2009-01.com.example:testdisk");
3523+ node.tpgt = 1;
3524+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1");
3525+ node.port = 3260;
3526+
3527+ context = libiscsi_init();
3528+ if (!context) {
3529+ fprintf(stderr, "Error initializing libiscsi\n");
3530+ return 1;
3531+ }
3532+
3533+ rc = libiscsi_node_logout(context, &node);
3534+ if (rc)
3535+ fprintf(stderr, "Error logging out: %s\n",
3536+ libiscsi_get_error_string(context));
3537+
3538+ libiscsi_cleanup(context);
3539+
3540+ return rc;
3541+}
3542diff --git a/libiscsi/tests/test_params.c b/libiscsi/tests/test_params.c
3543new file mode 100644
3544index 0000000..d3223be
3545--- /dev/null
3546+++ b/libiscsi/tests/test_params.c
3547@@ -0,0 +1,103 @@
3548+/*
3549+ * iSCSI Administration library
3550+ *
3551+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3552+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3553+ * maintained by open-iscsi@googlegroups.com
3554+ *
3555+ * This program is free software; you can redistribute it and/or modify
3556+ * it under the terms of the GNU General Public License as published
3557+ * by the Free Software Foundation; either version 2 of the License, or
3558+ * (at your option) any later version.
3559+ *
3560+ * This program is distributed in the hope that it will be useful, but
3561+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3562+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3563+ * General Public License for more details.
3564+ *
3565+ * See the file COPYING included with this distribution for more details.
3566+ */
3567+
3568+#include <stdio.h>
3569+#include <stdlib.h>
3570+#include <errno.h>
3571+#include <string.h>
3572+#include "libiscsi.h"
3573+
3574+int main(void)
3575+{
3576+ struct libiscsi_node node;
3577+ struct libiscsi_context *context;
3578+ char orig_value[LIBISCSI_VALUE_MAXLEN], value[LIBISCSI_VALUE_MAXLEN];
3579+ int rc = 0;
3580+
3581+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s",
3582+ "iqn.2009-01.com.example:testdisk");
3583+ node.tpgt = 1;
3584+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1");
3585+ node.port = 3260;
3586+
3587+ context = libiscsi_init();
3588+ if (!context) {
3589+ fprintf(stderr, "Error initializing libiscsi\n");
3590+ return 1;
3591+ }
3592+
3593+ rc = libiscsi_node_get_parameter(context, &node, "node.startup",
3594+ orig_value);
3595+ if (rc) {
3596+ fprintf(stderr, "Error getting original value: %s\n",
3597+ libiscsi_get_error_string(context));
3598+ goto leave;
3599+ }
3600+
3601+ rc = libiscsi_node_set_parameter(context, &node, "node.startup",
3602+ "automatic");
3603+ if (rc) {
3604+ fprintf(stderr, "Error setting node startup param: %s\n",
3605+ libiscsi_get_error_string(context));
3606+ goto leave;
3607+ }
3608+
3609+ rc = libiscsi_node_get_parameter(context, &node, "node.startup",
3610+ value);
3611+ if (rc) {
3612+ fprintf(stderr, "Error getting node startup param: %s\n",
3613+ libiscsi_get_error_string(context));
3614+ goto leave;
3615+ }
3616+
3617+ if (strcmp(value, "automatic")) {
3618+ fprintf(stderr, "Error set and get values do not match!\n");
3619+ rc = EIO;
3620+ goto leave;
3621+ }
3622+
3623+ rc = libiscsi_node_set_parameter(context, &node, "node.startup",
3624+ orig_value);
3625+ if (rc) {
3626+ fprintf(stderr, "Error setting original value: %s\n",
3627+ libiscsi_get_error_string(context));
3628+ goto leave;
3629+ }
3630+
3631+ rc = libiscsi_node_get_parameter(context, &node, "node.startup",
3632+ value);
3633+ if (rc) {
3634+ fprintf(stderr, "Error re-getting original value: %s\n",
3635+ libiscsi_get_error_string(context));
3636+ goto leave;
3637+ }
3638+
3639+ if (strcmp(value, orig_value)) {
3640+ fprintf(stderr,
3641+ "Error set and get original values do not match!\n");
3642+ rc = EIO;
3643+ goto leave;
3644+ }
3645+
3646+leave:
3647+ libiscsi_cleanup(context);
3648+
3649+ return rc;
3650+}
3651diff --git a/libiscsi/tests/test_set_auth.c b/libiscsi/tests/test_set_auth.c
3652new file mode 100644
3653index 0000000..a21f888
3654--- /dev/null
3655+++ b/libiscsi/tests/test_set_auth.c
3656@@ -0,0 +1,58 @@
3657+/*
3658+ * iSCSI Administration library
3659+ *
3660+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
3661+ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
3662+ * maintained by open-iscsi@googlegroups.com
3663+ *
3664+ * This program is free software; you can redistribute it and/or modify
3665+ * it under the terms of the GNU General Public License as published
3666+ * by the Free Software Foundation; either version 2 of the License, or
3667+ * (at your option) any later version.
3668+ *
3669+ * This program is distributed in the hope that it will be useful, but
3670+ * WITHOUT ANY WARRANTY; without even the implied warranty of
3671+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3672+ * General Public License for more details.
3673+ *
3674+ * See the file COPYING included with this distribution for more details.
3675+ */
3676+
3677+#include <stdio.h>
3678+#include <stdlib.h>
3679+#include <string.h>
3680+#include "libiscsi.h"
3681+
3682+int main(void)
3683+{
3684+ struct libiscsi_node node;
3685+ struct libiscsi_context *context;
3686+ struct libiscsi_auth_info auth_info;
3687+ int rc = 0;
3688+
3689+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s",
3690+ "iqn.2009-01.com.example:testdisk");
3691+ node.tpgt = 1;
3692+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1");
3693+ node.port = 3260;
3694+
3695+ memset(&auth_info, 0, sizeof(auth_info));
3696+ auth_info.method = libiscsi_auth_chap;
3697+ strcpy(auth_info.chap.username, "joe");
3698+ strcpy(auth_info.chap.password, "secret");
3699+
3700+ context = libiscsi_init();
3701+ if (!context) {
3702+ fprintf(stderr, "Error initializing libiscsi\n");
3703+ return 1;
3704+ }
3705+
3706+ rc = libiscsi_node_set_auth(context, &node, &auth_info);
3707+ if (rc)
3708+ fprintf(stderr, "Error setting authinfo: %s\n",
3709+ libiscsi_get_error_string(context));
3710+
3711+ libiscsi_cleanup(context);
3712+
3713+ return rc;
3714+}
3715diff --git a/usr/discovery.c b/usr/discovery.c
3716index 381f825..2233de7 100644
3717--- a/usr/discovery.c
3718+++ b/usr/discovery.c
3719@@ -36,6 +36,7 @@
3720 #include "types.h"
3721 #include "iscsi_proto.h"
3722 #include "initiator.h"
3723+#include "config.h"
3724 #include "log.h"
3725 #include "idbm.h"
3726 #include "iscsi_settings.h"
3727diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
3728index 74ef948..713914f 100644
3729--- a/usr/iscsi_ipc.h
3730+++ b/usr/iscsi_ipc.h
3731@@ -111,4 +111,6 @@ struct iscsi_ipc {
3732 int (*recv_pdu_end) (struct iscsi_conn *conn);
3733 };
3734
3735+struct iscsi_ipc *ipc;
3736+
3737 #endif /* ISCSI_IPC_H */