root/util_exec.cpp

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

DEFINITIONS

This source file includes following definitions.
  1. setVirtualPidEnvVar
  2. isdir0700
  3. safeMkdir
  4. safeSystem
  5. expandPathname
  6. elfType
  7. ld_linux_so_path
  8. isStaticallyLinked
  9. isScreen
  10. setScreenDir
  11. getScreenDir
  12. isSetuid
  13. patchArgvIfSetuid
  14. freePatchedArgv
  15. prepareDlsymWrapper
  16. getDlsymOffset
  17. getDlsymOffset_m32
  18. runMtcpRestore
  19. adjustRlimitStack
  20. getPath
  21. getDmtcpArgs

   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 <string.h>
  23 #include <fcntl.h>
  24 #include <sys/time.h>
  25 #include <sys/resource.h>
  26 #include  "util.h"
  27 #include  "syscallwrappers.h"
  28 #include  "uniquepid.h"
  29 #include  "protectedfds.h"
  30 #include  "shareddata.h"
  31 #include  "../jalib/jassert.h"
  32 #include  "../jalib/jfilesystem.h"
  33 #include  "../jalib/jconvert.h"
  34 
  35 using namespace dmtcp;
  36 
  37 static int32_t getDlsymOffset();
  38 static int32_t getDlsymOffset_m32();
  39 
  40 void Util::setVirtualPidEnvVar(pid_t pid, pid_t virtPpid, pid_t realPpid)
  41 {
  42   // We want to use setenv() only once. For all later changes, we manipulate
  43   // the buffer in place. This was done to avoid a bug when using Perl. Perl
  44   // implements its own setenv by keeping a private copy libc:environ and never
  45   // refers to libc:private, thus libc:setenv is outdated and calling setenv()
  46   // can cause segfault.
  47   char buf1[80];
  48   char buf2[80];
  49   memset(buf2, '#', sizeof(buf2));
  50   buf2[sizeof(buf2) - 1] = '\0';
  51 
  52   sprintf(buf1, "%d:%d:%d:", pid, virtPpid, realPpid);
  53 
  54   if (getenv(ENV_VAR_VIRTUAL_PID) == NULL) {
  55     memcpy(buf2, buf1, strlen(buf1));
  56     setenv(ENV_VAR_VIRTUAL_PID, buf2, 1);
  57   } else {
  58     char *envStr = (char*) getenv(ENV_VAR_VIRTUAL_PID);
  59     memcpy(envStr, buf1, strlen(buf1));
  60   }
  61 }
  62 
  63 // 'screen' requires directory with permissions 0700
  64 static int isdir0700(const char *pathname)
  65 {
  66   struct stat st;
  67   stat(pathname, &st);
  68   return (S_ISDIR(st.st_mode) == 1
  69           && (st.st_mode & 0777) == 0700
  70           && st.st_uid == getuid()
  71           && access(pathname, R_OK | W_OK | X_OK) == 0
  72       );
  73 }
  74 
  75 int Util::safeMkdir(const char *pathname, mode_t mode)
  76 {
  77   // If it exists and we can give it the right permissions, do it.
  78   chmod(pathname, 0700);
  79   if (isdir0700(pathname))
  80     return 0;
  81   // else start over
  82   unlink(pathname);
  83   rmdir(pathname); // Maybe it was an empty directory
  84   mkdir(pathname, 0700);
  85   return isdir0700(pathname);
  86 }
  87 
  88 int Util::safeSystem(const char *command)
  89 {
  90   char *str = getenv("LD_PRELOAD");
  91   string dmtcphjk;
  92   if (str != NULL)
  93     dmtcphjk = str;
  94   unsetenv("LD_PRELOAD");
  95   int rc = _real_system(command);
  96   if (str != NULL)
  97     setenv("LD_PRELOAD", dmtcphjk.c_str(), 1);
  98   return rc;
  99 }
 100 
 101 int Util::expandPathname(const char *inpath, char * const outpath,
 102                                 size_t size)
 103 {
 104   bool success = false;
 105   if (*inpath == '/' || strstr(inpath, "/") != NULL) {
 106     strncpy(outpath, inpath, size);
 107     success = true;
 108   } else if (strStartsWith(inpath, "~/")) {
 109     snprintf(outpath, size, "%s%s", getenv("HOME"), &inpath[1]);
 110     success = true;
 111   } else if (strStartsWith(inpath, "~")) {
 112     snprintf(outpath, size, "/home/%s", &inpath[1]);
 113     success = true;
 114   } else if (strStartsWith(inpath, ".")) {
 115     snprintf(outpath, size, "%s/%s", jalib::Filesystem::GetCWD().c_str(),
 116                                      inpath);
 117     success = true;
 118   } else {
 119     char *pathVar = getenv("PATH");
 120     outpath[0] = '\0';
 121     if (pathVar == NULL) {
 122       pathVar = (char*) ":/bin:/usr/bin";
 123     }
 124     while (*pathVar != '\0') {
 125       char *nextPtr;
 126       nextPtr = strchrnul(pathVar, ':');
 127       if (nextPtr == pathVar) {
 128         /* Two adjacent colons, or a colon at the beginning or the end
 129            of `PATH' means to search the current directory.  */
 130         strcpy(outpath, jalib::Filesystem::GetCWD().c_str());
 131       } else {
 132         strncpy(outpath, pathVar, nextPtr - pathVar);
 133         outpath[nextPtr-pathVar] = '\0';
 134       }
 135 
 136       JASSERT(size > strlen(outpath) + strlen(inpath) + 1)
 137         (size) (outpath) (strlen(outpath)) (inpath) (strlen(inpath))
 138          .Text("Pathname too long; Use larger buffer.");
 139 
 140       strcat(outpath, "/");
 141       strcat(outpath, inpath);
 142 
 143       if (*nextPtr  == '\0')
 144         pathVar = nextPtr;
 145       else // else *nextPtr == ':'
 146         pathVar = nextPtr + 1; // prepare for next iteration
 147       if (access(outpath, X_OK) == 0) {
 148         success = true;
 149         break;
 150       }
 151     }
 152   }
 153   return (success ? 0 : -1);
 154 }
 155 
 156 int Util::elfType(const char *pathname, bool *isElf, bool *is32bitElf)
 157 {
 158   const char *magic_elf = "\177ELF"; // Magic number for ELF
 159   const char *magic_elf32 = "\177ELF\001"; // Magic number for ELF 32-bit
 160   // Magic number for ELF 64-bit is "\177ELF\002"
 161   const int len = strlen(magic_elf32);
 162   char argv_buf[len + 1];
 163   char full_path[PATH_MAX];
 164   expandPathname(pathname, full_path, sizeof(full_path));
 165   int fd = _real_open(full_path, O_RDONLY, 0);
 166   if (fd == -1) {
 167     return -1;
 168   }
 169   ssize_t ret = readAll(fd, argv_buf, len);
 170   close (fd);
 171   if (ret != len) {
 172     return -1;
 173   }
 174   *isElf = (memcmp(magic_elf, argv_buf, strlen(magic_elf)) == 0);
 175   *is32bitElf = (memcmp(magic_elf32, argv_buf, strlen(magic_elf32)) == 0);
 176   return 0;
 177 }
 178 
 179 static string ld_linux_so_path(int version, bool is32bitElf = false)
 180 {
 181   char buf[80];
 182 #if (defined(__x86_64__) || defined(__aarch64__)) && !defined(CONFIG_M32)
 183   if (is32bitElf) {
 184     sprintf(buf, "/lib/ld-linux.so.%d", version);
 185   } else {
 186     sprintf(buf, ELF_INTERPRETER);
 187   }
 188 #else
 189   sprintf(buf, ELF_INTERPRETER);
 190 #endif
 191 
 192   string cmd = buf;
 193   return cmd;
 194 }
 195 
 196 bool Util::isStaticallyLinked(const char *filename)
 197 {
 198   bool isElf, is32bitElf;
 199   char pathname[PATH_MAX];
 200   expandPathname(filename, pathname, sizeof(pathname));
 201   elfType(pathname, &isElf, &is32bitElf);
 202 
 203   int version = 2;
 204   string cmd;
 205   do {
 206     cmd = ld_linux_so_path(version, is32bitElf);
 207     version++;
 208   } while (!jalib::Filesystem::FileExists(cmd) && version < 10);
 209 
 210   cmd = cmd + " --verify " + pathname + " > /dev/null";
 211 
 212   // FIXME:  When tested on dmtcp/test/pty.c, 'ld.so -verify' returns
 213   // nonzero status.  Why is this?  It's dynamically linked.
 214   if (isElf && safeSystem(cmd.c_str())) {
 215     return true;
 216   }
 217   return false;
 218 }
 219 
 220 bool Util::isScreen(const char *filename)
 221 {
 222   return jalib::Filesystem::BaseName(filename) == "screen" &&
 223          isSetuid(filename);
 224 }
 225 
 226 //NOTE:  This routine is called only if 'screen' is setuid.
 227 // In Ubuntu 9.10, an unprivileged 'screen' (no setuid) will ckpt and restart
 228 // fine if SCREENDIR is set to the file $USER/tmp4 when $USER/tmp4 doesn't exist
 229 // Arguably this is a bug in screen-4.0.  Should we take advantage of it?
 230 void Util::setScreenDir() {
 231   if (getenv("SCREENDIR") == NULL) {
 232     // This will flash by, but the user will see it again on exiting screen.
 233     JASSERT_STDERR <<"*** WARNING: Environment variable SCREENDIR is not set!\n"
 234                    << "***  Set this to a safe location, and if restarting on\n"
 235                    << "***  a new host, copy your SCREENDIR directory there.\n"
 236                    << "***  DMTCP will use"
 237                             " $DMTCP_TMPDIR/dmtcp-USER@HOST/uscreens for now,\n"
 238                    << "***  but this directory may not survive a re-boot!\n"
 239                    << "***      As of DMTCP-1.2.3, emacs23 not yet supported\n"
 240                    << "***  inside screen.  Please use emacs22 for now.  This\n"
 241                    << "***  will be fixed in a future version of DMTCP.\n\n";
 242     setenv("SCREENDIR", Util::getScreenDir().c_str(), 1);
 243   } else {
 244     if (access(getenv("SCREENDIR"), R_OK|W_OK|X_OK) != 0)
 245       JASSERT_STDERR << "*** WARNING: Environment variable SCREENDIR is set\n"
 246                      << "***  to directory with improper permissions.\n"
 247                      << "***  Please use a SCREENDIR with permission 700."
 248                      << "  [ SCREENDIR = " << getenv("SCREENDIR") << " ]\n"
 249                      << "***  Continuing anyway, and hoping for the best.\n";
 250   }
 251 
 252 }
 253 
 254 string Util::getScreenDir()
 255 {
 256   string tmpdir = string(dmtcp_get_tmpdir()) + "/" + "uscreens";
 257   safeMkdir(tmpdir.c_str(), 0700);
 258   return tmpdir;
 259 }
 260 
 261 bool Util::isSetuid(const char *filename)
 262 {
 263   char pathname[PATH_MAX];
 264   if (expandPathname(filename, pathname, sizeof(pathname)) ==  0) {
 265     struct stat buf;
 266     if (stat(pathname, &buf) == 0 && (buf.st_mode & S_ISUID ||
 267                                       buf.st_mode & S_ISGID)) {
 268       return true;
 269     }
 270   }
 271   return false;
 272 }
 273 
 274 void Util::patchArgvIfSetuid(const char* filename, char *const origArgv[],
 275                              char ***newArgv)
 276 {
 277   if (isSetuid(filename) == false) return;
 278 
 279   char realFilename[PATH_MAX];
 280   memset(realFilename, 0, sizeof(realFilename));
 281   expandPathname(filename, realFilename, sizeof (realFilename));
 282   //char expandedFilename[PATH_MAX];
 283 //  expandPathname(filename, expandedFilename, sizeof (expandedFilename));
 284 //  JASSERT(readlink(expandedFilename, realFilename, PATH_MAX - 1) != -1)
 285 //    (filename) (expandedFilename) (realFilename) (JASSERT_ERRNO);
 286 
 287   size_t newArgc = 0;
 288   while (origArgv[newArgc] != NULL) newArgc++;
 289   newArgc += 2;
 290   size_t newArgvSize = newArgc * sizeof(char*);
 291 
 292   // IS THIS A MEMORY LEAK?  WHEN DO WE FREE buf?  - Gene
 293   void *buf = JALLOC_HELPER_MALLOC(newArgvSize + 2 + PATH_MAX);
 294   memset(buf, 0, newArgvSize + 2 + PATH_MAX);
 295 
 296   *newArgv = (char**) buf;
 297   char *newFilename = (char*)buf + newArgvSize + 1;
 298 
 299 #define COPY_BINARY
 300 #ifdef COPY_BINARY
 301   // cp /usr/bin/screen /tmp/dmtcp-USER@HOST/screen
 302   char cpCmdBuf[PATH_MAX * 2 + 8];
 303 
 304   snprintf(newFilename, PATH_MAX, "%s/%s",
 305                                   dmtcp_get_tmpdir(),
 306                                   jalib::Filesystem::BaseName(realFilename).c_str());
 307 
 308   snprintf(cpCmdBuf, sizeof(cpCmdBuf),
 309            "/bin/cp %s %s", realFilename, newFilename);
 310 
 311   // Remove any stale copy, just in case it's not right.
 312   JASSERT(unlink(newFilename) == 0 || errno == ENOENT) (newFilename);
 313 
 314   JASSERT(safeSystem(cpCmdBuf) == 0)(cpCmdBuf)
 315     .Text("call to system(cpCmdBuf) failed");
 316 
 317   JASSERT(access(newFilename, X_OK) == 0) (newFilename) (JASSERT_ERRNO);
 318 
 319   (*newArgv)[0] = newFilename;
 320   int i;
 321   for (i = 1; origArgv[i] != NULL; i++)
 322     (*newArgv)[i] = (char*)origArgv[i];
 323   (*newArgv)[i] = origArgv[i];  // copy final NULL pointer.
 324 
 325   return;
 326 #else
 327   // FIXME : This might fail to compile. Will fix later. -- Kapil
 328   // Translate: screen   to: /lib/ld-linux.so /usr/bin/screen
 329   // This version is more general, but has a bug on restart:
 330   //    memory layout is altered on restart, and so brk() doesn't match.
 331   // Switch argvPtr from ptr to input to ptr to output now.
 332   *argvPtr = (char **)(cmdBuf + strlen(cmdBuf) + 1); // ... + 1 for '\0'
 333   // Use /lib64 if 64-bit O/S and not 32-bit app:
 334 
 335   char *ldStrPtr = NULL;
 336 #if (defined(__x86_64__) || defined(__aarch64__)) && !defined(CONFIG_M32)
 337   bool isElf, is32bitElf;
 338   elfType(cmdBuf, &isElf, &is32bitElf);
 339   if (is32bitElf)
 340     ldStrPtr = (char *)"/lib/ld-linux.so.2";
 341   else
 342     ldStrPtr = (char *)ELF_INTERPRETER;
 343 # else
 344   ldStrPtr = (char *)ELF_INTERPRETER;
 345 # endif
 346 
 347   JASSERT(newArgv0Len > strlen(origPath) + 1)
 348     (newArgv0Len) (origPath) (strlen(origPath)) .Text("Buffer not large enough");
 349 
 350   strncpy(newArgv0, origPath, newArgv0Len);
 351 
 352   size_t origArgvLen = 0;
 353   while (origArgv[origArgvLen] != NULL)
 354     origArgvLen++;
 355 
 356   JASSERT(newArgvLen >= origArgvLen + 1) (origArgvLen) (newArgvLen)
 357     .Text("newArgv not large enough to hold the expanded argv");
 358 
 359   // ISN'T THIS A BUG?  newArgv WAS DECLARED 'char ***'.
 360   newArgv[0] = ldStrPtr;
 361   newArgv[1] = newArgv0;
 362   for (int i = 1; origArgv[i] != NULL; i++)
 363     newArgv[i+1] = origArgv[i];
 364   newArgv[i+1] = origArgv[i]; // Copy final NULL pointer.
 365 #endif
 366   return;
 367 }
 368 
 369 void Util::freePatchedArgv(char **newArgv)
 370 {
 371   JALLOC_HELPER_FREE(*newArgv);
 372 }
 373 
 374 // FIXME: ENV_VAR_DLSYM_OFFSET should be reset in _real_dlsym and it should be
 375 // recalculated/reset right before returning from prepareForExec to support
 376 // process migration (the offset might have changed after the process had
 377 // migrated to a new machine with different ld.so.
 378 void Util::prepareDlsymWrapper()
 379 {
 380   /* For the sake of dlsym wrapper. We compute the address of _real_dlsym by
 381    * adding dlsym_offset to the address of dlopen after the exec into the user
 382    * application. */
 383   uint32_t offset = SharedData::getDlsymOffset();
 384   uint32_t offset_m32 = SharedData::getDlsymOffset_m32();
 385 
 386   if (offset == 0) {
 387     offset = getDlsymOffset();
 388     offset_m32 = getDlsymOffset_m32();
 389     SharedData::updateDlsymOffset(offset, offset_m32);
 390   }
 391 
 392   char str[21] = {0};
 393   sprintf(str, "%d", offset);
 394   setenv(ENV_VAR_DLSYM_OFFSET, str, 1);
 395   sprintf(str, "%d", offset_m32);
 396   setenv(ENV_VAR_DLSYM_OFFSET_M32, str, 1);
 397 }
 398 
 399 static int32_t getDlsymOffset()
 400 {
 401   void* base_addr = NULL;
 402   void* dlsym_addr = NULL;
 403   int32_t offset;
 404   void* handle = NULL;
 405   handle = dlopen(LIBDL_FILENAME, RTLD_NOW);
 406   JASSERT(handle != NULL) (dlerror());
 407 
 408   /* Earlier, we used to compute the offset of "dlsym" from "dlerror" by
 409    * computing the address of the two symbols using '&' operator. However, in
 410    * some distros (for ex. SLES 9), '&dlsym' might give the address of the
 411    * symbol defined in binary's PLT. Thus, to compute the correct offset, we
 412    * use dlopen/dlsym.
 413    */
 414   base_addr = dlsym(handle, LIBDL_BASE_FUNC_STR);
 415   dlsym_addr = dlsym(handle, "dlsym");
 416   dlclose(handle);
 417   offset = (char *)dlsym_addr - (char *)base_addr;
 418   return offset;
 419 }
 420 
 421 static int32_t getDlsymOffset_m32()
 422 {
 423   uint64_t base_addr = 0;
 424   uint64_t dlsym_addr = 0;
 425   int32_t offset;
 426   FILE *fp;
 427   char buf[PATH_MAX];
 428   string cmd1, cmd2, libdl, libdmtcp32;
 429 
 430   libdmtcp32 = Util::getPath("libdmtcp.so", true);
 431   if (libdmtcp32 == "libdmtcp.so") return 0;
 432 
 433   cmd1 = "ldd " + libdmtcp32 + " | grep " + LIBDL_FILENAME
 434        + " | tr '\t' ' ' | tr -s ' '| cut -d' ' -f4";
 435   fp = popen(cmd1.c_str(), "r");
 436   JASSERT(fp != NULL);
 437   JASSERT(fscanf(fp, "%s", (char*) &buf) == 1);
 438   fclose(fp);
 439   JASSERT(buf[0] == '/');
 440 
 441   libdl = buf;
 442 
 443   cmd2 = "nm -D -g " + libdl + " | grep '" + LIBDL_BASE_FUNC_STR + "'";
 444   fp = popen(cmd2.c_str(), "r");
 445   JASSERT(fp != NULL);
 446   // fread returns the total number of bytes read only when 'size' is 1.
 447   JASSERT(fread(buf, 1, sizeof(buf), fp) > 0);
 448   base_addr = strtoull(buf, NULL, 16);
 449   JASSERT(base_addr != 0);
 450   fclose(fp);
 451 
 452   cmd2 = "nm -D -g " + libdl + " | grep 'dlsym'";
 453   fp = popen(cmd2.c_str(), "r");
 454   JASSERT(fp != NULL);
 455   JASSERT(fread(buf, 1, sizeof(buf), fp) > 0);
 456   dlsym_addr = strtoull(buf, NULL, 16);
 457   JASSERT(base_addr != 0);
 458   fclose(fp);
 459 
 460   offset = (int32_t) ((char *)dlsym_addr - (char *)base_addr);
 461   return offset;
 462 }
 463 
 464 void Util::runMtcpRestore(int is32bitElf, const char* path, int fd,
 465                                  size_t argvSize, size_t envSize)
 466 {
 467   static string mtcprestart = Util::getPath ("mtcp_restart");
 468 
 469   if (is32bitElf) {
 470     mtcprestart = Util::getPath("mtcp_restart-32", is32bitElf);
 471   }
 472 
 473   // Tell mtcp_restart process to write its debugging information to
 474   // PROTECTED_STDERR_FD. This way we prevent it from spitting out garbage onto
 475   // FD_STDERR if it is being used by the user process in a special way.
 476   char protected_stderr_fd_str[16];
 477   sprintf(protected_stderr_fd_str, "%d", PROTECTED_STDERR_FD);
 478 
 479   char buf[64];
 480   sprintf(buf, "%d", fd);
 481 
 482   char* newArgs[] = {
 483     (char*) mtcprestart.c_str(),
 484     (char*) "--stderr-fd",
 485     protected_stderr_fd_str,
 486     (char*) "--fd",
 487     buf,
 488     NULL
 489   };
 490   JTRACE ("launching mtcp_restart --fd")(fd)(path);
 491 
 492   // Create the placeholder for "MTCP_OLDPERS" environment.
 493   // setenv("MTCP_OLDPERS_DUMMY", "XXXXXXXXXXXXXXXX", 1);
 494   // FIXME: Put an explanation of the logic below.   -- Kapil
 495 #define ENV_PTR(x) ((char*) (getenv(x) - strlen(x) - 1))
 496   char* dummyEnviron = NULL;
 497   const int pathIndex = 0; // index in newEnv[]
 498   const int dummyEnvironIndex = 1; // index in newEnv[]
 499   // Eventually, newEnv = {ENV_PTR("MTCP_OLDPERS"), ENV_PTR("PATH"), NULL}
 500   // newEnv[2] = NULL; newEnv[3] and newEnv[4] are available so that
 501   //    they can easily be used to modify envp inside mtcp_restart.c:main().
 502   //    for debugging in GDB.  These appear _after_ final NULL  of newEnv[].
 503   char* newEnv[7] = {NULL, NULL, NULL,
 504                      const_cast<char *> ("MTCP_RESTART_PAUSE=1"),
 505                      const_cast<char *> ("DMTCP_RESTART_PAUSE=1"),
 506                      const_cast<char *> ("MTCP_RESTART_PAUSE2=1"),
 507                      const_cast<char *> ("DMTCP_RESTART_PAUSE2=1")};
 508   // Will put ENV_PTR("MTCP_OLDPERS") here.
 509   newEnv[dummyEnvironIndex] = (char*) dummyEnviron;
 510   newEnv[pathIndex] = (getenv("PATH") ? ENV_PTR("PATH") : NULL);
 511 
 512   size_t newArgsSize = 0;
 513   for (int i = 0; newArgs[i] != 0; i++) {
 514     newArgsSize += strlen(newArgs[i]) + 1;
 515   }
 516   size_t newEnvSize = 0;
 517   for (int i = 0; newEnv[i] != 0; i++) {
 518     newEnvSize += strlen(newEnv[i]) + 1;
 519   }
 520   size_t originalArgvEnvSize = argvSize + envSize;
 521   size_t newArgvEnvSize = newArgsSize + newEnvSize + strlen(newArgs[0]);
 522   size_t argvSizeDiff = originalArgvEnvSize - newArgvEnvSize;
 523   if (argvSizeDiff > 0) {
 524     dummyEnviron = (char*) malloc(argvSizeDiff);
 525     memset(dummyEnviron, '0', argvSizeDiff - 1 );
 526     strncpy(dummyEnviron,
 527             ENV_VAR_DMTCP_DUMMY "=",
 528             strlen(ENV_VAR_DMTCP_DUMMY "="));
 529     dummyEnviron[argvSizeDiff - 1] = '\0';
 530     newEnv[dummyEnvironIndex] = dummyEnviron;
 531   }
 532 
 533   JTRACE("Args/Env Sizes")
 534     (newArgsSize) (newEnvSize) (argvSize) (envSize) (argvSizeDiff);
 535 
 536   execve (newArgs[0], newArgs, newEnv);
 537   JASSERT (false) (newArgs[0]) (newArgs[1]) (JASSERT_ERRNO)
 538           .Text ("exec() failed");
 539 }
 540 
 541 void Util::adjustRlimitStack()
 542 {
 543 #ifdef __i386__
 544   // This is needed in 32-bit Ubuntu 9.10, to fix bug with test/dmtcp5.c
 545   // NOTE:  Setting personality() is cleanest way to force legacy_va_layout,
 546   //   but there's currently a bug on restart in the sequence:
 547   //   checkpoint -> restart -> checkpoint -> restart
 548 # if 0
 549   { unsigned long oldPersonality = personality(0xffffffffL);
 550     if (! (oldPersonality & ADDR_COMPAT_LAYOUT)) {
 551       // Force ADDR_COMPAT_LAYOUT for libs in high mem, to avoid vdso conflict
 552       personality(oldPersonality & ADDR_COMPAT_LAYOUT);
 553       JTRACE("setting ADDR_COMPAT_LAYOUT");
 554       setenv("DMTCP_ADDR_COMPAT_LAYOUT", "temporarily is set", 1);
 555     }
 556   }
 557 # else
 558   { struct rlimit rlim;
 559     getrlimit(RLIMIT_STACK, &rlim);
 560     if (rlim.rlim_cur != RLIM_INFINITY) {
 561       char buf[100];
 562       sprintf(buf, "%lu", rlim.rlim_cur); // "%llu" for BSD/Mac OS
 563       JTRACE("setting rlim_cur for RLIMIT_STACK") (rlim.rlim_cur);
 564       setenv("DMTCP_RLIMIT_STACK", buf, 1);
 565       // Force kernel's internal compat_va_layout to 0; Force libs to high mem.
 566       rlim.rlim_cur = rlim.rlim_max;
 567       // FIXME: if rlim.rlim_cur != RLIM_INFINITY, then we should warn the user.
 568       setrlimit(RLIMIT_STACK, &rlim);
 569       // After exec, process will restore DMTCP_RLIMIT_STACK in DmtcpWorker()
 570     }
 571   }
 572 # endif
 573 #endif
 574 }
 575 
 576 // TODO(kapil): rewrite getPath to remove dependency on jalib.
 577 string Util::getPath(string cmd, bool is32bit)
 578 {
 579   // search relative to base dir of dmtcp installation.
 580   const char *p1[] = {
 581     "/bin/",
 582     "/lib64/dmtcp/",
 583     "/lib/dmtcp/",
 584   };
 585 
 586   string suffixFor32Bits;
 587 #if defined(__x86_64__) || defined(__aarch64__)
 588   if (is32bit) {  // if this is a multi-architecture build
 589     string basename = jalib::Filesystem::BaseName(cmd);
 590     if (cmd == "mtcp_restart-32") {
 591       suffixFor32Bits = "32/bin/";
 592     } else {
 593       suffixFor32Bits = "32/lib/dmtcp/";
 594     }
 595   }
 596 #endif
 597 
 598   // Search relative to dir of this command (bin/dmtcp_launch), (using p1).
 599   string udir = SharedData::getInstallDir();
 600   for (size_t i = 0; i < sizeof(p1) / sizeof(char*); i++) {
 601     string pth = udir + p1[i] + suffixFor32Bits + cmd;
 602     if (jalib::Filesystem::FileExists(pth)) {
 603       return pth;
 604     }
 605   }
 606 
 607   return cmd;
 608 }
 609 
 610 void Util::getDmtcpArgs(vector<string> &dmtcp_args)
 611 {
 612   const char * sigckpt              = getenv (ENV_VAR_SIGCKPT);
 613   const char * compression          = getenv (ENV_VAR_COMPRESSION);
 614   const char * allocPlugin          = getenv (ENV_VAR_ALLOC_PLUGIN);
 615   const char * dlPlugin             = getenv (ENV_VAR_DL_PLUGIN);
 616 #ifdef HBICT_DELTACOMP
 617   const char * deltacompression     = getenv (ENV_VAR_DELTACOMPRESSION);
 618 #endif
 619   const char * ckptOpenFiles        = getenv (ENV_VAR_CKPT_OPEN_FILES);
 620   const char * ckptDir              = getenv (ENV_VAR_CHECKPOINT_DIR);
 621   const char * tmpDir               = getenv (ENV_VAR_TMPDIR);
 622   const char * plugins              = getenv (ENV_VAR_PLUGIN);
 623 
 624   //modify the command
 625   dmtcp_args.clear();
 626   dmtcp_args.push_back("--coord-host");
 627   dmtcp_args.push_back(SharedData::coordHost());
 628   dmtcp_args.push_back("--coord-port");
 629   dmtcp_args.push_back(jalib::XToString(SharedData::coordPort()));
 630 
 631   if (jassert_quiet == 1) {
 632     dmtcp_args.push_back("-q");
 633   } else if (jassert_quiet == 2) {
 634     dmtcp_args.push_back("-q -q");
 635   }
 636 
 637   if (sigckpt != NULL) {
 638     dmtcp_args.push_back("--ckpt-signal");
 639     dmtcp_args.push_back(sigckpt);
 640   }
 641 
 642   if (ckptDir != NULL) {
 643     dmtcp_args.push_back("--ckptdir");
 644     dmtcp_args.push_back(ckptDir);
 645   }
 646 
 647   if (tmpDir != NULL) {
 648     dmtcp_args.push_back("--tmpdir");
 649     dmtcp_args.push_back(tmpDir);
 650   }
 651 
 652   if (ckptOpenFiles != NULL) {
 653     dmtcp_args.push_back("--checkpoint-open-files");
 654   }
 655 
 656   if (plugins != NULL) {
 657     dmtcp_args.push_back("--with-plugin");
 658     dmtcp_args.push_back(plugins);
 659   }
 660 
 661   if (compression != NULL) {
 662     if (strcmp (compression, "1") == 0)
 663       dmtcp_args.push_back("--no-gzip");
 664     else
 665       dmtcp_args.push_back("--gzip");
 666   }
 667 
 668   if (allocPlugin != NULL && strcmp(allocPlugin, "0") == 0) {
 669     dmtcp_args.push_back("--disable-alloc-plugin");
 670   }
 671 
 672   if (dlPlugin != NULL && strcmp(dlPlugin, "0") == 0) {
 673     dmtcp_args.push_back("--disable-dl-plugin");
 674   }
 675 
 676   if (dmtcp_ptrace_enabled != NULL && dmtcp_ptrace_enabled()) {
 677     dmtcp_args.push_back("--ptrace");
 678   }
 679 
 680   if (dmtcp_modify_env_enabled != NULL && dmtcp_modify_env_enabled()) {
 681     dmtcp_args.push_back("--modify_env");
 682   }
 683 
 684   if (dmtcp_infiniband_enabled != NULL && dmtcp_infiniband_enabled()) {
 685     dmtcp_args.push_back("--infiniband");
 686   }
 687 
 688   if (dmtcp_batch_queue_enabled != NULL && dmtcp_batch_queue_enabled()) {
 689     dmtcp_args.push_back("--batch-queue");
 690   }
 691 
 692 #ifdef HBICT_DELTACOMP
 693   if (deltacompression != NULL) {
 694     if (strcmp(deltacompression, "0") == 0)
 695       dmtcp_args.push_back("--no-hbict");
 696     else
 697       dmtcp_args.push_back("--hbict");
 698   }
 699 #endif
 700 }

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