Skip to content

Commit 3c577c7

Browse files
committed
translate selected format!/print strings in sudo
1 parent fb3f94d commit 3c577c7

File tree

6 files changed

+111
-54
lines changed

6 files changed

+111
-54
lines changed

src/pam/askpass.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::{io, process};
77
use libc::O_CLOEXEC;
88

99
use crate::cutils::cerr;
10+
use crate::log::user_error;
1011
use crate::system::interface::ProcessId;
1112
use crate::system::{fork, mark_fds_as_cloexec, ForkResult};
1213

@@ -50,9 +51,10 @@ fn handle_child(program: &Path, prompt: &str, stdout: OwnedFd) -> ! {
5051

5152
// Exec askpass program
5253
let error = Command::new(program).arg(prompt).stdout(stdout).exec();
53-
eprintln_ignore_io_error!(
54-
"Failed to run askpass program {}: {error}",
55-
program.display()
54+
user_error!(
55+
"Failed to run askpass program {path}: {error}",
56+
path = program.display(),
57+
error = error
5658
);
5759
process::exit(1);
5860
}

src/sudo/cli/mod.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::os::unix::ffi::OsStrExt;
44
use std::{borrow::Cow, mem};
55

66
use crate::common::{SudoPath, SudoString};
7+
use crate::gettext::xlat;
78
use crate::log::user_warn;
89

910
pub mod help;
@@ -557,14 +558,17 @@ impl SudoArg {
557558
// only accept arguments when one is expected
558559
// `--preserve-env` is special as it only takes an argument using this `key=value` syntax
559560
if !Self::TAKES_ARGUMENT.contains(&key) && key != "preserve-env" {
560-
Err(format!("'{key}' does not take any arguments"))?;
561+
Err(xlat!(
562+
"'{option}' does not take any arguments",
563+
option = key
564+
))?;
561565
}
562566
processed.push(SudoArg::Argument("--".to_string() + key, value.to_string()));
563567
} else if Self::TAKES_ARGUMENT.contains(&unprefixed) {
564568
if let Some(next) = arg_iter.next() {
565569
processed.push(SudoArg::Argument(arg, next));
566570
} else {
567-
Err(format!("'{arg}' expects an argument"))?;
571+
Err(xlat!("'{option}' expects an argument", option = arg))?;
568572
}
569573
} else {
570574
processed.push(SudoArg::Flag(arg));
@@ -592,7 +596,7 @@ impl SudoArg {
592596
// short version of --help has no arguments
593597
processed.push(SudoArg::Flag(flag));
594598
} else {
595-
Err(format!("'-{curr}' expects an argument"))?;
599+
Err(xlat!("'-{option}' expects an argument", option = curr))?;
596600
}
597601
break;
598602
} else {
@@ -813,7 +817,11 @@ fn ensure_is_absent(context: &str, thing: &dyn IsAbsent, name: &str) -> Result<(
813817
if thing.is_absent() {
814818
Ok(())
815819
} else {
816-
Err(format!("{context} cannot be used together with {name}"))
820+
Err(xlat!(
821+
"{context} cannot be used together with {option}",
822+
context = context,
823+
option = name
824+
))
817825
}
818826
}
819827

src/sudo/edit.rs

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::{io, process};
1010

1111
use crate::common::SudoPath;
1212
use crate::exec::ExitReason;
13+
use crate::gettext::xlat;
1314
use crate::log::{user_error, user_info};
1415
use crate::system::file::{create_temporary_dir, FileLock};
1516
use crate::system::wait::{Wait, WaitError, WaitOptions};
@@ -42,25 +43,43 @@ pub(super) fn edit_files(
4243
let metadata = file.metadata().map_err(|e| {
4344
io::Error::new(
4445
e.kind(),
45-
format!("Failed to read metadata for {}: {e}", path.display()),
46+
xlat!(
47+
"failed to read metadata for {path}: {error}",
48+
path = path.display(),
49+
error = e
50+
),
4651
)
4752
})?;
4853
if !metadata.is_file() {
4954
return Err(io::Error::new(
5055
io::ErrorKind::Other,
51-
format!("File {} is not a regular file", path.display()),
56+
xlat!("file {path} is not a regular file", path = path.display()),
5257
));
5358
}
5459

5560
// Take file lock
5661
let lock = FileLock::exclusive(&file, true).map_err(|e| {
57-
io::Error::new(e.kind(), format!("Failed to lock {}: {e}", path.display()))
62+
io::Error::new(
63+
e.kind(),
64+
xlat!(
65+
"failed to lock {path}: {error}",
66+
path = path.display(),
67+
error = e
68+
),
69+
)
5870
})?;
5971

6072
// Read file
6173
let mut old_data = Vec::new();
6274
file.read_to_end(&mut old_data).map_err(|e| {
63-
io::Error::new(e.kind(), format!("Failed to read {}: {e}", path.display()))
75+
io::Error::new(
76+
e.kind(),
77+
xlat!(
78+
"failed to read {path}: {error}",
79+
path = path.display(),
80+
error = e
81+
),
82+
)
6483
})?;
6584

6685
// Create socket
@@ -142,7 +161,11 @@ pub(super) fn edit_files(
142161
.map_err(|e| {
143162
io::Error::new(
144163
e.kind(),
145-
format!("Failed to write {}: {e}", file.path.display()),
164+
xlat!(
165+
"failed to write {path}: {error}",
166+
path = file.path.display(),
167+
error = e
168+
),
146169
)
147170
})?;
148171

@@ -186,16 +209,18 @@ fn handle_child_inner(editor: &Path, mut files: Vec<ChildFileInfo<'_>>) -> Resul
186209
}
187210

188211
let tempdir = TempDirDropGuard(
189-
create_temporary_dir().map_err(|e| format!("failed to create temporary directory: {e}"))?,
212+
create_temporary_dir()
213+
.map_err(|e| xlat!("failed to create temporary directory: {error}", error = e))?,
190214
);
191215

192216
for (i, file) in files.iter_mut().enumerate() {
193217
// Create temp file
194218
let dir = tempdir.0.join(format!("{i}"));
195219
std::fs::create_dir(&dir).map_err(|e| {
196-
format!(
197-
"failed to create temporary directory {}: {e}",
198-
dir.display(),
220+
xlat!(
221+
"failed to create temporary directory {path}: {error}",
222+
path = dir.display(),
223+
error = e
199224
)
200225
})?;
201226
let tempfile_path = dir.join(file.path.file_name().expect("file must have filename"));
@@ -206,17 +231,19 @@ fn handle_child_inner(editor: &Path, mut files: Vec<ChildFileInfo<'_>>) -> Resul
206231
.mode(0o600)
207232
.open(&tempfile_path)
208233
.map_err(|e| {
209-
format!(
210-
"failed to create temporary file {}: {e}",
211-
tempfile_path.display(),
234+
xlat!(
235+
"failed to create temporary file {path}: {error}",
236+
path = tempfile_path.display(),
237+
error = e
212238
)
213239
})?;
214240

215241
// Write to temp file
216242
tempfile.write_all(&file.old_data).map_err(|e| {
217-
format!(
218-
"failed to write to temporary file {}: {e}",
219-
tempfile_path.display(),
243+
xlat!(
244+
"failed to write to temporary file {path}: {error}",
245+
path = tempfile_path.display(),
246+
error = e
220247
)
221248
})?;
222249
drop(tempfile);
@@ -231,7 +258,13 @@ fn handle_child_inner(editor: &Path, mut files: Vec<ChildFileInfo<'_>>) -> Resul
231258
.map(|file| file.tempfile_path.as_ref().expect("filled in above")),
232259
)
233260
.status()
234-
.map_err(|e| format!("failed to run editor {}: {e}", editor.display()))?;
261+
.map_err(|e| {
262+
xlat!(
263+
"failed to run editor {path}: {error}",
264+
path = editor.display(),
265+
error = e
266+
)
267+
})?;
235268

236269
if !status.success() {
237270
drop(tempdir);
@@ -247,26 +280,28 @@ fn handle_child_inner(editor: &Path, mut files: Vec<ChildFileInfo<'_>>) -> Resul
247280

248281
// Read from temp file
249282
let new_data = std::fs::read(tempfile_path).map_err(|e| {
250-
format!(
251-
"failed to read from temporary file {}: {e}",
252-
tempfile_path.display(),
283+
xlat!(
284+
"failed to read from temporary file {path}: {error}",
285+
path = tempfile_path.display(),
286+
error = e
253287
)
254288
})?;
255289

256290
// FIXME preserve temporary file if the original couldn't be written to
257291
std::fs::remove_file(tempfile_path).map_err(|e| {
258-
format!(
259-
"failed to remove temporary file {}: {e}",
260-
tempfile_path.display(),
292+
xlat!(
293+
"failed to remove temporary file {path}: {error}",
294+
path = tempfile_path.display(),
295+
error = e
261296
)
262297
})?;
263298

264299
// If the file has been changed to be empty, ask the user what to do.
265300
if new_data.is_empty() && new_data != file.old_data {
266301
match crate::visudo::ask_response(
267-
format!(
268-
"sudoedit: truncate {} to zero? (y/n) [n] ",
269-
file.path.display()
302+
xlat!(
303+
"sudoedit: truncate {path} to zero? (y/n) [n] ",
304+
path = file.path.display()
270305
)
271306
.as_bytes(),
272307
b"yn",
@@ -277,7 +312,7 @@ fn handle_child_inner(editor: &Path, mut files: Vec<ChildFileInfo<'_>>) -> Resul
277312

278313
// Parent ignores write when new data matches old data
279314
write_stream(&mut file.new_data_tx, &file.old_data)
280-
.map_err(|e| format!("failed to write data to parent: {e}"))?;
315+
.map_err(|e| xlat!("failed to write data to parent: {error}", error = e))?;
281316

282317
continue;
283318
}
@@ -286,7 +321,7 @@ fn handle_child_inner(editor: &Path, mut files: Vec<ChildFileInfo<'_>>) -> Resul
286321

287322
// Write to socket
288323
write_stream(&mut file.new_data_tx, &new_data)
289-
.map_err(|e| format!("failed to write data to parent: {e}"))?;
324+
.map_err(|e| xlat!("failed to write data to parent: {error}", error = e))?;
290325
}
291326

292327
process::exit(0);

src/sudo/pipeline.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use super::diagnostic;
77
use crate::common::resolve::{AuthUser, CurrentUser};
88
use crate::common::{Context, Error};
99
use crate::exec::ExitReason;
10+
use crate::gettext::xlat;
1011
use crate::log::{auth_info, auth_warn};
1112
use crate::pam::PamContext;
1213
use crate::sudo::env::environment;
@@ -28,19 +29,19 @@ fn read_sudoers() -> Result<Sudoers, Error> {
2829
let (sudoers, syntax_errors) = Sudoers::open(sudoers_path).map_err(|e| {
2930
// Provide a more helpful error message when the sudoers file is missing
3031
if e.kind() == std::io::ErrorKind::NotFound {
31-
Error::Configuration(format!(
32-
"sudoers file not found: {}\n\
32+
Error::Configuration(xlat!(
33+
"sudoers file not found: {path}\n\
3334
\n\
3435
The sudoers file is required for sudo-rs to function. Please ensure:\n\
3536
- The file exists at the expected location\n\
3637
- You have the necessary permissions to read it\n\
3738
- If setting up sudo-rs for the first time, create a sudoers file with appropriate permissions\n\
3839
\n\
3940
For more information, see the sudo-rs documentation.",
40-
sudoers_path.display()
41+
path = sudoers_path.display()
4142
))
4243
} else {
43-
Error::Configuration(format!("invalid configuration: {e}"))
44+
Error::Configuration(xlat!("invalid configuration: {error}", error = e))
4445
}
4546
})?;
4647

src/sudo/pipeline/list.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::{borrow::Cow, ops::ControlFlow, path::Path};
22

33
use crate::{
44
common::{Context, Error},
5+
gettext::xlat,
56
sudo::cli::SudoListOptions,
67
sudoers::{Authorization, ListRequest, Request, Sudoers},
78
system::User,
@@ -40,9 +41,12 @@ pub(in crate::sudo) fn run_list(cmd_opts: SudoListOptions) -> Result<(), Error>
4041

4142
if matching_entries.peek().is_some() {
4243
println_ignore_io_error!(
43-
"User {} may run the following commands on {}:",
44-
inspected_user.name,
45-
context.hostname
44+
"{}",
45+
xlat!(
46+
"User {user} may run the following commands on {hostname}:",
47+
user = inspected_user.name,
48+
hostname = context.hostname
49+
)
4650
);
4751

4852
for entry in matching_entries {
@@ -55,9 +59,12 @@ pub(in crate::sudo) fn run_list(cmd_opts: SudoListOptions) -> Result<(), Error>
5559
}
5660
} else {
5761
println_ignore_io_error!(
58-
"User {} is not allowed to run sudo on {}.",
59-
inspected_user.name,
60-
context.hostname
62+
"{}",
63+
xlat!(
64+
"User {user} is not allowed to run sudo on {hostname}.",
65+
user = inspected_user.name,
66+
hostname = context.hostname,
67+
),
6168
);
6269
}
6370
}

src/system/audit.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use super::{
1414
cerr, inject_group, interface::UnixUser, set_supplementary_groups, Group, GroupId, User, UserId,
1515
};
1616
use crate::common::resolve::CurrentUser;
17+
use crate::gettext::xlat;
1718

1819
/// Temporary change privileges --- essentially a 'mini sudo'
1920
/// This is only used for sudoedit.
@@ -129,16 +130,19 @@ fn checks(path: &Path, meta: Metadata) -> io::Result<()> {
129130

130131
let path_mode = meta.permissions().mode();
131132
if meta.uid() != 0 {
132-
Err(error(format!("{} must be owned by root", path.display())))
133+
Err(error(xlat!(
134+
"{path} must be owned by root",
135+
path = path.display()
136+
)))
133137
} else if meta.gid() != 0 && (path_mode & mode(Category::Group, Op::Write) != 0) {
134-
Err(error(format!(
135-
"{} cannot be group-writable",
136-
path.display()
138+
Err(error(xlat!(
139+
"{path} cannot be group-writable",
140+
path = path.display()
137141
)))
138142
} else if path_mode & mode(Category::World, Op::Write) != 0 {
139-
Err(error(format!(
140-
"{} cannot be world-writable",
141-
path.display()
143+
Err(error(xlat!(
144+
"{path} cannot be world-writable",
145+
path = path.display()
142146
)))
143147
} else {
144148
Ok(())
@@ -177,9 +181,9 @@ fn secure_open_impl(
177181
checks(parent_dir, parent_meta)?;
178182
}
179183
} else {
180-
return Err(error(format!(
181-
"{} has no valid parent directory",
182-
path.display()
184+
return Err(error(xlat!(
185+
"{path} has no valid parent directory",
186+
path = path.display()
183187
)));
184188
}
185189
}

0 commit comments

Comments
 (0)