Sunday, January 30, 2022

[SOLVED] Is there a better way to detect that my Perl script was called from "firstboot"?

Issue

I have a Perl script that needs to act in a particular way if it was invoked by the firstboot script or invoked by a process that firstboot spawned. I have this routine handleFirstBoot and it seems to work ok, but there is probably better way to write this routine. So please take a look ...

sub handleFirstBoot {
    my $child_id = shift || $$;
    my $parent_id;
    foreach (`ps -ef`) {
        my ($uid,$pid,$ppid) = split;
        next unless ($pid eq $child_id);
        $parent_id = $ppid;
        last;
    }    
    if ( $parent_id == 0 ) {
        debug "firstboot is NOT an ancestor.\n";
        return;
    }    
    my $psout = `ps -p $parent_id | tail -1 |sed -e's/^ //g'| sed -e's/  */ /g'|cut -d' ' -f4`;
    if ( $psout =~ /firstboot/ ) {
        debug "firstboot IS an ancestor. Set post option.\n";
        $opt{'post'} = 1; 
        return;
    } else {
        # recursive case
        handleFirstBoot($parent_id);
    }    
}

Solution

Can I offer an alternative approach - from the comments, the problem you are trying to solve is a startup script stalling because it's waiting for this one to return.

So can I suggest that fork() is probably your friend here?

 my $pid = fork(); 
 if ( $pid ) { 
     exit; 
 }
 sleep $delay_time; 
 do_stuff(); 

What will happen is - your script will be called, and the caller will return immediately, but a parallel instance will spawn and delay the random delay interval - and for bonus points, this will work the same in cron too.

But as you seem to note in the comments - the 'good' solution is not to do it that way at all - I would suggest that looking at say, anacron which is available on most Linux systems would be exactly the tool for this particular job.



Answered By - Sobrique
Answer Checked By - Candace Johnson (WPSolving Volunteer)