2 * "Interpreter" that you can put in #! like this
3 * #!/usr/bin/prefork-interp [<options>] <interpreter>
8 * client (C wrapper) connects to server
10 * === acquire lock ===
11 * makes new listening socket
12 * makes first-instance socketpair
13 * forks setup (script, sock fds indicated in env)
14 * fd0, fd1, fd2: from-outer-caller
15 * other fd: call(client-end)(fake)
16 * reaps setup (and reports error)
17 * (implicitly releases lock)
19 * setup (pre-exec) fd0: null,
20 * fd[12: fd2-from-outer-caller
21 * env fds: orig-fd[01], listener,
22 * env fds: call(server-end)(fake)
25 * setup (script) runs initialisation parts of the script
26 * at prefork establishment point:
28 * forks for server, now becomes like monitor below
31 * server (script) fd0: null, fd[12]: syslog
32 * other fds: orig-fd[01], listener,
33 * other fds: call(server-end)(fake)
35 * right away, forks one fake-accepted monitor:
36 * f-a monitor [fd0: null, fd[12]: syslgo]
37 * other fds: call(server-end)(fake)
38 * runs as monitor, below
40 * [server (script)] fd0: null, fd[12]: syslog
42 * closes fds: orig-fd[01], call(server-end)fake)
43 * runs in loop accepting and forking,
44 * reaping and limiting children
45 * reports failures of monitors to syslog
47 * [client (C wrapper)] if client connect succeeds:
48 * now fd: call(client-end)
49 * sends message with: cmdline, env
52 * [server (script)] accepts, forks monitor
54 * monitor [fd0: null, fd[12]: syslgo]
55 * other fds: call(server-end)
56 * receives args, env, fds
59 * executor sorts out fds:
60 * fd0, fd1, fd2: from-outer-caller
61 * close fds: call(server-end)
62 * implicitly closed fds: syslog
65 * runs main part of script
68 * [monitor] [fd0: null, fd[12]: syslgo]
69 * [other fds: call(server-end)]
71 * reports status via socket
73 * [client (C wrapper)] [fd0, fd1, fd2: from-outer-caller]
74 * [other fd: call(client-end)]
75 * receives status, exits appropriately
76 * (if was bad signal, reports to stderr, exits 127)
79 struct sockaddr_un sun;
81 int main(int argc, const char *const *argv) {
82 script = process_opts(argc, argv);
86 sun.sun_family = AF_UNIX;
87 assert(strlen(socket_path) <= sizeof(sun.sun_path));
88 strncpy(sun.sun_path, socket_path, sizeof(sun.sun_path));
90 bool isgarbage = check_garbage();
92 int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
93 if (client_fd==-1) diee("socket() for client");
95 salen_t salen = sizeof(sun);
96 r = connect(client, (const struct sockaddr*)sun, salen);
98 if (errno==ECONNREFUSED || errno==ENOENT) {