2023-08-21 08:49:27 +00:00
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
2021-06-11 15:24:12 +00:00
// spell-checker:ignore (words) nosuchgroup groupname
2021-05-30 05:10:54 +00:00
2023-03-20 13:51:19 +00:00
use crate ::common ::util ::TestScenario ;
2023-06-04 12:55:16 +00:00
use uucore ::process ::getegid ;
2016-08-21 09:05:05 +00:00
#[ test ]
fn test_invalid_option ( ) {
2020-04-13 18:36:03 +00:00
new_ucmd! ( ) . arg ( " -w " ) . arg ( " / " ) . fails ( ) ;
2016-08-21 09:05:05 +00:00
}
2022-09-10 16:38:14 +00:00
#[ test ]
fn test_invalid_arg ( ) {
new_ucmd! ( ) . arg ( " --definitely-invalid " ) . fails ( ) . code_is ( 1 ) ;
}
2022-02-09 18:08:28 +00:00
static DIR : & str = " /dev " ;
2016-08-21 09:05:05 +00:00
2021-06-11 15:24:12 +00:00
// we should always get both arguments, regardless of whether --reference was used
2021-05-20 02:38:51 +00:00
#[ test ]
fn test_help ( ) {
new_ucmd! ( )
. arg ( " --help " )
. succeeds ( )
2022-09-29 13:29:32 +00:00
. stdout_contains ( " Arguments: " ) ;
2021-05-20 02:38:51 +00:00
}
#[ test ]
fn test_help_ref ( ) {
new_ucmd! ( )
. arg ( " --help " )
. arg ( " --reference=ref_file " )
. succeeds ( )
2022-09-29 13:29:32 +00:00
. stdout_contains ( " Arguments: " ) ;
2021-05-20 02:38:51 +00:00
}
#[ test ]
fn test_ref_help ( ) {
new_ucmd! ( )
. arg ( " --reference=ref_file " )
. arg ( " --help " )
. succeeds ( )
2022-09-29 13:29:32 +00:00
. stdout_contains ( " Arguments: " ) ;
2021-05-20 02:38:51 +00:00
}
2016-08-21 09:05:05 +00:00
#[ test ]
fn test_invalid_group ( ) {
2016-08-23 11:52:43 +00:00
new_ucmd! ( )
2018-03-02 07:08:09 +00:00
. arg ( " __nosuchgroup__ " )
2016-08-21 09:05:05 +00:00
. arg ( " / " )
. fails ( )
2023-01-05 20:09:15 +00:00
. stderr_is ( " chgrp: invalid group: '__nosuchgroup__' \n " ) ;
2016-08-21 09:05:05 +00:00
}
#[ test ]
fn test_1 ( ) {
2023-06-04 12:55:16 +00:00
if getegid ( ) ! = 0 {
2022-02-09 18:08:28 +00:00
new_ucmd! ( ) . arg ( " bin " ) . arg ( DIR ) . fails ( ) . stderr_contains (
// linux fails with "Operation not permitted (os error 1)"
// because of insufficient permissions,
// android fails with "Permission denied (os error 13)"
// because it can't resolve /proc (even though it can resolve /proc/self/)
" chgrp: changing group of '/dev': " ,
) ;
2018-03-02 07:08:09 +00:00
}
2016-08-21 09:05:05 +00:00
}
#[ test ]
fn test_fail_silently ( ) {
2023-06-04 12:55:16 +00:00
if getegid ( ) ! = 0 {
2022-04-02 08:47:37 +00:00
for opt in [ " -f " , " --silent " , " --quiet " , " --sil " , " --qui " ] {
2018-03-02 07:08:09 +00:00
new_ucmd! ( )
. arg ( opt )
. arg ( " bin " )
. arg ( DIR )
. run ( )
. fails_silently ( ) ;
}
2016-08-21 09:05:05 +00:00
}
}
#[ test ]
fn test_preserve_root ( ) {
2016-08-28 11:55:41 +00:00
// It's weird that on OS X, `realpath /etc/..` returns '/private'
2024-03-03 07:26:43 +00:00
new_ucmd! ( )
. arg ( " --preserve-root " )
. arg ( " -R " )
. arg ( " bin " )
. arg ( " / " )
. fails ( )
. stderr_is ( " chgrp: it is dangerous to operate recursively on '/' \n chgrp: use --no-preserve-root to override this failsafe \n " ) ;
2022-04-02 08:47:37 +00:00
for d in [
2022-02-09 18:08:28 +00:00
" /////dev///../../../../ " ,
2020-04-13 18:36:03 +00:00
" ../../../../../../../../../../../../../../ " ,
" ./../../../../../../../../../../../../../../ " ,
] {
2024-03-03 07:26:43 +00:00
let expected_error = format! (
" chgrp: it is dangerous to operate recursively on '{}' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ,
d ,
) ;
2016-08-28 11:55:41 +00:00
new_ucmd! ( )
. arg ( " --preserve-root " )
. arg ( " -R " )
2024-03-03 07:26:43 +00:00
. arg ( " bin " )
. arg ( d )
2016-08-28 11:55:41 +00:00
. fails ( )
2024-03-03 07:26:43 +00:00
. stderr_is ( expected_error ) ;
2016-08-28 11:55:41 +00:00
}
}
#[ test ]
fn test_preserve_root_symlink ( ) {
let file = " test_chgrp_symlink2root " ;
2022-04-02 08:47:37 +00:00
for d in [
2020-04-13 18:36:03 +00:00
" / " ,
2024-03-03 07:26:43 +00:00
" // " ,
" /// " ,
2022-02-09 18:08:28 +00:00
" ////dev//../../../../ " ,
2020-04-13 18:36:03 +00:00
" ..//../../..//../..//../../../../../../../../ " ,
" .//../../../../../../..//../../../../../../../ " ,
] {
2016-08-28 11:55:41 +00:00
let ( at , mut ucmd ) = at_and_ucmd! ( ) ;
2018-11-13 04:55:25 +00:00
at . symlink_file ( d , file ) ;
2024-03-10 12:56:31 +00:00
let expected_error =
" chgrp: it is dangerous to operate recursively on 'test_chgrp_symlink2root' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ;
2016-08-28 11:55:41 +00:00
ucmd . arg ( " --preserve-root " )
. arg ( " -HR " )
2024-03-03 07:26:43 +00:00
. arg ( " bin " )
. arg ( file )
2016-08-28 11:55:41 +00:00
. fails ( )
2024-03-03 07:26:43 +00:00
. stderr_is ( expected_error ) ;
2016-08-28 11:55:41 +00:00
}
let ( at , mut ucmd ) = at_and_ucmd! ( ) ;
2022-02-09 18:08:28 +00:00
at . symlink_file ( " ///dev " , file ) ;
2016-08-28 11:55:41 +00:00
ucmd . arg ( " --preserve-root " )
. arg ( " -HR " )
2023-01-27 09:29:45 +00:00
. arg ( " bin " ) . arg ( format! ( " .// {file} /..//..//../../ " ) )
2016-08-28 11:55:41 +00:00
. fails ( )
2024-03-03 07:26:43 +00:00
. stderr_is ( " chgrp: it is dangerous to operate recursively on './/test_chgrp_symlink2root/..//..//../../' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ) ;
2016-08-28 11:55:41 +00:00
let ( at , mut ucmd ) = at_and_ucmd! ( ) ;
2022-02-09 18:08:28 +00:00
at . symlink_file ( " / " , " __root__ " ) ;
2016-08-28 11:55:41 +00:00
ucmd . arg ( " --preserve-root " )
2016-08-21 09:05:05 +00:00
. arg ( " -R " )
2022-02-09 18:08:28 +00:00
. arg ( " bin " ) . arg ( " __root__/. " )
2016-08-21 09:05:05 +00:00
. fails ( )
2024-03-03 07:26:43 +00:00
. stderr_is ( " chgrp: it is dangerous to operate recursively on '__root__/.' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ) ;
}
#[ test ]
fn test_preserve_root_symlink_cwd_root ( ) {
new_ucmd! ( )
. current_dir ( " / " )
. arg ( " --preserve-root " )
. arg ( " -R " )
. arg ( " bin " ) . arg ( " . " )
. fails ( )
. stderr_is ( " chgrp: it is dangerous to operate recursively on '.' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ) ;
new_ucmd! ( )
. current_dir ( " / " )
. arg ( " --preserve-root " )
. arg ( " -R " )
. arg ( " bin " ) . arg ( " /. " )
. fails ( )
. stderr_is ( " chgrp: it is dangerous to operate recursively on '/.' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ) ;
new_ucmd! ( )
. current_dir ( " / " )
. arg ( " --preserve-root " )
. arg ( " -R " )
. arg ( " bin " ) . arg ( " .. " )
. fails ( )
. stderr_is ( " chgrp: it is dangerous to operate recursively on '..' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ) ;
new_ucmd! ( )
. current_dir ( " / " )
. arg ( " --preserve-root " )
. arg ( " -R " )
. arg ( " bin " ) . arg ( " /.. " )
. fails ( )
. stderr_is ( " chgrp: it is dangerous to operate recursively on '/..' (same as '/') \n chgrp: use --no-preserve-root to override this failsafe \n " ) ;
new_ucmd! ( )
. current_dir ( " / " )
. arg ( " --preserve-root " )
. arg ( " -R " )
. arg ( " bin " )
. arg ( " ... " )
. fails ( )
. stderr_is ( " chgrp: cannot access '...': No such file or directory \n " ) ;
2016-08-21 09:05:05 +00:00
}
#[ test ]
#[ cfg(target_os = " linux " ) ]
fn test_reference ( ) {
2019-12-25 06:42:11 +00:00
// skip for root or MS-WSL
// * MS-WSL is bugged (as of 2019-12-25), allowing non-root accounts su-level privileges for `chgrp`
// * for MS-WSL, succeeds and stdout == 'group of /etc retained as root'
2023-06-04 12:55:16 +00:00
if ! ( getegid ( ) = = 0 | | uucore ::os ::is_wsl_1 ( ) ) {
2018-03-02 07:08:09 +00:00
new_ucmd! ( )
. arg ( " -v " )
. arg ( " --reference=/etc/passwd " )
. arg ( " /etc " )
. fails ( )
2023-01-05 20:09:15 +00:00
. stderr_is ( " chgrp: changing group of '/etc': Operation not permitted (os error 1) \n failed to change group of '/etc' from root to root \n " ) ;
2018-03-02 07:08:09 +00:00
}
2016-08-21 09:05:05 +00:00
}
#[ test ]
2021-03-18 01:32:34 +00:00
#[ cfg(target_vendor = " apple " ) ]
2016-08-21 09:05:05 +00:00
fn test_reference ( ) {
2016-08-23 11:52:43 +00:00
new_ucmd! ( )
2016-08-21 09:05:05 +00:00
. arg ( " -v " )
2021-05-20 02:38:51 +00:00
. arg ( " --reference=ref_file " )
2016-08-21 09:05:05 +00:00
. arg ( " /etc " )
2021-05-20 02:38:51 +00:00
. fails ( )
// group name can differ, so just check the first part of the message
. stderr_contains ( " chgrp: changing group of '/etc': Operation not permitted (os error 1) \n failed to change group of '/etc' from " ) ;
}
#[ test ]
2022-02-09 18:08:28 +00:00
#[ cfg(any(target_os = " linux " , target_os = " android " , target_vendor = " apple " )) ]
2021-05-20 02:38:51 +00:00
fn test_reference_multi_no_equal ( ) {
new_ucmd! ( )
. arg ( " -v " )
. arg ( " --reference " )
. arg ( " ref_file " )
. arg ( " file1 " )
. arg ( " file2 " )
. succeeds ( )
. stderr_contains ( " chgrp: group of 'file1' retained as " )
. stderr_contains ( " \n chgrp: group of 'file2' retained as " ) ;
}
#[ test ]
2022-02-09 18:08:28 +00:00
#[ cfg(any(target_os = " linux " , target_os = " android " , target_vendor = " apple " )) ]
2021-05-20 02:38:51 +00:00
fn test_reference_last ( ) {
new_ucmd! ( )
. arg ( " -v " )
. arg ( " file1 " )
. arg ( " file2 " )
. arg ( " file3 " )
. arg ( " --reference " )
. arg ( " ref_file " )
. succeeds ( )
. stderr_contains ( " chgrp: group of 'file1' retained as " )
. stderr_contains ( " \n chgrp: group of 'file2' retained as " )
. stderr_contains ( " \n chgrp: group of 'file3' retained as " ) ;
}
#[ test ]
fn test_missing_files ( ) {
new_ucmd! ( )
. arg ( " -v " )
. arg ( " groupname " )
. fails ( )
. stderr_contains (
2023-03-08 14:06:07 +00:00
" error: the following required arguments were not provided: \n <FILE>... \n " ,
2021-05-20 02:38:51 +00:00
) ;
2016-08-21 09:05:05 +00:00
}
#[ test ]
#[ cfg(target_os = " linux " ) ]
fn test_big_p ( ) {
2023-06-04 12:55:16 +00:00
if getegid ( ) ! = 0 {
2018-03-02 07:08:09 +00:00
new_ucmd! ( )
. arg ( " -RP " )
. arg ( " bin " )
. arg ( " /proc/self/cwd " )
. fails ( )
2021-05-20 02:38:51 +00:00
. stderr_contains (
2020-04-13 18:36:03 +00:00
" chgrp: changing group of '/proc/self/cwd': Operation not permitted (os error 1) \n " ,
) ;
2018-03-02 07:08:09 +00:00
}
2016-08-21 09:05:05 +00:00
}
#[ test ]
2022-02-09 18:08:28 +00:00
#[ cfg(any(target_os = " linux " , target_os = " android " )) ]
2016-08-21 09:05:05 +00:00
fn test_big_h ( ) {
2023-06-04 12:55:16 +00:00
if getegid ( ) ! = 0 {
2020-04-13 18:36:03 +00:00
assert! (
new_ucmd! ( )
. arg ( " -RH " )
. arg ( " bin " )
. arg ( " /proc/self/fd " )
. fails ( )
2021-04-05 20:03:43 +00:00
. stderr_str ( )
2020-04-13 18:36:03 +00:00
. lines ( )
. fold ( 0 , | acc , _ | acc + 1 )
> 1
) ;
2018-03-02 07:08:09 +00:00
}
2016-08-21 09:05:05 +00:00
}
2021-08-08 23:33:02 +00:00
#[ test ]
2021-09-01 15:34:40 +00:00
#[ cfg(not(target_vendor = " apple " )) ]
2021-08-08 23:33:02 +00:00
fn basic_succeeds ( ) {
let ( at , mut ucmd ) = at_and_ucmd! ( ) ;
let one_group = nix ::unistd ::getgroups ( ) . unwrap ( ) ;
// if there are no groups we can't run this test.
if let Some ( group ) = one_group . first ( ) {
at . touch ( " f1 " ) ;
ucmd . arg ( group . as_raw ( ) . to_string ( ) )
. arg ( " f1 " )
. succeeds ( )
. no_stdout ( )
. no_stderr ( ) ;
}
}
2021-08-12 23:35:21 +00:00
2021-08-10 21:31:42 +00:00
#[ test ]
fn test_no_change ( ) {
let ( at , mut ucmd ) = at_and_ucmd! ( ) ;
at . touch ( " file " ) ;
ucmd . arg ( " " ) . arg ( at . plus ( " file " ) ) . succeeds ( ) ;
}
2021-09-01 15:34:40 +00:00
#[ test ]
#[ cfg(not(target_vendor = " apple " )) ]
fn test_permission_denied ( ) {
use std ::os ::unix ::prelude ::PermissionsExt ;
if let Some ( group ) = nix ::unistd ::getgroups ( ) . unwrap ( ) . first ( ) {
let ( at , mut ucmd ) = at_and_ucmd! ( ) ;
at . mkdir ( " dir " ) ;
at . touch ( " dir/file " ) ;
std ::fs ::set_permissions ( at . plus ( " dir " ) , PermissionsExt ::from_mode ( 0o0000 ) ) . unwrap ( ) ;
ucmd . arg ( " -R " )
. arg ( group . as_raw ( ) . to_string ( ) )
. arg ( " dir " )
. fails ( )
2023-01-05 20:09:15 +00:00
. stderr_only ( " chgrp: cannot access 'dir': Permission denied \n " ) ;
2021-09-01 15:34:40 +00:00
}
}
#[ test ]
#[ cfg(not(target_vendor = " apple " )) ]
fn test_subdir_permission_denied ( ) {
use std ::os ::unix ::prelude ::PermissionsExt ;
if let Some ( group ) = nix ::unistd ::getgroups ( ) . unwrap ( ) . first ( ) {
let ( at , mut ucmd ) = at_and_ucmd! ( ) ;
at . mkdir ( " dir " ) ;
at . mkdir ( " dir/subdir " ) ;
at . touch ( " dir/subdir/file " ) ;
std ::fs ::set_permissions ( at . plus ( " dir/subdir " ) , PermissionsExt ::from_mode ( 0o0000 ) ) . unwrap ( ) ;
ucmd . arg ( " -R " )
. arg ( group . as_raw ( ) . to_string ( ) )
. arg ( " dir " )
. fails ( )
2023-01-05 20:09:15 +00:00
. stderr_only ( " chgrp: cannot access 'dir/subdir': Permission denied \n " ) ;
2021-09-01 15:34:40 +00:00
}
}
2021-09-02 20:31:49 +00:00
#[ test ]
#[ cfg(not(target_vendor = " apple " )) ]
fn test_traverse_symlinks ( ) {
use std ::os ::unix ::prelude ::MetadataExt ;
let groups = nix ::unistd ::getgroups ( ) . unwrap ( ) ;
if groups . len ( ) < 2 {
return ;
}
let ( first_group , second_group ) = ( groups [ 0 ] , groups [ 1 ] ) ;
2022-04-02 08:47:37 +00:00
for ( args , traverse_first , traverse_second ) in [
2021-09-02 20:31:49 +00:00
( & [ ] [ .. ] as & [ & str ] , false , false ) ,
( & [ " -H " ] [ .. ] , true , false ) ,
( & [ " -P " ] [ .. ] , false , false ) ,
( & [ " -L " ] [ .. ] , true , true ) ,
] {
let scenario = TestScenario ::new ( " chgrp " ) ;
let ( at , mut ucmd ) = ( scenario . fixtures . clone ( ) , scenario . ucmd ( ) ) ;
at . mkdir ( " dir " ) ;
at . mkdir ( " dir2 " ) ;
at . touch ( " dir2/file " ) ;
at . mkdir ( " dir3 " ) ;
at . touch ( " dir3/file " ) ;
at . symlink_dir ( " dir2 " , " dir/dir2_ln " ) ;
at . symlink_dir ( " dir3 " , " dir3_ln " ) ;
scenario
. ccmd ( " chgrp " )
. arg ( first_group . to_string ( ) )
. arg ( " dir2/file " )
. arg ( " dir3/file " )
. succeeds ( ) ;
assert! ( at . plus ( " dir2/file " ) . metadata ( ) . unwrap ( ) . gid ( ) = = first_group . as_raw ( ) ) ;
assert! ( at . plus ( " dir3/file " ) . metadata ( ) . unwrap ( ) . gid ( ) = = first_group . as_raw ( ) ) ;
ucmd . arg ( " -R " )
. args ( args )
. arg ( second_group . to_string ( ) )
. arg ( " dir " )
. arg ( " dir3_ln " )
. succeeds ( )
. no_stderr ( ) ;
assert_eq! (
at . plus ( " dir2/file " ) . metadata ( ) . unwrap ( ) . gid ( ) ,
if traverse_second {
second_group . as_raw ( )
} else {
first_group . as_raw ( )
}
) ;
assert_eq! (
at . plus ( " dir3/file " ) . metadata ( ) . unwrap ( ) . gid ( ) ,
if traverse_first {
second_group . as_raw ( )
} else {
first_group . as_raw ( )
}
) ;
}
}