Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
0

Configure Feed

Select the types of activity you want to include in your feed.

ircd.rs / docs / superpowers / plans / 2026-06-06-p7ee-daemonize.md
3.7 kB

P7ee — port s_bsd.c daemonize (boot detach + resolver/iauth init)#

Scope#

daemonize (s_bsd.c:794) is the boot-time process-detach glue, called once from ircd.c:1152 (still C — resolves to the Rust def once dropped). It is now a clean leaf: its only non-libc callees — init_resolver (P6, Rust) and start_iauth (P7dd, Rust) — are already ported. With daemonize ported, the only still-C logic left in s_bsd.c is the event loop (read_message + its statics polludp/check_ping).

Config-resolved body (locked config)#

if (bootopt & BOOT_TTY) goto init_dgram;        /* debugging to a tty → skip detach */
fclose(stdout); close(1);
if (!(bootopt & BOOT_DEBUG)) { fclose(stderr); close(2); }
if (((bootopt & BOOT_CONSOLE) || isatty(0)) && !(bootopt & BOOT_INETD)) {
    if (fork()) exit(0);                         /* parent exits → detach */
    if ((fd = open("/dev/tty", O_RDWR)) >= 0) {  /* TIOCNOTTY defined on Linux */
        ioctl(fd, TIOCNOTTY, NULL); close(fd);
    }
    setpgrp(0, getpid());                        /* the `#else` BSD 2-arg branch compiles */
    fclose(stdin); close(0);
}
init_dgram:
resfd = init_resolver(0x1f);
start_iauth(0);
  • TIOCNOTTY is defined on Linux → the int fd + ioctl block compiles.
  • The setpgrp arm resolves to the #else setpgrp(0, getpid()) branch (verified by preprocessing — none of HPUX/SVR4/DYNIXPTX/_POSIX_SOURCE/SGI/__CYGWIN32__/ __APPLE__ are defined). The linked glibc symbol is setpgrp(void) (ignores the args) — call libc::setpgrp(), behaviourally identical to the C call.
  • bootopt (ircd.c), resfd (s_bsd.c) reached via bindgen externs; BOOT_* are bindgen consts; init_resolver/start_iauth declared local externs (resolve to the Rust defs).
  • stdout/stderr/stdin are glibc extern FILE * symbols (not the macros) → local externs.

Seam#

Partial port via the existing s_bsd_link.o recipe, new guard -DPORT_S_BSD_DAEMONIZE_P7ee; #ifndef-guard the C body (no #else proto needed — daemonize is declared in s_bsd_ext.h). read_message/polludp/check_ping stay C.

L1 — daemonize_diff.rs#

daemonize is mostly untestable by design: the detach path forks (parent exit(0)s) and closes 0/1/2 — calling it on that path destroys the harness, and even fork-isolation can't measure a function whose job is to detach. The only differentially-safe path is the BOOT_TTY short-circuit (goto init_dgram — no fork, no fd close), which is also the only path any harness ever takes (golden boots -t = BOOT_TTY).

One case, run on both worlds (c_daemonize link_name=daemonize → Rust; cref_daemonize → oracle), serialized on GLOBALS_LOCK:

  • Set bootopt = cref_bootopt = BOOT_TTY | BOOT_NOIAUTH, adfd = cref_adfd = -1, resfd = cref_resfd = -99 (sentinel).
  • Call each world's daemonize.
  • Assert: resfd != -99 and resfd >= 0 (init_resolver ran, opened the resolver socket), (resfd >= 0) == (cref_resfd >= 0) (both worlds succeeded identically); adfd == -1 and cref_adfd == -1 (the inverse check — start_iauth(0) was reached but short-circuited on BOOT_NOIAUTH, touching nothing). Close resfd/cref_resfd after.

Untested-by-design: the entire detach path (fclose/close of 0/1/2, fork+parent exit, TIOCNOTTY ioctl, setpgrp) — it detaches/forks the process; no harness exercises it (all boot -t).

L2 / S2S#

No new L2 (boot callee, not a msgtab handler; the existing golden suite boots through the BOOT_TTY path of daemonizegolden_registration stays byte-identical). No S2S (formats no remote-user wire fields).