int main(int argc, char* argv[])
{
  {
    // parse command-line arguments
    bool background = false;
    bool recover = false;
    bool watchdog = false;
    const char* bhDir = "/home/nao";

    for(int i = 1; i < argc; ++i)
      if(!strcmp(argv[i], "-b"))
        background = true;
      else if(!strcmp(argv[i], "-w"))
        watchdog = true;
      else if(!strcmp(argv[i], "-c") && i + 1 < argc)
        bhDir = argv[++i];
      else
      {
        fprintf(stderr, "Usage: %s [-b] [-c <dir>] [-w]\n\
    -b            run in background (as daemon)\n\
    -c <dir>      used gt directory (default is /home/nao)\n\
    -w            use a watchdog for crash recovery and creating trace dumps\n", argv[0]);
        exit(EXIT_FAILURE);
      }

    // avoid duplicated instances
    int fd = open("/tmp/bhuman", O_CREAT, 0600);
    if(fd == -1 || flock(fd, LOCK_EX | LOCK_NB) == -1)
    {
      fprintf(stderr, "There is already an instance of this process!\n");
      exit(EXIT_FAILURE);
    }

    // start as daemon
    if(background)
    {
      fprintf(stderr, "Starting as daemon...\n");
      pid_t childPid = fork();
      if(childPid == -1)
        exit(EXIT_FAILURE);
      if(childPid != 0)
        exit(EXIT_SUCCESS);
    }

    // change working directory
    if(*bhDir && chdir(bhDir) != 0)
    {
      fprintf(stderr, "chdir to config directory failed!\n");
      exit(EXIT_FAILURE);
    }

    // the watchdog
    if(watchdog)
    {
      for(;;)
      {
        // create pipe for logging
        int stdoutPipe[2];
        int stderrPipe[2];
        bool pipeReady = true;

        if(pipe(stdoutPipe) == -1 || pipe(stderrPipe) == -1)
        {
          fprintf(stderr, "B-Human: Error while creating pipes for logging. All logs will be printed on console only! \n");
          pipeReady = false;
        }

        bhumanPid = fork();
        if(bhumanPid == -1)
          exit(EXIT_FAILURE);
        if(bhumanPid != 0)
        {
          int status;
          signal(SIGTERM, sighandlerRedirect);
          signal(SIGINT, sighandlerRedirect);
          if(waitpid(bhumanPid, &status, 0) != bhumanPid)
          {
            exit(EXIT_FAILURE);
          }
          signal(SIGTERM, SIG_DFL);
          signal(SIGINT, SIG_DFL);

          if(pipeReady)
          {
            // close unused write end
            close(stdoutPipe[1]);
            close(stderrPipe[1]);

            dup2(STDOUT_FILENO, stdoutPipe[0]); // redirect out-pipe to stdout
            dup2(STDERR_FILENO, stderrPipe[0]); // redirect err-pipe to stderr
          }

          // detect requested or normal exit
          bool normalExit = !run || (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);

          // dump trace and assert trace
          if(!normalExit)
          {
            NaoBody naoBody;
            if(naoBody.init())
            {
              naoBody.setCrashed(WIFSIGNALED(status) ? int(WTERMSIG(status)) : int(abnormalTerminationState));
              naoBody.cleanup();
            }
            Assert::logDump(true, WIFSIGNALED(status) ? int(WTERMSIG(status)) : 0);
            Assert::logDump(false, WIFSIGNALED(status) ? int(WTERMSIG(status)) : 0);
          }

          // quit here?
          if(normalExit)
            exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);

          // don't restart if the child process got killed
          if(WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL)
            exit(EXIT_FAILURE);

          // restart in release mode only
#ifndef NDEBUG
          exit(EXIT_FAILURE);
#endif

          // deactivate the pre-initial state
          recover = true;

          usleep(2000 * 1000);
        }
        else
        {
          if(pipeReady)
          {
            // close unused read end
            close(stdoutPipe[0]);
            close(stderrPipe[0]);

            dup2(STDOUT_FILENO, stdoutPipe[1]); // redirect stdout to out-pipe
            dup2(STDERR_FILENO, stderrPipe[1]); // redirect stderr to err-pipe
          }
          break;
        }
      }
    }

    // wait for NaoQi/libbhuman
    NaoBody naoBody;
    if(!naoBody.init())
    {
      fprintf(stderr, "B-Human: Waiting for NaoQi/libbhuman...\n");
      do
      {
        usleep(1000000);
      }
      while(!naoBody.init());
    }

    // load first settings instance
    Settings settings;
    settings.recover = recover;

    if(!settings.loadingSucceeded())
      return EXIT_FAILURE;

    // register signal handler for strg+c and termination signal
    signal(SIGTERM, sighandlerShutdown);
    signal(SIGINT, sighandlerShutdown);

    //
    bhumanStart();
  }

  while(run)
    pause();

  bhumanStop();

  return EXIT_SUCCESS;
}
Exemple #2
0
int main(int argc, char *argv[]) 
{
  {
    // parse command-line arguments
    bool background = false;
    bool recover = false;
    bool watchdog = false;
    const char* gtDir = "/media/userdata";

    for(int i = 1; i < argc; ++i)
      if(!strcmp(argv[i], "-b"))
        background = true;
      else if(!strcmp(argv[i], "-w"))
        watchdog = true;
      else if(!strcmp(argv[i], "-c") && i + 1 < argc)
        gtDir = argv[++i];
      else 
      {
        fprintf(stderr, "Usage: %s [-b] [-c <dir>] [-w]\n\
    -b            run in background (as daemon)\n\
    -c <dir>      used gt directory (default is /media/userdata)\n\
    -w            use a watchdog for crash recovery and creating trace dumps\n", argv[0]);
        exit(EXIT_FAILURE);
      }

    // avoid duplicated instances
    int fd = open("/tmp/bhuman", O_CREAT, 0600);
    if(fd == -1 || flock(fd, LOCK_EX | LOCK_NB) == -1)
    {
      fprintf(stderr, "There is already an instance of this process!\n");
      exit(EXIT_FAILURE);
    }
    
    // start as deamon
    if(background)
    {
      fprintf(stderr, "Starting as daemon...\n");
      pid_t childPid = fork();
      if(childPid == -1)
        exit(EXIT_FAILURE);
      if(childPid != 0)
        exit(EXIT_SUCCESS);
    }

    // change working directory
    if(*gtDir && chdir(gtDir) != 0)
    {
      fprintf(stderr, "chdir to config directory failed! assuming we aren't on a robot\n");
    }

    // the watchdog
    if(watchdog)
      for(;;)
      {
        bhumanPid = fork();
        if(bhumanPid == -1)
          exit(EXIT_FAILURE);
        if(bhumanPid != 0)
        {
          int status;
          signal(SIGTERM, sighandlerRedirect);
          signal(SIGINT, sighandlerRedirect);
          if(waitpid(bhumanPid, &status, 0) != bhumanPid)
            exit(EXIT_FAILURE);
          signal(SIGTERM, SIG_DFL);
          signal(SIGINT, SIG_DFL);
         
          // detect requested or normal exit
          if(!run || (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS ))
            exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);

          // trace dump
          NaoBody naoBody;
          if(naoBody.init())
          {
            naoBody.setCrashed(WIFSIGNALED(status) ? int(WTERMSIG(status)) : int(abnormalTermination));
            naoBody.dumpTrace();
          }

          // don't restart if we got killed
          if(WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL)
            exit(EXIT_FAILURE);

          // restart in release mode only
#ifndef RELEASE
          exit(EXIT_FAILURE);
#endif
       
          // deactivate the pre-initial state
          recover = true;

          usleep(2000 * 1000);
        }
        else
          break;
      }

    // wait for NaoQi/libbhuman
    if(!naoBody.init())
    {
      fprintf(stderr, "BHuman: Waiting for NaoQi/libbhuman...\n");
      do
      {
        usleep(1000000);
      } while(!naoBody.init());
    }

    // register signal handler for strg+c and termination signal
    signal(SIGTERM, sighandlerShutdown);
    signal(SIGINT, sighandlerShutdown);
  
    //
    bhumanStart(recover);
  }

  while(run)
    pause();

  bhumanStop();

  return EXIT_SUCCESS;
}