starnix_kernel_runner/
mounts.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::{Error, anyhow, bail};
6use fidl_fuchsia_io as fio;
7use starnix_core::fs::fuchsia::{RemoteBundle, create_remotefs_filesystem};
8use starnix_core::fs::tmpfs::TmpFs;
9use starnix_core::task::{CurrentTask, Kernel};
10use starnix_core::vfs::fs_args::MountParams;
11use starnix_core::vfs::{FileSystemHandle, FileSystemOptions, FsString};
12use starnix_sync::{Locked, Unlocked};
13use starnix_uapi::mount_flags::MountFlags;
14
15pub struct MountAction {
16    pub path: FsString,
17    pub fs: FileSystemHandle,
18    pub flags: MountFlags,
19}
20
21impl MountAction {
22    pub fn new_for_root(
23        locked: &mut Locked<Unlocked>,
24        kernel: &Kernel,
25        pkg: &fio::DirectorySynchronousProxy,
26        spec: &str,
27    ) -> Result<MountAction, Error> {
28        let (spec, options) = MountSpec::parse(spec)?;
29        assert_eq!(spec.mount_point.as_slice(), b"/");
30        let rights = fio::PERM_READABLE | fio::PERM_EXECUTABLE;
31
32        // We only support mounting these file systems at the root.
33        // The root file system needs to be creatable without a task because we mount the root
34        // file system before creating the initial task.
35        let fs = match spec.fs_type.as_slice() {
36            b"remote_bundle" => RemoteBundle::new_fs(locked, kernel, pkg, options, rights)?,
37            b"remote_pkg_subdir" => {
38                create_remotefs_filesystem(locked, kernel, pkg, options, rights)?
39            }
40            b"tmpfs" => TmpFs::new_fs_with_options(locked, kernel, options)?,
41            _ => bail!("unsupported root file system: {}", spec.fs_type),
42        };
43
44        Ok(spec.into_action(fs))
45    }
46
47    pub fn from_spec(
48        locked: &mut Locked<Unlocked>,
49        current_task: &CurrentTask,
50        pkg: &fio::DirectorySynchronousProxy,
51        spec: &str,
52    ) -> Result<MountAction, Error> {
53        let (spec, options) = MountSpec::parse(spec)?;
54        let rights = fio::PERM_READABLE | fio::PERM_EXECUTABLE;
55
56        let fs = match spec.fs_type.as_slice() {
57            // The remote_bundle file system is available only via the mounts declaration in CML.
58            b"remote_bundle" => {
59                RemoteBundle::new_fs(locked, current_task.kernel(), pkg, options, rights)?
60            }
61
62            // Mounts a subdirectory of the container's `/pkg`.
63            b"remote_pkg_subdir" => {
64                create_remotefs_filesystem(locked, current_task.kernel(), pkg, options, rights)?
65            }
66
67            _ => current_task.create_filesystem(locked, spec.fs_type.as_ref(), options)?,
68        };
69
70        Ok(spec.into_action(fs))
71    }
72}
73
74struct MountSpec {
75    mount_point: FsString,
76    fs_type: FsString,
77    flags: MountFlags,
78}
79
80impl MountSpec {
81    fn parse(spec: &str) -> Result<(MountSpec, FileSystemOptions), Error> {
82        let mut iter = spec.splitn(4, ':');
83        let mount_point =
84            iter.next().ok_or_else(|| anyhow!("mount point is missing from {:?}", spec))?;
85        let fs_type = iter.next().ok_or_else(|| anyhow!("fs type is missing from {:?}", spec))?;
86        let fs_src = match iter.next() {
87            Some(src) if !src.is_empty() => src,
88            _ => ".",
89        };
90
91        let mut params = MountParams::parse(iter.next().unwrap_or_default().into())?;
92        let flags = params.remove_mount_flags();
93
94        Ok((
95            MountSpec { fs_type: fs_type.into(), mount_point: mount_point.into(), flags },
96            FileSystemOptions {
97                source: fs_src.into(),
98                flags: flags & MountFlags::STORED_ON_FILESYSTEM,
99                params,
100            },
101        ))
102    }
103
104    fn into_action(self, fs: FileSystemHandle) -> MountAction {
105        MountAction { path: self.mount_point.into(), fs, flags: self.flags }
106    }
107}