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