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 if (targ->t_address == NULL) 246 errx(1, "missing TargetAddress for target \"%s\"", 247 targ->t_nickname); 248 if (targ->t_initiator_name == NULL) 249 targ->t_initiator_name = default_initiator_name(); 250 if (valid_iscsi_name(targ->t_initiator_name) == false) 251 errx(1, "invalid initiator name \"%s\"", 252 targ->t_initiator_name); 253 if (targ->t_header_digest == DIGEST_UNSPECIFIED) 254 targ->t_header_digest = DIGEST_NONE; 255 if (targ->t_data_digest == DIGEST_UNSPECIFIED) 256 targ->t_data_digest = DIGEST_NONE; 257 if (targ->t_auth_method == AUTH_METHOD_UNSPECIFIED) { 258 if (targ->t_user != NULL || targ->t_secret != NULL || 259 targ->t_mutual_user != NULL || 260 targ->t_mutual_secret != NULL) 261 targ->t_auth_method = 262 AUTH_METHOD_CHAP; 263 else 264 targ->t_auth_method = 265 AUTH_METHOD_NONE; 266 } 267 if (targ->t_auth_method == AUTH_METHOD_CHAP) { 268 if (targ->t_user == NULL) { 269 errx(1, "missing chapIName for target \"%s\"", 270 targ->t_nickname); 271 } 272 if (targ->t_secret == NULL) 273 errx(1, "missing chapSecret for target \"%s\"", 274 targ->t_nickname); 275 if (targ->t_mutual_user != NULL || 276 targ->t_mutual_secret != NULL) { 277 if (targ->t_mutual_user == NULL) 278 errx(1, "missing tgtChapName for " 279 "target \"%s\"", targ->t_nickname); 280 if (targ->t_mutual_secret == NULL) 281 errx(1, "missing tgtChapSecret for " 282 "target \"%s\"", targ->t_nickname); 283 } 284 } 285 } 286 } 287 288 static void 289 conf_from_target(struct iscsi_session_conf *conf, 290 const struct target *targ) 291 { 292 memset(conf, 0, sizeof(*conf)); 293 294 /* 295 * XXX: Check bounds and return error instead of silently truncating. 296 */ 297 if (targ->t_initiator_name != NULL) 298 strlcpy(conf->isc_initiator, targ->t_initiator_name, 299 sizeof(conf->isc_initiator)); 300 if (targ->t_initiator_address != NULL) 301 strlcpy(conf->isc_initiator_addr, targ->t_initiator_address, 302 sizeof(conf->isc_initiator_addr)); 303 if (targ->t_initiator_alias != NULL) 304 strlcpy(conf->isc_initiator_alias, targ->t_initiator_alias, 305 sizeof(conf->isc_initiator_alias)); 306 if (targ->t_name != NULL) 307 strlcpy(conf->isc_target, targ->t_name, 308 sizeof(conf->isc_target)); 309 if (targ->t_address != NULL) 310 strlcpy(conf->isc_target_addr, targ->t_address, 311 sizeof(conf->isc_target_addr)); 312 if (targ->t_user != NULL) 313 strlcpy(conf->isc_user, targ->t_user, 314 sizeof(conf->isc_user)); 315 if (targ->t_secret != NULL) 316 strlcpy(conf->isc_secret, targ->t_secret, 317 sizeof(conf->isc_secret)); 318 if (targ->t_mutual_user != NULL) 319 strlcpy(conf->isc_mutual_user, targ->t_mutual_user, 320 sizeof(conf->isc_mutual_user)); 321 if (targ->t_mutual_secret != NULL) 322 strlcpy(conf->isc_mutual_secret, targ->t_mutual_secret, 323 sizeof(conf->isc_mutual_secret)); 324 if (targ->t_session_type == SESSION_TYPE_DISCOVERY) 325 conf->isc_discovery = 1; 326 if (targ->t_protocol == PROTOCOL_ISER) 327 conf->isc_iser = 1; 328 if (targ->t_header_digest == DIGEST_CRC32C) 329 conf->isc_header_digest = ISCSI_DIGEST_CRC32C; 330 else 331 conf->isc_header_digest = ISCSI_DIGEST_NONE; 332 if (targ->t_data_digest == DIGEST_CRC32C) 333 conf->isc_data_digest = ISCSI_DIGEST_CRC32C; 334 else 335 conf->isc_data_digest = ISCSI_DIGEST_NONE; 336 } 337 338 static int 339 kernel_add(int iscsi_fd, const struct target *targ) 340 { 341 struct iscsi_session_add isa; 342 int error; 343 344 memset(&isa, 0, sizeof(isa)); 345 conf_from_target(&isa.isa_conf, targ); 346 error = ioctl(iscsi_fd, ISCSISADD, &isa); 347 if (error != 0) 348 warn("ISCSISADD"); 349 return (error); 350 } 351 352 static int 353 kernel_remove(int iscsi_fd, const struct target *targ) 354 { 355 struct iscsi_session_remove isr; 356 int error; 357 358 memset(&isr, 0, sizeof(isr)); 359 conf_from_target(&isr.isr_conf, targ); 360 error = ioctl(iscsi_fd, ISCSISREMOVE, &isr); 361 if (error != 0) 362 warn("ISCSISREMOVE"); 363 return (error); 364 } 365 366 /* 367 * XXX: Add filtering. 368 */ 369 static int 370 kernel_list(int iscsi_fd, const struct target *targ __unused, 371 int verbose) 372 { 373 struct iscsi_session_state *states = NULL; 374 const struct iscsi_session_state *state; 375 const struct iscsi_session_conf *conf; 376 struct iscsi_session_list isl; 377 unsigned int i, nentries = 1; 378 int error; 379 380 for (;;) { 381 states = realloc(states, 382 nentries * sizeof(struct iscsi_session_state)); 383 if (states == NULL) 384 err(1, "realloc"); 385 386 memset(&isl, 0, sizeof(isl)); 387 isl.isl_nentries = nentries; 388 isl.isl_pstates = states; 389 390 error = ioctl(iscsi_fd, ISCSISLIST, &isl); 391 if (error != 0 && errno == EMSGSIZE) { 392 nentries *= 4; 393 continue; 394 } 395 break; 396 } 397 if (error != 0) { 398 warn("ISCSISLIST"); 399 return (error); 400 } 401 402 if (verbose != 0) { 403 for (i = 0; i < isl.isl_nentries; i++) { 404 state = &states[i]; 405 conf = &state->iss_conf; 406 407 printf("Session ID: %d\n", state->iss_id); 408 printf("Initiator name: %s\n", conf->isc_initiator); 409 printf("Initiator portal: %s\n", 410 conf->isc_initiator_addr); 411 printf("Initiator alias: %s\n", 412 conf->isc_initiator_alias); 413 printf("Target name: %s\n", conf->isc_target); 414 printf("Target portal: %s\n", 415 conf->isc_target_addr); 416 printf("Target alias: %s\n", 417 state->iss_target_alias); 418 printf("User: %s\n", conf->isc_user); 419 printf("Secret: %s\n", conf->isc_secret); 420 printf("Mutual user: %s\n", 421 conf->isc_mutual_user); 422 printf("Mutual secret: %s\n", 423 conf->isc_mutual_secret); 424 printf("Session type: %s\n", 425 conf->isc_discovery ? "Discovery" : "Normal"); 426 printf("Session state: %s\n", 427 state->iss_connected ? 428 "Connected" : "Disconnected"); 429 printf("Failure reason: %s\n", state->iss_reason); 430 printf("Header digest: %s\n", 431 state->iss_header_digest == ISCSI_DIGEST_CRC32C ? 432 "CRC32C" : "None"); 433 printf("Data digest: %s\n", 434 state->iss_data_digest == ISCSI_DIGEST_CRC32C ? 435 "CRC32C" : "None"); 436 printf("DataSegmentLen: %d\n", 437 state->iss_max_data_segment_length); 438 printf("ImmediateData: %s\n", 439 state->iss_immediate_data ? "Yes" : "No"); 440 printf("iSER (RDMA): %s\n", 441 conf->isc_iser ? "Yes" : "No"); 442 printf("Device nodes: "); 443 print_periphs(state->iss_id); 444 printf("\n\n"); 445 } 446 } else { 447 printf("%-36s %-16s %s\n", 448 "Target name", "Target portal", "State"); 449 for (i = 0; i < isl.isl_nentries; i++) { 450 state = &states[i]; 451 conf = &state->iss_conf; 452 453 printf("%-36s %-16s ", 454 conf->isc_target, conf->isc_target_addr); 455 456 if (state->iss_reason[0] != '\0') { 457 printf("%s\n", state->iss_reason); 458 } else { 459 if (conf->isc_discovery) { 460 printf("Discovery\n"); 461 } else if (state->iss_connected) { 462 printf("Connected: "); 463 print_periphs(state->iss_id); 464 printf("\n"); 465 } else { 466 printf("Disconnected\n"); 467 } 468 } 469 } 470 } 471 472 return (0); 473 } 474 475 static void 476 usage(void) 477 { 478 479 fprintf(stderr, "usage: iscsictl -A -p portal -t target " 480 "[-u user -s secret]\n"); 481 fprintf(stderr, " iscsictl -A -d discovery-host " 482 "[-u user -s secret]\n"); 483 fprintf(stderr, " iscsictl -A -a [-c path]\n"); 484 fprintf(stderr, " iscsictl -A -n nickname [-c path]\n"); 485 fprintf(stderr, " iscsictl -R [-p portal] [-t target]\n"); 486 fprintf(stderr, " iscsictl -R -a\n"); 487 fprintf(stderr, " iscsictl -R -n nickname [-c path]\n"); 488 fprintf(stderr, " iscsictl -L [-v]\n"); 489 exit(1); 490 } 491 492 char * 493 checked_strdup(const char *s) 494 { 495 char *c; 496 497 c = strdup(s); 498 if (c == NULL) 499 err(1, "strdup"); 500 return (c); 501 } 502 503 int 504 main(int argc, char **argv) 505 { 506 int Aflag = 0, Rflag = 0, Lflag = 0, aflag = 0, vflag = 0; 507 const char *conf_path = DEFAULT_CONFIG_PATH; 508 char *nickname = NULL, *discovery_host = NULL, *host = NULL, 509 *target = NULL, *user = NULL, *secret = NULL; 510 int ch, error, iscsi_fd, retval, saved_errno; 511 int failed = 0; 512 struct conf *conf; 513 struct target *targ; 514 515 while ((ch = getopt(argc, argv, "ARLac:d:n:p:t:u:s:v")) != -1) { 516 switch (ch) { 517 case 'A': 518 Aflag = 1; 519 break; 520 case 'R': 521 Rflag = 1; 522 break; 523 case 'L': 524 Lflag = 1; 525 break; 526 case 'a': 527 aflag = 1; 528 break; 529 case 'c': 530 conf_path = optarg; 531 break; 532 case 'd': 533 discovery_host = optarg; 534 break; 535 case 'n': 536 nickname = optarg; 537 break; 538 case 'p': 539 host = optarg; 540 break; 541 case 't': 542 target = optarg; 543 break; 544 case 'u': 545 user = optarg; 546 break; 547 case 's': 548 secret = optarg; 549 break; 550 case 'v': 551 vflag = 1; 552 break; 553 case '?': 554 default: 555 usage(); 556 } 557 } 558 argc -= optind; 559 if (argc != 0) 560 usage(); 561 562 if (Aflag + Rflag + Lflag == 0) 563 Lflag = 1; 564 if (Aflag + Rflag + Lflag > 1) 565 errx(1, "at most one of -A, -R, or -L may be specified"); 566 567 /* 568 * Note that we ignore unneccessary/inapplicable "-c" flag; so that 569 * people can do something like "alias ISCSICTL="iscsictl -c path" 570 * in shell scripts. 571 */ 572 if (Aflag != 0) { 573 if (aflag != 0) { 574 if (host != NULL) 575 errx(1, "-a and -p and mutually exclusive"); 576 if (target != NULL) 577 errx(1, "-a and -t and mutually exclusive"); 578 if (user != NULL) 579 errx(1, "-a and -u and mutually exclusive"); 580 if (secret != NULL) 581 errx(1, "-a and -s and mutually exclusive"); 582 if (nickname != NULL) 583 errx(1, "-a and -n and mutually exclusive"); 584 if (discovery_host != NULL) 585 errx(1, "-a and -d and mutually exclusive"); 586 } else if (nickname != NULL) { 587 if (host != NULL) 588 errx(1, "-n and -p and mutually exclusive"); 589 if (target != NULL) 590 errx(1, "-n and -t and mutually exclusive"); 591 if (user != NULL) 592 errx(1, "-n and -u and mutually exclusive"); 593 if (secret != NULL) 594 errx(1, "-n and -s and mutually exclusive"); 595 if (discovery_host != NULL) 596 errx(1, "-n and -d and mutually exclusive"); 597 } else if (discovery_host != NULL) { 598 if (host != NULL) 599 errx(1, "-d and -p and mutually exclusive"); 600 if (target != NULL) 601 errx(1, "-d and -t and mutually exclusive"); 602 } else { 603 if (target == NULL && host == NULL) 604 errx(1, "must specify -a, -n or -t/-p"); 605 606 if (target != NULL && host == NULL) 607 errx(1, "-t must always be used with -p"); 608 if (host != NULL && target == NULL) 609 errx(1, "-p must always be used with -t"); 610 } 611 612 if (user != NULL && secret == NULL) 613 errx(1, "-u must always be used with -s"); 614 if (secret != NULL && user == NULL) 615 errx(1, "-s must always be used with -u"); 616 617 if (vflag != 0) 618 errx(1, "-v cannot be used with -A"); 619 620 } else if (Rflag != 0) { 621 if (user != NULL) 622 errx(1, "-R and -u are mutually exclusive"); 623 if (secret != NULL) 624 errx(1, "-R and -s are mutually exclusive"); 625 if (discovery_host != NULL) 626 errx(1, "-R and -d are mutually exclusive"); 627 628 if (aflag != 0) { 629 if (host != NULL) 630 errx(1, "-a and -p and mutually exclusive"); 631 if (target != NULL) 632 errx(1, "-a and -t and mutually exclusive"); 633 if (nickname != NULL) 634 errx(1, "-a and -n and mutually exclusive"); 635 } else if (nickname != NULL) { 636 if (host != NULL) 637 errx(1, "-n and -p and mutually exclusive"); 638 if (target != NULL) 639 errx(1, "-n and -t and mutually exclusive"); 640 } else if (host != NULL) { 641 if (target != NULL) 642 errx(1, "-p and -t and mutually exclusive"); 643 } else if (target != NULL) { 644 if (host != NULL) 645 errx(1, "-t and -p and mutually exclusive"); 646 } else 647 errx(1, "must specify either -a, -n, -t, or -p"); 648 649 if (vflag != 0) 650 errx(1, "-v cannot be used with -R"); 651 652 } else { 653 assert(Lflag != 0); 654 655 if (host != NULL) 656 errx(1, "-L and -p and mutually exclusive"); 657 if (target != NULL) 658 errx(1, "-L and -t and mutually exclusive"); 659 if (user != NULL) 660 errx(1, "-L and -u and mutually exclusive"); 661 if (secret != NULL) 662 errx(1, "-L and -s and mutually exclusive"); 663 if (nickname != NULL) 664 errx(1, "-L and -n and mutually exclusive"); 665 if (discovery_host != NULL) 666 errx(1, "-L and -d and mutually exclusive"); 667 } 668 669 iscsi_fd = open(ISCSI_PATH, O_RDWR); 670 if (iscsi_fd < 0 && errno == ENOENT) { 671 saved_errno = errno; 672 retval = kldload("iscsi"); 673 if (retval != -1) 674 iscsi_fd = open(ISCSI_PATH, O_RDWR); 675 else 676 errno = saved_errno; 677 } 678 if (iscsi_fd < 0) 679 err(1, "failed to open %s", ISCSI_PATH); 680 681 if (Aflag != 0 && aflag != 0) { 682 conf = conf_new_from_file(conf_path); 683 684 TAILQ_FOREACH(targ, &conf->conf_targets, t_next) 685 failed += kernel_add(iscsi_fd, targ); 686 } else if (nickname != NULL) { 687 conf = conf_new_from_file(conf_path); 688 targ = target_find(conf, nickname); 689 if (targ == NULL) 690 errx(1, "target %s not found in the configuration file", 691 nickname); 692 693 if (Aflag != 0) 694 failed += kernel_add(iscsi_fd, targ); 695 else if (Rflag != 0) 696 failed += kernel_remove(iscsi_fd, targ); 697 else 698 failed += kernel_list(iscsi_fd, targ, vflag); 699 } else { 700 if (Aflag != 0 && target != NULL) { 701 if (valid_iscsi_name(target) == false) 702 errx(1, "invalid target name \"%s\"", target); 703 } 704 conf = conf_new(); 705 targ = target_new(conf); 706 targ->t_initiator_name = default_initiator_name(); 707 targ->t_header_digest = DIGEST_NONE; 708 targ->t_data_digest = DIGEST_NONE; 709 targ->t_name = target; 710 if (discovery_host != NULL) { 711 targ->t_session_type = SESSION_TYPE_DISCOVERY; 712 targ->t_address = discovery_host; 713 } else { 714 targ->t_session_type = SESSION_TYPE_NORMAL; 715 targ->t_address = host; 716 } 717 targ->t_user = user; 718 targ->t_secret = secret; 719 720 if (Aflag != 0) 721 failed += kernel_add(iscsi_fd, targ); 722 else if (Rflag != 0) 723 failed += kernel_remove(iscsi_fd, targ); 724 else 725 failed += kernel_list(iscsi_fd, targ, vflag); 726 } 727 728 error = close(iscsi_fd); 729 if (error != 0) 730 err(1, "close"); 731 732 if (failed > 0) 733 return (1); 734 return (0); 735 } 736