iscsi tools: add log_info helper
[open-iscsi.git] / usr / iscsiadm.c
blob2d9f1a2df01b3e0aafa6be9080733ea895529dea
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 * maintained by open-iscsi@googlegroups.com
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * See the file COPYING included with this distribution for more details.
22 #include <errno.h>
23 #include <getopt.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <sys/stat.h>
31 #include "initiator.h"
32 #include "discovery.h"
33 #include "log.h"
34 #include "mgmt_ipc.h"
35 #include "idbm.h"
36 #include "iscsi_util.h"
37 #include "transport.h"
38 #include "version.h"
39 #include "iscsi_sysfs.h"
40 #include "list.h"
41 #include "iscsi_settings.h"
42 #include "fw_context.h"
43 #include "iface.h"
44 #include "session_info.h"
45 #include "host.h"
46 #include "sysdeps.h"
47 #include "idbm_fields.h"
48 #include "session_mgmt.h"
49 #include "iscsid_req.h"
50 #include "isns-proto.h"
52 struct iscsi_ipc *ipc = NULL; /* dummy */
53 static char program_name[] = "iscsiadm";
54 static char config_file[TARGET_NAME_MAXLEN];
56 enum iscsiadm_mode {
57 MODE_DISCOVERY,
58 MODE_NODE,
59 MODE_SESSION,
60 MODE_HOST,
61 MODE_IFACE,
62 MODE_FW,
65 enum iscsiadm_op {
66 OP_NOOP = 0x0,
67 OP_NEW = 0x1,
68 OP_DELETE = 0x2,
69 OP_UPDATE = 0x4,
70 OP_SHOW = 0x8,
71 OP_NONPERSISTENT = 0x10
74 static struct option const long_options[] =
76 {"mode", required_argument, NULL, 'm'},
77 {"portal", required_argument, NULL, 'p'},
78 {"targetname", required_argument, NULL, 'T'},
79 {"interface", required_argument, NULL, 'I'},
80 {"op", required_argument, NULL, 'o'},
81 {"type", required_argument, NULL, 't'},
82 {"name", required_argument, NULL, 'n'},
83 {"value", required_argument, NULL, 'v'},
84 {"host", required_argument, NULL, 'H'},
85 {"sid", required_argument, NULL, 'r'},
86 {"rescan", no_argument, NULL, 'R'},
87 {"print", required_argument, NULL, 'P'},
88 {"login", no_argument, NULL, 'l'},
89 {"loginall", required_argument, NULL, 'L'},
90 {"logout", no_argument, NULL, 'u'},
91 {"logoutall", required_argument, NULL, 'U'},
92 {"stats", no_argument, NULL, 's'},
93 {"killiscsid", required_argument, NULL, 'k'},
94 {"debug", required_argument, NULL, 'd'},
95 {"show", no_argument, NULL, 'S'},
96 {"version", no_argument, NULL, 'V'},
97 {"help", no_argument, NULL, 'h'},
98 {NULL, 0, NULL, 0},
100 static char *short_options = "RlVhm:p:P:T:H:I:U:k:L:d:r:n:v:o:sSt:u";
102 static void usage(int status)
104 if (status != 0)
105 fprintf(stderr, "Try `%s --help' for more information.\n",
106 program_name);
107 else {
108 printf("\
109 iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ -p ip:port ] \
110 [ -o operation ] [ -n name ] [ -v value ]\n\
111 iscsiadm -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] ] \
112 [ [ -o operation ] [ -n name ] [ -v value ] ]\n\
113 iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\
114 iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\
115 iscsiadm -m fw [ -l ]\n\
116 iscsiadm -m host [ -P printlevel ] [ -H hostno ]\n\
117 iscsiadm -k priority\n");
119 exit(status == 0 ? 0 : -1);
122 static int
123 str_to_op(char *str)
125 int op;
127 if (!strcmp("new", str))
128 op = OP_NEW;
129 else if (!strcmp("delete", str))
130 op = OP_DELETE;
131 else if (!strcmp("update", str))
132 op = OP_UPDATE;
133 else if (!strcmp("show", str))
134 op = OP_SHOW;
135 else if (!strcmp("nonpersistent", str))
136 op = OP_NONPERSISTENT;
137 else
138 op = OP_NOOP;
140 return op;
143 static int
144 str_to_mode(char *str)
146 int mode;
148 if (!strcmp("discovery", str))
149 mode = MODE_DISCOVERY;
150 else if (!strcmp("node", str))
151 mode = MODE_NODE;
152 else if (!strcmp("session", str))
153 mode = MODE_SESSION;
154 else if (!strcmp("iface", str))
155 mode = MODE_IFACE;
156 else if (!strcmp("fw", str))
157 mode = MODE_FW;
158 else if (!strcmp("host", str))
159 mode = MODE_HOST;
160 else
161 mode = -1;
163 return mode;
166 static int
167 str_to_type(char *str)
169 int type;
171 if (!strcmp("sendtargets", str) ||
172 !strcmp("st", str))
173 type = DISCOVERY_TYPE_SENDTARGETS;
174 else if (!strcmp("slp", str))
175 type = DISCOVERY_TYPE_SLP;
176 else if (!strcmp("isns", str))
177 type = DISCOVERY_TYPE_ISNS;
178 else if (!strcmp("fw", str))
179 type = DISCOVERY_TYPE_FW;
180 else
181 type = -1;
183 return type;
186 static void kill_iscsid(int priority)
188 iscsiadm_req_t req;
189 iscsiadm_rsp_t rsp;
190 int rc;
193 * We only support SIGTERM like stoppage of iscsid for now.
194 * In the future we can do something where we try go finish
195 * up operations like login, error handling, etc, before
196 * iscsid is stopped, and we can add different values to indicate
197 * that the user wants iscsid to log out existing sessions before
198 * exiting.
200 if (priority != 0) {
201 log_error("Invalid iscsid priority %d. Priority must be 0.",
202 priority);
203 return;
206 memset(&req, 0, sizeof(req));
207 req.command = MGMT_IPC_IMMEDIATE_STOP;
208 rc = iscsid_exec_req(&req, &rsp, 0);
209 if (rc) {
210 iscsid_handle_error(rc);
211 log_error("Could not stop iscsid. Trying sending iscsid "
212 "SIGTERM or SIGKILL signals manually\n");
217 * TODO: we can display how the ifaces are related to node records.
218 * And we can add a scsi_host mode which would display how
219 * sessions are related to hosts
220 * (scsi_host and iscsi_sessions are the currently running instance of
221 * a iface or node record).
223 static int print_ifaces(struct iface_rec *iface, int info_level)
225 int err, num_found = 0;
227 switch (info_level) {
228 case 0:
229 case -1:
230 err = iface_for_each_iface(NULL, 0, &num_found,
231 iface_print_flat);
232 break;
233 case 1:
234 if (iface) {
235 err = iface_conf_read(iface);
236 if (err) {
237 log_error("Could not read iface %s.\n",
238 iface->name);
239 return err;
241 iface_print_tree(NULL, iface);
242 num_found = 1;
243 } else
244 err = iface_for_each_iface(NULL, 0, &num_found,
245 iface_print_tree);
246 break;
247 default:
248 log_error("Invalid info level %d. Try 0 - 1.", info_level);
249 return EINVAL;
252 if (!num_found) {
253 log_error("No interfaces found.");
254 err = ENODEV;
256 return err;
259 static int
260 match_startup_mode(node_rec_t *rec, char *mode)
263 * we always skip onboot because this should be handled by
264 * something else
266 if (rec->startup == ISCSI_STARTUP_ONBOOT)
267 return -1;
269 if ((!strcmp(mode, "automatic") &&
270 rec->startup == ISCSI_STARTUP_AUTOMATIC) ||
271 (!strcmp(mode, "manual") &&
272 rec->startup == ISCSI_STARTUP_MANUAL) ||
273 !strcmp(mode, "all"))
274 return 0;
276 /* support conn or session startup params */
277 if ((!strcmp(mode, "automatic") &&
278 rec->conn[0].startup == ISCSI_STARTUP_AUTOMATIC) ||
279 (!strcmp(mode, "manual") &&
280 rec->conn[0].startup == ISCSI_STARTUP_MANUAL) ||
281 !strcmp(mode, "all"))
282 return 0;
284 return -1;
287 static int
288 for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn)
290 int err, num_found = 0;
292 err = iscsi_sysfs_for_each_session(rec, &num_found, fn);
293 if (err)
294 log_error("Could not execute operation on all sessions. Err "
295 "%d.", err);
296 else if (!num_found) {
297 log_error("No portal found.");
298 err = ENODEV;
301 return err;
304 static int link_recs(void *data, struct node_rec *rec)
306 struct list_head *list = data;
307 struct node_rec *rec_copy;
309 rec_copy = calloc(1, sizeof(*rec_copy));
310 if (!rec_copy)
311 return ENOMEM;
312 memcpy(rec_copy, rec, sizeof(*rec_copy));
313 INIT_LIST_HEAD(&rec_copy->list);
314 list_add_tail(&rec_copy->list, list);
315 return 0;
318 static int
319 __logout_by_startup(void *data, struct list_head *list,
320 struct session_info *info)
322 char *mode = data;
323 node_rec_t rec;
324 int rc = 0;
326 memset(&rec, 0, sizeof(node_rec_t));
327 if (idbm_rec_read(&rec, info->targetname, info->tpgt,
328 info->persistent_address,
329 info->persistent_port, &info->iface)) {
331 * this is due to a HW driver or some other driver
332 * not hooked in
334 log_debug(7, "could not read data for [%s,%s.%d]\n",
335 info->targetname, info->persistent_address,
336 info->persistent_port);
337 return -1;
340 /* multiple drivers could be connected to the same portal */
341 if (strcmp(rec.iface.transport_name, info->iface.transport_name))
342 return -1;
344 * we always skip on boot because if the user killed this on
345 * they would not be able to do anything
347 if (rec.startup == ISCSI_STARTUP_ONBOOT)
348 return -1;
350 if (!match_startup_mode(&rec, mode))
351 rc = iscsi_logout_portal(info, list);
352 return rc;
355 static int
356 logout_by_startup(char *mode)
358 int nr_found;
360 if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") ||
361 !strcmp(mode,"manual"))) {
362 log_error("Invalid logoutall option %s.", mode);
363 usage(0);
364 return EINVAL;
367 return iscsi_logout_portals(mode, &nr_found, 1, __logout_by_startup);
371 * TODO: merged this and logout into the common for_each_rec by making
372 * the matching more generic
374 static int
375 __login_by_startup(void *data, struct list_head *list, struct node_rec *rec)
377 char *mode = data;
379 * we always skip onboot because this should be handled by
380 * something else
382 if (rec->startup == ISCSI_STARTUP_ONBOOT)
383 return -1;
385 if (match_startup_mode(rec, mode))
386 return -1;
388 iscsi_login_portal(NULL, list, rec);
389 return 0;
392 static int
393 login_by_startup(char *mode)
395 int nr_found = 0, rc, err;
396 struct list_head rec_list;
398 if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") ||
399 !strcmp(mode,"manual"))) {
400 log_error("Invalid loginall option %s.", mode);
401 usage(0);
402 return EINVAL;
405 INIT_LIST_HEAD(&rec_list);
406 rc = idbm_for_each_rec(&nr_found, &rec_list, link_recs);
407 err = iscsi_login_portals(mode, &nr_found, 1, &rec_list,
408 __login_by_startup);
409 if (err && !rc)
410 rc = err;
412 if (rc)
413 log_error("Could not log into all portals. Err %d.", rc);
414 else if (!nr_found) {
415 log_error("No records found!");
416 rc = ENODEV;
418 return rc;
422 * iscsi_logout_matched_portal - logout of targets matching the rec info
423 * @data: record to session with
424 * @list: list to add logout rec to
425 * @info: session to match with rec
427 static int iscsi_logout_matched_portal(void *data, struct list_head *list,
428 struct session_info *info)
430 struct node_rec *pattern_rec = data;
431 struct iscsi_transport *t;
433 t = iscsi_sysfs_get_transport_by_sid(info->sid);
434 if (!t)
435 return -1;
437 if (!iscsi_match_session(pattern_rec, info))
438 return -1;
440 /* we do not support this yet */
441 if (t->caps & CAP_FW_DB) {
442 log_error("Could not logout session of [sid: %d, "
443 "target: %s, portal: %s,%d].", info->sid,
444 info->targetname, info->persistent_address,
445 info->port);
446 log_error("Logout not supported for driver: %s.", t->name);
447 return -1;
449 return iscsi_logout_portal(info, list);
452 static int iface_fn(void *data, node_rec_t *rec)
454 struct rec_op_data *op_data = data;
456 if (!__iscsi_match_session(op_data->match_rec, rec->name,
457 rec->conn[0].address, rec->conn[0].port,
458 &rec->iface))
459 return -1;
460 return op_data->fn(op_data->data, rec);
463 static int __for_each_rec(int verbose, struct node_rec *rec,
464 void *data, idbm_iface_op_fn *fn)
466 struct rec_op_data op_data;
467 int nr_found = 0, rc;
469 memset(&op_data, 0, sizeof(struct rec_op_data));
470 op_data.data = data;
471 op_data.match_rec = rec;
472 op_data.fn = fn;
474 rc = idbm_for_each_rec(&nr_found, &op_data, iface_fn);
475 if (rc) {
476 if (verbose)
477 log_error("Could not execute operation on all "
478 "records. Err %d.", rc);
479 } else if (!nr_found) {
480 if (verbose)
481 log_error("no records found!");
482 rc = ENODEV;
485 return rc;
488 static int for_each_rec(struct node_rec *rec, void *data,
489 idbm_iface_op_fn *fn)
491 return __for_each_rec(1, rec, data, fn);
495 static int login_portals(struct node_rec *pattern_rec)
497 struct list_head rec_list;
498 int err, ret, nr_found;
500 INIT_LIST_HEAD(&rec_list);
501 ret = for_each_rec(pattern_rec, &rec_list, link_recs);
502 err = iscsi_login_portals(NULL, &nr_found, 1, &rec_list,
503 iscsi_login_portal);
504 if (err && !ret)
505 ret = err;
506 return ret;
509 static int print_nodes(int info_level, struct node_rec *rec)
511 struct node_rec tmp_rec;
512 int rc = 0;
514 switch (info_level) {
515 case 0:
516 case -1:
517 if (for_each_rec(rec, NULL, idbm_print_node_flat))
518 rc = -1;
519 break;
520 case 1:
521 memset(&tmp_rec, 0, sizeof(node_rec_t));
522 if (for_each_rec(rec, &tmp_rec, idbm_print_node_and_iface_tree))
523 rc = -1;
524 break;
525 default:
526 log_error("Invalid info level %d. Try 0 or 1.", info_level);
527 rc = -1;
530 return rc;
533 static char *get_config_file(void)
535 int rc;
536 iscsiadm_req_t req;
537 iscsiadm_rsp_t rsp;
539 memset(&req, 0, sizeof(req));
540 req.command = MGMT_IPC_CONFIG_FILE;
542 rc = iscsid_exec_req(&req, &rsp, 1);
543 if (rc)
544 return NULL;
546 if (rsp.u.config.var[0] != '\0') {
547 strcpy(config_file, rsp.u.config.var);
548 return config_file;
551 return NULL;
554 static int rescan_portal(void *data, struct session_info *info)
556 int host_no, err;
558 if (!iscsi_match_session(data, info))
559 return -1;
561 printf("Rescanning session [sid: %d, target: %s, portal: "
562 "%s,%d]\n", info->sid, info->targetname,
563 info->persistent_address, info->port);
565 host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &err);
566 if (err) {
567 log_error("Could not rescan session sid %d.", info->sid);
568 return err;
570 /* rescan each device to pick up size changes */
571 iscsi_sysfs_for_each_device(NULL, host_no, info->sid,
572 iscsi_sysfs_rescan_device);
573 /* now scan for new devices */
574 iscsi_sysfs_scan_host(host_no, 0);
575 return 0;
578 static int
579 session_stats(void *data, struct session_info *info)
581 int rc, i;
582 iscsiadm_req_t req;
583 iscsiadm_rsp_t rsp;
585 if (!iscsi_match_session(data, info))
586 return -1;
588 memset(&req, 0, sizeof(req));
589 req.command = MGMT_IPC_SESSION_STATS;
590 req.u.session.sid = info->sid;
592 rc = iscsid_exec_req(&req, &rsp, 1);
593 if (rc)
594 return EIO;
596 printf("Stats for session [sid: %d, target: %s, portal: "
597 "%s,%d]\n",
598 info->sid, info->targetname, info->persistent_address,
599 info->port);
601 printf( "iSCSI SNMP:\n"
603 "\ttxdata_octets: %lld\n"
604 "\trxdata_octets: %lld\n"
606 "\tnoptx_pdus: %u\n"
607 "\tscsicmd_pdus: %u\n"
608 "\ttmfcmd_pdus: %u\n"
609 "\tlogin_pdus: %u\n"
610 "\ttext_pdus: %u\n"
611 "\tdataout_pdus: %u\n"
612 "\tlogout_pdus: %u\n"
613 "\tsnack_pdus: %u\n"
615 "\tnoprx_pdus: %u\n"
616 "\tscsirsp_pdus: %u\n"
617 "\ttmfrsp_pdus: %u\n"
618 "\ttextrsp_pdus: %u\n"
619 "\tdatain_pdus: %u\n"
620 "\tlogoutrsp_pdus: %u\n"
621 "\tr2t_pdus: %u\n"
622 "\tasync_pdus: %u\n"
623 "\trjt_pdus: %u\n"
625 "\tdigest_err: %u\n"
626 "\ttimeout_err: %u\n",
627 (unsigned long long)rsp.u.getstats.stats.txdata_octets,
628 (unsigned long long)rsp.u.getstats.stats.rxdata_octets,
630 rsp.u.getstats.stats.noptx_pdus,
631 rsp.u.getstats.stats.scsicmd_pdus,
632 rsp.u.getstats.stats.tmfcmd_pdus,
633 rsp.u.getstats.stats.login_pdus,
634 rsp.u.getstats.stats.text_pdus,
635 rsp.u.getstats.stats.dataout_pdus,
636 rsp.u.getstats.stats.logout_pdus,
637 rsp.u.getstats.stats.snack_pdus,
639 rsp.u.getstats.stats.noprx_pdus,
640 rsp.u.getstats.stats.scsirsp_pdus,
641 rsp.u.getstats.stats.tmfrsp_pdus,
642 rsp.u.getstats.stats.textrsp_pdus,
643 rsp.u.getstats.stats.datain_pdus,
644 rsp.u.getstats.stats.logoutrsp_pdus,
645 rsp.u.getstats.stats.r2t_pdus,
646 rsp.u.getstats.stats.async_pdus,
647 rsp.u.getstats.stats.rjt_pdus,
649 rsp.u.getstats.stats.digest_err,
650 rsp.u.getstats.stats.timeout_err);
652 if (rsp.u.getstats.stats.custom_length)
653 printf( "iSCSI Extended:\n");
655 for (i = 0; i < rsp.u.getstats.stats.custom_length; i++) {
656 printf("\t%s: %llu\n", rsp.u.getstats.stats.custom[i].desc,
657 (unsigned long long)rsp.u.getstats.stats.custom[i].value);
660 return 0;
663 static int add_static_rec(int *found, char *targetname, int tpgt,
664 char *ip, int port, struct iface_rec *iface)
666 node_rec_t *rec;
667 discovery_rec_t *drec;
668 int rc;
670 rec = calloc(1, sizeof(*rec));
671 if (!rec) {
672 log_error("Could not allocate memory for node addition");
673 rc = ENOMEM;
674 goto done;
677 drec = calloc(1, sizeof(*drec));
678 if (!drec) {
679 log_error("Could not allocate memory for node addition");
680 rc = ENOMEM;
681 goto free_rec;
683 drec->type = DISCOVERY_TYPE_STATIC;
685 idbm_node_setup_from_conf(rec);
686 strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
687 rec->tpgt = tpgt;
688 rec->conn[0].port = port;
689 strlcpy(rec->conn[0].address, ip, NI_MAXHOST);
691 if (iface) {
692 rc = iface_conf_read(iface);
693 if (rc) {
694 log_error("Could not read iface %s. Error %d",
695 iface->name, rc);
696 return rc;
699 iface_copy(&rec->iface, iface);
702 rc = idbm_add_node(rec, drec, 1);
703 if (!rc) {
704 (*found)++;
705 printf("New iSCSI node [%s:" iface_fmt " %s,%d,%d %s] added\n",
706 rec->iface.transport_name, iface_str(&rec->iface),
707 ip, port, tpgt, targetname);
709 free(drec);
710 free_rec:
711 free(rec);
712 done:
713 return rc;
716 static int add_static_portal(int *found, void *data,
717 char *targetname, int tpgt, char *ip, int port)
719 node_rec_t *rec = data;
721 if (strlen(rec->conn[0].address) &&
722 strcmp(rec->conn[0].address, ip))
723 return 0;
725 if (rec->conn[0].port != -1 && rec->conn[0].port != port)
726 return 0;
728 return add_static_rec(found, targetname, tpgt, ip, port,
729 &rec->iface);
732 static int add_static_node(int *found, void *data,
733 char *targetname)
735 node_rec_t *rec = data;
737 if (!strlen(rec->name))
738 goto search;
740 if (strcmp(rec->name, targetname))
741 return 0;
743 if (!strlen(rec->conn[0].address))
744 goto search;
746 return add_static_rec(found, targetname, rec->tpgt,
747 rec->conn[0].address,
748 rec->conn[0].port, &rec->iface);
749 search:
750 return idbm_for_each_portal(found, data, add_static_portal,
751 targetname);
754 static int add_static_recs(struct node_rec *rec)
756 int rc, nr_found = 0;
758 rc = idbm_for_each_node(&nr_found, rec, add_static_node);
759 if (rc) {
760 log_error("Error while adding records. DB may be in an "
761 "inconsistent state. Err %d", rc);
762 return rc;
764 /* success */
765 if (nr_found > 0)
766 return 0;
768 /* brand new target */
769 if (strlen(rec->name) && strlen(rec->conn[0].address)) {
770 rc = add_static_rec(&nr_found, rec->name, rec->tpgt,
771 rec->conn[0].address, rec->conn[0].port,
772 &rec->iface);
773 if (rc)
774 goto done;
775 return 0;
777 done:
778 printf("No records added.\n");
779 return ENODEV;
783 * start sendtargets discovery process based on the
784 * particular config
786 static int
787 do_offload_sendtargets(discovery_rec_t *drec, int host_no, int do_login)
789 drec->type = DISCOVERY_TYPE_OFFLOAD_SENDTARGETS;
790 return discovery_offload_sendtargets(host_no, do_login, drec);
793 static int delete_node(void *data, struct node_rec *rec)
795 if (iscsi_check_for_running_session(rec)) {
797 * We could log out the session for the user, but if
798 * the session is being used the user may get something
799 * they were not expecting (FS errors and a read only
800 * remount).
802 log_error("This command will remove the record [iface: %s, "
803 "target: %s, portal: %s,%d], but a session is "
804 "using it. Logout session then rerun command to "
805 "remove record.", rec->iface.name, rec->name,
806 rec->conn[0].address, rec->conn[0].port);
807 return EINVAL;
810 return idbm_delete_node(rec);
813 static int delete_stale_rec(void *data, struct node_rec *rec)
815 struct list_head *new_rec_list = data;
816 struct node_rec *new_rec;
818 list_for_each_entry(new_rec, new_rec_list, list) {
820 * We could also move this to idbm.c and instead of looping
821 * over every node just loop over disc to node links.
823 if (rec->disc_type != new_rec->disc_type ||
824 rec->disc_port != new_rec->disc_port ||
825 strcmp(rec->disc_address, new_rec->disc_address))
827 * if we are not from the same discovery source
828 * ignore it
830 return 0;
832 if (__iscsi_match_session(rec,
833 new_rec->name,
834 new_rec->conn[0].address,
835 new_rec->conn[0].port,
836 &new_rec->iface))
837 return 0;
839 /* if there is a error we can continue on */
840 delete_node(NULL, rec);
841 return 0;
844 static int
845 exec_disc_op_on_recs(discovery_rec_t *drec, struct list_head *rec_list,
846 int info_level, int do_login, int op)
848 int rc = 0, err, found = 0;
849 struct node_rec *new_rec, tmp_rec;
851 /* clean up node db */
852 if (op & OP_DELETE)
853 idbm_for_each_rec(&found, rec_list, delete_stale_rec);
855 if (op & OP_NEW || op & OP_UPDATE) {
856 /* now add/update records */
857 list_for_each_entry(new_rec, rec_list, list) {
858 rc = idbm_add_node(new_rec, drec, op & OP_UPDATE);
859 if (rc)
860 log_error("Could not add/update "
861 "[%s:" iface_fmt " %s,%d,%d %s]",
862 new_rec->iface.transport_name,
863 iface_str(&new_rec->iface),
864 new_rec->conn[0].address,
865 new_rec->conn[0].port,
866 new_rec->tpgt, new_rec->name);
870 memset(&tmp_rec, 0, sizeof(node_rec_t));
871 list_for_each_entry(new_rec, rec_list, list) {
872 switch (info_level) {
873 case 0:
874 case -1:
875 idbm_print_node_flat(NULL, new_rec);
876 break;
877 case 1:
878 idbm_print_node_and_iface_tree(&tmp_rec, new_rec);
883 if (!do_login)
884 return 0;
886 err = iscsi_login_portals(NULL, &found, 1, rec_list,
887 iscsi_login_portal);
888 if (err && !rc)
889 rc = err;
890 return rc;
893 static int
894 do_software_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
895 int info_level, int do_login, int op)
897 struct list_head rec_list;
898 struct node_rec *rec, *tmp;
899 int rc;
901 INIT_LIST_HEAD(&rec_list);
903 * compat: if the user did not pass any op then we do all
904 * ops for them
906 if (!op)
907 op = OP_NEW | OP_DELETE | OP_UPDATE;
909 drec->type = DISCOVERY_TYPE_SENDTARGETS;
911 * we will probably want to know how a specific iface and discovery
912 * DB lined up, but for now just put all the targets found from
913 * a discovery portal in one place
915 if (!(op & OP_NONPERSISTENT)) {
916 rc = idbm_add_discovery(drec);
917 if (rc) {
918 log_error("Could not add new discovery record.");
919 return rc;
923 rc = idbm_bind_ifaces_to_nodes(discovery_sendtargets, drec, ifaces,
924 &rec_list);
925 if (rc) {
926 log_error("Could not perform SendTargets discovery.");
927 return rc;
930 rc = exec_disc_op_on_recs(drec, &rec_list, info_level, do_login, op);
932 list_for_each_entry_safe(rec, tmp, &rec_list, list) {
933 list_del(&rec->list);
934 free(rec);
937 return rc;
940 static int
941 do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
942 int info_level, int do_login, int op)
944 struct iface_rec *tmp, *iface;
945 int rc, host_no;
946 struct iscsi_transport *t;
948 if (list_empty(ifaces)) {
949 ifaces = NULL;
950 goto sw_st;
953 /* we allow users to mix hw and sw iscsi so we have to sort it out */
954 list_for_each_entry_safe(iface, tmp, ifaces, list) {
955 rc = iface_conf_read(iface);
956 if (rc) {
957 log_error("Could not read iface info for %s. "
958 "Make sure a iface config with the file "
959 "name and iface.iscsi_ifacename %s is in %s.",
960 iface->name, iface->name, IFACE_CONFIG_DIR);
961 list_del(&iface->list);
962 free(iface);
963 continue;
966 host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
967 if (rc || host_no == -1) {
968 log_debug(1, "Could not match iface" iface_fmt " to "
969 "host.", iface_str(iface));
970 /* try software iscsi */
971 continue;
974 t = iscsi_sysfs_get_transport_by_hba(host_no);
975 if (!t) {
976 log_error("Could not match hostno %d to "
977 "transport. Dropping interface %s,"
978 iface_fmt " ,%s.",
979 host_no, iface->transport_name,
980 iface_str(iface), iface->ipaddress);
981 list_del(&iface->list);
982 free(iface);
983 continue;
986 if (t->caps & CAP_SENDTARGETS_OFFLOAD) {
987 do_offload_sendtargets(drec, host_no, do_login);
988 list_del(&iface->list);
989 free(iface);
993 if (list_empty(ifaces))
994 return ENODEV;
996 sw_st:
997 return do_software_sendtargets(drec, ifaces, info_level, do_login,
998 op);
1001 static int do_isns(discovery_rec_t *drec, struct list_head *ifaces,
1002 int info_level, int do_login, int op)
1004 struct list_head rec_list;
1005 struct node_rec *rec, *tmp;
1006 int rc;
1008 INIT_LIST_HEAD(&rec_list);
1010 * compat: if the user did not pass any op then we do all
1011 * ops for them
1013 if (!op)
1014 op = OP_NEW | OP_DELETE | OP_UPDATE;
1016 drec->type = DISCOVERY_TYPE_ISNS;
1018 rc = idbm_bind_ifaces_to_nodes(discovery_isns, drec, ifaces,
1019 &rec_list);
1020 if (rc) {
1021 log_error("Could not perform iSNS discovery.");
1022 return rc;
1025 rc = exec_disc_op_on_recs(drec, &rec_list, info_level, do_login, op);
1027 list_for_each_entry_safe(rec, tmp, &rec_list, list) {
1028 list_del(&rec->list);
1029 free(rec);
1032 return rc;
1035 static int
1036 verify_mode_params(int argc, char **argv, char *allowed, int skip_m)
1038 int ch, longindex;
1039 int ret = 0;
1041 optind = 0;
1043 while ((ch = getopt_long(argc, argv, short_options,
1044 long_options, &longindex)) >= 0) {
1045 if (!strchr(allowed, ch)) {
1046 if (ch == 'm' && skip_m)
1047 continue;
1048 ret = ch;
1049 break;
1053 return ret;
1056 static void catch_sigint( int signo ) {
1057 log_warning("caught SIGINT, exiting...");
1058 exit(1);
1061 /* TODO: merge iter helpers and clean them up, so we can use them here */
1062 static int exec_iface_op(int op, int do_show, int info_level,
1063 struct iface_rec *iface, char *name, char *value)
1065 struct db_set_param set_param;
1066 struct node_rec *rec = NULL;
1067 int rc = 0;
1069 switch (op) {
1070 case OP_NEW:
1071 if (!iface) {
1072 log_error("Could not add interface. No interface "
1073 "passed in.");
1074 return EINVAL;
1077 rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 0);
1078 if (rec && iscsi_check_for_running_session(rec)) {
1079 rc = EBUSY;
1080 goto new_fail;
1083 iface_setup_defaults(iface);
1084 rc = iface_conf_write(iface);
1085 if (rc)
1086 goto new_fail;
1087 printf("New interface %s added\n", iface->name);
1088 break;
1089 new_fail:
1090 log_error("Could not create new interface %s.", iface->name);
1091 break;
1092 case OP_DELETE:
1093 if (!iface) {
1094 log_error("Could not delete interface. No interface "
1095 "passed in.");
1096 return EINVAL;
1099 rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
1100 if (!rec) {
1101 rc = EINVAL;
1102 goto delete_fail;
1105 /* logout and delete records using it first */
1106 rc = __for_each_rec(0, rec, NULL, delete_node);
1107 if (rc && rc != ENODEV)
1108 goto delete_fail;
1110 rc = iface_conf_delete(iface);
1111 if (rc)
1112 goto delete_fail;
1114 printf("%s unbound and deleted.\n", iface->name);
1115 break;
1116 delete_fail:
1117 log_error("Could not delete iface %s. A session is "
1118 "is using it or it could not be found.",
1119 iface->name);
1120 break;
1121 case OP_UPDATE:
1122 if (!iface || !name || !value) {
1123 log_error("Update requires name, value, and iface.");
1124 rc = EINVAL;
1125 break;
1128 rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1);
1129 if (!rec) {
1130 rc = EINVAL;
1131 goto update_fail;
1134 if (iscsi_check_for_running_session(rec))
1135 log_warning("Updating iface while iscsi sessions "
1136 "are using it. You must logout the running "
1137 "sessions then log back in for the "
1138 "new settings to take affect.");
1140 if (!strcmp(name, IFACE_ISCSINAME)) {
1141 log_error("Can not update "
1142 "iface.iscsi_ifacename. Delete it, "
1143 "and then create a new one.");
1144 rc = EINVAL;
1145 break;
1148 if (iface_is_bound_by_hwaddr(&rec->iface) &&
1149 !strcmp(name, IFACE_NETNAME)) {
1150 log_error("Can not update interface binding "
1151 "from hwaddress to net_ifacename. ");
1152 log_error("You must delete the interface and "
1153 "create a new one");
1154 rc = EINVAL;
1155 break;
1158 if (iface_is_bound_by_netdev(&rec->iface) &&
1159 !strcmp(name, IFACE_HWADDR)) {
1160 log_error("Can not update interface binding "
1161 "from net_ifacename to hwaddress. ");
1162 log_error("You must delete the interface and "
1163 "create a new one");
1164 rc = EINVAL;
1165 break;
1167 set_param.name = name;
1168 set_param.value = value;
1170 /* pass rec's iface because it has the db values */
1171 rc = iface_conf_update(&set_param, &rec->iface);
1172 if (rc)
1173 goto update_fail;
1175 rc = __for_each_rec(0, rec, &set_param, idbm_node_set_param);
1176 if (rc && rc != ENODEV)
1177 goto update_fail;
1179 printf("%s updated.\n", iface->name);
1180 break;
1181 update_fail:
1182 log_error("Could not update iface %s. A session is "
1183 "is using it or it could not be found.",
1184 iface->name);
1185 break;
1186 default:
1187 if (!iface || (iface && info_level > 0)) {
1188 if (op == OP_NOOP || op == OP_SHOW)
1189 rc = print_ifaces(iface, info_level);
1190 else
1191 rc = EINVAL;
1192 } else {
1193 rc = iface_conf_read(iface);
1194 if (!rc)
1195 idbm_print_iface_info(&do_show, iface);
1196 else
1197 log_error("Could not read iface %s (%d).",
1198 iface->name, rc);
1202 if (rec)
1203 free(rec);
1204 return rc;
1207 /* TODO cleanup arguments */
1208 static int exec_node_op(int op, int do_login, int do_logout,
1209 int do_show, int do_rescan, int do_stats,
1210 int info_level, struct node_rec *rec,
1211 char *name, char *value)
1213 int rc = 0;
1214 struct db_set_param set_param;
1216 if (rec)
1217 log_debug(2, "%s: %s:%s node [%s,%s,%d]", __FUNCTION__,
1218 rec->iface.transport_name, rec->iface.name,
1219 rec->name, rec->conn[0].address, rec->conn[0].port);
1221 if (op == OP_NEW) {
1222 if (add_static_recs(rec))
1223 rc = -1;
1224 goto out;
1227 if (do_rescan) {
1228 if (for_each_session(rec, rescan_portal))
1229 rc = -1;
1230 goto out;
1233 if (do_stats) {
1234 if (for_each_session(rec, session_stats))
1235 rc = -1;
1236 goto out;
1239 if (do_login && do_logout) {
1240 log_error("either login or logout at the time allowed!");
1241 rc = -1;
1242 goto out;
1245 if ((do_login || do_logout) && op > OP_NOOP) {
1246 log_error("either operation or login/logout "
1247 "at the time allowed!");
1248 rc = -1;
1249 goto out;
1252 if ((!do_login && !do_logout && op == OP_NOOP) &&
1253 (!strlen(rec->name) && !strlen(rec->conn[0].address) &&
1254 !strlen(rec->iface.name))) {
1255 rc = print_nodes(info_level, rec);
1256 goto out;
1259 if (do_login) {
1260 if (login_portals(rec))
1261 rc = -1;
1262 goto out;
1265 if (do_logout) {
1266 int nr_found;
1268 if (iscsi_logout_portals(rec, &nr_found, 1,
1269 iscsi_logout_matched_portal))
1270 rc = -1;
1271 goto out;
1274 if (op == OP_NOOP || (!do_login && !do_logout && op == OP_SHOW)) {
1275 if (for_each_rec(rec, &do_show, idbm_print_node_info))
1276 rc = -1;
1277 goto out;
1280 if (op == OP_UPDATE) {
1281 if (!name || !value) {
1282 log_error("update requires name and value");
1283 rc = -1;
1284 goto out;
1287 /* compat - old tools used node and iface transport name */
1288 if (!strncmp(name, "iface.", 6) &&
1289 strcmp(name, "iface.transport_name")) {
1290 log_error("Cannot modify %s. Use iface mode to update "
1291 "this value.", name);
1292 rc = -1;
1293 goto out;
1296 if (!strcmp(name, "node.transport_name"))
1297 name = "iface.transport_name";
1299 * tmp hack - we added compat crap above for the transport,
1300 * but want to fix Doran's issue in this release too. However
1301 * his patch is too harsh on many settings and we do not have
1302 * time to update apps so we have this tmp hack until we
1303 * can settle on a good interface that distros can use
1304 * and we can mark stable.
1306 if (!strcmp(name, "iface.transport_name")) {
1307 if (iscsi_check_for_running_session(rec)) {
1308 log_warning("Cannot modify node/iface "
1309 "transport name while a session "
1310 "is using it. Log out the session "
1311 "then update record.");
1312 rc = -1;
1313 goto out;
1317 set_param.name = name;
1318 set_param.value = value;
1320 if (for_each_rec(rec, &set_param, idbm_node_set_param))
1321 rc = -1;
1322 goto out;
1323 } else if (op == OP_DELETE) {
1324 if (for_each_rec(rec, NULL, delete_node))
1325 rc = -1;
1326 goto out;
1327 } else {
1328 log_error("operation is not supported.");
1329 rc = -1;
1330 goto out;
1332 out:
1333 return rc;
1336 static int exec_fw_disc_op(discovery_rec_t *drec, struct list_head *ifaces,
1337 int info_level, int do_login, int op)
1339 struct list_head targets, rec_list, new_ifaces;
1340 struct iface_rec *iface, *tmp_iface;
1341 struct node_rec *rec, *tmp_rec;
1342 int rc = 0;
1344 INIT_LIST_HEAD(&targets);
1345 INIT_LIST_HEAD(&rec_list);
1346 INIT_LIST_HEAD(&new_ifaces);
1348 * compat: if the user did not pass any op then we do all
1349 * ops for them
1351 if (!op)
1352 op = OP_NEW | OP_DELETE | OP_UPDATE;
1355 * if a user passed in ifaces then we use them and ignore the ibft
1356 * net info
1358 if (!list_empty(ifaces)) {
1359 list_for_each_entry_safe(iface, tmp_iface, ifaces, list) {
1360 rc = iface_conf_read(iface);
1361 if (rc) {
1362 log_error("Could not read iface info for %s. "
1363 "Make sure a iface config with the "
1364 "file name and iface.iscsi_ifacename "
1365 "%s is in %s.", iface->name,
1366 iface->name, IFACE_CONFIG_DIR);
1367 list_del_init(&iface->list);
1368 free(iface);
1369 continue;
1372 goto discover_fw_tgts;
1376 * Next, check if we see any offload cards. If we do then
1377 * we make a iface if needed.
1379 * Note1: if there is not a offload card we do not setup
1380 * software iscsi binding with the nic used for booting,
1381 * because we do not know if that was intended.
1383 * Note2: we assume that the user probably wanted to access
1384 * all targets through all the ifaces instead of being limited
1385 * to what you can export in ibft.
1387 rc = fw_get_targets(&targets);
1388 if (rc) {
1389 log_error("Could not get list of targets from firmware. "
1390 "(err %d)\n", rc);
1391 return rc;
1393 rc = iface_create_ifaces_from_boot_contexts(&new_ifaces, &targets);
1394 if (rc)
1395 goto done;
1396 if (!list_empty(&new_ifaces))
1397 ifaces = &new_ifaces;
1399 discover_fw_tgts:
1400 rc = idbm_bind_ifaces_to_nodes(discovery_fw, drec,
1401 ifaces, &rec_list);
1402 if (rc)
1403 log_error("Could not perform fw discovery.\n");
1404 else
1405 rc = exec_disc_op_on_recs(drec, &rec_list, info_level,
1406 do_login, op);
1408 done:
1409 fw_free_targets(&targets);
1411 list_for_each_entry_safe(iface, tmp_iface, &new_ifaces, list) {
1412 list_del(&iface->list);
1413 free(iface);
1416 list_for_each_entry_safe(rec, tmp_rec, &rec_list, list) {
1417 list_del(&rec->list);
1418 free(rec);
1420 return rc;
1423 static int exec_fw_op(discovery_rec_t *drec, struct list_head *ifaces,
1424 int info_level, int do_login, int op)
1426 struct boot_context *context;
1427 struct list_head targets, rec_list;
1428 struct node_rec *rec;
1429 int rc = 0;
1431 INIT_LIST_HEAD(&targets);
1432 INIT_LIST_HEAD(&rec_list);
1434 if (drec)
1435 return exec_fw_disc_op(drec, ifaces, info_level, do_login, op);
1437 /* The following ops do not interact with the DB */
1438 rc = fw_get_targets(&targets);
1439 if (rc) {
1440 log_error("Could not get list of targets from firmware. "
1441 "(err %d)\n", rc);
1442 return rc;
1445 if (do_login) {
1446 list_for_each_entry(context, &targets, list) {
1447 rec = idbm_create_rec_from_boot_context(context);
1448 if (!rec) {
1449 log_error("Could not convert firmware info to "
1450 "node record.\n");
1451 rc = ENOMEM;
1452 break;
1455 iscsi_login_portal(NULL, NULL, rec);
1456 free(rec);
1458 } else {
1459 list_for_each_entry(context, &targets, list)
1460 fw_print_entry(context);
1463 fw_free_targets(&targets);
1464 return rc;
1468 main(int argc, char **argv)
1470 char *ip = NULL, *name = NULL, *value = NULL;
1471 char *targetname = NULL, *group_session_mgmt_mode = NULL;
1472 int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0;
1473 int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0;
1474 int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0;
1475 int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0;
1476 struct sigaction sa_old;
1477 struct sigaction sa_new;
1478 discovery_rec_t drec;
1479 struct list_head ifaces;
1480 struct iface_rec *iface = NULL, *tmp;
1481 struct node_rec *rec = NULL;
1482 uint32_t host_no = -1;
1484 memset(&drec, 0, sizeof(discovery_rec_t));
1485 INIT_LIST_HEAD(&ifaces);
1486 /* do not allow ctrl-c for now... */
1487 memset(&sa_old, 0, sizeof(struct sigaction));
1488 memset(&sa_new, 0, sizeof(struct sigaction));
1490 sa_new.sa_handler = catch_sigint;
1491 sigemptyset(&sa_new.sa_mask);
1492 sa_new.sa_flags = 0;
1493 sigaction(SIGINT, &sa_new, &sa_old );
1495 umask(0177);
1497 /* enable stdout logging */
1498 log_init(program_name, 1024, log_do_log_std, NULL);
1499 sysfs_init();
1501 optopt = 0;
1502 while ((ch = getopt_long(argc, argv, short_options,
1503 long_options, &longindex)) >= 0) {
1504 switch (ch) {
1505 case 'k':
1506 killiscsid = atoi(optarg);
1507 if (killiscsid < 0) {
1508 log_error("Invalid killiscsid priority %d "
1509 "Priority must be greater than or "
1510 "equal to zero.", killiscsid);
1511 rc = -1;
1512 goto free_ifaces;
1514 break;
1515 case 't':
1516 type = str_to_type(optarg);
1517 break;
1518 case 'o':
1519 op |= str_to_op(optarg);
1520 if (op == OP_NOOP) {
1521 log_error("can not recognize operation: '%s'",
1522 optarg);
1523 rc = -1;
1524 goto free_ifaces;
1526 break;
1527 case 'n':
1528 name = optarg;
1529 break;
1530 case 'v':
1531 value = optarg;
1532 break;
1533 case 'H':
1534 errno = 0;
1535 host_no = strtoul(optarg, NULL, 10);
1536 if (errno) {
1537 log_error("invalid host no %s. %s.",
1538 optarg, strerror(errno));
1539 rc = -1;
1540 goto free_ifaces;
1542 break;
1543 case 'r':
1544 sid = iscsi_sysfs_get_sid_from_path(optarg);
1545 if (sid < 0) {
1546 log_error("invalid sid '%s'",
1547 optarg);
1548 rc = -1;
1549 goto free_ifaces;
1551 break;
1552 case 'R':
1553 do_rescan = 1;
1554 break;
1555 case 'P':
1556 info_level = atoi(optarg);
1557 break;
1558 case 'l':
1559 do_login = 1;
1560 break;
1561 case 'u':
1562 do_logout = 1;
1563 break;
1564 case 'U':
1565 do_logout_all = 1;
1566 group_session_mgmt_mode= optarg;
1567 break;
1568 case 'L':
1569 do_login_all= 1;
1570 group_session_mgmt_mode= optarg;
1571 break;
1572 case 's':
1573 do_stats = 1;
1574 break;
1575 case 'S':
1576 do_show = 1;
1577 break;
1578 case 'd':
1579 log_level = atoi(optarg);
1580 break;
1581 case 'm':
1582 mode = str_to_mode(optarg);
1583 break;
1584 case 'T':
1585 targetname = optarg;
1586 break;
1587 case 'p':
1588 ip = str_to_ipport(optarg, &port, &tpgt);
1589 break;
1590 case 'I':
1591 iface = iface_alloc(optarg, &rc);
1592 if (rc == EINVAL) {
1593 printf("Invalid iface name %s. Must be from "
1594 "1 to %d characters.\n",
1595 optarg, ISCSI_MAX_IFACE_LEN - 1);
1596 rc = -1;
1597 goto free_ifaces;
1598 } else if (!iface || rc) {
1599 printf("Could not add iface %s.", optarg);
1600 rc = -1;
1601 goto free_ifaces;
1604 list_add_tail(&iface->list, &ifaces);
1605 num_ifaces++;
1606 break;
1607 case 'V':
1608 printf("%s version %s\n", program_name,
1609 ISCSI_VERSION_STR);
1610 return 0;
1611 case 'h':
1612 usage(0);
1616 if (optopt) {
1617 log_error("unrecognized character '%c'", optopt);
1618 rc = -1;
1619 goto free_ifaces;
1622 if (killiscsid >= 0) {
1623 kill_iscsid(killiscsid);
1624 goto free_ifaces;
1627 if (mode < 0)
1628 usage(0);
1630 if (mode == MODE_FW) {
1631 if ((rc = verify_mode_params(argc, argv, "ml", 0))) {
1632 log_error("fw mode: option '-%c' is not "
1633 "allowed/supported", rc);
1634 rc = -1;
1635 goto free_ifaces;
1638 rc = exec_fw_op(NULL, NULL, info_level, do_login, op);
1639 goto free_ifaces;
1642 increase_max_files();
1643 if (idbm_init(get_config_file)) {
1644 log_warning("exiting due to idbm configuration error");
1645 rc = -1;
1646 goto free_ifaces;
1649 if (mode != MODE_DISCOVERY && ip)
1650 port = ISCSI_LISTEN_PORT;
1652 switch (mode) {
1653 case MODE_HOST:
1654 if ((rc = verify_mode_params(argc, argv, "HdmP", 0))) {
1655 log_error("host mode: option '-%c' is not "
1656 "allowed/supported", rc);
1657 rc = -1;
1658 goto out;
1661 rc = host_info_print(info_level, host_no);
1662 break;
1663 case MODE_IFACE:
1664 iface_setup_host_bindings();
1666 if ((rc = verify_mode_params(argc, argv, "IdnvmPo", 0))) {
1667 log_error("iface mode: option '-%c' is not "
1668 "allowed/supported", rc);
1669 rc = -1;
1670 goto out;
1673 if (!list_empty(&ifaces)) {
1674 iface = list_entry(ifaces.next, struct iface_rec,
1675 list);
1676 if (num_ifaces > 1)
1677 log_error("iface mode only accepts one "
1678 "interface. Using the first one "
1679 "%s.", iface->name);
1681 rc = exec_iface_op(op, do_show, info_level, iface,
1682 name, value);
1683 break;
1684 case MODE_DISCOVERY:
1685 if ((rc = verify_mode_params(argc, argv, "SIPdmntplov", 0))) {
1686 log_error("discovery mode: option '-%c' is not "
1687 "allowed/supported", rc);
1688 rc = -1;
1689 goto out;
1691 switch (type) {
1692 case DISCOVERY_TYPE_SENDTARGETS:
1693 if (port < 0)
1694 port = ISCSI_LISTEN_PORT;
1696 if (ip == NULL) {
1697 log_error("please specify right portal as "
1698 "<ipaddr>[:<ipport>]");
1699 rc = -1;
1700 goto out;
1703 if (idbm_discovery_read(&drec, ip, port)) {
1704 idbm_sendtargets_defaults(&drec.u.sendtargets);
1705 strlcpy(drec.address, ip, sizeof(drec.address));
1706 drec.port = port;
1709 if (do_sendtargets(&drec, &ifaces, info_level,
1710 do_login, op)) {
1711 rc = -1;
1712 goto out;
1714 break;
1715 case DISCOVERY_TYPE_SLP:
1716 log_error("SLP discovery is not fully "
1717 "implemented yet.");
1718 rc = -1;
1719 break;
1720 case DISCOVERY_TYPE_ISNS:
1721 if (!ip) {
1722 log_error("please specify right portal as "
1723 "<ipaddr>:[<ipport>]");
1724 rc = -1;
1725 goto out;
1728 strlcpy(drec.address, ip, sizeof(drec.address));
1729 if (port < 0)
1730 drec.port = ISNS_DEFAULT_PORT;
1731 else
1732 drec.port = port;
1734 if (do_isns(&drec, &ifaces, info_level, do_login, op)) {
1735 rc = -1;
1736 goto out;
1738 break;
1739 case DISCOVERY_TYPE_FW:
1740 drec.type = DISCOVERY_TYPE_FW;
1741 if (exec_fw_op(&drec, &ifaces, info_level, do_login,
1742 op))
1743 rc = -1;
1744 break;
1745 default:
1746 if (ip) {
1747 if (idbm_discovery_read(&drec, ip, port)) {
1748 log_error("discovery record [%s,%d] "
1749 "not found!", ip, port);
1750 rc = -1;
1751 goto out;
1753 if (do_login &&
1754 drec.type == DISCOVERY_TYPE_SENDTARGETS) {
1755 do_sendtargets(&drec, &ifaces,
1756 info_level, do_login,
1757 op);
1758 } else if (do_login &&
1759 drec.type == DISCOVERY_TYPE_SLP) {
1760 log_error("SLP discovery is not fully "
1761 "implemented yet.");
1762 rc = -1;
1763 goto out;
1764 } else if (do_login &&
1765 drec.type == DISCOVERY_TYPE_ISNS) {
1766 log_error("iSNS discovery is not fully "
1767 "implemented yet.");
1768 rc = -1;
1769 goto out;
1770 } else if (op == OP_NOOP || op == OP_SHOW) {
1771 if (!idbm_print_discovery_info(&drec,
1772 do_show)) {
1773 log_error("no records found!");
1774 rc = -1;
1776 } else if (op == OP_DELETE) {
1777 if (idbm_delete_discovery(&drec)) {
1778 log_error("unable to delete "
1779 "record!");
1780 rc = -1;
1782 } else if (op == OP_UPDATE) {
1783 struct db_set_param set_param;
1785 if (!name || !value) {
1786 log_error("Update requires "
1787 "name and value");
1788 rc = -1;
1789 goto out;
1791 set_param.name = name;
1792 set_param.value = value;
1793 if (idbm_discovery_set_param(&set_param,
1794 &drec))
1795 rc = -1;
1796 } else {
1797 log_error("operation is not supported.");
1798 rc = -1;
1799 goto out;
1802 } else if (op == OP_NOOP || op == OP_SHOW) {
1803 if (!idbm_print_all_discovery(info_level))
1804 rc = -1;
1805 goto out;
1806 } else if (op == OP_DELETE) {
1807 log_error("--record required for delete operation");
1808 rc = -1;
1809 goto out;
1810 } else {
1811 log_error("Operations: new and "
1812 "update for node is not fully "
1813 "implemented yet.");
1814 rc = -1;
1815 goto out;
1817 /* fall through */
1819 break;
1820 case MODE_NODE:
1821 if ((rc = verify_mode_params(argc, argv, "RsPIdmlSonvupTUL",
1822 0))) {
1823 log_error("node mode: option '-%c' is not "
1824 "allowed/supported", rc);
1825 rc = -1;
1826 goto out;
1829 if (do_login_all) {
1830 rc = login_by_startup(group_session_mgmt_mode);
1831 goto out;
1834 if (do_logout_all) {
1835 rc = logout_by_startup(group_session_mgmt_mode);
1836 goto out;
1839 if (!list_empty(&ifaces)) {
1840 iface = list_entry(ifaces.next, struct iface_rec,
1841 list);
1842 if (num_ifaces > 1)
1843 log_error("NODE mode only accepts one "
1844 "interface. Using the first one "
1845 "driver %s hwaddress %s ipaddress "
1846 "%s.", iface->transport_name,
1847 iface->hwaddress, iface->ipaddress);
1850 rec = idbm_create_rec(targetname, tpgt, ip, port, iface, 1);
1851 if (!rec) {
1852 rc = -1;
1853 goto out;
1856 rc = exec_node_op(op, do_login, do_logout, do_show,
1857 do_rescan, do_stats, info_level, rec,
1858 name, value);
1859 break;
1860 case MODE_SESSION:
1861 if ((rc = verify_mode_params(argc, argv,
1862 "PiRdrmusonuSv", 1))) {
1863 log_error("session mode: option '-%c' is not "
1864 "allowed or supported", rc);
1865 rc = -1;
1866 goto out;
1868 if (sid >= 0) {
1869 char session[64];
1870 struct session_info *info;
1872 snprintf(session, 63, "session%d", sid);
1873 session[63] = '\0';
1875 info = calloc(1, sizeof(*info));
1876 if (!info) {
1877 rc = ENOMEM;
1878 goto out;
1881 rc = iscsi_sysfs_get_sessioninfo_by_id(info, session);
1882 if (rc) {
1883 log_error("Could not get session info for sid "
1884 "%d", sid);
1885 goto free_info;
1889 * We should be able to go on, but for now
1890 * we only support session mode ops if the module
1891 * is loaded and we support that module.
1893 if (!iscsi_sysfs_get_transport_by_sid(sid))
1894 goto free_info;
1896 if (!do_logout && !do_rescan && !do_stats &&
1897 op == OP_NOOP && info_level > 0) {
1898 rc = session_info_print(info_level, info);
1899 if (rc)
1900 rc = -1;
1901 goto free_info;
1904 rec = idbm_create_rec(info->targetname,
1905 info->tpgt,
1906 info->persistent_address,
1907 info->persistent_port,
1908 &info->iface, 1);
1909 if (!rec) {
1910 rc = -1;
1911 goto free_info;
1914 /* drop down to node ops */
1915 rc = exec_node_op(op, do_login, do_logout, do_show,
1916 do_rescan, do_stats, info_level,
1917 rec, name, value);
1918 free_info:
1919 free(info);
1920 goto out;
1921 } else {
1922 if (do_logout || do_rescan || do_stats) {
1923 rc = exec_node_op(op, do_login, do_logout,
1924 do_show, do_rescan, do_stats,
1925 info_level, NULL, name, value);
1926 goto out;
1929 rc = session_info_print(info_level, NULL);
1931 break;
1932 default:
1933 log_error("This mode is not yet supported");
1934 /* fall through */
1937 out:
1938 if (rec)
1939 free(rec);
1940 idbm_terminate();
1941 free_ifaces:
1942 list_for_each_entry_safe(iface, tmp, &ifaces, list) {
1943 list_del(&iface->list);
1944 free(iface);
1946 free_transports();
1947 sysfs_cleanup();
1948 return rc;