hdiutil / hdik port plan — four optionsDecision document for the hdiutil/hdik/DiskImages workstream on freebsd-launchd-mach. Spun out of the v3 userland-cmds plan §16 deferred scoping after research into Darling's reimplementation revealed it's a partial-surface, copyleft-licensed substitute — not the drop-in replacement the original v3 deferral assumed. Four implementation paths are laid out below for later decision. No decision is being made in this document; it's for review and selection.
mdconfig/mdmfs from /usr/src (transitional gap-filler manifest per the v3 plan).
hdiutil/hdik actually dodarling-dmg as-is (GPL-3.0)darling-dmg + extend to full surfacefreebsd-launchd-mach is dropping FreeBSD-runtime + FreeBSD-utilities and replacing the userland with Apple-source ports. Per the userland-cmds v3 plan, every Apple userland repo we have open-source for gets vendored + ported. hdiutil/hdik are the gap — Apple-closed, no source to vendor, yet expected to be present at Apple-canonical paths.
The function this fills on the live ISO: create, attach, manipulate disk images — both the daily-driver "mount a downloaded DMG" use case AND the install-image production case (creating system images, converting between sparse/compressed/RW formats, etc.). FreeBSD's existing mdconfig/mdmfs cover the underlying memory-disk plumbing but expose a totally different CLI and don't speak DMG format at all.
hdiutil/hdik actually doPer the macOS 14 hdiutil(1) man page, ~30 subcommands:
| Category | Subcommands | What it does |
|---|---|---|
| Attach / detach | attach, detach, eject, mount, unmount, mountvol | Bind a disk image to a synthetic /dev/disk* device and mount its filesystem(s). |
| Create / format | create, partitiondisk, erasedisk, fdisk | Make a new disk image (sized, sparse, sparse bundle, encrypted, with specific format). |
| Convert | convert, makehybrid | Transform between formats: UDIF, UDZO, UDBZ, UDRO, ULFO, sparse, sparse bundle, ISO, IMG, NDIF, DC42, etc. makehybrid produces ISO/HFS+ hybrid images for cross-platform optical media. |
| Information | info, imageinfo, isencrypted, plugins, pmap, fsid, checksum, verify | Metadata inspection, partition-map dump, integrity check. |
| Maintenance | compact, resize, segment, chpass | Shrink unused space, grow image, split into segments, change encryption password. |
| Resource-fork tools | udifrez, udifderez | Get/set UDIF resource entries inside a DMG. |
| Optical-media | burn | Burn a disk image to CD/DVD via Apple's burning infrastructure. |
| Web-distribution | internet-enable | Toggle the Safari "auto-open after download" flag. |
| Low-level | conversion, mediakit | MediaKit framework introspection. |
hdik is the lower-level worker that hdiutil attach shells out to. It does the actual disk-image attach (creates the /dev/disk* node via IOHDIXController kext), without all of hdiutil's format conversion and metadata logic. On macOS today most attach paths go through hdiutil; hdik is the in-process helper.
Source availability: all of the above is closed-source. DiskImages.framework (which both hdiutil and hdik link) has never been published. The kext (IOHDIXController) is also closed in modern macOS. Apple's opensource.apple.com has no DiskImages, no hdiutil, no hdik, no IOHDIXController. Public references: the hdiutil(1) man page, Apple Technote TN1150 (HFS+), and the UDIF format reverse-engineering work done by the open-source community (notably by Jonathan Levin and the Darling team).
Two research deep-dives (2026-05-26, this session) confirmed the following coverage in the Darling project:
| Darling artifact | What it provides | Status |
|---|---|---|
darling-dmg (standalone repo) | FUSE-based, read-only hdiutil attach + detach. Parses UDIF containers (UDZO/UDBZ/UDRO/ULFO/Raw/ADC). From-scratch HFS+ reader (catalog B-tree, extents, attributes, resource forks, transparent zlib compression). Reads partition maps (APM, GPT). ~9 KB hdiutil shim + ~15 KB HFS+ B-tree + ~38 KB total source. | Working but narrow |
darling-dmg license | GPL-3.0 (full FSF text in LICENSE) | Copyleft |
hdik binary | Nothing | Never reimplemented |
DiskImages.framework | ~38 KB of void* foo(void) { return NULL; } stubs to satisfy dynamic link references. No functional behavior. | Link-stub only |
diskutil | 999-byte shell script. One verb (eject → shells to hdiutil detach). All others print "did not recognize verb". | Effectively nothing |
asr (Apple Software Restore) | Nothing | Completely missing |
hdiejectd, diskimages-helper, IOHDIXController, vsdbutil, MediaKit.framework | Nothing | All completely missing |
Darling's hdiutil coverage vs Apple's:
| Apple subcommand category | darling-dmg coverage |
|---|---|
| Attach/detach | 2 of 6 subcommands (attach, detach); read-only; ~60% of attach's flags |
| Create/format | 0 of 4 |
| Convert | 0 of 2 |
| Information | 0 of 8 (BLKX checksums are parsed but never validated) |
| Maintenance | 0 of 4 |
| Resource-fork | 0 of 2 |
| Optical-media | 0 of 1 |
| Web-distribution | 0 of 1 |
| Low-level | 0 of 2 |
| Total coverage | ~7% of subcommand surface (2/30) |
Functional coverage for the common case "open a downloaded UDZO/ULFO DMG, read files out of the HFS+ volume" is high. That one path is the project's entire goal.
Architecture: pure userland FUSE 2.x. No kernel helper, no /dev/disk* node creation. hdiutil attach daemonizes darling-dmg, which mounts the HFS+ volume via FUSE; hdiutil detach shells to fusermount -u.
FreeBSD portability: excellent. The source already has #ifdef __FreeBSD__ branches in src/be.h; no Linux-specific headers (linux/fs.h, sysfs, /proc, FIEMAP) anywhere in src/; only <sys/stat.h> + POSIX. FreeBSD ships fusefs-libs (libfuse 2.9.x, ABI-compatible) and the fusefs(5) kmod. darling-dmg should compile out of the box after pkg install fusefs-libs icu libxml2 openssl. The Darling-specific shim (main-hdiutil.cpp) needs replacing with a ~150-line native wrapper (no <elfcalls.h>, no __darling_vchroot_expand).
| Tool | What it does | Comparable to Apple's... |
|---|---|---|
mdconfig(8) | Create/destroy md(4) memory disks (vnode-backed, malloc-backed, swap-backed). Returns /dev/md* node. | The attach primitive only. No format parsing, no compression, no encryption. |
mdmfs(8) | Wrapper: mdconfig + newfs + mount in one step to make a memory-disk-backed UFS volume. | Roughly hdiutil attach -nomount followed by Disk Utility format. |
fdisk, gpart, bsdlabel | Partition-table tooling. | hdiutil pmap, hdiutil partitiondisk partially. |
| (missing) | DMG/UDIF format parsing | Most of hdiutil's value. |
| (missing) | HFS+ filesystem reader (no kmod, no fuse module shipped) | Required to mount Mac DMGs. |
| (missing) | APFS reader | Required for modern Mac DMGs (post-10.13 system images). |
FreeBSD's md(4) is the kernel-side analogue of Apple's IOHDIXController in terms of "expose a file as a block device," but it doesn't parse any disk-image format — it takes a raw file or already-formatted volume and exposes it. All format/compression/encryption logic on Apple lives in userland hdiutil + DiskImages.framework. So the Apple-shape "hdiutil attach foo.dmg" requires: (1) a DMG parser to find the embedded HFS+/APFS volume, (2) an HFS+/APFS reader to actually mount it, (3) the binding of (2)'s output to a synthetic /dev/disk* via md(4). FreeBSD has only (3).
hdiutil written from scratch into src/hdiutil/What it is: implement hdiutil's CLI surface from scratch in C/C++, written against Apple's published man page + Apple Technote TN1150 (HFS+) + the public UDIF format documentation. License under MIT or BSD-2-Clause to align with the rest of our src/ tree. No GPL'd code anywhere in the lineage; Darling sources used only as reference for confirming behavior, not copied.
What we deliver:
/usr/bin/hdiutil — the CLI binary at Apple-canonical path/usr/libexec/hdik — the attach worker, if we want to mirror Apple's two-binary split/usr/lib/libDiskImages.dylib (or .so.1) — the format/compression library; private to our tools/usr/include/DiskImages/ for future Apple-shape consumersSurface staged in phases (see §11 for the phased breakdown). Phase 1 = read-only attach/detach with UDZO/UDRO/ULFO and HFS+. Phase 2 = info/imageinfo/verify/checksum. Phase 3 = create and write support. Phase 4 = convert + sparse formats. Phase 5+ = the rest.
Effort estimate:
md(4) binding glue (~500 LOC), CLI argv + plist output (~500 LOC).Tradeoffs:
src/ tree; full vendoring storyhdiutil attach on the ISO (months, not weeks)darling-dmg as-is (GPL-3.0)src/darling-dmg/; ship as /usr/bin/hdiutilWhat it is: git-submodule or copy darling-dmg's source into our tree under src/darling-dmg/. Build it as-is against FreeBSD's fusefs-libs. Install the FUSE binary at /usr/libexec/darling-dmg; install the (rewritten) hdiutil shim at /usr/bin/hdiutil. License the vendored tree (and our shim) under GPL-3.0.
What we deliver:
/usr/bin/hdiutil — GPL-3.0 shim; ~150 LOC native BSD rewrite of Darling's main-hdiutil.cpp/usr/libexec/darling-dmg — the FUSE backend binary, GPL-3.0/usr/lib/libdmg.so — GPL-3.0 library; only linked by the above two binariesSurface delivered: ~7% of Apple's hdiutil. attach + detach only; read-only; UDIF formats only; HFS+/HFSX volumes only (no APFS).
Effort estimate:
<elfcalls.h> + the Mach-O/ELF bridge).Tradeoffs:
hdiutil attach on the ISO — weeks not monthssrc/ tree; full vendoring storygcc 4.2.1 specifically to dodge the GPL-3.0 patent-grant clause; replaced GCC with clang/LLVM (Apache 2.0). Per rule 3, shipping GPLv3 inside an Apple-shape userland is knowingly diverging from Apple's licensing posture.hdiutil create / convert / info / etc. breaklibdmg.so must NEVER be linked into non-GPL binaries or those binaries become GPL-3.0; documented constraint with risk of accidental violationdarling-dmg + extend to full surfaceWhat it is: Option B as the starting point, then incrementally add the missing 28 subcommands (create, convert, info, verify, compact, resize, etc.) on top of darling-dmg's existing UDIF parser and HFS+ reader. Because GPL-3.0 is copyleft, our extensions also become GPL-3.0.
What we deliver:
hdiutil over time, all GPL-3.0Effort estimate: Phase 1 = Option B (1–2 weeks). Phase 2–5 broadly comparable to Option A's later phases (~6–12 months of part-time work to cover the breadth of create/convert/compact/etc.).
Tradeoffs:
libdmg.so linking constraint as in Option B, but more painful: any helper binary we add (hdik, diskimages-helper) inherits GPL-3.0mdconfig/mdmfs from /usr/src; no hdiutil shippedWhat it is: the current v3 plan position. Live ISO continues to use FreeBSD's mdconfig/mdmfs from the gap-filler manifest. No hdiutil binary is installed at Apple-canonical paths. DMG files have to be manually unpacked with third-party tools (e.g., dmg2img from pkg) if needed; Mac-source workflows that expect hdiutil just fail.
What we deliver: nothing. Status quo.
Effort estimate: zero.
Tradeoffs:
hdiutil sees "command not found"| Dimension | A: Clean-room | B: Vendor as-is | C: Vendor + extend | D: Defer |
|---|---|---|---|---|
Time to first working hdiutil attach |
Months | 1–2 weeks | 1–2 weeks | Never |
| Eventual subcommand coverage | Phased; targetable to ~100% | ~7% (forever, unless reclassified to C) | Phased; targetable to ~100% | 0% |
| License | MIT/BSD-2 | GPL-3.0 | GPL-3.0 | n/a |
| Apple-divergence (rule 3) | Aligned (no GPLv3, like Apple) | Divergent (Apple avoids GPLv3) | Divergent | Aligned by absence |
| Total write effort | ~10K LOC + ongoing | ~150 LOC shim | ~150 LOC shim + ~10K LOC extensions | 0 |
| Linking-constraint risk | None | libdmg.so can't be linked into non-GPL binaries |
Same; more surface to police | None |
| Re-licensability of our work | Full | None (vendored is GPL-3.0) | None (extensions inherit GPL-3.0) | n/a |
| APFS support path | Phase 5+; we control it | Never (darling-dmg has no APFS) | Future GPL-3.0 work | Never |
| Write/create support | Phase 3+ | Never | Future GPL-3.0 work | Never |
FreeBSD precedent: the base system has shipped GPLv2 (gcc 4.2.1, groff, some diff tools) for decades. GDB was in base and was GPLv3 at one point. The "BSD only" framing is aspirational, not absolute; FreeBSD does ship GPLv3 components when there's no alternative.
Apple precedent: Apple explicitly avoids GPLv3. They froze on gcc 4.2.1 — the last GPLv2 release — rather than upgrade to a GPLv3 gcc. They eventually replaced GCC entirely with clang/LLVM (Apache 2.0). They also avoid GPLv3 versions of bash (frozen on bash 3.2), readline, etc. The reasons are widely understood to be the GPLv3 patent-grant clause and the anti-tivoization clause.
Net read for this project: shipping GPLv3 inside an otherwise Apple-shape userland is a knowingly-divergent choice. It's not a legal block, but it's a posture mismatch. Per rule 3 ("don't invent things Apple doesn't do"), the lean is toward avoiding GPL-3.0 if there's a reasonable alternative — and Option A is a reasonable alternative. The question is whether the time-to-delivery benefit of Options B/C outweighs the posture mismatch.
libdmg.so linking constraint (Options B and C)GPL-3.0 is copyleft. Any binary that links (statically or dynamically) against libdmg.so is "based on" GPL-3.0 work and itself becomes subject to GPL-3.0 distribution requirements (source must be made available, etc.). Practically this means: only hdiutil and hdik binaries (which we're OK with being GPL-3.0) can link libdmg.so. Any other tool that wants DMG-parsing capability would have to either (a) become GPL-3.0 too, or (b) shell out to hdiutil rather than linking.
This is a permanent operational discipline. Easy to enforce with a CI check (ldd on each non-GPL binary, fail if libdmg.so appears). But it's a permanent constraint that doesn't exist under Option A.
hdik as a separate binaryOn Apple, hdik is the lower-level attach worker that hdiutil shells to. Under our options:
hdik; we'd have to write a stub or skip it. hdiutil just calls into libdmg.so directly.hdik can be written as a thin GPL-3.0 wrapper if Apple-shape topology is wanted.Modern Mac DMGs (post-macOS 10.13) often contain APFS volumes, not HFS+. APFS is open-spec but Apple's reference implementation is closed. Third-party readers exist (libapfs, apfs-fuse) but coverage is partial and quality varies.
| Option | APFS path |
|---|---|
| A | Add APFS reader as a later phase; pick from MIT-compatible libraries or write our own. |
| B | No APFS, ever — darling-dmg has none. |
| C | Add APFS as GPL-3.0 extension; could vendor apfs-fuse (GPL-2 or GPL-3) under our broader GPL-3 envelope. |
| D | n/a. |
md(4) binding for synthetic /dev/disk*Apple's hdiutil attach creates a /dev/disk* node via IOHDIXController. Our equivalent under any option is binding to FreeBSD's md(4) — vnode-backed memory disk creates /dev/md*. We'd either (a) symlink or alias /dev/disk* → /dev/md* for Apple-shape paths, or (b) name disagree with Apple and accept it. This is independent of the option chosen above; it's the actual attach mechanism.
For the FUSE-based Options B and C: no /dev/disk* at all — the mount target is a normal FUSE mountpoint. Apps that look for /dev/disk* won't find it. This is a structural divergence from Apple's model that darling-dmg accepts; we'd inherit it.
Phasing for incremental delivery. Each phase ships independently with its own CI marker.
| Phase | What lands | CI marker | Apple coverage gain |
|---|---|---|---|
| 1 | attach + detach for UDZO/UDRO/ULFO + HFS+; read-only |
HDIUTIL-ATTACH-OK |
~7% (matches darling-dmg) |
| 2 | info, imageinfo, checksum, verify, pmap, isencrypted, plugins |
HDIUTIL-INFO-OK |
~25% |
| 3 | create (sparse + sparse-bundle), write support to HFS+ filesystem creation |
HDIUTIL-CREATE-OK |
~45% |
| 4 | convert (UDIF↔sparse↔sparse-bundle), compact, resize, segment |
HDIUTIL-CONVERT-OK |
~65% |
| 5 | APFS reader (mount-only first; write later if needed) | HDIUTIL-APFS-OK |
~75% |
| 6 | Encryption (chpass, attach with password, sparse-encrypted) |
HDIUTIL-ENCRYPT-OK |
~85% |
| 7+ | Long tail: burn, internet-enable, makehybrid, udifrez/udifderez, NDIF read, … |
(per-feature) | ~100% |
Realistic mileage: phases 1–3 are the load-bearing feature set for any actual ISO-production workflow. Phases 4–6 cover the daily-driver "I downloaded a DMG" experience. Phase 7+ is optional polish that may never need shipping.
Drafted 2026-05-26. Companion to the freebsd-apple-userland-cmds v3 plan §16 deferred scoping. Source data: two parallel research agent passes against darlinghq/darling-dmg and darlinghq/darling source trees, plus reference to Apple's hdiutil(1) man page and Technote TN1150. Decision pending in §9.