xref: /illumos-gate/usr/src/cmd/srptadm/srptadm.c (revision d8e10381a0083d7717710b0db7e64707bc0f3ff8)
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