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