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