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:
David van Moolenbroek 2015-10-13 22:43:53 +00:00 committed by Lionel Sambuc
parent eba1476389
commit e4e21ee1b2
39 changed files with 6783 additions and 40 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -157,6 +157,7 @@ autoboot|start)
edit ds
edit tty
edit memory
edit mib
edit pfs
edit init
#

View File

@ -216,6 +216,15 @@ service log
priority 2;
};
service mib
{
system
VIRCOPY # 15
;
ipc ALL;
uid 0;
};
service init
{
uid 0;

View File

@ -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 \

View File

@ -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,

View File

@ -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" },

View File

@ -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 \

View File

@ -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 *
*===========================================================================*/

View File

@ -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;

View 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 */

View File

@ -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" },
};

View File

@ -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

View 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;
}

View File

@ -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 \

View File

@ -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

View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

@ -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 */
};

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View 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)
};

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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!

View File

@ -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

View File

@ -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 */