1 /****************************************************************************
2 * Copyright (C) 2006-2010 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 the dmtcp/src module of DMTCP (DMTCP:dmtcp/src). *
6 * *
7 * DMTCP:dmtcp/src 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:dmtcp/src 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 <unistd.h>
23 #include <stdlib.h>
24 #include <string>
25 #include <stdio.h>
26 #include "../jalib/jassert.h"
27 #include <ctype.h>
28 #include "../jalib/jfilesystem.h"
29 #include "../jalib/jconvert.h"
30 #include "constants.h"
31 #include "dmtcpworker.h"
32 #include "dmtcpmessagetypes.h"
33 #include "syscallwrappers.h"
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <sys/time.h>
41 #include <sys/resource.h>
42 #include <sys/personality.h>
43 #include <string.h>
44 #include <dlfcn.h>
45
46 int testMatlab(const char *filename);
47 void testSetuid(const char *filename);
48 int testStaticallyLinked(const char *filename);
49 int testScreen(char **argvPtr[]);
50 void adjust_rlimit_stack();
51 int elfType(const char *pathname, bool *isElf, bool *is32bitElf);
52 int safe_system(const char *command);
53
54 // gcc-4.3.4 -Wformat=2 issues false positives for warnings unless the format
55 // string has at least one format specifier with corresponding format argument.
56 // Ubuntu 9.01 uses -Wformat=2 by default.
57 static const char* theUsage =
58 "USAGE: \n"
59 " dmtcp_checkpoint [OPTIONS] <command> [args...]\n\n"
60 "OPTIONS:\n"
61 " --host, -h, (environment variable DMTCP_HOST):\n"
62 " Hostname where dmtcp_coordinator is run (default: localhost)\n"
63 " --port, -p, (environment variable DMTCP_PORT):\n"
64 " Port where dmtcp_coordinator is run (default: 7779)\n"
65 " --gzip, --no-gzip, (environment variable DMTCP_GZIP=[01]):\n"
66 " Enable/disable compression of checkpoint images (default: 1)\n"
67 " --ckptdir, -c, (environment variable DMTCP_CHECKPOINT_DIR):\n"
68 " Directory to store checkpoint images (default: ./)\n"
69 " --tmpdir, -t, (environment variable DMTCP_TMPDIR):\n"
70 " Directory to store temporary files \n"
71 " (default: $TMDPIR/dmtcp-$USER@$HOST or /tmp/dmtcp-$USER@$HOST)\n"
72 " --join, -j:\n"
73 " Join an existing coordinator, raise error if one already exists\n"
74 " --new, -n:\n"
75 " Create a new coordinator, raise error if one already exists\n"
76 " --new-coordinator:\n"
77 " Create a new coordinator even if one already exists\n"
78 " --batch, -b:\n"
79 " Enable batch mode i.e. start the coordinator on the same node on\n"
80 " a randomly assigned port (if no port is specified by --port)\n"
81 " --interval, -i, (environment variable DMTCP_CHECKPOINT_INTERVAL):\n"
82 " Time in seconds between automatic checkpoints.\n"
83 " Not allowed if --join is specified\n"
84 " --batch implies -i 3600, unless otherwise specified.\n"
85 " --no-check:\n"
86 " Skip check for valid coordinator and never start one automatically\n"
87 " --checkpoint-open-files:\n"
88 " Checkpoint open files and restore old working dir. (Default: do neither)\n"
89 " --mtcp-checkpoint-signal:\n"
90 " Signal number used internally by MTCP for checkpointing (default: 12)\n"
91 " --quiet, -q, (or set environment variable DMTCP_QUIET = 0, 1, or 2):\n"
92 " Skip banner and NOTE messages; if given twice, also skip WARNINGs\n\n"
93 "See http://dmtcp.sf.net/ for more information.\n"
94 ;
95
96 static const char* theBanner =
97 "DMTCP/MTCP Copyright (C) 2006-2010 Jason Ansel, Michael Rieker,\n"
98 " Kapil Arya, and Gene Cooperman\n"
99 "This program comes with ABSOLUTELY NO WARRANTY.\n"
100 "This is free software, and you are welcome to redistribute it\n"
101 "under certain conditions; see COPYING file for details.\n"
102 "(Use flag \"-q\" to hide this message.)\n\n"
103 ;
104
105 // FIXME: The warnings below should be collected into a single function,
106 // and also called after a user exec(), not just in dmtcp_checkpoint.
107 static const char* theExecFailedMsg =
108 "ERROR: Failed to exec(\"%s\"): %s\n"
109 "Perhaps it is not in your $PATH?\n"
110 "See `dmtcp_checkpoint --help` for usage.\n"
111 ;
112
113 static dmtcp::string _stderrProcPath()
114 {
115 return "/proc/" + jalib::XToString ( getpid() ) + "/fd/" + jalib::XToString ( fileno ( stderr ) );
116 }
117
118 static void *get_libc_symbol ( const char* name )
119 {
120 static void* handle = NULL;
121 if ( handle==NULL && ( handle=dlopen ( LIBC_FILENAME,RTLD_NOW ) ) == NULL )
122 {
123 fprintf ( stderr, "dmtcp: get_libc_symbol: ERROR in dlopen: %s \n",
124 dlerror() );
125 abort();
126 }
127
128 void* tmp = dlsym ( handle, name );
129 if ( tmp == NULL )
130 {
131 fprintf ( stderr, "dmtcp: get_libc_symbol: ERROR finding symbol %s using dlsym: %s \n",
132 name, dlerror() );
133 abort();
134 }
135 return tmp;
136 }
137
138 static void prepareDmtcpWrappers()
139 {
140 #ifndef ENABLE_DLOPEN
141 unsigned int wrapperOffsetArray[numLibcWrappers];
142 char *glibc_base_function_addr = NULL;
143
144 # define _FIRST_BASE_ADDR(name) if (glibc_base_function_addr == NULL) \
145 glibc_base_function_addr = (char *)&name;
146 FOREACH_GLIBC_BASE_FUNC(_FIRST_BASE_ADDR);
147
148 # define _GET_OFFSET(x) \
149 wrapperOffsetArray[enum_ ## x] = ((char*)get_libc_symbol(#x) \
150 - glibc_base_function_addr);
151 FOREACH_GLIBC_FUNC_WRAPPER(_GET_OFFSET);
152
153 dmtcp::ostringstream os;
154 for (int i = 0; i < numLibcWrappers; i++) {
155 os << std::hex << wrapperOffsetArray[i] << ";";
156 }
157
158 setenv(ENV_VAR_LIBC_FUNC_OFFSETS, os.str().c_str(), 1);
159 #else
160 unsetenv(ENV_VAR_LIBC_FUNC_OFFSETS);
161 #endif
162
163 #ifdef PTRACE
164 /*
165 * For the sake of dlsym wrapper. We compute address of _real_dlsym by adding
166 * dlsym_offset to address of dlopen after the exec into the user application.
167 */
168 void* tmp1 = NULL;
169 void* tmp2 = NULL;
170 int tmp3;
171 static void* handle = NULL;
172 if ( handle==NULL && ( handle=dlopen ( "libdl.so",RTLD_NOW ) ) == NULL )
173 {
174 fprintf ( stderr,"dmtcp: get_libc_symbol: ERROR in dlopen: %s \n",dlerror() );
175 abort();
176 }
177 tmp1 = (void *) &dlopen;
178 tmp2 = (void *) &dlsym;
179 tmp3 = (char *)tmp2 - (char *) tmp1;
180 char str[21] = {0} ;
181 sprintf(str,"%d",tmp3);
182 setenv(ENV_VAR_DLSYM_OFFSET, str, 0);
183 dlclose(handle);
184 #endif
185 }
186
187
188 //shift args
189 #define shift argc--,argv++
190 int main ( int argc, char** argv )
191 {
192 bool isSSHSlave=false;
193 bool autoStartCoordinator=true;
194 bool checkpointOpenFiles=false;
195 int allowedModes = dmtcp::DmtcpWorker::COORD_ANY;
196
197 if (! getenv(ENV_VAR_QUIET))
198 setenv(ENV_VAR_QUIET, "0", 0);
199
200 //process args
201 shift;
202 while(true){
203 dmtcp::string s = argc>0 ? argv[0] : "--help";
204 if(s=="--help" || s=="-h" && argc==1){
205 JASSERT_STDERR << theUsage;
206 //fprintf(stderr, theUsage, "");
207 return 1;
208 }else if(s=="--ssh-slave"){
209 isSSHSlave = true;
210 shift;
211 }else if(s == "--no-check"){
212 autoStartCoordinator = false;
213 shift;
214 }else if(s == "-j" || s == "--join"){
215 allowedModes = dmtcp::DmtcpWorker::COORD_JOIN;
216 shift;
217 }else if(s == "--gzip"){
218 setenv(ENV_VAR_COMPRESSION, "1", 1);
219 shift;
220 }else if(s == "--no-gzip"){
221 setenv(ENV_VAR_COMPRESSION, "0", 1);
222 shift;
223 }else if(s == "-n" || s == "--new"){
224 allowedModes = dmtcp::DmtcpWorker::COORD_NEW;
225 shift;
226 }else if(s == "--new-coordinator"){
227 allowedModes = dmtcp::DmtcpWorker::COORD_FORCE_NEW;
228 shift;
229 }else if(s == "-b" || s == "--batch"){
230 allowedModes = dmtcp::DmtcpWorker::COORD_BATCH;
231 shift;
232 }else if(s == "-i" || s == "--interval"){
233 setenv(ENV_VAR_CKPT_INTR, argv[1], 1);
234 shift; shift;
235 }else if(argc>1 && (s == "-h" || s == "--host")){
236 setenv(ENV_VAR_NAME_ADDR, argv[1], 1);
237 shift; shift;
238 }else if(argc>1 && (s == "-p" || s == "--port")){
239 setenv(ENV_VAR_NAME_PORT, argv[1], 1);
240 shift; shift;
241 }else if(argc>1 && (s == "-c" || s == "--ckptdir")){
242 setenv(ENV_VAR_CHECKPOINT_DIR, argv[1], 1);
243 shift; shift;
244 }else if(argc>1 && (s == "-t" || s == "--tmpdir")){
245 setenv(ENV_VAR_TMPDIR, argv[1], 1);
246 shift; shift;
247 }else if(argc>1 && s == "--mtcp-checkpoint-signal"){
248 setenv(ENV_VAR_SIGCKPT, argv[1], 1);
249 shift; shift;
250 }else if(s == "--checkpoint-open-files"){
251 checkpointOpenFiles = true;
252 shift;
253 }else if(s == "-q" || s == "--quiet"){
254 *getenv(ENV_VAR_QUIET) = *getenv(ENV_VAR_QUIET) + 1;
255 // Just in case a non-standard version of setenv is being used:
256 setenv(ENV_VAR_QUIET, getenv(ENV_VAR_QUIET), 1);
257 shift;
258 }else if( (s.length()>2 && s.substr(0,2)=="--") ||
259 (s.length()>1 && s.substr(0,1)=="-" ) ) {
260 JASSERT_STDERR << "Invalid Argument\n";
261 JASSERT_STDERR << theUsage;
262 return 1;
263 }else if(argc>1 && s=="--"){
264 shift;
265 break;
266 }else{
267 break;
268 }
269 }
270
271 dmtcp::UniquePid::setTmpDir(getenv(ENV_VAR_TMPDIR));
272
273 jassert_quiet = *getenv(ENV_VAR_QUIET) - '0';
274
275 #ifdef FORKED_CHECKPOINTING
276 /* When this is robust, add --forked-checkpointing option on command-line,
277 * with #ifdef FORKED_CHECKPOINTING around the option, change default of
278 * configure.ac, dmtcp/configure.ac, to enable, and change them
279 * from enable-forked... to disable-...
280 */
281 setenv(ENV_VAR_FORKED_CKPT, "1", 1);
282 #endif
283
284 if (jassert_quiet == 0)
285 JASSERT_STDERR << theBanner;
286
287 // This code will go away when zero-mapped pages are implemented in MTCP.
288 struct rlimit rlim;
289 getrlimit(RLIMIT_STACK, &rlim);
290 if (rlim.rlim_cur > 256*1024*1024 && rlim.rlim_cur != RLIM_INFINITY)
291 JASSERT_STDERR <<
292 "*** WARNING: RLIMIT_STACK > 1/4 GB. This causes each thread to"
293 "\n*** receive a 1/4 GB stack segment. Checkpoint/restart will be slow,"
294 "\n*** and will potentially break if many threads are created."
295 "\n*** Suggest setting (sh/bash): ulimit -s 10000"
296 "\n*** (csh/tcsh): limit stacksize 10000"
297 "\n*** prior to using DMTCP. (This will be fixed in the future, when"
298 "\n*** DMTCP supports restoring zero-mapped pages.)\n\n\n" ;
299 // Remove this when zero-mapped pages are supported. For segments with
300 // no file backing: Start with 4096 (page) offset and keep doubling offset
301 // until finding region of memory segment with many zeroes.
302 // Then mark as CS_ZERO_PAGES in MTCP instead of CS_RESTORE (or mark
303 // entire segment as CS_ZERO_PAGES and then overwrite with CS_RESTORE
304 // region for portion to be read back fom checkpoint image.
305 // For CS_ZERO_PAGES region, mmap // on restart, but don't write in zeroes.
306 // Also, after checkpointing segment, munmap zero pages, and mmap them again.
307 // Don't try to find all pages. The above strategy may increase
308 // the non-zero-mapped mapped pages to no more than double the actual
309 // non-zero region (assuming that the zero-mapped pages are contiguous).
310 // - Gene
311
312 testMatlab(argv[0]);
313
314 // If dmtcphijack.so is in standard search path and also has setgid access,
315 // then LD_PRELOAD will work. Otherwise, it will only work if the
316 // application does not use setuid and setgid access. So, we test
317 // if the application does not use setuid/setgid. (See 'man ld.so')
318 testSetuid(argv[0]);
319
320 prepareDmtcpWrappers();
321
322 if(autoStartCoordinator)
323 dmtcp::DmtcpWorker::startCoordinatorIfNeeded(allowedModes);
324
325 dmtcp::string dmtcphjk =
326 jalib::Filesystem::FindHelperUtility ( "dmtcphijack.so" );
327 dmtcp::string searchDir = jalib::Filesystem::GetProgramDir();
328
329 // Initialize JASSERT library here
330 dmtcp::ostringstream o;
331 o << dmtcp::UniquePid::getTmpDir() << "/jassertlog." << dmtcp::UniquePid(getpid());
332 JASSERT_INIT(o.str());
333
334 if (argc > 0)
335 JTRACE("dmtcp_checkpoint starting new program:")(argv[0]);
336
337 //setup CHECKPOINT_DIR
338 if(getenv(ENV_VAR_CHECKPOINT_DIR) == NULL){
339 const char* ckptDir = get_current_dir_name();
340 if(ckptDir != NULL ){
341 //copy to private buffer
342 static dmtcp::string _buf = ckptDir;
343 ckptDir = _buf.c_str();
344 }else{
345 ckptDir=".";
346 }
347 setenv ( ENV_VAR_CHECKPOINT_DIR, ckptDir, 0 );
348 JTRACE("setting " ENV_VAR_CHECKPOINT_DIR)(ckptDir);
349 }
350
351 dmtcp::string stderrDevice = jalib::Filesystem::ResolveSymlink ( _stderrProcPath() );
352
353 //TODO:
354 // When stderr is a pseudo terminal for IPC between parent/child processes,
355 // this logic fails and JASSERT may write data to FD 2 (stderr)
356 // this will cause problems in programs that use FD 2 (stderr) for algorithmic things...
357 if ( stderrDevice.length() > 0
358 && jalib::Filesystem::FileExists ( stderrDevice ) )
359 setenv ( ENV_VAR_STDERR_PATH,stderrDevice.c_str(), 0 );
360 else// if( isSSHSlave )
361 setenv ( ENV_VAR_STDERR_PATH, "/dev/null", 0 );
362
363 // If dmtcp_checkpoint was called with user LD_PRELOAD, and if
364 // if dmtcp_checkpoint survived the experience, then pass it back to user.
365 if (getenv("LD_PRELOAD"))
366 dmtcphjk = dmtcphjk + ":" + getenv("LD_PRELOAD");
367 setenv ( "LD_PRELOAD", dmtcphjk.c_str(), 1 );
368 setenv ( ENV_VAR_HIJACK_LIB, dmtcphjk.c_str(), 0 );
369 setenv ( ENV_VAR_UTILITY_DIR, searchDir.c_str(), 0 );
370 if ( getenv(ENV_VAR_SIGCKPT) != NULL )
|
Event tainted_string_return_content: |
"getenv" returns tainted string content. |
|
Event tainted_string: |
Passing tainted string "getenv("DMTCP_SIGCKPT")" to a function that cannot accept tainted data. |
371 setenv ( "MTCP_SIGCKPT", getenv(ENV_VAR_SIGCKPT), 1);
372 else
373 unsetenv("MTCP_SIGCKPT");
374
375 if ( checkpointOpenFiles )
376 setenv( ENV_VAR_CKPT_OPEN_FILES, "1", 0 );
377 else
378 unsetenv( ENV_VAR_CKPT_OPEN_FILES);
379
380 #ifdef PID_VIRTUALIZATION
381 setenv( ENV_VAR_ROOT_PROCESS, "1", 1 );
382 #endif
383
384 bool isElf, is32bitElf;
385 if (elfType(argv[0], &isElf, &is32bitElf) == -1) {
386 // Couldn't read argv_buf
387 // FIXME: This could have been a symbolic link. Don't issue an error,
388 // unless we're sure that the executable is not readable.
389 JASSERT_STDERR <<
390 "*** ERROR: Executable to run w/ DMTCP appears not to be readable.\n\n"
391 << argv[0];
392 exit(1);
393 } else {
394 #if defined(__x86_64__) && !defined(CONFIG_M32)
395 if (is32bitElf)
396 JASSERT_STDERR << "*** ERROR: You appear to be checkpointing "
397 << "a 32-bit target under 64-bit Linux.\n"
398 << "*** If this fails, then please try re-configuring DMTCP:\n"
399 << "*** configure --enable-m32 ; make clean ; make\n\n";
400 #endif
401
402 testStaticallyLinked(argv[0]);
403 }
404
405 // FIXME: Unify this code with code prior to execvp in execwrappers.cpp
406 // Can use argument to dmtcpPrepareForExec() or getenv("DMTCP_...")
407 // from DmtcpWorker constructor, to distinguish the two cases.
408 adjust_rlimit_stack();
409
410 //run the user program
411 char **newArgv = argv;
412 if (0 == testScreen(&newArgv))
413 execvp ( newArgv[0], newArgv );
414 else
415 execvp ( argv[0], argv );
416
417 //should be unreachable
418 JASSERT_STDERR <<
419 "ERROR: Failed to exec(\"" << argv[0] << "\"): " << JASSERT_ERRNO << "\n"
420 << "Perhaps it is not in your $PATH?\n"
421 << "See `dmtcp_checkpoint --help` for usage.\n";
422 //fprintf(stderr, theExecFailedMsg, argv[0], JASSERT_ERRNO);
423
424 return -1;
425 }
426
427 int expandPathname(const char *inpath, char * const outpath, size_t size) {
428 bool success = false;
429 if (*inpath == '/' || strstr(inpath, "/") != NULL) {
430 strncpy(outpath, inpath, size);
431 success = true;
432 } else if (inpath[0] == '~' && inpath[1] == '/') {
433 strncpy(outpath, getenv("HOME"), size);
434 strncpy(outpath + strlen(outpath), inpath + 2, size-2);
435 success = true;
436 } else {
437 char *pathVar = getenv("PATH");
438 while (*pathVar != '\0') {
439 char *nextPtr;
440 nextPtr = strstr(pathVar, ":");
441 if (nextPtr == NULL)
442 nextPtr = pathVar + strlen(pathVar);
443 memcpy(outpath, pathVar, nextPtr - pathVar);
444 *(outpath + (nextPtr - pathVar)) = '/';
445 strcpy(outpath + (nextPtr - pathVar) + 1, inpath);
446 JASSERT (strlen(outpath) < size) (strlen(outpath)) (size)
447 (outpath) .Text("Pathname too long; Use larger buffer.");
448 if (*nextPtr == '\0')
449 pathVar = nextPtr;
450 else // else *nextPtr == ':'
451 pathVar = nextPtr + 1; // prepare for next iteration
452 if (access(outpath, X_OK) == 0) {
453 success = true;
454 break;
455 }
456 }
457 }
458 return (success ? 0 : -1);
459 }
460
461 int elfType(const char *pathname, bool *isElf, bool *is32bitElf) {
462 const char *magic_elf = "\177ELF"; // Magic number for ELF
463 const char *magic_elf32 = "\177ELF\001"; // Magic number for ELF 32-bit
464 // Magic number for ELF 64-bit is "\177ELF\002"
465 const int len = strlen(magic_elf32);
466 char argv_buf[len];
467 char full_path[1024];
468 expandPathname(pathname, full_path, sizeof(full_path));
469 int fd = open(full_path, O_RDONLY);
470 if (fd == -1 || 5 != read(fd, argv_buf, 5))
471 return -1;
472 else
473 close (fd);
474 *isElf = (memcmp(magic_elf, argv_buf, strlen(magic_elf)) == 0);
475 *is32bitElf = (memcmp(magic_elf32, argv_buf, strlen(magic_elf32)) == 0);
476 return 0;
477 }
478
479 // Doesn't malloc. Returns pointer to within pathname.
480 char *dmtcp_basename(char *pathname) {
481 char *ptr = pathname;
482 while (*ptr++ != '\0')
483 if (*ptr == '/')
484 pathname = ptr+1;
485 return pathname;
486 }
487
488 // 'screen' requires directory with permissions 0700
489 int isdir_0700(const char *pathname) {
490 struct stat st;
491 stat(pathname, &st);
492 return (S_ISDIR(st.st_mode) == 1
493 && st.st_mode & 0777 == 0700
494 && st.st_uid == getuid()
495 && access(pathname, R_OK | W_OK | X_OK) == 0
496 );
497 }
498 int safe_mkdir(const char *pathname, mode_t mode) {
499 // If it exists and we can give it the right permissions, do it.
500 chmod(pathname, 0700);
501 if (isdir_0700(pathname))
502 return 0;
503 // else start over
504 unlink(pathname);
505 rmdir(pathname); // Maybe it was an empty directory
506 mkdir(pathname, 0700);
507 return isdir_0700(pathname);
508 }
509 int safe_system(const char *command) {
510 char *str = getenv("LD_PRELOAD");
511 dmtcp::string dmtcphjk;
512 if (str != NULL)
513 dmtcphjk = str;
514 unsetenv("LD_PRELOAD");
515 int rc = system(command);
516 if (str != NULL)
517 setenv( "LD_PRELOAD", dmtcphjk.c_str(), 1 );
518 return rc;
519 }
520
521 int testMatlab(const char *filename) {
522 #ifdef __GNUC__
523 # if __GNUC__ == 4 && __GNUC_MINOR__ > 1
524 static const char* theMatlabWarning =
525 "\n**** WARNING: Earlier Matlab releases (e.g. release 7.4) use an\n"
526 "**** older glibc. Later releases (e.g. release 7.9) have no problem.\n"
527 "**** \n"
528 "**** If you are using an _earlier_ Matlab, please re-compile DMTCP/MTCP\n"
529 "**** with gcc-4.1 and g++-4.1\n"
530 "**** env CC=gcc-4.1 CXX=g++-4.1 ./configure\n"
531 "**** [ Also modify mtcp/Makefile to: CC=gcc-4.1 ]\n"
532 "**** [ Next, you may need an alternative Java JVM (see QUICK-START) ]\n"
533 "**** [ Finally, run as: dmtcp_checkpoint matlab -nodisplay ]\n"
534 "**** [ (DMTCP does not yet checkpoint X-Windows applications.) ]\n"
535 "**** [ You may see \"Not checkpointing libc-2.7.so\". This is normal. ]\n"
536 "**** (Assuming you have done the above, Will now continue"
537 " executing.)\n\n" ;
538
539 // FIXME: should expand filename and "matlab" before checking
540 if ( strcmp(filename, "matlab") == 0 ) {
541 JASSERT_STDERR << theMatlabWarning;
542 return -1;
543 }
544 # endif
545 #endif
546 return 0;
547 }
548
549 void testSetuid(const char *filename) {
550 static const char* theSetuidWarning =
551 "\n**** WARNING: This process has the setuid or setgid bit set. This is\n"
552 "*** incompatible with the use by DMTCP of LD_PRELOAD. The process\n"
553 "*** will not be checkpointed by DMTCP. Continuing and hoping\n"
554 "*** for the best. For some programs, you may wish to\n"
555 "*** compile your own private copy, without using setuid permission.\n\n" ;
556 char pathname[1024];
557 if (expandPathname(filename, pathname, sizeof(pathname)) == 0) {
558 struct stat buf;
559 int rc = stat(pathname, &buf);
560 // screen tested separately. Exclude it here.
561 if (rc == 0 && (buf.st_mode & S_ISUID || buf.st_mode & S_ISGID
562 && strcmp(pathname, "screen") != 0
563 && strstr(pathname, "/screen") == NULL)) {
564 JASSERT_STDERR << theSetuidWarning;
565 sleep(3);
566 }
567 }
568 }
569
570 int testStaticallyLinked(const char *filename) {
571 bool isElf, is32bitElf;
572 char pathname[1024];
573 expandPathname(filename, pathname, sizeof(pathname));
574 elfType(pathname, &isElf, &is32bitElf);
575 #if defined(__x86_64__) && !defined(CONFIG_M32)
576 dmtcp::string cmd = is32bitElf ? "/lib/ld-linux.so.2 --verify "
577 : "/lib64/ld-linux-x86-64.so.2 --verify " ;
578 #else
579 dmtcp::string cmd = "/lib/ld-linux.so.2 --verify " ;
580 #endif
581 cmd = cmd + pathname + " > /dev/null";
582 // FIXME: When tested on dmtcp/test/pty.c, 'ld.so -verify' returns
583 // nonzero status. Why is this? It's dynamically linked.
584 if ( isElf && safe_system(cmd.c_str()) ) {
585 JASSERT_STDERR <<
586 "*** WARNING: /lib/ld-2.10.1.so --verify " << pathname << " returns\n"
587 << "*** nonzero status. This often means that " << pathname << " is\n"
588 << "*** a statically linked target. If so, you can confirm this with\n"
589 << "*** the 'file' command.\n"
590 << "*** The standard DMTCP only supports dynamically"
591 << " linked executables.\n"
592 << "*** If you cannot recompile dynamically, please talk to the"
593 << " developers about a\n"
594 << "*** custom DMTCP version for statically linked executables.\n"
595 << "*** Proceeding for now, and hoping for the best.\n\n";
596 return -1;
597 } else
598 return 0;
599 }
600
601 void adjust_rlimit_stack() {
602 #ifdef __i386__
603 // This is needed in 32-bit Ubuntu 9.10, to fix bug with test/dmtcp5.c
604 // NOTE: Setting personality() is cleanest way to force legacy_va_layout,
605 // but there's currently a bug on restart in the sequence:
606 // checkpoint -> restart -> checkpoint -> restart
607 # if 0
608 { unsigned long oldPersonality = personality(0xffffffffL);
609 if ( ! (oldPersonality & ADDR_COMPAT_LAYOUT) ) {
610 // Force ADDR_COMPAT_LAYOUT for libs in high mem, to avoid vdso conflict
611 personality(oldPersonality & ADDR_COMPAT_LAYOUT);
612 JTRACE( "setting ADDR_COMPAT_LAYOUT" );
613 setenv("DMTCP_ADDR_COMPAT_LAYOUT", "temporarily is set", 1);
614 }
615 }
616 # else
617 { struct rlimit rlim;
618 getrlimit(RLIMIT_STACK, &rlim);
619 if (rlim.rlim_cur != RLIM_INFINITY) {
620 char buf[100];
621 sprintf(buf, "%lu", rlim.rlim_cur); // "%llu" for BSD/Mac OS
622 JTRACE( "setting rlim_cur for RLIMIT_STACK" ) ( rlim.rlim_cur );
623 setenv("DMTCP_RLIMIT_STACK", buf, 1);
624 // Force kernel's internal compat_va_layout to 0; Force libs to high mem.
625 rlim.rlim_cur = rlim.rlim_max;
626 // FIXME: if rlim.rlim_cur != RLIM_INFINITY, then we should warn the user.
627 setrlimit(RLIMIT_STACK, &rlim);
628 // After exec, process will restore DMTCP_RLIMIT_STACK in DmtcpWorker()
629 }
630 }
631 # endif
632 #endif
633 }
634
635 // Test for 'screen' program, argvPtr is an in- and out- parameter
636 int testScreen(char **argvPtr[]) {
637 struct stat st;
638 // If screen has setuid or segid bits set, ...
639 char *pathname_base = dmtcp_basename((*argvPtr)[0]);
640 char pathname[1024];
641 if ((*argvPtr)[0] == NULL)
642 return -1;
643 if (expandPathname((*argvPtr)[0], pathname, sizeof(pathname)) != 0)
644 return -1;
645 if ( strcmp(pathname_base, "screen") == 0
646 && stat(pathname, &st) == 0
647 && (st.st_mode & S_ISUID || st.st_mode & S_ISGID) ) {
648 dmtcp::string tmpdir = dmtcp::UniquePid::getTmpDir() + "/" + "uscreens";
649 safe_mkdir(tmpdir.c_str(), 0700);
650 setenv("SCREENDIR", tmpdir.c_str(), 1);
651
652 static char cmdBuf[1024];
653 bool isElf, is32bitElf;
654 char ** oldArgv = *argvPtr; // Initialize oldArgv with argument passed here
655 *(char **)(cmdBuf+sizeof(cmdBuf)-sizeof(char *)) = NULL;
656 expandPathname(oldArgv[0], cmdBuf, sizeof(cmdBuf));
657 #define COPY_SCREEN
658 #ifdef COPY_SCREEN
659 // cp /usr/bin/screen /tmp/dmtcp-USER@HOST/screen
660 char *newArgv0 = cmdBuf + strlen(cmdBuf) + 1;
661 snprintf(newArgv0, sizeof(cmdBuf)-(newArgv0-cmdBuf), "%s/%s",
662 dmtcp::UniquePid::getTmpDir().c_str(), pathname_base);
663 unlink(newArgv0); // Remove any stale copy, just in case it's not right.
664 char *cpCmd = newArgv0 + strlen(newArgv0) + 1;
665 snprintf(cpCmd, sizeof(cmdBuf)-(cpCmd-cmdBuf), "cp %s %s",
666 pathname, newArgv0);
667 safe_system(cpCmd);
668 JASSERT (access(newArgv0, X_OK) == 0) (newArgv0) (JASSERT_ERRNO);
669 (*argvPtr)[0] = newArgv0;
670 return 0;
671 #else
672 // Translate: screen to: /lib/ld-linux.so /usr/bin/screen
673 // This version is more general, but has a bug on restart:
674 // memory layout is altered on restart, and so brk() doesn't match.
675 // Switch argvPtr from ptr to input to ptr to output now.
676 *argvPtr = (char **)(cmdBuf + strlen(cmdBuf) + 1); // ... + 1 for '\0'
677 // Use /lib64 if 64-bit O/S and not 32-bit app:
678 # if defined(__x86_64__) && !defined(CONFIG_M32)
679 elfType(cmdBuf, &isElf, &is32bitElf);
680 if (is32bitElf)
681 (*argvPtr)[0] = (char *)"/lib/ld-linux.so.2";
682 else
683 (*argvPtr)[0] = (char *)"/lib64/ld-linux-x86-64.so.2";
684 # else
685 (*argvPtr)[0] = (char *)"/lib/ld-linux.so.2";
686 # endif
687 (*argvPtr)[1] = cmdBuf;
688 for (int i = 1; oldArgv[i] != NULL; i++)
689 *argvPtr[i+1] = oldArgv[i];
690 JASSERT ((char *)cmdBuf[sizeof(cmdBuf)-sizeof(char *)] == NULL)
691 (sizeof(cmdBuf)) .Text("Expanded command longer than sizeof(cmdBuf");
692 return 0;
693 #endif
694 } else
695 return -1;
696 }