1/* popen.c: A "safe" pipe open routine. 2 3%%% portions-copyright-cmetz-96 4Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights 5Reserved. The Inner Net License Version 2 applies to these portions of 6the software. 7You should have received a copy of the license with this software. If 8you didn't get a copy, you may request one from <license@inner.net>. 9 10Portions of this software are Copyright 1995 by Randall Atkinson and Dan 11McDonald, All Rights Reserved. All Rights under this copyright are assigned 12to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 13License Agreement applies to this software. 14 15 History: 16 17 Modified by cmetz for OPIE 2.31. Merged in some 4.4BSD-Lite fixes. 18 Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. 19 Removed useless string. ifdef around some headers. 20 Modified at NRL for OPIE 2.1. Optimized for only one pipe at a time. 21 Added minimal version of sigprocmask(). Moved some pid_t 22 dancing to the config headers. 23 Modified at NRL for OPIE 2.0. 24 Originally from BSD. 25 26$FreeBSD$ 27*/ 28/* 29 * Copyright (c) 1988, 1993, 1994 30 * The Regents of the University of California. All rights reserved. 31 * 32 * This code is derived from software written by Ken Arnold and 33 * published in UNIX Review, Vol. 6, No. 8. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. All advertising materials mentioning features or use of this software 44 * must display the following acknowledgement: 45 * This product includes software developed by the University of 46 * California, Berkeley and its contributors. 47 * 4. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 * 63 */ 64 65#include "opie_cfg.h" 66 67#include <sys/types.h> 68#include <sys/wait.h> 69#if HAVE_SIGNAL_H 70#include <signal.h> 71#endif /* HAVE_SIGNAL_H */ 72#if HAVE_SYS_SIGNAL_H 73#include <sys/signal.h> 74#endif /* HAVE_SYS_SIGNAL_H */ 75#if HAVE_UNISTD_H 76#include <unistd.h> 77#endif /* HAVE_UNISTD_H */ 78#include <stdio.h> 79#if HAVE_STDLIB_H 80#include <stdlib.h> 81#endif /* HAVE_STDLIB_H */ 82#if HAVE_STRING_H 83#include <string.h> 84#endif /* HAVE_STRING_H */ 85 86#include "opie.h" 87 88#define MAXUSRARGS 100 89#define MAXGLOBARGS 1000 90 91char **ftpglob __P((register char *)); 92char **copyblk __P((char **)); 93VOIDRET blkfree __P((char **)); 94 95/* 96 * Special version of popen which avoids call to shell. This ensures noone 97 * may create a pipe to a hidden program as a side effect of a list or dir 98 * command. 99 */ 100static pid_t child_pid = -1; 101static int pipe_fd; 102 103extern char **environ; 104 105FILE *ftpd_popen FUNCTION((program, type), char *program AND char *type) 106{ 107 char *cp; 108 FILE *iop; 109 int argc, gargc, pdes[2]; 110 char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS], *vv[2]; 111 112 if ((*type != 'r' && *type != 'w') || type[1]) 113 return (NULL); 114 115 if (pipe(pdes) < 0) 116 return (NULL); 117 118 /* break up string into pieces */ 119 for (argc = 0, cp = program; argc < MAXUSRARGS-1; cp = NULL) { 120 if (!(argv[argc++] = strtok(cp, " \t\n"))) 121 break; 122 } 123 argv[argc - 1] = NULL; 124 125 /* glob each piece */ 126 gargv[0] = argv[0]; 127 for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) { 128 if (!(pop = (char **) ftpglob(argv[argc]))) { 129 /* globbing failed */ 130 vv[0] = argv[argc]; 131 vv[1] = NULL; 132 pop = (char **) copyblk(vv); 133 } 134 argv[argc] = (char *) pop; /* save to free later */ 135 while (*pop && gargc < MAXGLOBARGS-1) 136 gargv[gargc++] = *pop++; 137 } 138 gargv[gargc] = NULL; 139 140 iop = NULL; 141 switch (child_pid = fork()) { 142 case -1: /* error */ 143 close(pdes[0]); 144 close(pdes[1]); 145 goto pfree; 146 /* NOTREACHED */ 147 case 0: /* child */ 148 if (*type == 'r') { 149 if (pdes[1] != 1) { 150 dup2(pdes[1], 1); 151 dup2(pdes[1], 2); /* stderr, too! */ 152 close(pdes[1]); 153 } 154 close(pdes[0]); 155 } else { 156 if (pdes[0] != 0) { 157 dup2(pdes[0], 0); 158 close(pdes[0]); 159 } 160 close(pdes[1]); 161 } 162 environ = NULL; 163 execv(gargv[0], gargv); 164 _exit(1); 165 } 166 167 /* parent; assume fdopen can't fail... */ 168 if (*type == 'r') { 169 iop = fdopen(pipe_fd = pdes[0], type); 170 close(pdes[1]); 171 } else { 172 iop = fdopen(pipe_fd = pdes[1], type); 173 close(pdes[0]); 174 } 175 176pfree: for (argc = 1; argv[argc] != NULL; argc++) { 177 blkfree((char **) argv[argc]); 178 free((char *) argv[argc]); 179 } 180 return (iop); 181} 182 183int ftpd_pclose FUNCTION((iop), FILE *iop) 184{ 185 int status; 186 pid_t pid; 187 sigset_t omask, mask; 188 189 sigemptyset(&mask); 190 sigaddset(&mask, SIGINT); 191 sigaddset(&mask, SIGQUIT); 192 sigaddset(&mask, SIGHUP); 193 194 /* pclose returns -1 if stream is not associated with a `popened' command, 195 or, if already `pclosed'. */ 196 if ((child_pid < 0) || (fileno(iop) != pipe_fd)) 197 return (-1); 198 199 fclose(iop); 200 sigprocmask(SIG_BLOCK, &mask, &omask); 201 202 while ((pid = wait(&status)) != child_pid && (pid != -1)); 203 sigprocmask(SIG_SETMASK, &omask, NULL); 204 205 child_pid = -1; 206 pipe_fd = -1; 207 208#if defined(WEXITSTATUS) && defined(WIFEXITED) 209 if ((pid > 0) && WIFEXITED(status)) 210 return WEXITSTATUS(status); 211 212 return -1; 213#else /* defined(WEXITSTATUS) && defined(WIFEXITED) */ 214 return (pid == -1 ? -1 : status.w_status); 215#endif /* defined(WEXITSTATUS) && defined(WIFEXITED) */ 216} 217