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