[GNU Manual] [No POSIX requirement] [Linux man] [FreeBSD man]

Summary
chroot - run a command with a different root directory
Lines of code: 431
Principal syscall: chroot() (Linux)
Support syscalls: execvp(), chdir()
Options: 5 (0 short, 5 long)
GNU implementation is possibly the earliest utility -- chroot syscall appeared in Version 7 UNIX (1979)
Added to Shellutils in March 1996 [First version]
Number of revisions: 110 [Code Evolution]
There is no current POSIX interface for chroot, which complicates utility execution across platforms. Here is the legacy POSIX interface
Helpers:is_root()- Tests if an input path is the same as '/'gid_set()- Tests ifgidhas a nontrivial valuegid_unset()- Tests ifgidis -1parse_additional_groups()- Parses comma separated groups in to a gid arrayset_groups()- Simulates setgroups() syscall with success/fail conditionsuid_set()- Tests ifuidhas a nontrivial valueuid_unset()- Tests ifuidis -1
die()- Exit with mandatory non-zero error and message to stderrerror()- Outputs error message to standard error with possible process terminationignore_value()- Prevents warning from GCCwarn_unused_resultattributeparse_user_spec()- Breaks a user:group in to components
Setup
The bulk of chroot executes within main(). The function begins by initializing nine locals:
c- The current command line option letter we're parsinggid- The group ID parsed fromuserspecgroups- Group list input from the--groupsoptionn_gids- The number of gid entriesout_gids- The resulting gids parsed fromgroupsskip_chdir- Flag to skip changing working directoryuid- user ID parsed fromuserspecusername- The user name pulled from the user fileuserspec- The user:group input from the--userspecoption
Parsing
Parsing collects options and a target path which considers the following questions:
- Should the new process use a specific group?
- Should the new process run under different credentials?
- Should the working directory change?
Parsing failures
These failure cases are explicitly checked:
- No new path to change root
- Trying to skip changing directory if the newroot isn't root
User specified parsing failures result in a short error message followed by the usage instructions. Access related parsing errors die with an error message.
Execution
chroot execution follows a fairly linear process:
- Set input users and groups as specified
- Perform
chroot()to the new location - Change working directory to the new root
- Update all users and groups to the new settings (with supplemental groups)
- Execute the desired command in the new root environment (default to new shell)
Since execvp() doesn't return any further execution in chroot implies a failure
Failure cases:
- Can't change root (
chroot()fails) - Can't change working directory (
chdir()fails) - Unknown group provided
- Can't change group ID
- Can't change user ID
execvpfailed for any reason
Failures output an error message to STDERR and return without displaying usage help