Decoded: install (coreutils)

[Back to Project Main Page]

Note: This page explores the design of command-line utilities. It is not a user guide.
[GNU Manual] [No POSIX requirement] [Linux man] [FreeBSD man]

Logical flow of install command (coreutils)

Summary

install - copy files and set attributes

[Source] [Code Walkthrough]

Lines of code: 1060
Principal syscall: lchown(), chmod()
Support syscalls: fork(), execlp(), stat(), unlink()
Options: 32 (15 short, 17 long)

Lineage unclear -- not included in Research UNIX or System V
Added to Fileutils in October 1992 [First version]
Number of revisions: 294

The install utility shares many ideas with cp but also allows the user to change attributes after copy. The idea is that install prepares future usage for other users.

Helpers:
  • announce_mkdir() - Prints the created directory
  • change_attributes() - Sets the attributes of a target file using chmod()
  • change_timestamps() - Sets file timestamp
  • copy_file() - Performs a file copy
  • cp_option_init() - Initializes a copy options structure (cp_options
  • extra_mode() - Tests input mode for no RWX permissions
  • get_ids() - Initializes user and group for target (passwd and group structures)
  • have_same_content() - Tests two file for the same content
  • install_file_in_dir() - Creates a directory and copies a file
  • install_file_in_file() - Copies a file and sets new permissions/timestamps as necessary
  • install_file_in_file_parents() - Recreates ancestor directories before copying file
  • make_ancestor() - Creates an ancestor directory
  • mkancesdirs_safe_wd() - Creates parent directories without affecting working directory
  • need_copy() - Tests if a file must be copied
  • process_dir() - Retrieves a command line file name
  • setdefaultfilecon() - Change file context, if applicable (two definitions)
  • strip() - Removes symbol table from a target file
  • target_directory_operand() - Tests if a target is a directory
External non-standard helpers:
  • die() - Exit with mandatory non-zero error and message to stderr
  • error() - Outputs error message to standard error with possible process termination

Setup

install uses globals flags and variables to manage execution, including:

  • copy_only_if_needed - Flag for the compare setting (-C)
  • dir_arg - Flag to make a directory instead of a file
  • dir_mode - The default mode for directories
  • dir_mode_bits - A subset of dir_mode bits (for make_dir_parents() in gnulib)
  • group_id - The gid of the target group
  • group_name - The name string of the target group
  • mode - The default mode for non-directory files
  • owner_id - The uid of the target owner
  • owner_name - The name string of the target owner
  • strip_files - Flag to strip the symbol table from the target file
  • *strip_program - The name of the program to strip the executable

main() introduces list of local variables:

  • *backup_suffix - The suffix to add to the file backup
  • exit_status - The final return status
  • **file - The source and destination file pointers
  • make_backups - Flag for making backups (-b)
  • mkdir_and_install - Flag to create parent directories prior to copying
  • n_files - The number of files provided by the user
  • no_target_directory - Flag to treat the target as a file
  • optc - The character for the next option to process
  • *scontext - The desired security context
  • *specified_mode - The target file mode bits
  • strip_program_specified - Flag to strip the target program
  • *target_directory - The name of the target directory
  • *version_control_string - The desired backup mode
  • x - The cp_options struct to control copy

Before parsing begins, the copy options are initialized to default values via copy_option_init()


Parsing

Parsing install options answers the following questions to define the execution parameters

  • Should we compare before copying to avoid redundancy?
  • Should we create missing parent directories before copying?
  • What is target file access mode, group, and owner?
  • Should we create a backup first?
  • Is there an associated security context?
  • How much feedback should we provide the user?

Parsing failures

These failure cases are explicitly checked:

  • Specifying multiple target directories
  • Providing a security context without SELinux enabled
  • Claiming a target to be a directory if it's not
  • Specifying an unknown security context
  • Attempting to set a context and preserve it
  • Missing source or target operands
  • Using both target and no-target options
  • Trying to compare files while preserving timestamps
  • Trying to compare files and strip symbol tables
  • Trying to compare files without permission
  • Unknown option used

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

install starts with preliminary fact-finding: Gathering information on the target directory, preparing backup file names, compiling the access mode bits, and gather user/group information

  • stat() target directory (if specified)
  • Prepare the backup file names
  • Compiling access mode bits
  • Gathering user and group information

Execution branches in three possible ways depending on if we have to create any directories. The base case is only copying files, which follows this procedure (install_file_in_file()):

  • If preserving timestamps, gather the information with stat()
  • Copy the files from source to destination using the options set during parsing
  • Clean the target symbol table if required
  • Transfer the timetamp information to the new file
  • Set the new file attributes

The other two cases consider if we need to create the target directory first or if we have several levels of parent directories that need to be created. These procedures are install_file_in_dir() and install_file_in_file_parents() respectively. Both procdures create the directories and then call the base case of copying the file.

Failure cases:

  • Unable to stat() source file or target directories
  • Directory creation failed
  • Failure to unlink target file
  • Unknown useror group specified
  • Failure to strip target file (fork() or execlp() failed)
  • Failure to change ownership or permissions
  • Unable to change timestamps
  • Unable to change context

All failures at this stage output an error message to STDERR and return without displaying usage help


[Back to Project Main Page]