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