1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge pull request #8086 from sylvestre/l10n-chcon

l10n: port chcon to translation + add french
This commit is contained in:
Daniel Hofstetter 2025-06-09 10:56:56 +02:00 committed by GitHub
commit 3b225aa1a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 281 additions and 100 deletions

View file

@ -3,3 +3,56 @@ chcon-about = Change the SELinux security context of each FILE to CONTEXT.
chcon-usage = chcon [OPTION]... CONTEXT FILE... chcon-usage = chcon [OPTION]... CONTEXT FILE...
chcon [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE... chcon [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE...
chcon [OPTION]... --reference=RFILE FILE... chcon [OPTION]... --reference=RFILE FILE...
# Help messages
chcon-help-help = Print help information.
chcon-help-dereference = Affect the referent of each symbolic link (this is the default), rather than the symbolic link itself.
chcon-help-no-dereference = Affect symbolic links instead of any referenced file.
chcon-help-preserve-root = Fail to operate recursively on '/'.
chcon-help-no-preserve-root = Do not treat '/' specially (the default).
chcon-help-reference = Use security context of RFILE, rather than specifying a CONTEXT value.
chcon-help-user = Set user USER in the target security context.
chcon-help-role = Set role ROLE in the target security context.
chcon-help-type = Set type TYPE in the target security context.
chcon-help-range = Set range RANGE in the target security context.
chcon-help-recursive = Operate on files and directories recursively.
chcon-help-follow-arg-dir-symlink = If a command line argument is a symbolic link to a directory, traverse it. Only valid when -R is specified.
chcon-help-follow-dir-symlinks = Traverse every symbolic link to a directory encountered. Only valid when -R is specified.
chcon-help-no-follow-symlinks = Do not traverse any symbolic links (default). Only valid when -R is specified.
chcon-help-verbose = Output a diagnostic for every file processed.
# Error messages - basic validation
chcon-error-no-context-specified = No context is specified
chcon-error-no-files-specified = No files are specified
chcon-error-data-out-of-range = Data is out of range
chcon-error-operation-failed = { $operation } failed
chcon-error-operation-failed-on = { $operation } failed on { $operand }
# Error messages - argument validation
chcon-error-invalid-context = Invalid security context '{ $context }'.
chcon-error-recursive-no-dereference-require-p = '--recursive' with '--no-dereference' require '-P'
chcon-error-recursive-dereference-require-h-or-l = '--recursive' with '--dereference' require either '-H' or '-L'
# Operation strings for error context
chcon-op-getting-security-context = Getting security context
chcon-op-file-name-validation = File name validation
chcon-op-getting-meta-data = Getting meta data
chcon-op-modifying-root-path = Modifying root path
chcon-op-accessing = Accessing
chcon-op-reading-directory = Reading directory
chcon-op-reading-cyclic-directory = Reading cyclic directory
chcon-op-applying-partial-context = Applying partial security context to unlabeled file
chcon-op-creating-security-context = Creating security context
chcon-op-setting-security-context-user = Setting security context user
chcon-op-setting-security-context = Setting security context
# Verbose output
chcon-verbose-changing-context = { $util_name }: changing security context of { $file }
# Warning messages
chcon-warning-dangerous-recursive-root = It is dangerous to operate recursively on '/'. Use --{ $option } to override this failsafe.
chcon-warning-dangerous-recursive-dir = It is dangerous to operate recursively on { $dir } (same as '/'). Use --{ $option } to override this failsafe.
chcon-warning-circular-directory = Circular directory structure.
This almost certainly means that you have a corrupted file system.
NOTIFY YOUR SYSTEM MANAGER.
The following directory is part of the cycle { $file }.

View file

@ -0,0 +1,58 @@
chcon-about = Changer le contexte de sécurité SELinux de chaque FICHIER vers CONTEXTE.
Avec --reference, changer le contexte de sécurité de chaque FICHIER vers celui de RFICHIER.
chcon-usage = chcon [OPTION]... CONTEXTE FICHIER...
chcon [OPTION]... [-u UTILISATEUR] [-r RÔLE] [-l PLAGE] [-t TYPE] FICHIER...
chcon [OPTION]... --reference=RFICHIER FICHIER...
# Messages d'aide
chcon-help-help = Afficher les informations d'aide.
chcon-help-dereference = Affecter la cible de chaque lien symbolique (par défaut), plutôt que le lien symbolique lui-même.
chcon-help-no-dereference = Affecter les liens symboliques au lieu de tout fichier référencé.
chcon-help-preserve-root = Échouer lors de l'opération récursive sur '/'.
chcon-help-no-preserve-root = Ne pas traiter '/' spécialement (par défaut).
chcon-help-reference = Utiliser le contexte de sécurité de RFICHIER, plutôt que de spécifier une valeur CONTEXTE.
chcon-help-user = Définir l'utilisateur UTILISATEUR dans le contexte de sécurité cible.
chcon-help-role = Définir le rôle RÔLE dans le contexte de sécurité cible.
chcon-help-type = Définir le type TYPE dans le contexte de sécurité cible.
chcon-help-range = Définir la plage PLAGE dans le contexte de sécurité cible.
chcon-help-recursive = Opérer sur les fichiers et répertoires de manière récursive.
chcon-help-follow-arg-dir-symlink = Si un argument de ligne de commande est un lien symbolique vers un répertoire, le traverser. Valide uniquement quand -R est spécifié.
chcon-help-follow-dir-symlinks = Traverser chaque lien symbolique vers un répertoire rencontré. Valide uniquement quand -R est spécifié.
chcon-help-no-follow-symlinks = Ne traverser aucun lien symbolique (par défaut). Valide uniquement quand -R est spécifié.
chcon-help-verbose = Afficher un diagnostic pour chaque fichier traité.
# Messages d'erreur - validation de base
chcon-error-no-context-specified = Aucun contexte n'est spécifié
chcon-error-no-files-specified = Aucun fichier n'est spécifié
chcon-error-data-out-of-range = Données hors limites
chcon-error-operation-failed = { $operation } a échoué
chcon-error-operation-failed-on = { $operation } a échoué sur { $operand }
# Messages d'erreur - validation des arguments
chcon-error-invalid-context = Contexte de sécurité invalide '{ $context }'.
chcon-error-recursive-no-dereference-require-p = '--recursive' avec '--no-dereference' nécessite '-P'
chcon-error-recursive-dereference-require-h-or-l = '--recursive' avec '--dereference' nécessite soit '-H' soit '-L'
# Chaînes d'opération pour le contexte d'erreur
chcon-op-getting-security-context = Obtention du contexte de sécurité
chcon-op-file-name-validation = Validation du nom de fichier
chcon-op-getting-meta-data = Obtention des métadonnées
chcon-op-modifying-root-path = Modification du chemin racine
chcon-op-accessing = Accès
chcon-op-reading-directory = Lecture du répertoire
chcon-op-reading-cyclic-directory = Lecture du répertoire cyclique
chcon-op-applying-partial-context = Application d'un contexte de sécurité partiel à un fichier non étiqueté
chcon-op-creating-security-context = Création du contexte de sécurité
chcon-op-setting-security-context-user = Définition de l'utilisateur du contexte de sécurité
chcon-op-setting-security-context = Définition du contexte de sécurité
# Sortie détaillée
chcon-verbose-changing-context = { $util_name } : changement du contexte de sécurité de { $file }
# Messages d'avertissement
chcon-warning-dangerous-recursive-root = Il est dangereux d'opérer récursivement sur '/'. Utilisez --{ $option } pour outrepasser cette protection.
chcon-warning-dangerous-recursive-dir = Il est dangereux d'opérer récursivement sur { $dir } (identique à '/'). Utilisez --{ $option } pour outrepasser cette protection.
chcon-warning-circular-directory = Structure de répertoire circulaire.
Cela signifie presque certainement que vous avez un système de fichiers corrompu.
NOTIFIEZ VOTRE ADMINISTRATEUR SYSTÈME.
Le répertoire suivant fait partie du cycle { $file }.

View file

@ -14,6 +14,7 @@ use clap::{Arg, ArgAction, Command};
use selinux::{OpaqueSecurityContext, SecurityContext}; use selinux::{OpaqueSecurityContext, SecurityContext};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::{CStr, CString, OsStr, OsString}; use std::ffi::{CStr, CString, OsStr, OsString};
use std::os::raw::c_int; use std::os::raw::c_int;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -24,7 +25,7 @@ mod fts;
use errors::*; use errors::*;
use uucore::locale::get_message; use uucore::locale::{get_message, get_message_with_args};
pub mod options { pub mod options {
pub static HELP: &str = "help"; pub static HELP: &str = "help";
@ -78,10 +79,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Ok(None) => { Ok(None) => {
let err = io::Error::from_raw_os_error(libc::ENODATA); let err = io::Error::from_raw_os_error(libc::ENODATA);
Err(Error::from_io1("Getting security context", reference, err)) Err(Error::from_io1(
get_message("chcon-op-getting-security-context"),
reference,
err,
))
} }
Err(r) => Err(Error::from_selinux("Getting security context", r)), Err(r) => Err(Error::from_selinux(
get_message("chcon-op-getting-security-context"),
r,
)),
}; };
match result { match result {
@ -103,7 +111,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Err(_r) => { Err(_r) => {
return Err(USimpleError::new( return Err(USimpleError::new(
libc::EXIT_FAILURE, libc::EXIT_FAILURE,
format!("Invalid security context {}.", context.quote()), get_message_with_args(
"chcon-error-invalid-context",
HashMap::from([("context".to_string(), context.quote().to_string())]),
),
)); ));
} }
}; };
@ -111,7 +122,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
if SecurityContext::from_c_str(&c_context, false).check() == Some(false) { if SecurityContext::from_c_str(&c_context, false).check() == Some(false) {
return Err(USimpleError::new( return Err(USimpleError::new(
libc::EXIT_FAILURE, libc::EXIT_FAILURE,
format!("Invalid security context {}.", context.quote()), get_message_with_args(
"chcon-error-invalid-context",
HashMap::from([("context".to_string(), context.quote().to_string())]),
),
)); ));
} }
@ -158,37 +172,34 @@ pub fn uu_app() -> Command {
.arg( .arg(
Arg::new(options::HELP) Arg::new(options::HELP)
.long(options::HELP) .long(options::HELP)
.help("Print help information.") .help(get_message("chcon-help-help"))
.action(ArgAction::Help), .action(ArgAction::Help),
) )
.arg( .arg(
Arg::new(options::dereference::DEREFERENCE) Arg::new(options::dereference::DEREFERENCE)
.long(options::dereference::DEREFERENCE) .long(options::dereference::DEREFERENCE)
.overrides_with(options::dereference::NO_DEREFERENCE) .overrides_with(options::dereference::NO_DEREFERENCE)
.help( .help(get_message("chcon-help-dereference"))
"Affect the referent of each symbolic link (this is the default), \
rather than the symbolic link itself.",
)
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::dereference::NO_DEREFERENCE) Arg::new(options::dereference::NO_DEREFERENCE)
.short('h') .short('h')
.long(options::dereference::NO_DEREFERENCE) .long(options::dereference::NO_DEREFERENCE)
.help("Affect symbolic links instead of any referenced file.") .help(get_message("chcon-help-no-dereference"))
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::preserve_root::PRESERVE_ROOT) Arg::new(options::preserve_root::PRESERVE_ROOT)
.long(options::preserve_root::PRESERVE_ROOT) .long(options::preserve_root::PRESERVE_ROOT)
.overrides_with(options::preserve_root::NO_PRESERVE_ROOT) .overrides_with(options::preserve_root::NO_PRESERVE_ROOT)
.help("Fail to operate recursively on '/'.") .help(get_message("chcon-help-preserve-root"))
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::preserve_root::NO_PRESERVE_ROOT) Arg::new(options::preserve_root::NO_PRESERVE_ROOT)
.long(options::preserve_root::NO_PRESERVE_ROOT) .long(options::preserve_root::NO_PRESERVE_ROOT)
.help("Do not treat '/' specially (the default).") .help(get_message("chcon-help-no-preserve-root"))
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
@ -197,10 +208,7 @@ pub fn uu_app() -> Command {
.value_name("RFILE") .value_name("RFILE")
.value_hint(clap::ValueHint::FilePath) .value_hint(clap::ValueHint::FilePath)
.conflicts_with_all([options::USER, options::ROLE, options::TYPE, options::RANGE]) .conflicts_with_all([options::USER, options::ROLE, options::TYPE, options::RANGE])
.help( .help(get_message("chcon-help-reference"))
"Use security context of RFILE, rather than specifying \
a CONTEXT value.",
)
.value_parser(ValueParser::os_string()), .value_parser(ValueParser::os_string()),
) )
.arg( .arg(
@ -209,7 +217,7 @@ pub fn uu_app() -> Command {
.long(options::USER) .long(options::USER)
.value_name("USER") .value_name("USER")
.value_hint(clap::ValueHint::Username) .value_hint(clap::ValueHint::Username)
.help("Set user USER in the target security context.") .help(get_message("chcon-help-user"))
.value_parser(ValueParser::os_string()), .value_parser(ValueParser::os_string()),
) )
.arg( .arg(
@ -217,7 +225,7 @@ pub fn uu_app() -> Command {
.short('r') .short('r')
.long(options::ROLE) .long(options::ROLE)
.value_name("ROLE") .value_name("ROLE")
.help("Set role ROLE in the target security context.") .help(get_message("chcon-help-role"))
.value_parser(ValueParser::os_string()), .value_parser(ValueParser::os_string()),
) )
.arg( .arg(
@ -225,7 +233,7 @@ pub fn uu_app() -> Command {
.short('t') .short('t')
.long(options::TYPE) .long(options::TYPE)
.value_name("TYPE") .value_name("TYPE")
.help("Set type TYPE in the target security context.") .help(get_message("chcon-help-type"))
.value_parser(ValueParser::os_string()), .value_parser(ValueParser::os_string()),
) )
.arg( .arg(
@ -233,14 +241,14 @@ pub fn uu_app() -> Command {
.short('l') .short('l')
.long(options::RANGE) .long(options::RANGE)
.value_name("RANGE") .value_name("RANGE")
.help("Set range RANGE in the target security context.") .help(get_message("chcon-help-range"))
.value_parser(ValueParser::os_string()), .value_parser(ValueParser::os_string()),
) )
.arg( .arg(
Arg::new(options::RECURSIVE) Arg::new(options::RECURSIVE)
.short('R') .short('R')
.long(options::RECURSIVE) .long(options::RECURSIVE)
.help("Operate on files and directories recursively.") .help(get_message("chcon-help-recursive"))
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
@ -251,10 +259,7 @@ pub fn uu_app() -> Command {
options::sym_links::FOLLOW_DIR_SYM_LINKS, options::sym_links::FOLLOW_DIR_SYM_LINKS,
options::sym_links::NO_FOLLOW_SYM_LINKS, options::sym_links::NO_FOLLOW_SYM_LINKS,
]) ])
.help( .help(get_message("chcon-help-follow-arg-dir-symlink"))
"If a command line argument is a symbolic link to a directory, \
traverse it. Only valid when -R is specified.",
)
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
@ -265,10 +270,7 @@ pub fn uu_app() -> Command {
options::sym_links::FOLLOW_ARG_DIR_SYM_LINK, options::sym_links::FOLLOW_ARG_DIR_SYM_LINK,
options::sym_links::NO_FOLLOW_SYM_LINKS, options::sym_links::NO_FOLLOW_SYM_LINKS,
]) ])
.help( .help(get_message("chcon-help-follow-dir-symlinks"))
"Traverse every symbolic link to a directory encountered. \
Only valid when -R is specified.",
)
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
@ -279,17 +281,14 @@ pub fn uu_app() -> Command {
options::sym_links::FOLLOW_ARG_DIR_SYM_LINK, options::sym_links::FOLLOW_ARG_DIR_SYM_LINK,
options::sym_links::FOLLOW_DIR_SYM_LINKS, options::sym_links::FOLLOW_DIR_SYM_LINKS,
]) ])
.help( .help(get_message("chcon-help-no-follow-symlinks"))
"Do not traverse any symbolic links (default). \
Only valid when -R is specified.",
)
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::VERBOSE) Arg::new(options::VERBOSE)
.short('v') .short('v')
.long(options::VERBOSE) .long(options::VERBOSE)
.help("Output a diagnostic for every file processed.") .help(get_message("chcon-help-verbose"))
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
@ -319,30 +318,24 @@ fn parse_command_line(config: Command, args: impl uucore::Args) -> Result<Option
let (recursive_mode, affect_symlink_referent) = if matches.get_flag(options::RECURSIVE) { let (recursive_mode, affect_symlink_referent) = if matches.get_flag(options::RECURSIVE) {
if matches.get_flag(options::sym_links::FOLLOW_DIR_SYM_LINKS) { if matches.get_flag(options::sym_links::FOLLOW_DIR_SYM_LINKS) {
if matches.get_flag(options::dereference::NO_DEREFERENCE) { if matches.get_flag(options::dereference::NO_DEREFERENCE) {
return Err(Error::ArgumentsMismatch(format!( return Err(Error::ArgumentsMismatch(get_message(
"'--{}' with '--{}' require '-P'", "chcon-error-recursive-no-dereference-require-p",
options::RECURSIVE,
options::dereference::NO_DEREFERENCE
))); )));
} }
(RecursiveMode::RecursiveAndFollowAllDirSymLinks, true) (RecursiveMode::RecursiveAndFollowAllDirSymLinks, true)
} else if matches.get_flag(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK) { } else if matches.get_flag(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK) {
if matches.get_flag(options::dereference::NO_DEREFERENCE) { if matches.get_flag(options::dereference::NO_DEREFERENCE) {
return Err(Error::ArgumentsMismatch(format!( return Err(Error::ArgumentsMismatch(get_message(
"'--{}' with '--{}' require '-P'", "chcon-error-recursive-no-dereference-require-p",
options::RECURSIVE,
options::dereference::NO_DEREFERENCE
))); )));
} }
(RecursiveMode::RecursiveAndFollowArgDirSymLinks, true) (RecursiveMode::RecursiveAndFollowArgDirSymLinks, true)
} else { } else {
if matches.get_flag(options::dereference::DEREFERENCE) { if matches.get_flag(options::dereference::DEREFERENCE) {
return Err(Error::ArgumentsMismatch(format!( return Err(Error::ArgumentsMismatch(get_message(
"'--{}' with '--{}' require either '-H' or '-L'", "chcon-error-recursive-dereference-require-h-or-l",
options::RECURSIVE,
options::dereference::DEREFERENCE
))); )));
} }
@ -516,12 +509,19 @@ fn process_file(
let mut entry = fts.last_entry_ref().unwrap(); let mut entry = fts.last_entry_ref().unwrap();
let file_full_name = entry.path().map(PathBuf::from).ok_or_else(|| { let file_full_name = entry.path().map(PathBuf::from).ok_or_else(|| {
Error::from_io("File name validation", io::ErrorKind::InvalidInput.into()) Error::from_io(
get_message("chcon-op-file-name-validation"),
io::ErrorKind::InvalidInput.into(),
)
})?; })?;
let fts_access_path = entry.access_path().ok_or_else(|| { let fts_access_path = entry.access_path().ok_or_else(|| {
let err = io::ErrorKind::InvalidInput.into(); let err = io::ErrorKind::InvalidInput.into();
Error::from_io1("File name validation", &file_full_name, err) Error::from_io1(
get_message("chcon-op-file-name-validation"),
&file_full_name,
err,
)
})?; })?;
let err = |s, k: io::ErrorKind| Error::from_io1(s, &file_full_name, k.into()); let err = |s, k: io::ErrorKind| Error::from_io1(s, &file_full_name, k.into());
@ -535,7 +535,10 @@ fn process_file(
let file_dev_ino: DeviceAndINode = if let Some(st) = entry.stat() { let file_dev_ino: DeviceAndINode = if let Some(st) = entry.stat() {
st.try_into()? st.try_into()?
} else { } else {
return Err(err("Getting meta data", io::ErrorKind::InvalidInput)); return Err(err(
get_message("chcon-op-getting-meta-data"),
io::ErrorKind::InvalidInput,
));
}; };
let mut result = Ok(()); let mut result = Ok(());
@ -554,7 +557,10 @@ fn process_file(
// Ensure that we do not process "/" on the second visit. // Ensure that we do not process "/" on the second visit.
let _ignored = fts.read_next_entry(); let _ignored = fts.read_next_entry();
return Err(err("Modifying root path", io::ErrorKind::PermissionDenied)); return Err(err(
get_message("chcon-op-modifying-root-path"),
io::ErrorKind::PermissionDenied,
));
} }
return Ok(()); return Ok(());
@ -579,17 +585,20 @@ fn process_file(
return Ok(()); return Ok(());
} }
result = fts_err("Accessing"); result = fts_err(get_message("chcon-op-accessing"));
} }
fts_sys::FTS_ERR => result = fts_err("Accessing"), fts_sys::FTS_ERR => result = fts_err(get_message("chcon-op-accessing")),
fts_sys::FTS_DNR => result = fts_err("Reading directory"), fts_sys::FTS_DNR => result = fts_err(get_message("chcon-op-reading-directory")),
fts_sys::FTS_DC => { fts_sys::FTS_DC => {
if cycle_warning_required(options.recursive_mode.fts_open_options(), &entry) { if cycle_warning_required(options.recursive_mode.fts_open_options(), &entry) {
emit_cycle_warning(&file_full_name); emit_cycle_warning(&file_full_name);
return Err(err("Reading cyclic directory", io::ErrorKind::InvalidData)); return Err(err(
get_message("chcon-op-reading-cyclic-directory"),
io::ErrorKind::InvalidData,
));
} }
} }
@ -601,15 +610,23 @@ fn process_file(
&& root_dev_ino_check(root_dev_ino, file_dev_ino) && root_dev_ino_check(root_dev_ino, file_dev_ino)
{ {
root_dev_ino_warn(&file_full_name); root_dev_ino_warn(&file_full_name);
result = Err(err("Modifying root path", io::ErrorKind::PermissionDenied)); result = Err(err(
get_message("chcon-op-modifying-root-path"),
io::ErrorKind::PermissionDenied,
));
} }
if result.is_ok() { if result.is_ok() {
if options.verbose { if options.verbose {
println!( println!(
"{}: changing security context of {}", "{}",
uucore::util_name(), get_message_with_args(
file_full_name.quote() "chcon-verbose-changing-context",
HashMap::from([
("util_name".to_string(), uucore::util_name().to_string()),
("file".to_string(), file_full_name.quote().to_string())
])
)
); );
} }
@ -637,7 +654,7 @@ fn change_file_context(
let err0 = || -> Result<()> { let err0 = || -> Result<()> {
// If the file doesn't have a context, and we're not setting all of the context // If the file doesn't have a context, and we're not setting all of the context
// components, there isn't really an obvious default. Thus, we just give up. // components, there isn't really an obvious default. Thus, we just give up.
let op = "Applying partial security context to unlabeled file"; let op = get_message("chcon-op-applying-partial-context");
let err = io::ErrorKind::InvalidInput.into(); let err = io::ErrorKind::InvalidInput.into();
Err(Error::from_io1(op, path, err)) Err(Error::from_io1(op, path, err))
}; };
@ -647,20 +664,30 @@ fn change_file_context(
Ok(Some(context)) => context, Ok(Some(context)) => context,
Ok(None) => return err0(), Ok(None) => return err0(),
Err(r) => return Err(Error::from_selinux("Getting security context", r)), Err(r) => {
return Err(Error::from_selinux(
get_message("chcon-op-getting-security-context"),
r,
));
}
}; };
let c_file_context = match file_context.to_c_string() { let c_file_context = match file_context.to_c_string() {
Ok(Some(context)) => context, Ok(Some(context)) => context,
Ok(None) => return err0(), Ok(None) => return err0(),
Err(r) => return Err(Error::from_selinux("Getting security context", r)), Err(r) => {
return Err(Error::from_selinux(
get_message("chcon-op-getting-security-context"),
r,
));
}
}; };
let se_context = let se_context =
OpaqueSecurityContext::from_c_str(c_file_context.as_ref()).map_err(|_r| { OpaqueSecurityContext::from_c_str(c_file_context.as_ref()).map_err(|_r| {
let err = io::ErrorKind::InvalidInput.into(); let err = io::ErrorKind::InvalidInput.into();
Error::from_io1("Creating security context", path, err) Error::from_io1(get_message("chcon-op-creating-security-context"), path, err)
})?; })?;
type SetValueProc = fn(&OpaqueSecurityContext, &CStr) -> selinux::errors::Result<()>; type SetValueProc = fn(&OpaqueSecurityContext, &CStr) -> selinux::errors::Result<()>;
@ -676,24 +703,34 @@ fn change_file_context(
if let Some(new_value) = new_value { if let Some(new_value) = new_value {
let c_new_value = os_str_to_c_string(new_value).map_err(|_r| { let c_new_value = os_str_to_c_string(new_value).map_err(|_r| {
let err = io::ErrorKind::InvalidInput.into(); let err = io::ErrorKind::InvalidInput.into();
Error::from_io1("Creating security context", path, err) Error::from_io1(
get_message("chcon-op-creating-security-context"),
path,
err,
)
})?; })?;
set_value_proc(&se_context, &c_new_value) set_value_proc(&se_context, &c_new_value).map_err(|r| {
.map_err(|r| Error::from_selinux("Setting security context user", r))?; Error::from_selinux(
get_message("chcon-op-setting-security-context-user"),
r,
)
})?;
} }
} }
let context_string = se_context let context_string = se_context.to_c_string().map_err(|r| {
.to_c_string() Error::from_selinux(get_message("chcon-op-getting-security-context"), r)
.map_err(|r| Error::from_selinux("Getting security context", r))?; })?;
if c_file_context.as_ref().to_bytes() == context_string.as_ref().to_bytes() { if c_file_context.as_ref().to_bytes() == context_string.as_ref().to_bytes() {
Ok(()) // Nothing to change. Ok(()) // Nothing to change.
} else { } else {
SecurityContext::from_c_str(&context_string, false) SecurityContext::from_c_str(&context_string, false)
.set_for_path(path, options.affect_symlink_referent, false) .set_for_path(path, options.affect_symlink_referent, false)
.map_err(|r| Error::from_selinux("Setting security context", r)) .map_err(|r| {
Error::from_selinux(get_message("chcon-op-setting-security-context"), r)
})
} }
} }
@ -701,10 +738,16 @@ fn change_file_context(
if let Some(c_context) = context.to_c_string()? { if let Some(c_context) = context.to_c_string()? {
SecurityContext::from_c_str(c_context.as_ref(), false) SecurityContext::from_c_str(c_context.as_ref(), false)
.set_for_path(path, options.affect_symlink_referent, false) .set_for_path(path, options.affect_symlink_referent, false)
.map_err(|r| Error::from_selinux("Setting security context", r)) .map_err(|r| {
Error::from_selinux(get_message("chcon-op-setting-security-context"), r)
})
} else { } else {
let err = io::ErrorKind::InvalidInput.into(); let err = io::ErrorKind::InvalidInput.into();
Err(Error::from_io1("Setting security context", path, err)) Err(Error::from_io1(
get_message("chcon-op-setting-security-context"),
path,
err,
))
} }
} }
} }
@ -733,16 +776,28 @@ fn root_dev_ino_check(root_dev_ino: Option<DeviceAndINode>, dir_dev_ino: DeviceA
fn root_dev_ino_warn(dir_name: &Path) { fn root_dev_ino_warn(dir_name: &Path) {
if dir_name.as_os_str() == "/" { if dir_name.as_os_str() == "/" {
show_warning!( show_warning!(
"It is dangerous to operate recursively on '/'. \ "{}",
Use --{} to override this failsafe.", get_message_with_args(
options::preserve_root::NO_PRESERVE_ROOT, "chcon-warning-dangerous-recursive-root",
HashMap::from([(
"option".to_string(),
options::preserve_root::NO_PRESERVE_ROOT.to_string()
)])
)
); );
} else { } else {
show_warning!( show_warning!(
"It is dangerous to operate recursively on {} (same as '/'). \ "{}",
Use --{} to override this failsafe.", get_message_with_args(
dir_name.quote(), "chcon-warning-dangerous-recursive-dir",
options::preserve_root::NO_PRESERVE_ROOT, HashMap::from([
("dir".to_string(), dir_name.to_string_lossy().to_string()),
(
"option".to_string(),
options::preserve_root::NO_PRESERVE_ROOT.to_string()
)
])
)
); );
} }
} }
@ -763,11 +818,11 @@ fn cycle_warning_required(fts_options: c_int, entry: &fts::EntryRef) -> bool {
fn emit_cycle_warning(file_name: &Path) { fn emit_cycle_warning(file_name: &Path) {
show_warning!( show_warning!(
"Circular directory structure.\n\ "{}",
This almost certainly means that you have a corrupted file system.\n\ get_message_with_args(
NOTIFY YOUR SYSTEM MANAGER.\n\ "chcon-warning-circular-directory",
The following directory is part of the cycle {}.", HashMap::from([("file".to_string(), file_name.to_string_lossy().to_string())])
file_name.quote() )
); );
} }

View file

@ -4,23 +4,26 @@
// file that was distributed with this source code. // file that was distributed with this source code.
#![cfg(target_os = "linux")] #![cfg(target_os = "linux")]
use std::collections::HashMap;
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt::Write; use std::fmt::Write;
use std::io; use std::io;
use thiserror::Error;
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::locale::{get_message, get_message_with_args};
pub(crate) type Result<T> = std::result::Result<T, Error>; pub(crate) type Result<T> = std::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)] #[derive(Error, Debug)]
pub(crate) enum Error { pub(crate) enum Error {
#[error("No context is specified")] #[error("{}", get_message("chcon-error-no-context-specified"))]
MissingContext, MissingContext,
#[error("No files are specified")] #[error("{}", get_message("chcon-error-no-files-specified"))]
MissingFiles, MissingFiles,
#[error("Data is out of range")] #[error("{}", get_message("chcon-error-data-out-of-range"))]
OutOfRange, OutOfRange,
#[error("{0}")] #[error("{0}")]
@ -29,45 +32,57 @@ pub(crate) enum Error {
#[error(transparent)] #[error(transparent)]
CommandLine(#[from] clap::Error), CommandLine(#[from] clap::Error),
#[error("{operation} failed")] #[error("{}", get_message_with_args("chcon-error-operation-failed", HashMap::from([("operation".to_string(), operation.clone())])))]
SELinux { SELinux {
operation: &'static str, operation: String,
#[source]
source: selinux::errors::Error, source: selinux::errors::Error,
}, },
#[error("{operation} failed")] #[error("{}", get_message_with_args("chcon-error-operation-failed", HashMap::from([("operation".to_string(), operation.clone())])))]
Io { Io {
operation: &'static str, operation: String,
#[source]
source: io::Error, source: io::Error,
}, },
#[error("{operation} failed on {}", .operand1.quote())] #[error("{}", get_message_with_args("chcon-error-operation-failed-on", HashMap::from([("operation".to_string(), operation.clone()), ("operand".to_string(), operand1.quote().to_string())])))]
Io1 { Io1 {
operation: &'static str, operation: String,
operand1: OsString, operand1: OsString,
#[source]
source: io::Error, source: io::Error,
}, },
} }
impl Error { impl Error {
pub(crate) fn from_io(operation: &'static str, source: io::Error) -> Self { pub(crate) fn from_io(operation: impl Into<String>, source: io::Error) -> Self {
Self::Io { operation, source } Self::Io {
operation: operation.into(),
source,
}
} }
pub(crate) fn from_io1( pub(crate) fn from_io1(
operation: &'static str, operation: impl Into<String>,
operand1: impl Into<OsString>, operand1: impl Into<OsString>,
source: io::Error, source: io::Error,
) -> Self { ) -> Self {
Self::Io1 { Self::Io1 {
operation, operation: operation.into(),
operand1: operand1.into(), operand1: operand1.into(),
source, source,
} }
} }
pub(crate) fn from_selinux(operation: &'static str, source: selinux::errors::Error) -> Self { pub(crate) fn from_selinux(
Self::SELinux { operation, source } operation: impl Into<String>,
source: selinux::errors::Error,
) -> Self {
Self::SELinux {
operation: operation.into(),
source,
}
} }
} }