popen.c revision 117501
153813Simp/* popen.c: A "safe" pipe open routine.
2180314Simp
3100213Simp%%% portions-copyright-cmetz-96
452506SimpPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights
552506SimpReserved. The Inner Net License Version 2 applies to these portions of
6140752Simpthe software.
752506SimpYou should have received a copy of the license with this software. If
852506Simpyou didn't get a copy, you may request one from <license@inner.net>.
952506Simp
1052506SimpPortions of this software are Copyright 1995 by Randall Atkinson and Dan
1152506SimpMcDonald, All Rights Reserved. All Rights under this copyright are assigned
1252506Simpto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
1352506SimpLicense Agreement applies to this software.
1452506Simp
1552506Simp	History:
1652506Simp
1752506Simp	Modified by cmetz for OPIE 2.31. Merged in some 4.4BSD-Lite fixes.
1852506Simp	Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al.
1952506Simp                Removed useless string. ifdef around some headers.
2052506Simp        Modified at NRL for OPIE 2.1. Optimized for only one pipe at a time.
2152506Simp                Added minimal version of sigprocmask(). Moved some pid_t
2252506Simp		dancing to the config headers.
2352506Simp	Modified at NRL for OPIE 2.0.
2452506Simp	Originally from BSD.
2552506Simp
2652506Simp$FreeBSD: head/contrib/opie/popen.c 117501 2003-07-13 05:59:50Z kris $
2752506Simp*/
2852506Simp/*
2952506Simp * Copyright (c) 1988, 1993, 1994
3052506Simp *     The Regents of the University of California.  All rights reserved.
3152506Simp *
3252506Simp * This code is derived from software written by Ken Arnold and
3352506Simp * published in UNIX Review, Vol. 6, No. 8.
34140752Simp *
35140752Simp * Redistribution and use in source and binary forms, with or without
36140752Simp * modification, are permitted provided that the following conditions
37140752Simp * are met:
38140752Simp * 1. Redistributions of source code must retain the above copyright
39140752Simp *    notice, this list of conditions and the following disclaimer.
40140752Simp * 2. Redistributions in binary form must reproduce the above copyright
41140752Simp *    notice, this list of conditions and the following disclaimer in the
42140752Simp *    documentation and/or other materials provided with the distribution.
43140752Simp * 3. All advertising materials mentioning features or use of this software
44140752Simp *    must display the following acknowledgement:
45140752Simp *      This product includes software developed by the University of
46140752Simp *      California, Berkeley and its contributors.
47140752Simp * 4. Neither the name of the University nor the names of its contributors
48140752Simp *    may be used to endorse or promote products derived from this software
49140752Simp *    without specific prior written permission.
50140752Simp *
51140752Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52140752Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53140752Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54140752Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55140752Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56140752Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57140752Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58140752Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59140752Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60140752Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6152506Simp * SUCH DAMAGE.
62140749Simp *
63166788Simp */
64140749Simp
65140749Simp#include "opie_cfg.h"
66140749Simp
67149869Simp#include <sys/types.h>
68149869Simp#include <sys/wait.h>
69149561Simp#if HAVE_SIGNAL_H
70166787Simp#include <signal.h>
71166787Simp#endif /* HAVE_SIGNAL_H */
72166787Simp#if HAVE_SYS_SIGNAL_H
73166787Simp#include <sys/signal.h>
74149869Simp#endif /* HAVE_SYS_SIGNAL_H */
75149869Simp#if HAVE_UNISTD_H
7652506Simp#include <unistd.h>
77140793Simp#endif /* HAVE_UNISTD_H */
78189680Simp#include <stdio.h>
79140793Simp#if HAVE_STDLIB_H
8058545Simp#include <stdlib.h>
8152506Simp#endif /* HAVE_STDLIB_H */
8265039Simp#if HAVE_STRING_H
8365039Simp#include <string.h>
84149869Simp#endif /* HAVE_STRING_H */
8552506Simp
86140793Simp#include "opie.h"
87149869Simp
88149869Simp#define MAXUSRARGS	100
89149869Simp#define MAXGLOBARGS	1000
90149869Simp
91149869Simpchar **ftpglob __P((register char *));
92149869Simpchar **copyblk __P((char **));
93149869SimpVOIDRET blkfree __P((char **));
94149869Simp
95149869Simp/*
96140793Simp * Special version of popen which avoids call to shell.  This ensures noone
9752506Simp * may create a pipe to a hidden program as a side effect of a list or dir
9852506Simp * command.
9952506Simp */
10052506Simpstatic pid_t child_pid = -1;
10158545Simpstatic int pipe_fd;
10252506Simp
10386455Simpextern char **environ;
10479270Simp
105107359SnonFILE *ftpd_popen FUNCTION((program, type), char *program AND char *type)
10652506Simp{
10786269Simp  char *cp;
10886455Simp  FILE *iop;
109119225Simp  int argc, gargc, pdes[2];
11052506Simp  char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS], *vv[2];
111140749Simp
11286455Simp  if ((*type != 'r' && *type != 'w') || type[1])
11358545Simp    return (NULL);
114104854Simp
115140886Simp  if (pipe(pdes) < 0)
11652506Simp    return (NULL);
11786455Simp
11852506Simp  /* break up string into pieces */
11986455Simp  for (argc = 0, cp = program; argc < MAXUSRARGS-1; cp = NULL) {
12053813Simp    if (!(argv[argc++] = strtok(cp, " \t\n")))
121148141Simp      break;
122100213Simp  }
12358545Simp  argv[argc - 1] = NULL;
12489945Simp
12584514Simp  /* glob each piece */
126147872Simp  gargv[0] = argv[0];
12758545Simp  for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) {
128119234Simp    if (!(pop = (char **) ftpglob(argv[argc]))) {
12969138Speter      /* globbing failed */
130118634Simp      vv[0] = argv[argc];
131149561Simp      vv[1] = NULL;
132172572Sremko      pop = (char **) copyblk(vv);
13352506Simp    }
13458545Simp    argv[argc] = (char *) pop;	/* save to free later */
135140837Simp    while (*pop && gargc < MAXGLOBARGS-1)
136140793Simp      gargv[gargc++] = *pop++;
137140793Simp  }
138147872Simp  gargv[gargc] = NULL;
139140793Simp
140176868Srink  iop = NULL;
14158545Simp  switch (child_pid = fork()) {
14265039Simp  case -1:	/* error */
14392471Simp    close(pdes[0]);
144140793Simp    close(pdes[1]);
145116207Simp    goto pfree;
14684514Simp    /* NOTREACHED */
14779270Simp  case 0:	/* child */
148140793Simp    if (*type == 'r') {
149190476Simp      if (pdes[1] != 1) {
15079270Simp	dup2(pdes[1], 1);
151117438Simp	dup2(pdes[1], 2);	/* stderr, too! */
152117602Simp	close(pdes[1]);
153148141Simp      }
154118895Simp      close(pdes[0]);
155119240Simp    } else {
156119240Simp      if (pdes[0] != 0) {
157119240Simp	dup2(pdes[0], 0);
158119240Simp	close(pdes[0]);
15993620Simp      }
16086455Simp      close(pdes[1]);
161119240Simp    }
162119240Simp    environ = NULL;
163119240Simp    execv(gargv[0], gargv);
164119240Simp    _exit(1);
165119240Simp  }
166140793Simp
167119240Simp  /* parent; assume fdopen can't fail...  */
168141122Simp  if (*type == 'r') {
169141122Simp    iop = fdopen(pipe_fd = pdes[0], type);
170141122Simp    close(pdes[1]);
171141122Simp  } else {
172141122Simp    iop = fdopen(pipe_fd = pdes[1], type);
173141122Simp    close(pdes[0]);
174141122Simp  }
175141122Simp
176145247Sdamienpfree: for (argc = 1; argv[argc] != NULL; argc++) {
177141122Simp    blkfree((char **) argv[argc]);
178119240Simp    free((char *) argv[argc]);
179119240Simp  }
180140792Simp  return (iop);
181140792Simp}
182141122Simp
183119240Simpint ftpd_pclose FUNCTION((iop), FILE *iop)
184190429Simp{
185140793Simp  int status;
18686455Simp  pid_t pid;
18786455Simp  sigset_t omask, mask;
18889945Simp
189149869Simp  sigemptyset(&mask);
19053813Simp  sigaddset(&mask, SIGINT);
191189679Simp  sigaddset(&mask, SIGQUIT);
19271279Simp  sigaddset(&mask, SIGHUP);
19371283Simp
194113667Ssanpei  /* pclose returns -1 if stream is not associated with a `popened' command,
19553813Simp     or, if already `pclosed'. */
19652506Simp  if ((child_pid < 0) || (fileno(iop) != pipe_fd))
197140793Simp    return (-1);
198140792Simp
199107359Snon  fclose(iop);
20071283Simp  sigprocmask(SIG_BLOCK, &mask, &omask);
20152506Simp
20252506Simp  while ((pid = wait(&status)) != child_pid && (pid != -1));
20386269Simp  sigprocmask(SIG_SETMASK, &omask, NULL);
20486269Simp
20552506Simp  child_pid = -1;
20653813Simp  pipe_fd = -1;
20752506Simp
20865039Simp#if defined(WEXITSTATUS) && defined(WIFEXITED)
20986269Simp  if ((pid > 0) && WIFEXITED(status))
21086269Simp    return WEXITSTATUS(status);
21186269Simp
212135002Semax  return -1;
21386269Simp#else /* defined(WEXITSTATUS) && defined(WIFEXITED) */
21452506Simp  return (pid == -1 ? -1 : status.w_status);
21552506Simp#endif /* defined(WEXITSTATUS) && defined(WIFEXITED) */
21652506Simp}
217180314Simp