diff options
| author | Saikari <[email protected]> | 2026-01-27 05:54:28 +0300 |
|---|---|---|
| committer | Saikari <[email protected]> | 2026-01-27 05:54:28 +0300 |
| commit | 41e460c869c15699d63f39e4fe433d88225818dc (patch) | |
| tree | 0faa42100418d0db0919c5d3a24613c5f3f130e4 | |
| parent | 6e6cf755b207fe128e6e8a534d3df15f56d9c8a4 (diff) | |
add function to find shell from parent process in Linux
| -rw-r--r-- | xmake/core/base/tty.lua | 149 |
1 files changed, 80 insertions, 69 deletions
diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 27788419b..788327d20 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -235,6 +235,84 @@ function tty.flush() return tty end +-- find the shell from the parent process (linux) +function tty._find_shell_from_parent() + if os.host() ~= "linux" or not os.isfile("/proc/self/stat") then + return + end + + local shell + local pid = os.getpid() + for i = 1, 10 do + local stat = io.readfile("/proc/" .. pid .. "/stat") + if not stat or #stat == 0 then + local tmpfile = os.tmpfile() + os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) + stat = io.readfile(tmpfile) + os.rm(tmpfile) + end + + -- find last ')' to handle "pid (comm) state ppid" + local start = stat and stat:find(")", 1, true) + while start do + local next_p = stat:find(")", start + 1, true) + if not next_p then break end + start = next_p + end + + if start then + local suffix = stat:sub(start + 1) + local fields = {} + for field in suffix:gmatch("%S+") do + table.insert(fields, field) + if #fields >= 2 then break end + end + + local ppid = tonumber(fields[2]) + if not ppid or ppid == 0 then break end + + local shell_name = nil + local shell_path = nil + if os.isfile("/proc/" .. ppid .. "/exe") then + local ok, link = pcall(os.readlink, "/proc/" .. ppid .. "/exe") + if ok and link then + shell_path = link + end + end + if not shell_path and os.isfile("/proc/" .. ppid .. "/comm") then + shell_name = io.readfile("/proc/" .. ppid .. "/comm") + if not shell_name or #shell_name == 0 then + local tmpfile = os.tmpfile() + os.runv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) + shell_name = io.readfile(tmpfile) + os.rm(tmpfile) + end + if shell_name then + shell_name = shell_name:match("^%s*(.-)%s*$") + end + end + if shell_path then + shell_name = path.filename(shell_path) + end + + if shell_name then + shell_name = shell_name:gsub("^-", "") + for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do + if shell_name == name then + shell = name + break + end + end + if shell then break end + end + pid = ppid + else + break + end + end + return shell +end + -- get shell name function tty.shell() local shell = tty._SHELL @@ -258,75 +336,8 @@ function tty.shell() end end -- try to find the shell from the parent process (linux) - if not shell and os.host() == "linux" and os.isfile("/proc/self/stat") then - local pid = os.getpid() - for i = 1, 10 do - local stat = io.readfile("/proc/" .. pid .. "/stat") - if not stat or #stat == 0 then - local tmpfile = os.tmpfile() - os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) - stat = io.readfile(tmpfile) - os.rm(tmpfile) - end - - -- find last ')' to handle "pid (comm) state ppid" - local start = stat and stat:find(")", 1, true) - while start do - local next_p = stat:find(")", start + 1, true) - if not next_p then break end - start = next_p - end - - if start then - local suffix = stat:sub(start + 1) - local fields = {} - for field in suffix:gmatch("%S+") do - table.insert(fields, field) - if #fields >= 2 then break end - end - - local ppid = tonumber(fields[2]) - if not ppid or ppid == 0 then break end - - local shell_name = nil - local shell_path = nil - if os.isfile("/proc/" .. ppid .. "/exe") then - local ok, link = pcall(os.readlink, "/proc/" .. ppid .. "/exe") - if ok and link then - shell_path = link - end - end - if not shell_path and os.isfile("/proc/" .. ppid .. "/comm") then - shell_name = io.readfile("/proc/" .. ppid .. "/comm") - if not shell_name or #shell_name == 0 then - local tmpfile = os.tmpfile() - os.runv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) - shell_name = io.readfile(tmpfile) - os.rm(tmpfile) - end - if shell_name then - shell_name = shell_name:match("^%s*(.-)%s*$") - end - end - if shell_path then - shell_name = path.filename(shell_path) - end - - if shell_name then - shell_name = shell_name:gsub("^-", "") - for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do - if shell_name == name then - shell = name - break - end - end - if shell then break end - end - pid = ppid - else - break - end - end + if not shell then + shell = tty._find_shell_from_parent() end if not shell then |
