15d9e6103SBrian Somers /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
45d9e6103SBrian Somers * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
55d9e6103SBrian Somers * All rights reserved.
65d9e6103SBrian Somers *
75d9e6103SBrian Somers * Redistribution and use in source and binary forms, with or without
85d9e6103SBrian Somers * modification, are permitted provided that the following conditions
95d9e6103SBrian Somers * are met:
105d9e6103SBrian Somers * 1. Redistributions of source code must retain the above copyright
115d9e6103SBrian Somers * notice, this list of conditions and the following disclaimer.
125d9e6103SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright
135d9e6103SBrian Somers * notice, this list of conditions and the following disclaimer in the
145d9e6103SBrian Somers * documentation and/or other materials provided with the distribution.
155d9e6103SBrian Somers *
165d9e6103SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
175d9e6103SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
185d9e6103SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
195d9e6103SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
205d9e6103SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
215d9e6103SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
225d9e6103SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
235d9e6103SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
245d9e6103SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
255d9e6103SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265d9e6103SBrian Somers * SUCH DAMAGE.
275d9e6103SBrian Somers */
285d9e6103SBrian Somers
295d9e6103SBrian Somers #include <sys/param.h>
305d9e6103SBrian Somers #include <sys/socket.h>
315d9e6103SBrian Somers #include <sys/un.h>
325d9e6103SBrian Somers
335d9e6103SBrian Somers #include <errno.h>
345d9e6103SBrian Somers #include <fcntl.h>
355d9e6103SBrian Somers #include <stdio.h>
365d9e6103SBrian Somers #include <stdlib.h>
375d9e6103SBrian Somers #include <string.h>
38887ff31fSBrian Somers #include <sysexits.h>
395d9e6103SBrian Somers #include <sys/wait.h>
40887ff31fSBrian Somers #include <sys/stat.h>
41f5a99677SBrian Somers #include <sys/uio.h>
425d9e6103SBrian Somers #include <termios.h>
435d9e6103SBrian Somers #include <unistd.h>
445d9e6103SBrian Somers
455d9e6103SBrian Somers #include "layer.h"
465d9e6103SBrian Somers #include "defs.h"
475d9e6103SBrian Somers #include "mbuf.h"
485d9e6103SBrian Somers #include "log.h"
495d9e6103SBrian Somers #include "timer.h"
505d9e6103SBrian Somers #include "lqr.h"
515d9e6103SBrian Somers #include "hdlc.h"
525d9e6103SBrian Somers #include "throughput.h"
535d9e6103SBrian Somers #include "fsm.h"
545d9e6103SBrian Somers #include "lcp.h"
555d9e6103SBrian Somers #include "ccp.h"
565d9e6103SBrian Somers #include "link.h"
575d9e6103SBrian Somers #include "async.h"
585d9e6103SBrian Somers #include "descriptor.h"
595d9e6103SBrian Somers #include "physical.h"
605d9e6103SBrian Somers #include "mp.h"
615d9e6103SBrian Somers #include "chat.h"
625d9e6103SBrian Somers #include "command.h"
635d9e6103SBrian Somers #include "auth.h"
645d9e6103SBrian Somers #include "chap.h"
655d9e6103SBrian Somers #include "cbcp.h"
665d9e6103SBrian Somers #include "datalink.h"
67e7d008b4SBrian Somers #include "id.h"
68887ff31fSBrian Somers #include "main.h"
695d9e6103SBrian Somers #include "exec.h"
705d9e6103SBrian Somers
71887ff31fSBrian Somers
72887ff31fSBrian Somers struct execdevice {
73887ff31fSBrian Somers struct device dev; /* What struct physical knows about */
74887ff31fSBrian Somers int fd_out; /* output descriptor */
75887ff31fSBrian Somers };
76887ff31fSBrian Somers
77887ff31fSBrian Somers #define device2exec(d) ((d)->type == EXEC_DEVICE ? (struct execdevice *)d : NULL)
78887ff31fSBrian Somers
79887ff31fSBrian Somers unsigned
exec_DeviceSize(void)80887ff31fSBrian Somers exec_DeviceSize(void)
81887ff31fSBrian Somers {
82887ff31fSBrian Somers return sizeof(struct execdevice);
83887ff31fSBrian Somers }
84887ff31fSBrian Somers
85887ff31fSBrian Somers static void
exec_Free(struct physical * p)86887ff31fSBrian Somers exec_Free(struct physical *p)
87887ff31fSBrian Somers {
88887ff31fSBrian Somers struct execdevice *dev = device2exec(p->handler);
89887ff31fSBrian Somers
90887ff31fSBrian Somers if (dev->fd_out != -1)
91887ff31fSBrian Somers close(dev->fd_out);
92887ff31fSBrian Somers free(dev);
93887ff31fSBrian Somers }
94887ff31fSBrian Somers
95887ff31fSBrian Somers static void
exec_device2iov(struct device * d,struct iovec * iov,int * niov,int maxiov __unused,int * auxfd,int * nauxfd)96887ff31fSBrian Somers exec_device2iov(struct device *d, struct iovec *iov, int *niov,
97887ff31fSBrian Somers int maxiov __unused, int *auxfd, int *nauxfd)
98887ff31fSBrian Somers {
99887ff31fSBrian Somers struct execdevice *dev;
100887ff31fSBrian Somers int sz = physical_MaxDeviceSize();
101887ff31fSBrian Somers
102887ff31fSBrian Somers iov[*niov].iov_base = d = realloc(d, sz);
103887ff31fSBrian Somers if (d == NULL) {
104887ff31fSBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
105887ff31fSBrian Somers AbortProgram(EX_OSERR);
106887ff31fSBrian Somers }
107887ff31fSBrian Somers iov[*niov].iov_len = sz;
108887ff31fSBrian Somers (*niov)++;
109887ff31fSBrian Somers
110887ff31fSBrian Somers dev = device2exec(d);
111887ff31fSBrian Somers if (dev->fd_out >= 0) {
112887ff31fSBrian Somers *auxfd = dev->fd_out;
113887ff31fSBrian Somers (*nauxfd)++;
114887ff31fSBrian Somers }
115887ff31fSBrian Somers }
116887ff31fSBrian Somers
117887ff31fSBrian Somers static int
exec_RemoveFromSet(struct physical * p,fd_set * r,fd_set * w,fd_set * e)118887ff31fSBrian Somers exec_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
119887ff31fSBrian Somers {
120887ff31fSBrian Somers struct execdevice *dev = device2exec(p->handler);
121887ff31fSBrian Somers int sets;
122887ff31fSBrian Somers
123887ff31fSBrian Somers p->handler->removefromset = NULL;
124887ff31fSBrian Somers sets = physical_RemoveFromSet(p, r, w, e);
125887ff31fSBrian Somers p->handler->removefromset = exec_RemoveFromSet;
126887ff31fSBrian Somers
127887ff31fSBrian Somers if (dev->fd_out >= 0) {
128887ff31fSBrian Somers if (w && FD_ISSET(dev->fd_out, w)) {
129887ff31fSBrian Somers FD_CLR(dev->fd_out, w);
130887ff31fSBrian Somers log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, dev->fd_out);
131887ff31fSBrian Somers sets++;
132887ff31fSBrian Somers }
133887ff31fSBrian Somers if (e && FD_ISSET(dev->fd_out, e)) {
134887ff31fSBrian Somers FD_CLR(dev->fd_out, e);
135887ff31fSBrian Somers log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, dev->fd_out);
136887ff31fSBrian Somers sets++;
137887ff31fSBrian Somers }
138887ff31fSBrian Somers }
139887ff31fSBrian Somers
140887ff31fSBrian Somers return sets;
141887ff31fSBrian Somers }
142887ff31fSBrian Somers
143887ff31fSBrian Somers static ssize_t
exec_Write(struct physical * p,const void * v,size_t n)144887ff31fSBrian Somers exec_Write(struct physical *p, const void *v, size_t n)
145887ff31fSBrian Somers {
146887ff31fSBrian Somers struct execdevice *dev = device2exec(p->handler);
147887ff31fSBrian Somers int fd = dev->fd_out == -1 ? p->fd : dev->fd_out;
148887ff31fSBrian Somers
149887ff31fSBrian Somers return write(fd, v, n);
150887ff31fSBrian Somers }
151887ff31fSBrian Somers
152887ff31fSBrian Somers static struct device baseexecdevice = {
1536815097bSBrian Somers EXEC_DEVICE,
1546815097bSBrian Somers "exec",
155c8b9fb53SBrian Somers 0,
156fdc29d54SBrian Somers { CD_NOTREQUIRED, 0 },
1576815097bSBrian Somers NULL,
158887ff31fSBrian Somers exec_RemoveFromSet,
1596815097bSBrian Somers NULL,
1606815097bSBrian Somers NULL,
1616815097bSBrian Somers NULL,
1626815097bSBrian Somers NULL,
1636815097bSBrian Somers NULL,
164887ff31fSBrian Somers exec_Free,
1656815097bSBrian Somers NULL,
166887ff31fSBrian Somers exec_Write,
167887ff31fSBrian Somers exec_device2iov,
168fb11a9c2SBrian Somers NULL,
169de59e178SBrian Somers NULL,
1706815097bSBrian Somers NULL
1716815097bSBrian Somers };
1726815097bSBrian Somers
1736815097bSBrian Somers struct device *
exec_iov2device(int type,struct physical * p,struct iovec * iov,int * niov,int maxiov __unused,int * auxfd,int * nauxfd)1746815097bSBrian Somers exec_iov2device(int type, struct physical *p, struct iovec *iov,
175887ff31fSBrian Somers int *niov, int maxiov __unused, int *auxfd, int *nauxfd)
1765d9e6103SBrian Somers {
177acbd1f00SBrian Somers if (type == EXEC_DEVICE) {
178887ff31fSBrian Somers struct execdevice *dev = (struct execdevice *)iov[(*niov)++].iov_base;
179887ff31fSBrian Somers
180887ff31fSBrian Somers dev = realloc(dev, sizeof *dev); /* Reduce to the correct size */
181887ff31fSBrian Somers if (dev == NULL) {
182887ff31fSBrian Somers log_Printf(LogALERT, "Failed to allocate memory: %d\n",
183887ff31fSBrian Somers (int)(sizeof *dev));
184887ff31fSBrian Somers AbortProgram(EX_OSERR);
185887ff31fSBrian Somers }
186887ff31fSBrian Somers
187887ff31fSBrian Somers if (*nauxfd) {
188887ff31fSBrian Somers dev->fd_out = *auxfd;
189887ff31fSBrian Somers (*nauxfd)--;
190887ff31fSBrian Somers } else
191887ff31fSBrian Somers dev->fd_out = -1;
192887ff31fSBrian Somers
193887ff31fSBrian Somers /* Refresh function pointers etc */
194887ff31fSBrian Somers memcpy(&dev->dev, &baseexecdevice, sizeof dev->dev);
195887ff31fSBrian Somers
196887ff31fSBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
197887ff31fSBrian Somers return &dev->dev;
198acbd1f00SBrian Somers }
1996815097bSBrian Somers
2006815097bSBrian Somers return NULL;
2016815097bSBrian Somers }
2026815097bSBrian Somers
203887ff31fSBrian Somers static int
exec_UpdateSet(struct fdescriptor * d,fd_set * r,fd_set * w,fd_set * e,int * n)204887ff31fSBrian Somers exec_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
205887ff31fSBrian Somers {
206887ff31fSBrian Somers struct physical *p = descriptor2physical(d);
207887ff31fSBrian Somers struct execdevice *dev = device2exec(p->handler);
208887ff31fSBrian Somers int result = 0;
209887ff31fSBrian Somers
210887ff31fSBrian Somers if (w && dev->fd_out >= 0) {
211887ff31fSBrian Somers FD_SET(dev->fd_out, w);
212887ff31fSBrian Somers log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, dev->fd_out);
213887ff31fSBrian Somers result++;
214887ff31fSBrian Somers w = NULL;
215887ff31fSBrian Somers }
216887ff31fSBrian Somers
217887ff31fSBrian Somers if (e && dev->fd_out >= 0) {
218887ff31fSBrian Somers FD_SET(dev->fd_out, e);
219887ff31fSBrian Somers log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, dev->fd_out);
220887ff31fSBrian Somers result++;
221887ff31fSBrian Somers }
222887ff31fSBrian Somers
223887ff31fSBrian Somers if (result && *n <= dev->fd_out)
224887ff31fSBrian Somers *n = dev->fd_out + 1;
225887ff31fSBrian Somers
226887ff31fSBrian Somers return result + physical_doUpdateSet(d, r, w, e, n, 0);
227887ff31fSBrian Somers }
228887ff31fSBrian Somers
229887ff31fSBrian Somers static int
exec_IsSet(struct fdescriptor * d,const fd_set * fdset)230887ff31fSBrian Somers exec_IsSet(struct fdescriptor *d, const fd_set *fdset)
231887ff31fSBrian Somers {
232887ff31fSBrian Somers struct physical *p = descriptor2physical(d);
233887ff31fSBrian Somers struct execdevice *dev = device2exec(p->handler);
234887ff31fSBrian Somers int result = dev->fd_out >= 0 && FD_ISSET(dev->fd_out, fdset);
235887ff31fSBrian Somers result += physical_IsSet(d, fdset);
236887ff31fSBrian Somers
237887ff31fSBrian Somers return result;
238887ff31fSBrian Somers }
239887ff31fSBrian Somers
2406815097bSBrian Somers struct device *
exec_Create(struct physical * p)2416815097bSBrian Somers exec_Create(struct physical *p)
2426815097bSBrian Somers {
243887ff31fSBrian Somers struct execdevice *dev;
244887ff31fSBrian Somers
245887ff31fSBrian Somers dev = NULL;
246887ff31fSBrian Somers if (p->fd < 0) {
247887ff31fSBrian Somers if (*p->name.full == '!') {
248d9626e94SBrian Somers int fids[2], type;
2495d9e6103SBrian Somers
250887ff31fSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL) {
251887ff31fSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n",
252887ff31fSBrian Somers p->link.name, strerror(errno));
253887ff31fSBrian Somers return NULL;
254887ff31fSBrian Somers }
255887ff31fSBrian Somers dev->fd_out = -1;
256887ff31fSBrian Somers
25787c3786eSBrian Somers p->fd--; /* We own the device but maybe can't use it - change fd */
258d9626e94SBrian Somers type = physical_IsSync(p) ? SOCK_DGRAM : SOCK_STREAM;
25987c3786eSBrian Somers
260887ff31fSBrian Somers if (socketpair(AF_UNIX, type, PF_UNSPEC, fids) < 0) {
2615d9e6103SBrian Somers log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n",
2625d9e6103SBrian Somers strerror(errno));
263887ff31fSBrian Somers free(dev);
264887ff31fSBrian Somers dev = NULL;
265887ff31fSBrian Somers } else {
26607e4efadSBrian Somers static int child_status; /* This variable is abused ! */
267d9626e94SBrian Somers int stat, argc, i, ret, wret, pidpipe[2];
2688fb106c6SBrian Somers pid_t pid, realpid;
2695d9e6103SBrian Somers char *argv[MAXARGS];
2705d9e6103SBrian Somers
2715d9e6103SBrian Somers stat = fcntl(fids[0], F_GETFL, 0);
2725d9e6103SBrian Somers if (stat > 0) {
2735d9e6103SBrian Somers stat |= O_NONBLOCK;
2745d9e6103SBrian Somers fcntl(fids[0], F_SETFL, stat);
2755d9e6103SBrian Somers }
2768fb106c6SBrian Somers realpid = getpid();
277d9626e94SBrian Somers if (pipe(pidpipe) == -1) {
278d9626e94SBrian Somers log_Printf(LogPHASE, "Unable to pipe for line exec: %s\n",
2795d9e6103SBrian Somers strerror(errno));
2803ce91245SBrian Somers close(fids[1]);
281887ff31fSBrian Somers close(fids[0]);
282887ff31fSBrian Somers free(dev);
283887ff31fSBrian Somers dev = NULL;
284d9626e94SBrian Somers } else switch ((pid = fork())) {
285d9626e94SBrian Somers case -1:
286d9626e94SBrian Somers log_Printf(LogPHASE, "Unable to fork for line exec: %s\n",
287d9626e94SBrian Somers strerror(errno));
288d9626e94SBrian Somers close(pidpipe[0]);
289d9626e94SBrian Somers close(pidpipe[1]);
290d9626e94SBrian Somers close(fids[1]);
291887ff31fSBrian Somers close(fids[0]);
2925d9e6103SBrian Somers break;
2935d9e6103SBrian Somers
2945d9e6103SBrian Somers case 0:
295d9626e94SBrian Somers close(pidpipe[0]);
2965d9e6103SBrian Somers close(fids[0]);
2975d9e6103SBrian Somers timer_TermService();
29868602c3eSBrian Somers #ifndef NOSUID
299a19a5c02SBrian Somers setuid(ID0realuid());
30068602c3eSBrian Somers #endif
3015d9e6103SBrian Somers
3023ce91245SBrian Somers child_status = 0;
303d9626e94SBrian Somers switch ((pid = vfork())) {
3045d9e6103SBrian Somers case 0:
305d9626e94SBrian Somers close(pidpipe[1]);
3065d9e6103SBrian Somers break;
3075d9e6103SBrian Somers
3085d9e6103SBrian Somers case -1:
3093ce91245SBrian Somers ret = errno;
310d9626e94SBrian Somers log_Printf(LogPHASE, "Unable to vfork to drop parent: %s\n",
3115d9e6103SBrian Somers strerror(errno));
312d9626e94SBrian Somers close(pidpipe[1]);
3133ce91245SBrian Somers _exit(ret);
3143ce91245SBrian Somers
3155d9e6103SBrian Somers default:
316d9626e94SBrian Somers write(pidpipe[1], &pid, sizeof pid);
317d9626e94SBrian Somers close(pidpipe[1]);
3183ce91245SBrian Somers _exit(child_status); /* The error from exec() ! */
3195d9e6103SBrian Somers }
3205d9e6103SBrian Somers
32144e73c12SBrian Somers log_Printf(LogDEBUG, "Exec'ing ``%s''\n", p->name.base);
32244e73c12SBrian Somers
3235b78bdf8SBrian Somers if ((argc = MakeArgs(p->name.base, argv, VECSIZE(argv),
3245b78bdf8SBrian Somers PARSE_REDUCE|PARSE_NOHASH)) < 0) {
325c39aa54eSBrian Somers log_Printf(LogWARN, "Syntax error in exec command\n");
3263ce91245SBrian Somers _exit(ESRCH);
327c39aa54eSBrian Somers }
328c39aa54eSBrian Somers
329c39aa54eSBrian Somers command_Expand(argv, argc, (char const *const *)argv,
330c39aa54eSBrian Somers p->dl->bundle, 0, realpid);
331c39aa54eSBrian Somers
3325d9e6103SBrian Somers dup2(fids[1], STDIN_FILENO);
3335d9e6103SBrian Somers dup2(fids[1], STDOUT_FILENO);
3345d9e6103SBrian Somers dup2(fids[1], STDERR_FILENO);
33544e73c12SBrian Somers for (i = getdtablesize(); i > STDERR_FILENO; i--)
33644e73c12SBrian Somers fcntl(i, F_SETFD, 1);
3375d9e6103SBrian Somers
3385d9e6103SBrian Somers execvp(*argv, argv);
3393ce91245SBrian Somers child_status = errno; /* Only works for vfork() */
3403ce91245SBrian Somers printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status));
3413ce91245SBrian Somers _exit(child_status);
3425d9e6103SBrian Somers break;
3435d9e6103SBrian Somers
3445d9e6103SBrian Somers default:
345d9626e94SBrian Somers close(pidpipe[1]);
3465d9e6103SBrian Somers close(fids[1]);
347d9626e94SBrian Somers if (read(pidpipe[0], &p->session_owner, sizeof p->session_owner) !=
348d9626e94SBrian Somers sizeof p->session_owner)
349d9626e94SBrian Somers p->session_owner = (pid_t)-1;
350d9626e94SBrian Somers close(pidpipe[0]);
3513ce91245SBrian Somers while ((wret = waitpid(pid, &stat, 0)) == -1 && errno == EINTR)
3523ce91245SBrian Somers ;
3533ce91245SBrian Somers if (wret == -1) {
3543ce91245SBrian Somers log_Printf(LogWARN, "Waiting for child process: %s\n",
3553ce91245SBrian Somers strerror(errno));
3563ce91245SBrian Somers close(fids[0]);
357d9626e94SBrian Somers p->session_owner = (pid_t)-1;
3583ce91245SBrian Somers break;
3593ce91245SBrian Somers } else if (WIFSIGNALED(stat)) {
3603ce91245SBrian Somers log_Printf(LogWARN, "Child process received sig %d !\n",
3613ce91245SBrian Somers WTERMSIG(stat));
3623ce91245SBrian Somers close(fids[0]);
363d9626e94SBrian Somers p->session_owner = (pid_t)-1;
3643ce91245SBrian Somers break;
3653ce91245SBrian Somers } else if (WIFSTOPPED(stat)) {
3663ce91245SBrian Somers log_Printf(LogWARN, "Child process received stop sig %d !\n",
3673ce91245SBrian Somers WSTOPSIG(stat));
3683ce91245SBrian Somers /* I guess that's ok.... */
3693ce91245SBrian Somers } else if ((ret = WEXITSTATUS(stat))) {
3703ce91245SBrian Somers log_Printf(LogWARN, "Cannot exec \"%s\": %s\n", p->name.base,
3713ce91245SBrian Somers strerror(ret));
3723ce91245SBrian Somers close(fids[0]);
373d9626e94SBrian Somers p->session_owner = (pid_t)-1;
3743ce91245SBrian Somers break;
3753ce91245SBrian Somers }
3765d9e6103SBrian Somers p->fd = fids[0];
3778e7bd08eSBrian Somers log_Printf(LogDEBUG, "Using descriptor %d for child\n", p->fd);
378887ff31fSBrian Somers }
379887ff31fSBrian Somers }
380887ff31fSBrian Somers }
381887ff31fSBrian Somers } else {
382887ff31fSBrian Somers struct stat st;
383887ff31fSBrian Somers
384887ff31fSBrian Somers if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFIFO)) {
385887ff31fSBrian Somers if ((dev = malloc(sizeof *dev)) == NULL)
386887ff31fSBrian Somers log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n",
387887ff31fSBrian Somers p->link.name, strerror(errno));
388887ff31fSBrian Somers else if (p->fd == STDIN_FILENO) {
389887ff31fSBrian Somers log_Printf(LogPHASE, "%s: Using stdin/stdout to communicate with "
390887ff31fSBrian Somers "parent (pipe mode)\n", p->link.name);
391887ff31fSBrian Somers dev->fd_out = dup(STDOUT_FILENO);
392887ff31fSBrian Somers
393887ff31fSBrian Somers /* Hook things up so that we monitor dev->fd_out */
394887ff31fSBrian Somers p->desc.UpdateSet = exec_UpdateSet;
395887ff31fSBrian Somers p->desc.IsSet = exec_IsSet;
396887ff31fSBrian Somers } else
397887ff31fSBrian Somers dev->fd_out = -1;
398887ff31fSBrian Somers }
399887ff31fSBrian Somers }
400887ff31fSBrian Somers
401887ff31fSBrian Somers if (dev) {
402887ff31fSBrian Somers memcpy(&dev->dev, &baseexecdevice, sizeof dev->dev);
403887ff31fSBrian Somers physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
404fdc29d54SBrian Somers if (p->cfg.cd.necessity != CD_DEFAULT)
405fdc29d54SBrian Somers log_Printf(LogWARN, "Carrier settings ignored\n");
406887ff31fSBrian Somers return &dev->dev;
4075d9e6103SBrian Somers }
4085d9e6103SBrian Somers
4096815097bSBrian Somers return NULL;
4105d9e6103SBrian Somers }
411