+***************************************************************************
+\f
+ Protocol, and functions of the script
+
+ 1. Script interpreter will be spawned apparently as normal;
+ should run synchronously in the normal way until
+ "initialisation complete" point. At initialisation complete:
+
+ 2. Env var PREFORK_INTERP contains:
+
+ v1,SECS.NSECS[,...] LISTEN,CALL,WATCHE,WATCHI[,...][ ...]
+
+ To parse it: split on ASCII space (or any whitespace), taking
+ first two words. There may or may not be further "words".
+ Then split each of the first two words on comma,
+ again taking the initial items as specified. The items are:
+
+ v1 Protocol version indicator - literal. If something else,
+ fail (installation is incompatible somehow).
+
+ SECS.NSECS
+ timestamp before script started running, as a decimal
+ time_t. NSECS is exactly 9 digits.
+ To be used for auto reloading.
+
+ These items are file descriptors:
+
+ LISTEN listening socket nonblocking
+ CALL call socket for initial call blocking
+ WATCHE liveness watcher stderr nonblocking
+ WATCHI liveness sentinel unspecified
+
+ 3. Library should do the following:
+
+ 1. Read and understand the PREFORK_INTERP env var.
+ If it is not set, initialisation complete should simply return.
+ This allows simple synchronous operation.
+
+ 2. Open syslog
+ 3. fork/exit (fork and have parent exit) (to make server)
+ 4. setsid (to become session leader)
+ 5. fork initial service (monitor) child, using CALL (see below)
+ 6. Replace stdin/stdout/stderr with /dev/null,
+ and make a note to send all error messages to syslog
+ 7. Enter select loop, looking for the following:
+
+ * accept on LISTEN:
+ i. see if we need to reload: is any file forming part
+ of the program newer than the SECS.NSECS ?
+ If so, log at LOG_INFO, and exit immediately
+ (dropping CALL, LISTEN, WATCHI, etc.)
+ ii. see if we can reap any children, possibly waiting
+ for children if we are at our concurrency limit
+ (limit should be configured through library, default 4)
+ iii. fork service (monitor) child, using accepted fd
+
+ * WATCHE is readable:
+ * EOF:: log at LOG_INFO, and exit
+ * data to read: read what is available immediately,
+ log it as a message at LOG_ERR, and exit
+
+ 4. service (monitor) child does the following:
+
+ 1. close all of LISTEN, WATCHI, WATCHE
+ 2. setpgrp
+ 3. send a greeting (on CALL) "PFI\n\0\0\0\0" (8 bytes)
+ 4. read a single byte, fail if it's not zero
+ 5. three times, receive a single byte with a file descriptor
+ attached as ancillary data. (These descriptors will be
+ service stdin, stdout, stderr.)
+ 6. read a 4-byte big-endian length
+ 7. read that many bytes, the initial service request message,
+ which contains the following nul-terminated strings:
+ * environment variable settings in the format NAME=value
+ * an empty string
+ * arguments NOT INCLUDING argv[0] or script filename
+ (not that this means the service request must end in a nul)
+ 8. make a new pipe EXECTERM
+ 9. fork for the service executor; in the child
+ i. redirect stdin/stdout/stderr to the recevied fds
+ ii. replace environment and arguments with those received,
+ iii. close descriptors: close the original received descriptors;
+ close CALL; keep only the writing end of EXECTERM
+ iv. if the script programming language does things with SIGINT,
+ set it set back to default handling (immediate termination).
+ v. return back to script, now in the grandchild
+
+ 10. in the parent, close EXECTERM writing end, and
+ 11. select, looking for one of the following:
+ * CALL is readable
+ * EXECTERM reading end is readable
+ No need to actually read, since these shouldn't produce
+ spurious wakeups (but do loop on EINTR).
+ 12. set SIGINT to ignored
+ 13. send SIGINT to the entire process group
+ 14. wait, blocking, for the executor child
+ 15. write the wait status, in 32-bit big-endian, to CALL
+ (this may generate SIGPIPE/EPIPE;
+ if so, die with SIGPIPE or exit 0; do treat that as failure)
+ 16. exit 0
+