1 /* source: xio-progcall.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
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
10 #include "xio-process.h"
11 #include "xio-progcall.h"
12
13 #include "xio-socket.h"
14
15
16 /* these options are used by address pty too */
17 #if HAVE_OPENPTY
18 const struct optdesc opt_openpty = { "openpty", NULL, OPT_OPENPTY, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
19 #endif /* HAVE_OPENPTY */
20 #if HAVE_DEV_PTMX || HAVE_DEV_PTC
21 const struct optdesc opt_ptmx = { "ptmx", NULL, OPT_PTMX, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
22 #endif
23
24 #if WITH_EXEC || WITH_SYSTEM
25
26 #define MAXPTYNAMELEN 64
27
28 const struct optdesc opt_fdin = { "fdin", NULL, OPT_FDIN, GROUP_FORK, PH_PASTBIGEN, TYPE_USHORT, OFUNC_SPEC };
29 const struct optdesc opt_fdout = { "fdout", NULL, OPT_FDOUT, GROUP_FORK, PH_PASTBIGEN, TYPE_USHORT, OFUNC_SPEC };
30 const struct optdesc opt_path = { "path", NULL, OPT_PATH, GROUP_EXEC, PH_PREEXEC, TYPE_STRING, OFUNC_SPEC };
31 const struct optdesc opt_pipes = { "pipes", NULL, OPT_PIPES, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
32 #if HAVE_PTY
33 const struct optdesc opt_pty = { "pty", NULL, OPT_PTY, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
34 #endif
35 const struct optdesc opt_stderr = { "stderr", NULL, OPT_STDERR, GROUP_FORK, PH_PASTFORK, TYPE_BOOL, OFUNC_SPEC };
36 const struct optdesc opt_nofork = { "nofork", NULL, OPT_NOFORK, GROUP_FORK, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
37 const struct optdesc opt_sighup = { "sighup", NULL, OPT_SIGHUP, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGHUP };
38 const struct optdesc opt_sigint = { "sigint", NULL, OPT_SIGINT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGINT };
39 const struct optdesc opt_sigquit = { "sigquit", NULL, OPT_SIGQUIT, GROUP_PARENT, PH_LATE, TYPE_CONST, OFUNC_SIGNAL, SIGQUIT };
40
41
42 /* fork for exec/system, but return before exec'ing.
43 return=0: is child process
44 return>0: is parent process
45 return<0: error occurred, assume parent process and no child exists !!!
46 */
_xioopen_foxec(int xioflags,struct single * fd,unsigned groups,struct opt ** copts,int * duptostderr)47 int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
48 struct single *fd,
49 unsigned groups,
50 struct opt **copts, /* in: opts; out: opts for child */
51 int *duptostderr /* out: redirect stderr to output fd */
52 ) {
53 struct opt *popts; /* parent process options */
54 int numleft;
55 int d, sv[2], rdpip[2], wrpip[2];
56 int rw = (xioflags & XIO_ACCMODE);
57 bool usepipes = false;
58 #if HAVE_PTY
59 int ptyfd = -1, ttyfd = -1;
60 bool usebestpty = false; /* use the best available way to open pty */
61 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
62 bool useptmx = false; /* use /dev/ptmx or equivalent */
63 #endif
64 #if HAVE_OPENPTY
65 bool useopenpty = false; /* try only openpty */
66 #endif /* HAVE_OPENPTY */
67 bool usepty = false; /* any of the pty options is selected */
68 char ptyname[MAXPTYNAMELEN];
69 #endif /* HAVE_PTY */
70 pid_t pid = 0; /* mostly int */
71 short fdi = 0, fdo = 1;
72 short result;
73 bool withstderr = false;
74 bool nofork = false;
75 bool withfork;
76
77 popts = moveopts(*copts, GROUP_ALL);
78 if (applyopts_single(fd, popts, PH_INIT) < 0) return -1;
79 applyopts2(-1, popts, PH_INIT, PH_EARLY);
80
81 retropt_bool(popts, OPT_NOFORK, &nofork);
82 withfork = !nofork;
83
84 retropt_bool(popts, OPT_PIPES, &usepipes);
85 #if HAVE_PTY
86 retropt_bool(popts, OPT_PTY, &usebestpty);
87 #if HAVE_OPENPTY
88 retropt_bool(popts, OPT_OPENPTY, &useopenpty);
89 #endif
90 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
91 retropt_bool(popts, OPT_PTMX, &useptmx);
92 #endif
93 usepty = (usebestpty
94 #if HAVE_OPENPTY
95 || useopenpty
96 #endif
97 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
98 || useptmx
99 #endif
100 );
101 if (usepipes && usepty) {
102 Warn("_xioopen_foxec(): options \"pipes\" and \"pty\" must not be specified together; ignoring \"pipes\"");
103 usepipes = false;
104 }
105 #endif /* HAVE_PTY */
106
107 if (retropt_ushort(popts, OPT_FDIN, (unsigned short *)&fdi) >= 0) {
108 if ((xioflags&XIO_ACCMODE) == XIO_RDONLY) {
109 Error("_xioopen_foxec(): option fdin is useless in read-only mode");
110 }
111 }
112 if (retropt_ushort(popts, OPT_FDOUT, (unsigned short *)&fdo) >= 0) {
113 if ((xioflags&XIO_ACCMODE) == XIO_WRONLY) {
114 Error("_xioopen_foxec(): option fdout is useless in write-only mode");
115 }
116 }
117
118 if (withfork) {
119 if (!(xioflags&XIO_MAYCHILD)) {
120 Error("cannot fork off child process here");
121 /*!! free something */
122 return -1;
123 }
124 fd->flags |= XIO_DOESCHILD;
125
126 #if HAVE_PTY
127 Notice2("forking off child, using %s for %s",
128 &("socket\0\0pipes\0\0\0pty\0\0\0\0\0"[(usepipes<<3)|(usepty<<4)]),
129 ddirection[rw]);
130 #else
131 Notice2("forking off child, using %s for %s",
132 &("socket\0\0pipes\0\0\0"[(usepipes<<3)]),
133 ddirection[rw]);
134 #endif /* HAVE_PTY */
135 }
136 applyopts(-1, popts, PH_PREBIGEN);
137
138 if (!withfork) {
139 /*0 struct single *stream1, *stream2;*/
140
141 if (!(xioflags & XIO_MAYEXEC /* means exec+nofork */)) {
142 Error("option nofork is not allowed here");
143 /*!! free something */
144 return -1;
145 }
146 fd->flags |= XIO_DOESEXEC;
147
148 free(*copts);
149 *copts = moveopts(popts, GROUP_ALL);
150
151 #if 0 /*!! */
152 if (sock1->tag == XIO_TAG_DUAL) {
153 stream1 = &sock1->dual.stream[0]->stream;
154 stream2 = &sock1->dual.stream[1]->stream;
155 } else {
156 stream1 = &sock1->stream;
157 stream2 = &sock1->stream;
158 }
159 if (stream1->dtype == DATA_READLINE || stream2->dtype == DATA_READLINE ||
160 stream1->dtype == DATA_OPENSSL || stream2->dtype == DATA_OPENSSL
161 ) {
162 Error("with option nofork, openssl and readline in address1 do not work");
163 }
164 if (stream1->lineterm != LINETERM_RAW ||
165 stream2->lineterm != LINETERM_RAW ||
166 stream1->ignoreeof || stream2->ignoreeof) {
167 Warn("due to option nofork, address1 options for lineterm and igoreeof do not apply");
168 }
169 #endif
170
171 /* remember: fdin is the fd where the sub program reads from, thus it is
172 sock0[]'s read fd */
173 /*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */
174 if (rw != XIO_WRONLY) {
175 if (XIO_GETWRFD(sock[0]/*!!*/) == fdo) {
176 if (Fcntl_l(fdo, F_SETFD, 0) < 0) {
177 Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno));
178 }
179 } else {
180 /* make sure that the internal diagnostic socket pair fds do not conflict
181 with our choices */
182 diag_reserve_fd(fdo);
183 if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) {
184 Error3("dup2(%d, %d): %s",
185 XIO_GETWRFD(sock[0]), fdo, strerror(errno));
186 }
187 }
188 /*0 Info2("dup2(%d, %d)", XIO_GETRDFD(sock[0]), fdi);*/
189 }
190 if (rw != XIO_RDONLY) {
191 if (XIO_GETRDFD(sock[0]) == fdi) {
192 if (Fcntl_l(fdi, F_SETFD, 0) < 0) {
193 Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno));
194 }
195 } else {
196 /* make sure that the internal diagnostic socket pair fds do not conflict
197 with our choices */
198 diag_reserve_fd(fdi);
199 if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) {
200 Error3("dup2(%d, %d): %s)",
201 XIO_GETRDFD(sock[0]), fdi, strerror(errno));
202 }
203 /*0 Info2("dup2(%d, %d)", XIO_GETWRFD(sock[0]), fdo);*/
204 }
205 }
206 } else
207 #if HAVE_PTY
208 if (usepty) {
209
210 #if defined(HAVE_DEV_PTMX)
211 # define PTMX "/dev/ptmx" /* Linux */
212 #elif HAVE_DEV_PTC
213 # define PTMX "/dev/ptc" /* AIX 4.3.3 */
214 #endif
215 fd->dtype = XIODATA_PTY;
216 #if HAVE_DEV_PTMX || HAVE_DEV_PTC
217 if (usebestpty || useptmx) {
218 if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
219 Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
220 strerror(errno));
221 /*!*/
222 } else {
223 /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/
224 }
225 if (ptyfd >= 0 && ttyfd < 0) {
226 char *tn = NULL;
227 /* we used PTMX before forking */
228 extern char *ptsname(int);
229 #if HAVE_GRANTPT /* AIX, not Linux */
230 if (Grantpt(ptyfd)/*!*/ < 0) {
231 Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
232 }
233 #endif /* HAVE_GRANTPT */
234 #if HAVE_UNLOCKPT
235 if (Unlockpt(ptyfd)/*!*/ < 0) {
236 Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
237 }
238 #endif /* HAVE_UNLOCKPT */
239 #if HAVE_PROTOTYPE_LIB_ptsname /* AIX, not Linux */
240 if ((tn = Ptsname(ptyfd)) == NULL) {
241 Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
242 }
243 #endif /* HAVE_PROTOTYPE_LIB_ptsname */
244 if (tn == NULL) {
245 if ((tn = Ttyname(ptyfd)) == NULL) {
246 Error2("ttyname(%d): %s", ptyfd, strerror(errno));
247 }
248 }
249 ptyname[0] = '\0'; strncat(ptyname, tn, MAXPTYNAMELEN-1);
250 if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
251 Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
252 } else {
253 /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
254 }
255
256 #ifdef I_PUSH
257 /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
258 /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
259 /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
260 /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
261 if (Ioctl(ttyfd, I_FIND, "ldterm\0") == 0) {
262 Ioctl(ttyfd, I_PUSH, "ptem\0\0\0"); /* 0 */ /* padding for AdressSanitizer */
263 Ioctl(ttyfd, I_PUSH, "ldterm\0"); /* 0 */
264 Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
265 }
266 #endif
267
268 #if 0 /* the following block need not work */
269
270 if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) {
271 Warn2("ttyname(%d): %s", ttyfd, strerror(errno));
272 }
273 if (tn == NULL) {
274 Error("could not open pty");
275 return -1;
276 }
277 #endif
278 Info1("opened pseudo terminal %s", tn);
279 }
280 }
281 #endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
282 #if HAVE_OPENPTY
283 if (ptyfd < 0) {
284 int result;
285 if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
286 Error4("openpty(%p, %p, %p, NULL, NULL): %s",
287 &ptyfd, &ttyfd, ptyname, strerror(errno));
288 return -1;
289 }
290 }
291 #endif /* HAVE_OPENPTY */
292 free(*copts);
293 if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
294 return -1;
295 }
296 applyopts_cloexec(ptyfd, popts);/*!*/
297 /* exec:...,pty did not kill child process under some circumstances */
298 if (fd->howtoend == END_UNSPEC) {
299 fd->howtoend = END_CLOSE_KILL;
300 }
301
302 /* this for parent, was after fork */
303 applyopts(ptyfd, popts, PH_FD);
304 applyopts(ptyfd, popts, PH_LATE);
305 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
306
307 fd->fd = ptyfd;
308
309 /* this for child, was after fork */
310 applyopts(ttyfd, *copts, PH_FD);
311 } else
312 #endif /* HAVE_PTY */
313 if (usepipes) {
314 struct opt *popts2, *copts2;
315
316 if (rw == XIO_RDWR)
317 fd->dtype = XIODATA_2PIPE;
318 if (rw != XIO_WRONLY) {
319 if (Pipe(rdpip) < 0) {
320 Error2("pipe(%p): %s", rdpip, strerror(errno));
321 return -1;
322 }
323 }
324 /*0 Info2("pipe({%d,%d})", rdpip[0], rdpip[1]);*/
325 /* rdpip[0]: read by socat; rdpip[1]: write by child */
326 free(*copts);
327 if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS))
328 == NULL) {
329 return -1;
330 }
331
332 popts2 = copyopts(popts, GROUP_ALL);
333 copts2 = copyopts(*copts, GROUP_ALL);
334
335 if (rw != XIO_WRONLY) {
336 applyopts_cloexec(rdpip[0], popts);
337 applyopts(rdpip[0], popts, PH_FD);
338 applyopts(rdpip[1], *copts, PH_FD);
339 }
340
341 if (rw != XIO_RDONLY) {
342 if (Pipe(wrpip) < 0) {
343 Error2("pipe(%p): %s", wrpip, strerror(errno));
344 return -1;
345 }
346 }
347 /*0 Info2("pipe({%d,%d})", wrpip[0], wrpip[1]);*/
348
349 /* wrpip[1]: write by socat; wrpip[0]: read by child */
350 if (rw != XIO_RDONLY) {
351 applyopts_cloexec(wrpip[1], popts2);
352 applyopts(wrpip[1], popts2, PH_FD);
353 applyopts(wrpip[0], copts2, PH_FD);
354 }
355 if (fd->howtoend == END_UNSPEC) {
356 fd->howtoend = END_CLOSE_KILL;
357 }
358
359 /* this for parent, was after fork */
360 switch (rw) {
361 case XIO_RDONLY: fd->fd = rdpip[0]; break;
362 case XIO_WRONLY: fd->fd = wrpip[1]; break;
363 case XIO_RDWR: fd->fd = rdpip[0];
364 fd->para.exec.fdout = wrpip[1];
365 break;
366 }
367 applyopts(fd->fd, popts, PH_FD);
368 applyopts(fd->fd, popts, PH_LATE);
369 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
370 } else {
371 d = AF_UNIX;
372 retropt_int(popts, OPT_PROTOCOL_FAMILY, &d);
373 result = xiosocketpair(popts, d, SOCK_STREAM, 0, sv);
374 if (result < 0) {
375 return -1;
376 }
377 /*0 Info5("socketpair(%d, %d, %d, {%d,%d})",
378 d, type, protocol, sv[0], sv[1]);*/
379 free(*copts);
380 if ((*copts = moveopts(popts, GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
381 return -1;
382 }
383 applyopts(sv[0], *copts, PH_PASTSOCKET);
384 applyopts(sv[1], popts, PH_PASTSOCKET);
385
386 applyopts_cloexec(sv[0], *copts);
387 applyopts(sv[0], *copts, PH_FD);
388 applyopts(sv[1], popts, PH_FD);
389
390 applyopts(sv[0], *copts, PH_PREBIND);
391 applyopts(sv[0], *copts, PH_BIND);
392 applyopts(sv[0], *copts, PH_PASTBIND);
393 applyopts(sv[1], popts, PH_PREBIND);
394 applyopts(sv[1], popts, PH_BIND);
395 applyopts(sv[1], popts, PH_PASTBIND);
396
397 if (fd->howtoend == END_UNSPEC) {
398 fd->howtoend = END_SHUTDOWN_KILL;
399 }
400
401 /* this for parent, was after fork */
402 fd->fd = sv[0];
403 applyopts(fd->fd, popts, PH_FD);
404 applyopts(fd->fd, popts, PH_LATE);
405 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
406 }
407 /*0 if ((optpr = copyopts(*copts, GROUP_PROCESS)) == NULL)
408 return -1;*/
409 retropt_bool(*copts, OPT_STDERR, &withstderr);
410
411 xiosetchilddied(); /* set SIGCHLD handler */
412
413 if (withfork) {
414 pid = xio_fork(true, E_ERROR);
415 if (pid < 0) {
416 return -1;
417 }
418 }
419 if (!withfork || pid == 0) { /* child */
420 if (withfork) {
421 /* The child should have default handling for SIGCHLD. */
422 /* In particular, it's not defined whether ignoring SIGCHLD is inheritable. */
423 if (Signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
424 Warn1("signal(SIGCHLD, SIG_DFL): %s", strerror(errno));
425 }
426
427 #if HAVE_PTY
428 if (usepty) {
429 Close(ptyfd);
430 if (rw != XIO_RDONLY && fdi != ttyfd) {
431 /* make sure that the internal diagnostic socket pair fds do not conflict
432 with our choices */
433 diag_reserve_fd(fdi);
434 if (Dup2(ttyfd, fdi) < 0) {
435 Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno));
436 return -1; }
437 /*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/
438 }
439 if (rw != XIO_WRONLY && fdo != ttyfd) {
440 /* make sure that the internal diagnostic socket pair fds do not conflict
441 with our choices */
442 diag_reserve_fd(fdo);
443 if (Dup2(ttyfd, fdo) < 0) {
444 Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno));
445 return -1; }
446 /*0 Info2("dup2(%d, %d)", ttyfd, fdo);*/
447 }
448 if ((rw == XIO_RDONLY || fdi != ttyfd) &&
449 (rw == XIO_WRONLY || fdo != ttyfd)) {
450 applyopts_cloexec(ttyfd, *copts);
451 }
452
453 applyopts(ttyfd, *copts, PH_LATE);
454
455 applyopts(ttyfd, *copts, PH_LATE2);
456 } else
457 #endif /* HAVE_PTY */
458 if (usepipes) {
459 /* we might have a temporary conflict between what FDs are
460 currently allocated, and which are to be used. We try to find
461 a graceful solution via temporary descriptors */
462 int tmpi, tmpo;
463
464 if (rw != XIO_WRONLY) Close(rdpip[0]);
465 if (rw != XIO_RDONLY) Close(wrpip[1]);
466 if (fdi == rdpip[1]) { /* a conflict here */
467 if ((tmpi = Dup(wrpip[0])) < 0) {
468 Error2("dup(%d): %s", wrpip[0], strerror(errno));
469 return -1;
470 }
471 /*0 Info2("dup(%d) -> %d", wrpip[0], tmpi);*/
472 rdpip[1] = tmpi;
473 }
474 if (fdo == wrpip[0]) { /* a conflict here */
475 if ((tmpo = Dup(rdpip[1])) < 0) {
476 Error2("dup(%d): %s", rdpip[1], strerror(errno));
477 return -1;
478 }
479 /*0 Info2("dup(%d) -> %d", rdpip[1], tmpo);*/
480 wrpip[0] = tmpo;
481 }
482
483 if (rw != XIO_WRONLY && rdpip[1] != fdo) {
484 /* make sure that the internal diagnostic socket pair fds do not conflict
485 with our choices */
486 diag_reserve_fd(fdo);
487 if (Dup2(rdpip[1], fdo) < 0) {
488 Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno));
489 return -1;
490 }
491 Close(rdpip[1]);
492 /*0 Info2("dup2(%d, %d)", rdpip[1], fdo);*/
493 /*0 applyopts_cloexec(fdo, *copts);*/
494 }
495 if (rw != XIO_RDONLY && wrpip[0] != fdi) {
496 /* make sure that the internal diagnostic socket pair fds do not conflict
497 with our choices */
498 diag_reserve_fd(fdi);
499 if (Dup2(wrpip[0], fdi) < 0) {
500 Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno));
501 return -1;
502 }
503 Close(wrpip[0]);
504 /*0 Info2("dup2(%d, %d)", wrpip[0], fdi);*/
505 /*0 applyopts_cloexec(wrpip[0], *copts);*/ /* option is already consumed! */
506 /* applyopts_cloexec(fdi, *copts);*/ /* option is already consumed! */
507 }
508
509 applyopts(fdi, *copts, PH_LATE);
510 applyopts(fdo, *copts, PH_LATE);
511 applyopts(fdi, *copts, PH_LATE2);
512 applyopts(fdo, *copts, PH_LATE2);
513
514 } else { /* socketpair */
515 Close(sv[0]);
516 if (rw != XIO_RDONLY && fdi != sv[1]) {
517 /* make sure that the internal diagnostic socket pair fds do not conflict
518 with our choices */
519 diag_reserve_fd(fdi);
520 if (Dup2(sv[1], fdi) < 0) {
521 Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno));
522 return -1; }
523 /*0 Info2("dup2(%d, %d)", sv[1], fdi);*/
524 }
525 if (rw != XIO_WRONLY && fdo != sv[1]) {
526 /* make sure that the internal diagnostic socket pair fds do not conflict
527 with our choices */
528 diag_reserve_fd(fdo);
529 if (Dup2(sv[1], fdo) < 0) {
530 Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno));
531 return -1; }
532 /*0 Info2("dup2(%d, %d)", sv[1], fdo);*/
533 }
534 if (fdi != sv[1] && fdo != sv[1]) {
535 applyopts_cloexec(sv[1], *copts);
536 Close(sv[1]);
537 }
538
539 applyopts(fdi, *copts, PH_LATE);
540 applyopts(fdi, *copts, PH_LATE2);
541 }
542 } /* withfork */
543 else {
544 applyopts(-1, *copts, PH_LATE);
545 applyopts(-1, *copts, PH_LATE2);
546 }
547 _xioopen_setdelayeduser();
548 if (withstderr) {
549 *duptostderr = fdo;
550 } else {
551 *duptostderr = -1;
552 }
553
554 return 0; /* indicate child process */
555 }
556
557 /* for parent (this is our socat process) */
558 Notice1("forked off child process "F_pid, pid);
559
560 #if 0
561 if ((popts = copyopts(*copts,
562 GROUP_FD|GROUP_TERMIOS|GROUP_FORK|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_FIFO)) == NULL)
563 return STAT_RETRYLATER;
564 #endif
565
566 #if HAVE_PTY
567 if (usepty) {
568 if (Close(ttyfd) < 0) {
569 Info2("close(%d): %s", ttyfd, strerror(errno));
570 }
571 } else
572 #endif /* HAVE_PTY */
573 if (usepipes) {
574 if (rw == XIO_RDONLY) Close(rdpip[1]);
575 if (rw == XIO_WRONLY) Close(wrpip[0]);
576 } else {
577 Close(sv[1]);
578 }
579 fd->para.exec.pid = pid;
580
581 if (applyopts_single(fd, popts, PH_LATE) < 0) return -1;
582 applyopts_signal(fd, popts);
583 if ((numleft = leftopts(popts)) > 0) {
584 Error1("%d option(s) could not be used", numleft);
585 showleft(popts);
586 return STAT_NORETRY;
587 }
588
589 return pid; /* indicate parent (main) process */
590 }
591 #endif /* WITH_EXEC || WITH_SYSTEM */
592
593
setopt_path(struct opt * opts,char ** path)594 int setopt_path(struct opt *opts, char **path) {
595 if (retropt_string(opts, OPT_PATH, path) >= 0) {
596 if (setenv("PATH", *path, 1) < 0) {
597 Error1("setenv(\"PATH\", \"%s\", 1): insufficient space", *path);
598 return -1;
599 }
600 }
601 return 0;
602 }
603