forked from brl/citadel-tools
Clippy fixes
This commit is contained in:
parent
fab4106302
commit
7d89c47eb2
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
**/target
|
**/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
**/*.iml
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ impl Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn apply_colors(&self, colors: theme::ColorPair) {
|
fn apply_colors(&self, colors: theme::ColorPair) {
|
||||||
with_color(&colors.front, |c| self.write(tcolor::Fg(c)));
|
with_color(colors.front, |c| self.write(tcolor::Fg(c)));
|
||||||
with_color(&colors.back, |c| self.write(tcolor::Bg(c)));
|
with_color(colors.back, |c| self.write(tcolor::Bg(c)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_key(&mut self, event: TEvent) -> Event {
|
fn map_key(&mut self, event: TEvent) -> Event {
|
||||||
@ -257,7 +257,7 @@ impl backend::Backend for Backend {
|
|||||||
self.current_style.set(color);
|
self.current_style.set(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
return current_style;
|
current_style
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_effect(&self, effect: theme::Effect) {
|
fn set_effect(&self, effect: theme::Effect) {
|
||||||
@ -326,11 +326,11 @@ impl backend::Backend for Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_color<F, R>(clr: &theme::Color, f: F) -> R
|
fn with_color<F, R>(clr: theme::Color, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&dyn tcolor::Color) -> R,
|
F: FnOnce(&dyn tcolor::Color) -> R,
|
||||||
{
|
{
|
||||||
match *clr {
|
match clr {
|
||||||
theme::Color::TerminalDefault => f(&tcolor::Reset),
|
theme::Color::TerminalDefault => f(&tcolor::Reset),
|
||||||
theme::Color::Dark(theme::BaseColor::Black) => f(&tcolor::Black),
|
theme::Color::Dark(theme::BaseColor::Black) => f(&tcolor::Black),
|
||||||
theme::Color::Dark(theme::BaseColor::Red) => f(&tcolor::Red),
|
theme::Color::Dark(theme::BaseColor::Red) => f(&tcolor::Red),
|
||||||
@ -374,10 +374,8 @@ pub fn start_resize_thread(
|
|||||||
// We know it will only contain SIGWINCH signals, so no need to check.
|
// We know it will only contain SIGWINCH signals, so no need to check.
|
||||||
if signals.wait().count() > 0 {
|
if signals.wait().count() > 0 {
|
||||||
// XXX fixed to avoid panic
|
// XXX fixed to avoid panic
|
||||||
if resize_running.load(Ordering::Relaxed) {
|
if resize_running.load(Ordering::Relaxed) && resize_sender.send(()).is_err() {
|
||||||
if let Err(_) = resize_sender.send(()) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ impl FieldLayout {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let labels = labels
|
let labels = labels
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(pad_label)
|
.map(pad_label)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ pub trait DialogButtonAdapter: Finder+ViewWrapper {
|
|||||||
{
|
{
|
||||||
let id = self.inner_id();
|
let id = self.inner_id();
|
||||||
self.call_on_id(id, cb)
|
self.call_on_id(id, cb)
|
||||||
.expect(format!("failed call_on_id({})", id).as_str())
|
.unwrap_or_else(|| panic!("failed call_on_id({})", id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button_enabled(&mut self, button: usize) -> bool {
|
fn button_enabled(&mut self, button: usize) -> bool {
|
||||||
@ -322,9 +322,9 @@ pub trait DialogButtonAdapter: Finder+ViewWrapper {
|
|||||||
|
|
||||||
fn set_button_enabled(&mut self, button: usize, enabled: bool) {
|
fn set_button_enabled(&mut self, button: usize, enabled: bool) {
|
||||||
self.call_on_dialog(|d| {
|
self.call_on_dialog(|d| {
|
||||||
d.buttons_mut()
|
if let Some(b) = d.buttons_mut().nth(button) {
|
||||||
.nth(button)
|
b.set_enabled(enabled);
|
||||||
.map(|b| b.set_enabled(enabled));
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,8 +416,7 @@ impl ValidatorResult {
|
|||||||
|
|
||||||
fn process(self, siv: &mut Cursive) {
|
fn process(self, siv: &mut Cursive) {
|
||||||
match self {
|
match self {
|
||||||
ValidatorResult::Allow(cb) => (cb)(siv),
|
ValidatorResult::Allow(cb) | ValidatorResult::Deny(cb) => (cb)(siv),
|
||||||
ValidatorResult::Deny(cb) => (cb)(siv),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,7 +469,7 @@ impl TextValidator {
|
|||||||
where F: FnOnce(&mut EditView) -> R {
|
where F: FnOnce(&mut EditView) -> R {
|
||||||
|
|
||||||
siv.call_on_id(&self.id, f)
|
siv.call_on_id(&self.id, f)
|
||||||
.expect(&format!("call_on_id({})", self.id))
|
.unwrap_or_else(|| panic!("call_on_id({})", self.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -134,8 +134,7 @@ impl <T: Clone + 'static> ItemList<T> {
|
|||||||
where F: FnOnce(&mut ItemList<T>) -> R
|
where F: FnOnce(&mut ItemList<T>) -> R
|
||||||
{
|
{
|
||||||
s.call_on_id(id, |v: &mut ItemList<T>| f(v))
|
s.call_on_id(id, |v: &mut ItemList<T>| f(v))
|
||||||
.expect(&format!("ItemList::call_on_id({})", id))
|
.unwrap_or_else(|| panic!("ItemList::call_on_id({})", id))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create<C>(id: &'static str, title: &str, content: C) -> impl View
|
pub fn create<C>(id: &'static str, title: &str, content: C) -> impl View
|
||||||
@ -294,7 +293,7 @@ impl Inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pop_style(&mut self) -> Style {
|
fn pop_style(&mut self) -> Style {
|
||||||
self.styles.pop().unwrap_or(Style::none())
|
self.styles.pop().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append(&mut self, s: StyledString) {
|
fn append(&mut self, s: StyledString) {
|
||||||
|
@ -79,10 +79,8 @@ impl RealmAction {
|
|||||||
let msg = "Open terminal in realm '$REALM'?";
|
let msg = "Open terminal in realm '$REALM'?";
|
||||||
Self::confirm_action(title, msg, |r| {
|
Self::confirm_action(title, msg, |r| {
|
||||||
let manager = r.manager();
|
let manager = r.manager();
|
||||||
if !r.is_active() {
|
if !r.is_active() && !Self::log_fail("starting realm", || manager.start_realm(r)) {
|
||||||
if !Self::log_fail("starting realm", || manager.start_realm(r)) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Self::log_fail("starting terminal", || manager.launch_terminal(r));
|
Self::log_fail("starting terminal", || manager.launch_terminal(r));
|
||||||
})
|
})
|
||||||
@ -146,7 +144,7 @@ impl RealmAction {
|
|||||||
EventResult::with_cb(|s| {
|
EventResult::with_cb(|s| {
|
||||||
let realm = RealmAction::current_realm(s);
|
let realm = RealmAction::current_realm(s);
|
||||||
let desc = format!("realm-{}", realm.name());
|
let desc = format!("realm-{}", realm.name());
|
||||||
let notes = realm.notes().unwrap_or(String::new());
|
let notes = realm.notes().unwrap_or_default();
|
||||||
NotesDialog::open(s, &desc, notes, move |s, notes| {
|
NotesDialog::open(s, &desc, notes, move |s, notes| {
|
||||||
if let Err(e) = realm.save_notes(notes) {
|
if let Err(e) = realm.save_notes(notes) {
|
||||||
warn!("error saving notes file for realm-{}: {}", realm.name(), e);
|
warn!("error saving notes file for realm-{}: {}", realm.name(), e);
|
||||||
|
@ -153,7 +153,7 @@ impl ConfigDialog {
|
|||||||
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
||||||
{
|
{
|
||||||
self.call_on_id(id, callback)
|
self.call_on_id(id, callback)
|
||||||
.expect(format!("failed call_on_id({})", id).as_str())
|
.unwrap_or_else(|| panic!("failed call_on_id({})", id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_changes(&mut self) {
|
pub fn reset_changes(&mut self) {
|
||||||
@ -372,15 +372,13 @@ impl OptionEntry {
|
|||||||
|
|
||||||
fn load(&mut self, config: &mut RealmConfig) {
|
fn load(&mut self, config: &mut RealmConfig) {
|
||||||
let var = (self.accessor)(config);
|
let var = (self.accessor)(config);
|
||||||
self.value = var.clone();
|
self.value = *var;
|
||||||
self.original = var.clone();
|
self.original = *var;
|
||||||
self.default = self.resolve_default(config);
|
self.default = self.resolve_default(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, v: bool) {
|
fn set(&mut self, v: bool) {
|
||||||
if v != self.default {
|
if v != self.default || self.original == Some(v) {
|
||||||
self.value = Some(v);
|
|
||||||
} else if Some(v) == self.original {
|
|
||||||
self.value = Some(v);
|
self.value = Some(v);
|
||||||
} else {
|
} else {
|
||||||
self.value = None;
|
self.value = None;
|
||||||
|
@ -156,9 +156,9 @@ impl <'a> RealmInfoRender <'a> {
|
|||||||
|
|
||||||
if self.realm.is_active() {
|
if self.realm.is_active() {
|
||||||
self.print(" Running");
|
self.print(" Running");
|
||||||
self.realm.leader_pid().map(|pid| {
|
if let Some(pid) = self.realm.leader_pid() {
|
||||||
self.print(format!(" (Leader pid: {})", pid));
|
self.print(format!(" (Leader pid: {})", pid));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
self.newlines(2);
|
self.newlines(2);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ impl NewRealmDialog {
|
|||||||
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
||||||
{
|
{
|
||||||
self.call_on_id(id, callback)
|
self.call_on_id(id, callback)
|
||||||
.expect(format!("failed call_on_id({})", id).as_str())
|
.unwrap_or_else(|| panic!("failed call_on_id({})", id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ impl NewRealmFSDialog {
|
|||||||
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
||||||
{
|
{
|
||||||
self.call_on_id(id, callback)
|
self.call_on_id(id, callback)
|
||||||
.expect(format!("failed call_on_id({})", id).as_str())
|
.unwrap_or_else(|| panic!("failed call_on_id({})", id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_ok_button_enabled(&mut self, enabled: bool) {
|
fn set_ok_button_enabled(&mut self, enabled: bool) {
|
||||||
|
@ -169,7 +169,7 @@ impl RealmFSAction {
|
|||||||
EventResult::with_cb(|s| {
|
EventResult::with_cb(|s| {
|
||||||
let realmfs = Self::current_realmfs(s);
|
let realmfs = Self::current_realmfs(s);
|
||||||
let desc = format!("{}-realmfs.img", realmfs.name());
|
let desc = format!("{}-realmfs.img", realmfs.name());
|
||||||
let notes = realmfs.notes().unwrap_or(String::new());
|
let notes = realmfs.notes().unwrap_or_default();
|
||||||
NotesDialog::open(s, &desc, notes, move |s, notes| {
|
NotesDialog::open(s, &desc, notes, move |s, notes| {
|
||||||
if let Err(e) = realmfs.save_notes(notes) {
|
if let Err(e) = realmfs.save_notes(notes) {
|
||||||
warn!("error saving notes file for {}-realmfs.img: {}", realmfs.name(), e);
|
warn!("error saving notes file for {}-realmfs.img: {}", realmfs.name(), e);
|
||||||
|
@ -113,7 +113,7 @@ impl ForkDialog {
|
|||||||
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
fn call_id<V: View, F: FnOnce(&mut V) -> R, R>(&mut self, id: &str, callback: F) -> R
|
||||||
{
|
{
|
||||||
self.call_on_id(id, callback)
|
self.call_on_id(id, callback)
|
||||||
.expect(format!("failed call_on_id({})", id).as_str())
|
.unwrap_or_else(|| panic!("failed call_on_id({})", id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ impl <'a> RealmFSInfoRender <'a> {
|
|||||||
|
|
||||||
self.print(" Device : ")
|
self.print(" Device : ")
|
||||||
.dim_style()
|
.dim_style()
|
||||||
.println(format!("{}", activation.device()))
|
.println(activation.device())
|
||||||
.pop();
|
.pop();
|
||||||
|
|
||||||
let mount = if activation.mountpoint_rw().is_some() { "Mounts" } else { "Mount "};
|
let mount = if activation.mountpoint_rw().is_some() { "Mounts" } else { "Mount "};
|
||||||
|
@ -46,7 +46,7 @@ impl ThemeHandler {
|
|||||||
(0x3, "highlight_inactive"),
|
(0x3, "highlight_inactive"),
|
||||||
];
|
];
|
||||||
for pair in &mapping {
|
for pair in &mapping {
|
||||||
ThemeHandler::set_palette_color(&mut theme, pair.1, base16.color(pair.0).rgb());
|
Self::set_palette_color(&mut theme, pair.1, base16.color(pair.0).rgb());
|
||||||
}
|
}
|
||||||
theme
|
theme
|
||||||
}
|
}
|
||||||
@ -55,13 +55,13 @@ impl ThemeHandler {
|
|||||||
const DEFAULT_SCHEME: &'static str = "default-dark";
|
const DEFAULT_SCHEME: &'static str = "default-dark";
|
||||||
|
|
||||||
pub fn save_base16_theme(base16: &Base16Scheme) {
|
pub fn save_base16_theme(base16: &Base16Scheme) {
|
||||||
if let Err(e) = fs::write(ThemeHandler::SCHEME_CONF_PATH, base16.slug()) {
|
if let Err(e) = fs::write(Self::SCHEME_CONF_PATH, base16.slug()) {
|
||||||
warn!("Error writing color scheme file ({}): {}", ThemeHandler::SCHEME_CONF_PATH, e);
|
warn!("Error writing color scheme file ({}): {}", Self::SCHEME_CONF_PATH, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_base16_scheme() -> Option<Base16Scheme> {
|
pub fn load_base16_scheme() -> Option<Base16Scheme> {
|
||||||
let path = Path::new(ThemeHandler::SCHEME_CONF_PATH);
|
let path = Path::new(Self::SCHEME_CONF_PATH);
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
fs::read_to_string(path).ok().and_then(|ref s| Base16Scheme::by_name(s).cloned())
|
fs::read_to_string(path).ok().and_then(|ref s| Base16Scheme::by_name(s).cloned())
|
||||||
} else {
|
} else {
|
||||||
@ -70,8 +70,8 @@ impl ThemeHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_base16_theme() -> Theme {
|
pub fn load_base16_theme() -> Theme {
|
||||||
let path = Path::new(ThemeHandler::SCHEME_CONF_PATH);
|
let path = Path::new(Self::SCHEME_CONF_PATH);
|
||||||
let mut scheme = Base16Scheme::by_name(ThemeHandler::DEFAULT_SCHEME).unwrap();
|
let mut scheme = Base16Scheme::by_name(Self::DEFAULT_SCHEME).unwrap();
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
if let Ok(scheme_name) = fs::read_to_string(path) {
|
if let Ok(scheme_name) = fs::read_to_string(path) {
|
||||||
if let Some(sch) = Base16Scheme::by_name(&scheme_name) {
|
if let Some(sch) = Base16Scheme::by_name(&scheme_name) {
|
||||||
@ -79,7 +79,7 @@ impl ThemeHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ThemeHandler::generate_base16_theme(scheme)
|
Self::generate_base16_theme(scheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ impl ThemeChooser {
|
|||||||
|
|
||||||
pub fn open(s: &mut Cursive) {
|
pub fn open(s: &mut Cursive) {
|
||||||
let initial = ThemeHandler::load_base16_scheme();
|
let initial = ThemeHandler::load_base16_scheme();
|
||||||
let chooser = ThemeChooser::new(initial, |s,v| {
|
let chooser = Self::new(initial, |s,v| {
|
||||||
ThemeHandler::save_base16_theme(v);
|
ThemeHandler::save_base16_theme(v);
|
||||||
let theme = ThemeHandler::generate_base16_theme(v);
|
let theme = ThemeHandler::generate_base16_theme(v);
|
||||||
s.set_theme(theme);
|
s.set_theme(theme);
|
||||||
@ -99,11 +99,11 @@ impl ThemeChooser {
|
|||||||
s.add_layer(chooser.with_id("theme-chooser"));
|
s.add_layer(chooser.with_id("theme-chooser"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new<F>(initial: Option<Base16Scheme>, cb: F) -> ThemeChooser
|
pub fn new<F>(initial: Option<Base16Scheme>, cb: F) -> Self
|
||||||
where F: 'static + Fn(&mut Cursive, &Base16Scheme)
|
where F: 'static + Fn(&mut Cursive, &Base16Scheme)
|
||||||
{
|
{
|
||||||
let select = ThemeChooser::create_tree_view(initial.clone(), cb);
|
let select = Self::create_tree_view(initial.clone(), cb);
|
||||||
let content = ThemeChooser::create_content(initial, select);
|
let content = Self::create_content(initial, select);
|
||||||
let inner = ViewBox::boxed(content);
|
let inner = ViewBox::boxed(content);
|
||||||
ThemeChooser { inner }
|
ThemeChooser { inner }
|
||||||
}
|
}
|
||||||
@ -136,16 +136,16 @@ impl ThemeChooser {
|
|||||||
where F: 'static + Fn(&mut Cursive, &Base16Scheme)
|
where F: 'static + Fn(&mut Cursive, &Base16Scheme)
|
||||||
{
|
{
|
||||||
let mut tree = TreeView::new()
|
let mut tree = TreeView::new()
|
||||||
.on_select(ThemeChooser::on_tree_select)
|
.on_select(Self::on_tree_select)
|
||||||
.on_collapse(ThemeChooser::on_tree_collapse)
|
.on_collapse(Self::on_tree_collapse)
|
||||||
.on_submit(move |s,idx| {
|
.on_submit(move |s,idx| {
|
||||||
let item = ThemeChooser::call_on_tree(s, |v| v.borrow_item(idx).cloned());
|
let item = Self::call_on_tree(s, |v| v.borrow_item(idx).cloned());
|
||||||
if let Some(TreeItem::ColorScheme(ref scheme)) = item {
|
if let Some(TreeItem::ColorScheme(ref scheme)) = item {
|
||||||
(cb)(s, scheme);
|
(cb)(s, scheme);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ThemeChooser::populate_tree(initial, &mut tree);
|
Self::populate_tree(initial, &mut tree);
|
||||||
tree.with_id("theme-tree")
|
tree.with_id("theme-tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ impl ThemeChooser {
|
|||||||
let mut category_rows = HashMap::new();
|
let mut category_rows = HashMap::new();
|
||||||
let mut last_row = 0;
|
let mut last_row = 0;
|
||||||
for scheme in &schemes {
|
for scheme in &schemes {
|
||||||
last_row = ThemeChooser::add_scheme_to_tree(initial.as_ref(), tree, last_row, scheme, &mut category_rows);
|
last_row = Self::add_scheme_to_tree(initial.as_ref(), tree, last_row, scheme, &mut category_rows);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ impl ThemeChooser {
|
|||||||
|
|
||||||
if let Some(category) = scheme.category() {
|
if let Some(category) = scheme.category() {
|
||||||
let is_initial_category = initial.map(|sc| sc.category() == scheme.category()).unwrap_or(false);
|
let is_initial_category = initial.map(|sc| sc.category() == scheme.category()).unwrap_or(false);
|
||||||
let category_row = ThemeChooser::get_category_row(!is_initial_category, tree, &mut last_row, category, category_rows);
|
let category_row = Self::get_category_row(!is_initial_category, tree, &mut last_row, category, category_rows);
|
||||||
if let Some(new_row) = tree.insert_item(item, Placement::LastChild, category_row) {
|
if let Some(new_row) = tree.insert_item(item, Placement::LastChild, category_row) {
|
||||||
if is_initial {
|
if is_initial {
|
||||||
tree.set_selected_row(new_row);
|
tree.set_selected_row(new_row);
|
||||||
@ -198,7 +198,7 @@ impl ThemeChooser {
|
|||||||
|
|
||||||
|
|
||||||
fn on_tree_select(s: &mut Cursive, idx: usize) {
|
fn on_tree_select(s: &mut Cursive, idx: usize) {
|
||||||
let selected = ThemeChooser::call_on_tree(s, |v| v.borrow_item(idx).cloned());
|
let selected = Self::call_on_tree(s, |v| v.borrow_item(idx).cloned());
|
||||||
|
|
||||||
if let Some(item) = selected {
|
if let Some(item) = selected {
|
||||||
if let TreeItem::ColorScheme(scheme) = item {
|
if let TreeItem::ColorScheme(scheme) = item {
|
||||||
@ -208,9 +208,9 @@ impl ThemeChooser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_tree_collapse(s: &mut Cursive, row: usize, is_collapsed: bool, _: usize) {
|
fn on_tree_collapse(s: &mut Cursive, row: usize, is_collapsed: bool, _: usize) {
|
||||||
ThemeChooser::call_on_tree(s, |v| {
|
Self::call_on_tree(s, |v| {
|
||||||
if let Some(item) = v.borrow_item_mut(row) {
|
if let Some(item) = v.borrow_item_mut(row) {
|
||||||
if let &mut TreeItem::Category(ref _name, ref mut collapsed) = item {
|
if let TreeItem::Category(ref _name, ref mut collapsed) = *item {
|
||||||
*collapsed = is_collapsed;
|
*collapsed = is_collapsed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,9 +227,9 @@ impl ThemeChooser {
|
|||||||
|
|
||||||
fn toggle_expand_item(&self) -> EventResult {
|
fn toggle_expand_item(&self) -> EventResult {
|
||||||
EventResult::with_cb(|s| {
|
EventResult::with_cb(|s| {
|
||||||
ThemeChooser::call_on_tree(s, |v| {
|
Self::call_on_tree(s, |v| {
|
||||||
if let Some(row) = v.row() {
|
if let Some(row) = v.row() {
|
||||||
ThemeChooser::toggle_item_collapsed(v, row);
|
Self::toggle_item_collapsed(v, row);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -570,7 +570,7 @@ impl<T: Display + Debug + 'static> View for TreeView<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn important_area(&self, size: Vec2) -> Rect {
|
fn important_area(&self, size: Vec2) -> Rect {
|
||||||
self.row().map(|i| Rect::from_size((0,i), (size.x, 1))).unwrap_or(Rect::from((0,0)))
|
self.row().map(|i| Rect::from_size((0,i), (size.x, 1))).unwrap_or_else(|| Rect::from((0,0)))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,8 @@ pub fn main(args: Vec<String>) {
|
|||||||
Logger::set_log_level(LogLevel::Info);
|
Logger::set_log_level(LogLevel::Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
let command = args.iter().skip(1).next();
|
|
||||||
|
|
||||||
let result = match command {
|
let result = match args.get(1) {
|
||||||
Some(s) if s == "rootfs" => do_rootfs(),
|
Some(s) if s == "rootfs" => do_rootfs(),
|
||||||
Some(s) if s == "setup" => do_setup(),
|
Some(s) if s == "setup" => do_setup(),
|
||||||
Some(s) if s == "start-realms" => do_start_realms(),
|
Some(s) if s == "start-realms" => do_start_realms(),
|
||||||
@ -48,10 +47,8 @@ fn setup_keyring() -> Result<()> {
|
|||||||
fn do_setup() -> Result<()> {
|
fn do_setup() -> Result<()> {
|
||||||
if CommandLine::live_mode() || CommandLine::install_mode() {
|
if CommandLine::live_mode() || CommandLine::install_mode() {
|
||||||
live::live_setup()?;
|
live::live_setup()?;
|
||||||
} else {
|
} else if let Err(err) = setup_keyring() {
|
||||||
if let Err(err) = setup_keyring() {
|
warn!("Failed to setup keyring: {}", err);
|
||||||
warn!("Failed to setup keyring: {}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceImage::mount_image_type("kernel")?;
|
ResourceImage::mount_image_type("kernel")?;
|
||||||
|
@ -89,7 +89,7 @@ fn choose_boot_partiton(scan: bool) -> Result<Partition> {
|
|||||||
for p in partitions {
|
for p in partitions {
|
||||||
best = compare_boot_partitions(best, p);
|
best = compare_boot_partitions(best, p);
|
||||||
}
|
}
|
||||||
best.ok_or(format_err!("No partition found to boot from"))
|
best.ok_or_else(|| format_err!("No partition found to boot from"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_boot_partitions(a: Option<Partition>, b: Partition) -> Option<Partition> {
|
fn compare_boot_partitions(a: Option<Partition>, b: Partition) -> Option<Partition> {
|
||||||
|
@ -91,8 +91,8 @@ fn choose_disk() -> Result<Option<Disk>> {
|
|||||||
|
|
||||||
fn prompt_choose_disk(disks: &[Disk]) -> Result<()> {
|
fn prompt_choose_disk(disks: &[Disk]) -> Result<()> {
|
||||||
println!("Available disks:\n");
|
println!("Available disks:\n");
|
||||||
for idx in 0..disks.len() {
|
for (idx,disk) in disks.iter().enumerate() {
|
||||||
println!(" [{}]: {} Size: {} Model: {}", idx + 1, disks[idx].path().display(), disks[idx].size_str(), disks[idx].model());
|
println!(" [{}]: {} Size: {} Model: {}", idx + 1, disk.path().display(), disk.size_str(), disk.model());
|
||||||
}
|
}
|
||||||
print!("\nChoose a disk to install to (q to quit): ");
|
print!("\nChoose a disk to install to (q to quit): ");
|
||||||
io::stdout().flush()?;
|
io::stdout().flush()?;
|
||||||
|
@ -490,7 +490,7 @@ impl Installer {
|
|||||||
|
|
||||||
fn kernel_imagename(&self) -> String {
|
fn kernel_imagename(&self) -> String {
|
||||||
let utsname = UtsName::uname();
|
let utsname = UtsName::uname();
|
||||||
let v = utsname.release().split("-").collect::<Vec<_>>();
|
let v = utsname.release().split('-').collect::<Vec<_>>();
|
||||||
format!("citadel-kernel-{}.img", v[0])
|
format!("citadel-kernel-{}.img", v[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch_command(args: Vec<String>) {
|
fn dispatch_command(args: Vec<String>) {
|
||||||
if let Some(command) = args.iter().skip(1).next() {
|
if let Some(command) = args.get(1) {
|
||||||
match command.as_str() {
|
match command.as_str() {
|
||||||
"boot" => boot::main(rebuild_args("citadel-boot", args)),
|
"boot" => boot::main(rebuild_args("citadel-boot", args)),
|
||||||
"install" => install::main(rebuild_args("citadel-install", args)),
|
"install" => install::main(rebuild_args("citadel-install", args)),
|
||||||
|
@ -8,7 +8,7 @@ mod build;
|
|||||||
|
|
||||||
pub fn main(args: Vec<String>) {
|
pub fn main(args: Vec<String>) {
|
||||||
|
|
||||||
let config_path = match args.iter().skip(1).next() {
|
let config_path = match args.get(1) {
|
||||||
Some(arg) => arg,
|
Some(arg) => arg,
|
||||||
None => {
|
None => {
|
||||||
println!("Expected config file argument");
|
println!("Expected config file argument");
|
||||||
|
@ -124,7 +124,7 @@ fn image_info(arg_matches: &ArgMatches) -> Result<()> {
|
|||||||
fn parse_resize_size(s: &str) -> Result<ResizeSize> {
|
fn parse_resize_size(s: &str) -> Result<ResizeSize> {
|
||||||
let unit = s.chars().last().filter(|c| c.is_alphabetic());
|
let unit = s.chars().last().filter(|c| c.is_alphabetic());
|
||||||
|
|
||||||
let skip = if s.starts_with("+") { 1 } else { 0 };
|
let skip = if s.starts_with('+') { 1 } else { 0 };
|
||||||
let size = s.chars()
|
let size = s.chars()
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
.take_while(|c| c.is_numeric())
|
.take_while(|c| c.is_numeric())
|
||||||
@ -149,7 +149,7 @@ fn resize(arg_matches: &ArgMatches) -> Result<()> {
|
|||||||
|
|
||||||
};
|
};
|
||||||
info!("Size is {}", size_arg);
|
info!("Size is {}", size_arg);
|
||||||
let mode_add = size_arg.starts_with("+");
|
let mode_add = size_arg.starts_with('+');
|
||||||
let size = parse_resize_size(size_arg)?;
|
let size = parse_resize_size(size_arg)?;
|
||||||
|
|
||||||
if mode_add {
|
if mode_add {
|
||||||
|
@ -129,7 +129,7 @@ impl DesktopFile {
|
|||||||
pub fn add_action_line(&mut self, action: &str, line: Line) {
|
pub fn add_action_line(&mut self, action: &str, line: Line) {
|
||||||
if line.is_key_value_type() {
|
if line.is_key_value_type() {
|
||||||
let idx = self.lines.len();
|
let idx = self.lines.len();
|
||||||
let map = self.groups.entry(action.to_string()).or_insert(HashMap::new());
|
let map = self.groups.entry(action.to_string()).or_insert_with(HashMap::new);
|
||||||
map.insert(line.get_key_string(), idx);
|
map.insert(line.get_key_string(), idx);
|
||||||
}
|
}
|
||||||
self.lines.push(line);
|
self.lines.push(line);
|
||||||
|
@ -38,7 +38,7 @@ impl IconCache {
|
|||||||
key.bytes().fold(0u32, |h, b|
|
key.bytes().fold(0u32, |h, b|
|
||||||
(h << 5)
|
(h << 5)
|
||||||
.wrapping_sub(h)
|
.wrapping_sub(h)
|
||||||
.wrapping_add(b as u32))
|
.wrapping_add(u32::from(b)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_string(&self, offset: usize) -> Result<String> {
|
fn read_string(&self, offset: usize) -> Result<String> {
|
||||||
|
@ -80,10 +80,8 @@ impl IconSync {
|
|||||||
for entry in fs::read_dir(&base)? {
|
for entry in fs::read_dir(&base)? {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
let apps = entry.path().join("apps");
|
let apps = entry.path().join("apps");
|
||||||
if apps.exists() {
|
if apps.exists() && self.search_subdirectory(&base, &apps, icon_name)? {
|
||||||
if self.search_subdirectory(&base, &apps, icon_name)? {
|
found = true;
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found {
|
if found {
|
||||||
|
@ -2,11 +2,11 @@ use libcitadel::{Result, Logger, LogLevel};
|
|||||||
|
|
||||||
mod desktop_file;
|
mod desktop_file;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod sync;
|
mod desktop_sync;
|
||||||
mod icons;
|
mod icons;
|
||||||
mod icon_cache;
|
mod icon_cache;
|
||||||
|
|
||||||
use self::sync::DesktopFileSync;
|
use self::desktop_sync::DesktopFileSync;
|
||||||
|
|
||||||
pub fn main(args: Vec<String>) {
|
pub fn main(args: Vec<String>) {
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ impl DesktopFileParser {
|
|||||||
|
|
||||||
if let Line::KeyValue(ref k, ref value) = line {
|
if let Line::KeyValue(ref k, ref value) = line {
|
||||||
if k == "Actions" {
|
if k == "Actions" {
|
||||||
for s in value.split_terminator(";") {
|
for s in value.split_terminator(';') {
|
||||||
self.known_actions.insert(s.trim().to_string());
|
self.known_actions.insert(s.trim().to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ impl DesktopFileParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DESKTOP_ACTION: &'static str = "Desktop Action ";
|
const DESKTOP_ACTION: &str = "Desktop Action ";
|
||||||
|
|
||||||
struct LineParser<'a> {
|
struct LineParser<'a> {
|
||||||
s: &'a str,
|
s: &'a str,
|
||||||
@ -202,17 +202,17 @@ impl <'a> LineParser<'a> {
|
|||||||
} else if content == "Desktop Entry" {
|
} else if content == "Desktop Entry" {
|
||||||
return Some(Line::DesktopHeader)
|
return Some(Line::DesktopHeader)
|
||||||
}
|
}
|
||||||
return Some(Line::GroupHeader(content.to_string()))
|
Some(Line::GroupHeader(content.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_keyval(&self) -> Option<Line> {
|
fn parse_keyval(&self) -> Option<Line> {
|
||||||
let parts: Vec<&str> = self.s.splitn(2, "=").collect();
|
let parts: Vec<&str> = self.s.splitn(2, '=').collect();
|
||||||
if parts.len() != 2 {
|
if parts.len() != 2 {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
let key = parts[0].trim();
|
let key = parts[0].trim();
|
||||||
let val = parts[1].trim();
|
let val = parts[1].trim();
|
||||||
if !key.contains("[") {
|
if !key.contains('[') {
|
||||||
if key == "Exec" {
|
if key == "Exec" {
|
||||||
return Some(Line::ExecLine(val.to_string()))
|
return Some(Line::ExecLine(val.to_string()))
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ impl <'a> LineParser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_locale(&self, key: &str) -> Option<(String,String)> {
|
fn parse_locale(&self, key: &str) -> Option<(String,String)> {
|
||||||
let idx = key.find("[").unwrap();
|
let idx = key.find('[').unwrap();
|
||||||
let (k,loc) = key.split_at(idx);
|
let (k,loc) = key.split_at(idx);
|
||||||
let mut chars = loc.chars();
|
let mut chars = loc.chars();
|
||||||
if let Some(']') = chars.next_back() {
|
if let Some(']') = chars.next_back() {
|
||||||
|
@ -38,40 +38,40 @@ impl CommandLine {
|
|||||||
|
|
||||||
/// Return `true` if variable citadel.noverity is present on kernel command line.
|
/// Return `true` if variable citadel.noverity is present on kernel command line.
|
||||||
pub fn noverity() -> bool {
|
pub fn noverity() -> bool {
|
||||||
CommandLine::var_exists("citadel.noverity")
|
Self::var_exists("citadel.noverity")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nosignatures() -> bool {
|
pub fn nosignatures() -> bool {
|
||||||
CommandLine::var_exists("citadel.nosignatures")
|
Self::var_exists("citadel.nosignatures")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if variable citadel.install is present on kernel command line.
|
/// Return `true` if variable citadel.install is present on kernel command line.
|
||||||
pub fn install_mode() -> bool {
|
pub fn install_mode() -> bool {
|
||||||
CommandLine::var_exists("citadel.install")
|
Self::var_exists("citadel.install")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if variable citadel.live is present on kernel command line.
|
/// Return `true` if variable citadel.live is present on kernel command line.
|
||||||
pub fn live_mode() -> bool {
|
pub fn live_mode() -> bool {
|
||||||
CommandLine::var_exists("citadel.live")
|
Self::var_exists("citadel.live")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if variable citadel.recovery is present on kernel command line.
|
/// Return `true` if variable citadel.recovery is present on kernel command line.
|
||||||
pub fn recovery_mode() -> bool {
|
pub fn recovery_mode() -> bool {
|
||||||
CommandLine::var_exists("citadel.recovery")
|
Self::var_exists("citadel.recovery")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn overlay() -> bool { CommandLine::var_exists("citadel.overlay") }
|
pub fn overlay() -> bool { Self::var_exists("citadel.overlay") }
|
||||||
|
|
||||||
/// Return `true` if sealed realmfs images are enabled on kernel command line
|
/// Return `true` if sealed realmfs images are enabled on kernel command line
|
||||||
pub fn sealed() -> bool { CommandLine::var_exists("citadel.sealed") }
|
pub fn sealed() -> bool { Self::var_exists("citadel.sealed") }
|
||||||
|
|
||||||
pub fn channel() -> Option<&'static str> {
|
pub fn channel() -> Option<&'static str> {
|
||||||
CommandLine::get_value("citadel.channel")
|
Self::get_value("citadel.channel")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _channel() -> Option<(&'static str,Option<&'static str>)> {
|
fn _channel() -> Option<(&'static str,Option<&'static str>)> {
|
||||||
if let Some(channel) = CommandLine::channel() {
|
if let Some(channel) = Self::channel() {
|
||||||
let parts = channel.splitn(2, ":").collect::<Vec<_>>();
|
let parts = channel.splitn(2, ':').collect::<Vec<_>>();
|
||||||
if parts.len() == 2 {
|
if parts.len() == 2 {
|
||||||
return Some((parts[0], Some(parts[1])))
|
return Some((parts[0], Some(parts[1])))
|
||||||
}
|
}
|
||||||
@ -82,33 +82,33 @@ impl CommandLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn channel_name() -> Option<&'static str> {
|
pub fn channel_name() -> Option<&'static str> {
|
||||||
if let Some((name, _)) = CommandLine::_channel() {
|
if let Some((name, _)) = Self::_channel() {
|
||||||
return Some(name)
|
return Some(name)
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channel_pubkey() -> Option<&'static str> {
|
pub fn channel_pubkey() -> Option<&'static str> {
|
||||||
if let Some((_, pubkey)) = CommandLine::_channel() {
|
if let Some((_, pubkey)) = Self::_channel() {
|
||||||
return pubkey
|
return pubkey
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verbose() -> bool {
|
pub fn verbose() -> bool {
|
||||||
CommandLine::var_exists("citadel.verbose")
|
Self::var_exists("citadel.verbose")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug() -> bool {
|
pub fn debug() -> bool {
|
||||||
CommandLine::var_exists("citadel.debug")
|
Self::var_exists("citadel.debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn new() -> CommandLine {
|
fn new() -> Self {
|
||||||
CommandLine{ varmap: HashMap::new() }
|
CommandLine{ varmap: HashMap::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load() -> Result<CommandLine> {
|
fn load() -> Result<Self> {
|
||||||
let s = fs::read_to_string("/proc/cmdline")?;
|
let s = fs::read_to_string("/proc/cmdline")?;
|
||||||
let varmap = CommandLineParser::new(s).parse();
|
let varmap = CommandLineParser::new(s).parse();
|
||||||
Ok(CommandLine{varmap})
|
Ok(CommandLine{varmap})
|
||||||
@ -157,7 +157,7 @@ struct CommandLineParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CommandLineParser {
|
impl CommandLineParser {
|
||||||
fn new(cmdline: String) -> CommandLineParser {
|
fn new(cmdline: String) -> Self {
|
||||||
CommandLineParser {
|
CommandLineParser {
|
||||||
cmdline,
|
cmdline,
|
||||||
varmap: HashMap::new(),
|
varmap: HashMap::new(),
|
||||||
|
@ -30,7 +30,7 @@ pub struct Exec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Exec {
|
impl Exec {
|
||||||
pub fn new(cmd: impl AsRef<str>) -> Exec {
|
pub fn new(cmd: impl AsRef<str>) -> Self {
|
||||||
Exec {
|
Exec {
|
||||||
cmd_name: cmd.as_ref().to_string(),
|
cmd_name: cmd.as_ref().to_string(),
|
||||||
cmd: Command::new(cmd.as_ref()),
|
cmd: Command::new(cmd.as_ref()),
|
||||||
@ -55,7 +55,7 @@ impl Exec {
|
|||||||
for line in BufReader::new(result.stderr.as_slice()).lines() {
|
for line in BufReader::new(result.stderr.as_slice()).lines() {
|
||||||
verbose!(" {}", line?);
|
verbose!(" {}", line?);
|
||||||
}
|
}
|
||||||
self.check_cmd_status(&result.status)
|
self.check_cmd_status(result.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ impl Exec {
|
|||||||
self.ensure_command_exists()?;
|
self.ensure_command_exists()?;
|
||||||
self.add_args(args.as_ref());
|
self.add_args(args.as_ref());
|
||||||
let result = self.cmd.stderr(Stdio::inherit()).output()?;
|
let result = self.cmd.stderr(Stdio::inherit()).output()?;
|
||||||
self.check_cmd_status(&result.status)?;
|
self.check_cmd_status(result.status)?;
|
||||||
Ok(String::from_utf8(result.stdout).unwrap().trim().to_owned())
|
Ok(String::from_utf8(result.stdout).unwrap().trim().to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ impl Exec {
|
|||||||
self.cmd.args(args);
|
self.cmd.args(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_cmd_status(&self, status: &ExitStatus) -> Result<()> {
|
fn check_cmd_status(&self, status: ExitStatus) -> Result<()> {
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
match status.code() {
|
match status.code() {
|
||||||
Some(code) => bail!("command {} failed with exit code: {}", self.cmd_name, code),
|
Some(code) => bail!("command {} failed with exit code: {}", self.cmd_name, code),
|
||||||
@ -116,7 +116,7 @@ impl Exec {
|
|||||||
fn ensure_command_exists(&self) -> Result<()> {
|
fn ensure_command_exists(&self) -> Result<()> {
|
||||||
let path = Path::new(&self.cmd_name);
|
let path = Path::new(&self.cmd_name);
|
||||||
if !path.is_absolute() {
|
if !path.is_absolute() {
|
||||||
Exec::search_path(&self.cmd_name)?;
|
Self::search_path(&self.cmd_name)?;
|
||||||
return Ok(())
|
return Ok(())
|
||||||
} else if path.exists() {
|
} else if path.exists() {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
@ -148,13 +148,13 @@ fn ranged_reader<P: AsRef<Path>>(path: P, range: FileRange) -> Result<Box<dyn Re
|
|||||||
let offset = match range {
|
let offset = match range {
|
||||||
FileRange::All => 0,
|
FileRange::All => 0,
|
||||||
FileRange::Offset(n) => n,
|
FileRange::Offset(n) => n,
|
||||||
FileRange::Range {offset, len: _} => offset,
|
FileRange::Range {offset, ..} => offset,
|
||||||
};
|
};
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
f.seek(SeekFrom::Start(offset as u64))?;
|
f.seek(SeekFrom::Start(offset as u64))?;
|
||||||
}
|
}
|
||||||
let r = BufReader::new(f);
|
let r = BufReader::new(f);
|
||||||
if let FileRange::Range {offset: _, len} = range {
|
if let FileRange::Range {len, ..} = range {
|
||||||
Ok(Box::new(r.take(len as u64)))
|
Ok(Box::new(r.take(len as u64)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Box::new(r))
|
Ok(Box::new(r))
|
||||||
|
@ -101,8 +101,8 @@ impl HeaderBytes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_u16(&self, idx: usize) -> u16 {
|
fn read_u16(&self, idx: usize) -> u16 {
|
||||||
let hi = self.read_u8(idx) as u16;
|
let hi = u16::from(self.read_u8(idx));
|
||||||
let lo = self.read_u8(idx + 1) as u16;
|
let lo = u16::from(self.read_u8(idx + 1));
|
||||||
(hi << 8) | lo
|
(hi << 8) | lo
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,11 +152,8 @@ impl ImageHeader {
|
|||||||
/// Size of header block
|
/// Size of header block
|
||||||
pub const HEADER_SIZE: usize = 4096;
|
pub const HEADER_SIZE: usize = 4096;
|
||||||
|
|
||||||
pub fn new() -> ImageHeader {
|
pub fn new() -> Self {
|
||||||
let metainfo = Mutex::new(None);
|
Self::default()
|
||||||
let buffer = HeaderBytes::create_empty();
|
|
||||||
let timestamp = AtomicIsize::new(0);
|
|
||||||
ImageHeader { buffer, metainfo, timestamp }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reload header if file has changed on disk
|
/// Reload header if file has changed on disk
|
||||||
@ -184,14 +181,14 @@ impl ImageHeader {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<ImageHeader> {
|
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let (size,ts) = Self::file_metadata(path)?;
|
let (size,ts) = Self::file_metadata(path)?;
|
||||||
if size < Self::HEADER_SIZE {
|
if size < Self::HEADER_SIZE {
|
||||||
bail!("Cannot load image header because {} has a size of {}", path.display(), size);
|
bail!("Cannot load image header because {} has a size of {}", path.display(), size);
|
||||||
}
|
}
|
||||||
let mut f = File::open(path)?;
|
let mut f = File::open(path)?;
|
||||||
let mut header = ImageHeader::from_reader(&mut f)?;
|
let mut header = Self::from_reader(&mut f)?;
|
||||||
*header.timestamp.get_mut() = ts;
|
*header.timestamp.get_mut() = ts;
|
||||||
Ok(header)
|
Ok(header)
|
||||||
}
|
}
|
||||||
@ -202,14 +199,14 @@ impl ImageHeader {
|
|||||||
Ok((metadata.len() as usize, metadata.mtime() as isize))
|
Ok((metadata.len() as usize, metadata.mtime() as isize))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_reader<R: Read>(r: &mut R) -> Result<ImageHeader> {
|
pub fn from_reader<R: Read>(r: &mut R) -> Result<Self> {
|
||||||
let mut v = vec![0u8; ImageHeader::HEADER_SIZE];
|
let mut v = vec![0u8; Self::HEADER_SIZE];
|
||||||
r.read_exact(&mut v)?;
|
r.read_exact(&mut v)?;
|
||||||
Self::from_slice(&v)
|
Self::from_slice(&v)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_slice(slice: &[u8]) -> Result<ImageHeader> {
|
fn from_slice(slice: &[u8]) -> Result<Self> {
|
||||||
assert_eq!(slice.len(), ImageHeader::HEADER_SIZE);
|
assert_eq!(slice.len(), Self::HEADER_SIZE);
|
||||||
let buffer = HeaderBytes::create_from_slice(slice);
|
let buffer = HeaderBytes::create_from_slice(slice);
|
||||||
let metainfo = Mutex::new(None);
|
let metainfo = Mutex::new(None);
|
||||||
let timestamp = AtomicIsize::new(0);
|
let timestamp = AtomicIsize::new(0);
|
||||||
@ -218,7 +215,7 @@ impl ImageHeader {
|
|||||||
Ok(header)
|
Ok(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_partition<P: AsRef<Path>>(path: P) -> Result<ImageHeader> {
|
pub fn from_partition<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||||
let mut dev = BlockDev::open_ro(path.as_ref())?;
|
let mut dev = BlockDev::open_ro(path.as_ref())?;
|
||||||
let nsectors = dev.nsectors()?;
|
let nsectors = dev.nsectors()?;
|
||||||
ensure!(
|
ensure!(
|
||||||
@ -227,7 +224,7 @@ impl ImageHeader {
|
|||||||
path.as_ref().display(),
|
path.as_ref().display(),
|
||||||
nsectors
|
nsectors
|
||||||
);
|
);
|
||||||
let mut buffer = AlignedBuffer::new(ImageHeader::HEADER_SIZE);
|
let mut buffer = AlignedBuffer::new(Self::HEADER_SIZE);
|
||||||
dev.read_sectors(nsectors - 8, buffer.as_mut())?;
|
dev.read_sectors(nsectors - 8, buffer.as_mut())?;
|
||||||
Self::from_slice(buffer.as_ref())
|
Self::from_slice(buffer.as_ref())
|
||||||
}
|
}
|
||||||
@ -276,7 +273,7 @@ impl ImageHeader {
|
|||||||
let mut lock = self.metainfo.lock().unwrap();
|
let mut lock = self.metainfo.lock().unwrap();
|
||||||
let mb = self.metainfo_bytes();
|
let mb = self.metainfo_bytes();
|
||||||
let metainfo = MetaInfo::parse_bytes(&mb)
|
let metainfo = MetaInfo::parse_bytes(&mb)
|
||||||
.ok_or(format_err!("ImageHeader has invalid metainfo"))?;
|
.ok_or_else(|| format_err!("ImageHeader has invalid metainfo"))?;
|
||||||
*lock = Some(Arc::new(metainfo));
|
*lock = Some(Arc::new(metainfo));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -338,7 +335,7 @@ impl ImageHeader {
|
|||||||
|
|
||||||
pub fn set_metainfo_bytes(&self, bytes: &[u8]) -> Result<()> {
|
pub fn set_metainfo_bytes(&self, bytes: &[u8]) -> Result<()> {
|
||||||
let metainfo = MetaInfo::parse_bytes(bytes)
|
let metainfo = MetaInfo::parse_bytes(bytes)
|
||||||
.ok_or(format_err!("Could not parse metainfo bytes as valid metainfo document"))?;
|
.ok_or_else(|| format_err!("Could not parse metainfo bytes as valid metainfo document"))?;
|
||||||
|
|
||||||
let mut lock = self.metainfo.lock().unwrap();
|
let mut lock = self.metainfo.lock().unwrap();
|
||||||
self.with_bytes_mut(|bs| {
|
self.with_bytes_mut(|bs| {
|
||||||
@ -418,6 +415,14 @@ impl ImageHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for ImageHeader {
|
||||||
|
fn default() -> Self {
|
||||||
|
let metainfo = Mutex::new(None);
|
||||||
|
let buffer = HeaderBytes::create_empty();
|
||||||
|
let timestamp = AtomicIsize::new(0);
|
||||||
|
ImageHeader { buffer, metainfo, timestamp }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Default)]
|
#[derive(Deserialize, Serialize, Clone, Default)]
|
||||||
pub struct MetaInfo {
|
pub struct MetaInfo {
|
||||||
|
@ -29,14 +29,14 @@ pub struct KeyRing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KeyRing {
|
impl KeyRing {
|
||||||
pub fn create_new() -> KeyRing {
|
pub fn create_new() -> Self {
|
||||||
let seed = KeyRing::new_random_seed();
|
let seed = Self::new_random_seed();
|
||||||
let mut keypairs = HashMap::new();
|
let mut keypairs = HashMap::new();
|
||||||
keypairs.insert("realmfs-user".to_string(), hex::encode(&seed.0));
|
keypairs.insert("realmfs-user".to_string(), hex::encode(&seed.0));
|
||||||
KeyRing { keypairs }
|
KeyRing { keypairs }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load<P: AsRef<Path>>(path: P, passphrase: &str) -> Result<KeyRing> {
|
pub fn load<P: AsRef<Path>>(path: P, passphrase: &str) -> Result<Self> {
|
||||||
let mut sbox = SecretBox::new(path.as_ref());
|
let mut sbox = SecretBox::new(path.as_ref());
|
||||||
sbox.read().map_err(|e| format_err!("Error reading keyring file: {}", e))?;
|
sbox.read().map_err(|e| format_err!("Error reading keyring file: {}", e))?;
|
||||||
let mut bytes = sbox.open(passphrase)?;
|
let mut bytes = sbox.open(passphrase)?;
|
||||||
@ -45,13 +45,13 @@ impl KeyRing {
|
|||||||
Ok(keyring)
|
Ok(keyring)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_with_cryptsetup_passphrase<P: AsRef<Path>>(path: P) -> Result<KeyRing> {
|
pub fn load_with_cryptsetup_passphrase<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||||
let passphrase = KeyRing::get_cryptsetup_passphrase()?;
|
let passphrase = Self::get_cryptsetup_passphrase()?;
|
||||||
KeyRing::load(path, &passphrase)
|
Self::load(path, &passphrase)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cryptsetup_passphrase() -> Result<String> {
|
fn get_cryptsetup_passphrase() -> Result<String> {
|
||||||
let key = KeyRing::get_key("cryptsetup")?;
|
let key = Self::get_key("cryptsetup")?;
|
||||||
info!("Got key {}", key.0);
|
info!("Got key {}", key.0);
|
||||||
let buf = key.read()?;
|
let buf = key.read()?;
|
||||||
match buf.split(|b| *b == 0).map(|bs| String::from_utf8_lossy(bs).to_string()).last() {
|
match buf.split(|b| *b == 0).map(|bs| String::from_utf8_lossy(bs).to_string()).last() {
|
||||||
@ -73,7 +73,7 @@ impl KeyRing {
|
|||||||
info!("Found {} key with request_key", name);
|
info!("Found {} key with request_key", name);
|
||||||
return Ok(key);
|
return Ok(key);
|
||||||
}
|
}
|
||||||
return Err(format_err!("kernel key '{}' not found", name))
|
Err(format_err!("kernel key '{}' not found", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_keys_to_kernel(&self) -> Result<()> {
|
pub fn add_keys_to_kernel(&self) -> Result<()> {
|
||||||
@ -81,13 +81,13 @@ impl KeyRing {
|
|||||||
info!("Adding {} to kernel keystore", k.as_str());
|
info!("Adding {} to kernel keystore", k.as_str());
|
||||||
let bytes = hex::decode(v)?;
|
let bytes = hex::decode(v)?;
|
||||||
let key = KernelKey::add_key("user", k.as_str(), &bytes, KEY_SPEC_USER_KEYRING)?;
|
let key = KernelKey::add_key("user", k.as_str(), &bytes, KEY_SPEC_USER_KEYRING)?;
|
||||||
key.set_perm(0x3f030000)?;
|
key.set_perm(0x3f03_0000)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_kernel_keypair(name: &str) -> Result<KeyPair> {
|
pub fn get_kernel_keypair(name: &str) -> Result<KeyPair> {
|
||||||
let key = KeyRing::get_key(name)?;
|
let key = Self::get_key(name)?;
|
||||||
let data = key.read()?;
|
let data = key.read()?;
|
||||||
KeyPair::from_bytes(&data)
|
KeyPair::from_bytes(&data)
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ struct SecretBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SecretBox {
|
impl SecretBox {
|
||||||
fn new(path: &Path) -> SecretBox {
|
fn new(path: &Path) -> Self {
|
||||||
SecretBox {
|
SecretBox {
|
||||||
path: path.to_path_buf(),
|
path: path.to_path_buf(),
|
||||||
salt: Salt([0; SALTBYTES]),
|
salt: Salt([0; SALTBYTES]),
|
||||||
@ -151,7 +151,7 @@ impl SecretBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn open(&self, passphrase: &str) -> Result<Vec<u8>> {
|
fn open(&self, passphrase: &str) -> Result<Vec<u8>> {
|
||||||
let key = SecretBox::passphrase_to_key(passphrase, &self.salt)?;
|
let key = Self::passphrase_to_key(passphrase, &self.salt)?;
|
||||||
let result = secretbox::open(&self.data, &self.nonce, &key)
|
let result = secretbox::open(&self.data, &self.nonce, &key)
|
||||||
.map_err(|_| format_err!("Failed to decrypt {}", self.path.display()))?;
|
.map_err(|_| format_err!("Failed to decrypt {}", self.path.display()))?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@ -180,31 +180,31 @@ pub struct KernelKey(int32_t);
|
|||||||
|
|
||||||
impl KernelKey {
|
impl KernelKey {
|
||||||
|
|
||||||
pub fn user_keyring() -> KernelKey {
|
pub fn user_keyring() -> Self {
|
||||||
KernelKey(KEY_SPEC_USER_KEYRING)
|
KernelKey(KEY_SPEC_USER_KEYRING)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_key(key_type: &str, description: &str) -> Result<KernelKey> {
|
pub fn request_key(key_type: &str, description: &str) -> Result<Self> {
|
||||||
let key_type = CString::new(key_type).unwrap();
|
let key_type = CString::new(key_type).unwrap();
|
||||||
let description = CString::new(description).unwrap();
|
let description = CString::new(description).unwrap();
|
||||||
let serial = _request_key(key_type.as_ptr(), description.as_ptr())?;
|
let serial = _request_key(key_type.as_ptr(), description.as_ptr())?;
|
||||||
Ok(KernelKey(serial as i32))
|
Ok(KernelKey(serial as i32))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_key(key_type: &str, description: &str, payload: &[u8], ring_id: c_int) -> Result<KernelKey> {
|
pub fn add_key(key_type: &str, description: &str, payload: &[u8], ring_id: c_int) -> Result<Self> {
|
||||||
let key_type = CString::new(key_type).unwrap();
|
let key_type = CString::new(key_type).unwrap();
|
||||||
let description = CString::new(description).unwrap();
|
let description = CString::new(description).unwrap();
|
||||||
let serial = _add_key(key_type.as_ptr(), description.as_ptr(), payload.as_ptr(), payload.len(), ring_id)?;
|
let serial = _add_key(key_type.as_ptr(), description.as_ptr(), payload.as_ptr(), payload.len(), ring_id)?;
|
||||||
Ok(KernelKey(serial as i32))
|
Ok(KernelKey(serial as i32))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_keyring_id(&self, create: bool) -> Result<KernelKey> {
|
pub fn get_keyring_id(&self, create: bool) -> Result<Self> {
|
||||||
let serial = keyctl2(KEYCTL_GET_KEYRING_ID, self.id(), create as u64)?;
|
let serial = keyctl2(KEYCTL_GET_KEYRING_ID, self.id(), create as u64)?;
|
||||||
Ok(KernelKey(serial as i32))
|
Ok(KernelKey(serial as i32))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_perm(&self, perm: u32) -> Result<()> {
|
pub fn set_perm(&self, perm: u32) -> Result<()> {
|
||||||
keyctl2(KEYCTL_SETPERM, self.id(), perm as u64)?;
|
keyctl2(KEYCTL_SETPERM, self.id(), u64::from(perm))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ impl KernelKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search(&self, description: &str) -> Result<KernelKey> {
|
pub fn search(&self, description: &str) -> Result<Self> {
|
||||||
let key_type = CString::new("user").unwrap();
|
let key_type = CString::new("user").unwrap();
|
||||||
let description = CString::new(description).unwrap();
|
let description = CString::new(description).unwrap();
|
||||||
|
|
||||||
|
@ -72,8 +72,8 @@ impl Logger {
|
|||||||
logger.log_message(level, message.as_ref());
|
logger.log_message(level, message.as_ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> Logger {
|
fn new() -> Self {
|
||||||
Logger { level: LogLevel::Notice, output: Box::new(DefaultLogOutput) }
|
Self { level: LogLevel::Notice, output: Box::new(DefaultLogOutput) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log_message(&mut self, level: LogLevel, message: &str) {
|
fn log_message(&mut self, level: LogLevel, message: &str) {
|
||||||
@ -96,11 +96,11 @@ impl Logger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone,Default)]
|
||||||
pub struct DefaultLogOutput;
|
pub struct DefaultLogOutput;
|
||||||
|
|
||||||
impl DefaultLogOutput {
|
impl DefaultLogOutput {
|
||||||
pub fn new() -> Self { DefaultLogOutput }
|
pub fn new() -> Self { DefaultLogOutput::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogOutput for DefaultLogOutput {
|
impl LogOutput for DefaultLogOutput {
|
||||||
|
@ -18,19 +18,19 @@ struct HeaderInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Partition {
|
impl Partition {
|
||||||
pub fn rootfs_partitions() -> Result<Vec<Partition>> {
|
pub fn rootfs_partitions() -> Result<Vec<Self>> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for path in rootfs_partition_paths()? {
|
for path in rootfs_partition_paths()? {
|
||||||
let partition = Partition::load(&path)?;
|
let partition = Self::load(&path)?;
|
||||||
v.push(partition);
|
v.push(partition);
|
||||||
}
|
}
|
||||||
v.sort_unstable_by(|a,b| a.path().cmp(b.path()));
|
v.sort_unstable_by(|a,b| a.path().cmp(b.path()));
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(dev: &Path) -> Result<Partition> {
|
fn load(dev: &Path) -> Result<Self> {
|
||||||
let is_mounted = is_in_use(dev)?;
|
let is_mounted = is_in_use(dev)?;
|
||||||
let header = Partition::load_header(dev)?;
|
let header = Self::load_header(dev)?;
|
||||||
Ok(Partition::new(dev, header, is_mounted))
|
Ok(Partition::new(dev, header, is_mounted))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ impl Partition {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(path: &Path, hinfo: Option<HeaderInfo>, is_mounted: bool) -> Partition {
|
fn new(path: &Path, hinfo: Option<HeaderInfo>, is_mounted: bool) -> Self {
|
||||||
Partition {
|
Partition {
|
||||||
path: path.to_owned(),
|
path: path.to_owned(),
|
||||||
hinfo, is_mounted,
|
hinfo, is_mounted,
|
||||||
|
@ -24,7 +24,7 @@ pub enum OverlayType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OverlayType {
|
impl OverlayType {
|
||||||
pub fn from_str_value(value: &str) -> OverlayType {
|
pub fn from_str_value(value: &str) -> Self {
|
||||||
if value == "tmpfs" {
|
if value == "tmpfs" {
|
||||||
OverlayType::TmpFS
|
OverlayType::TmpFS
|
||||||
} else if value == "storage" {
|
} else if value == "storage" {
|
||||||
@ -35,7 +35,7 @@ impl OverlayType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_str_value(&self) -> Option<&'static str> {
|
pub fn to_str_value(self) -> Option<&'static str> {
|
||||||
match self {
|
match self {
|
||||||
OverlayType::None => None,
|
OverlayType::None => None,
|
||||||
OverlayType::TmpFS => Some("tmpfs"),
|
OverlayType::TmpFS => Some("tmpfs"),
|
||||||
@ -122,25 +122,25 @@ pub struct RealmConfig {
|
|||||||
impl RealmConfig {
|
impl RealmConfig {
|
||||||
|
|
||||||
/// Return an 'unloaded' realm config instance.
|
/// Return an 'unloaded' realm config instance.
|
||||||
pub fn unloaded_realm_config(realm_name: &str) -> RealmConfig {
|
pub fn unloaded_realm_config(realm_name: &str) -> Self {
|
||||||
let path = Path::new(Realms::BASE_PATH)
|
let path = Path::new(Realms::BASE_PATH)
|
||||||
.join(format!("realm-{}", realm_name))
|
.join(format!("realm-{}", realm_name))
|
||||||
.join("config");
|
.join("config");
|
||||||
|
|
||||||
let mut config = RealmConfig::empty();
|
let mut config = Self::empty();
|
||||||
config.path = path;
|
config.path = path;
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_global_config() -> RealmConfig {
|
fn load_global_config() -> Self {
|
||||||
if let Some(mut global) = RealmConfig::load_config("/storage/realms/config") {
|
if let Some(mut global) = Self::load_config("/storage/realms/config") {
|
||||||
global.parent = Some(Box::new(RealmConfig::default()));
|
global.parent = Some(Box::new(Self::default()));
|
||||||
return global;
|
return global;
|
||||||
}
|
}
|
||||||
RealmConfig::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_config<P: AsRef<Path>>(path: P) -> Option<RealmConfig> {
|
fn load_config<P: AsRef<Path>>(path: P) -> Option<Self> {
|
||||||
if path.as_ref().exists() {
|
if path.as_ref().exists() {
|
||||||
match fs::read_to_string(path.as_ref()) {
|
match fs::read_to_string(path.as_ref()) {
|
||||||
Ok(s) => return toml::from_str::<RealmConfig>(&s).ok(),
|
Ok(s) => return toml::from_str::<RealmConfig>(&s).ok(),
|
||||||
@ -177,7 +177,7 @@ impl RealmConfig {
|
|||||||
let s = fs::read_to_string(&self.path)?;
|
let s = fs::read_to_string(&self.path)?;
|
||||||
*self = toml::from_str(&s)?;
|
*self = toml::from_str(&s)?;
|
||||||
} else {
|
} else {
|
||||||
*self = RealmConfig::empty();
|
*self = Self::empty();
|
||||||
}
|
}
|
||||||
self.path = path;
|
self.path = path;
|
||||||
self.loaded = Some(self.read_mtime());
|
self.loaded = Some(self.read_mtime());
|
||||||
@ -185,7 +185,7 @@ impl RealmConfig {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default() -> RealmConfig {
|
pub fn default() -> Self {
|
||||||
RealmConfig {
|
RealmConfig {
|
||||||
use_shared_dir: Some(true),
|
use_shared_dir: Some(true),
|
||||||
use_ephemeral_home: Some(false),
|
use_ephemeral_home: Some(false),
|
||||||
@ -215,7 +215,7 @@ impl RealmConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> RealmConfig {
|
pub fn empty() -> Self {
|
||||||
RealmConfig {
|
RealmConfig {
|
||||||
use_shared_dir: None,
|
use_shared_dir: None,
|
||||||
use_ephemeral_home: None,
|
use_ephemeral_home: None,
|
||||||
@ -394,8 +394,7 @@ impl RealmConfig {
|
|||||||
/// The type of overlay on root filesystem to set up for this realm.
|
/// The type of overlay on root filesystem to set up for this realm.
|
||||||
pub fn overlay(&self) -> OverlayType {
|
pub fn overlay(&self) -> OverlayType {
|
||||||
self.str_value(|c| c.overlay.as_ref())
|
self.str_value(|c| c.overlay.as_ref())
|
||||||
.map(OverlayType::from_str_value)
|
.map_or(OverlayType::None, OverlayType::from_str_value)
|
||||||
.unwrap_or(OverlayType::None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the overlay string variable according to the `OverlayType` argument.
|
/// Set the overlay string variable according to the `OverlayType` argument.
|
||||||
|
@ -7,6 +7,7 @@ use std::thread::{self,JoinHandle};
|
|||||||
use std::path;
|
use std::path;
|
||||||
|
|
||||||
use crate::{RealmManager, Result, Realm};
|
use crate::{RealmManager, Result, Realm};
|
||||||
|
use super::realms::HasCurrentChanged;
|
||||||
use dbus::{Connection, BusType, ConnectionItem, Message, Path};
|
use dbus::{Connection, BusType, ConnectionItem, Message, Path};
|
||||||
use inotify::{Inotify, WatchMask, WatchDescriptor, Event};
|
use inotify::{Inotify, WatchMask, WatchDescriptor, Event};
|
||||||
|
|
||||||
@ -54,8 +55,8 @@ impl Inner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_manager(&mut self, manager: Arc<RealmManager>) {
|
fn set_manager(&mut self, manager: &Arc<RealmManager>) {
|
||||||
self.manager = Arc::downgrade(&manager);
|
self.manager = Arc::downgrade(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_handler<F>(&mut self, handler: F)
|
pub fn add_handler<F>(&mut self, handler: F)
|
||||||
@ -96,7 +97,7 @@ impl RealmEventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_manager(&self, manager: Arc<RealmManager>) {
|
pub fn set_manager(&self, manager: &Arc<RealmManager>) {
|
||||||
self.inner_mut().set_manager(manager);
|
self.inner_mut().set_manager(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +243,7 @@ impl DbusEventListener {
|
|||||||
fn handle_signal(&self, message: Message) -> Result<()> {
|
fn handle_signal(&self, message: Message) -> Result<()> {
|
||||||
|
|
||||||
let member = message.member()
|
let member = message.member()
|
||||||
.ok_or(format_err!("invalid signal"))?;
|
.ok_or_else(|| format_err!("invalid signal"))?;
|
||||||
let (name, _path): (String, Path) = message.read2()?;
|
let (name, _path): (String, Path) = message.read2()?;
|
||||||
if let (Some(interface),Some(member)) = (message.interface(),message.member()) {
|
if let (Some(interface),Some(member)) = (message.interface(),message.member()) {
|
||||||
verbose!("DBUS: {}:[{}({})]", interface, member,name);
|
verbose!("DBUS: {}:[{}({})]", interface, member,name);
|
||||||
@ -343,7 +344,7 @@ impl InotifyEventListener {
|
|||||||
|
|
||||||
fn handle_current_event(&self) {
|
fn handle_current_event(&self) {
|
||||||
self.inner().with_manager(|m| {
|
self.inner().with_manager(|m| {
|
||||||
if let Some(current) = m.has_current_changed() {
|
if let HasCurrentChanged::Changed(current) = m.has_current_changed() {
|
||||||
self.inner().send_event(RealmEvent::Current(current));
|
self.inner().send_event(RealmEvent::Current(current));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -9,6 +9,7 @@ use crate::realmfs::realmfs_set::RealmFSSet;
|
|||||||
use super::systemd::Systemd;
|
use super::systemd::Systemd;
|
||||||
use super::network::NetworkConfig;
|
use super::network::NetworkConfig;
|
||||||
use super::events::{RealmEventListener, RealmEvent};
|
use super::events::{RealmEventListener, RealmEvent};
|
||||||
|
use crate::realm::realms::HasCurrentChanged;
|
||||||
|
|
||||||
pub struct RealmManager {
|
pub struct RealmManager {
|
||||||
inner: RwLock<Inner>,
|
inner: RwLock<Inner>,
|
||||||
@ -38,25 +39,25 @@ impl RealmManager {
|
|||||||
Ok(network)
|
Ok(network)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Result<Arc<RealmManager>> {
|
pub fn load() -> Result<Arc<Self>> {
|
||||||
let inner = Inner::new()?;
|
let inner = Inner::new()?;
|
||||||
let inner = RwLock::new(inner);
|
let inner = RwLock::new(inner);
|
||||||
|
|
||||||
let network = RealmManager::create_network_config()?;
|
let network = Self::create_network_config()?;
|
||||||
let systemd = Systemd::new(network);
|
let systemd = Systemd::new(network);
|
||||||
|
|
||||||
let manager = RealmManager{ inner, systemd };
|
let manager = RealmManager{ inner, systemd };
|
||||||
let manager = Arc::new(manager);
|
let manager = Arc::new(manager);
|
||||||
|
|
||||||
manager.set_manager(manager.clone());
|
manager.set_manager(&manager);
|
||||||
|
|
||||||
Ok(manager)
|
Ok(manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_manager(&self, manager: Arc<RealmManager>) {
|
fn set_manager(&self, manager: &Arc<RealmManager>) {
|
||||||
let mut inner = self.inner_mut();
|
let mut inner = self.inner_mut();
|
||||||
inner.events.set_manager(manager.clone());
|
inner.events.set_manager(manager);
|
||||||
inner.realms.set_manager(manager.clone());
|
inner.realms.set_manager(manager);
|
||||||
inner.realmfs_set.set_manager(manager);
|
inner.realmfs_set.set_manager(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ impl RealmManager {
|
|||||||
|
|
||||||
pub fn run_in_current<S: AsRef<str>>(args: &[S], use_launcher: bool) -> Result<()> {
|
pub fn run_in_current<S: AsRef<str>>(args: &[S], use_launcher: bool) -> Result<()> {
|
||||||
let realm = Realms::load_current_realm()
|
let realm = Realms::load_current_realm()
|
||||||
.ok_or(format_err!("Could not find current realm"))?;
|
.ok_or_else(|| format_err!("Could not find current realm"))?;
|
||||||
|
|
||||||
if !realm.is_active() {
|
if !realm.is_active() {
|
||||||
bail!("Current realm {} is not active?", realm.name());
|
bail!("Current realm {} is not active?", realm.name());
|
||||||
@ -130,8 +131,7 @@ impl RealmManager {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| {
|
.filter(|r| {
|
||||||
r.realmfs_mountpoint()
|
r.realmfs_mountpoint()
|
||||||
.map(|mp| activation.is_mountpoint(&mp))
|
.map_or(false, |mp| activation.is_mountpoint(&mp))
|
||||||
.unwrap_or(false)
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ impl RealmManager {
|
|||||||
|
|
||||||
/// Notify `RealmManager` that `mountpoint` has been released by a
|
/// Notify `RealmManager` that `mountpoint` has been released by a
|
||||||
/// `Realm`.
|
/// `Realm`.
|
||||||
pub fn release_mountpoint(&self, mountpoint: Mountpoint) {
|
pub fn release_mountpoint(&self, mountpoint: &Mountpoint) {
|
||||||
info!("releasing mountpoint: {}", mountpoint);
|
info!("releasing mountpoint: {}", mountpoint);
|
||||||
if !mountpoint.is_valid() {
|
if !mountpoint.is_valid() {
|
||||||
warn!("bad mountpoint {} passed to release_mountpoint()", mountpoint);
|
warn!("bad mountpoint {} passed to release_mountpoint()", mountpoint);
|
||||||
@ -158,12 +158,12 @@ impl RealmManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(realmfs) = self.realmfs_by_name(mountpoint.realmfs()) {
|
if let Some(realmfs) = self.realmfs_by_name(mountpoint.realmfs()) {
|
||||||
if realmfs.release_mountpoint(&mountpoint) {
|
if realmfs.release_mountpoint(mountpoint) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(activation) = Activation::for_mountpoint(&mountpoint) {
|
if let Some(activation) = Activation::for_mountpoint(mountpoint) {
|
||||||
let active = self.active_mountpoints();
|
let active = self.active_mountpoints();
|
||||||
if let Err(e) = activation.deactivate(&active) {
|
if let Err(e) = activation.deactivate(&active) {
|
||||||
warn!("error on detached deactivation for {}: {}",activation.device(), e);
|
warn!("error on detached deactivation for {}: {}",activation.device(), e);
|
||||||
@ -308,7 +308,7 @@ impl RealmManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_current_changed(&self) -> Option<Option<Realm>> {
|
pub fn has_current_changed(&self) -> HasCurrentChanged {
|
||||||
self.inner_mut().realms.has_current_changed()
|
self.inner_mut().realms.has_current_changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ pub(crate) mod overlay;
|
|||||||
pub(crate) mod config;
|
pub(crate) mod config;
|
||||||
pub(crate) mod realms;
|
pub(crate) mod realms;
|
||||||
pub(crate) mod manager;
|
pub(crate) mod manager;
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
pub(crate) mod realm;
|
pub(crate) mod realm;
|
||||||
pub (crate) mod network;
|
pub (crate) mod network;
|
||||||
pub(crate) mod create;
|
pub(crate) mod create;
|
||||||
|
@ -111,24 +111,23 @@ impl BridgeAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new(bridge: &str, network: Ipv4Addr, mask_size: usize) -> BridgeAllocator {
|
fn new(bridge: &str, network: Ipv4Addr, mask_size: usize) -> BridgeAllocator {
|
||||||
let allocator = BridgeAllocator {
|
BridgeAllocator {
|
||||||
bridge: bridge.to_owned(),
|
bridge: bridge.to_owned(),
|
||||||
allocated: HashSet::new(),
|
allocated: HashSet::new(),
|
||||||
allocations: HashMap::new(),
|
allocations: HashMap::new(),
|
||||||
network, mask_size,
|
network, mask_size,
|
||||||
};
|
}
|
||||||
allocator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_address_for(&mut self, realm_name: &str) -> Result<String> {
|
pub fn allocate_address_for(&mut self, realm_name: &str) -> Result<String> {
|
||||||
match self.find_free_address() {
|
match self.find_free_address() {
|
||||||
Some(addr) => {
|
Some(addr) => {
|
||||||
self.allocated.insert(addr.clone());
|
self.allocated.insert(addr);
|
||||||
if let Some(old) = self.allocations.insert(realm_name.to_owned(), addr.clone()) {
|
if let Some(old) = self.allocations.insert(realm_name.to_owned(), addr) {
|
||||||
self.allocated.remove(&old);
|
self.allocated.remove(&old);
|
||||||
}
|
}
|
||||||
self.write_state()?;
|
self.write_state()?;
|
||||||
return Ok(format!("{}/{}", addr, self.mask_size));
|
Ok(format!("{}/{}", addr, self.mask_size))
|
||||||
},
|
},
|
||||||
None => bail!("No free IP address could be found to assign to {}", realm_name),
|
None => bail!("No free IP address could be found to assign to {}", realm_name),
|
||||||
}
|
}
|
||||||
@ -136,7 +135,7 @@ impl BridgeAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn store_allocation(&mut self, realm_name: &str, address: Ipv4Addr) -> Result<()> {
|
fn store_allocation(&mut self, realm_name: &str, address: Ipv4Addr) -> Result<()> {
|
||||||
self.allocated.insert(address.clone());
|
self.allocated.insert(address);
|
||||||
if let Some(old) = self.allocations.insert(realm_name.to_string(), address) {
|
if let Some(old) = self.allocations.insert(realm_name.to_string(), address) {
|
||||||
self.allocated.remove(&old);
|
self.allocated.remove(&old);
|
||||||
}
|
}
|
||||||
@ -169,7 +168,7 @@ impl BridgeAllocator {
|
|||||||
if octet < RESERVED_START {
|
if octet < RESERVED_START {
|
||||||
bail!("Not a reserved octet: {}", octet);
|
bail!("Not a reserved octet: {}", octet);
|
||||||
}
|
}
|
||||||
let rsv = u32::from(self.network) | octet as u32;
|
let rsv = u32::from(self.network) | u32::from(octet);
|
||||||
let addr = Ipv4Addr::from(rsv);
|
let addr = Ipv4Addr::from(rsv);
|
||||||
let s = format!("{}/{}", addr, self.mask_size);
|
let s = format!("{}/{}", addr, self.mask_size);
|
||||||
if self.allocated.contains(&addr) {
|
if self.allocated.contains(&addr) {
|
||||||
@ -211,11 +210,11 @@ impl BridgeAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_state_line(&mut self, line: &str) -> Result<()> {
|
fn parse_state_line(&mut self, line: &str) -> Result<()> {
|
||||||
match line.find(":") {
|
match line.find(':') {
|
||||||
Some(idx) => {
|
Some(idx) => {
|
||||||
let (name,addr) = line.split_at(idx);
|
let (name,addr) = line.split_at(idx);
|
||||||
let ip = addr[1..].parse::<Ipv4Addr>()?;
|
let ip = addr[1..].parse::<Ipv4Addr>()?;
|
||||||
self.allocated.insert(ip.clone());
|
self.allocated.insert(ip);
|
||||||
self.allocations.insert(name.to_owned(), ip);
|
self.allocations.insert(name.to_owned(), ip);
|
||||||
},
|
},
|
||||||
None => bail!("Could not parse line from network state file: {}", line),
|
None => bail!("Could not parse line from network state file: {}", line),
|
||||||
|
@ -26,7 +26,7 @@ enum RealmActiveState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RealmActiveState {
|
impl RealmActiveState {
|
||||||
fn from_sysctl_output(line: &str) -> RealmActiveState {
|
fn from_sysctl_output(line: &str) -> Self {
|
||||||
match line {
|
match line {
|
||||||
"active" => RealmActiveState::Active,
|
"active" => RealmActiveState::Active,
|
||||||
"inactive" => RealmActiveState::Inactive,
|
"inactive" => RealmActiveState::Inactive,
|
||||||
@ -247,7 +247,7 @@ impl Realm {
|
|||||||
pub fn cleanup_rootfs(&self) {
|
pub fn cleanup_rootfs(&self) {
|
||||||
RealmOverlay::remove_any_overlay(self);
|
RealmOverlay::remove_any_overlay(self);
|
||||||
|
|
||||||
if let Some(mountpoint) = self.realmfs_mountpoint() {
|
if let Some(ref mountpoint) = self.realmfs_mountpoint() {
|
||||||
self.manager().release_mountpoint(mountpoint);
|
self.manager().release_mountpoint(mountpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ impl RealmMapList {
|
|||||||
RealmMapList { manager, map, list }
|
RealmMapList { manager, map, list }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_manager(&mut self, manager: Arc<RealmManager>) {
|
fn set_manager(&mut self, manager: &Arc<RealmManager>) {
|
||||||
self.manager = Arc::downgrade(&manager);
|
self.manager = Arc::downgrade(manager);
|
||||||
self.list.iter_mut().for_each(|r| r.set_manager(manager.clone()));
|
self.list.iter_mut().for_each(|r| r.set_manager(manager.clone()));
|
||||||
self.map.iter_mut().for_each(|(_,r)| r.set_manager(manager.clone()));
|
self.map.iter_mut().for_each(|(_,r)| r.set_manager(manager.clone()));
|
||||||
}
|
}
|
||||||
@ -55,6 +55,11 @@ impl RealmMapList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum HasCurrentChanged {
|
||||||
|
Changed(Option<Realm>),
|
||||||
|
NotChanged,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Realms {
|
pub struct Realms {
|
||||||
manager: Weak<RealmManager>,
|
manager: Weak<RealmManager>,
|
||||||
realms: RealmMapList,
|
realms: RealmMapList,
|
||||||
@ -84,7 +89,8 @@ impl Realms {
|
|||||||
fn all_realms(mark_active: bool) -> Result<Vec<Realm>> {
|
fn all_realms(mark_active: bool) -> Result<Vec<Realm>> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for entry in fs::read_dir(Realms::BASE_PATH)? {
|
for entry in fs::read_dir(Realms::BASE_PATH)? {
|
||||||
if let Some(realm) = Realms::entry_to_realm(entry?) {
|
let entry = entry?;
|
||||||
|
if let Some(realm) = Realms::entry_to_realm(&entry) {
|
||||||
v.push(realm);
|
v.push(realm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,14 +100,14 @@ impl Realms {
|
|||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_manager(&mut self, manager: Arc<RealmManager>) {
|
pub fn set_manager(&mut self, manager: &Arc<RealmManager>) {
|
||||||
self.manager = Arc::downgrade(&manager);
|
self.manager = Arc::downgrade(manager);
|
||||||
self.realms.set_manager(manager);
|
self.realms.set_manager(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Examine a directory entry and if it looks like a legit realm directory
|
// Examine a directory entry and if it looks like a legit realm directory
|
||||||
// extract realm name and return a `Realm` instance.
|
// extract realm name and return a `Realm` instance.
|
||||||
fn entry_to_realm(entry: fs::DirEntry) -> Option<Realm> {
|
fn entry_to_realm(entry: &fs::DirEntry) -> Option<Realm> {
|
||||||
match entry.path().symlink_metadata() {
|
match entry.path().symlink_metadata() {
|
||||||
Ok(ref meta) if meta.is_dir() => {},
|
Ok(ref meta) if meta.is_dir() => {},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
@ -215,7 +221,7 @@ impl Realms {
|
|||||||
// or when adding or removing a realm directory.
|
// or when adding or removing a realm directory.
|
||||||
//
|
//
|
||||||
fn realmslock() -> Result<FileLock> {
|
fn realmslock() -> Result<FileLock> {
|
||||||
let lockpath = Path::new(Realms::BASE_PATH)
|
let lockpath = Path::new(Self::BASE_PATH)
|
||||||
.join(".realmslock");
|
.join(".realmslock");
|
||||||
|
|
||||||
FileLock::acquire(lockpath)
|
FileLock::acquire(lockpath)
|
||||||
@ -263,21 +269,20 @@ impl Realms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_realm_current(&mut self, realm: &Realm) -> Result<()> {
|
pub fn set_realm_current(&mut self, realm: &Realm) -> Result<()> {
|
||||||
symlink::write(realm.run_path(), Realms::current_realm_symlink(), true)?;
|
symlink::write(realm.run_path(), Self::current_realm_symlink(), true)?;
|
||||||
self.last_current = Some(realm.clone());
|
self.last_current = Some(realm.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_realm_default(&self, realm: &Realm) -> Result<()> {
|
pub fn set_realm_default(&self, realm: &Realm) -> Result<()> {
|
||||||
symlink::write(realm.base_path(), Realms::default_symlink(), false)
|
symlink::write(realm.base_path(), Self::default_symlink(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_arbitrary_default(&mut self) -> Result<()> {
|
fn set_arbitrary_default(&mut self) -> Result<()> {
|
||||||
// Prefer a recently used realm and don't choose a system realm
|
// Prefer a recently used realm and don't choose a system realm
|
||||||
let choice = self.sorted()
|
let choice = self.sorted()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| !r.is_system())
|
.find(|r| !r.is_system());
|
||||||
.next();
|
|
||||||
|
|
||||||
if let Some(realm) = choice {
|
if let Some(realm) = choice {
|
||||||
info!("Setting '{}' as new default realm", realm.name());
|
info!("Setting '{}' as new default realm", realm.name());
|
||||||
@ -305,25 +310,23 @@ impl Realms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn current(&mut self) -> Option<Realm> {
|
pub fn current(&mut self) -> Option<Realm> {
|
||||||
let current = Realms::current_realm_name().and_then(|name| self.by_name(&name));
|
let current = Self::current_realm_name().and_then(|name| self.by_name(&name));
|
||||||
self.last_current = current.clone();
|
self.last_current = current.clone();
|
||||||
current
|
current
|
||||||
}
|
}
|
||||||
|
|
||||||
// None : no it's the same
|
pub fn has_current_changed(&mut self) -> HasCurrentChanged {
|
||||||
// Some() : yes and here's the new value
|
|
||||||
pub fn has_current_changed(&mut self) -> Option<Option<Realm>> {
|
|
||||||
let old = self.last_current.clone();
|
let old = self.last_current.clone();
|
||||||
let current = self.current();
|
let current = self.current();
|
||||||
if current == old {
|
if current == old {
|
||||||
None
|
HasCurrentChanged::NotChanged
|
||||||
} else {
|
} else {
|
||||||
Some(current)
|
HasCurrentChanged::Changed(current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default(&self) -> Option<Realm> {
|
pub fn default(&self) -> Option<Realm> {
|
||||||
Realms::default_realm_name().and_then(|name| self.by_name(&name))
|
Self::default_realm_name().and_then(|name| self.by_name(&name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the `Realm` marked as current, or `None` if no realm is current.
|
/// Return the `Realm` marked as current, or `None` if no realm is current.
|
||||||
@ -338,7 +341,7 @@ impl Realms {
|
|||||||
/// If the symlink exists it will point to run path of the current realm.
|
/// If the symlink exists it will point to run path of the current realm.
|
||||||
///
|
///
|
||||||
pub fn load_current_realm() -> Option<Realm> {
|
pub fn load_current_realm() -> Option<Realm> {
|
||||||
Realms::current_realm_name().map(|ref name| Realm::new(name))
|
Self::current_realm_name().map(|ref name| Realm::new(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if some realm has been marked as current.
|
/// Return `true` if some realm has been marked as current.
|
||||||
@ -349,57 +352,57 @@ impl Realms {
|
|||||||
/// /run/citadel/realms/current/current.realm
|
/// /run/citadel/realms/current/current.realm
|
||||||
///
|
///
|
||||||
pub fn is_some_realm_current() -> bool {
|
pub fn is_some_realm_current() -> bool {
|
||||||
Realms::current_realm_symlink().exists()
|
Self::current_realm_symlink().exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set no realm as current by removing the current.realm symlink.
|
/// Set no realm as current by removing the current.realm symlink.
|
||||||
fn clear_current_realm() -> Result<()> {
|
fn clear_current_realm() -> Result<()> {
|
||||||
symlink::remove(Realms::current_realm_symlink())
|
symlink::remove(Self::current_realm_symlink())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set no realm as default by removing the default.realm symlink.
|
/// Set no realm as default by removing the default.realm symlink.
|
||||||
pub fn clear_default_realm() -> Result<()> {
|
pub fn clear_default_realm() -> Result<()> {
|
||||||
symlink::remove(Realms::default_symlink())
|
symlink::remove(Self::default_symlink())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path of 'current.realm' symlink
|
// Path of 'current.realm' symlink
|
||||||
pub fn current_realm_symlink() -> PathBuf {
|
pub fn current_realm_symlink() -> PathBuf {
|
||||||
Path::new(Realms::RUN_PATH)
|
Path::new(Self::RUN_PATH)
|
||||||
.join("current")
|
.join("current")
|
||||||
.join("current.realm")
|
.join("current.realm")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_realm_name() -> Option<String> {
|
pub fn current_realm_name() -> Option<String> {
|
||||||
Realms::read_current_realm_symlink().as_ref().and_then(Realms::path_to_realm_name)
|
Self::read_current_realm_symlink().as_ref().and_then(Self::path_to_realm_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_current_realm_symlink() -> Option<PathBuf> {
|
pub fn read_current_realm_symlink() -> Option<PathBuf> {
|
||||||
symlink::read(Realms::current_realm_symlink())
|
symlink::read(Self::current_realm_symlink())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path of 'default.realm' symlink
|
// Path of 'default.realm' symlink
|
||||||
pub fn default_symlink() -> PathBuf {
|
pub fn default_symlink() -> PathBuf {
|
||||||
Path::new(Realms::BASE_PATH)
|
Path::new(Self::BASE_PATH)
|
||||||
.join("default.realm")
|
.join("default.realm")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_realm_name() -> Option<String> {
|
pub fn default_realm_name() -> Option<String> {
|
||||||
Realms::read_default_symlink().as_ref().and_then(Realms::path_to_realm_name)
|
Self::read_default_symlink().as_ref().and_then(Self::path_to_realm_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_default_symlink() -> Option<PathBuf> {
|
fn read_default_symlink() -> Option<PathBuf> {
|
||||||
symlink::read(Realms::default_symlink())
|
symlink::read(Self::default_symlink())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_to_realm_name(path: impl AsRef<Path>) -> Option<String> {
|
fn path_to_realm_name(path: impl AsRef<Path>) -> Option<String> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
if path.starts_with(Realms::BASE_PATH) {
|
if path.starts_with(Self::BASE_PATH) {
|
||||||
path.strip_prefix(Realms::BASE_PATH).ok()
|
path.strip_prefix(Self::BASE_PATH).ok()
|
||||||
} else if path.starts_with(Realms::RUN_PATH) {
|
} else if path.starts_with(Self::RUN_PATH) {
|
||||||
path.strip_prefix(Realms::RUN_PATH).ok()
|
path.strip_prefix(Self::RUN_PATH).ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}.and_then(Realms::dir_to_realm_name)
|
}.and_then(Self::dir_to_realm_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dir_to_realm_name(dir: &Path) -> Option<String> {
|
fn dir_to_realm_name(dir: &Path) -> Option<String> {
|
||||||
|
@ -6,10 +6,10 @@ use crate::realmfs::mountpoint::Mountpoint;
|
|||||||
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||||
use crate::verity::Verity;
|
use crate::verity::Verity;
|
||||||
|
|
||||||
/// Holds the activation status for a RealmFS and provides a thread-safe
|
/// Holds the activation status for a `RealmFS` and provides a thread-safe
|
||||||
/// interface to it.
|
/// interface to it.
|
||||||
///
|
///
|
||||||
/// If `state` is `None` then the RealmFS is not currently activated.
|
/// If `state` is `None` then the `RealmFS` is not currently activated.
|
||||||
///
|
///
|
||||||
pub struct ActivationState {
|
pub struct ActivationState {
|
||||||
state: RwLock<Option<Arc<Activation>>>,
|
state: RwLock<Option<Arc<Activation>>>,
|
||||||
@ -33,7 +33,7 @@ impl ActivationState {
|
|||||||
let activator = LoopActivator::new(realmfs);
|
let activator = LoopActivator::new(realmfs);
|
||||||
activator.activation()
|
activator.activation()
|
||||||
};
|
};
|
||||||
*self.state_mut() = activation.map(|a| Arc::new(a))
|
*self.state_mut() = activation.map(Arc::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If currently activated return the corresponding `Activation` instance
|
/// If currently activated return the corresponding `Activation` instance
|
||||||
@ -103,10 +103,10 @@ impl ActivationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a RealmFS in an activated state. The activation can be one of:
|
/// Represents a `RealmFS` in an activated state. The activation can be one of:
|
||||||
///
|
///
|
||||||
/// `Activation::Loop` if the RealmFS is unsealed
|
/// `Activation::Loop` if the `RealmFS` is unsealed
|
||||||
/// `Activation::Verity` if the RealmFS is sealed
|
/// `Activation::Verity` if the `RealmFS` is sealed
|
||||||
///
|
///
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Activation {
|
pub enum Activation {
|
||||||
@ -149,12 +149,12 @@ impl Activation {
|
|||||||
if mountpoint.tag() == "rw" || mountpoint.tag() == "ro" {
|
if mountpoint.tag() == "rw" || mountpoint.tag() == "ro" {
|
||||||
LoopDevice::find_mounted_loop(mountpoint.path()).map(|loopdev| {
|
LoopDevice::find_mounted_loop(mountpoint.path()).map(|loopdev| {
|
||||||
let (ro,rw) = Mountpoint::new_loop_pair(mountpoint.realmfs());
|
let (ro,rw) = Mountpoint::new_loop_pair(mountpoint.realmfs());
|
||||||
Activation::new_loop(ro, rw, loopdev)
|
Self::new_loop(ro, rw, loopdev)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let device = Verity::device_name_for_mountpoint(mountpoint);
|
let device = Verity::device_name_for_mountpoint(mountpoint);
|
||||||
if Path::new("/dev/mapper").join(&device).exists() {
|
if Path::new("/dev/mapper").join(&device).exists() {
|
||||||
Some(Activation::new_verity(mountpoint.clone(), device))
|
Some(Self::new_verity(mountpoint.clone(), device))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ mod activator;
|
|||||||
mod mountpoint;
|
mod mountpoint;
|
||||||
mod update;
|
mod update;
|
||||||
pub(crate) mod realmfs_set;
|
pub(crate) mod realmfs_set;
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
mod realmfs;
|
mod realmfs;
|
||||||
|
|
||||||
pub use self::realmfs::RealmFS;
|
pub use self::realmfs::RealmFS;
|
||||||
|
@ -79,7 +79,7 @@ impl Mountpoint {
|
|||||||
fn field(&self, n: usize) -> &str {
|
fn field(&self, n: usize) -> &str {
|
||||||
Self::filename_fields(self.path())
|
Self::filename_fields(self.path())
|
||||||
.and_then(|mut fields| fields.nth(n))
|
.and_then(|mut fields| fields.nth(n))
|
||||||
.expect(&format!("Failed to access field {} of mountpoint {}", n, self))
|
.unwrap_or_else(|| panic!("Failed to access field {} of mountpoint {}", n, self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if this instance is a `&Path` in `RealmFS::RUN_DIRECTORY` and
|
/// Return `true` if this instance is a `&Path` in `RealmFS::RUN_DIRECTORY` and
|
||||||
@ -90,11 +90,11 @@ impl Mountpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn has_valid_extention(&self) -> bool {
|
fn has_valid_extention(&self) -> bool {
|
||||||
self.path().extension().map(|e| e == "mountpoint").unwrap_or(false)
|
self.path().extension().map_or(false, |e| e == "mountpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filename_fields(path: &Path) -> Option<impl Iterator<Item=&str>> {
|
fn filename_fields(path: &Path) -> Option<impl Iterator<Item=&str>> {
|
||||||
Self::filename(path).map(|name| name.split("-"))
|
Self::filename(path).map(|name| name.split('-'))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filename(path: &Path) -> Option<&str> {
|
fn filename(path: &Path) -> Option<&str> {
|
||||||
|
@ -68,24 +68,24 @@ impl RealmFS {
|
|||||||
pub const USER_KEYNAME: &'static str = "realmfs-user";
|
pub const USER_KEYNAME: &'static str = "realmfs-user";
|
||||||
|
|
||||||
/// Locate a RealmFS image by name in the default location using the standard name convention
|
/// Locate a RealmFS image by name in the default location using the standard name convention
|
||||||
pub fn load_by_name(name: &str) -> Result<RealmFS> {
|
pub fn load_by_name(name: &str) -> Result<Self> {
|
||||||
RealmFS::validate_name(name)?;
|
Self::validate_name(name)?;
|
||||||
let path = RealmFS::image_path(name);
|
let path = Self::image_path(name);
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
bail!("No image found at {}", path.display());
|
bail!("No image found at {}", path.display());
|
||||||
}
|
}
|
||||||
|
|
||||||
RealmFS::load_from_path(path)
|
Self::load_from_path(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load RealmFS image from an exact path.
|
/// Load RealmFS image from an exact path.
|
||||||
pub fn load_from_path(path: impl AsRef<Path>) -> Result<RealmFS> {
|
pub fn load_from_path(path: impl AsRef<Path>) -> Result<Self> {
|
||||||
Self::_load_from_path(path.as_ref(), true)
|
Self::_load_from_path(path.as_ref(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _load_from_path(path: &Path, load_activation: bool) -> Result<RealmFS> {
|
fn _load_from_path(path: &Path, load_activation: bool) -> Result<Self> {
|
||||||
let path = Arc::new(path.to_owned());
|
let path = Arc::new(path.to_owned());
|
||||||
let header = RealmFS::load_realmfs_header(&path)?;
|
let header = Self::load_realmfs_header(&path)?;
|
||||||
let name = header.metainfo().realmfs_name()
|
let name = header.metainfo().realmfs_name()
|
||||||
.expect("RealmFS does not have a name")
|
.expect("RealmFS does not have a name")
|
||||||
.to_owned();
|
.to_owned();
|
||||||
@ -130,7 +130,7 @@ impl RealmFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_valid_realmfs_image(path: impl AsRef<Path>) -> bool {
|
pub fn is_valid_realmfs_image(path: impl AsRef<Path>) -> bool {
|
||||||
RealmFS::load_realmfs_header(path.as_ref()).is_ok()
|
Self::load_realmfs_header(path.as_ref()).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_realmfs_header(path: &Path) -> Result<ImageHeader> {
|
fn load_realmfs_header(path: &Path) -> Result<ImageHeader> {
|
||||||
@ -143,7 +143,7 @@ impl RealmFS {
|
|||||||
bail!("Image file {} is not a realmfs image", path.display());
|
bail!("Image file {} is not a realmfs image", path.display());
|
||||||
}
|
}
|
||||||
match metainfo.realmfs_name() {
|
match metainfo.realmfs_name() {
|
||||||
Some(name) => RealmFS::validate_name(name)?,
|
Some(name) => Self::validate_name(name)?,
|
||||||
None => bail!("RealmFS image file {} does not have a 'realmfs-name' field", path.display()),
|
None => bail!("RealmFS image file {} does not have a 'realmfs-name' field", path.display()),
|
||||||
};
|
};
|
||||||
Ok(header)
|
Ok(header)
|
||||||
@ -151,7 +151,7 @@ impl RealmFS {
|
|||||||
|
|
||||||
/// Return an Error result if name is not valid.
|
/// Return an Error result if name is not valid.
|
||||||
fn validate_name(name: &str) -> Result<()> {
|
fn validate_name(name: &str) -> Result<()> {
|
||||||
if RealmFS::is_valid_name(name) {
|
if Self::is_valid_name(name) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(format_err!("Invalid realm name '{}'", name))
|
Err(format_err!("Invalid realm name '{}'", name))
|
||||||
@ -173,11 +173,11 @@ impl RealmFS {
|
|||||||
if !util::is_valid_name(name, MAX_REALMFS_NAME_LEN) {
|
if !util::is_valid_name(name, MAX_REALMFS_NAME_LEN) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
RealmFS::is_valid_realmfs_image(RealmFS::image_path(name))
|
Self::is_valid_realmfs_image(Self::image_path(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn image_path(name: &str) -> PathBuf {
|
fn image_path(name: &str) -> PathBuf {
|
||||||
Path::new(RealmFS::BASE_PATH).join(format!("{}-realmfs.img", name))
|
Path::new(Self::BASE_PATH).join(format!("{}-realmfs.img", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the `Path` to this RealmFS image file.
|
/// Return the `Path` to this RealmFS image file.
|
||||||
@ -284,14 +284,14 @@ impl RealmFS {
|
|||||||
self.activation_state.deactivate(&active)
|
self.activation_state.deactivate(&active)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fork(&self, new_name: &str) -> Result<RealmFS> {
|
pub fn fork(&self, new_name: &str) -> Result<Self> {
|
||||||
self._fork(new_name, true)
|
self._fork(new_name, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an unsealed copy of this RealmFS image with a new image name.
|
/// Create an unsealed copy of this RealmFS image with a new image name.
|
||||||
///
|
///
|
||||||
pub fn fork_unsealed(&self, new_name: &str) -> Result<RealmFS> {
|
pub fn fork_unsealed(&self, new_name: &str) -> Result<Self> {
|
||||||
RealmFS::validate_name(new_name)?;
|
Self::validate_name(new_name)?;
|
||||||
info!("forking RealmFS image '{}' to new name '{}'", self.name(), new_name);
|
info!("forking RealmFS image '{}' to new name '{}'", self.name(), new_name);
|
||||||
|
|
||||||
let new_path = self.path_with_filename(format!("{}-realmfs.img", new_name));
|
let new_path = self.path_with_filename(format!("{}-realmfs.img", new_name));
|
||||||
@ -305,8 +305,8 @@ impl RealmFS {
|
|||||||
Ok(new_realmfs)
|
Ok(new_realmfs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _fork(&self, new_name: &str, sealed_fork: bool) -> Result<RealmFS> {
|
fn _fork(&self, new_name: &str, sealed_fork: bool) -> Result<Self> {
|
||||||
RealmFS::validate_name(new_name)?;
|
Self::validate_name(new_name)?;
|
||||||
info!("forking RealmFS image '{}' to new name '{}'", self.name(), new_name);
|
info!("forking RealmFS image '{}' to new name '{}'", self.name(), new_name);
|
||||||
let new_path = self.path_with_filename(format!("{}-realmfs.img", new_name));
|
let new_path = self.path_with_filename(format!("{}-realmfs.img", new_name));
|
||||||
if new_path.exists() {
|
if new_path.exists() {
|
||||||
@ -328,18 +328,18 @@ impl RealmFS {
|
|||||||
self.path().extension() == Some(OsStr::new("update"))
|
self.path().extension() == Some(OsStr::new("update"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update_copy(&self) -> Result<RealmFS> {
|
pub(crate) fn update_copy(&self) -> Result<Self> {
|
||||||
let path = self.path_with_extension("update");
|
let path = self.path_with_extension("update");
|
||||||
let name = self.name().to_string() + "-update";
|
let name = self.name().to_string() + "-update";
|
||||||
self.copy_image(&path, &name, false)
|
self.copy_image(&path, &name, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_image(&self, path: &Path, name: &str, sealed_copy: bool) -> Result<RealmFS> {
|
fn copy_image(&self, path: &Path, name: &str, sealed_copy: bool) -> Result<Self> {
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
bail!("Cannot create sealed copy because target path '{}' already exists", path.display());
|
bail!("Cannot create sealed copy because target path '{}' already exists", path.display());
|
||||||
}
|
}
|
||||||
cmd!("/usr/bin/cp", "--reflink=auto {} {}", self.path.display(), path.display())?;
|
cmd!("/usr/bin/cp", "--reflink=auto {} {}", self.path.display(), path.display())?;
|
||||||
let mut realmfs = RealmFS::_load_from_path(path, false)?;
|
let mut realmfs = Self::_load_from_path(path, false)?;
|
||||||
self.with_manager(|m| realmfs.set_manager(m));
|
self.with_manager(|m| realmfs.set_manager(m));
|
||||||
realmfs.name = Arc::new(name.to_owned());
|
realmfs.name = Arc::new(name.to_owned());
|
||||||
|
|
||||||
@ -365,13 +365,13 @@ impl RealmFS {
|
|||||||
let metainfo = self.metainfo();
|
let metainfo = self.metainfo();
|
||||||
let metainfo_bytes = self.generate_sealed_metainfo(self.name(), metainfo.verity_salt(), metainfo.verity_root());
|
let metainfo_bytes = self.generate_sealed_metainfo(self.name(), metainfo.verity_salt(), metainfo.verity_root());
|
||||||
let sig = keys.sign(&metainfo_bytes);
|
let sig = keys.sign(&metainfo_bytes);
|
||||||
self.write_new_metainfo(metainfo_bytes, Some(sig))
|
self.write_new_metainfo(&metainfo_bytes, Some(sig))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert to unsealed RealmFS image by removing dm-verity metadata and hash tree
|
/// Convert to unsealed RealmFS image by removing dm-verity metadata and hash tree
|
||||||
pub fn unseal(&self) -> Result<()> {
|
pub fn unseal(&self) -> Result<()> {
|
||||||
let bytes = RealmFS::generate_unsealed_metainfo(self.name(), self.metainfo().nblocks(), None);
|
let bytes = Self::generate_unsealed_metainfo(self.name(), self.metainfo().nblocks(), None);
|
||||||
self.write_new_metainfo(bytes, None)?;
|
self.write_new_metainfo(&bytes, None)?;
|
||||||
if self.has_verity_tree() {
|
if self.has_verity_tree() {
|
||||||
self.truncate_verity()?;
|
self.truncate_verity()?;
|
||||||
}
|
}
|
||||||
@ -384,7 +384,7 @@ impl RealmFS {
|
|||||||
}
|
}
|
||||||
if let Some(activation) = self.activation() {
|
if let Some(activation) = self.activation() {
|
||||||
let rw_mountpoint = activation.mountpoint_rw()
|
let rw_mountpoint = activation.mountpoint_rw()
|
||||||
.ok_or(format_err!("unsealed activation expected"))?;
|
.ok_or_else(|| format_err!("unsealed activation expected"))?;
|
||||||
if self.manager().active_mountpoints().contains(rw_mountpoint) {
|
if self.manager().active_mountpoints().contains(rw_mountpoint) {
|
||||||
bail!("Cannot set owner realm because RW mountpoint is in use (by current owner?)");
|
bail!("Cannot set owner realm because RW mountpoint is in use (by current owner?)");
|
||||||
}
|
}
|
||||||
@ -397,12 +397,12 @@ impl RealmFS {
|
|||||||
if self.is_sealed() {
|
if self.is_sealed() {
|
||||||
bail!("Cannot update metainfo on sealed realmfs image");
|
bail!("Cannot update metainfo on sealed realmfs image");
|
||||||
}
|
}
|
||||||
let metainfo_bytes = RealmFS::generate_unsealed_metainfo(name, nblocks, owner_realm);
|
let metainfo_bytes = Self::generate_unsealed_metainfo(name, nblocks, owner_realm);
|
||||||
self.write_new_metainfo(metainfo_bytes, None)
|
self.write_new_metainfo(&metainfo_bytes, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_new_metainfo(&self, bytes: Vec<u8>, sig: Option<Signature>) -> Result<()> {
|
fn write_new_metainfo(&self, bytes: &[u8], sig: Option<Signature>) -> Result<()> {
|
||||||
self.header.set_metainfo_bytes(&bytes)?;
|
self.header.set_metainfo_bytes(bytes)?;
|
||||||
if let Some(sig) = sig {
|
if let Some(sig) = sig {
|
||||||
self.header.set_signature(sig.to_bytes())?;
|
self.header.set_signature(sig.to_bytes())?;
|
||||||
}
|
}
|
||||||
@ -421,7 +421,7 @@ impl RealmFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_sealed_metainfo(&self, name: &str, verity_salt: &str, verity_root: &str) -> Vec<u8> {
|
fn generate_sealed_metainfo(&self, name: &str, verity_salt: &str, verity_root: &str) -> Vec<u8> {
|
||||||
let mut v = RealmFS::generate_unsealed_metainfo(name, self.metainfo().nblocks(), None);
|
let mut v = Self::generate_unsealed_metainfo(name, self.metainfo().nblocks(), None);
|
||||||
writeln!(v, "channel = \"{}\"", Self::USER_KEYNAME).unwrap();
|
writeln!(v, "channel = \"{}\"", Self::USER_KEYNAME).unwrap();
|
||||||
writeln!(v, "verity-salt = \"{}\"", verity_salt).unwrap();
|
writeln!(v, "verity-salt = \"{}\"", verity_salt).unwrap();
|
||||||
writeln!(v, "verity-root = \"{}\"", verity_root).unwrap();
|
writeln!(v, "verity-root = \"{}\"", verity_root).unwrap();
|
||||||
@ -499,7 +499,7 @@ impl RealmFS {
|
|||||||
|
|
||||||
let name = new_name.unwrap_or_else(|| self.name());
|
let name = new_name.unwrap_or_else(|| self.name());
|
||||||
|
|
||||||
let mut realmfs = RealmFS::load_from_path(&tmp)?;
|
let mut realmfs = Self::load_from_path(&tmp)?;
|
||||||
realmfs.set_manager(self.manager());
|
realmfs.set_manager(self.manager());
|
||||||
|
|
||||||
let finish = || {
|
let finish = || {
|
||||||
@ -525,7 +525,7 @@ impl RealmFS {
|
|||||||
let salt = hex::encode(randombytes(32));
|
let salt = hex::encode(randombytes(32));
|
||||||
let output = Verity::new(self.path()).generate_image_hashtree_with_salt(&self.metainfo(), &salt)?;
|
let output = Verity::new(self.path()).generate_image_hashtree_with_salt(&self.metainfo(), &salt)?;
|
||||||
let root_hash = output.root_hash()
|
let root_hash = output.root_hash()
|
||||||
.ok_or(format_err!("no root hash returned from verity format operation"))?;
|
.ok_or_else(|| format_err!("no root hash returned from verity format operation"))?;
|
||||||
info!("root hash is {}", output.root_hash().unwrap());
|
info!("root hash is {}", output.root_hash().unwrap());
|
||||||
|
|
||||||
info!("Signing new image with user realmfs keys");
|
info!("Signing new image with user realmfs keys");
|
||||||
@ -533,7 +533,7 @@ impl RealmFS {
|
|||||||
let sig = keys.sign(&metainfo_bytes);
|
let sig = keys.sign(&metainfo_bytes);
|
||||||
|
|
||||||
self.header().set_flag(ImageHeader::FLAG_HASH_TREE);
|
self.header().set_flag(ImageHeader::FLAG_HASH_TREE);
|
||||||
self.write_new_metainfo(metainfo_bytes, Some(sig))
|
self.write_new_metainfo(&metainfo_bytes, Some(sig))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_sealing_keys(&self) -> bool {
|
pub fn has_sealing_keys(&self) -> bool {
|
||||||
@ -545,7 +545,7 @@ impl RealmFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate(&self, new_file: &Path) -> Result<()> {
|
pub fn rotate(&self, new_file: &Path) -> Result<()> {
|
||||||
let backup = |n: usize| Path::new(RealmFS::BASE_PATH).join(format!("{}-realmfs.img.{}", self.name(), n));
|
let backup = |n: usize| Path::new(Self::BASE_PATH).join(format!("{}-realmfs.img.{}", self.name(), n));
|
||||||
|
|
||||||
for i in (1..NUM_BACKUPS).rev() {
|
for i in (1..NUM_BACKUPS).rev() {
|
||||||
let from = backup(i - 1);
|
let from = backup(i - 1);
|
||||||
@ -590,8 +590,7 @@ impl RealmFS {
|
|||||||
/// this `RealmFS`
|
/// this `RealmFS`
|
||||||
pub fn release_mountpoint(&self, mountpoint: &Mountpoint) -> bool {
|
pub fn release_mountpoint(&self, mountpoint: &Mountpoint) -> bool {
|
||||||
let is_ours = self.activation()
|
let is_ours = self.activation()
|
||||||
.map(|a| a.is_mountpoint(mountpoint))
|
.map_or(false, |a| a.is_mountpoint(mountpoint));
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
if is_ours {
|
if is_ours {
|
||||||
if let Err(e) = self.deactivate() {
|
if let Err(e) = self.deactivate() {
|
||||||
|
@ -21,14 +21,15 @@ impl RealmFSSet {
|
|||||||
fn load_all() -> Result<Vec<RealmFS>> {
|
fn load_all() -> Result<Vec<RealmFS>> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for entry in fs::read_dir(RealmFS::BASE_PATH)? {
|
for entry in fs::read_dir(RealmFS::BASE_PATH)? {
|
||||||
if let Some(realmfs) = Self::entry_to_realmfs(entry?) {
|
let entry = entry?;
|
||||||
|
if let Some(realmfs) = Self::entry_to_realmfs(&entry) {
|
||||||
v.push(realmfs)
|
v.push(realmfs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entry_to_realmfs(entry: fs::DirEntry) -> Option<RealmFS> {
|
fn entry_to_realmfs(entry: &fs::DirEntry) -> Option<RealmFS> {
|
||||||
if let Ok(filename) = entry.file_name().into_string() {
|
if let Ok(filename) = entry.file_name().into_string() {
|
||||||
if filename.ends_with("-realmfs.img") {
|
if filename.ends_with("-realmfs.img") {
|
||||||
let name = filename.trim_end_matches("-realmfs.img");
|
let name = filename.trim_end_matches("-realmfs.img");
|
||||||
@ -40,7 +41,7 @@ impl RealmFSSet {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_manager(&mut self, manager: Arc<RealmManager>) {
|
pub fn set_manager(&mut self, manager: &Arc<RealmManager>) {
|
||||||
self.realmfs_map.iter_mut().for_each(|(_,v)| v.set_manager(manager.clone()))
|
self.realmfs_map.iter_mut().for_each(|(_,v)| v.set_manager(manager.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ const BLOCKS_PER_GIG: usize = 1024 * BLOCKS_PER_MEG;
|
|||||||
const RESIZE2FS: &str = "resize2fs";
|
const RESIZE2FS: &str = "resize2fs";
|
||||||
|
|
||||||
// If less than 1gb remaining space
|
// If less than 1gb remaining space
|
||||||
const AUTO_RESIZE_MINIMUM_FREE: ResizeSize = ResizeSize(1 * BLOCKS_PER_GIG);
|
const AUTO_RESIZE_MINIMUM_FREE: ResizeSize = ResizeSize(BLOCKS_PER_GIG);
|
||||||
// ... add 4gb to size of image
|
// ... add 4gb to size of image
|
||||||
const AUTO_RESIZE_INCREASE_SIZE: ResizeSize = ResizeSize(4 * BLOCKS_PER_GIG);
|
const AUTO_RESIZE_INCREASE_SIZE: ResizeSize = ResizeSize(4 * BLOCKS_PER_GIG);
|
||||||
|
|
||||||
@ -21,19 +21,20 @@ pub struct ImageResizer<'a> {
|
|||||||
image: &'a RealmFS,
|
image: &'a RealmFS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy,Clone)]
|
||||||
pub struct ResizeSize(usize);
|
pub struct ResizeSize(usize);
|
||||||
|
|
||||||
impl ResizeSize {
|
impl ResizeSize {
|
||||||
|
|
||||||
pub fn gigs(n: usize) -> ResizeSize {
|
pub fn gigs(n: usize) -> Self {
|
||||||
ResizeSize(BLOCKS_PER_GIG * n)
|
ResizeSize(BLOCKS_PER_GIG * n)
|
||||||
|
|
||||||
}
|
}
|
||||||
pub fn megs(n: usize) -> ResizeSize {
|
pub fn megs(n: usize) -> Self {
|
||||||
ResizeSize(BLOCKS_PER_MEG * n)
|
ResizeSize(BLOCKS_PER_MEG * n)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocks(n: usize) -> ResizeSize {
|
pub fn blocks(n: usize) -> Self {
|
||||||
ResizeSize(n)
|
ResizeSize(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,13 +151,14 @@ impl <'a> ImageResizer<'a> {
|
|||||||
|
|
||||||
const SUPERBLOCK_SIZE: usize = 1024;
|
const SUPERBLOCK_SIZE: usize = 1024;
|
||||||
pub struct Superblock([u8; SUPERBLOCK_SIZE]);
|
pub struct Superblock([u8; SUPERBLOCK_SIZE]);
|
||||||
|
|
||||||
impl Superblock {
|
impl Superblock {
|
||||||
fn new() -> Superblock {
|
fn new() -> Self {
|
||||||
Superblock([0u8; SUPERBLOCK_SIZE])
|
Superblock([0u8; SUPERBLOCK_SIZE])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(path: impl AsRef<Path>, offset: u64) -> Result<Superblock> {
|
pub fn load(path: impl AsRef<Path>, offset: u64) -> Result<Self> {
|
||||||
let mut sb = Superblock::new();
|
let mut sb = Self::new();
|
||||||
let mut file = File::open(path.as_ref())?;
|
let mut file = File::open(path.as_ref())?;
|
||||||
file.seek(SeekFrom::Start(1024 + offset))?;
|
file.seek(SeekFrom::Start(1024 + offset))?;
|
||||||
file.read_exact(&mut sb.0)?;
|
file.read_exact(&mut sb.0)?;
|
||||||
@ -172,8 +174,8 @@ impl Superblock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn split_u64(&self, offset_lo: usize, offset_hi: usize) -> u64 {
|
fn split_u64(&self, offset_lo: usize, offset_hi: usize) -> u64 {
|
||||||
let lo = self.u32(offset_lo) as u64;
|
let lo = u64::from(self.u32(offset_lo));
|
||||||
let hi = self.u32(offset_hi) as u64;
|
let hi = u64::from(self.u32(offset_hi));
|
||||||
(hi << 32) | lo
|
(hi << 32) | lo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ impl <'a> Update<'a> {
|
|||||||
.map_err(|e| format_err!("failed to activate update image: {}", e))?;
|
.map_err(|e| format_err!("failed to activate update image: {}", e))?;
|
||||||
|
|
||||||
activation.mountpoint_rw().cloned()
|
activation.mountpoint_rw().cloned()
|
||||||
.ok_or(format_err!("Update image activation does not have a writeable mountpoint"))
|
.ok_or_else(|| format_err!("Update image activation does not have a writeable mountpoint"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_update_shell(&mut self, command: &str) -> Result<()> {
|
pub fn run_update_shell(&mut self, command: &str) -> Result<()> {
|
||||||
@ -83,7 +83,7 @@ impl <'a> Update<'a> {
|
|||||||
.arg("--quiet")
|
.arg("--quiet")
|
||||||
.arg(format!("--machine={}", self.name()))
|
.arg(format!("--machine={}", self.name()))
|
||||||
.arg(format!("--directory={}", mountpoint))
|
.arg(format!("--directory={}", mountpoint))
|
||||||
.arg(format!("--network-zone=clear"))
|
.arg("--network-zone=clear")
|
||||||
.arg("/bin/bash")
|
.arg("/bin/bash")
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(command)
|
.arg(command)
|
||||||
|
@ -39,8 +39,8 @@ impl ResourceImage {
|
|||||||
/// Locate and return a resource image of type `image_type`.
|
/// Locate and return a resource image of type `image_type`.
|
||||||
/// First the /run/citadel/images directory is searched, and if not found there,
|
/// First the /run/citadel/images directory is searched, and if not found there,
|
||||||
/// the image will be searched for in /storage/resources/$channel
|
/// the image will be searched for in /storage/resources/$channel
|
||||||
pub fn find(image_type: &str) -> Result<ResourceImage> {
|
pub fn find(image_type: &str) -> Result<Self> {
|
||||||
let channel = ResourceImage::rootfs_channel();
|
let channel = Self::rootfs_channel();
|
||||||
|
|
||||||
info!("Searching run directory for image {} with channel {}", image_type, channel);
|
info!("Searching run directory for image {} with channel {}", image_type, channel);
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ impl ResourceImage {
|
|||||||
return Ok(image);
|
return Ok(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ResourceImage::ensure_storage_mounted()? {
|
if !Self::ensure_storage_mounted()? {
|
||||||
bail!("Unable to mount /storage");
|
bail!("Unable to mount /storage");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,24 +62,24 @@ impl ResourceImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mount_image_type(image_type: &str) -> Result<()> {
|
pub fn mount_image_type(image_type: &str) -> Result<()> {
|
||||||
let mut image = ResourceImage::find(image_type)?;
|
let mut image = Self::find(image_type)?;
|
||||||
image.mount()
|
image.mount()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locate a rootfs image in /run/citadel/images and return it
|
/// Locate a rootfs image in /run/citadel/images and return it
|
||||||
pub fn find_rootfs() -> Result<ResourceImage> {
|
pub fn find_rootfs() -> Result<Self> {
|
||||||
match search_directory(RUN_DIRECTORY, "rootfs", None)? {
|
match search_directory(RUN_DIRECTORY, "rootfs", None)? {
|
||||||
Some(image) => Ok(image),
|
Some(image) => Ok(image),
|
||||||
None => Err(format_err!("Failed to find rootfs resource image")),
|
None => Err(format_err!("Failed to find rootfs resource image")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<ResourceImage> {
|
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||||
let header = ImageHeader::from_file(path.as_ref())?;
|
let header = ImageHeader::from_file(path.as_ref())?;
|
||||||
if !header.is_magic_valid() {
|
if !header.is_magic_valid() {
|
||||||
bail!("Image file {} does not have a valid header", path.as_ref().display());
|
bail!("Image file {} does not have a valid header", path.as_ref().display());
|
||||||
}
|
}
|
||||||
Ok(ResourceImage::new(path.as_ref(), header ))
|
Ok(Self::new(path.as_ref(), header ))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_valid_image(&self) -> bool {
|
pub fn is_valid_image(&self) -> bool {
|
||||||
@ -103,7 +103,7 @@ impl ResourceImage {
|
|||||||
self.header.metainfo()
|
self.header.metainfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(path: &Path, header: ImageHeader) -> ResourceImage {
|
fn new(path: &Path, header: ImageHeader) -> Self {
|
||||||
assert_eq!(path.extension(), Some(OsStr::new("img")), "image filename must have .img extension");
|
assert_eq!(path.extension(), Some(OsStr::new("img")), "image filename must have .img extension");
|
||||||
|
|
||||||
ResourceImage {
|
ResourceImage {
|
||||||
@ -297,14 +297,14 @@ impl ResourceImage {
|
|||||||
// If no colon character is present then the source and target paths are the same.
|
// If no colon character is present then the source and target paths are the same.
|
||||||
// The source path from the mounted resource image will be bind mounted to the target path on the system rootfs.
|
// The source path from the mounted resource image will be bind mounted to the target path on the system rootfs.
|
||||||
fn process_manifest_line(&self, line: &str) -> Result<()> {
|
fn process_manifest_line(&self, line: &str) -> Result<()> {
|
||||||
let line = line.trim_left_matches('/');
|
let line = line.trim_start_matches('/');
|
||||||
|
|
||||||
let (path_from, path_to) = if line.contains(":") {
|
let (path_from, path_to) = if line.contains(':') {
|
||||||
let v = line.split(":").collect::<Vec<_>>();
|
let v = line.split(':').collect::<Vec<_>>();
|
||||||
if v.len() != 2 {
|
if v.len() != 2 {
|
||||||
bail!("badly formed line '{}'", line);
|
bail!("badly formed line '{}'", line);
|
||||||
}
|
}
|
||||||
(v[0], v[1].trim_left_matches('/'))
|
(v[0], v[1].trim_start_matches('/'))
|
||||||
} else {
|
} else {
|
||||||
(line, line)
|
(line, line)
|
||||||
};
|
};
|
||||||
@ -418,7 +418,7 @@ fn parse_timestamp(img: &ResourceImage) -> Result<usize> {
|
|||||||
|
|
||||||
fn current_kernel_version() -> String {
|
fn current_kernel_version() -> String {
|
||||||
let utsname = UtsName::uname();
|
let utsname = UtsName::uname();
|
||||||
let v = utsname.release().split("-").collect::<Vec<_>>();
|
let v = utsname.release().split('-').collect::<Vec<_>>();
|
||||||
v[0].to_string()
|
v[0].to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,10 +484,8 @@ fn maybe_add_dir_entry(entry: DirEntry,
|
|||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
if image_type == "kernel" {
|
if image_type == "kernel" && (metainfo.kernel_version() != kernel_version || metainfo.kernel_id() != kernel_id) {
|
||||||
if metainfo.kernel_version() != kernel_version || metainfo.kernel_id() != kernel_id {
|
return Ok(());
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
images.push(ResourceImage::new(&path, header));
|
images.push(ResourceImage::new(&path, header));
|
||||||
|
@ -7,7 +7,7 @@ use crate::Result;
|
|||||||
pub fn read(path: impl AsRef<Path>) -> Option<PathBuf> {
|
pub fn read(path: impl AsRef<Path>) -> Option<PathBuf> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
if !fs::symlink_metadata(path).is_ok() {
|
if fs::symlink_metadata(path).is_err() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +44,8 @@ pub fn write(target: impl AsRef<Path>, link: impl AsRef<Path>, tmp_in_parent: bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_tmp_path(link: &Path, tmp_in_parent: bool) -> PathBuf {
|
fn write_tmp_path(link: &Path, tmp_in_parent: bool) -> PathBuf {
|
||||||
let skip = if tmp_in_parent { 2 } else { 1 };
|
let n = if tmp_in_parent { 2 } else { 1 };
|
||||||
let tmp_dir = link.ancestors().skip(skip).next()
|
let tmp_dir = link.ancestors().nth(n)
|
||||||
.expect("No parent directory in write_symlink");
|
.expect("No parent directory in write_symlink");
|
||||||
|
|
||||||
let mut tmp_fname = link.file_name()
|
let mut tmp_fname = link.file_name()
|
||||||
|
@ -24,7 +24,7 @@ impl LoopDevice {
|
|||||||
args += &format!("--offset {} ", offset);
|
args += &format!("--offset {} ", offset);
|
||||||
}
|
}
|
||||||
if read_only {
|
if read_only {
|
||||||
args += &format!("--read-only ");
|
args += "--read-only ";
|
||||||
}
|
}
|
||||||
args += &format!("-f --show {}", image.display());
|
args += &format!("-f --show {}", image.display());
|
||||||
let output = cmd_with_output!(Self::LOSETUP, args)?;
|
let output = cmd_with_output!(Self::LOSETUP, args)?;
|
||||||
@ -64,8 +64,8 @@ impl LoopDevice {
|
|||||||
// /dev/loop1: [0036]:64845938 (/storage/resources/dev/citadel-extra-dev-001.img), offset 4096
|
// /dev/loop1: [0036]:64845938 (/storage/resources/dev/citadel-extra-dev-001.img), offset 4096
|
||||||
let output:String = cmd_with_output!(Self::LOSETUP, "-j {}", image.display())?;
|
let output:String = cmd_with_output!(Self::LOSETUP, "-j {}", image.display())?;
|
||||||
Ok(output.lines()
|
Ok(output.lines()
|
||||||
.flat_map(|line| line.splitn(2, ":").next())
|
.flat_map(|line| line.splitn(2, ':').next())
|
||||||
.map(|s| LoopDevice::new(s))
|
.map(LoopDevice::new)
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use crate::Result;
|
|||||||
use crate::terminal::{RawTerminal, Color, Base16Scheme};
|
use crate::terminal::{RawTerminal, Color, Base16Scheme};
|
||||||
use std::io::{self,Read,Write,Stdout};
|
use std::io::{self,Read,Write,Stdout};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct AnsiControl(String);
|
pub struct AnsiControl(String);
|
||||||
|
|
||||||
impl AnsiControl {
|
impl AnsiControl {
|
||||||
@ -11,50 +12,45 @@ impl AnsiControl {
|
|||||||
const OSC: char = ']';
|
const OSC: char = ']';
|
||||||
const ST: char = '\\';
|
const ST: char = '\\';
|
||||||
|
|
||||||
pub fn new() -> Self {
|
|
||||||
AnsiControl(String::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn osc(n: u32) -> Self {
|
pub fn osc(n: u32) -> Self {
|
||||||
AnsiControl::new()
|
Self::default()
|
||||||
.push(AnsiControl::ESC)
|
.push(Self::ESC)
|
||||||
.push(AnsiControl::OSC)
|
.push(Self::OSC)
|
||||||
.num(n)
|
.num(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn csi() -> Self {
|
pub fn csi() -> Self {
|
||||||
AnsiControl::new()
|
Self::default()
|
||||||
.push(AnsiControl::ESC)
|
.push(Self::ESC)
|
||||||
.push(AnsiControl::CSI)
|
.push(Self::CSI)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bold() -> Self {
|
pub fn bold() -> Self {
|
||||||
AnsiControl::csi().push_str("1m")
|
Self::csi().push_str("1m")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unbold() -> Self {
|
pub fn unbold() -> Self {
|
||||||
AnsiControl::csi().push_str("22m")
|
Self::csi().push_str("22m")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear() -> Self {
|
pub fn clear() -> Self {
|
||||||
AnsiControl::csi().push_str("2J")
|
Self::csi().push_str("2J")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn goto(x: u16, y: u16) -> Self {
|
pub fn goto(x: u16, y: u16) -> Self {
|
||||||
AnsiControl::csi().push_str(x.to_string()).push(';').push_str(y.to_string()).push('H')
|
Self::csi().push_str(x.to_string()).push(';').push_str(y.to_string()).push('H')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_window_title<S: AsRef<str>>(title: S) -> AnsiControl {
|
pub fn set_window_title<S: AsRef<str>>(title: S) -> Self {
|
||||||
// AnsiControl::osc(2).sep().push_str(title.as_ref()).st()
|
Self::osc(0).sep().push_str(title.as_ref()).st()
|
||||||
AnsiControl::osc(0).sep().push_str(title.as_ref()).st()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_title_push_stack() -> AnsiControl {
|
pub fn window_title_push_stack() -> Self {
|
||||||
AnsiControl::csi().push_str("22;2t")
|
Self::csi().push_str("22;2t")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_title_pop_stack() -> AnsiControl {
|
pub fn window_title_pop_stack() -> Self {
|
||||||
AnsiControl::csi().push_str("23;2t")
|
Self::csi().push_str("23;2t")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sep(self) -> Self {
|
pub fn sep(self) -> Self {
|
||||||
@ -70,7 +66,7 @@ impl AnsiControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn st(self) -> Self {
|
pub fn st(self) -> Self {
|
||||||
self.push(AnsiControl::ESC).push(AnsiControl::ST)
|
self.push(Self::ESC).push(Self::ST)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_str<S: AsRef<str>>(mut self, s: S) -> Self {
|
pub fn push_str<S: AsRef<str>>(mut self, s: S) -> Self {
|
||||||
@ -92,8 +88,8 @@ impl AnsiControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_color_response(s: &str) -> Result<Vec<(u32, Color)>> {
|
fn parse_color_response(s: &str) -> Result<Vec<(u32, Color)>> {
|
||||||
let prefix = AnsiControl::osc(4).sep();
|
let prefix = Self::osc(4).sep();
|
||||||
let suffix = AnsiControl::new().st();
|
let suffix = Self::default().st();
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
|
|
||||||
let mut ptr = s;
|
let mut ptr = s;
|
||||||
@ -104,14 +100,14 @@ impl AnsiControl {
|
|||||||
None => bail!(":("),
|
None => bail!(":("),
|
||||||
};
|
};
|
||||||
let (elem, s) = s.split_at(offset);
|
let (elem, s) = s.split_at(offset);
|
||||||
res.push(AnsiControl::parse_idx_color_pair(elem)?);
|
res.push(Self::parse_idx_color_pair(elem)?);
|
||||||
ptr = s.trim_start_matches(suffix.as_str());
|
ptr = s.trim_start_matches(suffix.as_str());
|
||||||
}
|
}
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_idx_color_pair(s: &str) -> Result<(u32, Color)> {
|
fn parse_idx_color_pair(s: &str) -> Result<(u32, Color)> {
|
||||||
let v = s.split(";").collect::<Vec<_>>();
|
let v = s.split(';').collect::<Vec<_>>();
|
||||||
if v.len() != 2 {
|
if v.len() != 2 {
|
||||||
bail!("bad elem {}", s);
|
bail!("bad elem {}", s);
|
||||||
}
|
}
|
||||||
@ -175,7 +171,7 @@ impl AnsiTerminal {
|
|||||||
|
|
||||||
pub fn read_palette_bg(&mut self) -> Result<Color> {
|
pub fn read_palette_bg(&mut self) -> Result<Color> {
|
||||||
let prefix = AnsiControl::osc(11).sep();
|
let prefix = AnsiControl::osc(11).sep();
|
||||||
let suffix = AnsiControl::new().st();
|
let suffix = AnsiControl::default().st();
|
||||||
self.write_code(AnsiControl::osc(11).sep().push('?').st())?;
|
self.write_code(AnsiControl::osc(11).sep().push('?').st())?;
|
||||||
let response = self.read_response()?;
|
let response = self.read_response()?;
|
||||||
let color = Color::parse(response.trim_start_matches(prefix.as_str()).trim_end_matches(suffix.as_str()))?;
|
let color = Color::parse(response.trim_start_matches(prefix.as_str()).trim_end_matches(suffix.as_str()))?;
|
||||||
@ -184,7 +180,7 @@ impl AnsiTerminal {
|
|||||||
}
|
}
|
||||||
pub fn read_palette_fg(&mut self) -> Result<Color> {
|
pub fn read_palette_fg(&mut self) -> Result<Color> {
|
||||||
let prefix = AnsiControl::osc(10).sep();
|
let prefix = AnsiControl::osc(10).sep();
|
||||||
let suffix = AnsiControl::new().st();
|
let suffix = AnsiControl::default().st();
|
||||||
self.write_code(AnsiControl::osc(10).sep().push('?').st())?;
|
self.write_code(AnsiControl::osc(10).sep().push('?').st())?;
|
||||||
let response = self.read_response()?;
|
let response = self.read_response()?;
|
||||||
let color = Color::parse(response.trim_start_matches(prefix.as_str()).trim_end_matches(suffix.as_str()))?;
|
let color = Color::parse(response.trim_start_matches(prefix.as_str()).trim_end_matches(suffix.as_str()))?;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
#![allow(clippy::unreadable_literal)]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::terminal::{Color, Base16Shell};
|
use crate::terminal::{Color, Base16Shell};
|
||||||
use crate::{Realm, Result, util, RealmManager};
|
use crate::{Realm, Result, util, RealmManager};
|
||||||
@ -24,7 +24,7 @@ impl Base16Scheme {
|
|||||||
const BASE16_SHELL_FILE: &'static str = ".base16rc";
|
const BASE16_SHELL_FILE: &'static str = ".base16rc";
|
||||||
const BASE16_VIM_FILE: &'static str = ".base16vim";
|
const BASE16_VIM_FILE: &'static str = ".base16vim";
|
||||||
|
|
||||||
pub fn by_name(name: &str) -> Option<&'static Base16Scheme> {
|
pub fn by_name(name: &str) -> Option<&'static Self> {
|
||||||
SCHEMES.get(name)
|
SCHEMES.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,8 +34,8 @@ impl Base16Scheme {
|
|||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_schemes() -> Vec<Base16Scheme> {
|
pub fn all_schemes() -> Vec<Self> {
|
||||||
let mut v: Vec<Base16Scheme> =
|
let mut v: Vec<Self> =
|
||||||
SCHEMES.values().cloned().collect();
|
SCHEMES.values().cloned().collect();
|
||||||
|
|
||||||
v.sort_by(|a,b| a.name().cmp(b.name()));
|
v.sort_by(|a,b| a.name().cmp(b.name()));
|
||||||
@ -70,12 +70,12 @@ impl Base16Scheme {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(slug: &str, name: &str, v: Vec<u32>) -> Base16Scheme {
|
pub fn new(slug: &str, name: &str, v: Vec<u32>) -> Self {
|
||||||
assert_eq!(v.len(), 16);
|
assert_eq!(v.len(), 16);
|
||||||
let mut colors = [Color::default();16];
|
let mut colors = [Color::default();16];
|
||||||
let cs = v.iter().map(|&c| Base16Scheme::u32_to_color(c)).collect::<Vec<_>>();
|
let cs = v.iter().map(|&c| Self::u32_to_color(c)).collect::<Vec<_>>();
|
||||||
colors.copy_from_slice(&cs);
|
colors.copy_from_slice(&cs);
|
||||||
let category = Base16Scheme::find_category(name);
|
let category = Self::find_category(name);
|
||||||
Base16Scheme {
|
Base16Scheme {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
slug: slug.to_string(),
|
slug: slug.to_string(),
|
||||||
@ -110,7 +110,7 @@ impl Base16Scheme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminal_palette_color(&self, idx: usize) -> Color {
|
pub fn terminal_palette_color(&self, idx: usize) -> Color {
|
||||||
self.color(Base16Scheme::TERM_MAP[idx])
|
self.color(Self::TERM_MAP[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_to_realm(&self, manager: &RealmManager, realm: &Realm) -> Result<()> {
|
pub fn apply_to_realm(&self, manager: &RealmManager, realm: &Realm) -> Result<()> {
|
||||||
@ -925,7 +925,7 @@ fn create_schemes() -> HashMap<String, Base16Scheme> {
|
|||||||
vec![
|
vec![
|
||||||
0x1B2B34, 0x343D46, 0x4F5B66, 0x65737E,
|
0x1B2B34, 0x343D46, 0x4F5B66, 0x65737E,
|
||||||
0xA7ADBA, 0xC0C5CE, 0xCDD3DE, 0xD8DEE9,
|
0xA7ADBA, 0xC0C5CE, 0xCDD3DE, 0xD8DEE9,
|
||||||
0xEC5f67, 0xF99157, 0xFAC863, 0x99C794,
|
0xEC5F67, 0xF99157, 0xFAC863, 0x99C794,
|
||||||
0x5FB3B3, 0x6699CC, 0xC594C5, 0xAB7967,
|
0x5FB3B3, 0x6699CC, 0xC594C5, 0xAB7967,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@ -1029,7 +1029,7 @@ fn create_schemes() -> HashMap<String, Base16Scheme> {
|
|||||||
vec![
|
vec![
|
||||||
0x151718, 0x282a2b, 0x3B758C, 0x41535B,
|
0x151718, 0x282a2b, 0x3B758C, 0x41535B,
|
||||||
0x43a5d5, 0xd6d6d6, 0xeeeeee, 0xffffff,
|
0x43a5d5, 0xd6d6d6, 0xeeeeee, 0xffffff,
|
||||||
0xCd3f45, 0xdb7b55, 0xe6cd69, 0x9fca56,
|
0xcd3f45, 0xdb7b55, 0xe6cd69, 0x9fca56,
|
||||||
0x55dbbe, 0x55b5db, 0xa074c4, 0x8a553f,
|
0x55dbbe, 0x55b5db, 0xa074c4, 0x8a553f,
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
@ -13,18 +13,18 @@ impl Color {
|
|||||||
|
|
||||||
pub fn parse(s: &str) -> Result<Color> {
|
pub fn parse(s: &str) -> Result<Color> {
|
||||||
if s.starts_with("rgb:") {
|
if s.starts_with("rgb:") {
|
||||||
let v = s.trim_start_matches("rgb:").split("/").collect::<Vec<_>>();
|
let parts = s.trim_start_matches("rgb:").split('/').collect::<Vec<_>>();
|
||||||
if v.len() == 3 {
|
if parts.len() == 3 {
|
||||||
let r = u16::from_str_radix(&v[0], 16)?;
|
let r = u16::from_str_radix(&parts[0], 16)?;
|
||||||
let g = u16::from_str_radix(&v[1], 16)?;
|
let g = u16::from_str_radix(&parts[1], 16)?;
|
||||||
let b = u16::from_str_radix(&v[2], 16)?;
|
let b = u16::from_str_radix(&parts[2], 16)?;
|
||||||
return Ok(Color(r, g, b))
|
return Ok(Color(r, g, b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(format_err!("Cannot parse '{}'", s))
|
Err(format_err!("Cannot parse '{}'", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rgb(&self) -> (u16,u16,u16) {
|
pub fn rgb(self) -> (u16,u16,u16) {
|
||||||
(self.0, self.1, self.2)
|
(self.0, self.1, self.2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,9 +88,7 @@ impl TerminalPalette {
|
|||||||
self.fg = terminal.read_palette_fg()?;
|
self.fg = terminal.read_palette_fg()?;
|
||||||
let idxs = (0..22).collect::<Vec<_>>();
|
let idxs = (0..22).collect::<Vec<_>>();
|
||||||
let colors = terminal.read_palette_colors(&idxs)?;
|
let colors = terminal.read_palette_colors(&idxs)?;
|
||||||
for i in 0..self.palette.len() {
|
self.palette.clone_from_slice(&colors);
|
||||||
self.palette[i] = colors[i];
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ pub fn sha256<P: AsRef<Path>>(path: P) -> Result<String> {
|
|||||||
Ok(v[0].trim().to_owned())
|
Ok(v[0].trim().to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy,Clone)]
|
||||||
pub enum FileRange {
|
pub enum FileRange {
|
||||||
All,
|
All,
|
||||||
Offset(usize),
|
Offset(usize),
|
||||||
@ -78,13 +79,13 @@ fn ranged_reader<P: AsRef<Path>>(path: P, range: FileRange) -> Result<Box<dyn Re
|
|||||||
let offset = match range {
|
let offset = match range {
|
||||||
FileRange::All => 0,
|
FileRange::All => 0,
|
||||||
FileRange::Offset(n) => n,
|
FileRange::Offset(n) => n,
|
||||||
FileRange::Range {offset, len: _} => offset,
|
FileRange::Range {offset, .. } => offset,
|
||||||
};
|
};
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
f.seek(SeekFrom::Start(offset as u64))?;
|
f.seek(SeekFrom::Start(offset as u64))?;
|
||||||
}
|
}
|
||||||
let r = BufReader::new(f);
|
let r = BufReader::new(f);
|
||||||
if let FileRange::Range {offset: _, len} = range {
|
if let FileRange::Range {len, ..} = range {
|
||||||
Ok(Box::new(r.take(len as u64)))
|
Ok(Box::new(r.take(len as u64)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Box::new(r))
|
Ok(Box::new(r))
|
||||||
@ -191,7 +192,7 @@ fn _copy_tree(from_base: &Path, to_base: &Path, chown_to: Option<(u32,u32)>) ->
|
|||||||
for entry in WalkDir::new(from_base) {
|
for entry in WalkDir::new(from_base) {
|
||||||
let path = entry?.path().to_owned();
|
let path = entry?.path().to_owned();
|
||||||
let to = to_base.join(path.strip_prefix(from_base)?);
|
let to = to_base.join(path.strip_prefix(from_base)?);
|
||||||
if &to != to_base {
|
if to != to_base {
|
||||||
copy_path(&path, &to, chown_to)
|
copy_path(&path, &to, chown_to)
|
||||||
.map_err(|e| format_err!("failed to copy {} to {}: {}", path.display(), to.display(), e))?;
|
.map_err(|e| format_err!("failed to copy {} to {}: {}", path.display(), to.display(), e))?;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ pub struct VerityOutput {
|
|||||||
impl VerityOutput {
|
impl VerityOutput {
|
||||||
/// Parse the string `output` as standard output from the dm-verity
|
/// Parse the string `output` as standard output from the dm-verity
|
||||||
/// `veritysetup format` command.
|
/// `veritysetup format` command.
|
||||||
fn parse(output: &str) -> VerityOutput {
|
fn parse(output: &str) -> Self {
|
||||||
let mut vo = VerityOutput {
|
let mut vo = VerityOutput {
|
||||||
output: output.to_owned(),
|
output: output.to_owned(),
|
||||||
map: HashMap::new(),
|
map: HashMap::new(),
|
||||||
|
Loading…
Reference in New Issue
Block a user