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

Goal: fork Linux daemon from Perl script, save it's PID and use PID to stop daemon later. Daemon started by usual fork/exec pair. Problem: in Perl script fork returns PID of new process. Then started daemon forks another one process, redirect input/output to /dev/null and become daemon itself. And of course PID changed because of internal fork in daemon. So, result is - daemon is running but it's PID is different from saved in Perl script. How to get right PID on fork of daemon? I can't find it by myself, but I think that answer should exist. Perl and daemons are widely used, I don't believe that no one worked on this problem.
  • Comment on Fork daemon from Perl script and save it's PID. How to do it right?

Replies are listed 'Best First'.
Re: Fork daemon from Perl script and save it's PID. How to do it right?
by gone2015 (Deacon) on Nov 26, 2008 at 10:02 UTC

    So, we have a parent process that has spawned a child process, which has in turn spawned a grandchild.

    And the problem is that the grandparent doesn't even know the name of the grandchild. The child process doesn't call and it doesn't write. Nothing. (Is that not always the way ?)

    Now, I'm not an expert on family counselling, but it seems to me that the problem here really is communication. I know that sounds like a cliche. But like many cliches, there's a kernel of truth hidden in it. See if you can somehow persuade the grandparent and child to talk to each other... then the joy of the grandchild can surely be shared.

    I'm also not an expert on interprocess communication, so I'm guessing that my first thought -- email -- is probably too elaborate. Some form of pipe, perhaps ? perlipc

      I think about communication too. But there is no way to change behaviour of child. Actually I'm trying to fork DHCP daemon provided with SUSE10. Of course I can rewrite and recompile it but I have to support default binary and be able to provide my Perl script to any user of SUSE10 and it must work. Is there any way to handle starting/stopping of standard system daemons?
        Is there any way to handle starting/stopping of standard system daemons?
        On Debian that's simply /etc/init.d/daemonname start|stop, I'm sure that suse offers a similar way.

        A more low-level approach is to use start-stop-daemon directly.

Re: Fork daemon from Perl script and save it's PID. How to do it right?
by jonadab (Parson) on Nov 26, 2008 at 13:13 UTC

    It sounds to me like you're trying to do things with this program that it was fundamentally not designed to do. You want to control its processes manually from the outside, but it was clearly designed to handle them automatically internally. You want to separately manage multiple instances of it, but if it's an even vaguely typical Unix daemon (other than getty) it's probably either designed to only ever have one instance, or else to fork (or even prefork) as many processes as it needs automatically.

    Perl and daemons are widely used, I don't believe that no one worked on this problem.

    I think everything is working exactly as it was designed to work, but you're trying to change the design for how the program (the daemon) is supposed to work, and you want to do that without changing the program itself. Good luck with that.

    -- 
    We're working on a six-year set of freely redistributable Vacation Bible School materials.
Re: Fork daemon from Perl script and save it's PID. How to do it right?
by almut (Canon) on Nov 26, 2008 at 14:35 UTC

    An often overlooked concept are process group IDs.  Just create a new process group before you fork. Then, independently of how many children are being forked, and how deep their fork/exec level gets, you can address all of them in one go.  A short demo:

    #!/usr/bin/perl my $sid = getppid; # for the 'ps' only if (my $pid = fork()) { sleep 1; # wait somewhat until tree of children is set up # show related processes system "ps f -s $sid -o pid,ppid,pgrp,sid,cmd"; # kill process group after timeout sleep 5; kill -9, $pid; wait; print "killed children\n"; # show remaining processes system "ps f -s $sid -o pid,ppid,pgrp,sid,cmd"; # do something else... sleep 5; } elsif (defined $pid) { # create new process group setpgrp; # run something (consisting of several processes) that hangs system 'bash -c "cat; echo"'; exit; } else { die "couldn't fork"; } __END__ Sample output: $ ./726031.pl PID PPID PGRP SID CMD 29171 29169 29171 29171 bash -rcfile .bashrc 508 29171 508 29171 \_ /usr/bin/perl ./726031.pl 509 508 509 29171 \_ /usr/bin/perl ./726031.pl 510 509 509 29171 | \_ bash -c cat; echo 511 510 509 29171 | \_ cat 512 508 508 29171 \_ ps f -s 29171 -o pid,ppid,pgrp,sid,cmd killed children PID PPID PGRP SID CMD 29171 29169 29171 29171 bash -rcfile .bashrc 508 29171 508 29171 \_ /usr/bin/perl ./726031.pl 513 508 508 29171 \_ ps f -s 29171 -o pid,ppid,pgrp,sid,cmd

    As you can see in the PGRP column, the three child processes in question all belong to the same process group (here 509). The single kill addressed to this group gets rid of all three processes.

    The only issue you might run into is when some process further down the line itself creates another new process group. But as the concept is largely unknown/unused, the chances you'll encounter that problem in practice are rather low :)  At least, it's worth a try.

Re: Fork daemon from Perl script and save it's PID. How to do it right?
by cdarke (Prior) on Nov 26, 2008 at 13:04 UTC
    Many daemons save their pid in a file, check /var/run/dhcpd.pid.

      Yeah, usually daemon is able to save its pid into file, also many of them allow to specify name of the pid file as comand line option, e.g inetd -p /var/run/inetd.pid. So you can create temporary file using File::Temp, fork and exec daemon with such option, so you can run multiple instances of daemon and each will use its own pid file.

      Another approach is to use option that prevents daemon from forking if it has one.