xref: /illumos-gate/usr/src/lib/libreparse/common/fs_reparse_lib.c (revision bcb78a453dcc6eaa7c33432fac3626514e243154)
17a286c47SDai Ngo /*
27a286c47SDai Ngo  * CDDL HEADER START
37a286c47SDai Ngo  *
47a286c47SDai Ngo  * The contents of this file are subject to the terms of the
57a286c47SDai Ngo  * Common Development and Distribution License (the "License").
67a286c47SDai Ngo  * You may not use this file except in compliance with the License.
77a286c47SDai Ngo  *
87a286c47SDai Ngo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97a286c47SDai Ngo  * or http://www.opensolaris.org/os/licensing.
107a286c47SDai Ngo  * See the License for the specific language governing permissions
117a286c47SDai Ngo  * and limitations under the License.
127a286c47SDai Ngo  *
137a286c47SDai Ngo  * When distributing Covered Code, include this CDDL HEADER in each
147a286c47SDai Ngo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157a286c47SDai Ngo  * If applicable, add the following below this CDDL HEADER, with the
167a286c47SDai Ngo  * fields enclosed by brackets "[]" replaced with your own identifying
177a286c47SDai Ngo  * information: Portions Copyright [yyyy] [name of copyright owner]
187a286c47SDai Ngo  *
197a286c47SDai Ngo  * CDDL HEADER END
207a286c47SDai Ngo  */
217a286c47SDai Ngo 
227a286c47SDai Ngo /*
237a286c47SDai Ngo  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247a286c47SDai Ngo  * Use is subject to license terms.
257a286c47SDai Ngo  */
267a286c47SDai Ngo 
27*bcb78a45SJohn Levon /*
28*bcb78a45SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
29*bcb78a45SJohn Levon  */
30*bcb78a45SJohn Levon 
317a286c47SDai Ngo #include <stdio.h>
327a286c47SDai Ngo #include <stdlib.h>
337a286c47SDai Ngo #include <unistd.h>
347a286c47SDai Ngo #include <strings.h>
357a286c47SDai Ngo #include <string.h>
367a286c47SDai Ngo #include <dirent.h>
377a286c47SDai Ngo #include <sys/types.h>
387a286c47SDai Ngo #include <sys/stat.h>
397a286c47SDai Ngo #include <sys/param.h>
407a286c47SDai Ngo #include <sys/errno.h>
417a286c47SDai Ngo #include <limits.h>
427a286c47SDai Ngo #include <libnvpair.h>
437a286c47SDai Ngo #include <dlfcn.h>
447a286c47SDai Ngo #include <libintl.h>
457a286c47SDai Ngo #include <sys/systeminfo.h>
467a286c47SDai Ngo #include <sys/fs_reparse.h>
477a286c47SDai Ngo #include "rp_plugin.h"
487a286c47SDai Ngo 
497a286c47SDai Ngo #define	MAXISALEN	257	/* based on sysinfo(2) man page */
507a286c47SDai Ngo 
517a286c47SDai Ngo static rp_proto_handle_t rp_proto_handle;
527a286c47SDai Ngo static rp_proto_plugin_t *rp_proto_list;
537a286c47SDai Ngo 
547a286c47SDai Ngo int rp_plugin_init(void);
557a286c47SDai Ngo static void proto_plugin_fini(void);
567a286c47SDai Ngo static rp_plugin_ops_t *rp_find_protocol(const char *svctype);
577a286c47SDai Ngo 
587a286c47SDai Ngo extern int errno;
597a286c47SDai Ngo static int rp_plugin_inited = 0;
607a286c47SDai Ngo 
617a286c47SDai Ngo /*
627a286c47SDai Ngo  * reparse_create()
637a286c47SDai Ngo  *
647a286c47SDai Ngo  * Create a symlink at the specified 'path' as a reparse point.
657a286c47SDai Ngo  * This function will fail if path refers to an existing file system
667a286c47SDai Ngo  * object or an object named string already exists at the given path.
677a286c47SDai Ngo  *
687a286c47SDai Ngo  * return 0 if ok else return error code.
697a286c47SDai Ngo  */
707a286c47SDai Ngo int
716a1af1a6SRichard Lowe reparse_create(const char *path, const char *data)
727a286c47SDai Ngo {
737a286c47SDai Ngo 	int err;
747a286c47SDai Ngo 	struct stat sbuf;
757a286c47SDai Ngo 
766a1af1a6SRichard Lowe 	if (path == NULL || data == NULL)
777a286c47SDai Ngo 		return (EINVAL);
787a286c47SDai Ngo 
796a1af1a6SRichard Lowe 	if ((err = reparse_validate(data)) != 0)
807a286c47SDai Ngo 		return (err);
817a286c47SDai Ngo 
827a286c47SDai Ngo 	/* check if object exists */
837a286c47SDai Ngo 	if (lstat(path, &sbuf) == 0)
847a286c47SDai Ngo 		return (EEXIST);
857a286c47SDai Ngo 
866a1af1a6SRichard Lowe 	return (symlink(data, path) ? errno : 0);
877a286c47SDai Ngo }
887a286c47SDai Ngo 
897a286c47SDai Ngo /*
907a286c47SDai Ngo  * reparse_unparse()
917a286c47SDai Ngo  *
927a286c47SDai Ngo  * Convert an nvlist back to a string format suitable to write
937a286c47SDai Ngo  * to the reparse point symlink body.  The string returned is in
947a286c47SDai Ngo  * allocated memory and must be freed by the caller.
957a286c47SDai Ngo  *
967a286c47SDai Ngo  * return 0 if ok else return error code.
977a286c47SDai Ngo  */
987a286c47SDai Ngo int
997a286c47SDai Ngo reparse_unparse(nvlist_t *nvl, char **stringp)
1007a286c47SDai Ngo {
1017a286c47SDai Ngo 	int err, buflen;
1027a286c47SDai Ngo 	char *buf, *stype, *val;
1037a286c47SDai Ngo 	nvpair_t *curr;
1047a286c47SDai Ngo 
1057a286c47SDai Ngo 	if (nvl == NULL || stringp == NULL ||
1067a286c47SDai Ngo 	    ((curr = nvlist_next_nvpair(nvl, NULL)) == NULL))
1077a286c47SDai Ngo 		return (EINVAL);
1087a286c47SDai Ngo 
1097a286c47SDai Ngo 	buflen = SYMLINK_MAX;
1107a286c47SDai Ngo 	if ((buf = malloc(buflen)) == NULL)
1117a286c47SDai Ngo 		return (ENOMEM);
1127a286c47SDai Ngo 
1137a286c47SDai Ngo 	err = 0;
1147a286c47SDai Ngo 	(void) snprintf(buf, buflen, "%s", FS_REPARSE_TAG_STR);
1157a286c47SDai Ngo 	while (curr != NULL) {
1167a286c47SDai Ngo 		if (!(stype = nvpair_name(curr))) {
1177a286c47SDai Ngo 			err = EINVAL;
1187a286c47SDai Ngo 			break;
1197a286c47SDai Ngo 		}
1207a286c47SDai Ngo 		if ((strlcat(buf, FS_TOKEN_START_STR, buflen) >= buflen) ||
1217a286c47SDai Ngo 		    (strlcat(buf, stype, buflen) >= buflen) ||
1227a286c47SDai Ngo 		    (strlcat(buf, ":", buflen) >= buflen) ||
1237a286c47SDai Ngo 		    (nvpair_value_string(curr, &val) != 0) ||
1247a286c47SDai Ngo 		    (strlcat(buf, val, buflen) >= buflen) ||
1257a286c47SDai Ngo 		    (strlcat(buf, FS_TOKEN_END_STR, buflen) >= buflen)) {
1267a286c47SDai Ngo 			err = E2BIG;
1277a286c47SDai Ngo 			break;
1287a286c47SDai Ngo 		}
1297a286c47SDai Ngo 		curr = nvlist_next_nvpair(nvl, curr);
1307a286c47SDai Ngo 	}
1317a286c47SDai Ngo 	if (err != 0) {
1327a286c47SDai Ngo 		free(buf);
1337a286c47SDai Ngo 		return (err);
1347a286c47SDai Ngo 	}
1357a286c47SDai Ngo 	if (strlcat(buf, FS_REPARSE_TAG_END_STR, buflen) >= buflen) {
1367a286c47SDai Ngo 		free(buf);
1377a286c47SDai Ngo 		return (E2BIG);
1387a286c47SDai Ngo 	}
1397a286c47SDai Ngo 
1407a286c47SDai Ngo 	*stringp = buf;
1417a286c47SDai Ngo 	return (0);
1427a286c47SDai Ngo }
1437a286c47SDai Ngo 
1447a286c47SDai Ngo /*
1457a286c47SDai Ngo  * reparse_deref()
1467a286c47SDai Ngo  *
1477a286c47SDai Ngo  * Accepts the service-specific item from the reparse point and returns
1487a286c47SDai Ngo  * the service-specific data requested.  The caller specifies the size
1497a286c47SDai Ngo  * of the buffer provided via *bufsz.
1507a286c47SDai Ngo  *
1517a286c47SDai Ngo  * if ok return 0 and *bufsz is updated to contain the actual length of
1527a286c47SDai Ngo  * the returned results, else return error code. If the error code is
1537a286c47SDai Ngo  * EOVERFLOW; results do not fit in the buffer, *bufsz will be updated
1547a286c47SDai Ngo  * to contain the number of bytes needed to hold the results.
1557a286c47SDai Ngo  */
1567a286c47SDai Ngo int
1577a286c47SDai Ngo reparse_deref(const char *svc_type, const char *svc_data, char *buf,
1587a286c47SDai Ngo     size_t *bufsz)
1597a286c47SDai Ngo {
1607a286c47SDai Ngo 	rp_plugin_ops_t *ops;
1617a286c47SDai Ngo 
1627a286c47SDai Ngo 	if ((svc_type == NULL) || (svc_data == NULL) || (buf == NULL) ||
1637a286c47SDai Ngo 	    (bufsz == NULL))
1647a286c47SDai Ngo 		return (EINVAL);
1657a286c47SDai Ngo 
1667a286c47SDai Ngo 	ops = rp_find_protocol(svc_type);
1677a286c47SDai Ngo 	if ((ops != NULL) && (ops->rpo_deref != NULL))
1687a286c47SDai Ngo 		return (ops->rpo_deref(svc_type, svc_data, buf, bufsz));
1697a286c47SDai Ngo 
1707a286c47SDai Ngo 	/* no plugin, return error */
1717a286c47SDai Ngo 	return (ENOTSUP);
1727a286c47SDai Ngo }
1737a286c47SDai Ngo 
1747a286c47SDai Ngo /*
1757a286c47SDai Ngo  * reparse_delete()
1767a286c47SDai Ngo  *
1777a286c47SDai Ngo  * Delete a reparse point at a given pathname.  It will fail if
1787a286c47SDai Ngo  * a reparse point does not exist at the given path or the pathname
1797a286c47SDai Ngo  * is not a symlink.
1807a286c47SDai Ngo  *
1817a286c47SDai Ngo  * return 0 if ok else return error code.
1827a286c47SDai Ngo  */
1837a286c47SDai Ngo int
1847a286c47SDai Ngo reparse_delete(const char *path)
1857a286c47SDai Ngo {
1867a286c47SDai Ngo 	struct stat sbuf;
1877a286c47SDai Ngo 
1887a286c47SDai Ngo 	if (path == NULL)
1897a286c47SDai Ngo 		return (EINVAL);
1907a286c47SDai Ngo 
1917a286c47SDai Ngo 	/* check if object exists */
1927a286c47SDai Ngo 	if (lstat(path, &sbuf) != 0)
1937a286c47SDai Ngo 		return (errno);
1947a286c47SDai Ngo 
1957a286c47SDai Ngo 	if ((sbuf.st_mode & S_IFLNK) != S_IFLNK)
1967a286c47SDai Ngo 		return (EINVAL);
1977a286c47SDai Ngo 
1987a286c47SDai Ngo 	return (unlink(path) ? errno : 0);
1997a286c47SDai Ngo }
2007a286c47SDai Ngo 
2017a286c47SDai Ngo /*
2027a286c47SDai Ngo  * reparse_add()
2037a286c47SDai Ngo  *
2047a286c47SDai Ngo  * Add a service type entry to a nvlist with a copy of svc_data,
2057a286c47SDai Ngo  * replacing one of the same type if already present.
2067a286c47SDai Ngo  *
2077a286c47SDai Ngo  * return 0 if ok else return error code.
2087a286c47SDai Ngo  */
2097a286c47SDai Ngo int
2107a286c47SDai Ngo reparse_add(nvlist_t *nvl, const char *svc_type, const char *svc_data)
2117a286c47SDai Ngo {
2127a286c47SDai Ngo 	int err;
2137a286c47SDai Ngo 	char *buf;
2147a286c47SDai Ngo 	size_t bufsz;
2157a286c47SDai Ngo 	rp_plugin_ops_t *ops;
2167a286c47SDai Ngo 
2177a286c47SDai Ngo 	if ((nvl == NULL) || (svc_type == NULL) || (svc_data == NULL))
2187a286c47SDai Ngo 		return (EINVAL);
2197a286c47SDai Ngo 
2207a286c47SDai Ngo 	bufsz = SYMLINK_MAX;		/* no need to mess around */
2217a286c47SDai Ngo 	if ((buf = malloc(bufsz)) == NULL)
2227a286c47SDai Ngo 		return (ENOMEM);
2237a286c47SDai Ngo 
2247a286c47SDai Ngo 	ops = rp_find_protocol(svc_type);
2257a286c47SDai Ngo 	if ((ops != NULL) && (ops->rpo_form != NULL))
2267a286c47SDai Ngo 		err = ops->rpo_form(svc_type, svc_data, buf, &bufsz);
2277a286c47SDai Ngo 	else
2287a286c47SDai Ngo 		err = ENOTSUP;		/* no plugin */
2297a286c47SDai Ngo 
2307a286c47SDai Ngo 	if (err != 0) {
2317a286c47SDai Ngo 		free(buf);
2327a286c47SDai Ngo 		return (err);
2337a286c47SDai Ngo 	}
2347a286c47SDai Ngo 
2357a286c47SDai Ngo 	err =  nvlist_add_string(nvl, svc_type, buf);
2367a286c47SDai Ngo 	free(buf);
2377a286c47SDai Ngo 	return (err);
2387a286c47SDai Ngo }
2397a286c47SDai Ngo 
2407a286c47SDai Ngo /*
2417a286c47SDai Ngo  * reparse_remove()
2427a286c47SDai Ngo  *
2437a286c47SDai Ngo  * Remove a service type entry from the nvlist, if present.
2447a286c47SDai Ngo  *
2457a286c47SDai Ngo  * return 0 if ok else return error code.
2467a286c47SDai Ngo  */
2477a286c47SDai Ngo int
2487a286c47SDai Ngo reparse_remove(nvlist_t *nvl, const char *svc_type)
2497a286c47SDai Ngo {
2507a286c47SDai Ngo 	if ((nvl == NULL) || (svc_type == NULL))
2517a286c47SDai Ngo 		return (EINVAL);
2527a286c47SDai Ngo 
2537a286c47SDai Ngo 	return (nvlist_remove_all(nvl, svc_type));
2547a286c47SDai Ngo }
2557a286c47SDai Ngo 
2567a286c47SDai Ngo /*
2577a286c47SDai Ngo  * Returns true if name is "." or "..", otherwise returns false.
2587a286c47SDai Ngo  */
2597a286c47SDai Ngo static boolean_t
2607a286c47SDai Ngo rp_is_dot_or_dotdot(const char *name)
2617a286c47SDai Ngo {
2627a286c47SDai Ngo 	if (*name != '.')
2637a286c47SDai Ngo 		return (B_FALSE);
2647a286c47SDai Ngo 
2657a286c47SDai Ngo 	if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))
2667a286c47SDai Ngo 		return (B_TRUE);
2677a286c47SDai Ngo 
2687a286c47SDai Ngo 	return (B_FALSE);
2697a286c47SDai Ngo }
2707a286c47SDai Ngo 
2717a286c47SDai Ngo static void
2727a286c47SDai Ngo proto_plugin_fini()
2737a286c47SDai Ngo {
2747a286c47SDai Ngo 	rp_proto_plugin_t *p;
2757a286c47SDai Ngo 
2767a286c47SDai Ngo 	/*
2777a286c47SDai Ngo 	 * Protocols may call this framework during _fini
2787a286c47SDai Ngo 	 */
2797a286c47SDai Ngo 	for (p = rp_proto_list; p != NULL; p = p->plugin_next) {
2807a286c47SDai Ngo 		if (p->plugin_ops->rpo_fini)
281*bcb78a45SJohn Levon 			(void) p->plugin_ops->rpo_fini();
2827a286c47SDai Ngo 	}
2837a286c47SDai Ngo 	while ((p = rp_proto_list) != NULL) {
2847a286c47SDai Ngo 		rp_proto_list = p->plugin_next;
2857a286c47SDai Ngo 		if (p->plugin_handle != NULL)
2867a286c47SDai Ngo 			(void) dlclose(p->plugin_handle);
2877a286c47SDai Ngo 		free(p);
2887a286c47SDai Ngo 	}
2897a286c47SDai Ngo 
2907a286c47SDai Ngo 	if (rp_proto_handle.rp_ops != NULL) {
2917a286c47SDai Ngo 		free(rp_proto_handle.rp_ops);
2927a286c47SDai Ngo 		rp_proto_handle.rp_ops = NULL;
2937a286c47SDai Ngo 	}
2947a286c47SDai Ngo 	rp_proto_handle.rp_num_proto = 0;
2957a286c47SDai Ngo }
2967a286c47SDai Ngo 
2977a286c47SDai Ngo /*
2987a286c47SDai Ngo  * rp_plugin_init()
2997a286c47SDai Ngo  *
3007a286c47SDai Ngo  * Initialize the service type specific plugin modules.
3017a286c47SDai Ngo  * For each reparse service type, there should be a plugin library for it.
3027a286c47SDai Ngo  * This function walks /usr/lib/reparse directory for plugin libraries.
3037a286c47SDai Ngo  * For each plugin library found, initialize it and add it to the internal
3047a286c47SDai Ngo  * list of service type plugin. These are used for service type specific
3057a286c47SDai Ngo  * operations.
3067a286c47SDai Ngo  */
3077a286c47SDai Ngo int
3087a286c47SDai Ngo rp_plugin_init()
3097a286c47SDai Ngo {
3107a286c47SDai Ngo 	int err, ret = RP_OK;
3117a286c47SDai Ngo 	char isa[MAXISALEN], dirpath[MAXPATHLEN], path[MAXPATHLEN];
3127a286c47SDai Ngo 	int num_protos = 0;
3137a286c47SDai Ngo 	rp_proto_handle_t *rp_hdl;
3147a286c47SDai Ngo 	rp_proto_plugin_t *proto, *tmp;
3157a286c47SDai Ngo 	rp_plugin_ops_t *plugin_ops;
3167a286c47SDai Ngo 	struct stat st;
3177a286c47SDai Ngo 	void *dlhandle;
3187a286c47SDai Ngo 	DIR *dir;
3197a286c47SDai Ngo 	struct dirent *dent;
3207a286c47SDai Ngo 
3217a286c47SDai Ngo #if defined(_LP64)
3227a286c47SDai Ngo 	if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
3237a286c47SDai Ngo 		isa[0] = '\0';
3247a286c47SDai Ngo #else
3257a286c47SDai Ngo 	isa[0] = '\0';
3267a286c47SDai Ngo #endif
3277a286c47SDai Ngo 
3287a286c47SDai Ngo 	(void) snprintf(dirpath, MAXPATHLEN,
3297a286c47SDai Ngo 	    "%s/%s", RP_LIB_DIR, isa);
3307a286c47SDai Ngo 
3317a286c47SDai Ngo 	if ((dir = opendir(dirpath)) == NULL)
3327a286c47SDai Ngo 		return (RP_NO_PLUGIN_DIR);
3337a286c47SDai Ngo 
3347a286c47SDai Ngo 	while ((dent = readdir(dir)) != NULL) {
3357a286c47SDai Ngo 		if (rp_is_dot_or_dotdot(dent->d_name))
3367a286c47SDai Ngo 			continue;
3377a286c47SDai Ngo 
3387a286c47SDai Ngo 		(void) snprintf(path, MAXPATHLEN,
3397a286c47SDai Ngo 		    "%s/%s", dirpath, dent->d_name);
3407a286c47SDai Ngo 
3417a286c47SDai Ngo 		/*
3427a286c47SDai Ngo 		 * If file doesn't exist, don't try to map it
3437a286c47SDai Ngo 		 */
3447a286c47SDai Ngo 		if (stat(path, &st) < 0)
3457a286c47SDai Ngo 			continue;
3467a286c47SDai Ngo 		if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL)
3477a286c47SDai Ngo 			continue;
3487a286c47SDai Ngo 
3497a286c47SDai Ngo 		plugin_ops = (rp_plugin_ops_t *)
3507a286c47SDai Ngo 		    dlsym(dlhandle, "rp_plugin_ops");
3517a286c47SDai Ngo 		if (plugin_ops == NULL) {
3527a286c47SDai Ngo 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
3537a286c47SDai Ngo 			    "Error in plugin ops for service type %s\n%s\n"),
3547a286c47SDai Ngo 			    dent->d_name, dlerror());
3557a286c47SDai Ngo 			(void) dlclose(dlhandle);
3567a286c47SDai Ngo 			continue;
3577a286c47SDai Ngo 		}
3587a286c47SDai Ngo 		proto = (rp_proto_plugin_t *)
3597a286c47SDai Ngo 		    calloc(1, sizeof (rp_proto_plugin_t));
3607a286c47SDai Ngo 		if (proto == NULL) {
3617a286c47SDai Ngo 			(void) dlclose(dlhandle);
3627a286c47SDai Ngo 			(void) fprintf(stderr,
3637a286c47SDai Ngo 			    dgettext(TEXT_DOMAIN, "No memory for plugin %s\n"),
3647a286c47SDai Ngo 			    dent->d_name);
3657a286c47SDai Ngo 			ret = RP_NO_MEMORY;
3667a286c47SDai Ngo 			break;
3677a286c47SDai Ngo 		}
3687a286c47SDai Ngo 
3697a286c47SDai Ngo 		proto->plugin_ops = plugin_ops;
3707a286c47SDai Ngo 		proto->plugin_handle = dlhandle;
3717a286c47SDai Ngo 		num_protos++;
3727a286c47SDai Ngo 		proto->plugin_next = rp_proto_list;
3737a286c47SDai Ngo 		rp_proto_list = proto;
3747a286c47SDai Ngo 	}
3757a286c47SDai Ngo 
3767a286c47SDai Ngo 	(void) closedir(dir);
3777a286c47SDai Ngo 
3787a286c47SDai Ngo 	if ((num_protos == 0) && (ret == 0))
3797a286c47SDai Ngo 		ret = RP_NO_PLUGIN;
3807a286c47SDai Ngo 	/*
3817a286c47SDai Ngo 	 * There was an error, so cleanup prior to return of failure.
3827a286c47SDai Ngo 	 */
3837a286c47SDai Ngo 	if (ret != RP_OK) {
3847a286c47SDai Ngo 		proto_plugin_fini();
3857a286c47SDai Ngo 		return (ret);
3867a286c47SDai Ngo 	}
3877a286c47SDai Ngo 
3887a286c47SDai Ngo 	rp_proto_handle.rp_ops = (rp_plugin_ops_t **)calloc(num_protos,
3897a286c47SDai Ngo 	    sizeof (rp_plugin_ops_t *));
3907a286c47SDai Ngo 	if (!rp_proto_handle.rp_ops) {
3917a286c47SDai Ngo 		proto_plugin_fini();
3927a286c47SDai Ngo 		return (RP_NO_MEMORY);
3937a286c47SDai Ngo 	}
3947a286c47SDai Ngo 
3957a286c47SDai Ngo 	rp_hdl = &rp_proto_handle;
3967a286c47SDai Ngo 	rp_hdl->rp_num_proto = 0;
3977a286c47SDai Ngo 	for (tmp = rp_proto_list; rp_hdl->rp_num_proto < num_protos &&
3987a286c47SDai Ngo 	    tmp != NULL; tmp = tmp->plugin_next) {
3997a286c47SDai Ngo 
4007a286c47SDai Ngo 		err = RP_OK;
4017a286c47SDai Ngo 		if (tmp->plugin_ops->rpo_init != NULL)
4027a286c47SDai Ngo 			err = tmp->plugin_ops->rpo_init();
4037a286c47SDai Ngo 		if (err != RP_OK)
4047a286c47SDai Ngo 			continue;
4057a286c47SDai Ngo 		rp_hdl->rp_ops[rp_hdl->rp_num_proto++] = tmp->plugin_ops;
4067a286c47SDai Ngo 	}
4077a286c47SDai Ngo 
4087a286c47SDai Ngo 	return (rp_hdl->rp_num_proto > 0 ? RP_OK : RP_NO_PLUGIN);
4097a286c47SDai Ngo }
4107a286c47SDai Ngo 
4117a286c47SDai Ngo 
4127a286c47SDai Ngo /*
4137a286c47SDai Ngo  * find_protocol()
4147a286c47SDai Ngo  *
4157a286c47SDai Ngo  * Search the plugin list for the specified protocol and return the
4167a286c47SDai Ngo  * ops vector.  return NULL if protocol is not defined.
4177a286c47SDai Ngo  */
4187a286c47SDai Ngo static rp_plugin_ops_t *
4197a286c47SDai Ngo rp_find_protocol(const char *svc_type)
4207a286c47SDai Ngo {
4217a286c47SDai Ngo 	int i;
4227a286c47SDai Ngo 	rp_plugin_ops_t *ops = NULL;
4237a286c47SDai Ngo 
4247a286c47SDai Ngo 	if (svc_type == NULL)
4257a286c47SDai Ngo 		return (NULL);
4267a286c47SDai Ngo 
4277a286c47SDai Ngo 	if (rp_plugin_inited == 0) {
4287a286c47SDai Ngo 		if (rp_plugin_init() == RP_OK)
4297a286c47SDai Ngo 			rp_plugin_inited = 1;
4307a286c47SDai Ngo 		else
4317a286c47SDai Ngo 			return (NULL);
4327a286c47SDai Ngo 	}
4337a286c47SDai Ngo 
4347a286c47SDai Ngo 	for (i = 0; i < rp_proto_handle.rp_num_proto; i++) {
4357a286c47SDai Ngo 		ops = rp_proto_handle.rp_ops[i];
4367a286c47SDai Ngo 		if (ops->rpo_supports_svc(svc_type))
4377a286c47SDai Ngo 			return (ops);
4387a286c47SDai Ngo 
4397a286c47SDai Ngo 	}
4407a286c47SDai Ngo 	return (NULL);
4417a286c47SDai Ngo }
442