Bug#289384: gnome-system-monitor: segfault if special fs are used : bindfs and maybe udev

Loïc Minier Loïc Minier , 289384@bugs.debian.org
Fri, 18 Feb 2005 00:02:40 +0100


--3MwIy2ne0vdjdPXF
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

tags 289384 + fixed-upstream
thanks

        Hin

On jeu, f=E9v 17, 2005, Jaka Mocnik wrote:
> I noticed this is fixed in upstream CVS HEAD, destined for Gnome 2.10.
> It would be nice of the upstream author to fix it in 2.8 branch. In the
> meanwhile, here is a patch that fixes the bug for 2.8.1...

 This is fixed in the 2.8 branch too, as far as I can tell,
 src/callbacks.c from procman 2.8 branch is attached, feel free to
 check.

 Now we've got to wait for next upstream release.

   Regards,

--=20
Lo=EFc Minier <lool@dooz.org>
"Neutral President: I have no strong feelings one way or the other."

--3MwIy2ne0vdjdPXF
Content-Type: text/x-csrc; charset=us-ascii
Content-Disposition: attachment; filename="callbacks.c"

/* Procman - callbacks
 * Copyright (C) 2001 Kevin Vandersloot
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <libgnomevfs/gnome-vfs.h>

#include <glibtop/mountlist.h>
#include <glibtop/fsusage.h>
#include <signal.h>
#include "callbacks.h"
#include "interface.h"
#include "proctable.h"
#include "util.h"
#include "infoview.h"
#include "procactions.h"
#include "procdialogs.h"
#include "memmaps.h"
#include "favorites.h"
#include "load-graph.h"
#include "cellrenderer.h"

void
cb_preferences_activate (GtkMenuItem *menuitem, gpointer user_data)
{
	ProcData * const procdata = user_data;

	procdialog_create_preferences_dialog (procdata);
}


void
cb_renice (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	procdialog_create_renice_dialog (procdata);

}


void
cb_end_process (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	if (procdata->config.show_kill_warning)
		procdialog_create_kill_dialog (procdata, SIGTERM);
	else
		kill_process (procdata, SIGTERM);
}


void
cb_kill_process (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	if (procdata->config.show_kill_warning)
		procdialog_create_kill_dialog (procdata, SIGKILL);
	else
		kill_process (procdata, SIGKILL);
}


void
cb_show_memory_maps (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	create_memmaps_dialog (procdata);
}


void
cb_show_hidden_processes (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	create_blacklist_dialog (procdata);
}


void
cb_hide_process (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	if (procdata->config.show_hide_message)
		procdialog_create_hide_dialog (procdata);
	else
		add_selected_to_blacklist (procdata);
}


void
cb_about_activate (GtkMenuItem *menuitem, gpointer user_data)
{

	GtkWidget *about;
	GdkPixbuf *pixbuf;
	GError    *error = NULL;
	gchar     *file;


	static const gchar *authors[] = {
		N_("Kevin Vandersloot"),
		N_("Jorgen Scheibengruber - nicer devices treeview"),
		NULL
	};

	static const gchar *documenters[] = {
		NULL
	};

	const gchar *translator_credits = _("translator_credits");

	PROCMAN_GETTEXT_ARRAY_INIT(authors);
	PROCMAN_GETTEXT_ARRAY_INIT(documenters);


	file = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_PIXMAP,
					  "procman.png", FALSE, NULL);
	pixbuf = gdk_pixbuf_new_from_file (file, &error);

	if (error) {
		g_warning (G_STRLOC ": cannot open %s: %s", file, error->message);
		g_error_free (error);
	}

	g_free (file);


	about = gnome_about_new (_("System Monitor"), VERSION,
				 _("(C) 2001 Kevin Vandersloot"),
				 _("System resources monitor"),
				 authors,
				 documenters,
				 strcmp (translator_credits, "translator_credits") != 0 ? translator_credits : NULL,
				 pixbuf);

	if (pixbuf) {
		g_object_unref (pixbuf);
	}


	gtk_widget_show (about);
}


void
cb_app_exit (GtkObject *object, gpointer user_data)
{
	ProcData * const procdata = user_data;

	cb_app_delete (NULL, NULL, procdata);
}


gboolean
cb_app_delete (GtkWidget *window, GdkEventAny *event, gpointer data)
{
	ProcData * const procdata = data;

	procman_save_config (procdata);
	if (procdata->timeout != -1)
		gtk_timeout_remove (procdata->timeout);
	if (procdata->cpu_graph)
		gtk_timeout_remove (procdata->cpu_graph->timer_index);
	if (procdata->mem_graph)
		gtk_timeout_remove (procdata->mem_graph->timer_index);
	if (procdata->disk_timeout != -1)
		gtk_timeout_remove (procdata->disk_timeout);

	gtk_main_quit ();

	return TRUE;
}


#if 0
gboolean
cb_close_simple_dialog (GnomeDialog *dialog, gpointer data)
{
	ProcData * const procdata = data;

	if (procdata->timeout != -1)
		gtk_timeout_remove (procdata->timeout);

	gtk_main_quit ();

	return FALSE;

}
#endif



void
cb_proc_combo_changed (GtkComboBox *combo, gpointer data)
{
	ProcData * const procdata = data;
	GConfClient *client;

	g_return_if_fail (procdata);

	client = procdata->client;

	procdata->config.whose_process = gtk_combo_box_get_active (combo);
	gconf_client_set_int (client, "/apps/procman/view_as",
			      procdata->config.whose_process, NULL);
}


void
popup_menu_renice (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	procdialog_create_renice_dialog (procdata);
}


void
popup_menu_show_memory_maps (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	create_memmaps_dialog (procdata);
}


void
popup_menu_hide_process (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	if (procdata->config.show_hide_message)
		procdialog_create_hide_dialog (procdata);
	else
		add_selected_to_blacklist (procdata);
}


void
popup_menu_end_process (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	if (procdata->config.show_kill_warning)
		procdialog_create_kill_dialog (procdata, SIGTERM);
	else
		kill_process (procdata, SIGTERM);
}


void
popup_menu_kill_process (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;

	if (procdata->config.show_kill_warning)
		procdialog_create_kill_dialog (procdata, SIGKILL);
	else
		kill_process (procdata, SIGKILL);

}


#if 0
void
popup_menu_about_process (GtkMenuItem *menuitem, gpointer data)
{
	ProcData * const procdata = data;
	ProcInfo *info = NULL;
	gchar *name;

	if (!procdata->selected_node)
		return;

	info = e_tree_memory_node_get_data (procdata->memory,
					    procdata->selected_node);
	g_return_if_fail (info != NULL);

	/* FIXME: this is lame. GNOME help browser sucks balls. There should be a way
	to first check man pages, then info pages and give a nice error message if nothing
	exists */
	name = g_strdup_printf("man:%s", info->cmd);
	gnome_url_show (name);
	g_free (name);
}
#endif


