Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | } |