6

I'm trying to use a Raspberry Pi to log data from a sensor via eth0. When I run my code (and about 100 variations on the sigterms, kills, exits, etc.) the collection doesn't die after unplugging, and my file doesn't flush. Here's the current iteration of (most of) my code.

blink is a function that I've excluded but works and doesn't interact programmatically.

Does anyone have ideas on how I could successfully use disconnecting the network cable as a signal to flush the file and kill my script?

#!/bin/bash

# Function to check if the Ethernet interface is active
eth_active() {
    if ip link show eth0 up >/dev/null 2>&1; then
        return 0
    else
        return 1
    fi
}


dt=$(date '+%Y_%m_%d_%H_%M')
umask 0111
touch $dt.pcap

sleep 5

# Main script
if eth_active; then
# Ethernet active, execute the command
    dumpcap -i eth0 -P -w $dt.pcap &
    pid=$!
    if eth_active; then
        echo "working"
        sleep 2
    else
        kill -9 $pid
        echo "Ethernet interface is severed. Exiting..."
        blink
        shutdown -h now
    fi
else
# Ethernet interface is severed, exit the script
    echo "Not getting data"
    blink
    exit 0
fi
0

2 Answers 2

5

Does anyone have ideas on how I could successfully use pulling the plug as a signal to flush the file and kill my script?

First off, the function eth_active doesn't correctly identify whether the interface link is connected or not. Running a little bit of code can test this:

iface=enxb827eb315364    # Interface name
while sleep 3; do date; ip link show "$iface" up; echo SS=$?; echo; done

The exit status is shown as SS=… and you'll see that it always returns 0 ("ok") regardless of ethernet connection:

Tue 10 Oct 09:52:41 BST 2023
2: enxb827eb315364: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether b8:27:eb:31:53:64 brd ff:ff:ff:ff:ff:ff
SS=0

Tue 10 Oct 09:52:44 BST 2023
2: enxb827eb315364: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
    link/ether b8:27:eb:31:53:64 brd ff:ff:ff:ff:ff:ff
SS=0

[…]

Tue 10 Oct 09:52:53 BST 2023
2: enxb827eb315364: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether b8:27:eb:31:53:64 brd ff:ff:ff:ff:ff:ff
SS=0

So let's address this:

# Check if the Ethernet interface is active.
# Usage: eth_active [<interface_name>]
# Omitting the <interface_name> will default to eth0
#
eth_active() {
    ip link show "${1:-eth0}" up 2>&1 | grep -qF "state UP"
}

The return value from the function can be derived from the grep status (0=ok for a text match) so there's no need for the if … then to return explicit values.

Next, you need a loop to check this, otherwise the program will simply run from top to bottom, start dumpcap as a child and then exit.

I don't understand the logic you're trying to embody in your question description so I've simplified here to illustrate how you'd write the loop. It's not intended to replace your code but to help you understand how to write it yourself:

# Set the interface name
iface=eth0

# Start the packet capture
dumpcap -i "$iface" -P -w "$(date +'%Y-%m-%d_%H%M').pcap" &
pid=$!  

# Do nothing until either the network cable is pulled or dumpcap dies
while eth_active "$iface" && kill -0 "$pid" 2>/dev/null
do
    sleep 3
done

# Kill dumpcap if it's still around
kill "$pid" 2>/dev/null && ( sleep 3; kill -KILL "$pid" 2>/dev/null ) &

Notice we're not initially using kill -9 (SIGKILL) but instead the default SIGTERM. Generally SIGKILL is a bad option as it doesn't allow the target process any opportunity to tidy up; consider it the big bad hammer rather than the routine way to terminate a process. In dumpcap's case the SIGTERM tells it to quit - and more importantly, to flush any outstanding output to the capture file. However, just in case it's got itself in a twist we wait three seconds and then hit it with the big hammer anyway. If it's already gone then we'll just get an error from kill, but that's not a problem here.

4

You can try something like this (untested):

if eth_active; then
    # Ethernet active, execute the command
    dumpcap -i eth0 -P -w "$dt.pcap" &
    pid=$!

else
    # Ethernet interface is severed, exit the script
    echo "Not getting data"
    blink
    exit 0
fi

## run until eth_active is false
while eth_active; do
    echo "working"
    sleep 2
done

## Only kill the PID if the $pid variable is not empty
[ -n "$pid" ] && kill -9 "$pid"

echo "Ethernet interface is severed. Exiting..."
blink
shutdown -h now

This will test if the interface is up and, if it is, will launch your command, then test the interface again ever 2 seconds and continue to the rest of the script and shutting down the machine if the interface is down.

However, I don't quite get the logic you want here. If the interface is not up when you run this script, it will just shut down the machine directly, is that what you want?


Important: see Chris Davies' answer which points out that your eth_active() doesn't work as you intend it to.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .