popen.c revision 92906
122347Spst/* popen.c: A "safe" pipe open routine. 222347Spst 329964Sache%%% portions-copyright-cmetz-96 492906SmarkmPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights 522347SpstReserved. The Inner Net License Version 2 applies to these portions of 622347Spstthe software. 722347SpstYou should have received a copy of the license with this software. If 822347Spstyou didn't get a copy, you may request one from <license@inner.net>. 922347Spst 1022347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan 1122347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned 1222347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 1322347SpstLicense Agreement applies to this software. 1422347Spst 1522347Spst History: 1622347Spst 1729964Sache Modified by cmetz for OPIE 2.31. Merged in some 4.4BSD-Lite fixes. 1822347Spst Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. 1922347Spst Removed useless string. ifdef around some headers. 2022347Spst Modified at NRL for OPIE 2.1. Optimized for only one pipe at a time. 2122347Spst Added minimal version of sigprocmask(). Moved some pid_t 2222347Spst dancing to the config headers. 2322347Spst Modified at NRL for OPIE 2.0. 2422347Spst Originally from BSD. 2522347Spst 2622347Spst*/ 2722347Spst/* 2829964Sache * Copyright (c) 1988, 1993, 1994 2929964Sache * The Regents of the University of California. All rights reserved. 3022347Spst * 3122347Spst * This code is derived from software written by Ken Arnold and 3222347Spst * published in UNIX Review, Vol. 6, No. 8. 3322347Spst * 3422347Spst * Redistribution and use in source and binary forms, with or without 3522347Spst * modification, are permitted provided that the following conditions 3622347Spst * are met: 3722347Spst * 1. Redistributions of source code must retain the above copyright 3822347Spst * notice, this list of conditions and the following disclaimer. 3922347Spst * 2. Redistributions in binary form must reproduce the above copyright 4022347Spst * notice, this list of conditions and the following disclaimer in the 4122347Spst * documentation and/or other materials provided with the distribution. 4222347Spst * 3. All advertising materials mentioning features or use of this software 4322347Spst * must display the following acknowledgement: 4422347Spst * This product includes software developed by the University of 4522347Spst * California, Berkeley and its contributors. 4622347Spst * 4. Neither the name of the University nor the names of its contributors 4722347Spst * may be used to endorse or promote products derived from this software 4822347Spst * without specific prior written permission. 4922347Spst * 5022347Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5122347Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5222347Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5322347Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5422347Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5522347Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5622347Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5722347Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5822347Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5922347Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6022347Spst * SUCH DAMAGE. 6122347Spst * 6222347Spst */ 6322347Spst 6422347Spst#include "opie_cfg.h" 6522347Spst 6622347Spst#include <sys/types.h> 6722347Spst#include <sys/wait.h> 6822347Spst#if HAVE_SIGNAL_H 6922347Spst#include <signal.h> 7022347Spst#endif /* HAVE_SIGNAL_H */ 7122347Spst#if HAVE_SYS_SIGNAL_H 7222347Spst#include <sys/signal.h> 7322347Spst#endif /* HAVE_SYS_SIGNAL_H */ 7422347Spst#if HAVE_UNISTD_H 7522347Spst#include <unistd.h> 7622347Spst#endif /* HAVE_UNISTD_H */ 7722347Spst#include <stdio.h> 7822347Spst#if HAVE_STDLIB_H 7922347Spst#include <stdlib.h> 8022347Spst#endif /* HAVE_STDLIB_H */ 8122347Spst#if HAVE_STRING_H 8222347Spst#include <string.h> 8322347Spst#endif /* HAVE_STRING_H */ 8422347Spst 8522347Spst#include "opie.h" 8622347Spst 8722347Spstchar **ftpglob __P((register char *)); 8822347Spstchar **copyblk __P((char **)); 8922347SpstVOIDRET blkfree __P((char **)); 9022347Spst 9122347Spst/* 9229964Sache * Special version of popen which avoids call to shell. This ensures noone 9322347Spst * may create a pipe to a hidden program as a side effect of a list or dir 9422347Spst * command. 9522347Spst */ 9622347Spststatic pid_t child_pid = -1; 9722347Spststatic int pipe_fd; 9822347Spst 9929964Sacheextern char **environ; 10029964Sache 10122347SpstFILE *ftpd_popen FUNCTION((program, type), char *program AND char *type) 10222347Spst{ 10329964Sache char *cp; 10422347Spst FILE *iop; 10522347Spst int argc, gargc, pdes[2]; 10622347Spst char **pop, *argv[100], *gargv[1000], *vv[2]; 10722347Spst 10822347Spst if ((*type != 'r' && *type != 'w') || type[1]) 10922347Spst return (NULL); 11022347Spst 11122347Spst if (pipe(pdes) < 0) 11222347Spst return (NULL); 11322347Spst 11422347Spst /* break up string into pieces */ 11522347Spst for (argc = 0, cp = program;; cp = NULL) 11622347Spst if (!(argv[argc++] = strtok(cp, " \t\n"))) 11722347Spst break; 11822347Spst 11922347Spst /* glob each piece */ 12022347Spst gargv[0] = argv[0]; 12122347Spst for (gargc = argc = 1; argv[argc]; argc++) { 12222347Spst if (!(pop = (char **) ftpglob(argv[argc]))) { 12322347Spst /* globbing failed */ 12422347Spst vv[0] = argv[argc]; 12522347Spst vv[1] = NULL; 12622347Spst pop = (char **) copyblk(vv); 12722347Spst } 12822347Spst argv[argc] = (char *) pop; /* save to free later */ 12922347Spst while (*pop && gargc < 1000) 13022347Spst gargv[gargc++] = *pop++; 13122347Spst } 13222347Spst gargv[gargc] = NULL; 13322347Spst 13422347Spst iop = NULL; 13522347Spst switch (child_pid = fork()) { 13622347Spst case -1: /* error */ 13722347Spst close(pdes[0]); 13822347Spst close(pdes[1]); 13922347Spst goto pfree; 14022347Spst /* NOTREACHED */ 14122347Spst case 0: /* child */ 14222347Spst if (*type == 'r') { 14322347Spst if (pdes[1] != 1) { 14422347Spst dup2(pdes[1], 1); 14522347Spst dup2(pdes[1], 2); /* stderr, too! */ 14622347Spst close(pdes[1]); 14722347Spst } 14822347Spst close(pdes[0]); 14922347Spst } else { 15022347Spst if (pdes[0] != 0) { 15122347Spst dup2(pdes[0], 0); 15222347Spst close(pdes[0]); 15322347Spst } 15422347Spst close(pdes[1]); 15522347Spst } 15629964Sache environ = NULL; 15722347Spst execv(gargv[0], gargv); 15822347Spst _exit(1); 15922347Spst } 16022347Spst 16122347Spst /* parent; assume fdopen can't fail... */ 16222347Spst if (*type == 'r') { 16322347Spst iop = fdopen(pipe_fd = pdes[0], type); 16422347Spst close(pdes[1]); 16522347Spst } else { 16622347Spst iop = fdopen(pipe_fd = pdes[1], type); 16722347Spst close(pdes[0]); 16822347Spst } 16922347Spst 17022347Spstpfree: for (argc = 1; argv[argc] != NULL; argc++) { 17122347Spst blkfree((char **) argv[argc]); 17222347Spst free((char *) argv[argc]); 17322347Spst } 17422347Spst return (iop); 17522347Spst} 17622347Spst 17722347Spstint ftpd_pclose FUNCTION((iop), FILE *iop) 17822347Spst{ 17922347Spst int status; 18022347Spst pid_t pid; 18122347Spst sigset_t omask, mask; 18222347Spst 18322347Spst sigemptyset(&mask); 18422347Spst sigaddset(&mask, SIGINT); 18522347Spst sigaddset(&mask, SIGQUIT); 18622347Spst sigaddset(&mask, SIGHUP); 18722347Spst 18822347Spst /* pclose returns -1 if stream is not associated with a `popened' command, 18922347Spst or, if already `pclosed'. */ 19022347Spst if ((child_pid < 0) || (fileno(iop) != pipe_fd)) 19122347Spst return (-1); 19222347Spst 19322347Spst fclose(iop); 19422347Spst sigprocmask(SIG_BLOCK, &mask, &omask); 19522347Spst 19622347Spst while ((pid = wait(&status)) != child_pid && (pid != -1)); 19722347Spst sigprocmask(SIG_SETMASK, &omask, NULL); 19822347Spst 19922347Spst child_pid = -1; 20022347Spst pipe_fd = -1; 20122347Spst 20229964Sache#if defined(WEXITSTATUS) && defined(WIFEXITED) 20329964Sache if ((pid > 0) && WIFEXITED(status)) 20429964Sache return WEXITSTATUS(status); 20529964Sache 20629964Sache return -1; 20729964Sache#else /* defined(WEXITSTATUS) && defined(WIFEXITED) */ 20822347Spst return (pid == -1 ? -1 : status.w_status); 20929964Sache#endif /* defined(WEXITSTATUS) && defined(WIFEXITED) */ 21022347Spst} 211