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