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 2008 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 case USAGE_CTL_DELSECT: 113 ret = gettext("delsect [-h] section proto"); 114 break; 115 } 116 return (ret); 117 } 118 119 /*ARGSUSED*/ 120 static int 121 sc_get(sa_handle_t handle, int flags, int argc, char *argv[]) 122 { 123 char *proto = NULL; 124 struct options *optlist = NULL; 125 int ret = SA_OK; 126 int c; 127 sa_protocol_properties_t propset, propsect; 128 sa_property_t prop; 129 char *section, *value, *name; 130 int first = 1; 131 132 while ((c = getopt(argc, argv, "?hp:")) != EOF) { 133 switch (c) { 134 case 'p': 135 ret = add_opt(&optlist, optarg, 1); 136 if (ret != SA_OK) { 137 (void) printf(gettext( 138 "Problem with property: %s\n"), optarg); 139 return (SA_NO_MEMORY); 140 } 141 break; 142 default: 143 (void) printf(gettext("usage: %s\n"), 144 sc_get_usage(USAGE_CTL_GET)); 145 return (SA_SYNTAX_ERR); 146 case '?': 147 case 'h': 148 (void) printf(gettext("usage: %s\n"), 149 sc_get_usage(USAGE_CTL_GET)); 150 return (SA_OK); 151 break; 152 } 153 } 154 155 if (optind >= argc) { 156 (void) printf(gettext("usage: %s\n"), 157 sc_get_usage(USAGE_CTL_GET)); 158 (void) printf(gettext("\tprotocol must be specified.\n")); 159 return (SA_INVALID_PROTOCOL); 160 } 161 162 proto = argv[optind]; 163 if (!sa_valid_protocol(proto)) { 164 (void) printf(gettext("Invalid protocol specified: %s\n"), 165 proto); 166 return (SA_INVALID_PROTOCOL); 167 } 168 propset = sa_proto_get_properties(proto); 169 if (propset == NULL) 170 return (ret); 171 172 if (optlist == NULL) { 173 /* Display all known properties for this protocol */ 174 for (propsect = sa_get_protocol_section(propset, NULL); 175 propsect != NULL; 176 propsect = sa_get_next_protocol_section(propsect, NULL)) { 177 section = sa_get_property_attr(propsect, 178 "name"); 179 /* 180 * If properties are organized into sections, as 181 * in the SMB client, print the section name. 182 */ 183 if (sa_proto_get_featureset(proto) & 184 SA_FEATURE_HAS_SECTIONS) { 185 if (!first) 186 (void) printf("\n"); 187 first = 0; 188 (void) printf("[%s]\n", section); 189 } 190 /* Display properties for this section */ 191 for (prop = sa_get_protocol_property(propsect, NULL); 192 prop != NULL; 193 prop = sa_get_next_protocol_property(prop, NULL)) { 194 195 /* get and display the property and value */ 196 name = sa_get_property_attr(prop, "type"); 197 if (name != NULL) { 198 value = sa_get_property_attr(prop, 199 "value"); 200 (void) printf(gettext("%s=%s\n"), name, 201 value != NULL ? value : ""); 202 } 203 if (value != NULL) 204 sa_free_attr_string(value); 205 if (name != NULL) 206 sa_free_attr_string(name); 207 } 208 } 209 } else { 210 struct options *opt; 211 212 /* list the specified option(s) */ 213 for (opt = optlist; opt != NULL; opt = opt->next) { 214 int printed = 0; 215 216 for (propsect = sa_get_protocol_section(propset, NULL); 217 propsect != NULL; 218 propsect = sa_get_next_protocol_section(propsect, 219 NULL)) { 220 221 section = sa_get_property_attr(propsect, 222 "name"); 223 for (prop = sa_get_protocol_property(propsect, 224 opt->optname); 225 prop != NULL; 226 prop = sa_get_next_protocol_property( 227 propsect, opt->optname)) { 228 value = sa_get_property_attr(prop, 229 "value"); 230 if (sa_proto_get_featureset(proto) & 231 SA_FEATURE_HAS_SECTIONS) { 232 (void) printf( 233 gettext("[%s] %s=%s\n"), 234 section, opt->optname, 235 value != NULL ? value : ""); 236 sa_free_attr_string(section); 237 } else { 238 (void) printf( 239 gettext("%s=%s\n"), 240 opt->optname, 241 value != NULL ? value : ""); 242 } 243 sa_free_attr_string(value); 244 printed = 1; 245 } 246 } 247 if (!printed) { 248 (void) printf(gettext("%s: not defined\n"), 249 opt->optname); 250 ret = SA_NO_SUCH_PROP; 251 } 252 } 253 } 254 return (ret); 255 } 256 257 /*ARGSUSED*/ 258 static int 259 sc_set(sa_handle_t handle, int flags, int argc, char *argv[]) 260 { 261 char *proto = NULL; 262 struct options *optlist = NULL; 263 sa_protocol_properties_t propsect; 264 int ret = SA_OK; 265 int c; 266 int err; 267 sa_protocol_properties_t propset; 268 sa_property_t prop; 269 270 while ((c = getopt(argc, argv, "?hp:")) != EOF) { 271 switch (c) { 272 case 'p': 273 ret = add_opt(&optlist, optarg, 0); 274 if (ret != SA_OK) { 275 (void) printf(gettext( 276 "Problem with property: %s\n"), optarg); 277 return (SA_NO_MEMORY); 278 } 279 break; 280 default: 281 (void) printf(gettext("usage: %s\n"), 282 sc_get_usage(USAGE_CTL_SET)); 283 return (SA_SYNTAX_ERR); 284 case '?': 285 case 'h': 286 (void) printf(gettext("usage: %s\n"), 287 sc_get_usage(USAGE_CTL_SET)); 288 return (SA_OK); 289 break; 290 } 291 } 292 293 if (optind >= argc) { 294 (void) printf(gettext("usage: %s\n"), 295 sc_get_usage(USAGE_CTL_SET)); 296 (void) printf(gettext("\tprotocol must be specified.\n")); 297 return (SA_INVALID_PROTOCOL); 298 } 299 300 proto = argv[optind]; 301 if (!sa_valid_protocol(proto)) { 302 (void) printf(gettext("Invalid protocol specified: %s\n"), 303 proto); 304 return (SA_INVALID_PROTOCOL); 305 } 306 propset = sa_proto_get_properties(proto); 307 if (propset == NULL) 308 return (ret); 309 310 if (optlist == NULL) { 311 (void) printf(gettext("usage: %s\n"), 312 sc_get_usage(USAGE_CTL_SET)); 313 (void) printf(gettext( 314 "\tat least one property and value " 315 "must be specified\n")); 316 } else { 317 struct options *opt; 318 char *section = NULL; 319 /* fetch and change the specified option(s) */ 320 for (opt = optlist; opt != NULL; opt = opt->next) { 321 if (strncmp("section", opt->optname, 7) == 0) { 322 if (section != NULL) 323 free(section); 324 section = strdup(opt->optvalue); 325 continue; 326 } 327 if (sa_proto_get_featureset(proto) & 328 SA_FEATURE_HAS_SECTIONS) { 329 propsect = sa_get_protocol_section(propset, 330 section); 331 prop = sa_get_protocol_property(propsect, 332 opt->optname); 333 } else { 334 prop = sa_get_protocol_property(propset, 335 opt->optname); 336 } 337 if (prop == NULL && sa_proto_get_featureset(proto) & 338 SA_FEATURE_ADD_PROPERTIES) { 339 sa_property_t sect; 340 sect = sa_create_section(section, NULL); 341 sa_set_section_attr(sect, "type", proto); 342 (void) sa_add_protocol_property(propset, sect); 343 prop = sa_create_property( 344 opt->optname, opt->optvalue); 345 (void) sa_add_protocol_property(sect, prop); 346 } 347 if (prop != NULL) { 348 /* 349 * "err" is used in order to prevent 350 * setting ret to SA_OK if there has 351 * been a real error. We want to be 352 * able to return an error status on 353 * exit in that case. Error messages 354 * are printed for each error, so we 355 * only care on exit that there was an 356 * error and not the specific error 357 * value. 358 */ 359 err = sa_set_protocol_property(prop, section, 360 opt->optvalue); 361 if (err != SA_OK) { 362 (void) printf(gettext( 363 "Could not set property" 364 " %s: %s\n"), 365 opt->optname, sa_errorstr(err)); 366 ret = err; 367 } 368 } else { 369 (void) printf(gettext("%s: not defined\n"), 370 opt->optname); 371 ret = SA_NO_SUCH_PROP; 372 } 373 } 374 } 375 return (ret); 376 } 377 378 static void 379 show_status(char *proto) 380 { 381 char *status; 382 uint64_t features; 383 384 status = sa_get_protocol_status(proto); 385 features = sa_proto_get_featureset(proto); 386 (void) printf("%s\t%s", proto, status ? gettext(status) : "-"); 387 if (status != NULL) 388 free(status); 389 /* 390 * Need to flag a client only protocol so test suites can 391 * remove it from consideration. 392 */ 393 if (!(features & SA_FEATURE_SERVER)) 394 (void) printf(" client"); 395 (void) printf("\n"); 396 } 397 398 static int 399 valid_proto(char **protos, int num, char *proto) 400 { 401 int i; 402 for (i = 0; i < num; i++) 403 if (strcmp(protos[i], proto) == 0) 404 return (1); 405 return (0); 406 } 407 408 /*ARGSUSED*/ 409 static int 410 sc_status(sa_handle_t handle, int flags, int argc, char *argv[]) 411 { 412 char **protos; 413 int ret = SA_OK; 414 int c; 415 int i; 416 int num_proto; 417 int verbose = 0; 418 419 while ((c = getopt(argc, argv, "?hv")) != EOF) { 420 switch (c) { 421 case 'v': 422 verbose++; 423 break; 424 case '?': 425 case 'h': 426 (void) printf(gettext("usage: %s\n"), 427 sc_get_usage(USAGE_CTL_STATUS)); 428 return (SA_OK); 429 default: 430 (void) printf(gettext("usage: %s\n"), 431 sc_get_usage(USAGE_CTL_STATUS)); 432 return (SA_SYNTAX_ERR); 433 } 434 } 435 436 num_proto = sa_get_protocols(&protos); 437 if (optind == argc) { 438 /* status for all protocols */ 439 for (i = 0; i < num_proto; i++) { 440 show_status(protos[i]); 441 } 442 } else { 443 for (i = optind; i < argc; i++) { 444 if (valid_proto(protos, num_proto, argv[i])) { 445 show_status(argv[i]); 446 } else { 447 (void) printf(gettext("Invalid protocol: %s\n"), 448 argv[i]); 449 ret = SA_INVALID_PROTOCOL; 450 } 451 } 452 } 453 if (protos != NULL) 454 free(protos); 455 return (ret); 456 } 457 458 /*ARGSUSED*/ 459 static int 460 sc_delsect(sa_handle_t handle, int flags, int argc, char *argv[]) 461 { 462 char *proto = NULL; 463 char *section = NULL; 464 sa_protocol_properties_t propset; 465 sa_protocol_properties_t propsect; 466 int ret = SA_OK; 467 int c; 468 469 while ((c = getopt(argc, argv, "?h")) != EOF) { 470 switch (c) { 471 default: 472 ret = SA_SYNTAX_ERR; 473 /*FALLTHROUGH*/ 474 case '?': 475 case 'h': 476 (void) printf(gettext("usage: %s\n"), 477 sc_get_usage(USAGE_CTL_DELSECT)); 478 return (ret); 479 } 480 /*NOTREACHED*/ 481 } 482 483 section = argv[optind++]; 484 485 if (optind >= argc) { 486 (void) printf(gettext("usage: %s\n"), 487 sc_get_usage(USAGE_CTL_DELSECT)); 488 (void) printf(gettext( 489 "\tsection and protocol must be specified.\n")); 490 return (SA_INVALID_PROTOCOL); 491 } 492 493 proto = argv[optind]; 494 if (!sa_valid_protocol(proto)) { 495 (void) printf(gettext("Invalid protocol specified: %s\n"), 496 proto); 497 return (SA_INVALID_PROTOCOL); 498 } 499 500 if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 501 (void) printf(gettext("Protocol %s does not have sections\n"), 502 section, proto); 503 return (SA_NOT_SUPPORTED); 504 } 505 506 propset = sa_proto_get_properties(proto); 507 if (propset == NULL) { 508 (void) printf(gettext("Cannot get properties for %s\n"), 509 proto); 510 return (SA_NO_PROPERTIES); 511 } 512 513 propsect = sa_get_protocol_section(propset, section); 514 if (propsect == NULL) { 515 (void) printf(gettext("Cannot find section %s for proto %s\n"), 516 section, proto); 517 return (SA_NO_SUCH_SECTION); 518 } 519 520 ret = sa_proto_delete_section(proto, section); 521 522 return (ret); 523 } 524 525 static sa_command_t commands[] = { 526 {"get", 0, sc_get, USAGE_CTL_GET}, 527 {"set", 0, sc_set, USAGE_CTL_SET}, 528 {"status", 0, sc_status, USAGE_CTL_STATUS}, 529 {"delsect", 0, sc_delsect, USAGE_CTL_DELSECT}, 530 {NULL, 0, NULL, 0}, 531 }; 532 533 /*ARGSUSED*/ 534 void 535 sub_command_help(char *proto) 536 { 537 int i; 538 539 (void) printf("\tsub-commands:\n"); 540 for (i = 0; commands[i].cmdname != NULL; i++) { 541 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY))) 542 (void) printf("\t%s\n", 543 sc_get_usage((sc_usage_t)commands[i].cmdidx)); 544 } 545 } 546 547 sa_command_t * 548 sa_lookup(char *cmd) 549 { 550 int i; 551 size_t len; 552 553 len = strlen(cmd); 554 for (i = 0; commands[i].cmdname != NULL; i++) { 555 if (strncmp(cmd, commands[i].cmdname, len) == 0) 556 return (&commands[i]); 557 } 558 return (NULL); 559 } 560 561 static int 562 run_command(char *command, int argc, char *argv[], sa_handle_t handle) 563 { 564 sa_command_t *cmdvec; 565 int ret; 566 567 /* 568 * To get here, we know there should be a command due to the 569 * preprocessing done earlier. Need to find the protocol 570 * that is being affected. If no protocol, then it is ALL 571 * protocols. 572 * 573 * ??? do we really need the protocol at this level? it may be 574 * sufficient to let the commands look it up if needed since 575 * not all commands do proto specific things 576 * 577 * Known sub-commands are handled at this level. An unknown 578 * command will be passed down to the shared object that 579 * actually implements it. We can do this since the semantics 580 * of the common sub-commands is well defined. 581 */ 582 583 cmdvec = sa_lookup(command); 584 if (cmdvec == NULL) { 585 (void) printf(gettext("command %s not found\n"), command); 586 exit(1); 587 } 588 /* 589 * need to check priviledges and restrict what can be done 590 * based on least priviledge and sub-command. 591 */ 592 ret = cmdvec->cmdfunc(handle, NULL, argc, argv); 593 return (ret); 594 } 595