Depot-download subsystem

This commit is contained in:
Norman Feske 2017-12-08 16:44:44 +01:00
parent 66a93d9199
commit fefeb29d5f
20 changed files with 1278 additions and 0 deletions

View File

@ -0,0 +1,2 @@
Subsystem for downloading depot content

View File

@ -0,0 +1,18 @@
_/src/depot_download_manager
_/src/depot_query
_/src/verify
_/src/extract
_/src/report_rom
_/src/fs_rom
_/src/fetchurl
_/src/libc
_/src/libssh
_/src/libssl
_/src/libcrypto
_/src/zlib
_/src/curl
_/src/init
_/src/chroot
_/src/libarchive
_/src/liblzma
_/raw/depot_download

View File

@ -0,0 +1 @@
2018-01-18 eef2e5112de6ba055ad6e57dffdbaeae2ec4746e

View File

@ -0,0 +1,4 @@
content: depot_download.config
depot_download.config:
cp $(REP_DIR)/recipes/raw/depot_download/$@ $@

View File

@ -0,0 +1,64 @@
<config>
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="Report"/>
<service name="File_system"/>
<service name="Nic"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<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="dynamic -> config"
report="manager -> init_config"/>
<policy label="manager -> dependencies"
report="dynamic -> depot_query -> dependencies"/>
<policy label="manager -> user"
report="dynamic -> depot_query -> user"/>
<policy label="manager -> init_state"
report="dynamic -> state"/>
<policy label="manager -> verified"
report="dynamic -> verify -> result"/>
</config>
</start>
<start name="manager">
<binary name="depot_download_manager"/>
<resource name="RAM" quantum="1M"/>
<config/>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<service name="ROM" label="dependencies"> <child name="report_rom"/> </service>
<service name="ROM" label="user"> <child name="report_rom"/> </service>
<service name="ROM" label="init_state"> <child name="report_rom"/> </service>
<service name="ROM" label="verified"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="dynamic" caps="1000">
<resource name="RAM" quantum="24M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config"> <child name="report_rom"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="File_system" label="depot"> <parent label="depot"/> </service>
<service name="File_system" label="depot_rw"> <parent label="depot_rw"/> </service>
<service name="File_system" label="public"> <parent label="public"/> </service>
<service name="File_system" label="public_rw"> <parent label="public_rw"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>

View File

@ -0,0 +1 @@
2018-01-18 4755c0e7f19bb5c44bdbd5c1f276127c9a2a1487

View File

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

View File

@ -0,0 +1 @@
2018-01-18 7e032cc2fd00d9b4f885c718917cbc4bf9c46119

View File

@ -0,0 +1,6 @@
base
os
report_session
file_system_session
nic_session
timer_session

View File

