]>
Commit | Line | Data |
---|---|---|
ec824e0f VS |
1 | /* |
2 | * GRUB -- GRand Unified Bootloader | |
3 | * Copyright (C) 2013 Free Software Foundation, Inc. | |
4 | * | |
5 | * GRUB is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * GRUB is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include <grub/dl.h> | |
20 | #include <grub/misc.h> | |
21 | #include <grub/mm.h> | |
22 | #include <grub/env.h> | |
23 | #include <grub/command.h> | |
24 | #include <grub/extcmd.h> | |
25 | #include <grub/i18n.h> | |
26 | #include <grub/file.h> | |
27 | #include <grub/elf.h> | |
28 | #include <grub/xen_file.h> | |
29 | #include <grub/efi/pe32.h> | |
40dc61ed | 30 | #include <grub/arm/linux.h> |
9b37229f | 31 | #include <grub/arm64/linux.h> |
ec824e0f VS |
32 | #include <grub/i386/linux.h> |
33 | #include <grub/xnu.h> | |
34 | #include <grub/machoload.h> | |
35 | #include <grub/fileid.h> | |
36 | ||
37 | GRUB_MOD_LICENSE ("GPLv3+"); | |
38 | ||
39 | static const struct grub_arg_option options[] = { | |
40 | {"is-i386-xen-pae-domu", 0, 0, | |
496a6b30 | 41 | N_("Check if FILE can be booted as i386 PAE Xen unprivileged guest kernel"), |
ec824e0f VS |
42 | 0, 0}, |
43 | {"is-x86_64-xen-domu", 0, 0, | |
496a6b30 | 44 | N_("Check if FILE can be booted as x86_64 Xen unprivileged guest kernel"), 0, 0}, |
ec824e0f | 45 | {"is-x86-xen-dom0", 0, 0, |
496a6b30 | 46 | N_("Check if FILE can be used as Xen x86 privileged guest kernel"), 0, 0}, |
ec824e0f VS |
47 | {"is-x86-multiboot", 0, 0, |
48 | N_("Check if FILE can be used as x86 multiboot kernel"), 0, 0}, | |
49 | {"is-x86-multiboot2", 0, 0, | |
50 | N_("Check if FILE can be used as x86 multiboot2 kernel"), 0, 0}, | |
51 | {"is-arm-linux", 0, 0, | |
496a6b30 | 52 | N_("Check if FILE is ARM Linux"), 0, 0}, |
a4d61002 VS |
53 | {"is-arm64-linux", 0, 0, |
54 | N_("Check if FILE is ARM64 Linux"), 0, 0}, | |
ec824e0f | 55 | {"is-ia64-linux", 0, 0, |
496a6b30 | 56 | N_("Check if FILE is IA64 Linux"), 0, 0}, |
ec824e0f | 57 | {"is-mips-linux", 0, 0, |
496a6b30 | 58 | N_("Check if FILE is MIPS Linux"), 0, 0}, |
ec824e0f | 59 | {"is-mipsel-linux", 0, 0, |
496a6b30 | 60 | N_("Check if FILE is MIPSEL Linux"), 0, 0}, |
ec824e0f | 61 | {"is-sparc64-linux", 0, 0, |
496a6b30 | 62 | N_("Check if FILE is SPARC64 Linux"), 0, 0}, |
ec824e0f | 63 | {"is-powerpc-linux", 0, 0, |
496a6b30 | 64 | N_("Check if FILE is POWERPC Linux"), 0, 0}, |
ec824e0f | 65 | {"is-x86-linux", 0, 0, |
496a6b30 | 66 | N_("Check if FILE is x86 Linux"), 0, 0}, |
ec824e0f | 67 | {"is-x86-linux32", 0, 0, |
496a6b30 | 68 | N_("Check if FILE is x86 Linux supporting 32-bit protocol"), 0, 0}, |
ec824e0f | 69 | {"is-x86-kfreebsd", 0, 0, |
496a6b30 | 70 | N_("Check if FILE is x86 kFreeBSD"), 0, 0}, |
ec824e0f | 71 | {"is-i386-kfreebsd", 0, 0, |
496a6b30 | 72 | N_("Check if FILE is i386 kFreeBSD"), 0, 0}, |
ec824e0f | 73 | {"is-x86_64-kfreebsd", 0, 0, |
496a6b30 | 74 | N_("Check if FILE is x86_64 kFreeBSD"), 0, 0}, |
ec824e0f VS |
75 | |
76 | {"is-x86-knetbsd", 0, 0, | |
496a6b30 | 77 | N_("Check if FILE is x86 kNetBSD"), 0, 0}, |
ec824e0f | 78 | {"is-i386-knetbsd", 0, 0, |
496a6b30 | 79 | N_("Check if FILE is i386 kNetBSD"), 0, 0}, |
ec824e0f | 80 | {"is-x86_64-knetbsd", 0, 0, |
496a6b30 | 81 | N_("Check if FILE is x86_64 kNetBSD"), 0, 0}, |
ec824e0f VS |
82 | |
83 | {"is-i386-efi", 0, 0, | |
84 | N_("Check if FILE is i386 EFI file"), 0, 0}, | |
85 | {"is-x86_64-efi", 0, 0, | |
496a6b30 | 86 | N_("Check if FILE is x86_64 EFI file"), 0, 0}, |
ec824e0f VS |
87 | {"is-ia64-efi", 0, 0, |
88 | N_("Check if FILE is IA64 EFI file"), 0, 0}, | |
26063216 VS |
89 | {"is-arm64-efi", 0, 0, |
90 | N_("Check if FILE is ARM64 EFI file"), 0, 0}, | |
ec824e0f VS |
91 | {"is-arm-efi", 0, 0, |
92 | N_("Check if FILE is ARM EFI file"), 0, 0}, | |
f1957dc8 AG |
93 | {"is-riscv32-efi", 0, 0, |
94 | N_("Check if FILE is RISC-V 32bit EFI file"), 0, 0}, | |
95 | {"is-riscv64-efi", 0, 0, | |
96 | N_("Check if FILE is RISC-V 64bit EFI file"), 0, 0}, | |
ec824e0f VS |
97 | {"is-hibernated-hiberfil", 0, 0, |
98 | N_("Check if FILE is hiberfil.sys in hibernated state"), 0, 0}, | |
99 | {"is-x86_64-xnu", 0, 0, | |
496a6b30 | 100 | N_("Check if FILE is x86_64 XNU (Mac OS X kernel)"), 0, 0}, |
ec824e0f | 101 | {"is-i386-xnu", 0, 0, |
496a6b30 | 102 | N_("Check if FILE is i386 XNU (Mac OS X kernel)"), 0, 0}, |
ec824e0f | 103 | {"is-xnu-hibr", 0, 0, |
496a6b30 | 104 | N_("Check if FILE is XNU (Mac OS X kernel) hibernated image"), 0, 0}, |
ec824e0f VS |
105 | {"is-x86-bios-bootsector", 0, 0, |
106 | N_("Check if FILE is BIOS bootsector"), 0, 0}, | |
107 | {0, 0, 0, 0, 0, 0} | |
108 | }; | |
109 | ||
110 | enum | |
111 | { | |
112 | IS_PAE_DOMU, | |
113 | IS_64_DOMU, | |
114 | IS_DOM0, | |
115 | IS_MULTIBOOT, | |
116 | IS_MULTIBOOT2, | |
117 | IS_ARM_LINUX, | |
a4d61002 | 118 | IS_ARM64_LINUX, |
ec824e0f VS |
119 | IS_IA64_LINUX, |
120 | IS_MIPS_LINUX, | |
121 | IS_MIPSEL_LINUX, | |
122 | IS_SPARC64_LINUX, | |
123 | IS_POWERPC_LINUX, | |
124 | IS_X86_LINUX, | |
125 | IS_X86_LINUX32, | |
126 | IS_X86_KFREEBSD, | |
127 | IS_X86_KFREEBSD32, | |
128 | IS_X86_KFREEBSD64, | |
129 | IS_X86_KNETBSD, | |
130 | IS_X86_KNETBSD32, | |
131 | IS_X86_KNETBSD64, | |
132 | IS_32_EFI, | |
133 | IS_64_EFI, | |
134 | IS_IA_EFI, | |
26063216 | 135 | IS_ARM64_EFI, |
ec824e0f | 136 | IS_ARM_EFI, |
9340f5cb DF |
137 | IS_RISCV32_EFI, |
138 | IS_RISCV64_EFI, | |
ec824e0f VS |
139 | IS_HIBERNATED, |
140 | IS_XNU64, | |
141 | IS_XNU32, | |
142 | IS_XNU_HIBR, | |
143 | IS_BIOS_BOOTSECTOR, | |
144 | OPT_TYPE_MIN = IS_PAE_DOMU, | |
145 | OPT_TYPE_MAX = IS_BIOS_BOOTSECTOR | |
146 | }; | |
147 | ||
148 | ||
149 | static grub_err_t | |
150 | grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args) | |
151 | { | |
152 | grub_file_t file = 0; | |
153 | grub_elf_t elf = 0; | |
154 | grub_err_t err; | |
155 | int type = -1, i; | |
156 | int ret = 0; | |
157 | grub_macho_t macho = 0; | |
158 | ||
159 | if (argc == 0) | |
160 | return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); | |
161 | for (i = OPT_TYPE_MIN; i <= OPT_TYPE_MAX; i++) | |
162 | if (ctxt->state[i].set) | |
163 | { | |
164 | if (type == -1) | |
165 | { | |
166 | type = i; | |
167 | continue; | |
168 | } | |
169 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple types specified"); | |
170 | } | |
171 | if (type == -1) | |
172 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "no type specified"); | |
173 | ||
ca0a4f68 | 174 | file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL); |
ec824e0f VS |
175 | if (!file) |
176 | return grub_errno; | |
177 | switch (type) | |
178 | { | |
179 | case IS_BIOS_BOOTSECTOR: | |
180 | { | |
181 | grub_uint16_t sig; | |
182 | if (grub_file_size (file) != 512) | |
183 | break; | |
184 | if (grub_file_seek (file, 510) == (grub_size_t) -1) | |
185 | break; | |
186 | if (grub_file_read (file, &sig, 2) != 2) | |
187 | break; | |
188 | if (sig != grub_cpu_to_le16_compile_time (0xaa55)) | |
189 | break; | |
190 | ret = 1; | |
191 | break; | |
192 | } | |
193 | case IS_IA64_LINUX: | |
194 | { | |
195 | Elf64_Ehdr ehdr; | |
196 | ||
197 | if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) | |
198 | break; | |
199 | ||
200 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 | |
201 | || ehdr.e_ident[EI_MAG1] != ELFMAG1 | |
202 | || ehdr.e_ident[EI_MAG2] != ELFMAG2 | |
203 | || ehdr.e_ident[EI_MAG3] != ELFMAG3 | |
204 | || ehdr.e_ident[EI_VERSION] != EV_CURRENT | |
205 | || ehdr.e_version != EV_CURRENT) | |
206 | break; | |
207 | ||
208 | if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 | |
209 | || ehdr.e_ident[EI_DATA] != ELFDATA2LSB | |
210 | || ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_IA_64)) | |
211 | break; | |
212 | ||
213 | ret = 1; | |
214 | ||
215 | break; | |
216 | } | |
217 | ||
218 | case IS_SPARC64_LINUX: | |
219 | { | |
220 | Elf64_Ehdr ehdr; | |
221 | ||
222 | if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) | |
223 | break; | |
224 | ||
225 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 | |
226 | || ehdr.e_ident[EI_MAG1] != ELFMAG1 | |
227 | || ehdr.e_ident[EI_MAG2] != ELFMAG2 | |
228 | || ehdr.e_ident[EI_MAG3] != ELFMAG3 | |
229 | || ehdr.e_ident[EI_VERSION] != EV_CURRENT | |
230 | || ehdr.e_version != EV_CURRENT) | |
231 | break; | |
232 | ||
233 | if (ehdr.e_ident[EI_CLASS] != ELFCLASS64 | |
234 | || ehdr.e_ident[EI_DATA] != ELFDATA2MSB) | |
235 | break; | |
236 | ||
237 | if (ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_SPARCV9) | |
238 | || ehdr.e_type != grub_cpu_to_be16_compile_time (ET_EXEC)) | |
239 | break; | |
240 | ||
241 | ret = 1; | |
242 | ||
243 | break; | |
244 | } | |
245 | ||
246 | case IS_POWERPC_LINUX: | |
247 | { | |
248 | Elf32_Ehdr ehdr; | |
249 | ||
250 | if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) | |
251 | break; | |
252 | ||
253 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 | |
254 | || ehdr.e_ident[EI_MAG1] != ELFMAG1 | |
255 | || ehdr.e_ident[EI_MAG2] != ELFMAG2 | |
256 | || ehdr.e_ident[EI_MAG3] != ELFMAG3 | |
257 | || ehdr.e_ident[EI_VERSION] != EV_CURRENT | |
258 | || ehdr.e_version != EV_CURRENT) | |
259 | break; | |
260 | ||
261 | if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB | |
262 | || (ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_PPC) | |
263 | && ehdr.e_machine != | |
264 | grub_cpu_to_le16_compile_time (EM_PPC64))) | |
265 | break; | |
266 | ||
267 | if (ehdr.e_type != grub_cpu_to_be16_compile_time (ET_EXEC) | |
268 | && ehdr.e_type != grub_cpu_to_be16_compile_time (ET_DYN)) | |
269 | break; | |
270 | ||
271 | ret = 1; | |
272 | ||
273 | break; | |
274 | } | |
275 | ||
276 | case IS_MIPS_LINUX: | |
277 | { | |
278 | Elf32_Ehdr ehdr; | |
279 | ||
280 | if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) | |
281 | break; | |
282 | ||
283 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 | |
284 | || ehdr.e_ident[EI_MAG1] != ELFMAG1 | |
285 | || ehdr.e_ident[EI_MAG2] != ELFMAG2 | |
286 | || ehdr.e_ident[EI_MAG3] != ELFMAG3 | |
287 | || ehdr.e_ident[EI_VERSION] != EV_CURRENT | |
288 | || ehdr.e_version != EV_CURRENT) | |
289 | break; | |
290 | ||
291 | if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB | |
292 | || ehdr.e_machine != grub_cpu_to_be16_compile_time (EM_MIPS) | |
293 | || ehdr.e_type != grub_cpu_to_be16_compile_time (ET_EXEC)) | |
294 | break; | |
295 | ||
296 | ret = 1; | |
297 | ||
298 | break; | |
299 | } | |
300 | ||
301 | case IS_X86_KNETBSD: | |
302 | case IS_X86_KNETBSD32: | |
303 | case IS_X86_KNETBSD64: | |
304 | { | |
305 | int is32, is64; | |
306 | ||
307 | elf = grub_elf_file (file, file->name); | |
308 | ||
309 | if (elf->ehdr.ehdr32.e_type != grub_cpu_to_le16_compile_time (ET_EXEC) | |
310 | || elf->ehdr.ehdr32.e_ident[EI_DATA] != ELFDATA2LSB) | |
311 | break; | |
312 | ||
313 | is32 = grub_elf_is_elf32 (elf); | |
314 | is64 = grub_elf_is_elf64 (elf); | |
315 | if (!is32 && !is64) | |
316 | break; | |
317 | if (!is32 && type == IS_X86_KNETBSD32) | |
318 | break; | |
319 | if (!is64 && type == IS_X86_KNETBSD64) | |
320 | break; | |
321 | if (is64) | |
322 | ret = grub_file_check_netbsd64 (elf); | |
323 | if (is32) | |
324 | ret = grub_file_check_netbsd32 (elf); | |
325 | break; | |
326 | } | |
327 | ||
328 | case IS_X86_KFREEBSD: | |
329 | case IS_X86_KFREEBSD32: | |
330 | case IS_X86_KFREEBSD64: | |
331 | { | |
332 | Elf32_Ehdr ehdr; | |
333 | int is32, is64; | |
334 | ||
335 | if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) | |
336 | break; | |
337 | ||
338 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 | |
339 | || ehdr.e_ident[EI_MAG1] != ELFMAG1 | |
340 | || ehdr.e_ident[EI_MAG2] != ELFMAG2 | |
341 | || ehdr.e_ident[EI_MAG3] != ELFMAG3 | |
342 | || ehdr.e_ident[EI_VERSION] != EV_CURRENT | |
343 | || ehdr.e_version != EV_CURRENT) | |
344 | break; | |
345 | ||
346 | if (ehdr.e_type != grub_cpu_to_le16_compile_time (ET_EXEC) | |
347 | || ehdr.e_ident[EI_DATA] != ELFDATA2LSB) | |
348 | break; | |
349 | ||
350 | if (ehdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD) | |
351 | break; | |
352 | ||
353 | is32 = (ehdr.e_machine == grub_cpu_to_le16_compile_time (EM_386) | |
354 | && ehdr.e_ident[EI_CLASS] == ELFCLASS32); | |
355 | is64 = (ehdr.e_machine == grub_cpu_to_le16_compile_time (EM_X86_64) | |
356 | && ehdr.e_ident[EI_CLASS] == ELFCLASS64); | |
357 | if (!is32 && !is64) | |
358 | break; | |
359 | if (!is32 && (type == IS_X86_KFREEBSD32 || type == IS_X86_KNETBSD32)) | |
360 | break; | |
361 | if (!is64 && (type == IS_X86_KFREEBSD64 || type == IS_X86_KNETBSD64)) | |
362 | break; | |
363 | ret = 1; | |
364 | ||
365 | break; | |
366 | } | |
367 | ||
368 | ||
369 | case IS_MIPSEL_LINUX: | |
370 | { | |
371 | Elf32_Ehdr ehdr; | |
372 | ||
373 | if (grub_file_read (file, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) | |
374 | break; | |
375 | ||
376 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 | |
377 | || ehdr.e_ident[EI_MAG1] != ELFMAG1 | |
378 | || ehdr.e_ident[EI_MAG2] != ELFMAG2 | |
379 | || ehdr.e_ident[EI_MAG3] != ELFMAG3 | |
380 | || ehdr.e_ident[EI_VERSION] != EV_CURRENT | |
381 | || ehdr.e_version != EV_CURRENT) | |
382 | break; | |
383 | ||
384 | if (ehdr.e_machine != grub_cpu_to_le16_compile_time (EM_MIPS) | |
385 | || ehdr.e_type != grub_cpu_to_le16_compile_time (ET_EXEC)) | |
386 | break; | |
387 | ||
388 | ret = 1; | |
389 | ||
390 | break; | |
391 | } | |
392 | case IS_ARM_LINUX: | |
393 | { | |
40dc61ed LL |
394 | struct linux_arm_kernel_header lh; |
395 | ||
396 | if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) | |
95b56e3a | 397 | break; |
40dc61ed LL |
398 | /* Short forward branch in A32 state (for Raspberry pi kernels). */ |
399 | if (lh.code0 == grub_cpu_to_le32_compile_time (0xea000006)) | |
95b56e3a VS |
400 | { |
401 | ret = 1; | |
402 | break; | |
403 | } | |
404 | ||
40dc61ed LL |
405 | if (lh.magic == |
406 | grub_cpu_to_le32_compile_time (GRUB_LINUX_ARM_MAGIC_SIGNATURE)) | |
95b56e3a VS |
407 | { |
408 | ret = 1; | |
409 | break; | |
410 | } | |
ec824e0f VS |
411 | break; |
412 | } | |
a4d61002 VS |
413 | case IS_ARM64_LINUX: |
414 | { | |
9b37229f | 415 | struct linux_arm64_kernel_header lh; |
a4d61002 | 416 | |
9b37229f | 417 | if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) |
a4d61002 | 418 | break; |
9b37229f LL |
419 | |
420 | if (lh.magic == | |
421 | grub_cpu_to_le32_compile_time (GRUB_LINUX_ARM64_MAGIC_SIGNATURE)) | |
a4d61002 VS |
422 | { |
423 | ret = 1; | |
424 | break; | |
425 | } | |
426 | break; | |
427 | } | |
ec824e0f VS |
428 | case IS_PAE_DOMU ... IS_DOM0: |
429 | { | |
430 | struct grub_xen_file_info xen_inf; | |
431 | elf = grub_xen_file (file); | |
432 | if (!elf) | |
433 | break; | |
434 | err = grub_xen_get_info (elf, &xen_inf); | |
435 | if (err) | |
436 | break; | |
437 | /* Unfortuntely no way to check if kernel supports dom0. */ | |
438 | if (type == IS_DOM0) | |
439 | ret = 1; | |
440 | if (type == IS_PAE_DOMU) | |
441 | ret = (xen_inf.arch == GRUB_XEN_FILE_I386_PAE | |
442 | || xen_inf.arch == GRUB_XEN_FILE_I386_PAE_BIMODE); | |
443 | if (type == IS_64_DOMU) | |
444 | ret = (xen_inf.arch == GRUB_XEN_FILE_X86_64); | |
445 | break; | |
446 | } | |
447 | case IS_MULTIBOOT: | |
448 | case IS_MULTIBOOT2: | |
449 | { | |
450 | grub_uint32_t *buffer; | |
451 | grub_ssize_t len; | |
452 | grub_size_t search_size; | |
453 | grub_uint32_t *header; | |
454 | grub_uint32_t magic; | |
455 | grub_size_t step; | |
456 | ||
457 | if (type == IS_MULTIBOOT2) | |
458 | { | |
459 | search_size = 32768; | |
460 | magic = grub_cpu_to_le32_compile_time (0xe85250d6); | |
461 | step = 2; | |
462 | } | |
463 | else | |
464 | { | |
465 | search_size = 8192; | |
466 | magic = grub_cpu_to_le32_compile_time (0x1BADB002); | |
467 | step = 1; | |
468 | } | |
469 | ||
470 | buffer = grub_malloc (search_size); | |
471 | if (!buffer) | |
472 | break; | |
473 | ||
474 | len = grub_file_read (file, buffer, search_size); | |
475 | if (len < 32) | |
476 | { | |
477 | grub_free (buffer); | |
478 | break; | |
479 | } | |
480 | ||
481 | /* Look for the multiboot header in the buffer. The header should | |
482 | be at least 12 bytes and aligned on a 4-byte boundary. */ | |
483 | for (header = buffer; | |
484 | ((char *) header <= | |
b04c6d32 VS |
485 | (char *) buffer + len - (type == IS_MULTIBOOT2 ? 16 : 12)); |
486 | header += step) | |
ec824e0f VS |
487 | { |
488 | if (header[0] == magic | |
489 | && !(grub_le_to_cpu32 (header[0]) | |
490 | + grub_le_to_cpu32 (header[1]) | |
491 | + grub_le_to_cpu32 (header[2]) | |
492 | + (type == IS_MULTIBOOT2 | |
493 | ? grub_le_to_cpu32 (header[3]) : 0))) | |
b04c6d32 VS |
494 | { |
495 | ret = 1; | |
496 | break; | |
497 | } | |
ec824e0f VS |
498 | } |
499 | ||
ec824e0f VS |
500 | grub_free (buffer); |
501 | break; | |
502 | } | |
503 | case IS_X86_LINUX32: | |
504 | case IS_X86_LINUX: | |
505 | { | |
7d36709d | 506 | struct linux_i386_kernel_header lh; |
ec824e0f VS |
507 | if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) |
508 | break; | |
509 | if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) | |
510 | break; | |
511 | ||
512 | if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) | |
513 | break; | |
514 | ||
515 | /* FIXME: some really old kernels (< 1.3.73) will fail this. */ | |
516 | if (lh.header != | |
3245f02d | 517 | grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE) |
ec824e0f VS |
518 | || grub_le_to_cpu16 (lh.version) < 0x0200) |
519 | break; | |
520 | ||
521 | if (type == IS_X86_LINUX) | |
522 | { | |
523 | ret = 1; | |
524 | break; | |
525 | } | |
526 | ||
527 | /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and | |
528 | still not support 32-bit boot. */ | |
529 | if (lh.header != | |
3245f02d | 530 | grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE) |
ec824e0f VS |
531 | || grub_le_to_cpu16 (lh.version) < 0x0203) |
532 | break; | |
533 | ||
534 | if (!(lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL)) | |
535 | break; | |
536 | ret = 1; | |
537 | break; | |
538 | } | |
539 | case IS_HIBERNATED: | |
540 | { | |
541 | grub_uint8_t hibr_file_magic[4]; | |
542 | if (grub_file_read (file, &hibr_file_magic, sizeof (hibr_file_magic)) | |
543 | != sizeof (hibr_file_magic)) | |
544 | break; | |
545 | if (grub_memcmp ("hibr", hibr_file_magic, sizeof (hibr_file_magic)) == | |
546 | 0 | |
547 | || grub_memcmp ("HIBR", hibr_file_magic, | |
548 | sizeof (hibr_file_magic)) == 0) | |
549 | ret = 1; | |
550 | break; | |
551 | } | |
552 | case IS_XNU64: | |
553 | case IS_XNU32: | |
554 | { | |
ca0a4f68 VS |
555 | macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, |
556 | (type == IS_XNU64)); | |
ec824e0f VS |
557 | if (!macho) |
558 | break; | |
559 | /* FIXME: more checks? */ | |
560 | ret = 1; | |
561 | break; | |
562 | } | |
563 | case IS_XNU_HIBR: | |
564 | { | |
565 | struct grub_xnu_hibernate_header hibhead; | |
566 | if (grub_file_read (file, &hibhead, sizeof (hibhead)) | |
567 | != sizeof (hibhead)) | |
568 | break; | |
569 | if (hibhead.magic != | |
570 | grub_cpu_to_le32_compile_time (GRUB_XNU_HIBERNATE_MAGIC)) | |
571 | break; | |
572 | ret = 1; | |
573 | break; | |
574 | } | |
575 | case IS_32_EFI: | |
576 | case IS_64_EFI: | |
577 | case IS_IA_EFI: | |
26063216 | 578 | case IS_ARM64_EFI: |
ec824e0f | 579 | case IS_ARM_EFI: |
9340f5cb DF |
580 | case IS_RISCV32_EFI: |
581 | case IS_RISCV64_EFI: | |
ec824e0f VS |
582 | { |
583 | char signature[4]; | |
584 | grub_uint32_t pe_offset; | |
585 | struct grub_pe32_coff_header coff_head; | |
586 | ||
587 | if (grub_file_read (file, signature, 2) != 2) | |
588 | break; | |
589 | if (signature[0] != 'M' || signature[1] != 'Z') | |
590 | break; | |
591 | if ((grub_ssize_t) grub_file_seek (file, 0x3c) == -1) | |
592 | break; | |
593 | if (grub_file_read (file, &pe_offset, 4) != 4) | |
594 | break; | |
595 | if ((grub_ssize_t) grub_file_seek (file, grub_le_to_cpu32 (pe_offset)) | |
596 | == -1) | |
597 | break; | |
598 | if (grub_file_read (file, signature, 4) != 4) | |
599 | break; | |
600 | if (signature[0] != 'P' || signature[1] != 'E' | |
601 | || signature[2] != '\0' || signature[3] != '\0') | |
602 | break; | |
603 | ||
604 | if (grub_file_read (file, &coff_head, sizeof (coff_head)) | |
605 | != sizeof (coff_head)) | |
606 | break; | |
607 | if (type == IS_32_EFI | |
608 | && coff_head.machine != | |
609 | grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_I386)) | |
610 | break; | |
611 | if (type == IS_64_EFI | |
612 | && coff_head.machine != | |
613 | grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_X86_64)) | |
614 | break; | |
615 | if (type == IS_IA_EFI | |
616 | && coff_head.machine != | |
617 | grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_IA64)) | |
618 | break; | |
26063216 VS |
619 | if (type == IS_ARM64_EFI |
620 | && coff_head.machine != | |
621 | grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_ARM64)) | |
622 | break; | |
ec824e0f VS |
623 | if (type == IS_ARM_EFI |
624 | && coff_head.machine != | |
625 | grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_ARMTHUMB_MIXED)) | |
626 | break; | |
9340f5cb | 627 | if ((type == IS_RISCV32_EFI || type == IS_RISCV64_EFI) |
f1957dc8 AG |
628 | && coff_head.machine != |
629 | grub_cpu_to_le16_compile_time (GRUB_PE32_MACHINE_RISCV64)) | |
630 | /* TODO: Determine bitness dynamically */ | |
631 | break; | |
632 | if (type == IS_IA_EFI || type == IS_64_EFI || type == IS_ARM64_EFI || | |
9340f5cb | 633 | type == IS_RISCV32_EFI || type == IS_RISCV64_EFI) |
ec824e0f VS |
634 | { |
635 | struct grub_pe64_optional_header o64; | |
636 | if (grub_file_read (file, &o64, sizeof (o64)) != sizeof (o64)) | |
637 | break; | |
638 | if (o64.magic != | |
639 | grub_cpu_to_le16_compile_time (GRUB_PE32_PE64_MAGIC)) | |
640 | break; | |
641 | if (o64.subsystem != | |
642 | grub_cpu_to_le16_compile_time | |
643 | (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION)) | |
644 | break; | |
645 | ret = 1; | |
646 | break; | |
647 | } | |
648 | if (type == IS_32_EFI || type == IS_ARM_EFI) | |
649 | { | |
650 | struct grub_pe32_optional_header o32; | |
651 | if (grub_file_read (file, &o32, sizeof (o32)) != sizeof (o32)) | |
652 | break; | |
653 | if (o32.magic != | |
654 | grub_cpu_to_le16_compile_time (GRUB_PE32_PE32_MAGIC)) | |
655 | break; | |
656 | if (o32.subsystem != | |
657 | grub_cpu_to_le16_compile_time | |
658 | (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION)) | |
659 | break; | |
660 | ret = 1; | |
661 | break; | |
662 | } | |
663 | break; | |
664 | } | |
665 | } | |
666 | ||
667 | if (elf) | |
668 | grub_elf_close (elf); | |
669 | else if (macho) | |
670 | grub_macho_close (macho); | |
671 | else if (file) | |
672 | grub_file_close (file); | |
673 | ||
674 | if (!ret && (grub_errno == GRUB_ERR_BAD_OS || grub_errno == GRUB_ERR_NONE)) | |
675 | /* TRANSLATORS: it's a standalone boolean value, | |
676 | opposite of "true". */ | |
677 | grub_error (GRUB_ERR_TEST_FAILURE, N_("false")); | |
678 | return grub_errno; | |
679 | } | |
680 | ||
681 | static grub_extcmd_t cmd; | |
682 | ||
683 | GRUB_MOD_INIT(file) | |
684 | { | |
685 | cmd = grub_register_extcmd ("file", grub_cmd_file, 0, | |
636977b0 | 686 | N_("OPTIONS FILE"), |
ec824e0f VS |
687 | N_("Check if FILE is of specified type."), |
688 | options); | |
689 | } | |
690 | ||
691 | GRUB_MOD_FINI(file) | |
692 | { | |
693 | grub_unregister_extcmd (cmd); | |
694 | } |