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