1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 #include <stdlib.h> 25 #include <stdio.h> 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <fcntl.h> 29 #include <unistd.h> 30 #include <errno.h> 31 #include <string.h> 32 #include <getopt.h> 33 #include <strings.h> 34 #include <ctype.h> 35 #include <libnvpair.h> 36 #include <libintl.h> 37 #include <libgen.h> 38 #include <pwd.h> 39 #include <auth_attr.h> 40 #include <secdb.h> 41 #include <libscf.h> 42 #include <limits.h> 43 #include <locale.h> 44 #include <dirent.h> 45 46 #include <libstmf.h> 47 #include <libsrpt.h> 48 49 /* SMF service info */ 50 #define STMF_SVC "svc:/system/stmf:default" 51 52 #define STMF_STALE(ret) {\ 53 if (ret == STMF_ERROR_PROV_DATA_STALE) {\ 54 (void) fprintf(stderr, "%s\n",\ 55 gettext("Configuration changed during processing. "\ 56 "Check the configuration, then retry this command "\ 57 "if appropriate."));\ 58 }\ 59 } 60 61 #define SRPTADM_CHKAUTH(sec) {\ 62 if (!chkauthattr(sec, srptadm_uname)) {\ 63 (void) fprintf(stderr,\ 64 gettext("Error, operation requires authorization %s"),\ 65 sec);\ 66 (void) fprintf(stderr, "\n");\ 67 return (1);\ 68 }\ 69 } 70 71 #define PROPS_FORMAT " %-20s: " 72 73 static struct option srptadm_long[] = { 74 {"enable", no_argument, NULL, 'e'}, 75 {"disable", no_argument, NULL, 'd'}, 76 {"reset", no_argument, NULL, 'r'}, 77 {"help", no_argument, NULL, '?'}, 78 {"help", no_argument, NULL, 'h'}, 79 {NULL, 0, NULL, 0} 80 }; 81 82 static char m_def[] = "srptadm modify-defaults [-e] [-d]"; 83 static char l_def[] = "srptadm list-defaults"; 84 static char s_tgt[] = "srptadm modify-target [-e] [-d] [-r] <hca>"; 85 static char l_tgt[] = "srptadm list-target [<hca>]"; 86 87 /* keep the order of this enum in the same order as the 'subcmds' struct */ 88 typedef enum { 89 MODIFY_DEFAULT, 90 LIST_DEFAULT, 91 MODIFY_TARGET, 92 LIST_TARGET, 93 NULL_SUBCMD /* must always be last! */ 94 } srptadm_sub_t; 95 96 typedef struct { 97 char *name; 98 char *shortopts; 99 char *usemsg; 100 } srptadm_subcmds_t; 101 102 static srptadm_subcmds_t subcmds[] = { 103 {"modify-defaults", "edh?", m_def}, 104 {"list-defaults", "h?", l_def}, 105 {"modify-target", "edrh?", s_tgt}, 106 {"list-target", "h?", l_tgt}, 107 {NULL, ":h?", NULL}, 108 }; 109 110 /* used for checking if user is authorized */ 111 static char *srptadm_uname = NULL; 112 113 /* prototypes */ 114 static int get_local_hcas(char **hcaArray, int count); 115 static int print_target_props(char *hca); 116 static int list_target(char *hca); 117 static int disable_target(char *hca); 118 static int reset_target(char *hca); 119 static int list_defaults(void); 120 static int enable_target(char *hca); 121 static int set_default_state(boolean_t enabled); 122 123 int 124 main(int argc, char *argv[]) 125 { 126 int ret = 0; 127 int idx = NULL_SUBCMD; 128 char c; 129 int newargc = argc; 130 char **newargv = NULL; 131 char *objp; 132 int srptind = 0; 133 struct passwd *pwd = NULL; 134 char *smfstate = NULL; 135 boolean_t reset = B_FALSE; 136 int dflag = 0; 137 int eflag = 0; 138 139 (void) setlocale(LC_ALL, ""); 140 (void) textdomain(TEXT_DOMAIN); 141 142 if (argc < 2) { 143 ret = 1; 144 goto usage_error; 145 } 146 147 for (idx = 0; subcmds[idx].name != NULL; idx++) { 148 if (strcmp(argv[1], subcmds[idx].name) == 0) { 149 break; 150 } 151 } 152 153 /* get the caller's user name for subsequent chkauthattr() calls */ 154 pwd = getpwuid(getuid()); 155 if (pwd == NULL) { 156 (void) fprintf(stderr, "%s\n", 157 gettext("Could not determine callers user name.")); 158 return (1); 159 } 160 161 srptadm_uname = strdup(pwd->pw_name); 162 163 /* increment past command & subcommand */ 164 newargc--; 165 newargv = &(argv[1]); 166 167 while ((ret == 0) && (newargv)) { 168 c = getopt_long(newargc, newargv, subcmds[idx].shortopts, 169 srptadm_long, &srptind); 170 if (c == -1) { 171 break; 172 } 173 174 switch (c) { 175 case 0: 176 /* flag set by getopt */ 177 break; 178 case 'd': 179 dflag++; 180 break; 181 case 'e': 182 eflag++; 183 break; 184 case 'r': 185 reset = B_TRUE; 186 break; 187 case '?': 188 /* 189 * '?' is returned for both unrecognized 190 * options and if explicitly provided on 191 * the command line. The latter should 192 * be handled the same as -h. 193 */ 194 if (strcmp(newargv[optind-1], "-?") != 0) { 195 (void) fprintf(stderr, 196 gettext("Unrecognized option %s"), 197 newargv[optind-1]); 198 (void) fprintf(stderr, "\n"); 199 ret = 1; 200 } 201 goto usage_error; 202 case 'h': 203 goto usage_error; 204 case ':': 205 (void) fprintf(stderr, 206 gettext("Option %s requires an operand."), 207 newargv[optind-1]); 208 (void) fprintf(stderr, "\n"); 209 210 /* FALLTHROUGH */ 211 default: 212 ret = 1; 213 break; 214 } 215 } 216 217 if (ret != 0) { 218 goto usage_error; 219 } 220 221 /* after getopt() to allow handling of -h option */ 222 if ((srptadm_sub_t)idx == NULL_SUBCMD) { 223 (void) fprintf(stderr, "%s\n", 224 gettext("Error, no subcommand specified")); 225 ret = 1; 226 goto usage_error; 227 } 228 229 newargc -= optind; 230 if (newargc == 0) { 231 newargv = NULL; 232 objp = NULL; 233 } else { 234 newargv = &(newargv[optind]); 235 objp = newargv[0]; 236 } 237 238 if (objp == NULL) { 239 switch ((srptadm_sub_t)idx) { 240 case MODIFY_TARGET: 241 /* These subcommands need operands */ 242 ret = 1; 243 goto usage_error; 244 default: 245 break; 246 } 247 } 248 249 if (newargc > 1) { 250 switch ((srptadm_sub_t)idx) { 251 case MODIFY_TARGET: 252 case LIST_TARGET: 253 /* These subcommands should have at most one operand */ 254 ret = 1; 255 goto usage_error; 256 257 default: 258 break; 259 } 260 } 261 262 263 /* 264 * Make sure STMF service is enabled before proceeding. 265 */ 266 smfstate = smf_get_state(STMF_SVC); 267 if (!smfstate || 268 (strcmp(smfstate, SCF_STATE_STRING_ONLINE) != 0)) { 269 (void) fprintf(stderr, "%s\n", 270 gettext("The STMF service must be online " 271 "before running this command.")); 272 (void) fprintf(stderr, 273 gettext("Use 'svcadm enable -r %s'"), STMF_SVC); 274 (void) fprintf(stderr, "\n"); 275 (void) fprintf(stderr, "%s\n", 276 gettext("to enable the service and its prerequisite " 277 "services and/or")); 278 (void) fprintf(stderr, 279 gettext("'svcs -x %s' to determine why it is not online."), 280 STMF_SVC); 281 (void) fprintf(stderr, "\n"); 282 283 return (1); 284 } 285 286 switch ((srptadm_sub_t)idx) { 287 case MODIFY_DEFAULT: 288 if (eflag) { 289 ret = set_default_state(B_TRUE); 290 } else if (dflag) { 291 ret = set_default_state(B_FALSE); 292 } else { 293 ret = 1; 294 goto usage_error; 295 } 296 break; 297 case LIST_DEFAULT: 298 ret = list_defaults(); 299 break; 300 case MODIFY_TARGET: 301 if (reset) { 302 ret = reset_target(objp); 303 } else if (eflag) { 304 ret = enable_target(objp); 305 } else if (dflag) { 306 ret = disable_target(objp); 307 } else { 308 ret = 1; 309 goto usage_error; 310 } 311 break; 312 case LIST_TARGET: 313 ret = list_target(objp); 314 break; 315 default: 316 ret = 1; 317 goto usage_error; 318 } 319 320 if (ret != 0) { 321 (void) fprintf(stderr, 322 gettext("srptadm %s failed with error %d"), 323 subcmds[idx].name, ret); 324 (void) fprintf(stderr, "\n"); 325 } 326 return (ret); 327 328 usage_error: 329 if (subcmds[idx].name) { 330 (void) printf("%s\n", gettext(subcmds[idx].usemsg)); 331 } else { 332 /* overall usage */ 333 (void) printf("%s\n\n", gettext("srptadm usage:")); 334 for (idx = 0; subcmds[idx].name != NULL; idx++) { 335 if (!subcmds[idx].usemsg) { 336 continue; 337 } 338 (void) printf("\t%s\n", gettext(subcmds[idx].usemsg)); 339 } 340 } 341 342 return (ret); 343 } 344 345 static int 346 set_default_state(boolean_t enabled) 347 { 348 int ret; 349 char *sec = "solaris.smf.modify.stmf"; 350 351 SRPTADM_CHKAUTH(sec); 352 353 ret = srpt_SetDefaultState(enabled); 354 355 return (ret); 356 } 357 358 static int 359 enable_target(char *hca) 360 { 361 int ret; 362 char *sec = "solaris.smf.modify.stmf"; 363 364 SRPTADM_CHKAUTH(sec); 365 366 ret = srpt_SetTargetState(hca, B_TRUE); 367 368 return (ret); 369 } 370 371 static int 372 disable_target(char *hca) 373 { 374 int ret; 375 char *sec = "solaris.smf.modify.stmf"; 376 377 SRPTADM_CHKAUTH(sec); 378 379 ret = srpt_SetTargetState(hca, B_FALSE); 380 381 return (ret); 382 } 383 384 static int 385 reset_target(char *hca) 386 { 387 int ret; 388 char *sec = "solaris.smf.modify.stmf"; 389 390 SRPTADM_CHKAUTH(sec); 391 392 ret = srpt_ResetTarget(hca); 393 394 return (ret); 395 } 396 397 static int 398 list_defaults(void) 399 { 400 int ret; 401 char *sec = "solaris.smf.read.stmf"; 402 boolean_t enabled; 403 404 SRPTADM_CHKAUTH(sec); 405 406 /* only state set as default for now */ 407 ret = srpt_GetDefaultState(&enabled); 408 409 if (ret == 0) { 410 (void) printf("%s:\n\n", 411 gettext("SRP Target Service Default Properties")); 412 413 (void) printf(" %s:\t", 414 gettext("Target creation enabled by default")); 415 416 if (enabled) { 417 (void) printf("%s\n", gettext("true")); 418 } else { 419 (void) printf("%s\n", gettext("false")); 420 } 421 } 422 423 return (ret); 424 } 425 426 static int 427 list_target(char *hca) 428 { 429 int ret; 430 char *sec = "solaris.smf.read.stmf"; 431 char *hcaArr[1024]; /* way bigger than we'll ever see */ 432 int i; 433 434 SRPTADM_CHKAUTH(sec); 435 436 if (hca != NULL) { 437 ret = print_target_props(hca); 438 return (ret); 439 } 440 441 /* get list of HCAs configured on this system, from /dev/cfg */ 442 (void) memset(&hcaArr, 0, 1024 * sizeof (char *)); 443 444 ret = get_local_hcas(hcaArr, sizeof (hcaArr)); 445 if (ret == ETOOMANYREFS) { 446 (void) fprintf(stderr, "Internal error: too many HCAs\n"); 447 goto done; 448 } else if (ret != 0) { 449 (void) fprintf(stderr, "Error getting list of HCAs: %d\n", ret); 450 goto done; 451 } 452 453 for (i = 0; i < 1024; i++) { 454 if (hcaArr[i] == NULL) { 455 break; 456 } 457 ret = print_target_props(hcaArr[i]); 458 } 459 460 done: 461 for (i = 0; i < 1024; i++) { 462 if (hcaArr[i] == NULL) { 463 break; 464 } 465 free(hcaArr[i]); 466 } 467 468 return (ret); 469 } 470 471 static int 472 print_target_props(char *hca) 473 { 474 int ret; 475 boolean_t enabled; 476 char buf[32]; 477 char euibuf[64]; 478 uint64_t hcaguid; 479 stmfDevid devid; 480 stmfTargetProperties props; 481 char *state; 482 483 ret = srpt_NormalizeGuid(hca, buf, sizeof (buf), &hcaguid); 484 if (ret != 0) { 485 (void) fprintf(stderr, "Invalid target HCA: %s\n", 486 hca); 487 return (ret); 488 } 489 490 /* only property set is enabled */ 491 ret = srpt_GetTargetState(buf, &enabled); 492 if (ret != 0) { 493 (void) fprintf(stderr, 494 "Could not get enabled state for %s: %d\n", 495 buf, ret); 496 return (ret); 497 } 498 499 (void) printf("Target HCA %s:\n", buf); 500 501 (void) printf(PROPS_FORMAT, gettext("Enabled")); 502 503 if (enabled) { 504 (void) printf("%s\n", gettext("true")); 505 } else { 506 (void) printf("%s\n", gettext("false")); 507 } 508 509 state = "-"; 510 511 (void) snprintf(euibuf, sizeof (euibuf), "eui.%016llX", hcaguid); 512 513 ret = stmfDevidFromIscsiName(euibuf, &devid); 514 if (ret == STMF_STATUS_SUCCESS) { 515 ret = stmfGetTargetProperties(&devid, &props); 516 if (ret == STMF_STATUS_SUCCESS) { 517 if (props.status == STMF_TARGET_PORT_ONLINE) { 518 state = "online"; 519 } else { 520 state = "offline"; 521 } 522 } 523 } 524 525 (void) printf(PROPS_FORMAT, gettext("SRP Target Name")); 526 (void) printf("%s\n", euibuf); 527 (void) printf(PROPS_FORMAT, gettext("Operational Status")); 528 (void) printf("%s\n", state); 529 530 (void) printf("\n"); 531 532 return (0); 533 } 534 535 536 static int 537 get_local_hcas(char **hcaArray, int count) 538 { 539 int ret = 0; 540 char *cfgdir = "/dev/cfg"; 541 DIR *dirp = NULL; 542 struct dirent *entry; 543 int idx = 0; 544 char *bufp; 545 546 if ((hcaArray == NULL) || (count == 0)) { 547 return (EINVAL); 548 } 549 550 dirp = opendir(cfgdir); 551 552 if (dirp == NULL) { 553 ret = errno; 554 (void) fprintf(stderr, "Could not open %s: errno %d\n", 555 cfgdir, ret); 556 return (ret); 557 } 558 559 while ((entry = readdir(dirp)) != NULL) { 560 bufp = &entry->d_name[0]; 561 562 if (strncmp(bufp, "hca:", 4) != 0) { 563 continue; 564 } 565 566 bufp += 4; 567 568 hcaArray[idx] = strdup(bufp); 569 if (hcaArray[idx] == NULL) { 570 ret = ENOMEM; 571 break; 572 } 573 idx++; 574 575 if (idx >= count) { 576 ret = ETOOMANYREFS; 577 break; 578 } 579 } 580 581 return (ret); 582 } 583