WIP
This commit is contained in:
parent
0df7ab21e5
commit
cf91b29724
8 changed files with 357 additions and 59 deletions
70
Cargo.lock
generated
70
Cargo.lock
generated
|
|
@ -43,9 +43,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.4"
|
||||
version = "4.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
||||
checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
|
|
@ -58,9 +58,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.1.0"
|
||||
version = "4.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
||||
checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
|
@ -71,9 +71,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
||||
checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
|
@ -89,6 +89,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.0"
|
||||
|
|
@ -131,9 +137,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
|
|
@ -143,9 +149,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
|
||||
checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
|
|
@ -153,9 +159,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.3"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
|
||||
checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
|
|
@ -164,10 +170,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.5"
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
|
|
@ -230,9 +245,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.0"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
|
|
@ -313,9 +328,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.8"
|
||||
version = "0.36.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
|
||||
checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
|
|
@ -327,9 +342,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
|
|
@ -353,9 +368,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.92"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a"
|
||||
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
|
@ -376,9 +391,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -393,6 +408,7 @@ dependencies = [
|
|||
"clap",
|
||||
"dbus",
|
||||
"env_logger",
|
||||
"itertools",
|
||||
"log",
|
||||
"nix",
|
||||
"serde",
|
||||
|
|
@ -410,9 +426,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ anyhow = "1.0.68"
|
|||
clap = { version = "4.1.4", features = ["derive"] }
|
||||
dbus = "0.9.7"
|
||||
env_logger = "0.10.0"
|
||||
itertools = "0.10.5"
|
||||
log = "0.4.17"
|
||||
nix = "0.26.2"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
|
|
|
|||
11
nix/lib.nix
11
nix/lib.nix
|
|
@ -104,15 +104,12 @@ in
|
|||
${system-manager}/bin/system-manager deactivate "$@"
|
||||
'';
|
||||
|
||||
linkFarmEntryFromDrv = drv: {
|
||||
name = drv.name;
|
||||
path = drv;
|
||||
};
|
||||
|
||||
linkFarmBinEntryFromDrv = drv: {
|
||||
name = "bin/${drv.name}";
|
||||
linkFarmNestedEntryFromDrv = dirs: drv: {
|
||||
name = lib.concatStringsSep "/" (dirs ++ [ "${drv.name}" ]);
|
||||
path = drv;
|
||||
};
|
||||
linkFarmEntryFromDrv = linkFarmNestedEntryFromDrv [ ];
|
||||
linkFarmBinEntryFromDrv = linkFarmNestedEntryFromDrv [ "bin" ];
|
||||
in
|
||||
returnIfNoAssertions (
|
||||
pkgs.linkFarm "system-manager" [
|
||||
|
|
|
|||
|
|
@ -54,6 +54,20 @@ let
|
|||
group = "root";
|
||||
};
|
||||
|
||||
"a/nested/example/foo3" = {
|
||||
text = "boo!";
|
||||
mode = "0764";
|
||||
user = "root";
|
||||
group = "root";
|
||||
};
|
||||
|
||||
"a/nested/example2/foo3" = {
|
||||
text = "boo!";
|
||||
mode = "0764";
|
||||
user = "root";
|
||||
group = "root";
|
||||
};
|
||||
|
||||
out-of-store = {
|
||||
source = "/run/systemd/system/";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ pub fn activate(store_path: &StorePath, ephemeral: bool) -> Result<()> {
|
|||
log::info!("Running in ephemeral mode");
|
||||
}
|
||||
|
||||
// TODO we probably need to first deactivate left-over files and services
|
||||
// before we start putting in place the new ones.
|
||||
etc_files::activate(store_path, ephemeral)?;
|
||||
services::activate(store_path, ephemeral)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::DirBuilder;
|
||||
use std::fs::{DirBuilder, Permissions};
|
||||
use std::os::unix::prelude::PermissionsExt;
|
||||
use std::path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, io};
|
||||
|
||||
use crate::{create_link, create_store_link, StorePath};
|
||||
use crate::{
|
||||
create_link, create_store_link, remove_dir, remove_file, remove_link, StorePath,
|
||||
ETC_STATE_FILE_NAME, SYSTEM_MANAGER_STATE_DIR,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct EtcFile {
|
||||
source: StorePath,
|
||||
|
|
@ -22,13 +27,77 @@ struct EtcFile {
|
|||
|
||||
type EtcFiles = HashMap<String, EtcFile>;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct EtcFilesConfig {
|
||||
entries: EtcFiles,
|
||||
static_env: StorePath,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct EtcStateInfo {
|
||||
status: EtcFileStatus,
|
||||
// TODO directories and files are now both represented as a string associated with a nested
|
||||
// map. For files the nested map is simple empty.
|
||||
// We could potentially optimise this.
|
||||
nested: HashMap<String, EtcStateInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
enum EtcFileStatus {
|
||||
Managed,
|
||||
Unmanaged,
|
||||
}
|
||||
|
||||
impl EtcFileStatus {
|
||||
fn merge(&self, other: &Self) -> Self {
|
||||
use EtcFileStatus::*;
|
||||
|
||||
match (self, other) {
|
||||
(Unmanaged, Unmanaged) => Unmanaged,
|
||||
_ => Managed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EtcStateInfo {
|
||||
fn new() -> Self {
|
||||
Self::with_status(EtcFileStatus::Unmanaged)
|
||||
}
|
||||
|
||||
fn with_status(status: EtcFileStatus) -> Self {
|
||||
Self {
|
||||
status,
|
||||
nested: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO unit tests
|
||||
fn register_managed_path(mut self, components: &[String], path: String) -> Self {
|
||||
let state = components.iter().fold(&mut self, |state, component| {
|
||||
if !state.nested.contains_key(component) {
|
||||
let new_state = Self::new();
|
||||
state.nested.insert(component.to_owned(), new_state);
|
||||
}
|
||||
state.nested.get_mut(component).unwrap()
|
||||
});
|
||||
|
||||
state
|
||||
.nested
|
||||
.insert(path, Self::with_status(EtcFileStatus::Managed));
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct CreatedEtcFile {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
pub fn activate(store_path: &StorePath, ephemeral: bool) -> Result<()> {
|
||||
log::info!("Reading etc file definitions...");
|
||||
let file = fs::File::open(Path::new(&store_path.store_path).join("etcFiles/etcFiles.json"))?;
|
||||
|
|
@ -40,48 +109,205 @@ pub fn activate(store_path: &StorePath, ephemeral: bool) -> Result<()> {
|
|||
log::debug!("Storing /etc entries in {}", etc_dir.display());
|
||||
|
||||
DirBuilder::new().recursive(true).create(&etc_dir)?;
|
||||
create_store_link(
|
||||
&config.static_env,
|
||||
etc_dir.join(".system-manager-static").as_path(),
|
||||
)?;
|
||||
|
||||
config
|
||||
.entries
|
||||
.into_iter()
|
||||
.try_for_each(|(name, entry)| create_etc_link(&name, &entry, &etc_dir))?;
|
||||
// TODO: constant?
|
||||
let static_dir_name = ".system-manager-static";
|
||||
let static_path = etc_dir.join(static_dir_name);
|
||||
create_store_link(&config.static_env, static_path.as_path())?;
|
||||
|
||||
// TODO register the crated files (including .system-manager-static) in a
|
||||
// state file, and clean up old files from the previous generation
|
||||
// TODO remove all paths that are in the state file from the previous generation
|
||||
// and not in the current one.
|
||||
|
||||
let state = read_created_files()?;
|
||||
let new_state = create_etc_links(config.entries.values(), &etc_dir, state);
|
||||
serialise_created_files(&new_state.register_managed_path(&[], static_dir_name.to_owned()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO we need to record in a state file which files we created and then remove them
|
||||
pub fn deactivate() -> Result<()> {
|
||||
let old_created_files = read_created_files()?;
|
||||
log::debug!("{:?}", old_created_files);
|
||||
|
||||
// TODO
|
||||
//old_created_files
|
||||
// .iter()
|
||||
// .try_for_each(|created_file| remove_created_file(&created_file.path, "etc"))?;
|
||||
|
||||
serialise_created_files(&EtcStateInfo::new())?;
|
||||
|
||||
log::info!("Done");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_etc_link(name: &str, entry: &EtcFile, etc_dir: &Path) -> Result<()> {
|
||||
fn remove_created_file<P>(created_file: &P, root_dir: &str) -> Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let path = created_file.as_ref();
|
||||
let recurse = if path.is_file() {
|
||||
remove_file(path)?;
|
||||
true
|
||||
} else if path.is_symlink() {
|
||||
remove_link(path)?;
|
||||
true
|
||||
} else if path.is_dir() && fs::read_dir(created_file)?.next().is_none() {
|
||||
log::info!("We will remove the following directory: {}", path.display());
|
||||
remove_dir(path)?;
|
||||
true
|
||||
} else {
|
||||
log::debug!("Stopped at directory {}.", path.display());
|
||||
false
|
||||
};
|
||||
|
||||
if recurse {
|
||||
if let Some(parent) = path.parent() {
|
||||
if parent
|
||||
.file_name()
|
||||
.filter(|name| &root_dir != name)
|
||||
.is_some()
|
||||
{
|
||||
log::debug!("Recursing up into directory {}...", parent.display());
|
||||
return remove_created_file(&parent, root_dir);
|
||||
}
|
||||
log::debug!("Reached root dir: {}", parent.display());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_etc_links<'a, E>(entries: E, etc_dir: &Path, state: EtcStateInfo) -> EtcStateInfo
|
||||
where
|
||||
E: Iterator<Item = &'a EtcFile>,
|
||||
{
|
||||
entries.fold(state, |state, entry| {
|
||||
let (new_state, status) = create_etc_link(entry, etc_dir, state);
|
||||
match status {
|
||||
Ok(_) => new_state,
|
||||
Err(e) => {
|
||||
log::error!("Error while creating file in {}: {e}", etc_dir.display());
|
||||
new_state
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn create_etc_link(
|
||||
entry: &EtcFile,
|
||||
etc_dir: &Path,
|
||||
state: EtcStateInfo,
|
||||
) -> (EtcStateInfo, Result<()>) {
|
||||
if entry.mode == "symlink" {
|
||||
if let Some(path::Component::Normal(link_target)) =
|
||||
entry.target.components().into_iter().next()
|
||||
{
|
||||
create_link(
|
||||
let link_name = etc_dir.join(link_target);
|
||||
match create_link(
|
||||
Path::new(".")
|
||||
.join(".system-manager-static")
|
||||
.join("etc")
|
||||
.join(link_target)
|
||||
.as_path(),
|
||||
etc_dir.join(link_target).as_path(),
|
||||
)
|
||||
link_name.as_path(),
|
||||
) {
|
||||
Ok(_) => (
|
||||
state.register_managed_path(&[], link_target.to_string_lossy().into_owned()),
|
||||
Ok(()),
|
||||
),
|
||||
e => (state, e),
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!("Cannot create link for this entry ({name}).")
|
||||
(
|
||||
state,
|
||||
Err(anyhow!("Cannot create link: {}", entry.target.display(),)),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
let dirbuilder = DirBuilder::new();
|
||||
let target_path = etc_dir.join(entry.target.as_path());
|
||||
|
||||
// Create all parent dirs that do not exist yet
|
||||
let (new_state, created_paths, _, status) = target_path
|
||||
.parent()
|
||||
.unwrap() // TODO
|
||||
.components()
|
||||
.fold_while(
|
||||
(state, Vec::new(), PathBuf::from("/"), Ok(())),
|
||||
|(state, mut created, path, _), component| {
|
||||
use itertools::FoldWhile::{Continue, Done};
|
||||
use path::Component;
|
||||
|
||||
match component {
|
||||
Component::RootDir => Continue((state, created, path, Ok(()))),
|
||||
Component::Normal(dir) => {
|
||||
let new_path = path.join(dir);
|
||||
if !new_path.exists() {
|
||||
log::debug!("Creating path: {}", new_path.display());
|
||||
match dirbuilder.create(new_path.as_path()) {
|
||||
Ok(_) => {
|
||||
let new_state = state.register_managed_path(
|
||||
&created,
|
||||
dir.to_string_lossy().into_owned(),
|
||||
);
|
||||
created.push(dir.to_string_lossy().into_owned());
|
||||
Continue((new_state, created, new_path, Ok(())))
|
||||
}
|
||||
Err(e) => Done((state, created, path, Err(anyhow!(e)))),
|
||||
}
|
||||
} else {
|
||||
created.push(dir.to_string_lossy().into_owned());
|
||||
Continue((state, created, new_path, Ok(())))
|
||||
}
|
||||
}
|
||||
otherwise => Done((
|
||||
state,
|
||||
created,
|
||||
path,
|
||||
Err(anyhow!(
|
||||
"Unexpected path component encountered: {:?}",
|
||||
otherwise
|
||||
)),
|
||||
)),
|
||||
}
|
||||
},
|
||||
)
|
||||
.into_inner();
|
||||
|
||||
match status.and_then(|_| {
|
||||
copy_file(
|
||||
entry
|
||||
.source
|
||||
.store_path
|
||||
.join("etc")
|
||||
.join(&entry.target)
|
||||
.as_path(),
|
||||
&target_path,
|
||||
&entry.mode,
|
||||
)
|
||||
}) {
|
||||
Ok(_) => (
|
||||
new_state.register_managed_path(
|
||||
&created_paths,
|
||||
target_path
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
),
|
||||
Ok(()),
|
||||
),
|
||||
e => (new_state, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_file(source: &Path, target: &Path, mode: &str) -> Result<()> {
|
||||
fs::copy(source, target)?;
|
||||
let mode_int = u32::from_str_radix(mode, 8).map_err(anyhow::Error::from)?;
|
||||
fs::set_permissions(target, Permissions::from_mode(mode_int))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn etc_dir(ephemeral: bool) -> PathBuf {
|
||||
if ephemeral {
|
||||
Path::new("/run").join("etc")
|
||||
|
|
@ -89,3 +315,35 @@ fn etc_dir(ephemeral: bool) -> PathBuf {
|
|||
Path::new("/etc").to_path_buf()
|
||||
}
|
||||
}
|
||||
|
||||
fn serialise_created_files(created_files: &EtcStateInfo) -> Result<()> {
|
||||
let state_file = Path::new(SYSTEM_MANAGER_STATE_DIR).join(ETC_STATE_FILE_NAME);
|
||||
DirBuilder::new()
|
||||
.recursive(true)
|
||||
.create(SYSTEM_MANAGER_STATE_DIR)?;
|
||||
|
||||
log::info!("Writing state info into file: {}", state_file.display());
|
||||
let writer = io::BufWriter::new(fs::File::create(state_file)?);
|
||||
serde_json::to_writer(writer, created_files)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_created_files() -> Result<EtcStateInfo> {
|
||||
let state_file = Path::new(SYSTEM_MANAGER_STATE_DIR).join(ETC_STATE_FILE_NAME);
|
||||
DirBuilder::new()
|
||||
.recursive(true)
|
||||
.create(SYSTEM_MANAGER_STATE_DIR)?;
|
||||
|
||||
if Path::new(&state_file).is_file() {
|
||||
log::info!("Reading state info from {}", state_file.display());
|
||||
let reader = io::BufReader::new(fs::File::open(state_file)?);
|
||||
match serde_json::from_reader(reader) {
|
||||
Ok(created_files) => return Ok(created_files),
|
||||
Err(e) => {
|
||||
log::error!("Error reading the state file, ignoring.");
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(EtcStateInfo::new())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,8 +87,6 @@ pub fn deactivate() -> Result<()> {
|
|||
let old_linked_services = read_linked_services()?;
|
||||
log::debug!("{:?}", old_linked_services);
|
||||
|
||||
serialise_linked_services(&HashMap::new())?;
|
||||
|
||||
let service_manager = systemd::ServiceManager::new_session()?;
|
||||
let timeout = Some(Duration::from_secs(30));
|
||||
|
||||
|
|
@ -102,6 +100,8 @@ pub fn deactivate() -> Result<()> {
|
|||
log::info!("Reloading the systemd daemon...");
|
||||
service_manager.daemon_reload()?;
|
||||
|
||||
serialise_linked_services(&HashMap::new())?;
|
||||
|
||||
log::info!("Done");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
12
src/lib.rs
12
src/lib.rs
|
|
@ -14,7 +14,7 @@ const PROFILE_NAME: &str = "system-manager";
|
|||
const GCROOT_PATH: &str = "/nix/var/nix/gcroots/system-manager-current";
|
||||
const SYSTEM_MANAGER_STATE_DIR: &str = "/var/lib/system-manager/state";
|
||||
const SERVICES_STATE_FILE_NAME: &str = "services.json";
|
||||
//const ETC_STATE_FILE_NAME: &str = "etc-files.json";
|
||||
const ETC_STATE_FILE_NAME: &str = "etc-files.json";
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(from = "String", into = "String", rename_all = "camelCase")]
|
||||
|
|
@ -77,6 +77,16 @@ fn remove_link(from: &Path) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_file(from: &Path) -> Result<()> {
|
||||
log::info!("Removing file: {}", from.display());
|
||||
fs::remove_file(from).map_err(anyhow::Error::from)
|
||||
}
|
||||
|
||||
fn remove_dir(from: &Path) -> Result<()> {
|
||||
log::info!("Removing directory: {}", from.display());
|
||||
fs::remove_dir(from).map_err(anyhow::Error::from)
|
||||
}
|
||||
|
||||
pub fn compose<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
|
||||
where
|
||||
F: Fn(B) -> C,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue