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