Sculpt for The Curious (TC)

This commit updates Early-Adopters (EA) version of Sculpt to the version
for The Curious (TC). Most importantly, it contains the new interactive
sculpt-manager component that automates many system management and
configuration tasks.
This commit is contained in:
Norman Feske 2018-04-27 16:16:31 +02:00 committed by Christian Helmuth
parent 5d5756d0cb
commit 3dd81b0d32
78 changed files with 6957 additions and 1065 deletions

View File

@ -8,6 +8,7 @@
<rom label="libc.lib.so"/>
<rom label="libm.lib.so"/>
<rom label="vfs_ttf.lib.so"/>
<rom label="Vera.ttf"/>
<rom label="VeraMono.ttf"/>
<rom label="vfs.lib.so"/>
</content>

View File

@ -10,12 +10,8 @@ _/src/fs_report
_/src/nitpicker
_/src/global_keys_handler
_/src/nit_fb
_/src/nit_focus
_/src/nit_fader
_/src/rtc_drv
_/src/top
_/src/trace_subject_reporter
_/src/cpu_load_display
_/src/rom_filter
_/src/terminal_log
_/src/file_terminal
@ -36,8 +32,15 @@ _/src/curl
_/src/libssh
_/src/zlib
_/src/log_core
_/src/depot_deploy
_/src/part_blk
_/src/nic_router
_/src/e2fsprogs-minimal
_/src/nvme_drv
_/src/wm
_/src/themed_decorator
_/src/floating_window_layouter
_/src/libpng
_/src/zlib
_/src/menu_view
_/src/gpt_write
_/src/sculpt_manager

View File

@ -0,0 +1,10 @@
SRC_DIR := src/app/sculpt_manager
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
MIRROR_FROM_REP_DIR := include/depot src/app/depot_deploy
content: $(MIRROR_FROM_REP_DIR)
$(MIRROR_FROM_REP_DIR):
$(mirror_from_rep_dir)

View File

@ -0,0 +1 @@
2018-05-30-b 63bc6b2712d5fe8eccfc797b1c4062b2bd3fd01e

View File

@ -0,0 +1,14 @@
base
os
report_session
file_system_session
nic_session
timer_session
block_session
usb_session
framebuffer_session
platform_session
nitpicker_session
terminal_session
rtc_session
input_session

View File

@ -48,6 +48,10 @@ install_config {
<resource name="RAM" quantum="64M" constrain_phys="yes"/>
<binary name="init"/>
<route>
<service name="ROM" label_last="managed/input_filter">
<parent label="input_filter.config"/> </service>
<service name="ROM" label_last="numlock_remap">
<parent label="numlock_remap.config"/> </service>
<service name="ROM" label="config"> <parent label="drivers.config"/> </service>
<service name="ROM" label="capslock"> <child name="dynamic_rom"/> </service>
<service name="ROM" label="numlock"> <child name="dynamic_rom"/> </service>

View File

@ -0,0 +1,334 @@
create_boot_directory
proc depot_user {} { return [get_cmd_arg --depot-user genodelabs] }
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/[drivers_interactive_pkg] \
[depot_user]/pkg/fonts_fs \
[depot_user]/src/dynamic_rom \
[depot_user]/src/report_rom \
[depot_user]/src/fs_rom \
[depot_user]/src/fs_report \
[depot_user]/src/ram_fs \
[depot_user]/src/nitpicker \
[depot_user]/src/init \
[depot_user]/src/libc \
[depot_user]/src/wm \
[depot_user]/src/themed_decorator \
[depot_user]/src/nit_fb \
[depot_user]/src/nit_fader \
[depot_user]/src/libpng \
[depot_user]/src/zlib \
[depot_user]/src/menu_view \
[depot_user]/src/rom_filter \
[depot_user]/src/noux \
[depot_user]/src/terminal \
[depot_user]/src/posix \
[depot_user]/src/ram_blk \
[depot_user]/src/part_blk \
[depot_user]/src/rump \
[depot_user]/src/ncurses \
[depot_user]/src/usb_block_drv \
[depot_user]/src/bash-minimal \
[depot_user]/src/vim-minimal \
[depot_user]/src/coreutils-minimal \
[depot_user]/src/e2fsprogs-minimal \
[depot_user]/src/gpt_write \
[depot_user]/src/floating_window_layouter
install_config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<resource name="RAM" preserve="2M"/>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="drivers" caps="1000">
<resource name="RAM" quantum="32M" constrain_phys="yes"/>
<binary name="init"/>
<route>
<service name="ROM" label="config"> <parent label="drivers.config"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides>
<service name="Input"/> <service name="Framebuffer"/>
</provides>
</start>
<start name="report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="no">
<policy label="leitzentrale -> manager -> nitpicker_hover"
report="nitpicker -> hover"/>
<policy label="leitzentrale -> manager -> displays"
report="nitpicker -> displays"/>
</config>
</start>
<start name="nitpicker">
<resource name="RAM" quantum="4M"/>
<provides><service name="Nitpicker"/></provides>
<config focus="rom">
<report hover="yes" displays="yes"/>
<background color="#000000"/>
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="default" layer="3" content="client" label="no" hover="always" />
<policy label_prefix="pointer" domain="pointer"/>
<default-policy domain="default"/>
</config>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/></any-service>
</route>
</start>
<start name="pointer">
<resource name="RAM" quantum="1M"/>
<route>
<service name="Nitpicker"> <child name="nitpicker" /> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="config_fs">
<binary name="ram_fs"/>
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system"/> </provides>
<config>
<content>
<dir name="managed">
<rom name="fonts.config" as="fonts"/>
<inline name="runtime"><config/></inline>
<inline name="depot_query"><query/></inline>
</dir>
<inline name="deploy"></inline>
</content>
<default-policy root="/" writeable="yes"/>
</config>
</start>
<start name="config_rom">
<resource name="RAM" quantum="1M"/>
<binary name="fs_rom"/>
<provides> <service name="ROM"/> </provides>
<config/>
<route>
<service name="File_system"> <child name="config_fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="report_fs">
<binary name="ram_fs"/>
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system"/> </provides>
<config>
<default-policy root="/" writeable="yes"/>
</config>
</start>
<start name="fs_report">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> </provides>
<config> <vfs> <fs/> </vfs> </config>
<route>
<service name="File_system"> <child name="report_fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="report_fs_rom">
<resource name="RAM" quantum="1M"/>
<binary name="fs_rom"/>
<provides> <service name="ROM"/> </provides>
<config/>
<route>
<service name="File_system"> <child name="report_fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="leitzentrale_config">
<binary name="rom_filter"/>
<resource name="RAM" quantum="1M"/>
<provides><service name="ROM"/></provides>
<route>
<service name="ROM" label="config">
<parent label="leitzentrale.config"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="usb_active_config_rom">
<binary name="dynamic_rom"/>
<resource name="RAM" quantum="4M"/>
<provides> <service name="ROM"/> </provides>
<config>
<rom name="usb_active_config">
<inline description="USB storage present">
<config>
<raw> <policy label_suffix="usb-1-2" class="storage"/> </raw>
</config>
</inline>
<sleep milliseconds="5000" />
<inline description="USB storage absent">
<config/>
</inline>
<sleep milliseconds="500000" />
</rom>
</config>
</start>
<start name="ahci-1">
<binary name="lx_block"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Block"/> </provides>
<config file="ahci-1.img" block_size="512" writeable="yes"/>
</start>
<start name="ahci-2">
<binary name="ram_blk"/>
<resource name="RAM" quantum="10M"/>
<config nofile="ahci-1.img" size="8M" block_size="512"/>
<provides> <service name="Block"/> </provides>
</start>
<start name="leitzentrale" caps="4000">
<binary name="init"/>
<resource name="RAM" quantum="128M"/>
<provides> <service name="Nitpicker"/> </provides>
<route>
<service name="ROM" label="config">
<child name="leitzentrale_config"/> </service>
<service name="ROM" label_prefix="manager -> config -> ">
<child name="config_rom"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="File_system" label="config">
<child name="config_fs" label="rw"/> </service>
<service name="File_system" label="report">
<child name="report_fs" label="rw"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="ROM" label_last="drivers/block_devices">
<parent label="block_devices"/> </service>
<service name="ROM" label_last="drivers/usb_active_config">
<child name="usb_active_config_rom" label="usb_active_config"/> </service>
<service name="ROM" label_last="runtime/state">
<child name="report_fs_rom" label="runtime/state"/> </service>
<service name="ROM" label_last="deploy">
<child name="config_rom"/> </service>
<service name="ROM" label_last="managed/fonts">
<child name="config_rom" label="managed/fonts"/> </service>
<service name="ROM" label_prefix="manager -> report">
<child name="report_fs_rom"/> </service>
<service name="ROM" label="manager -> nitpicker_hover">
<child name="report_rom"/> </service>
<service name="ROM" label="manager -> displays">
<child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="runtime" caps="50000">
<binary name="init"/>
<resource name="RAM" quantum="1G"/>
<route>
<service name="ROM" label="config">
<child name="config_rom" label="managed/runtime"/> </service>
<service name="ROM" label_prefix="config -> ">
<child name="config_rom"/> </service>
<service name="File_system" label="config">
<child name="config_fs" label="rw"/> </service>
<service name="File_system" label="report">
<child name="report_fs" label="ro"/> </service>
<service name="Block" label_last="ahci-1"> <child name="ahci-1"/> </service>
<service name="Block" label_last="ahci-2"> <child name="ahci-2"/> </service>
<service name="Block"> <child name="drivers"/> </service>
<service name="Usb"> <child name="drivers"/> </service>
<service name="Nitpicker" label_prefix="leitzentrale">
<child name="leitzentrale"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>}
file copy -force [genode_dir]/repos/gems/recipes/raw/fonts_fs/fonts_fs.config [run_dir]/genode/fonts.config
file copy -force [genode_dir]/repos/gems/run/sculpt/leitzentrale.config [run_dir]/genode/
file copy -force [genode_dir]/repos/gems/run/sculpt/vimrc [run_dir]/genode/
file copy -force [genode_dir]/repos/gems/src/app/backdrop/genode_logo.png [run_dir]/genode/
proc install_rom_module { name content } {
set fd [open [run_dir]/genode/$name w]
puts $fd $content
close $fd
}
# generate disk image with GPT partition table
proc ahci_1_img { } { return "bin/ahci-1.img" }
catch { exec dd if=/dev/zero of=[ahci_1_img] bs=1M count=10 }
exec parted -a none -s [ahci_1_img] -- mklabel gpt \
mkpart BOOT fat32 256s 1023s \
mkpart GRUB fat32 1024s 1279s \
mkpart GENODE ext2 1280s 3700s
install_rom_module focus {<focus label="leitzentrale -> manager -> fader -> "/>}
install_rom_module leitzentrale {<leitzentrale enabled="yes"/>}
install_rom_module reset {<reset enabled="no"/>}
install_rom_module README {nothing to read here}
install_rom_module VERSION {unknown version}
install_rom_module block_devices {
<block_devices>
<device label="ahci-1" block_count="123" block_size="1024" model="Model"/>
<device label="ahci-2" block_count="123" block_size="1024" model="Broken"/>
</block_devices>}
install_rom_module usb_active_config {
<config>
<raw> <policy label_suffix="usb-1-2" class="storage"/> </raw>
</config>}
build { server/lx_block app/menu_view app/sculpt_manager }
build_boot_image { lx_block menu_view sculpt_manager ahci-1.img }
if {[have_spec linux]} {
set max_fds [exec bash -c "ulimit -n"]
if {$max_fds < 4096} {
puts stderr "\nMaximum number of file descriptors is too low for this run script."
puts stderr "You may use the following command to increase the limit:\n"
puts stderr " ulimit -n 4096\n"
exit 1
}
}
run_genode_until forever

View File

