dhcptab.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 (c) 2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains public functions for managing the dhcptab container.
* For the semantics of these functions, please see the Enterprise DHCP
* Architecture Document.
*
* This module uses synchronization guarantees provided by dsvclockd(1M);
* please see $SRC/lib/libdhcpsvc/private/README.synch for details.
*
* Big Theory Statement for the SUNWbinfiles DHCP Table Module
* ===========================================================
*
* Since the dhcptab container does not have any performance-critical
* consumers, this module focuses on being simple and robust rather than
* fast. The on-disk structure consists of a minimal header followed by a
* list of dt_filerec_t's in no particular order. Note that the dt_rec_t's
* dt_value can be arbitrarily large, which means each dt_filerec_t is also
* of arbitrary size; we deal with this by storing the on-disk size of each
* record in the record itself.
*
* To meet our robustness requirements (see the Big Theory Statement in
* dhcp_network.c), each update operation does its work on a copy of the
* dhcptab, which is then atomically renamed to the name of the actual
* dhcptab upon completion (yes, this is *very slow*). To speed this up a
* little, we use mmap(2) to generate the copy, which is about twice as
* fast as using read(2)/write(2).
*/
#include <unistd.h>
#include <dhcp_svc_public.h>
#include <sys/isa_defs.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <alloca.h>
#include "dhcptab.h"
#include "util.h"
/*
* We compute the RECSIZE using the offset of `rec_dtval' rather than the
* sizeof (dt_filerec_t) so that we don't include any trailing structure
* padding in the size calculation.
*/
static int read_header(int, dt_header_t *);
static int write_header(int, dt_header_t *);
dt_rec_list_t **, uint_t *);
int
{
dt_header_t header = { 0 };
char dtpath[MAXPATHLEN];
int retval;
int fd;
return (DSVC_NO_MEMORY);
if (retval != DSVC_SUCCESS) {
return (retval);
}
if (flags & DSVC_CREATE) {
/*
* We just created the per-network container; initialize
* the header and put it out on disk.
*/
return (retval);
}
} else {
/*
* Container already exists; sanity check against the
* header that's on-disk.
*/
return (retval);
}
return (DSVC_INTERNAL);
}
}
return (DSVC_SUCCESS);
}
int
{
return (DSVC_SUCCESS);
}
int
{
char dtpath[MAXPATHLEN];
return (syserr_to_dsvcerr(errno));
return (DSVC_SUCCESS);
}
int
{
int fd;
int retval;
char dtpath[MAXPATHLEN];
return (DSVC_ACCESS);
if (fd == -1)
return (syserr_to_dsvcerr(errno));
return (retval);
}
/*
* Internal version of lookup_dt() used by lookup_dt(), modify_dt(),
* add_dt(), and delete_dt(); same semantics as lookup_dt() except that the
* `partial' argument has been generalized into a `flags' field and the
* handle has been turned into a file descriptor.
*/
static int
{
int retval = DSVC_SUCCESS;
return (syserr_to_dsvcerr(errno));
return (DSVC_INTERNAL);
break;
}
/*
* See if we've got a match...
*/
continue;
/*
* Caller just wants a count of the number of matching
* records, not the records themselves; continue.
*/
nrecords++;
continue;
}
/*
* Allocate record; if FIND_POSITION flag is set, then
* we need to allocate an extended (dt_recpos_t) record.
*/
if (flags & FIND_POSITION)
else
if ((flags & FIND_PARTIAL) == 0)
break;
}
/*
* Fill in record; do a structure copy from our automatic
* record. If FIND_POSITION flag is on, pass back
* additional location information.
*/
if ((flags & FIND_PARTIAL) == 0)
break;
}
if ((flags & FIND_PARTIAL) == 0)
break;
}
if (flags & FIND_POSITION) {
}
/*
* Chuck the record on the list and up the counter.
*/
if (new_records == NULL) {
if ((flags & FIND_PARTIAL) == 0)
break;
}
nrecords++;
}
if (retval == DSVC_SUCCESS) {
return (DSVC_SUCCESS);
}
return (retval);
}
/*
* Compares `dtp' to the target `targetp', using `query' to decide what
* fields to compare. Returns B_TRUE if `dtp' matches `targetp', B_FALSE
* if not.
*/
static boolean_t
{
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
}
int
{
unsigned int found;
int query;
int retval;
return (DSVC_ACCESS);
if (fd == -1)
return (syserr_to_dsvcerr(errno));
/*
* Make sure the record wasn't created when we weren't looking.
*/
if (retval != DSVC_SUCCESS) {
return (retval);
}
if (found != 0) {
return (DSVC_EXISTS);
}
/*
* Make a new copy of the dhcptab with the new record appended.
* Once done, atomically rename the new dhcptab to the old name.
*/
return (DSVC_INTERNAL);
}
if (newfd == -1) {
goto out;
}
if (retval != DSVC_SUCCESS)
goto out;
goto out;
}
/*
* Note: we close these descriptors before the rename(2) (rather
* than just having the `out:' label clean them up) to save NFS
* some work (otherwise, NFS has to save `dtpath' to an alternate
* name since its vnode would still be active).
*/
return (retval);
out:
return (retval);
}
int
{
unsigned int found;
int query;
int retval;
return (DSVC_ACCESS);
if (fd == -1)
return (syserr_to_dsvcerr(errno));
/*
* If we're changing the key for this record, make sure the key
* we're changing to doesn't already exist.
*/
if (retval != DSVC_SUCCESS) {
return (retval);
}
if (found != 0) {
return (DSVC_EXISTS);
}
}
/*
* Fetch the original again to make sure it didn't go stale.
*/
if (retval != DSVC_SUCCESS) {
return (retval);
}
if (found == 0) {
return (DSVC_NOENT);
}
return (DSVC_COLLISION);
}
/*
* Make a new copy of the dhcptab, sans the record we're modifying,
* then append modified record at the end. Once done, atomically
* rename the new dhcptab to the old name.
*/
return (DSVC_INTERNAL);
}
if (newfd == -1) {
goto out;
}
if (retval != DSVC_SUCCESS)
goto out;
if (retval != DSVC_SUCCESS)
goto out;
goto out;
}
/*
* See comment in add_dt() regarding the next two lines.
*/
return (retval);
out:
return (retval);
}
int
{
unsigned int found;
int query;
int retval;
return (DSVC_ACCESS);
if (fd == -1)
return (syserr_to_dsvcerr(errno));
/*
* Make sure the record exists and also that the signatures match;
* if `delp->dt_sig' is zero, then skip signature comparison (this
* is so one can delete records that were not looked up).
*/
if (retval != DSVC_SUCCESS) {
return (retval);
}
if (found == 0) {
return (DSVC_NOENT);
}
return (DSVC_COLLISION);
}
/*
* Make a new copy of the dhcptab, sans the record we're deleting.
* Once done, atomically rename the new dhcptab to the old name.
*/
return (DSVC_INTERNAL);
}
if (newfd == -1) {
goto out;
}
if (retval != DSVC_SUCCESS)
goto out;
if (retval != DSVC_SUCCESS)
goto out;
/*
* See comment in add_dt() regarding the next two lines.
*/
return (retval);
out:
return (retval);
}
int
{
char dtpath[MAXPATHLEN];
char **listpp;
switch (errno) {
case EACCES:
case EPERM:
return (DSVC_ACCESS);
case ENOENT:
return (DSVC_NO_LOCATION);
default:
break;
}
return (DSVC_INTERNAL);
}
*countp = 0;
return (DSVC_SUCCESS);
}
return (DSVC_NO_MEMORY);
return (DSVC_NO_MEMORY);
}
*countp = 1;
return (DSVC_SUCCESS);
}
/*
* Given a buffer `path' of `pathlen' bytes, fill it in with a path to the
* dhcptab in directory `dir' with a suffix of `suffix'.
*/
static void
{
}
/*
* Convert dt_header_t pointed to by `headerp' from native (host) to
* network order or the other way.
*/
/* ARGSUSED */
static void
{
#ifdef _LITTLE_ENDIAN
#endif
}
/*
* Convert dt_filerec_t pointed to by `rec' from native (host) to network
* order or the other way.
*/
/* ARGSUSED */
static void
{
#ifdef _LITTLE_ENDIAN
#endif
}
/*
* Read the dt_header_t in the container at open file `fd' into the header
* pointed to by `headerp'. Returns 0 on success, -1 on failure (errno is
* set).
*/
static int
{
return (-1);
return (0);
}
/*
* Write the dt_header_t pointed to by `headerp' to the container at open
* file `fd'. Returns 0 on success, -1 on failure (errno is set).
*/
static int
{
int retval;
return (retval);
}
/*
* Read the dt_filerec_t in the container from offset `recoff' in the
* container at open file `fd'. Note that this only returns the fixed
* sized part of the dt_filerec_t; the caller must retrieve `rev_dtval' on
* their own. Returns 0 on success, -1 on failure (errno is set).
*/
static int
{
return (-1);
return (0);
}
/*
* Write the dt_filerec_t pointed to be `rec' to offset `recoff' in the
* container at open file `fd'. Returns 0 on success, -1 on failure (errno
* is set).
*/
static int
{
int retval;
return (retval);
}