| 1 | |
| 2 | #ifdef HAVE_XORG_CONFIG_H |
| 3 | #include <xorg-config.h> |
| 4 | #endif |
| 5 | |
| 6 | #include <errno.h> |
| 7 | #include <fcntl.h> |
| 8 | #include <unistd.h> |
| 9 | #include <sys/wait.h> |
| 10 | #include <signal.h> |
| 11 | #include "xf86_OSlib.h" |
| 12 | #include "xf86.h" |
| 13 | |
| 14 | #define MODPROBE_PATH_FILE "/proc/sys/kernel/modprobe" |
| 15 | #define MAX_PATH 1024 |
| 16 | |
| 17 | #if 0 |
| 18 | /* XFree86 #defines execl to be the xf86execl() function which does |
| 19 | * a fork AND exec. We don't want that. We want the regular, |
| 20 | * standard execl(). |
| 21 | */ |
| 22 | #ifdef execl |
| 23 | #undef execl |
| 24 | #endif |
| 25 | #endif |
| 26 | |
| 27 | /* |
| 28 | * Load a Linux kernel module. |
| 29 | * This is used by the DRI/DRM to load a DRM kernel module when |
| 30 | * the X server starts. It could be used for other purposes in the future. |
| 31 | * Input: |
| 32 | * modName - name of the kernel module (Ex: "tdfx") |
| 33 | * Return: |
| 34 | * 0 for failure, 1 for success |
| 35 | */ |
| 36 | int |
| 37 | xf86LoadKernelModule(const char *modName) |
| 38 | { |
| 39 | char mpPath[MAX_PATH] = ""; |
| 40 | int fd = -1, status, n; |
| 41 | pid_t pid; |
| 42 | |
| 43 | /* get the path to the modprobe program */ |
| 44 | fd = open(MODPROBE_PATH_FILE, O_RDONLY); |
| 45 | if (fd >= 0) { |
| 46 | int count = read(fd, mpPath, MAX_PATH - 1); |
| 47 | |
| 48 | if (count <= 0) { |
| 49 | mpPath[0] = 0; |
| 50 | } |
| 51 | else if (mpPath[count - 1] == '\n') { |
| 52 | mpPath[count - 1] = 0; /* replaces \n with \0 */ |
| 53 | } |
| 54 | close(fd); |
| 55 | /* if this worked, mpPath will be "/sbin/modprobe" or similar. */ |
| 56 | } |
| 57 | |
| 58 | if (mpPath[0] == 0) { |
| 59 | /* we failed to get the path from the system, use a default */ |
| 60 | strcpy(mpPath, "/sbin/modprobe"); |
| 61 | } |
| 62 | |
| 63 | /* now fork/exec the modprobe command */ |
| 64 | /* |
| 65 | * It would be good to capture stdout/stderr so that it can be directed |
| 66 | * to the log file. modprobe errors currently are missing from the log |
| 67 | * file. |
| 68 | */ |
| 69 | switch (pid = fork()) { |
| 70 | case 0: /* child */ |
| 71 | /* change real/effective user ID to 0/0 as we need to |
| 72 | * preinstall agpgart module for some DRM modules |
| 73 | */ |
| 74 | if (setreuid(0, 0)) { |
| 75 | xf86Msg(X_WARNING, "LoadKernelModule: " |
| 76 | "Setting of real/effective user Id to 0/0 failed"); |
| 77 | } |
| 78 | setenv("PATH", "/sbin", 1); |
| 79 | n = execl(mpPath, "modprobe", modName, NULL); |
| 80 | xf86Msg(X_WARNING, "LoadKernelModule %s\n", strerror(errno)); |
| 81 | exit(EXIT_FAILURE); /* if we get here the child's exec failed */ |
| 82 | break; |
| 83 | case -1: /* fork failed */ |
| 84 | return 0; |
| 85 | default: /* fork worked */ |
| 86 | { |
| 87 | /* XXX we loop over waitpid() because it sometimes fails on |
| 88 | * the first attempt. Don't know why! |
| 89 | */ |
| 90 | int count = 0, p; |
| 91 | |
| 92 | do { |
| 93 | p = waitpid(pid, &status, 0); |
| 94 | } while (p == -1 && count++ < 4); |
| 95 | |
| 96 | if (p == -1) { |
| 97 | return 0; |
| 98 | } |
| 99 | |
| 100 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { |
| 101 | return 1; /* success! */ |
| 102 | } |
| 103 | else { |
| 104 | return 0; |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | /* never get here */ |
| 110 | return 0; |
| 111 | } |