@ -0,0 +1,129 @@
create_boot_directory
import_from_depot genodelabs/src/[base_src] \
genodelabs/src/report_rom \
genodelabs/src/fs_rom \
genodelabs/src/vfs \
genodelabs/src/fetchurl \
genodelabs/src/libc \
genodelabs/src/libssh \
genodelabs/src/libssl \
genodelabs/src/libcrypto \
genodelabs/src/zlib \
genodelabs/src/curl \
genodelabs/src/init \
genodelabs/src/chroot \
genodelabs/src/acpi_drv \
genodelabs/src/ipxe_nic_drv \
genodelabs/src/platform_drv \
genodelabs/src/extract \
genodelabs/src/libarchive \
genodelabs/src/liblzma \
genodelabs/src/verify
source ${genode_dir}/repos/base/run/platform_drv.inc
set 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>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>}
append_platform_drv_config
proc depot_user { } { return nfeske }
proc depot_user_download { } {
return [exec cat [genode_dir]/depot/[depot_user]/download] }
proc depot_user_pubkey { } {
return [exec cat [genode_dir]/depot/[depot_user]/pubkey] }
append config {
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="vfs">
<resource name="RAM" quantum="20M"/>
<provides> <service name="File_system"/> </provides>
<config>
<vfs>
<dir name="depot">
<dir name="} [depot_user] {">
<ram/>
<inline name="download">} [depot_user_download] {</inline>
<inline name="pubkey">} [depot_user_pubkey] {</inline>
</dir>
</dir>
<dir name="public"> <ram/> </dir>
</vfs>
<policy label="depot_download -> depot_rw" root="/depot" writeable="yes"/>
<policy label="depot_download -> depot" root="/depot"/>
<policy label="depot_download -> public_rw" root="/public" writeable="yes"/>
<policy label="depot_download -> public" root="/public"/>
</config>
</start>
<start name="report_rom">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="yes">
</config>
</start>
<start name="nic_drv">
<resource name="RAM" quantum="6M"/>
<provides> <service name="Nic"/> </provides>
</start>
<start name="depot_download" caps="2000">
<binary name="init"/>
<resource name="RAM" quantum="32M"/>
<route>
<service name="ROM" label="config">
<parent label="depot_download.config"/> </service>
<service name="File_system"> <child name="vfs"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>}
set fd [open [run_dir]/genode/installation w]
puts $fd "
<installation arch=\"x86_64\">
<archive path=\"[depot_user]/pkg/wm/2017-12-13\"/>
</installation>"
close $fd
install_config $config
file copy -force [genode_dir]/repos/gems/recipes/raw/depot_download/depot_download.config \
[run_dir]/genode/depot_download.config
build { app/depot_download_manager app/depot_query }
append boot_modules { depot_download_manager depot_query }
build_boot_image $boot_modules
append qemu_args " -nographic -net nic,model=e1000 -net user "
run_genode_until forever

View File

@ -0,0 +1,44 @@
/*
* \brief XML configuration for the chroot component
* \author Norman Feske
* \date 2017-12-08
*/
/*
* 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.
*/
#include "xml.h"
void Depot_download_manager::gen_chroot_start_content(Xml_generator &xml,
Archive::User const &user)
{
gen_common_start_content(xml, Path("/depot/", user),
Cap_quota{100}, Ram_quota{1*1024*1024});
xml.node("binary", [&] () { xml.attribute("name", "chroot"); });
xml.node("config", [&] () {
xml.node("default-policy", [&] () {
xml.attribute("path", Path("/", user)); }); });
xml.node("provides", [&] () {
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name()); }); });
xml.node("route", [&] () {
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name());
xml.node("parent", [&] () {
xml.attribute("label", "depot_rw"); });
});
gen_parent_unscoped_rom_route(xml, "chroot");
gen_parent_unscoped_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,61 @@
/*
* \brief XML configuration for the depot-query tool
* \author Norman Feske
* \date 2017-12-08
*/
/*
* 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.
*/
#include "xml.h"
void Depot_download_manager::gen_depot_query_start_content(Xml_generator &xml,
Xml_node installation,
Archive::User const &next_user,
Depot_query_version version)
{
gen_common_start_content(xml, "depot_query",
Cap_quota{100}, Ram_quota{2*1024*1024});
xml.node("config", [&] () {
xml.attribute("version", version.value);
typedef String<32> Arch;
xml.attribute("arch", installation.attribute_value("arch", Arch()));
xml.node("vfs", [&] () {
xml.node("dir", [&] () {
xml.attribute("name", "depot");
xml.node("fs", [&] () {
xml.attribute("label", "depot"); });
});
});
installation.for_each_sub_node("archive", [&] (Xml_node archive) {
xml.node("dependencies", [&] () {
xml.attribute("path", archive.attribute_value("path", Archive::Path()));
xml.attribute("source", archive.attribute_value("source", true));
xml.attribute("binary", archive.attribute_value("binary", true));
});
});
if (next_user.valid())
xml.node("user", [&] () { xml.attribute("name", next_user); });
});
xml.node("route", [&] () {
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name());
xml.node("parent", [&] () {
xml.attribute("label", "depot"); });
});
gen_parent_unscoped_rom_route(xml, "depot_query");
gen_parent_unscoped_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<Report::Session>(xml);
});
}

View File

