Blame sysdeps/freebsd/procopenfiles.c

Packit d37888
/* Copyright (C) 1998-99 Martin Baulig
Packit d37888
   Copyright (C) 2004 Nicolás Lichtmaier
Packit d37888
   Copyright (C) 2007 Joe Marcus Clarke
Packit d37888
   This file is part of LibGTop 1.0.
Packit d37888
Packit d37888
   Modified by Nicolás Lichtmaier to give a process open files.
Packit d37888
Packit d37888
   Contributed by Martin Baulig <martin@home-of-linux.org>, April 1998.
Packit d37888
Packit d37888
   LibGTop is free software; you can redistribute it and/or modify it
Packit d37888
   under the terms of the GNU General Public License as published by
Packit d37888
   the Free Software Foundation; either version 2 of the License,
Packit d37888
   or (at your option) any later version.
Packit d37888
Packit d37888
   LibGTop is distributed in the hope that it will be useful, but WITHOUT
Packit d37888
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit d37888
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit d37888
   for more details.
Packit d37888
Packit d37888
   You should have received a copy of the GNU General Public License
Packit d37888
   along with LibGTop; see the file COPYING. If not, write to the
Packit d37888
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit d37888
   Boston, MA 02110-1301, USA.
Packit d37888
*/
Packit d37888
Packit d37888
#include <config.h>
Packit d37888
#include <glibtop.h>
Packit d37888
#include <glibtop/error.h>
Packit d37888
#include <glibtop/procopenfiles.h>
Packit d37888
#include <sys/types.h>
Packit d37888
#include <sys/socket.h>
Packit d37888
#include <sys/param.h>
Packit d37888
#include <sys/sysctl.h>
Packit d37888
#include <sys/un.h>
Packit d37888
#include <sys/user.h>
Packit d37888
#include <netinet/in.h>
Packit d37888
#include <arpa/inet.h>
Packit d37888
#ifdef HAVE_KINFO_GETFILE
Packit d37888
#include <libutil.h>
Packit d37888
#endif
Packit d37888
#include <string.h>
Packit d37888
#include <stdlib.h>
Packit d37888
Packit d37888
#include "glibtop_private.h"
Packit d37888
Packit d37888
static const unsigned long _glibtop_sysdeps_proc_open_files =
Packit d37888
(1L << GLIBTOP_PROC_OPEN_FILES_NUMBER)|
Packit d37888
(1L << GLIBTOP_PROC_OPEN_FILES_TOTAL)|
Packit d37888
(1L << GLIBTOP_PROC_OPEN_FILES_SIZE);
Packit d37888
Packit d37888
/* Init function. */
Packit d37888
Packit d37888
void
Packit d37888
_glibtop_init_proc_open_files_s (glibtop *server)
Packit d37888
{
Packit d37888
	server->sysdeps.proc_open_files = _glibtop_sysdeps_proc_open_files;
Packit d37888
}
Packit d37888
Packit d37888
#if __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104)
Packit d37888
static char *
Packit d37888
addr_to_string(struct sockaddr_storage *ss)
Packit d37888
{
Packit d37888
	char *buffer = NULL;
Packit d37888
	char buffer2[INET6_ADDRSTRLEN];
Packit d37888
	struct sockaddr_in6 *sin6;
Packit d37888
	struct sockaddr_in *sin;
Packit d37888
	struct sockaddr_un *sun;
Packit d37888
Packit d37888
	switch (ss->ss_family) {
Packit d37888
		case AF_LOCAL:
Packit d37888
			sun = (struct sockaddr_un *)ss;
Packit d37888
			if (strlen(sun->sun_path) == 0)
Packit d37888
				buffer = g_strdup("-");
Packit d37888
			else
Packit d37888
				buffer = g_strdup(sun->sun_path);
Packit d37888
			break;
Packit d37888
		case AF_INET:
Packit d37888
			sin = (struct sockaddr_in *)ss;
Packit d37888
			buffer = g_strdup(inet_ntoa(sin->sin_addr));
Packit d37888
			break;
Packit d37888
		case AF_INET6:
Packit d37888
			sin6 = (struct sockaddr_in6 *)ss;
Packit d37888
			if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2,
Packit d37888
			    sizeof(buffer2)) != NULL)
Packit d37888
				buffer = g_strdup(buffer2);
Packit d37888
			else
Packit d37888
				buffer = g_strdup("-");
Packit d37888
			break;
Packit d37888
	}
Packit d37888
Packit d37888
	return buffer;
Packit d37888
}
Packit d37888
Packit d37888
static int
Packit d37888
addr_to_port(struct sockaddr_storage *ss)
Packit d37888
{
Packit d37888
	int port = 0;
Packit d37888
	struct sockaddr_in6 *sin6;
Packit d37888
	struct sockaddr_in *sin;
Packit d37888
Packit d37888
	switch (ss->ss_family) {
Packit d37888
		case AF_INET:
Packit d37888
			sin = (struct sockaddr_in *)ss;
Packit d37888
			port = ntohs(sin->sin_port);
Packit d37888
			break;
Packit d37888
		case AF_INET6:
Packit d37888
			sin6 = (struct sockaddr_in6 *)ss;
Packit d37888
			port = ntohs(sin6->sin6_port);
Packit d37888
			break;
Packit d37888
	}
Packit d37888
Packit d37888
	return port;
Packit d37888
}
Packit d37888
#else
Packit d37888
Packit d37888
static GArray *
Packit d37888
parse_output(const char *output) {
Packit d37888
	GArray *entries;
Packit d37888
	char **lines;
Packit d37888
	char  *ftype = NULL;
Packit d37888
	char  *fname = NULL;
Packit d37888
	guint  i;
Packit d37888
	guint  len;
Packit d37888
	int    fd = -1;
Packit d37888
Packit d37888
	entries = g_array_new(FALSE, FALSE, sizeof(glibtop_open_files_entry));
Packit d37888
Packit d37888
	lines = g_strsplit(output, "\n", 0);
Packit d37888
	len = g_strv_length(lines);
Packit d37888
Packit d37888
	for (i = 0; i < len && lines[i]; i++) {
Packit d37888
		glibtop_open_files_entry entry = {0};
Packit d37888
Packit d37888
		if (strlen(lines[i]) < 2)
Packit d37888
			continue;
Packit d37888
Packit d37888
		if (!g_str_has_prefix(lines[i], "f") &&
Packit d37888
		    !g_str_has_prefix(lines[i], "t") &&
Packit d37888
		    !g_str_has_prefix(lines[i], "n"))
Packit d37888
			continue;
Packit d37888
Packit d37888
		if (g_str_has_prefix(lines[i], "f")) {
Packit d37888
			if (!g_ascii_isdigit(*(lines[i] + 1)))
Packit d37888
				i += 2;
Packit d37888
			else
Packit d37888
				fd = atoi(lines[i] + 1);
Packit d37888
			continue;
Packit d37888
		}
Packit d37888
Packit d37888
		if (g_str_has_prefix(lines[i], "t")) {
Packit d37888
			ftype = lines[i];
Packit d37888
			ftype++;
Packit d37888
			continue;
Packit d37888
		} else {
Packit d37888
			fname = lines[i];
Packit d37888
			fname++;
Packit d37888
		}
Packit d37888
Packit d37888
		if (ftype == NULL || fname == NULL)
Packit d37888
			continue;
Packit d37888
Packit d37888
		if (!strcmp(ftype, "unix")) {
Packit d37888
			entry.type = GLIBTOP_FILE_TYPE_LOCALSOCKET;
Packit d37888
			g_strlcpy(entry.info.localsock.name, fname,
Packit d37888
			  	  sizeof(entry.info.localsock.name));
Packit d37888
		} else if (!strcmp(ftype, "PIPE")) {
Packit d37888
			entry.type = GLIBTOP_FILE_TYPE_PIPE;
Packit d37888
		} else if (!strcmp(ftype, "VREG") ||
Packit d37888
			   !strcmp(ftype, "GDIR") ||
Packit d37888
			   !strcmp(ftype, "GREG") ||
Packit d37888
			   !strcmp(ftype, "VCHR") ||
Packit d37888
			   !strcmp(ftype, "VBLK") ||
Packit d37888
			   !strcmp(ftype, "DIR")  ||
Packit d37888
			   !strcmp(ftype, "LINK") ||
Packit d37888
			   !strcmp(ftype, "REG")  ||
Packit d37888
			   !strcmp(ftype, "VDIR")) {
Packit d37888
			entry.type = GLIBTOP_FILE_TYPE_FILE;
Packit d37888
			g_strlcpy(entry.info.file.name, fname,
Packit d37888
				  sizeof(entry.info.file.name));
Packit d37888
		} else if (!strcmp(ftype, "IPv4")) {
Packit d37888
			char **hosts;
Packit d37888
			char **remote_host;
Packit d37888
Packit d37888
			if (!strstr(fname, "->")) {
Packit d37888
				remote_host = g_strsplit(fname, ":", 0);
Packit d37888
			} else {
Packit d37888
				hosts = g_strsplit(fname, "->", 0);
Packit d37888
				if (g_strv_length(hosts) < 2) {
Packit d37888
					g_strfreev(hosts);
Packit d37888
					continue;
Packit d37888
				}
Packit d37888
Packit d37888
				remote_host = g_strsplit(hosts[1], ":", 0);
Packit d37888
				g_strfreev(hosts);
Packit d37888
			}
Packit d37888
Packit d37888
			if (g_strv_length(remote_host) < 2) {
Packit d37888
				g_strfreev(remote_host);
Packit d37888
				continue;
Packit d37888
			}
Packit d37888
Packit d37888
			entry.type = GLIBTOP_FILE_TYPE_INETSOCKET;
Packit d37888
			if (!strcmp(remote_host[0], "*"))
Packit d37888
				g_strlcpy(entry.info.sock.dest_host, "0.0.0.0",
Packit d37888
					  sizeof(entry.info.sock.dest_host));
Packit d37888
			else
Packit d37888
				g_strlcpy(entry.info.sock.dest_host,
Packit d37888
					  remote_host[0],
Packit d37888
					  sizeof(entry.info.sock.dest_host));
Packit d37888
			entry.info.sock.dest_port = atoi(remote_host[1]);
Packit d37888
Packit d37888
			g_strfreev(remote_host);
Packit d37888
		} else if (!strcmp(ftype, "IPv6")) {
Packit d37888
			char **hosts;
Packit d37888
			char **remote_host;
Packit d37888
Packit d37888
			if (!strstr(fname, "->")) {
Packit d37888
				remote_host = g_strsplit(fname, ":", 0);
Packit d37888
			} else {
Packit d37888
				hosts = g_strsplit(fname, "->", 0);
Packit d37888
				if (g_strv_length(hosts) < 2) {
Packit d37888
					g_strfreev(hosts);
Packit d37888
					continue;
Packit d37888
				}
Packit d37888
Packit d37888
				remote_host = g_strsplit(hosts[1], "]", 0);
Packit d37888
				g_strfreev(hosts);
Packit d37888
			}
Packit d37888
Packit d37888
			if (g_strv_length(remote_host) < 2) {
Packit d37888
				g_strfreev(remote_host);
Packit d37888
				continue;
Packit d37888
			}
Packit d37888
Packit d37888
			entry.type = GLIBTOP_FILE_TYPE_INET6SOCKET;
Packit d37888
			if (!strcmp(remote_host[0], "*"))
Packit d37888
				g_strlcpy(entry.info.sock.dest_host, "0.0.0.0",
Packit d37888
					  sizeof(entry.info.sock.dest_host));
Packit d37888
			else
Packit d37888
				g_strlcpy(entry.info.sock.dest_host,
Packit d37888
					  remote_host[0] + 1,
Packit d37888
					  sizeof(entry.info.sock.dest_host));
Packit d37888
			entry.info.sock.dest_port = atoi(remote_host[1] + 1);
Packit d37888
Packit d37888
			g_strfreev(remote_host);
Packit d37888
		} else
Packit d37888
			continue;
Packit d37888
Packit d37888
		entry.fd = fd;
Packit d37888
Packit d37888
		fd = -1;
Packit d37888
		ftype = NULL;
Packit d37888
		fname = NULL;
Packit d37888
Packit d37888
		g_array_append_val(entries, entry);
Packit d37888
	}
Packit d37888
Packit d37888
	g_strfreev(lines);
Packit d37888
Packit d37888
	return entries;
Packit d37888
}
Packit d37888
#endif
Packit d37888
Packit d37888
glibtop_open_files_entry *
Packit d37888
glibtop_get_proc_open_files_s (glibtop *server, glibtop_proc_open_files *buf,	pid_t pid)
Packit d37888
{
Packit d37888
#if __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104)
Packit d37888
	struct kinfo_file *freep, *kif;
Packit d37888
#ifndef HAVE_KINFO_GETFILE
Packit d37888
	int name[4];
Packit d37888
	size_t len;
Packit d37888
#else
Packit d37888
	int cnt;
Packit d37888
#endif
Packit d37888
	ssize_t i;
Packit d37888
#else
Packit d37888
	char *output;
Packit d37888
#endif
Packit d37888
	GArray *entries;
Packit d37888
Packit d37888
	memset(buf, 0, sizeof (glibtop_proc_open_files));
Packit d37888
Packit d37888
#if __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104)
Packit d37888
#ifndef HAVE_KINFO_GETFILE
Packit d37888
	name[0] = CTL_KERN;
Packit d37888
	name[1] = KERN_PROC;
Packit d37888
	name[2] = KERN_PROC_FILEDESC;
Packit d37888
	name[3] = pid;
Packit d37888
Packit d37888
	if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
Packit d37888
		return NULL;
Packit d37888
Packit d37888
	freep = kif = g_malloc(len);
Packit d37888
	if (sysctl(name, 4, kif, &len, NULL, 0) < 0) {
Packit d37888
		g_free(freep);
Packit d37888
		return NULL;
Packit d37888
	}
Packit d37888
#else
Packit d37888
	freep = kinfo_getfile(pid, &cnt);
Packit d37888
#endif
Packit d37888
Packit d37888
	entries = g_array_new(FALSE, FALSE, sizeof(glibtop_open_files_entry));
Packit d37888
Packit d37888
#ifndef HAVE_KINFO_GETFILE
Packit d37888
	for (i = 0; i < len / sizeof(*kif); i++, kif++) {
Packit d37888
		glibtop_open_files_entry entry = {0};
Packit d37888
Packit d37888
		if (kif->kf_structsize != sizeof(*kif))
Packit d37888
			continue;
Packit d37888
#else
Packit d37888
	for (i = 0; i < cnt; i++) {
Packit d37888
		glibtop_open_files_entry entry = {0};
Packit d37888
Packit d37888
		kif = &freep[i];
Packit d37888
#endif
Packit d37888
Packit d37888
		if (kif->kf_fd < 0)
Packit d37888
			continue;
Packit d37888
Packit d37888
		if (kif->kf_type == KF_TYPE_SOCKET) {
Packit d37888
			if (kif->kf_sock_domain == AF_LOCAL) {
Packit d37888
				struct sockaddr_un *sun;
Packit d37888
Packit d37888
				entry.type = GLIBTOP_FILE_TYPE_LOCALSOCKET;
Packit d37888
				sun = (struct sockaddr_un *)&kif->kf_sa_local;
Packit d37888
Packit d37888
				if (sun->sun_path[0]) {
Packit d37888
					char *addrstr;
Packit d37888
Packit d37888
					addrstr = addr_to_string(&kif->kf_sa_local);
Packit d37888
					g_strlcpy(entry.info.localsock.name,
Packit d37888
						  addrstr,
Packit d37888
						  sizeof(entry.info.localsock.name));
Packit d37888
					g_free(addrstr);
Packit d37888
				} else {
Packit d37888
					char *addrstr;
Packit d37888
Packit d37888
					addrstr = addr_to_string(&kif->kf_sa_peer);
Packit d37888
					g_strlcpy(entry.info.localsock.name,
Packit d37888
						  addrstr,
Packit d37888
						  sizeof(entry.info.localsock.name));
Packit d37888
					g_free(addrstr);
Packit d37888
				}
Packit d37888
			} else if (kif->kf_sock_domain == AF_INET ||
Packit d37888
				   kif->kf_sock_domain == AF_INET6) {
Packit d37888
				char *addrstr;
Packit d37888
Packit d37888
				if (kif->kf_sock_domain == AF_INET)
Packit d37888
					entry.type = GLIBTOP_FILE_TYPE_INETSOCKET;
Packit d37888
				else
Packit d37888
					entry.type = GLIBTOP_FILE_TYPE_INET6SOCKET;
Packit d37888
				addrstr = addr_to_string(&kif->kf_sa_peer);
Packit d37888
				g_strlcpy(entry.info.sock.dest_host,
Packit d37888
					  addrstr,
Packit d37888
					  sizeof(entry.info.sock.dest_host));
Packit d37888
				g_free(addrstr);
Packit d37888
				entry.info.sock.dest_port = addr_to_port(&kif->kf_sa_peer);
Packit d37888
			}
Packit d37888
		} else if (kif->kf_type == KF_TYPE_PIPE) {
Packit d37888
			entry.type = GLIBTOP_FILE_TYPE_PIPE;
Packit d37888
		} else if (kif->kf_type == KF_TYPE_VNODE) {
Packit d37888
			entry.type = GLIBTOP_FILE_TYPE_FILE;
Packit d37888
			g_strlcpy(entry.info.file.name, kif->kf_path,
Packit d37888
				  sizeof(entry.info.file.name));
Packit d37888
		} else
Packit d37888
			continue;
Packit d37888
Packit d37888
		entry.fd = kif->kf_fd;
Packit d37888
Packit d37888
		g_array_append_val(entries, entry);
Packit d37888
	}
Packit d37888
	g_free(freep);
Packit d37888
#else
Packit d37888
Packit d37888
	output = execute_lsof(pid);
Packit d37888
	if (output == NULL) return NULL;
Packit d37888
Packit d37888
	entries = parse_output(output);
Packit d37888
Packit d37888
	g_free(output);
Packit d37888
#endif
Packit d37888
Packit d37888
	buf->flags = _glibtop_sysdeps_proc_open_files;
Packit d37888
	buf->number = entries->len;
Packit d37888
	buf->size = sizeof(glibtop_open_files_entry);
Packit d37888
	buf->total = buf->number * buf->size;
Packit d37888
Packit d37888
	return (glibtop_open_files_entry*)g_array_free(entries, FALSE);
Packit d37888
}