xref: /illumos-gate/usr/src/cmd/dfs.cmds/sharectl/sharectl.c (revision 3448eae2e9d99e7fadeb43056eb8e788c7ea93be)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2016 Nexenta Systems, Inc.
27  */
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <getopt.h>
35 #include <libgen.h>
36 
37 #include "libshare.h"
38 #include <sharemgr.h>
39 
40 #include <libintl.h>
41 #include <locale.h>
42 
43 static int run_command(char *, int, char **, sa_handle_t);
44 static void sub_command_help(char *proto);
45 
46 static void
47 global_help()
48 {
49 	(void) printf(gettext("usage: sharectl <subcommand> [<options>]\n"));
50 	sub_command_help(NULL);
51 }
52 
53 int
54 main(int argc, char *argv[])
55 {
56 	int c;
57 	int help = 0;
58 	int rval;
59 	char *command;
60 	sa_handle_t handle;
61 
62 	/*
63 	 * make sure locale and gettext domain is setup
64 	 */
65 	(void) setlocale(LC_ALL, "");
66 	(void) textdomain(TEXT_DOMAIN);
67 
68 	handle = sa_init(SA_INIT_CONTROL_API);
69 
70 	while ((c = getopt(argc, argv, "h?")) != EOF) {
71 		switch (c) {
72 		case '?':
73 		case 'h':
74 			help = 1;
75 			break;
76 		default:
77 			(void) printf(gettext("Invalid option: %c\n"), c);
78 		}
79 	}
80 	if (optind == argc || help) {
81 		/* no subcommand */
82 		global_help();
83 		exit(0);
84 	}
85 	optind = 1;
86 
87 	/*
88 	 * now have enough to parse rest of command line
89 	 */
90 	command = argv[optind];
91 	rval = run_command(command, argc - optind, argv + optind, handle);
92 
93 	sa_fini(handle);
94 	return (rval);
95 }
96 
97 char *
98 sc_get_usage(sc_usage_t index)
99 {
100 	char *ret = NULL;
101 
102 	switch (index) {
103 	case USAGE_CTL_DELSECT:
104 		ret = gettext("delsect\t<section> <proto>");
105 		break;
106 	case USAGE_CTL_GET:
107 		ret = gettext("get\t[-p <property>]... <proto>");
108 		break;
109 	case USAGE_CTL_SET:
110 		ret = gettext("set\t{-p <property>=<value>}... <proto>");
111 		break;
112 	case USAGE_CTL_STATUS:
113 		ret = gettext("status\t[<proto>]...");
114 		break;
115 	}
116 	return (ret);
117 }
118 
119 /*ARGSUSED*/
120 static int
121 sc_get(sa_handle_t handle, int flags, int argc, char *argv[])
122 {
123 	char *proto = NULL;
124 	struct options *optlist = NULL;
125 	int ret = SA_OK;
126 	int c;
127 	sa_protocol_properties_t propset, propsect;
128 	sa_property_t prop;
129 	char *section, *value, *name;
130 	int first = 1;
131 
132 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
133 		switch (c) {
134 		case 'p':
135 			ret = add_opt(&optlist, optarg, 1);
136 			if (ret != SA_OK) {
137 				(void) printf(gettext(
138 				    "Problem with property: %s\n"), optarg);
139 				return (SA_NO_MEMORY);
140 			}
141 			break;
142 		default:
143 			(void) printf(gettext("usage: %s\n"),
144 			    sc_get_usage(USAGE_CTL_GET));
145 			return (SA_SYNTAX_ERR);
146 		case '?':
147 		case 'h':
148 			(void) printf(gettext("usage: %s\n"),
149 			    sc_get_usage(USAGE_CTL_GET));
150 			return (SA_OK);
151 		}
152 	}
153 
154 	if (optind >= argc) {
155 		(void) printf(gettext("usage: %s\n"),
156 		    sc_get_usage(USAGE_CTL_GET));
157 		(void) printf(gettext("\tprotocol must be specified.\n"));
158 		return (SA_INVALID_PROTOCOL);
159 	}
160 
161 	proto = argv[optind];
162 	if (!sa_valid_protocol(proto)) {
163 		(void) printf(gettext("Invalid protocol specified: %s\n"),
164 		    proto);
165 		return (SA_INVALID_PROTOCOL);
166 	}
167 	propset = sa_proto_get_properties(proto);
168 	if (propset == NULL)
169 		return (ret);
170 
171 	if (optlist == NULL) {
172 		/* Display all known properties for this protocol */
173 		for (propsect = sa_get_protocol_section(propset, NULL);
174 		    propsect != NULL;
175 		    propsect = sa_get_next_protocol_section(propsect, NULL)) {
176 			section = sa_get_property_attr(propsect,
177 			    "name");
178 			/*
179 			 * If properties are organized into sections, as
180 			 * in the SMB client, print the section name.
181 			 */
182 			if (sa_proto_get_featureset(proto) &
183 			    SA_FEATURE_HAS_SECTIONS) {
184 				if (!first)
185 					(void) printf("\n");
186 				first = 0;
187 				(void) printf("[%s]\n",
188 				    section != NULL ? section : "");
189 			}
190 			if (section != NULL)
191 				sa_free_attr_string(section);
192 
193 			/* Display properties for this section */
194 			for (prop = sa_get_protocol_property(propsect, NULL);
195 			    prop != NULL;
196 			    prop = sa_get_next_protocol_property(prop, NULL)) {
197 
198 				/* get and display the property and value */
199 				name = sa_get_property_attr(prop, "type");
200 				value = NULL;
201 				if (name != NULL) {
202 					value = sa_get_property_attr(prop,
203 					    "value");
204 					(void) printf(gettext("%s=%s\n"), name,
205 					    value != NULL ? value : "");
206 				}
207 				if (value != NULL)
208 					sa_free_attr_string(value);
209 				if (name != NULL)
210 					sa_free_attr_string(name);
211 			}
212 		}
213 	} else {
214 		struct options *opt;
215 
216 		/* list the specified option(s) */
217 		for (opt = optlist; opt != NULL; opt = opt->next) {
218 			int printed = 0;
219 
220 			for (propsect = sa_get_protocol_section(propset, NULL);
221 			    propsect != NULL;
222 			    propsect = sa_get_next_protocol_section(propsect,
223 			    NULL)) {
224 
225 				section = sa_get_property_attr(propsect,
226 				    "name");
227 				for (prop = sa_get_protocol_property(propsect,
228 				    opt->optname);
229 				    prop != NULL;
230 				    prop = sa_get_next_protocol_property(
231 				    propsect, opt->optname)) {
232 					value = sa_get_property_attr(prop,
233 					    "value");
234 					if (sa_proto_get_featureset(proto) &
235 					    SA_FEATURE_HAS_SECTIONS) {
236 						(void) printf(
237 						    gettext("[%s] %s=%s\n"),
238 						    section != NULL ?
239 						    section : "", opt->optname,
240 						    value != NULL ? value : "");
241 					} else {
242 						(void) printf(
243 						    gettext("%s=%s\n"),
244 						    opt->optname,
245 						    value != NULL ? value : "");
246 					}
247 					if (value != NULL)
248 						sa_free_attr_string(value);
249 					printed = 1;
250 				}
251 				if (section != NULL)
252 					sa_free_attr_string(section);
253 			}
254 			if (!printed) {
255 				(void) printf(gettext("%s: not defined\n"),
256 				    opt->optname);
257 				ret = SA_NO_SUCH_PROP;
258 			}
259 		}
260 	}
261 	return (ret);
262 }
263 
264 /*ARGSUSED*/
265 static int
266 sc_set(sa_handle_t handle, int flags, int argc, char *argv[])
267 {
268 	char *proto = NULL;
269 	struct options *optlist = NULL;
270 	sa_protocol_properties_t propsect;
271 	int ret = SA_OK;
272 	int c;
273 	int err;
274 	sa_protocol_properties_t propset;
275 	sa_property_t prop;
276 
277 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
278 		switch (c) {
279 		case 'p':
280 			ret = add_opt(&optlist, optarg, 0);
281 			if (ret != SA_OK) {
282 				(void) printf(gettext(
283 				    "Problem with property: %s\n"), optarg);
284 				return (SA_NO_MEMORY);
285 			}
286 			break;
287 		default:
288 			(void) printf(gettext("usage: %s\n"),
289 			    sc_get_usage(USAGE_CTL_SET));
290 			return (SA_SYNTAX_ERR);
291 		case '?':
292 		case 'h':
293 			(void) printf(gettext("usage: %s\n"),
294 			    sc_get_usage(USAGE_CTL_SET));
295 			return (SA_OK);
296 		}
297 	}
298 
299 	if (optind >= argc) {
300 		(void) printf(gettext("usage: %s\n"),
301 		    sc_get_usage(USAGE_CTL_SET));
302 		(void) printf(gettext("\tprotocol must be specified.\n"));
303 		return (SA_INVALID_PROTOCOL);
304 	}
305 
306 	proto = argv[optind];
307 	if (!sa_valid_protocol(proto)) {
308 		(void) printf(gettext("Invalid protocol specified: %s\n"),
309 		    proto);
310 		return (SA_INVALID_PROTOCOL);
311 	}
312 	propset = sa_proto_get_properties(proto);
313 	if (propset == NULL)
314 		return (ret);
315 
316 	if (optlist == NULL) {
317 		(void) printf(gettext("usage: %s\n"),
318 		    sc_get_usage(USAGE_CTL_SET));
319 		(void) printf(gettext(
320 		    "\tat least one property and value "
321 		    "must be specified\n"));
322 	} else {
323 		struct options *opt;
324 		char *section = NULL;
325 		/* fetch and change the specified option(s) */
326 		for (opt = optlist; opt != NULL; opt = opt->next) {
327 			if (strncmp("section", opt->optname, 7) == 0) {
328 				if (section != NULL)
329 					free(section);
330 				section = strdup(opt->optvalue);
331 				continue;
332 			}
333 			if (sa_proto_get_featureset(proto) &
334 			    SA_FEATURE_HAS_SECTIONS) {
335 				propsect = sa_get_protocol_section(propset,
336 				    section);
337 				prop = sa_get_protocol_property(propsect,
338 				    opt->optname);
339 			} else {
340 				prop = sa_get_protocol_property(propset,
341 				    opt->optname);
342 			}
343 			if (prop == NULL && sa_proto_get_featureset(proto) &
344 			    SA_FEATURE_ADD_PROPERTIES) {
345 				sa_property_t sect;
346 				sect = sa_create_section(section, NULL);
347 				sa_set_section_attr(sect, "type", proto);
348 				(void) sa_add_protocol_property(propset, sect);
349 				prop = sa_create_property(
350 				    opt->optname, opt->optvalue);
351 				(void) sa_add_protocol_property(sect, prop);
352 			}
353 			if (prop != NULL) {
354 				/*
355 				 * "err" is used in order to prevent
356 				 * setting ret to SA_OK if there has
357 				 * been a real error. We want to be
358 				 * able to return an error status on
359 				 * exit in that case. Error messages
360 				 * are printed for each error, so we
361 				 * only care on exit that there was an
362 				 * error and not the specific error
363 				 * value.
364 				 */
365 				err = sa_set_protocol_property(prop, section,
366 				    opt->optvalue);
367 				if (err != SA_OK) {
368 					(void) printf(gettext(
369 					    "Could not set property"
370 					    " %s: %s\n"),
371 					    opt->optname, sa_errorstr(err));
372 					ret = err;
373 				}
374 			} else {
375 				(void) printf(gettext("%s: not defined\n"),
376 				    opt->optname);
377 				ret = SA_NO_SUCH_PROP;
378 			}
379 		}
380 	}
381 	return (ret);
382 }
383 
384 static void
385 show_status(char *proto)
386 {
387 	char *status;
388 	uint64_t features;
389 
390 	status = sa_get_protocol_status(proto);
391 	features = sa_proto_get_featureset(proto);
392 	(void) printf("%s\t%s", proto, status ? gettext(status) : "-");
393 	if (status != NULL)
394 		free(status);
395 	/*
396 	 * Need to flag a client only protocol so test suites can
397 	 * remove it from consideration.
398 	 */
399 	if (!(features & SA_FEATURE_SERVER))
400 		(void) printf(" client");
401 	(void) printf("\n");
402 }
403 
404 static int
405 valid_proto(char **protos, int num, char *proto)
406 {
407 	int i;
408 	for (i = 0; i < num; i++)
409 		if (strcmp(protos[i], proto) == 0)
410 			return (1);
411 	return (0);
412 }
413 
414 /*ARGSUSED*/
415 static int
416 sc_status(sa_handle_t handle, int flags, int argc, char *argv[])
417 {
418 	char **protos;
419 	int ret = SA_OK;
420 	int c;
421 	int i;
422 	int num_proto;
423 	int verbose = 0;
424 
425 	while ((c = getopt(argc, argv, "?hv")) != EOF) {
426 		switch (c) {
427 		case 'v':
428 			verbose++;
429 			break;
430 		case '?':
431 		case 'h':
432 			(void) printf(gettext("usage: %s\n"),
433 			    sc_get_usage(USAGE_CTL_STATUS));
434 			return (SA_OK);
435 		default:
436 			(void) printf(gettext("usage: %s\n"),
437 			    sc_get_usage(USAGE_CTL_STATUS));
438 			return (SA_SYNTAX_ERR);
439 		}
440 	}
441 
442 	num_proto = sa_get_protocols(&protos);
443 	if (optind == argc) {
444 		/* status for all protocols */
445 		for (i = 0; i < num_proto; i++) {
446 			show_status(protos[i]);
447 		}
448 	} else {
449 		for (i = optind; i < argc; i++) {
450 			if (valid_proto(protos, num_proto, argv[i])) {
451 				show_status(argv[i]);
452 			} else {
453 				(void) printf(gettext("Invalid protocol: %s\n"),
454 				    argv[i]);
455 				ret = SA_INVALID_PROTOCOL;
456 			}
457 		}
458 	}
459 	if (protos != NULL)
460 		free(protos);
461 	return (ret);
462 }
463 
464 /*ARGSUSED*/
465 static int
466 sc_delsect(sa_handle_t handle, int flags, int argc, char *argv[])
467 {
468 	char *proto = NULL;
469 	char *section = NULL;
470 	sa_protocol_properties_t propset;
471 	sa_protocol_properties_t propsect;
472 	int ret = SA_OK;
473 	int c;
474 
475 	while ((c = getopt(argc, argv, "?h")) != EOF) {
476 		switch (c) {
477 		default:
478 			ret = SA_SYNTAX_ERR;
479 			/*FALLTHROUGH*/
480 		case '?':
481 		case 'h':
482 			(void) printf(gettext("usage: %s\n"),
483 			    sc_get_usage(USAGE_CTL_DELSECT));
484 			return (ret);
485 		}
486 		/*NOTREACHED*/
487 	}
488 
489 	section = argv[optind++];
490 
491 	if (optind >= argc) {
492 		(void) printf(gettext("usage: %s\n"),
493 		    sc_get_usage(USAGE_CTL_DELSECT));
494 		(void) printf(gettext(
495 		    "\tsection and protocol must be specified.\n"));
496 		return (SA_INVALID_PROTOCOL);
497 	}
498 
499 	proto = argv[optind];
500 	if (!sa_valid_protocol(proto)) {
501 		(void) printf(gettext("Invalid protocol specified: %s\n"),
502 		    proto);
503 		return (SA_INVALID_PROTOCOL);
504 	}
505 
506 	if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
507 		(void) printf(gettext("Protocol %s does not have sections\n"),
508 		    proto);
509 		return (SA_NOT_SUPPORTED);
510 	}
511 
512 	propset = sa_proto_get_properties(proto);
513 	if (propset == NULL) {
514 		(void) printf(gettext("Cannot get properties for %s\n"),
515 		    proto);
516 		return (SA_NO_PROPERTIES);
517 	}
518 
519 	propsect = sa_get_protocol_section(propset, section);
520 	if (propsect == NULL) {
521 		(void) printf(gettext("Cannot find section %s for proto %s\n"),
522 		    section, proto);
523 		return (SA_NO_SUCH_SECTION);
524 	}
525 
526 	ret = sa_proto_delete_section(proto, section);
527 
528 	return (ret);
529 }
530 
531 static sa_command_t commands[] = {
532 	{"delsect", 0, sc_delsect, USAGE_CTL_DELSECT},
533 	{"get", 0, sc_get, USAGE_CTL_GET},
534 	{"set", 0, sc_set, USAGE_CTL_SET},
535 	{"status", 0, sc_status, USAGE_CTL_STATUS},
536 	{NULL, 0, NULL, 0},
537 };
538 
539 /*ARGSUSED*/
540 void
541 sub_command_help(char *proto)
542 {
543 	int i;
544 
545 	for (i = 0; commands[i].cmdname != NULL; i++) {
546 		if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
547 			(void) printf("\t%s\n",
548 			    sc_get_usage((sc_usage_t)commands[i].cmdidx));
549 	}
550 }
551 
552 sa_command_t *
553 sa_lookup(char *cmd)
554 {
555 	int i;
556 	size_t len;
557 
558 	len = strlen(cmd);
559 	for (i = 0; commands[i].cmdname != NULL; i++) {
560 		if (strncmp(cmd, commands[i].cmdname, len) == 0)
561 			return (&commands[i]);
562 	}
563 	return (NULL);
564 }
565 
566 static int
567 run_command(char *command, int argc, char *argv[], sa_handle_t handle)
568 {
569 	sa_command_t *cmdvec;
570 	int ret;
571 
572 	/*
573 	 * To get here, we know there should be a command due to the
574 	 * preprocessing done earlier.  Need to find the protocol
575 	 * that is being affected. If no protocol, then it is ALL
576 	 * protocols.
577 	 *
578 	 * ??? do we really need the protocol at this level? it may be
579 	 * sufficient to let the commands look it up if needed since
580 	 * not all commands do proto specific things
581 	 *
582 	 * Known sub-commands are handled at this level. An unknown
583 	 * command will be passed down to the shared object that
584 	 * actually implements it. We can do this since the semantics
585 	 * of the common sub-commands is well defined.
586 	 */
587 
588 	cmdvec = sa_lookup(command);
589 	if (cmdvec == NULL) {
590 		(void) printf(gettext("command %s not found\n"), command);
591 		exit(1);
592 	}
593 	/*
594 	 * need to check priviledges and restrict what can be done
595 	 * based on least priviledge and sub-command.
596 	 */
597 	ret = cmdvec->cmdfunc(handle, 0, argc, argv);
598 	return (ret);
599 }
600