Skip to content

Commit 0e27b95

Browse files
committed
Bette verification about root partition
1 parent b8de7a0 commit 0e27b95

1 file changed

Lines changed: 100 additions & 44 deletions

File tree

src/main.rs

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use std::process::{Command, Stdio};
88
use clap::{Parser, Subcommand};
99

1010
use systemd_swap::config::{Config, WORK_DIR};
11-
use systemd_swap::helpers::{am_i_root, find_swap_units, force_remove, get_what_from_swap_unit, makedirs, read_file};
11+
use systemd_swap::helpers::{
12+
am_i_root, find_swap_units, force_remove, get_what_from_swap_unit, makedirs, read_file,
13+
};
1214
use systemd_swap::meminfo::{get_mem_stats, get_page_size};
1315
use systemd_swap::swapfc::SwapFc;
1416
use systemd_swap::systemd::{notify_ready, notify_stopping, swapoff};
@@ -38,10 +40,10 @@ enum Commands {
3840
#[derive(Debug, Clone, Copy, PartialEq)]
3941
enum SwapMode {
4042
Auto,
41-
ZramSwapfc, // zram + writeback to swap files (best for desktop!)
42-
ZswapSwapfc, // zswap + swap files (alternative)
43-
ZramOnly, // zram only (for non-btrfs)
44-
Manual, // Use explicit config values
43+
ZramSwapfc, // zram + writeback to swap files (legacy option)
44+
ZswapSwapfc, // zswap + swap files (BEST for installed desktops: btrfs, ext4, xfs)
45+
ZramOnly, // zram only (for LiveCD or unsupported filesystems)
46+
Manual, // Use explicit config values
4547
}
4648

4749
fn main() {
@@ -67,19 +69,33 @@ fn main() {
6769
}
6870

6971
/// Detect filesystem type for a path
72+
/// Falls back to root filesystem if path doesn't exist yet
7073
fn get_path_fstype(path: &str) -> Option<String> {
71-
// Check the parent directory or the path itself
72-
let check_path = if Path::new(path).exists() {
73-
path.to_string()
74-
} else if let Some(parent) = Path::new(path).parent() {
75-
parent.to_string_lossy().to_string()
74+
// Build list of paths to check: path itself, parent, grandparent, ..., root
75+
let mut check_path = None;
76+
let mut current = Path::new(path);
77+
78+
// First check if the path itself exists
79+
if current.exists() {
80+
check_path = Some(path.to_string());
7681
} else {
77-
"/".to_string()
78-
};
82+
// Walk up the directory tree to find an existing parent
83+
while let Some(parent) = current.parent() {
84+
if parent.exists() && parent.to_string_lossy() != "" {
85+
check_path = Some(parent.to_string_lossy().to_string());
86+
break;
87+
}
88+
current = parent;
89+
}
90+
}
91+
92+
// Fall back to root if nothing found
93+
let check_path = check_path.unwrap_or_else(|| "/".to_string());
7994

8095
let output = Command::new("df")
8196
.args(["--output=fstype", &check_path])
8297
.stdout(Stdio::piped())
98+
.stderr(Stdio::null())
8399
.output()
84100
.ok()?;
85101

@@ -98,7 +114,12 @@ fn is_swapfc_supported(path: &str) -> bool {
98114

99115
/// Parse swap_mode from config
100116
fn get_swap_mode(config: &Config) -> SwapMode {
101-
match config.get("swap_mode").unwrap_or("auto").to_lowercase().as_str() {
117+
match config
118+
.get("swap_mode")
119+
.unwrap_or("auto")
120+
.to_lowercase()
121+
.as_str()
122+
{
102123
"zram+swapfc" | "zram_swapfc" => SwapMode::ZramSwapfc,
103124
"zswap+swapfc" | "zswap" => SwapMode::ZswapSwapfc,
104125
"zram" | "zram_only" => SwapMode::ZramOnly,
@@ -116,7 +137,7 @@ fn run_zram_only(config: &Config) -> Result<(), Box<dyn std::error::Error>> {
116137
}
117138
notify_ready();
118139
info!("Zram setup complete (fallback mode)");
119-
140+
120141
// Keep running to respond to signals
121142
loop {
122143
std::thread::sleep(std::time::Duration::from_secs(60));
@@ -136,23 +157,34 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
136157

137158
// Initialize directories
138159
makedirs(WORK_DIR)?;
139-
makedirs(format!("{}/system/local-fs.target.wants", systemd_swap::config::RUN_SYSD))?;
140-
makedirs(format!("{}/system/swap.target.wants", systemd_swap::config::RUN_SYSD))?;
160+
makedirs(format!(
161+
"{}/system/local-fs.target.wants",
162+
systemd_swap::config::RUN_SYSD
163+
))?;
164+
makedirs(format!(
165+
"{}/system/swap.target.wants",
166+
systemd_swap::config::RUN_SYSD
167+
))?;
141168

142169
let config = Config::load()?;
143170
let swap_mode = get_swap_mode(&config);
144171

145172
// Determine effective mode
173+
// For installed systems (btrfs, ext4, xfs): use zswap + swapfc (best performance)
174+
// For LiveCD or unsupported filesystems: use zram only
146175
let effective_mode = match swap_mode {
147176
SwapMode::Auto => {
148177
let swapfc_path = config.get("swapfc_path").unwrap_or("/swapfc/swapfile");
149178
if is_swapfc_supported(swapfc_path) {
150179
let fstype = get_path_fstype(swapfc_path).unwrap_or_default();
151-
info!("Auto-detected {}: using zswap + swapfc", fstype);
180+
info!("Auto-detected {} filesystem: using zswap + swapfc (best for installed systems)", fstype);
152181
SwapMode::ZswapSwapfc
153182
} else {
154183
let fstype = get_path_fstype(swapfc_path).unwrap_or_else(|| "unknown".to_string());
155-
info!("Filesystem '{}' not supported for swap files: using zram only", fstype);
184+
info!(
185+
"Filesystem '{}' not supported for swap files: using zram only (LiveCD mode)",
186+
fstype
187+
);
156188
SwapMode::ZramOnly
157189
}
158190
}
@@ -164,9 +196,9 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
164196

165197
match effective_mode {
166198
SwapMode::ZramSwapfc => {
167-
// Desktop-optimized mode: zram for speed + swapfc for overflow
168-
// zram is faster than zswap because it's a dedicated block device
169-
199+
// Legacy mode: zram for speed + swapfc for overflow
200+
// Note: zswap+swapfc is now preferred for installed systems
201+
170202
// Set up signal handler
171203
signal_hook::flag::register(
172204
signal_hook::consts::SIGTERM,
@@ -206,7 +238,10 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
206238
}
207239
Err(e) => {
208240
// swapfc failed but zram is already running - continue in zram-only mode
209-
warn!("swapFC: initialization failed: {} - continuing with zram-only", e);
241+
warn!(
242+
"swapFC: initialization failed: {} - continuing with zram-only",
243+
e
244+
);
210245
notify_ready();
211246
loop {
212247
std::thread::sleep(std::time::Duration::from_secs(60));
@@ -219,9 +254,10 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
219254
}
220255

221256
SwapMode::ZswapSwapfc => {
222-
// For zswap: create swap file FIRST, then enable zswap
223-
// zswap needs a backing swap device to work
224-
257+
// RECOMMENDED for installed desktops (btrfs, ext4, xfs)
258+
// zswap compresses pages in RAM before writing to swap files
259+
// Create swap file FIRST, then enable zswap (zswap needs backing swap)
260+
225261
// Set up signal handler
226262
signal_hook::flag::register(
227263
signal_hook::consts::SIGTERM,
@@ -256,20 +292,23 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
256292
}
257293
}
258294
Err(e) => {
259-
warn!("swapFC: initialization failed: {} - falling back to zram-only", e);
295+
warn!(
296+
"swapFC: initialization failed: {} - falling back to zram-only",
297+
e
298+
);
260299
run_zram_only(&config)?;
261300
}
262301
}
263302
}
264303

265304
SwapMode::ZramOnly => {
266-
// For zram: just set up zram, no swap files needed
305+
// For LiveCD or unsupported filesystems: zram only, no swap files
267306
if let Err(e) = systemd_swap::zram::start(&config) {
268307
error!("Zram: {}", e);
269308
}
270309
notify_ready();
271310
info!("Zram setup complete");
272-
311+
273312
// Keep running to respond to signals
274313
loop {
275314
std::thread::sleep(std::time::Duration::from_secs(60));
@@ -281,7 +320,7 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
281320

282321
SwapMode::Manual => {
283322
// Legacy mode: use explicit config values
284-
323+
285324
// Warn about incompatible configurations
286325
if config.get_bool("zram_enabled")
287326
&& (config.get_bool("zswap_enabled") || config.get_bool("swapfc_enabled"))
@@ -435,7 +474,7 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
435474
if usage.zswap_active {
436475
let zswap_original = swap_used.saturating_sub(usage.swap_used_disk);
437476
let zswap_compressed = usage.zswap_pool_bytes;
438-
477+
439478
let ratio = if zswap_original > 0 {
440479
(zswap_compressed as f64 / zswap_original as f64) * 100.0
441480
} else {
@@ -444,22 +483,30 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
444483

445484
println!();
446485
println!(" === Pool Statistics ===");
447-
println!(" pool_size: {:.1} MiB (compressed)", zswap_compressed as f64 / 1024.0 / 1024.0);
448-
println!(" stored_data: {:.1} MiB (original)", zswap_original as f64 / 1024.0 / 1024.0);
486+
println!(
487+
" pool_size: {:.1} MiB (compressed)",
488+
zswap_compressed as f64 / 1024.0 / 1024.0
489+
);
490+
println!(
491+
" stored_data: {:.1} MiB (original)",
492+
zswap_original as f64 / 1024.0 / 1024.0
493+
);
449494
println!(" pool_utilization: {}%", usage.zswap_pool_percent);
450495
println!(" compress_ratio: {:.0}%", ratio);
451496

452497
// If running as root, show additional debugfs stats
453498
if is_root && (zswap.stored_pages > 0 || zswap.written_back_pages > 0) {
454499
let page_size = get_page_size();
455-
500+
456501
println!();
457502
println!(" === Writeback Statistics (debugfs) ===");
458503
println!(" stored_pages: {}", zswap.stored_pages);
459504
println!(" same_filled_pages: {}", zswap.same_filled_pages);
460-
println!(" written_back_pages: {} ({:.1} MiB)",
461-
zswap.written_back_pages,
462-
(zswap.written_back_pages * page_size) as f64 / 1024.0 / 1024.0);
505+
println!(
506+
" written_back_pages: {} ({:.1} MiB)",
507+
zswap.written_back_pages,
508+
(zswap.written_back_pages * page_size) as f64 / 1024.0 / 1024.0
509+
);
463510
println!(" pool_limit_hit: {}", zswap.pool_limit_hit);
464511
println!(" reject_reclaim_fail: {}", zswap.reject_reclaim_fail);
465512
}
@@ -468,9 +515,18 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
468515
if swap_used > 0 {
469516
println!();
470517
println!(" === Effective Swap Usage ===");
471-
println!(" kernel_reported_used: {:.1} MiB", swap_used as f64 / 1024.0 / 1024.0);
472-
println!(" in_zswap_pool (RAM): {:.1} MiB", zswap_original as f64 / 1024.0 / 1024.0);
473-
println!(" actual_disk_used: {:.1} MiB", usage.swap_used_disk as f64 / 1024.0 / 1024.0);
518+
println!(
519+
" kernel_reported_used: {:.1} MiB",
520+
swap_used as f64 / 1024.0 / 1024.0
521+
);
522+
println!(
523+
" in_zswap_pool (RAM): {:.1} MiB",
524+
zswap_original as f64 / 1024.0 / 1024.0
525+
);
526+
println!(
527+
" actual_disk_used: {:.1} MiB",
528+
usage.swap_used_disk as f64 / 1024.0 / 1024.0
529+
);
474530
let percent_in_ram = (zswap_original as f64 / swap_used as f64) * 100.0;
475531
println!(" swap_in_ram: {:.0}%", percent_in_ram);
476532
}
@@ -479,17 +535,18 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
479535
}
480536

481537
// Zram status
482-
let zramctl_output = Command::new("zramctl")
483-
.stdout(Stdio::piped())
484-
.output();
538+
let zramctl_output = Command::new("zramctl").stdout(Stdio::piped()).output();
485539

486540
if let Ok(output) = zramctl_output {
487541
let output_str = String::from_utf8_lossy(&output.stdout);
488542
if output_str.contains("[SWAP]") {
489543
println!("\nZram:");
490544
for line in output_str.lines() {
491545
if line.starts_with("NAME") || line.contains("[SWAP]") {
492-
let line = line.trim_end_matches("[SWAP]").trim_end_matches("MOUNTPOINT").trim();
546+
let line = line
547+
.trim_end_matches("[SWAP]")
548+
.trim_end_matches("MOUNTPOINT")
549+
.trim();
493550
println!(" {}", line);
494551
}
495552
}
@@ -513,4 +570,3 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
513570

514571
Ok(())
515572
}
516-

0 commit comments

Comments
 (0)