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