module: use libkmod2 instead of modprobe
authorOndřej Janošík <j.ondra14@gmail.com>
Thu, 5 May 2016 16:48:43 +0000 (18:48 +0200)
committerAndreas Beckmann <anbe@debian.org>
Sat, 22 Aug 2020 20:31:43 +0000 (21:31 +0100)
Gbp-Pq: Name libkmod.patch

Makefile.am
README.markdown
configure.ac
src/bbconfig.c
src/bbconfig.h
src/bblogger.c
src/bumblebeed.c
src/module.c
src/optirun.c

index 0f38a54baca22f1f190031d6d12b3e5d6054c3af..25e32d5f4ce9e9b889a5785776ee415e90e4e38f 100644 (file)
@@ -10,7 +10,7 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} \
                -DCONF_XORG='"$(bumblebeedconfdir)/xorg.conf.DRIVER"' \
                -DCONF_XORG_DIR='"$(bumblebeedconfdir)/xorg.conf.d"'
 AM_CFLAGS = ${regular_CFLAGS} \
-               ${x11_CFLAGS} ${libbsd_CFLAGS} ${glib_CFLAGS} \
+               ${x11_CFLAGS} ${libbsd_CFLAGS} ${glib_CFLAGS} ${kmod_CFLAGS} \
                -Wextra -funsigned-char -DGITVERSION='"${GITVERSION}"'
 
 noinst_SCRIPTS = scripts/systemd/bumblebeed.service \
@@ -49,13 +49,13 @@ sbin_PROGRAMS = bin/bumblebeed
 bin_PROGRAMS = bin/optirun
 
 bin_optirun_SOURCES = src/module.c src/bbconfig.c src/bblogger.c src/bbrun.c \
-       src/bbsocket.c src/driver.c src/optirun.c src/bbsocketclient.c
-bin_optirun_LDADD = ${glib_LIBS} -lrt
+       src/bbsocket.c src/optirun.c src/bbsocketclient.c
+bin_optirun_LDADD = ${glib_LIBS} ${kmod_LIBS} -lrt
 bin_bumblebeed_SOURCES = src/pci.c src/bbconfig.c src/bblogger.c src/bbrun.c \
        src/bbsocket.c src/module.c src/bbsecondary.c src/switch/switching.c \
        src/switch/sw_bbswitch.c src/switch/sw_switcheroo.c \
        src/driver.c src/bumblebeed.c
-bin_bumblebeed_LDADD = ${x11_LIBS} ${libbsd_LIBS} ${glib_LIBS} -lrt
+bin_bumblebeed_LDADD = ${x11_LIBS} ${libbsd_LIBS} ${glib_LIBS} ${kmod_LIBS} -lrt
 
 dist_doc_DATA = $(relnotes) README.markdown
 bumblebeedconf_DATA = conf/bumblebee.conf conf/xorg.conf.nouveau conf/xorg.conf.nvidia
index b534a6c13b155fdde02dc4f0119876c9f4db4a9c..5c2baa51dbcd541c731635f278e033eb0314e839 100644 (file)
@@ -19,6 +19,7 @@ The following packages are dependencies for the build process:
 - pkg-config
 - glib-2.0 and development headers
 - libx11 and development headers
+- libkmod2 and development headers
 - libbsd and development headers (if pidfile support is enabled, default yes)
 - help2man (optional, it is needed for building manual pages)
 
index 4e22314f9a39151f86e7afa46a7e5b44b595f039..d5194b8f35647d86bd6275e64fefff626b8175f4 100644 (file)
@@ -132,6 +132,7 @@ AC_SUBST([regular_CFLAGS])
 # Checks for header files.
 PKG_CHECK_MODULES([x11], [x11])
 PKG_CHECK_MODULES([glib], [glib-2.0])
