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

Oh Wise Perl Ones;
I have searched the lovely net high and low and I cannot find any perl code to split a ps aux (linux system) into an array.

I'm consulting for a small ISP that uses sendmail. We are being hammered by spammers, so I felt a perl solutions would be more than sufficient. What I'm attempting to do is monitor /var/log/messages for the hoards of "User unknown" messages resulting from name-list spam techniques. The messages log contains the pid of the sendmail process in question. I can then run a ps aux, match up the pid, and get the IP of the spammer, so that I can then add it to my firewall's block list.

This sounds like a fairly simple job for perl, however I am running into extreme difficulty splitting the ps aux into a usable format. Proc::ProcessTable is incredibly poorly documented, so it has been of little aid to this point. Here is a sample of a line from ps aux that I would need to extract the IP address from:

root 27979 0.0 0.7 1468 1008 ? S 14:59 0:00 sendmail: s +erver foo.bar.org [222.22.22.21] cmd read

Any suggestions for handling the ps aux and extracting the IP would be greatly appreciated!

-Jerry http://www.digilliance.net

Replies are listed 'Best First'.
Re: ps aux and perl
by c (Hermit) on Aug 21, 2001 at 23:15 UTC
    I am sincerely not discouraging you from continuing down the path you are going, however one thing you might want to look into is checking to verify that the information you are wanting to parse is located within /var/log/messages or /var/log/maillog. If sendmail is logging conversations to the latter, you can use perl to read over the last n lines of that (much more specific) log and take action.
    If you're looking for a good base on what others have done for the goal you're aiming towards, take a look at spamshield, which although not perfect could give you a good base to work up from.
    Sorry for not answering your question directly, but I've been in your shoes and I think there might be a less intensive way to do it.

    humbly -c

Re: ps aux and perl
by lemming (Priest) on Aug 21, 2001 at 23:19 UTC
    Some pseudo code:
    open pipe from ps aux, perhaps after grepping for sendmail while(<PIPE>) { my ($owner, $pid, undef, undef, undef, undef, undef, undef, undef, undef, # Throw +eight values away $command_withIP) = split(' ', $_, 11); Do stuff }

    Update: What c suggests is a good path to take, especially since the ps table is rather transitory. You won't be sure of having a pid match. If the log doesn't have the IP address, I'm sure that can be set via sendmail.cf. You may also want to look into /etc/mail for some more clues.

    Update2: thank you bbfu

      I assume that the 'j' in $j[1..8] stands for 'junk'... If you're actually going to not use those variables, you might consider using the following idiom to reduce the number of unused lexical variables created, 'variable used only once' warnings, and typing. ;)

      my ($owner, $pid, (undef) x 8, $command_withIP) = split(' ', $_, 11);

      Anyway, it's just a thought. Take it or leave it. :-)

      Update: D'oh! Forgot necessary spaces around the x operator. Thanks lemming. :-)

      bbfu
      Seasons don't fear The Reaper.
      Nor do the wind, the sun, and the rain.
      We can be like they are.

      When I run this code, $command_withIP contains the whole line, not the command with ip. For some reason, the splits ppl recommend don't seem to work at all.

      -Jerry
      http://www.digilliance.net

Re: ps aux and perl
by Cine (Friar) on Aug 21, 2001 at 23:34 UTC
    c has a good point, but didnt answer your question.
    @arr = split /\s+/,'root 27979 0.0 0.7 1468 1008 ? S 14:5 +9 0:00 sendmail: server foo.bar.org [222.22.22.21] cmd read';
    Should do it.

    T I M T O W T D I
      I saw a post recommending that code earlier... I wrote a small script using it:

      #!/usr/bin/perl @arr = split /\s+/, 'root 30341 0.0 0.7 1468 1008 ? S 15:4 +4 0:00 sendmail: server IDENT:root@bar.foobar.es [212.7.33.22] cmd +read'; foreach($var, @arr) { print "$var\n"; }

      All it returns is approximately 14 blank lines. Any ideas? -Jerry
      http://www.digilliance.net

        Yes.
        @arr = blablabla... foreach my $var (@arr) { print "$var\n"; }
        Good advise: Always use strict and always have warnings ON.

        T I M T O W T D I
Re: ps aux and perl
by Beatnik (Parson) on Aug 21, 2001 at 23:31 UTC
      Yes I have....
      as I said in my initial post, I have been unable to use it because it is so poorly documented. If you care to explain it a bit more, or point me to some better doc than CPAN has, I'd be very interested.

      -Jerry
      http://www.digilliance.net