kanit

Toy init system
Log | Files | Refs | README | LICENSE

localmount.rs (3356B)


      1 use async_process::{Command, Stdio};
      2 use async_trait::async_trait;
      3 use log::info;
      4 use nix::unistd::sync;
      5 
      6 use kanit_common::error::{Context, ErrorKind, Result, StaticError};
      7 use kanit_unit::{Dependencies, Unit};
      8 
      9 use crate::mounts::{is_fs_mounted, parse_mounts};
     10 use crate::oneshot::{Clock, Modules, RootFs};
     11 use crate::unit_name;
     12 
     13 pub struct LocalMount;
     14 
     15 async fn kill_fs_users(fs: &str) -> Result<()> {
     16     Command::new("fuser")
     17         .args(["-KILL", "-k", "-m", fs])
     18         .spawn()
     19         .context("failed to spawn fuser")?
     20         .status()
     21         .await
     22         .context("failed to wait fuser")?;
     23 
     24     Ok(())
     25 }
     26 
     27 #[async_trait]
     28 impl Unit for LocalMount {
     29     unit_name!("localmount");
     30 
     31     fn dependencies(&self) -> Dependencies {
     32         Dependencies::new()
     33             .need(RootFs.name())
     34             .after(Clock.name())
     35             .after(Modules.name())
     36             .clone()
     37     }
     38 
     39     async fn start(&mut self) -> Result<()> {
     40         info!("mounting local filesystems");
     41 
     42         let succ = Command::new("mount")
     43             .stdout(Stdio::null())
     44             .args(["-a", "-t", "noproc"])
     45             .spawn()
     46             .context("failed to spawn mount")?
     47             .status()
     48             .await
     49             .context("failed to wait on mount")?
     50             .success();
     51 
     52         if !succ {
     53             Err(StaticError("failed to mount local filesystems")).kind(ErrorKind::Recoverable)?;
     54         }
     55 
     56         Ok(())
     57     }
     58 
     59     async fn stop(&mut self) -> Result<()> {
     60         sync();
     61 
     62         let mounted = async_fs::read_to_string("/proc/mounts")
     63             .await
     64             .context("failed to read mounts")?;
     65         // loopback
     66         info!("unmounting loopback");
     67 
     68         for mount in parse_mounts(&mounted)? {
     69             if !is_fs_mounted(mount.fs_file).await.unwrap_or(false) {
     70                 continue;
     71             }
     72 
     73             if !mount.fs_file.starts_with("/dev/loop") {
     74                 continue;
     75             }
     76 
     77             // should already be dead since init should've killed
     78             kill_fs_users(mount.fs_file).await?;
     79 
     80             Command::new("umount")
     81                 .args(["-d", mount.fs_file])
     82                 .spawn()
     83                 .context("failed to spawn umount")?
     84                 .status()
     85                 .await
     86                 .context("failed to wait umount")?;
     87         }
     88 
     89         // now everything but network
     90         info!("unmounting filesystems");
     91         for mount in parse_mounts(&mounted)? {
     92             let n = mount.fs_file;
     93 
     94             if !is_fs_mounted(n).await.unwrap_or(false) {
     95                 continue;
     96             }
     97 
     98             if n == "/"
     99                 || n == "/dev"
    100                 || n == "/sys"
    101                 || n == "/proc"
    102                 || n == "/run"
    103                 || n.starts_with("/dev/")
    104                 || n.starts_with("/sys/")
    105                 || n.starts_with("/proc/")
    106             {
    107                 continue;
    108             }
    109 
    110             if mount.fs_mntopts.contains_key("_netdev") {
    111                 continue;
    112             }
    113 
    114             kill_fs_users(mount.fs_file).await?;
    115 
    116             Command::new("umount")
    117                 .arg(mount.fs_file)
    118                 .spawn()
    119                 .context("failed to spawn umount")?
    120                 .status()
    121                 .await
    122                 .context("failed to wait umount")?;
    123         }
    124 
    125         Ok(())
    126     }
    127 }