/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include "libshare.h" #include #include #include static int run_command(char *, int, char **, sa_handle_t); static void sub_command_help(char *proto); static void global_help() { (void) printf(gettext("usage: sharectl [options]\n")); sub_command_help(NULL); } int main(int argc, char *argv[]) { int c; int help = 0; int rval; char *command; sa_handle_t handle; /* * make sure locale and gettext domain is setup */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); handle = sa_init(SA_INIT_CONTROL_API); while ((c = getopt(argc, argv, "h?")) != EOF) { switch (c) { case '?': case 'h': help = 1; break; default: (void) printf(gettext("Invalid option: %c\n"), c); } } if (optind == argc || help) { /* no subcommand */ global_help(); exit(0); } optind = 1; /* * now have enough to parse rest of command line */ command = argv[optind]; rval = run_command(command, argc - optind, argv + optind, handle); sa_fini(handle); return (rval); } char * sc_get_usage(sc_usage_t index) { char *ret = NULL; switch (index) { case USAGE_CTL_GET: ret = gettext("get [-h | -p property ...] proto"); break; case USAGE_CTL_SET: ret = gettext("set [-h] -p property=value ... proto"); break; case USAGE_CTL_STATUS: ret = gettext("status [-h | proto ...]"); break; } return (ret); } /*ARGSUSED*/ static int sc_get(sa_handle_t handle, int flags, int argc, char *argv[]) { char *proto = NULL; struct options *optlist = NULL; int ret = SA_OK; int c; while ((c = getopt(argc, argv, "?hp:")) != EOF) { switch (c) { case 'p': ret = add_opt(&optlist, optarg, 1); if (ret != SA_OK) { (void) printf(gettext( "Problem with property: %s\n"), optarg); return (SA_NO_MEMORY); } break; default: (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_GET)); return (SA_SYNTAX_ERR); case '?': case 'h': (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_GET)); return (SA_OK); break; } } if (optind >= argc) { (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_GET)); (void) printf(gettext("\tprotocol must be specified.\n")); return (SA_INVALID_PROTOCOL); } proto = argv[optind]; if (sa_valid_protocol(proto)) { sa_protocol_properties_t propset; propset = sa_proto_get_properties(proto); if (propset != NULL) { sa_property_t prop; char *value; char *name; if (optlist == NULL) { /* * Display all known properties for * this protocol. */ for (prop = sa_get_protocol_property(propset, NULL); prop != NULL; prop = sa_get_next_protocol_property( prop)) { /* * Get and display the * property and value. */ name = sa_get_property_attr(prop, "type"); if (name != NULL) { value = sa_get_property_attr( prop, "value"); (void) printf(gettext( "%s=%s\n"), name, value != NULL ? value : ""); } if (value != NULL) sa_free_attr_string(value); if (name != NULL) sa_free_attr_string(name); } } else { struct options *opt; /* list the specified option(s) */ for (opt = optlist; opt != NULL; opt = opt->next) { prop = sa_get_protocol_property( propset, opt->optname); if (prop != NULL) { value = sa_get_property_attr( prop, "value"); (void) printf(gettext( "%s=%s\n"), opt->optname, value != NULL ? value : ""); sa_free_attr_string(value); } else { (void) printf(gettext( "%s: not defined\n"), opt->optname); ret = SA_NO_SUCH_PROP; } } } } } else { (void) printf(gettext("Invalid protocol specified: %s\n"), proto); ret = SA_INVALID_PROTOCOL; } return (ret); } /*ARGSUSED*/ static int sc_set(sa_handle_t handle, int flags, int argc, char *argv[]) { char *proto = NULL; struct options *optlist = NULL; int ret = SA_OK; int c; sa_protocol_properties_t propset; while ((c = getopt(argc, argv, "?hp:")) != EOF) { switch (c) { case 'p': ret = add_opt(&optlist, optarg, 0); if (ret != SA_OK) { (void) printf(gettext( "Problem with property: %s\n"), optarg); return (SA_NO_MEMORY); } break; default: (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_SET)); return (SA_SYNTAX_ERR); case '?': case 'h': (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_SET)); return (SA_OK); break; } } if (optind >= argc) { (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_SET)); (void) printf(gettext("\tprotocol must be specified.\n")); return (SA_INVALID_PROTOCOL); } proto = argv[optind]; if (!sa_valid_protocol(proto)) { (void) printf(gettext("Invalid protocol specified: %s\n"), proto); return (SA_INVALID_PROTOCOL); } propset = sa_proto_get_properties(proto); if (propset != NULL) { sa_property_t prop; int err; if (optlist == NULL) { (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_SET)); (void) printf(gettext( "\tat least one property and value " "must be specified\n")); } else { struct options *opt; /* list the specified option(s) */ for (opt = optlist; opt != NULL; opt = opt->next) { prop = sa_get_protocol_property( propset, opt->optname); if (prop != NULL) { /* * "err" is used in order to * prevent setting ret to * SA_OK if there has been a * real error. We want to be * able to return an error * status on exit in that * case. Error messages are * printed for each error, so * we only care on exit that * there was an error and not * the specific error value. */ err = sa_set_protocol_property( prop, opt->optvalue); if (err != SA_OK) { (void) printf(gettext( "Could not set property" " %s: %s\n"), opt->optname, sa_errorstr(err)); ret = err; } } else { (void) printf(gettext( "%s: not defined\n"), opt->optname); ret = SA_NO_SUCH_PROP; } } } } return (ret); } static void show_status(char *proto) { char *status; status = sa_get_protocol_status(proto); (void) printf("%s\t%s\n", proto, status ? gettext(status) : "-"); if (status != NULL) free(status); } static int valid_proto(char **protos, int num, char *proto) { int i; for (i = 0; i < num; i++) if (strcmp(protos[i], proto) == 0) return (1); return (0); } /*ARGSUSED*/ static int sc_status(sa_handle_t handle, int flags, int argc, char *argv[]) { char **protos; int ret = SA_OK; int c; int i; int num_proto; int verbose = 0; while ((c = getopt(argc, argv, "?hv")) != EOF) { switch (c) { case 'v': verbose++; break; case '?': case 'h': (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_STATUS)); return (SA_OK); default: (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_STATUS)); return (SA_SYNTAX_ERR); } } num_proto = sa_get_protocols(&protos); if (optind == argc) { /* status for all protocols */ for (i = 0; i < num_proto; i++) { show_status(protos[i]); } } else { for (i = optind; i < argc; i++) { if (valid_proto(protos, num_proto, argv[i])) { show_status(argv[i]); } else { (void) printf(gettext("Invalid protocol: %s\n"), argv[i]); ret = SA_INVALID_PROTOCOL; } } } if (protos != NULL) free(protos); return (ret); } static sa_command_t commands[] = { {"get", 0, sc_get, USAGE_CTL_GET}, {"set", 0, sc_set, USAGE_CTL_SET}, {"status", 0, sc_status, USAGE_CTL_STATUS}, {NULL, 0, NULL, 0}, }; /*ARGSUSED*/ void sub_command_help(char *proto) { int i; (void) printf("\tsub-commands:\n"); for (i = 0; commands[i].cmdname != NULL; i++) { if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) (void) printf("\t%s\n", sc_get_usage((sc_usage_t)commands[i].cmdidx)); } } sa_command_t * sa_lookup(char *cmd) { int i; size_t len; len = strlen(cmd); for (i = 0; commands[i].cmdname != NULL; i++) { if (strncmp(cmd, commands[i].cmdname, len) == 0) return (&commands[i]); } return (NULL); } static int run_command(char *command, int argc, char *argv[], sa_handle_t handle) { sa_command_t *cmdvec; int ret; /* * To get here, we know there should be a command due to the * preprocessing done earlier. Need to find the protocol * that is being affected. If no protocol, then it is ALL * protocols. * * ??? do we really need the protocol at this level? it may be * sufficient to let the commands look it up if needed since * not all commands do proto specific things * * Known sub-commands are handled at this level. An unknown * command will be passed down to the shared object that * actually implements it. We can do this since the semantics * of the common sub-commands is well defined. */ cmdvec = sa_lookup(command); if (cmdvec == NULL) { (void) printf(gettext("command %s not found\n"), command); exit(1); } /* * need to check priviledges and restrict what can be done * based on least priviledge and sub-command. */ ret = cmdvec->cmdfunc(handle, NULL, argc, argv); return (ret); }