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

Summary

chgrp - change group ownership

[Source] [Code Walkthrough]

Lines of code: 320
Principal syscall: chownat()
Support syscalls: stat()
Options: 20 (8 short, 12 long, does not include perm digits)

Descended from chgrp introduced in Version 6 UNIX (1975)
Added to Fileutils in October 1992 [First version]
Number of revisions: 163

The chgrp utility is a limited-use chown for managing group ownership. Much of the work behind both utilities is factored out to a common source file: chown-core.c. Note that the primary syscall is a variant of chown() depending on the situation

Helpers:
  • parse_group() - Retrieves a GID from an input string
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

Setup

At global scope, chgrp.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)
  • 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)

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 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 handling symlinks
  • Mismatch between actual and expected operand count

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 the GID and associated name, either through a provided reference file using stat() or as provided by the user.

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

The bulk of the work to change ownership is handed off to chown-core. We push the computed parameters (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]