int main(int argc, char **argv) {
  int fd = -1;
  char magicbuf[MAGIC_LEN], *restorename;
  char *version = PACKAGE_VERSION;

  restorename = argv[1];
  if (argc == 1 || (strcmp(argv[1], "--help") == 0 && argc == 2)) {
    printf("%s", theUsage);
    return 1;
  } else if (strcmp (argv[1], "--version") == 0 && argc == 2) {
    printf("%s\n", (version[0] == '\0' ? "Standalone MTCP" : version));
    return 1;
  } else if (restorename[0] == '-' && restorename[1] == '\0') {
    fd = 0; /* read from stdin */
  } else {    /* argv[1] should be a real filename */
    if (-1 == (fd = open(restorename, O_RDONLY))) {
      perror("open");
      return 1; }
  }

  memset(magicbuf, 0, sizeof magicbuf);
  readall(fd, magicbuf, MAGIC_LEN);
  if (memcmp (magicbuf, "DMTCP_CHECKPOINT", MAGIC_LEN) == 0) {
    while (memcmp(magicbuf, MAGIC, MAGIC_LEN) != 0) {
      int i;
      for (i = 0; i < MAGIC_LEN-1; i++)
        magicbuf[i] = magicbuf[i+1];
      magicbuf[MAGIC_LEN-1] = '\0'; /* MAGIC should be a string w/o '\0' */
      if (0 == readall(fd, magicbuf+(MAGIC_LEN-1), 1)) /* if EOF */
        break;
    }
  }
  if (memcmp (magicbuf, MAGIC, MAGIC_LEN) != 0) {
    char command[512];
    fprintf (stderr, "readmtcp: Not an mtcp image; trying it as dmtcp image\n");
    sprintf (command, "gzip -dc %s | %s -", restorename, argv[0]);
    exit( system(command) );
  }


  /* Find where the restore image goes */
  VA restore_begin;
  size_t restore_size;
  void *restore_start; /* will be bound to fnc, mtcp_restore_start */
  void (*finishrestore) (void);

  /* Set the resource limits for stack from saved values */
  struct rlimit stack_rlimit;

#ifdef FAST_CKPT_RST_VIA_MMAP
  Area area;
  fastckpt_read_header(fd, &stack_rlimit, &area, (VA*) &restore_start);
  restore_begin = area.addr;
  restore_size = area.size;
  finishrestore = (void*) fastckpt_get_finishrestore();

  printf("mtcp_restart: saved stack resource limit:" \
	 " soft_lim: %lu, hard_lim: %lu\n",
	 stack_rlimit.rlim_cur, stack_rlimit.rlim_max);
  printf("*** restored libmtcp.so\n");

  printf("%p-%p rwxp %p 00:00 0          [libmtcp.so]\n",
	restore_begin, restore_begin + restore_size, restore_begin);
  printf("restore_start routine: %p\n", restore_start);

  printf("*** finishrestore\n");
  printf("finishrestore routine: %p\n", finishrestore);
#else
  readcs (fd, CS_STACKRLIMIT); /* resource limit for stack */
  readall(fd, &stack_rlimit, sizeof stack_rlimit);
  printf("mtcp_restart: saved stack resource limit:" \
	 " soft_lim: %lu, hard_lim: %lu\n",
	 stack_rlimit.rlim_cur, stack_rlimit.rlim_max);

  printf("*** restored libmtcp.so\n");
  readcs (fd, CS_RESTOREBEGIN); /* beginning of checkpointed libmtcp.so image */
  readall(fd, &restore_begin, sizeof restore_begin);
  readcs (fd, CS_RESTORESIZE); /* size of checkpointed libmtcp.so image */
  readall(fd, &restore_size, sizeof restore_size);
  readcs (fd, CS_RESTORESTART);
  readall(fd, &restore_start, sizeof restore_start);
  readcs (fd, CS_RESTOREIMAGE);
  skipfile (fd, restore_size);

  printf("%p-%p rwxp %p 00:00 0          [libmtcp.so]\n",
	restore_begin, restore_begin + restore_size, restore_begin);
  printf("restore_start routine: %p\n", restore_start);


  printf("*** finishrestore\n");
  readcs (fd, CS_FINISHRESTORE);
  readall(fd, &finishrestore, sizeof finishrestore);
  printf("finishrestore routine: %p\n", finishrestore);


  char linkbuf[FILENAMESIZE];
  int fdnum, linklen ;
  struct stat statbuf;
  off_t offset;

  printf("*** file descriptors\n");
  readcs (fd, CS_FILEDESCRS);
  while (1) {

    /* Read parameters of next file to restore */

    readall(fd, &fdnum, sizeof fdnum);
    if (fdnum < 0) break;
    readall(fd, &statbuf, sizeof statbuf);
    readall(fd, &offset, sizeof offset);
    readall(fd, &linklen, sizeof linklen);
    if ((size_t)linklen >= sizeof linkbuf) {
      printf ("filename too long %d\n", linklen);
      exit(1);
    }
    readall(fd, linkbuf, linklen);
    linkbuf[linklen] = '\0';
  }
#endif

  printf("*** memory sections\n");
  while(1) {
    Area area;
    char cstype;
#ifdef FAST_CKPT_RST_VIA_MMAP
    if (fastckpt_get_next_area_dscr(&area) == 0) break;
#else
    readall(fd, &cstype, sizeof cstype);
    if (cstype == CS_THEEND) break;
    if (cstype != CS_AREADESCRIP) {
      printf ("readmtcp: expected CS_AREADESCRIP but had %d\n", cstype);
      exit(1);
    }

    readall(fd, &area, sizeof area);
    readcs (fd, CS_AREACONTENTS);
#ifdef ANDROID
    if ((area.prot & MTCP_PROT_SKIP_PAGE) != 0) {
      printf("%p-%p %s skipped\n", area.addr, area.addr + area.size, area.name);
    } else
#endif
    if ((area.prot & MTCP_PROT_ZERO_PAGE) == 0) {
      skipfile (fd, area.size);
    }
#endif
    printf("%p-%p %c%c%c%c %8x 00:00 0          %s\n",
	   area.addr, area.addr + area.size,
	    ( area.prot & PROT_READ  ? 'r' : '-' ),
	    ( area.prot & PROT_WRITE ? 'w' : '-' ),
	    ( area.prot & PROT_EXEC  ? 'x' : '-' ),
	    ( area.flags & MAP_SHARED ? 's'
              : ( area.flags & MAP_ANONYMOUS ? 'p' : '-' ) ),
	    0, area.name);
  }

  printf("*** done\n");
   close (fd);
   mtcp_restore_cpfd = -1;
   return 0;
}
Beispiel #2
0
int main (int argc, char *argv[], char *envp[])
{
  char magicbuf[MAGIC_LEN], *restorename;
  int fd, verify;
  size_t restore_size, offset=0;
  void *restore_begin, *restore_mmap;
  void (*restore_start) (int fd, int verify, pid_t decomp_child_pid,
                         char *ckpt_newname, char *cmd_file,
                         char *argv[], char *envp[]);
  char cmd_file[PATH_MAX+1];
  char ckpt_newname[PATH_MAX+1] = "";
  char **orig_argv = argv;
  int orig_argc = argc;
  environ = envp;

  if (mtcp_sys_getuid() == 0 || mtcp_sys_geteuid() == 0) {
    mtcp_printf("Running mtcp_restart as root is dangerous.  Aborting.\n" \
	   "If you still want to do this (at your own risk)," \
	   "  then modify mtcp/%s:%d and re-compile.\n",
	   __FILE__, __LINE__ - 4);
    mtcp_abort();
  }

  // Turn off randomize_va (by re-exec'ing) or warn user if vdso_enabled is on.
  mtcp_check_vdso_enabled();

  fd = decomp_child_pid = -1;
  verify = 0;

  shift;
  while (1) {
    if (argc == 0 || (mtcp_strcmp(argv[0], "--help") == 0 && argc == 1)) {
      mtcp_printf("%s", theUsage);
      return (-1);
    } else if (mtcp_strcmp (argv[0], "--version") == 0 && argc == 1) {
      mtcp_printf("%s", VERSION_AND_COPYRIGHT_INFO);
      return (-1);
    } else if (mtcp_strcmp (argv[0], "--verify") == 0 && argc == 2) {
      verify = 1;
      restorename = argv[1];
      break;
    } else if (mtcp_strcmp (argv[0], "--offset") == 0 && argc >= 3) {
      offset = mtcp_atoi(argv[1]);
      shift; shift;
    } else if (mtcp_strcmp (argv[0], "--fd") == 0 && argc >= 2) {
      fd = mtcp_atoi(argv[1]);
      shift; shift;
    } else if (mtcp_strcmp (argv[0], "--gzip-child-pid") == 0 && argc >= 2) {
      decomp_child_pid = mtcp_atoi(argv[1]);
      shift; shift;
    } else if (mtcp_strcmp (argv[0], "--rename-ckpt") == 0 && argc >= 2) {
      mtcp_strncpy(ckpt_newname, argv[1], PATH_MAX);
      shift; shift;
    } else if (mtcp_strcmp (argv[0], "--stderr-fd") == 0 && argc >= 2) {
      // If using with DMTCP/jassert, Pass in a non-standard stderr
      dmtcp_info_stderr_fd = mtcp_atoi(argv[1]);
      shift; shift;
    } else if (mtcp_strcmp (argv[0], "--") == 0 && argc == 2) {
      restorename = argv[1];
      break;
    } else if (argc == 1) {
      restorename = argv[0];
      break;
    } else {
      mtcp_printf("%s", theUsage);
      return (-1);
    }
  }
  // Restore argc and argv pointer
  argv = orig_argv;
  argc = orig_argc;

  /* XXX XXX XXX:
   *    DO NOT USE mtcp_printf OR DPRINTF BEFORE THIS BLOCK, IT'S DANGEROUS AND
   *    CAN MESS UP YOUR PROCESSES BY WRITING GARBAGE TO THEIR STDERR FD,
   *    IF THEY ARE NOT USING IT AS STDERR.
   *                                                                   --Kapil
   */

  if (fd != -1 && decomp_child_pid != -1) {
    restorename = NULL;
  } else if ((fd == -1 && decomp_child_pid != -1) ||
             (offset != 0 && fd != -1)) {
    mtcp_printf("%s", theUsage);
    return (-1);
  }

  if (restorename) {
#if 1
    if (mtcp_sys_access(restorename, R_OK) != 0 && mtcp_sys_errno == EACCES) {
      MTCP_PRINTF("\nProcess does not have read permission for\n" \
	          "  checkpoint image (%s).\n" \
                  "  (Check file permissions, UIDs etc.)\n",
                  restorename);
      mtcp_abort();
    }
#else
    struct stat buf;
    int rc = mtcp_sys_stat(restorename, &buf);
    if (rc == -1) {
      MTCP_PRINTF("Error %d stat()'ing ckpt image %s.",
                  mtcp_sys_errno, restorename);
      mtcp_abort();
    } else if (buf.st_uid != mtcp_sys_getuid()) { /*Could also run if geteuid()
                                                    matches*/
      MTCP_PRINTF("\nProcess uid (%d) doesn't match uid (%d) of\n" \
	          "  checkpoint image (%s).\n" \
		  "This is dangerous.  Aborting for security reasons.\n" \
                  "If you still want to do this, modify mtcp/%s:%d and"
                  "  re-compile.\n",
                  mtcp_sys_getuid(), buf.st_uid, restorename,
                  __FILE__, __LINE__ - 5);
      mtcp_abort();
    }
#endif
  }

  if (mtcp_strlen(ckpt_newname) == 0 && restorename != NULL && offset != 0) {
    mtcp_strncpy(ckpt_newname, restorename, PATH_MAX);
  }

  if (restorename!=NULL) fd = open_ckpt_to_read(restorename, envp);
  if (offset>0) {
    //skip into the file a bit
    VA addr = (VA) mtcp_sys_mmap(0, offset, PROT_READ | PROT_WRITE,
                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (addr == MAP_FAILED) {
      MTCP_PRINTF("mmap failed with error %d\n", mtcp_sys_errno);
      mtcp_abort();
    }
    mtcp_readfile(fd, addr, offset);
    if (mtcp_sys_munmap(addr, offset) == -1) {
      MTCP_PRINTF("munmap failed with error %d\n", mtcp_sys_errno);
      mtcp_abort();
    }
  }
  mtcp_memset(magicbuf, 0, sizeof magicbuf);
  mtcp_readfile (fd, magicbuf, MAGIC_LEN);
  if (mtcp_memcmp (magicbuf, MAGIC, MAGIC_LEN) != 0) {
    MTCP_PRINTF("'%s' is '%s', but this restore is '%s' (fd=%d)\n",
                restorename, magicbuf, MAGIC, fd);
    return (-1);
  }

  /* Set the resource limits for stack from saved values */
  struct rlimit stack_rlimit;

#ifdef FAST_CKPT_RST_VIA_MMAP
  Area area;
  fastckpt_read_header(fd, &stack_rlimit, &area, (VA*) &restore_start);
  restore_begin = area.addr;
  restore_size = area.size;
#else
  mtcp_readcs (fd, CS_STACKRLIMIT); /* resource limit for stack */
  mtcp_readfile (fd, &stack_rlimit, sizeof stack_rlimit);
  /* Find where the restore image goes */
  mtcp_readcs (fd, CS_RESTOREBEGIN); /* beginning of checkpointed libmtcp.so image */
  mtcp_readfile (fd, &restore_begin, sizeof restore_begin);
  mtcp_readcs (fd, CS_RESTORESIZE); /* size of checkpointed libmtcp.so image */
  mtcp_readfile (fd, &restore_size, sizeof restore_size);
  mtcp_readcs (fd, CS_RESTORESTART);
  mtcp_readfile (fd, &restore_start, sizeof restore_start);

  DPRINTF("saved stack resource limit: soft_lim:%p, hard_lim:%p\n",
          stack_rlimit.rlim_cur, stack_rlimit.rlim_max);

#endif // FAST_CKPT_RST_VIA_MMAP
  mtcp_sys_setrlimit(RLIMIT_STACK, &stack_rlimit);

  /* Read in the restore image to same address where it was loaded at time
   *  of checkpoint.  This is libmtcp.so, including both text and data sections
   *  as a single section.  Hence, we need both write and exec permission,
   *  and MAP_ANONYMOUS, since the data could have changed.
   */

  DPRINTF("restoring anonymous area %p at %p\n", restore_size, restore_begin);

  if (mtcp_sys_munmap(restore_begin, restore_size) < 0) {
    MTCP_PRINTF("failed to unmap region at %p\n", restore_begin);
    mtcp_abort ();
  }

#ifdef FAST_CKPT_RST_VIA_MMAP
  fastckpt_load_restore_image(fd, &area);
#else
  restore_mmap = mtcp_safemmap (restore_begin, restore_size,
                                PROT_READ | PROT_WRITE | PROT_EXEC,
                                MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0);
  if (restore_mmap == MAP_FAILED) {
#ifndef _XOPEN_UNIX
    MTCP_PRINTF("Does mmap here support MAP_FIXED?\n");
#endif
    if (mtcp_sys_errno != EBUSY) {
      MTCP_PRINTF("Error %d creating %p byte restore region at %p.\n",
                  mtcp_sys_errno, restore_size, restore_begin);
      mtcp_abort ();
    } else {
      MTCP_PRINTF("restarting due to address conflict...\n");
      mtcp_sys_close (fd);
      mtcp_sys_execve (argv[0], argv, envp);
    }
  }
  if (restore_mmap != restore_begin) {
    MTCP_PRINTF("%p byte restore region at %p got mapped at %p\n",
                restore_size, restore_begin, restore_mmap);
    mtcp_abort ();
  }
  mtcp_readcs (fd, CS_RESTOREIMAGE);
  mtcp_readfile (fd, restore_begin, restore_size);
#endif

#ifndef __x86_64__
  // Copy command line to libmtcp.so, so that we can re-exec if randomized vdso
  //   steps on us.  This won't be needed when we use the linker to map areas.
  cmd_file[0] = '\0';
  { int cmd_len = mtcp_sys_readlink("/proc/self/exe", cmd_file, PATH_MAX);
    if (cmd_len == -1)
      MTCP_PRINTF("WARNING:  Couldn't find /proc/self/exe."
		  "  Trying to continue anyway.\n");
    else
      cmd_file[cmd_len] = '\0';
  }
#endif

#ifdef LIBC_STATIC_AVAILABLE
/********************************************************************
 * Apparently, there is no consistent way to define LIBC_STATIC_AVAILABLE.
 * The purpose of the code below is to be able to use a symbolic debugger
 * like gdb when dmtcp_restart calls MTCP.  It would print a command that
 * you can paste into gdb to allow debugging inside the function restore_start.
 * When "ifdef LIBC_STATIC_AVAILABLE" was added, mtcp/Makefile was modified
 * to forbid using functions from libc.a like popen.  If you want to debug
 * restore_start(), you should read the code below and manually calculate
 * by hand what this used to automatically calculate.  For a semi-automated
 * substitute, when you reach restore_start(), call it with (gdb) si
 * Then try:  (gdb) shell ../utils/gdb-add-libmtcp-symbol-file.py
 * where ADDR will be restore_start or an arb. address in restore_start()
 ********************************************************************/
# ifdef DEBUG
  char *p, symbolbuff[256];
  FILE *symbolfile;
  long textbase; /* offset */

  MTCP_PRINTF("restore_begin=%p, restore_start=%p\n",
      	restore_begin, restore_start);
  textbase = 0;

  symbolfile = popen ("readelf -S libmtcp.so", "r");
  if (symbolfile != NULL) {
    while (fgets (symbolbuff, sizeof symbolbuff, symbolfile) != NULL) {
      if (memcmp (symbolbuff + 5, "] .text ", 8) == 0) {
        textbase = strtoul (symbolbuff + 41, &p, 16);
      }
    }
    pclose (symbolfile);
    if (textbase != 0) {
      mtcp_printf("\n**********\nmtcp_restart*: The symbol table of the"
      	 " checkpointed file can be\nmade available to gdb."
      	 "  Just type the command below in gdb:\n");
      mtcp_printf("     add-symbol-file libmtcp.so %p\n",
               restore_begin + textbase);
      mtcp_printf("Then type \"continue\" to continue debugging.\n");
      mtcp_printf("**********\n");
    }
  }
  mtcp_maybebpt ();
# endif
#endif

  /* Now call it - it shouldn't return */
  (*restore_start) (fd, verify, decomp_child_pid, ckpt_newname, cmd_file, argv, envp);
  MTCP_PRINTF("restore routine returned (it should never do this!)\n");
  mtcp_abort ();
  return (0);
}