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 /* 191 * Free up all the protocols, calling their fini, if there is 192 * one. 193 */ 194 while (sap_proto_list != NULL) { 195 struct sa_proto_plugin *next; 196 197 next = sap_proto_list->plugin_next; 198 sap_proto_list->plugin_ops->sa_fini(); 199 if (sap_proto_list->plugin_handle != NULL) 200 (void) dlclose(sap_proto_list->plugin_handle); 201 free(sap_proto_list); 202 sap_proto_list = next; 203 } 204 if (sa_proto_handle.sa_ops != NULL) { 205 free(sa_proto_handle.sa_ops); 206 sa_proto_handle.sa_ops = NULL; 207 } 208 if (sa_proto_handle.sa_proto != NULL) { 209 free(sa_proto_handle.sa_proto); 210 sa_proto_handle.sa_proto = NULL; 211 } 212 sa_proto_handle.sa_num_proto = 0; 213 } 214 215 /* 216 * find_protocol(proto) 217 * 218 * Search the plugin list for the specified protocol and return the 219 * ops vector. NULL if protocol is not defined. 220 */ 221 222 static struct sa_plugin_ops * 223 find_protocol(char *proto) 224 { 225 int i; 226 struct sa_plugin_ops *ops = NULL; 227 extern mutex_t sa_global_lock; 228 229 (void) mutex_lock(&sa_global_lock); 230 if (proto != NULL) { 231 for (i = 0; i < sa_proto_handle.sa_num_proto; i++) { 232 if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0) { 233 ops = sa_proto_handle.sa_ops[i]; 234 break; 235 } 236 } 237 } 238 (void) mutex_unlock(&sa_global_lock); 239 return (ops); 240 } 241 242 /* 243 * sa_proto_share(proto, share) 244 * 245 * Activate a share for the specified protocol. 246 */ 247 248 int 249 sa_proto_share(char *proto, sa_share_t share) 250 { 251 struct sa_plugin_ops *ops = find_protocol(proto); 252 int ret = SA_INVALID_PROTOCOL; 253 254 if (ops != NULL && ops->sa_share != NULL) 255 ret = ops->sa_share(share); 256 return (ret); 257 } 258 259 /* 260 * sa_proto_unshare(proto, share) 261 * 262 * Deactivate (unshare) the share for this protocol. 263 */ 264 265 int 266 sa_proto_unshare(sa_share_t share, char *proto, char *path) 267 { 268 struct sa_plugin_ops *ops = find_protocol(proto); 269 int ret = SA_INVALID_PROTOCOL; 270 271 if (ops != NULL && ops->sa_unshare != NULL) 272 ret = ops->sa_unshare(share, path); 273 return (ret); 274 } 275 276 /* 277 * sa_proto_share_resource(char *proto, sa_resource_t resource) 278 * 279 * For protocols that actually enable at the resource level, do the 280 * protocol specific resource enable. If it doesn't, return an error. 281 * Note that the resource functions are optional so can return 282 * SA_NOT_SUPPORTED. 283 */ 284 285 int 286 sa_proto_share_resource(char *proto, sa_resource_t resource) 287 { 288 struct sa_plugin_ops *ops = find_protocol(proto); 289 int ret = SA_INVALID_PROTOCOL; 290 291 if (ops != NULL) { 292 if (ops->sa_enable_resource != NULL) 293 ret = ops->sa_enable_resource(resource); 294 else 295 ret = SA_NOT_SUPPORTED; 296 } 297 return (ret); 298 } 299 300 /* 301 * sa_proto_unshare_resource(char *proto, sa_resource_t resource) 302 * 303 * For protocols that actually disable at the resource level, do the 304 * protocol specific resource disable. If it doesn't, return an error. 305 */ 306 307 int 308 sa_proto_unshare_resource(char *proto, sa_resource_t resource) 309 { 310 struct sa_plugin_ops *ops = find_protocol(proto); 311 int ret = SA_INVALID_PROTOCOL; 312 313 if (ops != NULL) { 314 if (ops->sa_disable_resource != NULL) 315 ret = ops->sa_disable_resource(resource); 316 else 317 ret = SA_NOT_SUPPORTED; 318 } 319 return (ret); 320 } 321 322 /* 323 * sa_proto_valid_prop(handle, proto, prop, opt) 324 * 325 * Check to see if the specified prop is valid for this protocol. 326 */ 327 328 int 329 sa_proto_valid_prop(sa_handle_t handle, char *proto, sa_property_t prop, 330 sa_optionset_t opt) 331 { 332 struct sa_plugin_ops *ops = find_protocol(proto); 333 int ret = 0; 334 335 if (ops != NULL && ops->sa_valid_prop != NULL) 336 ret = ops->sa_valid_prop(handle, prop, opt); 337 return (ret); 338 } 339 340 /* 341 * sa_proto_valid_space(proto, space) 342 * 343 * Check if space is valid optionspace for proto. 344 * Protocols that don't implement this don't support spaces. 345 */ 346 int 347 sa_proto_valid_space(char *proto, char *token) 348 { 349 struct sa_plugin_ops *ops = find_protocol(proto); 350 int ret = 0; 351 352 if (ops != NULL && ops->sa_valid_space != NULL) 353 ret = ops->sa_valid_space(token); 354 return (ret); 355 } 356 357 /* 358 * sa_proto_space_alias(proto, space) 359 * 360 * If the name for space is an alias, return its proper name. This is 361 * used to translate "default" values into proper form. 362 */ 363 char * 364 sa_proto_space_alias(char *proto, char *space) 365 { 366 struct sa_plugin_ops *ops = find_protocol(proto); 367 char *ret = space; 368 369 if (ops != NULL && ops->sa_space_alias != NULL) 370 ret = ops->sa_space_alias(space); 371 return (ret); 372 } 373 374 /* 375 * sa_proto_security_prop(proto, token) 376 * 377 * Check to see if the property name in token is a valid named 378 * optionset property. 379 */ 380 381 int 382 sa_proto_security_prop(char *proto, char *token) 383 { 384 struct sa_plugin_ops *ops = find_protocol(proto); 385 int ret = 0; 386 387 if (ops != NULL && ops->sa_security_prop != NULL) 388 ret = ops->sa_security_prop(token); 389 return (ret); 390 } 391 392 /* 393 * sa_proto_legacy_opts(proto, grouup, options) 394 * 395 * Have the protocol specific parser parse the options string and add 396 * an appropriate optionset to group. 397 */ 398 399 int 400 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options) 401 { 402 struct sa_plugin_ops *ops = find_protocol(proto); 403 int ret = SA_INVALID_PROTOCOL; 404 405 if (ops != NULL && ops->sa_legacy_opts != NULL) 406 ret = ops->sa_legacy_opts(group, options); 407 return (ret); 408 } 409 410 /* 411 * sa_proto_legacy_format(proto, group, hier) 412 * 413 * Return a legacy format string representing either the group's 414 * properties or the groups hierarchical properties. 415 */ 416 417 char * 418 sa_proto_legacy_format(char *proto, sa_group_t group, int hier) 419 { 420 struct sa_plugin_ops *ops = find_protocol(proto); 421 char *ret = NULL; 422 423 if (ops != NULL && ops->sa_legacy_format != NULL) 424 ret = ops->sa_legacy_format(group, hier); 425 return (ret); 426 } 427 428 void 429 sa_format_free(char *str) 430 { 431 free(str); 432 } 433 434 /* 435 * sharectl related API functions 436 */ 437 438 /* 439 * sa_proto_get_properties(proto) 440 * 441 * Return the set of properties that are specific to the 442 * protocol. These are usually in /etc/dfs/<proto> and related files, 443 * but only the protocol module knows which ones for sure. 444 */ 445 446 sa_protocol_properties_t 447 sa_proto_get_properties(char *proto) 448 { 449 struct sa_plugin_ops *ops = find_protocol(proto); 450 sa_protocol_properties_t props = NULL; 451 452 if (ops != NULL && ops->sa_get_proto_set != NULL) 453 props = ops->sa_get_proto_set(); 454 return (props); 455 } 456 457 /* 458 * sa_proto_set_property(proto, prop) 459 * 460 * Update the protocol specific property. 461 */ 462 463 int 464 sa_proto_set_property(char *proto, sa_property_t prop) 465 { 466 struct sa_plugin_ops *ops = find_protocol(proto); 467 int ret = SA_OK; 468 469 if (ops != NULL && ops->sa_set_proto_prop != NULL) 470 ret = ops->sa_set_proto_prop(prop); 471 return (ret); 472 } 473 474 /* 475 * sa_valid_protocol(proto) 476 * 477 * Check to see if the protocol specified is defined by a 478 * plugin. Returns true (1) or false (0) 479 */ 480 481 int 482 sa_valid_protocol(char *proto) 483 { 484 struct sa_plugin_ops *ops = find_protocol(proto); 485 return (ops != NULL); 486 } 487 488 /* 489 * Return the current operational status of the protocol 490 */ 491 492 char * 493 sa_get_protocol_status(char *proto) 494 { 495 struct sa_plugin_ops *ops = find_protocol(proto); 496 char *ret = NULL; 497 if (ops != NULL && ops->sa_get_proto_status != NULL) 498 ret = ops->sa_get_proto_status(proto); 499 return (ret); 500 } 501 502 /* 503 * sa_proto_update_legacy(proto, share) 504 * 505 * Update the protocol specific legacy files if necessary for the 506 * specified share. 507 */ 508 509 int 510 sa_proto_update_legacy(char *proto, sa_share_t share) 511 { 512 struct sa_plugin_ops *ops = find_protocol(proto); 513 int ret = SA_NOT_IMPLEMENTED; 514 515 if (ops != NULL) { 516 if (ops->sa_update_legacy != NULL) 517 ret = ops->sa_update_legacy(share); 518 } 519 return (ret); 520 } 521 522 /* 523 * sa_delete_legacy(proto, share) 524 * 525 * Remove the specified share from the protocol specific legacy files. 526 */ 527 528 int 529 sa_proto_delete_legacy(char *proto, sa_share_t share) 530 { 531 struct sa_plugin_ops *ops = find_protocol(proto); 532 int ret = SA_NOT_IMPLEMENTED; 533 534 if (ops != NULL) { 535 if (ops->sa_delete_legacy != NULL) 536 ret = ops->sa_delete_legacy(share); 537 } else { 538 if (proto != NULL) 539 ret = SA_NOT_IMPLEMENTED; 540 else 541 ret = SA_INVALID_PROTOCOL; 542 } 543 return (ret); 544 } 545 546 /* 547 * sa_proto_delete_section(proto, section) 548 * 549 * Remove the specified section from the protocol specific legacy files, 550 * if supported. 551 */ 552 553 int 554 sa_proto_delete_section(char *proto, char *section) 555 { 556 struct sa_plugin_ops *ops = find_protocol(proto); 557 int ret = SA_OK; 558 559 if (ops != NULL) { 560 if (ops->sa_delete_proto_section != NULL) 561 ret = ops->sa_delete_proto_section(section); 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_change_notify(share, char *protocol) 573 * 574 * Notify the protocol that a change has been made to the share 575 */ 576 577 int 578 sa_proto_change_notify(sa_share_t share, char *proto) 579 { 580 struct sa_plugin_ops *ops = find_protocol(proto); 581 int ret = SA_NOT_IMPLEMENTED; 582 583 if (ops != NULL) { 584 if (ops->sa_change_notify != NULL) 585 ret = ops->sa_change_notify(share); 586 } else if (proto == NULL) { 587 588 ret = SA_INVALID_PROTOCOL; 589 } 590 return (ret); 591 } 592 593 /* 594 * sa_proto_notify_resource(resource, char *protocol) 595 * 596 * Notify the protocol that a change has been made to the share 597 */ 598 599 int 600 sa_proto_notify_resource(sa_resource_t resource, char *proto) 601 { 602 struct sa_plugin_ops *ops = find_protocol(proto); 603 int ret = SA_NOT_IMPLEMENTED; 604 605 if (ops != NULL) { 606 if (ops->sa_notify_resource != NULL) 607 ret = ops->sa_notify_resource(resource); 608 } else if (proto == NULL) { 609 ret = SA_INVALID_PROTOCOL; 610 } 611 return (ret); 612 } 613 614 /* 615 * sa_proto_get_featureset(protocol) 616 * 617 * Get bitmask of defined features of the protocol. These are 618 * primarily things like SA_FEATURE_RESOURCE (shares are by resource 619 * name rather than path) and other operational features that affect 620 * behavior. 621 */ 622 623 uint64_t 624 sa_proto_get_featureset(char *proto) 625 { 626 struct sa_plugin_ops *ops = find_protocol(proto); 627 uint64_t ret = 0; 628 629 if (ops != NULL) { 630 if (ops->sa_features != NULL) 631 ret = ops->sa_features(); 632 } 633 /* if not implemented, zero is valid */ 634 return (ret); 635 } 636 637 /* 638 * sa_proto_get_transients(sa_handle_t) 639 * 640 * Called to get any protocol specific transient shares. NFS doesn't 641 * use this since the info is in sharetab which is processed as a 642 * common transient store. 643 * 644 * The protocol plugin should verify that the share isn't in the 645 * repository and then add it as a transient. 646 * 647 * Not having an entry is not a problem. It returns 0 in that case. 648 */ 649 650 int 651 sa_proto_get_transients(sa_handle_t handle, char *proto) 652 { 653 struct sa_plugin_ops *ops = find_protocol(proto); 654 int ret = 0; 655 656 if (ops != NULL) { 657 if (ops->sa_get_transient_shares != NULL) 658 ret = ops->sa_get_transient_shares(handle); 659 } 660 return (ret); 661 } 662 663 /* 664 * sa_proto_rename_resource(sa_handle_t, proto, sa_resource_t, newname) 665 * 666 * Protocols may need to know when a resource has changed names in 667 * order to notify clients. This must be done "before" the name in the 668 * resource has been changed. Not being implemented is not a problem. 669 */ 670 671 int 672 sa_proto_rename_resource(sa_handle_t handle, char *proto, 673 sa_resource_t resource, char *newname) 674 { 675 struct sa_plugin_ops *ops = find_protocol(proto); 676 int ret = SA_OK; 677 678 if (ops != NULL) { 679 if (ops->sa_rename_resource != NULL) 680 ret = ops->sa_rename_resource(handle, resource, 681 newname); 682 } 683 return (ret); 684 } 685