@ -0,0 +1,95 @@
/*
* \brief XML configuration for the extract tool
* \author Norman Feske
* \date 2017-12-08
*/
/*
* 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.
*/
#include "xml.h"
void Depot_download_manager::gen_extract_start_content(Xml_generator &xml,
Import const &import,
Path const &user_path,
Archive::User const &user)
{
gen_common_start_content(xml, "extract",
Cap_quota{200}, Ram_quota{12*1024*1024});
xml.node("config", [&] () {
xml.attribute("verbose", "yes");
xml.node("libc", [&] () {
xml.attribute("stdout", "/dev/log");
xml.attribute("stderr", "/dev/log");
xml.attribute("rtc", "/dev/null");
xml.attribute("cwd", user_path);
});
xml.node("vfs", [&] () {
xml.node("dir", [&] () {
xml.attribute("name", "public");
xml.node("fs", [&] () { xml.attribute("label", "public"); });
});
xml.node("dir", [&] () {
xml.attribute("name", "depot");
xml.node("dir", [&] () {
xml.attribute("name", user);
xml.node("fs", [&] () {
xml.attribute("label", user_path); });
});
});
xml.node("dir", [&] () {
xml.attribute("name", "dev");
xml.node("log", [&] () { });
xml.node("null", [&] () { });
});
});
import.for_each_verified_archive([&] (Archive::Path const &path) {
typedef String<160> Path;
typedef String<16> Ext;
Ext const ext (".tar.xz");
Path const tar_path ("/public/", path, ext);
Path const dst_path ("/depot/", without_last_path_element(path));
xml.node("extract", [&] () {
xml.attribute("archive", tar_path);
xml.attribute("to", dst_path);
});
});
});
xml.node("route", [&] () {
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name());
xml.attribute("label", "public");
xml.node("parent", [&] () {
xml.attribute("label", "public"); });
});
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name());
xml.attribute("label", user_path);
xml.node("child", [&] () {
xml.attribute("name", user_path); });
});
gen_parent_unscoped_rom_route(xml, "extract");
gen_parent_unscoped_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "posix.lib.so");
gen_parent_rom_route(xml, "libarchive.lib.so");
gen_parent_rom_route(xml, "zlib.lib.so");
gen_parent_rom_route(xml, "liblzma.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,94 @@
/*
* \brief XML configuration for fetchurl
* \author Norman Feske
* \date 2017-12-08
*/
/*
* 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.
*/
#include "xml.h"
void Depot_download_manager::gen_fetchurl_start_content(Xml_generator &xml,
Import const &import,
Url const &current_user_url,
Fetchurl_version version)
{
gen_common_start_content(xml, "fetchurl",
Cap_quota{500}, Ram_quota{8*1024*1024});
xml.attribute("version", version.value);
xml.node("config", [&] () {
xml.node("libc", [&] () {
xml.attribute("stdout", "/dev/log");
xml.attribute("stderr", "/dev/log");
xml.attribute("rtc", "/dev/rtc");
});
xml.node("vfs", [&] () {
xml.node("dir", [&] () {
xml.attribute("name", "download");
xml.node("fs", [&] () {
xml.attribute("label", "download"); });
});
xml.node("dir", [&] () {
xml.attribute("name", "dev");
xml.node("log", [&] () { });
xml.node("null", [&] () { });
xml.node("inline", [&] () {
xml.attribute("name", "rtc");
String<64> date("2000-01-01 00:00");
xml.append(date.string());
});
});
});
import.for_each_download([&] (Archive::Path const &path) {
typedef String<160> Remote;
typedef String<160> Local;
typedef String<16> Ext;
Ext const ext (".tar.xz");
Remote const remote (current_user_url, "/", path, ext);
Local const local ("/download/", path, ext);
xml.node("fetch", [&] () {
xml.attribute("url", remote);
xml.attribute("path", local);
});
xml.node("fetch", [&] () {
xml.attribute("url", Remote(remote, ".sig"));
xml.attribute("path", Local (local, ".sig"));
});
});
});
xml.node("route", [&] () {
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name());
xml.attribute("label", "download");
xml.node("parent", [&] () {
xml.attribute("label", "public_rw"); });
});
gen_parent_unscoped_rom_route(xml, "fetchurl");
gen_parent_unscoped_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "lwip.lib.so");
gen_parent_rom_route(xml, "curl.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, "pthread.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_parent_route<Nic::Session> (xml);
});
}