@ -11,16 +11,9 @@ import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/sculpt
proc config_system_content {} { return {\
<!-- set 'state' value to "reset" to reboot the machine -->
<system state=""/>} }
proc config_trace_subject_reporter_content {} { return {\
<config period_ms="2000">
<report activity="yes" affinity="yes"/>
</config>} }
install_config {
<config prio_levels="4"> <!-- set prio_levels to 4 -->
<parent-provides>
@ -48,21 +41,6 @@ install_config {
<provides><service name="Timer"/></provides>
</start>
<start name="top">
<resource name="RAM" quantum="2M"/>
<config period_ms="60000"/>
</start>
<start name="trace_subject_reporter" >
<resource name="RAM" quantum="24M"/>
<route>
<service name="ROM" label="config">
<child name="config_rom" label="trace_subject_reporter.config"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/>
@ -70,25 +48,24 @@ install_config {
<config verbose="no">
<policy label="leitzentrale_config -> leitzentrale"
report="global_keys_handler -> leitzentrale"/>
<policy label="leitzentrale_config -> reset"
report="global_keys_handler -> reset"/>
<policy label="leitzentrale -> trace_subjects"
report="trace_subject_reporter -> trace_subjects"/>
<policy label="leitzentrale -> manager -> nitpicker_hover"
report="nitpicker -> hover"/>
<policy label="pointer -> hover" report="nitpicker -> hover"/>
<policy label="pointer -> xray"
report="global_keys_handler -> leitzentrale"/>
<policy label="pointer -> shape" report="shape"/>
<policy label="pointer -> shape" report="shape"/>
<policy label="drivers -> capslock" report="global_keys_handler -> capslock"/>
<policy label="runtime -> capslock" report="global_keys_handler -> capslock"/>
<policy label="drivers -> numlock" report="global_keys_handler -> numlock"/>
<policy label="runtime -> clicked" report="nitpicker -> clicked"/>
<policy label="nit_focus -> focus" report="runtime -> focus"/>
<policy label="runtime -> clicked" report="nitpicker -> clicked"/>
<policy label="nit_focus -> leitzentrale"
report="global_keys_handler -> leitzentrale"/>
<policy label="nit_focus -> slides"
report="global_keys_handler -> slides"/>
<policy label="slides_nit_fb_config -> slides"
report="global_keys_handler -> slides"/>
<policy label="leitzentrale -> manager -> displays"
report="nitpicker -> displays"/>
</config>
</start>
@ -105,67 +82,35 @@ install_config {
<provides> <service name="File_system"/> </provides>
<config>
<content>
<rom name="fb_drv.config"/>
<rom name="nitpicker.config"/>
<rom name="fonts.config"/>
<rom name="input_filter.config"/>
<dir name="managed">
<rom name="fonts.config" as="fonts"/>
<rom name="fb_drv.config" as="fb_drv"/>
<rom name="wlan.config" as="wlan"/>
<rom name="installation"/>
<rom name="empty_runtime.config" as="runtime"/>
<rom name="input_filter.config" as="input_filter"/>
<inline name="depot_query"><query/></inline>
</dir>
<rom name="input_filter.config" as="input_filter"/>
<rom name="fb_drv.config" as="fb_drv"/>
<rom name="nitpicker.config" as="nitpicker"/>
<rom name="numlock_remap.config" as="numlock_remap"/>
<rom name="leitzentrale.config" as="leitzentrale"/>
<rom name="drivers.config" as="drivers"/>
<rom name="manual_deploy.config" as="deploy"/>
<rom name="en_us.chargen"/>
<rom name="de.chargen"/>
<rom name="special.chargen"/>
<rom name="numlock_remap.config"/>
<rom name="vimrc"/>
<rom name="wlan.config"/>
<rom name="installation"/>
<dir name="leitzentrale">
<rom name="leitzentrale.config" as="config"/>
</dir>
<dir name="examples">
<dir name="vm">
<dir name="debian">
<rom name="machine.vbox"/>
<rom name="machine.vdi"/>
</dir>
</dir>
<dir name="depot">
<dir name="} [depot_user ] {">
<rom name="} [depot_user] {_pubkey" as="pubkey"/>
<rom name="} [depot_user] {_download" as="download"/>
</dir>
</dir>
</dir>
<dir name="drivers">
<rom name="drivers.config" as="config"/>
</dir>
<dir name="runtime">
<rom name="empty_runtime.config" as="config"/>
<rom name="empty_runtime.config" as="empty.config" />
<rom name="block_runtime.config" as="block.config" />
<rom name="load_runtime.config" as="load.config" />
<rom name="fs_runtime.config" as="fs.config" />
<rom name="download_runtime.config" as="download.config" />
<rom name="update_runtime.config" as="update.config" />
<rom name="deploy_runtime.config" as="deploy.config" />
</dir>
<dir name="subinit">
<rom name="default_fs_subinit.config" as="default_fs.config" />
<rom name="default_nic_subinit.config" as="default_nic.config" />
<rom name="default_noux_subinit.config" as="default_noux.config" />
<rom name="depot_download.config"/>
</dir>
<dir name="deploy">
<rom name="deploy.config" as="config"/>
</dir>
<inline name="trace_subject_reporter.config">} [config_trace_subject_reporter_content] {
</inline>
<inline name="system">} [config_system_content] {
</inline>
</content>
<policy label="config_rom -> " root="/" />
<policy label="config_fs_rom -> " root="/" />
<policy label="rw" root="/" writeable="yes" />
</config>
</start>
<start name="config_rom">
<start name="config_fs_rom">
<binary name="fs_rom"/>
<resource name="RAM" quantum="10M"/>
<provides> <service name="ROM"/> </provides>
@ -175,6 +120,16 @@ install_config {
</route>
</start>
<start name="report_fs_rom">
<binary name="fs_rom"/>
<resource name="RAM" quantum="3M"/>
<provides> <service name="ROM"/> </provides>
<route>
<service name="File_system"> <child name="report_fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="report_fs">
<binary name="ram_fs"/>
<resource name="RAM" quantum="16M"/>
@ -182,10 +137,21 @@ install_config {
<config>
<content>
<inline name="log">### start ###</inline>
<dir name="runtime">
<inline name="state"><empty/></inline>
<dir name="wifi_drv">
<inline name="wlan_accesspoints"><empty/></inline>
<inline name="wlan_state"> <empty/> </inline>
</dir>
<dir name="nic_router"> <inline name="state"> <empty/></inline> </dir>
<dir name="update"> <inline name="state"> <empty/></inline> </dir>
<dir name="depot_query"><inline name="blueprint"><empty/></inline> </dir>
</dir>
</content>
<policy label="fs_report -> " root="/" writeable="yes" />
<policy label="log_terminal -> " root="/" writeable="yes" />
<policy label="ro" root="/" />
<policy label="fs_report -> " root="/" writeable="yes"/>
<policy label="log_terminal -> " root="/" writeable="yes"/>
<policy label="report_fs_rom -> " root="/"/>
<policy label="ro" root="/"/>
</config>
</start>
@ -242,15 +208,15 @@ install_config {
<route>
<service name="LOG"> <child name="log"/> </service>
<service name="ROM" label="config">
<child name="config_rom" label="drivers/config"/> </service>
<service name="ROM" label="input_filter.config"> <child name="config_rom"/> </service>
<service name="ROM" label="numlock_remap.config"> <child name="config_rom"/> </service>
<service name="ROM" label_suffix=".chargen"> <child name="config_rom"/> </service>
<service name="ROM" label_suffix=".remap"> <child name="config_rom"/> </service>
<service name="ROM" label="capslock"> <child name="report_rom"/> </service>
<service name="ROM" label="numlock"> <child name="report_rom"/> </service>
<service name="ROM" label="system"> <child name="config_rom"/> </service>
<service name="ROM" label_suffix="fb_drv.config"> <child name="config_rom"/> </service>
<child name="config_fs_rom" label="drivers"/> </service>
<service name="ROM" label_last="capslock"> <child name="report_rom"/> </service>
<service name="ROM" label_last="input_filter.config">
<child name="config_fs_rom" label="managed/input_filter"/> </service>
<service name="ROM" label_last="fb_drv.config">
<child name="config_fs_rom" label="managed/fb_drv"/> </service>
<service name="ROM" label_last="numlock_remap.config">
<child name="config_fs_rom" label="numlock_remap"/> </service>
<service name="ROM" label_last="numlock"> <child name="report_rom"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<any-service> <parent/> </any-service>
@ -269,7 +235,7 @@ install_config {
<provides><service name="Nitpicker"/></provides>
<route>
<service name="ROM" label="config">
<child name="config_rom" label="nitpicker.config"/> </service>
<child name="config_fs_rom" label="nitpicker"/> </service>
<service name="ROM" label="focus">
<child name="nit_focus"/> </service>
<service name="Report" label="keystate">
@ -292,13 +258,11 @@ install_config {
<attribute name="enabled" /> </input>
<input name="slides_enabled" rom="slides" node="slides">
<attribute name="enabled" /> </input>
<input name="runtime_focus" rom="focus" node="focus">
<attribute name="label"/> </input>
<output node="focus">
<if>
<has_value input="leitzentrale_enabled" value="yes" />
<then>
<attribute name="label" value="leitzentrale -> control_fader -> "/>
<attribute name="label" value="leitzentrale -> manager -> fader -> "/>
</then>
<else>
<if>
@ -307,7 +271,7 @@ install_config {
<attribute name="label" value="slides"/>
</then>
<else>
<attribute name="label" input="runtime_focus"/>
<attribute name="label" value="runtime -> focus"/>
</else>
</if>
</else>
@ -316,7 +280,6 @@ install_config {
</config>
<route>
<service name="ROM" label="leitzentrale"> <child name="report_rom"/> </service>
<service name="ROM" label="focus"> <child name="report_rom"/> </service>
<service name="ROM" label="slides"> <child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
@ -338,20 +301,16 @@ install_config {
<resource name="RAM" quantum="1M"/>
<config>
<bool name="leitzentrale" initial="yes"/>
<bool name="reset" initial="no"/>
<bool name="capslock" initial="no"/>
<bool name="numlock" initial="no"/>
<bool name="slides" initial="no"/>
<press name="KEY_PRESENTATION" bool="slides" change="toggle"/>
<press name="KEY_RESTART" bool="reset" change="on"/>
<release name="KEY_RESTART" bool="reset" change="off"/>
<press name="KEY_DASHBOARD" bool="leitzentrale" change="toggle"/>
<press name="KEY_CAPSLOCK" bool="capslock" change="toggle"/>
<press name="KEY_NUMLOCK" bool="numlock" change="toggle"/>
<press name="KEY_PRESENTATION" bool="slides" change="toggle"/>
<press name="KEY_DASHBOARD" bool="leitzentrale" change="toggle"/>
<press name="KEY_CAPSLOCK" bool="capslock" change="toggle"/>
<press name="KEY_NUMLOCK" bool="numlock" change="toggle"/>
<report name="leitzentrale"> <bool name="leitzentrale"/> </report>
<report name="reset"> <bool name="reset"/> </report>
<report name="capslock"> <bool name="capslock"/> </report>
<report name="numlock"> <bool name="numlock"/> </report>
<report name="slides"> <bool name="slides"/> </report>
@ -370,33 +329,39 @@ install_config {
<provides><service name="ROM"/></provides>
<route>
<service name="ROM" label="leitzentrale"> <child name="report_rom"/> </service>
<service name="ROM" label="reset"> <child name="report_rom"/> </service>
<service name="ROM" label="config">
<child name="config_rom" label="leitzentrale/config"/> </service>
<child name="config_fs_rom" label="leitzentrale"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="leitzentrale" caps="2000" priority="-2">
<start name="leitzentrale" caps="4000" priority="-2">
<binary name="init"/>
<resource name="RAM" quantum="128M"/>
<provides> <service name="Nitpicker"/> </provides>
<route>
<service name="LOG"> <child name="log"/> </service>
<service name="ROM" label="config">
<child name="leitzentrale_config"/> </service>
<service name="ROM" label_last="vimrc">
<child name="config_rom"/> </service>
<service name="ROM" label_last="fonts.config">
<child name="config_rom"/> </service>
<service name="ROM" label="trace_subjects">
<service name="ROM" label_prefix="report -> ">
<child name="report_fs_rom"/> </service>
<service name="ROM" label_prefix="manager -> report -> ">
<child name="report_fs_rom"/> </service>
<service name="ROM" label_prefix="manager -> config -> ">
<child name="config_fs_rom"/> </service>
<service name="ROM" label_prefix="manager -> displays">
<child name="report_rom"/> </service>
<service name="ROM" label_prefix="config -> ">
<child name="config_fs_rom"/> </service>
<service name="ROM" label="manager -> nitpicker_hover">
<child name="report_rom"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="File_system" label="control_noux -> config">
<service name="File_system" label="config">
<child name="config_fs" label="rw"/> </service>
<service name="File_system" label="control_noux -> report">
<service name="File_system" label="report">
<child name="report_fs" label="ro"/> </service>
<service name="File_system" label="log_noux -> report">
<service name="File_system" label="report">
<child name="report_fs" label="ro"/> </service>
<any-service> <parent/> </any-service>
</route>
@ -409,16 +374,12 @@ install_config {
<start name="runtime" caps="50000" priority="-3">
<binary name="init"/>
<resource name="RAM" quantum="12G"/>
<resource name="RAM" quantum="32G"/>
<route>
<service name="ROM" label="config">
<child name="config_rom" label="runtime/config"/> </service>
<child name="config_fs_rom" label="managed/runtime"/> </service>
<service name="ROM" label_prefix="config -> ">
<child name="config_rom"/> </service>
<service name="ROM" label_suffix="-> vimrc">
<child name="config_rom" label="vimrc"/> </service>
<service name="ROM" label="system">
<child name="config_rom"/> </service>
<child name="config_fs_rom"/> </service>
<service name="ROM" label="capslock">
<child name="report_rom"/> </service>
<service name="ROM" label="clicked">
@ -432,12 +393,13 @@ install_config {
<service name="Platform" label_prefix="acpica">
<child name="drivers" label="acpica"/> </service>
<service name="Platform"> <child name="drivers"/> </service>
<service name="Nitpicker" label_prefix="leitzentrale">
<child name="leitzentrale"/> </service>
<service name="Nitpicker" label="backdrop">
<child name="nitpicker" label="backdrop"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="Report" label_suffix="-> shape"> <child name="pointer"/> </service>
<service name="Report" label="focus"> <child name="report_rom"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="LOG" label="unlogged"> <parent/> </service>
<service name="LOG"> <child name="log"/> </service>
@ -481,11 +443,10 @@ file copy -force [genode_dir]/repos/gems/recipes/raw/drivers_managed-pc/input_fi
file copy -force [genode_dir]/repos/gems/recipes/raw/depot_download/depot_download.config \
[run_dir]/genode/depot_download.config
file copy -force [genode_dir]/depot/[depot_user]/pubkey [run_dir]/genode/[depot_user]_pubkey
file copy -force [genode_dir]/depot/[depot_user]/download [run_dir]/genode/[depot_user]_download
file copy -force [genode_dir]/VERSION [run_dir]/genode/
file copy -force [genode_dir]/repos/gems/src/app/backdrop/genode_logo.png [run_dir]/genode/
exec gzip -dc [genode_dir]/repos/gems/run/sculpt/machine.vdi.gz > [run_dir]/genode/machine.vdi
@ -502,21 +463,23 @@ close $fd
#
# Package-management support
#
# The package management has two aspects, installation and deployment.
# Packages are installed via the 'install' runtime, which takes the
# information about the packages to install from 'config/installation'.
# Once installed, packages can be deployed via the 'deploy' runtime.
# This runtime can be tailored by modifying 'config/deploy/config'.
# Assemble 'depot_users.tar' with the keys and download locations of the
# depot user found at genode/depot/.
#
set depot_users_files [exec sh -c "cd [genode_dir]; \
find depot -maxdepth 3 -name pubkey \
-or -name download"]
exec sh -c "tar cf [run_dir]/genode/depot_users.tar -C [genode_dir] \
[join $depot_users_files]"
proc current_pkg { pkg } { return $pkg/[_current_depot_archive_version pkg $pkg] }
#
# Depot packages to be included in the default installation
#
set pkgs_to_install { sculpt-installation }
proc current_pkg { pkg } { return $pkg/[_current_depot_archive_version pkg $pkg] }
set pkgs_to_install { }
set fd [open [run_dir]/genode/installation w]
puts $fd "<installation arch=\"[depot_spec]\">"
@ -525,32 +488,17 @@ foreach pkg $pkgs_to_install {
puts $fd "</installation>"
close $fd
#
# Configuration of deploy runtime
# Manual configuration of deploy runtime
#
# This configuration is not provided as a file at run/sculpt/ because some
# parts need to be filled in at run-script execution time, in particular the
# current versions of the packages to deploy.
#
append depot_deploy_config {
append manual_deploy_config {
<config arch="} [depot_spec] {">
<static>
<parent-provides>
<service name="ROM"/>
<service name="CPU"/>
<service name="PD"/>
<service name="RM"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="Nitpicker"/>
<service name="File_system"/>
<service name="Rtc"/>
<service name="Usb"/>
<service name="Report"/>
<service name="Block"/>
<service name="Platform"/>
</parent-provides>
</static>
<common_routes>
<service name="ROM" label_last="ld.lib.so"> <parent/> </service>
<service name="ROM" label_last="init"> <parent/> </service>
@ -560,30 +508,16 @@ append depot_deploy_config {
<service name="Timer"> <parent/> </service>
</common_routes>
<start name="focus_rom" pkg="} [depot_user]/pkg/[current_pkg rom_filter] {">
<config>
<output node="focus">
<attribute name="label" value="runtime -> dynamic -> wm -> wm -> "/>
</output>
</config>
</start>
<start name="focus_reporter" pkg="} [depot_user]/pkg/[current_pkg rom_reporter] {">
<config> <rom label="focus"/> </config>
<route>
<service name="ROM" label="focus"> <child name="focus_rom"/> </service>
<service name="Report" label="focus"> <parent label="focus"/> </service>
</route>
</start>
<!--
<start name="fonts_fs" pkg="} [depot_user]/pkg/[current_pkg fonts_fs] {">
<route>
<service name="ROM" label="config"> <parent label="fonts.config"/> </service>
<service name="ROM" label="config"> <parent label="config -> managed/fonts"/> </service>
</route>
</start>
<start name="wm" pkg="} [depot_user]/pkg/[current_pkg themed_wm] {">
<route>
<service name="Nitpicker" label="wm -> "> <parent label="focus"/> </service>
<service name="Nitpicker"> <parent/> </service>
</route>
</start>
@ -593,7 +527,17 @@ append depot_deploy_config {
<service name="Nitpicker"> <parent label="backdrop"/> </service>
</route>
</start>
-->
<!--
<start name="nano3d" pkg="} [depot_user]/pkg/[current_pkg nano3d] {">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</start>
-->
<!--
<start name="noux" pkg="} [depot_user]/pkg/[current_pkg noux-system] {">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
@ -604,61 +548,17 @@ append depot_deploy_config {
<service name="File_system" label="fonts">
<child name="fonts_fs"/> </service>
<service name="File_system" label="target">
<parent label="rw"/> </service>
<service name="ROM" label="vimrc"> <parent/> </service>
<child name="default_fs_rw"/> </service>
<service name="ROM" label_last="vimrc">
<parent label="config -> vimrc"/> </service>
</route>
</start>
-->
<!--
<start name="nano3d" pkg="} [depot_user]/pkg/[current_pkg nano3d] {">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</start>
-->
<!--
<start name="nic_drv" pkg="} [depot_user]/pkg/[current_pkg wifi] {">
<route>
<service name="Platform"> <parent label="wifi"/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Report"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="ROM" label="wlan_configuration">
<parent label="wlan.config"/> </service>
</route>
</start>
-->
<!--
<start name="nic_drv" pkg="} [depot_user]/pkg/[current_pkg ipxe_nic_drv] {">
<route>
<service name="Platform"> <parent label="nic"/> </service>
<service name="Report"> <parent/> </service>
<service name="RM"> <parent/> </service>
</route>
</start>
-->
<!--
<start name="nic_router" pkg="} [depot_user]/pkg/[current_pkg nic_router-nat] {">
<route>
<service name="Nic"> <child name="nic_drv"/> </service>
</route>
</start>
-->
<!--
<start name="vm_fs" pkg="} [depot_user]/pkg/[current_pkg chroot] {">
<route>
<service name="File_system"> <parent label="rw"/> </service>
</route>
<config> <default-policy path="/vm/debian" writeable="yes"/> </config>
</start>
<start name="shared_fs" pkg="} [depot_user]/pkg/[current_pkg chroot] {">
<route>
<service name="File_system"> <parent label="rw"/> </service>
<service name="File_system"> <child name="default_fs_rw"/> </service>
</route>
<config> <default-policy path="/shared" writeable="yes"/> </config>
</start>
@ -671,8 +571,17 @@ append depot_deploy_config {
</output>
</config>
</start>
-->
<start name="vm" pkg="} [depot_user]/pkg/[current_pkg vbox5-nova-sculpt] {">
<!--
<start name="vm_fs" pkg="} [depot_user]/pkg/[current_pkg chroot] {">
<route>
<service name="File_system"> <child name="default_fs_rw"/> </service>
</route>
<config> <default-policy path="/vm/debian" writeable="yes"/> </config>
</start>
<start name="vm" ram="4300M" pkg="} [depot_user]/pkg/[current_pkg vbox5-nova-sculpt] {">
<route>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
@ -690,10 +599,79 @@ append depot_deploy_config {
</start>
-->
<!--
<start name="download_debian" pkg="cnuke/pkg/download_debian/2018-05-30">
<route>
<service name="File_system" label="fonts"> <child name="fonts_fs"/> </service>
<service name="File_system" label="target"> <child name="vm_fs"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="RM"> <parent/> </service>
</route>
</start>
-->
<!--
<start name="top_view" pkg="alex-ab/pkg/top_view/2018-05-29-a">
<route>
<service name="TRACE"> <parent/> </service>
<service name="Timer"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="File_system" label="fonts">
<child name="fonts_fs"/> </service>
</route>
</start>
-->
<!--
<start name="2048" pkg="ehmry/pkg/2048/18.05">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</start>
-->
<!--
<start name="vbox5-tc-browser" pkg="alex-ab/pkg/vbox5-tc-firefox-nova-sculpt/2018-05-30">
<route>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> vm -> shape"/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="File_system" label="shared"> <child name="shared_fs"/> </service>
</route>
</start>
-->
<!--
<start name="seoul-vmm-browser" pkg="alex-ab/pkg/seoul-nova-sculpt/2018-05-30">
<route>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
</route>
</start>
-->
<!--
<start name="qt5_textedit" pkg="cproc/pkg/qt5_textedit/2018-05-30">
<route>
<service name="File_system" label="rw"> <parent label="config"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> qt5_textedit -> shape"/> </service>
</route>
</start>
-->
</config>}
set fd [open [run_dir]/genode/deploy.config w]
puts $fd $depot_deploy_config
set fd [open [run_dir]/genode/manual_deploy.config w]
puts $fd $manual_deploy_config
close $fd

View File

@ -1,72 +0,0 @@
<config>
<report init_ram="yes" child_ram="yes" delay_ms="4000"/>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Nitpicker"/>
<service name="Timer"/>
<service name="Report"/>
<service name="Block"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="nit_focus">
<resource name="RAM" quantum="1M"/>
<config>
<policy label_prefix="leitzentrale" focus="no"/>
<default-policy focus="yes"/>
</config>
<route>
<service name="ROM" label="clicked"> <parent label="clicked"/> </service>
<service name="Report" label="focus"> <parent label="focus"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="nit_fb">
<resource name="RAM" quantum="4M"/>
<provides> <service name="Framebuffer"/> <service name="Input"/> </provides>
<config xpos="200" ypos="50" width="800" height="600"/>
</start>
<start name="terminal">
<binary name="terminal"/>
<resource name="RAM" quantum="4M"/>
<provides> <service name="Terminal"/> </provides>
<route>
<service name="ROM" label="config"> <parent label="config -> fonts.config"/> </service>
<service name="Framebuffer"> <child name="nit_fb"/> </service>
<service name="Input"> <child name="nit_fb"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="noux" caps="500">
<binary name="noux"/>
<resource name="RAM" quantum="100M" />
<config>
<fstab>
<tar name="bash-minimal.tar" />
<tar name="coreutils-minimal.tar" />
<tar name="vim-minimal.tar" />
<tar name="e2fsprogs-minimal.tar" />
<dir name="dev">
<zero/> <null/>
<block name="block" label="default" block_buffer_count="128"/>
</dir>
</fstab>
<start name="/bin/bash">
<env name="TERM" value="screen" />
<env name="PS1" value="block:$PWD> " />
</start>
</config>
</start>
</config>

View File

@ -1,47 +0,0 @@
<config>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="Block"/>
</parent-provides>
<default-route> <any-service> <parent/> </any-service> </default-route>
<service name="File_system">
<default-policy> <child name="vfs"/> </default-policy> </service>
<start name="vfs" caps="400">
<resource name="RAM" quantum="100M" />
<provides> <service name="File_system"/> </provides>
<config>
<vfs> <rump fs="ext2fs" ram="48M" writeable="yes"/> </vfs>
<default-policy root="/" writeable="yes"/>
</config>
<route>
<service name="Block"> <parent label="default"/> </service>
<!--
<service name="Block"> <child name="part_blk"/> </service>
-->
<any-service> <parent/> </any-service>
</route>
</start>
<!--
<start name="part_blk" caps="100">
<resource name="RAM" quantum="10M"/>
<provides><service name="Block"/></provides>
<config use_gpt="yes">
<policy label_prefix="vfs" partition="1" writeable="yes"/>
</config>
<route>
<service name="Block"> <parent label="default"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
-->
</config>

View File

@ -1,54 +0,0 @@
<config>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="Platform"/>
<service name="Report"/>
<service name="Rtc"/>
</parent-provides>
<default-route> <any-service> <parent/> </any-service> </default-route>
<service name="Nic">
<default-policy> <child name="nic"/> </default-policy> </service>
<!-- wifi driver (default) -->
<start name="nic" caps="300">
<binary name="wifi_drv" />
<resource name="RAM" quantum="54M"/>
<provides> <service name="Nic"/> </provides>
<config ld_verbose="yes" verbose="yes" use_11n="no" connected_scan_interval="0">
<vfs>
<dir name="dev"> <log/> <rtc/> <null/>
<jitterentropy name="random"/>
<jitterentropy name="urandom"/>
</dir>
<dir name="config"> <ram/> </dir>
</vfs>
<libc stdout="/dev/null" stderr="/dev/log" rtc="/dev/rtc"/>
</config>
<route>
<service name="ROM" label="wlan_configuration">
<parent label="wlan.config"/> </service>
<service name="Platform"> <parent label="wifi"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<!-- uncomment for wired NIC driver -->
<!-- <start name="nic" caps="300">
<binary name="nic_drv" />
<resource name="RAM" quantum="16M"/>
<provides> <service name="Nic"/> </provides>
<config />
<route>
<service name="Platform"> <parent label="nic"/> </service>
<any-service> <parent/> </any-service>
</route>
</start> -->
</config>

View File

@ -1,63 +0,0 @@
<config>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="File_system"/>
<service name="Nitpicker"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="nit_fb">
<resource name="RAM" quantum="4M"/>
<provides> <service name="Framebuffer"/> <service name="Input"/> </provides>
<config xpos="10" ypos="10" width="800" height="600"/>
</start>
<start name="terminal">
<binary name="terminal"/>
<resource name="RAM" quantum="4M"/>
<provides> <service name="Terminal"/> </provides>
<route>
<service name="ROM" label="config"> <parent label="fonts.config"/> </service>
<service name="Framebuffer"> <child name="nit_fb"/> </service>
<service name="Input"> <child name="nit_fb"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="noux" caps="500">
<binary name="noux"/>
<resource name="RAM" quantum="64M" />
<exit propagate="yes"/>
<config>
<fstab>
<tar name="bash-minimal.tar" />
<tar name="coreutils-minimal.tar" />
<tar name="vim-minimal.tar" />
<dir name="dev"> <zero/> <null/> </dir>
<dir name="rw"> <fs label="target"/> </dir>
<dir name="config"> <fs label="config"/> </dir>
<dir name="tmp"> <ram /> </dir>
<dir name="share"> <dir name="vim"> <rom name="vimrc"/> </dir> </dir>
</fstab>
<start name="/bin/bash">
<env name="TERM" value="screen" />
<env name="PS1" value="noux:$PWD> " />
</start>
</config>
<route>
<service name="File_system" label="target"> <parent label="target"/> </service>
<service name="File_system" label="config"> <parent label="config"/> </service>
<service name="Terminal"> <child name="terminal"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>

View File

@ -1,119 +0,0 @@
<config verbose="no" prio_levels="2">
<report init_ram="yes" requested="yes" child_ram="yes" delay_ms="2000" buffer="128K"/>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Nitpicker"/>
<service name="Timer"/>
<service name="Block"/>
<service name="Report"/>
<service name="Rtc"/>
<service name="Usb"/>
<service name="File_system"/>
<service name="Platform"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="fs" caps="500">
<resource name="RAM" quantum="114M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_fs.config"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides> <service name="File_system"/> <service name="Block"/> </provides>
</start>
<start name="depot_fs" priority="0">
<binary name="chroot"/>
<resource name="RAM" quantum="1M" />
<provides> <service name="File_system"/> </provides>
<config> <default-policy path="/depot"/> </config>
<route>
<service name="File_system"> <child name="fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="no">
<policy label="depot_deploy -> blueprint" report="depot_query -> blueprint"/>
<policy label="depot_query -> query" report="depot_deploy -> query"/>
<policy label="dynamic -> config" report="depot_deploy -> init.config"/>
</config>
</start>
<start name="depot_rom">
<binary name="fs_rom"/>
<resource name="RAM" quantum="80M"/>
<provides> <service name="ROM"/> </provides>
<route>
<service name="File_system"> <child name="depot_fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="depot_query">
<resource name="RAM" quantum="1M"/>
<config query="rom">
<vfs> <dir name="depot"> <fs/> </dir> </vfs>
</config>
<route>
<service name="ROM" label="query"> <child name="report_rom"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="File_system"> <child name="depot_fs"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="depot_deploy">
<resource name="RAM" quantum="1M"/>
<route>
<service name="ROM" label="config">
<parent label="config -> deploy/config"/> </service>
<service name="ROM" label="blueprint"> <child name="report_rom"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="dynamic" caps="30000">
<resource name="RAM" quantum="12G"/>
<binary name="init"/>
<route>
<service name="ROM" label_last="ld.lib.so"> <parent/> </service>
<service name="ROM" label_last="init"> <parent/> </service>
<service name="ROM" label_last="vimrc"> <parent/> </service>
<service name="ROM" label_last="slides.pdf"> <parent/> </service>
<service name="ROM" label_last="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label_last="platform_info"> <parent/> </service>
<service name="ROM" label_last="wlan.config">
<parent label="config -> wlan.config"/> </service>
<service name="ROM" label_last="fonts.config">
<parent label="config -> fonts.config"/> </service>
<service name="ROM" label="config"> <child name="report_rom"/> </service>
<service name="ROM" label="clicked"> <parent label="clicked"/> </service>
<service name="ROM"> <child name="depot_rom"/> </service>
<service name="Report" label="focus"> <parent label="focus"/> </service>
<service name="Nitpicker" label="backdrop"> <parent label="backdrop"/> </service>
<service name="File_system" label="config"> <parent label="config"/> </service>
<service name="File_system" label="report"> <parent label="report"/> </service>
<service name="File_system" label="rw"> <child name="fs"/> </service>
<service name="Block" label_prefix="default"> <child name="fs"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>

View File

@ -1,144 +0,0 @@
<config verbose="yes" prio_levels="2">
<report init_ram="yes" requested="yes" child_ram="yes" delay_ms="2000" buffer="128K"/>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Nitpicker"/>
<service name="Timer"/>
<service name="Block"/>
<service name="Report"/>
<service name="Rtc"/>
<service name="File_system"/>
<service name="Platform"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="nit_focus">
<resource name="RAM" quantum="1M"/>
<config>
<policy label_prefix="leitzentrale" focus="no"/>
<default-policy focus="yes"/>
</config>
<route>
<service name="ROM" label="clicked"> <parent label="clicked"/> </service>
<service name="Report" label="focus"> <parent label="focus"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="fs" caps="500">
<resource name="RAM" quantum="114M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_fs.config"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides> <service name="File_system"/> </provides>
</start>
<start name="noux" caps="1000">
<resource name="RAM" quantum="80M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_noux.config"/> </service>
<service name="ROM" label="fonts.config">
<parent label="config -> fonts.config"/> </service>
<service name="File_system" label="config">
<parent label="config"/> </service>
<service name="File_system" label="target">
<child name="fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="nic" caps="500">
<resource name="RAM" quantum="60M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_nic.config"/> </service>
<service name="ROM" label="wlan.config">
<parent label="config -> wlan.config"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides> <service name="Nic"/> </provides>
</start>
<start name="nic_router" caps="300">
<resource name="RAM" quantum="10M"/>
<provides><service name="Nic"/></provides>
<config verbose_domain_state="yes">
<default-policy domain="default" />
<domain name="uplink">
<nat domain="default" tcp-ports="1000" udp-ports="1000"/>
</domain>
<domain name="default" interface="10.0.1.1/24">
<dhcp-server ip_first="10.0.1.2"
ip_last="10.0.1.200"
ip_lease_time_sec="360"
dns_server="1.1.1.1"/>
<tcp dst="0.0.0.0/0"><permit-any domain="uplink"/></tcp>
<udp dst="0.0.0.0/0"><permit-any domain="uplink"/></udp>
</domain>
</config>
<route>
<service name="Nic"> <child name="nic"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<!--
<start name="download_fs">
<binary name="chroot"/>
<resource name="RAM" quantum="1M" />
<provides> <service name="File_system"/> </provides>
<config> <default-policy path="/vm/debian" writeable="yes"/> </config>
<route>
<service name="File_system"> <child name="fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="fetchurl" caps="500">
<resource name="RAM" quantum="32M"/>
<config>
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc" socket="/socket"/>
<vfs>
<dir name="etc">
<inline name="resolv.conf">nameserver 1.1.1.1</inline>
<inline name="hosts"/>
</dir>
<dir name="socket">
<lxip dhcp="yes"/>
</dir>
<dir name="download"> <fs label="download"/> </dir>
<dir name="dev">
<log/> <null/> <inline name="rtc">2000-01-01 00:00</inline>
<inline name="random">01234567890123456789</inline>
</dir>
</vfs>
<fetch url="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-9.3.0-amd64-netinst.iso"
path="/download/installer.iso"/>
</config>
<route>
<service name="File_system"> <child name="download_fs"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
-->
</config>

View File

@ -1,9 +1,19 @@
<config>
<vfs>
<rom name="Vera.ttf"/>
<rom name="VeraMono.ttf"/>
<dir name="fonts">
<dir name="title">
<ttf name="regular" path="/Vera.ttf" size_px="18" cache="256K"/>
</dir>
<dir name="text">
<ttf name="regular" path="/Vera.ttf" size_px="14" cache="256K"/>
</dir>
<dir name="annotation">
<ttf name="regular" path="/Vera.ttf" size_px="11" cache="256K"/>
</dir>
<dir name="monospace">
<ttf name="regular" path="/VeraMono.ttf" size_px="16" cache="256K"/>
<ttf name="regular" path="/VeraMono.ttf" size_px="14" cache="256K"/>
</dir>
</dir>
</vfs>

View File

@ -1,63 +0,0 @@
<config verbose="yes">
<report init_ram="yes" requested="yes" child_ram="yes" delay_ms="2000" buffer="128K"/>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Nitpicker"/>
<service name="Timer"/>
<service name="Report"/>
<service name="Block"/>
<service name="File_system"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="nit_focus">
<resource name="RAM" quantum="1M"/>
<config>
<policy label_prefix="leitzentrale" focus="no"/>
<default-policy focus="yes"/>
</config>
<route>
<service name="ROM" label="clicked"> <parent label="clicked"/> </service>
<service name="Report" label="focus"> <parent label="focus"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="fs" caps="500">
<resource name="RAM" quantum="114M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_fs.config"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides> <service name="File_system"/> </provides>
</start>
<start name="noux" version="fs" caps="1000">
<resource name="RAM" quantum="80M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_noux.config"/> </service>
<service name="ROM" label="fonts.config">
<parent label="config -> fonts.config"/> </service>
<service name="File_system" label="config">
<parent label="config"/> </service>
<service name="File_system" label="target">
<child name="fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>

View File

@ -1,8 +1,6 @@
<config>
<input name="leitzentrale_enabled" rom="leitzentrale" node="leitzentrale">
<attribute name="enabled" /> </input>
<input name="reset_enabled" rom="reset" node="reset">
<attribute name="enabled" /> </input>
<output node="config">
<inline>
@ -12,6 +10,7 @@
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Report"/>
<service name="Nitpicker"/>
<service name="Timer"/>
<service name="File_system"/>
@ -20,50 +19,202 @@
<default-route> <any-service> <parent/> </any-service> </default-route>
<default caps="100"/>
<service name="Nitpicker">
<default-policy> <child name="wm"/> </default-policy> </service>
</inline>
<if>
<has_value input="leitzentrale_enabled" value="yes" />
<then>
<inline>
<start name="control_fader">
<start name="fader">
<binary name="nit_fader"/>
<resource name="RAM" quantum="19M"/>
<resource name="RAM" quantum="22M"/>
<provides> <service name="Nitpicker"/> </provides>
<config alpha="190"/>
</start>
<start name="log_fader">
<binary name="nit_fader"/>
<resource name="RAM" quantum="8M"/>
<provides> <service name="Nitpicker"/> </provides>
<config alpha="200"/>
<config alpha="210"/>
<route>
<service name="Nitpicker"> <child name="manager"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</inline>
</then>
<else>
<inline>
<start name="control_fader">
<start name="fader">
<binary name="nit_fader"/>
<resource name="RAM" quantum="19M"/>
<provides> <service name="Nitpicker"/> </provides>
<config alpha="0"/>
</start>
<start name="log_fader">
<binary name="nit_fader"/>
<resource name="RAM" quantum="8M"/>
<resource name="RAM" quantum="22M"/>
<provides> <service name="Nitpicker"/> </provides>
<config alpha="0"/>
<route>
<service name="Nitpicker"> <child name="manager"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</inline>
</else>
</if>
<inline>
<start name="control_nit_fb">
<binary name="nit_fb"/>
<resource name="RAM" quantum="8M"/>
<start name="nit_fb">
<resource name="RAM" quantum="10M"/>
<provides> <service name="Framebuffer"/> <service name="Input"/> </provides>
<config xpos="2" ypos="2" width="-416" height="-4"/>
<config/>
<route>
<service name="Nitpicker"> <child name="control_fader"/> </service>
<service name="Nitpicker"> <child name="fader"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="nitpicker" caps="200">
<resource name="RAM" quantum="6M"/>
<provides> <service name="Nitpicker"/> </provides>
<config focus="rom">
<background color="#272f45"/>
<domain name="default" layer="1" content="client" label="no" hover="always" focus="click"/>
<default-policy domain="default"/>
</config>
<route>
<service name="Input"> <child name="nit_fb"/> </service>
<service name="Framebuffer"> <child name="nit_fb"/> </service>
<service name="ROM" label="focus"> <child name="report_rom"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="report_rom">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Report"/>
<service name="ROM"/>
</provides>
<config verbose="no">
<policy label="layouter -> window_list" report="wm -> window_list"/>
<policy label="layouter -> focus_request" report="wm -> focus_request"/>
<policy label="decorator -> window_layout" report="layouter -> window_layout"/>
<policy label="wm -> resize_request" report="layouter -> resize_request"/>
<policy label="decorator -> pointer" report="wm -> pointer"/>
<policy label="layouter -> hover" report="decorator -> hover"/>
<policy label="layouter -> decorator_margins" report="decorator -> decorator_margins"/>
<policy label="wm -> focus" report="layouter -> focus"/>
<policy label="gui -> config" report="manager -> gui_config"/>
<policy label="gui -> menu_view -> dialog" report="manager -> menu_dialog"/>
<policy label="manager -> menu_view_hover" report="gui -> menu_view -> hover"/>
<policy label="nitpicker -> focus" report="manager -> focus"/>
</config>
</start>
<start name="wm" caps="150">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Nitpicker"/> </provides>
<config>
<policy label_prefix="decorator" role="decorator"/>
<policy label_prefix="layouter" role="layouter"/>
</config>
<route>
<service name="ROM" label="resize_request"> <child name="report_rom"/> </service>
<service name="ROM" label="focus"> <child name="report_rom"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="layouter">
<binary name="floating_window_layouter"/>
<resource name="RAM" quantum="2M"/>
<config/>
<route>
<service name="ROM" label="window_list"> <child name="report_rom"/> </service>
<service name="ROM" label="focus_request"> <child name="report_rom"/> </service>
<service name="ROM" label="hover"> <child name="report_rom"/> </service>
<service name="ROM" label="decorator_margins"> <child name="report_rom"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<any-service> <child name="wm"/> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="decorator" caps="200">
<binary name="themed_decorator"/>
<resource name="RAM" quantum="8M"/>
<config>
<libc/>
<vfs> <tar name="plain_decorator_theme.tar"/> </vfs>
</config>
<route>
<service name="ROM" label="window_layout"> <child name="report_rom"/> </service>
<service name="ROM" label="pointer"> <child name="report_rom"/> </service>
<service name="Report" label="decorator_margins"> <child name="report_rom"/> </service>
<service name="Report" label="hover"> <child name="report_rom"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="config_fs_report">
<binary name="fs_report"/>
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> </provides>
<config> <vfs> <fs/> </vfs> </config>
<route>
<service name="File_system"> <parent label="config"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="manager" caps="200">
<binary name="sculpt_manager"/>
<resource name="RAM" quantum="16M"/>
<provides> <service name="Nitpicker"/> </provides>
<config/>
<route>
<service name="Report" label="runtime_config">
<child name="config_fs_report" label="managed -> runtime"/> </service>
<service name="Report" label="wlan_config">
<child name="config_fs_report" label="managed -> wlan"/> </service>
<service name="Report" label="fonts_config">
<child name="config_fs_report" label="managed -> fonts"/> </service>
<service name="Report" label="nic_router_config">
<child name="config_fs_report" label="managed -> nic_router"/> </service>
<service name="Report" label="fb_drv_config">
<child name="config_fs_report" label="managed -> fb_drv"/> </service>
<service name="Report" label="input_filter_config">
<child name="config_fs_report" label="managed -> input_filter"/> </service>
<service name="Report" label="installation_config">
<child name="config_fs_report" label="managed -> installation"/> </service>
<service name="Report" label="depot_query">
<child name="config_fs_report" label="managed -> depot_query"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="ROM" label="nitpicker_hover"> <parent/> </service>
<service name="ROM" label_prefix="report ->"> <parent/> </service>
<service name="ROM" label="menu_view_hover"> <child name="report_rom"/> </service>
<service name="Nitpicker"> <parent/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="fonts_fs" caps="100">
<binary name="vfs"/>
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system"/> </provides>
<route>
<service name="ROM" label="config">
<parent label="config -> managed/fonts"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="gui" caps="1400">
<binary name="init"/>
<resource name="RAM" quantum="12M"/>
<route>
<service name="ROM" label="config"> <child name="report_rom"/> </service>
<service name="ROM" label_last="dialog"> <child name="report_rom"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="File_system" label="fonts"> <child name="fonts_fs"/> </service>
<service name="Report" label_last="hover"> <child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
@ -74,7 +225,7 @@
<provides> <service name="Framebuffer"/> <service name="Input"/> </provides>
<config origin="top_right" xpos="-412" ypos="2" width="410" height="-4"/>
<route>
<service name="Nitpicker"> <child name="log_fader"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
@ -114,63 +265,11 @@
</start>
</config>
<route>
<service name="File_system"> <parent label="report"/> </service>
<any-service> <child name="log_terminal"/> <parent/> </any-service>
</route>
</start>
<!--
<start name="cpu_load_display">
<resource name="RAM" quantum="6M"/>
<route>
<service name="ROM" label="trace_subjects"> <parent label="trace_subjects"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
-->
</inline>
<if>
<has_value input="reset_enabled" value="no" />
<then>
<inline>
<start name="control_terminal">
<binary name="terminal"/>
<resource name="RAM" quantum="8M"/>
<provides> <service name="Terminal"/> </provides>
<route>
<service name="ROM" label="config"> <parent label="fonts.config"/> </service>
<any-service> <child name="control_nit_fb"/> <parent/> </any-service>
</route>
</start>
<start name="control_noux" caps="1000">
<binary name="noux"/>
<resource name="RAM" quantum="48M" />
<config>
<fstab>
<tar name="coreutils-minimal.tar" />
<tar name="vim-minimal.tar" />
<tar name="bash-minimal.tar" />
<dir name="dev"> <zero/> <null/> </dir>
<dir name="config"> <fs label="config"/> </dir>
<dir name="report"> <fs label="report"/> </dir>
<dir name="tmp"> <ram /> </dir>
<dir name="share"> <dir name="vim"> <rom name="vimrc"/> </dir> </dir>
<rom name="README"/>
<rom name="VERSION"/>
</fstab>
<start name="/bin/bash">
<env name="TERM" value="screen" />
<env name="PS1" value="genode:$PWD> " />
</start>
</config>
<route>
<any-service> <child name="control_terminal"/> <parent/> </any-service>
</route>
</start>
</inline>
</then>
</if>
</output>
</config>

View File

@ -1,69 +0,0 @@
<config>
<report init_ram="yes" requested="yes" child_ram="yes" delay_ms="2000" buffer="128K"/>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Nitpicker"/>
<service name="Timer"/>
<service name="Report"/>
<service name="Block"/>
<service name="File_system"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="fs" caps="500">
<resource name="RAM" quantum="114M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_fs.config"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides> <service name="File_system"/> </provides>
</start>
<start name="noux" caps="500" version="initial">
<binary name="noux"/>
<resource name="RAM" quantum="100M" />
<config stdout="/dev/null" stderr="/dev/null" stdin="/dev/null">
<fstab>
<inline name=".bash_profile">
export VERSION=`cat /VERSION`
cp /rw/config/$VERSION/* /config/
cp /rw/config/$VERSION/subinit/*.config /config/subinit/
cp /rw/config/$VERSION/deploy/* /config/deploy/
cp /rw/config/$VERSION/leitzentrale/config /config/leitzentrale/
cp /rw/config/$VERSION/runtime/*.config /config/runtime/
cp /rw/config/$VERSION/runtime/config /config/runtime/
</inline>
<tar name="bash-minimal.tar" />
<tar name="coreutils-minimal.tar" />
<dir name="dev"> <zero/> <null/> <log/> </dir>
<dir name="rw"> <fs label="target"/> </dir>
<dir name="config"> <fs label="config"/> </dir>
<rom name="VERSION"/>
</fstab>
<start name="/bin/bash">
<env name="TERM" value="screen" />
<env name="PS1" value="fs:$PWD> " />
<env name="HOME" value="/" />
<arg value="--login"/>
</start>
</config>
<route>
<service name="File_system" label="target"> <child name="fs"/> </service>
<service name="File_system" label="config"> <parent label="config"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>

View File

@ -1,5 +1,5 @@
<config focus="rom">
<report hover="yes" focus="yes" clicked="yes" keystate="no"/>
<report hover="yes" focus="yes" clicked="yes" keystate="no" displays="yes"/>
<background color="#131415"/>
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="leitzentrale" layer="2" content="client" label="no" hover="always" focus="click" />
@ -9,8 +9,8 @@
<domain name="desktop" layer="4" content="client" label="no" hover="always" focus="click" />
<domain name="background" layer="5" content="client" label="no" hover="always" focus="transient" />
<policy label_prefix="runtime -> dynamic -> wm -> wm -> decorator" domain="decorator"/>
<policy label_prefix="runtime -> dynamic -> wm" domain="desktop"/>
<policy label_prefix="runtime -> wm -> wm -> decorator" domain="decorator"/>
<policy label_prefix="runtime -> wm" domain="desktop"/>
<policy label_prefix="pointer" domain="pointer"/>
<policy label_prefix="leitzentrale -> " domain="leitzentrale"/>
@ -22,5 +22,5 @@
<global-key name="KEY_DASHBOARD" label="global_keys_handler -> input" />
<global-key name="KEY_CAPSLOCK" label="global_keys_handler -> input" />
<global-key name="KEY_NUMLOCK" label="global_keys_handler -> input" />
<global-key name="KEY_SCREEN" label="runtime -> dynamic -> wm -> wm -> decorator" />
<global-key name="KEY_SCREEN" label="runtime -> wm -> wm -> decorator" />
</config>

View File

@ -1,121 +0,0 @@
<config verbose="yes" prio_levels="2">
<report init_ram="yes" requested="yes" child_ram="yes" delay_ms="2000" buffer="128K"/>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Nitpicker"/>
<service name="Timer"/>
<service name="Block"/>
<service name="Report"/>
<service name="Rtc"/>
<service name="File_system"/>
<service name="Platform"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="nic" caps="500">
<resource name="RAM" quantum="60M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_nic.config"/> </service>
<service name="ROM" label="wlan.config">
<parent label="config -> wlan.config"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides> <service name="Nic"/> </provides>
</start>
<start name="nic_router" caps="300">
<resource name="RAM" quantum="10M"/>
<provides><service name="Nic"/></provides>
<config verbose_domain_state="yes">
<default-policy domain="default" />
<domain name="uplink">
<nat domain="default" tcp-ports="1000" udp-ports="1000"/>
</domain>
<domain name="default" interface="10.0.1.1/24">
<dhcp-server ip_first="10.0.1.2"
ip_last="10.0.1.200"
ip_lease_time_sec="360"
dns_server="1.1.1.1"/>
<tcp dst="0.0.0.0/0"><permit-any domain="uplink"/></tcp>
<udp dst="0.0.0.0/0"><permit-any domain="uplink"/></udp>
</domain>
</config>
<route>
<service name="Nic"> <child name="nic"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="fs" caps="500">
<resource name="RAM" quantum="114M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/default_fs.config"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides> <service name="File_system"/> </provides>
</start>
<start name="depot_fs" priority="0">
<binary name="chroot"/>
<resource name="RAM" quantum="1M" />
<provides> <service name="File_system"/> </provides>
<config> <default-policy path="/depot" writeable="yes"/> </config>
<route>
<service name="File_system"> <child name="fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="public_fs" priority="0">
<binary name="chroot"/>
<resource name="RAM" quantum="1M" />
<provides> <service name="File_system"/> </provides>
<config> <default-policy path="/public" writeable="yes"/> </config>
<route>
<service name="File_system"> <child name="fs"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="depot_download" caps="2000">
<binary name="init"/>
<resource name="RAM" quantum="64M"/>
<route>
<service name="ROM" label="config">
<parent label="config -> subinit/depot_download.config"/> </service>
<service name="ROM" label_last="installation">
<parent label="config -> installation"/> </service>
<service name="File_system" label="depot">
<child name="depot_fs" label="depot"/> </service>
<service name="File_system" label="public">
<child name="public_fs" label="public"/> </service>
<service name="File_system" label="depot_rw">
<child name="depot_fs" label="depot_rw"/> </service>
<service name="File_system" label="public_rw">
<child name="public_fs" label="public_rw"/> </service>
<service name="LOG" label="dynamic -> fetchurl">
<parent label="fetchurl"/> </service>
<service name="LOG" label="dynamic -> verify">
<parent label="verify"/> </service>
<service name="LOG" label="dynamic -> extract">
<parent label="extract"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>

View File

@ -12,7 +12,7 @@ if {![file exists bin/sculpt-ahci.raw]} {
catch { exec dd if=/dev/zero of=$disk_image bs=1M count=512 }
}
append qemu_args " -device ahci,id=ahci "
append qemu_args " -drive id=hdd,file=$disk_image,format=raw,if=none -device ide-hd,drive=hdd,bus=ahci.0 "
append qemu_args " -drive id=hdd,file=$disk_image,format=raw,if=none -device ide-hd,drive=hdd,bus=ahci.1 "
# attach small NVMe disk to Qemu to experiment with file-system access
if {$use_nvme} {

View File

@ -217,6 +217,8 @@ class Depot_deploy::Child : public List_model<Child>::Element
xml.attribute("source", "no");
});
}
bool incomplete() const { return _pkg_incomplete; }
};

View File

@ -102,6 +102,14 @@ class Depot_deploy::Children
_children.for_each([&] (Child const &child) {
child.gen_installation_entry(xml); });
}
bool any_incomplete() const {
bool result = false;
_children.for_each([&] (Child const &child) {
result |= child.incomplete(); });
return result;
}
};
#endif /* _CHILDREN_H_ */

View File

@ -0,0 +1,88 @@
/*
* \brief Sculpt deploy management
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <deploy.h>
void Sculpt::Deploy::handle_deploy()
{
Xml_node const manual_deploy = _manual_deploy_rom.xml();
/* determine CPU architecture of deployment */
_arch = manual_deploy.attribute_value("arch", Arch());
if (!_arch.valid())
warning("manual deploy config lacks 'arch' attribute");
try { _children.apply_config(manual_deploy); }
catch (...) {
error("spurious exception during deploy update (apply_config)"); }
/* update query for blueprints of all unconfigured start nodes */
if (_arch.valid()) {
_depot_query_reporter.generate([&] (Xml_generator &xml) {
xml.attribute("arch", _arch);
xml.attribute("version", _query_version.value);
_children.gen_queries(xml);
});
}
/*
* Apply blueprint after 'gen_queries'. Otherwise the application of a
* stale blueprint may flag children whose pkgs have been installed in the
* meanwhile as incomplete, suppressing their respective queries.
*/
try {
Xml_node const blueprint = _blueprint_rom.xml();
/* apply blueprint, except when stale */
typedef String<32> Version;
Version const version = blueprint.attribute_value("version", Version());
if (version == Version(_query_version.value))
_children.apply_blueprint(_blueprint_rom.xml());
}
catch (...) {
error("spurious exception during deploy update (apply_blueprint)"); }
/* feed missing packages to installation queue */
if (!_installation.try_generate_manually_managed())
_installation.generate([&] (Xml_generator &xml) {
xml.attribute("arch", _arch);
_children.gen_installation_entries(xml); });
_runtime_config_generator.generate_runtime_config();
}
void Sculpt::Deploy::gen_runtime_start_nodes(Xml_generator &xml) const
{
xml.node("start", [&] () {
gen_fs_rom_start_content(xml, "depot_rom", "depot",
depot_rom_state.ram_quota); });
xml.node("start", [&] () {
gen_depot_query_start_content(xml); });
Xml_node const manual_deploy = _manual_deploy_rom.xml();
/* insert content of '<static>' node as is */
if (manual_deploy.has_sub_node("static")) {
Xml_node static_config = manual_deploy.sub_node("static");
xml.append(static_config.content_base(), static_config.content_size());
}
/* generate start nodes for deployed packages */
if (manual_deploy.has_sub_node("common_routes"))
_children.gen_start_nodes(xml, manual_deploy.sub_node("common_routes"),
"depot_rom");
}

View File

@ -0,0 +1,121 @@
/*
* \brief Sculpt deploy management
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DEPLOY_H_
#define _DEPLOY_H_
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
/* included from depot_deploy tool */
#include <children.h>
/* local includes */
#include <types.h>
#include <runtime.h>
#include <managed_config.h>
namespace Sculpt { struct Deploy; }
struct Sculpt::Deploy
{
Env &_env;
Allocator &_alloc;
Runtime_config_generator &_runtime_config_generator;
typedef String<16> Arch;
Arch _arch { };
struct Query_version { unsigned value; } _query_version { 0 };
struct Depot_rom_state { Ram_quota ram_quota; };
Depot_rom_state depot_rom_state { 32*1024*1024 };
Attached_rom_dataspace _manual_deploy_rom { _env, "config -> deploy" };
Attached_rom_dataspace _blueprint_rom { _env, "report -> runtime/depot_query/blueprint" };
Expanding_reporter _depot_query_reporter { _env, "query", "depot_query"};
bool _manual_installation_scheduled = false;
Managed_config<Deploy> _installation {
_env, "installation", "installation", *this, &Deploy::_handle_installation };
void _handle_installation(Xml_node manual_config)
{
_manual_installation_scheduled = manual_config.has_sub_node("archive");
handle_deploy();
}
Depot_deploy::Children _children { _alloc };
bool update_needed() const
{
return _manual_installation_scheduled || _children.any_incomplete();
}
void handle_deploy();
void _handle_manual_deploy()
{
_manual_deploy_rom.update();
_query_version.value++;
handle_deploy();
}
void _handle_blueprint()
{
_blueprint_rom.update();
handle_deploy();
}
void gen_runtime_start_nodes(Xml_generator &) const;
Signal_handler<Deploy> _manual_deploy_handler {
_env.ep(), *this, &Deploy::_handle_manual_deploy };
Signal_handler<Deploy> _blueprint_handler {
_env.ep(), *this, &Deploy::_handle_blueprint };
void restart()
{
/* ignore stale query results */
_query_version.value++;
_children.apply_config(Xml_node("<config/>"));
}
void reattempt_after_installation()
{
_children.reset_incomplete();
handle_deploy();
}
Deploy(Env &env, Allocator &alloc,
Runtime_config_generator &runtime_config_generator)
:
_env(env), _alloc(alloc),
_runtime_config_generator(runtime_config_generator)
{
_manual_deploy_rom.sigh(_manual_deploy_handler);
_blueprint_rom.sigh(_blueprint_handler);
}
};
#endif /* _DEPLOY_H_ */

View File

@ -0,0 +1,104 @@
/*
* \brief Sculpt GUI management
* \author Norman Feske
* \date 2018-04-30
*
* The GUI is based on a dynamically configured init component, which hosts
* one menu-view component for each dialog.
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
/* local includes */
#include <gui.h>
void Sculpt::Gui::_gen_menu_view_start_content(Xml_generator &xml,
Label const &label,
Point pos) const
{
xml.attribute("version", version.value);
gen_common_start_content(xml, label, Cap_quota{150}, Ram_quota{8*1024*1024});
gen_named_node(xml, "binary", "menu_view");
xml.node("config", [&] () {
xml.attribute("xpos", pos.x());
xml.attribute("ypos", pos.y());
xml.attribute("width", menu_width);
xml.node("libc", [&] () { xml.attribute("stderr", "/dev/log"); });
xml.node("report", [&] () { xml.attribute("hover", "yes"); });
xml.node("vfs", [&] () {
gen_named_node(xml, "tar", "menu_view_styles.tar");
gen_named_node(xml, "dir", "styles", [&] () {
gen_named_node(xml, "dir", "frame", [&] () {
gen_named_node(xml, "dir", "logo", [&] () {
gen_named_node(xml, "rom", "background.png", [&] () {
xml.attribute("label", "genode_logo.png"); }); }); }); });
gen_named_node(xml, "dir", "fonts", [&] () {
xml.node("fs", [&] () {
xml.attribute("label", "fonts"); }); });
gen_named_node(xml, "dir", "dev", [&] () {
xml.node("log", [&] () { }); });
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "menu_view");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "libpng.lib.so");
gen_parent_rom_route(xml, "zlib.lib.so");
gen_parent_rom_route(xml, "menu_view_styles.tar");
gen_parent_rom_route(xml, "genode_logo.png");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_parent_route<Nitpicker::Session> (xml);
gen_service_node<Rom_session>(xml, [&] () {
xml.attribute("label", "dialog");
xml.node("parent", [&] () { }); });
gen_service_node<Report::Session>(xml, [&] () {
xml.attribute("label", "hover");
xml.node("parent", [&] () { }); });
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "fonts");
xml.node("parent", [&] () {
xml.attribute("label", "fonts"); }); });
});
}
void Sculpt::Gui::_generate_config(Xml_generator &xml) const
{
xml.node("parent-provides", [&] () {
gen_parent_service<Rom_session>(xml);
gen_parent_service<Cpu_session>(xml);
gen_parent_service<Pd_session>(xml);
gen_parent_service<Log_session>(xml);
gen_parent_service<Timer::Session>(xml);
gen_parent_service<Report::Session>(xml);
gen_parent_service<Nitpicker::Session>(xml);
gen_parent_service<::File_system::Session>(xml);
});
xml.node("start", [&] () {
_gen_menu_view_start_content(xml, "menu_view", Point(0, 0)); });
}

View File

@ -0,0 +1,54 @@
/*
* \brief Sculpt GUI management
* \author Norman Feske
* \date 2018-04-30
*
* The GUI is based on a dynamically configured init component, which hosts
* one menu-view component for each dialog.
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _GUI_H_
#define _GUI_H_
/* Genode includes */
#include <os/reporter.h>
/* local includes */
#include <types.h>
#include <xml.h>
namespace Sculpt { struct Gui; }
struct Sculpt::Gui
{
Env &_env;
Expanding_reporter _config { _env, "config", "gui_config" };
typedef String<32> Label;
struct Version { unsigned value; } version { 0 };
unsigned menu_width = 0;
void _gen_menu_view_start_content(Xml_generator &, Label const &, Point) const;
void _generate_config(Xml_generator &) const;
void generate_config()
{
_config.generate([&] (Xml_generator &xml) { _generate_config(xml); });
}
Gui(Env &env) : _env(env) { }
};
#endif /* _GUI_H_ */

View File

@ -0,0 +1,30 @@
/*
* \brief Interface for handling input events
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INPUT_EVENT_HANDLER_H_
#define _INPUT_EVENT_HANDLER_H_
/* Genode includes */
#include <input/event.h>
/* local includes */
#include "types.h"
namespace Sculpt { struct Input_event_handler; }
struct Sculpt::Input_event_handler : Interface
{
virtual void handle_input_event(Input::Event const &) = 0;
};
#endif /* _INPUT_EVENT_HANDLER_H_ */

View File

@ -0,0 +1,77 @@
/*
* \brief Keyboard-focus policy
* \author Norman Feske
* \date 2018-05-23
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _KEYBOARD_FOCUS_H_
#define _KEYBOARD_FOCUS_H_
/* Genode includes */
#include <os/reporter.h>
/* local includes */
#include <types.h>
#include <view/network_dialog.h>
namespace Sculpt { struct Keyboard_focus; }
struct Sculpt::Keyboard_focus
{
enum Target { INITIAL, WPA_PASSPHRASE, WM } target { INITIAL };
Expanding_reporter _focus_reporter;
Network_dialog const &_network_dialog;
Wpa_passphrase &_wpa_passphrase;
void update()
{
Target const orig_target = target;
target = WM;
if (_network_dialog.need_keyboard_focus_for_passphrase())
target = WPA_PASSPHRASE;
if (orig_target == target)
return;
if (orig_target == WPA_PASSPHRASE)
_wpa_passphrase = Wpa_passphrase { };
_focus_reporter.generate([&] (Xml_generator &xml) {
switch (target) {
case WPA_PASSPHRASE:
xml.attribute("label", "manager -> input");
break;
case INITIAL:
case WM:
xml.attribute("label", "wm -> ");
break;
};
});
}
Keyboard_focus(Env &env,
Network_dialog const &network_dialog,
Wpa_passphrase &wpa_passphrase)
:
_focus_reporter(env, "focus", "focus"),
_network_dialog(network_dialog),
_wpa_passphrase(wpa_passphrase)
{
update();
}
};
#endif /* _KEYBOARD_FOCUS_H_ */

View File

@ -0,0 +1,662 @@
/*
* \brief Sculpt system manager
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/component.h>
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
#include <nitpicker_session/connection.h>
/* included from depot_deploy tool */
#include <children.h>
/* local includes */
#include <model/child_exit_state.h>
#include <view/download_status.h>
#include <gui.h>
#include <nitpicker.h>
#include <runtime.h>
#include <keyboard_focus.h>
#include <network.h>
#include <storage.h>
#include <deploy.h>
namespace Sculpt { struct Main; }
struct Sculpt::Main : Input_event_handler,
Dialog::Generator,
Runtime_config_generator,
Runtime_info,
Storage::Target_user
{
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
Constructible<Nitpicker::Connection> _nitpicker { };
Signal_handler<Main> _input_handler {
_env.ep(), *this, &Main::_handle_input };
void _handle_input()
{
_nitpicker->input()->for_each_event([&] (Input::Event const &ev) {
handle_input_event(ev); });
}
Signal_handler<Main> _nitpicker_mode_handler {
_env.ep(), *this, &Main::_handle_nitpicker_mode };
void _handle_nitpicker_mode();
Managed_config<Main> _fonts_config {
_env, "config", "fonts", *this, &Main::_handle_fonts_config };
void _handle_fonts_config(Xml_node) { _handle_nitpicker_mode(); }
Managed_config<Main> _input_filter_config {
_env, "config", "input_filter", *this, &Main::_handle_input_filter_config };
void _handle_input_filter_config(Xml_node)
{
_input_filter_config.try_generate_manually_managed();
}
bool _first_hover_report = true;
Attached_rom_dataspace _nitpicker_hover { _env, "nitpicker_hover" };
Signal_handler<Main> _nitpicker_hover_handler {
_env.ep(), *this, &Main::_handle_nitpicker_hover };
void _handle_nitpicker_hover();
/***************************
** Configuration loading **
***************************/
Prepare_version _prepare_version { 0 };
Prepare_version _prepare_completed { 0 };
bool _prepare_in_progress() const
{
return _prepare_version.value != _prepare_completed.value;
}
Storage _storage { _env, _heap, *this, *this, *this };
/**
* Storage::Target_user interface
*/
void use_storage_target(Storage_target const &target) override
{
_storage._sculpt_partition = target;
/* trigger loading of the configuration from the sculpt partition */
_prepare_version.value++;
_deploy.restart();
generate_runtime_config();
}
Network _network { _env, _heap, *this, *this, *this };
/************
** Update **
************/
Attached_rom_dataspace _update_state_rom {
_env, "report -> runtime/update/state" };
void _handle_update_state();
Signal_handler<Main> _update_state_handler {
_env.ep(), *this, &Main::_handle_update_state };
bool _update_running() const { return _storage._sculpt_partition.valid()
&& !_prepare_in_progress()
&& _network.ready()
&& _deploy.update_needed(); };
Deploy _deploy { _env, _heap, *this };
/************
** Global **
************/
Gui _gui { _env };
Expanding_reporter _dialog_reporter { _env, "dialog", "menu_dialog" };
Attached_rom_dataspace _hover_rom { _env, "menu_view_hover" };
Signal_handler<Main> _hover_handler {
_env.ep(), *this, &Main::_handle_hover };
struct Hovered { enum Dialog { NONE, STORAGE, NETWORK } value; };
Hovered::Dialog _hovered_dialog { Hovered::NONE };
template <typename FN>
void _apply_to_hovered_dialog(Hovered::Dialog dialog, FN const &fn)
{
if (dialog == Hovered::STORAGE) fn(_storage.dialog);
if (dialog == Hovered::NETWORK) fn(_network.dialog);
}
void _handle_hover();
/**
* Dialog::Generator interface
*/
void generate_dialog() override
{
_dialog_reporter.generate([&] (Xml_generator &xml) {
xml.node("vbox", [&] () {
gen_named_node(xml, "frame", "logo", [&] () {
xml.node("float", [&] () {
xml.node("frame", [&] () {
xml.attribute("style", "logo"); }); }); });
if (_manually_managed_runtime)
return;
_storage.dialog.generate(xml);
_network.dialog.generate(xml);
gen_named_node(xml, "frame", "runtime", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "label", "title", [&] () {
xml.attribute("text", "Runtime");
xml.attribute("font", "title/regular");
});
Xml_node const state = _update_state_rom.xml();
if (_update_running() && state.has_sub_node("archive"))
gen_download_status(xml, state);
});
});
});
});
}
Attached_rom_dataspace _runtime_state { _env, "report -> runtime/state" };
/**
* Runtime_info interface
*/
bool present_in_runtime(Start_name const &name) const override
{
bool present = false;
_runtime_state.xml().for_each_sub_node("child", [&] (Xml_node child) {
if (child.attribute_value("name", Start_name()) == name)
present = true; });
return present;
}
Managed_config<Main> _runtime_config {
_env, "config", "runtime", *this, &Main::_handle_runtime };
bool _manually_managed_runtime = false;
void _handle_runtime(Xml_node config)
{
_manually_managed_runtime = !config.has_type("empty");
generate_runtime_config();
generate_dialog();
}
void _generate_runtime_config(Xml_generator &) const;
/**
* Runtime_config_generator interface
*/
void generate_runtime_config() override
{
if (!_runtime_config.try_generate_manually_managed())
_runtime_config.generate([&] (Xml_generator &xml) {
_generate_runtime_config(xml); });
}
Signal_handler<Main> _runtime_state_handler {
_env.ep(), *this, &Main::_handle_runtime_state };
void _handle_runtime_state();
Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase };
/**
* Input_event_handler interface
*/
void handle_input_event(Input::Event const &ev) override
{
if (ev.key_press(Input::BTN_LEFT)) {
if (_hovered_dialog == Hovered::STORAGE) _storage.dialog.click(_storage);
if (_hovered_dialog == Hovered::NETWORK) _network.dialog.click(_network);
}
if (ev.key_release(Input::BTN_LEFT))
_storage.dialog.clack(_storage);
if (_keyboard_focus.target == Keyboard_focus::WPA_PASSPHRASE)
ev.handle_press([&] (Input::Keycode, Codepoint code) {
_network.handle_key_press(code); });
if (ev.press())
_keyboard_focus.update();
}
Managed_config<Main> _fb_drv_config {
_env, "config", "fb_drv", *this, &Main::_handle_fb_drv_config };
void _handle_fb_drv_config(Xml_node)
{
_fb_drv_config.try_generate_manually_managed();
}
Attached_rom_dataspace _nitpicker_displays { _env, "displays" };
Signal_handler<Main> _nitpicker_displays_handler {
_env.ep(), *this, &Main::_handle_nitpicker_displays };
void _handle_nitpicker_displays()
{
_nitpicker_displays.update();
if (!_nitpicker_displays.xml().has_sub_node("display"))
return;
if (_nitpicker.constructed())
return;
/*
* Since nitpicker has successfully issued the first 'displays' report,
* there is a good chance that the framebuffer driver is running. This
* is a good time to activate the GUI.
*/
_nitpicker.construct(_env, "input");
_nitpicker->input()->sigh(_input_handler);
_nitpicker->mode_sigh(_nitpicker_mode_handler);
/*
* Adjust GUI parameters to initial nitpicker mode
*/
_handle_nitpicker_mode();
/*
* Avoid 'Constructible<Nitpicker::Root>' because it requires the
* definition of 'Nitpicker::Session_component'.
*/
static Nitpicker::Root gui_nitpicker(_env, _heap, *this);
_gui.generate_config();
}
Main(Env &env) : _env(env)
{
_runtime_state.sigh(_runtime_state_handler);
_nitpicker_displays.sigh(_nitpicker_displays_handler);
/*
* Subscribe to reports
*/
_update_state_rom.sigh(_update_state_handler);
_nitpicker_hover .sigh(_nitpicker_hover_handler);
_hover_rom .sigh(_hover_handler);
/*
* Generate initial configurations
*/
_network.wifi_disconnect();
/*
* Import initial report content
*/
_storage.handle_storage_devices_update();
_deploy.handle_deploy();
generate_runtime_config();
generate_dialog();
}
};
void Sculpt::Main::_handle_nitpicker_mode()
{
if (!_fonts_config.try_generate_manually_managed()) {
Framebuffer::Mode const mode = _nitpicker->mode();
float const text_size = (float)mode.height() / 60.0;
_gui.menu_width = text_size*21;
_fonts_config.generate([&] (Xml_generator &xml) {
xml.node("vfs", [&] () {
gen_named_node(xml, "rom", "Vera.ttf");
gen_named_node(xml, "rom", "VeraMono.ttf");
gen_named_node(xml, "dir", "fonts", [&] () {
auto gen_ttf_dir = [&] (char const *dir_name,
char const *ttf_path, float size_px) {
gen_named_node(xml, "dir", dir_name, [&] () {
gen_named_node(xml, "ttf", "regular", [&] () {
xml.attribute("path", ttf_path);
xml.attribute("size_px", size_px);
xml.attribute("cache", "256K");
});
});
};
gen_ttf_dir("title", "/Vera.ttf", text_size*1.25);
gen_ttf_dir("text", "/Vera.ttf", text_size);
gen_ttf_dir("annotation", "/Vera.ttf", text_size*0.8);
gen_ttf_dir("monospace", "/VeraMono.ttf", text_size);
});
});
xml.node("default-policy", [&] () { xml.attribute("root", "/fonts"); });
});
}
_gui.version.value++;
_gui.generate_config();
}
void Sculpt::Main::_handle_hover()
{
_hover_rom.update();
Xml_node const hover = _hover_rom.xml();
Hovered::Dialog const orig_hovered_dialog = _hovered_dialog;
typedef String<32> Top_level_frame;
Top_level_frame const top_level_frame =
query_attribute<Top_level_frame>(hover, "dialog", "vbox", "frame", "name");
_hovered_dialog = Hovered::NONE;
if (top_level_frame == "network") _hovered_dialog = Hovered::NETWORK;
if (top_level_frame == "storage") _hovered_dialog = Hovered::STORAGE;
if (orig_hovered_dialog != _hovered_dialog)
_apply_to_hovered_dialog(orig_hovered_dialog, [&] (Dialog &dialog) {
dialog.hover(Xml_node("<hover/>")); });
_apply_to_hovered_dialog(_hovered_dialog, [&] (Dialog &dialog) {
dialog.hover(hover.sub_node("dialog").sub_node("vbox")
.sub_node("frame")); });
}
void Sculpt::Main::_handle_nitpicker_hover()
{
if (!_first_hover_report)
return;
if (!_storage._discovery_state.discovery_in_progress())
return;
_nitpicker_hover.update();
Xml_node const hover = _nitpicker_hover.xml();
if (!hover.has_type("hover"))
return;
_first_hover_report = false;
if (hover.attribute_value("active", false) == true)
_storage._discovery_state.user_intervention = true;
}
void Sculpt::Main::_handle_update_state()
{
_update_state_rom.update();
generate_dialog();
bool const installation_complete =
!_update_state_rom.xml().has_sub_node("archive");
if (installation_complete)
_deploy.reattempt_after_installation();
}
void Sculpt::Main::_handle_runtime_state()
{
_runtime_state.update();
Xml_node state = _runtime_state.xml();
bool reconfigure_runtime = false;
/* check for completed storage operations */
_storage._storage_devices.for_each([&] (Storage_device &device) {
device.for_each_partition([&] (Partition &partition) {
Storage_target const target { device.label, partition.number };
if (partition.check_in_progress) {
String<64> name(target.label(), ".fsck.ext2");
Child_exit_state exit_state(state, name);
if (exit_state.exited) {
if (exit_state.code != 0)
error("file-system check failed");
if (exit_state.code == 0)
log("file-system check succeeded");
partition.check_in_progress = 0;
reconfigure_runtime = true;
_storage.dialog.reset_operation();
}
}
if (partition.format_in_progress) {
String<64> name(target.label(), ".mkfs.ext2");
Child_exit_state exit_state(state, name);
if (exit_state.exited) {
if (exit_state.code != 0)
error("file-system creation failed");
partition.format_in_progress = false;
partition.file_system.type = File_system::EXT2;
if (partition.whole_device())
device.rediscover();
reconfigure_runtime = true;
_storage.dialog.reset_operation();
}
}
/* respond to completion of file-system resize operation */
if (partition.fs_resize_in_progress) {
Child_exit_state exit_state(state, Start_name(target.label(), ".resize2fs"));
if (exit_state.exited) {
partition.fs_resize_in_progress = false;
reconfigure_runtime = true;
device.rediscover();
_storage.dialog.reset_operation();
}
}
}); /* for each partition */
/* respond to completion of GPT relabeling */
if (device.relabel_in_progress()) {
Child_exit_state exit_state(state, device.relabel_start_name());
if (exit_state.exited) {
device.rediscover();
reconfigure_runtime = true;
_storage.dialog.reset_operation();
}
}
/* respond to completion of GPT expand */
if (device.gpt_expand_in_progress()) {
Child_exit_state exit_state(state, device.expand_start_name());
if (exit_state.exited) {
/* kick off resize2fs */
device.for_each_partition([&] (Partition &partition) {
if (partition.gpt_expand_in_progress) {
partition.gpt_expand_in_progress = false;
partition.fs_resize_in_progress = true;
}
});
reconfigure_runtime = true;
_storage.dialog.reset_operation();
}
}
}); /* for each device */
/* remove prepare subsystem when finished */
{
Child_exit_state exit_state(state, "prepare");
if (exit_state.exited) {
_prepare_completed = _prepare_version;
/* trigger deployment */
_deploy.handle_deploy();
/* trigger update and deploy */
reconfigure_runtime = true;
}
}
/* upgrade ram_fs quota on demand */
state.for_each_sub_node("child", [&] (Xml_node child) {
if (child.attribute_value("name", String<16>()) == "ram_fs"
&& child.has_sub_node("ram")
&& child.sub_node("ram").has_attribute("requested")) {
_storage._ram_fs_state.ram_quota.value *= 2;
reconfigure_runtime = true;
generate_dialog();
}
});
/* upgrade depot_rom quota on demand */
state.for_each_sub_node("child", [&] (Xml_node child) {
if (child.attribute_value("name", String<16>()) == "depot_rom"
&& child.has_sub_node("ram")
&& child.sub_node("ram").has_attribute("requested")) {
_deploy.depot_rom_state.ram_quota.value *= 2;
reconfigure_runtime = true;
}
});
/*
* Re-attempt NIC-router configuration as the uplink may have become
* available in the meantime.
*/
_network.reattempt_nic_router_config();
if (reconfigure_runtime)
generate_runtime_config();
}
void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
{
xml.attribute("verbose", "yes");
xml.node("report", [&] () {
xml.attribute("init_ram", "yes");
xml.attribute("init_caps", "yes");
xml.attribute("child_ram", "yes");
xml.attribute("delay_ms", 4*500);
xml.attribute("buffer", "64K");
});
xml.node("parent-provides", [&] () {
gen_parent_service<Rom_session>(xml);
gen_parent_service<Cpu_session>(xml);
gen_parent_service<Pd_session>(xml);
gen_parent_service<Rm_session>(xml);
gen_parent_service<Log_session>(xml);
gen_parent_service<Timer::Session>(xml);
gen_parent_service<Report::Session>(xml);
gen_parent_service<Platform::Session>(xml);
gen_parent_service<Block::Session>(xml);
gen_parent_service<Usb::Session>(xml);
gen_parent_service<::File_system::Session>(xml);
gen_parent_service<Nitpicker::Session>(xml);
gen_parent_service<Rtc::Session>(xml);
gen_parent_service<Trace::Session>(xml);
});
_storage.gen_runtime_start_nodes(xml);
/*
* Load configuration and update depot config on the sculpt partition
*/
if (_storage._sculpt_partition.valid() && _prepare_in_progress())
xml.node("start", [&] () {
gen_prepare_start_content(xml, _prepare_version); });
if (_storage.any_file_system_inspected())
gen_file_browser(xml, _storage._storage_devices, _storage._ram_fs_state,
_storage._file_browser_version);
/*
* Spawn chroot instances for accessing '/depot' and '/public'. The
* chroot instances implicitly refer to the 'default_fs_rw'.
*/
if (_storage._sculpt_partition.valid()) {
auto chroot = [&] (Start_name const &name, Path const &path, Writeable w) {
xml.node("start", [&] () {
gen_chroot_start_content(xml, name, path, w); }); };
chroot("depot_rw", "/depot", WRITEABLE);
chroot("depot", "/depot", READ_ONLY);
chroot("public_rw", "/public", WRITEABLE);
}
_network.gen_runtime_start_nodes(xml);
if (_update_running())
xml.node("start", [&] () {
gen_update_start_content(xml); });
if (_storage._sculpt_partition.valid() && !_prepare_in_progress())
_deploy.gen_runtime_start_nodes(xml);
}
void Component::construct(Genode::Env &env)
{
static Sculpt::Main main(env);
}

View File

@ -0,0 +1,99 @@
/*
* \brief Management of configurations that can be overridden by the user
* \author Norman Feske
* \date 2018-05-25
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MANAGED_CONFIG_H_
#define _MANAGED_CONFIG_H_
/* Genode includes */
#include <os/reporter.h>
#include <base/attached_rom_dataspace.h>
/* local includes */
#include <types.h>
namespace Sculpt { template <typename> struct Managed_config; }
template <typename HANDLER>
struct Sculpt::Managed_config
{
Env &_env;
typedef String<20> Xml_node_name;
typedef String<32> Rom_name;
enum Mode { MANAGED, MANUAL } _mode { MANAGED };
HANDLER &_obj;
void (HANDLER::*_handle) (Xml_node);
/*
* Configuration supplied by the user
*/
Attached_rom_dataspace _manual_config_rom;
/*
* Resulting configuration
*/
Expanding_reporter _config;
Signal_handler<Managed_config> _manual_config_handler {
_env.ep(), *this, &Managed_config::_handle_manual_config };
void _handle_manual_config()
{
_manual_config_rom.update();
Xml_node const config = _manual_config_rom.xml();
_mode = config.has_type("empty") ? MANAGED : MANUAL;
(_obj.*_handle)(config);
}
/**
* \return true if manually-managed configuration could be used
*/
bool try_generate_manually_managed()
{
if (_mode == MANAGED)
return false;
/*
* If a manually managed config at 'config/' is provided, copy its
* content to the effective config at 'config/managed/'.
*/
_config.generate(_manual_config_rom.xml());
return true;
}
template <typename FN>
void generate(FN const &fn)
{
_config.generate([&] (Xml_generator &xml) { fn(xml); });
}
Managed_config(Env &env, Xml_node_name const &xml_node_name,
Rom_name const &rom_name,
HANDLER &obj, void (HANDLER::*handle) (Xml_node))
:
_env(env), _obj(obj), _handle(handle),
_manual_config_rom(_env, Label("config -> ", rom_name).string()),
_config(_env, xml_node_name.string(), Label(rom_name, "_config").string())
{
_manual_config_rom.sigh(_manual_config_handler);
}
};
#endif /* _MANAGED_CONFIG_H_ */

View File

@ -0,0 +1,82 @@
/*
* \brief Representation of a wireless access point
* \author Norman Feske
* \date 2018-05-07
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__ACCESS_POINT_H_
#define _MODEL__ACCESS_POINT_H_
#include "types.h"
namespace Sculpt {
struct Access_point;
struct Access_point_update_policy;
typedef List_model<Access_point> Access_points;
};
struct Sculpt::Access_point : List_model<Access_point>::Element
{
typedef String<32> Bssid;
typedef String<32> Ssid;
enum Protection { UNKNOWN, UNPROTECTED, WPA_PSK };
Bssid const bssid;
Ssid const ssid;
Protection const protection;
unsigned quality = 0;
Access_point(Bssid const &bssid, Ssid const &ssid, Protection protection)
: bssid(bssid), ssid(ssid), protection(protection) { }
bool unprotected() const { return protection == UNPROTECTED; }
bool wpa_protected() const { return protection == WPA_PSK; }
};
/**
* Policy for transforming a 'wlan_accesspoints' report into a list model
*/
struct Sculpt::Access_point_update_policy : List_model<Access_point>::Update_policy
{
Allocator &_alloc;
Access_point_update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Access_point &elem) { destroy(_alloc, &elem); }
Access_point &create_element(Xml_node node)
{
auto const protection = node.attribute_value("protection", String<16>());
return *new (_alloc)
Access_point(node.attribute_value("bssid", Access_point::Bssid()),
node.attribute_value("ssid", Access_point::Ssid()),
protection == "WPA-PSK" ? Access_point::Protection::WPA_PSK :
Access_point::Protection::UNPROTECTED);
}
void update_element(Access_point &ap, Xml_node node)
{
ap.quality = node.attribute_value("quality", 0UL);
}
static bool element_matches_xml_node(Access_point const &elem, Xml_node node)
{
return node.attribute_value("ssid", Access_point::Ssid()) == elem.ssid;
}
};
#endif /* _MODEL__ACCESS_POINT_H_ */

View File

@ -0,0 +1,73 @@
/*
* \brief Representation of AHCI and NVMe devices
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__BLOCK_DEVICE_H_
#define _MODEL__BLOCK_DEVICE_H_
#include "storage_device.h"
namespace Sculpt {
struct Block_device;
struct Block_device_update_policy;
typedef List_model<Block_device> Block_devices;
};
struct Sculpt::Block_device : List_model<Block_device>::Element,
Storage_device
{
typedef String<16> Model;
Model const model;
Block_device(Env &env, Allocator &alloc, Signal_context_capability sigh,
Label const &label, Model const &model, Capacity capacity)
:
Storage_device(env, alloc, label, capacity, sigh), model(model)
{ }
};
struct Sculpt::Block_device_update_policy : List_model<Block_device>::Update_policy
{
Env &_env;
Allocator &_alloc;
Signal_context_capability _sigh;
Block_device_update_policy(Env &env, Allocator &alloc, Signal_context_capability sigh)
: _env(env), _alloc(alloc), _sigh(sigh) { }
void destroy_element(Block_device &elem) { destroy(_alloc, &elem); }
Block_device &create_element(Xml_node node)
{
return *new (_alloc)
Block_device(_env, _alloc, _sigh,
node.attribute_value("label", Block_device::Label()),
node.attribute_value("model", Block_device::Model()),
Capacity { node.attribute_value("block_size", 0ULL)
* node.attribute_value("block_count", 0ULL) });
}
void update_element(Block_device &, Xml_node) { }
static bool element_matches_xml_node(Block_device const &elem, Xml_node node)
{
return node.attribute_value("label", Block_device::Label()) == elem.label;
}
};
#endif /* _MODEL__BLOCK_DEVICE_H_ */

View File

@ -0,0 +1,37 @@
/*
* \brief Printable byte capacity
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__CAPACITY_H_
#define _MODEL__CAPACITY_H_
#include "types.h"
namespace Sculpt { struct Capacity; }
struct Sculpt::Capacity
{
uint64_t value;
void print(Output &out) const
{
uint64_t const KB = 1024, MB = 1024*KB, GB = 1024*MB;
typedef String<64> Text;
Text const text = (value > GB) ? Text((float)value/GB, " GiB")
: (value > MB) ? Text((float)value/MB, " MiB")
: (value > KB) ? Text((float)value/KB, " KiB")
: Text(value, " bytes");
Genode::print(out, text);
}
};
#endif /* _MODEL__CAPACITY_H_ */

View File

@ -0,0 +1,47 @@
/*
* \brief Utility for querying the child-exit state from init's state report
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__CHILD_EXIT_STATE_H_
#define _MODEL__CHILD_EXIT_STATE_H_
/* Genode includes */
#include <util/xml_node.h>
/* local includes */
#include "types.h"
namespace Sculpt { struct Child_exit_state; }
struct Sculpt::Child_exit_state
{
bool exists = false;
bool exited = false;
int code = 0;
typedef String<64> Name;
Child_exit_state(Xml_node init_state, Name const &name)
{
init_state.for_each_sub_node("child", [&] (Xml_node child) {
if (child.attribute_value("name", Name()) == name) {
exists = true;
if (child.has_attribute("exited")) {
exited = true;
code = child.attribute_value("exited", 0L);
}
}
});
}
};
#endif /* _MODEL__CHILD_EXIT_STATE_H_ */

View File

@ -0,0 +1,100 @@
/*
* \brief State of automated selection of the sculpt partition
* \author Norman Feske
* \date 2018-05-16
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__DISCOVERY_STATE_H_
#define _MODEL__DISCOVERY_STATE_H_
/* Genode includes */
#include <util/xml_node.h>
/* local includes */
#include <types.h>
#include <model/storage_target.h>
#include <model/storage_devices.h>
namespace Sculpt { struct Discovery_state; }
struct Sculpt::Discovery_state
{
bool user_intervention = false;
bool _done = false;
bool discovery_in_progress() const { return !_done; }
Storage_target detect_default_target(Storage_devices const &devices)
{
/* apply the automated selection only once */
if (_done)
return Storage_target { };
/* user intervention disarms the built-in selection policy */
if (user_intervention)
return Storage_target { };
/* defer decision until the low-level device enumeration is complete */
if (!devices.all_devices_enumerated())
return Storage_target { };
/*
* As long as not all devices are completely known, it is too early to
* take a decision.
*/
bool all_devices_discovered = true;
devices.for_each([&] (Storage_device const &device) {
if (device.state == Storage_device::UNKNOWN)
all_devices_discovered = false; });
if (!all_devices_discovered)
return Storage_target { };
/*
* Search for a partition with the magic label "GENODE*", or - if no
* such partition is present - a whole-device file system.
*
* Prefer USB storage devices over block devices. If no partition with
* the magic label is present but a block device that is formatted as
* a file system (the Sculpt EA way), this block device is selected.
*/
Storage_target target { };
auto check_partitions = [&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
if (!partition.whole_device()
&& partition.label == "GENODE*"
&& partition.file_system.accessible())
target = Storage_target { device.label, partition.number }; });
};
if (!target.valid())
devices.usb_storage_devices.for_each([&] (Storage_device const &device) {
check_partitions(device); });
if (!target.valid())
devices.block_devices.for_each([&] (Storage_device const &device) {
check_partitions(device); });
if (!target.valid())
devices.block_devices.for_each([&] (Storage_device const &device) {
if (device.whole_device
&& device.whole_device_partition->file_system.accessible())
target = Storage_target { device.label, Partition::Number() }; });
if (target.valid())
_done = true;
return target;
}
};
#endif /* _MODEL__DISCOVERY_STATE_H_ */

View File

@ -0,0 +1,41 @@
/*
* \brief State of the NIC session provided by the NIC router
* \author Norman Feske
* \date 2018-05-08
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__NIC_STATE_H_
#define _MODEL__NIC_STATE_H_
#include "types.h"
namespace Sculpt { struct Nic_state; }
struct Sculpt::Nic_state
{
typedef String<32> Ipv4;
Ipv4 ipv4;
static Nic_state from_xml(Xml_node node)
{
Ipv4 result { };
node.for_each_sub_node("domain", [&] (Xml_node domain) {
if (domain.attribute_value("name", String<16>()) == "uplink")
result = domain.attribute_value("ipv4", Ipv4()); });
return Nic_state { result };
}
bool ready() const { return ipv4.valid(); }
};
#endif /* _MODEL__NIC_STATE_H_ */

View File

@ -0,0 +1,40 @@
/*
* \brief Argument type for denoting a network interface
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__NIC_TARGET_H_
#define _MODEL__NIC_TARGET_H_
#include "types.h"
namespace Sculpt { struct Nic_target; }
struct Sculpt::Nic_target : Noncopyable
{
enum Type { OFF, LOCAL, WIRED, WIFI } type { OFF };
enum Policy { MANAGED, MANUAL } policy { MANAGED };
bool manual() const { return policy == MANUAL; }
bool managed() const { return policy == MANAGED; }
bool local() const { return type == LOCAL; }
bool wired() const { return type == WIRED; }
bool wifi() const { return type == WIFI; }
bool nic_router_needed() const { return type != OFF; }
bool ready() const { return type == WIRED || type == WIFI; }
};
#endif /* _MODEL__NIC_TARGET_H_ */

View File

@ -0,0 +1,170 @@
/*
* \brief Representation of block-device partition
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__PARTITION_H_
#define _MODEL__PARTITION_H_
#include "types.h"
#include "capacity.h"
namespace Sculpt {
struct File_system;
struct Partition;
struct Partition_update_policy;
typedef List_model<Partition> Partitions;
};
struct Sculpt::File_system
{
enum Type { UNKNOWN, EXT2, FAT32 } type;
bool accessible() const { return type == EXT2 || type == FAT32; }
bool expandable() const { return type == EXT2; }
File_system(Type type) : type(type) { }
};
struct Sculpt::Partition : List_model<Partition>::Element
{
typedef String<16> Number;
typedef String<32> Label;
enum Expandable { FIXED_SIZE, EXPANDABLE };
Number const number;
Label const label;
Capacity const capacity;
Expandable const _expandable;
Label next_label = label; /* used to set/unset the default partition */
File_system file_system;
bool check_in_progress = false;
bool format_in_progress = false;
bool file_system_inspected = false;
bool gpt_expand_in_progress = false;
bool fs_resize_in_progress = false;
bool relabel_in_progress() const { return label != next_label; }
bool expand_in_progress() const { return gpt_expand_in_progress
|| fs_resize_in_progress; }
bool checkable() const { return file_system.type == File_system::EXT2; }
bool expandable() const
{
return file_system.expandable() && _expandable == EXPANDABLE;
}
bool idle() const { return !check_in_progress
&& !format_in_progress
&& !file_system_inspected
&& !relabel_in_progress(); }
bool genode_default() const { return label == "GENODE*"; }
bool genode() const { return label == "GENODE" || genode_default(); }
void toggle_default_label()
{
if (label == "GENODE") next_label = Label("GENODE*");
if (label == "GENODE*") next_label = Label("GENODE");
}
struct Args
{
Number number;
Label label;
Capacity capacity;
Expandable expandable;
File_system::Type fs_type;
static Args from_xml(Xml_node node)
{
auto const file_system = node.attribute_value("file_system", String<16>());
File_system::Type const fs_type = (file_system == "Ext2") ? File_system::EXT2
: (file_system == "FAT32") ? File_system::FAT32
: File_system::UNKNOWN;
Number const number = node.attribute_value("number", Number());
unsigned long const block_size =
node.attribute_value("block_size", 512ULL);
unsigned long long const expandable =
node.attribute_value("expandable", 0ULL);
return Args { number == "0" ? Number{} : number,
node.attribute_value("name", Label()),
Capacity { node.attribute_value("length", 0ULL)*block_size },
(expandable*block_size > 1024*1024) ? EXPANDABLE : FIXED_SIZE,
fs_type };
}
static Args whole_device(Capacity capacity)
{
return { Number{}, "", capacity, FIXED_SIZE, File_system::UNKNOWN };
};
};
Partition(Args const &args)
:
number(args.number), label(args.label), capacity(args.capacity),
_expandable(args.expandable), file_system(args.fs_type)
{ }
bool whole_device() const { return !number.valid(); }
};
/**
* Policy for transforming a part_blk report into a list of partitions
*/
struct Sculpt::Partition_update_policy : List_model<Partition>::Update_policy
{
Allocator &_alloc;
Partition_update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Partition &elem) { destroy(_alloc, &elem); }
Partition &create_element(Xml_node node)
{
return *new (_alloc) Partition(Partition::Args::from_xml(node));
}
void update_element(Partition &, Xml_node) { }
static bool node_is_element(Xml_node node)
{
/*
* Partition "0" is a pseudo partition that refers to the whole device
* with no partition table.
*/
return (node.attribute_value("number", Partition::Number()) != "0");
}
static bool element_matches_xml_node(Partition const &elem, Xml_node node)
{
return node.attribute_value("number", Partition::Number()) == elem.number;
}
};
#endif /* _MODEL__PARTITION_H_ */

View File

@ -0,0 +1,36 @@
/*
* \brief Runtime state of the RAM file system
* \author Norman Feske
* \date 2018-05-15
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__RAM_FS_STATE_H_
#define _MODEL__RAM_FS_STATE_H_
/* Genode includes */
#include <util/xml_node.h>
/* local includes */
#include "types.h"
namespace Sculpt { struct Ram_fs_state; }
struct Sculpt::Ram_fs_state : Noncopyable
{
static Ram_quota initial_ram() { return Ram_quota{1024*1024}; }
Ram_quota ram_quota = initial_ram();
struct Version { unsigned value; } version { 0 };
bool inspected = false;
};
#endif /* _MODEL__RAM_FS_STATE_H_ */

View File

@ -0,0 +1,252 @@
/*
* \brief Common representation of all storage devices
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__STORAGE_DEVICE_H_
#define _MODEL__STORAGE_DEVICE_H_
#include "types.h"
#include "partition.h"
#include "capacity.h"
#include "xml.h"
namespace Sculpt { struct Storage_device; };
struct Sculpt::Storage_device
{
enum State {
UNKNOWN, /* partition information not yet known */
USED, /* part_blk is running and has reported partition info */
RELEASED /* partition info is known but part_blk is not running */
};
Allocator &_alloc;
typedef String<32> Label;
Label const label;
Capacity capacity; /* non-const because USB storage devices need to update it */
State state { UNKNOWN };
bool whole_device = false;
Reconstructible<Partition> whole_device_partition {
Partition::Args::whole_device(capacity) };
Partitions partitions { };
Attached_rom_dataspace _partitions_rom;
unsigned _part_blk_version = 0;
/**
* Trigger the rediscovery of the device, e.g., after partitioning of after
* formatting the whole device.
*/
void rediscover()
{
state = UNKNOWN;
_part_blk_version++;
Partition_update_policy policy(_alloc);
partitions.update_from_xml(policy, Xml_node("<partitions/>"));
}
void process_part_blk_report()
{
_partitions_rom.update();
Xml_node const report = _partitions_rom.xml();
if (!report.has_type("partitions"))
return;
whole_device = (report.attribute_value("type", String<16>()) == "disk");
Partition_update_policy policy(_alloc);
partitions.update_from_xml(policy, report);
/*
* Import whole-device partition information.
*
* Ignore reports that come in while the device is in use. Otherwise,
* the reconstruction of 'whole_device_partition' would wrongly reset
* the partition state such as the 'file_system_inspected' flag.
*/
if (!whole_device_partition.constructed() || whole_device_partition->idle()) {
whole_device_partition.construct(Partition::Args::whole_device(capacity));
report.for_each_sub_node("partition", [&] (Xml_node partition) {
if (partition.attribute_value("number", Partition::Number()) == "0")
whole_device_partition.construct(Partition::Args::from_xml(partition)); });
}
/* finish initial discovery phase */
if (state == UNKNOWN)
state = RELEASED;
}
/**
* Constructor
*
* \param label label of block device
* \param sigh signal handler to be notified on partition-info updates
*/
Storage_device(Env &env, Allocator &alloc, Label const &label,
Capacity capacity, Signal_context_capability sigh)
:
_alloc(alloc), label(label), capacity(capacity),
_partitions_rom(env, String<80>("report -> runtime/", label, ".part_blk/partitions").string())
{
_partitions_rom.sigh(sigh);
process_part_blk_report();
}
~Storage_device()
{
/* release partition info */
rediscover();
}
bool part_blk_needed_for_discovery() const
{
return state == UNKNOWN;
}
bool part_blk_needed_for_access() const
{
bool needed_for_access = false;
partitions.for_each([&] (Partition const &partition) {
needed_for_access |= partition.check_in_progress;
needed_for_access |= partition.format_in_progress;
needed_for_access |= partition.file_system_inspected;
needed_for_access |= partition.fs_resize_in_progress;
});
if (whole_device_partition->format_in_progress
|| whole_device_partition->check_in_progress) {
needed_for_access = false;
}
return needed_for_access;
}
/**
* Generate content of start node for part_blk
*
* \param service_name name of server that provides the block device, or
* if invalid, request block device from parent.
*/
inline void gen_part_blk_start_content(Xml_generator &xml, Label const &server_name) const;
template <typename FN>
void for_each_partition(FN const &fn) const
{
fn(*whole_device_partition);
partitions.for_each([&] (Partition const &partition) { fn(partition); });
}
template <typename FN>
void for_each_partition(FN const &fn)
{
fn(*whole_device_partition);
partitions.for_each([&] (Partition &partition) { fn(partition); });
}
bool all_partitions_idle() const
{
bool idle = true;
partitions.for_each([&] (Partition const &partition) {
idle &= partition.idle(); });
return idle;
}
bool relabel_in_progress() const
{
bool result = false;
partitions.for_each([&] (Partition const &partition) {
result |= partition.relabel_in_progress(); });
return result;
}
bool gpt_expand_in_progress() const
{
bool result = false;
partitions.for_each([&] (Partition const &partition) {
result |= partition.gpt_expand_in_progress; });
return result;
}
bool fs_resize_in_progress() const
{
bool result = false;
partitions.for_each([&] (Partition const &partition) {
result |= partition.fs_resize_in_progress; });
return result;
}
bool expand_in_progress() const
{
return gpt_expand_in_progress() || fs_resize_in_progress();
}
Start_name relabel_start_name() const { return Start_name(label, ".relabel"); }
Start_name expand_start_name() const { return Start_name(label, ".expand"); }
};
void Sculpt::Storage_device::gen_part_blk_start_content(Xml_generator &xml,
Label const &server_name) const
{
xml.attribute("version", _part_blk_version);
gen_common_start_content(xml, Label(label, ".part_blk"),
Cap_quota{100}, Ram_quota{8*1024*1024});
gen_named_node(xml, "binary", "part_blk");
xml.node("config", [&] () {
xml.node("report", [&] () { xml.attribute("partitions", "yes"); });
for (unsigned i = 1; i < 10; i++) {
xml.node("policy", [&] () {
xml.attribute("label", i);
xml.attribute("partition", i);
xml.attribute("writeable", "yes");
});
}
});
gen_provides<Block::Session>(xml);
xml.node("route", [&] () {
gen_parent_rom_route(xml, "part_blk");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_service_node<Block::Session>(xml, [&] () {
if (server_name.valid())
gen_named_node(xml, "child", server_name);
else
xml.node("parent", [&] () {
xml.attribute("label", label); }); });
gen_service_node<Report::Session>(xml, [&] () {
xml.attribute("label", "partitions");
xml.node("parent", [&] () { }); });
});
}
#endif /* _MODEL__STORAGE_DEVICE_H_ */

View File

@ -0,0 +1,86 @@
/*
* \brief Registry of known storage devices
* \author Norman Feske
* \date 2018-05-03
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__STORAGE_DEVICES_
#define _MODEL__STORAGE_DEVICES_
#include "types.h"
#include "block_device.h"
#include "usb_storage_device.h"
namespace Sculpt { struct Storage_devices; }
struct Sculpt::Storage_devices
{
Block_devices block_devices { };
Usb_storage_devices usb_storage_devices { };
bool _block_devices_report_valid = false;
bool _usb_active_config_valid = false;
/**
* Update 'block_devices' from 'block_devices' report
*/
template <typename POLICY>
void update_block_devices_from_xml(POLICY &policy, Xml_node node)
{
block_devices.update_from_xml(policy, node);
if (node.has_type("block_devices"))
_block_devices_report_valid = true;
}
/**
* Update 'usb_storage_devices' from 'usb_active_config' report
*/
template <typename POLICY>
void update_usb_storage_devices_from_xml(POLICY &policy, Xml_node node)
{
usb_storage_devices.update_from_xml(policy, node);
if (node.has_type("raw"))
_usb_active_config_valid = true;
}
/**
* Return true as soon as the storage-device information from the drivers
* subsystem is complete.
*/
bool all_devices_enumerated() const
{
return _block_devices_report_valid && _usb_active_config_valid;
}
template <typename FN>
void for_each(FN const &fn) const
{
block_devices.for_each([&] (Block_device const &dev) {
fn(dev); });
usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
fn(dev); });
}
template <typename FN>
void for_each(FN const &fn)
{
block_devices.for_each([&] (Block_device &dev) {
fn(dev); });
usb_storage_devices.for_each([&] (Usb_storage_device &dev) {
fn(dev); });
}
};
#endif /* _MODEL__STORAGE_DEVICES_ */

View File

@ -0,0 +1,85 @@
/*
* \brief Argument type for denoting a storage target
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__STORAGE_TARGET_H_
#define _MODEL__STORAGE_TARGET_H_
#include "types.h"
#include "storage_device.h"
namespace Sculpt { struct Storage_target; }
struct Sculpt::Storage_target
{
typedef String<Storage_device::Label::capacity() + 4> Label;
Storage_device::Label device;
Partition::Number partition;
bool operator == (Storage_target const &other) const
{
return (device == other.device) && (partition == other.partition);
}
bool operator != (Storage_target const &other) const { return !(*this == other); }
bool valid() const { return device.valid(); }
/**
* Return string to be used as session label referring to the target
*/
Label label() const
{
return partition.valid() ? Label(device, ".", partition) : Label(device);
}
Label fs() const { return Label(label(), ".fs"); }
bool ram_fs() const { return device == "ram_fs"; }
void gen_block_session_route(Xml_generator &xml) const
{
bool const ahci = (Label(Cstring(device.string(), 4)) == "ahci");
bool const nvme = (Label(Cstring(device.string(), 4)) == "nvme");
bool const usb = (Label(Cstring(device.string(), 3)) == "usb");
bool const whole_device = !partition.valid();
xml.node("service", [&] () {
xml.attribute("name", Block::Session::service_name());
if (whole_device) {
if (ahci || nvme)
xml.node("parent", [&] () { xml.attribute("label", device); });
if (usb)
xml.node("child", [&] () {
xml.attribute("name", Label(device, ".drv"));
xml.attribute("label", partition);
});
}
/* access partition */
else {
xml.node("child", [&] () {
xml.attribute("name", Label(device, ".part_blk"));
xml.attribute("label", partition);
});
}
});
}
};
#endif /* _MODEL__STORAGE_TARGET_H_ */

View File

@ -0,0 +1,172 @@
/*
* \brief Representation of USB storage devices
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__USB_STORAGE_DEVICE_H_
#define _MODEL__USB_STORAGE_DEVICE_H_
#include "storage_device.h"
namespace Sculpt {
struct Usb_storage_device;
struct Usb_storage_device_update_policy;
typedef List_model<Usb_storage_device> Usb_storage_devices;
};
struct Sculpt::Usb_storage_device : List_model<Usb_storage_device>::Element,
Storage_device
{
/**
* Information that is reported asynchronously by 'usb_block_drv'
*/
struct Driver_info
{
typedef String<28> Vendor;
typedef String<48> Product;
Vendor const vendor;
Product const product;
Driver_info(Xml_node device)
:
vendor (device.attribute_value("vendor", Vendor())),
product(device.attribute_value("product", Product()))
{ }
};
/* information provided asynchronously by usb_block_drv */
Constructible<Driver_info> driver_info { };
Attached_rom_dataspace _driver_report_rom;
void process_driver_report()
{
_driver_report_rom.update();
Xml_node report = _driver_report_rom.xml();
if (!report.has_sub_node("device"))
return;
Xml_node device = report.sub_node("device");
capacity = Capacity { device.attribute_value("block_count", 0ULL)
* device.attribute_value("block_size", 0ULL) };
driver_info.construct(device);
}
bool usb_block_drv_needed() const
{
bool drv_needed = false;
for_each_partition([&] (Partition const &partition) {
drv_needed |= partition.check_in_progress
|| partition.format_in_progress
|| partition.file_system_inspected
|| partition.relabel_in_progress()
|| partition.expand_in_progress(); });
return drv_needed || Storage_device::state == UNKNOWN;
}
Label usb_block_drv_name() const { return Label(label, ".drv"); }
Usb_storage_device(Env &env, Allocator &alloc, Signal_context_capability sigh,
Label const &label)
:
Storage_device(env, alloc, label, Capacity{0}, sigh),
_driver_report_rom(env, String<80>("report -> runtime/", usb_block_drv_name(),
"/devices").string())
{
_driver_report_rom.sigh(sigh);
process_driver_report();
}
inline void gen_usb_block_drv_start_content(Xml_generator &xml) const;
};
void Sculpt::Usb_storage_device::gen_usb_block_drv_start_content(Xml_generator &xml) const
{
gen_common_start_content(xml, usb_block_drv_name(),
Cap_quota{100}, Ram_quota{4*1024*1024});
gen_named_node(xml, "binary", "usb_block_drv");
xml.node("config", [&] () {
xml.attribute("report", "yes");
xml.attribute("writeable", "yes");
});
gen_provides<Block::Session>(xml);
xml.node("route", [&] () {
gen_parent_rom_route(xml, "usb_block_drv");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_service_node<Usb::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", label); }); });
gen_service_node<Report::Session>(xml, [&] () {
xml.node("parent", [&] () { }); });
});
}
struct Sculpt::Usb_storage_device_update_policy
:
List_model<Usb_storage_device>::Update_policy
{
Env &_env;
Allocator &_alloc;
Signal_context_capability _sigh;
Usb_storage_device_update_policy(Env &env, Allocator &alloc,
Signal_context_capability sigh)
:
_env(env), _alloc(alloc), _sigh(sigh)
{ }
typedef Usb_storage_device::Label Label;
void destroy_element(Usb_storage_device &elem) { destroy(_alloc, &elem); }
Usb_storage_device &create_element(Xml_node node)
{
return *new (_alloc)
Usb_storage_device(_env, _alloc, _sigh,
node.attribute_value("label_suffix", Label()));
}
void update_element(Usb_storage_device &, Xml_node) { }
static bool node_is_element(Xml_node node)
{
return node.attribute_value("class", String<32>()) == "storage";
};
static bool element_matches_xml_node(Usb_storage_device const &elem, Xml_node node)
{
return node.attribute_value("label_suffix", Label()) == elem.label;
}
};
#endif /* _MODEL__BLOCK_DEVICE_H_ */

View File

@ -0,0 +1,60 @@
/*
* \brief Connection state of the wireless driver
* \author Norman Feske
* \date 2018-05-08
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__WIFI_CONNECTION_H_
#define _MODEL__WIFI_CONNECTION_H_
#include "access_point.h"
namespace Sculpt { struct Wifi_connection; }
struct Sculpt::Wifi_connection
{
enum State { DISCONNECTED, CONNECTING, CONNECTED };
State state;
Access_point::Bssid bssid;
Access_point::Ssid ssid;
/**
* Create 'Wifi_connection' object from 'wlan_state' report
*/
static Wifi_connection from_xml(Xml_node node)
{
bool const connected =
node.has_sub_node("accesspoint") &&
node.sub_node("accesspoint").attribute("state").has_value("connected");
if (!connected)
return { .state = DISCONNECTED,
.bssid = Access_point::Bssid{},
.ssid = Access_point::Bssid{} };
Xml_node const ap = node.sub_node("accesspoint");
return { .state = CONNECTED,
.bssid = ap.attribute_value("bssid", Access_point::Bssid()),
.ssid = ap.attribute_value("ssid", Access_point::Ssid()) };
}
static Wifi_connection disconnected_wifi_connection()
{
return Wifi_connection { DISCONNECTED, Access_point::Bssid{}, Access_point::Ssid{} };
}
bool connected() const { return state == CONNECTED; }
};
#endif /* _MODEL__WIFI_CONNECTION_H_ */

