elf_runner/
runtime_dir.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use fidl::endpoints::ServerEnd;
use fidl_fuchsia_io as fio;
use std::sync::Arc;
use vfs::directory::entry_container::Directory;
use vfs::directory::helper::DirectlyMutable;
use vfs::directory::immutable::simple as pfs;
use vfs::execution_scope::ExecutionScope;
use vfs::file::vmo::read_only;
use vfs::path::Path as fvfsPath;
use vfs::tree_builder::TreeBuilder;

// Simple directory type which is used to implement `ComponentStartInfo.runtime_directory`.
pub struct RuntimeDirectory(Arc<pfs::Simple>);

impl RuntimeDirectory {
    pub fn add_process_id(&self, process_id: u64) {
        self.elf_dir()
            .add_entry("process_id", read_only(process_id.to_string()))
            .expect("failed to add process_id");
    }

    pub fn add_process_start_time(&self, process_start_time: i64) {
        self.elf_dir()
            .add_entry("process_start_time", read_only(process_start_time.to_string()))
            .expect("failed to add process_start_time");
    }

    pub fn add_process_start_time_utc_estimate(&self, process_start_time_utc_estimate: String) {
        self.elf_dir()
            .add_entry(
                "process_start_time_utc_estimate",
                read_only(process_start_time_utc_estimate),
            )
            .expect("failed to add process_start_time_utc_estimate");
    }

    // Create an empty runtime directory, for test purpose only.
    #[cfg(test)]
    pub fn empty() -> Self {
        let mut empty = TreeBuilder::empty_dir();
        empty.add_empty_dir(["elf"]).expect("failed to add elf directory");
        RuntimeDirectory(empty.build())
    }

    fn elf_dir(&self) -> Arc<pfs::Simple> {
        self.0
            .get_entry("elf")
            .expect("elf directory should be present")
            .into_any()
            .downcast::<pfs::Simple>()
            .expect("could not downcast elf to a directory")
    }
}

pub struct RuntimeDirBuilder {
    args: Vec<String>,
    job_id: Option<u64>,
    server_end: ServerEnd<fio::NodeMarker>,
}

impl RuntimeDirBuilder {
    pub fn new(server_end: ServerEnd<fio::DirectoryMarker>) -> Self {
        // Transform the server end to speak Node protocol only
        let server_end = ServerEnd::<fio::NodeMarker>::new(server_end.into_channel());
        Self { args: vec![], job_id: None, server_end }
    }

    pub fn args(mut self, args: Vec<String>) -> Self {
        self.args = args;
        self
    }

    pub fn job_id(mut self, job_id: u64) -> Self {
        self.job_id = Some(job_id);
        self
    }

    pub fn serve(mut self) -> RuntimeDirectory {
        // Create the runtime tree structure
        //
        // runtime
        // |- args
        // |  |- 0
        // |  |- 1
        // |  \- ...
        // \- elf
        //    |- job_id
        //    \- process_id
        let mut runtime_tree_builder = TreeBuilder::empty_dir();
        let mut count: u32 = 0;
        for arg in self.args.drain(..) {
            runtime_tree_builder
                .add_entry(["args", &count.to_string()], read_only(arg))
                .expect("Failed to add arg to runtime directory");
            count += 1;
        }

        // Always add the "elf" directory so we can add process information later.
        runtime_tree_builder.add_empty_dir(["elf"]).expect("failed to add elf directory");

        if let Some(job_id) = self.job_id {
            runtime_tree_builder
                .add_entry(["elf", "job_id"], read_only(job_id.to_string()))
                .expect("Failed to add job_id to runtime/elf directory");
        }

        let runtime_directory = runtime_tree_builder.build();

        // Serve the runtime directory
        runtime_directory.clone().open(
            ExecutionScope::new(),
            fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE,
            fvfsPath::dot(),
            self.server_end,
        );

        RuntimeDirectory(runtime_directory)
    }
}