Documents
CLI Configuration And Usage
CLI Configuration And Usage
Type
Topic
Status
Published
Created
Mar 1, 2026
Updated
Apr 27, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

CLI Configuration and Usage#

rmagic is a pure-Rust command-line tool for file type identification that serves as a memory-safe alternative to the GNU file command. The CLI uses magic rules to examine file contents rather than extensions, providing accurate file type detection for binaries, archives, images, and documents. The CLI was developed as part of the Phase 1 MVP focused on delivering a working command-line tool alongside library functionality, prioritizing memory safety and compatibility with GNU file.

The tool uses clap version 4.6.1 with derive macros for declarative argument parsing, implemented entirely in src/main.rs. The CLI supports multiple input modes (files, stdin), output formats (text, JSON), custom magic files, and built-in fallback rules. Configuration follows a clear flag-based precedence strategy with no configuration file support - all configuration is done via command-line arguments.

The rmagic CLI emphasizes robust error handling, actionable error messages, and Unix pipeline integration. It implements strict mode for CI/CD environments, timeout protection for complex evaluations, and graceful degradation when processing multiple files.


CLI Structure and Interface Design#

Basic Invocation#

rmagic [OPTIONS] <FILE>...
rmagic [OPTIONS] -

The CLI requires at least one positional argument: files to analyze or - for stdin. The tool uses the FileOrStdin type from clap-stdin to handle both file paths and stdin input seamlessly.

Functional Categories#

The CLI is organized around three functional categories:

  1. Output Format Selection – Control how results are displayed (--text, --json)
  2. Magic File Source Selection – Choose where magic rules come from (--magic-file, --use-builtin)
  3. Behavior Configuration – Control processing behavior (--strict, --timeout-ms)

Command-Line Flags#

Output Format Flags (Mutually Exclusive)#

FlagTypeDefaultDescription
--textbooltrueOutput results in text format (one line per file)
--jsonboolfalseOutput results in JSON format

The --text and --json flags are mutually exclusive, enforced via clap's conflicts_with = "text" attribute on the json field. Passing both flags produces a clap validation error before execution.

Magic File Selection Flags#

FlagTypeDefaultDescription
--magic-file FILEOption<PathBuf>NoneUse a custom magic file or directory
--use-builtinboolfalseUse built-in magic rules compiled into the binary

When both --use-builtin and --magic-file are provided, --use-builtin takes precedence. This allows users to override a default magic file path with the built-in rules.

Behavior Configuration Flags#

FlagTypeDefaultDescription
--strictboolfalseExit with non-zero code on processing failures
--timeout-ms MSOption<u64>NonePer-file evaluation timeout in milliseconds

Standard Flags#

FlagDescription
-h, --helpPrint help information
-V, --versionPrint version information

Configuration Precedence and Loading#

Magic File Resolution Order#

The CLI follows a strict precedence order when determining which magic rules to use:

  1. --use-builtin flag (highest priority) – Use embedded magic rules regardless of other flags
  2. --magic-file PATH flagUse explicitly specified custom magic file or directory
  3. Platform-specific automatic discoverySearch standard system locations for magic files
  4. Error with actionable messageIf no magic file is found, display suggested options

Platform-Specific Magic File Discovery#

When no explicit magic file is specified, rmagic implements an OpenBSD-inspired search strategy that prefers human-readable text files over compiled binary .mgc files.

Unix/Linux/macOS Search Order#

The search is defined in the MAGIC_FILE_CANDIDATES constant, with text files/directories checked first, binary .mgc files as fallbacks:

Text format (highest priority):

  1. /usr/share/file/magic/Magdir (OpenBSD-style directory)
  2. /usr/share/file/magic (text directory/file)
  3. /usr/share/misc/magic (BSD text)
  4. /usr/local/share/misc/magic (FreeBSD/Homebrew)
  5. /etc/magic (system-wide text)
  6. /opt/local/share/file/magic (MacPorts)

Binary format (fallback):
7. /usr/share/file/magic.mgc
8. /usr/local/share/misc/magic.mgc
9. /opt/local/share/file/magic.mgc
10. /etc/magic.mgc
11. /usr/share/misc/magic.mgc

