linuxutils_system/
swapoff.rs1use 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#[derive(Parser)]
19#[command(
20 name = "swapoff",
21 about = "Disable devices and files for paging and swapping"
22)]
23pub struct Args {
24 #[arg(short = 'a', long)]
26 all: bool,
27
28 #[arg(short = 'v', long)]
30 verbose: bool,
31
32 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}