+PKG_CHECK_MODULES([kmod], [libkmod])
 AS_IF([test "x$with_pidfile" != xno], [
                PKG_CHECK_MODULES([libbsd], [libbsd >= 0.2.0])
                PKG_CHECK_EXISTS([libbsd = 0.2.0], [AC_DEFINE(HAVE_LIBBSD_020)])
index 4f5ac7a8850ae1c8a299352b058c7daf1193d4fb..62a33061890c800b6ab3ca4345bdb690c7bad49f 100644 (file)
@@ -251,12 +251,6 @@ Bumblebee homepage: <http://Bumblebee-Project.org/>\n", out);
  */
 static int bbconfig_parse_common(int opt, char *value) {
   switch (opt) {
-    case 'q'://quiet mode
-      bb_status.verbosity = VERB_NONE;
-      break;
-    case OPT_DEBUG://debug mode
-      bb_status.verbosity = VERB_ALL;
-      break;
     case 'd'://X display number
       set_string_value(&bb_config.x_display, value);
       break;
@@ -307,6 +301,12 @@ void bbconfig_parse_opts(int argc, char *argv[], int conf_round) {
             bb_status.verbosity++;
           }
           break;
+        case 'q'://quiet mode
+          bb_status.verbosity = VERB_NONE;
+          break;
+        case OPT_DEBUG://debug mode
+          bb_status.verbosity = VERB_ALL;
+          break;
         case 's': /* Unix socket to use for communication */
           set_string_value(&bb_config.socket_path, optarg);
           break;
index 656286bb5e6858f42f43cbf918b2ad8e9c4e035d..a19f5d396c71780391f2cea7802c9ad3f0888d36 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistd.h> //for pid_t
 #include <limits.h> //for CHAR_MAX
 #include <glib.h>
+#include <libkmod.h>
 
 /* Daemon states */
 #define BB_DAEMON 1
@@ -118,6 +119,7 @@ struct bb_status_struct {
     int x_pipe[2];//pipes for reading/writing output from X's stdout/stderr
     gboolean use_syslog;
     char *program_name;
+    struct kmod_ctx *kmod_ctx;
 };
 
 /* Structure containing the configuration. */
index ba3787ee1e7ee092d899d2896075ce7d3c97738d..7c13c93ebe95bf1f9b06c14d6047e2f30a2104ec 100644 (file)
@@ -228,7 +228,7 @@ void check_xorg_pipe(void){
         /* line / buffer is full, process the remaining buffer the next round */
         repeat = 1;
       }
-    }else{
+    } else {
       if (r == 0 || (errno != EAGAIN && r == -1)){
         /* the pipe is closed/invalid. Clean up. */
         if (bb_status.x_pipe[0] != -1){close(bb_status.x_pipe[0]); bb_status.x_pipe[0] = -1;}
@@ -257,5 +257,5 @@ void check_xorg_pipe(void){
         memmove(x_output_buffer, next_part, x_buffer_pos);
       }
     }
-  }while(repeat);
+  }while (repeat);
 }/* check_xorg_pipe */
index a911da9a474a5fe69e813b7f38d7ce7906f8d125..6e0ade5d4601546775eb6d4fb6ff9280914d19ea 100644 (file)
@@ -34,6 +34,7 @@
 #include <string.h>
 #include <errno.h>
 #include <getopt.h>
+#include <libkmod.h>
 #ifdef WITH_PIDFILE
 #ifdef HAVE_LIBBSD_020
 #include <libutil.h>
@@ -488,6 +489,14 @@ int main(int argc, char* argv[]) {
 
   free(pci_id_igd);
 
+  // kmod context have to be available for driver detection
+  bb_status.kmod_ctx = kmod_new(NULL, NULL);
+  if (bb_status.kmod_ctx == NULL) {
+    bb_log(LOG_ERR, "kmod_new() failed!\n");
+    bb_closelog();
+    exit(EXIT_FAILURE);
+  }
+
   GKeyFile *bbcfg = bbconfig_parse_conf();
   bbconfig_parse_opts(argc, argv, PARSE_STAGE_DRIVER);
   driver_detect();
@@ -500,6 +509,7 @@ int main(int argc, char* argv[]) {
 
   /* dump the config after detecting the driver */
   config_dump();
+
   if (config_validate() != 0) {
     return (EXIT_FAILURE);
   }
@@ -572,5 +582,7 @@ int main(int argc, char* argv[]) {
   //close X pipe, if any parts of it are open still
   if (bb_status.x_pipe[0] != -1){close(bb_status.x_pipe[0]); bb_status.x_pipe[0] = -1;}
   if (bb_status.x_pipe[1] != -1){close(bb_status.x_pipe[1]); bb_status.x_pipe[1] = -1;}
+  //cleanup kmod context
+  kmod_unref(bb_status.kmod_ctx);
   return (EXIT_SUCCESS);
 }
index bb32e15da6db578d571d104b90bcb29dee922846..ef3e84cd16c7753f9e0c93f5f88175c1429eac11 100644 (file)
 #include <ctype.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <libkmod.h>
+#include <errno.h>
 #include "module.h"
 #include "bblogger.h"
 #include "bbrun.h"
+#include "bbconfig.h"
+
+int module_unload_recursive(struct kmod_module *mod);
 
 /**
- * Checks in /proc/modules whether a kernel module is loaded
+ * 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) {
-  // use the same buffer length as lsmod
-  char buffer[4096];
-  FILE * bbs = fopen("/proc/modules", "r");
-  int ret = 0;
-  /* assume mod_len <= sizeof(buffer) */
-  int mod_len = strlen(driver);
-
-  if (bbs == 0) {//error opening, return -1
-    bb_log(LOG_DEBUG, "Couldn't open /proc/modules");
-    return -1;
-  }
-  while (fgets(buffer, sizeof(buffer), bbs)) {
-    /* match "module" with "module " and not "module-blah" */
-    if (!strncmp(buffer, driver, mod_len) && isspace(buffer[mod_len])) {
-      /* module is found */
-      ret = 1;
-      break;
-    }
+  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;
   }
-  fclose(bbs);
-  return ret;
+
+  state = kmod_module_get_initstate(mod);
+  kmod_module_unref(mod);
+
+  return state == KMOD_MODULE_LIVE;
 }
 
 /**
- * Attempts to load a module. If the module has not been loaded after ten
- * seconds, give up
+ * 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 successfully 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);
-    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);
+
+    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);
   }
-  return 1;
+
+  return err >= 0;
 }
 
 /**
- * Attempts to unload a module if loaded, for ten seconds before
- * giving up
+ * Unloads module and modules that are depending on this module.
+ *
+ * @param mod Reference to libkmod module
+ * @return 1 if the module is successfully unloaded, 0 otherwise
+ */
+int module_unload_recursive(struct kmod_module *mod) {
+  int err = 0, flags = 0, refcnt;
+  struct kmod_list *holders;
+
+  holders = kmod_module_get_holders(mod);
+  if (holders != NULL) {
+    struct kmod_list *itr;
+
+    kmod_list_foreach(itr, holders) {
+      struct kmod_module *hm = kmod_module_get_module(itr);
+      err = module_unload_recursive(hm);
+      kmod_module_unref(hm);
+
+      if (err < 0) {
+        break;
+      }
+    }
+    kmod_module_unref_list(holders);
+  }
+
+  refcnt = kmod_module_get_refcnt(mod);
+  if (refcnt == 0) {
+    bb_log(LOG_INFO, "Unloading module %s\n", kmod_module_get_name(mod));
+    err = kmod_module_remove_module(mod, flags);
+  } else {
+    bb_log(LOG_ERR, "Failed to unload module '%s' (ref count: %d).\n",
+      kmod_module_get_name(mod), refcnt);
+    err = 1;
+  }
+
+  return err == 0;
+}
+
+/**
+ * Attempts to unload a module if loaded.
  *
  * @param driver The name of the driver (not a filename)
  * @return 1 if the driver is successfully unloaded, 0 otherwise
  */
 int module_unload(char *driver) {
+  int err;
+  struct kmod_module *mod;
   if (module_is_loaded(driver) == 1) {
-    int retries = 30;
-    bb_log(LOG_INFO, "Unloading %s driver\n", driver);
-    char *mod_argv[] = {
-      "modprobe",
-      "-r",
-      driver,
-      NULL
-    };
-    bb_run_fork_wait(mod_argv, 10);
-    while (retries-- > 0 && module_is_loaded(driver) == 1) {
-      usleep(100000);
-    }
-    if (module_is_loaded(driver) == 1) {
-      bb_log(LOG_ERR, "Unloading %s driver timed out.\n", driver);
+    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;
     }
+
+    err = module_unload_recursive(mod);
+    kmod_module_unref(mod);
+
+    return err;
   }
   return 1;
 }
@@ -120,18 +181,20 @@ int module_unload(char *driver) {
  * @return 1 if the module is available for loading, 0 otherwise
  */
 int module_is_available(char *module_name) {
-  /* HACK to support call from optirun */
-  char *modprobe_bin = "/sbin/modprobe";
-  if (access(modprobe_bin, X_OK)) {
-    /* if /sbin/modprobe is not found, pray that PATH contains it */
-    modprobe_bin = "modprobe";
+  int err, available;
+  struct kmod_list *list = NULL;
+
+  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;
   }
-  char *mod_argv[] = {
-    modprobe_bin,
-    "--dry-run",
-    "--quiet",
-    module_name,
-    NULL
-  };
-  return bb_run_fork(mod_argv, 1) == EXIT_SUCCESS;
+
+  available = list != NULL;
+
+  kmod_module_unref_list(list);
+
+  return available;
 }
index bcc6c13b226e19535c2d82499385e61aae4b5b24..f05f05c5f1aad1716a2419dcac5e852b47afc70d 100644 (file)
@@ -37,7 +37,6 @@
 #include "bbsocketclient.h"
 #include "bblogger.h"
 #include "bbrun.h"
-#include "driver.h"
 
 
 /**