Skip to content

Commit c424232

Browse files
committed
freebsd-libxpc plan: Phase 5 = clean Apple launchd-842.92.1 import (not ravynOS fork)
Apple's open-source launchd hasn't moved since 2014 (launchd-842.92.1). Both freebsd-launchd's minimal rewrite and ravynOS's near-full launchd descend from this same source. Phase 5 imports it verbatim and layers patches on top, matching how configd is already imported in freebsd-launchd and how libdispatch is patched in gershwin-developer. Why this over a ravynOS fork: clean provenance (every commit is either Apple verbatim or our patch), license clarity, no inheritance of NextBSD's 36 dormant #if 0/FIXME bisect markers, consistent with our configd / libdispatch / libxpc import pattern, easy re-imports if Apple ever publishes a newer launchd. Estimated patch size: ~700-1500 lines on top of ~16,500 lines of clean Apple source. Patches cover: bsd.prog.mk Makefile, MIG .defs build orchestration, Mach API compat shims for our libmach subset, <Availability.h> macros, audit-session workaround, per-user env file. Also updated cross-references: the bootstrap-server risk discussion now explains the Phase 3 (small standalone) vs Phase 5 (full Apple launchd) split; the table-level summary points to the new Phase 5 approach.
1 parent 542e6c5 commit c424232

1 file changed

Lines changed: 73 additions & 12 deletions

File tree

‎freebsd-libxpc-plan.html‎

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,12 @@ <h3>launchd</h3>
479479

480480
<p><strong>Critical missing pieces from <code>freebsd-launchd</code>:</strong> EnvironmentVariables, StartCalendarInterval, WorkingDirectory, UserName/GroupName, StandardOut/ErrorPath, Umask, ThrottleInterval, <code>launchctl load -w</code>, enable/disable, override-file mechanism. Per <a href="freebsd-launchd-plan.html"><code>freebsd-launchd-plan</code></a>'s matrix &mdash; Phase 5 batch is the remaining work.</p>
481481

482-
<p><strong>Decision-critical:</strong> The NextBSD/ravynOS launchd is closer to Apple parity but only runs on a Mach-coupled kernel. Now that our <code>mach.ko</code> exists, we could theoretically <em>swap forward</em> &mdash; replace <code>freebsd-launchd</code>'s daemon with NextBSD/ravynOS's launchd source built against our libmach + libxpc. The cost is wiring all the missing Mach port traps (see <a href="#deps">&sect;6</a>) and getting the bootstrap server alive. The benefit is jumping from 1,500 LoC of hand-coded subset to 16k LoC of battle-tested Apple-shape code. <strong>This swap is enabled by libxpc.</strong></p>
482+
<p><strong>Decision-critical:</strong> The NextBSD/ravynOS launchd is closer to Apple parity but only runs on a Mach-coupled kernel. Now that our <code>mach.ko</code> exists, we have two ways to swap forward to the Apple-shape launchd:</p>
483+
<ul>
484+
<li><strong>Fork ravynOS's launchd source</strong> &mdash; faster, inherits ravynOS's FreeBSD-15 patches, but inherits NextBSD's squashed-history mess and 36 dormant <code>#if 0</code>/FIXME bisect markers.</li>
485+
<li><strong>Clean import from Apple <code>launchd-842.92.1</code></strong> &mdash; same source code as the ravynOS path (everyone descends from this), but with clean provenance, our own patch series, and no inherited cruft. Same model as our configd / libdispatch / libxpc imports. <strong>Chosen approach</strong> &mdash; see Phase 5 below.</li>
486+
</ul>
487+
<p>Either way, the swap is enabled by libxpc and jumps us from 1,500 LoC of hand-coded subset to 16k+ LoC of battle-tested Apple-shape code.</p>
483488

484489
<h3>configd / SystemConfiguration</h3>
485490

