/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <libnvpair.h>
#include <dlfcn.h>
#include <libintl.h>
#include <sys/systeminfo.h>
#include <sys/fs_reparse.h>
#include "rp_plugin.h"
int rp_plugin_init(void);
static void proto_plugin_fini(void);
extern int errno;
static int rp_plugin_inited = 0;
/*
* reparse_create()
*
* Create a symlink at the specified 'path' as a reparse point.
* This function will fail if path refers to an existing file system
* object or an object named string already exists at the given path.
*
* return 0 if ok else return error code.
*/
int
{
int err;
return (EINVAL);
return (err);
/* check if object exists */
return (EEXIST);
}
/*
* reparse_unparse()
*
* Convert an nvlist back to a string format suitable to write
* to the reparse point symlink body. The string returned is in
* allocated memory and must be freed by the caller.
*
* return 0 if ok else return error code.
*/
int
{
return (EINVAL);
return (ENOMEM);
err = 0;
break;
}
break;
}
}
if (err != 0) {
return (err);
}
return (E2BIG);
}
return (0);
}
/*
* reparse_deref()
*
* Accepts the service-specific item from the reparse point and returns
* the service-specific data requested. The caller specifies the size
* of the buffer provided via *bufsz.
*
* if ok return 0 and *bufsz is updated to contain the actual length of
* the returned results, else return error code. If the error code is
* EOVERFLOW; results do not fit in the buffer, *bufsz will be updated
* to contain the number of bytes needed to hold the results.
*/
int
{
return (EINVAL);
/* no plugin, return error */
return (ENOTSUP);
}
/*
* reparse_delete()
*
* Delete a reparse point at a given pathname. It will fail if
* a reparse point does not exist at the given path or the pathname
* is not a symlink.
*
* return 0 if ok else return error code.
*/
int
{
return (EINVAL);
/* check if object exists */
return (errno);
return (EINVAL);
}
/*
* reparse_add()
*
* Add a service type entry to a nvlist with a copy of svc_data,
* replacing one of the same type if already present.
*
* return 0 if ok else return error code.
*/
int
{
int err;
char *buf;
return (EINVAL);
return (ENOMEM);
else
if (err != 0) {
return (err);
}
return (err);
}
/*
* reparse_remove()
*
* Remove a service type entry from the nvlist, if present.
*
* return 0 if ok else return error code.
*/
int
{
return (EINVAL);
}
/*
* Returns true if name is "." or "..", otherwise returns false.
*/
static boolean_t
{
if (*name != '.')
return (B_FALSE);
return (B_TRUE);
return (B_FALSE);
}
static void
{
/*
* Protocols may call this framework during _fini
*/
if (p->plugin_ops->rpo_fini)
p->plugin_ops->rpo_fini();
}
while ((p = rp_proto_list) != NULL) {
rp_proto_list = p->plugin_next;
if (p->plugin_handle != NULL)
(void) dlclose(p->plugin_handle);
free(p);
}
}
}
/*
* rp_plugin_init()
*
* Initialize the service type specific plugin modules.
* For each reparse service type, there should be a plugin library for it.
* For each plugin library found, initialize it and add it to the internal
* list of service type plugin. These are used for service type specific
* operations.
*/
int
{
int num_protos = 0;
void *dlhandle;
#if defined(_LP64)
isa[0] = '\0';
#else
isa[0] = '\0';
#endif
return (RP_NO_PLUGIN_DIR);
continue;
/*
* If file doesn't exist, don't try to map it
*/
continue;
continue;
plugin_ops = (rp_plugin_ops_t *)
if (plugin_ops == NULL) {
"Error in plugin ops for service type %s\n%s\n"),
continue;
}
proto = (rp_proto_plugin_t *)
ret = RP_NO_MEMORY;
break;
}
num_protos++;
}
if ((num_protos == 0) && (ret == 0))
ret = RP_NO_PLUGIN;
/*
* There was an error, so cleanup prior to return of failure.
*/
return (ret);
}
sizeof (rp_plugin_ops_t *));
if (!rp_proto_handle.rp_ops) {
return (RP_NO_MEMORY);
}
rp_hdl->rp_num_proto = 0;
continue;
}
}
/*
* find_protocol()
*
* Search the plugin list for the specified protocol and return the
* ops vector. return NULL if protocol is not defined.
*/
static rp_plugin_ops_t *
{
int i;
return (NULL);
if (rp_plugin_inited == 0) {
if (rp_plugin_init() == RP_OK)
rp_plugin_inited = 1;
else
return (NULL);
}
for (i = 0; i < rp_proto_handle.rp_num_proto; i++) {
return (ops);
}
return (NULL);
}