chiark / gitweb /
prefork-interp: wip
[chiark-utils.git] / prefork-interp.c
1 /*
2  * "Interpreter" that you can put in #! like this
3  *   #!/usr/bin/prefork-interp [<options>] <interpreter>
4  */
5
6 /*
7  * Process structure:
8  *  client (C wrapper)        connects to server
9  *                            if fails or garbage
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)
18  *
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)
23  *                            close fd: lockfile
24  *
25  *     setup (script)         runs initialisation parts of the script
26  *                            at prefork establishment point:
27  *                            forks to logger(1)
28  *                            forks for server, now becomes like monitor below
29  *                            exits
30  *
31  *         server (script)    fd0: null, fd[12]: syslog
32  *                            other fds: orig-fd[01], listener,
33  *                            other fds: call(server-end)(fake)
34  *
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
39  *         
40  *         [server (script)]  fd0: null, fd[12]: syslog
41  *                            other fds: listener
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
46  *
47  *  [client (C wrapper)]      if client connect succeeds:
48  *                            now fd: call(client-end)
49  *                               sends message with: cmdline, env
50  *                               sends fds
51  *
52  *        [server (script)]   accepts, forks monitor
53  *
54  *          monitor           [fd0: null, fd[12]: syslgo]
55  *                            other fds: call(server-end)
56  *                            receives args, env, fds
57  *                            forks executor
58  *
59  *            executor        sorts out fds:
60  *                            fd0, fd1, fd2: from-outer-caller
61  *                            close fds: call(server-end)
62  *                            implicitly closed fds: syslog
63  *
64  *                            sets cmdline, env
65  *                            runs main part of script
66  *                            exits normally
67  *
68  *          [monitor]         [fd0: null, fd[12]: syslgo]
69  *                            [other fds: call(server-end)]
70  *                            reaps executor
71  *                            reports status via socket
72  *
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)
77  */
78
79 struct sockaddr_un sun;
80
81 int main(int argc, const char *const *argv) {
82   script = process_opts(argc, argv);
83
84   find_socket_path();
85   FILLZERO(sun);
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));
89
90   bool isgarbage = check_garbage();
91
92   int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
93   if (client_fd==-1) diee("socket() for client");
94
95   salen_t salen = sizeof(sun);
96   r = connect(client, (const struct sockaddr*)sun, salen);
97   if (r==-1) {
98     if (errno==ECONNREFUSED || errno==ENOENT) {
99       
100 }