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