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

Summary

ln - make links between files

[Source] [Code Walkthrough]

Lines of code: 619
Principal syscall: linkat(), symlinkat()
Support syscalls: stat(), lstat()
Options: 29 (14 short, 15 long)

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

A key idea behind ln is the distinction between hard links and symbolic links: Hard links reference the same inode, but symbolic links are distinct inodes with no data. Mechanically, the difference lies in the syscall used to create the files. This utility has a large number of corner cases documented in do_link()

Helpers:
  • convert_abs_rel() - Returns the relative link between source and target paths
  • do_link() - The primary link procedure
  • errno_nonexisting() - Checks if an input error is due to a nonexistent file
  • target_directory_operand() - Detects if the full path/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
  • force_linkat() - Creates a hard link (from gnulib)
  • force_symblinkat() - Creates a symbolic link (from gnulib)

Setup

Most of the logical control for ln is managed through global variables:

  • dereference_dest_dir_symlinks - Flag to assume target is a symlink
  • dest_set - The destination inode triple for hard links
  • hard_dir_link - Flag that forces links to other links to actually use the target
  • interactive - Flag to query the user before removing existing files
  • logical - Flag to ensure that hard links are logical
  • relative - Flag to make symbolic links relative
  • remove_existing_files - Flag to force removal of existing files
  • symbolic_link - Flag to differentiate between making hard/symbolic links
  • verbose - Flag to list all activities for the user

main() introduces several local variables for additional processing:

  • *backup_suffix - The suffix used for backup files (-b, -s)
  • c - The character for the next option to process
  • **file - Pointer to a list of files
  • make_backups - Flag used to force backups (-b)
  • n_files - The number of files specified
  • no_target_directory - Flag to assume that the target is a normal file (-T)
  • ok - The final return status
  • *target_directory - The destination directory (-t)
  • *version_control_string - The user chosen backup option (-b)

Parsing

Parsing ln considers the following questions:

  • Are we creating hard or symbolic links?
  • Should we force remove files? Query the user and notify the user?
  • Should files be backed up? If so, by what method?
  • Are the targets directories?
  • Any special handling of symlinks?

Parsing failures

These failure cases are explicitly checked:

  • Missing target information
  • Specifying a target directory with no-target-directory flag
  • Missing destination operands
  • Extra operands
  • Forcing directory handling on a file
  • Using an unknown backup type
  • Trying to use relative linking without specifying a symlink
  • Unknown options

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

The ln utility is dominated by checks for many edge cases, especially those involving target types and hard/symbolic link nuances.

After parsing, we prepare variables needed for the linking operation, including the backup type/name and the correct file names expected by do_link. The link process kicks off by:

  • Getting the source file information via stat() or lstat() as appropriate.
  • Then we check if a destination file already exists so it can be removed
  • We convert absolute names to relative names as needed by a link
  • Create the hard or symbolic link with the appropriate gnulib wrapper
  • Update file entry as needed
  • Free name allocations previously malloc'd

Failure cases:

  • Unable to stat() source file
  • Attempting to hard link a directory
  • Unable to remove target file
  • Attempting to overwrite an existing hard link
  • Trying to link the same file for a source and target
  • Trying to overwrite a directory
  • Unable to create a backup
  • Failed to create a link of any type (syscall failure)

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


[Back to Project Main Page]