Lightweight disk identity, mount, and S.M.A.R.T. extraction toolkit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

7.3 KiB

bsdiskinfo

A lightweight, modular, and dependency-free FreeBSD C library along with high-performance native Lua bindings for extracting precise hardware disk identity properties, active filesystem mounts, and raw S.M.A.R.T. metrics.

The architecture strictly separates the system-level extraction engine from execution layers, allowing easy integration with multiple runtime environments (Lua, Python, Go, etc.) without inflating overhead or calling external binaries.

Features

  • Advanced Identity Verification: Direct hardware query via libcam taskfiles. Successfully bypasses standard USB bridge constraints using SCSI SAT ATA PASS-THROUGH (16) to pull authentic models, serial numbers, firmware versions, WWN identifiers, and native sector geometry configs.
  • Granular Type Classification: Employs robust heuristics to accurately identify target media storage profiles (ssd, hdd, nvme, sdcard, or standard usb drive tokens).
  • Fast Mount Traversal: Scans active filesystem topologies directly via kernel getfsstat wrappers with non-blocking configurations, safely mitigating hung network storage paths.
  • Isolated S.M.A.R.T. Matrix Layout: Exposes full 30-slot attribute maps to user space, eliminating raw hex-parsing complexities inside scripting architectures.

Repository Structure

bsdiskinfo/
├── include/
│   └── bsdiskinfo.h         # Public standalone C API header
├── src/
│   ├── libbsdiskinfo.c      # Core library implementation layers
│   ├── cli.c                # POSIX-compliant administrative CLI testbed
│   └── smart.h              # Shared structural S.M.A.R.T. hardware definitions
├── modules/
│   └── lua/
│       ├── Makefile         # Dynamic Lua module build configurations
│       └── lua_bsdiskinfo.c # High-performance C-to-Lua binding translator
│   └── perl/
│       ├── Makefile.PL       # Perl ExtUtils::MakeMaker build script
│       ├── bsdiskinfo.xs     # Core C-to-Perl XS translator bridge
│       └── lib/
│           └── bsdiskinfo.pm # Public Perl module interface and POD docs
├── examples/
│   └── tree_view.lua        # Complex hardware tree mapping layout example
├── LICENSE                  # BSD 2-Clause Simplified License
└── Makefile                 # Native FreeBSD root pmake script

Building and Installation

The build workflow utilizes native FreeBSD bmake engines and standard pkg-config routines to automatically discover installed platform toolchains.

Build Everything (Library + CLI + Lua Module)

make

Build Library Only (Headless C Environment)

make WITHOUT_CLI=1 WITHOUT_LUA=1

Build Targeting a Specific Lua Environment

make LUA_VER=5.1

Build without Perl XS module bindings

make WITHOUT_PERL=1

Build targeting a specific custom Perl layout

cd modules/perl && perl Makefile.PL PREFIX=/my/path && make

Standard System Deployment

sudo make install

Installs components under /usr/local/ paths (lib/, include/, sbin/, and corresponding Lua runtime folders).

Usage Profiles

Binary CLI Diagnostic Tool

You can invoke the isolated diagnostics executable directly via administrative flags (-i identity, -m mounts, -s S.M.A.R.T.):

# Print identity and active storage mount points for a block device node
./bsdiskinfo-cli -im ada0

Lua Scripting Layer Integration

A production-ready implementation mapping out the whole physical ecosystem using devel/lua-sysctl looks like this:

local bsdiskinfo = require("bsdiskinfo")
local sysctl = require("sysctl")

local disks_str = sysctl.get("kern.disks") or ""
for disk in disks_str:gmatch("%S+") do
    local props = bsdiskinfo.get_properties(disk)
    if props then
        print(string.format("Drive: /dev/%s [Model: %s, Serial: %s, Type: %s]", 
            disk, props.model, props.serial, props.type))
            
        -- Process mount objects safely
        local mounts = bsdiskinfo.get_mounts(disk) or {}
        for _, mnt in ipairs(mounts) do
            print(string.format("  └─ Mounted partition %s at %s", mnt.device, mnt.path))
        end
    end
end

(See more extensive processing inside examples/tree_view.lua).

Perl5 Scripting Layer Integration

A production-ready Perl 5 execution layer maps out the storage ecosystem using high-performance native XS structures. For direct kernel MIB tree traversal without spawning shell processes, the sysutils/p5-BSD-Sysctl port is highly recommended as a companion dependency.

The integration utilizes standard UTF-8 stream handling to seamlessly draw complex nested topology layouts:

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;
use open qw/:std :encoding(utf8)/; # Ensures proper UTF-8 printing bounds

use bsdiskinfo;
use BSD::Sysctl; # Native FreeBSD kernel MIB traversal bindings

# Query available physical drives straight from the kernel tree
my \$disks_str = BSD::Sysctl::sysctl('kern.disks') // "";

for my \(disk (sort (split /\s+/,\)disks_str)) {
    # Protect routing logic by verifying character device existence
    next unless bsdiskinfo::exists(\$disk);

    my \(props = get_properties(\)disk);
    if (\$props) {
        print "Drive: /dev/\$disk [Model: props->model, Type: props->{type}]\n";

        # Traverse active slices and mounted partitions
        my \(mounts = get_mounts(\)disk) // [];
        for my \(mnt (@\)mounts) {
            print "  └─ Partition \$mnt->{device} mounted at mnt->path (mnt->{fstype})\n";
        }
    }
}

(See examples/tree_view.pl for an expanded implementation containing full raw S.M.A.R.T. matrix unpacking).

Device Access & Permissions

By default, raw character device nodes under /dev/ (e.g., /dev/ada*, /dev/da*) are strictly accessible only by the root user in FreeBSD. Running the binary CLI tool or calling the Lua module as an unprivileged user will fail during transport library initialization (Permission denied).

To safely grant a specific non-root user or daemon group (e.g., operator) execution rights to query hardware parameters without escalating system-wide privileges, configure the native FreeBSD devfs rules subsystem.

1. Append Rules to /etc/devfs.rules

Create or modify the local rulesets configuration file to assign proper ownership and read/write accessibility maps to storage targets:

[local_devices=10]
add path 'ada*' mode 0660 group operator
add path 'da*'   mode 0660 group operator
add path 'nvme*' mode 0660 group operator

2. Enable the Ruleset inside /etc/rc.conf

Instruct the kernel subsystem init profiles to mount the default active /dev structure bound strictly against your custom ruleset index sequence:

devfs_system_ruleset="local_devices"

3. Apply Changes Immediately

Restart the system-wide device filesystem management daemon wrapper layer to evaluate state mutations on the fly:

sudo service devfs restart

Ensure your unprivileged target runtime user account belongs to the configured destination group mapping bounds (e.g., pw groupmod operator -m myuser).

License

This project is licensed under the terms of the BSD 2-Clause Simplified License. See LICENSE for details.