xref: /onnv-gate/usr/src/lib/libreparse/common/fs_reparse_lib.c (revision 10793:34709091de6d)
1*10793Sdai.ngo@sun.com /*
2*10793Sdai.ngo@sun.com  * CDDL HEADER START
3*10793Sdai.ngo@sun.com  *
4*10793Sdai.ngo@sun.com  * The contents of this file are subject to the terms of the
5*10793Sdai.ngo@sun.com  * Common Development and Distribution License (the "License").
6*10793Sdai.ngo@sun.com  * You may not use this file except in compliance with the License.
7*10793Sdai.ngo@sun.com  *
8*10793Sdai.ngo@sun.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10793Sdai.ngo@sun.com  * or http://www.opensolaris.org/os/licensing.
10*10793Sdai.ngo@sun.com  * See the License for the specific language governing permissions
11*10793Sdai.ngo@sun.com  * and limitations under the License.
12*10793Sdai.ngo@sun.com  *
13*10793Sdai.ngo@sun.com  * When distributing Covered Code, include this CDDL HEADER in each
14*10793Sdai.ngo@sun.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10793Sdai.ngo@sun.com  * If applicable, add the following below this CDDL HEADER, with the
16*10793Sdai.ngo@sun.com  * fields enclosed by brackets "[]" replaced with your own identifying
17*10793Sdai.ngo@sun.com  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10793Sdai.ngo@sun.com  *
19*10793Sdai.ngo@sun.com  * CDDL HEADER END
20*10793Sdai.ngo@sun.com  */
21*10793Sdai.ngo@sun.com 
22*10793Sdai.ngo@sun.com /*
23*10793Sdai.ngo@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*10793Sdai.ngo@sun.com  * Use is subject to license terms.
25*10793Sdai.ngo@sun.com  */
26*10793Sdai.ngo@sun.com 
27*10793Sdai.ngo@sun.com #include <stdio.h>
28*10793Sdai.ngo@sun.com #include <stdlib.h>
29*10793Sdai.ngo@sun.com #include <unistd.h>
30*10793Sdai.ngo@sun.com #include <strings.h>
31*10793Sdai.ngo@sun.com #include <string.h>
32*10793Sdai.ngo@sun.com #include <dirent.h>
33*10793Sdai.ngo@sun.com #include <sys/types.h>
34*10793Sdai.ngo@sun.com #include <sys/stat.h>
35*10793Sdai.ngo@sun.com #include <sys/param.h>
36*10793Sdai.ngo@sun.com #include <sys/errno.h>
37*10793Sdai.ngo@sun.com #include <limits.h>
38*10793Sdai.ngo@sun.com #include <libnvpair.h>
39*10793Sdai.ngo@sun.com #include <dlfcn.h>
40*10793Sdai.ngo@sun.com #include <libintl.h>
41*10793Sdai.ngo@sun.com #include <sys/systeminfo.h>
42*10793Sdai.ngo@sun.com #include <sys/fs_reparse.h>
43*10793Sdai.ngo@sun.com #include "rp_plugin.h"
44*10793Sdai.ngo@sun.com 
45*10793Sdai.ngo@sun.com #define	MAXISALEN	257	/* based on sysinfo(2) man page */
46*10793Sdai.ngo@sun.com 
47*10793Sdai.ngo@sun.com static rp_proto_handle_t rp_proto_handle;
48*10793Sdai.ngo@sun.com static rp_proto_plugin_t *rp_proto_list;
49*10793Sdai.ngo@sun.com 
50*10793Sdai.ngo@sun.com int rp_plugin_init(void);
51*10793Sdai.ngo@sun.com static void proto_plugin_fini(void);
52*10793Sdai.ngo@sun.com static rp_plugin_ops_t *rp_find_protocol(const char *svctype);
53*10793Sdai.ngo@sun.com 
54*10793Sdai.ngo@sun.com extern int errno;
55*10793Sdai.ngo@sun.com static int rp_plugin_inited = 0;
56*10793Sdai.ngo@sun.com 
57*10793Sdai.ngo@sun.com /*
58*10793Sdai.ngo@sun.com  * reparse_create()
59*10793Sdai.ngo@sun.com  *
60*10793Sdai.ngo@sun.com  * Create a symlink at the specified 'path' as a reparse point.
61*10793Sdai.ngo@sun.com  * This function will fail if path refers to an existing file system
62*10793Sdai.ngo@sun.com  * object or an object named string already exists at the given path.
63*10793Sdai.ngo@sun.com  *
64*10793Sdai.ngo@sun.com  * return 0 if ok else return error code.
65*10793Sdai.ngo@sun.com  */
66*10793Sdai.ngo@sun.com int
reparse_create(const char * path,const char * string)67*10793Sdai.ngo@sun.com reparse_create(const char *path, const char *string)
68*10793Sdai.ngo@sun.com {
69*10793Sdai.ngo@sun.com 	int err;
70*10793Sdai.ngo@sun.com 	struct stat sbuf;
71*10793Sdai.ngo@sun.com 
72*10793Sdai.ngo@sun.com 	if (path == NULL || string == NULL)
73*10793Sdai.ngo@sun.com 		return (EINVAL);
74*10793Sdai.ngo@sun.com 
75*10793Sdai.ngo@sun.com 	if ((err = reparse_validate(string)) != 0)
76*10793Sdai.ngo@sun.com 		return (err);
77*10793Sdai.ngo@sun.com 
78*10793Sdai.ngo@sun.com 	/* check if object exists */
79*10793Sdai.ngo@sun.com 	if (lstat(path, &sbuf) == 0)
80*10793Sdai.ngo@sun.com 		return (EEXIST);
81*10793Sdai.ngo@sun.com 
82*10793Sdai.ngo@sun.com 	return (symlink(string, path) ? errno : 0);
83*10793Sdai.ngo@sun.com }
84*10793Sdai.ngo@sun.com 
85*10793Sdai.ngo@sun.com /*
86*10793Sdai.ngo@sun.com  * reparse_unparse()
87*10793Sdai.ngo@sun.com  *
88*10793Sdai.ngo@sun.com  * Convert an nvlist back to a string format suitable to write
89*10793Sdai.ngo@sun.com  * to the reparse point symlink body.  The string returned is in
90*10793Sdai.ngo@sun.com  * allocated memory and must be freed by the caller.
91*10793Sdai.ngo@sun.com  *
92*10793Sdai.ngo@sun.com  * return 0 if ok else return error code.
93*10793Sdai.ngo@sun.com  */
94*10793Sdai.ngo@sun.com int
reparse_unparse(nvlist_t * nvl,char ** stringp)95*10793Sdai.ngo@sun.com reparse_unparse(nvlist_t *nvl, char **stringp)
96*10793Sdai.ngo@sun.com {
97*10793Sdai.ngo@sun.com 	int err, buflen;
98*10793Sdai.ngo@sun.com 	char *buf, *stype, *val;
99*10793Sdai.ngo@sun.com 	nvpair_t *curr;
100*10793Sdai.ngo@sun.com 
101*10793Sdai.ngo@sun.com 	if (nvl == NULL || stringp == NULL ||
102*10793Sdai.ngo@sun.com 	    ((curr = nvlist_next_nvpair(nvl, NULL)) == NULL))
103*10793Sdai.ngo@sun.com 		return (EINVAL);
104*10793Sdai.ngo@sun.com 
105*10793Sdai.ngo@sun.com 	buflen = SYMLINK_MAX;
106*10793Sdai.ngo@sun.com 	if ((buf = malloc(buflen)) == NULL)
107*10793Sdai.ngo@sun.com 		return (ENOMEM);
108*10793Sdai.ngo@sun.com 
109*10793Sdai.ngo@sun.com 	err = 0;
110*10793Sdai.ngo@sun.com 	(void) snprintf(buf, buflen, "%s", FS_REPARSE_TAG_STR);
111*10793Sdai.ngo@sun.com 	while (curr != NULL) {
112*10793Sdai.ngo@sun.com 		if (!(stype = nvpair_name(curr))) {
113*10793Sdai.ngo@sun.com 			err = EINVAL;
114*10793Sdai.ngo@sun.com 			break;
115*10793Sdai.ngo@sun.com 		}
116*10793Sdai.ngo@sun.com 		if ((strlcat(buf, FS_TOKEN_START_STR, buflen) >= buflen) ||
117*10793Sdai.ngo@sun.com 		    (strlcat(buf, stype, buflen) >= buflen) ||
118*10793Sdai.ngo@sun.com 		    (strlcat(buf, ":", buflen) >= buflen) ||
119*10793Sdai.ngo@sun.com 		    (nvpair_value_string(curr, &val) != 0) ||
120*10793Sdai.ngo@sun.com 		    (strlcat(buf, val, buflen) >= buflen) ||
121*10793Sdai.ngo@sun.com 		    (strlcat(buf, FS_TOKEN_END_STR, buflen) >= buflen)) {
122*10793Sdai.ngo@sun.com 			err = E2BIG;
123*10793Sdai.ngo@sun.com 			break;
124*10793Sdai.ngo@sun.com 		}
125*10793Sdai.ngo@sun.com 		curr = nvlist_next_nvpair(nvl, curr);
126*10793Sdai.ngo@sun.com 	}
127*10793Sdai.ngo@sun.com 	if (err != 0) {
128*10793Sdai.ngo@sun.com 		free(buf);
129*10793Sdai.ngo@sun.com 		return (err);
130*10793Sdai.ngo@sun.com 	}
131*10793Sdai.ngo@sun.com 	if (strlcat(buf, FS_REPARSE_TAG_END_STR, buflen) >= buflen) {
132*10793Sdai.ngo@sun.com 		free(buf);
133*10793Sdai.ngo@sun.com 		return (E2BIG);
134*10793Sdai.ngo@sun.com 	}
135*10793Sdai.ngo@sun.com 
136*10793Sdai.ngo@sun.com 	*stringp = buf;
137*10793Sdai.ngo@sun.com 	return (0);
138*10793Sdai.ngo@sun.com }
139*10793Sdai.ngo@sun.com 
140*10793Sdai.ngo@sun.com /*
141*10793Sdai.ngo@sun.com  * reparse_deref()
142*10793Sdai.ngo@sun.com  *
143*10793Sdai.ngo@sun.com  * Accepts the service-specific item from the reparse point and returns
144*10793Sdai.ngo@sun.com  * the service-specific data requested.  The caller specifies the size
145*10793Sdai.ngo@sun.com  * of the buffer provided via *bufsz.
146*10793Sdai.ngo@sun.com  *
147*10793Sdai.ngo@sun.com  * if ok return 0 and *bufsz is updated to contain the actual length of
148*10793Sdai.ngo@sun.com  * the returned results, else return error code. If the error code is
149*10793Sdai.ngo@sun.com  * EOVERFLOW; results do not fit in the buffer, *bufsz will be updated
150*10793Sdai.ngo@sun.com  * to contain the number of bytes needed to hold the results.
151*10793Sdai.ngo@sun.com  */
152*10793Sdai.ngo@sun.com int
reparse_deref(const char * svc_type,const char * svc_data,char * buf,size_t * bufsz)153*10793Sdai.ngo@sun.com reparse_deref(const char *svc_type, const char *svc_data, char *buf,
154*10793Sdai.ngo@sun.com     size_t *bufsz)
155*10793Sdai.ngo@sun.com {
156*10793Sdai.ngo@sun.com 	rp_plugin_ops_t *ops;
157*10793Sdai.ngo@sun.com 
158*10793Sdai.ngo@sun.com 	if ((svc_type == NULL) || (svc_data == NULL) || (buf == NULL) ||
159*10793Sdai.ngo@sun.com 	    (bufsz == NULL))
160*10793Sdai.ngo@sun.com 		return (EINVAL);
161*10793Sdai.ngo@sun.com 
162*10793Sdai.ngo@sun.com 	ops = rp_find_protocol(svc_type);
163*10793Sdai.ngo@sun.com 	if ((ops != NULL) && (ops->rpo_deref != NULL))
164*10793Sdai.ngo@sun.com 		return (ops->rpo_deref(svc_type, svc_data, buf, bufsz));
165*10793Sdai.ngo@sun.com 
166*10793Sdai.ngo@sun.com 	/* no plugin, return error */
167*10793Sdai.ngo@sun.com 	return (ENOTSUP);
168*10793Sdai.ngo@sun.com }
169*10793Sdai.ngo@sun.com 
170*10793Sdai.ngo@sun.com /*
171*10793Sdai.ngo@sun.com  * reparse_delete()
172*10793Sdai.ngo@sun.com  *
173*10793Sdai.ngo@sun.com  * Delete a reparse point at a given pathname.  It will fail if
174*10793Sdai.ngo@sun.com  * a reparse point does not exist at the given path or the pathname
175*10793Sdai.ngo@sun.com  * is not a symlink.
176*10793Sdai.ngo@sun.com  *
177*10793Sdai.ngo@sun.com  * return 0 if ok else return error code.
178*10793Sdai.ngo@sun.com  */
179*10793Sdai.ngo@sun.com int
reparse_delete(const char * path)180*10793Sdai.ngo@sun.com reparse_delete(const char *path)
181*10793Sdai.ngo@sun.com {
182*10793Sdai.ngo@sun.com 	struct stat sbuf;
183*10793Sdai.ngo@sun.com 
184*10793Sdai.ngo@sun.com 	if (path == NULL)
185*10793Sdai.ngo@sun.com 		return (EINVAL);
186*10793Sdai.ngo@sun.com 
187*10793Sdai.ngo@sun.com 	/* check if object exists */
188*10793Sdai.ngo@sun.com 	if (lstat(path, &sbuf) != 0)
189*10793Sdai.ngo@sun.com 		return (errno);
190*10793Sdai.ngo@sun.com 
191*10793Sdai.ngo@sun.com 	if ((sbuf.st_mode & S_IFLNK) != S_IFLNK)
192*10793Sdai.ngo@sun.com 		return (EINVAL);
193*10793Sdai.ngo@sun.com 
194*10793Sdai.ngo@sun.com 	return (unlink(path) ? errno : 0);
195*10793Sdai.ngo@sun.com }
196*10793Sdai.ngo@sun.com 
197*10793Sdai.ngo@sun.com /*
198*10793Sdai.ngo@sun.com  * reparse_add()
199*10793Sdai.ngo@sun.com  *
200*10793Sdai.ngo@sun.com  * Add a service type entry to a nvlist with a copy of svc_data,
201*10793Sdai.ngo@sun.com  * replacing one of the same type if already present.
202*10793Sdai.ngo@sun.com  *
203*10793Sdai.ngo@sun.com  * return 0 if ok else return error code.
204*10793Sdai.ngo@sun.com  */
205*10793Sdai.ngo@sun.com int
reparse_add(nvlist_t * nvl,const char * svc_type,const char * svc_data)206*10793Sdai.ngo@sun.com reparse_add(nvlist_t *nvl, const char *svc_type, const char *svc_data)
207*10793Sdai.ngo@sun.com {
208*10793Sdai.ngo@sun.com 	int err;
209*10793Sdai.ngo@sun.com 	char *buf;
210*10793Sdai.ngo@sun.com 	size_t bufsz;
211*10793Sdai.ngo@sun.com 	rp_plugin_ops_t *ops;
212*10793Sdai.ngo@sun.com 
213*10793Sdai.ngo@sun.com 	if ((nvl == NULL) || (svc_type == NULL) || (svc_data == NULL))
214*10793Sdai.ngo@sun.com 		return (EINVAL);
215*10793Sdai.ngo@sun.com 
216*10793Sdai.ngo@sun.com 	bufsz = SYMLINK_MAX;		/* no need to mess around */
217*10793Sdai.ngo@sun.com 	if ((buf = malloc(bufsz)) == NULL)
218*10793Sdai.ngo@sun.com 		return (ENOMEM);
219*10793Sdai.ngo@sun.com 
220*10793Sdai.ngo@sun.com 	ops = rp_find_protocol(svc_type);
221*10793Sdai.ngo@sun.com 	if ((ops != NULL) && (ops->rpo_form != NULL))
222*10793Sdai.ngo@sun.com 		err = ops->rpo_form(svc_type, svc_data, buf, &bufsz);
223*10793Sdai.ngo@sun.com 	else
224*10793Sdai.ngo@sun.com 		err = ENOTSUP;		/* no plugin */
225*10793Sdai.ngo@sun.com 
226*10793Sdai.ngo@sun.com 	if (err != 0) {
227*10793Sdai.ngo@sun.com 		free(buf);
228*10793Sdai.ngo@sun.com 		return (err);
229*10793Sdai.ngo@sun.com 	}
230*10793Sdai.ngo@sun.com 
231*10793Sdai.ngo@sun.com 	err =  nvlist_add_string(nvl, svc_type, buf);
232*10793Sdai.ngo@sun.com 	free(buf);
233*10793Sdai.ngo@sun.com 	return (err);
234*10793Sdai.ngo@sun.com }
235*10793Sdai.ngo@sun.com 
236*10793Sdai.ngo@sun.com /*
237*10793Sdai.ngo@sun.com  * reparse_remove()
238*10793Sdai.ngo@sun.com  *
239*10793Sdai.ngo@sun.com  * Remove a service type entry from the nvlist, if present.
240*10793Sdai.ngo@sun.com  *
241*10793Sdai.ngo@sun.com  * return 0 if ok else return error code.
242*10793Sdai.ngo@sun.com  */
243*10793Sdai.ngo@sun.com int
reparse_remove(nvlist_t * nvl,const char * svc_type)244*10793Sdai.ngo@sun.com reparse_remove(nvlist_t *nvl, const char *svc_type)
245*10793Sdai.ngo@sun.com {
246*10793Sdai.ngo@sun.com 	if ((nvl == NULL) || (svc_type == NULL))
247*10793Sdai.ngo@sun.com 		return (EINVAL);
248*10793Sdai.ngo@sun.com 
249*10793Sdai.ngo@sun.com 	return (nvlist_remove_all(nvl, svc_type));
250*10793Sdai.ngo@sun.com }
251*10793Sdai.ngo@sun.com 
252*10793Sdai.ngo@sun.com /*
253*10793Sdai.ngo@sun.com  * Returns true if name is "." or "..", otherwise returns false.
254*10793Sdai.ngo@sun.com  */
255*10793Sdai.ngo@sun.com static boolean_t
rp_is_dot_or_dotdot(const char * name)256*10793Sdai.ngo@sun.com rp_is_dot_or_dotdot(const char *name)
257*10793Sdai.ngo@sun.com {
258*10793Sdai.ngo@sun.com 	if (*name != '.')
259*10793Sdai.ngo@sun.com 		return (B_FALSE);
260*10793Sdai.ngo@sun.com 
261*10793Sdai.ngo@sun.com 	if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))
262*10793Sdai.ngo@sun.com 		return (B_TRUE);
263*10793Sdai.ngo@sun.com 
264*10793Sdai.ngo@sun.com 	return (B_FALSE);
265*10793Sdai.ngo@sun.com }
266*10793Sdai.ngo@sun.com 
267*10793Sdai.ngo@sun.com static void
proto_plugin_fini()268*10793Sdai.ngo@sun.com proto_plugin_fini()
269*10793Sdai.ngo@sun.com {
270*10793Sdai.ngo@sun.com 	rp_proto_plugin_t *p;
271*10793Sdai.ngo@sun.com 
272*10793Sdai.ngo@sun.com 	/*
273*10793Sdai.ngo@sun.com 	 * Protocols may call this framework during _fini
274*10793Sdai.ngo@sun.com 	 */
275*10793Sdai.ngo@sun.com 	for (p = rp_proto_list; p != NULL; p = p->plugin_next) {
276*10793Sdai.ngo@sun.com 		if (p->plugin_ops->rpo_fini)
277*10793Sdai.ngo@sun.com 			p->plugin_ops->rpo_fini();
278*10793Sdai.ngo@sun.com 	}
279*10793Sdai.ngo@sun.com 	while ((p = rp_proto_list) != NULL) {
280*10793Sdai.ngo@sun.com 		rp_proto_list = p->plugin_next;
281*10793Sdai.ngo@sun.com 		if (p->plugin_handle != NULL)
282*10793Sdai.ngo@sun.com 			(void) dlclose(p->plugin_handle);
283*10793Sdai.ngo@sun.com 		free(p);
284*10793Sdai.ngo@sun.com 	}
285*10793Sdai.ngo@sun.com 
286*10793Sdai.ngo@sun.com 	if (rp_proto_handle.rp_ops != NULL) {
287*10793Sdai.ngo@sun.com 		free(rp_proto_handle.rp_ops);
288*10793Sdai.ngo@sun.com 		rp_proto_handle.rp_ops = NULL;
289*10793Sdai.ngo@sun.com 	}
290*10793Sdai.ngo@sun.com 	rp_proto_handle.rp_num_proto = 0;
291*10793Sdai.ngo@sun.com }
292*10793Sdai.ngo@sun.com 
293*10793Sdai.ngo@sun.com /*
294*10793Sdai.ngo@sun.com  * rp_plugin_init()
295*10793Sdai.ngo@sun.com  *
296*10793Sdai.ngo@sun.com  * Initialize the service type specific plugin modules.
297*10793Sdai.ngo@sun.com  * For each reparse service type, there should be a plugin library for it.
298*10793Sdai.ngo@sun.com  * This function walks /usr/lib/reparse directory for plugin libraries.
299*10793Sdai.ngo@sun.com  * For each plugin library found, initialize it and add it to the internal
300*10793Sdai.ngo@sun.com  * list of service type plugin. These are used for service type specific
301*10793Sdai.ngo@sun.com  * operations.
302*10793Sdai.ngo@sun.com  */
303*10793Sdai.ngo@sun.com int
rp_plugin_init()304*10793Sdai.ngo@sun.com rp_plugin_init()
305*10793Sdai.ngo@sun.com {
306*10793Sdai.ngo@sun.com 	int err, ret = RP_OK;
307*10793Sdai.ngo@sun.com 	char isa[MAXISALEN], dirpath[MAXPATHLEN], path[MAXPATHLEN];
308*10793Sdai.ngo@sun.com 	int num_protos = 0;
309*10793Sdai.ngo@sun.com 	rp_proto_handle_t *rp_hdl;
310*10793Sdai.ngo@sun.com 	rp_proto_plugin_t *proto, *tmp;
311*10793Sdai.ngo@sun.com 	rp_plugin_ops_t *plugin_ops;
312*10793Sdai.ngo@sun.com 	struct stat st;
313*10793Sdai.ngo@sun.com 	void *dlhandle;
314*10793Sdai.ngo@sun.com 	DIR *dir;
315*10793Sdai.ngo@sun.com 	struct dirent *dent;
316*10793Sdai.ngo@sun.com 
317*10793Sdai.ngo@sun.com #if defined(_LP64)
318*10793Sdai.ngo@sun.com 	if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
319*10793Sdai.ngo@sun.com 		isa[0] = '\0';
320*10793Sdai.ngo@sun.com #else
321*10793Sdai.ngo@sun.com 	isa[0] = '\0';
322*10793Sdai.ngo@sun.com #endif
323*10793Sdai.ngo@sun.com 
324*10793Sdai.ngo@sun.com 	(void) snprintf(dirpath, MAXPATHLEN,
325*10793Sdai.ngo@sun.com 	    "%s/%s", RP_LIB_DIR, isa);
326*10793Sdai.ngo@sun.com 
327*10793Sdai.ngo@sun.com 	if ((dir = opendir(dirpath)) == NULL)
328*10793Sdai.ngo@sun.com 		return (RP_NO_PLUGIN_DIR);
329*10793Sdai.ngo@sun.com 
330*10793Sdai.ngo@sun.com 	while ((dent = readdir(dir)) != NULL) {
331*10793Sdai.ngo@sun.com 		if (rp_is_dot_or_dotdot(dent->d_name))
332*10793Sdai.ngo@sun.com 			continue;
333*10793Sdai.ngo@sun.com 
334*10793Sdai.ngo@sun.com 		(void) snprintf(path, MAXPATHLEN,
335*10793Sdai.ngo@sun.com 		    "%s/%s", dirpath, dent->d_name);
336*10793Sdai.ngo@sun.com 
337*10793Sdai.ngo@sun.com 		/*
338*10793Sdai.ngo@sun.com 		 * If file doesn't exist, don't try to map it
339*10793Sdai.ngo@sun.com 		 */
340*10793Sdai.ngo@sun.com 		if (stat(path, &st) < 0)
341*10793Sdai.ngo@sun.com 			continue;
342*10793Sdai.ngo@sun.com 		if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL)
343*10793Sdai.ngo@sun.com 			continue;
344*10793Sdai.ngo@sun.com 
345*10793Sdai.ngo@sun.com 		plugin_ops = (rp_plugin_ops_t *)
346*10793Sdai.ngo@sun.com 		    dlsym(dlhandle, "rp_plugin_ops");
347*10793Sdai.ngo@sun.com 		if (plugin_ops == NULL) {
348*10793Sdai.ngo@sun.com 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
349*10793Sdai.ngo@sun.com 			    "Error in plugin ops for service type %s\n%s\n"),
350*10793Sdai.ngo@sun.com 			    dent->d_name, dlerror());
351*10793Sdai.ngo@sun.com 			(void) dlclose(dlhandle);
352*10793Sdai.ngo@sun.com 			continue;
353*10793Sdai.ngo@sun.com 		}
354*10793Sdai.ngo@sun.com 		proto = (rp_proto_plugin_t *)
355*10793Sdai.ngo@sun.com 		    calloc(1, sizeof (rp_proto_plugin_t));
356*10793Sdai.ngo@sun.com 		if (proto == NULL) {
357*10793Sdai.ngo@sun.com 			(void) dlclose(dlhandle);
358*10793Sdai.ngo@sun.com 			(void) fprintf(stderr,
359*10793Sdai.ngo@sun.com 			    dgettext(TEXT_DOMAIN, "No memory for plugin %s\n"),
360*10793Sdai.ngo@sun.com 			    dent->d_name);
361*10793Sdai.ngo@sun.com 			ret = RP_NO_MEMORY;
362*10793Sdai.ngo@sun.com 			break;
363*10793Sdai.ngo@sun.com 		}
364*10793Sdai.ngo@sun.com 
365*10793Sdai.ngo@sun.com 		proto->plugin_ops = plugin_ops;
366*10793Sdai.ngo@sun.com 		proto->plugin_handle = dlhandle;
367*10793Sdai.ngo@sun.com 		num_protos++;
368*10793Sdai.ngo@sun.com 		proto->plugin_next = rp_proto_list;
369*10793Sdai.ngo@sun.com 		rp_proto_list = proto;
370*10793Sdai.ngo@sun.com 	}
371*10793Sdai.ngo@sun.com 
372*10793Sdai.ngo@sun.com 	(void) closedir(dir);
373*10793Sdai.ngo@sun.com 
374*10793Sdai.ngo@sun.com 	if ((num_protos == 0) && (ret == 0))
375*10793Sdai.ngo@sun.com 		ret = RP_NO_PLUGIN;
376*10793Sdai.ngo@sun.com 	/*
377*10793Sdai.ngo@sun.com 	 * There was an error, so cleanup prior to return of failure.
378*10793Sdai.ngo@sun.com 	 */
379*10793Sdai.ngo@sun.com 	if (ret != RP_OK) {
380*10793Sdai.ngo@sun.com 		proto_plugin_fini();
381*10793Sdai.ngo@sun.com 		return (ret);
382*10793Sdai.ngo@sun.com 	}
383*10793Sdai.ngo@sun.com 
384*10793Sdai.ngo@sun.com 	rp_proto_handle.rp_ops = (rp_plugin_ops_t **)calloc(num_protos,
385*10793Sdai.ngo@sun.com 	    sizeof (rp_plugin_ops_t *));
386*10793Sdai.ngo@sun.com 	if (!rp_proto_handle.rp_ops) {
387*10793Sdai.ngo@sun.com 		proto_plugin_fini();
388*10793Sdai.ngo@sun.com 		return (RP_NO_MEMORY);
389*10793Sdai.ngo@sun.com 	}
390*10793Sdai.ngo@sun.com 
391*10793Sdai.ngo@sun.com 	rp_hdl = &rp_proto_handle;
392*10793Sdai.ngo@sun.com 	rp_hdl->rp_num_proto = 0;
393*10793Sdai.ngo@sun.com 	for (tmp = rp_proto_list; rp_hdl->rp_num_proto < num_protos &&
394*10793Sdai.ngo@sun.com 	    tmp != NULL; tmp = tmp->plugin_next) {
395*10793Sdai.ngo@sun.com 
396*10793Sdai.ngo@sun.com 		err = RP_OK;
397*10793Sdai.ngo@sun.com 		if (tmp->plugin_ops->rpo_init != NULL)
398*10793Sdai.ngo@sun.com 			err = tmp->plugin_ops->rpo_init();
399*10793Sdai.ngo@sun.com 		if (err != RP_OK)
400*10793Sdai.ngo@sun.com 			continue;
401*10793Sdai.ngo@sun.com 		rp_hdl->rp_ops[rp_hdl->rp_num_proto++] = tmp->plugin_ops;
402*10793Sdai.ngo@sun.com 	}
403*10793Sdai.ngo@sun.com 
404*10793Sdai.ngo@sun.com 	return (rp_hdl->rp_num_proto > 0 ? RP_OK : RP_NO_PLUGIN);
405*10793Sdai.ngo@sun.com }
406*10793Sdai.ngo@sun.com 
407*10793Sdai.ngo@sun.com 
408*10793Sdai.ngo@sun.com /*
409*10793Sdai.ngo@sun.com  * find_protocol()
410*10793Sdai.ngo@sun.com  *
411*10793Sdai.ngo@sun.com  * Search the plugin list for the specified protocol and return the
412*10793Sdai.ngo@sun.com  * ops vector.  return NULL if protocol is not defined.
413*10793Sdai.ngo@sun.com  */
414*10793Sdai.ngo@sun.com static rp_plugin_ops_t *
rp_find_protocol(const char * svc_type)415*10793Sdai.ngo@sun.com rp_find_protocol(const char *svc_type)
416*10793Sdai.ngo@sun.com {
417*10793Sdai.ngo@sun.com 	int i;
418*10793Sdai.ngo@sun.com 	rp_plugin_ops_t *ops = NULL;
419*10793Sdai.ngo@sun.com 
420*10793Sdai.ngo@sun.com 	if (svc_type == NULL)
421*10793Sdai.ngo@sun.com 		return (NULL);
422*10793Sdai.ngo@sun.com 
423*10793Sdai.ngo@sun.com 	if (rp_plugin_inited == 0) {
424*10793Sdai.ngo@sun.com 		if (rp_plugin_init() == RP_OK)
425*10793Sdai.ngo@sun.com 			rp_plugin_inited = 1;
426*10793Sdai.ngo@sun.com 		else
427*10793Sdai.ngo@sun.com 			return (NULL);
428*10793Sdai.ngo@sun.com 	}
429*10793Sdai.ngo@sun.com 
430*10793Sdai.ngo@sun.com 	for (i = 0; i < rp_proto_handle.rp_num_proto; i++) {
431*10793Sdai.ngo@sun.com 		ops = rp_proto_handle.rp_ops[i];
432*10793Sdai.ngo@sun.com 		if (ops->rpo_supports_svc(svc_type))
433*10793Sdai.ngo@sun.com 			return (ops);
434*10793Sdai.ngo@sun.com 
435*10793Sdai.ngo@sun.com 	}
436*10793Sdai.ngo@sun.com 	return (NULL);
437*10793Sdai.ngo@sun.com }
438