View File

@ -0,0 +1,122 @@
/*
* \brief WPA passphrase
* \author Norman Feske
* \date 2018-05-23
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__WPA_PASSPHRASE_H_
#define _MODEL__WPA_PASSPHRASE_H_
#include <base/output.h>
#include <util/utf8.h>
#include <types.h>
#include <xml.h>
namespace Sculpt {
struct Blind_wpa_passphrase;
struct Wpa_passphrase;
}
struct Sculpt::Blind_wpa_passphrase
{
virtual void print_bullets(Output &) const = 0;
virtual ~Blind_wpa_passphrase() { }
void print(Output &out) const { print_bullets(out); }
virtual bool suitable_for_connect() const = 0;
};
struct Sculpt::Wpa_passphrase : Blind_wpa_passphrase
{
private:
enum { CAPACITY = 64 };
Codepoint _characters[CAPACITY] { };
unsigned _length = 0;
public:
/**
* Print PSK as UTF-8 string
*/
void print(Output &out) const
{
/*
* XXX duplicated from gems/src/server/terminal/main.cc
*/
struct Utf8 { char b0, b1, b2, b3, b4; };
auto utf8_from_codepoint = [] (unsigned c) {
/* extract 'n' bits 'at' bit position of value 'c' */
auto bits = [c] (unsigned at, unsigned n) {
return (c >> at) & ((1 << n) - 1); };
return (c < 2<<7) ? Utf8 { char(bits( 0, 7)), 0, 0, 0, 0 }
: (c < 2<<11) ? Utf8 { char(bits( 6, 5) | 0xc0),
char(bits( 0, 6) | 0x80), 0, 0, 0 }
: (c < 2<<16) ? Utf8 { char(bits(12, 4) | 0xe0),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0, 0 }
: (c < 2<<21) ? Utf8 { char(bits(18, 3) | 0xf0),
char(bits(12, 6) | 0x80),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0 }
: Utf8 { };
};
for (unsigned i = 0; i < _length; i++) {
Utf8 const utf8 = utf8_from_codepoint(_characters[i].value);
auto _print = [&] (char c) {
if (c)
Genode::print(out, Char(c)); };
_print(utf8.b0); _print(utf8.b1); _print(utf8.b2);
_print(utf8.b3); _print(utf8.b4);
}
}
void append_character(Codepoint c)
{
if (_length < CAPACITY) {
_characters[_length] = c;
_length++;
}
}
void remove_last_character()
{
if (_length > 0) {
_length--;
_characters[_length].value = 0;
}
}
/**
* Print passphrase as a number of bullets
*/
void print_bullets(Output &out) const override
{
char const bullet_utf8[4] = { (char)0xe2, (char)0x80, (char)0xa2, 0 };
for (unsigned i = 0; i < _length; i++)
Genode::print(out, bullet_utf8);
}
bool suitable_for_connect() const override { return _length >= 8; }
};
#endif /* _MODEL__WPA_PASSPHRASE_H_ */

