root/src/popen.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. cron_popen
  2. cron_pclose

   1 /*      $NetBSD: popen.c,v 1.9 2005/03/16 02:53:55 xtraeme Exp $        */
   2 
   3 /*
   4  * Copyright (c) 1988, 1993, 1994
   5  *      The Regents of the University of California.  All rights reserved.
   6  *
   7  * This code is derived from software written by Ken Arnold and
   8  * published in UNIX Review, Vol. 6, No. 8.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  * 1. Redistributions of source code must retain the above copyright
  14  *    notice, this list of conditions and the following disclaimer.
  15  * 2. Redistributions in binary form must reproduce the above copyright
  16  *    notice, this list of conditions and the following disclaimer in the
  17  *    documentation and/or other materials provided with the distribution.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29  * SUCH DAMAGE.
  30  *
  31  */
  32 
  33 #include "config.h"
  34 
  35 #include <errno.h>
  36 #include <pwd.h>
  37 #include <stdio.h>
  38 #include <stdlib.h>
  39 #include <string.h>
  40 #include <sys/wait.h>
  41 #include <unistd.h>
  42 
  43 #include "funcs.h"
  44 #include "globals.h"
  45 #include "macros.h"
  46 
  47 #ifdef HAVE_SYS_CDEFS_H
  48 # include <sys/cdefs.h>
  49 #endif
  50 
  51 #include <signal.h>
  52 
  53 /*
  54  * Special version of popen which avoids call to shell.  This insures noone
  55  * may create a pipe to a hidden program as a side effect of a list or dir
  56  * command.
  57  */
  58 static PID_T *pids;
  59 static int fds;
  60 
  61 #define MAX_ARGS 1024
  62 
  63 FILE *cron_popen(char *program, const char *type, struct passwd *pw, char **jobenv) {
     /* [previous][next][first][last][top][bottom][index][help]  */
  64         char *cp;
  65         FILE *iop;
  66         int argc, pdes[2];
  67         PID_T pid;
  68         char *argv[MAX_ARGS];
  69         ssize_t out;
  70         char buf[PIPE_BUF];
  71         struct sigaction sa;
  72         int fd;
  73 
  74 #ifdef __GNUC__
  75         (void) &iop;    /* Avoid fork clobbering */
  76 #endif
  77 
  78         if ((*type != 'r' && *type != 'w') || type[1])
  79                 return (NULL);
  80 
  81         if (!pids) {
  82                 if ((fds = getdtablesize()) <= 0)
  83                         return (NULL);
  84                 if (!(pids = (PID_T *) malloc((u_int) ((size_t)fds * sizeof (PID_T)))))
  85                         return (NULL);
  86                 memset((char *) pids, 0, (size_t)fds * sizeof (PID_T));
  87         }
  88         if (pipe(pdes) < 0)
  89                 return (NULL);
  90 
  91         /* break up string into pieces */
  92         for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL)
  93                 if (!(argv[argc++] = strtok(cp, " \t\n")))
  94                         break;
  95 
  96         iop = NULL;
  97         switch (pid = fork()) {
  98         case -1:        /* error */
  99                 (void) close(pdes[0]);
 100                 (void) close(pdes[1]);
 101                 goto pfree;
 102                 /* NOTREACHED */
 103         case 0: /* child */
 104                 if (*type == 'r') {
 105                         if (pdes[1] != STDOUT) {
 106                                 dup2(pdes[1], STDOUT);
 107                                 dup2(pdes[1], STDERR);  /* stderr, too! */
 108                                 (void) close(pdes[1]);
 109                         }
 110                         (void) close(pdes[0]);
 111                 }
 112                 else {
 113                         if (pdes[0] != STDIN) {
 114                                 dup2(pdes[0], STDIN);
 115                                 (void) close(pdes[0]);
 116                         }
 117                         (void) close(pdes[1]);
 118                 }
 119 
 120                 /* reset SIGPIPE to default for the child */
 121                 memset(&sa, 0, sizeof(sa));
 122                 sa.sa_handler = SIG_DFL;
 123                 sigaction(SIGPIPE, &sa, NULL);
 124 
 125                 /* close all unwanted open file descriptors */
 126                 for (fd = STDERR + 1; fd < fds; fd++) {
 127                         close(fd);
 128                 }
 129 
 130                 if (cron_change_user_permanently(pw, env_get("HOME", jobenv)) != 0)
 131                         _exit(2);
 132 
 133                 if (execvpe(argv[0], argv, jobenv) < 0) {
 134                         int save_errno = errno;
 135 
 136                         log_it("CRON", getpid(), "EXEC FAILED", program, save_errno);
 137                         if (*type != 'r') {
 138                                 while (0 != (out = read(STDIN, buf, PIPE_BUF))) {
 139                                         if ((out == -1) && (errno != EINTR))
 140                                                 break;
 141                                 }
 142                         }
 143                 }
 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         }
 151         else {
 152                 iop = fdopen(pdes[1], type);
 153                 (void) close(pdes[0]);
 154         }
 155         pids[fileno(iop)] = pid;
 156 
 157   pfree:
 158         return (iop);
 159 }
 160 
 161 int cron_pclose(FILE * iop) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 162         int fdes;
 163         sigset_t oset, nset;
 164         WAIT_T stat_loc;
 165         PID_T pid;
 166 
 167         /*
 168          * pclose returns -1 if stream is not associated with a
 169          * `popened' command, or, if already `pclosed'.
 170          */
 171         if (pids == 0 || pids[fdes = fileno(iop)] == 0)
 172                 return (-1);
 173         (void) fclose(iop);
 174 
 175         sigemptyset(&nset);
 176         sigaddset(&nset, SIGINT);
 177         sigaddset(&nset, SIGQUIT);
 178         sigaddset(&nset, SIGHUP);
 179         (void) sigprocmask(SIG_BLOCK, &nset, &oset);
 180         while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1) ;
 181         (void) sigprocmask(SIG_SETMASK, &oset, NULL);
 182         pids[fdes] = 0;
 183         return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
 184 }

/* [previous][next][first][last][top][bottom][index][help]  */