void
cb_end_process_button_pressed (GtkButton *button, gpointer data)
{

	ProcData * const procdata = data;

	if (procdata->config.show_kill_warning)
		procdialog_create_kill_dialog (procdata, SIGTERM);
	else
		kill_process (procdata, SIGTERM);

}


void
cb_info_button_pressed (GtkButton *button, gpointer user_data)
{
	ProcData * const procdata = user_data;

	toggle_infoview (procdata);
}


void
cb_search (GtkEditable *editable, gpointer data)
{
	ProcData * const procdata = data;
	gchar *text;

	text = gtk_editable_get_chars (editable, 0, -1);

	proctable_search_table (procdata, text);
	gtk_widget_grab_focus (GTK_WIDGET (editable));
	g_free (text);
}


static void change_gconf_color(GConfClient *client, const char *key,
			       guint r, guint g, guint b)
{
	char color[24]; /* color should be 1 + 3*4 + 1 = 15 chars -> 24 */
	g_snprintf(color, sizeof color, "#%04x%04x%04x", r, g, b);
	gconf_client_set_string (client, key, color, NULL);
}


void
cb_cpu_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b,
		      guint a, gpointer data)
{
	gint i = GPOINTER_TO_INT (data);
	GConfClient *client = gconf_client_get_default ();

	if (i == 0)
		change_gconf_color(client, "/apps/procman/cpu_color", r, g, b);
	else {
		gchar key[sizeof "/apps/procman/cpu_color%d"];
		g_snprintf(key, sizeof key, "/apps/procman/cpu_color%d", i);
		change_gconf_color(client, key, r, g, b);
	}
}

void
cb_mem_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b,
		      guint a, gpointer data)
{
	ProcData * const procdata = data;
	change_gconf_color(procdata->client, "/apps/procman/mem_color", r, g, b);
}


void
cb_swap_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b,
		       guint a, gpointer data)
{
	ProcData * const procdata = data;
	change_gconf_color(procdata->client, "/apps/procman/swap_color", r, g, b);
}