View File

@ -0,0 +1,87 @@
/*
* \brief XML configuration for the verify tool
* \author Norman Feske
* \date 2017-12-08
*/
/*
* 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.
*/
#include "xml.h"
void Depot_download_manager::gen_verify_start_content(Xml_generator &xml,
Import const &import,
Path const &user_path)
{
gen_common_start_content(xml, "verify",
Cap_quota{200}, Ram_quota{12*1024*1024});
xml.node("config", [&] () {
xml.attribute("verbose", "yes");
xml.node("libc", [&] () {
xml.attribute("stdout", "/dev/null");
xml.attribute("stderr", "/dev/null");
xml.attribute("rtc", "/dev/null");
});
xml.node("vfs", [&] () {
xml.node("dir", [&] () {
xml.attribute("name", "public");
xml.node("fs", [&] () { xml.attribute("label", "public"); });
});
xml.node("dir", [&] () {
xml.attribute("name", "depot");
xml.node("fs", [&] () { xml.attribute("label", "depot"); });
});
xml.node("dir", [&] () {
xml.attribute("name", "dev");
xml.node("log", [&] () { });
xml.node("null", [&] () { });
});
});
import.for_each_unverified_archive([&] (Archive::Path const &path) {
typedef String<160> Path;
typedef String<16> Ext;
Ext const ext (".tar.xz");
Path const tar_path ("/public/", path, ext);
Path const pubkey_path (user_path, "/pubkey");
xml.node("verify", [&] () {
xml.attribute("path", tar_path);
xml.attribute("pubkey", pubkey_path);
});
});
});
xml.node("route", [&] () {
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name());
xml.attribute("label", "public");
xml.node("parent", [&] () {
xml.attribute("label", "public"); });
});
xml.node("service", [&] () {
xml.attribute("name", File_system::Session::service_name());
xml.attribute("label", "depot");
xml.node("parent", [&] () {
xml.attribute("label", "depot"); });
});
gen_parent_unscoped_rom_route(xml, "verify");
gen_parent_unscoped_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "pthread.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Report::Session>(xml);
});
}

View File

