ZFS On Linux Quota


Written by

As you may know, linux quota tool doesn’t work with ZFS, this is a known issue and I have previously hacked around it but I’ve recently had issues with the very rudimentary ZFS quota script I deployed at work for two reasons:

  1. A new ZFS server was not in LDAP so was unaware of Usernames it only showed UIDs
  2. Partial matches on Usernames caused weirdness
ZFS on Linux Logo

So I moved to change the script a little, it now outputs as UIDS, this has an advantage that the server does not need to know the usernames, so you can have local users on remote servers etc. It also makes the output more obscure, due to it being readable by all, it containing names meant it could leak some personal details to systems that do not include the ability to view it.

This change meant that the new server output and client reader is incompatible with the old, so the previous version is now labelled as v1. Due to this breaking change, I thought it would be best to split the code out from my monolithic git repo to it’s own zfs-quota repository meaning others can contribute easier.

The change also highlighted that the UID output (previously name) could partial match, the previous version just hoped and user some poor-mans greping to only output a single match. Using UID also meant that the UID could possibly match a ZFS Byte output. So the new version actually checks the UID field and will only return if that value is a complete match to the UID the system is searching for.

ZFS Quota Output

So please find my ZFS on Linux Quota scripts on github, there’s a Server script and a client script, both of which are targeting CentOS7, and they at least work on Fedora 32/33/34 as well as CentOS8 but they should work on pretty much any Linux distro. Hopefully the client script is simple enough for others to understand and if required port to Windows or MacOS.

Poor-Man’s Raspberry Pi Web based Digital Signage


Written by

There’s lots of Raspberry Pi Digital Signage software suites available but most of them expect you to pay or are really out-dated.

This is a short guide on how to setup a small fleet of Raspberry Pis (Although most of the content applies to any Linux based system).

Simple Steps:

  • Image your System – Raspberry Pi OS or Other Linux.
  • Make sure your system displays correctly on your screen.
  • Install Chromium or Google-Chrome.
  • Run Chrome in Kiosk Mode.
  • Restart Chrome every x minutes.
  • Physically install your screen and pi.

I intend to run multiple systems to display different information signs with some of the systems being out of reach so they needed to be fairly robust stand-alone setup; if I wanted to change the content being displayed, then I needed a way to reconfigure this without having to re-image the raspberry pi or remove the signs.

The Signage Script

The signage bash script will try to detect the system mac address of the two possible system interfaces on a Raspberry Pi (feel free to add/edit these). The start url loads the web server php scripts below to allow changing of content at a later date. It will also detect google-chrome or chromium on the system and use which ever it finds.

The script runs in a loop, showing the web page for 30minutes (can be configured to anything else) and then restarts the browser; this means if there is an issue with network connectivity then you dont need to restart the entire system, it will be back in 30minutes or less.

#!/bin/bash
#
# Horrible Digital Signage Startup Script
# 2021 - Adam Boutcher - aboutcher.co.uk
#

STARTURL="http://my-server/tv/manager.php"
REFRESH=30 #Minutes
INTERFACES=(eth0 wlan0)

# Function to check that a binary exists
function check_bin() {
  which $1 1>/dev/null 2>&1
  if [[ $? -ne 0 ]]; then
    echo "$1 cannot be found. Please install it or add it to the path. Exiting."
    exit 1
  fi
}

check_bin which
check_bin cat
check_bin awk
check_bin sleep
check_bin kill
check_bin echo
check_bin ethtool

# Looping through listed interfaces
for INT in ${INTERFACES[@]}; do
  if [[ $(cat /sys/class/net/$INT/operstate 2>/dev/null) == "up" ]]; then
    MAC=$(/usr/sbin/ethtool -P $INT | awk '{print $3}');
    break
  fi
done

if [ -z $MAC ]; then
  echo "No MAC address found"
  exit 1
fi

echo 
echo Poor-Mans Digital Signage
echo Adam Boutcher - www.aboutcher.co.uk
echo 
echo System MAC: $MAC
echo Starting URL: $STARTURL
echo Refresh in: $REFRESH Minutes

BROWSERS=("google-chrome" "chromium")
for BROWSER in ${BROWSERS[@]}; do
  which $BROWSER >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    echo Found Browser: $BROWSER
    break;
  fi
done;

while true; do
  echo 
  $BROWSER --new-window --kiosk --ingognito $STARTURL?mac=$MAC >/dev/null 2>&1 &
  if [ -z $WEBPID ]; then
    WEBPID=$!
    echo "First Start"
  else
    NEWPID=$!
    sleep 0.5
    kill -9 $WEBPID 2>/dev/null
    WEBPID=$NEWPID
  fi
  echo Running on PID: $WEBPID
  echo "Sleeping..."
  sleep $((REFRESH*60))
  echo "Restarting"
done

The Web Server Script

This a simple php logic script to redirect the system to your actual web content. This means that upon restart of the web browser, it will re-check this web server script for its content location.

<?php

// This array is key = mac, dest = value
$CLIENTS = array (
                "dc:a6:32:zz:yy:xx" => "https://example.com",
                "dc:a6:32:xy:zx:yz" => "https://aboutcher.co.uk",
        );