void
cb_bg_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b,
		     guint a, gpointer data)
{
	ProcData * const procdata = data;
	change_gconf_color(procdata->client, "/apps/procman/bg_color", r, g, b);
}

void
cb_frame_color_changed (GnomeColorPicker *cp, guint r, guint g, guint b,
			guint a, gpointer data)
{
	ProcData * const procdata = data;
	change_gconf_color(procdata->client, "/apps/procman/frame_color", r, g, b);
}



static ProcInfo *selected_process = NULL;

static void
get_last_selected (GtkTreeModel *model, GtkTreePath *path,
		   GtkTreeIter *iter, gpointer data)
{
	ProcInfo *info;

	gtk_tree_model_get (model, iter, COL_POINTER, &info, -1);
	g_return_if_fail (info);

	selected_process = info;
}


void
cb_row_selected (GtkTreeSelection *selection, gpointer data)
{
	ProcData * const procdata = data;

	procdata->selection = selection;

	/* get the most recent selected process and determine if there are
	** no selected processes
	*/
	selected_process = NULL;
	gtk_tree_selection_selected_foreach (procdata->selection, get_last_selected,
					     procdata);

	if (selected_process) {
		procdata->selected_process = selected_process;
		if (procdata->config.show_more_info == TRUE)
			infoview_update (procdata);
		update_sensitivity (procdata, TRUE);
	}
	else {
		procdata->selected_process = NULL;
		update_sensitivity (procdata, FALSE);
	}

}


void
cb_tree_row_activated (GtkTreeView *view,
		       GtkTreePath *path,
		       GtkTreeViewColumn *column,
		       gpointer data)
{
	ProcData * const procdata = data;

	toggle_infoview (procdata);
}


gboolean
cb_tree_button_pressed (GtkWidget *widget,
			GdkEventButton *event,
			gpointer data)
{
	ProcData * const procdata = data;

	if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
		do_popup_menu (procdata, event);

	return FALSE;
}


gboolean
cb_tree_popup_menu (GtkWidget *widget, gpointer data)
{
	ProcData * const procdata = data;

	do_popup_menu (procdata, NULL);

	return TRUE;
}


void
cb_switch_page (GtkNotebook *nb, GtkNotebookPage *page,
		gint num, gpointer data)
{
	ProcData * const procdata = data;

	procdata->config.current_tab = num;

	if (num == 0) {
		if (procdata->timeout == -1)
			procdata->timeout = gtk_timeout_add (procdata->config.update_interval,
							     cb_timeout, procdata);
		load_graph_stop (procdata->cpu_graph);
		load_graph_stop (procdata->mem_graph);
		if (procdata->selected_process)
			update_sensitivity (procdata, TRUE);
	}
	else {
		if (procdata->timeout != -1 ) {
			gtk_timeout_remove (procdata->timeout);
			procdata->timeout = -1;
		}
		load_graph_start (procdata->cpu_graph);
		load_graph_start (procdata->mem_graph);
		load_graph_draw (procdata->cpu_graph);
		load_graph_draw (procdata->mem_graph);
		if (procdata->selected_process)
			update_sensitivity (procdata, FALSE);
	}

}


static GList *old_disks = NULL;


static void
fsusage_stats(const glibtop_fsusage *buf,
	      float *bused, float *bfree, float *btotal,
	      float *percentage)
{
	*btotal = buf->blocks * buf->block_size;
	*bfree  = buf->bfree  * buf->block_size;
	*bused  = *btotal - *bfree;
	*percentage = *bused / *btotal;
}


static gboolean
compare_disks (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
	GHashTable * const new_disks = data;

	GtkTreeIter *old_iter;
	glibtop_mountentry *entry;
	gchar *old_name;

	gtk_tree_model_get (model, iter, 1, &old_name, -1);

	entry = g_hash_table_lookup (new_disks, old_name);
	if (entry) {
		glibtop_fsusage usage;
		gchar *used, *total;
		float percentage, bused, bfree, btotal;

		glibtop_get_fsusage (&usage, entry->mountdir);

		fsusage_stats(&usage, &bused, &bfree, &btotal, &percentage);

		used = gnome_vfs_format_file_size_for_display (bused);
		total = gnome_vfs_format_file_size_for_display (btotal);

		gtk_tree_store_set (GTK_TREE_STORE (model), iter,
				    4, total,
				    5, used,
				    6, percentage,
				    7, btotal,
				    8, bfree,
				    -1);

		g_hash_table_remove (new_disks, old_name);

		g_free (used);
		g_free (total);
	}
	else {
		old_iter = gtk_tree_iter_copy (iter);
		old_disks = g_list_prepend (old_disks, old_iter);
	}

	g_free (old_name);
	return FALSE;
}