@ -0,0 +1,176 @@
/*
* \brief Data structure for tracking the state of imported archives
* \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 _IMPORT_H_
#define _IMPORT_H_
/* Genode includes */
#include <util/xml_node.h>
#include <base/registry.h>
#include <base/allocator.h>
#include "types.h"
namespace Depot_download_manager {
using namespace Depot;
struct Import;
}
class Depot_download_manager::Import
{
private:
struct Item
{
Registry<Item>::Element _element;
Archive::Path const path;
enum State { DOWNLOAD_IN_PROGRESS,
DOWNLOAD_COMPLETE,
VERIFIED,
VERIFICATION_FAILED,
UNPACKED };
State state = DOWNLOAD_IN_PROGRESS;
Item(Registry<Item> &registry, Archive::Path const &path)
:
_element(registry, *this), path(path)
{ }
};
Allocator &_alloc;
Registry<Item> _items { };
template <typename FN>
void _for_each_item(Item::State state, FN const &fn) const
{
_items.for_each([&] (Item const &item) {
if (item.state == state)
fn(item.path); });
}
/**
* Return true if at least one item is in the given 'state'
*/
bool _item_state_exists(Item::State state) const
{
bool result = false;
_items.for_each([&] (Item const &item) {
if (!result && item.state == state)
result = true; });
return result;
}
public:
/**
* Constructor
*
* \param user depot origin to use for the import
* \param node XML node containing any number of '<missing>' sub nodes
*
* The import constructor considers only those '<missing>' sub nodes as
* items that match the 'user'. The remaining sub nodes are imported in
* a future iteration.
*/
Import(Allocator &alloc, Archive::User const &user, Xml_node node)
:
_alloc(alloc)
{
node.for_each_sub_node("missing", [&] (Xml_node item) {
Archive::Path const path = item.attribute_value("path", Archive::Path());
if (Archive::user(path) == user)
new (alloc) Item(_items, path);
});
}
~Import()
{
_items.for_each([&] (Item &item) { destroy(_alloc, &item); });
}
bool downloads_in_progress() const
{
return _item_state_exists(Item::DOWNLOAD_IN_PROGRESS);
}
bool unverified_archives_available() const
{
return _item_state_exists(Item::DOWNLOAD_COMPLETE);
}
bool verified_archives_available() const
{
return _item_state_exists(Item::VERIFIED);
}
template <typename FN>
void for_each_download(FN const &fn) const
{
_for_each_item(Item::DOWNLOAD_IN_PROGRESS, fn);
}
template <typename FN>
void for_each_unverified_archive(FN const &fn) const
{
_for_each_item(Item::DOWNLOAD_COMPLETE, fn);
}
template <typename FN>
void for_each_verified_archive(FN const &fn) const
{
_for_each_item(Item::VERIFIED, fn);
}
template <typename FN>
void for_each_ready_archive(FN const &fn) const
{
_for_each_item(Item::UNPACKED, fn);
}
void all_downloads_completed()
{
_items.for_each([&] (Item &item) {
if (item.state == Item::DOWNLOAD_IN_PROGRESS)
item.state = Item::DOWNLOAD_COMPLETE; });
}
void archive_verified(Archive::Path const &archive)
{
_items.for_each([&] (Item &item) {
if (item.state == Item::DOWNLOAD_COMPLETE)
if (item.path == archive)
item.state = Item::VERIFIED; });
}
void archive_verification_failed(Archive::Path const &archive)
{
_items.for_each([&] (Item &item) {
if (item.state == Item::DOWNLOAD_COMPLETE)
if (item.path == archive)
item.state = Item::VERIFICATION_FAILED; });
}
void all_verified_archives_extracted()
{
_items.for_each([&] (Item &item) {
if (item.state == Item::VERIFIED)
item.state = Item::UNPACKED; });
}
};
#endif /* _IMPORT_H_ */

View File

