linuxutils_system/
renice.rs1use linuxutils_common::man::ManContent;
2
3pub const MAN: ManContent = ManContent::empty();
4
5use clap::Parser;
6use rustix::process::{
7 Pid, Uid, getpriority_pgrp, getpriority_process, getpriority_user,
8 setpriority_pgrp, setpriority_process, setpriority_user,
9};
10use std::{ffi::CString, process::ExitCode};
11
12#[derive(Parser)]
13#[command(
14 name = "renice",
15 about = "Alter priority of running processes",
16 override_usage = "renice [-n|--priority|--relative] priority [-p|--pid] pid...\n \
17 renice [-n|--priority|--relative] priority -g|--pgrp pgid...\n \
18 renice [-n|--priority|--relative] priority -u|--user user..."
19)]
20pub struct Args {
21 #[arg(short = 'n', long = "priority", allow_hyphen_values = true)]
23 priority_flag: Option<i32>,
24
25 #[arg(long = "relative")]
27 relative: bool,
28
29 #[arg(short = 'p', long = "pid")]
31 pid: bool,
32
33 #[arg(short = 'g', long = "pgrp")]
35 pgrp: bool,
36
37 #[arg(short = 'u', long = "user")]
39 user: bool,
40
41 #[arg(required = true, allow_hyphen_values = true)]
43 args: Vec<String>,
44}
45
46fn resolve_uid(name: &str) -> Option<u32> {
47 let c_name = CString::new(name).ok()?;
48 let pw = unsafe { libc::getpwnam(c_name.as_ptr()) };
49 if pw.is_null() {
50 None
51 } else {
52 Some(unsafe { (*pw).pw_uid })
53 }
54}
55
56fn renice_pid(
57 pid_val: u32,
58 priority: i32,
59 relative: bool,
60) -> Result<(i32, i32), String> {
61 let pid = Pid::from_raw(pid_val as i32)
62 .ok_or_else(|| "invalid pid 0".to_string())?;
63 let old = getpriority_process(Some(pid)).map_err(|e| format!("{e}"))?;
64 let new_prio = if relative { old + priority } else { priority };
65 setpriority_process(Some(pid), new_prio).map_err(|e| format!("{e}"))?;
66 let actual = getpriority_process(Some(pid)).map_err(|e| format!("{e}"))?;
67 Ok((old, actual))
68}
69
70fn renice_pgrp(
71 pgid_val: u32,
72 priority: i32,
73 relative: bool,
74) -> Result<(i32, i32), String> {
75 let pgid = if pgid_val == 0 {
76 None
77 } else {
78 Some(
79 Pid::from_raw(pgid_val as i32)
80 .ok_or_else(|| "invalid pgid".to_string())?,
81 )
82 };
83 let old = getpriority_pgrp(pgid).map_err(|e| format!("{e}"))?;
84 let new_prio = if relative { old + priority } else { priority };
85 setpriority_pgrp(pgid, new_prio).map_err(|e| format!("{e}"))?;
86 let actual = getpriority_pgrp(pgid).map_err(|e| format!("{e}"))?;
87 Ok((old, actual))
88}
89
90fn renice_user(
91 uid_val: u32,
92 priority: i32,
93 relative: bool,
94) -> Result<(i32, i32), String> {
95 let uid = Uid::from_raw(uid_val);
96 let old = getpriority_user(uid).map_err(|e| format!("{e}"))?;
97 let new_prio = if relative { old + priority } else { priority };
98 setpriority_user(uid, new_prio).map_err(|e| format!("{e}"))?;
99 let actual = getpriority_user(uid).map_err(|e| format!("{e}"))?;
100 Ok((old, actual))
101}
102
103pub fn run(args: Args) -> ExitCode {
104 let (priority, targets) = if let Some(p) = args.priority_flag {
105 (p, args.args.as_slice())
106 } else {
107 let Some(first) = args.args.first() else {
108 eprintln!("renice: missing priority");
109 return ExitCode::FAILURE;
110 };
111 let p: i32 = match first.parse() {
112 Ok(v) => v,
113 Err(_) => {
114 eprintln!("renice: invalid priority '{first}'");
115 return ExitCode::FAILURE;
116 }
117 };
118 if args.args.len() < 2 {
119 eprintln!("renice: missing target");
120 return ExitCode::FAILURE;
121 }
122 (p, &args.args[1..])
123 };
124
125 let mut failed = false;
126
127 for target in targets {
128 if args.user {
129 let uid = match target.parse::<u32>() {
130 Ok(uid) => uid,
131 Err(_) => match resolve_uid(target) {
132 Some(uid) => uid,
133 None => {
134 eprintln!("renice: unknown user {target}");
135 failed = true;
136 continue;
137 }
138 },
139 };
140 match renice_user(uid, priority, args.relative) {
141 Ok((old, new)) => println!(
142 "{uid} (user ID) old priority {old}, new priority {new}"
143 ),
144 Err(e) => {
145 eprintln!(
146 "renice: failed to set priority for user {target}: {e}"
147 );
148 failed = true;
149 }
150 }
151 } else if args.pgrp {
152 let pgid: u32 = match target.parse() {
153 Ok(v) => v,
154 Err(_) => {
155 eprintln!("renice: invalid process group ID '{target}'");
156 failed = true;
157 continue;
158 }
159 };
160 match renice_pgrp(pgid, priority, args.relative) {
161 Ok((old, new)) => {
162 println!(
163 "{pgid} (process group ID) old priority {old}, new priority {new}"
164 )
165 }
166 Err(e) => {
167 eprintln!(
168 "renice: failed to set priority for pgid {pgid}: {e}"
169 );
170 failed = true;
171 }
172 }
173 } else {
174 let pid: u32 = match target.parse() {
175 Ok(v) => v,
176 Err(_) => {
177 eprintln!("renice: invalid process ID '{target}'");
178 failed = true;
179 continue;
180 }
181 };
182 match renice_pid(pid, priority, args.relative) {
183 Ok((old, new)) => {
184 println!(
185 "{pid} (process ID) old priority {old}, new priority {new}"
186 )
187 }
188 Err(e) => {
189 eprintln!(
190 "renice: failed to set priority for pid {pid}: {e}"
191 );
192 failed = true;
193 }
194 }
195 }
196 }
197
198 if failed {
199 ExitCode::FAILURE
200 } else {
201 ExitCode::SUCCESS
202 }
203}