Add MIB service, sysctl(2) support
The new MIB service implements the sysctl(2) system call which, as we adopt more NetBSD code, is an increasingly important part of the operating system API. The system call is implemented in the new service rather than as part of an existing service, because it will eventually call into many other services in order to gather data, similar to ProcFS. Since the sysctl(2) functionality is used even by init(8), the MIB service is added to the boot image. MIB stands for Management Information Base, and the MIB service should be seen as a knowledge base of management information. The MIB service implementation of the sysctl(2) interface is fairly complete; it incorporates support for both static and dynamic nodes and imitates many NetBSD-specific quirks expected by userland. The patch also adds trace(1) support for the new system call, and adds a new test, test87, which tests the fundamental operation of the MIB service rather thoroughly. Change-Id: I4766b410b25e94e9cd4affb72244112c2910ff67
This commit is contained in:
parent
eba1476389
commit
e4e21ee1b2
@ -206,6 +206,7 @@
|
||||
./service/lwip minix-base
|
||||
./service/memory minix-base
|
||||
./service/mfs minix-base
|
||||
./service/mib minix-base
|
||||
./service/pfs minix-base
|
||||
./service/pm minix-base
|
||||
./service/procfs minix-base
|
||||
|
@ -1237,6 +1237,7 @@
|
||||
./usr/include/minix/sound.h minix-comp
|
||||
./usr/include/minix/spin.h minix-comp
|
||||
./usr/include/minix/sys_config.h minix-comp
|
||||
./usr/include/minix/sysctl.h minix-comp
|
||||
./usr/include/minix/sysinfo.h minix-comp
|
||||
./usr/include/minix/syslib.h minix-comp
|
||||
./usr/include/minix/sysutil.h minix-comp
|
||||
|
@ -17,10 +17,11 @@
|
||||
./boot/minix/.temp/mod05_vfs minix-kernel
|
||||
./boot/minix/.temp/mod06_memory minix-kernel
|
||||
./boot/minix/.temp/mod07_tty minix-kernel
|
||||
./boot/minix/.temp/mod08_mfs minix-kernel
|
||||
./boot/minix/.temp/mod08_mib minix-kernel
|
||||
./boot/minix/.temp/mod09_vm minix-kernel
|
||||
./boot/minix/.temp/mod10_pfs minix-kernel
|
||||
./boot/minix/.temp/mod11_init minix-kernel
|
||||
./boot/minix/.temp/mod11_mfs minix-kernel
|
||||
./boot/minix/.temp/mod12_init minix-kernel
|
||||
./etc minix-kernel
|
||||
./etc/mtree minix-kernel
|
||||
./etc/mtree/set.minix-kernel minix-kernel
|
||||
|
@ -186,6 +186,7 @@
|
||||
./usr/tests/minix-posix/test84 minix-tests
|
||||
./usr/tests/minix-posix/test85 minix-tests
|
||||
./usr/tests/minix-posix/test86 minix-tests
|
||||
./usr/tests/minix-posix/test87 minix-tests
|
||||
./usr/tests/minix-posix/test9 minix-tests
|
||||
./usr/tests/minix-posix/testinterp minix-tests
|
||||
./usr/tests/minix-posix/testisofs minix-tests
|
||||
|
1
etc/rc
1
etc/rc
@ -157,6 +157,7 @@ autoboot|start)
|
||||
edit ds
|
||||
edit tty
|
||||
edit memory
|
||||
edit mib
|
||||
edit pfs
|
||||
edit init
|
||||
#
|
||||
|
@ -216,6 +216,15 @@ service log
|
||||
priority 2;
|
||||
};
|
||||
|
||||
service mib
|
||||
{
|
||||
system
|
||||
VIRCOPY # 15
|
||||
;
|
||||
ipc ALL;
|
||||
uid 0;
|
||||
};
|
||||
|
||||
service init
|
||||
{
|
||||
uid 0;
|
||||
|
@ -21,8 +21,7 @@ SRCS+= _errno.c
|
||||
.if defined(__MINIX)
|
||||
# Unsupported by Minix.
|
||||
# closefrom.c confstr.c extattr.c getdevmajor.c \
|
||||
# pthread_atfork.c \
|
||||
# sysctlbyname.c sysctlgetmibinfo.c sysctlnametomib.c
|
||||
# pthread_atfork.c
|
||||
#
|
||||
# To be ported
|
||||
# nlist.c nlist_aout.c nlist_coff.c nlist_ecoff.c nlist_elf32.c nlist_elf64.c
|
||||
@ -30,7 +29,7 @@ SRCS+= _errno.c
|
||||
# Not useful but portable
|
||||
# disklabel.c
|
||||
|
||||
SRCS+= alarm.c alphasort.c arc4random.c assert.c \
|
||||
SRCS+= alarm.c alphasort.c arc4random.c assert.c asysctl.c \
|
||||
basename.c clock.c closedir.c \
|
||||
ctermid.c ctype_.c daemon.c \
|
||||
dehumanize_number.c devname.c dirname.c err.c errx.c \
|
||||
@ -53,8 +52,8 @@ SRCS+= alarm.c alphasort.c arc4random.c assert.c \
|
||||
shquote.c shquotev.c sighold.c sigignore.c siginterrupt.c \
|
||||
siglist.c signal.c signame.c sigrelse.c \
|
||||
sigset.c sigsetops.c sleep.c \
|
||||
stringlist.c sysconf.c sysctl.c \
|
||||
syslog.c telldir.c time.c \
|
||||
stringlist.c sysconf.c sysctl.c sysctlbyname.c sysctlgetmibinfo.c \
|
||||
sysctlnametomib.c syslog.c telldir.c time.c \
|
||||
times.c toascii.c tolower_.c ttyname.c ttyslot.c toupper_.c ualarm.c \
|
||||
ulimit.c uname.c unvis.c usleep.c utime.c utimens.c utmp.c \
|
||||
utmpx.c valloc.c vis.c wait.c wait3.c waitpid.c warn.c warnx.c \
|
||||
|
@ -69,16 +69,6 @@ static size_t __cvt_node_out(uint, const struct sysctlnode *, void **,
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__minix)
|
||||
int __sysctl(const int *name, unsigned int namelen,
|
||||
void *oldp, size_t *oldlenp,
|
||||
const void *newp, size_t newlen)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
#endif /* defined(__minix) */
|
||||
|
||||
int
|
||||
sysctl(const int *name, unsigned int namelen,
|
||||
void *oldp, size_t *oldlenp,
|
||||
|
@ -127,6 +127,7 @@ service_get_policies(struct policies * pol, index_t slot)
|
||||
{ .label = "input", .policy_str = "reset" },
|
||||
{ .label = "ipc", .policy_str = "restart" },
|
||||
{ .label = "is", .policy_str = "restart" },
|
||||
{ .label = "mib", .policy_str = "restart" },
|
||||
{ .label = "pm", .policy_str = "restart" },
|
||||
{ .label = "rs", .policy_str = "restart" },
|
||||
{ .label = "sched", .policy_str = "restart" },
|
||||
|
@ -17,7 +17,7 @@ INCS+= acpi.h audio_fw.h bitmap.h \
|
||||
netdriver.h optset.h padconf.h partition.h portio.h \
|
||||
priv.h procfs.h profile.h queryparam.h \
|
||||
rs.h safecopies.h sched.h sef.h sffs.h \
|
||||
sound.h spin.h sys_config.h sysinfo.h \
|
||||
sound.h spin.h sys_config.h sysctl.h sysinfo.h \
|
||||
syslib.h sysutil.h timers.h type.h \
|
||||
u64.h usb.h usb_ch9.h vbox.h \
|
||||
vboxfs.h vboxif.h vboxtype.h vm.h \
|
||||
|
@ -29,6 +29,7 @@
|
||||
* 0x1500 - 0x15FF Input server messages
|
||||
* 0x1600 - 0x16FF VirtualBox (VBOX) requests (see vboxif.h)
|
||||
* 0x1700 - 0x17FF PTYFS requests
|
||||
* 0x1800 - 0x18FF Management Information Base (MIB) requests
|
||||
*
|
||||
* Zero and negative values are widely used for OK and error responses.
|
||||
*/
|
||||
@ -60,10 +61,11 @@
|
||||
#define SCHED_PROC_NR ((endpoint_t) 4) /* scheduler */
|
||||
#define TTY_PROC_NR ((endpoint_t) 5) /* terminal (TTY) driver */
|
||||
#define DS_PROC_NR ((endpoint_t) 6) /* data store server */
|
||||
#define MFS_PROC_NR ((endpoint_t) 7) /* minix root filesystem */
|
||||
#define MIB_PROC_NR ((endpoint_t) 7) /* management info base service */
|
||||
#define VM_PROC_NR ((endpoint_t) 8) /* memory server */
|
||||
#define PFS_PROC_NR ((endpoint_t) 9) /* pipe filesystem */
|
||||
#define LAST_SPECIAL_PROC_NR 10 /* An untyped version for
|
||||
#define MFS_PROC_NR ((endpoint_t) 10) /* minix root filesystem */
|
||||
#define LAST_SPECIAL_PROC_NR 11 /* An untyped version for
|
||||
computation in macros.*/
|
||||
#define INIT_PROC_NR ((endpoint_t) LAST_SPECIAL_PROC_NR) /* init
|
||||
-- goes multiuser */
|
||||
@ -1002,6 +1004,18 @@
|
||||
#define RTCDEV_Y2KBUG 0x01 /* Interpret 1980 as 2000 for RTC w/Y2K bug */
|
||||
#define RTCDEV_CMOSREG 0x02 /* Also set the CMOS clock register bits. */
|
||||
|
||||
/*===========================================================================*
|
||||
* Calls to MIB *
|
||||
*===========================================================================*/
|
||||
|
||||
#define MIB_BASE 0x1800
|
||||
|
||||
#define IS_MIB_CALL(type) (((type) & ~0xff) == MIB_BASE)
|
||||
|
||||
#define MIB_SYSCTL (MIB_BASE + 0) /* sysctl(2) */
|
||||
|
||||
#define NR_MIB_CALLS 1 /* highest number from base plus one */
|
||||
|
||||
/*===========================================================================*
|
||||
* Internal codes used by several services *
|
||||
*===========================================================================*/
|
||||
|
@ -12,6 +12,7 @@
|
||||
*==========================================================================*/
|
||||
|
||||
#define M_PATH_STRING_MAX 40
|
||||
#define CTL_SHORTNAME 8 /* max sysctl(2) name length that fits in message */
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[56];
|
||||
@ -420,6 +421,17 @@ typedef struct {
|
||||
} mess_lc_ipc_shmget;
|
||||
_ASSERT_MSG_SIZE(mess_lc_ipc_shmget);
|
||||
|
||||
typedef struct {
|
||||
vir_bytes oldp;
|
||||
size_t oldlen;
|
||||
vir_bytes newp;
|
||||
size_t newlen;
|
||||
unsigned int namelen;
|
||||
vir_bytes namep;
|
||||
int name[CTL_SHORTNAME];
|
||||
} mess_lc_mib_sysctl;
|
||||
_ASSERT_MSG_SIZE(mess_lc_mib_sysctl);
|
||||
|
||||
typedef struct {
|
||||
vir_bytes name;
|
||||
size_t namelen;
|
||||
@ -1396,6 +1408,12 @@ typedef struct {
|
||||
} mess_lsys_vm_watch_exit;
|
||||
_ASSERT_MSG_SIZE(mess_lsys_vm_watch_exit);
|
||||
|
||||
typedef struct {
|
||||
size_t oldlen;
|
||||
uint8_t padding[52];
|
||||
} mess_mib_lc_sysctl;
|
||||
_ASSERT_MSG_SIZE(mess_mib_lc_sysctl);
|
||||
|
||||
typedef struct {
|
||||
off_t offset;
|
||||
void *addr;
|
||||
@ -2074,6 +2092,7 @@ typedef struct noxfer_message {
|
||||
mess_lc_ipc_shmctl m_lc_ipc_shmctl;
|
||||
mess_lc_ipc_shmdt m_lc_ipc_shmdt;
|
||||
mess_lc_ipc_shmget m_lc_ipc_shmget;
|
||||
mess_lc_mib_sysctl m_lc_mib_sysctl;
|
||||
mess_lc_pm_exec m_lc_pm_exec;
|
||||
mess_lc_pm_exit m_lc_pm_exit;
|
||||
mess_lc_pm_getsid m_lc_pm_getsid;
|
||||
@ -2182,6 +2201,7 @@ typedef struct noxfer_message {
|
||||
mess_lsys_vm_update m_lsys_vm_update;
|
||||
mess_lsys_vm_vmremap m_lsys_vm_vmremap;
|
||||
mess_lsys_vm_watch_exit m_lsys_vm_watch_exit;
|
||||
mess_mib_lc_sysctl m_mib_lc_sysctl;
|
||||
mess_mmap m_mmap;
|
||||
mess_net_netdrv_dl_conf m_net_netdrv_dl_conf;
|
||||
mess_net_netdrv_dl_getstat_s m_net_netdrv_dl_getstat_s;
|
||||
|
53
minix/include/minix/sysctl.h
Normal file
53
minix/include/minix/sysctl.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef _MINIX_SYSCTL_H
|
||||
#define _MINIX_SYSCTL_H
|
||||
|
||||
/* MINIX3-specific sysctl(2) extensions. */
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
/* Special values. */
|
||||
#define SYSCTL_NODE_FN ((sysctlfn)0x1) /* node is function-driven */
|
||||
|
||||
/*
|
||||
* The top-level MINIX3 identifier is quite a bit beyond the last top-level
|
||||
* identifier in use by NetBSD, because NetBSD may add more later, and we do
|
||||
* not want conflicts: this definition is part of the MINIX3 ABI.
|
||||
*/
|
||||
#define CTL_MINIX 32
|
||||
|
||||
#if CTL_MAXID > CTL_MINIX
|
||||
#error "CTL_MAXID has grown too large!"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The identifiers below follow the standard sysctl naming scheme, which means
|
||||
* care should be taken not to introduce clashes with other definitions
|
||||
* elsewhere. On the upside, not many places need to include this header file.
|
||||
*/
|
||||
#define MINIX_TEST 0
|
||||
#define MINIX_MIB 1
|
||||
|
||||
/*
|
||||
* These identifiers, under MINIX_TEST, are used by test87 to test the MIB
|
||||
* service.
|
||||
*/
|
||||
#define TEST_INT 0
|
||||
#define TEST_BOOL 1
|
||||
#define TEST_QUAD 2
|
||||
#define TEST_STRING 3
|
||||
#define TEST_STRUCT 4
|
||||
#define TEST_PRIVATE 5
|
||||
#define TEST_ANYWRITE 6
|
||||
#define TEST_DYNAMIC 7
|
||||
#define TEST_SECRET 8
|
||||
#define TEST_PERM 9
|
||||
#define TEST_DESTROY1 10
|
||||
#define TEST_DESTROY2 11
|
||||
|
||||
#define SECRET_VALUE 0
|
||||
|
||||
/* Identifiers for subnodes of MINIX_MIB. */
|
||||
#define MIB_NODES 1
|
||||
#define MIB_OBJECTS 2
|
||||
|
||||
#endif /* !_MINIX_SYSCTL_H */
|
@ -43,7 +43,7 @@
|
||||
*/
|
||||
|
||||
struct boot_image image[NR_BOOT_PROCS] = {
|
||||
/* process nr, flags, stack size, name */
|
||||
/* process nr, name */
|
||||
{ASYNCM, "asyncm"},
|
||||
{IDLE, "idle" },
|
||||
{CLOCK, "clock" },
|
||||
@ -58,9 +58,10 @@ struct boot_image image[NR_BOOT_PROCS] = {
|
||||
{VFS_PROC_NR, "vfs" },
|
||||
{MEM_PROC_NR, "memory"},
|
||||
{TTY_PROC_NR, "tty" },
|
||||
{MFS_PROC_NR, "mfs" },
|
||||
{MIB_PROC_NR, "mib" },
|
||||
{VM_PROC_NR, "vm" },
|
||||
{PFS_PROC_NR, "pfs" },
|
||||
{MFS_PROC_NR, "mfs" },
|
||||
{INIT_PROC_NR, "init" },
|
||||
};
|
||||
|
||||
|
@ -23,7 +23,7 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
|
||||
wait4.c write.c \
|
||||
utimensat.c utimes.c futimes.c lutimes.c futimens.c \
|
||||
_exit.c _ucontext.c environ.c __getcwd.c vfork.c sizeup.c init.c \
|
||||
getrusage.c setrlimit.c setpgid.c
|
||||
getrusage.c setrlimit.c setpgid.c __sysctl.c
|
||||
|
||||
# Minix specific syscalls / utils.
|
||||
SRCS+= kernel_utils.c sprofile.c stack_utils.c _mcontext.c
|
||||
|
40
minix/lib/libc/sys/__sysctl.c
Normal file
40
minix/lib/libc/sys/__sysctl.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include <sys/cdefs.h>
|
||||
#include <lib.h>
|
||||
#include "namespace.h"
|
||||
#include "extern.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* The sysctl(2) system call, handled by the MIB service.
|
||||
*/
|
||||
int
|
||||
__sysctl(const int * name, unsigned int namelen, void * oldp, size_t * oldlenp,
|
||||
const void * newp, size_t newlen)
|
||||
{
|
||||
message m;
|
||||
int r;
|
||||
|
||||
memset(&m, 0, sizeof(m));
|
||||
m.m_lc_mib_sysctl.oldp = (vir_bytes)oldp;
|
||||
m.m_lc_mib_sysctl.oldlen = (oldlenp != NULL) ? *oldlenp : 0;
|
||||
m.m_lc_mib_sysctl.newp = (vir_bytes)newp;
|
||||
m.m_lc_mib_sysctl.newlen = newlen;
|
||||
m.m_lc_mib_sysctl.namelen = namelen;
|
||||
m.m_lc_mib_sysctl.namep = (vir_bytes)name;
|
||||
if (namelen <= CTL_SHORTNAME)
|
||||
memcpy(m.m_lc_mib_sysctl.name, name, sizeof(*name) * namelen);
|
||||
|
||||
r = _syscall(MIB_PROC_NR, MIB_SYSCTL, &m);
|
||||
|
||||
/*
|
||||
* We copy the NetBSD behavior of replying with the old length also if
|
||||
* the call failed, typically with ENOMEM. This is undocumented
|
||||
* behavior, but unfortunately relied on by sysctl(8) and other NetBSD
|
||||
* userland code. If the call failed at the IPC level, the resulting
|
||||
* value will be garbage, but it should then not be used anyway.
|
||||
*/
|
||||
if (oldlenp != NULL)
|
||||
*oldlenp = m.m_mib_lc_sysctl.oldlen;
|
||||
|
||||
return r;
|
||||
}
|
@ -270,6 +270,17 @@ CPPFLAGS.malloc.c+= -D_LIBSYS
|
||||
SECTIONIFY.malloc.c+= -sectionify-no-override \
|
||||
-sectionify-data-section-map=.*/magic_malloc_data
|
||||
|
||||
.for f in \
|
||||
strdup.o
|
||||
${f} ${f:C/\.o/.bc/}: ${LIBCDIR}/string/${f:C/\.o/.c/}
|
||||
OBJS+= ${f}
|
||||
CLEANFILES+= ${f}
|
||||
|
||||
.if ${USE_BITCODE:Uno} == "yes"
|
||||
OBJS+= ${f:C/\.o/.bc/}
|
||||
CLEANFILES+= ${f:C/\.o/.bc/}
|
||||
.endif # ${USE_BITCODE:Uno} == "yes"
|
||||
.endfor
|
||||
|
||||
.for f in \
|
||||
access.o brk.o close.o environ.o execve.o fork.o fsync.o \
|
||||
|
@ -1,6 +1,6 @@
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR+= ds input pm rs sched vfs vm
|
||||
SUBDIR+= ds input mib pm rs sched vfs vm
|
||||
|
||||
.if ${MKIMAGEONLY} == "no"
|
||||
SUBDIR+= ipc is devman
|
||||
|
11
minix/servers/mib/Makefile
Normal file
11
minix/servers/mib/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# Makefile for the Management Information Base (MIB) server
|
||||
|
||||
PROG= mib
|
||||
SRCS= main.c tree.c kern.c minix.c
|
||||
|
||||
DPADD+= ${LIBSYS}
|
||||
LDADD+= -lsys
|
||||
|
||||
WARNS?= 5
|
||||
|
||||
.include <minix.service.mk>
|
19
minix/servers/mib/kern.c
Normal file
19
minix/servers/mib/kern.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* MIB service - kern.c - implementation of the CTL_KERN subtree */
|
||||
|
||||
#include "mib.h"
|
||||
|
||||
static struct mib_node mib_kern_table[] = {
|
||||
/* 8*/ [KERN_ARGMAX] = MIB_INT(_P | _RO, ARG_MAX, "argmax",
|
||||
"Maximum number of bytes of arguments to "
|
||||
"execve(2)"),
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the CTL_KERN subtree.
|
||||
*/
|
||||
void
|
||||
mib_kern_init(struct mib_node * node)
|
||||
{
|
||||
|
||||
MIB_INIT_ENODE(node, mib_kern_table);
|
||||
}
|
401
minix/servers/mib/main.c
Normal file
401
minix/servers/mib/main.c
Normal file
@ -0,0 +1,401 @@
|
||||
/* MIB service - main.c - request abstraction and first-level tree */
|
||||
/*
|
||||
* This is the Management Information Base (MIB) service. Its one and only
|
||||
* task is to implement the sysctl(2) system call, which plays a fairly
|
||||
* important role in parts of *BSD userland.
|
||||
*
|
||||
* The sysctl(2) interface is used to access a variety of information. In
|
||||
* order to obtain that information, and possibly modify it, the MIB service
|
||||
* calls into many other services. The MIB service must therefore not be
|
||||
* called directly from other services, with the exception of ProcFS. In fact,
|
||||
* ProcFS is currently the only service that is modeled as logically higher in
|
||||
* the MINIX3 service stack than MIB, something that itself is possible only
|
||||
* due to the nonblocking nature of VFS. MIB may issue blocking calls to VFS.
|
||||
*
|
||||
* The MIB service is in the boot image because even init(8) makes use of
|
||||
* sysctl(2) during its own startup, so launching the MIB service at any later
|
||||
* time would make a proper implementation of sysctl(2) impossible. Also, the
|
||||
* service needs superuser privileges because it may need to issue privileged
|
||||
* calls and obtain privileged information from other services.
|
||||
*
|
||||
* The MIB service was created by David van Moolenbroek <david@minix3.org>.
|
||||
*/
|
||||
|
||||
#include "mib.h"
|
||||
|
||||
/*
|
||||
* Most of these initially empty nodes are filled in by their corresponding
|
||||
* modules' _init calls; see mib_init below. However, CTL_USER stays empty:
|
||||
* the libc sysctl(3) wrapper code takes care of that subtree. It must have
|
||||
* an entry here though, or sysctl(8) will not list it. CTL_VENDOR is also
|
||||
* empty, but writable, so that it may be used by third parties.
|
||||
*/
|
||||
static struct mib_node mib_table[] = {
|
||||
/* 1*/ [CTL_KERN] = MIB_ENODE(_P | _RO, "kern", "High kernel"),
|
||||
/* 8*/ [CTL_USER] = MIB_ENODE(_P | _RO, "user", "User-level"),
|
||||
/*11*/ [CTL_VENDOR] = MIB_ENODE(_P | _RW, "vendor", "Vendor specific"),
|
||||
/*32*/ [CTL_MINIX] = MIB_ENODE(_P | _RO, "minix", "MINIX3 specific"),
|
||||
};
|
||||
|
||||
/*
|
||||
* The root node of the tree. The root node is used internally only--it is
|
||||
* impossible to access the root node itself from userland in any way. The
|
||||
* node is writable by default, so that programs such as init(8) may create
|
||||
* their own top-level entries.
|
||||
*/
|
||||
static struct mib_node mib_root = MIB_NODE(_RW, mib_table, "", "");
|
||||
|
||||
/*
|
||||
* Structures describing old and new data as provided by userland. The primary
|
||||
* advantage of these opaque structures is that we could in principle use them
|
||||
* to implement storage of small data results in the sysctl reply message, so
|
||||
* as to avoid the kernel copy, without changing any of the handler code.
|
||||
*/
|
||||
struct mib_oldp {
|
||||
endpoint_t oldp_endpt;
|
||||
vir_bytes oldp_addr;
|
||||
size_t oldp_len;
|
||||
};
|
||||
/*
|
||||
* Same structure, different type: prevent accidental mixups, and avoid the
|
||||
* need to use __restrict everywhere.
|
||||
*/
|
||||
struct mib_newp {
|
||||
endpoint_t newp_endpt;
|
||||
vir_bytes newp_addr;
|
||||
size_t newp_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Return TRUE or FALSE indicating whether the given offset is within the range
|
||||
* of data that is to be copied out. This call can be used to test whether
|
||||
* certain bits of data need to be prepared for copying at all.
|
||||
*/
|
||||
int
|
||||
mib_inrange(struct mib_oldp * oldp, size_t off)
|
||||
{
|
||||
|
||||
if (oldp == NULL)
|
||||
return FALSE;
|
||||
|
||||
return (off < oldp->oldp_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the total length of the requested data. This should not be used
|
||||
* directly except in highly unusual cases, such as particular node requests
|
||||
* where the request semantics blatantly violate overall sysctl(2) semantics.
|
||||
*/
|
||||
size_t
|
||||
mib_getoldlen(struct mib_oldp * oldp)
|
||||
{
|
||||
|
||||
if (oldp == NULL)
|
||||
return 0;
|
||||
|
||||
return oldp->oldp_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy out (partial) data to the user. The copy is automatically limited to
|
||||
* the range of data requested by the user. Return the requested length on
|
||||
* success (for the caller's convenience) or an error code on failure.
|
||||
*/
|
||||
ssize_t
|
||||
mib_copyout(struct mib_oldp * __restrict oldp, size_t off,
|
||||
const void * __restrict buf, size_t size)
|
||||
{
|
||||
size_t len;
|
||||
int r;
|
||||
|
||||
len = size;
|
||||
assert(len <= SSIZE_MAX);
|
||||
|
||||
if (oldp == NULL || off >= oldp->oldp_len)
|
||||
return size; /* nothing to do */
|
||||
|
||||
if (len > oldp->oldp_len - off)
|
||||
len = oldp->oldp_len - off;
|
||||
|
||||
if ((r = sys_datacopy(SELF, (vir_bytes)buf, oldp->oldp_endpt,
|
||||
oldp->oldp_addr + off, len)) != OK)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Override the oldlen value returned from the call, in situations where an
|
||||
* error is thrown as well.
|
||||
*/
|
||||
void
|
||||
mib_setoldlen(struct mib_call * call, size_t oldlen)
|
||||
{
|
||||
|
||||
call->call_reslen = oldlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the new data length as provided by the user, or 0 if the user did not
|
||||
* supply new data.
|
||||
*/
|
||||
size_t
|
||||
mib_getnewlen(struct mib_newp * newp)
|
||||
{
|
||||
|
||||
if (newp == NULL)
|
||||
return 0;
|
||||
|
||||
return newp->newp_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in data from the user. The given length must match exactly the length
|
||||
* given by the user. Return OK or an error code.
|
||||
*/
|
||||
int
|
||||
mib_copyin(struct mib_newp * __restrict newp, void * __restrict buf,
|
||||
size_t len)
|
||||
{
|
||||
|
||||
if (newp == NULL || len != newp->newp_len)
|
||||
return EINVAL;
|
||||
|
||||
if (len == 0)
|
||||
return OK;
|
||||
|
||||
return sys_datacopy(newp->newp_endpt, newp->newp_addr, SELF,
|
||||
(vir_bytes)buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in auxiliary data from the user, based on a user pointer obtained from
|
||||
* data copied in earlier through mib_copyin().
|
||||
*/
|
||||
int
|
||||
mib_copyin_aux(struct mib_newp * __restrict newp, vir_bytes addr,
|
||||
void * __restrict buf, size_t len)
|
||||
{
|
||||
|
||||
assert(newp != NULL);
|
||||
|
||||
if (len == 0)
|
||||
return OK;
|
||||
|
||||
return sys_datacopy(newp->newp_endpt, addr, SELF, (vir_bytes)buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the user is allowed to perform privileged operations. The
|
||||
* function returns a nonzero value if this is the case, and zero otherwise.
|
||||
* Authorization is performed only once per call.
|
||||
*/
|
||||
int
|
||||
mib_authed(struct mib_call * call)
|
||||
{
|
||||
|
||||
if ((call->call_flags & (MIB_FLAG_AUTH | MIB_FLAG_NOAUTH)) == 0) {
|
||||
/* Ask PM if this endpoint has superuser privileges. */
|
||||
if (getnuid(call->call_endpt) == SUPER_USER)
|
||||
call->call_flags |= MIB_FLAG_AUTH;
|
||||
else
|
||||
call->call_flags |= MIB_FLAG_NOAUTH;
|
||||
}
|
||||
|
||||
return (call->call_flags & MIB_FLAG_AUTH);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the sysctl(2) system call.
|
||||
*/
|
||||
static int
|
||||
mib_sysctl(message * __restrict m_in, message * __restrict m_out)
|
||||
{
|
||||
vir_bytes oldaddr, newaddr;
|
||||
size_t oldlen, newlen;
|
||||
unsigned int namelen;
|
||||
int s, name[CTL_MAXNAME];
|
||||
endpoint_t endpt;
|
||||
struct mib_oldp oldp, *oldpp;
|
||||
struct mib_newp newp, *newpp;
|
||||
struct mib_call call;
|
||||
ssize_t r;
|
||||
|
||||
endpt = m_in->m_source;
|
||||
oldaddr = m_in->m_lc_mib_sysctl.oldp;
|
||||
oldlen = m_in->m_lc_mib_sysctl.oldlen;
|
||||
newaddr = m_in->m_lc_mib_sysctl.newp;
|
||||
newlen = m_in->m_lc_mib_sysctl.newlen;
|
||||
namelen = m_in->m_lc_mib_sysctl.namelen;
|
||||
|
||||
if (namelen == 0 || namelen > CTL_MAXNAME)
|
||||
return EINVAL;
|
||||
|
||||
/*
|
||||
* In most cases, the entire name fits in the request message, so we
|
||||
* can avoid a kernel copy.
|
||||
*/
|
||||
if (namelen > CTL_SHORTNAME) {
|
||||
if ((s = sys_datacopy(endpt, m_in->m_lc_mib_sysctl.namep, SELF,
|
||||
(vir_bytes)&name, sizeof(name[0]) * namelen)) != OK)
|
||||
return s;
|
||||
} else
|
||||
memcpy(name, m_in->m_lc_mib_sysctl.name,
|
||||
sizeof(name[0]) * namelen);
|
||||
|
||||
/*
|
||||
* Set up a structure for the old data, if any. When no old address is
|
||||
* given, be forgiving if oldlen is not zero, as the user may simply
|
||||
* not have initialized the variable before passing a pointer to it.
|
||||
*/
|
||||
if (oldaddr != 0) {
|
||||
oldp.oldp_endpt = endpt;
|
||||
oldp.oldp_addr = oldaddr;
|
||||
oldp.oldp_len = oldlen;
|
||||
oldpp = &oldp;
|
||||
} else
|
||||
oldpp = NULL;
|
||||
|
||||
/*
|
||||
* Set up a structure for the new data, if any. If one of newaddr and
|
||||
* newlen is zero but not the other, we (like NetBSD) disregard both.
|
||||
*/
|
||||
if (newaddr != 0 && newlen != 0) {
|
||||
newp.newp_endpt = endpt;
|
||||
newp.newp_addr = newaddr;
|
||||
newp.newp_len = newlen;
|
||||
newpp = &newp;
|
||||
} else
|
||||
newpp = NULL;
|
||||
|
||||
/*
|
||||
* Set up a structure for other call parameters. Most of these should
|
||||
* be used rarely, and we may want to add more later, so do not pass
|
||||
* all of them around as actual function parameters all the time.
|
||||
*/
|
||||
call.call_endpt = endpt;
|
||||
call.call_name = name;
|
||||
call.call_namelen = namelen;
|
||||
call.call_flags = 0;
|
||||
call.call_reslen = 0;
|
||||
|
||||
r = mib_dispatch(&call, &mib_root, oldpp, newpp);
|
||||
|
||||
/*
|
||||
* From NetBSD: we copy out as much as we can from the old data, while
|
||||
* at the same time computing the full data length. Then, here at the
|
||||
* end, if the entire result did not fit in the destination buffer, we
|
||||
* return ENOMEM instead of success, thus also returning a partial
|
||||
* result and the full data length.
|
||||
*
|
||||
* It is also possible that data are copied out along with a "real"
|
||||
* error. In that case, we must report a nonzero resulting length
|
||||
* along with that error code. This is currently the case when node
|
||||
* creation resulted in a collision, in which case the error code is
|
||||
* EEXIST while the existing node is copied out as well.
|
||||
*/
|
||||
if (r >= 0) {
|
||||
m_out->m_mib_lc_sysctl.oldlen = (size_t)r;
|
||||
|
||||
if (oldaddr != 0 && oldlen < (size_t)r)
|
||||
r = ENOMEM;
|
||||
else
|
||||
r = OK;
|
||||
} else
|
||||
m_out->m_mib_lc_sysctl.oldlen = call.call_reslen;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the service.
|
||||
*/
|
||||
static int
|
||||
mib_init(int type __unused, sef_init_info_t * info __unused)
|
||||
{
|
||||
|
||||
/*
|
||||
* Initialize pointers and sizes of subtrees in different modules.
|
||||
* This is needed because we cannot use sizeof on external arrays.
|
||||
* We do initialize the node entry (including any other fields)
|
||||
* statically through MIB_ENODE because that forces the array to be
|
||||
* large enough to store the entry.
|
||||
*/
|
||||
mib_kern_init(&mib_table[CTL_KERN]);
|
||||
mib_minix_init(&mib_table[CTL_MINIX]);
|
||||
|
||||
/*
|
||||
* Now that the static tree is complete, go through the entire tree,
|
||||
* initializing miscellaneous fields.
|
||||
*/
|
||||
mib_tree_init(&mib_root);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform SEF startup.
|
||||
*/
|
||||
static void
|
||||
mib_startup(void)
|
||||
{
|
||||
|
||||
sef_setcb_init_fresh(mib_init);
|
||||
/*
|
||||
* If we restart we lose all dynamic state, which means we lose all
|
||||
* nodes that have been created at run time. However, running with
|
||||
* only the static node tree is still better than not running at all.
|
||||
*/
|
||||
sef_setcb_init_restart(mib_init);
|
||||
|
||||
sef_startup();
|
||||
}
|
||||
|
||||
/*
|
||||
* The Management Information Base (MIB) service.
|
||||
*/
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
message m_in, m_out;
|
||||
int r, ipc_status;
|
||||
|
||||
/* Perform initialization. */
|
||||
mib_startup();
|
||||
|
||||
/* The main message loop. */
|
||||
for (;;) {
|
||||
/* Receive a request. */
|
||||
if ((r = sef_receive_status(ANY, &m_in, &ipc_status)) != OK)
|
||||
panic("sef_receive failed: %d", r);
|
||||
|
||||
/* Process the request. */
|
||||
if (is_ipc_notify(ipc_status)) {
|
||||
/* We are not expecting any notifications. */
|
||||
printf("MIB: notification from %d\n", m_in.m_source);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&m_out, 0, sizeof(m_out));
|
||||
|
||||
switch (m_in.m_type) {
|
||||
case MIB_SYSCTL:
|
||||
r = mib_sysctl(&m_in, &m_out);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
r = ENOSYS;
|
||||
}
|
||||
|
||||
/* Send the reply. */
|
||||
m_out.m_type = r;
|
||||
|
||||
if ((r = ipc_sendnb(m_in.m_source, &m_out)) != OK)
|
||||
printf("MIB: ipc_sendnb failed (%d)\n", r);
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
268
minix/servers/mib/mib.h
Normal file
268
minix/servers/mib/mib.h
Normal file
@ -0,0 +1,268 @@
|
||||
#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>
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* subtree modules */
|
||||
void mib_kern_init(struct mib_node *);
|
||||
void mib_minix_init(struct mib_node *);
|
||||
|
||||
#endif /* !_MINIX_MIB_MIB_H */
|
73
minix/servers/mib/minix.c
Normal file
73
minix/servers/mib/minix.c
Normal file
@ -0,0 +1,73 @@
|
||||
/* MIB service - minix.c - implementation of the CTL_MINIX subtree */
|
||||
|
||||
#include "mib.h"
|
||||
|
||||
#if MINIX_TEST_SUBTREE
|
||||
|
||||
static char test_string[16], test_struct[12];
|
||||
|
||||
static struct mib_node mib_minix_test_secret_table[] = {
|
||||
/* 0*/ [SECRET_VALUE] = MIB_INT(_RO, 12345, "value",
|
||||
"The combination to my luggage"),
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that even the descriptions here have been chosen such that returned
|
||||
* description array alignment is tested. Do not change existing fields
|
||||
* lightly, although adding new fields is always fine.
|
||||
*/
|
||||
static struct mib_node mib_minix_test_table[] = {
|
||||
/* 0*/ [TEST_INT] = MIB_INT(_RO | CTLFLAG_HEX, 0x01020304, "int",
|
||||
"Value test field"),
|
||||
/* 1*/ [TEST_BOOL] = MIB_BOOL(_RW, 0, "bool",
|
||||
"Boolean test field"),
|
||||
/* 2*/ [TEST_QUAD] = MIB_QUAD(_RW, 0, "quad", "Quad test field"),
|
||||
/* 3*/ [TEST_STRING] = MIB_STRING(_RW, test_string, "string",
|
||||
"String test field"),
|
||||
/* 4*/ [TEST_STRUCT] = MIB_STRUCT(_RW, test_struct, "struct",
|
||||
"Structure test field"),
|
||||
/* 5*/ [TEST_PRIVATE] = MIB_INT(_RW | CTLFLAG_PRIVATE, -5375,
|
||||
"private", "Private test field"),
|
||||
/* 6*/ [TEST_ANYWRITE] = MIB_INT(_RW | CTLFLAG_ANYWRITE, 0,
|
||||
"anywrite", "AnyWrite test field"),
|
||||
/* 7*/ [TEST_DYNAMIC] = MIB_INT(_RO, 0, "deleteme",
|
||||
"This node will be destroyed"),
|
||||
/* 8*/ [TEST_SECRET] = MIB_NODE(_RO | CTLFLAG_PRIVATE,
|
||||
mib_minix_test_secret_table, "secret",
|
||||
"Private subtree"),
|
||||
/* 9*/ [TEST_PERM] = MIB_INT(_P | _RO, 1, "permanent", NULL),
|
||||
/*10*/ [TEST_DESTROY1] = MIB_INT(_RO, 123, "destroy1", NULL),
|
||||
/*11*/ [TEST_DESTROY2] = MIB_INT(_RO, 456, "destroy2",
|
||||
"This node will be destroyed"),
|
||||
};
|
||||
|
||||
#endif /* MINIX_TEST_SUBTREE */
|
||||
|
||||
static struct mib_node mib_minix_mib_table[] = {
|
||||
/* 1*/ [MIB_NODES] = MIB_INTPTR(_P | _RO | CTLFLAG_UNSIGNED,
|
||||
&nodes, "nodes",
|
||||
"Number of nodes in the MIB tree"),
|
||||
/* 2*/ [MIB_OBJECTS] = MIB_INTPTR(_P | _RO | CTLFLAG_UNSIGNED,
|
||||
&objects, "objects", "Number of "
|
||||
"dynamically allocated MIB objects"),
|
||||
};
|
||||
|
||||
static struct mib_node mib_minix_table[] = {
|
||||
#if MINIX_TEST_SUBTREE
|
||||
/* 0*/ [MINIX_TEST] = MIB_NODE(_RW | CTLFLAG_HIDDEN,
|
||||
mib_minix_test_table, "test",
|
||||
"Test87 testing ground"),
|
||||
#endif /* MINIX_TEST_SUBTREE */
|
||||
/* 1*/ [MINIX_MIB] = MIB_NODE(_P | _RO, mib_minix_mib_table,
|
||||
"mib", "MIB service information"),
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the CTL_MINIX subtree.
|
||||
*/
|
||||
void
|
||||
mib_minix_init(struct mib_node * node)
|
||||
{
|
||||
|
||||
MIB_INIT_ENODE(node, mib_minix_table);
|
||||
}
|
1418
minix/servers/mib/tree.c
Normal file
1418
minix/servers/mib/tree.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -22,8 +22,9 @@ struct boot_image_priv boot_image_priv_table[] = {
|
||||
{DS_PROC_NR, "ds", SRV_F },
|
||||
{TTY_PROC_NR, "tty", SRV_F },
|
||||
{MEM_PROC_NR, "memory", SRV_F },
|
||||
{MFS_PROC_NR,"fs_imgrd", SRV_F },
|
||||
{MIB_PROC_NR, "mib", SRV_F },
|
||||
{PFS_PROC_NR, "pfs", SRV_F },
|
||||
{MFS_PROC_NR,"fs_imgrd", SRV_F },
|
||||
{INIT_PROC_NR, "init", USR_F },
|
||||
{NULL_BOOT_NR, "", 0, } /* null entry */
|
||||
};
|
||||
@ -37,7 +38,6 @@ struct boot_image_sys boot_image_sys_table[] = {
|
||||
{ SCHED_PROC_NR, SRVR_SF },
|
||||
{ VFS_PROC_NR, SRVR_SF },
|
||||
{ MFS_PROC_NR, 0 },
|
||||
{ PFS_PROC_NR, SRV_SF },
|
||||
{ DEFAULT_BOOT_NR, SRV_SF } /* default entry */
|
||||
};
|
||||
|
||||
|
@ -59,7 +59,7 @@ MINIX_TESTS= \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
|
||||
61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
|
||||
81 82 83 84 85 86
|
||||
81 82 83 84 85 86 87
|
||||
|
||||
FILES += t84_h_nonexec.sh
|
||||
|
||||
|
@ -22,7 +22,7 @@ export USENETWORK # set to "yes" for test48+82 to use the network
|
||||
|
||||
# Programs that require setuid
|
||||
setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \
|
||||
test69 test73 test74 test78 test83 test85"
|
||||
test69 test73 test74 test78 test83 test85 test87"
|
||||
# Scripts that require to be run as root
|
||||
rootscripts="testisofs testvnd testrelpol"
|
||||
|
||||
@ -30,7 +30,7 @@ alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
||||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
|
||||
81 82 83 84 85 86 sh1 sh2 interp mfs isofs vnd"
|
||||
81 82 83 84 85 86 87 sh1 sh2 interp mfs isofs vnd"
|
||||
tests_no=`expr 0`
|
||||
|
||||
# If root, make sure the setuid tests have the correct permissions
|
||||
|
3657
minix/tests/test87.c
Normal file
3657
minix/tests/test87.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ PROG= trace
|
||||
SRCS= call.o error.o escape.o format.o ioctl.o kernel.o mem.o output.o \
|
||||
proc.o signal.o trace.o
|
||||
.PATH: ${.CURDIR}/service
|
||||
SRCS+= pm.o vfs.o rs.o vm.o ipc.o
|
||||
SRCS+= pm.o vfs.o rs.o mib.o vm.o ipc.o
|
||||
.PATH: ${.CURDIR}/ioctl
|
||||
SRCS+= block.o char.o net.o svrctl.o
|
||||
|
||||
|
@ -9,6 +9,7 @@ static const struct calls *call_table[] = {
|
||||
&pm_calls,
|
||||
&vfs_calls,
|
||||
&rs_calls,
|
||||
&mib_calls,
|
||||
&vm_calls,
|
||||
&ipc_calls,
|
||||
};
|
||||
@ -66,6 +67,7 @@ put_endpoint(struct trace_proc * proc, const char * name, endpoint_t endpt)
|
||||
TEXT(SCHED_PROC_NR);
|
||||
TEXT(TTY_PROC_NR);
|
||||
TEXT(DS_PROC_NR);
|
||||
TEXT(MIB_PROC_NR);
|
||||
TEXT(VM_PROC_NR);
|
||||
TEXT(PFS_PROC_NR);
|
||||
TEXT(ANY);
|
||||
@ -684,3 +686,22 @@ call_name(struct trace_proc * proc)
|
||||
|
||||
return proc->call_name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return whether the current call failed due to an error at the system call
|
||||
* level, and if so, return the error code as well. May be called during the
|
||||
* leave phase of a call only.
|
||||
*/
|
||||
int
|
||||
call_errno(struct trace_proc * proc, int * err)
|
||||
{
|
||||
|
||||
if (proc->call_flags & (CF_REG_ERR | CF_MSG_ERR | CF_IPC_ERR))
|
||||
return FALSE;
|
||||
|
||||
if (proc->call_result >= 0)
|
||||
return FALSE;
|
||||
|
||||
*err = -proc->call_result;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -53,6 +53,13 @@ struct trace_proc {
|
||||
/* ioctl state (ioctl.c) */
|
||||
int ioctl_index;
|
||||
unsigned int ioctl_flags;
|
||||
|
||||
/* sysctl state (service/mib.c) */
|
||||
uint32_t sctl_flags;
|
||||
size_t sctl_size;
|
||||
int (*sctl_proc)(struct trace_proc *, const char *, int, const void *,
|
||||
vir_bytes, size_t);
|
||||
int sctl_arg;
|
||||
};
|
||||
|
||||
/* Trace flags. */
|
||||
@ -97,3 +104,8 @@ struct trace_proc {
|
||||
#define IF_OUT 0x1 /* call to print outgoing (written) data */
|
||||
#define IF_IN 0x2 /* call to print incoming (read) data */
|
||||
#define IF_ALL 0x4 /* all fields printed (not really a bit) */
|
||||
|
||||
/* Sysctl processing types, determining what the callback function is to do. */
|
||||
#define ST_NAME 0 /* print the rest of the name */
|
||||
#define ST_OLDP 1 /* print the data pointed to by oldp */
|
||||
#define ST_NEWP 2 /* print the data pointed to by newp */
|
||||
|
@ -10,6 +10,7 @@ int call_enter(struct trace_proc *proc, int show_stack);
|
||||
void call_leave(struct trace_proc *proc, int skip);
|
||||
void call_replay(struct trace_proc *proc);
|
||||
const char *call_name(struct trace_proc *proc);
|
||||
int call_errno(struct trace_proc *proc, int *err);
|
||||
|
||||
/* error.c */
|
||||
const char *get_error_name(int err);
|
||||
@ -107,6 +108,7 @@ void put_dev(struct trace_proc *proc, const char *name, dev_t dev);
|
||||
const struct calls pm_calls;
|
||||
const struct calls vfs_calls;
|
||||
const struct calls rs_calls;
|
||||
const struct calls mib_calls;
|
||||
const struct calls vm_calls;
|
||||
const struct calls ipc_calls;
|
||||
|
||||
|
714
minix/usr.bin/trace/service/mib.c
Normal file
714
minix/usr.bin/trace/service/mib.c
Normal file
@ -0,0 +1,714 @@
|
||||
|
||||
#include "inc.h"
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
struct sysctl_tab {
|
||||
int id;
|
||||
size_t size;
|
||||
const struct sysctl_tab *tab;
|
||||
int (*proc)(struct trace_proc *, const char *, int, const void *,
|
||||
vir_bytes, size_t);
|
||||
};
|
||||
#define NODE(i,t) { .id = i, .size = __arraycount(t), .tab = t }
|
||||
#define PROC(i,s,p) { .id = i, .size = s, .proc = p }
|
||||
|
||||
/* The CTL_KERN table. */
|
||||
static const struct sysctl_tab kern_tab[] = {
|
||||
};
|
||||
|
||||
/* The top-level table, which is indexed by identifier. */
|
||||
static const struct sysctl_tab root_tab[] = {
|
||||
[CTL_KERN] = NODE(0, kern_tab),
|
||||
};
|
||||
|
||||
/*
|
||||
* This buffer should be large enough to avoid having to perform dynamic
|
||||
* allocation in all but highly exceptional cases. The CTL_KERN subtree is
|
||||
* currently the largest, so we base the buffer size on its length.
|
||||
* TODO: merge this buffer with ioctlbuf.
|
||||
*/
|
||||
static char sysctlbuf[sizeof(struct sysctlnode) * KERN_MAXID];
|
||||
|
||||
static const struct flags sysctl_flags[] = {
|
||||
FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERS_0),
|
||||
FLAG_MASK(SYSCTL_VERS_MASK, SYSCTL_VERSION),
|
||||
#define SYSCTL_VER_ENTRIES 2 /* the first N entries are for SYSCTL_VERS_MASK */
|
||||
FLAG(CTLFLAG_UNSIGNED),
|
||||
FLAG(CTLFLAG_OWNDESC),
|
||||
FLAG(CTLFLAG_MMAP),
|
||||
FLAG(CTLFLAG_ALIAS),
|
||||
FLAG(CTLFLAG_ANYNUMBER),
|
||||
FLAG(CTLFLAG_ROOT),
|
||||
FLAG(CTLFLAG_HEX),
|
||||
FLAG(CTLFLAG_IMMEDIATE),
|
||||
FLAG(CTLFLAG_OWNDATA),
|
||||
FLAG(CTLFLAG_HIDDEN),
|
||||
FLAG(CTLFLAG_PERMANENT),
|
||||
FLAG(CTLFLAG_PRIVATE),
|
||||
FLAG(CTLFLAG_ANYWRITE),
|
||||
FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READONLY),
|
||||
FLAG_MASK(CTLFLAG_READWRITE, CTLFLAG_READWRITE),
|
||||
FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_NODE),
|
||||
FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_INT),
|
||||
FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRING),
|
||||
FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_QUAD),
|
||||
FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_STRUCT),
|
||||
FLAG_MASK(SYSCTL_TYPEMASK, CTLTYPE_BOOL),
|
||||
};
|
||||
|
||||
/*
|
||||
* Print the immediate value of a sysctl node.
|
||||
*/
|
||||
static void
|
||||
put_sysctl_imm(struct trace_proc * proc, struct sysctlnode * scn, int use_name)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = NULL;
|
||||
|
||||
switch (SYSCTL_TYPE(scn->sysctl_flags)) {
|
||||
case CTLTYPE_INT:
|
||||
if (use_name)
|
||||
name = "sysctl_idata";
|
||||
if (scn->sysctl_flags & CTLFLAG_HEX)
|
||||
put_value(proc, name, "0x%x", scn->sysctl_idata);
|
||||
else if (scn->sysctl_flags & CTLFLAG_UNSIGNED)
|
||||
put_value(proc, name, "%u", scn->sysctl_idata);
|
||||
else
|
||||
put_value(proc, name, "%d", scn->sysctl_idata);
|
||||
break;
|
||||
case CTLTYPE_BOOL:
|
||||
if (use_name)
|
||||
name = "sysctl_bdata";
|
||||
put_field(proc, name, (scn->sysctl_bdata) ? "true" : "false");
|
||||
break;
|
||||
case CTLTYPE_QUAD:
|
||||
if (use_name)
|
||||
name = "sysctl_qdata";
|
||||
if (scn->sysctl_flags & CTLFLAG_HEX)
|
||||
put_value(proc, name, "0x%"PRIx64, scn->sysctl_qdata);
|
||||
else
|
||||
put_value(proc, name, "%"PRIu64, scn->sysctl_qdata);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Printer for CTL_QUERY data.
|
||||
*/
|
||||
static int
|
||||
put_sysctl_query(struct trace_proc * proc, const char * name, int type,
|
||||
const void * data __unused, vir_bytes addr, size_t size)
|
||||
{
|
||||
struct sysctlnode scn;
|
||||
|
||||
if (type == ST_NEWP) {
|
||||
if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
|
||||
return TRUE;
|
||||
|
||||
/* Print just the protocol version, that's all there is. */
|
||||
if (verbose > 1)
|
||||
put_flags(proc, "sysctl_flags", sysctl_flags,
|
||||
SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
|
||||
|
||||
put_close_struct(proc, FALSE /*all*/);
|
||||
} else {
|
||||
/* TODO: optionally dump struct sysctlnode array */
|
||||
put_open(proc, name, 0, "[", ", ");
|
||||
if (size > 0)
|
||||
put_tail(proc, size / sizeof(scn), 0);
|
||||
put_close(proc, "]");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Printer for CTL_CREATE data.
|
||||
*/
|
||||
static int
|
||||
put_sysctl_create(struct trace_proc * proc, const char * name, int type,
|
||||
const void * data __unused, vir_bytes addr, size_t size)
|
||||
{
|
||||
struct sysctlnode scn;
|
||||
|
||||
if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
|
||||
return TRUE;
|
||||
|
||||
if (type == ST_NEWP)
|
||||
put_flags(proc, "sysctl_flags", sysctl_flags,
|
||||
COUNT(sysctl_flags), "0x%x", scn.sysctl_flags);
|
||||
|
||||
if (scn.sysctl_num == CTL_CREATE && type == ST_NEWP && !valuesonly)
|
||||
put_field(proc, "sysctl_num", "CTL_CREATE");
|
||||
else
|
||||
put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
|
||||
|
||||
if (type == ST_NEWP) {
|
||||
put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
|
||||
(vir_bytes)scn.sysctl_name, sizeof(scn.sysctl_name));
|
||||
}
|
||||
if (scn.sysctl_ver != 0 && verbose > 0)
|
||||
put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
|
||||
|
||||
if (type == ST_NEWP) {
|
||||
if (scn.sysctl_flags & CTLFLAG_IMMEDIATE)
|
||||
put_sysctl_imm(proc, &scn, TRUE /*use_name*/);
|
||||
|
||||
switch (SYSCTL_TYPE(scn.sysctl_flags)) {
|
||||
case CTLTYPE_NODE:
|
||||
break;
|
||||
case CTLTYPE_STRING:
|
||||
if (scn.sysctl_data != NULL)
|
||||
put_buf(proc, "sysctl_data", PF_STRING,
|
||||
(vir_bytes)scn.sysctl_data,
|
||||
(scn.sysctl_size > 0) ? scn.sysctl_size :
|
||||
SSIZE_MAX /* hopefully it stops early */);
|
||||
if (scn.sysctl_data != NULL || verbose == 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (!(scn.sysctl_flags & CTLFLAG_IMMEDIATE) &&
|
||||
verbose > 0)
|
||||
put_ptr(proc, "sysctl_data",
|
||||
(vir_bytes)scn.sysctl_data);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_STRUCT ||
|
||||
verbose > 0)
|
||||
put_value(proc, "sysctl_size", "%zu", scn.sysctl_size);
|
||||
}
|
||||
|
||||
put_close_struct(proc, FALSE /*all*/);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Printer for CTL_DESTROY data.
|
||||
*/
|
||||
static int
|
||||
put_sysctl_destroy(struct trace_proc * proc, const char * name, int type,
|
||||
const void * data __unused, vir_bytes addr, size_t size)
|
||||
{
|
||||
struct sysctlnode scn;
|
||||
|
||||
if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
|
||||
return TRUE;
|
||||
|
||||
if (type == ST_NEWP) {
|
||||
put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
|
||||
if (scn.sysctl_name[0] != '\0')
|
||||
put_buf(proc, "sysctl_name", PF_LOCADDR | PF_STRING,
|
||||
(vir_bytes)scn.sysctl_name,
|
||||
sizeof(scn.sysctl_name));
|
||||
if (scn.sysctl_ver != 0 && verbose > 0)
|
||||
put_value(proc, "sysctl_ver", "%u", scn.sysctl_ver);
|
||||
}
|
||||
|
||||
put_close_struct(proc, FALSE /*all*/);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Printer for CTL_CREATE data.
|
||||
*/
|
||||
static int
|
||||
put_sysctl_describe(struct trace_proc * proc, const char * name, int type,
|
||||
const void * data __unused, vir_bytes addr, size_t size)
|
||||
{
|
||||
struct sysctlnode scn;
|
||||
|
||||
if (type == ST_NEWP) {
|
||||
if (!put_open_struct(proc, name, 0, addr, &scn, sizeof(scn)))
|
||||
return TRUE;
|
||||
|
||||
/* Print just the protocol version, that's all there is. */
|
||||
if (verbose > 1)
|
||||
put_flags(proc, "sysctl_flags", sysctl_flags,
|
||||
SYSCTL_VER_ENTRIES, "0x%x", scn.sysctl_flags);
|
||||
|
||||
put_value(proc, "sysctl_num", "%d", scn.sysctl_num);
|
||||
|
||||
if (scn.sysctl_desc != NULL)
|
||||
put_buf(proc, "sysctl_desc", PF_STRING,
|
||||
(vir_bytes)scn.sysctl_desc, 1024 /*no constant!*/);
|
||||
else if (verbose > 0)
|
||||
put_ptr(proc, "sysctl_desc",
|
||||
(vir_bytes)scn.sysctl_desc);
|
||||
|
||||
put_close_struct(proc, FALSE /*all*/);
|
||||
} else {
|
||||
/* TODO: optionally dump struct sysctldesc array */
|
||||
put_field(proc, name, (size == 0) ? "[]" : "[..]");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Printer for generic data, using the node flags stored in proc->sysctl_flags.
|
||||
*/
|
||||
static int
|
||||
put_sysctl_generic(struct trace_proc * proc, const char * name, int type,
|
||||
const void * data __unused, vir_bytes addr, size_t size)
|
||||
{
|
||||
struct sysctlnode scn;
|
||||
void *ptr;
|
||||
int i;
|
||||
bool b;
|
||||
u_quad_t q;
|
||||
size_t len;
|
||||
|
||||
switch (SYSCTL_TYPE(proc->sctl_flags)) {
|
||||
case CTLTYPE_STRING:
|
||||
put_buf(proc, name, PF_STRING, addr, size);
|
||||
return TRUE;
|
||||
case CTLTYPE_INT:
|
||||
ptr = &scn.sysctl_idata;
|
||||
len = sizeof(scn.sysctl_idata);
|
||||
break;
|
||||
case CTLTYPE_BOOL:
|
||||
ptr = &scn.sysctl_bdata;
|
||||
len = sizeof(scn.sysctl_bdata);
|
||||
break;
|
||||
case CTLTYPE_QUAD:
|
||||
ptr = &scn.sysctl_qdata;
|
||||
len = sizeof(scn.sysctl_qdata);
|
||||
break;
|
||||
case CTLTYPE_STRUCT:
|
||||
default:
|
||||
ptr = NULL;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr == NULL || len != size ||
|
||||
mem_get_data(proc->pid, addr, ptr, len) < 0) {
|
||||
put_ptr(proc, name, addr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
put_open(proc, name, PF_NONAME, "{", ", ");
|
||||
|
||||
scn.sysctl_flags = proc->sctl_flags;
|
||||
|
||||
put_sysctl_imm(proc, &scn, FALSE);
|
||||
|
||||
put_close(proc, "}");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain information about a particular node 'id' in the node directory
|
||||
* identified by the MIB path 'name' (length 'namelen'). Return TRUE if the
|
||||
* node was found, in which case it is copied into 'scnp'. Return FALSE if the
|
||||
* node was not found or another error occurred.
|
||||
*/
|
||||
static int
|
||||
get_sysctl_node(const int * name, unsigned int namelen, int id,
|
||||
struct sysctlnode * scnp)
|
||||
{
|
||||
struct sysctlnode *scn, *escn, *fscn;
|
||||
char *buf;
|
||||
size_t len, elen;
|
||||
int r, mib[CTL_MAXNAME];
|
||||
|
||||
assert(namelen < CTL_MAXNAME);
|
||||
assert(id >= 0);
|
||||
|
||||
/* Query the parent, first using our static buffer for the results. */
|
||||
memcpy(mib, name, sizeof(mib[0]) * namelen);
|
||||
mib[namelen] = CTL_QUERY;
|
||||
len = sizeof(sysctlbuf);
|
||||
r = sysctl(mib, namelen + 1, sysctlbuf, &len, NULL, 0);
|
||||
if (r == -1 && (errno != ENOMEM || len == 0))
|
||||
return FALSE;
|
||||
|
||||
/* Even with partial results, check if we already found the node. */
|
||||
elen = MIN(len, sizeof(sysctlbuf));
|
||||
scn = (struct sysctlnode *)sysctlbuf;
|
||||
escn = (struct sysctlnode *)&sysctlbuf[elen];
|
||||
fscn = NULL; /* pointer to the node once found, NULL until then */
|
||||
for (; scn < escn && fscn == NULL; scn++)
|
||||
if (scn->sysctl_num == id)
|
||||
fscn = scn;
|
||||
|
||||
/* If our buffer was too small, use a temporary buffer. */
|
||||
if (fscn == NULL && r == -1) {
|
||||
if ((buf = malloc(len)) == NULL)
|
||||
return FALSE;
|
||||
if (sysctl(mib, namelen, buf, &len, NULL, 0) == 0) {
|
||||
scn = (struct sysctlnode *)sysctlbuf;
|
||||
escn = (struct sysctlnode *)&sysctlbuf[len];
|
||||
for (; scn < escn && fscn != NULL; scn++)
|
||||
if (scn->sysctl_num == id)
|
||||
fscn = scn;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if (fscn != NULL) {
|
||||
memcpy(scnp, fscn, sizeof(*scnp));
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the name string of one level of a sysctl(2) name, while also gathering
|
||||
* information about the target node. Return 1 if name interpretation should
|
||||
* continue as before, meaning this function will also be called for the next
|
||||
* name component (if any). Return 0 if the rest of the name should be printed
|
||||
* as numbers, without interpretation. Return -1 if printing the name is now
|
||||
* complete.
|
||||
*/
|
||||
static int
|
||||
put_sysctl_namestr(struct trace_proc * proc, const int * name,
|
||||
unsigned int namelen, unsigned int n, int all,
|
||||
const struct sysctl_tab ** sctp)
|
||||
{
|
||||
const struct sysctl_tab *sct;
|
||||
struct sysctlnode scn;
|
||||
const char *namestr;
|
||||
int i, r, id, is_last;
|
||||
|
||||
assert(n < namelen);
|
||||
|
||||
id = name[n];
|
||||
is_last = (n == namelen - 1 && all);
|
||||
namestr = NULL;
|
||||
|
||||
/* Negative identifiers are meta-identifiers. */
|
||||
if (id < 0) {
|
||||
switch (id) {
|
||||
case CTL_EOL: namestr = "<eol>"; break;
|
||||
case CTL_QUERY: namestr = "<query>"; break;
|
||||
case CTL_CREATE: namestr = "<create>"; break;
|
||||
case CTL_CREATESYM: namestr = "<createsym>"; break;
|
||||
case CTL_DESTROY: namestr = "<destroy>"; break;
|
||||
case CTL_MMAP: namestr = "<mmap>"; break;
|
||||
case CTL_DESCRIBE: namestr = "<describe>"; break;
|
||||
}
|
||||
|
||||
/* For some of them, we can print their parameters. */
|
||||
if (is_last) {
|
||||
switch (id) {
|
||||
case CTL_QUERY:
|
||||
proc->sctl_proc = put_sysctl_query;
|
||||
break;
|
||||
case CTL_CREATE:
|
||||
proc->sctl_proc = put_sysctl_create;
|
||||
break;
|
||||
case CTL_DESTROY:
|
||||
proc->sctl_proc = put_sysctl_destroy;
|
||||
break;
|
||||
case CTL_DESCRIBE:
|
||||
proc->sctl_proc = put_sysctl_describe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Meta-identifiers are allowed only at the very end of a name,
|
||||
* so if anything follows a meta-identifier, there is no good
|
||||
* way to interpret it. We just print numbers.
|
||||
*/
|
||||
r = 0;
|
||||
} else if (get_sysctl_node(name, n, id, &scn)) {
|
||||
/*
|
||||
* For regular identifiers, first see if we have a callback
|
||||
* function that does the interpretation. The use of the
|
||||
* callback function depends on whether the current node is of
|
||||
* type CTLTYPE_NODE: if it is, the callback function is
|
||||
* responsible for printing the rest of the name (and we return
|
||||
* -1 here after we are done, #1); if it isn't, then we just
|
||||
* use the callback function to interpret the node value (#2).
|
||||
* If we do not have a callback function, but the current node
|
||||
* is of type CTLTYPE_NODE *and* has a non-NULL callback
|
||||
* function registered in the MIB service, the remote callback
|
||||
* function would interpret the rest of the name, so we simply
|
||||
* print the rest of the name as numbers (returning 0 once we
|
||||
* are done, #3). Without a MIB-service callback function,
|
||||
* such nodes are just taken as path components and thus we
|
||||
* return 1 to continue resolution (#4). Finally, if we do not
|
||||
* have a callback function, and the current node is a data
|
||||
* node (i.e., *not* of type CTLTYPE_NODE), we try to interpret
|
||||
* it generically if it is the last component (#5), or we give
|
||||
* up and just print numbers otherwise (#6).
|
||||
*/
|
||||
|
||||
/* Okay, so start by looking up the node in our own tables. */
|
||||
sct = NULL;
|
||||
if (n == 0) {
|
||||
/* The top level is ID-indexed for performance. */
|
||||
if ((unsigned int)id < __arraycount(root_tab))
|
||||
*sctp = &root_tab[id];
|
||||
else
|
||||
*sctp = NULL;
|
||||
} else if (*sctp != NULL) {
|
||||
/* Other levels are searched, because of sparseness. */
|
||||
sct = (*sctp)->tab; /* NULL if missing or leaf */
|
||||
for (i = (int)(*sctp)->size; sct != NULL && i > 0;
|
||||
i--, sct++)
|
||||
if (sct->id == id)
|
||||
break;
|
||||
if (i == 0)
|
||||
sct = NULL;
|
||||
*sctp = sct;
|
||||
}
|
||||
|
||||
/* Now determine what to do. */
|
||||
if (SYSCTL_TYPE(scn.sysctl_flags) == CTLTYPE_NODE) {
|
||||
if (sct != NULL && sct->proc != NULL) {
|
||||
proc->sctl_size = sct->size;
|
||||
proc->sctl_proc = sct->proc;
|
||||
r = -1; /* #1 */
|
||||
} else if (scn.sysctl_func != NULL)
|
||||
r = 0; /* #3 */
|
||||
else
|
||||
r = 1; /* #4 */
|
||||
} else {
|
||||
if (!is_last)
|
||||
r = 0; /* #6 */
|
||||
else if (sct != NULL && sct->proc != NULL) {
|
||||
/* A nonzero size must match the node size. */
|
||||
if (sct->size == 0 ||
|
||||
sct->size == scn.sysctl_size) {
|
||||
proc->sctl_size = sct->size;
|
||||
proc->sctl_proc = sct->proc;
|
||||
}
|
||||
r = 0; /* #2 */
|
||||
} else {
|
||||
proc->sctl_flags = scn.sysctl_flags;
|
||||
proc->sctl_proc = put_sysctl_generic;
|
||||
r = 0; /* #5 */
|
||||
}
|
||||
}
|
||||
|
||||
namestr = scn.sysctl_name;
|
||||
} else {
|
||||
/*
|
||||
* The node was not found. This basically means that we will
|
||||
* not be able to get any information about deeper nodes
|
||||
* either. We do not even try: just print numbers.
|
||||
*/
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!valuesonly && namestr != NULL)
|
||||
put_field(proc, NULL, namestr);
|
||||
else
|
||||
put_value(proc, NULL, "%d", id);
|
||||
|
||||
/*
|
||||
* Did we determine that the rest of the name should be printed by the
|
||||
* callback function? Then we might as well make that happen. The
|
||||
* abuse of the parameter types is not great, oh well.
|
||||
*/
|
||||
if (r == -1)
|
||||
(void)proc->sctl_proc(proc, NULL, ST_NAME, &name[n + 1], 0,
|
||||
namelen - n - 1);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the sysctl(2) name parameter, and gather information needed to print
|
||||
* the oldp and newp parameters later.
|
||||
*/
|
||||
static void
|
||||
put_sysctl_name(struct trace_proc * proc, const char * name, int flags,
|
||||
vir_bytes addr, unsigned int namelen)
|
||||
{
|
||||
const struct sysctl_tab *sct = NULL;
|
||||
const char *namestr;
|
||||
int r, all, namebuf[CTL_MAXNAME];
|
||||
unsigned int n;
|
||||
|
||||
if (namelen > CTL_MAXNAME) {
|
||||
namelen = CTL_MAXNAME;
|
||||
all = 0;
|
||||
} else
|
||||
all = 1;
|
||||
|
||||
if ((flags & PF_FAILED) || valuesonly > 1 || namelen > CTL_MAXNAME ||
|
||||
(namelen > 0 && !(flags & PF_LOCADDR) &&
|
||||
mem_get_data(proc->pid, addr, namebuf,
|
||||
namelen * sizeof(namebuf[0])) < 0)) {
|
||||
if (flags & PF_LOCADDR)
|
||||
put_field(proc, name, "&..");
|
||||
else
|
||||
put_ptr(proc, name, addr);
|
||||
return;
|
||||
} else if (namelen > 0 && (flags & PF_LOCADDR))
|
||||
memcpy(namebuf, (void *)addr, sizeof(namebuf[0]) * namelen);
|
||||
|
||||
/*
|
||||
* Print the path name of the node as possible, and find information
|
||||
* about the target node as we go along. See put_sysctl_namestr() for
|
||||
* the meaning of 'r'.
|
||||
*/
|
||||
put_open(proc, name, PF_NONAME, "[", ".");
|
||||
for (n = 0, r = 1; n < namelen; n++) {
|
||||
if (r == 1) {
|
||||
if ((r = put_sysctl_namestr(proc, namebuf, namelen, n,
|
||||
all, &sct)) < 0)
|
||||
break;
|
||||
} else
|
||||
put_value(proc, NULL, "%d", namebuf[n]);
|
||||
}
|
||||
if (!all)
|
||||
put_field(proc, NULL, "..");
|
||||
put_close(proc, "]");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the sysctl(2) oldp or newp parameter. PF_ALT means that the given
|
||||
* parameter is newp rather than oldp, in which case PF_FAILED will not be set.
|
||||
*/
|
||||
static void
|
||||
put_sysctl_data(struct trace_proc * proc, const char * name, int flags,
|
||||
vir_bytes addr, size_t len)
|
||||
{
|
||||
char *ptr;
|
||||
int type, all;
|
||||
|
||||
if ((flags & PF_FAILED) || addr == 0 || valuesonly > 1 ||
|
||||
proc->sctl_proc == NULL || proc->sctl_size > sizeof(sysctlbuf) ||
|
||||
(proc->sctl_size > 0 && (proc->sctl_size != len ||
|
||||
mem_get_data(proc->pid, addr, sysctlbuf, proc->sctl_size) < 0))) {
|
||||
put_ptr(proc, name, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
type = (flags & PF_ALT) ? ST_NEWP : ST_OLDP;
|
||||
ptr = (proc->sctl_size > 0) ? sysctlbuf : NULL;
|
||||
|
||||
/*
|
||||
* The rough idea here: we have a "simple" mode and a "flexible" mode,
|
||||
* depending on whether a size was specified in our table. For the
|
||||
* simple mode, we only call the callback function when we have been
|
||||
* able to copy in the data. A surrounding {} block will be printed
|
||||
* automatically, the callback function only has to print the data
|
||||
* fields. The simple mode is basically for structures. In contrast,
|
||||
* the flexible mode leaves both the copying and the printing entirely
|
||||
* to the callback function, which thus may print the pointer on copy
|
||||
* failure (in which case the surrounding {}s would get in the way).
|
||||
*/
|
||||
if (ptr != NULL)
|
||||
put_open(proc, name, 0, "{", ", ");
|
||||
|
||||
all = proc->sctl_proc(proc, name, type, ptr, addr, len);
|
||||
|
||||
if (ptr != NULL) {
|
||||
if (all == FALSE)
|
||||
put_field(proc, NULL, "..");
|
||||
put_close(proc, "}");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mib_sysctl_out(struct trace_proc * proc, const message * m_out)
|
||||
{
|
||||
unsigned int namelen;
|
||||
|
||||
/* Reset the sysctl-related state. */
|
||||
proc->sctl_flags = 0;
|
||||
proc->sctl_size = 0;
|
||||
proc->sctl_proc = NULL;
|
||||
proc->sctl_arg = 0;
|
||||
|
||||
namelen = m_out->m_lc_mib_sysctl.namelen;
|
||||
|
||||
/* As part of processing the name, we initialize the state. */
|
||||
if (namelen <= CTL_SHORTNAME)
|
||||
put_sysctl_name(proc, "name", PF_LOCADDR,
|
||||
(vir_bytes)&m_out->m_lc_mib_sysctl.name, namelen);
|
||||
else
|
||||
put_sysctl_name(proc, "name", 0, m_out->m_lc_mib_sysctl.namep,
|
||||
namelen);
|
||||
|
||||
put_value(proc, "namelen", "%u", namelen);
|
||||
|
||||
if (m_out->m_lc_mib_sysctl.oldp == 0 || valuesonly > 1) {
|
||||
put_sysctl_data(proc, "oldp", 0,
|
||||
m_out->m_lc_mib_sysctl.oldp,
|
||||
m_out->m_lc_mib_sysctl.oldlen);
|
||||
/* If oldp is NULL, oldlen may contain garbage; don't print. */
|
||||
if (m_out->m_lc_mib_sysctl.oldp != 0)
|
||||
put_value(proc, "oldlen", "%zu", /* {%zu} is more */
|
||||
m_out->m_lc_mib_sysctl.oldlen); /* correct.. */
|
||||
else
|
||||
put_value(proc, "oldlen", "%d", 0);
|
||||
put_sysctl_data(proc, "newp", PF_ALT,
|
||||
m_out->m_lc_mib_sysctl.newp,
|
||||
m_out->m_lc_mib_sysctl.newlen);
|
||||
put_value(proc, "newlen", "%zu",
|
||||
m_out->m_lc_mib_sysctl.newlen);
|
||||
return CT_DONE;
|
||||
} else
|
||||
return CT_NOTDONE;
|
||||
}
|
||||
|
||||
static void
|
||||
mib_sysctl_in(struct trace_proc * proc, const message * m_out,
|
||||
const message * m_in, int failed)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (m_out->m_lc_mib_sysctl.oldp != 0 && valuesonly <= 1) {
|
||||
put_sysctl_data(proc, "oldp", failed,
|
||||
m_out->m_lc_mib_sysctl.oldp,
|
||||
m_in->m_mib_lc_sysctl.oldlen /* the returned length */);
|
||||
put_value(proc, "oldlen", "%zu", /* {%zu} is more correct.. */
|
||||
m_out->m_lc_mib_sysctl.oldlen);
|
||||
put_sysctl_data(proc, "newp", PF_ALT,
|
||||
m_out->m_lc_mib_sysctl.newp,
|
||||
m_out->m_lc_mib_sysctl.newlen);
|
||||
put_value(proc, "newlen", "%zu",
|
||||
m_out->m_lc_mib_sysctl.newlen);
|
||||
put_equals(proc);
|
||||
}
|
||||
|
||||
put_result(proc);
|
||||
|
||||
/*
|
||||
* We want to print the returned old length in the following cases:
|
||||
* 1. the call succeeded, the old pointer was NULL, and no new data was
|
||||
* supplied;
|
||||
* 2. the call succeeded, the old pointer was not NULL, and the
|
||||
* returned old length is different from the supplied old length.
|
||||
* 3. the call failed with ENOMEM or EEXIST, and the old pointer was
|
||||
* not NULL (an undocumented NetBSD feature, used by sysctl(8)).
|
||||
*/
|
||||
if (/*#1*/ (!failed && m_out->m_lc_mib_sysctl.oldp == 0 &&
|
||||
(m_out->m_lc_mib_sysctl.newp == 0 ||
|
||||
m_out->m_lc_mib_sysctl.newlen == 0)) ||
|
||||
/*#2*/ (!failed && m_out->m_lc_mib_sysctl.oldp != 0 &&
|
||||
m_out->m_lc_mib_sysctl.oldlen != m_in->m_mib_lc_sysctl.oldlen) ||
|
||||
/*#3*/ (failed && call_errno(proc, &err) &&
|
||||
(err == ENOMEM || err == EEXIST) &&
|
||||
m_out->m_lc_mib_sysctl.oldp != 0)) {
|
||||
put_open(proc, NULL, 0, "(", ", ");
|
||||
put_value(proc, "oldlen", "%zu", m_in->m_mib_lc_sysctl.oldlen);
|
||||
put_close(proc, ")");
|
||||
}
|
||||
}
|
||||
|
||||
#define MIB_CALL(c) [((MIB_ ## c) - MIB_BASE)]
|
||||
|
||||
static const struct call_handler mib_map[] = {
|
||||
MIB_CALL(SYSCTL) = HANDLER("sysctl", mib_sysctl_out, mib_sysctl_in),
|
||||
};
|
||||
|
||||
const struct calls mib_calls = {
|
||||
.endpt = MIB_PROC_NR,
|
||||
.base = MIB_BASE,
|
||||
.map = mib_map,
|
||||
.count = COUNT(mib_map)
|
||||
};
|
@ -20,9 +20,10 @@ PROGRAMS+= ${PROGROOT}/minix/servers/sched/sched
|
||||
PROGRAMS+= ${PROGROOT}/minix/servers/vfs/vfs
|
||||
PROGRAMS+= ${PROGROOT}/minix/drivers/storage/memory/memory
|
||||
PROGRAMS+= ${PROGROOT}/minix/drivers/tty/tty/tty
|
||||
PROGRAMS+= ${PROGROOT}/minix/fs/mfs/mfs
|
||||
PROGRAMS+= ${PROGROOT}/minix/servers/mib/mib
|
||||
PROGRAMS+= ${PROGROOT}/minix/servers/vm/vm
|
||||
PROGRAMS+= ${PROGROOT}/minix/fs/pfs/pfs
|
||||
PROGRAMS+= ${PROGROOT}/minix/fs/mfs/mfs
|
||||
PROGRAMS+= ${PROGROOT}/sbin/init/init
|
||||
|
||||
all usage help:
|
||||
|
@ -170,7 +170,7 @@ ${CROSS_PREFIX}objcopy ${OBJ}/minix/kernel/kernel -O binary ${OBJ}/kernel.bin
|
||||
mcopy -bsp -i ${WORK_DIR}/fat.img ${OBJ}/kernel.bin ::kernel.bin
|
||||
|
||||
for f in servers/vm/vm servers/rs/rs servers/pm/pm servers/sched/sched \
|
||||
servers/vfs/vfs servers/ds/ds fs/mfs/mfs fs/pfs/pfs \
|
||||
servers/vfs/vfs servers/ds/ds servers/mib/mib fs/pfs/pfs fs/mfs/mfs \
|
||||
../sbin/init/init
|
||||
do
|
||||
fn=`basename $f`.elf
|
||||
|
@ -9,10 +9,11 @@ list="0x80200000 kernel.bin
|
||||
0x84000000 vfs.elf
|
||||
0x84800000 memory.elf
|
||||
0x85000000 tty.elf
|
||||
0x85800000 mfs.elf
|
||||
0x85800000 mib.elf
|
||||
0x86000000 vm.elf
|
||||
0x86800000 pfs.elf
|
||||
0x87000000 init.elf"
|
||||
0x87000000 mfs.elf
|
||||
0x87800000 init.elf"
|
||||
|
||||
#
|
||||
# PREFIX for loading file over tftp to allow hosting multiple
|
||||
|
@ -77,10 +77,11 @@ load=/mod04_sched
|
||||
load=/mod05_vfs
|
||||
load=/mod06_memory
|
||||
load=/mod07_tty
|
||||
load=/mod08_mfs
|
||||
load=/mod08_mib
|
||||
load=/mod09_vm
|
||||
load=/mod10_pfs
|
||||
load=/mod11_init
|
||||
load=/mod11_mfs
|
||||
load=/mod12_init
|
||||
# This space intentionally left blank - leave to appease bootloader!
|
||||
# This space intentionally left blank - leave to appease bootloader!
|
||||
# This space intentionally left blank - leave to appease bootloader!
|
||||
|
@ -62,10 +62,11 @@ load=/boot/minix_default/mod04_sched
|
||||
load=/boot/minix_default/mod05_vfs
|
||||
load=/boot/minix_default/mod06_memory
|
||||
load=/boot/minix_default/mod07_tty
|
||||
load=/boot/minix_default/mod08_mfs
|
||||
load=/boot/minix_default/mod08_mib
|
||||
load=/boot/minix_default/mod09_vm
|
||||
load=/boot/minix_default/mod10_pfs
|
||||
load=/boot/minix_default/mod11_init
|
||||
load=/boot/minix_default/mod11_mfs
|
||||
load=/boot/minix_default/mod12_init
|
||||
END_BOOT_CFG
|
||||
add_file_spec "boot.cfg" extra.cdfiles
|
||||
|
||||
|
@ -1341,16 +1341,16 @@ typedef void *sysctlfn;
|
||||
|
||||
__BEGIN_DECLS
|
||||
int sysctl(const int *, u_int, void *, size_t *, const void *, size_t);
|
||||
#if !defined(__minix)
|
||||
int sysctlbyname(const char *, void *, size_t *, const void *, size_t);
|
||||
int sysctlgetmibinfo(const char *, int *, u_int *,
|
||||
char *, size_t *, struct sysctlnode **, int);
|
||||
int sysctlnametomib(const char *, int *, size_t *);
|
||||
#if !defined(__minix)
|
||||
int proc_compare(const struct kinfo_proc2 *, const struct kinfo_lwp *,
|
||||
const struct kinfo_proc2 *, const struct kinfo_lwp *);
|
||||
#endif /* !defined(__minix) */
|
||||
void *asysctl(const int *, size_t, size_t *);
|
||||
void *asysctlbyname(const char *, size_t *);
|
||||
#endif /* !defined(__minix) */
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_KERNEL */
|
||||
|
Loading…
x
Reference in New Issue
Block a user