xref: /aosp_15_r20/external/ltp/lib/tst_kernel.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 /*
2  * Copyright (c) 2017 Cyril Hrubis <[email protected]>
3  * Copyright (c) 2020-2021 Petr Vorel <[email protected]>
4  * Copyright (c) Linux Test Project, 2017-2024
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <sys/personality.h>
21 #include <sys/utsname.h>
22 #include <stdbool.h>
23 #include <limits.h>
24 
25 #include "test.h"
26 #include "tst_kernel.h"
27 #include "old_safe_stdio.h"
28 #include "lapi/abisize.h"
29 
get_kernel_bits_from_uname(struct utsname * buf)30 static int get_kernel_bits_from_uname(struct utsname *buf)
31 {
32 	if (uname(buf)) {
33 		tst_brkm(TBROK | TERRNO, NULL, "uname()");
34 		return -1;
35 	}
36 
37 	return strstr(buf->machine, "64") ? 64 : 32;
38 }
39 
tst_kernel_bits(void)40 int tst_kernel_bits(void)
41 {
42 	struct utsname buf;
43 	static int kernel_bits;
44 
45 	if (kernel_bits)
46 		return kernel_bits;
47 
48 	kernel_bits = get_kernel_bits_from_uname(&buf);
49 
50 	if (kernel_bits == -1)
51 		return -1;
52 
53 	/*
54 	 * ARM64 (aarch64) defines 32-bit compatibility modes as
55 	 * armv8l and armv8b (little and big endian).
56 	 * s390x is 64bit but not contain 64 in the words.
57 	 */
58 	if (!strcmp(buf.machine, "armv8l") || !strcmp(buf.machine, "armv8b")
59 			|| !strcmp(buf.machine, "s390x"))
60 		kernel_bits = 64;
61 
62 #ifdef __ANDROID__
63 	/* Android's bionic libc sets the PER_LINUX32 personality for all 32-bit
64 	 * programs. This will cause buf.machine to report as i686 even though
65 	 * the kernel itself is 64-bit.
66 	 */
67 	if (!strcmp(buf.machine, "i686") &&
68 			(personality(0xffffffff) & PER_MASK) == PER_LINUX32) {
69 		/* Set the personality back to the default. */
70 		if (personality(PER_LINUX) == -1) {
71 			tst_brkm(TBROK | TERRNO, NULL, "personality()");
72 			return -1;
73 		}
74 
75 		/* Redo the uname check without the PER_LINUX32 personality to
76 		 * determine the actual kernel bits value.
77 		 */
78 		kernel_bits = get_kernel_bits_from_uname(&buf);
79 		if (kernel_bits == -1)
80 			return -1;
81 
82 		/* Set the personality back to PER_LINUX32. */
83 		if (personality(PER_LINUX32) == -1) {
84 			tst_brkm(TBROK | TERRNO, NULL, "personality()");
85 			return -1;
86 		}
87 	}
88 #endif  /* __ANDROID__ */
89 
90 	tst_resm(TINFO, "uname.machine=%s kernel is %ibit",
91 		 buf.machine, kernel_bits);
92 
93 	return kernel_bits;
94 }
95 
tst_is_compat_mode(void)96 int tst_is_compat_mode(void)
97 {
98 	return TST_ABI != tst_kernel_bits();
99 }
100 
tst_abi_bits(int abi)101 bool tst_abi_bits(int abi)
102 {
103 	if (abi != 32 && abi != 64)
104 		tst_brkm(TBROK | TERRNO, NULL, "abi parameter can be only 32 or 64");
105 
106 	return abi == TST_ABI;
107 }
108 
tst_search_driver_(const char * driver,const char * file)109 static int tst_search_driver_(const char *driver, const char *file)
110 {
111 	struct stat st;
112 	char buf[PATH_MAX];
113 	char *path = NULL, *search = NULL, *sep = NULL;
114 	FILE *f;
115 	int ret = -1;
116 
117 	struct utsname uts;
118 
119 	if (uname(&uts)) {
120 		tst_brkm(TBROK | TERRNO, NULL, "uname() failed");
121 		return -1;
122 	}
123 	SAFE_ASPRINTF(NULL, &path, "/lib/modules/%s/%s", uts.release, file);
124 
125 	if (stat(path, &st) || !(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) {
126 		tst_resm(TWARN, "expected file %s does not exist or not a file", path);
127 		return -1;
128 	}
129 
130 	if (access(path, R_OK)) {
131 		tst_resm(TWARN, "file %s cannot be read", path);
132 		return -1;
133 	}
134 
135 	/* always search for x86_64 */
136 	char *fix = strstr(driver, "x86-64");
137 
138 	if (fix)
139 		fix[3] = '_';
140 
141 	SAFE_ASPRINTF(NULL, &search, "/%s.ko", driver);
142 
143 	f = SAFE_FOPEN(NULL, path, "r");
144 
145 	while (fgets(buf, sizeof(buf), f)) {
146 		/* cut dependencies after : */
147 		if ((sep = strchr(buf, ':')))
148 			*sep = 0;
149 
150 		/* driver found */
151 		if (strstr(buf, search) != NULL) {
152 			ret = 0;
153 			break;
154 		}
155 	}
156 
157 	SAFE_FCLOSE(NULL, f);
158 	free(search);
159 	free(path);
160 
161 	return ret;
162 }
163 
tst_search_driver(const char * driver,const char * file)164 static int tst_search_driver(const char *driver, const char *file)
165 {
166 #ifdef __ANDROID__
167 	/*
168 	 * Android may not have properly installed modules.* files. We could
169 	 * search modules in /system/lib/modules, but to determine built-in
170 	 * drivers we need modules.builtin. Therefore assume all drivers are
171 	 * available.
172 	 */
173 	return 0;
174 #endif
175 
176 	if (!tst_search_driver_(driver, file))
177 		return 0;
178 
179 	int ret = -1;
180 
181 	if (strrchr(driver, '-') || strrchr(driver, '_')) {
182 		char *driver2 = strdup(driver);
183 		char *ix = driver2;
184 		char find = '-', replace = '_';
185 
186 		if (strrchr(driver, '_')) {
187 			find = '_';
188 			replace = '-';
189 		}
190 
191 		while ((ix = strchr(ix, find)))
192 			*ix++ = replace;
193 
194 		ret = tst_search_driver_(driver2, file);
195 		free(driver2);
196 	}
197 
198 	return ret;
199 }
200 
tst_check_builtin_driver(const char * driver)201 int tst_check_builtin_driver(const char *driver)
202 {
203 	if (!tst_search_driver(driver, "modules.builtin"))
204 		return 0;
205 
206 	return -1;
207 }
208 
tst_check_driver(const char * driver)209 int tst_check_driver(const char *driver)
210 {
211 	if (!tst_search_driver(driver, "modules.dep") ||
212 		!tst_check_builtin_driver(driver))
213 		return 0;
214 
215 	return -1;
216 }
217