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