If none of these paths exist, rmagic falls back to /usr/share/file/magic.mgc.

Windows Search Order#

On Windows, the tool checks %APPDATA%\Magic\magic first, then falls back to the bundled third_party/magic.mgc:

  1. %APPDATA%\Magic\magic
  2. third_party/magic.mgc (bundled fallback)

Environment Variables#

Environment variables are used only for internal magic file discovery and CI/CD detection, not exposed as CLI configuration:

VariablePlatformPurpose
CIUnixCI/CD environment detection
GITHUB_ACTIONSUnixGitHub Actions detection
APPDATAWindowsUser application data directory

No Configuration File Support#

The CLI does not support configuration files. All configuration must be provided via command-line flags.


Mutually Exclusive Options and Validation#

Clap-Level Validation#

Mutual exclusivity between --json and --text is enforced via clap's conflicts_with attribute, which prevents both flags from being specified simultaneously. This produces an immediate error before any processing:

$ rmagic --json --text file.bin
error: the argument '--json' cannot be used with '--text'

Application-Level Validation#

The validate_arguments() function performs additional validation:

  1. Files vector checkEnsures at least one file argument is provided (redundant with clap's required = true)
  2. Magic file path checkValidates that magic file paths are non-empty when provided

Configuration Validation#

The EvaluationConfig::validate() method enforces runtime constraints:

ParameterValid RangeDefaultValidation
max_recursion_depth1-1,00020Must be within bounds
max_string_length1-1,048,576 bytes8,192Must be within bounds
timeout_ms1-300,000 (5 min)NoneMust be within bounds when specified
Resource combination--Rejects high recursion (>100) + large strings (>65KB)

Output Format Detection and Selection#

Text Output (Default)#

Text output prints one line per file in the format filename: description:

$ rmagic image.png document.pdf
image.png: PNG image data
document.pdf: PDF document

When a file type cannot be determined, the description is data:

$ rmagic unknown.bin
unknown.bin: data

JSON Output Format#

The CLI automatically selects between two JSON formats based on the number of input files:

Single File: Pretty-Printed JSON#

Single file analysis produces pretty-printed JSON with a matches array:

$ rmagic --json image.png
{
  "matches": [
    {
      "description": "PNG image data",
      "offset": 0,
      "tags": ["image", "png"],
      "mime_type": "image/png",
      "score": 90
    }
  ]
}

Multiple Files: JSON Lines Format#

Multiple files produce JSON Lines format (newline-delimited JSON):

$ rmagic --json file1.bin file2.txt
{"filename":"file1.bin","matches":[...]}
{"filename":"file2.txt","matches":[...]}

Each line is a self-contained JSON object, making it straightforward to parse with line-oriented tools:

$ rmagic --json *.bin | jq -r '.filename + ": " + .matches[0].mime_type'

This automatic format selection eliminates user configuration needs and optimizes for the most common use case.


Built-in Magic Rules#

The --use-builtin flag was introduced in PR #28 to provide pre-compiled magic rules embedded in the binary. The built-in rules cover common file types: ELF, PE/DOS, ZIP, TAR, GZIP, JPEG, PNG, GIF, BMP, and PDF. They are compiled at build time and require no external files, making the CLI portable and reliable when system magic files are unavailable.

# Use built-in rules (no external magic file required)
$ rmagic --use-builtin binary.exe
binary.exe: PE32 executable

Built-in rules provide a fallback mechanism when magic file discovery fails, ensuring the tool remains functional in restricted environments.


Stdin Support#

PR #27 introduced stdin support via the clap-stdin crate. Use - as the filename argument to read input from stdin:

$ cat sample.bin | rmagic -
stdin: data

$ echo "hello" | rmagic -
stdin: data

Stdin Behavior#

The process_file() function handles stdin specially:

Combining Stdin with Files#

Stdin can be combined with regular file arguments:

$ rmagic --use-builtin file1.bin - file2.txt < input.dat
file1.bin: ZIP archive data
stdin: data
file2.txt: ASCII text

Timeout Configuration#

The --timeout-ms flag was introduced in PR #27 to prevent indefinite hangs on complex magic rule evaluations. The flag sets a per-file timeout for magic rule evaluation, with each file receiving its own independent timeout window.

# Set a 500ms timeout per file
$ rmagic --timeout-ms 500 large_file.bin

# Combine with strict mode to fail on timeout
$ rmagic --strict --timeout-ms 1000 *.bin

Valid values range from 1 to 300,000 milliseconds (5 minutes). If evaluation exceeds the specified duration, the file is skipped with an error and exit code 5 (timeout) in strict mode.


Strict Mode and Error Handling#

Non-Strict Mode (Default)#

Without --strict, processing errors for individual files are printed to stderr but do not affect the exit code. The tool continues processing remaining files and exits 0 if the overall invocation succeeded:

$ rmagic good.png /nonexistent bad_perms.bin
good.png: PNG image data
Error processing /nonexistent: ...
Error processing bad_perms.bin: ...
$ echo $?
0

Strict Mode#

With --strict, the first processing error (I/O, parse, or evaluation) causes a non-zero exit code. The tool still processes all files and prints errors as they occur, but returns the exit code corresponding to the first error:

$ rmagic --strict good.png /nonexistent bad_perms.bin
good.png: PNG image data
Error processing /nonexistent: ...
Error processing bad_perms.bin: ...
$ echo $?
3

A "data" result (unknown file type) is never treated as an error, even in strict mode.

Exit Codes#

The handle_error() function maps errors to Unix-style exit codes:

CodeMeaningError Types
0SuccessNormal completion
1General errorEvaluationError, ConfigError
2Invalid argumentsIoError with InvalidInput kind
3File not found/access deniedIoError with NotFound or PermissionDenied
4Magic file errorParseError
5Evaluation timeoutTimeout error

Multiple File Processing#

When multiple files are provided, each file is processed sequentially with independent error handling. A failure in one file does not prevent processing of subsequent files:

$ rmagic --use-builtin image.png archive.zip README.md
image.png: PNG image data
archive.zip: Zip archive data
README.md: data

Errors for individual files are printed to stderr with the filename for context:

$ rmagic --use-builtin good.png /nonexistent bad_perms.bin
good.png: PNG image data
Error processing /nonexistent: File not found
Error processing bad_perms.bin: Permission denied

Usage Examples#

Basic File Identification#

# Identify a single file
$ rmagic document.pdf
document.pdf: PDF document, version 1.4

# Identify multiple files
$ rmagic file1.bin file2.exe file3.pdf
file1.bin: data
file2.exe: PE32 executable (console) Intel 80386
file3.pdf: PDF document, version 1.7

# Use built-in rules
$ rmagic --use-builtin archive.tar.gz
archive.tar.gz: gzip compressed data

JSON Output for Scripting#

# Single file with pretty JSON
$ rmagic --json executable.elf
{
  "matches": [
    {
      "description": "ELF 64-bit LSB executable",
      ...
    }
  ]
}

# Multiple files with JSON Lines
$ rmagic --json file1.bin file2.bin file3.bin
{"filename":"file1.bin","matches":[...]}
{"filename":"file2.bin","matches":[...]}
{"filename":"file3.bin","matches":[...]}

# Parse JSON output with jq
$ rmagic --json binary.exe | jq '.matches[0].mime_type'
"application/x-dosexec"

# Extract MIME types from multiple files
$ rmagic --json *.bin | jq -r '.filename + ": " + .matches[0].mime_type'

Custom Magic Files#

# Use specific magic file
$ rmagic --magic-file /path/to/custom.magic firmware.img
firmware.img: Custom firmware image

# Use magic directory (Magdir style)
$ rmagic --magic-file /usr/share/file/magic files/*

Error Handling and Strict Mode#

# Default: continue on errors, exit 0
$ rmagic file1.bin /nonexistent file2.bin
file1.bin: data
Error: /nonexistent: No such file or directory
file2.bin: ELF 64-bit LSB executable
$ echo $?
0

# Strict mode: fail on first error
$ rmagic --strict file1.bin /nonexistent file2.bin
file1.bin: data
Error: /nonexistent: No such file or directory
file2.bin: ELF 64-bit LSB executable
$ echo $?
3

Timeout Protection#

# Set per-file timeout
$ rmagic --timeout-ms 5000 large-file.bin

# Combine with strict mode
$ rmagic --strict --timeout-ms 10000 *.bin

# Batch processing with timeout protection
$ find . -type f | xargs rmagic --timeout-ms 1000 --use-builtin

Pipeline and Batch Operations#

# Find all ELF files in a directory
$ find . -type f -exec rmagic --use-builtin {} + | grep ELF

# Process files and output JSON Lines
$ for f in *.bin; do
    rmagic --json "$f" >> results.jsonl
done

# Use with xargs
$ find . -name "*.dat" -print0 | xargs -0 rmagic --use-builtin

# Filter by MIME type
$ rmagic --json *.bin | jq -r 'select(.matches[0].mime_type == "application/x-executable") | .filename'

Stdin Processing#

# Read from stdin
$ cat sample.bin | rmagic -
stdin: data

# Combine stdin with files
$ rmagic --use-builtin file1.bin - file2.txt < input.dat
file1.bin: ZIP archive data
stdin: data
file2.txt: ASCII text

# Pipeline stdin processing
$ curl -s https://example.com/file | rmagic --json -

Scripting Examples#

#!/bin/bash
# Check if file is an image

if rmagic --use-builtin "$1" | grep -q "image"; then
    echo "File is an image"
    exit 0
else
    echo "File is not an image"
    exit 1
fi
#!/bin/bash
# Batch convert images based on detected format

for file in *; do
    format=$(rmagic --json "$file" | jq -r '.matches[0].mime_type')
    case "$format" in
        image/png)
            convert "$file" "${file%.png}.jpg"
            ;;
        image/jpeg)
            echo "Already JPEG: $file"
            ;;
    esac
done

Implementation Files#

The rmagic CLI is implemented in the following source files:


Design Decisions and Rationale#

1. Text-First Magic File Discovery#

rmagic prefers human-readable text magic files over compiled binary .mgc files for better debuggability and version control compatibility. This OpenBSD-inspired approach makes it easier for users to inspect, modify, and debug magic rules without specialized tools.

2. Automatic JSON Format Selection#

The CLI automatically selects between pretty-printed JSON (single file) and JSON Lines format (multiple files) based on input count. This eliminates user configuration burden while optimizing for common use cases: human readability for single-file inspection and machine parsing for batch processing.

3. Independent Timeout Per File#

Each file receives its own independent timeout window rather than a global timeout, allowing flexible processing of mixed file sets without penalizing fast evaluations for the actions of slow ones.

4. Graceful Degradation in Non-Strict Mode#

Processing errors do not halt execution or affect exit code unless --strict is specified, enabling robust batch processing of potentially problematic files. This is appropriate for exploratory use cases, while strict mode serves CI/CD and validation scenarios.

5. Built-in Rules Always Available#

Pre-compiled magic rules for common formats are embedded in the binary via the --use-builtin flag, eliminating external dependencies and ensuring predictable behavior. This makes rmagic portable and reliable in restricted environments where system magic files may be unavailable.

6. No Configuration File Support#

The CLI deliberately avoids configuration file support, keeping the interface simple and explicit. All configuration happens via flags, making invocations self-documenting and reproducible.

7. Clap Derive for Declarative Argument Parsing#

The use of clap derive macros provides compile-time validation of CLI argument definitions, reducing runtime errors and making the CLI interface more maintainable. Mutual exclusivity is enforced declaratively via conflicts_with attributes.

8. Actionable Error Messages#

When magic file discovery fails, the CLI displays actionable error messages with suggested options and example commands, following best practices for user experience. This reduces friction for new users and makes troubleshooting straightforward.


  • Magic Rule Parsing – The parser implementation that loads and interprets magic file formats
  • Evaluation Engine – The core engine that applies magic rules to file buffers
  • Library API – The Rust library API for embedding libmagic-rs in applications
  • Built-in Rules Generation – Build-time compilation of magic rules into the binary
  • Output Formatting – Implementation of text and JSON output formats