/** * Forks and runs the given application, waits for a maximum of timeout seconds for process to finish. * * @param argv The arguments values, the first one is the application path or name */ void bb_run_fork_wait(char** argv, int timeout) { check_handler(); // Fork and attempt to run given application pid_t ret = fork(); if (ret == 0) { // Fork went ok, child process replace bb_run_exec(argv); } else { if (ret > 0) { // Fork went ok, parent process continues bb_log(LOG_DEBUG, "Process %s started, PID %i.\n", argv[0], ret); pidlist_add(ret); //sleep until process finishes or timeout reached int i = 0; while (bb_is_running(ret) && ((i < timeout) || (timeout == 0)) && dowait) { usleep(1000000); i++; } //make a single attempt to kill the process if timed out, without waiting if (bb_is_running(ret)) { bb_stop(ret); } } else { // Fork failed bb_log(LOG_ERR, "Process %s could not be started. fork() failed.\n", argv[0]); return; } } return; }
/** * Runs a requested program if fallback mode was enabled * @param argv The program and param list to be executed * @return EXIT_FAILURE on failure and if fallback was disabled, -1 on failure * and if fallback was enabled and never on success */ static int run_fallback(char *argv[]) { if (bb_status.runmode == BB_RUN_APP && bb_config.fallback_start) { bb_log(LOG_WARNING, "The Bumblebee server was not available.\n"); bb_run_exec(argv); bb_log(LOG_ERR, "Unable to start program in fallback mode.\n"); } return EXIT_FAILURE; }
/** * Forks and runs the given application, using an optional LD_LIBRARY_PATH. The * function then returns immediately. * stderr and stdout of the ran application is redirected to the parameter redirect. * stdin is redirected to /dev/null always. * * @param argv The arguments values, the first one is the program * @param ldpath The library path to be used if any (may be NULL) * @param redirect The file descriptor to redirect stdout/stderr to. Must be valid and open. * @return The childs process ID */ pid_t bb_run_fork_ld_redirect(char **argv, char *ldpath, int redirect) { check_handler(); // Fork and attempt to run given application pid_t ret = fork(); if (ret == 0) { if (ldpath && *ldpath) { char *current_path = getenv("LD_LIBRARY_PATH"); /* Fork went ok, set environment if necessary */ if (current_path) { char *ldpath_new = malloc(strlen(ldpath) + 1 + strlen(current_path) + 1); if (ldpath_new) { strcpy(ldpath_new, ldpath); strcat(ldpath_new, ":"); strcat(ldpath_new, current_path); setenv("LD_LIBRARY_PATH", ldpath_new, 1); free(ldpath_new); } else { bb_log(LOG_WARNING, "Could not allocate memory for LD_LIBRARY_PATH\n"); } } else { setenv("LD_LIBRARY_PATH", ldpath, 1); } } //open /dev/null for stdin redirect int devnull = open("/dev/null", O_RDWR); //fail silently on error, nothing we can do about it anyway... if (devnull >= 0){dup2(devnull, STDIN_FILENO);} //redirect stdout and stderr to the given filenum. dup2(redirect, STDOUT_FILENO); dup2(redirect, STDERR_FILENO); close(devnull); //ok, all ready, now actually execute bb_run_exec(argv); } else { if (ret > 0) { // Fork went ok, parent process continues bb_log(LOG_DEBUG, "Process %s started, PID %i.\n", argv[0], ret); pidlist_add(ret); } else { // Fork failed bb_log(LOG_ERR, "Process %s could not be started. fork() failed.\n", argv[0]); return 0; } } return ret; }
/** * Forks and runs the given application and waits for the process to finish * * @param argv The arguments values, the first one is the program * @param detached non-zero if the std in/output must be redirected to /dev/null, zero otherwise * @return Exit code of the program (between 0 and 255) or -1 on failure */ int bb_run_fork(char **argv, int detached) { int exitcode = -1; check_handler(); /* Fork and attempt to run given application */ pid_t pid = fork(); if (pid == 0) { /* child process after fork */ if (detached) { bb_run_exec_detached(argv); } else { bb_run_exec(argv); } } else if (pid > 0) { /* parent process after fork */ int status = 0; bb_log(LOG_DEBUG, "Process %s started, PID %i.\n", argv[0], pid); pidlist_add(pid); if (waitpid(pid, &status, 0) != -1) { if (WIFEXITED(status)) { /* program exited normally, return status */ exitcode = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { /* program was terminated by a signal */ exitcode = 128 + WTERMSIG(status); } } else { bb_log(LOG_ERR, "waitpid(%i) faild with %s\n", pid, strerror(errno)); } pidlist_remove(pid); } else { /* Fork failed */ bb_log(LOG_ERR, "Process %s could not be started. fork() failed.\n", argv[0]); } /* could not determine return value */ return exitcode; }
/** * Forks and runs the given application, using an optional LD_LIBRARY_PATH. The * function then returns immediately * * @param argv The arguments values, the first one is the program * @param ldpath The library path to be used if any (may be NULL) * @return The childs process ID */ pid_t bb_run_fork_ld(char **argv, char *ldpath) { check_handler(); // Fork and attempt to run given application pid_t ret = fork(); if (ret == 0) { if (ldpath && *ldpath) { char *current_path = getenv("LD_LIBRARY_PATH"); /* Fork went ok, set environment if necessary */ if (current_path) { char *ldpath_new = malloc(strlen(ldpath) + 1 + strlen(current_path) + 1); if (ldpath_new) { strcpy(ldpath_new, ldpath); strcat(ldpath_new, ":"); strcat(ldpath_new, current_path); setenv("LD_LIBRARY_PATH", ldpath_new, 1); free(ldpath_new); } else { bb_log(LOG_WARNING, "Could not allocate memory for LD_LIBRARY_PATH\n"); } } else { setenv("LD_LIBRARY_PATH", ldpath, 1); } } bb_run_exec(argv); } else { if (ret > 0) { // Fork went ok, parent process continues bb_log(LOG_INFO, "Process %s started, PID %i.\n", argv[0], ret); pidlist_add(ret); } else { // Fork failed bb_log(LOG_ERR, "Process %s could not be started. fork() failed.\n", argv[0]); return 0; } } return ret; }
int main(int argc, char* argv[]) { /* Setup signal handling before anything else */ signal(SIGHUP, handle_signal); signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); signal(SIGQUIT, handle_signal); /* Initializing configuration */ init_config(argc, argv); /* set runmode depending on leftover arguments */ if (optind >= argc) { bb_status.runmode = BB_RUN_STATUS; } else { bb_status.runmode = BB_RUN_APP; } bb_init_log(); bb_log(LOG_DEBUG, "%s version %s starting...\n", bb_status.program_name, GITVERSION); /* Connect to listening daemon */ bb_status.bb_socket = socketConnect(bb_config.socket_path, SOCK_NOBLOCK); if (bb_status.bb_socket < 0) { bb_log(LOG_ERR, "Could not connect to bumblebee daemon - is it running?\n"); bb_closelog(); return EXIT_FAILURE; } char buffer[BUFFER_SIZE]; int r; /* Request status */ if (bb_status.runmode == BB_RUN_STATUS) { r = snprintf(buffer, BUFFER_SIZE, "Status?"); socketWrite(&bb_status.bb_socket, buffer, r); while (bb_status.bb_socket != -1) { r = socketRead(&bb_status.bb_socket, buffer, BUFFER_SIZE); if (r > 0) { printf("Bumblebee status: %*s\n", r, buffer); socketClose(&bb_status.bb_socket); } } } /* Run given application */ if (bb_status.runmode == BB_RUN_APP) { int ranapp = 0; r = snprintf(buffer, BUFFER_SIZE, "Checking availability..."); socketWrite(&bb_status.bb_socket, buffer, r); while (bb_status.bb_socket != -1) { r = socketRead(&bb_status.bb_socket, buffer, BUFFER_SIZE); if (r > 0) { bb_log(LOG_INFO, "Response: %*s\n", r, buffer); switch (buffer[0]) { case 'N': //No, run normally. socketClose(&bb_status.bb_socket); if (!bb_config.fallback_start){ bb_log(LOG_ERR, "Cannot access secondary GPU. Aborting.\n"); } break; case 'Y': //Yes, run through vglrun bb_log(LOG_INFO, "Running application through vglrun.\n"); ranapp = 1; //run vglclient if any method other than proxy is used if (strncmp(bb_config.vgl_compress, "proxy", BUFFER_SIZE) != 0) { char * vglclient_args[] = { "vglclient", "-detach", 0 }; bb_run_fork(vglclient_args); } char ** vglrun_args = malloc(sizeof (char *) * (9 + argc - optind)); vglrun_args[0] = "vglrun"; vglrun_args[1] = "-c"; vglrun_args[2] = bb_config.vgl_compress; vglrun_args[3] = "-d"; vglrun_args[4] = bb_config.x_display; vglrun_args[5] = "-ld"; vglrun_args[6] = bb_config.ld_path; vglrun_args[7] = "--"; for (r = 0; r < argc - optind; r++) { vglrun_args[8 + r] = argv[optind + r]; } vglrun_args[8 + r] = 0; bb_run_fork_wait(vglrun_args); socketClose(&bb_status.bb_socket); break; default: //Something went wrong - output and exit. bb_log(LOG_ERR, "Problem: %*s\n", r, buffer); socketClose(&bb_status.bb_socket); break; } } } if (!ranapp && bb_config.fallback_start) { bb_log(LOG_WARNING, "Running application normally.\n"); bb_run_exec(argv + optind); } } bb_closelog(); bb_stop_all(); //stop any started processes that are left return (EXIT_SUCCESS); }