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; }
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; }