View File

@ -0,0 +1,202 @@
/*
* \brief Sculpt network management
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <network.h>
void Sculpt::Network::handle_key_press(Codepoint code)
{
enum { BACKSPACE = 8, ENTER = 10 };
if (code.value == BACKSPACE)
wpa_passphrase.remove_last_character();
else if (code.value == ENTER)
wifi_connect(dialog.selected_ap());
else if (code.value != 0)
wpa_passphrase.append_character(code);
/*
* Keep updating the passphase when pressing keys after
* clicking the connect button once.
*/
if (_wifi_connection.state == Wifi_connection::CONNECTING)
wifi_connect(_wifi_connection.bssid);
_dialog_generator.generate_dialog();
}
void Sculpt::Network::_generate_nic_router_config()
{
if ((_nic_target.wired() && !_runtime_info.present_in_runtime("nic_drv"))
|| (_nic_target.wifi() && !_runtime_info.present_in_runtime("wifi_drv"))) {
/* defer NIC router reconfiguration until the needed uplink is present */
_nic_router_config_up_to_date = false;
return;
}
_nic_router_config_up_to_date = true;
if (_nic_router_config.try_generate_manually_managed())
return;
if (!_nic_target.nic_router_needed()) {
_nic_router_config.generate([&] (Xml_generator &xml) {
xml.attribute("verbose_domain_state", "yes"); });
return;
}
_nic_router_config.generate([&] (Xml_generator &xml) {
xml.attribute("verbose_domain_state", "yes");
xml.node("report", [&] () {
xml.attribute("interval_sec", "5");
xml.attribute("bytes", "yes");
xml.attribute("config", "yes");
xml.attribute("config_triggers", "yes");
});
xml.node("default-policy", [&] () {
xml.attribute("domain", "default"); });
if (_nic_target.type != Nic_target::LOCAL) {
gen_named_node(xml, "domain", "uplink", [&] () {
switch (_nic_target.type) {
case Nic_target::WIRED: xml.attribute("label", "wired"); break;
case Nic_target::WIFI: xml.attribute("label", "wifi"); break;
default: break;
}
xml.node("nat", [&] () {
xml.attribute("domain", "default");
xml.attribute("tcp-ports", "1000");
xml.attribute("udp-ports", "1000");
xml.attribute("icmp-ids", "1000");
});
});
}
gen_named_node(xml, "domain", "default", [&] () {
xml.attribute("interface", "10.0.1.1/24");
xml.node("dhcp-server", [&] () {
xml.attribute("ip_first", "10.0.1.2");
xml.attribute("ip_last", "10.0.1.200");
if (_nic_target.type != Nic_target::LOCAL) {
xml.attribute("dns_server_from", "uplink"); }
});
if (_nic_target.type != Nic_target::LOCAL) {
xml.node("tcp", [&] () {
xml.attribute("dst", "0.0.0.0/0");
xml.node("permit-any", [&] () {
xml.attribute("domain", "uplink"); }); });
xml.node("udp", [&] () {
xml.attribute("dst", "0.0.0.0/0");
xml.node("permit-any", [&] () {
xml.attribute("domain", "uplink"); }); });
xml.node("icmp", [&] () {
xml.attribute("dst", "0.0.0.0/0");
xml.attribute("domain", "uplink"); });
}
});
});
}
void Sculpt::Network::_handle_wlan_accesspoints()
{
bool const initial_scan = !_wlan_accesspoints_rom.xml().has_sub_node("accesspoint");
_wlan_accesspoints_rom.update();
/* suppress updating the list while the access-point list is hovered */
if (!initial_scan && dialog.ap_list_hovered())
return;
Access_point_update_policy policy(_alloc);
_access_points.update_from_xml(policy, _wlan_accesspoints_rom.xml());
_dialog_generator.generate_dialog();
}
void Sculpt::Network::_handle_wlan_state()
{
_wlan_state_rom.update();
_wifi_connection = Wifi_connection::from_xml(_wlan_state_rom.xml());
_dialog_generator.generate_dialog();
}
void Sculpt::Network::_handle_nic_router_state()
{
_nic_router_state_rom.update();
Nic_state const old_nic_state = _nic_state;
_nic_state = Nic_state::from_xml(_nic_router_state_rom.xml());
if (_nic_state.ipv4 != old_nic_state.ipv4)
_dialog_generator.generate_dialog();
/* if the nic state becomes ready, consider spawning the update subsystem */
if (old_nic_state.ready() != _nic_state.ready())
_runtime_config_generator.generate_runtime_config();
}
void Sculpt::Network::_handle_nic_router_config(Xml_node config)
{
_nic_target.policy = config.has_type("empty")
? Nic_target::MANAGED : Nic_target::MANUAL;
/* obtain uplink information from configuration */
Nic_target::Type target = Nic_target::LOCAL;
target = Nic_target::LOCAL;
if (!config.has_sub_node("domain"))
target = Nic_target::OFF;
config.for_each_sub_node("domain", [&] (Xml_node domain) {
/* skip non-uplink domains */
if (domain.attribute_value("name", String<16>()) != "uplink")
return;
if (domain.attribute_value("label", String<16>()) == "wired")
target = Nic_target::WIRED;
if (domain.attribute_value("label", String<16>()) == "wifi")
target = Nic_target::WIFI;
});
nic_target(target);
_generate_nic_router_config();
_runtime_config_generator.generate_runtime_config();
_dialog_generator.generate_dialog();
}
void Sculpt::Network::gen_runtime_start_nodes(Xml_generator &xml) const
{
if (_use_nic_drv)
xml.node("start", [&] () { gen_nic_drv_start_content(xml); });
if (_use_wifi_drv)
xml.node("start", [&] () { gen_wifi_drv_start_content(xml); });
if (_nic_target.type != Nic_target::OFF)
xml.node("start", [&] () {
gen_nic_router_start_content(xml); });
}

