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