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  	}