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