xref: /freebsd/usr.sbin/ppp/exec.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
15d9e6103SBrian Somers /*-
2*1de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*1de7b4b8SPedro 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  *
2897d92980SPeter Wemm  * $FreeBSD$
295d9e6103SBrian Somers  */
305d9e6103SBrian Somers 
315d9e6103SBrian Somers #include <sys/param.h>
325d9e6103SBrian Somers #include <sys/socket.h>
335d9e6103SBrian Somers #include <sys/un.h>
345d9e6103SBrian Somers 
355d9e6103SBrian Somers #include <errno.h>
365d9e6103SBrian Somers #include <fcntl.h>
375d9e6103SBrian Somers #include <stdio.h>
385d9e6103SBrian Somers #include <stdlib.h>
395d9e6103SBrian Somers #include <string.h>
40887ff31fSBrian Somers #include <sysexits.h>
415d9e6103SBrian Somers #include <sys/wait.h>
42887ff31fSBrian Somers #include <sys/stat.h>
43f5a99677SBrian Somers #include <sys/uio.h>
445d9e6103SBrian Somers #include <termios.h>
455d9e6103SBrian Somers #include <unistd.h>
465d9e6103SBrian Somers 
475d9e6103SBrian Somers #include "layer.h"
485d9e6103SBrian Somers #include "defs.h"
495d9e6103SBrian Somers #include "mbuf.h"
505d9e6103SBrian Somers #include "log.h"
515d9e6103SBrian Somers #include "timer.h"
525d9e6103SBrian Somers #include "lqr.h"
535d9e6103SBrian Somers #include "hdlc.h"
545d9e6103SBrian Somers #include "throughput.h"
555d9e6103SBrian Somers #include "fsm.h"
565d9e6103SBrian Somers #include "lcp.h"
575d9e6103SBrian Somers #include "ccp.h"
585d9e6103SBrian Somers #include "link.h"
595d9e6103SBrian Somers #include "async.h"
605d9e6103SBrian Somers #include "descriptor.h"
615d9e6103SBrian Somers #include "physical.h"
625d9e6103SBrian Somers #include "mp.h"
635d9e6103SBrian Somers #include "chat.h"
645d9e6103SBrian Somers #include "command.h"
655d9e6103SBrian Somers #include "auth.h"
665d9e6103SBrian Somers #include "chap.h"
675d9e6103SBrian Somers #include "cbcp.h"
685d9e6103SBrian Somers #include "datalink.h"
69e7d008b4SBrian Somers #include "id.h"
70887ff31fSBrian Somers #include "main.h"
715d9e6103SBrian Somers #include "exec.h"
725d9e6103SBrian Somers 
73887ff31fSBrian Somers 
74887ff31fSBrian Somers struct execdevice {
75887ff31fSBrian Somers   struct device dev;		/* What struct physical knows about */
76887ff31fSBrian Somers   int fd_out;			/* output descriptor */
77887ff31fSBrian Somers };
78887ff31fSBrian Somers 
79887ff31fSBrian Somers #define device2exec(d) ((d)->type == EXEC_DEVICE ? (struct execdevice *)d : NULL)
80887ff31fSBrian Somers 
81887ff31fSBrian Somers unsigned
82887ff31fSBrian Somers exec_DeviceSize(void)
83887ff31fSBrian Somers {
84887ff31fSBrian Somers   return sizeof(struct execdevice);
85887ff31fSBrian Somers }
86887ff31fSBrian Somers 
87887ff31fSBrian Somers static void
88887ff31fSBrian Somers exec_Free(struct physical *p)
89887ff31fSBrian Somers {
90887ff31fSBrian Somers   struct execdevice *dev = device2exec(p->handler);
91887ff31fSBrian Somers 
92887ff31fSBrian Somers   if (dev->fd_out != -1)
93887ff31fSBrian Somers     close(dev->fd_out);
94887ff31fSBrian Somers   free(dev);
95887ff31fSBrian Somers }
96887ff31fSBrian Somers 
97887ff31fSBrian Somers static void
98887ff31fSBrian Somers exec_device2iov(struct device *d, struct iovec *iov, int *niov,
99887ff31fSBrian Somers                int maxiov __unused, int *auxfd, int *nauxfd)
100887ff31fSBrian Somers {
101887ff31fSBrian Somers   struct execdevice *dev;
102887ff31fSBrian Somers   int sz = physical_MaxDeviceSize();
103887ff31fSBrian Somers 
104887ff31fSBrian Somers   iov[*niov].iov_base = d = realloc(d, sz);
105887ff31fSBrian Somers   if (d == NULL) {
106887ff31fSBrian Somers     log_Printf(LogALERT, "Failed to allocate memory: %d\n", sz);
107887ff31fSBrian Somers     AbortProgram(EX_OSERR);
108887ff31fSBrian Somers   }
109887ff31fSBrian Somers   iov[*niov].iov_len = sz;
110887ff31fSBrian Somers   (*niov)++;
111887ff31fSBrian Somers 
112887ff31fSBrian Somers   dev = device2exec(d);
113887ff31fSBrian Somers   if (dev->fd_out >= 0) {
114887ff31fSBrian Somers     *auxfd = dev->fd_out;
115887ff31fSBrian Somers     (*nauxfd)++;
116887ff31fSBrian Somers   }
117887ff31fSBrian Somers }
118887ff31fSBrian Somers 
119887ff31fSBrian Somers static int
120887ff31fSBrian Somers exec_RemoveFromSet(struct physical *p, fd_set *r, fd_set *w, fd_set *e)
121887ff31fSBrian Somers {
122887ff31fSBrian Somers   struct execdevice *dev = device2exec(p->handler);
123887ff31fSBrian Somers   int sets;
124887ff31fSBrian Somers 
125887ff31fSBrian Somers   p->handler->removefromset = NULL;
126887ff31fSBrian Somers   sets = physical_RemoveFromSet(p, r, w, e);
127887ff31fSBrian Somers   p->handler->removefromset = exec_RemoveFromSet;
128887ff31fSBrian Somers 
129887ff31fSBrian Somers   if (dev->fd_out >= 0) {
130887ff31fSBrian Somers     if (w && FD_ISSET(dev->fd_out, w)) {
131887ff31fSBrian Somers       FD_CLR(dev->fd_out, w);
132887ff31fSBrian Somers       log_Printf(LogTIMER, "%s: fdunset(w) %d\n", p->link.name, dev->fd_out);
133887ff31fSBrian Somers       sets++;
134887ff31fSBrian Somers     }
135887ff31fSBrian Somers     if (e && FD_ISSET(dev->fd_out, e)) {
136887ff31fSBrian Somers       FD_CLR(dev->fd_out, e);
137887ff31fSBrian Somers       log_Printf(LogTIMER, "%s: fdunset(e) %d\n", p->link.name, dev->fd_out);
138887ff31fSBrian Somers       sets++;
139887ff31fSBrian Somers     }
140887ff31fSBrian Somers   }
141887ff31fSBrian Somers 
142887ff31fSBrian Somers   return sets;
143887ff31fSBrian Somers }
144887ff31fSBrian Somers 
145887ff31fSBrian Somers static ssize_t
146887ff31fSBrian Somers exec_Write(struct physical *p, const void *v, size_t n)
147887ff31fSBrian Somers {
148887ff31fSBrian Somers   struct execdevice *dev = device2exec(p->handler);
149887ff31fSBrian Somers   int fd = dev->fd_out == -1 ? p->fd : dev->fd_out;
150887ff31fSBrian Somers 
151887ff31fSBrian Somers   return write(fd, v, n);
152887ff31fSBrian Somers }
153887ff31fSBrian Somers 
154887ff31fSBrian Somers static struct device baseexecdevice = {
1556815097bSBrian Somers   EXEC_DEVICE,
1566815097bSBrian Somers   "exec",
157c8b9fb53SBrian Somers   0,
158fdc29d54SBrian Somers   { CD_NOTREQUIRED, 0 },
1596815097bSBrian Somers   NULL,
160887ff31fSBrian Somers   exec_RemoveFromSet,
1616815097bSBrian Somers   NULL,
1626815097bSBrian Somers   NULL,
1636815097bSBrian Somers   NULL,
1646815097bSBrian Somers   NULL,
1656815097bSBrian Somers   NULL,
166887ff31fSBrian Somers   exec_Free,
1676815097bSBrian Somers   NULL,
168887ff31fSBrian Somers   exec_Write,
169887ff31fSBrian Somers   exec_device2iov,
170fb11a9c2SBrian Somers   NULL,
171de59e178SBrian Somers   NULL,
1726815097bSBrian Somers   NULL
1736815097bSBrian Somers };
1746815097bSBrian Somers 
1756815097bSBrian Somers struct device *
1766815097bSBrian Somers exec_iov2device(int type, struct physical *p, struct iovec *iov,
177887ff31fSBrian Somers                 int *niov, int maxiov __unused, int *auxfd, int *nauxfd)
1785d9e6103SBrian Somers {
179acbd1f00SBrian Somers   if (type == EXEC_DEVICE) {
180887ff31fSBrian Somers     struct execdevice *dev = (struct execdevice *)iov[(*niov)++].iov_base;
181887ff31fSBrian Somers 
182887ff31fSBrian Somers     dev = realloc(dev, sizeof *dev);	/* Reduce to the correct size */
183887ff31fSBrian Somers     if (dev == NULL) {
184887ff31fSBrian Somers       log_Printf(LogALERT, "Failed to allocate memory: %d\n",
185887ff31fSBrian Somers                  (int)(sizeof *dev));
186887ff31fSBrian Somers       AbortProgram(EX_OSERR);
187887ff31fSBrian Somers     }
188887ff31fSBrian Somers 
189887ff31fSBrian Somers     if (*nauxfd) {
190887ff31fSBrian Somers       dev->fd_out = *auxfd;
191887ff31fSBrian Somers       (*nauxfd)--;
192887ff31fSBrian Somers     } else
193887ff31fSBrian Somers       dev->fd_out = -1;
194887ff31fSBrian Somers 
195887ff31fSBrian Somers     /* Refresh function pointers etc */
196887ff31fSBrian Somers     memcpy(&dev->dev, &baseexecdevice, sizeof dev->dev);
197887ff31fSBrian Somers 
198887ff31fSBrian Somers     physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
199887ff31fSBrian Somers     return &dev->dev;
200acbd1f00SBrian Somers   }
2016815097bSBrian Somers 
2026815097bSBrian Somers   return NULL;
2036815097bSBrian Somers }
2046815097bSBrian Somers 
205887ff31fSBrian Somers static int
206887ff31fSBrian Somers exec_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
207887ff31fSBrian Somers {
208887ff31fSBrian Somers   struct physical *p = descriptor2physical(d);
209887ff31fSBrian Somers   struct execdevice *dev = device2exec(p->handler);
210887ff31fSBrian Somers   int result = 0;
211887ff31fSBrian Somers 
212887ff31fSBrian Somers   if (w && dev->fd_out >= 0) {
213887ff31fSBrian Somers     FD_SET(dev->fd_out, w);
214887ff31fSBrian Somers     log_Printf(LogTIMER, "%s: fdset(w) %d\n", p->link.name, dev->fd_out);
215887ff31fSBrian Somers     result++;
216887ff31fSBrian Somers     w = NULL;
217887ff31fSBrian Somers   }
218887ff31fSBrian Somers 
219887ff31fSBrian Somers   if (e && dev->fd_out >= 0) {
220887ff31fSBrian Somers     FD_SET(dev->fd_out, e);
221887ff31fSBrian Somers     log_Printf(LogTIMER, "%s: fdset(e) %d\n", p->link.name, dev->fd_out);
222887ff31fSBrian Somers     result++;
223887ff31fSBrian Somers   }
224887ff31fSBrian Somers 
225887ff31fSBrian Somers   if (result && *n <= dev->fd_out)
226887ff31fSBrian Somers     *n = dev->fd_out + 1;
227887ff31fSBrian Somers 
228887ff31fSBrian Somers   return result + physical_doUpdateSet(d, r, w, e, n, 0);
229887ff31fSBrian Somers }
230887ff31fSBrian Somers 
231887ff31fSBrian Somers static int
232887ff31fSBrian Somers exec_IsSet(struct fdescriptor *d, const fd_set *fdset)
233887ff31fSBrian Somers {
234887ff31fSBrian Somers   struct physical *p = descriptor2physical(d);
235887ff31fSBrian Somers   struct execdevice *dev = device2exec(p->handler);
236887ff31fSBrian Somers   int result = dev->fd_out >= 0 && FD_ISSET(dev->fd_out, fdset);
237887ff31fSBrian Somers   result += physical_IsSet(d, fdset);
238887ff31fSBrian Somers 
239887ff31fSBrian Somers   return result;
240887ff31fSBrian Somers }
241887ff31fSBrian Somers 
2426815097bSBrian Somers struct device *
2436815097bSBrian Somers exec_Create(struct physical *p)
2446815097bSBrian Somers {
245887ff31fSBrian Somers   struct execdevice *dev;
246887ff31fSBrian Somers 
247887ff31fSBrian Somers   dev = NULL;
248887ff31fSBrian Somers   if (p->fd < 0) {
249887ff31fSBrian Somers     if (*p->name.full == '!') {
250d9626e94SBrian Somers       int fids[2], type;
2515d9e6103SBrian Somers 
252887ff31fSBrian Somers       if ((dev = malloc(sizeof *dev)) == NULL) {
253887ff31fSBrian Somers         log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n",
254887ff31fSBrian Somers                    p->link.name, strerror(errno));
255887ff31fSBrian Somers         return NULL;
256887ff31fSBrian Somers       }
257887ff31fSBrian Somers       dev->fd_out = -1;
258887ff31fSBrian Somers 
25987c3786eSBrian Somers       p->fd--;	/* We own the device but maybe can't use it - change fd */
260d9626e94SBrian Somers       type = physical_IsSync(p) ? SOCK_DGRAM : SOCK_STREAM;
26187c3786eSBrian Somers 
262887ff31fSBrian Somers       if (socketpair(AF_UNIX, type, PF_UNSPEC, fids) < 0) {
2635d9e6103SBrian Somers         log_Printf(LogPHASE, "Unable to create pipe for line exec: %s\n",
2645d9e6103SBrian Somers                    strerror(errno));
265887ff31fSBrian Somers         free(dev);
266887ff31fSBrian Somers         dev = NULL;
267887ff31fSBrian Somers       } else {
26807e4efadSBrian Somers         static int child_status;		/* This variable is abused ! */
269d9626e94SBrian Somers         int stat, argc, i, ret, wret, pidpipe[2];
2708fb106c6SBrian Somers         pid_t pid, realpid;
2715d9e6103SBrian Somers         char *argv[MAXARGS];
2725d9e6103SBrian Somers 
2735d9e6103SBrian Somers         stat = fcntl(fids[0], F_GETFL, 0);
2745d9e6103SBrian Somers         if (stat > 0) {
2755d9e6103SBrian Somers           stat |= O_NONBLOCK;
2765d9e6103SBrian Somers           fcntl(fids[0], F_SETFL, stat);
2775d9e6103SBrian Somers         }
2788fb106c6SBrian Somers         realpid = getpid();
279d9626e94SBrian Somers         if (pipe(pidpipe) == -1) {
280d9626e94SBrian Somers           log_Printf(LogPHASE, "Unable to pipe for line exec: %s\n",
2815d9e6103SBrian Somers                      strerror(errno));
2823ce91245SBrian Somers           close(fids[1]);
283887ff31fSBrian Somers           close(fids[0]);
284887ff31fSBrian Somers           free(dev);
285887ff31fSBrian Somers           dev = NULL;
286d9626e94SBrian Somers         } else switch ((pid = fork())) {
287d9626e94SBrian Somers           case -1:
288d9626e94SBrian Somers             log_Printf(LogPHASE, "Unable to fork for line exec: %s\n",
289d9626e94SBrian Somers                        strerror(errno));
290d9626e94SBrian Somers             close(pidpipe[0]);
291d9626e94SBrian Somers             close(pidpipe[1]);
292d9626e94SBrian Somers             close(fids[1]);
293887ff31fSBrian Somers             close(fids[0]);
2945d9e6103SBrian Somers             break;
2955d9e6103SBrian Somers 
2965d9e6103SBrian Somers           case 0:
297d9626e94SBrian Somers             close(pidpipe[0]);
2985d9e6103SBrian Somers             close(fids[0]);
2995d9e6103SBrian Somers             timer_TermService();
30068602c3eSBrian Somers   #ifndef NOSUID
301a19a5c02SBrian Somers             setuid(ID0realuid());
30268602c3eSBrian Somers   #endif
3035d9e6103SBrian Somers 
3043ce91245SBrian Somers             child_status = 0;
305d9626e94SBrian Somers             switch ((pid = vfork())) {
3065d9e6103SBrian Somers               case 0:
307d9626e94SBrian Somers                 close(pidpipe[1]);
3085d9e6103SBrian Somers                 break;
3095d9e6103SBrian Somers 
3105d9e6103SBrian Somers               case -1:
3113ce91245SBrian Somers                 ret = errno;
312d9626e94SBrian Somers                 log_Printf(LogPHASE, "Unable to vfork to drop parent: %s\n",
3135d9e6103SBrian Somers                            strerror(errno));
314d9626e94SBrian Somers                 close(pidpipe[1]);
3153ce91245SBrian Somers                 _exit(ret);
3163ce91245SBrian Somers 
3175d9e6103SBrian Somers               default:
318d9626e94SBrian Somers                 write(pidpipe[1], &pid, sizeof pid);
319d9626e94SBrian Somers                 close(pidpipe[1]);
3203ce91245SBrian Somers                 _exit(child_status);	/* The error from exec() ! */
3215d9e6103SBrian Somers             }
3225d9e6103SBrian Somers 
32344e73c12SBrian Somers             log_Printf(LogDEBUG, "Exec'ing ``%s''\n", p->name.base);
32444e73c12SBrian Somers 
3255b78bdf8SBrian Somers             if ((argc = MakeArgs(p->name.base, argv, VECSIZE(argv),
3265b78bdf8SBrian Somers                                  PARSE_REDUCE|PARSE_NOHASH)) < 0) {
327c39aa54eSBrian Somers               log_Printf(LogWARN, "Syntax error in exec command\n");
3283ce91245SBrian Somers               _exit(ESRCH);
329c39aa54eSBrian Somers             }
330c39aa54eSBrian Somers 
331c39aa54eSBrian Somers             command_Expand(argv, argc, (char const *const *)argv,
332c39aa54eSBrian Somers                            p->dl->bundle, 0, realpid);
333c39aa54eSBrian Somers 
3345d9e6103SBrian Somers             dup2(fids[1], STDIN_FILENO);
3355d9e6103SBrian Somers             dup2(fids[1], STDOUT_FILENO);
3365d9e6103SBrian Somers             dup2(fids[1], STDERR_FILENO);
33744e73c12SBrian Somers             for (i = getdtablesize(); i > STDERR_FILENO; i--)
33844e73c12SBrian Somers               fcntl(i, F_SETFD, 1);
3395d9e6103SBrian Somers 
3405d9e6103SBrian Somers             execvp(*argv, argv);
3413ce91245SBrian Somers             child_status = errno;		/* Only works for vfork() */
3423ce91245SBrian Somers             printf("execvp failed: %s: %s\r\n", *argv, strerror(child_status));
3433ce91245SBrian Somers             _exit(child_status);
3445d9e6103SBrian Somers             break;
3455d9e6103SBrian Somers 
3465d9e6103SBrian Somers           default:
347d9626e94SBrian Somers             close(pidpipe[1]);
3485d9e6103SBrian Somers             close(fids[1]);
349d9626e94SBrian Somers             if (read(pidpipe[0], &p->session_owner, sizeof p->session_owner) !=
350d9626e94SBrian Somers                 sizeof p->session_owner)
351d9626e94SBrian Somers               p->session_owner = (pid_t)-1;
352d9626e94SBrian Somers             close(pidpipe[0]);
3533ce91245SBrian Somers             while ((wret = waitpid(pid, &stat, 0)) == -1 && errno == EINTR)
3543ce91245SBrian Somers               ;
3553ce91245SBrian Somers             if (wret == -1) {
3563ce91245SBrian Somers               log_Printf(LogWARN, "Waiting for child process: %s\n",
3573ce91245SBrian Somers                          strerror(errno));
3583ce91245SBrian Somers               close(fids[0]);
359d9626e94SBrian Somers               p->session_owner = (pid_t)-1;
3603ce91245SBrian Somers               break;
3613ce91245SBrian Somers             } else if (WIFSIGNALED(stat)) {
3623ce91245SBrian Somers               log_Printf(LogWARN, "Child process received sig %d !\n",
3633ce91245SBrian Somers                          WTERMSIG(stat));
3643ce91245SBrian Somers               close(fids[0]);
365d9626e94SBrian Somers               p->session_owner = (pid_t)-1;
3663ce91245SBrian Somers               break;
3673ce91245SBrian Somers             } else if (WIFSTOPPED(stat)) {
3683ce91245SBrian Somers               log_Printf(LogWARN, "Child process received stop sig %d !\n",
3693ce91245SBrian Somers                          WSTOPSIG(stat));
3703ce91245SBrian Somers               /* I guess that's ok.... */
3713ce91245SBrian Somers             } else if ((ret = WEXITSTATUS(stat))) {
3723ce91245SBrian Somers               log_Printf(LogWARN, "Cannot exec \"%s\": %s\n", p->name.base,
3733ce91245SBrian Somers                          strerror(ret));
3743ce91245SBrian Somers               close(fids[0]);
375d9626e94SBrian Somers               p->session_owner = (pid_t)-1;
3763ce91245SBrian Somers               break;
3773ce91245SBrian Somers             }
3785d9e6103SBrian Somers             p->fd = fids[0];
3798e7bd08eSBrian Somers             log_Printf(LogDEBUG, "Using descriptor %d for child\n", p->fd);
380887ff31fSBrian Somers         }
381887ff31fSBrian Somers       }
382887ff31fSBrian Somers     }
383887ff31fSBrian Somers   } else {
384887ff31fSBrian Somers     struct stat st;
385887ff31fSBrian Somers 
386887ff31fSBrian Somers     if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFIFO)) {
387887ff31fSBrian Somers       if ((dev = malloc(sizeof *dev)) == NULL)
388887ff31fSBrian Somers         log_Printf(LogWARN, "%s: Cannot allocate an exec device: %s\n",
389887ff31fSBrian Somers                    p->link.name, strerror(errno));
390887ff31fSBrian Somers       else if (p->fd == STDIN_FILENO) {
391887ff31fSBrian Somers         log_Printf(LogPHASE, "%s: Using stdin/stdout to communicate with "
392887ff31fSBrian Somers                    "parent (pipe mode)\n", p->link.name);
393887ff31fSBrian Somers         dev->fd_out = dup(STDOUT_FILENO);
394887ff31fSBrian Somers 
395887ff31fSBrian Somers         /* Hook things up so that we monitor dev->fd_out */
396887ff31fSBrian Somers         p->desc.UpdateSet = exec_UpdateSet;
397887ff31fSBrian Somers         p->desc.IsSet = exec_IsSet;
398887ff31fSBrian Somers       } else
399887ff31fSBrian Somers         dev->fd_out = -1;
400887ff31fSBrian Somers     }
401887ff31fSBrian Somers   }
402887ff31fSBrian Somers 
403887ff31fSBrian Somers   if (dev) {
404887ff31fSBrian Somers     memcpy(&dev->dev, &baseexecdevice, sizeof dev->dev);
405887ff31fSBrian Somers     physical_SetupStack(p, dev->dev.name, PHYSICAL_NOFORCE);
406fdc29d54SBrian Somers     if (p->cfg.cd.necessity != CD_DEFAULT)
407fdc29d54SBrian Somers       log_Printf(LogWARN, "Carrier settings ignored\n");
408887ff31fSBrian Somers     return &dev->dev;
4095d9e6103SBrian Somers   }
4105d9e6103SBrian Somers 
4116815097bSBrian Somers   return NULL;
4125d9e6103SBrian Somers }
413