#!/usr/bin/perl main( @ARGV ); exit; sub main { $DEBUG = grep /-d/, @ARGV; my $user = ( scalar grep !/^-/, @ARGV ) ? ( ( grep !/^-/, @ARGV )[0] ) : $ENV{'USER'}; my $ps = user_ps( $user ); unlink "/home/$user/.gnome/session"; my @to_kill; do { for ( [ zombies => sub { grep $_->{'status'} =~ /Z/, @_ } ], [ firefox => sub { grep $_->{'command'} =~ /firefox/, @_ } ] ) { my ( $name, $filter ) = @$_; @to_kill = $filter->( @$ps ); killall( \ @to_kill, $ps ); } } until not @to_kill; 1; } sub killall { my @to_find = @{ shift() }; my @ps = @{ shift() }; my %pids; my %rel; for ( @ps ) { $pids{$->{'pid'}} = 1; $rel{$_->{'pid' }}{$_->{'ppid'}} = 1; $rel{$_->{'ppid'}}{$_->{'pid' }} = 1; } my %seen; my @to_kill = map $_->{pid}, @to_find; { my $changed = 0; do { my @n = grep !$seen{$_}++, grep $pids{$_}, map keys(%$_), grep ref(), delete @rel{ @to_kill }; push @to_kill, @n; $changed = scalar @n; } while $changed; } for my $sig ( qw[ INT TERM KILL ] ) { if ( @to_kill ) { my $cmd = "kill -$sig @to_kill"; if ( $DEBUG ) { print STDERR "$cmd\n"; } system $cmd; @to_kill = grep kill(0,$_), @to_kill; } if ( @to_kill ) { sleep 5; } } return 1; } sub all_user_ps { [ map { ! /(\S+)\s+(\S+)\s+(\S+)\s+(.+)/ ? () : +{ pid => $1, ppid => $2, status => $3, command => $4 } } split /[\r\n]+/, `ps a } sub user_ps { my $user = shift; [ map { ! /(\S+)\s+(\S+)\s+(\S+)\s+(.+)/ ? () : +{ pid => $1, ppid => $2, status => $3, command => $4 } } split /[\r\n]+/, `ps -U $user -o pid=,ppid=,s=,comm= --sort=pid,ppid` ]; }