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