/* * Return process TCP and UDP connections as a list of tuples. * References: * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0 * - /usr/include/sys/proc_info.h */ static PyObject* get_process_connections(PyObject* self, PyObject* args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer; struct proc_fdinfo *fdp_pointer; struct socket_fdinfo si; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; PyObject *laddr = NULL; PyObject *raddr = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (pid == 0) { return retList; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { goto error; } fds_pointer = malloc(pidinfo_result); pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); free(fds_pointer); if (pidinfo_result <= 0) { goto error; } iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); for (i = 0; i < iterations; i++) { errno = 0; fdp_pointer = &fds_pointer[i]; // if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si)); // --- errors checking if (nb <= 0) { if (errno == EBADF) { // let's assume socket has been closed continue; } if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); } } if (nb < sizeof(si)) { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)"); } // --- /errors checking // int fd, family, type, lport, rport; char lip[200], rip[200]; char *state; fd = (int)fdp_pointer->proc_fd; family = si.psi.soi_family; type = si.psi.soi_kind; if ((family != AF_INET) && (family != AF_INET6)) { continue; } if (type == 2) type = SOCK_STREAM; else if (type == 1) type = SOCK_DGRAM; else continue; if (errno != 0) { printf("errno 1 = %i\n", errno); return PyErr_SetFromErrno(PyExc_OSError); } if (family == AF_INET) { inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4, lip, sizeof(lip)); inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4, rip, sizeof(lip)); } else { inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6, lip, sizeof(lip)); inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6, lip, sizeof(rip)); } // check for inet_ntop failures if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); if (type == SOCK_STREAM) state = get_connection_status((int)si.psi.soi_proto.pri_tcp.tcpsi_state); else state = ""; laddr = Py_BuildValue("(si)", lip, lport); if (rport != 0) raddr = Py_BuildValue("(si)", rip, rport); else raddr = PyTuple_New(0); // --- construct python list tuple = Py_BuildValue("(iiiNNs)", fd, family, type, laddr, raddr, state); PyList_Append(retList, tuple); Py_DECREF(tuple); // --- /construct python list } } return retList; error: if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); else if (! pid_exists(pid) ) return NoSuchProcess(); else return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); }
/* * Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure * fills the structure with process information. * On success return 1, else 0 with Python exception already set. */ int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, PVOID *retBuffer) { static ULONG initialBufferSize = 0x4000; NTSTATUS status; PVOID buffer; ULONG bufferSize; PSYSTEM_PROCESS_INFORMATION process; // get NtQuerySystemInformation typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); NTQSI_PROC NtQuerySystemInformation; HINSTANCE hNtDll; hNtDll = LoadLibrary(TEXT("ntdll.dll")); NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( hNtDll, "NtQuerySystemInformation"); bufferSize = initialBufferSize; buffer = malloc(bufferSize); if (buffer == NULL) { PyErr_NoMemory(); goto error; } while (TRUE) { status = NtQuerySystemInformation(SystemProcessInformation, buffer, bufferSize, &bufferSize); if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) { free(buffer); buffer = malloc(bufferSize); if (buffer == NULL) { PyErr_NoMemory(); goto error; } } else { break; } } if (status != 0) { PyErr_Format(PyExc_RuntimeError, "NtQuerySystemInformation() failed"); goto error; } if (bufferSize <= 0x20000) { initialBufferSize = bufferSize; } process = PH_FIRST_PROCESS(buffer); do { if (process->UniqueProcessId == (HANDLE)pid) { *retProcess = process; *retBuffer = buffer; return 1; } } while ( (process = PH_NEXT_PROCESS(process)) ); NoSuchProcess(); goto error; error: FreeLibrary(hNtDll); if (buffer != NULL) free(buffer); return 0; }
/* * Return process threads */ static PyObject* get_process_threads(PyObject* self, PyObject* args) { long pid; int err, j, ret; kern_return_t kr; unsigned int info_count = TASK_BASIC_INFO_COUNT; mach_port_t task; struct task_basic_info tasks_info; thread_act_port_array_t thread_list; thread_info_data_t thinfo; thread_basic_info_t basic_info_th; mach_msg_type_number_t thread_count, thread_info_count; PyObject* retList = PyList_New(0); PyObject* pyTuple = NULL; // the argument passed should be a process id if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } // task_for_pid() requires special privileges err = task_for_pid(mach_task_self(), pid, &task); if (err != KERN_SUCCESS) { if (! pid_exists(pid) ) { return NoSuchProcess(); } return AccessDenied(); } info_count = TASK_BASIC_INFO_COUNT; err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count); if (err != KERN_SUCCESS) { // errcode 4 is "invalid argument" (access denied) if (err == 4) { return AccessDenied(); } // otherwise throw a runtime error with appropriate error code return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed"); } err = task_threads(task, &thread_list, &thread_count); if (err != KERN_SUCCESS) { return PyErr_Format(PyExc_RuntimeError, "task_threads() failed"); } for (j = 0; j < thread_count; j++) { thread_info_count = THREAD_INFO_MAX; kr = thread_info(thread_list[j], THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count); if (kr != KERN_SUCCESS) { return PyErr_Format(PyExc_RuntimeError, "thread_info() failed"); } basic_info_th = (thread_basic_info_t)thinfo; // XXX - thread_info structure does not provide any process id; // the best we can do is assigning an incremental bogus value pyTuple = Py_BuildValue("Iff", j + 1, (float)basic_info_th->user_time.microseconds / 1000000.0, (float)basic_info_th->system_time.microseconds / 1000000.0 ); PyList_Append(retList, pyTuple); Py_XDECREF(pyTuple); } ret = vm_deallocate(task, (vm_address_t)thread_list, thread_count * sizeof(int)); if (ret != KERN_SUCCESS) { printf("vm_deallocate() failed\n"); } return retList; }
/* * Return process open files as a Python tuple. * References: * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd * - /usr/include/sys/proc_info.h */ static PyObject* get_process_open_files(PyObject* self, PyObject* args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer; struct proc_fdinfo *fdp_pointer; struct vnode_fdinfowithpath vi; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { goto error; } fds_pointer = malloc(pidinfo_result); pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); free(fds_pointer); if (pidinfo_result <= 0) { goto error; } iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); for (i = 0; i < iterations; i++) { fdp_pointer = &fds_pointer[i]; // if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi)); // --- errors checking if (nb <= 0) { if ((errno == ENOENT) || (errno == EBADF)) { // no such file or directory or bad file descriptor; // let's assume the file has been closed or removed continue; } if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); } if (nb < sizeof(vi)) { return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)"); } // --- /errors checking // --- construct python list tuple = Py_BuildValue("(si)", vi.pvip.vip_path, (int)fdp_pointer->proc_fd); PyList_Append(retList, tuple); Py_DECREF(tuple); // --- /construct python list } } return retList; error: if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); else if (! pid_exists(pid) ) return NoSuchProcess(); else return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); }
/* * Return a tuple of RSS and VMS memory usage. */ static PyObject* get_memory_info(PyObject* self, PyObject* args) { long pid; int err; unsigned int info_count = TASK_BASIC_INFO_COUNT; mach_port_t task; struct task_basic_info tasks_info; vm_region_basic_info_data_64_t b_info; vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT; vm_size_t size; mach_port_t object_name; // the argument passed should be a process id if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } /* task_for_pid() requires special privileges * "This function can be called only if the process is owned by the * procmod group or if the caller is root." * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/chapter_5_section_19.html */ err = task_for_pid(mach_task_self(), pid, &task); if ( err == KERN_SUCCESS) { info_count = TASK_BASIC_INFO_COUNT; err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count); if (err != KERN_SUCCESS) { if (err == 4) { // errcode 4 is "invalid argument" (access denied) return AccessDenied(); } // otherwise throw a runtime error with appropriate error code return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed"); } /* Issue #73 http://code.google.com/p/psutil/issues/detail?id=73 * adjust the virtual memory size down to account for * shared memory that task_info.virtual_size includes w/every process */ info_count = VM_REGION_BASIC_INFO_COUNT_64; err = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info, &info_count, &object_name); if (err == KERN_SUCCESS) { if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) && tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE)) { tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE); } } } else { if (! pid_exists(pid) ) { return NoSuchProcess(); } // pid exists, so return AccessDenied error since task_for_pid() failed return AccessDenied(); } return Py_BuildValue("(ll)", tasks_info.resident_size, tasks_info.virtual_size); }
/* * Return a Python tuple (user_time, kernel_time) */ static PyObject* get_cpu_times(PyObject* self, PyObject* args) { long pid; int err; unsigned int info_count = TASK_BASIC_INFO_COUNT; task_port_t task; // = (task_port_t)NULL; time_value_t user_time, system_time; struct task_basic_info tasks_info; struct task_thread_times_info task_times; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } /* task_for_pid() requires special privileges * "This function can be called only if the process is owned by the * procmod group or if the caller is root." * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/chapter_5_section_19.html */ err = task_for_pid(mach_task_self(), pid, &task); if ( err == KERN_SUCCESS) { info_count = TASK_BASIC_INFO_COUNT; err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count); if (err != KERN_SUCCESS) { // errcode 4 is "invalid argument" (access denied) if (err == 4) { return AccessDenied(); } // otherwise throw a runtime error with appropriate error code return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed"); } info_count = TASK_THREAD_TIMES_INFO_COUNT; err = task_info(task, TASK_THREAD_TIMES_INFO, (task_info_t)&task_times, &info_count); if (err != KERN_SUCCESS) { // errcode 4 is "invalid argument" (access denied) if (err == 4) { return AccessDenied(); } return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed"); } } else { // task_for_pid failed if (! pid_exists(pid) ) { return NoSuchProcess(); } // pid exists, so return AccessDenied error since task_for_pid() failed return AccessDenied(); } float user_t = -1.0; float sys_t = -1.0; user_time = tasks_info.user_time; system_time = tasks_info.system_time; time_value_add(&user_time, &task_times.user_time); time_value_add(&system_time, &task_times.system_time); user_t = (float)user_time.seconds + ((float)user_time.microseconds / 1000000.0); sys_t = (float)system_time.seconds + ((float)system_time.microseconds / 1000000.0); return Py_BuildValue("(dd)", user_t, sys_t); }
PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { // Retrieves all threads used by process returning a list of tuples // including thread id, user time and system time. // Thanks to Robert N. M. Watson: // http://fxr.googlebit.com/source/usr.bin/procstat/ // procstat_threads.c?v=8-CURRENT long pid; int mib[4]; struct kinfo_proc *kip = NULL; struct kinfo_proc *kipp = NULL; int error; unsigned int i; size_t size; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; // we need to re-query for thread information, so don't use *kipp mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD; mib[3] = pid; size = 0; error = sysctl(mib, 4, NULL, &size, NULL, 0); if (error == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if (size == 0) { NoSuchProcess(); goto error; } kip = malloc(size); if (kip == NULL) { PyErr_NoMemory(); goto error; } error = sysctl(mib, 4, kip, &size, NULL, 0); if (error == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if (size == 0) { NoSuchProcess(); goto error; } for (i = 0; i < size / sizeof(*kipp); i++) { kipp = &kip[i]; py_tuple = Py_BuildValue("Idd", kipp->ki_tid, PSUTIL_TV2DOUBLE(kipp->ki_rusage.ru_utime), PSUTIL_TV2DOUBLE(kipp->ki_rusage.ru_stime)); if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(kip); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (kip != NULL) free(kip); return NULL; }
/* * Retrieves all threads used by process returning a list of tuples * including thread id, user time and system time. * Thanks to Robert N. M. Watson: * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_threads.c?v=8-CURRENT */ static PyObject* get_process_threads(PyObject* self, PyObject* args) { long pid; int mib[4]; struct kinfo_proc *kip; struct kinfo_proc *kipp; int error; unsigned int i; size_t size; PyObject* retList = PyList_New(0); PyObject* pyTuple = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } /* * We need to re-query for thread information, so don't use *kipp. */ mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; size = 0; error = sysctl(mib, 4, NULL, &size, NULL, 0); if (error == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (size == 0) { return NoSuchProcess(); } kip = malloc(size); if (kip == NULL) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } error = sysctl(mib, 4, kip, &size, NULL, 0); if (error == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (size == 0) { return NoSuchProcess(); } for (i = 0; i < size / sizeof(*kipp); i++) { kipp = &kip[i]; pyTuple = Py_BuildValue("Idd", 0, // FIXME thread id? kipp->p_uutime_sec, kipp->p_ustime_sec ); PyList_Append(retList, pyTuple); Py_XDECREF(pyTuple); } free(kip); return retList; }
PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { pid_t pid; int mib[5]; int i, nlwps; ssize_t st; size_t size; struct kinfo_lwp *kl = NULL; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; mib[0] = CTL_KERN; mib[1] = KERN_LWP; mib[2] = pid; mib[3] = sizeof(struct kinfo_lwp); mib[4] = 0; st = sysctl(mib, 5, NULL, &size, NULL, 0); if (st == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if (size == 0) { NoSuchProcess(""); goto error; } mib[4] = size / sizeof(size_t); kl = malloc(size); if (kl == NULL) { PyErr_NoMemory(); goto error; } st = sysctl(mib, 5, kl, &size, NULL, 0); if (st == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if (size == 0) { NoSuchProcess(""); goto error; } nlwps = (int)(size / sizeof(struct kinfo_lwp)); for (i = 0; i < nlwps; i++) { py_tuple = Py_BuildValue("idd", (&kl[i])->l_lid, PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime), PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime)); if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(kl); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (kl != NULL) free(kl); return NULL; }