"Fossies" - the Fresh Open Source Software Archive

Member "open-iscsi-2.0.878/usr/idbm.c" (12 Sep 2019, 87010 Bytes) of package /linux/misc/open-iscsi-2.0.878.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "idbm.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.0.877_vs_2.0.878.

    1 /*
    2  * iSCSI Discovery Database Library
    3  *
    4  * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
    5  * Copyright (C) 2006 Mike Christie
    6  * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
    7  * maintained by open-iscsi@@googlegroups.com
    8  *
    9  * This program is free software; you can redistribute it and/or modify
   10  * it under the terms of the GNU General Public License as published
   11  * by the Free Software Foundation; either version 2 of the License, or
   12  * (at your option) any later version.
   13  *
   14  * This program is distributed in the hope that it will be useful, but
   15  * WITHOUT ANY WARRANTY; without even the implied warranty of
   16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   17  * General Public License for more details.
   18  *
   19  * See the file COPYING included with this distribution for more details.
   20  */
   21 
   22 #include <stdio.h>
   23 #include <ctype.h>
   24 #include <unistd.h>
   25 #include <stdlib.h>
   26 #include <string.h>
   27 #include <errno.h>
   28 #include <dirent.h>
   29 #include <limits.h>
   30 #include <fcntl.h>
   31 #include <sys/stat.h>
   32 #include <sys/file.h>
   33 #include <inttypes.h>
   34 
   35 #include "idbm.h"
   36 #include "idbm_fields.h"
   37 #include "log.h"
   38 #include "iscsi_util.h"
   39 #include "iscsi_settings.h"
   40 #include "transport.h"
   41 #include "iscsi_sysfs.h"
   42 #include "iface.h"
   43 #include "sysdeps.h"
   44 #include "fw_context.h"
   45 #include "iscsi_err.h"
   46 
   47 #define IDBM_HIDE   0    /* Hide parameter when print. */
   48 #define IDBM_SHOW   1    /* Show parameter when print. */
   49 #define IDBM_MASKED 2    /* Show "stars" instead of real value when print */
   50 
   51 static struct idbm *db;
   52 
   53 #define __recinfo_str(_key, _info, _rec, _name, _show, _n, _mod) do { \
   54     _info[_n].type = TYPE_STR; \
   55     strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
   56     if (strlen((char*)_rec->_name)) \
   57         strlcpy((char*)_info[_n].value, (char*)_rec->_name, \
   58             VALUE_MAXVAL); \
   59     _info[_n].data = &_rec->_name; \
   60     _info[_n].data_len = sizeof(_rec->_name); \
   61     _info[_n].visible = _show; \
   62     _info[_n].can_modify = _mod; \
   63     _n++; \
   64 } while(0)
   65 
   66 #define __recinfo_int(_key, _info, _rec, _name, _show, _n, _mod) do { \
   67     _info[_n].type = TYPE_INT; \
   68     strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
   69     snprintf(_info[_n].value, VALUE_MAXVAL, "%" PRIi32, _rec->_name); \
   70     _info[_n].data = &_rec->_name; \
   71     _info[_n].data_len = sizeof(_rec->_name); \
   72     _info[_n].visible = _show; \
   73     _info[_n].can_modify = _mod; \
   74     _n++; \
   75 } while(0)
   76 
   77 #define __recinfo_uint8(_key, _info, _rec, _name, _show, _n, _mod) do { \
   78     _info[_n].type = TYPE_UINT8; \
   79     strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
   80     snprintf(_info[_n].value, VALUE_MAXVAL, "%" PRIu8, _rec->_name); \
   81     _info[_n].data = &_rec->_name; \
   82     _info[_n].data_len = sizeof(_rec->_name); \
   83     _info[_n].visible = _show; \
   84     _info[_n].can_modify = _mod; \
   85     _n++; \
   86 } while (0)
   87 
   88 #define __recinfo_uint16(_key, _info, _rec, _name, _show, _n, _mod) do { \
   89     _info[_n].type = TYPE_UINT16; \
   90     strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
   91     snprintf(_info[_n].value, VALUE_MAXVAL, "%" PRIu16, _rec->_name); \
   92     _info[_n].data = &_rec->_name; \
   93     _info[_n].data_len = sizeof(_rec->_name); \
   94     _info[_n].visible = _show; \
   95     _info[_n].can_modify = _mod; \
   96     _n++; \
   97 } while (0)
   98 
   99 #define __recinfo_uint32(_key, _info, _rec, _name, _show, _n, _mod) do { \
  100     _info[_n].type = TYPE_UINT32; \
  101     strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
  102     snprintf(_info[_n].value, VALUE_MAXVAL, "%" PRIu32, _rec->_name); \
  103     _info[_n].data = &_rec->_name; \
  104     _info[_n].data_len = sizeof(_rec->_name); \
  105     _info[_n].visible = _show; \
  106     _info[_n].can_modify = _mod; \
  107     _n++; \
  108 } while (0)
  109 
  110 #define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \
  111     _info[_n].type = TYPE_INT_O; \
  112     strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
  113     if (_rec->_name == 0) strlcpy(_info[_n].value, _op0, VALUE_MAXVAL); \
  114     if (_rec->_name == 1) strlcpy(_info[_n].value, _op1, VALUE_MAXVAL); \
  115     _info[_n].data = &_rec->_name; \
  116     _info[_n].data_len = sizeof(_rec->_name); \
  117     _info[_n].visible = _show; \
  118     _info[_n].opts[0] = _op0; \
  119     _info[_n].opts[1] = _op1; \
  120     _info[_n].numopts = 2; \
  121     _info[_n].can_modify = _mod; \
  122     _n++; \
  123 } while(0)
  124 
  125 #define __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, \
  126              _mod) do { \
  127     __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod); \
  128     _n--; \
  129     if (_rec->_name == 2) strlcpy(_info[_n].value, _op2, VALUE_MAXVAL);\
  130     _info[_n].opts[2] = _op2; \
  131     _info[_n].numopts = 3; \
  132     _n++; \
  133 } while(0)
  134 
  135 #define __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n, \
  136              _mod) do { \
  137     __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, _mod); \
  138     _n--; \
  139     if (_rec->_name == 3) strlcpy(_info[_n].value, _op3, VALUE_MAXVAL); \
  140     _info[_n].opts[3] = _op3; \
  141     _info[_n].numopts = 4; \
  142     _n++; \
  143 } while(0)
  144 
  145 #define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
  146              _op4,_n, _mod) do { \
  147     __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
  148               _n,_mod); \
  149     _n--; \
  150     if (_rec->_name == 4) strlcpy(_info[_n].value, _op4, VALUE_MAXVAL); \
  151     _info[_n].opts[4] = _op4; \
  152     _info[_n].numopts = 5; \
  153     _n++; \
  154 } while(0)
  155 
  156 #define __recinfo_int_o6(_key,_info,_rec,_name,_show,_op0,_op1,_op2, \
  157              _op3,_op4,_op5,_n,_mod) do { \
  158     __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
  159              _op4,_n,_mod); \
  160     _n--; \
  161     if (_rec->_name == 5) strlcpy(_info[_n].value, _op5, VALUE_MAXVAL); \
  162     _info[_n].opts[5] = _op5; \
  163     _info[_n].numopts = 6; \
  164     _n++; \
  165 } while(0)
  166 
  167 static void
  168 idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri)
  169 {
  170     int num = 0;
  171 
  172     __recinfo_int_o2(DISC_STARTUP, ri, r, startup, IDBM_SHOW,
  173             "manual", "automatic", num, 1);
  174     __recinfo_int_o6(DISC_TYPE, ri, r, type, IDBM_SHOW,
  175             "sendtargets", "isns", "offload_send_targets", "slp",
  176             "static", "fw", num, 0);
  177     switch (r->type) {
  178     case DISCOVERY_TYPE_SENDTARGETS:
  179         __recinfo_str(DISC_ST_ADDR, ri, r,
  180             address, IDBM_SHOW, num, 0);
  181         __recinfo_int(DISC_ST_PORT, ri, r,
  182             port, IDBM_SHOW, num, 0);
  183         __recinfo_int_o2(DISC_ST_AUTH_METHOD, ri, r,
  184             u.sendtargets.auth.authmethod,
  185             IDBM_SHOW, "None", "CHAP", num, 1);
  186         __recinfo_str(DISC_ST_USERNAME, ri, r,
  187             u.sendtargets.auth.username, IDBM_SHOW, num, 1);
  188         __recinfo_str(DISC_ST_PASSWORD, ri, r,
  189             u.sendtargets.auth.password, IDBM_MASKED, num, 1);
  190         __recinfo_int(DISC_ST_PASSWORD_LEN, ri, r,
  191             u.sendtargets.auth.password_length, IDBM_HIDE, num, 1);
  192         __recinfo_str(DISC_ST_USERNAME_IN, ri, r,
  193             u.sendtargets.auth.username_in, IDBM_SHOW, num, 1);
  194         __recinfo_str(DISC_ST_PASSWORD_IN, ri, r,
  195             u.sendtargets.auth.password_in, IDBM_MASKED, num, 1);
  196         __recinfo_int(DISC_ST_PASSWORD_IN_LEN, ri, r,
  197             u.sendtargets.auth.password_in_length, IDBM_HIDE,
  198             num, 1);
  199         __recinfo_int(DISC_ST_LOGIN_TMO, ri, r,
  200             u.sendtargets.conn_timeo.login_timeout,
  201             IDBM_SHOW, num, 1);
  202         __recinfo_int_o2(DISC_ST_USE_DISC_DAEMON, ri, r,
  203             u.sendtargets.use_discoveryd,
  204             IDBM_SHOW, "No", "Yes", num, 1);
  205         __recinfo_int(DISC_ST_DISC_DAEMON_POLL_INVAL, ri, r,
  206             u.sendtargets.discoveryd_poll_inval,
  207             IDBM_SHOW, num, 1);
  208         __recinfo_int(DISC_ST_REOPEN_MAX, ri, r,
  209             u.sendtargets.reopen_max,
  210             IDBM_SHOW, num, 1);
  211         __recinfo_int(DISC_ST_AUTH_TMO, ri, r,
  212             u.sendtargets.conn_timeo.auth_timeout,
  213             IDBM_SHOW, num, 1);
  214         __recinfo_int(DISC_ST_ACTIVE_TMO, ri, r,
  215                   u.sendtargets.conn_timeo.active_timeout,
  216                   IDBM_SHOW, num, 1);
  217         __recinfo_int(DISC_ST_MAX_RECV_DLEN, ri, r,
  218                   u.sendtargets.conn_conf.MaxRecvDataSegmentLength,
  219                   IDBM_SHOW, num, 1);
  220         break;
  221     case DISCOVERY_TYPE_ISNS:
  222         __recinfo_str(DISC_ISNS_ADDR, ri, r,
  223             address, IDBM_SHOW, num, 0);
  224         __recinfo_int(DISC_ISNS_PORT, ri, r,
  225             port, IDBM_SHOW, num, 0);
  226         __recinfo_int_o2(DISC_ISNS_USE_DISC_DAEMON, ri, r,
  227             u.isns.use_discoveryd,
  228             IDBM_SHOW, "No", "Yes", num, 1);
  229         __recinfo_int(DISC_ISNS_DISC_DAEMON_POLL_INVAL, ri, r,
  230             u.isns.discoveryd_poll_inval,
  231             IDBM_SHOW, num, 1);
  232         break;
  233     default:
  234         break;
  235     }
  236 }
  237 
  238 void
  239 idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
  240 {
  241     int num = 0, i;
  242     int iface_type;
  243 
  244     iface_type = iface_get_iptype(&r->iface);
  245 
  246     __recinfo_str(NODE_NAME, ri, r, name, IDBM_SHOW, num, 0);
  247     __recinfo_int(NODE_TPGT, ri, r, tpgt, IDBM_SHOW, num, 0);
  248     __recinfo_int_o3(NODE_STARTUP, ri, r, startup,
  249             IDBM_SHOW, "manual", "automatic", "onboot", num, 1);
  250     __recinfo_int_o2(NODE_LEADING_LOGIN, ri, r, leading_login, IDBM_SHOW,
  251              "No", "Yes", num, 1);
  252     /*
  253      * Note: because we do not add the iface.iscsi_ifacename to
  254      * sysfs iscsiadm does some weird matching. We can change the iface
  255      * values if a session is not running, but node record ifaces values
  256      * have to be changed and so do the iface record ones.
  257      *
  258      * Users should nornmally not want to change the iface ones
  259      * in the node record directly and instead do it through
  260      * the iface mode which will do the right thing (although that
  261      * needs some locking).
  262      */
  263     __recinfo_str(IFACE_HWADDR, ri, r, iface.hwaddress, IDBM_SHOW, num, 1);
  264     __recinfo_str(IFACE_IPADDR, ri, r, iface.ipaddress, IDBM_SHOW, num, 1);
  265     __recinfo_str(IFACE_ISCSINAME, ri, r, iface.name, IDBM_SHOW, num, 1);
  266     __recinfo_str(IFACE_NETNAME, ri, r, iface.netdev, IDBM_SHOW, num, 1);
  267     __recinfo_str(IFACE_GATEWAY, ri, r, iface.gateway, IDBM_SHOW, num, 1);
  268     __recinfo_str(IFACE_SUBNET_MASK, ri, r, iface.subnet_mask, IDBM_SHOW, num, 1);
  269     __recinfo_uint8(IFACE_PREFIX_LEN, ri, r, iface.prefix_len,
  270             IDBM_SHOW, num, 1);
  271     /*
  272      * svn 780 compat: older versions used node.transport_name and
  273      * rec->transport_name
  274      */
  275     __recinfo_str(IFACE_TRANSPORTNAME, ri, r, iface.transport_name,
  276               IDBM_SHOW, num, 1);
  277     __recinfo_str(IFACE_INAME, ri, r, iface.iname, IDBM_SHOW, num, 1);
  278     __recinfo_str(IFACE_STATE, ri, r, iface.state, IDBM_SHOW, num, 1);
  279     __recinfo_uint16(IFACE_VLAN_ID, ri, r, iface.vlan_id, IDBM_SHOW, num,
  280              1);
  281     __recinfo_uint8(IFACE_VLAN_PRIORITY, ri, r, iface.vlan_priority,
  282             IDBM_SHOW, num, 1);
  283     __recinfo_str(IFACE_VLAN_STATE, ri, r, iface.vlan_state, IDBM_SHOW,
  284               num, 1);
  285     __recinfo_int(IFACE_NUM, ri, r, iface.iface_num, IDBM_SHOW, num, 1);
  286     __recinfo_uint16(IFACE_MTU, ri, r, iface.mtu, IDBM_SHOW, num, 1);
  287     __recinfo_uint16(IFACE_PORT, ri, r, iface.port, IDBM_SHOW, num, 1);
  288 
  289     if (iface_type == ISCSI_IFACE_TYPE_IPV4) {
  290         __recinfo_str(IFACE_BOOT_PROTO, ri, r, iface.bootproto,
  291                   IDBM_SHOW, num, 1);
  292         __recinfo_str(IFACE_DHCP_ALT_CID, ri, r,
  293                   iface.dhcp_alt_client_id_state, IDBM_SHOW,
  294                   num, 1);
  295         __recinfo_str(IFACE_DHCP_ALT_CID_STR, ri, r,
  296                   iface.dhcp_alt_client_id, IDBM_SHOW, num, 1);
  297         __recinfo_str(IFACE_DHCP_DNS, ri, r, iface.dhcp_dns, IDBM_SHOW,
  298                   num, 1);
  299         __recinfo_str(IFACE_DHCP_LEARN_IQN, ri, r,
  300                   iface.dhcp_learn_iqn, IDBM_SHOW, num, 1);
  301         __recinfo_str(IFACE_DHCP_REQ_VID, ri, r,
  302                   iface.dhcp_req_vendor_id_state, IDBM_SHOW,
  303                   num, 1);
  304         __recinfo_str(IFACE_DHCP_VID, ri, r, iface.dhcp_vendor_id_state,
  305                   IDBM_SHOW, num, 1);
  306         __recinfo_str(IFACE_DHCP_VID_STR, ri, r, iface.dhcp_vendor_id,
  307                   IDBM_SHOW, num, 1);
  308         __recinfo_str(IFACE_DHCP_SLP_DA, ri, r, iface.dhcp_slp_da,
  309                   IDBM_SHOW, num, 1);
  310         __recinfo_str(IFACE_FRAGMENTATION, ri, r, iface.fragmentation,
  311                   IDBM_SHOW, num, 1);
  312         __recinfo_str(IFACE_GRAT_ARP, ri, r, iface.gratuitous_arp,
  313                   IDBM_SHOW, num, 1);
  314         __recinfo_str(IFACE_IN_FORWARD, ri, r,
  315                   iface.incoming_forwarding, IDBM_SHOW, num, 1);
  316         __recinfo_str(IFACE_TOS_STATE, ri, r, iface.tos_state,
  317                   IDBM_SHOW, num, 1);
  318         __recinfo_uint8(IFACE_TOS, ri, r, iface.tos, IDBM_SHOW, num, 1);
  319         __recinfo_uint8(IFACE_TTL, ri, r, iface.ttl, IDBM_SHOW, num, 1);
  320     } else if (iface_type == ISCSI_IFACE_TYPE_IPV6) {
  321         __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, iface.ipv6_autocfg,
  322                   IDBM_SHOW, num, 1);
  323         __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r,
  324                   iface.linklocal_autocfg, IDBM_SHOW, num, 1);
  325         __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, iface.router_autocfg,
  326                   IDBM_SHOW, num, 1);
  327         __recinfo_str(IFACE_LINKLOCAL, ri, r, iface.ipv6_linklocal,
  328                   IDBM_SHOW, num, 1);
  329         __recinfo_str(IFACE_ROUTER, ri, r, iface.ipv6_router,
  330                   IDBM_SHOW, num, 1);
  331         __recinfo_uint8(IFACE_DUP_ADDR_DETECT_CNT, ri, r,
  332                 iface.dup_addr_detect_cnt, IDBM_SHOW, num, 1);
  333         __recinfo_uint32(IFACE_FLOW_LABEL, ri, r, iface.flow_label,
  334                  IDBM_SHOW, num, 1);
  335         __recinfo_str(IFACE_GRAT_NEIGHBOR_ADV, ri, r,
  336                   iface.gratuitous_neighbor_adv, IDBM_SHOW, num, 1);
  337         __recinfo_uint8(IFACE_HOP_LIMIT, ri, r, iface.hop_limit,
  338                 IDBM_SHOW, num, 1);
  339         __recinfo_str(IFACE_MLD, ri, r, iface.mld, IDBM_SHOW, num, 1);
  340         __recinfo_uint32(IFACE_ND_REACHABLE_TMO, ri, r,
  341                  iface.nd_reachable_tmo, IDBM_SHOW, num, 1);
  342         __recinfo_uint32(IFACE_ND_REXMIT_TIME, ri, r,
  343                  iface.nd_rexmit_time, IDBM_SHOW, num, 1);
  344         __recinfo_uint32(IFACE_ND_STALE_TMO, ri, r, iface.nd_stale_tmo,
  345                  IDBM_SHOW, num, 1);
  346         __recinfo_uint32(IFACE_RTR_ADV_LINK_MTU, ri, r,
  347                  iface.router_adv_link_mtu, IDBM_SHOW, num, 1);
  348         __recinfo_uint8(IFACE_TRAFFIC_CLASS, ri, r, iface.traffic_class,
  349                 IDBM_SHOW, num, 1);
  350     }
  351 
  352     __recinfo_str(IFACE_DELAYED_ACK, ri, r, iface.delayed_ack, IDBM_SHOW,
  353               num, 1);
  354     __recinfo_str(IFACE_TCP_NAGLE, ri, r, iface.nagle, IDBM_SHOW, num, 1);
  355     __recinfo_str(IFACE_TCP_WSF_STATE, ri, r, iface.tcp_wsf_state,
  356               IDBM_SHOW, num, 1);
  357     __recinfo_uint8(IFACE_TCP_WSF, ri, r, iface.tcp_wsf, IDBM_SHOW, num, 1);
  358     __recinfo_uint8(IFACE_TCP_TIMER_SCALE, ri, r, iface.tcp_timer_scale,
  359             IDBM_SHOW, num, 1);
  360     __recinfo_str(IFACE_TCP_TIMESTAMP, ri, r, iface.tcp_timestamp,
  361               IDBM_SHOW, num, 1);
  362     __recinfo_str(IFACE_REDIRECT, ri, r, iface.redirect, IDBM_SHOW, num, 1);
  363     __recinfo_uint16(IFACE_DEF_TMF_TMO, ri, r, iface.def_task_mgmt_tmo,
  364              IDBM_SHOW, num, 1);
  365     __recinfo_str(IFACE_HDRDGST, ri, r, iface.header_digest, IDBM_SHOW,
  366               num, 1);
  367     __recinfo_str(IFACE_DATADGST, ri, r, iface.data_digest, IDBM_SHOW,
  368               num, 1);
  369     __recinfo_str(IFACE_IMM_DATA, ri, r, iface.immediate_data, IDBM_SHOW,
  370               num, 1);
  371     __recinfo_str(IFACE_INITIAL_R2T, ri, r, iface.initial_r2t, IDBM_SHOW,
  372               num, 1);
  373     __recinfo_str(IFACE_DSEQ_INORDER, ri, r, iface.data_seq_inorder,
  374               IDBM_SHOW, num, 1);
  375     __recinfo_str(IFACE_DPDU_INORDER, ri, r, iface.data_pdu_inorder,
  376               IDBM_SHOW, num, 1);
  377     __recinfo_uint8(IFACE_ERL, ri, r, iface.erl, IDBM_SHOW, num, 1);
  378     __recinfo_uint32(IFACE_MAX_RECV_DLEN, ri, r, iface.max_recv_dlength,
  379              IDBM_SHOW, num, 1);
  380     __recinfo_uint32(IFACE_FIRST_BURST, ri, r, iface.first_burst_len,
  381              IDBM_SHOW, num, 1);
  382     __recinfo_uint16(IFACE_MAX_R2T, ri, r, iface.max_out_r2t, IDBM_SHOW,
  383              num, 1);
  384     __recinfo_uint32(IFACE_MAX_BURST, ri, r, iface.max_burst_len, IDBM_SHOW,
  385              num, 1);
  386     __recinfo_str(IFACE_CHAP_AUTH, ri, r, iface.chap_auth, IDBM_SHOW,
  387               num, 1);
  388     __recinfo_str(IFACE_BIDI_CHAP, ri, r, iface.bidi_chap, IDBM_SHOW,
  389               num, 1);
  390     __recinfo_str(IFACE_STRICT_LOGIN_COMP, ri, r, iface.strict_login_comp,
  391               IDBM_SHOW, num, 1);
  392     __recinfo_str(IFACE_DISCOVERY_AUTH, ri, r, iface.discovery_auth,
  393               IDBM_SHOW, num, 1);
  394     __recinfo_str(IFACE_DISCOVERY_LOGOUT, ri, r, iface.discovery_logout,
  395               IDBM_SHOW, num, 1);
  396 
  397 
  398     __recinfo_str(NODE_DISC_ADDR, ri, r, disc_address, IDBM_SHOW,
  399               num, 0);
  400     __recinfo_int(NODE_DISC_PORT, ri, r, disc_port, IDBM_SHOW,
  401               num, 0);
  402     __recinfo_int_o6(NODE_DISC_TYPE, ri, r, disc_type, IDBM_SHOW,
  403              "send_targets", "isns", "offload_send_targets", "slp",
  404              "static", "fw", num, 0);
  405     __recinfo_int(SESSION_INIT_CMDSN, ri, r,
  406               session.initial_cmdsn, IDBM_SHOW, num, 1);
  407     __recinfo_int(SESSION_INIT_LOGIN_RETRY, ri, r,
  408               session.initial_login_retry_max, IDBM_SHOW, num, 1);
  409     __recinfo_int(SESSION_XMIT_THREAD_PRIORITY, ri, r,
  410               session.xmit_thread_priority, IDBM_SHOW, num, 1);
  411     __recinfo_int(SESSION_CMDS_MAX, ri, r,
  412               session.cmds_max, IDBM_SHOW, num, 1);
  413     __recinfo_int(SESSION_QDEPTH, ri, r,
  414                session.queue_depth, IDBM_SHOW, num, 1);
  415     __recinfo_int(SESSION_NR_SESSIONS, ri, r,
  416                session.nr_sessions, IDBM_SHOW, num, 1);
  417     __recinfo_int_o2(SESSION_AUTH_METHOD, ri, r, session.auth.authmethod,
  418              IDBM_SHOW, "None", "CHAP", num, 1);
  419     __recinfo_str(SESSION_USERNAME, ri, r,
  420               session.auth.username, IDBM_SHOW, num, 1);
  421     __recinfo_str(SESSION_PASSWORD, ri, r,
  422               session.auth.password, IDBM_MASKED, num, 1);
  423     __recinfo_int(SESSION_PASSWORD_LEN, ri, r,
  424               session.auth.password_length, IDBM_HIDE, num, 1);
  425     __recinfo_str(SESSION_USERNAME_IN, ri, r,
  426               session.auth.username_in, IDBM_SHOW, num, 1);
  427     __recinfo_str(SESSION_PASSWORD_IN, ri, r,
  428               session.auth.password_in, IDBM_MASKED, num, 1);
  429     __recinfo_int(SESSION_PASSWORD_IN_LEN, ri, r,
  430               session.auth.password_in_length, IDBM_HIDE, num, 1);
  431     __recinfo_int(SESSION_REPLACEMENT_TMO, ri, r,
  432               session.timeo.replacement_timeout,
  433               IDBM_SHOW, num, 1);
  434     __recinfo_int(SESSION_ABORT_TMO, ri, r,
  435               session.err_timeo.abort_timeout,
  436               IDBM_SHOW, num, 1);
  437     __recinfo_int(SESSION_LU_RESET_TMO, ri, r,
  438               session.err_timeo.lu_reset_timeout,
  439               IDBM_SHOW, num, 1);
  440     __recinfo_int(SESSION_TGT_RESET_TMO, ri, r,
  441               session.err_timeo.tgt_reset_timeout,
  442               IDBM_SHOW, num, 1);
  443     __recinfo_int(SESSION_HOST_RESET_TMO, ri, r,
  444               session.err_timeo.host_reset_timeout,
  445               IDBM_SHOW, num, 1);
  446     __recinfo_int_o2(SESSION_FAST_ABORT, ri, r,
  447              session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes",
  448              num, 1);
  449     __recinfo_int_o2(SESSION_INITIAL_R2T, ri, r,
  450             session.iscsi.InitialR2T, IDBM_SHOW,
  451             "No", "Yes", num, 1);
  452     __recinfo_int_o2(SESSION_IMM_DATA, ri, r,
  453             session.iscsi.ImmediateData,
  454             IDBM_SHOW, "No", "Yes", num, 1);
  455     __recinfo_int(SESSION_FIRST_BURST, ri, r,
  456               session.iscsi.FirstBurstLength, IDBM_SHOW, num, 1);
  457     __recinfo_int(SESSION_MAX_BURST, ri, r,
  458               session.iscsi.MaxBurstLength, IDBM_SHOW, num, 1);
  459     __recinfo_int(SESSION_DEF_TIME2RETAIN, ri, r,
  460               session.iscsi.DefaultTime2Retain, IDBM_SHOW, num, 1);
  461     __recinfo_int(SESSION_DEF_TIME2WAIT, ri, r,
  462               session.iscsi.DefaultTime2Wait, IDBM_SHOW, num, 1);
  463     __recinfo_int(SESSION_MAX_CONNS, ri, r,
  464               session.iscsi.MaxConnections, IDBM_SHOW, num, 1);
  465     __recinfo_int(SESSION_MAX_R2T, ri, r,
  466               session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num, 1);
  467     __recinfo_int(SESSION_ERL, ri, r,
  468               session.iscsi.ERL, IDBM_SHOW, num, 1);
  469     __recinfo_int_o2(SESSION_SCAN, ri, r,
  470              session.scan, IDBM_SHOW, "manual", "auto",
  471              num, 1);
  472     __recinfo_int(SESSION_REOPEN_MAX, ri, r,
  473             session.reopen_max, IDBM_SHOW, num, 1);
  474 
  475     for (i = 0; i < ISCSI_CONN_MAX; i++) {
  476         char key[NAME_MAXVAL];
  477 
  478         sprintf(key, CONN_ADDR, i);
  479         __recinfo_str(key, ri, r, conn[i].address, IDBM_SHOW, num, 0);
  480         sprintf(key, CONN_PORT, i);
  481         __recinfo_int(key, ri, r, conn[i].port, IDBM_SHOW, num, 0);
  482         sprintf(key, CONN_STARTUP, i);
  483         __recinfo_int_o3(key, ri, r, conn[i].startup, IDBM_SHOW,
  484                  "manual", "automatic", "onboot", num, 1);
  485         sprintf(key, CONN_WINDOW_SIZE, i);
  486         __recinfo_int(key, ri, r, conn[i].tcp.window_size,
  487                   IDBM_SHOW, num, 1);
  488         sprintf(key, CONN_SERVICE_TYPE, i);
  489         __recinfo_int(key, ri, r, conn[i].tcp.type_of_service,
  490                 IDBM_SHOW, num, 1);
  491         sprintf(key, CONN_LOGOUT_TMO, i);
  492         __recinfo_int(key, ri, r, conn[i].timeo.logout_timeout,
  493                 IDBM_SHOW, num, 1);
  494         sprintf(key, CONN_LOGIN_TMO, i);
  495         __recinfo_int(key, ri, r, conn[i].timeo.login_timeout,
  496                 IDBM_SHOW, num, 1);
  497         sprintf(key, CONN_AUTH_TMO, i);
  498         __recinfo_int(key, ri, r, conn[i].timeo.auth_timeout,
  499                 IDBM_SHOW, num, 1);
  500 
  501         sprintf(key, CONN_NOP_INT, i);
  502         __recinfo_int(key, ri, r, conn[i].timeo.noop_out_interval,
  503                 IDBM_SHOW, num, 1);
  504         sprintf(key, CONN_NOP_TMO, i);
  505         __recinfo_int(key, ri, r, conn[i].timeo.noop_out_timeout,
  506                 IDBM_SHOW, num, 1);
  507 
  508         sprintf(key, CONN_MAX_XMIT_DLEN, i);
  509         __recinfo_int(key, ri, r,
  510             conn[i].iscsi.MaxXmitDataSegmentLength, IDBM_SHOW,
  511             num, 1);
  512         sprintf(key, CONN_MAX_RECV_DLEN, i);
  513         __recinfo_int(key, ri, r,
  514             conn[i].iscsi.MaxRecvDataSegmentLength, IDBM_SHOW,
  515             num, 1);
  516         sprintf(key, CONN_HDR_DIGEST, i);
  517         __recinfo_int_o4(key, ri, r, conn[i].iscsi.HeaderDigest,
  518                  IDBM_SHOW, "None", "CRC32C", "CRC32C,None",
  519                  "None,CRC32C", num, 1);
  520         sprintf(key, CONN_DATA_DIGEST, i);
  521         __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW,
  522                  "None", "CRC32C", "CRC32C,None",
  523                  "None,CRC32C", num, 1);
  524         sprintf(key, CONN_IFMARKER, i);
  525         __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW,
  526                 "No", "Yes", num, 1);
  527         sprintf(key, CONN_OFMARKER, i);
  528         __recinfo_int_o2(key, ri, r, conn[i].iscsi.OFMarker, IDBM_SHOW,
  529                 "No", "Yes", num, 1);
  530     }
  531 }
  532 
  533 void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
  534 {
  535     int num = 0;
  536     int iface_type;
  537 
  538     iface_type = iface_get_iptype(r);
  539 
  540     __recinfo_str(IFACE_ISCSINAME, ri, r, name, IDBM_SHOW, num, 0);
  541     __recinfo_str(IFACE_NETNAME, ri, r, netdev, IDBM_SHOW, num, 1);
  542     __recinfo_str(IFACE_IPADDR, ri, r, ipaddress, IDBM_SHOW, num, 1);
  543     __recinfo_uint8(IFACE_PREFIX_LEN, ri, r, prefix_len, IDBM_SHOW, num, 1);
  544     __recinfo_str(IFACE_HWADDR, ri, r, hwaddress, IDBM_SHOW, num, 1);
  545     __recinfo_str(IFACE_TRANSPORTNAME, ri, r, transport_name,
  546               IDBM_SHOW, num, 1);
  547     __recinfo_str(IFACE_INAME, ri, r, iname, IDBM_SHOW, num, 1);
  548     __recinfo_str(IFACE_STATE, ri, r, state, IDBM_SHOW, num, 1);
  549     __recinfo_uint16(IFACE_VLAN_ID, ri, r, vlan_id, IDBM_SHOW, num, 1);
  550     __recinfo_uint8(IFACE_VLAN_PRIORITY, ri, r, vlan_priority,
  551               IDBM_SHOW, num, 1);
  552     __recinfo_str(IFACE_VLAN_STATE, ri, r, vlan_state, IDBM_SHOW, num, 1);
  553     __recinfo_int(IFACE_NUM, ri, r, iface_num, IDBM_SHOW, num, 1);
  554     __recinfo_uint16(IFACE_MTU, ri, r, mtu, IDBM_SHOW, num, 1);
  555     __recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1);
  556 
  557     if (iface_type == ISCSI_IFACE_TYPE_IPV4) {
  558         __recinfo_str(IFACE_BOOT_PROTO, ri, r, bootproto, IDBM_SHOW,
  559                   num, 1);
  560         __recinfo_str(IFACE_SUBNET_MASK, ri, r, subnet_mask, IDBM_SHOW,
  561                   num, 1);
  562         __recinfo_str(IFACE_GATEWAY, ri, r, gateway, IDBM_SHOW, num, 1);
  563         __recinfo_str(IFACE_DHCP_ALT_CID, ri, r,
  564                   dhcp_alt_client_id_state, IDBM_SHOW, num, 1);
  565         __recinfo_str(IFACE_DHCP_ALT_CID_STR, ri, r, dhcp_alt_client_id,
  566                   IDBM_SHOW, num, 1);
  567         __recinfo_str(IFACE_DHCP_DNS, ri, r, dhcp_dns, IDBM_SHOW,
  568                   num, 1);
  569         __recinfo_str(IFACE_DHCP_LEARN_IQN, ri, r, dhcp_learn_iqn,
  570                   IDBM_SHOW, num, 1);
  571         __recinfo_str(IFACE_DHCP_REQ_VID, ri, r,
  572                   dhcp_req_vendor_id_state, IDBM_SHOW, num, 1);
  573         __recinfo_str(IFACE_DHCP_VID, ri, r, dhcp_vendor_id_state,
  574                   IDBM_SHOW, num, 1);
  575         __recinfo_str(IFACE_DHCP_VID_STR, ri, r, dhcp_vendor_id,
  576                   IDBM_SHOW, num, 1);
  577         __recinfo_str(IFACE_DHCP_SLP_DA, ri, r, dhcp_slp_da, IDBM_SHOW,
  578                   num, 1);
  579         __recinfo_str(IFACE_FRAGMENTATION, ri, r, fragmentation,
  580                   IDBM_SHOW, num, 1);
  581         __recinfo_str(IFACE_GRAT_ARP, ri, r, gratuitous_arp, IDBM_SHOW,
  582                   num, 1);
  583         __recinfo_str(IFACE_IN_FORWARD, ri, r, incoming_forwarding,
  584                   IDBM_SHOW, num, 1);
  585         __recinfo_str(IFACE_TOS_STATE, ri, r, tos_state, IDBM_SHOW,
  586                   num, 1);
  587         __recinfo_uint8(IFACE_TOS, ri, r, tos, IDBM_SHOW, num, 1);
  588         __recinfo_uint8(IFACE_TTL, ri, r, ttl, IDBM_SHOW, num, 1);
  589     } else if (iface_type == ISCSI_IFACE_TYPE_IPV6) {
  590         __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, ipv6_autocfg,
  591                   IDBM_SHOW, num, 1);
  592         __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, linklocal_autocfg,
  593                   IDBM_SHOW, num, 1);
  594         __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, router_autocfg,
  595                   IDBM_SHOW, num, 1);
  596         __recinfo_str(IFACE_LINKLOCAL, ri, r, ipv6_linklocal, IDBM_SHOW,
  597                   num, 1);
  598         __recinfo_str(IFACE_ROUTER, ri, r, ipv6_router, IDBM_SHOW,
  599                   num, 1);
  600         __recinfo_uint8(IFACE_DUP_ADDR_DETECT_CNT, ri, r,
  601                 dup_addr_detect_cnt, IDBM_SHOW, num, 1);
  602         __recinfo_uint32(IFACE_FLOW_LABEL, ri, r, flow_label, IDBM_SHOW,
  603                  num, 1);
  604         __recinfo_str(IFACE_GRAT_NEIGHBOR_ADV, ri, r,
  605                   gratuitous_neighbor_adv, IDBM_SHOW, num, 1);
  606         __recinfo_uint8(IFACE_HOP_LIMIT, ri, r, hop_limit, IDBM_SHOW,
  607                 num, 1);
  608         __recinfo_str(IFACE_MLD, ri, r, mld, IDBM_SHOW, num, 1);
  609         __recinfo_uint32(IFACE_ND_REACHABLE_TMO, ri, r,
  610                  nd_reachable_tmo, IDBM_SHOW, num, 1);
  611         __recinfo_uint32(IFACE_ND_REXMIT_TIME, ri, r, nd_rexmit_time,
  612                  IDBM_SHOW, num, 1);
  613         __recinfo_uint32(IFACE_ND_STALE_TMO, ri, r, nd_stale_tmo,
  614                  IDBM_SHOW, num, 1);
  615         __recinfo_uint32(IFACE_RTR_ADV_LINK_MTU, ri, r,
  616                  router_adv_link_mtu, IDBM_SHOW, num, 1);
  617         __recinfo_uint8(IFACE_TRAFFIC_CLASS, ri, r, traffic_class,
  618                 IDBM_SHOW, num, 1);
  619     }
  620 
  621     __recinfo_str(IFACE_DELAYED_ACK, ri, r, delayed_ack, IDBM_SHOW, num, 1);
  622     __recinfo_str(IFACE_TCP_NAGLE, ri, r, nagle, IDBM_SHOW, num, 1);
  623     __recinfo_str(IFACE_TCP_WSF_STATE, ri, r, tcp_wsf_state, IDBM_SHOW,
  624               num, 1);
  625     __recinfo_uint8(IFACE_TCP_WSF, ri, r, tcp_wsf, IDBM_SHOW, num, 1);
  626     __recinfo_uint8(IFACE_TCP_TIMER_SCALE, ri, r, tcp_timer_scale,
  627             IDBM_SHOW, num, 1);
  628     __recinfo_str(IFACE_TCP_TIMESTAMP, ri, r, tcp_timestamp, IDBM_SHOW,
  629               num, 1);
  630     __recinfo_str(IFACE_REDIRECT, ri, r, redirect, IDBM_SHOW, num, 1);
  631     __recinfo_uint16(IFACE_DEF_TMF_TMO, ri, r, def_task_mgmt_tmo, IDBM_SHOW,
  632              num, 1);
  633     __recinfo_str(IFACE_HDRDGST, ri, r, header_digest, IDBM_SHOW, num, 1);
  634     __recinfo_str(IFACE_DATADGST, ri, r, data_digest, IDBM_SHOW, num, 1);
  635     __recinfo_str(IFACE_IMM_DATA, ri, r, immediate_data, IDBM_SHOW, num, 1);
  636     __recinfo_str(IFACE_INITIAL_R2T, ri, r, initial_r2t, IDBM_SHOW, num, 1);
  637     __recinfo_str(IFACE_DSEQ_INORDER, ri, r, data_seq_inorder, IDBM_SHOW,
  638               num, 1);
  639     __recinfo_str(IFACE_DPDU_INORDER, ri, r, data_pdu_inorder, IDBM_SHOW,
  640               num, 1);
  641     __recinfo_uint8(IFACE_ERL, ri, r, erl, IDBM_SHOW, num, 1);
  642     __recinfo_uint32(IFACE_MAX_RECV_DLEN, ri, r, max_recv_dlength,
  643              IDBM_SHOW, num, 1);
  644     __recinfo_uint32(IFACE_FIRST_BURST, ri, r, first_burst_len, IDBM_SHOW,
  645              num, 1);
  646     __recinfo_uint16(IFACE_MAX_R2T, ri, r, max_out_r2t, IDBM_SHOW, num, 1);
  647     __recinfo_uint32(IFACE_MAX_BURST, ri, r, max_burst_len, IDBM_SHOW,
  648              num, 1);
  649     __recinfo_str(IFACE_CHAP_AUTH, ri, r, chap_auth, IDBM_SHOW, num, 1);
  650     __recinfo_str(IFACE_BIDI_CHAP, ri, r, bidi_chap, IDBM_SHOW, num, 1);
  651     __recinfo_str(IFACE_STRICT_LOGIN_COMP, ri, r, strict_login_comp,
  652               IDBM_SHOW, num, 1);
  653     __recinfo_str(IFACE_DISCOVERY_AUTH, ri, r, discovery_auth, IDBM_SHOW,
  654               num, 1);
  655     __recinfo_str(IFACE_DISCOVERY_LOGOUT, ri, r, discovery_logout,
  656               IDBM_SHOW, num, 1);
  657 }
  658 
  659 void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
  660 {
  661     int num = 0;
  662 
  663     __recinfo_uint16(HOST_AUTH_INDEX, ri, r, chap_tbl_idx, IDBM_SHOW,
  664              num, 1);
  665 
  666     if (r->chap_type == CHAP_TYPE_OUT) {
  667         __recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW,
  668                   num, 1);
  669         __recinfo_str(HOST_AUTH_PASSWORD, ri, r, password, IDBM_MASKED,
  670                   num, 1);
  671         __recinfo_int(HOST_AUTH_PASSWORD_LEN, ri, r, password_length,
  672                   IDBM_HIDE, num, 1);
  673     } else {
  674         __recinfo_str(HOST_AUTH_USERNAME_IN, ri, r, username, IDBM_SHOW,
  675                   num, 1);
  676         __recinfo_str(HOST_AUTH_PASSWORD_IN, ri, r, password,
  677                   IDBM_MASKED, num, 1);
  678         __recinfo_int(HOST_AUTH_PASSWORD_IN_LEN, ri, r, password_length,
  679                   IDBM_HIDE, num, 1);
  680     }
  681 }
  682 
  683 void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri)
  684 {
  685     int num = 0;
  686     int i;
  687 
  688     __recinfo_uint8(FLASHNODE_SESS_AUTO_SND_TGT_DISABLE, ri, r,
  689             sess.auto_snd_tgt_disable, IDBM_SHOW, num, 1);
  690     __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_SESS, ri, r,
  691             sess.discovery_session, IDBM_SHOW, num, 1);
  692     __recinfo_str(FLASHNODE_SESS_PORTAL_TYPE, ri, r, sess.portal_type,
  693               IDBM_SHOW, num, 1);
  694     __recinfo_uint8(FLASHNODE_SESS_ENTRY_EN, ri, r,
  695             sess.entry_enable, IDBM_SHOW, num, 1);
  696     __recinfo_uint8(FLASHNODE_SESS_IMM_DATA_EN, ri, r, sess.immediate_data,
  697             IDBM_SHOW, num, 1);
  698     __recinfo_uint8(FLASHNODE_SESS_INITIAL_R2T_EN, ri, r, sess.initial_r2t,
  699             IDBM_SHOW, num, 1);
  700     __recinfo_uint8(FLASHNODE_SESS_DATASEQ_INORDER, ri, r,
  701             sess.data_seq_in_order, IDBM_SHOW, num, 1);
  702     __recinfo_uint8(FLASHNODE_SESS_PDU_INORDER, ri, r,
  703             sess.data_pdu_in_order, IDBM_SHOW, num, 1);
  704     __recinfo_uint8(FLASHNODE_SESS_CHAP_AUTH_EN, ri, r, sess.chap_auth_en,
  705             IDBM_SHOW, num, 1);
  706     __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_LOGOUT_EN, ri, r,
  707             sess.discovery_logout_en, IDBM_SHOW, num, 1);
  708     __recinfo_uint8(FLASHNODE_SESS_BIDI_CHAP_EN, ri, r, sess.bidi_chap_en,
  709             IDBM_SHOW, num, 1);
  710     __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL, ri, r,
  711             sess.discovery_auth_optional, IDBM_SHOW, num, 1);
  712     __recinfo_uint8(FLASHNODE_SESS_ERL, ri, r, sess.erl, IDBM_SHOW, num, 1);
  713     __recinfo_uint32(FLASHNODE_SESS_FIRST_BURST, ri, r,
  714              sess.first_burst_len, IDBM_SHOW, num, 1);
  715     __recinfo_uint16(FLASHNODE_SESS_DEF_TIME2WAIT, ri, r,
  716              sess.def_time2wait, IDBM_SHOW, num, 1);
  717     __recinfo_uint16(FLASHNODE_SESS_DEF_TIME2RETAIN, ri, r,
  718              sess.def_time2retain, IDBM_SHOW, num, 1);
  719     __recinfo_uint16(FLASHNODE_SESS_MAX_R2T, ri, r,
  720              sess.max_outstanding_r2t, IDBM_SHOW, num, 1);
  721     __recinfo_str(FLASHNODE_SESS_ISID, ri, r, sess.isid, IDBM_SHOW, num, 1);
  722     __recinfo_uint16(FLASHNODE_SESS_TSID, ri, r, sess.tsid, IDBM_SHOW,
  723              num, 1);
  724     __recinfo_uint32(FLASHNODE_SESS_MAX_BURST, ri, r, sess.max_burst_len,
  725              IDBM_SHOW, num, 1);
  726     __recinfo_uint16(FLASHNODE_SESS_DEF_TASKMGMT_TMO, ri, r,
  727              sess.def_taskmgmt_tmo, IDBM_SHOW, num, 1);
  728     __recinfo_str(FLASHNODE_SESS_ALIAS, ri, r, sess.targetalias, IDBM_SHOW,
  729               num, 1);
  730     __recinfo_str(FLASHNODE_SESS_NAME, ri, r, sess.targetname, IDBM_SHOW,
  731               num, 1);
  732     __recinfo_uint16(FLASHNODE_SESS_DISCOVERY_PARENT_IDX, ri, r,
  733              sess.discovery_parent_idx, IDBM_SHOW, num, 1);
  734     __recinfo_str(FLASHNODE_SESS_DISCOVERY_PARENT_TYPE, ri, r,
  735               sess.discovery_parent_type, IDBM_SHOW, num, 1);
  736     __recinfo_uint16(FLASHNODE_SESS_TPGT, ri, r, sess.tpgt, IDBM_SHOW,
  737              num, 1);
  738     __recinfo_uint16(FLASHNODE_SESS_CHAP_OUT_IDX, ri, r, sess.chap_out_idx,
  739              IDBM_SHOW, num, 1);
  740     __recinfo_uint16(FLASHNODE_SESS_CHAP_IN_IDX, ri, r, sess.chap_in_idx,
  741              IDBM_SHOW, num, 1);
  742     __recinfo_str(FLASHNODE_SESS_USERNAME, ri, r, sess.username, IDBM_SHOW,
  743               num, 1);
  744     __recinfo_str(FLASHNODE_SESS_USERNAME_IN, ri, r, sess.username_in,
  745               IDBM_SHOW, num, 1);
  746     __recinfo_str(FLASHNODE_SESS_PASSWORD, ri, r, sess.password, IDBM_SHOW,
  747               num, 1);
  748     __recinfo_str(FLASHNODE_SESS_PASSWORD_IN, ri, r, sess.password_in,
  749               IDBM_SHOW, num, 1);
  750     __recinfo_uint8(FLASHNODE_SESS_IS_BOOT_TGT, ri, r, sess.is_boot_target,
  751             IDBM_SHOW, num, 1);
  752 
  753     for (i = 0; i < ISCSI_CONN_MAX; i++) {
  754         char key[NAME_MAXVAL];
  755 
  756         sprintf(key, FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6, i);
  757         __recinfo_uint8(key, ri, r, conn[i].is_fw_assigned_ipv6,
  758                 IDBM_SHOW, num, 1);
  759         sprintf(key, FLASHNODE_CONN_HDR_DGST_EN, i);
  760         __recinfo_uint8(key, ri, r, conn[i].header_digest_en, IDBM_SHOW,
  761                 num, 1);
  762         sprintf(key, FLASHNODE_CONN_DATA_DGST_EN, i);
  763         __recinfo_uint8(key, ri, r, conn[i].data_digest_en, IDBM_SHOW,
  764                 num, 1);
  765         sprintf(key, FLASHNODE_CONN_SNACK_REQ_EN, i);
  766         __recinfo_uint8(key, ri, r, conn[i].snack_req_en, IDBM_SHOW,
  767                 num, 1);
  768         sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_STAT, i);
  769         __recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_stat,
  770                 IDBM_SHOW, num, 1);
  771         sprintf(key, FLASHNODE_CONN_TCP_NAGLE_DISABLE, i);
  772         __recinfo_uint8(key, ri, r, conn[i].tcp_nagle_disable,
  773                 IDBM_SHOW, num, 1);
  774         sprintf(key, FLASHNODE_CONN_TCP_WSF_DISABLE, i);
  775         __recinfo_uint8(key, ri, r, conn[i].tcp_wsf_disable, IDBM_SHOW,
  776                 num, 1);
  777         sprintf(key, FLASHNODE_CONN_TCP_TIMER_SCALE, i);
  778         __recinfo_uint8(key, ri, r, conn[i].tcp_timer_scale, IDBM_SHOW,
  779                 num, 1);
  780         sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_EN, i);
  781         __recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_en,
  782                 IDBM_SHOW, num, 1);
  783         sprintf(key, FLASHNODE_CONN_IP_FRAG_DISABLE, i);
  784         __recinfo_uint8(key, ri, r, conn[i].fragment_disable, IDBM_SHOW,
  785                 num, 1);
  786         sprintf(key, FLASHNODE_CONN_MAX_XMIT_DLENGTH, i);
  787         __recinfo_uint32(key, ri, r, conn[i].max_xmit_dlength,
  788                  IDBM_SHOW, num, 1);
  789         sprintf(key, FLASHNODE_CONN_MAX_RECV_DLENGTH, i);
  790         __recinfo_uint32(key, ri, r, conn[i].max_recv_dlength,
  791                  IDBM_SHOW, num, 1);
  792         sprintf(key, FLASHNODE_CONN_KEEPALIVE_TMO, i);
  793         __recinfo_uint16(key, ri, r, conn[i].keepalive_tmo, IDBM_SHOW,
  794                  num, 1);
  795         sprintf(key, FLASHNODE_CONN_PORT, i);
  796         __recinfo_uint16(key, ri, r, conn[i].port, IDBM_SHOW, num, 1);
  797         sprintf(key, FLASHNODE_CONN_IPADDR, i);
  798         __recinfo_str(key, ri, r, conn[i].ipaddress, IDBM_SHOW, num, 1);
  799         sprintf(key, FLASHNODE_CONN_REDIRECT_IPADDR, i);
  800         __recinfo_str(key, ri, r, conn[i].redirect_ipaddr, IDBM_SHOW,
  801                   num, 1);
  802         sprintf(key, FLASHNODE_CONN_MAX_SEGMENT_SIZE, i);
  803         __recinfo_uint32(key, ri, r, conn[i].max_segment_size,
  804                  IDBM_SHOW, num, 1);
  805         sprintf(key, FLASHNODE_CONN_LOCAL_PORT, i);
  806         __recinfo_uint16(key, ri, r, conn[i].local_port, IDBM_SHOW,
  807                  num, 1);
  808         sprintf(key, FLASHNODE_CONN_IPV4_TOS, i);
  809         __recinfo_uint8(key, ri, r, conn[i].ipv4_tos, IDBM_SHOW,
  810                 num, 1);
  811         sprintf(key, FLASHNODE_CONN_IPV6_TC, i);
  812         __recinfo_uint8(key, ri, r, conn[i].ipv6_traffic_class,
  813                 IDBM_SHOW, num, 1);
  814         sprintf(key, FLASHNODE_CONN_IPV6_FLOW_LABEL, i);
  815         __recinfo_uint16(key, ri, r, conn[i].ipv6_flow_lbl, IDBM_SHOW,
  816                  num, 1);
  817         sprintf(key, FLASHNODE_CONN_LINK_LOCAL_IPV6, i);
  818         __recinfo_str(key, ri, r, conn[i].link_local_ipv6, IDBM_SHOW,
  819                   num, 1);
  820         sprintf(key, FLASHNODE_CONN_TCP_XMIT_WSF, i);
  821         __recinfo_uint32(key, ri, r, conn[i].tcp_xmit_wsf, IDBM_SHOW,
  822                  num, 1);
  823         sprintf(key, FLASHNODE_CONN_TCP_RECV_WSF, i);
  824         __recinfo_uint32(key, ri, r, conn[i].tcp_recv_wsf, IDBM_SHOW,
  825                  num, 1);
  826         sprintf(key, FLASHNODE_CONN_STATSN, i);
  827         __recinfo_uint32(key, ri, r, conn[i].stat_sn, IDBM_SHOW,
  828                  num, 1);
  829         sprintf(key, FLASHNODE_CONN_EXP_STATSN, i);
  830         __recinfo_uint32(key, ri, r, conn[i].exp_stat_sn, IDBM_SHOW,
  831                  num, 1);
  832     }
  833 }
  834 
  835 recinfo_t *idbm_recinfo_alloc(int max_keys)
  836 {
  837     recinfo_t *info;
  838 
  839     info = malloc(sizeof(recinfo_t)*max_keys);
  840     if (!info)
  841         return NULL;
  842     memset(info, 0, sizeof(recinfo_t)*max_keys);
  843     return info;
  844 }
  845 
  846 void idbm_print(int type, void *rec, int show, FILE *f)
  847 {
  848     int i;
  849     recinfo_t *info;
  850 
  851     info = idbm_recinfo_alloc(MAX_KEYS);
  852     if (!info)
  853         return;
  854 
  855     switch (type) {
  856     case IDBM_PRINT_TYPE_DISCOVERY:
  857         idbm_recinfo_discovery((discovery_rec_t*)rec, info);
  858         break;
  859     case IDBM_PRINT_TYPE_NODE:
  860         idbm_recinfo_node((node_rec_t*)rec, info);
  861         break;
  862     case IDBM_PRINT_TYPE_IFACE:
  863         idbm_recinfo_iface((struct iface_rec *)rec, info);
  864         break;
  865     case IDBM_PRINT_TYPE_HOST_CHAP:
  866         idbm_recinfo_host_chap((struct iscsi_chap_rec *)rec, info);
  867         break;
  868     case IDBM_PRINT_TYPE_FLASHNODE:
  869         idbm_recinfo_flashnode((struct flashnode_rec *)rec, info);
  870         break;
  871     }
  872 
  873     fprintf(f, "%s\n", ISCSI_BEGIN_REC);
  874     for (i = 0; i < MAX_KEYS; i++) {
  875         if (!info[i].visible)
  876             continue;
  877         if (!show && info[i].visible == IDBM_MASKED) {
  878             if (*(char*)info[i].data) {
  879                 fprintf(f, "%s = ********\n", info[i].name);
  880                 continue;
  881             }
  882             /* fall through */
  883         }
  884 
  885         if (strlen(info[i].value))
  886             fprintf(f, "%s = %s\n", info[i].name, info[i].value);
  887         else if (f == stdout)
  888             fprintf(f, "%s = <empty>\n", info[i].name);
  889     }
  890     fprintf(f, "%s\n", ISCSI_END_REC);
  891 
  892     free(info);
  893 }
  894 
  895 static void
  896 idbm_setup_session_defaults(struct iscsi_session_operational_config *conf)
  897 {
  898     conf->InitialR2T = 0;
  899     conf->ImmediateData = 1;
  900     conf->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
  901     conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
  902     conf->DefaultTime2Wait = ISCSI_DEF_TIME2WAIT;
  903     conf->DefaultTime2Retain = 0;
  904     conf->MaxConnections = 1;
  905     conf->MaxOutstandingR2T = 1;
  906     conf->ERL = 0;
  907     conf->FastAbort = 1;
  908 }
  909 
  910 static void idbm_setup_conn_defaults(struct iscsi_conn_operational_config *conf)
  911 {
  912     conf->MaxXmitDataSegmentLength = 0;
  913     conf->MaxRecvDataSegmentLength = DEF_INI_MAX_RECV_SEG_LEN;
  914     conf->HeaderDigest = CONFIG_DIGEST_NEVER;
  915     conf->DataDigest = CONFIG_DIGEST_NEVER;
  916     conf->IFMarker = 0;
  917     conf->OFMarker = 0;
  918 }
  919 
  920 static void
  921 idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type)
  922 {
  923     memset(rec, 0, sizeof(discovery_rec_t));
  924 
  925     rec->startup = ISCSI_STARTUP_MANUAL;
  926     rec->type = type;
  927     rec->iscsid_req_tmo = -1;
  928     switch (type) {
  929     case DISCOVERY_TYPE_SENDTARGETS:
  930         rec->u.sendtargets.discoveryd_poll_inval = 30;
  931         rec->u.sendtargets.use_discoveryd = 0;
  932         rec->u.sendtargets.reopen_max = 5;
  933         rec->u.sendtargets.auth.authmethod = 0;
  934         rec->u.sendtargets.auth.password_length = 0;
  935         rec->u.sendtargets.auth.password_in_length = 0;
  936         rec->u.sendtargets.conn_timeo.login_timeout=15;
  937         rec->u.sendtargets.conn_timeo.auth_timeout = 45;
  938         rec->u.sendtargets.conn_timeo.active_timeout=30;
  939         idbm_setup_session_defaults(&rec->u.sendtargets.session_conf);
  940         idbm_setup_conn_defaults(&rec->u.sendtargets.conn_conf);
  941         /* override def setting */
  942         rec->u.sendtargets.conn_conf.MaxRecvDataSegmentLength =
  943                         DEF_INI_DISC_MAX_RECV_SEG_LEN;
  944         break;
  945     case DISCOVERY_TYPE_SLP:
  946         rec->u.slp.interfaces = NULL;
  947         rec->u.slp.scopes = NULL;
  948         rec->u.slp.poll_interval = 5 * 60;  /* 5 minutes */
  949         rec->u.slp.auth.authmethod = 0;
  950         rec->u.slp.auth.password_length = 0;
  951         rec->u.slp.auth.password_in_length = 0;
  952         rec->u.slp.auth.password_in_length = 0;
  953         break;
  954     case DISCOVERY_TYPE_ISNS:
  955         rec->u.isns.use_discoveryd = 0;
  956         rec->u.isns.discoveryd_poll_inval = -1;
  957         break;
  958     default:
  959         break;
  960     }
  961 }
  962 
  963 int idbm_rec_update_param(recinfo_t *info, char *name, char *value,
  964               int line_number)
  965 {
  966     int i;
  967     int passwd_done = 0;
  968     char passwd_len[8];
  969 
  970 setup_passwd_len:
  971     for (i=0; i<MAX_KEYS; i++) {
  972         if (!strcmp(name, info[i].name)) {
  973             int j;
  974 
  975             log_debug(7, "updated '%s', '%s' => '%s'", name,
  976                   info[i].value, value);
  977             /* parse recinfo by type */
  978             if (info[i].type == TYPE_INT) {
  979                 if (!info[i].data)
  980                     continue;
  981 
  982                 *(int*)info[i].data =
  983                     strtoul(value, NULL, 10);
  984                 goto updated;
  985             } else if (info[i].type == TYPE_UINT8) {
  986                 if (!info[i].data)
  987                     continue;
  988 
  989                 *(uint8_t *)info[i].data =
  990                     strtoul(value, NULL, 10);
  991                 goto updated;
  992             } else if (info[i].type == TYPE_UINT16) {
  993                 if (!info[i].data)
  994                     continue;
  995 
  996                 *(uint16_t *)info[i].data =
  997                     strtoul(value, NULL, 10);
  998                 goto updated;
  999             } else if (info[i].type == TYPE_UINT32) {
 1000                 if (!info[i].data)
 1001                     continue;
 1002 
 1003                 *(uint32_t *)info[i].data =
 1004                     strtoul(value, NULL, 10);
 1005                 goto updated;
 1006             } else if (info[i].type == TYPE_STR) {
 1007                 if (!info[i].data)
 1008                     continue;
 1009 
 1010                 strlcpy((char*)info[i].data,
 1011                     value, info[i].data_len);
 1012                 goto updated;
 1013             }
 1014             for (j=0; j<info[i].numopts; j++) {
 1015                 if (!strcmp(value, info[i].opts[j])) {
 1016                     if (!info[i].data)
 1017                         continue;
 1018 
 1019                     *(int*)info[i].data = j;
 1020                     goto updated;
 1021                 }
 1022             }
 1023             if (line_number) {
 1024                 log_warning("config file line %d contains "
 1025                         "unknown value format '%s' for "
 1026                         "parameter name '%s'",
 1027                         line_number, value, name);
 1028             } else {
 1029                 log_error("unknown value format '%s' for "
 1030                       "parameter name '%s'", value, name);
 1031             }
 1032             break;
 1033         }
 1034     }
 1035 
 1036     return ISCSI_ERR_INVAL;
 1037 
 1038 updated:
 1039     strlcpy((char*)info[i].value, value, VALUE_MAXVAL);
 1040 
 1041 #define check_password_param(_param) \
 1042     if (!passwd_done && !strcmp(#_param, name)) { \
 1043         passwd_done = 1; \
 1044         name = #_param "_length"; \
 1045         snprintf(passwd_len, 8, "%.7" PRIi32, (int)strlen(value) & 0xffff); \
 1046         value = passwd_len; \
 1047         goto setup_passwd_len; \
 1048     }
 1049 
 1050     check_password_param(node.session.auth.password);
 1051     check_password_param(node.session.auth.password_in);
 1052     check_password_param(discovery.sendtargets.auth.password);
 1053     check_password_param(discovery.sendtargets.auth.password_in);
 1054     check_password_param(discovery.slp.auth.password);
 1055     check_password_param(discovery.slp.auth.password_in);
 1056     check_password_param(host.auth.password);
 1057     check_password_param(host.auth.password_in);
 1058 
 1059     return 0;
 1060 }
 1061 
 1062 /*
 1063  * TODO: we can also check for valid values here.
 1064  */
 1065 int idbm_verify_param(recinfo_t *info, char *name)
 1066 {
 1067     int i;
 1068 
 1069     for (i = 0; i < MAX_KEYS; i++) {
 1070         if (strcmp(name, info[i].name))
 1071             continue;
 1072 
 1073         log_debug(7, "verify %s %d", name, info[i].can_modify);
 1074         if (info[i].can_modify)
 1075             return 0;
 1076         else {
 1077             log_error("Cannot modify %s. It is used to look up "
 1078                   "the record and cannot be changed.", name);
 1079             return ISCSI_ERR_INVAL;
 1080         }
 1081     }
 1082 
 1083     log_error("Cannot modify %s. Invalid param name.", name);
 1084     return ISCSI_ERR_INVAL;
 1085 }
 1086 
 1087 void idbm_recinfo_config(recinfo_t *info, FILE *f)
 1088 {
 1089     char name[NAME_MAXVAL];
 1090     char value[VALUE_MAXVAL];
 1091     char *line, *nl, buffer[2048];
 1092     int line_number = 0;
 1093     int c = 0, i;
 1094 
 1095     fseek(f, 0, SEEK_SET);
 1096 
 1097     /* process the config file */
 1098     do {
 1099         line = fgets(buffer, sizeof (buffer), f);
 1100         line_number++;
 1101         if (!line)
 1102             continue;
 1103 
 1104         nl = line + strlen(line) - 1;
 1105         if (*nl != '\n') {
 1106             log_warning("Config file line %d too long.",
 1107                    line_number);
 1108             continue;
 1109         }
 1110 
 1111         line = strstrip(line);
 1112         /* process any non-empty, non-comment lines */
 1113         if (!*line || *line == '\0' || *line ==  '\n' || *line == '#')
 1114             continue;
 1115 
 1116         /* parse name */
 1117         i=0; nl = line; *name = 0;
 1118         while (*nl && !isspace(c = *nl) && *nl != '=') {
 1119             *(name+i) = *nl; i++; nl++;
 1120         }
 1121         if (!*nl) {
 1122             log_warning("config file line %d do not has value",
 1123                    line_number);
 1124             continue;
 1125         }
 1126         *(name+i)=0; nl++;
 1127         /* skip after-name traling spaces */
 1128         while (*nl && isspace(c = *nl)) nl++;
 1129         if (*nl && *nl != '=') {
 1130             log_warning("config file line %d has not '=' sepa",
 1131                    line_number);
 1132             continue;
 1133         }
 1134         /* skip '=' sepa */
 1135         nl++;
 1136         /* skip after-sepa traling spaces */
 1137         while (*nl && isspace(c = *nl)) nl++;
 1138         if (!*nl) {
 1139             log_warning("config file line %d do not has value",
 1140                    line_number);
 1141             continue;
 1142         }
 1143         /* parse value */
 1144         i=0; *value = 0;
 1145         while (*nl) {
 1146             *(value+i) = *nl; i++; nl++;
 1147         }
 1148         *(value+i) = 0;
 1149 
 1150         idbm_rec_update_param(info, name, value, line_number);
 1151     } while (line);
 1152 }
 1153 
 1154 /*
 1155  * TODO: remove db's copy of nrec and infos
 1156  */
 1157 static void idbm_sync_config(void)
 1158 {
 1159     char *config_file;
 1160     FILE *f;
 1161 
 1162     /* in case of no configuration file found we just
 1163      * initialize default node and default discovery records
 1164      * from hard-coded default values */
 1165     idbm_node_setup_defaults(&db->nrec);
 1166     idbm_discovery_setup_defaults(&db->drec_st, DISCOVERY_TYPE_SENDTARGETS);
 1167     idbm_discovery_setup_defaults(&db->drec_slp, DISCOVERY_TYPE_SLP);
 1168     idbm_discovery_setup_defaults(&db->drec_isns, DISCOVERY_TYPE_ISNS);
 1169 
 1170     idbm_recinfo_discovery(&db->drec_st, db->dinfo_st);
 1171     idbm_recinfo_discovery(&db->drec_slp, db->dinfo_slp);
 1172     idbm_recinfo_discovery(&db->drec_isns, db->dinfo_isns);
 1173     idbm_recinfo_node(&db->nrec, db->ninfo);
 1174 
 1175     if (!db->get_config_file) {
 1176         log_debug(1, "Could not get config file. No config file fn");
 1177         return;
 1178     }
 1179 
 1180     config_file = db->get_config_file();
 1181     if (!config_file) {
 1182         log_debug(1, "Could not get config file for sync config");
 1183         return;
 1184     }
 1185 
 1186     f = fopen(config_file, "r");
 1187     if (!f) {
 1188         log_debug(1, "cannot open configuration file %s. "
 1189               "Default location is %s.",
 1190               config_file, CONFIG_FILE);
 1191         return;
 1192     }
 1193     log_debug(5, "updating defaults from '%s'", config_file);
 1194 
 1195     idbm_recinfo_config(db->dinfo_st, f);
 1196     idbm_recinfo_config(db->dinfo_slp, f);
 1197     idbm_recinfo_config(db->dinfo_isns, f);
 1198     idbm_recinfo_config(db->ninfo, f);
 1199     fclose(f);
 1200 
 1201     /* update password lengths */
 1202     if (*db->drec_st.u.sendtargets.auth.password)
 1203         db->drec_st.u.sendtargets.auth.password_length =
 1204             strlen((char*)db->drec_st.u.sendtargets.auth.password);
 1205     if (*db->drec_st.u.sendtargets.auth.password_in)
 1206         db->drec_st.u.sendtargets.auth.password_in_length =
 1207              strlen((char*)db->drec_st.u.sendtargets.auth.password_in);
 1208     if (*db->drec_slp.u.slp.auth.password)
 1209         db->drec_slp.u.slp.auth.password_length =
 1210             strlen((char*)db->drec_slp.u.slp.auth.password);
 1211     if (*db->drec_slp.u.slp.auth.password_in)
 1212         db->drec_slp.u.slp.auth.password_in_length =
 1213             strlen((char*)db->drec_slp.u.slp.auth.password_in);
 1214     if (*db->nrec.session.auth.password)
 1215         db->nrec.session.auth.password_length =
 1216             strlen((char*)db->nrec.session.auth.password);
 1217     if (*db->nrec.session.auth.password_in)
 1218         db->nrec.session.auth.password_in_length =
 1219             strlen((char*)db->nrec.session.auth.password_in);
 1220 }
 1221 
 1222 void idbm_node_setup_from_conf(node_rec_t *rec)
 1223 {
 1224     memset(rec, 0, sizeof(*rec));
 1225     idbm_node_setup_defaults(rec);
 1226     idbm_sync_config();
 1227     memcpy(rec, &db->nrec, sizeof(*rec));
 1228 }
 1229 
 1230 int idbm_print_discovery_info(discovery_rec_t *rec, int show)
 1231 {
 1232     idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, show, stdout);
 1233     return 1;
 1234 }
 1235 
 1236 int idbm_print_node_info(void *data, node_rec_t *rec)
 1237 {
 1238     int show = *((int *)data);
 1239 
 1240     idbm_print(IDBM_PRINT_TYPE_NODE, rec, show, stdout);
 1241     return 0;
 1242 }
 1243 
 1244 int idbm_print_host_chap_info(struct iscsi_chap_rec *chap)
 1245 {
 1246     /* User only calls this to print chap so always print */
 1247     idbm_print(IDBM_PRINT_TYPE_HOST_CHAP, chap, 1, stdout);
 1248     return 0;
 1249 }
 1250 
 1251 int idbm_print_flashnode_info(struct flashnode_rec *fnode)
 1252 {
 1253     idbm_print(IDBM_PRINT_TYPE_FLASHNODE, fnode, 1, stdout);
 1254     return 0;
 1255 }
 1256 
 1257 int idbm_print_node_flat(void *data, node_rec_t *rec)
 1258 {
 1259     if (strchr(rec->conn[0].address, '.'))
 1260         printf("%s:%d,%d %s\n", rec->conn[0].address, rec->conn[0].port,
 1261             rec->tpgt, rec->name);
 1262     else
 1263         printf("[%s]:%d,%d %s\n", rec->conn[0].address,
 1264                rec->conn[0].port, rec->tpgt, rec->name);
 1265     return 0;
 1266 }
 1267 
 1268 int idbm_print_node_tree(struct node_rec *last_rec, struct node_rec *rec,
 1269              char *prefix)
 1270 {
 1271     if (!last_rec || strcmp(last_rec->name, rec->name)) {
 1272         printf("%sTarget: %s\n", prefix, rec->name);
 1273         if (last_rec)
 1274             memset(last_rec, 0, sizeof(node_rec_t));
 1275     }
 1276 
 1277     if (!last_rec ||
 1278          ((strcmp(last_rec->conn[0].address, rec->conn[0].address) ||
 1279          last_rec->conn[0].port != rec->conn[0].port))) {
 1280         if (strchr(rec->conn[0].address, '.'))
 1281             printf("%s\tPortal: %s:%d,%d\n", prefix,
 1282                    rec->conn[0].address,
 1283                    rec->conn[0].port, rec->tpgt);
 1284         else
 1285             printf("%s\tPortal: [%s]:%d,%d\n", prefix,
 1286                    rec->conn[0].address,
 1287                    rec->conn[0].port, rec->tpgt);
 1288     }
 1289 
 1290     if (last_rec)
 1291         memcpy(last_rec, rec, sizeof(node_rec_t));
 1292     return 0;
 1293 }
 1294 
 1295 int idbm_print_node_and_iface_tree(void *data, node_rec_t *rec)
 1296 {
 1297     idbm_print_node_tree(data, rec, "");
 1298     printf("\t\tIface Name: %s\n", rec->iface.name);
 1299     return 0;
 1300 }
 1301 
 1302 static int
 1303 get_params_from_disc_link(char *link, char **target, char **tpgt,
 1304               char **address, char **port, char **ifaceid)
 1305 {
 1306     (*target) = link;
 1307     *address = strchr(*target, ',');
 1308     if (!(*address))
 1309         return ISCSI_ERR_INVAL;
 1310     *(*address)++ = '\0';
 1311     *port = strchr(*address, ',');
 1312     if (!(*port))
 1313         return ISCSI_ERR_INVAL;
 1314     *(*port)++ = '\0';
 1315     *tpgt = strchr(*port, ',');
 1316     if (!(*tpgt))
 1317         return ISCSI_ERR_INVAL;
 1318     *(*tpgt)++ = '\0';
 1319     *ifaceid = strchr(*tpgt, ',');
 1320     if (!(*ifaceid))
 1321         return ISCSI_ERR_INVAL;
 1322     *(*ifaceid)++ = '\0';
 1323     return 0;
 1324 }
 1325 
 1326 int idbm_lock(void)
 1327 {
 1328     int fd, i, ret;
 1329 
 1330     if (db->refs > 0) {
 1331         db->refs++;
 1332         return 0;
 1333     }
 1334 
 1335     if (access(LOCK_DIR, F_OK) != 0) {
 1336         if (mkdir(LOCK_DIR, 0660) != 0) {
 1337             log_error("Could not open %s: %s", LOCK_DIR,
 1338                   strerror(errno));
 1339             return ISCSI_ERR_IDBM;
 1340         }
 1341     }
 1342 
 1343     fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666);
 1344     if (fd >= 0)
 1345         close(fd);
 1346 
 1347     for (i = 0; i < 3000; i++) {
 1348         ret = link(LOCK_FILE, LOCK_WRITE_FILE);
 1349         if (ret == 0)
 1350             break;
 1351 
 1352         if (errno != EEXIST) {
 1353             log_error("Maybe you are not root?");
 1354             log_error("Could not lock discovery DB: %s: %s",
 1355                     LOCK_WRITE_FILE, strerror(errno));
 1356             return ISCSI_ERR_IDBM;
 1357         } else if (i == 0)
 1358             log_debug(2, "Waiting for discovery DB lock");
 1359 
 1360         usleep(10000);
 1361     }
 1362 
 1363     db->refs = 1;
 1364     return 0;
 1365 }
 1366 
 1367 void idbm_unlock(void)
 1368 {
 1369     if (db->refs > 1) {
 1370         db->refs--;
 1371         return;
 1372     }
 1373 
 1374     db->refs = 0;
 1375     unlink(LOCK_WRITE_FILE);
 1376 }
 1377 
 1378 /*
 1379  * Backwards Compat:
 1380  * If the portal is a file then we are doing the old style default
 1381  * session behavior (svn pre 780).
 1382  */
 1383 static FILE *idbm_open_rec_r(char *portal, char *config)
 1384 {
 1385     struct stat statb;
 1386 
 1387     log_debug(5, "Looking for config file %s config %s.", portal, config);
 1388 
 1389     if (stat(portal, &statb)) {
 1390         log_debug(5, "Could not stat %s err %d.", portal, errno);
 1391         return NULL;
 1392     }
 1393 
 1394     if (S_ISDIR(statb.st_mode)) {
 1395         strlcat(portal, "/", PATH_MAX);
 1396         strlcat(portal, config, PATH_MAX);
 1397     }
 1398     return fopen(portal, "r");
 1399 }
 1400 
 1401 /*
 1402  * When the disable_lock param is true, the idbm_lock/idbm_unlock needs
 1403  * to be holt by the caller, this will avoid overwriting each other in
 1404  * case of updating(read-modify-write) the recs in parallel.
 1405  */
 1406 static int __idbm_rec_read(node_rec_t *out_rec, char *conf, bool disable_lock)
 1407 {
 1408     recinfo_t *info;
 1409     FILE *f;
 1410     int rc = 0;
 1411 
 1412     info = idbm_recinfo_alloc(MAX_KEYS);
 1413     if (!info)
 1414         return ISCSI_ERR_NOMEM;
 1415 
 1416     if (!disable_lock) {
 1417         rc = idbm_lock();
 1418         if (rc)
 1419             goto free_info;
 1420     }
 1421 
 1422     f = fopen(conf, "r");
 1423     if (!f) {
 1424         log_debug(5, "Could not open %s err %s", conf,
 1425               strerror(errno));
 1426         rc = ISCSI_ERR_IDBM;
 1427         goto unlock;
 1428     }
 1429 
 1430     memset(out_rec, 0, sizeof(*out_rec));
 1431     idbm_node_setup_defaults(out_rec);
 1432     idbm_recinfo_node(out_rec, info);
 1433     idbm_recinfo_config(info, f);
 1434     fclose(f);
 1435 
 1436 unlock:
 1437     if (!disable_lock)
 1438         idbm_unlock();
 1439 free_info:
 1440     free(info);
 1441     return rc;
 1442 }
 1443 
 1444 /*
 1445  * When the disable_lock param is true, the idbm_lock/idbm_unlock needs
 1446  * to be holt by the caller, this will avoid overwriting each other in
 1447  * case of updating(read-modify-write) the recs in parallel.
 1448  */
 1449 int
 1450 idbm_rec_read(node_rec_t *out_rec, char *targetname, int tpgt,
 1451           char *ip, int port, struct iface_rec *iface, bool disable_lock)
 1452 {
 1453     struct stat statb;
 1454     char *portal;
 1455     int rc;
 1456 
 1457     portal = calloc(1, PATH_MAX);
 1458     if (!portal)
 1459         return ISCSI_ERR_IDBM;
 1460 
 1461     /* try old style portal as config */
 1462     snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
 1463          targetname, ip, port);
 1464     log_debug(5, "rec read looking for config file %s.", portal);
 1465     if (!stat(portal, &statb))
 1466         goto read;
 1467 
 1468     snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
 1469          targetname, ip, port, tpgt, iface->name);
 1470     log_debug(5, "rec read looking for config file %s.", portal);
 1471     if (!strlen(iface->name)) {
 1472         rc = ISCSI_ERR_INVAL;
 1473         goto free_portal;
 1474     }
 1475 
 1476     if (stat(portal, &statb)) {
 1477         log_debug(5, "Could not stat %s: %s.", portal, strerror(errno));
 1478         free(portal);
 1479         return ISCSI_ERR_IDBM;
 1480     }
 1481 
 1482 read:
 1483     rc = __idbm_rec_read(out_rec, portal, disable_lock);
 1484 free_portal:
 1485     free(portal);
 1486     return rc;
 1487 }
 1488 
 1489 static int print_discovered_flat(void *data, node_rec_t *rec)
 1490 {
 1491     struct discovery_rec *drec = data;
 1492 
 1493     if (rec->disc_type != drec->type)
 1494         goto no_match;
 1495 
 1496     if (drec->type == DISCOVERY_TYPE_SENDTARGETS ||
 1497         drec->type == DISCOVERY_TYPE_ISNS) {
 1498         if (rec->disc_port != drec->port ||
 1499             strcmp(rec->disc_address, drec->address))
 1500             goto no_match;
 1501     }
 1502 
 1503     idbm_print_node_flat(NULL, rec);
 1504     return 0;
 1505 no_match:
 1506     return -1;
 1507 }
 1508 
 1509 struct discovered_tree_info {
 1510     struct discovery_rec *drec;
 1511     struct node_rec *last_rec;
 1512 };
 1513 
 1514 static int print_discovered_tree(void *data, node_rec_t *rec)
 1515 {
 1516     struct discovered_tree_info *tree_info = data;
 1517     struct discovery_rec *drec = tree_info->drec;
 1518 
 1519     if (rec->disc_type != drec->type)
 1520         goto no_match;
 1521 
 1522     if (strlen(drec->address)) {
 1523         if (rec->disc_port != drec->port ||
 1524             strcmp(rec->disc_address, drec->address))
 1525             goto no_match;
 1526     }
 1527 
 1528     idbm_print_node_and_iface_tree(tree_info->last_rec, rec);
 1529     return 0;
 1530 no_match:
 1531     return -1;
 1532 }
 1533 
 1534 static int idbm_print_discovered(discovery_rec_t *drec, int info_level)
 1535 {
 1536     int num_found = 0;
 1537 
 1538     if (info_level < 1)
 1539         idbm_for_each_rec(&num_found, drec, print_discovered_flat, false);
 1540     else {
 1541         struct discovered_tree_info tree_info;
 1542         struct node_rec last_rec;
 1543 
 1544         memset(&last_rec, 0, sizeof(struct node_rec));
 1545 
 1546         tree_info.drec = drec;
 1547         tree_info.last_rec = &last_rec;
 1548 
 1549         idbm_for_each_rec(&num_found, &tree_info, print_discovered_tree, false);
 1550     }
 1551     return num_found;
 1552 }
 1553 
 1554 static int idbm_for_each_drec(int type, char *config_root, void *data,
 1555                   idbm_drec_op_fn *fn)
 1556 {
 1557     DIR *entity_dirfd;
 1558     struct dirent *entity_dent;
 1559     int found = 0;
 1560     discovery_rec_t drec;
 1561     char *tmp_port;
 1562 
 1563     entity_dirfd = opendir(config_root);
 1564     if (!entity_dirfd)
 1565         return found;
 1566 
 1567     while ((entity_dent = readdir(entity_dirfd))) {
 1568         if (!strcmp(entity_dent->d_name, ".") ||
 1569             !strcmp(entity_dent->d_name, ".."))
 1570             continue;
 1571 
 1572         log_debug(5, "found %s", entity_dent->d_name);
 1573 
 1574         tmp_port = strchr(entity_dent->d_name, ',');
 1575         if (!tmp_port)
 1576             continue;
 1577         /*
 1578          * pre 872 tools dumped the target portal symlinks in the isns
 1579          * dir instead of the server. If we find one of those links
 1580          * (by checking if there is a valid port) we skip it.
 1581          */
 1582         if (strchr(tmp_port, ':') || strchr(tmp_port, '.'))
 1583             continue;
 1584         *tmp_port++ = '\0';
 1585 
 1586         memset(&drec, 0, sizeof(drec));
 1587         if (idbm_discovery_read(&drec, type, entity_dent->d_name,
 1588                     atoi(tmp_port))) {
 1589             log_error("Could not read discovery record for "
 1590                   "%s:%s.", entity_dent->d_name, tmp_port);
 1591             continue;
 1592         }
 1593 
 1594         if (!fn(data, &drec))
 1595             found++;
 1596     }
 1597     closedir(entity_dirfd);
 1598     return found;
 1599 }
 1600 
 1601 int idbm_for_each_st_drec(void *data, idbm_drec_op_fn *fn)
 1602 {
 1603     return idbm_for_each_drec(DISCOVERY_TYPE_SENDTARGETS, ST_CONFIG_DIR,
 1604                   data, fn);
 1605 }
 1606 
 1607 int idbm_for_each_isns_drec(void *data, idbm_drec_op_fn *fn)
 1608 {
 1609     return idbm_for_each_drec(DISCOVERY_TYPE_ISNS, ISNS_CONFIG_DIR,
 1610                   data, fn);
 1611 }
 1612 
 1613 static int __idbm_print_all_by_drec(void *data, struct discovery_rec *drec)
 1614 {
 1615     int info_level = *(int *)data;
 1616 
 1617     if (info_level >= 1) {
 1618         printf("DiscoveryAddress: %s,%d\n",
 1619                drec->address, drec->port);
 1620         idbm_print_discovered(drec, info_level);
 1621     } else
 1622         printf("%s:%d via %s\n", drec->address, drec->port,
 1623                drec->type == DISCOVERY_TYPE_ISNS ?
 1624                "isns" : "sendtargets");
 1625     return 0;
 1626 }
 1627 
 1628 static int idbm_print_all_st(int info_level)
 1629 {
 1630     int rc;
 1631 
 1632     rc = idbm_for_each_st_drec(&info_level, __idbm_print_all_by_drec);
 1633     if (rc < 0)
 1634         return 0;
 1635     return rc;
 1636 }
 1637 
 1638 static int idbm_print_all_isns(int info_level)
 1639 {
 1640     int rc;
 1641 
 1642     rc = idbm_for_each_isns_drec(&info_level, __idbm_print_all_by_drec);
 1643     if (rc < 0)
 1644         return 0;
 1645     return rc;
 1646 }
 1647 
 1648 int idbm_print_all_discovery(int info_level)
 1649 {
 1650     discovery_rec_t *drec;
 1651     int found = 0, tmp;
 1652 
 1653     if (info_level < 1) {
 1654         found = idbm_print_all_st(info_level);
 1655         found += idbm_print_all_isns(info_level);
 1656         return found;
 1657     }
 1658 
 1659     drec = calloc(1, sizeof(*drec));
 1660     if (!drec)
 1661         return 0;
 1662 
 1663     tmp = 0;
 1664     printf("SENDTARGETS:\n");
 1665     tmp = idbm_print_all_st(info_level);
 1666     if (!tmp)
 1667         printf("No targets found.\n");
 1668     found += tmp;
 1669     tmp = 0;
 1670 
 1671     printf("iSNS:\n");
 1672     tmp = idbm_print_all_isns(info_level);
 1673     if (!tmp) {
 1674         /*
 1675          * pre 872 tools did not store the server ip,port so
 1676          * we drop down here, to just look for target portals.
 1677          */
 1678         drec->type = DISCOVERY_TYPE_ISNS;
 1679         tmp = idbm_print_discovered(drec, info_level);
 1680         if (!tmp)
 1681             printf("No targets found.\n");
 1682     }
 1683     found += tmp;
 1684     tmp = 0;
 1685 
 1686     printf("STATIC:\n");
 1687     drec->type = DISCOVERY_TYPE_STATIC;
 1688     tmp = idbm_print_discovered(drec, info_level);
 1689     if (!tmp)
 1690         printf("No targets found.\n");
 1691     found += tmp;
 1692     tmp = 0;
 1693 
 1694     printf("FIRMWARE:\n");
 1695     drec->type = DISCOVERY_TYPE_FW;
 1696     tmp = idbm_print_discovered(drec, info_level);
 1697     if (!tmp)
 1698         printf("No targets found.\n");
 1699     found += tmp;
 1700 
 1701     free(drec);
 1702     return found;
 1703 }
 1704 
 1705 /**
 1706  * idbm_for_each_iface - iterate over bound iface recs
 1707  * @found: nr of recs found so far
 1708  * @data: data pointer passed to fn
 1709  * @fn: iterator function ran over each bound iface rec
 1710  * @targetname: rec's target name
 1711  * @tpgt: rec's portal group tag
 1712  * @ip: rec's ip address
 1713  * @port: rec's port
 1714  *
 1715  * This will run fn over all recs with the {targetname,tpgt,ip,port}
 1716  * id. It does not iterate over the ifaces setup in /etc/iscsi/ifaces.
 1717  *
 1718  * fn should return -1 if it skipped the rec, an ISCSI_ERR error code if
 1719  * the operation failed or 0 if fn was run successfully.
 1720  */
 1721 static int idbm_for_each_iface(int *found, void *data, idbm_iface_op_fn *fn,
 1722                    char *targetname, int tpgt, char *ip, int port,
 1723                    bool ruw_lock)
 1724 {
 1725     DIR *iface_dirfd;
 1726     struct dirent *iface_dent;
 1727     struct stat statb;
 1728     node_rec_t rec;
 1729     int rc = 0;
 1730     char *portal;
 1731 
 1732     portal = calloc(1, PATH_MAX);
 1733     if (!portal)
 1734         return ISCSI_ERR_NOMEM;
 1735 
 1736     if (tpgt >= 0)
 1737         goto read_iface;
 1738 
 1739     /* old style portal as a config */
 1740     snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, targetname,
 1741          ip, port);
 1742     if (stat(portal, &statb)) {
 1743         log_error("iface iter could not stat %s.", portal);
 1744         rc = ISCSI_ERR_IDBM;
 1745         goto free_portal;
 1746     }
 1747 
 1748     rc = __idbm_rec_read(&rec, portal, ruw_lock);
 1749     if (rc)
 1750         goto free_portal;
 1751 
 1752     rc = fn(data, &rec);
 1753     if (!rc)
 1754         (*found)++;
 1755     else if (rc == -1)
 1756         rc = 0;
 1757     goto free_portal;
 1758 
 1759 read_iface:
 1760     snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
 1761          targetname, ip, port, tpgt);
 1762 
 1763     iface_dirfd = opendir(portal);
 1764     if (!iface_dirfd) {
 1765         log_error("iface iter could not read dir %s.", portal);
 1766         rc = ISCSI_ERR_IDBM;
 1767         goto free_portal;
 1768     }
 1769 
 1770     while ((iface_dent = readdir(iface_dirfd))) {
 1771         int curr_rc;
 1772 
 1773         if (!strcmp(iface_dent->d_name, ".") ||
 1774             !strcmp(iface_dent->d_name, ".."))
 1775             continue;
 1776 
 1777         log_debug(5, "iface iter found %s.", iface_dent->d_name);
 1778         memset(portal, 0, PATH_MAX);
 1779         snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
 1780              targetname, ip, port, tpgt, iface_dent->d_name);
 1781         if (__idbm_rec_read(&rec, portal, ruw_lock))
 1782             continue;
 1783 
 1784         curr_rc = fn(data, &rec);
 1785         /* less than zero means it was not a match */
 1786         if (curr_rc > 0 && !rc)
 1787             rc = curr_rc;
 1788         else if (curr_rc == 0)
 1789             (*found)++;
 1790     }
 1791 
 1792     closedir(iface_dirfd);
 1793 free_portal:
 1794     free(portal);
 1795     return rc;
 1796 }
 1797 
 1798 /*
 1799  * backwards compat
 1800  * The portal could be a file or dir with interfaces
 1801  */
 1802 int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn,
 1803              char *targetname, bool ruw_lock)
 1804 {
 1805     DIR *portal_dirfd;
 1806     struct dirent *portal_dent;
 1807     int rc = 0;
 1808     char *portal;
 1809 
 1810     portal = calloc(1, PATH_MAX);
 1811     if (!portal)
 1812         return ISCSI_ERR_NOMEM;
 1813 
 1814     snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, targetname);
 1815     portal_dirfd = opendir(portal);
 1816     if (!portal_dirfd) {
 1817         rc = ISCSI_ERR_IDBM;
 1818         goto done;
 1819     }
 1820 
 1821     while ((portal_dent = readdir(portal_dirfd))) {
 1822         char *tmp_port, *tmp_tpgt;
 1823         int curr_rc;
 1824 
 1825         if (!strcmp(portal_dent->d_name, ".") ||
 1826             !strcmp(portal_dent->d_name, ".."))
 1827             continue;
 1828 
 1829         log_debug(5, "found %s", portal_dent->d_name);
 1830         tmp_port = strchr(portal_dent->d_name, ',');
 1831         if (!tmp_port)
 1832             continue;
 1833         *tmp_port++ = '\0';
 1834         tmp_tpgt = strchr(tmp_port, ',');
 1835         if (tmp_tpgt)
 1836             *tmp_tpgt++ = '\0';
 1837 
 1838         curr_rc = fn(found, data, targetname,
 1839             tmp_tpgt ? atoi(tmp_tpgt) : -1,
 1840             portal_dent->d_name, atoi(tmp_port),
 1841             ruw_lock);
 1842         /* less than zero means it was not a match */
 1843         if (curr_rc > 0 && !rc)
 1844             rc = curr_rc;
 1845     }
 1846     closedir(portal_dirfd);
 1847 done:
 1848     free(portal);
 1849     return rc;
 1850 }
 1851 
 1852 int idbm_for_each_node(int *found, void *data, idbm_node_op_fn *fn, bool ruw_lock)
 1853 {
 1854     DIR *node_dirfd;
 1855     struct dirent *node_dent;
 1856     int rc = 0;
 1857 
 1858     *found = 0;
 1859 
 1860     node_dirfd = opendir(NODE_CONFIG_DIR);
 1861     if (!node_dirfd)
 1862         /* on start up node dir may not be created */
 1863         return 0;
 1864 
 1865     while ((node_dent = readdir(node_dirfd))) {
 1866         int curr_rc;
 1867 
 1868         if (!strcmp(node_dent->d_name, ".") ||
 1869             !strcmp(node_dent->d_name, ".."))
 1870             continue;
 1871 
 1872         log_debug(5, "searching %s", node_dent->d_name);
 1873         curr_rc = fn(found, data, node_dent->d_name, ruw_lock);
 1874         /* less than zero means it was not a match */
 1875         if (curr_rc > 0 && !rc)
 1876             rc = curr_rc;
 1877     }
 1878 
 1879     closedir(node_dirfd);
 1880     return rc;
 1881 }
 1882 
 1883 static int iface_fn(void *data, node_rec_t *rec)
 1884 {
 1885     struct rec_op_data *op_data = data;
 1886 
 1887     return op_data->fn(op_data->data, rec);
 1888 }
 1889 
 1890 static int portal_fn(int *found, void *data, char *targetname,
 1891              int tpgt, char *ip, int port, bool ruw_lock)
 1892 {
 1893     int rc;
 1894 
 1895     if (ruw_lock) {
 1896         rc = idbm_lock();
 1897         if (rc)
 1898             return rc;
 1899     }
 1900 
 1901     rc = idbm_for_each_iface(found, data, iface_fn, targetname,
 1902                      tpgt, ip, port, ruw_lock);
 1903     if (ruw_lock)
 1904         idbm_unlock();
 1905 
 1906     return rc;
 1907 }
 1908 
 1909 static int node_fn(int *found, void *data, char *targetname, bool ruw_lock)
 1910 {
 1911     return idbm_for_each_portal(found, data, portal_fn, targetname, ruw_lock);
 1912 }
 1913 
 1914 int idbm_for_each_rec(int *found, void *data, idbm_iface_op_fn *fn, bool ruw_lock)
 1915 {
 1916     struct rec_op_data op_data;
 1917 
 1918     memset(&op_data, 0, sizeof(struct rec_op_data));
 1919     op_data.data = data;
 1920     op_data.fn = fn;
 1921 
 1922     return idbm_for_each_node(found, &op_data, node_fn, ruw_lock);
 1923 }
 1924 
 1925 static struct {
 1926     char *config_root;
 1927     char *config_name;
 1928 } disc_type_to_config_vals[] = {
 1929     { ST_CONFIG_DIR, ST_CONFIG_NAME },
 1930     { ISNS_CONFIG_DIR, ISNS_CONFIG_NAME },
 1931 };
 1932 
 1933 int
 1934 idbm_discovery_read(discovery_rec_t *out_rec, int drec_type,
 1935             char *addr, int port)
 1936 {
 1937     recinfo_t *info;
 1938     char *portal;
 1939     int rc = 0;
 1940     FILE *f;
 1941 
 1942     if (drec_type > 1)
 1943         return ISCSI_ERR_INVAL;
 1944 
 1945     memset(out_rec, 0, sizeof(discovery_rec_t));
 1946     out_rec->iscsid_req_tmo = -1;
 1947 
 1948     info = idbm_recinfo_alloc(MAX_KEYS);
 1949     if (!info)
 1950         return ISCSI_ERR_NOMEM;
 1951 
 1952     portal = malloc(PATH_MAX);
 1953     if (!portal) {
 1954         rc = ISCSI_ERR_NOMEM;
 1955         goto free_info;
 1956     }
 1957 
 1958     snprintf(portal, PATH_MAX, "%s/%s,%d",
 1959          disc_type_to_config_vals[drec_type].config_root,
 1960          addr, port);
 1961     log_debug(5, "Looking for config file %s", portal);
 1962 
 1963     rc = idbm_lock();
 1964     if (rc)
 1965         goto free_info;
 1966 
 1967     f = idbm_open_rec_r(portal,
 1968                 disc_type_to_config_vals[drec_type].config_name);
 1969     if (!f) {
 1970         log_debug(1, "Could not open %s: %s", portal,
 1971               strerror(errno));
 1972         rc = ISCSI_ERR_IDBM;
 1973         goto unlock;
 1974     }
 1975 
 1976     idbm_discovery_setup_defaults(out_rec, drec_type);
 1977     idbm_recinfo_discovery(out_rec, info);
 1978     idbm_recinfo_config(info, f);
 1979     fclose(f);
 1980 
 1981 unlock:
 1982     idbm_unlock();
 1983 free_info:
 1984     free(portal);
 1985     free(info);
 1986     return rc;
 1987 }
 1988 
 1989 /*
 1990  * Backwards Compat:
 1991  * If the portal is a file then we are doing the old style default
 1992  * session behavior (svn pre 780).
 1993  */
 1994 static FILE *idbm_open_rec_w(char *portal, char *config)
 1995 {
 1996     struct stat statb;
 1997     FILE *f;
 1998     int err;
 1999 
 2000     log_debug(5, "Looking for config file %s", portal);
 2001 
 2002     err = stat(portal, &statb);
 2003     if (err)
 2004         goto mkdir_portal;
 2005 
 2006     if (!S_ISDIR(statb.st_mode)) {
 2007         /*
 2008          * Old style portal as a file. Let's update it.
 2009          */
 2010         if (unlink(portal)) {
 2011             log_error("Could not convert %s to %s/%s. "
 2012                  "err %d", portal, portal,
 2013                   config, errno);
 2014             return NULL;
 2015         }
 2016 
 2017 mkdir_portal:
 2018         if (mkdir(portal, 0660) != 0) {
 2019             log_error("Could not make dir %s err %d",
 2020                   portal, errno);
 2021             return NULL;
 2022         }
 2023     }
 2024 
 2025     strlcat(portal, "/", PATH_MAX);
 2026     strlcat(portal, config, PATH_MAX);
 2027     f = fopen(portal, "w");
 2028     if (!f)
 2029         log_error("Could not open %s err %d", portal, errno);
 2030     return f;
 2031 }
 2032 
 2033 /*
 2034  * When the disable_lock param is true, the idbm_lock/idbm_unlock needs
 2035  * to be holt by the caller, this will avoid overwriting each other in
 2036  * case of updating(read-modify-write) the recs in parallel.
 2037  */
 2038 static int idbm_rec_write(node_rec_t *rec, bool disable_lock)
 2039 {
 2040     struct stat statb;
 2041     FILE *f;
 2042     char *portal;
 2043     int rc = 0;
 2044 
 2045     portal = malloc(PATH_MAX);
 2046     if (!portal) {
 2047         log_error("Could not alloc portal");
 2048         return ISCSI_ERR_NOMEM;
 2049     }
 2050 
 2051     snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR);
 2052     if (access(portal, F_OK) != 0) {
 2053         if (mkdir(portal, 0660) != 0) {
 2054             log_error("Could not make %s: %s", portal,
 2055                   strerror(errno));
 2056             rc = ISCSI_ERR_IDBM;
 2057             goto free_portal;
 2058         }
 2059     }
 2060 
 2061     snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name);
 2062     if (access(portal, F_OK) != 0) {
 2063         if (mkdir(portal, 0660) != 0) {
 2064             log_error("Could not make %s: %s", portal,
 2065                   strerror(errno));
 2066             rc = ISCSI_ERR_IDBM;
 2067             goto free_portal;
 2068         }
 2069     }
 2070 
 2071     snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
 2072          rec->name, rec->conn[0].address, rec->conn[0].port);
 2073     log_debug(5, "Looking for config file %s", portal);
 2074 
 2075     if (!disable_lock) {
 2076         rc = idbm_lock();
 2077         if (rc)
 2078             goto free_portal;
 2079     }
 2080 
 2081     rc = stat(portal, &statb);
 2082     if (rc) {
 2083         rc = 0;
 2084         /*
 2085          * older iscsiadm versions had you create the config then set
 2086          * set the tgpt. In new versions you must pass all the info in
 2087          * from the start
 2088          */
 2089         if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
 2090             /* drop down to old style portal as config */
 2091             goto open_conf;
 2092         else
 2093             goto mkdir_portal;
 2094     }
 2095 
 2096     if (!S_ISDIR(statb.st_mode)) {
 2097         /*
 2098          * older iscsiadm versions had you create the config then set
 2099          * set the tgpt. In new versions you must pass all the info in
 2100          * from the start
 2101          */
 2102         if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
 2103             /* drop down to old style portal as config */
 2104             goto open_conf;
 2105         /*
 2106          * Old style portal as a file, but with tpgt. Let's update it.
 2107          */
 2108         if (unlink(portal)) {
 2109             log_error("Could not convert %s: %s", portal,
 2110                   strerror(errno));
 2111             rc = ISCSI_ERR_IDBM;
 2112             goto unlock;
 2113         }
 2114     } else {
 2115         rc = ISCSI_ERR_INVAL;
 2116         goto unlock;
 2117     }
 2118 
 2119 mkdir_portal:
 2120     snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
 2121          rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt);
 2122     if (stat(portal, &statb)) {
 2123         if (mkdir(portal, 0660) != 0) {
 2124             log_error("Could not make dir %s: %s",
 2125                   portal, strerror(errno));
 2126             rc = ISCSI_ERR_IDBM;
 2127             goto unlock;
 2128         }
 2129     }
 2130 
 2131     snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
 2132          rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt,
 2133          rec->iface.name);
 2134 open_conf:
 2135     f = fopen(portal, "w");
 2136     if (!f) {
 2137         log_error("Could not open %s: %s", portal, strerror(errno));
 2138         rc = ISCSI_ERR_IDBM;
 2139         goto unlock;
 2140     }
 2141 
 2142     idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f);
 2143     fclose(f);
 2144 unlock:
 2145     if (!disable_lock)
 2146         idbm_unlock();
 2147 free_portal:
 2148     free(portal);
 2149     return rc;
 2150 }
 2151 
 2152 static int
 2153 idbm_discovery_write(discovery_rec_t *rec)
 2154 {
 2155     FILE *f;
 2156     char *portal;
 2157     int rc = 0;
 2158 
 2159     if (rec->type > 1)
 2160         return ISCSI_ERR_INVAL;
 2161 
 2162     portal = malloc(PATH_MAX);
 2163     if (!portal) {
 2164         log_error("Could not alloc portal");
 2165         return ISCSI_ERR_NOMEM;
 2166     }
 2167 
 2168     rc = idbm_lock();
 2169     if (rc)
 2170         goto free_portal;
 2171 
 2172     snprintf(portal, PATH_MAX, "%s",
 2173          disc_type_to_config_vals[rec->type].config_root);
 2174     if (access(portal, F_OK) != 0) {
 2175         if (mkdir(portal, 0660) != 0) {
 2176             log_error("Could not make %s: %s", portal,
 2177                   strerror(errno));
 2178             rc = ISCSI_ERR_IDBM;
 2179             goto unlock;
 2180         }
 2181     }
 2182 
 2183     snprintf(portal, PATH_MAX, "%s/%s,%d",
 2184          disc_type_to_config_vals[rec->type].config_root,
 2185          rec->address, rec->port);
 2186 
 2187     f = idbm_open_rec_w(portal,
 2188                 disc_type_to_config_vals[rec->type].config_name);
 2189     if (!f) {
 2190         log_error("Could not open %s: %s", portal, strerror(errno));
 2191         rc = ISCSI_ERR_IDBM;
 2192         goto unlock;
 2193     }
 2194 
 2195     idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, 1, f);
 2196     fclose(f);
 2197 unlock:
 2198     idbm_unlock();
 2199 free_portal:
 2200     free(portal);
 2201     return rc;
 2202 }
 2203 
 2204 int idbm_add_discovery(discovery_rec_t *newrec)
 2205 {
 2206     discovery_rec_t rec;
 2207 
 2208     if (!idbm_discovery_read(&rec, newrec->type, newrec->address,
 2209                 newrec->port)) {
 2210         log_debug(7, "disc rec already exists");
 2211         /* fall through */
 2212     } else
 2213         log_debug(7, "adding new DB record");
 2214 
 2215     return idbm_discovery_write(newrec);
 2216 }
 2217 
 2218 static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec)
 2219 {
 2220     struct stat statb;
 2221     int rc = 0;
 2222 
 2223     switch (rec->disc_type) {
 2224     case DISCOVERY_TYPE_SENDTARGETS:
 2225         /* st dir setup when we create its discovery node */
 2226         snprintf(disc_portal, PATH_MAX, "%s/%s,%d/%s,%s,%d,%d,%s",
 2227              ST_CONFIG_DIR,
 2228              rec->disc_address, rec->disc_port, rec->name,
 2229              rec->conn[0].address, rec->conn[0].port, rec->tpgt,
 2230              rec->iface.name);
 2231         break;
 2232     case DISCOVERY_TYPE_FW:
 2233         if (access(FW_CONFIG_DIR, F_OK) != 0) {
 2234             if (mkdir(FW_CONFIG_DIR, 0660) != 0) {
 2235                 log_error("Could not make %s: %s",
 2236                       FW_CONFIG_DIR, strerror(errno));
 2237                 rc = ISCSI_ERR_IDBM;
 2238             }
 2239         }
 2240 
 2241         snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
 2242              FW_CONFIG_DIR, rec->name,
 2243              rec->conn[0].address, rec->conn[0].port, rec->tpgt,
 2244              rec->iface.name);
 2245         break;
 2246     case DISCOVERY_TYPE_STATIC:
 2247         if (access(STATIC_CONFIG_DIR, F_OK) != 0) {
 2248             if (mkdir(STATIC_CONFIG_DIR, 0660) != 0) {
 2249                 log_error("Could not make %s; %s",
 2250                       STATIC_CONFIG_DIR, strerror(errno));
 2251                 rc = ISCSI_ERR_IDBM;
 2252             }
 2253         }
 2254 
 2255         snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
 2256              STATIC_CONFIG_DIR, rec->name,
 2257              rec->conn[0].address, rec->conn[0].port, rec->tpgt,
 2258              rec->iface.name);
 2259         break;
 2260     case DISCOVERY_TYPE_ISNS:
 2261         if (access(ISNS_CONFIG_DIR, F_OK) != 0) {
 2262             if (mkdir(ISNS_CONFIG_DIR, 0660) != 0) {
 2263                 log_error("Could not make %s: %s",
 2264                       ISNS_CONFIG_DIR, strerror(errno));
 2265                 rc = ISCSI_ERR_IDBM;
 2266             }
 2267         }
 2268 
 2269         /*
 2270          * Older tools lumped all portals together in the
 2271          * isns config dir. In 2.0-872, the isns dir added
 2272          * a isns server (ddress and port) dir like sendtargets.
 2273          *
 2274          * If we found a older style link we return that so it
 2275          * can be removed. If this function is called for
 2276          * addition of a rec then the older link should have been
 2277          * removed and we break down below.
 2278          */
 2279         snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
 2280              ISNS_CONFIG_DIR,
 2281              rec->name, rec->conn[0].address,
 2282              rec->conn[0].port, rec->tpgt, rec->iface.name);
 2283         if (!stat(disc_portal, &statb)) {
 2284             log_debug(7, "using old style isns dir %s.",
 2285                   disc_portal);
 2286             break;
 2287         }
 2288 
 2289         snprintf(disc_portal, PATH_MAX, "%s/%s,%d",
 2290              ISNS_CONFIG_DIR, rec->disc_address, rec->disc_port);
 2291         if (!stat(disc_portal, &statb) && S_ISDIR(statb.st_mode)) {
 2292             /*
 2293              * if there is a dir for this isns server then
 2294              * assume we are using the new style links
 2295              */
 2296             snprintf(disc_portal, PATH_MAX,
 2297                  "%s/%s,%d/%s,%s,%d,%d,%s",
 2298                  ISNS_CONFIG_DIR, rec->disc_address,
 2299                  rec->disc_port, rec->name,
 2300                  rec->conn[0].address, rec->conn[0].port,
 2301                  rec->tpgt, rec->iface.name);
 2302             break;
 2303         }
 2304 
 2305         /* adding a older link */
 2306         snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
 2307              ISNS_CONFIG_DIR, rec->name, rec->conn[0].address,
 2308              rec->conn[0].port, rec->tpgt, rec->iface.name);
 2309         break;
 2310     case DISCOVERY_TYPE_SLP:
 2311     default:
 2312         rc = ISCSI_ERR_INVAL;
 2313     }
 2314 
 2315     return rc;
 2316 }
 2317 
 2318 int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec, int overwrite)
 2319 {
 2320     node_rec_t rec;
 2321     char *node_portal = NULL, *disc_portal;
 2322     int rc;
 2323 
 2324     rc = idbm_lock();
 2325     if (rc)
 2326         return rc;
 2327 
 2328     if (!idbm_rec_read(&rec, newrec->name, newrec->tpgt,
 2329                newrec->conn[0].address, newrec->conn[0].port,
 2330                &newrec->iface, true)) {
 2331         if (!overwrite) {
 2332             rc = 0;
 2333             goto unlock;
 2334         }
 2335 
 2336         rc = idbm_delete_node(&rec);
 2337         if (rc)
 2338             goto unlock;
 2339         log_debug(7, "overwriting existing record");
 2340     } else
 2341         log_debug(7, "adding new DB record");
 2342 
 2343     if (drec) {
 2344         newrec->disc_type = drec->type;
 2345         newrec->disc_port = drec->port;
 2346         strcpy(newrec->disc_address, drec->address);
 2347     }
 2348 
 2349     rc = idbm_rec_write(newrec, true);
 2350     /*
 2351      * if a old app passed in a bogus tpgt then we do not create links
 2352      * since it will set a different tpgt in another iscsiadm call
 2353      */
 2354     if (rc || !drec || newrec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
 2355         goto unlock;
 2356 
 2357     node_portal = calloc(2, PATH_MAX);
 2358     if (!node_portal) {
 2359         rc = ISCSI_ERR_NOMEM;
 2360         goto unlock;
 2361     }
 2362 
 2363     disc_portal = node_portal + PATH_MAX;
 2364     snprintf(node_portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
 2365          newrec->name, newrec->conn[0].address, newrec->conn[0].port,
 2366          newrec->tpgt);
 2367     rc = setup_disc_to_node_link(disc_portal, newrec);
 2368     if (rc)
 2369         goto unlock;
 2370 
 2371     log_debug(7, "node addition making link from %s to %s", node_portal,
 2372          disc_portal);
 2373 
 2374     if (symlink(node_portal, disc_portal)) {
 2375         if (errno == EEXIST)
 2376             log_debug(7, "link from %s to %s exists", node_portal,
 2377                   disc_portal);
 2378         else {
 2379             rc = ISCSI_ERR_IDBM;
 2380             log_error("Could not make link from disc source %s to "
 2381                  "node %s: %s", disc_portal, node_portal,
 2382                  strerror(errno));
 2383         }
 2384     }
 2385 unlock:
 2386     idbm_unlock();
 2387     free(node_portal);
 2388     return rc;
 2389 }
 2390 
 2391 static int idbm_bind_iface_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
 2392                     void *data, struct iface_rec *iface,
 2393                     struct list_head *bound_recs)
 2394 {
 2395     struct node_rec *rec, *tmp;
 2396     struct list_head new_recs;
 2397     int rc;
 2398 
 2399     INIT_LIST_HEAD(&new_recs);
 2400     rc = disc_node_fn(data, iface, &new_recs);
 2401     if (rc)
 2402         return rc;
 2403 
 2404     list_for_each_entry_safe(rec, tmp, &new_recs, list) {
 2405         list_del_init(&rec->list);
 2406         list_add_tail(&rec->list, bound_recs);
 2407         iface_copy(&rec->iface, iface);
 2408     }
 2409     return 0;
 2410 }
 2411 
 2412 static int
 2413 discovery_error_fatal(int err)
 2414 {
 2415     switch (err) {
 2416     /* No error */
 2417     case ISCSI_SUCCESS:
 2418     /* Transport errors or timeouts are not fatal */
 2419     case ISCSI_ERR_TRANS:
 2420     case ISCSI_ERR_TRANS_TIMEOUT:
 2421         return 0;
 2422     }
 2423     return 1;
 2424 }
 2425 
 2426 int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
 2427                   void *data, struct list_head *ifaces,
 2428                   struct list_head *bound_recs)
 2429 {
 2430     struct list_head def_ifaces;
 2431     struct node_rec *rec, *tmp_rec;
 2432     struct iface_rec *iface, *tmp_iface;
 2433     struct iscsi_transport *t;
 2434     int rc = 0, found = 0;
 2435 
 2436     INIT_LIST_HEAD(&def_ifaces);
 2437 
 2438     if (!ifaces || list_empty(ifaces)) {
 2439         iface_link_ifaces(&def_ifaces);
 2440 
 2441         list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
 2442             list_del(&iface->list);
 2443             t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
 2444             /*
 2445              * only auto bind to software iscsi if it is
 2446              * not the default iface (that is handled below)
 2447              */
 2448             if (!t || strcmp(t->name, DEFAULT_TRANSPORT) ||
 2449                 !strcmp(iface->name, DEFAULT_IFACENAME)) {
 2450                 free(iface);
 2451                 continue;
 2452             }
 2453 
 2454             rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
 2455                               bound_recs);
 2456             free(iface);
 2457             if (discovery_error_fatal(rc))
 2458                 goto fail;
 2459             found = 1;
 2460         }
 2461 
 2462         /* create default iface with old/default behavior */
 2463         if (!found) {
 2464             struct iface_rec def_iface;
 2465 
 2466             memset(&def_iface, 0, sizeof(struct iface_rec));
 2467             iface_setup_defaults(&def_iface);
 2468             return idbm_bind_iface_to_nodes(disc_node_fn, data,
 2469                             &def_iface, bound_recs);
 2470         }
 2471     } else {
 2472         list_for_each_entry(iface, ifaces, list) {
 2473             if (strcmp(iface->name, DEFAULT_IFACENAME) &&
 2474                 !iface_is_valid(iface)) {
 2475                 log_error("iface %s is not valid. Will not "
 2476                       "bind node to it. Iface settings "
 2477                       iface_fmt, iface->name,
 2478                       iface_str(iface));
 2479                 continue;
 2480             }
 2481 
 2482             rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
 2483                               bound_recs);
 2484             if (discovery_error_fatal(rc))
 2485                 goto fail;
 2486         }
 2487     }
 2488     return 0;
 2489 
 2490 fail:
 2491     list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
 2492         list_del(&iface->list);
 2493         free(iface);
 2494     }
 2495 
 2496     list_for_each_entry_safe(rec, tmp_rec, bound_recs, list) {
 2497         list_del(&rec->list);
 2498         free(rec);
 2499     }
 2500     return rc;
 2501 }
 2502 
 2503 static void idbm_rm_disc_node_links(char *disc_dir)
 2504 {
 2505     char *target = NULL, *tpgt = NULL, *port = NULL;
 2506     char *address = NULL, *iface_id = NULL;
 2507     DIR *disc_dirfd;
 2508     struct dirent *disc_dent;
 2509     node_rec_t *rec;
 2510 
 2511     rec = calloc(1, sizeof(*rec));
 2512     if (!rec)
 2513         return;
 2514 
 2515     disc_dirfd = opendir(disc_dir);
 2516     if (!disc_dirfd)
 2517         goto free_rec;
 2518 
 2519     /* rm links to nodes */
 2520     while ((disc_dent = readdir(disc_dirfd))) {
 2521         if (!strcmp(disc_dent->d_name, ".") ||
 2522             !strcmp(disc_dent->d_name, ".."))
 2523             continue;
 2524 
 2525 
 2526         if (get_params_from_disc_link(disc_dent->d_name, &target, &tpgt,
 2527                           &address, &port, &iface_id)) {
 2528             log_error("Improperly formed disc to node link");
 2529             continue;
 2530         }
 2531 
 2532         log_debug(5, "disc removal removing link %s %s %s %s",
 2533               target, address, port, iface_id);
 2534 
 2535         memset(rec, 0, sizeof(*rec));
 2536         strlcpy(rec->name, target, TARGET_NAME_MAXLEN);
 2537         rec->tpgt = atoi(tpgt);
 2538         rec->conn[0].port = atoi(port);
 2539         strlcpy(rec->conn[0].address, address, NI_MAXHOST);
 2540         strlcpy(rec->iface.name, iface_id, ISCSI_MAX_IFACE_LEN);
 2541 
 2542         if (idbm_delete_node(rec))
 2543             log_error("Could not delete node %s/%s/%s,%s/%s",
 2544                   NODE_CONFIG_DIR, target, address, port,
 2545                   iface_id);
 2546     }
 2547 
 2548     closedir(disc_dirfd);
 2549 free_rec:
 2550     free(rec);
 2551 }
 2552 
 2553 int idbm_delete_discovery(discovery_rec_t *drec)
 2554 {
 2555     char *portal;
 2556     struct stat statb;
 2557     int rc = 0;
 2558 
 2559     portal = calloc(1, PATH_MAX);
 2560     if (!portal)
 2561         return ISCSI_ERR_NOMEM;
 2562 
 2563     snprintf(portal, PATH_MAX, "%s/%s,%d",
 2564          disc_type_to_config_vals[drec->type].config_root,
 2565          drec->address, drec->port);
 2566     log_debug(5, "Removing config file %s", portal);
 2567 
 2568     if (stat(portal, &statb)) {
 2569         log_debug(5, "Could not stat %s to delete disc err %d",
 2570               portal, errno);
 2571         goto free_portal;
 2572     }
 2573 
 2574     if (S_ISDIR(statb.st_mode)) {
 2575         strlcat(portal, "/", PATH_MAX);
 2576         strlcat(portal,
 2577             disc_type_to_config_vals[drec->type].config_name,
 2578             PATH_MAX);
 2579     }
 2580 
 2581     if (unlink(portal))
 2582         log_debug(5, "Could not remove %s err %d", portal, errno);
 2583 
 2584     memset(portal, 0, PATH_MAX);
 2585     snprintf(portal, PATH_MAX, "%s/%s,%d",
 2586          disc_type_to_config_vals[drec->type].config_root,
 2587          drec->address, drec->port);
 2588     idbm_rm_disc_node_links(portal);
 2589 
 2590     /* rm portal dir */
 2591     if (S_ISDIR(statb.st_mode)) {
 2592         memset(portal, 0, PATH_MAX);
 2593         snprintf(portal, PATH_MAX, "%s/%s,%d",
 2594              disc_type_to_config_vals[drec->type].config_root,
 2595              drec->address, drec->port);
 2596         rmdir(portal);
 2597     }
 2598 
 2599 free_portal:
 2600     free(portal);
 2601     return rc;
 2602 }
 2603 
 2604 /*
 2605  * Backwards Compat or SLP:
 2606  * if there is no link then this is pre svn 780 version where
 2607  * we did not link the disc source and node
 2608  */
 2609 static int idbm_remove_disc_to_node_link(node_rec_t *rec,
 2610                      char *portal)
 2611 {
 2612     int rc = 0;
 2613     struct stat statb;
 2614     node_rec_t *tmprec;
 2615 
 2616     tmprec = malloc(sizeof(*tmprec));
 2617     if (!tmprec)
 2618         return ISCSI_ERR_NOMEM;
 2619 
 2620     memset(portal, 0, PATH_MAX);
 2621     snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
 2622          rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt,
 2623          rec->iface.name);
 2624 
 2625     rc = __idbm_rec_read(tmprec, portal, false);
 2626     if (rc) {
 2627         /* old style recs will not have tpgt or a link so skip */
 2628         rc = 0;
 2629         goto done;
 2630     }
 2631 
 2632     log_debug(7, "found drec %s %d",
 2633           tmprec->disc_address, tmprec->disc_port);
 2634     /* rm link from discovery source to node */
 2635     memset(portal, 0, PATH_MAX);
 2636     rc = setup_disc_to_node_link(portal, tmprec);
 2637     if (rc)
 2638         goto done;
 2639 
 2640     rc = idbm_lock();
 2641     if (rc)
 2642         goto done;
 2643 
 2644     if (!stat(portal, &statb)) {
 2645         if (unlink(portal)) {
 2646             log_error("Could not remove link %s: %s",
 2647                   portal, strerror(errno));
 2648             rc = ISCSI_ERR_IDBM;
 2649         } else
 2650             log_debug(7, "rmd %s", portal);
 2651     } else
 2652         log_debug(7, "Could not stat %s", portal);
 2653     idbm_unlock();
 2654 
 2655 done:
 2656     free(tmprec);
 2657     return rc;
 2658 }
 2659 
 2660 static int st_disc_filter(const struct dirent *dir)
 2661 {
 2662     return strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") &&
 2663         strcmp(dir->d_name, ST_CONFIG_NAME);
 2664 }
 2665 
 2666 int idbm_delete_node(node_rec_t *rec)
 2667 {
 2668     struct stat statb;
 2669     char *portal;
 2670     int rc = 0, dir_rm_rc = 0;
 2671 
 2672     portal = calloc(1, PATH_MAX);
 2673     if (!portal)
 2674         return ISCSI_ERR_NOMEM;
 2675 
 2676     rc = idbm_remove_disc_to_node_link(rec, portal);
 2677     if (rc)
 2678         goto free_portal;
 2679 
 2680     memset(portal, 0, PATH_MAX);
 2681     snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
 2682          rec->name, rec->conn[0].address, rec->conn[0].port);
 2683     log_debug(5, "Removing config file %s iface id %s",
 2684           portal, rec->iface.name);
 2685 
 2686     rc = idbm_lock();
 2687     if (rc)
 2688         goto free_portal;
 2689 
 2690     if (!stat(portal, &statb))
 2691         goto rm_conf;
 2692 
 2693     snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
 2694          rec->name, rec->conn[0].address, rec->conn[0].port,
 2695          rec->tpgt, rec->iface.name);
 2696     log_debug(5, "Removing config file %s", portal);
 2697 
 2698     if (!stat(portal, &statb))
 2699         goto rm_conf;
 2700 
 2701     log_error("Could not stat %s to delete node: %s",
 2702           portal, strerror(errno));
 2703     rc = ISCSI_ERR_IDBM;
 2704     goto unlock;
 2705 
 2706 rm_conf:
 2707     if (unlink(portal)) {
 2708         log_error("Could not remove %s: %s", portal, strerror(errno));
 2709         rc = ISCSI_ERR_IDBM;
 2710         goto unlock;
 2711     }
 2712 
 2713     memset(portal, 0, PATH_MAX);
 2714     snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
 2715          rec->name, rec->conn[0].address, rec->conn[0].port,
 2716          rec->tpgt);
 2717     if (!stat(portal, &statb)) {
 2718         struct dirent **namelist;
 2719         int n, i;
 2720 
 2721         memset(portal, 0, PATH_MAX);
 2722         snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
 2723              rec->name, rec->conn[0].address, rec->conn[0].port,
 2724              rec->tpgt);
 2725         n = scandir(portal, &namelist, st_disc_filter, alphasort);
 2726         if (n < 0)
 2727             goto free_portal;
 2728         if (n == 0)
 2729             dir_rm_rc = rmdir(portal);
 2730 
 2731         for (i = 0; i < n; i++)
 2732             free(namelist[i]);
 2733         free(namelist);
 2734     }
 2735     /* rm target dir */
 2736     if (!dir_rm_rc) {
 2737         memset(portal, 0, PATH_MAX);
 2738         snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name);
 2739         rmdir(portal);
 2740     }
 2741 unlock:
 2742     idbm_unlock();
 2743 free_portal:
 2744     free(portal);
 2745     return rc;
 2746 }
 2747 
 2748 void
 2749 idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg)
 2750 {
 2751     idbm_sync_config();
 2752     memcpy(cfg, &db->drec_st.u.sendtargets,
 2753            sizeof(struct iscsi_sendtargets_config));
 2754 }
 2755 
 2756 void
 2757 idbm_isns_defaults(struct iscsi_isns_config *cfg)
 2758 {
 2759     idbm_sync_config();
 2760     memcpy(cfg, &db->drec_isns.u.isns,
 2761            sizeof(struct iscsi_isns_config));
 2762 }
 2763 
 2764 void
 2765 idbm_slp_defaults(struct iscsi_slp_config *cfg)
 2766 {
 2767     memcpy(cfg, &db->drec_slp.u.slp,
 2768            sizeof(struct iscsi_slp_config));
 2769 }
 2770 
 2771 int
 2772 idbm_session_autoscan(struct iscsi_session *session)
 2773 {
 2774     if (session)
 2775         return session->nrec.session.scan;
 2776     return db->nrec.session.scan;
 2777 }
 2778 
 2779 struct user_param *idbm_alloc_user_param(char *name, char *value)
 2780 {
 2781     struct user_param *param;
 2782 
 2783     param = calloc(1, sizeof(*param));
 2784     if (!param)
 2785         return NULL;
 2786 
 2787     INIT_LIST_HEAD(&param->list);
 2788 
 2789     param->name = strdup(name);
 2790     if (!param->name)
 2791         goto free_param;
 2792 
 2793     param->value = strdup(value);
 2794     if (!param->value)
 2795         goto free_name;
 2796 
 2797     return param;
 2798 
 2799 free_name:
 2800     free(param->name);
 2801 free_param:
 2802     free(param);
 2803     return NULL;
 2804 }
 2805 
 2806 int idbm_node_set_rec_from_param(struct list_head *params, node_rec_t *rec,
 2807                  int verify)
 2808 {
 2809     struct user_param *param;
 2810     recinfo_t *info;
 2811     int rc = 0;
 2812 
 2813     if (list_empty(params))
 2814         return 0;
 2815 
 2816     info = idbm_recinfo_alloc(MAX_KEYS);
 2817     if (!info)
 2818         return ISCSI_ERR_NOMEM;
 2819 
 2820     idbm_recinfo_node(rec, info);
 2821 
 2822     if (verify) {
 2823         list_for_each_entry(param, params, list) {
 2824             rc = idbm_verify_param(info, param->name);
 2825             if (rc)
 2826                 goto free_info;
 2827         }
 2828     }
 2829 
 2830     list_for_each_entry(param, params, list) {
 2831         rc = idbm_rec_update_param(info, param->name, param->value, 0);
 2832         if (rc) {
 2833             if (rc == ISCSI_ERR_INVAL)
 2834                 log_error("Unknown parameter %s.", param->name);
 2835             goto free_info;
 2836         }
 2837     }
 2838 
 2839 free_info:
 2840     free(info);
 2841     return rc;
 2842 }
 2843 
 2844 int idbm_node_set_param(void *data, node_rec_t *rec)
 2845 {
 2846     int rc;
 2847 
 2848     rc = idbm_node_set_rec_from_param(data, rec, 1);
 2849     if (rc)
 2850         return rc;
 2851 
 2852     return idbm_rec_write(rec, true);
 2853 }
 2854 
 2855 int idbm_discovery_set_param(void *data, discovery_rec_t *rec)
 2856 {
 2857     struct list_head *params = data;
 2858     struct user_param *param;
 2859     recinfo_t *info;
 2860     int rc = 0;
 2861 
 2862     info = idbm_recinfo_alloc(MAX_KEYS);
 2863     if (!info)
 2864         return ISCSI_ERR_NOMEM;
 2865 
 2866     idbm_recinfo_discovery((discovery_rec_t *)rec, info);
 2867 
 2868     list_for_each_entry(param, params, list) {
 2869         rc = idbm_verify_param(info, param->name);
 2870         if (rc)
 2871             goto free_info;
 2872     }
 2873 
 2874     list_for_each_entry(param, params, list) {
 2875         rc = idbm_rec_update_param(info, param->name, param->value, 0);
 2876         if (rc)
 2877             goto free_info;
 2878     }
 2879 
 2880     rc = idbm_discovery_write((discovery_rec_t *)rec);
 2881     if (rc)
 2882         goto free_info;
 2883 
 2884 free_info:
 2885     free(info);
 2886     return rc;
 2887 }
 2888 
 2889 int idbm_init(idbm_get_config_file_fn *fn)
 2890 {
 2891     /* make sure root db dir is there */
 2892     if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) {
 2893         if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) {
 2894             log_error("Could not make %s %d", ISCSI_CONFIG_ROOT,
 2895                    errno);
 2896             return errno;
 2897         }
 2898     }
 2899 
 2900     db = malloc(sizeof(idbm_t));
 2901     if (!db) {
 2902         log_error("out of memory on idbm allocation");
 2903         return ISCSI_ERR_NOMEM;
 2904     }
 2905     memset(db, 0, sizeof(idbm_t));
 2906     db->get_config_file = fn;
 2907     return 0;
 2908 }
 2909 
 2910 void idbm_terminate(void)
 2911 {
 2912     if (db)
 2913         free(db);
 2914 }
 2915 
 2916 /**
 2917  * idbm_create_rec - allocate and setup a node record
 2918  * @targetname: target name
 2919  * @tgpt: target portal group
 2920  * @ip: ip address of portal
 2921  * @port: port of portal
 2922  * @iface: iscsi iface info
 2923  * @verbose: flag indicating whether to log ifaces setup errors
 2924  *
 2925  * The iface only needs to have the name set. This function will
 2926  * read in the other values.
 2927  */
 2928 struct node_rec *idbm_create_rec(char *targetname, int tpgt, char *ip,
 2929                  int port, struct iface_rec *iface,
 2930                  int verbose)
 2931 {
 2932     struct node_rec *rec;
 2933 
 2934     rec = calloc(1, sizeof(*rec));
 2935     if (!rec) {
 2936         log_error("Could not not allocate memory to create node "
 2937               "record.");
 2938         return NULL;
 2939     }
 2940 
 2941     idbm_node_setup_defaults(rec);
 2942     if (targetname)
 2943         strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
 2944     rec->tpgt = tpgt;
 2945     rec->conn[0].port = port;
 2946     if (ip)
 2947         strlcpy(rec->conn[0].address, ip, NI_MAXHOST);
 2948     memset(&rec->iface, 0, sizeof(struct iface_rec));
 2949     if (iface) {
 2950         iface_copy(&rec->iface, iface);
 2951         if (strlen(iface->name)) {
 2952             if (iface_conf_read(&rec->iface)) {
 2953                 if (verbose)
 2954                     log_error("Could not read iface info "
 2955                           "for %s.", iface->name);
 2956                 goto free_rec;
 2957             }
 2958         }
 2959     }
 2960     return rec;
 2961 free_rec:
 2962     free(rec);
 2963     return NULL;
 2964 }
 2965 
 2966 struct node_rec *idbm_create_rec_from_boot_context(struct boot_context *context)
 2967 {
 2968     struct node_rec *rec;
 2969 
 2970     /* tpgt hard coded to 1 ??? */
 2971     rec = idbm_create_rec(context->targetname, 1,
 2972                   context->target_ipaddr, context->target_port,
 2973                   NULL, 1);
 2974     if (!rec) {
 2975         log_error("Could not setup rec for fw discovery login.");
 2976         return NULL;
 2977     }
 2978 
 2979     iface_setup_defaults(&rec->iface);
 2980     strlcpy(rec->session.auth.username, context->chap_name,
 2981         sizeof(context->chap_name));
 2982     strlcpy((char *)rec->session.auth.password, context->chap_password,
 2983         sizeof(context->chap_password));
 2984     strlcpy(rec->session.auth.username_in, context->chap_name_in,
 2985         sizeof(context->chap_name_in));
 2986     strlcpy((char *)rec->session.auth.password_in,
 2987         context->chap_password_in,
 2988         sizeof(context->chap_password_in));
 2989     rec->session.auth.password_length =
 2990                 strlen((char *)context->chap_password);
 2991     rec->session.auth.password_in_length =
 2992                 strlen((char *)context->chap_password_in);
 2993     strlcpy(rec->session.boot_root, context->boot_root,
 2994         sizeof(context->boot_root));
 2995     strlcpy(rec->session.boot_nic, context->boot_nic,
 2996         sizeof(context->boot_nic));
 2997     strlcpy(rec->session.boot_target, context->boot_target,
 2998         sizeof(context->boot_target));
 2999 
 3000     iface_setup_from_boot_context(&rec->iface, context);
 3001 
 3002     return rec;
 3003 }
 3004 
 3005 void idbm_node_setup_defaults(node_rec_t *rec)
 3006 {
 3007     int i;
 3008 
 3009     memset(rec, 0, sizeof(node_rec_t));
 3010 
 3011     INIT_LIST_HEAD(&rec->list);
 3012 
 3013     rec->tpgt = PORTAL_GROUP_TAG_UNKNOWN;
 3014     rec->disc_type = DISCOVERY_TYPE_STATIC;
 3015     rec->leading_login = 0;
 3016     rec->session.cmds_max = CMDS_MAX;
 3017     rec->session.xmit_thread_priority = XMIT_THREAD_PRIORITY;
 3018     rec->session.initial_cmdsn = 0;
 3019     rec->session.queue_depth = QUEUE_DEPTH;
 3020     rec->session.nr_sessions = 1;
 3021     rec->session.initial_login_retry_max = DEF_INITIAL_LOGIN_RETRIES_MAX;
 3022     rec->session.reopen_max = DEF_SESSION_REOPEN_MAX;
 3023     rec->session.auth.authmethod = 0;
 3024     rec->session.auth.password_length = 0;
 3025     rec->session.auth.password_in_length = 0;
 3026     rec->session.err_timeo.abort_timeout = DEF_ABORT_TIMEO;
 3027     rec->session.err_timeo.lu_reset_timeout = DEF_LU_RESET_TIMEO;
 3028     rec->session.err_timeo.tgt_reset_timeout = DEF_TGT_RESET_TIMEO;
 3029     rec->session.err_timeo.host_reset_timeout = DEF_HOST_RESET_TIMEO;
 3030     rec->session.timeo.replacement_timeout = DEF_REPLACEMENT_TIMEO;
 3031     rec->session.info = NULL;
 3032     rec->session.sid = 0;
 3033     rec->session.multiple = 0;
 3034     rec->session.scan = DEF_INITIAL_SCAN;
 3035     idbm_setup_session_defaults(&rec->session.iscsi);
 3036 
 3037     for (i=0; i<ISCSI_CONN_MAX; i++) {
 3038         rec->conn[i].startup = ISCSI_STARTUP_MANUAL;
 3039         rec->conn[i].port = ISCSI_LISTEN_PORT;
 3040         rec->conn[i].tcp.window_size = TCP_WINDOW_SIZE;
 3041         rec->conn[i].tcp.type_of_service = 0;
 3042         rec->conn[i].timeo.login_timeout= DEF_LOGIN_TIMEO;
 3043         rec->conn[i].timeo.logout_timeout= DEF_LOGOUT_TIMEO;
 3044         rec->conn[i].timeo.auth_timeout = 45;
 3045 
 3046         rec->conn[i].timeo.noop_out_interval = DEF_NOOP_OUT_INTERVAL;
 3047         rec->conn[i].timeo.noop_out_timeout = DEF_NOOP_OUT_TIMEO;
 3048 
 3049         idbm_setup_conn_defaults(&rec->conn[i].iscsi);
 3050     }
 3051 
 3052     iface_setup_defaults(&rec->iface);
 3053 }
 3054 
 3055 struct node_rec *
 3056 idbm_find_rec_in_list(struct list_head *rec_list, char *targetname, char *addr,
 3057               int port, struct iface_rec *iface)
 3058 {
 3059     struct node_rec *rec;
 3060 
 3061     list_for_each_entry(rec, rec_list, list) {
 3062         if (__iscsi_match_session(rec, targetname, addr, port, iface,
 3063                       MATCH_ANY_SID))
 3064             return rec;
 3065     }
 3066 
 3067     return NULL;
 3068 }