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