2 * iSCSI Administration Utility
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 * Copyright (C) 2011 Dell Inc.
8 * maintained by open-iscsi@googlegroups.com
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * See the file COPYING included with this distribution for more details.
32 #include "initiator.h"
33 #include "discovery.h"
37 #include "iscsi_util.h"
38 #include "transport.h"
40 #include "iscsi_sysfs.h"
42 #include "iscsi_settings.h"
43 #include "fw_context.h"
45 #include "session_info.h"
48 #include "idbm_fields.h"
49 #include "session_mgmt.h"
50 #include "iscsid_req.h"
51 #include "isns-proto.h"
52 #include "iscsi_err.h"
54 static char program_name
[] = "iscsiadm";
55 static char config_file
[TARGET_NAME_MAXLEN
];
56 extern struct iscsi_ipc
*ipc
;
74 OP_NONPERSISTENT
= 0x10
77 static struct option
const long_options
[] =
79 {"mode", required_argument
, NULL
, 'm'},
80 {"portal", required_argument
, NULL
, 'p'},
81 {"targetname", required_argument
, NULL
, 'T'},
82 {"interface", required_argument
, NULL
, 'I'},
83 {"op", required_argument
, NULL
, 'o'},
84 {"type", required_argument
, NULL
, 't'},
85 {"name", required_argument
, NULL
, 'n'},
86 {"value", required_argument
, NULL
, 'v'},
87 {"host", required_argument
, NULL
, 'H'},
88 {"sid", required_argument
, NULL
, 'r'},
89 {"rescan", no_argument
, NULL
, 'R'},
90 {"print", required_argument
, NULL
, 'P'},
91 {"discover", no_argument
, NULL
, 'D'},
92 {"login", no_argument
, NULL
, 'l'},
93 {"loginall", required_argument
, NULL
, 'L'},
94 {"logout", no_argument
, NULL
, 'u'},
95 {"logoutall", required_argument
, NULL
, 'U'},
96 {"stats", no_argument
, NULL
, 's'},
97 {"killiscsid", required_argument
, NULL
, 'k'},
98 {"debug", required_argument
, NULL
, 'd'},
99 {"show", no_argument
, NULL
, 'S'},
100 {"version", no_argument
, NULL
, 'V'},
101 {"help", no_argument
, NULL
, 'h'},
104 static char *short_options
= "RlDVhm:p:P:T:H:I:U:k:L:d:r:n:v:o:sSt:u";
106 static void usage(int status
)
109 fprintf(stderr
, "Try `%s --help' for more information.\n",
113 iscsiadm -m discoverydb [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -Dl ] ] | [ [ -p ip:port -t type] \
114 [ -o operation ] [ -n name ] [ -v value ] [ -lD ] ] \n\
115 iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ [ -p ip:port ] [ -l | -D ] ] \n\
116 iiscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I ifaceN ] [ -l | -u | -R | -s] ] \
117 [ [ -o operation ] [ -n name ] [ -v value ] ]\n\
118 iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\
119 iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\
120 iscsiadm -m fw [ -l ]\n\
121 iscsiadm -m host [ -P printlevel ] [ -H hostno ]\n\
122 iscsiadm -k priority\n");
132 if (!strcmp("new", str
))
134 else if (!strcmp("delete", str
))
136 else if (!strcmp("update", str
))
138 else if (!strcmp("show", str
))
140 else if (!strcmp("nonpersistent", str
))
141 op
= OP_NONPERSISTENT
;
149 str_to_mode(char *str
)
153 if (!strcmp("discovery", str
))
154 mode
= MODE_DISCOVERY
;
155 else if (!strcmp("discoverydb", str
))
156 mode
= MODE_DISCOVERYDB
;
157 else if (!strcmp("node", str
))
159 else if (!strcmp("session", str
))
161 else if (!strcmp("iface", str
))
163 else if (!strcmp("fw", str
))
165 else if (!strcmp("host", str
))
174 str_to_type(char *str
)
178 if (!strcmp("sendtargets", str
) ||
180 type
= DISCOVERY_TYPE_SENDTARGETS
;
181 else if (!strcmp("slp", str
))
182 type
= DISCOVERY_TYPE_SLP
;
183 else if (!strcmp("isns", str
))
184 type
= DISCOVERY_TYPE_ISNS
;
185 else if (!strcmp("fw", str
))
186 type
= DISCOVERY_TYPE_FW
;
193 static void kill_iscsid(int priority
)
200 * We only support SIGTERM like stoppage of iscsid for now.
201 * In the future we can do something where we try go finish
202 * up operations like login, error handling, etc, before
203 * iscsid is stopped, and we can add different values to indicate
204 * that the user wants iscsid to log out existing sessions before
208 log_error("Invalid iscsid priority %d. Priority must be 0.",
213 memset(&req
, 0, sizeof(req
));
214 req
.command
= MGMT_IPC_IMMEDIATE_STOP
;
215 rc
= iscsid_exec_req(&req
, &rsp
, 0);
217 iscsi_err_print_msg(rc
);
218 log_error("Could not stop iscsid. Trying sending iscsid "
219 "SIGTERM or SIGKILL signals manually\n");
224 * TODO: we can display how the ifaces are related to node records.
225 * And we can add a scsi_host mode which would display how
226 * sessions are related to hosts
227 * (scsi_host and iscsi_sessions are the currently running instance of
228 * a iface or node record).
230 static int print_ifaces(struct iface_rec
*iface
, int info_level
)
232 int err
, num_found
= 0;
234 switch (info_level
) {
237 err
= iface_for_each_iface(NULL
, 0, &num_found
,
242 err
= iface_conf_read(iface
);
244 log_error("Could not read iface %s.\n",
248 iface_print_tree(NULL
, iface
);
251 err
= iface_for_each_iface(NULL
, 0, &num_found
,
255 log_error("Invalid info level %d. Try 0 - 1.", info_level
);
256 return ISCSI_ERR_INVAL
;
260 log_error("No interfaces found.");
261 err
= ISCSI_ERR_NO_OBJS_FOUND
;
267 match_startup_mode(node_rec_t
*rec
, char *mode
)
269 if ((!strcmp(mode
, "automatic") &&
270 rec
->startup
== ISCSI_STARTUP_AUTOMATIC
) ||
271 (!strcmp(mode
, "onboot") &&
272 rec
->startup
== ISCSI_STARTUP_ONBOOT
) ||
273 (!strcmp(mode
, "manual") &&
274 rec
->startup
== ISCSI_STARTUP_MANUAL
) ||
275 !strcmp(mode
, "all"))
278 /* support conn or session startup params */
279 if ((!strcmp(mode
, "automatic") &&
280 rec
->conn
[0].startup
== ISCSI_STARTUP_AUTOMATIC
) ||
281 (!strcmp(mode
, "onboot") &&
282 rec
->conn
[0].startup
== ISCSI_STARTUP_ONBOOT
) ||
283 (!strcmp(mode
, "manual") &&
284 rec
->conn
[0].startup
== ISCSI_STARTUP_MANUAL
) ||
285 !strcmp(mode
, "all"))
292 for_each_session(struct node_rec
*rec
, iscsi_sysfs_session_op_fn
*fn
)
294 int err
, num_found
= 0;
296 if (rec
&& rec
->session
.info
) {
298 err
= fn(rec
, rec
->session
.info
);
300 err
= iscsi_sysfs_for_each_session(rec
, &num_found
, fn
);
303 log_error("Could not execute operation on all sessions: %s",
304 iscsi_err_to_str(err
));
305 else if (!num_found
) {
306 log_error("No session found.");
307 err
= ISCSI_ERR_NO_OBJS_FOUND
;
313 static int link_recs(void *data
, struct node_rec
*rec
)
315 struct list_head
*list
= data
;
316 struct node_rec
*rec_copy
;
318 rec_copy
= calloc(1, sizeof(*rec_copy
));
320 return ISCSI_ERR_NOMEM
;
321 memcpy(rec_copy
, rec
, sizeof(*rec_copy
));
322 INIT_LIST_HEAD(&rec_copy
->list
);
323 list_add_tail(&rec_copy
->list
, list
);
328 __logout_by_startup(void *data
, struct list_head
*list
,
329 struct session_info
*info
)
334 memset(&rec
, 0, sizeof(node_rec_t
));
335 if (idbm_rec_read(&rec
, info
->targetname
, info
->tpgt
,
336 info
->persistent_address
,
337 info
->persistent_port
, &info
->iface
)) {
339 * this is due to a HW driver or some other driver
342 log_debug(7, "could not read data for [%s,%s.%d]\n",
343 info
->targetname
, info
->persistent_address
,
344 info
->persistent_port
);
348 /* multiple drivers could be connected to the same portal */
349 if (strcmp(rec
.iface
.transport_name
, info
->iface
.transport_name
))
352 * we always skip on boot because if the user killed this on
353 * they would not be able to do anything
355 if (rec
.startup
== ISCSI_STARTUP_ONBOOT
)
358 if (match_startup_mode(&rec
, mode
))
361 return iscsi_logout_portal(info
, list
);
365 logout_by_startup(char *mode
)
370 if (!mode
|| !(!strcmp(mode
, "automatic") || !strcmp(mode
, "all") ||
371 !strcmp(mode
,"manual"))) {
372 log_error("Invalid logoutall option %s.", mode
);
373 usage(ISCSI_ERR_INVAL
);
374 return ISCSI_ERR_INVAL
;
377 rc
= iscsi_logout_portals(mode
, &nr_found
, 1, __logout_by_startup
);
378 if (rc
== ISCSI_ERR_NO_OBJS_FOUND
)
379 log_error("No matching sessions found");
383 struct startup_data
{
385 struct list_head all_logins
;
386 struct list_head leading_logins
;
389 static int link_startup_recs(void *data
, struct node_rec
*rec
)
391 struct startup_data
*startup
= data
;
392 struct node_rec
*rec_copy
;
394 if (match_startup_mode(rec
, startup
->mode
))
397 rec_copy
= calloc(1, sizeof(*rec_copy
));
399 return ISCSI_ERR_NOMEM
;
400 memcpy(rec_copy
, rec
, sizeof(*rec_copy
));
401 INIT_LIST_HEAD(&rec_copy
->list
);
403 if (rec_copy
->leading_login
)
404 list_add_tail(&rec_copy
->list
, &startup
->leading_logins
);
406 list_add_tail(&rec_copy
->list
, &startup
->all_logins
);
411 __do_leading_login(void *data
, struct list_head
*list
, struct node_rec
*rec
)
413 struct iface_rec
*pattern_iface
= data
;
416 /* Skip any records that do not match the pattern iface */
417 if (!iface_match(pattern_iface
, &rec
->iface
))
421 * If there is an existing session that matcthes the target,
422 * the leading login is complete.
424 if (iscsi_sysfs_for_each_session(rec
, &nr_found
, iscsi_match_target
)) {
425 log_debug(1, "Skipping %s: Already a session for that target",
430 /* No existing session: Attempt a login. */
431 return iscsi_login_portal(NULL
, list
, rec
);
435 login_by_startup(char *mode
)
437 int nr_found
= 0, err
, rc
;
438 struct startup_data startup
;
440 if (!mode
|| !(!strcmp(mode
, "automatic") || !strcmp(mode
, "all") ||
441 !strcmp(mode
,"manual") || !strcmp(mode
, "onboot"))) {
442 log_error("Invalid loginall option %s.", mode
);
443 usage(ISCSI_ERR_INVAL
);
444 return ISCSI_ERR_INVAL
;
448 * Filter all node records that match the given 'mode' into 2 lists:
449 * Those with leading_login enabled, and those without.
452 INIT_LIST_HEAD(&startup
.all_logins
);
453 INIT_LIST_HEAD(&startup
.leading_logins
);
454 err
= idbm_for_each_rec(&nr_found
, &startup
, link_startup_recs
);
455 if (err
&& (!list_empty(&startup
.all_logins
) ||
456 !list_empty(&startup
.leading_logins
)))
457 /* log msg and try to log into what we found */
458 log_error("Could not read all records: %s",
459 iscsi_err_to_str(err
));
460 else if (list_empty(&startup
.all_logins
) &&
461 list_empty(&startup
.leading_logins
)) {
463 log_error("Could not read node DB: %s.",
464 iscsi_err_to_str(err
));
466 log_error("No records found");
467 err
= ISCSI_ERR_NO_OBJS_FOUND
;
473 if (!list_empty(&startup
.all_logins
)) {
474 log_debug(1, "Logging into normal (non-leading-login) portals");
475 /* Login all regular (non-leading-login) portals first */
476 err
= iscsi_login_portals(NULL
, &nr_found
, 1,
477 &startup
.all_logins
, iscsi_login_portal
);
479 log_error("Could not log into all portals");
484 if (!list_empty(&startup
.leading_logins
)) {
486 * For each iface in turn, try to login all portals on that
487 * iface that do not already have a session present.
489 struct iface_rec
*pattern_iface
, *tmp_iface
;
490 struct node_rec
*rec
, *tmp_rec
;
491 struct list_head iface_list
;
492 int missed_leading_login
= 0;
493 log_debug(1, "Logging into leading-login portals");
494 INIT_LIST_HEAD(&iface_list
);
495 iface_link_ifaces(&iface_list
);
496 list_for_each_entry_safe(pattern_iface
, tmp_iface
, &iface_list
,
498 log_debug(1, "Establishing leading-logins via iface %s",
499 pattern_iface
->name
);
500 err
= iscsi_login_portals_safe(pattern_iface
, &nr_found
,
502 &startup
.leading_logins
,
505 log_error("Could not log into all portals on "
506 "%s, trying next interface",
507 pattern_iface
->name
);
510 * Note: We always try all iface records in case there
511 * are targets that are associated with only a subset
512 * of iface records. __do_leading_login already
513 * prevents duplicate sessions if an iface has succeded
514 * for a particular target.
518 * Double-check that all leading-login portals have at least
521 list_for_each_entry_safe(rec
, tmp_rec
, &startup
.leading_logins
,
523 if (!iscsi_sysfs_for_each_session(rec
, &nr_found
,
525 missed_leading_login
++;
527 * Cleanup the list, since 'iscsi_login_portals_safe'
530 list_del(&rec
->list
);
533 if (missed_leading_login
) {
534 log_error("Could not login all leading-login portals");
536 rc
= ISCSI_ERR_FATAL_LOGIN
;
544 * iscsi_logout_matched_portal - logout of targets matching the rec info
545 * @data: record to session with
546 * @list: list to add logout rec to
547 * @info: session to match with rec
549 static int iscsi_logout_matched_portal(void *data
, struct list_head
*list
,
550 struct session_info
*info
)
552 struct node_rec
*pattern_rec
= data
;
553 struct iscsi_transport
*t
;
555 t
= iscsi_sysfs_get_transport_by_sid(info
->sid
);
559 if (!iscsi_match_session(pattern_rec
, info
))
562 /* we do not support this yet */
563 if (t
->caps
& CAP_FW_DB
) {
564 log_error("Could not logout session of [sid: %d, "
565 "target: %s, portal: %s,%d].", info
->sid
,
566 info
->targetname
, info
->persistent_address
,
568 log_error("Logout not supported for driver: %s.", t
->name
);
571 return iscsi_logout_portal(info
, list
);
574 static int rec_match_fn(void *data
, node_rec_t
*rec
)
576 struct rec_op_data
*op_data
= data
;
578 if (!__iscsi_match_session(op_data
->match_rec
, rec
->name
,
579 rec
->conn
[0].address
, rec
->conn
[0].port
,
580 &rec
->iface
, rec
->session
.sid
))
582 return op_data
->fn(op_data
->data
, rec
);
585 static int __for_each_matched_rec(int verbose
, struct node_rec
*rec
,
586 void *data
, idbm_iface_op_fn
*fn
)
588 struct rec_op_data op_data
;
589 int nr_found
= 0, rc
;
591 memset(&op_data
, 0, sizeof(struct rec_op_data
));
593 op_data
.match_rec
= rec
;
596 rc
= idbm_for_each_rec(&nr_found
, &op_data
, rec_match_fn
);
599 log_error("Could not execute operation on all "
600 "records: %s", iscsi_err_to_str(rc
));
601 } else if (!nr_found
) {
603 log_error("No records found");
604 rc
= ISCSI_ERR_NO_OBJS_FOUND
;
610 static int for_each_matched_rec(struct node_rec
*rec
, void *data
,
611 idbm_iface_op_fn
*fn
)
613 return __for_each_matched_rec(1, rec
, data
, fn
);
617 static int login_portals(struct node_rec
*pattern_rec
)
619 struct list_head rec_list
;
620 int nr_found
, rc
, err
;
622 INIT_LIST_HEAD(&rec_list
);
623 err
= for_each_matched_rec(pattern_rec
, &rec_list
, link_recs
);
624 if (err
== ISCSI_ERR_NO_OBJS_FOUND
)
626 else if (err
&& list_empty(&rec_list
))
630 /* if there is an err but some recs then try to login to what we have */
632 err
= iscsi_login_portals(pattern_rec
, &nr_found
, 1, &rec_list
,
635 log_error("Could not log into all portals");
643 static int print_nodes(int info_level
, struct node_rec
*rec
)
645 struct node_rec tmp_rec
;
648 switch (info_level
) {
651 rc
= for_each_matched_rec(rec
, NULL
, idbm_print_node_flat
);
654 memset(&tmp_rec
, 0, sizeof(node_rec_t
));
655 rc
= for_each_matched_rec(rec
, &tmp_rec
,
656 idbm_print_node_and_iface_tree
);
659 log_error("Invalid info level %d. Try 0 or 1.", info_level
);
660 rc
= ISCSI_ERR_INVAL
;
666 static char *get_config_file(void)
672 memset(&req
, 0, sizeof(req
));
673 req
.command
= MGMT_IPC_CONFIG_FILE
;
675 rc
= iscsid_exec_req(&req
, &rsp
, 1);
679 if (rsp
.u
.config
.var
[0] != '\0') {
680 strcpy(config_file
, rsp
.u
.config
.var
);
687 static int rescan_portal(void *data
, struct session_info
*info
)
691 if (!iscsi_match_session(data
, info
))
694 printf("Rescanning session [sid: %d, target: %s, portal: "
695 "%s,%d]\n", info
->sid
, info
->targetname
,
696 info
->persistent_address
, info
->port
);
698 host_no
= iscsi_sysfs_get_host_no_from_sid(info
->sid
, &err
);
700 log_error("Could not rescan session sid %d.", info
->sid
);
703 /* rescan each device to pick up size changes */
704 iscsi_sysfs_for_each_device(NULL
, host_no
, info
->sid
,
705 iscsi_sysfs_rescan_device
);
706 /* now scan for new devices */
707 iscsi_sysfs_scan_host(host_no
, 0);
712 session_stats(void *data
, struct session_info
*info
)
718 if (!iscsi_match_session(data
, info
))
721 memset(&req
, 0, sizeof(req
));
722 req
.command
= MGMT_IPC_SESSION_STATS
;
723 req
.u
.session
.sid
= info
->sid
;
725 rc
= iscsid_exec_req(&req
, &rsp
, 1);
729 printf("Stats for session [sid: %d, target: %s, portal: "
731 info
->sid
, info
->targetname
, info
->persistent_address
,
734 printf( "iSCSI SNMP:\n"
736 "\ttxdata_octets: %lld\n"
737 "\trxdata_octets: %lld\n"
740 "\tscsicmd_pdus: %u\n"
741 "\ttmfcmd_pdus: %u\n"
744 "\tdataout_pdus: %u\n"
745 "\tlogout_pdus: %u\n"
749 "\tscsirsp_pdus: %u\n"
750 "\ttmfrsp_pdus: %u\n"
751 "\ttextrsp_pdus: %u\n"
752 "\tdatain_pdus: %u\n"
753 "\tlogoutrsp_pdus: %u\n"
759 "\ttimeout_err: %u\n",
760 (unsigned long long)rsp
.u
.getstats
.stats
.txdata_octets
,
761 (unsigned long long)rsp
.u
.getstats
.stats
.rxdata_octets
,
763 rsp
.u
.getstats
.stats
.noptx_pdus
,
764 rsp
.u
.getstats
.stats
.scsicmd_pdus
,
765 rsp
.u
.getstats
.stats
.tmfcmd_pdus
,
766 rsp
.u
.getstats
.stats
.login_pdus
,
767 rsp
.u
.getstats
.stats
.text_pdus
,
768 rsp
.u
.getstats
.stats
.dataout_pdus
,
769 rsp
.u
.getstats
.stats
.logout_pdus
,
770 rsp
.u
.getstats
.stats
.snack_pdus
,
772 rsp
.u
.getstats
.stats
.noprx_pdus
,
773 rsp
.u
.getstats
.stats
.scsirsp_pdus
,
774 rsp
.u
.getstats
.stats
.tmfrsp_pdus
,
775 rsp
.u
.getstats
.stats
.textrsp_pdus
,
776 rsp
.u
.getstats
.stats
.datain_pdus
,
777 rsp
.u
.getstats
.stats
.logoutrsp_pdus
,
778 rsp
.u
.getstats
.stats
.r2t_pdus
,
779 rsp
.u
.getstats
.stats
.async_pdus
,
780 rsp
.u
.getstats
.stats
.rjt_pdus
,
782 rsp
.u
.getstats
.stats
.digest_err
,
783 rsp
.u
.getstats
.stats
.timeout_err
);
785 if (rsp
.u
.getstats
.stats
.custom_length
)
786 printf( "iSCSI Extended:\n");
788 for (i
= 0; i
< rsp
.u
.getstats
.stats
.custom_length
; i
++) {
789 printf("\t%s: %llu\n", rsp
.u
.getstats
.stats
.custom
[i
].desc
,
790 (unsigned long long)rsp
.u
.getstats
.stats
.custom
[i
].value
);
796 static int add_static_rec(int *found
, char *targetname
, int tpgt
,
797 char *ip
, int port
, struct iface_rec
*iface
)
800 discovery_rec_t
*drec
;
803 rec
= calloc(1, sizeof(*rec
));
805 log_error("Could not allocate memory for node addition");
806 rc
= ISCSI_ERR_NOMEM
;
810 drec
= calloc(1, sizeof(*drec
));
812 log_error("Could not allocate memory for node addition");
813 rc
= ISCSI_ERR_NOMEM
;
816 drec
->type
= DISCOVERY_TYPE_STATIC
;
818 idbm_node_setup_from_conf(rec
);
819 strlcpy(rec
->name
, targetname
, TARGET_NAME_MAXLEN
);
821 rec
->conn
[0].port
= port
;
822 strlcpy(rec
->conn
[0].address
, ip
, NI_MAXHOST
);
825 rc
= iface_conf_read(iface
);
827 log_error("Could not read iface %s. Error %d",
832 iface_copy(&rec
->iface
, iface
);
835 rc
= idbm_add_node(rec
, drec
, 1);
838 printf("New iSCSI node [%s:" iface_fmt
" %s,%d,%d %s] added\n",
839 rec
->iface
.transport_name
, iface_str(&rec
->iface
),
840 ip
, port
, tpgt
, targetname
);
849 static int add_static_portal(int *found
, void *data
,
850 char *targetname
, int tpgt
, char *ip
, int port
)
852 node_rec_t
*rec
= data
;
854 if (strlen(rec
->conn
[0].address
) &&
855 strcmp(rec
->conn
[0].address
, ip
))
858 if (rec
->conn
[0].port
!= -1 && rec
->conn
[0].port
!= port
)
861 return add_static_rec(found
, targetname
, tpgt
, ip
, port
,
865 static int add_static_node(int *found
, void *data
,
868 node_rec_t
*rec
= data
;
870 if (!strlen(rec
->name
))
873 if (strcmp(rec
->name
, targetname
))
876 if (!strlen(rec
->conn
[0].address
))
879 return add_static_rec(found
, targetname
, rec
->tpgt
,
880 rec
->conn
[0].address
,
881 rec
->conn
[0].port
, &rec
->iface
);
883 return idbm_for_each_portal(found
, data
, add_static_portal
,
887 static int add_static_recs(struct node_rec
*rec
)
889 int rc
, nr_found
= 0;
891 rc
= idbm_for_each_node(&nr_found
, rec
, add_static_node
);
898 /* brand new target */
899 if (strlen(rec
->name
) && strlen(rec
->conn
[0].address
)) {
900 rc
= add_static_rec(&nr_found
, rec
->name
, rec
->tpgt
,
901 rec
->conn
[0].address
, rec
->conn
[0].port
,
907 log_error("Error while adding record: %s", iscsi_err_to_str(rc
));
912 * start sendtargets discovery process based on the
916 do_offload_sendtargets(discovery_rec_t
*drec
, int host_no
, int do_login
)
918 drec
->type
= DISCOVERY_TYPE_OFFLOAD_SENDTARGETS
;
919 return discovery_offload_sendtargets(host_no
, do_login
, drec
);
922 static int delete_node(void *data
, struct node_rec
*rec
)
924 if (iscsi_check_for_running_session(rec
)) {
926 * We could log out the session for the user, but if
927 * the session is being used the user may get something
928 * they were not expecting (FS errors and a read only
931 log_error("This command will remove the record [iface: %s, "
932 "target: %s, portal: %s,%d], but a session is "
933 "using it. Logout session then rerun command to "
934 "remove record.", rec
->iface
.name
, rec
->name
,
935 rec
->conn
[0].address
, rec
->conn
[0].port
);
936 return ISCSI_ERR_SESS_EXISTS
;
939 return idbm_delete_node(rec
);
942 static int delete_stale_rec(void *data
, struct node_rec
*rec
)
944 struct list_head
*new_rec_list
= data
;
945 struct node_rec
*new_rec
;
947 list_for_each_entry(new_rec
, new_rec_list
, list
) {
949 * We could also move this to idbm.c and instead of looping
950 * over every node just loop over disc to node links.
952 if (rec
->disc_type
!= new_rec
->disc_type
||
953 rec
->disc_port
!= new_rec
->disc_port
||
954 strcmp(rec
->disc_address
, new_rec
->disc_address
))
956 * if we are not from the same discovery source
961 if (__iscsi_match_session(rec
,
963 new_rec
->conn
[0].address
,
964 new_rec
->conn
[0].port
,
966 new_rec
->session
.sid
))
969 /* if there is a error we can continue on */
970 return delete_node(NULL
, rec
);
974 exec_disc_op_on_recs(discovery_rec_t
*drec
, struct list_head
*rec_list
,
975 int info_level
, int do_login
, int op
)
977 int rc
= 0, err
, found
= 0;
978 struct node_rec
*new_rec
, tmp_rec
;
980 /* clean up node db */
982 idbm_for_each_rec(&found
, rec_list
, delete_stale_rec
);
984 if (op
& OP_NEW
|| op
& OP_UPDATE
) {
985 /* now add/update records */
986 list_for_each_entry(new_rec
, rec_list
, list
) {
987 rc
= idbm_add_node(new_rec
, drec
, op
& OP_UPDATE
);
989 log_error("Could not add/update "
990 "[%s:" iface_fmt
" %s,%d,%d %s]",
991 new_rec
->iface
.transport_name
,
992 iface_str(&new_rec
->iface
),
993 new_rec
->conn
[0].address
,
994 new_rec
->conn
[0].port
,
995 new_rec
->tpgt
, new_rec
->name
);
999 memset(&tmp_rec
, 0, sizeof(node_rec_t
));
1000 list_for_each_entry(new_rec
, rec_list
, list
) {
1001 switch (info_level
) {
1004 idbm_print_node_flat(NULL
, new_rec
);
1007 idbm_print_node_and_iface_tree(&tmp_rec
, new_rec
);
1015 err
= iscsi_login_portals(NULL
, &found
, 1, rec_list
,
1016 iscsi_login_portal
);
1023 do_software_sendtargets(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1024 int info_level
, int do_login
, int op
, int sync_drec
)
1026 struct list_head rec_list
;
1027 struct node_rec
*rec
, *tmp
;
1030 INIT_LIST_HEAD(&rec_list
);
1032 * compat: if the user did not pass any op then we do all
1036 op
= OP_NEW
| OP_DELETE
| OP_UPDATE
;
1038 drec
->type
= DISCOVERY_TYPE_SENDTARGETS
;
1040 * we will probably want to know how a specific iface and discovery
1041 * DB lined up, but for now just put all the targets found from
1042 * a discovery portal in one place
1044 if ((!(op
& OP_NONPERSISTENT
)) && sync_drec
) {
1045 rc
= idbm_add_discovery(drec
);
1047 log_error("Could not add new discovery record.");
1052 rc
= idbm_bind_ifaces_to_nodes(discovery_sendtargets
, drec
, ifaces
,
1055 log_error("Could not perform SendTargets discovery: %s",
1056 iscsi_err_to_str(rc
));
1058 } else if (list_empty(&rec_list
)) {
1059 log_error("No portals found");
1060 return ISCSI_ERR_NO_OBJS_FOUND
;
1063 rc
= exec_disc_op_on_recs(drec
, &rec_list
, info_level
, do_login
, op
);
1065 list_for_each_entry_safe(rec
, tmp
, &rec_list
, list
) {
1066 list_del(&rec
->list
);
1074 do_sendtargets(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1075 int info_level
, int do_login
, int op
, int sync_drec
)
1077 struct iface_rec
*tmp
, *iface
;
1079 struct iscsi_transport
*t
;
1081 if (list_empty(ifaces
)) {
1086 /* we allow users to mix hw and sw iscsi so we have to sort it out */
1087 list_for_each_entry_safe(iface
, tmp
, ifaces
, list
) {
1088 rc
= iface_conf_read(iface
);
1090 log_error("Could not read iface info for %s. "
1091 "Make sure a iface config with the file "
1092 "name and iface.iscsi_ifacename %s is in %s.",
1093 iface
->name
, iface
->name
, IFACE_CONFIG_DIR
);
1094 list_del(&iface
->list
);
1099 host_no
= iscsi_sysfs_get_host_no_from_hwinfo(iface
, &rc
);
1100 if (rc
|| host_no
== -1) {
1101 log_debug(1, "Could not match iface" iface_fmt
" to "
1102 "host.", iface_str(iface
));
1103 /* try software iscsi */
1107 t
= iscsi_sysfs_get_transport_by_hba(host_no
);
1109 log_error("Could not match hostno %d to "
1110 "transport. Dropping interface %s,"
1112 host_no
, iface
->transport_name
,
1113 iface_str(iface
), iface
->ipaddress
);
1114 list_del(&iface
->list
);
1119 if (t
->caps
& CAP_SENDTARGETS_OFFLOAD
) {
1120 do_offload_sendtargets(drec
, host_no
, do_login
);
1121 list_del(&iface
->list
);
1126 if (list_empty(ifaces
))
1127 return ISCSI_ERR_NO_OBJS_FOUND
;
1130 return do_software_sendtargets(drec
, ifaces
, info_level
, do_login
,
1134 static int do_isns(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1135 int info_level
, int do_login
, int op
)
1137 struct list_head rec_list
;
1138 struct node_rec
*rec
, *tmp
;
1141 INIT_LIST_HEAD(&rec_list
);
1143 * compat: if the user did not pass any op then we do all
1147 op
= OP_NEW
| OP_DELETE
| OP_UPDATE
;
1149 drec
->type
= DISCOVERY_TYPE_ISNS
;
1151 rc
= idbm_bind_ifaces_to_nodes(discovery_isns
, drec
, ifaces
,
1154 log_error("Could not perform iSNS discovery: %s",
1155 iscsi_err_to_str(rc
));
1157 } else if (list_empty(&rec_list
)) {
1158 log_error("No portals found");
1159 return ISCSI_ERR_NO_OBJS_FOUND
;
1162 rc
= exec_disc_op_on_recs(drec
, &rec_list
, info_level
, do_login
, op
);
1164 list_for_each_entry_safe(rec
, tmp
, &rec_list
, list
) {
1165 list_del(&rec
->list
);
1173 verify_mode_params(int argc
, char **argv
, char *allowed
, int skip_m
)
1180 while ((ch
= getopt_long(argc
, argv
, short_options
,
1181 long_options
, &longindex
)) >= 0) {
1182 if (!strchr(allowed
, ch
)) {
1183 if (ch
== 'm' && skip_m
)
1193 static void catch_sigint( int signo
) {
1194 log_warning("caught SIGINT, exiting...");
1198 /* TODO: merge iter helpers and clean them up, so we can use them here */
1199 static int exec_iface_op(int op
, int do_show
, int info_level
,
1200 struct iface_rec
*iface
, char *name
, char *value
)
1202 struct db_set_param set_param
;
1203 struct node_rec
*rec
= NULL
;
1209 log_error("Could not add interface. No interface "
1214 rec
= idbm_create_rec(NULL
, -1, NULL
, -1, iface
, 0);
1215 if (rec
&& iscsi_check_for_running_session(rec
)) {
1216 rc
= ISCSI_ERR_SESS_EXISTS
;
1220 iface_setup_defaults(iface
);
1221 rc
= iface_conf_write(iface
);
1224 printf("New interface %s added\n", iface
->name
);
1227 log_error("Could not create new interface %s.", iface
->name
);
1231 log_error("Could not delete interface. No interface "
1233 return ISCSI_ERR_INVAL
;
1236 rec
= idbm_create_rec(NULL
, -1, NULL
, -1, iface
, 1);
1238 rc
= ISCSI_ERR_INVAL
;
1242 /* logout and delete records using it first */
1243 rc
= __for_each_matched_rec(0, rec
, NULL
, delete_node
);
1244 if (rc
&& rc
!= ISCSI_ERR_NO_OBJS_FOUND
)
1247 rc
= iface_conf_delete(iface
);
1251 printf("%s unbound and deleted.\n", iface
->name
);
1254 log_error("Could not delete iface %s: %s", iface
->name
,
1255 iscsi_err_to_str(rc
));
1258 if (!iface
|| !name
|| !value
) {
1259 log_error("Update requires name, value, and iface.");
1260 rc
= ISCSI_ERR_INVAL
;
1264 rec
= idbm_create_rec(NULL
, -1, NULL
, -1, iface
, 1);
1266 rc
= ISCSI_ERR_INVAL
;
1270 if (iscsi_check_for_running_session(rec
))
1271 log_warning("Updating iface while iscsi sessions "
1272 "are using it. You must logout the running "
1273 "sessions then log back in for the "
1274 "new settings to take affect.");
1276 if (!strcmp(name
, IFACE_ISCSINAME
)) {
1277 log_error("Can not update "
1278 "iface.iscsi_ifacename. Delete it, "
1279 "and then create a new one.");
1280 rc
= ISCSI_ERR_INVAL
;
1284 if (iface_is_bound_by_hwaddr(&rec
->iface
) &&
1285 !strcmp(name
, IFACE_NETNAME
)) {
1286 log_error("Can not update interface binding "
1287 "from hwaddress to net_ifacename. ");
1288 log_error("You must delete the interface and "
1289 "create a new one");
1290 rc
= ISCSI_ERR_INVAL
;
1294 if (iface_is_bound_by_netdev(&rec
->iface
) &&
1295 !strcmp(name
, IFACE_HWADDR
)) {
1296 log_error("Can not update interface binding "
1297 "from net_ifacename to hwaddress. ");
1298 log_error("You must delete the interface and "
1299 "create a new one");
1300 rc
= ISCSI_ERR_INVAL
;
1303 set_param
.name
= name
;
1304 set_param
.value
= value
;
1306 /* pass rec's iface because it has the db values */
1307 rc
= iface_conf_update(&set_param
, &rec
->iface
);
1311 rc
= __for_each_matched_rec(0, rec
, &set_param
,
1312 idbm_node_set_param
);
1313 if (rc
== ISCSI_ERR_NO_OBJS_FOUND
)
1318 printf("%s updated.\n", iface
->name
);
1321 log_error("Could not update iface %s: %s",
1322 iface
->name
, iscsi_err_to_str(rc
));
1325 if (!iface
|| (iface
&& info_level
> 0)) {
1326 if (op
== OP_NOOP
|| op
== OP_SHOW
)
1327 rc
= print_ifaces(iface
, info_level
);
1329 rc
= ISCSI_ERR_INVAL
;
1331 rc
= iface_conf_read(iface
);
1333 idbm_print_iface_info(&do_show
, iface
);
1335 log_error("Could not read iface %s (%d).",
1345 /* TODO cleanup arguments */
1346 static int exec_node_op(int op
, int do_login
, int do_logout
,
1347 int do_show
, int do_rescan
, int do_stats
,
1348 int info_level
, struct node_rec
*rec
,
1349 char *name
, char *value
)
1352 struct db_set_param set_param
;
1355 log_debug(2, "%s: %s:%s node [%s,%s,%d] sid %u", __FUNCTION__
,
1356 rec
->iface
.transport_name
, rec
->iface
.name
,
1357 rec
->name
, rec
->conn
[0].address
, rec
->conn
[0].port
,
1361 rc
= add_static_recs(rec
);
1366 rc
= for_each_session(rec
, rescan_portal
);
1371 rc
= for_each_session(rec
, session_stats
);
1375 if (do_login
&& do_logout
) {
1376 log_error("Invalid parameters. Both login and logout passed in");
1377 rc
= ISCSI_ERR_INVAL
;
1381 if ((do_login
|| do_logout
) && op
> OP_NOOP
) {
1382 log_error("Invalid parameters. Login/logout and op passed in");
1383 rc
= ISCSI_ERR_INVAL
;
1387 if ((!do_login
&& !do_logout
&& op
== OP_NOOP
) &&
1388 (!strlen(rec
->name
) && !strlen(rec
->conn
[0].address
) &&
1389 !strlen(rec
->iface
.name
))) {
1390 rc
= print_nodes(info_level
, rec
);
1395 rc
= login_portals(rec
);
1402 rc
= iscsi_logout_portals(rec
, &nr_found
, 1,
1403 iscsi_logout_matched_portal
);
1404 if (rc
== ISCSI_ERR_NO_OBJS_FOUND
)
1405 log_error("No matching sessions found");
1409 if (op
== OP_NOOP
|| (!do_login
&& !do_logout
&& op
== OP_SHOW
)) {
1410 rc
= for_each_matched_rec(rec
, &do_show
, idbm_print_node_info
);
1414 if (op
== OP_UPDATE
) {
1415 if (!name
|| !value
) {
1416 log_error("update requires name and value");
1417 rc
= ISCSI_ERR_INVAL
;
1421 /* compat - old tools used node and iface transport name */
1422 if (!strncmp(name
, "iface.", 6) &&
1423 strcmp(name
, "iface.transport_name")) {
1424 log_error("Cannot modify %s. Use iface mode to update "
1425 "this value.", name
);
1426 rc
= ISCSI_ERR_INVAL
;
1430 if (!strcmp(name
, "node.transport_name"))
1431 name
= "iface.transport_name";
1433 * tmp hack - we added compat crap above for the transport,
1434 * but want to fix Doran's issue in this release too. However
1435 * his patch is too harsh on many settings and we do not have
1436 * time to update apps so we have this tmp hack until we
1437 * can settle on a good interface that distros can use
1438 * and we can mark stable.
1440 if (!strcmp(name
, "iface.transport_name")) {
1441 if (iscsi_check_for_running_session(rec
)) {
1442 log_warning("Cannot modify node/iface "
1443 "transport name while a session "
1444 "is using it. Log out the session "
1445 "then update record.");
1446 rc
= ISCSI_ERR_SESS_EXISTS
;
1451 set_param
.name
= name
;
1452 set_param
.value
= value
;
1454 rc
= for_each_matched_rec(rec
, &set_param
, idbm_node_set_param
);
1456 } else if (op
== OP_DELETE
) {
1457 rc
= for_each_matched_rec(rec
, NULL
, delete_node
);
1460 log_error("operation is not supported.");
1461 rc
= ISCSI_ERR_INVAL
;
1468 static int exec_fw_disc_op(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1469 int info_level
, int do_login
, int op
)
1471 struct list_head targets
, rec_list
, new_ifaces
;
1472 struct iface_rec
*iface
, *tmp_iface
;
1473 struct node_rec
*rec
, *tmp_rec
;
1476 INIT_LIST_HEAD(&targets
);
1477 INIT_LIST_HEAD(&rec_list
);
1478 INIT_LIST_HEAD(&new_ifaces
);
1480 * compat: if the user did not pass any op then we do all
1484 op
= OP_NEW
| OP_DELETE
| OP_UPDATE
;
1487 * if a user passed in ifaces then we use them and ignore the ibft
1490 if (!list_empty(ifaces
)) {
1491 list_for_each_entry_safe(iface
, tmp_iface
, ifaces
, list
) {
1492 rc
= iface_conf_read(iface
);
1494 log_error("Could not read iface info for %s. "
1495 "Make sure a iface config with the "
1496 "file name and iface.iscsi_ifacename "
1497 "%s is in %s.", iface
->name
,
1498 iface
->name
, IFACE_CONFIG_DIR
);
1499 list_del_init(&iface
->list
);
1504 goto discover_fw_tgts
;
1508 * Next, check if we see any offload cards. If we do then
1509 * we make a iface if needed.
1511 * Note1: if there is not a offload card we do not setup
1512 * software iscsi binding with the nic used for booting,
1513 * because we do not know if that was intended.
1515 * Note2: we assume that the user probably wanted to access
1516 * all targets through all the ifaces instead of being limited
1517 * to what you can export in ibft.
1519 rc
= fw_get_targets(&targets
);
1521 log_error("Could not get list of targets from firmware. "
1525 rc
= iface_create_ifaces_from_boot_contexts(&new_ifaces
, &targets
);
1528 if (!list_empty(&new_ifaces
))
1529 ifaces
= &new_ifaces
;
1532 rc
= idbm_bind_ifaces_to_nodes(discovery_fw
, drec
,
1535 log_error("Could not perform fw discovery.\n");
1537 rc
= exec_disc_op_on_recs(drec
, &rec_list
, info_level
,
1541 fw_free_targets(&targets
);
1543 list_for_each_entry_safe(iface
, tmp_iface
, &new_ifaces
, list
) {
1544 list_del(&iface
->list
);
1548 list_for_each_entry_safe(rec
, tmp_rec
, &rec_list
, list
) {
1549 list_del(&rec
->list
);
1555 static int exec_fw_op(discovery_rec_t
*drec
, struct list_head
*ifaces
,
1556 int info_level
, int do_login
, int op
)
1558 struct boot_context
*context
;
1559 struct list_head targets
, rec_list
;
1560 struct node_rec
*rec
;
1563 INIT_LIST_HEAD(&targets
);
1564 INIT_LIST_HEAD(&rec_list
);
1567 return exec_fw_disc_op(drec
, ifaces
, info_level
, do_login
, op
);
1569 /* The following ops do not interact with the DB */
1570 rc
= fw_get_targets(&targets
);
1572 log_error("Could not get list of targets from firmware. "
1578 list_for_each_entry(context
, &targets
, list
) {
1579 rec
= idbm_create_rec_from_boot_context(context
);
1581 log_error("Could not convert firmware info to "
1583 rc
= ISCSI_ERR_NOMEM
;
1587 iscsi_login_portal(NULL
, NULL
, rec
);
1591 list_for_each_entry(context
, &targets
, list
)
1592 fw_print_entry(context
);
1595 fw_free_targets(&targets
);
1599 static void setup_drec_defaults(int type
, char *ip
, int port
,
1600 struct discovery_rec
*drec
)
1603 case DISCOVERY_TYPE_ISNS
:
1604 idbm_isns_defaults(&drec
->u
.isns
);
1606 case DISCOVERY_TYPE_SENDTARGETS
:
1607 idbm_sendtargets_defaults(&drec
->u
.sendtargets
);
1610 log_error("Invalid disc type.");
1612 strlcpy(drec
->address
, ip
, sizeof(drec
->address
));
1618 * exec_discover - prep, add, read and exec discovery on drec
1619 * @type: discovery type
1622 * @ifaces: list of ifaces to bind to
1623 * @info_level: print level
1624 * @do_login: set to 1 if discovery function should also log into portals found
1625 * @do_discover: set to 1 if discovery was requested
1626 * @op: ops passed in by user
1627 * @drec: discovery rec struct
1629 * This function determines what type of op needs to be executed
1630 * and will read and add a drec, and perform discovery if needed.
1633 * Greater than 0 - error
1634 * 0 - op/discovery completed
1637 static int exec_discover(int disc_type
, char *ip
, int port
,
1638 struct list_head
*ifaces
, int info_level
,
1639 int do_login
, int do_discover
, int op
,
1640 struct discovery_rec
*drec
)
1645 log_error("Please specify portal as <ipaddr>[:<ipport>]");
1646 return ISCSI_ERR_INVAL
;
1649 if (op
& OP_NEW
&& !do_discover
) {
1650 setup_drec_defaults(disc_type
, ip
, port
, drec
);
1652 rc
= idbm_add_discovery(drec
);
1654 log_error("Could not add new discovery record.");
1657 printf("New discovery record for [%s,%d] added.\n", ip
,
1663 rc
= idbm_discovery_read(drec
, disc_type
, ip
, port
);
1666 log_error("Discovery record [%s,%d] not found.",
1671 /* Just add default rec for user */
1672 log_debug(1, "Discovery record [%s,%d] not found!",
1674 setup_drec_defaults(disc_type
, ip
, port
, drec
);
1675 if (!(op
& OP_NONPERSISTENT
)) {
1676 rc
= idbm_add_discovery(drec
);
1678 log_error("Could not add new discovery "
1683 } else if (!do_discover
)
1687 switch (disc_type
) {
1688 case DISCOVERY_TYPE_SENDTARGETS
:
1690 * idbm_add_discovery call above handles drec syncing so
1691 * we always pass in 0 here.
1693 rc
= do_sendtargets(drec
, ifaces
, info_level
, do_login
, op
,
1696 case DISCOVERY_TYPE_ISNS
:
1697 rc
= do_isns(drec
, ifaces
, info_level
, do_login
, op
);
1700 log_error("Unsupported discovery type.");
1707 static int exec_disc2_op(int disc_type
, char *ip
, int port
,
1708 struct list_head
*ifaces
, int info_level
, int do_login
,
1709 int do_discover
, int op
, char *name
, char *value
,
1712 struct discovery_rec drec
;
1715 memset(&drec
, 0, sizeof(struct discovery_rec
));
1716 if (disc_type
!= -1)
1717 drec
.type
= disc_type
;
1719 switch (disc_type
) {
1720 case DISCOVERY_TYPE_SENDTARGETS
:
1722 port
= ISCSI_LISTEN_PORT
;
1724 rc
= exec_discover(disc_type
, ip
, port
, ifaces
, info_level
,
1725 do_login
, do_discover
, op
, &drec
);
1729 case DISCOVERY_TYPE_SLP
:
1730 log_error("SLP discovery is not fully implemented yet.");
1731 rc
= ISCSI_ERR_INVAL
;
1733 case DISCOVERY_TYPE_ISNS
:
1735 port
= ISNS_DEFAULT_PORT
;
1737 rc
= exec_discover(disc_type
, ip
, port
, ifaces
, info_level
,
1738 do_login
, do_discover
, op
, &drec
);
1742 case DISCOVERY_TYPE_FW
:
1744 log_error("Invalid command. Possibly missing "
1745 "--discover argument.");
1746 rc
= ISCSI_ERR_INVAL
;
1750 drec
.type
= DISCOVERY_TYPE_FW
;
1751 rc
= exec_fw_op(&drec
, ifaces
, info_level
, do_login
, op
);
1754 rc
= ISCSI_ERR_INVAL
;
1757 if (op
== OP_NOOP
|| op
== OP_SHOW
) {
1758 if (idbm_print_all_discovery(info_level
))
1759 /* successfully found some recs */
1762 rc
= ISCSI_ERR_NO_OBJS_FOUND
;
1764 log_error("Invalid operation. Operation not "
1767 log_error("Invalid command. Possibly missing discovery "
1770 log_error("Invalid command. Portal not needed or "
1771 "Possibly missing discovery --type.");
1778 if (op
== OP_NOOP
|| op
== OP_SHOW
) {
1779 if (!idbm_print_discovery_info(&drec
, do_show
)) {
1780 log_error("No records found");
1781 rc
= ISCSI_ERR_NO_OBJS_FOUND
;
1783 } else if (op
== OP_DELETE
) {
1784 rc
= idbm_delete_discovery(&drec
);
1786 log_error("Unable to delete record!");
1787 } else if (op
== OP_UPDATE
) {
1788 struct db_set_param set_param
;
1790 if (!name
|| !value
) {
1791 log_error("Update requires name and value.");
1792 rc
= ISCSI_ERR_INVAL
;
1795 set_param
.name
= name
;
1796 set_param
.value
= value
;
1797 rc
= idbm_discovery_set_param(&set_param
, &drec
);
1799 log_error("Operation is not supported.");
1800 rc
= ISCSI_ERR_INVAL
;
1807 static int exec_disc_op(int disc_type
, char *ip
, int port
,
1808 struct list_head
*ifaces
, int info_level
, int do_login
,
1809 int do_discover
, int op
, char *name
, char *value
,
1812 struct discovery_rec drec
;
1815 memset(&drec
, 0, sizeof(struct discovery_rec
));
1817 switch (disc_type
) {
1818 case DISCOVERY_TYPE_SENDTARGETS
:
1819 drec
.type
= DISCOVERY_TYPE_SENDTARGETS
;
1822 port
= ISCSI_LISTEN_PORT
;
1825 log_error("Please specify portal as "
1826 "<ipaddr>[:<ipport>]");
1827 rc
= ISCSI_ERR_INVAL
;
1831 idbm_sendtargets_defaults(&drec
.u
.sendtargets
);
1832 strlcpy(drec
.address
, ip
, sizeof(drec
.address
));
1835 rc
= do_sendtargets(&drec
, ifaces
, info_level
,
1840 case DISCOVERY_TYPE_SLP
:
1841 log_error("SLP discovery is not fully implemented yet.");
1842 rc
= ISCSI_ERR_INVAL
;
1844 case DISCOVERY_TYPE_ISNS
:
1846 log_error("Please specify portal as "
1847 "<ipaddr>:[<ipport>]");
1848 rc
= ISCSI_ERR_INVAL
;
1852 strlcpy(drec
.address
, ip
, sizeof(drec
.address
));
1854 drec
.port
= ISNS_DEFAULT_PORT
;
1858 rc
= do_isns(&drec
, ifaces
, info_level
, do_login
, op
);
1862 case DISCOVERY_TYPE_FW
:
1863 drec
.type
= DISCOVERY_TYPE_FW
;
1864 rc
= exec_fw_op(&drec
, ifaces
, info_level
, do_login
, op
);
1869 * We only have sendtargets disc recs in discovery
1870 * mode, so we can hardcode the port check to the
1871 * iscsi default here.
1873 * For isns or slp recs then discovery db mode
1877 port
= ISCSI_LISTEN_PORT
;
1879 if (idbm_discovery_read(&drec
,
1880 DISCOVERY_TYPE_SENDTARGETS
,
1882 log_error("Discovery record [%s,%d] "
1883 "not found!", ip
, port
);
1884 rc
= ISCSI_ERR_INVAL
;
1887 if ((do_discover
|| do_login
) &&
1888 drec
.type
== DISCOVERY_TYPE_SENDTARGETS
) {
1889 rc
= do_sendtargets(&drec
, ifaces
, info_level
,
1891 } else if (op
== OP_NOOP
|| op
== OP_SHOW
) {
1892 if (!idbm_print_discovery_info(&drec
,
1894 log_error("No records found");
1895 rc
= ISCSI_ERR_NO_OBJS_FOUND
;
1897 } else if (op
== OP_DELETE
) {
1898 rc
= idbm_delete_discovery(&drec
);
1900 log_error("Unable to delete record!");
1901 } else if (op
== OP_UPDATE
|| op
== OP_NEW
) {
1902 log_error("Operations new and update for "
1903 "discovery mode is not supported. "
1904 "Use discoverydb mode.");
1905 rc
= ISCSI_ERR_INVAL
;
1908 log_error("Invalid operation.");
1909 rc
= ISCSI_ERR_INVAL
;
1912 } else if (op
== OP_NOOP
|| op
== OP_SHOW
) {
1913 if (!idbm_print_all_discovery(info_level
))
1914 rc
= ISCSI_ERR_NO_OBJS_FOUND
;
1917 log_error("Invalid operation.");
1918 rc
= ISCSI_ERR_INVAL
;
1929 main(int argc
, char **argv
)
1931 char *ip
= NULL
, *name
= NULL
, *value
= NULL
;
1932 char *targetname
= NULL
, *group_session_mgmt_mode
= NULL
;
1933 int ch
, longindex
, mode
=-1, port
=-1, do_login
=0, do_rescan
=0;
1934 int rc
=0, sid
=-1, op
=OP_NOOP
, type
=-1, do_logout
=0, do_stats
=0;
1935 int do_login_all
=0, do_logout_all
=0, info_level
=-1, num_ifaces
= 0;
1936 int tpgt
= PORTAL_GROUP_TAG_UNKNOWN
, killiscsid
=-1, do_show
=0;
1937 int do_discover
= 0;
1938 struct sigaction sa_old
;
1939 struct sigaction sa_new
;
1940 struct list_head ifaces
;
1941 struct iface_rec
*iface
= NULL
, *tmp
;
1942 struct node_rec
*rec
= NULL
;
1943 uint32_t host_no
= -1;
1945 INIT_LIST_HEAD(&ifaces
);
1946 /* do not allow ctrl-c for now... */
1947 memset(&sa_old
, 0, sizeof(struct sigaction
));
1948 memset(&sa_new
, 0, sizeof(struct sigaction
));
1950 sa_new
.sa_handler
= catch_sigint
;
1951 sigemptyset(&sa_new
.sa_mask
);
1952 sa_new
.sa_flags
= 0;
1953 sigaction(SIGINT
, &sa_new
, &sa_old
);
1957 /* enable stdout logging */
1958 log_init(program_name
, 1024, log_do_log_std
, NULL
);
1962 while ((ch
= getopt_long(argc
, argv
, short_options
,
1963 long_options
, &longindex
)) >= 0) {
1966 killiscsid
= atoi(optarg
);
1967 if (killiscsid
< 0) {
1968 log_error("Invalid killiscsid priority %d "
1969 "Priority must be greater than or "
1970 "equal to zero.", killiscsid
);
1971 rc
= ISCSI_ERR_INVAL
;
1976 type
= str_to_type(optarg
);
1979 op
|= str_to_op(optarg
);
1980 if (op
== OP_NOOP
) {
1981 log_error("can not recognize operation: '%s'",
1983 rc
= ISCSI_ERR_INVAL
;
1995 host_no
= strtoul(optarg
, NULL
, 10);
1997 log_error("invalid host no %s. %s.",
1998 optarg
, strerror(errno
));
1999 rc
= ISCSI_ERR_INVAL
;
2004 sid
= iscsi_sysfs_get_sid_from_path(optarg
);
2006 log_error("invalid sid '%s'",
2008 rc
= ISCSI_ERR_INVAL
;
2016 info_level
= atoi(optarg
);
2029 group_session_mgmt_mode
= optarg
;
2033 group_session_mgmt_mode
= optarg
;
2042 log_level
= atoi(optarg
);
2045 mode
= str_to_mode(optarg
);
2048 targetname
= optarg
;
2051 ip
= str_to_ipport(optarg
, &port
, &tpgt
);
2054 iface
= iface_alloc(optarg
, &rc
);
2055 if (rc
== ISCSI_ERR_INVAL
) {
2056 printf("Invalid iface name %s. Must be from "
2057 "1 to %d characters.\n",
2058 optarg
, ISCSI_MAX_IFACE_LEN
- 1);
2060 } else if (!iface
|| rc
) {
2061 printf("Could not add iface %s.", optarg
);
2062 rc
= ISCSI_ERR_INVAL
;
2066 list_add_tail(&iface
->list
, &ifaces
);
2070 printf("%s version %s\n", program_name
,
2079 log_error("unrecognized character '%c'", optopt
);
2080 rc
= ISCSI_ERR_INVAL
;
2084 if (killiscsid
>= 0) {
2085 kill_iscsid(killiscsid
);
2090 usage(ISCSI_ERR_INVAL
);
2092 if (mode
== MODE_FW
) {
2093 if ((rc
= verify_mode_params(argc
, argv
, "ml", 0))) {
2094 log_error("fw mode: option '-%c' is not "
2095 "allowed/supported", rc
);
2096 rc
= ISCSI_ERR_INVAL
;
2100 rc
= exec_fw_op(NULL
, NULL
, info_level
, do_login
, op
);
2104 increase_max_files();
2105 if (idbm_init(get_config_file
)) {
2106 log_warning("exiting due to idbm configuration error");
2107 rc
= ISCSI_ERR_IDBM
;
2113 if ((rc
= verify_mode_params(argc
, argv
, "HdmP", 0))) {
2114 log_error("host mode: option '-%c' is not "
2115 "allowed/supported", rc
);
2116 rc
= ISCSI_ERR_INVAL
;
2120 rc
= host_info_print(info_level
, host_no
);
2123 iface_setup_host_bindings();
2125 if ((rc
= verify_mode_params(argc
, argv
, "IdnvmPo", 0))) {
2126 log_error("iface mode: option '-%c' is not "
2127 "allowed/supported", rc
);
2128 rc
= ISCSI_ERR_INVAL
;
2132 if (!list_empty(&ifaces
)) {
2133 iface
= list_entry(ifaces
.next
, struct iface_rec
,
2136 log_error("iface mode only accepts one "
2137 "interface. Using the first one "
2138 "%s.", iface
->name
);
2140 rc
= exec_iface_op(op
, do_show
, info_level
, iface
,
2143 case MODE_DISCOVERYDB
:
2144 if ((rc
= verify_mode_params(argc
, argv
, "DSIPdmntplov", 0))) {
2145 log_error("discovery mode: option '-%c' is not "
2146 "allowed/supported", rc
);
2147 rc
= ISCSI_ERR_INVAL
;
2151 rc
= exec_disc2_op(type
, ip
, port
, &ifaces
, info_level
,
2152 do_login
, do_discover
, op
, name
, value
,
2155 case MODE_DISCOVERY
:
2156 if ((rc
= verify_mode_params(argc
, argv
, "DSIPdmntplov", 0))) {
2157 log_error("discovery mode: option '-%c' is not "
2158 "allowed/supported", rc
);
2159 rc
= ISCSI_ERR_INVAL
;
2163 rc
= exec_disc_op(type
, ip
, port
, &ifaces
, info_level
,
2164 do_login
, do_discover
, op
, name
, value
,
2168 if ((rc
= verify_mode_params(argc
, argv
, "RsPIdmlSonvupTUL",
2170 log_error("node mode: option '-%c' is not "
2171 "allowed/supported", rc
);
2172 rc
= ISCSI_ERR_INVAL
;
2177 rc
= login_by_startup(group_session_mgmt_mode
);
2181 if (do_logout_all
) {
2182 rc
= logout_by_startup(group_session_mgmt_mode
);
2186 if (!list_empty(&ifaces
)) {
2187 iface
= list_entry(ifaces
.next
, struct iface_rec
,
2190 log_error("NODE mode only accepts one "
2191 "interface. Using the first one "
2192 "driver %s hwaddress %s ipaddress "
2193 "%s.", iface
->transport_name
,
2194 iface
->hwaddress
, iface
->ipaddress
);
2197 if (ip
&& port
== -1)
2198 port
= ISCSI_LISTEN_PORT
;
2200 rec
= idbm_create_rec(targetname
, tpgt
, ip
, port
, iface
, 1);
2202 rc
= ISCSI_ERR_NOMEM
;
2206 rc
= exec_node_op(op
, do_login
, do_logout
, do_show
,
2207 do_rescan
, do_stats
, info_level
, rec
,
2211 if ((rc
= verify_mode_params(argc
, argv
,
2212 "PiRdrmusonuSv", 1))) {
2213 log_error("session mode: option '-%c' is not "
2214 "allowed or supported", rc
);
2215 rc
= ISCSI_ERR_INVAL
;
2220 struct session_info
*info
;
2222 snprintf(session
, 63, "session%d", sid
);
2225 info
= calloc(1, sizeof(*info
));
2227 rc
= ISCSI_ERR_NOMEM
;
2231 rc
= iscsi_sysfs_get_sessioninfo_by_id(info
, session
);
2233 log_error("Could not get session info for sid "
2239 * We should be able to go on, but for now
2240 * we only support session mode ops if the module
2241 * is loaded and we support that module.
2243 if (!iscsi_sysfs_get_transport_by_sid(sid
))
2246 if (!do_logout
&& !do_rescan
&& !do_stats
&&
2247 op
== OP_NOOP
&& info_level
> 0) {
2248 rc
= session_info_print(info_level
, info
);
2252 rec
= idbm_create_rec(info
->targetname
,
2254 info
->persistent_address
,
2255 info
->persistent_port
,
2258 rc
= ISCSI_ERR_NOMEM
;
2261 rec
->session
.info
= info
;
2262 rec
->session
.sid
= sid
;
2265 * A "new" session means to login a multiple of the
2266 * currently-detected session.
2271 rec
->session
.multiple
= 1;
2274 /* drop down to node ops */
2275 rc
= exec_node_op(op
, do_login
, do_logout
, do_show
,
2276 do_rescan
, do_stats
, info_level
,
2283 log_error("session mode: Operation 'new' only "
2284 "allowed with specific session IDs");
2285 rc
= ISCSI_ERR_INVAL
;
2288 if (do_logout
|| do_rescan
|| do_stats
) {
2289 rc
= exec_node_op(op
, do_login
, do_logout
,
2290 do_show
, do_rescan
, do_stats
,
2291 info_level
, NULL
, name
, value
);
2295 rc
= session_info_print(info_level
, NULL
);
2299 log_error("This mode is not yet supported");
2308 list_for_each_entry_safe(iface
, tmp
, &ifaces
, list
) {
2309 list_del(&iface
->list
);