diff --git a/.gitignore b/.gitignore index e69de29..31fa575 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,11 @@ +/open-iscsi-2.0-873.tar.gz +/iscsiuio-0.7.2.1.tar.gz +/open-iscsi-4c9d6f9.tar.gz +/open-iscsi-4c1f2d9.tar.gz +/open-iscsi-86e8892.tar.gz +/open-iscsi-4ef9261.tar.gz +/open-iscsi-f3c8e90.tar.gz +/open-iscsi-4440e57.tar.gz +/open-iscsi-ac87641.tar.gz +/open-iscsi-802688d.tar.gz +/open-iscsi-13e7f58.tar.gz diff --git a/0001-configuration-support-for-CHAP-algorithms-rebased.patch b/0001-configuration-support-for-CHAP-algorithms-rebased.patch new file mode 100644 index 0000000..329a063 --- /dev/null +++ b/0001-configuration-support-for-CHAP-algorithms-rebased.patch @@ -0,0 +1,658 @@ +From d3daa7a2bc3f5bca874d3efd072b34a657c4d492 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Sun, 24 Nov 2019 13:51:09 -0800 +Subject: [PATCH] configuration support for CHAP algorithms + +Introduces support for preference lists in configuration files, and uses +that for the 'node.session.auth.chap_algs' setting. + +This is also re-used for discovery authentication, rather than have two +different configurations. +--- + etc/iscsid.conf | 7 ++ + libopeniscsiusr/default.c | 3 + + libopeniscsiusr/idbm.c | 95 +++++++++++++++++++++++++ + libopeniscsiusr/idbm.h | 9 +++ + libopeniscsiusr/idbm_fields.h | 1 + + usr/auth.c | 64 ++++++++++++----- + usr/auth.h | 3 + + usr/config.h | 1 + + usr/idbm.c | 126 ++++++++++++++++++++++++++++++---- + usr/idbm.h | 2 + + usr/idbm_fields.h | 1 + + usr/initiator.h | 1 + + usr/initiator_common.c | 2 + + usr/login.c | 11 +++ + 14 files changed, 294 insertions(+), 32 deletions(-) + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index 70985afd..58f60404 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -57,6 +57,13 @@ node.leading_login = No + # to CHAP. The default is None. + #node.session.auth.authmethod = CHAP + ++# To configure which CHAP algorithms to enable set ++# node.session.auth.chap_algs to a comma seperated list. ++# The algorithms should be listen with most prefered first. ++# Valid values are MD5, SHA1, SHA256, and SHA3-256. ++# The default is MD5. ++#node.session.auth.chap_algs = SHA3-256,SHA256,SHA1,MD5 ++ + # To set a CHAP username and password for initiator + # authentication by the target(s), uncomment the following lines: + #node.session.auth.username = username +diff --git a/libopeniscsiusr/default.c b/libopeniscsiusr/default.c +index d01d8928..d3b3da35 100644 +--- a/libopeniscsiusr/default.c ++++ b/libopeniscsiusr/default.c +@@ -78,6 +78,9 @@ void _default_node(struct iscsi_node *node) + node->session.initial_login_retry_max = DEF_INITIAL_LOGIN_RETRIES_MAX; + node->session.reopen_max = DEF_SESSION_REOPEN_MAX; + node->session.auth.authmethod = 0; ++ /* TYPE_INT_LIST fields should be initialized to ~0 to indicate unset values */ ++ memset(node->session.auth.chap_algs, ~0, sizeof(node->session.auth.chap_algs)); ++ node->session.auth.chap_algs[0] = ISCSI_AUTH_CHAP_ALG_MD5; + node->session.auth.password_length = 0; + node->session.auth.password_in_length = 0; + node->session.err_tmo.abort_timeout = DEF_ABORT_TIMEO; +diff --git a/libopeniscsiusr/idbm.c b/libopeniscsiusr/idbm.c +index d020e6ce..05cb7f9f 100644 +--- a/libopeniscsiusr/idbm.c ++++ b/libopeniscsiusr/idbm.c +@@ -73,6 +73,7 @@ + #define TYPE_INT32 6 + #define TYPE_INT64 7 + #define TYPE_BOOL 8 ++#define TYPE_INT_LIST 9 + #define MAX_KEYS 256 /* number of keys total(including CNX_MAX) */ + #define NAME_MAXVAL 128 /* the maximum length of key name */ + #define VALUE_MAXVAL 256 /* the maximum length of 223 bytes in the RFC. */ +@@ -248,6 +249,39 @@ do { \ + _n++; \ + } while(0) + ++#define ARRAY_LEN(x) ( sizeof(x) / sizeof((x)[0]) ) ++ ++/* Options list type, rather than matching a single value this populates an ++ * array with a list of values in user specified order. ++ * Requires a table matching config strings to values. ++ **/ ++#define _rec_int_list(_key, _recs, _org, _name, _show, _tbl, _n, _mod) \ ++do {\ ++ _recs[_n].type = TYPE_INT_LIST; \ ++ _strncpy(_recs[_n].name, _key, NAME_MAXVAL); \ ++ for (unsigned int _i = 0; _i < ARRAY_LEN(_org->_name); _i++) { \ ++ if (_org->_name[_i] != ~0UL) { \ ++ for (unsigned int _j = 0; _j < ARRAY_LEN(_tbl); _j++) { \ ++ if (_tbl[_j].value == _org->_name[_i]) { \ ++ strcat(_recs[_n].value, _tbl[_j].name); \ ++ strcat(_recs[_n].value, ","); \ ++ break; \ ++ } \ ++ } \ ++ } \ ++ } \ ++ /* delete traling ',' */ \ ++ if (strrchr(_recs[_n].value, ',')) \ ++ *strrchr(_recs[_n].value, ',') = '\0'; \ ++ _recs[_n].data = &_org->_name; \ ++ _recs[_n].data_len = sizeof(_org->_name); \ ++ _recs[_n].visible = _show; \ ++ _recs[_n].opts[0] = (void *)&_tbl; \ ++ _recs[_n].numopts = ARRAY_LEN(_tbl); \ ++ _recs[_n].can_modify = _mod; \ ++ _n++; \ ++} while(0) ++ + enum modify_mode { + _CANNOT_MODIFY, + _CAN_MODIFY, +@@ -558,6 +592,11 @@ void _idbm_node_print(struct iscsi_node *node, FILE *f, bool show_secret) + _idbm_recs_free(recs); + } + ++struct int_list_tbl { ++ const char *name; ++ unsigned int value; ++}; ++ + static int _idbm_rec_update_param(struct iscsi_context *ctx, + struct idbm_rec *recs, char *name, + char *value, int line_number) +@@ -565,8 +604,14 @@ static int _idbm_rec_update_param(struct iscsi_context *ctx, + int rc = LIBISCSI_OK; + int i = 0; + int j = 0; ++ int k = 0; + int passwd_done = 0; + char passwd_len[8]; ++ struct int_list_tbl *tbl = NULL; ++ char *tmp_value; ++ int *tmp_data; ++ bool *found; ++ char *token; + + assert(ctx != NULL); + assert(recs != NULL); +@@ -643,6 +688,47 @@ static int _idbm_rec_update_param(struct iscsi_context *ctx, + else + goto unknown_value; + goto updated; ++ case TYPE_INT_LIST: ++ if (!recs[i].data) ++ continue; ++ tbl = (void *)recs[i].opts[0]; ++ /* strsep is destructive, make a copy to work with */ ++ tmp_value = strdup(value); ++ k = 0; ++ tmp_data = malloc(recs[i].data_len); ++ memset(tmp_data, ~0, recs[i].data_len); ++ found = calloc(recs[i].numopts, sizeof(bool)); ++next_token: while ((token = strsep(&tmp_value, ", \n"))) { ++ if (!strlen(token)) ++ continue; ++ if ((k * (int)sizeof(int)) >= (recs[i].data_len)) { ++ _warn(ctx, "Too many values set for '%s'" ++ ", continuing without processing them all", ++ recs[i].name); ++ break; ++ } ++ for (j = 0; j < recs[i].numopts; j++) { ++ if (!strcmp(token, tbl[j].name)) { ++ if ((found[j])) { ++ _warn(ctx, "Ignoring repeated value '%s'" ++ " for '%s'", token, recs[i].name); ++ goto next_token; ++ } ++ ((unsigned *)tmp_data)[k++] = tbl[j].value; ++ found[j] = true; ++ goto next_token; ++ } ++ } ++ _warn(ctx, "Ignoring unknown value '%s'" ++ " for '%s'", token, recs[i].name); ++ } ++ memcpy(recs[i].data, tmp_data, recs[i].data_len); ++ free(tmp_value); ++ free(tmp_data); ++ tmp_value = NULL; ++ tmp_data = NULL; ++ token = NULL; ++ goto updated; + default: + unknown_value: + _error(ctx, "Got unknown data type %d " +@@ -882,6 +968,13 @@ void _idbm_free(struct idbm *db) + free(db); + } + ++static struct int_list_tbl chap_algs[] = { ++ { "MD5", ISCSI_AUTH_CHAP_ALG_MD5 }, ++ { "SHA1", ISCSI_AUTH_CHAP_ALG_SHA1 }, ++ { "SHA256", ISCSI_AUTH_CHAP_ALG_SHA256 }, ++ { "SHA3-256", ISCSI_AUTH_CHAP_ALG_SHA3_256 }, ++}; ++ + static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs) + { + int num = 0; +@@ -944,6 +1037,8 @@ static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs) + _rec_uint32(SESSION_PASSWORD_IN_LEN, recs, node, + session.auth.password_in_length, IDBM_HIDE, num, + _CAN_MODIFY); ++ _rec_int_list(SESSION_CHAP_ALGS, recs, node, session.auth.chap_algs, ++ IDBM_SHOW, chap_algs, num, _CAN_MODIFY); + _rec_int64(SESSION_REPLACEMENT_TMO, recs, node, + session.tmo.replacement_timeout, IDBM_SHOW, num, + _CAN_MODIFY); +diff --git a/libopeniscsiusr/idbm.h b/libopeniscsiusr/idbm.h +index 3fd0864a..cc90388b 100644 +--- a/libopeniscsiusr/idbm.h ++++ b/libopeniscsiusr/idbm.h +@@ -48,6 +48,14 @@ enum iscsi_auth_method { + ISCSI_AUTH_METHOD_CHAP, + }; + ++enum iscsi_chap_algs { ++ ISCSI_AUTH_CHAP_ALG_MD5 = 5, ++ ISCSI_AUTH_CHAP_ALG_SHA1 = 6, ++ ISCSI_AUTH_CHAP_ALG_SHA256 = 7, ++ ISCSI_AUTH_CHAP_ALG_SHA3_256 = 8, ++ AUTH_CHAP_ALG_MAX_COUNT = 5, ++}; ++ + enum iscsi_startup_type { + ISCSI_STARTUP_MANUAL, + ISCSI_STARTUP_AUTOMATIC, +@@ -92,6 +100,7 @@ struct iscsi_auth_config { + char username_in[AUTH_STR_MAX_LEN]; + unsigned char password_in[AUTH_STR_MAX_LEN]; + uint32_t password_in_length; ++ unsigned int chap_algs[AUTH_CHAP_ALG_MAX_COUNT]; + }; + + /* all TCP options go in this structure. +diff --git a/libopeniscsiusr/idbm_fields.h b/libopeniscsiusr/idbm_fields.h +index 29a2090c..8bf17b02 100644 +--- a/libopeniscsiusr/idbm_fields.h ++++ b/libopeniscsiusr/idbm_fields.h +@@ -120,6 +120,7 @@ + #define SESSION_USERNAME_IN "node.session.auth.username_in" + #define SESSION_PASSWORD_IN "node.session.auth.password_in" + #define SESSION_PASSWORD_IN_LEN "node.session.auth.password_in_length" ++#define SESSION_CHAP_ALGS "node.session.auth.chap_algs" + #define SESSION_REPLACEMENT_TMO "node.session.timeo.replacement_timeout" + #define SESSION_ABORT_TMO "node.session.err_timeo.abort_timeout" + #define SESSION_LU_RESET_TMO "node.session.err_timeo.lu_reset_timeout" +diff --git a/usr/auth.c b/usr/auth.c +index 5c819c28..a222c531 100644 +--- a/usr/auth.c ++++ b/usr/auth.c +@@ -1806,7 +1806,7 @@ acl_chk_chap_alg_list(unsigned int option_count, const int *option_list) + return 0; + } + +-static int ++int + acl_set_chap_alg_list(struct iscsi_acl *client, unsigned int option_count, + const int *option_list) + { +@@ -1819,22 +1819,54 @@ acl_set_chap_alg_list(struct iscsi_acl *client, unsigned int option_count, + } + + int +-acl_init_chap_digests(int *value_list) { ++acl_init_chap_digests(int *value_list, unsigned *chap_algs, int conf_count) { + EVP_MD_CTX *context = EVP_MD_CTX_new(); + int i = 0; + +- if (EVP_DigestInit_ex(context, EVP_sha3_256(), NULL)) { +- value_list[i++] = AUTH_CHAP_ALG_SHA3_256; +- } +- if (EVP_DigestInit_ex(context, EVP_sha256(), NULL)) { +- value_list[i++] = AUTH_CHAP_ALG_SHA256; +- } +- if (EVP_DigestInit_ex(context, EVP_sha1(), NULL)) { +- value_list[i++] = AUTH_CHAP_ALG_SHA1; +- } +- if (EVP_DigestInit_ex(context, EVP_md5(), NULL)) { +- value_list[i++] = AUTH_CHAP_ALG_MD5; ++ for (int j = 0; j < conf_count; j++) { ++ switch (chap_algs[j]) { ++ case AUTH_CHAP_ALG_MD5: ++ if (EVP_DigestInit_ex(context, EVP_md5(), NULL)) { ++ value_list[i++] = AUTH_CHAP_ALG_MD5; ++ } else { ++ log_warning("Ignoring CHAP algorthm request for " ++ "MD5 due to crypto lib configuration"); ++ } ++ break; ++ case AUTH_CHAP_ALG_SHA1: ++ if (EVP_DigestInit_ex(context, EVP_sha1(), NULL)) { ++ value_list[i++] = AUTH_CHAP_ALG_SHA1; ++ } else { ++ log_warning("Ignoring CHAP algorthm request for " ++ "SHA1 due to crypto lib configuration"); ++ } ++ break; ++ case AUTH_CHAP_ALG_SHA256: ++ if (EVP_DigestInit_ex(context, EVP_sha256(), NULL)) { ++ value_list[i++] = AUTH_CHAP_ALG_SHA256; ++ } else { ++ log_warning("Ignoring CHAP algorthm request for " ++ "SHA256 due to crypto lib configuration"); ++ } ++ break; ++ case AUTH_CHAP_ALG_SHA3_256: ++ if (EVP_DigestInit_ex(context, EVP_sha3_256(), NULL)) { ++ value_list[i++] = AUTH_CHAP_ALG_SHA3_256; ++ } else { ++ log_warning("Ignoring CHAP algorthm request for " ++ "SHA3-256 due to crypto lib configuration"); ++ } ++ break; ++ case ~0: ++ /* unset value in array, just ignore */ ++ break; ++ default: ++ log_warning("Ignoring unknown CHAP algorithm request " ++ "'%d'", chap_algs[j]); ++ break; ++ } + } ++ + return i; + } + +@@ -1926,12 +1958,6 @@ acl_init(int node_type, int buf_desc_count, struct auth_buffer_desc *buff_desc) + return AUTH_STATUS_ERROR; + } + +- if (acl_set_chap_alg_list(client, acl_init_chap_digests(value_list), +- value_list) != AUTH_STATUS_NO_ERROR) { +- client->phase = AUTH_PHASE_ERROR; +- return AUTH_STATUS_ERROR; +- } +- + return AUTH_STATUS_NO_ERROR; + } + +diff --git a/usr/auth.h b/usr/auth.h +index f6dbbe4b..16cdb242 100644 +--- a/usr/auth.h ++++ b/usr/auth.h +@@ -271,6 +271,9 @@ extern int acl_send_transit_bit(struct iscsi_acl *client, int *value); + extern int acl_set_user_name(struct iscsi_acl *client, const char *username); + extern int acl_set_passwd(struct iscsi_acl *client, + const unsigned char *pw_data, unsigned int pw_len); ++extern int acl_set_chap_alg_list(struct iscsi_acl *client, unsigned int option_count, ++ const int *option_list); ++extern int acl_init_chap_digests(int *value_list, unsigned int *chap_algs, int count); + extern int acl_set_auth_rmt(struct iscsi_acl *client, int auth_rmt); + extern int acl_set_ip_sec(struct iscsi_acl *client, int ip_sec); + extern int acl_get_dbg_status(struct iscsi_acl *client, int *value); +diff --git a/usr/config.h b/usr/config.h +index 250879db..79059ec3 100644 +--- a/usr/config.h ++++ b/usr/config.h +@@ -58,6 +58,7 @@ struct iscsi_auth_config { + char username_in[AUTH_STR_MAX_LEN]; + unsigned char password_in[AUTH_STR_MAX_LEN]; + unsigned int password_in_length; ++ unsigned int chap_algs[AUTH_CHAP_ALG_MAX_COUNT]; + }; + + /* all per-connection timeouts go in this structure. +diff --git a/usr/idbm.c b/usr/idbm.c +index be4d4e36..e08301c6 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -50,6 +50,8 @@ + + static struct idbm *db; + ++#define ARRAY_LEN(x) ( sizeof(x) / sizeof((x)[0]) ) ++ + #define __recinfo_str(_key, _info, _rec, _name, _show, _n, _mod) do { \ + _info[_n].type = TYPE_STR; \ + strlcpy(_info[_n].name, _key, NAME_MAXVAL); \ +@@ -164,6 +166,42 @@ static struct idbm *db; + _n++; \ + } while(0) + ++#define __recinfo_int_list(_key,_info,_rec,_name,_show,_tbl,_n,_mod) do { \ ++ _info[_n].type = TYPE_INT_LIST; \ ++ strlcpy(_info[_n].name, _key, NAME_MAXVAL); \ ++ for(int _i = 0; _i < ARRAY_LEN(_rec->_name); _i++) { \ ++ if (_rec->_name[_i] != ~0) { \ ++ for (int _j = 0; _j < ARRAY_LEN(_tbl); _j++) { \ ++ if (_tbl[_j].value == _rec->_name[_i]) { \ ++ strcat(_info[_n].value, _tbl[_j].name); \ ++ strcat(_info[_n].value, ","); \ ++ break; \ ++ } \ ++ } \ ++ } \ ++ } \ ++ /* delete trailing ',' */ \ ++ if (strrchr(_info[_n].value, ',')) \ ++ *strrchr(_info[_n].value, ',') = '\0'; \ ++ _info[_n].data = &_rec->_name; \ ++ _info[_n].data_len = sizeof(_rec->_name); \ ++ _info[_n].visible = _show; \ ++ _info[_n].opts[0] = (void *)&_tbl; \ ++ _info[_n].numopts = ARRAY_LEN(_tbl); \ ++ _info[_n].can_modify = _mod; \ ++ _n++; \ ++} while (0) ++ ++static struct int_list_tbl { ++ const char *name; ++ int value; ++} chap_algs [] = { ++ { "MD5", AUTH_CHAP_ALG_MD5 }, ++ { "SHA1", AUTH_CHAP_ALG_SHA1 }, ++ { "SHA256", AUTH_CHAP_ALG_SHA256 }, ++ { "SHA3-256", AUTH_CHAP_ALG_SHA3_256 }, ++}; ++ + static int idbm_remove_disc_to_node_link(node_rec_t *rec, char *portal); + + static void +@@ -196,6 +234,10 @@ idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) + __recinfo_int(DISC_ST_PASSWORD_IN_LEN, ri, r, + u.sendtargets.auth.password_in_length, IDBM_HIDE, + num, 1); ++ /* reusing SESSION_CHAP_ALGS */ ++ __recinfo_int_list(SESSION_CHAP_ALGS, ri, r, ++ u.sendtargets.auth.chap_algs, ++ IDBM_SHOW, chap_algs, num, 1); + __recinfo_int(DISC_ST_LOGIN_TMO, ri, r, + u.sendtargets.conn_timeo.login_timeout, + IDBM_SHOW, num, 1); +@@ -428,6 +470,8 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + session.auth.password_in, IDBM_MASKED, num, 1); + __recinfo_int(SESSION_PASSWORD_IN_LEN, ri, r, + session.auth.password_in_length, IDBM_HIDE, num, 1); ++ __recinfo_int_list(SESSION_CHAP_ALGS, ri, r, ++ session.auth.chap_algs, IDBM_SHOW, chap_algs, num, 1); + __recinfo_int(SESSION_REPLACEMENT_TMO, ri, r, + session.timeo.replacement_timeout, + IDBM_SHOW, num, 1); +@@ -933,6 +977,9 @@ idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type) + rec->u.sendtargets.auth.authmethod = 0; + rec->u.sendtargets.auth.password_length = 0; + rec->u.sendtargets.auth.password_in_length = 0; ++ /* TYPE_INT_LIST fields should be initialized to ~0 to indicate unset values */ ++ memset(rec->u.sendtargets.auth.chap_algs, ~0, sizeof(rec->u.sendtargets.auth.chap_algs)); ++ rec->u.sendtargets.auth.chap_algs[0] = AUTH_CHAP_ALG_MD5; + rec->u.sendtargets.conn_timeo.login_timeout=15; + rec->u.sendtargets.conn_timeo.auth_timeout = 45; + rec->u.sendtargets.conn_timeo.active_timeout=30; +@@ -966,59 +1013,109 @@ int idbm_rec_update_param(recinfo_t *info, char *name, char *value, + int i; + int passwd_done = 0; + char passwd_len[8]; ++ char *tmp_value, *token; ++ bool *found; ++ int *tmp_data; + + setup_passwd_len: + for (i=0; i '%s'", name, + info[i].value, value); + /* parse recinfo by type */ +- if (info[i].type == TYPE_INT) { ++ switch (info[i].type) { ++ case TYPE_INT: + if (!info[i].data) + continue; + + *(int*)info[i].data = + strtoul(value, NULL, 10); + goto updated; +- } else if (info[i].type == TYPE_UINT8) { ++ case TYPE_UINT8: + if (!info[i].data) + continue; + + *(uint8_t *)info[i].data = + strtoul(value, NULL, 10); + goto updated; +- } else if (info[i].type == TYPE_UINT16) { ++ case TYPE_UINT16: + if (!info[i].data) + continue; + + *(uint16_t *)info[i].data = + strtoul(value, NULL, 10); + goto updated; +- } else if (info[i].type == TYPE_UINT32) { ++ case TYPE_UINT32: + if (!info[i].data) + continue; + + *(uint32_t *)info[i].data = + strtoul(value, NULL, 10); + goto updated; +- } else if (info[i].type == TYPE_STR) { ++ case TYPE_STR: + if (!info[i].data) + continue; + + strlcpy((char*)info[i].data, + value, info[i].data_len); + goto updated; +- } +- for (j=0; j= (info[i].data_len)) { ++ log_warning("Too many values set for '%s'" ++ ", continuing without processing them all", ++ info[i].name); ++ break; ++ } ++ for (j = 0; j < info[i].numopts; j++) { ++ if (!strcmp(token, tbl[j].name)) { ++ if ((found[j])) { ++ log_warning("Ignoring repeated " ++ "value '%s' " ++ "for '%s'", token, ++ info[i].name); ++ goto next_token; ++ } ++ ((int*)tmp_data)[k++] = tbl[j].value; ++ found[j] = true; ++ goto next_token; ++ } ++ } ++ log_warning("Ignoring unknown value '%s'" ++ " for '%s'", token, info[i].name); + } ++ memcpy(info[i].data, tmp_data, info[i].data_len); ++ free(tmp_value); ++ free(tmp_data); ++ tmp_value = NULL; ++ tmp_data = NULL; ++ token = NULL; ++ goto updated; + } + if (line_number) { + log_warning("config file line %d contains " +@@ -3021,6 +3118,9 @@ void idbm_node_setup_defaults(node_rec_t *rec) + rec->session.initial_login_retry_max = DEF_INITIAL_LOGIN_RETRIES_MAX; + rec->session.reopen_max = DEF_SESSION_REOPEN_MAX; + rec->session.auth.authmethod = 0; ++ /* TYPE_INT_LIST fields should be initialized to ~0 to indicate unset values */ ++ memset(rec->session.auth.chap_algs, ~0, sizeof(rec->session.auth.chap_algs)); ++ rec->session.auth.chap_algs[0] = AUTH_CHAP_ALG_MD5; + rec->session.auth.password_length = 0; + rec->session.auth.password_in_length = 0; + rec->session.err_timeo.abort_timeout = DEF_ABORT_TIMEO; +diff --git a/usr/idbm.h b/usr/idbm.h +index 18c50255..46cd82ac 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -45,6 +45,8 @@ + #define TYPE_UINT8 3 + #define TYPE_UINT16 4 + #define TYPE_UINT32 5 ++#define TYPE_INT_LIST 6 ++ + #define MAX_KEYS 256 /* number of keys total(including CNX_MAX) */ + #define NAME_MAXVAL 128 /* the maximum length of key name */ + #define VALUE_MAXVAL 256 /* the maximum length of 223 bytes in the RFC. */ +diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h +index 142c7ae6..4a967fc0 100644 +--- a/usr/idbm_fields.h ++++ b/usr/idbm_fields.h +@@ -30,6 +30,7 @@ + #define SESSION_USERNAME_IN "node.session.auth.username_in" + #define SESSION_PASSWORD_IN "node.session.auth.password_in" + #define SESSION_PASSWORD_IN_LEN "node.session.auth.password_in_length" ++#define SESSION_CHAP_ALGS "node.session.auth.chap_algs" + #define SESSION_REPLACEMENT_TMO "node.session.timeo.replacement_timeout" + #define SESSION_ABORT_TMO "node.session.err_timeo.abort_timeout" + #define SESSION_LU_RESET_TMO "node.session.err_timeo.lu_reset_timeout" +diff --git a/usr/initiator.h b/usr/initiator.h +index eccafb90..6a49ea6e 100644 +--- a/usr/initiator.h ++++ b/usr/initiator.h +@@ -243,6 +243,7 @@ typedef struct iscsi_session { + char username_in[AUTH_STR_MAX_LEN]; + uint8_t password_in[AUTH_STR_MAX_LEN]; + int password_in_length; ++ unsigned int chap_algs[AUTH_CHAP_ALG_MAX_COUNT]; + iscsi_conn_t conn[ISCSI_CONN_MAX]; + uint64_t param_mask; + +diff --git a/usr/initiator_common.c b/usr/initiator_common.c +index 790f13de..81da8fdb 100644 +--- a/usr/initiator_common.c ++++ b/usr/initiator_common.c +@@ -94,6 +94,8 @@ int iscsi_setup_authentication(struct iscsi_session *session, + memcpy(session->password_in, auth_cfg->password_in, + session->password_in_length); + ++ memcpy(session->chap_algs, auth_cfg->chap_algs, sizeof(auth_cfg->chap_algs)); ++ + if (session->password_length || session->password_in_length) { + /* setup the auth buffers */ + session->auth_buffers[0].address = &session->auth_client_block; +diff --git a/usr/login.c b/usr/login.c +index d7dad211..1251e61c 100644 +--- a/usr/login.c ++++ b/usr/login.c +@@ -1262,6 +1262,17 @@ check_for_authentication(iscsi_session_t *session, + goto end; + } + ++ int value_list[AUTH_CHAP_ALG_MAX_COUNT]; ++ ++ if (acl_set_chap_alg_list(auth_client, ++ acl_init_chap_digests(value_list, ++ session->chap_algs, ++ AUTH_CHAP_ALG_MAX_COUNT), ++ value_list) != AUTH_STATUS_NO_ERROR) { ++ log_error("Couldn't set CHAP algorithm list"); ++ goto end; ++ } ++ + if (acl_set_ip_sec(auth_client, 1) != AUTH_STATUS_NO_ERROR) { + log_error("Couldn't set IPSec"); + goto end; diff --git a/0001-service-file-tweaks.patch b/0001-service-file-tweaks.patch new file mode 100644 index 0000000..c83faf3 --- /dev/null +++ b/0001-service-file-tweaks.patch @@ -0,0 +1,146 @@ +From 2d84ee02e9ac69928261b38b5876bebb2349bd65 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 4 Jun 2019 13:23:32 -0700 +Subject: [PATCH] service file tweaks + +--- + etc/systemd/iscsi-mark-root-nodes | 30 ++++++++++++++++++++++++++++++ + etc/systemd/iscsi-shutdown.service | 14 ++++++++++++++ + etc/systemd/iscsi.service | 23 +++++++++++++---------- + etc/systemd/iscsid.service | 6 ++++-- + etc/systemd/iscsiuio.service | 2 +- + 5 files changed, 62 insertions(+), 13 deletions(-) + create mode 100755 etc/systemd/iscsi-mark-root-nodes + create mode 100644 etc/systemd/iscsi-shutdown.service + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +new file mode 100755 +index 0000000..c693707 +--- /dev/null ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -0,0 +1,30 @@ ++#!/bin/bash ++ ++ISCSIADM=/usr/sbin/iscsiadm ++start_iscsid=0 ++start_iscsiuio=0 ++ ++while read t num p target flash; do ++ # strip tag number from portal, keep "ip:port" ++ portal=${p%,*} ++ transport=${t%:} ++ ++ $ISCSIADM -m node -p $portal -T $target -o update -n node.startup -v onboot ++ ++ start_iscsid=1 ++ ++ if [ "$transport" = bnx2i ] || [ "$transport" = qedi ]; then ++ start_iscsiuio=1 ++ fi ++done < <( $ISCSIADM -m session ) ++ ++# force iscsid and iscsiuio to start if needed for ++# recovering sessions created in the initrd ++ ++if [ "$start_iscsid" -eq 1 ]; then ++ systemctl --no-block start iscsid.service ++fi ++if [ "$start_iscsiuio" -eq 1 ]; then ++ systemctl --no-block start iscsiuio.service ++fi ++ +diff --git a/etc/systemd/iscsi-shutdown.service b/etc/systemd/iscsi-shutdown.service +new file mode 100644 +index 0000000..69c1c77 +--- /dev/null ++++ b/etc/systemd/iscsi-shutdown.service +@@ -0,0 +1,14 @@ ++[Unit] ++Description=Logout off all iSCSI sessions on shutdown ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++Wants=remote-fs-pre.target ++RefuseManualStop=yes ++ ++[Service] ++Type=oneshot ++RemainAfterExit=true ++ExecStop=-/usr/sbin/iscsiadm -m node --logoutall=all +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index e475888..eadfcec 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -1,18 +1,21 @@ + [Unit] + Description=Login and scanning of iSCSI devices +-Documentation=man:iscsiadm(8) man:iscsid(8) +-Before=remote-fs.target +-After=network.target network-online.target iscsid.service +-Requires=iscsid.service +-ConditionPathExists=/etc/iscsi/initiatorname.iscsi ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++Wants=remote-fs-pre.target iscsi-shutdown.service ++ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes ++ConditionDirectoryNotEmpty=|/sys/class/iscsi_session + + [Service] + Type=oneshot +-ExecStart=/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=/sbin/iscsiadm -m node --logoutall=automatic +-ExecStop=/sbin/iscsiadm -m node --logoutall=manual +-SuccessExitStatus=21 + RemainAfterExit=true ++ExecStart=-/usr/libexec/iscsi-mark-root-nodes ++ExecStart=-/usr/sbin/iscsiadm -m node --loginall=automatic ++ExecReload=-/usr/sbin/iscsiadm -m node --loginall=automatic ++SuccessExitStatus=21 + + [Install] +-WantedBy=remote-fs.target ++WantedBy=sysinit.target +diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service +index 4fef168..8d50cf0 100644 +--- a/etc/systemd/iscsid.service ++++ b/etc/systemd/iscsid.service +@@ -1,14 +1,16 @@ + [Unit] + Description=Open-iSCSI +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) ++Documentation=man:iscsid(8) man:iscsiadm(8) + DefaultDependencies=no ++Conflicts=shutdown.target + After=network.target iscsiuio.service + Before=remote-fs-pre.target + + [Service] + Type=notify + NotifyAccess=main +-ExecStart=/sbin/iscsid -f ++ExecStart=/usr/sbin/iscsid -f ++ExecStop=/usr/sbin/iscsiadm -k 0 2 + KillMode=mixed + Restart=on-failure + +diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service +index e4d9fd0..8620cde 100644 +--- a/etc/systemd/iscsiuio.service ++++ b/etc/systemd/iscsiuio.service +@@ -11,7 +11,7 @@ Before=remote-fs-pre.target iscsid.service + [Service] + Type=notify + NotifyAccess=main +-ExecStart=/sbin/iscsiuio -f ++ExecStart=/usr/sbin/iscsiuio -f + KillMode=mixed + Restart=on-failure + +-- +2.21.0 + diff --git a/0001-stop-using-Werror-for-now.patch b/0001-stop-using-Werror-for-now.patch new file mode 100644 index 0000000..9d8d040 --- /dev/null +++ b/0001-stop-using-Werror-for-now.patch @@ -0,0 +1,56 @@ +From d4758b0d347e4adccf4d39e6bd29ba68c53a92b8 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 3 Mar 2020 10:35:40 -0800 +Subject: [PATCH 1/1] stop using Werror for now + +need to work through these warning that only appear on s390x +Werror seems bad for release, makes packaging a nightmare when new +compilers come around +--- + Makefile | 2 +- + usr/Makefile | 2 +- + usr/initiator.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Makefile b/Makefile +index 7e6b734..0069e75 100644 +--- a/Makefile ++++ b/Makefile +@@ -7,7 +7,7 @@ + DESTDIR ?= + + prefix = /usr +-exec_prefix = / ++exec_prefix = /usr + sbindir = $(exec_prefix)/sbin + bindir = $(exec_prefix)/bin + mandir = $(prefix)/share/man +diff --git a/usr/Makefile b/usr/Makefile +index 885243a..1a743d1 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -35,7 +35,7 @@ endif + PKG_CONFIG = /usr/bin/pkg-config + + CFLAGS ?= -O2 -g +-WARNFLAGS ?= -Wall -Wextra -Werror -Wstrict-prototypes -fno-common ++WARNFLAGS ?= -Wall -Wextra -Wstrict-prototypes -fno-common + CFLAGS += $(WARNFLAGS) -I../include -I. -D_GNU_SOURCE \ + -I$(TOPDIR)/libopeniscsiusr -DISNS_ENABLE + CFLAGS += $(shell $(PKG_CONFIG) --cflags libkmod) +diff --git a/usr/initiator.c b/usr/initiator.c +index a07f9aa..a06760c 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -580,7 +580,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop, + int redirected) + { + iscsi_session_t *session = conn->session; +- uint32_t delay; ++ uint32_t delay = 0; + + log_debug(1, "re-opening session %d (reopen_cnt %d)", session->id, + session->reopen_cnt); +-- +2.21.1 + diff --git a/0001-unit-file-tweaks.patch b/0001-unit-file-tweaks.patch new file mode 100644 index 0000000..828f17d --- /dev/null +++ b/0001-unit-file-tweaks.patch @@ -0,0 +1,158 @@ +From 52806cfdca12164f0757dcecd05c25c6aa4dda43 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 4 Jun 2019 13:23:32 -0700 +Subject: [PATCH] unit file tweaks + +--- + etc/systemd/iscsi-mark-root-nodes | 29 +++++++++++++++++++++++++++++ + etc/systemd/iscsi-onboot.service | 15 +++++++++++++++ + etc/systemd/iscsi-shutdown.service | 14 ++++++++++++++ + etc/systemd/iscsi.service | 10 +++++++--- + etc/systemd/iscsid.service | 4 ++-- + etc/systemd/iscsiuio.service | 2 +- + 6 files changed, 68 insertions(+), 6 deletions(-) + create mode 100755 etc/systemd/iscsi-mark-root-nodes + create mode 100644 etc/systemd/iscsi-onboot.service + create mode 100644 etc/systemd/iscsi-shutdown.service + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +new file mode 100755 +index 0000000..e5a09c6 +--- /dev/null ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -0,0 +1,29 @@ ++#!/bin/bash ++ ++ISCSIADM=/usr/sbin/iscsiadm ++start_iscsid=0 ++start_iscsiuio=0 ++ ++while read t num p target flash; do ++ # strip tag number from portal, keep "ip:port" ++ portal=${p%,*} ++ transport=${t%:} ++ ++ # use session number to find the iface name in use ++ num=${num#[}; num=${num%]} ++ iface=$(iscsiadm -m session -r $num | grep iface.iscsi_ifacename | cut -d= -f2) ++ ++ $ISCSIADM -m node -p $portal -T $target -I $iface -o update -n node.startup -v onboot ++ ++ start_iscsid=1 ++ ++ if [ "$transport" = bnx2i ] || [ "$transport" = qedi ]; then ++ start_iscsiuio=1 ++ fi ++done < <( $ISCSIADM -m session ) ++ ++# force iscsid and iscsiuio to start if needed for ++# recovering sessions created in the initrd ++ ++if [ "$start_iscsid" -eq 1 ]; then ++ systemctl --no-block start iscsid.service +diff --git a/etc/systemd/iscsi-onboot.service b/etc/systemd/iscsi-onboot.service +new file mode 100644 +index 0000000..42ced68 +--- /dev/null ++++ b/etc/systemd/iscsi-onboot.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Special handling of early boot iSCSI sessions ++Documentation=man:iscsiadm(8) man:iscsid(8) ++DefaultDependencies=no ++RefuseManualStart=true ++Before=iscsi.service ++After=systemd-remount-fs.service ++ConditionDirectoryNotEmpty=/sys/class/iscsi_session ++ ++[Service] ++Type=oneshot ++ExecStart=-/usr/libexec/iscsi-mark-root-nodes ++ ++[Install] ++WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi-shutdown.service b/etc/systemd/iscsi-shutdown.service +new file mode 100644 +index 0000000..6848a72 +--- /dev/null ++++ b/etc/systemd/iscsi-shutdown.service +@@ -0,0 +1,14 @@ ++[Unit] ++Description=Logout off all iSCSI sessions on shutdown ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++Wants=remote-fs-pre.target ++RefuseManualStop=yes ++ ++[Service] ++Type=oneshot ++RemainAfterExit=true ++ExecStart=-/usr/bin/true +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index 2f2bf81..51810c9 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -1,16 +1,20 @@ + [Unit] + Description=Login and scanning of iSCSI devices + Documentation=man:iscsiadm(8) man:iscsid(8) ++DefaultDependencies=no ++Conflicts=shutdown.target + Before=remote-fs.target ++After=systemd-remount-fs.service iscsiuio.service + After=network.target network-online.target + After=iscsid.service iscsi-init.service + Requires=iscsid.socket iscsi-init.service ++Wants=remote-fs-pre.target iscsi-shutdown.service ++ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes + + [Service] + Type=oneshot +-ExecStart=/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=/sbin/iscsiadm -m node --logoutall=automatic +-ExecStop=/sbin/iscsiadm -m node --logoutall=manual ++ExecStart=-/usr/sbin/iscsiadm -m node --loginall=automatic ++ExecReload=-/usr/sbin/iscsiadm -m node --loginall=automatic + SuccessExitStatus=21 15 + RemainAfterExit=true + +diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service +index 648ceea..79e63cd 100644 +--- a/etc/systemd/iscsid.service ++++ b/etc/systemd/iscsid.service +@@ -1,6 +1,6 @@ + [Unit] + Description=Open-iSCSI +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) ++Documentation=man:iscsid(8) man:iscsiuio(8) + DefaultDependencies=no + After=network.target iscsiuio.service + Before=remote-fs-pre.target +@@ -9,7 +9,7 @@ Wants=remote-fs-pre.target + [Service] + Type=notify + NotifyAccess=main +-ExecStart=/sbin/iscsid -f ++ExecStart=/usr/sbin/iscsid -f + KillMode=mixed + Restart=on-failure + +diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service +index 923e019..f92b0e7 100644 +--- a/etc/systemd/iscsiuio.service ++++ b/etc/systemd/iscsiuio.service +@@ -12,7 +12,7 @@ Wants=remote-fs-pre.target + [Service] + Type=notify + NotifyAccess=main +-ExecStart=/sbin/iscsiuio -f ++ExecStart=/usr/sbin/iscsiuio -f + KillMode=mixed + Restart=on-failure + +-- +2.26.2 + diff --git a/0002-idmb_rec_write-check-for-tpgt-first.patch b/0002-idmb_rec_write-check-for-tpgt-first.patch new file mode 100644 index 0000000..5b9d247 --- /dev/null +++ b/0002-idmb_rec_write-check-for-tpgt-first.patch @@ -0,0 +1,54 @@ +From 97071360caa6868c21a161047ed471790c405efb Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 10:59:44 -0700 +Subject: [PATCH] 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 be4d4e3..a7da540 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2078,6 +2078,10 @@ static int idbm_rec_write(node_rec_t *rec, bool disable_lock) + 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; +@@ -2086,22 +2090,10 @@ static int idbm_rec_write(node_rec_t *rec, bool disable_lock) + * 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. + */ +-- +2.21.0 + diff --git a/0003-idbm_rec_write-seperate-old-and-new-style-writes.patch b/0003-idbm_rec_write-seperate-old-and-new-style-writes.patch new file mode 100644 index 0000000..25cddd3 --- /dev/null +++ b/0003-idbm_rec_write-seperate-old-and-new-style-writes.patch @@ -0,0 +1,193 @@ +From 4c6e7c0fcc6da66cf81c0714bf907762194eedf2 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 11:34:31 -0700 +Subject: [PATCH] idbm_rec_write, seperate old and new style writes + +Duplicates a small bit of code, but easier to understand and extened. +--- + usr/idbm.c | 129 +++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 86 insertions(+), 43 deletions(-) + +diff --git a/usr/idbm.c b/usr/idbm.c +index a7da540..2f5e309 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2030,12 +2030,7 @@ mkdir_portal: + return f; + } + +-/* +- * When the disable_lock param is true, the idbm_lock/idbm_unlock needs +- * to be holt by the caller, this will avoid overwriting each other in +- * case of updating(read-modify-write) the recs in parallel. +- */ +-static int idbm_rec_write(node_rec_t *rec, bool disable_lock) ++static int idbm_rec_write_new(node_rec_t *rec) + { + struct stat statb; + FILE *f; +@@ -2048,39 +2043,8 @@ static int idbm_rec_write(node_rec_t *rec, bool disable_lock) + 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", 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", 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); +- +- if (!disable_lock) { +- 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) { +@@ -2101,11 +2065,11 @@ static int idbm_rec_write(node_rec_t *rec, bool disable_lock) + log_error("Could not convert %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + } else { + rc = ISCSI_ERR_INVAL; +- goto unlock; ++ goto free_portal; + } + + mkdir_portal: +@@ -2116,24 +2080,103 @@ mkdir_portal: + log_error("Could not make dir %s: %s", + 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: ++ + f = fopen(portal, "w"); + if (!f) { + log_error("Could not open %s: %s", 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"); ++ 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", 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; ++} ++ ++/* ++ * When the disable_lock param is true, the idbm_lock/idbm_unlock needs ++ * to be holt by the caller, this will avoid overwriting each other in ++ * case of updating(read-modify-write) the recs in parallel. ++ */ ++static int idbm_rec_write(node_rec_t *rec, bool disable_lock) ++{ ++ char *portal; ++ int rc = 0; ++ ++ portal = malloc(PATH_MAX); ++ if (!portal) { ++ log_error("Could not alloc portal"); ++ 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", 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", portal, ++ strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ } ++ ++ if (!disable_lock) { ++ 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); ++ + if (!disable_lock) + idbm_unlock(); + free_portal: +-- +2.21.0 + diff --git a/0004-idbw_rec_write-pick-tpgt-from-existing-record.patch b/0004-idbw_rec_write-pick-tpgt-from-existing-record.patch new file mode 100644 index 0000000..41436fb --- /dev/null +++ b/0004-idbw_rec_write-pick-tpgt-from-existing-record.patch @@ -0,0 +1,87 @@ +From 351ee477f713730d1c53cf26b6fb87706d268a5f Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 12:39:07 -0700 +Subject: [PATCH 1/1] 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 | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/usr/idbm.c b/usr/idbm.c +index b6193e7..2208c4a 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -202,6 +203,8 @@ static struct int_list_tbl { + { "SHA3-256", AUTH_CHAP_ALG_SHA3_256 }, + }; + ++static int idbm_remove_disc_to_node_link(node_rec_t *rec, char *portal); ++ + static void + idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) + { +@@ -2206,12 +2209,49 @@ static int idbm_rec_write_old(node_rec_t *rec) + FILE *f; + char *portal; + int rc = 0; ++ glob_t globbuf; ++ size_t i; ++ int tpgt = PORTAL_GROUP_TAG_UNKNOWN; + + portal = malloc(PATH_MAX); + if (!portal) { + log_error("Could not alloc portal"); + 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); ++ rc = 0; ++ ++ /* 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; ++ rc = idbm_remove_disc_to_node_link(rec, portal); ++ 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); + +-- +2.21.1 + diff --git a/0005-update-initscripts-and-docs.patch b/0005-update-initscripts-and-docs.patch new file mode 100644 index 0000000..e749a89 --- /dev/null +++ b/0005-update-initscripts-and-docs.patch @@ -0,0 +1,123 @@ +From 6602f08bfcc2b2e75d1a58671cb160c96cf2d99b Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:37:13 -0800 +Subject: [PATCH] update initscripts and docs + +--- + README | 10 ++++------ + etc/iscsid.conf | 21 ++++++++++----------- + usr/idbm.c | 4 ++++ + 3 files changed, 18 insertions(+), 17 deletions(-) + +diff --git a/README b/README +index 2499d9a..c05814a 100644 +--- a/README ++++ b/README +@@ -77,11 +77,6 @@ the cache sync command will fail. + - iscsiadm's -P 3 option will not print out scsi devices. + - iscsid will not automatically online devices. + +-You need to enable "Cryptographic API" under "Cryptographic options" in the +-kernel config. And you must enable "CRC32c CRC algorithm" even if +-you do not use header or data digests. They are the kernel options +-CONFIG_CRYPTO and CONFIG_CRYPTO_CRC32C, respectively. +- + The userspace components iscsid, iscsiadm and iscsistart require the + open-isns library, which can be found here: + https://github.com/gonzoleeman/open-isns/releases +@@ -1151,7 +1146,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: +@@ -1353,6 +1348,9 @@ iscsid will only perform rediscovery when it gets a SCN from the server. + # linux-isns (SLES's iSNS server) where it sometimes does not send SCN + # events in the proper format, so they may not get handled. + ++To set the startup value, so that nodes are not logged into automatically ++use the value "manual". ++ + Examples + -------- + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index f21ed3d..56c56a9 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -19,7 +19,7 @@ + # the time then leave this attribute commented out. + # + # Default for Fedora and RHEL. (uncomment to activate). +-# iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket ++iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket + # + # Default if you are not using systemd (uncomment to activate) + # iscsid.startup = /usr/bin/service start iscsid +@@ -41,8 +41,8 @@ + # To request that the iscsi initd scripts startup a session set to "automatic". + # node.startup = automatic + # +-# To manually startup the session set to "manual". The default is manual. +-node.startup = manual ++# To manually startup the session set to "manual". The default is automatic. ++node.startup = automatic + + # For "automatic" startup nodes, setting this to "Yes" will try logins on each + # available iface until one succeeds, and then stop. The default "No" will try +@@ -271,25 +271,22 @@ 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: +-#node.conn[0].iscsi.HeaderDigest = None +-#node.conn[0].iscsi.DataDigest = None ++# iSCSI PDUs, uncomment the following line: ++node.conn[0].iscsi.HeaderDigest = None + # + # The default is to never use DataDigests or HeaderDigests. + # +diff --git a/usr/idbm.c b/usr/idbm.c +index a2332cc..aed08f2 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -521,9 +521,13 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + IDBM_SHOW, "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); + sprintf(key, CONN_DATA_DIGEST, i); ++ ++#if 0 ++We do not support data digests + __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW, + "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); ++#endif + sprintf(key, CONN_IFMARKER, i); + __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW, + "No", "Yes", num, 1); +-- +2.21.0 + diff --git a/0006-use-var-for-config.patch b/0006-use-var-for-config.patch new file mode 100644 index 0000000..db63b54 --- /dev/null +++ b/0006-use-var-for-config.patch @@ -0,0 +1,255 @@ +From 9cae86dd15bf78ee9d221f722f723062eb6ad3d8 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:38:45 -0800 +Subject: [PATCH] use var for config + +--- + README | 33 ++++++++++++++++----------------- + doc/iscsiadm.8 | 8 ++++---- + doc/iscsid.8 | 2 +- + usr/idbm.c | 6 +++--- + usr/idbm.h | 13 +++++++------ + usr/iface.h | 3 ++- + 6 files changed, 33 insertions(+), 32 deletions(-) + +diff --git a/README b/README +index c05814a..326c3b0 100644 +--- a/README ++++ b/README +@@ -172,8 +172,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: + +@@ -561,7 +560,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 + ---- +@@ -594,7 +593,7 @@ Running + The command + iscsiadm -m iface + +-will report iface configurations that are setup in /etc/iscsi/ifaces: ++will report iface configurations that are setup in /var/lib/iscsi/ifaces: + + 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 +@@ -604,10 +603,10 @@ The format is: + + For software iscsi, you can create the iface configs by hand, but it is + recommended that you use iscsiadm's iface mode. There is an 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 separate iface config in /etc/iscsi/ifaces and each iface config file ++a separate 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 +@@ -615,12 +614,12 @@ 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 +@@ -662,7 +661,7 @@ port. The iface name will be of the form: + Running the following command: + iscsiadm -m iface + +-will report iface configurations that are setup in /etc/iscsi/ifaces: ++will report iface configurations that are setup in /var/lib/iscsi/ifaces: + + default tcp,,,, + iser iser,,,, +@@ -742,7 +741,7 @@ need a separate 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/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 overridden by passing in the interfaces you want to use. For the case +@@ -757,7 +756,7 @@ If you had defined interfaces but wanted the old behavior, where we do not + bind a session to an iface, then you can use the special iface "default": + 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, allowing the network subsystem to decide which device to use. + +@@ -793,7 +792,7 @@ Discovery mode + ID [192.168.1.1:3260]: + 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 +@@ -802,7 +801,7 @@ Discovery mode + The argument to -p may also be a hostname instead of an address: + iscsiadm -m discoverydb -t st -p somehost --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 +@@ -853,7 +852,7 @@ Discovery mode + + - SendTargets iSCSI Discovery with a specific interface. + If you wish to only use a subset of the interfaces in +- /etc/iscsi/ifaces, then you can pass them in during discovery: ++ /var/lib/iscsi/ifaces, then you can pass them in during discovery: + iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \ + --interface=iface0 --interface=iface1 --discover + +@@ -1223,8 +1222,8 @@ where targetname is the name of the target and ip_address:port is the address + and port of the portal. tpgt is the Target Portal Group Tag of + the portal, and is not used in iscsiadm commands except for static + record creation. ifacename 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 whichever NIC the + network layer decides is best. + +@@ -1336,7 +1335,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 bf23dd2..9cfce16 100644 +--- a/doc/iscsiadm.8 ++++ b/doc/iscsiadm.8 +@@ -228,7 +228,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 +@@ -301,7 +301,7 @@ If no other options are specified: for \fIdiscovery\fR, \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. ++and for \fIiface\fR, all ifaces setup in /var/lib/iscsi/ifaces are displayed. + .TP + \fB\-n\fR, \fB\-\-name=\fIname\fR + In node mode, specify a field \fIname\fR in a record. In flashnode submode +@@ -640,10 +640,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" + .BR iscsid (8) +diff --git a/doc/iscsid.8 b/doc/iscsid.8 +index 6f9218f..0da0551 100644 +--- a/doc/iscsid.8 ++++ b/doc/iscsid.8 +@@ -65,7 +65,7 @@ and + .B iscsiadm + on startup. + .TP +-/etc/iscsi/nodes ++/var/lib/iscsi/nodes + Open-iSCSI persistent configuration database + + .SH "SEE ALSO" +diff --git a/usr/idbm.c b/usr/idbm.c +index aed08f2..15802c3 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2968,9 +2968,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", ISCSI_CONFIG_ROOT, ++ if (access(ISCSIVAR, F_OK) != 0) { ++ if (mkdir(ISCSIVAR, 0660) != 0) { ++ log_error("Could not make %s %d", ISCSIVAR, + errno); + return errno; + } +diff --git a/usr/idbm.h b/usr/idbm.h +index 18c5025..6bdfd60 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -30,12 +30,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 6c06f7f..c8b9de9 100644 +--- a/usr/iface.h ++++ b/usr/iface.h +@@ -21,8 +21,9 @@ + #define ISCSI_IFACE_H + + #include ++#include "idbm.h" + +-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" ++#define IFACE_CONFIG_DIR ISCSIVAR"ifaces" + + struct iface_rec; + struct list_head; +-- +2.21.0 + diff --git a/0007-use-red-hat-for-name.patch b/0007-use-red-hat-for-name.patch new file mode 100644 index 0000000..2719565 --- /dev/null +++ b/0007-use-red-hat-for-name.patch @@ -0,0 +1,39 @@ +From 1ddee25396962a6bd966b98311881ed6d4cba87c Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:40:04 -0800 +Subject: [PATCH] use red hat for name + +--- + doc/iscsi-iname.8 | 2 +- + utils/iscsi-iname.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/doc/iscsi-iname.8 b/doc/iscsi-iname.8 +index 6a413f6..dd77ed9 100644 +--- a/doc/iscsi-iname.8 ++++ b/doc/iscsi-iname.8 +@@ -14,7 +14,7 @@ generates a unique iSCSI node name on every invocation. + Display help + .TP + .BI [-p=]\fIprefix\fP +-Use the prefix passed in instead of the default "iqn.2016-04.com.open-iscsi" ++Use the prefix passed in instead of the default "iqn.1994-05.com.redhat" + + .SH AUTHORS + Open-iSCSI project +diff --git a/utils/iscsi-iname.c b/utils/iscsi-iname.c +index da850dc..29aa4ad 100644 +--- a/utils/iscsi-iname.c ++++ b/utils/iscsi-iname.c +@@ -80,7 +80,7 @@ main(int argc, char *argv[]) + exit(0); + } + } else { +- prefix = "iqn.2016-04.com.open-iscsi"; ++ prefix = "iqn.1994-05.com.redhat"; + } + + /* try to feed some entropy from the pool to MD5 in order to get +-- +2.21.0 + diff --git a/0008-libiscsi.patch b/0008-libiscsi.patch new file mode 100644 index 0000000..9b0aed0 --- /dev/null +++ b/0008-libiscsi.patch @@ -0,0 +1,4014 @@ +From 029ded4ed0de80a15836caed8747fab17958179a Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Mon, 26 Jan 2015 12:57:11 -0800 +Subject: [PATCH 1/1] libiscsi + +--- + Makefile | 2 + + libiscsi/Makefile | 65 + + libiscsi/libiscsi.c | 617 ++++++++ + libiscsi/libiscsi.doxy | 1473 +++++++++++++++++++ + libiscsi/libiscsi.h | 344 +++++ + libiscsi/no_date_footer.html | 6 + + libiscsi/pylibiscsi.c | 709 +++++++++ + libiscsi/setup.py | 9 + + libiscsi/tests/test_discovery_firmware.c | 53 + + libiscsi/tests/test_discovery_sendtargets.c | 60 + + libiscsi/tests/test_get_auth.c | 70 + + libiscsi/tests/test_get_initiator_name.c | 38 + + libiscsi/tests/test_get_network_config.c | 45 + + libiscsi/tests/test_login.c | 52 + + libiscsi/tests/test_logout.c | 51 + + libiscsi/tests/test_params.c | 103 ++ + libiscsi/tests/test_set_auth.c | 58 + + usr/Makefile | 2 +- + usr/discovery.c | 5 + + usr/idbm.c | 6 +- + usr/idbm.h | 3 + + usr/iscsi_ipc.h | 2 + + 22 files changed, 3769 insertions(+), 4 deletions(-) + create mode 100644 libiscsi/Makefile + create mode 100644 libiscsi/libiscsi.c + create mode 100644 libiscsi/libiscsi.doxy + create mode 100644 libiscsi/libiscsi.h + create mode 100644 libiscsi/no_date_footer.html + create mode 100644 libiscsi/pylibiscsi.c + create mode 100644 libiscsi/setup.py + create mode 100644 libiscsi/tests/test_discovery_firmware.c + create mode 100644 libiscsi/tests/test_discovery_sendtargets.c + create mode 100644 libiscsi/tests/test_get_auth.c + create mode 100644 libiscsi/tests/test_get_initiator_name.c + create mode 100644 libiscsi/tests/test_get_network_config.c + create mode 100644 libiscsi/tests/test_login.c + create mode 100644 libiscsi/tests/test_logout.c + create mode 100644 libiscsi/tests/test_params.c + create mode 100644 libiscsi/tests/test_set_auth.c + +diff --git a/Makefile b/Makefile +index 7b445a5..4ab091f 100644 +--- a/Makefile ++++ b/Makefile +@@ -65,6 +65,7 @@ user: iscsiuio/Makefile + $(MAKE) -C usr + $(MAKE) -C utils + $(MAKE) -C iscsiuio ++ $(MAKE) -C libiscsi + @echo + @echo "Compilation complete Output file" + @echo "----------------------------------- ----------------" +@@ -85,6 +86,7 @@ iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile + force: ; + + clean: ++ $(MAKE) -C libiscsi clean + $(MAKE) -C utils/sysdeps clean + $(MAKE) -C utils/fwparam_ibft clean + $(MAKE) -C utils clean +diff --git a/libiscsi/Makefile b/libiscsi/Makefile +new file mode 100644 +index 0000000..53f9746 +--- /dev/null ++++ b/libiscsi/Makefile +@@ -0,0 +1,65 @@ ++# This Makefile will work only with GNU make. ++ ++ifeq ($(TOPDIR),) ++ TOPDIR = .. ++endif ++ ++OSNAME=$(shell uname -s) ++OPTFLAGS ?= -O2 -g ++WARNFLAGS ?= -Wall -Wstrict-prototypes ++CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \ ++ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden ++LIB = libiscsi.so.0 ++TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware ++TESTS += tests/test_login tests/test_logout tests/test_params ++TESTS += tests/test_get_network_config tests/test_get_initiator_name ++TESTS += tests/test_set_auth tests/test_get_auth ++ ++COMMON_SRCS = sysdeps.o ++# sources shared between iscsid, iscsiadm and iscsistart ++ISCSI_LIB_SRCS = netlink.o transport.o cxgbi.o be2iscsi.o iscsi_timer.o initiator_common.o iscsi_err.o session_info.o iscsi_util.o io.o auth.o discovery.o login.o log.o md5.o sha1.o iface.o idbm.o sysfs.o iscsi_sysfs.o iscsi_net_util.o iscsid_req.o iser.o uip_mgmt_ipc.o ++FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sysfs.o ++ ++# sources shared with the userspace utils, note we build these separately ++# to get PIC versions. ++COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS)) ++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o) ++FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS)) ++ ++# Flags for the tests ++tests/% : CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I. ++ ++all: lib tests html ++ ++lib: $(LIB) ++tests: $(TESTS) ++ ++common-objs/%.o: ../utils/sysdeps/%.c ++ mkdir -p common-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++usr-objs/%.o: ../usr/%.c ++ mkdir -p usr-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++fw-objs/%.o: ../utils/fwparam_ibft/%.c ++ mkdir -p fw-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++$(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o ++ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr ++ ln -s -f $(LIB) libiscsi.so ++ ++$(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB) ++ ++html: libiscsi.h libiscsi.doxy ++ doxygen libiscsi.doxy ++ ++clean: ++ rm -rf *.o common-objs usr-objs fw-objs libuip-objs libiscsi.so* \ ++ .depend *~ html $(TESTS) tests/*~ ++ ++depend: ++ gcc $(CFLAGS) -M `ls *.c` > .depend ++ ++-include .depend ../usr/.depend +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +new file mode 100644 +index 0000000..064e4b5 +--- /dev/null ++++ b/libiscsi/libiscsi.c +@@ -0,0 +1,617 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * 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; ++ strlcpy(config->iface_name, fw_entry.iface, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->mac_address, fw_entry.mac, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->ip_address, fw_entry.ipaddr, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->netmask, fw_entry.mask, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->gateway, fw_entry.gateway, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->primary_dns, fw_entry.primary_dns, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->secondary_dns, fw_entry.secondary_dns, LIBISCSI_VALUE_MAXLEN); ++ return 0; ++} ++ ++int libiscsi_get_firmware_initiator_name(char *initiatorname) ++{ ++ struct boot_context fw_entry; ++ ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ ++ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN); ++ memset(&fw_entry, 0, sizeof fw_entry); ++ if (fw_get_entry(&fw_entry)) ++ return ENODEV; ++ ++ strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN); ++ ++ return 0; ++} +diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy +new file mode 100644 +index 0000000..7a5ff7f +--- /dev/null ++++ b/libiscsi/libiscsi.doxy +@@ -0,0 +1,1473 @@ ++# Doxyfile 1.5.7.1 ++ ++# This file describes the settings to be used by the documentation system ++# doxygen (www.doxygen.org) for a project ++# ++# All text after a hash (#) is considered a comment and will be ignored ++# The format is: ++# TAG = value [value, ...] ++# For lists items can also be appended using: ++# TAG += value [value, ...] ++# Values that contain spaces should be placed between quotes (" ") ++ ++#--------------------------------------------------------------------------- ++# Project related configuration options ++#--------------------------------------------------------------------------- ++ ++# This tag specifies the encoding used for all characters in the config file ++# that follow. The default is UTF-8 which is also the encoding used for all ++# text before the first occurrence of this tag. Doxygen uses libiconv (or the ++# iconv built into libc) for the transcoding. See ++# http://www.gnu.org/software/libiconv for the list of possible encodings. ++ ++DOXYFILE_ENCODING = UTF-8 ++ ++# The PROJECT_NAME tag is a single word (or a sequence of words surrounded ++# by quotes) that should identify the project. ++ ++PROJECT_NAME = libiscsi ++ ++# The PROJECT_NUMBER tag can be used to enter a project or revision number. ++# This could be handy for archiving the generated documentation or ++# if some version control system is used. ++ ++PROJECT_NUMBER = ++ ++# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) ++# base path where the generated documentation will be put. ++# If a relative path is entered, it will be relative to the location ++# where doxygen was started. If left blank the current directory will be used. ++ ++OUTPUT_DIRECTORY = ++ ++# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create ++# 4096 sub-directories (in 2 levels) under the output directory of each output ++# format and will distribute the generated files over these directories. ++# Enabling this option can be useful when feeding doxygen a huge amount of ++# source files, where putting all generated files in the same directory would ++# otherwise cause performance problems for the file system. ++ ++CREATE_SUBDIRS = NO ++ ++# The OUTPUT_LANGUAGE tag is used to specify the language in which all ++# documentation generated by doxygen is written. Doxygen will use this ++# information to generate all constant output in the proper language. ++# The default language is English, other supported languages are: ++# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, ++# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, ++# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), ++# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, ++# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, ++# Spanish, Swedish, and Ukrainian. ++ ++OUTPUT_LANGUAGE = English ++ ++# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will ++# include brief member descriptions after the members that are listed in ++# the file and class documentation (similar to JavaDoc). ++# Set to NO to disable this. ++ ++BRIEF_MEMBER_DESC = YES ++ ++# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend ++# the brief description of a member or function before the detailed description. ++# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the ++# brief descriptions will be completely suppressed. ++ ++REPEAT_BRIEF = NO ++ ++# This tag implements a quasi-intelligent brief description abbreviator ++# that is used to form the text in various listings. Each string ++# in this list, if found as the leading text of the brief description, will be ++# stripped from the text and the result after processing the whole list, is ++# used as the annotated text. Otherwise, the brief description is used as-is. ++# If left blank, the following values are used ("$name" is automatically ++# replaced with the name of the entity): "The $name class" "The $name widget" ++# "The $name file" "is" "provides" "specifies" "contains" ++# "represents" "a" "an" "the" ++ ++ABBREVIATE_BRIEF = ++ ++# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then ++# Doxygen will generate a detailed section even if there is only a brief ++# description. ++ ++ALWAYS_DETAILED_SEC = YES ++ ++# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all ++# inherited members of a class in the documentation of that class as if those ++# members were ordinary class members. Constructors, destructors and assignment ++# operators of the base classes will not be shown. ++ ++INLINE_INHERITED_MEMB = NO ++ ++# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full ++# path before files name in the file list and in the header files. If set ++# to NO the shortest path that makes the file name unique will be used. ++ ++FULL_PATH_NAMES = YES ++ ++# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag ++# can be used to strip a user-defined part of the path. Stripping is ++# only done if one of the specified strings matches the left-hand part of ++# the path. The tag can be used to show relative paths in the file list. ++# If left blank the directory from which doxygen is run is used as the ++# path to strip. ++ ++STRIP_FROM_PATH = ++ ++# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of ++# the path mentioned in the documentation of a class, which tells ++# the reader which header file to include in order to use a class. ++# If left blank only the name of the header file containing the class ++# definition is used. Otherwise one should specify the include paths that ++# are normally passed to the compiler using the -I flag. ++ ++STRIP_FROM_INC_PATH = ++ ++# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter ++# (but less readable) file names. This can be useful is your file systems ++# doesn't support long names like on DOS, Mac, or CD-ROM. ++ ++SHORT_NAMES = NO ++ ++# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen ++# will interpret the first line (until the first dot) of a JavaDoc-style ++# comment as the brief description. If set to NO, the JavaDoc ++# comments will behave just like regular Qt-style comments ++# (thus requiring an explicit @brief command for a brief description.) ++ ++JAVADOC_AUTOBRIEF = NO ++ ++# If the QT_AUTOBRIEF tag is set to YES then Doxygen will ++# interpret the first line (until the first dot) of a Qt-style ++# comment as the brief description. If set to NO, the comments ++# will behave just like regular Qt-style comments (thus requiring ++# an explicit \brief command for a brief description.) ++ ++QT_AUTOBRIEF = NO ++ ++# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen ++# treat a multi-line C++ special comment block (i.e. a block of //! or /// ++# comments) as a brief description. This used to be the default behaviour. ++# The new default is to treat a multi-line C++ comment block as a detailed ++# description. Set this tag to YES if you prefer the old behaviour instead. ++ ++MULTILINE_CPP_IS_BRIEF = NO ++ ++# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented ++# member inherits the documentation from any documented member that it ++# re-implements. ++ ++INHERIT_DOCS = YES ++ ++# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce ++# a new page for each member. If set to NO, the documentation of a member will ++# be part of the file/class/namespace that contains it. ++ ++SEPARATE_MEMBER_PAGES = NO ++ ++# The TAB_SIZE tag can be used to set the number of spaces in a tab. ++# Doxygen uses this value to replace tabs by spaces in code fragments. ++ ++TAB_SIZE = 8 ++ ++# This tag can be used to specify a number of aliases that acts ++# as commands in the documentation. An alias has the form "name=value". ++# For example adding "sideeffect=\par Side Effects:\n" will allow you to ++# put the command \sideeffect (or @sideeffect) in the documentation, which ++# will result in a user-defined paragraph with heading "Side Effects:". ++# You can put \n's in the value part of an alias to insert newlines. ++ ++ALIASES = ++ ++# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C ++# sources only. Doxygen will then generate output that is more tailored for C. ++# For instance, some of the names that are used will be different. The list ++# of all members will be omitted, etc. ++ ++OPTIMIZE_OUTPUT_FOR_C = YES ++ ++# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java ++# sources only. Doxygen will then generate output that is more tailored for ++# Java. For instance, namespaces will be presented as packages, qualified ++# scopes will look different, etc. ++ ++OPTIMIZE_OUTPUT_JAVA = NO ++ ++# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran ++# sources only. Doxygen will then generate output that is more tailored for ++# Fortran. ++ ++OPTIMIZE_FOR_FORTRAN = NO ++ ++# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL ++# sources. Doxygen will then generate output that is tailored for ++# VHDL. ++ ++OPTIMIZE_OUTPUT_VHDL = NO ++ ++# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want ++# to include (a tag file for) the STL sources as input, then you should ++# set this tag to YES in order to let doxygen match functions declarations and ++# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. ++# func(std::string) {}). This also make the inheritance and collaboration ++# diagrams that involve STL classes more complete and accurate. ++ ++BUILTIN_STL_SUPPORT = NO ++ ++# If you use Microsoft's C++/CLI language, you should set this option to YES to ++# enable parsing support. ++ ++CPP_CLI_SUPPORT = NO ++ ++# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. ++# Doxygen will parse them like normal C++ but will assume all classes use public ++# instead of private inheritance when no explicit protection keyword is present. ++ ++SIP_SUPPORT = NO ++ ++# For Microsoft's IDL there are propget and propput attributes to indicate getter ++# and setter methods for a property. Setting this option to YES (the default) ++# will make doxygen to replace the get and set methods by a property in the ++# documentation. This will only work if the methods are indeed getting or ++# setting a simple type. If this is not the case, or you want to show the ++# methods anyway, you should set this option to NO. ++ ++IDL_PROPERTY_SUPPORT = YES ++ ++# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC ++# tag is set to YES, then doxygen will reuse the documentation of the first ++# member in the group (if any) for the other members of the group. By default ++# all members of a group must be documented explicitly. ++ ++DISTRIBUTE_GROUP_DOC = NO ++ ++# Set the SUBGROUPING tag to YES (the default) to allow class member groups of ++# the same type (for instance a group of public functions) to be put as a ++# subgroup of that type (e.g. under the Public Functions section). Set it to ++# NO to prevent subgrouping. Alternatively, this can be done per class using ++# the \nosubgrouping command. ++ ++SUBGROUPING = YES ++ ++# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum ++# is documented as struct, union, or enum with the name of the typedef. So ++# typedef struct TypeS {} TypeT, will appear in the documentation as a struct ++# with name TypeT. When disabled the typedef will appear as a member of a file, ++# namespace, or class. And the struct will be named TypeS. This can typically ++# be useful for C code in case the coding convention dictates that all compound ++# types are typedef'ed and only the typedef is referenced, never the tag name. ++ ++TYPEDEF_HIDES_STRUCT = NO ++ ++# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to ++# determine which symbols to keep in memory and which to flush to disk. ++# When the cache is full, less often used symbols will be written to disk. ++# For small to medium size projects (<1000 input files) the default value is ++# probably good enough. For larger projects a too small cache size can cause ++# doxygen to be busy swapping symbols to and from disk most of the time ++# causing a significant performance penality. ++# If the system has enough physical memory increasing the cache will improve the ++# performance by keeping more symbols in memory. Note that the value works on ++# a logarithmic scale so increasing the size by one will rougly double the ++# memory usage. The cache size is given by this formula: ++# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, ++# corresponding to a cache size of 2^16 = 65536 symbols ++ ++SYMBOL_CACHE_SIZE = 0 ++ ++#--------------------------------------------------------------------------- ++# Build related configuration options ++#--------------------------------------------------------------------------- ++ ++# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in ++# documentation are documented, even if no documentation was available. ++# Private class members and static file members will be hidden unless ++# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES ++ ++EXTRACT_ALL = YES ++ ++# If the EXTRACT_PRIVATE tag is set to YES all private members of a class ++# will be included in the documentation. ++ ++EXTRACT_PRIVATE = NO ++ ++# If the EXTRACT_STATIC tag is set to YES all static members of a file ++# will be included in the documentation. ++ ++EXTRACT_STATIC = NO ++ ++# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) ++# defined locally in source files will be included in the documentation. ++# If set to NO only classes defined in header files are included. ++ ++EXTRACT_LOCAL_CLASSES = YES ++ ++# This flag is only useful for Objective-C code. When set to YES local ++# methods, which are defined in the implementation section but not in ++# the interface are included in the documentation. ++# If set to NO (the default) only methods in the interface are included. ++ ++EXTRACT_LOCAL_METHODS = NO ++ ++# If this flag is set to YES, the members of anonymous namespaces will be ++# extracted and appear in the documentation as a namespace called ++# 'anonymous_namespace{file}', where file will be replaced with the base ++# name of the file that contains the anonymous namespace. By default ++# anonymous namespace are hidden. ++ ++EXTRACT_ANON_NSPACES = NO ++ ++# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all ++# undocumented members of documented classes, files or namespaces. ++# If set to NO (the default) these members will be included in the ++# various overviews, but no documentation section is generated. ++# This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_MEMBERS = NO ++ ++# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all ++# undocumented classes that are normally visible in the class hierarchy. ++# If set to NO (the default) these classes will be included in the various ++# overviews. This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_CLASSES = NO ++ ++# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all ++# friend (class|struct|union) declarations. ++# If set to NO (the default) these declarations will be included in the ++# documentation. ++ ++HIDE_FRIEND_COMPOUNDS = NO ++ ++# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any ++# documentation blocks found inside the body of a function. ++# If set to NO (the default) these blocks will be appended to the ++# function's detailed documentation block. ++ ++HIDE_IN_BODY_DOCS = NO ++ ++# The INTERNAL_DOCS tag determines if documentation ++# that is typed after a \internal command is included. If the tag is set ++# to NO (the default) then the documentation will be excluded. ++# Set it to YES to include the internal documentation. ++ ++INTERNAL_DOCS = NO ++ ++# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate ++# file names in lower-case letters. If set to YES upper-case letters are also ++# allowed. This is useful if you have classes or files whose names only differ ++# in case and if your file system supports case sensitive file names. Windows ++# and Mac users are advised to set this option to NO. ++ ++CASE_SENSE_NAMES = YES ++ ++# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen ++# will show members with their full class and namespace scopes in the ++# documentation. If set to YES the scope will be hidden. ++ ++HIDE_SCOPE_NAMES = NO ++ ++# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen ++# will put a list of the files that are included by a file in the documentation ++# of that file. ++ ++SHOW_INCLUDE_FILES = YES ++ ++# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] ++# is inserted in the documentation for inline members. ++ ++INLINE_INFO = YES ++ ++# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen ++# will sort the (detailed) documentation of file and class members ++# alphabetically by member name. If set to NO the members will appear in ++# declaration order. ++ ++SORT_MEMBER_DOCS = YES ++ ++# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the ++# brief documentation of file, namespace and class members alphabetically ++# by member name. If set to NO (the default) the members will appear in ++# declaration order. ++ ++SORT_BRIEF_DOCS = NO ++ ++# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the ++# hierarchy of group names into alphabetical order. If set to NO (the default) ++# the group names will appear in their defined order. ++ ++SORT_GROUP_NAMES = NO ++ ++# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be ++# sorted by fully-qualified names, including namespaces. If set to ++# NO (the default), the class list will be sorted only by class name, ++# not including the namespace part. ++# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. ++# Note: This option applies only to the class list, not to the ++# alphabetical list. ++ ++SORT_BY_SCOPE_NAME = NO ++ ++# The GENERATE_TODOLIST tag can be used to enable (YES) or ++# disable (NO) the todo list. This list is created by putting \todo ++# commands in the documentation. ++ ++GENERATE_TODOLIST = YES ++ ++# The GENERATE_TESTLIST tag can be used to enable (YES) or ++# disable (NO) the test list. This list is created by putting \test ++# commands in the documentation. ++ ++GENERATE_TESTLIST = YES ++ ++# The GENERATE_BUGLIST tag can be used to enable (YES) or ++# disable (NO) the bug list. This list is created by putting \bug ++# commands in the documentation. ++ ++GENERATE_BUGLIST = YES ++ ++# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or ++# disable (NO) the deprecated list. This list is created by putting ++# \deprecated commands in the documentation. ++ ++GENERATE_DEPRECATEDLIST= YES ++ ++# The ENABLED_SECTIONS tag can be used to enable conditional ++# documentation sections, marked by \if sectionname ... \endif. ++ ++ENABLED_SECTIONS = ++ ++# The MAX_INITIALIZER_LINES tag determines the maximum number of lines ++# the initial value of a variable or define consists of for it to appear in ++# the documentation. If the initializer consists of more lines than specified ++# here it will be hidden. Use a value of 0 to hide initializers completely. ++# The appearance of the initializer of individual variables and defines in the ++# documentation can be controlled using \showinitializer or \hideinitializer ++# command in the documentation regardless of this setting. ++ ++MAX_INITIALIZER_LINES = 30 ++ ++# Set the SHOW_USED_FILES tag to NO to disable the list of files generated ++# at the bottom of the documentation of classes and structs. If set to YES the ++# list will mention the files that were used to generate the documentation. ++ ++SHOW_USED_FILES = YES ++ ++# If the sources in your project are distributed over multiple directories ++# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy ++# in the documentation. The default is NO. ++ ++SHOW_DIRECTORIES = NO ++ ++# Set the SHOW_FILES tag to NO to disable the generation of the Files page. ++# This will remove the Files entry from the Quick Index and from the ++# Folder Tree View (if specified). The default is YES. ++ ++SHOW_FILES = YES ++ ++# Set the SHOW_NAMESPACES tag to NO to disable the generation of the ++# Namespaces page. This will remove the Namespaces entry from the Quick Index ++# and from the Folder Tree View (if specified). The default is YES. ++ ++SHOW_NAMESPACES = YES ++ ++# The FILE_VERSION_FILTER tag can be used to specify a program or script that ++# doxygen should invoke to get the current version for each file (typically from ++# the version control system). Doxygen will invoke the program by executing (via ++# popen()) the command , 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 = no_date_footer.html ++ ++# The HTML_STYLESHEET tag can be used to specify a user-defined cascading ++# style sheet that is used by each HTML page. It can be used to ++# fine-tune the look of the HTML output. If the tag is left blank doxygen ++# will generate a default style sheet. Note that doxygen will try to copy ++# the style sheet file to the HTML output directory, so don't put your own ++# stylesheet in the HTML output directory as well, or it will be erased! ++ ++HTML_STYLESHEET = ++ ++# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, ++# files or namespaces will be aligned in HTML using tables. If set to ++# NO a bullet list will be used. ++ ++HTML_ALIGN_MEMBERS = YES ++ ++# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML ++# documentation will contain sections that can be hidden and shown after the ++# page has loaded. For this to work a browser that supports ++# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox ++# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). ++ ++HTML_DYNAMIC_SECTIONS = NO ++ ++# If the GENERATE_DOCSET tag is set to YES, additional index files ++# will be generated that can be used as input for Apple's Xcode 3 ++# integrated development environment, introduced with OSX 10.5 (Leopard). ++# To create a documentation set, doxygen will generate a Makefile in the ++# HTML output directory. Running make will produce the docset in that ++# directory and running "make install" will install the docset in ++# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find ++# it at startup. ++# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. ++ ++GENERATE_DOCSET = NO ++ ++# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the ++# feed. A documentation feed provides an umbrella under which multiple ++# documentation sets from a single provider (such as a company or product suite) ++# can be grouped. ++ ++DOCSET_FEEDNAME = "Doxygen generated docs" ++ ++# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that ++# should uniquely identify the documentation set bundle. This should be a ++# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen ++# will append .docset to the name. ++ ++DOCSET_BUNDLE_ID = org.doxygen.Project ++ ++# If the GENERATE_HTMLHELP tag is set to YES, additional index files ++# will be generated that can be used as input for tools like the ++# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) ++# of the generated HTML documentation. ++ ++GENERATE_HTMLHELP = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can ++# be used to specify the file name of the resulting .chm file. You ++# can add a path in front of the file if the result should not be ++# written to the html output directory. ++ ++CHM_FILE = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can ++# be used to specify the location (absolute path including file name) of ++# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run ++# the HTML help compiler on the generated index.hhp. ++ ++HHC_LOCATION = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag ++# controls if a separate .chi index file is generated (YES) or that ++# it should be included in the master .chm file (NO). ++ ++GENERATE_CHI = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING ++# is used to encode HtmlHelp index (hhk), content (hhc) and project file ++# content. ++ ++CHM_INDEX_ENCODING = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag ++# controls whether a binary table of contents is generated (YES) or a ++# normal table of contents (NO) in the .chm file. ++ ++BINARY_TOC = NO ++ ++# The TOC_EXPAND flag can be set to YES to add extra items for group members ++# to the contents of the HTML help documentation and to the tree view. ++ ++TOC_EXPAND = NO ++ ++# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER ++# are set, an additional index file will be generated that can be used as input for ++# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated ++# HTML documentation. ++ ++GENERATE_QHP = NO ++ ++# If the QHG_LOCATION tag is specified, the QCH_FILE tag can ++# be used to specify the file name of the resulting .qch file. ++# The path specified is relative to the HTML output folder. ++ ++QCH_FILE = ++ ++# The QHP_NAMESPACE tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# 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/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
++ ++ +diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c +new file mode 100644 +index 0000000..8800853 +--- /dev/null ++++ b/libiscsi/pylibiscsi.c +@@ -0,0 +1,709 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * 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" ++ ++#if PY_MAJOR_VERSION >= 3 ++#define IS_PY3K ++#define MODINITERROR return NULL ++#define PYNUM_FROMLONG PyLong_FromLong ++#define PYSTR_FROMSTRING PyUnicode_FromString ++#else ++#define MODINITERROR return ++#define PYNUM_FROMLONG PyInt_FromLong ++#define PYSTR_FROMSTRING PyString_FromString ++#endif ++ ++#define RET_TRUE_ELSE_FALSE { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } ++#define CMP_TO_RICHCMP(cmpfunc) \ ++ int comp_res = cmpfunc(self, other); \ ++ switch (op) { \ ++ case Py_LT: \ ++ if (comp_res < 0) RET_TRUE_ELSE_FALSE \ ++ case Py_LE: \ ++ if (comp_res <= 0) RET_TRUE_ELSE_FALSE \ ++ case Py_EQ: \ ++ if (comp_res == 0) RET_TRUE_ELSE_FALSE \ ++ case Py_NE: \ ++ if (comp_res != 0) RET_TRUE_ELSE_FALSE \ ++ case Py_GT: \ ++ if (comp_res > 0) RET_TRUE_ELSE_FALSE \ ++ default: \ ++ if (comp_res >= 0) RET_TRUE_ELSE_FALSE \ ++ } ++ ++static struct libiscsi_context *context = NULL; ++ ++/****************************** helpers ***********************************/ ++static int check_string(const char *string) ++{ ++ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) { ++ PyErr_SetString(PyExc_ValueError, "string too long"); ++ return -1; ++ } ++ return 0; ++} ++ ++/********************** PyIscsiChapAuthInfo ***************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_auth_info info; ++} PyIscsiChapAuthInfo; ++ ++static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ int i; ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char *kwlist[] = {"username", "password", "reverse_username", ++ "reverse_password", NULL}; ++ const char *string[4] = { NULL, NULL, NULL, NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, ++ "zz|zz:chapAuthInfo.__init__", ++ kwlist, &string[0], &string[1], ++ &string[2], &string[3])) ++ return -1; ++ ++ for (i = 0; i < 4; i++) ++ if (string[i] && check_string(string[i])) ++ return -1; ++ ++ memset (&chap->info, 0, sizeof(chap->info)); ++ chap->info.method = libiscsi_auth_chap; ++ if (string[0]) ++ strcpy(chap->info.chap.username, string[0]); ++ if (string[1]) ++ strcpy(chap->info.chap.password, string[1]); ++ if (string[2]) ++ strcpy(chap->info.chap.reverse_username, string[2]); ++ if (string[3]) ++ strcpy(chap->info.chap.reverse_password, string[3]); ++ ++ if (libiscsi_verify_auth_info(context, &chap->info)) { ++ PyErr_SetString(PyExc_ValueError, ++ libiscsi_get_error_string(context)); ++ return -1; ++ } ++ return 0; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "username")) { ++ return PYSTR_FROMSTRING(chap->info.chap.username); ++ } else if (!strcmp(attr, "password")) { ++ return PYSTR_FROMSTRING(chap->info.chap.password); ++ } else if (!strcmp(attr, "reverse_username")) { ++ return PYSTR_FROMSTRING(chap->info.chap.reverse_username); ++ } else if (!strcmp(attr, "reverse_password")) { ++ return PYSTR_FROMSTRING(chap->info.chap.reverse_password); ++ } ++ return NULL; ++} ++ ++static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ ++ if (!strcmp(attr, "username")) { ++ strcpy(chap->info.chap.username, str); ++ } else if (!strcmp(attr, "password")) { ++ strcpy(chap->info.chap.password, str); ++ } else if (!strcmp(attr, "reverse_username")) { ++ strcpy(chap->info.chap.reverse_username, str); ++ } else if (!strcmp(attr, "reverse_password")) { ++ strcpy(chap->info.chap.reverse_password, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self, ++ PyIscsiChapAuthInfo *other) ++{ ++ int r; ++ ++ r = strcmp(self->info.chap.username, other->info.chap.username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.password, other->info.chap.password); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_username, ++ other->info.chap.reverse_username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_password, ++ other->info.chap.reverse_password); ++ return r; ++} ++ ++PyObject *PyIscsiChapAuthInfo_richcompare(PyIscsiChapAuthInfo *self, ++ PyIscsiChapAuthInfo *other, ++ int op) ++{ ++ CMP_TO_RICHCMP(PyIscsiChapAuthInfo_compare) ++} ++ ++static PyObject *PyIscsiChapAuthInfo_str(PyObject *self) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char s[1024], reverse[512] = ""; ++ ++ if (chap->info.chap.reverse_username[0]) ++ snprintf(reverse, sizeof(reverse), ", %s:%s", ++ chap->info.chap.reverse_username, ++ chap->info.chap.reverse_password); ++ ++ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username, ++ chap->info.chap.password, reverse); ++ ++ return PYSTR_FROMSTRING(s); ++} ++ ++static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = { ++ {"username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "username", "username"}, ++ {"password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "password", "password"}, ++ {"reverse_username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_username", "reverse_username"}, ++ {"reverse_password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_password", "reverse_password"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiChapAuthInfo_Type = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ .tp_name = "libiscsi.chapAuthInfo", ++ .tp_basicsize = sizeof (PyIscsiChapAuthInfo), ++ .tp_getset = PyIscsiChapAuthInfo_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ++#ifndef IS_PY3K ++ // Py_TPFLAGS_CHECKTYPES is only needed on Python 2 ++ | Py_TPFLAGS_CHECKTYPES ++#endif ++ , ++ .tp_richcompare = (richcmpfunc)PyIscsiChapAuthInfo_compare, ++ .tp_init = PyIscsiChapAuthInfo_init, ++ .tp_str = PyIscsiChapAuthInfo_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "iscsi chap authentication information.", ++}; ++ ++/***************************** PyIscsiNode ********************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_node node; ++} PyIscsiNode; ++ ++static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char *kwlist[] = {"name", "tpgt", "address", "port", "iface", NULL}; ++ const char *name = NULL, *address = NULL, *iface = NULL; ++ int tpgt = -1, port = 3260; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isis:node.__init__", ++ kwlist, &name, &tpgt, &address, ++ &port, &iface)) ++ return -1; ++ if (address == NULL) { ++ PyErr_SetString(PyExc_ValueError, "address not set"); ++ return -1; ++ } ++ if (check_string(name) || check_string(address) || check_string(iface)) ++ return -1; ++ ++ strcpy(node->node.name, name); ++ node->node.tpgt = tpgt; ++ strcpy(node->node.address, address); ++ node->node.port = port; ++ strcpy(node->node.iface, iface); ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_get(PyObject *self, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "name")) { ++ return PYSTR_FROMSTRING(node->node.name); ++ } else if (!strcmp(attr, "tpgt")) { ++ return PYNUM_FROMLONG(node->node.tpgt); ++ } else if (!strcmp(attr, "address")) { ++ return PYSTR_FROMSTRING(node->node.address); ++ } else if (!strcmp(attr, "port")) { ++ return PYNUM_FROMLONG(node->node.port); ++ } else if (!strcmp(attr, "iface")) { ++ return PYSTR_FROMSTRING(node->node.iface); ++ } ++ return NULL; ++} ++ ++static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ int i; ++ ++ if (!strcmp(attr, "name")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.name, str); ++ } else if (!strcmp(attr, "tpgt")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.tpgt = i; ++ } else if (!strcmp(attr, "address")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.address, str); ++ } else if (!strcmp(attr, "port")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.port = i; ++ } else if (!strcmp(attr, "iface")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.iface, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other) ++{ ++ int res; ++ ++ res = strcmp(self->node.name, other->node.name); ++ if (res) ++ return res; ++ ++ if (self->node.tpgt < other->node.tpgt) ++ return -1; ++ if (self->node.tpgt > other->node.tpgt) ++ return -1; ++ ++ res = strcmp(self->node.address, other->node.address); ++ if (res) ++ return res; ++ ++ if (self->node.port < other->node.port) ++ return -1; ++ if (self->node.port > other->node.port) ++ return -1; ++ ++ res = strcmp(self->node.iface, other->node.iface); ++ if (res) ++ return res; ++ ++ return 0; ++} ++ ++PyObject *PyIscsiNode_richcompare(PyIscsiNode *self, PyIscsiNode *other, int op) ++{ ++ CMP_TO_RICHCMP(PyIscsiNode_compare) ++} ++ ++static PyObject *PyIscsiNode_str(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char s[1024], tpgt[16] = ""; ++ ++ if (node->node.tpgt != -1) ++ sprintf(tpgt, ",%d", node->node.tpgt); ++ ++ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address, ++ node->node.port, tpgt, node->node.name); ++ ++ return PYSTR_FROMSTRING(s); ++} ++ ++static PyObject *PyIscsiNode_login(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_login(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_logout(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_logout(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"authinfo", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyObject *arg; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) ++ return NULL; ++ ++ if (arg == Py_None) { ++ authinfo = NULL; ++ } else if (PyObject_IsInstance(arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg; ++ authinfo = &pyauthinfo->info; ++ } else { ++ PyErr_SetString(PyExc_ValueError, "invalid authinfo type"); ++ return NULL; ++ } ++ ++ if (libiscsi_node_set_auth(context, &node->node, authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getAuth(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyIscsiChapAuthInfo *pyauthinfo; ++ struct libiscsi_auth_info authinfo; ++ ++ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ switch (authinfo.method) { ++ case libiscsi_auth_chap: ++ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo, ++ &PyIscsiChapAuthInfo_Type); ++ if (!pyauthinfo) ++ return NULL; ++ ++ pyauthinfo->info = authinfo; ++ ++ return (PyObject *)pyauthinfo; ++ ++ case libiscsi_auth_none: ++ default: ++ Py_RETURN_NONE; ++ } ++} ++ ++static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", "value", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter, *value; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, ++ ¶meter, &value)) ++ return NULL; ++ if (check_string(parameter) || check_string(value)) ++ return NULL; ++ ++ if (libiscsi_node_set_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, ¶meter)) ++ return NULL; ++ if (check_string(parameter)) ++ return NULL; ++ ++ if (libiscsi_node_get_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ return Py_BuildValue("s", value); ++} ++ ++static struct PyGetSetDef PyIscsiNode_getseters[] = { ++ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "name", "name"}, ++ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "tpgt", "tpgt"}, ++ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "address", "address"}, ++ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "port", "port"}, ++ {"iface", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "iface", "iface"}, ++ {NULL} ++}; ++ ++static struct PyMethodDef PyIscsiNode_methods[] = { ++ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS, ++ "Log in to the node"}, ++ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS, ++ "Log out of the node"}, ++ {"setAuth", (PyCFunction) PyIscsiNode_setAuth, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set authentication information"}, ++ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS, ++ "Get authentication information"}, ++ {"setParameter", (PyCFunction) PyIscsiNode_setParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set an iscsi node parameter"}, ++ {"getParameter", (PyCFunction) PyIscsiNode_getParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Get an iscsi node parameter"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiNode_Type = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ .tp_name = "libiscsi.node", ++ .tp_basicsize = sizeof (PyIscsiNode), ++ .tp_getset = PyIscsiNode_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE ++#ifndef IS_PY3K ++ | Py_TPFLAGS_CHECKTYPES ++#endif ++ , ++ .tp_methods = PyIscsiNode_methods, ++ .tp_richcompare = (richcmpfunc)PyIscsiNode_richcompare, ++ .tp_init = PyIscsiNode_init, ++ .tp_str = PyIscsiNode_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "The iscsi node contains iscsi node information.", ++}; ++ ++/***************************************************************************/ ++ ++static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, ++ PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"address", "port", "authinfo", NULL}; ++ const char *address = NULL; ++ int i, nr_found, port = 3260; ++ PyObject *authinfo_arg = NULL; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO", ++ kwlist, &address, &port, ++ &authinfo_arg)) ++ return NULL; ++ ++ if (authinfo_arg) { ++ if (PyObject_IsInstance(authinfo_arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = ++ (PyIscsiChapAuthInfo *)authinfo_arg; ++ authinfo = &pyauthinfo->info; ++ } else if (authinfo_arg != Py_None) { ++ PyErr_SetString(PyExc_ValueError, ++ "invalid authinfo type"); ++ return NULL; ++ } ++ } ++ ++ if (libiscsi_discover_sendtargets(context, address, port, authinfo, ++ &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_discover_firmware(PyObject *self) ++{ ++ int i, nr_found; ++ struct libiscsi_node *found_nodes; ++ 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 PYSTR_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} ++}; ++ ++#ifdef IS_PY3K ++static struct PyModuleDef libiscsi_def = { ++ PyModuleDef_HEAD_INIT, ++ "libiscsi", ++ NULL, ++ -1, ++ pylibiscsi_functions, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ ++PyMODINIT_FUNC PyInit_libiscsi(void) ++#else ++PyMODINIT_FUNC initlibiscsi(void) ++#endif ++{ ++ PyObject *m; ++ ++ if (!context) /* We may be called more then once */ ++ context = libiscsi_init(); ++ if (!context) ++ MODINITERROR; ++ ++ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0) ++ MODINITERROR; ++ ++ if (PyType_Ready(&PyIscsiNode_Type) < 0) ++ MODINITERROR; ++ ++#ifdef IS_PY3K ++ m = PyModule_Create(&libiscsi_def); ++#else ++ m = Py_InitModule("libiscsi", pylibiscsi_functions); ++#endif ++ Py_INCREF(&PyIscsiChapAuthInfo_Type); ++ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type); ++ Py_INCREF(&PyIscsiNode_Type); ++ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type); ++#ifdef IS_PY3K ++ return m; ++#endif ++} +diff --git a/libiscsi/setup.py b/libiscsi/setup.py +new file mode 100644 +index 0000000..caa4e66 +--- /dev/null ++++ b/libiscsi/setup.py +@@ -0,0 +1,9 @@ ++from distutils.core import setup, Extension ++ ++module1 = Extension('libiscsi', ++ 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 21bb154..885243a 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -37,7 +37,7 @@ PKG_CONFIG = /usr/bin/pkg-config + CFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wextra -Werror -Wstrict-prototypes -fno-common + CFLAGS += $(WARNFLAGS) -I../include -I. -D_GNU_SOURCE \ +- -I$(TOPDIR)/libopeniscsiusr ++ -I$(TOPDIR)/libopeniscsiusr -DISNS_ENABLE + CFLAGS += $(shell $(PKG_CONFIG) --cflags libkmod) + ISCSI_LIB = -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr + LDFLAGS += $(shell $(PKG_CONFIG) --libs libkmod) +diff --git a/usr/discovery.c b/usr/discovery.c +index 9ce122e..4ef5448 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" +@@ -49,10 +50,12 @@ + #include "iface.h" + #include "iscsi_timer.h" + #include "iscsi_err.h" ++#ifdef ISNS_ENABLE + /* libisns includes */ + #include + #include + #include ++#endif + + #ifdef SLP_ENABLE + #include "iscsi-slp-discovery.h" +@@ -98,6 +101,7 @@ static int request_initiator_name(int tmo) + 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, + __attribute__((unused))struct iface_rec *iface, +diff --git a/usr/idbm.c b/usr/idbm.c +index a5c653c..d5e16cb 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1824,9 +1824,9 @@ int idbm_print_all_discovery(int info_level) + * fn should return -1 if it skipped the rec, an 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, +- bool ruw_lock) ++int idbm_for_each_iface(int *found, void *data, idbm_iface_op_fn *fn, ++ char *targetname, int tpgt, char *ip, int port, ++ bool ruw_lock) + { + DIR *iface_dirfd; + struct dirent *iface_dent; +diff --git a/usr/idbm.h b/usr/idbm.h +index ce098b7..d1a7f63 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -105,6 +105,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, ++ bool ruw_lock); + extern int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn, + char *targetname, bool ruw_lock); + extern int idbm_for_each_node(int *found, void *data, +diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h +index 47857dd..fb8e965 100644 +--- a/usr/iscsi_ipc.h ++++ b/usr/iscsi_ipc.h +@@ -162,4 +162,6 @@ struct iscsi_ipc { + char *host_stats); + }; + ++extern struct iscsi_ipc *ipc; ++ + #endif /* ISCSI_IPC_H */ +-- +2.21.1 + diff --git a/0009-Add-macros-to-release-GIL-lock.patch b/0009-Add-macros-to-release-GIL-lock.patch new file mode 100644 index 0000000..6804133 --- /dev/null +++ b/0009-Add-macros-to-release-GIL-lock.patch @@ -0,0 +1,56 @@ +From 3df19ccba0af40da8cdb15c41e1bcd08ce25fbd9 Mon Sep 17 00:00:00 2001 +From: Jiri Konecny +Date: Mon, 11 May 2015 13:16:26 +0200 +Subject: [PATCH] Add macros to release GIL lock + +Other threads are blocked when GIL is not released before the time consuming +functions. +--- + libiscsi/pylibiscsi.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c +index 8800853..40b5955 100644 +--- a/libiscsi/pylibiscsi.c ++++ b/libiscsi/pylibiscsi.c +@@ -364,8 +364,13 @@ static PyObject *PyIscsiNode_str(PyObject *self) + static PyObject *PyIscsiNode_login(PyObject *self) + { + PyIscsiNode *node = (PyIscsiNode *)self; ++ int ret; + +- if (libiscsi_node_login(context, &node->node)) { ++ Py_BEGIN_ALLOW_THREADS ++ ret = libiscsi_node_login(context, &node->node); ++ Py_END_ALLOW_THREADS ++ ++ if (ret) { + PyErr_SetString(PyExc_IOError, + libiscsi_get_error_string(context)); + return NULL; +@@ -551,6 +556,7 @@ static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, + const struct libiscsi_auth_info *authinfo = NULL; + struct libiscsi_node *found_nodes; + PyObject* found_node_list; ++ int ret; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO", + kwlist, &address, &port, +@@ -570,8 +576,12 @@ static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, + } + } + +- if (libiscsi_discover_sendtargets(context, address, port, authinfo, +- &nr_found, &found_nodes)) { ++ Py_BEGIN_ALLOW_THREADS ++ ret = libiscsi_discover_sendtargets(context, address, port, authinfo, ++ &nr_found, &found_nodes); ++ Py_END_ALLOW_THREADS ++ ++ if (ret) { + PyErr_SetString(PyExc_IOError, + libiscsi_get_error_string(context)); + return NULL; +-- +2.21.0 + diff --git a/0010-libiscsi-introduce-sessions-API.patch b/0010-libiscsi-introduce-sessions-API.patch new file mode 100644 index 0000000..b6c3728 --- /dev/null +++ b/0010-libiscsi-introduce-sessions-API.patch @@ -0,0 +1,290 @@ +From bca0b3a085b7a169aa40d81ed7997c73fde8b4d3 Mon Sep 17 00:00:00 2001 +From: Peter Hatina +Date: Mon, 5 Oct 2015 16:50:36 -0700 +Subject: [PATCH] libiscsi introduce sessions API + +--- + libiscsi/libiscsi.c | 125 ++++++++++++++++++++++++++++++++++++++++++++ + libiscsi/libiscsi.h | 56 ++++++++++++++++++++ + usr/iscsi_sysfs.c | 6 +++ + usr/iscsi_sysfs.h | 2 + + 4 files changed, 189 insertions(+) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index 064e4b5..755c18c 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. + * Copyright (C) 2008-2009 Hans de Goede ++ * Copyright (C) 2015 Peter Hatina + * maintained by open-iscsi@googlegroups.com + * + * This program is free software; you can redistribute it and/or modify +@@ -469,6 +470,130 @@ leave: + return rc; + } + ++struct libiscsi_session_array { ++ int cnt; ++ int size; ++ struct libiscsi_session_info *data; ++}; ++ ++static void libiscsi_session_array_init(struct libiscsi_session_array *arr) ++{ ++ arr->cnt = 0; ++ arr->size = 0; ++ arr->data = NULL; ++} ++ ++static int libiscsi_session_array_grow(struct libiscsi_session_array *arr) ++{ ++ if (arr->size == 0) ++ arr->size = 4; ++ else ++ arr->size *= 2; ++ ++ arr->data = (struct libiscsi_session_info *) realloc( ++ arr->data, ++ arr->size * sizeof(struct libiscsi_session_info)); ++ ++ return arr->data ? 0 : 1; ++} ++ ++static int libiscsi_session_array_grow_ondemand(struct libiscsi_session_array *arr) ++{ ++ if (arr->size == arr->cnt) ++ return libiscsi_session_array_grow(arr); ++ return 0; ++} ++ ++static int libiscsi_session_array_resize_precize(struct libiscsi_session_array *arr) ++{ ++ arr->data = (struct libiscsi_session_info *) realloc( ++ arr->data, ++ arr->cnt * sizeof(struct libiscsi_session_info)); ++ arr->size = arr->cnt; ++ ++ return arr->data ? 0 : 1; ++} ++ ++static void copy_session_info_to_libiscsi_session_info( ++ struct libiscsi_session_info *info, ++ struct session_info *s_info) ++{ ++ /* Copy session info to public struct. */ ++ info->sid = s_info->sid; ++ /* Timeouts */ ++ memcpy(&info->tmo, &s_info->tmo, sizeof(struct libiscsi_session_timeout)); ++ /* CHAP authentication information */ ++ memcpy(&info->chap, &s_info->chap, sizeof(struct libiscsi_chap_auth_info)); ++ /* Target information */ ++ strncpy(info->targetname, s_info->targetname, LIBISCSI_VALUE_MAXLEN); ++ strncpy(info->address, s_info->address, NI_MAXHOST); ++ strncpy(info->persistent_address, s_info->persistent_address, NI_MAXHOST); ++ info->tpgt = s_info->tpgt; ++ info->persistent_port = s_info->persistent_port; ++} ++ ++static int get_sessions_helper(void *data, struct session_info *s_info) ++{ ++ struct libiscsi_session_array *arr = (struct libiscsi_session_array *) data; ++ ++ if (libiscsi_session_array_grow_ondemand(arr) != 0) ++ return 1; ++ ++ copy_session_info_to_libiscsi_session_info(&arr->data[arr->cnt++], s_info); ++ ++ return 0; ++} ++ ++int libiscsi_get_session_infos(struct libiscsi_context *context, ++ struct libiscsi_session_info **infos, ++ int *nr_sessions) ++{ ++ int rc = 0; ++ int nr_found = 0; ++ struct libiscsi_session_array arr; ++ ++ if (!context || !infos || !nr_sessions) ++ return 1; ++ ++ libiscsi_session_array_init(&arr); ++ ++ rc = iscsi_sysfs_for_each_session((void *) &arr, &nr_found, ++ get_sessions_helper, 0); ++ if (rc != 0 || nr_found == 0) { ++ strcpy(context->error_str, "No matching session"); ++ return ENODEV; ++ } ++ ++ if (libiscsi_session_array_resize_precize(&arr) != 0) { ++ strcpy(context->error_str, "Can't allocate memory for session infos"); ++ return ENOMEM; ++ } ++ ++ *infos = arr.data; ++ *nr_sessions = nr_found; ++ ++ return 0; ++} ++ ++int libiscsi_get_session_info_by_id(struct libiscsi_context *context, ++ struct libiscsi_session_info *info, ++ const char *session) ++{ ++ struct session_info s_info; ++ ++ if (!context || !info || !session) ++ return 1; ++ ++ if (iscsi_sysfs_get_sessioninfo_by_id(&s_info, (char*) session) != 0) { ++ strcpy(context->error_str, "No matching session"); ++ return ENODEV; ++ } ++ ++ copy_session_info_to_libiscsi_session_info(info, &s_info); ++ ++ return 0; ++} ++ + int libiscsi_node_set_parameter(struct libiscsi_context *context, + const struct libiscsi_node *node, + const char *parameter, const char *value) +diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h +index 756590e..a9891f4 100644 +--- a/libiscsi/libiscsi.h ++++ b/libiscsi/libiscsi.h +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. + * Copyright (C) 2008-2009 Hans de Goede ++ * Copyright (C) 2015 Peter Hatina + * maintained by open-iscsi@googlegroups.com + * + * This program is free software; you can redistribute it and/or modify +@@ -56,6 +57,17 @@ enum libiscsi_auth_t { + */ + struct libiscsi_context; + ++/** \brief iSCSI session timeouts ++ * ++ * Struct holding session timeouts. ++ */ ++struct libiscsi_session_timeout { ++ int abort_tmo; ++ int lu_reset_tmo; ++ int recovery_tmo; ++ int tgt_reset_tmo; ++}; ++ + /** \brief iSCSI node record + * + * Struct holding data uniquely identifying an iSCSI node. +@@ -84,6 +96,24 @@ struct libiscsi_chap_auth_info { + char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */; + }; + ++/** \brief iSCSI session ++ * ++ * Struct hoding iSCSI session information. ++ */ ++struct libiscsi_session_info { ++ int sid; ++ ++ struct libiscsi_session_timeout tmo; ++ struct libiscsi_chap_auth_info chap; ++ ++ char targetname[LIBISCSI_VALUE_MAXLEN]; ++ int tpgt; ++ char address[NI_MAXHOST]; ++ int port; ++ char persistent_address[NI_MAXHOST]; ++ int persistent_port; ++}; ++ + /** \brief generic libiscsi authentication information struct + * + * Struct holding authentication information for discovery and login. +@@ -248,6 +278,32 @@ PUBLIC int libiscsi_node_login(struct libiscsi_context *context, + PUBLIC int libiscsi_node_logout(struct libiscsi_context *context, + const struct libiscsi_node *node); + ++/** \brief Get an array of iSCSI sessions. ++ * ++ * Get the array containing iSCSI sessions' information. ++ * ++ * \param context libiscsi context to operate on. ++ * \param infos Array of iSCSI sessions' information. ++ * Release with free(). ++ * \param nr_sessions The number of elements in \e infos. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_get_session_infos(struct libiscsi_context *context, ++ struct libiscsi_session_info **infos, int *nr_sessions); ++ ++/** \brief Get session information by session ID. ++ * ++ * \param context libiscsi context to operate on. ++ * \param info iSCSI session information. ++ * \param session Session name. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h) ++ */ ++PUBLIC int libiscsi_get_session_info_by_id(struct libiscsi_context *context, ++ struct libiscsi_session_info *info, ++ const char *session); ++ + /** \brief Set an iSCSI parameter for the given node + * + * Set the given nodes iSCSI parameter named by \e parameter to value \e value. +diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c +index 418f51b..6febba2 100644 +--- a/usr/iscsi_sysfs.c ++++ b/usr/iscsi_sysfs.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2006 Mike Christie + * Copyright (C) 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2015 Peter Hatina + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published +@@ -1151,6 +1152,11 @@ free_info: + return rc; + } + ++const char *iscsi_sysfs_get_session_path(void) ++{ ++ return ISCSI_SESSION_DIR; ++} ++ + int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no, + int *nr_found, + iscsi_sysfs_iface_op_fn *fn) +diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h +index 1d0377f..909db34 100644 +--- a/usr/iscsi_sysfs.h ++++ b/usr/iscsi_sysfs.h +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2006 Mike Christie + * Copyright (C) 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2015 Peter Hatina + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published +@@ -47,6 +48,7 @@ typedef int (iscsi_sysfs_flashnode_op_fn)(void *, struct flashnode_rec *, + uint32_t, uint32_t); + typedef int (iscsi_sysfs_iface_op_fn)(void *, struct iface_rec *); + ++extern const char *iscsi_sysfs_get_session_path(void); + extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no, + int *nr_found, + iscsi_sysfs_iface_op_fn *fn); +-- +2.21.0 + diff --git a/0011-libiscsi-fix-discovery-request-timeout-regression.patch b/0011-libiscsi-fix-discovery-request-timeout-regression.patch new file mode 100644 index 0000000..8771f6a --- /dev/null +++ b/0011-libiscsi-fix-discovery-request-timeout-regression.patch @@ -0,0 +1,32 @@ +From 2e660a78632545e98f7c9e2ffb8518512c0db5ff Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 28 Feb 2017 09:00:41 -0800 +Subject: [PATCH] libiscsi: fix discovery request timeout regression + +--- + libiscsi/libiscsi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index 755c18c..bb17dfc 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -136,6 +136,7 @@ int libiscsi_discover_sendtargets(struct libiscsi_context *context, + + /* Fill the drec struct with all needed info */ + memset(&drec, 0, sizeof drec); ++ drec.iscsid_req_tmo = -1; + idbm_sendtargets_defaults(&drec.u.sendtargets); + drec.type = DISCOVERY_TYPE_SENDTARGETS; + strlcpy(drec.address, address, sizeof(drec.address)); +@@ -228,6 +229,7 @@ int libiscsi_discover_firmware(struct libiscsi_context *context, + CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets)); + + memset(&drec, 0, sizeof(drec)); ++ drec.iscsid_req_tmo = -1; + drec.type = DISCOVERY_TYPE_FW; + rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list); + if (rc) { +-- +2.21.0 + diff --git a/0012-libiscsi-format-security-build-errors.patch b/0012-libiscsi-format-security-build-errors.patch new file mode 100644 index 0000000..19244b3 --- /dev/null +++ b/0012-libiscsi-format-security-build-errors.patch @@ -0,0 +1,35 @@ +From 3040b7530eda1ab5625d76783dc7b8cf595a0ef0 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 28 Feb 2017 10:06:42 -0800 +Subject: [PATCH] libiscsi format-security build errors + +--- + libiscsi/libiscsi.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index bb17dfc..7003388 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -177,7 +177,8 @@ int libiscsi_discover_sendtargets(struct libiscsi_context *context, + *found_nodes = calloc(found, sizeof **found_nodes); + if (*found_nodes == NULL) { + snprintf(context->error_str, +- sizeof(context->error_str), strerror(ENOMEM)); ++ sizeof(context->error_str), ++ "%s", strerror(ENOMEM)); + rc = ENOMEM; + goto leave; + } +@@ -634,7 +635,7 @@ static int get_parameter_helper(void *data, node_rec_t *rec) + info = idbm_recinfo_alloc(MAX_KEYS); + if (!info) { + snprintf(context->error_str, sizeof(context->error_str), +- strerror(ENOMEM)); ++ "%s", strerror(ENOMEM)); + return ENOMEM; + } + +-- +2.21.0 + diff --git a/0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch b/0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch new file mode 100644 index 0000000..65688a7 --- /dev/null +++ b/0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch @@ -0,0 +1,36 @@ +From 123fc55dd8ad98c9afd39bf0824b3d31d5e93214 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Thu, 24 May 2018 15:17:05 -0700 +Subject: [PATCH] libiscsi fix build to use libopeniscsiusr + +--- + libiscsi/Makefile | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libiscsi/Makefile b/libiscsi/Makefile +index 53f9746..f2cf248 100644 +--- a/libiscsi/Makefile ++++ b/libiscsi/Makefile +@@ -8,7 +8,9 @@ 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 ++ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden \ ++ -I../libopeniscsiusr ++LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr + LIB = libiscsi.so.0 + TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware + TESTS += tests/test_login tests/test_logout tests/test_params +@@ -23,7 +25,7 @@ FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sys + # 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) ++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) local_strings.o) + FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS)) + + # Flags for the tests +-- +2.21.0 + diff --git a/0014-libiscsi-fix-build-against-latest-upstream-again.patch b/0014-libiscsi-fix-build-against-latest-upstream-again.patch new file mode 100644 index 0000000..ef2c891 --- /dev/null +++ b/0014-libiscsi-fix-build-against-latest-upstream-again.patch @@ -0,0 +1,66 @@ +From 039700890e11dff3323241349d3858f258c09cc0 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Thu, 7 Nov 2019 09:16:17 -0800 +Subject: [PATCH] libiscsi: fix build against latest upstream, again + +--- + libiscsi/Makefile | 4 ++-- + libiscsi/libiscsi.c | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/libiscsi/Makefile b/libiscsi/Makefile +index f2cf248..462d666 100644 +--- a/libiscsi/Makefile ++++ b/libiscsi/Makefile +@@ -10,7 +10,7 @@ WARNFLAGS ?= -Wall -Wstrict-prototypes + CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \ + -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden \ + -I../libopeniscsiusr +-LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr ++LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr -lkmod -lcrypto + LIB = libiscsi.so.0 + TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware + TESTS += tests/test_login tests/test_logout tests/test_params +@@ -19,7 +19,7 @@ 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 ++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 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 +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index 7003388..c598aee 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -429,7 +429,7 @@ int libiscsi_node_login(struct libiscsi_context *context, + + CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper, + (char *)node->name, node->tpgt, +- (char *)node->address, node->port)) ++ (char *)node->address, node->port, false)) + if (nr_found == 0) { + strcpy(context->error_str, "No such node"); + rc = ENODEV; +@@ -615,7 +615,7 @@ int libiscsi_node_set_parameter(struct libiscsi_context *context, + + CHECK(idbm_for_each_iface(&nr_found, ¶ms, idbm_node_set_param, + (char *)node->name, node->tpgt, +- (char *)node->address, node->port)) ++ (char *)node->address, node->port, false)) + if (nr_found == 0) { + strcpy(context->error_str, "No such node"); + rc = ENODEV; +@@ -677,7 +677,7 @@ int libiscsi_node_get_parameter(struct libiscsi_context *context, + 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)) ++ (char *)node->address, node->port, false)) + if (nr_found == 0) { + strcpy(context->error_str, "No such node"); + rc = ENODEV; +-- +2.21.0 + diff --git a/0015-remove-the-offload-boot-supported-ifdef.patch b/0015-remove-the-offload-boot-supported-ifdef.patch new file mode 100644 index 0000000..d63dbd9 --- /dev/null +++ b/0015-remove-the-offload-boot-supported-ifdef.patch @@ -0,0 +1,45 @@ +From d0689253c9e2eb78fc5296adb109aba4d35a13fd Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 17:09:24 -0800 +Subject: [PATCH] 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 645b0b8..9cd07fd 100644 +--- a/usr/iface.c ++++ b/usr/iface.c +@@ -993,6 +993,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, +@@ -1006,10 +1007,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 */ +@@ -1035,9 +1033,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; + +-- +2.21.0 + diff --git a/0016-Revert-iscsiadm-return-error-when-login-fails.patch b/0016-Revert-iscsiadm-return-error-when-login-fails.patch new file mode 100644 index 0000000..0420b01 --- /dev/null +++ b/0016-Revert-iscsiadm-return-error-when-login-fails.patch @@ -0,0 +1,34 @@ +From ccb9d70a0dad7c42f926f1680ae708a5ae3d3696 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 24 Feb 2014 09:33:33 -0800 +Subject: [PATCH] Revert "iscsiadm: return error when login fails" + +This reverts commit fc2a8e9a2911bc76f961fe3e4a159fab9b8b9691. + +Done to address RHBZ #1015563 +--- + usr/session_mgmt.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c +index 0500f15..1e1f2bc 100644 +--- a/usr/session_mgmt.c ++++ b/usr/session_mgmt.c +@@ -178,12 +178,12 @@ int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec) + goto done; + } + if (session_count >= rec->session.nr_sessions) { +- log_warning("%s: %d session%s requested, but %d " ++ log_debug(1, "%s: %d session%s requested, but %d " + "already present.", + rec->iface.name, rec->session.nr_sessions, + rec->session.nr_sessions == 1 ? "" : "s", + session_count); +- rc = ISCSI_ERR_SESS_EXISTS; ++ rc = 0; + goto done; + } + +-- +2.21.0 + diff --git a/0017-dont-install-scripts.patch b/0017-dont-install-scripts.patch new file mode 100644 index 0000000..14c3683 --- /dev/null +++ b/0017-dont-install-scripts.patch @@ -0,0 +1,25 @@ +From f524e332835b2b59d3f3ff8a67814ef2d58a2857 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 25 May 2018 09:39:07 -0700 +Subject: [PATCH] dont install scripts + +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 4ab091f..7e6b734 100644 +--- a/Makefile ++++ b/Makefile +@@ -116,7 +116,7 @@ install_systemd: + $(INSTALL) -d $(DESTDIR)$(systemddir) + $(INSTALL) -m 644 $(SYSTEMDFILES) $(DESTDIR)/$(systemddir) + +-install_programs: $(PROGRAMS) $(SCRIPTS) ++install_programs: $(PROGRAMS) # $(SCRIPTS) + $(INSTALL) -d $(DESTDIR)$(sbindir) + $(INSTALL) -m 755 $^ $(DESTDIR)$(sbindir) + +-- +2.21.0 + diff --git a/0018-use-var-lib-iscsi-in-libopeniscsiusr.patch b/0018-use-var-lib-iscsi-in-libopeniscsiusr.patch new file mode 100644 index 0000000..08d5ed2 --- /dev/null +++ b/0018-use-var-lib-iscsi-in-libopeniscsiusr.patch @@ -0,0 +1,109 @@ +From e2b8215b80cc037ecbcb9eef50e432c31d5e56eb Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Wed, 30 May 2018 16:08:30 -0700 +Subject: [PATCH] use /var/lib/iscsi in libopeniscsiusr + +--- + libopeniscsiusr/idbm.h | 3 ++- + libopeniscsiusr/iface.c | 2 +- + libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h | 8 ++++---- + libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h | 2 +- + libopeniscsiusr/node.h | 2 +- + 5 files changed, 9 insertions(+), 8 deletions(-) + +diff --git a/libopeniscsiusr/idbm.h b/libopeniscsiusr/idbm.h +index 3fd0864..c84d332 100644 +--- a/libopeniscsiusr/idbm.h ++++ b/libopeniscsiusr/idbm.h +@@ -31,7 +31,8 @@ + #include "libopeniscsiusr/libopeniscsiusr_common.h" + + #define ISCSI_CONFIG_ROOT "/etc/iscsi/" +-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" ++#define ISCSI_VAR_LIB "/var/lib/iscsi/" ++#define IFACE_CONFIG_DIR ISCSI_VAR_LIB"ifaces" + #define AUTH_STR_MAX_LEN 256 + #define BOOT_NAME_MAXLEN 256 + #define IDBM_DUMP_SIZE 8192 +diff --git a/libopeniscsiusr/iface.c b/libopeniscsiusr/iface.c +index e7938a5..99ab7b5 100644 +--- a/libopeniscsiusr/iface.c ++++ b/libopeniscsiusr/iface.c +@@ -381,7 +381,7 @@ int iscsi_default_iface_setup(struct iscsi_context *ctx) + + _good(_iscsi_hids_get(ctx, &hids, &hid_count), rc, out); + for (i = 0; i < hid_count; ++i) { +- /* Create /etc/iscsi/ifaces/ file if not found ++ /* Create /var/lib/iscsi/ifaces/ file if not found + */ + _good(_iscsi_ifaces_get_from_sysfs(ctx, hids[i], &ifaces, &iface_count), + rc, out); +diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h +index 4395902..81582da 100644 +--- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h ++++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h +@@ -339,7 +339,7 @@ __DLL_EXPORT void iscsi_session_free(struct iscsi_session *se); + * * bnx2i + * + * It will also create configuration files for iSCSI hardware offload cards in +- * /etc/iscsi/ifaces/. ++ * /var/lib/iscsi/ifaces/. + * + * @ctx: + * Pointer of 'struct iscsi_context'. +@@ -369,7 +369,7 @@ __DLL_EXPORT int iscsi_default_iface_setup(struct iscsi_context *ctx); + * Retrieves all iSCSI interfaces. For the properties of 'struct iscsi_iface', + * please refer to the functions defined in 'libopeniscsiusr_iface.h' file. + * The returned results contains default iSCSI interfaces(iser and iscsi_tcp) +- * and iSCSI interfaces configured in "/etc/iscsi/ifaces/". ++ * and iSCSI interfaces configured in "/var/lib/iscsi/ifaces/". + * Illegal configuration file will be skipped and warned. + * To generate iSCSI interface configuration when new card installed, please + * use iscsi_default_iface_setup(). +@@ -427,7 +427,7 @@ __DLL_EXPORT void iscsi_ifaces_free(struct iscsi_iface **ifaces, + * iscsi_iface_get() - Retrieve specified iSCSI interface. + * + * Retrieves specified iSCSI interfaces by reading configuration from +- * "/etc/iscsi/iface/". ++ * "/var/lib/iscsi/iface/". + * To generate iSCSI interface configuration when new card installed, please + * use iscsi_default_iface_setup(). + * Illegal configuration file will be treated as error LIBISCSI_ERR_IDBM. +@@ -438,7 +438,7 @@ __DLL_EXPORT void iscsi_ifaces_free(struct iscsi_iface **ifaces, + * If this pointer is NULL, your program will be terminated by assert. + * @iface_name: + * String. Name of iSCSI interface. Also the file name of configuration +- * file "/etc/iscsi/iface/". ++ * file "/var/lib/iscsi/iface/". + * If this pointer is NULL or empty string, your program will be terminated + * by assert. + * @iface: +diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h +index a1a2552..95b0160 100644 +--- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h ++++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h +@@ -182,7 +182,7 @@ __DLL_EXPORT const char *iscsi_iface_name_get(struct iscsi_iface *iface); + * + * Dump all configurations of specified iSCSI interface. Will skip empty + * configuration so that output string could be saved directly to +- * /etc/iscsi/ifaces/ file. ++ * /var/lib/iscsi/ifaces/ file. + * + * @iface: + * Pointer of 'struct iscsi_iface'. +diff --git a/libopeniscsiusr/node.h b/libopeniscsiusr/node.h +index 39e07b3..9eba7fa 100644 +--- a/libopeniscsiusr/node.h ++++ b/libopeniscsiusr/node.h +@@ -44,7 +44,7 @@ struct iscsi_node { + char portal[NI_MAXHOST * 2]; + }; + +-#define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" ++#define NODE_CONFIG_DIR ISCSI_VAR_LIB"nodes" + + /* Might be public in the future */ + __DLL_LOCAL void iscsi_node_free(struct iscsi_node *node); +-- +2.21.0 + diff --git a/0019-Coverity-scan-fixes.patch b/0019-Coverity-scan-fixes.patch new file mode 100644 index 0000000..24f006f --- /dev/null +++ b/0019-Coverity-scan-fixes.patch @@ -0,0 +1,100 @@ +From ad8c3353b8e482575ff2208182290cf35b624dde Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 5 Jun 2019 09:08:39 -0700 +Subject: [PATCH 1/1] Coverity scan fixes + +--- + iscsiuio/src/unix/libs/qedi.c | 2 +- + iscsiuio/src/unix/main.c | 3 +++ + libopeniscsiusr/idbm.c | 11 +++++------ + usr/idbm.c | 10 ++++------ + usr/iscsid.c | 2 +- + 5 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/iscsiuio/src/unix/libs/qedi.c b/iscsiuio/src/unix/libs/qedi.c +index 3414cb5..a359700 100644 +--- a/iscsiuio/src/unix/libs/qedi.c ++++ b/iscsiuio/src/unix/libs/qedi.c +@@ -1023,7 +1023,7 @@ static int qedi_read(nic_t *nic, packet_t *pkt) + + LOG_DEBUG(PFX "%s:hw_prod %d bd_prod %d, rx_pkt_idx %d, rxlen %d", + nic->log_name, hw_prod, bd_prod, rx_bd->rx_pkt_index, len); +- LOG_DEBUG(PFX "%s: sw_con %d bd_cons %d num BD %d", ++ LOG_DEBUG(PFX "%s: sw_con %d bd_cons %d num BD %lu", + nic->log_name, sw_cons, bd_cons, QEDI_NUM_RX_BD); + + if (bd_cons != bd_prod) { +diff --git a/iscsiuio/src/unix/main.c b/iscsiuio/src/unix/main.c +index 0c9ad49..f83f305 100644 +--- a/iscsiuio/src/unix/main.c ++++ b/iscsiuio/src/unix/main.c +@@ -391,6 +391,9 @@ int main(int argc, char *argv[]) + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGUSR1); + rc = pthread_sigmask(SIG_SETMASK, &set, NULL); ++ if (rc != 0) { ++ LOG_ERR("Failed to set thread signal mask"); ++ } + + /* Spin off the signal handling thread */ + pthread_attr_init(&attr); +diff --git a/libopeniscsiusr/idbm.c b/libopeniscsiusr/idbm.c +index 7bc2381..7d4c338 100644 +--- a/libopeniscsiusr/idbm.c ++++ b/libopeniscsiusr/idbm.c +@@ -321,12 +321,11 @@ int _idbm_lock(struct iscsi_context *ctx) + return 0; + } + +- if (access(LOCK_DIR, F_OK) != 0) { +- if (mkdir(LOCK_DIR, 0660) != 0) { +- _error(ctx, "Could not open %s: %d %s", LOCK_DIR, errno, +- _strerror(errno, strerr_buff)); +- return LIBISCSI_ERR_IDBM; +- } ++ if (((mkdir(LOCK_DIR, 0660) != 0) && (errno != EEXIST)) || ++ (access(LOCK_DIR, F_OK) != 0)) { ++ _error(ctx, "Could not open %s: %d %s", LOCK_DIR, errno, ++ _strerror(errno, strerr_buff)); ++ return LIBISCSI_ERR_IDBM; + } + + fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666); +diff --git a/usr/idbm.c b/usr/idbm.c +index d5e16cb..a210c88 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1438,12 +1438,10 @@ int idbm_lock(void) + return 0; + } + +- if (access(LOCK_DIR, F_OK) != 0) { +- if (mkdir(LOCK_DIR, 0660) != 0) { +- log_error("Could not open %s: %s", LOCK_DIR, +- strerror(errno)); +- return ISCSI_ERR_IDBM; +- } ++ if (((mkdir(LOCK_DIR, 0660) != 0) && (errno != EEXIST)) || ++ (access(LOCK_DIR, F_OK) != 0)) { ++ log_error("Could not open %s: %s", LOCK_DIR, strerror(errno)); ++ return ISCSI_ERR_IDBM; + } + + fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666); +diff --git a/usr/iscsid.c b/usr/iscsid.c +index 99d27ab..dbb0900 100644 +--- a/usr/iscsid.c ++++ b/usr/iscsid.c +@@ -490,8 +490,8 @@ int main(int argc, char *argv[]) + log_close(log_pid); + exit(ISCSI_ERR); + } ++ close(fd); + } +- close(fd); + + if ((control_fd = ipc->ctldev_open()) < 0) { + log_close(log_pid); +-- +2.21.1 + diff --git a/0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch b/0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch new file mode 100644 index 0000000..b7d5c02 --- /dev/null +++ b/0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch @@ -0,0 +1,29 @@ +From 4142125fa296d21a307fb2370b2d4d7e8487f22c Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Wed, 16 Oct 2019 23:17:20 -0700 +Subject: [PATCH] fix upstream build breakage of iscsiuio LDFLAGS + +--- + iscsiuio/configure.ac | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac +index b41df0e..a856cc5 100644 +--- a/iscsiuio/configure.ac ++++ b/iscsiuio/configure.ac +@@ -67,10 +67,10 @@ AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) + AC_ARG_WITH([systemd], + AS_HELP_STRING([--without-systemd], [Build without systemd]), + [case "${withval}" in +- yes) LDFLAGS="`pkg-config --libs libsystemd`" ;; ++ yes) LDFLAGS="${LDFLAGS} `pkg-config --libs libsystemd`" ;; + no) CFLAGS="${CFLAGS} -DNO_SYSTEMD" ;; + *) AC_MSG_ERROR([bad value $withval for --with-systemd]) ;; +- esac],[LDFLAGS="`pkg-config --libs libsystemd`"]) ++ esac],[LDFLAGS="${LDFLAGS} `pkg-config --libs libsystemd`"]) + + AC_CONFIG_COMMANDS([default],[[ + if [ -n "$SOURCE_DATE_EPOCH" ] ; then +-- +2.21.0 + diff --git a/0021-improve-systemd-service-files-for-boot-session-handl.patch b/0021-improve-systemd-service-files-for-boot-session-handl.patch new file mode 100644 index 0000000..ba53b55 --- /dev/null +++ b/0021-improve-systemd-service-files-for-boot-session-handl.patch @@ -0,0 +1,130 @@ +From 77150edd697669467ff9f8775b93bd9d7a34cadf Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Mon, 28 Oct 2019 10:20:56 -0700 +Subject: [PATCH] improve systemd service files for boot session handling + +--- + etc/systemd/iscsi-mark-root-nodes | 6 +++++- + etc/systemd/iscsi-onboot.service | 15 +++++++++++++++ + etc/systemd/iscsi-shutdown.service | 1 + + etc/systemd/iscsi.service | 11 ++++------- + etc/systemd/iscsid.service | 4 +--- + etc/systemd/iscsiuio.service | 1 - + 6 files changed, 26 insertions(+), 12 deletions(-) + create mode 100644 etc/systemd/iscsi-onboot.service + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +index c693707..9d48805 100755 +--- a/etc/systemd/iscsi-mark-root-nodes ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -9,7 +9,11 @@ while read t num p target flash; do + portal=${p%,*} + transport=${t%:} + +- $ISCSIADM -m node -p $portal -T $target -o update -n node.startup -v onboot ++ # use session number to find the iface name in use ++ num=${num#[}; num=${num%]} ++ iface=$(iscsiadm -m session -r $num | grep iface.iscsi_ifacename | cut -d= -f2) ++ ++ $ISCSIADM -m node -p $portal -T $target -I $iface -o update -n node.startup -v onboot + + start_iscsid=1 + +diff --git a/etc/systemd/iscsi-onboot.service b/etc/systemd/iscsi-onboot.service +new file mode 100644 +index 0000000..42ced68 +--- /dev/null ++++ b/etc/systemd/iscsi-onboot.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Special handling of early boot iSCSI sessions ++Documentation=man:iscsiadm(8) man:iscsid(8) ++DefaultDependencies=no ++RefuseManualStart=true ++Before=iscsi.service ++After=systemd-remount-fs.service ++ConditionDirectoryNotEmpty=/sys/class/iscsi_session ++ ++[Service] ++Type=oneshot ++ExecStart=-/usr/libexec/iscsi-mark-root-nodes ++ ++[Install] ++WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi-shutdown.service b/etc/systemd/iscsi-shutdown.service +index 69c1c77..caee933 100644 +--- a/etc/systemd/iscsi-shutdown.service ++++ b/etc/systemd/iscsi-shutdown.service +@@ -11,4 +11,5 @@ RefuseManualStop=yes + [Service] + Type=oneshot + RemainAfterExit=true ++ExecStart=-/usr/bin/true + ExecStop=-/usr/sbin/iscsiadm -m node --logoutall=all +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index eadfcec..175cb2c 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -1,21 +1,18 @@ + [Unit] + Description=Login and scanning of iSCSI devices +-Documentation=man:iscsid(8) man:iscsiadm(8) ++Documentation=man:iscsiadm(8) man:iscsid(8) + DefaultDependencies=no +-Conflicts=shutdown.target +-After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target ++After=network.target network-online.target iscsid.service iscsiuio.service systemd-remount-fs.service + Wants=remote-fs-pre.target iscsi-shutdown.service +-ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes +-ConditionDirectoryNotEmpty=|/sys/class/iscsi_session ++ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes + + [Service] + Type=oneshot + RemainAfterExit=true +-ExecStart=-/usr/libexec/iscsi-mark-root-nodes + ExecStart=-/usr/sbin/iscsiadm -m node --loginall=automatic + ExecReload=-/usr/sbin/iscsiadm -m node --loginall=automatic + SuccessExitStatus=21 + + [Install] +-WantedBy=sysinit.target ++WantedBy=remote-fs.target +diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service +index 8d50cf0..28402fb 100644 +--- a/etc/systemd/iscsid.service ++++ b/etc/systemd/iscsid.service +@@ -1,8 +1,7 @@ + [Unit] + Description=Open-iSCSI +-Documentation=man:iscsid(8) man:iscsiadm(8) ++Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) + DefaultDependencies=no +-Conflicts=shutdown.target + After=network.target iscsiuio.service + Before=remote-fs-pre.target + +@@ -10,7 +9,6 @@ Before=remote-fs-pre.target + Type=notify + NotifyAccess=main + ExecStart=/usr/sbin/iscsid -f +-ExecStop=/usr/sbin/iscsiadm -k 0 2 + KillMode=mixed + Restart=on-failure + +diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service +index 8620cde..fc0be93 100644 +--- a/etc/systemd/iscsiuio.service ++++ b/etc/systemd/iscsiuio.service +@@ -2,7 +2,6 @@ + Description=iSCSI UserSpace I/O driver + Documentation=man:iscsiuio(8) + DefaultDependencies=no +-Conflicts=shutdown.target + Requires=iscsid.service + BindTo=iscsid.service + After=network.target +-- +2.21.0 + diff --git a/0021-use-Red-Hat-version-string-to-match-RPM-package-vers.patch b/0021-use-Red-Hat-version-string-to-match-RPM-package-vers.patch new file mode 100644 index 0000000..5821bcb --- /dev/null +++ b/0021-use-Red-Hat-version-string-to-match-RPM-package-vers.patch @@ -0,0 +1,25 @@ +From 58d24c239b9b6f762231ff3eedbc685971ce0a98 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 21 Jan 2013 15:43:36 -0800 +Subject: [PATCH 1/1] 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 4fa9179..c5c9e76 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.1.2" ++#define ISCSI_VERSION_STR "6.2.1.1-0" + #define ISCSI_VERSION_FILE "/sys/module/scsi_transport_iscsi/version" + + #endif +-- +2.21.1 + diff --git a/0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch b/0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch new file mode 100644 index 0000000..1c899de --- /dev/null +++ b/0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch @@ -0,0 +1,44 @@ +From a37c8753f277c156bcd4b3e7596931e3de2e67d7 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 11 Aug 2020 21:00:29 +0200 +Subject: [PATCH] iscsi_if.h replace zero-length array with flexible-array + member + +--- + include/iscsi_if.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/iscsi_if.h b/include/iscsi_if.h +index 5a1c614..e8cee0d 100644 +--- a/include/iscsi_if.h ++++ b/include/iscsi_if.h +@@ -337,7 +337,7 @@ enum iscsi_param_type { + struct iscsi_param_info { + uint32_t len; /* Actual length of the param value */ + uint16_t param; /* iscsi param */ +- uint8_t value[0]; /* length sized value follows */ ++ uint8_t value[]; /* length sized value follows */ + } __attribute__((__packed__)); + + struct iscsi_iface_param_info { +@@ -346,7 +346,7 @@ struct iscsi_iface_param_info { + uint16_t param; /* iscsi param value */ + uint8_t iface_type; /* IPv4 or IPv6 */ + uint8_t param_type; /* iscsi_param_type */ +- uint8_t value[0]; /* length sized value follows */ ++ uint8_t value[]; /* length sized value follows */ + } __attribute__((__packed__)); + + /* +@@ -723,7 +723,7 @@ enum iscsi_flashnode_param { + struct iscsi_flashnode_param_info { + uint32_t len; /* Actual length of the param */ + uint16_t param; /* iscsi param value */ +- uint8_t value[0]; /* length sized value follows */ ++ uint8_t value[]; /* length sized value follows */ + } __attribute__((__packed__)); + + enum iscsi_discovery_parent_type { +-- +2.26.2 + diff --git a/04-iscsi b/04-iscsi new file mode 100755 index 0000000..864ade7 --- /dev/null +++ b/04-iscsi @@ -0,0 +1,7 @@ +#!/bin/sh + +case "$2" in + up|vpn-up) + /bin/systemctl --no-block reload iscsi.service || : + ;; +esac diff --git a/iscsi-initiator-utils.spec b/iscsi-initiator-utils.spec new file mode 100644 index 0000000..580cf39 --- /dev/null +++ b/iscsi-initiator-utils.spec @@ -0,0 +1,622 @@ +%global open_iscsi_version 2.1 +%global open_iscsi_build 2 +%global commit0 13e7f58a1658636202994e3298237edefb985919 +%global shortcommit0 %(c=%{commit0}; echo ${c:0:7}) + +# Disable python2 build by default +%bcond_with python2 + +Summary: iSCSI daemon and utility programs +Name: iscsi-initiator-utils +Version: 6.%{open_iscsi_version}.%{open_iscsi_build} +Release: 1.git%{shortcommit0}%{?dist} +License: GPLv2+ +URL: http://www.open-iscsi.org +Source0: https://github.com/open-iscsi/open-iscsi/archive/%{commit0}.tar.gz#/open-iscsi-%{shortcommit0}.tar.gz +Source4: 04-iscsi +Source5: iscsi-tmpfiles.conf + +Patch0001: 0001-unit-file-tweaks.patch +Patch0002: 0002-idmb_rec_write-check-for-tpgt-first.patch +Patch0003: 0003-idbm_rec_write-seperate-old-and-new-style-writes.patch +Patch0004: 0004-idbw_rec_write-pick-tpgt-from-existing-record.patch +Patch0005: 0005-update-initscripts-and-docs.patch +Patch0006: 0006-use-var-for-config.patch +Patch0007: 0007-use-red-hat-for-name.patch +Patch0008: 0008-libiscsi.patch +Patch0009: 0009-Add-macros-to-release-GIL-lock.patch +Patch0010: 0010-libiscsi-introduce-sessions-API.patch +Patch0011: 0011-libiscsi-fix-discovery-request-timeout-regression.patch +Patch0012: 0012-libiscsi-format-security-build-errors.patch +Patch0013: 0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch +Patch0014: 0014-libiscsi-fix-build-against-latest-upstream-again.patch +Patch0015: 0015-remove-the-offload-boot-supported-ifdef.patch +Patch0016: 0016-Revert-iscsiadm-return-error-when-login-fails.patch +Patch0017: 0017-dont-install-scripts.patch +Patch0018: 0018-use-var-lib-iscsi-in-libopeniscsiusr.patch +Patch0019: 0019-Coverity-scan-fixes.patch +Patch0020: 0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch +Patch0021: 0021-use-Red-Hat-version-string-to-match-RPM-package-vers.patch +Patch0022: 0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch +Patch0023: 0001-stop-using-Werror-for-now.patch + +BuildRequires: flex bison doxygen kmod-devel systemd-units +BuildRequires: autoconf automake libtool libmount-devel openssl-devel +BuildRequires: isns-utils-devel +BuildRequires: systemd-devel +Requires: %{name}-iscsiuio >= %{version}-%{release} +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +# Old NetworkManager expects the dispatcher scripts in a different place +Conflicts: NetworkManager < 1.20 + +%global _hardened_build 1 +%global __provides_exclude_from ^(%{python2_sitearch}/.*\\.so|%{python3_sitearch}/.*\\.so)$ + +%description +The iscsi package provides the server daemon for the iSCSI protocol, +as well as the utility programs used to manage it. iSCSI is a protocol +for distributed disk access using SCSI commands sent over Internet +Protocol networks. + +# I don't think we're ready to expose these just yet +# For now just add the needed library to the base package + +#%%package -n libopeniscsiusr +#Summary: library providing access to Open-iSCSI initiator functionality +#Group: Development/Libraries +#License: BSD + +#%%description -n libopeniscsiusr +#The libopeniscsiusr library provides a C API for access to the Open-iSCSI +#initiator. It is used by the Open-iSCSI command line tools. + +#%%package -n libopeniscsiusr-devel +#Summary: Development files for libopeniscsiusr +#Group: Development/Libraries +#Requires: libopeniscsiusr = %%{version}-%%{release} + +#%%description -n libopeniscsiusr-devel +#The libopeniscsiusr-devel package contains libraries and header files for +#developing applications that use libopeniscsiusr. + +%package iscsiuio +Summary: Userspace configuration daemon required for some iSCSI hardware +License: BSD +Requires: %{name} = %{version}-%{release} + +%description iscsiuio +The iscsiuio configuration daemon provides network configuration help +for some iSCSI offload hardware. + +%package devel +Summary: Development files for %{name} +Requires: %{name} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + +%if %{with python2} +%package -n python2-%{name} +%{?python_provide:%python_provide python2-%{name}} +Summary: Python %{python2_version} bindings to %{name} +Requires: %{name} = %{version}-%{release} +BuildRequires: python2-devel +BuildRequires: python2-setuptools + +%description -n python2-%{name} +The %{name}-python2 package contains Python %{python2_version} bindings to the +libiscsi interface for interacting with %{name} +%endif +# ended with python2 + +%package -n python3-%{name} +%{?python_provide:%python_provide python3-%{name}} +Summary: Python %{python3_version} bindings to %{name} +Requires: %{name} = %{version}-%{release} +BuildRequires: python3-devel +BuildRequires: python3-setuptools + +%description -n python3-%{name} +The %{name}-python3 package contains Python %{python3_version} bindings to the +libiscsi interface for interacting with %{name} + +%prep +%autosetup -p1 -n open-iscsi-%{commit0} + +# change exec_prefix, there's no easy way to override +%{__sed} -i -e 's|^exec_prefix = /$|exec_prefix = %{_exec_prefix}|' Makefile + +%build +# avoid undefined references linking failures +%undefine _ld_as_needed + +# configure sub-packages from here +# letting the top level Makefile do it will lose setting from rpm +cd iscsiuio +autoreconf --install +%{configure} +cd .. + +%{__make} OPTFLAGS="%{optflags} %{?__global_ldflags}" +pushd libiscsi +%if %{with python2} +%py2_build +%endif +# ended with python2 +%py3_build +touch -r libiscsi.doxy html/* +popd + + +%install +%{__make} DESTDIR=%{?buildroot} install_programs install_doc install_etc install_libopeniscsiusr +# upstream makefile doesn't get everything the way we like it +#rm $RPM_BUILD_ROOT%%{_sbindir}/iscsi_discovery +rm $RPM_BUILD_ROOT%{_mandir}/man8/iscsi_discovery.8 +rm $RPM_BUILD_ROOT%{_mandir}/man8/iscsi_fw_login.8 +%{__install} -pm 755 usr/iscsistart $RPM_BUILD_ROOT%{_sbindir} +%{__install} -pm 644 doc/iscsistart.8 $RPM_BUILD_ROOT%{_mandir}/man8 +%{__install} -pm 644 doc/iscsi-iname.8 $RPM_BUILD_ROOT%{_mandir}/man8 +%{__install} -d $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d +%{__install} -pm 644 iscsiuio/iscsiuiolog $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d + +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/nodes +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/send_targets +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/static +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/isns +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/slp +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/ifaces + +# for %%ghost +%{__install} -d $RPM_BUILD_ROOT%{_rundir}/lock/iscsi +touch $RPM_BUILD_ROOT%{_rundir}/lock/iscsi/lock + + +%{__install} -d $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsi.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsi-init.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsi-shutdown.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsid.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsid.socket $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsiuio.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsiuio.socket $RPM_BUILD_ROOT%{_unitdir} + +%{__install} -d $RPM_BUILD_ROOT%{_libexecdir} +%{__install} -pm 755 etc/systemd/iscsi-mark-root-nodes $RPM_BUILD_ROOT%{_libexecdir} + +%{__install} -d $RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d +%{__install} -pm 755 %{SOURCE4} $RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d + +%{__install} -d $RPM_BUILD_ROOT%{_tmpfilesdir} +%{__install} -pm 644 %{SOURCE5} $RPM_BUILD_ROOT%{_tmpfilesdir}/iscsi.conf + +%{__install} -d $RPM_BUILD_ROOT%{_libdir} +%{__install} -pm 755 libiscsi/libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir} +%{__ln_s} libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir}/libiscsi.so +%{__install} -d $RPM_BUILD_ROOT%{_includedir} +%{__install} -pm 644 libiscsi/libiscsi.h $RPM_BUILD_ROOT%{_includedir} + +%if %{with python2} +%{__install} -d $RPM_BUILD_ROOT%{python2_sitearch} +%endif +# ended with python2 +%{__install} -d $RPM_BUILD_ROOT%{python3_sitearch} +pushd libiscsi +%if %{with python2} +%py2_install +%endif +# ended with python2 +%py3_install +popd + + +%post +%systemd_post iscsi.service iscsi-shutdown.service iscsid.service iscsid.socket + +%post iscsiuio +%systemd_post iscsiuio.service iscsiuio.socket + +%preun +%systemd_preun iscsi.service iscsi-shutdown.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket + +%preun iscsiuio +%systemd_preun iscsiuio.service iscsiuio.socket + +%postun +%systemd_postun iscsi.service iscsi-shutdown.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket + +%postun iscsiuio +%systemd_postun iscsiuio.service iscsiuio.socket + +%triggerun -- iscsi-initiator-utils < 6.2.0.873-25 +# prior to 6.2.0.873-24 iscsi.service was missing a Wants=remote-fs-pre.target +# this forces remote-fs-pre.target active if needed for a clean shutdown/reboot +# after upgrading this package +if [ $1 -gt 0 ]; then + /usr/bin/systemctl -q is-active iscsi.service + if [ $? -eq 0 ]; then + /usr/bin/systemctl -q is-active remote-fs-pre.target + if [ $? -ne 0 ]; then + SRC=`/usr/bin/systemctl show --property FragmentPath remote-fs-pre.target | cut -d= -f2` + DST=/run/systemd/system/remote-fs-pre.target + if [ $SRC != $DST ]; then + cp $SRC $DST + fi + sed -i 's/RefuseManualStart=yes/RefuseManualStart=no/' $DST + /usr/bin/systemctl daemon-reload >/dev/null 2>&1 || : + /usr/bin/systemctl start remote-fs-pre.target >/dev/null 2>&1 || : + fi + fi +fi +# added in 6.2.0.873-25 +if [ $1 -gt 0 ]; then + systemctl start iscsi-shutdown.service >/dev/null 2>&1 || : +fi + + +%files +%doc README +%dir %{_sharedstatedir}/iscsi +%dir %{_sharedstatedir}/iscsi/nodes +%dir %{_sharedstatedir}/iscsi/isns +%dir %{_sharedstatedir}/iscsi/static +%dir %{_sharedstatedir}/iscsi/slp +%dir %{_sharedstatedir}/iscsi/ifaces +%dir %{_sharedstatedir}/iscsi/send_targets +%ghost %{_rundir}/lock/iscsi +%{_unitdir}/iscsi.service +%{_unitdir}/iscsi-init.service +%{_unitdir}/iscsi-shutdown.service +%{_unitdir}/iscsid.service +%{_unitdir}/iscsid.socket +%{_libexecdir}/iscsi-mark-root-nodes +%{_prefix}/lib/NetworkManager +%{_tmpfilesdir}/iscsi.conf +%dir %{_sysconfdir}/iscsi +%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/iscsi/iscsid.conf +%{_sbindir}/iscsi-iname +%{_sbindir}/iscsiadm +%{_sbindir}/iscsid +%{_sbindir}/iscsistart +%{_libdir}/libiscsi.so.0 +%{_mandir}/man8/iscsi-iname.8.gz +%{_mandir}/man8/iscsiadm.8.gz +%{_mandir}/man8/iscsid.8.gz +%{_mandir}/man8/iscsistart.8.gz +# until we decide to setup libopeniscsiusr as a subpkg for real +%{_libdir}/libopeniscsiusr.so.* +%exclude %{_libdir}/libopeniscsiusr.so +%exclude %{_includedir}/libopeniscsiusr.h +%exclude %{_includedir}/libopeniscsiusr_common.h +%exclude %{_includedir}/libopeniscsiusr_iface.h +%exclude %{_includedir}/libopeniscsiusr_node.h +%exclude %{_includedir}/libopeniscsiusr_session.h +%exclude %{_libdir}/pkgconfig/libopeniscsiusr.pc + +# %%files -n libopeniscsiusr +# %%{_libdir}/libopeniscsiusr.so.* +# +# %%files -n libopeniscsiusr-devel +# %%{_libdir}/libopeniscsiusr.so +# %%{_includedir}/libopeniscsiusr.h +# %%{_includedir}/libopeniscsiusr_common.h +# %%{_includedir}/libopeniscsiusr_iface.h +# %%{_includedir}/libopeniscsiusr_session.h +# %%{_libdir}/pkgconfig/libopeniscsiusr.pc + +%files iscsiuio +%{_sbindir}/iscsiuio +%{_unitdir}/iscsiuio.service +%{_unitdir}/iscsiuio.socket +%config(noreplace) %{_sysconfdir}/logrotate.d/iscsiuiolog +%{_mandir}/man8/iscsiuio.8.gz + +%files devel +%doc libiscsi/html +%{_libdir}/libiscsi.so +%{_includedir}/libiscsi.h + +%if %{with python2} +%files -n python2-%{name} +%{python2_sitearch}/* +%endif +# ended with python2 + +%files -n python3-%{name} +%{python3_sitearch}/* + +%changelog +* Mon Sep 21 2020 Chris Leech - 6.2.1.2-1.git13e7f58 +- iscsiadm overflow regression when discovering many targets at once +- check for invalid session id during stop connection +- add ability to attempt target logins asynchronously + +* Tue Aug 11 2020 Christian Glombek - 6.2.1.2-0.git802688d +- Update to upstream v2.1.2 +- Remove systemctl enable calls, as this is now handled by Fedora presets +- per the guidelines +- Remove initiator name generation, as this is now handled by an init service +- Install ghost lockfile and dir to /run instead of /var +- Rebased/fixed up patches +- Fixed macros in comments and comments after macros +- Merged service-file-tweaks.patch and +- improve-systemd-service-files-for-boot-session-handl.patch +- into unit-file-tweaks.patch +- Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1493296 +- Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1729740 +- Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1834509 + +* Tue Jul 28 2020 Fedora Release Engineering - 6.2.1.1-0.gitac87641.2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue May 26 2020 Miro Hrončok - 6.2.1.1-0.gitac87641.1 +- Rebuilt for Python 3.9 + +* Mon Mar 02 2020 Chris Leech - 6.2.1.1-0.gitac87641 +- rebase to new upstream v2.1.1 +- enhanced CHAP options are now a configuration to deal with broken targets (#1774746) + +* Sun Mar 01 2020 Adam Williamson - 6.2.1.0-2.git4440e57 +- Backport upstream d3daa7a2 to fix bz #1774746 + +* Mon Feb 24 2020 Than Ngo - 6.2.1.0-1.git4440e57 +- upstream patch to support gcc -fno-common option + +* Wed Jan 29 2020 Fedora Release Engineering - 6.2.1.0-0.git4440e57.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Tue Nov 19 2019 Chris Leech - 6.2.1.0-0.git4440e57 +- update to upstream v2.1.0 + +* Thu Aug 22 2019 Lubomir Rintel - 6.2.0.876-12.gitf3c8e90 +- Move the NetworkManager dispatcher script out of /etc + +* Mon Aug 19 2019 Miro Hrončok - 6.2.0.876-11.gitf3c8e90 +- Rebuilt for Python 3.8 + +* Thu Jul 25 2019 Fedora Release Engineering - 6.2.0.876-10.gitf3c8e90 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Thu May 30 2019 Chris Leech - 6.2.0.876-9.gitf3c8e90 +- FTBFS: %%systemd_postun scriptlets need service files as an argument + +* Tue Feb 12 2019 Igor Gnatenko - 6.2.0.876-8.gitf3c8e90 +- Remove obsolete scriptlets + +* Fri Feb 01 2019 Fedora Release Engineering - 6.2.0.876-7.gitf3c8e90 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Thu Jan 10 2019 Miro Hrončok - 6.2.0.876-6.gitf3c8e90 +- Disable python2 build + +* Tue Jul 10 2018 Chris Leech - 6.2.0.876-5.gitf3c8e90 +- iscsiuio: add mutex to protect netlink buffer for pass-through xmit +- iscsid: get gateway information from sysfs when recovering sessions +- enabled MaxOustandingR2T negotiation during login + +* Mon Jun 25 2018 Adam Williamson - 6.2.0.876-4.git4ef9261 +- Rebuilt for Python 3.7, again + +* Mon Jun 25 2018 Adam Williamson - 6.2.0.876-3.git4ef9261 +- Link libiscsi against libopeniscsiusr (bz #1594946) (python 3.6 build) + +* Wed Jun 20 2018 Miro Hrončok - 6.2.0.876-2.git4ef9261 +- Rebuilt for Python 3.7 + +* Tue Jun 19 2018 Chris Leech - 6.2.0.876-1.git4ef9261 +- pull in post 2.0.876 tagged fixes from upstream git +- minimal packaging of libopeniscsiusr (internal use only, no dev package yet) +- Conditionalize the python2 subpackage [Charalampos Stratakis ] + +* Tue Jun 19 2018 Chris Leech - 6.2.0.876-1.git24580ad +- rebase to upstream 2.0.876 + +* Tue Jun 19 2018 Miro Hrončok - 6.2.0.874-10.git86e8892 +- Rebuilt for Python 3.7 + +* Wed Feb 07 2018 Fedora Release Engineering - 6.2.0.874-9.git86e8892 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Fri Jan 05 2018 Iryna Shcherbina - 6.2.0.874-8.git86e8892 +- Update Python 2 dependency declarations to new packaging standards + (See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3) + +* Sat Aug 19 2017 Zbigniew Jędrzejewski-Szmek - 6.2.0.874-7.git86e8892 +- Python 2 binary package renamed to python2-iscsi-initiator-utils + See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3 + +* Wed Aug 02 2017 Fedora Release Engineering - 6.2.0.874-6.git86e8892 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 6.2.0.874-5.git86e8892 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Apr 12 2017 Chris Leech - 6.2.0.874-4.git86e8892 +- rebuild to use shared libisns + +* Tue Feb 28 2017 Chris Leech - 6.2.0.874-3.git86e8892 +- libiscsi: fix discovery command timeout regression +- libiscsi: fix format security build errors + +* Thu Feb 16 2017 Chris Leech - 6.2.0.874-2.git86e8892 +- fix regression with iscsiadm discoverydb commands having a 0 timeout + +* Thu Feb 09 2017 Chris Leech - 6.2.0.874-1 +- update to 2.0.874 + +* Mon Dec 12 2016 Charalampos Stratakis - 6.2.0.873-35.git4c1f2d9 +- Rebuild for Python 3.6 + +* Tue Jul 19 2016 Fedora Release Engineering - 6.2.0.873-34.git4c1f2d9 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Fri Feb 19 2016 Chris Leech - 6.2.0.873-33.git4c1f2d9 +- sync with upstream +- sysfs handling changes to speed up operations over large number of sessions + +* Thu Feb 04 2016 Fedora Release Engineering - 6.2.0.873-32.git4c9d6f9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Feb 3 2016 Michael Schwendt - 6.2.0.873-31.git4c9d6f9 +- BuildRequires: isns-utils-static for -lisns (bz #1291913) + +* Tue Nov 03 2015 Robert Kuska - 6.2.0.873-30.git4c9d6f9 +- Rebuilt for Python3.5 rebuild + +* Tue Oct 06 2015 Chris Leech - 6.2.0.873-29.git4c9d6f9 +- rebase with upstream, change Source0 url to github +- build with external isns-utils + +* Mon Oct 05 2015 Chris Leech - 6.2.0.873-28.git6aa2c9b +- fixed broken multiple trigger scripts, removed old pre-systemd migration triggers +- added libiscsi session API patch (bz #1262279) + +* Wed Jun 17 2015 Fedora Release Engineering - 6.2.0.873-27.git6aa2c9b +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Wed Jun 10 2015 Chris Leech - 6.2.0.873-26.git6aa2c9b +- rebase to upstream snapshot +- add patch to improve GIL lock performance in libiscsi +- Split Python 2 and Python 3 bindings out into subpackages + +* Wed Jan 28 2015 Chris Leech - 6.2.0.873-25.gitc9d830b +- split out session logout on shutdown to a separate service +- 985321 roll up libiscsi patches, update python bindings to support python3 +- scriptlets were never split out properly for the iscsiuio subpackage +- fix regression in network interface binding +- created iscsi-shutdown.service to ensure that session cleanup happens +- Add --with-slp=no +- segfault from unexpected netlink event during discovery +- inhibit strict aliasing optimizations in iscsiuio, rpmdiff error + +* Thu Oct 23 2014 Chris Leech - 6.2.0.873-24.gitc9d830b +- sync with upstream v2.0.873-84-gc9d830b +- ignore iscsiadm return in iscsi.service +- make sure systemd order against remote mounts is correct +- add discovery as a valid mode in iscsiadm.8 +- make sure to pass --with-security=no to isns configure + +* Sat Aug 16 2014 Fedora Release Engineering - 6.2.0.873-23 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 6.2.0.873-22 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Mon Apr 14 2014 Chris Leech - 6.2.0.873-21 +- boot session handling improvements +- split out iscsiuio into a seperate sub-package +- sync with new upstream additions +- revert change to return code when calling login_portal for sessions + that already exist, as it impacts users scripting around iscsiadm + +* Tue Dec 10 2013 Chris Leech - 6.2.0.873-17 +- fix regression in glob use, inappropriate error code escape +- clean up dead node links from discovery when reusing tpgt + +* Mon Nov 25 2013 Chris Leech - 6.2.0.873-16 +- fix iscsiuio socket activation +- have systemd start socket units on iscsiadm use, if not already listening + +* Sun Sep 15 2013 Chris Leech - 6.2.0.873-15 +- move /sbin to /usr/sbin +- use rpm macros in install rules + +* Fri Sep 13 2013 Chris Leech - 6.2.0.873-14 +- fix iscsiuio hardened build and other compiler flags + +* Fri Aug 23 2013 Andy Grover - 6.2.0.873-13 +- Fix patch 0041 to check session != NULL before calling iscsi_sysfs_read_boot() + +* Tue Aug 20 2013 Chris Leech - 6.2.0.873-12 +- fix regression in last build, database records can't be accessed + +* Mon Aug 19 2013 Chris Leech - 6.2.0.873-11 +- iscsi boot related fixes + 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 + remove patches related to running iscsid from initrd, possible to revisit later + +* Sun Aug 18 2013 Chris Leech - 6.2.0.873-10 +- sync with upstream git, minor context fixes after rebase of out-of-tree patches +- iscsiuio is merged upstream, remove old source archive and patches +- spec cleanups to fix rpmlint issues + +* Sun Aug 4 2013 Peter Robinson 6.2.0.873-9 +- Fix FTBFS, cleanup spec + +* Sat Aug 03 2013 Fedora Release Engineering - 6.2.0.873-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Tue Jun 11 2013 Chris Leech - 6.2.0.873-7 +- Use the systemd tmpfiles service to recreate lockfiles in /var/lock +- 955167 build as a position independent executable +- 894576 fix order of setuid/setgid and drop additional groups + +* Tue May 28 2013 Chris Leech - 6.2.0.873-6 +- Don't have iscsiadm scan for autostart record if node db is empty (bug #951951) + +* Tue Apr 30 2013 Orion Poplawski - 6.2.0.873-5 +- Fix typo in NM dispatcher script (bug #917058) + +* Thu Feb 21 2013 Chris Leech - 6.2.0.873-4 +- build with libkmod support, instead of calling out to modprobe +- enable socket activation by default + +* Thu Jan 24 2013 Kalev Lember - 6.2.0.873-3 +- Fix the postun script to not use ldconfig as the interpreter + +* Wed Jan 23 2013 Chris Leech - 6.2.0.873-2 +- package iscsi_mark_root_nodes script, it's being referenced by the unit files + +* Tue Jan 22 2013 Chris Leech - 6.2.0.873-1 +- rebase to new upstream code +- systemd conversion +- 565245 Fix multilib issues caused by timestamp in doxygen footers + +* Thu Jul 19 2012 Fedora Release Engineering - 6.2.0.872-19 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Feb 14 2012 Mike Christie 6.2.0.872.18 +- 789683 Fix boot slow down when the iscsi service is started + (regression added in 6.2.0.872.16 when the nm wait was added). + +* Mon Feb 6 2012 Mike Christie 6.2.0.872.17 +- 786174 Change iscsid/iscsi service startup, so it always starts + when called. + +* Sat Feb 4 2012 Mike Christie 6.2.0.872.16 +- 747479 Fix iscsidevs handling of network requirement + +* Fri Jan 13 2012 Fedora Release Engineering - 6.2.0.872-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Nov 30 2011 Mike Christie 6.2.0.872.14 +- Fix version string to reflect fedora and not rhel. + +* Tue Oct 18 2011 Mike Christie 6.2.0.872.13 +- Update iscsi tools. + +* Sat Apr 30 2011 Hans de Goede - 6.2.0.872-12 +- Change iscsi init scripts to check for networking being actually up, rather + then for NetworkManager being started (#692230) + +* Tue Apr 26 2011 Hans de Goede - 6.2.0.872-11 +- Fix iscsid autostarting when upgrading from an older version + (add iscsid.startup key to iscsid.conf on upgrade) +- Fix printing of [ OK ] when successfully stopping iscsid +- systemd related fixes: + - Add Should-Start/Stop tgtd to iscsi init script to fix (re)boot from + hanging when using locally hosted targets + - %%ghost /var/lock/iscsi and contents (#656605) + +* Mon Apr 25 2011 Mike Christie 6.2.0.872-10 +- Fix iscsi init scripts check for networking being up (#692230) + +* Wed Feb 09 2011 Fedora Release Engineering - 6.2.0.872-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild diff --git a/iscsi-tmpfiles.conf b/iscsi-tmpfiles.conf new file mode 100644 index 0000000..eab4fb2 --- /dev/null +++ b/iscsi-tmpfiles.conf @@ -0,0 +1,2 @@ +d /run/lock/iscsi 0700 root root - +f /run/lock/iscsi/lock 0600 root root - diff --git a/sources b/sources new file mode 100644 index 0000000..6023c6a --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (open-iscsi-13e7f58.tar.gz) = baaf1b69c6e2da24684458bd3042dae07dcaa415b0b4c44d2b5b9076f17871f7c430e6f515a18ea439ee02da7d76af25fee82a9e88196eea59cce88979b5bc9b