root/popen.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _lock_popen_map
  2. _unlock_popen_map
  3. popen
  4. pclose
  5. dmtcp_is_popen_fp

   1 /****************************************************************************
   2  *   Copyright (C) 2006-2013 by Jason Ansel, Kapil Arya, and Gene Cooperman *
   3  *   jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu              *
   4  *                                                                          *
   5  *  This file is part of DMTCP.                                             *
   6  *                                                                          *
   7  *  DMTCP is free software: you can redistribute it and/or                  *
   8  *  modify it under the terms of the GNU Lesser General Public License as   *
   9  *  published by the Free Software Foundation, either version 3 of the      *
  10  *  License, or (at your option) any later version.                         *
  11  *                                                                          *
  12  *  DMTCP is distributed in the hope that it will be useful,                *
  13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of          *
  14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
  15  *  GNU Lesser General Public License for more details.                     *
  16  *                                                                          *
  17  *  You should have received a copy of the GNU Lesser General Public        *
  18  *  License along with DMTCP:dmtcp/src.  If not, see                        *
  19  *  <http://www.gnu.org/licenses/>.                                         *
  20  ****************************************************************************/
  21 
  22 #include "syscallwrappers.h"
  23 #include "threadsync.h"
  24 #include "../jalib/jassert.h"
  25 
  26 using namespace dmtcp;
  27 
  28 static map<FILE*, pid_t> _dmtcpPopenPidMap;
  29 typedef map<FILE*, pid_t>::iterator _dmtcpPopenPidMapIterator;
  30 
  31 static pthread_mutex_t popen_map_lock = PTHREAD_MUTEX_INITIALIZER;
  32 
  33 static void _lock_popen_map()
  34 {
  35   JASSERT(_real_pthread_mutex_lock(&popen_map_lock) == 0) (JASSERT_ERRNO);
  36 }
  37 
  38 static void _unlock_popen_map()
  39 {
  40   JASSERT(_real_pthread_mutex_unlock(&popen_map_lock) == 0) (JASSERT_ERRNO);
  41 }
  42 
  43 extern "C"
  44 FILE *popen(const char *command, const char *mode)
  45 {
  46   FILE *fp;
  47   int parent_fd, child_fd;
  48   int pipe_fds[2];
  49   pid_t child_pid;
  50   char new_mode[2] = "r";
  51 
  52   int do_read = 0;
  53   int do_write = 0;
  54   int do_cloexec = 0;
  55   while (*mode != '\0') {
  56     switch (*mode++) {
  57       case 'r':
  58         do_read = 1;
  59         break;
  60       case 'w':
  61         do_write = 1;
  62         break;
  63       case 'e':
  64         do_cloexec = 1;
  65         break;
  66       default:
  67         errno = EINVAL;
  68         return NULL;
  69     }
  70   }
  71 
  72   if ((do_read ^ do_write) == 0) {
  73     errno = EINVAL;
  74     return NULL;
  75   }
  76 
  77   {
  78     WRAPPER_EXECUTION_DISABLE_CKPT();
  79     if (pipe(pipe_fds) < 0) {
  80       return NULL;
  81     }
  82     // Mark the parent_end with FD_CLOEXEC so that if there is fork/exec while
  83     // we are inside this wrapper, these fds are closed.
  84     fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC);
  85     fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC);
  86 
  87     if (do_read) {
  88       parent_fd = pipe_fds[0];
  89       child_fd = pipe_fds[1];
  90       strcpy(new_mode, "r");
  91     } else {
  92       parent_fd = pipe_fds[1];
  93       child_fd = pipe_fds[0];
  94       strcpy(new_mode, "w");
  95     }
  96     WRAPPER_EXECUTION_ENABLE_CKPT();
  97   }
  98 
  99   child_pid = fork();
 100   if (child_pid == 0) {
 101     int child_std_fd = do_read ? STDOUT_FILENO : STDIN_FILENO;
 102     close(parent_fd);
 103     if (child_fd != child_std_fd) {
 104       dup2(child_fd, child_std_fd);
 105       close(child_fd);
 106     }
 107     /* POSIX.2:  "popen() shall ensure that any streams from previous
 108        popen() calls that remain open in the parent process are closed
 109        in the new child process." */
 110     _dmtcpPopenPidMapIterator it;
 111     for (it = _dmtcpPopenPidMap.begin(); it != _dmtcpPopenPidMap.end(); it++) {
 112       int fd = fileno(it->first);
 113       /* If any stream from previous popen() calls has fileno
 114          child_std_end, it has been already closed by the dup2 syscall
 115          above.  */
 116       if (fd != child_std_fd) {
 117         _real_fclose(it->first);
 118       }
 119     }
 120     _dmtcpPopenPidMap.clear();
 121 
 122     fcntl(child_std_fd, F_SETFD, 0);
 123     execl("/bin/sh", "sh", "-c", command, (char *) 0);
 124     exit(127);
 125   }
 126   close(child_fd);
 127   if (child_pid < 0) {
 128     close(parent_fd);
 129     return NULL;
 130   }
 131 
 132   {
 133     WRAPPER_EXECUTION_DISABLE_CKPT();
 134     fp = fdopen(parent_fd, new_mode);
 135     if (!do_cloexec) {
 136       fcntl(parent_fd, F_SETFD, 0);
 137     }
 138     _lock_popen_map();
 139     _dmtcpPopenPidMap[fp] = child_pid;
 140     _unlock_popen_map();
 141     WRAPPER_EXECUTION_ENABLE_CKPT();
 142   }
 143 
 144   return fp;
 145 }
 146 
 147 extern "C"
 148 int pclose(FILE *fp)
 149 {
 150   _dmtcpPopenPidMapIterator it;
 151   int wstatus;
 152   pid_t pid = -1;
 153   pid_t wait_pid;
 154 
 155   _lock_popen_map();
 156   it = _dmtcpPopenPidMap.find(fp);
 157   if (it != _dmtcpPopenPidMap.end()) {
 158     fp = it->first;
 159     pid = it->second;
 160     _dmtcpPopenPidMap.erase(it);
 161   }
 162   _unlock_popen_map();
 163 
 164   if (pid == -1 || _real_fclose(fp) != 0) {
 165     return -1;
 166   }
 167 
 168   do {
 169     wait_pid = waitpid(pid, &wstatus, 0);
 170   } while (wait_pid == -1 && errno == EINTR);
 171   if (wait_pid == -1) {
 172     return -1;
 173   }
 174   return wstatus;
 175 }
 176 
 177 EXTERNC int dmtcp_is_popen_fp(FILE *fp)
 178 {
 179   int popen_fp = 0;
 180   _lock_popen_map();
 181   if (_dmtcpPopenPidMap.find(fp) != _dmtcpPopenPidMap.end()) {
 182     popen_fp = 1;
 183   }
 184   _unlock_popen_map();
 185   return popen_fp;
 186 }

/* [<][>][^][v][top][bottom][index][help] */