diff options
author | alxchk <alxchk@gmail.com> | 2018-03-11 18:48:13 +0200 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2018-03-11 09:48:13 -0700 |
commit | 66edd7ade36c871a15f2cb230ae1c054f842555a (patch) | |
tree | 7c71109b266e6f18688751ee28ff12542b222047 /psutil/_psutil_sunos.c | |
parent | 2ffb0ecc5e41c5486056fcd00aca274d77858860 (diff) | |
download | psutil-66edd7ade36c871a15f2cb230ae1c054f842555a.tar.gz |
Try to extract argv[] from process address space first (#1220)
* Try to extract argv[] from process address space first
* Add comments and OOM exception
* Handle the case with empty array
Diffstat (limited to 'psutil/_psutil_sunos.c')
-rw-r--r-- | psutil/_psutil_sunos.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/psutil/_psutil_sunos.c b/psutil/_psutil_sunos.c index c6673642..4d38a342 100644 --- a/psutil/_psutil_sunos.c +++ b/psutil/_psutil_sunos.c @@ -116,6 +116,58 @@ psutil_proc_basic_info(PyObject *self, PyObject *args) { ); } +/* + * Join array of C strings to C string with delemiter dm. + * Omit empty records. + */ +static int +cstrings_array_to_string(char **joined, char ** array, size_t count, char dm) { + int i; + size_t total_length = 0; + size_t item_length = 0; + char *result = NULL; + char *last = NULL; + + if (!array || !joined) + return 0; + + for (i=0; i<count; i++) { + if (!array[i]) + continue; + + item_length = strlen(array[i]) + 1; + total_length += item_length; + } + + if (!total_length) { + return 0; + } + + result = malloc(total_length); + if (!result) { + PyErr_NoMemory(); + return -1; + } + + result[0] = '\0'; + last = result; + + for (i=0; i<count; i++) { + if (!array[i]) + continue; + + item_length = strlen(array[i]); + memcpy(last, array[i], item_length); + last[item_length] = dm; + + last += item_length + 1; + } + + result[total_length-1] = '\0'; + *joined = result; + + return total_length; +} /* * Return process name and args as a Python tuple. @@ -125,6 +177,10 @@ psutil_proc_name_and_args(PyObject *self, PyObject *args) { int pid; char path[1000]; psinfo_t info; + size_t argc; + int joined; + char **argv; + char *argv_plain; const char *procfs_path; PyObject *py_name = NULL; PyObject *py_args = NULL; @@ -139,12 +195,37 @@ psutil_proc_name_and_args(PyObject *self, PyObject *args) { py_name = PyUnicode_DecodeFSDefault(info.pr_fname); if (!py_name) goto error; - py_args = PyUnicode_DecodeFSDefault(info.pr_psargs); + + /* SunOS truncates arguments to length PRARGSZ, very likely args are truncated. + * The only way to retrieve full command line is to parse process memory */ + if (info.pr_argc && strlen(info.pr_psargs) == PRARGSZ-1) { + argv = psutil_read_raw_args(info, procfs_path, &argc); + if (argv) { + joined = cstrings_array_to_string(&argv_plain, argv, argc, ' '); + if (joined > 0) { + py_args = PyUnicode_DecodeFSDefault(argv_plain); + free(argv_plain); + } else if (joined < 0) { + goto error; + } + + psutil_free_cstrings_array(argv, argc); + } + } + + /* If we can't read process memory or can't decode the result + * then return args from /proc. */ + if (!py_args) + py_args = PyUnicode_DecodeFSDefault(info.pr_psargs); + + /* Both methods has been failed. */ if (!py_args) goto error; + py_retlist = Py_BuildValue("OO", py_name, py_args); if (!py_retlist) goto error; + Py_DECREF(py_name); Py_DECREF(py_args); return py_retlist; |