diff options
| author | Hisham Muhammad <hisham@gobolinux.org> | 2018-10-30 10:04:23 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-30 10:04:23 -0300 |
| commit | 760ad7c98a4a322b1f028ea9585cd17c5b74b2e2 (patch) | |
| tree | cde11b0975132e82062417c2a0057b13c7b6df4d | |
| parent | 0c534c71465474b92710a2951bf15370fcc8c663 (diff) | |
| download | luarocks-760ad7c98a4a322b1f028ea9585cd17c5b74b2e2.tar.gz luarocks-760ad7c98a4a322b1f028ea9585cd17c5b74b2e2.tar.bz2 luarocks-760ad7c98a4a322b1f028ea9585cd17c5b74b2e2.zip | |
core.sysdetect: add fork-free OS detection (#938)
Detect operating system and architecture without forking subprocesses,
doing `file`-like detection reading data from well-known system
executables.
| -rwxr-xr-x | binary/all_in_one | 12 | ||||
| -rw-r--r-- | install.bat | 2 | ||||
| -rw-r--r-- | spec/util/test_env.lua | 4 | ||||
| -rw-r--r-- | src/luarocks/core/cfg.lua | 70 | ||||
| -rw-r--r-- | src/luarocks/core/sysdetect.lua | 407 |
5 files changed, 447 insertions, 48 deletions
diff --git a/binary/all_in_one b/binary/all_in_one index 01758758..43a18a3b 100755 --- a/binary/all_in_one +++ b/binary/all_in_one | |||
| @@ -50,6 +50,7 @@ local path = require("luarocks.path") | |||
| 50 | local manif = require("luarocks.manif") | 50 | local manif = require("luarocks.manif") |
| 51 | local queries = require("luarocks.queries") | 51 | local queries = require("luarocks.queries") |
| 52 | local persist = require("luarocks.persist") | 52 | local persist = require("luarocks.persist") |
| 53 | local sysdetect = require("luarocks.core.sysdetect") | ||
| 53 | 54 | ||
| 54 | -------------------------------------------------------------------------------- | 55 | -------------------------------------------------------------------------------- |
| 55 | 56 | ||
| @@ -144,16 +145,7 @@ local function write_hardcoded_module(dir) | |||
| 144 | local processor = if_platform("windows", "x86") | 145 | local processor = if_platform("windows", "x86") |
| 145 | 146 | ||
| 146 | if if_platform("unix", true) then | 147 | if if_platform("unix", true) then |
| 147 | system = util.popen_read("uname -s") | 148 | system, processor = sysdetect.detect() |
| 148 | processor = util.popen_read("uname -m") | ||
| 149 | |||
| 150 | if processor:match("i[%d]86") then | ||
| 151 | processor = "x86" | ||
| 152 | elseif processor:match("amd64") or processor:match("x86_64") then | ||
| 153 | processor = "x86_64" | ||
| 154 | elseif processor:match("Power Macintosh") then | ||
| 155 | processor = "powerpc" | ||
| 156 | end | ||
| 157 | end | 149 | end |
| 158 | 150 | ||
| 159 | local hardcoded = { | 151 | local hardcoded = { |
diff --git a/install.bat b/install.bat index 444a6847..4120db49 100644 --- a/install.bat +++ b/install.bat | |||
| @@ -1015,7 +1015,7 @@ local hardcoded_lua = S[[$LUADIR\luarocks\core\hardcoded.lua]] | |||
| 1015 | 1015 | ||
| 1016 | os.remove(hardcoded_lua) | 1016 | os.remove(hardcoded_lua) |
| 1017 | 1017 | ||
| 1018 | vars.SYSTEM = USE_MINGW and "MINGW" or "WindowsNT" | 1018 | vars.SYSTEM = USE_MINGW and "mingw" or "windows" |
| 1019 | 1019 | ||
| 1020 | local f = io.open(hardcoded_lua, "w") | 1020 | local f = io.open(hardcoded_lua, "w") |
| 1021 | f:write(S[=[ | 1021 | f:write(S[=[ |
diff --git a/spec/util/test_env.lua b/spec/util/test_env.lua index f4cd3f60..6850214f 100644 --- a/spec/util/test_env.lua +++ b/spec/util/test_env.lua | |||
| @@ -807,9 +807,9 @@ local function setup_luarocks() | |||
| 807 | 807 | ||
| 808 | if test_env.TEST_TARGET_OS == "windows" then | 808 | if test_env.TEST_TARGET_OS == "windows" then |
| 809 | if test_env.MINGW then | 809 | if test_env.MINGW then |
| 810 | table.insert(lines, [[SYSTEM = "MINGW",]]) | 810 | table.insert(lines, [[SYSTEM = "mingw",]]) |
| 811 | else | 811 | else |
| 812 | table.insert(lines, [[SYSTEM = "WindowsNT",]]) | 812 | table.insert(lines, [[SYSTEM = "windows",]]) |
| 813 | end | 813 | end |
| 814 | table.insert(lines, ("WIN_TOOLS = %q,"):format(testing_paths.win_tools)) | 814 | table.insert(lines, ("WIN_TOOLS = %q,"):format(testing_paths.win_tools)) |
| 815 | end | 815 | end |
diff --git a/src/luarocks/core/cfg.lua b/src/luarocks/core/cfg.lua index 9be573ce..bbcc72ac 100644 --- a/src/luarocks/core/cfg.lua +++ b/src/luarocks/core/cfg.lua | |||
| @@ -15,6 +15,7 @@ local next, table, pairs, require, os, pcall, ipairs, package, tonumber, type, a | |||
| 15 | 15 | ||
| 16 | local util = require("luarocks.core.util") | 16 | local util = require("luarocks.core.util") |
| 17 | local persist = require("luarocks.core.persist") | 17 | local persist = require("luarocks.core.persist") |
| 18 | local sysdetect = require("luarocks.core.sysdetect") | ||
| 18 | 19 | ||
| 19 | -------------------------------------------------------------------------------- | 20 | -------------------------------------------------------------------------------- |
| 20 | 21 | ||
| @@ -151,22 +152,23 @@ do | |||
| 151 | end | 152 | end |
| 152 | end | 153 | end |
| 153 | 154 | ||
| 155 | local platform_sets = { | ||
| 156 | freebsd = { unix = true, bsd = true, freebsd = true }, | ||
| 157 | openbsd = { unix = true, bsd = true, openbsd = true }, | ||
| 158 | solaris = { unix = true, solaris = true }, | ||
| 159 | windows = { windows = true, win32 = true }, | ||
| 160 | cygwin = { unix = true, cygwin = true }, | ||
| 161 | macosx = { unix = true, bsd = true, macosx = true, macos = true }, | ||
| 162 | netbsd = { unix = true, bsd = true, netbsd = true }, | ||
| 163 | haiku = { unix = true, haiku = true }, | ||
| 164 | linux = { unix = true, linux = true }, | ||
| 165 | mingw = { windows = true, win32 = true, mingw32 = true, mingw = true }, | ||
| 166 | msys = { unix = true, cygwin = true, msys = true }, | ||
| 167 | } | ||
| 168 | |||
| 154 | local function make_platforms(system) | 169 | local function make_platforms(system) |
| 155 | if system then | 170 | -- fallback to Unix in unknown systems |
| 156 | if system == "Linux" then return { unix = true, linux = true } | 171 | return platform_sets[system] or { unix = true } |
| 157 | elseif system == "FreeBSD" then return { unix = true, bsd = true, freebsd = true } | ||
| 158 | elseif system == "OpenBSD" then return { unix = true, bsd = true, openbsd = true } | ||
| 159 | elseif system == "NetBSD" then return { unix = true, bsd = true, netbsd = true } | ||
| 160 | elseif system == "Darwin" then return { unix = true, bsd = true, macosx = true, macos = true } | ||
| 161 | elseif system == "SunOS" then return { unix = true, solaris = true } | ||
| 162 | elseif system == "Haiku" then return { unix = true, haiku = true } | ||
| 163 | elseif system:match("^CYGWIN") then return { unix = true, cygwin = true } | ||
| 164 | elseif system:match("^MSYS") then return { unix = true, cygwin = true, msys = true } | ||
| 165 | elseif system:match("^Windows") then return { windows = true, win32 = true } | ||
| 166 | elseif system:match("^MINGW") then return { windows = true, win32 = true, mingw32 = true, mingw = true } | ||
| 167 | end | ||
| 168 | end | ||
| 169 | return { unix = true } -- fallback to Unix in unknown systems | ||
| 170 | end | 172 | end |
| 171 | 173 | ||
| 172 | -------------------------------------------------------------------------------- | 174 | -------------------------------------------------------------------------------- |
| @@ -593,29 +595,27 @@ function cfg.init(lua_data, project_dir, warning) | |||
| 593 | -- A proper build of LuaRocks will hardcode the system | 595 | -- A proper build of LuaRocks will hardcode the system |
| 594 | -- and proc values with hardcoded.SYSTEM and hardcoded.PROCESSOR. | 596 | -- and proc values with hardcoded.SYSTEM and hardcoded.PROCESSOR. |
| 595 | -- If that is not available, we try to identify the system. | 597 | -- If that is not available, we try to identify the system. |
| 596 | local system = hardcoded.SYSTEM | 598 | local system, processor = sysdetect.detect() |
| 597 | local processor = hardcoded.PROCESSOR | 599 | if hardcoded.SYSTEM then |
| 598 | if is_windows then | 600 | system = hardcoded.SYSTEM |
| 599 | if not system then | 601 | end |
| 600 | if os.getenv("VCINSTALLDIR") then | 602 | if hardcoded.PROCESSOR then |
| 601 | -- running from the Development Command prompt for VS 2017 | 603 | processor = hardcoded.PROCESSOR |
| 602 | system = "Windows" | 604 | end |
| 605 | |||
| 606 | if system == "windows" then | ||
| 607 | if os.getenv("VCINSTALLDIR") then | ||
| 608 | -- running from the Development Command prompt for VS 2017 | ||
| 609 | system = "windows" | ||
| 610 | else | ||
| 611 | local fd = io.open("/bin/sh", "r") | ||
| 612 | if fd then | ||
| 613 | fd:close() | ||
| 614 | system = "msys" | ||
| 603 | else | 615 | else |
| 604 | system = "MINGW" | 616 | system = "mingw" |
| 605 | end | ||
| 606 | end | ||
| 607 | if not processor then | ||
| 608 | local pe_parser = require("luarocks.fs.win32.pe-parser") | ||
| 609 | local err | ||
| 610 | local lua_exe = lua_bindir .. "\\" .. lua_interpreter | ||
| 611 | processor, err = pe_parser.get_architecture(lua_exe) | ||
| 612 | if err then | ||
| 613 | processor = "x86" | ||
| 614 | end | 617 | end |
| 615 | end | 618 | end |
| 616 | else | ||
| 617 | system = system or util.popen_read("uname -s") | ||
| 618 | processor = processor or util.popen_read("uname -m") | ||
| 619 | end | 619 | end |
| 620 | 620 | ||
| 621 | cfg.target_cpu = processor | 621 | cfg.target_cpu = processor |
diff --git a/src/luarocks/core/sysdetect.lua b/src/luarocks/core/sysdetect.lua new file mode 100644 index 00000000..bd5139b7 --- /dev/null +++ b/src/luarocks/core/sysdetect.lua | |||
| @@ -0,0 +1,407 @@ | |||
| 1 | -- Detect the operating system and architecture without forking a subprocess. | ||
| 2 | -- | ||
| 3 | -- We are not going for exhaustive list of every historical system here, | ||
| 4 | -- but aiming to cover every platform where LuaRocks is known to run. | ||
| 5 | -- If your system is not detected, patches are welcome! | ||
| 6 | |||
| 7 | local sysdetect = {} | ||
| 8 | |||
| 9 | local function hex(s) | ||
| 10 | return s:gsub("$(..)", function(x) | ||
| 11 | return string.char(tonumber(x, 16)) | ||
| 12 | end) | ||
| 13 | end | ||
| 14 | |||
| 15 | local function read_int8(fd) | ||
| 16 | if io.type(fd) == "closed file" then | ||
| 17 | return nil | ||
| 18 | end | ||
| 19 | local s = fd:read(1) | ||
| 20 | if not s then | ||
| 21 | fd:close() | ||
| 22 | return nil | ||
| 23 | end | ||
| 24 | return s:byte() | ||
| 25 | end | ||
| 26 | |||
| 27 | local LITTLE = 1 | ||
| 28 | -- local BIG = 2 | ||
| 29 | |||
| 30 | local function bytes2number(s, endian) | ||
| 31 | local r = 0 | ||
| 32 | if endian == LITTLE then | ||
| 33 | for i = #s, 1, -1 do | ||
| 34 | r = r*256 + s:byte(i,i) | ||
| 35 | end | ||
| 36 | else | ||
| 37 | for i = 1, #s do | ||
| 38 | r = r*256 + s:byte(i,i) | ||
| 39 | end | ||
| 40 | end | ||
| 41 | return r | ||
| 42 | end | ||
| 43 | |||
| 44 | local function read(fd, bytes, endian) | ||
| 45 | if io.type(fd) == "closed file" then | ||
| 46 | return nil | ||
| 47 | end | ||
| 48 | local s = fd:read(bytes) | ||
| 49 | if not s | ||
| 50 | then fd:close() | ||
| 51 | return nil | ||
| 52 | end | ||
| 53 | return bytes2number(s, endian) | ||
| 54 | end | ||
| 55 | |||
| 56 | local function read_int32le(fd) | ||
| 57 | return read(fd, 4, LITTLE) | ||
| 58 | end | ||
| 59 | |||
| 60 | -------------------------------------------------------------------------------- | ||
| 61 | -- @section ELF | ||
| 62 | -------------------------------------------------------------------------------- | ||
| 63 | |||
| 64 | local e_osabi = { | ||
| 65 | [0x00] = "sysv", | ||
| 66 | [0x01] = "hpux", | ||
| 67 | [0x02] = "netbsd", | ||
| 68 | [0x03] = "linux", | ||
| 69 | [0x04] = "hurd", | ||
| 70 | [0x06] = "solaris", | ||
| 71 | [0x07] = "aix", | ||
| 72 | [0x08] = "irix", | ||
| 73 | [0x09] = "freebsd", | ||
| 74 | [0x0c] = "openbsd", | ||
| 75 | } | ||
| 76 | |||
| 77 | local e_machines = { | ||
| 78 | [0x02] = "sparc", | ||
| 79 | [0x03] = "x86", | ||
| 80 | [0x08] = "mips", | ||
| 81 | [0x0f] = "hppa", | ||
| 82 | [0x12] = "sparcv8", | ||
| 83 | [0x14] = "ppc", | ||
| 84 | [0x15] = "ppc64", | ||
| 85 | [0x16] = "s390", | ||
| 86 | [0x28] = "arm", | ||
| 87 | [0x2a] = "superh", | ||
| 88 | [0x2b] = "sparcv9", | ||
| 89 | [0x32] = "ia_64", | ||
| 90 | [0x3E] = "x86_64", | ||
| 91 | [0xB6] = "alpha", | ||
| 92 | [0xB7] = "aarch64", | ||
| 93 | [0xF3] = "riscv64", | ||
| 94 | [0x9026] = "alpha", | ||
| 95 | } | ||
| 96 | |||
| 97 | local SHT_NOTE = 7 | ||
| 98 | |||
| 99 | local function read_elf_section_headers(fd, hdr) | ||
| 100 | local endian = hdr.endian | ||
| 101 | local word = hdr.word | ||
| 102 | |||
| 103 | local strtab_offset | ||
| 104 | local sections = {} | ||
| 105 | for i = 0, hdr.e_shnum - 1 do | ||
| 106 | fd:seek("set", hdr.e_shoff + (i * hdr.e_shentsize)) | ||
| 107 | local section = {} | ||
| 108 | section.sh_name_off = read(fd, 4, endian) | ||
| 109 | section.sh_type = read(fd, 4, endian) | ||
| 110 | section.sh_flags = read(fd, word, endian) | ||
| 111 | section.sh_addr = read(fd, word, endian) | ||
| 112 | section.sh_offset = read(fd, word, endian) | ||
| 113 | section.sh_size = read(fd, word, endian) | ||
| 114 | section.sh_link = read(fd, 4, endian) | ||
| 115 | section.sh_info = read(fd, 4, endian) | ||
| 116 | if section.sh_type == SHT_NOTE then | ||
| 117 | fd:seek("set", section.sh_offset) | ||
| 118 | section.namesz = read(fd, 4, endian) | ||
| 119 | section.descsz = read(fd, 4, endian) | ||
| 120 | section.type = read(fd, 4, endian) | ||
| 121 | section.namedata = fd:read(section.namesz):gsub("%z.*", "") | ||
| 122 | section.descdata = fd:read(section.descsz) | ||
| 123 | elseif i == hdr.e_shstrndx then | ||
| 124 | strtab_offset = section.sh_offset | ||
| 125 | end | ||
| 126 | table.insert(sections, section) | ||
| 127 | end | ||
| 128 | if strtab_offset then | ||
| 129 | for _, section in ipairs(sections) do | ||
| 130 | fd:seek("set", strtab_offset + section.sh_name_off) | ||
| 131 | section.name = fd:read(32):gsub("%z.*", "") | ||
| 132 | sections[section.name] = section | ||
| 133 | end | ||
| 134 | end | ||
| 135 | return sections | ||
| 136 | end | ||
| 137 | |||
| 138 | local function detect_elf_system(fd, hdr, sections) | ||
| 139 | local system = e_osabi[hdr.osabi] | ||
| 140 | local endian = hdr.endian | ||
| 141 | |||
| 142 | if system == "sysv" then | ||
| 143 | local abitag = sections[".note.ABI-tag"] | ||
| 144 | if abitag then | ||
| 145 | if abitag.namedata == "GNU" and abitag.type == 1 | ||
| 146 | and abitag.descdata:sub(0, 4) == "\0\0\0\0" then | ||
| 147 | return "linux" | ||
| 148 | end | ||
| 149 | elseif sections[".SUNW_version"] | ||
| 150 | or sections[".SUNW_signature"] then | ||
| 151 | return "solaris" | ||
| 152 | elseif sections[".note.netbsd.ident"] then | ||
| 153 | return "netbsd" | ||
| 154 | elseif sections[".note.openbsd.ident"] then | ||
| 155 | return "openbsd" | ||
| 156 | end | ||
| 157 | |||
| 158 | local gnu_version_r = sections[".gnu.version_r"] | ||
| 159 | if gnu_version_r then | ||
| 160 | |||
| 161 | local dynstr = sections[".dynstr"].sh_offset | ||
| 162 | |||
| 163 | local idx = 0 | ||
| 164 | for _ = 0, gnu_version_r.sh_info - 1 do | ||
| 165 | fd:seek("set", gnu_version_r.sh_offset + idx) | ||
| 166 | assert(read(fd, 2, endian)) -- vn_version | ||
| 167 | local vn_cnt = read(fd, 2, endian) | ||
| 168 | local vn_file = read(fd, 4, endian) | ||
| 169 | local vn_next = read(fd, 2, endian) | ||
| 170 | |||
| 171 | fd:seek("set", dynstr + vn_file) | ||
| 172 | local libname = fd:read(64):gsub("%z.*", "") | ||
| 173 | |||
| 174 | if hdr.e_type == 0x03 and libname == "libroot.so" then | ||
| 175 | return "haiku" | ||
| 176 | elseif libname:match("linux") then | ||
| 177 | return "linux" | ||
| 178 | end | ||
| 179 | |||
| 180 | idx = idx + (vn_next * (vn_cnt + 1)) | ||
| 181 | end | ||
| 182 | end | ||
| 183 | end | ||
| 184 | |||
| 185 | return system | ||
| 186 | end | ||
| 187 | |||
| 188 | local function read_elf_header(fd) | ||
| 189 | local hdr = {} | ||
| 190 | |||
| 191 | hdr.bits = read_int8(fd) | ||
| 192 | hdr.endian = read_int8(fd) | ||
| 193 | hdr.elf_version = read_int8(fd) | ||
| 194 | if hdr.elf_version ~= 1 then | ||
| 195 | return nil | ||
| 196 | end | ||
| 197 | hdr.osabi = read_int8(fd) | ||
| 198 | if not hdr.osabi then | ||
| 199 | return nil | ||
| 200 | end | ||
| 201 | |||
| 202 | local endian = hdr.endian | ||
| 203 | fd:seek("set", 0x10) | ||
| 204 | hdr.e_type = read(fd, 2, endian) | ||
| 205 | local machine = read(fd, 2, endian) | ||
| 206 | local processor = e_machines[machine] or "unknown" | ||
| 207 | if endian == 1 and processor == "ppc64" then | ||
| 208 | processor = "ppc64le" | ||
| 209 | end | ||
| 210 | |||
| 211 | local elfversion = read(fd, 4, endian) | ||
| 212 | if elfversion ~= 1 then | ||
| 213 | return nil | ||
| 214 | end | ||
| 215 | |||
| 216 | local word = (hdr.bits == 1) and 4 or 8 | ||
| 217 | hdr.word = word | ||
| 218 | |||
| 219 | hdr.e_entry = read(fd, word, endian) | ||
| 220 | hdr.e_phoff = read(fd, word, endian) | ||
| 221 | hdr.e_shoff = read(fd, word, endian) | ||
| 222 | hdr.e_flags = read(fd, 4, endian) | ||
| 223 | hdr.e_ehsize = read(fd, 2, endian) | ||
| 224 | hdr.e_phentsize = read(fd, 2, endian) | ||
| 225 | hdr.e_phnum = read(fd, 2, endian) | ||
| 226 | hdr.e_shentsize = read(fd, 2, endian) | ||
| 227 | hdr.e_shnum = read(fd, 2, endian) | ||
| 228 | hdr.e_shstrndx = read(fd, 2, endian) | ||
| 229 | |||
| 230 | return hdr, processor | ||
| 231 | end | ||
| 232 | |||
| 233 | local function detect_elf(fd) | ||
| 234 | local hdr, processor = read_elf_header(fd) | ||
| 235 | if not hdr then | ||
| 236 | return nil | ||
| 237 | end | ||
| 238 | local sections = read_elf_section_headers(fd, hdr) | ||
| 239 | local system = detect_elf_system(fd, hdr, sections) | ||
| 240 | return system, processor | ||
| 241 | end | ||
| 242 | |||
| 243 | -------------------------------------------------------------------------------- | ||
| 244 | -- @section Mach Objects (Apple) | ||
| 245 | -------------------------------------------------------------------------------- | ||
| 246 | |||
| 247 | local mach_l64 = { | ||
| 248 | [7] = "x86_64", | ||
| 249 | [12] = "aarch64", | ||
| 250 | } | ||
| 251 | |||
| 252 | local mach_b64 = { | ||
| 253 | [0] = "ppc64", | ||
| 254 | } | ||
| 255 | |||
| 256 | local mach_l32 = { | ||
| 257 | [7] = "x86", | ||
| 258 | [12] = "arm", | ||
| 259 | } | ||
| 260 | |||
| 261 | local mach_b32 = { | ||
| 262 | [0] = "ppc", | ||
| 263 | } | ||
| 264 | |||
| 265 | local function detect_mach(magic, fd) | ||
| 266 | if not magic then | ||
| 267 | return nil | ||
| 268 | end | ||
| 269 | |||
| 270 | if magic == hex("$CA$FE$BA$BE") then | ||
| 271 | -- fat binary, go for the first one | ||
| 272 | fd:seek("set", 0x12) | ||
| 273 | local offs = read_int8(fd) | ||
| 274 | if not offs then | ||
| 275 | return nil | ||
| 276 | end | ||
| 277 | fd:seek("set", offs * 256) | ||
| 278 | magic = fd:read(4) | ||
| 279 | return detect_mach(magic, fd) | ||
| 280 | end | ||
| 281 | |||
| 282 | local cputype = read_int8(fd) | ||
| 283 | |||
| 284 | if magic == hex("$CF$FA$ED$FE") then | ||
| 285 | return "macosx", mach_l64[cputype] or "unknown" | ||
| 286 | elseif magic == hex("$FE$ED$CF$FA") then | ||
| 287 | return "macosx", mach_b64[cputype] or "unknown" | ||
| 288 | elseif magic == hex("$CE$FA$ED$FE") then | ||
| 289 | return "macosx", mach_l32[cputype] or "unknown" | ||
| 290 | elseif magic == hex("$FE$ED$FA$CE") then | ||
| 291 | return "macosx", mach_b32[cputype] or "unknown" | ||
| 292 | end | ||
| 293 | end | ||
| 294 | |||
| 295 | -------------------------------------------------------------------------------- | ||
| 296 | -- @section PE (Windows) | ||
| 297 | -------------------------------------------------------------------------------- | ||
| 298 | |||
| 299 | local pe_machine = { | ||
| 300 | [0x8664] = "x86_64", | ||
| 301 | [0x01c0] = "arm", | ||
| 302 | [0x01c4] = "armv7l", | ||
| 303 | [0xaa64] = "arm64", | ||
| 304 | [0x014c] = "x86", | ||
| 305 | } | ||
| 306 | |||
| 307 | local function detect_pe(fd) | ||
| 308 | fd:seek("set", 60) -- position of PE header position | ||
| 309 | local peoffset = read_int32le(fd) -- read position of PE header | ||
| 310 | if not peoffset then | ||
| 311 | return nil | ||
| 312 | end | ||
| 313 | local system = "windows" | ||
| 314 | fd:seek("set", peoffset + 4) -- move to position of Machine section | ||
| 315 | local machine = read(fd, 2, LITTLE) | ||
| 316 | local processor = pe_machine[machine] | ||
| 317 | |||
| 318 | local rdata_pos = fd:read(736):match(".rdata%z%z............(....)") | ||
| 319 | if rdata_pos then | ||
| 320 | rdata_pos = bytes2number(rdata_pos, LITTLE) | ||
| 321 | fd:seek("set", rdata_pos) | ||
| 322 | local data = fd:read(512) | ||
| 323 | if data:match("cyggcc") then | ||
| 324 | system = "cygwin" | ||
| 325 | end | ||
| 326 | end | ||
| 327 | |||
| 328 | return system, processor or "unknown" | ||
| 329 | end | ||
| 330 | |||
| 331 | -------------------------------------------------------------------------------- | ||
| 332 | -- @section API | ||
| 333 | -------------------------------------------------------------------------------- | ||
| 334 | |||
| 335 | function sysdetect.detect_file(file) | ||
| 336 | assert(type(file) == "string") | ||
| 337 | local fd = io.open(file, "rb") | ||
| 338 | if not fd then | ||
| 339 | return nil | ||
| 340 | end | ||
| 341 | local magic = fd:read(4) | ||
| 342 | if magic == hex("$7FELF") then | ||
| 343 | return detect_elf(fd) | ||
| 344 | end | ||
| 345 | if magic == hex("MZ$90$00") then | ||
| 346 | return detect_pe(fd) | ||
| 347 | end | ||
| 348 | return detect_mach(magic, fd) | ||
| 349 | end | ||
| 350 | |||
| 351 | local cache_system | ||
| 352 | local cache_processor | ||
| 353 | |||
| 354 | function sysdetect.detect(input_file) | ||
| 355 | local dirsep = package.config:sub(1,1) | ||
| 356 | local files | ||
| 357 | |||
| 358 | if input_file then | ||
| 359 | files = { input_file } | ||
| 360 | else | ||
| 361 | if cache_system then | ||
| 362 | return cache_system, cache_processor | ||
| 363 | end | ||
| 364 | |||
| 365 | local PATHsep | ||
| 366 | local interp = arg and arg[-1] | ||
| 367 | if dirsep == "/" then | ||
| 368 | -- Unix | ||
| 369 | files = { | ||
| 370 | "/bin/sh", -- Unix: well-known POSIX path | ||
| 371 | "/proc/self/exe", -- Linux: this should always have a working binary | ||
| 372 | } | ||
| 373 | PATHsep = ":" | ||
| 374 | else | ||
| 375 | -- Windows | ||
| 376 | local systemroot = os.getenv("SystemRoot") | ||
| 377 | files = { | ||
| 378 | systemroot .. "\\system32\\notepad.exe", -- well-known Windows path | ||
| 379 | systemroot .. "\\explorer.exe", -- well-known Windows path | ||
| 380 | } | ||
| 381 | if interp and not interp:lower():match("exe$") then | ||
| 382 | interp = interp .. ".exe" | ||
| 383 | end | ||
| 384 | PATHsep = ";" | ||
| 385 | end | ||
| 386 | if interp then | ||
| 387 | if interp:match(dirsep) then | ||
| 388 | -- interpreter path is absolute | ||
| 389 | table.insert(files, interp) | ||
| 390 | else | ||
| 391 | for d in os.getenv("PATH"):gmatch("[^"..PATHsep.."]+") do | ||
| 392 | table.insert(files, d .. dirsep .. interp) | ||
| 393 | end | ||
| 394 | end | ||
| 395 | end | ||
| 396 | end | ||
| 397 | for _, f in ipairs(files) do | ||
| 398 | local system, processor = sysdetect.detect_file(f) | ||
| 399 | if system then | ||
| 400 | cache_system = system | ||
| 401 | cache_processor = processor | ||
| 402 | return system, processor | ||
| 403 | end | ||
| 404 | end | ||
| 405 | end | ||
| 406 | |||
| 407 | return sysdetect | ||
