usr/config.h: fix comment for struct iscsi_session_timeout_config
[open-iscsi.git] / usr / idbm.c
blobd3383fce23af45a45903e49b8b44cf6e98b6f1a7
1 /*
2 * iSCSI Discovery Database Library
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
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.
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.
19 * See the file COPYING included with this distribution for more details.
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 <sys/stat.h>
31 #include <sys/file.h>
33 #include "idbm.h"
34 #include "idbm_fields.h"
35 #include "log.h"
36 #include "iscsi_util.h"
37 #include "iscsi_settings.h"
38 #include "transport.h"
39 #include "iscsi_sysfs.h"
40 #include "iface.h"
41 #include "sysdeps.h"
42 #include "fw_context.h"
43 #include "iscsi_err.h"
45 #define IDBM_HIDE 0 /* Hide parameter when print. */
46 #define IDBM_SHOW 1 /* Show parameter when print. */
47 #define IDBM_MASKED 2 /* Show "stars" instead of real value when print */
49 static struct idbm *db;
51 #define __recinfo_str(_key, _info, _rec, _name, _show, _n, _mod) do { \
52 _info[_n].type = TYPE_STR; \
53 strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
54 if (strlen((char*)_rec->_name)) \
55 strlcpy((char*)_info[_n].value, (char*)_rec->_name, \
56 VALUE_MAXVAL); \
57 _info[_n].data = &_rec->_name; \
58 _info[_n].data_len = sizeof(_rec->_name); \
59 _info[_n].visible = _show; \
60 _info[_n].can_modify = _mod; \
61 _n++; \
62 } while(0)
64 #define __recinfo_int(_key, _info, _rec, _name, _show, _n, _mod) do { \
65 _info[_n].type = TYPE_INT; \
66 strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
67 snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \
68 _info[_n].data = &_rec->_name; \
69 _info[_n].data_len = sizeof(_rec->_name); \
70 _info[_n].visible = _show; \
71 _info[_n].can_modify = _mod; \
72 _n++; \
73 } while(0)
75 #define __recinfo_uint8(_key, _info, _rec, _name, _show, _n, _mod) do { \
76 _info[_n].type = TYPE_UINT8; \
77 strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
78 snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \
79 _info[_n].data = &_rec->_name; \
80 _info[_n].data_len = sizeof(_rec->_name); \
81 _info[_n].visible = _show; \
82 _info[_n].can_modify = _mod; \
83 _n++; \
84 } while (0)
86 #define __recinfo_uint16(_key, _info, _rec, _name, _show, _n, _mod) do { \
87 _info[_n].type = TYPE_UINT16; \
88 strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
89 snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \
90 _info[_n].data = &_rec->_name; \
91 _info[_n].data_len = sizeof(_rec->_name); \
92 _info[_n].visible = _show; \
93 _info[_n].can_modify = _mod; \
94 _n++; \
95 } while (0)
97 #define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \
98 _info[_n].type = TYPE_INT_O; \
99 strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
100 if (_rec->_name == 0) strlcpy(_info[_n].value, _op0, VALUE_MAXVAL); \
101 if (_rec->_name == 1) strlcpy(_info[_n].value, _op1, VALUE_MAXVAL); \
102 _info[_n].data = &_rec->_name; \
103 _info[_n].data_len = sizeof(_rec->_name); \
104 _info[_n].visible = _show; \
105 _info[_n].opts[0] = _op0; \
106 _info[_n].opts[1] = _op1; \
107 _info[_n].numopts = 2; \
108 _info[_n].can_modify = _mod; \
109 _n++; \
110 } while(0)
112 #define __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, \
113 _mod) do { \
114 __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod); \
115 _n--; \
116 if (_rec->_name == 2) strlcpy(_info[_n].value, _op2, VALUE_MAXVAL);\
117 _info[_n].opts[2] = _op2; \
118 _info[_n].numopts = 3; \
119 _n++; \
120 } while(0)
122 #define __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n, \
123 _mod) do { \
124 __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, _mod); \
125 _n--; \
126 if (_rec->_name == 3) strlcpy(_info[_n].value, _op3, VALUE_MAXVAL); \
127 _info[_n].opts[3] = _op3; \
128 _info[_n].numopts = 4; \
129 _n++; \
130 } while(0)
132 #define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
133 _op4,_n, _mod) do { \
134 __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
135 _n,_mod); \
136 _n--; \
137 if (_rec->_name == 4) strlcpy(_info[_n].value, _op4, VALUE_MAXVAL); \
138 _info[_n].opts[4] = _op4; \
139 _info[_n].numopts = 5; \
140 _n++; \
141 } while(0)
143 #define __recinfo_int_o6(_key,_info,_rec,_name,_show,_op0,_op1,_op2, \
144 _op3,_op4,_op5,_n,_mod) do { \
145 __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \
146 _op4,_n,_mod); \
147 _n--; \
148 if (_rec->_name == 5) strlcpy(_info[_n].value, _op5, VALUE_MAXVAL); \
149 _info[_n].opts[5] = _op5; \
150 _info[_n].numopts = 6; \
151 _n++; \
152 } while(0)
154 static void
155 idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri)
157 int num = 0;
159 __recinfo_int_o2(DISC_STARTUP, ri, r, startup, IDBM_SHOW,
160 "manual", "automatic", num, 1);
161 __recinfo_int_o6(DISC_TYPE, ri, r, type, IDBM_SHOW,
162 "sendtargets", "isns", "offload_send_targets", "slp",
163 "static", "fw", num, 0);
164 switch (r->type) {
165 case DISCOVERY_TYPE_SENDTARGETS:
166 __recinfo_str(DISC_ST_ADDR, ri, r,
167 address, IDBM_SHOW, num, 0);
168 __recinfo_int(DISC_ST_PORT, ri, r,
169 port, IDBM_SHOW, num, 0);
170 __recinfo_int_o2(DISC_ST_AUTH_METHOD, ri, r,
171 u.sendtargets.auth.authmethod,
172 IDBM_SHOW, "None", "CHAP", num, 1);
173 __recinfo_str(DISC_ST_USERNAME, ri, r,
174 u.sendtargets.auth.username, IDBM_SHOW, num, 1);
175 __recinfo_str(DISC_ST_PASSWORD, ri, r,
176 u.sendtargets.auth.password, IDBM_MASKED, num, 1);
177 __recinfo_int(DISC_ST_PASSWORD_LEN, ri, r,
178 u.sendtargets.auth.password_length, IDBM_HIDE, num, 1);
179 __recinfo_str(DISC_ST_USERNAME_IN, ri, r,
180 u.sendtargets.auth.username_in, IDBM_SHOW, num, 1);
181 __recinfo_str(DISC_ST_PASSWORD_IN, ri, r,
182 u.sendtargets.auth.password_in, IDBM_MASKED, num, 1);
183 __recinfo_int(DISC_ST_PASSWORD_IN_LEN, ri, r,
184 u.sendtargets.auth.password_in_length, IDBM_HIDE,
185 num, 1);
186 __recinfo_int(DISC_ST_LOGIN_TMO, ri, r,
187 u.sendtargets.conn_timeo.login_timeout,
188 IDBM_SHOW, num, 1);
189 __recinfo_int_o2(DISC_ST_USE_DISC_DAEMON, ri, r,
190 u.sendtargets.use_discoveryd,
191 IDBM_SHOW, "No", "Yes", num, 1);
192 __recinfo_int(DISC_ST_DISC_DAEMON_POLL_INVAL, ri, r,
193 u.sendtargets.discoveryd_poll_inval,
194 IDBM_SHOW, num, 1);
195 __recinfo_int(DISC_ST_REOPEN_MAX, ri, r,
196 u.sendtargets.reopen_max,
197 IDBM_SHOW, num, 1);
198 __recinfo_int(DISC_ST_AUTH_TMO, ri, r,
199 u.sendtargets.conn_timeo.auth_timeout,
200 IDBM_SHOW, num, 1);
201 __recinfo_int(DISC_ST_ACTIVE_TMO, ri, r,
202 u.sendtargets.conn_timeo.active_timeout,
203 IDBM_SHOW, num, 1);
204 __recinfo_int(DISC_ST_MAX_RECV_DLEN, ri, r,
205 u.sendtargets.conn_conf.MaxRecvDataSegmentLength,
206 IDBM_SHOW, num, 1);
207 break;
208 case DISCOVERY_TYPE_ISNS:
209 __recinfo_str(DISC_ISNS_ADDR, ri, r,
210 address, IDBM_SHOW, num, 0);
211 __recinfo_int(DISC_ISNS_PORT, ri, r,
212 port, IDBM_SHOW, num, 0);
213 __recinfo_int_o2(DISC_ISNS_USE_DISC_DAEMON, ri, r,
214 u.isns.use_discoveryd,
215 IDBM_SHOW, "No", "Yes", num, 1);
216 __recinfo_int(DISC_ISNS_DISC_DAEMON_POLL_INVAL, ri, r,
217 u.isns.discoveryd_poll_inval,
218 IDBM_SHOW, num, 1);
219 break;
220 default:
221 break;
225 void
226 idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
228 int num = 0, i;
230 __recinfo_str(NODE_NAME, ri, r, name, IDBM_SHOW, num, 0);
231 __recinfo_int(NODE_TPGT, ri, r, tpgt, IDBM_SHOW, num, 0);
232 __recinfo_int_o3(NODE_STARTUP, ri, r, startup,
233 IDBM_SHOW, "manual", "automatic", "onboot", num, 1);
234 __recinfo_int_o2(NODE_LEADING_LOGIN, ri, r, leading_login, IDBM_SHOW,
235 "No", "Yes", num, 1);
237 * Note: because we do not add the iface.iscsi_ifacename to
238 * sysfs iscsiadm does some weird matching. We can change the iface
239 * values if a session is not running, but node record ifaces values
240 * have to be changed and so do the iface record ones.
242 * Users should nornmally not want to change the iface ones
243 * in the node record directly and instead do it through
244 * the iface mode which will do the right thing (althought that
245 * needs some locking).
247 __recinfo_str(IFACE_HWADDR, ri, r, iface.hwaddress, IDBM_SHOW, num, 1);
248 __recinfo_str(IFACE_IPADDR, ri, r, iface.ipaddress, IDBM_SHOW, num, 1);
249 __recinfo_str(IFACE_ISCSINAME, ri, r, iface.name, IDBM_SHOW, num, 1);
250 __recinfo_str(IFACE_NETNAME, ri, r, iface.netdev, IDBM_SHOW, num, 1);
252 * svn 780 compat: older versions used node.transport_name and
253 * rec->transport_name
255 __recinfo_str(IFACE_TRANSPORTNAME, ri, r, iface.transport_name,
256 IDBM_SHOW, num, 1);
257 __recinfo_str(IFACE_INAME, ri, r, iface.iname, IDBM_SHOW, num, 1);
258 __recinfo_str(NODE_DISC_ADDR, ri, r, disc_address, IDBM_SHOW,
259 num, 0);
260 __recinfo_int(NODE_DISC_PORT, ri, r, disc_port, IDBM_SHOW,
261 num, 0);
262 __recinfo_int_o6(NODE_DISC_TYPE, ri, r, disc_type, IDBM_SHOW,
263 "send_targets", "isns", "offload_send_targets", "slp",
264 "static", "fw", num, 0);
265 __recinfo_int(SESSION_INIT_CMDSN, ri, r,
266 session.initial_cmdsn, IDBM_SHOW, num, 1);
267 __recinfo_int(SESSION_INIT_LOGIN_RETRY, ri, r,
268 session.initial_login_retry_max, IDBM_SHOW, num, 1);
269 __recinfo_int(SESSION_XMIT_THREAD_PRIORITY, ri, r,
270 session.xmit_thread_priority, IDBM_SHOW, num, 1);
271 __recinfo_int(SESSION_CMDS_MAX, ri, r,
272 session.cmds_max, IDBM_SHOW, num, 1);
273 __recinfo_int(SESSION_QDEPTH, ri, r,
274 session.queue_depth, IDBM_SHOW, num, 1);
275 __recinfo_int(SESSION_NR_SESSIONS, ri, r,
276 session.nr_sessions, IDBM_SHOW, num, 1);
277 __recinfo_int_o2(SESSION_AUTH_METHOD, ri, r, session.auth.authmethod,
278 IDBM_SHOW, "None", "CHAP", num, 1);
279 __recinfo_str(SESSION_USERNAME, ri, r,
280 session.auth.username, IDBM_SHOW, num, 1);
281 __recinfo_str(SESSION_PASSWORD, ri, r,
282 session.auth.password, IDBM_MASKED, num, 1);
283 __recinfo_int(SESSION_PASSWORD_LEN, ri, r,
284 session.auth.password_length, IDBM_HIDE, num, 1);
285 __recinfo_str(SESSION_USERNAME_IN, ri, r,
286 session.auth.username_in, IDBM_SHOW, num, 1);
287 __recinfo_str(SESSION_PASSWORD_IN, ri, r,
288 session.auth.password_in, IDBM_MASKED, num, 1);
289 __recinfo_int(SESSION_PASSWORD_IN_LEN, ri, r,
290 session.auth.password_in_length, IDBM_HIDE, num, 1);
291 __recinfo_int(SESSION_REPLACEMENT_TMO, ri, r,
292 session.timeo.replacement_timeout,
293 IDBM_SHOW, num, 1);
294 __recinfo_int(SESSION_ABORT_TMO, ri, r,
295 session.err_timeo.abort_timeout,
296 IDBM_SHOW, num, 1);
297 __recinfo_int(SESSION_LU_RESET_TMO, ri, r,
298 session.err_timeo.lu_reset_timeout,
299 IDBM_SHOW, num, 1);
300 __recinfo_int(SESSION_TGT_RESET_TMO, ri, r,
301 session.err_timeo.tgt_reset_timeout,
302 IDBM_SHOW, num, 1);
303 __recinfo_int(SESSION_HOST_RESET_TMO, ri, r,
304 session.err_timeo.host_reset_timeout,
305 IDBM_SHOW, num, 1);
306 __recinfo_int_o2(SESSION_FAST_ABORT, ri, r,
307 session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes",
308 num, 1);
309 __recinfo_int_o2(SESSION_INITIAL_R2T, ri, r,
310 session.iscsi.InitialR2T, IDBM_SHOW,
311 "No", "Yes", num, 1);
312 __recinfo_int_o2(SESSION_IMM_DATA, ri, r,
313 session.iscsi.ImmediateData,
314 IDBM_SHOW, "No", "Yes", num, 1);
315 __recinfo_int(SESSION_FIRST_BURST, ri, r,
316 session.iscsi.FirstBurstLength, IDBM_SHOW, num, 1);
317 __recinfo_int(SESSION_MAX_BURST, ri, r,
318 session.iscsi.MaxBurstLength, IDBM_SHOW, num, 1);
319 __recinfo_int(SESSION_DEF_TIME2RETAIN, ri, r,
320 session.iscsi.DefaultTime2Retain, IDBM_SHOW, num, 1);
321 __recinfo_int(SESSION_DEF_TIME2WAIT, ri, r,
322 session.iscsi.DefaultTime2Wait, IDBM_SHOW, num, 1);
323 __recinfo_int(SESSION_MAX_CONNS, ri, r,
324 session.iscsi.MaxConnections, IDBM_SHOW, num, 1);
325 __recinfo_int(SESSION_MAX_R2T, ri, r,
326 session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num, 1);
327 __recinfo_int(SESSION_ERL, ri, r,
328 session.iscsi.ERL, IDBM_SHOW, num, 1);
330 for (i = 0; i < ISCSI_CONN_MAX; i++) {
331 char key[NAME_MAXVAL];
333 sprintf(key, CONN_ADDR, i);
334 __recinfo_str(key, ri, r, conn[i].address, IDBM_SHOW, num, 0);
335 sprintf(key, CONN_PORT, i);
336 __recinfo_int(key, ri, r, conn[i].port, IDBM_SHOW, num, 0);
337 sprintf(key, CONN_STARTUP, i);
338 __recinfo_int_o3(key, ri, r, conn[i].startup, IDBM_SHOW,
339 "manual", "automatic", "onboot", num, 1);
340 sprintf(key, CONN_WINDOW_SIZE, i);
341 __recinfo_int(key, ri, r, conn[i].tcp.window_size,
342 IDBM_SHOW, num, 1);
343 sprintf(key, CONN_SERVICE_TYPE, i);
344 __recinfo_int(key, ri, r, conn[i].tcp.type_of_service,
345 IDBM_SHOW, num, 1);
346 sprintf(key, CONN_LOGOUT_TMO, i);
347 __recinfo_int(key, ri, r, conn[i].timeo.logout_timeout,
348 IDBM_SHOW, num, 1);
349 sprintf(key, CONN_LOGIN_TMO, i);
350 __recinfo_int(key, ri, r, conn[i].timeo.login_timeout,
351 IDBM_SHOW, num, 1);
352 sprintf(key, CONN_AUTH_TMO, i);
353 __recinfo_int(key, ri, r, conn[i].timeo.auth_timeout,
354 IDBM_SHOW, num, 1);
356 sprintf(key, CONN_NOP_INT, i);
357 __recinfo_int(key, ri, r, conn[i].timeo.noop_out_interval,
358 IDBM_SHOW, num, 1);
359 sprintf(key, CONN_NOP_TMO, i);
360 __recinfo_int(key, ri, r, conn[i].timeo.noop_out_timeout,
361 IDBM_SHOW, num, 1);
363 sprintf(key, CONN_MAX_XMIT_DLEN, i);
364 __recinfo_int(key, ri, r,
365 conn[i].iscsi.MaxXmitDataSegmentLength, IDBM_SHOW,
366 num, 1);
367 sprintf(key, CONN_MAX_RECV_DLEN, i);
368 __recinfo_int(key, ri, r,
369 conn[i].iscsi.MaxRecvDataSegmentLength, IDBM_SHOW,
370 num, 1);
371 sprintf(key, CONN_HDR_DIGEST, i);
372 __recinfo_int_o4(key, ri, r, conn[i].iscsi.HeaderDigest,
373 IDBM_SHOW, "None", "CRC32C", "CRC32C,None",
374 "None,CRC32C", num, 1);
375 sprintf(key, CONN_DATA_DIGEST, i);
376 __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW,
377 "None", "CRC32C", "CRC32C,None",
378 "None,CRC32C", num, 1);
379 sprintf(key, CONN_IFMARKER, i);
380 __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW,
381 "No", "Yes", num, 1);
382 sprintf(key, CONN_OFMARKER, i);
383 __recinfo_int_o2(key, ri, r, conn[i].iscsi.OFMarker, IDBM_SHOW,
384 "No", "Yes", num, 1);
388 void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
390 int num = 0;
392 __recinfo_str(IFACE_ISCSINAME, ri, r, name, IDBM_SHOW, num, 0);
393 __recinfo_str(IFACE_NETNAME, ri, r, netdev, IDBM_SHOW, num, 1);
394 __recinfo_str(IFACE_IPADDR, ri, r, ipaddress, IDBM_SHOW, num, 1);
395 __recinfo_str(IFACE_HWADDR, ri, r, hwaddress, IDBM_SHOW, num, 1);
396 __recinfo_str(IFACE_TRANSPORTNAME, ri, r, transport_name,
397 IDBM_SHOW, num, 1);
398 __recinfo_str(IFACE_INAME, ri, r, iname, IDBM_SHOW, num, 1);
399 __recinfo_str(IFACE_BOOT_PROTO, ri, r, bootproto, IDBM_SHOW, num, 1);
400 __recinfo_str(IFACE_SUBNET_MASK, ri, r, subnet_mask,
401 IDBM_SHOW, num, 1);
402 __recinfo_str(IFACE_GATEWAY, ri, r, gateway, IDBM_SHOW, num, 1);
403 __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, ipv6_autocfg,
404 IDBM_SHOW, num, 1);
405 __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, linklocal_autocfg,
406 IDBM_SHOW, num, 1);
407 __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, router_autocfg,
408 IDBM_SHOW, num, 1);
409 __recinfo_str(IFACE_LINKLOCAL, ri, r, ipv6_linklocal,
410 IDBM_SHOW, num, 1);
411 __recinfo_str(IFACE_ROUTER, ri, r, ipv6_router, IDBM_SHOW, num, 1);
412 __recinfo_str(IFACE_STATE, ri, r, state, IDBM_SHOW, num, 1);
413 __recinfo_uint16(IFACE_VLAN_ID, ri, r, vlan_id, IDBM_SHOW, num, 1);
414 __recinfo_uint8(IFACE_VLAN_PRIORITY, ri, r, vlan_priority,
415 IDBM_SHOW, num, 1);
416 __recinfo_str(IFACE_VLAN_STATE, ri, r, vlan_state, IDBM_SHOW, num, 1);
417 __recinfo_int(IFACE_NUM, ri, r, iface_num, IDBM_SHOW, num, 1);
418 __recinfo_uint16(IFACE_MTU, ri, r, mtu, IDBM_SHOW, num, 1);
419 __recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1);
422 recinfo_t *idbm_recinfo_alloc(int max_keys)
424 recinfo_t *info;
426 info = malloc(sizeof(recinfo_t)*max_keys);
427 if (!info)
428 return NULL;
429 memset(info, 0, sizeof(recinfo_t)*max_keys);
430 return info;
433 void idbm_print(int type, void *rec, int show, FILE *f)
435 int i;
436 recinfo_t *info;
438 info = idbm_recinfo_alloc(MAX_KEYS);
439 if (!info)
440 return;
442 switch (type) {
443 case IDBM_PRINT_TYPE_DISCOVERY:
444 idbm_recinfo_discovery((discovery_rec_t*)rec, info);
445 break;
446 case IDBM_PRINT_TYPE_NODE:
447 idbm_recinfo_node((node_rec_t*)rec, info);
448 break;
449 case IDBM_PRINT_TYPE_IFACE:
450 idbm_recinfo_iface((struct iface_rec *)rec, info);
451 break;
454 fprintf(f, "%s\n", ISCSI_BEGIN_REC);
455 for (i = 0; i < MAX_KEYS; i++) {
456 if (!info[i].visible)
457 continue;
458 if (!show && info[i].visible == IDBM_MASKED) {
459 if (*(char*)info[i].data) {
460 fprintf(f, "%s = ********\n", info[i].name);
461 continue;
463 /* fall through */
466 if (strlen(info[i].value))
467 fprintf(f, "%s = %s\n", info[i].name, info[i].value);
468 else if (f == stdout)
469 fprintf(f, "%s = <empty>\n", info[i].name);
471 fprintf(f, "%s\n", ISCSI_END_REC);
473 free(info);
476 static void
477 idbm_setup_session_defaults(struct iscsi_session_operational_config *conf)
479 conf->InitialR2T = 0;
480 conf->ImmediateData = 1;
481 conf->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
482 conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
483 conf->DefaultTime2Wait = ISCSI_DEF_TIME2WAIT;
484 conf->DefaultTime2Retain = 0;
485 conf->MaxConnections = 1;
486 conf->MaxOutstandingR2T = 1;
487 conf->ERL = 0;
488 conf->FastAbort = 1;
491 static void idbm_setup_conn_defaults(struct iscsi_conn_operational_config *conf)
493 conf->MaxXmitDataSegmentLength = 0;
494 conf->MaxRecvDataSegmentLength = DEF_INI_MAX_RECV_SEG_LEN;
495 conf->HeaderDigest = CONFIG_DIGEST_NEVER;
496 conf->DataDigest = CONFIG_DIGEST_NEVER;
497 conf->IFMarker = 0;
498 conf->OFMarker = 0;
501 static void
502 idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type)
504 memset(rec, 0, sizeof(discovery_rec_t));
506 rec->startup = ISCSI_STARTUP_MANUAL;
507 rec->type = type;
508 switch (type) {
509 case DISCOVERY_TYPE_SENDTARGETS:
510 rec->u.sendtargets.discoveryd_poll_inval = 30;
511 rec->u.sendtargets.use_discoveryd = 0;
512 rec->u.sendtargets.reopen_max = 5;
513 rec->u.sendtargets.auth.authmethod = 0;
514 rec->u.sendtargets.auth.password_length = 0;
515 rec->u.sendtargets.auth.password_in_length = 0;
516 rec->u.sendtargets.conn_timeo.login_timeout=15;
517 rec->u.sendtargets.conn_timeo.auth_timeout = 45;
518 rec->u.sendtargets.conn_timeo.active_timeout=30;
519 idbm_setup_session_defaults(&rec->u.sendtargets.session_conf);
520 idbm_setup_conn_defaults(&rec->u.sendtargets.conn_conf);
521 /* override def setting */
522 rec->u.sendtargets.conn_conf.MaxRecvDataSegmentLength =
523 DEF_INI_DISC_MAX_RECV_SEG_LEN;
524 break;
525 case DISCOVERY_TYPE_SLP:
526 rec->u.slp.interfaces = NULL;
527 rec->u.slp.scopes = NULL;
528 rec->u.slp.poll_interval = 5 * 60; /* 5 minutes */
529 rec->u.slp.auth.authmethod = 0;
530 rec->u.slp.auth.password_length = 0;
531 rec->u.slp.auth.password_in_length = 0;
532 rec->u.slp.auth.password_in_length = 0;
533 break;
534 case DISCOVERY_TYPE_ISNS:
535 rec->u.isns.use_discoveryd = 0;
536 rec->u.isns.discoveryd_poll_inval = -1;
537 break;
538 default:
539 break;
543 int idbm_rec_update_param(recinfo_t *info, char *name, char *value,
544 int line_number)
546 int i;
547 int passwd_done = 0;
548 char passwd_len[8];
550 setup_passwd_len:
551 for (i=0; i<MAX_KEYS; i++) {
552 if (!strcmp(name, info[i].name)) {
553 int j;
554 log_debug(7, "updated '%s', '%s' => '%s'", name,
555 info[i].value, value);
556 /* parse recinfo by type */
557 if (info[i].type == TYPE_INT) {
558 if (!info[i].data)
559 continue;
561 *(int*)info[i].data =
562 strtoul(value, NULL, 10);
563 goto updated;
564 } else if (info[i].type == TYPE_UINT8) {
565 if (!info[i].data)
566 continue;
568 *(uint8_t *)info[i].data =
569 strtoul(value, NULL, 10);
570 goto updated;
571 } else if (info[i].type == TYPE_UINT16) {
572 if (!info[i].data)
573 continue;
575 *(uint16_t *)info[i].data =
576 strtoul(value, NULL, 10);
577 goto updated;
578 } else if (info[i].type == TYPE_STR) {
579 if (!info[i].data)
580 continue;
582 strlcpy((char*)info[i].data,
583 value, info[i].data_len);
584 goto updated;
586 for (j=0; j<info[i].numopts; j++) {
587 if (!strcmp(value, info[i].opts[j])) {
588 if (!info[i].data)
589 continue;
591 *(int*)info[i].data = j;
592 goto updated;
595 if (line_number) {
596 log_warning("config file line %d contains "
597 "unknown value format '%s' for "
598 "parameter name '%s'",
599 line_number, value, name);
600 } else {
601 log_error("unknown value format '%s' for "
602 "parameter name '%s'", value, name);
604 break;
608 return ISCSI_ERR_INVAL;
610 updated:
611 strlcpy((char*)info[i].value, value, VALUE_MAXVAL);
613 #define check_password_param(_param) \
614 if (!passwd_done && !strcmp(#_param, name)) { \
615 passwd_done = 1; \
616 name = #_param "_length"; \
617 snprintf(passwd_len, 8, "%d", (int)strlen(value)); \
618 value = passwd_len; \
619 goto setup_passwd_len; \
622 check_password_param(node.session.auth.password);
623 check_password_param(node.session.auth.password_in);
624 check_password_param(discovery.sendtargets.auth.password);
625 check_password_param(discovery.sendtargets.auth.password_in);
626 check_password_param(discovery.slp.auth.password);
627 check_password_param(discovery.slp.auth.password_in);
629 return 0;
633 * TODO: we can also check for valid values here.
635 int idbm_verify_param(recinfo_t *info, char *name)
637 int i;
639 for (i = 0; i < MAX_KEYS; i++) {
640 if (strcmp(name, info[i].name))
641 continue;
643 log_debug(7, "verify %s %d\n", name, info[i].can_modify);
644 if (info[i].can_modify)
645 return 0;
646 else {
647 log_error("Cannot modify %s. It is used to look up "
648 "the record and cannot be changed.", name);
649 return ISCSI_ERR_INVAL;
653 log_error("Cannot modify %s. Invalid param name.", name);
654 return ISCSI_ERR_INVAL;
657 void idbm_recinfo_config(recinfo_t *info, FILE *f)
659 char name[NAME_MAXVAL];
660 char value[VALUE_MAXVAL];
661 char *line, *nl, buffer[2048];
662 int line_number = 0;
663 int c = 0, i;
665 fseek(f, 0, SEEK_SET);
667 /* process the config file */
668 do {
669 line = fgets(buffer, sizeof (buffer), f);
670 line_number++;
671 if (!line)
672 continue;
674 nl = line + strlen(line) - 1;
675 if (*nl != '\n') {
676 log_warning("Config file line %d too long.",
677 line_number);
678 continue;
681 line = strstrip(line);
682 /* process any non-empty, non-comment lines */
683 if (!*line || *line == '\0' || *line == '\n' || *line == '#')
684 continue;
686 /* parse name */
687 i=0; nl = line; *name = 0;
688 while (*nl && !isspace(c = *nl) && *nl != '=') {
689 *(name+i) = *nl; i++; nl++;
691 if (!*nl) {
692 log_warning("config file line %d do not has value",
693 line_number);
694 continue;
696 *(name+i)=0; nl++;
697 /* skip after-name traling spaces */
698 while (*nl && isspace(c = *nl)) nl++;
699 if (*nl && *nl != '=') {
700 log_warning("config file line %d has not '=' sepa",
701 line_number);
702 continue;
704 /* skip '=' sepa */
705 nl++;
706 /* skip after-sepa traling spaces */
707 while (*nl && isspace(c = *nl)) nl++;
708 if (!*nl) {
709 log_warning("config file line %d do not has value",
710 line_number);
711 continue;
713 /* parse value */
714 i=0; *value = 0;
715 while (*nl) {
716 *(value+i) = *nl; i++; nl++;
718 *(value+i) = 0;
720 idbm_rec_update_param(info, name, value, line_number);
721 } while (line);
725 * TODO: remove db's copy of nrec and infos
727 static void idbm_sync_config(void)
729 char *config_file;
730 FILE *f;
732 /* in case of no configuration file found we just
733 * initialize default node and default discovery records
734 * from hard-coded default values */
735 idbm_node_setup_defaults(&db->nrec);
736 idbm_discovery_setup_defaults(&db->drec_st, DISCOVERY_TYPE_SENDTARGETS);
737 idbm_discovery_setup_defaults(&db->drec_slp, DISCOVERY_TYPE_SLP);
738 idbm_discovery_setup_defaults(&db->drec_isns, DISCOVERY_TYPE_ISNS);
740 idbm_recinfo_discovery(&db->drec_st, db->dinfo_st);
741 idbm_recinfo_discovery(&db->drec_slp, db->dinfo_slp);
742 idbm_recinfo_discovery(&db->drec_isns, db->dinfo_isns);
743 idbm_recinfo_node(&db->nrec, db->ninfo);
745 if (!db->get_config_file) {
746 log_debug(1, "Could not get config file. No config file fn\n");
747 return;
750 config_file = db->get_config_file();
751 if (!config_file) {
752 log_debug(1, "Could not get config file for sync config\n");
753 return;
756 f = fopen(config_file, "r");
757 if (!f) {
758 log_debug(1, "cannot open configuration file %s. "
759 "Default location is %s.\n",
760 config_file, CONFIG_FILE);
761 return;
763 log_debug(5, "updating defaults from '%s'", config_file);
765 idbm_recinfo_config(db->dinfo_st, f);
766 idbm_recinfo_config(db->dinfo_slp, f);
767 idbm_recinfo_config(db->dinfo_isns, f);
768 idbm_recinfo_config(db->ninfo, f);
769 fclose(f);
771 /* update password lengths */
772 if (*db->drec_st.u.sendtargets.auth.password)
773 db->drec_st.u.sendtargets.auth.password_length =
774 strlen((char*)db->drec_st.u.sendtargets.auth.password);
775 if (*db->drec_st.u.sendtargets.auth.password_in)
776 db->drec_st.u.sendtargets.auth.password_in_length =
777 strlen((char*)db->drec_st.u.sendtargets.auth.password_in);
778 if (*db->drec_slp.u.slp.auth.password)
779 db->drec_slp.u.slp.auth.password_length =
780 strlen((char*)db->drec_slp.u.slp.auth.password);
781 if (*db->drec_slp.u.slp.auth.password_in)
782 db->drec_slp.u.slp.auth.password_in_length =
783 strlen((char*)db->drec_slp.u.slp.auth.password_in);
784 if (*db->nrec.session.auth.password)
785 db->nrec.session.auth.password_length =
786 strlen((char*)db->nrec.session.auth.password);
787 if (*db->nrec.session.auth.password_in)
788 db->nrec.session.auth.password_in_length =
789 strlen((char*)db->nrec.session.auth.password_in);
792 void idbm_node_setup_from_conf(node_rec_t *rec)
794 memset(rec, 0, sizeof(*rec));
795 idbm_node_setup_defaults(rec);
796 idbm_sync_config();
797 memcpy(rec, &db->nrec, sizeof(*rec));
800 int idbm_print_discovery_info(discovery_rec_t *rec, int show)
802 idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, show, stdout);
803 return 1;
806 int idbm_print_node_info(void *data, node_rec_t *rec)
808 int show = *((int *)data);
810 idbm_print(IDBM_PRINT_TYPE_NODE, rec, show, stdout);
811 return 0;
814 int idbm_print_iface_info(void *data, struct iface_rec *iface)
816 int show = *((int *)data);
818 idbm_print(IDBM_PRINT_TYPE_IFACE, iface, show, stdout);
819 return 0;
822 int idbm_print_node_flat(void *data, node_rec_t *rec)
824 if (strchr(rec->conn[0].address, '.'))
825 printf("%s:%d,%d %s\n", rec->conn[0].address, rec->conn[0].port,
826 rec->tpgt, rec->name);
827 else
828 printf("[%s]:%d,%d %s\n", rec->conn[0].address,
829 rec->conn[0].port, rec->tpgt, rec->name);
830 return 0;
833 int idbm_print_node_tree(struct node_rec *last_rec, struct node_rec *rec,
834 char *prefix)
836 if (!last_rec || strcmp(last_rec->name, rec->name)) {
837 printf("%sTarget: %s\n", prefix, rec->name);
838 if (last_rec)
839 memset(last_rec, 0, sizeof(node_rec_t));
842 if (!last_rec ||
843 ((strcmp(last_rec->conn[0].address, rec->conn[0].address) ||
844 last_rec->conn[0].port != rec->conn[0].port))) {
845 if (strchr(rec->conn[0].address, '.'))
846 printf("%s\tPortal: %s:%d,%d\n", prefix,
847 rec->conn[0].address,
848 rec->conn[0].port, rec->tpgt);
849 else
850 printf("%s\tPortal: [%s]:%d,%d\n", prefix,
851 rec->conn[0].address,
852 rec->conn[0].port, rec->tpgt);
855 if (last_rec)
856 memcpy(last_rec, rec, sizeof(node_rec_t));
857 return 0;
860 int idbm_print_node_and_iface_tree(void *data, node_rec_t *rec)
862 idbm_print_node_tree(data, rec, "");
863 printf("\t\tIface Name: %s\n", rec->iface.name);
864 return 0;
867 static int
868 get_params_from_disc_link(char *link, char **target, char **tpgt,
869 char **address, char **port, char **ifaceid)
871 (*target) = link;
872 *address = strchr(*target, ',');
873 if (!(*address))
874 return ISCSI_ERR_INVAL;
875 *(*address)++ = '\0';
876 *port = strchr(*address, ',');
877 if (!(*port))
878 return ISCSI_ERR_INVAL;
879 *(*port)++ = '\0';
880 *tpgt = strchr(*port, ',');
881 if (!(*tpgt))
882 return ISCSI_ERR_INVAL;
883 *(*tpgt)++ = '\0';
884 *ifaceid = strchr(*tpgt, ',');
885 if (!(*ifaceid))
886 return ISCSI_ERR_INVAL;
887 *(*ifaceid)++ = '\0';
888 return 0;
891 int idbm_lock(void)
893 int fd, i, ret;
895 if (db->refs > 0) {
896 db->refs++;
897 return 0;
900 if (access(LOCK_DIR, F_OK) != 0) {
901 if (mkdir(LOCK_DIR, 0660) != 0) {
902 log_error("Could not open %s: %s\n", LOCK_DIR,
903 strerror(errno));
904 return ISCSI_ERR_IDBM;
908 fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666);
909 if (fd >= 0)
910 close(fd);
912 for (i = 0; i < 3000; i++) {
913 ret = link(LOCK_FILE, LOCK_WRITE_FILE);
914 if (ret == 0)
915 break;
917 if (errno != EEXIST) {
918 log_error("Maybe you are not root?");
919 log_error("Could not lock discovery DB: %s: %s",
920 LOCK_WRITE_FILE, strerror(errno));
921 return ISCSI_ERR_IDBM;
922 } else if (i == 0)
923 log_debug(2, "Waiting for discovery DB lock");
925 usleep(10000);
928 db->refs = 1;
929 return 0;
932 void idbm_unlock(void)
934 if (db->refs > 1) {
935 db->refs--;
936 return;
939 db->refs = 0;
940 unlink(LOCK_WRITE_FILE);
944 * Backwards Compat:
945 * If the portal is a file then we are doing the old style default
946 * session behavior (svn pre 780).
948 static FILE *idbm_open_rec_r(char *portal, char *config)
950 struct stat statb;
952 log_debug(5, "Looking for config file %s config %s.", portal, config);
954 if (stat(portal, &statb)) {
955 log_debug(5, "Could not stat %s err %d.", portal, errno);
956 return NULL;
959 if (S_ISDIR(statb.st_mode)) {
960 strlcat(portal, "/", PATH_MAX);
961 strlcat(portal, config, PATH_MAX);
963 return fopen(portal, "r");
966 static int __idbm_rec_read(node_rec_t *out_rec, char *conf)
968 recinfo_t *info;
969 FILE *f;
970 int rc = 0;
972 info = idbm_recinfo_alloc(MAX_KEYS);
973 if (!info)
974 return ISCSI_ERR_NOMEM;
976 rc = idbm_lock();
977 if (rc)
978 goto free_info;
980 f = fopen(conf, "r");
981 if (!f) {
982 log_debug(5, "Could not open %s err %s\n", conf,
983 strerror(errno));
984 rc = ISCSI_ERR_IDBM;
985 goto unlock;
988 memset(out_rec, 0, sizeof(*out_rec));
989 idbm_node_setup_defaults(out_rec);
990 idbm_recinfo_node(out_rec, info);
991 idbm_recinfo_config(info, f);
992 fclose(f);
994 unlock:
995 idbm_unlock();
996 free_info:
997 free(info);
998 return rc;
1002 idbm_rec_read(node_rec_t *out_rec, char *targetname, int tpgt,
1003 char *ip, int port, struct iface_rec *iface)
1005 struct stat statb;
1006 char *portal;
1007 int rc;
1009 portal = calloc(1, PATH_MAX);
1010 if (!portal)
1011 return ISCSI_ERR_IDBM;
1013 /* try old style portal as config */
1014 snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
1015 targetname, ip, port);
1016 log_debug(5, "rec read looking for config file %s.", portal);
1017 if (!stat(portal, &statb))
1018 goto read;
1020 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
1021 targetname, ip, port, tpgt, iface->name);
1022 log_debug(5, "rec read looking for config file %s.", portal);
1023 if (!strlen(iface->name)) {
1024 rc = ISCSI_ERR_INVAL;
1025 goto free_portal;
1028 if (stat(portal, &statb)) {
1029 log_debug(5, "Could not stat %s: %s.", portal, strerror(errno));
1030 free(portal);
1031 return ISCSI_ERR_IDBM;
1034 read:
1035 rc = __idbm_rec_read(out_rec, portal);
1036 free_portal:
1037 free(portal);
1038 return rc;
1041 static int print_discovered_flat(void *data, node_rec_t *rec)
1043 struct discovery_rec *drec = data;
1045 if (rec->disc_type != drec->type)
1046 goto no_match;
1048 if (drec->type == DISCOVERY_TYPE_SENDTARGETS ||
1049 drec->type == DISCOVERY_TYPE_ISNS) {
1050 if (rec->disc_port != drec->port ||
1051 strcmp(rec->disc_address, drec->address))
1052 goto no_match;
1055 idbm_print_node_flat(NULL, rec);
1056 return 0;
1057 no_match:
1058 return -1;
1061 struct discovered_tree_info {
1062 struct discovery_rec *drec;
1063 struct node_rec *last_rec;
1066 static int print_discovered_tree(void *data, node_rec_t *rec)
1068 struct discovered_tree_info *tree_info = data;
1069 struct discovery_rec *drec = tree_info->drec;
1071 if (rec->disc_type != drec->type)
1072 goto no_match;
1074 if (strlen(drec->address)) {
1075 if (rec->disc_port != drec->port ||
1076 strcmp(rec->disc_address, drec->address))
1077 goto no_match;
1080 idbm_print_node_and_iface_tree(tree_info->last_rec, rec);
1081 return 0;
1082 no_match:
1083 return -1;
1086 static int idbm_print_discovered(discovery_rec_t *drec, int info_level)
1088 int num_found = 0;
1090 if (info_level < 1)
1091 idbm_for_each_rec(&num_found, drec, print_discovered_flat);
1092 else {
1093 struct discovered_tree_info tree_info;
1094 struct node_rec last_rec;
1096 memset(&last_rec, 0, sizeof(struct node_rec));
1098 tree_info.drec = drec;
1099 tree_info.last_rec = &last_rec;
1101 idbm_for_each_rec(&num_found, &tree_info, print_discovered_tree);
1103 return num_found;
1106 static int idbm_for_each_drec(int type, char *config_root, void *data,
1107 idbm_drec_op_fn *fn)
1109 DIR *entity_dirfd;
1110 struct dirent *entity_dent;
1111 int found = 0;
1112 discovery_rec_t drec;
1113 char *tmp_port;
1115 entity_dirfd = opendir(config_root);
1116 if (!entity_dirfd)
1117 return found;
1119 while ((entity_dent = readdir(entity_dirfd))) {
1120 if (!strcmp(entity_dent->d_name, ".") ||
1121 !strcmp(entity_dent->d_name, ".."))
1122 continue;
1124 log_debug(5, "found %s\n", entity_dent->d_name);
1126 tmp_port = strchr(entity_dent->d_name, ',');
1127 if (!tmp_port)
1128 continue;
1130 * pre 872 tools dumped the target portal symlinks in the isns
1131 * dir instead of the server. If we find one of those links
1132 * (by checking if there is a valid port) we skip it.
1134 if (strchr(tmp_port, ':') || strchr(tmp_port, '.'))
1135 continue;
1136 *tmp_port++ = '\0';
1138 memset(&drec, 0, sizeof(drec));
1139 if (idbm_discovery_read(&drec, type, entity_dent->d_name,
1140 atoi(tmp_port))) {
1141 log_error("Could not read discovery record for "
1142 "%s:%s.", entity_dent->d_name, tmp_port);
1143 continue;
1146 if (!fn(data, &drec))
1147 found++;
1149 closedir(entity_dirfd);
1150 return found;
1153 int idbm_for_each_st_drec(void *data, idbm_drec_op_fn *fn)
1155 return idbm_for_each_drec(DISCOVERY_TYPE_SENDTARGETS, ST_CONFIG_DIR,
1156 data, fn);
1159 int idbm_for_each_isns_drec(void *data, idbm_drec_op_fn *fn)
1161 return idbm_for_each_drec(DISCOVERY_TYPE_ISNS, ISNS_CONFIG_DIR,
1162 data, fn);
1165 static int __idbm_print_all_by_drec(void *data, struct discovery_rec *drec)
1167 int info_level = *(int *)data;
1169 if (info_level >= 1) {
1170 printf("DiscoveryAddress: %s,%d\n",
1171 drec->address, drec->port);
1172 idbm_print_discovered(drec, info_level);
1173 } else
1174 printf("%s:%d via %s\n", drec->address, drec->port,
1175 drec->type == DISCOVERY_TYPE_ISNS ?
1176 "isns" : "sendtargets");
1177 return 0;
1180 static int idbm_print_all_st(int info_level)
1182 int rc;
1184 rc = idbm_for_each_st_drec(&info_level, __idbm_print_all_by_drec);
1185 if (rc < 0)
1186 return 0;
1187 return rc;
1190 static int idbm_print_all_isns(int info_level)
1192 int rc;
1194 rc = idbm_for_each_isns_drec(&info_level, __idbm_print_all_by_drec);
1195 if (rc < 0)
1196 return 0;
1197 return rc;
1200 int idbm_print_all_discovery(int info_level)
1202 discovery_rec_t *drec;
1203 int found = 0, tmp;
1205 if (info_level < 1) {
1206 found = idbm_print_all_st(info_level);
1207 found += idbm_print_all_isns(info_level);
1208 return found;
1211 drec = calloc(1, sizeof(*drec));
1212 if (!drec)
1213 return 0;
1215 tmp = 0;
1216 printf("SENDTARGETS:\n");
1217 tmp = idbm_print_all_st(info_level);
1218 if (!tmp)
1219 printf("No targets found.\n");
1220 found += tmp;
1221 tmp = 0;
1223 printf("iSNS:\n");
1224 tmp = idbm_print_all_isns(info_level);
1225 if (!tmp) {
1227 * pre 872 tools did not store the server ip,port so
1228 * we drop down here, to just look for target portals.
1230 drec->type = DISCOVERY_TYPE_ISNS;
1231 tmp = idbm_print_discovered(drec, info_level);
1232 if (!tmp)
1233 printf("No targets found.\n");
1235 found += tmp;
1236 tmp = 0;
1238 printf("STATIC:\n");
1239 drec->type = DISCOVERY_TYPE_STATIC;
1240 tmp = idbm_print_discovered(drec, info_level);
1241 if (!tmp)
1242 printf("No targets found.\n");
1243 found += tmp;
1244 tmp = 0;
1246 printf("FIRMWARE:\n");
1247 drec->type = DISCOVERY_TYPE_FW;
1248 tmp = idbm_print_discovered(drec, info_level);
1249 if (!tmp)
1250 printf("No targets found.\n");
1251 found += tmp;
1253 free(drec);
1254 return found;
1258 * idbm_for_each_iface - iterate over bound iface recs
1259 * @found: nr of recs found so far
1260 * @data: data pointer passed to fn
1261 * @fn: iterator function ran over each bound iface rec
1262 * @targetname: rec's target name
1263 * @tpgt: rec's portal group tag
1264 * @ip: rec's ip address
1265 * @port: rec's port
1267 * This will run fn over all recs with the {targetname,tpgt,ip,port}
1268 * id. It does not iterate over the ifaces setup in /etc/iscsi/ifaces.
1270 * fn should return -1 if it skipped the rec, a ISCSI_ERR error code if
1271 * the operation failed or 0 if fn was run successfully.
1273 static int idbm_for_each_iface(int *found, void *data,
1274 idbm_iface_op_fn *fn,
1275 char *targetname, int tpgt, char *ip, int port)
1277 DIR *iface_dirfd;
1278 struct dirent *iface_dent;
1279 struct stat statb;
1280 node_rec_t rec;
1281 int rc = 0;
1282 char *portal;
1284 portal = calloc(1, PATH_MAX);
1285 if (!portal)
1286 return ISCSI_ERR_NOMEM;
1288 if (tpgt >= 0)
1289 goto read_iface;
1291 /* old style portal as a config */
1292 snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, targetname,
1293 ip, port);
1294 if (stat(portal, &statb)) {
1295 log_error("iface iter could not stat %s.", portal);
1296 rc = ISCSI_ERR_IDBM;
1297 goto free_portal;
1300 rc = __idbm_rec_read(&rec, portal);
1301 if (rc)
1302 goto free_portal;
1304 rc = fn(data, &rec);
1305 if (!rc)
1306 (*found)++;
1307 else if (rc == -1)
1308 rc = 0;
1309 goto free_portal;
1311 read_iface:
1312 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
1313 targetname, ip, port, tpgt);
1315 iface_dirfd = opendir(portal);
1316 if (!iface_dirfd) {
1317 log_error("iface iter could not read dir %s.", portal);
1318 rc = ISCSI_ERR_IDBM;
1319 goto free_portal;
1322 while ((iface_dent = readdir(iface_dirfd))) {
1323 int curr_rc;
1325 if (!strcmp(iface_dent->d_name, ".") ||
1326 !strcmp(iface_dent->d_name, ".."))
1327 continue;
1329 log_debug(5, "iface iter found %s.", iface_dent->d_name);
1330 memset(portal, 0, PATH_MAX);
1331 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
1332 targetname, ip, port, tpgt, iface_dent->d_name);
1333 if (__idbm_rec_read(&rec, portal))
1334 continue;
1336 curr_rc = fn(data, &rec);
1337 /* less than zero means it was not a match */
1338 if (curr_rc > 0 && !rc)
1339 rc = curr_rc;
1340 else if (curr_rc == 0)
1341 (*found)++;
1344 closedir(iface_dirfd);
1345 free_portal:
1346 free(portal);
1347 return rc;
1351 * backwards compat
1352 * The portal could be a file or dir with interfaces
1354 int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn,
1355 char *targetname)
1357 DIR *portal_dirfd;
1358 struct dirent *portal_dent;
1359 int rc = 0;
1360 char *portal;
1362 portal = calloc(1, PATH_MAX);
1363 if (!portal)
1364 return ISCSI_ERR_NOMEM;
1366 snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, targetname);
1367 portal_dirfd = opendir(portal);
1368 if (!portal_dirfd) {
1369 rc = ISCSI_ERR_IDBM;
1370 goto done;
1373 while ((portal_dent = readdir(portal_dirfd))) {
1374 char *tmp_port, *tmp_tpgt;
1375 int curr_rc;
1377 if (!strcmp(portal_dent->d_name, ".") ||
1378 !strcmp(portal_dent->d_name, ".."))
1379 continue;
1381 log_debug(5, "found %s\n", portal_dent->d_name);
1382 tmp_port = strchr(portal_dent->d_name, ',');
1383 if (!tmp_port)
1384 continue;
1385 *tmp_port++ = '\0';
1386 tmp_tpgt = strchr(tmp_port, ',');
1387 if (tmp_tpgt)
1388 *tmp_tpgt++ = '\0';
1390 curr_rc = fn(found, data, targetname,
1391 tmp_tpgt ? atoi(tmp_tpgt) : -1,
1392 portal_dent->d_name, atoi(tmp_port));
1393 /* less than zero means it was not a match */
1394 if (curr_rc > 0 && !rc)
1395 rc = curr_rc;
1397 closedir(portal_dirfd);
1398 done:
1399 free(portal);
1400 return rc;
1403 int idbm_for_each_node(int *found, void *data, idbm_node_op_fn *fn)
1405 DIR *node_dirfd;
1406 struct dirent *node_dent;
1407 int rc = 0;
1409 *found = 0;
1411 node_dirfd = opendir(NODE_CONFIG_DIR);
1412 if (!node_dirfd)
1413 /* on start up node dir may not be created */
1414 return 0;
1416 while ((node_dent = readdir(node_dirfd))) {
1417 int curr_rc;
1419 if (!strcmp(node_dent->d_name, ".") ||
1420 !strcmp(node_dent->d_name, ".."))
1421 continue;
1423 log_debug(5, "searching %s\n", node_dent->d_name);
1424 curr_rc = fn(found, data, node_dent->d_name);
1425 /* less than zero means it was not a match */
1426 if (curr_rc > 0 && !rc)
1427 rc = curr_rc;
1430 closedir(node_dirfd);
1431 return rc;
1434 static int iface_fn(void *data, node_rec_t *rec)
1436 struct rec_op_data *op_data = data;
1438 return op_data->fn(op_data->data, rec);
1441 static int portal_fn(int *found, void *data, char *targetname,
1442 int tpgt, char *ip, int port)
1444 return idbm_for_each_iface(found, data, iface_fn, targetname,
1445 tpgt, ip, port);
1448 static int node_fn(int *found, void *data, char *targetname)
1450 return idbm_for_each_portal(found, data, portal_fn, targetname);
1453 int idbm_for_each_rec(int *found, void *data, idbm_iface_op_fn *fn)
1455 struct rec_op_data op_data;
1457 memset(&op_data, 0, sizeof(struct rec_op_data));
1458 op_data.data = data;
1459 op_data.fn = fn;
1461 return idbm_for_each_node(found, &op_data, node_fn);
1464 static struct {
1465 char *config_root;
1466 char *config_name;
1467 } disc_type_to_config_vals[] = {
1468 { ST_CONFIG_DIR, ST_CONFIG_NAME },
1469 { ISNS_CONFIG_DIR, ISNS_CONFIG_NAME },
1473 idbm_discovery_read(discovery_rec_t *out_rec, int drec_type,
1474 char *addr, int port)
1476 recinfo_t *info;
1477 char *portal;
1478 int rc = 0;
1479 FILE *f;
1481 if (drec_type > 1)
1482 return ISCSI_ERR_INVAL;
1484 memset(out_rec, 0, sizeof(discovery_rec_t));
1486 info = idbm_recinfo_alloc(MAX_KEYS);
1487 if (!info)
1488 return ISCSI_ERR_NOMEM;
1490 portal = malloc(PATH_MAX);
1491 if (!portal) {
1492 rc = ISCSI_ERR_NOMEM;
1493 goto free_info;
1496 snprintf(portal, PATH_MAX, "%s/%s,%d",
1497 disc_type_to_config_vals[drec_type].config_root,
1498 addr, port);
1499 log_debug(5, "Looking for config file %s\n", portal);
1501 rc = idbm_lock();
1502 if (rc)
1503 goto free_info;
1505 f = idbm_open_rec_r(portal,
1506 disc_type_to_config_vals[drec_type].config_name);
1507 if (!f) {
1508 log_debug(1, "Could not open %s: %s\n", portal,
1509 strerror(errno));
1510 rc = ISCSI_ERR_IDBM;
1511 goto unlock;
1514 idbm_discovery_setup_defaults(out_rec, drec_type);
1515 idbm_recinfo_discovery(out_rec, info);
1516 idbm_recinfo_config(info, f);
1517 fclose(f);
1519 unlock:
1520 idbm_unlock();
1521 free_info:
1522 free(portal);
1523 free(info);
1524 return rc;
1528 * Backwards Compat:
1529 * If the portal is a file then we are doing the old style default
1530 * session behavior (svn pre 780).
1532 static FILE *idbm_open_rec_w(char *portal, char *config)
1534 struct stat statb;
1535 FILE *f;
1536 int err;
1538 log_debug(5, "Looking for config file %s\n", portal);
1540 err = stat(portal, &statb);
1541 if (err)
1542 goto mkdir_portal;
1544 if (!S_ISDIR(statb.st_mode)) {
1546 * Old style portal as a file. Let's update it.
1548 if (unlink(portal)) {
1549 log_error("Could not convert %s to %s/%s. "
1550 "err %d\n", portal, portal,
1551 config, errno);
1552 return NULL;
1555 mkdir_portal:
1556 if (mkdir(portal, 0660) != 0) {
1557 log_error("Could not make dir %s err %d\n",
1558 portal, errno);
1559 return NULL;
1563 strlcat(portal, "/", PATH_MAX);
1564 strlcat(portal, config, PATH_MAX);
1565 f = fopen(portal, "w");
1566 if (!f)
1567 log_error("Could not open %s err %d\n", portal, errno);
1568 return f;
1571 static int idbm_rec_write(node_rec_t *rec)
1573 struct stat statb;
1574 FILE *f;
1575 char *portal;
1576 int rc = 0;
1578 portal = malloc(PATH_MAX);
1579 if (!portal) {
1580 log_error("Could not alloc portal\n");
1581 return ISCSI_ERR_NOMEM;
1584 snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR);
1585 if (access(portal, F_OK) != 0) {
1586 if (mkdir(portal, 0660) != 0) {
1587 log_error("Could not make %s: %s\n", portal,
1588 strerror(errno));
1589 rc = ISCSI_ERR_IDBM;
1590 goto free_portal;
1594 snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name);
1595 if (access(portal, F_OK) != 0) {
1596 if (mkdir(portal, 0660) != 0) {
1597 log_error("Could not make %s: %s\n", portal,
1598 strerror(errno));
1599 rc = ISCSI_ERR_IDBM;
1600 goto free_portal;
1604 snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
1605 rec->name, rec->conn[0].address, rec->conn[0].port);
1606 log_debug(5, "Looking for config file %s", portal);
1608 rc = idbm_lock();
1609 if (rc)
1610 goto free_portal;
1612 rc = stat(portal, &statb);
1613 if (rc) {
1614 rc = 0;
1616 * older iscsiadm versions had you create the config then set
1617 * set the tgpt. In new versions you must pass all the info in
1618 * from the start
1620 if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
1621 /* drop down to old style portal as config */
1622 goto open_conf;
1623 else
1624 goto mkdir_portal;
1627 if (!S_ISDIR(statb.st_mode)) {
1629 * older iscsiadm versions had you create the config then set
1630 * set the tgpt. In new versions you must pass all the info in
1631 * from the start
1633 if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
1634 /* drop down to old style portal as config */
1635 goto open_conf;
1637 * Old style portal as a file, but with tpgt. Let's update it.
1639 if (unlink(portal)) {
1640 log_error("Could not convert %s: %s\n", portal,
1641 strerror(errno));
1642 rc = ISCSI_ERR_IDBM;
1643 goto unlock;
1645 } else {
1646 rc = ISCSI_ERR_INVAL;
1647 goto unlock;
1650 mkdir_portal:
1651 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
1652 rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt);
1653 if (stat(portal, &statb)) {
1654 if (mkdir(portal, 0660) != 0) {
1655 log_error("Could not make dir %s: %s\n",
1656 portal, strerror(errno));
1657 rc = ISCSI_ERR_IDBM;
1658 goto unlock;
1662 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
1663 rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt,
1664 rec->iface.name);
1665 open_conf:
1666 f = fopen(portal, "w");
1667 if (!f) {
1668 log_error("Could not open %s: %sd\n", portal, strerror(errno));
1669 rc = ISCSI_ERR_IDBM;
1670 goto unlock;
1673 idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f);
1674 fclose(f);
1675 unlock:
1676 idbm_unlock();
1677 free_portal:
1678 free(portal);
1679 return rc;
1682 static int
1683 idbm_discovery_write(discovery_rec_t *rec)
1685 FILE *f;
1686 char *portal;
1687 int rc = 0;
1689 if (rec->type > 1)
1690 return ISCSI_ERR_INVAL;
1692 portal = malloc(PATH_MAX);
1693 if (!portal) {
1694 log_error("Could not alloc portal\n");
1695 return ISCSI_ERR_NOMEM;
1698 rc = idbm_lock();
1699 if (rc)
1700 goto free_portal;
1702 snprintf(portal, PATH_MAX, "%s",
1703 disc_type_to_config_vals[rec->type].config_root);
1704 if (access(portal, F_OK) != 0) {
1705 if (mkdir(portal, 0660) != 0) {
1706 log_error("Could not make %s: %s\n", portal,
1707 strerror(errno));
1708 rc = ISCSI_ERR_IDBM;
1709 goto unlock;
1713 snprintf(portal, PATH_MAX, "%s/%s,%d",
1714 disc_type_to_config_vals[rec->type].config_root,
1715 rec->address, rec->port);
1717 f = idbm_open_rec_w(portal,
1718 disc_type_to_config_vals[rec->type].config_name);
1719 if (!f) {
1720 log_error("Could not open %s: %s\n", portal, strerror(errno));
1721 rc = ISCSI_ERR_IDBM;
1722 goto unlock;
1725 idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, 1, f);
1726 fclose(f);
1727 unlock:
1728 idbm_unlock();
1729 free_portal:
1730 free(portal);
1731 return rc;
1734 int idbm_add_discovery(discovery_rec_t *newrec)
1736 discovery_rec_t rec;
1738 if (!idbm_discovery_read(&rec, newrec->type, newrec->address,
1739 newrec->port)) {
1740 log_debug(7, "disc rec already exists");
1741 /* fall through */
1742 } else
1743 log_debug(7, "adding new DB record");
1745 return idbm_discovery_write(newrec);
1748 static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec)
1750 struct stat statb;
1751 int rc = 0;
1753 switch (rec->disc_type) {
1754 case DISCOVERY_TYPE_SENDTARGETS:
1755 /* st dir setup when we create its discovery node */
1756 snprintf(disc_portal, PATH_MAX, "%s/%s,%d/%s,%s,%d,%d,%s",
1757 ST_CONFIG_DIR,
1758 rec->disc_address, rec->disc_port, rec->name,
1759 rec->conn[0].address, rec->conn[0].port, rec->tpgt,
1760 rec->iface.name);
1761 break;
1762 case DISCOVERY_TYPE_FW:
1763 if (access(FW_CONFIG_DIR, F_OK) != 0) {
1764 if (mkdir(FW_CONFIG_DIR, 0660) != 0) {
1765 log_error("Could not make %s: %s",
1766 FW_CONFIG_DIR, strerror(errno));
1767 rc = ISCSI_ERR_IDBM;
1771 snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
1772 FW_CONFIG_DIR, rec->name,
1773 rec->conn[0].address, rec->conn[0].port, rec->tpgt,
1774 rec->iface.name);
1775 break;
1776 case DISCOVERY_TYPE_STATIC:
1777 if (access(STATIC_CONFIG_DIR, F_OK) != 0) {
1778 if (mkdir(STATIC_CONFIG_DIR, 0660) != 0) {
1779 log_error("Could not make %s; %s",
1780 STATIC_CONFIG_DIR, strerror(errno));
1781 rc = ISCSI_ERR_IDBM;
1785 snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
1786 STATIC_CONFIG_DIR, rec->name,
1787 rec->conn[0].address, rec->conn[0].port, rec->tpgt,
1788 rec->iface.name);
1789 break;
1790 case DISCOVERY_TYPE_ISNS:
1791 if (access(ISNS_CONFIG_DIR, F_OK) != 0) {
1792 if (mkdir(ISNS_CONFIG_DIR, 0660) != 0) {
1793 log_error("Could not make %s: %s",
1794 ISNS_CONFIG_DIR, strerror(errno));
1795 rc = ISCSI_ERR_IDBM;
1800 * Older tools lumped all portals together in the
1801 * isns config dir. In 2.0-872, the isns dir added
1802 * a isns server (ddress and port) dir like sendtargets.
1804 * If we found a older style link we return that so it
1805 * can be removed. If this function is called for
1806 * addition of a rec then the older link should have been
1807 * removed and we break down below.
1809 snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
1810 ISNS_CONFIG_DIR,
1811 rec->name, rec->conn[0].address,
1812 rec->conn[0].port, rec->tpgt, rec->iface.name);
1813 if (!stat(disc_portal, &statb)) {
1814 log_debug(7, "using old style isns dir %s.",
1815 disc_portal);
1816 break;
1819 snprintf(disc_portal, PATH_MAX, "%s/%s,%d",
1820 ISNS_CONFIG_DIR, rec->disc_address, rec->disc_port);
1821 if (!stat(disc_portal, &statb) && S_ISDIR(statb.st_mode)) {
1823 * if there is a dir for this isns server then
1824 * assume we are using the new style links
1826 snprintf(disc_portal, PATH_MAX,
1827 "%s/%s,%d/%s,%s,%d,%d,%s",
1828 ISNS_CONFIG_DIR, rec->disc_address,
1829 rec->disc_port, rec->name,
1830 rec->conn[0].address, rec->conn[0].port,
1831 rec->tpgt, rec->iface.name);
1832 break;
1835 /* adding a older link */
1836 snprintf(disc_portal, PATH_MAX, "%s/%s,%s,%d,%d,%s",
1837 ISNS_CONFIG_DIR, rec->name, rec->conn[0].address,
1838 rec->conn[0].port, rec->tpgt, rec->iface.name);
1839 break;
1840 case DISCOVERY_TYPE_SLP:
1841 default:
1842 rc = ISCSI_ERR_INVAL;
1845 return rc;
1848 int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec, int overwrite)
1850 node_rec_t rec;
1851 char *node_portal, *disc_portal;
1852 int rc;
1854 if (!idbm_rec_read(&rec, newrec->name, newrec->tpgt,
1855 newrec->conn[0].address, newrec->conn[0].port,
1856 &newrec->iface)) {
1857 if (!overwrite)
1858 return 0;
1860 rc = idbm_delete_node(&rec);
1861 if (rc)
1862 return rc;
1863 log_debug(7, "overwriting existing record");
1864 } else
1865 log_debug(7, "adding new DB record");
1867 if (drec) {
1868 newrec->disc_type = drec->type;
1869 newrec->disc_port = drec->port;
1870 strcpy(newrec->disc_address, drec->address);
1873 rc = idbm_rec_write(newrec);
1875 * if a old app passed in a bogus tpgt then we do not create links
1876 * since it will set a different tpgt in another iscsiadm call
1878 if (rc || !drec || newrec->tpgt == PORTAL_GROUP_TAG_UNKNOWN)
1879 return rc;
1881 node_portal = calloc(2, PATH_MAX);
1882 if (!node_portal)
1883 return ISCSI_ERR_NOMEM;
1885 disc_portal = node_portal + PATH_MAX;
1886 snprintf(node_portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
1887 newrec->name, newrec->conn[0].address, newrec->conn[0].port,
1888 newrec->tpgt);
1889 rc = setup_disc_to_node_link(disc_portal, newrec);
1890 if (rc)
1891 goto free_portal;
1893 log_debug(7, "node addition making link from %s to %s", node_portal,
1894 disc_portal);
1896 rc = idbm_lock();
1897 if (rc)
1898 goto free_portal;
1900 if (symlink(node_portal, disc_portal)) {
1901 if (errno == EEXIST)
1902 log_debug(7, "link from %s to %s exists", node_portal,
1903 disc_portal);
1904 else {
1905 rc = ISCSI_ERR_IDBM;
1906 log_error("Could not make link from disc source %s to "
1907 "node %s: %s", disc_portal, node_portal,
1908 strerror(errno));
1911 idbm_unlock();
1912 free_portal:
1913 free(node_portal);
1914 return rc;
1917 static int idbm_bind_iface_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
1918 void *data, struct iface_rec *iface,
1919 struct list_head *bound_recs)
1921 struct node_rec *rec, *tmp;
1922 struct list_head new_recs;
1923 int rc;
1925 INIT_LIST_HEAD(&new_recs);
1926 rc = disc_node_fn(data, iface, &new_recs);
1927 if (rc)
1928 return rc;
1930 list_for_each_entry_safe(rec, tmp, &new_recs, list) {
1931 list_del_init(&rec->list);
1932 list_add_tail(&rec->list, bound_recs);
1933 iface_copy(&rec->iface, iface);
1935 return 0;
1938 static int
1939 discovery_error_fatal(int err)
1941 switch (err) {
1942 /* No error */
1943 case ISCSI_SUCCESS:
1944 /* Transport errors or timeouts are not fatal */
1945 case ISCSI_ERR_TRANS:
1946 case ISCSI_ERR_TRANS_TIMEOUT:
1947 return 0;
1949 return 1;
1952 int idbm_bind_ifaces_to_nodes(idbm_disc_nodes_fn *disc_node_fn,
1953 void *data, struct list_head *ifaces,
1954 struct list_head *bound_recs)
1956 struct list_head def_ifaces;
1957 struct node_rec *rec, *tmp_rec;
1958 struct iface_rec *iface, *tmp_iface;
1959 struct iscsi_transport *t;
1960 int rc = 0, found = 0;
1962 INIT_LIST_HEAD(&def_ifaces);
1964 if (!ifaces || list_empty(ifaces)) {
1965 iface_link_ifaces(&def_ifaces);
1967 list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
1968 list_del(&iface->list);
1969 t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
1971 * only auto bind to software iscsi if it is
1972 * not the default iface (that is handled below)
1974 if (!t || strcmp(t->name, DEFAULT_TRANSPORT) ||
1975 !strcmp(iface->name, DEFAULT_IFACENAME)) {
1976 free(iface);
1977 continue;
1980 rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
1981 bound_recs);
1982 free(iface);
1983 if (discovery_error_fatal(rc))
1984 goto fail;
1985 found = 1;
1988 /* create default iface with old/default behavior */
1989 if (!found) {
1990 struct iface_rec def_iface;
1992 memset(&def_iface, 0, sizeof(struct iface_rec));
1993 iface_setup_defaults(&def_iface);
1994 return idbm_bind_iface_to_nodes(disc_node_fn, data,
1995 &def_iface, bound_recs);
1997 } else {
1998 list_for_each_entry(iface, ifaces, list) {
1999 if (strcmp(iface->name, DEFAULT_IFACENAME) &&
2000 !iface_is_valid(iface)) {
2001 log_error("iface %s is not valid. Will not "
2002 "bind node to it. Iface settings "
2003 iface_fmt, iface->name,
2004 iface_str(iface));
2005 continue;
2008 rc = idbm_bind_iface_to_nodes(disc_node_fn, data, iface,
2009 bound_recs);
2010 if (discovery_error_fatal(rc))
2011 goto fail;
2014 return 0;
2016 fail:
2017 list_for_each_entry_safe(iface, tmp_iface, &def_ifaces, list) {
2018 list_del(&iface->list);
2019 free(iface);
2022 list_for_each_entry_safe(rec, tmp_rec, bound_recs, list) {
2023 list_del(&rec->list);
2024 free(rec);
2026 return rc;
2029 static void idbm_rm_disc_node_links(char *disc_dir)
2031 char *target = NULL, *tpgt = NULL, *port = NULL;
2032 char *address = NULL, *iface_id = NULL;
2033 DIR *disc_dirfd;
2034 struct dirent *disc_dent;
2035 node_rec_t *rec;
2037 rec = calloc(1, sizeof(*rec));
2038 if (!rec)
2039 return;
2041 disc_dirfd = opendir(disc_dir);
2042 if (!disc_dirfd)
2043 goto free_rec;
2045 /* rm links to nodes */
2046 while ((disc_dent = readdir(disc_dirfd))) {
2047 if (!strcmp(disc_dent->d_name, ".") ||
2048 !strcmp(disc_dent->d_name, ".."))
2049 continue;
2052 if (get_params_from_disc_link(disc_dent->d_name, &target, &tpgt,
2053 &address, &port, &iface_id)) {
2054 log_error("Improperly formed disc to node link");
2055 continue;
2058 log_debug(5, "disc removal removing link %s %s %s %s",
2059 target, address, port, iface_id);
2061 memset(rec, 0, sizeof(*rec));
2062 strlcpy(rec->name, target, TARGET_NAME_MAXLEN);
2063 rec->tpgt = atoi(tpgt);
2064 rec->conn[0].port = atoi(port);
2065 strlcpy(rec->conn[0].address, address, NI_MAXHOST);
2066 strlcpy(rec->iface.name, iface_id, ISCSI_MAX_IFACE_LEN);
2068 if (idbm_delete_node(rec))
2069 log_error("Could not delete node %s/%s/%s,%s/%s",
2070 NODE_CONFIG_DIR, target, address, port,
2071 iface_id);
2074 closedir(disc_dirfd);
2075 free_rec:
2076 free(rec);
2079 int idbm_delete_discovery(discovery_rec_t *drec)
2081 char *portal;
2082 struct stat statb;
2083 int rc = 0;
2085 portal = calloc(1, PATH_MAX);
2086 if (!portal)
2087 return ISCSI_ERR_NOMEM;
2089 snprintf(portal, PATH_MAX, "%s/%s,%d",
2090 disc_type_to_config_vals[drec->type].config_root,
2091 drec->address, drec->port);
2092 log_debug(5, "Removing config file %s\n", portal);
2094 if (stat(portal, &statb)) {
2095 log_debug(5, "Could not stat %s to delete disc err %d\n",
2096 portal, errno);
2097 goto free_portal;
2100 if (S_ISDIR(statb.st_mode)) {
2101 strlcat(portal, "/", PATH_MAX);
2102 strlcat(portal,
2103 disc_type_to_config_vals[drec->type].config_name,
2104 PATH_MAX);
2107 if (unlink(portal))
2108 log_debug(5, "Could not remove %s err %d\n", portal, errno);
2110 memset(portal, 0, PATH_MAX);
2111 snprintf(portal, PATH_MAX, "%s/%s,%d",
2112 disc_type_to_config_vals[drec->type].config_root,
2113 drec->address, drec->port);
2114 idbm_rm_disc_node_links(portal);
2116 /* rm portal dir */
2117 if (S_ISDIR(statb.st_mode)) {
2118 memset(portal, 0, PATH_MAX);
2119 snprintf(portal, PATH_MAX, "%s/%s,%d",
2120 disc_type_to_config_vals[drec->type].config_root,
2121 drec->address, drec->port);
2122 rmdir(portal);
2125 free_portal:
2126 free(portal);
2127 return rc;
2131 * Backwards Compat or SLP:
2132 * if there is no link then this is pre svn 780 version where
2133 * we did not link the disc source and node
2135 static int idbm_remove_disc_to_node_link(node_rec_t *rec,
2136 char *portal)
2138 int rc = 0;
2139 struct stat statb;
2140 node_rec_t *tmprec;
2142 tmprec = malloc(sizeof(*tmprec));
2143 if (!tmprec)
2144 return ISCSI_ERR_NOMEM;
2146 memset(portal, 0, PATH_MAX);
2147 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
2148 rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt,
2149 rec->iface.name);
2151 rc = __idbm_rec_read(tmprec, portal);
2152 if (rc) {
2153 /* old style recs will not have tpgt or a link so skip */
2154 rc = 0;
2155 goto done;
2158 log_debug(7, "found drec %s %d\n",
2159 tmprec->disc_address, tmprec->disc_port);
2160 /* rm link from discovery source to node */
2161 memset(portal, 0, PATH_MAX);
2162 rc = setup_disc_to_node_link(portal, tmprec);
2163 if (rc)
2164 goto done;
2166 rc = idbm_lock();
2167 if (rc)
2168 goto done;
2170 if (!stat(portal, &statb)) {
2171 if (unlink(portal)) {
2172 log_error("Could not remove link %s: %s\n",
2173 portal, strerror(errno));
2174 rc = ISCSI_ERR_IDBM;
2175 } else
2176 log_debug(7, "rmd %s", portal);
2177 } else
2178 log_debug(7, "Could not stat %s", portal);
2179 idbm_unlock();
2181 done:
2182 free(tmprec);
2183 return rc;
2186 static int st_disc_filter(const struct dirent *dir)
2188 return strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..") &&
2189 strcmp(dir->d_name, ST_CONFIG_NAME);
2192 int idbm_delete_node(node_rec_t *rec)
2194 struct stat statb;
2195 char *portal;
2196 int rc = 0, dir_rm_rc = 0;
2198 portal = calloc(1, PATH_MAX);
2199 if (!portal)
2200 return ISCSI_ERR_NOMEM;
2202 rc = idbm_remove_disc_to_node_link(rec, portal);
2203 if (rc)
2204 goto free_portal;
2206 memset(portal, 0, PATH_MAX);
2207 snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
2208 rec->name, rec->conn[0].address, rec->conn[0].port);
2209 log_debug(5, "Removing config file %s iface id %s\n",
2210 portal, rec->iface.name);
2212 rc = idbm_lock();
2213 if (rc)
2214 goto free_portal;
2216 if (!stat(portal, &statb))
2217 goto rm_conf;
2219 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR,
2220 rec->name, rec->conn[0].address, rec->conn[0].port,
2221 rec->tpgt, rec->iface.name);
2222 log_debug(5, "Removing config file %s", portal);
2224 if (!stat(portal, &statb))
2225 goto rm_conf;
2227 log_error("Could not stat %s to delete node: %s\n",
2228 portal, strerror(errno));
2229 rc = ISCSI_ERR_IDBM;
2230 goto unlock;
2232 rm_conf:
2233 if (unlink(portal)) {
2234 log_error("Could not remove %s: %s\n", portal, strerror(errno));
2235 rc = ISCSI_ERR_IDBM;
2236 goto unlock;
2239 memset(portal, 0, PATH_MAX);
2240 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
2241 rec->name, rec->conn[0].address, rec->conn[0].port,
2242 rec->tpgt);
2243 if (!stat(portal, &statb)) {
2244 struct dirent **namelist;
2245 int n, i;
2247 memset(portal, 0, PATH_MAX);
2248 snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR,
2249 rec->name, rec->conn[0].address, rec->conn[0].port,
2250 rec->tpgt);
2251 n = scandir(portal, &namelist, st_disc_filter, alphasort);
2252 if (n < 0)
2253 goto free_portal;
2254 if (n == 0)
2255 dir_rm_rc = rmdir(portal);
2257 for (i = 0; i < n; i++)
2258 free(namelist[i]);
2259 free(namelist);
2261 /* rm target dir */
2262 if (!dir_rm_rc) {
2263 memset(portal, 0, PATH_MAX);
2264 snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name);
2265 rmdir(portal);
2267 unlock:
2268 idbm_unlock();
2269 free_portal:
2270 free(portal);
2271 return rc;
2274 void
2275 idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg)
2277 idbm_sync_config();
2278 memcpy(cfg, &db->drec_st.u.sendtargets,
2279 sizeof(struct iscsi_sendtargets_config));
2282 void
2283 idbm_isns_defaults(struct iscsi_isns_config *cfg)
2285 idbm_sync_config();
2286 memcpy(cfg, &db->drec_isns.u.isns,
2287 sizeof(struct iscsi_isns_config));
2290 void
2291 idbm_slp_defaults(struct iscsi_slp_config *cfg)
2293 memcpy(cfg, &db->drec_slp.u.slp,
2294 sizeof(struct iscsi_slp_config));
2297 int idbm_node_set_param(void *data, node_rec_t *rec)
2299 struct db_set_param *param = data;
2300 recinfo_t *info;
2301 int rc = 0;
2303 info = idbm_recinfo_alloc(MAX_KEYS);
2304 if (!info)
2305 return ISCSI_ERR_NOMEM;
2307 idbm_recinfo_node(rec, info);
2309 rc = idbm_verify_param(info, param->name);
2310 if (rc)
2311 goto free_info;
2313 rc = idbm_rec_update_param(info, param->name, param->value, 0);
2314 if (rc)
2315 goto free_info;
2317 rc = idbm_rec_write(rec);
2318 if (rc)
2319 goto free_info;
2321 free_info:
2322 free(info);
2323 return rc;
2326 int idbm_discovery_set_param(void *data, discovery_rec_t *rec)
2328 struct db_set_param *param = data;
2329 recinfo_t *info;
2330 int rc = 0;
2332 info = idbm_recinfo_alloc(MAX_KEYS);
2333 if (!info)
2334 return ISCSI_ERR_NOMEM;
2336 idbm_recinfo_discovery((discovery_rec_t *)rec, info);
2338 rc = idbm_verify_param(info, param->name);
2339 if (rc)
2340 goto free_info;
2342 rc = idbm_rec_update_param(info, param->name, param->value, 0);
2343 if (rc)
2344 goto free_info;
2346 rc = idbm_discovery_write((discovery_rec_t *)rec);
2347 if (rc)
2348 goto free_info;
2350 free_info:
2351 free(info);
2352 return rc;
2355 int idbm_init(idbm_get_config_file_fn *fn)
2357 /* make sure root db dir is there */
2358 if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) {
2359 if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) {
2360 log_error("Could not make %s %d\n", ISCSI_CONFIG_ROOT,
2361 errno);
2362 return errno;
2366 db = malloc(sizeof(idbm_t));
2367 if (!db) {
2368 log_error("out of memory on idbm allocation");
2369 return ISCSI_ERR_NOMEM;
2371 memset(db, 0, sizeof(idbm_t));
2372 db->get_config_file = fn;
2373 return 0;
2376 void idbm_terminate(void)
2378 if (db)
2379 free(db);
2383 * idbm_create_rec - allocate and setup a node record
2384 * @targetname: target name
2385 * @tgpt: target portal group
2386 * @ip: ip address of portal
2387 * @port: port of portal
2388 * @iface: iscsi iface info
2389 * @verbose: flag indicating whether to log ifaces setup errors
2391 * The iface only needs to have the name set. This function will
2392 * read in the other values.
2394 struct node_rec *idbm_create_rec(char *targetname, int tpgt, char *ip,
2395 int port, struct iface_rec *iface,
2396 int verbose)
2398 struct node_rec *rec;
2400 rec = calloc(1, sizeof(*rec));
2401 if (!rec) {
2402 log_error("Could not not allocate memory to create node "
2403 "record.");
2404 return NULL;
2407 idbm_node_setup_defaults(rec);
2408 if (targetname)
2409 strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
2410 rec->tpgt = tpgt;
2411 rec->conn[0].port = port;
2412 if (ip)
2413 strlcpy(rec->conn[0].address, ip, NI_MAXHOST);
2414 memset(&rec->iface, 0, sizeof(struct iface_rec));
2415 if (iface) {
2416 iface_copy(&rec->iface, iface);
2417 if (strlen(iface->name)) {
2418 if (iface_conf_read(&rec->iface)) {
2419 if (verbose)
2420 log_error("Could not read iface info "
2421 "for %s.", iface->name);
2422 goto free_rec;
2426 return rec;
2427 free_rec:
2428 free(rec);
2429 return NULL;
2432 struct node_rec *idbm_create_rec_from_boot_context(struct boot_context *context)
2434 struct node_rec *rec;
2436 /* tpgt hard coded to 1 ??? */
2437 rec = idbm_create_rec(context->targetname, 1,
2438 context->target_ipaddr, context->target_port,
2439 NULL, 1);
2440 if (!rec) {
2441 log_error("Could not setup rec for fw discovery login.");
2442 return NULL;
2445 iface_setup_defaults(&rec->iface);
2446 strlcpy(rec->session.auth.username, context->chap_name,
2447 sizeof(context->chap_name));
2448 strlcpy((char *)rec->session.auth.password, context->chap_password,
2449 sizeof(context->chap_password));
2450 strlcpy(rec->session.auth.username_in, context->chap_name_in,
2451 sizeof(context->chap_name_in));
2452 strlcpy((char *)rec->session.auth.password_in,
2453 context->chap_password_in,
2454 sizeof(context->chap_password_in));
2455 rec->session.auth.password_length =
2456 strlen((char *)context->chap_password);
2457 rec->session.auth.password_in_length =
2458 strlen((char *)context->chap_password_in);
2460 iface_setup_from_boot_context(&rec->iface, context);
2462 return rec;
2465 void idbm_node_setup_defaults(node_rec_t *rec)
2467 int i;
2469 memset(rec, 0, sizeof(node_rec_t));
2471 INIT_LIST_HEAD(&rec->list);
2473 rec->tpgt = PORTAL_GROUP_TAG_UNKNOWN;
2474 rec->disc_type = DISCOVERY_TYPE_STATIC;
2475 rec->leading_login = 0;
2476 rec->session.cmds_max = CMDS_MAX;
2477 rec->session.xmit_thread_priority = XMIT_THREAD_PRIORITY;
2478 rec->session.initial_cmdsn = 0;
2479 rec->session.queue_depth = QUEUE_DEPTH;
2480 rec->session.nr_sessions = 1;
2481 rec->session.initial_login_retry_max = DEF_INITIAL_LOGIN_RETRIES_MAX;
2482 rec->session.reopen_max = 32;
2483 rec->session.auth.authmethod = 0;
2484 rec->session.auth.password_length = 0;
2485 rec->session.auth.password_in_length = 0;
2486 rec->session.err_timeo.abort_timeout = DEF_ABORT_TIMEO;
2487 rec->session.err_timeo.lu_reset_timeout = DEF_LU_RESET_TIMEO;
2488 rec->session.err_timeo.tgt_reset_timeout = DEF_TGT_RESET_TIMEO;
2489 rec->session.err_timeo.host_reset_timeout = DEF_HOST_RESET_TIMEO;
2490 rec->session.timeo.replacement_timeout = DEF_REPLACEMENT_TIMEO;
2491 rec->session.info = NULL;
2492 rec->session.sid = 0;
2493 rec->session.multiple = 0;
2494 idbm_setup_session_defaults(&rec->session.iscsi);
2496 for (i=0; i<ISCSI_CONN_MAX; i++) {
2497 rec->conn[i].startup = ISCSI_STARTUP_MANUAL;
2498 rec->conn[i].port = ISCSI_LISTEN_PORT;
2499 rec->conn[i].tcp.window_size = TCP_WINDOW_SIZE;
2500 rec->conn[i].tcp.type_of_service = 0;
2501 rec->conn[i].timeo.login_timeout= DEF_LOGIN_TIMEO;
2502 rec->conn[i].timeo.logout_timeout= DEF_LOGOUT_TIMEO;
2503 rec->conn[i].timeo.auth_timeout = 45;
2505 rec->conn[i].timeo.noop_out_interval = DEF_NOOP_OUT_INTERVAL;
2506 rec->conn[i].timeo.noop_out_timeout = DEF_NOOP_OUT_TIMEO;
2508 idbm_setup_conn_defaults(&rec->conn[i].iscsi);
2511 iface_setup_defaults(&rec->iface);
2514 struct node_rec *
2515 idbm_find_rec_in_list(struct list_head *rec_list, char *targetname, char *addr,
2516 int port, struct iface_rec *iface)
2518 struct node_rec *rec;
2520 list_for_each_entry(rec, rec_list, list) {
2521 if (__iscsi_match_session(rec, targetname, addr, port, iface,
2522 MATCH_ANY_SID))
2523 return rec;
2526 return NULL;