View File

@ -0,0 +1,203 @@
/*
* \brief Sculpt network management
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NETWORK_H_
#define _NETWORK_H_
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
/* local includes */
#include <model/child_exit_state.h>
#include <view/network_dialog.h>
#include <gui.h>
#include <runtime.h>
#include <keyboard_focus.h>
#include <managed_config.h>
namespace Sculpt { struct Network; }
struct Sculpt::Network : Network_dialog::Action
{
Env &_env;
Allocator &_alloc;
Dialog::Generator &_dialog_generator;
Runtime_config_generator &_runtime_config_generator;
Runtime_info const &_runtime_info;
Nic_target _nic_target { };
Nic_state _nic_state { };
bool _nic_router_config_up_to_date = false;
Wpa_passphrase wpa_passphrase { };
bool _use_nic_drv = false;
bool _use_wifi_drv = false;
Attached_rom_dataspace _wlan_accesspoints_rom {
_env, "report -> runtime/wifi_drv/wlan_accesspoints" };
Attached_rom_dataspace _wlan_state_rom {
_env, "report -> runtime/wifi_drv/wlan_state" };
Attached_rom_dataspace _nic_router_state_rom {
_env, "report -> runtime/nic_router/state" };
void _generate_nic_router_config();
Access_points _access_points { };
Wifi_connection _wifi_connection = Wifi_connection::disconnected_wifi_connection();
void gen_runtime_start_nodes(Xml_generator &xml) const;
bool ready() const { return _nic_target.ready() && _nic_state.ready(); }
void handle_key_press(Codepoint);
void _handle_wlan_accesspoints();
void _handle_wlan_state();
void _handle_nic_router_state();
void _handle_nic_router_config(Xml_node);
Managed_config<Network> _nic_router_config {
_env, "config", "nic_router", *this, &Network::_handle_nic_router_config };
Signal_handler<Network> _wlan_accesspoints_handler {
_env.ep(), *this, &Network::_handle_wlan_accesspoints };
Signal_handler<Network> _wlan_state_handler {
_env.ep(), *this, &Network::_handle_wlan_state };
Signal_handler<Network> _nic_router_state_handler {
_env.ep(), *this, &Network::_handle_nic_router_state };
Network_dialog::Wlan_config_policy _wlan_config_policy =
Network_dialog::WLAN_CONFIG_MANAGED;
Network_dialog dialog {
_env, _dialog_generator, _nic_target, _access_points,
_wifi_connection, _nic_state, wpa_passphrase, _wlan_config_policy };
Managed_config<Network> _wlan_config {
_env, "selected_network", "wlan", *this, &Network::_handle_wlan_config };
void _handle_wlan_config(Xml_node)
{
if (_wlan_config.try_generate_manually_managed()) {
_wlan_config_policy = Network_dialog::WLAN_CONFIG_MANUAL;
_dialog_generator.generate_dialog();
return;
}
_wlan_config_policy = Network_dialog::WLAN_CONFIG_MANAGED;;
if (_wifi_connection.connected())
wifi_connect(_wifi_connection.bssid);
else
wifi_disconnect();
}
void reattempt_nic_router_config()
{
if (_nic_target.nic_router_needed() && !_nic_router_config_up_to_date)
_generate_nic_router_config();
}
/**
* Network_dialog::Action interface
*/
void nic_target(Nic_target::Type const type) override
{
/*
* Start drivers on first use but never remove them to avoid
* driver-restarting issues.
*/
if (type == Nic_target::WIFI) _use_wifi_drv = true;
if (type == Nic_target::WIRED) _use_nic_drv = true;
if (type != _nic_target.type) {
_nic_target.type = type;
_generate_nic_router_config();
_runtime_config_generator.generate_runtime_config();
_dialog_generator.generate_dialog();
}
}
void wifi_connect(Access_point::Bssid bssid) override
{
_access_points.for_each([&] (Access_point const &ap) {
if (ap.bssid != bssid)
return;
_wifi_connection.ssid = ap.ssid;
_wifi_connection.bssid = ap.bssid;
_wifi_connection.state = Wifi_connection::CONNECTING;
_wlan_config.generate([&] (Xml_generator &xml) {
xml.attribute("ssid", ap.ssid);
if (ap.protection == Access_point::WPA_PSK) {
xml.attribute("protection", "WPA-PSK");
String<128> const psk(wpa_passphrase);
xml.attribute("psk", psk);
}
});
});
}
void wifi_disconnect() override
{
/*
* Reflect state change immediately to the user interface even
* if the wifi driver will take a while to perform the disconnect.
*/
_wifi_connection = Wifi_connection::disconnected_wifi_connection();
_wlan_config.generate([&] (Xml_generator &xml) {
/* generate attributes to ease subsequent manual tweaking */
xml.attribute("ssid", "");
xml.attribute("protection", "WPA-PSK");
xml.attribute("psk", "");
});
_runtime_config_generator.generate_runtime_config();
}
Network(Env &env, Allocator &alloc, Dialog::Generator &dialog_generator,
Runtime_config_generator &runtime_config_generator,
Runtime_info const &runtime_info)
:
_env(env), _alloc(alloc), _dialog_generator(dialog_generator),
_runtime_config_generator(runtime_config_generator),
_runtime_info(runtime_info)
{
_generate_nic_router_config();
/*
* Subscribe to reports
*/
_wlan_accesspoints_rom.sigh(_wlan_accesspoints_handler);
_wlan_state_rom .sigh(_wlan_state_handler);
_nic_router_state_rom .sigh(_nic_router_state_handler);
}
};
#endif /* _NETWORK_H_ */

