From 858573ca6bf57cae345d2047c7a79e2da6a7d345 Mon Sep 17 00:00:00 2001 From: Thierry Vignaud Date: Sat, 21 Dec 2013 02:05:57 +0100 Subject: split mgaapplet-update-checker since we cannot prevent glib/gtk to spawn threads behind our back, we can at least try to prevent segfaults due to mixing threads with secular forks by exec()ing immediately --- Makefile | 2 +- NEWS | 3 ++ mgaapplet | 95 +--------------------------------------- mgaapplet-update-checker | 111 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 94 deletions(-) create mode 100755 mgaapplet-update-checker diff --git a/Makefile b/Makefile index 182e8429..25416351 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ clean: install: all install -d $(PREFIX)/usr/{bin,libexec,share/{mime/packages,$(NAME)/pixmaps,autostart,gnome/autostart,icons/{mini,large}},lib/libDrakX/drakfirsttime} install -m755 $(MGAUPDATE) $(MGAAPPLET)-config $(MGAAPPLET)-upgrade-helper $(LIBEXECDIR) - install -m755 $(MGAAPPLET) $(BINDIR) + install -m755 $(MGAAPPLET) $(MGAAPPLET)-update-checker $(BINDIR) install -d $(SYSCONFDIR) install -m644 mgaapplet.conf $(SYSCONFDIR)/mgaapplet install -m644 icons/$(NAME)16.png $(ICONSDIR)/mini/$(NAME).png diff --git a/NEWS b/NEWS index 099a8b99..4e4f72d0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +- split mgaapplet-update-checker + (prevents segfault due to mixing glib threads with secular forks) + Version 3.2 - 16 December 2013, Thierry Vignaud - fix crashing when displaying about dialog (mga#12009) diff --git a/mgaapplet b/mgaapplet index 77b6f6dd..ede55a51 100755 --- a/mgaapplet +++ b/mgaapplet @@ -552,22 +552,6 @@ sub installUpdates() { silentCheck(); gtkflush(); } -sub checker_exit { - my ($state) = @_; - POSIX::_exit($comm_codes{$state}{code}); -} - -sub update_backport_media { - my ($urpm) = @_; - # update inactive backport media: - my @inactive_backport_media = Rpmdrake::open_db::get_inactive_backport_media($urpm); - return if !@inactive_backport_media; - log::explanations("updating inactive backport media " . join(', ', @inactive_backport_media)); - foreach (@inactive_backport_media) { - run_program::run('urpmi.update', if_($root, "--urpmi-root=$root"), $_); - } -} - sub silentCheck() { state $check_time; my $new_time = time(); @@ -583,83 +567,8 @@ sub silentCheck() { # are there any updates ? - $checker_pid = fork(); - if (defined $checker_pid) { - return if $checker_pid; # parent - - # immediate exit, else forked gtk+ object destructors will badly catch up parent applet - my $_safe = before_leaving { - my $err = $@; - log::explanations("mgaapplet check crashed: $err "); - warn "Error: $err\n" . common::backtrace(); - POSIX::_exit(0); - }; - - # be nice with other processes: - setpriority(0, $$, 7); # 0 is PRIO_PROCESS - - my $will_not_update_media; - require urpm; - require urpm::lock; - # so that get_inactive_backport_media() doesn't vivify $urpm->{media}: - my $urpm = Rpmdrake::open_db::fast_open_urpmi_db(); - { - local $urpm->{fatal} = sub { - print "Fatal: @_\n"; - $will_not_update_media = 1; - }; - local $urpm->{error} = $urpm->{fatal}; - - urpm::lock::urpmi_db($urpm, 'exclusive', 1); - } - checker_exit('locked') if $will_not_update_media; - - my $is_it_a_devel_distro = is_it_a_devel_distro(); - - my $media = $is_it_a_devel_distro ? '-a' : '--update'; - if (!run_program::run('urpmi.update', $media, if_($root, "--urpmi-root=$root"))) { - checker_exit('error_updating') if $will_not_update_media; - } - - update_backport_media($urpm); - - require urpm::select; - require urpm::media; - # this eats 52Mb of RAM on 64bit: - # (hence we do it in the forked helper so that the applet doesn't eat too much RAM) - urpm::media::configure($urpm, if_(!$is_it_a_devel_distro, update => 1)); - - my @update_medias = get_update_medias($urpm); - - if (!@update_medias) { - checker_exit('no_update_medium'); - } elsif (!any { ! $_->{ignore} } @update_medias) { - checker_exit('no_enabled_medium'); - } - - if (my $_db = urpm::db_open_or_die($urpm)) { - my $requested = {}; - my $state = {}; - my $need_restart = urpm::select::resolve_dependencies( - $urpm, $state, $requested, - callback_choices => sub { 0 }, - priority_upgrade => $urpm->{options}{'priority-upgrade'}, - auto_select => 1, - ); - my @requested_strict = map { scalar $_->fullname } @{$urpm->{depslist}}[keys %{$state->{selected}}]; - - if ($need_restart || @requested_strict) { - # FIXME: log first found pkgs? - warn ">> need_restart=$need_restart, updates=" . join(', ', @requested_strict) . "\n"; - checker_exit('updates'); - } else { - checker_exit('uptodate'); - } - } else { - checker_exit('db_not_open'); - } - checker_exit('updates'); - } else { + $checker_pid = fork_exec('mgaapplet-update-checker', $root); + if (!$checker_pid) { log::explanations("cannot fork: %s", "update checker ($!)"); go2State('critical'); } diff --git a/mgaapplet-update-checker b/mgaapplet-update-checker new file mode 100755 index 00000000..bb852150 --- /dev/null +++ b/mgaapplet-update-checker @@ -0,0 +1,111 @@ +#!/usr/bin/perl +################################################################################ +# Mandriva Online # +# # +# Copyright (C) 2003-2010 Mandriva # +# # +# Daouda Lo # +# Thierry Vignaud # +# # +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU General Public License Version 2 as # +# published by the Free Software Foundation. # +# # +# 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 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. # +################################################################################ +use lib qw(/usr/lib/libDrakX /usr/lib/libDrakX/drakfirsttime); +use standalone; # for explanations +use MDK::Common; +use Rpmdrake::open_db; +use mgaapplet; + +# be nice with other processes: +setpriority(0, $$, 7); # 0 is PRIO_PROCESS + +my $root = $ARGV[0]; + +my $will_not_update_media; +require urpm; +require urpm::lock; +# so that get_inactive_backport_media() doesn't vivify $urpm->{media}: +my $urpm = Rpmdrake::open_db::fast_open_urpmi_db(); +{ + local $urpm->{fatal} = sub { + print "Fatal: @_\n"; + $will_not_update_media = 1; + }; + local $urpm->{error} = $urpm->{fatal}; + + urpm::lock::urpmi_db($urpm, 'exclusive', 1); +} +checker_exit('locked') if $will_not_update_media; + +my $is_it_a_devel_distro = is_it_a_devel_distro(); + +my $media = $is_it_a_devel_distro ? '-a' : '--update'; +if (!run_program::run('urpmi.update', $media, if_($root, "--urpmi-root=$root"))) { + checker_exit('error_updating') if $will_not_update_media; +} + +update_backport_media($urpm); + +require urpm::select; +require urpm::media; +# this eats 52Mb of RAM on 64bit: +# (hence we do it in the forked helper so that the applet doesn't eat too much RAM) +urpm::media::configure($urpm, if_(!$is_it_a_devel_distro, update => 1)); + +my @update_medias = get_update_medias($urpm); + +if (!@update_medias) { + checker_exit('no_update_medium'); +} elsif (!any { ! $_->{ignore} } @update_medias) { + checker_exit('no_enabled_medium'); +} + +if (my $_db = urpm::db_open_or_die($urpm)) { + my $requested = {}; + my $state = {}; + my $need_restart = urpm::select::resolve_dependencies( + $urpm, $state, $requested, + callback_choices => sub { 0 }, + priority_upgrade => $urpm->{options}{'priority-upgrade'}, + auto_select => 1, + ); + my @requested_strict = map { scalar $_->fullname } @{$urpm->{depslist}}[keys %{$state->{selected}}]; + + if ($need_restart || @requested_strict) { + # FIXME: log first found pkgs? + warn ">> need_restart=$need_restart, updates=" . join(', ', @requested_strict) . "\n"; + checker_exit('updates'); + } else { + checker_exit('uptodate'); + } +} else { + checker_exit('db_not_open'); +} +checker_exit('updates'); + +sub checker_exit { + my ($state) = @_; + POSIX::_exit($comm_codes{$state}{code}); +} + +sub update_backport_media { + my ($urpm) = @_; + # update inactive backport media: + my @inactive_backport_media = Rpmdrake::open_db::get_inactive_backport_media($urpm); + return if !@inactive_backport_media; + log::explanations("updating inactive backport media " . join(', ', @inactive_backport_media)); + foreach (@inactive_backport_media) { + run_program::run('urpmi.update', if_($root, "--urpmi-root=$root"), $_); + } +} + -- cgit v1.2.1