287 lines
11 KiB
C
287 lines
11 KiB
C
#ifndef _MINIX_MIB_MIB_H
|
|
#define _MINIX_MIB_MIB_H
|
|
|
|
#include <minix/drivers.h>
|
|
#include <minix/sysctl.h>
|
|
#include <machine/vmparam.h>
|
|
#include <assert.h>
|
|
|
|
#if defined(__i386__)
|
|
#include "kernel/arch/i386/include/archconst.h"
|
|
#endif
|
|
|
|
#ifndef CONFIG_MAX_CPUS
|
|
#define CONFIG_MAX_CPUS 1
|
|
#endif
|
|
|
|
/*
|
|
* The following setting toggles the existence of the minix.test subtree. For
|
|
* production environments, it should probably be disabled, although it should
|
|
* do no harm either. For development platforms, it should be enabled, or
|
|
* test87 will fail.
|
|
*/
|
|
#define MINIX_TEST_SUBTREE 1 /* include the minix.test subtree? */
|
|
|
|
struct mib_oldp;
|
|
struct mib_newp;
|
|
|
|
/*
|
|
* This structure contains a number of less heavily used parameters for handler
|
|
* functions, mainly to provide extensibility while limiting argument clutter.
|
|
*/
|
|
struct mib_call {
|
|
endpoint_t call_endpt; /* endpoint of the user process */
|
|
const int *call_name; /* remaining part of the name */
|
|
unsigned int call_namelen; /* length of the remaining name part */
|
|
unsigned int call_flags; /* internal call processing flags */
|
|
size_t call_reslen; /* resulting oldlen value on error */
|
|
};
|
|
|
|
/* Call flags. */
|
|
#define MIB_FLAG_AUTH 0x01 /* user verified to be superuser */
|
|
#define MIB_FLAG_NOAUTH 0x02 /* user verified to be regular user */
|
|
|
|
/*
|
|
* We reassign new meaning to two NetBSD node flags, because we do not use the
|
|
* flags in the way NetBSD does:
|
|
*
|
|
* - On NetBSD, CTLFLAG_ROOT is used to mark the root of the sysctl tree. The
|
|
* entire root node is not exposed to userland, and thus, neither is this
|
|
* flag. We do not need the flag as we do not have parent pointers.
|
|
* - On NetBSD, CTLFLAG_ALIAS is used to mark one node as an alias of another
|
|
* node, presumably to avoid having to duplicate entire subtrees. We can
|
|
* simply have two nodes point to the same subtree instead, and thus, we do
|
|
* not need to support this functionality at all.
|
|
*
|
|
* The meaning of our replacement flags is explained further below. We ensure
|
|
* that neither of these flags are ever exposed to userland. As such, our own
|
|
* definitions can be changed as necessary without breaking anything.
|
|
*/
|
|
#define CTLFLAG_PARENT CTLFLAG_ROOT /* node is a real parent node */
|
|
#define CTLFLAG_VERIFY CTLFLAG_ALIAS /* node has verification function */
|
|
|
|
/*
|
|
* The following node structure definition aims to meet several goals at once:
|
|
*
|
|
* 1) it can be used for static and dynamic nodes;
|
|
* 2) it can be used to point to both static and dynamic child arrays at once;
|
|
* 3) it allows for embedded, pointed-to, and function-generated data;
|
|
* 4) its unions are compatible with magic instrumentation;
|
|
* 5) it is optimized for size, assuming many static and few dynamic nodes.
|
|
*
|
|
* All nodes have flags, a size, a version, a name, and optionally a
|
|
* description. The use of the rest of the fields depends on the type of the
|
|
* node, which is defined by part of the flags field.
|
|
*
|
|
* Data nodes, that is, nodes of type CTLTYPE_{BOOL,INT,QUAD,STRING,STRUCT},
|
|
* have associated data. For types CTLTYPE_{BOOL,INT,QUAD}, the node may have
|
|
* immediate data (CTLFLAG_IMMEDIATE), in which case the value of the node is
|
|
* stored in the node structure itself (node_bool, node_int, node_quad). These
|
|
* node types may instead also have a pointer to data. This is always the case
|
|
* for types CTLTYPE_STRING and CTLTYPE_STRUCT. In that case, node_data is a
|
|
* valid pointer, and CTLFLAG_IMMEDIATE is not set. Either way, node_size is
|
|
* the size of the data, which for strings is the maximum string size; for
|
|
* other types, it defines the exact field size. In addition, data nodes may
|
|
* have the CTLFLAG_VERIFY flag set, which indicates that node_valid points
|
|
* to a callback function that verifies whether a newly written value is valid
|
|
* for the node. If this flag is not set, data nodes may have an associated
|
|
* function, in which case node_func is not NULL, which will be called to read
|
|
* and write data instead. The function may optionally use the node's regular
|
|
* (size, immediate and/or pointer) data fields as it sees fit.
|
|
*
|
|
* Node-type nodes, of type CTLTYPE_NODE, behave differently. Such nodes may
|
|
* have either static and dynamic child nodes, or an associated function. Such
|
|
* a function handles all access to the entire subtree. If no function is set,
|
|
* the CTLFLAG_PARENT flag is set, to indicate that this node is the root of a
|
|
* real subtree; CTLFLAG_PARENT must not be set if the node has an associated
|
|
* function. For real node-type nodes (with CTLFLAG_PARENT set), node_size is
|
|
* the number (not size!) of the array of static child nodes, which is pointed
|
|
* to by node_scptr and indexed by child identifier. Within the static array,
|
|
* child nodes with zeroed flags fields are not in use. The node_dcptr field
|
|
* points to a linked list of dynamic child nodes. The node_csize field is set
|
|
* to the size of the static array plus the number of dynamic nodes; node_clen
|
|
* is set to the number of valid entries in the static array plus the number of
|
|
* dynamic nodes. If a function is set, none of these fields are used, and the
|
|
* node_size field is typically (but not necessarily) set to zero.
|
|
*
|
|
* The structure uses unions for either only pointers or only non-pointers, to
|
|
* simplify live update support. However, this does not mean the structure is
|
|
* not fully used: real node-type nodes use node_{flags,size,ver,csize,clen,
|
|
* scptr,dcptr,name,desc}, which together add up to the full structure size.
|
|
*/
|
|
struct mib_node;
|
|
struct mib_dynode;
|
|
|
|
typedef ssize_t (*mib_func_ptr)(struct mib_call *, struct mib_node *,
|
|
struct mib_oldp *, struct mib_newp *);
|
|
typedef int (*mib_verify_ptr)(struct mib_call *, struct mib_node *, void *,
|
|
size_t);
|
|
|
|
struct mib_node {
|
|
uint32_t node_flags; /* CTLTYPE_ type and CTLFLAGS_ flags */
|
|
size_t node_size; /* size of associated data (bytes) */
|
|
uint32_t node_ver; /* node version */
|
|
union ixfer_node_val_u {
|
|
struct {
|
|
uint32_t nvuc_csize; /* number of child slots */
|
|
uint32_t nvuc_clen; /* number of actual children */
|
|
} nvu_child;
|
|
int nvu_int; /* immediate integer */
|
|
bool nvu_bool; /* immediate boolean */
|
|
u_quad_t nvu_quad; /* immediate quad */
|
|
} node_val_u;
|
|
union pxfer_node_ptr_u {
|
|
void *npu_data; /* struct or string data pointer */
|
|
struct mib_node *npu_scptr; /* static child node array */
|
|
} node_ptr_u;
|
|
union pxfer_node_aux_u {
|
|
struct mib_dynode *nau_dcptr; /* dynamic child node list */
|
|
mib_func_ptr nau_func; /* handler function */
|
|
mib_verify_ptr nau_verify; /* verification function */
|
|
} node_aux_u;
|
|
const char *node_name; /* node name string */
|
|
const char *node_desc; /* node description (may be NULL) */
|
|
};
|
|
#define node_csize node_val_u.nvu_child.nvuc_csize
|
|
#define node_clen node_val_u.nvu_child.nvuc_clen
|
|
#define node_int node_val_u.nvu_int
|
|
#define node_bool node_val_u.nvu_bool
|
|
#define node_quad node_val_u.nvu_quad
|
|
#define node_data node_ptr_u.npu_data
|
|
#define node_scptr node_ptr_u.npu_scptr
|
|
#define node_dcptr node_aux_u.nau_dcptr
|
|
#define node_func node_aux_u.nau_func
|
|
#define node_verify node_aux_u.nau_verify
|
|
|
|
/*
|
|
* This structure is used for dynamically allocated nodes, that is, nodes
|
|
* created by userland at run time. It contains not only the fields below, but
|
|
* also the full name and, for leaf nodes with non-immediate data, the actual
|
|
* data area.
|
|
*/
|
|
struct mib_dynode {
|
|
struct mib_dynode *dynode_next; /* next in linked dynamic node list */
|
|
int dynode_id; /* identifier of this node */
|
|
struct mib_node dynode_node; /* actual node */
|
|
char dynode_name[1]; /* node name data (variable size) */
|
|
};
|
|
|
|
/* Static node initialization macros. */
|
|
#define MIB_NODE(f,t,n,d) { \
|
|
.node_flags = CTLTYPE_NODE | CTLFLAG_PARENT | f, \
|
|
.node_size = __arraycount(t), \
|
|
.node_scptr = t, \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
#define MIB_ENODE(f,n,d) { /* "E"mpty or "E"xternal */ \
|
|
.node_flags = CTLTYPE_NODE | CTLFLAG_PARENT | f, \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
#define MIB_INT(f,i,n,d) { \
|
|
.node_flags = CTLTYPE_INT | CTLFLAG_IMMEDIATE | f, \
|
|
.node_size = sizeof(int), \
|
|
.node_int = i, \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
#define MIB_BOOL(f,b,n,d) { \
|
|
.node_flags = CTLTYPE_BOOL | CTLFLAG_IMMEDIATE | f, \
|
|
.node_size = sizeof(bool), \
|
|
.node_bool = b, \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
#define MIB_QUAD(f,q,n,d) { \
|
|
.node_flags = CTLTYPE_QUAD | CTLFLAG_IMMEDIATE | f, \
|
|
.node_size = sizeof(u_quad_t), \
|
|
.node_quad = q, \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
#define MIB_DATA(f,s,n,d) { \
|
|
.node_flags = f, \
|
|
.node_size = sizeof(s), \
|
|
.node_data = __UNCONST(s), \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
#define MIB_STRING(f,p,n,d) MIB_DATA(CTLTYPE_STRING | f, p, n, d)
|
|
#define MIB_STRUCT(f,p,n,d) MIB_DATA(CTLTYPE_STRUCT | f, p, n, d)
|
|
#define MIB_INTPTR(f,p,n,d) MIB_DATA(CTLTYPE_INT | f, p, n, d)
|
|
#define MIB_FUNC(f,s,fp,n,d) { \
|
|
.node_flags = f, \
|
|
.node_size = s, \
|
|
.node_func = fp, \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
#define MIB_INTV(f,i,vp,n,d) { \
|
|
.node_flags = CTLTYPE_INT | CTLFLAG_IMMEDIATE | \
|
|
CTLFLAG_VERIFY | f, \
|
|
.node_size = sizeof(int), \
|
|
.node_int = i, \
|
|
.node_verify = vp, \
|
|
.node_name = n, \
|
|
.node_desc = d \
|
|
}
|
|
|
|
/* Finalize a node initialized with MIB_ENODE. */
|
|
#define MIB_INIT_ENODE(n,t) \
|
|
do { \
|
|
(n)->node_size = __arraycount(t); \
|
|
(n)->node_scptr = t; \
|
|
} while (0)
|
|
|
|
/* Some convenient shortcuts for highly common flags. */
|
|
#define _RO CTLFLAG_READONLY
|
|
#define _RW CTLFLAG_READWRITE
|
|
#define _P CTLFLAG_PERMANENT
|
|
|
|
/*
|
|
* If this check fails, all uses of "struct sysctlnode" and "struct sysctldesc"
|
|
* need to be revised, and translation between different versions of those
|
|
* structures may have to be added for backward compatibility.
|
|
*/
|
|
#if SYSCTL_VERSION != SYSCTL_VERS_1
|
|
#error "NetBSD sysctl headers are ahead of our implementation"
|
|
#endif
|
|
|
|
/* main.c */
|
|
int mib_inrange(struct mib_oldp *, size_t);
|
|
size_t mib_getoldlen(struct mib_oldp *);
|
|
ssize_t mib_copyout(struct mib_oldp *, size_t, const void * __restrict,
|
|
size_t);
|
|
void mib_setoldlen(struct mib_call *, size_t);
|
|
size_t mib_getnewlen(struct mib_newp *);
|
|
int mib_copyin(struct mib_newp * __restrict, void * __restrict, size_t);
|
|
int mib_copyin_aux(struct mib_newp * __restrict, vir_bytes,
|
|
void * __restrict, size_t);
|
|
int mib_authed(struct mib_call *);
|
|
|
|
/* tree.c */
|
|
ssize_t mib_readwrite(struct mib_call *, struct mib_node *, struct mib_oldp *,
|
|
struct mib_newp *, mib_verify_ptr);
|
|
ssize_t mib_dispatch(struct mib_call *, struct mib_node *, struct mib_oldp *,
|
|
struct mib_newp *);
|
|
void mib_tree_init(struct mib_node *);
|
|
extern unsigned int nodes;
|
|
extern unsigned int objects;
|
|
|
|
/* proc.c */
|
|
ssize_t mib_kern_lwp(struct mib_call *, struct mib_node *, struct mib_oldp *,
|
|
struct mib_newp *);
|
|
ssize_t mib_kern_proc2(struct mib_call *, struct mib_node *, struct mib_oldp *,
|
|
struct mib_newp *);
|
|
ssize_t mib_kern_proc_args(struct mib_call *, struct mib_node *,
|
|
struct mib_oldp *, struct mib_newp *);
|
|
|
|
/* subtree modules */
|
|
void mib_kern_init(struct mib_node *);
|
|
void mib_vm_init(struct mib_node *);
|
|
void mib_hw_init(struct mib_node *);
|
|
void mib_minix_init(struct mib_node *);
|
|
|
|
#endif /* !_MINIX_MIB_MIB_H */
|