diff --git a/0043-idmb_rec_write-check-for-tpgt-first.patch b/0043-idmb_rec_write-check-for-tpgt-first.patch deleted file mode 100644 index cdc958a..0000000 --- a/0043-idmb_rec_write-check-for-tpgt-first.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 24a4d8156786dfd91dcc17b2472653e963ebd028 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 13 Aug 2013 10:59:44 -0700 -Subject: idmb_rec_write, check for tpgt first - -Factor out the check for a tpgt to a single place, before going crazy on -the rec files. Makes flow of this function easier to follow, and preps -for splitting it up. ---- - usr/idbm.c | 18 +++++------------- - 1 file changed, 5 insertions(+), 13 deletions(-) - -diff --git a/usr/idbm.c b/usr/idbm.c -index 1e4f8c8..0a88699 100644 ---- a/usr/idbm.c -+++ b/usr/idbm.c -@@ -1849,6 +1849,10 @@ static int idbm_rec_write(node_rec_t *rec) - if (rc) - goto free_portal; - -+ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) -+ /* drop down to old style portal as config */ -+ goto open_conf; -+ - rc = stat(portal, &statb); - if (rc) { - rc = 0; -@@ -1857,23 +1861,11 @@ static int idbm_rec_write(node_rec_t *rec) - * set the tgpt. In new versions you must pass all the info in - * from the start - */ -- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) -- /* drop down to old style portal as config */ -- goto open_conf; -- else -- goto mkdir_portal; -+ goto mkdir_portal; - } - - if (!S_ISDIR(statb.st_mode)) { - /* -- * older iscsiadm versions had you create the config then set -- * set the tgpt. In new versions you must pass all the info in -- * from the start -- */ -- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) -- /* drop down to old style portal as config */ -- goto open_conf; -- /* - * Old style portal as a file, but with tpgt. Let's update it. - */ - if (unlink(portal)) { --- -1.8.1.4 - diff --git a/0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch b/0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch deleted file mode 100644 index 358b50c..0000000 --- a/0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch +++ /dev/null @@ -1,61 +0,0 @@ -From b1799fe84ed94a19bba6bcd7284ce8b038be4ffe Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 10 Dec 2012 13:20:47 -0800 -Subject: iscsid: add --initrd option to set run from initrd hint for systemd - -See http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons - -Signed-off-by: Chris Leech ---- - usr/iscsid.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/usr/iscsid.c b/usr/iscsid.c -index b4bb65b..7d71085 100644 ---- a/usr/iscsid.c -+++ b/usr/iscsid.c -@@ -61,6 +61,7 @@ static pid_t log_pid; - static gid_t gid; - static int daemonize = 1; - static int mgmt_ipc_fd; -+static int initrd = 0; - - static struct option const long_options[] = { - {"config", required_argument, NULL, 'c'}, -@@ -73,6 +74,7 @@ static struct option const long_options[] = { - {"pid", required_argument, NULL, 'p'}, - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, -+ {"initrd", no_argument, &initrd, 1}, - {NULL, 0, NULL, 0}, - }; - -@@ -95,6 +97,7 @@ Open-iSCSI initiator daemon.\n\ - -p, --pid=pidfile use pid file (default " PID_FILE ").\n\ - -h, --help display this help and exit\n\ - -v, --version display version and exit\n\ -+ --initrd run from initrd\n\ - "); - } - exit(status); -@@ -383,12 +386,17 @@ int main(int argc, char *argv[]) - case 'h': - usage(0); - break; -+ case 0: -+ break; - default: - usage(1); - break; - } - } - -+ if (initrd) -+ argv[0][0] = '@'; -+ - /* initialize logger */ - log_pid = log_init(program_name, DEFAULT_AREA_SIZE, - daemonize ? log_do_log_daemon : log_do_log_std, NULL); --- -1.7.11.7 - diff --git a/0045-idbm_rec_write-seperate-old-and-new-style-writes.patch b/0045-idbm_rec_write-seperate-old-and-new-style-writes.patch deleted file mode 100644 index d138233..0000000 --- a/0045-idbm_rec_write-seperate-old-and-new-style-writes.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 954a9492b5ed1de5907ad2a7d7cc0ae6215d8fac Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 13 Aug 2013 11:34:31 -0700 -Subject: idbm_rec_write, seperate old and new style writes - -Duplicates a small bit of code, but easier to understand and extened. ---- - usr/idbm.c | 116 +++++++++++++++++++++++++++++++++++++++++-------------------- - 1 file changed, 79 insertions(+), 37 deletions(-) - -diff --git a/usr/idbm.c b/usr/idbm.c -index 0a88699..cb6ffd1 100644 ---- a/usr/idbm.c -+++ b/usr/idbm.c -@@ -1808,7 +1808,7 @@ mkdir_portal: - return f; - } - --static int idbm_rec_write(node_rec_t *rec) -+static int idbm_rec_write_new(node_rec_t *rec) - { - struct stat statb; - FILE *f; -@@ -1820,38 +1820,8 @@ static int idbm_rec_write(node_rec_t *rec) - log_error("Could not alloc portal\n"); - return ISCSI_ERR_NOMEM; - } -- -- snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); -- if (access(portal, F_OK) != 0) { -- if (mkdir(portal, 0660) != 0) { -- log_error("Could not make %s: %s\n", portal, -- strerror(errno)); -- rc = ISCSI_ERR_IDBM; -- goto free_portal; -- } -- } -- -- snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); -- if (access(portal, F_OK) != 0) { -- if (mkdir(portal, 0660) != 0) { -- log_error("Could not make %s: %s\n", portal, -- strerror(errno)); -- rc = ISCSI_ERR_IDBM; -- goto free_portal; -- } -- } -- - snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, - rec->name, rec->conn[0].address, rec->conn[0].port); -- log_debug(5, "Looking for config file %s", portal); -- -- rc = idbm_lock(); -- if (rc) -- goto free_portal; -- -- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) -- /* drop down to old style portal as config */ -- goto open_conf; - - rc = stat(portal, &statb); - if (rc) { -@@ -1872,11 +1842,11 @@ static int idbm_rec_write(node_rec_t *rec) - log_error("Could not convert %s: %s\n", portal, - strerror(errno)); - rc = ISCSI_ERR_IDBM; -- goto unlock; -+ goto free_portal; - } - } else { - rc = ISCSI_ERR_INVAL; -- goto unlock; -+ goto free_portal; - } - - mkdir_portal: -@@ -1887,24 +1857,96 @@ mkdir_portal: - log_error("Could not make dir %s: %s\n", - portal, strerror(errno)); - rc = ISCSI_ERR_IDBM; -- goto unlock; -+ goto free_portal; - } - } - - snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR, - rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt, - rec->iface.name); --open_conf: -+/* open_conf: */ - f = fopen(portal, "w"); - if (!f) { - log_error("Could not open %s: %sd\n", portal, strerror(errno)); - rc = ISCSI_ERR_IDBM; -- goto unlock; -+ goto free_portal; - } - - idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); - fclose(f); --unlock: -+free_portal: -+ free(portal); -+ return rc; -+} -+ -+static int idbm_rec_write_old(node_rec_t *rec) -+{ -+ FILE *f; -+ char *portal; -+ int rc = 0; -+ -+ portal = malloc(PATH_MAX); -+ if (!portal) { -+ log_error("Could not alloc portal\n"); -+ return ISCSI_ERR_NOMEM; -+ } -+ snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, -+ rec->name, rec->conn[0].address, rec->conn[0].port); -+ -+ f = fopen(portal, "w"); -+ if (!f) { -+ log_error("Could not open %s: %sd\n", portal, strerror(errno)); -+ rc = ISCSI_ERR_IDBM; -+ goto free_portal; -+ } -+ idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); -+ fclose(f); -+free_portal: -+ free(portal); -+ return rc; -+} -+ -+static int idbm_rec_write(node_rec_t *rec) -+{ -+ char *portal; -+ int rc = 0; -+ -+ portal = malloc(PATH_MAX); -+ if (!portal) { -+ log_error("Could not alloc portal\n"); -+ return ISCSI_ERR_NOMEM; -+ } -+ -+ snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); -+ if (access(portal, F_OK) != 0) { -+ if (mkdir(portal, 0660) != 0) { -+ log_error("Could not make %s: %s\n", portal, -+ strerror(errno)); -+ rc = ISCSI_ERR_IDBM; -+ goto free_portal; -+ } -+ } -+ -+ snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); -+ if (access(portal, F_OK) != 0) { -+ if (mkdir(portal, 0660) != 0) { -+ log_error("Could not make %s: %s\n", portal, -+ strerror(errno)); -+ rc = ISCSI_ERR_IDBM; -+ goto free_portal; -+ } -+ } -+ -+ rc = idbm_lock(); -+ if (rc) -+ goto free_portal; -+ -+ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) -+ /* old style portal as config */ -+ rc = idbm_rec_write_old(rec); -+ else -+ rc = idbm_rec_write_new(rec); -+ - idbm_unlock(); - free_portal: - free(portal); --- -1.8.1.4 - diff --git a/0046-idbw_rec_write-pick-tpgt-from-existing-record.patch b/0046-idbw_rec_write-pick-tpgt-from-existing-record.patch deleted file mode 100644 index 894eb4b..0000000 --- a/0046-idbw_rec_write-pick-tpgt-from-existing-record.patch +++ /dev/null @@ -1,76 +0,0 @@ -From cdb98072f7690cd9f5ec4aa5aa503711e552b5da Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 13 Aug 2013 12:39:07 -0700 -Subject: idbw_rec_write, pick tpgt from existing record - -On a static add (-m node -o new) without a user specified tpgt, looks -for existing new style records with tpgt before creating an old style -record without. If one exists, take the tpgt from it an write an -updated new style record instead. ---- - usr/idbm.c | 36 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/usr/idbm.c b/usr/idbm.c -index cb6ffd1..5adbd95 100644 ---- a/usr/idbm.c -+++ b/usr/idbm.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -1884,12 +1885,47 @@ static int idbm_rec_write_old(node_rec_t *rec) - FILE *f; - char *portal; - int rc = 0; -+ glob_t globbuf; -+ int i; -+ int tpgt = PORTAL_GROUP_TAG_UNKNOWN; - - portal = malloc(PATH_MAX); - if (!portal) { - log_error("Could not alloc portal\n"); - return ISCSI_ERR_NOMEM; - } -+ -+ /* check for newer portal dir with tpgt */ -+ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,*", NODE_CONFIG_DIR, -+ rec->name, rec->conn[0].address, rec->conn[0].port); -+ rc = glob(portal, GLOB_ONLYDIR, NULL, &globbuf); -+ if (!rc) { -+ if (globbuf.gl_pathc > 1) -+ log_warning("multiple tpg records for portal " -+ "%s/%s:%d found", rec->name, -+ rec->conn[0].address, rec->conn[0].port); -+ /* set pattern for sscanf matching of tpgt */ -+ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%%u", NODE_CONFIG_DIR, -+ rec->name, rec->conn[0].address, rec->conn[0].port); -+ for (i = 0; i < globbuf.gl_pathc; i++) { -+ rc = sscanf(globbuf.gl_pathv[i], portal, &tpgt); -+ if (rc == 1) -+ break; -+ } -+ if (tpgt == PORTAL_GROUP_TAG_UNKNOWN) -+ log_warning("glob match on existing records, " -+ "but no valid tpgt found"); -+ } -+ globfree(&globbuf); -+ -+ /* if a tpgt was selected from an old record, write entry in new format */ -+ if (tpgt != PORTAL_GROUP_TAG_UNKNOWN) { -+ log_warning("using tpgt %u from existing record", tpgt); -+ rec->tpgt = tpgt; -+ free(portal); -+ return idbm_rec_write_new(rec); -+ } -+ - snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, - rec->name, rec->conn[0].address, rec->conn[0].port); - --- -1.8.1.4 - diff --git a/0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch b/0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch deleted file mode 100644 index 537a947..0000000 --- a/0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch +++ /dev/null @@ -1,158 +0,0 @@ -From e5d7c7070358a5db8b849c8c5886e67881fe8906 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Fri, 7 Dec 2012 17:01:42 -0800 -Subject: [PATCH 47/47] iscsiadm, iscsid: newroot command to survive - switch_root - -When started from initramfs, iscsid needs to be able to chroot itself -to the runtime filesystem before the switch_root occurs. In the -initramfs "iscsiadm --newroot {root fs mount before switch}" should be -called before the switch_root. - -Signed-off-by: Chris Leech ---- - usr/iscsiadm.c | 30 ++++++++++++++++++++++++++++++ - usr/mgmt_ipc.c | 11 +++++++++++ - usr/mgmt_ipc.h | 6 +++++- - 3 files changed, 46 insertions(+), 1 deletion(-) - -diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c -index da0a3ec..af6d607 100644 ---- a/usr/iscsiadm.c -+++ b/usr/iscsiadm.c -@@ -117,6 +117,7 @@ static struct option const long_options[] = - {"interval", required_argument, NULL, 'i'}, - {"flashnode_idx", optional_argument, NULL, 'x'}, - {"portal_type", optional_argument, NULL, 'A'}, -+ {"newroot", required_argument, NULL, 0}, - {NULL, 0, NULL, 0}, - }; - static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:"; -@@ -137,6 +138,7 @@ iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid - iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\ - iscsiadm -m fw [ -d debug_level ] [ -l ]\n\ - iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ] | [ -C flashnode [ -o operation ] [ -A portal_type ] [ -x flashnode_idx ] [ -n name ] [ -v value ] ] ]\n\ -+iscsiadm --newroot switch_root_path\n\ - iscsiadm -k priority\n"); - } - exit(status); -@@ -278,6 +280,22 @@ static void kill_iscsid(int priority) - } - } - -+static void do_newroot(char *newroot) -+{ -+ iscsiadm_req_t req; -+ iscsiadm_rsp_t rsp; -+ int rc; -+ -+ memset(&req, 0, sizeof(req)); -+ req.command = MGMT_IPC_NEWROOT; -+ strncpy(req.u.newroot.path, newroot, PATH_MAX); -+ rc = iscsid_exec_req(&req, &rsp, 0); -+ if (rc) { -+ iscsi_err_print_msg(rc); -+ log_error("Could not send NEWROOT command"); -+ } -+} -+ - /* - * TODO: we can display how the ifaces are related to node records. - * And we can add a scsi_host mode which would display how -@@ -2800,6 +2818,7 @@ main(int argc, char **argv) - { - char *ip = NULL, *name = NULL, *value = NULL; - char *targetname = NULL, *group_session_mgmt_mode = NULL; -+ char *newroot = NULL; - int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0; - int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0; - int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0; -@@ -2837,6 +2856,12 @@ main(int argc, char **argv) - while ((ch = getopt_long(argc, argv, short_options, - long_options, &longindex)) >= 0) { - switch (ch) { -+ case 0: -+ if (long_options[longindex].flag != 0) -+ break; -+ if (!strcmp(long_options[longindex].name, "newroot")) -+ newroot = optarg; -+ break; - case 'k': - killiscsid = atoi(optarg); - if (killiscsid < 0) { -@@ -2989,6 +3014,11 @@ main(int argc, char **argv) - goto free_ifaces; - } - -+ if (newroot) { -+ do_newroot(newroot); -+ goto free_ifaces; -+ } -+ - if (mode < 0) - usage(ISCSI_ERR_INVAL); - -diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c -index 87bd346..5cb7143 100644 ---- a/usr/mgmt_ipc.c -+++ b/usr/mgmt_ipc.c -@@ -226,6 +226,16 @@ mgmt_ipc_immediate_stop(queue_task_t *qtask) - } - - static int -+mgmt_ipc_newroot(queue_task_t *qtask) -+{ -+ char *newroot = qtask->req.u.newroot.path; -+ if (chdir(newroot) || chroot(".") || chdir("/")) -+ return ISCSI_ERR; -+ mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS); -+ return ISCSI_SUCCESS; -+} -+ -+static int - mgmt_ipc_conn_remove(queue_task_t *qtask) - { - return ISCSI_ERR; -@@ -534,6 +544,7 @@ static mgmt_ipc_fn_t * mgmt_ipc_functions[__MGMT_IPC_MAX_COMMAND] = { - [MGMT_IPC_NOTIFY_DEL_NODE] = mgmt_ipc_notify_del_node, - [MGMT_IPC_NOTIFY_ADD_PORTAL] = mgmt_ipc_notify_add_portal, - [MGMT_IPC_NOTIFY_DEL_PORTAL] = mgmt_ipc_notify_del_portal, -+[MGMT_IPC_NEWROOT] = mgmt_ipc_newroot, - }; - - void mgmt_ipc_handle(int accept_fd) -diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h -index 55972ed..102ffff 100644 ---- a/usr/mgmt_ipc.h -+++ b/usr/mgmt_ipc.h -@@ -22,6 +22,7 @@ - #include "types.h" - #include "iscsi_if.h" - #include "config.h" -+#include "limits.h" - - #define ISCSIADM_NAMESPACE "ISCSIADM_ABSTRACT_NAMESPACE" - #define PEERUSER_MAX 64 -@@ -46,6 +47,7 @@ typedef enum iscsiadm_cmd { - MGMT_IPC_NOTIFY_DEL_NODE = 17, - MGMT_IPC_NOTIFY_ADD_PORTAL = 18, - MGMT_IPC_NOTIFY_DEL_PORTAL = 19, -+ MGMT_IPC_NEWROOT = 20, - - __MGMT_IPC_MAX_COMMAND - } iscsiadm_cmd_e; -@@ -75,8 +77,10 @@ typedef struct iscsiadm_req { - int param; - /* TODO: make this variable len to support */ - char value[IFNAMSIZ + 1]; -- - } set_host_param; -+ struct ipc_msg_newroot { -+ char path[PATH_MAX + 1]; -+ } newroot; - } u; - } iscsiadm_req_t; - --- -1.8.1.4 - diff --git a/0047-iscsiuio-systemd-socket-activation-support.patch b/0047-iscsiuio-systemd-socket-activation-support.patch deleted file mode 100644 index 896eba9..0000000 --- a/0047-iscsiuio-systemd-socket-activation-support.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 8003178db245b43d04b27b559d5541ced24ec13f Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Wed, 19 Dec 2012 21:39:06 -0800 -Subject: [PATCH] iscsiuio systemd socket activation support - ---- - iscsiuio/src/unix/iscsid_ipc.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/iscsiuio/src/unix/iscsid_ipc.c b/iscsiuio/src/unix/iscsid_ipc.c -index e22de0d..4908cb7 100644 ---- a/iscsiuio/src/unix/iscsid_ipc.c -+++ b/iscsiuio/src/unix/iscsid_ipc.c -@@ -948,6 +948,30 @@ static void *iscsid_loop(void *arg) - pthread_exit(NULL); - } - -+#define SD_SOCKET_FDS_START 3 -+ -+static int ipc_systemd(void) -+{ -+ char *env; -+ -+ env = getenv("LISTEN_PID"); -+ -+ if (!env || (strtoul(env, NULL, 10) != getpid())) -+ return -EINVAL; -+ -+ env = getenv("LISTEN_FDS"); -+ -+ if (!env) -+ return -EINVAL; -+ -+ if (strtoul(env, NULL, 10) != 1) { -+ LOG_ERR("Did not receive exactly one IPC socket from systemd"); -+ return -EINVAL; -+ } -+ -+ return SD_SOCKET_FDS_START; -+} -+ - /****************************************************************************** - * Initialize/Cleanup routines - ******************************************************************************/ -@@ -961,6 +985,10 @@ int iscsid_init() - int rc, addr_len; - struct sockaddr_un addr; - -+ iscsid_opts.fd = ipc_systemd(); -+ if (iscsid_opts.fd >= 0) -+ return 0; -+ - iscsid_opts.fd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (iscsid_opts.fd < 0) { - LOG_ERR(PFX "Can not create IPC socket"); --- -1.8.3.1 - diff --git a/0048-iscsiadm-param-parsing-for-advanced-node-creation.patch b/0048-iscsiadm-param-parsing-for-advanced-node-creation.patch deleted file mode 100644 index a39833b..0000000 --- a/0048-iscsiadm-param-parsing-for-advanced-node-creation.patch +++ /dev/null @@ -1,337 +0,0 @@ -From b58f3b48a36821d10a3377acfcbf18113fba0c9d Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 18 Dec 2012 11:27:00 -0800 -Subject: [PATCH 48/48] iscsiadm: --param parsing for advanced node creation - -Share parse_param and apply_param code from iscsistart, allow using multiple ---param options to set arbitrary fields in node mode. - -Signed-off-by: Chris Leech ---- - usr/Makefile | 2 +- - usr/iscsi_param.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - usr/iscsi_param.h | 7 ++++ - usr/iscsiadm.c | 16 ++++++++-- - usr/iscsistart.c | 91 ++-------------------------------------------------- - 5 files changed, 120 insertions(+), 91 deletions(-) - create mode 100644 usr/iscsi_param.c - create mode 100644 usr/iscsi_param.h - -diff --git a/usr/Makefile b/usr/Makefile -index 3d8ee22..a7e80c0 100644 ---- a/usr/Makefile -+++ b/usr/Makefile -@@ -40,7 +40,7 @@ SYSDEPS_SRCS = $(wildcard ../utils/sysdeps/*.o) - ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \ - sha1.o iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \ - iscsi_net_util.o iscsid_req.o transport.o iser.o cxgbi.o be2iscsi.o \ -- initiator_common.o iscsi_err.o flashnode.o uip_mgmt_ipc.o \ -+ initiator_common.o iscsi_err.o iscsi_param.o flashnode.o uip_mgmt_ipc.o \ - $(IPC_OBJ) $(SYSDEPS_SRCS) - # core initiator files - INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o kern_err_table.o -diff --git a/usr/iscsi_param.c b/usr/iscsi_param.c -new file mode 100644 -index 0000000..c075e8f ---- /dev/null -+++ b/usr/iscsi_param.c -@@ -0,0 +1,95 @@ -+#include -+#include "log.h" -+#include "config.h" -+#include "idbm.h" -+#include "list.h" -+#include "iface.h" -+#include "idbm_fields.h" -+#include "iscsi_err.h" -+ -+int apply_params(struct list_head *user_params, struct node_rec *rec) -+{ -+ struct user_param *param; -+ int rc; -+ -+ /* Must init this so we can check if user overrode them */ -+ rec->session.initial_login_retry_max = -1; -+ rec->conn[0].timeo.noop_out_interval = -1; -+ rec->conn[0].timeo.noop_out_timeout = -1; -+ -+ list_for_each_entry(param, user_params, list) { -+ /* -+ * user may not have passed in all params that were set by -+ * ibft/iscsi_boot, so clear out values that might conflict -+ * with user overrides -+ */ -+ if (!strcmp(param->name, IFACE_NETNAME)) { -+ /* overriding netname so MAC will be for old netdev */ -+ memset(rec->iface.hwaddress, 0, -+ sizeof(rec->iface.hwaddress)); -+ } else if (!strcmp(param->name, IFACE_HWADDR)) { -+ /* overriding MAC so netdev will be for old MAC */ -+ memset(rec->iface.netdev, 0, sizeof(rec->iface.netdev)); -+ } else if (!strcmp(param->name, IFACE_TRANSPORTNAME)) { -+ /* -+ * switching drivers so all old binding info is no -+ * longer valid. Old values were either for offload -+ * and we are switching to software or the reverse, -+ * or switching types of cards (bnx2i to cxgb3i). -+ */ -+ memset(&rec->iface, 0, sizeof(rec->iface)); -+ iface_setup_defaults(&rec->iface); -+ } -+ } -+ -+ rc = idbm_node_set_rec_from_param(user_params, rec, 0); -+ if (rc) -+ return rc; -+ -+ /* -+ * For root boot we could not change this in older versions so -+ * if user did not override then use the defaults. -+ * -+ * Increase to account for boot using static setup. -+ */ -+ if (rec->session.initial_login_retry_max == -1) -+ rec->session.initial_login_retry_max = 30; -+ /* we used to not be able to answer so turn off */ -+ if (rec->conn[0].timeo.noop_out_interval == -1) -+ rec->conn[0].timeo.noop_out_interval = 0; -+ if (rec->conn[0].timeo.noop_out_timeout == -1) -+ rec->conn[0].timeo.noop_out_timeout = 0; -+ -+ return 0; -+} -+ -+int parse_param(struct list_head *user_params, char *param_str) -+{ -+ struct user_param *param; -+ char *name, *value; -+ -+ name = param_str; -+ -+ value = strchr(param_str, '='); -+ if (!value) { -+ log_error("Invalid --param %s. Missing value.", param_str); -+ return ISCSI_ERR_INVAL; -+ } -+ *value = '\0'; -+ -+ value++; -+ if (!strlen(value)) { -+ log_error("Invalid --param %s. Missing value.", param_str); -+ return ISCSI_ERR_INVAL; -+ } -+ -+ param = idbm_alloc_user_param(name, value); -+ if (!param) { -+ log_error("Could not allocate memory for param."); -+ return ISCSI_ERR_NOMEM; -+ } -+ -+ list_add(¶m->list, user_params); -+ return 0; -+} -+ -diff --git a/usr/iscsi_param.h b/usr/iscsi_param.h -new file mode 100644 -index 0000000..8b7956c ---- /dev/null -+++ b/usr/iscsi_param.h -@@ -0,0 +1,7 @@ -+#ifndef ISCSI_PARAM_H -+#define ISCSI_PARAM_H -+ -+extern int parse_param(struct list_head *user_params, char *param_str); -+extern int apply_params(struct list_head *user_params, struct node_rec *rec); -+ -+#endif -diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c -index af6d607..2003d48 100644 ---- a/usr/iscsiadm.c -+++ b/usr/iscsiadm.c -@@ -53,6 +53,7 @@ - #include "iscsi_err.h" - #include "iscsi_ipc.h" - #include "iscsi_timer.h" -+#include "iscsi_param.h" - #include "flashnode.h" - - static char program_name[] = "iscsiadm"; -@@ -118,6 +119,7 @@ static struct option const long_options[] = - {"flashnode_idx", optional_argument, NULL, 'x'}, - {"portal_type", optional_argument, NULL, 'A'}, - {"newroot", required_argument, NULL, 0}, -+ {"param", required_argument, NULL, 0}, - {NULL, 0, NULL, 0}, - }; - static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:"; -@@ -133,7 +135,7 @@ iscsiadm -m discoverydb [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p - [ -o operation ] [ -n name ] [ -v value ] [ -lD ] ] \n\ - iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ [ -p ip:port ] [ -l | -D ] ] \n\ - iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I ifaceN ] [ -l | -u | -R | -s] ] \ --[ [ -o operation ] [ -n name ] [ -v value ] ]\n\ -+[ [ -o operation ] [ -n name ] [ -v value ] ] [ --param=NAME=VALUE ]\n\ - iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\ - iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\ - iscsiadm -m fw [ -d debug_level ] [ -l ]\n\ -@@ -2834,9 +2836,11 @@ main(int argc, char **argv) - uint32_t host_no = -1; - struct user_param *param; - struct list_head params; -+ struct list_head user_params; - - INIT_LIST_HEAD(¶ms); - INIT_LIST_HEAD(&ifaces); -+ INIT_LIST_HEAD(&user_params); - /* do not allow ctrl-c for now... */ - memset(&sa_old, 0, sizeof(struct sigaction)); - memset(&sa_new, 0, sizeof(struct sigaction)); -@@ -2859,8 +2863,14 @@ main(int argc, char **argv) - case 0: - if (long_options[longindex].flag != 0) - break; -- if (!strcmp(long_options[longindex].name, "newroot")) -+ if (!strcmp(long_options[longindex].name, "newroot")) { - newroot = optarg; -+ break; -+ } -+ if (!strcmp(long_options[longindex].name, "param")) { -+ parse_param(&user_params, optarg); -+ break; -+ } - break; - case 'k': - killiscsid = atoi(optarg); -@@ -3169,6 +3179,8 @@ main(int argc, char **argv) - goto out; - } - -+ apply_params(&user_params, rec); -+ - rc = exec_node_op(op, do_login, do_logout, do_show, - do_rescan, do_stats, info_level, rec, - ¶ms); -diff --git a/usr/iscsistart.c b/usr/iscsistart.c -index 6924d49..85be35b 100644 ---- a/usr/iscsistart.c -+++ b/usr/iscsistart.c -@@ -50,6 +50,7 @@ - #include "iscsid_req.h" - #include "iscsi_err.h" - #include "iface.h" -+#include "iscsi_param.h" - - /* global config info */ - /* initiator needs initiator name/alias */ -@@ -131,99 +132,13 @@ static int stop_event_loop(void) - return rc; - } - --static int apply_params(struct node_rec *rec) --{ -- struct user_param *param; -- int rc; -- -- /* Must init this so we can check if user overrode them */ -- rec->session.initial_login_retry_max = -1; -- rec->conn[0].timeo.noop_out_interval = -1; -- rec->conn[0].timeo.noop_out_timeout = -1; -- -- list_for_each_entry(param, &user_params, list) { -- /* -- * user may not have passed in all params that were set by -- * ibft/iscsi_boot, so clear out values that might conflict -- * with user overrides -- */ -- if (!strcmp(param->name, IFACE_NETNAME)) { -- /* overriding netname so MAC will be for old netdev */ -- memset(rec->iface.hwaddress, 0, -- sizeof(rec->iface.hwaddress)); -- } else if (!strcmp(param->name, IFACE_HWADDR)) { -- /* overriding MAC so netdev will be for old MAC */ -- memset(rec->iface.netdev, 0, sizeof(rec->iface.netdev)); -- } else if (!strcmp(param->name, IFACE_TRANSPORTNAME)) { -- /* -- * switching drivers so all old binding info is no -- * longer valid. Old values were either for offload -- * and we are switching to software or the reverse, -- * or switching types of cards (bnx2i to cxgb3i). -- */ -- memset(&rec->iface, 0, sizeof(rec->iface)); -- iface_setup_defaults(&rec->iface); -- } -- } -- -- rc = idbm_node_set_rec_from_param(&user_params, rec, 0); -- if (rc) -- return rc; -- -- /* -- * For root boot we could not change this in older versions so -- * if user did not override then use the defaults. -- * -- * Increase to account for boot using static setup. -- */ -- if (rec->session.initial_login_retry_max == -1) -- rec->session.initial_login_retry_max = 30; -- /* we used to not be able to answer so turn off */ -- if (rec->conn[0].timeo.noop_out_interval == -1) -- rec->conn[0].timeo.noop_out_interval = 0; -- if (rec->conn[0].timeo.noop_out_timeout == -1) -- rec->conn[0].timeo.noop_out_timeout = 0; -- -- return 0; --} -- --static int parse_param(char *param_str) --{ -- struct user_param *param; -- char *name, *value; -- -- name = param_str; -- -- value = strchr(param_str, '='); -- if (!value) { -- log_error("Invalid --param %s. Missing value.", param_str); -- return ISCSI_ERR_INVAL; -- } -- *value = '\0'; -- -- value++; -- if (!strlen(value)) { -- log_error("Invalid --param %s. Missing value.", param_str); -- return ISCSI_ERR_INVAL; -- } -- -- param = idbm_alloc_user_param(name, value); -- if (!param) { -- log_error("Could not allocate memory for param."); -- return ISCSI_ERR_NOMEM; -- } -- -- list_add(¶m->list, &user_params); -- return 0; --} -- - static int login_session(struct node_rec *rec) - { - iscsiadm_req_t req; - iscsiadm_rsp_t rsp; - int rc, retries = 0; - -- rc = apply_params(rec); -+ rc = apply_params(&user_params, rec); - if (rc) - return rc; - -@@ -426,7 +341,7 @@ int main(int argc, char *argv[]) - fw_free_targets(&targets); - exit(0); - case 'P': -- err = parse_param(optarg); -+ err = parse_param(&user_params, optarg); - if (err) - exit(err); - break; --- -1.8.1.4 - diff --git a/0049-update-systemd-service-files-add-iscsi.service-for-s.patch b/0049-update-systemd-service-files-add-iscsi.service-for-s.patch deleted file mode 100644 index 966bb9f..0000000 --- a/0049-update-systemd-service-files-add-iscsi.service-for-s.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 1c3b1d23e0b3f17399ffd4463cafad813b0444d5 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Wed, 19 Dec 2012 15:07:36 -0800 -Subject: update systemd service files, add iscsi.service for starting - sessions on boot - -Signed-off-by: Chris Leech ---- - etc/systemd/iscsi.service | 19 +++++++++++++++++++ - etc/systemd/iscsi_mark_root_nodes | 14 ++++++++++++++ - etc/systemd/iscsid.service | 7 +++++-- - etc/systemd/iscsid.socket | 2 +- - 4 files changed, 39 insertions(+), 3 deletions(-) - create mode 100644 etc/systemd/iscsi.service - create mode 100755 etc/systemd/iscsi_mark_root_nodes - -diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service -new file mode 100644 -index 0000000..bbd52fd ---- /dev/null -+++ b/etc/systemd/iscsi.service -@@ -0,0 +1,19 @@ -+[Unit] -+Description=Login and scanning of iSCSI devices -+Documentation=man:iscsid(8) man:iscsiadm(8) -+DefaultDependencies=no -+Conflicts=shutdown.target -+After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service -+Before=remote-fs-pre.target -+ConditionPathExists=/etc/iscsi/initiatorname.iscsi -+ -+[Service] -+Type=oneshot -+RemainAfterExit=true -+ExecStart=/usr/libexec/iscsi_mark_root_nodes -+ExecStart=/sbin/iscsiadm -m node --loginall=automatic -+ExecStop=/bin/sync -+ExecStop=/sbin/iscsiadm -m node --logoutall=automatic -+ -+[Install] -+WantedBy=sysinit.target -diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes -new file mode 100755 -index 0000000..c68475c ---- /dev/null -+++ b/etc/systemd/iscsi_mark_root_nodes -@@ -0,0 +1,14 @@ -+#!/bin/bash -+ -+ISCSIADM=/sbin/iscsiadm -+SESSION_FILE=/run/initramfs/iscsi.sessions -+ -+if [ ! -f $SESSION_FILE ] ; then -+ exit 0 -+fi -+ -+while read t num i target; do -+ ip=${i%:*} -+ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot -+done < $SESSION_FILE -+ -diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service -index 028e0b3..653dd08 100644 ---- a/etc/systemd/iscsid.service -+++ b/etc/systemd/iscsid.service -@@ -1,7 +1,10 @@ - [Unit] - Description=Open-iSCSI --Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) --After=network.target NetworkManager-wait-online.service iscsiuio.service tgtd.service targetcli.service -+Documentation=man:iscsid(8) man:iscsiadm(8) -+DefaultDependencies=no -+Conflicts=shutdown.target -+After=network.target iscsiuio.service -+Before=remote-fs-pre.target - - [Service] - Type=forking -diff --git a/etc/systemd/iscsid.socket b/etc/systemd/iscsid.socket -index 832451d..58a8d12 100644 ---- a/etc/systemd/iscsid.socket -+++ b/etc/systemd/iscsid.socket -@@ -1,6 +1,6 @@ - [Unit] - Description=Open-iSCSI iscsid Socket --Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) -+Documentation=man:iscsid(8) man:iscsiadm(8) - - [Socket] - ListenStream=@ISCSIADM_ABSTRACT_NAMESPACE --- -1.7.11.7 - diff --git a/0050-iscsi-boot-related-service-file-updates.patch b/0050-iscsi-boot-related-service-file-updates.patch deleted file mode 100644 index 19450ee..0000000 --- a/0050-iscsi-boot-related-service-file-updates.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 8f79529354b4023c371e00091f11bdd523497639 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 19 Aug 2013 07:18:25 -0700 -Subject: iscsi boot related service file updates - -make sure iscsid gets started if there are any boot sessions running -add reload target to fix double session problem when restarting from NM -don't rely on session list passed from initrd, never got fully implemented ---- - etc/systemd/iscsi-mark-root-nodes | 13 +++++++++++++ - etc/systemd/iscsi.service | 3 ++- - etc/systemd/iscsi_mark_root_nodes | 14 -------------- - 3 files changed, 15 insertions(+), 15 deletions(-) - create mode 100644 etc/systemd/iscsi-mark-root-nodes - delete mode 100644 etc/systemd/iscsi_mark_root_nodes - -diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes -new file mode 100644 -index 0000000..157be62 ---- /dev/null -+++ b/etc/systemd/iscsi-mark-root-nodes -@@ -0,0 +1,13 @@ -+#!/bin/bash -+ -+ISCSIADM=/sbin/iscsiadm -+ -+$ISCSIADM -m session >/dev/null 2>&1 || exit 0 -+ -+$ISCSIADM -m session | while read t num i target; do -+ ip=${i%:*} -+ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot -+done -+ -+systemctl start iscsid.service -+ -diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service -index 7b4efee..d5712bd 100644 ---- a/etc/systemd/iscsi.service -+++ b/etc/systemd/iscsi.service -@@ -10,10 +10,11 @@ ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes - [Service] - Type=oneshot - RemainAfterExit=true --ExecStart=/usr/libexec/iscsi_mark_root_nodes -+ExecStart=/usr/libexec/iscsi-mark-root-nodes - ExecStart=/sbin/iscsiadm -m node --loginall=automatic - ExecStop=/bin/sync - ExecStop=/sbin/iscsiadm -m node --logoutall=automatic -+ExecReload=/sbin/iscsiadm -m node --loginall=automatic - - [Install] - WantedBy=sysinit.target -diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes -deleted file mode 100644 -index c68475c..0000000 ---- a/etc/systemd/iscsi_mark_root_nodes -+++ /dev/null -@@ -1,14 +0,0 @@ --#!/bin/bash -- --ISCSIADM=/sbin/iscsiadm --SESSION_FILE=/run/initramfs/iscsi.sessions -- --if [ ! -f $SESSION_FILE ] ; then -- exit 0 --fi -- --while read t num i target; do -- ip=${i%:*} -- $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot --done < $SESSION_FILE -- --- -1.8.1.4 - diff --git a/0051-update-initscripts-and-docs.patch b/0051-update-initscripts-and-docs.patch deleted file mode 100644 index e2d4cdc..0000000 --- a/0051-update-initscripts-and-docs.patch +++ /dev/null @@ -1,130 +0,0 @@ -From c255c2cd43afeaefa428237a3200f02fb238d89e Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 19 Nov 2012 16:37:13 -0800 -Subject: update initscripts and docs - ---- - README | 9 +++------ - etc/iscsid.conf | 23 +++++++++++------------ - usr/idbm.c | 4 ++++ - 3 files changed, 18 insertions(+), 18 deletions(-) - -diff --git a/README b/README -index ec22098..2a8319a 100644 ---- a/README -+++ b/README -@@ -74,11 +74,6 @@ the cache sync command will fail. - - iscsiadm's -P 3 option will not print out scsi devices. - - iscsid will not automatically online devices. - --You need to enable "Cryptographic API" under "Cryptographic options" in the --kernel config. And you must enable "CRC32c CRC algorithm" even if --you do not use header or data digests. They are the kernel options, --CONFIG_CRYPTO and CONFIG_CRYPTO_CRC32C, respectively. -- - By default the kernel's iSCSI modules will be used. Running: - - make -@@ -997,7 +992,7 @@ Red Hat or Fedora: - ----------------- - To start open-iscsi in Red Hat/Fedora you can do: - -- service open-iscsi start -+ service iscsi start - - To get open-iscsi to automatically start at run time you may have to - run: -@@ -1205,6 +1200,8 @@ iscsid will only perform rediscovery when it gets a SCN from the server. - # linux-isns (SLES's iSNS server) where it sometimes does not send SCN - # events in the proper format, so they may not get handled. - -+To set the startup value, so that nodes are not logged into automatically -+use the value "manual". - - Example: - -------- -diff --git a/etc/iscsid.conf b/etc/iscsid.conf -index ef76dc0..ac1d231 100644 ---- a/etc/iscsid.conf -+++ b/etc/iscsid.conf -@@ -17,10 +17,10 @@ - # maintainers. - # - # Default for Fedora and RHEL. (uncomment to activate). --# iscsid.startup = /etc/rc.d/init.d/iscsid force-start -+iscsid.startup = /etc/rc.d/init.d/iscsid force-start - # - # Default for upstream open-iscsi scripts (uncomment to activate). --iscsid.startup = /sbin/iscsid -+# iscsid.startup = /sbin/iscsid - - - ############################# -@@ -36,8 +36,8 @@ iscsid.startup = /sbin/iscsid - # To request that the iscsi initd scripts startup a session set to "automatic". - # node.startup = automatic - # --# To manually startup the session set to "manual". The default is manual. --node.startup = manual -+# To manually startup the session set to "manual". The default is automatic. -+node.startup = automatic - - # For "automatic" startup nodes, setting this to "Yes" will try logins on each - # available iface until one succeeds, and then stop. The default "No" will try -@@ -259,28 +259,27 @@ node.conn[0].iscsi.MaxXmitDataSegmentLength = 0 - discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 - - # To allow the targets to control the setting of the digest checking, --# with the initiator requesting a preference of enabling the checking, uncomment# one or both of the following lines: -+# with the initiator requesting a preference of enabling the checking, uncomment -+# the following lines (Data digests are not supported.): - #node.conn[0].iscsi.HeaderDigest = CRC32C,None --#node.conn[0].iscsi.DataDigest = CRC32C,None -+ - # - # To allow the targets to control the setting of the digest checking, - # with the initiator requesting a preference of disabling the checking, --# uncomment one or both of the following lines: -+# uncomment the following line: - #node.conn[0].iscsi.HeaderDigest = None,CRC32C --#node.conn[0].iscsi.DataDigest = None,CRC32C - # - # To enable CRC32C digest checking for the header and/or data part of --# iSCSI PDUs, uncomment one or both of the following lines: -+# iSCSI PDUs, uncomment the following line: - #node.conn[0].iscsi.HeaderDigest = CRC32C --#node.conn[0].iscsi.DataDigest = CRC32C - # - # To disable digest checking for the header and/or data part of --# iSCSI PDUs, uncomment one or both of the following lines: -+# iSCSI PDUs, uncomment the following line: - #node.conn[0].iscsi.HeaderDigest = None --#node.conn[0].iscsi.DataDigest = None - # - # The default is to never use DataDigests or HeaderDigests. - # -+node.conn[0].iscsi.HeaderDigest = None - - # For multipath configurations, you may want more than one session to be - # created on each iface record. If node.session.nr_sessions is greater -diff --git a/usr/idbm.c b/usr/idbm.c -index 4d30aa9..a1d7d37 100644 ---- a/usr/idbm.c -+++ b/usr/idbm.c -@@ -399,9 +399,13 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) - IDBM_SHOW, "None", "CRC32C", "CRC32C,None", - "None,CRC32C", num, 1); - sprintf(key, CONN_DATA_DIGEST, i); -+ -+#if 0 -+We do not support data digests - __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW, - "None", "CRC32C", "CRC32C,None", - "None,CRC32C", num, 1); -+#endif - sprintf(key, CONN_IFMARKER, i); - __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW, - "No", "Yes", num, 1); --- -1.7.11.7 - diff --git a/0052-use-var-for-config.patch b/0052-use-var-for-config.patch deleted file mode 100644 index 2e4288c..0000000 --- a/0052-use-var-for-config.patch +++ /dev/null @@ -1,239 +0,0 @@ -From be8702e609fdfd417547f758cb88956066b63023 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 19 Nov 2012 16:38:45 -0800 -Subject: use var for config - ---- - README | 33 ++++++++++++++++----------------- - doc/iscsiadm.8 | 8 ++++---- - usr/idbm.c | 6 +++--- - usr/idbm.h | 13 +++++++------ - usr/iface.h | 4 +++- - 5 files changed, 33 insertions(+), 31 deletions(-) - -diff --git a/README b/README -index 90e2074..9cc62ca 100644 ---- a/README -+++ b/README -@@ -156,8 +156,7 @@ Usage: iscsid [OPTION] - - Open-iSCSI persistent configuration is stored in a number of - directories under a configuration root directory, using a flat-file --format. This configuration root directory is /etc/iscsi by default, --but may also commonly be in /var/lib/iscsi. -+format. This configuration root directory is /var/lib/iscsi by default. - - Configuration is contained in directories for: - -@@ -467,7 +466,7 @@ a scsi_host per HBA port). - To manage both types of initiator stacks, iscsiadm uses the interface (iface) - structure. For each HBA port or for software iscsi for each network - device (ethX) or NIC, that you wish to bind sessions to you must create --a iface config /etc/iscsi/ifaces. -+a iface config /var/lib/iscsi/ifaces. - - Prep: - -@@ -501,29 +500,29 @@ Running: - iface0 qla4xxx,00:c0:dd:08:63:e8,20.15.0.7,default,iqn.2005-06.com.redhat:madmax - iface1 qla4xxx,00:c0:dd:08:63:ea,20.15.0.9,default,iqn.2005-06.com.redhat:madmax - --Will report iface configurations that are setup in /etc/iscsi/ifaces. -+Will report iface configurations that are setup in /var/lib/iscsi/ifaces. - The format is: - - iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname - - For software iscsi, you can create the iface configs by hand, but it is - reccomended that you use iscsiadm's iface mode. There is a iface.example in --/etc/iscsi/ifaces which can be used as a template for the daring. -+/var/lib/iscsi/ifaces which can be used as a template for the daring. - - For each network object you wish to bind a session to you must create --a seperate iface config in /etc/iscsi/ifaces and each iface config file -+a seperate iface config in /var/lib/iscsi/ifaces and each iface config file - must have a unique name which is less than or equal to 64 characters. - - Example: - - If you have NIC1 with MAC address 00:0F:1F:92:6B:BF and NIC2 with - MAC address 00:C0:DD:08:63:E7 and you wanted to do software iscsi over --TCP/IP. Then in /etc/iscsi/ifaces/iface0 you would enter: -+TCP/IP. Then in /var/lib/iscsi/ifaces/iface0 you would enter: - - iface.transport_name = tcp - iface.hwaddress = 00:0F:1F:92:6B:BF - --and in /etc/iscsi/ifaces/iface1 you would enter: -+and in /var/lib/iscsi/ifaces/iface1 you would enter: - - iface.transport_name = tcp - iface.hwaddress = 00:C0:DD:08:63:E7 -@@ -573,7 +572,7 @@ cxgb3i.00:07:43:05:97:07 cxgb3i,00:07:43:05:97:07,,, - qla4xxx.00:0e:1e:04:8b:2e qla4xxx,00:0e:1e:04:8b:2e,,, - - --Will report iface configurations that are setup in /etc/iscsi/ifaces. -+Will report iface configurations that are setup in /var/lib/iscsi/ifaces. - The format is: - - iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname -@@ -659,7 +658,7 @@ need a seperate network connection to the target for discovery purposes. - *This will be fixed in the next version of open-iscsi* - - For compatibility reasons, when you run iscsiadm to do discovery, it --will check for interfaces in /etc/iscsi/iscsi/ifaces that are using -+will check for interfaces in /var/lib/iscsi/ifaces that are using - tcp for the iface.transport and it will bind the portals that are discovered - so that they will be logged in through those ifaces. This behavior can also - be overriden by passing in the interfaces you want to use. For the case -@@ -677,7 +676,7 @@ we do not bind a session to a iface, then you can use the special iface - - iscsiadm -m discoverydb -t st -p ip:port -I default --discover -P 1 - --And if you did not define any interfaces in /etc/iscsi/ifaces and do -+And if you did not define any interfaces in /var/lib/iscsi/ifaces and do - not pass anything into iscsiadm, running iscsiadm will do the default - behavior, where we allow the network subsystem to decide which - device to use. -@@ -719,7 +718,7 @@ To now log into targets it is the same as with sofware iscsi. See section - - ./iscsiadm -m discoverydb -t st -p 192.168.1.1:3260 --discover - -- This will search /etc/iscsi/send_targets for a record with the -+ This will search /var/lib/iscsi/send_targets for a record with the - ID [portal = 192.168.1.1:3260 and type = sendtargets. If found it - will perform discovery using the settings stored in the record. - If a record does not exist, it will be created using the iscsid.conf -@@ -728,7 +727,7 @@ To now log into targets it is the same as with sofware iscsi. See section - The argument to -p may also be a hostname instead of an address. - ./iscsiadm -m discoverydb -t st -p smoehost --discover - -- For the ifaces, iscsiadm will first search /etc/iscsi/ifaces for -+ For the ifaces, iscsiadm will first search /var/lib/iscsi/ifaces for - interfaces using software iscsi. If any are found then nodes found - during discovery will be setup so that they can logged in through - those interfaces. To specify a specific iface, pass the -@@ -784,7 +783,7 @@ To now log into targets it is the same as with sofware iscsi. See section - This command will perform discovery, but not manipulate the node DB. - - - SendTargets iSCSI Discovery with a specific interface. If you -- wish to only use a subset of the interfaces in /etc/iscsi/ifaces -+ wish to only use a subset of the interfaces in /var/lib/iscsi/ifaces - then you can pass them in during discovery: - - ./iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \ -@@ -1145,8 +1144,8 @@ where targetname is the name of the target and ip_address:port is the address - and port of the portal. tpgt, is the portal group tag of - the portal, and is not used in iscsiadm commands except for static - record creation. And iface name is the name of the iscsi interface --defined in /etc/iscsi/ifaces. If no interface was defined in --/etc/iscsi/ifaces or passed in, the default behavior is used. -+defined in /var/lib/iscsi/ifaces. If no interface was defined in -+/var/lib/iscsi/ifaces or passed in, the default behavior is used. - Default here is iscsi_tcp/tcp to be used over which ever NIC the - network layer decides is best. - -@@ -1261,7 +1260,7 @@ If set, iscsid will perform discovery to the address every - discovery.isns.discoveryd_poll_inval or - discovery.sendtargets.discoveryd_poll_inval seconds, - and it will log into any portals found from the discovery source using --the ifaces in /etc/iscsi/ifaces. -+the ifaces in /var/lib/iscsi/ifaces. - - Note that for iSNS the poll_interval does not have to be set. If not set, - iscsid will only perform rediscovery when it gets a SCN from the server. -diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 -index 6b15fcd..30811bd 100644 ---- a/doc/iscsiadm.8 -+++ b/doc/iscsiadm.8 -@@ -101,7 +101,7 @@ This option is only valid for ping submode. - .TP - \fB\-I\fR, \fB\-\-interface=\fI[iface]\fR - The interface argument specifies the iSCSI interface to use for the operation. --iSCSI interfaces (iface) are defined in /etc/iscsi/ifaces. For hardware -+iSCSI interfaces (iface) are defined in /var/lib/iscsi/ifaces. For hardware - iSCSI (qla4xxx) the iface config must have the hardware address - (iface.hwaddress = port's MAC address) - and the driver/transport_name (iface.transport_name). The iface's name is -@@ -178,7 +178,7 @@ If no other options are specified: for \fIdiscoverydb\fR and \fInode\fR, all - of their respective records are displayed; for \fIsession\fR, all active - sessions and connections are displayed; for \fIfw\fR, all boot firmware - values are displayed; for \fIhost\fR, all iSCSI hosts are displayed; and --for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed. -+for \fIiface\fR, all ifaces setup in /var/lib/iscsi/ifaces are displayed. - - .TP - \fB\-n\fR, \fB\-\-name=\fIname\fR -@@ -562,10 +562,10 @@ The configuration file read by \fBiscsid\fR and \fBiscsiadm\fR on startup. - The file containing the iSCSI InitiatorName and InitiatorAlias read by - \fBiscsid\fR and \fBiscsiadm\fR on startup. - .TP --/etc/iscsi/nodes/ -+/var/lib/iscsi/nodes/ - This directory contains the nodes with their targets. - .TP --/etc/iscsi/send_targets -+/var/lib/iscsi/send_targets - This directory contains the portals. - - .SH "SEE ALSO" -diff --git a/usr/idbm.c b/usr/idbm.c -index 634e547..4bb9810 100644 ---- a/usr/idbm.c -+++ b/usr/idbm.c -@@ -2721,9 +2721,9 @@ free_info: - int idbm_init(idbm_get_config_file_fn *fn) - { - /* make sure root db dir is there */ -- if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) { -- if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) { -- log_error("Could not make %s %d\n", ISCSI_CONFIG_ROOT, -+ if (access(ISCSIVAR, F_OK) != 0) { -+ if (mkdir(ISCSIVAR, 0660) != 0) { -+ log_error("Could not make %s %d\n", ISCSIVAR, - errno); - return errno; - } -diff --git a/usr/idbm.h b/usr/idbm.h -index 5e4038d..1e9b132 100644 ---- a/usr/idbm.h -+++ b/usr/idbm.h -@@ -29,12 +29,13 @@ - #include "list.h" - #include "flashnode.h" - --#define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" --#define SLP_CONFIG_DIR ISCSI_CONFIG_ROOT"slp" --#define ISNS_CONFIG_DIR ISCSI_CONFIG_ROOT"isns" --#define STATIC_CONFIG_DIR ISCSI_CONFIG_ROOT"static" --#define FW_CONFIG_DIR ISCSI_CONFIG_ROOT"fw" --#define ST_CONFIG_DIR ISCSI_CONFIG_ROOT"send_targets" -+#define ISCSIVAR "/var/lib/iscsi/" -+#define NODE_CONFIG_DIR ISCSIVAR"nodes" -+#define SLP_CONFIG_DIR ISCSIVAR"slp" -+#define ISNS_CONFIG_DIR ISCSIVAR"isns" -+#define STATIC_CONFIG_DIR ISCSIVAR"static" -+#define FW_CONFIG_DIR ISCSIVAR"fw" -+#define ST_CONFIG_DIR ISCSIVAR"send_targets" - #define ST_CONFIG_NAME "st_config" - #define ISNS_CONFIG_NAME "isns_config" - -diff --git a/usr/iface.h b/usr/iface.h -index 01f7074..f396918 100644 ---- a/usr/iface.h -+++ b/usr/iface.h -@@ -20,7 +20,9 @@ - #ifndef ISCSI_IFACE_H - #define ISCSI_IFACE_H - --#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" -+#include "idbm.h" -+ -+#define IFACE_CONFIG_DIR ISCSIVAR"ifaces" - - struct iface_rec; - struct list_head; --- -1.8.1.4 - diff --git a/0053-use-red-hat-for-name.patch b/0053-use-red-hat-for-name.patch deleted file mode 100644 index 8888200..0000000 --- a/0053-use-red-hat-for-name.patch +++ /dev/null @@ -1,25 +0,0 @@ -From bf7f9118ab2f1a5302dafa198d3351f6f977b7bd Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 19 Nov 2012 16:40:04 -0800 -Subject: use red hat for name - ---- - utils/iscsi-iname.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/utils/iscsi-iname.c b/utils/iscsi-iname.c -index 6347edc..cb2f6c8 100644 ---- a/utils/iscsi-iname.c -+++ b/utils/iscsi-iname.c -@@ -73,7 +73,7 @@ main(int argc, char *argv[]) - exit(0); - } - } else { -- prefix = "iqn.2005-03.org.open-iscsi"; -+ prefix = "iqn.1994-05.com.redhat"; - } - - /* try to feed some entropy from the pool to MD5 in order to get --- -1.7.11.7 - diff --git a/0054-add-libiscsi.patch b/0054-add-libiscsi.patch deleted file mode 100644 index e3d2324..0000000 --- a/0054-add-libiscsi.patch +++ /dev/null @@ -1,3927 +0,0 @@ -From 38800fb6984ca4c3ad963708c47c1946c33b6d1a Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 19 Nov 2012 16:43:15 -0800 -Subject: add libiscsi - ---- - Makefile | 2 + - libiscsi/Makefile | 61 ++ - libiscsi/libiscsi.c | 620 +++++++++++ - libiscsi/libiscsi.doxy | 1473 +++++++++++++++++++++++++++ - libiscsi/libiscsi.h | 344 +++++++ - libiscsi/pylibiscsi.c | 638 ++++++++++++ - libiscsi/setup.py | 9 + - libiscsi/tests/test_discovery_firmware.c | 53 + - libiscsi/tests/test_discovery_sendtargets.c | 60 ++ - libiscsi/tests/test_get_auth.c | 70 ++ - libiscsi/tests/test_get_initiator_name.c | 38 + - libiscsi/tests/test_get_network_config.c | 45 + - libiscsi/tests/test_login.c | 52 + - libiscsi/tests/test_logout.c | 51 + - libiscsi/tests/test_params.c | 103 ++ - libiscsi/tests/test_set_auth.c | 58 ++ - usr/Makefile | 2 +- - usr/discovery.c | 5 + - usr/idbm.c | 6 +- - usr/idbm.h | 3 + - usr/iscsi_ipc.h | 2 + - 21 files changed, 3691 insertions(+), 4 deletions(-) - create mode 100644 libiscsi/Makefile - create mode 100644 libiscsi/libiscsi.c - create mode 100644 libiscsi/libiscsi.doxy - create mode 100644 libiscsi/libiscsi.h - create mode 100644 libiscsi/pylibiscsi.c - create mode 100644 libiscsi/setup.py - create mode 100644 libiscsi/tests/test_discovery_firmware.c - create mode 100644 libiscsi/tests/test_discovery_sendtargets.c - create mode 100644 libiscsi/tests/test_get_auth.c - create mode 100644 libiscsi/tests/test_get_initiator_name.c - create mode 100644 libiscsi/tests/test_get_network_config.c - create mode 100644 libiscsi/tests/test_login.c - create mode 100644 libiscsi/tests/test_logout.c - create mode 100644 libiscsi/tests/test_params.c - create mode 100644 libiscsi/tests/test_set_auth.c - -diff --git a/Makefile b/Makefile -index 0b7bb98..02346bf 100644 ---- a/Makefile -+++ b/Makefile -@@ -33,6 +33,7 @@ user: utils/open-isns/Makefile iscsiuio/Makefile - $(MAKE) -C usr - $(MAKE) -C utils - $(MAKE) -C iscsiuio -+ $(MAKE) -C libiscsi - @echo - @echo "Compilation complete Output file" - @echo "----------------------------------- ----------------" -@@ -61,6 +62,7 @@ kernel: force - force: ; - - clean: -+ $(MAKE) -C libiscsi clean - $(MAKE) -C utils/sysdeps clean - $(MAKE) -C utils/fwparam_ibft clean - $(MAKE) -C utils clean -diff --git a/libiscsi/Makefile b/libiscsi/Makefile -new file mode 100644 -index 0000000..317a7ec ---- /dev/null -+++ b/libiscsi/Makefile -@@ -0,0 +1,61 @@ -+# This Makefile will work only with GNU make. -+ -+OSNAME=$(shell uname -s) -+OPTFLAGS ?= -O2 -g -+WARNFLAGS ?= -Wall -Wstrict-prototypes -+CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \ -+ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden -+LIB = libiscsi.so.0 -+TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware -+TESTS += tests/test_login tests/test_logout tests/test_params -+TESTS += tests/test_get_network_config tests/test_get_initiator_name -+TESTS += tests/test_set_auth tests/test_get_auth -+ -+COMMON_SRCS = sysdeps.o -+# sources shared between iscsid, iscsiadm and iscsistart -+ISCSI_LIB_SRCS = netlink.o transport.o cxgbi.o be2iscsi.o iscsi_timer.o initiator_common.o iscsi_err.o session_info.o iscsi_util.o io.o auth.o discovery.o login.o log.o md5.o sha1.o iface.o idbm.o sysfs.o iscsi_sysfs.o iscsi_net_util.o iscsid_req.o iser.o uip_mgmt_ipc.o -+FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sysfs.o -+ -+# sources shared with the userspace utils, note we build these separately -+# to get PIC versions. -+COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS)) -+USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o) -+FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS)) -+ -+# Flags for the tests -+tests/% : CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I. -+ -+all: lib tests html -+ -+lib: $(LIB) -+tests: $(TESTS) -+ -+common-objs/%.o: ../utils/sysdeps/%.c -+ mkdir -p common-objs -+ $(CC) $(CFLAGS) -c $< -o $@ -+ -+usr-objs/%.o: ../usr/%.c -+ mkdir -p usr-objs -+ $(CC) $(CFLAGS) -c $< -o $@ -+ -+fw-objs/%.o: ../utils/fwparam_ibft/%.c -+ mkdir -p fw-objs -+ $(CC) $(CFLAGS) -c $< -o $@ -+ -+$(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o -+ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ -+ ln -s -f $(LIB) libiscsi.so -+ -+$(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB) -+ -+html: libiscsi.h libiscsi.doxy -+ doxygen libiscsi.doxy -+ -+clean: -+ rm -rf *.o common-objs usr-objs fw-objs libuip-objs libiscsi.so* \ -+ .depend *~ html $(TESTS) tests/*~ -+ -+depend: -+ gcc $(CFLAGS) -M `ls *.c` > .depend -+ -+-include .depend ../usr/.depend -diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c -new file mode 100644 -index 0000000..2a176e8 ---- /dev/null -+++ b/libiscsi/libiscsi.c -@@ -0,0 +1,620 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libiscsi.h" -+#include "idbm.h" -+#include "discovery.h" -+#include "log.h" -+#include "sysfs.h" -+#include "iscsi_sysfs.h" -+#include "session_info.h" -+#include "iscsi_util.h" -+#include "sysdeps.h" -+#include "iface.h" -+#include "iscsi_proto.h" -+#include "fw_context.h" -+#include "iscsid_req.h" -+#include "iscsi_err.h" -+ -+#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; } -+ -+/* UGLY, not thread safe :( */ -+static int sysfs_initialized = 0; -+ -+struct libiscsi_context { -+ char error_str[256]; -+ /* For get_parameter_helper() */ -+ const char *parameter; -+ char *value; -+}; -+ -+static void libiscsi_log(int prio, void *priv, const char *fmt, va_list ap) -+{ -+ struct libiscsi_context *context = priv; -+ -+ if (prio > LOG_ERR) /* We are only interested in errors (or worse) */ -+ return; -+ -+ vsnprintf(context->error_str, sizeof(context->error_str), fmt, ap); -+} -+ -+struct libiscsi_context *libiscsi_init(void) -+{ -+ struct libiscsi_context *context; -+ -+ context = calloc(1, sizeof *context); -+ if (!context) -+ return NULL; -+ -+ log_init("libiscsi", 1024, libiscsi_log, context); -+ if (!sysfs_initialized) { -+ sysfs_init(); -+ sysfs_initialized = 1; -+ } -+ increase_max_files(); -+ if (idbm_init(NULL)) { -+ sysfs_cleanup(); -+ free(context); -+ return NULL; -+ } -+ -+ iface_setup_host_bindings(); -+ -+ return context; -+} -+ -+void libiscsi_cleanup(struct libiscsi_context *context) -+{ -+ idbm_terminate(); -+ free_transports(); -+ sysfs_cleanup(); -+ free(context); -+} -+ -+static void free_iface_list(struct list_head *ifaces) -+{ -+ struct iface_rec *iface, *tmp_iface; -+ -+ list_for_each_entry_safe(iface, tmp_iface, ifaces, list) { -+ list_del(&iface->list); -+ free(iface); -+ } -+} -+ -+static void free_rec_list(struct list_head *rec_list) -+{ -+ struct node_rec *rec, *tmp; -+ -+ list_for_each_entry_safe(rec, tmp, rec_list, list) { -+ list_del(&rec->list); -+ free(rec); -+ } -+} -+ -+int libiscsi_discover_sendtargets(struct libiscsi_context *context, -+ const char *address, int port, -+ const struct libiscsi_auth_info *auth_info, -+ int *nr_found, struct libiscsi_node **found_nodes) -+{ -+ struct discovery_rec drec; -+ LIST_HEAD(bound_rec_list); -+ struct node_rec *rec; -+ int rc = 0, found = 0; -+ -+ INIT_LIST_HEAD(&bound_rec_list); -+ -+ if (nr_found) -+ *nr_found = 0; -+ if (found_nodes) -+ *found_nodes = NULL; -+ -+ CHECK(libiscsi_verify_auth_info(context, auth_info)) -+ -+ /* Fill the drec struct with all needed info */ -+ memset(&drec, 0, sizeof drec); -+ idbm_sendtargets_defaults(&drec.u.sendtargets); -+ drec.type = DISCOVERY_TYPE_SENDTARGETS; -+ strlcpy(drec.address, address, sizeof(drec.address)); -+ drec.port = port ? port : ISCSI_LISTEN_PORT; -+ switch(auth_info ? auth_info->method : libiscsi_auth_none) { -+ case libiscsi_auth_chap: -+ drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP; -+ strlcpy(drec.u.sendtargets.auth.username, -+ auth_info->chap.username, AUTH_STR_MAX_LEN); -+ strlcpy((char *)drec.u.sendtargets.auth.password, -+ auth_info->chap.password, AUTH_STR_MAX_LEN); -+ drec.u.sendtargets.auth.password_length = -+ strlen((char *)drec.u.sendtargets.auth.password); -+ strlcpy(drec.u.sendtargets.auth.username_in, -+ auth_info->chap.reverse_username, AUTH_STR_MAX_LEN); -+ strlcpy((char *)drec.u.sendtargets.auth.password_in, -+ auth_info->chap.reverse_password, AUTH_STR_MAX_LEN); -+ drec.u.sendtargets.auth.password_in_length = -+ strlen((char *)drec.u.sendtargets.auth.password_in); -+ break; -+ } -+ -+ CHECK(idbm_add_discovery(&drec)) -+ -+ CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets, -+ &drec, NULL, &bound_rec_list)) -+ -+ /* now add/update records */ -+ list_for_each_entry(rec, &bound_rec_list, list) { -+ CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */)) -+ found++; -+ } -+ -+ if (nr_found) -+ *nr_found = found; -+ -+ if (found_nodes && found) { -+ *found_nodes = calloc(found, sizeof **found_nodes); -+ if (*found_nodes == NULL) { -+ snprintf(context->error_str, -+ sizeof(context->error_str), strerror(ENOMEM)); -+ rc = ENOMEM; -+ goto leave; -+ } -+ found = 0; -+ list_for_each_entry(rec, &bound_rec_list, list) { -+ strlcpy((*found_nodes)[found].name, rec->name, -+ LIBISCSI_VALUE_MAXLEN); -+ (*found_nodes)[found].tpgt = rec->tpgt; -+ strlcpy((*found_nodes)[found].address, -+ rec->conn[0].address, NI_MAXHOST); -+ (*found_nodes)[found].port = rec->conn[0].port; -+ strlcpy((*found_nodes)[found].iface, -+ rec->iface.name, LIBISCSI_VALUE_MAXLEN); -+ found++; -+ } -+ } -+ -+leave: -+ free_rec_list(&bound_rec_list); -+ return rc; -+} -+ -+int libiscsi_discover_firmware(struct libiscsi_context *context, -+ int *nr_found, struct libiscsi_node **found_nodes) -+{ -+ struct list_head targets, ifaces, rec_list; -+ discovery_rec_t drec; -+ int rc = 0; -+ -+ INIT_LIST_HEAD(&targets); -+ INIT_LIST_HEAD(&ifaces); -+ INIT_LIST_HEAD(&rec_list); -+ -+ if (nr_found) { -+ *nr_found = 0; -+ } -+ -+ if (found_nodes) { -+ *found_nodes = NULL; -+ } -+ -+ rc = fw_get_targets(&targets); -+ if (rc) { -+ log_error("%s: Could not get list of targets from firmware " -+ "(err %d).\n", __func__, rc); -+ return rc; -+ } -+ -+ CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets)); -+ -+ memset(&drec, 0, sizeof(drec)); -+ drec.type = DISCOVERY_TYPE_FW; -+ rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list); -+ if (rc) { -+ log_error("%s: Could not determine target nodes from firmware " -+ "(err %d).\n", __func__, rc); -+ goto leave; -+ } -+ -+ int node_count = 0; -+ struct list_head *pos; -+ list_for_each(pos, &rec_list) { -+ ++node_count; -+ } -+ -+ struct libiscsi_node* new_nodes; -+ /* allocate enough space for all the nodes */ -+ new_nodes = calloc(node_count, sizeof *new_nodes); -+ if (new_nodes == NULL) { -+ rc = ENOMEM; -+ log_error("%s: %s.\n", __func__, strerror(ENOMEM)); -+ goto leave; -+ } -+ -+ struct node_rec *rec; -+ struct libiscsi_node *new_node = new_nodes; -+ /* in one loop, add nodes to idbm and create libiscsi_node entries */ -+ list_for_each_entry(rec, &rec_list, list) { -+ CHECK(idbm_add_node(rec, NULL, 1 /* overwrite */)); -+ -+ strlcpy(new_node->name, rec->name, LIBISCSI_VALUE_MAXLEN); -+ new_node->tpgt = rec->tpgt; -+ strlcpy(new_node->address, rec->conn[0].address, NI_MAXHOST); -+ new_node->port = rec->conn[0].port; -+ strlcpy(new_node->iface, rec->iface.name, LIBISCSI_VALUE_MAXLEN); -+ -+ ++new_node; -+ } -+ -+ /* update output parameters */ -+ if (nr_found) { -+ *nr_found = node_count; -+ } -+ if (found_nodes) { -+ *found_nodes = new_nodes; -+ } -+ -+leave: -+ fw_free_targets(&targets); -+ -+ free_iface_list(&ifaces); -+ free_rec_list(&rec_list); -+ -+ return rc; -+} -+ -+int libiscsi_verify_auth_info(struct libiscsi_context *context, -+ const struct libiscsi_auth_info *auth_info) -+{ -+ switch(auth_info ? auth_info->method : libiscsi_auth_none) { -+ case libiscsi_auth_none: -+ break; -+ case libiscsi_auth_chap: -+ if (!auth_info->chap.username[0]) { -+ strcpy(context->error_str, "Empty username"); -+ return EINVAL; -+ } -+ if (!auth_info->chap.password[0]) { -+ strcpy(context->error_str, "Empty password"); -+ return EINVAL; -+ } -+ if (auth_info->chap.reverse_username[0] && -+ !auth_info->chap.reverse_password[0]) { -+ strcpy(context->error_str, "Empty reverse password"); -+ return EINVAL; -+ } -+ break; -+ default: -+ sprintf(context->error_str, -+ "Invalid authentication method: %d", -+ (int)auth_info->method); -+ return EINVAL; -+ } -+ return 0; -+} -+ -+int libiscsi_node_set_auth(struct libiscsi_context *context, -+ const struct libiscsi_node *node, -+ const struct libiscsi_auth_info *auth_info) -+{ -+ int rc = 0; -+ -+ CHECK(libiscsi_verify_auth_info(context, auth_info)) -+ -+ switch(auth_info ? auth_info->method : libiscsi_auth_none) { -+ case libiscsi_auth_none: -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.authmethod", "None")) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.username", "")) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.password", "")) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.username_in", "")) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.password_in", "")) -+ break; -+ -+ case libiscsi_auth_chap: -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.authmethod", "CHAP")) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.username", -+ auth_info->chap.username)) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.password", -+ auth_info->chap.password)) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.username_in", -+ auth_info->chap.reverse_username)) -+ CHECK(libiscsi_node_set_parameter(context, node, -+ "node.session.auth.password_in", -+ auth_info->chap.reverse_password)) -+ break; -+ } -+leave: -+ return rc; -+} -+ -+int libiscsi_node_get_auth(struct libiscsi_context *context, -+ const struct libiscsi_node *node, -+ struct libiscsi_auth_info *auth_info) -+{ -+ int rc = 0; -+ char value[LIBISCSI_VALUE_MAXLEN]; -+ -+ memset(auth_info, 0, sizeof *auth_info); -+ -+ CHECK(libiscsi_node_get_parameter(context, node, -+ "node.session.auth.authmethod", value)) -+ -+ if (!strcmp(value, "None")) { -+ auth_info->method = libiscsi_auth_none; -+ } else if (!strcmp(value, "CHAP")) { -+ auth_info->method = libiscsi_auth_chap; -+ CHECK(libiscsi_node_get_parameter(context, node, -+ "node.session.auth.username", -+ auth_info->chap.username)) -+ CHECK(libiscsi_node_get_parameter(context, node, -+ "node.session.auth.password", -+ auth_info->chap.password)) -+ CHECK(libiscsi_node_get_parameter(context, node, -+ "node.session.auth.username_in", -+ auth_info->chap.reverse_username)) -+ CHECK(libiscsi_node_get_parameter(context, node, -+ "node.session.auth.password_in", -+ auth_info->chap.reverse_password)) -+ } else { -+ snprintf(context->error_str, sizeof(context->error_str), -+ "unknown authentication method: %s", value); -+ rc = EINVAL; -+ } -+leave: -+ return rc; -+} -+ -+static void node_to_rec(const struct libiscsi_node *node, -+ struct node_rec *rec) -+{ -+ memset(rec, 0, sizeof *rec); -+ idbm_node_setup_defaults(rec); -+ strlcpy(rec->name, node->name, TARGET_NAME_MAXLEN); -+ rec->tpgt = node->tpgt; -+ strlcpy(rec->conn[0].address, node->address, NI_MAXHOST); -+ rec->conn[0].port = node->port; -+} -+ -+int login_helper(void *data, node_rec_t *rec) -+{ -+ char *iface = (char*)data; -+ if (strcmp(iface, rec->iface.name)) -+ /* different iface, skip it */ -+ return -1; -+ -+ int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec); -+ if (rc) { -+ iscsi_err_print_msg(rc); -+ rc = ENOTCONN; -+ } -+ return rc; -+} -+ -+int libiscsi_node_login(struct libiscsi_context *context, -+ const struct libiscsi_node *node) -+{ -+ int nr_found = 0, rc; -+ -+ CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper, -+ (char *)node->name, node->tpgt, -+ (char *)node->address, node->port)) -+ if (nr_found == 0) { -+ strcpy(context->error_str, "No such node"); -+ rc = ENODEV; -+ } -+leave: -+ return rc; -+} -+ -+static int logout_helper(void *data, struct session_info *info) -+{ -+ int rc; -+ struct node_rec *rec = data; -+ -+ if (!iscsi_match_session(rec, info)) -+ /* Tell iscsi_sysfs_for_each_session this session was not a -+ match so that it will not increase nr_found. */ -+ return -1; -+ -+ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid); -+ if (rc) { -+ iscsi_err_print_msg(rc); -+ rc = EIO; -+ } -+ -+ return rc; -+} -+ -+int libiscsi_node_logout(struct libiscsi_context *context, -+ const struct libiscsi_node *node) -+{ -+ int nr_found = 0, rc; -+ struct node_rec rec; -+ -+ node_to_rec(node, &rec); -+ CHECK(iscsi_sysfs_for_each_session(&rec, &nr_found, logout_helper,0)) -+ if (nr_found == 0) { -+ strcpy(context->error_str, "No matching session"); -+ rc = ENODEV; -+ } -+leave: -+ return rc; -+} -+ -+int libiscsi_node_set_parameter(struct libiscsi_context *context, -+ const struct libiscsi_node *node, -+ const char *parameter, const char *value) -+{ -+ int nr_found = 0, rc; -+ struct user_param *param; -+ struct list_head params; -+ -+ INIT_LIST_HEAD(¶ms); -+ param = idbm_alloc_user_param(parameter, value); -+ if (!param) { -+ rc = ENOMEM; -+ goto leave; -+ } -+ list_add_tail(¶ms, ¶m->list); -+ -+ CHECK(idbm_for_each_iface(&nr_found, ¶ms, idbm_node_set_param, -+ (char *)node->name, node->tpgt, -+ (char *)node->address, node->port)) -+ if (nr_found == 0) { -+ strcpy(context->error_str, "No such node"); -+ rc = ENODEV; -+ } -+ free(param->name); -+ free(param); -+leave: -+ return rc; -+} -+ -+static int get_parameter_helper(void *data, node_rec_t *rec) -+{ -+ struct libiscsi_context *context = data; -+ recinfo_t *info; -+ int i; -+ -+ info = idbm_recinfo_alloc(MAX_KEYS); -+ if (!info) { -+ snprintf(context->error_str, sizeof(context->error_str), -+ strerror(ENOMEM)); -+ return ENOMEM; -+ } -+ -+ idbm_recinfo_node(rec, info); -+ -+ for (i = 0; i < MAX_KEYS; i++) { -+ if (!info[i].visible) -+ continue; -+ -+ if (strcmp(context->parameter, info[i].name)) -+ continue; -+ -+ strlcpy(context->value, info[i].value, LIBISCSI_VALUE_MAXLEN); -+ break; -+ } -+ -+ free(info); -+ -+ if (i == MAX_KEYS) { -+ strcpy(context->error_str, "No such parameter"); -+ return EINVAL; -+ } -+ -+ return 0; -+} -+ -+int libiscsi_node_get_parameter(struct libiscsi_context *context, -+ const struct libiscsi_node *node, const char *parameter, char *value) -+{ -+ int nr_found = 0, rc = 0; -+ -+ context->parameter = parameter; -+ context->value = value; -+ -+ /* Note we assume there is only one interface, if not we will get -+ the value from the last interface iterated over! -+ This (multiple interfaces) can only happen if someone explicitly -+ created ones using iscsiadm. Even then this should not be a problem -+ as most settings should be the same independent of the iface. */ -+ CHECK(idbm_for_each_iface(&nr_found, context, get_parameter_helper, -+ (char *)node->name, node->tpgt, -+ (char *)node->address, node->port)) -+ if (nr_found == 0) { -+ strcpy(context->error_str, "No such node"); -+ rc = ENODEV; -+ } -+leave: -+ return rc; -+} -+ -+const char *libiscsi_get_error_string(struct libiscsi_context *context) -+{ -+ /* Sometimes the core open-iscsi code does not give us an error -+ message */ -+ if (!context->error_str[0]) -+ return "Unknown error"; -+ -+ return context->error_str; -+} -+ -+ -+/************************** Utility functions *******************************/ -+ -+int libiscsi_get_firmware_network_config( -+ struct libiscsi_network_config *config) -+{ -+ struct boot_context fw_entry; -+ -+ if (!sysfs_initialized) { -+ sysfs_init(); -+ sysfs_initialized = 1; -+ } -+ -+ memset(config, 0, sizeof *config); -+ memset(&fw_entry, 0, sizeof fw_entry); -+ if (fw_get_entry(&fw_entry)) -+ return ENODEV; -+ -+ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0; -+ strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface); -+ strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac); -+ strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr); -+ strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask); -+ strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway); -+ strncpy(config->primary_dns, fw_entry.primary_dns, -+ sizeof fw_entry.primary_dns); -+ strncpy(config->secondary_dns, fw_entry.secondary_dns, -+ sizeof fw_entry.secondary_dns); -+ return 0; -+} -+ -+int libiscsi_get_firmware_initiator_name(char *initiatorname) -+{ -+ struct boot_context fw_entry; -+ -+ if (!sysfs_initialized) { -+ sysfs_init(); -+ sysfs_initialized = 1; -+ } -+ -+ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN); -+ memset(&fw_entry, 0, sizeof fw_entry); -+ if (fw_get_entry(&fw_entry)) -+ return ENODEV; -+ -+ strncpy(initiatorname, fw_entry.initiatorname, -+ sizeof fw_entry.initiatorname); -+ -+ return 0; -+} -diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy -new file mode 100644 -index 0000000..663770f ---- /dev/null -+++ b/libiscsi/libiscsi.doxy -@@ -0,0 +1,1473 @@ -+# Doxyfile 1.5.7.1 -+ -+# This file describes the settings to be used by the documentation system -+# doxygen (www.doxygen.org) for a project -+# -+# All text after a hash (#) is considered a comment and will be ignored -+# The format is: -+# TAG = value [value, ...] -+# For lists items can also be appended using: -+# TAG += value [value, ...] -+# Values that contain spaces should be placed between quotes (" ") -+ -+#--------------------------------------------------------------------------- -+# Project related configuration options -+#--------------------------------------------------------------------------- -+ -+# This tag specifies the encoding used for all characters in the config file -+# that follow. The default is UTF-8 which is also the encoding used for all -+# text before the first occurrence of this tag. Doxygen uses libiconv (or the -+# iconv built into libc) for the transcoding. See -+# http://www.gnu.org/software/libiconv for the list of possible encodings. -+ -+DOXYFILE_ENCODING = UTF-8 -+ -+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -+# by quotes) that should identify the project. -+ -+PROJECT_NAME = libiscsi -+ -+# The PROJECT_NUMBER tag can be used to enter a project or revision number. -+# This could be handy for archiving the generated documentation or -+# if some version control system is used. -+ -+PROJECT_NUMBER = -+ -+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -+# base path where the generated documentation will be put. -+# If a relative path is entered, it will be relative to the location -+# where doxygen was started. If left blank the current directory will be used. -+ -+OUTPUT_DIRECTORY = -+ -+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -+# 4096 sub-directories (in 2 levels) under the output directory of each output -+# format and will distribute the generated files over these directories. -+# Enabling this option can be useful when feeding doxygen a huge amount of -+# source files, where putting all generated files in the same directory would -+# otherwise cause performance problems for the file system. -+ -+CREATE_SUBDIRS = NO -+ -+# The OUTPUT_LANGUAGE tag is used to specify the language in which all -+# documentation generated by doxygen is written. Doxygen will use this -+# information to generate all constant output in the proper language. -+# The default language is English, other supported languages are: -+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, -+# Spanish, Swedish, and Ukrainian. -+ -+OUTPUT_LANGUAGE = English -+ -+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -+# include brief member descriptions after the members that are listed in -+# the file and class documentation (similar to JavaDoc). -+# Set to NO to disable this. -+ -+BRIEF_MEMBER_DESC = YES -+ -+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -+# the brief description of a member or function before the detailed description. -+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -+# brief descriptions will be completely suppressed. -+ -+REPEAT_BRIEF = NO -+ -+# This tag implements a quasi-intelligent brief description abbreviator -+# that is used to form the text in various listings. Each string -+# in this list, if found as the leading text of the brief description, will be -+# stripped from the text and the result after processing the whole list, is -+# used as the annotated text. Otherwise, the brief description is used as-is. -+# If left blank, the following values are used ("$name" is automatically -+# replaced with the name of the entity): "The $name class" "The $name widget" -+# "The $name file" "is" "provides" "specifies" "contains" -+# "represents" "a" "an" "the" -+ -+ABBREVIATE_BRIEF = -+ -+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -+# Doxygen will generate a detailed section even if there is only a brief -+# description. -+ -+ALWAYS_DETAILED_SEC = YES -+ -+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -+# inherited members of a class in the documentation of that class as if those -+# members were ordinary class members. Constructors, destructors and assignment -+# operators of the base classes will not be shown. -+ -+INLINE_INHERITED_MEMB = NO -+ -+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -+# path before files name in the file list and in the header files. If set -+# to NO the shortest path that makes the file name unique will be used. -+ -+FULL_PATH_NAMES = YES -+ -+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -+# can be used to strip a user-defined part of the path. Stripping is -+# only done if one of the specified strings matches the left-hand part of -+# the path. The tag can be used to show relative paths in the file list. -+# If left blank the directory from which doxygen is run is used as the -+# path to strip. -+ -+STRIP_FROM_PATH = -+ -+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -+# the path mentioned in the documentation of a class, which tells -+# the reader which header file to include in order to use a class. -+# If left blank only the name of the header file containing the class -+# definition is used. Otherwise one should specify the include paths that -+# are normally passed to the compiler using the -I flag. -+ -+STRIP_FROM_INC_PATH = -+ -+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -+# (but less readable) file names. This can be useful is your file systems -+# doesn't support long names like on DOS, Mac, or CD-ROM. -+ -+SHORT_NAMES = NO -+ -+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -+# will interpret the first line (until the first dot) of a JavaDoc-style -+# comment as the brief description. If set to NO, the JavaDoc -+# comments will behave just like regular Qt-style comments -+# (thus requiring an explicit @brief command for a brief description.) -+ -+JAVADOC_AUTOBRIEF = NO -+ -+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -+# interpret the first line (until the first dot) of a Qt-style -+# comment as the brief description. If set to NO, the comments -+# will behave just like regular Qt-style comments (thus requiring -+# an explicit \brief command for a brief description.) -+ -+QT_AUTOBRIEF = NO -+ -+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -+# treat a multi-line C++ special comment block (i.e. a block of //! or /// -+# comments) as a brief description. This used to be the default behaviour. -+# The new default is to treat a multi-line C++ comment block as a detailed -+# description. Set this tag to YES if you prefer the old behaviour instead. -+ -+MULTILINE_CPP_IS_BRIEF = NO -+ -+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -+# member inherits the documentation from any documented member that it -+# re-implements. -+ -+INHERIT_DOCS = YES -+ -+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -+# a new page for each member. If set to NO, the documentation of a member will -+# be part of the file/class/namespace that contains it. -+ -+SEPARATE_MEMBER_PAGES = NO -+ -+# The TAB_SIZE tag can be used to set the number of spaces in a tab. -+# Doxygen uses this value to replace tabs by spaces in code fragments. -+ -+TAB_SIZE = 8 -+ -+# This tag can be used to specify a number of aliases that acts -+# as commands in the documentation. An alias has the form "name=value". -+# For example adding "sideeffect=\par Side Effects:\n" will allow you to -+# put the command \sideeffect (or @sideeffect) in the documentation, which -+# will result in a user-defined paragraph with heading "Side Effects:". -+# You can put \n's in the value part of an alias to insert newlines. -+ -+ALIASES = -+ -+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -+# sources only. Doxygen will then generate output that is more tailored for C. -+# For instance, some of the names that are used will be different. The list -+# of all members will be omitted, etc. -+ -+OPTIMIZE_OUTPUT_FOR_C = YES -+ -+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -+# sources only. Doxygen will then generate output that is more tailored for -+# Java. For instance, namespaces will be presented as packages, qualified -+# scopes will look different, etc. -+ -+OPTIMIZE_OUTPUT_JAVA = NO -+ -+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -+# sources only. Doxygen will then generate output that is more tailored for -+# Fortran. -+ -+OPTIMIZE_FOR_FORTRAN = NO -+ -+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -+# sources. Doxygen will then generate output that is tailored for -+# VHDL. -+ -+OPTIMIZE_OUTPUT_VHDL = NO -+ -+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -+# to include (a tag file for) the STL sources as input, then you should -+# set this tag to YES in order to let doxygen match functions declarations and -+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -+# func(std::string) {}). This also make the inheritance and collaboration -+# diagrams that involve STL classes more complete and accurate. -+ -+BUILTIN_STL_SUPPORT = NO -+ -+# If you use Microsoft's C++/CLI language, you should set this option to YES to -+# enable parsing support. -+ -+CPP_CLI_SUPPORT = NO -+ -+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -+# Doxygen will parse them like normal C++ but will assume all classes use public -+# instead of private inheritance when no explicit protection keyword is present. -+ -+SIP_SUPPORT = NO -+ -+# For Microsoft's IDL there are propget and propput attributes to indicate getter -+# and setter methods for a property. Setting this option to YES (the default) -+# will make doxygen to replace the get and set methods by a property in the -+# documentation. This will only work if the methods are indeed getting or -+# setting a simple type. If this is not the case, or you want to show the -+# methods anyway, you should set this option to NO. -+ -+IDL_PROPERTY_SUPPORT = YES -+ -+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -+# tag is set to YES, then doxygen will reuse the documentation of the first -+# member in the group (if any) for the other members of the group. By default -+# all members of a group must be documented explicitly. -+ -+DISTRIBUTE_GROUP_DOC = NO -+ -+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -+# the same type (for instance a group of public functions) to be put as a -+# subgroup of that type (e.g. under the Public Functions section). Set it to -+# NO to prevent subgrouping. Alternatively, this can be done per class using -+# the \nosubgrouping command. -+ -+SUBGROUPING = YES -+ -+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -+# is documented as struct, union, or enum with the name of the typedef. So -+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -+# with name TypeT. When disabled the typedef will appear as a member of a file, -+# namespace, or class. And the struct will be named TypeS. This can typically -+# be useful for C code in case the coding convention dictates that all compound -+# types are typedef'ed and only the typedef is referenced, never the tag name. -+ -+TYPEDEF_HIDES_STRUCT = NO -+ -+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -+# determine which symbols to keep in memory and which to flush to disk. -+# When the cache is full, less often used symbols will be written to disk. -+# For small to medium size projects (<1000 input files) the default value is -+# probably good enough. For larger projects a too small cache size can cause -+# doxygen to be busy swapping symbols to and from disk most of the time -+# causing a significant performance penality. -+# If the system has enough physical memory increasing the cache will improve the -+# performance by keeping more symbols in memory. Note that the value works on -+# a logarithmic scale so increasing the size by one will rougly double the -+# memory usage. The cache size is given by this formula: -+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -+# corresponding to a cache size of 2^16 = 65536 symbols -+ -+SYMBOL_CACHE_SIZE = 0 -+ -+#--------------------------------------------------------------------------- -+# Build related configuration options -+#--------------------------------------------------------------------------- -+ -+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -+# documentation are documented, even if no documentation was available. -+# Private class members and static file members will be hidden unless -+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES -+ -+EXTRACT_ALL = YES -+ -+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -+# will be included in the documentation. -+ -+EXTRACT_PRIVATE = NO -+ -+# If the EXTRACT_STATIC tag is set to YES all static members of a file -+# will be included in the documentation. -+ -+EXTRACT_STATIC = NO -+ -+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -+# defined locally in source files will be included in the documentation. -+# If set to NO only classes defined in header files are included. -+ -+EXTRACT_LOCAL_CLASSES = YES -+ -+# This flag is only useful for Objective-C code. When set to YES local -+# methods, which are defined in the implementation section but not in -+# the interface are included in the documentation. -+# If set to NO (the default) only methods in the interface are included. -+ -+EXTRACT_LOCAL_METHODS = NO -+ -+# If this flag is set to YES, the members of anonymous namespaces will be -+# extracted and appear in the documentation as a namespace called -+# 'anonymous_namespace{file}', where file will be replaced with the base -+# name of the file that contains the anonymous namespace. By default -+# anonymous namespace are hidden. -+ -+EXTRACT_ANON_NSPACES = NO -+ -+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -+# undocumented members of documented classes, files or namespaces. -+# If set to NO (the default) these members will be included in the -+# various overviews, but no documentation section is generated. -+# This option has no effect if EXTRACT_ALL is enabled. -+ -+HIDE_UNDOC_MEMBERS = NO -+ -+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -+# undocumented classes that are normally visible in the class hierarchy. -+# If set to NO (the default) these classes will be included in the various -+# overviews. This option has no effect if EXTRACT_ALL is enabled. -+ -+HIDE_UNDOC_CLASSES = NO -+ -+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -+# friend (class|struct|union) declarations. -+# If set to NO (the default) these declarations will be included in the -+# documentation. -+ -+HIDE_FRIEND_COMPOUNDS = NO -+ -+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -+# documentation blocks found inside the body of a function. -+# If set to NO (the default) these blocks will be appended to the -+# function's detailed documentation block. -+ -+HIDE_IN_BODY_DOCS = NO -+ -+# The INTERNAL_DOCS tag determines if documentation -+# that is typed after a \internal command is included. If the tag is set -+# to NO (the default) then the documentation will be excluded. -+# Set it to YES to include the internal documentation. -+ -+INTERNAL_DOCS = NO -+ -+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -+# file names in lower-case letters. If set to YES upper-case letters are also -+# allowed. This is useful if you have classes or files whose names only differ -+# in case and if your file system supports case sensitive file names. Windows -+# and Mac users are advised to set this option to NO. -+ -+CASE_SENSE_NAMES = YES -+ -+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -+# will show members with their full class and namespace scopes in the -+# documentation. If set to YES the scope will be hidden. -+ -+HIDE_SCOPE_NAMES = NO -+ -+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -+# will put a list of the files that are included by a file in the documentation -+# of that file. -+ -+SHOW_INCLUDE_FILES = YES -+ -+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -+# is inserted in the documentation for inline members. -+ -+INLINE_INFO = YES -+ -+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -+# will sort the (detailed) documentation of file and class members -+# alphabetically by member name. If set to NO the members will appear in -+# declaration order. -+ -+SORT_MEMBER_DOCS = YES -+ -+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -+# brief documentation of file, namespace and class members alphabetically -+# by member name. If set to NO (the default) the members will appear in -+# declaration order. -+ -+SORT_BRIEF_DOCS = NO -+ -+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -+# hierarchy of group names into alphabetical order. If set to NO (the default) -+# the group names will appear in their defined order. -+ -+SORT_GROUP_NAMES = NO -+ -+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -+# sorted by fully-qualified names, including namespaces. If set to -+# NO (the default), the class list will be sorted only by class name, -+# not including the namespace part. -+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -+# Note: This option applies only to the class list, not to the -+# alphabetical list. -+ -+SORT_BY_SCOPE_NAME = NO -+ -+# The GENERATE_TODOLIST tag can be used to enable (YES) or -+# disable (NO) the todo list. This list is created by putting \todo -+# commands in the documentation. -+ -+GENERATE_TODOLIST = YES -+ -+# The GENERATE_TESTLIST tag can be used to enable (YES) or -+# disable (NO) the test list. This list is created by putting \test -+# commands in the documentation. -+ -+GENERATE_TESTLIST = YES -+ -+# The GENERATE_BUGLIST tag can be used to enable (YES) or -+# disable (NO) the bug list. This list is created by putting \bug -+# commands in the documentation. -+ -+GENERATE_BUGLIST = YES -+ -+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -+# disable (NO) the deprecated list. This list is created by putting -+# \deprecated commands in the documentation. -+ -+GENERATE_DEPRECATEDLIST= YES -+ -+# The ENABLED_SECTIONS tag can be used to enable conditional -+# documentation sections, marked by \if sectionname ... \endif. -+ -+ENABLED_SECTIONS = -+ -+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -+# the initial value of a variable or define consists of for it to appear in -+# the documentation. If the initializer consists of more lines than specified -+# here it will be hidden. Use a value of 0 to hide initializers completely. -+# The appearance of the initializer of individual variables and defines in the -+# documentation can be controlled using \showinitializer or \hideinitializer -+# command in the documentation regardless of this setting. -+ -+MAX_INITIALIZER_LINES = 30 -+ -+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -+# at the bottom of the documentation of classes and structs. If set to YES the -+# list will mention the files that were used to generate the documentation. -+ -+SHOW_USED_FILES = YES -+ -+# If the sources in your project are distributed over multiple directories -+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -+# in the documentation. The default is NO. -+ -+SHOW_DIRECTORIES = NO -+ -+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -+# This will remove the Files entry from the Quick Index and from the -+# Folder Tree View (if specified). The default is YES. -+ -+SHOW_FILES = YES -+ -+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -+# Namespaces page. This will remove the Namespaces entry from the Quick Index -+# and from the Folder Tree View (if specified). The default is YES. -+ -+SHOW_NAMESPACES = YES -+ -+# The FILE_VERSION_FILTER tag can be used to specify a program or script that -+# doxygen should invoke to get the current version for each file (typically from -+# the version control system). Doxygen will invoke the program by executing (via -+# popen()) the command , where is the value of -+# the FILE_VERSION_FILTER tag, and is the name of an input file -+# provided by doxygen. Whatever the program writes to standard output -+# is used as the file version. See the manual for examples. -+ -+FILE_VERSION_FILTER = -+ -+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -+# doxygen. The layout file controls the global structure of the generated output files -+# in an output format independent way. The create the layout file that represents -+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -+# file name after the option, if omitted DoxygenLayout.xml will be used as the name -+# of the layout file. -+ -+LAYOUT_FILE = -+ -+#--------------------------------------------------------------------------- -+# configuration options related to warning and progress messages -+#--------------------------------------------------------------------------- -+ -+# The QUIET tag can be used to turn on/off the messages that are generated -+# by doxygen. Possible values are YES and NO. If left blank NO is used. -+ -+QUIET = YES -+ -+# The WARNINGS tag can be used to turn on/off the warning messages that are -+# generated by doxygen. Possible values are YES and NO. If left blank -+# NO is used. -+ -+WARNINGS = YES -+ -+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -+# automatically be disabled. -+ -+WARN_IF_UNDOCUMENTED = YES -+ -+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -+# potential errors in the documentation, such as not documenting some -+# parameters in a documented function, or documenting parameters that -+# don't exist or using markup commands wrongly. -+ -+WARN_IF_DOC_ERROR = YES -+ -+# This WARN_NO_PARAMDOC option can be abled to get warnings for -+# functions that are documented, but have no documentation for their parameters -+# or return value. If set to NO (the default) doxygen will only warn about -+# wrong or incomplete parameter documentation, but not about the absence of -+# documentation. -+ -+WARN_NO_PARAMDOC = NO -+ -+# The WARN_FORMAT tag determines the format of the warning messages that -+# doxygen can produce. The string should contain the $file, $line, and $text -+# tags, which will be replaced by the file and line number from which the -+# warning originated and the warning text. Optionally the format may contain -+# $version, which will be replaced by the version of the file (if it could -+# be obtained via FILE_VERSION_FILTER) -+ -+WARN_FORMAT = "$file:$line: $text" -+ -+# The WARN_LOGFILE tag can be used to specify a file to which warning -+# and error messages should be written. If left blank the output is written -+# to stderr. -+ -+WARN_LOGFILE = -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the input files -+#--------------------------------------------------------------------------- -+ -+# The INPUT tag can be used to specify the files and/or directories that contain -+# documented source files. You may enter file names like "myfile.cpp" or -+# directories like "/usr/src/myproject". Separate the files or directories -+# with spaces. -+ -+INPUT = -+ -+# This tag can be used to specify the character encoding of the source files -+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -+# also the default input encoding. Doxygen uses libiconv (or the iconv built -+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -+# the list of possible encodings. -+ -+INPUT_ENCODING = UTF-8 -+ -+# If the value of the INPUT tag contains directories, you can use the -+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -+# and *.h) to filter out the source-files in the directories. If left -+# blank the following patterns are tested: -+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 -+ -+FILE_PATTERNS = -+ -+# The RECURSIVE tag can be used to turn specify whether or not subdirectories -+# should be searched for input files as well. Possible values are YES and NO. -+# If left blank NO is used. -+ -+RECURSIVE = NO -+ -+# The EXCLUDE tag can be used to specify files and/or directories that should -+# excluded from the INPUT source files. This way you can easily exclude a -+# subdirectory from a directory tree whose root is specified with the INPUT tag. -+ -+EXCLUDE = -+ -+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -+# directories that are symbolic links (a Unix filesystem feature) are excluded -+# from the input. -+ -+EXCLUDE_SYMLINKS = NO -+ -+# If the value of the INPUT tag contains directories, you can use the -+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -+# certain files from those directories. Note that the wildcards are matched -+# against the file with absolute path, so to exclude all test directories -+# for example use the pattern */test/* -+ -+EXCLUDE_PATTERNS = -+ -+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -+# (namespaces, classes, functions, etc.) that should be excluded from the -+# output. The symbol name can be a fully qualified name, a word, or if the -+# wildcard * is used, a substring. Examples: ANamespace, AClass, -+# AClass::ANamespace, ANamespace::*Test -+ -+EXCLUDE_SYMBOLS = -+ -+# The EXAMPLE_PATH tag can be used to specify one or more files or -+# directories that contain example code fragments that are included (see -+# the \include command). -+ -+EXAMPLE_PATH = -+ -+# If the value of the EXAMPLE_PATH tag contains directories, you can use the -+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -+# and *.h) to filter out the source-files in the directories. If left -+# blank all files are included. -+ -+EXAMPLE_PATTERNS = -+ -+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -+# searched for input files to be used with the \include or \dontinclude -+# commands irrespective of the value of the RECURSIVE tag. -+# Possible values are YES and NO. If left blank NO is used. -+ -+EXAMPLE_RECURSIVE = NO -+ -+# The IMAGE_PATH tag can be used to specify one or more files or -+# directories that contain image that are included in the documentation (see -+# the \image command). -+ -+IMAGE_PATH = -+ -+# The INPUT_FILTER tag can be used to specify a program that doxygen should -+# invoke to filter for each input file. Doxygen will invoke the filter program -+# by executing (via popen()) the command , where -+# is the value of the INPUT_FILTER tag, and is the name of an -+# input file. Doxygen will then use the output that the filter program writes -+# to standard output. If FILTER_PATTERNS is specified, this tag will be -+# ignored. -+ -+INPUT_FILTER = -+ -+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -+# basis. Doxygen will compare the file name with each pattern and apply the -+# filter if there is a match. The filters are a list of the form: -+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -+# is applied to all files. -+ -+FILTER_PATTERNS = -+ -+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -+# INPUT_FILTER) will be used to filter the input files when producing source -+# files to browse (i.e. when SOURCE_BROWSER is set to YES). -+ -+FILTER_SOURCE_FILES = NO -+ -+#--------------------------------------------------------------------------- -+# configuration options related to source browsing -+#--------------------------------------------------------------------------- -+ -+# If the SOURCE_BROWSER tag is set to YES then a list of source files will -+# be generated. Documented entities will be cross-referenced with these sources. -+# Note: To get rid of all source code in the generated output, make sure also -+# VERBATIM_HEADERS is set to NO. -+ -+SOURCE_BROWSER = NO -+ -+# Setting the INLINE_SOURCES tag to YES will include the body -+# of functions and classes directly in the documentation. -+ -+INLINE_SOURCES = NO -+ -+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -+# doxygen to hide any special comment blocks from generated source code -+# fragments. Normal C and C++ comments will always remain visible. -+ -+STRIP_CODE_COMMENTS = YES -+ -+# If the REFERENCED_BY_RELATION tag is set to YES -+# then for each documented function all documented -+# functions referencing it will be listed. -+ -+REFERENCED_BY_RELATION = NO -+ -+# If the REFERENCES_RELATION tag is set to YES -+# then for each documented function all documented entities -+# called/used by that function will be listed. -+ -+REFERENCES_RELATION = NO -+ -+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -+# link to the source code. Otherwise they will link to the documentstion. -+ -+REFERENCES_LINK_SOURCE = YES -+ -+# If the USE_HTAGS tag is set to YES then the references to source code -+# will point to the HTML generated by the htags(1) tool instead of doxygen -+# built-in source browser. The htags tool is part of GNU's global source -+# tagging system (see http://www.gnu.org/software/global/global.html). You -+# will need version 4.8.6 or higher. -+ -+USE_HTAGS = NO -+ -+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -+# will generate a verbatim copy of the header file for each class for -+# which an include is specified. Set to NO to disable this. -+ -+VERBATIM_HEADERS = YES -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the alphabetical class index -+#--------------------------------------------------------------------------- -+ -+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -+# of all compounds will be generated. Enable this if the project -+# contains a lot of classes, structs, unions or interfaces. -+ -+ALPHABETICAL_INDEX = NO -+ -+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -+# in which this list will be split (can be a number in the range [1..20]) -+ -+COLS_IN_ALPHA_INDEX = 5 -+ -+# In case all classes in a project start with a common prefix, all -+# classes will be put under the same header in the alphabetical index. -+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -+# should be ignored while generating the index headers. -+ -+IGNORE_PREFIX = -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the HTML output -+#--------------------------------------------------------------------------- -+ -+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -+# generate HTML output. -+ -+GENERATE_HTML = YES -+ -+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -+# If a relative path is entered the value of OUTPUT_DIRECTORY will be -+# put in front of it. If left blank `html' will be used as the default path. -+ -+HTML_OUTPUT = html -+ -+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -+# doxygen will generate files with .html extension. -+ -+HTML_FILE_EXTENSION = .html -+ -+# The HTML_HEADER tag can be used to specify a personal HTML header for -+# each generated HTML page. If it is left blank doxygen will generate a -+# standard header. -+ -+HTML_HEADER = -+ -+# The HTML_FOOTER tag can be used to specify a personal HTML footer for -+# each generated HTML page. If it is left blank doxygen will generate a -+# standard footer. -+ -+HTML_FOOTER = -+ -+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -+# style sheet that is used by each HTML page. It can be used to -+# fine-tune the look of the HTML output. If the tag is left blank doxygen -+# will generate a default style sheet. Note that doxygen will try to copy -+# the style sheet file to the HTML output directory, so don't put your own -+# stylesheet in the HTML output directory as well, or it will be erased! -+ -+HTML_STYLESHEET = -+ -+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -+# files or namespaces will be aligned in HTML using tables. If set to -+# NO a bullet list will be used. -+ -+HTML_ALIGN_MEMBERS = YES -+ -+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -+# documentation will contain sections that can be hidden and shown after the -+# page has loaded. For this to work a browser that supports -+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). -+ -+HTML_DYNAMIC_SECTIONS = NO -+ -+# If the GENERATE_DOCSET tag is set to YES, additional index files -+# will be generated that can be used as input for Apple's Xcode 3 -+# integrated development environment, introduced with OSX 10.5 (Leopard). -+# To create a documentation set, doxygen will generate a Makefile in the -+# HTML output directory. Running make will produce the docset in that -+# directory and running "make install" will install the docset in -+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -+# it at startup. -+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. -+ -+GENERATE_DOCSET = NO -+ -+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -+# feed. A documentation feed provides an umbrella under which multiple -+# documentation sets from a single provider (such as a company or product suite) -+# can be grouped. -+ -+DOCSET_FEEDNAME = "Doxygen generated docs" -+ -+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -+# should uniquely identify the documentation set bundle. This should be a -+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -+# will append .docset to the name. -+ -+DOCSET_BUNDLE_ID = org.doxygen.Project -+ -+# If the GENERATE_HTMLHELP tag is set to YES, additional index files -+# will be generated that can be used as input for tools like the -+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -+# of the generated HTML documentation. -+ -+GENERATE_HTMLHELP = NO -+ -+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -+# be used to specify the file name of the resulting .chm file. You -+# can add a path in front of the file if the result should not be -+# written to the html output directory. -+ -+CHM_FILE = -+ -+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -+# be used to specify the location (absolute path including file name) of -+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -+# the HTML help compiler on the generated index.hhp. -+ -+HHC_LOCATION = -+ -+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -+# controls if a separate .chi index file is generated (YES) or that -+# it should be included in the master .chm file (NO). -+ -+GENERATE_CHI = NO -+ -+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -+# is used to encode HtmlHelp index (hhk), content (hhc) and project file -+# content. -+ -+CHM_INDEX_ENCODING = -+ -+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -+# controls whether a binary table of contents is generated (YES) or a -+# normal table of contents (NO) in the .chm file. -+ -+BINARY_TOC = NO -+ -+# The TOC_EXPAND flag can be set to YES to add extra items for group members -+# to the contents of the HTML help documentation and to the tree view. -+ -+TOC_EXPAND = NO -+ -+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -+# are set, an additional index file will be generated that can be used as input for -+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -+# HTML documentation. -+ -+GENERATE_QHP = NO -+ -+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -+# be used to specify the file name of the resulting .qch file. -+# The path specified is relative to the HTML output folder. -+ -+QCH_FILE = -+ -+# The QHP_NAMESPACE tag specifies the namespace to use when generating -+# Qt Help Project output. For more information please see -+# Qt Help Project / Namespace. -+ -+QHP_NAMESPACE = org.doxygen.Project -+ -+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -+# Qt Help Project output. For more information please see -+# Qt Help Project / Virtual Folders. -+ -+QHP_VIRTUAL_FOLDER = doc -+ -+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -+# be used to specify the location of Qt's qhelpgenerator. -+# If non-empty doxygen will try to run qhelpgenerator on the generated -+# .qhp file . -+ -+QHG_LOCATION = -+ -+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -+# top of each HTML page. The value NO (the default) enables the index and -+# the value YES disables it. -+ -+DISABLE_INDEX = NO -+ -+# This tag can be used to set the number of enum values (range [1..20]) -+# that doxygen will group on one line in the generated HTML documentation. -+ -+ENUM_VALUES_PER_LINE = 4 -+ -+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -+# structure should be generated to display hierarchical information. -+# If the tag value is set to FRAME, a side panel will be generated -+# containing a tree-like index structure (just like the one that -+# is generated for HTML Help). For this to work a browser that supports -+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -+# probably better off using the HTML help feature. Other possible values -+# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -+# and Class Hierarchy pages using a tree view instead of an ordered list; -+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -+# disables this behavior completely. For backwards compatibility with previous -+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -+# respectively. -+ -+GENERATE_TREEVIEW = NONE -+ -+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -+# used to set the initial width (in pixels) of the frame in which the tree -+# is shown. -+ -+TREEVIEW_WIDTH = 250 -+ -+# Use this tag to change the font size of Latex formulas included -+# as images in the HTML documentation. The default is 10. Note that -+# when you change the font size after a successful doxygen run you need -+# to manually remove any form_*.png images from the HTML output directory -+# to force them to be regenerated. -+ -+FORMULA_FONTSIZE = 10 -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the LaTeX output -+#--------------------------------------------------------------------------- -+ -+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -+# generate Latex output. -+ -+GENERATE_LATEX = NO -+ -+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -+# If a relative path is entered the value of OUTPUT_DIRECTORY will be -+# put in front of it. If left blank `latex' will be used as the default path. -+ -+LATEX_OUTPUT = latex -+ -+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -+# invoked. If left blank `latex' will be used as the default command name. -+ -+LATEX_CMD_NAME = latex -+ -+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -+# generate index for LaTeX. If left blank `makeindex' will be used as the -+# default command name. -+ -+MAKEINDEX_CMD_NAME = makeindex -+ -+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -+# LaTeX documents. This may be useful for small projects and may help to -+# save some trees in general. -+ -+COMPACT_LATEX = NO -+ -+# The PAPER_TYPE tag can be used to set the paper type that is used -+# by the printer. Possible values are: a4, a4wide, letter, legal and -+# executive. If left blank a4wide will be used. -+ -+PAPER_TYPE = a4wide -+ -+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -+# packages that should be included in the LaTeX output. -+ -+EXTRA_PACKAGES = -+ -+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -+# the generated latex document. The header should contain everything until -+# the first chapter. If it is left blank doxygen will generate a -+# standard header. Notice: only use this tag if you know what you are doing! -+ -+LATEX_HEADER = -+ -+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -+# is prepared for conversion to pdf (using ps2pdf). The pdf file will -+# contain links (just like the HTML output) instead of page references -+# This makes the output suitable for online browsing using a pdf viewer. -+ -+PDF_HYPERLINKS = YES -+ -+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -+# plain latex in the generated Makefile. Set this option to YES to get a -+# higher quality PDF documentation. -+ -+USE_PDFLATEX = YES -+ -+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -+# command to the generated LaTeX files. This will instruct LaTeX to keep -+# running if errors occur, instead of asking the user for help. -+# This option is also used when generating formulas in HTML. -+ -+LATEX_BATCHMODE = NO -+ -+# If LATEX_HIDE_INDICES is set to YES then doxygen will not -+# include the index chapters (such as File Index, Compound Index, etc.) -+# in the output. -+ -+LATEX_HIDE_INDICES = NO -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the RTF output -+#--------------------------------------------------------------------------- -+ -+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -+# The RTF output is optimized for Word 97 and may not look very pretty with -+# other RTF readers or editors. -+ -+GENERATE_RTF = NO -+ -+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -+# If a relative path is entered the value of OUTPUT_DIRECTORY will be -+# put in front of it. If left blank `rtf' will be used as the default path. -+ -+RTF_OUTPUT = rtf -+ -+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -+# RTF documents. This may be useful for small projects and may help to -+# save some trees in general. -+ -+COMPACT_RTF = NO -+ -+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -+# will contain hyperlink fields. The RTF file will -+# contain links (just like the HTML output) instead of page references. -+# This makes the output suitable for online browsing using WORD or other -+# programs which support those fields. -+# Note: wordpad (write) and others do not support links. -+ -+RTF_HYPERLINKS = NO -+ -+# Load stylesheet definitions from file. Syntax is similar to doxygen's -+# config file, i.e. a series of assignments. You only have to provide -+# replacements, missing definitions are set to their default value. -+ -+RTF_STYLESHEET_FILE = -+ -+# Set optional variables used in the generation of an rtf document. -+# Syntax is similar to doxygen's config file. -+ -+RTF_EXTENSIONS_FILE = -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the man page output -+#--------------------------------------------------------------------------- -+ -+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -+# generate man pages -+ -+GENERATE_MAN = NO -+ -+# The MAN_OUTPUT tag is used to specify where the man pages will be put. -+# If a relative path is entered the value of OUTPUT_DIRECTORY will be -+# put in front of it. If left blank `man' will be used as the default path. -+ -+MAN_OUTPUT = man -+ -+# The MAN_EXTENSION tag determines the extension that is added to -+# the generated man pages (default is the subroutine's section .3) -+ -+MAN_EXTENSION = .3 -+ -+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -+# then it will generate one additional man file for each entity -+# documented in the real man page(s). These additional files -+# only source the real man page, but without them the man command -+# would be unable to find the correct page. The default is NO. -+ -+MAN_LINKS = NO -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the XML output -+#--------------------------------------------------------------------------- -+ -+# If the GENERATE_XML tag is set to YES Doxygen will -+# generate an XML file that captures the structure of -+# the code including all documentation. -+ -+GENERATE_XML = NO -+ -+# The XML_OUTPUT tag is used to specify where the XML pages will be put. -+# If a relative path is entered the value of OUTPUT_DIRECTORY will be -+# put in front of it. If left blank `xml' will be used as the default path. -+ -+XML_OUTPUT = xml -+ -+# The XML_SCHEMA tag can be used to specify an XML schema, -+# which can be used by a validating XML parser to check the -+# syntax of the XML files. -+ -+XML_SCHEMA = -+ -+# The XML_DTD tag can be used to specify an XML DTD, -+# which can be used by a validating XML parser to check the -+# syntax of the XML files. -+ -+XML_DTD = -+ -+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -+# dump the program listings (including syntax highlighting -+# and cross-referencing information) to the XML output. Note that -+# enabling this will significantly increase the size of the XML output. -+ -+XML_PROGRAMLISTING = YES -+ -+#--------------------------------------------------------------------------- -+# configuration options for the AutoGen Definitions output -+#--------------------------------------------------------------------------- -+ -+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -+# generate an AutoGen Definitions (see autogen.sf.net) file -+# that captures the structure of the code including all -+# documentation. Note that this feature is still experimental -+# and incomplete at the moment. -+ -+GENERATE_AUTOGEN_DEF = NO -+ -+#--------------------------------------------------------------------------- -+# configuration options related to the Perl module output -+#--------------------------------------------------------------------------- -+ -+# If the GENERATE_PERLMOD tag is set to YES Doxygen will -+# generate a Perl module file that captures the structure of -+# the code including all documentation. Note that this -+# feature is still experimental and incomplete at the -+# moment. -+ -+GENERATE_PERLMOD = NO -+ -+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -+# the necessary Makefile rules, Perl scripts and LaTeX code to be able -+# to generate PDF and DVI output from the Perl module output. -+ -+PERLMOD_LATEX = NO -+ -+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -+# nicely formatted so it can be parsed by a human reader. This is useful -+# if you want to understand what is going on. On the other hand, if this -+# tag is set to NO the size of the Perl module output will be much smaller -+# and Perl will parse it just the same. -+ -+PERLMOD_PRETTY = YES -+ -+# The names of the make variables in the generated doxyrules.make file -+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -+# This is useful so different doxyrules.make files included by the same -+# Makefile don't overwrite each other's variables. -+ -+PERLMOD_MAKEVAR_PREFIX = -+ -+#--------------------------------------------------------------------------- -+# Configuration options related to the preprocessor -+#--------------------------------------------------------------------------- -+ -+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -+# evaluate all C-preprocessor directives found in the sources and include -+# files. -+ -+ENABLE_PREPROCESSING = YES -+ -+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -+# names in the source code. If set to NO (the default) only conditional -+# compilation will be performed. Macro expansion can be done in a controlled -+# way by setting EXPAND_ONLY_PREDEF to YES. -+ -+MACRO_EXPANSION = NO -+ -+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -+# then the macro expansion is limited to the macros specified with the -+# PREDEFINED and EXPAND_AS_DEFINED tags. -+ -+EXPAND_ONLY_PREDEF = NO -+ -+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -+# in the INCLUDE_PATH (see below) will be search if a #include is found. -+ -+SEARCH_INCLUDES = YES -+ -+# The INCLUDE_PATH tag can be used to specify one or more directories that -+# contain include files that are not input files but should be processed by -+# the preprocessor. -+ -+INCLUDE_PATH = -+ -+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -+# patterns (like *.h and *.hpp) to filter out the header-files in the -+# directories. If left blank, the patterns specified with FILE_PATTERNS will -+# be used. -+ -+INCLUDE_FILE_PATTERNS = -+ -+# The PREDEFINED tag can be used to specify one or more macro names that -+# are defined before the preprocessor is started (similar to the -D option of -+# gcc). The argument of the tag is a list of macros of the form: name -+# or name=definition (no spaces). If the definition and the = are -+# omitted =1 is assumed. To prevent a macro definition from being -+# undefined via #undef or recursively expanded use the := operator -+# instead of the = operator. -+ -+PREDEFINED = -+ -+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -+# this tag can be used to specify a list of macro names that should be expanded. -+# The macro definition that is found in the sources will be used. -+# Use the PREDEFINED tag if you want to use a different macro definition. -+ -+EXPAND_AS_DEFINED = -+ -+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -+# doxygen's preprocessor will remove all function-like macros that are alone -+# on a line, have an all uppercase name, and do not end with a semicolon. Such -+# function macros are typically used for boiler-plate code, and will confuse -+# the parser if not removed. -+ -+SKIP_FUNCTION_MACROS = YES -+ -+#--------------------------------------------------------------------------- -+# Configuration::additions related to external references -+#--------------------------------------------------------------------------- -+ -+# The TAGFILES option can be used to specify one or more tagfiles. -+# Optionally an initial location of the external documentation -+# can be added for each tagfile. The format of a tag file without -+# this location is as follows: -+# TAGFILES = file1 file2 ... -+# Adding location for the tag files is done as follows: -+# TAGFILES = file1=loc1 "file2 = loc2" ... -+# where "loc1" and "loc2" can be relative or absolute paths or -+# URLs. If a location is present for each tag, the installdox tool -+# does not have to be run to correct the links. -+# Note that each tag file must have a unique name -+# (where the name does NOT include the path) -+# If a tag file is not located in the directory in which doxygen -+# is run, you must also specify the path to the tagfile here. -+ -+TAGFILES = -+ -+# When a file name is specified after GENERATE_TAGFILE, doxygen will create -+# a tag file that is based on the input files it reads. -+ -+GENERATE_TAGFILE = -+ -+# If the ALLEXTERNALS tag is set to YES all external classes will be listed -+# in the class index. If set to NO only the inherited external classes -+# will be listed. -+ -+ALLEXTERNALS = NO -+ -+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -+# in the modules index. If set to NO, only the current project's groups will -+# be listed. -+ -+EXTERNAL_GROUPS = YES -+ -+# The PERL_PATH should be the absolute path and name of the perl script -+# interpreter (i.e. the result of `which perl'). -+ -+PERL_PATH = /usr/bin/perl -+ -+#--------------------------------------------------------------------------- -+# Configuration options related to the dot tool -+#--------------------------------------------------------------------------- -+ -+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -+# or super classes. Setting the tag to NO turns the diagrams off. Note that -+# this option is superseded by the HAVE_DOT option below. This is only a -+# fallback. It is recommended to install and use dot, since it yields more -+# powerful graphs. -+ -+CLASS_DIAGRAMS = YES -+ -+# You can define message sequence charts within doxygen comments using the \msc -+# command. Doxygen will then run the mscgen tool (see -+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -+# documentation. The MSCGEN_PATH tag allows you to specify the directory where -+# the mscgen tool resides. If left empty the tool is assumed to be found in the -+# default search path. -+ -+MSCGEN_PATH = -+ -+# If set to YES, the inheritance and collaboration graphs will hide -+# inheritance and usage relations if the target is undocumented -+# or is not a class. -+ -+HIDE_UNDOC_RELATIONS = YES -+ -+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -+# available from the path. This tool is part of Graphviz, a graph visualization -+# toolkit from AT&T and Lucent Bell Labs. The other options in this section -+# have no effect if this option is set to NO (the default) -+ -+HAVE_DOT = NO -+ -+# By default doxygen will write a font called FreeSans.ttf to the output -+# directory and reference it in all dot files that doxygen generates. This -+# font does not include all possible unicode characters however, so when you need -+# these (or just want a differently looking font) you can specify the font name -+# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -+# which can be done by putting it in a standard location or by setting the -+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -+# containing the font. -+ -+DOT_FONTNAME = FreeSans -+ -+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -+# The default size is 10pt. -+ -+DOT_FONTSIZE = 10 -+ -+# By default doxygen will tell dot to use the output directory to look for the -+# FreeSans.ttf font (which doxygen will put there itself). If you specify a -+# different font using DOT_FONTNAME you can set the path where dot -+# can find it using this tag. -+ -+DOT_FONTPATH = -+ -+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -+# will generate a graph for each documented class showing the direct and -+# indirect inheritance relations. Setting this tag to YES will force the -+# the CLASS_DIAGRAMS tag to NO. -+ -+CLASS_GRAPH = YES -+ -+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -+# will generate a graph for each documented class showing the direct and -+# indirect implementation dependencies (inheritance, containment, and -+# class references variables) of the class with other documented classes. -+ -+COLLABORATION_GRAPH = YES -+ -+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -+# will generate a graph for groups, showing the direct groups dependencies -+ -+GROUP_GRAPHS = YES -+ -+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -+# collaboration diagrams in a style similar to the OMG's Unified Modeling -+# Language. -+ -+UML_LOOK = NO -+ -+# If set to YES, the inheritance and collaboration graphs will show the -+# relations between templates and their instances. -+ -+TEMPLATE_RELATIONS = NO -+ -+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -+# tags are set to YES then doxygen will generate a graph for each documented -+# file showing the direct and indirect include dependencies of the file with -+# other documented files. -+ -+INCLUDE_GRAPH = YES -+ -+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -+# documented header file showing the documented files that directly or -+# indirectly include this file. -+ -+INCLUDED_BY_GRAPH = YES -+ -+# If the CALL_GRAPH and HAVE_DOT options are set to YES then -+# doxygen will generate a call dependency graph for every global function -+# or class method. Note that enabling this option will significantly increase -+# the time of a run. So in most cases it will be better to enable call graphs -+# for selected functions only using the \callgraph command. -+ -+CALL_GRAPH = NO -+ -+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -+# doxygen will generate a caller dependency graph for every global function -+# or class method. Note that enabling this option will significantly increase -+# the time of a run. So in most cases it will be better to enable caller -+# graphs for selected functions only using the \callergraph command. -+ -+CALLER_GRAPH = NO -+ -+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -+# will graphical hierarchy of all classes instead of a textual one. -+ -+GRAPHICAL_HIERARCHY = YES -+ -+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -+# then doxygen will show the dependencies a directory has on other directories -+# in a graphical way. The dependency relations are determined by the #include -+# relations between the files in the directories. -+ -+DIRECTORY_GRAPH = YES -+ -+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -+# generated by dot. Possible values are png, jpg, or gif -+# If left blank png will be used. -+ -+DOT_IMAGE_FORMAT = png -+ -+# The tag DOT_PATH can be used to specify the path where the dot tool can be -+# found. If left blank, it is assumed the dot tool can be found in the path. -+ -+DOT_PATH = -+ -+# The DOTFILE_DIRS tag can be used to specify one or more directories that -+# contain dot files that are included in the documentation (see the -+# \dotfile command). -+ -+DOTFILE_DIRS = -+ -+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -+# nodes that will be shown in the graph. If the number of nodes in a graph -+# becomes larger than this value, doxygen will truncate the graph, which is -+# visualized by representing a node as a red box. Note that doxygen if the -+# number of direct children of the root node in a graph is already larger than -+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. -+ -+DOT_GRAPH_MAX_NODES = 50 -+ -+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -+# graphs generated by dot. A depth value of 3 means that only nodes reachable -+# from the root by following a path via at most 3 edges will be shown. Nodes -+# that lay further from the root node will be omitted. Note that setting this -+# option to 1 or 2 may greatly reduce the computation time needed for large -+# code bases. Also note that the size of a graph can be further restricted by -+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. -+ -+MAX_DOT_GRAPH_DEPTH = 0 -+ -+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -+# background. This is disabled by default, because dot on Windows does not -+# seem to support this out of the box. Warning: Depending on the platform used, -+# enabling this option may lead to badly anti-aliased labels on the edges of -+# a graph (i.e. they become hard to read). -+ -+DOT_TRANSPARENT = NO -+ -+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -+# files in one run (i.e. multiple -o and -T options on the command line). This -+# makes dot run faster, but since only newer versions of dot (>1.8.10) -+# support this, this feature is disabled by default. -+ -+DOT_MULTI_TARGETS = NO -+ -+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -+# generate a legend page explaining the meaning of the various boxes and -+# arrows in the dot generated graphs. -+ -+GENERATE_LEGEND = YES -+ -+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -+# remove the intermediate dot files that are used to generate -+# the various graphs. -+ -+DOT_CLEANUP = YES -+ -+#--------------------------------------------------------------------------- -+# Configuration::additions related to the search engine -+#--------------------------------------------------------------------------- -+ -+# The SEARCHENGINE tag specifies whether or not a search engine should be -+# used. If set to NO the values of all tags below this one will be ignored. -+ -+SEARCHENGINE = NO -diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h -new file mode 100644 -index 0000000..756590e ---- /dev/null -+++ b/libiscsi/libiscsi.h -@@ -0,0 +1,344 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#ifndef __LIBISCSI_H -+#define __LIBISCSI_H -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif /* __cplusplus */ -+ -+#if __GNUC__ >= 4 -+#define PUBLIC __attribute__ ((visibility("default"))) -+#else -+#define PUBLIC -+#endif -+ -+/** \brief Maximum length for iSCSI values. -+ * -+ * Maximum length for iSCSI values such as hostnames and parameter values. -+ */ -+#define LIBISCSI_VALUE_MAXLEN 256 -+ -+/** \brief supported authentication methods -+ * -+ * This enum lists all supported authentication methods. -+ */ -+enum libiscsi_auth_t { -+ libiscsi_auth_none /** No authentication */, -+ libiscsi_auth_chap /** CHAP authentication */, -+}; -+ -+/** \brief libiscsi context struct -+ * -+ * Note: even though libiscsi uses a context struct, the underlying open-iscsi -+ * code does not, so libiscsi is not thread safe, not even when using one -+ * context per thread! -+ */ -+struct libiscsi_context; -+ -+/** \brief iSCSI node record -+ * -+ * Struct holding data uniquely identifying an iSCSI node. -+ */ -+struct libiscsi_node { -+ char name[LIBISCSI_VALUE_MAXLEN] /** iSCSI iqn for the node. */; -+ int tpgt /** Portal group number. */; -+ /* Note open-iscsi has some code in place for multiple connections in one -+ node record and thus multiple address / port combi's, but this does not -+ get used anywhere, so we keep things simple and assume one connection */ -+ char address[NI_MAXHOST] /** Portal hostname or IP-address. */; -+ int port /** Portal port number. */; -+ char iface[LIBISCSI_VALUE_MAXLEN] /** Interface to connect through. */; -+}; -+ -+/** \brief libiscsi CHAP authentication information struct -+ * -+ * Struct holding all data needed for CHAP login / authentication. Note that -+ * \e reverse_username may be a 0 length string in which case only forward -+ * authentication will be done. -+ */ -+struct libiscsi_chap_auth_info { -+ char username[LIBISCSI_VALUE_MAXLEN] /** Username */; -+ char password[LIBISCSI_VALUE_MAXLEN] /** Password */; -+ char reverse_username[LIBISCSI_VALUE_MAXLEN] /** Reverse Username */; -+ char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */; -+}; -+ -+/** \brief generic libiscsi authentication information struct -+ * -+ * Struct holding authentication information for discovery and login. -+ */ -+struct libiscsi_auth_info { -+ enum libiscsi_auth_t method /** Authentication method to use */; -+ union { -+ struct libiscsi_chap_auth_info chap /** Chap specific info */; -+ } /** Union holding method depenend info */; -+}; -+ -+/** \brief Initalize libiscsi -+ * -+ * This function creates a libiscsi context and initalizes it. This context -+ * is need to use other libiscsi funtions. -+ * -+ * \return A pointer to the created context, or NULL in case of an error. -+ */ -+PUBLIC struct libiscsi_context *libiscsi_init(void); -+ -+/** \brief Cleanup libiscsi used resource -+ * -+ * This function cleanups any used resources and then destroys the passed -+ * context. After this the passed in context may no longer be used! -+ * -+ * \param context libiscsi context to operate on. -+ */ -+PUBLIC void libiscsi_cleanup(struct libiscsi_context *context); -+ -+/** \brief Discover iSCSI nodes using sendtargets and add them to the node db. -+ * -+ * This function connects to the given address and port and then tries to -+ * discover iSCSI nodes using the sendtargets protocol. Any found nodes are -+ * added to the local iSCSI node database and are returned in a dynamically -+ * allocated array. -+ * -+ * Note that the (optional) authentication info is for authenticating the -+ * discovery, and is not for the found nodes! If the connection(s) to the -+ * node(s) need authentication too, you can set the username / password for -+ * those (which can be different!) using the libiscsi_node_set_auth() function. -+ * -+ * \param context libiscsi context to operate on. -+ * \param address Hostname or IP-address to connect to. -+ * \param port Port to connect to, or 0 for the default port. -+ * \param auth_info Authentication information, or NULL. -+ * \param nr_found The number of found nodes will be returned -+ * through this pointer if not NULL. -+ * \param found_nodes The address of the dynamically allocated array -+ * of found nodes will be returned through this -+ * pointer if not NULL. The caller must free this -+ * array using free(). -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context, -+ const char *address, int port, const struct libiscsi_auth_info *auth_info, -+ int *nr_found, struct libiscsi_node **found_nodes); -+ -+/** \brief Read iSCSI node info from firmware and add them to the node db. -+ * -+ * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found -+ * nodes are added to the local iSCSI node database and are returned in a -+ * dynamically allocated array. -+ * -+ * Note that unlike sendtargets discovery, this function will also read -+ * authentication info and store that in the database too. -+ * -+ * Note this function currently is a stub which will always return -EINVAL -+ * (IOW it is not yet implemented) -+ * -+ * \param context libiscsi context to operate on. -+ * \param nr_found The number of found nodes will be returned -+ * through this pointer if not NULL. -+ * \param found_nodes The address of the dynamically allocated array -+ * of found nodes will be returned through this -+ * pointer if not NULL. The caller must free this -+ * array using free(). -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_discover_firmware(struct libiscsi_context *context, -+ int *nr_found, struct libiscsi_node **found_nodes); -+ -+/** \brief Check validity of the given authentication info. -+ * -+ * This function checks the validity of the given authentication info. For -+ * example in case of CHAP, if the username and password are not empty. -+ * -+ * This function is mainly intended for use by language bindings. -+ * -+ * \param context libiscsi context to operate on. -+ * \param auth_info Authentication information to check. -+ * \return 0 on success, otherwise EINVAL. -+ */ -+PUBLIC int libiscsi_verify_auth_info(struct libiscsi_context *context, -+ const struct libiscsi_auth_info *auth_info); -+ -+/** \brief Set the authentication info for the given node. -+ * -+ * This function sets the authentication information for the node described by -+ * the given node record. This will overwrite any existing authentication -+ * information. -+ * -+ * This is the way to specify authentication information for nodes found -+ * through sendtargets discovery. -+ * -+ * Note: -+ * 1) This is a convience wrapper around libiscsi_node_set_parameter(), -+ * setting the node.session.auth.* parameters. -+ * 2) For nodes found through firmware discovery the authentication information -+ * has already been set from the firmware. -+ * 3) \e auth_info may be NULL in which case any existing authinfo will be -+ * cleared. -+ * -+ * \param context libiscsi context to operate on. -+ * \param node iSCSI node to set auth information of -+ * \param auth_info Authentication information, or NULL. -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_node_set_auth(struct libiscsi_context *context, -+ const struct libiscsi_node *node, -+ const struct libiscsi_auth_info *auth_info); -+ -+/** \brief Get the authentication info for the given node. -+ * -+ * This function gets the authentication information for the node described by -+ * the given node record. -+ * -+ * \param context libiscsi context to operate on. -+ * \param node iSCSI node to set auth information of -+ * \param auth_info Pointer to a libiscsi_auth_info struct where -+ * the retreived information will be stored. -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_node_get_auth(struct libiscsi_context *context, -+ const struct libiscsi_node *node, -+ struct libiscsi_auth_info *auth_info); -+ -+/** \brief Login to an iSCSI node. -+ * -+ * Login to the iSCSI node described by the given node record. -+ * -+ * \param context libiscsi context to operate on. -+ * \param node iSCSI node to login to. -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_node_login(struct libiscsi_context *context, -+ const struct libiscsi_node *node); -+ -+/** \brief Logout of an iSCSI node. -+ * -+ * Logout of the iSCSI node described by the given node record. -+ * -+ * \param context libiscsi context to operate on. -+ * \param node iSCSI node to logout from. -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_node_logout(struct libiscsi_context *context, -+ const struct libiscsi_node *node); -+ -+/** \brief Set an iSCSI parameter for the given node -+ * -+ * Set the given nodes iSCSI parameter named by \e parameter to value \e value. -+ * -+ * \param context libiscsi context to operate on. -+ * \param node iSCSI node to change a parameter from. -+ * \param parameter Name of the parameter to set. -+ * \param value Value to set the parameter too. -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_node_set_parameter(struct libiscsi_context *context, -+ const struct libiscsi_node *node, -+ const char *parameter, const char *value); -+ -+/** \brief Get the value of an iSCSI parameter for the given node -+ * -+ * Get the value of the given nodes iSCSI parameter named by \e parameter. -+ * -+ * \param context libiscsi context to operate on. -+ * \param node iSCSI node to change a parameter from. -+ * \param parameter Name of the parameter to get. -+ * \param value The retreived value is stored here, this buffer must be -+ * atleast LIBISCSI_VALUE_MAXLEN bytes large. -+ * \return 0 on success, otherwise a standard error code -+ * (from errno.h). -+ */ -+PUBLIC int libiscsi_node_get_parameter(struct libiscsi_context *context, -+ const struct libiscsi_node *node, const char *parameter, char *value); -+ -+/** \brief Get human readable string describing the last libiscsi error. -+ * -+ * This function can be called to get a human readable error string when a -+ * libiscsi function has returned an error. This function uses a single buffer -+ * per context, thus the result is only valid as long as no other libiscsi -+ * calls are made on the same context after the failing function call. -+ * -+ * \param context libiscsi context to operate on. -+ * -+ * \return human readable string describing the last libiscsi error. -+ */ -+PUBLIC const char *libiscsi_get_error_string(struct libiscsi_context *context); -+ -+ -+/************************** Utility functions *******************************/ -+ -+/** \brief libiscsi network config struct -+ * -+ * libiscsi network config struct. -+ */ -+struct libiscsi_network_config { -+ int dhcp /** Using DHCP? (boolean). */; -+ char iface_name[LIBISCSI_VALUE_MAXLEN] /** Interface name. */; -+ char mac_address[LIBISCSI_VALUE_MAXLEN] /** MAC address. */; -+ char ip_address[LIBISCSI_VALUE_MAXLEN] /** IP address. */; -+ char netmask[LIBISCSI_VALUE_MAXLEN] /** Netmask. */; -+ char gateway[LIBISCSI_VALUE_MAXLEN] /** IP of Default gateway. */; -+ char primary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Primary DNS. */; -+ char secondary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Secondary DNS. */; -+}; -+ -+/** \brief Get network configuration information from iscsi firmware -+ * -+ * Function can be called to get the network configuration information -+ * (like dhcp, ip, netmask, default gateway, etc.) from the firmware of a -+ * network adapter with iscsi boot firmware. -+ * -+ * Note that not all fields of the returned struct are necessarilly filled, -+ * unset fields contain a 0 length string. -+ * -+ * \param config pointer to a libiscsi_network_config struct to fill. -+ * -+ * \return 0 on success, ENODEV when no iscsi firmware was found. -+ */ -+PUBLIC int libiscsi_get_firmware_network_config( -+ struct libiscsi_network_config *config); -+ -+/** \brief Get the initiator name (iqn) from the iscsi firmware -+ * -+ * Get the initiator name (iqn) from the iscsi firmware. -+ * -+ * \param initiatorname The initiator name is stored here, this buffer must be -+ * atleast LIBISCSI_VALUE_MAXLEN bytes large. -+ * \return 0 on success, ENODEV when no iscsi firmware was found. -+ */ -+PUBLIC int libiscsi_get_firmware_initiator_name(char *initiatorname); -+ -+#undef PUBLIC -+ -+#ifdef __cplusplus -+} -+#endif /* __cplusplus */ -+ -+#endif -diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c -new file mode 100644 -index 0000000..4b09aa7 ---- /dev/null -+++ b/libiscsi/pylibiscsi.c -@@ -0,0 +1,638 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include "libiscsi.h" -+ -+static struct libiscsi_context *context = NULL; -+ -+/****************************** helpers ***********************************/ -+static int check_string(const char *string) -+{ -+ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) { -+ PyErr_SetString(PyExc_ValueError, "string too long"); -+ return -1; -+ } -+ return 0; -+} -+ -+/********************** PyIscsiChapAuthInfo ***************************/ -+ -+typedef struct { -+ PyObject_HEAD -+ -+ struct libiscsi_auth_info info; -+} PyIscsiChapAuthInfo; -+ -+static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args, -+ PyObject *kwds) -+{ -+ int i; -+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; -+ char *kwlist[] = {"username", "password", "reverse_username", -+ "reverse_password", NULL}; -+ const char *string[4] = { NULL, NULL, NULL, NULL }; -+ -+ if (!PyArg_ParseTupleAndKeywords(args, kwds, -+ "zz|zz:chapAuthInfo.__init__", -+ kwlist, &string[0], &string[1], -+ &string[2], &string[3])) -+ return -1; -+ -+ for (i = 0; i < 4; i++) -+ if (string[i] && check_string(string[i])) -+ return -1; -+ -+ memset (&chap->info, 0, sizeof(chap->info)); -+ chap->info.method = libiscsi_auth_chap; -+ if (string[0]) -+ strcpy(chap->info.chap.username, string[0]); -+ if (string[1]) -+ strcpy(chap->info.chap.password, string[1]); -+ if (string[2]) -+ strcpy(chap->info.chap.reverse_username, string[2]); -+ if (string[3]) -+ strcpy(chap->info.chap.reverse_password, string[3]); -+ -+ if (libiscsi_verify_auth_info(context, &chap->info)) { -+ PyErr_SetString(PyExc_ValueError, -+ libiscsi_get_error_string(context)); -+ return -1; -+ } -+ return 0; -+} -+ -+static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data) -+{ -+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; -+ const char *attr = (const char *)data; -+ -+ if (!strcmp(attr, "username")) { -+ return PyString_FromString(chap->info.chap.username); -+ } else if (!strcmp(attr, "password")) { -+ return PyString_FromString(chap->info.chap.password); -+ } else if (!strcmp(attr, "reverse_username")) { -+ return PyString_FromString(chap->info.chap.reverse_username); -+ } else if (!strcmp(attr, "reverse_password")) { -+ return PyString_FromString(chap->info.chap.reverse_password); -+ } -+ return NULL; -+} -+ -+static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data) -+{ -+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; -+ const char *attr = (const char *)data; -+ const char *str; -+ -+ if (!PyArg_Parse(value, "s", &str) || check_string(str)) -+ return -1; -+ -+ if (!strcmp(attr, "username")) { -+ strcpy(chap->info.chap.username, str); -+ } else if (!strcmp(attr, "password")) { -+ strcpy(chap->info.chap.password, str); -+ } else if (!strcmp(attr, "reverse_username")) { -+ strcpy(chap->info.chap.reverse_username, str); -+ } else if (!strcmp(attr, "reverse_password")) { -+ strcpy(chap->info.chap.reverse_password, str); -+ } -+ -+ return 0; -+} -+ -+static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self, -+ PyIscsiChapAuthInfo *other) -+{ -+ int r; -+ -+ r = strcmp(self->info.chap.username, other->info.chap.username); -+ if (r) -+ return r; -+ -+ r = strcmp(self->info.chap.password, other->info.chap.password); -+ if (r) -+ return r; -+ -+ r = strcmp(self->info.chap.reverse_username, -+ other->info.chap.reverse_username); -+ if (r) -+ return r; -+ -+ r = strcmp(self->info.chap.reverse_password, -+ other->info.chap.reverse_password); -+ return r; -+} -+ -+static PyObject *PyIscsiChapAuthInfo_str(PyObject *self) -+{ -+ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; -+ char s[1024], reverse[512] = ""; -+ -+ if (chap->info.chap.reverse_username[0]) -+ snprintf(reverse, sizeof(reverse), ", %s:%s", -+ chap->info.chap.reverse_username, -+ chap->info.chap.reverse_password); -+ -+ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username, -+ chap->info.chap.password, reverse); -+ -+ return PyString_FromString(s); -+} -+ -+static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = { -+ {"username", (getter)PyIscsiChapAuthInfo_get, -+ (setter)PyIscsiChapAuthInfo_set, -+ "username", "username"}, -+ {"password", (getter)PyIscsiChapAuthInfo_get, -+ (setter)PyIscsiChapAuthInfo_set, -+ "password", "password"}, -+ {"reverse_username", (getter)PyIscsiChapAuthInfo_get, -+ (setter)PyIscsiChapAuthInfo_set, -+ "reverse_username", "reverse_username"}, -+ {"reverse_password", (getter)PyIscsiChapAuthInfo_get, -+ (setter)PyIscsiChapAuthInfo_set, -+ "reverse_password", "reverse_password"}, -+ {NULL} -+}; -+ -+PyTypeObject PyIscsiChapAuthInfo_Type = { -+ PyObject_HEAD_INIT(NULL) -+ .tp_name = "libiscsi.chapAuthInfo", -+ .tp_basicsize = sizeof (PyIscsiChapAuthInfo), -+ .tp_getset = PyIscsiChapAuthInfo_getseters, -+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | -+ Py_TPFLAGS_BASETYPE, -+ .tp_compare = (cmpfunc)PyIscsiChapAuthInfo_compare, -+ .tp_init = PyIscsiChapAuthInfo_init, -+ .tp_str = PyIscsiChapAuthInfo_str, -+ .tp_new = PyType_GenericNew, -+ .tp_doc = "iscsi chap authentication information.", -+}; -+ -+/***************************** PyIscsiNode ********************************/ -+ -+typedef struct { -+ PyObject_HEAD -+ -+ struct libiscsi_node node; -+} PyIscsiNode; -+ -+static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds) -+{ -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ char *kwlist[] = {"name", "tpgt", "address", "port", "iface", NULL}; -+ const char *name = NULL, *address = NULL, *iface = NULL; -+ int tpgt = -1, port = 3260; -+ -+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isis:node.__init__", -+ kwlist, &name, &tpgt, &address, -+ &port, &iface)) -+ return -1; -+ if (address == NULL) { -+ PyErr_SetString(PyExc_ValueError, "address not set"); -+ return -1; -+ } -+ if (check_string(name) || check_string(address) || check_string(iface)) -+ return -1; -+ -+ strcpy(node->node.name, name); -+ node->node.tpgt = tpgt; -+ strcpy(node->node.address, address); -+ node->node.port = port; -+ strcpy(node->node.iface, iface); -+ -+ return 0; -+} -+ -+static PyObject *PyIscsiNode_get(PyObject *self, void *data) -+{ -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ const char *attr = (const char *)data; -+ -+ if (!strcmp(attr, "name")) { -+ return PyString_FromString(node->node.name); -+ } else if (!strcmp(attr, "tpgt")) { -+ return PyInt_FromLong(node->node.tpgt); -+ } else if (!strcmp(attr, "address")) { -+ return PyString_FromString(node->node.address); -+ } else if (!strcmp(attr, "port")) { -+ return PyInt_FromLong(node->node.port); -+ } else if (!strcmp(attr, "iface")) { -+ return PyString_FromString(node->node.iface); -+ } -+ return NULL; -+} -+ -+static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data) -+{ -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ const char *attr = (const char *)data; -+ const char *str; -+ int i; -+ -+ if (!strcmp(attr, "name")) { -+ if (!PyArg_Parse(value, "s", &str) || check_string(str)) -+ return -1; -+ strcpy(node->node.name, str); -+ } else if (!strcmp(attr, "tpgt")) { -+ if (!PyArg_Parse(value, "i", &i)) -+ return -1; -+ node->node.tpgt = i; -+ } else if (!strcmp(attr, "address")) { -+ if (!PyArg_Parse(value, "s", &str) || check_string(str)) -+ return -1; -+ strcpy(node->node.address, str); -+ } else if (!strcmp(attr, "port")) { -+ if (!PyArg_Parse(value, "i", &i)) -+ return -1; -+ node->node.port = i; -+ } else if (!strcmp(attr, "iface")) { -+ if (!PyArg_Parse(value, "s", &str) || check_string(str)) -+ return -1; -+ strcpy(node->node.iface, str); -+ } -+ -+ return 0; -+} -+ -+static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other) -+{ -+ int res; -+ -+ res = strcmp(self->node.name, other->node.name); -+ if (res) -+ return res; -+ -+ if (self->node.tpgt < other->node.tpgt) -+ return -1; -+ if (self->node.tpgt > other->node.tpgt) -+ return -1; -+ -+ res = strcmp(self->node.address, other->node.address); -+ if (res) -+ return res; -+ -+ if (self->node.port < other->node.port) -+ return -1; -+ if (self->node.port > other->node.port) -+ return -1; -+ -+ res = strcmp(self->node.iface, other->node.iface); -+ if (res) -+ return res; -+ -+ return 0; -+} -+ -+static PyObject *PyIscsiNode_str(PyObject *self) -+{ -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ char s[1024], tpgt[16] = ""; -+ -+ if (node->node.tpgt != -1) -+ sprintf(tpgt, ",%d", node->node.tpgt); -+ -+ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address, -+ node->node.port, tpgt, node->node.name); -+ -+ return PyString_FromString(s); -+} -+ -+static PyObject *PyIscsiNode_login(PyObject *self) -+{ -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ -+ if (libiscsi_node_login(context, &node->node)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} -+ -+static PyObject *PyIscsiNode_logout(PyObject *self) -+{ -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ -+ if (libiscsi_node_logout(context, &node->node)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} -+ -+static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args, -+ PyObject *kwds) -+{ -+ char *kwlist[] = {"authinfo", NULL}; -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ PyObject *arg; -+ const struct libiscsi_auth_info *authinfo = NULL; -+ -+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) -+ return NULL; -+ -+ if (arg == Py_None) { -+ authinfo = NULL; -+ } else if (PyObject_IsInstance(arg, (PyObject *) -+ &PyIscsiChapAuthInfo_Type)) { -+ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg; -+ authinfo = &pyauthinfo->info; -+ } else { -+ PyErr_SetString(PyExc_ValueError, "invalid authinfo type"); -+ return NULL; -+ } -+ -+ if (libiscsi_node_set_auth(context, &node->node, authinfo)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} -+ -+static PyObject *PyIscsiNode_getAuth(PyObject *self) -+{ -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ PyIscsiChapAuthInfo *pyauthinfo; -+ struct libiscsi_auth_info authinfo; -+ -+ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ -+ switch (authinfo.method) { -+ case libiscsi_auth_chap: -+ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo, -+ &PyIscsiChapAuthInfo_Type); -+ if (!pyauthinfo) -+ return NULL; -+ -+ pyauthinfo->info = authinfo; -+ -+ return (PyObject *)pyauthinfo; -+ -+ case libiscsi_auth_none: -+ default: -+ Py_RETURN_NONE; -+ } -+} -+ -+static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args, -+ PyObject *kwds) -+{ -+ char *kwlist[] = {"parameter", "value", NULL}; -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ const char *parameter, *value; -+ -+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, -+ ¶meter, &value)) -+ return NULL; -+ if (check_string(parameter) || check_string(value)) -+ return NULL; -+ -+ if (libiscsi_node_set_parameter(context, &node->node, parameter, -+ value)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} -+ -+static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args, -+ PyObject *kwds) -+{ -+ char *kwlist[] = {"parameter", NULL}; -+ PyIscsiNode *node = (PyIscsiNode *)self; -+ const char *parameter; -+ char value[LIBISCSI_VALUE_MAXLEN]; -+ -+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, ¶meter)) -+ return NULL; -+ if (check_string(parameter)) -+ return NULL; -+ -+ if (libiscsi_node_get_parameter(context, &node->node, parameter, -+ value)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ return Py_BuildValue("s", value); -+} -+ -+static struct PyGetSetDef PyIscsiNode_getseters[] = { -+ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, -+ "name", "name"}, -+ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, -+ "tpgt", "tpgt"}, -+ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, -+ "address", "address"}, -+ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, -+ "port", "port"}, -+ {"iface", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, -+ "iface", "iface"}, -+ {NULL} -+}; -+ -+static struct PyMethodDef PyIscsiNode_methods[] = { -+ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS, -+ "Log in to the node"}, -+ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS, -+ "Log out of the node"}, -+ {"setAuth", (PyCFunction) PyIscsiNode_setAuth, -+ METH_VARARGS|METH_KEYWORDS, -+ "Set authentication information"}, -+ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS, -+ "Get authentication information"}, -+ {"setParameter", (PyCFunction) PyIscsiNode_setParameter, -+ METH_VARARGS|METH_KEYWORDS, -+ "Set an iscsi node parameter"}, -+ {"getParameter", (PyCFunction) PyIscsiNode_getParameter, -+ METH_VARARGS|METH_KEYWORDS, -+ "Get an iscsi node parameter"}, -+ {NULL} -+}; -+ -+PyTypeObject PyIscsiNode_Type = { -+ PyObject_HEAD_INIT(NULL) -+ .tp_name = "libiscsi.node", -+ .tp_basicsize = sizeof (PyIscsiNode), -+ .tp_getset = PyIscsiNode_getseters, -+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | -+ Py_TPFLAGS_BASETYPE, -+ .tp_methods = PyIscsiNode_methods, -+ .tp_compare = (cmpfunc)PyIscsiNode_compare, -+ .tp_init = PyIscsiNode_init, -+ .tp_str = PyIscsiNode_str, -+ .tp_new = PyType_GenericNew, -+ .tp_doc = "The iscsi node contains iscsi node information.", -+}; -+ -+/***************************************************************************/ -+ -+static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, -+ PyObject *args, PyObject *kwds) -+{ -+ char *kwlist[] = {"address", "port", "authinfo", NULL}; -+ const char *address = NULL; -+ int i, nr_found, port = 3260; -+ PyObject *authinfo_arg = NULL; -+ const struct libiscsi_auth_info *authinfo = NULL; -+ struct libiscsi_node *found_nodes; -+ PyObject* found_node_list; -+ -+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO", -+ kwlist, &address, &port, -+ &authinfo_arg)) -+ return NULL; -+ -+ if (authinfo_arg) { -+ if (PyObject_IsInstance(authinfo_arg, (PyObject *) -+ &PyIscsiChapAuthInfo_Type)) { -+ PyIscsiChapAuthInfo *pyauthinfo = -+ (PyIscsiChapAuthInfo *)authinfo_arg; -+ authinfo = &pyauthinfo->info; -+ } else if (authinfo_arg != Py_None) { -+ PyErr_SetString(PyExc_ValueError, -+ "invalid authinfo type"); -+ return NULL; -+ } -+ } -+ -+ if (libiscsi_discover_sendtargets(context, address, port, authinfo, -+ &nr_found, &found_nodes)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ -+ if (nr_found == 0) -+ Py_RETURN_NONE; -+ -+ found_node_list = PyList_New(nr_found); -+ if (!found_node_list) -+ return NULL; -+ -+ for(i = 0; i < nr_found; i++) { -+ PyIscsiNode *pynode; -+ -+ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); -+ if (!pynode) { -+ /* This will deref already added nodes for us */ -+ Py_DECREF(found_node_list); -+ return NULL; -+ } -+ pynode->node = found_nodes[i]; -+ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); -+ } -+ -+ return found_node_list; -+} -+ -+static PyObject *pylibiscsi_discover_firmware(PyObject *self) -+{ -+ int i, nr_found; -+ struct libiscsi_node *found_nodes; -+ PyObject* found_node_list; -+ -+ if (libiscsi_discover_firmware(context, &nr_found, &found_nodes)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ -+ if (nr_found == 0) -+ Py_RETURN_NONE; -+ -+ found_node_list = PyList_New(nr_found); -+ if (!found_node_list) -+ return NULL; -+ -+ for(i = 0; i < nr_found; i++) { -+ PyIscsiNode *pynode; -+ -+ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); -+ if (!pynode) { -+ /* This will deref already added nodes for us */ -+ Py_DECREF(found_node_list); -+ return NULL; -+ } -+ pynode->node = found_nodes[i]; -+ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); -+ } -+ -+ return found_node_list; -+} -+ -+static PyObject *pylibiscsi_get_firmware_initiator_name(PyObject *self) -+{ -+ char initiatorname[LIBISCSI_VALUE_MAXLEN]; -+ -+ if (libiscsi_get_firmware_initiator_name(initiatorname)) { -+ PyErr_SetString(PyExc_IOError, -+ libiscsi_get_error_string(context)); -+ return NULL; -+ } -+ -+ return PyString_FromString(initiatorname); -+} -+ -+static PyMethodDef pylibiscsi_functions[] = { -+ { "discover_sendtargets", -+ (PyCFunction)pylibiscsi_discover_sendtargets, -+ METH_VARARGS|METH_KEYWORDS, -+ "Do sendtargets discovery and return a list of found nodes)"}, -+ { "discover_firmware", -+ (PyCFunction)pylibiscsi_discover_firmware, METH_NOARGS, -+ "Do firmware discovery and return a list of found nodes)"}, -+ { "get_firmware_initiator_name", -+ (PyCFunction)pylibiscsi_get_firmware_initiator_name, -+ METH_NOARGS, -+ "Get initator name (iqn) from firmware"}, -+ {NULL, NULL} -+}; -+ -+PyMODINIT_FUNC initlibiscsi(void) -+{ -+ PyObject *m; -+ -+ if (!context) /* We may be called more then once */ -+ context = libiscsi_init(); -+ if (!context) -+ return; -+ -+ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0) -+ return; -+ -+ if (PyType_Ready(&PyIscsiNode_Type) < 0) -+ return; -+ -+ m = Py_InitModule("libiscsi", pylibiscsi_functions); -+ Py_INCREF(&PyIscsiChapAuthInfo_Type); -+ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type); -+ Py_INCREF(&PyIscsiNode_Type); -+ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type); -+} -diff --git a/libiscsi/setup.py b/libiscsi/setup.py -new file mode 100644 -index 0000000..bb4329b ---- /dev/null -+++ b/libiscsi/setup.py -@@ -0,0 +1,9 @@ -+from distutils.core import setup, Extension -+ -+module1 = Extension('libiscsimodule', -+ sources = ['pylibiscsi.c'], -+ libraries = ['iscsi'], -+ library_dirs = ['.']) -+ -+setup (name = 'PyIscsi',version = '1.0', -+ description = 'libiscsi python bindings', ext_modules = [module1]) -diff --git a/libiscsi/tests/test_discovery_firmware.c b/libiscsi/tests/test_discovery_firmware.c -new file mode 100644 -index 0000000..76e852a ---- /dev/null -+++ b/libiscsi/tests/test_discovery_firmware.c -@@ -0,0 +1,53 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_node *found_nodes; -+ struct libiscsi_context *context; -+ int i, found, rc = 0; -+ -+ context = libiscsi_init(); -+ if (!context) { -+ fprintf(stderr, "Error initializing libiscsi\n"); -+ return 1; -+ } -+ -+ rc = libiscsi_discover_firmware(context, &found, &found_nodes); -+ if (rc) -+ fprintf(stderr, "Error discovering: %s\n", -+ libiscsi_get_error_string(context)); -+ -+ for (i = 0; i < found; i++) { -+ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", -+ found_nodes[i].name, found_nodes[i].tpgt, -+ found_nodes[i].address, found_nodes[i].port); -+ } -+ -+ libiscsi_cleanup(context); -+ free (found_nodes); -+ -+ return rc; -+} -diff --git a/libiscsi/tests/test_discovery_sendtargets.c b/libiscsi/tests/test_discovery_sendtargets.c -new file mode 100644 -index 0000000..1a3c12e ---- /dev/null -+++ b/libiscsi/tests/test_discovery_sendtargets.c -@@ -0,0 +1,60 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_node *found_nodes; -+ struct libiscsi_context *context; -+ struct libiscsi_auth_info auth_info; -+ int i, found, rc = 0; -+ -+ context = libiscsi_init(); -+ if (!context) { -+ fprintf(stderr, "Error initializing libiscsi\n"); -+ return 1; -+ } -+ -+ memset(&auth_info, 0, sizeof(auth_info)); -+ auth_info.method = libiscsi_auth_chap; -+ strcpy(auth_info.chap.username, "joe"); -+ strcpy(auth_info.chap.password, "secret"); -+ -+ rc = libiscsi_discover_sendtargets(context, "127.0.0.1", 3260, -+ &auth_info, &found, &found_nodes); -+ if (rc) -+ fprintf(stderr, "Error discovering: %s\n", -+ libiscsi_get_error_string(context)); -+ -+ for (i = 0; i < found; i++) { -+ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", -+ found_nodes[i].name, found_nodes[i].tpgt, -+ found_nodes[i].address, found_nodes[i].port); -+ } -+ -+ libiscsi_cleanup(context); -+ free (found_nodes); -+ -+ return rc; -+} -diff --git a/libiscsi/tests/test_get_auth.c b/libiscsi/tests/test_get_auth.c -new file mode 100644 -index 0000000..5e234da ---- /dev/null -+++ b/libiscsi/tests/test_get_auth.c -@@ -0,0 +1,70 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_node node; -+ struct libiscsi_context *context; -+ struct libiscsi_auth_info auth_info; -+ int rc = 0; -+ -+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", -+ "iqn.2009-01.com.example:testdisk"); -+ node.tpgt = 1; -+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); -+ node.port = 3260; -+ -+ context = libiscsi_init(); -+ if (!context) { -+ fprintf(stderr, "Error initializing libiscsi\n"); -+ return 1; -+ } -+ -+ rc = libiscsi_node_get_auth(context, &node, &auth_info); -+ if (rc) { -+ fprintf(stderr, "Error setting authinfo: %s\n", -+ libiscsi_get_error_string(context)); -+ goto leave; -+ } -+ -+ switch (auth_info.method) { -+ case libiscsi_auth_none: -+ printf("Method: \"None\"\n"); -+ break; -+ case libiscsi_auth_chap: -+ printf("Method: \"CHAP\"\n"); -+ printf("User: \"%s\"\n", auth_info.chap.username); -+ printf("Pass: \"%s\"\n", auth_info.chap.password); -+ printf("RevUser: \"%s\"\n", -+ auth_info.chap.reverse_username); -+ printf("RevPass: \"%s\"\n", -+ auth_info.chap.reverse_password); -+ break; -+ } -+leave: -+ libiscsi_cleanup(context); -+ -+ return rc; -+} -diff --git a/libiscsi/tests/test_get_initiator_name.c b/libiscsi/tests/test_get_initiator_name.c -new file mode 100644 -index 0000000..997c053 ---- /dev/null -+++ b/libiscsi/tests/test_get_initiator_name.c -@@ -0,0 +1,38 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ char initiatorname[LIBISCSI_VALUE_MAXLEN]; -+ -+ if (libiscsi_get_firmware_initiator_name(initiatorname)) { -+ fprintf(stderr, "No iscsi boot firmware found\n"); -+ return 1; -+ } -+ -+ printf("iqn:\t%s\n", initiatorname); -+ -+ return 0; -+} -diff --git a/libiscsi/tests/test_get_network_config.c b/libiscsi/tests/test_get_network_config.c -new file mode 100644 -index 0000000..2dedd61 ---- /dev/null -+++ b/libiscsi/tests/test_get_network_config.c -@@ -0,0 +1,45 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_network_config config; -+ -+ if (libiscsi_get_firmware_network_config(&config)) { -+ fprintf(stderr, "No iscsi boot firmware found\n"); -+ return 1; -+ } -+ -+ printf("dhcp:\t%d\n", config.dhcp); -+ printf("iface:\t%s\n", config.iface_name); -+ printf("mac:\t%s\n", config.mac_address); -+ printf("ipaddr:\t%s\n", config.ip_address); -+ printf("mask:\t%s\n", config.netmask); -+ printf("gate:\t%s\n", config.gateway); -+ printf("dns1:\t%s\n", config.primary_dns); -+ printf("dns2:\t%s\n", config.secondary_dns); -+ -+ return 0; -+} -diff --git a/libiscsi/tests/test_login.c b/libiscsi/tests/test_login.c -new file mode 100644 -index 0000000..3eb70d6 ---- /dev/null -+++ b/libiscsi/tests/test_login.c -@@ -0,0 +1,52 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_node node; -+ struct libiscsi_context *context; -+ int rc = 0; -+ -+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", -+ "iqn.2009-01.com.example:testdisk"); -+ node.tpgt = 1; -+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); -+ node.port = 3260; -+ -+ context = libiscsi_init(); -+ if (!context) { -+ fprintf(stderr, "Error initializing libiscsi\n"); -+ return 1; -+ } -+ -+ rc = libiscsi_node_login(context, &node); -+ if (rc) -+ fprintf(stderr, "Error logging in: %s\n", -+ libiscsi_get_error_string(context)); -+ -+ libiscsi_cleanup(context); -+ -+ return rc; -+} -diff --git a/libiscsi/tests/test_logout.c b/libiscsi/tests/test_logout.c -new file mode 100644 -index 0000000..b734dca ---- /dev/null -+++ b/libiscsi/tests/test_logout.c -@@ -0,0 +1,51 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_node node; -+ struct libiscsi_context *context; -+ int rc = 0; -+ -+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", -+ "iqn.2009-01.com.example:testdisk"); -+ node.tpgt = 1; -+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); -+ node.port = 3260; -+ -+ context = libiscsi_init(); -+ if (!context) { -+ fprintf(stderr, "Error initializing libiscsi\n"); -+ return 1; -+ } -+ -+ rc = libiscsi_node_logout(context, &node); -+ if (rc) -+ fprintf(stderr, "Error logging out: %s\n", -+ libiscsi_get_error_string(context)); -+ -+ libiscsi_cleanup(context); -+ -+ return rc; -+} -diff --git a/libiscsi/tests/test_params.c b/libiscsi/tests/test_params.c -new file mode 100644 -index 0000000..d3223be ---- /dev/null -+++ b/libiscsi/tests/test_params.c -@@ -0,0 +1,103 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_node node; -+ struct libiscsi_context *context; -+ char orig_value[LIBISCSI_VALUE_MAXLEN], value[LIBISCSI_VALUE_MAXLEN]; -+ int rc = 0; -+ -+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", -+ "iqn.2009-01.com.example:testdisk"); -+ node.tpgt = 1; -+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); -+ node.port = 3260; -+ -+ context = libiscsi_init(); -+ if (!context) { -+ fprintf(stderr, "Error initializing libiscsi\n"); -+ return 1; -+ } -+ -+ rc = libiscsi_node_get_parameter(context, &node, "node.startup", -+ orig_value); -+ if (rc) { -+ fprintf(stderr, "Error getting original value: %s\n", -+ libiscsi_get_error_string(context)); -+ goto leave; -+ } -+ -+ rc = libiscsi_node_set_parameter(context, &node, "node.startup", -+ "automatic"); -+ if (rc) { -+ fprintf(stderr, "Error setting node startup param: %s\n", -+ libiscsi_get_error_string(context)); -+ goto leave; -+ } -+ -+ rc = libiscsi_node_get_parameter(context, &node, "node.startup", -+ value); -+ if (rc) { -+ fprintf(stderr, "Error getting node startup param: %s\n", -+ libiscsi_get_error_string(context)); -+ goto leave; -+ } -+ -+ if (strcmp(value, "automatic")) { -+ fprintf(stderr, "Error set and get values do not match!\n"); -+ rc = EIO; -+ goto leave; -+ } -+ -+ rc = libiscsi_node_set_parameter(context, &node, "node.startup", -+ orig_value); -+ if (rc) { -+ fprintf(stderr, "Error setting original value: %s\n", -+ libiscsi_get_error_string(context)); -+ goto leave; -+ } -+ -+ rc = libiscsi_node_get_parameter(context, &node, "node.startup", -+ value); -+ if (rc) { -+ fprintf(stderr, "Error re-getting original value: %s\n", -+ libiscsi_get_error_string(context)); -+ goto leave; -+ } -+ -+ if (strcmp(value, orig_value)) { -+ fprintf(stderr, -+ "Error set and get original values do not match!\n"); -+ rc = EIO; -+ goto leave; -+ } -+ -+leave: -+ libiscsi_cleanup(context); -+ -+ return rc; -+} -diff --git a/libiscsi/tests/test_set_auth.c b/libiscsi/tests/test_set_auth.c -new file mode 100644 -index 0000000..a21f888 ---- /dev/null -+++ b/libiscsi/tests/test_set_auth.c -@@ -0,0 +1,58 @@ -+/* -+ * iSCSI Administration library -+ * -+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2008-2009 Hans de Goede -+ * maintained by open-iscsi@googlegroups.com -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published -+ * by the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * See the file COPYING included with this distribution for more details. -+ */ -+ -+#include -+#include -+#include -+#include "libiscsi.h" -+ -+int main(void) -+{ -+ struct libiscsi_node node; -+ struct libiscsi_context *context; -+ struct libiscsi_auth_info auth_info; -+ int rc = 0; -+ -+ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", -+ "iqn.2009-01.com.example:testdisk"); -+ node.tpgt = 1; -+ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); -+ node.port = 3260; -+ -+ memset(&auth_info, 0, sizeof(auth_info)); -+ auth_info.method = libiscsi_auth_chap; -+ strcpy(auth_info.chap.username, "joe"); -+ strcpy(auth_info.chap.password, "secret"); -+ -+ context = libiscsi_init(); -+ if (!context) { -+ fprintf(stderr, "Error initializing libiscsi\n"); -+ return 1; -+ } -+ -+ rc = libiscsi_node_set_auth(context, &node, &auth_info); -+ if (rc) -+ fprintf(stderr, "Error setting authinfo: %s\n", -+ libiscsi_get_error_string(context)); -+ -+ libiscsi_cleanup(context); -+ -+ return rc; -+} -diff --git a/usr/Makefile b/usr/Makefile -index 3d8ee22..e731545 100644 ---- a/usr/Makefile -+++ b/usr/Makefile -@@ -31,7 +31,7 @@ endif - OPTFLAGS ?= -O2 -g - WARNFLAGS ?= -Wall -Wstrict-prototypes - CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../include -I. -I../utils/open-isns \ -- -D$(OSNAME) $(IPC_CFLAGS) -+ -D$(OSNAME) $(IPC_CFLAGS) -DISNS_ENABLE - PROGRAMS = iscsid iscsiadm iscsistart - - # libc compat files -diff --git a/usr/discovery.c b/usr/discovery.c -index afce6c0..0c93749 100644 ---- a/usr/discovery.c -+++ b/usr/discovery.c -@@ -36,6 +36,7 @@ - #include "types.h" - #include "iscsi_proto.h" - #include "initiator.h" -+#include "config.h" - #include "log.h" - #include "idbm.h" - #include "iscsi_settings.h" -@@ -50,9 +51,11 @@ - #include "iscsi_timer.h" - #include "iscsi_err.h" - /* libisns includes */ -+#ifdef ISNS_ENABLE - #include "isns.h" - #include "paths.h" - #include "message.h" -+#endif - - #ifdef SLP_ENABLE - #include "iscsi-slp-discovery.h" -@@ -98,6 +101,7 @@ static int request_initiator_name(void) - return 0; - } - -+#ifdef ISNS_ENABLE - void discovery_isns_free_servername(void) - { - if (isns_config.ic_server_name) -@@ -377,6 +381,7 @@ retry: - discovery_isns_free_servername(); - return rc; - } -+#endif - - int discovery_fw(void *data, struct iface_rec *iface, - struct list_head *rec_list) -diff --git a/usr/idbm.c b/usr/idbm.c -index 4bb9810..c84ae69 100644 ---- a/usr/idbm.c -+++ b/usr/idbm.c -@@ -1515,9 +1515,9 @@ int idbm_print_all_discovery(int info_level) - * fn should return -1 if it skipped the rec, a ISCSI_ERR error code if - * the operation failed or 0 if fn was run successfully. - */ --static int idbm_for_each_iface(int *found, void *data, -- idbm_iface_op_fn *fn, -- char *targetname, int tpgt, char *ip, int port) -+int idbm_for_each_iface(int *found, void *data, -+ idbm_iface_op_fn *fn, -+ char *targetname, int tpgt, char *ip, int port) - { - DIR *iface_dirfd; - struct dirent *iface_dent; -diff --git a/usr/idbm.h b/usr/idbm.h -index 1e9b132..4d08b31 100644 ---- a/usr/idbm.h -+++ b/usr/idbm.h -@@ -102,6 +102,9 @@ struct rec_op_data { - node_rec_t *match_rec; - idbm_iface_op_fn *fn; - }; -+extern int idbm_for_each_iface(int *found, void *data, -+ idbm_iface_op_fn *fn, -+ char *targetname, int tpgt, char *ip, int port); - extern int idbm_for_each_portal(int *found, void *data, - idbm_portal_op_fn *fn, char *targetname); - extern int idbm_for_each_node(int *found, void *data, -diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h -index b6665cb..3e7f82a 100644 ---- a/usr/iscsi_ipc.h -+++ b/usr/iscsi_ipc.h -@@ -160,4 +160,6 @@ struct iscsi_ipc { - uint32_t host_no, uint32_t sid); - }; - -+struct iscsi_ipc *ipc; -+ - #endif /* ISCSI_IPC_H */ --- -1.8.1.4 - diff --git a/0055-dont-use-static.patch b/0055-dont-use-static.patch deleted file mode 100644 index 9e43b7b..0000000 --- a/0055-dont-use-static.patch +++ /dev/null @@ -1,25 +0,0 @@ -From ff224a16d409c4b479b3ac1ff662093cb067e281 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 19 Nov 2012 17:04:29 -0800 -Subject: dont use static - ---- - usr/Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/usr/Makefile b/usr/Makefile -index 015f1b9..1669890 100644 ---- a/usr/Makefile -+++ b/usr/Makefile -@@ -61,7 +61,7 @@ iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o - - iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ - iscsistart.o statics.o -- $(CC) $(CFLAGS) -static $^ -o $@ -+ $(CC) $(CFLAGS) $^ -o $@ - clean: - rm -f *.o $(PROGRAMS) .depend $(LIBSYS) - --- -1.7.11.7 - diff --git a/0056-remove-the-offload-boot-supported-ifdef.patch b/0056-remove-the-offload-boot-supported-ifdef.patch deleted file mode 100644 index a1ccdc7..0000000 --- a/0056-remove-the-offload-boot-supported-ifdef.patch +++ /dev/null @@ -1,45 +0,0 @@ -From aa58a042ec20575143c1a5c813c9552a286aeb0e Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 19 Nov 2012 17:09:24 -0800 -Subject: remove the offload boot supported ifdef - ---- - usr/iface.c | 7 +------ - 1 file changed, 1 insertion(+), 6 deletions(-) - -diff --git a/usr/iface.c b/usr/iface.c -index c86892e..f5441c0 100644 ---- a/usr/iface.c -+++ b/usr/iface.c -@@ -895,6 +895,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, - { - struct iscsi_transport *t = NULL; - uint32_t hostno; -+ int rc; - - if (strlen(context->initiatorname)) - strlcpy(iface->iname, context->initiatorname, -@@ -907,10 +908,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, - return 0; - } - } else if (strlen(context->iface)) { --/* this ifdef is only temp until distros and firmwares are updated */ --#ifdef OFFLOAD_BOOT_SUPPORTED - char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; -- int rc; - - memset(transport_name, 0, ISCSI_TRANSPORT_NAME_MAXLEN); - /* make sure offload driver is loaded */ -@@ -936,9 +934,6 @@ int iface_setup_from_boot_context(struct iface_rec *iface, - } - - strlcpy(iface->netdev, context->iface, sizeof(iface->netdev)); --#else -- return 0; --#endif - } else - return 0; - --- -1.7.11.7 - diff --git a/0058-iscsiuio-IPC-newroot-command.patch b/0058-iscsiuio-IPC-newroot-command.patch deleted file mode 100644 index fa3f4c7..0000000 --- a/0058-iscsiuio-IPC-newroot-command.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 6e979154c9c51dedd54c91e46106e495a65ced43 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Wed, 2 Jan 2013 14:45:05 -0800 -Subject: [PATCH 58/58] iscsiuio IPC newroot command - ---- - usr/mgmt_ipc.c | 11 +++++++++++ - usr/transport.c | 1 + - usr/transport.h | 1 + - usr/uip_mgmt_ipc.c | 14 ++++++++++++++ - usr/uip_mgmt_ipc.h | 5 +++++ - 5 files changed, 32 insertions(+) - -diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c -index 5cb7143..a8f8473 100644 ---- a/usr/mgmt_ipc.c -+++ b/usr/mgmt_ipc.c -@@ -36,6 +36,7 @@ - #include "sysdeps.h" - #include "iscsi_ipc.h" - #include "iscsi_err.h" -+#include "iscsi_sysfs.h" - - #define PEERUSER_MAX 64 - #define EXTMSG_MAX (64 * 1024) -@@ -229,8 +230,18 @@ static int - mgmt_ipc_newroot(queue_task_t *qtask) - { - char *newroot = qtask->req.u.newroot.path; -+ struct iscsi_transport *t; -+ - if (chdir(newroot) || chroot(".") || chdir("/")) - return ISCSI_ERR; -+ -+ /* if a registered transport has a separate userspace process, -+ * notify it of the root change as well */ -+ list_for_each_entry(t, &transports, list) { -+ if (t->template->newroot) -+ t->template->newroot(t, newroot); -+ } -+ - mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS); - return ISCSI_SUCCESS; - } -diff --git a/usr/transport.c b/usr/transport.c -index 4d030a8..e0488ad 100644 ---- a/usr/transport.c -+++ b/usr/transport.c -@@ -83,6 +83,7 @@ struct iscsi_transport_template bnx2i = { - .ep_poll = ktransport_ep_poll, - .ep_disconnect = ktransport_ep_disconnect, - .set_net_config = uip_broadcast_params, -+ .newroot = uip_broadcast_newroot, - }; - - struct iscsi_transport_template be2iscsi = { -diff --git a/usr/transport.h b/usr/transport.h -index 388e4b1..d4d9ec7 100644 ---- a/usr/transport.h -+++ b/usr/transport.h -@@ -39,6 +39,7 @@ struct iscsi_transport_template { - int (*set_net_config) (struct iscsi_transport *t, - struct iface_rec *iface, - struct iscsi_session *session); -+ void (*newroot) (struct iscsi_transport *t, char *path); - }; - - /* represents data path provider */ -diff --git a/usr/uip_mgmt_ipc.c b/usr/uip_mgmt_ipc.c -index f3074ee..d5d496a 100644 ---- a/usr/uip_mgmt_ipc.c -+++ b/usr/uip_mgmt_ipc.c -@@ -39,3 +39,17 @@ int uip_broadcast_params(struct iscsi_transport *t, - sizeof(iscsid_uip_broadcast_header_t) + - sizeof(*iface)); - } -+ -+int uip_broadcast_newroot(struct iscsi_transport *t, char *newroot) -+{ -+ struct iscsid_uip_broadcast broadcast; -+ -+ memset(&broadcast, 0, sizeof(broadcast)); -+ -+ broadcast.header.command = ISCSID_UIP_NEWROOT; -+ strncpy(broadcast.u.newroot.path, newroot, PATH_MAX); -+ -+ return uip_broadcast(&broadcast, -+ sizeof(iscsid_uip_broadcast_header_t) + -+ PATH_MAX + 1); -+} -diff --git a/usr/uip_mgmt_ipc.h b/usr/uip_mgmt_ipc.h -index 29a4769..3ca4fb1 100644 ---- a/usr/uip_mgmt_ipc.h -+++ b/usr/uip_mgmt_ipc.h -@@ -29,6 +29,7 @@ - typedef enum iscsid_uip_cmd { - ISCSID_UIP_IPC_UNKNOWN = 0, - ISCSID_UIP_IPC_GET_IFACE = 1, -+ ISCSID_UIP_NEWROOT = 2, - - __ISCSID_UIP_IPC_MAX_COMMAND - } iscsid_uip_cmd_e; -@@ -47,6 +48,9 @@ typedef struct iscsid_uip_broadcast { - struct ipc_broadcast_iface_rec { - struct iface_rec rec; - } iface_rec; -+ struct ipc_broadcast_newroot { -+ char path[PATH_MAX + 1]; -+ } newroot; - } u; - } iscsid_uip_broadcast_t; - -@@ -69,5 +73,6 @@ extern int uip_broadcast_params(struct iscsi_transport *t, - struct iface_rec *iface, - struct iscsi_session *session); - -+extern int uip_broadcast_newroot(struct iscsi_transport *t, char *path); - - #endif /* UIP_MGMT_IPC_H */ --- -1.8.1.4 - diff --git a/0059-iscsiuio-systemd-unit-files.patch b/0059-iscsiuio-systemd-unit-files.patch deleted file mode 100644 index 2d0e213..0000000 --- a/0059-iscsiuio-systemd-unit-files.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 822b53e6c9ebb0fe7236ebd3b4c73b009100592d Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 22 Jan 2013 14:27:12 -0800 -Subject: iscsiuio systemd unit files - ---- - etc/systemd/iscsiuio.service | 17 +++++++++++++++++ - etc/systemd/iscsiuio.socket | 9 +++++++++ - 2 files changed, 26 insertions(+) - create mode 100644 etc/systemd/iscsiuio.service - create mode 100644 etc/systemd/iscsiuio.socket - -diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service -new file mode 100644 -index 0000000..f0410b7 ---- /dev/null -+++ b/etc/systemd/iscsiuio.service -@@ -0,0 +1,17 @@ -+[Unit] -+Description=iSCSI UserSpace I/O driver -+Documentation=man:iscsiuio(8) -+DefaultDependencies=no -+Conflicts=shutdown.target -+Requires=iscsid.service -+BindTo=iscsid.service -+After=network.target -+Before=remote-fs-pre.target iscsid.service -+ -+[Service] -+Type=forking -+PIDFile=/var/run/iscsiuio.pid -+ExecStart=/usr/sbin/iscsiuio -+ -+[Install] -+WantedBy=multi-user.target -diff --git a/etc/systemd/iscsiuio.socket b/etc/systemd/iscsiuio.socket -new file mode 100644 -index 0000000..d42cedc ---- /dev/null -+++ b/etc/systemd/iscsiuio.socket -@@ -0,0 +1,9 @@ -+[Unit] -+Description=Open-iSCSI iscsiuio Socket -+Documentation=man:iscsiuio(8) -+ -+[Socket] -+ListenStream=@ISCSID_UIP_ABSTRACT_NAMESPACE -+ -+[Install] -+WantedBy=sockets.target --- -1.7.11.7 - diff --git a/0060-use-systemctl-to-start-iscsid.patch b/0060-use-systemctl-to-start-iscsid.patch deleted file mode 100644 index 81aa2a3..0000000 --- a/0060-use-systemctl-to-start-iscsid.patch +++ /dev/null @@ -1,25 +0,0 @@ -From c3d2b8f3de5b6161845304cf46982d2c5a9918b6 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Thu Feb 21 21:05:39 PST 2013 -Subject: disable iscsid.startup from iscsiadm, prefer systemd socket activation - ---- - etc/iscsid.conf | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/etc/iscsid.conf b/etc/iscsid.conf -index ac1d231..5851fa5 100644 ---- a/etc/iscsid.conf -+++ b/etc/iscsid.conf -@@ -17,7 +17,7 @@ - # maintainers. - # - # Default for Fedora and RHEL. (uncomment to activate). --iscsid.startup = /etc/rc.d/init.d/iscsid force-start -+#iscsid.startup = /bin/systemctl start iscsid.service - # - # Default for upstream open-iscsi scripts (uncomment to activate). - # iscsid.startup = /sbin/iscsid --- -1.7.11.7 - diff --git a/0061-resolve-565245-multilib-issues-caused-by-doxygen.patch b/0061-resolve-565245-multilib-issues-caused-by-doxygen.patch deleted file mode 100644 index 1f64d9c..0000000 --- a/0061-resolve-565245-multilib-issues-caused-by-doxygen.patch +++ /dev/null @@ -1,39 +0,0 @@ -From bc4cf1487b4d6039de2a082c1786ac83ab148c88 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 22 Jan 2013 15:14:21 -0800 -Subject: resolve 565245: multilib issues caused by doxygen - ---- - libiscsi/libiscsi.doxy | 2 +- - libiscsi/no_date_footer.html | 6 ++++++ - 2 files changed, 7 insertions(+), 1 deletion(-) - create mode 100644 libiscsi/no_date_footer.html - -diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy -index 663770f..7a5ff7f 100644 ---- a/libiscsi/libiscsi.doxy -+++ b/libiscsi/libiscsi.doxy -@@ -765,7 +765,7 @@ HTML_HEADER = - # each generated HTML page. If it is left blank doxygen will generate a - # standard footer. - --HTML_FOOTER = -+HTML_FOOTER = no_date_footer.html - - # The HTML_STYLESHEET tag can be used to specify a user-defined cascading - # style sheet that is used by each HTML page. It can be used to -diff --git a/libiscsi/no_date_footer.html b/libiscsi/no_date_footer.html -new file mode 100644 -index 0000000..1e0c6c4 ---- /dev/null -+++ b/libiscsi/no_date_footer.html -@@ -0,0 +1,6 @@ -+
-+Generated for $projectname by doxygen -+$doxygenversion
-+ -+ --- -1.7.11.7 - diff --git a/0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch b/0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch deleted file mode 100644 index 684463f..0000000 --- a/0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch +++ /dev/null @@ -1,30 +0,0 @@ -From ab79bdb20e37216ca969e06d63a952acfd023963 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 28 May 2013 13:12:27 -0700 -Subject: [PATCH] Don't check for autostart sessions if iscsi is not used (bug - #951951) - -Change conditional startup in iscsi.service to check for a non-empty -nodes directory, instead of initiator-name. This fits better with what -it's doing, as there's no need to scan for autostart node records if -there are no node records at all. ---- - etc/systemd/iscsi.service | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service -index bbd52fd..7b4efee 100644 ---- a/etc/systemd/iscsi.service -+++ b/etc/systemd/iscsi.service -@@ -5,7 +5,7 @@ DefaultDependencies=no - Conflicts=shutdown.target - After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service - Before=remote-fs-pre.target --ConditionPathExists=/etc/iscsi/initiatorname.iscsi -+ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes - - [Service] - Type=oneshot --- -1.8.1.4 - diff --git a/0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch b/0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch deleted file mode 100644 index cedb4e0..0000000 --- a/0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 3cac85a3f97d0a22270166f428209f873b58c319 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Tue, 11 Jun 2013 11:25:27 -0700 -Subject: [PATCH] iscsid: fix order of setting uid/gid and drop supplementary - groups - -If using the user and group ID settings together the existing order of -calling setuid first will almost always cause the setgid call to fail, -assuming the new effective user id does not have the CAP_SETGID -capability. The effective group ID needs to change first. - -While we're at it, if iscsid is started as root it should drop any -inherited supplementary group permissions. - -And if anyone is actually using this to try and isolate capabilities, -they probably care enough to want to known that it is failing. Make -iscsid startup fail instead of just calling perror. - -Signed-off-by: Chris Leech ---- - usr/iscsid.c | 23 +++++++++++++++++++---- - 1 file changed, 19 insertions(+), 4 deletions(-) - -diff --git a/usr/iscsid.c b/usr/iscsid.c -index b4bb65b..c0ea6fa 100644 ---- a/usr/iscsid.c -+++ b/usr/iscsid.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -477,11 +478,25 @@ int main(int argc, char *argv[]) - } - } - -- if (uid && setuid(uid) < 0) -- perror("setuid\n"); -+ if (gid && setgid(gid) < 0) { -+ log_error("Unable to setgid to %d\n", gid); -+ log_close(log_pid); -+ exit(ISCSI_ERR); -+ } - -- if (gid && setgid(gid) < 0) -- perror("setgid\n"); -+ if ((geteuid() == 0) && (getgroups(0, NULL))) { -+ if (setgroups(0, NULL) != 0) { -+ log_error("Unable to drop supplementary group ids\n"); -+ log_close(log_pid); -+ exit(ISCSI_ERR); -+ } -+ } -+ -+ if (uid && setuid(uid) < 0) { -+ log_error("Unable to setuid to %d\n", uid); -+ log_close(log_pid); -+ exit(ISCSI_ERR); -+ } - - memset(&daemon_config, 0, sizeof (daemon_config)); - daemon_config.pid_file = pid_file; --- -1.8.1.4 - diff --git a/0064-libiscsi-fix-incorrect-strncpy-use.patch b/0064-libiscsi-fix-incorrect-strncpy-use.patch deleted file mode 100644 index 55d1166..0000000 --- a/0064-libiscsi-fix-incorrect-strncpy-use.patch +++ /dev/null @@ -1,52 +0,0 @@ -From fcad7de1a8c3d140d1d0eb120727966017d3727b Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Sat, 17 Aug 2013 15:50:45 -0700 -Subject: libiscsi: fix incorrect strncpy use - -Changes to internal structures make the src and dst buffers of some -copies (potentially) different sizes. Fix strncpy calls that were using -the size of the src argument as the limit. ---- - libiscsi/libiscsi.c | 19 ++++++++----------- - 1 file changed, 8 insertions(+), 11 deletions(-) - -diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c -index 6e6846a..064e4b5 100644 ---- a/libiscsi/libiscsi.c -+++ b/libiscsi/libiscsi.c -@@ -587,15 +587,13 @@ int libiscsi_get_firmware_network_config( - return ENODEV; - - config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0; -- strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface); -- strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac); -- strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr); -- strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask); -- strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway); -- strncpy(config->primary_dns, fw_entry.primary_dns, -- sizeof fw_entry.primary_dns); -- strncpy(config->secondary_dns, fw_entry.secondary_dns, -- sizeof fw_entry.secondary_dns); -+ strlcpy(config->iface_name, fw_entry.iface, LIBISCSI_VALUE_MAXLEN); -+ strlcpy(config->mac_address, fw_entry.mac, LIBISCSI_VALUE_MAXLEN); -+ strlcpy(config->ip_address, fw_entry.ipaddr, LIBISCSI_VALUE_MAXLEN); -+ strlcpy(config->netmask, fw_entry.mask, LIBISCSI_VALUE_MAXLEN); -+ strlcpy(config->gateway, fw_entry.gateway, LIBISCSI_VALUE_MAXLEN); -+ strlcpy(config->primary_dns, fw_entry.primary_dns, LIBISCSI_VALUE_MAXLEN); -+ strlcpy(config->secondary_dns, fw_entry.secondary_dns, LIBISCSI_VALUE_MAXLEN); - return 0; - } - -@@ -613,8 +611,7 @@ int libiscsi_get_firmware_initiator_name(char *initiatorname) - if (fw_get_entry(&fw_entry)) - return ENODEV; - -- strncpy(initiatorname, fw_entry.initiatorname, -- sizeof fw_entry.initiatorname); -+ strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN); - - return 0; - } --- -1.8.1.4 - diff --git a/0065-fix-hardened-build-of-iscsiuio.patch b/0065-fix-hardened-build-of-iscsiuio.patch deleted file mode 100644 index 9a5c8f6..0000000 --- a/0065-fix-hardened-build-of-iscsiuio.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 436ac9074def43ae09d7ecc28eec6cdc77a9d0e2 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Fri, 13 Sep 2013 16:56:51 -0700 -Subject: [PATCH 65/65] fix hardened build of iscsiuio - -The new iscsiuio code sets CFLAGS in configure.ac, wiping out the -environment setup by rpm. Patch that out. - -Also fix local build when iscsi-initiator-utils is installed, but having -the check to prevent overwriting configuration files during install look -in DESTDIR. ---- - Makefile | 2 +- - iscsiuio/configure | 2 +- - iscsiuio/configure.ac | 2 +- - 3 files changed, 3 insertions(+), 3 deletions(-) - mode change 100644 => 100755 iscsiuio/configure - -diff --git a/Makefile b/Makefile -index 02346bf..172d30e 100644 ---- a/Makefile -+++ b/Makefile -@@ -123,7 +123,7 @@ install_iface: $(IFACEFILES) - $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi/ifaces - - install_etc: $(ETCFILES) -- if [ ! -f /etc/iscsi/iscsid.conf ]; then \ -+ if [ ! -f $(DESTDIR)$(etcdir)/iscsi/iscsid.conf ]; then \ - $(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi ; \ - $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi ; \ - fi -diff --git a/iscsiuio/configure b/iscsiuio/configure -old mode 100644 -new mode 100755 -index 2740598..cd13f92 ---- a/iscsiuio/configure -+++ b/iscsiuio/configure -@@ -21288,7 +21288,7 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - --CFLAGS="-O2 -Wall" -+CFLAGS="${CFLAGS} -O2 -Wall" - ## check for --enable-debug first before checking CFLAGS before - ## so that we don't mix -O and -g - # Check whether --enable-debug or --disable-debug was given. -diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac -index e9a5e32..d9a6bdb 100644 ---- a/iscsiuio/configure.ac -+++ b/iscsiuio/configure.ac -@@ -52,7 +52,7 @@ AC_LIBTOOL_DLOPEN - # libtool stuff - AC_PROG_LIBTOOL - --CFLAGS="-O2 -Wall" -+CFLAGS="${CFLAGS} -O2 -Wall" - ## check for --enable-debug first before checking CFLAGS before - ## so that we don't mix -O and -g - AC_ARG_ENABLE(debug, --- -1.8.1.4 - diff --git a/0066-start-socket-listeners-on-iscsiadm-command.patch b/0066-start-socket-listeners-on-iscsiadm-command.patch deleted file mode 100644 index cb363b7..0000000 --- a/0066-start-socket-listeners-on-iscsiadm-command.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 89e9c2ff66d069b812fabcd4fefe453bbcea73e4 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 25 Nov 2013 22:28:12 -0800 -Subject: [PATCH] start socket listeners on iscsiadm command - -fix for trying to run iscsiadm commands right after installing the rpm -without manually starting the systemd units ---- - etc/iscsid.conf | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/etc/iscsid.conf b/etc/iscsid.conf -index 1fd3000..412f130 100644 ---- a/etc/iscsid.conf -+++ b/etc/iscsid.conf -@@ -17,7 +17,8 @@ - # maintainers. - # - # Default for Fedora and RHEL. (uncomment to activate). --#iscsid.startup = /bin/systemctl start iscsid.service -+# Use socket activation, but try to make sure the socket units are listening -+iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket - # - # Default for upstream open-iscsi scripts (uncomment to activate). - # iscsid.startup = /sbin/iscsid --- -1.8.3.1 - diff --git a/0099-use-Red-Hat-version-string-to-match-RPM-package-vers.patch b/0099-use-Red-Hat-version-string-to-match-RPM-package-vers.patch deleted file mode 100644 index c6398b1..0000000 --- a/0099-use-Red-Hat-version-string-to-match-RPM-package-vers.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1483a176fdbb22bbfecf06eea57d1aa200f30561 Mon Sep 17 00:00:00 2001 -From: Chris Leech -Date: Mon, 21 Jan 2013 15:43:36 -0800 -Subject: use Red Hat version string to match RPM package version - ---- - usr/version.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/usr/version.h b/usr/version.h -index a090522..aef0c3d 100644 ---- a/usr/version.h -+++ b/usr/version.h -@@ -6,7 +6,7 @@ - * This may not be the same value as the kernel versions because - * some other maintainer could merge a patch without going through us - */ --#define ISCSI_VERSION_STR "2.0-873" -+#define ISCSI_VERSION_STR "6.2.0.873-14" - #define ISCSI_VERSION_FILE "/sys/module/scsi_transport_iscsi/version" - - #endif --- -1.7.11.7 - diff --git a/0143-idmb_rec_write-check-for-tpgt-first.patch b/0143-idmb_rec_write-check-for-tpgt-first.patch new file mode 100644 index 0000000..cdc958a --- /dev/null +++ b/0143-idmb_rec_write-check-for-tpgt-first.patch @@ -0,0 +1,55 @@ +From 24a4d8156786dfd91dcc17b2472653e963ebd028 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 10:59:44 -0700 +Subject: idmb_rec_write, check for tpgt first + +Factor out the check for a tpgt to a single place, before going crazy on +the rec files. Makes flow of this function easier to follow, and preps +for splitting it up. +--- + usr/idbm.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/usr/idbm.c b/usr/idbm.c +index 1e4f8c8..0a88699 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1849,6 +1849,10 @@ static int idbm_rec_write(node_rec_t *rec) + if (rc) + goto free_portal; + ++ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ /* drop down to old style portal as config */ ++ goto open_conf; ++ + rc = stat(portal, &statb); + if (rc) { + rc = 0; +@@ -1857,23 +1861,11 @@ static int idbm_rec_write(node_rec_t *rec) + * set the tgpt. In new versions you must pass all the info in + * from the start + */ +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; +- else +- goto mkdir_portal; ++ goto mkdir_portal; + } + + if (!S_ISDIR(statb.st_mode)) { + /* +- * older iscsiadm versions had you create the config then set +- * set the tgpt. In new versions you must pass all the info in +- * from the start +- */ +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; +- /* + * Old style portal as a file, but with tpgt. Let's update it. + */ + if (unlink(portal)) { +-- +1.8.1.4 + diff --git a/0144-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch b/0144-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch new file mode 100644 index 0000000..358b50c --- /dev/null +++ b/0144-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch @@ -0,0 +1,61 @@ +From b1799fe84ed94a19bba6bcd7284ce8b038be4ffe Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 10 Dec 2012 13:20:47 -0800 +Subject: iscsid: add --initrd option to set run from initrd hint for systemd + +See http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons + +Signed-off-by: Chris Leech +--- + usr/iscsid.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/usr/iscsid.c b/usr/iscsid.c +index b4bb65b..7d71085 100644 +--- a/usr/iscsid.c ++++ b/usr/iscsid.c +@@ -61,6 +61,7 @@ static pid_t log_pid; + static gid_t gid; + static int daemonize = 1; + static int mgmt_ipc_fd; ++static int initrd = 0; + + static struct option const long_options[] = { + {"config", required_argument, NULL, 'c'}, +@@ -73,6 +74,7 @@ static struct option const long_options[] = { + {"pid", required_argument, NULL, 'p'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, ++ {"initrd", no_argument, &initrd, 1}, + {NULL, 0, NULL, 0}, + }; + +@@ -95,6 +97,7 @@ Open-iSCSI initiator daemon.\n\ + -p, --pid=pidfile use pid file (default " PID_FILE ").\n\ + -h, --help display this help and exit\n\ + -v, --version display version and exit\n\ ++ --initrd run from initrd\n\ + "); + } + exit(status); +@@ -383,12 +386,17 @@ int main(int argc, char *argv[]) + case 'h': + usage(0); + break; ++ case 0: ++ break; + default: + usage(1); + break; + } + } + ++ if (initrd) ++ argv[0][0] = '@'; ++ + /* initialize logger */ + log_pid = log_init(program_name, DEFAULT_AREA_SIZE, + daemonize ? log_do_log_daemon : log_do_log_std, NULL); +-- +1.7.11.7 + diff --git a/0145-idbm_rec_write-seperate-old-and-new-style-writes.patch b/0145-idbm_rec_write-seperate-old-and-new-style-writes.patch new file mode 100644 index 0000000..d138233 --- /dev/null +++ b/0145-idbm_rec_write-seperate-old-and-new-style-writes.patch @@ -0,0 +1,180 @@ +From 954a9492b5ed1de5907ad2a7d7cc0ae6215d8fac Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 11:34:31 -0700 +Subject: idbm_rec_write, seperate old and new style writes + +Duplicates a small bit of code, but easier to understand and extened. +--- + usr/idbm.c | 116 +++++++++++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 79 insertions(+), 37 deletions(-) + +diff --git a/usr/idbm.c b/usr/idbm.c +index 0a88699..cb6ffd1 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1808,7 +1808,7 @@ mkdir_portal: + return f; + } + +-static int idbm_rec_write(node_rec_t *rec) ++static int idbm_rec_write_new(node_rec_t *rec) + { + struct stat statb; + FILE *f; +@@ -1820,38 +1820,8 @@ static int idbm_rec_write(node_rec_t *rec) + log_error("Could not alloc portal\n"); + return ISCSI_ERR_NOMEM; + } +- +- snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); +- if (access(portal, F_OK) != 0) { +- if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s\n", portal, +- strerror(errno)); +- rc = ISCSI_ERR_IDBM; +- goto free_portal; +- } +- } +- +- snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); +- if (access(portal, F_OK) != 0) { +- if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s\n", portal, +- strerror(errno)); +- rc = ISCSI_ERR_IDBM; +- goto free_portal; +- } +- } +- + snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port); +- log_debug(5, "Looking for config file %s", portal); +- +- rc = idbm_lock(); +- if (rc) +- goto free_portal; +- +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; + + rc = stat(portal, &statb); + if (rc) { +@@ -1872,11 +1842,11 @@ static int idbm_rec_write(node_rec_t *rec) + log_error("Could not convert %s: %s\n", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + } else { + rc = ISCSI_ERR_INVAL; +- goto unlock; ++ goto free_portal; + } + + mkdir_portal: +@@ -1887,24 +1857,96 @@ mkdir_portal: + log_error("Could not make dir %s: %s\n", + portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + } + + snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt, + rec->iface.name); +-open_conf: ++/* open_conf: */ + f = fopen(portal, "w"); + if (!f) { + log_error("Could not open %s: %sd\n", portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + + idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); + fclose(f); +-unlock: ++free_portal: ++ free(portal); ++ return rc; ++} ++ ++static int idbm_rec_write_old(node_rec_t *rec) ++{ ++ FILE *f; ++ char *portal; ++ int rc = 0; ++ ++ portal = malloc(PATH_MAX); ++ if (!portal) { ++ log_error("Could not alloc portal\n"); ++ return ISCSI_ERR_NOMEM; ++ } ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ ++ f = fopen(portal, "w"); ++ if (!f) { ++ log_error("Could not open %s: %sd\n", portal, strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); ++ fclose(f); ++free_portal: ++ free(portal); ++ return rc; ++} ++ ++static int idbm_rec_write(node_rec_t *rec) ++{ ++ char *portal; ++ int rc = 0; ++ ++ portal = malloc(PATH_MAX); ++ if (!portal) { ++ log_error("Could not alloc portal\n"); ++ return ISCSI_ERR_NOMEM; ++ } ++ ++ snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); ++ if (access(portal, F_OK) != 0) { ++ if (mkdir(portal, 0660) != 0) { ++ log_error("Could not make %s: %s\n", portal, ++ strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ } ++ ++ snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); ++ if (access(portal, F_OK) != 0) { ++ if (mkdir(portal, 0660) != 0) { ++ log_error("Could not make %s: %s\n", portal, ++ strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ } ++ ++ rc = idbm_lock(); ++ if (rc) ++ goto free_portal; ++ ++ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ /* old style portal as config */ ++ rc = idbm_rec_write_old(rec); ++ else ++ rc = idbm_rec_write_new(rec); ++ + idbm_unlock(); + free_portal: + free(portal); +-- +1.8.1.4 + diff --git a/0146-idbw_rec_write-pick-tpgt-from-existing-record.patch b/0146-idbw_rec_write-pick-tpgt-from-existing-record.patch new file mode 100644 index 0000000..894eb4b --- /dev/null +++ b/0146-idbw_rec_write-pick-tpgt-from-existing-record.patch @@ -0,0 +1,76 @@ +From cdb98072f7690cd9f5ec4aa5aa503711e552b5da Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 12:39:07 -0700 +Subject: idbw_rec_write, pick tpgt from existing record + +On a static add (-m node -o new) without a user specified tpgt, looks +for existing new style records with tpgt before creating an old style +record without. If one exists, take the tpgt from it an write an +updated new style record instead. +--- + usr/idbm.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/usr/idbm.c b/usr/idbm.c +index cb6ffd1..5adbd95 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -1884,12 +1885,47 @@ static int idbm_rec_write_old(node_rec_t *rec) + FILE *f; + char *portal; + int rc = 0; ++ glob_t globbuf; ++ int i; ++ int tpgt = PORTAL_GROUP_TAG_UNKNOWN; + + portal = malloc(PATH_MAX); + if (!portal) { + log_error("Could not alloc portal\n"); + return ISCSI_ERR_NOMEM; + } ++ ++ /* check for newer portal dir with tpgt */ ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,*", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ rc = glob(portal, GLOB_ONLYDIR, NULL, &globbuf); ++ if (!rc) { ++ if (globbuf.gl_pathc > 1) ++ log_warning("multiple tpg records for portal " ++ "%s/%s:%d found", rec->name, ++ rec->conn[0].address, rec->conn[0].port); ++ /* set pattern for sscanf matching of tpgt */ ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%%u", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ for (i = 0; i < globbuf.gl_pathc; i++) { ++ rc = sscanf(globbuf.gl_pathv[i], portal, &tpgt); ++ if (rc == 1) ++ break; ++ } ++ if (tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ log_warning("glob match on existing records, " ++ "but no valid tpgt found"); ++ } ++ globfree(&globbuf); ++ ++ /* if a tpgt was selected from an old record, write entry in new format */ ++ if (tpgt != PORTAL_GROUP_TAG_UNKNOWN) { ++ log_warning("using tpgt %u from existing record", tpgt); ++ rec->tpgt = tpgt; ++ free(portal); ++ return idbm_rec_write_new(rec); ++ } ++ + snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port); + +-- +1.8.1.4 + diff --git a/0147-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch b/0147-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch new file mode 100644 index 0000000..537a947 --- /dev/null +++ b/0147-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch @@ -0,0 +1,158 @@ +From e5d7c7070358a5db8b849c8c5886e67881fe8906 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Fri, 7 Dec 2012 17:01:42 -0800 +Subject: [PATCH 47/47] iscsiadm, iscsid: newroot command to survive + switch_root + +When started from initramfs, iscsid needs to be able to chroot itself +to the runtime filesystem before the switch_root occurs. In the +initramfs "iscsiadm --newroot {root fs mount before switch}" should be +called before the switch_root. + +Signed-off-by: Chris Leech +--- + usr/iscsiadm.c | 30 ++++++++++++++++++++++++++++++ + usr/mgmt_ipc.c | 11 +++++++++++ + usr/mgmt_ipc.h | 6 +++++- + 3 files changed, 46 insertions(+), 1 deletion(-) + +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index da0a3ec..af6d607 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -117,6 +117,7 @@ static struct option const long_options[] = + {"interval", required_argument, NULL, 'i'}, + {"flashnode_idx", optional_argument, NULL, 'x'}, + {"portal_type", optional_argument, NULL, 'A'}, ++ {"newroot", required_argument, NULL, 0}, + {NULL, 0, NULL, 0}, + }; + static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:"; +@@ -137,6 +138,7 @@ iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid + iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\ + iscsiadm -m fw [ -d debug_level ] [ -l ]\n\ + iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ] | [ -C flashnode [ -o operation ] [ -A portal_type ] [ -x flashnode_idx ] [ -n name ] [ -v value ] ] ]\n\ ++iscsiadm --newroot switch_root_path\n\ + iscsiadm -k priority\n"); + } + exit(status); +@@ -278,6 +280,22 @@ static void kill_iscsid(int priority) + } + } + ++static void do_newroot(char *newroot) ++{ ++ iscsiadm_req_t req; ++ iscsiadm_rsp_t rsp; ++ int rc; ++ ++ memset(&req, 0, sizeof(req)); ++ req.command = MGMT_IPC_NEWROOT; ++ strncpy(req.u.newroot.path, newroot, PATH_MAX); ++ rc = iscsid_exec_req(&req, &rsp, 0); ++ if (rc) { ++ iscsi_err_print_msg(rc); ++ log_error("Could not send NEWROOT command"); ++ } ++} ++ + /* + * TODO: we can display how the ifaces are related to node records. + * And we can add a scsi_host mode which would display how +@@ -2800,6 +2818,7 @@ main(int argc, char **argv) + { + char *ip = NULL, *name = NULL, *value = NULL; + char *targetname = NULL, *group_session_mgmt_mode = NULL; ++ char *newroot = NULL; + int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0; + int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0; + int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0; +@@ -2837,6 +2856,12 @@ main(int argc, char **argv) + while ((ch = getopt_long(argc, argv, short_options, + long_options, &longindex)) >= 0) { + switch (ch) { ++ case 0: ++ if (long_options[longindex].flag != 0) ++ break; ++ if (!strcmp(long_options[longindex].name, "newroot")) ++ newroot = optarg; ++ break; + case 'k': + killiscsid = atoi(optarg); + if (killiscsid < 0) { +@@ -2989,6 +3014,11 @@ main(int argc, char **argv) + goto free_ifaces; + } + ++ if (newroot) { ++ do_newroot(newroot); ++ goto free_ifaces; ++ } ++ + if (mode < 0) + usage(ISCSI_ERR_INVAL); + +diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c +index 87bd346..5cb7143 100644 +--- a/usr/mgmt_ipc.c ++++ b/usr/mgmt_ipc.c +@@ -226,6 +226,16 @@ mgmt_ipc_immediate_stop(queue_task_t *qtask) + } + + static int ++mgmt_ipc_newroot(queue_task_t *qtask) ++{ ++ char *newroot = qtask->req.u.newroot.path; ++ if (chdir(newroot) || chroot(".") || chdir("/")) ++ return ISCSI_ERR; ++ mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS); ++ return ISCSI_SUCCESS; ++} ++ ++static int + mgmt_ipc_conn_remove(queue_task_t *qtask) + { + return ISCSI_ERR; +@@ -534,6 +544,7 @@ static mgmt_ipc_fn_t * mgmt_ipc_functions[__MGMT_IPC_MAX_COMMAND] = { + [MGMT_IPC_NOTIFY_DEL_NODE] = mgmt_ipc_notify_del_node, + [MGMT_IPC_NOTIFY_ADD_PORTAL] = mgmt_ipc_notify_add_portal, + [MGMT_IPC_NOTIFY_DEL_PORTAL] = mgmt_ipc_notify_del_portal, ++[MGMT_IPC_NEWROOT] = mgmt_ipc_newroot, + }; + + void mgmt_ipc_handle(int accept_fd) +diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h +index 55972ed..102ffff 100644 +--- a/usr/mgmt_ipc.h ++++ b/usr/mgmt_ipc.h +@@ -22,6 +22,7 @@ + #include "types.h" + #include "iscsi_if.h" + #include "config.h" ++#include "limits.h" + + #define ISCSIADM_NAMESPACE "ISCSIADM_ABSTRACT_NAMESPACE" + #define PEERUSER_MAX 64 +@@ -46,6 +47,7 @@ typedef enum iscsiadm_cmd { + MGMT_IPC_NOTIFY_DEL_NODE = 17, + MGMT_IPC_NOTIFY_ADD_PORTAL = 18, + MGMT_IPC_NOTIFY_DEL_PORTAL = 19, ++ MGMT_IPC_NEWROOT = 20, + + __MGMT_IPC_MAX_COMMAND + } iscsiadm_cmd_e; +@@ -75,8 +77,10 @@ typedef struct iscsiadm_req { + int param; + /* TODO: make this variable len to support */ + char value[IFNAMSIZ + 1]; +- + } set_host_param; ++ struct ipc_msg_newroot { ++ char path[PATH_MAX + 1]; ++ } newroot; + } u; + } iscsiadm_req_t; + +-- +1.8.1.4 + diff --git a/0147-iscsiuio-systemd-socket-activation-support.patch b/0147-iscsiuio-systemd-socket-activation-support.patch new file mode 100644 index 0000000..896eba9 --- /dev/null +++ b/0147-iscsiuio-systemd-socket-activation-support.patch @@ -0,0 +1,58 @@ +From 8003178db245b43d04b27b559d5541ced24ec13f Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 19 Dec 2012 21:39:06 -0800 +Subject: [PATCH] iscsiuio systemd socket activation support + +--- + iscsiuio/src/unix/iscsid_ipc.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/iscsiuio/src/unix/iscsid_ipc.c b/iscsiuio/src/unix/iscsid_ipc.c +index e22de0d..4908cb7 100644 +--- a/iscsiuio/src/unix/iscsid_ipc.c ++++ b/iscsiuio/src/unix/iscsid_ipc.c +@@ -948,6 +948,30 @@ static void *iscsid_loop(void *arg) + pthread_exit(NULL); + } + ++#define SD_SOCKET_FDS_START 3 ++ ++static int ipc_systemd(void) ++{ ++ char *env; ++ ++ env = getenv("LISTEN_PID"); ++ ++ if (!env || (strtoul(env, NULL, 10) != getpid())) ++ return -EINVAL; ++ ++ env = getenv("LISTEN_FDS"); ++ ++ if (!env) ++ return -EINVAL; ++ ++ if (strtoul(env, NULL, 10) != 1) { ++ LOG_ERR("Did not receive exactly one IPC socket from systemd"); ++ return -EINVAL; ++ } ++ ++ return SD_SOCKET_FDS_START; ++} ++ + /****************************************************************************** + * Initialize/Cleanup routines + ******************************************************************************/ +@@ -961,6 +985,10 @@ int iscsid_init() + int rc, addr_len; + struct sockaddr_un addr; + ++ iscsid_opts.fd = ipc_systemd(); ++ if (iscsid_opts.fd >= 0) ++ return 0; ++ + iscsid_opts.fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (iscsid_opts.fd < 0) { + LOG_ERR(PFX "Can not create IPC socket"); +-- +1.8.3.1 + diff --git a/0148-iscsiadm-param-parsing-for-advanced-node-creation.patch b/0148-iscsiadm-param-parsing-for-advanced-node-creation.patch new file mode 100644 index 0000000..a39833b --- /dev/null +++ b/0148-iscsiadm-param-parsing-for-advanced-node-creation.patch @@ -0,0 +1,337 @@ +From b58f3b48a36821d10a3377acfcbf18113fba0c9d Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 18 Dec 2012 11:27:00 -0800 +Subject: [PATCH 48/48] iscsiadm: --param parsing for advanced node creation + +Share parse_param and apply_param code from iscsistart, allow using multiple +--param options to set arbitrary fields in node mode. + +Signed-off-by: Chris Leech +--- + usr/Makefile | 2 +- + usr/iscsi_param.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + usr/iscsi_param.h | 7 ++++ + usr/iscsiadm.c | 16 ++++++++-- + usr/iscsistart.c | 91 ++-------------------------------------------------- + 5 files changed, 120 insertions(+), 91 deletions(-) + create mode 100644 usr/iscsi_param.c + create mode 100644 usr/iscsi_param.h + +diff --git a/usr/Makefile b/usr/Makefile +index 3d8ee22..a7e80c0 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -40,7 +40,7 @@ SYSDEPS_SRCS = $(wildcard ../utils/sysdeps/*.o) + ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \ + sha1.o iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \ + iscsi_net_util.o iscsid_req.o transport.o iser.o cxgbi.o be2iscsi.o \ +- initiator_common.o iscsi_err.o flashnode.o uip_mgmt_ipc.o \ ++ initiator_common.o iscsi_err.o iscsi_param.o flashnode.o uip_mgmt_ipc.o \ + $(IPC_OBJ) $(SYSDEPS_SRCS) + # core initiator files + INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o kern_err_table.o +diff --git a/usr/iscsi_param.c b/usr/iscsi_param.c +new file mode 100644 +index 0000000..c075e8f +--- /dev/null ++++ b/usr/iscsi_param.c +@@ -0,0 +1,95 @@ ++#include ++#include "log.h" ++#include "config.h" ++#include "idbm.h" ++#include "list.h" ++#include "iface.h" ++#include "idbm_fields.h" ++#include "iscsi_err.h" ++ ++int apply_params(struct list_head *user_params, struct node_rec *rec) ++{ ++ struct user_param *param; ++ int rc; ++ ++ /* Must init this so we can check if user overrode them */ ++ rec->session.initial_login_retry_max = -1; ++ rec->conn[0].timeo.noop_out_interval = -1; ++ rec->conn[0].timeo.noop_out_timeout = -1; ++ ++ list_for_each_entry(param, user_params, list) { ++ /* ++ * user may not have passed in all params that were set by ++ * ibft/iscsi_boot, so clear out values that might conflict ++ * with user overrides ++ */ ++ if (!strcmp(param->name, IFACE_NETNAME)) { ++ /* overriding netname so MAC will be for old netdev */ ++ memset(rec->iface.hwaddress, 0, ++ sizeof(rec->iface.hwaddress)); ++ } else if (!strcmp(param->name, IFACE_HWADDR)) { ++ /* overriding MAC so netdev will be for old MAC */ ++ memset(rec->iface.netdev, 0, sizeof(rec->iface.netdev)); ++ } else if (!strcmp(param->name, IFACE_TRANSPORTNAME)) { ++ /* ++ * switching drivers so all old binding info is no ++ * longer valid. Old values were either for offload ++ * and we are switching to software or the reverse, ++ * or switching types of cards (bnx2i to cxgb3i). ++ */ ++ memset(&rec->iface, 0, sizeof(rec->iface)); ++ iface_setup_defaults(&rec->iface); ++ } ++ } ++ ++ rc = idbm_node_set_rec_from_param(user_params, rec, 0); ++ if (rc) ++ return rc; ++ ++ /* ++ * For root boot we could not change this in older versions so ++ * if user did not override then use the defaults. ++ * ++ * Increase to account for boot using static setup. ++ */ ++ if (rec->session.initial_login_retry_max == -1) ++ rec->session.initial_login_retry_max = 30; ++ /* we used to not be able to answer so turn off */ ++ if (rec->conn[0].timeo.noop_out_interval == -1) ++ rec->conn[0].timeo.noop_out_interval = 0; ++ if (rec->conn[0].timeo.noop_out_timeout == -1) ++ rec->conn[0].timeo.noop_out_timeout = 0; ++ ++ return 0; ++} ++ ++int parse_param(struct list_head *user_params, char *param_str) ++{ ++ struct user_param *param; ++ char *name, *value; ++ ++ name = param_str; ++ ++ value = strchr(param_str, '='); ++ if (!value) { ++ log_error("Invalid --param %s. Missing value.", param_str); ++ return ISCSI_ERR_INVAL; ++ } ++ *value = '\0'; ++ ++ value++; ++ if (!strlen(value)) { ++ log_error("Invalid --param %s. Missing value.", param_str); ++ return ISCSI_ERR_INVAL; ++ } ++ ++ param = idbm_alloc_user_param(name, value); ++ if (!param) { ++ log_error("Could not allocate memory for param."); ++ return ISCSI_ERR_NOMEM; ++ } ++ ++ list_add(¶m->list, user_params); ++ return 0; ++} ++ +diff --git a/usr/iscsi_param.h b/usr/iscsi_param.h +new file mode 100644 +index 0000000..8b7956c +--- /dev/null ++++ b/usr/iscsi_param.h +@@ -0,0 +1,7 @@ ++#ifndef ISCSI_PARAM_H ++#define ISCSI_PARAM_H ++ ++extern int parse_param(struct list_head *user_params, char *param_str); ++extern int apply_params(struct list_head *user_params, struct node_rec *rec); ++ ++#endif +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index af6d607..2003d48 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -53,6 +53,7 @@ + #include "iscsi_err.h" + #include "iscsi_ipc.h" + #include "iscsi_timer.h" ++#include "iscsi_param.h" + #include "flashnode.h" + + static char program_name[] = "iscsiadm"; +@@ -118,6 +119,7 @@ static struct option const long_options[] = + {"flashnode_idx", optional_argument, NULL, 'x'}, + {"portal_type", optional_argument, NULL, 'A'}, + {"newroot", required_argument, NULL, 0}, ++ {"param", required_argument, NULL, 0}, + {NULL, 0, NULL, 0}, + }; + static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:"; +@@ -133,7 +135,7 @@ iscsiadm -m discoverydb [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p + [ -o operation ] [ -n name ] [ -v value ] [ -lD ] ] \n\ + iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ [ -p ip:port ] [ -l | -D ] ] \n\ + iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I ifaceN ] [ -l | -u | -R | -s] ] \ +-[ [ -o operation ] [ -n name ] [ -v value ] ]\n\ ++[ [ -o operation ] [ -n name ] [ -v value ] ] [ --param=NAME=VALUE ]\n\ + iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\ + iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\ + iscsiadm -m fw [ -d debug_level ] [ -l ]\n\ +@@ -2834,9 +2836,11 @@ main(int argc, char **argv) + uint32_t host_no = -1; + struct user_param *param; + struct list_head params; ++ struct list_head user_params; + + INIT_LIST_HEAD(¶ms); + INIT_LIST_HEAD(&ifaces); ++ INIT_LIST_HEAD(&user_params); + /* do not allow ctrl-c for now... */ + memset(&sa_old, 0, sizeof(struct sigaction)); + memset(&sa_new, 0, sizeof(struct sigaction)); +@@ -2859,8 +2863,14 @@ main(int argc, char **argv) + case 0: + if (long_options[longindex].flag != 0) + break; +- if (!strcmp(long_options[longindex].name, "newroot")) ++ if (!strcmp(long_options[longindex].name, "newroot")) { + newroot = optarg; ++ break; ++ } ++ if (!strcmp(long_options[longindex].name, "param")) { ++ parse_param(&user_params, optarg); ++ break; ++ } + break; + case 'k': + killiscsid = atoi(optarg); +@@ -3169,6 +3179,8 @@ main(int argc, char **argv) + goto out; + } + ++ apply_params(&user_params, rec); ++ + rc = exec_node_op(op, do_login, do_logout, do_show, + do_rescan, do_stats, info_level, rec, + ¶ms); +diff --git a/usr/iscsistart.c b/usr/iscsistart.c +index 6924d49..85be35b 100644 +--- a/usr/iscsistart.c ++++ b/usr/iscsistart.c +@@ -50,6 +50,7 @@ + #include "iscsid_req.h" + #include "iscsi_err.h" + #include "iface.h" ++#include "iscsi_param.h" + + /* global config info */ + /* initiator needs initiator name/alias */ +@@ -131,99 +132,13 @@ static int stop_event_loop(void) + return rc; + } + +-static int apply_params(struct node_rec *rec) +-{ +- struct user_param *param; +- int rc; +- +- /* Must init this so we can check if user overrode them */ +- rec->session.initial_login_retry_max = -1; +- rec->conn[0].timeo.noop_out_interval = -1; +- rec->conn[0].timeo.noop_out_timeout = -1; +- +- list_for_each_entry(param, &user_params, list) { +- /* +- * user may not have passed in all params that were set by +- * ibft/iscsi_boot, so clear out values that might conflict +- * with user overrides +- */ +- if (!strcmp(param->name, IFACE_NETNAME)) { +- /* overriding netname so MAC will be for old netdev */ +- memset(rec->iface.hwaddress, 0, +- sizeof(rec->iface.hwaddress)); +- } else if (!strcmp(param->name, IFACE_HWADDR)) { +- /* overriding MAC so netdev will be for old MAC */ +- memset(rec->iface.netdev, 0, sizeof(rec->iface.netdev)); +- } else if (!strcmp(param->name, IFACE_TRANSPORTNAME)) { +- /* +- * switching drivers so all old binding info is no +- * longer valid. Old values were either for offload +- * and we are switching to software or the reverse, +- * or switching types of cards (bnx2i to cxgb3i). +- */ +- memset(&rec->iface, 0, sizeof(rec->iface)); +- iface_setup_defaults(&rec->iface); +- } +- } +- +- rc = idbm_node_set_rec_from_param(&user_params, rec, 0); +- if (rc) +- return rc; +- +- /* +- * For root boot we could not change this in older versions so +- * if user did not override then use the defaults. +- * +- * Increase to account for boot using static setup. +- */ +- if (rec->session.initial_login_retry_max == -1) +- rec->session.initial_login_retry_max = 30; +- /* we used to not be able to answer so turn off */ +- if (rec->conn[0].timeo.noop_out_interval == -1) +- rec->conn[0].timeo.noop_out_interval = 0; +- if (rec->conn[0].timeo.noop_out_timeout == -1) +- rec->conn[0].timeo.noop_out_timeout = 0; +- +- return 0; +-} +- +-static int parse_param(char *param_str) +-{ +- struct user_param *param; +- char *name, *value; +- +- name = param_str; +- +- value = strchr(param_str, '='); +- if (!value) { +- log_error("Invalid --param %s. Missing value.", param_str); +- return ISCSI_ERR_INVAL; +- } +- *value = '\0'; +- +- value++; +- if (!strlen(value)) { +- log_error("Invalid --param %s. Missing value.", param_str); +- return ISCSI_ERR_INVAL; +- } +- +- param = idbm_alloc_user_param(name, value); +- if (!param) { +- log_error("Could not allocate memory for param."); +- return ISCSI_ERR_NOMEM; +- } +- +- list_add(¶m->list, &user_params); +- return 0; +-} +- + static int login_session(struct node_rec *rec) + { + iscsiadm_req_t req; + iscsiadm_rsp_t rsp; + int rc, retries = 0; + +- rc = apply_params(rec); ++ rc = apply_params(&user_params, rec); + if (rc) + return rc; + +@@ -426,7 +341,7 @@ int main(int argc, char *argv[]) + fw_free_targets(&targets); + exit(0); + case 'P': +- err = parse_param(optarg); ++ err = parse_param(&user_params, optarg); + if (err) + exit(err); + break; +-- +1.8.1.4 + diff --git a/0149-update-systemd-service-files-add-iscsi.service-for-s.patch b/0149-update-systemd-service-files-add-iscsi.service-for-s.patch new file mode 100644 index 0000000..966bb9f --- /dev/null +++ b/0149-update-systemd-service-files-add-iscsi.service-for-s.patch @@ -0,0 +1,93 @@ +From 1c3b1d23e0b3f17399ffd4463cafad813b0444d5 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 19 Dec 2012 15:07:36 -0800 +Subject: update systemd service files, add iscsi.service for starting + sessions on boot + +Signed-off-by: Chris Leech +--- + etc/systemd/iscsi.service | 19 +++++++++++++++++++ + etc/systemd/iscsi_mark_root_nodes | 14 ++++++++++++++ + etc/systemd/iscsid.service | 7 +++++-- + etc/systemd/iscsid.socket | 2 +- + 4 files changed, 39 insertions(+), 3 deletions(-) + create mode 100644 etc/systemd/iscsi.service + create mode 100755 etc/systemd/iscsi_mark_root_nodes + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +new file mode 100644 +index 0000000..bbd52fd +--- /dev/null ++++ b/etc/systemd/iscsi.service +@@ -0,0 +1,19 @@ ++[Unit] ++Description=Login and scanning of iSCSI devices ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++ConditionPathExists=/etc/iscsi/initiatorname.iscsi ++ ++[Service] ++Type=oneshot ++RemainAfterExit=true ++ExecStart=/usr/libexec/iscsi_mark_root_nodes ++ExecStart=/sbin/iscsiadm -m node --loginall=automatic ++ExecStop=/bin/sync ++ExecStop=/sbin/iscsiadm -m node --logoutall=automatic ++ ++[Install] ++WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes +new file mode 100755 +index 0000000..c68475c +--- /dev/null ++++ b/etc/systemd/iscsi_mark_root_nodes +@@ -0,0 +1,14 @@ ++#!/bin/bash ++ ++ISCSIADM=/sbin/iscsiadm ++SESSION_FILE=/run/initramfs/iscsi.sessions ++ ++if [ ! -f $SESSION_FILE ] ; then ++ exit 0 ++fi ++ ++while read t num i target; do ++ ip=${i%:*} ++ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot ++done < $SESSION_FILE ++ +diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service +index 028e0b3..653dd08 100644 +--- a/etc/systemd/iscsid.service ++++ b/etc/systemd/iscsid.service +@@ -1,7 +1,10 @@ + [Unit] + Description=Open-iSCSI +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) +-After=network.target NetworkManager-wait-online.service iscsiuio.service tgtd.service targetcli.service ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=network.target iscsiuio.service ++Before=remote-fs-pre.target + + [Service] + Type=forking +diff --git a/etc/systemd/iscsid.socket b/etc/systemd/iscsid.socket +index 832451d..58a8d12 100644 +--- a/etc/systemd/iscsid.socket ++++ b/etc/systemd/iscsid.socket +@@ -1,6 +1,6 @@ + [Unit] + Description=Open-iSCSI iscsid Socket +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) ++Documentation=man:iscsid(8) man:iscsiadm(8) + + [Socket] + ListenStream=@ISCSIADM_ABSTRACT_NAMESPACE +-- +1.7.11.7 + diff --git a/0150-iscsi-boot-related-service-file-updates.patch b/0150-iscsi-boot-related-service-file-updates.patch new file mode 100644 index 0000000..19450ee --- /dev/null +++ b/0150-iscsi-boot-related-service-file-updates.patch @@ -0,0 +1,75 @@ +From 8f79529354b4023c371e00091f11bdd523497639 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Aug 2013 07:18:25 -0700 +Subject: iscsi boot related service file updates + +make sure iscsid gets started if there are any boot sessions running +add reload target to fix double session problem when restarting from NM +don't rely on session list passed from initrd, never got fully implemented +--- + etc/systemd/iscsi-mark-root-nodes | 13 +++++++++++++ + etc/systemd/iscsi.service | 3 ++- + etc/systemd/iscsi_mark_root_nodes | 14 -------------- + 3 files changed, 15 insertions(+), 15 deletions(-) + create mode 100644 etc/systemd/iscsi-mark-root-nodes + delete mode 100644 etc/systemd/iscsi_mark_root_nodes + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +new file mode 100644 +index 0000000..157be62 +--- /dev/null ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -0,0 +1,13 @@ ++#!/bin/bash ++ ++ISCSIADM=/sbin/iscsiadm ++ ++$ISCSIADM -m session >/dev/null 2>&1 || exit 0 ++ ++$ISCSIADM -m session | while read t num i target; do ++ ip=${i%:*} ++ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot ++done ++ ++systemctl start iscsid.service ++ +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index 7b4efee..d5712bd 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -10,10 +10,11 @@ ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes + [Service] + Type=oneshot + RemainAfterExit=true +-ExecStart=/usr/libexec/iscsi_mark_root_nodes ++ExecStart=/usr/libexec/iscsi-mark-root-nodes + ExecStart=/sbin/iscsiadm -m node --loginall=automatic + ExecStop=/bin/sync + ExecStop=/sbin/iscsiadm -m node --logoutall=automatic ++ExecReload=/sbin/iscsiadm -m node --loginall=automatic + + [Install] + WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes +deleted file mode 100644 +index c68475c..0000000 +--- a/etc/systemd/iscsi_mark_root_nodes ++++ /dev/null +@@ -1,14 +0,0 @@ +-#!/bin/bash +- +-ISCSIADM=/sbin/iscsiadm +-SESSION_FILE=/run/initramfs/iscsi.sessions +- +-if [ ! -f $SESSION_FILE ] ; then +- exit 0 +-fi +- +-while read t num i target; do +- ip=${i%:*} +- $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot +-done < $SESSION_FILE +- +-- +1.8.1.4 + diff --git a/0151-update-initscripts-and-docs.patch b/0151-update-initscripts-and-docs.patch new file mode 100644 index 0000000..e2d4cdc --- /dev/null +++ b/0151-update-initscripts-and-docs.patch @@ -0,0 +1,130 @@ +From c255c2cd43afeaefa428237a3200f02fb238d89e Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:37:13 -0800 +Subject: update initscripts and docs + +--- + README | 9 +++------ + etc/iscsid.conf | 23 +++++++++++------------ + usr/idbm.c | 4 ++++ + 3 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/README b/README +index ec22098..2a8319a 100644 +--- a/README ++++ b/README +@@ -74,11 +74,6 @@ the cache sync command will fail. + - iscsiadm's -P 3 option will not print out scsi devices. + - iscsid will not automatically online devices. + +-You need to enable "Cryptographic API" under "Cryptographic options" in the +-kernel config. And you must enable "CRC32c CRC algorithm" even if +-you do not use header or data digests. They are the kernel options, +-CONFIG_CRYPTO and CONFIG_CRYPTO_CRC32C, respectively. +- + By default the kernel's iSCSI modules will be used. Running: + + make +@@ -997,7 +992,7 @@ Red Hat or Fedora: + ----------------- + To start open-iscsi in Red Hat/Fedora you can do: + +- service open-iscsi start ++ service iscsi start + + To get open-iscsi to automatically start at run time you may have to + run: +@@ -1205,6 +1200,8 @@ iscsid will only perform rediscovery when it gets a SCN from the server. + # linux-isns (SLES's iSNS server) where it sometimes does not send SCN + # events in the proper format, so they may not get handled. + ++To set the startup value, so that nodes are not logged into automatically ++use the value "manual". + + Example: + -------- +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index ef76dc0..ac1d231 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -17,10 +17,10 @@ + # maintainers. + # + # Default for Fedora and RHEL. (uncomment to activate). +-# iscsid.startup = /etc/rc.d/init.d/iscsid force-start ++iscsid.startup = /etc/rc.d/init.d/iscsid force-start + # + # Default for upstream open-iscsi scripts (uncomment to activate). +-iscsid.startup = /sbin/iscsid ++# iscsid.startup = /sbin/iscsid + + + ############################# +@@ -36,8 +36,8 @@ iscsid.startup = /sbin/iscsid + # To request that the iscsi initd scripts startup a session set to "automatic". + # node.startup = automatic + # +-# To manually startup the session set to "manual". The default is manual. +-node.startup = manual ++# To manually startup the session set to "manual". The default is automatic. ++node.startup = automatic + + # For "automatic" startup nodes, setting this to "Yes" will try logins on each + # available iface until one succeeds, and then stop. The default "No" will try +@@ -259,28 +259,27 @@ node.conn[0].iscsi.MaxXmitDataSegmentLength = 0 + discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 + + # To allow the targets to control the setting of the digest checking, +-# with the initiator requesting a preference of enabling the checking, uncomment# one or both of the following lines: ++# with the initiator requesting a preference of enabling the checking, uncomment ++# the following lines (Data digests are not supported.): + #node.conn[0].iscsi.HeaderDigest = CRC32C,None +-#node.conn[0].iscsi.DataDigest = CRC32C,None ++ + # + # To allow the targets to control the setting of the digest checking, + # with the initiator requesting a preference of disabling the checking, +-# uncomment one or both of the following lines: ++# uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = None,CRC32C +-#node.conn[0].iscsi.DataDigest = None,CRC32C + # + # To enable CRC32C digest checking for the header and/or data part of +-# iSCSI PDUs, uncomment one or both of the following lines: ++# iSCSI PDUs, uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = CRC32C +-#node.conn[0].iscsi.DataDigest = CRC32C + # + # To disable digest checking for the header and/or data part of +-# iSCSI PDUs, uncomment one or both of the following lines: ++# iSCSI PDUs, uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = None +-#node.conn[0].iscsi.DataDigest = None + # + # The default is to never use DataDigests or HeaderDigests. + # ++node.conn[0].iscsi.HeaderDigest = None + + # For multipath configurations, you may want more than one session to be + # created on each iface record. If node.session.nr_sessions is greater +diff --git a/usr/idbm.c b/usr/idbm.c +index 4d30aa9..a1d7d37 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -399,9 +399,13 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + IDBM_SHOW, "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); + sprintf(key, CONN_DATA_DIGEST, i); ++ ++#if 0 ++We do not support data digests + __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW, + "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); ++#endif + sprintf(key, CONN_IFMARKER, i); + __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW, + "No", "Yes", num, 1); +-- +1.7.11.7 + diff --git a/0152-use-var-for-config.patch b/0152-use-var-for-config.patch new file mode 100644 index 0000000..2e4288c --- /dev/null +++ b/0152-use-var-for-config.patch @@ -0,0 +1,239 @@ +From be8702e609fdfd417547f758cb88956066b63023 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:38:45 -0800 +Subject: use var for config + +--- + README | 33 ++++++++++++++++----------------- + doc/iscsiadm.8 | 8 ++++---- + usr/idbm.c | 6 +++--- + usr/idbm.h | 13 +++++++------ + usr/iface.h | 4 +++- + 5 files changed, 33 insertions(+), 31 deletions(-) + +diff --git a/README b/README +index 90e2074..9cc62ca 100644 +--- a/README ++++ b/README +@@ -156,8 +156,7 @@ Usage: iscsid [OPTION] + + Open-iSCSI persistent configuration is stored in a number of + directories under a configuration root directory, using a flat-file +-format. This configuration root directory is /etc/iscsi by default, +-but may also commonly be in /var/lib/iscsi. ++format. This configuration root directory is /var/lib/iscsi by default. + + Configuration is contained in directories for: + +@@ -467,7 +466,7 @@ a scsi_host per HBA port). + To manage both types of initiator stacks, iscsiadm uses the interface (iface) + structure. For each HBA port or for software iscsi for each network + device (ethX) or NIC, that you wish to bind sessions to you must create +-a iface config /etc/iscsi/ifaces. ++a iface config /var/lib/iscsi/ifaces. + + Prep: + +@@ -501,29 +500,29 @@ Running: + iface0 qla4xxx,00:c0:dd:08:63:e8,20.15.0.7,default,iqn.2005-06.com.redhat:madmax + iface1 qla4xxx,00:c0:dd:08:63:ea,20.15.0.9,default,iqn.2005-06.com.redhat:madmax + +-Will report iface configurations that are setup in /etc/iscsi/ifaces. ++Will report iface configurations that are setup in /var/lib/iscsi/ifaces. + The format is: + + iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname + + For software iscsi, you can create the iface configs by hand, but it is + reccomended that you use iscsiadm's iface mode. There is a iface.example in +-/etc/iscsi/ifaces which can be used as a template for the daring. ++/var/lib/iscsi/ifaces which can be used as a template for the daring. + + For each network object you wish to bind a session to you must create +-a seperate iface config in /etc/iscsi/ifaces and each iface config file ++a seperate iface config in /var/lib/iscsi/ifaces and each iface config file + must have a unique name which is less than or equal to 64 characters. + + Example: + + If you have NIC1 with MAC address 00:0F:1F:92:6B:BF and NIC2 with + MAC address 00:C0:DD:08:63:E7 and you wanted to do software iscsi over +-TCP/IP. Then in /etc/iscsi/ifaces/iface0 you would enter: ++TCP/IP. Then in /var/lib/iscsi/ifaces/iface0 you would enter: + + iface.transport_name = tcp + iface.hwaddress = 00:0F:1F:92:6B:BF + +-and in /etc/iscsi/ifaces/iface1 you would enter: ++and in /var/lib/iscsi/ifaces/iface1 you would enter: + + iface.transport_name = tcp + iface.hwaddress = 00:C0:DD:08:63:E7 +@@ -573,7 +572,7 @@ cxgb3i.00:07:43:05:97:07 cxgb3i,00:07:43:05:97:07,,, + qla4xxx.00:0e:1e:04:8b:2e qla4xxx,00:0e:1e:04:8b:2e,,, + + +-Will report iface configurations that are setup in /etc/iscsi/ifaces. ++Will report iface configurations that are setup in /var/lib/iscsi/ifaces. + The format is: + + iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname +@@ -659,7 +658,7 @@ need a seperate network connection to the target for discovery purposes. + *This will be fixed in the next version of open-iscsi* + + For compatibility reasons, when you run iscsiadm to do discovery, it +-will check for interfaces in /etc/iscsi/iscsi/ifaces that are using ++will check for interfaces in /var/lib/iscsi/ifaces that are using + tcp for the iface.transport and it will bind the portals that are discovered + so that they will be logged in through those ifaces. This behavior can also + be overriden by passing in the interfaces you want to use. For the case +@@ -677,7 +676,7 @@ we do not bind a session to a iface, then you can use the special iface + + iscsiadm -m discoverydb -t st -p ip:port -I default --discover -P 1 + +-And if you did not define any interfaces in /etc/iscsi/ifaces and do ++And if you did not define any interfaces in /var/lib/iscsi/ifaces and do + not pass anything into iscsiadm, running iscsiadm will do the default + behavior, where we allow the network subsystem to decide which + device to use. +@@ -719,7 +718,7 @@ To now log into targets it is the same as with sofware iscsi. See section + + ./iscsiadm -m discoverydb -t st -p 192.168.1.1:3260 --discover + +- This will search /etc/iscsi/send_targets for a record with the ++ This will search /var/lib/iscsi/send_targets for a record with the + ID [portal = 192.168.1.1:3260 and type = sendtargets. If found it + will perform discovery using the settings stored in the record. + If a record does not exist, it will be created using the iscsid.conf +@@ -728,7 +727,7 @@ To now log into targets it is the same as with sofware iscsi. See section + The argument to -p may also be a hostname instead of an address. + ./iscsiadm -m discoverydb -t st -p smoehost --discover + +- For the ifaces, iscsiadm will first search /etc/iscsi/ifaces for ++ For the ifaces, iscsiadm will first search /var/lib/iscsi/ifaces for + interfaces using software iscsi. If any are found then nodes found + during discovery will be setup so that they can logged in through + those interfaces. To specify a specific iface, pass the +@@ -784,7 +783,7 @@ To now log into targets it is the same as with sofware iscsi. See section + This command will perform discovery, but not manipulate the node DB. + + - SendTargets iSCSI Discovery with a specific interface. If you +- wish to only use a subset of the interfaces in /etc/iscsi/ifaces ++ wish to only use a subset of the interfaces in /var/lib/iscsi/ifaces + then you can pass them in during discovery: + + ./iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \ +@@ -1145,8 +1144,8 @@ where targetname is the name of the target and ip_address:port is the address + and port of the portal. tpgt, is the portal group tag of + the portal, and is not used in iscsiadm commands except for static + record creation. And iface name is the name of the iscsi interface +-defined in /etc/iscsi/ifaces. If no interface was defined in +-/etc/iscsi/ifaces or passed in, the default behavior is used. ++defined in /var/lib/iscsi/ifaces. If no interface was defined in ++/var/lib/iscsi/ifaces or passed in, the default behavior is used. + Default here is iscsi_tcp/tcp to be used over which ever NIC the + network layer decides is best. + +@@ -1261,7 +1260,7 @@ If set, iscsid will perform discovery to the address every + discovery.isns.discoveryd_poll_inval or + discovery.sendtargets.discoveryd_poll_inval seconds, + and it will log into any portals found from the discovery source using +-the ifaces in /etc/iscsi/ifaces. ++the ifaces in /var/lib/iscsi/ifaces. + + Note that for iSNS the poll_interval does not have to be set. If not set, + iscsid will only perform rediscovery when it gets a SCN from the server. +diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 +index 6b15fcd..30811bd 100644 +--- a/doc/iscsiadm.8 ++++ b/doc/iscsiadm.8 +@@ -101,7 +101,7 @@ This option is only valid for ping submode. + .TP + \fB\-I\fR, \fB\-\-interface=\fI[iface]\fR + The interface argument specifies the iSCSI interface to use for the operation. +-iSCSI interfaces (iface) are defined in /etc/iscsi/ifaces. For hardware ++iSCSI interfaces (iface) are defined in /var/lib/iscsi/ifaces. For hardware + iSCSI (qla4xxx) the iface config must have the hardware address + (iface.hwaddress = port's MAC address) + and the driver/transport_name (iface.transport_name). The iface's name is +@@ -178,7 +178,7 @@ If no other options are specified: for \fIdiscoverydb\fR and \fInode\fR, all + of their respective records are displayed; for \fIsession\fR, all active + sessions and connections are displayed; for \fIfw\fR, all boot firmware + values are displayed; for \fIhost\fR, all iSCSI hosts are displayed; and +-for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed. ++for \fIiface\fR, all ifaces setup in /var/lib/iscsi/ifaces are displayed. + + .TP + \fB\-n\fR, \fB\-\-name=\fIname\fR +@@ -562,10 +562,10 @@ The configuration file read by \fBiscsid\fR and \fBiscsiadm\fR on startup. + The file containing the iSCSI InitiatorName and InitiatorAlias read by + \fBiscsid\fR and \fBiscsiadm\fR on startup. + .TP +-/etc/iscsi/nodes/ ++/var/lib/iscsi/nodes/ + This directory contains the nodes with their targets. + .TP +-/etc/iscsi/send_targets ++/var/lib/iscsi/send_targets + This directory contains the portals. + + .SH "SEE ALSO" +diff --git a/usr/idbm.c b/usr/idbm.c +index 634e547..4bb9810 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2721,9 +2721,9 @@ free_info: + int idbm_init(idbm_get_config_file_fn *fn) + { + /* make sure root db dir is there */ +- if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) { +- if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) { +- log_error("Could not make %s %d\n", ISCSI_CONFIG_ROOT, ++ if (access(ISCSIVAR, F_OK) != 0) { ++ if (mkdir(ISCSIVAR, 0660) != 0) { ++ log_error("Could not make %s %d\n", ISCSIVAR, + errno); + return errno; + } +diff --git a/usr/idbm.h b/usr/idbm.h +index 5e4038d..1e9b132 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -29,12 +29,13 @@ + #include "list.h" + #include "flashnode.h" + +-#define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" +-#define SLP_CONFIG_DIR ISCSI_CONFIG_ROOT"slp" +-#define ISNS_CONFIG_DIR ISCSI_CONFIG_ROOT"isns" +-#define STATIC_CONFIG_DIR ISCSI_CONFIG_ROOT"static" +-#define FW_CONFIG_DIR ISCSI_CONFIG_ROOT"fw" +-#define ST_CONFIG_DIR ISCSI_CONFIG_ROOT"send_targets" ++#define ISCSIVAR "/var/lib/iscsi/" ++#define NODE_CONFIG_DIR ISCSIVAR"nodes" ++#define SLP_CONFIG_DIR ISCSIVAR"slp" ++#define ISNS_CONFIG_DIR ISCSIVAR"isns" ++#define STATIC_CONFIG_DIR ISCSIVAR"static" ++#define FW_CONFIG_DIR ISCSIVAR"fw" ++#define ST_CONFIG_DIR ISCSIVAR"send_targets" + #define ST_CONFIG_NAME "st_config" + #define ISNS_CONFIG_NAME "isns_config" + +diff --git a/usr/iface.h b/usr/iface.h +index 01f7074..f396918 100644 +--- a/usr/iface.h ++++ b/usr/iface.h +@@ -20,7 +20,9 @@ + #ifndef ISCSI_IFACE_H + #define ISCSI_IFACE_H + +-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" ++#include "idbm.h" ++ ++#define IFACE_CONFIG_DIR ISCSIVAR"ifaces" + + struct iface_rec; + struct list_head; +-- +1.8.1.4 + diff --git a/0153-use-red-hat-for-name.patch b/0153-use-red-hat-for-name.patch new file mode 100644 index 0000000..8888200 --- /dev/null +++ b/0153-use-red-hat-for-name.patch @@ -0,0 +1,25 @@ +From bf7f9118ab2f1a5302dafa198d3351f6f977b7bd Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:40:04 -0800 +Subject: use red hat for name + +--- + utils/iscsi-iname.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/utils/iscsi-iname.c b/utils/iscsi-iname.c +index 6347edc..cb2f6c8 100644 +--- a/utils/iscsi-iname.c ++++ b/utils/iscsi-iname.c +@@ -73,7 +73,7 @@ main(int argc, char *argv[]) + exit(0); + } + } else { +- prefix = "iqn.2005-03.org.open-iscsi"; ++ prefix = "iqn.1994-05.com.redhat"; + } + + /* try to feed some entropy from the pool to MD5 in order to get +-- +1.7.11.7 + diff --git a/0154-add-libiscsi.patch b/0154-add-libiscsi.patch new file mode 100644 index 0000000..e3d2324 --- /dev/null +++ b/0154-add-libiscsi.patch @@ -0,0 +1,3927 @@ +From 38800fb6984ca4c3ad963708c47c1946c33b6d1a Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:43:15 -0800 +Subject: add libiscsi + +--- + Makefile | 2 + + libiscsi/Makefile | 61 ++ + libiscsi/libiscsi.c | 620 +++++++++++ + libiscsi/libiscsi.doxy | 1473 +++++++++++++++++++++++++++ + libiscsi/libiscsi.h | 344 +++++++ + libiscsi/pylibiscsi.c | 638 ++++++++++++ + libiscsi/setup.py | 9 + + libiscsi/tests/test_discovery_firmware.c | 53 + + libiscsi/tests/test_discovery_sendtargets.c | 60 ++ + libiscsi/tests/test_get_auth.c | 70 ++ + libiscsi/tests/test_get_initiator_name.c | 38 + + libiscsi/tests/test_get_network_config.c | 45 + + libiscsi/tests/test_login.c | 52 + + libiscsi/tests/test_logout.c | 51 + + libiscsi/tests/test_params.c | 103 ++ + libiscsi/tests/test_set_auth.c | 58 ++ + usr/Makefile | 2 +- + usr/discovery.c | 5 + + usr/idbm.c | 6 +- + usr/idbm.h | 3 + + usr/iscsi_ipc.h | 2 + + 21 files changed, 3691 insertions(+), 4 deletions(-) + create mode 100644 libiscsi/Makefile + create mode 100644 libiscsi/libiscsi.c + create mode 100644 libiscsi/libiscsi.doxy + create mode 100644 libiscsi/libiscsi.h + create mode 100644 libiscsi/pylibiscsi.c + create mode 100644 libiscsi/setup.py + create mode 100644 libiscsi/tests/test_discovery_firmware.c + create mode 100644 libiscsi/tests/test_discovery_sendtargets.c + create mode 100644 libiscsi/tests/test_get_auth.c + create mode 100644 libiscsi/tests/test_get_initiator_name.c + create mode 100644 libiscsi/tests/test_get_network_config.c + create mode 100644 libiscsi/tests/test_login.c + create mode 100644 libiscsi/tests/test_logout.c + create mode 100644 libiscsi/tests/test_params.c + create mode 100644 libiscsi/tests/test_set_auth.c + +diff --git a/Makefile b/Makefile +index 0b7bb98..02346bf 100644 +--- a/Makefile ++++ b/Makefile +@@ -33,6 +33,7 @@ user: utils/open-isns/Makefile iscsiuio/Makefile + $(MAKE) -C usr + $(MAKE) -C utils + $(MAKE) -C iscsiuio ++ $(MAKE) -C libiscsi + @echo + @echo "Compilation complete Output file" + @echo "----------------------------------- ----------------" +@@ -61,6 +62,7 @@ kernel: force + force: ; + + clean: ++ $(MAKE) -C libiscsi clean + $(MAKE) -C utils/sysdeps clean + $(MAKE) -C utils/fwparam_ibft clean + $(MAKE) -C utils clean +diff --git a/libiscsi/Makefile b/libiscsi/Makefile +new file mode 100644 +index 0000000..317a7ec +--- /dev/null ++++ b/libiscsi/Makefile +@@ -0,0 +1,61 @@ ++# This Makefile will work only with GNU make. ++ ++OSNAME=$(shell uname -s) ++OPTFLAGS ?= -O2 -g ++WARNFLAGS ?= -Wall -Wstrict-prototypes ++CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \ ++ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden ++LIB = libiscsi.so.0 ++TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware ++TESTS += tests/test_login tests/test_logout tests/test_params ++TESTS += tests/test_get_network_config tests/test_get_initiator_name ++TESTS += tests/test_set_auth tests/test_get_auth ++ ++COMMON_SRCS = sysdeps.o ++# sources shared between iscsid, iscsiadm and iscsistart ++ISCSI_LIB_SRCS = netlink.o transport.o cxgbi.o be2iscsi.o iscsi_timer.o initiator_common.o iscsi_err.o session_info.o iscsi_util.o io.o auth.o discovery.o login.o log.o md5.o sha1.o iface.o idbm.o sysfs.o iscsi_sysfs.o iscsi_net_util.o iscsid_req.o iser.o uip_mgmt_ipc.o ++FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sysfs.o ++ ++# sources shared with the userspace utils, note we build these separately ++# to get PIC versions. ++COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS)) ++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o) ++FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS)) ++ ++# Flags for the tests ++tests/% : CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I. ++ ++all: lib tests html ++ ++lib: $(LIB) ++tests: $(TESTS) ++ ++common-objs/%.o: ../utils/sysdeps/%.c ++ mkdir -p common-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++usr-objs/%.o: ../usr/%.c ++ mkdir -p usr-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++fw-objs/%.o: ../utils/fwparam_ibft/%.c ++ mkdir -p fw-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++$(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o ++ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ ++ ln -s -f $(LIB) libiscsi.so ++ ++$(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB) ++ ++html: libiscsi.h libiscsi.doxy ++ doxygen libiscsi.doxy ++ ++clean: ++ rm -rf *.o common-objs usr-objs fw-objs libuip-objs libiscsi.so* \ ++ .depend *~ html $(TESTS) tests/*~ ++ ++depend: ++ gcc $(CFLAGS) -M `ls *.c` > .depend ++ ++-include .depend ../usr/.depend +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +new file mode 100644 +index 0000000..2a176e8 +--- /dev/null ++++ b/libiscsi/libiscsi.c +@@ -0,0 +1,620 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++#include "idbm.h" ++#include "discovery.h" ++#include "log.h" ++#include "sysfs.h" ++#include "iscsi_sysfs.h" ++#include "session_info.h" ++#include "iscsi_util.h" ++#include "sysdeps.h" ++#include "iface.h" ++#include "iscsi_proto.h" ++#include "fw_context.h" ++#include "iscsid_req.h" ++#include "iscsi_err.h" ++ ++#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; } ++ ++/* UGLY, not thread safe :( */ ++static int sysfs_initialized = 0; ++ ++struct libiscsi_context { ++ char error_str[256]; ++ /* For get_parameter_helper() */ ++ const char *parameter; ++ char *value; ++}; ++ ++static void libiscsi_log(int prio, void *priv, const char *fmt, va_list ap) ++{ ++ struct libiscsi_context *context = priv; ++ ++ if (prio > LOG_ERR) /* We are only interested in errors (or worse) */ ++ return; ++ ++ vsnprintf(context->error_str, sizeof(context->error_str), fmt, ap); ++} ++ ++struct libiscsi_context *libiscsi_init(void) ++{ ++ struct libiscsi_context *context; ++ ++ context = calloc(1, sizeof *context); ++ if (!context) ++ return NULL; ++ ++ log_init("libiscsi", 1024, libiscsi_log, context); ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ increase_max_files(); ++ if (idbm_init(NULL)) { ++ sysfs_cleanup(); ++ free(context); ++ return NULL; ++ } ++ ++ iface_setup_host_bindings(); ++ ++ return context; ++} ++ ++void libiscsi_cleanup(struct libiscsi_context *context) ++{ ++ idbm_terminate(); ++ free_transports(); ++ sysfs_cleanup(); ++ free(context); ++} ++ ++static void free_iface_list(struct list_head *ifaces) ++{ ++ struct iface_rec *iface, *tmp_iface; ++ ++ list_for_each_entry_safe(iface, tmp_iface, ifaces, list) { ++ list_del(&iface->list); ++ free(iface); ++ } ++} ++ ++static void free_rec_list(struct list_head *rec_list) ++{ ++ struct node_rec *rec, *tmp; ++ ++ list_for_each_entry_safe(rec, tmp, rec_list, list) { ++ list_del(&rec->list); ++ free(rec); ++ } ++} ++ ++int libiscsi_discover_sendtargets(struct libiscsi_context *context, ++ const char *address, int port, ++ const struct libiscsi_auth_info *auth_info, ++ int *nr_found, struct libiscsi_node **found_nodes) ++{ ++ struct discovery_rec drec; ++ LIST_HEAD(bound_rec_list); ++ struct node_rec *rec; ++ int rc = 0, found = 0; ++ ++ INIT_LIST_HEAD(&bound_rec_list); ++ ++ if (nr_found) ++ *nr_found = 0; ++ if (found_nodes) ++ *found_nodes = NULL; ++ ++ CHECK(libiscsi_verify_auth_info(context, auth_info)) ++ ++ /* Fill the drec struct with all needed info */ ++ memset(&drec, 0, sizeof drec); ++ idbm_sendtargets_defaults(&drec.u.sendtargets); ++ drec.type = DISCOVERY_TYPE_SENDTARGETS; ++ strlcpy(drec.address, address, sizeof(drec.address)); ++ drec.port = port ? port : ISCSI_LISTEN_PORT; ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_chap: ++ drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP; ++ strlcpy(drec.u.sendtargets.auth.username, ++ auth_info->chap.username, AUTH_STR_MAX_LEN); ++ strlcpy((char *)drec.u.sendtargets.auth.password, ++ auth_info->chap.password, AUTH_STR_MAX_LEN); ++ drec.u.sendtargets.auth.password_length = ++ strlen((char *)drec.u.sendtargets.auth.password); ++ strlcpy(drec.u.sendtargets.auth.username_in, ++ auth_info->chap.reverse_username, AUTH_STR_MAX_LEN); ++ strlcpy((char *)drec.u.sendtargets.auth.password_in, ++ auth_info->chap.reverse_password, AUTH_STR_MAX_LEN); ++ drec.u.sendtargets.auth.password_in_length = ++ strlen((char *)drec.u.sendtargets.auth.password_in); ++ break; ++ } ++ ++ CHECK(idbm_add_discovery(&drec)) ++ ++ CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets, ++ &drec, NULL, &bound_rec_list)) ++ ++ /* now add/update records */ ++ list_for_each_entry(rec, &bound_rec_list, list) { ++ CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */)) ++ found++; ++ } ++ ++ if (nr_found) ++ *nr_found = found; ++ ++ if (found_nodes && found) { ++ *found_nodes = calloc(found, sizeof **found_nodes); ++ if (*found_nodes == NULL) { ++ snprintf(context->error_str, ++ sizeof(context->error_str), strerror(ENOMEM)); ++ rc = ENOMEM; ++ goto leave; ++ } ++ found = 0; ++ list_for_each_entry(rec, &bound_rec_list, list) { ++ strlcpy((*found_nodes)[found].name, rec->name, ++ LIBISCSI_VALUE_MAXLEN); ++ (*found_nodes)[found].tpgt = rec->tpgt; ++ strlcpy((*found_nodes)[found].address, ++ rec->conn[0].address, NI_MAXHOST); ++ (*found_nodes)[found].port = rec->conn[0].port; ++ strlcpy((*found_nodes)[found].iface, ++ rec->iface.name, LIBISCSI_VALUE_MAXLEN); ++ found++; ++ } ++ } ++ ++leave: ++ free_rec_list(&bound_rec_list); ++ return rc; ++} ++ ++int libiscsi_discover_firmware(struct libiscsi_context *context, ++ int *nr_found, struct libiscsi_node **found_nodes) ++{ ++ struct list_head targets, ifaces, rec_list; ++ discovery_rec_t drec; ++ int rc = 0; ++ ++ INIT_LIST_HEAD(&targets); ++ INIT_LIST_HEAD(&ifaces); ++ INIT_LIST_HEAD(&rec_list); ++ ++ if (nr_found) { ++ *nr_found = 0; ++ } ++ ++ if (found_nodes) { ++ *found_nodes = NULL; ++ } ++ ++ rc = fw_get_targets(&targets); ++ if (rc) { ++ log_error("%s: Could not get list of targets from firmware " ++ "(err %d).\n", __func__, rc); ++ return rc; ++ } ++ ++ CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets)); ++ ++ memset(&drec, 0, sizeof(drec)); ++ drec.type = DISCOVERY_TYPE_FW; ++ rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list); ++ if (rc) { ++ log_error("%s: Could not determine target nodes from firmware " ++ "(err %d).\n", __func__, rc); ++ goto leave; ++ } ++ ++ int node_count = 0; ++ struct list_head *pos; ++ list_for_each(pos, &rec_list) { ++ ++node_count; ++ } ++ ++ struct libiscsi_node* new_nodes; ++ /* allocate enough space for all the nodes */ ++ new_nodes = calloc(node_count, sizeof *new_nodes); ++ if (new_nodes == NULL) { ++ rc = ENOMEM; ++ log_error("%s: %s.\n", __func__, strerror(ENOMEM)); ++ goto leave; ++ } ++ ++ struct node_rec *rec; ++ struct libiscsi_node *new_node = new_nodes; ++ /* in one loop, add nodes to idbm and create libiscsi_node entries */ ++ list_for_each_entry(rec, &rec_list, list) { ++ CHECK(idbm_add_node(rec, NULL, 1 /* overwrite */)); ++ ++ strlcpy(new_node->name, rec->name, LIBISCSI_VALUE_MAXLEN); ++ new_node->tpgt = rec->tpgt; ++ strlcpy(new_node->address, rec->conn[0].address, NI_MAXHOST); ++ new_node->port = rec->conn[0].port; ++ strlcpy(new_node->iface, rec->iface.name, LIBISCSI_VALUE_MAXLEN); ++ ++ ++new_node; ++ } ++ ++ /* update output parameters */ ++ if (nr_found) { ++ *nr_found = node_count; ++ } ++ if (found_nodes) { ++ *found_nodes = new_nodes; ++ } ++ ++leave: ++ fw_free_targets(&targets); ++ ++ free_iface_list(&ifaces); ++ free_rec_list(&rec_list); ++ ++ return rc; ++} ++ ++int libiscsi_verify_auth_info(struct libiscsi_context *context, ++ const struct libiscsi_auth_info *auth_info) ++{ ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_none: ++ break; ++ case libiscsi_auth_chap: ++ if (!auth_info->chap.username[0]) { ++ strcpy(context->error_str, "Empty username"); ++ return EINVAL; ++ } ++ if (!auth_info->chap.password[0]) { ++ strcpy(context->error_str, "Empty password"); ++ return EINVAL; ++ } ++ if (auth_info->chap.reverse_username[0] && ++ !auth_info->chap.reverse_password[0]) { ++ strcpy(context->error_str, "Empty reverse password"); ++ return EINVAL; ++ } ++ break; ++ default: ++ sprintf(context->error_str, ++ "Invalid authentication method: %d", ++ (int)auth_info->method); ++ return EINVAL; ++ } ++ return 0; ++} ++ ++int libiscsi_node_set_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const struct libiscsi_auth_info *auth_info) ++{ ++ int rc = 0; ++ ++ CHECK(libiscsi_verify_auth_info(context, auth_info)) ++ ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_none: ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.authmethod", "None")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username_in", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password_in", "")) ++ break; ++ ++ case libiscsi_auth_chap: ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.authmethod", "CHAP")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username", ++ auth_info->chap.username)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password", ++ auth_info->chap.password)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username_in", ++ auth_info->chap.reverse_username)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password_in", ++ auth_info->chap.reverse_password)) ++ break; ++ } ++leave: ++ return rc; ++} ++ ++int libiscsi_node_get_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ struct libiscsi_auth_info *auth_info) ++{ ++ int rc = 0; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ memset(auth_info, 0, sizeof *auth_info); ++ ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.authmethod", value)) ++ ++ if (!strcmp(value, "None")) { ++ auth_info->method = libiscsi_auth_none; ++ } else if (!strcmp(value, "CHAP")) { ++ auth_info->method = libiscsi_auth_chap; ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.username", ++ auth_info->chap.username)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.password", ++ auth_info->chap.password)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.username_in", ++ auth_info->chap.reverse_username)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.password_in", ++ auth_info->chap.reverse_password)) ++ } else { ++ snprintf(context->error_str, sizeof(context->error_str), ++ "unknown authentication method: %s", value); ++ rc = EINVAL; ++ } ++leave: ++ return rc; ++} ++ ++static void node_to_rec(const struct libiscsi_node *node, ++ struct node_rec *rec) ++{ ++ memset(rec, 0, sizeof *rec); ++ idbm_node_setup_defaults(rec); ++ strlcpy(rec->name, node->name, TARGET_NAME_MAXLEN); ++ rec->tpgt = node->tpgt; ++ strlcpy(rec->conn[0].address, node->address, NI_MAXHOST); ++ rec->conn[0].port = node->port; ++} ++ ++int login_helper(void *data, node_rec_t *rec) ++{ ++ char *iface = (char*)data; ++ if (strcmp(iface, rec->iface.name)) ++ /* different iface, skip it */ ++ return -1; ++ ++ int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec); ++ if (rc) { ++ iscsi_err_print_msg(rc); ++ rc = ENOTCONN; ++ } ++ return rc; ++} ++ ++int libiscsi_node_login(struct libiscsi_context *context, ++ const struct libiscsi_node *node) ++{ ++ int nr_found = 0, rc; ++ ++ CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++static int logout_helper(void *data, struct session_info *info) ++{ ++ int rc; ++ struct node_rec *rec = data; ++ ++ if (!iscsi_match_session(rec, info)) ++ /* Tell iscsi_sysfs_for_each_session this session was not a ++ match so that it will not increase nr_found. */ ++ return -1; ++ ++ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid); ++ if (rc) { ++ iscsi_err_print_msg(rc); ++ rc = EIO; ++ } ++ ++ return rc; ++} ++ ++int libiscsi_node_logout(struct libiscsi_context *context, ++ const struct libiscsi_node *node) ++{ ++ int nr_found = 0, rc; ++ struct node_rec rec; ++ ++ node_to_rec(node, &rec); ++ CHECK(iscsi_sysfs_for_each_session(&rec, &nr_found, logout_helper,0)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No matching session"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++int libiscsi_node_set_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const char *parameter, const char *value) ++{ ++ int nr_found = 0, rc; ++ struct user_param *param; ++ struct list_head params; ++ ++ INIT_LIST_HEAD(¶ms); ++ param = idbm_alloc_user_param(parameter, value); ++ if (!param) { ++ rc = ENOMEM; ++ goto leave; ++ } ++ list_add_tail(¶ms, ¶m->list); ++ ++ CHECK(idbm_for_each_iface(&nr_found, ¶ms, idbm_node_set_param, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++ free(param->name); ++ free(param); ++leave: ++ return rc; ++} ++ ++static int get_parameter_helper(void *data, node_rec_t *rec) ++{ ++ struct libiscsi_context *context = data; ++ recinfo_t *info; ++ int i; ++ ++ info = idbm_recinfo_alloc(MAX_KEYS); ++ if (!info) { ++ snprintf(context->error_str, sizeof(context->error_str), ++ strerror(ENOMEM)); ++ return ENOMEM; ++ } ++ ++ idbm_recinfo_node(rec, info); ++ ++ for (i = 0; i < MAX_KEYS; i++) { ++ if (!info[i].visible) ++ continue; ++ ++ if (strcmp(context->parameter, info[i].name)) ++ continue; ++ ++ strlcpy(context->value, info[i].value, LIBISCSI_VALUE_MAXLEN); ++ break; ++ } ++ ++ free(info); ++ ++ if (i == MAX_KEYS) { ++ strcpy(context->error_str, "No such parameter"); ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ ++int libiscsi_node_get_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, const char *parameter, char *value) ++{ ++ int nr_found = 0, rc = 0; ++ ++ context->parameter = parameter; ++ context->value = value; ++ ++ /* Note we assume there is only one interface, if not we will get ++ the value from the last interface iterated over! ++ This (multiple interfaces) can only happen if someone explicitly ++ created ones using iscsiadm. Even then this should not be a problem ++ as most settings should be the same independent of the iface. */ ++ CHECK(idbm_for_each_iface(&nr_found, context, get_parameter_helper, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++const char *libiscsi_get_error_string(struct libiscsi_context *context) ++{ ++ /* Sometimes the core open-iscsi code does not give us an error ++ message */ ++ if (!context->error_str[0]) ++ return "Unknown error"; ++ ++ return context->error_str; ++} ++ ++ ++/************************** Utility functions *******************************/ ++ ++int libiscsi_get_firmware_network_config( ++ struct libiscsi_network_config *config) ++{ ++ struct boot_context fw_entry; ++ ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ ++ memset(config, 0, sizeof *config); ++ memset(&fw_entry, 0, sizeof fw_entry); ++ if (fw_get_entry(&fw_entry)) ++ return ENODEV; ++ ++ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0; ++ strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface); ++ strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac); ++ strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr); ++ strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask); ++ strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway); ++ strncpy(config->primary_dns, fw_entry.primary_dns, ++ sizeof fw_entry.primary_dns); ++ strncpy(config->secondary_dns, fw_entry.secondary_dns, ++ sizeof fw_entry.secondary_dns); ++ return 0; ++} ++ ++int libiscsi_get_firmware_initiator_name(char *initiatorname) ++{ ++ struct boot_context fw_entry; ++ ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ ++ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN); ++ memset(&fw_entry, 0, sizeof fw_entry); ++ if (fw_get_entry(&fw_entry)) ++ return ENODEV; ++ ++ strncpy(initiatorname, fw_entry.initiatorname, ++ sizeof fw_entry.initiatorname); ++ ++ return 0; ++} +diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy +new file mode 100644 +index 0000000..663770f +--- /dev/null ++++ b/libiscsi/libiscsi.doxy +@@ -0,0 +1,1473 @@ ++# Doxyfile 1.5.7.1 ++ ++# This file describes the settings to be used by the documentation system ++# doxygen (www.doxygen.org) for a project ++# ++# All text after a hash (#) is considered a comment and will be ignored ++# The format is: ++# TAG = value [value, ...] ++# For lists items can also be appended using: ++# TAG += value [value, ...] ++# Values that contain spaces should be placed between quotes (" ") ++ ++#--------------------------------------------------------------------------- ++# Project related configuration options ++#--------------------------------------------------------------------------- ++ ++# This tag specifies the encoding used for all characters in the config file ++# that follow. The default is UTF-8 which is also the encoding used for all ++# text before the first occurrence of this tag. Doxygen uses libiconv (or the ++# iconv built into libc) for the transcoding. See ++# http://www.gnu.org/software/libiconv for the list of possible encodings. ++ ++DOXYFILE_ENCODING = UTF-8 ++ ++# The PROJECT_NAME tag is a single word (or a sequence of words surrounded ++# by quotes) that should identify the project. ++ ++PROJECT_NAME = libiscsi ++ ++# The PROJECT_NUMBER tag can be used to enter a project or revision number. ++# This could be handy for archiving the generated documentation or ++# if some version control system is used. ++ ++PROJECT_NUMBER = ++ ++# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) ++# base path where the generated documentation will be put. ++# If a relative path is entered, it will be relative to the location ++# where doxygen was started. If left blank the current directory will be used. ++ ++OUTPUT_DIRECTORY = ++ ++# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create ++# 4096 sub-directories (in 2 levels) under the output directory of each output ++# format and will distribute the generated files over these directories. ++# Enabling this option can be useful when feeding doxygen a huge amount of ++# source files, where putting all generated files in the same directory would ++# otherwise cause performance problems for the file system. ++ ++CREATE_SUBDIRS = NO ++ ++# The OUTPUT_LANGUAGE tag is used to specify the language in which all ++# documentation generated by doxygen is written. Doxygen will use this ++# information to generate all constant output in the proper language. ++# The default language is English, other supported languages are: ++# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, ++# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, ++# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), ++# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, ++# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, ++# Spanish, Swedish, and Ukrainian. ++ ++OUTPUT_LANGUAGE = English ++ ++# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will ++# include brief member descriptions after the members that are listed in ++# the file and class documentation (similar to JavaDoc). ++# Set to NO to disable this. ++ ++BRIEF_MEMBER_DESC = YES ++ ++# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend ++# the brief description of a member or function before the detailed description. ++# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the ++# brief descriptions will be completely suppressed. ++ ++REPEAT_BRIEF = NO ++ ++# This tag implements a quasi-intelligent brief description abbreviator ++# that is used to form the text in various listings. Each string ++# in this list, if found as the leading text of the brief description, will be ++# stripped from the text and the result after processing the whole list, is ++# used as the annotated text. Otherwise, the brief description is used as-is. ++# If left blank, the following values are used ("$name" is automatically ++# replaced with the name of the entity): "The $name class" "The $name widget" ++# "The $name file" "is" "provides" "specifies" "contains" ++# "represents" "a" "an" "the" ++ ++ABBREVIATE_BRIEF = ++ ++# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then ++# Doxygen will generate a detailed section even if there is only a brief ++# description. ++ ++ALWAYS_DETAILED_SEC = YES ++ ++# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all ++# inherited members of a class in the documentation of that class as if those ++# members were ordinary class members. Constructors, destructors and assignment ++# operators of the base classes will not be shown. ++ ++INLINE_INHERITED_MEMB = NO ++ ++# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full ++# path before files name in the file list and in the header files. If set ++# to NO the shortest path that makes the file name unique will be used. ++ ++FULL_PATH_NAMES = YES ++ ++# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag ++# can be used to strip a user-defined part of the path. Stripping is ++# only done if one of the specified strings matches the left-hand part of ++# the path. The tag can be used to show relative paths in the file list. ++# If left blank the directory from which doxygen is run is used as the ++# path to strip. ++ ++STRIP_FROM_PATH = ++ ++# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of ++# the path mentioned in the documentation of a class, which tells ++# the reader which header file to include in order to use a class. ++# If left blank only the name of the header file containing the class ++# definition is used. Otherwise one should specify the include paths that ++# are normally passed to the compiler using the -I flag. ++ ++STRIP_FROM_INC_PATH = ++ ++# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter ++# (but less readable) file names. This can be useful is your file systems ++# doesn't support long names like on DOS, Mac, or CD-ROM. ++ ++SHORT_NAMES = NO ++ ++# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen ++# will interpret the first line (until the first dot) of a JavaDoc-style ++# comment as the brief description. If set to NO, the JavaDoc ++# comments will behave just like regular Qt-style comments ++# (thus requiring an explicit @brief command for a brief description.) ++ ++JAVADOC_AUTOBRIEF = NO ++ ++# If the QT_AUTOBRIEF tag is set to YES then Doxygen will ++# interpret the first line (until the first dot) of a Qt-style ++# comment as the brief description. If set to NO, the comments ++# will behave just like regular Qt-style comments (thus requiring ++# an explicit \brief command for a brief description.) ++ ++QT_AUTOBRIEF = NO ++ ++# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen ++# treat a multi-line C++ special comment block (i.e. a block of //! or /// ++# comments) as a brief description. This used to be the default behaviour. ++# The new default is to treat a multi-line C++ comment block as a detailed ++# description. Set this tag to YES if you prefer the old behaviour instead. ++ ++MULTILINE_CPP_IS_BRIEF = NO ++ ++# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented ++# member inherits the documentation from any documented member that it ++# re-implements. ++ ++INHERIT_DOCS = YES ++ ++# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce ++# a new page for each member. If set to NO, the documentation of a member will ++# be part of the file/class/namespace that contains it. ++ ++SEPARATE_MEMBER_PAGES = NO ++ ++# The TAB_SIZE tag can be used to set the number of spaces in a tab. ++# Doxygen uses this value to replace tabs by spaces in code fragments. ++ ++TAB_SIZE = 8 ++ ++# This tag can be used to specify a number of aliases that acts ++# as commands in the documentation. An alias has the form "name=value". ++# For example adding "sideeffect=\par Side Effects:\n" will allow you to ++# put the command \sideeffect (or @sideeffect) in the documentation, which ++# will result in a user-defined paragraph with heading "Side Effects:". ++# You can put \n's in the value part of an alias to insert newlines. ++ ++ALIASES = ++ ++# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C ++# sources only. Doxygen will then generate output that is more tailored for C. ++# For instance, some of the names that are used will be different. The list ++# of all members will be omitted, etc. ++ ++OPTIMIZE_OUTPUT_FOR_C = YES ++ ++# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java ++# sources only. Doxygen will then generate output that is more tailored for ++# Java. For instance, namespaces will be presented as packages, qualified ++# scopes will look different, etc. ++ ++OPTIMIZE_OUTPUT_JAVA = NO ++ ++# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran ++# sources only. Doxygen will then generate output that is more tailored for ++# Fortran. ++ ++OPTIMIZE_FOR_FORTRAN = NO ++ ++# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL ++# sources. Doxygen will then generate output that is tailored for ++# VHDL. ++ ++OPTIMIZE_OUTPUT_VHDL = NO ++ ++# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want ++# to include (a tag file for) the STL sources as input, then you should ++# set this tag to YES in order to let doxygen match functions declarations and ++# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. ++# func(std::string) {}). This also make the inheritance and collaboration ++# diagrams that involve STL classes more complete and accurate. ++ ++BUILTIN_STL_SUPPORT = NO ++ ++# If you use Microsoft's C++/CLI language, you should set this option to YES to ++# enable parsing support. ++ ++CPP_CLI_SUPPORT = NO ++ ++# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. ++# Doxygen will parse them like normal C++ but will assume all classes use public ++# instead of private inheritance when no explicit protection keyword is present. ++ ++SIP_SUPPORT = NO ++ ++# For Microsoft's IDL there are propget and propput attributes to indicate getter ++# and setter methods for a property. Setting this option to YES (the default) ++# will make doxygen to replace the get and set methods by a property in the ++# documentation. This will only work if the methods are indeed getting or ++# setting a simple type. If this is not the case, or you want to show the ++# methods anyway, you should set this option to NO. ++ ++IDL_PROPERTY_SUPPORT = YES ++ ++# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC ++# tag is set to YES, then doxygen will reuse the documentation of the first ++# member in the group (if any) for the other members of the group. By default ++# all members of a group must be documented explicitly. ++ ++DISTRIBUTE_GROUP_DOC = NO ++ ++# Set the SUBGROUPING tag to YES (the default) to allow class member groups of ++# the same type (for instance a group of public functions) to be put as a ++# subgroup of that type (e.g. under the Public Functions section). Set it to ++# NO to prevent subgrouping. Alternatively, this can be done per class using ++# the \nosubgrouping command. ++ ++SUBGROUPING = YES ++ ++# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum ++# is documented as struct, union, or enum with the name of the typedef. So ++# typedef struct TypeS {} TypeT, will appear in the documentation as a struct ++# with name TypeT. When disabled the typedef will appear as a member of a file, ++# namespace, or class. And the struct will be named TypeS. This can typically ++# be useful for C code in case the coding convention dictates that all compound ++# types are typedef'ed and only the typedef is referenced, never the tag name. ++ ++TYPEDEF_HIDES_STRUCT = NO ++ ++# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to ++# determine which symbols to keep in memory and which to flush to disk. ++# When the cache is full, less often used symbols will be written to disk. ++# For small to medium size projects (<1000 input files) the default value is ++# probably good enough. For larger projects a too small cache size can cause ++# doxygen to be busy swapping symbols to and from disk most of the time ++# causing a significant performance penality. ++# If the system has enough physical memory increasing the cache will improve the ++# performance by keeping more symbols in memory. Note that the value works on ++# a logarithmic scale so increasing the size by one will rougly double the ++# memory usage. The cache size is given by this formula: ++# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, ++# corresponding to a cache size of 2^16 = 65536 symbols ++ ++SYMBOL_CACHE_SIZE = 0 ++ ++#--------------------------------------------------------------------------- ++# Build related configuration options ++#--------------------------------------------------------------------------- ++ ++# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in ++# documentation are documented, even if no documentation was available. ++# Private class members and static file members will be hidden unless ++# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES ++ ++EXTRACT_ALL = YES ++ ++# If the EXTRACT_PRIVATE tag is set to YES all private members of a class ++# will be included in the documentation. ++ ++EXTRACT_PRIVATE = NO ++ ++# If the EXTRACT_STATIC tag is set to YES all static members of a file ++# will be included in the documentation. ++ ++EXTRACT_STATIC = NO ++ ++# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) ++# defined locally in source files will be included in the documentation. ++# If set to NO only classes defined in header files are included. ++ ++EXTRACT_LOCAL_CLASSES = YES ++ ++# This flag is only useful for Objective-C code. When set to YES local ++# methods, which are defined in the implementation section but not in ++# the interface are included in the documentation. ++# If set to NO (the default) only methods in the interface are included. ++ ++EXTRACT_LOCAL_METHODS = NO ++ ++# If this flag is set to YES, the members of anonymous namespaces will be ++# extracted and appear in the documentation as a namespace called ++# 'anonymous_namespace{file}', where file will be replaced with the base ++# name of the file that contains the anonymous namespace. By default ++# anonymous namespace are hidden. ++ ++EXTRACT_ANON_NSPACES = NO ++ ++# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all ++# undocumented members of documented classes, files or namespaces. ++# If set to NO (the default) these members will be included in the ++# various overviews, but no documentation section is generated. ++# This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_MEMBERS = NO ++ ++# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all ++# undocumented classes that are normally visible in the class hierarchy. ++# If set to NO (the default) these classes will be included in the various ++# overviews. This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_CLASSES = NO ++ ++# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all ++# friend (class|struct|union) declarations. ++# If set to NO (the default) these declarations will be included in the ++# documentation. ++ ++HIDE_FRIEND_COMPOUNDS = NO ++ ++# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any ++# documentation blocks found inside the body of a function. ++# If set to NO (the default) these blocks will be appended to the ++# function's detailed documentation block. ++ ++HIDE_IN_BODY_DOCS = NO ++ ++# The INTERNAL_DOCS tag determines if documentation ++# that is typed after a \internal command is included. If the tag is set ++# to NO (the default) then the documentation will be excluded. ++# Set it to YES to include the internal documentation. ++ ++INTERNAL_DOCS = NO ++ ++# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate ++# file names in lower-case letters. If set to YES upper-case letters are also ++# allowed. This is useful if you have classes or files whose names only differ ++# in case and if your file system supports case sensitive file names. Windows ++# and Mac users are advised to set this option to NO. ++ ++CASE_SENSE_NAMES = YES ++ ++# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen ++# will show members with their full class and namespace scopes in the ++# documentation. If set to YES the scope will be hidden. ++ ++HIDE_SCOPE_NAMES = NO ++ ++# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen ++# will put a list of the files that are included by a file in the documentation ++# of that file. ++ ++SHOW_INCLUDE_FILES = YES ++ ++# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] ++# is inserted in the documentation for inline members. ++ ++INLINE_INFO = YES ++ ++# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen ++# will sort the (detailed) documentation of file and class members ++# alphabetically by member name. If set to NO the members will appear in ++# declaration order. ++ ++SORT_MEMBER_DOCS = YES ++ ++# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the ++# brief documentation of file, namespace and class members alphabetically ++# by member name. If set to NO (the default) the members will appear in ++# declaration order. ++ ++SORT_BRIEF_DOCS = NO ++ ++# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the ++# hierarchy of group names into alphabetical order. If set to NO (the default) ++# the group names will appear in their defined order. ++ ++SORT_GROUP_NAMES = NO ++ ++# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be ++# sorted by fully-qualified names, including namespaces. If set to ++# NO (the default), the class list will be sorted only by class name, ++# not including the namespace part. ++# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. ++# Note: This option applies only to the class list, not to the ++# alphabetical list. ++ ++SORT_BY_SCOPE_NAME = NO ++ ++# The GENERATE_TODOLIST tag can be used to enable (YES) or ++# disable (NO) the todo list. This list is created by putting \todo ++# commands in the documentation. ++ ++GENERATE_TODOLIST = YES ++ ++# The GENERATE_TESTLIST tag can be used to enable (YES) or ++# disable (NO) the test list. This list is created by putting \test ++# commands in the documentation. ++ ++GENERATE_TESTLIST = YES ++ ++# The GENERATE_BUGLIST tag can be used to enable (YES) or ++# disable (NO) the bug list. This list is created by putting \bug ++# commands in the documentation. ++ ++GENERATE_BUGLIST = YES ++ ++# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or ++# disable (NO) the deprecated list. This list is created by putting ++# \deprecated commands in the documentation. ++ ++GENERATE_DEPRECATEDLIST= YES ++ ++# The ENABLED_SECTIONS tag can be used to enable conditional ++# documentation sections, marked by \if sectionname ... \endif. ++ ++ENABLED_SECTIONS = ++ ++# The MAX_INITIALIZER_LINES tag determines the maximum number of lines ++# the initial value of a variable or define consists of for it to appear in ++# the documentation. If the initializer consists of more lines than specified ++# here it will be hidden. Use a value of 0 to hide initializers completely. ++# The appearance of the initializer of individual variables and defines in the ++# documentation can be controlled using \showinitializer or \hideinitializer ++# command in the documentation regardless of this setting. ++ ++MAX_INITIALIZER_LINES = 30 ++ ++# Set the SHOW_USED_FILES tag to NO to disable the list of files generated ++# at the bottom of the documentation of classes and structs. If set to YES the ++# list will mention the files that were used to generate the documentation. ++ ++SHOW_USED_FILES = YES ++ ++# If the sources in your project are distributed over multiple directories ++# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy ++# in the documentation. The default is NO. ++ ++SHOW_DIRECTORIES = NO ++ ++# Set the SHOW_FILES tag to NO to disable the generation of the Files page. ++# This will remove the Files entry from the Quick Index and from the ++# Folder Tree View (if specified). The default is YES. ++ ++SHOW_FILES = YES ++ ++# Set the SHOW_NAMESPACES tag to NO to disable the generation of the ++# Namespaces page. This will remove the Namespaces entry from the Quick Index ++# and from the Folder Tree View (if specified). The default is YES. ++ ++SHOW_NAMESPACES = YES ++ ++# The FILE_VERSION_FILTER tag can be used to specify a program or script that ++# doxygen should invoke to get the current version for each file (typically from ++# the version control system). Doxygen will invoke the program by executing (via ++# popen()) the command , where is the value of ++# the FILE_VERSION_FILTER tag, and is the name of an input file ++# provided by doxygen. Whatever the program writes to standard output ++# is used as the file version. See the manual for examples. ++ ++FILE_VERSION_FILTER = ++ ++# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by ++# doxygen. The layout file controls the global structure of the generated output files ++# in an output format independent way. The create the layout file that represents ++# doxygen's defaults, run doxygen with the -l option. You can optionally specify a ++# file name after the option, if omitted DoxygenLayout.xml will be used as the name ++# of the layout file. ++ ++LAYOUT_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to warning and progress messages ++#--------------------------------------------------------------------------- ++ ++# The QUIET tag can be used to turn on/off the messages that are generated ++# by doxygen. Possible values are YES and NO. If left blank NO is used. ++ ++QUIET = YES ++ ++# The WARNINGS tag can be used to turn on/off the warning messages that are ++# generated by doxygen. Possible values are YES and NO. If left blank ++# NO is used. ++ ++WARNINGS = YES ++ ++# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings ++# for undocumented members. If EXTRACT_ALL is set to YES then this flag will ++# automatically be disabled. ++ ++WARN_IF_UNDOCUMENTED = YES ++ ++# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for ++# potential errors in the documentation, such as not documenting some ++# parameters in a documented function, or documenting parameters that ++# don't exist or using markup commands wrongly. ++ ++WARN_IF_DOC_ERROR = YES ++ ++# This WARN_NO_PARAMDOC option can be abled to get warnings for ++# functions that are documented, but have no documentation for their parameters ++# or return value. If set to NO (the default) doxygen will only warn about ++# wrong or incomplete parameter documentation, but not about the absence of ++# documentation. ++ ++WARN_NO_PARAMDOC = NO ++ ++# The WARN_FORMAT tag determines the format of the warning messages that ++# doxygen can produce. The string should contain the $file, $line, and $text ++# tags, which will be replaced by the file and line number from which the ++# warning originated and the warning text. Optionally the format may contain ++# $version, which will be replaced by the version of the file (if it could ++# be obtained via FILE_VERSION_FILTER) ++ ++WARN_FORMAT = "$file:$line: $text" ++ ++# The WARN_LOGFILE tag can be used to specify a file to which warning ++# and error messages should be written. If left blank the output is written ++# to stderr. ++ ++WARN_LOGFILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the input files ++#--------------------------------------------------------------------------- ++ ++# The INPUT tag can be used to specify the files and/or directories that contain ++# documented source files. You may enter file names like "myfile.cpp" or ++# directories like "/usr/src/myproject". Separate the files or directories ++# with spaces. ++ ++INPUT = ++ ++# This tag can be used to specify the character encoding of the source files ++# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is ++# also the default input encoding. Doxygen uses libiconv (or the iconv built ++# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for ++# the list of possible encodings. ++ ++INPUT_ENCODING = UTF-8 ++ ++# If the value of the INPUT tag contains directories, you can use the ++# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank the following patterns are tested: ++# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx ++# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 ++ ++FILE_PATTERNS = ++ ++# The RECURSIVE tag can be used to turn specify whether or not subdirectories ++# should be searched for input files as well. Possible values are YES and NO. ++# If left blank NO is used. ++ ++RECURSIVE = NO ++ ++# The EXCLUDE tag can be used to specify files and/or directories that should ++# excluded from the INPUT source files. This way you can easily exclude a ++# subdirectory from a directory tree whose root is specified with the INPUT tag. ++ ++EXCLUDE = ++ ++# The EXCLUDE_SYMLINKS tag can be used select whether or not files or ++# directories that are symbolic links (a Unix filesystem feature) are excluded ++# from the input. ++ ++EXCLUDE_SYMLINKS = NO ++ ++# If the value of the INPUT tag contains directories, you can use the ++# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude ++# certain files from those directories. Note that the wildcards are matched ++# against the file with absolute path, so to exclude all test directories ++# for example use the pattern */test/* ++ ++EXCLUDE_PATTERNS = ++ ++# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names ++# (namespaces, classes, functions, etc.) that should be excluded from the ++# output. The symbol name can be a fully qualified name, a word, or if the ++# wildcard * is used, a substring. Examples: ANamespace, AClass, ++# AClass::ANamespace, ANamespace::*Test ++ ++EXCLUDE_SYMBOLS = ++ ++# The EXAMPLE_PATH tag can be used to specify one or more files or ++# directories that contain example code fragments that are included (see ++# the \include command). ++ ++EXAMPLE_PATH = ++ ++# If the value of the EXAMPLE_PATH tag contains directories, you can use the ++# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank all files are included. ++ ++EXAMPLE_PATTERNS = ++ ++# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be ++# searched for input files to be used with the \include or \dontinclude ++# commands irrespective of the value of the RECURSIVE tag. ++# Possible values are YES and NO. If left blank NO is used. ++ ++EXAMPLE_RECURSIVE = NO ++ ++# The IMAGE_PATH tag can be used to specify one or more files or ++# directories that contain image that are included in the documentation (see ++# the \image command). ++ ++IMAGE_PATH = ++ ++# The INPUT_FILTER tag can be used to specify a program that doxygen should ++# invoke to filter for each input file. Doxygen will invoke the filter program ++# by executing (via popen()) the command , where ++# is the value of the INPUT_FILTER tag, and is the name of an ++# input file. Doxygen will then use the output that the filter program writes ++# to standard output. If FILTER_PATTERNS is specified, this tag will be ++# ignored. ++ ++INPUT_FILTER = ++ ++# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern ++# basis. Doxygen will compare the file name with each pattern and apply the ++# filter if there is a match. The filters are a list of the form: ++# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further ++# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER ++# is applied to all files. ++ ++FILTER_PATTERNS = ++ ++# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using ++# INPUT_FILTER) will be used to filter the input files when producing source ++# files to browse (i.e. when SOURCE_BROWSER is set to YES). ++ ++FILTER_SOURCE_FILES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to source browsing ++#--------------------------------------------------------------------------- ++ ++# If the SOURCE_BROWSER tag is set to YES then a list of source files will ++# be generated. Documented entities will be cross-referenced with these sources. ++# Note: To get rid of all source code in the generated output, make sure also ++# VERBATIM_HEADERS is set to NO. ++ ++SOURCE_BROWSER = NO ++ ++# Setting the INLINE_SOURCES tag to YES will include the body ++# of functions and classes directly in the documentation. ++ ++INLINE_SOURCES = NO ++ ++# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct ++# doxygen to hide any special comment blocks from generated source code ++# fragments. Normal C and C++ comments will always remain visible. ++ ++STRIP_CODE_COMMENTS = YES ++ ++# If the REFERENCED_BY_RELATION tag is set to YES ++# then for each documented function all documented ++# functions referencing it will be listed. ++ ++REFERENCED_BY_RELATION = NO ++ ++# If the REFERENCES_RELATION tag is set to YES ++# then for each documented function all documented entities ++# called/used by that function will be listed. ++ ++REFERENCES_RELATION = NO ++ ++# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) ++# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from ++# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will ++# link to the source code. Otherwise they will link to the documentstion. ++ ++REFERENCES_LINK_SOURCE = YES ++ ++# If the USE_HTAGS tag is set to YES then the references to source code ++# will point to the HTML generated by the htags(1) tool instead of doxygen ++# built-in source browser. The htags tool is part of GNU's global source ++# tagging system (see http://www.gnu.org/software/global/global.html). You ++# will need version 4.8.6 or higher. ++ ++USE_HTAGS = NO ++ ++# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen ++# will generate a verbatim copy of the header file for each class for ++# which an include is specified. Set to NO to disable this. ++ ++VERBATIM_HEADERS = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the alphabetical class index ++#--------------------------------------------------------------------------- ++ ++# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index ++# of all compounds will be generated. Enable this if the project ++# contains a lot of classes, structs, unions or interfaces. ++ ++ALPHABETICAL_INDEX = NO ++ ++# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then ++# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns ++# in which this list will be split (can be a number in the range [1..20]) ++ ++COLS_IN_ALPHA_INDEX = 5 ++ ++# In case all classes in a project start with a common prefix, all ++# classes will be put under the same header in the alphabetical index. ++# The IGNORE_PREFIX tag can be used to specify one or more prefixes that ++# should be ignored while generating the index headers. ++ ++IGNORE_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the HTML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_HTML tag is set to YES (the default) Doxygen will ++# generate HTML output. ++ ++GENERATE_HTML = YES ++ ++# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `html' will be used as the default path. ++ ++HTML_OUTPUT = html ++ ++# The HTML_FILE_EXTENSION tag can be used to specify the file extension for ++# each generated HTML page (for example: .htm,.php,.asp). If it is left blank ++# doxygen will generate files with .html extension. ++ ++HTML_FILE_EXTENSION = .html ++ ++# The HTML_HEADER tag can be used to specify a personal HTML header for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard header. ++ ++HTML_HEADER = ++ ++# The HTML_FOOTER tag can be used to specify a personal HTML footer for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard footer. ++ ++HTML_FOOTER = ++ ++# The HTML_STYLESHEET tag can be used to specify a user-defined cascading ++# style sheet that is used by each HTML page. It can be used to ++# fine-tune the look of the HTML output. If the tag is left blank doxygen ++# will generate a default style sheet. Note that doxygen will try to copy ++# the style sheet file to the HTML output directory, so don't put your own ++# stylesheet in the HTML output directory as well, or it will be erased! ++ ++HTML_STYLESHEET = ++ ++# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, ++# files or namespaces will be aligned in HTML using tables. If set to ++# NO a bullet list will be used. ++ ++HTML_ALIGN_MEMBERS = YES ++ ++# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML ++# documentation will contain sections that can be hidden and shown after the ++# page has loaded. For this to work a browser that supports ++# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox ++# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). ++ ++HTML_DYNAMIC_SECTIONS = NO ++ ++# If the GENERATE_DOCSET tag is set to YES, additional index files ++# will be generated that can be used as input for Apple's Xcode 3 ++# integrated development environment, introduced with OSX 10.5 (Leopard). ++# To create a documentation set, doxygen will generate a Makefile in the ++# HTML output directory. Running make will produce the docset in that ++# directory and running "make install" will install the docset in ++# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find ++# it at startup. ++# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. ++ ++GENERATE_DOCSET = NO ++ ++# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the ++# feed. A documentation feed provides an umbrella under which multiple ++# documentation sets from a single provider (such as a company or product suite) ++# can be grouped. ++ ++DOCSET_FEEDNAME = "Doxygen generated docs" ++ ++# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that ++# should uniquely identify the documentation set bundle. This should be a ++# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen ++# will append .docset to the name. ++ ++DOCSET_BUNDLE_ID = org.doxygen.Project ++ ++# If the GENERATE_HTMLHELP tag is set to YES, additional index files ++# will be generated that can be used as input for tools like the ++# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) ++# of the generated HTML documentation. ++ ++GENERATE_HTMLHELP = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can ++# be used to specify the file name of the resulting .chm file. You ++# can add a path in front of the file if the result should not be ++# written to the html output directory. ++ ++CHM_FILE = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can ++# be used to specify the location (absolute path including file name) of ++# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run ++# the HTML help compiler on the generated index.hhp. ++ ++HHC_LOCATION = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag ++# controls if a separate .chi index file is generated (YES) or that ++# it should be included in the master .chm file (NO). ++ ++GENERATE_CHI = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING ++# is used to encode HtmlHelp index (hhk), content (hhc) and project file ++# content. ++ ++CHM_INDEX_ENCODING = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag ++# controls whether a binary table of contents is generated (YES) or a ++# normal table of contents (NO) in the .chm file. ++ ++BINARY_TOC = NO ++ ++# The TOC_EXPAND flag can be set to YES to add extra items for group members ++# to the contents of the HTML help documentation and to the tree view. ++ ++TOC_EXPAND = NO ++ ++# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER ++# are set, an additional index file will be generated that can be used as input for ++# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated ++# HTML documentation. ++ ++GENERATE_QHP = NO ++ ++# If the QHG_LOCATION tag is specified, the QCH_FILE tag can ++# be used to specify the file name of the resulting .qch file. ++# The path specified is relative to the HTML output folder. ++ ++QCH_FILE = ++ ++# The QHP_NAMESPACE tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Namespace. ++ ++QHP_NAMESPACE = org.doxygen.Project ++ ++# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Virtual Folders. ++ ++QHP_VIRTUAL_FOLDER = doc ++ ++# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can ++# be used to specify the location of Qt's qhelpgenerator. ++# If non-empty doxygen will try to run qhelpgenerator on the generated ++# .qhp file . ++ ++QHG_LOCATION = ++ ++# The DISABLE_INDEX tag can be used to turn on/off the condensed index at ++# top of each HTML page. The value NO (the default) enables the index and ++# the value YES disables it. ++ ++DISABLE_INDEX = NO ++ ++# This tag can be used to set the number of enum values (range [1..20]) ++# that doxygen will group on one line in the generated HTML documentation. ++ ++ENUM_VALUES_PER_LINE = 4 ++ ++# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index ++# structure should be generated to display hierarchical information. ++# If the tag value is set to FRAME, a side panel will be generated ++# containing a tree-like index structure (just like the one that ++# is generated for HTML Help). For this to work a browser that supports ++# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, ++# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are ++# probably better off using the HTML help feature. Other possible values ++# for this tag are: HIERARCHIES, which will generate the Groups, Directories, ++# and Class Hierarchy pages using a tree view instead of an ordered list; ++# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which ++# disables this behavior completely. For backwards compatibility with previous ++# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE ++# respectively. ++ ++GENERATE_TREEVIEW = NONE ++ ++# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be ++# used to set the initial width (in pixels) of the frame in which the tree ++# is shown. ++ ++TREEVIEW_WIDTH = 250 ++ ++# Use this tag to change the font size of Latex formulas included ++# as images in the HTML documentation. The default is 10. Note that ++# when you change the font size after a successful doxygen run you need ++# to manually remove any form_*.png images from the HTML output directory ++# to force them to be regenerated. ++ ++FORMULA_FONTSIZE = 10 ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the LaTeX output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will ++# generate Latex output. ++ ++GENERATE_LATEX = NO ++ ++# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `latex' will be used as the default path. ++ ++LATEX_OUTPUT = latex ++ ++# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be ++# invoked. If left blank `latex' will be used as the default command name. ++ ++LATEX_CMD_NAME = latex ++ ++# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to ++# generate index for LaTeX. If left blank `makeindex' will be used as the ++# default command name. ++ ++MAKEINDEX_CMD_NAME = makeindex ++ ++# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact ++# LaTeX documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_LATEX = NO ++ ++# The PAPER_TYPE tag can be used to set the paper type that is used ++# by the printer. Possible values are: a4, a4wide, letter, legal and ++# executive. If left blank a4wide will be used. ++ ++PAPER_TYPE = a4wide ++ ++# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX ++# packages that should be included in the LaTeX output. ++ ++EXTRA_PACKAGES = ++ ++# The LATEX_HEADER tag can be used to specify a personal LaTeX header for ++# the generated latex document. The header should contain everything until ++# the first chapter. If it is left blank doxygen will generate a ++# standard header. Notice: only use this tag if you know what you are doing! ++ ++LATEX_HEADER = ++ ++# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated ++# is prepared for conversion to pdf (using ps2pdf). The pdf file will ++# contain links (just like the HTML output) instead of page references ++# This makes the output suitable for online browsing using a pdf viewer. ++ ++PDF_HYPERLINKS = YES ++ ++# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of ++# plain latex in the generated Makefile. Set this option to YES to get a ++# higher quality PDF documentation. ++ ++USE_PDFLATEX = YES ++ ++# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. ++# command to the generated LaTeX files. This will instruct LaTeX to keep ++# running if errors occur, instead of asking the user for help. ++# This option is also used when generating formulas in HTML. ++ ++LATEX_BATCHMODE = NO ++ ++# If LATEX_HIDE_INDICES is set to YES then doxygen will not ++# include the index chapters (such as File Index, Compound Index, etc.) ++# in the output. ++ ++LATEX_HIDE_INDICES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the RTF output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output ++# The RTF output is optimized for Word 97 and may not look very pretty with ++# other RTF readers or editors. ++ ++GENERATE_RTF = NO ++ ++# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `rtf' will be used as the default path. ++ ++RTF_OUTPUT = rtf ++ ++# If the COMPACT_RTF tag is set to YES Doxygen generates more compact ++# RTF documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_RTF = NO ++ ++# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated ++# will contain hyperlink fields. The RTF file will ++# contain links (just like the HTML output) instead of page references. ++# This makes the output suitable for online browsing using WORD or other ++# programs which support those fields. ++# Note: wordpad (write) and others do not support links. ++ ++RTF_HYPERLINKS = NO ++ ++# Load stylesheet definitions from file. Syntax is similar to doxygen's ++# config file, i.e. a series of assignments. You only have to provide ++# replacements, missing definitions are set to their default value. ++ ++RTF_STYLESHEET_FILE = ++ ++# Set optional variables used in the generation of an rtf document. ++# Syntax is similar to doxygen's config file. ++ ++RTF_EXTENSIONS_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the man page output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_MAN tag is set to YES (the default) Doxygen will ++# generate man pages ++ ++GENERATE_MAN = NO ++ ++# The MAN_OUTPUT tag is used to specify where the man pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `man' will be used as the default path. ++ ++MAN_OUTPUT = man ++ ++# The MAN_EXTENSION tag determines the extension that is added to ++# the generated man pages (default is the subroutine's section .3) ++ ++MAN_EXTENSION = .3 ++ ++# If the MAN_LINKS tag is set to YES and Doxygen generates man output, ++# then it will generate one additional man file for each entity ++# documented in the real man page(s). These additional files ++# only source the real man page, but without them the man command ++# would be unable to find the correct page. The default is NO. ++ ++MAN_LINKS = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the XML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_XML tag is set to YES Doxygen will ++# generate an XML file that captures the structure of ++# the code including all documentation. ++ ++GENERATE_XML = NO ++ ++# The XML_OUTPUT tag is used to specify where the XML pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `xml' will be used as the default path. ++ ++XML_OUTPUT = xml ++ ++# The XML_SCHEMA tag can be used to specify an XML schema, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_SCHEMA = ++ ++# The XML_DTD tag can be used to specify an XML DTD, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_DTD = ++ ++# If the XML_PROGRAMLISTING tag is set to YES Doxygen will ++# dump the program listings (including syntax highlighting ++# and cross-referencing information) to the XML output. Note that ++# enabling this will significantly increase the size of the XML output. ++ ++XML_PROGRAMLISTING = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options for the AutoGen Definitions output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will ++# generate an AutoGen Definitions (see autogen.sf.net) file ++# that captures the structure of the code including all ++# documentation. Note that this feature is still experimental ++# and incomplete at the moment. ++ ++GENERATE_AUTOGEN_DEF = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the Perl module output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_PERLMOD tag is set to YES Doxygen will ++# generate a Perl module file that captures the structure of ++# the code including all documentation. Note that this ++# feature is still experimental and incomplete at the ++# moment. ++ ++GENERATE_PERLMOD = NO ++ ++# If the PERLMOD_LATEX tag is set to YES Doxygen will generate ++# the necessary Makefile rules, Perl scripts and LaTeX code to be able ++# to generate PDF and DVI output from the Perl module output. ++ ++PERLMOD_LATEX = NO ++ ++# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be ++# nicely formatted so it can be parsed by a human reader. This is useful ++# if you want to understand what is going on. On the other hand, if this ++# tag is set to NO the size of the Perl module output will be much smaller ++# and Perl will parse it just the same. ++ ++PERLMOD_PRETTY = YES ++ ++# The names of the make variables in the generated doxyrules.make file ++# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. ++# This is useful so different doxyrules.make files included by the same ++# Makefile don't overwrite each other's variables. ++ ++PERLMOD_MAKEVAR_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the preprocessor ++#--------------------------------------------------------------------------- ++ ++# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will ++# evaluate all C-preprocessor directives found in the sources and include ++# files. ++ ++ENABLE_PREPROCESSING = YES ++ ++# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro ++# names in the source code. If set to NO (the default) only conditional ++# compilation will be performed. Macro expansion can be done in a controlled ++# way by setting EXPAND_ONLY_PREDEF to YES. ++ ++MACRO_EXPANSION = NO ++ ++# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES ++# then the macro expansion is limited to the macros specified with the ++# PREDEFINED and EXPAND_AS_DEFINED tags. ++ ++EXPAND_ONLY_PREDEF = NO ++ ++# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files ++# in the INCLUDE_PATH (see below) will be search if a #include is found. ++ ++SEARCH_INCLUDES = YES ++ ++# The INCLUDE_PATH tag can be used to specify one or more directories that ++# contain include files that are not input files but should be processed by ++# the preprocessor. ++ ++INCLUDE_PATH = ++ ++# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard ++# patterns (like *.h and *.hpp) to filter out the header-files in the ++# directories. If left blank, the patterns specified with FILE_PATTERNS will ++# be used. ++ ++INCLUDE_FILE_PATTERNS = ++ ++# The PREDEFINED tag can be used to specify one or more macro names that ++# are defined before the preprocessor is started (similar to the -D option of ++# gcc). The argument of the tag is a list of macros of the form: name ++# or name=definition (no spaces). If the definition and the = are ++# omitted =1 is assumed. To prevent a macro definition from being ++# undefined via #undef or recursively expanded use the := operator ++# instead of the = operator. ++ ++PREDEFINED = ++ ++# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then ++# this tag can be used to specify a list of macro names that should be expanded. ++# The macro definition that is found in the sources will be used. ++# Use the PREDEFINED tag if you want to use a different macro definition. ++ ++EXPAND_AS_DEFINED = ++ ++# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then ++# doxygen's preprocessor will remove all function-like macros that are alone ++# on a line, have an all uppercase name, and do not end with a semicolon. Such ++# function macros are typically used for boiler-plate code, and will confuse ++# the parser if not removed. ++ ++SKIP_FUNCTION_MACROS = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to external references ++#--------------------------------------------------------------------------- ++ ++# The TAGFILES option can be used to specify one or more tagfiles. ++# Optionally an initial location of the external documentation ++# can be added for each tagfile. The format of a tag file without ++# this location is as follows: ++# TAGFILES = file1 file2 ... ++# Adding location for the tag files is done as follows: ++# TAGFILES = file1=loc1 "file2 = loc2" ... ++# where "loc1" and "loc2" can be relative or absolute paths or ++# URLs. If a location is present for each tag, the installdox tool ++# does not have to be run to correct the links. ++# Note that each tag file must have a unique name ++# (where the name does NOT include the path) ++# If a tag file is not located in the directory in which doxygen ++# is run, you must also specify the path to the tagfile here. ++ ++TAGFILES = ++ ++# When a file name is specified after GENERATE_TAGFILE, doxygen will create ++# a tag file that is based on the input files it reads. ++ ++GENERATE_TAGFILE = ++ ++# If the ALLEXTERNALS tag is set to YES all external classes will be listed ++# in the class index. If set to NO only the inherited external classes ++# will be listed. ++ ++ALLEXTERNALS = NO ++ ++# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed ++# in the modules index. If set to NO, only the current project's groups will ++# be listed. ++ ++EXTERNAL_GROUPS = YES ++ ++# The PERL_PATH should be the absolute path and name of the perl script ++# interpreter (i.e. the result of `which perl'). ++ ++PERL_PATH = /usr/bin/perl ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the dot tool ++#--------------------------------------------------------------------------- ++ ++# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will ++# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base ++# or super classes. Setting the tag to NO turns the diagrams off. Note that ++# this option is superseded by the HAVE_DOT option below. This is only a ++# fallback. It is recommended to install and use dot, since it yields more ++# powerful graphs. ++ ++CLASS_DIAGRAMS = YES ++ ++# You can define message sequence charts within doxygen comments using the \msc ++# command. Doxygen will then run the mscgen tool (see ++# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the ++# documentation. The MSCGEN_PATH tag allows you to specify the directory where ++# the mscgen tool resides. If left empty the tool is assumed to be found in the ++# default search path. ++ ++MSCGEN_PATH = ++ ++# If set to YES, the inheritance and collaboration graphs will hide ++# inheritance and usage relations if the target is undocumented ++# or is not a class. ++ ++HIDE_UNDOC_RELATIONS = YES ++ ++# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is ++# available from the path. This tool is part of Graphviz, a graph visualization ++# toolkit from AT&T and Lucent Bell Labs. The other options in this section ++# have no effect if this option is set to NO (the default) ++ ++HAVE_DOT = NO ++ ++# By default doxygen will write a font called FreeSans.ttf to the output ++# directory and reference it in all dot files that doxygen generates. This ++# font does not include all possible unicode characters however, so when you need ++# these (or just want a differently looking font) you can specify the font name ++# using DOT_FONTNAME. You need need to make sure dot is able to find the font, ++# which can be done by putting it in a standard location or by setting the ++# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory ++# containing the font. ++ ++DOT_FONTNAME = FreeSans ++ ++# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. ++# The default size is 10pt. ++ ++DOT_FONTSIZE = 10 ++ ++# By default doxygen will tell dot to use the output directory to look for the ++# FreeSans.ttf font (which doxygen will put there itself). If you specify a ++# different font using DOT_FONTNAME you can set the path where dot ++# can find it using this tag. ++ ++DOT_FONTPATH = ++ ++# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect inheritance relations. Setting this tag to YES will force the ++# the CLASS_DIAGRAMS tag to NO. ++ ++CLASS_GRAPH = YES ++ ++# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect implementation dependencies (inheritance, containment, and ++# class references variables) of the class with other documented classes. ++ ++COLLABORATION_GRAPH = YES ++ ++# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for groups, showing the direct groups dependencies ++ ++GROUP_GRAPHS = YES ++ ++# If the UML_LOOK tag is set to YES doxygen will generate inheritance and ++# collaboration diagrams in a style similar to the OMG's Unified Modeling ++# Language. ++ ++UML_LOOK = NO ++ ++# If set to YES, the inheritance and collaboration graphs will show the ++# relations between templates and their instances. ++ ++TEMPLATE_RELATIONS = NO ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT ++# tags are set to YES then doxygen will generate a graph for each documented ++# file showing the direct and indirect include dependencies of the file with ++# other documented files. ++ ++INCLUDE_GRAPH = YES ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and ++# HAVE_DOT tags are set to YES then doxygen will generate a graph for each ++# documented header file showing the documented files that directly or ++# indirectly include this file. ++ ++INCLUDED_BY_GRAPH = YES ++ ++# If the CALL_GRAPH and HAVE_DOT options are set to YES then ++# doxygen will generate a call dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable call graphs ++# for selected functions only using the \callgraph command. ++ ++CALL_GRAPH = NO ++ ++# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then ++# doxygen will generate a caller dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable caller ++# graphs for selected functions only using the \callergraph command. ++ ++CALLER_GRAPH = NO ++ ++# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen ++# will graphical hierarchy of all classes instead of a textual one. ++ ++GRAPHICAL_HIERARCHY = YES ++ ++# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES ++# then doxygen will show the dependencies a directory has on other directories ++# in a graphical way. The dependency relations are determined by the #include ++# relations between the files in the directories. ++ ++DIRECTORY_GRAPH = YES ++ ++# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images ++# generated by dot. Possible values are png, jpg, or gif ++# If left blank png will be used. ++ ++DOT_IMAGE_FORMAT = png ++ ++# The tag DOT_PATH can be used to specify the path where the dot tool can be ++# found. If left blank, it is assumed the dot tool can be found in the path. ++ ++DOT_PATH = ++ ++# The DOTFILE_DIRS tag can be used to specify one or more directories that ++# contain dot files that are included in the documentation (see the ++# \dotfile command). ++ ++DOTFILE_DIRS = ++ ++# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of ++# nodes that will be shown in the graph. If the number of nodes in a graph ++# becomes larger than this value, doxygen will truncate the graph, which is ++# visualized by representing a node as a red box. Note that doxygen if the ++# number of direct children of the root node in a graph is already larger than ++# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note ++# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. ++ ++DOT_GRAPH_MAX_NODES = 50 ++ ++# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the ++# graphs generated by dot. A depth value of 3 means that only nodes reachable ++# from the root by following a path via at most 3 edges will be shown. Nodes ++# that lay further from the root node will be omitted. Note that setting this ++# option to 1 or 2 may greatly reduce the computation time needed for large ++# code bases. Also note that the size of a graph can be further restricted by ++# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. ++ ++MAX_DOT_GRAPH_DEPTH = 0 ++ ++# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent ++# background. This is disabled by default, because dot on Windows does not ++# seem to support this out of the box. Warning: Depending on the platform used, ++# enabling this option may lead to badly anti-aliased labels on the edges of ++# a graph (i.e. they become hard to read). ++ ++DOT_TRANSPARENT = NO ++ ++# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output ++# files in one run (i.e. multiple -o and -T options on the command line). This ++# makes dot run faster, but since only newer versions of dot (>1.8.10) ++# support this, this feature is disabled by default. ++ ++DOT_MULTI_TARGETS = NO ++ ++# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will ++# generate a legend page explaining the meaning of the various boxes and ++# arrows in the dot generated graphs. ++ ++GENERATE_LEGEND = YES ++ ++# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will ++# remove the intermediate dot files that are used to generate ++# the various graphs. ++ ++DOT_CLEANUP = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to the search engine ++#--------------------------------------------------------------------------- ++ ++# The SEARCHENGINE tag specifies whether or not a search engine should be ++# used. If set to NO the values of all tags below this one will be ignored. ++ ++SEARCHENGINE = NO +diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h +new file mode 100644 +index 0000000..756590e +--- /dev/null ++++ b/libiscsi/libiscsi.h +@@ -0,0 +1,344 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#ifndef __LIBISCSI_H ++#define __LIBISCSI_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++#if __GNUC__ >= 4 ++#define PUBLIC __attribute__ ((visibility("default"))) ++#else ++#define PUBLIC ++#endif ++ ++/** \brief Maximum length for iSCSI values. ++ * ++ * Maximum length for iSCSI values such as hostnames and parameter values. ++ */ ++#define LIBISCSI_VALUE_MAXLEN 256 ++ ++/** \brief supported authentication methods ++ * ++ * This enum lists all supported authentication methods. ++ */ ++enum libiscsi_auth_t { ++ libiscsi_auth_none /** No authentication */, ++ libiscsi_auth_chap /** CHAP authentication */, ++}; ++ ++/** \brief libiscsi context struct ++ * ++ * Note: even though libiscsi uses a context struct, the underlying open-iscsi ++ * code does not, so libiscsi is not thread safe, not even when using one ++ * context per thread! ++ */ ++struct libiscsi_context; ++ ++/** \brief iSCSI node record ++ * ++ * Struct holding data uniquely identifying an iSCSI node. ++ */ ++struct libiscsi_node { ++ char name[LIBISCSI_VALUE_MAXLEN] /** iSCSI iqn for the node. */; ++ int tpgt /** Portal group number. */; ++ /* Note open-iscsi has some code in place for multiple connections in one ++ node record and thus multiple address / port combi's, but this does not ++ get used anywhere, so we keep things simple and assume one connection */ ++ char address[NI_MAXHOST] /** Portal hostname or IP-address. */; ++ int port /** Portal port number. */; ++ char iface[LIBISCSI_VALUE_MAXLEN] /** Interface to connect through. */; ++}; ++ ++/** \brief libiscsi CHAP authentication information struct ++ * ++ * Struct holding all data needed for CHAP login / authentication. Note that ++ * \e reverse_username may be a 0 length string in which case only forward ++ * authentication will be done. ++ */ ++struct libiscsi_chap_auth_info { ++ char username[LIBISCSI_VALUE_MAXLEN] /** Username */; ++ char password[LIBISCSI_VALUE_MAXLEN] /** Password */; ++ char reverse_username[LIBISCSI_VALUE_MAXLEN] /** Reverse Username */; ++ char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */; ++}; ++ ++/** \brief generic libiscsi authentication information struct ++ * ++ * Struct holding authentication information for discovery and login. ++ */ ++struct libiscsi_auth_info { ++ enum libiscsi_auth_t method /** Authentication method to use */; ++ union { ++ struct libiscsi_chap_auth_info chap /** Chap specific info */; ++ } /** Union holding method depenend info */; ++}; ++ ++/** \brief Initalize libiscsi ++ * ++ * This function creates a libiscsi context and initalizes it. This context ++ * is need to use other libiscsi funtions. ++ * ++ * \return A pointer to the created context, or NULL in case of an error. ++ */ ++PUBLIC struct libiscsi_context *libiscsi_init(void); ++ ++/** \brief Cleanup libiscsi used resource ++ * ++ * This function cleanups any used resources and then destroys the passed ++ * context. After this the passed in context may no longer be used! ++ * ++ * \param context libiscsi context to operate on. ++ */ ++PUBLIC void libiscsi_cleanup(struct libiscsi_context *context); ++ ++/** \brief Discover iSCSI nodes using sendtargets and add them to the node db. ++ * ++ * This function connects to the given address and port and then tries to ++ * discover iSCSI nodes using the sendtargets protocol. Any found nodes are ++ * added to the local iSCSI node database and are returned in a dynamically ++ * allocated array. ++ * ++ * Note that the (optional) authentication info is for authenticating the ++ * discovery, and is not for the found nodes! If the connection(s) to the ++ * node(s) need authentication too, you can set the username / password for ++ * those (which can be different!) using the libiscsi_node_set_auth() function. ++ * ++ * \param context libiscsi context to operate on. ++ * \param address Hostname or IP-address to connect to. ++ * \param port Port to connect to, or 0 for the default port. ++ * \param auth_info Authentication information, or NULL. ++ * \param nr_found The number of found nodes will be returned ++ * through this pointer if not NULL. ++ * \param found_nodes The address of the dynamically allocated array ++ * of found nodes will be returned through this ++ * pointer if not NULL. The caller must free this ++ * array using free(). ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context, ++ const char *address, int port, const struct libiscsi_auth_info *auth_info, ++ int *nr_found, struct libiscsi_node **found_nodes); ++ ++/** \brief Read iSCSI node info from firmware and add them to the node db. ++ * ++ * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found ++ * nodes are added to the local iSCSI node database and are returned in a ++ * dynamically allocated array. ++ * ++ * Note that unlike sendtargets discovery, this function will also read ++ * authentication info and store that in the database too. ++ * ++ * Note this function currently is a stub which will always return -EINVAL ++ * (IOW it is not yet implemented) ++ * ++ * \param context libiscsi context to operate on. ++ * \param nr_found The number of found nodes will be returned ++ * through this pointer if not NULL. ++ * \param found_nodes The address of the dynamically allocated array ++ * of found nodes will be returned through this ++ * pointer if not NULL. The caller must free this ++ * array using free(). ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_discover_firmware(struct libiscsi_context *context, ++ int *nr_found, struct libiscsi_node **found_nodes); ++ ++/** \brief Check validity of the given authentication info. ++ * ++ * This function checks the validity of the given authentication info. For ++ * example in case of CHAP, if the username and password are not empty. ++ * ++ * This function is mainly intended for use by language bindings. ++ * ++ * \param context libiscsi context to operate on. ++ * \param auth_info Authentication information to check. ++ * \return 0 on success, otherwise EINVAL. ++ */ ++PUBLIC int libiscsi_verify_auth_info(struct libiscsi_context *context, ++ const struct libiscsi_auth_info *auth_info); ++ ++/** \brief Set the authentication info for the given node. ++ * ++ * This function sets the authentication information for the node described by ++ * the given node record. This will overwrite any existing authentication ++ * information. ++ * ++ * This is the way to specify authentication information for nodes found ++ * through sendtargets discovery. ++ * ++ * Note: ++ * 1) This is a convience wrapper around libiscsi_node_set_parameter(), ++ * setting the node.session.auth.* parameters. ++ * 2) For nodes found through firmware discovery the authentication information ++ * has already been set from the firmware. ++ * 3) \e auth_info may be NULL in which case any existing authinfo will be ++ * cleared. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to set auth information of ++ * \param auth_info Authentication information, or NULL. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_set_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const struct libiscsi_auth_info *auth_info); ++ ++/** \brief Get the authentication info for the given node. ++ * ++ * This function gets the authentication information for the node described by ++ * the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to set auth information of ++ * \param auth_info Pointer to a libiscsi_auth_info struct where ++ * the retreived information will be stored. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_get_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ struct libiscsi_auth_info *auth_info); ++ ++/** \brief Login to an iSCSI node. ++ * ++ * Login to the iSCSI node described by the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to login to. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_login(struct libiscsi_context *context, ++ const struct libiscsi_node *node); ++ ++/** \brief Logout of an iSCSI node. ++ * ++ * Logout of the iSCSI node described by the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to logout from. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_logout(struct libiscsi_context *context, ++ const struct libiscsi_node *node); ++ ++/** \brief Set an iSCSI parameter for the given node ++ * ++ * Set the given nodes iSCSI parameter named by \e parameter to value \e value. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to change a parameter from. ++ * \param parameter Name of the parameter to set. ++ * \param value Value to set the parameter too. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_set_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const char *parameter, const char *value); ++ ++/** \brief Get the value of an iSCSI parameter for the given node ++ * ++ * Get the value of the given nodes iSCSI parameter named by \e parameter. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to change a parameter from. ++ * \param parameter Name of the parameter to get. ++ * \param value The retreived value is stored here, this buffer must be ++ * atleast LIBISCSI_VALUE_MAXLEN bytes large. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_get_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, const char *parameter, char *value); ++ ++/** \brief Get human readable string describing the last libiscsi error. ++ * ++ * This function can be called to get a human readable error string when a ++ * libiscsi function has returned an error. This function uses a single buffer ++ * per context, thus the result is only valid as long as no other libiscsi ++ * calls are made on the same context after the failing function call. ++ * ++ * \param context libiscsi context to operate on. ++ * ++ * \return human readable string describing the last libiscsi error. ++ */ ++PUBLIC const char *libiscsi_get_error_string(struct libiscsi_context *context); ++ ++ ++/************************** Utility functions *******************************/ ++ ++/** \brief libiscsi network config struct ++ * ++ * libiscsi network config struct. ++ */ ++struct libiscsi_network_config { ++ int dhcp /** Using DHCP? (boolean). */; ++ char iface_name[LIBISCSI_VALUE_MAXLEN] /** Interface name. */; ++ char mac_address[LIBISCSI_VALUE_MAXLEN] /** MAC address. */; ++ char ip_address[LIBISCSI_VALUE_MAXLEN] /** IP address. */; ++ char netmask[LIBISCSI_VALUE_MAXLEN] /** Netmask. */; ++ char gateway[LIBISCSI_VALUE_MAXLEN] /** IP of Default gateway. */; ++ char primary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Primary DNS. */; ++ char secondary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Secondary DNS. */; ++}; ++ ++/** \brief Get network configuration information from iscsi firmware ++ * ++ * Function can be called to get the network configuration information ++ * (like dhcp, ip, netmask, default gateway, etc.) from the firmware of a ++ * network adapter with iscsi boot firmware. ++ * ++ * Note that not all fields of the returned struct are necessarilly filled, ++ * unset fields contain a 0 length string. ++ * ++ * \param config pointer to a libiscsi_network_config struct to fill. ++ * ++ * \return 0 on success, ENODEV when no iscsi firmware was found. ++ */ ++PUBLIC int libiscsi_get_firmware_network_config( ++ struct libiscsi_network_config *config); ++ ++/** \brief Get the initiator name (iqn) from the iscsi firmware ++ * ++ * Get the initiator name (iqn) from the iscsi firmware. ++ * ++ * \param initiatorname The initiator name is stored here, this buffer must be ++ * atleast LIBISCSI_VALUE_MAXLEN bytes large. ++ * \return 0 on success, ENODEV when no iscsi firmware was found. ++ */ ++PUBLIC int libiscsi_get_firmware_initiator_name(char *initiatorname); ++ ++#undef PUBLIC ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif +diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c +new file mode 100644 +index 0000000..4b09aa7 +--- /dev/null ++++ b/libiscsi/pylibiscsi.c +@@ -0,0 +1,638 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include "libiscsi.h" ++ ++static struct libiscsi_context *context = NULL; ++ ++/****************************** helpers ***********************************/ ++static int check_string(const char *string) ++{ ++ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) { ++ PyErr_SetString(PyExc_ValueError, "string too long"); ++ return -1; ++ } ++ return 0; ++} ++ ++/********************** PyIscsiChapAuthInfo ***************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_auth_info info; ++} PyIscsiChapAuthInfo; ++ ++static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ int i; ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char *kwlist[] = {"username", "password", "reverse_username", ++ "reverse_password", NULL}; ++ const char *string[4] = { NULL, NULL, NULL, NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, ++ "zz|zz:chapAuthInfo.__init__", ++ kwlist, &string[0], &string[1], ++ &string[2], &string[3])) ++ return -1; ++ ++ for (i = 0; i < 4; i++) ++ if (string[i] && check_string(string[i])) ++ return -1; ++ ++ memset (&chap->info, 0, sizeof(chap->info)); ++ chap->info.method = libiscsi_auth_chap; ++ if (string[0]) ++ strcpy(chap->info.chap.username, string[0]); ++ if (string[1]) ++ strcpy(chap->info.chap.password, string[1]); ++ if (string[2]) ++ strcpy(chap->info.chap.reverse_username, string[2]); ++ if (string[3]) ++ strcpy(chap->info.chap.reverse_password, string[3]); ++ ++ if (libiscsi_verify_auth_info(context, &chap->info)) { ++ PyErr_SetString(PyExc_ValueError, ++ libiscsi_get_error_string(context)); ++ return -1; ++ } ++ return 0; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "username")) { ++ return PyString_FromString(chap->info.chap.username); ++ } else if (!strcmp(attr, "password")) { ++ return PyString_FromString(chap->info.chap.password); ++ } else if (!strcmp(attr, "reverse_username")) { ++ return PyString_FromString(chap->info.chap.reverse_username); ++ } else if (!strcmp(attr, "reverse_password")) { ++ return PyString_FromString(chap->info.chap.reverse_password); ++ } ++ return NULL; ++} ++ ++static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ ++ if (!strcmp(attr, "username")) { ++ strcpy(chap->info.chap.username, str); ++ } else if (!strcmp(attr, "password")) { ++ strcpy(chap->info.chap.password, str); ++ } else if (!strcmp(attr, "reverse_username")) { ++ strcpy(chap->info.chap.reverse_username, str); ++ } else if (!strcmp(attr, "reverse_password")) { ++ strcpy(chap->info.chap.reverse_password, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self, ++ PyIscsiChapAuthInfo *other) ++{ ++ int r; ++ ++ r = strcmp(self->info.chap.username, other->info.chap.username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.password, other->info.chap.password); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_username, ++ other->info.chap.reverse_username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_password, ++ other->info.chap.reverse_password); ++ return r; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_str(PyObject *self) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char s[1024], reverse[512] = ""; ++ ++ if (chap->info.chap.reverse_username[0]) ++ snprintf(reverse, sizeof(reverse), ", %s:%s", ++ chap->info.chap.reverse_username, ++ chap->info.chap.reverse_password); ++ ++ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username, ++ chap->info.chap.password, reverse); ++ ++ return PyString_FromString(s); ++} ++ ++static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = { ++ {"username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "username", "username"}, ++ {"password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "password", "password"}, ++ {"reverse_username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_username", "reverse_username"}, ++ {"reverse_password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_password", "reverse_password"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiChapAuthInfo_Type = { ++ PyObject_HEAD_INIT(NULL) ++ .tp_name = "libiscsi.chapAuthInfo", ++ .tp_basicsize = sizeof (PyIscsiChapAuthInfo), ++ .tp_getset = PyIscsiChapAuthInfo_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | ++ Py_TPFLAGS_BASETYPE, ++ .tp_compare = (cmpfunc)PyIscsiChapAuthInfo_compare, ++ .tp_init = PyIscsiChapAuthInfo_init, ++ .tp_str = PyIscsiChapAuthInfo_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "iscsi chap authentication information.", ++}; ++ ++/***************************** PyIscsiNode ********************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_node node; ++} PyIscsiNode; ++ ++static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char *kwlist[] = {"name", "tpgt", "address", "port", "iface", NULL}; ++ const char *name = NULL, *address = NULL, *iface = NULL; ++ int tpgt = -1, port = 3260; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isis:node.__init__", ++ kwlist, &name, &tpgt, &address, ++ &port, &iface)) ++ return -1; ++ if (address == NULL) { ++ PyErr_SetString(PyExc_ValueError, "address not set"); ++ return -1; ++ } ++ if (check_string(name) || check_string(address) || check_string(iface)) ++ return -1; ++ ++ strcpy(node->node.name, name); ++ node->node.tpgt = tpgt; ++ strcpy(node->node.address, address); ++ node->node.port = port; ++ strcpy(node->node.iface, iface); ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_get(PyObject *self, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "name")) { ++ return PyString_FromString(node->node.name); ++ } else if (!strcmp(attr, "tpgt")) { ++ return PyInt_FromLong(node->node.tpgt); ++ } else if (!strcmp(attr, "address")) { ++ return PyString_FromString(node->node.address); ++ } else if (!strcmp(attr, "port")) { ++ return PyInt_FromLong(node->node.port); ++ } else if (!strcmp(attr, "iface")) { ++ return PyString_FromString(node->node.iface); ++ } ++ return NULL; ++} ++ ++static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ int i; ++ ++ if (!strcmp(attr, "name")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.name, str); ++ } else if (!strcmp(attr, "tpgt")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.tpgt = i; ++ } else if (!strcmp(attr, "address")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.address, str); ++ } else if (!strcmp(attr, "port")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.port = i; ++ } else if (!strcmp(attr, "iface")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.iface, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other) ++{ ++ int res; ++ ++ res = strcmp(self->node.name, other->node.name); ++ if (res) ++ return res; ++ ++ if (self->node.tpgt < other->node.tpgt) ++ return -1; ++ if (self->node.tpgt > other->node.tpgt) ++ return -1; ++ ++ res = strcmp(self->node.address, other->node.address); ++ if (res) ++ return res; ++ ++ if (self->node.port < other->node.port) ++ return -1; ++ if (self->node.port > other->node.port) ++ return -1; ++ ++ res = strcmp(self->node.iface, other->node.iface); ++ if (res) ++ return res; ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_str(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char s[1024], tpgt[16] = ""; ++ ++ if (node->node.tpgt != -1) ++ sprintf(tpgt, ",%d", node->node.tpgt); ++ ++ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address, ++ node->node.port, tpgt, node->node.name); ++ ++ return PyString_FromString(s); ++} ++ ++static PyObject *PyIscsiNode_login(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_login(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_logout(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_logout(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"authinfo", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyObject *arg; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) ++ return NULL; ++ ++ if (arg == Py_None) { ++ authinfo = NULL; ++ } else if (PyObject_IsInstance(arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg; ++ authinfo = &pyauthinfo->info; ++ } else { ++ PyErr_SetString(PyExc_ValueError, "invalid authinfo type"); ++ return NULL; ++ } ++ ++ if (libiscsi_node_set_auth(context, &node->node, authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getAuth(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyIscsiChapAuthInfo *pyauthinfo; ++ struct libiscsi_auth_info authinfo; ++ ++ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ switch (authinfo.method) { ++ case libiscsi_auth_chap: ++ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo, ++ &PyIscsiChapAuthInfo_Type); ++ if (!pyauthinfo) ++ return NULL; ++ ++ pyauthinfo->info = authinfo; ++ ++ return (PyObject *)pyauthinfo; ++ ++ case libiscsi_auth_none: ++ default: ++ Py_RETURN_NONE; ++ } ++} ++ ++static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", "value", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter, *value; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, ++ ¶meter, &value)) ++ return NULL; ++ if (check_string(parameter) || check_string(value)) ++ return NULL; ++ ++ if (libiscsi_node_set_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, ¶meter)) ++ return NULL; ++ if (check_string(parameter)) ++ return NULL; ++ ++ if (libiscsi_node_get_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ return Py_BuildValue("s", value); ++} ++ ++static struct PyGetSetDef PyIscsiNode_getseters[] = { ++ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "name", "name"}, ++ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "tpgt", "tpgt"}, ++ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "address", "address"}, ++ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "port", "port"}, ++ {"iface", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "iface", "iface"}, ++ {NULL} ++}; ++ ++static struct PyMethodDef PyIscsiNode_methods[] = { ++ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS, ++ "Log in to the node"}, ++ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS, ++ "Log out of the node"}, ++ {"setAuth", (PyCFunction) PyIscsiNode_setAuth, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set authentication information"}, ++ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS, ++ "Get authentication information"}, ++ {"setParameter", (PyCFunction) PyIscsiNode_setParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set an iscsi node parameter"}, ++ {"getParameter", (PyCFunction) PyIscsiNode_getParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Get an iscsi node parameter"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiNode_Type = { ++ PyObject_HEAD_INIT(NULL) ++ .tp_name = "libiscsi.node", ++ .tp_basicsize = sizeof (PyIscsiNode), ++ .tp_getset = PyIscsiNode_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | ++ Py_TPFLAGS_BASETYPE, ++ .tp_methods = PyIscsiNode_methods, ++ .tp_compare = (cmpfunc)PyIscsiNode_compare, ++ .tp_init = PyIscsiNode_init, ++ .tp_str = PyIscsiNode_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "The iscsi node contains iscsi node information.", ++}; ++ ++/***************************************************************************/ ++ ++static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, ++ PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"address", "port", "authinfo", NULL}; ++ const char *address = NULL; ++ int i, nr_found, port = 3260; ++ PyObject *authinfo_arg = NULL; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO", ++ kwlist, &address, &port, ++ &authinfo_arg)) ++ return NULL; ++ ++ if (authinfo_arg) { ++ if (PyObject_IsInstance(authinfo_arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = ++ (PyIscsiChapAuthInfo *)authinfo_arg; ++ authinfo = &pyauthinfo->info; ++ } else if (authinfo_arg != Py_None) { ++ PyErr_SetString(PyExc_ValueError, ++ "invalid authinfo type"); ++ return NULL; ++ } ++ } ++ ++ if (libiscsi_discover_sendtargets(context, address, port, authinfo, ++ &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_discover_firmware(PyObject *self) ++{ ++ int i, nr_found; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (libiscsi_discover_firmware(context, &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_get_firmware_initiator_name(PyObject *self) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ return PyString_FromString(initiatorname); ++} ++ ++static PyMethodDef pylibiscsi_functions[] = { ++ { "discover_sendtargets", ++ (PyCFunction)pylibiscsi_discover_sendtargets, ++ METH_VARARGS|METH_KEYWORDS, ++ "Do sendtargets discovery and return a list of found nodes)"}, ++ { "discover_firmware", ++ (PyCFunction)pylibiscsi_discover_firmware, METH_NOARGS, ++ "Do firmware discovery and return a list of found nodes)"}, ++ { "get_firmware_initiator_name", ++ (PyCFunction)pylibiscsi_get_firmware_initiator_name, ++ METH_NOARGS, ++ "Get initator name (iqn) from firmware"}, ++ {NULL, NULL} ++}; ++ ++PyMODINIT_FUNC initlibiscsi(void) ++{ ++ PyObject *m; ++ ++ if (!context) /* We may be called more then once */ ++ context = libiscsi_init(); ++ if (!context) ++ return; ++ ++ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0) ++ return; ++ ++ if (PyType_Ready(&PyIscsiNode_Type) < 0) ++ return; ++ ++ m = Py_InitModule("libiscsi", pylibiscsi_functions); ++ Py_INCREF(&PyIscsiChapAuthInfo_Type); ++ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type); ++ Py_INCREF(&PyIscsiNode_Type); ++ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type); ++} +diff --git a/libiscsi/setup.py b/libiscsi/setup.py +new file mode 100644 +index 0000000..bb4329b +--- /dev/null ++++ b/libiscsi/setup.py +@@ -0,0 +1,9 @@ ++from distutils.core import setup, Extension ++ ++module1 = Extension('libiscsimodule', ++ sources = ['pylibiscsi.c'], ++ libraries = ['iscsi'], ++ library_dirs = ['.']) ++ ++setup (name = 'PyIscsi',version = '1.0', ++ description = 'libiscsi python bindings', ext_modules = [module1]) +diff --git a/libiscsi/tests/test_discovery_firmware.c b/libiscsi/tests/test_discovery_firmware.c +new file mode 100644 +index 0000000..76e852a +--- /dev/null ++++ b/libiscsi/tests/test_discovery_firmware.c +@@ -0,0 +1,53 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_discover_firmware(context, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_discovery_sendtargets.c b/libiscsi/tests/test_discovery_sendtargets.c +new file mode 100644 +index 0000000..1a3c12e +--- /dev/null ++++ b/libiscsi/tests/test_discovery_sendtargets.c +@@ -0,0 +1,60 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ rc = libiscsi_discover_sendtargets(context, "127.0.0.1", 3260, ++ &auth_info, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_get_auth.c b/libiscsi/tests/test_get_auth.c +new file mode 100644 +index 0000000..5e234da +--- /dev/null ++++ b/libiscsi/tests/test_get_auth.c +@@ -0,0 +1,70 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_auth(context, &node, &auth_info); ++ if (rc) { ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ switch (auth_info.method) { ++ case libiscsi_auth_none: ++ printf("Method: \"None\"\n"); ++ break; ++ case libiscsi_auth_chap: ++ printf("Method: \"CHAP\"\n"); ++ printf("User: \"%s\"\n", auth_info.chap.username); ++ printf("Pass: \"%s\"\n", auth_info.chap.password); ++ printf("RevUser: \"%s\"\n", ++ auth_info.chap.reverse_username); ++ printf("RevPass: \"%s\"\n", ++ auth_info.chap.reverse_password); ++ break; ++ } ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_get_initiator_name.c b/libiscsi/tests/test_get_initiator_name.c +new file mode 100644 +index 0000000..997c053 +--- /dev/null ++++ b/libiscsi/tests/test_get_initiator_name.c +@@ -0,0 +1,38 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("iqn:\t%s\n", initiatorname); ++ ++ return 0; ++} +diff --git a/libiscsi/tests/test_get_network_config.c b/libiscsi/tests/test_get_network_config.c +new file mode 100644 +index 0000000..2dedd61 +--- /dev/null ++++ b/libiscsi/tests/test_get_network_config.c +@@ -0,0 +1,45 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_network_config config; ++ ++ if (libiscsi_get_firmware_network_config(&config)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("dhcp:\t%d\n", config.dhcp); ++ printf("iface:\t%s\n", config.iface_name); ++ printf("mac:\t%s\n", config.mac_address); ++ printf("ipaddr:\t%s\n", config.ip_address); ++ printf("mask:\t%s\n", config.netmask); ++ printf("gate:\t%s\n", config.gateway); ++ printf("dns1:\t%s\n", config.primary_dns); ++ printf("dns2:\t%s\n", config.secondary_dns); ++ ++ return 0; ++} +diff --git a/libiscsi/tests/test_login.c b/libiscsi/tests/test_login.c +new file mode 100644 +index 0000000..3eb70d6 +--- /dev/null ++++ b/libiscsi/tests/test_login.c +@@ -0,0 +1,52 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_login(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging in: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_logout.c b/libiscsi/tests/test_logout.c +new file mode 100644 +index 0000000..b734dca +--- /dev/null ++++ b/libiscsi/tests/test_logout.c +@@ -0,0 +1,51 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_logout(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging out: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_params.c b/libiscsi/tests/test_params.c +new file mode 100644 +index 0000000..d3223be +--- /dev/null ++++ b/libiscsi/tests/test_params.c +@@ -0,0 +1,103 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ char orig_value[LIBISCSI_VALUE_MAXLEN], value[LIBISCSI_VALUE_MAXLEN]; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ "automatic"); ++ if (rc) { ++ fprintf(stderr, "Error setting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error getting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, "automatic")) { ++ fprintf(stderr, "Error set and get values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error setting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error re-getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, orig_value)) { ++ fprintf(stderr, ++ "Error set and get original values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_set_auth.c b/libiscsi/tests/test_set_auth.c +new file mode 100644 +index 0000000..a21f888 +--- /dev/null ++++ b/libiscsi/tests/test_set_auth.c +@@ -0,0 +1,58 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_set_auth(context, &node, &auth_info); ++ if (rc) ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/usr/Makefile b/usr/Makefile +index 3d8ee22..e731545 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -31,7 +31,7 @@ endif + OPTFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wstrict-prototypes + CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../include -I. -I../utils/open-isns \ +- -D$(OSNAME) $(IPC_CFLAGS) ++ -D$(OSNAME) $(IPC_CFLAGS) -DISNS_ENABLE + PROGRAMS = iscsid iscsiadm iscsistart + + # libc compat files +diff --git a/usr/discovery.c b/usr/discovery.c +index afce6c0..0c93749 100644 +--- a/usr/discovery.c ++++ b/usr/discovery.c +@@ -36,6 +36,7 @@ + #include "types.h" + #include "iscsi_proto.h" + #include "initiator.h" ++#include "config.h" + #include "log.h" + #include "idbm.h" + #include "iscsi_settings.h" +@@ -50,9 +51,11 @@ + #include "iscsi_timer.h" + #include "iscsi_err.h" + /* libisns includes */ ++#ifdef ISNS_ENABLE + #include "isns.h" + #include "paths.h" + #include "message.h" ++#endif + + #ifdef SLP_ENABLE + #include "iscsi-slp-discovery.h" +@@ -98,6 +101,7 @@ static int request_initiator_name(void) + return 0; + } + ++#ifdef ISNS_ENABLE + void discovery_isns_free_servername(void) + { + if (isns_config.ic_server_name) +@@ -377,6 +381,7 @@ retry: + discovery_isns_free_servername(); + return rc; + } ++#endif + + int discovery_fw(void *data, struct iface_rec *iface, + struct list_head *rec_list) +diff --git a/usr/idbm.c b/usr/idbm.c +index 4bb9810..c84ae69 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1515,9 +1515,9 @@ int idbm_print_all_discovery(int info_level) + * fn should return -1 if it skipped the rec, a ISCSI_ERR error code if + * the operation failed or 0 if fn was run successfully. + */ +-static int idbm_for_each_iface(int *found, void *data, +- idbm_iface_op_fn *fn, +- char *targetname, int tpgt, char *ip, int port) ++int idbm_for_each_iface(int *found, void *data, ++ idbm_iface_op_fn *fn, ++ char *targetname, int tpgt, char *ip, int port) + { + DIR *iface_dirfd; + struct dirent *iface_dent; +diff --git a/usr/idbm.h b/usr/idbm.h +index 1e9b132..4d08b31 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -102,6 +102,9 @@ struct rec_op_data { + node_rec_t *match_rec; + idbm_iface_op_fn *fn; + }; ++extern int idbm_for_each_iface(int *found, void *data, ++ idbm_iface_op_fn *fn, ++ char *targetname, int tpgt, char *ip, int port); + extern int idbm_for_each_portal(int *found, void *data, + idbm_portal_op_fn *fn, char *targetname); + extern int idbm_for_each_node(int *found, void *data, +diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h +index b6665cb..3e7f82a 100644 +--- a/usr/iscsi_ipc.h ++++ b/usr/iscsi_ipc.h +@@ -160,4 +160,6 @@ struct iscsi_ipc { + uint32_t host_no, uint32_t sid); + }; + ++struct iscsi_ipc *ipc; ++ + #endif /* ISCSI_IPC_H */ +-- +1.8.1.4 + diff --git a/0155-dont-use-static.patch b/0155-dont-use-static.patch new file mode 100644 index 0000000..9e43b7b --- /dev/null +++ b/0155-dont-use-static.patch @@ -0,0 +1,25 @@ +From ff224a16d409c4b479b3ac1ff662093cb067e281 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 17:04:29 -0800 +Subject: dont use static + +--- + usr/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/usr/Makefile b/usr/Makefile +index 015f1b9..1669890 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -61,7 +61,7 @@ iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o + + iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ + iscsistart.o statics.o +- $(CC) $(CFLAGS) -static $^ -o $@ ++ $(CC) $(CFLAGS) $^ -o $@ + clean: + rm -f *.o $(PROGRAMS) .depend $(LIBSYS) + +-- +1.7.11.7 + diff --git a/0156-remove-the-offload-boot-supported-ifdef.patch b/0156-remove-the-offload-boot-supported-ifdef.patch new file mode 100644 index 0000000..a1ccdc7 --- /dev/null +++ b/0156-remove-the-offload-boot-supported-ifdef.patch @@ -0,0 +1,45 @@ +From aa58a042ec20575143c1a5c813c9552a286aeb0e Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 17:09:24 -0800 +Subject: remove the offload boot supported ifdef + +--- + usr/iface.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/usr/iface.c b/usr/iface.c +index c86892e..f5441c0 100644 +--- a/usr/iface.c ++++ b/usr/iface.c +@@ -895,6 +895,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + { + struct iscsi_transport *t = NULL; + uint32_t hostno; ++ int rc; + + if (strlen(context->initiatorname)) + strlcpy(iface->iname, context->initiatorname, +@@ -907,10 +908,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + return 0; + } + } else if (strlen(context->iface)) { +-/* this ifdef is only temp until distros and firmwares are updated */ +-#ifdef OFFLOAD_BOOT_SUPPORTED + char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; +- int rc; + + memset(transport_name, 0, ISCSI_TRANSPORT_NAME_MAXLEN); + /* make sure offload driver is loaded */ +@@ -936,9 +934,6 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + } + + strlcpy(iface->netdev, context->iface, sizeof(iface->netdev)); +-#else +- return 0; +-#endif + } else + return 0; + +-- +1.7.11.7 + diff --git a/0158-iscsiuio-IPC-newroot-command.patch b/0158-iscsiuio-IPC-newroot-command.patch new file mode 100644 index 0000000..fa3f4c7 --- /dev/null +++ b/0158-iscsiuio-IPC-newroot-command.patch @@ -0,0 +1,122 @@ +From 6e979154c9c51dedd54c91e46106e495a65ced43 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 2 Jan 2013 14:45:05 -0800 +Subject: [PATCH 58/58] iscsiuio IPC newroot command + +--- + usr/mgmt_ipc.c | 11 +++++++++++ + usr/transport.c | 1 + + usr/transport.h | 1 + + usr/uip_mgmt_ipc.c | 14 ++++++++++++++ + usr/uip_mgmt_ipc.h | 5 +++++ + 5 files changed, 32 insertions(+) + +diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c +index 5cb7143..a8f8473 100644 +--- a/usr/mgmt_ipc.c ++++ b/usr/mgmt_ipc.c +@@ -36,6 +36,7 @@ + #include "sysdeps.h" + #include "iscsi_ipc.h" + #include "iscsi_err.h" ++#include "iscsi_sysfs.h" + + #define PEERUSER_MAX 64 + #define EXTMSG_MAX (64 * 1024) +@@ -229,8 +230,18 @@ static int + mgmt_ipc_newroot(queue_task_t *qtask) + { + char *newroot = qtask->req.u.newroot.path; ++ struct iscsi_transport *t; ++ + if (chdir(newroot) || chroot(".") || chdir("/")) + return ISCSI_ERR; ++ ++ /* if a registered transport has a separate userspace process, ++ * notify it of the root change as well */ ++ list_for_each_entry(t, &transports, list) { ++ if (t->template->newroot) ++ t->template->newroot(t, newroot); ++ } ++ + mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS); + return ISCSI_SUCCESS; + } +diff --git a/usr/transport.c b/usr/transport.c +index 4d030a8..e0488ad 100644 +--- a/usr/transport.c ++++ b/usr/transport.c +@@ -83,6 +83,7 @@ struct iscsi_transport_template bnx2i = { + .ep_poll = ktransport_ep_poll, + .ep_disconnect = ktransport_ep_disconnect, + .set_net_config = uip_broadcast_params, ++ .newroot = uip_broadcast_newroot, + }; + + struct iscsi_transport_template be2iscsi = { +diff --git a/usr/transport.h b/usr/transport.h +index 388e4b1..d4d9ec7 100644 +--- a/usr/transport.h ++++ b/usr/transport.h +@@ -39,6 +39,7 @@ struct iscsi_transport_template { + int (*set_net_config) (struct iscsi_transport *t, + struct iface_rec *iface, + struct iscsi_session *session); ++ void (*newroot) (struct iscsi_transport *t, char *path); + }; + + /* represents data path provider */ +diff --git a/usr/uip_mgmt_ipc.c b/usr/uip_mgmt_ipc.c +index f3074ee..d5d496a 100644 +--- a/usr/uip_mgmt_ipc.c ++++ b/usr/uip_mgmt_ipc.c +@@ -39,3 +39,17 @@ int uip_broadcast_params(struct iscsi_transport *t, + sizeof(iscsid_uip_broadcast_header_t) + + sizeof(*iface)); + } ++ ++int uip_broadcast_newroot(struct iscsi_transport *t, char *newroot) ++{ ++ struct iscsid_uip_broadcast broadcast; ++ ++ memset(&broadcast, 0, sizeof(broadcast)); ++ ++ broadcast.header.command = ISCSID_UIP_NEWROOT; ++ strncpy(broadcast.u.newroot.path, newroot, PATH_MAX); ++ ++ return uip_broadcast(&broadcast, ++ sizeof(iscsid_uip_broadcast_header_t) + ++ PATH_MAX + 1); ++} +diff --git a/usr/uip_mgmt_ipc.h b/usr/uip_mgmt_ipc.h +index 29a4769..3ca4fb1 100644 +--- a/usr/uip_mgmt_ipc.h ++++ b/usr/uip_mgmt_ipc.h +@@ -29,6 +29,7 @@ + typedef enum iscsid_uip_cmd { + ISCSID_UIP_IPC_UNKNOWN = 0, + ISCSID_UIP_IPC_GET_IFACE = 1, ++ ISCSID_UIP_NEWROOT = 2, + + __ISCSID_UIP_IPC_MAX_COMMAND + } iscsid_uip_cmd_e; +@@ -47,6 +48,9 @@ typedef struct iscsid_uip_broadcast { + struct ipc_broadcast_iface_rec { + struct iface_rec rec; + } iface_rec; ++ struct ipc_broadcast_newroot { ++ char path[PATH_MAX + 1]; ++ } newroot; + } u; + } iscsid_uip_broadcast_t; + +@@ -69,5 +73,6 @@ extern int uip_broadcast_params(struct iscsi_transport *t, + struct iface_rec *iface, + struct iscsi_session *session); + ++extern int uip_broadcast_newroot(struct iscsi_transport *t, char *path); + + #endif /* UIP_MGMT_IPC_H */ +-- +1.8.1.4 + diff --git a/0159-iscsiuio-systemd-unit-files.patch b/0159-iscsiuio-systemd-unit-files.patch new file mode 100644 index 0000000..2d0e213 --- /dev/null +++ b/0159-iscsiuio-systemd-unit-files.patch @@ -0,0 +1,53 @@ +From 822b53e6c9ebb0fe7236ebd3b4c73b009100592d Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 22 Jan 2013 14:27:12 -0800 +Subject: iscsiuio systemd unit files + +--- + etc/systemd/iscsiuio.service | 17 +++++++++++++++++ + etc/systemd/iscsiuio.socket | 9 +++++++++ + 2 files changed, 26 insertions(+) + create mode 100644 etc/systemd/iscsiuio.service + create mode 100644 etc/systemd/iscsiuio.socket + +diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service +new file mode 100644 +index 0000000..f0410b7 +--- /dev/null ++++ b/etc/systemd/iscsiuio.service +@@ -0,0 +1,17 @@ ++[Unit] ++Description=iSCSI UserSpace I/O driver ++Documentation=man:iscsiuio(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++Requires=iscsid.service ++BindTo=iscsid.service ++After=network.target ++Before=remote-fs-pre.target iscsid.service ++ ++[Service] ++Type=forking ++PIDFile=/var/run/iscsiuio.pid ++ExecStart=/usr/sbin/iscsiuio ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/etc/systemd/iscsiuio.socket b/etc/systemd/iscsiuio.socket +new file mode 100644 +index 0000000..d42cedc +--- /dev/null ++++ b/etc/systemd/iscsiuio.socket +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Open-iSCSI iscsiuio Socket ++Documentation=man:iscsiuio(8) ++ ++[Socket] ++ListenStream=@ISCSID_UIP_ABSTRACT_NAMESPACE ++ ++[Install] ++WantedBy=sockets.target +-- +1.7.11.7 + diff --git a/0160-use-systemctl-to-start-iscsid.patch b/0160-use-systemctl-to-start-iscsid.patch new file mode 100644 index 0000000..81aa2a3 --- /dev/null +++ b/0160-use-systemctl-to-start-iscsid.patch @@ -0,0 +1,25 @@ +From c3d2b8f3de5b6161845304cf46982d2c5a9918b6 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Thu Feb 21 21:05:39 PST 2013 +Subject: disable iscsid.startup from iscsiadm, prefer systemd socket activation + +--- + etc/iscsid.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index ac1d231..5851fa5 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -17,7 +17,7 @@ + # maintainers. + # + # Default for Fedora and RHEL. (uncomment to activate). +-iscsid.startup = /etc/rc.d/init.d/iscsid force-start ++#iscsid.startup = /bin/systemctl start iscsid.service + # + # Default for upstream open-iscsi scripts (uncomment to activate). + # iscsid.startup = /sbin/iscsid +-- +1.7.11.7 + diff --git a/0161-resolve-565245-multilib-issues-caused-by-doxygen.patch b/0161-resolve-565245-multilib-issues-caused-by-doxygen.patch new file mode 100644 index 0000000..1f64d9c --- /dev/null +++ b/0161-resolve-565245-multilib-issues-caused-by-doxygen.patch @@ -0,0 +1,39 @@ +From bc4cf1487b4d6039de2a082c1786ac83ab148c88 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 22 Jan 2013 15:14:21 -0800 +Subject: resolve 565245: multilib issues caused by doxygen + +--- + libiscsi/libiscsi.doxy | 2 +- + libiscsi/no_date_footer.html | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + create mode 100644 libiscsi/no_date_footer.html + +diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy +index 663770f..7a5ff7f 100644 +--- a/libiscsi/libiscsi.doxy ++++ b/libiscsi/libiscsi.doxy +@@ -765,7 +765,7 @@ HTML_HEADER = + # each generated HTML page. If it is left blank doxygen will generate a + # standard footer. + +-HTML_FOOTER = ++HTML_FOOTER = no_date_footer.html + + # The HTML_STYLESHEET tag can be used to specify a user-defined cascading + # style sheet that is used by each HTML page. It can be used to +diff --git a/libiscsi/no_date_footer.html b/libiscsi/no_date_footer.html +new file mode 100644 +index 0000000..1e0c6c4 +--- /dev/null ++++ b/libiscsi/no_date_footer.html +@@ -0,0 +1,6 @@ ++
++Generated for $projectname by doxygen ++$doxygenversion
++ ++ +-- +1.7.11.7 + diff --git a/0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch b/0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch new file mode 100644 index 0000000..684463f --- /dev/null +++ b/0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch @@ -0,0 +1,30 @@ +From ab79bdb20e37216ca969e06d63a952acfd023963 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 28 May 2013 13:12:27 -0700 +Subject: [PATCH] Don't check for autostart sessions if iscsi is not used (bug + #951951) + +Change conditional startup in iscsi.service to check for a non-empty +nodes directory, instead of initiator-name. This fits better with what +it's doing, as there's no need to scan for autostart node records if +there are no node records at all. +--- + etc/systemd/iscsi.service | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index bbd52fd..7b4efee 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,7 +5,7 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target +-ConditionPathExists=/etc/iscsi/initiatorname.iscsi ++ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes + + [Service] + Type=oneshot +-- +1.8.1.4 + diff --git a/0163-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch b/0163-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch new file mode 100644 index 0000000..cedb4e0 --- /dev/null +++ b/0163-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch @@ -0,0 +1,68 @@ +From 3cac85a3f97d0a22270166f428209f873b58c319 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 11 Jun 2013 11:25:27 -0700 +Subject: [PATCH] iscsid: fix order of setting uid/gid and drop supplementary + groups + +If using the user and group ID settings together the existing order of +calling setuid first will almost always cause the setgid call to fail, +assuming the new effective user id does not have the CAP_SETGID +capability. The effective group ID needs to change first. + +While we're at it, if iscsid is started as root it should drop any +inherited supplementary group permissions. + +And if anyone is actually using this to try and isolate capabilities, +they probably care enough to want to known that it is failing. Make +iscsid startup fail instead of just calling perror. + +Signed-off-by: Chris Leech +--- + usr/iscsid.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/usr/iscsid.c b/usr/iscsid.c +index b4bb65b..c0ea6fa 100644 +--- a/usr/iscsid.c ++++ b/usr/iscsid.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -477,11 +478,25 @@ int main(int argc, char *argv[]) + } + } + +- if (uid && setuid(uid) < 0) +- perror("setuid\n"); ++ if (gid && setgid(gid) < 0) { ++ log_error("Unable to setgid to %d\n", gid); ++ log_close(log_pid); ++ exit(ISCSI_ERR); ++ } + +- if (gid && setgid(gid) < 0) +- perror("setgid\n"); ++ if ((geteuid() == 0) && (getgroups(0, NULL))) { ++ if (setgroups(0, NULL) != 0) { ++ log_error("Unable to drop supplementary group ids\n"); ++ log_close(log_pid); ++ exit(ISCSI_ERR); ++ } ++ } ++ ++ if (uid && setuid(uid) < 0) { ++ log_error("Unable to setuid to %d\n", uid); ++ log_close(log_pid); ++ exit(ISCSI_ERR); ++ } + + memset(&daemon_config, 0, sizeof (daemon_config)); + daemon_config.pid_file = pid_file; +-- +1.8.1.4 + diff --git a/0164-libiscsi-fix-incorrect-strncpy-use.patch b/0164-libiscsi-fix-incorrect-strncpy-use.patch new file mode 100644 index 0000000..55d1166 --- /dev/null +++ b/0164-libiscsi-fix-incorrect-strncpy-use.patch @@ -0,0 +1,52 @@ +From fcad7de1a8c3d140d1d0eb120727966017d3727b Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Sat, 17 Aug 2013 15:50:45 -0700 +Subject: libiscsi: fix incorrect strncpy use + +Changes to internal structures make the src and dst buffers of some +copies (potentially) different sizes. Fix strncpy calls that were using +the size of the src argument as the limit. +--- + libiscsi/libiscsi.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index 6e6846a..064e4b5 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -587,15 +587,13 @@ int libiscsi_get_firmware_network_config( + return ENODEV; + + config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0; +- strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface); +- strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac); +- strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr); +- strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask); +- strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway); +- strncpy(config->primary_dns, fw_entry.primary_dns, +- sizeof fw_entry.primary_dns); +- strncpy(config->secondary_dns, fw_entry.secondary_dns, +- sizeof fw_entry.secondary_dns); ++ strlcpy(config->iface_name, fw_entry.iface, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->mac_address, fw_entry.mac, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->ip_address, fw_entry.ipaddr, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->netmask, fw_entry.mask, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->gateway, fw_entry.gateway, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->primary_dns, fw_entry.primary_dns, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->secondary_dns, fw_entry.secondary_dns, LIBISCSI_VALUE_MAXLEN); + return 0; + } + +@@ -613,8 +611,7 @@ int libiscsi_get_firmware_initiator_name(char *initiatorname) + if (fw_get_entry(&fw_entry)) + return ENODEV; + +- strncpy(initiatorname, fw_entry.initiatorname, +- sizeof fw_entry.initiatorname); ++ strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN); + + return 0; + } +-- +1.8.1.4 + diff --git a/0165-fix-hardened-build-of-iscsiuio.patch b/0165-fix-hardened-build-of-iscsiuio.patch new file mode 100644 index 0000000..9a5c8f6 --- /dev/null +++ b/0165-fix-hardened-build-of-iscsiuio.patch @@ -0,0 +1,62 @@ +From 436ac9074def43ae09d7ecc28eec6cdc77a9d0e2 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Fri, 13 Sep 2013 16:56:51 -0700 +Subject: [PATCH 65/65] fix hardened build of iscsiuio + +The new iscsiuio code sets CFLAGS in configure.ac, wiping out the +environment setup by rpm. Patch that out. + +Also fix local build when iscsi-initiator-utils is installed, but having +the check to prevent overwriting configuration files during install look +in DESTDIR. +--- + Makefile | 2 +- + iscsiuio/configure | 2 +- + iscsiuio/configure.ac | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + mode change 100644 => 100755 iscsiuio/configure + +diff --git a/Makefile b/Makefile +index 02346bf..172d30e 100644 +--- a/Makefile ++++ b/Makefile +@@ -123,7 +123,7 @@ install_iface: $(IFACEFILES) + $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi/ifaces + + install_etc: $(ETCFILES) +- if [ ! -f /etc/iscsi/iscsid.conf ]; then \ ++ if [ ! -f $(DESTDIR)$(etcdir)/iscsi/iscsid.conf ]; then \ + $(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi ; \ + $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi ; \ + fi +diff --git a/iscsiuio/configure b/iscsiuio/configure +old mode 100644 +new mode 100755 +index 2740598..cd13f92 +--- a/iscsiuio/configure ++++ b/iscsiuio/configure +@@ -21288,7 +21288,7 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + +-CFLAGS="-O2 -Wall" ++CFLAGS="${CFLAGS} -O2 -Wall" + ## check for --enable-debug first before checking CFLAGS before + ## so that we don't mix -O and -g + # Check whether --enable-debug or --disable-debug was given. +diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac +index e9a5e32..d9a6bdb 100644 +--- a/iscsiuio/configure.ac ++++ b/iscsiuio/configure.ac +@@ -52,7 +52,7 @@ AC_LIBTOOL_DLOPEN + # libtool stuff + AC_PROG_LIBTOOL + +-CFLAGS="-O2 -Wall" ++CFLAGS="${CFLAGS} -O2 -Wall" + ## check for --enable-debug first before checking CFLAGS before + ## so that we don't mix -O and -g + AC_ARG_ENABLE(debug, +-- +1.8.1.4 + diff --git a/0166-start-socket-listeners-on-iscsiadm-command.patch b/0166-start-socket-listeners-on-iscsiadm-command.patch new file mode 100644 index 0000000..cb363b7 --- /dev/null +++ b/0166-start-socket-listeners-on-iscsiadm-command.patch @@ -0,0 +1,28 @@ +From 89e9c2ff66d069b812fabcd4fefe453bbcea73e4 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 25 Nov 2013 22:28:12 -0800 +Subject: [PATCH] start socket listeners on iscsiadm command + +fix for trying to run iscsiadm commands right after installing the rpm +without manually starting the systemd units +--- + etc/iscsid.conf | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index 1fd3000..412f130 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -17,7 +17,8 @@ + # maintainers. + # + # Default for Fedora and RHEL. (uncomment to activate). +-#iscsid.startup = /bin/systemctl start iscsid.service ++# Use socket activation, but try to make sure the socket units are listening ++iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket + # + # Default for upstream open-iscsi scripts (uncomment to activate). + # iscsid.startup = /sbin/iscsid +-- +1.8.3.1 + diff --git a/0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch b/0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch new file mode 100644 index 0000000..c6398b1 --- /dev/null +++ b/0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch @@ -0,0 +1,25 @@ +From 1483a176fdbb22bbfecf06eea57d1aa200f30561 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 21 Jan 2013 15:43:36 -0800 +Subject: use Red Hat version string to match RPM package version + +--- + usr/version.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/usr/version.h b/usr/version.h +index a090522..aef0c3d 100644 +--- a/usr/version.h ++++ b/usr/version.h +@@ -6,7 +6,7 @@ + * This may not be the same value as the kernel versions because + * some other maintainer could merge a patch without going through us + */ +-#define ISCSI_VERSION_STR "2.0-873" ++#define ISCSI_VERSION_STR "6.2.0.873-14" + #define ISCSI_VERSION_FILE "/sys/module/scsi_transport_iscsi/version" + + #endif +-- +1.7.11.7 + diff --git a/iscsi-initiator-utils.spec b/iscsi-initiator-utils.spec index e3b2fe5..4fa2d59 100644 --- a/iscsi-initiator-utils.spec +++ b/iscsi-initiator-utils.spec @@ -57,29 +57,29 @@ Patch40: 0040-iscsi-tools-Correctly-get-username_in-and-password_i.patch Patch41: 0041-README-changes-for-adding-support-to-set-CHAP-entry.patch # not (yet) upstream merged -Patch43: 0043-idmb_rec_write-check-for-tpgt-first.patch -Patch45: 0045-idbm_rec_write-seperate-old-and-new-style-writes.patch -Patch46: 0046-idbw_rec_write-pick-tpgt-from-existing-record.patch -Patch47: 0047-iscsiuio-systemd-socket-activation-support.patch -Patch49: 0049-update-systemd-service-files-add-iscsi.service-for-s.patch -Patch50: 0050-iscsi-boot-related-service-file-updates.patch +Patch143: 0143-idmb_rec_write-check-for-tpgt-first.patch +Patch145: 0145-idbm_rec_write-seperate-old-and-new-style-writes.patch +Patch146: 0146-idbw_rec_write-pick-tpgt-from-existing-record.patch +Patch147: 0147-iscsiuio-systemd-socket-activation-support.patch +Patch149: 0149-update-systemd-service-files-add-iscsi.service-for-s.patch +Patch150: 0150-iscsi-boot-related-service-file-updates.patch # distro specific modifications -Patch51: 0051-update-initscripts-and-docs.patch -Patch52: 0052-use-var-for-config.patch -Patch53: 0053-use-red-hat-for-name.patch -Patch54: 0054-add-libiscsi.patch -Patch55: 0055-dont-use-static.patch -Patch56: 0056-remove-the-offload-boot-supported-ifdef.patch -Patch59: 0059-iscsiuio-systemd-unit-files.patch -Patch60: 0060-use-systemctl-to-start-iscsid.patch -Patch61: 0061-resolve-565245-multilib-issues-caused-by-doxygen.patch -Patch62: 0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch -Patch63: 0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch -Patch64: 0064-libiscsi-fix-incorrect-strncpy-use.patch -Patch65: 0065-fix-hardened-build-of-iscsiuio.patch -Patch66: 0066-start-socket-listeners-on-iscsiadm-command.patch +Patch151: 0151-update-initscripts-and-docs.patch +Patch152: 0152-use-var-for-config.patch +Patch153: 0153-use-red-hat-for-name.patch +Patch154: 0154-add-libiscsi.patch +Patch155: 0155-dont-use-static.patch +Patch156: 0156-remove-the-offload-boot-supported-ifdef.patch +Patch159: 0159-iscsiuio-systemd-unit-files.patch +Patch160: 0160-use-systemctl-to-start-iscsid.patch +Patch161: 0161-resolve-565245-multilib-issues-caused-by-doxygen.patch +Patch162: 0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch +Patch163: 0163-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch +Patch164: 0164-libiscsi-fix-incorrect-strncpy-use.patch +Patch165: 0165-fix-hardened-build-of-iscsiuio.patch +Patch166: 0166-start-socket-listeners-on-iscsiadm-command.patch # version string, needs to be updated with each build -Patch99: 0099-use-Red-Hat-version-string-to-match-RPM-package-vers.patch +Patch199: 0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch BuildRequires: flex bison python-devel doxygen kmod-devel systemd-devel # For dir ownership @@ -150,29 +150,29 @@ developing applications that use %{name}. %patch40 -p1 %patch41 -p1 # pending upstream merge -%patch43 -p1 -%patch45 -p1 -%patch46 -p1 -%patch47 -p1 -%patch49 -p1 -%patch50 -p1 +%patch143 -p1 +%patch145 -p1 +%patch146 -p1 +%patch147 -p1 +%patch149 -p1 +%patch150 -p1 # distro specific modifications -%patch51 -p1 -%patch52 -p1 -%patch53 -p1 -%patch54 -p1 -%patch55 -p1 -%patch56 -p1 -%patch59 -p1 -%patch60 -p1 -%patch61 -p1 -%patch62 -p1 -%patch63 -p1 -%patch64 -p1 -%patch65 -p1 -%patch66 -p1 +%patch151 -p1 +%patch152 -p1 +%patch153 -p1 +%patch154 -p1 +%patch155 -p1 +%patch156 -p1 +%patch159 -p1 +%patch160 -p1 +%patch161 -p1 +%patch162 -p1 +%patch163 -p1 +%patch164 -p1 +%patch165 -p1 +%patch166 -p1 # version string -%patch99 -p1 +%patch199 -p1 # change exec_prefix, there's no easy way to override %{__sed} -i -e 's|^exec_prefix = /$|exec_prefix = %{_exec_prefix}|' Makefile