static GdkPixbuf*
get_icon_for_device(GnomeIconTheme *icontheme, const char *mountpoint)
{
	GdkPixbuf *pixbuf;
	GnomeVFSVolumeMonitor* monitor;
	GnomeVFSVolume* volume;
	char *i_type;
	char *path;
	int size = 24;

	monitor = gnome_vfs_get_volume_monitor();
	volume = gnome_vfs_volume_monitor_get_volume_for_path(monitor, mountpoint);

	if(!volume) return NULL;

	i_type = gnome_vfs_volume_get_icon(volume);
	gnome_vfs_volume_unref(volume);

	path = gnome_icon_theme_lookup_icon(icontheme, i_type, 24, NULL, &size);

	g_free(i_type);

	if(!path) return NULL;

	pixbuf = gdk_pixbuf_new_from_file(path, NULL);

	g_free(path);

	if (pixbuf && size != 24)
	{
		GdkPixbuf *scaled;
		scaled = gdk_pixbuf_scale_simple (pixbuf, 24, 24,
						  GDK_INTERP_HYPER);
		g_object_unref(pixbuf);
		pixbuf = scaled;
	}

	return pixbuf;
}


static void
add_new_disks (gpointer key, gpointer value, gpointer data)
{
	glibtop_mountentry * const entry = value;
	GtkTreeModel * const model = data;

	glibtop_fsusage usage;
	gchar *text[5];
	GdkPixbuf *pixbuf;
	GnomeIconTheme *icontheme;
	GtkTreeIter row;
	float percentage, btotal, bfree, bused;

	glibtop_get_fsusage (&usage, entry->mountdir);

	/* Hmm, usage.blocks == 0 seems to get rid of /proc and all
	** the other useless entries
	** glibtop_get_mountlist(&buf, FALSE) in libgtop2.8 is now sane.
	** so this test will be removed
	** TODO: remove this test
	*/
	if (usage.blocks == 0)	return;


	icontheme = gnome_icon_theme_new();

	fsusage_stats(&usage, &bused, &bfree, &btotal, &percentage);

	/*  Load an icon corresponding to the type of the device */
	pixbuf = get_icon_for_device(icontheme, entry->mountdir);

	text[0] = g_strdup (entry->devname);
	text[1] = g_strdup (entry->mountdir);
	text[2] = g_strdup (entry->type);
	text[3] = gnome_vfs_format_file_size_for_display (btotal);
	text[4] = gnome_vfs_format_file_size_for_display (bused);

	gtk_tree_store_insert (GTK_TREE_STORE (model), &row, NULL, 0);
	gtk_tree_store_set (GTK_TREE_STORE (model), &row,
			    0, pixbuf,
			    1, text[0],
			    2, text[1],
			    3, text[2],
			    4, text[3],
			    5, text[4],
			    6, percentage,
			    7, btotal,
			    8, bfree,
			    -1);

	g_free (text[0]);
	g_free (text[1]);
	g_free (text[2]);
	g_free (text[3]);
	g_free (text[4]);

	if(pixbuf) g_object_unref (pixbuf);
	g_object_unref (icontheme);
}


gint
cb_update_disks (gpointer data)
{
	ProcData * const procdata = data;

	GtkTreeModel *model;
	glibtop_mountentry *entry;
	glibtop_mountlist mountlist;
	GHashTable *new_disks = NULL;
	guint i;

	model = gtk_tree_view_get_model (GTK_TREE_VIEW (procdata->disk_list));

	entry = glibtop_get_mountlist (&mountlist, FALSE);

	new_disks = g_hash_table_new (g_str_hash, g_str_equal);
	for (i=0; i < mountlist.number; i++) {
		g_hash_table_insert (new_disks, entry[i].devname, &entry[i]);
	}

	gtk_tree_model_foreach (model, compare_disks, new_disks);

	g_hash_table_foreach (new_disks, add_new_disks, model);

	while (old_disks) {
		GtkTreeIter *iter = old_disks->data;

		gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
		gtk_tree_iter_free (iter);

		old_disks = g_list_next (old_disks);
	}

	g_hash_table_destroy (new_disks);
	g_free (entry);

	return TRUE;
}


gint
cb_timeout (gpointer data)
{
	ProcData * const procdata = data;

	proctable_update_all (procdata);

	return TRUE;
}

--3MwIy2ne0vdjdPXF--