mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-19 02:27:10 +03:00
Implement getting cmdline of process on macOS as well
This commit is contained in:
parent
5485436ea1
commit
0dd3334811
@ -9,21 +9,23 @@
|
||||
|
||||
from .constants import is_macos, shell_path, terminfo_dir
|
||||
|
||||
if is_macos:
|
||||
from kitty.fast_data_types import cmdline_of_process as _cmdl, cwd_of_process as _cwd
|
||||
|
||||
def cwd_of_process(pid):
|
||||
if is_macos:
|
||||
from kitty.fast_data_types import cwd_of_process
|
||||
ans = cwd_of_process(pid)
|
||||
else:
|
||||
def cmdline_of_process(pid):
|
||||
return _cmdl(pid)
|
||||
|
||||
def cwd_of_process(pid):
|
||||
return os.path.realpath(_cwd(pid))
|
||||
|
||||
else:
|
||||
|
||||
def cmdline_of_process(pid):
|
||||
return list(filter(None, open('/proc/{}/cmdline'.format(pid), 'rb').read().decode('utf-8').split('\0')))
|
||||
|
||||
def cwd_of_process(pid):
|
||||
ans = '/proc/{}/cwd'.format(pid)
|
||||
return os.path.realpath(ans)
|
||||
|
||||
|
||||
def cmdline_of_process(pid):
|
||||
if is_macos:
|
||||
# TODO: macOS implementation, see DarwinProcess.c in htop for inspiration
|
||||
raise NotImplementedError()
|
||||
return list(filter(None, open('/proc/{}/cmdline'.format(pid), 'rb').read().decode('utf-8').split('\0')))
|
||||
return os.path.realpath(ans)
|
||||
|
||||
|
||||
def remove_cloexec(fd):
|
||||
|
@ -12,8 +12,6 @@
|
||||
#include <AvailabilityMacros.h>
|
||||
// Needed for _NSGetProgname
|
||||
#include <crt_externs.h>
|
||||
typedef void* rusage_info_t; // needed for libproc.h
|
||||
#include <libproc.h>
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101200)
|
||||
#define NSWindowStyleMaskResizable NSResizableWindowMask
|
||||
@ -234,15 +232,6 @@ + (GlobalMenuTarget *) shared_instance
|
||||
return Py_BuildValue("s", [locale UTF8String]);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
cwd_of_process(PyObject *self UNUSED, PyObject *pid_) {
|
||||
long pid = PyLong_AsLong(pid_);
|
||||
struct proc_vnodepathinfo vpi;
|
||||
int ret = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));
|
||||
if (ret < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; }
|
||||
return PyUnicode_FromString(vpi.pvi_cdir.vip_path);
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_set_hide_from_tasks(void) {
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
|
||||
@ -276,7 +265,6 @@ + (GlobalMenuTarget *) shared_instance
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
||||
{"cwd_of_process", (PyCFunction)cwd_of_process, METH_O, ""},
|
||||
{"cocoa_set_new_window_trigger", (PyCFunction)cocoa_set_new_window_trigger, METH_VARARGS, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
@ -215,6 +215,7 @@ extern bool init_png_reader(PyObject *module);
|
||||
#ifdef __APPLE__
|
||||
extern int init_CoreText(PyObject *);
|
||||
extern bool init_cocoa(PyObject *module);
|
||||
extern bool init_macos_process_info(PyObject *module);
|
||||
#else
|
||||
extern bool init_freetype_library(PyObject*);
|
||||
#endif
|
||||
@ -249,6 +250,7 @@ PyInit_fast_data_types(void) {
|
||||
if (!init_kittens(m)) return NULL;
|
||||
if (!init_png_reader(m)) return NULL;
|
||||
#ifdef __APPLE__
|
||||
if (!init_macos_process_info(m)) return NULL;
|
||||
if (!init_CoreText(m)) return NULL;
|
||||
if (!init_cocoa(m)) return NULL;
|
||||
#else
|
||||
|
147
kitty/macos_process_info.c
Normal file
147
kitty/macos_process_info.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* macos_process_info.c
|
||||
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "data-types.h"
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
typedef void* rusage_info_t; // needed for libproc.h
|
||||
#include <libproc.h>
|
||||
|
||||
static PyObject*
|
||||
cwd_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; }
|
||||
struct proc_vnodepathinfo vpi;
|
||||
int ret = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));
|
||||
if (ret < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; }
|
||||
return PyUnicode_FromString(vpi.pvi_cdir.vip_path);
|
||||
}
|
||||
|
||||
// Read the maximum argument size for processes
|
||||
static inline int
|
||||
get_argmax() {
|
||||
int argmax;
|
||||
int mib[] = { CTL_KERN, KERN_ARGMAX };
|
||||
size_t size = sizeof(argmax);
|
||||
|
||||
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0)
|
||||
return argmax;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
cmdline_of_process(PyObject *self UNUSED, PyObject *pid_) {
|
||||
// Taken from psutil, with thanks (BSD 3-clause license)
|
||||
int mib[3];
|
||||
int nargs;
|
||||
size_t len;
|
||||
char *procargs = NULL;
|
||||
char *arg_ptr;
|
||||
char *arg_end;
|
||||
char *curr_arg;
|
||||
size_t argmax;
|
||||
|
||||
PyObject *py_arg = NULL;
|
||||
PyObject *py_retlist = NULL;
|
||||
if (!PyLong_Check(pid_)) { PyErr_SetString(PyExc_TypeError, "pid must be an int"); goto error; }
|
||||
long pid = PyLong_AsLong(pid_);
|
||||
if (pid < 0) { PyErr_SetString(PyExc_TypeError, "pid cannot be negative"); goto error; }
|
||||
|
||||
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
|
||||
if (pid == 0)
|
||||
return Py_BuildValue("[]");
|
||||
|
||||
// read argmax and allocate memory for argument space.
|
||||
argmax = get_argmax();
|
||||
if (!argmax) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
procargs = (char *)malloc(argmax);
|
||||
if (NULL == procargs) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// read argument space
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = (pid_t)pid;
|
||||
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
||||
// In case of zombie process or non-existant process we'll get EINVAL.
|
||||
if (errno == EINVAL)
|
||||
PyErr_Format(PyExc_ValueError, "process with pid %ld either does not exist or is a zombie", pid);
|
||||
else
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
arg_end = &procargs[argmax];
|
||||
// copy the number of arguments to nargs
|
||||
memcpy(&nargs, procargs, sizeof(nargs));
|
||||
|
||||
arg_ptr = procargs + sizeof(nargs);
|
||||
len = strlen(arg_ptr);
|
||||
arg_ptr += len + 1;
|
||||
|
||||
if (arg_ptr == arg_end) {
|
||||
free(procargs);
|
||||
return Py_BuildValue("[]");
|
||||
}
|
||||
|
||||
// skip ahead to the first argument
|
||||
for (; arg_ptr < arg_end; arg_ptr++) {
|
||||
if (*arg_ptr != '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
// iterate through arguments
|
||||
curr_arg = arg_ptr;
|
||||
py_retlist = Py_BuildValue("[]");
|
||||
if (!py_retlist)
|
||||
goto error;
|
||||
while (arg_ptr < arg_end && nargs > 0) {
|
||||
if (*arg_ptr++ == '\0') {
|
||||
py_arg = PyUnicode_DecodeFSDefault(curr_arg);
|
||||
if (! py_arg)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_arg))
|
||||
goto error;
|
||||
Py_DECREF(py_arg);
|
||||
// iterate to next arg and decrement # of args
|
||||
curr_arg = arg_ptr;
|
||||
nargs--;
|
||||
}
|
||||
}
|
||||
|
||||
free(procargs);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_arg);
|
||||
Py_XDECREF(py_retlist);
|
||||
if (procargs != NULL)
|
||||
free(procargs);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"cwd_of_process", (PyCFunction)cwd_of_process, METH_O, ""},
|
||||
{"cmdline_of_process", (PyCFunction)cmdline_of_process, METH_O, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
init_macos_process_info(PyObject *module) {
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
return true;
|
||||
}
|
2
setup.py
2
setup.py
@ -402,7 +402,7 @@ def compile_c_extension(kenv, module, incremental, compilation_database, all_key
|
||||
def find_c_files():
|
||||
ans, headers = [], []
|
||||
d = os.path.join(base, 'kitty')
|
||||
exclude = {'fontconfig.c', 'freetype.c', 'desktop.c'} if is_macos else {'core_text.m', 'cocoa_window.m'}
|
||||
exclude = {'fontconfig.c', 'freetype.c', 'desktop.c'} if is_macos else {'core_text.m', 'cocoa_window.m', 'macos_process_info.c'}
|
||||
for x in os.listdir(d):
|
||||
ext = os.path.splitext(x)[1]
|
||||
if ext in ('.c', '.m') and os.path.basename(x) not in exclude:
|
||||
|
Loading…
Reference in New Issue
Block a user