// This file is part of the uutils util-linux package. // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. #[cfg(target_family = "unix")] mod unix { use crate::common::util::{TestScenario, UCommand, TESTS_BINARY}; #[test] fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails().code_is(1); new_ucmd!() .arg("-f") .fails() .code_is(1) .stderr_is("setsid: no command specified\n"); } #[test] fn fork_isolates_child_exit_code() { new_ucmd!() .arg("-f") .arg("/usr/bin/false") .succeeds() .no_output(); } #[test] fn non_fork_returns_child_exit_code() { new_ucmd!() .arg("/usr/bin/false") .fails() .code_is(1) .no_output(); } #[test] fn fork_wait_returns_child_exit_code() { new_ucmd!() .arg("-f") .arg("-w") .arg("/usr/bin/false") .fails() .code_is(1) .no_output(); } #[test] fn non_fork_returns_not_found_error() { new_ucmd!() .arg("/usr/bin/this-tool-does-not-exist-hopefully") .fails() .code_is(127) .stderr_is("setsid: failed to execute /usr/bin/this-tool-does-not-exist-hopefully: No such file or directory\n"); } #[test] fn non_fork_on_non_executable_returns_permission_denied_error() { new_ucmd!() .arg("/etc/passwd") .fails() .code_is(126) .stderr_is("setsid: failed to execute /etc/passwd: Permission denied\n"); } #[test] fn fork_isolates_not_found_error() { new_ucmd!() .arg("-f") .arg("/usr/bin/this-tool-does-not-exist-hopefully") .succeeds(); // no test for output, as it's a race whether the not found error gets printed // quickly enough, potential flakyness } #[test] fn unprivileged_user_cannot_steal_controlling_tty() { let shell_cmd = format!("{TESTS_BINARY} setsid -w -c {TESTS_BINARY} setsid -w -c /b/usrin/true"); UCommand::new() .terminal_simulation(true) .arg(&shell_cmd) .fails() .code_is(1) .no_stdout() .stderr_is("setsid: failed to set the controlling terminal: Permission denied\r\n"); } #[cfg(target_os = "linux")] #[test] fn unprivileged_user_can_take_new_controlling_tty() { let shell_cmd = format!( "/usr/bin/cat /proc/self/stat; {TESTS_BINARY} setsid -w -c /usr/bin/cat /proc/self/stat" ); let cmd_result = UCommand::new() .terminal_simulation(true) .arg(&shell_cmd) .succeeds(); let output = cmd_result.code_is(0).no_stderr().stdout_str(); // /proc/self/stat format has controlling terminal as the 7th // space-separated item; if we managed to change the controlling // terminal, we should see a difference there let (before, after) = output .split_once('\n') .expect("expected 2 lines of output at least"); let before = before .split_whitespace() .nth(6) .expect("unexpected stat format"); let after = after .split_whitespace() .nth(6) .expect("unexpected stat format"); assert_ne!(before, after); } #[cfg(target_os = "linux")] #[test] fn setsid_takes_session_leadership() { let shell_cmd = format!( "/usr/bin/cat /proc/self/stat; {TESTS_BINARY} setsid /usr/bin/cat /proc/self/stat" ); let cmd_result = UCommand::new() .terminal_simulation(true) .arg(&shell_cmd) .run(); let output = cmd_result.code_is(0).no_stderr().stdout_str(); // /proc/self/stat format has sessiion ID as the 6th space-separated // item; if we managed to get session leadership, we should see a // difference there... let (before, after) = output .split_once('\n') .expect("expected 2 lines of output at least"); let before = before .split_whitespace() .nth(5) .expect("unexpected stat format"); let after = after .split_whitespace() .nth(5) .expect("unexpected stat format"); assert_ne!(before, after); // ...and it should actually be the PID of our child! We take the child // PID here to avoid differences in handling by different shells or // distributions. let pid = after.split_whitespace().next().unwrap(); assert_eq!(after, pid); } } #[cfg(not(target_family = "unix"))] mod non_unix { use crate::common::util::TestScenario; #[test] fn unsupported_platforms() { new_ucmd!() .arg("/usr/bin/true") .fails() .code_is(1) .stderr_is("setsid: `setsid` is unavailable on non-UNIX-like platforms.\n"); } }