View File

@ -0,0 +1,131 @@
/*
* \brief Nitpicker wrapper for monitoring the user input of GUI components
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include "nitpicker.h"
/* Genode includes */
#include <input/component.h>
#include <nitpicker_session/connection.h>
#include <base/heap.h>
struct Nitpicker::Session_component : Rpc_object<Nitpicker::Session>
{
Env &_env;
Input_event_handler &_event_handler;
Nitpicker::Connection _connection;
Input::Session_component _input_component { _env, _env.ram() };
Signal_handler<Session_component> _input_handler {
_env.ep(), *this, &Session_component::_handle_input };
void _handle_input()
{
_connection.input()->for_each_event([&] (Input::Event ev) {
/* handle event locally within the sculpt manager */
_event_handler.handle_input_event(ev);
_input_component.submit(ev);
});
}
Session_component(Env &env, char const *args, Input_event_handler &event_handler)
:
_env(env), _event_handler(event_handler),
_connection(env, session_label_from_args(args).string())
{
_connection.input()->sigh(_input_handler);
_env.ep().manage(_input_component);
_input_component.event_queue().enabled(true);
}
~Session_component() { _env.ep().dissolve(_input_component); }
void upgrade(Session::Resources const &resources)
{
_connection.upgrade(resources);
}
Framebuffer::Session_capability framebuffer_session() override {
return _connection.framebuffer_session(); }
Input::Session_capability input_session() override {
return _input_component.cap(); }
View_handle create_view(View_handle parent) override {
return _connection.create_view(parent); }
void destroy_view(View_handle view) override {
_connection.destroy_view(view); }
View_handle view_handle(View_capability view_cap, View_handle handle) override {
return _connection.view_handle(view_cap, handle); }
View_capability view_capability(View_handle view) override {
return _connection.view_capability(view); }
void release_view_handle(View_handle view) override {
_connection.release_view_handle(view); }
Dataspace_capability command_dataspace() override {
return _connection.command_dataspace(); }
void execute() override {
_connection.execute(); }
Framebuffer::Mode mode() override {
return _connection.mode(); }
void mode_sigh(Signal_context_capability sigh) override {
_connection.mode_sigh(sigh); }
void buffer(Framebuffer::Mode mode, bool use_alpha) override {
_connection.buffer(mode, use_alpha); }
void focus(Capability<Nitpicker::Session> session) override {
_connection.focus(session); }
};
Nitpicker::Session_component *Nitpicker::Root::_create_session(const char *args)
{
return new (md_alloc()) Session_component(_env, args, _event_handler);
}
void Nitpicker::Root::_upgrade_session(Session_component *session, const char *args)
{
session->upgrade(session_resources_from_args(args));
}
void Nitpicker::Root::_destroy_session(Session_component *session)
{
Genode::destroy(md_alloc(), session);
}
Nitpicker::Root::Root(Env &env, Allocator &md_alloc, Input_event_handler &event_handler)
:
Root_component<Session_component>(env.ep(), md_alloc),
_env(env), _event_handler(event_handler)
{
env.parent().announce(env.ep().manage(*this));
}
Nitpicker::Root::~Root() { _env.ep().dissolve(*this); }

View File

@ -0,0 +1,49 @@
/*
* \brief Nitpicker wrapper for monitoring the user input of GUI components
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NITPICKER_H_
#define _NITPICKER_H_
/* Genode includes */
#include <root/component.h>
#include <nitpicker_session/nitpicker_session.h>
#include <base/component.h>
/* local includes */
#include "input_event_handler.h"
namespace Nitpicker {
using namespace Genode;
using Sculpt::Input_event_handler;
struct Session_component;
struct Root;
}
struct Nitpicker::Root : Genode::Root_component<Session_component>
{
Env &_env;
Input_event_handler &_event_handler;
Session_component *_create_session(const char *) override;
void _upgrade_session(Session_component *, const char *) override;
void _destroy_session(Session_component *) override;
Root(Env &, Allocator &, Input_event_handler &);
~Root();
};
#endif /* _NITPICKER_H_ */

View File

@ -0,0 +1,73 @@
/*
* \brief Utilities for generating runtime configurations
* \author Norman Feske
* \date 2018-05-18
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _RUNTIME_H_
#define _RUNTIME_H_
#include <xml.h>
#include <model/ram_fs_state.h>
#include <model/storage_devices.h>
#include <model/storage_target.h>
#include <model/nic_target.h>
namespace Sculpt {
struct Runtime_config_generator : Interface
{
virtual void generate_runtime_config() = 0;
};
struct Runtime_info : Interface
{
/**
* Return true if specified child is present in the runtime subsystem
*/
virtual bool present_in_runtime(Start_name const &) const = 0;
};
void gen_chroot_start_content(Xml_generator &, Start_name const &,
Path const &, Writeable);
void gen_depot_query_start_content(Xml_generator &);
struct File_browser_version { unsigned value; };
void gen_file_browser(Xml_generator &, Storage_devices const &,
Ram_fs_state const &, File_browser_version);
void gen_fs_start_content(Xml_generator &, Storage_target const &,
File_system::Type);
void gen_fs_rom_start_content(Xml_generator &, Start_name const &, Start_name const &, Ram_quota);
void gen_gpt_relabel_start_content(Xml_generator &, Storage_device const &);
void gen_gpt_expand_start_content (Xml_generator &, Storage_device const &);
void gen_nic_drv_start_content(Xml_generator &);
void gen_wifi_drv_start_content(Xml_generator &);
void gen_nic_router_start_content(Xml_generator &);
void gen_nic_router_uplink(Xml_generator &, char const *);
struct Prepare_version { unsigned value; };
void gen_prepare_start_content(Xml_generator &, Prepare_version);
void gen_ram_fs_start_content(Xml_generator &, Ram_fs_state const &);
void gen_update_start_content(Xml_generator &);
void gen_fsck_ext2_start_content(Xml_generator &, Storage_target const &);
void gen_mkfs_ext2_start_content(Xml_generator &, Storage_target const &);
void gen_resize2fs_start_content(Xml_generator &, Storage_target const &);
}
#endif /* _RUNTIME_H_ */

View File

@ -0,0 +1,44 @@
/*
* \brief XML configuration for the chroot component
* \author Norman Feske
* \date 2018-05-18
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_chroot_start_content(Xml_generator &xml, Start_name const &name,
Path const &path, Writeable writable)
{
gen_common_start_content(xml, name, Cap_quota{100}, Ram_quota{2*1024*1024});
gen_named_node(xml, "binary", "chroot");
xml.node("config", [&] () {
xml.node("default-policy", [&] () {
xml.attribute("path", path);
if (writable == WRITEABLE)
xml.attribute("writeable", "yes");
});
});
gen_provides<::File_system::Session>(xml);
xml.node("route", [&] () {
gen_service_node<::File_system::Session>(xml, [&] () {
gen_named_node(xml, "child", "default_fs_rw"); });
gen_parent_rom_route(xml, "chroot");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session>(xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session>(xml);
});
}

View File

@ -0,0 +1,43 @@
/*
* \brief XML configuration for the depot-query tool
* \author Norman Feske
* \date 2018-05-09
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_depot_query_start_content(Xml_generator &xml)
{
gen_common_start_content(xml, "depot_query",
Cap_quota{200}, Ram_quota{2*1024*1024});
gen_named_node(xml, "binary", "depot_query");
xml.node("config", [&] () {
xml.attribute("query", "rom");
xml.node("vfs", [&] () {
gen_named_node(xml, "dir", "depot", [&] () {
xml.node("fs", [&] () {}); }); }); });
xml.node("route", [&] () {
gen_parent_rom_route(xml, "depot_query");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "query", "config -> managed/depot_query");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Report::Session> (xml);
gen_service_node<::File_system::Session>(xml, [&] () {
gen_named_node(xml, "child", "depot"); });
});
}

View File

@ -0,0 +1,107 @@
/*
* \brief XML configuration for invoking e2fstools
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
namespace Sculpt {
template <typename GEN_ARGS_FN>
void gen_e2fs_start_content(Xml_generator &, Storage_target const &,
Rom_name const &, GEN_ARGS_FN const &);
}
template <typename GEN_ARGS_FN>
void Sculpt::gen_e2fs_start_content(Xml_generator &xml,
Storage_target const &target,
Rom_name const &tool,
GEN_ARGS_FN const &gen_args_fn)
{
gen_common_start_content(xml, String<64>(target.label(), ".", tool),
Cap_quota{500}, Ram_quota{100*1024*1024});
gen_named_node(xml, "binary", "noux");
xml.node("config", [&] () {
xml.attribute("stdout", "/dev/log");
xml.attribute("stderr", "/dev/log");
xml.attribute("stdin", "/dev/null");
xml.node("fstab", [&] () {
gen_named_node(xml, "tar", "e2fsprogs-minimal.tar");
gen_named_node(xml, "dir", "dev", [&] () {
gen_named_node(xml, "block", "block", [&] () {
xml.attribute("label", "default");
xml.attribute("block_buffer_count", 128);
});
xml.node("null", [&] () {});
xml.node("log", [&] () {});
});
});
gen_named_node(xml, "start", Rom_name("/bin/", tool), [&] () {
gen_args_fn(xml); });
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "noux");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Rom_session> (xml);
gen_parent_route<Timer::Session> (xml);
target.gen_block_session_route(xml);
});
}
void Sculpt::gen_fsck_ext2_start_content(Xml_generator &xml,
Storage_target const &target)
{
auto gen_args = [&] (Xml_generator &xml) {
xml.node("arg", [&] () { xml.attribute("value", "-yv"); });
xml.node("arg", [&] () { xml.attribute("value", "/dev/block"); });
};
gen_e2fs_start_content(xml, target, "fsck.ext2", gen_args);
}
void Sculpt::gen_mkfs_ext2_start_content(Xml_generator &xml,
Storage_target const &target)
{
auto gen_args = [&] (Xml_generator &xml) {
xml.node("arg", [&] () {
xml.attribute("value", "/dev/block"); }); };
gen_e2fs_start_content(xml, target, "mkfs.ext2", gen_args);
}
void Sculpt::gen_resize2fs_start_content(Xml_generator &xml,
Storage_target const &target)
{
auto gen_args = [&] (Xml_generator &xml) {
auto gen_arg = [&] (char const *arg) {
xml.node("arg", [&] () {
xml.attribute("value", arg); }); };
gen_arg("-f");
gen_arg("-p");
gen_arg("/dev/block");
};
gen_e2fs_start_content(xml, target, "resize2fs", gen_args);
}

View File

@ -0,0 +1,227 @@
/*
* \brief XML configuration for file-browser subsystem
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
namespace Sculpt {
template <typename FN>
void for_each_inspected_storage_target(Storage_devices const &devices, FN const &fn)
{
devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
if (partition.file_system_inspected)
fn(Storage_target { device.label, partition.number }); }); });
}
void gen_nit_fb_start(Xml_generator &, Rom_name const &);
void gen_terminal_start(Xml_generator &, Rom_name const &, Rom_name const &,
File_browser_version);
void gen_noux_start(Xml_generator &, Rom_name const &, Rom_name const &,
Storage_devices const &, Ram_fs_state const &, File_browser_version);
}
void Sculpt::gen_nit_fb_start(Xml_generator &xml, Rom_name const &name)
{
gen_common_start_content(xml, name, Cap_quota{100}, Ram_quota{4*1024*1024});
gen_named_node(xml, "binary", "nit_fb");
xml.node("provides", [&] () {
gen_service_node<Framebuffer::Session>(xml, [&] () {});
gen_service_node<Input::Session>(xml, [&] () {});
});
xml.node("config", [&] () {
xml.attribute("initial_width", "600");
xml.attribute("initial_height", "500");
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "nit_fb");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_service_node<Nitpicker::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", String<64>("leitzentrale -> ", name)); }); });
});
}
void Sculpt::gen_terminal_start(Xml_generator &xml, Rom_name const &name,
Rom_name const &nit_fb_name,
File_browser_version version)
{
xml.attribute("version", version.value);
gen_common_start_content(xml, name, Cap_quota{100}, Ram_quota{4*1024*1024});
gen_named_node(xml, "binary", "terminal");
gen_provides<Terminal::Session>(xml);
xml.node("route", [&] () {
gen_parent_rom_route(xml, "terminal");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "vfs_ttf.lib.so");
gen_parent_rom_route(xml, "Vera.ttf");
gen_parent_rom_route(xml, "VeraMono.ttf");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_named_node(xml, "service", Rom_session::service_name(), [&] () {
xml.attribute("label", "config");
xml.node("parent", [&] () {
xml.attribute("label", "config -> managed/fonts"); }); });
gen_service_node<Framebuffer::Session>(xml, [&] () {
gen_named_node(xml, "child", nit_fb_name); });
gen_service_node<Input::Session>(xml, [&] () {
gen_named_node(xml, "child", nit_fb_name); });
});
}
void Sculpt::gen_noux_start(Xml_generator &xml, Rom_name const &name,
Rom_name const &terminal_name,
Storage_devices const &devices,
Ram_fs_state const &ram_fs_state,
File_browser_version version)
{
xml.attribute("version", version.value);
gen_common_start_content(xml, name, Cap_quota{500}, Ram_quota{64*1024*1024});
gen_named_node(xml, "binary", "noux");
xml.node("config", [&] () {
xml.node("fstab", [&] () {
gen_named_node(xml, "tar", "bash-minimal.tar");
gen_named_node(xml, "tar", "coreutils-minimal.tar");
gen_named_node(xml, "tar", "vim-minimal.tar");
gen_named_node(xml, "dir", "dev", [&] () {
xml.node("null", [&] () {});
xml.node("zero", [&] () {});
});
gen_named_node(xml, "dir", "share", [&] () {
gen_named_node(xml, "tar", "depot_users.tar"); });
auto fs_dir = [&] (String<64> const &label) {
gen_named_node(xml, "dir", label, [&] () {
xml.node("fs", [&] () { xml.attribute("label", label); }); }); };
fs_dir("config");
fs_dir("report");
for_each_inspected_storage_target(devices, [&] (Storage_target const &target) {
fs_dir(target.label()); });
if (ram_fs_state.inspected)
fs_dir("ram");
gen_named_node(xml, "dir", "tmp", [&] () {
xml.node("ram", [&] () { }); });
gen_named_node(xml, "dir", "share", [&] () {
gen_named_node(xml, "dir", "vim", [&] () {
xml.node("rom", [&] () {
xml.attribute("name", "vimrc"); }); }); });
gen_named_node(xml, "rom", "VERSION");
});
gen_named_node(xml, "start", "/bin/bash", [&] () {
gen_named_node(xml, "env", "TERM", [&] () {
xml.attribute("value", "screen"); });
gen_named_node(xml, "env", "PS1", [&] () {
xml.attribute("value", "inspect:$PWD> "); });
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "noux");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libc_noux.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "bash-minimal.tar");
gen_parent_rom_route(xml, "coreutils-minimal.tar");
gen_parent_rom_route(xml, "vim-minimal.tar");
gen_parent_rom_route(xml, "ncurses.lib.so");
gen_parent_rom_route(xml, "posix.lib.so");
gen_parent_rom_route(xml, "depot_users.tar");
gen_parent_rom_route(xml, "vimrc");
gen_parent_rom_route(xml, "VERSION");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_service_node<Terminal::Session>(xml, [&] () {
gen_named_node(xml, "child", terminal_name); });
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "config");
xml.node("parent", [&] () { xml.attribute("label", "config"); });
});
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "report");
xml.node("parent", [&] () { xml.attribute("label", "report"); });
});
for_each_inspected_storage_target(devices, [&] (Storage_target const &target) {
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", target.label());
gen_named_node(xml, "child", target.fs());
});
});
if (ram_fs_state.inspected)
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "ram");
gen_named_node(xml, "child", "ram_fs");
});
});
}
void Sculpt::gen_file_browser(Xml_generator &xml,
Storage_devices const &devices,
Ram_fs_state const &ram_fs_state,
File_browser_version version)
{
xml.node("start", [&] () {
gen_nit_fb_start(xml, "storage browser"); });
xml.node("start", [&] () {
gen_terminal_start(xml, "storage browser terminal", "storage browser",
version); });
xml.node("start", [&] () {
gen_noux_start(xml, "storage browser noux", "storage browser terminal",
devices, ram_fs_state, version); });
}

View File

@ -0,0 +1,60 @@
/*
* \brief XML configuration for file-system server
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_fs_start_content(Xml_generator &xml,
Storage_target const &target,
File_system::Type fs_type)
{
gen_common_start_content(xml, target.fs(),
Cap_quota{400}, Ram_quota{64*1024*1024});
gen_named_node(xml, "binary", "vfs");
gen_provides<::File_system::Session>(xml);
xml.node("config", [&] () {
xml.node("vfs", [&] () {
xml.node("rump", [&] () {
switch (fs_type) {
case File_system::EXT2: xml.attribute("fs", "ext2fs"); break;
case File_system::FAT32: xml.attribute("fs", "msdos"); break;
case File_system::UNKNOWN: break;
};
xml.attribute("ram", "48M");
xml.attribute("writeable", "yes");
});
});
xml.node("default-policy", [&] () {
xml.attribute("root", "/");
xml.attribute("writeable", "yes");
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "vfs");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "vfs_rump.lib.so");
gen_parent_rom_route(xml, "rump.lib.so");
gen_parent_rom_route(xml, "rump_fs.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Rm_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
target.gen_block_session_route(xml);
});
}

View File

@ -0,0 +1,41 @@
/*
* \brief XML configuration for the fs-rom component
* \author Norman Feske
* \date 2018-05-09
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_fs_rom_start_content(Xml_generator &xml,
Start_name const &name,
Start_name const &server,
Ram_quota ram_quota)
{
gen_common_start_content(xml, name,
Cap_quota{200}, ram_quota);
gen_named_node(xml, "binary", "fs_rom");
xml.node("config", [&] () { });
gen_provides<Rom_session>(xml);
xml.node("route", [&] () {
gen_service_node<::File_system::Session>(xml, [&] () {
gen_named_node(xml, "child", server); });
gen_parent_rom_route(xml, "fs_rom");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session>(xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session>(xml);
});
}

View File

@ -0,0 +1,81 @@
/*
* \brief XML configuration for invoking the gpt_write_tool
* \author Norman Feske
* \date 2018-05-16
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
namespace Sculpt {
template <typename GEN_ACTIONS_FN>
void _gen_gpt_write_start_content(Xml_generator &, Storage_device const &,
Start_name const &, GEN_ACTIONS_FN const &);
}
template <typename GEN_ACTIONS_FN>
void Sculpt::_gen_gpt_write_start_content(Xml_generator &xml,
Storage_device const &device,
Start_name const &name,
GEN_ACTIONS_FN const &fn)
{
gen_common_start_content(xml, name, Cap_quota{100}, Ram_quota{2*1024*1024});
gen_named_node(xml, "binary", "gpt_write");
xml.node("config", [&] () {
xml.attribute("verbose", "yes");
xml.attribute("update_geometry", "yes");
xml.node("actions", [&] () { fn(xml); });
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "gpt_write");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Rom_session> (xml);
Storage_target const target { device.label, Partition::Number { } };
target.gen_block_session_route(xml);
});
}
void Sculpt::gen_gpt_relabel_start_content(Xml_generator &xml,
Storage_device const &device)
{
Start_name const name = device.relabel_start_name();
_gen_gpt_write_start_content(xml, device, name, [&] (Xml_generator &xml) {
device.for_each_partition([&] (Partition const &partition) {
if (partition.number.valid() && partition.relabel_in_progress())
xml.node("modify", [&] () {
xml.attribute("entry", partition.number);
xml.attribute("new_label", partition.next_label); }); }); });
}
void Sculpt::gen_gpt_expand_start_content(Xml_generator &xml,
Storage_device const &device)
{
Start_name const name = device.expand_start_name();
_gen_gpt_write_start_content(xml, device, name, [&] (Xml_generator &xml) {
device.for_each_partition([&] (Partition const &partition) {
if (partition.number.valid() && partition.gpt_expand_in_progress)
xml.node("modify", [&] () {
xml.attribute("entry", partition.number);
xml.attribute("new_size", "max"); }); }); });
}

View File

@ -0,0 +1,37 @@
/*
* \brief XML configuration for wired NIC driver
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_nic_drv_start_content(Xml_generator &xml)
{
gen_common_start_content(xml, "nic_drv", Cap_quota{300}, Ram_quota{16*1024*1024});
gen_provides<Nic::Session>(xml);
xml.node("config", [&] () { });
xml.node("route", [&] () {
gen_parent_rom_route(xml, "nic_drv");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Rm_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_service_node<Platform::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", "nic"); }); });
});
}

View File

@ -0,0 +1,43 @@
/*
* \brief XML configuration for the NIC router
* \author Norman Feske
* \date 2018-05-08
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_nic_router_start_content(Xml_generator &xml)
{
gen_common_start_content(xml, "nic_router",
Cap_quota{300}, Ram_quota{10*1024*1024});
gen_provides<Nic::Session>(xml);
xml.node("route", [&] () {
gen_parent_rom_route(xml, "nic_router");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "config", "config -> managed/nic_router");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Rm_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_parent_route<Report::Session> (xml);
gen_service_node<Nic::Session>(xml, [&] () {
xml.attribute("label", "wired");
gen_named_node(xml, "child", "nic_drv");
});
gen_service_node<Nic::Session>(xml, [&] () {
xml.attribute("label", "wifi");
gen_named_node(xml, "child", "wifi_drv");
});
});
}

View File

@ -0,0 +1,97 @@
/*
* \brief XML configuration for config loading and depot initialization
* \author Norman Feske
* \date 2018-05-08
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_prepare_start_content(Xml_generator &xml, Prepare_version version)
{
xml.attribute("version", version.value);
gen_common_start_content(xml, "prepare", Cap_quota{500}, Ram_quota{100*1024*1024});
gen_named_node(xml, "binary", "noux");
char const * const script =
"export VERSION=`cat /VERSION`\n"
"cp -r /rw/config/$VERSION/* /config/\n"
"mkdir -p /rw/depot\n"
"cp -r depot/genodelabs depot/alex-ab depot/chelmuth depot/cproc"
" depot/cnuke depot/ehmry depot/nfeske depot/skalk"
" /rw/depot\n";
xml.node("config", [&] () {
xml.attribute("stdout", "/dev/null");
xml.attribute("stderr", "/dev/null");
xml.attribute("stdin", "/dev/null");
xml.node("fstab", [&] () {
gen_named_node(xml, "tar", "bash-minimal.tar");
gen_named_node(xml, "tar", "coreutils-minimal.tar");
gen_named_node(xml, "tar", "depot_users.tar");
gen_named_node(xml, "inline", ".bash_profile", [&] () {
xml.append(script); });
gen_named_node(xml, "dir", "dev", [&] () {
xml.node("null", [&] () {});
xml.node("log", [&] () {});
xml.node("zero", [&] () {}); });
gen_named_node(xml, "dir", "rw", [&] () {
xml.node("fs", [&] () { xml.attribute("label", "target"); }); });
gen_named_node(xml, "dir", "config", [&] () {
xml.node("fs", [&] () { xml.attribute("label", "config"); }); });
gen_named_node(xml, "rom", "VERSION");
});
gen_named_node(xml, "start", "/bin/bash", [&] () {
gen_named_node(xml, "env", "HOME", [&] () {
xml.attribute("value", "/"); });
gen_named_node(xml, "env", "TERM", [&] () {
xml.attribute("value", "screen"); });
xml.node("arg", [&] () { xml.attribute("value", "--login"); });
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "noux");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "bash-minimal.tar");
gen_parent_rom_route(xml, "coreutils-minimal.tar");
gen_parent_rom_route(xml, "depot_users.tar");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libc_noux.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "posix.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Rom_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "target");
gen_named_node(xml, "child", "default_fs_rw"); });
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "config");
xml.node("parent", [&] () { xml.attribute("label", "config"); }); });
});
}

View File

@ -0,0 +1,39 @@
/*
* \brief XML configuration for RAM file system
* \author Norman Feske
* \date 2018-05-15
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_ram_fs_start_content(Xml_generator &xml,
Ram_fs_state const &state)
{
xml.attribute("version", state.version.value);
gen_common_start_content(xml, "ram_fs", Cap_quota{300}, state.ram_quota);
gen_provides<::File_system::Session>(xml);
xml.node("config", [&] () {
xml.node("default-policy", [&] () {
xml.attribute("root", "/");
xml.attribute("writeable", "yes");
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "ram_fs");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
});
}

View File

@ -0,0 +1,81 @@
/*
* \brief XML configuration for the depot-download subsystem
* \author Norman Feske
* \date 2018-05-08
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_update_start_content(Xml_generator &xml)
{
gen_common_start_content(xml, "update", Cap_quota{2000}, Ram_quota{64*1024*1024});
gen_named_node(xml, "binary", "init");
xml.node("route", [&] () {
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "extract");
gen_parent_rom_route(xml, "verify");
gen_parent_rom_route(xml, "fetchurl");
gen_parent_rom_route(xml, "chroot");
gen_parent_rom_route(xml, "curl.lib.so");
gen_parent_rom_route(xml, "init");
gen_parent_rom_route(xml, "depot_query");
gen_parent_rom_route(xml, "depot_download_manager");
gen_parent_rom_route(xml, "report_rom");
gen_parent_rom_route(xml, "vfs");
gen_parent_rom_route(xml, "lxip.lib.so");
gen_parent_rom_route(xml, "vfs_lxip.lib.so");
gen_parent_rom_route(xml, "posix.lib.so");
gen_parent_rom_route(xml, "libssh.lib.so");
gen_parent_rom_route(xml, "libssl.lib.so");
gen_parent_rom_route(xml, "libcrypto.lib.so");
gen_parent_rom_route(xml, "zlib.lib.so");
gen_parent_rom_route(xml, "libarchive.lib.so");
gen_parent_rom_route(xml, "liblzma.lib.so");
gen_parent_rom_route(xml, "pthread.lib.so");
gen_parent_rom_route(xml, "config", "depot_download.config");
gen_parent_rom_route(xml, "installation", "config -> managed/installation");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Rm_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_parent_route<Report::Session>(xml);
typedef String<32> Label;
auto gen_fs = [&] (Label const &label, Label const &server) {
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", label);
gen_named_node(xml, "child", server); }); };
/* connect file-system sessions to chroot instances */
gen_fs("depot", "depot_rw");
gen_fs("public", "public_rw");
auto gen_relabeled_log = [&] (Label const &label, Label const &relabeled) {
gen_service_node<Log_session>(xml, [&] () {
xml.attribute("label", label);
xml.node("parent", [&] () {
xml.attribute("label", relabeled); }); }); };
/* shorten LOG-session labels to reduce the debug-output noise */
gen_relabeled_log("dynamic -> fetchurl", "fetchurl");
gen_relabeled_log("dynamic -> verify", "verify");
gen_relabeled_log("dynamic -> extract", "extract");
gen_parent_route<Log_session>(xml);
gen_service_node<Nic::Session>(xml, [&] () {
gen_named_node(xml, "child", "nic_router"); });
});
}

