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