aboutsummaryrefslogtreecommitdiffstats
path: root/package/busybox/patches/470-insmod_search.patch
blob: 7f0188fc82da1eead00b7fce60887dd578e78284 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
--- a/modutils/Config.src
+++ b/modutils/Config.src
@@ -247,7 +247,7 @@ config FEATURE_MODUTILS_SYMBOLS
 config DEFAULT_MODULES_DIR
 	string "Default directory containing modules"
 	default "/lib/modules"
-	depends on DEPMOD || MODPROBE || MODPROBE_SMALL || MODINFO
+	depends on DEPMOD || INSMOD || MODPROBE || MODPROBE_SMALL || MODINFO
 	help
 	  Directory that contains kernel modules.
 	  Defaults to "/lib/modules"
--- a/modutils/insmod.c
+++ b/modutils/insmod.c
@@ -11,6 +11,106 @@
 
 #include "libbb.h"
 #include "modutils.h"
+#include <sys/utsname.h>
+#ifndef CONFIG_FEATURE_2_4_MODULES
+#include <sys/mman.h>
+#include <asm/unistd.h>
+#include <sys/syscall.h>
+#endif
+
+static char *g_filename = NULL;
+
+static int FAST_FUNC check_module_name_match(const char *filename, struct stat *statbuf,
+				   void *userdata, int depth)
+{
+	char *fullname = (char *) userdata;
+	char *tmp;
+
+	if (fullname[0] == '\0')
+		return FALSE;
+
+	tmp = bb_get_last_path_component_nostrip(filename);
+	if (strcmp(tmp, fullname) == 0) {
+		/* Stop searching if we find a match */
+		g_filename = xstrdup(filename);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int find_module(char *filename)
+{
+	char *module_dir, real_module_dir[FILENAME_MAX];
+	int len, slen, ret = ENOENT, k_version;
+	struct utsname myuname;
+	const char *suffix = ".ko";
+	struct stat st;
+
+	/* check the kernel version */
+	if (uname(&myuname) != 0)
+		return EINVAL;
+
+	k_version = myuname.release[0] - '0';
+
+	if (k_version < 2 || k_version > 9)
+		return EINVAL;
+
+	if (k_version == 2) {
+		int k_patchlevel = myuname.release[2] - '0';
+		if (k_patchlevel <= 4)
+#if ENABLE_FEATURE_2_4_MODULES
+			suffix = ".o";
+#else
+			return EINVAL;
+#endif
+	}
+
+	len = strlen(filename);
+	slen = strlen(suffix);
+
+	/* check for suffix and absolute path first */
+	if ((len < slen + 2) || (strcmp(filename + len - slen, suffix) != 0)) {
+		filename = xasprintf("%s%s", filename, suffix);
+	} else {
+		filename = strdup(filename);
+		if ((stat(filename, &st) == 0) && S_ISREG(st.st_mode)) {
+			g_filename = filename;
+			return 0;
+		}
+		free(filename);
+		return ENOENT;
+	}
+
+	/* next: scan /lib/modules/<release> */
+	/* Jump through hoops in case /lib/modules/`uname -r`
+	* is a symlink.  We do not want recursive_action to
+	* follow symlinks, but we do want to follow the
+	* /lib/modules/`uname -r` dir, So resolve it ourselves
+	* if it is a link... */
+	module_dir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, myuname.release);
+	if (realpath(module_dir, real_module_dir) != NULL) {
+		free(module_dir);
+		module_dir = real_module_dir;
+	}
+
+	recursive_action(module_dir, ACTION_RECURSE,
+		check_module_name_match, 0, filename, 0);
+
+	/* Check if we have a complete path */
+	if (g_filename == NULL)
+		goto done;
+
+	if ((stat(g_filename, &st) == 0) && S_ISREG(st.st_mode))
+		ret = 0;
+	else
+		free(g_filename);
+
+done:
+	free(filename);
+
+	return ret;
+}
 
 /* 2.6 style insmod has no options and required filename
  * (not module name - .ko can't be omitted) */
@@ -58,9 +158,15 @@ int insmod_main(int argc UNUSED_PARAM, c
 	if (!filename)
 		bb_show_usage();
 
-	rc = bb_init_module(filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0));
+	rc = find_module(filename);
+	if (rc || (g_filename == NULL))
+		goto done;
+
+	rc = bb_init_module(g_filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0));
 	if (rc)
 		bb_error_msg("can't insert '%s': %s", filename, moderror(rc));
+	free (g_filename);
 
+done:
 	return rc;
 }