2020-12-04 18:05:14 +03:00
use crate ::ffiutil ;
2020-12-11 04:21:33 +03:00
use anyhow ::Result ;
use ffiutil ::ffi_view_openat_dir ;
2020-12-04 18:05:14 +03:00
use openat_ext ::OpenatDirExt ;
/// Guard for running logic in a context with temporary /etc.
///
/// We have a messy dance in dealing with /usr/etc and /etc; the
/// current model is basically to have it be /etc whenever we're running
/// any code.
#[ derive(Debug) ]
pub struct TempEtcGuard {
rootfs : openat ::Dir ,
renamed_etc : bool ,
}
2020-12-11 04:21:33 +03:00
pub fn prepare_tempetc_guard ( rootfs : i32 ) -> Result < Box < TempEtcGuard > > {
let rootfs = ffi_view_openat_dir ( rootfs ) ;
let has_usretc = rootfs . exists ( " usr/etc " ) ? ;
let mut renamed_etc = false ;
if has_usretc {
// In general now, we place contents in /etc when running scripts
rootfs . local_rename ( " usr/etc " , " etc " ) ? ;
// But leave a compat symlink, as we used to bind mount, so scripts
// could still use that too.
rootfs . symlink ( " usr/etc " , " ../etc " ) ? ;
renamed_etc = true ;
2020-12-04 18:05:14 +03:00
}
2020-12-11 04:21:33 +03:00
Ok ( Box ::new ( TempEtcGuard {
rootfs ,
renamed_etc ,
} ) )
}
2020-12-04 18:05:14 +03:00
2020-12-11 04:21:33 +03:00
impl TempEtcGuard {
2020-12-04 18:05:14 +03:00
/// Remove the temporary /etc, and destroy the guard.
2020-12-11 04:21:33 +03:00
pub fn undo ( & self ) -> anyhow ::Result < ( ) > {
2020-12-04 18:05:14 +03:00
if self . renamed_etc {
/* Remove the symlink and swap back */
self . rootfs . remove_file ( " usr/etc " ) ? ;
self . rootfs . local_rename ( " etc " , " usr/etc " ) ? ;
}
Ok ( ( ) )
}
}
2020-12-11 04:21:33 +03:00
#[ cfg(test) ]
mod test {
2020-12-04 18:05:14 +03:00
use super ::* ;
2020-12-11 04:21:33 +03:00
use std ::os ::unix ::prelude ::* ;
2020-12-04 18:05:14 +03:00
2020-12-11 04:21:33 +03:00
#[ test ]
fn basic ( ) -> Result < ( ) > {
let td = tempfile ::tempdir ( ) ? ;
let d = openat ::Dir ::open ( td . path ( ) ) ? ;
let g = super ::prepare_tempetc_guard ( d . as_raw_fd ( ) ) ? ;
g . undo ( ) ? ;
d . ensure_dir_all ( " usr/etc/foo " , 0o755 ) ? ;
assert! ( ! d . exists ( " etc/foo " ) ? ) ;
let g = super ::prepare_tempetc_guard ( d . as_raw_fd ( ) ) ? ;
assert! ( d . exists ( " etc/foo " ) ? ) ;
g . undo ( ) ? ;
assert! ( ! d . exists ( " etc " ) ? ) ;
assert! ( d . exists ( " usr/etc/foo " ) ? ) ;
Ok ( ( ) )
2020-12-04 18:05:14 +03:00
}
}