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

I have an issue to figure out. I need to come up with a way to track process demons, if stopped to restart it and if started to stop it. Does anyone have any clues on how I can go about this.
curtisb --> "Please help!!!!!!"

Replies are listed 'Best First'.
Re: Where do I begin????
by arhuman (Vicar) on Mar 19, 2001 at 16:15 UTC
    Could you please tell us on what platform you're planning to work
    (or if it should be multiplatform)
    for the best module for the task heavily depends on the platform constraints...

    (A CPAN search will give you tons of possibilities :
    Proc::ProcessTable, Mac::Processes, Win32::Process, Watchdog::Process...)

    UPDATE (After the Unix AND windows constraint):

    I've search in my memories and in CPAN archives, i didn't find a portable module/way to do so on these 2 OS.

    So what I suggest is either use external programs (very dirty...) : you'll set up its path/name dependng on the platform your code is running on. (ps/kill , prcview...)

    The cleanest way IMHO would be to do the same using 2 modules (Win32::Process and Proc::ProcessTable)

    To help you, here are some examples (from the freely downloadable 'Perl for system administration' code examples see O'REILLY SITE) :
    #Example code from Perl for System Administration by David #N. Blank-E +delman #O'Reilly and Associates, 1st Edition, ISBN 1-56592-609-9 #* #* show the process list on NT/2000 using PULIST from the NT Resource +Kit #* $pulistexe = "\\bin\\PULIST.EXE"; # location of the executable open(PULIST,"$pulistexe|") or die "Can't execute $pulistexe:$!\n"; scalar <PULIST>; # drop the first title line while(defined($_=<PULIST>)){ ($pname,$pid,$puser) = /^(\S+)\s*(\d+)\s*(.+)/; print "$pname:$pid:$puser\n"; close(PULIST); ------- #* #* show the list of process ids and names under NT/2000 using Win32::I +Proc #* use Win32::IProc; $pobj=new Win32::IProc or die "Unable to create process object: $!\n"; $pobj->EnumProcesses(\@processlist) or die "Unable to get process list:$!\n"; foreach $process (@processlist){ $pid = $process->{ProcessId}; $name = $process->{ProcessName}; write; } format STDOUT_TOP = Process ID Process Name ========== =============================== . format STDOUT = @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $pid, $name . ------- #* #* show the process time info under NT/2000 using Win32::Iproc #* use Win32::IProc qw(PROCESS_QUERY_INFORMATION INHERITED DIGITAL); $pobj = new Win32::IProc; $pobj->Open($ARGV[0],PROCESS_QUERY_INFORMATION,INHERITED,\$handle) or warn "Can't get handle:".$pobj->LastError()."\n"; # DIGITAL = pretty-printed times $pobj->GetStatus($handle,\$statusinfo,DIGITAL); $pobj->CloseHandle($handle); while (($procname,$value)=each %$statusinfo){ print "$procname: $value\n"; } ------- #* #* show the process ids and names under NT/2000 using Win32::Setupsup #* use Win32::Setupsup; $machine = ""; # query the list on the current machine Win32::Setupsup::GetProcessList($machine, \@processlist, \@threadlist) + or die "process list error: ".Win32::Setupsup::GetLastError()."\n"; pop(@processlist); # remove the bogus entry always appended to the lis +t foreach $processlist (@processlist){ $pid = $processlist->{pid}; $name = $processlist->{name}; write; } format STDOUT_TOP = Process ID Process Name ========== =============================== . format STDOUT = @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $pid, $name . ------- ------- #* #* retrieve a WMI Win32_Process object (the hard way) #* use Win32::OLE('in'); $server = ''; # connect to local machine # get a SWbemLocator object $lobj = Win32::OLE->new('WbemScripting.SWbemLocator') or die "can't create locator object: ".Win32::OLE->LastError()."\n"; # set the impersonate level to "impersonate" $lobj->{Security_}->{impersonationlevel} = 3; # use it to get a an SWbemServices object $sobj = $lobj->ConnectServer($server, 'root\cimv2') or die "can't create server object: ".Win32::OLE->LastError()."\n"; # get the schema object $procschm = $sobj->Get('Win32_Process'); ------- #* #* retrieve a WMI Win32_Process object (the easy way) #* use Win32::OLE('in'); $procschm = Win32::OLE->GetObject( 'winmgmts:{impersonationLevel=impersonate}!Win32_Process') or die "can't create server object: ".Win32::OLE->LastError()."\n +"; ------- #* #* show the properties and methods of the Win32_Process object by quer +ying #* the schema #* use Win32::OLE('in'); # connect to namespace, set the impersonate level, and retrieve the # Win32_process object just by using a display name $procschm = Win32::OLE->GetObject( 'winmgmts:{impersonationLevel=impersonate}!Win32_Process' +) or die "can't create server object: ".Win32::OLE->LastError()."\n +"; print "--- Properties ---\n"; print join("\n",map {$_->{Name}}(in $procschm->{Properties_})); print "--- Methods ---\n"; print join("\n",map {$_->{Name}}(in $procschm->{Methods_})); ------- #* #* retrieve the list of currently running processes using WMI under NT +/2000 #* use Win32::OLE('in'); # perform all of the initial steps in one swell foop $sobj = Win32::OLE->GetObject( 'winmgmts:{impersonationLevel=impersonate}') or die "can't create server object: ".Win32::OLE->LastError()."\ +n"; foreach $process (in $sobj->InstancesOf("Win32_Process")){ print $process->{Name}." is pid #".$process->{ProcessId},"\n"; } ------- #* #* retrieve the process id/user list under UNIX by looking at /proc #* opendir(PROC,"/proc") or die "Unable to open /proc:$!\n"; while (defined($_= readdir(PROC))){ next if ($_ eq "." or $_ eq ".."); next unless /^\d+$/; # filter out any random non-pid files print "$_\t". getpwuid((lstat "/proc/$_")[4])."\n"; } closedir(PROC); ------- #* #* retrieve a list of process ids/owners under UNIX using Proc::Proces +sTable #* use Proc::ProcessTable; $tobj = new Proc::ProcessTable; $proctable = $tobj->table(); for (@$proctable){ print $_->pid."\t". getpwuid($_->uid)."\n"; } ------- #* #* look and log processes named "eggdrop" under UNIX #* use Proc::ProcessTable; open(LOG,">>$logfile") or die "Can't open logfile for append:$!\n"; $t = new Proc::ProcessTable; foreach $p (@{$t->table}){ if ($p->fname() =~ /eggdrop/i){ print LOG time."\t".getpwuid($p->uid)."\t".$p->fname()."\n"; } } close(LOG); ------- #* #* collect stats on running processes under UNIX and dump them once an + hour #* use Proc::ProcessTable; $interval = 600; # sleep interval of 5 minutes $partofhour = 0; # keep track of where in hour we are $tobj = new Proc::ProcessTable; # create new process object # forever loop, collecting stats every $intervar secs # and dumping them once an hour while(1){ &collectstats; &dumpandreset if ($partofhour >= 3600); sleep($interval); } # collect the process statistics sub collectstats { my($process); foreach $process (@{$tobj->table}){ # we should ignore ourself next if ($process->pid() == $$); # save this process info for our next run push(@last,$process->pid(),$process->fname()); # ignore this process if we saw it last iteration next if ($last{$process->pid()} eq $process->fname()); # else, remember it $collection{$process->fname()}++; } # set the last hash using the current table for our next run %last = @last; $partofhour += $interval; } # dump out the results and reset our counters sub dumpandreset{ print scalar localtime(time).("-"x50)."\n"; for (sort reverse_value_sort keys %collection){ write; } # reset counters undef %collection; $partofhour = 0; } # (reverse) sort by values in %collection and by key name sub reverse_value_sort{ return $collection{$b} <=> $collection{$a} || $a cmp $b; } format STDOUT = @<<<<<<<<<<<<< @>>>> $_, $collection{$_} . format STDOUT_TOP = Name Count -------------- ----- . -------

    "Trying to be a SMART lamer" (thanx to Merlyn ;-)
      This will be for both windows and UNIX platforms.
      Thanks
      curtisb
Re: Where do I begin????
by busunsl (Vicar) on Mar 19, 2001 at 16:14 UTC
    Have a look at freshmeat.net
    There is a tool called 'mon', that can do this kind of stuff (and a lot more).
Re: Tracking process daemons
by AgentM (Curate) on Mar 19, 2001 at 20:26 UTC
    There is a horrendously simple way to do this under UNIX. Let the watchdog process fork the daemon with a full-duplex pipe (or two half-duplex pipes). Let one get the read end and the other the write end. At the beginning of each program, select the handles for reading/writing (appropriately) but don't send anything on the pipes. If your select ever returns values during the process (you could even use asynchronous IO to skip threading- just DON'T POLL!!!), you know the other is down and an error has occcured somewhere. This way you have the watchdog watching the daemon and the daemon watching the watchdog. If the daemon fails, refork it and log the error. If watchdog fails, log the error and cleanly quit the daemon. Obviously, it becomes extremely important to have a bug-free, non-deprecated watchdog. Good luck!
    AgentM Systems nor Nasca Enterprises nor Bone::Easy nor Macperl is responsible for the comments made by AgentM. Remember, you can build any logical system with NOR.

      Note that you can do this same trick under Win32 if you substitute a socket for the pipe (well, and I wouldn't suggest using fork directly for either case).

              - tye (but my friends call me "Tye")