Decoded: nice (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 nice command (coreutils)

Summary

nice - run a command with modified niceness

[Source] [Code Walkthrough]

Lines of code: 222
Principal syscall: nice(), setpriority()
Support syscall: execvp()
Options: 4 (1 short, 3 long)

Descended from nice in Version 4 UNIX (late 1973)
Added to Coreutils in November 1992 [First version]
Number of revisions: 128 [Code Evolution]

Helpers:
  • perm_related_errno() - Checks if an error is permissions related
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
  • quote() - Converts an input argument to a printable string

Setup

nice begins with a couple macro definitions:

  • GET_NICENESS() - Function-like macro that returns the current nice value
  • NZERO - the most favorable nice value (without sign)

main() initializes the following:

  • current_niceness - The current niceness of the process
  • adjustment - The adjustment requested by the user
  • adjustment_given - The given adjustment input string
  • ok - The return status of the program
  • i - Generic iterator over arguments

Parsing

Two questions answered by parsing:

  • What niceness adjustment should be applied?
  • What program do we modify?

Parsing failures

These failure cases are explicitly checked:

  • Nice value is too large
  • An adjustment is provided, but not a command

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

Extra comments

The parsing procedure uses both Getopt and checks an older syntax of only providing a number for backwards compatibility.


Execution

Despite the length of the utility, the common case only involves two lines of code (1, 2):

...
  ok = (nice (adjustment) != -1 || errno == 0);
...
  execvp (argv[i], &argv[i]);
...

The first changes the current nice value while the second executes the given command (cloning from the nice utility with the modified nice value). If control returns to the nice utility after calling execvp(), that means execution failed and we need to handle an error.

The remaining lines of code provide for contingencies. Such as for newer systems that don't include a nice() syscall, instead we use setpriority()

Exit Status

The nice utility is one of the few that specify more exit values than 0 (EXIT_SUCCESS) and 1 (EXIT_FAILURE). Instead, we also include:

  • EXIT_CANCELED - The nice portion of execution failed
  • EXIT_ENOENT - The target command doesn't exist
  • EXIT_CANNOT_INVOKE - The target command did not execute properly

Failure cases:

  • We cannot retrieve the current niceness
  • We cannot set the new niceness value (i.e. no perms for lower niceness)

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


[Back to Project Main Page]