I use i3wm. I use it because it has a very low resource footprint, it has great documentation, and it's simple to configure.
Complementing i3wm is the i3status status provider to the i3bar. It provides a good suite of preset components for things like temperatur measurement, disk capacity. It also provides a couple of generic ones, namely "output the contents of a file" or "yes if file exists, no if not."
It's not you, it's me?
Warning
Always use a VPN! Always!!
Now, I always use VPN no matter what, and I configure network manually. That is, I do not use a network manager. For this reason, when network applications start misbehaving, it's sometimes hard to tell whether it is because the host is gone, the local network is flaky, the internet route is flaky, or simply that the connection is gone for good.
Evidently, it would be practical to have an item in the status bar telling me whether I have access to internet right now or not.
The "yes if file exists, no if not" option seems to be the right one to go for. Basically, we need to stick an empty file in a runtime file store whenever we detect that internet is available.
Ping, rinse, repeat
There's not much trickery involved here. The check is a ping to a remote location every now and then.
Some caveats to cover to grant it some minimum of intelligence:
- We need a few alternative destinations for the ping, that can take over if others happen to be down or take too long to repond.
- To make the script useful for general purpose use, we'd also want to be able to supply a custom list of hosts to ping.
- We also want to make sure that when the script is interrupted, it deletes the internet indicator file. That way, when it stops running, the internet indicator will be frozen in the "no" state.
- Lastly, it can be useful to log to syslog every time the state of the internet connection (or the script itself) changes.
That can translate to a shell script like this;
#!/bin/bash # this is our runtime file, if - which exists - tells us internet is up f="/run/user/$UID/probe_up" rm -f $f up() { if [ ! -f $f ]; then logger -p info "iup up" fi touch $f } down() { if [ -f $f ]; then logger -p info "iup down" fi rm -f $f } argh() { logger -p info "iup die" rm -f $f exit 0 } IUP_DELAY=${IUP_DELAY:-$1} if [ -z $IUP_DELAY ]; then IUP_DELAY=5 fi logger -p debug iup started with delay $IUP_DELAY hosts=() while read h; do hosts+=($h) done < $HOME/.config/iup 2> /dev/null if [ ${#hosts[@]} -eq "0" ]; then hosts=(8.8.8.8 151.101.193.67) # google nameserver and cnn.com logger -p warn missing hosts input file, using evil default: ${hosts[@]} fi trap argh SIGINT trap argh SIGTERM trap argh SIGQUIT while true; do isup="" for h in ${hosts[@]}; do ping -c1 $h -w1 -q &> /dev/null if [ $? -eq '0' ]; then up isup=1 #logger -p debug "ping success $h" break fi done if [ -z $isup ]; then down fi sleep $IUP_DELAY done
Since we'll want this to run when network interfaces allegedly are up, it makes sense to link it to systemd and the network target:
[Unit] Description=Internet connection poller After=multi-user.target [Service] ExecStart=/usr/local/bin/iup.sh Restart=always [Install] WantedBy=multi-user.target
Stick this in ~/.config/systemd/user/iup.service
and enable and start the service:
$ systemctl --user enable iup.service
$ systemctl --user start iup.service
Checking what status our status is in
Now, in the i3status configuration, assuming that your system uid is 1000 [1], add:
order += "run_watch INET"
kj
run_watch INET {
pidfile = "/run/user/1000/probe_up"
}
To reload the config on the fly, press mod+r
(that's ctrl+r
on mine). The result should be a new item in your bar showing INET: yes
(most likely yes, anyway, since you're currently reading this).
Safety first, eh ... second
Warning
Did I mention that you should always use a VPN?
The same run_watch
trick can be used for VPN.
I use openvpn
, and it defines a flag --writepid
. If you pass a file path to this parameter, either through the writepid
config directiry or on the --writepid
flag on the command line, it will write the openvpn pid to that file, and similarly remove it when the openvpn service ends.
However, this raises another issue. Namely the fact that a location is needed for openvpn to write the file to, for which it also has access.
If we want to use the /run
directory again, now we also has to make sure that this directory exists.
Got the runs?
This is exactly what systemd-tmpfiles
is for. You can add files to /etc/tmpfiles.d
which describe what kind of temporary files or directories to add [2].
Create a file /etc/tmpfiles.d/openvpn.conf
and add a single line to it:
d /run/openvpn 0755 openvpn openvpn
This will ensure that the folder is created at startup.
Now, to create one right away for the current session, run systemd-tmpfiles --create
.
Now we have everything we need to add the VPN status to i3status aswell. Provided that we chose /run/openvpn/openvpn.pid
as our argument to openvpn --writepid
, the setup is more or less the same as before:
order += "run_watch VPN"
kj
run_watch VPN {
pidfile = "/run/openvpn/openvpn.pid"
}
[1] The /run/user/$UID
folder will be created on system startup, and will be writable by that user. It provides a tmpfs storage location for processes that run in early stages of boot, before the entire filesystem tree (which may include/var/run
because/var
may be on a separate partition) has been mounted. More in that here: https://lwn.net/Articles/436012/
[2] This service has an impressive amount of flexibility, which you can inspect yourself by visiting the tmpfiles.d
(andsystemd-tmpfiles
) manpage.