@ -0,0 +1,329 @@
/*
* \brief Tool for managing the download of depot content
* \author Norman Feske
* \date 2017-12-08
*/
/*
* 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.
*/
/* Genode includes */
#include <base/component.h>
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
/* local includes */
#include "xml.h"
namespace Depot_download_manager {
using namespace Depot;
struct Child_exit_state;
struct Main;
}
struct Depot_download_manager::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);
}
}
});
}
};
struct Depot_download_manager::Main
{
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
Attached_rom_dataspace _installation { _env, "installation" };
Attached_rom_dataspace _dependencies { _env, "dependencies" };
Attached_rom_dataspace _init_state { _env, "init_state" };
/**
* User identity, from which current downloads are fetched
*/
Attached_rom_dataspace _current_user { _env, "user" };
/**
* Result of signature verification, reported by the 'verify' component
*/
Attached_rom_dataspace _verified { _env, "verified" };
class Invalid_download_url : Exception { };
/**
* \throw Invalid_download_url
*/
Url _current_user_url() const;
Archive::User _current_user_name() const
{
return _current_user.xml().attribute_value("name", Archive::User());
}
Path _current_user_path() const
{
return Path("/depot/", _current_user_name());
}
Expanding_reporter _init_config { _env, "config", "init_config" };
/**
* Version counters, used to enforce the restart or reconfiguration of
* components.
*/
Depot_query_version _depot_query_count { 1 };
Fetchurl_version _fetchurl_count { 1 };
Archive::User _next_user { };
Constructible<Import> _import { };
void _generate_init_config(Xml_generator &);
void _generate_init_config()
{
_init_config.generate([&] (Xml_generator &xml) {
_generate_init_config(xml); });
}
Signal_handler<Main> _query_result_handler {
_env.ep(), *this, &Main::_handle_query_result };
void _handle_query_result();
Signal_handler<Main> _init_state_handler {
_env.ep(), *this, &Main::_handle_init_state };
void _handle_init_state();
Main(Env &env) : _env(env)
{
_dependencies.sigh(_query_result_handler);
_current_user.sigh(_query_result_handler);
_init_state .sigh(_init_state_handler);
_verified .sigh(_init_state_handler);
_generate_init_config();
}
};
Depot_download_manager::Url
Depot_download_manager::Main::_current_user_url() const
{
if (!_current_user.xml().has_sub_node("url"))
throw Invalid_download_url();
Url const url = _current_user.xml().sub_node("url").decoded_content<Url>();
/*
* Ensure that the URL does not contain any '"' character because it will
* be taken as an XML attribute value.
*
* XXX This should better be addressed by sanitizing the argument of
* 'Xml_generator::attribute' (issue #1757).
*/
for (char const *s = url.string(); *s; s++)
if (*s == '"')
throw Invalid_download_url();
return url;
}
void Depot_download_manager::Main::_generate_init_config(Xml_generator &xml)
{
xml.node("report", [&] () {
xml.attribute("delay_ms", 500); });
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<Nic::Session>(xml);
gen_parent_service<File_system::Session>(xml);
});
xml.node("start", [&] () {
gen_depot_query_start_content(xml, _installation.xml(),
_next_user, _depot_query_count); });
if (_import.constructed() && _import->downloads_in_progress()) {
try {
xml.node("start", [&] () {
gen_fetchurl_start_content(xml, *_import, _current_user_url(),
_fetchurl_count); });
}
catch (Invalid_download_url) {
error("invalid download URL for depot user:", _current_user.xml());
}
}
if (_import.constructed() && _import->unverified_archives_available())
xml.node("start", [&] () {
gen_verify_start_content(xml, *_import, _current_user_path()); });
if (_import.constructed() && _import->verified_archives_available()) {
xml.node("start", [&] () {
gen_chroot_start_content(xml, _current_user_name()); });
xml.node("start", [&] () {
gen_extract_start_content(xml, *_import, _current_user_path(),
_current_user_name()); });
}
}
void Depot_download_manager::Main::_handle_query_result()
{
/* finish current import before starting a new one */
if (_import.constructed())
return;
_dependencies.update();
_current_user.update();
Xml_node const dependencies = _dependencies.xml();
if (dependencies.num_sub_nodes() == 0)
return;
if (!dependencies.has_sub_node("missing")) {
log("installation complete.");
return;
}
Archive::Path const path =
dependencies.sub_node("missing").attribute_value("path", Archive::Path());
if (Archive::user(path) != _current_user_name()) {
_next_user = Archive::user(path);
/* query user info from 'depot_query' */
_generate_init_config();
return;
}
/* start new import */
_import.construct(_heap, _current_user_name(), _dependencies.xml());
/* spawn fetchurl */
_generate_init_config();
}
void Depot_download_manager::Main::_handle_init_state()
{
_init_state.update();
_verified.update();
bool reconfigure_init = false;
bool import_finished = false;
if (!_import.constructed())
return;
Import &import = *_import;
if (import.downloads_in_progress()) {
Child_exit_state const fetchurl_state(_init_state.xml(), "fetchurl");
if (fetchurl_state.exited && fetchurl_state.code != 0) {
error("fetchurl failed with exit code ", fetchurl_state.code);
/* retry by incrementing the version attribute of the start node */
_fetchurl_count.value++;
reconfigure_init = true;
}
if (fetchurl_state.exited && fetchurl_state.code == 0) {
import.all_downloads_completed();
/* kill fetchurl, start untar */
reconfigure_init = true;
}
}
if (import.unverified_archives_available()) {
_verified.xml().for_each_sub_node([&] (Xml_node node) {
/* path in the VFS name space of the 'verify' component */
Path const abs_path = node.attribute_value("path", Archive::Path());
/* determine matching archive path */
Path path;
import.for_each_unverified_archive([&] (Archive::Path const &archive) {
if (abs_path == Path("/public/", archive, ".tar.xz"))
path = archive; });
if (path.valid()) {
if (node.type() == "good") {
import.archive_verified(path);
} else {
error("signature check failed for '", path, "' "
"(", node.attribute_value("reason", String<64>()), ")");
import.archive_verification_failed(path);
}
}
reconfigure_init = true;
});
}
if (import.verified_archives_available()) {
Child_exit_state const extract_state(_init_state.xml(), "extract");
if (extract_state.exited && extract_state.code != 0)
error("extract failed with exit code ", extract_state.code);
if (extract_state.exited && extract_state.code == 0) {
import.all_verified_archives_extracted();
import_finished = true;
/* kill extract, re-issue new depot query to start next iteration */
_depot_query_count.value++;
reconfigure_init = true;
}
}
if (import_finished)
_import.destruct();
if (reconfigure_init)
_generate_init_config();
}
void Component::construct(Genode::Env &env)
{
static Depot_download_manager::Main main(env);
}

