xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/os-support/linux/lnx_kmod.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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
xf86LoadKernelModule(const char * modName)37 xf86LoadKernelModule(const char *modName)
38 {
39     char mpPath[MAX_PATH] = "";
40     int fd = -1, status;
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         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 }
112