open-isns: Fix warnings reported by gcc-4.5.2
[open-iscsi.git] / usr / iscsiadm.c
blob91d886b0ad74f6341c9392c4628f77260742570f
1 /*
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.
23 #include <errno.h>
24 #include <getopt.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <signal.h>
30 #include <sys/stat.h>
32 #include "initiator.h"
33 #include "discovery.h"
34 #include "log.h"
35 #include "mgmt_ipc.h"
36 #include "idbm.h"
37 #include "iscsi_util.h"
38 #include "transport.h"
39 #include "version.h"
40 #include "iscsi_sysfs.h"
41 #include "list.h"
42 #include "iscsi_settings.h"
43 #include "fw_context.h"
44 #include "iface.h"
45 #include "session_info.h"
46 #include "host.h"
47 #include "sysdeps.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;
58 enum iscsiadm_mode {
59 MODE_DISCOVERY,
60 MODE_DISCOVERYDB,
61 MODE_NODE,
62 MODE_SESSION,
63 MODE_HOST,
64 MODE_IFACE,
65 MODE_FW,
68 enum iscsiadm_op {
69 OP_NOOP = 0x0,
70 OP_NEW = 0x1,
71 OP_DELETE = 0x2,
72 OP_UPDATE = 0x4,
73 OP_SHOW = 0x8,
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'},
102 {NULL, 0, NULL, 0},
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)
108 if (status != 0)
109 fprintf(stderr, "Try `%s --help' for more information.\n",
110 program_name);
111 else {
112 printf("\
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");
124 exit(status);
127 static int
128 str_to_op(char *str)
130 int op;
132 if (!strcmp("new", str))
133 op = OP_NEW;
134 else if (!strcmp("delete", str))
135 op = OP_DELETE;
136 else if (!strcmp("update", str))
137 op = OP_UPDATE;
138 else if (!strcmp("show", str))
139 op = OP_SHOW;
140 else if (!strcmp("nonpersistent", str))
141 op = OP_NONPERSISTENT;
142 else
143 op = OP_NOOP;
145 return op;
148 static int
149 str_to_mode(char *str)
151 int mode;
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))
158 mode = MODE_NODE;
159 else if (!strcmp("session", str))
160 mode = MODE_SESSION;
161 else if (!strcmp("iface", str))
162 mode = MODE_IFACE;
163 else if (!strcmp("fw", str))
164 mode = MODE_FW;
165 else if (!strcmp("host", str))
166 mode = MODE_HOST;
167 else
168 mode = -1;
170 return mode;
173 static int
174 str_to_type(char *str)
176 int type;
178 if (!strcmp("sendtargets", str) ||
179 !strcmp("st", 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;
187 else
188 type = -1;
190 return type;
193 static void kill_iscsid(int priority)
195 iscsiadm_req_t req;
196 iscsiadm_rsp_t rsp;
197 int rc;
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
205 * exiting.
207 if (priority != 0) {
208 log_error("Invalid iscsid priority %d. Priority must be 0.",
209 priority);
210 return;
213 memset(&req, 0, sizeof(req));
214 req.command = MGMT_IPC_IMMEDIATE_STOP;
215 rc = iscsid_exec_req(&req, &rsp, 0);
216 if (rc) {
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) {
235 case 0:
236 case -1:
237 err = iface_for_each_iface(NULL, 0, &num_found,
238 iface_print_flat);
239 break;
240 case 1:
241 if (iface) {
242 err = iface_conf_read(iface);
243 if (err) {
244 log_error("Could not read iface %s.\n",
245 iface->name);
246 return err;
248 iface_print_tree(NULL, iface);
249 num_found = 1;
250 } else
251 err = iface_for_each_iface(NULL, 0, &num_found,
252 iface_print_tree);
253 break;
254 default:
255 log_error("Invalid info level %d. Try 0 - 1.", info_level);
256 return ISCSI_ERR_INVAL;
259 if (!num_found) {
260 log_error("No interfaces found.");
261 err = ISCSI_ERR_NO_OBJS_FOUND;
263 return err;
266 static int
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"))
276 return 0;
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"))
286 return 0;
288 return -1;
291 static int
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) {
297 num_found = 1;
298 err = fn(rec, rec->session.info);
299 } else {
300 err = iscsi_sysfs_for_each_session(rec, &num_found, fn);
302 if (err)
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;
310 return err;
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));
319 if (!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);
324 return 0;
327 static int
328 __logout_by_startup(void *data, struct list_head *list,
329 struct session_info *info)
331 char *mode = data;
332 node_rec_t rec;
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
340 * not hooked in
342 log_debug(7, "could not read data for [%s,%s.%d]\n",
343 info->targetname, info->persistent_address,
344 info->persistent_port);
345 return -1;
348 /* multiple drivers could be connected to the same portal */
349 if (strcmp(rec.iface.transport_name, info->iface.transport_name))
350 return -1;
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)
356 return -1;
358 if (match_startup_mode(&rec, mode))
359 return -1;
361 return iscsi_logout_portal(info, list);
364 static int
365 logout_by_startup(char *mode)
367 int nr_found;
368 int rc;
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");
380 return rc;
383 struct startup_data {
384 char *mode;
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))
395 return -1;
397 rec_copy = calloc(1, sizeof(*rec_copy));
398 if (!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);
405 else
406 list_add_tail(&rec_copy->list, &startup->all_logins);
407 return 0;
410 static int
411 __do_leading_login(void *data, struct list_head *list, struct node_rec *rec)
413 struct iface_rec *pattern_iface = data;
414 int nr_found;
416 /* Skip any records that do not match the pattern iface */
417 if (!iface_match(pattern_iface, &rec->iface))
418 return -1;
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",
426 rec->name);
427 return -1;
430 /* No existing session: Attempt a login. */
431 return iscsi_login_portal(NULL, list, rec);
434 static int
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.
451 startup.mode = mode;
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)) {
462 if (err) {
463 log_error("Could not read node DB: %s.",
464 iscsi_err_to_str(err));
465 } else {
466 log_error("No records found");
467 err = ISCSI_ERR_NO_OBJS_FOUND;
469 return err;
471 rc = err;
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);
478 if (err)
479 log_error("Could not log into all portals");
480 if (err && !rc)
481 rc = err;
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,
497 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,
503 __do_leading_login);
504 if (err)
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
519 * one session
521 list_for_each_entry_safe(rec, tmp_rec, &startup.leading_logins,
522 list) {
523 if (!iscsi_sysfs_for_each_session(rec, &nr_found,
524 iscsi_match_target))
525 missed_leading_login++;
527 * Cleanup the list, since 'iscsi_login_portals_safe'
528 * does not
530 list_del(&rec->list);
531 free(rec);
533 if (missed_leading_login) {
534 log_error("Could not login all leading-login portals");
535 if (!rc)
536 rc = ISCSI_ERR_FATAL_LOGIN;
540 return rc;
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);
556 if (!t)
557 return -1;
559 if (!iscsi_match_session(pattern_rec, info))
560 return -1;
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,
567 info->port);
568 log_error("Logout not supported for driver: %s.", t->name);
569 return -1;
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))
581 return -1;
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));
592 op_data.data = data;
593 op_data.match_rec = rec;
594 op_data.fn = fn;
596 rc = idbm_for_each_rec(&nr_found, &op_data, rec_match_fn);
597 if (rc) {
598 if (verbose)
599 log_error("Could not execute operation on all "
600 "records: %s", iscsi_err_to_str(rc));
601 } else if (!nr_found) {
602 if (verbose)
603 log_error("No records found");
604 rc = ISCSI_ERR_NO_OBJS_FOUND;
607 return rc;
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)
625 return err;
626 else if (err && list_empty(&rec_list))
627 return err;
629 rc = err;
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,
633 iscsi_login_portal);
634 if (err)
635 log_error("Could not log into all portals");
637 if (err && !rc)
638 rc = err;
640 return rc;
643 static int print_nodes(int info_level, struct node_rec *rec)
645 struct node_rec tmp_rec;
646 int rc = 0;
648 switch (info_level) {
649 case 0:
650 case -1:
651 rc = for_each_matched_rec(rec, NULL, idbm_print_node_flat);
652 break;
653 case 1:
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);
657 break;
658 default:
659 log_error("Invalid info level %d. Try 0 or 1.", info_level);
660 rc = ISCSI_ERR_INVAL;
663 return rc;
666 static char *get_config_file(void)
668 int rc;
669 iscsiadm_req_t req;
670 iscsiadm_rsp_t rsp;
672 memset(&req, 0, sizeof(req));
673 req.command = MGMT_IPC_CONFIG_FILE;
675 rc = iscsid_exec_req(&req, &rsp, 1);
676 if (rc)
677 return NULL;
679 if (rsp.u.config.var[0] != '\0') {
680 strcpy(config_file, rsp.u.config.var);
681 return config_file;
684 return NULL;
687 static int rescan_portal(void *data, struct session_info *info)
689 int host_no, err;
691 if (!iscsi_match_session(data, info))
692 return -1;
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);
699 if (err) {
700 log_error("Could not rescan session sid %d.", info->sid);
701 return err;
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);
708 return 0;
711 static int
712 session_stats(void *data, struct session_info *info)
714 int rc, i;
715 iscsiadm_req_t req;
716 iscsiadm_rsp_t rsp;
718 if (!iscsi_match_session(data, info))
719 return -1;
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);
726 if (rc)
727 return rc;
729 printf("Stats for session [sid: %d, target: %s, portal: "
730 "%s,%d]\n",
731 info->sid, info->targetname, info->persistent_address,
732 info->port);
734 printf( "iSCSI SNMP:\n"
736 "\ttxdata_octets: %lld\n"
737 "\trxdata_octets: %lld\n"
739 "\tnoptx_pdus: %u\n"
740 "\tscsicmd_pdus: %u\n"
741 "\ttmfcmd_pdus: %u\n"
742 "\tlogin_pdus: %u\n"
743 "\ttext_pdus: %u\n"
744 "\tdataout_pdus: %u\n"
745 "\tlogout_pdus: %u\n"
746 "\tsnack_pdus: %u\n"
748 "\tnoprx_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"
754 "\tr2t_pdus: %u\n"
755 "\tasync_pdus: %u\n"
756 "\trjt_pdus: %u\n"
758 "\tdigest_err: %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);
793 return 0;
796 static int add_static_rec(int *found, char *targetname, int tpgt,
797 char *ip, int port, struct iface_rec *iface)
799 node_rec_t *rec;
800 discovery_rec_t *drec;
801 int rc;
803 rec = calloc(1, sizeof(*rec));
804 if (!rec) {
805 log_error("Could not allocate memory for node addition");
806 rc = ISCSI_ERR_NOMEM;
807 goto done;
810 drec = calloc(1, sizeof(*drec));
811 if (!drec) {
812 log_error("Could not allocate memory for node addition");
813 rc = ISCSI_ERR_NOMEM;
814 goto free_rec;
816 drec->type = DISCOVERY_TYPE_STATIC;
818 idbm_node_setup_from_conf(rec);
819 strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
820 rec->tpgt = tpgt;
821 rec->conn[0].port = port;
822 strlcpy(rec->conn[0].address, ip, NI_MAXHOST);
824 if (iface) {
825 rc = iface_conf_read(iface);
826 if (rc) {
827 log_error("Could not read iface %s. Error %d",
828 iface->name, rc);
829 return rc;
832 iface_copy(&rec->iface, iface);
835 rc = idbm_add_node(rec, drec, 1);
836 if (!rc) {
837 (*found)++;
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);
842 free(drec);
843 free_rec:
844 free(rec);
845 done:
846 return rc;
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))
856 return -1;
858 if (rec->conn[0].port != -1 && rec->conn[0].port != port)
859 return -1;
861 return add_static_rec(found, targetname, tpgt, ip, port,
862 &rec->iface);
865 static int add_static_node(int *found, void *data,
866 char *targetname)
868 node_rec_t *rec = data;
870 if (!strlen(rec->name))
871 goto search;
873 if (strcmp(rec->name, targetname))
874 return -1;
876 if (!strlen(rec->conn[0].address))
877 goto search;
879 return add_static_rec(found, targetname, rec->tpgt,
880 rec->conn[0].address,
881 rec->conn[0].port, &rec->iface);
882 search:
883 return idbm_for_each_portal(found, data, add_static_portal,
884 targetname);
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);
892 if (rc)
893 goto done;
894 /* success */
895 if (nr_found > 0)
896 return 0;
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,
902 &rec->iface);
903 if (!rc)
904 return 0;
906 done:
907 log_error("Error while adding record: %s", iscsi_err_to_str(rc));
908 return rc;
912 * start sendtargets discovery process based on the
913 * particular config
915 static int
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
929 * remount).
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
957 * ignore it
959 return -1;
961 if (__iscsi_match_session(rec,
962 new_rec->name,
963 new_rec->conn[0].address,
964 new_rec->conn[0].port,
965 &new_rec->iface,
966 new_rec->session.sid))
967 return -1;
969 /* if there is a error we can continue on */
970 return delete_node(NULL, rec);
973 static int
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 */
981 if (op & OP_DELETE)
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);
988 if (rc)
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) {
1002 case 0:
1003 case -1:
1004 idbm_print_node_flat(NULL, new_rec);
1005 break;
1006 case 1:
1007 idbm_print_node_and_iface_tree(&tmp_rec, new_rec);
1012 if (!do_login)
1013 return 0;
1015 err = iscsi_login_portals(NULL, &found, 1, rec_list,
1016 iscsi_login_portal);
1017 if (err && !rc)
1018 rc = err;
1019 return rc;
1022 static int
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;
1028 int rc;
1030 INIT_LIST_HEAD(&rec_list);
1032 * compat: if the user did not pass any op then we do all
1033 * ops for them
1035 if (!op)
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);
1046 if (rc) {
1047 log_error("Could not add new discovery record.");
1048 return rc;
1052 rc = idbm_bind_ifaces_to_nodes(discovery_sendtargets, drec, ifaces,
1053 &rec_list);
1054 if (rc) {
1055 log_error("Could not perform SendTargets discovery: %s",
1056 iscsi_err_to_str(rc));
1057 return 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);
1067 free(rec);
1070 return rc;
1073 static int
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;
1078 int rc, host_no;
1079 struct iscsi_transport *t;
1081 if (list_empty(ifaces)) {
1082 ifaces = NULL;
1083 goto sw_st;
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);
1089 if (rc) {
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);
1095 free(iface);
1096 continue;
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 */
1104 continue;
1107 t = iscsi_sysfs_get_transport_by_hba(host_no);
1108 if (!t) {
1109 log_error("Could not match hostno %d to "
1110 "transport. Dropping interface %s,"
1111 iface_fmt " ,%s.",
1112 host_no, iface->transport_name,
1113 iface_str(iface), iface->ipaddress);
1114 list_del(&iface->list);
1115 free(iface);
1116 continue;
1119 if (t->caps & CAP_SENDTARGETS_OFFLOAD) {
1120 do_offload_sendtargets(drec, host_no, do_login);
1121 list_del(&iface->list);
1122 free(iface);
1126 if (list_empty(ifaces))
1127 return ISCSI_ERR_NO_OBJS_FOUND;
1129 sw_st:
1130 return do_software_sendtargets(drec, ifaces, info_level, do_login,
1131 op, sync_drec);
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;
1139 int rc;
1141 INIT_LIST_HEAD(&rec_list);
1143 * compat: if the user did not pass any op then we do all
1144 * ops for them
1146 if (!op)
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,
1152 &rec_list);
1153 if (rc) {
1154 log_error("Could not perform iSNS discovery: %s",
1155 iscsi_err_to_str(rc));
1156 return 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);
1166 free(rec);
1169 return rc;
1172 static int
1173 verify_mode_params(int argc, char **argv, char *allowed, int skip_m)
1175 int ch, longindex;
1176 int ret = 0;
1178 optind = 0;
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)
1184 continue;
1185 ret = ch;
1186 break;
1190 return ret;
1193 static void catch_sigint( int signo ) {
1194 log_warning("caught SIGINT, exiting...");
1195 exit(1);
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;
1204 int rc = 0;
1206 switch (op) {
1207 case OP_NEW:
1208 if (!iface) {
1209 log_error("Could not add interface. No interface "
1210 "passed in.");
1211 return EINVAL;
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;
1217 goto new_fail;
1220 iface_setup_defaults(iface);
1221 rc = iface_conf_write(iface);
1222 if (rc)
1223 goto new_fail;
1224 printf("New interface %s added\n", iface->name);
1225 break;
1226 new_fail:
1227 log_error("Could not create new interface %s.", iface->name);
1228 break;
1229 case OP_DELETE:
1230 if (!iface) {
1231 log_error("Could not delete interface. No interface "
1232 "passed in.");
1233 return ISCSI_ERR_INVAL;
1236 rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
1237 if (!rec) {
1238 rc = ISCSI_ERR_INVAL;
1239 goto delete_fail;
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)
1245 goto delete_fail;
1247 rc = iface_conf_delete(iface);
1248 if (rc)
1249 goto delete_fail;
1251 printf("%s unbound and deleted.\n", iface->name);
1252 break;
1253 delete_fail:
1254 log_error("Could not delete iface %s: %s", iface->name,
1255 iscsi_err_to_str(rc));
1256 break;
1257 case OP_UPDATE:
1258 if (!iface || !name || !value) {
1259 log_error("Update requires name, value, and iface.");
1260 rc = ISCSI_ERR_INVAL;
1261 break;
1264 rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
1265 if (!rec) {
1266 rc = ISCSI_ERR_INVAL;
1267 goto update_fail;
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;
1281 break;
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;
1291 break;
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;
1301 break;
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);
1308 if (rc)
1309 goto update_fail;
1311 rc = __for_each_matched_rec(0, rec, &set_param,
1312 idbm_node_set_param);
1313 if (rc == ISCSI_ERR_NO_OBJS_FOUND)
1314 rc = 0;
1315 else if (rc)
1316 goto update_fail;
1318 printf("%s updated.\n", iface->name);
1319 break;
1320 update_fail:
1321 log_error("Could not update iface %s: %s",
1322 iface->name, iscsi_err_to_str(rc));
1323 break;
1324 default:
1325 if (!iface || (iface && info_level > 0)) {
1326 if (op == OP_NOOP || op == OP_SHOW)
1327 rc = print_ifaces(iface, info_level);
1328 else
1329 rc = ISCSI_ERR_INVAL;
1330 } else {
1331 rc = iface_conf_read(iface);
1332 if (!rc)
1333 idbm_print_iface_info(&do_show, iface);
1334 else
1335 log_error("Could not read iface %s (%d).",
1336 iface->name, rc);
1340 if (rec)
1341 free(rec);
1342 return rc;
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)
1351 int rc = 0;
1352 struct db_set_param set_param;
1354 if (rec)
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,
1358 rec->session.sid);
1360 if (op == OP_NEW) {
1361 rc = add_static_recs(rec);
1362 goto out;
1365 if (do_rescan) {
1366 rc = for_each_session(rec, rescan_portal);
1367 goto out;
1370 if (do_stats) {
1371 rc = for_each_session(rec, session_stats);
1372 goto out;
1375 if (do_login && do_logout) {
1376 log_error("Invalid parameters. Both login and logout passed in");
1377 rc = ISCSI_ERR_INVAL;
1378 goto out;
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;
1384 goto out;
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);
1391 goto out;
1394 if (do_login) {
1395 rc = login_portals(rec);
1396 goto out;
1399 if (do_logout) {
1400 int nr_found;
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");
1406 goto out;
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);
1411 goto out;
1414 if (op == OP_UPDATE) {
1415 if (!name || !value) {
1416 log_error("update requires name and value");
1417 rc = ISCSI_ERR_INVAL;
1418 goto out;
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;
1427 goto out;
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;
1447 goto out;
1451 set_param.name = name;
1452 set_param.value = value;
1454 rc = for_each_matched_rec(rec, &set_param, idbm_node_set_param);
1455 goto out;
1456 } else if (op == OP_DELETE) {
1457 rc = for_each_matched_rec(rec, NULL, delete_node);
1458 goto out;
1459 } else {
1460 log_error("operation is not supported.");
1461 rc = ISCSI_ERR_INVAL;
1462 goto out;
1464 out:
1465 return rc;
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;
1474 int rc = 0;
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
1481 * ops for them
1483 if (!op)
1484 op = OP_NEW | OP_DELETE | OP_UPDATE;
1487 * if a user passed in ifaces then we use them and ignore the ibft
1488 * net info
1490 if (!list_empty(ifaces)) {
1491 list_for_each_entry_safe(iface, tmp_iface, ifaces, list) {
1492 rc = iface_conf_read(iface);
1493 if (rc) {
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);
1500 free(iface);
1501 continue;
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);
1520 if (rc) {
1521 log_error("Could not get list of targets from firmware. "
1522 "(err %d)\n", rc);
1523 return rc;
1525 rc = iface_create_ifaces_from_boot_contexts(&new_ifaces, &targets);
1526 if (rc)
1527 goto done;
1528 if (!list_empty(&new_ifaces))
1529 ifaces = &new_ifaces;
1531 discover_fw_tgts:
1532 rc = idbm_bind_ifaces_to_nodes(discovery_fw, drec,
1533 ifaces, &rec_list);
1534 if (rc)
1535 log_error("Could not perform fw discovery.\n");
1536 else
1537 rc = exec_disc_op_on_recs(drec, &rec_list, info_level,
1538 do_login, op);
1540 done:
1541 fw_free_targets(&targets);
1543 list_for_each_entry_safe(iface, tmp_iface, &new_ifaces, list) {
1544 list_del(&iface->list);
1545 free(iface);
1548 list_for_each_entry_safe(rec, tmp_rec, &rec_list, list) {
1549 list_del(&rec->list);
1550 free(rec);
1552 return rc;
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;
1561 int rc = 0;
1563 INIT_LIST_HEAD(&targets);
1564 INIT_LIST_HEAD(&rec_list);
1566 if (drec)
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);
1571 if (rc) {
1572 log_error("Could not get list of targets from firmware. "
1573 "(err %d)\n", rc);
1574 return rc;
1577 if (do_login) {
1578 list_for_each_entry(context, &targets, list) {
1579 rec = idbm_create_rec_from_boot_context(context);
1580 if (!rec) {
1581 log_error("Could not convert firmware info to "
1582 "node record.\n");
1583 rc = ISCSI_ERR_NOMEM;
1584 break;
1587 iscsi_login_portal(NULL, NULL, rec);
1588 free(rec);
1590 } else {
1591 list_for_each_entry(context, &targets, list)
1592 fw_print_entry(context);
1595 fw_free_targets(&targets);
1596 return rc;
1599 static void setup_drec_defaults(int type, char *ip, int port,
1600 struct discovery_rec *drec)
1602 switch (type) {
1603 case DISCOVERY_TYPE_ISNS:
1604 idbm_isns_defaults(&drec->u.isns);
1605 break;
1606 case DISCOVERY_TYPE_SENDTARGETS:
1607 idbm_sendtargets_defaults(&drec->u.sendtargets);
1608 break;
1609 default:
1610 log_error("Invalid disc type.");
1612 strlcpy(drec->address, ip, sizeof(drec->address));
1613 drec->port = port;
1614 drec->type = type;
1618 * exec_discover - prep, add, read and exec discovery on drec
1619 * @type: discovery type
1620 * @ip: IP address
1621 * @port: port
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.
1632 * returns:
1633 * Greater than 0 - error
1634 * 0 - op/discovery completed
1635 * -1 - exec db op
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)
1642 int rc;
1644 if (ip == NULL) {
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);
1653 if (rc) {
1654 log_error("Could not add new discovery record.");
1655 return rc;
1656 } else {
1657 printf("New discovery record for [%s,%d] added.\n", ip,
1658 port);
1659 return 0;
1663 rc = idbm_discovery_read(drec, disc_type, ip, port);
1664 if (rc) {
1665 if (!do_discover) {
1666 log_error("Discovery record [%s,%d] not found.",
1667 ip, port);
1668 return rc;
1671 /* Just add default rec for user */
1672 log_debug(1, "Discovery record [%s,%d] not found!",
1673 ip, port);
1674 setup_drec_defaults(disc_type, ip, port, drec);
1675 if (!(op & OP_NONPERSISTENT)) {
1676 rc = idbm_add_discovery(drec);
1677 if (rc) {
1678 log_error("Could not add new discovery "
1679 "record.");
1680 return rc;
1683 } else if (!do_discover)
1684 return -1;
1686 rc = 0;
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,
1695 break;
1696 case DISCOVERY_TYPE_ISNS:
1697 rc = do_isns(drec, ifaces, info_level, do_login, op);
1698 break;
1699 default:
1700 log_error("Unsupported discovery type.");
1701 break;
1704 return rc;
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,
1710 int do_show)
1712 struct discovery_rec drec;
1713 int rc = 0;
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:
1721 if (port < 0)
1722 port = ISCSI_LISTEN_PORT;
1724 rc = exec_discover(disc_type, ip, port, ifaces, info_level,
1725 do_login, do_discover, op, &drec);
1726 if (rc < 0)
1727 goto do_db_op;
1728 goto done;
1729 case DISCOVERY_TYPE_SLP:
1730 log_error("SLP discovery is not fully implemented yet.");
1731 rc = ISCSI_ERR_INVAL;
1732 goto done;
1733 case DISCOVERY_TYPE_ISNS:
1734 if (port < 0)
1735 port = ISNS_DEFAULT_PORT;
1737 rc = exec_discover(disc_type, ip, port, ifaces, info_level,
1738 do_login, do_discover, op, &drec);
1739 if (rc < 0)
1740 goto do_db_op;
1741 goto done;
1742 case DISCOVERY_TYPE_FW:
1743 if (!do_discover) {
1744 log_error("Invalid command. Possibly missing "
1745 "--discover argument.");
1746 rc = ISCSI_ERR_INVAL;
1747 goto done;
1750 drec.type = DISCOVERY_TYPE_FW;
1751 rc = exec_fw_op(&drec, ifaces, info_level, do_login, op);
1752 goto done;
1753 default:
1754 rc = ISCSI_ERR_INVAL;
1756 if (!ip) {
1757 if (op == OP_NOOP || op == OP_SHOW) {
1758 if (idbm_print_all_discovery(info_level))
1759 /* successfully found some recs */
1760 rc = 0;
1761 else
1762 rc = ISCSI_ERR_NO_OBJS_FOUND;
1763 } else
1764 log_error("Invalid operation. Operation not "
1765 "supported.");
1766 } else if (op)
1767 log_error("Invalid command. Possibly missing discovery "
1768 "--type.");
1769 else
1770 log_error("Invalid command. Portal not needed or "
1771 "Possibly missing discovery --type.");
1772 goto done;
1775 do_db_op:
1776 rc = 0;
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);
1785 if (rc)
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;
1793 goto done;
1795 set_param.name = name;
1796 set_param.value = value;
1797 rc = idbm_discovery_set_param(&set_param, &drec);
1798 } else {
1799 log_error("Operation is not supported.");
1800 rc = ISCSI_ERR_INVAL;
1801 goto done;
1803 done:
1804 return rc;
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,
1810 int do_show)
1812 struct discovery_rec drec;
1813 int rc = 0;
1815 memset(&drec, 0, sizeof(struct discovery_rec));
1817 switch (disc_type) {
1818 case DISCOVERY_TYPE_SENDTARGETS:
1819 drec.type = DISCOVERY_TYPE_SENDTARGETS;
1821 if (port < 0)
1822 port = ISCSI_LISTEN_PORT;
1824 if (ip == NULL) {
1825 log_error("Please specify portal as "
1826 "<ipaddr>[:<ipport>]");
1827 rc = ISCSI_ERR_INVAL;
1828 goto done;
1831 idbm_sendtargets_defaults(&drec.u.sendtargets);
1832 strlcpy(drec.address, ip, sizeof(drec.address));
1833 drec.port = port;
1835 rc = do_sendtargets(&drec, ifaces, info_level,
1836 do_login, op, 1);
1837 if (rc)
1838 goto done;
1839 break;
1840 case DISCOVERY_TYPE_SLP:
1841 log_error("SLP discovery is not fully implemented yet.");
1842 rc = ISCSI_ERR_INVAL;
1843 break;
1844 case DISCOVERY_TYPE_ISNS:
1845 if (!ip) {
1846 log_error("Please specify portal as "
1847 "<ipaddr>:[<ipport>]");
1848 rc = ISCSI_ERR_INVAL;
1849 goto done;
1852 strlcpy(drec.address, ip, sizeof(drec.address));
1853 if (port < 0)
1854 drec.port = ISNS_DEFAULT_PORT;
1855 else
1856 drec.port = port;
1858 rc = do_isns(&drec, ifaces, info_level, do_login, op);
1859 if (rc)
1860 goto done;
1861 break;
1862 case DISCOVERY_TYPE_FW:
1863 drec.type = DISCOVERY_TYPE_FW;
1864 rc = exec_fw_op(&drec, ifaces, info_level, do_login, op);
1865 break;
1866 default:
1867 if (ip) {
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
1874 * must be used.
1876 if (port < 0)
1877 port = ISCSI_LISTEN_PORT;
1879 if (idbm_discovery_read(&drec,
1880 DISCOVERY_TYPE_SENDTARGETS,
1881 ip, port)) {
1882 log_error("Discovery record [%s,%d] "
1883 "not found!", ip, port);
1884 rc = ISCSI_ERR_INVAL;
1885 goto done;
1887 if ((do_discover || do_login) &&
1888 drec.type == DISCOVERY_TYPE_SENDTARGETS) {
1889 rc = do_sendtargets(&drec, ifaces, info_level,
1890 do_login, op, 0);
1891 } else if (op == OP_NOOP || op == OP_SHOW) {
1892 if (!idbm_print_discovery_info(&drec,
1893 do_show)) {
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);
1899 if (rc)
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;
1906 goto done;
1907 } else {
1908 log_error("Invalid operation.");
1909 rc = ISCSI_ERR_INVAL;
1910 goto done;
1912 } else if (op == OP_NOOP || op == OP_SHOW) {
1913 if (!idbm_print_all_discovery(info_level))
1914 rc = ISCSI_ERR_NO_OBJS_FOUND;
1915 goto done;
1916 } else {
1917 log_error("Invalid operation.");
1918 rc = ISCSI_ERR_INVAL;
1919 goto done;
1921 /* fall through */
1924 done:
1925 return rc;
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 );
1955 umask(0177);
1957 /* enable stdout logging */
1958 log_init(program_name, 1024, log_do_log_std, NULL);
1959 sysfs_init();
1961 optopt = 0;
1962 while ((ch = getopt_long(argc, argv, short_options,
1963 long_options, &longindex)) >= 0) {
1964 switch (ch) {
1965 case 'k':
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;
1972 goto free_ifaces;
1974 break;
1975 case 't':
1976 type = str_to_type(optarg);
1977 break;
1978 case 'o':
1979 op |= str_to_op(optarg);
1980 if (op == OP_NOOP) {
1981 log_error("can not recognize operation: '%s'",
1982 optarg);
1983 rc = ISCSI_ERR_INVAL;
1984 goto free_ifaces;
1986 break;
1987 case 'n':
1988 name = optarg;
1989 break;
1990 case 'v':
1991 value = optarg;
1992 break;
1993 case 'H':
1994 errno = 0;
1995 host_no = strtoul(optarg, NULL, 10);
1996 if (errno) {
1997 log_error("invalid host no %s. %s.",
1998 optarg, strerror(errno));
1999 rc = ISCSI_ERR_INVAL;
2000 goto free_ifaces;
2002 break;
2003 case 'r':
2004 sid = iscsi_sysfs_get_sid_from_path(optarg);
2005 if (sid < 0) {
2006 log_error("invalid sid '%s'",
2007 optarg);
2008 rc = ISCSI_ERR_INVAL;
2009 goto free_ifaces;
2011 break;
2012 case 'R':
2013 do_rescan = 1;
2014 break;
2015 case 'P':
2016 info_level = atoi(optarg);
2017 break;
2018 case 'D':
2019 do_discover = 1;
2020 break;
2021 case 'l':
2022 do_login = 1;
2023 break;
2024 case 'u':
2025 do_logout = 1;
2026 break;
2027 case 'U':
2028 do_logout_all = 1;
2029 group_session_mgmt_mode= optarg;
2030 break;
2031 case 'L':
2032 do_login_all= 1;
2033 group_session_mgmt_mode= optarg;
2034 break;
2035 case 's':
2036 do_stats = 1;
2037 break;
2038 case 'S':
2039 do_show = 1;
2040 break;
2041 case 'd':
2042 log_level = atoi(optarg);
2043 break;
2044 case 'm':
2045 mode = str_to_mode(optarg);
2046 break;
2047 case 'T':
2048 targetname = optarg;
2049 break;
2050 case 'p':
2051 ip = str_to_ipport(optarg, &port, &tpgt);
2052 break;
2053 case 'I':
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);
2059 goto free_ifaces;
2060 } else if (!iface || rc) {
2061 printf("Could not add iface %s.", optarg);
2062 rc = ISCSI_ERR_INVAL;
2063 goto free_ifaces;
2066 list_add_tail(&iface->list, &ifaces);
2067 num_ifaces++;
2068 break;
2069 case 'V':
2070 printf("%s version %s\n", program_name,
2071 ISCSI_VERSION_STR);
2072 return 0;
2073 case 'h':
2074 usage(0);
2078 if (optopt) {
2079 log_error("unrecognized character '%c'", optopt);
2080 rc = ISCSI_ERR_INVAL;
2081 goto free_ifaces;
2084 if (killiscsid >= 0) {
2085 kill_iscsid(killiscsid);
2086 goto free_ifaces;
2089 if (mode < 0)
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;
2097 goto free_ifaces;
2100 rc = exec_fw_op(NULL, NULL, info_level, do_login, op);
2101 goto free_ifaces;
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;
2108 goto free_ifaces;
2111 switch (mode) {
2112 case MODE_HOST:
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;
2117 goto out;
2120 rc = host_info_print(info_level, host_no);
2121 break;
2122 case MODE_IFACE:
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;
2129 goto out;
2132 if (!list_empty(&ifaces)) {
2133 iface = list_entry(ifaces.next, struct iface_rec,
2134 list);
2135 if (num_ifaces > 1)
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,
2141 name, value);
2142 break;
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;
2148 goto out;
2151 rc = exec_disc2_op(type, ip, port, &ifaces, info_level,
2152 do_login, do_discover, op, name, value,
2153 do_show);
2154 break;
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;
2160 goto out;
2163 rc = exec_disc_op(type, ip, port, &ifaces, info_level,
2164 do_login, do_discover, op, name, value,
2165 do_show);
2166 break;
2167 case MODE_NODE:
2168 if ((rc = verify_mode_params(argc, argv, "RsPIdmlSonvupTUL",
2169 0))) {
2170 log_error("node mode: option '-%c' is not "
2171 "allowed/supported", rc);
2172 rc = ISCSI_ERR_INVAL;
2173 goto out;
2176 if (do_login_all) {
2177 rc = login_by_startup(group_session_mgmt_mode);
2178 goto out;
2181 if (do_logout_all) {
2182 rc = logout_by_startup(group_session_mgmt_mode);
2183 goto out;
2186 if (!list_empty(&ifaces)) {
2187 iface = list_entry(ifaces.next, struct iface_rec,
2188 list);
2189 if (num_ifaces > 1)
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);
2201 if (!rec) {
2202 rc = ISCSI_ERR_NOMEM;
2203 goto out;
2206 rc = exec_node_op(op, do_login, do_logout, do_show,
2207 do_rescan, do_stats, info_level, rec,
2208 name, value);
2209 break;
2210 case MODE_SESSION:
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;
2216 goto out;
2218 if (sid >= 0) {
2219 char session[64];
2220 struct session_info *info;
2222 snprintf(session, 63, "session%d", sid);
2223 session[63] = '\0';
2225 info = calloc(1, sizeof(*info));
2226 if (!info) {
2227 rc = ISCSI_ERR_NOMEM;
2228 goto out;
2231 rc = iscsi_sysfs_get_sessioninfo_by_id(info, session);
2232 if (rc) {
2233 log_error("Could not get session info for sid "
2234 "%d", sid);
2235 goto free_info;
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))
2244 goto free_info;
2246 if (!do_logout && !do_rescan && !do_stats &&
2247 op == OP_NOOP && info_level > 0) {
2248 rc = session_info_print(info_level, info);
2249 goto free_info;
2252 rec = idbm_create_rec(info->targetname,
2253 info->tpgt,
2254 info->persistent_address,
2255 info->persistent_port,
2256 &info->iface, 1);
2257 if (!rec) {
2258 rc = ISCSI_ERR_NOMEM;
2259 goto free_info;
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.
2268 if (op == OP_NEW) {
2269 op = OP_NOOP;
2270 do_login = 1;
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,
2277 rec, name, value);
2278 free_info:
2279 free(info);
2280 goto out;
2281 } else {
2282 if (op == OP_NEW) {
2283 log_error("session mode: Operation 'new' only "
2284 "allowed with specific session IDs");
2285 rc = ISCSI_ERR_INVAL;
2286 goto out;
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);
2292 goto out;
2295 rc = session_info_print(info_level, NULL);
2297 break;
2298 default:
2299 log_error("This mode is not yet supported");
2300 /* fall through */
2303 out:
2304 if (rec)
2305 free(rec);
2306 idbm_terminate();
2307 free_ifaces:
2308 list_for_each_entry_safe(iface, tmp, &ifaces, list) {
2309 list_del(&iface->list);
2310 free(iface);
2312 free_transports();
2313 sysfs_cleanup();
2314 return rc;