13034Sdougm /* 23034Sdougm * CDDL HEADER START 33034Sdougm * 43034Sdougm * The contents of this file are subject to the terms of the 53034Sdougm * Common Development and Distribution License (the "License"). 63034Sdougm * You may not use this file except in compliance with the License. 73034Sdougm * 83034Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93034Sdougm * or http://www.opensolaris.org/os/licensing. 103034Sdougm * See the License for the specific language governing permissions 113034Sdougm * and limitations under the License. 123034Sdougm * 133034Sdougm * When distributing Covered Code, include this CDDL HEADER in each 143034Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153034Sdougm * If applicable, add the following below this CDDL HEADER, with the 163034Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 173034Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 183034Sdougm * 193034Sdougm * CDDL HEADER END 203034Sdougm */ 213034Sdougm 223034Sdougm /* 233393Sdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243034Sdougm * Use is subject to license terms. 253034Sdougm */ 263034Sdougm 273034Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 283034Sdougm 293034Sdougm #include <stdlib.h> 303034Sdougm #include <stdio.h> 313034Sdougm #include <string.h> 323034Sdougm #include <ctype.h> 333034Sdougm #include <unistd.h> 343034Sdougm #include <getopt.h> 353034Sdougm #include <libgen.h> 363034Sdougm 373034Sdougm #include "libshare.h" 383034Sdougm #include <sharemgr.h> 393034Sdougm 403034Sdougm #include <libintl.h> 413034Sdougm #include <locale.h> 423034Sdougm 433910Sdougm static int run_command(char *, int, char **, sa_handle_t); 443034Sdougm static void sub_command_help(char *proto); 453034Sdougm 463034Sdougm static void 473034Sdougm global_help() 483034Sdougm { 493034Sdougm (void) printf(gettext("usage: sharectl <command> [options]\n")); 503034Sdougm sub_command_help(NULL); 513034Sdougm } 523034Sdougm 533034Sdougm int 543034Sdougm main(int argc, char *argv[]) 553034Sdougm { 563034Sdougm int c; 573034Sdougm int help = 0; 583034Sdougm int rval; 593034Sdougm char *command; 603910Sdougm sa_handle_t handle; 613034Sdougm 623034Sdougm /* 633034Sdougm * make sure locale and gettext domain is setup 643034Sdougm */ 653034Sdougm (void) setlocale(LC_ALL, ""); 663034Sdougm (void) textdomain(TEXT_DOMAIN); 673034Sdougm 683910Sdougm handle = sa_init(SA_INIT_CONTROL_API); 693034Sdougm 703034Sdougm while ((c = getopt(argc, argv, "h?")) != EOF) { 71*4653Sdougm switch (c) { 72*4653Sdougm case '?': 73*4653Sdougm case 'h': 74*4653Sdougm help = 1; 75*4653Sdougm break; 76*4653Sdougm default: 77*4653Sdougm (void) printf(gettext("Invalid option: %c\n"), c); 78*4653Sdougm } 793034Sdougm } 803034Sdougm if (optind == argc || help) { 81*4653Sdougm /* no subcommand */ 82*4653Sdougm global_help(); 83*4653Sdougm exit(0); 843034Sdougm } 853034Sdougm optind = 1; 863034Sdougm 873034Sdougm /* 883034Sdougm * now have enough to parse rest of command line 893034Sdougm */ 903034Sdougm command = argv[optind]; 913910Sdougm rval = run_command(command, argc - optind, argv + optind, handle); 923034Sdougm 933910Sdougm sa_fini(handle); 943034Sdougm return (rval); 953034Sdougm } 963034Sdougm 973034Sdougm char * 983034Sdougm sc_get_usage(sc_usage_t index) 993034Sdougm { 1003034Sdougm char *ret = NULL; 1013034Sdougm 1023034Sdougm switch (index) { 1033034Sdougm case USAGE_CTL_GET: 104*4653Sdougm ret = gettext("get [-h | -p property ...] proto"); 105*4653Sdougm break; 1063034Sdougm case USAGE_CTL_SET: 107*4653Sdougm ret = gettext("set [-h] -p property=value ... proto"); 108*4653Sdougm break; 1093034Sdougm case USAGE_CTL_STATUS: 110*4653Sdougm ret = gettext("status [-h | proto ...]"); 111*4653Sdougm break; 1123034Sdougm } 1133034Sdougm return (ret); 1143034Sdougm } 1153034Sdougm 1163910Sdougm /*ARGSUSED*/ 1173034Sdougm static int 1183910Sdougm sc_get(sa_handle_t handle, int flags, int argc, char *argv[]) 1193034Sdougm { 1203034Sdougm char *proto = NULL; 1213034Sdougm struct options *optlist = NULL; 1223034Sdougm int ret = SA_OK; 1233034Sdougm int c; 1243034Sdougm 1253034Sdougm while ((c = getopt(argc, argv, "?hp:")) != EOF) { 126*4653Sdougm switch (c) { 127*4653Sdougm case 'p': 128*4653Sdougm ret = add_opt(&optlist, optarg, 1); 129*4653Sdougm if (ret != SA_OK) { 130*4653Sdougm (void) printf(gettext( 131*4653Sdougm "Problem with property: %s\n"), optarg); 132*4653Sdougm return (SA_NO_MEMORY); 133*4653Sdougm } 134*4653Sdougm break; 135*4653Sdougm default: 136*4653Sdougm (void) printf(gettext("usage: %s\n"), 137*4653Sdougm sc_get_usage(USAGE_CTL_GET)); 138*4653Sdougm return (SA_SYNTAX_ERR); 139*4653Sdougm case '?': 140*4653Sdougm case 'h': 141*4653Sdougm (void) printf(gettext("usage: %s\n"), 142*4653Sdougm sc_get_usage(USAGE_CTL_GET)); 143*4653Sdougm return (SA_OK); 144*4653Sdougm break; 1453034Sdougm } 1463034Sdougm } 1473034Sdougm 1483034Sdougm if (optind >= argc) { 149*4653Sdougm (void) printf(gettext("usage: %s\n"), 150*4653Sdougm sc_get_usage(USAGE_CTL_GET)); 151*4653Sdougm (void) printf(gettext("\tprotocol must be specified.\n")); 152*4653Sdougm return (SA_INVALID_PROTOCOL); 1533034Sdougm } 1543034Sdougm 1553034Sdougm proto = argv[optind]; 1563034Sdougm if (sa_valid_protocol(proto)) { 157*4653Sdougm sa_protocol_properties_t propset; 158*4653Sdougm propset = sa_proto_get_properties(proto); 159*4653Sdougm if (propset != NULL) { 160*4653Sdougm sa_property_t prop; 161*4653Sdougm char *value; 162*4653Sdougm char *name; 163*4653Sdougm 164*4653Sdougm if (optlist == NULL) { 165*4653Sdougm /* 166*4653Sdougm * Display all known properties for 167*4653Sdougm * this protocol. 168*4653Sdougm */ 169*4653Sdougm for (prop = sa_get_protocol_property(propset, 170*4653Sdougm NULL); 171*4653Sdougm prop != NULL; 172*4653Sdougm prop = sa_get_next_protocol_property( 173*4653Sdougm prop)) { 1743034Sdougm 175*4653Sdougm /* 176*4653Sdougm * Get and display the 177*4653Sdougm * property and value. 178*4653Sdougm */ 179*4653Sdougm name = sa_get_property_attr(prop, 180*4653Sdougm "type"); 181*4653Sdougm if (name != NULL) { 182*4653Sdougm value = sa_get_property_attr( 183*4653Sdougm prop, "value"); 184*4653Sdougm (void) printf(gettext( 185*4653Sdougm "%s=%s\n"), name, 186*4653Sdougm value != NULL ? value : ""); 187*4653Sdougm } 188*4653Sdougm if (value != NULL) 189*4653Sdougm sa_free_attr_string(value); 190*4653Sdougm if (name != NULL) 191*4653Sdougm sa_free_attr_string(name); 192*4653Sdougm } 193*4653Sdougm } else { 194*4653Sdougm struct options *opt; 195*4653Sdougm /* list the specified option(s) */ 196*4653Sdougm for (opt = optlist; 197*4653Sdougm opt != NULL; 198*4653Sdougm opt = opt->next) { 199*4653Sdougm prop = sa_get_protocol_property( 200*4653Sdougm propset, opt->optname); 201*4653Sdougm if (prop != NULL) { 202*4653Sdougm value = sa_get_property_attr( 203*4653Sdougm prop, "value"); 204*4653Sdougm (void) printf(gettext( 205*4653Sdougm "%s=%s\n"), 206*4653Sdougm opt->optname, 207*4653Sdougm value != NULL ? 208*4653Sdougm value : ""); 209*4653Sdougm sa_free_attr_string(value); 210*4653Sdougm } else { 211*4653Sdougm (void) printf(gettext( 212*4653Sdougm "%s: not defined\n"), 213*4653Sdougm opt->optname); 214*4653Sdougm ret = SA_NO_SUCH_PROP; 215*4653Sdougm } 216*4653Sdougm } 2173034Sdougm } 2183034Sdougm } 2193034Sdougm } else { 220*4653Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 221*4653Sdougm proto); 222*4653Sdougm ret = SA_INVALID_PROTOCOL; 2233034Sdougm } 2243034Sdougm return (ret); 2253034Sdougm } 2263034Sdougm 2273910Sdougm /*ARGSUSED*/ 2283034Sdougm static int 2293910Sdougm sc_set(sa_handle_t handle, int flags, int argc, char *argv[]) 2303034Sdougm { 2313034Sdougm char *proto = NULL; 2323034Sdougm struct options *optlist = NULL; 2333034Sdougm int ret = SA_OK; 2343034Sdougm int c; 235*4653Sdougm sa_protocol_properties_t propset; 2363034Sdougm 2373034Sdougm while ((c = getopt(argc, argv, "?hp:")) != EOF) { 238*4653Sdougm switch (c) { 239*4653Sdougm case 'p': 240*4653Sdougm ret = add_opt(&optlist, optarg, 0); 241*4653Sdougm if (ret != SA_OK) { 242*4653Sdougm (void) printf(gettext( 243*4653Sdougm "Problem with property: %s\n"), optarg); 244*4653Sdougm return (SA_NO_MEMORY); 245*4653Sdougm } 246*4653Sdougm break; 247*4653Sdougm default: 248*4653Sdougm (void) printf(gettext("usage: %s\n"), 249*4653Sdougm sc_get_usage(USAGE_CTL_SET)); 250*4653Sdougm return (SA_SYNTAX_ERR); 251*4653Sdougm case '?': 252*4653Sdougm case 'h': 253*4653Sdougm (void) printf(gettext("usage: %s\n"), 254*4653Sdougm sc_get_usage(USAGE_CTL_SET)); 255*4653Sdougm return (SA_OK); 256*4653Sdougm break; 2573034Sdougm } 2583034Sdougm } 2593034Sdougm 2603034Sdougm if (optind >= argc) { 261*4653Sdougm (void) printf(gettext("usage: %s\n"), 262*4653Sdougm sc_get_usage(USAGE_CTL_SET)); 263*4653Sdougm (void) printf(gettext("\tprotocol must be specified.\n")); 264*4653Sdougm return (SA_INVALID_PROTOCOL); 2653034Sdougm } 2663034Sdougm 2673034Sdougm proto = argv[optind]; 268*4653Sdougm if (!sa_valid_protocol(proto)) { 269*4653Sdougm (void) printf(gettext("Invalid protocol specified: %s\n"), 270*4653Sdougm proto); 271*4653Sdougm return (SA_INVALID_PROTOCOL); 272*4653Sdougm } 273*4653Sdougm propset = sa_proto_get_properties(proto); 274*4653Sdougm if (propset != NULL) { 2753034Sdougm sa_property_t prop; 2763393Sdougm int err; 2773034Sdougm if (optlist == NULL) { 278*4653Sdougm (void) printf(gettext("usage: %s\n"), 279*4653Sdougm sc_get_usage(USAGE_CTL_SET)); 280*4653Sdougm (void) printf(gettext( 281*4653Sdougm "\tat least one property and value " 282*4653Sdougm "must be specified\n")); 2833034Sdougm } else { 284*4653Sdougm struct options *opt; 285*4653Sdougm /* list the specified option(s) */ 286*4653Sdougm for (opt = optlist; 287*4653Sdougm opt != NULL; 288*4653Sdougm opt = opt->next) { 289*4653Sdougm prop = sa_get_protocol_property( 290*4653Sdougm propset, opt->optname); 291*4653Sdougm if (prop != NULL) { 292*4653Sdougm /* 293*4653Sdougm * "err" is used in order to 294*4653Sdougm * prevent setting ret to 295*4653Sdougm * SA_OK if there has been a 296*4653Sdougm * real error. We want to be 297*4653Sdougm * able to return an error 298*4653Sdougm * status on exit in that 299*4653Sdougm * case. Error messages are 300*4653Sdougm * printed for each error, so 301*4653Sdougm * we only care on exit that 302*4653Sdougm * there was an error and not 303*4653Sdougm * the specific error value. 304*4653Sdougm */ 305*4653Sdougm err = sa_set_protocol_property( 306*4653Sdougm prop, opt->optvalue); 307*4653Sdougm if (err != SA_OK) { 308*4653Sdougm (void) printf(gettext( 309*4653Sdougm "Could not set property" 310*4653Sdougm " %s: %s\n"), 311*4653Sdougm opt->optname, 312*4653Sdougm sa_errorstr(err)); 313*4653Sdougm ret = err; 314*4653Sdougm } 315*4653Sdougm } else { 316*4653Sdougm (void) printf(gettext( 317*4653Sdougm "%s: not defined\n"), 318*4653Sdougm opt->optname); 319*4653Sdougm ret = SA_NO_SUCH_PROP; 320*4653Sdougm } 3213034Sdougm } 3223034Sdougm } 3233034Sdougm } 3243034Sdougm return (ret); 3253034Sdougm } 3263034Sdougm 3273034Sdougm static void 3283034Sdougm show_status(char *proto) 3293034Sdougm { 3303034Sdougm char *status; 331*4653Sdougm 3323034Sdougm status = sa_get_protocol_status(proto); 3333034Sdougm (void) printf("%s\t%s\n", proto, status ? gettext(status) : "-"); 3343034Sdougm if (status != NULL) 335*4653Sdougm free(status); 3363034Sdougm } 3373034Sdougm 3383034Sdougm static int 3393034Sdougm valid_proto(char **protos, int num, char *proto) 3403034Sdougm { 3413034Sdougm int i; 3423034Sdougm for (i = 0; i < num; i++) 343*4653Sdougm if (strcmp(protos[i], proto) == 0) 344*4653Sdougm return (1); 3453034Sdougm return (0); 3463034Sdougm } 3473034Sdougm 3483910Sdougm /*ARGSUSED*/ 3493034Sdougm static int 3503910Sdougm sc_status(sa_handle_t handle, int flags, int argc, char *argv[]) 3513034Sdougm { 3523034Sdougm char **protos; 3533034Sdougm int ret = SA_OK; 3543034Sdougm int c; 3553034Sdougm int i; 3563034Sdougm int num_proto; 3573034Sdougm int verbose = 0; 3583034Sdougm 3593034Sdougm while ((c = getopt(argc, argv, "?hv")) != EOF) { 360*4653Sdougm switch (c) { 361*4653Sdougm case 'v': 362*4653Sdougm verbose++; 363*4653Sdougm break; 364*4653Sdougm case '?': 365*4653Sdougm case 'h': 366*4653Sdougm (void) printf(gettext("usage: %s\n"), 367*4653Sdougm sc_get_usage(USAGE_CTL_STATUS)); 368*4653Sdougm return (SA_OK); 369*4653Sdougm default: 370*4653Sdougm (void) printf(gettext("usage: %s\n"), 371*4653Sdougm sc_get_usage(USAGE_CTL_STATUS)); 372*4653Sdougm return (SA_SYNTAX_ERR); 373*4653Sdougm } 3743034Sdougm } 3753034Sdougm 3763034Sdougm num_proto = sa_get_protocols(&protos); 3773034Sdougm if (optind == argc) { 378*4653Sdougm /* status for all protocols */ 379*4653Sdougm for (i = 0; i < num_proto; i++) { 380*4653Sdougm show_status(protos[i]); 381*4653Sdougm } 3823034Sdougm } else { 383*4653Sdougm for (i = optind; i < argc; i++) { 384*4653Sdougm if (valid_proto(protos, num_proto, argv[i])) { 385*4653Sdougm show_status(argv[i]); 386*4653Sdougm } else { 387*4653Sdougm (void) printf(gettext("Invalid protocol: %s\n"), 388*4653Sdougm argv[i]); 389*4653Sdougm ret = SA_INVALID_PROTOCOL; 390*4653Sdougm } 3913034Sdougm } 3923034Sdougm } 3933034Sdougm if (protos != NULL) 394*4653Sdougm free(protos); 3953034Sdougm return (ret); 3963034Sdougm } 3973034Sdougm 3983034Sdougm static sa_command_t commands[] = { 3993034Sdougm {"get", 0, sc_get, USAGE_CTL_GET}, 4003034Sdougm {"set", 0, sc_set, USAGE_CTL_SET}, 4013034Sdougm {"status", 0, sc_status, USAGE_CTL_STATUS}, 4023034Sdougm {NULL, 0, NULL, 0}, 4033034Sdougm }; 4043034Sdougm 4053910Sdougm /*ARGSUSED*/ 4063034Sdougm void 4073034Sdougm sub_command_help(char *proto) 4083034Sdougm { 4093034Sdougm int i; 4103034Sdougm 4113034Sdougm (void) printf("\tsub-commands:\n"); 4123034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 4133034Sdougm if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 4143034Sdougm (void) printf("\t%s\n", 415*4653Sdougm sc_get_usage((sc_usage_t)commands[i].cmdidx)); 4163034Sdougm } 4173034Sdougm } 4183034Sdougm 4193034Sdougm sa_command_t * 4203034Sdougm sa_lookup(char *cmd) 4213034Sdougm { 4223034Sdougm int i; 4233034Sdougm size_t len; 4243034Sdougm 4253034Sdougm len = strlen(cmd); 4263034Sdougm for (i = 0; commands[i].cmdname != NULL; i++) { 4273034Sdougm if (strncmp(cmd, commands[i].cmdname, len) == 0) 4283034Sdougm return (&commands[i]); 4293034Sdougm } 4303034Sdougm return (NULL); 4313034Sdougm } 4323034Sdougm 4333034Sdougm static int 4343910Sdougm run_command(char *command, int argc, char *argv[], sa_handle_t handle) 4353034Sdougm { 4363034Sdougm sa_command_t *cmdvec; 4373034Sdougm int ret; 4383034Sdougm 4393034Sdougm /* 4403034Sdougm * To get here, we know there should be a command due to the 4413034Sdougm * preprocessing done earlier. Need to find the protocol 4423034Sdougm * that is being affected. If no protocol, then it is ALL 4433034Sdougm * protocols. 4443034Sdougm * 4453034Sdougm * ??? do we really need the protocol at this level? it may be 4463034Sdougm * sufficient to let the commands look it up if needed since 4473034Sdougm * not all commands do proto specific things 4483034Sdougm * 4493034Sdougm * Known sub-commands are handled at this level. An unknown 4503034Sdougm * command will be passed down to the shared object that 4513034Sdougm * actually implements it. We can do this since the semantics 4523034Sdougm * of the common sub-commands is well defined. 4533034Sdougm */ 4543034Sdougm 4553034Sdougm cmdvec = sa_lookup(command); 4563034Sdougm if (cmdvec == NULL) { 4573034Sdougm (void) printf(gettext("command %s not found\n"), command); 4583034Sdougm exit(1); 4593034Sdougm } 4603034Sdougm /* 4613034Sdougm * need to check priviledges and restrict what can be done 4623034Sdougm * based on least priviledge and sub-command. 4633034Sdougm */ 4643910Sdougm ret = cmdvec->cmdfunc(handle, NULL, argc, argv); 4653034Sdougm return (ret); 4663034Sdougm } 467