View File

@ -0,0 +1,84 @@
/*
* \brief XML configuration for wireless driver
* \author Norman Feske
* \date 2018-05-02
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <runtime.h>
void Sculpt::gen_wifi_drv_start_content(Xml_generator &xml)
{
gen_common_start_content(xml, "wifi_drv", Cap_quota{300}, Ram_quota{54*1024*1024});
gen_provides<Nic::Session>(xml);
xml.node("config", [&] () {
xml.attribute("connected_scan_interval", "0");
xml.attribute("use_11n", "no");
xml.node("vfs", [&] () {
gen_named_node(xml, "dir", "dev", [&] () {
xml.node("null", [&] () {});
xml.node("zero", [&] () {});
xml.node("rtc", [&] () {});
xml.node("log", [&] () {});
gen_named_node(xml, "jitterentropy", "random");
gen_named_node(xml, "jitterentropy", "urandom"); });
gen_named_node(xml, "dir", "config", [&] () {
xml.node("ram", [&] () {}); });
});
xml.node("libc", [&] () {
xml.attribute("stdout", "/dev/null");
xml.attribute("stderr", "/dev/log");
xml.attribute("rtc", "/dev/rtc");
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "wifi_drv");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "libcrypto.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "vfs_jitterentropy.lib.so");
gen_parent_rom_route(xml, "libssl.lib.so");
gen_parent_rom_route(xml, "wifi.lib.so");
gen_parent_rom_route(xml, "wpa_driver_nl80211.lib.so");
gen_parent_rom_route(xml, "wpa_supplicant.lib.so");
gen_parent_rom_route(xml, "iwlwifi-1000-5.ucode");
gen_parent_rom_route(xml, "iwlwifi-3160-16.ucode");
gen_parent_rom_route(xml, "iwlwifi-6000-4.ucode");
gen_parent_rom_route(xml, "iwlwifi-6000g2a-6.ucode");
gen_parent_rom_route(xml, "iwlwifi-6000g2b-6.ucode");
gen_parent_rom_route(xml, "iwlwifi-7260-16.ucode");
gen_parent_rom_route(xml, "iwlwifi-7265-16.ucode");
gen_parent_rom_route(xml, "iwlwifi-7265D-16.ucode");
gen_parent_rom_route(xml, "iwlwifi-8000C-16.ucode");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Rm_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_parent_route<Rtc::Session> (xml);
gen_parent_route<Report::Session> (xml);
gen_service_node<Rom_session>(xml, [&] () {
xml.attribute("label", "wlan_configuration");
xml.node("parent", [&] () {
xml.attribute("label", "config -> managed/wlan"); }); });
gen_service_node<Platform::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", "wifi"); }); });
});
}

View File

@ -0,0 +1,156 @@
/*
* \brief Sculpt storage management
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <storage.h>
void Sculpt::Storage::handle_storage_devices_update()
{
bool reconfigure_runtime = false;
{
_block_devices_rom.update();
Block_device_update_policy policy(_env, _alloc, _storage_device_update_handler);
_storage_devices.update_block_devices_from_xml(policy, _block_devices_rom.xml());
_storage_devices.block_devices.for_each([&] (Block_device &dev) {
dev.process_part_blk_report();
if (dev.state == Storage_device::UNKNOWN) {
reconfigure_runtime = true; };
});
}
{
_usb_active_config_rom.update();
Usb_storage_device_update_policy policy(_env, _alloc, _storage_device_update_handler);
Xml_node const config = _usb_active_config_rom.xml();
Xml_node const raw = config.has_sub_node("raw")
? config.sub_node("raw") : Xml_node("<raw/>");
_storage_devices.update_usb_storage_devices_from_xml(policy, raw);
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device &dev) {
dev.process_driver_report();
dev.process_part_blk_report();
if (dev.state == Storage_device::UNKNOWN) {
reconfigure_runtime = true; };
});
}
if (!_sculpt_partition.valid()) {
Storage_target const default_target =
_discovery_state.detect_default_target(_storage_devices);
if (default_target.valid())
use(default_target);
}
_dialog_generator.generate_dialog();
if (reconfigure_runtime)
_runtime_config_generator.generate_runtime_config();
}
void Sculpt::Storage::gen_runtime_start_nodes(Xml_generator &xml) const
{
xml.node("start", [&] () {
gen_ram_fs_start_content(xml, _ram_fs_state); });
auto part_blk_needed_for_use = [&] (Storage_device const &dev) {
return (_sculpt_partition.device == dev.label)
&& _sculpt_partition.partition.valid(); };
_storage_devices.block_devices.for_each([&] (Block_device const &dev) {
if (dev.part_blk_needed_for_discovery()
|| dev.part_blk_needed_for_access()
|| part_blk_needed_for_use(dev))
xml.node("start", [&] () {
Storage_device::Label const parent { };
dev.gen_part_blk_start_content(xml, parent); }); });
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
if (dev.usb_block_drv_needed() || _sculpt_partition.device == dev.label)
xml.node("start", [&] () {
dev.gen_usb_block_drv_start_content(xml); });
if (dev.part_blk_needed_for_discovery()
|| dev.part_blk_needed_for_access()
|| part_blk_needed_for_use(dev))
xml.node("start", [&] () {
Storage_device::Label const driver = dev.usb_block_drv_name();
dev.gen_part_blk_start_content(xml, driver);
});
});
_storage_devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
Storage_target const target { device.label, partition.number };
if (partition.check_in_progress) {
xml.node("start", [&] () {
gen_fsck_ext2_start_content(xml, target); }); }
if (partition.format_in_progress) {
xml.node("start", [&] () {
gen_mkfs_ext2_start_content(xml, target); }); }
if (partition.fs_resize_in_progress) {
xml.node("start", [&] () {
gen_resize2fs_start_content(xml, target); }); }
if (partition.file_system.type != File_system::UNKNOWN) {
if (partition.file_system_inspected || target == _sculpt_partition)
xml.node("start", [&] () {
gen_fs_start_content(xml, target, partition.file_system.type); });
/*
* Create alias so that the default file system can be referred
* to as "default_fs_rw" without the need to know the name of the
* underlying storage target.
*/
if (target == _sculpt_partition)
gen_named_node(xml, "alias", "default_fs_rw", [&] () {
xml.attribute("child", target.fs()); });
}
}); /* for each partition */
/* relabel partitions if needed */
if (device.relabel_in_progress())
xml.node("start", [&] () {
gen_gpt_relabel_start_content(xml, device); });
/* expand partitions if needed */
if (device.expand_in_progress())
xml.node("start", [&] () {
gen_gpt_expand_start_content(xml, device); });
}); /* for each device */
if (_sculpt_partition.ram_fs())
gen_named_node(xml, "alias", "default_fs_rw", [&] () {
xml.attribute("child", "ram_fs"); });
}

View File

@ -0,0 +1,207 @@
/*
* \brief Sculpt storage management
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _STORAGE_H_
#define _STORAGE_H_
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
/* local includes */
#include <model/discovery_state.h>
#include <view/storage_dialog.h>
#include <runtime.h>
namespace Sculpt { struct Storage; }
struct Sculpt::Storage : Storage_dialog::Action
{
Env &_env;
Allocator &_alloc;
Dialog::Generator &_dialog_generator;
Runtime_config_generator &_runtime_config_generator;
struct Target_user : Interface
{
virtual void use_storage_target(Storage_target const &) = 0;
};
Target_user &_target_user;
Attached_rom_dataspace _block_devices_rom { _env, "report -> drivers/block_devices" };
Attached_rom_dataspace _usb_active_config_rom { _env, "report -> drivers/usb_active_config" };
Storage_devices _storage_devices { };
Ram_fs_state _ram_fs_state { };
Storage_target _sculpt_partition { };
Discovery_state _discovery_state { };
File_browser_version _file_browser_version { 0 };
Storage_dialog dialog {
_env, _dialog_generator, _storage_devices, _ram_fs_state, _sculpt_partition };
void handle_storage_devices_update();
Signal_handler<Storage> _storage_device_update_handler {
_env.ep(), *this, &Storage::handle_storage_devices_update };
/*
* Determine whether showing the file-system browser or not
*/
bool any_file_system_inspected() const
{
bool result = _ram_fs_state.inspected;
_storage_devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
result |= partition.file_system_inspected; }); });
return result;
}
void gen_runtime_start_nodes(Xml_generator &) const;
template <typename FN>
void _apply_partition(Storage_target const &target, FN const &fn)
{
_storage_devices.for_each([&] (Storage_device &device) {
if (target.device != device.label)
return;
device.for_each_partition([&] (Partition &partition) {
bool const whole_device = !target.partition.valid()
&& !partition.number.valid();
bool const partition_matches = (device.label == target.device)
&& (partition.number == target.partition);
if (whole_device || partition_matches) {
fn(partition);
_runtime_config_generator.generate_runtime_config();
}
});
});
}
/**
* Storage_dialog::Action interface
*/
void format(Storage_target const &target) override
{
_apply_partition(target, [&] (Partition &partition) {
partition.format_in_progress = true; });
}
void cancel_format(Storage_target const &target) override
{
_apply_partition(target, [&] (Partition &partition) {
if (partition.format_in_progress) {
partition.file_system.type = File_system::UNKNOWN;
partition.format_in_progress = false;
}
dialog.reset_operation();
});
}
void expand(Storage_target const &target) override
{
_apply_partition(target, [&] (Partition &partition) {
partition.gpt_expand_in_progress = true; });
}
void cancel_expand(Storage_target const &target) override
{
_apply_partition(target, [&] (Partition &partition) {
if (partition.expand_in_progress()) {
partition.file_system.type = File_system::UNKNOWN;
partition.gpt_expand_in_progress = false;
partition.fs_resize_in_progress = false;
}
dialog.reset_operation();
});
}
void check(Storage_target const &target) override
{
_apply_partition(target, [&] (Partition &partition) {
partition.check_in_progress = true; });
}
void toggle_file_browser(Storage_target const &target) override
{
File_browser_version const orig_version = _file_browser_version;
if (target.ram_fs()) {
_ram_fs_state.inspected = !_ram_fs_state.inspected;
_file_browser_version.value++;
}
_apply_partition(target, [&] (Partition &partition) {
partition.file_system_inspected = !partition.file_system_inspected;
_file_browser_version.value++;
});
if (orig_version.value == _file_browser_version.value)
return;
_runtime_config_generator.generate_runtime_config();
}
void toggle_default_storage_target(Storage_target const &target) override
{
_apply_partition(target, [&] (Partition &partition) {
partition.toggle_default_label(); });
}
void use(Storage_target const &target) override
{
_target_user.use_storage_target(target);
}
void reset_ram_fs() override
{
_ram_fs_state.ram_quota = Ram_fs_state::initial_ram();
_ram_fs_state.version.value++;
dialog.reset_operation();
_runtime_config_generator.generate_runtime_config();
}
Storage(Env &env, Allocator &alloc, Dialog::Generator &dialog_generator,
Runtime_config_generator &runtime_config_generator,
Target_user &target_user)
:
_env(env), _alloc(alloc),
_dialog_generator(dialog_generator),
_runtime_config_generator(runtime_config_generator),
_target_user(target_user)
{
_block_devices_rom .sigh(_storage_device_update_handler);
_usb_active_config_rom.sigh(_storage_device_update_handler);
}
};
#endif /* _STORAGE_H_ */

View File

@ -0,0 +1,7 @@
TARGET := sculpt_manager
SRC_CC := $(notdir $(wildcard $(PRG_DIR)/*.cc))
SRC_CC += $(addprefix runtime/,$(notdir $(wildcard $(PRG_DIR)/runtime/*.cc)))
SRC_CC += $(addprefix view/, $(notdir $(wildcard $(PRG_DIR)/view/*.cc)))
SRC_CC += $(addprefix model/, $(notdir $(wildcard $(PRG_DIR)/model/*.cc)))
LIBS += base
INC_DIR += $(PRG_DIR) $(REP_DIR)/src/app/depot_deploy

View File

@ -0,0 +1,49 @@
/*
* \brief Common types used within the Sculpt manager
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _TYPES_H_
#define _TYPES_H_
#include <util/list_model.h>
#include <base/env.h>
#include <base/attached_rom_dataspace.h>
#include <platform_session/platform_session.h>
#include <nitpicker_session/nitpicker_session.h>
#include <usb_session/usb_session.h>
#include <log_session/log_session.h>
#include <timer_session/timer_session.h>
#include <file_system_session/file_system_session.h>
#include <report_session/report_session.h>
#include <block_session/block_session.h>
#include <terminal_session/terminal_session.h>
#include <rom_session/rom_session.h>
#include <rm_session/rm_session.h>
#include <nic_session/nic_session.h>
#include <rtc_session/rtc_session.h>
#include <trace_session/trace_session.h>
namespace Sculpt {
using namespace Genode;
typedef String<32> Rom_name;
typedef String<128> Path;
typedef String<36> Start_name;
typedef String<64> Label;
typedef Nitpicker::Point Point;
enum Writeable { WRITEABLE, READ_ONLY };
}
#endif /* _TYPES_H_ */

View File

@ -0,0 +1,65 @@
/*
* \brief GUI element that can be activated on clack
* \author Norman Feske
* \date 2018-05-03
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__ACTIVATABLE_ITEM_H_
#define _VIEW__ACTIVATABLE_ITEM_H_
#include "hoverable_item.h"
namespace Sculpt { struct Activatable_item; }
struct Sculpt::Activatable_item : Hoverable_item
{
typedef Hoverable_item::Id Id;
Id _selected { };
Id _activated { };
/**
* Apply click - if item is hovered, the click selects the item but
* does not activate it yet
*/
void propose_activation_on_click()
{
_selected = _hovered;
}
void confirm_activation_on_clack()
{
if (_hovered.valid() && (_hovered == _selected))
_activated = _selected;
}
void reset() { _selected = Id{}, _activated = Id{}; }
/**
* Return true if item is currently activated
*/
bool activated(Id const &id) const { return id == _activated; }
/**
* Generate button attributes depending on the item state
*/
void gen_button_attr(Xml_generator &xml, Id const &id) const
{
/* hover only as long as the button is not activated */
if (!_selected.valid() || !_activated.valid())
Hoverable_item::gen_button_attr(xml, id);
if (_selected.valid() && _selected == _hovered)
xml.attribute("selected", "yes");
}
};
#endif /* _VIEW__ACTIVATABLE_ITEM_H_ */

View File

@ -0,0 +1,39 @@
/*
* \brief Menu-view dialog handling
* \author Norman Feske
* \date 2018-05-18
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__DIALOG_H_
#define _VIEW__DIALOG_H_
/* Genode includes */
#include <input/event.h>
/* local includes */
#include "types.h"
namespace Sculpt { struct Dialog; }
struct Sculpt::Dialog : Interface
{
/**
* Interface for triggering the (re-)generation of a menu-view dialog
*
* This interface ls implemented by a top-level dialog and called by a sub
* dialog.
*/
struct Generator : Interface { virtual void generate_dialog() = 0; };
virtual void hover(Xml_node hover) = 0;
};
#endif /* _VIEW__DIALOG_H_ */

View File

@ -0,0 +1,69 @@
/*
* \brief Generate download-status view
* \author Norman Feske
* \date 2018-05-18
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__DOWNLOAD_STATUS_H_
#define _VIEW__DOWNLOAD_STATUS_H_
/* local includes */
#include <xml.h>
namespace Sculpt { static void gen_download_status(Xml_generator &, Xml_node); }
void Sculpt::gen_download_status(Xml_generator &xml, Xml_node state)
{
gen_named_node(xml, "frame", "downloads", [&] () {
xml.node("vbox", [&] () {
xml.node("label", [&] () {
xml.attribute("text", "Download"); });
unsigned count = 0;
state.for_each_sub_node("archive", [&] (Xml_node archive) {
gen_named_node(xml, "hbox", String<10>(count++), [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
typedef String<40> Path;
xml.node("label", [&] () {
xml.attribute("text", archive.attribute_value("path", Path()));
xml.attribute("font", "annotation/regular");
});
});
typedef String<16> Info;
Info info = archive.attribute_value("state", Info());
float const total = archive.attribute_value("total", 0.0);
float const now = archive.attribute_value("now", 0.0);
if (info == "download") {
if (total > 0.0)
info = Info((unsigned)((100*now)/total), "%");
else
info = Info("fetch");
}
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", info);
xml.attribute("font", "annotation/regular");
});
});
});
});
});
});
}
#endif /* _VIEW__DOWNLOAD_STATUS_H_ */

View File

@ -0,0 +1,58 @@
/*
* \brief GUI element that shows hovering feedback
* \author Norman Feske
* \date 2018-05-03
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__HOVERABLE_ITEM_H_
#define _VIEW__HOVERABLE_ITEM_H_
#include "types.h"
#include "xml.h"
namespace Sculpt { struct Hoverable_item; }
struct Sculpt::Hoverable_item
{
typedef String<64> Id;
Id _hovered { };
/**
* Set ID to matching hover sub node name
*
* \return true if hovering changed
*/
template <typename... ARGS>
bool match(Xml_node hover, ARGS &&... args)
{
Id const orig = _hovered;
_hovered = query_attribute<Id>(hover, args...);
return _hovered != orig;
}
/**
* Return true if item is currently hovered
*/
bool hovered(Id const &id) const { return id == _hovered; }
/**
* Generate button attributes depending on the item state
*/
void gen_button_attr(Xml_generator &xml, Id const &id) const
{
xml.attribute("name", id);
if (hovered(id)) xml.attribute("hovered", "yes");
}
};
#endif /* _VIEW__HOVERABLE_ITEM_H_ */

View File

