Decoded: env (coreutils)

[Back to Project Main Page]

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

Logical flow of env command (coreutils)

Summary

env - run a command in a modified environment

[Source] [Code Walkthrough]

Lines of code: 662
Principal syscalls: putenv(), unsetenv()
Support syscall: execvp()
Options: 14 (6 short, 8 long)

Descended from env as originated in System III (1982)
Added to Shellutils in November 1992 [First version]
Number of revisions: 117 [Code Evolution]

Helpers:
  • append_unset_var() - Adds a new variable to the unset list
  • build_argv() - Constructs an array vector from a string
  • escape_char() - Converts a text escape code in to the actual code value
  • extract_varname() - Finds a pointer to the desired variable
  • parse_split_string() - Breaks an input string in to the argument vector
  • scan_varname() - Finds a pointer to the end of a variable name
  • unset_envvars() - Removes desired variables from the environment
  • validate_escape_sequence() - Tests if an input escape sequence is valid
  • validate_split_str() - Separates a string based on the FreeBSD syntax, if possible
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

env prepares some data at global to support execution: A list of variables that need to be removed from the environment and details about the environment string to set. Variables include:

  • dev_debug - Flag to use verbose debug information
  • **usvars - Pointer to the list of variables to unset
  • usvars_alloc - The number of unset variables allocated
  • usvars_used - The number of unset variables defined
  • *varname - The list of variables to set
  • vnlen - The number of variables to set

main() initializes the following:

  • ignore_environment - Flag for providing a blank environment (-i)
  • newdir - The user provided working directory for the target commend (-C)
  • opt_nul_terminate_output - Flag for null terminating output (-0)
  • optc - The current command line option letter

Parsing

Parsing for env is more complicated than most utilities because user-provided arguments must be parsed for the environment -- either building a new argv, or building a list of variables to remove (-S and -u respectively).

Several questions answered by parsing:

  • What new environment variables should be added?
  • Should nay environment variables be removed?
  • Shuld we use a completely blank environment?
  • Should test output be null-terminated rather than newlined?
  • How much feedback should be give the user?
  • Should the target command execute in a different directory?

Parsing failures

These failure cases are explicitly checked:

  • User-specified string has invalid formats
  • Using null-term output with an executable command
  • Providing a working directory without a command
  • An unknown option is used

All parsing failures result in a short error message followed by the usage instructions.


Execution

As execution begins, most of the prep work has already been accomplished. All that's left is to change the environment and execute the desired command

The exact process is:

  • Remove any (or all) environment variables if requested
  • Set environment variables, with possible debug messages
  • If this was a test run, output the final environment state
  • Change directory to the new target if requested
  • Debug output the target command and arguments
  • Call execvp()
  • Handle any execvp() failure cases (return status)

Failure cases:

  • Setting or unsetting any environment fails
  • execvp() fails for any reason

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


[Back to Project Main Page]