Port Apple's ASL (Apple System Log) + libnotify+notifyd as a single cohesive block, replacing the removed FreeBSD-syslogd and unblocking the downstream Apple-service daemon ports (configd, IPConfiguration, PowerManagement, DiskArbitration, IOKitUser). Status: draft; synthesized from five parallel research agents on 2026-05-16. Supersedes the earlier v0 plan (which assumed AF_UNIX / GNUstep Distributed Objects substrate — wrong now that Mach IPC + libxpc + libdispatch + libCoreFoundation are all working).
notify_* call sites across 6 downstream daemons (ASL=52, IOKitUser=56, configd=60, IPConfiguration=7, PowerManagement=154, DiskArbitration=6); stubbing scales badly because configd/pmconfigd are event-driven and would run permanently broken with stubs.syslog(3) interop is achievable with three small patches to Apple syslogd: add a bsd_in.c input module that listens on /var/run/log, add an RFC 5424 branch to asl_syslog_input_convert() (FreeBSD libc emits RFC 5424; Apple syslogd parses RFC 3164), and add a launchd Sockets entry. Zero changes to FreeBSD's getty / login.printf(9) / log(9) → kernel msgbuf → /dev/klog → Apple syslogd's klog_in.c module (works on FreeBSD unmodified) → ASL store. Same path covers FreeBSD core + mach.ko + every other kld.os/log.h + os/log_private.h + os/assumes.h + os/activity.h + os/transaction_private.h header pack (~700 lines, required to compile both ASL and IOKitUser later); membership.h stub (~20 lines, ASL only); configuration_profile.h stub (~10 lines, ASL only).libbsm as-is — FreeBSD base ships <bsm/libbsm.h> with identical audit_token_to_au32/audit_token_to_pid signatures (contrib/openbsm/bsm/libbsm.h:1257-1294).syslog(3) interop strategylog.c interactionThe runtime ISO currently ships no syslog daemon at all. FreeBSD-syslogd was removed at commit 88694f0 (2026-05-16) alongside FreeBSD-rc, FreeBSD-devd, and several other base packages we no longer need under PID-1 launchd. Apps that call syslog(3) via libc (getty, login, and a small handful of FreeBSD-base utilities) write to /var/run/log — which doesn't exist — and the messages silently drop. Kernel printfs accumulate in the kernel msgbuf and never make it to any persistent log.
This is fine for boot-to-login validation (no boot-critical decision depends on logs), but blocks essentially every next step. hwregd needs to log events for operational visibility. configd, IPConfiguration, mDNSResponder, PowerManagement — every Apple-source service daemon — calls asl_log() natively in its source. We can either:
syslog(3) consumers but leaves the Apple-source daemons either calling no-op stubs or shelling out — a permanent two-track logging architecture.Option 2 is the wrong end state; Apple's daemons assume ASL and we'd be undoing this later anyway. Option 1 — port ASL once, correctly — is the path the project's scope_split memory already commits to ("Apple source only for system services: Mach/launchd/configd/notifyd/asl/libdispatch/libxpc/liblaunch"). ASL is in scope.
| Component | Source location | Phase | Notes |
|---|---|---|---|
libsystem_asl (client lib) | syslog/libsystem_asl.tproj/ | J1 | ~14.6k LoC. Public asl.h, internal subprojects. Every Apple daemon links this. |
aslcommon (static lib shared by daemon + client) | syslog/aslcommon/ | J1 | ~4.5k LoC. asl_ipc.defs MIG (subsystem 114), asl_memory.c, asl_common.c. |
syslogd daemon | syslog/syslogd.tproj/ | J2-J3 | ~8.4k LoC. Mach RX loop + input/output modules + ASL store driver. |
New: bsd_in.c module | NEW under syslogd.tproj/ | J3 | ~150 LoC. Listens on /var/run/log (AF_UNIX SOCK_DGRAM) so FreeBSD libc syslog(3) consumers reach ASL transparently. |
RFC 5424 branch in asl_syslog_input_convert() | syslogd.tproj/daemon.c:1057 | J3 | ~50 LoC. FreeBSD libc emits RFC 5424 (<pri>1 timestamp ...); Apple parses only RFC 3164. |
libnotify client lib | Libnotify/ (top-level + headers) | J1 | ~7.7k LoC. notify_register_*, notify_post, notify_check, etc. |
notifyd daemon | Libnotify/notifyd/ | J2 | ~5.1k LoC. Mach-backed pub/sub server. Required because configd/pmconfigd hard-depend on real notify behavior. |
os/* header stubs | NEW under freebsd-shims/ | J1 | ~700 lines. os_log/os_assumes/os_activity/os_transaction_private macro to printf/syslog/no-op. Required to compile. |
membership.h stub | NEW under freebsd-shims/ | J1 | ~20 lines. mbr_uid_to_uuid → KERN_FAILURE. ASL store ACL groups degrade to uid/gid. |
configuration_profile.h stub | NEW under freebsd-shims/ | J1 | ~10 lines. MDM profile overrides — irrelevant on FreeBSD; returns NULL. |
aslmanager log-rotation daemon | syslog/aslmanager.tproj/ | J4 | ~2k LoC. Without it /var/log/asl/ grows unbounded (syslogd self-rotates current files but never archives or deletes). Real disk-fillup consequence — not optional for a shipping system. |
syslog(1) CLI | syslog/util.tproj/ | J5 | ~2.9k LoC. Required for structured queries against the binary /var/log/asl/*.asl database (operators have no shell-side ASL read access without it). Send-side covered by FreeBSD's existing logger(1) + our bsd_in.c, but read-side is syslog(1)-only. |
newsyslog | syslog/newsyslog/ | SKIP | FreeBSD base already has working newsyslog; no need to port Apple's variant. |
Vendored locally at /Users/jmaloney/Documents/launchd/syslog/. License: APSL 2.0. ~32k LoC total C.
Six Xcode targets in syslog.xcodeproj/project.pbxproj:
aslcommon (static lib) libaslcommon.a
└ asl_ipc.defs (MIG subsystem 114), asl_memory.c, asl_common.c
libsystem_asl (shared lib) libsystem_asl.dylib
└ asl.c (2064), asl_msg.c (3295), asl_file.c (2653),
asl_core.c (1164), asl_store.c (1155), asl_legacy1.c (807),
asl_string.c (747), asl_client.c (614), asl_msg_list.c (587),
asl_object.c (426), asl_util.c (342), asl_fd.c (328),
syslog.c (288 — BSD syslog(3) shim that wraps to ASL),
asl_mt_shim.c (100)
syslogd (tool) /usr/sbin/syslogd
└ syslogd.c (712), daemon.c (1426), dbserver.c (1648),
asl_action.c (2457), bsd_out.c (811), klog_in.c (141),
udp_in.c (222), remote.c (935)
links: libaslcommon.a, libbsm.dylib
aslmanager (tool) /usr/libexec/aslmanager
util (tool) /usr/bin/syslog
newsyslog (tool) skip — FreeBSD base has its own
Dependency DAG: aslcommon → libsystem_asl → {syslogd, aslmanager, util}. newsyslog is standalone. No Security.framework, IOKit, CoreFoundation, or libsystem_info usage anywhere (verified grep).
syslogd.c:224-229)| Module | Source | Wire | Status on FreeBSD |
|---|---|---|---|
m_asl | Mach IPC via com.apple.system.logger (launchd MachServices port) | MIG _asl_server_message | Works as-is once liblaunch returns the Mach port |
m_klog_in | klog_in.c reads /dev/klog via dispatch READ source | Plain open(O_RDONLY|O_NONBLOCK) | Works on FreeBSD unmodified — /dev/klog exists, same single-reader semantic |
m_udp_in | udp_in.c, network RFC 3164 from UDP 514 | SOCK_DGRAM from launchd Sockets | Disabled by default; enable per-plist if remote syslog needed |
m_remote | remote.c, AF_UNIX SOCK_STREAM control socket | For syslog -w watchers | iOS-targeted; skippable for v1 |
| m_bsd_in (NEW) | NEW bsd_in.c modeled on klog_in.c | AF_UNIX SOCK_DGRAM on /var/run/log | Required for FreeBSD getty/login interop |
asl_action.c) — writes ASL binary database to /var/log/asl/*.asl via asl_store.c / asl_file.c. Self-rotates current files.bsd_out.c) — reads /etc/syslog.conf (native BSD format), writes to /var/log/system.log, /var/log/messages, etc. via the standard facility.priority routing.The agent audit found 347 notify_* call sites across 6 downstream Apple daemons:
| Daemon | notify_* calls | Files | Behavior if stubbed |
|---|---|---|---|
| ASL (syslogd + libsystem_asl + aslmanager + util) | 52 | 9 | Loses syslog -w, syslog -c, asl.conf =notify. Logging itself fine. |
| IOKitUser (pwr_mgt + ps subprojects) | 56 | 11 | IOPMAssertion / IOPS notifications broken. |
| configd | 60 | 14 | Permanently broken. Event-driven; network-change/host-name-change/ip-plugin-recompute all hang on notify wakeups. |
| IPConfiguration | 7 | 1 | Lease renewal + interface state-change dropped. |
| PowerManagement (pmconfigd) | 154 | 17 | Permanently broken. Sleep/wake/lid/battery-thresh all hang. |
| DiskArbitration | 6 | 2 | Disk arrival/eject callbacks broken. |
| Total | 335 | 54 |
For ASL alone, stubbing is plausible (~80 lines across 9 files). But the moment configd or pmconfigd enters scope — and both are in our commit-to-port list — the stub story collapses. libnotify itself has only 3 unported deps, all already on our roadmap. Cost: ~12.8k LoC, ~1.5-2 weeks port effort. Versus stubbing across 6 daemons: ~480 lines of degraded-mode shim, configd + pmconfigd unusable. The leverage ratio (one ~12.8k-LoC port unblocks 5 daemon ports cleanly) makes libnotify the highest-priority cross-cutting dep.
syslog(3) interop strategyToday's broken chain:
FreeBSD getty/login
→ libc syslog(3) (lib/libc/gen/syslog.c)
→ connect("/var/run/log", AF_UNIX, SOCK_DGRAM)
→ ECONNREFUSED (no listener) → silent drop
Target chain:
FreeBSD getty/login
→ libc syslog(3)
→ sendto("/var/run/log", AF_UNIX, SOCK_DGRAM, RFC-5424-msg)
→ Apple syslogd's NEW bsd_in.c module
→ asl_input_parse() with patched RFC 5424 branch
→ ASL store + /etc/syslog.conf routing to /var/log/messages
Three concrete patches required (all in syslogd.tproj/):
bsd_in.c modeled on klog_in.c. Get the listening fd from launchd via LAUNCH_JOBKEY_SOCKETS. Per-dgram recv() → asl_input_parse(buf, len, NULL, SOURCE_BSD_SOCKET). Register m_bsd_in in syslogd.c:215-229.asl_syslog_input_convert() (daemon.c:1057). FreeBSD libc emits <pri>1 YYYY-MM-DDTHH:MM:SS ...; Apple's existing parser hard-checks for the RFC 3164 timestamp Mmm dd HH:MM:SS. Add a branch: if next bytes after <pri> are 1 , parse RFC 5424.Sockets entry in the syslogd plist:
<key>Sockets</key>
<dict>
<key>BSDSystemLogger</key>
<dict>
<key>SockPathName</key><string>/var/run/log</string>
<key>SockType</key><string>dgram</string>
<key>SockPathMode</key><integer>0666</integer>
</dict>
</dict>
Kernel log ingest works as-is: klog_in.c opens /dev/klog via plain open(O_RDONLY|O_NONBLOCK), FreeBSD's /dev/klog from sys/kern/subr_log.c has the same single-reader semantic. No patches needed. /etc/syslog.conf compat is already in Apple syslogd via bsd_out_init() at bsd_out.c:732 — also no patches.
Short answer: partially, and not worth chasing. Below is the explicit matrix.
Two paths a userland program can reach ASL:
libsystem_asl.so, calls asl_log() directly OR calls syslog(3) which is intercepted by the libsystem_asl shim (libsystem_asl.tproj/src/syslog.c, 288 lines) and routed to syslogd over Mach IPC. No bsd_in.c involved.syslog(3) which writes RFC 5424 to /var/run/log AF_UNIX SOCK_DGRAM. bsd_in.c required to listen on that socket and route into ASL.So bsd_in.c is the catch-all for path 2. Porting an Apple utility moves that one binary to path 1, but bsd_in.c stays mandatory for every other FreeBSD-base utility still on path 2.
| FreeBSD-base utility | In our rootfs? | Apple equivalent | Apple version uses asl directly? | Porting drops bsd_in.c for this consumer? | Worth porting? |
|---|---|---|---|---|---|
/usr/libexec/getty |
Yes (FreeBSD-runtime) | system_cmds/getty.tproj/ |
Yes (via libsystem_asl syslog shim + native asl calls) | Yes (for getty) | No — Apple version has Darwin audit hooks + asl-direct integration we'd strip; result functionally equivalent to FreeBSD's. bsd_in.c covers transparently. |
/usr/bin/login |
Yes (FreeBSD-runtime) | system_cmds/login.tproj/ |
Yes (asl + audit session) | Yes (for login) | No — Same logic as getty. Apple's adds OpenDirectory hooks we don't have; strip-and-port gives near-identical behavior. |
/usr/bin/su |
Yes (FreeBSD-runtime) | system_cmds/su.tproj/ |
Yes (asl + audit) | Yes (for su) | No — Same reasoning. |
/usr/bin/passwd |
Yes (FreeBSD-runtime) | system_cmds/passwd.tproj/ |
Yes | Yes (for passwd) | No — Same reasoning. |
/usr/sbin/cron |
Optional (not in minimal rootfs) | cron (Apple ships BSD cron with patches) |
Partial — calls syslog(3), not asl directly | No real win — even Apple cron uses syslog(3) | No — Both versions go through bsd_in.c anyway. |
/usr/libexec/atrun |
Optional | Same as cron — BSD inheritance | No | No | No |
/usr/sbin/sshd |
No (FreeBSD-ssh removed at 88694f0) | Apple openssh-portable fork (heavily patched) | Yes (asl + audit) | Yes (for sshd when it returns) | Maybe later — when sshd comes back, the Apple version brings session-context logging worth having. Independent of this plan. |
/sbin/dhclient |
No (removed at 88694f0; will be replaced by IPConfiguration) | N/A — IPConfiguration is the Apple equivalent | Yes (asl direct) | Yes (IPConfiguration won't use syslog(3)) | Yes — separate plan |
/usr/sbin/newsyslog |
Yes (FreeBSD-runtime) | syslog/newsyslog/ (Apple variant) |
No (BSD-style) | No | No — FreeBSD's works; Apple's variant in our vendored syslog repo is intentionally skipped per the J0 plan. |
/usr/sbin/syslogd |
No (removed at 88694f0) | This plan | N/A — IS the daemon | N/A | Yes — this plan |
/usr/sbin/powerd |
Not in our build path | PowerManagement/pmconfigd/ |
Yes (asl + notify) | Yes (when pmconfigd lands) | Eventually — covered by IOKit/PowerManagement plan downstream. |
/usr/sbin/ntpd |
Not in our build path | Apple ntp fork (deprecated on macOS in favor of timed) | Some — calls asl in patches | Partial | No — Apple themselves abandoned ntpd; if time sync becomes a need, port Apple's timed or ship freebsd-base ntpd through bsd_in.c. |
| Future ports-tree apps using syslog(3) | Whatever the user installs | N/A — third-party | No | No (can't patch user-installed pkgs) | bsd_in.c is the only answer |
Even if we ported every Apple system_cmds utility that has a syslog-using counterpart (getty / login / su / passwd / atrun), bsd_in.c would still be required for:
syslog(3) universallyAnd per the earlier audit (apple-userland-cmds plan and the IOKit-plan synthesis), Apple's userland utilities that talk to the kernel (getty/login/ifconfig/route/netstat/ping/ps/top/mount/etc.) aren't worth porting: their value over FreeBSD's is near-zero after stripping Darwin-specific kernel-ABI ties (audit sessions, asl-direct integration, OpenDirectory hooks), all of which we don't have anyway. bsd_in.c is the leverage move: ~200 LoC covers every present and future FreeBSD syslog(3) consumer transparently.
The only Apple utilities worth porting from a logging-perspective alone are those that talk to Apple services (launchctl, scutil, networksetup, defaults, log, syslog(1) itself) — they have no FreeBSD equivalent and their value compounds beyond just logging.
| Artifact | Path |
|---|---|
libsystem_asl.so | /usr/lib/system/libsystem_asl.so + sonname symlink |
libnotify.so (client lib) | /usr/lib/system/libnotify.so + sonname symlink |
Public headers (asl.h, notify.h, notify_keys.h) | /usr/include/ |
Private headers (asl_private.h, etc.) | /usr/include/asl/ |
syslogd binary | /usr/sbin/syslogd |
notifyd binary | /usr/sbin/notifyd |
aslmanager binary (J5) | /usr/libexec/aslmanager |
syslog(1) CLI (J5) | /usr/bin/syslog |
| launchd plists | /System/Library/LaunchDaemons/com.apple.syslogd.plist, com.apple.notifyd.plist |
Default asl.conf | /etc/asl.conf + drop-in dir /etc/asl/ |
| ASL DB | /var/log/asl/*.asl |
| BSD text log | /var/log/system.log, /var/log/messages, etc. |
os/* header pack (~700 lines) under src/freebsd-shims/os/. os/log.h, os/log_private.h, os/assumes.h, os/activity.h, os/transaction_private.h. Macro-expand os_log() family to fprintf(stderr, ...) initially; re-expand to asl_log() once ASL is up. Required to compile both ASL and IOKitUser (708 os_log* call sites tree-wide).membership.h stub (~20 lines). mbr_uid_to_uuid() returns KERN_FAILURE. ASL store ACL groups degrade to plain uid/gid checks.configuration_profile.h stub (~10 lines). configuration_profile_copy_property_list() returns NULL. MDM-profile overrides irrelevant on FreeBSD.libbsm — base ships identical signatures via contrib/openbsm/bsm/libbsm.h:1257-1294. Skip the Apple version.syslogd.sb) — skip; no Apple sandbox on FreeBSD.This section is for application developers writing new code (or porting existing code) that wants to log via ASL after this plan ships.
Header: <asl.h> (lives at /usr/include/asl.h after J1).
Link: -lsystem_asl (the soname is libsystem_asl.so.1 under /usr/lib/system/; rpath baked at link time per install_layout_policies).
#include <asl.h>
int main(void)
{
asl_log(NULL, NULL, ASL_LEVEL_NOTICE,
"hello from %s pid=%d", "myapp", (int)getpid());
return 0;
}
Build: cc -o myapp myapp.c -L/usr/lib/system -lsystem_asl (the rpath baked at install layout makes runtime resolution automatic). No asl_open needed — the implicit default client is created on first asl_log.
#include <asl.h>
static asl_object_t client;
int main(void)
{
/* facility = "com.example.myapp", options = 0 */
client = asl_open("myapp", "com.example.myapp", 0);
asl_log(client, NULL, ASL_LEVEL_NOTICE, "starting up");
/* ... */
asl_close(client);
return 0;
}
#include <asl.h>
asl_object_t msg = asl_new(ASL_TYPE_MSG);
asl_set(msg, ASL_KEY_MSG, "request completed");
asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
asl_set(msg, "Request-ID", request_id);
asl_set(msg, "Latency-ms", latency_str);
asl_send(client, msg);
asl_release(msg);
Querying / filtering / live-tail are covered in asl.h proper (asl_search, asl_next, asl_match); not needed for most daemons.
syslog(3) still worksExisting code that calls openlog() / syslog() / closelog() needs zero changes. There are two paths and both reach ASL:
libsystem_asl.so: the shim in libsystem_asl.tproj/src/syslog.c (288 lines) overrides libc's syslog(3) and routes directly to ASL via Mach IPC.syslog(3) writes RFC 5424 to /var/run/log AF_UNIX SOCK_DGRAM → Apple syslogd's new bsd_in.c module → ASL.Either path lands in /var/log/asl/*.asl (binary ASL store) and /var/log/messages (per /etc/syslog.conf).
ASL is a pure C API. Objective-C consumers call it identically — no Foundation wrapper required:
#import <Foundation/Foundation.h>
#import <asl.h>
@interface MyLogger : NSObject
@property (assign) asl_object_t client;
@end
@implementation MyLogger
- (instancetype)init {
if ((self = [super init])) {
_client = asl_open([@"MyApp" UTF8String],
[@"com.example.myapp" UTF8String], 0);
}
return self;
}
- (void)logRequest:(NSString *)requestID latency:(NSTimeInterval)ms {
asl_object_t msg = asl_new(ASL_TYPE_MSG);
asl_set(msg, ASL_KEY_MSG, "request completed");
asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
asl_set(msg, "Request-ID", [requestID UTF8String]);
asl_set(msg, "Latency-ms",
[[NSString stringWithFormat:@"%.0f", ms] UTF8String]);
asl_send(_client, msg);
asl_release(msg);
}
- (void)dealloc {
asl_close(_client);
}
@end
Build with the standard GNUstep / libobjc2 chain: cc -fobjc-runtime=gnustep-2.0 myapp.m -lsystem_asl -lobjc -lgnustep-base -o myapp. The libobjc2 runtime is unchanged by ASL — there is no ObjC bridge layer; logging is a flat C call from any method.
NSLog() behaviorGNUstep's NSLog() writes to stderr by default. To have NSLog() output also land in ASL, install an NSLog handler that wraps asl_log:
static void asl_nslog_handler(NSString *fmt, va_list args) {
NSString *s = [[NSString alloc] initWithFormat:fmt arguments:args];
asl_log(NULL, NULL, ASL_LEVEL_NOTICE, "%s", [s UTF8String]);
}
/* In main, before any NSLog: */
_NSSetLogCStringFunction(asl_nslog_handler); /* GNUstep extension */
Alternative for new ObjC code: skip NSLog() entirely; call asl_log() directly — same as the C example above.
os_log()?Apple's newer os_log() family (introduced on macOS 10.12 / iOS 10) is part of the closed-source libsystem_trace + kernel firehose. We're not porting that. Our os/log.h stub (Phase J1) provides macro definitions that expand to asl_log(), so any Apple source code that calls os_log() compiles and routes to ASL transparently — but new application code should call asl_log() directly for clarity. os_log() is preserved for source-compat with the Apple daemons we vendor; it's not the recommended consumer API for new C/ObjC code on this stack.
| ASL constant | syslog(3) equiv | Numeric | Meaning |
|---|---|---|---|
ASL_LEVEL_EMERG | LOG_EMERG | 0 | System unusable |
ASL_LEVEL_ALERT | LOG_ALERT | 1 | Action required immediately |
ASL_LEVEL_CRIT | LOG_CRIT | 2 | Critical condition |
ASL_LEVEL_ERR | LOG_ERR | 3 | Error |
ASL_LEVEL_WARNING | LOG_WARNING | 4 | Warning |
ASL_LEVEL_NOTICE | LOG_NOTICE | 5 | Normal but significant (default for daemons) |
ASL_LEVEL_INFO | LOG_INFO | 6 | Informational |
ASL_LEVEL_DEBUG | LOG_DEBUG | 7 | Debug-level message |
From the shell (after J5 ships syslog(1)):
# All notice+ messages
syslog -k Level Nle 5
# Messages from a specific sender
syslog -k Sender myapp
# Live tail
syslog -w 0
# Standard BSD text log also works
tail -f /var/log/messages
Vendor syslog/ and Libnotify/ at src/syslog/ and src/Libnotify/ in the freebsd-launchd-mach repo. Initial commit of unmodified source as the diff baseline.
Build libsystem_asl.so + libnotify.so via bsd.lib.mk style Makefiles (mirroring libxpc/libdispatch). Wire MIG asl_ipc.defs and notify_ipc.defs via in-tree migcom. Install to /usr/lib/system/. Drop the os/* + membership.h + configuration_profile.h stubs. Suppress __API_DEPRECATED noise.
Smoke marker: ASL-LIB-OK — hello binary calls asl_log(NULL, NULL, 6, "hi"), links + runs.
Build syslogd with klog_in/udp_in/remote modules disabled at init_modules() — Mach-only ingest via database_server() loop. Build notifyd similarly: minimal Mach-port server registering com.apple.system.notification_center. Both run under PID-1 launchd via plists.
Smoke markers: ASL-RUN-OK, NOTIFYD-RUN-OK, ASL-STORE-OK (test asl_log → persisted to /var/log/asl/), NOTIFY-ROUNDTRIP-OK.
Implement the three FreeBSD-interop patches: new bsd_in.c input module, RFC 5424 branch in asl_syslog_input_convert(), BSD-socket Sockets entry in plist. Enable klog_in + bsd_out modules. Ship minimal /etc/syslog.conf.
Smoke markers: SYSLOG-RESTORED-OK, KLOG-OK.
Build aslmanager daemon (~2k LoC). Install at /usr/libexec/aslmanager. Wire launchd plist for periodic activation (Apple ships it as on-demand via XPC from syslogd; we can match). Without aslmanager /var/log/asl/ grows unbounded — real disk-fillup consequence, not optional.
Full-boot CI assertion: PID-1 launchd boots; getty + hwregd + syslogd + notifyd + aslmanager all up; login: prompt appears; tail /var/log/messages shows getty/login session creation. Update hwregd's xlog() to call asl_log() instead of fprintf(stderr, ...) — single ~5-line additive patch, no plist change needed.
Smoke markers: ASLMANAGER-OK, ASL-FROM-HWREGD-OK, BOOT-WITH-ASL-OK.
Final phase of the ASL port. ~2.9k LoC operator CLI. Required for structured queries against the binary /var/log/asl/*.asl database — without it operators have no shell-side ASL read access (only tail /var/log/messages via the BSD-text output route, which flattens structured fields). Also handles runtime daemon filter control (syslog -c <pid> <mask>) and live-tail with structured filtering (syslog -w 0 -k Sender hwregd).
Send-side from shell is already covered by FreeBSD's existing logger(1) + our bsd_in.c socket compat, so syslog(1)'s send mode is redundant but harmless.
Smoke marker: SYSLOG-CLI-OK — query roundtrip writes a message via libsystem_asl then reads it back via syslog -k Sender hwregd.
| Marker | Phase | What it asserts |
|---|---|---|
ASL-BUILD-OK | J1 | libsystem_asl.so + libnotify.so + syslogd + notifyd binaries built + installed |
ASL-LIB-OK | J1 | Hello binary links + runs against libsystem_asl + libnotify |
ASL-RUN-OK | J2 | syslogd starts under PID-1 launchd, registers Mach service |
NOTIFYD-RUN-OK | J2 | notifyd starts under PID-1 launchd, registers Mach service |
ASL-STORE-OK | J2 | Test client asl_log() → persists to /var/log/asl/ |
NOTIFY-ROUNDTRIP-OK | J2 | Client A posts; client B (registered watcher) receives via Mach |
SYSLOG-RESTORED-OK | J3 | FreeBSD-base syslog(3) caller lands in ASL + /var/log/messages |
KLOG-OK | J3 | Kernel printf appears in ASL |
ASL-FROM-HWREGD-OK | J4 | hwregd's asl_log() calls appear in /var/log/asl/ |
BOOT-WITH-ASL-OK | J4 | Full PID-1 boot to login with all daemons running |
SYSLOG-CLI-OK | J5 | syslog(1) query roundtrip: write via libsystem_asl, read back via syslog -k Sender hwregd |
log.c interactionlaunchd-842 has its own log subsystem in src/launchd/src/log.c using launchd_syslog(). On macOS the internal backend writes to ASL via asl_log_message(); in our port the backend currently writes to /dev/console.
Decision: keep the BSD path for now. Once ASL is up, optionally swap launchd's internal backend to call asl_log_message() — behind-the-scenes change in log.c, no callsite churn across launchd's 28k LoC. The BSD-only backend stays useful as a fallback during early boot before syslogd is reachable. Additive, not undoing.
bootstrap_look_up() returns a usable send-right immediately, even before the target daemon runs. First message queues in the kernel Mach port, triggers on-demand activation, drains when the daemon's mach_msg_server starts. Our launchd-842 port already implements this — it's how com.apple.bootstrap_server works (proved in phase_g2_complete).sys/fileport.h's fileport_makefd / fileport_makeport. Apple implements as kernel Mach traps (XNU), with the kernel tracking fileglob ↔ Mach-port associations and supporting atomic fd-passing inside Mach message bodies. Decision: same architecture on FreeBSD via new ops in our mach.ko trap multiplexer (slot 219). Implementation: fget(td, fd, ...) + fhold() for makeport, falloc_noinstall() + finstall() for makefd, store struct file * in the Mach port's kobject slot. ~200-300 LoC, same shape as the task_get/set_special_port ops we added in Phase G prereqs. Slotted as a J2 prereq; bumps J2 from ~1.5-2 wk to ~2.5-3 wk./var/log/asl/ grows unbounded — real disk-fillup consequence, not optional for a shipping system./Users/jmaloney/Documents/launchd/syslog/syslog.xcodeproj/project.pbxproj — Xcode targets, MIG defs/Users/jmaloney/Documents/launchd/syslog/aslcommon/asl_ipc.defs — MIG subsystem 114/Users/jmaloney/Documents/launchd/syslog/libsystem_asl.tproj/include/asl.h — public API/Users/jmaloney/Documents/launchd/syslog/libsystem_asl.tproj/src/asl.c — client core/Users/jmaloney/Documents/launchd/syslog/libsystem_asl.tproj/src/syslog.c — BSD syslog(3) shim/Users/jmaloney/Documents/launchd/syslog/syslogd.tproj/syslogd.c — daemon main/Users/jmaloney/Documents/launchd/syslog/syslogd.tproj/dbserver.c — Mach RX loop/Users/jmaloney/Documents/launchd/syslog/syslogd.tproj/daemon.c:1057,1121 — parser to patch/Users/jmaloney/Documents/launchd/syslog/syslogd.tproj/klog_in.c — /dev/klog reader/Users/jmaloney/Documents/launchd/syslog/syslogd.tproj/bsd_out.c — /etc/syslog.conf parser/Users/jmaloney/Documents/launchd/syslog/syslogd.tproj/asl_action.c — output module/Users/jmaloney/Documents/launchd/syslog/syslogd.tproj/com.apple.syslogd.plist — launchd plist/Users/jmaloney/Documents/launchd/syslog/aslcommon/asl_common.c — config + module merge/Users/jmaloney/Documents/launchd/Libnotify/notifyd/notifyd.c — notifyd main + deps/Users/jmaloney/Documents/launchd/Libnotify/notify_client.c + libnotify.c — client API/Users/jmaloney/Documents/launchd/IOKitUser/IOKitPMUnitTests/Stubs/NotifyStubs.{h,m} — Apple's own notify-stub template (reference shape)freebsd-src/lib/libc/gen/syslog.c — libc syslog(3) emits RFC 5424freebsd-src/sys/kern/subr_log.c — /dev/klog cdevfreebsd-src/sys/sys/syslog.h — _PATH_LOGfreebsd-src/contrib/openbsm/bsm/libbsm.h:1257-1294 — identical audit_token signaturesphase_e_libdispatch_mach_recv — Mach RECV backend; syslogd's database_server() uses the same patternphase_g2_complete — bootstrap server; syslogd + notifyd register via thisphase_h_libxpc_complete — libxpc already built; ASL uses XPC entitlement queriesphase_i1c_launchd_built — launchd-842 built; LAUNCH_JOBKEY_MACHSERVICES hands Mach portphase_i3_pid1_launchd_boot — PID-1 launchd boots to login; syslogd + notifyd run as launchd daemonsinstall_layout_policies — /usr/lib/system/ install pathfreebsd_launchd_mach_pkgbase_migration — FreeBSD-syslogd removed at 88694f0Plan synthesized from five parallel research agents on 2026-05-16:
(1) Apple syslog source audit, (2) libnotify dependency analysis, (3) FreeBSD syslog interop audit, (4) existing plan validation, (5) ASL + IOKit shared-dep audit. Supersedes the earlier freebsd-asl-plan.html v0 (which assumed an AF_UNIX / GNUstep Distributed Objects substrate — wrong now that Mach IPC + libxpc + libdispatch + libCoreFoundation are all working). Section 9 (Consumer guide) added per user request: documents how C and Objective-C consumers use ASL after this plan ships. Please flag anything that should change before this becomes a committed plan.