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