1
2 #include "cntl.h"
3 #include <unistd.h>
4
5 #include <poll.h>
6 #include <socket_poll.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <signal.h>
11
12 #define EX_UTILS_NO_FUNCS 1
13 #include "ex_utils.h"
14
15 #include "mk.h"
16
17 #include "bag.h"
18
19 struct Cntl_child_obj
20 {
21 struct Evnt evnt[1];
22 pid_t pid;
23 };
24
25 struct Cntl_waiter_obj
26 {
27 struct Evnt *evnt;
28 unsigned int num;
29 };
30
31 static Vlg *vlg = NULL;
32 static struct Evnt *acpt_cntl_evnt = NULL;
33 static struct Evnt *acpt_pipe_evnt = NULL;
34
35 static Bag *childs = NULL;
36 static Bag *waiters = NULL;
37
38 static unsigned int potential_waiters = 0;
39
40
cntl__fin(Vstr_base * out)41 static void cntl__fin(Vstr_base *out)
42 {
43 size_t ns1 = 0;
44 size_t ns2 = 0;
45
46 if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
47 return;
48 if (!(ns2 = vstr_add_netstr_beg(out, out->len)))
49 return;
50 vstr_add_netstr_end(out, ns2, out->len);
51 vstr_add_netstr_end(out, ns1, out->len);
52 }
53
cntl_waiter_get_first(void)54 static struct Cntl_waiter_obj *cntl_waiter_get_first(void)
55 {
56 Bag_iter iter[1];
57 const Bag_obj *obj = bag_iter_beg(waiters, iter);
58
59 while (obj)
60 {
61 struct Cntl_waiter_obj *val = obj->val;
62
63 if (val->num)
64 return (val);
65
66 obj = bag_iter_nxt(iter);
67 }
68
69 return (NULL);
70 }
71
cntl_waiter_add(struct Evnt * evnt,size_t pos,size_t len,int * stop)72 static int cntl_waiter_add(struct Evnt *evnt, size_t pos, size_t len, int *stop)
73 {
74 Bag_iter iter[1];
75 const Bag_obj *obj = NULL;
76 struct Cntl_waiter_obj *val = NULL;
77 Bag *tmp = NULL;
78
79 ASSERT(stop);
80
81 if (!childs)
82 {
83 cntl__fin(evnt->io_w);
84 return (TRUE);
85 }
86
87 if (!(val = MK(sizeof(struct Cntl_waiter_obj))))
88 return (FALSE);
89
90 if (!(tmp = bag_add_obj(waiters, NULL, val)))
91 {
92 F(val);
93 VLG_WARNNOMEM_RET(FALSE, (vlg, "%s: %m\n", "cntl waiters"));
94 }
95
96 waiters = tmp;
97
98 val->evnt = evnt;
99 val->num = childs->num;
100
101 obj = bag_iter_beg(childs, iter);
102 while (obj)
103 {
104 struct Cntl_child_obj *child = (void *)obj->val;
105 Vstr_base *out = NULL;
106
107 if (!child)
108 return (FALSE);
109
110 out = child->evnt->io_w;
111
112 if (!vstr_add_vstr(out, out->len, evnt->io_r, pos, len, VSTR_TYPE_ADD_DEF))
113 {
114 out->conf->malloc_bad = FALSE;
115 return (FALSE);
116 }
117
118 if (!evnt_send_add(child->evnt, FALSE, 32))
119 {
120 evnt_close(child->evnt);
121 return (FALSE);
122 }
123
124 evnt_put_pkt(child->evnt);
125 obj = bag_iter_nxt(iter);
126 }
127
128 evnt_wait_cntl_del(evnt, POLLIN);
129 *stop = TRUE;
130
131 return (TRUE);
132 }
133
cntl_waiter_del(struct Evnt * child_evnt,struct Cntl_waiter_obj * val)134 static void cntl_waiter_del(struct Evnt *child_evnt,
135 struct Cntl_waiter_obj *val)
136 {
137 evnt_got_pkt(child_evnt);
138
139 if (!--val->num)
140 {
141 if (val->evnt)
142 {
143 cntl__fin(val->evnt->io_w);
144 if (!evnt_send_add(val->evnt, FALSE, 32))
145 evnt_close(val->evnt);
146 else
147 evnt_wait_cntl_add(val->evnt, POLLIN);
148 }
149
150 if (!cntl_waiter_get_first()) /* no more left... */
151 bag_del_all(waiters);
152 }
153 }
154
cntl__ns_out_cstr_ptr(Vstr_base * out,const char * ptr)155 static void cntl__ns_out_cstr_ptr(Vstr_base *out, const char *ptr)
156 {
157 size_t ns = 0;
158
159 if (!(ns = vstr_add_netstr_beg(out, out->len)))
160 return;
161
162 vstr_add_cstr_ptr(out, out->len, ptr);
163
164 vstr_add_netstr_end(out, ns, out->len);
165 }
166
167 static void cntl__ns_out_fmt(Vstr_base *out, const char *fmt, ...)
168 VSTR__COMPILE_ATTR_FMT(2, 3);
cntl__ns_out_fmt(Vstr_base * out,const char * fmt,...)169 static void cntl__ns_out_fmt(Vstr_base *out, const char *fmt, ...)
170 {
171 va_list ap;
172 size_t ns = 0;
173
174 if (!(ns = vstr_add_netstr_beg(out, out->len)))
175 return;
176
177 va_start(ap, fmt);
178 vstr_add_vfmt(out, out->len, fmt, ap);
179 va_end(ap);
180
181 vstr_add_netstr_end(out, ns, out->len);
182 }
183
cntl__close(Vstr_base * out)184 static void cntl__close(Vstr_base *out)
185 {
186 struct Evnt *evnt = evnt_queue("accept");
187
188 if (!evnt)
189 return;
190
191 while (evnt)
192 {
193 size_t ns1 = 0;
194
195 if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
196 return;
197
198 cntl__ns_out_cstr_ptr(out, "CLOSE");
199 cntl__ns_out_fmt(out, "from[$<sa:%p>]", EVNT_SA(evnt));
200 cntl__ns_out_fmt(out, "ctime[%lu:%lu]",
201 (unsigned long)evnt->ctime.tv_sec,
202 (unsigned long)evnt->ctime.tv_usec);
203 cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
204
205 vstr_add_netstr_end(out, ns1, out->len);
206
207 vlg_dbg2(vlg, "evnt_close acpt %p\n", evnt);
208 evnt_close(evnt);
209
210 evnt = evnt->next;
211 }
212
213 if (evnt_is_child())
214 evnt_shutdown_r(acpt_cntl_evnt, FALSE);
215 }
216
cntl__scan_events(Vstr_base * out,const char * tag,struct Evnt * beg)217 static void cntl__scan_events(Vstr_base *out, const char *tag, struct Evnt *beg)
218 {
219 struct Evnt *ev = beg;
220
221 while (ev)
222 {
223 size_t ns = 0;
224
225 if (!(ns = vstr_add_netstr_beg(out, out->len)))
226 return;
227
228 cntl__ns_out_fmt(out, "EVNT %s", tag);
229 cntl__ns_out_fmt(out, "from[$<sa:%p>]", EVNT_SA(ev));
230 cntl__ns_out_fmt(out, "ctime[%lu:%lu]",
231 (unsigned long)ev->ctime.tv_sec,
232 (unsigned long)ev->ctime.tv_usec);
233 cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
234 cntl__ns_out_fmt(out, "req_got[%'u:%u]",
235 ev->acct.req_got, ev->acct.req_got);
236 cntl__ns_out_fmt(out, "req_put[%'u:%u]",
237 ev->acct.req_put, ev->acct.req_put);
238 cntl__ns_out_fmt(out, "recv[${BKMG.ju:%ju}:%ju]",
239 ev->acct.bytes_r, ev->acct.bytes_r);
240 cntl__ns_out_fmt(out, "send[${BKMG.ju:%ju}:%ju]",
241 ev->acct.bytes_w, ev->acct.bytes_w);
242
243 vstr_add_netstr_end(out, ns, out->len);
244
245 ev = ev->next;
246 }
247 }
248
cntl__status(Vstr_base * out)249 static void cntl__status(Vstr_base *out)
250 {
251 struct Evnt *evnt = evnt_queue("accept");
252
253 while (evnt)
254 {
255 size_t ns1 = 0;
256
257 if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
258 return;
259
260 cntl__ns_out_cstr_ptr(out, "STATUS");
261 cntl__ns_out_fmt(out, "from[$<sa:%p>]", EVNT_SA(evnt));
262 cntl__ns_out_fmt(out, "ctime[%lu:%lu]",
263 (unsigned long)evnt->ctime.tv_sec,
264 (unsigned long)evnt->ctime.tv_usec);
265
266 cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
267
268 vstr_add_netstr_end(out, ns1, out->len);
269
270 evnt = evnt->next;
271 }
272 }
273
cntl__dbg(Vstr_base * out)274 static void cntl__dbg(Vstr_base *out)
275 {
276 size_t ns1 = 0;
277
278 if (!(ns1 = vstr_add_netstr_beg(out, out->len)))
279 return;
280
281 cntl__ns_out_cstr_ptr(out, "DBG");
282 cntl__ns_out_fmt(out, "pid[%lu]", (unsigned long)getpid());
283 cntl__ns_out_fmt(out, "dbg[%u]", (unsigned)vlg->out_dbg);
284 vstr_add_netstr_end(out, ns1, out->len);
285 }
286
cntl__srch_waiter_evnt(const Bag_obj * obj,const void * data)287 static int cntl__srch_waiter_evnt(const Bag_obj *obj, const void *data)
288 {
289 const struct Cntl_waiter_obj *val = obj->val;
290 const struct Evnt *evnt = data;
291
292 return (val->evnt == evnt);
293 }
294
cntl__cb_func_free(struct Evnt * evnt)295 static void cntl__cb_func_free(struct Evnt *evnt)
296 {
297 evnt_vlg_stats_info(evnt, "CNTL FREE");
298
299 if (waiters)
300 {
301 const Bag_obj *obj = bag_srch_eq(waiters, cntl__srch_waiter_evnt, evnt);
302
303 if (obj)
304 {
305 struct Cntl_waiter_obj *val = obj->val;
306
307 ASSERT(val->evnt == evnt);
308 val->evnt = NULL;
309 }
310 }
311
312 F(evnt);
313
314 ASSERT(potential_waiters >= 1);
315 --potential_waiters;
316
317 if (childs && !potential_waiters && !acpt_cntl_evnt)
318 bag_del_all(childs);
319 }
320
cntl__cb_func_recv(struct Evnt * evnt)321 static int cntl__cb_func_recv(struct Evnt *evnt)
322 {
323 int ret = evnt_cb_func_recv(evnt);
324 int stop = FALSE;
325
326 if (!ret)
327 goto malloc_bad;
328
329 vlg_dbg2(vlg, "CNTL recv %zu\n", evnt->io_r->len);
330
331 while (evnt->io_r->len && !stop)
332 {
333 size_t pos = 0;
334 size_t len = 0;
335 size_t ns1 = 0;
336
337 if (!(ns1 = vstr_parse_netstr(evnt->io_r, 1, evnt->io_r->len, &pos, &len)))
338 {
339 if (!(SOCKET_POLL_INDICATOR(evnt->ind)->events & POLLIN))
340 return (FALSE);
341 return (TRUE);
342 }
343
344 evnt_got_pkt(evnt);
345
346 if (0){ }
347 else if (vstr_cmp_cstr_eq(evnt->io_r, pos, len, "CLOSE"))
348 {
349 cntl__close(evnt->io_w);
350
351 if (!cntl_waiter_add(evnt, 1, ns1, &stop))
352 goto malloc_bad;
353 }
354 else if (vstr_cmp_cstr_eq(evnt->io_r, pos, len, "DBG"))
355 {
356 vlg_debug(vlg);
357 cntl__dbg(evnt->io_w);
358
359 if (!cntl_waiter_add(evnt, 1, ns1, &stop))
360 goto malloc_bad;
361 }
362 else if (vstr_cmp_cstr_eq(evnt->io_r, pos, len, "UNDBG"))
363 {
364 vlg_undbg(vlg);
365 cntl__dbg(evnt->io_w);
366
367 if (!cntl_waiter_add(evnt, 1, ns1, &stop))
368 goto malloc_bad;
369 }
370 else if (vstr_cmp_cstr_eq(evnt->io_r, pos, len, "LIST"))
371 {
372 cntl__scan_events(evnt->io_w, "CONNECT", evnt_queue("connect"));
373 cntl__scan_events(evnt->io_w, "ACCEPT", evnt_queue("accept"));
374 cntl__scan_events(evnt->io_w, "SEND/RECV", evnt_queue("send_recv"));
375 cntl__scan_events(evnt->io_w, "RECV", evnt_queue("recv"));
376 cntl__scan_events(evnt->io_w, "NONE", evnt_queue("none"));
377 cntl__scan_events(evnt->io_w, "SEND_NOW", evnt_queue("send_now"));
378
379 if (!cntl_waiter_add(evnt, 1, ns1, &stop))
380 goto malloc_bad;
381 }
382 else if (vstr_cmp_cstr_eq(evnt->io_r, pos, len, "STATUS"))
383 {
384 cntl__status(evnt->io_w);
385
386 if (!cntl_waiter_add(evnt, 1, ns1, &stop))
387 goto malloc_bad;
388 }
389 else
390 return (FALSE);
391
392 if (evnt->io_w->conf->malloc_bad)
393 goto malloc_bad;
394
395 evnt_put_pkt(evnt);
396 if (!evnt_send_add(evnt, FALSE, 32))
397 return (FALSE);
398
399 vstr_del(evnt->io_r, 1, ns1);
400 }
401
402 return (TRUE);
403
404 malloc_bad:
405 evnt->io_r->conf->malloc_bad = FALSE;
406 evnt->io_w->conf->malloc_bad = FALSE;
407 return (FALSE);
408 }
409
410
cntl__cb_func_acpt_free(struct Evnt * evnt)411 static void cntl__cb_func_acpt_free(struct Evnt *evnt)
412 {
413 evnt_vlg_stats_info(evnt, "ACCEPT CNTL FREE");
414
415 ASSERT(acpt_cntl_evnt == evnt);
416
417 acpt_cntl_evnt = NULL;
418
419 F(evnt);
420
421 evnt_acpt_close_all();
422
423 if (childs && !potential_waiters)
424 bag_del_all(childs);
425 }
426
cntl__cb_func_accept(struct Evnt * from_evnt,int fd,struct sockaddr * sa,socklen_t len)427 static struct Evnt *cntl__cb_func_accept(struct Evnt *from_evnt, int fd,
428 struct sockaddr *sa, socklen_t len)
429 {
430 struct Evnt *evnt = NULL;
431
432 ASSERT(acpt_cntl_evnt);
433 ASSERT(acpt_cntl_evnt == from_evnt);
434 ASSERT(from_evnt->sa_ref);
435 ASSERT(len >= 2);
436
437 if (sa->sa_family != AF_LOCAL)
438 goto make_acpt_fail;
439
440 if (!(evnt = MK(sizeof(struct Evnt))))
441 goto mk_acpt_fail;
442 if (!evnt_make_acpt_ref(evnt, fd, from_evnt->sa_ref))
443 goto make_acpt_fail;
444
445 vlg_info(vlg, "CNTL CONNECT from[$<sa:%p>]\n", EVNT_SA(evnt));
446
447 evnt->cbs->cb_func_recv = cntl__cb_func_recv;
448 evnt->cbs->cb_func_free = cntl__cb_func_free;
449 ++potential_waiters;
450
451 return (evnt);
452
453 make_acpt_fail:
454 F(evnt);
455 VLG_WARNNOMEM_RET(NULL, (vlg, "%s: %m\n", "accept"));
456 mk_acpt_fail:
457 VLG_WARN_RET(NULL, (vlg, "%s: %m\n", "accept"));
458 }
459
cntl_make_file(Vlg * passed_vlg,const char * fname)460 void cntl_make_file(Vlg *passed_vlg, const char *fname)
461 {
462 struct Evnt *evnt = NULL;
463
464 ASSERT(!vlg && passed_vlg);
465
466 vlg = passed_vlg;
467
468 ASSERT(fname);
469 ASSERT(!acpt_cntl_evnt);
470
471 if (!(evnt = MK(sizeof(struct Evnt))))
472 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "cntl file: %m\n"));
473
474 if (!evnt_make_bind_local(evnt, fname, 8))
475 vlg_err(vlg, EXIT_FAILURE, "cntl file: %m\n");
476
477 evnt->cbs->cb_func_accept = cntl__cb_func_accept;
478 evnt->cbs->cb_func_free = cntl__cb_func_acpt_free;
479
480 acpt_cntl_evnt = evnt;
481 }
482
cntl__cb_func_cntl_acpt_free(struct Evnt * evnt)483 static void cntl__cb_func_cntl_acpt_free(struct Evnt *evnt)
484 {
485 evnt_vlg_stats_info(evnt, "CHILD CNTL FREE");
486
487 ASSERT(acpt_cntl_evnt == evnt);
488
489 acpt_cntl_evnt = NULL;
490
491 F(evnt);
492
493 evnt_acpt_close_all();
494 }
495
cntl__cb_func_pipe_acpt_free(struct Evnt * evnt)496 static void cntl__cb_func_pipe_acpt_free(struct Evnt *evnt)
497 {
498 evnt_vlg_stats_info(evnt, "CHILD PIPE FREE");
499
500 ASSERT(acpt_pipe_evnt == evnt);
501
502 acpt_pipe_evnt = NULL;
503
504 F(evnt);
505
506 evnt_acpt_close_all();
507 }
508
509 /* used to get death sig or pass through cntl data */
cntl_pipe_acpt_fds(Vlg * passed_vlg,int fd,int allow_pdeathsig)510 static void cntl_pipe_acpt_fds(Vlg *passed_vlg, int fd, int allow_pdeathsig)
511 {
512 ASSERT(fd != -1);
513
514 if (acpt_cntl_evnt)
515 {
516 int old_fd = SOCKET_POLL_INDICATOR(acpt_cntl_evnt->ind)->fd;
517
518 ASSERT(vlg == passed_vlg);
519
520 if (!evnt_poll_swap_accept_read(acpt_cntl_evnt, fd))
521 vlg_abort(vlg, "%s: %m\n", "swap_acpt");
522
523 close(old_fd);
524
525 acpt_cntl_evnt->cbs->cb_func_recv = cntl__cb_func_recv;
526 acpt_cntl_evnt->cbs->cb_func_free = cntl__cb_func_cntl_acpt_free;
527
528 if (allow_pdeathsig)
529 PROC_CNTL_PDEATHSIG(SIGCHLD);
530 }
531 else
532 {
533 if (!vlg)
534 vlg = passed_vlg;
535 ASSERT(vlg == passed_vlg);
536
537 if (allow_pdeathsig && (PROC_CNTL_PDEATHSIG(SIGCHLD) != -1))
538 {
539 close(fd);
540 return;
541 }
542
543 if (!(acpt_pipe_evnt = MK(sizeof(struct Evnt))))
544 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "pipe evnt"));
545
546 if (!evnt_make_custom(acpt_pipe_evnt, fd, 0, 0))
547 vlg_err(vlg, EXIT_FAILURE, "%s: %m\n", "pipe evnt");
548
549 acpt_pipe_evnt->cbs->cb_func_free = cntl__cb_func_pipe_acpt_free;
550 }
551 }
552
cntl__bag_cb_free_evnt(void * val)553 static void cntl__bag_cb_free_evnt(void *val)
554 {
555 evnt_close(val);
556 }
557
cntl__bag_cb_free_F(void * val)558 static void cntl__bag_cb_free_F(void *val)
559 {
560 F(val);
561 }
562
cntl_child_make(unsigned int num)563 void cntl_child_make(unsigned int num)
564 {
565 ASSERT(!childs && !waiters && acpt_cntl_evnt);
566
567 if (!(childs = bag_make(num, bag_cb_free_nothing, cntl__bag_cb_free_evnt)))
568 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
569 if (!(waiters = bag_make(4, bag_cb_free_nothing, cntl__bag_cb_free_F)))
570 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
571 }
572
cntl_child_free(void)573 void cntl_child_free(void)
574 {
575 bag_free(childs); childs = NULL;
576 bag_free(waiters); waiters = NULL;
577 }
578
cntl__cb_func_child_recv(struct Evnt * evnt)579 static int cntl__cb_func_child_recv(struct Evnt *evnt)
580 {
581 struct Cntl_waiter_obj *val = cntl_waiter_get_first();
582
583 ASSERT(val);
584
585 if (!evnt_cb_func_recv(evnt))
586 goto malloc_bad;
587
588 while (evnt->io_r->len)
589 {
590 size_t ns1 = 0;
591 size_t pos = 0;
592 size_t len = 0;
593 size_t vpos = 0;
594 size_t vlen = 0;
595 size_t nse2 = 0;
596 int done = FALSE;
597
598 ASSERT(val);
599
600 if (!(ns1 = vstr_parse_netstr(evnt->io_r, 1, evnt->io_r->len, &pos, &len)))
601 {
602 if (!(SOCKET_POLL_INDICATOR(evnt->ind)->events & POLLIN))
603 return (FALSE);
604 return (TRUE);
605 }
606
607 while ((nse2 = vstr_parse_netstr(evnt->io_r, pos, len, &vpos, &vlen)))
608 {
609 if (!done && !vlen && (nse2 == len))
610 {
611 cntl_waiter_del(evnt, val);
612 vstr_del(evnt->io_r, 1, ns1);
613 val = cntl_waiter_get_first();
614 break;
615 }
616
617 done = TRUE;
618 len -= nse2; pos += nse2;
619 }
620 if (nse2)
621 continue;
622
623 if (len)
624 VLG_WARN_RET(FALSE, (vlg, "invalid entry\n"));
625
626 if (!val->evnt)
627 vstr_del(evnt->io_r, 1, ns1);
628 else
629 {
630 struct Evnt *out = val->evnt;
631
632 if (!vstr_mov(out->io_w, out->io_w->len, evnt->io_r, 1, ns1))
633 goto malloc_bad;
634 }
635 }
636
637 return (TRUE);
638
639 malloc_bad:
640 evnt_close(val->evnt);
641 evnt->io_r->conf->malloc_bad = FALSE;
642 evnt->io_w->conf->malloc_bad = FALSE;
643 return (TRUE); /* this is "true" because the app. dies if we kill this con */
644 }
645
cntl__cb_func_child_free(struct Evnt * evnt)646 static void cntl__cb_func_child_free(struct Evnt *evnt)
647 {
648 if (childs)
649 {
650 const Bag_obj *obj = bag_srch_eq(childs, bag_cb_srch_eq_val_ptr, evnt);
651
652 if (obj) /* FIXME: const cast */
653 ((Bag_obj *)obj)->val = NULL;
654 }
655
656 F(evnt);
657 }
658
cntl_child_pid(pid_t pid,int fd)659 void cntl_child_pid(pid_t pid, int fd)
660 {
661 struct Cntl_child_obj *obj = NULL;
662
663 ASSERT(acpt_cntl_evnt);
664
665 if (!(obj = MK(sizeof(struct Cntl_child_obj))))
666 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
667
668 obj->pid = pid;
669
670 if (!evnt_make_custom(obj->evnt, fd, 0, POLLIN))
671 vlg_err(vlg, EXIT_FAILURE, "%s: %m\n", "cntl children");
672
673 obj->evnt->cbs->cb_func_free = cntl__cb_func_child_free;
674 obj->evnt->cbs->cb_func_recv = cntl__cb_func_child_recv;
675
676 if (!(childs = bag_add_obj(childs, NULL, obj)))
677 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "%s: %m\n", "cntl children"));
678 }
679
680 /* Here we fork multiple procs. however:
681 *
682 * If we have a cntl connection we keep two way communication open with the
683 * children.
684 *
685 * If not we "leak" the writable side of the pipe() fd in the parent,
686 * which will cause an error on all the children's fd when the parent dies.
687 *
688 * The children also kill themselves if the parent fd has an error.
689 */
cntl_sc_multiproc(Vlg * passed_vlg,unsigned int num,int use_cntl,int allow_pdeathsig)690 void cntl_sc_multiproc(Vlg *passed_vlg,
691 unsigned int num, int use_cntl, int allow_pdeathsig)
692 {
693 int pfds[2] = {-1, -1};
694
695 if (!vlg)
696 vlg = passed_vlg;
697
698 ASSERT(vlg == passed_vlg);
699
700 vlg_pid_set(vlg, TRUE);
701
702 if (!use_cntl && (pipe(pfds) == -1))
703 vlg_err(vlg, EXIT_FAILURE, "pipe(): %m\n");
704
705 if (use_cntl)
706 cntl_child_make(num - 1);
707
708 while (--num)
709 {
710 pid_t cpid = -1;
711
712 if (use_cntl && (socketpair(PF_LOCAL, SOCK_STREAM, IPPROTO_IP, pfds) == -1))
713 vlg_err(vlg, EXIT_FAILURE, "socketpair(): %m\n");
714
715 if ((cpid = evnt_make_child()) == -1)
716 vlg_err(vlg, EXIT_FAILURE, "fork(): %m\n");
717
718 if (use_cntl && cpid) /* parent */
719 {
720 close(pfds[0]);
721 cntl_child_pid(cpid, pfds[1]);
722 }
723 else if (!cpid)
724 { /* child */
725 close(pfds[1]);
726 cntl_child_free();
727 cntl_pipe_acpt_fds(vlg, pfds[0], allow_pdeathsig);
728
729 evnt_scan_q_close();
730 return;
731 }
732 }
733
734 if (!use_cntl)
735 close(pfds[0]); /* close child pipe() */
736
737 evnt_scan_q_close();
738 }
739
740