Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Killing clones for fun and profit

by CheeseLord (Deacon)
on Jul 06, 2001 at 00:43 UTC ( [id://94270]=perlquestion: print w/replies, xml ) Need Help??

CheeseLord has asked for the wisdom of the Perl Monks concerning the following question:

Like many other users of Windows, my computer crashes frequently. I've gotten to the point where I don't really mind it all that much, but I spend a great deal of time logged into my account at school from my home computer, and when my comp crashes, I remain logged in. I know after a while these logins will (hopefully) be killed off, but I'm impatient. So I harnessed the power of Perl to find a way to kill these clones so that I don't appear to have 14 terminals open at a time. My code follows:

#!/usr/bin/perl -w use strict; my $prog = (split "\/", $0)[-1]; die "Usage: $prog\n" if @ARGV; my $user = getpwuid $<; my @results = `ps -ef`; chomp @results; shift @results; # remove header my @listing; for (@results) { if (m|^([\w\d]+) \s+ (\d+) \s+ (\d+) \s+ (\d+) \s+ ([\w\d:]+) \s+ ([\w\d/?]+) \s+ ([\w\d:]+) \s+ (.*)$|x) { my $hashref = {}; $$hashref{'uid'} = $1; $$hashref{'pid'} = $2; $$hashref{'ppid'} = $3; $$hashref{'c'} = $4; $$hashref{'stime'} = $5; $$hashref{'tty'} = $6; $$hashref{'time'} = $7; $$hashref{'cmd'} = $8; push @listing, $hashref; } else { warn "$prog: Could not process line! Line follows:\n$_\n"; next } } # My thinking: when run from the shell, this process' ppid will be the # pid of my shell. Problem is, what happens when it's not run from the # shell (say, run through vi's ":!killclone")? my $ppid = (grep {$$_{'pid'} eq $$} @listing)[0]->{'ppid'}; @listing = grep {$$_{'uid'} eq $user} @listing; # Just mine @listing = grep {$$_{'cmd'} =~ /^-/} @listing; # Just login shells @listing = grep {$$_{'pid'} ne $ppid} @listing; # Not this shell for (@listing) { kill 9, $$_{'pid'} }

It seems to be working fine, but there is the problem I note in the comments above "my $ppid". I'd like to know how to solve that, as well as any of your suggestions on other things I should have done, or places my logic is just shot. Also, I know that the dot-star in the regex isn't looked upon all that highly here at PM, but I think that it's the right tool for this, as I really do want everything to the end of the line... I think. :) Anyway, thanks in advance for your help.

Note: While I appreciate the awesomeness of CPAN, CPAN modules would be a less-than-ideal solution, as I don't have access to do a real install, and I don't have all that much room on this account. But, if it would significantly improve things, I'm always open to clearing space for a module.

His Royal Cheeziness

Replies are listed 'Best First'.
Re: Killing clones for fun and profit
by tadman (Prior) on Jul 06, 2001 at 00:52 UTC
    First thing, if your process has a $ppid, then that process might also have a $ppid. You can trace your way up to the real parent process that way. I'm pretty sure that's how it works.

    Secondly, "dot star" is a real issue because it does things you don't expect it to when it gets really greedy, which is why there is postings like Death to Dot Star! Since you're using it as the last thing in your expression, you should be okay. It's when you put it in the middle that it can wreak havok on your data.
Re: Killing clones for fun and profit
by blakem (Monsignor) on Jul 06, 2001 at 02:53 UTC
    Interesting... Another solution to this is to run screen on the remote machine. I highly recommend it as a solution to buggy client machines, or dropped dial-up connections. It allows you to resume a terminal session exactly where you left it before you dropped off the machine.

    -Blake

      Screen is the best!! I use it all the time and it's never let me down. I made a mini-tutorial, which includes a pretty basic overview of screen here.

Re: Killing clones for fun and profit
by PrakashK (Pilgrim) on Jul 06, 2001 at 02:57 UTC
    Instead of:
    my @results = `ps -ef`;
    you could do:
    my @results = `ps -fu $user`;
    This should give you only your processes and eliminates one of your filters.

    TO check if the parent process is a shell or not, check the command part of the process info, which should be the basename of your $SHELL value. If not, you would have to go for its parent until you find the real shell.

    Also, I would use a hash instead of an array for the list of process hashrefs.

    Anyway, here is some (untested) changes to your code:

    #!/usr/bin/perl -w use strict; my $prog = (split "\/", $0)[-1]; die "Usage: $prog\n" if @ARGV; my $user = getpwuid $<; my @results = qx{/bin/ps -fu $user}; chomp @results; shift @results; # remove header my %listing; for (@results) { if (m|^([\w\d]+) \s+ (\d+) \s+ (\d+) \s+ (\d+) \s+ ([\w\d:]+) \s+ ([\w\d/?]+) \s+ ([\w\d:]+) \s+ (.*)$|x) { my $hashref; $$hashref{'uid'} = $1; $$hashref{'pid'} = $2; $$hashref{'ppid'} = $3; $$hashref{'c'} = $4; $$hashref{'stime'} = $5; $$hashref{'tty'} = $6; $$hashref{'time'} = $7; $$hashref{'cmd'} = $8; $listing{$pid} = $hashref; } else { warn "$prog: Could not process line! Line follows:\n$_\n"; next } } my ($shell) = ($ENV{SHELL} =~ m{([^/]*)$}; # get the basename of the s +hell my $pid = $$; my $ppid = $listing{$pid}->{ppid}; while ($listing{$ppid}->{cmd} !~ m/$shell$/;) { $pid = $ppid; $ppid = $listing{$pid}->{ppid}; } # $ppid should have the current shell's pid for my $pid (keys %listing) { kill 9, $pid unless $listing{$pid}->{cmd} =~ m/^-/ and $pid != $ppid; }
    /prakash

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://94270]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (3)
As of 2024-04-26 06:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found