1 /*- 2 * Copyright (c) 2012 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Edward Tomasz Napierala under sponsorship 6 * from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/ioctl.h> 33 #include <sys/param.h> 34 #include <sys/linker.h> 35 #include <assert.h> 36 #include <ctype.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <limits.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include <iscsi_ioctl.h> 47 #include "iscsictl.h" 48 49 struct conf * 50 conf_new(void) 51 { 52 struct conf *conf; 53 54 conf = calloc(1, sizeof(*conf)); 55 if (conf == NULL) 56 err(1, "calloc"); 57 58 TAILQ_INIT(&conf->conf_targets); 59 60 return (conf); 61 } 62 63 struct target * 64 target_find(struct conf *conf, const char *nickname) 65 { 66 struct target *targ; 67 68 TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 69 if (targ->t_nickname != NULL && 70 strcasecmp(targ->t_nickname, nickname) == 0) 71 return (targ); 72 } 73 74 return (NULL); 75 } 76 77 struct target * 78 target_new(struct conf *conf) 79 { 80 struct target *targ; 81 82 targ = calloc(1, sizeof(*targ)); 83 if (targ == NULL) 84 err(1, "calloc"); 85 targ->t_conf = conf; 86 TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 87 88 return (targ); 89 } 90 91 void 92 target_delete(struct target *targ) 93 { 94 95 TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 96 free(targ); 97 } 98 99 100 static char * 101 default_initiator_name(void) 102 { 103 char *name; 104 size_t namelen; 105 int error; 106 107 namelen = _POSIX_HOST_NAME_MAX + strlen(DEFAULT_IQN); 108 109 name = calloc(1, namelen + 1); 110 if (name == NULL) 111 err(1, "calloc"); 112 strcpy(name, DEFAULT_IQN); 113 error = gethostname(name + strlen(DEFAULT_IQN), 114 namelen - strlen(DEFAULT_IQN)); 115 if (error != 0) 116 err(1, "gethostname"); 117 118 return (name); 119 } 120 121 static bool 122 valid_hex(const char ch) 123 { 124 switch (ch) { 125 case '0': 126 case '1': 127 case '2': 128 case '3': 129 case '4': 130 case '5': 131 case '6': 132 case '7': 133 case '8': 134 case '9': 135 case 'a': 136 case 'A': 137 case 'b': 138 case 'B': 139 case 'c': 140 case 'C': 141 case 'd': 142 case 'D': 143 case 'e': 144 case 'E': 145 case 'f': 146 case 'F': 147 return (true); 148 default: 149 return (false); 150 } 151 } 152 153 bool 154 valid_iscsi_name(const char *name) 155 { 156 int i; 157 158 if (strlen(name) >= MAX_NAME_LEN) { 159 warnx("overlong name for \"%s\"; max length allowed " 160 "by iSCSI specification is %d characters", 161 name, MAX_NAME_LEN); 162 return (false); 163 } 164 165 /* 166 * In the cases below, we don't return an error, just in case the admin 167 * was right, and we're wrong. 168 */ 169 if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 170 for (i = strlen("iqn."); name[i] != '\0'; i++) { 171 /* 172 * XXX: We should verify UTF-8 normalisation, as defined 173 * by 3.2.6.2: iSCSI Name Encoding. 174 */ 175 if (isalnum(name[i])) 176 continue; 177 if (name[i] == '-' || name[i] == '.' || name[i] == ':') 178 continue; 179 warnx("invalid character \"%c\" in iSCSI name " 180 "\"%s\"; allowed characters are letters, digits, " 181 "'-', '.', and ':'", name[i], name); 182 break; 183 } 184 /* 185 * XXX: Check more stuff: valid date and a valid reversed domain. 186 */ 187 } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 188 if (strlen(name) != strlen("eui.") + 16) 189 warnx("invalid iSCSI name \"%s\"; the \"eui.\" " 190 "should be followed by exactly 16 hexadecimal " 191 "digits", name); 192 for (i = strlen("eui."); name[i] != '\0'; i++) { 193 if (!valid_hex(name[i])) { 194 warnx("invalid character \"%c\" in iSCSI " 195 "name \"%s\"; allowed characters are 1-9 " 196 "and A-F", name[i], name); 197 break; 198 } 199 } 200 } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 201 if (strlen(name) > strlen("naa.") + 32) 202 warnx("invalid iSCSI name \"%s\"; the \"naa.\" " 203 "should be followed by at most 32 hexadecimal " 204 "digits", name); 205 for (i = strlen("naa."); name[i] != '\0'; i++) { 206 if (!valid_hex(name[i])) { 207 warnx("invalid character \"%c\" in ISCSI " 208 "name \"%s\"; allowed characters are 1-9 " 209 "and A-F", name[i], name); 210 break; 211 } 212 } 213 } else { 214 warnx("invalid iSCSI name \"%s\"; should start with " 215 "either \".iqn\", \"eui.\", or \"naa.\"", 216 name); 217 } 218 return (true); 219 } 220 221 void 222 conf_verify(struct conf *conf) 223 { 224 struct target *targ; 225 226 TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 227 assert(targ->t_nickname != NULL); 228 if (targ->t_session_type == SESSION_TYPE_UNSPECIFIED) 229 targ->t_session_type = SESSION_TYPE_NORMAL; 230 if (targ->t_session_type == SESSION_TYPE_NORMAL && 231 targ->t_name == NULL) 232 errx(1, "missing TargetName for target \"%s\"", 233 targ->t_nickname); 234 if (targ->t_session_type == SESSION_TYPE_DISCOVERY && 235 targ->t_name != NULL) 236 errx(1, "cannot specify TargetName for discovery " 237 "sessions for target \"%s\"", targ->t_nickname); 238 if (targ->t_name != NULL) { 239 if (valid_iscsi_name(targ->t_name) == false) 240 errx(1, "invalid target name \"%s\"", 241 targ->t_name); 242 } 243 if (targ->t_protocol == PROTOCOL_UNSPECIFIED) 244 targ->t_protocol = PROTOCOL_ISCSI; 245 #ifndef ICL_KERNEL_PROXY 246 if (targ->t_protocol == PROTOCOL_ISER) 247 errx(1, "iSER support requires ICL_KERNEL_PROXY; " 248 "see iscsi(4) for details"); 249 #endif 250 if (targ->t_address == NULL) 251 errx(1, "missing TargetAddress for target \"%s\"", 252 targ->t_nickname); 253 if (targ->t_initiator_name == NULL) 254 targ->t_initiator_name = default_initiator_name(); 255 if (valid_iscsi_name(targ->t_initiator_name) == false) 256 errx(1, "invalid initiator name \"%s\"", 257 targ->t_initiator_name); 258 if (targ->t_header_digest == DIGEST_UNSPECIFIED) 259 targ->t_header_digest = DIGEST_NONE; 260 if (targ->t_data_digest == DIGEST_UNSPECIFIED) 261 targ->t_data_digest = DIGEST_NONE; 262 if (targ->t_auth_method == AUTH_METHOD_UNSPECIFIED) { 263 if (targ->t_user != NULL || targ->t_secret != NULL || 264 targ->t_mutual_user != NULL || 265 targ->t_mutual_secret != NULL) 266 targ->t_auth_method = 267 AUTH_METHOD_CHAP; 268 else 269 targ->t_auth_method = 270 AUTH_METHOD_NONE; 271 } 272 if (targ->t_auth_method == AUTH_METHOD_CHAP) { 273 if (targ->t_user == NULL) { 274 errx(1, "missing chapIName for target \"%s\"", 275 targ->t_nickname); 276 } 277 if (targ->t_secret == NULL) 278 errx(1, "missing chapSecret for target \"%s\"", 279 targ->t_nickname); 280 if (targ->t_mutual_user != NULL || 281 targ->t_mutual_secret != NULL) { 282 if (targ->t_mutual_user == NULL) 283 errx(1, "missing tgtChapName for " 284 "target \"%s\"", targ->t_nickname); 285 if (targ->t_mutual_secret == NULL) 286 errx(1, "missing tgtChapSecret for " 287 "target \"%s\"", targ->t_nickname); 288 } 289 } 290 } 291 } 292 293 static void 294 conf_from_target(struct iscsi_session_conf *conf, 295 const struct target *targ) 296 { 297 memset(conf, 0, sizeof(*conf)); 298 299 /* 300 * XXX: Check bounds and return error instead of silently truncating. 301 */ 302 if (targ->t_initiator_name != NULL) 303 strlcpy(conf->isc_initiator, targ->t_initiator_name, 304 sizeof(conf->isc_initiator)); 305 if (targ->t_initiator_address != NULL) 306 strlcpy(conf->isc_initiator_addr, targ->t_initiator_address, 307 sizeof(conf->isc_initiator_addr)); 308 if (targ->t_initiator_alias != NULL) 309 strlcpy(conf->isc_initiator_alias, targ->t_initiator_alias, 310 sizeof(conf->isc_initiator_alias)); 311 if (targ->t_name != NULL) 312 strlcpy(conf->isc_target, targ->t_name, 313 sizeof(conf->isc_target)); 314 if (targ->t_address != NULL) 315 strlcpy(conf->isc_target_addr, targ->t_address, 316 sizeof(conf->isc_target_addr)); 317 if (targ->t_user != NULL) 318 strlcpy(conf->isc_user, targ->t_user, 319 sizeof(conf->isc_user)); 320 if (targ->t_secret != NULL) 321 strlcpy(conf->isc_secret, targ->t_secret, 322 sizeof(conf->isc_secret)); 323 if (targ->t_mutual_user != NULL) 324 strlcpy(conf->isc_mutual_user, targ->t_mutual_user, 325 sizeof(conf->isc_mutual_user)); 326 if (targ->t_mutual_secret != NULL) 327 strlcpy(conf->isc_mutual_secret, targ->t_mutual_secret, 328 sizeof(conf->isc_mutual_secret)); 329 if (targ->t_session_type == SESSION_TYPE_DISCOVERY) 330 conf->isc_discovery = 1; 331 if (targ->t_protocol == PROTOCOL_ISER) 332 conf->isc_iser = 1; 333 if (targ->t_header_digest == DIGEST_CRC32C) 334 conf->isc_header_digest = ISCSI_DIGEST_CRC32C; 335 else 336 conf->isc_header_digest = ISCSI_DIGEST_NONE; 337 if (targ->t_data_digest == DIGEST_CRC32C) 338 conf->isc_data_digest = ISCSI_DIGEST_CRC32C; 339 else 340 conf->isc_data_digest = ISCSI_DIGEST_NONE; 341 } 342 343 static int 344 kernel_add(int iscsi_fd, const struct target *targ) 345 { 346 struct iscsi_session_add isa; 347 int error; 348 349 memset(&isa, 0, sizeof(isa)); 350 conf_from_target(&isa.isa_conf, targ); 351 error = ioctl(iscsi_fd, ISCSISADD, &isa); 352 if (error != 0) 353 warn("ISCSISADD"); 354 return (error); 355 } 356 357 static int 358 kernel_remove(int iscsi_fd, const struct target *targ) 359 { 360 struct iscsi_session_remove isr; 361 int error; 362 363 memset(&isr, 0, sizeof(isr)); 364 conf_from_target(&isr.isr_conf, targ); 365 error = ioctl(iscsi_fd, ISCSISREMOVE, &isr); 366 if (error != 0) 367 warn("ISCSISREMOVE"); 368 return (error); 369 } 370 371 /* 372 * XXX: Add filtering. 373 */ 374 static int 375 kernel_list(int iscsi_fd, const struct target *targ __unused, 376 int verbose) 377 { 378 struct iscsi_session_state *states = NULL; 379 const struct iscsi_session_state *state; 380 const struct iscsi_session_conf *conf; 381 struct iscsi_session_list isl; 382 unsigned int i, nentries = 1; 383 int error; 384 bool show_periphs; 385 386 for (;;) { 387 states = realloc(states, 388 nentries * sizeof(struct iscsi_session_state)); 389 if (states == NULL) 390 err(1, "realloc"); 391 392 memset(&isl, 0, sizeof(isl)); 393 isl.isl_nentries = nentries; 394 isl.isl_pstates = states; 395 396 error = ioctl(iscsi_fd, ISCSISLIST, &isl); 397 if (error != 0 && errno == EMSGSIZE) { 398 nentries *= 4; 399 continue; 400 } 401 break; 402 } 403 if (error != 0) { 404 warn("ISCSISLIST"); 405 return (error); 406 } 407 408 if (verbose != 0) { 409 for (i = 0; i < isl.isl_nentries; i++) { 410 state = &states[i]; 411 conf = &state->iss_conf; 412 413 printf("Session ID: %d\n", state->iss_id); 414 printf("Initiator name: %s\n", conf->isc_initiator); 415 printf("Initiator portal: %s\n", 416 conf->isc_initiator_addr); 417 printf("Initiator alias: %s\n", 418 conf->isc_initiator_alias); 419 printf("Target name: %s\n", conf->isc_target); 420 printf("Target portal: %s\n", 421 conf->isc_target_addr); 422 printf("Target alias: %s\n", 423 state->iss_target_alias); 424 printf("User: %s\n", conf->isc_user); 425 printf("Secret: %s\n", conf->isc_secret); 426 printf("Mutual user: %s\n", 427 conf->isc_mutual_user); 428 printf("Mutual secret : %s\n", 429 conf->isc_mutual_secret); 430 printf("Session type: %s\n", 431 conf->isc_discovery ? "Discovery" : "Normal"); 432 printf("Session state: %s\n", 433 state->iss_connected ? 434 "Connected" : "Disconnected"); 435 printf("Failure reason: %s\n", state->iss_reason); 436 printf("Header digest: %s\n", 437 state->iss_header_digest == ISCSI_DIGEST_CRC32C ? 438 "CRC32C" : "None"); 439 printf("Data digest: %s\n", 440 state->iss_data_digest == ISCSI_DIGEST_CRC32C ? 441 "CRC32C" : "None"); 442 printf("DataSegmentLen: %d\n", 443 state->iss_max_data_segment_length); 444 printf("ImmediateData: %s\n", 445 state->iss_immediate_data ? "Yes" : "No"); 446 printf("iSER (RDMA): %s\n", 447 conf->isc_iser ? "Yes" : "No"); 448 printf("Device nodes: "); 449 print_periphs(state->iss_id); 450 printf("\n\n"); 451 } 452 } else { 453 printf("%-36s %-16s %s\n", 454 "Target name", "Target portal", "State"); 455 for (i = 0; i < isl.isl_nentries; i++) { 456 state = &states[i]; 457 conf = &state->iss_conf; 458 show_periphs = false; 459 460 printf("%-36s %-16s ", 461 conf->isc_target, conf->isc_target_addr); 462 463 if (state->iss_reason[0] != '\0') { 464 printf("%s\n", state->iss_reason); 465 } else { 466 if (conf->isc_discovery) { 467 printf("Discovery\n"); 468 } else if (state->iss_connected) { 469 printf("Connected: "); 470 print_periphs(state->iss_id); 471 printf("\n"); 472 } else { 473 printf("Disconnected\n"); 474 } 475 } 476 } 477 } 478 479 return (0); 480 } 481 482 static void 483 usage(void) 484 { 485 486 fprintf(stderr, "usage: iscsictl -A -p portal -t target " 487 "[-u user -s secret]\n"); 488 fprintf(stderr, " iscsictl -A -d discovery-host " 489 "[-u user -s secret]\n"); 490 fprintf(stderr, " iscsictl -A -a [-c path]\n"); 491 fprintf(stderr, " iscsictl -A -n nickname [-c path]\n"); 492 fprintf(stderr, " iscsictl -R [-p portal] [-t target]\n"); 493 fprintf(stderr, " iscsictl -R -a\n"); 494 fprintf(stderr, " iscsictl -R -n nickname [-c path]\n"); 495 fprintf(stderr, " iscsictl -L [-v]\n"); 496 exit(1); 497 } 498 499 char * 500 checked_strdup(const char *s) 501 { 502 char *c; 503 504 c = strdup(s); 505 if (c == NULL) 506 err(1, "strdup"); 507 return (c); 508 } 509 510 int 511 main(int argc, char **argv) 512 { 513 int Aflag = 0, Rflag = 0, Lflag = 0, aflag = 0, vflag = 0; 514 const char *conf_path = DEFAULT_CONFIG_PATH; 515 char *nickname = NULL, *discovery_host = NULL, *host = NULL, 516 *target = NULL, *user = NULL, *secret = NULL; 517 int ch, error, iscsi_fd, retval, saved_errno; 518 int failed = 0; 519 struct conf *conf; 520 struct target *targ; 521 522 while ((ch = getopt(argc, argv, "ARLac:d:n:p:t:u:s:v")) != -1) { 523 switch (ch) { 524 case 'A': 525 Aflag = 1; 526 break; 527 case 'R': 528 Rflag = 1; 529 break; 530 case 'L': 531 Lflag = 1; 532 break; 533 case 'a': 534 aflag = 1; 535 break; 536 case 'c': 537 conf_path = optarg; 538 break; 539 case 'd': 540 discovery_host = optarg; 541 break; 542 case 'n': 543 nickname = optarg; 544 break; 545 case 'p': 546 host = optarg; 547 break; 548 case 't': 549 target = optarg; 550 break; 551 case 'u': 552 user = optarg; 553 break; 554 case 's': 555 secret = optarg; 556 break; 557 case 'v': 558 vflag = 1; 559 break; 560 case '?': 561 default: 562 usage(); 563 } 564 } 565 argc -= optind; 566 if (argc != 0) 567 usage(); 568 569 if (Aflag + Rflag + Lflag == 0) 570 Lflag = 1; 571 if (Aflag + Rflag + Lflag > 1) 572 errx(1, "at most one of -A, -R, or -L may be specified"); 573 574 /* 575 * Note that we ignore unneccessary/inapplicable "-c" flag; so that 576 * people can do something like "alias ISCSICTL="iscsictl -c path" 577 * in shell scripts. 578 */ 579 if (Aflag != 0) { 580 if (aflag != 0) { 581 if (host != NULL) 582 errx(1, "-a and -p and mutually exclusive"); 583 if (target != NULL) 584 errx(1, "-a and -t and mutually exclusive"); 585 if (user != NULL) 586 errx(1, "-a and -u and mutually exclusive"); 587 if (secret != NULL) 588 errx(1, "-a and -s and mutually exclusive"); 589 if (nickname != NULL) 590 errx(1, "-a and -n and mutually exclusive"); 591 if (discovery_host != NULL) 592 errx(1, "-a and -d and mutually exclusive"); 593 } else if (nickname != NULL) { 594 if (host != NULL) 595 errx(1, "-n and -p and mutually exclusive"); 596 if (target != NULL) 597 errx(1, "-n and -t and mutually exclusive"); 598 if (user != NULL) 599 errx(1, "-n and -u and mutually exclusive"); 600 if (secret != NULL) 601 errx(1, "-n and -s and mutually exclusive"); 602 if (discovery_host != NULL) 603 errx(1, "-n and -d and mutually exclusive"); 604 } else if (discovery_host != NULL) { 605 if (host != NULL) 606 errx(1, "-d and -p and mutually exclusive"); 607 if (target != NULL) 608 errx(1, "-d and -t and mutually exclusive"); 609 } else { 610 if (target == NULL && host == NULL) 611 errx(1, "must specify -a, -n or -t/-p"); 612 613 if (target != NULL && host == NULL) 614 errx(1, "-t must always be used with -p"); 615 if (host != NULL && target == NULL) 616 errx(1, "-p must always be used with -t"); 617 } 618 619 if (user != NULL && secret == NULL) 620 errx(1, "-u must always be used with -s"); 621 if (secret != NULL && user == NULL) 622 errx(1, "-s must always be used with -u"); 623 624 if (vflag != 0) 625 errx(1, "-v cannot be used with -A"); 626 627 } else if (Rflag != 0) { 628 if (user != NULL) 629 errx(1, "-R and -u are mutually exclusive"); 630 if (secret != NULL) 631 errx(1, "-R and -s are mutually exclusive"); 632 if (discovery_host != NULL) 633 errx(1, "-R and -d are mutually exclusive"); 634 635 if (aflag != 0) { 636 if (host != NULL) 637 errx(1, "-a and -p and mutually exclusive"); 638 if (target != NULL) 639 errx(1, "-a and -t and mutually exclusive"); 640 if (nickname != NULL) 641 errx(1, "-a and -n and mutually exclusive"); 642 } else if (nickname != NULL) { 643 if (host != NULL) 644 errx(1, "-n and -p and mutually exclusive"); 645 if (target != NULL) 646 errx(1, "-n and -t and mutually exclusive"); 647 } else if (host != NULL) { 648 if (target != NULL) 649 errx(1, "-p and -t and mutually exclusive"); 650 } else if (target != NULL) { 651 if (host != NULL) 652 errx(1, "-t and -p and mutually exclusive"); 653 } else 654 errx(1, "must specify either -a, -n, -t, or -p"); 655 656 if (vflag != 0) 657 errx(1, "-v cannot be used with -R"); 658 659 } else { 660 assert(Lflag != 0); 661 662 if (host != NULL) 663 errx(1, "-L and -p and mutually exclusive"); 664 if (target != NULL) 665 errx(1, "-L and -t and mutually exclusive"); 666 if (user != NULL) 667 errx(1, "-L and -u and mutually exclusive"); 668 if (secret != NULL) 669 errx(1, "-L and -s and mutually exclusive"); 670 if (nickname != NULL) 671 errx(1, "-L and -n and mutually exclusive"); 672 if (discovery_host != NULL) 673 errx(1, "-L and -d and mutually exclusive"); 674 } 675 676 iscsi_fd = open(ISCSI_PATH, O_RDWR); 677 if (iscsi_fd < 0 && errno == ENOENT) { 678 saved_errno = errno; 679 retval = kldload("iscsi"); 680 if (retval != -1) 681 iscsi_fd = open(ISCSI_PATH, O_RDWR); 682 else 683 errno = saved_errno; 684 } 685 if (iscsi_fd < 0) 686 err(1, "failed to open %s", ISCSI_PATH); 687 688 if (Aflag != 0 && aflag != 0) { 689 conf = conf_new_from_file(conf_path); 690 691 TAILQ_FOREACH(targ, &conf->conf_targets, t_next) 692 failed += kernel_add(iscsi_fd, targ); 693 } else if (nickname != NULL) { 694 conf = conf_new_from_file(conf_path); 695 targ = target_find(conf, nickname); 696 if (targ == NULL) 697 errx(1, "target %s not found in the configuration file", 698 nickname); 699 700 if (Aflag != 0) 701 failed += kernel_add(iscsi_fd, targ); 702 else if (Rflag != 0) 703 failed += kernel_remove(iscsi_fd, targ); 704 else 705 failed += kernel_list(iscsi_fd, targ, vflag); 706 } else { 707 if (Aflag != 0 && target != NULL) { 708 if (valid_iscsi_name(target) == false) 709 errx(1, "invalid target name \"%s\"", target); 710 } 711 conf = conf_new(); 712 targ = target_new(conf); 713 targ->t_initiator_name = default_initiator_name(); 714 targ->t_header_digest = DIGEST_NONE; 715 targ->t_data_digest = DIGEST_NONE; 716 targ->t_name = target; 717 if (discovery_host != NULL) { 718 targ->t_session_type = SESSION_TYPE_DISCOVERY; 719 targ->t_address = discovery_host; 720 } else { 721 targ->t_session_type = SESSION_TYPE_NORMAL; 722 targ->t_address = host; 723 } 724 targ->t_user = user; 725 targ->t_secret = secret; 726 727 if (Aflag != 0) 728 failed += kernel_add(iscsi_fd, targ); 729 else if (Rflag != 0) 730 failed += kernel_remove(iscsi_fd, targ); 731 else 732 failed += kernel_list(iscsi_fd, targ, vflag); 733 } 734 735 error = close(iscsi_fd); 736 if (error != 0) 737 err(1, "close"); 738 739 if (failed > 0) 740 return (1); 741 return (0); 742 } 743