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

Summary

chown - change file owner and group

[Source] [Code Walkthrough]

Lines of code: 332
Principal syscall: chownat()
Support syscalls: stat()
Options: 21 (8 short, 13 long, does not include perm digits)

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

The chown utility pushes much of the work to a separate source file (chown-core.c), which it shared with chgrp

Helpers:
  • None
External non-standard helpers:
  • chown_files() - Processes all input files via chown-core.c
  • die() - Exit with mandatory non-zero error and message to stderr
  • error() - Outputs error message to standard error with possible process termination
  • gid_to_name() - Converts a group id to a string
  • parse_user_spec() - Separates UID:GID strings.
  • uid_to_name() - Converts a user id to a string

Setup

At global scope, chown.c defines *reference_file to hold a possible file name argument passed by the user.

Afterward, main() initializes the following:

  • bit_flags - Bit flags for behavior of the file traversal systems
  • chopt - A structure that organizes option settings for the utility
  • dereference - Flag for how to handle symlinks (link or target)
  • gid - GID specified by the user (from ref file)
  • ok - The final return status. Note overloaded usage
  • optc - The character for the next option to process
  • preserve_root - Flag set to preserve root (--preserve-root option)
  • required_gid - The original GID as passed directly (--from)
  • required_uid - The original UID as passed directly (--from)
  • uid - UID specified by the user (from ref file)

Parsing kicks off with the short options passed as a string literal:
"HLPRcfhv"


Parsing

Parsing, collects options and arguments to answer the following questions:

  • Which file(s) do we modify
  • What is the new group?
  • Is the user:group provided directly or with a reference file
  • Are we preserving root?
  • Are we operating recursively
  • What amount of reporting should we provide?

Parsing failures

These failure cases are explicitly checked:

  • Providing conflicting options for recursion and symlink handling
  • Mismatch between actual and expected operand count (references files, etc)

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

Execution begins by finding UID:GID and associated name strings. The source is provided either as reference file to stat() or directly by the user as an argument.

Next, if we're preserving root, we find the root inode and buffer it

Changing User:Group is handed off to chown-core. We push the computed parameters (uid, gid, bit fields, and behavior flags) to chown_files(). In most cases, this ends with a call to a chown() variant depending on the target file types.

Failure cases:

  • Cannot stat() reference file (missing, no perms, etc)
  • Cannot access filesystem root while preserving and recursing
  • Implicitly, failure includes the ways that chown() could fail.

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


[Back to Project Main Page]