@@ -695,7 +700,7 @@ <h3>Decision summary</h3>
695700
<tr><td>libdispatch</td><td><span class="pill pill-good">pure C + blocks</span></td><td>gershwin-developer install</td></tr>
696701
<tr><td>libnv (bundled with libxpc)</td><td><span class="pill pill-good">pure C</span></td><td>BSD libnv, bundled in libxpc tree</td></tr>
697702
<tr><td>liblaunch</td><td><span class="pill pill-good">pure C</span></td><td>freebsd-launchd's existing version</td></tr>
698-
<tr><td>launchd daemon</td><td><span class="pill pill-good">pure C</span></td><td>freebsd-launchd or ravynOS launchd swap (both C)</td></tr>
703+
<tr><td>launchd daemon</td><td><span class="pill pill-good">pure C</span></td><td>freebsd-launchd (current minimal); Phase 5 swaps to clean Apple <code>launchd-842.92.1</code> import</td></tr>
699704
<tr><td>configd daemon</td><td><span class="pill pill-warn">C + CoreFoundation</span></td><td>Apple verbatim &mdash; CF supplied by hybrid <strong>libs-corebase</strong> (value types) + <strong>CF-Lite</strong> (CFMachPort, CFRunLoop v1, CFBundle, CFPreferences); see &sect;9.5</td></tr>
700705
<tr><td>configd's small ObjC shim</td><td><span class="pill pill-good">GNUstep libobjc2</span></td><td><code>NCDaemon.m</code> already uses GNUstep runtime</td></tr>
701706
<tr><td>SystemConfiguration framework</td><td><span class="pill pill-warn">C + CoreFoundation</span></td><td>Apple verbatim &mdash; same CF dependency as configd</td></tr>
@@ -813,7 +818,7 @@ <h3>libs-corebase coverage of configd's CF needs</h3>
813818
<p><span class="verdict verdict-warn">Significant gaps &mdash; hybrid with Apple CF-Lite required.</span> Per the audit in &sect;9.5: corebase has CFMachPort absent, CFRunLoop version1 sources unimplemented (TODO stub), CFPreferences absent. Roughly 3,000-5,000 lines of new/imported code needed &mdash; pulled from Apple's open-source CF-Lite (plain C, not ObjC). This is its own sub-project, sequenced before Phase 6 (configd functional).</p>
814819

815820
<h3>Bootstrap server complexity</h3>
816-
<p><span class="verdict verdict-warn">Real work.</span> <code>bootstrap_check_in</code> / <code>bootstrap_look_up</code> need a userspace name service. NextBSD/ravynOS have a working bootstrap server inside their launchd, but they're disabled in our cut-down <code>freebsd-launchd</code>. Bringing the bootstrap server up means partially or fully swapping <code>freebsd-launchd</code> for the NextBSD/ravynOS launchd source built against our libmach. This is the most significant scope change implied by libxpc.</p>
821+
<p><span class="verdict verdict-warn">Real work.</span> <code>bootstrap_check_in</code> / <code>bootstrap_look_up</code> need a userspace name service. Apple's launchd <em>is</em> the bootstrap server &mdash; the bootstrap subsystem is internal to the launchd daemon. Our current <code>freebsd-launchd</code> minimal rewrite doesn't have it; the clean Apple <code>launchd-842.92.1</code> import in Phase 5 will. Either we stand up a small standalone bootstrap server in Phase 3 (smaller, faster, gets libxpc tested), or we wait for Phase 5's full Apple launchd to bring the bootstrap server along with it. The plan recommends both: Phase 3 minimal standalone for testing, Phase 5 swap to Apple's full launchd for production.</p>
817822

818823
<h3>"Should we just use D-Bus or AF_UNIX everywhere?"</h3>
819824
<p><span class="verdict verdict-no">Already decided: no.</span> The whole project's premise is that Apple's system-service plumbing &mdash; including XPC's connection-based-async-with-typed-dictionaries shape &mdash; is what we want to modernize FreeBSD <em>toward</em>. Substituting another IPC mechanism breaks source compatibility with every daemon we want to inherit. The cost of libxpc is the price of admission.</p>
@@ -999,10 +1004,10 @@ <h3>Phase 3 &mdash; bootstrap server (2-3 weeks)</h3>
9991004
<p>The hard part. Options, in order of effort:</p>
10001005
<ol>
10011006
<li><strong>Option A: minimal standalone bootstrap server.</strong> Write a tiny daemon that owns the bootstrap port, accepts <code>bootstrap_register</code> / <code>bootstrap_look_up</code> over Mach, stores port-name mappings in memory. ~500-1000 lines. Reuses NextBSD's MIG <code>.defs</code> for the bootstrap protocol.</li>
1002-
<li><strong>Option B: port NextBSD/ravynOS launchd's bootstrap subsystem</strong> piecemeal &mdash; just <code>job_mig_dispatch</code> + the bootstrap port handling, not the rest of launchd. Maybe 2000-3000 lines. Closer to Apple-shape but heavier.</li>
1003-
<li><strong>Option C: full launchd swap.</strong> Replace <code>freebsd-launchd</code>'s daemon entirely with NextBSD/ravynOS launchd source built against our libmach + libxpc. Highest payoff (16k LoC of working Apple-shape code), highest risk (most surface to debug). Defer to Phase 5.</li>
1007+
<li><strong>Option B: extract just the bootstrap subsystem from Apple's launchd</strong> &mdash; pull <code>job_mig_dispatch</code> + bootstrap port handling out of <code>launchd-842.92.1</code> source, ship it as a standalone daemon. Maybe 2000-3000 lines. Closer to Apple-shape but heavier.</li>
1008+
<li><strong>Option C: full clean Apple launchd import.</strong> Phase 5's plan: import <code>launchd-842.92.1</code> verbatim from <code>apple-oss-distributions/launchd</code>, build against our libmach + libxpc + libdispatch with a patch series for FreeBSD adaptations. Highest payoff (16k+ LoC of upstream-clean Apple code), highest risk (most surface to debug). This becomes the production launchd.</li>
10041009
</ol>
1005-
<p>Recommended Phase 3 scope: <strong>Option A</strong>. Smallest critical path to "libxpc connections actually work end-to-end." Defer the larger launchd swap to Phase 5 once libxpc is proven.</p>
1010+
<p>Recommended Phase 3 scope: <strong>Option A</strong>. Smallest critical path to "libxpc connections actually work end-to-end." The full Apple-launchd import comes in Phase 5 once libxpc is proven.</p>
10061011

