1

I am using a Raspberry Pi4 with Linux raspberrypi 4.19.58-v7l+ #1245 SMP Fri Jul 12 17:31:45 BST 2019 armv7l GNU/Linux.

I have a service that starts a C++ program. This program starts a script, reads content from some files and outputs information on a RGB LED Display.

This is the script:

#!/bin/bash

line=$(head -n 1 /var/www/html/configuration.txt)
file=/var/www/html/4panel/url_response.txt
if [ -f "$file" ]; then
    wget -q -i $line -O $file 
    chown pi:pi $file
else
    echo > $file
    chown pi:pi $file 
fi

I need to do wget periodically because that URL sends the information that I need to output on the Display. In order to do this, I call this script from inside the C++ program with:

system("/var/www/html/4panel/get_page.sh");

But after some time url_response.txt gets empty and remains empty until I restart the service. Meaning that the script isn't working properly.

This is the service:

[Unit]
Description=PPD_Display service
After=multi-user.target

[Service]
ExecStart=/var/www/html/4panel/Big_ppd_display_try1

[Install]
WantedBy=multi-user.target

A weird thing that I've noticed is that the script runs two times, and maybe that's why it stops working properly:

root     26849  0.0  0.0   1940   364 ?        S    12:55   0:00 sh -c /var/www/html/4panel/get_page.sh
root     26850  0.0  0.1   7808  2580 ?        S    12:55   0:00 /bin/bash /var/www/html/4panel/get_page.sh

And if that is not the problem, then why does the script just stops working correctly if the service is still running ?

3

You should analyse the exit code wget is returning: this will allow you to tell if it's a file IO problem, a network problem, etc. You should also use --timeout=seconds to make sure wget won't sit there indefinitely waiting for a connection.

Having two processes is quite normal, as you use system() which executes a command using /bin/sh, and your script says in the first line that it wants to be executed with /bin/bash, so /bin/sh has no other option but to start a sub-process to run it. It shouldn't be a problem.

A lot of potential issues with file permissions, interlocking and process handling could be avoided if you just used libcurl to read the HTTP stream directly into your C++ program's memory buffer.

  • How could I do the same thing that the script does in C++ ? How would a simple example that gets content from the URL look like ? – bleah1 Sep 16 at 11:23
  • Also, I've been trying $? = 'wget -q -i "$line" -O $file --timeout=2' echo "$?" and it returns command not found and 127 – bleah1 Sep 16 at 11:25
  • I've done it like this: wget_output=$(wget -q -i "$line" -O $file) echo "$?" and it returns 0 – bleah1 Sep 16 at 11:36
  • The very first example in libcurl tutorial shows how to get a page from http://domain.com/. And you don't need to (and can't) assign assign anything to $?, that variable is set automatically by the shell after each command. – Dmitry Grigoryev Sep 16 at 11:37
  • 1
    @bleah1 You should be able to use the bash script. My point is, depending on the robustness you need, you may actually spend less time studying libcurl, compared to debugging all the edge cases in the script. – Dmitry Grigoryev Sep 16 at 12:36
2

The real issue was that wget would occasionally wait to read data from the URL. It's default read timeout is 900 seconds, which froze/paused the service making it appear like it crashed. Or it would just return 4 , which means Network Failure and wait indefinitely.

Thanks to @Dmitry Grigoryev I have added a simple --timeout=2 which will tell wget to wait 2 seconds instead of 900 or indefinitely, effectively solving my issue.

This is how the script looks like now:

#!/bin/bash

line=$(head -n 1 /var/www/html/configuration.txt)
file=/var/www/html/4panel/url_response.txt
if [ -f "$file" ]; then
    wget -q -i "$line" -O $file --timeout=2
else
    echo > $file
    chown pi:pi $file 
fi
  • Hey, I'm glad you figured it out! And BTW, wget has a default read timeout of 900 seconds. On a network failure, it will wait indefinitely AFAIK. – Dmitry Grigoryev Sep 18 at 9:03
1

I agree with @DmitryGrigoryev to use libcurl in the C++ program and handle everything there without a shell script because of robustness. But because you still asked in a comment: "So there is no way of debugging that stupid script ?" I will give this answer how I would do it.

I would execute the shell script directly with a service. So you can verify if the problem is the script or the C++ program. Because you want to execute wget periodically I would make a sleep loop like this:

#!/bin/bash
LINE=$(/usr/bin/head -n 1 /var/www/html/configuration.txt)
FILE=/var/www/html/4panel/url_response.txt
SLEEPTIME=60
while true; do
    if [ -f "$FILE" ]; then
        /usr/bin/wget -q -i $LINE -O $FILE
    else
        echo > $FILE
    fi
    /bin/chown pi:pi $FILE
    /bin/sleep $SLEEPTIME
done

This will wget every minute. You may modify SLEEPTIME. Now just replace ExecStart in the unit file with:

ExecStart=/var/www/html/4panel/get_page.sh

Now you can see if the script runs stable for a long time. You can check journalctl -b -e for output or restricted to the service:

rpi ~$ systemctl status my_wget_test.service
rpi ~$ journalctl --unit=my_wget_test.service

Stop the service with systemctl stop my_wget_test.service.

  • libcurl does seem nice, but it would take some time to start and use it properly. Also, this debug method looks solid. In the meantime I've managed to fix the script. The issue was that wget would sometime hang on the call to the URL and would wait its 900 seconds timeout period which made the service freeze. Adding a --timeout=2 solved everything. – bleah1 Sep 18 at 8:17
  • @bleah1 Please make an answer and explain the solution there. This will finish your question and show others that it has a solution. – Ingo Sep 18 at 8:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.