View File

@ -0,0 +1,4 @@
TARGET := depot_download_manager
SRC_CC := main.cc gen_depot_query.cc gen_fetchurl.cc gen_verify.cc \
gen_chroot.cc gen_extract.cc
LIBS += base

View File

@ -0,0 +1,52 @@
/*
* \brief Types used the depot download manager
* \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 _TYPES_H_
#define _TYPES_H_
#include <util/string.h>
#include <base/exception.h>
#include <depot/archive.h>
namespace Depot_download_manager {
using namespace Depot;
typedef String<32> Rom_name;
typedef String<160> Url;
typedef String<160> Path;
struct Depot_query_version { unsigned value; };
struct Fetchurl_version { unsigned value; };
}
namespace Genode {
/**
* Strip off the last element from 'path'
*/
template <size_t N>
static String<N> without_last_path_element(String<N> const &path)
{
unsigned last_slash = 0;
char const * const s = path.string();
for (unsigned i = 0; s[i]; i++)
if (s[i] == '/')
last_slash = i;
return String<N>(Cstring(s, last_slash));
}
}
#endif /* _TYPES_H_ */

View File

@ -0,0 +1,100 @@
/*
* \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 _GENERATE_XML_H_
#define _GENERATE_XML_H_
/* Genode includes */
#include <util/xml_generator.h>
#include <rom_session/rom_session.h>
#include <cpu_session/cpu_session.h>
#include <log_session/log_session.h>
#include <pd_session/pd_session.h>
#include <timer_session/timer_session.h>
#include <nic_session/nic_session.h>
#include <report_session/report_session.h>
#include <file_system_session/file_system_session.h>
/* local includes */
#include "import.h"
namespace Depot_download_manager {
template <typename SESSION>
static inline void gen_parent_service(Xml_generator &xml)
{
xml.node("service", [&] () {
xml.attribute("name", SESSION::service_name()); });
};
template <typename SESSION>
static inline void gen_parent_route(Xml_generator &xml)
{
xml.node("service", [&] () {
xml.attribute("name", SESSION::service_name());
xml.node("parent", [&] () { });
});
}
static inline void gen_parent_unscoped_rom_route(Xml_generator &xml,
Rom_name const &name)
{
xml.node("service", [&] () {
xml.attribute("name", Rom_session::service_name());
xml.attribute("unscoped_label", name);
xml.node("parent", [&] () {
xml.attribute("label", name); });
});
}
static inline void gen_parent_rom_route(Xml_generator &xml,
Rom_name const &name)
{
xml.node("service", [&] () {
xml.attribute("name", Rom_session::service_name());
xml.attribute("label", name);
xml.node("parent", [&] () {
xml.attribute("label", 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);
xml.node("resource", [&] () {
xml.attribute("name", "RAM");
xml.attribute("quantum", String<64>(Number_of_bytes(ram.value)));
});
}
void gen_depot_query_start_content(Xml_generator &,
Xml_node installation,
Archive::User const &,
Depot_query_version);
void gen_fetchurl_start_content(Xml_generator &, Import const &, Url const &,
Fetchurl_version);
void gen_verify_start_content(Xml_generator &, Import const &, Path const &);
void gen_chroot_start_content(Xml_generator &, Archive::User const &);
void gen_extract_start_content(Xml_generator &, Import const &,
Path const &, Archive::User const &);
}
#endif /* _GENERATE_XML_H_ */