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 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <libshare.h> 31 #include "libshare_impl.h" 32 #include <dlfcn.h> 33 #include <link.h> 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/stat.h> 37 #include <dirent.h> 38 #include <libintl.h> 39 #include <sys/systeminfo.h> 40 #include <thread.h> 41 #include <synch.h> 42 43 #define MAXISALEN 257 /* based on sysinfo(2) man page */ 44 45 /* 46 * protocol plugin interface 47 * 48 * finds plugins and makes them accessible. This is only "used" by 49 * libshare.so. 50 */ 51 52 struct sa_proto_plugin *sap_proto_list; 53 54 static struct sa_proto_handle sa_proto_handle; 55 56 void proto_plugin_fini(); 57 58 /* 59 * Returns true if name is "." or "..", otherwise returns false. 60 */ 61 static boolean_t 62 proto_is_dot_or_dotdot(const char *name) 63 { 64 if (*name != '.') 65 return (B_FALSE); 66 67 if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0')) 68 return (B_TRUE); 69 70 return (B_FALSE); 71 } 72 73 /* 74 * proto_plugin_init() 75 * 76 * Initialize the protocol specific plugin modules. 77 * 78 * Walk /usr/lib/fs/\* for libshare_*.so modules, for example, 79 * /usr/lib/fs/nfs/libshare_nfs.so. A protocol specific directory 80 * would have modules with names of the form libshare_<proto>.so. 81 * For each protocol found, initialize it and add it to the internal 82 * list of protocols. These are used for protocol specific operations. 83 */ 84 85 int 86 proto_plugin_init() 87 { 88 struct sa_proto_plugin *proto; 89 int num_protos = 0; 90 struct sa_plugin_ops *plugin_ops; 91 void *dlhandle; 92 DIR *dir; 93 struct dirent *dent; 94 int ret = SA_OK; 95 struct stat st; 96 char isa[MAXISALEN]; 97 98 #if defined(_LP64) 99 if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) 100 isa[0] = '\0'; 101 #else 102 isa[0] = '\0'; 103 #endif 104 105 if ((dir = opendir(SA_LIB_DIR)) == NULL) 106 return (SA_OK); 107 108 while ((dent = readdir(dir)) != NULL) { 109 char path[MAXPATHLEN]; 110 111 if (proto_is_dot_or_dotdot(dent->d_name)) 112 continue; 113 114 (void) snprintf(path, MAXPATHLEN, 115 "%s/%s/%s/libshare_%s.so.1", SA_LIB_DIR, 116 dent->d_name, isa, dent->d_name); 117 118 /* 119 * If file doesn't exist, don't try to map it 120 */ 121 if (stat(path, &st) < 0) 122 continue; 123 124 if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL) { 125 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 126 "Error in plugin for protocol %s: %s\n"), 127 dent->d_name, dlerror()); 128 continue; 129 } 130 131 plugin_ops = (struct sa_plugin_ops *) 132 dlsym(dlhandle, "sa_plugin_ops"); 133 if (plugin_ops == NULL) { 134 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 135 "Error in plugin ops for protocol %s: %s\n"), 136 dent->d_name, dlerror()); 137 (void) dlclose(dlhandle); 138 continue; 139 } 140 141 proto = (struct sa_proto_plugin *) 142 calloc(1, sizeof (struct sa_proto_plugin)); 143 if (proto == NULL) { 144 (void) dlclose(dlhandle); 145 ret = SA_NO_MEMORY; 146 continue; 147 } 148 149 proto->plugin_ops = plugin_ops; 150 proto->plugin_handle = dlhandle; 151 num_protos++; 152 proto->plugin_next = sap_proto_list; 153 sap_proto_list = proto; 154 } 155 156 (void) closedir(dir); 157 158 if (num_protos != 0) { 159 sa_proto_handle.sa_proto = 160 (char **)calloc(num_protos, sizeof (char *)); 161 sa_proto_handle.sa_ops = 162 (struct sa_plugin_ops **)calloc(num_protos, 163 sizeof (struct sa_plugin_ops *)); 164 if (sa_proto_handle.sa_proto != NULL && 165 sa_proto_handle.sa_ops != NULL) { 166 int i; 167 struct sa_proto_plugin *tmp; 168 169 for (i = 0, tmp = sap_proto_list; 170 i < num_protos && tmp != NULL; 171 tmp = tmp->plugin_next) { 172 int err; 173 err = SA_OK; 174 if (tmp->plugin_ops->sa_init != NULL) 175 err = tmp->plugin_ops->sa_init(); 176 if (err == SA_OK) { 177 /* 178 * Only include if the init 179 * succeeded or was NULL 180 */ 181 sa_proto_handle.sa_num_proto++; 182 sa_proto_handle.sa_ops[i] = 183 tmp->plugin_ops; 184 sa_proto_handle.sa_proto[i] = 185 tmp->plugin_ops->sa_protocol; 186 i++; 187 } 188 } 189 } else { 190 ret = SA_NO_MEMORY; 191 } 192 } 193 194 /* 195 * There was an error, so cleanup prior to return of failure. 196 */ 197 if (ret != SA_OK) 198 proto_plugin_fini(); 199 200 return (ret); 201 } 202 203 /* 204 * proto_plugin_fini() 205 * 206 * Uninitialize all the plugin modules. 207 */ 208 209 void 210 proto_plugin_fini() 211 { 212 struct sa_proto_plugin *p; 213 214 /* 215 * Protocols may call this framework during _fini 216 * (the smbfs plugin is known to do this) so do 217 * two passes: 1st call _fini; 2nd free, dlclose. 218 */ 219 for (p = sap_proto_list; p != NULL; p = p->plugin_next) 220 p->plugin_ops->sa_fini(); 221 222 while ((p = sap_proto_list) != NULL) { 223 sap_proto_list = p->plugin_next; 224 225 if (p->plugin_handle != NULL) 226 (void) dlclose(p->plugin_handle); 227 free(p); 228 } 229 if (sa_proto_handle.sa_ops != NULL) { 230 free(sa_proto_handle.sa_ops); 231 sa_proto_handle.sa_ops = NULL; 232 } 233 if (sa_proto_handle.sa_proto != NULL) { 234 free(sa_proto_handle.sa_proto); 235 sa_proto_handle.sa_proto = NULL; 236 } 237 sa_proto_handle.sa_num_proto = 0; 238 } 239 240 /* 241 * find_protocol(proto) 242 * 243 * Search the plugin list for the specified protocol and return the 244 * ops vector. NULL if protocol is not defined. 245 */ 246 247 static struct sa_plugin_ops * 248 find_protocol(char *proto) 249 { 250 int i; 251 struct sa_plugin_ops *ops = NULL; 252 extern mutex_t sa_global_lock; 253 254 (void) mutex_lock(&sa_global_lock); 255 if (proto != NULL) { 256 for (i = 0; i < sa_proto_handle.sa_num_proto; i++) { 257 if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0) { 258 ops = sa_proto_handle.sa_ops[i]; 259 break; 260 } 261 } 262 } 263 (void) mutex_unlock(&sa_global_lock); 264 return (ops); 265 } 266 267 /* 268 * sa_proto_share(proto, share) 269 * 270 * Activate a share for the specified protocol. 271 */ 272 273 int 274 sa_proto_share(char *proto, sa_share_t share) 275 { 276 struct sa_plugin_ops *ops = find_protocol(proto); 277 int ret = SA_INVALID_PROTOCOL; 278 279 if (ops != NULL && ops->sa_share != NULL) 280 ret = ops->sa_share(share); 281 return (ret); 282 } 283 284 /* 285 * sa_proto_unshare(proto, share) 286 * 287 * Deactivate (unshare) the share for this protocol. 288 */ 289 290 int 291 sa_proto_unshare(sa_share_t share, char *proto, char *path) 292 { 293 struct sa_plugin_ops *ops = find_protocol(proto); 294 int ret = SA_INVALID_PROTOCOL; 295 296 if (ops != NULL && ops->sa_unshare != NULL) 297 ret = ops->sa_unshare(share, path); 298 return (ret); 299 } 300 301 /* 302 * sa_proto_share_resource(char *proto, sa_resource_t resource) 303 * 304 * For protocols that actually enable at the resource level, do the 305 * protocol specific resource enable. If it doesn't, return an error. 306 * Note that the resource functions are optional so can return 307 * SA_NOT_SUPPORTED. 308 */ 309 310 int 311 sa_proto_share_resource(char *proto, sa_resource_t resource) 312 { 313 struct sa_plugin_ops *ops = find_protocol(proto); 314 int ret = SA_INVALID_PROTOCOL; 315 316 if (ops != NULL) { 317 if (ops->sa_enable_resource != NULL) 318 ret = ops->sa_enable_resource(resource); 319 else 320 ret = SA_NOT_SUPPORTED; 321 } 322 return (ret); 323 } 324 325 /* 326 * sa_proto_unshare_resource(char *proto, sa_resource_t resource) 327 * 328 * For protocols that actually disable at the resource level, do the 329 * protocol specific resource disable. If it doesn't, return an error. 330 */ 331 332 int 333 sa_proto_unshare_resource(char *proto, sa_resource_t resource) 334 { 335 struct sa_plugin_ops *ops = find_protocol(proto); 336 int ret = SA_INVALID_PROTOCOL; 337 338 if (ops != NULL) { 339 if (ops->sa_disable_resource != NULL) 340 ret = ops->sa_disable_resource(resource); 341 else 342 ret = SA_NOT_SUPPORTED; 343 } 344 return (ret); 345 } 346 347 /* 348 * sa_proto_valid_prop(handle, proto, prop, opt) 349 * 350 * Check to see if the specified prop is valid for this protocol. 351 */ 352 353 int 354 sa_proto_valid_prop(sa_handle_t handle, char *proto, sa_property_t prop, 355 sa_optionset_t opt) 356 { 357 struct sa_plugin_ops *ops = find_protocol(proto); 358 int ret = 0; 359 360 if (ops != NULL && ops->sa_valid_prop != NULL) 361 ret = ops->sa_valid_prop(handle, prop, opt); 362 return (ret); 363 } 364 365 /* 366 * sa_proto_valid_space(proto, space) 367 * 368 * Check if space is valid optionspace for proto. 369 * Protocols that don't implement this don't support spaces. 370 */ 371 int 372 sa_proto_valid_space(char *proto, char *token) 373 { 374 struct sa_plugin_ops *ops = find_protocol(proto); 375 int ret = 0; 376 377 if (ops != NULL && ops->sa_valid_space != NULL) 378 ret = ops->sa_valid_space(token); 379 return (ret); 380 } 381 382 /* 383 * sa_proto_space_alias(proto, space) 384 * 385 * If the name for space is an alias, return its proper name. This is 386 * used to translate "default" values into proper form. 387 */ 388 char * 389 sa_proto_space_alias(char *proto, char *space) 390 { 391 struct sa_plugin_ops *ops = find_protocol(proto); 392 char *ret = space; 393 394 if (ops != NULL && ops->sa_space_alias != NULL) 395 ret = ops->sa_space_alias(space); 396 return (ret); 397 } 398 399 /* 400 * sa_proto_security_prop(proto, token) 401 * 402 * Check to see if the property name in token is a valid named 403 * optionset property. 404 */ 405 406 int 407 sa_proto_security_prop(char *proto, char *token) 408 { 409 struct sa_plugin_ops *ops = find_protocol(proto); 410 int ret = 0; 411 412 if (ops != NULL && ops->sa_security_prop != NULL) 413 ret = ops->sa_security_prop(token); 414 return (ret); 415 } 416 417 /* 418 * sa_proto_legacy_opts(proto, grouup, options) 419 * 420 * Have the protocol specific parser parse the options string and add 421 * an appropriate optionset to group. 422 */ 423 424 int 425 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options) 426 { 427 struct sa_plugin_ops *ops = find_protocol(proto); 428 int ret = SA_INVALID_PROTOCOL; 429 430 if (ops != NULL && ops->sa_legacy_opts != NULL) 431 ret = ops->sa_legacy_opts(group, options); 432 return (ret); 433 } 434 435 /* 436 * sa_proto_legacy_format(proto, group, hier) 437 * 438 * Return a legacy format string representing either the group's 439 * properties or the groups hierarchical properties. 440 */ 441 442 char * 443 sa_proto_legacy_format(char *proto, sa_group_t group, int hier) 444 { 445 struct sa_plugin_ops *ops = find_protocol(proto); 446 char *ret = NULL; 447 448 if (ops != NULL && ops->sa_legacy_format != NULL) 449 ret = ops->sa_legacy_format(group, hier); 450 return (ret); 451 } 452 453 void 454 sa_format_free(char *str) 455 { 456 free(str); 457 } 458 459 /* 460 * sharectl related API functions 461 */ 462 463 /* 464 * sa_proto_get_properties(proto) 465 * 466 * Return the set of properties that are specific to the 467 * protocol. These are usually in /etc/dfs/<proto> and related files, 468 * but only the protocol module knows which ones for sure. 469 */ 470 471 sa_protocol_properties_t 472 sa_proto_get_properties(char *proto) 473 { 474 struct sa_plugin_ops *ops = find_protocol(proto); 475 sa_protocol_properties_t props = NULL; 476 477 if (ops != NULL && ops->sa_get_proto_set != NULL) 478 props = ops->sa_get_proto_set(); 479 return (props); 480 } 481 482 /* 483 * sa_proto_set_property(proto, prop) 484 * 485 * Update the protocol specific property. 486 */ 487 488 int 489 sa_proto_set_property(char *proto, sa_property_t prop) 490 { 491 struct sa_plugin_ops *ops = find_protocol(proto); 492 int ret = SA_OK; 493 494 if (ops != NULL && ops->sa_set_proto_prop != NULL) 495 ret = ops->sa_set_proto_prop(prop); 496 return (ret); 497 } 498 499 /* 500 * sa_valid_protocol(proto) 501 * 502 * Check to see if the protocol specified is defined by a 503 * plugin. Returns true (1) or false (0) 504 */ 505 506 int 507 sa_valid_protocol(char *proto) 508 { 509 struct sa_plugin_ops *ops = find_protocol(proto); 510 return (ops != NULL); 511 } 512 513 /* 514 * Return the current operational status of the protocol 515 */ 516 517 char * 518 sa_get_protocol_status(char *proto) 519 { 520 struct sa_plugin_ops *ops = find_protocol(proto); 521 char *ret = NULL; 522 if (ops != NULL && ops->sa_get_proto_status != NULL) 523 ret = ops->sa_get_proto_status(proto); 524 return (ret); 525 } 526 527 /* 528 * sa_proto_update_legacy(proto, share) 529 * 530 * Update the protocol specific legacy files if necessary for the 531 * specified share. 532 */ 533 534 int 535 sa_proto_update_legacy(char *proto, sa_share_t share) 536 { 537 struct sa_plugin_ops *ops = find_protocol(proto); 538 int ret = SA_NOT_IMPLEMENTED; 539 540 if (ops != NULL) { 541 if (ops->sa_update_legacy != NULL) 542 ret = ops->sa_update_legacy(share); 543 } 544 return (ret); 545 } 546 547 /* 548 * sa_delete_legacy(proto, share) 549 * 550 * Remove the specified share from the protocol specific legacy files. 551 */ 552 553 int 554 sa_proto_delete_legacy(char *proto, sa_share_t share) 555 { 556 struct sa_plugin_ops *ops = find_protocol(proto); 557 int ret = SA_NOT_IMPLEMENTED; 558 559 if (ops != NULL) { 560 if (ops->sa_delete_legacy != NULL) 561 ret = ops->sa_delete_legacy(share); 562 } else { 563 if (proto != NULL) 564 ret = SA_NOT_IMPLEMENTED; 565 else 566 ret = SA_INVALID_PROTOCOL; 567 } 568 return (ret); 569 } 570 571 /* 572 * sa_proto_delete_section(proto, section) 573 * 574 * Remove the specified section from the protocol specific legacy files, 575 * if supported. 576 */ 577 578 int 579 sa_proto_delete_section(char *proto, char *section) 580 { 581 struct sa_plugin_ops *ops = find_protocol(proto); 582 int ret = SA_OK; 583 584 if (ops != NULL) { 585 if (ops->sa_delete_proto_section != NULL) 586 ret = ops->sa_delete_proto_section(section); 587 } else { 588 if (proto != NULL) 589 ret = SA_NOT_IMPLEMENTED; 590 else 591 ret = SA_INVALID_PROTOCOL; 592 } 593 return (ret); 594 } 595 596 /* 597 * sa_proto_change_notify(share, char *protocol) 598 * 599 * Notify the protocol that a change has been made to the share 600 */ 601 602 int 603 sa_proto_change_notify(sa_share_t share, char *proto) 604 { 605 struct sa_plugin_ops *ops = find_protocol(proto); 606 int ret = SA_NOT_IMPLEMENTED; 607 608 if (ops != NULL) { 609 if (ops->sa_change_notify != NULL) 610 ret = ops->sa_change_notify(share); 611 } else if (proto == NULL) { 612 613 ret = SA_INVALID_PROTOCOL; 614 } 615 return (ret); 616 } 617 618 /* 619 * sa_proto_notify_resource(resource, char *protocol) 620 * 621 * Notify the protocol that a change has been made to the share 622 */ 623 624 int 625 sa_proto_notify_resource(sa_resource_t resource, char *proto) 626 { 627 struct sa_plugin_ops *ops = find_protocol(proto); 628 int ret = SA_NOT_IMPLEMENTED; 629 630 if (ops != NULL) { 631 if (ops->sa_notify_resource != NULL) 632 ret = ops->sa_notify_resource(resource); 633 } else if (proto == NULL) { 634 ret = SA_INVALID_PROTOCOL; 635 } 636 return (ret); 637 } 638 639 /* 640 * sa_proto_get_featureset(protocol) 641 * 642 * Get bitmask of defined features of the protocol. These are 643 * primarily things like SA_FEATURE_RESOURCE (shares are by resource 644 * name rather than path) and other operational features that affect 645 * behavior. 646 */ 647 648 uint64_t 649 sa_proto_get_featureset(char *proto) 650 { 651 struct sa_plugin_ops *ops = find_protocol(proto); 652 uint64_t ret = 0; 653 654 if (ops != NULL) { 655 if (ops->sa_features != NULL) 656 ret = ops->sa_features(); 657 } 658 /* if not implemented, zero is valid */ 659 return (ret); 660 } 661 662 /* 663 * sa_proto_get_transients(sa_handle_t) 664 * 665 * Called to get any protocol specific transient shares. NFS doesn't 666 * use this since the info is in sharetab which is processed as a 667 * common transient store. 668 * 669 * The protocol plugin should verify that the share isn't in the 670 * repository and then add it as a transient. 671 * 672 * Not having an entry is not a problem. It returns 0 in that case. 673 */ 674 675 int 676 sa_proto_get_transients(sa_handle_t handle, char *proto) 677 { 678 struct sa_plugin_ops *ops = find_protocol(proto); 679 int ret = 0; 680 681 if (ops != NULL) { 682 if (ops->sa_get_transient_shares != NULL) 683 ret = ops->sa_get_transient_shares(handle); 684 } 685 return (ret); 686 } 687 688 /* 689 * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname) 690 * 691 * Protocols may need to know when a resource has changed names in 692 * order to notify clients. This must be done "before" the name in the 693 * resource has been changed. Not being implemented is not a problem. 694 */ 695 696 int 697 sa_proto_rename_resource(sa_handle_t handle, char *proto, 698 sa_resource_t resource, char *newname) 699 { 700 struct sa_plugin_ops *ops = find_protocol(proto); 701 int ret = SA_OK; 702 703 if (ops != NULL) { 704 if (ops->sa_rename_resource != NULL) 705 ret = ops->sa_rename_resource(handle, resource, 706 newname); 707 } 708 return (ret); 709 } 710