From d04bb12a0998b910b51065ed1364989bc3d9ae45 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 16 Aug 2025 17:33:00 +0530 Subject: [PATCH] Use absolute path when serializing foreground process --- kitty/child.py | 7 +++++++ kitty/fast_data_types.pyi | 2 ++ kitty/macos_process_info.c | 14 ++++++++++++++ kitty/window.py | 4 ++++ 4 files changed, 27 insertions(+) diff --git a/kitty/child.py b/kitty/child.py index 69ada6cf0..2f5a8f6ac 100644 --- a/kitty/child.py +++ b/kitty/child.py @@ -20,6 +20,7 @@ if is_macos: + from kitty.fast_data_types import abspath_of_process as _abspath_of_process from kitty.fast_data_types import cmdline_of_process as cmdline_ from kitty.fast_data_types import cwd_of_process as _cwd from kitty.fast_data_types import environ_of_process as _environ_of_process @@ -30,6 +31,9 @@ def cwd_of_process(pid: int) -> str: # anyway but we use realpath for extra safety. return os.path.realpath(_cwd(pid)) + def abspath_of_exe(pid: int) -> str: + return os.path.realpath(_abspath_of_process(pid)) + def process_group_map() -> DefaultDict[int, list[int]]: ans: DefaultDict[int, list[int]] = defaultdict(list) for pid, pgid in _process_group_map(): @@ -82,6 +86,9 @@ def process_group_map() -> DefaultDict[int, list[int]]: ans[q].append(pid) return ans + def abspath_of_exe(pid: int) -> str: + return os.path.realpath(f'/proc/{pid}/exe') + @run_once def checked_terminfo_dir() -> str | None: diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index bbd8da152..e7a0e98d8 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -383,6 +383,8 @@ def cwd_of_process(pid: int) -> str: pass +def abspath_of_process(pid: int) -> str: ... + def default_color_table() -> Tuple[int, ...]: pass diff --git a/kitty/macos_process_info.c b/kitty/macos_process_info.c index aa65a2e61..a81f6f2a4 100644 --- a/kitty/macos_process_info.c +++ b/kitty/macos_process_info.c @@ -22,6 +22,19 @@ cwd_of_process(PyObject *self UNUSED, PyObject *pid_) { return PyUnicode_FromString(vpi.pvi_cdir.vip_path); } +static PyObject* +abspath_of_process(PyObject *self UNUSED, PyObject *pid_) { + if (!PyLong_Check(pid_)) { PyErr_SetString(PyExc_TypeError, "pid must be an int"); return NULL; } + long pid = PyLong_AsLong(pid_); + if (pid < 0) { PyErr_SetString(PyExc_TypeError, "pid cannot be negative"); return NULL; } + char pathbuf[PROC_PIDPATHINFO_MAXSIZE+1]; + int ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf)); + if (ret <= 0) { + PyErr_SetFromErrno(PyExc_OSError); return NULL; + } + return PyUnicode_FromString(pathbuf); +} + // Read the maximum argument size for processes static int get_argmax(void) { @@ -272,6 +285,7 @@ error: static PyMethodDef module_methods[] = { {"cwd_of_process", (PyCFunction)cwd_of_process, METH_O, ""}, + {"abspath_of_process", (PyCFunction)abspath_of_process, METH_O, ""}, {"cmdline_of_process", (PyCFunction)cmdline_of_process, METH_O, ""}, {"environ_of_process", (PyCFunction)environ_of_process, METH_O, ""}, {"get_all_processes", (PyCFunction)get_all_processes, METH_NOARGS, ""}, diff --git a/kitty/window.py b/kitty/window.py index 2d74c7e7f..e28d036df 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -2012,6 +2012,10 @@ def as_launch_command(self, ser_opts: SaveAsSessionOptions, is_overlay: bool = F fcmd = self.child.cmdline_of_pid(pid) if fcmd: unserialize_data['cmd_at_shell_startup'] = fcmd + if not os.path.isabs(fcmd[0]): + with suppress(Exception): + from .child import abspath_of_exe + fcmd[0] = abspath_of_exe(pid) ans.insert(1, unserialize_launch_flag + json.dumps(unserialize_data)) ans.extend(cmd) return ans