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