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} ;
|
Event secure_coding: |
[VERY RISKY]. Using "sprintf" can cause a buffer overflow when done incorrectly. Because sprintf() assumes an arbitrarily long string, callers must be careful not to overflow the actual space of the destination. Use snprintf() instead, or correct precision specifiers. |
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 )
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 }