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