Blame sysdeps/linux/procopenfiles.c

Packit Service 407539
/* Copyright (C) 1998-99 Martin Baulig
Packit Service 407539
   Copyright (C) 2004 Nicolás Lichtmaier
Packit Service 407539
   This file is part of LibGTop 1.0.
Packit Service 407539
Packit Service 407539
   Modified by Nicolás Lichtmaier to give a process open files.
Packit Service 407539
Packit Service 407539
   Contributed by Martin Baulig <martin@home-of-linux.org>, April 1998.
Packit Service 407539
Packit Service 407539
   LibGTop is free software; you can redistribute it and/or modify it
Packit Service 407539
   under the terms of the GNU General Public License as published by
Packit Service 407539
   the Free Software Foundation; either version 2 of the License,
Packit Service 407539
   or (at your option) any later version.
Packit Service 407539
Packit Service 407539
   LibGTop is distributed in the hope that it will be useful, but WITHOUT
Packit Service 407539
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit Service 407539
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit Service 407539
   for more details.
Packit Service 407539
Packit Service 407539
   You should have received a copy of the GNU General Public License
Packit Service 407539
   along with LibGTop; see the file COPYING. If not, write to the
Packit Service 407539
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit Service 407539
   Boston, MA 02110-1301, USA.
Packit Service 407539
*/
Packit Service 407539
Packit Service 407539
#include <config.h>
Packit Service 407539
#include <glibtop.h>
Packit Service 407539
#include <glibtop/error.h>
Packit Service 407539
#include <glibtop/procopenfiles.h>
Packit Service 407539
#include <sys/types.h>
Packit Service 407539
#include <dirent.h>
Packit Service 407539
#include <string.h>
Packit Service 407539
#include <stdio.h>
Packit Service 407539
#include <arpa/inet.h>
Packit Service 407539
Packit Service 407539
#include "glibtop_private.h"
Packit Service 407539
Packit Service 407539
static const unsigned long _glibtop_sysdeps_proc_open_files =
Packit Service 407539
(1L << GLIBTOP_PROC_OPEN_FILES_NUMBER)|
Packit Service 407539
(1L << GLIBTOP_PROC_OPEN_FILES_TOTAL)|
Packit Service 407539
(1L << GLIBTOP_PROC_OPEN_FILES_SIZE);
Packit Service 407539
Packit Service 407539
/* Init function. */
Packit Service 407539
Packit Service 407539
void
Packit Service 407539
_glibtop_init_proc_open_files_s (glibtop *server)
Packit Service 407539
{
Packit Service 407539
	server->sysdeps.proc_open_files = _glibtop_sysdeps_proc_open_files;
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
typedef void (*LineParser)(GHashTable *dict, const char *line);
Packit Service 407539
Packit Service 407539
Packit Service 407539
static void
Packit Service 407539
parse_file(const char *filename, LineParser parser, GHashTable *dict)
Packit Service 407539
{
Packit Service 407539
	FILE *f;
Packit Service 407539
	char *line = NULL;
Packit Service 407539
	size_t size = 0;
Packit Service 407539
Packit Service 407539
	f = fopen(filename, "r");
Packit Service 407539
Packit Service 407539
	if(!f) {
Packit Service 407539
		g_warning("Cannot open '%s'", filename);
Packit Service 407539
		return;
Packit Service 407539
	}
Packit Service 407539
Packit Service 407539
Packit Service 407539
	/* skip the first line */
Packit Service 407539
	if (getline(&line, &size, f) == -1)
Packit Service 407539
		goto eof;
Packit Service 407539
Packit Service 407539
	while (getline(&line, &size, f) != -1)
Packit Service 407539
		parser(dict, line);
Packit Service 407539
Packit Service 407539
 eof:
Packit Service 407539
	free(line);
Packit Service 407539
	fclose(f);
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
static GHashTable*
Packit Service 407539
get_all(const char *filename, LineParser parser)
Packit Service 407539
{
Packit Service 407539
	GHashTable *dict;
Packit Service 407539
Packit Service 407539
	dict = g_hash_table_new_full(g_direct_hash, g_direct_equal,
Packit Service 407539
				     NULL, g_free);
Packit Service 407539
Packit Service 407539
	parse_file(filename, parser, dict);
Packit Service 407539
Packit Service 407539
	return dict;
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
struct Inet6SocketEntry
Packit Service 407539
{
Packit Service 407539
	char host[GLIBTOP_OPEN_DEST_HOST_LEN + 1];
Packit Service 407539
	int port;
Packit Service 407539
};
Packit Service 407539
Packit Service 407539
Packit Service 407539
static void
Packit Service 407539
inet6_socket_parser(GHashTable *dict, const char* line)
Packit Service 407539
{
Packit Service 407539
	struct Inet6SocketEntry *se;
Packit Service 407539
	int sock;
Packit Service 407539
	struct in6_addr addr;
Packit Service 407539
Packit Service 407539
	se = g_malloc0(sizeof *se);
Packit Service 407539
Packit Service 407539
	if(sscanf(line, "%*d: %*s %8x%8x%8x%8x:%4x %*x %*x:%*x %*x:%*x %*d %*d %*d %d",
Packit Service 407539
		  &addr.s6_addr32[0], &addr.s6_addr32[1], &addr.s6_addr32[2],
Packit Service 407539
		  &addr.s6_addr32[3], &se->port, &sock) != 6)
Packit Service 407539
		goto error;
Packit Service 407539
Packit Service 407539
	if(!inet_ntop(AF_INET6, &addr, se->host, sizeof se->host))
Packit Service 407539
		goto error;
Packit Service 407539
Packit Service 407539
	g_hash_table_insert(dict, GINT_TO_POINTER(sock), se);
Packit Service 407539
	return;
Packit Service 407539
Packit Service 407539
 error:
Packit Service 407539
	g_free(se);
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
static inline GHashTable *
Packit Service 407539
get_all_inet6_sockets()
Packit Service 407539
{
Packit Service 407539
	return get_all("/proc/net/tcp6", inet6_socket_parser);
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
struct InetSocketEntry
Packit Service 407539
{
Packit Service 407539
	char host[GLIBTOP_OPEN_DEST_HOST_LEN + 1];
Packit Service 407539
	int port;
Packit Service 407539
};
Packit Service 407539
Packit Service 407539
Packit Service 407539
static void
Packit Service 407539
inet_socket_parser(GHashTable *dict, const char* line)
Packit Service 407539
{
Packit Service 407539
	struct InetSocketEntry *se;
Packit Service 407539
	int sock;
Packit Service 407539
	unsigned addr;
Packit Service 407539
Packit Service 407539
	se = g_malloc0(sizeof *se);
Packit Service 407539
Packit Service 407539
	if(sscanf(line, "%*d: %*x:%*x %8x:%4x %*x %*x:%*x %*x:%*x %*d %*d %*d %d",
Packit Service 407539
		  &addr, &se->port, &sock) != 3)
Packit Service 407539
		goto error;
Packit Service 407539
Packit Service 407539
	if(!inet_ntop(AF_INET, &addr, se->host, sizeof se->host))
Packit Service 407539
		goto error;
Packit Service 407539
Packit Service 407539
	g_hash_table_insert(dict, GINT_TO_POINTER(sock), se);
Packit Service 407539
	return;
Packit Service 407539
Packit Service 407539
 error:
Packit Service 407539
	g_free(se);
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
static inline GHashTable *
Packit Service 407539
get_all_inet_sockets()
Packit Service 407539
{
Packit Service 407539
	return get_all("/proc/net/tcp", inet_socket_parser);
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
struct LocalSocketEntry
Packit Service 407539
{
Packit Service 407539
	char name[GLIBTOP_OPEN_DEST_HOST_LEN + 1];
Packit Service 407539
};
Packit Service 407539
Packit Service 407539
Packit Service 407539
static void
Packit Service 407539
local_socket_parser(GHashTable *dict, const char *line)
Packit Service 407539
{
Packit Service 407539
	int sock;
Packit Service 407539
	struct LocalSocketEntry *use;
Packit Service 407539
	char *p;
Packit Service 407539
Packit Service 407539
	use = g_malloc0(sizeof *use);
Packit Service 407539
Packit Service 407539
	/* dfaf1640: 00000003 00000000 00000000 0001 03  6457 /dev/log */
Packit Service 407539
	p = skip_multiple_token(line, 6);
Packit Service 407539
Packit Service 407539
	sock = strtoul(p, &p, 10);
Packit Service 407539
	g_strlcpy(use->name, p, sizeof use->name);
Packit Service 407539
	g_strstrip(use->name);
Packit Service 407539
	g_hash_table_insert(dict, GINT_TO_POINTER(sock), use);
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
static inline GHashTable *
Packit Service 407539
get_all_local_sockets()
Packit Service 407539
{
Packit Service 407539
	return get_all("/proc/net/unix", local_socket_parser);
Packit Service 407539
}
Packit Service 407539
Packit Service 407539
Packit Service 407539
Packit Service 407539
/* Provides detailed information about a process' open files */
Packit Service 407539
Packit Service 407539
glibtop_open_files_entry *
Packit Service 407539
glibtop_get_proc_open_files_s (glibtop *server, glibtop_proc_open_files *buf,	pid_t pid)
Packit Service 407539
{
Packit Service 407539
	char fn [BUFSIZ];
Packit Service 407539
	GArray *entries;
Packit Service 407539
	GHashTable *inet6_sockets = NULL, *inet_sockets = NULL, *local_sockets = NULL;
Packit Service 407539
	struct dirent *direntry;
Packit Service 407539
	DIR *dir;
Packit Service 407539
Packit Service 407539
	memset (buf, 0, sizeof (glibtop_proc_open_files));
Packit Service 407539
Packit Service 407539
	sprintf (fn, "/proc/%d/fd", pid);
Packit Service 407539
Packit Service 407539
	dir = opendir (fn);
Packit Service 407539
	if (!dir) return NULL;
Packit Service 407539
Packit Service 407539
	entries = g_array_new(FALSE, FALSE, sizeof(glibtop_open_files_entry));
Packit Service 407539
Packit Service 407539
	while((direntry = readdir(dir))) {
Packit Service 407539
		char tgt [BUFSIZ];
Packit Service 407539
		glibtop_open_files_entry entry = {0};
Packit Service 407539
Packit Service 407539
		if(direntry->d_name[0] == '.')
Packit Service 407539
			continue;
Packit Service 407539
Packit Service 407539
		g_snprintf(fn, sizeof fn, "/proc/%d/fd/%s",
Packit Service 407539
			   pid, direntry->d_name);
Packit Service 407539
Packit Service 407539
		if (!safe_readlink(fn, tgt, sizeof tgt))
Packit Service 407539
			continue;
Packit Service 407539
Packit Service 407539
		entry.fd = atoi(direntry->d_name);
Packit Service 407539
Packit Service 407539
		if(g_str_has_prefix(tgt, "socket:["))
Packit Service 407539
		{
Packit Service 407539
			int sockfd;
Packit Service 407539
			struct Inet6SocketEntry *i6se;
Packit Service 407539
			struct InetSocketEntry *ise;
Packit Service 407539
			struct LocalSocketEntry *lse;
Packit Service 407539
Packit Service 407539
			if(!inet6_sockets) inet6_sockets = get_all_inet6_sockets();
Packit Service 407539
			if(!inet_sockets) inet_sockets = get_all_inet_sockets();
Packit Service 407539
			if(!local_sockets) local_sockets = get_all_local_sockets();
Packit Service 407539
Packit Service 407539
			sockfd = atoi(tgt + 8);
Packit Service 407539
Packit Service 407539
			i6se = g_hash_table_lookup(inet6_sockets,
Packit Service 407539
						 GINT_TO_POINTER(sockfd));
Packit Service 407539
Packit Service 407539
			if(i6se) {
Packit Service 407539
				entry.type = GLIBTOP_FILE_TYPE_INET6SOCKET;
Packit Service 407539
				entry.info.sock.dest_port = i6se->port;
Packit Service 407539
				g_strlcpy(entry.info.sock.dest_host, i6se->host,
Packit Service 407539
					  sizeof entry.info.sock.dest_host);
Packit Service 407539
				goto found;
Packit Service 407539
			}
Packit Service 407539
Packit Service 407539
			ise = g_hash_table_lookup(inet_sockets,
Packit Service 407539
						 GINT_TO_POINTER(sockfd));
Packit Service 407539
Packit Service 407539
			if(ise) {
Packit Service 407539
				entry.type = GLIBTOP_FILE_TYPE_INETSOCKET;
Packit Service 407539
				entry.info.sock.dest_port = ise->port;
Packit Service 407539
				g_strlcpy(entry.info.sock.dest_host, ise->host,
Packit Service 407539
					  sizeof entry.info.sock.dest_host);
Packit Service 407539
				goto found;
Packit Service 407539
			}
Packit Service 407539
Packit Service 407539
			lse = g_hash_table_lookup(local_sockets,
Packit Service 407539
						  GINT_TO_POINTER(sockfd));
Packit Service 407539
Packit Service 407539
			if(lse) {
Packit Service 407539
				entry.type = GLIBTOP_FILE_TYPE_LOCALSOCKET;
Packit Service 407539
				g_strlcpy(entry.info.localsock.name, lse->name,
Packit Service 407539
					  sizeof entry.info.localsock.name);
Packit Service 407539
				goto found;
Packit Service 407539
			}
Packit Service 407539
Packit Service 407539
		found:
Packit Service 407539
			(void)0; /* kills warning */
Packit Service 407539
		}
Packit Service 407539
		else if(g_str_has_prefix(tgt, "pipe:["))
Packit Service 407539
		{
Packit Service 407539
			entry.type = GLIBTOP_FILE_TYPE_PIPE;
Packit Service 407539
		}
Packit Service 407539
		else
Packit Service 407539
		{
Packit Service 407539
			entry.type = GLIBTOP_FILE_TYPE_FILE;
Packit Service 407539
			g_strlcpy(entry.info.file.name, tgt, sizeof entry.info.file.name);
Packit Service 407539
		}
Packit Service 407539
Packit Service 407539
		g_array_append_val(entries, entry);
Packit Service 407539
	}
Packit Service 407539
Packit Service 407539
	closedir (dir);
Packit Service 407539
Packit Service 407539
	if(inet_sockets) g_hash_table_destroy(inet_sockets);
Packit Service 407539
	if(inet6_sockets) g_hash_table_destroy(inet6_sockets);
Packit Service 407539
	if(local_sockets) g_hash_table_destroy(local_sockets);
Packit Service 407539
Packit Service 407539
	buf->flags = _glibtop_sysdeps_proc_open_files;
Packit Service 407539
	buf->number = entries->len;
Packit Service 407539
	buf->size = sizeof(glibtop_open_files_entry);
Packit Service 407539
	buf->total = buf->number * buf->size;
Packit Service 407539
Packit Service 407539
	return (glibtop_open_files_entry*)g_array_free(entries, FALSE);
Packit Service 407539
}