if ( isset($CLIENTS[$_GET['mac']]) ) {
  header("HTTP/1.1 302 Found");
  header('Location: '.$CLIENTS[$_GET['mac']]);
} else {
  echo "System not recognised.<br/>";
  if ( !empty($_GET['mac']) ) {
    echo $_GET['mac'];
  } else {
    echo "No mac";
  }
}

?>

Raspberry Pi Auto Start:

Save this file in /home/pi/.config/autostart/signage.desktop

[Desktop Entry]
Type=Application
Name=Digital Signage
Exec=/home/pi/digitalsignage.sh

Raspberry Pi Tweaks:

You can disable screen blanking in the Raspberry Pi Configuration GUI as well as enable auto-gui and auto-login.

I would also recommend disabling SSH and VNC if remote access isn’t required; you can also enable the filesystem to be read-only which should save the SD card’s life span.

Save the signage script into /home/pi/digitalsignage.sh and then add the autostart script to /home/pi/.config/autostart/signage.desktop, you might need to make the autostart directory.

The raspberry pi is a nice simple solution as they’re easy to get hold of and has a large community to help you get things perfect, there’s also nice features for display rotation and a host of ways to add hacks, so for instance you could add temperature probes and display the temperature results locally.

Marlin Firmware for Ender 2


Written by

This is my Marlin firmware build and config for an Ender 2 with an SKR E3 Mini v1.2 (512k).

It worked with Marlinfw 2.0.7.2, these all contain various different tweaks, such as bed size changes, z axis changes, BLTouch, stepper silencing, menu options. I’m using the latest version at the top but you might find other versions work better for you.

Pre-Compiled Firmware:

Config Files:

Goodix Fingerprint Reader on Fedora Linux


Written by

My Dell XPS 9500 has a built in Goodix fingerprint reader, there are drivers for this in Windows but originally the Linux driver didn’t exist.

A driver for Ubuntu has now arrived but there is no Fedora support. The driver is a libfrpint-2-tod driver. Someone has ported the finger print driver into the Arch User Repo as libfprint-2-tod1-xps9300-bin and it reported to work. My work below is derived from both these sources.

The following is my attempt within Fedora Linux 33 (reported to work on Fedora 32 too):

# Install default systemfprintd and libfrint
yum install fprintd fprintd-pam

# Build libfprint and libfprint-tod
git clone https://gitlab.freedesktop.org/3v1n0/libfprint.git
yum install -y gcc gcc-c++ glib glib-devel glibc glibc-devel glib2 glib2-devel libusb libusb-devel nss-devel pixman pixman-devel libX11 libX11-devel libXv libXv-devel gtk-doc libgusb libgusb-devel gobject-introspection gobject-introspection-devel ninja-build
cd libfprint
git checkout tags/v1.90.3+tod1
meson builddir && cd builddir
meson compile
meson install

# Overwrite the system libfprint with our version
cp libfprint/libfprint-2.so.2.0.0 /usr/lib64/
cp libfprint/tod/libfprint-2-tod.so /usr/lib64/
cp libfprint/tod/libfprint-2-tod.so.1 /usr/lib64/

# Get the Goodix libfprint driver/udev rules
wget http://dell.archive.canonical.com/updates/pool/public/libf/libfprint-2-tod1-goodix/libfprint-2-tod1-goodix_0.0.4-0ubuntu1somerville1.tar.gz
tar -xvf libfprint-2-tod1-goodix_0.0.4-0ubuntu1somerville1.tar.gz

# Move the libfprint driver to where we think it should go
mkdir -p /usr/lib/libfprint-2/tod-1/
mkdir -p /usr/local/lib64/libfprint-2/tod-1/
cp libfprint-2-tod1-goodix/usr/lib/x86_64-linux-gnu/libfprint-2/tod-1/libfprint-tod-goodix-53xc-0.0.4.so /usr/lib/libfprint-2/tod-1/
ln -s /usr/lib/libfprint-2/tod-1/libfprint-tod-goodix-53xc-0.0.4.so /usr/local/lib64/libfprint-2/tod-1/libfprint-tod-goodix-53xc-0.0.4.so
sudo chmod 755 /usr/lib/libfprint-2/tod-1/libfprint-tod-goodix-53xc-0.0.4.so
cp libfprint-2-tod1-goodix/lib/udev/rules.d/60-libfprint-2-tod1-goodix.rules /lib/udev/rules.d/
mkdir -p /var/lib/fprint/goodix

# Add some things into the module alias file
cat libfprint-2-tod1-goodix/debian/modaliases >> /lib/modules/$(uname -r)/modules.alias

This should now work with the examples and fprintd-enroll

Enable fingerprint service for use

authselect enable-feature with-fingerprint
authselect apply-changes
systemctl enable fprintd
systemctl start fprintd

Shared Fail2Ban Puppet


Written by

I’ve written a very simple Puppet module for the Shared Fail2Ban system we use at work.

I’ve sanitised and uploaded the module to github under the name Shared Fail2Ban Puppet.

The module is fairly simple and depends on the puppet labs mysql module on puppet forge. It may clash with other peoples fail2ban modules.

The shared installation will install ssh iptables with shared iptables on the clients with an option of mysql or api on the shared fail2ban server. You can however change the files it pushes for your own jails.