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