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