@ -0,0 +1,295 @@
/*
* \brief Network management dialog
* \author Norman Feske
* \date 2018-05-07
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
/* local includes */
#include "network_dialog.h"
void Sculpt::Network_dialog::_gen_access_point(Xml_generator &xml,
Access_point const &ap) const
{
gen_named_node(xml, "hbox", ap.bssid, [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "button", [&] () {
if (_wifi_connection.connected())
xml.attribute("selected", "yes");
else
_ap_item.gen_button_attr(xml, ap.bssid);
xml.node("label", [&] () {
xml.attribute("text", " "); }); });
gen_named_node(xml, "label", "ssid", [&] () {
xml.attribute("text", String<20>(" ", ap.ssid)); });
gen_named_node(xml, "label", "protection", [&] () {
xml.attribute("font", "annotation/regular");
if (ap.protection == Access_point::WPA_PSK)
xml.attribute("text", " (WPA) ");
else
xml.attribute("text", " ");
});
});
});
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<8>(ap.quality, "%")); });
});
});
}
bool Sculpt::Network_dialog::_selected_ap_visible() const
{
unsigned cnt = 0;
return _for_each_ap([&] (Access_point const &ap) {
return (cnt++ < _max_visible_aps) && _ap_item.selected(ap.bssid); });
}
bool Sculpt::Network_dialog::_selected_ap_unprotected() const
{
return _for_each_ap([&] (Access_point const &ap) {
return _ap_item.selected(ap.bssid) && ap.unprotected(); });
}
bool Sculpt::Network_dialog::need_keyboard_focus_for_passphrase() const
{
if (_wifi_connection.state == Wifi_connection::CONNECTED)
return false;
return _for_each_ap([&] (Access_point const &ap) {
return _ap_item.selected(ap.bssid) && ap.wpa_protected(); });
}
void Sculpt::Network_dialog::_gen_access_point_list(Xml_generator &xml) const
{
if (_wlan_config_policy == WLAN_CONFIG_MANUAL)
return;
bool const selected_ap_visible = _selected_ap_visible();
unsigned cnt = 0;
_access_points.for_each([&] (Access_point const &ap) {
if (cnt++ >= _max_visible_aps)
return;
/*
* Whenever the user has selected an access point, hide all others.
* Should the selected AP disappear from the list, show all others.
*/
bool const selected = _ap_item.selected(ap.bssid);
if (selected_ap_visible && !selected)
return;
_gen_access_point(xml, ap);
if (!selected)
return;
bool const connected_to_selected_ap =
(selected && _wifi_connection.bssid == ap.bssid)
&& _wifi_connection.state == Wifi_connection::CONNECTED;
if (connected_to_selected_ap)
return;
if (ap.protection == Access_point::WPA_PSK) {
gen_named_node(xml, "label", "passphrase msg", [&] () {
xml.attribute("text", "Enter passphrase:"); });
gen_named_node(xml, "frame", "passphrase", [&] () {
xml.node("float", [&] () {
xml.attribute("west", "yes");
xml.node("label", [&] () {
xml.attribute("font", "title/regular");
xml.attribute("text", String<3*64>(" ", _wpa_passphrase));
});
});
});
if (_wpa_passphrase.suitable_for_connect()) {
xml.node("button", [&] () {
if (_wifi_connection.state == Wifi_connection::CONNECTING)
xml.attribute("selected", "yes");
/* suppress hover while connecting */
else
_connect_item.gen_button_attr(xml, "connect");
xml.node("label", [&] () {
xml.attribute("text", "Connect"); });
});
}
}
});
/*
* Present motivational message until we get the first 'wlan_accesspoints'
* report.
*/
if (cnt == 0)
xml.node("label", [&] () {
xml.attribute("text", "Scanning..."); });
}
void Sculpt::Network_dialog::_gen_connected_ap(Xml_generator &xml) const
{
bool done = false;
/*
* Try to present complete info including the quality from access-point
* list.
*/
_access_points.for_each([&] (Access_point const &ap) {
if (!done && _wifi_connection.bssid == ap.bssid) {
_gen_access_point(xml, ap);
done = true;
}
});
/*
* If access point is not present in the list, fall back to the information
* given in the 'wlan_state' report.
*/
if (!done)
_gen_access_point(xml, Access_point { _wifi_connection.bssid,
_wifi_connection.ssid,
Access_point::UNKNOWN });
gen_named_node(xml, "label", "associated", [&] () {
xml.attribute("text", "associated"); });
}
void Sculpt::Network_dialog::generate(Xml_generator &xml) const
{
gen_named_node(xml, "frame", "network", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "label", "title", [&] () {
xml.attribute("text", "Network");
xml.attribute("font", "title/regular");
});
gen_named_node(xml, "hbox", "type", [&] () {
auto gen_nic_button = [&] (Hoverable_item::Id const &id,
Nic_target::Type const type,
String<10> const &label) {
gen_named_node(xml, "button", id, [&] () {
_nic_item.gen_button_attr(xml, id);
if (_nic_target.type == type)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", label); });
});
};
gen_nic_button("off", Nic_target::OFF, "Off");
/*
* Allow interactive selection only if NIC-router configuration
* is not manually maintained.
*/
if (_nic_target.managed() || _nic_target.local())
gen_nic_button("local", Nic_target::LOCAL, "Local");
if (_nic_target.managed() || _nic_target.wired())
gen_nic_button("wired", Nic_target::WIRED, "Wired");
if (_nic_target.managed() || _nic_target.wifi())
gen_nic_button("wifi", Nic_target::WIFI, "Wifi");
});
if (_nic_target.type == Nic_target::WIFI || _nic_target.type == Nic_target::WIRED) {
gen_named_node(xml, "frame", "nic_info", [&] () {
xml.node("vbox", [&] () {
/*
* If connected via Wifi, show the information of the
* connected access point. If not connected, present
* the complete list of access points with the option
* to select one.
*/
if (_nic_target.type == Nic_target::WIFI) {
if (_wifi_connection.connected())
_gen_connected_ap(xml);
else
_gen_access_point_list(xml);
}
/* append display of uplink IP address */
if (_nic_state.ready())
gen_named_node(xml, "label", "ip", [&] () {
xml.attribute("text", _nic_state.ipv4); });
});
});
}
});
});
}
void Sculpt::Network_dialog::hover(Xml_node hover)
{
bool const changed =
_nic_item .match(hover, "vbox", "hbox", "button", "name") |
_ap_item .match(hover, "vbox", "frame", "vbox", "hbox", "name") |
_connect_item.match(hover, "vbox", "frame", "vbox", "button", "name");
_nic_info.match(hover, "vbox", "frame", "name");
if (changed)
_dialog_generator.generate_dialog();
}
void Sculpt::Network_dialog::click(Action &action)
{
if (_nic_item.hovered("off")) action.nic_target(Nic_target::OFF);
if (_nic_item.hovered("local")) action.nic_target(Nic_target::LOCAL);
if (_nic_item.hovered("wired")) action.nic_target(Nic_target::WIRED);
if (_nic_item.hovered("wifi")) action.nic_target(Nic_target::WIFI);
if (_wifi_connection.connected() && _ap_item.hovered(_wifi_connection.bssid)) {
action.wifi_disconnect();
_ap_item.reset();
} else {
_ap_item.toggle_selection_on_click();
/* immediately connect to unprotected access point when selected */
if (_ap_item.any_selected() && _selected_ap_unprotected())
action.wifi_connect(selected_ap());
}
if (_connect_item.hovered("connect"))
action.wifi_connect(selected_ap());
_dialog_generator.generate_dialog();
}

View File

@ -0,0 +1,113 @@
/*
* \brief Network management dialog
* \author Norman Feske
* \date 2018-05-07
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__NETWORK_DIALOG_H_
#define _VIEW__NETWORK_DIALOG_H_
#include <types.h>
#include <model/nic_target.h>
#include <model/nic_state.h>
#include <model/wifi_connection.h>
#include <model/wpa_passphrase.h>
#include <view/dialog.h>
#include <view/selectable_item.h>
namespace Sculpt { struct Network_dialog; }
struct Sculpt::Network_dialog : Dialog
{
Env &_env;
Dialog::Generator &_dialog_generator;
enum Wlan_config_policy { WLAN_CONFIG_MANAGED, WLAN_CONFIG_MANUAL };
Nic_target const &_nic_target;
Access_points const &_access_points;
Wifi_connection const &_wifi_connection;
Nic_state const &_nic_state;
Blind_wpa_passphrase const &_wpa_passphrase;
Wlan_config_policy const &_wlan_config_policy;
Hoverable_item _nic_item { };
Selectable_item _ap_item { };
Hoverable_item _nic_info { };
Hoverable_item _connect_item { }; /* confirm WPA passphrase */
bool ap_list_hovered() const { return _nic_target.type == Nic_target::WIFI
&& _nic_info.hovered("nic_info"); }
/*
* \return true if at least one access point fulfils the condition 'COND_FN'
*/
template <typename COND_FN>
bool _for_each_ap(COND_FN const &cond_fn) const
{
bool result = false;
_access_points.for_each([&] (Access_point const &ap) {
result |= cond_fn(ap); });
return result;
}
Access_point::Bssid selected_ap() const { return _ap_item._selected; }
/* limit view to highest-quality access points */
unsigned const _max_visible_aps = 20;
/* determine whether the selected AP is present in access-point list */
bool _selected_ap_visible() const;
bool _selected_ap_unprotected() const;
void _gen_access_point(Xml_generator &, Access_point const &) const;
void _gen_connected_ap(Xml_generator &) const;
void _gen_access_point_list(Xml_generator &) const;
void generate(Xml_generator &) const;
bool need_keyboard_focus_for_passphrase() const;
/**
* Dialog interface
*/
void hover(Xml_node hover) override;
struct Action : Interface
{
virtual void nic_target(Nic_target::Type) = 0;
virtual void wifi_connect(Access_point::Ssid) = 0;
virtual void wifi_disconnect() = 0;
};
void click(Action &action);
Network_dialog(Env &env,
Dialog::Generator &dialog_generator,
Nic_target const &nic_target,
Access_points const &access_points,
Wifi_connection const &wifi_connection,
Nic_state const &nic_state,
Blind_wpa_passphrase const &wpa_passphrase,
Wlan_config_policy const &wlan_config_policy)
:
_env(env), _dialog_generator(dialog_generator),
_nic_target(nic_target), _access_points(access_points),
_wifi_connection(wifi_connection), _nic_state(nic_state),
_wpa_passphrase(wpa_passphrase), _wlan_config_policy(wlan_config_policy)
{ }
};
#endif /* _VIEW__NETWORK_DIALOG_H_ */

View File

@ -0,0 +1,59 @@
/*
* \brief GUI element that has a hovered and selected state
* \author Norman Feske
* \date 2018-05-03
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__SELECTABLE_ITEM_H_
#define _VIEW__SELECTABLE_ITEM_H_
#include "hoverable_item.h"
namespace Sculpt { struct Selectable_item; }
struct Sculpt::Selectable_item : Hoverable_item
{
typedef Hoverable_item::Id Id;
Id _selected { };
/**
* Apply click - if item is hovered, the click toggles the selection
*/
void toggle_selection_on_click()
{
if (_hovered.valid())
_selected = (_hovered == _selected) ? Id() : _hovered;
}
void select(Id const &id) { _selected = id; }
void reset() { _selected = Id{}; }
/**
* Return true if item is currently selected
*/
bool selected(Id const &id) const { return id == _selected; }
bool any_selected() const { return _selected.valid(); }
/**
* Generate button attributes depending on the item state
*/
void gen_button_attr(Xml_generator &xml, Id const &id) const
{
Hoverable_item::gen_button_attr(xml, id);
if (selected(id)) xml.attribute("selected", "yes");
}
};
#endif /* _SELECTABLE_ITEM_H_ */

View File

@ -0,0 +1,533 @@
/*
* \brief Storage management dialog
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
/* local includes */
#include "storage_dialog.h"
void Sculpt::Storage_dialog::_gen_partition_operations(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
{
Storage_target const target { device.label, partition.number };
String<16> const version(device.label, ".", partition.number);
bool const whole_device = !partition.number.valid();
bool const device_in_use = (_used_target.device == device.label);
bool const target_in_use = (_used_target == target)
|| (whole_device && device_in_use)
|| partition.file_system_inspected;
bool const relabel_in_progress = device.relabel_in_progress();
bool const expand_in_progress = device.expand_in_progress();
bool const format_selected = _operation_item.selected("format");
bool const expand_selected = _operation_item.selected("expand");
if (partition.file_system.accessible() && !format_selected
&& !expand_selected && !expand_in_progress) {
if (!partition.check_in_progress && !partition.format_in_progress
&& partition.file_system.accessible() && !relabel_in_progress) {
xml.node("button", [&] () {
_inspect_item.gen_button_attr(xml, "browse");
xml.attribute("version", version);
if (partition.file_system_inspected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
});
}
if ((!_used_target.valid() || _used_target == target)
&& !partition.check_in_progress && !partition.format_in_progress
&& !relabel_in_progress) {
xml.node("button", [&] () {
xml.attribute("version", version);
_use_item.gen_button_attr(xml, "use");
if (_used_target == target)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Use"); });
});
}
if ((device.all_partitions_idle() || partition.relabel_in_progress())
&& partition.genode() && !device_in_use) {
xml.node("button", [&] () {
/* support hovering only if no relabeling is in progress */
if (partition.relabel_in_progress())
xml.attribute("name", "relabel");
else
_relabel_item.gen_button_attr(xml, "relabel");
xml.attribute("version", version);
if (partition.genode_default() || partition.relabel_in_progress())
xml.attribute("selected", "yes");
xml.node("label", [&] () {
xml.attribute("text", "Default"); });
});
if (partition.relabel_in_progress())
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
}
if (!target_in_use && !partition.format_in_progress && partition.checkable()
&& !relabel_in_progress) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "check");
xml.attribute("version", version);
if (partition.check_in_progress)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Check"); });
});
if (partition.check_in_progress)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
}
}
bool const whole_device_with_partition_in_use =
whole_device && !device.all_partitions_idle();
bool const format_button_visible = !target_in_use
&& !whole_device_with_partition_in_use
&& !partition.check_in_progress
&& !expand_in_progress
&& !relabel_in_progress
&& !_operation_item.selected("expand");
bool const expand_button_visible = !target_in_use
&& !whole_device
&& !partition.check_in_progress
&& !partition.format_in_progress
&& !relabel_in_progress
&& partition.expandable()
&& !_operation_item.selected("format");
bool const progress_msg_visible =
(_operation_item.selected("format") && partition.format_in_progress)
|| (_operation_item.selected("expand") && partition.expand_in_progress());
bool const confirm_visible =
(_operation_item.selected("format") && !partition.format_in_progress)
|| (_operation_item.selected("expand") && !partition.expand_in_progress());
if (format_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "format");
xml.attribute("version", version);
if (partition.format_in_progress)
xml.attribute("selected", "yes");
if (whole_device) {
xml.node("label", [&] () { xml.attribute("text", "Format device"); });
} else {
xml.node("label", [&] () { xml.attribute("text", "Format partition"); });
}
});
}
if (expand_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "expand");
xml.attribute("version", version);
if (partition.expand_in_progress())
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Expand"); });
});
}
if (progress_msg_visible)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
if (confirm_visible) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.attribute("version", version);
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
void Sculpt::Storage_dialog::_gen_partition(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
{
bool const selected = _partition_item.selected(partition.number);
gen_named_node(xml, "hbox", partition.number, [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "button", [&] () {
if (_partition_item.hovered(partition.number))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", partition.number); });
});
if (partition.label.length() > 1)
gen_named_node(xml, "label", "label", [&] () {
xml.attribute("text", String<80>(" (", partition.label, ") ")); });
Storage_target const target { device.label, partition.number };
if (_used_target == target)
gen_named_node(xml, "label", "used", [&] () { xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(partition.capacity, " ")); });
});
});
if (selected)
_gen_partition_operations(xml, device, partition);
}
void Sculpt::Storage_dialog::_gen_block_device(Xml_generator &xml,
Block_device const &dev) const
{
bool const selected = _device_item.selected(dev.label);
xml.node("button", [&] () {
xml.attribute("name", dev.label);
if (_device_item.hovered(dev.label))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", dev.label); });
gen_named_node(xml, "label", "model", [&] () {
xml.attribute("text", String<80>(" (", dev.model, ") ")); });
if (_used_target.device == dev.label)
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(dev.capacity)); }); });
});
});
if (selected) {
xml.node("frame", [&] () {
xml.attribute("name", dev.label);
xml.node("vbox", [&] () {
dev.partitions.for_each([&] (Partition const &partition) {
_gen_partition(xml, dev, partition); });
if (!_partition_item.any_selected())
_gen_partition_operations(xml, dev, *dev.whole_device_partition);
});
});
}
}
void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &xml,
Usb_storage_device const &dev) const
{
bool const selected = _device_item.selected(dev.label);
xml.node("button", [&] () {
xml.attribute("name", dev.label);
if (_device_item.hovered(dev.label))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", dev.label); });
if (dev.driver_info.constructed()) {
gen_named_node(xml, "label", "vendor", [&] () {
String<16> const vendor { dev.driver_info->vendor };
xml.attribute("text", String<64>(" (", vendor, ") ")); });
}
if (_used_target.device == dev.label)
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", " *"); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(dev.capacity)); }); });
});
});
if (selected)
xml.node("frame", [&] () {
xml.attribute("name", dev.label);
xml.node("vbox", [&] () {
dev.partitions.for_each([&] (Partition const &partition) {
_gen_partition(xml, dev, partition); });
if (!_partition_item.any_selected())
_gen_partition_operations(xml, dev, *dev.whole_device_partition);
});
});
}
void Sculpt::Storage_dialog::_gen_ram_fs(Xml_generator &xml) const
{
bool const selected = _device_item.selected("ram_fs");
gen_named_node(xml, "button", "ram_fs", [&] () {
if (_device_item.hovered("ram_fs"))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", "ram (in-memory file system) "); });
if (_used_target.device == "ram_fs")
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
Capacity const capacity { _ram_fs_state.ram_quota.value };
xml.attribute("text", String<64>(capacity)); }); });
});
});
if (selected) {
xml.node("frame", [&] () {
xml.attribute("name", "ram_fs_operations");
xml.node("vbox", [&] () {
xml.node("button", [&] () {
_inspect_item.gen_button_attr(xml, "browse");
if (_ram_fs_state.inspected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
});
if (!_used_target.valid() || _used_target.ram_fs()) {
xml.node("button", [&] () {
_use_item.gen_button_attr(xml, "use");
if (_used_target.ram_fs())
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Use"); });
});
}
if (!_used_target.ram_fs() && !_ram_fs_state.inspected) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "reset");
xml.node("label", [&] () { xml.attribute("text", "Reset"); });
});
if (_operation_item.selected("reset")) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
});
});
}
}
void Sculpt::Storage_dialog::generate(Xml_generator &xml) const
{
gen_named_node(xml, "frame", "storage", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "label", "title", [&] () {
xml.attribute("text", "Storage");
xml.attribute("font", "title/regular");
});
_storage_devices.block_devices.for_each([&] (Block_device const &dev) {
_gen_block_device(xml, dev); });
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
_gen_usb_storage_device(xml, dev); });
_gen_ram_fs(xml);
});
});
}
void Sculpt::Storage_dialog::hover(Xml_node hover)
{
bool const changed =
_device_item .match(hover, "vbox", "button", "name") |
_partition_item.match(hover, "vbox", "frame", "vbox", "hbox", "name") |
_use_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_relabel_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_inspect_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_operation_item.match(hover, "vbox", "frame", "vbox", "button", "name") |
_confirm_item .match(hover, "vbox", "frame", "vbox", "button", "name");
if (changed)
_dialog_generator.generate_dialog();
}
void Sculpt::Storage_dialog::click(Action &action)
{
Selectable_item::Id const old_selected_device = _device_item._selected;
Selectable_item::Id const old_selected_partition = _partition_item._selected;
_device_item.toggle_selection_on_click();
_partition_item.toggle_selection_on_click();
if (!_device_item.selected(old_selected_device))
_partition_item.reset();
if (!_device_item.selected(old_selected_device)
|| !_partition_item.selected(old_selected_partition))
reset_operation();
Storage_target const target = _selected_storage_target();
if (_operation_item.hovered("format")) {
if (_operation_item.selected("format"))
action.cancel_format(_selected_storage_target());
else
_operation_item.toggle_selection_on_click();
}
if (_operation_item.hovered("expand")) {
if (_operation_item.selected("expand"))
action.cancel_expand(_selected_storage_target());
else
_operation_item.toggle_selection_on_click();
}
/* toggle confirmation button when clicking on ram_fs reset */
if (_operation_item.hovered("reset"))
_operation_item.toggle_selection_on_click();
if (_operation_item.hovered("check"))
action.check(target);
/* toggle file browser */
if (_inspect_item.hovered("browse"))
action.toggle_file_browser(target);
if (_use_item.hovered("use")) {
/* release currently used device */
if (target.valid() && target == _used_target)
action.use(Storage_target{});
/* select new used device if none is defined */
else if (!_used_target.valid())
action.use(target);
}
if (_relabel_item.hovered("relabel"))
action.toggle_default_storage_target(target);
if (_confirm_item.hovered("confirm")) {
_confirm_item.propose_activation_on_click();
}
_dialog_generator.generate_dialog();
}
void Sculpt::Storage_dialog::clack(Action &action)
{
if (_confirm_item.hovered("confirm")) {
_confirm_item.confirm_activation_on_clack();
if (_confirm_item.activated("confirm")) {
Storage_target const target = _selected_storage_target();
if (_operation_item.selected("format"))
action.format(target);
if (_operation_item.selected("expand"))
action.expand(target);
if (target.ram_fs() && _operation_item.selected("reset"))
action.reset_ram_fs();
}
} else {
_confirm_item.reset();
}
_dialog_generator.generate_dialog();
}

View File

@ -0,0 +1,114 @@
/*
* \brief Storage management dialog
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__STORAGE_DIALOG_H_
#define _VIEW__STORAGE_DIALOG_H_
#include <types.h>
#include <model/storage_devices.h>
#include <model/storage_target.h>
#include <model/ram_fs_state.h>
#include <view/selectable_item.h>
#include <view/activatable_item.h>
#include <view/dialog.h>
namespace Sculpt { struct Storage_dialog; }
struct Sculpt::Storage_dialog : Dialog
{
Env &_env;
Dialog::Generator &_dialog_generator;
Storage_devices const &_storage_devices;
Ram_fs_state const &_ram_fs_state;
Selectable_item _device_item { };
Selectable_item _partition_item { };
Hoverable_item _use_item { };
Hoverable_item _relabel_item { };
Hoverable_item _inspect_item { };
Selectable_item _operation_item { };
Activatable_item _confirm_item { };
void generate(Xml_generator &) const;
void _gen_block_device(Xml_generator &, Block_device const &) const;
void _gen_partition(Xml_generator &, Storage_device const &, Partition const &) const;
void _gen_partition_operations(Xml_generator &, Storage_device const &, Partition const &) const;
void _gen_usb_storage_device(Xml_generator &, Usb_storage_device const &) const;
void _gen_ram_fs(Xml_generator &) const;
void hover(Xml_node hover);
Storage_target const &_used_target;
struct Action : Interface
{
virtual void format(Storage_target const &) = 0;
virtual void cancel_format(Storage_target const &) = 0;
virtual void expand(Storage_target const &) = 0;
virtual void cancel_expand(Storage_target const &) = 0;
virtual void check(Storage_target const &) = 0;
virtual void toggle_file_browser(Storage_target const &) = 0;
virtual void toggle_default_storage_target(Storage_target const &) = 0;
virtual void use(Storage_target const &) = 0;
virtual void reset_ram_fs() = 0;
};
Storage_target _selected_storage_target() const
{
Partition::Number partition = (_partition_item._selected == "")
? Partition::Number { }
: Partition::Number(_partition_item._selected);
return Storage_target { _device_item._selected, partition };
}
void reset_operation()
{
_operation_item.reset();
_confirm_item.reset();
_dialog_generator.generate_dialog();
}
void click(Action &action);
void clack(Action &action);
Storage_dialog(Env &env, Dialog::Generator &dialog_generator,
Storage_devices const &storage_devices,
Ram_fs_state const &ram_fs_state, Storage_target const &used)
:
_env(env), _dialog_generator(dialog_generator),
_storage_devices(storage_devices), _ram_fs_state(ram_fs_state),
_used_target(used)
{ }
};
#endif /* _STORAGE_DIALOG_H_ */

View File

@ -0,0 +1,136 @@
/*
* \brief Utilities for generating XML
* \author Norman Feske
* \date 2018-01-11
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _XML_H_
#define _XML_H_
/* Genode includes */
#include <util/xml_generator.h>
#include <base/log.h>
/* local includes */
#include "types.h"
namespace Sculpt {
template <typename FN>
static inline void gen_named_node(Xml_generator &xml,
char const *type, char const *name, FN const &fn)
{
xml.node(type, [&] () {
xml.attribute("name", name);
fn();
});
}
static inline void gen_named_node(Xml_generator &xml, char const *type, char const *name)
{
xml.node(type, [&] () { xml.attribute("name", name); });
}
template <size_t N, typename FN>
static inline void gen_named_node(Xml_generator &xml,
char const *type, String<N> const &name, FN const &fn)
{
gen_named_node(xml, type, name.string(), fn);
}
template <size_t N>
static inline void gen_named_node(Xml_generator &xml, char const *type, String<N> const &name)
{
gen_named_node(xml, type, name.string());
}
template <typename SESSION, typename FN>
static inline void gen_service_node(Xml_generator &xml, FN const &fn)
{
gen_named_node(xml, "service", SESSION::service_name(), fn);
}
template <typename SESSION>
static inline void gen_parent_service(Xml_generator &xml)
{
gen_named_node(xml, "service", SESSION::service_name());
};
template <typename SESSION>
static inline void gen_parent_route(Xml_generator &xml)
{
gen_named_node(xml, "service", SESSION::service_name(), [&] () {
xml.node("parent", [&] () { }); });
}
static inline void gen_parent_rom_route(Xml_generator &xml,
Rom_name const &name,
Label const &label)
{
gen_service_node<Rom_session>(xml, [&] () {
xml.attribute("label_last", name);
xml.node("parent", [&] () {
xml.attribute("label", label); });
});
}
static inline void gen_parent_rom_route(Xml_generator &xml,
Rom_name const &name)
{
gen_parent_rom_route(xml, name, name);
}
template <typename SESSION>
static inline void gen_provides(Xml_generator &xml)
{
xml.node("provides", [&] () {
gen_named_node(xml, "service", SESSION::service_name()); });
}
static inline void gen_common_start_content(Xml_generator &xml,
Rom_name const &name,
Cap_quota const caps,
Ram_quota const ram)
{
xml.attribute("name", name);
xml.attribute("caps", caps.value);
gen_named_node(xml, "resource", "RAM", [&] () {
xml.attribute("quantum", String<64>(Number_of_bytes(ram.value))); });
}
template <typename T>
static T _attribute_value(Xml_node node, char const *attr_name)
{
return node.attribute_value(attr_name, T{});
}
template <typename T, typename... ARGS>
static T _attribute_value(Xml_node node, char const *sub_node_type, ARGS... args)
{
if (!node.has_sub_node(sub_node_type))
return T{};
return _attribute_value<T>(node.sub_node(sub_node_type), args...);
}
/**
* Query attribute value from XML sub nodd
*
* The list of arguments except for the last one refer to XML path into the
* XML structure. The last argument denotes the queried attribute name.
*/
template <typename T, typename... ARGS>
static T query_attribute(Xml_node node, ARGS &&... args)
{
return _attribute_value<T>(node, args...);
}
}
#endif /* _XML_H_ */