root/dmtcp_launch.cpp
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- processArgs
- main
- testMatlab
- testJava
- testSetuid
- testStaticallyLinked
- testScreen
- 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 }