root/execwrappers.cpp

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

DEFINITIONS

This source file includes following definitions.
  1. isPerformingCkptRestart
  2. isBlacklistedProgram
  3. pthread_atfork_prepare
  4. pthread_atfork_parent
  5. pthread_atfork_child
  6. fork
  7. vfork
  8. execShortLivedProcessAndExit
  9. dmtcpPrepareForExec
  10. dmtcpProcessFailedExec
  11. getUpdatedLdPreload
  12. copyEnv
  13. stringVectorToPointerArray
  14. isImportantEnv
  15. patchUserEnv
  16. execve
  17. execv
  18. execvp
  19. execvpe
  20. fexecve
  21. execl
  22. execlp
  23. execle
  24. system

   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 <sys/syscall.h>
  23 #ifdef __aarch64__
  24 # define __ARCH_WANT_SYSCALL_DEPRECATED
  25 // SYS_fork is a deprecated kernel call in aarch64; in favor of SYS_clone?
  26 # include <asm-generic/unistd.h>
  27 // SYS_fork undefined in aarch64, but add extra insurance
  28 # undef SYS_fork
  29 # define SYS_fork __NR_fork
  30 #endif
  31 #include "constants.h"
  32 #include "uniquepid.h"
  33 #include "dmtcpworker.h"
  34 #include "processinfo.h"
  35 #include "syscallwrappers.h"
  36 #include "syslogwrappers.h"
  37 #include "util.h"
  38 #include "coordinatorapi.h"
  39 #include "mtcpinterface.h"
  40 #include "shareddata.h"
  41 #include "threadsync.h"
  42 #include  "../jalib/jconvert.h"
  43 #include  "../jalib/jassert.h"
  44 #include  "../jalib/jfilesystem.h"
  45 
  46 #define INITIAL_ARGV_MAX 32
  47 
  48 using namespace dmtcp;
  49 
  50 #ifdef DEBUG
  51   const static bool dbg = true;
  52 #else
  53   const static bool dbg = false;
  54 #endif
  55 
  56 static bool pthread_atfork_enabled = false;
  57 static uint64_t child_time;
  58 static CoordinatorAPI coordinatorAPI;
  59 
  60 // Allow plugins to call fork/exec/system to perform specific tasks during
  61 // preCKpt/postCkpt/PostRestart etc. event.
  62 static bool isPerformingCkptRestart()
  63 {
  64   if (WorkerState::currentState() != WorkerState::UNKNOWN &&
  65       WorkerState::currentState() != WorkerState::RUNNING) {
  66     return true;
  67   }
  68   return false;
  69 }
  70 
  71 static bool isBlacklistedProgram(const char *path)
  72 {
  73   string programName = jalib::Filesystem::BaseName(path);
  74 
  75   JASSERT(programName != "dmtcp_coordinator" &&
  76           programName != "dmtcp_launch"  &&
  77           programName != "dmtcp_restart"     &&
  78           programName != "mtcp_restart")
  79     (programName) .Text("This program should not be run under ckpt control");
  80 
  81   /*
  82    * When running gdb or any shell which does a waitpid() on the child
  83    * processes, executing dmtcp_command from within gdb session / shell results
  84    * in process getting hung up because:
  85    *   gdb shell dmtcp_command -c => hangs because gdb forks off a new process
  86    *   and it does a waitpid  (in which we block signals) ...
  87    */
  88   if (programName == "dmtcp_command") {
  89     //make sure coordinator connection is closed
  90     _real_close (PROTECTED_COORD_FD);
  91 
  92     pid_t cpid = _real_fork();
  93     JASSERT(cpid != -1);
  94     if (cpid != 0) {
  95       _real_exit(0);
  96     }
  97   }
  98 
  99   if (programName == "dmtcp_nocheckpoint" || programName == "dmtcp_command" ||
 100       programName == "ssh") {
 101     return true;
 102   }
 103   return false;
 104 }
 105 
 106 LIB_PRIVATE void pthread_atfork_prepare()
 107 {
 108   /* FIXME: The user process might register a fork prepare handler with
 109    * pthread_atfork. That handler will be called _after_ we have acquired the
 110    * wrapper-exec lock in exclusive mode. This can lead to a deadlock situation
 111    * if the user process decides to do some operations that require calling a
 112    * dmtcp wrapper that require the wrapper-exec lock.
 113    *
 114    * Also, the preparation that dmtcp needs to do for fork() should be done
 115    * right before the child process is created, i.e. after all the user
 116    * handlers have been invoked. Fortunately, pthread_atfork prepare handlers
 117    * are called in reverse order or registration (as opposed to parent and
 118    * child handlers which are called in the order of registration), thus our
 119    * prepare handle will be called at the very last.
 120    *
 121    * FIXME: PID-conflict detection poses yet another serious problem. On a
 122    * pid-conflict, _real_fork() will be called more than once, resulting in
 123    * multiple calls of user-defined prepare handlers. This is undesired and can
 124    * cause several issues. One solution to this problem is to call the fork
 125    * system call directly whenever a tid-conflict is detected, however, it
 126    * might have some other side-effects.  Another possible solution would be to
 127    * have pid-virtualization plugin, which always assigns virtual pids, to the
 128    * newly created processes, and thus avoiding the pid-conflict totally.
 129    */
 130   return;
 131 }
 132 
 133 LIB_PRIVATE void pthread_atfork_parent()
 134 {
 135   return;
 136 }
 137 
 138 LIB_PRIVATE void pthread_atfork_child()
 139 {
 140   if (!pthread_atfork_enabled) {
 141     return;
 142   }
 143   pthread_atfork_enabled = false;
 144 
 145   uint64_t host = UniquePid::ThisProcess().hostid();
 146   UniquePid parent = UniquePid::ThisProcess();
 147   UniquePid child = UniquePid(host, getpid(), child_time);
 148   string child_name = jalib::Filesystem::GetProgramName() + "_(forked)";
 149   _dmtcp_remutex_on_fork();
 150   ThreadSync::resetLocks();
 151 
 152   UniquePid::resetOnFork(child);
 153   Util::initializeLogFile(child_name);
 154 
 155   ProcessInfo::instance().resetOnFork();
 156 
 157   JTRACE("fork()ed [CHILD]") (child) (parent);
 158   CoordinatorAPI::resetOnFork(coordinatorAPI);
 159   DmtcpWorker::resetOnFork();
 160 }
 161 
 162 extern "C" pid_t fork()
 163 {
 164   if (isPerformingCkptRestart()) {
 165     return _real_syscall(SYS_fork);
 166   }
 167 
 168   /* Acquire the wrapperExeution lock to prevent checkpoint to happen while
 169    * processing this system call.
 170    */
 171   WRAPPER_EXECUTION_GET_EXCL_LOCK();
 172   DmtcpWorker::eventHook(DMTCP_EVENT_ATFORK_PREPARE, NULL);
 173 
 174   /* Little bit cheating here: child_time should be same for both parent and
 175    * child, thus we compute it before forking the child. */
 176   child_time = time(NULL);
 177   uint64_t host = UniquePid::ThisProcess().hostid();
 178   UniquePid parent = UniquePid::ThisProcess();
 179   string child_name = jalib::Filesystem::GetProgramName() + "_(forked)";
 180 
 181   coordinatorAPI.createNewConnectionBeforeFork(child_name);
 182 
 183   //Enable the pthread_atfork child call
 184   pthread_atfork_enabled = true;
 185   pid_t childPid = _real_fork();
 186 
 187   if (childPid == -1) {
 188   } else if (childPid == 0) { /* child process */
 189     /* NOTE: Any work that needs to be done for the newly created child
 190      * should be put into pthread_atfork_child() function. That function is
 191      * hooked to the libc:fork() and will be called right after the new
 192      * process is created and before the fork() returns.
 193      *
 194      * pthread_atfork_child is registered by calling pthread_atfork() from
 195      * within the DmtcpWorker constructor to make sure that this is the first
 196      * registered handle.
 197      */
 198     UniquePid child = UniquePid(host, getpid(), child_time);
 199     JTRACE("fork() done [CHILD]") (child) (parent);
 200 
 201     initializeMtcpEngine();
 202   } else if (childPid > 0) { /* Parent Process */
 203     UniquePid child = UniquePid(host, childPid, child_time);
 204     ProcessInfo::instance().insertChild(childPid, child);
 205     JTRACE("fork()ed [PARENT] done") (child);;
 206   }
 207 
 208   pthread_atfork_enabled = false;
 209 
 210   if (childPid != 0) {
 211     coordinatorAPI.closeConnection();
 212     DmtcpWorker::eventHook(DMTCP_EVENT_ATFORK_PARENT, NULL);
 213     WRAPPER_EXECUTION_RELEASE_EXCL_LOCK();
 214   }
 215   return childPid;
 216 }
 217 
 218 extern "C" pid_t vfork()
 219 {
 220   JTRACE("vfork wrapper calling fork");
 221   // This might not preserve the full semantics of vfork.
 222   // Used for checkpointing gdb.
 223   return fork();
 224 }
 225 
 226 // Special short-lived processes from executables like /lib/libc.so.6
 227 //   and man setuid/setgid executables cannot be loaded with LD_PRELOAD.
 228 // Since they're short-lived, we execute them while holding a lock
 229 //   delaying checkpointing.
 230 static void execShortLivedProcessAndExit(const char *path, char *const argv[])
 231 {
 232   unsetenv("LD_PRELOAD"); // /lib/ld.so won't let us preload if exec'ing lib
 233   const unsigned int bufSize = 100000;
 234   char *buf = (char*)JALLOC_HELPER_MALLOC(bufSize);
 235   memset(buf, 0, bufSize);
 236   FILE *output;
 237   if (argv[0] == NULL) {
 238     output = _real_popen(path, "r");
 239   } else {
 240     string command = path;
 241     for (int i = 1; argv[i] != NULL; i++)
 242       command = command + " " + argv[i];
 243     output = _real_popen(command.c_str(), "r");
 244   }
 245   int numRead = fread(buf, 1, bufSize - 1, output);
 246   numRead++, numRead--; // suppress unused-var warning
 247 
 248   pclose(output); // /lib/libXXX process is now done; can checkpoint now
 249   // FIXME:  code currently allows wrapper to proceed without lock if
 250   //   it was busy because of a writer.  The unlock will then fail below.
 251   bool __wrapperExecutionLockAcquired = true; // needed for LOCK_UNLOCK macro
 252   WRAPPER_EXECUTION_RELEASE_EXCL_LOCK();
 253   // We  are now the new /lib/libXXX process, and it's safe for DMTCP to ckpt us.
 254   printf("%s", buf); // print buf, which is what /lib/libXXX would print
 255   JALLOC_HELPER_FREE(buf);
 256   // Avoid running exit handlers of the parent process by calling _exit.
 257   _exit(0);
 258 }
 259 
 260 // FIXME:  Unify this code with code prior to execvp in dmtcp_launch.cpp
 261 //   Can use argument to dmtcpPrepareForExec() or getenv("DMTCP_...")
 262 //   from DmtcpWorker constructor, to distinguish the two cases.
 263 static void dmtcpPrepareForExec(const char *path, char *const argv[],
 264                                 char **filename, char ***newArgv)
 265 {
 266   JTRACE("Preparing for Exec") (path);
 267 
 268   const char * libPrefix = "/lib/lib";
 269   const char * lib64Prefix = "/lib64/lib";
 270   if (path != NULL && Util::strStartsWith(path, libPrefix))
 271     execShortLivedProcessAndExit(path, argv);
 272   if (path != NULL && Util::strStartsWith(path, lib64Prefix))
 273     execShortLivedProcessAndExit(path, argv);
 274   // Needed for /usr/libexec/utempter/utempter and other short-lived
 275   //  setuid/setgid processes.
 276   // FIXME:  USE THIS FOR ALL setuid/setgid PROCESSES EXCEPT ONES THAT
 277   //         WE DIRECTLY HANDLE, LIKE 'screen'.  (Need to name special routine,
 278   //         execScreenProcess() ??)
 279   if (path != NULL && Util::strEndsWith(path, "/utempter")) {
 280     JTRACE("Trying to exec: utempter")(path)(argv[0])(argv[1]);
 281     int oldIdx = -1;
 282     char *oldStr = NULL;
 283     string realPtsNameStr;
 284     // utempter takes a pts slave name as an argument. Since we virtualize
 285     // ptys, the slave name points to a virtual slave name, thus we need to
 286     // replace it with the real one.
 287     for (size_t i = 0; argv[i] != NULL; i++) {
 288       if (Util::strStartsWith(argv[i], VIRT_PTS_PREFIX_STR)) {
 289         // FIXME: Potential memory leak if exec() fails.
 290         char *realPtsNameStr = (char*)JALLOC_HELPER_MALLOC(PTS_PATH_MAX);
 291         oldStr = argv[i];
 292         oldIdx = i;
 293         SharedData::getRealPtyName(argv[i], realPtsNameStr,
 294                                           PTS_PATH_MAX);
 295         // Override const restriction
 296         *(const char**)&argv[i] = realPtsNameStr;
 297       }
 298     }
 299     execShortLivedProcessAndExit(path, argv);
 300     if (oldIdx != -1) {
 301       // Restore original argv[] if exec failed.
 302       *(const char**)&argv[oldIdx] = oldStr;
 303     }
 304   }
 305 
 306   // FIXME:  SEE COMMENTS IN dmtcp_launch.cpp, rev. 1087; AND CHANGE THIS.
 307   if (Util::isSetuid(path)) {
 308     if (Util::isScreen(path)) {
 309       Util::setScreenDir();
 310     }
 311     // THIS NEXT LINE IS DANGEROUS.  MOST setuid PROGRAMS CAN'T RUN UNPRIVILEGED
 312     Util::patchArgvIfSetuid(path, argv, newArgv);
 313     // BUG:  Util::patchArgvIfSetuid() DOES NOT SET newArgv WHEN COPYING
 314     //   BINARY IN CODE RE-FACTORING FROM REVISION 911.
 315     *filename = (*newArgv)[0];
 316   } else {
 317     *filename = (char*)path;
 318     *newArgv = (char**)argv;
 319   }
 320 
 321   ostringstream os;
 322   os << dmtcp_get_tmpdir() << "/dmtcpLifeBoat." << UniquePid::ThisProcess()
 323      << "-XXXXXX";
 324   char *buf = (char*) JALLOC_HELPER_MALLOC(os.str().length()+1);
 325   strcpy(buf, os.str().c_str());
 326   int fd = _real_mkstemp(buf);
 327   JASSERT(fd != -1) (JASSERT_ERRNO);
 328   JASSERT(unlink(buf) == 0) (JASSERT_ERRNO);
 329   Util::changeFd(fd, PROTECTED_LIFEBOAT_FD);
 330   jalib::JBinarySerializeWriterRaw wr ("", PROTECTED_LIFEBOAT_FD);
 331   UniquePid::serialize (wr);
 332   DmtcpEventData_t edata;
 333   edata.serializerInfo.fd = PROTECTED_LIFEBOAT_FD;
 334   DmtcpWorker::eventHook(DMTCP_EVENT_PRE_EXEC, &edata);
 335 
 336   JTRACE("Will exec filename instead of path") (path) (*filename);
 337 
 338   Util::adjustRlimitStack();
 339   Util::prepareDlsymWrapper();
 340 
 341   // Remove FD_CLOEXEC flag from protected file descriptors.
 342   for (size_t i  = PROTECTED_FD_START; i < PROTECTED_FD_END; i++) {
 343     int flags = fcntl(i, F_GETFD, NULL);
 344     if (flags != -1) {
 345       fcntl(i, F_SETFD, flags & ~FD_CLOEXEC);
 346     }
 347   }
 348   JTRACE("Prepared for Exec") (getenv("LD_PRELOAD"));
 349 }
 350 
 351 static void dmtcpProcessFailedExec(const char *path, char *newArgv[])
 352 {
 353   int saved_errno = errno;
 354 
 355   if (Util::isSetuid(path)) {
 356     Util::freePatchedArgv(newArgv);
 357   }
 358 
 359   restoreUserLDPRELOAD();
 360 
 361   unsetenv(ENV_VAR_DLSYM_OFFSET);
 362   unsetenv(ENV_VAR_DLSYM_OFFSET_M32);
 363 
 364   JTRACE("Processed failed Exec Attempt") (path) (getenv("LD_PRELOAD"));
 365   errno = saved_errno;
 366   JASSERT(_real_close(PROTECTED_LIFEBOAT_FD) == 0) (JASSERT_ERRNO);
 367 }
 368 
 369 static string getUpdatedLdPreload(const char* filename,
 370                                   const char* currLdPreload)
 371 {
 372   string preload = getenv(ENV_VAR_HIJACK_LIBS);
 373 
 374   bool isElf = false;
 375   bool is32bitElf = false;
 376   if (getenv(ENV_VAR_HIJACK_LIBS_M32) != NULL &&
 377       Util::elfType(filename, &isElf, &is32bitElf) != -1 &&
 378       isElf &&
 379       is32bitElf) {
 380     preload = getenv(ENV_VAR_HIJACK_LIBS_M32);
 381   }
 382 
 383   vector<string> pluginLibraries = Util::tokenizeString(preload, ":");
 384   for (size_t i = 0; i < pluginLibraries.size(); i++) {
 385     // If the plugin doesn't exist, try to search it in the current install
 386     // directory.
 387     if (!jalib::Filesystem::FileExists(pluginLibraries[i])) {
 388       pluginLibraries[i] =
 389         Util::getPath(jalib::Filesystem::BaseName(pluginLibraries[i]),
 390                                                   is32bitElf);
 391     }
 392   }
 393 
 394   const char *preloadEnv = getenv("LD_PRELOAD");
 395   if (currLdPreload != NULL && strlen(currLdPreload) > 0) {
 396     pluginLibraries.push_back(currLdPreload);
 397     setenv(ENV_VAR_ORIG_LD_PRELOAD, currLdPreload, 1);
 398   } else if (preloadEnv != NULL && strlen(preloadEnv) > 0) {
 399     pluginLibraries.push_back(preloadEnv);
 400     setenv(ENV_VAR_ORIG_LD_PRELOAD, preloadEnv, 1);
 401   }
 402 
 403   string newPreload = Util::joinStrings(pluginLibraries, ":");
 404   return newPreload;
 405 }
 406 
 407 static vector<string> copyEnv(char *const envp[])
 408 {
 409   vector<string> result;
 410   for (size_t i = 0; envp[i] != NULL; i++) {
 411     result.push_back(envp[i]);
 412   }
 413   return result;
 414 }
 415 
 416 static vector<const char*> stringVectorToPointerArray(const vector<string>& s)
 417 {
 418   vector<const char*> result;
 419   // Now get the pointers.
 420   for (size_t i = 0; i < s.size(); i++) {
 421     result.push_back(s[i].c_str());
 422   }
 423   result.push_back(NULL);
 424   return result;
 425 }
 426 
 427 static const char* ourImportantEnvs[] =
 428 {
 429   ENV_VARS_ALL //expands to a long list
 430 };
 431 #define ourImportantEnvsCnt ((sizeof(ourImportantEnvs))/(sizeof(const char*)))
 432 
 433 static bool isImportantEnv (string str)
 434 {
 435   str = str.substr(0, str.find("="));
 436 
 437   for (size_t i=0; i<ourImportantEnvsCnt; ++i) {
 438     if (str == ourImportantEnvs[i])
 439       return true;
 440   }
 441   return false;
 442 }
 443 
 444 static vector<string> patchUserEnv (vector<string> env, const char* filename)
 445 {
 446   vector<string> result;
 447   string userPreloadStr;
 448 
 449   ostringstream out;
 450   out << "non-DMTCP env vars:\n";
 451 
 452   for (size_t i = 0; i < env.size(); i++) {
 453     if (isImportantEnv (env[i])) {
 454       if (dbg) {
 455         out << "     skipping: " << env[i] << '\n';
 456       }
 457       continue;
 458     }
 459     if (Util::strStartsWith(env[i], "LD_PRELOAD=")) {
 460       userPreloadStr = env[i].substr(strlen("LD_PRELOAD="));
 461       continue;
 462     }
 463 
 464     result.push_back(env[i]);
 465     if (dbg) {
 466       out << "     addenv[user]:" << result.back() << '\n';
 467     }
 468   }
 469   JTRACE("Creating a copy of (non-DMTCP) user env vars...") (out.str());
 470 
 471   //pack up our ENV into the new ENV
 472   out.str("DMTCP env vars:\n");
 473   for (size_t i=0; i<ourImportantEnvsCnt; ++i) {
 474     const char* v = getenv(ourImportantEnvs[i]);
 475     const string e = ourImportantEnvs[i];
 476     if (e == ENV_VAR_ORIG_LD_PRELOAD && !userPreloadStr.empty()) {
 477       result.push_back(e + "=" + userPreloadStr);
 478     } else if (v != NULL) {
 479       result.push_back (e + '=' + v);
 480       if (dbg) {
 481         out << "     addenv[dmtcp]:" << result.back() << '\n';
 482       }
 483     }
 484   }
 485 
 486   string ldPreloadStr = "LD_PRELOAD=";
 487   ldPreloadStr += getUpdatedLdPreload(filename, userPreloadStr.c_str());
 488 
 489   result.push_back(ldPreloadStr);
 490   if (dbg) {
 491     out << "     addenv[dmtcp]:" << result.back() << '\n';
 492   }
 493 
 494   JTRACE("Patched user envp...")  (out.str());
 495 
 496   return result;
 497 }
 498 
 499 extern "C" int execve (const char *filename, char *const argv[],
 500                         char *const envp[])
 501 {
 502 
 503   if (isPerformingCkptRestart() || isBlacklistedProgram(filename) ) {
 504     return _real_execve(filename, argv, envp);
 505   }
 506   JTRACE("execve() wrapper") (filename);
 507 
 508   /* Acquire the wrapperExeution lock to prevent checkpoint to happen while
 509    * processing this system call.
 510    */
 511   WRAPPER_EXECUTION_GET_EXCL_LOCK();
 512 
 513   const vector<string> env = copyEnv(envp);
 514 
 515   char *newFilename;
 516   char **newArgv;
 517   dmtcpPrepareForExec(filename, argv, &newFilename, &newArgv);
 518 
 519   const vector<string> envStrings = patchUserEnv(env, filename);
 520   const vector<const char*> newEnv = stringVectorToPointerArray(envStrings);
 521 
 522   int retVal = _real_execve (newFilename, newArgv, (char* const*)&newEnv[0]);
 523 
 524   dmtcpProcessFailedExec(filename, newArgv);
 525 
 526   WRAPPER_EXECUTION_RELEASE_EXCL_LOCK();
 527 
 528   return retVal;
 529 }
 530 
 531 extern "C" int execv (const char *path, char *const argv[])
 532 {
 533   JTRACE("execv() wrapper, calling execve with environ") (path);
 534 
 535   // Make a copy of the environ coz it might change after a setenv().
 536   const vector<string> envStrings = copyEnv(environ);
 537   // Now get the pointers.
 538   const vector<const char*> env = stringVectorToPointerArray(envStrings);
 539 
 540   return execve(path, argv, (char* const*) &env[0]);
 541 }
 542 
 543 extern "C" int execvp (const char *filename, char *const argv[])
 544 {
 545   if (isPerformingCkptRestart() || isBlacklistedProgram(filename) ) {
 546     return _real_execvp(filename, argv);
 547   }
 548   JTRACE("execvp() wrapper") (filename);
 549   /* Acquire the wrapperExeution lock to prevent checkpoint to happen while
 550    * processing this system call.
 551    */
 552   WRAPPER_EXECUTION_GET_EXCL_LOCK();
 553 
 554   char *newFilename;
 555   char **newArgv;
 556   dmtcpPrepareForExec(filename, argv, &newFilename, &newArgv);
 557   setenv("LD_PRELOAD", getUpdatedLdPreload(filename, NULL).c_str(), 1);
 558 
 559   int retVal = _real_execvp (newFilename, newArgv);
 560 
 561   dmtcpProcessFailedExec(filename, newArgv);
 562 
 563   WRAPPER_EXECUTION_RELEASE_EXCL_LOCK();
 564 
 565   return retVal;
 566 }
 567 
 568 // This function first appeared in glibc 2.11
 569 extern "C" int execvpe (const char *filename, char *const argv[],
 570                          char *const envp[])
 571 {
 572   if (isPerformingCkptRestart() || isBlacklistedProgram(filename)) {
 573     return _real_execvpe(filename, argv, envp);
 574   }
 575   JTRACE("execvpe() wrapper") (filename);
 576   /* Acquire the wrapperExeution lock to prevent checkpoint to happen while
 577    * processing this system call.
 578    */
 579   WRAPPER_EXECUTION_GET_EXCL_LOCK();
 580 
 581   // Make a copy of the environ coz it might change after a setenv().
 582   const vector<string> env = copyEnv(envp);
 583 
 584   char *newFilename;
 585   char **newArgv;
 586   dmtcpPrepareForExec(filename, argv, &newFilename, &newArgv);
 587 
 588   const vector<string> newEnvStrings = patchUserEnv(env, filename);
 589   const vector<const char*> newEnv = stringVectorToPointerArray(newEnvStrings);
 590 
 591   int retVal = _real_execvpe(newFilename, newArgv, (char* const*)&newEnv[0]);
 592 
 593   dmtcpProcessFailedExec(filename, newArgv);
 594 
 595   WRAPPER_EXECUTION_RELEASE_EXCL_LOCK();
 596 
 597   return retVal;
 598 }
 599 
 600 extern "C" int fexecve (int fd, char *const argv[], char *const envp[])
 601 {
 602   char buf[sizeof "/proc/self/fd/" + sizeof (int) * 3];
 603   snprintf (buf, sizeof (buf), "/proc/self/fd/%d", fd);
 604 
 605   JTRACE("fexecve() wrapper calling execve()") (fd) (buf);
 606   return execve(buf, argv, envp);
 607 }
 608 
 609 
 610 extern "C" int execl (const char *path, const char *arg, ...)
 611 {
 612   JTRACE("execl() wrapper") (path);
 613 
 614   size_t argv_max = INITIAL_ARGV_MAX;
 615   const char *initial_argv[INITIAL_ARGV_MAX];
 616   const char **argv = initial_argv;
 617   va_list args;
 618 
 619   argv[0] = arg;
 620 
 621   va_start (args, arg);
 622   unsigned int i = 0;
 623   while (argv[i++] != NULL)
 624   {
 625     if (i == argv_max)
 626     {
 627       argv_max *= 2;
 628       const char **nptr = (const char**) realloc (argv == initial_argv ? NULL : argv,
 629           argv_max * sizeof (const char *));
 630       if (nptr == NULL)
 631       {
 632         if (argv != initial_argv)
 633           free (argv);
 634         return -1;
 635       }
 636       if (argv == initial_argv)
 637         /* We have to copy the already filled-in data ourselves.  */
 638         memcpy (nptr, argv, i * sizeof (const char *));
 639 
 640       argv = nptr;
 641     }
 642 
 643     argv[i] = va_arg (args, const char *);
 644   }
 645   va_end (args);
 646 
 647   int ret = execv (path, (char *const *) argv);
 648   if (argv != initial_argv)
 649     free (argv);
 650 
 651   return ret;
 652 }
 653 
 654 
 655 extern "C" int execlp (const char *file, const char *arg, ...)
 656 {
 657   JTRACE("execlp() wrapper") (file);
 658 
 659   size_t argv_max = INITIAL_ARGV_MAX;
 660   const char *initial_argv[INITIAL_ARGV_MAX];
 661   const char **argv = initial_argv;
 662   va_list args;
 663 
 664   argv[0] = arg;
 665 
 666   va_start (args, arg);
 667   unsigned int i = 0;
 668   while (argv[i++] != NULL)
 669   {
 670     if (i == argv_max)
 671     {
 672       argv_max *= 2;
 673       const char **nptr = (const char**) realloc (argv == initial_argv ? NULL : argv,
 674           argv_max * sizeof (const char *));
 675       if (nptr == NULL)
 676       {
 677         if (argv != initial_argv)
 678           free (argv);
 679         return -1;
 680       }
 681       if (argv == initial_argv)
 682         /* We have to copy the already filled-in data ourselves.  */
 683         memcpy (nptr, argv, i * sizeof (const char *));
 684 
 685       argv = nptr;
 686     }
 687 
 688     argv[i] = va_arg (args, const char *);
 689   }
 690   va_end (args);
 691 
 692   int ret = execvp (file, (char *const *) argv);
 693   if (argv != initial_argv)
 694     free (argv);
 695 
 696   return ret;
 697 }
 698 
 699 
 700 extern "C" int execle(const char *path, const char *arg, ...)
 701 {
 702   JTRACE("execle() wrapper") (path);
 703 
 704   size_t argv_max = INITIAL_ARGV_MAX;
 705   const char *initial_argv[INITIAL_ARGV_MAX];
 706   const char **argv = initial_argv;
 707   va_list args;
 708   argv[0] = arg;
 709 
 710   va_start (args, arg);
 711   unsigned int i = 0;
 712   while (argv[i++] != NULL)
 713   {
 714     if (i == argv_max)
 715     {
 716       argv_max *= 2;
 717       const char **nptr = (const char**) realloc (argv == initial_argv ? NULL : argv,
 718           argv_max * sizeof (const char *));
 719       if (nptr == NULL)
 720       {
 721         if (argv != initial_argv)
 722           free (argv);
 723         return -1;
 724       }
 725       if (argv == initial_argv)
 726         /* We have to copy the already filled-in data ourselves.  */
 727         memcpy (nptr, argv, i * sizeof (const char *));
 728 
 729       argv = nptr;
 730     }
 731 
 732     argv[i] = va_arg (args, const char *);
 733   }
 734 
 735   const char *const *envp = va_arg (args, const char *const *);
 736   va_end (args);
 737 
 738   int ret = execve (path, (char *const *) argv, (char *const *) envp);
 739   if (argv != initial_argv)
 740     free (argv);
 741 
 742   return ret;
 743 }
 744 
 745 // See comment in glibcsystem.cpp for why this exists and how it works.
 746 extern int do_system (const char *line);
 747 
 748 extern "C" int system (const char *line)
 749 {
 750   JTRACE("before system(), checkpointing may not work")
 751     (line) (getenv (ENV_VAR_HIJACK_LIBS)) (getenv ("LD_PRELOAD"));
 752 
 753   if (line == NULL)
 754     /* Check that we have a command processor available.  It might
 755        not be available after a chroot(), for example.  */
 756     return do_system ("exit 0") == 0;
 757 
 758   int result = do_system (line);
 759 
 760   JTRACE("after system()");
 761 
 762   return result;
 763 }

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