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 385 for (;;) { 386 states = realloc(states, 387 nentries * sizeof(struct iscsi_session_state)); 388 if (states == NULL) 389 err(1, "realloc"); 390 391 memset(&isl, 0, sizeof(isl)); 392 isl.isl_nentries = nentries; 393 isl.isl_pstates = states; 394 395 error = ioctl(iscsi_fd, ISCSISLIST, &isl); 396 if (error != 0 && errno == EMSGSIZE) { 397 nentries *= 4; 398 continue; 399 } 400 break; 401 } 402 if (error != 0) { 403 warn("ISCSISLIST"); 404 return (error); 405 } 406 407 if (verbose != 0) { 408 for (i = 0; i < isl.isl_nentries; i++) { 409 state = &states[i]; 410 conf = &state->iss_conf; 411 412 printf("Session ID: %d\n", state->iss_id); 413 printf("Initiator name: %s\n", conf->isc_initiator); 414 printf("Initiator portal: %s\n", 415 conf->isc_initiator_addr); 416 printf("Initiator alias: %s\n", 417 conf->isc_initiator_alias); 418 printf("Target name: %s\n", conf->isc_target); 419 printf("Target portal: %s\n", 420 conf->isc_target_addr); 421 printf("Target alias: %s\n", 422 state->iss_target_alias); 423 printf("User: %s\n", conf->isc_user); 424 printf("Secret: %s\n", conf->isc_secret); 425 printf("Mutual user: %s\n", 426 conf->isc_mutual_user); 427 printf("Mutual secret: %s\n", 428 conf->isc_mutual_secret); 429 printf("Session type: %s\n", 430 conf->isc_discovery ? "Discovery" : "Normal"); 431 printf("Session state: %s\n", 432 state->iss_connected ? 433 "Connected" : "Disconnected"); 434 printf("Failure reason: %s\n", state->iss_reason); 435 printf("Header digest: %s\n", 436 state->iss_header_digest == ISCSI_DIGEST_CRC32C ? 437 "CRC32C" : "None"); 438 printf("Data digest: %s\n", 439 state->iss_data_digest == ISCSI_DIGEST_CRC32C ? 440 "CRC32C" : "None"); 441 printf("DataSegmentLen: %d\n", 442 state->iss_max_data_segment_length); 443 printf("ImmediateData: %s\n", 444 state->iss_immediate_data ? "Yes" : "No"); 445 printf("iSER (RDMA): %s\n", 446 conf->isc_iser ? "Yes" : "No"); 447 printf("Device nodes: "); 448 print_periphs(state->iss_id); 449 printf("\n\n"); 450 } 451 } else { 452 printf("%-36s %-16s %s\n", 453 "Target name", "Target portal", "State"); 454 for (i = 0; i < isl.isl_nentries; i++) { 455 state = &states[i]; 456 conf = &state->iss_conf; 457 458 printf("%-36s %-16s ", 459 conf->isc_target, conf->isc_target_addr); 460 461 if (state->iss_reason[0] != '\0') { 462 printf("%s\n", state->iss_reason); 463 } else { 464 if (conf->isc_discovery) { 465 printf("Discovery\n"); 466 } else if (state->iss_connected) { 467 printf("Connected: "); 468 print_periphs(state->iss_id); 469 printf("\n"); 470 } else { 471 printf("Disconnected\n"); 472 } 473 } 474 } 475 } 476 477 return (0); 478 } 479 480 static void 481 usage(void) 482 { 483 484 fprintf(stderr, "usage: iscsictl -A -p portal -t target " 485 "[-u user -s secret]\n"); 486 fprintf(stderr, " iscsictl -A -d discovery-host " 487 "[-u user -s secret]\n"); 488 fprintf(stderr, " iscsictl -A -a [-c path]\n"); 489 fprintf(stderr, " iscsictl -A -n nickname [-c path]\n"); 490 fprintf(stderr, " iscsictl -R [-p portal] [-t target]\n"); 491 fprintf(stderr, " iscsictl -R -a\n"); 492 fprintf(stderr, " iscsictl -R -n nickname [-c path]\n"); 493 fprintf(stderr, " iscsictl -L [-v]\n"); 494 exit(1); 495 } 496 497 char * 498 checked_strdup(const char *s) 499 { 500 char *c; 501 502 c = strdup(s); 503 if (c == NULL) 504 err(1, "strdup"); 505 return (c); 506 } 507 508 int 509 main(int argc, char **argv) 510 { 511 int Aflag = 0, Rflag = 0, Lflag = 0, aflag = 0, vflag = 0; 512 const char *conf_path = DEFAULT_CONFIG_PATH; 513 char *nickname = NULL, *discovery_host = NULL, *host = NULL, 514 *target = NULL, *user = NULL, *secret = NULL; 515 int ch, error, iscsi_fd, retval, saved_errno; 516 int failed = 0; 517 struct conf *conf; 518 struct target *targ; 519 520 while ((ch = getopt(argc, argv, "ARLac:d:n:p:t:u:s:v")) != -1) { 521 switch (ch) { 522 case 'A': 523 Aflag = 1; 524 break; 525 case 'R': 526 Rflag = 1; 527 break; 528 case 'L': 529 Lflag = 1; 530 break; 531 case 'a': 532 aflag = 1; 533 break; 534 case 'c': 535 conf_path = optarg; 536 break; 537 case 'd': 538 discovery_host = optarg; 539 break; 540 case 'n': 541 nickname = optarg; 542 break; 543 case 'p': 544 host = optarg; 545 break; 546 case 't': 547 target = optarg; 548 break; 549 case 'u': 550 user = optarg; 551 break; 552 case 's': 553 secret = optarg; 554 break; 555 case 'v': 556 vflag = 1; 557 break; 558 case '?': 559 default: 560 usage(); 561 } 562 } 563 argc -= optind; 564 if (argc != 0) 565 usage(); 566 567 if (Aflag + Rflag + Lflag == 0) 568 Lflag = 1; 569 if (Aflag + Rflag + Lflag > 1) 570 errx(1, "at most one of -A, -R, or -L may be specified"); 571 572 /* 573 * Note that we ignore unneccessary/inapplicable "-c" flag; so that 574 * people can do something like "alias ISCSICTL="iscsictl -c path" 575 * in shell scripts. 576 */ 577 if (Aflag != 0) { 578 if (aflag != 0) { 579 if (host != NULL) 580 errx(1, "-a and -p and mutually exclusive"); 581 if (target != NULL) 582 errx(1, "-a and -t and mutually exclusive"); 583 if (user != NULL) 584 errx(1, "-a and -u and mutually exclusive"); 585 if (secret != NULL) 586 errx(1, "-a and -s and mutually exclusive"); 587 if (nickname != NULL) 588 errx(1, "-a and -n and mutually exclusive"); 589 if (discovery_host != NULL) 590 errx(1, "-a and -d and mutually exclusive"); 591 } else if (nickname != NULL) { 592 if (host != NULL) 593 errx(1, "-n and -p and mutually exclusive"); 594 if (target != NULL) 595 errx(1, "-n and -t and mutually exclusive"); 596 if (user != NULL) 597 errx(1, "-n and -u and mutually exclusive"); 598 if (secret != NULL) 599 errx(1, "-n and -s and mutually exclusive"); 600 if (discovery_host != NULL) 601 errx(1, "-n and -d and mutually exclusive"); 602 } else if (discovery_host != NULL) { 603 if (host != NULL) 604 errx(1, "-d and -p and mutually exclusive"); 605 if (target != NULL) 606 errx(1, "-d and -t and mutually exclusive"); 607 } else { 608 if (target == NULL && host == NULL) 609 errx(1, "must specify -a, -n or -t/-p"); 610 611 if (target != NULL && host == NULL) 612 errx(1, "-t must always be used with -p"); 613 if (host != NULL && target == NULL) 614 errx(1, "-p must always be used with -t"); 615 } 616 617 if (user != NULL && secret == NULL) 618 errx(1, "-u must always be used with -s"); 619 if (secret != NULL && user == NULL) 620 errx(1, "-s must always be used with -u"); 621 622 if (vflag != 0) 623 errx(1, "-v cannot be used with -A"); 624 625 } else if (Rflag != 0) { 626 if (user != NULL) 627 errx(1, "-R and -u are mutually exclusive"); 628 if (secret != NULL) 629 errx(1, "-R and -s are mutually exclusive"); 630 if (discovery_host != NULL) 631 errx(1, "-R and -d are mutually exclusive"); 632 633 if (aflag != 0) { 634 if (host != NULL) 635 errx(1, "-a and -p and mutually exclusive"); 636 if (target != NULL) 637 errx(1, "-a and -t and mutually exclusive"); 638 if (nickname != NULL) 639 errx(1, "-a and -n and mutually exclusive"); 640 } else if (nickname != NULL) { 641 if (host != NULL) 642 errx(1, "-n and -p and mutually exclusive"); 643 if (target != NULL) 644 errx(1, "-n and -t and mutually exclusive"); 645 } else if (host != NULL) { 646 if (target != NULL) 647 errx(1, "-p and -t and mutually exclusive"); 648 } else if (target != NULL) { 649 if (host != NULL) 650 errx(1, "-t and -p and mutually exclusive"); 651 } else 652 errx(1, "must specify either -a, -n, -t, or -p"); 653 654 if (vflag != 0) 655 errx(1, "-v cannot be used with -R"); 656 657 } else { 658 assert(Lflag != 0); 659 660 if (host != NULL) 661 errx(1, "-L and -p and mutually exclusive"); 662 if (target != NULL) 663 errx(1, "-L and -t and mutually exclusive"); 664 if (user != NULL) 665 errx(1, "-L and -u and mutually exclusive"); 666 if (secret != NULL) 667 errx(1, "-L and -s and mutually exclusive"); 668 if (nickname != NULL) 669 errx(1, "-L and -n and mutually exclusive"); 670 if (discovery_host != NULL) 671 errx(1, "-L and -d and mutually exclusive"); 672 } 673 674 iscsi_fd = open(ISCSI_PATH, O_RDWR); 675 if (iscsi_fd < 0 && errno == ENOENT) { 676 saved_errno = errno; 677 retval = kldload("iscsi"); 678 if (retval != -1) 679 iscsi_fd = open(ISCSI_PATH, O_RDWR); 680 else 681 errno = saved_errno; 682 } 683 if (iscsi_fd < 0) 684 err(1, "failed to open %s", ISCSI_PATH); 685 686 if (Aflag != 0 && aflag != 0) { 687 conf = conf_new_from_file(conf_path); 688 689 TAILQ_FOREACH(targ, &conf->conf_targets, t_next) 690 failed += kernel_add(iscsi_fd, targ); 691 } else if (nickname != NULL) { 692 conf = conf_new_from_file(conf_path); 693 targ = target_find(conf, nickname); 694 if (targ == NULL) 695 errx(1, "target %s not found in the configuration file", 696 nickname); 697 698 if (Aflag != 0) 699 failed += kernel_add(iscsi_fd, targ); 700 else if (Rflag != 0) 701 failed += kernel_remove(iscsi_fd, targ); 702 else 703 failed += kernel_list(iscsi_fd, targ, vflag); 704 } else { 705 if (Aflag != 0 && target != NULL) { 706 if (valid_iscsi_name(target) == false) 707 errx(1, "invalid target name \"%s\"", target); 708 } 709 conf = conf_new(); 710 targ = target_new(conf); 711 targ->t_initiator_name = default_initiator_name(); 712 targ->t_header_digest = DIGEST_NONE; 713 targ->t_data_digest = DIGEST_NONE; 714 targ->t_name = target; 715 if (discovery_host != NULL) { 716 targ->t_session_type = SESSION_TYPE_DISCOVERY; 717 targ->t_address = discovery_host; 718 } else { 719 targ->t_session_type = SESSION_TYPE_NORMAL; 720 targ->t_address = host; 721 } 722 targ->t_user = user; 723 targ->t_secret = secret; 724 725 if (Aflag != 0) 726 failed += kernel_add(iscsi_fd, targ); 727 else if (Rflag != 0) 728 failed += kernel_remove(iscsi_fd, targ); 729 else 730 failed += kernel_list(iscsi_fd, targ, vflag); 731 } 732 733 error = close(iscsi_fd); 734 if (error != 0) 735 err(1, "close"); 736 737 if (failed > 0) 738 return (1); 739 return (0); 740 } 741