mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
Test for combining loader with chroot
This commit is contained in:
parent
17b60f8d41
commit
ed867817b6
139
os/run/chroot_loader.run
Normal file
139
os/run/chroot_loader.run
Normal file
@ -0,0 +1,139 @@
|
||||
#
|
||||
# \brief Test for using chroot on Linux
|
||||
# \author Norman Feske
|
||||
# \date 2012-06-06
|
||||
#
|
||||
#
|
||||
if {![have_spec linux]} { puts "Run script requires Linux"; exit 0 }
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
build { core init app/chroot drivers/timer/linux test/timer
|
||||
server/loader test/chroot_loader }
|
||||
|
||||
if {[catch { exec which setcap }]} {
|
||||
puts stderr "Error: setcap not available, please install the libcap2-bin package"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
set config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="LOG"/>
|
||||
<service name="CAP"/>
|
||||
<service name="RAM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="RM"/>
|
||||
<service name="PD"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="loader">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Loader"/></provides>
|
||||
</start>
|
||||
<start name="test-chroot_loader">
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
<config>
|
||||
<static_test chroot_path="chroot_path_1" />
|
||||
<dynamic_test chroot_path="chroot_path_2" />
|
||||
</config>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
proc chroot_path { id } { return "/tmp/chroot-test-$id" }
|
||||
|
||||
proc chroot_cwd_path { id } { return "[chroot_path $id][pwd]/[run_dir]" }
|
||||
|
||||
proc chroot_genode_tmp_path { id } { return "[chroot_path $id]/tmp/genode-[exec id -u]" }
|
||||
|
||||
proc cleanup_chroot { } {
|
||||
foreach id { 1 2 } {
|
||||
catch { exec sudo umount -l [chroot_cwd_path $id] }
|
||||
catch { exec sudo umount -l [chroot_genode_tmp_path $id] }
|
||||
catch { exec sudo umount -l [chroot_path $id]/lib }
|
||||
catch { exec rm -rf [chroot_path $id] }
|
||||
}
|
||||
}
|
||||
|
||||
# replace 'chroot_path' markers in config with actual paths
|
||||
foreach id { 1 2 } {
|
||||
regsub "chroot_path_$id" $config [chroot_path $id] config }
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Copy boot modules into run directory
|
||||
#
|
||||
# We cannot use the predefined 'build_boot_image' function here because
|
||||
# this would create mere symlinks. However, we want to hardlink the
|
||||
# run directory into the chroot environment. If the directory entries
|
||||
# were symlinks, those would point to nowhere within the chroot.
|
||||
#
|
||||
foreach binary { core init chroot timer loader test-chroot_loader test-timer} {
|
||||
exec cp -H bin/$binary [run_dir] }
|
||||
|
||||
#
|
||||
# Grant chroot permission to 'chroot' tool
|
||||
#
|
||||
# CAP_SYS_ADMIN is needed for bind mounting genode runtime directories
|
||||
# CAP_SYS_CHROOT is needed to perform the chroot syscall
|
||||
#
|
||||
exec sudo setcap cap_sys_admin,cap_sys_chroot=ep [run_dir]/chroot
|
||||
|
||||
#
|
||||
# Setup chroot environment
|
||||
#
|
||||
|
||||
# start with fresh directory
|
||||
cleanup_chroot
|
||||
foreach id { 1 2 } {
|
||||
exec mkdir -p [chroot_path $id]
|
||||
exec mkdir -p [chroot_path $id]/lib
|
||||
|
||||
# bind mount '/lib' as need libc within the chroot environment
|
||||
exec sudo mount --bind /lib [chroot_path $id]/lib
|
||||
}
|
||||
|
||||
#
|
||||
# Execute test case
|
||||
#
|
||||
run_genode_until {.*--- chroot-loader test finished ---\s*\n} 60
|
||||
|
||||
#
|
||||
# Validate log output
|
||||
#
|
||||
|
||||
if {[regexp -all -- {--- timer test ---} $output] != 6} {
|
||||
puts stderr "Number of spawned subsystems differs from 6"
|
||||
exit 2
|
||||
}
|
||||
|
||||
if {![regexp -- {chroot-1 -> test-timer] wait 2/10} $output]} {
|
||||
puts stderr "Long-running timer test has made too little progress"
|
||||
exit 3
|
||||
}
|
||||
|
||||
#
|
||||
# Remove artifacts created while running the test
|
||||
#
|
||||
cleanup_chroot
|
||||
|
||||
# vi: set ft=tcl :
|
174
os/src/test/chroot_loader/main.cc
Normal file
174
os/src/test/chroot_loader/main.cc
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* \brief Test for dynamically starting chrooted subsystems via the loader
|
||||
* \author Norman Feske
|
||||
* \date 2012-06-06
|
||||
*
|
||||
* This test creates two subsystems, each residing in a dedicated chroot
|
||||
* environment, by combining the loader service with the chroot mechanism.
|
||||
* One subsystem runs infinitely. The other subsystem will be repeatedly
|
||||
* started and killed.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/snprintf.h>
|
||||
#include <loader_session/connection.h>
|
||||
#include <os/config.h>
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
|
||||
/*******************************************************
|
||||
** Helpers for obtaining test parameters from config **
|
||||
*******************************************************/
|
||||
|
||||
static char const *chroot_path_from_config(char const *node_name,
|
||||
char *dst, Genode::size_t dst_len)
|
||||
{
|
||||
Genode::config()->xml_node().sub_node(node_name)
|
||||
.attribute("chroot_path").value(dst, dst_len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
static char const *chroot_path_of_static_test()
|
||||
{
|
||||
static char buf[1024];
|
||||
return chroot_path_from_config("static_test", buf, sizeof(buf));
|
||||
}
|
||||
|
||||
|
||||
static char const *chroot_path_of_dynamic_test()
|
||||
{
|
||||
static char buf[1024];
|
||||
return chroot_path_from_config("dynamic_test", buf, sizeof(buf));
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
** Test **
|
||||
**********/
|
||||
|
||||
/**
|
||||
* Return format string used as template for the subsystem configuration.
|
||||
*
|
||||
* Note the format-string argument used for inserting the chroot path.
|
||||
*/
|
||||
static char const *config_template()
|
||||
{
|
||||
return "<config verbose=\"yes\">\n"
|
||||
" <root path=\"%s\" />\n"
|
||||
" <parent-provides>\n"
|
||||
" <service name=\"ROM\"/>\n"
|
||||
" <service name=\"LOG\"/>\n"
|
||||
" <service name=\"CAP\"/>\n"
|
||||
" <service name=\"RAM\"/>\n"
|
||||
" <service name=\"CPU\"/>\n"
|
||||
" <service name=\"RM\"/>\n"
|
||||
" <service name=\"PD\"/>\n"
|
||||
" <service name=\"Timer\"/>\n"
|
||||
" </parent-provides>\n"
|
||||
" <default-route>\n"
|
||||
" <any-service> <parent/> </any-service>\n"
|
||||
" </default-route>\n"
|
||||
" <start name=\"test-timer\">\n"
|
||||
" <resource name=\"RAM\" quantum=\"1G\"/>\n"
|
||||
" </start>\n"
|
||||
"</config>\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Chroot subsystem corresponding to a loader session
|
||||
*/
|
||||
class Chroot_subsystem
|
||||
{
|
||||
private:
|
||||
|
||||
Loader::Connection _loader;
|
||||
|
||||
char _label[32];
|
||||
|
||||
/**
|
||||
* Import data as ROM module into the subsystem-specific ROM service
|
||||
*/
|
||||
void _import_rom_module(char const *name, void *ptr, Genode::size_t size)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Dataspace_capability ds = _loader.alloc_rom_module(name, size);
|
||||
|
||||
/* fill ROM module with data */
|
||||
char *local_addr = env()->rm_session()->attach(ds);
|
||||
memcpy(local_addr, ptr, size);
|
||||
env()->rm_session()->detach(local_addr);
|
||||
|
||||
_loader.commit_rom_module(name);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Chroot_subsystem(char const *chroot_path, Genode::size_t ram_quota)
|
||||
:
|
||||
_loader(ram_quota)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/*
|
||||
* Generate Genode configuration of the new subsystem and import
|
||||
* it into the subsystem's loader session as a ROM module named
|
||||
* "config".
|
||||
*/
|
||||
char buf[strlen(chroot_path) + strlen(config_template()) + 1];
|
||||
snprintf(buf, sizeof(buf), config_template(), chroot_path);
|
||||
|
||||
_import_rom_module("config", buf, strlen(buf) + 1);
|
||||
|
||||
/*
|
||||
* Name of the Genode binary is start as the root of the new
|
||||
* subsystem.
|
||||
*/
|
||||
char const *chroot_binary_name = "chroot";
|
||||
|
||||
/*
|
||||
* Generate unique label name using a counter
|
||||
*
|
||||
* The label appears in the LOG output of the loaded subsystem.
|
||||
* Technically, it does need to be unique. It is solely used
|
||||
* for validating the test in the run script.
|
||||
*/
|
||||
static int cnt = 0;
|
||||
snprintf(_label, sizeof(_label), "%s-%d", chroot_binary_name, ++cnt);
|
||||
|
||||
/* start execution of new subsystem */
|
||||
_loader.start(chroot_binary_name, Loader::Session::Name(_label));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
Genode::printf("--- chroot-loader test started ---\n");
|
||||
|
||||
static Chroot_subsystem static_subsystem(chroot_path_of_static_test(),
|
||||
2*1024*1024);
|
||||
|
||||
static Timer::Connection timer;
|
||||
|
||||
for (unsigned i = 0; i < 5; i++) {
|
||||
|
||||
PLOG("dynamic test iteration %d", i);
|
||||
|
||||
Chroot_subsystem subsystem(chroot_path_of_dynamic_test(),
|
||||
2*1024*1024);
|
||||
|
||||
/* grant the subsystem one second of life */
|
||||
timer.msleep(1000);
|
||||
|
||||
/*
|
||||
* The local 'dynamic_subsystem' instance will be destructed at the of
|
||||
* the loop body.
|
||||
*/
|
||||
}
|
||||
|
||||
Genode::printf("--- chroot-loader test finished ---\n");
|
||||
return 0;
|
||||
}
|
3
os/src/test/chroot_loader/target.mk
Normal file
3
os/src/test/chroot_loader/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-chroot_loader
|
||||
SRC_CC = main.cc
|
||||
LIBS += cxx env
|
Loading…
x
Reference in New Issue
Block a user