/** * Check for the availability of a PM method, warn if no method is available */ void check_pm_method(void) { if (bb_config.pm_method == PM_DISABLED) { bb_log(LOG_INFO, "PM is disabled, not performing detection.\n"); } else { struct switch_info info; memset(&info, 0, sizeof info); info.driver = bb_config.driver; info.configured_pm = bb_pm_method_string[bb_config.pm_method]; const char *pm_method = NULL; if (bb_config.pm_method != PM_AUTO) { /* auto-detection override */ pm_method = bb_pm_method_string[bb_config.pm_method]; } switcher = switcher_detect(pm_method, info); if (switcher) { bb_log(LOG_INFO, "Switching method '%s' is available and will be used.\n", switcher->name); } else { bb_log(LOG_WARNING, "No switching method available. The dedicated card" " will always be on.\n"); } } }
/** * Fork to the background, and exit parent. */ static void daemonize(void) { /* Fork off the parent process */ pid_t bb_pid = fork(); if (bb_pid < 0) { bb_log(LOG_ERR, "Could not fork to background\n"); exit(EXIT_FAILURE); } /* If we got a good PID, then we can exit the parent process. */ if (bb_pid > 0) { exit(EXIT_SUCCESS); } /* Create a new SID for the child process */ pid_t bb_sid = setsid(); if (bb_sid < 0) { bb_log(LOG_ERR, "Could not set SID: %s\n", strerror(errno)); exit(EXIT_FAILURE); } /* Change the current working directory */ if ((chdir("/")) < 0) { bb_log(LOG_ERR, "Could not change to root directory: %s\n", strerror(errno)); exit(EXIT_FAILURE); } /* Close out the standard file descriptors */ close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); }
/** * Requests a key over the socket * @param key The key to be retrieved * @param target A pointer to a char to store the value in * @param max_len The maximum number of bytes to be written in target, must be * greater than 0 * @return 0 on success, non-zero on failure */ int bbsocket_query(const char *key, char *target, size_t max_len) { char buff[BUFFER_SIZE]; snprintf(buff, sizeof buff, "Query %s", key); if (!socketWrite(&bb_status.bb_socket, buff, strlen(buff) + 1)) { bb_log(LOG_DEBUG, "Write failed for query of %s\n", key); return 1; } while (bb_status.bb_socket != -1) { if (socketRead(&bb_status.bb_socket, buff, sizeof (buff))) { if (strncmp("Value: ", buff, strlen("Value: "))) { bb_log(LOG_DEBUG, "Failed to query for %s: %s\n", key, buff); return 1; } strncpy(target, buff + strlen("Value: "), max_len); target[max_len - 1] = 0; /* remove trailing newline */ if (strlen(target)) { target[strlen(target) - 1] = 0; } return 0; } } bb_log(LOG_DEBUG, "Read failed for query of %s\n", key); return 1; }
int socketConnect(char * address, int nonblock) { //create the socket itself int sock = socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { bb_log(LOG_ERR, "Could not create socket. Error: %s\n", strerror(errno)); return -1; } //full our the address information for the connection struct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, address); //attempt to connect int r = connect(sock, (struct sockaddr*) & addr, sizeof (addr)); if (r == 0) { //connection success, set nonblocking if requested. if (nonblock == 1) { int flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); } } else { //connection fail bb_log(LOG_ERR, "Could not connect to %s! Error: %s\n", address, strerror(errno)); //close the socket and set it to -1 socketClose(&sock); } return sock; }//socketConnect
/** * 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; }
int main(int argc, char *argv[]) { int exitcode = EXIT_FAILURE; init_early_config(argc, argv, BB_RUN_APP); /* Setup signal handling before anything else */ signal(SIGHUP, handle_signal); signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); signal(SIGQUIT, handle_signal); bb_init_log(); /* Initializing configuration */ init_config(argc, argv); bbconfig_parse_opts(argc, argv, PARSE_STAGE_PRECONF); GKeyFile *bbcfg = bbconfig_parse_conf(); /* XXX load the driver (or even better, the ldpath) through the protocol */ bbconfig_parse_opts(argc, argv, PARSE_STAGE_DRIVER); driver_detect(); if (bbcfg) { bbconfig_parse_conf_driver(bbcfg, bb_config.driver); g_key_file_free(bbcfg); } bbconfig_parse_opts(argc, argv, PARSE_STAGE_OTHER); config_dump(); bb_log(LOG_DEBUG, "%s version %s starting...\n", "optirun", 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"); run_fallback(argv + optind); bb_closelog(); return exitcode; } /* Request status */ if (bb_status.runmode == BB_RUN_STATUS) { exitcode = report_daemon_status(); } /* Run given application */ if (bb_status.runmode == BB_RUN_APP) { if (optind >= argc) { bb_log(LOG_ERR, "Missing argument: application to run\n"); print_usage(EXIT_FAILURE); } else { exitcode = run_app(argc, argv); } } bb_closelog(); bb_stop_all(); //stop any started processes that are left return exitcode; }
static void bbswitch_write(char *msg) { FILE *bbs = fopen(BBSWITCH_PATH, "w"); if (bbs == 0) { bb_log(LOG_ERR, "Could not open %s: %s\n", BBSWITCH_PATH, strerror(errno)); return; } fwrite(msg, sizeof msg, strlen(msg) + 1, bbs); if (ferror(bbs)) { bb_log(LOG_WARNING, "Could not write to %s: %s\n", BBSWITCH_PATH, strerror(errno)); } fclose(bbs); }
/** * Attempts to run the given application, replacing the current process but hide * any stderr output from the executed program * @param argv The program to be run */ static void bb_run_exec_hide_stderr(char **argv) { int old_stderr, exec_err; bb_log(LOG_DEBUG, "Hiding stderr for execution of %s\n", argv[0]); /* stderr fd no = 2 */ old_stderr = dup(2); close(2); execvp(argv[0], argv); /* note: the below lines are only executed if execvp fails */ exec_err = errno; dup2(old_stderr, 2); close(old_stderr); bb_log(LOG_ERR, "Error running \"%s\": %s\n", argv[0], strerror(exec_err)); exit(exec_err); }
/** * Stops all the running processes, if any */ void bb_stop_all(void) { bb_log(LOG_DEBUG, "Killing all remaining processes.\n"); /* keep killing the first program in the list until it's empty */ while (pidlist_start) { bb_stop_wait(pidlist_start->PID); } }
/** * Handle recieved signals - except SIGCHLD, which is handled in bbrun.c */ static void handle_signal(int sig) { switch (sig) { case SIGHUP: bb_log(LOG_WARNING, "Received %s signal (ignoring...)\n", strsignal(sig)); break; case SIGINT: case SIGQUIT: case SIGTERM: bb_log(LOG_WARNING, "Received %s signal.\n", strsignal(sig)); socketClose(&bb_status.bb_socket); //closing the socket terminates the server break; default: bb_log(LOG_WARNING, "Unhandled signal %s\n", strsignal(sig)); break; } }
/** * 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; }
/** * Attempts to unload a module if loaded, for ten seconds before * giving up * * @param driver The name of the driver (not a filename) * @return 1 if the driver is succesfully unloaded, 0 otherwise */ int module_unload(char *driver) { if (module_is_loaded(driver) == 1) { bb_log(LOG_INFO, "Unloading %s driver\n", driver); char *mod_argv[] = { "rmmod", "--wait", driver, NULL }; bb_run_fork_wait(mod_argv, 10); if (module_is_loaded(driver) == 1) { bb_log(LOG_ERR, "Unloading %s driver timed out.\n", driver); return 0; } } return 1; }
/** * Attempts to load a module. If the module has not been loaded after ten * seconds, give up * * @param module_name The filename of the module to be loaded * @param driver The name of the driver to be loaded * @return 1 if the driver is succesfully loaded, 0 otherwise */ int module_load(char *module_name, char *driver) { if (module_is_loaded(driver) == 0) { /* the module has not loaded yet, try to load it */ bb_log(LOG_INFO, "Loading driver %s (module %s)\n", driver, module_name); char *mod_argv[] = { "modprobe", module_name, NULL }; bb_run_fork_wait(mod_argv, 10); if (module_is_loaded(driver) == 0) { bb_log(LOG_ERR, "Module %s could not be loaded (timeout?)\n", module_name); return 0; } } return 1; }
/** * Change GID and umask of the daemon */ static int bb_chgid(void) { /* Change the Group ID of bumblebee */ struct group *gp; errno = 0; gp = getgrnam(bb_config.gid_name); if (gp == NULL) { int error_num = errno; bb_log(LOG_ERR, "%s\n", strerror(error_num)); bb_log(LOG_ERR, "There is no \"%s\" group\n", bb_config.gid_name); exit(EXIT_FAILURE); } if (setgid(gp->gr_gid) != 0) { bb_log(LOG_ERR, "Could not set the GID of bumblebee: %s\n", strerror(errno)); exit(EXIT_FAILURE); } /* Change the file mode mask */ umask(023); return 0; }
/** * Attempts to load a module. * * @param module_name The filename of the module to be loaded * @param driver The name of the driver to be loaded * @return 1 if the driver is succesfully loaded, 0 otherwise */ int module_load(char *module_name, char *driver) { int err = 0; int flags = KMOD_PROBE_IGNORE_LOADED; struct kmod_list *l, *list = NULL; if (module_is_loaded(driver) == 0) { /* the module has not loaded yet, try to load it */ bb_log(LOG_INFO, "Loading driver '%s' (module '%s')\n", driver, module_name); err = kmod_module_new_from_lookup(bb_status.kmod_ctx, module_name, &list); if (err < 0) { bb_log(LOG_DEBUG, "kmod_module_new_from_lookup(%s) failed (err: %d).\n", module_name, err); return 0; } if (list == NULL) { bb_log(LOG_ERR, "Module '%s' not found.\n", module_name); return 0; } kmod_list_foreach(l, list) { struct kmod_module *mod = kmod_module_get_module(l); bb_log(LOG_DEBUG, "Loading module '%s'.\n", kmod_module_get_name(mod)); err = kmod_module_probe_insert_module(mod, flags, NULL, NULL, NULL, 0); if (err < 0) { bb_log(LOG_DEBUG, "kmod_module_probe_insert_module(%s) failed (err: %d).\n", kmod_module_get_name(mod), err); } kmod_module_unref(mod); if (err < 0) { break; } } kmod_module_unref_list(list); }
static void childsig_handler(int signum) { if (signum != SIGCHLD) { return; } int chld_stat = 0; /* Wait for the child to exit */ pid_t ret = wait(&chld_stat); /* Log the child termination and return value */ if (ret == -1) { bb_log(LOG_DEBUG, "SIGCHILD received, but wait failed with %s\n", strerror(errno)); } else if (WIFEXITED(chld_stat)) { bb_log(LOG_DEBUG, "Process with PID %i returned code %i\n", ret, WEXITSTATUS (chld_stat)); } else if (WIFSIGNALED(chld_stat)) { bb_log(LOG_DEBUG, "Process with PID %i terminated with %i\n", ret, WTERMSIG(chld_stat)); } pidlist_remove(ret); }//childsig_handler
/** * 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; }
/** * Kill the second X server if any, turn card off if requested. */ void stop_secondary() { char driver[BUFFER_SIZE]; // kill X if it is running if (bb_is_running(bb_status.x_pid)) { bb_log(LOG_INFO, "Stopping X server\n"); bb_stop_wait(bb_status.x_pid); } if (bb_config.pm_method == PM_DISABLED && bb_status.runmode != BB_RUN_EXIT) { /* do not disable the card if PM is disabled unless exiting */ return; } //if card is on and can be switched, switch it off if (switcher) { if (switcher->need_driver_unloaded) { /* do not unload the drivers nor disable the card if the card is not on */ if (switcher->status() != SWITCH_ON) { return; } if (pci_config_save(pci_bus_id_discrete, &pci_config_state_discrete)) { bb_log(LOG_WARNING, "Could not save PCI configuration space: %s\n", strerror(errno)); } /* unload the driver loaded by the graphica card */ if (pci_get_driver(driver, pci_bus_id_discrete, sizeof driver)) { module_unload(driver); } //only turn card off if no drivers are loaded if (pci_get_driver(NULL, pci_bus_id_discrete, 0)) { bb_log(LOG_DEBUG, "Drivers are still loaded, unable to disable card\n"); return; } } if (switch_off() != SWITCH_OFF) { bb_log(LOG_WARNING, "Unable to disable discrete card."); } } }//stop_secondary
void socketClose(int * sock) { bb_log(LOG_INFO, "Socket closed.\n"); // do not attempt to close closed or uninitialized sockets if (!sock || *sock == -1) { return; } //half-close the socket first shutdown(*sock, SHUT_RDWR); //fully close the socket close(*sock); //set to -1 to prevent usage *sock = -1; }//socketClose
int socketServer(char * address, int nonblock) { //delete the file currently there, if any unlink(address); //create the socket int sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { bb_log(LOG_ERR, "Could not create socket! Error: %s\n", strerror(errno)); return -1; } //set to nonblocking if requested if (nonblock == 1) { int flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); } //fill address information struct sockaddr_un addr; addr.sun_family = AF_UNIX; // XXX this path is 107 bytes (excl. null) on Linux, a larger path is // truncated. bb_config.socket_path can therefore be shrinked as well strncpy(addr.sun_path, address, sizeof(addr.sun_path) - 1); addr.sun_path[sizeof(addr.sun_path) - 1] = 0; //bind the socket int ret = bind(sock, (struct sockaddr*) & addr, sizeof (addr)); if (ret == 0) { ret = listen(sock, 100); //start listening, backlog of 100 allowed //allow reading and writing for group and self chmod(address, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (ret != 0) { bb_log(LOG_ERR, "Listen failed! Error: %s\n", strerror(errno)); socketClose(&sock); } } else { bb_log(LOG_ERR, "Binding failed! Error: %s\n", strerror(errno)); socketClose(&sock); } return sock; }//socketServer
/** * Whether bbswitch is available for use * * @param info A struct containing information which would help with the * decision whether bbswitch is usable or not * @return 1 if available for use for PM, 0 otherwise */ int bbswitch_is_available(struct switch_info info) { (void) info; /* unused parameter */ /* easy one: if the path is available, bbswitch is usable */ if (access(BBSWITCH_PATH, F_OK | R_OK | W_OK) == 0) { /* file exists and read/write is allowed */ bb_log(LOG_DEBUG, "bbswitch has been detected.\n"); return 1; } /* module is not loaded yet. Try to load it, checking whether the device is * recognized by bbswitch. Assuming that vga_switcheroo was not told to OFF * the device */ if (module_load("bbswitch", "bbswitch")) { bb_log(LOG_DEBUG, "succesfully loaded bbswitch\n"); /* hurrah, bbswitch could be loaded which means that the module is * available and that the card is supported */ return 1; } /* nope, we can't use bbswitch */ bb_log(LOG_DEBUG, "bbswitch is not available, perhaps you need to insmod" " it?\n"); return 0; }
/** * 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; }
static void handle_socket(struct clientsocket * C) { static char buffer[BUFFER_SIZE]; //since these are local sockets, we can safely assume we get whole messages at a time int r = socketRead(&C->sock, buffer, BUFFER_SIZE); if (r > 0) { switch (buffer[0]) { case 'S'://status if (bb_status.errors[0] != 0) { r = snprintf(buffer, BUFFER_SIZE, "Error (%s): %s\n", GITVERSION, bb_status.errors); } else { if (bb_is_running(bb_status.x_pid)) { r = snprintf(buffer, BUFFER_SIZE, "Ready (%s). X is PID %i, %i applications using bumblebeed.\n", GITVERSION, bb_status.x_pid, bb_status.appcount); } else { r = snprintf(buffer, BUFFER_SIZE, "Ready (%s). X inactive.\n", GITVERSION); } } socketWrite(&C->sock, buffer, r); //we assume the write is fully successful. break; case 'F'://force VirtualGL if possible case 'C'://check if VirtualGL is allowed /// \todo Handle power management cases and powering card on/off. //no X? attempt to start it if (!bb_is_running(bb_status.x_pid)) { start_secondary(); } if (bb_is_running(bb_status.x_pid)) { r = snprintf(buffer, BUFFER_SIZE, "Yes. X is active.\n"); if (C->inuse == 0) { C->inuse = 1; bb_status.appcount++; } } else { if (bb_status.errors[0] != 0) { r = snprintf(buffer, BUFFER_SIZE, "No - error: %s\n", bb_status.errors); } else { r = snprintf(buffer, BUFFER_SIZE, "No, secondary X is not active.\n"); } } socketWrite(&C->sock, buffer, r); //we assume the write is fully successful. break; case 'D'://done, close the socket. socketClose(&C->sock); break; default: bb_log(LOG_WARNING, "Unhandled message received: %*s\n", r, buffer); break; } } }
/** * Attempts to run the given application, replacing the current process but * redirect all standard in/outputs to /dev/null. * @param argv The program to be run */ static void bb_run_exec_detached(char **argv) { int old_stderr, exec_err; bb_log(LOG_DEBUG, "Hiding stderr for execution of %s\n", argv[0]); /* Redirect all three standard file descriptors to /dev/null. * If daemonized, this already happened - but doing it * again doesn't hurt since this fork won't run forever anyway. */ int devnull = open("/dev/null", O_RDWR); if (devnull < 0){ bb_log(LOG_ERR, "Could not open /dev/null: %s\n", strerror(errno)); } old_stderr = dup(STDERR_FILENO); dup2(devnull, STDIN_FILENO); dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); close(devnull); //done redirecting, do the exec execvp(argv[0], argv); /* note: the below lines are only executed if execvp fails */ exec_err = errno; dup2(old_stderr, STDERR_FILENO); bb_log(LOG_ERR, "Error running \"%s\": %s\n", argv[0], strerror(exec_err)); exit(exec_err); }
/** * Checks whether a kernel module is loaded * * @param driver The name of the driver (not a filename) * @return 1 if the module is loaded, 0 otherwise */ int module_is_loaded(char *driver) { int err, state; struct kmod_module *mod; err = kmod_module_new_from_name(bb_status.kmod_ctx, driver, &mod); if (err < 0) { bb_log(LOG_DEBUG, "kmod_module_new_from_name(%s) failed (err: %d).\n", driver, err); return 0; } state = kmod_module_get_initstate(mod); kmod_module_unref(mod); return state == KMOD_MODULE_LIVE; }
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); bb_init_log(); check_secondary(); init_config(argc, argv); /* Change GID and mask according to configuration */ if ((bb_config.gid_name != 0) && (bb_config.gid_name[0] != 0)){ bb_chgid(); } bb_log(LOG_DEBUG, "%s version %s starting...\n", bb_status.program_name, GITVERSION); /* Daemonized if daemon flag is activated */ if (bb_status.runmode == BB_RUN_DAEMON) { daemonize(); } /* Initialize communication socket, enter main loop */ bb_status.bb_socket = socketServer(bb_config.socket_path, SOCK_NOBLOCK); stop_secondary();//turn off card, nobody is connected right now. main_loop(); unlink(bb_config.socket_path); bb_status.runmode = BB_RUN_EXIT;//make sure all methods understand we are shutting down if (bb_config.card_shutdown_state) { //if shutdown state = 1, turn on card start_secondary(); } else { //if shutdown state = 0, turn off card stop_secondary(); } bb_closelog(); bb_stop_all(); //stop any started processes that are left return (EXIT_SUCCESS); }
int socketAccept(int * sock, int nonblock) { if (*sock < 0) { return -1; } int r = accept(*sock, 0, 0); //set the socket to be nonblocking, if requested. //we could do this through accept4 with a flag, but that call is non-standard... if ((r >= 0) && (nonblock == 1)) { int flags = fcntl(r, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(r, F_SETFL, flags); } if (r < 0) { if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)) { bb_log(LOG_ERR, "Error during accept - closing server socket: %s\n", strerror(errno)); socketClose(sock); } } return r; }
int socketRead(int * sock, void * buffer, int len) { if (*sock < 0) { return 0; } int r = recv(*sock, buffer, len, 0); if (r < 0) { switch (errno) { case EWOULDBLOCK: return 0; break; default: bb_log(LOG_WARNING, "Could not read data! Error: %s\n", strerror(errno)); socketClose(sock); return 0; break; } } if (r == 0) { socketClose(sock); } return r; }//socketRead
/** * Substitutes DRIVER in the passed path * @param x_conf_file A path to be processed * @param driver The replacement for each occurence of DRIVER * @return A path to xorg.conf with DRIVER substituted for the driver */ static char *xorg_path_w_driver(char *x_conf_file, char *driver) { static char *path; const char *driver_keyword = "DRIVER"; unsigned int driver_occurences = 0; int path_length; char *pos, *next; /* calculate the path buffer size */ pos = x_conf_file; while ((next = strstr(pos, driver_keyword)) != 0) { driver_occurences++; pos = next + strlen(driver_keyword); } path_length = strlen(x_conf_file) + driver_occurences * (strlen(driver_keyword) - 1); /* allocate some memory including null byte and make it an empty string */ path = malloc(path_length + 1); if (!path) { bb_log(LOG_WARNING, "Could not allocate memory for xorg conf path\n"); return NULL; } path[0] = 0; /* now replace for real */ pos = x_conf_file; while ((next = strstr(pos, driver_keyword)) != 0) { int len = next - pos; strncat(path, pos, len); strncat(path, driver, path_length); /* the next search starts at the position after %s */ pos = next + strlen(driver_keyword); } /* append the remainder after the last %s if any and overwrite the setting */ strncat(path, pos, path_length); return path; }