4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 #include <sys/types.h>
37 #include <libnvpair.h>
41 #include <auth_attr.h>
48 #include <libiscsit.h>
50 /* what's this used for?? */
51 #define ITADM_VERSION "1.0"
53 /* SMF service info */
54 #define ISCSIT_SVC "svc:/network/iscsi/target:default"
56 #define STMF_STALE(ret) {\
57 if (ret == STMF_ERROR_PROV_DATA_STALE) {\
58 output_config_error(ret, NULL);\
59 } else if (ret != 0) {\
60 output_config_error(ret,\
61 gettext("Configuration change failed"));\
65 #define ITADM_CHKAUTH(sec) {\
66 if (!chkauthattr(sec, itadm_uname)) {\
67 (void) fprintf(stderr,\
68 gettext("Error, operation requires authorization %s"),\
70 (void) fprintf(stderr, "\n");\
76 static struct option itadm_long
[] = {
77 {"alias", required_argument
, NULL
, 'l'},
78 {"auth-method", required_argument
, NULL
, 'a'},
79 {"chap-secret", no_argument
, NULL
, 's'},
80 {"chap-secret-file", required_argument
, NULL
, 'S'},
81 {"chap-user", required_argument
, NULL
, 'u'},
82 {"force", no_argument
, NULL
, 'f'},
83 {"help", no_argument
, NULL
, 'h'},
84 {"help", no_argument
, NULL
, '?'},
85 {"isns", required_argument
, NULL
, 'i'},
86 {"isns-server", required_argument
, NULL
, 'I'},
87 {"node-name", required_argument
, NULL
, 'n'},
88 {"parsable", no_argument
, NULL
, 'p'},
89 {"radius-secret", no_argument
, NULL
, 'd'},
90 {"radius-secret-file", required_argument
, NULL
, 'D'},
91 {"radius-server", required_argument
, NULL
, 'r'},
92 {"tpg-tag", required_argument
, NULL
, 't'},
93 {"verbose", no_argument
, NULL
, 'v'},
94 {"version", no_argument
, NULL
, 'V'},
99 " create-target [-a radius|chap|none|default] [-s]\n"
100 " [-S <chap-secret-path>] [-u <chap-user-name>]\n"
101 " [-n <target-node-name>] [-l <alias>]\n"
102 " [-t <tpg-name>[,<tpg-name>]...]";
104 static char m_tgt
[] =
105 " modify-target [-a radius|chap|none|default] [-s]\n"
106 " [-S <chap-secret-path>] [-u <chap-username>]\n"
107 " [-n <new-target-node-name>] [-l <alias>]\n"
108 " [-t <tpg-name>[,<tpg-name>]...] <target-node-name>";
110 static char d_tgt
[] =
111 " delete-target [-f] <target-node-name>";
113 static char l_tgt
[] =
114 " list-target [-pv] [<target-node-name>]";
116 static char c_tpg
[] =
117 " create-tpg <tpg-name> <IP-address>[:<port>]...";
119 static char l_tpg
[] =
120 " list-tpg [-pv] [<tpg-name>]";
122 static char d_tpg
[] =
123 " delete-tpg [-f] <tpg-name>";
125 static char c_ini
[] =
126 " create-initiator [-s] [-S <chap-secret-path>]\n"
127 " [-u <chap-username>] <initiator-node-name>";
129 static char m_ini
[] =
130 " modify-initiator [-s] [-S <chap-secret-path>]\n"
131 " [-u <chap-username>] <initiator-node-name>";
133 static char l_ini
[] =
134 " list-initiator [-pv] [<initiator-node-name>]";
136 static char d_ini
[] =
137 " delete-initiator <initiator-node-name>";
139 static char m_def
[] =
140 " modify-defaults [-a radius|chap|none] [-r <IP-address>[:<port>]] [-d]\n"
141 " [-D <radius-secret-path>] [-i enable|disable]\n"
142 " [-I <IP-address>[:<port>][,<IP-adddress>[:<port>]]...]";
144 static char l_def
[] =
145 " list-defaults [-p]";
148 /* keep the order of this enum in the same order as the 'subcmds' struct */
163 NULL_SUBCMD
/* must always be last! */
172 static itadm_subcmds_t subcmds
[] = {
173 {"create-target", ":a:sS:u:n:l:t:h?", c_tgt
},
174 {"modify-target", ":a:sS:u:n:l:t:h?", m_tgt
},
175 {"delete-target", ":fh?", d_tgt
},
176 {"list-target", ":hpv?", l_tgt
},
177 {"create-tpg", ":h?", c_tpg
},
178 {"delete-tpg", ":fh?", d_tpg
},
179 {"list-tpg", ":hpv?", l_tpg
},
180 {"create-initiator", ":sS:u:h?", c_ini
},
181 {"modify-initiator", ":sS:u:h?", m_ini
},
182 {"list-initiator", ":hpv?", l_ini
},
183 {"delete-initiator", ":h?", d_ini
},
184 {"modify-defaults", ":a:r:dD:i:I:h?", m_def
},
185 {"list-defaults", ":hp?", l_def
},
189 /* used for checking if user is authorized */
190 static char *itadm_uname
= NULL
;
194 itadm_get_password(nvlist_t
*nvl
, char *key
, char *passfile
,
198 itadm_opt_to_arr(nvlist_t
*nvl
, char *key
, char *opt
, uint32_t *num
);
201 create_target(char *tgt
, nvlist_t
*proplist
);
204 modify_target(char *tgt
, char *new, nvlist_t
*proplist
);
207 delete_target(char *tgt
, boolean_t force
);
210 list_target(char *tgt
, boolean_t verbose
, boolean_t script
);
213 create_tpg(char *tpg
, int addrc
, char **addrs
);
216 list_tpg(char *tpg
, boolean_t verbose
, boolean_t script
);
219 delete_tpg(char *tpg
, boolean_t force
);
222 modify_initiator(char *ini
, nvlist_t
*proplist
, boolean_t create
);
225 list_initiator(char *ini
, boolean_t verbose
, boolean_t script
);
228 delete_initiator(char *ini
);
231 modify_defaults(nvlist_t
*proplist
);
234 list_defaults(boolean_t script
);
237 tag_name_to_num(char *tagname
, uint16_t *tagnum
);
239 /* prototype from iscsit_common.h */
241 sockaddr_to_str(struct sockaddr_storage
*sa
, char **addr
);
243 static void output_config_error(int error_code
, char *msg
);
246 main(int argc
, char *argv
[])
249 int idx
= NULL_SUBCMD
;
252 char **newargv
= NULL
;
255 nvlist_t
*proplist
= NULL
;
256 boolean_t verbose
= B_FALSE
;
257 boolean_t script
= B_FALSE
;
259 char *targetname
= NULL
;
261 boolean_t force
= B_FALSE
;
262 struct passwd
*pwd
= NULL
;
264 char *smfstate
= NULL
;
266 (void) setlocale(LC_ALL
, "");
267 (void) textdomain(TEXT_DOMAIN
);
274 for (idx
= 0; subcmds
[idx
].name
!= NULL
; idx
++) {
275 if (strcmp(argv
[1], subcmds
[idx
].name
) == 0) {
281 /* get the caller's user name for subsequent chkauthattr() calls */
282 pwd
= getpwuid(getuid());
284 (void) fprintf(stderr
, "%s\n",
285 gettext("Could not determine callers user name"));
289 itadm_uname
= strdup(pwd
->pw_name
);
291 /* increment past command & subcommand */
293 newargv
= &(argv
[1]);
295 ret
= nvlist_alloc(&proplist
, NV_UNIQUE_NAME
, 0);
298 output_config_error(ret
, gettext("Could not allocate nvlist"));
303 while ((ret
== 0) && (newargv
)) {
304 c
= getopt_long(newargc
, newargv
, subcmds
[idx
].shortopts
,
312 /* flag set by getopt */
315 ret
= nvlist_add_string(proplist
,
319 ret
= itadm_get_password(proplist
,
320 "radiussecret", NULL
,
321 gettext("Enter RADIUS secret: "));
324 ret
= itadm_get_password(proplist
,
325 "radiussecret", optarg
, NULL
);
332 * '?' is returned for both unrecognized
333 * options and if explicitly provided on
334 * the command line. The latter should
335 * be handled the same as -h.
337 if (strcmp(newargv
[optind
-1], "-?") != 0) {
338 (void) fprintf(stderr
,
339 gettext("Unrecognized option %s"),
341 (void) fprintf(stderr
, "\n");
348 if (strncmp(optarg
, "enable", strlen(optarg
))
351 } else if (strncmp(optarg
, "disable",
352 strlen(optarg
)) == 0) {
355 (void) fprintf(stderr
, "%s\n",
356 gettext("invalid value for -i"));
360 ret
= nvlist_add_boolean_value(proplist
,
364 /* possibly multi-valued */
365 ret
= itadm_opt_to_arr(proplist
,
366 "isnsserver", optarg
, &count
);
367 if ((ret
== 0) && (count
> 8)) {
368 (void) fprintf(stderr
, "%s\n",
370 "Too many iSNS servers specified, "
371 "maximum of 8 allowed"));
376 ret
= nvlist_add_string(proplist
,
380 targetname
= strdup(optarg
);
381 if (targetname
== NULL
) {
389 ret
= nvlist_add_string(proplist
,
390 "radiusserver", optarg
);
393 if ((idx
== CREATE_TGT
) ||
394 (idx
== MODIFY_TGT
)) {
395 propname
= "targetchapsecret";
397 propname
= "chapsecret";
399 ret
= itadm_get_password(proplist
,
401 gettext("Enter CHAP secret: "));
404 if ((idx
== CREATE_TGT
) ||
405 (idx
== MODIFY_TGT
)) {
406 propname
= "targetchapsecret";
408 propname
= "chapsecret";
410 ret
= itadm_get_password(proplist
,
411 propname
, optarg
, NULL
);
414 /* possibly multi-valued */
415 ret
= itadm_opt_to_arr(proplist
,
416 "tpg-tag", optarg
, NULL
);
419 if ((idx
== CREATE_TGT
) ||
420 (idx
== MODIFY_TGT
)) {
421 propname
= "targetchapuser";
423 propname
= "chapuser";
425 ret
= nvlist_add_string(proplist
,
432 (void) fprintf(stderr
,
433 gettext("Option %s requires an operand"),
435 (void) fprintf(stderr
, "\n");
437 /* fall through to default */
448 /* after getopt() to allow handling of -h option */
449 if ((itadm_sub_t
)idx
== NULL_SUBCMD
) {
450 (void) fprintf(stderr
, "%s\n",
451 gettext("Error, no subcommand specified"));
457 * some subcommands take multiple operands, so adjust now that
465 newargv
= &(newargv
[optind
]);
470 switch ((itadm_sub_t
)idx
) {
478 /* These subcommands need at least one operand */
479 (void) fprintf(stderr
,
480 gettext("Error, %s requires an operand"),
482 (void) fprintf(stderr
, "\n");
492 switch ((itadm_sub_t
)idx
) {
502 /* These subcommands should have at most one operand */
503 (void) fprintf(stderr
,
504 gettext("Error, %s accepts only a single operand"),
506 (void) fprintf(stderr
, "\n");
517 switch ((itadm_sub_t
)idx
) {
521 /* These subcommands do not support an operand */
522 (void) fprintf(stderr
,
523 gettext("Error, %s does not support any operands"),
525 (void) fprintf(stderr
, "\n");
536 * XXX - this should probably get pushed down to the library
537 * depending on the decision to allow/disallow configuratoin
538 * without the service running.
541 * Make sure iSCSI target service is enabled before
544 smfstate
= smf_get_state(ISCSIT_SVC
);
546 (strcmp(smfstate
, SCF_STATE_STRING_ONLINE
) != 0)) {
547 (void) fprintf(stderr
, "%s\n",
548 gettext("The iSCSI target service must be online "
549 "before running this command."));
550 (void) fprintf(stderr
,
551 gettext("Use 'svcadm enable -r %s'"), ISCSIT_SVC
);
552 (void) fprintf(stderr
, "\n");
553 (void) fprintf(stderr
, "%s\n",
554 gettext("to enable the service and its prerequisite "
556 (void) fprintf(stderr
,
557 gettext("'svcs -x %s' to determine why it is not online."),
559 (void) fprintf(stderr
, "\n");
564 switch ((itadm_sub_t
)idx
) {
567 * OK for targetname to be NULL here. If the
568 * user did not specify a target name,
569 * one will be generated.
571 ret
= create_target(targetname
, proplist
);
574 ret
= modify_target(objp
, targetname
, proplist
);
577 ret
= delete_target(objp
, force
);
580 ret
= list_target(objp
, verbose
, script
);
583 ret
= create_tpg(objp
, newargc
- 1, &(newargv
[1]));
586 ret
= delete_tpg(objp
, force
);
589 ret
= list_tpg(objp
, verbose
, script
);
592 ret
= modify_initiator(objp
, proplist
, B_TRUE
);
595 ret
= modify_initiator(objp
, proplist
, B_FALSE
);
598 ret
= list_initiator(objp
, verbose
, script
);
601 ret
= delete_initiator(objp
);
604 ret
= modify_defaults(proplist
);
607 ret
= list_defaults(script
);
615 (void) fprintf(stderr
,
616 gettext("itadm %s failed with error %d"),
617 subcmds
[idx
].name
, ret
);
618 (void) fprintf(stderr
, "\n");
623 if (subcmds
[idx
].name
) {
624 (void) printf("%s\n%s\n", gettext("usage:"),
625 gettext(subcmds
[idx
].usemsg
));
628 (void) printf("%s\n",
629 gettext("usage: itadm <subcommand> <args> ..."));
630 for (idx
= 0; subcmds
[idx
].name
!= NULL
; idx
++) {
631 if (!subcmds
[idx
].usemsg
) {
634 (void) printf("%s\n", gettext(subcmds
[idx
].usemsg
));
642 create_target(char *tgt
, nvlist_t
*proplist
)
645 it_config_t
*cfg
= NULL
;
649 nvlist_t
*errlist
= NULL
;
651 it_tpg_t
*tpg
= NULL
;
654 char *sec
= "solaris.smf.modify.stmf";
655 boolean_t did_it_config_load
= B_FALSE
;
661 * Validate target name.
663 if (!IS_IQN_NAME(tgt
) && !IS_EUI_NAME(tgt
)) {
664 (void) fprintf(stderr
, gettext("Invalid name %s"),
666 (void) fprintf(stderr
, "\n");
671 ret
= it_config_load(&cfg
);
673 output_config_error(ret
,
674 gettext("Error retrieving iSCSI target configuration"));
678 did_it_config_load
= B_TRUE
;
680 ret
= it_tgt_create(cfg
, &tgtp
, tgt
);
683 (void) fprintf(stderr
,
684 gettext("Invalid iSCSI name %s"), tgt
);
685 (void) fprintf(stderr
, "\n");
686 } else if (ret
== EEXIST
) {
687 (void) fprintf(stderr
,
688 gettext("iSCSI target %s already configured"),
690 (void) fprintf(stderr
, "\n");
691 } else if (ret
== E2BIG
) {
692 (void) fprintf(stderr
,
693 gettext("Maximum of %d iSCSI targets"),
695 (void) fprintf(stderr
, "\n");
697 output_config_error(ret
,
698 gettext("Error creating target"));
704 /* set the target portal group tags */
705 ret
= nvlist_lookup_string_array(proplist
, "tpg-tag", &tags
,
709 /* none specified. is this ok? */
711 } else if (ret
!= 0) {
712 output_config_error(ret
, gettext("Internal error"));
716 /* special case, don't set any TPGs */
717 if (tags
&& (count
== 1) && (strcmp("default", tags
[0]) == 0)) {
721 for (i
= 0; i
< count
; i
++) {
726 /* see that all referenced groups are already defined */
727 tpg
= cfg
->config_tpg_list
;
728 while (tpg
!= NULL
) {
729 if (strcmp(tags
[i
], tpg
->tpg_name
) == 0) {
736 (void) fprintf(stderr
,
737 gettext("Invalid tpg-tag %s, tag not defined"),
739 (void) fprintf(stderr
, "\n");
744 /* generate the tag number to use */
745 tag_name_to_num(tags
[i
], &tagid
);
747 ret
= it_tpgt_create(cfg
, tgtp
, &tpgt
, tags
[i
], tagid
);
749 (void) fprintf(stderr
, gettext(
750 "Could not add target portal group tag %s: "),
752 output_config_error(ret
, NULL
);
758 /* remove the tags from the proplist before continuing */
760 (void) nvlist_remove_all(proplist
, "tpg-tag");
763 ret
= it_tgt_setprop(cfg
, tgtp
, proplist
, &errlist
);
765 (void) fprintf(stderr
,
766 gettext("Error setting target properties: %d"), ret
);
767 (void) fprintf(stderr
, "\n");
769 nvpair_t
*nvp
= NULL
;
773 while ((nvp
= nvlist_next_nvpair(errlist
, nvp
))
777 nn
= nvpair_name(nvp
);
778 (void) nvpair_value_string(nvp
, &nv
);
781 (void) fprintf(stderr
, "\t%s: %s\n",
786 nvlist_free(errlist
);
792 ret
= it_config_commit(cfg
);
798 (void) printf(gettext("Target %s successfully created"),
803 if (did_it_config_load
)
810 list_target(char *tgt
, boolean_t verbose
, boolean_t script
)
815 boolean_t found
= B_FALSE
;
816 boolean_t first
= B_TRUE
;
817 boolean_t first_tag
= B_TRUE
;
818 char *gauth
= "none";
825 char *sec
= "solaris.smf.read.stmf";
827 stmfSessionList
*sess
= NULL
;
828 stmfTargetProperties props
;
834 ret
= it_config_load(&cfg
);
836 output_config_error(ret
,
837 gettext("Error retrieving iSCSI target configuration"));
841 ptr
= cfg
->config_tgt_list
;
843 /* grab global defaults for auth, alias */
844 if (cfg
->config_global_properties
) {
845 (void) nvlist_lookup_string(cfg
->config_global_properties
,
847 (void) nvlist_lookup_string(cfg
->config_global_properties
,
851 for (; ptr
!= NULL
; ptr
= ptr
->tgt_next
) {
858 * We do a case-insensitive match in case
859 * a non-lower case value got stored.
861 if (strcasecmp(tgt
, ptr
->tgt_name
) != 0) {
873 * make a best effort to retrieve target status and
874 * number of active sessions from STMF.
876 ret
= stmfDevidFromIscsiName(ptr
->tgt_name
, &devid
);
877 if (ret
== STMF_STATUS_SUCCESS
) {
878 ret
= stmfGetTargetProperties(&devid
, &props
);
879 if (ret
== STMF_STATUS_SUCCESS
) {
880 if (props
.status
== STMF_TARGET_PORT_ONLINE
) {
887 if (ret
== STMF_STATUS_SUCCESS
) {
888 ret
= stmfGetSessionList(&devid
, &sess
);
889 if (ret
== STMF_STATUS_SUCCESS
) {
890 num_sessions
= sess
->cnt
;
895 /* reset ret so we don't return an error */
898 if (!script
&& first
) {
899 (void) printf("%-61s%-9s%-9s\n", "TARGET NAME",
900 "STATE", "SESSIONS");
906 * try not to let columns run into each other.
907 * Stick a tab after too-long fields.
908 * Lengths chosen are for the 'common' cases.
910 (void) printf("%-61s", ptr
->tgt_name
);
911 if (strlen(ptr
->tgt_name
) > 60) {
914 (void) printf("%-9s%-9d", state
, num_sessions
);
916 (void) printf("%s\t%s\t%d", ptr
->tgt_name
,
917 state
, num_sessions
);
930 if (ptr
->tgt_properties
) {
931 (void) nvlist_lookup_string(ptr
->tgt_properties
,
933 (void) nvlist_lookup_string(ptr
->tgt_properties
,
935 if (nvlist_exists(ptr
->tgt_properties
,
936 "targetchapsecret")) {
939 (void) nvlist_lookup_string(ptr
->tgt_properties
,
940 "targetchapuser", &chapu
);
944 (void) printf("\n\t%-20s\t%s\n\t%-20s\t%s %s\n"
945 "\t%-20s\t%s\n\t%-20s\t%s\n\t%-20s\t",
946 "alias:", alias
, "auth:", auth
,
947 ((auth
== gauth
) ? "(defaults)" : ""),
949 chapu
, "targetchapsecret:", chaps
, "tpg-tags:");
951 (void) printf("\t%s\t%s %s\t%s\t%s\t",
953 ((auth
== gauth
) ? "(defaults)" : ""),
958 tagp
= ptr
->tgt_tpgt_list
;
959 for (; tagp
!= NULL
; tagp
= tagp
->tpgt_next
) {
965 (void) printf("%s = %d",
966 tagp
->tpgt_tpg_name
, tagp
->tpgt_tag
);
970 /* didn't find any */
971 (void) printf("default");
977 if (tgt
&& (!found
)) {
978 (void) fprintf(stderr
,
979 gettext("Target %s not found!"), tgt
);
980 (void) fprintf(stderr
, "\n");
990 delete_target(char *tgt
, boolean_t force
)
995 char *sec
= "solaris.smf.modify.stmf";
1000 (void) fprintf(stderr
, "%s\n",
1001 gettext("Error, no target specified"));
1005 ret
= it_config_load(&cfg
);
1007 output_config_error(ret
,
1008 gettext("Error retrieving iSCSI target configuration"));
1012 ptr
= cfg
->config_tgt_list
;
1015 * We do a case-insensitive match in case
1016 * a non-lower case value got stored.
1018 if (strcasecmp(ptr
->tgt_name
, tgt
) == 0) {
1022 ptr
= ptr
->tgt_next
;
1026 ret
= it_tgt_delete(cfg
, ptr
, force
);
1030 (void) fprintf(stderr
,
1031 gettext("The target is online or busy. "
1032 "Use the -f (force) option, or "
1033 "'stmfadm offline-target %s'"), tgt
);
1034 (void) fprintf(stderr
, "\n");
1036 output_config_error(ret
, gettext(
1037 "Error deleting target"));
1042 ret
= it_config_commit(cfg
);
1046 (void) fprintf(stderr
,
1047 gettext("Target %s not found"), tgt
);
1048 (void) fprintf(stderr
, "\n");
1052 it_config_free(cfg
);
1058 modify_target(char *tgt
, char *newname
, nvlist_t
*proplist
)
1061 it_config_t
*cfg
= NULL
;
1062 it_tgt_t
*ptr
= NULL
;
1063 it_tgt_t
*tgtp
= NULL
;
1066 nvlist_t
*errlist
= NULL
;
1068 it_tpg_t
*tpg
= NULL
;
1070 it_tpgt_t
*tpgt
= NULL
;
1071 char *sec
= "solaris.smf.modify.stmf";
1072 boolean_t did_it_config_load
= B_FALSE
;
1076 /* XXX: Do we need to offline anything here too? */
1079 (void) fprintf(stderr
, "%s\n",
1080 gettext("Error, no target specified"));
1085 ret
= it_config_load(&cfg
);
1087 output_config_error(ret
,
1088 gettext("Error retrieving iSCSI target configuration"));
1092 did_it_config_load
= B_TRUE
;
1095 * If newname is specified, ensure it is a valid name.
1098 if (!validate_iscsi_name(newname
)) {
1099 (void) fprintf(stderr
,
1100 gettext("Invalid iSCSI name %s"), newname
);
1101 (void) fprintf(stderr
, "\n");
1108 * Loop through to verify that the target to be modified truly
1109 * exists. If this target is to be renamed, ensure the new
1110 * name is not already in use.
1112 ptr
= cfg
->config_tgt_list
;
1115 * Does a target with the new name already exist?
1118 (strcasecmp(newname
, ptr
->tgt_name
) == 0)) {
1119 (void) fprintf(stderr
,
1120 gettext("A target with name %s already exists"),
1122 (void) fprintf(stderr
, "\n");
1127 if (strcasecmp(ptr
->tgt_name
, tgt
) == 0) {
1131 ptr
= ptr
->tgt_next
;
1135 (void) fprintf(stderr
,
1136 gettext("Target %s not found"), tgt
);
1137 (void) fprintf(stderr
, "\n");
1142 /* set the target portal group tags */
1143 ret
= nvlist_lookup_string_array(proplist
, "tpg-tag", &tags
,
1146 if (ret
== ENOENT
) {
1147 /* none specified. is this ok? */
1149 } else if (ret
!= 0) {
1150 output_config_error(ret
, gettext("Internal error"));
1154 /* special case, remove all explicit TPGs, and don't add any */
1155 if (tags
&& (count
== 1) && (strcmp("default", tags
[0]) == 0)) {
1159 for (i
= 0; i
< count
; i
++) {
1160 if (!tags
|| !tags
[i
]) {
1164 /* see that all referenced groups are already defined */
1165 tpg
= cfg
->config_tpg_list
;
1166 while (tpg
!= NULL
) {
1167 if (strcmp(tags
[i
], tpg
->tpg_name
) == 0) {
1170 tpg
= tpg
->tpg_next
;
1173 (void) fprintf(stderr
,
1174 gettext("Invalid tpg-name %s: not defined"),
1176 (void) fprintf(stderr
, "\n");
1183 * don't recreate tags that are already associated,
1184 * remove tags not requested.
1187 tpgt
= tgtp
->tgt_tpgt_list
;
1189 for (i
= 0; i
< count
; i
++) {
1194 if (strcmp(tpgt
->tpgt_tpg_name
, tags
[i
])
1196 /* non-null tags will be created */
1203 it_tpgt_t
*ptr
= tpgt
;
1205 tpgt
= ptr
->tpgt_next
;
1206 it_tpgt_delete(cfg
, tgtp
, ptr
);
1208 tpgt
= tpgt
->tpgt_next
;
1213 /* see if there are any left to add */
1214 for (i
= 0; i
< count
; i
++) {
1215 if (!tags
|| !tags
[i
]) {
1219 /* generate the tag number to use */
1220 tag_name_to_num(tags
[i
], &tagid
);
1222 ret
= it_tpgt_create(cfg
, tgtp
, &tpgt
, tags
[i
], tagid
);
1225 (void) fprintf(stderr
, "%s\n",
1226 gettext("Error, no portal tag available"));
1228 (void) fprintf(stderr
, gettext(
1229 "Could not add target portal group"
1230 " tag %s: "), tags
[i
]);
1231 output_config_error(ret
, NULL
);
1237 /* remove the tags from the proplist before continuing */
1238 (void) nvlist_remove_all(proplist
, "tpg-tag");
1241 * Rename this target, if requested. Save the old name in
1242 * the property list, so the kernel knows this is a renamed
1243 * target, and not a new one.
1245 if (newname
&& (strlen(newname
) > 0)) {
1246 ret
= nvlist_add_string(proplist
, "oldtargetname",
1249 output_config_error(ret
,
1250 gettext("Error renaming target"));
1253 (void) strlcpy(tgtp
->tgt_name
, newname
,
1254 sizeof (tgtp
->tgt_name
));
1257 ret
= it_tgt_setprop(cfg
, tgtp
, proplist
, &errlist
);
1259 (void) fprintf(stderr
,
1260 gettext("Error setting target properties: %d"), ret
);
1261 (void) fprintf(stderr
, "\n");
1263 nvpair_t
*nvp
= NULL
;
1267 while ((nvp
= nvlist_next_nvpair(errlist
, nvp
))
1271 nn
= nvpair_name(nvp
);
1272 (void) nvpair_value_string(nvp
, &nv
);
1275 (void) fprintf(stderr
, "\t%s: %s\n",
1280 nvlist_free(errlist
);
1286 ret
= it_config_commit(cfg
);
1292 (void) printf(gettext("Target %s successfully modified"),
1294 (void) printf("\n");
1297 if (did_it_config_load
)
1298 it_config_free(cfg
);
1304 create_tpg(char *tpg
, int addrc
, char **addrs
)
1311 char *sec
= "solaris.smf.modify.stmf";
1317 (void) fprintf(stderr
, "%s\n",
1318 gettext("Error, no target portal group specified"));
1322 if (strlen(tpg
) > (MAX_TPG_NAMELEN
- 1)) {
1323 (void) fprintf(stderr
,
1324 gettext("Target Portal Group name must be no longer "
1325 "than %d characters"), (MAX_TPG_NAMELEN
- 1));
1326 (void) fprintf(stderr
, "\n");
1330 if (!addrs
|| (addrc
<= 0)) {
1331 (void) fprintf(stderr
, "%s\n",
1332 gettext("Error, no portal addresses specified"));
1336 ret
= it_config_load(&cfg
);
1338 output_config_error(ret
,
1339 gettext("Error retrieving iSCSI target configuration"));
1343 tpgp
= cfg
->config_tpg_list
;
1344 while (tpgp
!= NULL
) {
1345 if (strcmp(tpgp
->tpg_name
, tpg
) == 0) {
1346 (void) fprintf(stderr
,
1347 gettext("Target Portal Group %s already exists"),
1349 (void) fprintf(stderr
, "\n");
1350 it_config_free(cfg
);
1353 tpgp
= tpgp
->tpg_next
;
1357 * Ensure that the addrs don't contain commas.
1359 for (i
= 0; i
< addrc
; i
++) {
1360 if (strchr(addrs
[i
], ',')) {
1361 (void) fprintf(stderr
,
1362 gettext("Bad portal name %s"),
1364 (void) fprintf(stderr
, "\n");
1366 it_config_free(cfg
);
1372 * Create the portal group and first portal
1374 ret
= it_tpg_create(cfg
, &tpgp
, tpg
, addrs
[count
]);
1376 if (ret
== EEXIST
) {
1377 (void) fprintf(stderr
,
1378 gettext("Portal %s already in use"),
1380 (void) fprintf(stderr
, "\n");
1382 output_config_error(ret
, gettext("Could not create the "
1383 "target portal group"));
1385 it_config_free(cfg
);
1390 * Add the remaining portals
1392 for (count
= 1; count
< addrc
; count
++) {
1393 if (!addrs
[count
]) {
1397 ret
= it_portal_create(cfg
, tpgp
, &ptl
, addrs
[count
]);
1399 if (ret
== EEXIST
) {
1400 (void) fprintf(stderr
,
1401 gettext("Portal %s already in use"),
1403 (void) fprintf(stderr
, "\n");
1405 (void) fprintf(stderr
,
1406 gettext("Error adding portal %s: "),
1408 output_config_error(ret
, NULL
);
1415 ret
= it_config_commit(cfg
);
1419 it_config_free(cfg
);
1425 list_tpg(char *tpg
, boolean_t verbose
, boolean_t script
)
1430 boolean_t found
= B_FALSE
;
1431 it_portal_t
*portal
;
1432 boolean_t first
= B_TRUE
;
1433 boolean_t first_portal
;
1435 char *sec
= "solaris.smf.read.stmf";
1439 ret
= it_config_load(&cfg
);
1441 output_config_error(ret
,
1442 gettext("Error retrieving iSCSI target configuration"));
1446 ptr
= cfg
->config_tpg_list
;
1448 for (; ptr
!= NULL
; ptr
= ptr
->tpg_next
) {
1454 if (strcmp(tpg
, ptr
->tpg_name
) != 0) {
1461 if (!script
&& first
) {
1462 (void) printf("%-30s%-9s\n", "TARGET PORTAL GROUP",
1468 (void) printf("%-30s", ptr
->tpg_name
);
1469 if (strlen(ptr
->tpg_name
) > 30) {
1470 (void) printf("\t");
1472 (void) printf("%-9d", ptr
->tpg_portal_count
);
1474 (void) printf("%s\t%d", ptr
->tpg_name
,
1475 ptr
->tpg_portal_count
);
1479 (void) printf("\n");
1484 (void) printf("\n portals:");
1487 first_portal
= B_TRUE
;
1489 portal
= ptr
->tpg_portal_list
;
1490 for (; portal
!= NULL
; portal
= portal
->portal_next
) {
1491 ret
= sockaddr_to_str(&(portal
->portal_addr
), &pstr
);
1496 if (!first_portal
) {
1499 (void) printf("\t");
1500 first_portal
= B_FALSE
;
1503 (void) printf("%s", pstr
);
1509 (void) printf("\t<none>");
1512 (void) printf("\n");
1515 if (tpg
&& (!found
)) {
1516 (void) fprintf(stderr
,
1517 gettext("Target Portal Group %s not found!\n"), tpg
);
1518 (void) fprintf(stderr
, "\n");
1522 it_config_free(cfg
);
1528 delete_tpg(char *tpg
, boolean_t force
)
1532 it_tpg_t
*ptpg
= NULL
;
1533 char *sec
= "solaris.smf.modify.stmf";
1538 (void) fprintf(stderr
, "%s\n",
1539 gettext("Error, no target portal group specified"));
1543 ret
= it_config_load(&cfg
);
1545 output_config_error(ret
,
1546 gettext("Error retrieving iSCSI target configuration"));
1550 ptpg
= cfg
->config_tpg_list
;
1551 for (; ptpg
!= NULL
; ptpg
= ptpg
->tpg_next
) {
1552 if (strcmp(tpg
, ptpg
->tpg_name
) == 0) {
1558 (void) fprintf(stderr
,
1559 gettext("Target portal group %s does not exist"),
1561 (void) fprintf(stderr
, "\n");
1564 ret
= it_tpg_delete(cfg
, ptpg
, force
);
1566 (void) fprintf(stderr
, "%s\n",
1568 "Target portal group associated with one or more "
1569 "targets. Cannot delete."));
1570 } else if (ret
!= 0) {
1571 output_config_error(ret
, gettext("Could not delete "
1572 "target portal group"));
1576 ret
= it_config_commit(cfg
);
1581 it_config_free(cfg
);
1587 modify_initiator(char *ini
, nvlist_t
*proplist
, boolean_t create
)
1592 nvlist_t
*errlist
= NULL
;
1593 nvpair_t
*nvp
= NULL
;
1594 char *sec
= "solaris.smf.modify.stmf";
1595 boolean_t changed
= B_TRUE
;
1600 (void) fprintf(stderr
, "%s\n",
1601 gettext("Error, no initiator specified"));
1603 } else if (create
) {
1605 * validate input name - what are the rules for EUI
1608 if (!IS_IQN_NAME(ini
) && !IS_EUI_NAME(ini
)) {
1609 (void) fprintf(stderr
, gettext("Invalid name %s"),
1611 (void) fprintf(stderr
, "\n");
1617 * See if any properties were actually specified.
1620 nvp
= nvlist_next_nvpair(proplist
, nvp
);
1623 if ((nvp
== NULL
) && !create
) {
1628 * If no properties, and this is really a modify op, verify
1629 * that the requested initiator exists, but then don't do anything.
1630 * Modifying non-existent is an error; doing nothing to a defined
1634 ret
= it_config_load(&cfg
);
1636 output_config_error(ret
,
1637 gettext("Error retrieving iSCSI target configuration"));
1641 inip
= cfg
->config_ini_list
;
1643 if (strcasecmp(inip
->ini_name
, ini
) == 0) {
1647 inip
= inip
->ini_next
;
1652 (void) fprintf(stderr
,
1653 gettext("Initiator %s already exists"),
1655 (void) fprintf(stderr
, "\n");
1658 ret
= it_ini_create(cfg
, &inip
, ini
);
1660 if (ret
== EFAULT
) {
1661 (void) fprintf(stderr
,
1662 gettext("Invalid iSCSI name %s"),
1664 (void) fprintf(stderr
, "\n");
1666 output_config_error(ret
, gettext(
1667 "Error creating initiator"));
1673 (void) fprintf(stderr
,
1674 gettext("Error, initiator %s not found"),
1676 (void) fprintf(stderr
, "\n");
1679 if ((ret
== 0) && nvp
) {
1680 ret
= it_ini_setprop(inip
, proplist
, &errlist
);
1683 (void) fprintf(stderr
,
1684 gettext("Error setting initiator properties: %d"),
1686 (void) fprintf(stderr
, "\n");
1688 nvpair_t
*nvp
= NULL
;
1692 while ((nvp
= nvlist_next_nvpair(errlist
, nvp
))
1696 nn
= nvpair_name(nvp
);
1697 (void) nvpair_value_string(nvp
, &nv
);
1700 (void) fprintf(stderr
,
1701 "\t%s: %s\n", nn
, nv
);
1705 nvlist_free(errlist
);
1710 if ((ret
== 0) && changed
) {
1711 ret
= it_config_commit(cfg
);
1715 it_config_free(cfg
);
1721 list_initiator(char *ini
, boolean_t verbose
, boolean_t script
) /* ARGSUSED */
1726 boolean_t found
= B_FALSE
;
1727 boolean_t first
= B_TRUE
;
1730 char *sec
= "solaris.smf.read.stmf";
1734 ret
= it_config_load(&cfg
);
1736 output_config_error(ret
,
1737 gettext("Error retrieving iSCSI target configuration"));
1741 ptr
= cfg
->config_ini_list
;
1743 for (; ptr
!= NULL
; ptr
= ptr
->ini_next
) {
1752 if (strcasecmp(ini
, ptr
->ini_name
) != 0) {
1759 if (ptr
->ini_properties
) {
1760 if (nvlist_exists(ptr
->ini_properties
, "chapsecret")) {
1763 (void) nvlist_lookup_string(ptr
->ini_properties
,
1764 "chapuser", &iuser
);
1768 /* there's nothing to print for verbose yet */
1769 if (!script
&& first
) {
1770 (void) printf("%-61s%-10s%-7s\n", "INITIATOR NAME",
1771 "CHAPUSER", "SECRET");
1777 * try not to let columns run into each other.
1778 * Stick a tab after too-long fields.
1779 * Lengths chosen are for the 'common' cases.
1781 (void) printf("%-61s", ptr
->ini_name
);
1783 if (strlen(ptr
->ini_name
) > 60) {
1784 (void) printf("\t");
1787 (void) printf("%-15s", iuser
);
1788 if (strlen(iuser
) >= 15) {
1789 (void) printf("\t");
1792 (void) printf("%-4s", isecret
);
1794 (void) printf("%s\t%s\t%s", ptr
->ini_name
,
1798 (void) printf("\n");
1801 if (ini
&& (!found
)) {
1802 (void) fprintf(stderr
,
1803 gettext("Initiator %s not found!"), ini
);
1804 (void) fprintf(stderr
, "\n");
1808 it_config_free(cfg
);
1814 delete_initiator(char *ini
)
1819 char *sec
= "solaris.smf.modify.stmf";
1824 (void) fprintf(stderr
, "%s\n",
1825 gettext("Error, no initiator specified"));
1829 ret
= it_config_load(&cfg
);
1831 output_config_error(ret
,
1832 gettext("Error retrieving iSCSI target configuration"));
1836 ptr
= cfg
->config_ini_list
;
1838 if (strcasecmp(ptr
->ini_name
, ini
) == 0) {
1842 ptr
= ptr
->ini_next
;
1846 it_ini_delete(cfg
, ptr
);
1848 ret
= it_config_commit(cfg
);
1851 (void) fprintf(stderr
,
1852 gettext("Initiator %s not found"), ini
);
1853 (void) fprintf(stderr
, "\n");
1861 modify_defaults(nvlist_t
*proplist
)
1865 nvlist_t
*errlist
= NULL
;
1866 nvpair_t
*nvp
= NULL
;
1867 char *sec
= "solaris.smf.modify.stmf";
1872 /* make sure at least one property is specified */
1873 nvp
= nvlist_next_nvpair(proplist
, nvp
);
1878 (void) fprintf(stderr
, "%s\n",
1879 gettext("Error, no properties specified"));
1883 ret
= it_config_load(&cfg
);
1885 output_config_error(ret
,
1886 gettext("Error retrieving iSCSI target configuration"));
1890 ret
= it_config_setprop(cfg
, proplist
, &errlist
);
1892 (void) fprintf(stderr
,
1893 gettext("Error setting global properties: %d"),
1895 (void) fprintf(stderr
, "\n");
1897 nvpair_t
*nvp
= NULL
;
1901 while ((nvp
= nvlist_next_nvpair(errlist
, nvp
))
1905 nn
= nvpair_name(nvp
);
1906 (void) nvpair_value_string(nvp
, &nv
);
1909 (void) fprintf(stderr
, "\t%s: %s\n",
1914 nvlist_free(errlist
);
1919 ret
= it_config_commit(cfg
);
1923 it_config_free(cfg
);
1929 list_defaults(boolean_t script
)
1934 char *alias
= "<none>";
1935 char *auth
= "<none>";
1936 char *isns
= "disabled";
1937 char **isvrs
= NULL
;
1938 uint32_t scount
= 0;
1939 char *rsvr
= "<none>";
1940 char *rsecret
= "unset";
1941 boolean_t val
= B_FALSE
;
1943 char *sec
= "solaris.smf.read.stmf";
1947 ret
= it_config_load(&cfg
);
1949 output_config_error(ret
,
1950 gettext("Error retrieving iSCSI target configuration"));
1954 nvl
= cfg
->config_global_properties
;
1956 /* look up all possible options */
1957 (void) nvlist_lookup_string(nvl
, "alias", &alias
);
1958 (void) nvlist_lookup_string(nvl
, "auth", &auth
);
1959 (void) nvlist_lookup_boolean_value(nvl
, "isns", &val
);
1960 if (val
== B_TRUE
) {
1963 (void) nvlist_lookup_string_array(nvl
, "isnsserver", &isvrs
,
1965 (void) nvlist_lookup_string(nvl
, "radiusserver", &rsvr
);
1966 if (nvlist_exists(nvl
, "radiussecret")) {
1971 (void) printf("%s:\n\n",
1972 gettext("iSCSI Target Default Properties"));
1976 (void) printf("%s\t%s\t%s\t%s\t%s\t",
1977 alias
, auth
, rsvr
, rsecret
, isns
);
1979 (void) printf("%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n"
1980 "%-15s\t%s\n%-15s\t",
1981 "alias:", alias
, "auth:", auth
, "radiusserver:",
1982 rsvr
, "radiussecret:", rsecret
, "isns:", isns
,
1986 for (i
= 0; i
< scount
; i
++) {
1987 if (!isvrs
|| !isvrs
[i
]) {
1993 (void) printf("%s", isvrs
[i
]);
1997 (void) printf("%s", "<none>");
2000 (void) printf("\n");
2002 it_config_free(cfg
);
2008 itadm_get_password(nvlist_t
*nvl
, char *key
, char *passfile
,
2023 ret
= stat64(passfile
, &sbuf
);
2024 if ((ret
!= 0) || (!S_ISREG(sbuf
.st_mode
))) {
2025 (void) fprintf(stderr
,
2026 gettext("Invalid secret file %s"),
2028 (void) fprintf(stderr
, "\n");
2032 fd
= open64(passfile
, O_RDONLY
);
2035 (void) fprintf(stderr
,
2036 gettext("Could not open secret file %s: "),
2038 output_config_error(ret
, NULL
);
2042 rd
= read(fd
, buf
, sbuf
.st_size
);
2045 if (rd
!= sbuf
.st_size
) {
2047 (void) fprintf(stderr
,
2048 gettext("Could not read secret file %s: "),
2050 output_config_error(ret
, NULL
);
2054 /* ensure buf is properly terminated */
2057 /* if last char is a newline, strip it off */
2058 if (buf
[rd
- 1] == '\n') {
2062 /* validate length */
2063 if ((strlen(buf
) > 255) || (strlen(buf
) < 12)) {
2064 (void) fprintf(stderr
, "%s\n",
2066 "Secret must be between 12 and 255 characters"));
2070 /* prompt for secret */
2075 pass
= getpassphrase(phrase
);
2078 output_config_error(ret
,
2079 gettext("Could not read secret"));
2083 /* validate length */
2084 if ((strlen(pass
) > 255) || (strlen(pass
) < 12)) {
2085 (void) fprintf(stderr
, "%s\n",
2087 "Secret must be between 12 and 255 characters"));
2091 (void) strlcpy(buf
, pass
, sizeof (buf
));
2093 /* confirm entered secret */
2094 pass
= getpassphrase(gettext("Re-enter secret: "));
2097 output_config_error(ret
,
2098 gettext("Could not read secret"));
2102 if (strcmp(buf
, pass
) != 0) {
2104 (void) fprintf(stderr
, "%s\n",
2105 gettext("Secret validation failed"));
2111 ret
= nvlist_add_string(nvl
, key
, buf
);
2117 itadm_opt_to_arr(nvlist_t
*nvl
, char *key
, char *opt
, uint32_t *num
)
2123 if (!opt
|| !key
|| !nvl
) {
2131 bufp
= strchr(bufp
, ',');
2139 arr
= calloc(count
, sizeof (char *));
2145 /* set delimiter to comma */
2146 (void) bufsplit(",", 0, NULL
);
2148 /* split up that buf! */
2149 (void) bufsplit(bufp
, count
, arr
);
2151 /* if requested, return the number of array members found */
2156 return (nvlist_add_string_array(nvl
, key
, arr
, count
));
2160 tag_name_to_num(char *tagname
, uint16_t *tagnum
)
2165 if (!tagname
|| !tagnum
) {
2171 id
= strtoul(tagname
, &ptr
, 10);
2173 /* Must be entirely numeric and in-range */
2174 if (ptr
&& (*ptr
!= '\0')) {
2178 if ((id
<= UINT16_MAX
) && (id
> 1)) {
2179 *tagnum
= (uint16_t)id
;
2184 * Print error messages to stderr for errnos and expected stmf errors.
2185 * This function should generally not be used for cases where the
2186 * calling code can generate a more detailed error message based on
2187 * the contextual knowledge of the meaning of specific errors.
2190 output_config_error(int error
, char *msg
)
2194 (void) fprintf(stderr
, "%s: ", msg
);
2197 if (error
& STMF_STATUS_ERROR
) {
2199 case STMF_ERROR_PERM
:
2200 (void) fprintf(stderr
, "%s",
2201 gettext("permission denied"));
2203 case STMF_ERROR_BUSY
:
2204 (void) fprintf(stderr
, "%s",
2205 gettext("resource busy"));
2207 case STMF_ERROR_NOMEM
:
2208 (void) fprintf(stderr
, "%s",
2209 gettext("out of memory"));
2211 case STMF_ERROR_SERVICE_NOT_FOUND
:
2212 (void) fprintf(stderr
, "%s",
2213 gettext("STMF service not found"));
2215 case STMF_ERROR_SERVICE_DATA_VERSION
:
2216 (void) fprintf(stderr
, "%s",
2217 gettext("STMF service version incorrect"));
2219 case STMF_ERROR_PROV_DATA_STALE
:
2220 (void) fprintf(stderr
, "%s",
2221 gettext("Configuration changed during processing. "
2222 "Check the configuration, then retry this "
2223 "command if appropriate."));
2226 (void) fprintf(stderr
, "%s", gettext("unknown error"));
2232 (void) strerror_r(error
, buf
, sizeof (buf
));
2233 (void) fprintf(stderr
, "%s", buf
);
2236 (void) fprintf(stderr
, "\n");