File: filearch.ml

package info (click to toggle)
libguestfs 1%3A1.40.2-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 123,660 kB
  • sloc: ansic: 460,074; ml: 63,059; sh: 14,955; java: 9,512; makefile: 9,133; cs: 6,300; haskell: 5,652; python: 3,856; perl: 3,619; erlang: 2,435; xml: 1,683; ruby: 350; pascal: 255; lex: 135; yacc: 128; cpp: 10
file content (140 lines) | stat: -rw-r--r-- 4,335 bytes parent folder | download
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
138
139
140
(* guestfs-inspection
 * Copyright (C) 2009-2019 Red Hat Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *)

open Unix
open Printf

open Std_utils
open Unix_utils

open Utils

let re_file_elf =
  PCRE.compile "ELF (\\d+)-bit (MSB|LSB).*(?:executable|shared object|relocatable)(?:,)? ([^,]+?),"

let re_file_elf_ppc64 = PCRE.compile ".*64.*PowerPC"

let initrd_binaries = [
  "bin/ls";
  "bin/rm";
  "bin/modprobe";
  "sbin/modprobe";
  "bin/sh";
  "bin/bash";
  "bin/dash";
  "bin/nash";
]

let rec file_architecture orig_path =
  (* Get the output of the "file" command.  Note that because this
   * is running in the daemon, LANG=C so it's in English.
   *)
  let magic = File.file orig_path in
  file_architecture_of_magic magic orig_path orig_path

and file_architecture_of_magic magic orig_path path =
  if PCRE.matches re_file_elf magic then (
    let bits = PCRE.sub 1 in
    let endianness = PCRE.sub 2 in
    let elf_arch = PCRE.sub 3 in
    canonical_elf_arch bits endianness elf_arch
  )
  else if String.find magic "PE32 executable" >= 0 then
    "i386"
  else if String.find magic "PE32+ executable" >= 0 then
    "x86_64"
  else if String.find magic "cpio archive" >= 0 then
    cpio_arch magic orig_path path
  else
    failwithf "unknown architecture: %s" path

(* Convert output from 'file' command on ELF files to the canonical
 * architecture string.
 *)
and canonical_elf_arch bits endianness elf_arch =
  let substr s = String.find elf_arch s >= 0 in
  if substr "Intel 80386" || substr "Intel 80486" then
    "i386"
  else if substr "x86-64" || substr "AMD x86-64" then
    "x86_64"
  else if substr "SPARC32" then
    "sparc"
  else if substr "SPARC V9" then
    "sparc64"
  else if substr "IA-64" then
    "ia64"
  else if PCRE.matches re_file_elf_ppc64 elf_arch then (
    match endianness with
    | "MSB" -> "ppc64"
    | "LSB" -> "ppc64le"
    | _ -> failwithf "unknown endianness '%s'" endianness
  )
  else if substr "PowerPC" then
    "ppc"
  else if substr "ARM aarch64" then
    "aarch64"
  else if substr "ARM" then
    "arm"
  else if substr "UCB RISC-V" then
    sprintf "riscv%s" bits
  else if substr "IBM S/390" then (
    match bits with
    | "32" -> "s390"
    | "64" -> "s390x"
    | _ -> failwithf "unknown S/390 bit size: %s" bits
  )
  else
    elf_arch

and cpio_arch magic orig_path path =
  let zcat =
    if String.find magic "gzip" >= 0 then "zcat"
    else if String.find magic "bzip2" >= 0 then "bzcat"
    else if String.find magic "XZ compressed" >= 0 then "xzcat"
    else "cat" in

  let tmpdir = Mkdtemp.temp_dir "filearch" in
  let finally () = ignore (Sys.command (sprintf "rm -rf %s" (quote tmpdir))) in

  protect ~finally ~f:(
    fun () ->
      (* Construct a command to extract named binaries from the initrd file. *)
      let cmd =
        sprintf "cd %s && %s %s | cpio --quiet -id %s"
                tmpdir zcat (quote (Sysroot.sysroot_path path))
                (String.concat " " (List.map quote initrd_binaries)) in
      if verbose () then eprintf "%s\n%!" cmd;
      if Sys.command cmd <> 0 then
        failwith "cpio command failed";

      (* See if any of the binaries were present in the output. *)
      let rec loop = function
        | bin :: bins ->
           let bin_path = tmpdir // bin in
           if is_regular_file bin_path then (
             let out = command "file" ["-zb"; bin_path] in
             file_architecture_of_magic out orig_path bin_path
           )
           else
             loop bins
        | [] ->
           failwithf "could not determine architecture of cpio archive: %s"
                     path
      in
      loop initrd_binaries
  )