root/dmtcp_launch.cpp

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

DEFINITIONS

This source file includes following definitions.
  1. processArgs
  2. main
  3. testMatlab
  4. testJava
  5. testSetuid
  6. testStaticallyLinked
  7. testScreen
  8. setLDPreloadLibs

   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/resource.h>
  23 #include  "../jalib/jassert.h"
  24 #include  "../jalib/jfilesystem.h"
  25 #include  "../jalib/jconvert.h"
  26 #include "constants.h"
  27 #include "dmtcpmessagetypes.h"
  28 #include "syscallwrappers.h"
  29 #include "coordinatorapi.h"
  30 #include "shareddata.h"
  31 #include "util.h"
  32 
  33 #define BINARY_NAME "dmtcp_launch"
  34 
  35 using namespace dmtcp;
  36 
  37 static void processArgs(int *orig_argc, char ***orig_argv,
  38                         string *tmpDir_p, const char **host,
  39                         const char **portStr);
  40 static int testMatlab(const char *filename);
  41 static int testJava(char **argv);
  42 static bool testSetuid(const char *filename);
  43 static void testStaticallyLinked(const char *filename);
  44 static bool testScreen(char **argv, char ***newArgv);
  45 static void setLDPreloadLibs(bool is32bitElf);
  46 
  47 // gcc-4.3.4 -Wformat=2 issues false positives for warnings unless the format
  48 // string has at least one format specifier with corresponding format argument.
  49 // Ubuntu 9.01 uses -Wformat=2 by default.
  50 static const char* theUsage =
  51   "Usage: dmtcp_launch [OPTIONS] <command> [args...]\n"
  52   "Start a process under DMTCP control.\n\n"
  53   "Connecting to the DMTCP Coordinator:\n"
  54   "  -h, --coord-host HOSTNAME (environment variable DMTCP_COORD_HOST)\n"
  55   "              Hostname where dmtcp_coordinator is run (default: localhost)\n"
  56   "  -p, --coord-port PORT_NUM (environment variable DMTCP_COORD_PORT)\n"
  57   "              Port where dmtcp_coordinator is run (default: 7779)\n"
  58   "  --port-file FILENAME\n"
  59   "              File to write listener port number.  (Useful with\n"
  60   "              '--coord-port 0', which is used to assign a random port)\n"
  61   "  -j, --join\n"
  62   "              Join an existing coordinator, raise error if one doesn't\n"
  63   "              already exist\n"
  64   "  --new-coordinator\n"
  65   "              Create a new coordinator at the given port. Fail if one\n"
  66   "              already exists on the given port. The port can be specified\n"
  67   "              with --coord-port, or with environment variable DMTCP_COORD_PORT.\n"
  68   "              If no port is specified, start coordinator at a random port\n"
  69   "              (same as specifying port '0').\n"
  70   "  --no-coordinator\n"
  71   "              Execute the process in standalone coordinator-less mode.\n"
  72   "              Use dmtcp_command or --interval to request checkpoints.\n"
  73   "  -i, --interval SECONDS (environment variable DMTCP_CHECKPOINT_INTERVAL)\n"
  74   "              Time in seconds between automatic checkpoints.\n"
  75   "              0 implies never (manual ckpt only); if not set and no env var,\n"
  76   "              use default value set in dmtcp_coordinator or dmtcp_command.\n"
  77   "              Not allowed if --join is specified\n"
  78   "\n"
  79   "Checkpoint image generation:\n"
  80   "  --gzip, --no-gzip, (environment variable DMTCP_GZIP=[01])\n"
  81   "              Enable/disable compression of checkpoint images (default: 1)\n"
  82   "              WARNING:  gzip adds seconds.  Without gzip, ckpt is often < 1 s\n"
  83 #ifdef HBICT_DELTACOMP
  84   "  --hbict, --no-hbict, (environment variable DMTCP_HBICT=[01])\n"
  85   "              Enable/disable compression of checkpoint images (default: 1)\n"
  86 #endif
  87   "  --ckptdir PATH (environment variable DMTCP_CHECKPOINT_DIR)\n"
  88   "              Directory to store checkpoint images\n"
  89   "              (default: curr dir at launch)\n"
  90   "  --ckpt-open-files\n"
  91   "  --checkpoint-open-files\n"
  92   "              Checkpoint open files and restore old working dir.\n"
  93   "              (default: do neither)\n"
  94   "  --ckpt-signal signum\n"
  95   "              Signal number used internally by DMTCP for checkpointing\n"
  96   "              (default: SIGUSR2/12).\n"
  97   "\n"
  98   "Enable/disable plugins:\n"
  99   "  --with-plugin (environment variable DMTCP_PLUGIN)\n"
 100   "              Colon-separated list of DMTCP plugins to be preloaded with DMTCP.\n"
 101   "              (Absolute pathnames are required.)\n"
 102   "  --batch-queue, --rm\n"
 103   "              Enable support for resource managers (Torque PBS and SLURM).\n"
 104   "              (default: disabled)\n"
 105   "  --ptrace\n"
 106   "              Enable support for PTRACE system call for gdb/strace etc.\n"
 107   "              (default: disabled)\n"
 108   "  --modify-env\n"
 109   "              Update environment variables based on the environment on the\n"
 110   "              restart host (e.g., DISPLAY=$DISPLAY).\n"
 111   "              This can be set in a file dmtcp_env.txt.\n"
 112   "              (default: disabled)\n"
 113   "  --ib, --infiniband\n"
 114   "              Enable InfiniBand plugin. (default: disabled)\n"
 115   "  --disable-alloc-plugin: (environment variable DMTCP_ALLOC_PLUGIN=[01])\n"
 116   "              Disable alloc plugin (default: enabled).\n"
 117   "  --disable-dl-plugin: (environment variable DMTCP_DL_PLUGIN=[01])\n"
 118   "              Disable dl plugin (default: enabled).\n"
 119   "  --disable-all-plugins (EXPERTS ONLY, FOR DEBUGGING)\n"
 120   "              Disable all plugins.\n"
 121   "\n"
 122   "Other options:\n"
 123   "  --tmpdir PATH (environment variable DMTCP_TMPDIR)\n"
 124   "              Directory to store temporary files (default: $TMDPIR or /tmp)\n"
 125   "              (Behavior is undefined if two launched processes specify\n"
 126   "               different tmpdirs.)\n"
 127   "  -q, --quiet (or set environment variable DMTCP_QUIET = 0, 1, or 2)\n"
 128   "              Skip NOTE messages; if given twice, also skip WARNINGs\n"
 129   "  --help\n"
 130   "              Print this message and exit.\n"
 131   "  --version\n"
 132   "              Print version information and exit.\n"
 133   "\n"
 134   HELP_AND_CONTACT_INFO
 135   "\n"
 136 ;
 137 
 138 // FIXME:  The warnings below should be collected into a single function,
 139 //          and also called after a user exec(), not just in dmtcp_launch.
 140 // static const char* theExecFailedMsg =
 141 //   "ERROR: Failed to exec(\"%s\"): %s\n"
 142 //   "Perhaps it is not in your $PATH?\n"
 143 //   "See `dmtcp_launch --help` for usage.\n"
 144 // ;
 145 
 146 static bool disableAllPlugins=false;
 147 static bool checkpointOpenFiles=false;
 148 
 149 static bool enablePtracePlugin=false;
 150 static bool enableModifyEnvPlugin=false;
 151 static bool enableRMPlugin=false;
 152 static bool explicitSrun = false;
 153 
 154 static bool enableIB2TcpPlugin=false;
 155 static bool enableIBPlugin=false;
 156 
 157 static bool enableAllocPlugin=true;
 158 static bool enableDlPlugin=true;
 159 static bool enableIPCPlugin=true;
 160 static bool enableSvipcPlugin=true;
 161 static bool enableTimerPlugin=true;
 162 
 163 #ifdef UNIQUE_CHECKPOINT_FILENAMES
 164 static bool enableUniqueCkptPlugin=true;
 165 #else
 166 static bool enableUniqueCkptPlugin=false;
 167 #endif
 168 // This is the base library.
 169 static bool enableLibDMTCP=true;
 170 
 171 // PID plugin must come last.
 172 static bool enablePIDPlugin=true;
 173 
 174 static string thePortFile;
 175 
 176 struct PluginInfo {
 177   bool *enabled;
 178   const char *lib;
 179 };
 180 
 181 static struct PluginInfo pluginInfo[] = {               // Default value
 182   {&enablePtracePlugin,     "libdmtcp_ptrace.so"},      // Disabled
 183   {&enableModifyEnvPlugin,  "libdmtcp_modify-env.so"},  // Disabled
 184   {&enableUniqueCkptPlugin, "libdmtcp_unique-ckpt.so"}, // Disabled
 185   {&enableIB2TcpPlugin,     "libdmtcp_ib2tcp.so"},      // Disabled
 186   {&enableIBPlugin,         "libdmtcp_infiniband.so"},  // Disabled
 187   {&enableRMPlugin,         "libdmtcp_batch-queue.so"}, // Disabled
 188   {&enableAllocPlugin,      "libdmtcp_alloc.so"},       // Enabled
 189   {&enableDlPlugin,         "libdmtcp_dl.so"},          // Enabled
 190   {&enableIPCPlugin,        "libdmtcp_ipc.so"},         // Enabled
 191   {&enableSvipcPlugin,      "libdmtcp_svipc.so"},       // Enabled
 192   {&enableTimerPlugin,      "libdmtcp_timer.so"},       // Enabled
 193   {&enableLibDMTCP,         "libdmtcp.so"},             // Enabled
 194   // PID plugin must come last.
 195   {&enablePIDPlugin,        "libdmtcp_pid.so"}          // Enabled
 196 };
 197 
 198 const size_t numLibs = sizeof(pluginInfo) / sizeof (struct PluginInfo);
 199 
 200 static CoordinatorMode allowedModes = COORD_ANY;
 201 
 202 //shift args
 203 #define shift argc--,argv++
 204 static void processArgs(int *orig_argc, char ***orig_argv,
 205                         string *tmpDir_p,
 206                         const char **host, const char **portStr)
 207 {
 208   int argc = *orig_argc;
 209   char **argv = *orig_argv;
 210   char *tmpdir_arg = NULL;
 211   *host = NULL; // uninitialized
 212   *portStr = NULL; // uninitialized
 213 
 214   if (argc == 1) {
 215     printf("%s", DMTCP_VERSION_AND_COPYRIGHT_INFO);
 216     printf("(For help: %s --help)\n\n", argv[0]);
 217     exit(DMTCP_FAIL_RC);
 218   }
 219 
 220   //process args
 221   shift;
 222   while (true) {
 223     string s = argc>0 ? argv[0] : "--help";
 224     if ((s=="--help") && argc<=1) {
 225       printf("%s", theUsage);
 226       exit(DMTCP_FAIL_RC);
 227     } else if ((s=="--version") && argc==1) {
 228       printf("%s", DMTCP_VERSION_AND_COPYRIGHT_INFO);
 229       exit(DMTCP_FAIL_RC);
 230     } else if (s == "-j" || s == "--join") {
 231       allowedModes = COORD_JOIN;
 232       shift;
 233     } else if (s == "--gzip") {
 234       setenv(ENV_VAR_COMPRESSION, "1", 1);
 235       shift;
 236     } else if (s == "--no-gzip") {
 237       setenv(ENV_VAR_COMPRESSION, "0", 1);
 238       shift;
 239     }
 240 #ifdef HBICT_DELTACOMP
 241     else if (s == "--hbict") {
 242       setenv(ENV_VAR_DELTACOMPRESSION, "1", 1);
 243       shift;
 244     } else if (s == "--no-hbict") {
 245       setenv(ENV_VAR_DELTACOMPRESSION, "0", 1);
 246       shift;
 247     }
 248 #endif
 249     else if (s == "--new-coordinator") {
 250       allowedModes = COORD_NEW;
 251       shift;
 252     } else if (s == "--no-coordinator") {
 253       allowedModes = COORD_NONE;
 254       shift;
 255     } else if (s == "-i" || s == "--interval") {
 256       setenv(ENV_VAR_CKPT_INTR, argv[1], 1);
 257       shift; shift;
 258     } else if (argv[0][0] == '-' && argv[0][1] == 'i' &&
 259                isdigit(argv[0][2])) { // else if -i5, for example
 260       setenv(ENV_VAR_CKPT_INTR, argv[0]+2, 1);
 261       shift;
 262     } else if (argc>1 && (s == "-h" || s == "--coord-host" || s == "--host")) {
 263       *host = argv[1];
 264       shift; shift;
 265     } else if (argc>1 && (s == "-p" || s == "--coord-port" || s == "--port")) {
 266       *portStr = argv[1];
 267       shift; shift;
 268     } else if (argv[0][0] == '-' && argv[0][1] == 'p' &&
 269                isdigit(argv[0][2])) { // else if -p0, for example
 270       *portStr = argv[0]+2; // Must use argv[0] here, and not s
 271       shift;
 272     } else if (argc>1 && s == "--port-file"){
 273       thePortFile = argv[1];
 274       shift; shift;
 275     } else if (argc>1 && (s == "-c" || s == "--ckptdir")) {
 276       setenv(ENV_VAR_CHECKPOINT_DIR, argv[1], 1);
 277       shift; shift;
 278     } else if (argc>1 && (s == "-t" || s == "--tmpdir")) {
 279       tmpdir_arg = argv[1];
 280       shift; shift;
 281     } else if (argc>1 && s == "--ckpt-signal") {
 282       setenv(ENV_VAR_SIGCKPT, argv[1], 1);
 283       shift; shift;
 284     } else if (s == "--checkpoint-open-files" || s == "--ckpt-open-files") {
 285       checkpointOpenFiles = true;
 286       shift;
 287     } else if (s == "--ptrace") {
 288       enablePtracePlugin = true;
 289       shift;
 290     } else if (s == "--modify-env") {
 291       enableModifyEnvPlugin = true;
 292       shift;
 293     } else if (s == "--ib" || s == "--infiniband") {
 294       enableIBPlugin = true;
 295       shift;
 296     } else if (s == "--ib2tcp") {
 297       enableIB2TcpPlugin = true;
 298       shift;
 299     } else if (s == "--disable-alloc-plugin") {
 300       setenv(ENV_VAR_ALLOC_PLUGIN, "0", 1);
 301       shift;
 302     } else if (s == "--disable-dl-plugin") {
 303       setenv(ENV_VAR_DL_PLUGIN, "0", 1);
 304       shift;
 305     } else if (s == "--no-plugins" || s == "--disable-all-plugins") {
 306       disableAllPlugins = true;
 307       shift;
 308     } else if (s == "--rm" || s == "--batch-queue") {
 309       enableRMPlugin = true;
 310       shift;
 311     } else if (s == "--explicit-srun" ) {
 312       explicitSrun = true;
 313       shift;
 314     } else if (s == "--with-plugin") {
 315       setenv(ENV_VAR_PLUGIN, argv[1], 1);
 316       shift; shift;
 317     } else if (s == "-q" || s == "--quiet") {
 318       *getenv(ENV_VAR_QUIET) = *getenv(ENV_VAR_QUIET) + 1;
 319       // Just in case a non-standard version of setenv is being used:
 320       setenv(ENV_VAR_QUIET, getenv(ENV_VAR_QUIET), 1);
 321       shift;
 322     } else if ( (s.length()>2 && s.substr(0,2)=="--") ||
 323               (s.length()>1 && s.substr(0,1)=="-" ) ) {
 324       printf("Invalid Argument\n%s", theUsage);
 325       exit(DMTCP_FAIL_RC);
 326     } else if (argc>1 && s=="--") {
 327       shift;
 328       break;
 329     } else {
 330       break;
 331     }
 332   }
 333   *tmpDir_p = Util::calcTmpDir(tmpdir_arg);
 334   *orig_argc = argc;
 335   *orig_argv = argv;
 336 }
 337 
 338 int main ( int argc, char** argv )
 339 {
 340   for (size_t fd = PROTECTED_FD_START; fd < PROTECTED_FD_END; fd++) {
 341     close(fd);
 342   }
 343 
 344   if (! getenv(ENV_VAR_QUIET))
 345     setenv(ENV_VAR_QUIET, "0", 0);
 346 
 347   string tmpDir = "tmpDir is not set";
 348   const char *host;
 349   const char *portStr;
 350   // This will change argv to refer to the target application.
 351   processArgs(&argc, &argv, &tmpDir, &host, &portStr);
 352 
 353   initializeJalib();
 354 
 355   UniquePid::ThisProcess(true);
 356   Util::initializeLogFile(tmpDir);
 357 
 358 #ifdef FORKED_CHECKPOINTING
 359   /* When this is robust, add --forked-checkpointing option on command-line,
 360    * with #ifdef FORKED_CHECKPOINTING around the option, change default of
 361    * configure.ac, dmtcp/configure.ac, to enable, and change them
 362    * from enable-forked... to disable-...
 363    */
 364   setenv(ENV_VAR_FORKED_CKPT, "1", 1);
 365 #endif
 366 
 367   // This code will go away when zero-mapped pages are implemented in MTCP.
 368   struct rlimit rlim;
 369   getrlimit(RLIMIT_STACK, &rlim);
 370   if (rlim.rlim_cur > 256*1024*1024 && rlim.rlim_cur != RLIM_INFINITY)
 371     JASSERT_STDERR <<
 372       "*** WARNING:  RLIMIT_STACK > 1/4 GB.  This causes each thread to"
 373       "\n***  receive a 1/4 GB stack segment.  Checkpoint/restart will be slow,"
 374       "\n***  and will potentially break if many threads are created."
 375       "\n*** Suggest setting (sh/bash):  ulimit -s 10000"
 376       "\n***                (csh/tcsh):  limit stacksize 10000"
 377       "\n*** prior to using DMTCP.  (This will be fixed in the future, when"
 378       "\n*** DMTCP supports restoring zero-mapped pages.)\n\n\n" ;
 379   // Remove this when zero-mapped pages are supported.  For segments with
 380   // no file backing:  Start with 4096 (page) offset and keep doubling offset
 381   // until finding region of memory segment with many zeroes.
 382   // Then mark as CS_ZERO_PAGES in MTCP instead of CS_RESTORE (or mark
 383   // entire segment as CS_ZERO_PAGES and then overwrite with CS_RESTORE
 384   // region for portion to be read back from checkpoint image.
 385   // For CS_ZERO_PAGES region, mmap // on restart, but don't write in zeroes.
 386   // Also, after checkpointing segment, munmap zero pages, and mmap them again.
 387   // Don't try to find all pages.  The above strategy may increase
 388   // the non-zero-mapped mapped pages to no more than double the actual
 389   // non-zero region (assuming that the zero-mapped pages are contiguous).
 390   // - Gene
 391 
 392   testMatlab(argv[0]);
 393   testJava(argv);  // Warn that -Xmx flag needed to limit virtual memory size
 394 
 395   // If libdmtcp.so is in standard search path and _also_ has setgid access,
 396   //   then LD_PRELOAD will work.
 397   // Otherwise, it will only work if the application does not use setuid and
 398   //   setgid access.  So, we test //   if the application does not use
 399   //   setuid/setgid.  (See 'man ld.so')
 400   // FIXME:  ALSO DO THIS FOR execwrappers.cpp:dmtcpPrepareForExec()
 401   //   Should pass libdmtcp.so path, and let testSetuid determine
 402   //     if setgid is set for it.  If so, no problem:  continue.
 403   //   If not, call testScreen() and adapt 'screen' to run using
 404   //     Util::patchArgvIfSetuid(argv[0], argv, &newArgv) (which shouldn't
 405   //     will just modify argv[0] to point to /tmp/dmtcp-USER@HOST/screen
 406   //     and other modifications:  doesn't need newArgv).
 407   //   If it's not 'screen' and if no setgid for libdmtcp.so, then testSetuid
 408   //    should issue the warning, unset our LD_PRELOAD, and hope for the best.
 409   //    A program like /usr/libexec/utempter/utempter (Fedora path)
 410   //    is short-lived and can be safely run.  Ideally, we should
 411   //    disable checkpoints while utempter is running, and enable checkpoints
 412   //    when utempter finishes.  See possible model at
 413   //    execwrappers.cpp:execLibProcessAndExit(), since the same applies
 414   //    to running /lib/libXXX.so for running libraries as executables.
 415   if (testSetuid(argv[0])) {
 416     char **newArgv;
 417     // THIS NEXT LINE IS DANGEROUS.  MOST setuid PROGRAMS CAN'T RUN UNPRIVILEGED
 418     Util::patchArgvIfSetuid(argv[0], argv, &newArgv);
 419     argv = newArgv;
 420   };
 421 
 422   if (argc > 0) {
 423     JTRACE("dmtcp_launch starting new program:")(argv[0]);
 424   }
 425 
 426   //set up CHECKPOINT_DIR
 427   if(getenv(ENV_VAR_CHECKPOINT_DIR) == NULL){
 428     const char* ckptDir = get_current_dir_name();
 429     if(ckptDir != NULL ){
 430       //copy to private buffer
 431       static string _buf = ckptDir;
 432       ckptDir = _buf.c_str();
 433     }else{
 434       ckptDir=".";
 435     }
 436     setenv ( ENV_VAR_CHECKPOINT_DIR, ckptDir, 0 );
 437     JTRACE("setting " ENV_VAR_CHECKPOINT_DIR)(ckptDir);
 438   }
 439 
 440   if ( checkpointOpenFiles )
 441     setenv( ENV_VAR_CKPT_OPEN_FILES, "1", 0 );
 442   else
 443     unsetenv( ENV_VAR_CKPT_OPEN_FILES);
 444 
 445   bool isElf, is32bitElf;
 446   if  (Util::elfType(argv[0], &isElf, &is32bitElf) == -1) {
 447     // Couldn't read argv_buf
 448     // FIXME:  This could have been a symbolic link.  Don't issue an error,
 449     //         unless we're sure that the executable is not readable.
 450     JASSERT_STDERR <<
 451       "*** ERROR:  Executable to run w/ DMTCP appears not to be readable,\n"
 452       "***         or no such executable in path.\n\n"
 453       << argv[0] << "\n";
 454     exit(DMTCP_FAIL_RC);
 455   } else {
 456     testStaticallyLinked(argv[0]);
 457   }
 458 
 459   if (getenv("DISPLAY") != NULL) {
 460     setenv("ORIG_DISPLAY", getenv("DISPLAY"), 1);
 461     // UNSET DISPLAY environment variable.
 462     unsetenv("DISPLAY");
 463   }
 464 
 465   // Unset SESSION_MANAGER environment variable. SESSION_MANAGER is used by the
 466   // X Window system to save and restore the current state of applications.
 467   // For example, on a session crash, the X session manager attempts to reopen
 468   // the applications that were open before the crash.  An application has to
 469   // create a (socket) connection to the SESSION_MANAGER to communicate the
 470   // current state.
 471   // See http://en.wikipedia.org/wiki/X_session_manager for more information.
 472   //
 473   // For our purposes, we don't care about session management and thus we
 474   // should disable the SESSION_MANAGER environment variable to prevent the
 475   // application from communication with the X session manager.
 476   if (getenv("SESSION_MANAGER") != NULL) {
 477     JTRACE("Unsetting SESSION_MANAGER environment variable.");
 478     unsetenv("SESSION_MANAGER");
 479   }
 480 
 481   if( explicitSrun ){
 482       setenv(ENV_VAR_EXPLICIT_SRUN, "1", 1);
 483   }
 484 
 485 // FIXME:  Unify this code with code prior to execvp in execwrappers.cpp
 486 //   Can use argument to dmtcpPrepareForExec() or getenv("DMTCP_...")
 487 //   from DmtcpWorker constructor, to distinguish the two cases.
 488   Util::adjustRlimitStack();
 489 
 490   DmtcpUniqueProcessId compId;
 491   CoordinatorInfo coordInfo;
 492   struct in_addr localIPAddr;
 493   int port = (portStr ? jalib::StringToInt(portStr) : UNINITIALIZED_PORT);
 494   // Initialize host and port now.  Will be used in low-level functions.
 495   Util::getCoordHostAndPort(allowedModes, &host, &port);
 496   CoordinatorAPI::instance().connectToCoordOnStartup(allowedModes, argv[0],
 497                                                      &compId, &coordInfo,
 498                                                      &localIPAddr);
 499   // If port was 0, we'll get new random port when coordinator starts up.
 500   Util::getCoordHostAndPort(allowedModes, &host, &port);
 501   Util::writeCoordPortToFile(port, thePortFile.c_str());
 502 
 503   string installDir =
 504     jalib::Filesystem::DirName(jalib::Filesystem::GetProgramDir());
 505 
 506 #if defined(__i386__) || defined(__arm__)
 507   if (Util::strEndsWith(installDir, "/lib/dmtcp/32")) {
 508     // If dmtcp_launch was compiled for 32 bits in a 64-bit O/S, then note:
 509     // DMTCP_ROOT/bin/dmtcp_launch is a symbolic link to:
 510     //    DMTCP_ROOT/bin/dmtcp_launch/lib/dmtcp/32/bin
 511     // GetProgramDir() followed the link.  So, we need to remove the suffix.
 512     char *str = const_cast<char*>(installDir.c_str());
 513     str[strlen(str) - strlen("/lib/dmtcp/32")] = '\0';
 514     installDir = str;
 515   }
 516 #endif
 517 
 518   /* We need to initialize SharedData here to make sure that it is
 519    * initialized with the correct coordinator timestamp.  The coordinator
 520    * timestamp is updated only during postCkpt callback. However, the
 521    * SharedData area may be initialized earlier (for example, while
 522    * recreating threads), causing it to use *older* timestamp.
 523    */
 524   SharedData::initialize(tmpDir.c_str(),
 525                          installDir.c_str(),
 526                          &compId,
 527                          &coordInfo,
 528                          &localIPAddr);
 529 
 530   // Set DLSYM_OFFSET env var(s).
 531   Util::prepareDlsymWrapper();
 532 
 533   setLDPreloadLibs(is32bitElf);
 534 
 535   //run the user program
 536   char **newArgv = NULL;
 537   if (testScreen(argv, &newArgv))
 538     execvp ( newArgv[0], newArgv );
 539   else
 540     execvp ( argv[0], argv );
 541 
 542   //should be unreachable
 543   JASSERT_STDERR <<
 544     "ERROR: Failed to exec(\"" << argv[0] << "\"): " << JASSERT_ERRNO << "\n"
 545     << "Perhaps it is not in your $PATH?\n"
 546     << "See `dmtcp_launch --help` for usage.\n";
 547   //fprintf(stderr, theExecFailedMsg, argv[0], JASSERT_ERRNO);
 548 
 549   return -1;
 550 }
 551 
 552 static int testMatlab(const char *filename)
 553 {
 554 #ifdef __GNUC__
 555 # if __GNUC__ == 4 && __GNUC_MINOR__ > 1
 556   static const char* theMatlabWarning =
 557     "\n**** WARNING:  Earlier Matlab releases (e.g. release 7.4) use an\n"
 558     "****  older glibc.  Later releases (e.g. release 7.9) have no problem.\n"
 559     "****\n"
 560     "****  If you are using an _earlier_ Matlab, please re-compile DMTCP\n"
 561     "****  with gcc-4.1 and g++-4.1\n"
 562     "**** env CC=gcc-4.1 CXX=g++-4.1 ./configure\n"
 563     "**** [ Also modify mtcp/Makefile to:  CC=gcc-4.1 ]\n"
 564     "**** [ Next, you may need an alternative Java JVM (see QUICK-START.md) ]\n"
 565     "**** [ Finally, run as:   dmtcp_launch matlab -nodisplay ]\n"
 566     "**** [   (DMTCP does not yet checkpoint X-Windows applications.) ]\n"
 567     "**** [ You may see \"Not checkpointing libc-2.7.so\".  This is normal. ]\n"
 568     "****   (Assuming you have done the above, Will now continue"
 569             " executing.)\n\n" ;
 570 
 571   // FIXME:  should expand filename and "matlab" before checking
 572   if ( strcmp(filename, "matlab") == 0 && getenv(ENV_VAR_QUIET) == NULL) {
 573     JASSERT_STDERR << theMatlabWarning;
 574     return -1;
 575   }
 576 # endif
 577 #endif
 578   return 0;
 579 }
 580 
 581 // FIXME:  Remove this when DMTCP supports zero-mapped pages
 582 static int testJava(char **argv)
 583 {
 584   static const char* theJavaWarning =
 585     "\n**** WARNING:  Sun/Oracle Java claims a large amount of memory\n"
 586     "****  for its heap on startup.  As of DMTCP version 1.2.4, DMTCP _does_\n"
 587     "****  handle zero-mapped virtual memory, but it may take up to a\n"
 588     "****  minute.  This will be fixed to be much faster in a future\n"
 589     "****  version of DMTCP.  In the meantime, if your Java supports it,\n"
 590     "****  use the -Xmx flag for a smaller heap:  e.g.  java -Xmx64M javaApp\n"
 591     "****  (Invoke dmtcp_launch with --quiet to avoid this msg.)\n\n" ;
 592 
 593   if (getenv(ENV_VAR_QUIET) != NULL
 594       && strcmp(getenv(ENV_VAR_QUIET), "0") != 0)
 595     return 0;
 596   if ( strcmp(argv[0], "java") == 0 ) {
 597     while (*(++argv) != NULL)
 598       if (strncmp(*argv, "-Xmx", sizeof("-Xmx")-1) == 0)
 599         return 0; // The user called java with -Xmx.  No need for warning.
 600   }
 601 
 602   // If user has more than 4 GB of RAM, warn them that -Xmx is faster.
 603   int fd;
 604   char buf[100];
 605   static const char *meminfoPrefix = "MemTotal:       ";
 606   if ( (fd = open("/proc/meminfo", O_RDONLY)) != -1 &&
 607     read(fd, buf, sizeof(meminfoPrefix) + 16) == sizeof(meminfoPrefix) + 16 &&
 608     strncmp(buf, meminfoPrefix, sizeof(meminfoPrefix)+1) == 0 &&
 609     atol(buf + sizeof(meminfoPrefix)) > 17000000) /* units of kB : mem > 4 GB */
 610       JASSERT_STDERR << theJavaWarning;
 611   if (fd != -1)
 612     close(fd);
 613   return -1;
 614 }
 615 
 616 static bool testSetuid(const char *filename)
 617 {
 618   if (Util::isSetuid(filename) &&
 619       strcmp(filename, "screen") != 0 && strstr(filename, "/screen") == NULL) {
 620 
 621     static const char* theSetuidWarning =
 622       "\n**** WARNING:  This process has the setuid or setgid bit set.  This is\n"
 623       "***  incompatible with the use by DMTCP of LD_PRELOAD.  The process\n"
 624       "***  will not be checkpointed by DMTCP.  Continuing and hoping\n"
 625       "***  for the best.  For some programs, you may wish to\n"
 626       "***  compile your own private copy, without using setuid permission.\n\n" ;
 627 
 628     JASSERT_STDERR << theSetuidWarning;
 629     sleep(3);
 630     return true;
 631   }
 632   return false;
 633 }
 634 
 635 void testStaticallyLinked(const char *pathname)
 636 {
 637   if (Util::isStaticallyLinked(pathname)) {
 638     JASSERT_STDERR <<
 639       "*** WARNING:  " ELF_INTERPRETER " --verify " << pathname << " returns\n"
 640       << "***  nonzero status.\n"
 641       << "*** This often means that " << pathname << " is\n"
 642       << "*** a statically linked target.  If so, you can confirm this with\n"
 643       << "*** the 'file' command.\n"
 644       << "***  The standard DMTCP only supports dynamically"
 645       << " linked executables.\n"
 646       << "*** If you cannot recompile dynamically, please talk to the"
 647       << " developers about a\n"
 648       << "*** custom DMTCP version for statically linked executables.\n"
 649       << "*** Proceeding for now, and hoping for the best.\n\n";
 650   }
 651   return;
 652 }
 653 
 654 // Test for 'screen' program, argvPtr is an in- and out- parameter
 655 static bool testScreen(char **argv, char ***newArgv)
 656 {
 657   if (Util::isScreen(argv[0])) {
 658     Util::setScreenDir();
 659     Util::patchArgvIfSetuid(argv[0], argv, newArgv);
 660     return true;
 661   }
 662   return false;
 663 }
 664 
 665 static void setLDPreloadLibs(bool is32bitElf)
 666 {
 667   // preloadLibs are to set LD_PRELOAD:
 668   //   LD_PRELOAD=PLUGIN_LIBS:UTILITY_DIR/libdmtcp.so:R_LIBSR_UTILITY_DIR/
 669   string preloadLibs = "";
 670   // FIXME:  If the colon-separated elements of ENV_VAR_PLUGIN are not
 671   //     absolute pathnames, then they must be expanded to absolute pathnames.
 672   //     Warn user if an absolute pathname is not valid.
 673   if ( getenv(ENV_VAR_PLUGIN) != NULL ) {
 674     preloadLibs += getenv(ENV_VAR_PLUGIN);
 675     preloadLibs += ":";
 676   }
 677   string preloadLibs32 = preloadLibs;
 678 
 679   //set up Alloc plugin
 680   if (getenv(ENV_VAR_ALLOC_PLUGIN) != NULL){
 681     const char *ptr = getenv(ENV_VAR_ALLOC_PLUGIN);
 682     if (strcmp(ptr, "1") == 0) {
 683       enableAllocPlugin = true;
 684     } else if (strcmp(ptr, "0") == 0) {
 685       enableAllocPlugin = false;
 686     } else {
 687       JASSERT(false) (getenv(ENV_VAR_ALLOC_PLUGIN))
 688         .Text("Invalid value for the environment variable.");
 689     }
 690   }
 691 
 692   // Setup Dl plugin
 693   if (getenv(ENV_VAR_DL_PLUGIN) != NULL){
 694     const char *ptr = getenv(ENV_VAR_DL_PLUGIN);
 695     if (strcmp(ptr, "1") == 0) {
 696       enableDlPlugin = true;
 697     } else if (strcmp(ptr, "0") == 0) {
 698       enableDlPlugin = false;
 699     } else {
 700       JASSERT(false) (getenv(ENV_VAR_DL_PLUGIN))
 701         .Text("Invalid value for the environment variable.");
 702     }
 703   }
 704 
 705   if (disableAllPlugins) {
 706     preloadLibs = Util::getPath("libdmtcp.so");
 707 #if defined(__x86_64__) || defined(__aarch64__)
 708     preloadLibs32 = Util::getPath("libdmtcp.so", true);
 709 #endif
 710   } else {
 711     for (size_t i = 0; i < numLibs; i++) {
 712       struct PluginInfo *p= &pluginInfo[i];
 713       if (*p->enabled) {
 714         preloadLibs += Util::getPath(p->lib, is32bitElf) + ":";
 715 #if defined(__x86_64__) || defined(__aarch64__)
 716         preloadLibs32 += Util::getPath(p->lib, true) + ":";
 717 #endif
 718       }
 719     }
 720   }
 721 
 722   setenv(ENV_VAR_HIJACK_LIBS, preloadLibs.c_str(), 1);
 723 #if defined(__x86_64__) || defined(__aarch64__)
 724   setenv(ENV_VAR_HIJACK_LIBS_M32, preloadLibs32.c_str(), 1);
 725 #endif
 726 
 727   // If dmtcp_launch was called with user LD_PRELOAD, and if
 728   //   dmtcp_launch survived the experience, then pass it back to user.
 729   if (getenv("LD_PRELOAD")) {
 730     setenv(ENV_VAR_ORIG_LD_PRELOAD, getenv("LD_PRELOAD"), 1);
 731     preloadLibs = preloadLibs + ":" + getenv("LD_PRELOAD");
 732 #if defined(__x86_64__) || defined(__aarch64__)
 733     preloadLibs32 = preloadLibs32 + ":" + getenv("LD_PRELOAD");
 734 #endif
 735   }
 736 
 737   setenv("LD_PRELOAD", preloadLibs.c_str(), 1);
 738 #if defined(__x86_64__) || defined(__aarch64__)
 739   if (is32bitElf) {
 740     string libdmtcp = Util::getPath("libdmtcp.so", true);
 741     JWARNING(libdmtcp != "libdmtcp.so") (libdmtcp)
 742       .Text("You appear to be checkpointing a 32-bit target under 64-bit Linux.\n"
 743             "DMTCP was unable to find the 32-bit installation.\n"
 744             "See DMTCP FAQ or try:\n"
 745             "  ./configure --enable-m32 && make clean && make -j && make install\n"
 746             "  ./configure && make clean && make -j && make install\n");
 747     setenv("LD_PRELOAD", preloadLibs.c_str(), 1);
 748   }
 749 #endif
 750   JTRACE("getting value of LD_PRELOAD")
 751     (getenv("LD_PRELOAD")) (preloadLibs) (preloadLibs32);
 752 }

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