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

On a Fedora 22 box I have in rc.local:
#!/bin/sh /var/tmp/DiaPixie.sh & /var/tmp/DiaPixie.pl & exit 0
And the scripts contain:
#!/bin/sh while : ; do r=`wget -O - "http://myip.dtdns.com" 2>/dev/null | head -1` logger -t DiaPixie.sh "Got: $r" sleep 180 done
And:
#!/usr/bin/env perl use strict; use warnings; use LWP::Simple; use Sys::Syslog; while (1) { if( defined(my $Address=get("http://myip.dtdns.com")) ) { syslog("info","Got: $Address") } else { syslog("info","Got: " ) } sleep 180 }
So I'd expect them both to generate similar messages. But the shell script fails to get an address the first time (as we might expect), and the Perl script (when initiated from rc.local) fails every time. What's going on here?

Replies are listed 'Best First'.
Re: Systemd Network Problem
by hippo (Archbishop) on Jun 13, 2015 at 09:59 UTC
    the Perl script (when initiated from rc.local) fails every time. What's going on here?

    The documentation for LWP::Simple includes this gem in the description of get():

    You will not be able to examine the response code or response headers (like 'Content-Type') when you are accessing the web using this function. If you need that information you should use the full OO interface (see LWP::UserAgent).

    So the answer is: "something". If you want to find out more, switch temporarily to full-on LWP and use the additional info available there to determine why the request fails.

    Alternatively, compare the environments between running it in rc.local under systemd and running it in a standard way which by inference I assume works fine for you.

    Final option: run a packet sniffer on the gateway to see the request and response in all their detail.

    Hopefully one of these will work for you. I feel your systemd pain and hope that you can find a suitable simple fix.

Re: Systemd Network Problem
by Anonymous Monk on Jun 13, 2015 at 11:05 UTC

    Problem: when your programs try to resolve a name, glibc caches the contents of /etc/resolv.conf, which may be still empty by the time when /etc/rc.local is run. Wget process is restarted and has a chance to read a valid /etc/resolv.conf with nameservers inside, while your Perl script just runs and doesn't know that resolv.conf was overwritten with valid nameservers.

    Solutions:

    1. (proper) Write a proper unit file for your scripts, so they start after NetworkManager has a working connection to the internet.
    2. Discard NM and use a static resolv.conf which does not change between reboots.
    3. (improper solutions start here) Add some sleep in your rc.local before launching your scripts.
    4. Move sleep 180 to the beginning of the loop, so the first gethostbyname will have a chance to wait for the connection to appear before caching resolv.conf.

      Yup, I already found that inserting an initial sleep would resolve the problem, but I couldn't understand why; now I do! Thanks a million. The code segment is part of the DnsPixie.pl program which you can find at http://www.cpan.org/scripts/. It's intended to update dynamic DNS records when the host address changes. And it actually works well on other (Ubuntu, OpenBSD, Windows-XP, etc.) platforms. So I guess I need to force a cache refresh at each pass? Perhaps by a call to gethostbyname? Or .. ??
        In glibc, there is res_init function to reread resolv.conf. I'm not sure whether it's possible to call it from Perl without writing XS/Inline::C.