diff options
| author | wiggin15 <wiggin15@yahoo.com> | 2017-09-26 14:52:42 +0300 |
|---|---|---|
| committer | Giampaolo Rodola <g.rodola@gmail.com> | 2017-09-26 19:52:42 +0800 |
| commit | 1ebe625e5aa21b33e9de5652c305d1d0a2147059 (patch) | |
| tree | 79448f6cc3df6d892c2fe22ead726b2a94a52111 /psutil/arch/aix | |
| parent | 730e0fbba6a2ef4a01a5a67759e15dad5613d3a9 (diff) | |
| download | psutil-1ebe625e5aa21b33e9de5652c305d1d0a2147059.tar.gz | |
AIX support (#1123)
* AIX support
* AIX support
* AIX support
* AIX support - use get_procfs_path() instead of /proc
* AIX support - group sections like in other modules
* AIX support
* AIX support
* AIX support
* AIX support - remove unnecessary dict copy
Diffstat (limited to 'psutil/arch/aix')
| -rw-r--r-- | psutil/arch/aix/ifaddrs.c | 149 | ||||
| -rw-r--r-- | psutil/arch/aix/ifaddrs.h | 35 | ||||
| -rw-r--r-- | psutil/arch/aix/net_connections.c | 346 | ||||
| -rw-r--r-- | psutil/arch/aix/net_connections.h | 10 | ||||
| -rw-r--r-- | psutil/arch/aix/net_kernel_structs.h | 110 |
5 files changed, 650 insertions, 0 deletions
diff --git a/psutil/arch/aix/ifaddrs.c b/psutil/arch/aix/ifaddrs.c new file mode 100644 index 00000000..1a819365 --- /dev/null +++ b/psutil/arch/aix/ifaddrs.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017, Arnon Yaari + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/*! Based on code from + https://lists.samba.org/archive/samba-technical/2009-February/063079.html +!*/ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "ifaddrs.h" + +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define SIZE(p) MAX((p).sa_len,sizeof(p)) + + +static struct sockaddr * +sa_dup(struct sockaddr *sa1) +{ + struct sockaddr *sa2; + size_t sz = sa1->sa_len; + sa2 = (struct sockaddr *) calloc(1, sz); + if (sa2 == NULL) + return NULL; + memcpy(sa2, sa1, sz); + return sa2; +} + + +void freeifaddrs(struct ifaddrs *ifp) +{ + if (NULL == ifp) return; + free(ifp->ifa_name); + free(ifp->ifa_addr); + free(ifp->ifa_netmask); + free(ifp->ifa_dstaddr); + freeifaddrs(ifp->ifa_next); + free(ifp); +} + + +int getifaddrs(struct ifaddrs **ifap) +{ + int sd, ifsize; + char *ccp, *ecp; + struct ifconf ifc; + struct ifreq *ifr; + struct ifaddrs *cifa = NULL; /* current */ + struct ifaddrs *pifa = NULL; /* previous */ + const size_t IFREQSZ = sizeof(struct ifreq); + int fam; + + *ifap = NULL; + + sd = socket(AF_INET, SOCK_DGRAM, 0); + if (sd == -1) + goto error; + + /* find how much memory to allocate for the SIOCGIFCONF call */ + if (ioctl(sd, SIOCGSIZIFCONF, (caddr_t)&ifsize) < 0) + goto error; + + ifc.ifc_req = (struct ifreq *) calloc(1, ifsize); + if (ifc.ifc_req == NULL) + goto error; + ifc.ifc_len = ifsize; + + if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) + goto error; + + ccp = (char *)ifc.ifc_req; + ecp = ccp + ifsize; + + while (ccp < ecp) { + + ifr = (struct ifreq *) ccp; + ifsize = sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr); + fam = ifr->ifr_addr.sa_family; + + if (fam == AF_INET || fam == AF_INET6) { + cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs)); + if (cifa == NULL) + goto error; + cifa->ifa_next = NULL; + + if (pifa == NULL) *ifap = cifa; /* first one */ + else pifa->ifa_next = cifa; + + cifa->ifa_name = strdup(ifr->ifr_name); + if (cifa->ifa_name == NULL) + goto error; + cifa->ifa_flags = 0; + cifa->ifa_dstaddr = NULL; + + cifa->ifa_addr = sa_dup(&ifr->ifr_addr); + if (cifa->ifa_addr == NULL) + goto error; + + if (fam == AF_INET) { + if (ioctl(sd, SIOCGIFNETMASK, ifr, IFREQSZ) < 0) + goto error; + cifa->ifa_netmask = sa_dup(&ifr->ifr_addr); + if (cifa->ifa_netmask == NULL) + goto error; + } + + if (0 == ioctl(sd, SIOCGIFFLAGS, ifr)) /* optional */ + cifa->ifa_flags = ifr->ifr_flags; + + if (fam == AF_INET) { + if (ioctl(sd, SIOCGIFDSTADDR, ifr, IFREQSZ) < 0) { + if (0 == ioctl(sd, SIOCGIFBRDADDR, ifr, IFREQSZ)) { + cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr); + if (cifa->ifa_dstaddr == NULL) + goto error; + } + } + else { + cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr); + if (cifa->ifa_dstaddr == NULL) + goto error; + } + } + pifa = cifa; + } + + ccp += ifsize; + } + free(ifc.ifc_req); + close(sd); + return 0; +error: + if (ifc.ifc_req != NULL) + free(ifc.ifc_req); + if (sd != -1) + close(sd); + freeifaddrs(*ifap); + return (-1); +}
\ No newline at end of file diff --git a/psutil/arch/aix/ifaddrs.h b/psutil/arch/aix/ifaddrs.h new file mode 100644 index 00000000..3920c1cc --- /dev/null +++ b/psutil/arch/aix/ifaddrs.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Arnon Yaari + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/*! Based on code from + https://lists.samba.org/archive/samba-technical/2009-February/063079.html +!*/ + + +#ifndef GENERIC_AIX_IFADDRS_H +#define GENERIC_AIX_IFADDRS_H + +#include <sys/socket.h> +#include <net/if.h> + +#undef ifa_dstaddr +#undef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; +}; + +extern int getifaddrs(struct ifaddrs **); +extern void freeifaddrs(struct ifaddrs *); + +#endif
\ No newline at end of file diff --git a/psutil/arch/aix/net_connections.c b/psutil/arch/aix/net_connections.c new file mode 100644 index 00000000..364cd1b7 --- /dev/null +++ b/psutil/arch/aix/net_connections.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017, Arnon Yaari + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Baded on code from lsof: + * http://www.ibm.com/developerworks/aix/library/au-lsof.html + * - dialects/aix/dproc.c:gather_proc_info + * - lib/prfp.c:process_file + * - dialects/aix/dsock.c:process_socket + * - dialects/aix/dproc.c:get_kernel_access +*/ + +#include "net_connections.h" +#include <fcntl.h> +#include <sys/types.h> +#define _KERNEL 1 +#include <sys/file.h> +#undef _KERNEL +#include <stdlib.h> +#include <sys/core.h> +#include <sys/domain.h> +#include <sys/un.h> +#include <netinet/in_pcb.h> +#include <arpa/inet.h> +#include "net_kernel_structs.h" + + + +#define PROCINFO_INCR (256) +#define PROCSIZE (sizeof(struct procentry64)) +#define FDSINFOSIZE (sizeof(struct fdsinfo64)) +#define KMEM "/dev/kmem" +#define NO_SOCKET (PyObject *)(-1) + +typedef u_longlong_t KA_T; +static int PSUTIL_CONN_NONE = 128; + +/* psutil_kread() - read from kernel memory */ +static int +psutil_kread( + int Kd, /* kernel memory file descriptor */ + KA_T addr, /* kernel memory address */ + char *buf, /* buffer to receive data */ + size_t len) { /* length to read */ + int br; + + if (lseek64(Kd, (off64_t)addr, L_SET) == (off64_t)-1) { + PyErr_SetFromErrno(PyExc_OSError); + return 1; + } + br = read(Kd, buf, len); + if (br == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return 1; + } + if (br != len) { + PyErr_SetString(PyExc_RuntimeError, + "size mismatch when reading kernel memory fd"); + return 1; + } + return 0; +} + +static int +read_unp_addr( + int Kd, + KA_T unp_addr, + char *buf, + size_t buflen +) { + struct sockaddr_un *ua = (struct sockaddr_un *)NULL; + struct sockaddr_un un; + struct mbuf64 mb; + int uo; + + if (psutil_kread(Kd, unp_addr, (char *)&mb, sizeof(mb))) { + return 1; + } + + uo = (int)(mb.m_hdr.mh_data - unp_addr); + if ((uo + sizeof(struct sockaddr)) <= sizeof(mb)) + ua = (struct sockaddr_un *)((char *)&mb + uo); + else { + if (psutil_kread(Kd, (KA_T)mb.m_hdr.mh_data, + (char *)&un, sizeof(un))) { + return 1; + } + ua = &un; + } + if (ua && ua->sun_path[0]) { + if (mb.m_len > sizeof(struct sockaddr_un)) + mb.m_len = sizeof(struct sockaddr_un); + *((char *)ua + mb.m_len - 1) = '\0'; + snprintf(buf, buflen, "%s", ua->sun_path); + } + return 0; +} + +static PyObject * +process_file(int Kd, pid32_t pid, int fd, KA_T fp) { + struct file64 f; + struct socket64 s; + struct protosw64 p; + struct domain d; + struct inpcb64 inp; + int fam; + struct tcpcb64 t; + int state = PSUTIL_CONN_NONE; + unsigned char *laddr = (unsigned char *)NULL; + unsigned char *raddr = (unsigned char *)NULL; + int rport, lport; + char laddr_str[INET6_ADDRSTRLEN]; + char raddr_str[INET6_ADDRSTRLEN]; + struct unpcb64 unp; + char unix_laddr_str[PATH_MAX] = { 0 }; + char unix_raddr_str[PATH_MAX] = { 0 }; + + /* Read file structure */ + if (psutil_kread(Kd, fp, (char *)&f, sizeof(f))) { + return NULL; + } + if (!f.f_count || f.f_type != DTYPE_SOCKET) { + return NO_SOCKET; + } + + if (psutil_kread(Kd, (KA_T) f.f_data, (char *) &s, sizeof(s))) { + return NULL; + } + + if (!s.so_type) { + return NO_SOCKET; + } + + if (!s.so_proto) { + PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol handle"); + return NULL; + } + if (psutil_kread(Kd, (KA_T)s.so_proto, (char *)&p, sizeof(p))) { + return NULL; + } + + if (!p.pr_domain) { + PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol domain"); + return NULL; + } + if (psutil_kread(Kd, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) { + return NULL; + } + + fam = d.dom_family; + if (fam == AF_INET || fam == AF_INET6) { + /* Read protocol control block */ + if (!s.so_pcb) { + PyErr_SetString(PyExc_RuntimeError, "invalid socket PCB"); + return NULL; + } + if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *) &inp, sizeof(inp))) { + return NULL; + } + + if (p.pr_protocol == IPPROTO_TCP) { + /* If this is a TCP socket, read its control block */ + if (inp.inp_ppcb + && !psutil_kread(Kd, (KA_T)inp.inp_ppcb, + (char *)&t, sizeof(t))) + state = t.t_state; + } + + if (fam == AF_INET6) { + laddr = (unsigned char *)&inp.inp_laddr6; + if (!IN6_IS_ADDR_UNSPECIFIED(&inp.inp_faddr6)) { + raddr = (unsigned char *)&inp.inp_faddr6; + rport = (int)ntohs(inp.inp_fport); + } + } + if (fam == AF_INET) { + laddr = (unsigned char *)&inp.inp_laddr; + if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) { + raddr = (unsigned char *)&inp.inp_faddr; + rport = (int)ntohs(inp.inp_fport); + } + } + lport = (int)ntohs(inp.inp_lport); + + inet_ntop(fam, laddr, laddr_str, sizeof(laddr_str)); + + if (raddr != NULL) { + inet_ntop(fam, raddr, raddr_str, sizeof(raddr_str)); + return Py_BuildValue("(iii(si)(si)ii)", fd, fam, + s.so_type, laddr_str, lport, raddr_str, + rport, state, pid); + } + else { + return Py_BuildValue("(iii(si)()ii)", fd, fam, + s.so_type, laddr_str, lport, state, + pid); + } + } + + + if (fam == AF_UNIX) { + if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *)&unp, sizeof(unp))) { + return NULL; + } + if ((KA_T) f.f_data != (KA_T) unp.unp_socket) { + PyErr_SetString(PyExc_RuntimeError, "unp_socket mismatch"); + return NULL; + } + + if (unp.unp_addr) { + if (read_unp_addr(Kd, unp.unp_addr, unix_laddr_str, + sizeof(unix_laddr_str))) { + return NULL; + } + } + + if (unp.unp_conn) { + if (psutil_kread(Kd, (KA_T) unp.unp_conn, (char *)&unp, + sizeof(unp))) { + return NULL; + } + if (read_unp_addr(Kd, unp.unp_addr, unix_raddr_str, + sizeof(unix_raddr_str))) { + return NULL; + } + } + + return Py_BuildValue("(iiissii)", fd, d.dom_family, + s.so_type, unix_laddr_str, unix_raddr_str, PSUTIL_CONN_NONE, + pid); + } + return NO_SOCKET; +} + +PyObject * +psutil_net_connections(PyObject *self, PyObject *args) { + PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + KA_T fp; + int Kd = -1; + int i, np; + struct procentry64 *p; + struct fdsinfo64 *fds = (struct fdsinfo64 *)NULL; + size_t msz; + pid32_t requested_pid; + pid32_t pid; + int Np = 0; /* number of processes */ + struct procentry64 *processes = (struct procentry64 *)NULL; + /* the process table */ + + if (py_retlist == NULL) + goto error; + if (! PyArg_ParseTuple(args, "i", &requested_pid)) + goto error; + + Kd = open(KMEM, O_RDONLY, 0); + if (Kd < 0) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, KMEM); + goto error; + } + + /* Read the process table */ + msz = (size_t)(PROCSIZE * PROCINFO_INCR); + processes = (struct procentry64 *)malloc(msz); + if (!processes) { + PyErr_NoMemory(); + goto error; + } + Np = PROCINFO_INCR; + np = pid = 0; + p = processes; + while ((i = getprocs64(p, PROCSIZE, (struct fdsinfo64 *)NULL, 0, &pid, + PROCINFO_INCR)) + == PROCINFO_INCR) { + np += PROCINFO_INCR; + if (np >= Np) { + msz = (size_t)(PROCSIZE * (Np + PROCINFO_INCR)); + processes = (struct procentry64 *)realloc((char *)processes, msz); + if (!processes) { + PyErr_NoMemory(); + goto error; + } + Np += PROCINFO_INCR; + } + p = (struct procentry64 *)((char *)processes + (np * PROCSIZE)); + } + + if (i > 0) + np += i; + + /* Loop through processes */ + for (p = processes; np > 0; np--, p++) { + pid = p->pi_pid; + if (requested_pid != -1 && requested_pid != pid) + continue; + if (p->pi_state == 0 || p->pi_state == SZOMB) + continue; + + + if (!fds) { + fds = (struct fdsinfo64 *)malloc((size_t)FDSINFOSIZE); + if (!fds) { + PyErr_NoMemory(); + goto error; + } + } + if (getprocs64((struct procentry64 *)NULL, PROCSIZE, fds, FDSINFOSIZE, + &pid, 1) + != 1) + continue; + + /* loop over file descriptors */ + for (i = 0; i < p->pi_maxofile; i++) { + fp = (KA_T)fds->pi_ufd[i].fp; + if (fp) { + py_tuple = process_file(Kd, p->pi_pid, i, fp); + if (py_tuple == NULL) + goto error; + if (py_tuple != NO_SOCKET) { + if (PyList_Append(py_retlist, py_tuple)) + goto error; + Py_DECREF(py_tuple); + } + } + } + } + close(Kd); + free(processes); + if (fds != NULL) + free(fds); + return py_retlist; + +error: + Py_XDECREF(py_tuple); + Py_DECREF(py_retlist); + if (Kd > 0) + close(Kd); + if (processes != NULL) + free(processes); + if (fds != NULL) + free(fds); + return NULL; +} diff --git a/psutil/arch/aix/net_connections.h b/psutil/arch/aix/net_connections.h new file mode 100644 index 00000000..f6a726cb --- /dev/null +++ b/psutil/arch/aix/net_connections.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2017, Arnon Yaari + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <Python.h> + +PyObject* psutil_net_connections(PyObject *self, PyObject *args); diff --git a/psutil/arch/aix/net_kernel_structs.h b/psutil/arch/aix/net_kernel_structs.h new file mode 100644 index 00000000..09f320ff --- /dev/null +++ b/psutil/arch/aix/net_kernel_structs.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017, Arnon Yaari + * All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* The kernel is always 64 bit but Python is usually compiled as a 32 bit + * process. We're reading the kernel memory to get the network connections, + * so we need the structs we read to be defined with 64 bit "pointers". + * Here are the partial definitions of the structs we use, taken from the + * header files, with data type sizes converted to their 64 bit counterparts, + * and unused data truncated. */ + +#ifdef __64BIT__ +/* In case we're in a 64 bit process after all */ +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/unpcb.h> +#include <sys/mbuf_base.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#define file64 file +#define socket64 socket +#define protosw64 protosw +#define inpcb64 inpcb +#define tcpcb64 tcpcb +#define unpcb64 unpcb +#define mbuf64 mbuf +#else + struct file64 { + int f_flag; + int f_count; + int f_options; + int f_type; + u_longlong_t f_data; + }; + + struct socket64 { + short so_type; /* generic type, see socket.h */ + short so_options; /* from socket call, see socket.h */ + ushort so_linger; /* time to linger while closing */ + short so_state; /* internal state flags SS_*, below */ + u_longlong_t so_pcb; /* protocol control block */ + u_longlong_t so_proto; /* protocol handle */ + }; + + struct protosw64 { + short pr_type; /* socket type used for */ + u_longlong_t pr_domain; /* domain protocol a member of */ + short pr_protocol; /* protocol number */ + short pr_flags; /* see below */ + }; + + struct inpcb64 { + u_longlong_t inp_next,inp_prev; + /* pointers to other pcb's */ + u_longlong_t inp_head; /* pointer back to chain of inpcb's + for this protocol */ + u_int32_t inp_iflowinfo; /* input flow label */ + u_short inp_fport; /* foreign port */ + u_int16_t inp_fatype; /* foreign address type */ + union in_addr_6 inp_faddr_6; /* foreign host table entry */ + u_int32_t inp_oflowinfo; /* output flow label */ + u_short inp_lport; /* local port */ + u_int16_t inp_latype; /* local address type */ + union in_addr_6 inp_laddr_6; /* local host table entry */ + u_longlong_t inp_socket; /* back pointer to socket */ + u_longlong_t inp_ppcb; /* pointer to per-protocol pcb */ + u_longlong_t space_rt; + struct sockaddr_in6 spare_dst; + u_longlong_t inp_ifa; /* interface address to use */ + int inp_flags; /* generic IP/datagram flags */ +}; + +struct tcpcb64 { + u_longlong_t seg__next; + u_longlong_t seg__prev; + short t_state; /* state of this connection */ +}; + +struct unpcb64 { + u_longlong_t unp_socket; /* pointer back to socket */ + u_longlong_t unp_vnode; /* if associated with file */ + ino_t unp_vno; /* fake vnode number */ + u_longlong_t unp_conn; /* control block of connected socket */ + u_longlong_t unp_refs; /* referencing socket linked list */ + u_longlong_t unp_nextref; /* link in unp_refs list */ + u_longlong_t unp_addr; /* bound address of socket */ +}; + +struct m_hdr64 +{ + u_longlong_t mh_next; /* next buffer in chain */ + u_longlong_t mh_nextpkt; /* next chain in queue/record */ + long mh_len; /* amount of data in this mbuf */ + u_longlong_t mh_data; /* location of data */ +}; + +struct mbuf64 +{ + struct m_hdr64 m_hdr; +}; + +#define m_len m_hdr.mh_len + +#endif
\ No newline at end of file |
