Add generic properties.
This commit is contained in:
parent
f39983133f
commit
e1bd5ac110
296
share/man/man9/properties.9
Normal file
296
share/man/man9/properties.9
Normal file
@ -0,0 +1,296 @@
|
||||
.\" $NetBSD: properties.9,v 1.1 2001/10/04 18:56:43 eeh Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Eduardo Horvath
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed for the
|
||||
.\" NetBSD Project. See http://www.netbsd.org/ for
|
||||
.\" information about NetBSD.
|
||||
.\" 4. The name of the author may not be used to endorse or promote products
|
||||
.\" derived from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\"
|
||||
.Dd October 3, 2001
|
||||
.Dt PROPERTIES 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm propdb_create ,
|
||||
.Nm propdb_destroy ,
|
||||
.Nm prop_set ,
|
||||
.Nm prop_get ,
|
||||
.Nm prop_delete ,
|
||||
.Nm prop_copy ,
|
||||
.Nm prop_objs ,
|
||||
.Nm prop_list
|
||||
.Nd generic kernel properties
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <sys/properties.h>
|
||||
.Pp
|
||||
.Va typedef void *propdb_t
|
||||
.Pp
|
||||
.Va typedef int64_t opaque_t
|
||||
.Ft propdb_t
|
||||
.Fn propdb_create "const char *name"
|
||||
.Ft void
|
||||
.Fn propdb_destroy "propdb_t db"
|
||||
.Ft int
|
||||
.Fn prop_set "propdb_t db" "opaque_t object" "const char *name" "void *val" \
|
||||
"size_t len" "int type" "int wait"
|
||||
.Ft size_t
|
||||
.Fn prop_get "propdb_t db" "opaque_t object" "const char *name" "void *val" \
|
||||
"size_t len" "int *type"
|
||||
.Ft int
|
||||
.Fn prop_delete "propdb_t db" "opaque_t object" "const char *name"
|
||||
.Ft int
|
||||
.Fn prop_copy "propdb_t db" "opaque_t source" "opaque_t dest" "int wait"
|
||||
.Ft size_t
|
||||
.Fn prop_objs "propdb_t db" "opaque_t *objects" "size_t len"
|
||||
.Ft size_t
|
||||
.Fn prop_list "propdb_t db" "opaque_t object" "char *names" "size_t len"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nx
|
||||
property management routines allow kernel subsystems to associate
|
||||
.Po name, value
|
||||
.Pc pairs with arbitrary keys in a generalized manner.
|
||||
.Pp
|
||||
A database is a container for a set of properties. It is created with
|
||||
.Fn propdb_create
|
||||
and discarded with
|
||||
.Fn propdb_destroy .
|
||||
Kernel subsystems should create their own databases to prevent possible
|
||||
namespace conflicts.
|
||||
.Pp
|
||||
A property is a tuple that consists of an opaque identifier
|
||||
.Po often a pointer to a kernel data structure
|
||||
.Pc , string, and an arbitrary amount of data. This
|
||||
association is established by
|
||||
.Fn prop_set ,
|
||||
retrieved by
|
||||
.Fn prop_get ,
|
||||
and destroyed by
|
||||
.Fn prop_delete .
|
||||
.Pp
|
||||
A system call interface makes use of the existing
|
||||
.Ic sysctl
|
||||
interface, and is provided
|
||||
primarily for diagnostic purposes.
|
||||
.Pp
|
||||
.Sh TYPES
|
||||
Several types are defined in
|
||||
.Pa Aq sys/properties.h .
|
||||
.Pp
|
||||
.Bl -ohang -compact
|
||||
.It Fa propdb_t
|
||||
.Pp
|
||||
The
|
||||
.Fa probdb_t
|
||||
type is used to contain a handle for a property database.
|
||||
.Pp
|
||||
.It Fa opaque_t
|
||||
.Pp
|
||||
The
|
||||
.Fa opaque_t
|
||||
type is a 64-bit scalar type used to store arbitrary object identifiers.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
makes no type distinctions, but it does associate a type datum with each
|
||||
property. Users of the interface can use that field to help determine what
|
||||
information is stored in the value field of the property. There are three
|
||||
base types:
|
||||
.El
|
||||
.Pp
|
||||
.Bl -tag -width "PROP_ELSZ(type)" -compact -offset indent
|
||||
.It PROP_INT
|
||||
Property is an integer type.
|
||||
.It PROP_STRING
|
||||
Property is a string.
|
||||
.It PROP_AGGREGATE
|
||||
Property is an aggregation of different types.
|
||||
.El
|
||||
.Pp
|
||||
Which can be further modified:
|
||||
.Pp
|
||||
.Bl -tag -width "PROP_ELSZ(type)" -compact -offset indent
|
||||
.It PROP_ARRAY
|
||||
Property is an array of values.
|
||||
.It PROP_CONST
|
||||
Property value has static storage and is maintained outside the database.
|
||||
.It PROP_ELSZ
|
||||
.Pq Fa size
|
||||
Encode element size into the type field. This is primarily used to describe
|
||||
the size of individual elements of an array.
|
||||
.El
|
||||
.Pp
|
||||
.Sh FUNCTIONS
|
||||
.Pp
|
||||
.Bl -tag -width indent
|
||||
.It Fn "propdb_t propdb_create" "const char *name"
|
||||
.Pp
|
||||
Allocate and initialize a kernel database object, and associate
|
||||
.Fa name
|
||||
with the database.
|
||||
.Fa name
|
||||
may later be used to access this database from userland throught the
|
||||
userland database query interface. This operation may block.
|
||||
Returns
|
||||
.Li NULL
|
||||
on failure.
|
||||
.Pp
|
||||
.It Fn "void propdb_destroy" "propdb_t db"
|
||||
Destroy and deallocate a kernel database and all data within. This
|
||||
routine deallocates all properties contained within the database.
|
||||
.Pp
|
||||
.It Fn "int prop_set" "propdb_t db" "opaque_t object" "const char *name" \
|
||||
"void *val" "size_t len" "int type" "int wait"
|
||||
Create a property
|
||||
.Fa name
|
||||
associated with
|
||||
.Fa object
|
||||
inside database
|
||||
.Fa db ,
|
||||
with a
|
||||
.Fa len
|
||||
byte value copied from location
|
||||
.Fa val .
|
||||
The database must already have been initialized with
|
||||
.Fn propdb_create .
|
||||
.Fa object
|
||||
is treated as an opaque value. If
|
||||
.Fa len
|
||||
is
|
||||
.Li 0
|
||||
then no data is copied. This can be used to create properties which
|
||||
convey information by their presence or absence. The
|
||||
.Fa type
|
||||
field is used to identify what the format of the object is. This value
|
||||
is usually only used to help programs dump property values into human
|
||||
readable formats. However, if
|
||||
.Li PROP_CONST
|
||||
is specified in the
|
||||
.Fa type
|
||||
field, no storage is allocated for the value, and when the property is
|
||||
queried it will copy
|
||||
.Fa len
|
||||
bytes directly from the location specified by
|
||||
.Fa val ,
|
||||
so that data cannot be freed or the kernel may panic. If
|
||||
.Fa wait
|
||||
is zero then
|
||||
.Fn prop_set
|
||||
will not sleep for resource shortage. Returns
|
||||
.Li 0
|
||||
on success, or an error value.
|
||||
.Pp
|
||||
.It Fn "size_t prop_get" "propdb_t db" "opaque_t object" "const char *name" \
|
||||
"void *val" "size_t len" "int *type"
|
||||
Retrieve a property called
|
||||
.Fa name
|
||||
associated with
|
||||
.Fa object .
|
||||
.Fa name
|
||||
is a pointer to a string. The property that matches both
|
||||
.Fa object
|
||||
and
|
||||
.Fa name
|
||||
will be selected, and the data and type information associated with that
|
||||
property will be returned in the buffers pointed to by
|
||||
.Fa val
|
||||
and
|
||||
.Fa type
|
||||
as appropriate.
|
||||
.Pp
|
||||
Returns
|
||||
.Li -1
|
||||
if the property cannot be found, otherwise it returns the length of the
|
||||
value data, and copies up to
|
||||
.Fa len
|
||||
bytes of the property data to the location pointed to by
|
||||
.Fa val .
|
||||
If
|
||||
.Fa type
|
||||
is not
|
||||
.Li NULL ,
|
||||
the type information associated with that property is stored in the location
|
||||
it points to.
|
||||
.Pp
|
||||
.It Fn "int prop_delete" "propdb_t db" "opaque_t object" "const char *name"
|
||||
Remove a property from a database. If a
|
||||
.Li NULL
|
||||
is supplied for
|
||||
.Fa name ,
|
||||
.Fn prop_delete
|
||||
will remove all properties associated with
|
||||
.Fa object .
|
||||
It returns the number of properties deleted.
|
||||
.Pp
|
||||
.It Fn "int prop_copy" "propdb_t db" "opaque_t source" "opaque_t dest" \
|
||||
"int wait"
|
||||
Copy all properties associated with
|
||||
.Fa source
|
||||
to
|
||||
.Fa dest
|
||||
structure. If
|
||||
.Fa wait
|
||||
is zero then
|
||||
.Fn prop_copy
|
||||
will not sleep for resource shortage. Returns
|
||||
.Li 0
|
||||
on success or an error value. The state of properties is undefined if the
|
||||
operation fails.
|
||||
.It Fn "size_t prop_objs" "propdb_t db" "opaque_t *objects" "size_t len"
|
||||
Get a list of objects identifiers from a database. An array of object
|
||||
idientifiers will be copied into the buffer pointed to by
|
||||
.Fa objects
|
||||
up to
|
||||
.Fa len
|
||||
bytes. It returns the amount of memory needed to store the entire list.
|
||||
.Pp
|
||||
.It Fn "size_t prop_list" "propdb_t db" "opaque_t object" "char *names" \
|
||||
"size_t len"
|
||||
Get a list of an object's properties from the database. It queries the
|
||||
database to locate all properties associated with
|
||||
.Pa object
|
||||
objedt identifier, and copies up to
|
||||
.Pa len
|
||||
bytes of
|
||||
.Li NUL
|
||||
terminated property names into the buffer pointed to by
|
||||
.Pa names .
|
||||
Partial strings are not copied, and another NUL character to indicate the
|
||||
termination of the list. It returns the size needed to hold the
|
||||
entire list.
|
||||
.El
|
||||
.Pp
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nx
|
||||
property management system was developed by Eduardo Horvath <eeh@netbsd.org>
|
||||
.Sh SEE ALSO
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nx
|
||||
property management system first appeared in
|
||||
.Nx 1.6 .
|
966
sys/kern/subr_prop.c
Normal file
966
sys/kern/subr_prop.c
Normal file
@ -0,0 +1,966 @@
|
||||
/* $NetBSD: subr_prop.c,v 1.1 2001/10/04 18:56:06 eeh Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Eduardo Horvath.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Eduardo Horvath.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/properties.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
int propdebug = 0;
|
||||
#define DPRINTF(v, t) if (propdebug) printf t
|
||||
#else
|
||||
#define DPRINTF(v, t)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Kernel properties database implementation.
|
||||
*
|
||||
* While this could theoretically be flat, lookups
|
||||
* are always done in the following order:
|
||||
*
|
||||
* database, object, name
|
||||
*
|
||||
* So we'll lay out the structures to make this efficient.
|
||||
*
|
||||
*/
|
||||
#define KDB_SIZE 32 /* Initial hash table size */
|
||||
#define KDB_MAXLEN 6 /* Max acceptable bucket length */
|
||||
#define KDB_STEP 2 /* Increment size for hash table */
|
||||
#define KDB_HASH(v, s) ((((v)>>16)^((v)>>8))&((s)-1))
|
||||
|
||||
typedef LIST_HEAD(kobj_head, kdbobj) kobj_bucket_t;
|
||||
|
||||
static LIST_HEAD(propdb_list, propdb) propdbs =
|
||||
LIST_HEAD_INITIALIZER(propdbs);
|
||||
|
||||
struct propdb {
|
||||
LIST_ENTRY(propdb) kd_link;
|
||||
char kd_name[MAX_KDBNAME];
|
||||
size_t kd_size;
|
||||
|
||||
/* Hash table of kdbobj structs */
|
||||
kobj_bucket_t *kd_obj;
|
||||
int kd_longest; /* Keep track of collisions */
|
||||
};
|
||||
|
||||
struct kdbobj {
|
||||
LIST_ENTRY(kdbobj) ko_link;
|
||||
opaque_t ko_object;
|
||||
/*
|
||||
* There should only be a dozen props for each object,
|
||||
* so we can keep them in a list.
|
||||
*/
|
||||
LIST_HEAD(kprops, kdbprop) ko_props;
|
||||
};
|
||||
|
||||
struct kdbprop {
|
||||
LIST_ENTRY(kdbprop) kp_link;
|
||||
const char *kp_name;
|
||||
const char *kp_val;
|
||||
int kp_len;
|
||||
int kp_type;
|
||||
};
|
||||
|
||||
|
||||
static struct kdbprop *allocprop(const char *name, size_t len, int wait);
|
||||
static void kdb_rehash(struct propdb *db);
|
||||
static struct kdbobj *kdbobj_find(propdb_t db, opaque_t object,
|
||||
int create, int wait);
|
||||
static int prop_insert(struct kdbobj *obj, const char *name, void *val,
|
||||
size_t len, int type, int wait);
|
||||
|
||||
/*
|
||||
* Allocate a prop structure large enough to hold
|
||||
* `name' and `len' bytes of data. For PROP_CONST
|
||||
* pass in a `len' of 0.
|
||||
*/
|
||||
static struct kdbprop *
|
||||
allocprop(const char *name, size_t len, int wait)
|
||||
{
|
||||
struct kdbprop *kp;
|
||||
char *np, *vp;
|
||||
size_t dsize, nsize;
|
||||
|
||||
dsize = ALIGN(len);
|
||||
nsize = ALIGN(strlen(name));
|
||||
|
||||
DPRINTF(x, ("allocprop: allocating %ld bytes for %s %s\n",
|
||||
sizeof(struct kdbprop) + dsize + nsize, name,
|
||||
wait ? "can wait" : "can't wait"));
|
||||
|
||||
kp = (struct kdbprop *)malloc(sizeof(struct kdbprop) + dsize + nsize,
|
||||
M_PROP, wait ? M_WAITOK : M_NOWAIT);
|
||||
|
||||
DPRINTF(x, ("allocprop: got %p for prop\n", kp));
|
||||
|
||||
if (kp) {
|
||||
/* Install name and init pointers */
|
||||
vp = (char *)&kp[1];
|
||||
kp->kp_val = (const char *)vp;
|
||||
np = vp + dsize;
|
||||
strcpy(np, name);
|
||||
kp->kp_name = (const char *)np;
|
||||
kp->kp_len = len;
|
||||
}
|
||||
return (kp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If the database hash chains grow too long try to resize
|
||||
* the hash table. Failure is not catastrophic.
|
||||
*/
|
||||
static void
|
||||
kdb_rehash(struct propdb *db)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
kobj_bucket_t *new, *old = db->kd_obj;
|
||||
long hash;
|
||||
size_t newsize = (db->kd_size << KDB_STEP);
|
||||
int i, s;
|
||||
|
||||
new = (kobj_bucket_t *)malloc(sizeof(kobj_bucket_t) * newsize,
|
||||
M_PROP, M_NOWAIT);
|
||||
if (!new) return;
|
||||
s = splvm();
|
||||
for (i=0; i<newsize; i++)
|
||||
LIST_INIT(&new[i]);
|
||||
|
||||
/* Now pop an object from the old table and insert it in the new one. */
|
||||
for (i=0; i<db->kd_size; i++) {
|
||||
while ((obj = LIST_FIRST(&old[i]))) {
|
||||
LIST_REMOVE(obj, ko_link);
|
||||
hash = (long)obj->ko_object;
|
||||
hash = KDB_HASH(hash, db->kd_size);
|
||||
LIST_INSERT_HEAD(&new[hash], obj, ko_link);
|
||||
}
|
||||
}
|
||||
db->kd_size = newsize;
|
||||
db->kd_obj = new;
|
||||
splx(s);
|
||||
free(old, M_PROP);
|
||||
}
|
||||
|
||||
/*
|
||||
* For propdb structures we use a simple power-of-2
|
||||
* hash.
|
||||
*/
|
||||
|
||||
propdb_t
|
||||
propdb_create(const char *name)
|
||||
{
|
||||
struct propdb *db;
|
||||
int i;
|
||||
|
||||
db = (struct propdb *)malloc(sizeof(struct propdb),
|
||||
M_PROP, M_WAITOK);
|
||||
|
||||
strncpy(db->kd_name, name, 32);
|
||||
|
||||
/* Initialize the hash table. */
|
||||
db->kd_size = KDB_SIZE;
|
||||
db->kd_longest = 0;
|
||||
db->kd_obj = (kobj_bucket_t *)malloc(sizeof(kobj_bucket_t) *
|
||||
db->kd_size, M_PROP, M_WAITOK);
|
||||
for (i = 0; i < db->kd_size; i++)
|
||||
LIST_INIT(&db->kd_obj[i]);
|
||||
LIST_INSERT_HEAD(&propdbs, db, kd_link);
|
||||
return (db);
|
||||
}
|
||||
|
||||
void
|
||||
propdb_destroy(propdb_t db)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
struct kdbprop *prop;
|
||||
int i;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
struct propdb *p;
|
||||
|
||||
/* Make sure we have a handle to a valid database */
|
||||
LIST_FOREACH(p, &propdbs, kd_link) {
|
||||
if (p == db) break;
|
||||
}
|
||||
if (p == NULL) panic("propdb_destroy: invalid database\n");
|
||||
#endif
|
||||
LIST_REMOVE(db, kd_link);
|
||||
|
||||
/* Empty out each hash bucket */
|
||||
for (i = 0; i < db->kd_size; i++) {
|
||||
while ((obj = LIST_FIRST(&db->kd_obj[i]))) {
|
||||
LIST_REMOVE(obj, ko_link);
|
||||
while ((prop = LIST_FIRST(&obj->ko_props))) {
|
||||
LIST_REMOVE(prop, kp_link);
|
||||
free(prop, M_PROP);
|
||||
}
|
||||
free(obj, M_PROP);
|
||||
}
|
||||
}
|
||||
free(db->kd_obj, M_PROP);
|
||||
free(db, M_PROP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an object in the database and possibly create it too.
|
||||
*/
|
||||
static struct kdbobj *
|
||||
kdbobj_find(propdb_t db, opaque_t object, int create, int wait)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
long hash = (long)object;
|
||||
int i;
|
||||
|
||||
/* Find our object */
|
||||
hash = KDB_HASH(hash, db->kd_size);
|
||||
i=0;
|
||||
LIST_FOREACH(obj, &db->kd_obj[hash], ko_link) {
|
||||
i++; /* Measure chain depth */
|
||||
if (obj->ko_object == object)
|
||||
break;
|
||||
}
|
||||
if (create && (obj == NULL)) {
|
||||
/* Need a new object. */
|
||||
obj = (struct kdbobj *)malloc(sizeof(struct kdbobj),
|
||||
M_PROP, wait ? M_WAITOK : M_NOWAIT);
|
||||
|
||||
if (!obj) {
|
||||
return (obj);
|
||||
}
|
||||
|
||||
/* Handle hash table growth */
|
||||
if (++i > db->kd_longest)
|
||||
db->kd_longest = i;
|
||||
if (db->kd_longest > KDB_MAXLEN) {
|
||||
/* Increase the size of our hash table */
|
||||
kdb_rehash(db);
|
||||
}
|
||||
|
||||
/* Initialize object */
|
||||
obj->ko_object = object;
|
||||
LIST_INIT(&obj->ko_props);
|
||||
LIST_INSERT_HEAD(&db->kd_obj[hash], obj, ko_link);
|
||||
}
|
||||
return (obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal property insertion routine.
|
||||
*/
|
||||
static int
|
||||
prop_insert(struct kdbobj *obj, const char *name, void *val, size_t len,
|
||||
int type, int wait)
|
||||
{
|
||||
struct kdbprop *prop = NULL, *oprop;
|
||||
|
||||
/* Does the prop exist already? */
|
||||
LIST_FOREACH(oprop, &obj->ko_props, kp_link) {
|
||||
if (strcmp(oprop->kp_name, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (oprop) {
|
||||
/* Can is it big enough? */
|
||||
if ((type & PROP_CONST) ||
|
||||
((ALIGN(len) < ALIGN(oprop->kp_len)) &&
|
||||
(oprop->kp_type & PROP_CONST) == 0)) {
|
||||
/* We can reuse it */
|
||||
prop = oprop;
|
||||
}
|
||||
}
|
||||
if (!prop) {
|
||||
/* Allocate a new prop */
|
||||
if (type & PROP_CONST)
|
||||
prop = allocprop(name, 0, wait);
|
||||
else
|
||||
prop = allocprop(name, len, wait);
|
||||
if (!prop) return (wait ? ENOMEM : EAGAIN);
|
||||
}
|
||||
/* Set the values */
|
||||
if (type & PROP_CONST) {
|
||||
prop->kp_val = val;
|
||||
} else {
|
||||
char *dest = (char *)prop->kp_val;
|
||||
memcpy(dest, val, len);
|
||||
}
|
||||
prop->kp_len = len;
|
||||
prop->kp_type = type;
|
||||
|
||||
/* Now clean up if necessary */
|
||||
if (prop != oprop) {
|
||||
LIST_INSERT_HEAD(&obj->ko_props, prop, kp_link);
|
||||
if (oprop) {
|
||||
LIST_REMOVE(oprop, kp_link);
|
||||
free(oprop, M_PROP);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
prop_set(propdb_t db, opaque_t object, const char *name,
|
||||
void *val, size_t len, int type, int wait)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
struct kdbprop *prop = NULL, *oprop;
|
||||
int s;
|
||||
|
||||
DPRINTF(x, ("prop_set: %p, %p, %s, %p, %lx, %x, %d\n", db, object,
|
||||
name ? name : "NULL", val, len, type, wait));
|
||||
|
||||
/* Find our object */
|
||||
s = splvm();
|
||||
obj = kdbobj_find(db, object, 1, wait);
|
||||
if (!obj) {
|
||||
splx(s);
|
||||
return (wait ? ENOMEM : EAGAIN);
|
||||
}
|
||||
|
||||
#if 1
|
||||
{
|
||||
int rv;
|
||||
|
||||
oprop = prop; /* XXXX -- use vars to make gcc happy. */
|
||||
rv = prop_insert(obj, name, val, len, type, wait);
|
||||
splx(s);
|
||||
return (rv);
|
||||
}
|
||||
#else
|
||||
/* Does the prop exist already? */
|
||||
LIST_FOREACH(oprop, &obj->ko_props, kp_link) {
|
||||
if (strcmp(oprop->kp_name, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (oprop) {
|
||||
/* Can is it big enough? */
|
||||
if ((type & PROP_CONST) ||
|
||||
((ALIGN(len) < ALIGN(oprop->kp_len)) &&
|
||||
(oprop->kp_type & PROP_CONST) == 0)) {
|
||||
/* We can reuse it */
|
||||
prop = oprop;
|
||||
}
|
||||
}
|
||||
if (!prop) {
|
||||
/* Allocate a new prop */
|
||||
if (type & PROP_CONST)
|
||||
prop = allocprop(name, 0, wait);
|
||||
else
|
||||
prop = allocprop(name, len, wait);
|
||||
if (!prop) return (wait ? ENOMEM : EAGAIN);
|
||||
}
|
||||
/* Set the values */
|
||||
if (type & PROP_CONST) {
|
||||
prop->kp_val = val;
|
||||
} else {
|
||||
char *dest = (char *)prop->kp_val;
|
||||
memcpy(dest, val, len);
|
||||
}
|
||||
prop->kp_len = len;
|
||||
prop->kp_type = type;
|
||||
|
||||
/* Now clean up if necessary */
|
||||
if (prop != oprop) {
|
||||
LIST_INSERT_HEAD(&obj->ko_props, prop, kp_link);
|
||||
if (oprop) {
|
||||
LIST_REMOVE(oprop, kp_link);
|
||||
free(oprop, M_PROP);
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t
|
||||
prop_get(propdb_t db, opaque_t object, const char *name, void *val,
|
||||
size_t len, int *type)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
struct kdbprop *prop = NULL;
|
||||
int s;
|
||||
|
||||
DPRINTF(x, ("prop_get: %p, %p, %s, %p, %lx, %p\n", db, object,
|
||||
name ? name : "NULL", val, len, type));
|
||||
|
||||
/* Find our object */
|
||||
s = splvm();
|
||||
obj = kdbobj_find(db, object, 0, 0);
|
||||
if (!obj) {
|
||||
splx(s);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* find our prop */
|
||||
LIST_FOREACH(prop, &obj->ko_props, kp_link) {
|
||||
if (strcmp(prop->kp_name, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (!prop) {
|
||||
splx(s);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Copy out our prop */
|
||||
len = min(len, prop->kp_len);
|
||||
if (val && len) {
|
||||
memcpy(val, prop->kp_val, len);
|
||||
}
|
||||
if (type)
|
||||
*type = prop->kp_type;
|
||||
splx(s);
|
||||
return (prop->kp_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the total number of objects in the database and as
|
||||
* many as fit in the buffer.
|
||||
*/
|
||||
size_t
|
||||
prop_objs(propdb_t db, opaque_t *objects, size_t len)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
int i, j, s, nelem = (len / sizeof(opaque_t));
|
||||
|
||||
DPRINTF(x, ("prop_objs: %p, %p, %lx\n", db, objects, len));
|
||||
|
||||
s = splvm();
|
||||
for (i=0, j=0; i < db->kd_size; i++) {
|
||||
LIST_FOREACH(obj, &db->kd_obj[i], ko_link) {
|
||||
if (objects && j<nelem)
|
||||
objects[j] = obj->ko_object;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
return (j * sizeof(opaque_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the total number of property names associated with an object
|
||||
* and as many as fit in the buffer.
|
||||
*/
|
||||
size_t
|
||||
prop_list(propdb_t db, opaque_t object, char *names, size_t len)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
struct kdbprop *prop = NULL;
|
||||
size_t total_len = 0;
|
||||
int s, i = 0;
|
||||
|
||||
DPRINTF(x, ("prop_list: %p, %p, %p, %lx\n",
|
||||
db, object, names, len));
|
||||
|
||||
/* Find our source object */
|
||||
s = splvm();
|
||||
obj = kdbobj_find(db, object, 0, 0);
|
||||
if (obj == NULL) {
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
LIST_FOREACH(prop, &obj->ko_props, kp_link) {
|
||||
i = strlen(prop->kp_name) + 1;
|
||||
total_len += i;
|
||||
if (total_len < len) {
|
||||
strcpy(names, prop->kp_name);
|
||||
names += i;
|
||||
/* Add an extra NUL */
|
||||
names[i+1] = 0;
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
return (total_len);
|
||||
}
|
||||
|
||||
int
|
||||
prop_delete(propdb_t db, opaque_t object, const char *name)
|
||||
{
|
||||
struct kdbobj *obj;
|
||||
struct kdbprop *prop = NULL;
|
||||
int s, i = 0;
|
||||
|
||||
DPRINTF(x, ("prop_delete: %p, %p, %s\n", db, object,
|
||||
name ? name : "NULL"));
|
||||
|
||||
/* Find our object */
|
||||
s = splvm();
|
||||
obj = kdbobj_find(db, object, 0, 0);
|
||||
if (obj == NULL) {
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
/* Find our prop */
|
||||
LIST_FOREACH(prop, &obj->ko_props, kp_link) {
|
||||
if (strcmp(prop->kp_name, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (!prop) {
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
LIST_REMOVE(prop, kp_link);
|
||||
free(prop, M_PROP);
|
||||
i++;
|
||||
} else {
|
||||
while ((prop = LIST_FIRST(&obj->ko_props))) {
|
||||
LIST_REMOVE(prop, kp_link);
|
||||
free(prop, M_PROP);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (LIST_EMPTY(&obj->ko_props)) {
|
||||
/* Free up the empty container. */
|
||||
LIST_REMOVE(obj, ko_link);
|
||||
free(obj, M_PROP);
|
||||
}
|
||||
splx(s);
|
||||
return (i);
|
||||
}
|
||||
|
||||
int
|
||||
prop_copy(propdb_t db, opaque_t source, opaque_t dest, int wait)
|
||||
{
|
||||
struct kdbobj *nobj, *oobj;
|
||||
struct kdbprop *prop, *oprop, *srcp;
|
||||
int s;
|
||||
|
||||
DPRINTF(x, ("prop_copy: %p, %p, %p, %d\n", db, source, dest, wait));
|
||||
|
||||
/* Find our source object */
|
||||
s = splvm();
|
||||
oobj = kdbobj_find(db, source, 0, wait);
|
||||
if (oobj == NULL) {
|
||||
splx(s);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Find our dest object */
|
||||
nobj = kdbobj_find(db, dest, 1, wait);
|
||||
if (!nobj) {
|
||||
splx(s);
|
||||
return (wait ? ENOMEM : EAGAIN);
|
||||
}
|
||||
|
||||
/* Copy these properties over now */
|
||||
LIST_FOREACH(srcp, &oobj->ko_props, kp_link) {
|
||||
|
||||
DPRINTF(x, ("prop_copy: copying prop %s\n",
|
||||
srcp->kp_name));
|
||||
|
||||
#if 1
|
||||
{
|
||||
int rv;
|
||||
|
||||
oprop = prop; /* XXXX -- use vars to make gcc happy. */
|
||||
rv = prop_insert(nobj, srcp->kp_name,
|
||||
(void *)srcp->kp_val, srcp->kp_len,
|
||||
srcp->kp_type, wait);
|
||||
if (rv) {
|
||||
/* Error of some sort */
|
||||
splx(s);
|
||||
return (rv);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Does the prop exist already? */
|
||||
prop = NULL;
|
||||
LIST_FOREACH(oprop, &nobj->ko_props, kp_link) {
|
||||
if (strcmp(oprop->kp_name, srcp->kp_name) == 0)
|
||||
break;
|
||||
}
|
||||
if (oprop) {
|
||||
|
||||
DPRINTF(x, ("prop_copy: found old prop %p\n",
|
||||
oprop));
|
||||
|
||||
/* Can is it big enough? */
|
||||
if ((srcp->kp_type & PROP_CONST) ||
|
||||
((ALIGN(srcp->kp_len) < ALIGN(oprop->kp_len)) &&
|
||||
(oprop->kp_type & PROP_CONST) == 0)) {
|
||||
/* We can reuse it */
|
||||
prop = oprop;
|
||||
DPRINTF(x, ("prop_copy: using old prop\n"));
|
||||
}
|
||||
}
|
||||
if (!prop) {
|
||||
/* Allocate a new prop */
|
||||
if (srcp->kp_type & PROP_CONST)
|
||||
prop = allocprop(srcp->kp_name, 0, wait);
|
||||
else
|
||||
prop = allocprop(srcp->kp_name,
|
||||
srcp->kp_len, wait);
|
||||
if (!prop) {
|
||||
splx(s);
|
||||
return (wait ? ENOMEM : EAGAIN);
|
||||
}
|
||||
}
|
||||
/* Set the values */
|
||||
if (srcp->kp_type & PROP_CONST) {
|
||||
prop->kp_val = srcp->kp_val;
|
||||
} else {
|
||||
char *dest = (char *)prop->kp_val;
|
||||
memcpy(dest, srcp->kp_val, srcp->kp_len);
|
||||
}
|
||||
prop->kp_len = srcp->kp_len;
|
||||
prop->kp_type = srcp->kp_type;
|
||||
|
||||
/* Now clean up if necessary */
|
||||
if (prop != oprop) {
|
||||
|
||||
DPRINTF(x, ("prop_copy: inserting prop %p\n", prop));
|
||||
LIST_INSERT_HEAD(&nobj->ko_props, prop, kp_link);
|
||||
if (oprop) {
|
||||
DPRINTF(x, ("prop_copy: removing prop %p\n",
|
||||
oprop));
|
||||
LIST_REMOVE(oprop, kp_link);
|
||||
free(oprop, M_PROP);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
DPRINTF(x, ("prop_copy: done\n"));
|
||||
splx(s);
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* sysctl() accessors.
|
||||
*
|
||||
* Operations:
|
||||
*
|
||||
* CTL_KERN.KERN_DB.KERN_DB_ALL
|
||||
*
|
||||
* Return an array of kinfo_kdb structures for all databases.
|
||||
*
|
||||
* CTL_KERN.KERN_DB.KERN_DB_OBJ_ALL.dbid.dbid
|
||||
*
|
||||
* Return an array of int64_t identifiers for a specific database.
|
||||
*
|
||||
* CTL_KERN.KERN_DB.KERN_DB_PROP_ALL.dbid.dbid.objid.objid
|
||||
*
|
||||
* Return ????
|
||||
*
|
||||
*
|
||||
*/
|
||||
int
|
||||
sysctl_propdb(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen)
|
||||
{
|
||||
struct propdb *kdb;
|
||||
struct kdbobj *obj;
|
||||
struct kdbprop *prop;
|
||||
struct kinfo_kdb kdbi;
|
||||
struct kinfo_prop kip, *kipp;
|
||||
u_int64_t val;
|
||||
caddr_t dp = (caddr_t)oldp;
|
||||
size_t dlen;
|
||||
int i, s, op;
|
||||
int error = 0, needed = 0;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/* How can this happen if we've gotten this far? */
|
||||
if (namelen <= 1)
|
||||
return (EINVAL);
|
||||
#endif
|
||||
op = name[1];
|
||||
switch(op) {
|
||||
case KERN_DB_ALL:
|
||||
if (namelen != 2)
|
||||
return (EINVAL);
|
||||
break;
|
||||
case KERN_DB_OBJ_ALL:
|
||||
if (namelen != 4)
|
||||
return (EINVAL);
|
||||
break;
|
||||
case KERN_DB_PROP_ALL:
|
||||
if (namelen != 6)
|
||||
return (EINVAL);
|
||||
break;
|
||||
case KERN_DB_PROP_GET:
|
||||
case KERN_DB_PROP_SET:
|
||||
case KERN_DB_PROP_DELETE:
|
||||
if (namelen != 6)
|
||||
return (EINVAL);
|
||||
if (newlen < sizeof(kip) || newp == NULL)
|
||||
return (EINVAL);
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Figure out how much space we were given */
|
||||
if (oldp && oldlenp)
|
||||
dlen = *oldlenp;
|
||||
else
|
||||
dlen = 0;
|
||||
|
||||
if (name[0] != KERN_DB) {
|
||||
/* How did we get here? */
|
||||
DPRINTF(x, ("sysctl_propdb: %d != KERN_DB (%d)\n",
|
||||
name[0], KERN_DB));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
s = splvm();
|
||||
if (op == KERN_DB_ALL) {
|
||||
LIST_FOREACH(kdb, &propdbs, kd_link) {
|
||||
/* Fill the kdbi */
|
||||
strncpy(&kdbi.ki_name[0], kdb->kd_name, MAX_KDBNAME);
|
||||
kdbi.ki_id = (u_int64_t)(u_long)kdb;
|
||||
|
||||
/* And copy it out if we can */
|
||||
if (dlen >= sizeof(kdbi)) {
|
||||
error = copyout((caddr_t)&kdbi, dp,
|
||||
sizeof(kdbi));
|
||||
dp += sizeof(kdbi);
|
||||
dlen -= sizeof(kdbi);
|
||||
}
|
||||
if (error)
|
||||
goto cleanup;
|
||||
needed += sizeof(kdbi);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Get database ID. I wish sysctl used 64-bit ints. */
|
||||
val = (((u_int64_t)name[2])<<32)|name[3];
|
||||
|
||||
/* Find the correct database */
|
||||
LIST_FOREACH(kdb, &propdbs, kd_link) {
|
||||
if (val == (u_int64_t)(u_long)kdb)
|
||||
break;
|
||||
}
|
||||
if (kdb == NULL) {
|
||||
error = ENOENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (op == KERN_DB_OBJ_ALL) {
|
||||
/* Now write out each object id XXX we should batch this... */
|
||||
for (i=0; i < kdb->kd_size; i++) {
|
||||
LIST_FOREACH(obj, &kdb->kd_obj[i], ko_link) {
|
||||
size_t siz = sizeof(u_int64_t);
|
||||
|
||||
if (dlen >= siz) {
|
||||
error = copyout((caddr_t)
|
||||
&obj->ko_object, dp, siz);
|
||||
dp += siz;
|
||||
dlen -= siz;
|
||||
}
|
||||
if (error)
|
||||
goto cleanup;
|
||||
needed += siz;
|
||||
}
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Get object ID. */
|
||||
val = (((u_int64_t)name[4]<<32))|name[5];
|
||||
|
||||
/* Find object */
|
||||
obj = kdbobj_find(kdb, (opaque_t)(long)val, 0, 0);
|
||||
if (obj == NULL) {
|
||||
error = ENOENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (op == KERN_DB_PROP_ALL) {
|
||||
LIST_FOREACH(prop, &obj->ko_props, kp_link) {
|
||||
size_t stlen;
|
||||
int vlen;
|
||||
|
||||
kipp = (struct kinfo_prop *)dp;
|
||||
vlen = prop->kp_len;
|
||||
|
||||
/* XXXX we don't know how long this will get... */
|
||||
if (dlen >= sizeof(kip)) {
|
||||
error = copyoutstr(prop->kp_name,
|
||||
&kipp->kip_name[0],
|
||||
dlen - sizeof(kip), &stlen);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
|
||||
/* Fill out some of the kinfo_prop */
|
||||
kip.kip_len = stlen;
|
||||
kip.kip_vallen = vlen;
|
||||
kip.kip_type = prop->kp_type;
|
||||
|
||||
/* Round to a pointer boundary */
|
||||
stlen = ALIGN(stlen);
|
||||
dp += sizeof(kip) + stlen;
|
||||
dlen -= sizeof(kip) - stlen;
|
||||
|
||||
/* Finish filling out kinfo_prop */
|
||||
kip.kip_valoff =
|
||||
(uintptr_t)dp - (uintptr_t)kipp;
|
||||
kip.kip_len = kip.kip_valoff + kip.kip_vallen;
|
||||
error = copyout((caddr_t)&kip, dp,
|
||||
sizeof(kip) - 1);
|
||||
} else
|
||||
stlen = ALIGN(strlen(prop->kp_name) + 1);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
|
||||
/* Finally we can try to copy out the value */
|
||||
if (dlen >= prop->kp_len) {
|
||||
error = copyout(prop->kp_val, dp,
|
||||
vlen);
|
||||
dp += vlen;
|
||||
dlen -= vlen;
|
||||
}
|
||||
if (error)
|
||||
goto cleanup;
|
||||
needed += stlen + dlen;
|
||||
}
|
||||
} else {
|
||||
caddr_t inbuf, outbuf = NULL;
|
||||
|
||||
/* Change a property */
|
||||
error = copyin(newp, (caddr_t)&kip, sizeof(kip) - 1);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
|
||||
if (kip.kip_len > newlen) {
|
||||
/* The property is bigger than the buffer? */
|
||||
error = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate storage for our args and copy them in */
|
||||
inbuf = malloc(kip.kip_len, M_TEMP, M_WAITOK);
|
||||
if (!inbuf) {
|
||||
error = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
error = copyin(newp, inbuf, kip.kip_len);
|
||||
if (error) {
|
||||
free(inbuf, M_TEMP);
|
||||
goto cleanup;
|
||||
}
|
||||
kipp = (struct kinfo_prop *)inbuf;
|
||||
/* Make *sure* we're NULL terminated. */
|
||||
if (kip.kip_valoff > sizeof(kip) ||
|
||||
kip.kip_valoff > kip.kip_len)
|
||||
inbuf[kip.kip_len] = 0;
|
||||
else
|
||||
inbuf[kip.kip_valoff - 1] = 0;
|
||||
|
||||
/*
|
||||
* We need to copy out the old prop before we zap it.
|
||||
*/
|
||||
if (dp && dlen) {
|
||||
/* Find out how big the existing prop is (if any) */
|
||||
kipp->kip_vallen = prop_get(kdb, obj->ko_object,
|
||||
kipp->kip_name, NULL, 0, &kipp->kip_type);
|
||||
if (op == KERN_DB_PROP_GET && kipp->kip_len < 0) {
|
||||
free(inbuf, M_TEMP);
|
||||
error = ENOENT;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Calculate where we'll store the data. */
|
||||
kipp->kip_valoff = ALIGN(strlen(kipp->kip_name) + 1);
|
||||
needed = kipp->kip_vallen + kipp->kip_valoff;
|
||||
kipp->kip_len = needed;
|
||||
if (needed > dlen) {
|
||||
free(inbuf, M_TEMP);
|
||||
goto cleanup;
|
||||
}
|
||||
if (kipp->kip_vallen > 0) {
|
||||
outbuf = malloc(kipp->kip_vallen,
|
||||
M_TEMP, M_WAITOK);
|
||||
if (!outbuf) {
|
||||
free(inbuf, M_TEMP);
|
||||
error = ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
if (prop_get(kdb, obj->ko_object,
|
||||
kipp->kip_name, outbuf,
|
||||
kipp->kip_vallen, NULL) !=
|
||||
kipp->kip_vallen) {
|
||||
/* It existed a second ago */
|
||||
panic("sysctl_propdb: "
|
||||
"inconsistent property %s",
|
||||
kipp->kip_name);
|
||||
}
|
||||
/* copyout the data */
|
||||
error = copyout(outbuf, dp + kipp->kip_valoff,
|
||||
kipp->kip_vallen);
|
||||
free(outbuf, M_TEMP);
|
||||
if (error) {
|
||||
free(inbuf, M_TEMP);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
/* Now copyout the header and string */
|
||||
error = copyout((caddr_t)kipp, dp,
|
||||
kipp->kip_valoff);
|
||||
if (error) {
|
||||
free(inbuf, M_TEMP);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* We can finally replace/delete the property.
|
||||
*/
|
||||
|
||||
if (op == KERN_DB_PROP_SET) {
|
||||
/* XXXX sleeping at splvm() */
|
||||
error = prop_set(kdb, obj->ko_object, kipp->kip_name,
|
||||
(caddr_t)kipp + kip.kip_valoff,
|
||||
kip.kip_vallen, kip.kip_type, 1);
|
||||
} else if (op == KERN_DB_PROP_DELETE) {
|
||||
error = prop_delete(kdb, obj->ko_object,
|
||||
kipp->kip_name);
|
||||
}
|
||||
|
||||
free(inbuf, M_TEMP);
|
||||
}
|
||||
cleanup:
|
||||
splx(s);
|
||||
dlen = dp - (caddr_t)oldp;
|
||||
if (needed > dlen)
|
||||
dlen = needed;
|
||||
if (oldp && oldlenp)
|
||||
*oldlenp = dlen;
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
118
sys/sys/properties.h
Normal file
118
sys/sys/properties.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* $NetBSD: properties.h,v 1.1 2001/10/04 18:56:06 eeh Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Eduardo Horvath.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Eduardo Horvath.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_PROPERTIES_H_
|
||||
#define _SYS_PROPERTIES_H_
|
||||
|
||||
typedef void *opaque_t; /* Value large enough to hold a pointer */
|
||||
|
||||
struct propdb;
|
||||
typedef struct propdb *propdb_t;
|
||||
|
||||
#define MAX_KDBNAME 32
|
||||
|
||||
#define PROP_INT 0x10000000
|
||||
#define PROP_STRING 0x20000000
|
||||
#define PROP_AGGREGATE 0x30000000
|
||||
#define PROP_TYPE(x) ((x)&0x30000000)
|
||||
|
||||
#define PROP_ARRAY 0x40000000
|
||||
#define PROP_CONST 0x80000000
|
||||
#define PROP_ELSZ(x) 0x0fffffff
|
||||
|
||||
propdb_t propdb_create(const char *name);
|
||||
void propdb_destroy(propdb_t db);
|
||||
|
||||
int prop_set(propdb_t db, opaque_t object, const char *name,
|
||||
void *val, size_t len, int type, int wait);
|
||||
size_t prop_objs(propdb_t db, opaque_t *objects, size_t len);
|
||||
size_t prop_list(propdb_t db, opaque_t object, char *names,
|
||||
size_t len);
|
||||
size_t prop_get(propdb_t db, opaque_t object, const char *name,
|
||||
void *val, size_t len, int *type);
|
||||
int prop_delete(propdb_t db, opaque_t object, const char *name);
|
||||
int prop_copy(propdb_t db, opaque_t source, opaque_t dest,
|
||||
int wait);
|
||||
|
||||
int sysctl_propdb(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen);
|
||||
|
||||
|
||||
/*
|
||||
* KERN_DB subtypes
|
||||
*/
|
||||
|
||||
#define KERN_DB_ALL 0 /* all databases */
|
||||
#define KERN_DB_OBJ_ALL 1 /* all objects in a database */
|
||||
#define KERN_DB_PROP_ALL 2 /* all properties in an object */
|
||||
#define KERN_DB_PROP_GET 3 /* get a single property */
|
||||
#define KERN_DB_PROP_SET 4 /* set a single property */
|
||||
#define KERN_DB_PROP_DELETE 5 /* delete a single property */
|
||||
|
||||
#define CTL_DB_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
{ "all", CTLTYPE_STRUCT }, \
|
||||
{ "allobj", CTLTYPE_QUAD }, \
|
||||
{ "allprops", CTLTYPE_INT }, \
|
||||
{ "propget", CTLTYPE_STRUCT }, \
|
||||
{ "propset", CTLTYPE_STRUCT }, \
|
||||
{ "propdelete", CTLTYPE_STRUCT }, \
|
||||
}
|
||||
|
||||
/* Info available for each database. */
|
||||
struct kinfo_kdb {
|
||||
char ki_name[MAX_KDBNAME];
|
||||
uint64_t ki_id;
|
||||
};
|
||||
|
||||
/* A single property */
|
||||
struct kinfo_prop {
|
||||
uint32_t kip_len; /* total len of this prop */
|
||||
uint32_t kip_type; /* type of this prop */
|
||||
uint32_t kip_valoff; /* offset of start of value */
|
||||
uint32_t kip_vallen; /* length of value */
|
||||
char kip_name[1]; /* name of this property */
|
||||
};
|
||||
|
||||
/* Use these macros to encode database and object information in the MIB. */
|
||||
#define KERN_DB_ENCODE_DB(p, m) do { \
|
||||
(m)[2] = (int)(((uint64_t)(long)(p))>>32); \
|
||||
(m)[3] = (int)(p); \
|
||||
} while (0)
|
||||
|
||||
#define KERN_DB_ENCODE_OBJ(p, o, m) do { \
|
||||
(m)[2] = (int)(((uint64_t)(long)(p))>>32); \
|
||||
(m)[3] = (int)(p); \
|
||||
(m)[4] = (int)(((uint64_t)(long)(o))>>32); \
|
||||
(m)[5] = (int)(o); \
|
||||
} while (0)
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user