10071012
<h3>Phase 4 &mdash; xpc_connection end-to-end test (1 week)</h3>
10081013
<ol>
@@ -1012,15 +1017,71 @@ <h3>Phase 4 &mdash; xpc_connection end-to-end test (1 week)</h3>
10121017
<li>This is the libxpc equivalent of C3's "userland mach_msg works end-to-end" milestone.</li>
10131018
</ol>
10141019

1015-
<h3>Phase 5 &mdash; launchd swap (3-6 weeks)</h3>
1020+
<h3>Phase 5 &mdash; Apple launchd-842.92.1 clean import (4-8 weeks)</h3>
1021+
1022+
<p>Replace <code>freebsd-launchd</code>'s 1,496-LoC minimal rewrite with a clean verbatim import of Apple's last open-source launchd, building against our libmach + libxpc + libdispatch stack and keeping all Mach paths intact (no stripping, unlike <code>freebsd-launchd</code>'s original approach).</p>
1023+
1024+
<p><strong>Why this over a ravynOS fork:</strong> same source code either way (ravynOS's launchd descends from NextBSD which descends from Apple <code>launchd-842.x</code>), but a clean import gives us:</p>
1025+
<ul>
1026+
<li>Clean provenance &mdash; every commit is either "Apple verbatim" or "our patch"</li>
1027+
<li>License clarity &mdash; Apple's APSL preserved on imported files; patches unambiguously ours</li>
1028+
<li>Same model as our configd / libdispatch / libxpc imports &mdash; project-wide consistency</li>
1029+
<li>No inheritance of NextBSD's 36 dormant <code>#if 0</code>/FIXME bisect markers</li>
1030+
<li>Easy re-imports if Apple ever publishes a newer launchd (unlikely but possible)</li>
1031+
</ul>
1032+
1033+
<p><strong>Layout (mirrors configd's import pattern):</strong></p>
1034+
1035+
<pre><code>freebsd-launchd-mach/
1036+
├── src/sbin/launchd/
1037+
│ ├── (Apple verbatim from launchd-842.92.1)
1038+
│ ├── core.c (~12k lines)
1039+
│ ├── runtime.c, launchd.c, ipc.c, log.c
1040+
│ ├── *.defs (MIG protocol_jobmgr, job, job_reply, ...)
1041+
│ └── ...
1042+
├── scripts/import-launchd.sh (refresh-from-upstream tool)
1043+
└── patches/launchd/
1044+
├── 0001-freebsd-15-availability-header.patch (~20 lines)
1045+
├── 0002-build-flags-pic-no-werror.patch (~10 lines)
1046+
├── 0003-audit-session-self-workaround.patch (~30 lines)
1047+
├── 0004-link-against-libmach-libxpc-libdispatch.patch
1048+
├── 0005-freebsd-mach-compat-shim.patch (the bulk)
1049+
├── 0006-mig-defs-for-freebsd-makefile.patch
1050+
└── 0007-per-user-env-file.patch (~45 lines; useful ravynOS feature)</code></pre>
1051+
1052+
<p><strong>Estimated patch size:</strong> ~700-1500 lines sitting on top of Apple's ~16,500 lines of clean source. Comparable to gershwin's libdispatch patch in approach, larger in absolute size.</p>
1053+
1054+
<p><strong>What the patches must do:</strong></p>
10161055
<ol>
1017-
<li>Build ravynOS's launchd source against our libmach + libxpc + bootstrap server.</li>
1018-
<li>Migrate the FreeBSD-15 fixes (per-user env file, audit-session workaround, build flags) from ravynOS's tree.</li>
1019-
<li>Audit-mark the 36 <code>#if 0</code> / FIXME sites for which need re-enabling on FreeBSD.</li>
1020-
<li>CI gate: ravynOS-launchd boots a livecd to multiuser, can start/stop a daemon, processes the existing FreeBSD launch.plists.</li>
1021-
<li>Cut over the ISO build from <code>freebsd-launchd</code> to <code>freebsd-launchd-mach</code> launchd. Keep <code>freebsd-launchd</code>'s minimal daemon around as a fallback for non-Mach-aware deployments.</li>
1056+
<li><strong>FreeBSD <code>bsd.prog.mk</code> Makefile</strong> replacing Apple's xcconfig. ~50-100 lines.</li>
1057+
<li><strong>MIG <code>.defs</code> compilation</strong> &mdash; Apple's <code>protocol_jobmgr.defs</code>, <code>job.defs</code>, etc. via a FreeBSD-host <code>mig</code> tool producing our shape of stubs. ~100-200 lines of build orchestration.</li>
1058+
<li><strong>Mach API compat shims</strong> &mdash; Apple's launchd assumes the full XNU Mach ABI (<code>bootstrap_*</code>, <code>mach_port_construct</code>, <code>MACH_NOTIFY_DEAD_NAME</code>, voucher APIs). Our libmach exposes a subset (Phase 1 expansion + Phase 3 bootstrap server). Either widen libmach to cover what launchd needs, or write thin compat shims that route to what we have. ~500-1000 lines.</li>
1059+
<li><strong><code>&lt;Availability.h&gt;</code> shim</strong> &mdash; Apple's headers reference <code>__OSX_AVAILABLE_STARTING(...)</code>; trivial macro stubs. ~20 lines.</li>
1060+
<li><strong>Audit-session workarounds</strong> &mdash; same <code>_audit_session_self()</code> issues ravynOS hit on FreeBSD 15. ~30 lines.</li>
1061+
<li><strong>Per-user env file</strong> &mdash; <code>_read_env_file()</code> that ravynOS added; useful for FreeBSD-style <code>/etc/launchd_user.env</code>. ~45 lines.</li>
10221062
</ol>
10231063

1064+
<p><strong>Dependencies on prior phases:</strong></p>
1065+
<ul>
1066+
<li>Phase 0 (libdispatch Mach backend) &mdash; required, launchd uses dispatch heavily</li>
1067+
<li>Phase 1 (mach.ko port-management syscalls) &mdash; required, launchd allocates ports</li>
1068+
<li>Phase 2-4 (libxpc) &mdash; required, modern launchd routes job management through libxpc</li>
1069+
<li>Phase 3 (bootstrap server) &mdash; or absorbed into this phase; Apple's launchd is itself the bootstrap server</li>
1070+
</ul>
1071+
1072+
<p><strong>Reference NOT fork:</strong> NextBSD's <code>sbin/launchd/</code> and ravynOS's <code>sbin/launchd/</code> are useful prior art &mdash; their FreeBSD shims have already solved many of the same problems we'll hit. We can read their patches as guidance, but our patches stay clean-room (commit messages describe the underlying problem, not "ported from NextBSD"). Keep the lineage cleanly "Apple upstream + our patches."</p>
1073+
1074+
<p><strong>Test gate (matches Phase B Tier 1's smoke-driven completion criterion):</strong></p>
1075+
<ol>
1076+
<li>launchd boots as PID 1 on a livecd</li>
1077+
<li>Processes <code>org.freebsd.*</code> launch.plists from <code>/System/Library/LaunchDaemons/</code></li>
1078+
<li>Can start/stop a daemon via <code>launchctl load</code> / <code>launchctl unload</code></li>
1079+
<li>Bootstrap port-name registration / lookup works (proves the libxpc + bootstrap server integration)</li>
1080+
<li>System reaches multiuser without panic across at least 100 boot cycles</li>
1081+
</ol>
1082+
1083+
<p><strong>Cutover:</strong> ISO build switches from <code>freebsd-launchd</code> to <code>freebsd-launchd-mach</code> launchd. Keep <code>freebsd-launchd</code>'s minimal daemon around as a fallback for non-Mach-aware deployments (e.g. a stripped-down FreeBSD build that doesn't load mach.ko).</p>
1084+
10241085
<h3>Phase 5.5 &mdash; CoreFoundation hybrid (libCoreFoundation-freebsd) (3-6 weeks)</h3>
10251086

10261087
<p>Prerequisite for Phase 6. Per the audit in &sect;9.5, GNUstep libs-corebase has critical gaps that block configd. Build a hybrid CF library that ships with <code>freebsd-launchd</code>:</p>

0 commit comments

Comments
 (0)