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
main(int argc,char * argv[])124 main(int argc, char *argv[])
125 {
126 int ret = 0;
127 int idx = NULL_SUBCMD;
128 int 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
set_default_state(boolean_t enabled)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
enable_target(char * hca)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
disable_target(char * hca)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
reset_target(char * hca)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
list_defaults(void)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
list_target(char * hca)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
print_target_props(char * hca)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
get_local_hcas(char ** hcaArray,int count)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