/*
* 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
*/
/*
*/
/*
* This module contains the private layer API.
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libelf.h>
#include <gelf.h>
#include <dlfcn.h>
#include <glob.h>
#include <fcntl.h>
#include <libinetutil.h>
#include <dhcp_svc_public.h>
#include <dhcp_svc_private.h>
/*
* Threading notes for private layer consumers:
*
* The handles returned from open_dd() may be shared across multiple
* threads with no adverse side effects. However, it's up to that consumer
* to ensure that all threads have finished using an instance before
* closing the instance or removing the container it's referencing.
* Phrased differently:
*
* * Consumers must ensure all threads sharing a handle are
* finished before calling close_dd().
*
* * Consumers must ensure all threads referencing a container are
* closed before calling remove_dd().
*/
static void synch_fini(dsvc_handle_t);
/*
* Order here should match the function array in <dhcp_svc_private.h>
*/
static char *funcnames[] = {
"status", "version", "mklocation",
"list_dt", "open_dt", "close_dt", "remove_dt",
"lookup_dt", "add_dt", "modify_dt", "delete_dt",
"list_dn", "open_dn", "close_dn", "remove_dn",
"lookup_dn", "add_dn", "modify_dn", "delete_dn"
};
extern dsvc_synch_ops_t dsvcd_synch_ops;
/*
* Retrieve the current version associated with the datastore named by
* `resource' and store in `converp'. One might think we could do this via
* a simple readlink(2), but on internal release builds $(ROOTLINKS)
* installs using hardlinks, not symlinks. For this reason and to make it
* harder for us to be fooled, we'll dredge up the actual soname through
* ELF. Close your eyes, it's gonna get ugly.
*/
static int
{
int elf_fd;
int i;
if (elf_fd == -1)
return (DSVC_MODULE_ERR);
return (DSVC_INTERNAL);
}
return (DSVC_INTERNAL);
}
continue;
continue;
continue;
i = 0;
do {
}
return (DSVC_MODULE_ERR);
}
return (DSVC_SUCCESS);
}
/*
* Unload a public datastore module.
*/
static int
{
return (DSVC_MODULE_UNLOAD_ERR);
return (DSVC_SUCCESS);
}
/*
* Load public datastore module. Validates version of module. Returns
* instance of opened module, and populates the api argument with the
* function addresses exporting the API.
*/
static int
{
int i, v;
return (DSVC_MODULE_LOAD_ERR);
/*
* No requirement to duplicate the names - we can always reference
* the same set.
*/
v != DSVC_PUBLIC_VERSION) {
return (DSVC_MODULE_VERSION);
}
return (DSVC_MODULE_CFG_ERR);
}
}
for (i = 0; i < DSVC_NSPLFUNCS; i++) {
if ((((dsvc_splfuncp_t *)api)[i] =
return (DSVC_MODULE_ERR);
}
}
/*
* Caller requested the current version; fill in what that current
* version is.
*/
int error;
if (error != DSVC_SUCCESS) {
return (error);
}
}
return (DSVC_SUCCESS);
}
/*
* Return a dynamically-allocated null-terminated list of the available
* modules stored in the module directory. A count of the available
* modules is stored in the num argument. Caller is responsible for
* freeing the list.
*/
int
{
int i, retval;
char *ptr;
return (DSVC_INVAL);
if (retval != 0) {
switch (retval) {
case GLOB_NOMATCH:
*nump = 0;
return (DSVC_SUCCESS);
case GLOB_NOSPACE:
return (DSVC_NO_MEMORY);
default:
return (DSVC_INTERNAL);
}
}
return (DSVC_NO_MEMORY);
}
else
ptr++;
while (i--)
return (DSVC_NO_MEMORY);
}
}
*nump = i;
return (DSVC_SUCCESS);
}
/*
* Check the status of the underlying service supporting the data store.
* Caller is responsible for freeing any dynamically allocated arguments.
*/
int
{
void *instance;
int error;
if (error != DSVC_SUCCESS)
return (error);
return (error);
}
/*
* Create within the data store the "location" where containers will be
* stored.
*/
int
{
void *instance;
int error;
if (error != DSVC_SUCCESS)
return (error);
return (error);
}
/*
* Return a list of the current container objects of type 'type' located at
* 'location' in listppp. Return the number of list elements in 'count'.
*/
int
{
void *instance;
int error;
if (error != DSVC_SUCCESS)
return (error);
if (type == DSVC_DHCPTAB)
else
return (error);
}
/*
* Creates or opens the DHCP container of type called name within the
* specific datastore referenced by ddp, and returns a handle to this
* container in the handp argument. New containers are created with
* the identity of the caller. Caller is responsible for freeing any
* dynamically allocated arguments. The returned handle instance must
* be released by calling close_dd().
*/
int
{
int error;
return (DSVC_INVAL);
return (DSVC_INVAL);
return (DSVC_NO_MEMORY);
if (type == DSVC_DHCPNETWORK) {
return (DSVC_INVAL);
}
}
if (error != DSVC_SUCCESS) {
return (error);
}
goto error;
}
/*
* Initialize the synchronization strategy (may not be any).
*/
if (error != DSVC_SUCCESS)
goto error;
if (type == DSVC_DHCPTAB)
else
if (error != DSVC_SUCCESS) {
synch_fini(hp);
goto error;
}
return (DSVC_SUCCESS);
return (error);
}
/*
* Remove DHCP container called name of type within the specific datastore
* referenced by ddp. Caller is responsible for freeing any dynamically
* allocated arguments.
*/
int
{
void *instance;
int error;
if (type != DSVC_DHCPTAB) {
return (DSVC_INVAL);
}
if (error != DSVC_SUCCESS)
return (error);
/* remove the DHCP container */
if (type == DSVC_DHCPTAB)
else
return (error);
}
/*
* Delete the handle instance referenced by hand. Frees hand if the close
* operation was successful. NOTE: Caller is responsible for synchronizing
* multiple threads such that close_dd() is called when all consuming
* threads have exited.
*/
int
{
int error;
return (DSVC_INVAL);
else
if (error == DSVC_SUCCESS) {
synch_fini(*handp);
}
return (error);
}
/*
* Searches hand container for records that match the query described by
* the combination of query and targetp. If the partial field is true, then
* lookup operations that have located some records but are unable to
* complete entirely are allowed. The query argument consists of 2 fields,
* each 16 bits long. The lower 16 bits selects which fields in the targetp
* record are to be considered in the query. The upper 16 bits identifies
* whether a particular field value must match (bit set) or not match (bit
* clear). Unused bits in both 16 bit fields must be 0. The count argument
* specifies the maximum number of matching records to return. A count
* value of -1 requests that all matching records be returned. recordsp is
* set to point to the resulting list of records; if recordsp is NULL then
* no records are actually returned. Note that these records are
* dynamically allocated, thus the caller is responsible for freeing them.
* The number of records found is returned in nrecordsp; a value of 0 means
* that no records matched the query.
*/
int
{
int error;
void *unlock_cookie;
int (*lookup)();
return (DSVC_INVAL);
} else {
}
/* validate query */
return (DSVC_INVAL);
/*
* XXX: need to validate the `targetp' -- what a mess cuz only the
* fields lit in `query' need to be valid.
*/
if (error != DSVC_SUCCESS)
return (error);
}
return (error);
}
/*
* Frees the record pointed to by entryp.
*/
void
{
return;
else
}
/*
* Frees the list of records pointed to by listp.
*/
void
{
return;
else
}
/*
* Add the record newp to the DHCP container hand. newp's update signature
* will be updated by the public layer module doing the update. Caller is
* responsible for freeing newp if it was dynamically allocated.
*/
int
{
int error;
void *unlock_cookie;
if (DSVC_HANDLE_INVAL(hand))
return (DSVC_INVAL);
return (DSVC_INVAL);
if (error != DSVC_SUCCESS)
return (error);
}
else
return (error);
}
/*
* Modify the record origp with the record newp in the DHCP container hand.
* newp's update signature will be updated by the public layer module doing
* were dynamically allocated.
*/
int
{
int error;
void *unlock_cookie;
if (DSVC_HANDLE_INVAL(hand))
return (DSVC_INVAL);
return (DSVC_INVAL);
return (DSVC_INVAL);
if (error != DSVC_SUCCESS)
return (error);
}
else
return (error);
}
/*
* Deletes the record referred to by entryp from the DHCP container hand.
* Caller is responsible for freeing entryp if it was dynamically
* allocated.
*/
int
{
int error;
void *unlock_cookie;
if (DSVC_HANDLE_INVAL(hand))
return (DSVC_INVAL);
return (DSVC_INVAL);
if (error != DSVC_SUCCESS)
return (error);
}
else
return (error);
}
/*
* Validate that the DHCP network record `dn' is correctly formed; returns
* B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then only
* validate the key.
*/
static boolean_t
{
/* CIP must be on container's network */
return (B_FALSE);
if (justkey)
return (B_TRUE);
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
}
/*
* Validate that the dhcptab record `dt' is correctly formed; returns
* B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then only
* validate the key.
*/
/* ARGSUSED */
static boolean_t
{
}
/*
* Validate that a DHCP record of type `hand->d_type' is correctly formed;
* returns B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then
* only validate the key.
*/
static boolean_t
{
return (B_FALSE);
return (B_FALSE);
}
/*
* Get the type of synchronization needed for this module and store in
* `synchtypep'. Returns a DSVC_* code. This function is exported so that
* dsvclockd(1M) can use it.
*/
int
{
void *instance;
return (DSVC_INTERNAL);
if (dsvc_synchtypep != NULL)
else
return (DSVC_SUCCESS);
}
/*
* Initialize private-layer synchronization on handle `hand' for container
* `conname'; `flags' is the same flags passed into open_dd(). If there's
* no synchronization needed, always succeeds. Returns a DSVC_* code.
*/
int
{
int error;
int (*mkloctoken)(const char *, char *, size_t);
if (error != DSVC_SUCCESS)
return (error);
if (synchtype == DSVC_SYNCH_NONE)
return (DSVC_SUCCESS);
return (DSVC_NO_MEMORY);
return (DSVC_NO_MEMORY);
}
if (mkloctoken == NULL) {
sizeof (sp->s_loctoken));
} else {
sizeof (sp->s_loctoken));
if (error != DSVC_SUCCESS) {
return (error);
}
}
/*
* The only synchtype supported is DSVC_SYNCH_DSVCD; if this
* changes, we'll need to enhance this.
*/
if (error != DSVC_SUCCESS) {
return (error);
}
return (DSVC_SUCCESS);
}
/*
* Finish using private-layer synchronization on handle `hand'.
*/
void
{
}