From bb3d8eb56f2d502370ec37b7b2d85b1881165cc1 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 4 Feb 2024 21:37:31 -0600 Subject: [PATCH] Explain why toybox doesn't have (or need) cttyhack. --- www/faq.html | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) mode change 100755 => 100644 www/faq.html diff --git a/www/faq.html b/www/faq.html old mode 100755 new mode 100644 index 3d5ead48..84cf3107 --- a/www/faq.html +++ b/www/faq.html @@ -30,6 +30,12 @@
  • How do I build a working Linux system with toybox?

  • +

    Specific commands

    + + +

    Q: "Why is there toybox? What was wrong with busybox?"

    A: Toybox started back in 2006 when I (Rob Landley) @@ -858,6 +864,70 @@ why it uses the .config that's there when there is one, but the default is currently wrong because it's not quite finished yet. All this should be cleaned up in a future release, before 1.0.)

    - - +

    Q: Why doesn't toybox have cttyhack?

    + +

    A: Because it's unnecessary (it has "hack" in the name). Here's what +mkroot does in its PID 1 init script instead (after mounting /sys and /dev):

    + +

    +trap '' CHLD
    +CONSOLE=$(sed '$s@.*/@@' /sys/class/tty/console/active)
    +: ${HANDOFF:=/bin/sh}
    +setsid -c <>/dev/$CONSOLE >&0 2>&1 $HANDOFF
    +reboot -f &
    +sleep 5
    +

    + +

    The "trap" tells the shell to accept and discard exiting child +processes (so zombies don't accumulate). +Child processes whose parents have already exited get reparented to init +(I.E. pid 1) and the shell script is sticking around as PID 1. +Setting SIGCHLD to SIG_IGN (which trap with an empty string does) +prevents them from waiting around in Z state to deliver their exit status +in case the parent ever gets around to calling wait().

    + +

    $CONSOLE fishes the underlying console device behind /dev/console out +of sysfs, because the linux kernel's /dev/console device can't act as a +controlling tty (for some reason). Since there may be more than one, and it +might or might not have a /dev/ prefix, we use sed to take the last +entry and remove any path.

    + +

    $HANDOFF is the child program to run, and the third line above +gives it the default value of /bin/sh if it wasn't already set on the +kernel command line. The bash ${NAME:=default value} syntax assigns a default +value to blank environment variables (see the bash man page) and : is a synonym +for the "true" command which ignores its arguments, so this combination is a +quick way to assign default values to blank variables. You can set $HANDOFF on +the kernel command line via "KARGS='HANDOFF=cal' ./run-qemu.sh" +since the run-qemu.sh script appends $KARGS to the end of the kernel +command line when launching QEMU, and unrecognized linux kernel command line +arguments with an = in them are treated as variable assignments exported into +PID 1's environment.

    + +

    The "setsid" command runs a command in a new session (see "man 7 +credentials") and the -c option makes stdin the controling TTY for the new +session. The first redirect points stdin at the new console device (the +<> redirect opens the file for both reading and writing at +the same time) and the second and third redirects duplicate the stdin +file descriptor to stdout and stderr. Redirects are guaranteed to be evaluated +from left to right, and all redirects happen before launching the command, +so -c grabs the new TTY device as the child's controlling tty.

    + +

    When the child process setsid launched exits (usually by using the shell's +builtin "exit" command) the PID 1 shell script resumes and calls +"reboot" to exit qemu. Ordinarily the reboot command sends SIGTERM +to PID 1, but that won't do anything useful here, so we give it the -f option to +force it to call the reboot() syscall directly (see man 2 reboot). For +some reason the Linux reboot() syscall exits the process instead of blocking, +and if PID 1 exits the kernel panics, which aborts the reboot process, so +we background the reboot request into a child process and sleep 5 +to give the reboot time to finish.

    + +

    Toybox also has a oneit command that can do all this, and has a -3 +option which hands off daemon management to a child process by writing each +exiting orphaned task's PID to the child's file descriptor 3 (the next +available on after stdin, stdout, and stderr). It can also respawn its +child (instead of halting or rebooting) when it exits, but you could add +a loop to the shell script easily enough.

    + -- 2.39.2