xref: /freebsd/usr.sbin/ppp/exec.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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