Skip to main content

linuxutils_system/
swapoff.rs

1use linuxutils_common::man::ManContent;
2
3pub const MAN: ManContent = ManContent::empty();
4
5use clap::Parser;
6use std::{
7    ffi::CString,
8    fs::File,
9    io::{self, BufRead},
10    process::ExitCode,
11};
12
13/// Disable devices and files for paging and swapping.
14///
15/// Calls swapoff(2) to deactivate swap areas. The kernel pages all
16/// swap contents back to RAM before deactivating, which may take
17/// significant time if the swap is heavily used.
18#[derive(Parser)]
19#[command(
20    name = "swapoff",
21    about = "Disable devices and files for paging and swapping"
22)]
23pub struct Args {
24    /// Disable all active swap areas
25    #[arg(short = 'a', long)]
26    all: bool,
27
28    /// Verbose output
29    #[arg(short = 'v', long)]
30    verbose: bool,
31
32    /// Devices or files to disable
33    devices: Vec<String>,
34}
35
36fn read_active_swaps() -> Vec<String> {
37    let Ok(file) = File::open("/proc/swaps") else {
38        return Vec::new();
39    };
40    io::BufReader::new(file)
41        .lines()
42        .map_while(Result::ok)
43        .skip(1)
44        .filter_map(|line| {
45            line.split_whitespace().next().map(|s| s.to_string())
46        })
47        .collect()
48}
49
50fn do_swapoff(path: &str) -> io::Result<()> {
51    let cpath =
52        CString::new(path).map_err(|e| io::Error::other(e.to_string()))?;
53    if unsafe { libc::swapoff(cpath.as_ptr()) } < 0 {
54        Err(io::Error::last_os_error())
55    } else {
56        Ok(())
57    }
58}
59
60pub fn run(args: Args) -> ExitCode {
61    let devices = if args.all {
62        read_active_swaps()
63    } else if args.devices.is_empty() {
64        eprintln!("swapoff: no device specified. Try 'swapoff --help'");
65        return ExitCode::from(16);
66    } else {
67        args.devices.clone()
68    };
69
70    let mut successes = 0;
71    let mut failures = 0;
72
73    for device in &devices {
74        if args.verbose {
75            eprintln!("swapoff: disabling {device}");
76        }
77        if let Err(e) = do_swapoff(device) {
78            eprintln!("swapoff: {device}: {e}");
79            failures += 1;
80        } else {
81            successes += 1;
82        }
83    }
84
85    if failures == 0 {
86        ExitCode::SUCCESS
87    } else if args.all && successes == 0 {
88        ExitCode::from(32)
89    } else if args.all {
90        ExitCode::from(64)
91    } else {
92        ExitCode::from(4)
93    }
94}