libc: read sysctl info from /.sysctl/...

Fixes #1931
This commit is contained in:
Emery Hemingway 2016-04-15 14:19:51 +02:00 committed by Christian Helmuth
parent 19b3824bfb
commit 93b82c14ac
7 changed files with 401 additions and 49 deletions

View File

@ -3,6 +3,11 @@ LIBC_GEN_DIR = $(LIBC_DIR)/lib/libc/gen
# this file produces a warning about a missing header file, lets drop it
FILTER_OUT_C += getosreldate.c sem.c valloc.c getpwent.c
# the following are superceded by our minimalist sysctl and sysconf
FILTER_OUT_C += \
devname.c feature_present.c getpagesizes.c getvfsbyname.c \
setproctitle.c sysconf.c sysctlbyname.c
SRC_C = $(filter-out $(FILTER_OUT_C),$(notdir $(wildcard $(LIBC_GEN_DIR)/*.c)))
# 'sysconf.c' includes the local 'stdtime/tzfile.h'

View File

@ -17,6 +17,8 @@ SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \
libc_pdbg.cc vfs_plugin.cc rtc.cc dynamic_linker.cc signal.cc \
socket_operations.cc task.cc
CC_OPT_sysctl += -Wno-write-strings
INC_DIR += $(REP_DIR)/src/lib/libc
INC_DIR += $(REP_DIR)/src/lib/libc/include
@ -31,6 +33,11 @@ SRC_C += strcoll.c strxfrm.c wcscoll.c wcsxfrm.c
include $(REP_DIR)/lib/mk/libc-common.inc
#
# Version information for sysctl
#
include $(REP_DIR)/src/lib/libc/version.inc
vpath % $(REP_DIR)/src/lib/libc
vpath % $(LIBC_DIR)/lib/libc/string

View File

@ -94,5 +94,4 @@ File_descriptor *File_descriptor_allocator::find_by_libc_fd(int libc_fd)
** Libc functions **
********************/
extern "C" int __attribute__((weak)) getdtablesize(void) {
PDBG("libc"); return MAX_NUM_FDS; }
extern "C" int __attribute__((weak)) getdtablesize(void) { return MAX_NUM_FDS; }

View File

@ -0,0 +1,31 @@
/*
* \brief C++ wrapper over errno
* \author Christian Helmuth
* \date 2016-04-26
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LIBC_ERRNO_H_
#define _LIBC_ERRNO_H_
/* libc includes */
#include <errno.h>
namespace Libc { struct Errno; }
struct Libc::Errno
{
int const error;
explicit Errno(int error) : error(error) { errno = error; }
operator int() const { return -1; }
};
#endif /* _LIBC_ERRNO_H_ */

View File

@ -1,73 +1,266 @@
/*
* \brief C-library back end
* \author Norman Feske
* \date 2008-11-11
* \brief Sysctl facade
* \author Emery Hemingway
* \date 2016-04-27
*/
/*
* Copyright (C) 2008-2013 Genode Labs GmbH
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
/* Genode includes */
#include <util/string.h>
#include <base/env.h>
#include <sys/types.h>
/* Genode-specific libc interfaces */
#include <libc-plugin/plugin.h>
#include <libc-plugin/fd_alloc.h>
/* Libc includes */
#include <sys/sysctl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "libc_errno.h"
enum { PAGESIZE = 4096 };
extern "C" long sysconf(int name)
{
switch (name) {
case _SC_CHILD_MAX: return CHILD_MAX;
case _SC_OPEN_MAX: return getdtablesize();
case _SC_NPROCESSORS_CONF: return 1;
case _SC_NPROCESSORS_ONLN: return 1;
case _SC_PAGESIZE: return PAGESIZE;
case _SC_PHYS_PAGES:
return Genode::env()->ram_session()->quota() / PAGESIZE;
default:
PWRN("%s(%d) not implemented", __func__, name);
return Libc::Errno(EINVAL);
}
}
/* non-standard FreeBSD function not supported */
extern "C" int sysctlbyname(char const *name, void *oldp, size_t *oldlenp,
void *newp, size_t newlen)
{
PWRN("%s(%s,...) not implemented", __func__, name);
return Libc::Errno(ENOENT);
}
#include "libc_debug.h"
extern "C" int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen)
{
int i;
raw_write_str("__sysctl called\n");
static const ctlname ctl_names[] = CTL_NAMES;
static const ctlname ctl_kern_names[] = CTL_KERN_NAMES;
static const ctlname ctl_hw_names[] = CTL_HW_NAMES;
static const ctlname ctl_user_names[] = CTL_USER_NAMES;
static const ctlname ctl_p1003_1b_names[] = CTL_P1003_1B_NAMES;
/*
* During printf, __sysctl is called by malloc with the parameters
*
* name[0] == 6 (CTL_HW)
* name[1] == 3 (HW_NCPU)
*
* In this case, we can return -1, and the libC assumes that we
* have one CPU.
*/
if ((name[0] == CTL_HW) && (name[1] == HW_NCPU))
return -1;
/* read only */
if (!oldp) /* check for write attempt */
return Libc::Errno(newp ? EPERM : EINVAL);
/*
* CTL_P1003_1B is used by sysconf(_SC_PAGESIZE) to determine
* the actual page size.
*/
if (((name[0] == CTL_HW) && (name[1] == HW_PAGESIZE)) ||
((name[0] == CTL_P1003_1B) && (name[1] == CTL_P1003_1B_PAGESIZE))) {
int result = 4096;
if (oldp) {
if (*oldlenp >= sizeof(result)) {
*(int*)oldp = result;
*oldlenp = sizeof(result);
ctlname const *ctl = nullptr;
char *buf = (char*)oldp;
int index_a = name[0];
int index_b = name[1];
if (namelen != 2) return Libc::Errno(ENOENT);
if (index_a >= CTL_MAXID) return Libc::Errno(EINVAL);
switch(index_a) {
case CTL_KERN:
if (index_b >= KERN_MAXID) return Libc::Errno(EINVAL);
ctl = &ctl_kern_names[index_b]; break;
case CTL_HW:
if (index_b >= HW_MAXID) return Libc::Errno(EINVAL);
ctl = &ctl_hw_names[index_b]; break;
case CTL_USER:
if (index_b >= USER_MAXID) return Libc::Errno(EINVAL);
ctl = &ctl_user_names[index_b]; break;
case CTL_P1003_1B:
if (index_b >= CTL_P1003_1B_MAXID) return Libc::Errno(EINVAL);
ctl = &ctl_p1003_1b_names[index_b]; break;
}
if (!ctl) return Libc::Errno(EINVAL);
if (((ctl->ctl_type == CTLTYPE_INT) && (*oldlenp < sizeof(int))) ||
((ctl->ctl_type == CTLTYPE_STRING) && (*oldlenp < 1)) ||
((ctl->ctl_type == CTLTYPE_QUAD) && (*oldlenp < sizeof(Genode::uint64_t))) ||
((ctl->ctl_type == CTLTYPE_UINT) && (*oldlenp < sizeof(unsigned int))) ||
((ctl->ctl_type == CTLTYPE_LONG) && (*oldlenp < sizeof(long))) ||
((ctl->ctl_type == CTLTYPE_ULONG) && (*oldlenp < sizeof(unsigned long))))
{
return Libc::Errno(EINVAL);
}
/* builtins */
{
switch(index_a) {
case CTL_HW: switch(index_b) {
case HW_PHYSMEM:
case HW_USERMEM:
*(unsigned long*)oldp = Genode::env()->ram_session()->quota();
*oldlenp = sizeof(unsigned long);
return 0;
} else {
PERR("not enough room to store the old value");
return -1;
}
} else {
PERR("cannot store the result in oldp, since it is NULL");
return -1;
case HW_PAGESIZE:
*(int*)oldp = (int)PAGESIZE;
*oldlenp = sizeof(int);
return 0;
} break;
case CTL_P1003_1B: switch(index_b) {
case CTL_P1003_1B_PAGESIZE:
*(int*)oldp = PAGESIZE;
*oldlenp = sizeof(int);
return 0;
} break;
}
}
raw_write_str(newp ? "newp provided\n" : "no newp provided\n");
for (i = 0; i < name[0]; i++)
raw_write_str("*");
raw_write_str("\n");
for (i = 0; i < name[1]; i++)
raw_write_str("%");
raw_write_str("\n");
/* runtime overrides */
{
Libc::Absolute_path sysctl_path(ctl_names[index_a].ctl_name, "/.sysctl/");
sysctl_path.append("/");
sysctl_path.append(ctl->ctl_name);
return 0;
/*
* read from /.sysctl/...
*
* The abstracted libc interface is used to read files here
* rather than to explicity resolve a file system plugin.
*/
int fd = open(sysctl_path.base(), 0);
if (fd != -1) {
auto n = read(fd, buf, *oldlenp);
close(fd);
if (n > 0) switch (ctl->ctl_type) {
case CTLTYPE_INT: {
long value = 0;
Genode::ascii_to((char*)oldp, value);
*(int*)oldp = int(value);
*oldlenp = sizeof(int);
return 0;
}
case CTLTYPE_STRING:
*oldlenp = n;
return 0;
case CTLTYPE_QUAD: {
Genode::uint64_t value = 0;
Genode::ascii_to((char*)oldp, value);
*(Genode::uint64_t*)oldp = value;
*oldlenp = sizeof(Genode::uint64_t);
return 0;
}
case CTLTYPE_UINT: {
unsigned value = 0;
Genode::ascii_to((char*)oldp, value);
*(unsigned*)oldp = value;
*oldlenp = sizeof(unsigned);
return 0;
}
case CTLTYPE_LONG: {
long value = 0;
Genode::ascii_to((char*)oldp, value);
*(long*)oldp = value;
*oldlenp = sizeof(long);
return 0;
}
case CTLTYPE_ULONG: {
unsigned long value = 0;
Genode::ascii_to((char*)oldp, value);
*(unsigned long*)oldp = value;
*oldlenp = sizeof(unsigned long);
return 0;
}
default:
PWRN("unhandled sysctl data type for %s", sysctl_path.base());
return Libc::Errno(EINVAL);
}
}
}
/* fallback values */
{
switch(index_a) {
case CTL_KERN:
switch(index_b) {
case KERN_OSTYPE:
Genode::strncpy(buf, "Genode", *oldlenp);
*oldlenp = Genode::strlen(buf);
return 0;
case KERN_OSRELEASE:
Genode::strncpy(buf, GENODE_OSRELEASE, *oldlenp);
*oldlenp = Genode::strlen(buf);
return 0;
case KERN_OSREV:
*(int*)oldp = int(GENODE_OSREV);
*oldlenp = sizeof(int);
return 0;
case KERN_VERSION:
Genode::strncpy(buf, GENODE_VERSION, *oldlenp);
*oldlenp = Genode::strlen(buf);
return 0;
case KERN_HOSTNAME:
Genode::strncpy(buf, "localhost", *oldlenp);
*oldlenp = Genode::strlen(buf);
return 0;
} break;
case CTL_HW: switch(index_b) {
case HW_MACHINE:
Genode::strncpy(buf, GENODE_MACHINE, *oldlenp);
*oldlenp = Genode::strlen(buf);
return 0;
case HW_NCPU:
*(int*)oldp = 1;
*oldlenp = sizeof(int);
return 0;
} break;
}
}
PWRN("sysctl: no builtin or override value found for %s.%s",
ctl_names[index_a].ctl_name, ctl->ctl_name);
return Libc::Errno(ENOENT);
}

View File

@ -0,0 +1,41 @@
#
# Provide version information to sysctl
#
GENODE_ROOT_DIR = $(REP_DIR)/../..
GENODE_OSRELEASE := $(shell cat $(GENODE_ROOT_DIR)/VERSION)
GENODE_OSREV := $(shell which git > /dev/null && git rev-list --count HEAD)
GENODE_VERSION := $(shell \
which git > /dev/null \
&& git -C $(GENODE_ROOT_DIR) describe 2> /dev/null \
&& exit 0 \
|| \
test -r $(GENODE_ROOT_DIR)/VERSION \
&& cat $(GENODE_ROOT_DIR)/VERSION \
&& exit 0 \
|| \
echo "<unknown version>")
CC_OPT += -DGENODE_OSRELEASE="\"$(GENODE_OSRELEASE)\""
CC_OPT += -DGENODE_OSREV="$(GENODE_OSREV)"
CC_OPT += -DGENODE_VERSION="\"$(GENODE_VERSION)\""
ifeq ($(findstring arm, $(SPECS)), arm)
CC_OPT += -DGENODE_MACHINE="\"arm\""
else
ifeq ($(findstring riscv, $(SPECS)), riscv)
CC_OPT += -DGENODE_MACHINE="\"riscv\""
else
ifeq ($(findstring x86_32, $(SPECS)), x86_32)
CC_OPT += -DGENODE_MACHINE="\"i686\""
else
ifeq ($(findstring x86_64, $(SPECS)), x86_64)
CC_OPT += -DGENODE_MACHINE="\"x86_64\""
else
CC_OPT += -DGENODE_MACHINE="\"unknown\""
endif
endif
endif
endif

View File

@ -0,0 +1,76 @@
build { core init drivers/timer noux/minimal
lib/libc_noux noux-pkg/coreutils }
# strip coreutils binaries and create tar archive
exec sh -c "[cross_dev_prefix]strip bin/coreutils/bin/*"
exec tar cfv bin/coreutils.tar -h -C bin/coreutils .
create_boot_directory
install_config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="LOG"/>
<service name="CAP"/>
<service name="RAM"/>
<service name="RM"/>
<service name="CPU"/>
<service name="PD"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service> <any-child/> <parent/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="spoof">
<binary name="noux"/>
<resource name="RAM" quantum="16M"/>
<config verbose="yes" stdin="/null" stdout="/log" stderr="/log">
<fstab>
<null/> <log/>
<dir name=".sysctl">
<dir name="kern">
<inline name="ostype">Muck OS XIII</inline>
<inline name="hostname">localhost</inline>
</dir>
<dir name="hw">
<inline name="machine">norisc</inline>
</dir>
</dir>
<tar name="coreutils.tar" />
</fstab>
<start name="/bin/uname"> <arg value="-a"/> </start>
</config>
</start>
<start name="noux">
<resource name="RAM" quantum="16M"/>
<config verbose="yes" stdin="/null" stdout="/log" stderr="/log">
<fstab> <null/> <log/> <tar name="coreutils.tar" /> </fstab>
<start name="/bin/uname"> <arg value="-a"/> </start>
</config>
</start>
</config>
}
build_boot_image {
core init timer ld.lib.so noux libc.lib.so libm.lib.so
libc_noux.lib.so coreutils.tar
}
append qemu_args " -nographic -serial mon:stdio "
if {[have_spec x86_64]} {
# coreutils.tar is really huge when built for x86_64
append qemu_args " -m 300 "
}
run_genode_until {child "noux" exited with exit value 0.*\n} 30
exec rm bin/coreutils.tar