Print this page
4459 Typo in itadm(1m) usage message: delete-inititator
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/itadm/itadm.c
+++ new/usr/src/cmd/itadm/itadm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24 #include <stdlib.h>
25 25 #include <stdio.h>
26 26 #include <sys/types.h>
27 27 #include <sys/stat.h>
28 28 #include <fcntl.h>
29 29 #include <unistd.h>
30 30 #include <errno.h>
31 31 #include <string.h>
32 32 #include <getopt.h>
33 33 #include <strings.h>
34 34 #include <ctype.h>
35 35 #include <libnvpair.h>
36 36 #include <libintl.h>
37 37 #include <libgen.h>
38 38 #include <pwd.h>
39 39 #include <auth_attr.h>
40 40 #include <secdb.h>
41 41 #include <libscf.h>
42 42 #include <limits.h>
43 43 #include <locale.h>
44 44
45 45 #include <libstmf.h>
46 46 #include <libiscsit.h>
47 47
48 48 /* what's this used for?? */
49 49 #define ITADM_VERSION "1.0"
50 50
51 51 /* SMF service info */
52 52 #define ISCSIT_SVC "svc:/network/iscsi/target:default"
53 53
54 54 #define STMF_STALE(ret) {\
55 55 if (ret == STMF_ERROR_PROV_DATA_STALE) {\
56 56 output_config_error(ret, NULL);\
57 57 } else if (ret != 0) {\
58 58 output_config_error(ret,\
59 59 gettext("Configuration change failed"));\
60 60 }\
61 61 }
62 62
63 63 #define ITADM_CHKAUTH(sec) {\
64 64 if (!chkauthattr(sec, itadm_uname)) {\
65 65 (void) fprintf(stderr,\
66 66 gettext("Error, operation requires authorization %s"),\
67 67 sec);\
68 68 (void) fprintf(stderr, "\n");\
69 69 return (1);\
70 70 }\
71 71 }
72 72
73 73
74 74 static struct option itadm_long[] = {
75 75 {"alias", required_argument, NULL, 'l'},
76 76 {"auth-method", required_argument, NULL, 'a'},
77 77 {"chap-secret", no_argument, NULL, 's'},
78 78 {"chap-secret-file", required_argument, NULL, 'S'},
79 79 {"chap-user", required_argument, NULL, 'u'},
80 80 {"force", no_argument, NULL, 'f'},
81 81 {"help", no_argument, NULL, 'h'},
82 82 {"help", no_argument, NULL, '?'},
83 83 {"isns", required_argument, NULL, 'i'},
84 84 {"isns-server", required_argument, NULL, 'I'},
85 85 {"node-name", required_argument, NULL, 'n'},
86 86 {"radius-secret", no_argument, NULL, 'd'},
87 87 {"radius-secret-file", required_argument, NULL, 'D'},
88 88 {"radius-server", required_argument, NULL, 'r'},
89 89 {"tpg-tag", required_argument, NULL, 't'},
90 90 {"verbose", no_argument, NULL, 'v'},
91 91 {"version", no_argument, NULL, 'V'},
92 92 {NULL, 0, NULL, 0}
93 93 };
94 94
95 95 char c_tgt[] = "itadm create-target [-a radius|chap|none|default] [-s] \
96 96 [-S chap-secret-path] [-u chap-username] [-n target-node-name] \
97 97 [-l alias] [-t tpg-name[,tpg-name,...]]";
98 98
99 99 static char m_tgt[] = "itadm modify-target [-a radius|chap|none|default] [-s] \
100 100 [-S chap-secret-path] [-u chap-username] [-n new-target-node-name] \
101 101 [-l alias] [-t tpg-name[,tpg-name,...]] target-node-name";
102 102
103 103 static char d_tgt[] = "itadm delete-target [-f] target-node-name";
104 104
105 105 static char l_tgt[] = "itadm list-target [-v] [target-node-name]";
106 106
107 107 static char c_tpg[] = "itadm create-tpg tpg-name IP-address[:port] \
108 108 [IP-address[:port]] [...]";
109 109
110 110 static char l_tpg[] = "itadm list-tpg [-v] [tpg-name]";
111 111
↓ open down ↓ |
111 lines elided |
↑ open up ↑ |
112 112 static char d_tpg[] = "itadm delete-tpg [-f] tpg-name";
113 113
114 114 static char c_ini[] = "itadm create-initiator [-s] [-S chap-secret-path] \
115 115 [-u chap-username] initiator-node-name";
116 116
117 117 static char m_ini[] = "itadm modify-initiator [-s] [-S chap-secret-path] \
118 118 [-u chap-username] initiator-node-name";
119 119
120 120 static char l_ini[] = "itadm list-initiator [-v] initiator-node-name";
121 121
122 -static char d_ini[] = "itadm delete-inititator initiator-node-name";
122 +static char d_ini[] = "itadm delete-initiator initiator-node-name";
123 123
124 124 static char m_def[] = "itadm modify-defaults [-a radius|chap|none] \
125 125 [-r IP-address[:port]] [-d] [-D radius-secret-path] [-i enable|disable] \
126 126 [-I IP-address[:port][,IP-adddress[:port]]]";
127 127
128 128 static char l_def[] = "itadm list-defaults";
129 129
130 130
131 131 /* keep the order of this enum in the same order as the 'subcmds' struct */
132 132 typedef enum {
133 133 CREATE_TGT,
134 134 MODIFY_TGT,
135 135 DELETE_TGT,
136 136 LIST_TGT,
137 137 CREATE_TPG,
138 138 DELETE_TPG,
139 139 LIST_TPG,
140 140 CREATE_INI,
141 141 MODIFY_INI,
142 142 LIST_INI,
143 143 DELETE_INI,
144 144 MODIFY_DEF,
145 145 LIST_DEF,
146 146 NULL_SUBCMD /* must always be last! */
147 147 } itadm_sub_t;
148 148
149 149 typedef struct {
150 150 char *name;
151 151 char *shortopts;
152 152 char *usemsg;
153 153 } itadm_subcmds_t;
154 154
155 155 static itadm_subcmds_t subcmds[] = {
156 156 {"create-target", ":a:sS:u:n:l:t:h?", c_tgt},
157 157 {"modify-target", ":a:sS:u:n:l:t:h?", m_tgt},
158 158 {"delete-target", ":fh?", d_tgt},
159 159 {"list-target", ":vh?", l_tgt},
160 160 {"create-tpg", ":h?", c_tpg},
161 161 {"delete-tpg", ":fh?", d_tpg},
162 162 {"list-tpg", ":vh?", l_tpg},
163 163 {"create-initiator", ":sS:u:h?", c_ini},
164 164 {"modify-initiator", ":sS:u:h?", m_ini},
165 165 {"list-initiator", ":vh?", l_ini},
166 166 {"delete-initiator", ":h?", d_ini},
167 167 {"modify-defaults", ":a:r:dD:i:I:h?", m_def},
168 168 {"list-defaults", ":h?", l_def},
169 169 {NULL, ":h?", NULL},
170 170 };
171 171
172 172 /* used for checking if user is authorized */
173 173 static char *itadm_uname = NULL;
174 174
175 175 /* prototypes */
176 176 static int
177 177 itadm_get_password(nvlist_t *nvl, char *key, char *passfile,
178 178 char *phrase);
179 179
180 180 static int
181 181 itadm_opt_to_arr(nvlist_t *nvl, char *key, char *opt, uint32_t *num);
182 182
183 183 static int
184 184 create_target(char *tgt, nvlist_t *proplist);
185 185
186 186 static int
187 187 modify_target(char *tgt, char *new, nvlist_t *proplist);
188 188
189 189 static int
190 190 delete_target(char *tgt, boolean_t force);
191 191
192 192 static int
193 193 list_target(char *tgt, boolean_t verbose, boolean_t script);
194 194
195 195 static int
196 196 create_tpg(char *tpg, int addrc, char **addrs);
197 197
198 198 static int
199 199 list_tpg(char *tpg, boolean_t verbose, boolean_t script);
200 200
201 201 static int
202 202 delete_tpg(char *tpg, boolean_t force);
203 203
204 204 static int
205 205 modify_initiator(char *ini, nvlist_t *proplist, boolean_t create);
206 206
207 207 static int
208 208 list_initiator(char *ini, boolean_t verbose, boolean_t script);
209 209
210 210 static int
211 211 delete_initiator(char *ini);
212 212
213 213 static int
214 214 modify_defaults(nvlist_t *proplist);
215 215
216 216 static int
217 217 list_defaults(boolean_t script);
218 218
219 219 static void
220 220 tag_name_to_num(char *tagname, uint16_t *tagnum);
221 221
222 222 /* prototype from iscsit_common.h */
223 223 extern int
224 224 sockaddr_to_str(struct sockaddr_storage *sa, char **addr);
225 225
226 226 static void output_config_error(int error_code, char *msg);
227 227
228 228 int
229 229 main(int argc, char *argv[])
230 230 {
231 231 int ret = 0;
232 232 int idx = NULL_SUBCMD;
233 233 char c;
234 234 int newargc = argc;
235 235 char **newargv = NULL;
236 236 char *objp;
237 237 int itind = 0;
238 238 nvlist_t *proplist = NULL;
239 239 boolean_t verbose = B_FALSE;
240 240 boolean_t scripting = B_FALSE;
241 241 boolean_t tbool;
242 242 char *targetname = NULL;
243 243 char *propname;
244 244 boolean_t force = B_FALSE;
245 245 struct passwd *pwd = NULL;
246 246 uint32_t count = 0;
247 247 char *smfstate = NULL;
248 248
249 249 (void) setlocale(LC_ALL, "");
250 250 (void) textdomain(TEXT_DOMAIN);
251 251
252 252 if (argc < 2) {
253 253 ret = 1;
254 254 goto usage_error;
255 255 }
256 256
257 257 for (idx = 0; subcmds[idx].name != NULL; idx++) {
258 258 if (strcmp(argv[1], subcmds[idx].name) == 0) {
259 259 break;
260 260 }
261 261 }
262 262
263 263
264 264 /* get the caller's user name for subsequent chkauthattr() calls */
265 265 pwd = getpwuid(getuid());
266 266 if (pwd == NULL) {
267 267 (void) fprintf(stderr, "%s\n",
268 268 gettext("Could not determine callers user name"));
269 269 return (1);
270 270 }
271 271
272 272 itadm_uname = strdup(pwd->pw_name);
273 273
274 274 /* increment past command & subcommand */
275 275 newargc--;
276 276 newargv = &(argv[1]);
277 277
278 278 ret = nvlist_alloc(&proplist, NV_UNIQUE_NAME, 0);
279 279 if (ret != 0) {
280 280 ret = errno;
281 281 output_config_error(ret, gettext("Could not allocate nvlist"));
282 282 ret = 1;
283 283 goto usage_error;
284 284 }
285 285
286 286 while ((ret == 0) && (newargv)) {
287 287 c = getopt_long(newargc, newargv, subcmds[idx].shortopts,
288 288 itadm_long, &itind);
289 289 if (c == -1) {
290 290 break;
291 291 }
292 292
293 293 switch (c) {
294 294 case 0:
295 295 /* flag set by getopt */
296 296 break;
297 297 case 'a':
298 298 ret = nvlist_add_string(proplist,
299 299 "auth", optarg);
300 300 break;
301 301 case 'd':
302 302 ret = itadm_get_password(proplist,
303 303 "radiussecret", NULL,
304 304 gettext("Enter RADIUS secret: "));
305 305 break;
306 306 case 'D':
307 307 ret = itadm_get_password(proplist,
308 308 "radiussecret", optarg, NULL);
309 309 break;
310 310 case 'f':
311 311 force = B_TRUE;
312 312 break;
313 313 case '?':
314 314 /*
315 315 * '?' is returned for both unrecognized
316 316 * options and if explicitly provided on
317 317 * the command line. The latter should
318 318 * be handled the same as -h.
319 319 */
320 320 if (strcmp(newargv[optind-1], "-?") != 0) {
321 321 (void) fprintf(stderr,
322 322 gettext("Unrecognized option %s"),
323 323 newargv[optind-1]);
324 324 (void) fprintf(stderr, "\n");
325 325 ret = 1;
326 326 }
327 327 goto usage_error;
328 328 case 'h':
329 329 goto usage_error;
330 330 case 'i':
331 331 if (strncmp(optarg, "enable", strlen(optarg))
332 332 == 0) {
333 333 tbool = B_TRUE;
334 334 } else if (strncmp(optarg, "disable",
335 335 strlen(optarg)) == 0) {
336 336 tbool = B_FALSE;
337 337 } else {
338 338 (void) fprintf(stderr, "%s\n",
339 339 gettext("invalid value for -i"));
340 340 ret = 1;
341 341 break;
342 342 }
343 343 ret = nvlist_add_boolean_value(proplist,
344 344 "isns", tbool);
345 345 break;
346 346 case 'I':
347 347 /* possibly multi-valued */
348 348 ret = itadm_opt_to_arr(proplist,
349 349 "isnsserver", optarg, &count);
350 350 if ((ret == 0) && (count > 8)) {
351 351 (void) fprintf(stderr, "%s\n",
352 352 gettext(
353 353 "Too many iSNS servers specified, "
354 354 "maximum of 8 allowed"));
355 355 ret = 1;
356 356 }
357 357 break;
358 358 case 'l':
359 359 ret = nvlist_add_string(proplist,
360 360 "alias", optarg);
361 361 break;
362 362 case 'n':
363 363 targetname = strdup(optarg);
364 364 if (targetname == NULL) {
365 365 ret = ENOMEM;
366 366 }
367 367 break;
368 368 case 'r':
369 369 ret = nvlist_add_string(proplist,
370 370 "radiusserver", optarg);
371 371 break;
372 372 case 's':
373 373 if ((idx == CREATE_TGT) ||
374 374 (idx == MODIFY_TGT)) {
375 375 propname = "targetchapsecret";
376 376 } else {
377 377 propname = "chapsecret";
378 378 }
379 379 ret = itadm_get_password(proplist,
380 380 propname, NULL,
381 381 gettext("Enter CHAP secret: "));
382 382 break;
383 383 case 'S':
384 384 if ((idx == CREATE_TGT) ||
385 385 (idx == MODIFY_TGT)) {
386 386 propname = "targetchapsecret";
387 387 } else {
388 388 propname = "chapsecret";
389 389 }
390 390 ret = itadm_get_password(proplist,
391 391 propname, optarg, NULL);
392 392 break;
393 393 case 't':
394 394 /* possibly multi-valued */
395 395 ret = itadm_opt_to_arr(proplist,
396 396 "tpg-tag", optarg, NULL);
397 397 break;
398 398 case 'u':
399 399 if ((idx == CREATE_TGT) ||
400 400 (idx == MODIFY_TGT)) {
401 401 propname = "targetchapuser";
402 402 } else {
403 403 propname = "chapuser";
404 404 }
405 405 ret = nvlist_add_string(proplist,
406 406 propname, optarg);
407 407 break;
408 408 case 'v':
409 409 verbose = B_TRUE;
410 410 break;
411 411 case ':':
412 412 (void) fprintf(stderr,
413 413 gettext("Option %s requires an operand"),
414 414 newargv[optind-1]);
415 415 (void) fprintf(stderr, "\n");
416 416
417 417 /* fall through to default */
418 418 default:
419 419 ret = 1;
420 420 break;
421 421 }
422 422 }
423 423
424 424 if (ret != 0) {
425 425 goto usage_error;
426 426 }
427 427
428 428 /* after getopt() to allow handling of -h option */
429 429 if ((itadm_sub_t)idx == NULL_SUBCMD) {
430 430 (void) fprintf(stderr, "%s\n",
431 431 gettext("Error, no subcommand specified"));
432 432 ret = 1;
433 433 goto usage_error;
434 434 }
435 435
436 436 /*
437 437 * some subcommands take multiple operands, so adjust now that
438 438 * getopt is complete
439 439 */
440 440 newargc -= optind;
441 441 if (newargc == 0) {
442 442 newargv = NULL;
443 443 objp = NULL;
444 444 } else {
445 445 newargv = &(newargv[optind]);
446 446 objp = newargv[0];
447 447 }
448 448
449 449 if (objp == NULL) {
450 450 switch ((itadm_sub_t)idx) {
451 451 case MODIFY_TGT:
452 452 case DELETE_TGT:
453 453 case CREATE_TPG:
454 454 case DELETE_TPG:
455 455 case CREATE_INI:
456 456 case MODIFY_INI:
457 457 case DELETE_INI:
458 458 /* These subcommands need at least one operand */
459 459 (void) fprintf(stderr,
460 460 gettext("Error, %s requires an operand"),
461 461 subcmds[idx].name);
462 462 (void) fprintf(stderr, "\n");
463 463
464 464 ret = 1;
465 465 goto usage_error;
466 466 default:
467 467 break;
468 468 }
469 469 }
470 470
471 471 if (newargc > 1) {
472 472 switch ((itadm_sub_t)idx) {
473 473 case MODIFY_TGT:
474 474 case DELETE_TGT:
475 475 case LIST_TGT:
476 476 case DELETE_TPG:
477 477 case LIST_TPG:
478 478 case CREATE_INI:
479 479 case MODIFY_INI:
480 480 case LIST_INI:
481 481 case DELETE_INI:
482 482 /* These subcommands should have at most one operand */
483 483 (void) fprintf(stderr,
484 484 gettext("Error, %s accepts only a single operand"),
485 485 subcmds[idx].name);
486 486 (void) fprintf(stderr, "\n");
487 487
488 488 ret = 1;
489 489 goto usage_error;
490 490
491 491 default:
492 492 break;
493 493 }
494 494 }
495 495
496 496 if (newargc > 0) {
497 497 switch ((itadm_sub_t)idx) {
498 498 case CREATE_TGT:
499 499 case MODIFY_DEF:
500 500 case LIST_DEF:
501 501 /* These subcommands do not support an operand */
502 502 (void) fprintf(stderr,
503 503 gettext("Error, %s does not support any operands"),
504 504 subcmds[idx].name);
505 505 (void) fprintf(stderr, "\n");
506 506
507 507 ret = 1;
508 508 goto usage_error;
509 509
510 510 default:
511 511 break;
512 512 }
513 513 }
514 514
515 515 /*
516 516 * XXX - this should probably get pushed down to the library
517 517 * depending on the decision to allow/disallow configuratoin
518 518 * without the service running.
519 519 */
520 520 /*
521 521 * Make sure iSCSI target service is enabled before
522 522 * proceeding.
523 523 */
524 524 smfstate = smf_get_state(ISCSIT_SVC);
525 525 if (!smfstate ||
526 526 (strcmp(smfstate, SCF_STATE_STRING_ONLINE) != 0)) {
527 527 (void) fprintf(stderr, "%s\n",
528 528 gettext("The iSCSI target service must be online "
529 529 "before running this command."));
530 530 (void) fprintf(stderr,
531 531 gettext("Use 'svcadm enable -r %s'"), ISCSIT_SVC);
532 532 (void) fprintf(stderr, "\n");
533 533 (void) fprintf(stderr, "%s\n",
534 534 gettext("to enable the service and its prerequisite "
535 535 "services and/or"));
536 536 (void) fprintf(stderr,
537 537 gettext("'svcs -x %s' to determine why it is not online."),
538 538 ISCSIT_SVC);
539 539 (void) fprintf(stderr, "\n");
540 540
541 541 return (1);
542 542 }
543 543
544 544 switch ((itadm_sub_t)idx) {
545 545 case CREATE_TGT:
546 546 /*
547 547 * OK for targetname to be NULL here. If the
548 548 * user did not specify a target name,
549 549 * one will be generated.
550 550 */
551 551 ret = create_target(targetname, proplist);
552 552 break;
553 553 case MODIFY_TGT:
554 554 ret = modify_target(objp, targetname, proplist);
555 555 break;
556 556 case DELETE_TGT:
557 557 ret = delete_target(objp, force);
558 558 break;
559 559 case LIST_TGT:
560 560 ret = list_target(objp, verbose, scripting);
561 561 break;
562 562 case CREATE_TPG:
563 563 ret = create_tpg(objp, newargc - 1, &(newargv[1]));
564 564 break;
565 565 case DELETE_TPG:
566 566 ret = delete_tpg(objp, force);
567 567 break;
568 568 case LIST_TPG:
569 569 ret = list_tpg(objp, verbose, scripting);
570 570 break;
571 571 case CREATE_INI:
572 572 ret = modify_initiator(objp, proplist, B_TRUE);
573 573 break;
574 574 case MODIFY_INI:
575 575 ret = modify_initiator(objp, proplist, B_FALSE);
576 576 break;
577 577 case LIST_INI:
578 578 ret = list_initiator(objp, verbose, scripting);
579 579 break;
580 580 case DELETE_INI:
581 581 ret = delete_initiator(objp);
582 582 break;
583 583 case MODIFY_DEF:
584 584 ret = modify_defaults(proplist);
585 585 break;
586 586 case LIST_DEF:
587 587 ret = list_defaults(scripting);
588 588 break;
589 589 default:
590 590 ret = 1;
591 591 goto usage_error;
592 592 }
593 593
594 594 if (ret != 0) {
595 595 (void) fprintf(stderr,
596 596 gettext("itadm %s failed with error %d"),
597 597 subcmds[idx].name, ret);
598 598 (void) fprintf(stderr, "\n");
599 599 }
600 600 return (ret);
601 601
602 602 usage_error:
603 603 if (subcmds[idx].name) {
604 604 (void) printf("%s\n", gettext(subcmds[idx].usemsg));
605 605 } else {
606 606 /* overall usage */
607 607 (void) printf("%s\n\n", gettext("itadm usage:"));
608 608 for (idx = 0; subcmds[idx].name != NULL; idx++) {
609 609 if (!subcmds[idx].usemsg) {
610 610 continue;
611 611 }
612 612 (void) printf("\t%s\n", gettext(subcmds[idx].usemsg));
613 613 }
614 614 }
615 615
616 616 return (ret);
617 617 }
618 618
619 619 static int
620 620 create_target(char *tgt, nvlist_t *proplist)
621 621 {
622 622 int ret;
623 623 it_config_t *cfg = NULL;
624 624 it_tgt_t *tgtp;
625 625 char **tags = NULL;
626 626 uint32_t count = 0;
627 627 nvlist_t *errlist = NULL;
628 628 int i;
629 629 it_tpg_t *tpg = NULL;
630 630 uint16_t tagid = 0;
631 631 it_tpgt_t *tpgt;
632 632 char *sec = "solaris.smf.modify.stmf";
633 633 boolean_t did_it_config_load = B_FALSE;
634 634
635 635 ITADM_CHKAUTH(sec);
636 636
637 637 if (tgt) {
638 638 /*
639 639 * Validate target name.
640 640 */
641 641 if (!IS_IQN_NAME(tgt) && !IS_EUI_NAME(tgt)) {
642 642 (void) fprintf(stderr, gettext("Invalid name %s"),
643 643 tgt);
644 644 (void) fprintf(stderr, "\n");
645 645 return (EINVAL);
646 646 }
647 647 }
648 648
649 649 ret = it_config_load(&cfg);
650 650 if (ret != 0) {
651 651 output_config_error(ret,
652 652 gettext("Error retrieving iSCSI target configuration"));
653 653 goto done;
654 654 }
655 655
656 656 did_it_config_load = B_TRUE;
657 657
658 658 ret = it_tgt_create(cfg, &tgtp, tgt);
659 659 if (ret != 0) {
660 660 if (ret == EFAULT) {
661 661 (void) fprintf(stderr,
662 662 gettext("Invalid iSCSI name %s"), tgt);
663 663 (void) fprintf(stderr, "\n");
664 664 } else if (ret == EEXIST) {
665 665 (void) fprintf(stderr,
666 666 gettext("iSCSI target %s already configured"),
667 667 tgt);
668 668 (void) fprintf(stderr, "\n");
669 669 } else if (ret == E2BIG) {
670 670 (void) fprintf(stderr,
671 671 gettext("Maximum of %d iSCSI targets"),
672 672 MAX_TARGETS);
673 673 (void) fprintf(stderr, "\n");
674 674 } else {
675 675 output_config_error(ret,
676 676 gettext("Error creating target"));
677 677 }
678 678
679 679 goto done;
680 680 }
681 681
682 682 /* set the target portal group tags */
683 683 ret = nvlist_lookup_string_array(proplist, "tpg-tag", &tags,
684 684 &count);
685 685
686 686 if (ret == ENOENT) {
687 687 /* none specified. is this ok? */
688 688 ret = 0;
689 689 } else if (ret != 0) {
690 690 output_config_error(ret, gettext("Internal error"));
691 691 goto done;
692 692 }
693 693
694 694 /* special case, don't set any TPGs */
695 695 if (tags && (count == 1) && (strcmp("default", tags[0]) == 0)) {
696 696 count = 0;
697 697 }
698 698
699 699 for (i = 0; i < count; i++) {
700 700 if (!tags[i]) {
701 701 continue;
702 702 }
703 703
704 704 /* see that all referenced groups are already defined */
705 705 tpg = cfg->config_tpg_list;
706 706 while (tpg != NULL) {
707 707 if (strcmp(tags[i], tpg->tpg_name) == 0) {
708 708 break;
709 709 }
710 710
711 711 tpg = tpg->tpg_next;
712 712 }
713 713 if (tpg == NULL) {
714 714 (void) fprintf(stderr,
715 715 gettext("Invalid tpg-tag %s, tag not defined"),
716 716 tags[i]);
717 717 (void) fprintf(stderr, "\n");
718 718 ret = 1;
719 719 goto done;
720 720 }
721 721
722 722 /* generate the tag number to use */
723 723 tag_name_to_num(tags[i], &tagid);
724 724
725 725 ret = it_tpgt_create(cfg, tgtp, &tpgt, tags[i], tagid);
726 726 if (ret != 0) {
727 727 (void) fprintf(stderr, gettext(
728 728 "Could not add target portal group tag %s: "),
729 729 tags[i]);
730 730 output_config_error(ret, NULL);
731 731 goto done;
732 732 }
733 733 tagid++;
734 734 }
735 735
736 736 /* remove the tags from the proplist before continuing */
737 737 if (tags) {
738 738 (void) nvlist_remove_all(proplist, "tpg-tag");
739 739 }
740 740
741 741 ret = it_tgt_setprop(cfg, tgtp, proplist, &errlist);
742 742 if (ret != 0) {
743 743 (void) fprintf(stderr,
744 744 gettext("Error setting target properties: %d"), ret);
745 745 (void) fprintf(stderr, "\n");
746 746 if (errlist) {
747 747 nvpair_t *nvp = NULL;
748 748 char *nn;
749 749 char *nv;
750 750
751 751 while ((nvp = nvlist_next_nvpair(errlist, nvp))
752 752 != NULL) {
753 753 nv = NULL;
754 754
755 755 nn = nvpair_name(nvp);
756 756 (void) nvpair_value_string(nvp, &nv);
757 757
758 758 if (nv != NULL) {
759 759 (void) fprintf(stderr, "\t%s: %s\n",
760 760 nn, nv);
761 761 }
762 762 }
763 763
764 764 nvlist_free(errlist);
765 765 }
766 766 goto done;
767 767 }
768 768
769 769 if (ret == 0) {
770 770 ret = it_config_commit(cfg);
771 771 STMF_STALE(ret);
772 772 }
773 773
774 774 done:
775 775 if (ret == 0) {
776 776 (void) printf(gettext("Target %s successfully created"),
777 777 tgtp->tgt_name);
778 778 (void) printf("\n");
779 779 }
780 780
781 781 if (did_it_config_load)
782 782 it_config_free(cfg);
783 783
784 784 return (ret);
785 785 }
786 786
787 787 int
788 788 list_target(char *tgt, boolean_t verbose, boolean_t script)
789 789 {
790 790 int ret;
791 791 it_config_t *cfg;
792 792 it_tgt_t *ptr;
793 793 boolean_t found = B_FALSE;
794 794 boolean_t first = B_TRUE;
795 795 boolean_t first_tag = B_TRUE;
796 796 char *gauth = "none";
797 797 char *galias = "-";
798 798 char *auth;
799 799 char *alias;
800 800 char *chapu;
801 801 char *chaps;
802 802 it_tpgt_t *tagp;
803 803 char *sec = "solaris.smf.read.stmf";
804 804 stmfDevid devid;
805 805 stmfSessionList *sess = NULL;
806 806 stmfTargetProperties props;
807 807 char *state;
808 808 int num_sessions;
809 809
810 810 ITADM_CHKAUTH(sec);
811 811
812 812 ret = it_config_load(&cfg);
813 813 if (ret != 0) {
814 814 output_config_error(ret,
815 815 gettext("Error retrieving iSCSI target configuration"));
816 816 return (ret);
817 817 }
818 818
819 819 ptr = cfg->config_tgt_list;
820 820
821 821 /* grab global defaults for auth, alias */
822 822 if (cfg->config_global_properties) {
823 823 (void) nvlist_lookup_string(cfg->config_global_properties,
824 824 "alias", &galias);
825 825 (void) nvlist_lookup_string(cfg->config_global_properties,
826 826 "auth", &gauth);
827 827 }
828 828
829 829 for (; ptr != NULL; ptr = ptr->tgt_next) {
830 830 if (found) {
831 831 break;
832 832 }
833 833
834 834 if (tgt) {
835 835 /*
836 836 * We do a case-insensitive match in case
837 837 * a non-lower case value got stored.
838 838 */
839 839 if (strcasecmp(tgt, ptr->tgt_name) != 0) {
840 840 continue;
841 841 } else {
842 842 found = B_TRUE;
843 843 }
844 844 }
845 845
846 846 state = "-";
847 847 num_sessions = 0;
848 848 sess = NULL;
849 849
850 850 /*
851 851 * make a best effort to retrieve target status and
852 852 * number of active sessions from STMF.
853 853 */
854 854 ret = stmfDevidFromIscsiName(ptr->tgt_name, &devid);
855 855 if (ret == STMF_STATUS_SUCCESS) {
856 856 ret = stmfGetTargetProperties(&devid, &props);
857 857 if (ret == STMF_STATUS_SUCCESS) {
858 858 if (props.status == STMF_TARGET_PORT_ONLINE) {
859 859 state = "online";
860 860 } else {
861 861 state = "offline";
862 862 }
863 863 }
864 864 }
865 865 if (ret == STMF_STATUS_SUCCESS) {
866 866 ret = stmfGetSessionList(&devid, &sess);
867 867 if (ret == STMF_STATUS_SUCCESS) {
868 868 num_sessions = sess->cnt;
869 869 free(sess);
870 870 }
871 871 }
872 872
873 873 /* reset ret so we don't return an error */
874 874 ret = 0;
875 875
876 876 if (!script && first) {
877 877 (void) printf("%-61s%-9s%-9s\n", "TARGET NAME",
878 878 "STATE", "SESSIONS");
879 879 first = B_FALSE;
880 880 }
881 881
882 882 if (!script) {
883 883 /*
884 884 * try not to let columns run into each other.
885 885 * Stick a tab after too-long fields.
886 886 * Lengths chosen are for the 'common' cases.
887 887 */
888 888 (void) printf("%-61s", ptr->tgt_name);
889 889 if (strlen(ptr->tgt_name) > 60) {
890 890 (void) printf("\t");
891 891 }
892 892 (void) printf("%-9s%-9d", state, num_sessions);
893 893 } else {
894 894 (void) printf("%s\t%s\t%d", ptr->tgt_name,
895 895 state, num_sessions);
896 896 }
897 897
898 898 if (!verbose) {
899 899 (void) printf("\n");
900 900 continue;
901 901 }
902 902
903 903 auth = gauth;
904 904 alias = galias;
905 905 chapu = "-";
906 906 chaps = "unset";
907 907
908 908 if (ptr->tgt_properties) {
909 909 (void) nvlist_lookup_string(ptr->tgt_properties,
910 910 "auth", &auth);
911 911 (void) nvlist_lookup_string(ptr->tgt_properties,
912 912 "alias", &alias);
913 913 if (nvlist_exists(ptr->tgt_properties,
914 914 "targetchapsecret")) {
915 915 chaps = "set";
916 916 }
917 917 (void) nvlist_lookup_string(ptr->tgt_properties,
918 918 "targetchapuser", &chapu);
919 919 }
920 920
921 921 if (!script) {
922 922 (void) printf("\n\t%-20s\t%s\n\t%-20s\t%s %s\n"
923 923 "\t%-20s\t%s\n\t%-20s\t%s\n\t%-20s\t",
924 924 "alias:", alias, "auth:", auth,
925 925 ((auth == gauth) ? "(defaults)" : ""),
926 926 "targetchapuser:",
927 927 chapu, "targetchapsecret:", chaps, "tpg-tags:");
928 928 } else {
929 929 (void) printf("\t%s\t%s %s\t%s\t%s\t",
930 930 alias, auth,
931 931 ((auth == gauth) ? "(defaults)" : ""),
932 932 chapu, chaps);
933 933 }
934 934
935 935 first_tag = B_TRUE;
936 936 tagp = ptr->tgt_tpgt_list;
937 937 for (; tagp != NULL; tagp = tagp->tpgt_next) {
938 938 if (!first_tag) {
939 939 (void) printf(",");
940 940 } else {
941 941 first_tag = B_FALSE;
942 942 }
943 943 (void) printf("%s = %d",
944 944 tagp->tpgt_tpg_name, tagp->tpgt_tag);
945 945 }
946 946
947 947 if (first_tag) {
948 948 /* didn't find any */
949 949 (void) printf("default");
950 950 }
951 951
952 952 (void) printf("\n");
953 953 }
954 954
955 955 if (tgt && (!found)) {
956 956 (void) fprintf(stderr,
957 957 gettext("Target %s not found!"), tgt);
958 958 (void) fprintf(stderr, "\n");
959 959 ret = 1;
960 960 }
961 961
962 962 it_config_free(cfg);
963 963
964 964 return (ret);
965 965 }
966 966
967 967 int
968 968 delete_target(char *tgt, boolean_t force)
969 969 {
970 970 int ret;
971 971 it_config_t *cfg;
972 972 it_tgt_t *ptr;
973 973 char *sec = "solaris.smf.modify.stmf";
974 974
975 975 ITADM_CHKAUTH(sec);
976 976
977 977 if (!tgt) {
978 978 (void) fprintf(stderr, "%s\n",
979 979 gettext("Error, no target specified"));
980 980 return (EINVAL);
981 981 }
982 982
983 983 ret = it_config_load(&cfg);
984 984 if (ret != 0) {
985 985 output_config_error(ret,
986 986 gettext("Error retrieving iSCSI target configuration"));
987 987 return (ret);
988 988 }
989 989
990 990 ptr = cfg->config_tgt_list;
991 991 while (ptr) {
992 992 /*
993 993 * We do a case-insensitive match in case
994 994 * a non-lower case value got stored.
995 995 */
996 996 if (strcasecmp(ptr->tgt_name, tgt) == 0) {
997 997 break;
998 998 }
999 999
1000 1000 ptr = ptr->tgt_next;
1001 1001 }
1002 1002
1003 1003 if (ptr) {
1004 1004 ret = it_tgt_delete(cfg, ptr, force);
1005 1005
1006 1006 if (ret != 0) {
1007 1007 if (ret == EBUSY) {
1008 1008 (void) fprintf(stderr,
1009 1009 gettext("The target is online or busy. "
1010 1010 "Use the -f (force) option, or "
1011 1011 "'stmfadm offline-target %s'"), tgt);
1012 1012 (void) fprintf(stderr, "\n");
1013 1013 } else {
1014 1014 output_config_error(ret, gettext(
1015 1015 "Error deleting target"));
1016 1016 }
1017 1017 }
1018 1018
1019 1019 if (ret == 0) {
1020 1020 ret = it_config_commit(cfg);
1021 1021 STMF_STALE(ret);
1022 1022 }
1023 1023 } else {
1024 1024 (void) fprintf(stderr,
1025 1025 gettext("Target %s not found"), tgt);
1026 1026 (void) fprintf(stderr, "\n");
1027 1027 ret = 1;
1028 1028 }
1029 1029
1030 1030 it_config_free(cfg);
1031 1031
1032 1032 return (ret);
1033 1033 }
1034 1034
1035 1035 static int
1036 1036 modify_target(char *tgt, char *newname, nvlist_t *proplist)
1037 1037 {
1038 1038 int ret;
1039 1039 it_config_t *cfg = NULL;
1040 1040 it_tgt_t *ptr = NULL;
1041 1041 it_tgt_t *tgtp = NULL;
1042 1042 char **tags = NULL;
1043 1043 uint32_t count = 0;
1044 1044 nvlist_t *errlist = NULL;
1045 1045 int i;
1046 1046 it_tpg_t *tpg = NULL;
1047 1047 uint16_t tagid;
1048 1048 it_tpgt_t *tpgt = NULL;
1049 1049 char *sec = "solaris.smf.modify.stmf";
1050 1050 boolean_t did_it_config_load = B_FALSE;
1051 1051
1052 1052 ITADM_CHKAUTH(sec);
1053 1053
1054 1054 /* XXX: Do we need to offline anything here too? */
1055 1055
1056 1056 if (!tgt) {
1057 1057 (void) fprintf(stderr, "%s\n",
1058 1058 gettext("Error, no target specified"));
1059 1059 ret = EINVAL;
1060 1060 goto done;
1061 1061 }
1062 1062
1063 1063 ret = it_config_load(&cfg);
1064 1064 if (ret != 0) {
1065 1065 output_config_error(ret,
1066 1066 gettext("Error retrieving iSCSI target configuration"));
1067 1067 goto done;
1068 1068 }
1069 1069
1070 1070 did_it_config_load = B_TRUE;
1071 1071
1072 1072 /*
1073 1073 * If newname is specified, ensure it is a valid name.
1074 1074 */
1075 1075 if (newname) {
1076 1076 if (!validate_iscsi_name(newname)) {
1077 1077 (void) fprintf(stderr,
1078 1078 gettext("Invalid iSCSI name %s"), newname);
1079 1079 (void) fprintf(stderr, "\n");
1080 1080 ret = 1;
1081 1081 goto done;
1082 1082 }
1083 1083 }
1084 1084
1085 1085 /*
1086 1086 * Loop through to verify that the target to be modified truly
1087 1087 * exists. If this target is to be renamed, ensure the new
1088 1088 * name is not already in use.
1089 1089 */
1090 1090 ptr = cfg->config_tgt_list;
1091 1091 while (ptr) {
1092 1092 /*
1093 1093 * Does a target with the new name already exist?
1094 1094 */
1095 1095 if (newname &&
1096 1096 (strcasecmp(newname, ptr->tgt_name) == 0)) {
1097 1097 (void) fprintf(stderr,
1098 1098 gettext("A target with name %s already exists"),
1099 1099 newname);
1100 1100 (void) fprintf(stderr, "\n");
1101 1101 ret = 1;
1102 1102 goto done;
1103 1103 }
1104 1104
1105 1105 if (strcasecmp(ptr->tgt_name, tgt) == 0) {
1106 1106 tgtp = ptr;
1107 1107 }
1108 1108
1109 1109 ptr = ptr ->tgt_next;
1110 1110 }
1111 1111
1112 1112 if (!tgtp) {
1113 1113 (void) fprintf(stderr,
1114 1114 gettext("Target %s not found"), tgt);
1115 1115 (void) fprintf(stderr, "\n");
1116 1116 ret = EINVAL;
1117 1117 goto done;
1118 1118 }
1119 1119
1120 1120 /* set the target portal group tags */
1121 1121 ret = nvlist_lookup_string_array(proplist, "tpg-tag", &tags,
1122 1122 &count);
1123 1123
1124 1124 if (ret == ENOENT) {
1125 1125 /* none specified. is this ok? */
1126 1126 ret = 0;
1127 1127 } else if (ret != 0) {
1128 1128 output_config_error(ret, gettext("Internal error"));
1129 1129 goto done;
1130 1130 }
1131 1131
1132 1132 /* special case, remove all explicit TPGs, and don't add any */
1133 1133 if (tags && (count == 1) && (strcmp("default", tags[0]) == 0)) {
1134 1134 count = 0;
1135 1135 }
1136 1136
1137 1137 for (i = 0; i < count; i++) {
1138 1138 if (!tags || !tags[i]) {
1139 1139 continue;
1140 1140 }
1141 1141
1142 1142 /* see that all referenced groups are already defined */
1143 1143 tpg = cfg->config_tpg_list;
1144 1144 while (tpg != NULL) {
1145 1145 if (strcmp(tags[i], tpg->tpg_name) == 0) {
1146 1146 break;
1147 1147 }
1148 1148 tpg = tpg->tpg_next;
1149 1149 }
1150 1150 if (tpg == NULL) {
1151 1151 (void) fprintf(stderr,
1152 1152 gettext("Invalid tpg-name %s: not defined"),
1153 1153 tags[i]);
1154 1154 (void) fprintf(stderr, "\n");
1155 1155 ret = 1;
1156 1156 goto done;
1157 1157 }
1158 1158 }
1159 1159
1160 1160 /*
1161 1161 * don't recreate tags that are already associated,
1162 1162 * remove tags not requested.
1163 1163 */
1164 1164 if (tags) {
1165 1165 tpgt = tgtp->tgt_tpgt_list;
1166 1166 while (tpgt) {
1167 1167 for (i = 0; i < count; i++) {
1168 1168 if (!tags[i]) {
1169 1169 continue;
1170 1170 }
1171 1171
1172 1172 if (strcmp(tpgt->tpgt_tpg_name, tags[i])
1173 1173 == 0) {
1174 1174 /* non-null tags will be created */
1175 1175 tags[i] = NULL;
1176 1176 break;
1177 1177 }
1178 1178 }
1179 1179 if (i == count) {
1180 1180 /* one to remove */
1181 1181 it_tpgt_t *ptr = tpgt;
1182 1182
1183 1183 tpgt = ptr->tpgt_next;
1184 1184 it_tpgt_delete(cfg, tgtp, ptr);
1185 1185 } else {
1186 1186 tpgt = tpgt->tpgt_next;
1187 1187 }
1188 1188 }
1189 1189 }
1190 1190
1191 1191 /* see if there are any left to add */
1192 1192 for (i = 0; i < count; i++) {
1193 1193 if (!tags || !tags[i]) {
1194 1194 continue;
1195 1195 }
1196 1196
1197 1197 /* generate the tag number to use */
1198 1198 tag_name_to_num(tags[i], &tagid);
1199 1199
1200 1200 ret = it_tpgt_create(cfg, tgtp, &tpgt, tags[i], tagid);
1201 1201 if (ret != 0) {
1202 1202 if (ret == E2BIG) {
1203 1203 (void) fprintf(stderr, "%s\n",
1204 1204 gettext("Error, no portal tag available"));
1205 1205 } else {
1206 1206 (void) fprintf(stderr, gettext(
1207 1207 "Could not add target portal group"
1208 1208 " tag %s: "), tags[i]);
1209 1209 output_config_error(ret, NULL);
1210 1210 }
1211 1211 goto done;
1212 1212 }
1213 1213 }
1214 1214
1215 1215 /* remove the tags from the proplist before continuing */
1216 1216 (void) nvlist_remove_all(proplist, "tpg-tag");
1217 1217
1218 1218 /*
1219 1219 * Rename this target, if requested. Save the old name in
1220 1220 * the property list, so the kernel knows this is a renamed
1221 1221 * target, and not a new one.
1222 1222 */
1223 1223 if (newname && (strlen(newname) > 0)) {
1224 1224 ret = nvlist_add_string(proplist, "oldtargetname",
1225 1225 tgtp->tgt_name);
1226 1226 if (ret != 0) {
1227 1227 output_config_error(ret,
1228 1228 gettext("Error renaming target"));
1229 1229 goto done;
1230 1230 }
1231 1231 (void) strlcpy(tgtp->tgt_name, newname,
1232 1232 sizeof (tgtp->tgt_name));
1233 1233 }
1234 1234
1235 1235 ret = it_tgt_setprop(cfg, tgtp, proplist, &errlist);
1236 1236 if (ret != 0) {
1237 1237 (void) fprintf(stderr,
1238 1238 gettext("Error setting target properties: %d"), ret);
1239 1239 (void) fprintf(stderr, "\n");
1240 1240 if (errlist) {
1241 1241 nvpair_t *nvp = NULL;
1242 1242 char *nn;
1243 1243 char *nv;
1244 1244
1245 1245 while ((nvp = nvlist_next_nvpair(errlist, nvp))
1246 1246 != NULL) {
1247 1247 nv = NULL;
1248 1248
1249 1249 nn = nvpair_name(nvp);
1250 1250 (void) nvpair_value_string(nvp, &nv);
1251 1251
1252 1252 if (nv != NULL) {
1253 1253 (void) fprintf(stderr, "\t%s: %s\n",
1254 1254 nn, nv);
1255 1255 }
1256 1256 }
1257 1257
1258 1258 nvlist_free(errlist);
1259 1259 }
1260 1260 goto done;
1261 1261 }
1262 1262
1263 1263 if (ret == 0) {
1264 1264 ret = it_config_commit(cfg);
1265 1265 STMF_STALE(ret);
1266 1266 }
1267 1267
1268 1268 done:
1269 1269 if (ret == 0) {
1270 1270 (void) printf(gettext("Target %s successfully modified"),
1271 1271 tgtp->tgt_name);
1272 1272 (void) printf("\n");
1273 1273 }
1274 1274
1275 1275 if (did_it_config_load)
1276 1276 it_config_free(cfg);
1277 1277
1278 1278 return (ret);
1279 1279 }
1280 1280
1281 1281 int
1282 1282 create_tpg(char *tpg, int addrc, char **addrs)
1283 1283 {
1284 1284 int ret;
1285 1285 it_config_t *cfg;
1286 1286 it_tpg_t *tpgp;
1287 1287 int count = 0;
1288 1288 it_portal_t *ptl;
1289 1289 char *sec = "solaris.smf.modify.stmf";
1290 1290 int i = 0;
1291 1291
1292 1292 ITADM_CHKAUTH(sec);
1293 1293
1294 1294 if (!tpg) {
1295 1295 (void) fprintf(stderr, "%s\n",
1296 1296 gettext("Error, no target portal group specified"));
1297 1297 return (EINVAL);
1298 1298 }
1299 1299
1300 1300 if (strlen(tpg) > (MAX_TPG_NAMELEN - 1)) {
1301 1301 (void) fprintf(stderr,
1302 1302 gettext("Target Portal Group name must be no longer "
1303 1303 "than %d characters"), (MAX_TPG_NAMELEN - 1));
1304 1304 (void) fprintf(stderr, "\n");
1305 1305 return (EINVAL);
1306 1306 }
1307 1307
1308 1308 if (!addrs || (addrc <= 0)) {
1309 1309 (void) fprintf(stderr, "%s\n",
1310 1310 gettext("Error, no portal addresses specified"));
1311 1311 return (EINVAL);
1312 1312 }
1313 1313
1314 1314 ret = it_config_load(&cfg);
1315 1315 if (ret != 0) {
1316 1316 output_config_error(ret,
1317 1317 gettext("Error retrieving iSCSI target configuration"));
1318 1318 return (ret);
1319 1319 }
1320 1320
1321 1321 tpgp = cfg->config_tpg_list;
1322 1322 while (tpgp != NULL) {
1323 1323 if (strcmp(tpgp->tpg_name, tpg) == 0) {
1324 1324 (void) fprintf(stderr,
1325 1325 gettext("Target Portal Group %s already exists"),
1326 1326 tpg);
1327 1327 (void) fprintf(stderr, "\n");
1328 1328 it_config_free(cfg);
1329 1329 return (1);
1330 1330 }
1331 1331 tpgp = tpgp->tpg_next;
1332 1332 }
1333 1333
1334 1334 /*
1335 1335 * Ensure that the addrs don't contain commas.
1336 1336 */
1337 1337 for (i = 0; i < addrc; i++) {
1338 1338 if (strchr(addrs[i], ',')) {
1339 1339 (void) fprintf(stderr,
1340 1340 gettext("Bad portal name %s"),
1341 1341 addrs[i]);
1342 1342 (void) fprintf(stderr, "\n");
1343 1343
1344 1344 it_config_free(cfg);
1345 1345 return (EINVAL);
1346 1346 }
1347 1347 }
1348 1348
1349 1349 /*
1350 1350 * Create the portal group and first portal
1351 1351 */
1352 1352 ret = it_tpg_create(cfg, &tpgp, tpg, addrs[count]);
1353 1353 if (ret != 0) {
1354 1354 if (ret == EEXIST) {
1355 1355 (void) fprintf(stderr,
1356 1356 gettext("Portal %s already in use"),
1357 1357 addrs[count]);
1358 1358 (void) fprintf(stderr, "\n");
1359 1359 } else {
1360 1360 output_config_error(ret, gettext("Could not create the "
1361 1361 "target portal group"));
1362 1362 }
1363 1363 it_config_free(cfg);
1364 1364 return (ret);
1365 1365 }
1366 1366
1367 1367 /*
1368 1368 * Add the remaining portals
1369 1369 */
1370 1370 for (count = 1; count < addrc; count++) {
1371 1371 if (!addrs[count]) {
1372 1372 continue;
1373 1373 }
1374 1374
1375 1375 ret = it_portal_create(cfg, tpgp, &ptl, addrs[count]);
1376 1376 if (ret != 0) {
1377 1377 if (ret == EEXIST) {
1378 1378 (void) fprintf(stderr,
1379 1379 gettext("Portal %s already in use"),
1380 1380 addrs[count]);
1381 1381 (void) fprintf(stderr, "\n");
1382 1382 } else {
1383 1383 (void) fprintf(stderr,
1384 1384 gettext("Error adding portal %s: "),
1385 1385 addrs[count]);
1386 1386 output_config_error(ret, NULL);
1387 1387 break;
1388 1388 }
1389 1389 }
1390 1390 }
1391 1391
1392 1392 if (ret == 0) {
1393 1393 ret = it_config_commit(cfg);
1394 1394 STMF_STALE(ret);
1395 1395 }
1396 1396
1397 1397 it_config_free(cfg);
1398 1398
1399 1399 return (ret);
1400 1400 }
1401 1401
1402 1402 static int
1403 1403 list_tpg(char *tpg, boolean_t verbose, boolean_t script)
1404 1404 {
1405 1405 int ret;
1406 1406 it_config_t *cfg;
1407 1407 it_tpg_t *ptr;
1408 1408 boolean_t found = B_FALSE;
1409 1409 it_portal_t *portal;
1410 1410 boolean_t first = B_TRUE;
1411 1411 boolean_t first_portal;
1412 1412 char *pstr;
1413 1413 char *sec = "solaris.smf.read.stmf";
1414 1414
1415 1415 ITADM_CHKAUTH(sec);
1416 1416
1417 1417 ret = it_config_load(&cfg);
1418 1418 if (ret != 0) {
1419 1419 output_config_error(ret,
1420 1420 gettext("Error retrieving iSCSI target configuration"));
1421 1421 return (ret);
1422 1422 }
1423 1423
1424 1424 ptr = cfg->config_tpg_list;
1425 1425
1426 1426 for (; ptr != NULL; ptr = ptr->tpg_next) {
1427 1427 if (found) {
1428 1428 break;
1429 1429 }
1430 1430
1431 1431 if (tpg) {
1432 1432 if (strcmp(tpg, ptr->tpg_name) != 0) {
1433 1433 continue;
1434 1434 } else {
1435 1435 found = B_TRUE;
1436 1436 }
1437 1437 }
1438 1438
1439 1439 if (!script && first) {
1440 1440 (void) printf("%-30s%-9s\n", "TARGET PORTAL GROUP",
1441 1441 "PORTAL COUNT");
1442 1442 first = B_FALSE;
1443 1443 }
1444 1444
1445 1445 if (!script) {
1446 1446 (void) printf("%-30s", ptr->tpg_name);
1447 1447 if (strlen(ptr->tpg_name) > 30) {
1448 1448 (void) printf("\t");
1449 1449 }
1450 1450 (void) printf("%-9d", ptr->tpg_portal_count);
1451 1451 } else {
1452 1452 (void) printf("%s\t%d", ptr->tpg_name,
1453 1453 ptr->tpg_portal_count);
1454 1454 }
1455 1455
1456 1456 if (!verbose) {
1457 1457 (void) printf("\n");
1458 1458 continue;
1459 1459 }
1460 1460
1461 1461 if (!script) {
1462 1462 (void) printf("\n portals:");
1463 1463 }
1464 1464
1465 1465 first_portal = B_TRUE;
1466 1466
1467 1467 portal = ptr->tpg_portal_list;
1468 1468 for (; portal != NULL; portal = portal->portal_next) {
1469 1469 ret = sockaddr_to_str(&(portal->portal_addr), &pstr);
1470 1470 if (ret != 0) {
1471 1471 /* invalid addr? */
1472 1472 continue;
1473 1473 }
1474 1474 if (!first_portal) {
1475 1475 (void) printf(",");
1476 1476 } else {
1477 1477 (void) printf("\t");
1478 1478 first_portal = B_FALSE;
1479 1479 }
1480 1480
1481 1481 (void) printf("%s", pstr);
1482 1482 free(pstr);
1483 1483 }
1484 1484
1485 1485 if (first_portal) {
1486 1486 /* none found */
1487 1487 (void) printf("\t<none>");
1488 1488 }
1489 1489
1490 1490 (void) printf("\n");
1491 1491 }
1492 1492
1493 1493 if (tpg && (!found)) {
1494 1494 (void) fprintf(stderr,
1495 1495 gettext("Target Portal Group %s not found!\n"), tpg);
1496 1496 (void) fprintf(stderr, "\n");
1497 1497 ret = 1;
1498 1498 }
1499 1499
1500 1500 it_config_free(cfg);
1501 1501
1502 1502 return (ret);
1503 1503 }
1504 1504
1505 1505 static int
1506 1506 delete_tpg(char *tpg, boolean_t force)
1507 1507 {
1508 1508 int ret;
1509 1509 it_config_t *cfg;
1510 1510 it_tpg_t *ptpg = NULL;
1511 1511 char *sec = "solaris.smf.modify.stmf";
1512 1512
1513 1513 ITADM_CHKAUTH(sec);
1514 1514
1515 1515 if (!tpg) {
1516 1516 (void) fprintf(stderr, "%s\n",
1517 1517 gettext("Error, no target portal group specified"));
1518 1518 return (EINVAL);
1519 1519 }
1520 1520
1521 1521 ret = it_config_load(&cfg);
1522 1522 if (ret != 0) {
1523 1523 output_config_error(ret,
1524 1524 gettext("Error retrieving iSCSI target configuration"));
1525 1525 return (ret);
1526 1526 }
1527 1527
1528 1528 ptpg = cfg->config_tpg_list;
1529 1529 for (; ptpg != NULL; ptpg = ptpg->tpg_next) {
1530 1530 if (strcmp(tpg, ptpg->tpg_name) == 0) {
1531 1531 break;
1532 1532 }
1533 1533 }
1534 1534
1535 1535 if (!ptpg) {
1536 1536 (void) fprintf(stderr,
1537 1537 gettext("Target portal group %s does not exist"),
1538 1538 tpg);
1539 1539 (void) fprintf(stderr, "\n");
1540 1540 ret = 1;
1541 1541 } else {
1542 1542 ret = it_tpg_delete(cfg, ptpg, force);
1543 1543 if (ret == EBUSY) {
1544 1544 (void) fprintf(stderr, "%s\n",
1545 1545 gettext(
1546 1546 "Target portal group associated with one or more "
1547 1547 "targets. Cannot delete."));
1548 1548 } else if (ret != 0) {
1549 1549 output_config_error(ret, gettext("Could not delete "
1550 1550 "target portal group"));
1551 1551 }
1552 1552
1553 1553 if (ret == 0) {
1554 1554 ret = it_config_commit(cfg);
1555 1555 STMF_STALE(ret);
1556 1556 }
1557 1557 }
1558 1558
1559 1559 it_config_free(cfg);
1560 1560
1561 1561 return (ret);
1562 1562 }
1563 1563
1564 1564 static int
1565 1565 modify_initiator(char *ini, nvlist_t *proplist, boolean_t create)
1566 1566 {
1567 1567 int ret;
1568 1568 it_config_t *cfg;
1569 1569 it_ini_t *inip;
1570 1570 nvlist_t *errlist = NULL;
1571 1571 nvpair_t *nvp = NULL;
1572 1572 char *sec = "solaris.smf.modify.stmf";
1573 1573 boolean_t changed = B_TRUE;
1574 1574
1575 1575 ITADM_CHKAUTH(sec);
1576 1576
1577 1577 if (!ini) {
1578 1578 (void) fprintf(stderr, "%s\n",
1579 1579 gettext("Error, no initiator specified"));
1580 1580 return (EINVAL);
1581 1581 } else if (create) {
1582 1582 /*
1583 1583 * validate input name - what are the rules for EUI
1584 1584 * and IQN values?
1585 1585 */
1586 1586 if (!IS_IQN_NAME(ini) && !IS_EUI_NAME(ini)) {
1587 1587 (void) fprintf(stderr, gettext("Invalid name %s"),
1588 1588 ini);
1589 1589 (void) fprintf(stderr, "\n");
1590 1590 return (EINVAL);
1591 1591 }
1592 1592 }
1593 1593
1594 1594 /*
1595 1595 * See if any properties were actually specified.
1596 1596 */
1597 1597 if (proplist) {
1598 1598 nvp = nvlist_next_nvpair(proplist, nvp);
1599 1599 }
1600 1600
1601 1601 if ((nvp == NULL) && !create) {
1602 1602 changed = B_FALSE;
1603 1603 }
1604 1604
1605 1605 /*
1606 1606 * If no properties, and this is really a modify op, verify
1607 1607 * that the requested initiator exists, but then don't do anything.
1608 1608 * Modifying non-existent is an error; doing nothing to a defined
1609 1609 * initiator is not.
1610 1610 */
1611 1611
1612 1612 ret = it_config_load(&cfg);
1613 1613 if (ret != 0) {
1614 1614 output_config_error(ret,
1615 1615 gettext("Error retrieving iSCSI target configuration"));
1616 1616 return (ret);
1617 1617 }
1618 1618
1619 1619 inip = cfg->config_ini_list;
1620 1620 while (inip) {
1621 1621 if (strcasecmp(inip->ini_name, ini) == 0) {
1622 1622 break;
1623 1623 }
1624 1624
1625 1625 inip = inip->ini_next;
1626 1626 }
1627 1627
1628 1628 if (create) {
1629 1629 if (inip) {
1630 1630 (void) fprintf(stderr,
1631 1631 gettext("Initiator %s already exists"),
1632 1632 inip->ini_name);
1633 1633 (void) fprintf(stderr, "\n");
1634 1634 ret = EINVAL;
1635 1635 } else {
1636 1636 ret = it_ini_create(cfg, &inip, ini);
1637 1637 if (ret != 0) {
1638 1638 if (ret == EFAULT) {
1639 1639 (void) fprintf(stderr,
1640 1640 gettext("Invalid iSCSI name %s"),
1641 1641 ini);
1642 1642 (void) fprintf(stderr, "\n");
1643 1643 } else {
1644 1644 output_config_error(ret, gettext(
1645 1645 "Error creating initiator"));
1646 1646 }
1647 1647 }
1648 1648 }
1649 1649 } else if (!inip) {
1650 1650 ret = ENOENT;
1651 1651 (void) fprintf(stderr,
1652 1652 gettext("Error, initiator %s not found"),
1653 1653 ini);
1654 1654 (void) fprintf(stderr, "\n");
1655 1655 }
1656 1656
1657 1657 if ((ret == 0) && nvp) {
1658 1658 ret = it_ini_setprop(inip, proplist, &errlist);
1659 1659
1660 1660 if (ret != 0) {
1661 1661 (void) fprintf(stderr,
1662 1662 gettext("Error setting initiator properties: %d"),
1663 1663 ret);
1664 1664 (void) fprintf(stderr, "\n");
1665 1665 if (errlist) {
1666 1666 nvpair_t *nvp = NULL;
1667 1667 char *nn;
1668 1668 char *nv;
1669 1669
1670 1670 while ((nvp = nvlist_next_nvpair(errlist, nvp))
1671 1671 != NULL) {
1672 1672 nv = NULL;
1673 1673
1674 1674 nn = nvpair_name(nvp);
1675 1675 (void) nvpair_value_string(nvp, &nv);
1676 1676
1677 1677 if (nv != NULL) {
1678 1678 (void) fprintf(stderr,
1679 1679 "\t%s: %s\n", nn, nv);
1680 1680 }
1681 1681 }
1682 1682
1683 1683 nvlist_free(errlist);
1684 1684 }
1685 1685 }
1686 1686 }
1687 1687
1688 1688 if ((ret == 0) && changed) {
1689 1689 ret = it_config_commit(cfg);
1690 1690 STMF_STALE(ret);
1691 1691 }
1692 1692
1693 1693 it_config_free(cfg);
1694 1694
1695 1695 return (ret);
1696 1696 }
1697 1697
1698 1698 static int
1699 1699 list_initiator(char *ini, boolean_t verbose, boolean_t script) /* ARGSUSED */
1700 1700 {
1701 1701 int ret;
1702 1702 it_config_t *cfg;
1703 1703 it_ini_t *ptr;
1704 1704 boolean_t found = B_FALSE;
1705 1705 boolean_t first = B_TRUE;
1706 1706 char *isecret;
1707 1707 char *iuser;
1708 1708 char *sec = "solaris.smf.read.stmf";
1709 1709
1710 1710 ITADM_CHKAUTH(sec);
1711 1711
1712 1712 ret = it_config_load(&cfg);
1713 1713 if (ret != 0) {
1714 1714 output_config_error(ret,
1715 1715 gettext("Error retrieving iSCSI target configuration"));
1716 1716 return (ret);
1717 1717 }
1718 1718
1719 1719 ptr = cfg->config_ini_list;
1720 1720
1721 1721 for (; ptr != NULL; ptr = ptr->ini_next) {
1722 1722 isecret = "unset";
1723 1723 iuser = "<none>";
1724 1724
1725 1725 if (found) {
1726 1726 break;
1727 1727 }
1728 1728
1729 1729 if (ini) {
1730 1730 if (strcasecmp(ini, ptr->ini_name) != 0) {
1731 1731 continue;
1732 1732 } else {
1733 1733 found = B_TRUE;
1734 1734 }
1735 1735 }
1736 1736
1737 1737 if (ptr->ini_properties) {
1738 1738 if (nvlist_exists(ptr->ini_properties, "chapsecret")) {
1739 1739 isecret = "set";
1740 1740 }
1741 1741 (void) nvlist_lookup_string(ptr->ini_properties,
1742 1742 "chapuser", &iuser);
1743 1743
1744 1744 }
1745 1745
1746 1746 /* there's nothing to print for verbose yet */
1747 1747 if (!script && first) {
1748 1748 (void) printf("%-61s%-10s%-7s\n", "INITIATOR NAME",
1749 1749 "CHAPUSER", "SECRET");
1750 1750 first = B_FALSE;
1751 1751 }
1752 1752
1753 1753 if (!script) {
1754 1754 /*
1755 1755 * try not to let columns run into each other.
1756 1756 * Stick a tab after too-long fields.
1757 1757 * Lengths chosen are for the 'common' cases.
1758 1758 */
1759 1759 (void) printf("%-61s", ptr->ini_name);
1760 1760
1761 1761 if (strlen(ptr->ini_name) > 60) {
1762 1762 (void) printf("\t");
1763 1763 }
1764 1764
1765 1765 (void) printf("%-15s", iuser);
1766 1766 if (strlen(iuser) >= 15) {
1767 1767 (void) printf("\t");
1768 1768 }
1769 1769
1770 1770 (void) printf("%-4s", isecret);
1771 1771 } else {
1772 1772 (void) printf("%s\t%s\t%s", ptr->ini_name,
1773 1773 iuser, isecret);
1774 1774 }
1775 1775
1776 1776 (void) printf("\n");
1777 1777 }
1778 1778
1779 1779 if (ini && (!found)) {
1780 1780 (void) fprintf(stderr,
1781 1781 gettext("Initiator %s not found!"), ini);
1782 1782 (void) fprintf(stderr, "\n");
1783 1783 ret = 1;
1784 1784 }
1785 1785
1786 1786 it_config_free(cfg);
1787 1787
1788 1788 return (ret);
1789 1789 }
1790 1790
1791 1791 int
1792 1792 delete_initiator(char *ini)
1793 1793 {
1794 1794 int ret;
1795 1795 it_config_t *cfg;
1796 1796 it_ini_t *ptr;
1797 1797 char *sec = "solaris.smf.modify.stmf";
1798 1798
1799 1799 ITADM_CHKAUTH(sec);
1800 1800
1801 1801 if (!ini) {
1802 1802 (void) fprintf(stderr, "%s\n",
1803 1803 gettext("Error, no initiator specified"));
1804 1804 return (EINVAL);
1805 1805 }
1806 1806
1807 1807 ret = it_config_load(&cfg);
1808 1808 if (ret != 0) {
1809 1809 output_config_error(ret,
1810 1810 gettext("Error retrieving iSCSI target configuration"));
1811 1811 return (ret);
1812 1812 }
1813 1813
1814 1814 ptr = cfg->config_ini_list;
1815 1815 while (ptr) {
1816 1816 if (strcasecmp(ptr->ini_name, ini) == 0) {
1817 1817 break;
1818 1818 }
1819 1819
1820 1820 ptr = ptr->ini_next;
1821 1821 }
1822 1822
1823 1823 if (ptr) {
1824 1824 it_ini_delete(cfg, ptr);
1825 1825
1826 1826 ret = it_config_commit(cfg);
1827 1827 STMF_STALE(ret);
1828 1828 } else {
1829 1829 (void) fprintf(stderr,
1830 1830 gettext("Initiator %s not found"), ini);
1831 1831 (void) fprintf(stderr, "\n");
1832 1832 ret = 1;
1833 1833 }
1834 1834
1835 1835 return (ret);
1836 1836 }
1837 1837
1838 1838 static int
1839 1839 modify_defaults(nvlist_t *proplist)
1840 1840 {
1841 1841 int ret;
1842 1842 it_config_t *cfg;
1843 1843 nvlist_t *errlist = NULL;
1844 1844 nvpair_t *nvp = NULL;
1845 1845 char *sec = "solaris.smf.modify.stmf";
1846 1846
1847 1847 ITADM_CHKAUTH(sec);
1848 1848
1849 1849 if (proplist) {
1850 1850 /* make sure at least one property is specified */
1851 1851 nvp = nvlist_next_nvpair(proplist, nvp);
1852 1852 }
1853 1853
1854 1854 if (nvp == NULL) {
1855 1855 /* empty list */
1856 1856 (void) fprintf(stderr, "%s\n",
1857 1857 gettext("Error, no properties specified"));
1858 1858 return (EINVAL);
1859 1859 }
1860 1860
1861 1861 ret = it_config_load(&cfg);
1862 1862 if (ret != 0) {
1863 1863 output_config_error(ret,
1864 1864 gettext("Error retrieving iSCSI target configuration"));
1865 1865 return (ret);
1866 1866 }
1867 1867
1868 1868 ret = it_config_setprop(cfg, proplist, &errlist);
1869 1869 if (ret != 0) {
1870 1870 (void) fprintf(stderr,
1871 1871 gettext("Error setting global properties: %d"),
1872 1872 ret);
1873 1873 (void) fprintf(stderr, "\n");
1874 1874 if (errlist) {
1875 1875 nvpair_t *nvp = NULL;
1876 1876 char *nn;
1877 1877 char *nv;
1878 1878
1879 1879 while ((nvp = nvlist_next_nvpair(errlist, nvp))
1880 1880 != NULL) {
1881 1881 nv = NULL;
1882 1882
1883 1883 nn = nvpair_name(nvp);
1884 1884 (void) nvpair_value_string(nvp, &nv);
1885 1885
1886 1886 if (nv != NULL) {
1887 1887 (void) fprintf(stderr, "\t%s: %s\n",
1888 1888 nn, nv);
1889 1889 }
1890 1890 }
1891 1891
1892 1892 nvlist_free(errlist);
1893 1893 }
1894 1894 }
1895 1895
1896 1896 if (ret == 0) {
1897 1897 ret = it_config_commit(cfg);
1898 1898 STMF_STALE(ret);
1899 1899 }
1900 1900
1901 1901 it_config_free(cfg);
1902 1902
1903 1903 return (ret);
1904 1904 }
1905 1905
1906 1906 static int
1907 1907 list_defaults(boolean_t script)
1908 1908 {
1909 1909 int ret;
1910 1910 it_config_t *cfg;
1911 1911 nvlist_t *nvl;
1912 1912 char *alias = "<none>";
1913 1913 char *auth = "<none>";
1914 1914 char *isns = "disabled";
1915 1915 char **isvrs = NULL;
1916 1916 uint32_t scount = 0;
1917 1917 char *rsvr = "<none>";
1918 1918 char *rsecret = "unset";
1919 1919 boolean_t val = B_FALSE;
1920 1920 int i;
1921 1921 char *sec = "solaris.smf.read.stmf";
1922 1922
1923 1923 ITADM_CHKAUTH(sec);
1924 1924
1925 1925 ret = it_config_load(&cfg);
1926 1926 if (ret != 0) {
1927 1927 output_config_error(ret,
1928 1928 gettext("Error retrieving iSCSI target configuration"));
1929 1929 return (ret);
1930 1930 }
1931 1931
1932 1932 nvl = cfg->config_global_properties;
1933 1933
1934 1934 /* look up all possible options */
1935 1935 (void) nvlist_lookup_string(nvl, "alias", &alias);
1936 1936 (void) nvlist_lookup_string(nvl, "auth", &auth);
1937 1937 (void) nvlist_lookup_boolean_value(nvl, "isns", &val);
1938 1938 if (val == B_TRUE) {
1939 1939 isns = "enabled";
1940 1940 }
1941 1941 (void) nvlist_lookup_string_array(nvl, "isnsserver", &isvrs,
1942 1942 &scount);
1943 1943 (void) nvlist_lookup_string(nvl, "radiusserver", &rsvr);
1944 1944 if (nvlist_exists(nvl, "radiussecret")) {
1945 1945 rsecret = "set";
1946 1946 }
1947 1947
1948 1948 if (!script) {
1949 1949 (void) printf("%s:\n\n",
1950 1950 gettext("iSCSI Target Default Properties"));
1951 1951 }
1952 1952
1953 1953 if (script) {
1954 1954 (void) printf("%s\t%s\t%s\t%s\t%s\t",
1955 1955 alias, auth, rsvr, rsecret, isns);
1956 1956 } else {
1957 1957 (void) printf("%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n%-15s\t%s\n"
1958 1958 "%-15s\t%s\n%-15s\t",
1959 1959 "alias:", alias, "auth:", auth, "radiusserver:",
1960 1960 rsvr, "radiussecret:", rsecret, "isns:", isns,
1961 1961 "isnsserver:");
1962 1962 }
1963 1963
1964 1964 for (i = 0; i < scount; i++) {
1965 1965 if (!isvrs || !isvrs[i]) {
1966 1966 break;
1967 1967 }
1968 1968 if (i > 0) {
1969 1969 (void) printf(",");
1970 1970 }
1971 1971 (void) printf("%s", isvrs[i]);
1972 1972 }
1973 1973
1974 1974 if (i == 0) {
1975 1975 (void) printf("%s", "<none>");
1976 1976 }
1977 1977
1978 1978 (void) printf("\n");
1979 1979
1980 1980 it_config_free(cfg);
1981 1981
1982 1982 return (0);
1983 1983 }
1984 1984
1985 1985 static int
1986 1986 itadm_get_password(nvlist_t *nvl, char *key, char *passfile,
1987 1987 char *phrase)
1988 1988 {
1989 1989 int ret = 0;
1990 1990 char *pass;
1991 1991 char buf[1024];
1992 1992 int fd;
1993 1993 struct stat64 sbuf;
1994 1994 size_t rd;
1995 1995
1996 1996 if (!nvl || !key) {
1997 1997 return (EINVAL);
1998 1998 }
1999 1999
2000 2000 if (passfile) {
2001 2001 ret = stat64(passfile, &sbuf);
2002 2002 if ((ret != 0) || (!S_ISREG(sbuf.st_mode))) {
2003 2003 (void) fprintf(stderr,
2004 2004 gettext("Invalid secret file %s"),
2005 2005 passfile);
2006 2006 (void) fprintf(stderr, "\n");
2007 2007 return (EBADF);
2008 2008 }
2009 2009
2010 2010 fd = open64(passfile, O_RDONLY);
2011 2011 if (fd == -1) {
2012 2012 ret = errno;
2013 2013 (void) fprintf(stderr,
2014 2014 gettext("Could not open secret file %s: "),
2015 2015 passfile);
2016 2016 output_config_error(ret, NULL);
2017 2017 return (ret);
2018 2018 }
2019 2019
2020 2020 rd = read(fd, buf, sbuf.st_size);
2021 2021 (void) close(fd);
2022 2022
2023 2023 if (rd != sbuf.st_size) {
2024 2024 ret = EIO;
2025 2025 (void) fprintf(stderr,
2026 2026 gettext("Could not read secret file %s: "),
2027 2027 passfile);
2028 2028 output_config_error(ret, NULL);
2029 2029 return (ret);
2030 2030 }
2031 2031
2032 2032 /* ensure buf is properly terminated */
2033 2033 buf[rd] = '\0';
2034 2034
2035 2035 /* if last char is a newline, strip it off */
2036 2036 if (buf[rd - 1] == '\n') {
2037 2037 buf[rd - 1] = '\0';
2038 2038 }
2039 2039
2040 2040 /* validate length */
2041 2041 if ((strlen(buf) > 255) || (strlen(buf) < 12)) {
2042 2042 (void) fprintf(stderr, "%s\n",
2043 2043 gettext(
2044 2044 "Secret must be between 12 and 255 characters"));
2045 2045 return (EINVAL);
2046 2046 }
2047 2047 } else {
2048 2048 /* prompt for secret */
2049 2049 if (!phrase) {
2050 2050 return (EINVAL);
2051 2051 }
2052 2052
2053 2053 pass = getpassphrase(phrase);
2054 2054 if (!pass) {
2055 2055 ret = errno;
2056 2056 output_config_error(ret,
2057 2057 gettext("Could not read secret"));
2058 2058 return (ret);
2059 2059 }
2060 2060
2061 2061 /* validate length */
2062 2062 if ((strlen(pass) > 255) || (strlen(pass) < 12)) {
2063 2063 (void) fprintf(stderr, "%s\n",
2064 2064 gettext(
2065 2065 "Secret must be between 12 and 255 characters"));
2066 2066 return (EINVAL);
2067 2067 }
2068 2068
2069 2069 (void) strlcpy(buf, pass, sizeof (buf));
2070 2070
2071 2071 /* confirm entered secret */
2072 2072 pass = getpassphrase(gettext("Re-enter secret: "));
2073 2073 if (!pass) {
2074 2074 ret = errno;
2075 2075 output_config_error(ret,
2076 2076 gettext("Could not read secret"));
2077 2077 return (ret);
2078 2078 }
2079 2079
2080 2080 if (strcmp(buf, pass) != 0) {
2081 2081 ret = EINVAL;
2082 2082 (void) fprintf(stderr, "%s\n",
2083 2083 gettext("Secret validation failed"));
2084 2084 return (ret);
2085 2085 }
2086 2086
2087 2087 }
2088 2088
2089 2089 ret = nvlist_add_string(nvl, key, buf);
2090 2090
2091 2091 return (ret);
2092 2092 }
2093 2093
2094 2094 static int
2095 2095 itadm_opt_to_arr(nvlist_t *nvl, char *key, char *opt, uint32_t *num)
2096 2096 {
2097 2097 int count;
2098 2098 char *bufp;
2099 2099 char **arr;
2100 2100
2101 2101 if (!opt || !key || !nvl) {
2102 2102 return (EINVAL);
2103 2103 }
2104 2104
2105 2105 bufp = opt;
2106 2106 count = 1;
2107 2107
2108 2108 for (;;) {
2109 2109 bufp = strchr(bufp, ',');
2110 2110 if (!bufp) {
2111 2111 break;
2112 2112 }
2113 2113 bufp++;
2114 2114 count++;
2115 2115 }
2116 2116
2117 2117 arr = calloc(count, sizeof (char *));
2118 2118 if (!arr) {
2119 2119 return (ENOMEM);
2120 2120 }
2121 2121
2122 2122 bufp = opt;
2123 2123 /* set delimiter to comma */
2124 2124 (void) bufsplit(",", 0, NULL);
2125 2125
2126 2126 /* split up that buf! */
2127 2127 (void) bufsplit(bufp, count, arr);
2128 2128
2129 2129 /* if requested, return the number of array members found */
2130 2130 if (num) {
2131 2131 *num = count;
2132 2132 }
2133 2133
2134 2134 return (nvlist_add_string_array(nvl, key, arr, count));
2135 2135 }
2136 2136
2137 2137 static void
2138 2138 tag_name_to_num(char *tagname, uint16_t *tagnum)
2139 2139 {
2140 2140 ulong_t id;
2141 2141 char *ptr = NULL;
2142 2142
2143 2143 if (!tagname || !tagnum) {
2144 2144 return;
2145 2145 }
2146 2146
2147 2147 *tagnum = 0;
2148 2148
2149 2149 id = strtoul(tagname, &ptr, 10);
2150 2150
2151 2151 /* Must be entirely numeric and in-range */
2152 2152 if (ptr && (*ptr != '\0')) {
2153 2153 return;
2154 2154 }
2155 2155
2156 2156 if ((id <= UINT16_MAX) && (id > 1)) {
2157 2157 *tagnum = (uint16_t)id;
2158 2158 }
2159 2159 }
2160 2160
2161 2161 /*
2162 2162 * Print error messages to stderr for errnos and expected stmf errors.
2163 2163 * This function should generally not be used for cases where the
2164 2164 * calling code can generate a more detailed error message based on
2165 2165 * the contextual knowledge of the meaning of specific errors.
2166 2166 */
2167 2167 static void
2168 2168 output_config_error(int error, char *msg)
2169 2169 {
2170 2170
2171 2171 if (msg) {
2172 2172 (void) fprintf(stderr, "%s: ", msg);
2173 2173 }
2174 2174
2175 2175 if (error & STMF_STATUS_ERROR) {
2176 2176 switch (error) {
2177 2177 case STMF_ERROR_PERM:
2178 2178 (void) fprintf(stderr, "%s",
2179 2179 gettext("permission denied"));
2180 2180 break;
2181 2181 case STMF_ERROR_BUSY:
2182 2182 (void) fprintf(stderr, "%s",
2183 2183 gettext("resource busy"));
2184 2184 break;
2185 2185 case STMF_ERROR_NOMEM:
2186 2186 (void) fprintf(stderr, "%s",
2187 2187 gettext("out of memory"));
2188 2188 break;
2189 2189 case STMF_ERROR_SERVICE_NOT_FOUND:
2190 2190 (void) fprintf(stderr, "%s",
2191 2191 gettext("STMF service not found"));
2192 2192 break;
2193 2193 case STMF_ERROR_SERVICE_DATA_VERSION:
2194 2194 (void) fprintf(stderr, "%s",
2195 2195 gettext("STMF service version incorrect"));
2196 2196 break;
2197 2197 case STMF_ERROR_PROV_DATA_STALE:
2198 2198 (void) fprintf(stderr, "%s",
2199 2199 gettext("Configuration changed during processing. "
2200 2200 "Check the configuration, then retry this "
2201 2201 "command if appropriate."));
2202 2202 break;
2203 2203 default:
2204 2204 (void) fprintf(stderr, "%s", gettext("unknown error"));
2205 2205 break;
2206 2206 }
2207 2207 } else {
2208 2208 char buf[80] = "";
2209 2209
2210 2210 (void) strerror_r(error, buf, sizeof (buf));
2211 2211 (void) fprintf(stderr, "%s", buf);
2212 2212 }
2213 2213
2214 2214 (void) fprintf(stderr, "\n");
2215 2215 }
↓ open down ↓ |
2083 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX