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 2007 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 } 113 return (ret); 114 } 115 116 /*ARGSUSED*/ 117 static int 118 sc_get(sa_handle_t handle, int flags, int argc, char *argv[]) 119 { 120 char *proto = NULL; 121 struct options *optlist = NULL; 122 int ret = SA_OK; 123 int c; 124 125 while ((c = getopt(argc, argv, "?hp:")) != EOF) { 126 switch (c) { 127 case 'p': 128 ret = add_opt(&optlist, optarg, 1); 129 if (ret != SA_OK) { 130 (void) printf(gettext( 131 "Problem with property: %s\n"), optarg); 132 return (SA_NO_MEMORY); 133 } 134 break; 135 default: 136 (void) printf(gettext("usage: %s\n"), 137 sc_get_usage(USAGE_CTL_GET)); 138 return (SA_SYNTAX_ERR); 139 case '?': 140 case 'h': 141 (void) printf(gettext("usage: %s\n"), 142 sc_get_usage(USAGE_CTL_GET)); 143 return (SA_OK); 144 break; 145 } 146 } 147 148 if (optind >= argc) { 149 (void) printf(gettext("usage: %s\n"), 150 sc_get_usage(USAGE_CTL_GET)); 151 (void) printf(gettext("\tprotocol must be specified.\n")); 152 return (SA_INVALID_PROTOCOL); 153 } 154 155 proto = argv[optind]; 156 if (sa_valid_protocol(proto)) { 157 sa_protocol_properties_t propset; 158 propset = sa_proto_get_properties(proto); 159 if (propset != NULL) { 160 sa_property_t prop; 161 char *value; 162 char *name; 163 164 if (optlist == NULL) { 165 /* 166 * Display all known properties for 167 * this protocol. 168 */ 169 for (prop = sa_get_protocol_property(propset, 170 NULL); 171 prop != NULL; 172 prop = sa_get_next_protocol_property( 173 prop)) { 174 175 /* 176 * Get and display the 177 * property and value. 178 */ 179 name = sa_get_property_attr(prop, 180 "type"); 181 if (name != NULL) { 182 value = sa_get_property_attr( 183 prop, "value"); 184 (void) printf(gettext( 185 "%s=%s\n"), name, 186 value != NULL ? value : ""); 187 } 188 if (value != NULL) 189 sa_free_attr_string(value); 190 if (name != NULL) 191 sa_free_attr_string(name); 192 } 193 } else { 194 struct options *opt; 195 /* list the specified option(s) */ 196 for (opt = optlist; 197 opt != NULL; 198 opt = opt->next) { 199 prop = sa_get_protocol_property( 200 propset, opt->optname); 201 if (prop != NULL) { 202 value = sa_get_property_attr( 203 prop, "value"); 204 (void) printf(gettext( 205 "%s=%s\n"), 206 opt->optname, 207 value != NULL ? 208 value : ""); 209 sa_free_attr_string(value); 210 } else { 211 (void) printf(gettext( 212 "%s: not defined\n"), 213 opt->optname); 214 ret = SA_NO_SUCH_PROP; 215 } 216 } 217 } 218 } 219 } else { 220 (void) printf(gettext("Invalid protocol specified: %s\n"), 221 proto); 222 ret = SA_INVALID_PROTOCOL; 223 } 224 return (ret); 225 } 226 227 /*ARGSUSED*/ 228 static int 229 sc_set(sa_handle_t handle, int flags, int argc, char *argv[]) 230 { 231 char *proto = NULL; 232 struct options *optlist = NULL; 233 int ret = SA_OK; 234 int c; 235 sa_protocol_properties_t propset; 236 237 while ((c = getopt(argc, argv, "?hp:")) != EOF) { 238 switch (c) { 239 case 'p': 240 ret = add_opt(&optlist, optarg, 0); 241 if (ret != SA_OK) { 242 (void) printf(gettext( 243 "Problem with property: %s\n"), optarg); 244 return (SA_NO_MEMORY); 245 } 246 break; 247 default: 248 (void) printf(gettext("usage: %s\n"), 249 sc_get_usage(USAGE_CTL_SET)); 250 return (SA_SYNTAX_ERR); 251 case '?': 252 case 'h': 253 (void) printf(gettext("usage: %s\n"), 254 sc_get_usage(USAGE_CTL_SET)); 255 return (SA_OK); 256 break; 257 } 258 } 259 260 if (optind >= argc) { 261 (void) printf(gettext("usage: %s\n"), 262 sc_get_usage(USAGE_CTL_SET)); 263 (void) printf(gettext("\tprotocol must be specified.\n")); 264 return (SA_INVALID_PROTOCOL); 265 } 266 267 proto = argv[optind]; 268 if (!sa_valid_protocol(proto)) { 269 (void) printf(gettext("Invalid protocol specified: %s\n"), 270 proto); 271 return (SA_INVALID_PROTOCOL); 272 } 273 propset = sa_proto_get_properties(proto); 274 if (propset != NULL) { 275 sa_property_t prop; 276 int err; 277 if (optlist == NULL) { 278 (void) printf(gettext("usage: %s\n"), 279 sc_get_usage(USAGE_CTL_SET)); 280 (void) printf(gettext( 281 "\tat least one property and value " 282 "must be specified\n")); 283 } else { 284 struct options *opt; 285 /* list the specified option(s) */ 286 for (opt = optlist; 287 opt != NULL; 288 opt = opt->next) { 289 prop = sa_get_protocol_property( 290 propset, opt->optname); 291 if (prop != NULL) { 292 /* 293 * "err" is used in order to 294 * prevent setting ret to 295 * SA_OK if there has been a 296 * real error. We want to be 297 * able to return an error 298 * status on exit in that 299 * case. Error messages are 300 * printed for each error, so 301 * we only care on exit that 302 * there was an error and not 303 * the specific error value. 304 */ 305 err = sa_set_protocol_property( 306 prop, opt->optvalue); 307 if (err != SA_OK) { 308 (void) printf(gettext( 309 "Could not set property" 310 " %s: %s\n"), 311 opt->optname, 312 sa_errorstr(err)); 313 ret = err; 314 } 315 } else { 316 (void) printf(gettext( 317 "%s: not defined\n"), 318 opt->optname); 319 ret = SA_NO_SUCH_PROP; 320 } 321 } 322 } 323 } 324 return (ret); 325 } 326 327 static void 328 show_status(char *proto) 329 { 330 char *status; 331 332 status = sa_get_protocol_status(proto); 333 (void) printf("%s\t%s\n", proto, status ? gettext(status) : "-"); 334 if (status != NULL) 335 free(status); 336 } 337 338 static int 339 valid_proto(char **protos, int num, char *proto) 340 { 341 int i; 342 for (i = 0; i < num; i++) 343 if (strcmp(protos[i], proto) == 0) 344 return (1); 345 return (0); 346 } 347 348 /*ARGSUSED*/ 349 static int 350 sc_status(sa_handle_t handle, int flags, int argc, char *argv[]) 351 { 352 char **protos; 353 int ret = SA_OK; 354 int c; 355 int i; 356 int num_proto; 357 int verbose = 0; 358 359 while ((c = getopt(argc, argv, "?hv")) != EOF) { 360 switch (c) { 361 case 'v': 362 verbose++; 363 break; 364 case '?': 365 case 'h': 366 (void) printf(gettext("usage: %s\n"), 367 sc_get_usage(USAGE_CTL_STATUS)); 368 return (SA_OK); 369 default: 370 (void) printf(gettext("usage: %s\n"), 371 sc_get_usage(USAGE_CTL_STATUS)); 372 return (SA_SYNTAX_ERR); 373 } 374 } 375 376 num_proto = sa_get_protocols(&protos); 377 if (optind == argc) { 378 /* status for all protocols */ 379 for (i = 0; i < num_proto; i++) { 380 show_status(protos[i]); 381 } 382 } else { 383 for (i = optind; i < argc; i++) { 384 if (valid_proto(protos, num_proto, argv[i])) { 385 show_status(argv[i]); 386 } else { 387 (void) printf(gettext("Invalid protocol: %s\n"), 388 argv[i]); 389 ret = SA_INVALID_PROTOCOL; 390 } 391 } 392 } 393 if (protos != NULL) 394 free(protos); 395 return (ret); 396 } 397 398 static sa_command_t commands[] = { 399 {"get", 0, sc_get, USAGE_CTL_GET}, 400 {"set", 0, sc_set, USAGE_CTL_SET}, 401 {"status", 0, sc_status, USAGE_CTL_STATUS}, 402 {NULL, 0, NULL, 0}, 403 }; 404 405 /*ARGSUSED*/ 406 void 407 sub_command_help(char *proto) 408 { 409 int i; 410 411 (void) printf("\tsub-commands:\n"); 412 for (i = 0; commands[i].cmdname != NULL; i++) { 413 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 414 (void) printf("\t%s\n", 415 sc_get_usage((sc_usage_t)commands[i].cmdidx)); 416 } 417 } 418 419 sa_command_t * 420 sa_lookup(char *cmd) 421 { 422 int i; 423 size_t len; 424 425 len = strlen(cmd); 426 for (i = 0; commands[i].cmdname != NULL; i++) { 427 if (strncmp(cmd, commands[i].cmdname, len) == 0) 428 return (&commands[i]); 429 } 430 return (NULL); 431 } 432 433 static int 434 run_command(char *command, int argc, char *argv[], sa_handle_t handle) 435 { 436 sa_command_t *cmdvec; 437 int ret; 438 439 /* 440 * To get here, we know there should be a command due to the 441 * preprocessing done earlier. Need to find the protocol 442 * that is being affected. If no protocol, then it is ALL 443 * protocols. 444 * 445 * ??? do we really need the protocol at this level? it may be 446 * sufficient to let the commands look it up if needed since 447 * not all commands do proto specific things 448 * 449 * Known sub-commands are handled at this level. An unknown 450 * command will be passed down to the shared object that 451 * actually implements it. We can do this since the semantics 452 * of the common sub-commands is well defined. 453 */ 454 455 cmdvec = sa_lookup(command); 456 if (cmdvec == NULL) { 457 (void) printf(gettext("command %s not found\n"), command); 458 exit(1); 459 } 460 /* 461 * need to check priviledges and restrict what can be done 462 * based on least priviledge and sub-command. 463 */ 464 ret = cmdvec->cmdfunc(handle, NULL, argc, argv); 465 return (ret); 466 } 467