nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* source: xio-progcall.c */
2 /* Copyright Gerhard Rieger */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4  
5 /* this file contains common code dealing with program calls (exec, system) */
6  
7 #include "xiosysincludes.h"
8 #include "xioopen.h"
9 #include "xiosigchld.h"
10  
11 #include "xio-process.h"
12 #include "xio-progcall.h"
13  
14 #include "xio-socket.h"
15  
16  
17 static int reassignfds(int oldfd1, int oldfd2, int newfd1, int newfd2);
18  
19  
20 /* these options are used by address pty too */
21 #if HAVE_OPENPTY
22 const struct optdesc opt_openpty = { "openpty", NULL, OPT_OPENPTY, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
23 #endif /* HAVE_OPENPTY */
24 #if HAVE_DEV_PTMX || HAVE_DEV_PTC
25 const struct optdesc opt_ptmx = { "ptmx", NULL, OPT_PTMX, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
26 #endif
27  
28 #if WITH_EXEC || WITH_SYSTEM
29  
30 #define MAXPTYNAMELEN 64
31  
32 const struct optdesc opt_leftfd = { "leftfd", "left", OPT_LEFTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
33 const struct optdesc opt_leftinfd = { "leftin", "fdin", OPT_LEFTINFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
34 const struct optdesc opt_leftoutfd = { "leftout", "fdout", OPT_LEFTOUTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
35 const struct optdesc opt_rightfd = { "rightfd", "right", OPT_RIGHTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
36 const struct optdesc opt_rightinfd = { "rightinfd", "rightin", OPT_RIGHTINFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
37 const struct optdesc opt_rightoutfd = { "rightoutfd", "rightout", OPT_RIGHTOUTFD, GROUP_FORK, PH_PASTBIGEN, TYPE_INT, OFUNC_SPEC };
38 const struct optdesc opt_path = { "path", NULL, OPT_PATH, GROUP_EXEC, PH_PREEXEC, TYPE_STRING, OFUNC_SPEC };
39 const struct optdesc opt_pipes = { "pipes", NULL, OPT_PIPES, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
40 #if HAVE_PTY
41 const struct optdesc opt_pty = { "pty", NULL, OPT_PTY, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
42 #endif
43 const struct optdesc opt_commtype= { "commtype", NULL, OPT_COMMTYPE, GROUP_FORK, PH_BIGEN, TYPE_STRING, OFUNC_SPEC };
44 const struct optdesc opt_stderr = { "stderr", NULL, OPT_STDERR, GROUP_FORK, PH_PASTFORK, TYPE_BOOL, OFUNC_SPEC };
45 const struct optdesc opt_nofork = { "nofork", NULL, OPT_NOFORK, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
46 const struct optdesc opt_sighup = { "sighup", NULL, OPT_SIGHUP, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGHUP };
47 const struct optdesc opt_sigint = { "sigint", NULL, OPT_SIGINT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGINT };
48 const struct optdesc opt_sigquit = { "sigquit", NULL, OPT_SIGQUIT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGQUIT };
49  
50 int getcommtype(const char *commname) {
51 struct wordent commnames[] = {
52 { "pipes", (void *)XIOCOMM_PIPES },
53 { "pty", (void *)XIOCOMM_PTY },
54 { "ptys", (void *)XIOCOMM_PTYS },
55 { "socketpair", (void *)XIOCOMM_SOCKETPAIR },
56 { "socketpairs", (void *)XIOCOMM_SOCKETPAIRS },
57 { "tcp", (void *)XIOCOMM_TCP },
58 { "tcp4", (void *)XIOCOMM_TCP4 },
59 { "tcp4listen", (void *)XIOCOMM_TCP4_LISTEN },
60 { NULL }
61 } ;
62 const struct wordent *comm_ent;
63 comm_ent = keyw((struct wordent *)commnames, commname,
64 sizeof(commnames)/sizeof(struct wordent));
65 if (!comm_ent) {
66 return -1;
67 }
68 return (int)comm_ent->desc;
69 }
70  
71 /* fork for exec/system, but return before exec'ing.
72 return=0: is child process
73 return>0: is parent process
74 return<0: error occurred, assume parent process and no child exists !!!
75 function formerly known as _xioopen_foxec()
76 */
77 int _xioopen_progcall(int xioflags, /* XIO_RDONLY etc. */
78 struct single *xfd,
79 unsigned groups,
80 struct opt **copts, /* in: opts; out: opts for child */
81 int *duptostderr,
82 bool inter, /* is interaddr, not endpoint */
83 int form /* with interaddr: =2: FDs 1,0--4,3
84 =1: FDs 1--0 */
85 ) {
86 struct single *fd = xfd;
87 struct opt *popts; /* parent process options */
88 int numleft;
89 int sv[2], rdpip[2], wrpip[2];
90 int saverfd = -1, savewfd = -1; /* with inter addr, save assigned right fds */
91 int rw = (xioflags & XIO_ACCMODE);
92 char *commname;
93 int commtype = XIOCOMM_SOCKETPAIRS;
94 bool usepipes = false;
95 #if HAVE_PTY
96 int ptyfd = -1, ttyfd = -1;
97 bool usebestpty = false; /* use the best available way to open pty */
98 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
99 bool useptmx = false; /* use /dev/ptmx or equivalent */
100 #endif
101 #if HAVE_OPENPTY
102 bool useopenpty = false; /* try only openpty */
103 #endif /* HAVE_OPENPTY */
104 bool usepty = false; /* any of the pty options is selected */
105 char ptyname[MAXPTYNAMELEN];
106 #endif /* HAVE_PTY */
107 pid_t pid = 0; /* mostly int */
108 int leftfd[2] = { 0, 1 };
109 # define fdi (leftfd[0])
110 # define fdo (leftfd[1])
111 int rightfd[2] = { 3, 4 };
112 # define rightin (rightfd[0])
113 # define rightout (rightfd[1])
114 short result;
115 bool withstderr = false;
116 bool nofork = false;
117 bool withfork;
118  
119 popts = moveopts(*copts, GROUP_ALL);
120 if (applyopts_single(fd, popts, PH_INIT) < 0) return -1;
121 applyopts2(-1, popts, PH_INIT, PH_EARLY);
122  
123 retropt_bool(popts, OPT_NOFORK, &nofork);
124 withfork = !nofork;
125  
126 if ((retropt_string(popts, OPT_COMMTYPE, &commname)) >= 0) {
127 if ((commtype = getcommtype(commname)) < 0) {
128 Error1("bad communication type \"%s\"", commname);
129 commtype = XIOCOMM_SOCKETPAIRS;
130 }
131 }
132  
133 retropt_bool(popts, OPT_PIPES, &usepipes);
134 #if HAVE_PTY
135 retropt_bool(popts, OPT_PTY, &usebestpty);
136 #if HAVE_OPENPTY
137 retropt_bool(popts, OPT_OPENPTY, &useopenpty);
138 #endif
139 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
140 retropt_bool(popts, OPT_PTMX, &useptmx);
141 #endif
142 usepty = (usebestpty
143 #if HAVE_OPENPTY
144 || useopenpty
145 #endif
146 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
147 || useptmx
148 #endif
149 );
150 if (usepipes && usepty) {
151 Warn("_xioopen_progcall(): options \"pipes\" and \"pty\" must not be specified together; ignoring \"pipes\"");
152 usepipes = false;
153 }
154 #endif /* HAVE_PTY */
155  
156 if (usepty) {
157 commtype = XIOCOMM_PTY;
158 } else if (usepipes) {
159 commtype = XIOCOMM_PIPES;
160 }
161  
162 /*------------------------------------------------------------------------*/
163 /* retrieve options regarding file descriptors */
164 if (!retropt_int(popts, OPT_LEFTFD, &fdi)) {
165 fdo = fdi;
166 }
167  
168 if (retropt_int(popts, OPT_LEFTINFD, (unsigned short *)&fdi) >= 0) {
169 if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
170 Error("_xioopen_progcall(): option fdin is useless in read-only mode");
171 }
172 }
173 if (retropt_int(popts, OPT_LEFTOUTFD, (unsigned short *)&fdo) >= 0) {
174 if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
175 Error("_xioopen_progcall(): option fdout is useless in write-only mode");
176 }
177 }
178  
179 if (!retropt_int(popts, OPT_RIGHTFD, &rightin)) {
180 rightout = rightin;
181 }
182 retropt_int(popts, OPT_RIGHTINFD, &rightin);
183 retropt_int(popts, OPT_RIGHTOUTFD, &rightout);
184 /* when the superordinate communication type provides two distinct fds we
185 cannot pass just one fd to the program */
186 if (rw == XIO_RDWR && rightin==rightout) {
187 struct stat rstat, wstat;
188 if (Fstat(xfd->rfd, &rstat) < 0)
189 Error2("fstat(%d, ...): %s", xfd->rfd, strerror(errno));
190 if (Fstat(xfd->wfd, &wstat) < 0)
191 Error2("fstat(%d, ...): %s", xfd->wfd, strerror(errno));
192 if (memcmp(&rstat, &wstat, sizeof(rstat))) {
193 Error("exec/system: your rightfd options require the same FD for both directions but the communication environment provides two different FDs");
194 }
195 }
196  
197 /*------------------------------------------------------------------------*/
198 if (rw == XIO_WRONLY) {
199 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
200 fd->howtoclose = XIOCLOSE_SLEEP_SIGTERM;
201 }
202 }
203 if (withfork) {
204 const char *typename;
205 if (!(xioflags&XIO_MAYCHILD)) {
206 Error("fork for exec not allowed in this context");
207 /*!! free something */
208 return -1;
209 }
210 fd->flags |= XIO_DOESCHILD;
211  
212 switch (commtype) {
213 case XIOCOMM_PIPES: typename = "pipes"; break;
214 #if HAVE_PTY
215 case XIOCOMM_PTY: typename = "pty"; break;
216 case XIOCOMM_PTYS: typename = "two pty's"; break;
217 #endif /* HAVE_PTY */
218 case XIOCOMM_SOCKETPAIR: typename = "socketpair"; break;
219 case XIOCOMM_SOCKETPAIRS: typename = "two socketpairs"; break;
220 #if _WITH_TCP
221 case XIOCOMM_TCP: typename = "TCP socket pair"; break;
222 case XIOCOMM_TCP4: typename = "TCP4 socket pair"; break;
223 case XIOCOMM_TCP4_LISTEN: typename = "TCP4 listen socket pair"; break;
224 #endif
225 default: typename = NULL; break;
226 }
227 Notice2("forking off child, using %s for %s",
228 typename, ddirection[rw]);
229 }
230 applyopts(-1, popts, PH_PREBIGEN);
231  
232 if (inter) {
233 saverfd = xfd->rfd;
234 savewfd = xfd->wfd;
235 xfd->howtoshut = XIOSHUT_UNSPEC;
236 xfd->howtoclose = XIOCLOSE_UNSPEC;
237 }
238  
239 if (!withfork) {
240 /*0 struct single *stream1, *stream2;*/
241  
242 free(*copts);
243 *copts = moveopts(popts, GROUP_ALL);
244 /* what if WE are sock1 ? */
245 #if 1
246 if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) {
247 Error("nofork option is not allowed here");
248 /*!! free something */
249 return -1;
250 }
251 fd->flags |= XIO_DOESEXEC;
252 #else /*!! */
253 if (sock1 == NULL) {
254 Fatal("nofork option must no be applied to first socat address");
255 }
256 #endif
257 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
258 fd->howtoclose = XIOCLOSE_CLOSE;
259 }
260  
261 #if 0 /*!! */
262 if (sock1->tag == XIO_TAG_DUAL) {
263 stream1 = &sock1->dual.stream[0]->stream;
264 stream2 = &sock1->dual.stream[1]->stream;
265 } else {
266 stream1 = &sock1->stream;
267 stream2 = &sock1->stream;
268 }
269 if (stream1->dtype == DATA_READLINE || stream2->dtype == DATA_READLINE ||
270 stream1->dtype == DATA_OPENSSL || stream2->dtype == DATA_OPENSSL
271 ) {
272 Error("with option nofork, openssl and readline in address1 do not work");
273 }
274 if (stream1->lineterm != LINETERM_RAW ||
275 stream2->lineterm != LINETERM_RAW ||
276 stream1->ignoreeof || stream2->ignoreeof) {
277 Warn("due to option nofork, address1 options for lineterm and igoreeof do not apply");
278 }
279 #endif
280  
281 /*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */
282 if (rw != XIO_WRONLY) {
283 if (XIO_GETRDFD(sock[0]/*!!!*/) == fdi) {
284 if (Fcntl_l(fdi, F_SETFD, 0) < 0) {
285 Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno));
286 }
287 if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
288 Error3("dup2(%d, %d): %s",
289 XIO_GETRDFD(sock[0]), fdi, strerror(errno));
290 }
291 /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
292 } else {
293 if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
294 Error3("dup2(%d, %d): %s",
295 XIO_GETRDFD(sock[0]), fdi, strerror(errno));
296 }
297 /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
298 }
299 }
300 if (rw != XIO_RDONLY) {
301 if (XIO_GETWRFD(sock[0]) == fdo) {
302 if (Fcntl_l(fdo, F_SETFD, 0) < 0) {
303 Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno));
304 }
305 if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
306 Error3("dup2(%d, %d): %s)",
307 XIO_GETWRFD(sock[0]), fdo, strerror(errno));
308 }
309 /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
310 } else {
311 if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
312 Error3("dup2(%d, %d): %s)",
313 XIO_GETWRFD(sock[0]), fdo, strerror(errno));
314 }
315 /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
316 }
317 }
318 } else /* withfork */
319 /* create fd pair(s), set related xfd parameters, and apply options */
320 switch (commtype) {
321  
322 #if HAVE_PTY
323 case XIOCOMM_PTY:
324 /*!indent*/
325 #if defined(HAVE_DEV_PTMX)
326 # define PTMX "/dev/ptmx" /* Linux */
327 #elif HAVE_DEV_PTC
328 # define PTMX "/dev/ptc" /* AIX 4.3.3 */
329 #endif
330 fd->dtype = XIODATA_PTY;
331 #if 0
332 if (fd->howtoshut == XIOSHUT_UNSPEC) {
333 fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
334 }
335 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
336 fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
337 }
338 #endif
339  
340 if (xiopty(usebestpty||useptmx, &ttyfd, &ptyfd) < 0) {
341 return -1;
342 }
343  
344 free(*copts);
345 if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
346 return -1;
347 }
348 applyopts_cloexec(ptyfd, popts);/*!*/
349  
350 /* exec:...,pty did not kill child process under some circumstances */
351 if (fd->howtoshut == XIOSHUT_UNSPEC) {
352 fd->howtoshut = XIOSHUTRD_SIGTERM|XIOSHUTWR_SIGHUP;
353 }
354 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
355 fd->howtoclose = XIOCLOSE_CLOSE_SIGTERM;
356 }
357  
358 /* this for parent, was after fork */
359 applyopts(ptyfd, popts, PH_FD);
360 applyopts(ptyfd, popts, PH_LATE);
361 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
362  
363 if (XIOWITHRD(rw)) fd->rfd = ptyfd;
364 if (XIOWITHWR(rw)) fd->wfd = ptyfd;
365  
366 /* this for child, was after fork */
367 applyopts(ttyfd, *copts, PH_FD);
368  
369 break;
370 #endif /* HAVE_PTY */
371  
372 case XIOCOMM_PIPES: {
373 /*!indent*/
374 struct opt *popts2, *copts2;
375  
376 if (rw == XIO_RDWR) {
377 fd->dtype = XIODATA_2PIPE;
378 }
379 if (fd->howtoshut == XIOSHUT_UNSPEC || fd->howtoshut == XIOSHUT_DOWN) {
380 fd->howtoshut = XIOSHUT_CLOSE;
381 }
382 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
383 fd->howtoclose = XIOCLOSE_CLOSE;
384 }
385  
386 if (rw != XIO_WRONLY) {
387 if (Pipe(rdpip) < 0) {
388 Error2("pipe(%p): %s", rdpip, strerror(errno));
389 return -1;
390 }
391 }
392 /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
393 /* rdpip[0]: read by socat; rdpip[1]: write by child */
394 free(*copts);
395 if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS))
396 == NULL) {
397 return -1;
398 }
399  
400 popts2 = copyopts(popts, GROUP_ALL);
401 copts2 = copyopts(*copts, GROUP_ALL);
402  
403 if (rw != XIO_WRONLY) {
404 applyopts_cloexec(rdpip[0], popts);
405 applyopts(rdpip[0], popts, PH_FD);
406 applyopts(rdpip[1], *copts, PH_FD);
407 }
408  
409 if (rw != XIO_RDONLY) {
410 if (Pipe(wrpip) < 0) {
411 Error2("pipe(%p): %s", wrpip, strerror(errno));
412 return -1;
413 }
414 }
415 /*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
416  
417 /* wrpip[1]: write by socat; wrpip[0]: read by child */
418 if (rw != XIO_RDONLY) {
419 applyopts_cloexec(wrpip[1], popts2);
420 applyopts(wrpip[1], popts2, PH_FD);
421 applyopts(wrpip[0], copts2, PH_FD);
422 }
423  
424 /* this for parent, was after fork */
425 if (XIOWITHRD(rw)) fd->rfd = rdpip[0];
426 if (XIOWITHWR(rw)) fd->wfd = wrpip[1];
427 applyopts(fd->rfd, popts, PH_FD);
428 applyopts(fd->rfd, popts, PH_LATE);
429 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
430 break;
431 }
432  
433 case XIOCOMM_SOCKETPAIR: {
434 /*!indent*/
435 int pf = AF_UNIX;
436 retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf);
437 result = xiosocketpair(popts, pf, SOCK_STREAM, 0, sv);
438 if (result < 0) {
439 return -1;
440 }
441  
442 if (xfd->howtoshut == XIOSHUT_UNSPEC) {
443 xfd->howtoshut = XIOSHUT_DOWN;
444 }
445 if (xfd->howtoclose == XIOCLOSE_UNSPEC) {
446 xfd->howtoclose = XIOCLOSE_CLOSE;
447 }
448  
449 /*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
450 d, type, protocol, sv[0], sv[1]);*/
451 free(*copts);
452 if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
453 return -1;
454 }
455 applyopts(sv[0], *copts, PH_PASTSOCKET);
456 applyopts(sv[1], popts, PH_PASTSOCKET);
457  
458 applyopts_cloexec(sv[0], *copts);
459 applyopts(sv[0], *copts, PH_FD);
460 applyopts(sv[1], popts, PH_FD);
461  
462 applyopts(sv[0], *copts, PH_PREBIND);
463 applyopts(sv[0], *copts, PH_BIND);
464 applyopts(sv[0], *copts, PH_PASTBIND);
465 applyopts(sv[1], popts, PH_PREBIND);
466 applyopts(sv[1], popts, PH_BIND);
467 applyopts(sv[1], popts, PH_PASTBIND);
468  
469 Warn1("xio-progcall.c: fd->howtoshut == %d", fd->howtoshut);
470 if (inter || fd->howtoshut == XIOSHUT_UNSPEC) {
471 fd->howtoshut = XIOSHUT_DOWN;
472 }
473 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
474 fd->howtoclose = XIOCLOSE_SIGTERM;
475 }
476  
477 /* this for parent, was after fork */
478 /*!!!*/ Warn2("2: fd->rfd==%d, fd->wfd==%d", fd->rfd, fd->wfd);
479 if (XIOWITHRD(rw)) fd->rfd = sv[0];
480 if (XIOWITHWR(rw)) fd->wfd = sv[0];
481 /*!!!*/ Warn2("3: fd->rfd==%d, fd->wfd==%d", fd->rfd, fd->wfd);
482 applyopts(fd->rfd, popts, PH_FD);
483 applyopts(fd->rfd, popts, PH_LATE);
484 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
485 }
486 break;
487  
488 case XIOCOMM_TCP:
489 case XIOCOMM_TCP4: {
490 /*!indent*/
491 int pf = AF_INET;
492 xiofd_t socatfd, execfd;
493 retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf);
494 if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
495 0, &socatfd, &execfd) < 0) {
496 return -1;
497 }
498 free(*copts);
499 if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
500 return -1;
501 }
502 sv[0] = socatfd.rfd; /*!!! r/w */
503 sv[1] = execfd.wfd;
504 applyopts(socatfd.rfd, *copts, PH_PASTSOCKET);
505 applyopts(execfd.rfd, popts, PH_PASTSOCKET);
506  
507 applyopts_cloexec(sv[0], *copts);
508 applyopts(sv[0], *copts, PH_FD);
509 applyopts(sv[1], popts, PH_FD);
510  
511 applyopts(sv[0], *copts, PH_PREBIND);
512 applyopts(sv[0], *copts, PH_BIND);
513 applyopts(sv[0], *copts, PH_PASTBIND);
514 applyopts(sv[1], popts, PH_PREBIND);
515 applyopts(sv[1], popts, PH_BIND);
516 applyopts(sv[1], popts, PH_PASTBIND);
517  
518 Warn1("xio-progcall.c: fd->howtoshut == %d", fd->howtoshut);
519 if (inter || fd->howtoshut == XIOSHUT_UNSPEC) {
520 fd->howtoshut = XIOSHUT_DOWN;
521 }
522 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
523 fd->howtoclose = XIOCLOSE_SIGTERM;
524 }
525  
526 /* this for parent, was after fork */
527 if (XIOWITHRD(rw)) fd->rfd = sv[0];
528 if (XIOWITHWR(rw)) fd->wfd = sv[0];
529 applyopts(fd->rfd, popts, PH_FD);
530 applyopts(fd->rfd, popts, PH_LATE);
531 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
532 }
533 break;
534  
535 #if LATER
536 case XIOCOMM_TCP4_LISTEN: {
537 /*!indent*/
538 int pf = AF_INET;
539 xiofd_t socatfd, execfd;
540 retropt_int(popts, OPT_PROTOCOL_FAMILY, &pf);
541 if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
542 0, &socatfd, &execfd) < 0) {
543 return -1;
544 }
545  
546 free(*copts);
547 if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
548 return -1;
549 }
550 applyopts_cloexec(ptyfd, popts);/*!*/
551 }
552 break;
553 #endif /* LATER */
554  
555 case XIOCOMM_SOCKETPAIRS:
556 case XIOCOMM_PTYS: {
557 xiofd_t socatfd, execfd;
558 struct termios andmask, ormask;
559 switch (commtype) {
560 case XIOCOMM_SOCKETPAIRS:
561 if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
562 0, &socatfd, &execfd, PF_UNIX, SOCK_STREAM, 0) < 0)
563 return -1;
564 break;
565 case XIOCOMM_PTYS:
566 if (xiocommpair(commtype, XIOWITHWR(rw), XIOWITHRD(rw),
567 0, &socatfd, &execfd, &andmask, &ormask) < 0)
568 return -1;
569 break;
570 }
571  
572 free(*copts);
573 if ((*copts = copyopts(popts, GROUP_TERMIOS|GROUP_FORK)) == NULL) {
574 return -1;
575 }
576 if (socatfd.rfd >= 0) {
577 applyopts_cloexec(socatfd.rfd, *copts);/*!*/
578 applyopts(socatfd.rfd, *copts, PH_FD);
579 applyopts(socatfd.rfd, *copts, PH_LATE);
580 }
581 if (applyopts_single(xfd, *copts, PH_LATE) < 0) return -1;
582  
583 free(*copts);
584 if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
585 return -1;
586 }
587 if (socatfd.wfd >= 0) {
588 applyopts_cloexec(socatfd.wfd, *copts);/*!*/
589 applyopts(socatfd.wfd, *copts, PH_FD);
590 applyopts(socatfd.wfd, *copts, PH_LATE);
591 }
592 if (applyopts_single(xfd, *copts, PH_LATE) < 0) return -1;
593  
594 if (XIOWITHRD(rw)) xfd->rfd = socatfd.rfd;
595 if (XIOWITHWR(rw)) xfd->wfd = socatfd.wfd;
596 xfd->dtype = socatfd.dtype;
597 if (xfd->howtoshut == XIOSHUT_UNSPEC)
598 xfd->howtoshut = socatfd.howtoshut;
599 if (fd->howtoclose == XIOCLOSE_UNSPEC) {
600 fd->howtoclose = XIOWITHRD(rw)?XIOCLOSE_CLOSE_SIGTERM:XIOCLOSE_SLEEP_SIGTERM;
601 }
602 wrpip[0] = execfd.rfd;
603 rdpip[1] = execfd.wfd;
604 rdpip[0] = socatfd.rfd;
605 wrpip[1] = socatfd.wfd;
606 }
607 break;
608  
609 default:
610 Error1("_xioopen_progcall() internal: commtype %d not handled",
611 commtype);
612 break;
613 }
614  
615 /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
616 return -1;*/
617 retropt_bool(*copts, OPT_STDERR, &withstderr);
618  
619 xiosetchilddied(); /* set SIGCHLD handler */
620  
621 xiosetchilddied(); /* set SIGCHLD handler */
622  
623 if (withfork) {
624 sigset_t set, oldset;
625  
626 sigemptyset(&set);
627 sigaddset(&set, SIGCHLD);
628 Sigprocmask(SIG_BLOCK, &set, &oldset); /* disable SIGCHLD */
629 pid = xio_fork(true, E_ERROR);
630 if (pid < 0) {
631 Sigprocmask(SIG_SETMASK, &oldset, NULL);
632 Error1("fork(): %s", strerror(errno));
633 return -1;
634 }
635  
636 if (pid > 0) {
637 /* for parent (this is our socat process) */
638 xiosigchld_register(pid, xiosigaction_child, fd);
639 Sigprocmask(SIG_SETMASK, &oldset, NULL); /* enable SIGCHLD */
640 }
641  
642 if (pid == 0) { /* child */
643 /* drop parents locks, reset FIPS... */
644 if (xio_forked_inchild() != 0) {
645 Exit(1);
646 }
647 Sigprocmask(SIG_SETMASK, &oldset, NULL); /* enable SIGCHLD */
648 }
649 }
650 if (!withfork || pid == 0) { /* child */
651 uid_t user;
652 gid_t group;
653  
654 if (withfork) {
655 /* The child should have default handling for SIGCHLD. */
656 /* In particular, it's not defined whether ignoring SIGCHLD is inheritable. */
657 if (Signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
658 Warn1("signal(SIGCHLD, SIG_DFL): %s", strerror(errno));
659 }
660  
661 /* dup2() the fds to desired values, close old fds, and apply late
662 options */
663 switch (commtype) {
664 #if HAVE_PTY
665 case XIOCOMM_PTY:
666 if (rw != XIO_RDONLY && fdi != ttyfd) {
667 if (Dup2(ttyfd, fdi) < 0) {
668 Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
669 return -1; }
670 /*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/
671 }
672 if (rw != XIO_WRONLY && fdo != ttyfd) {
673 if (Dup2(ttyfd, fdo) < 0) {
674 Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno));
675 return -1; }
676 /*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/
677 }
678 if ((rw == XIO_RDONLY || fdi != ttyfd) &&
679 (rw == XIO_WRONLY || fdo != ttyfd)) {
680 applyopts_cloexec(ttyfd, *copts);
681 }
682  
683 applyopts(ttyfd, *copts, PH_LATE);
684 applyopts(ttyfd, *copts, PH_LATE2);
685 break;
686 #endif /* HAVE_PTY */
687  
688 case XIOCOMM_PIPES:
689 case XIOCOMM_SOCKETPAIRS:
690 case XIOCOMM_PTYS:
691 {
692 /*!indent*/
693 /* we might have a temporary conflict between what FDs are
694 currently allocated, and which are to be used. We try to find
695 a graceful solution via temporary descriptors */
696 int tmpi, tmpo;
697  
698 /* needed with system() (not with exec()) */
699 if (XIOWITHRD(rw)) Close(rdpip[0]);
700 if (XIOWITHWR(rw)) Close(wrpip[1]);
701 #if 0
702 /*! might not be needed */
703 if (XIOWITHRD(rw)) Close(rdpip[0]);
704 if (XIOWITHWR(rw)) Close(wrpip[1]);
705  
706 if (fdi == rdpip[1]) { /* a conflict here */
707 if ((tmpi = Dup(wrpip[0])) < 0) {
708 Error2("dup(%d): %s", wrpip[0], strerror(errno));
709 return -1;
710 }
711 /*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/
712 rdpip[1] = tmpi;
713 }
714 if (fdo == wrpip[0]) { /* a conflict here */
715 if ((tmpo = Dup(rdpip[1])) < 0) {
716 Error2("dup(%d): %s", rdpip[1], strerror(errno));
717 return -1;
718 }
719 /*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/
720 wrpip[0] = tmpo;
721 }
722  
723 if (rw != XIO_WRONLY && rdpip[1] != fdo) {
724 if (Dup2(rdpip[1], fdo) < 0) {
725 Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno));
726 return -1;
727 }
728 Close(rdpip[1]);
729 /*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/
730 /*0 applyopts_cloexec(fdo, *copts);*/
731 }
732 if (rw != XIO_RDONLY && wrpip[0] != fdi) {
733 if (Dup2(wrpip[0], fdi) < 0) {
734 Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno));
735 return -1;
736 }
737 Close(wrpip[0]);
738 /*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/
739 /*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */
740 /* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */
741 }
742 #else
743 result = reassignfds(XIOWITHWR(rw)?wrpip[0]:-1,
744 XIOWITHRD(rw)?rdpip[1]:-1,
745 fdi, fdo);
746 if (result < 0) return result;
747 #endif
748 applyopts(fdi, *copts, PH_LATE);
749 applyopts(fdo, *copts, PH_LATE);
750 applyopts(fdi, *copts, PH_LATE2);
751 applyopts(fdo, *copts, PH_LATE2);
752 break;
753 }
754 case XIOCOMM_SOCKETPAIR:
755 case XIOCOMM_TCP:
756 case XIOCOMM_TCP4:
757 case XIOCOMM_TCP4_LISTEN:
758 /*!indent*/
759 if (rw != XIO_RDONLY && fdi != sv[1]) {
760 if (Dup2(sv[1], fdi) < 0) {
761 Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
762 return -1; }
763 /*0 Info2("dup2(%d, %d)", sv[1], fdi);*/
764 }
765 if (rw != XIO_WRONLY && fdo != sv[1]) {
766 if (Dup2(sv[1], fdo) < 0) {
767 Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno));
768 return -1; }
769 /*0 Info2("dup2(%d, %d)", sv[1], fdo);*/
770 }
771 if (fdi != sv[1] && fdo != sv[1]) {
772 applyopts_cloexec(sv[1], *copts);
773 Close(sv[1]);
774 }
775  
776 applyopts(fdi, *copts, PH_LATE);
777 applyopts(fdi, *copts, PH_LATE2);
778 Close(sv[1]);
779 break;
780  
781 default:
782 Error1("_xioopen_progcall() internal: commtype %d not handled",
783 commtype);
784 break;
785  
786 }
787  
788 /* in case of an inter address, assign the right side FDs (e.g. 3 and 4) */
789 if (inter) {
790 Info2("preparing the right side FDs %d and %d for exec process",
791 rightin, rightout);
792 result = reassignfds(XIOWITHRD(rw)?saverfd:-1,
793 XIOWITHWR(rw)?savewfd:-1,
794 rightin, form==2?rightout:STDOUT_FILENO);
795 if (result < 0) return result;
796 if (form == 2) {
797 Fcntl_l(rightin, F_SETFD, 0);
798 Fcntl_l(rightout, F_SETFD, 0);
799 }
800 }
801  
802 } /* withfork */
803 else /* !withfork */ {
804 applyopts(-1, *copts, PH_LATE);
805 applyopts(-1, *copts, PH_LATE2);
806 }
807 _xioopen_setdelayeduser();
808 /* set group before user - maybe you are not permitted afterwards */
809 if (retropt_gidt(*copts, OPT_SETGID, &group) >= 0) {
810 Setgid(group);
811 }
812 if (retropt_uidt(*copts, OPT_SETUID, &user) >= 0) {
813 Setuid(user);
814 }
815 if (withstderr) {
816 *duptostderr = fdo;
817 } else {
818 *duptostderr = -1;
819 }
820  
821 return 0; /* indicate child process */
822 }
823  
824 /* for parent (this is our socat process) */
825 Notice1("forked off child process "F_pid, pid);
826  
827 #if 0
828 if ((popts = copyopts(*copts,
829 GROUP_FD|GROUP_TERMIOS|GROUP_FORK|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_FIFO)) == NULL)
830 return STAT_RETRYLATER;
831 #endif
832  
833 /* in parent: close fds that are only needed in child */
834 switch (commtype) {
835 #if HAVE_PTY
836 case XIOCOMM_PTY:
837 if (Close(ttyfd) < 0) {
838 Info2("close(%d): %s", ttyfd, strerror(errno));
839 }
840 break;
841 #endif /* HAVE_PTY */
842 case XIOCOMM_SOCKETPAIR:
843 case XIOCOMM_TCP:
844 case XIOCOMM_TCP4:
845 case XIOCOMM_TCP4_LISTEN:
846 Close(sv[1]);
847 break;
848 case XIOCOMM_PIPES:
849 default:
850 if (XIOWITHWR(rw)) Close(wrpip[0]);
851 if (XIOWITHRD(rw)) Close(rdpip[1]);
852 break;
853 }
854  
855 fd->child.pid = pid;
856  
857 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
858 applyopts_signal(fd, popts);
859 if ((numleft = leftopts(popts)) > 0) {
860 Error1("%d option(s) could not be used", numleft);
861 showleft(popts);
862 return STAT_NORETRY;
863 }
864  
865 if (inter) {
866 if (XIOWITHRD(rw)) Close(saverfd);
867 if (XIOWITHWR(rw)) Close(savewfd);
868 }
869  
870 return pid; /* indicate parent (main) process */
871 }
872  
873 #endif /* WITH_EXEC || WITH_SYSTEM */
874  
875  
876 int setopt_path(struct opt *opts, char **path) {
877 if (retropt_string(opts, OPT_PATH, path) >= 0) {
878 if (setenv("PATH", *path, 1) < 0) {
879 Error1("setenv(\"PATH\", \"%s\", 1): insufficient space", *path);
880 return -1;
881 }
882 }
883 return 0;
884 }
885  
886  
887 /* like dup(), but prints error on failure */
888 static int xiodup(int oldfd) {
889 int result;
890 if ((result = Dup(oldfd)) >= 0) return result;
891 Error2("dup2(%d): %s", oldfd, strerror(errno));
892 return result;
893 }
894  
895 /* like dup2(), but prints error on failure and returns 0 on success */
896 static int xiodup2(int oldfd, int newfd) {
897 int result;
898 if ((result = Dup2(oldfd, newfd)) >= 0) return 0;
899 Error3("dup2(%d, %d): %s", oldfd, newfd, strerror(errno));
900 return result;
901 }
902  
903 /* move the filedescriptors from the old handles to the new handles.
904 old -1 handles are ignored, new -1 handles are not closed.
905 returns 0 on success, -1 if a dup error occurred, or 1 on a close error
906 */
907 static int reassignfds(int oldfd1, int oldfd2, int newfd1, int newfd2) {
908 int tmpfd;
909 int result;
910  
911 Debug4("reassignfds(%d, %d, %d, %d)", oldfd1, oldfd2, newfd1, newfd2);
912 if (oldfd1 == newfd1) {
913 Fcntl_l(newfd1, F_SETFD, 0);
914 oldfd1 = -1;
915 }
916 if (oldfd2 == newfd2) {
917 Fcntl_l(newfd2, F_SETFD, 0);
918 oldfd2 = -1;
919 }
920  
921 if (oldfd1 < 0 && oldfd2 < 0) return 0;
922  
923 if (oldfd2 < 0) {
924 if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
925 if (newfd2 != oldfd1) if (Close(oldfd1) < 0) return 1;
926 return 0;
927 }
928  
929 if (oldfd1 < 0) {
930 if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
931 if (oldfd2 >= 0) if (Close(oldfd2) < 0) return 1;
932 return 0;
933 }
934  
935 if (oldfd2 == newfd1) {
936 if (oldfd1 == newfd2) {
937 /* exchange them */
938 if ((tmpfd = xiodup(oldfd2)) < 0) return tmpfd;
939 if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
940 if ((result = xiodup2(tmpfd, newfd2)) < 0) return result;
941 if (Close(tmpfd) < 0) return 1;
942 } else {
943 if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
944 if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
945 if (Close(oldfd1) < 0) return 1;
946 }
947 } else {
948 if (oldfd1 == newfd2) {
949 if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
950 if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
951 if (Close(oldfd2) < 0) return 1;
952 } else {
953 if ((result = xiodup2(oldfd1, newfd1)) < 0) return result;
954 if ((result = xiodup2(oldfd2, newfd2)) < 0) return result;
955 if (Close(oldfd1) < 0 || Close(oldfd2) < 0) return 1;
956 }
957 }
958 return 0;
959 }