summaryrefslogtreecommitdiffstats
path: root/usr.bin/iscsictl/iscsictl.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/iscsictl/iscsictl.c')
-rw-r--r--usr.bin/iscsictl/iscsictl.c742
1 files changed, 742 insertions, 0 deletions
diff --git a/usr.bin/iscsictl/iscsictl.c b/usr.bin/iscsictl/iscsictl.c
new file mode 100644
index 0000000..1088d69
--- /dev/null
+++ b/usr.bin/iscsictl/iscsictl.c
@@ -0,0 +1,742 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <iscsi_ioctl.h>
+#include "iscsictl.h"
+
+struct conf *
+conf_new(void)
+{
+ struct conf *conf;
+
+ conf = calloc(1, sizeof(*conf));
+ if (conf == NULL)
+ err(1, "calloc");
+
+ TAILQ_INIT(&conf->conf_targets);
+
+ return (conf);
+}
+
+struct target *
+target_find(struct conf *conf, const char *nickname)
+{
+ struct target *targ;
+
+ TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
+ if (targ->t_nickname != NULL &&
+ strcasecmp(targ->t_nickname, nickname) == 0)
+ return (targ);
+ }
+
+ return (NULL);
+}
+
+struct target *
+target_new(struct conf *conf)
+{
+ struct target *targ;
+
+ targ = calloc(1, sizeof(*targ));
+ if (targ == NULL)
+ err(1, "calloc");
+ targ->t_conf = conf;
+ TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next);
+
+ return (targ);
+}
+
+void
+target_delete(struct target *targ)
+{
+
+ TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next);
+ free(targ);
+}
+
+
+static char *
+default_initiator_name(void)
+{
+ char *name;
+ size_t namelen;
+ int error;
+
+ namelen = _POSIX_HOST_NAME_MAX + strlen(DEFAULT_IQN);
+
+ name = calloc(1, namelen + 1);
+ if (name == NULL)
+ err(1, "calloc");
+ strcpy(name, DEFAULT_IQN);
+ error = gethostname(name + strlen(DEFAULT_IQN),
+ namelen - strlen(DEFAULT_IQN));
+ if (error != 0)
+ err(1, "gethostname");
+
+ return (name);
+}
+
+static bool
+valid_hex(const char ch)
+{
+ switch (ch) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'A':
+ case 'b':
+ case 'B':
+ case 'c':
+ case 'C':
+ case 'd':
+ case 'D':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+bool
+valid_iscsi_name(const char *name)
+{
+ int i;
+
+ if (strlen(name) >= MAX_NAME_LEN) {
+ warnx("overlong name for \"%s\"; max length allowed "
+ "by iSCSI specification is %d characters",
+ name, MAX_NAME_LEN);
+ return (false);
+ }
+
+ /*
+ * In the cases below, we don't return an error, just in case the admin
+ * was right, and we're wrong.
+ */
+ if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) {
+ for (i = strlen("iqn."); name[i] != '\0'; i++) {
+ /*
+ * XXX: We should verify UTF-8 normalisation, as defined
+ * by 3.2.6.2: iSCSI Name Encoding.
+ */
+ if (isalnum(name[i]))
+ continue;
+ if (name[i] == '-' || name[i] == '.' || name[i] == ':')
+ continue;
+ warnx("invalid character \"%c\" in iSCSI name "
+ "\"%s\"; allowed characters are letters, digits, "
+ "'-', '.', and ':'", name[i], name);
+ break;
+ }
+ /*
+ * XXX: Check more stuff: valid date and a valid reversed domain.
+ */
+ } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) {
+ if (strlen(name) != strlen("eui.") + 16)
+ warnx("invalid iSCSI name \"%s\"; the \"eui.\" "
+ "should be followed by exactly 16 hexadecimal "
+ "digits", name);
+ for (i = strlen("eui."); name[i] != '\0'; i++) {
+ if (!valid_hex(name[i])) {
+ warnx("invalid character \"%c\" in iSCSI "
+ "name \"%s\"; allowed characters are 1-9 "
+ "and A-F", name[i], name);
+ break;
+ }
+ }
+ } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) {
+ if (strlen(name) > strlen("naa.") + 32)
+ warnx("invalid iSCSI name \"%s\"; the \"naa.\" "
+ "should be followed by at most 32 hexadecimal "
+ "digits", name);
+ for (i = strlen("naa."); name[i] != '\0'; i++) {
+ if (!valid_hex(name[i])) {
+ warnx("invalid character \"%c\" in ISCSI "
+ "name \"%s\"; allowed characters are 1-9 "
+ "and A-F", name[i], name);
+ break;
+ }
+ }
+ } else {
+ warnx("invalid iSCSI name \"%s\"; should start with "
+ "either \".iqn\", \"eui.\", or \"naa.\"",
+ name);
+ }
+ return (true);
+}
+
+void
+conf_verify(struct conf *conf)
+{
+ struct target *targ;
+
+ TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
+ assert(targ->t_nickname != NULL);
+ if (targ->t_session_type == SESSION_TYPE_UNSPECIFIED)
+ targ->t_session_type = SESSION_TYPE_NORMAL;
+ if (targ->t_session_type == SESSION_TYPE_NORMAL &&
+ targ->t_name == NULL)
+ errx(1, "missing TargetName for target \"%s\"",
+ targ->t_nickname);
+ if (targ->t_session_type == SESSION_TYPE_DISCOVERY &&
+ targ->t_name != NULL)
+ errx(1, "cannot specify TargetName for discovery "
+ "sessions for target \"%s\"", targ->t_nickname);
+ if (targ->t_name != NULL) {
+ if (valid_iscsi_name(targ->t_name) == false)
+ errx(1, "invalid target name \"%s\"",
+ targ->t_name);
+ }
+ if (targ->t_protocol == PROTOCOL_UNSPECIFIED)
+ targ->t_protocol = PROTOCOL_ISCSI;
+#ifndef ICL_KERNEL_PROXY
+ if (targ->t_protocol == PROTOCOL_ISER)
+ errx(1, "iSER support requires ICL_KERNEL_PROXY; "
+ "see iscsi(4) for details");
+#endif
+ if (targ->t_address == NULL)
+ errx(1, "missing TargetAddress for target \"%s\"",
+ targ->t_nickname);
+ if (targ->t_initiator_name == NULL)
+ targ->t_initiator_name = default_initiator_name();
+ if (valid_iscsi_name(targ->t_initiator_name) == false)
+ errx(1, "invalid initiator name \"%s\"",
+ targ->t_initiator_name);
+ if (targ->t_header_digest == DIGEST_UNSPECIFIED)
+ targ->t_header_digest = DIGEST_NONE;
+ if (targ->t_data_digest == DIGEST_UNSPECIFIED)
+ targ->t_data_digest = DIGEST_NONE;
+ if (targ->t_auth_method == AUTH_METHOD_UNSPECIFIED) {
+ if (targ->t_user != NULL || targ->t_secret != NULL ||
+ targ->t_mutual_user != NULL ||
+ targ->t_mutual_secret != NULL)
+ targ->t_auth_method =
+ AUTH_METHOD_CHAP;
+ else
+ targ->t_auth_method =
+ AUTH_METHOD_NONE;
+ }
+ if (targ->t_auth_method == AUTH_METHOD_CHAP) {
+ if (targ->t_user == NULL) {
+ errx(1, "missing chapIName for target \"%s\"",
+ targ->t_nickname);
+ }
+ if (targ->t_secret == NULL)
+ errx(1, "missing chapSecret for target \"%s\"",
+ targ->t_nickname);
+ if (targ->t_mutual_user != NULL ||
+ targ->t_mutual_secret != NULL) {
+ if (targ->t_mutual_user == NULL)
+ errx(1, "missing tgtChapName for "
+ "target \"%s\"", targ->t_nickname);
+ if (targ->t_mutual_secret == NULL)
+ errx(1, "missing tgtChapSecret for "
+ "target \"%s\"", targ->t_nickname);
+ }
+ }
+ }
+}
+
+static void
+conf_from_target(struct iscsi_session_conf *conf,
+ const struct target *targ)
+{
+ memset(conf, 0, sizeof(*conf));
+
+ /*
+ * XXX: Check bounds and return error instead of silently truncating.
+ */
+ if (targ->t_initiator_name != NULL)
+ strlcpy(conf->isc_initiator, targ->t_initiator_name,
+ sizeof(conf->isc_initiator));
+ if (targ->t_initiator_address != NULL)
+ strlcpy(conf->isc_initiator_addr, targ->t_initiator_address,
+ sizeof(conf->isc_initiator_addr));
+ if (targ->t_initiator_alias != NULL)
+ strlcpy(conf->isc_initiator_alias, targ->t_initiator_alias,
+ sizeof(conf->isc_initiator_alias));
+ if (targ->t_name != NULL)
+ strlcpy(conf->isc_target, targ->t_name,
+ sizeof(conf->isc_target));
+ if (targ->t_address != NULL)
+ strlcpy(conf->isc_target_addr, targ->t_address,
+ sizeof(conf->isc_target_addr));
+ if (targ->t_user != NULL)
+ strlcpy(conf->isc_user, targ->t_user,
+ sizeof(conf->isc_user));
+ if (targ->t_secret != NULL)
+ strlcpy(conf->isc_secret, targ->t_secret,
+ sizeof(conf->isc_secret));
+ if (targ->t_mutual_user != NULL)
+ strlcpy(conf->isc_mutual_user, targ->t_mutual_user,
+ sizeof(conf->isc_mutual_user));
+ if (targ->t_mutual_secret != NULL)
+ strlcpy(conf->isc_mutual_secret, targ->t_mutual_secret,
+ sizeof(conf->isc_mutual_secret));
+ if (targ->t_session_type == SESSION_TYPE_DISCOVERY)
+ conf->isc_discovery = 1;
+ if (targ->t_protocol == PROTOCOL_ISER)
+ conf->isc_iser = 1;
+ if (targ->t_header_digest == DIGEST_CRC32C)
+ conf->isc_header_digest = ISCSI_DIGEST_CRC32C;
+ else
+ conf->isc_header_digest = ISCSI_DIGEST_NONE;
+ if (targ->t_data_digest == DIGEST_CRC32C)
+ conf->isc_data_digest = ISCSI_DIGEST_CRC32C;
+ else
+ conf->isc_data_digest = ISCSI_DIGEST_NONE;
+}
+
+static int
+kernel_add(int iscsi_fd, const struct target *targ)
+{
+ struct iscsi_session_add isa;
+ int error;
+
+ memset(&isa, 0, sizeof(isa));
+ conf_from_target(&isa.isa_conf, targ);
+ error = ioctl(iscsi_fd, ISCSISADD, &isa);
+ if (error != 0)
+ warn("ISCSISADD");
+ return (error);
+}
+
+static int
+kernel_remove(int iscsi_fd, const struct target *targ)
+{
+ struct iscsi_session_remove isr;
+ int error;
+
+ memset(&isr, 0, sizeof(isr));
+ conf_from_target(&isr.isr_conf, targ);
+ error = ioctl(iscsi_fd, ISCSISREMOVE, &isr);
+ if (error != 0)
+ warn("ISCSISREMOVE");
+ return (error);
+}
+
+/*
+ * XXX: Add filtering.
+ */
+static int
+kernel_list(int iscsi_fd, const struct target *targ __unused,
+ int verbose)
+{
+ struct iscsi_session_state *states = NULL;
+ const struct iscsi_session_state *state;
+ const struct iscsi_session_conf *conf;
+ struct iscsi_session_list isl;
+ unsigned int i, nentries = 1;
+ int error;
+ bool show_periphs;
+
+ for (;;) {
+ states = realloc(states,
+ nentries * sizeof(struct iscsi_session_state));
+ if (states == NULL)
+ err(1, "realloc");
+
+ memset(&isl, 0, sizeof(isl));
+ isl.isl_nentries = nentries;
+ isl.isl_pstates = states;
+
+ error = ioctl(iscsi_fd, ISCSISLIST, &isl);
+ if (error != 0 && errno == EMSGSIZE) {
+ nentries *= 4;
+ continue;
+ }
+ break;
+ }
+ if (error != 0) {
+ warn("ISCSISLIST");
+ return (error);
+ }
+
+ if (verbose != 0) {
+ for (i = 0; i < isl.isl_nentries; i++) {
+ state = &states[i];
+ conf = &state->iss_conf;
+
+ printf("Session ID: %d\n", state->iss_id);
+ printf("Initiator name: %s\n", conf->isc_initiator);
+ printf("Initiator addr: %s\n",
+ conf->isc_initiator_addr);
+ printf("Initiator alias: %s\n",
+ conf->isc_initiator_alias);
+ printf("Target name: %s\n", conf->isc_target);
+ printf("Target addr: %s\n",
+ conf->isc_target_addr);
+ printf("Target alias: %s\n",
+ state->iss_target_alias);
+ printf("User: %s\n", conf->isc_user);
+ printf("Secret: %s\n", conf->isc_secret);
+ printf("Mutual user: %s\n",
+ conf->isc_mutual_user);
+ printf("Mutual secret: %s\n",
+ conf->isc_mutual_secret);
+ printf("Session type: %s\n",
+ conf->isc_discovery ? "Discovery" : "Normal");
+ printf("Session state: %s\n",
+ state->iss_connected ?
+ "Connected" : "Disconnected");
+ printf("Failure reason: %s\n", state->iss_reason);
+ printf("Header digest: %s\n",
+ state->iss_header_digest == ISCSI_DIGEST_CRC32C ?
+ "CRC32C" : "None");
+ printf("Data digest: %s\n",
+ state->iss_data_digest == ISCSI_DIGEST_CRC32C ?
+ "CRC32C" : "None");
+ printf("DataSegmentLen: %d\n",
+ state->iss_max_data_segment_length);
+ printf("ImmediateData: %s\n",
+ state->iss_immediate_data ? "Yes" : "No");
+ printf("iSER (RDMA): %s\n",
+ conf->isc_iser ? "Yes" : "No");
+ printf("Device nodes: ");
+ print_periphs(state->iss_id);
+ printf("\n\n");
+ }
+ } else {
+ printf("%-36s %-16s %s\n",
+ "Target name", "Target addr", "State");
+ for (i = 0; i < isl.isl_nentries; i++) {
+ state = &states[i];
+ conf = &state->iss_conf;
+ show_periphs = false;
+
+ printf("%-36s %-16s ",
+ conf->isc_target, conf->isc_target_addr);
+
+ if (state->iss_reason[0] != '\0') {
+ printf("%s\n", state->iss_reason);
+ } else {
+ if (conf->isc_discovery) {
+ printf("Discovery\n");
+ } else if (state->iss_connected) {
+ printf("Connected: ");
+ print_periphs(state->iss_id);
+ printf("\n");
+ } else {
+ printf("Disconnected\n");
+ }
+ }
+ }
+ }
+
+ return (0);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: iscsictl -A -h host -t target "
+ "[-u user -s secret]\n");
+ fprintf(stderr, " iscsictl -A -d discovery-host "
+ "[-u user -s secret]\n");
+ fprintf(stderr, " iscsictl -A -a [-c path]\n");
+ fprintf(stderr, " iscsictl -A -n nickname [-c path]\n");
+ fprintf(stderr, " iscsictl -R [-h host] [-t target]\n");
+ fprintf(stderr, " iscsictl -R -a\n");
+ fprintf(stderr, " iscsictl -R -n nickname [-c path]\n");
+ fprintf(stderr, " iscsictl -L [-v]\n");
+ exit(1);
+}
+
+char *
+checked_strdup(const char *s)
+{
+ char *c;
+
+ c = strdup(s);
+ if (c == NULL)
+ err(1, "strdup");
+ return (c);
+}
+
+int
+main(int argc, char **argv)
+{
+ int Aflag = 0, Rflag = 0, Lflag = 0, aflag = 0, vflag = 0;
+ const char *conf_path = DEFAULT_CONFIG_PATH;
+ char *nickname = NULL, *discovery_host = NULL, *host = NULL,
+ *target = NULL, *user = NULL, *secret = NULL;
+ int ch, error, iscsi_fd, retval, saved_errno;
+ int failed = 0;
+ struct conf *conf;
+ struct target *targ;
+
+ while ((ch = getopt(argc, argv, "ARLac:d:n:h:t:u:s:v")) != -1) {
+ switch (ch) {
+ case 'A':
+ Aflag = 1;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'L':
+ Lflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ conf_path = optarg;
+ break;
+ case 'd':
+ discovery_host = optarg;
+ break;
+ case 'n':
+ nickname = optarg;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 't':
+ target = optarg;
+ break;
+ case 'u':
+ user = optarg;
+ break;
+ case 's':
+ secret = optarg;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ if (argc != 0)
+ usage();
+
+ if (Aflag + Rflag + Lflag == 0)
+ Lflag = 1;
+ if (Aflag + Rflag + Lflag > 1)
+ errx(1, "at most one of -A, -R, or -L may be specified");
+
+ /*
+ * Note that we ignore unneccessary/inapplicable "-c" flag; so that
+ * people can do something like "alias ISCSICTL="iscsictl -c path"
+ * in shell scripts.
+ */
+ if (Aflag != 0) {
+ if (aflag != 0) {
+ if (host != NULL)
+ errx(1, "-a and -h and mutually exclusive");
+ if (target != NULL)
+ errx(1, "-a and -t and mutually exclusive");
+ if (user != NULL)
+ errx(1, "-a and -u and mutually exclusive");
+ if (secret != NULL)
+ errx(1, "-a and -s and mutually exclusive");
+ if (nickname != NULL)
+ errx(1, "-a and -n and mutually exclusive");
+ if (discovery_host != NULL)
+ errx(1, "-a and -d and mutually exclusive");
+ } else if (nickname != NULL) {
+ if (host != NULL)
+ errx(1, "-n and -h and mutually exclusive");
+ if (target != NULL)
+ errx(1, "-n and -t and mutually exclusive");
+ if (user != NULL)
+ errx(1, "-n and -u and mutually exclusive");
+ if (secret != NULL)
+ errx(1, "-n and -s and mutually exclusive");
+ if (discovery_host != NULL)
+ errx(1, "-n and -d and mutually exclusive");
+ } else if (discovery_host != NULL) {
+ if (host != NULL)
+ errx(1, "-d and -h and mutually exclusive");
+ if (target != NULL)
+ errx(1, "-d and -t and mutually exclusive");
+ } else {
+ if (target == NULL && host == NULL)
+ errx(1, "must specify -a, -n or -t/-h");
+
+ if (target != NULL && host == NULL)
+ errx(1, "-t must always be used with -h");
+ if (host != NULL && target == NULL)
+ errx(1, "-h must always be used with -t");
+ }
+
+ if (user != NULL && secret == NULL)
+ errx(1, "-u must always be used with -s");
+ if (secret != NULL && user == NULL)
+ errx(1, "-s must always be used with -u");
+
+ if (vflag != 0)
+ errx(1, "-v cannot be used with -A");
+
+ } else if (Rflag != 0) {
+ if (user != NULL)
+ errx(1, "-R and -u are mutually exclusive");
+ if (secret != NULL)
+ errx(1, "-R and -s are mutually exclusive");
+ if (discovery_host != NULL)
+ errx(1, "-R and -d are mutually exclusive");
+
+ if (aflag != 0) {
+ if (host != NULL)
+ errx(1, "-a and -h and mutually exclusive");
+ if (target != NULL)
+ errx(1, "-a and -t and mutually exclusive");
+ if (nickname != NULL)
+ errx(1, "-a and -n and mutually exclusive");
+ } else if (nickname != NULL) {
+ if (host != NULL)
+ errx(1, "-n and -h and mutually exclusive");
+ if (target != NULL)
+ errx(1, "-n and -t and mutually exclusive");
+ } else if (host != NULL) {
+ if (target != NULL)
+ errx(1, "-h and -t and mutually exclusive");
+ } else if (target != NULL) {
+ if (host != NULL)
+ errx(1, "-t and -h and mutually exclusive");
+ } else
+ errx(1, "must specify either-a, -n, -t, or -h");
+
+ if (vflag != 0)
+ errx(1, "-v cannot be used with -R");
+
+ } else {
+ assert(Lflag != 0);
+
+ if (host != NULL)
+ errx(1, "-L and -h and mutually exclusive");
+ if (target != NULL)
+ errx(1, "-L and -t and mutually exclusive");
+ if (user != NULL)
+ errx(1, "-L and -u and mutually exclusive");
+ if (secret != NULL)
+ errx(1, "-L and -s and mutually exclusive");
+ if (nickname != NULL)
+ errx(1, "-L and -n and mutually exclusive");
+ if (discovery_host != NULL)
+ errx(1, "-L and -d and mutually exclusive");
+ }
+
+ iscsi_fd = open(ISCSI_PATH, O_RDWR);
+ if (iscsi_fd < 0 && errno == ENOENT) {
+ saved_errno = errno;
+ retval = kldload("iscsi");
+ if (retval != -1)
+ iscsi_fd = open(ISCSI_PATH, O_RDWR);
+ else
+ errno = saved_errno;
+ }
+ if (iscsi_fd < 0)
+ err(1, "failed to open %s", ISCSI_PATH);
+
+ if (Aflag != 0 && aflag != 0) {
+ conf = conf_new_from_file(conf_path);
+
+ TAILQ_FOREACH(targ, &conf->conf_targets, t_next)
+ failed += kernel_add(iscsi_fd, targ);
+ } else if (nickname != NULL) {
+ conf = conf_new_from_file(conf_path);
+ targ = target_find(conf, nickname);
+ if (targ == NULL)
+ errx(1, "target %s not found in the configuration file",
+ nickname);
+
+ if (Aflag != 0)
+ failed += kernel_add(iscsi_fd, targ);
+ else if (Rflag != 0)
+ failed += kernel_remove(iscsi_fd, targ);
+ else
+ failed += kernel_list(iscsi_fd, targ, vflag);
+ } else {
+ if (Aflag != 0 && target != NULL) {
+ if (valid_iscsi_name(target) == false)
+ errx(1, "invalid target name \"%s\"", target);
+ }
+ conf = conf_new();
+ targ = target_new(conf);
+ targ->t_initiator_name = default_initiator_name();
+ targ->t_header_digest = DIGEST_NONE;
+ targ->t_data_digest = DIGEST_NONE;
+ targ->t_name = target;
+ if (discovery_host != NULL) {
+ targ->t_session_type = SESSION_TYPE_DISCOVERY;
+ targ->t_address = discovery_host;
+ } else {
+ targ->t_session_type = SESSION_TYPE_NORMAL;
+ targ->t_address = host;
+ }
+ targ->t_user = user;
+ targ->t_secret = secret;
+
+ if (Aflag != 0)
+ failed += kernel_add(iscsi_fd, targ);
+ else if (Rflag != 0)
+ failed += kernel_remove(iscsi_fd, targ);
+ else
+ failed += kernel_list(iscsi_fd, targ, vflag);
+ }
+
+ error = close(iscsi_fd);
+ if (error != 0)
+ err(1, "close");
+
+ if (failed > 0)
+ return (1);
+ return (0);
+}
OpenPOWER on IntegriCloud