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

I have a perl program that is starting multiple quake3 servers. They are all running on different ports and can be recognized by what game type they are running (eg. capture the flag, or teamplay). How would I use the perl program to recognize specific pid's of each game? I may want to stop/kill the Capture the Flag server for example, but leave the teamplay one alone.
You would get something like this:
linux/djw # ps ax|grep [q]3ded 2894 pts/0 R 0:32 ./q3ded +exec ctf.cfg 2899 pts/0 R 0:25 ./q3ded +exec tourney.cfg 2904 pts/0 R 0:12 ./q3ded +exec team.cfg
Could I have the pid's written to files in /var/run/quake3 for example? Maybe I could use file names like: ctf.pid, tourney.pid etc. to seperate them?

Any ideas on how that is done? Using Linux.

Thanks,
djw

Replies are listed 'Best First'.
Re: working with pid's
by vaevictus (Pilgrim) on Sep 18, 2000 at 17:22 UTC
    Well... this is not entirely a perl solution, but it's something you should consider... Make virtual links "ln -s filename linkname" to q3ded (or copies), in the same directory...
    Call them q3ctf q3tourney q3team... then execute them with these alternate names. The program will execute the same, but you can use commands like killall .
    Furthermore, if at this point you'd wish to use perl, it becomes easier to distinguish between the different games, based on actual process name. a simple open (GAMES,"ps cax|grep $gamename|awk '{print $4}' |"); should list your game. (the awk command may vary, if your columns are set up differently in ps). that way you could just
    @games=<GAMES>; foreach $running_game (@games) { print "some sort of menu here maybe.\n or maybe a webpage.<br>"; #or maybe just system ("killall -$signal $running_game");") }
    Alternatively, you can drop the awk, and easily collect the PID and other info.
Re: working with pid's
by Maqs (Deacon) on Sep 18, 2000 at 17:34 UTC
    you may use rather pidfiles and read them or do ps lookups as shown below
    note: this code was not hardly tested:
    my %name2pid; @qpids = `ps -aux | grep q3ded`; foreach $qpid (@qpids){ ($pid, $name)=(split /\s/, $qpid)[0,-1] $name=~s/^(.*)\..*/$1/; $name2pid{$name}=$pid;
    now %name2pid contains pairs "servername<->pid" and you can manupulate them
    i.e. $name2pid{'ctf'} gives you ctf server's pid number.

    /Maqs.
Re: working with pid's
by cianoz (Friar) on Sep 18, 2000 at 17:56 UTC
    you could execute your server process with something like that:
    #!/usr/bin/perl -w use File::Basename; my ($daemon, @args) = @ARGV; my $pid; if($pid =fork()) { # i am parent.. my $dname = basename($daemon); # maybe here you prefer # my $dname = basename($args[1]) . '.pid'; open PIDFILE, ">/var/run/$dname" || die "cannot write pid file"; print PIDFILE $pid; close PIDFILE; } else { exec($daemon, @args) || die "cannot execute $daemon: $!"; }
    if you are under redhat you should use "daemon()" from an init script (it's a shell function)
    why reinvent the weel?
RE: working with pid's
by moen (Hermit) on Sep 18, 2000 at 17:36 UTC
    Of course if you want to invent the wheel again go ahead, but you got an excellent tool in the daemontools package by D. J. Bernstein that do just that, namely supervise. I use it myself on qmail and my halflife server ;o) If you want do do this in perl you may try something like this:
    #!/usr/bin/perl -w open(PH, "ps -A|"); while (<PH>) { if (/q3ded/) { /\b(\d+)\b/; $pid = $1; } } print $pid;
    It will at least return the pid, and you can do whatever you like with it.
      oopps..that was wrong code :) This is correct.
      Update!!: I just now saw that you also needed the names so, here's an edit.
      #!/usr/bin/perl -w use strict; my(%list); open(PH, "ps aux|"); while (<PH>) { if (/q3ded/) { /\b(\d+)\b.*:(.{3})(.*)/; $list{$1} = $3; } } close(PH); foreach (keys %list) { print $_, " ", $list{$_}, "\n"; }
Re: working with pid's
by kilinrax (Deacon) on Sep 18, 2000 at 17:35 UTC
    Not sure if i'm missing something, but I'm pretty sure the following will work:
    @processes = map { (m@^(\d+)\s+\S+\s+\w+\s+[\d:]+\s+(.+)$@) && ($proce +ss = $1) && ($name = $2) && ($name =~ /q3ded/) \&& ($name =~ /\+exec +$type/) ? $process : () } `ps ax`;
    Simply set $type to the name of the config file
    Have fun ;-)
RE: working with pid's
by Anonymous Monk on Sep 19, 2000 at 16:48 UTC
    You seem to be misunderstanting the diference between call multiple process from batch and spawning child processes from a parent (Independent Processes vs. Process with Child).

    What you described can be best done with creating child processes. You need to learn about Inter Process Communication (IPC). Buy Programming Perl from O'Reilley and read from pg 343 through end of chapter very carefully.

    Good luck,

    Yussef

    Edit kudra, 2001-12-17 Added breaks; merged with near-duplicate update attempt

      I have it and I'll take a look.

      Thanks,
      djw