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

Summary

mv - move (rename) files

[Source] [Code Walkthrough]

Lines of code: 513
Principal syscall: None
Support syscalls: fstatat()
Options: 23 (10 short, 13 long, does not include perm digits)

Descended from mv introduced in Version 1 UNIX (1971)
Added to Fileutils in October 1992 [First version]
Number of revisions: 250

The actual move procedure is a type of copy that is over 1000 lines long due to the many implementation methods and edge cases. Since it's only referenced from mv.c, I won't discuss it directly, but if you need more details, dig in to copy.h.

Helpers:
  • cp_option_init() - Initializes a struct cp_options to default values
  • do_move() - The procedure for moving a single file
  • movefile() - Moves a single file, handling directories as need
  • rm_option_init() - Initializes a struct rm_options to default values
  • target_directory_operand() - Detects if an input file path\name is a directory
External non-standard helpers:
  • copy() - The tie to coreutils copy implementation
  • die() - Exit with mandatory non-zero error and message to stderr
  • error() - Outputs error message to standard error with possible process termination

Setup

mv does little work at global scope but defines a long list of variables in main():

  • *backup_suffix - The suffix added to backup files
  • c - The current command line option letter we're parsing
  • **file - The start of the file array
  • make_backups - Flag if backups of processed files should be made
  • n_files - The number of files provided be the user (index to file[])
  • no_target_directory - Flag to ignore special trailing directory handling
  • ok - The final return status. Note overloaded usage
  • selinux_enabled - Flag if SELinux is enabled
  • *target_directory - The destination path as provided by the user
  • *version_control_string - The backup method argument provided by the user
  • x - A copy options structure used to control move behavior

Parsing begins with the short options passed as a string literal:
"bfint:uvS:TZ"


Parsing

Parsing collects all of the user specified options, answering questions about execution:

  • Which file do we move and where to?
  • If it's a directory, how should we handle certain cases?
  • Should we create a backup, if so, is there a special suffix?
  • Should the operation force move?
  • Is there a security context?

Parsing failures

These failure cases are explicitly checked:

  • Specifying multiple target directories
  • Specifying an inaccessible or non-existent target directory
  • Using both no-target-directory and target-directory
  • Missing source or destination files
  • Using both backup and no-clobber options
  • Using an unknown option

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

mv passes off most of the execution to the copy subsystem (copy.h). However some prep work is still required.

  • Initialize a hash table used for file system triples (name, inode, device)
  • If there is a target directory, build the full path and remove trailing slashes
  • Pass the files and the parsed options to copy()
  • Return the status from copy()

While no failure cases are explicitly checked for mv, the copy subsystem mail fail for a variety of reasons.


[Back to Project Main Page]