home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / ftpd / popen.c < prev   
C/C++ Source or Header  |  1996-09-28  |  5KB  |  207 lines

  1. /*
  2.  * Copyright (c) 1988, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * This code is derived from software written by Ken Arnold and
  6.  * published in UNIX Review, Vol. 6, No. 8.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  */
  37.  
  38. #ifndef lint
  39. static char sccsid[] = "@(#)popen.c    8.3 (Berkeley) 4/6/94";
  40. #endif /* not lint */
  41.  
  42. #ifdef HAVE_CONFIG_H
  43. #include <config.h>
  44. #endif
  45.  
  46. #include <sys/types.h>
  47. #include <sys/wait.h>
  48.  
  49. #include <errno.h>
  50. #include <glob.h>
  51. #include <signal.h>
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include <unistd.h>
  56.  
  57. #include "extern.h"
  58.  
  59. /*
  60.  * Special version of popen which avoids call to shell.  This ensures noone
  61.  * may create a pipe to a hidden program as a side effect of a list or dir
  62.  * command.
  63.  */
  64.  
  65. struct file_pid {
  66.       FILE *file;
  67.     pid_t pid;
  68.     struct file_pid *next;
  69. };
  70.  
  71. /* A linked list associating ftpd_popen'd FILEs with pids.  */
  72. struct file_pid *file_pids = 0;
  73.  
  74. FILE *
  75. ftpd_popen(program, type)
  76.     char *program, *type;
  77. {
  78.     char *cp;
  79.     FILE *iop;
  80.     struct file_pid *fpid;
  81.     int argc, gargc, pdes[2], pid;
  82.     char **pop, *argv[100], *gargv[1000];
  83.  
  84.     if (*type != 'r' && *type != 'w' || type[1])
  85.         return (NULL);
  86.  
  87.     if (pipe(pdes) < 0)
  88.         return (NULL);
  89.  
  90.     /* break up string into pieces */
  91.     for (argc = 0, cp = program;; cp = NULL)
  92.         if (!(argv[argc++] = strtok(cp, " \t\n")))
  93.             break;
  94.  
  95.     /* glob each piece */
  96.     gargv[0] = argv[0];
  97.     for (gargc = argc = 1; argv[argc]; argc++) {
  98.         glob_t gl;
  99.         int flags = GLOB_NOCHECK;
  100.  
  101. #ifdef GLOB_BRACE
  102.                 flags |= GLOB_BRACE;
  103. #endif
  104. #ifdef GLOB_QUOTE
  105.                 flags |= GLOB_QUOTE;
  106. #endif
  107. #ifdef GLOB_TILDE
  108.                 flags |= GLOB_TILDE;
  109. #endif
  110.  
  111.         memset(&gl, 0, sizeof(gl));
  112.         if (glob(argv[argc], flags, NULL, &gl))
  113.             gargv[gargc++] = strdup(argv[argc]);
  114.         else
  115.             for (pop = gl.gl_pathv; *pop; pop++)
  116.                 gargv[gargc++] = strdup(*pop);
  117.         globfree(&gl);
  118.     }
  119.     gargv[gargc] = NULL;
  120.  
  121.     iop = NULL;
  122.     switch(pid = vfork()) {
  123.     case -1:            /* error */
  124.         (void)close(pdes[0]);
  125.         (void)close(pdes[1]);
  126.         goto pfree;
  127.         /* NOTREACHED */
  128.     case 0:                /* child */
  129.         if (*type == 'r') {
  130.             if (pdes[1] != STDOUT_FILENO) {
  131.                 dup2(pdes[1], STDOUT_FILENO);
  132.                 (void)close(pdes[1]);
  133.             }
  134.             dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
  135.             (void)close(pdes[0]);
  136.         } else {
  137.             if (pdes[0] != STDIN_FILENO) {
  138.                 dup2(pdes[0], STDIN_FILENO);
  139.                 (void)close(pdes[0]);
  140.             }
  141.             (void)close(pdes[1]);
  142.         }
  143.         execv(gargv[0], gargv);
  144.         _exit(1);
  145.     }
  146.     /* parent; assume fdopen can't fail...  */
  147.     if (*type == 'r') {
  148.         iop = fdopen(pdes[0], type);
  149.         (void)close(pdes[1]);
  150.     } else {
  151.         iop = fdopen(pdes[1], type);
  152.         (void)close(pdes[0]);
  153.     }
  154.  
  155.     fpid = malloc (sizeof (struct file_pid));
  156.     if (fpid) {
  157.         fpid->file = iop;
  158.         fpid->pid = pid;
  159.         fpid->next = file_pids;
  160.         file_pids = fpid;
  161.     }
  162.  
  163. pfree:    for (argc = 1; gargv[argc] != NULL; argc++)
  164.         free(gargv[argc]);
  165.  
  166.     return (iop);
  167. }
  168.  
  169. int
  170. ftpd_pclose(iop)
  171.     FILE *iop;
  172. {
  173.     struct file_pid *fpid = file_pids, *prev_fpid = 0;
  174.     int fdes, omask, status;
  175.     pid_t pid;
  176.  
  177.     /*
  178.      * pclose returns -1 if stream is not associated with a
  179.      * `popened' command, or, if already `pclosed'.
  180.      */
  181.     while (fpid && fpid->file != iop) {
  182.          prev_fpid = fpid;
  183.          fpid = fpid->next;
  184.     }
  185.     if (! fpid)
  186.             return -1;
  187.  
  188.     if (prev_fpid)
  189.         prev_fpid->next = fpid->next;
  190.     else
  191.         file_pids = fpid->next;
  192.  
  193.     (void)fclose(iop);
  194.     omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
  195.     while ((pid = waitpid(fpid->pid, &status, 0)) < 0 && errno == EINTR)
  196.         continue;
  197.  
  198.     free (fpid);
  199.  
  200.     (void)sigsetmask(omask);
  201.     if (pid < 0)
  202.         return (pid);
  203.     if (WIFEXITED(status))
  204.         return (WEXITSTATUS(status));
  205.     return (1);
  206. }
  207.