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 2006 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 42 /* 43 * protocol plugin interface 44 * 45 * finds plugins and makes them accessible. This is only "used" by 46 * libshare.so. 47 */ 48 49 struct sa_proto_plugin *sap_proto_list; 50 51 static struct sa_proto_handle sa_proto_handle; 52 53 void proto_plugin_fini(); 54 55 /* 56 * proto_plugin_init() 57 * 58 * Initialize the protocol specific plugin modules. 59 * 60 * Walk /usr/lib/fs/\* for libshare_*.so modules. That is, 61 * /usr/lib/fs/nfs/libshare_nfs.so. The protocol specific directory 62 * would have a modules with name libshare_<proto>.so. If one is 63 * found, initialize it and add to the internal list of 64 * protocols. These are used for protocol specifici operations. 65 */ 66 67 int 68 proto_plugin_init() 69 { 70 struct sa_proto_plugin *proto; 71 int num_protos = 0; 72 int err; 73 struct sa_plugin_ops *plugin_ops; 74 void *dlhandle; 75 DIR *dir; 76 struct dirent *dent; 77 int ret = SA_OK; 78 struct stat st; 79 80 /* 81 * should walk "/usr/lib/fs/" for files of the form: 82 * libshare_*.so 83 */ 84 dir = opendir(SA_LIB_DIR); 85 if (dir != NULL) { 86 while (ret == SA_OK && (dent = readdir(dir)) != NULL) { 87 char path[MAXPATHLEN]; 88 (void) snprintf(path, MAXPATHLEN, 89 "%s/%s/libshare_%s.so", SA_LIB_DIR, 90 dent->d_name, dent->d_name); 91 if (stat(path, &st) < 0) { 92 /* file doesn't exist, so don't try to map it */ 93 continue; 94 } 95 dlhandle = dlopen(path, RTLD_NOW|RTLD_GLOBAL|RTLD_WORLD); 96 if (dlhandle != NULL) { 97 plugin_ops = (struct sa_plugin_ops *) 98 dlsym(dlhandle, "sa_plugin_ops"); 99 proto = (struct sa_proto_plugin *) 100 calloc(1, sizeof (struct sa_proto_plugin)); 101 if (proto != NULL) { 102 proto->plugin_ops = plugin_ops; 103 proto->plugin_handle = dlhandle; 104 num_protos++; 105 proto->plugin_next = sap_proto_list; 106 sap_proto_list = proto; 107 } else { 108 ret = SA_NO_MEMORY; 109 } 110 } else { 111 (void) fprintf(stderr, 112 gettext("Error in plugin for protocol %s: %s\n"), 113 dent->d_name, dlerror()); 114 } 115 } 116 (void) closedir(dir); 117 } 118 if (ret == SA_OK) { 119 sa_proto_handle.sa_proto = 120 (char **)calloc(num_protos, sizeof (char *)); 121 sa_proto_handle.sa_ops = 122 (struct sa_plugin_ops **)calloc(num_protos, 123 sizeof (struct sa_plugin_ops *)); 124 if (sa_proto_handle.sa_proto != NULL && 125 sa_proto_handle.sa_ops != NULL) { 126 int i; 127 struct sa_proto_plugin *tmp; 128 for (i = 0, tmp = sap_proto_list; i < num_protos; 129 tmp = tmp->plugin_next) { 130 err = 0; 131 if (tmp->plugin_ops->sa_init != NULL) 132 err = tmp->plugin_ops->sa_init(); 133 if (err == SA_OK) { 134 /* only include if the init succeeded or was NULL */ 135 sa_proto_handle.sa_num_proto++; 136 sa_proto_handle.sa_ops[i] = tmp->plugin_ops; 137 sa_proto_handle.sa_proto[i] = 138 tmp->plugin_ops->sa_protocol; 139 i++; 140 } 141 } 142 } 143 } else { 144 /* there was an error, so cleanup prior to return of failure. */ 145 proto_plugin_fini(); 146 } 147 return (ret); 148 } 149 150 /* 151 * proto_plugin_fini() 152 * 153 * uninitialize all the plugin modules. 154 */ 155 156 void 157 proto_plugin_fini() 158 { 159 /* 160 * free up all the protocols, calling their fini, if there is 161 * one. 162 */ 163 while (sap_proto_list != NULL) { 164 struct sa_proto_plugin *next; 165 next = sap_proto_list->plugin_next; 166 sap_proto_list->plugin_ops->sa_fini(); 167 if (sap_proto_list->plugin_handle != NULL) 168 (void) dlclose(sap_proto_list->plugin_handle); 169 free(sap_proto_list); 170 sap_proto_list = next; 171 } 172 if (sa_proto_handle.sa_ops != NULL) { 173 free(sa_proto_handle.sa_ops); 174 sa_proto_handle.sa_ops = NULL; 175 } 176 if (sa_proto_handle.sa_proto != NULL) { 177 free(sa_proto_handle.sa_proto); 178 sa_proto_handle.sa_proto = NULL; 179 } 180 sa_proto_handle.sa_num_proto = 0; 181 } 182 183 /* 184 * find_protocol(proto) 185 * 186 * Search the plugin list for the specified protocol and return the 187 * ops vector. NULL if protocol is not defined. 188 */ 189 190 static struct sa_plugin_ops * 191 find_protocol(char *proto) 192 { 193 int i; 194 195 if (proto != NULL) { 196 for (i = 0; i < sa_proto_handle.sa_num_proto; i++) { 197 if (strcmp(proto, sa_proto_handle.sa_proto[i]) == 0) 198 return (sa_proto_handle.sa_ops[i]); 199 } 200 } 201 return (NULL); 202 } 203 204 /* 205 * sa_proto_share(proto, share) 206 * 207 * Activate a share for the specified protocol. 208 */ 209 210 int 211 sa_proto_share(char *proto, sa_share_t share) 212 { 213 struct sa_plugin_ops *ops = find_protocol(proto); 214 int ret = SA_INVALID_PROTOCOL; 215 216 if (ops != NULL && ops->sa_share != NULL) 217 ret = ops->sa_share(share); 218 return (ret); 219 } 220 221 /* 222 * sa_proto_unshare(proto, path) 223 * 224 * Deactivate (unshare) the path for this protocol. 225 */ 226 227 int 228 sa_proto_unshare(char *proto, char *path) 229 { 230 struct sa_plugin_ops *ops = find_protocol(proto); 231 int ret = SA_INVALID_PROTOCOL; 232 233 if (ops != NULL && ops->sa_unshare != NULL) 234 ret = ops->sa_unshare(path); 235 return (ret); 236 } 237 238 /* 239 * sa_proto_valid_prop(proto, prop, opt) 240 * 241 * check to see if the specified prop is valid for this protocol. 242 */ 243 244 int 245 sa_proto_valid_prop(char *proto, sa_property_t prop, sa_optionset_t opt) 246 { 247 struct sa_plugin_ops *ops = find_protocol(proto); 248 int ret = 0; 249 250 if (ops != NULL && ops->sa_valid_prop != NULL) 251 ret = ops->sa_valid_prop(prop, opt); 252 return (ret); 253 } 254 255 /* 256 * sa_proto_valid_space(proto, space) 257 * 258 * check if space is valid optionspace for proto. 259 * Protocols that don't implement this don't support spaces. 260 */ 261 int 262 sa_proto_valid_space(char *proto, char *token) 263 { 264 struct sa_plugin_ops *ops = find_protocol(proto); 265 int ret = 0; 266 267 if (ops != NULL && ops->sa_valid_space != NULL) 268 ret = ops->sa_valid_space(token); 269 return (ret); 270 } 271 272 /* 273 * sa_proto_space_alias(proto, space) 274 * 275 * if the name for space is an alias, return its proper name. This is 276 * used to translate "default" values into proper form. 277 */ 278 char * 279 sa_proto_space_alias(char *proto, char *space) 280 { 281 struct sa_plugin_ops *ops = find_protocol(proto); 282 char *ret = space; 283 284 if (ops != NULL && ops->sa_space_alias != NULL) 285 ret = ops->sa_space_alias(space); 286 return (ret); 287 } 288 289 /* 290 * sa_proto_security_prop(proto, token) 291 * 292 * Check to see if the property name in token is a valid named 293 * optionset property. 294 */ 295 296 int 297 sa_proto_security_prop(char *proto, char *token) 298 { 299 struct sa_plugin_ops *ops = find_protocol(proto); 300 int ret = 0; 301 302 if (ops != NULL && ops->sa_security_prop != NULL) 303 ret = ops->sa_security_prop(token); 304 return (ret); 305 } 306 307 /* 308 * sa_proto_legacy_opts(proto, grouup, options) 309 * 310 * Have the protocol specific parser parse the options string and add 311 * an appropriate optionset to group. 312 */ 313 314 int 315 sa_proto_legacy_opts(char *proto, sa_group_t group, char *options) 316 { 317 struct sa_plugin_ops *ops = find_protocol(proto); 318 int ret = SA_INVALID_PROTOCOL; 319 320 if (ops != NULL && ops->sa_legacy_opts != NULL) 321 ret = ops->sa_legacy_opts(group, options); 322 return (ret); 323 } 324 325 /* 326 * sa_proto_legacy_format(proto, group, hier) 327 * 328 * Return a legacy format string representing either the group's 329 * properties or the groups hierarchical properties. 330 */ 331 332 char * 333 sa_proto_legacy_format(char *proto, sa_group_t group, int hier) 334 { 335 struct sa_plugin_ops *ops = find_protocol(proto); 336 char *ret = NULL; 337 338 if (ops != NULL && ops->sa_legacy_format != NULL) 339 ret = ops->sa_legacy_format(group, hier); 340 return (ret); 341 } 342 343 void 344 sa_format_free(char *str) 345 { 346 free(str); 347 } 348 349 /* 350 * sharectl related API functions 351 */ 352 353 /* 354 * sa_proto_get_properties(proto) 355 * 356 * Return the set of properties that are specific to the 357 * protocol. These are usually in /etc/dfs/<proto> and related files, 358 * but only the protocol module knows which ones for sure. 359 */ 360 361 sa_protocol_properties_t 362 sa_proto_get_properties(char *proto) 363 { 364 struct sa_plugin_ops *ops = find_protocol(proto); 365 sa_protocol_properties_t props = NULL; 366 367 if (ops != NULL && ops->sa_get_proto_set != NULL) 368 props = ops->sa_get_proto_set(); 369 return (props); 370 } 371 372 /* 373 * sa_proto_set_property(proto, prop) 374 * 375 * Update the protocol specifiec property. 376 */ 377 378 int 379 sa_proto_set_property(char *proto, sa_property_t prop) 380 { 381 struct sa_plugin_ops *ops = find_protocol(proto); 382 int ret = SA_OK; 383 if (ops != NULL && ops->sa_set_proto_prop != NULL) 384 ret = ops->sa_set_proto_prop(prop); 385 return (ret); 386 } 387 388 /* 389 * sa_valid_protocol(proto) 390 * 391 * check to see if the protocol specified is defined by a 392 * plugin. Returns true (1) or false (0) 393 */ 394 395 int 396 sa_valid_protocol(char *proto) 397 { 398 struct sa_plugin_ops *ops = find_protocol(proto); 399 return (ops != NULL); 400 } 401 402 /* 403 * Return the current operational status of the protocol 404 */ 405 406 char * 407 sa_get_protocol_status(char *proto) 408 { 409 struct sa_plugin_ops *ops = find_protocol(proto); 410 char *ret = NULL; 411 if (ops != NULL && ops->sa_get_proto_status != NULL) 412 ret = ops->sa_get_proto_status(proto); 413 return (ret); 414 } 415 416 /* 417 * sa_proto_update_legacy(proto, share) 418 * 419 * Update the protocol specific legacy files if necessary for the 420 * specified share. 421 */ 422 423 int 424 sa_proto_update_legacy(char *proto, sa_share_t share) 425 { 426 struct sa_plugin_ops *ops = find_protocol(proto); 427 int ret = SA_NOT_IMPLEMENTED; 428 429 if (ops != NULL) { 430 if (ops->sa_update_legacy != NULL) 431 ret = ops->sa_update_legacy(share); 432 } 433 return (ret); 434 } 435 436 /* 437 * sa_delete_legacy(proto, share) 438 * 439 * remove the specified share from the protocol specific legacy files. 440 */ 441 442 int 443 sa_proto_delete_legacy(char *proto, sa_share_t share) 444 { 445 struct sa_plugin_ops *ops = find_protocol(proto); 446 int ret = SA_OK; 447 448 if (ops != NULL) { 449 if (ops->sa_delete_legacy != NULL) 450 ret = ops->sa_delete_legacy(share); 451 } else { 452 if (proto != NULL) 453 ret = SA_NOT_IMPLEMENTED; 454 else 455 ret = SA_INVALID_PROTOCOL; 456 } 457 return (ret); 458 } 459