

paul@f0:~ % doas zpool create -m /data zdata /dev/ada1 paul@f0:~ % zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT zdata 928G 12.1M 928G - - 0% 0% 1.00x ONLINE - zroot 472G 29.0G 443G - - 0% 6% 1.00x ONLINE - paul@f0:/ % doas camcontrol devlist <512GB SSD D910R170> at scbus0 target 0 lun 0 (pass0,ada0) <Samsung SSD 870 EVO 1TB SVT03B6Q> at scbus1 target 0 lun 0 (pass1,ada1) paul@f0:/ %
paul@f1:/ % doas camcontrol devlist <512GB SSD D910R170> at scbus0 target 0 lun 0 (pass0,ada0) <CT1000BX500SSD1 M6CR072> at scbus1 target 0 lun 0 (pass1,ada1)

paul@f0:/ % doas camcontrol devlist <512GB SSD D910R170> at scbus0 target 0 lun 0 (pass0,ada0) <Samsung SSD 870 EVO 1TB SVT03B6Q> at scbus1 target 0 lun 0 (pass1,ada1) <Generic Flash Disk 8.07> at scbus2 target 0 lun 0 (da0,pass2) paul@f0:/ %
paul@f0:/ % doas newfs /dev/da0
/dev/da0: 15000.0MB (30720000 sectors) block size 32768, fragment size 4096
using 24 cylinder groups of 625.22MB, 20007 blks, 80128 inodes.
with soft updates
super-block backups (for fsck_ffs -b #) at:
192, 1280640, 2561088, 3841536, 5121984, 6402432, 7682880, 8963328, 10243776,
11524224, 12804672, 14085120, 15365568, 16646016, 17926464, 19206912,k 20487360,
...
paul@f0:/ % echo '/dev/da0 /keys ufs rw 0 2' | doas tee -a /etc/fstab
/dev/da0 /keys ufs rw 0 2
paul@f0:/ % doas mkdir /keys
paul@f0:/ % doas mount /keys
paul@f0:/ % df | grep keys
/dev/da0 14877596 8 13687384 0% /keys

paul@f0:/keys % doas openssl rand -out /keys/f0.lan.buetow.org:bhyve.key 32 paul@f0:/keys % doas openssl rand -out /keys/f1.lan.buetow.org:bhyve.key 32 paul@f0:/keys % doas openssl rand -out /keys/f2.lan.buetow.org:bhyve.key 32 paul@f0:/keys % doas openssl rand -out /keys/f0.lan.buetow.org:zdata.key 32 paul@f0:/keys % doas openssl rand -out /keys/f1.lan.buetow.org:zdata.key 32 paul@f0:/keys % doas openssl rand -out /keys/f2.lan.buetow.org:zdata.key 32 paul@f0:/keys % doas chown root * paul@f0:/keys % doas chmod 400 * paul@f0:/keys % ls -l total 20 *r-------- 1 root wheel 32 May 25 13:07 f0.lan.buetow.org:bhyve.key *r-------- 1 root wheel 32 May 25 13:07 f1.lan.buetow.org:bhyve.key *r-------- 1 root wheel 32 May 25 13:07 f2.lan.buetow.org:bhyve.key *r-------- 1 root wheel 32 May 25 13:07 f0.lan.buetow.org:zdata.key *r-------- 1 root wheel 32 May 25 13:07 f1.lan.buetow.org:zdata.key *r-------- 1 root wheel 32 May 25 13:07 f2.lan.buetow.org:zdata.key
paul@f0:/keys % doas zfs create -o encryption=on -o keyformat=raw -o \ keylocation=file:///keys/`hostname`:zdata.key zdata/enc paul@f0:/ % zfs list | grep zdata zdata 836K 899G 96K /data zdata/enc 200K 899G 200K /data/enc paul@f0:/keys % zfs get all zdata/enc | grep -E -i '(encryption|key)' zdata/enc encryption aes-256-gcm - zdata/enc keylocation file:///keys/f0.lan.buetow.org:zdata.key local zdata/enc keyformat raw - zdata/enc encryptionroot zdata/enc - zdata/enc keystatus available -
paul@f0:/keys % doas vm stop rocky Sending ACPI shutdown to rocky paul@f0:/keys % doas vm list NAME DATASTORE LOADER CPU MEMORY VNC AUTO STATE rocky default uefi 4 14G - Yes [1] Stopped
paul@f0:/keys % doas zfs rename zroot/bhyve zroot/bhyve_old paul@f0:/keys % doas zfs set mountpoint=/mnt zroot/bhyve_old paul@f0:/keys % doas zfs snapshot zroot/bhyve_old/rocky@hamburger paul@f0:/keys % doas zfs create -o encryption=on -o keyformat=raw -o \ keylocation=file:///keys/`hostname`:bhyve.key zroot/bhyve paul@f0:/keys % doas zfs set mountpoint=/zroot/bhyve zroot/bhyve paul@f0:/keys % doas zfs set mountpoint=/zroot/bhyve/rocky zroot/bhyve/rocky
paul@f0:/keys % doas zfs send zroot/bhyve_old/rocky@hamburger | \ doas zfs recv zroot/bhyve/rocky paul@f0:/keys % doas cp -Rp /mnt/.config /zroot/bhyve/ paul@f0:/keys % doas cp -Rp /mnt/.img /zroot/bhyve/ paul@f0:/keys % doas cp -Rp /mnt/.templates /zroot/bhyve/ paul@f0:/keys % doas cp -Rp /mnt/.iso /zroot/bhyve/
paul@f0:/keys % doas sysrc zfskeys_enable=YES zfskeys_enable: -> YES paul@f0:/keys % doas vm init paul@f0:/keys % doas reboot . . . paul@f0:~ % doas vm list paul@f0:~ % doas vm list NAME DATASTORE LOADER CPU MEMORY VNC AUTO STATE rocky default uefi 4 14G 0.0.0.0:5900 Yes [1] Running (2265)
paul@f0:~ % doas zfs destroy -R zroot/bhyve_old
paul@f0:~ % zfs get all zroot/bhyve | grep -E '(encryption|key)' zroot/bhyve encryption aes-256-gcm - zroot/bhyve keylocation file:///keys/f0.lan.buetow.org:bhyve.key local zroot/bhyve keyformat raw - zroot/bhyve encryptionroot zroot/bhyve - zroot/bhyve keystatus available - paul@f0:~ % zfs get all zroot/bhyve/rocky | grep -E '(encryption|key)' zroot/bhyve/rocky encryption aes-256-gcm - zroot/bhyve/rocky keylocation none default zroot/bhyve/rocky keyformat raw - zroot/bhyve/rocky encryptionroot zroot/bhyve - zroot/bhyve/rocky keystatus available -
paul@f0:~ % doas pkg install -y zrepl
# On f0 paul@f0:~ % doas zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT zdata 928G 1.03M 928G - - 0% 0% 1.00x ONLINE - zroot 472G 26.7G 445G - - 0% 5% 1.00x ONLINE - paul@f0:~ % doas zfs list -r zdata/enc NAME USED AVAIL REFER MOUNTPOINT zdata/enc 200K 899G 200K /data/enc # On f1 paul@f1:~ % doas zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT zdata 928G 956K 928G - - 0% 0% 1.00x ONLINE - zroot 472G 11.7G 460G - - 0% 2% 1.00x ONLINE - paul@f1:~ % doas zfs list -r zdata/enc NAME USED AVAIL REFER MOUNTPOINT zdata/enc 200K 899G 200K /data/enc
# Check WireGuard interface IPs paul@f0:~ % ifconfig wg0 | grep inet inet 192.168.2.130 netmask 0xffffff00 paul@f1:~ % ifconfig wg0 | grep inet inet 192.168.2.131 netmask 0xffffff00
# Create the nfsdata dataset that will hold all data exposed via NFS paul@f0:~ % doas zfs create zdata/enc/nfsdata
paul@f0:~ % doas tee /usr/local/etc/zrepl/zrepl.yml <<'EOF'
global:
logging:
- type: stdout
level: info
format: human
jobs:
- name: f0_to_f1_nfsdata
type: push
connect:
type: tcp
address: "192.168.2.131:8888"
filesystems:
"zdata/enc/nfsdata": true
send:
encrypted: true
snapshotting:
type: periodic
prefix: zrepl_
interval: 1m
pruning:
keep_sender:
- type: last_n
count: 10
keep_receiver:
- type: last_n
count: 10
- name: f0_to_f1_fedora
type: push
connect:
type: tcp
address: "192.168.2.131:8888"
filesystems:
"zroot/bhyve/fedora": true
send:
encrypted: true
snapshotting:
type: periodic
prefix: zrepl_
interval: 10m
pruning:
keep_sender:
- type: last_n
count: 10
keep_receiver:
- type: last_n
count: 10
EOF
# First, create a dedicated sink dataset
paul@f1:~ % doas zfs create zdata/sink
paul@f1:~ % doas tee /usr/local/etc/zrepl/zrepl.yml <<'EOF'
global:
logging:
- type: stdout
level: info
format: human
jobs:
- name: sink
type: sink
serve:
type: tcp
listen: "192.168.2.131:8888"
clients:
"192.168.2.130": "f0"
recv:
placeholder:
encryption: inherit
root_fs: "zdata/sink"
EOF
# On f0 paul@f0:~ % doas sysrc zrepl_enable=YES zrepl_enable: -> YES paul@f0:~ % doas service `zrepl` start Starting zrepl. # On f1 paul@f1:~ % doas sysrc zrepl_enable=YES zrepl_enable: -> YES paul@f1:~ % doas service `zrepl` start Starting zrepl.
# On f0, check `zrepl` status (use raw mode for non-tty)
paul@f0:~ % doas pkg install jq
paul@f0:~ % doas zrepl status --mode raw | grep -A2 "Replication" | jq .
"Replication":{"StartAt":"2025-07-01T22:31:48.712143123+03:00"...
# Check if services are running
paul@f0:~ % doas service zrepl status
zrepl is running as pid 2649.
paul@f1:~ % doas service zrepl status
zrepl is running as pid 2574.
# Check for `zrepl` snapshots on source
paul@f0:~ % doas zfs list -t snapshot -r zdata/enc | grep zrepl
zdata/enc@zrepl_20250701_193148_000 0B - 176K -
# On f1, verify the replicated datasets
paul@f1:~ % doas zfs list -r zdata | grep f0
zdata/f0 576K 899G 200K none
zdata/f0/zdata 376K 899G 200K none
zdata/f0/zdata/enc 176K 899G 176K none
# Check replicated snapshots on f1
paul@f1:~ % doas zfs list -t snapshot -r zdata | grep zrepl
zdata/f0/zdata/enc@zrepl_20250701_193148_000 0B - 176K -
zdata/f0/zdata/enc@zrepl_20250701_194148_000 0B - 176K -
.
.
.
paul@f0:~ % doas zrepl status

paul@f0:~ % uptime 11:17PM up 1 min, 0 users, load averages: 0.16, 0.06, 0.02 paul@f0:~ % doas service `zrepl` status zrepl is running as pid 2366. paul@f1:~ % doas service `zrepl` status zrepl is running as pid 2309. # Check that new snapshots are being created and replicated paul@f0:~ % doas zfs list -t snapshot | grep `zrepl` | tail -2 zdata/enc/nfsdata@zrepl_20250701_202530_000 0B - 200K - zroot/bhyve/fedora@zrepl_20250701_202530_000 0B - 2.97G - . . . paul@f1:~ % doas zfs list -t snapshot -r zdata/sink | grep 202530 zdata/sink/f0/zdata/enc/nfsdata@zrepl_20250701_202530_000 0B - 176K - zdata/sink/f0/zroot/bhyve/fedora@zrepl_20250701_202530_000 0B - 2.97G - . . .
# On f0 - set mountpoint for the primary nfsdata paul@f0:~ % doas zfs set mountpoint=/data/nfs zdata/enc/nfsdata paul@f0:~ % doas mkdir -p /data/nfs # Verify it's mounted paul@f0:~ % df -h /data/nfs Filesystem Size Used Avail Capacity Mounted on zdata/enc/nfsdata 899G 204K 899G 0% /data/nfs
# On f1 - first check encryption status
paul@f1:~ % doas zfs get keystatus zdata/sink/f0/zdata/enc/nfsdata
NAME PROPERTY VALUE SOURCE
zdata/sink/f0/zdata/enc/nfsdata keystatus unavailable -
# Load the encryption key (using f0's key stored on the USB)
paul@f1:~ % doas zfs load-key -L file:///keys/f0.lan.buetow.org:zdata.key \
zdata/sink/f0/zdata/enc/nfsdata
# Set mountpoint and mount (same path as f0 for easier failover)
paul@f1:~ % doas mkdir -p /data/nfs
paul@f1:~ % doas zfs set mountpoint=/data/nfs zdata/sink/f0/zdata/enc/nfsdata
paul@f1:~ % doas zfs mount zdata/sink/f0/zdata/enc/nfsdata
# Make it read-only to prevent accidental writes that would break replication
paul@f1:~ % doas zfs set readonly=on zdata/sink/f0/zdata/enc/nfsdata
# Verify
paul@f1:~ % df -h /data/nfs
Filesystem Size Used Avail Capacity Mounted on
zdata/sink/f0/zdata/enc/nfsdata 896G 204K 896G 0% /data/nfs
# Option 1: Rollback to the last common snapshot (loses local changes) paul@f1:~ % doas zfs rollback zdata/sink/f0/zdata/enc/nfsdata@zrepl_20250701_204054_000 # Option 2: Make it read-only to prevent accidents again paul@f1:~ % doas zfs set readonly=on zdata/sink/f0/zdata/enc/nfsdata
paul@f0:~ % doas zfs list -o name,mountpoint,mounted | grep nfsdata zdata/enc/nfsdata /data/nfs yes
paul@f0:~ % doas zfs get keystatus zdata/enc/nfsdata NAME PROPERTY VALUE SOURCE zdata/enc/nfsdata keystatus available - # If "unavailable", load the key: paul@f0:~ % doas zfs load-key -L file:///keys/f0.lan.buetow.org:zdata.key zdata/enc/nfsdata paul@f0:~ % doas zfs mount zdata/enc/nfsdata
paul@f0:~ % ls -la /data/nfs/.zfs/snapshot/zrepl_*/
# On f0 - configure all encrypted datasets paul@f0:~ % doas sysrc zfskeys_enable=YES zfskeys_enable: YES -> YES paul@f0:~ % doas sysrc zfskeys_datasets="zdata/enc zdata/enc/nfsdata zroot/bhyve" zfskeys_datasets: -> zdata/enc zdata/enc/nfsdata zroot/bhyve # Set correct key locations for all datasets paul@f0:~ % doas zfs set \ keylocation=file:///keys/f0.lan.buetow.org:zdata.key zdata/enc/nfsdata # On f1 - include the replicated dataset paul@f1:~ % doas sysrc zfskeys_enable=YES zfskeys_enable: YES -> YES paul@f1:~ % doas sysrc \ zfskeys_datasets="zdata/enc zroot/bhyve zdata/sink/f0/zdata/enc/nfsdata" zfskeys_datasets: -> zdata/enc zroot/bhyve zdata/sink/f0/zdata/enc/nfsdata # Set key location for replicated dataset paul@f1:~ % doas zfs set \ keylocation=file:///keys/f0.lan.buetow.org:zdata.key zdata/sink/f0/zdata/enc/nfsdata
# The virtual IP 192.168.1.138 will float between f0 and f1 ifconfig_re0_alias0="inet vhid 1 pass testpass alias 192.168.1.138/32"
192.168.1.138 f3s-storage-ha f3s-storage-ha.lan f3s-storage-ha.lan.buetow.org
paul@f0:~ % cat <<END | doas tee -a /etc/devd.conf
notify 0 {
match "system" "CARP";
match "subsystem" "[0-9]+@[0-9a-z.]+";
match "type" "(MASTER|BACKUP)";
action "/usr/local/bin/carpcontrol.sh $subsystem $type";
};
END
paul@f0:~ % doas service devd restart
paul@f0:~ % doas tee /usr/local/bin/carpcontrol.sh <<'EOF'
#!/bin/sh
# CARP state change control script
case "$1" in
MASTER)
logger "CARP state changed to MASTER, starting services"
;;
BACKUP)
logger "CARP state changed to BACKUP, stopping services"
;;
*)
logger "CARP state changed to $1 (unhandled)"
;;
esac
EOF
paul@f0:~ % doas chmod +x /usr/local/bin/carpcontrol.sh
# Copy the same script to f1
paul@f0:~ % scp /usr/local/bin/carpcontrol.sh f1:/tmp/
paul@f1:~ % doas mv /tmp/carpcontrol.sh /usr/local/bin/
paul@f1:~ % doas chmod +x /usr/local/bin/carpcontrol.sh
paul@f0:~ % echo 'carp_load="YES"' | doas tee -a /boot/loader.conf carp_load="YES" paul@f1:~ % echo 'carp_load="YES"' | doas tee -a /boot/loader.conf carp_load="YES"
paul@f0:~ % doas sysrc nfs_server_enable=YES nfs_server_enable: YES -> YES paul@f0:~ % doas sysrc nfsv4_server_enable=YES nfsv4_server_enable: YES -> YES paul@f0:~ % doas sysrc nfsuserd_enable=YES nfsuserd_enable: YES -> YES paul@f0:~ % doas sysrc mountd_enable=YES mountd_enable: NO -> YES paul@f0:~ % doas sysrc rpcbind_enable=YES rpcbind_enable: NO -> YES
# First, ensure the dataset is mounted paul@f0:~ % doas zfs get mounted zdata/enc/nfsdata NAME PROPERTY VALUE SOURCE zdata/enc/nfsdata mounted yes - # Create the k3svolumes directory paul@f0:~ % doas mkdir -p /data/nfs/k3svolumes paul@f0:~ % doas chmod 755 /data/nfs/k3svolumes
paul@f0:~ % doas tee /etc/exports <<'EOF' V4: /data/nfs -sec=sys /data/nfs -alldirs -maproot=root -network 127.0.0.1 -mask 255.255.255.255 EOF
paul@f0:~ % doas service rpcbind start Starting rpcbind. paul@f0:~ % doas service mountd start Starting mountd. paul@f0:~ % doas service nfsd start Starting nfsd. paul@f0:~ % doas service nfsuserd start Starting nfsuserd.
CARP VIP (192.168.1.138)
|
f0 (MASTER) ←---------→|←---------→ f1 (BACKUP)
stunnel:2323 | stunnel:stopped
nfsd:2049 | nfsd:stopped
|
Clients connect here
# On f0 - Create CA
paul@f0:~ % doas mkdir -p /usr/local/etc/stunnel/ca
paul@f0:~ % cd /usr/local/etc/stunnel/ca
paul@f0:~ % doas openssl genrsa -out ca-key.pem 4096
paul@f0:~ % doas openssl req -new -x509 -days 3650 -key ca-key.pem -out ca-cert.pem \
-subj '/C=US/ST=State/L=City/O=F3S Storage/CN=F3S Stunnel CA'
# Create server certificate
paul@f0:~ % cd /usr/local/etc/stunnel
paul@f0:~ % doas openssl genrsa -out server-key.pem 4096
paul@f0:~ % doas openssl req -new -key server-key.pem -out server.csr \
-subj '/C=US/ST=State/L=City/O=F3S Storage/CN=f3s-storage-ha.lan'
paul@f0:~ % doas openssl x509 -req -days 3650 -in server.csr -CA ca/ca-cert.pem \
-CAkey ca/ca-key.pem -CAcreateserial -out server-cert.pem
# Create client certificates for authorised clients
paul@f0:~ % cd /usr/local/etc/stunnel/ca
paul@f0:~ % doas sh -c 'for client in r0 r1 r2 earth; do
openssl genrsa -out ${client}-key.pem 4096
openssl req -new -key ${client}-key.pem -out ${client}.csr \
-subj "/C=US/ST=State/L=City/O=F3S Storage/CN=${client}.lan.buetow.org"
openssl x509 -req -days 3650 -in ${client}.csr -CA ca-cert.pem \
-CAkey ca-key.pem -CAcreateserial -out ${client}-cert.pem
done'
# Install stunnel paul@f0:~ % doas pkg install -y stunnel # Configure stunnel server with client certificate authentication paul@f0:~ % doas tee /usr/local/etc/stunnel/stunnel.conf <<'EOF' cert = /usr/local/etc/stunnel/server-cert.pem key = /usr/local/etc/stunnel/server-key.pem setuid = stunnel setgid = stunnel [nfs-tls] accept = 192.168.1.138:2323 connect = 127.0.0.1:2049 CAfile = /usr/local/etc/stunnel/ca/ca-cert.pem verify = 2 requireCert = yes EOF # Enable and start stunnel paul@f0:~ % doas sysrc stunnel_enable=YES stunnel_enable: -> YES paul@f0:~ % doas service stunnel start Starting stunnel. # Restart stunnel to apply the CARP VIP binding paul@f0:~ % doas service stunnel restart Stopping stunnel. Starting stunnel.
paul@f1:~ % doas sysrc nfs_server_enable=YES nfs_server_enable: NO -> YES paul@f1:~ % doas sysrc nfsv4_server_enable=YES nfsv4_server_enable: NO -> YES paul@f1:~ % doas sysrc nfsuserd_enable=YES nfsuserd_enable: NO -> YES paul@f1:~ % doas sysrc mountd_enable=YES mountd_enable: NO -> YES paul@f1:~ % doas sysrc rpcbind_enable=YES rpcbind_enable: NO -> YES paul@f1:~ % doas tee /etc/exports <<'EOF' V4: /data/nfs -sec=sys /data/nfs -alldirs -maproot=root -network 127.0.0.1 -mask 255.255.255.255 EOF paul@f1:~ % doas service rpcbind start Starting rpcbind. paul@f1:~ % doas service mountd start Starting mountd. paul@f1:~ % doas service nfsd start Starting nfsd. paul@f1:~ % doas service nfsuserd start Starting nfsuserd.
# Install stunnel paul@f1:~ % doas pkg install -y stunnel # Copy certificates from f0 paul@f0:~ % doas tar -cf /tmp/stunnel-certs.tar \ -C /usr/local/etc/stunnel server-cert.pem server-key.pem ca paul@f0:~ % scp /tmp/stunnel-certs.tar f1:/tmp/ paul@f1:~ % cd /usr/local/etc/stunnel && doas tar -xf /tmp/stunnel-certs.tar # Configure stunnel server on f1 with client certificate authentication paul@f1:~ % doas tee /usr/local/etc/stunnel/stunnel.conf <<'EOF' cert = /usr/local/etc/stunnel/server-cert.pem key = /usr/local/etc/stunnel/server-key.pem setuid = stunnel setgid = stunnel [nfs-tls] accept = 192.168.1.138:2323 connect = 127.0.0.1:2049 CAfile = /usr/local/etc/stunnel/ca/ca-cert.pem verify = 2 requireCert = yes EOF # Enable and start stunnel paul@f1:~ % doas sysrc stunnel_enable=YES stunnel_enable: -> YES paul@f1:~ % doas service stunnel start Starting stunnel. # Restart stunnel to apply the CARP VIP binding paul@f1:~ % doas service stunnel restart Stopping stunnel. Starting stunnel.
# Create CARP control script on both f0 and f1
paul@f0:~ % doas tee /usr/local/bin/carpcontrol.sh <<'EOF'
#!/bin/sh
# CARP state change control script
case "$1" in
MASTER)
logger "CARP state changed to MASTER, starting services"
service rpcbind start >/dev/null 2>&1
service mountd start >/dev/null 2>&1
service nfsd start >/dev/null 2>&1
service nfsuserd start >/dev/null 2>&1
service stunnel restart >/dev/null 2>&1
logger "CARP MASTER: NFS and stunnel services started"
;;
BACKUP)
logger "CARP state changed to BACKUP, stopping services"
service stunnel stop >/dev/null 2>&1
service nfsd stop >/dev/null 2>&1
service mountd stop >/dev/null 2>&1
service nfsuserd stop >/dev/null 2>&1
logger "CARP BACKUP: NFS and stunnel services stopped"
;;
*)
logger "CARP state changed to $1 (unhandled)"
;;
esac
EOF
paul@f0:~ % doas chmod +x /usr/local/bin/carpcontrol.sh
# Create the CARP management script
paul@f0:~ % doas tee /usr/local/bin/carp <<'EOF'
#!/bin/sh
# CARP state management script
# Usage: carp [master|backup|auto-failback enable|auto-failback disable]
# Without arguments: shows current state
# Find the interface with CARP configured
CARP_IF=$(ifconfig -l | xargs -n1 | while read if; do
ifconfig "$if" 2>/dev/null | grep -q "carp:" && echo "$if" && break
done)
if [ -z "$CARP_IF" ]; then
echo "Error: No CARP interface found"
exit 1
fi
# Get CARP VHID
VHID=$(ifconfig "$CARP_IF" | grep "carp:" | sed -n 's/.*vhid \([0-9]*\).*/\1/p')
if [ -z "$VHID" ]; then
echo "Error: Could not determine CARP VHID"
exit 1
fi
# Function to get the current state
get_state() {
ifconfig "$CARP_IF" | grep "carp:" | awk '{print $2}'
}
# Check for auto-failback block file
BLOCK_FILE="/data/nfs/nfs.NO_AUTO_FAILBACK"
check_auto_failback() {
if [ -f "$BLOCK_FILE" ]; then
echo "WARNING: Auto-failback is DISABLED (file exists: $BLOCK_FILE)"
fi
}
# Main logic
case "$1" in
"")
# No argument - show current state
STATE=$(get_state)
echo "CARP state on $CARP_IF (vhid $VHID): $STATE"
check_auto_failback
;;
master)
# Force to MASTER state
echo "Setting CARP to MASTER state..."
ifconfig "$CARP_IF" vhid "$VHID" state master
sleep 1
STATE=$(get_state)
echo "CARP state on $CARP_IF (vhid $VHID): $STATE"
check_auto_failback
;;
backup)
# Force to BACKUP state
echo "Setting CARP to BACKUP state..."
ifconfig "$CARP_IF" vhid "$VHID" state backup
sleep 1
STATE=$(get_state)
echo "CARP state on $CARP_IF (vhid $VHID): $STATE"
check_auto_failback
;;
auto-failback)
case "$2" in
enable)
if [ -f "$BLOCK_FILE" ]; then
rm "$BLOCK_FILE"
echo "Auto-failback ENABLED (removed $BLOCK_FILE)"
else
echo "Auto-failback was already enabled"
fi
;;
disable)
if [ ! -f "$BLOCK_FILE" ]; then
touch "$BLOCK_FILE"
echo "Auto-failback DISABLED (created $BLOCK_FILE)"
else
echo "Auto-failback was already disabled"
fi
;;
*)
echo "Usage: $0 auto-failback [enable|disable]"
echo " enable: Remove block file to allow automatic failback"
echo " disable: Create block file to prevent automatic failback"
exit 1
;;
esac
;;
*)
echo "Usage: $0 [master|backup|auto-failback enable|auto-failback disable]"
echo " Without arguments: show current CARP state"
echo " master: force this node to become CARP MASTER"
echo " backup: force this node to become CARP BACKUP"
echo " auto-failback enable: allow automatic failback to f0"
echo " auto-failback disable: prevent automatic failback to f0"
exit 1
;;
esac
EOF
paul@f0:~ % doas chmod +x /usr/local/bin/carp
# Copy to f1 as well
paul@f0:~ % scp /usr/local/bin/carp f1:/tmp/
paul@f1:~ % doas cp /tmp/carp /usr/local/bin/carp && doas chmod +x /usr/local/bin/carp
# Check current CARP state paul@f0:~ % doas carp CARP state on re0 (vhid 1): MASTER # If auto-failback is disabled, you'll see a warning paul@f0:~ % doas carp CARP state on re0 (vhid 1): MASTER WARNING: Auto-failback is DISABLED (file exists: /data/nfs/nfs.NO_AUTO_FAILBACK) # Force f0 to become BACKUP (triggers failover to f1) paul@f0:~ % doas carp backup Setting CARP to BACKUP state... CARP state on re0 (vhid 1): BACKUP # Disable auto-failback (useful for maintenance) paul@f0:~ % doas carp auto-failback disable Auto-failback DISABLED (created /data/nfs/nfs.NO_AUTO_FAILBACK) # Enable auto-failback paul@f0:~ % doas carp auto-failback enable Auto-failback ENABLED (removed /data/nfs/nfs.NO_AUTO_FAILBACK)
paul@f0:~ % doas tee /usr/local/bin/carp-auto-failback.sh <<'EOF'
#!/bin/sh
# CARP automatic failback script for f0
# Ensures f0 reclaims MASTER role after reboot when storage is ready
LOGFILE="/var/log/carp-auto-failback.log"
MARKER_FILE="/data/nfs/nfs.DO_NOT_REMOVE"
BLOCK_FILE="/data/nfs/nfs.NO_AUTO_FAILBACK"
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOGFILE"
}
# Check if we're already MASTER
CURRENT_STATE=$(/usr/local/bin/carp | awk '{print $NF}')
if [ "$CURRENT_STATE" = "MASTER" ]; then
exit 0
fi
# Check if /data/nfs is mounted
if ! mount | grep -q "on /data/nfs "; then
log_message "SKIP: /data/nfs not mounted"
exit 0
fi
# Check if the marker file exists
# (identifies that the ZFS data set is properly mounted)
if [ ! -f "$MARKER_FILE" ]; then
log_message "SKIP: Marker file $MARKER_FILE not found"
exit 0
fi
# Check if failback is blocked (for maintenance)
if [ -f "$BLOCK_FILE" ]; then
log_message "SKIP: Failback blocked by $BLOCK_FILE"
exit 0
fi
# Check if NFS services are running (ensure we're fully ready)
if ! service nfsd status >/dev/null 2>&1; then
log_message "SKIP: NFS services not yet running"
exit 0
fi
# All conditions met - promote to MASTER
log_message "CONDITIONS MET: Promoting to MASTER (was $CURRENT_STATE)"
/usr/local/bin/carp master
# Log result
sleep 2
NEW_STATE=$(/usr/local/bin/carp | awk '{print $NF}')
log_message "Failback complete: State is now $NEW_STATE"
# If successful, log to the system log too
if [ "$NEW_STATE" = "MASTER" ]; then
logger "CARP: f0 automatically reclaimed MASTER role"
fi
EOF
paul@f0:~ % doas chmod +x /usr/local/bin/carp-auto-failback.sh
paul@f0:~ % doas touch /data/nfs/nfs.DO_NOT_REMOVE
paul@f0:~ % echo "* * * * * /usr/local/bin/carp-auto-failback.sh" | doas crontab -
paul@f0:~ % doas carp auto-failback disable Auto-failback DISABLED (created /data/nfs/nfs.NO_AUTO_FAILBACK)
paul@f0:~ % doas carp auto-failback enable Auto-failback ENABLED (removed /data/nfs/nfs.NO_AUTO_FAILBACK)
paul@f0:~ % doas carp CARP state on re0 (vhid 1): MASTER # If disabled, you'll see: WARNING: Auto-failback is DISABLED
# Install stunnel on client (example for `r0`) [root@r0 ~]# dnf install -y stunnel nfs-utils # Copy client certificate and CA certificate from f0 [root@r0 ~]# scp f0:/usr/local/etc/stunnel/ca/r0-key.pem /etc/stunnel/ [root@r0 ~]# scp f0:/usr/local/etc/stunnel/ca/ca-cert.pem /etc/stunnel/ # Configure stunnel client with certificate authentication [root@r0 ~]# tee /etc/stunnel/stunnel.conf <<'EOF' cert = /etc/stunnel/r0-key.pem CAfile = /etc/stunnel/ca-cert.pem client = yes verify = 2 [nfs-ha] accept = 127.0.0.1:2323 connect = 192.168.1.138:2323 EOF # Enable and start stunnel [root@r0 ~]# systemctl enable --now stunnel # Repeat for r1 and r2 with their respective certificates
# Create a mount point [root@r0 ~]# mkdir -p /data/nfs/k3svolumes # Mount through stunnel (using localhost and NFSv4) [root@r0 ~]# mount -t nfs4 -o port=2323 127.0.0.1:/data/nfs/k3svolumes /data/nfs/k3svolumes # Verify mount [root@r0 ~]# mount | grep k3svolumes 127.0.0.1:/data/nfs/k3svolumes on /data/nfs/k3svolumes type nfs4 (rw,relatime,vers=4.2,rsize=131072,wsize=131072, namlen=255,hard,proto=tcp,port=2323,timeo=600,retrans=2,sec=sys, clientaddr=127.0.0.1,local_lock=none,addr=127.0.0.1) # For persistent mount, add to /etc/fstab: 127.0.0.1:/data/nfs/k3svolumes /data/nfs/k3svolumes nfs4 port=2323,_netdev 0 0
# On f0 (current MASTER) - trigger failover
paul@f0:~ % doas ifconfig re0 vhid 1 state backup
# On f1 - verify it becomes MASTER
paul@f1:~ % ifconfig re0 | grep carp
inet 192.168.1.138 netmask 0xffffffff broadcast 192.168.1.138 vhid 1
# Check stunnel is now listening on f1
paul@f1:~ % doas sockstat -l | grep 2323
stunnel stunnel 4567 3 tcp4 192.168.1.138:2323 *:*
# On client - verify NFS mount still works
[root@r0 ~]# ls /data/nfs/k3svolumes/
[root@r0 ~]# echo "Test after failover" > /data/nfs/k3svolumes/failover-test.txt
# Force unmount and remount [root@r0 ~]# umount -f /data/nfs/k3svolumes [root@r0 ~]# mount /data/nfs/k3svolumes
[root@r0 ~]# cat > /usr/local/bin/check-nfs-mount.sh << 'EOF'
#!/bin/bash
# Fast NFS mount health monitor - runs every 10 seconds via systemd timer
MOUNT_POINT="/data/nfs/k3svolumes"
LOCK_FILE="/var/run/nfs-mount-check.lock"
# Use a lock file to prevent concurrent runs
if [ -f "$LOCK_FILE" ]; then
exit 0
fi
touch "$LOCK_FILE"
trap "rm -f $LOCK_FILE" EXIT
fix_mount () {
echo "Attempting to remount NFS mount $MOUNT_POINT"
if mount -o remount -f "$MOUNT_POINT" 2>/dev/null; then
echo "Remount command issued for $MOUNT_POINT"
else
echo "Failed to remount NFS mount $MOUNT_POINT"
fi
echo "Checking if $MOUNT_POINT is a mountpoint"
if mountpoint "$MOUNT_POINT" >/dev/null 2>&1; then
echo "$MOUNT_POINT is a valid mountpoint"
else
echo "$MOUNT_POINT is not a valid mountpoint, attempting mount"
if mount "$MOUNT_POINT"; then
echo "Successfully mounted $MOUNT_POINT"
return
else
echo "Failed to mount $MOUNT_POINT"
fi
fi
echo "Attempting to unmount $MOUNT_POINT"
if umount -f "$MOUNT_POINT" 2>/dev/null; then
echo "Successfully unmounted $MOUNT_POINT"
else
echo "Failed to unmount $MOUNT_POINT (it might not be mounted)"
fi
echo "Attempting to mount $MOUNT_POINT"
if mount "$MOUNT_POINT"; then
echo "NFS mount $MOUNT_POINT mounted successfully"
return
else
echo "Failed to mount NFS mount $MOUNT_POINT"
fi
echo "Failed to fix NFS mount $MOUNT_POINT"
exit 1
}
if ! mountpoint "$MOUNT_POINT" >/dev/null 2>&1; then
echo "NFS mount $MOUNT_POINT not found"
fix_mount
fi
if ! timeout 2s stat "$MOUNT_POINT" >/dev/null 2>&1; then
echo "NFS mount $MOUNT_POINT appears to be unresponsive"
fix_mount
fi
EOF
[root@r0 ~]# chmod +x /usr/local/bin/check-nfs-mount.sh
[root@r0 ~]# cat > /etc/systemd/system/nfs-mount-monitor.service << 'EOF' [Unit] Description=NFS Mount Health Monitor After=network-online.target [Service] Type=oneshot ExecStart=/usr/local/bin/check-nfs-mount.sh StandardOutput=journal StandardError=journal EOF
[root@r0 ~]# cat > /etc/systemd/system/nfs-mount-monitor.timer << 'EOF' [Unit] Description=Run NFS Mount Health Monitor every 10 seconds Requires=nfs-mount-monitor.service [Timer] OnBootSec=30s OnUnitActiveSec=10s AccuracySec=1s [Install] WantedBy=timers.target EOF
[root@r0 ~]# systemctl daemon-reload
[root@r0 ~]# systemctl enable nfs-mount-monitor.timer
[root@r0 ~]# systemctl start nfs-mount-monitor.timer
# Check status
[root@r0 ~]# systemctl status nfs-mount-monitor.timer
● nfs-mount-monitor.timer - Run NFS Mount Health Monitor every 10 seconds
Loaded: loaded (/etc/systemd/system/nfs-mount-monitor.timer; enabled)
Active: active (waiting) since Sat 2025-07-06 10:00:00 EEST
Trigger: Sat 2025-07-06 10:00:10 EEST; 8s left
# Monitor logs
[root@r0 ~]# journalctl -u nfs-mount-monitor -f
# 1. Check the initial state
paul@f0:~ % ifconfig re0 | grep carp
carp: MASTER vhid 1 advbase 1 advskew 0
paul@f1:~ % ifconfig re0 | grep carp
carp: BACKUP vhid 1 advbase 1 advskew 0
# 2. Create a test file from a client
[root@r0 ~]# echo "test before failover" > /data/nfs/k3svolumes/test-before.txt
# 3. Trigger failover (f0 → f1)
paul@f0:~ % doas ifconfig re0 vhid 1 state backup
# 4. Monitor client behaviour
[root@r0 ~]# ls /data/nfs/k3svolumes/
ls: cannot access '/data/nfs/k3svolumes/': Stale file handle
# 5. Check automatic recovery (within 10 seconds)
[root@r0 ~]# journalctl -u nfs-mount-monitor -f
Jul 06 10:15:32 r0 nfs-monitor[1234]: NFS mount unhealthy detected at \
Sun Jul 6 10:15:32 EEST 2025
Jul 06 10:15:32 r0 nfs-monitor[1234]: Attempting to fix stale NFS mount at \
Sun Jul 6 10:15:32 EEST 2025
Jul 06 10:15:33 r0 nfs-monitor[1234]: NFS mount fixed at \
Sun Jul 6 10:15:33 EEST 2025



paul@f0:~ % doas freebsd-update fetch paul@f0:~ % doas freebsd-update install paul@f0:~ % doas shutdown -r now .. .. paul@f0:~ % doas pkg update paul@f0:~ % doas pkg upgrade paul@f0:~ % reboot
paul@f0:~ % doas pkg install wireguard-tools paul@f0:~ % doas sysrc wireguard_interfaces=wg0 wireguard_interfaces: -> wg0 paul@f0:~ % doas sysrc wireguard_enable=YES wireguard_enable: -> YES paul@f0:~ % doas mkdir -p /usr/local/etc/wireguard paul@f0:~ % doas touch /usr/local/etc/wireguard/wg0.conf paul@f0:~ % doas service wireguard start paul@f0:~ % doas wg show interface: wg0 public key: L+V9o0fNYkMVKNqsX7spBzD/9oSvxM/C7ZCZX1jLO3Q= private key: (hidden) listening port: 20246
paul@f0:~ % cat <<END | doas tee -a /etc/hosts 192.168.1.120 r0 r0.lan r0.lan.buetow.org 192.168.1.121 r1 r1.lan r1.lan.buetow.org 192.168.1.122 r2 r2.lan r2.lan.buetow.org 192.168.2.130 f0.wg0 f0.wg0.wan.buetow.org 192.168.2.131 f1.wg0 f1.wg0.wan.buetow.org 192.168.2.132 f2.wg0 f2.wg0.wan.buetow.org 192.168.2.120 r0.wg0 r0.wg0.wan.buetow.org 192.168.2.121 r1.wg0 r1.wg0.wan.buetow.org 192.168.2.122 r2.wg0 r2.wg0.wan.buetow.org 192.168.2.110 blowfish.wg0 blowfish.wg0.wan.buetow.org 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org END
[root@r0 ~] dnf update -y [root@r0 ~] reboot
[root@r0 ~] dnf install -y wireguard-tools [root@r0 ~] mkdir -p /etc/wireguard [root@r0 ~] touch /etc/wireguard/wg0.conf [root@r0 ~] systemctl enable wg-quick@wg0.service [root@r0 ~] systemctl start wg-quick@wg0.service [root@r0 ~] systemctl disable firewalld
[root@r0 ~] cat <<END >>/etc/hosts 192.168.1.130 f0 f0.lan f0.lan.buetow.org 192.168.1.131 f1 f1.lan f1.lan.buetow.org 192.168.1.132 f2 f2.lan f2.lan.buetow.org 192.168.2.130 f0.wg0 f0.wg0.wan.buetow.org 192.168.2.131 f1.wg0 f1.wg0.wan.buetow.org 192.168.2.132 f2.wg0 f2.wg0.wan.buetow.org 192.168.2.120 r0.wg0 r0.wg0.wan.buetow.org 192.168.2.121 r1.wg0 r1.wg0.wan.buetow.org 192.168.2.122 r2.wg0 r2.wg0.wan.buetow.org 192.168.2.110 blowfish.wg0 blowfish.wg0.wan.buetow.org 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org END
[root@r0 ~] dnf install -y policycoreutils-python-utils [root@r0 ~] semanage permissive -a wireguard_t [root@r0 ~] reboot
blowfish$ doas pkg_add wireguard-tools blowfish$ doas mkdir /etc/wireguard blowfish$ doas touch /etc/wireguard/wg0.conf blowsish$ cat <<END | doas tee /etc/hostname.wg0 inet 192.168.2.110 255.255.255.0 NONE up !/usr/local/bin/wg setconf wg0 /etc/wireguard/wg0.conf END
blowfish$ cat <<END | doas tee -a /etc/hosts 192.168.2.130 f0.wg0 f0.wg0.wan.buetow.org 192.168.2.131 f1.wg0 f1.wg0.wan.buetow.org 192.168.2.132 f2.wg0 f2.wg0.wan.buetow.org 192.168.2.120 r0.wg0 r0.wg0.wan.buetow.org 192.168.2.121 r1.wg0 r1.wg0.wan.buetow.org 192.168.2.122 r2.wg0 r2.wg0.wan.buetow.org 192.168.2.110 blowfish.wg0 blowfish.wg0.wan.buetow.org 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org END
[Interface] # f0.wg0.wan.buetow.org Address = 192.168.2.130 PrivateKey = ************************** ListenPort = 56709 [Peer] # f1.lan.buetow.org as f1.wg0.wan.buetow.org PublicKey = ************************** PresharedKey = ************************** AllowedIPs = 192.168.2.131/32 Endpoint = 192.168.1.131:56709 # No KeepAlive configured [Peer] # f2.lan.buetow.org as f2.wg0.wan.buetow.org PublicKey = ************************** PresharedKey = ************************** AllowedIPs = 192.168.2.132/32 Endpoint = 192.168.1.132:56709 # No KeepAlive configured [Peer] # r0.lan.buetow.org as r0.wg0.wan.buetow.org PublicKey = ************************** PresharedKey = ************************** AllowedIPs = 192.168.2.120/32 Endpoint = 192.168.1.120:56709 # No KeepAlive configured [Peer] # r1.lan.buetow.org as r1.wg0.wan.buetow.org PublicKey = ************************** PresharedKey = ************************** AllowedIPs = 192.168.2.121/32 Endpoint = 192.168.1.121:56709 # No KeepAlive configured [Peer] # r2.lan.buetow.org as r2.wg0.wan.buetow.org PublicKey = ************************** PresharedKey = ************************** AllowedIPs = 192.168.2.122/32 Endpoint = 192.168.1.122:56709 # No KeepAlive configured [Peer] # blowfish.buetow.org as blowfish.wg0.wan.buetow.org PublicKey = ************************** PresharedKey = ************************** AllowedIPs = 192.168.2.110/32 Endpoint = 23.88.35.144:56709 PersistentKeepalive = 25 [Peer] # fishfinger.buetow.org as fishfinger.wg0.wan.buetow.org PublicKey = ************************** PresharedKey = ************************** AllowedIPs = 192.168.2.111/32 Endpoint = 46.23.94.99:56709 PersistentKeepalive = 25
> git clone https://codeberg.org/snonux/wireguardmeshgenerator > cd ./wireguardmeshgenerator > bundle install > sudo dnf install -y wireguard-tools
---
hosts:
f0:
os: FreeBSD
ssh:
user: paul
conf_dir: /usr/local/etc/wireguard
sudo_cmd: doas
reload_cmd: service wireguard reload
lan:
domain: 'lan.buetow.org'
ip: '192.168.1.130'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.130'
f1:
os: FreeBSD
ssh:
user: paul
conf_dir: /usr/local/etc/wireguard
sudo_cmd: doas
reload_cmd: service wireguard reload
lan:
domain: 'lan.buetow.org'
ip: '192.168.1.131'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.131'
f2:
os: FreeBSD
ssh:
user: paul
conf_dir: /usr/local/etc/wireguard
sudo_cmd: doas
reload_cmd: service wireguard reload
lan:
domain: 'lan.buetow.org'
ip: '192.168.1.132'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.132'
r0:
os: Linux
ssh:
user: root
conf_dir: /etc/wireguard
sudo_cmd:
reload_cmd: systemctl reload wg-quick@wg0.service
lan:
domain: 'lan.buetow.org'
ip: '192.168.1.120'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.120'
r1:
os: Linux
ssh:
user: root
conf_dir: /etc/wireguard
sudo_cmd:
reload_cmd: systemctl reload wg-quick@wg0.service
lan:
domain: 'lan.buetow.org'
ip: '192.168.1.121'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.121'
r2:
os: Linux
ssh:
user: root
conf_dir: /etc/wireguard
sudo_cmd:
reload_cmd: systemctl reload wg-quick@wg0.service
lan:
domain: 'lan.buetow.org'
ip: '192.168.1.122'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.122'
blowfish:
os: OpenBSD
ssh:
user: rex
conf_dir: /etc/wireguard
sudo_cmd: doas
reload_cmd: sh /etc/netstart wg0
internet:
domain: 'buetow.org'
ip: '23.88.35.144'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.110'
fishfinger:
os: OpenBSD
ssh:
user: rex
conf_dir: /etc/wireguard
sudo_cmd: doas
reload_cmd: sh /etc/netstart wg0
internet:
domain: 'buetow.org'
ip: '46.23.94.99'
wg0:
domain: 'wg0.wan.buetow.org'
ip: '192.168.2.111'
begin
options = { hosts: [] }
OptionParser.new do |opts|
opts.banner = 'Usage: wireguardmeshgenerator.rb [options]'
opts.on('--generate', 'Generate Wireguard configs') do
options[:generate] = true
end
opts.on('--install', 'Install Wireguard configs') do
options[:install] = true
end
opts.on('--clean', 'Clean Wireguard configs') do
options[:clean] = true
end
opts.on('--hosts=HOSTS', 'Comma separated hosts to configure') do |hosts|
options[:hosts] = hosts.split(',')
end
end.parse!
conf = YAML.load_file('wireguardmeshgenerator.yaml').freeze
conf['hosts'].keys.select { options[:hosts].empty? || options[:hosts].include?(_1) }
.each do |host|
# Generate Wireguard configuration for the host reload!
WireguardConfig.new(host, conf['hosts']).generate! if options[:generate]
# Install Wireguard configuration for the host.
InstallConfig.new(host, conf['hosts']).upload!.install!.reload! if options[:install]
# Clean Wireguard configuration for the host.
WireguardConfig.new(host, conf['hosts']).clean! if options[:clean]
end
rescue StandardError => e
puts "Error: #{e.message}"
puts e.backtrace.join("\n")
exit 2
end
task :generate do ruby 'wireguardmeshgenerator.rb', '--generate' end task :clean do ruby 'wireguardmeshgenerator.rb', '--clean' end task :install do ruby 'wireguardmeshgenerator.rb', '--install' end task default: :generate
> rake generate /usr/bin/ruby wireguardmeshgenerator.rb --generate Generating dist/f0/etc/wireguard/wg0.conf Generating dist/f1/etc/wireguard/wg0.conf Generating dist/f2/etc/wireguard/wg0.conf Generating dist/r0/etc/wireguard/wg0.conf Generating dist/r1/etc/wireguard/wg0.conf Generating dist/r2/etc/wireguard/wg0.conf Generating dist/blowfish/etc/wireguard/wg0.conf Generating dist/fishfinger/etc/wireguard/wg0.conf
> find keys/ -type f keys/f0/priv.key keys/f0/pub.key keys/psk/f0_f1.key keys/psk/f0_f2.key keys/psk/f0_r0.key keys/psk/f0_r1.key keys/psk/f0_r2.key keys/psk/blowfish_f0.key keys/psk/f0_fishfinger.key keys/psk/f1_f2.key keys/psk/f1_r0.key keys/psk/f1_r1.key keys/psk/f1_r2.key keys/psk/blowfish_f1.key keys/psk/f1_fishfinger.key keys/psk/f2_r0.key keys/psk/f2_r1.key keys/psk/f2_r2.key keys/psk/blowfish_f2.key keys/psk/f2_fishfinger.key keys/psk/r0_r1.key keys/psk/r0_r2.key keys/psk/blowfish_r0.key keys/psk/fishfinger_r0.key keys/psk/r1_r2.key keys/psk/blowfish_r1.key keys/psk/fishfinger_r1.key keys/psk/blowfish_r2.key keys/psk/fishfinger_r2.key keys/psk/blowfish_fishfinger.key keys/f1/priv.key keys/f1/pub.key keys/f2/priv.key keys/f2/pub.key keys/r0/priv.key keys/r0/pub.key keys/r1/priv.key keys/r1/pub.key keys/r2/priv.key keys/r2/pub.key keys/blowfish/priv.key keys/blowfish/pub.key keys/fishfinger/priv.key keys/fishfinger/pub.key
> rake install /usr/bin/ruby wireguardmeshgenerator.rb --install Uploading dist/f0/etc/wireguard/wg0.conf to f0.lan.buetow.org:. Installing Wireguard config on f0 Uploading cmd.sh to f0.lan.buetow.org:. + [ ! -d /usr/local/etc/wireguard ] + doas chmod 700 /usr/local/etc/wireguard + doas mv -v wg0.conf /usr/local/etc/wireguard wg0.conf -> /usr/local/etc/wireguard/wg0.conf + doas chmod 644 /usr/local/etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on f0 Uploading cmd.sh to f0.lan.buetow.org:. + doas service wireguard reload + rm cmd.sh Uploading dist/f1/etc/wireguard/wg0.conf to f1.lan.buetow.org:. Installing Wireguard config on f1 Uploading cmd.sh to f1.lan.buetow.org:. + [ ! -d /usr/local/etc/wireguard ] + doas chmod 700 /usr/local/etc/wireguard + doas mv -v wg0.conf /usr/local/etc/wireguard wg0.conf -> /usr/local/etc/wireguard/wg0.conf + doas chmod 644 /usr/local/etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on f1 Uploading cmd.sh to f1.lan.buetow.org:. + doas service wireguard reload + rm cmd.sh Uploading dist/f2/etc/wireguard/wg0.conf to f2.lan.buetow.org:. Installing Wireguard config on f2 Uploading cmd.sh to f2.lan.buetow.org:. + [ ! -d /usr/local/etc/wireguard ] + doas chmod 700 /usr/local/etc/wireguard + doas mv -v wg0.conf /usr/local/etc/wireguard wg0.conf -> /usr/local/etc/wireguard/wg0.conf + doas chmod 644 /usr/local/etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on f2 Uploading cmd.sh to f2.lan.buetow.org:. + doas service wireguard reload + rm cmd.sh Uploading dist/r0/etc/wireguard/wg0.conf to r0.lan.buetow.org:. Installing Wireguard config on r0 Uploading cmd.sh to r0.lan.buetow.org:. + '[' '!' -d /etc/wireguard ']' + chmod 700 /etc/wireguard + mv -v wg0.conf /etc/wireguard renamed 'wg0.conf' -> '/etc/wireguard/wg0.conf' + chmod 644 /etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on r0 Uploading cmd.sh to r0.lan.buetow.org:. + systemctl reload wg-quick@wg0.service + rm cmd.sh Uploading dist/r1/etc/wireguard/wg0.conf to r1.lan.buetow.org:. Installing Wireguard config on r1 Uploading cmd.sh to r1.lan.buetow.org:. + '[' '!' -d /etc/wireguard ']' + chmod 700 /etc/wireguard + mv -v wg0.conf /etc/wireguard renamed 'wg0.conf' -> '/etc/wireguard/wg0.conf' + chmod 644 /etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on r1 Uploading cmd.sh to r1.lan.buetow.org:. + systemctl reload wg-quick@wg0.service + rm cmd.sh Uploading dist/r2/etc/wireguard/wg0.conf to r2.lan.buetow.org:. Installing Wireguard config on r2 Uploading cmd.sh to r2.lan.buetow.org:. + '[' '!' -d /etc/wireguard ']' + chmod 700 /etc/wireguard + mv -v wg0.conf /etc/wireguard renamed 'wg0.conf' -> '/etc/wireguard/wg0.conf' + chmod 644 /etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on r2 Uploading cmd.sh to r2.lan.buetow.org:. + systemctl reload wg-quick@wg0.service + rm cmd.sh Uploading dist/blowfish/etc/wireguard/wg0.conf to blowfish.buetow.org:. Installing Wireguard config on blowfish Uploading cmd.sh to blowfish.buetow.org:. + [ ! -d /etc/wireguard ] + doas chmod 700 /etc/wireguard + doas mv -v wg0.conf /etc/wireguard wg0.conf -> /etc/wireguard/wg0.conf + doas chmod 644 /etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on blowfish Uploading cmd.sh to blowfish.buetow.org:. + doas sh /etc/netstart wg0 + rm cmd.sh Uploading dist/fishfinger/etc/wireguard/wg0.conf to fishfinger.buetow.org:. Installing Wireguard config on fishfinger Uploading cmd.sh to fishfinger.buetow.org:. + [ ! -d /etc/wireguard ] + doas chmod 700 /etc/wireguard + doas mv -v wg0.conf /etc/wireguard wg0.conf -> /etc/wireguard/wg0.conf + doas chmod 644 /etc/wireguard/wg0.conf + rm cmd.sh Reloading Wireguard on fishfinger Uploading cmd.sh to fishfinger.buetow.org:. + doas sh /etc/netstart wg0 + rm cmd.sh
> rake clean > rake generate > rake install
paul@f0:~ % doas wg show interface: wg0 public key: Jm6YItMt94++dIeOyVi1I9AhNt2qQcryxCZezoX7X2Y= private key: (hidden) listening port: 56709 peer: 8PvGZH1NohHpZPVJyjhctBX9xblsNvYBhpg68FsFcns= preshared key: (hidden) endpoint: 46.23.94.99:56709 allowed ips: 192.168.2.111/32 latest handshake: 1 minute, 46 seconds ago transfer: 124 B received, 1.75 KiB sent persistent keepalive: every 25 seconds peer: Xow+d3qVXgUMk4pcRSQ6Fe+vhYBa3VDyHX/4jrGoKns= preshared key: (hidden) endpoint: 23.88.35.144:56709 allowed ips: 192.168.2.110/32 latest handshake: 1 minute, 52 seconds ago transfer: 124 B received, 1.60 KiB sent persistent keepalive: every 25 seconds peer: s3e93XoY7dPUQgLiVO4d8x/SRCFgEew+/wP7+zwgehI= preshared key: (hidden) endpoint: 192.168.1.120:56709 allowed ips: 192.168.2.120/32 peer: 2htXdNcxzpI2FdPDJy4T4VGtm1wpMEQu1AkQHjNY6F8= preshared key: (hidden) endpoint: 192.168.1.131:56709 allowed ips: 192.168.2.131/32 peer: 0Y/H20W8YIbF7DA1sMwMacLI8WS9yG+1/QO7m2oyllg= preshared key: (hidden) endpoint: 192.168.1.122:56709 allowed ips: 192.168.2.122/32 peer: Hhy9kMPOOjChXV2RA5WeCGs+J0FE3rcNPDw/TLSn7i8= preshared key: (hidden) endpoint: 192.168.1.121:56709 allowed ips: 192.168.2.121/32 peer: SlGVsACE1wiaRoGvCR3f7AuHfRS+1jjhS+YwEJ2HvF0= preshared key: (hidden) endpoint: 192.168.1.132:56709 allowed ips: 192.168.2.132/32
paul@f0:~ % foreach peer ( f1 f2 r0 r1 r2 blowfish fishfinger ) foreach? ping -c2 $peer.wg0 foreach? echo foreach? end PING f1.wg0 (192.168.2.131): 56 data bytes 64 bytes from 192.168.2.131: icmp_seq=0 ttl=64 time=0.334 ms 64 bytes from 192.168.2.131: icmp_seq=1 ttl=64 time=0.260 ms --- f1.wg0 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.260/0.297/0.334/0.037 ms PING f2.wg0 (192.168.2.132): 56 data bytes 64 bytes from 192.168.2.132: icmp_seq=0 ttl=64 time=0.323 ms 64 bytes from 192.168.2.132: icmp_seq=1 ttl=64 time=0.303 ms --- f2.wg0 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.303/0.313/0.323/0.010 ms PING r0.wg0 (192.168.2.120): 56 data bytes 64 bytes from 192.168.2.120: icmp_seq=0 ttl=64 time=0.716 ms 64 bytes from 192.168.2.120: icmp_seq=1 ttl=64 time=0.406 ms --- r0.wg0 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.406/0.561/0.716/0.155 ms PING r1.wg0 (192.168.2.121): 56 data bytes 64 bytes from 192.168.2.121: icmp_seq=0 ttl=64 time=0.639 ms 64 bytes from 192.168.2.121: icmp_seq=1 ttl=64 time=0.629 ms --- r1.wg0 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.629/0.634/0.639/0.005 ms PING r2.wg0 (192.168.2.122): 56 data bytes 64 bytes from 192.168.2.122: icmp_seq=0 ttl=64 time=0.569 ms 64 bytes from 192.168.2.122: icmp_seq=1 ttl=64 time=0.479 ms --- r2.wg0 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.479/0.524/0.569/0.045 ms PING blowfish.wg0 (192.168.2.110): 56 data bytes 64 bytes from 192.168.2.110: icmp_seq=0 ttl=255 time=35.745 ms 64 bytes from 192.168.2.110: icmp_seq=1 ttl=255 time=35.481 ms --- blowfish.wg0 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 35.481/35.613/35.745/0.132 ms PING fishfinger.wg0 (192.168.2.111): 56 data bytes 64 bytes from 192.168.2.111: icmp_seq=0 ttl=255 time=33.992 ms 64 bytes from 192.168.2.111: icmp_seq=1 ttl=255 time=33.751 ms --- fishfinger.wg0 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 33.751/33.872/33.992/0.120 ms
paul@f0:~ % doas wg show interface: wg0 public key: Jm6YItMt94++dIeOyVi1I9AhNt2qQcryxCZezoX7X2Y= private key: (hidden) listening port: 56709 peer: 0Y/H20W8YIbF7DA1sMwMacLI8WS9yG+1/QO7m2oyllg= preshared key: (hidden) endpoint: 192.168.1.122:56709 allowed ips: 192.168.2.122/32 latest handshake: 10 seconds ago transfer: 440 B received, 532 B sent peer: Hhy9kMPOOjChXV2RA5WeCGs+J0FE3rcNPDw/TLSn7i8= preshared key: (hidden) endpoint: 192.168.1.121:56709 allowed ips: 192.168.2.121/32 latest handshake: 12 seconds ago transfer: 440 B received, 564 B sent peer: s3e93XoY7dPUQgLiVO4d8x/SRCFgEew+/wP7+zwgehI= preshared key: (hidden) endpoint: 192.168.1.120:56709 allowed ips: 192.168.2.120/32 latest handshake: 14 seconds ago transfer: 440 B received, 564 B sent peer: SlGVsACE1wiaRoGvCR3f7AuHfRS+1jjhS+YwEJ2HvF0= preshared key: (hidden) endpoint: 192.168.1.132:56709 allowed ips: 192.168.2.132/32 latest handshake: 17 seconds ago transfer: 472 B received, 564 B sent peer: Xow+d3qVXgUMk4pcRSQ6Fe+vhYBa3VDyHX/4jrGoKns= preshared key: (hidden) endpoint: 23.88.35.144:56709 allowed ips: 192.168.2.110/32 latest handshake: 55 seconds ago transfer: 472 B received, 596 B sent persistent keepalive: every 25 seconds peer: 8PvGZH1NohHpZPVJyjhctBX9xblsNvYBhpg68FsFcns= preshared key: (hidden) endpoint: 46.23.94.99:56709 allowed ips: 192.168.2.111/32 latest handshake: 55 seconds ago transfer: 472 B received, 596 B sent persistent keepalive: every 25 seconds peer: 2htXdNcxzpI2FdPDJy4T4VGtm1wpMEQu1AkQHjNY6F8= preshared key: (hidden) endpoint: 192.168.1.131:56709 allowed ips: 192.168.2.131/32
_______ s
|.-----.| s
|| Tmux|| s
||_.-._|| |\ \\\\__ o s
`--)-(--` | \_/ o \ o s
__[=== o]__ > _ (( <_ oo s
|:::::::::::|\ | / \__+___/ s
jgs `-=========-`() |/ |/ s
mod. by Paul B.
alias tn 'tmux::new' alias ta 'tmux::attach' alias tx 'tmux::remote' alias ts 'tmux::search' alias tssh 'tmux::cluster_ssh' alias tm tmux alias tl 'tmux list-sessions' alias foo 'tmux::new foo' alias bar 'tmux::new bar' alias baz 'tmux::new baz'
# Create new session and if alread exists attach to it
function tmux::new
set -l session $argv[1]
_tmux::cleanup_default
if test -z "$session"
tmux::new (string join "" T (date +%s))
else
tmux new-session -d -s $session
tmux -2 attach-session -t $session || tmux -2 switch-client -t $session
end
end
function _tmux::cleanup_default
tmux list-sessions | string match -r '^T.*: ' | string match -v -r attached | string split ':' | while read -l s
echo "Killing $s"
tmux kill-session -t "$s"
end
end
function tmux::attach
set -l session $argv[1]
if test -z "$session"
tmux attach-session || tmux::new
else
tmux attach-session -t $session || tmux::new $session
end
end
function tmux::remote
set -l server $argv[1]
tmux new -s $server "ssh -A -t $server 'tmux attach-session || tmux'" || tmux attach-session -d -t $server
end
set-option -g prefix C-g
function tmux::search
set -l session (tmux list-sessions | fzf | cut -d: -f1)
if test -z "$TMUX"
tmux attach-session -t $session
else
tmux switch -t $session
end
end

function tmux::cluster_ssh
if test -f "$argv[1]"
tmux::tssh_from_file $argv[1]
return
end
tmux::tssh_from_argument $argv
end
function tmux::tssh_from_argument
set -l session $argv[1]
set first_server_or_container $argv[2]
set remaining_servers $argv[3..-1]
if test -z "$first_server_or_container"
set first_server_or_container $session
end
tmux new-session -d -s $session (_tmux::connect_command "$first_server_or_container")
if not tmux list-session | grep "^$session:"
echo "Could not create session $session"
return 2
end
for server_or_container in $remaining_servers
tmux split-window -t $session "tmux select-layout tiled; $(_tmux::connect_command "$server_or_container")"
end
tmux setw -t $session synchronize-panes on
tmux -2 attach-session -t $session || tmux -2 switch-client -t $session
end
bind-key p setw synchronize-panes off bind-key P setw synchronize-panes on
function tmux::tssh_from_file
set -l serverlist $argv[1]
set -l session (basename $serverlist | cut -d. -f1)
tmux::tssh_from_argument $session (awk '{ print $1 }' $serverlist | sed 's/.lan./.lan/g')
end
$ tssh fish blowfish.buetow.org fishfinger.buetow.org \
fishbone.buetow.org user@octopus.buetow.org
$ tssh manyservers.txt
bind-key -T copy-mode-vi 'v' send -X begin-selection bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel
source ~/.config/tmux/tmux.local.conf set-option -g allow-rename off set-option -g history-limit 100000 set-option -g status-bg '#444444' set-option -g status-fg '#ffa500' set-option -s escape-time 0
set-window-option -g mode-keys vi bind-key -T copy-mode-vi 'v' send -X begin-selection bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel
bind-key h select-pane -L bind-key j select-pane -D bind-key k select-pane -U bind-key l select-pane -R bind-key H resize-pane -L 5 bind-key J resize-pane -D 5 bind-key K resize-pane -U 5 bind-key L resize-pane -R 5
bind-key c new-window -c '#{pane_current_path}'
bind-key F new-window -n "session-switcher" "tmux list-sessions | fzf | cut -d: -f1 | xargs tmux switch-client -t"
bind-key T choose-tree

bind-key p setw synchronize-panes off bind-key P setw synchronize-panes on bind-key r source-file ~/.config/tmux/tmux.conf \; display-message "tmux.conf reloaded"
__ (`/\ `=\/\ __...--~~~~~-._ _.-~~~~~--...__ `=\/\ \ / \\ `=\/ V \\ //_\___--~~~~~~-._ | _.-~~~~~~--...__\\ // ) (..----~~~~._\ | /_.~~~~----.....__\\ ===( INK )==========\\|//==================== __ejm\___/________dwb`---`______________________

paul@f0:~ % dmesg | grep 'Features2=.*POPCNT' Features2=0x7ffafbbf<SSE3,PCLMULQDQ,DTES64,MON,DS_CPL,VMX,EST,TM2,SSSE3,SDBG, FMA,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,TSCDLT,AESNI,XSAVE, OSXSAVE,AVX,F16C,RDRAND>
paul@f0:~ % doas pkg install vm-bhyve bhyve-firmware paul@f0:~ % doas sysrc vm_enable=YES vm_enable: -> YES paul@f0:~ % doas sysrc vm_dir=zfs:zroot/bhyve vm_dir: -> zfs:zroot/bhyve paul@f0:~ % doas zfs create zroot/bhyve paul@f0:~ % doas vm init paul@f0:~ % doas vm switch create public paul@f0:~ % doas vm switch add public re0
paul@f0:~ % zfs list | grep bhyve zroot/bhyve 1.74M 453G 1.74M /zroot/bhyve
paul@f0:~ % doas ln -s /zroot/bhyve/ /bhyve
paul@f0:~ % doas vm list NAME DATASTORE LOADER CPU MEMORY VNC AUTO STATE
paul@f0:~ % doas vm iso \ https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9.5-x86_64-minimal.iso /zroot/bhyve/.iso/Rocky-9.5-x86_64-minimal.iso 1808 MB 4780 kBps 06m28s paul@f0:/bhyve % doas vm create rocky
paul@f0:/bhyve/rocky % cat rocky.conf loader="bhyveload" cpu=1 memory=256M network0_type="virtio-net" network0_switch="public" disk0_type="virtio-blk" disk0_name="disk0.img" uuid="1c4655ac-c828-11ef-a920-e8ff1ed71ca0" network0_mac="58:9c:fc:0d:13:3f"
guest="linux" loader="uefi" uefi_vars="yes" cpu=4 memory=14G network0_type="virtio-net" network0_switch="public" disk0_type="virtio-blk" disk0_name="disk0.img" graphics="yes" graphics_vga=io uuid="1c45400b-c828-11ef-8871-e8ff1ed71cac" network0_mac="58:9c:fc:0d:13:3f"
paul@f0:~ % doas vm install rocky Rocky-9.5-x86_64-minimal.iso Starting rocky * found guest in /zroot/bhyve/rocky * booting... paul@f0:/bhyve/rocky % doas vm list NAME DATASTORE LOADER CPU MEMORY VNC AUTO STATE rocky default uefi 4 14G 0.0.0.0:5900 No Locked (f0.lan.buetow.org) paul@f0:/bhyve/rocky % doas sockstat -4 | grep 5900 root bhyve 6079 8 tcp4 *:5900 *:*
paul@f0:/bhyve/rocky % doas vm stop rocky paul@f0:/bhyve/rocky % doas truncate -s 100G disk0.img paul@f0:/bhyve/rocky % doas vm install rocky Rocky-9.5-x86_64-minimal.iso




paul@f0:/bhyve/rocky % cat <<END | doas tee -a /etc/rc.conf vm_list="rocky" vm_delay="5"
paul@f0:~ % doas vm list NAME DATASTORE LOADER CPU MEMORY VNC AUTO STATE rocky default uefi 4 14G 0.0.0.0:5900 Yes [1] Running (2063)
192.168.1.130 f0 f0.lan f0.lan.buetow.org 192.168.1.131 f1 f1.lan f1.lan.buetow.org 192.168.1.132 f2 f2.lan f2.lan.buetow.org
paul@f0:/bhyve/rocky % cat <<END | doas tee -a /etc/hosts 192.168.1.120 r0 r0.lan r0.lan.buetow.org 192.168.1.121 r1 r1.lan r1.lan.buetow.org 192.168.1.122 r2 r2.lan r2.lan.buetow.org END
[root@r0 ~] % dnmcli connection modify enp0s5 ipv4.address 192.168.1.120/24 [root@r0 ~] % dnmcli connection modify enp0s5 ipv4.gateway 192.168.1.1 [root@r0 ~] % dnmcli connection modify enp0s5 ipv4.DNS 192.168.1.1 [root@r0 ~] % dnmcli connection modify enp0s5 ipv4.method manual [root@r0 ~] % dnmcli connection down enp0s5 [root@r0 ~] % dnmcli connection up enp0s5 [root@r0 ~] % hostnamectl set-hostname r0.lan.buetow.org [root@r0 ~] % cat <<END >>/etc/hosts 192.168.1.120 r0 r0.lan r0.lan.buetow.org 192.168.1.121 r1 r1.lan r1.lan.buetow.org 192.168.1.122 r2 r2.lan r2.lan.buetow.org END
% for i in 0 1 2; do ssh-copy-id root@r$i.lan.buetow.org; done
[root@r0 ~] % dnf update [root@r0 ~] % reboot
package main
import "testing"
func BenchmarkCPUSilly1(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = i * i
}
}
func BenchmarkCPUSilly2(b *testing.B) {
var sillyResult float64
for i := 0; i < b.N; i++ {
sillyResult += float64(i)
sillyResult *= float64(i)
divisor := float64(i) + 1
if divisor > 0 {
sillyResult /= divisor
}
}
_ = sillyResult // to avoid compiler optimization
}
paul@f0:~ % doas pkg install git go paul@f0:~ % mkdir ~/git && cd ~/git && \ git clone https://codeberg.org/snonux/sillybench && \ cd sillybench
paul@f0:~/git/sillybench % go version go version go1.24.1 freebsd/amd64 paul@f0:~/git/sillybench % go test -bench=. goos: freebsd goarch: amd64 pkg: codeberg.org/snonux/sillybench cpu: Intel(R) N100 BenchmarkCPUSilly1-4 1000000000 0.4022 ns/op BenchmarkCPUSilly2-4 1000000000 0.4027 ns/op PASS ok codeberg.org/snonux/sillybench 0.891s
[root@r0 ~]# dnf install golang git [root@r0 ~]# mkdir ~/git && cd ~/git && \ git clone https://codeberg.org/snonux/sillybench && \ cd sillybench
[root@r0 sillybench]# go version go version go1.22.9 (Red Hat 1.22.9-2.el9_5) linux/amd64 [root@r0 sillybench]# go test -bench=. goos: linux goarch: amd64 pkg: codeberg.org/snonux/sillybench cpu: Intel(R) N100 BenchmarkCPUSilly1-4 1000000000 0.4347 ns/op BenchmarkCPUSilly2-4 1000000000 0.4345 ns/op
root@freebsd:~/git/sillybench # go test -bench=. goos: freebsd goarch: amd64 pkg: codeberg.org/snonux/sillybench cpu: Intel(R) N100 BenchmarkCPUSilly1 1000000000 0.4273 ns/op BenchmarkCPUSilly2 1000000000 0.4286 ns/op PASS ok codeberg.org/snonux/sillybench 0.949s
paul@f0:~ % doas ubench -s 1 Unix Benchmark Utility v.0.3 Copyright (C) July, 1999 PhysTech, Inc. Author: Sergei Viznyuk <sv@phystech.com> http://www.phystech.com/download/ubench.html FreeBSD 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC amd64 Ubench Single CPU: 671010 (0.40s) Ubench Single MEM: 1705237 (0.48s) ----------------------------------- Ubench Single AVG: 1188123
paul@f0:~ % doas ubench Unix Benchmark Utility v.0.3 Copyright (C) July, 1999 PhysTech, Inc. Author: Sergei Viznyuk <sv@phystech.com> http://www.phystech.com/download/ubench.html FreeBSD 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC amd64 Ubench CPU: 2660220 Ubench MEM: 3095182 -------------------- Ubench AVG: 2877701
root@freebsd:~ # ubench -s 1 Unix Benchmark Utility v.0.3 Copyright (C) July, 1999 PhysTech, Inc. Author: Sergei Viznyuk <sv@phystech.com> http://www.phystech.com/download/ubench.html FreeBSD 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC amd64 Ubench Single CPU: 672792 (0.40s) Ubench Single MEM: 852757 (0.48s) ----------------------------------- Ubench Single AVG: 762774
root@freebsd:~ # ubench Unix Benchmark Utility v.0.3 Copyright (C) July, 1999 PhysTech, Inc. Author: Sergei Viznyuk <sv@phystech.com> http://www.phystech.com/download/ubench.html FreeBSD 14.2-RELEASE-p1 FreeBSD 14.2-RELEASE-p1 GENERIC amd64 Ubench CPU: 2652857 swap_pager: out of swap space swp_pager_getswapspace(27): failed swap_pager: out of swap space swp_pager_getswapspace(18): failed Apr 4 23:02:43 freebsd kernel: pid 862 (ubench), jid 0, uid 0, was killed: failed to reclaim memory swp_pager_getswapspace(6): failed Apr 4 23:02:46 freebsd kernel: pid 863 (ubench), jid 0, uid 0, was killed: failed to reclaim memory Apr 4 23:02:47 freebsd kernel: pid 864 (ubench), jid 0, uid 0, was killed: failed to reclaim memory Apr 4 23:02:48 freebsd kernel: pid 865 (ubench), jid 0, uid 0, was killed: failed to reclaim memory Apr 4 23:02:49 freebsd kernel: pid 861 (ubench), jid 0, uid 0, was killed: failed to reclaim memory Apr 4 23:02:51 freebsd kernel: pid 839 (ubench), jid 0, uid 0, was killed: failed to reclaim memory
PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND 7449 root 14 20 0 14G 78M kqread 2 2:12 399.81% bhyve

git clone https://codeberg.org/snonux/gos.git cd gos
go build -o gos ./cmd/gos go build -o gosc ./cmd/gosc sudo mv gos ~/go/bin sudo mv gosc ~/go/bin
go-task install
{
"MastodonURL": "https://mastodon.example.com",
"MastodonAccessToken": "your-mastodon-access-token",
"LinkedInClientID": "your-linkedin-client-id",
"LinkedInSecret": "your-linkedin-client-secret",
"LinkedInRedirectURL": "http://localhost:8080/callback",
}
./gos --dry
./gos

This is a sample message to be posted on social media platforms. Maybe add a link here: https://foo.zone #foo #cool #gos #golang
share:mastodon The content of the post here
share:mastodon The content of the post is here https://some.foo/link #some #hashtags
share:mastodon,ask,prio Hello wold :-)
share:mastodon,ask,prio Hello World :-)
~/.gosdir/db/platforms/linkedin/foo.share:-mastodon.txt.20241022-102343.queued
./db/platforms/linkedin/foo.share:-mastodon.txt.20241112-121323.posted
gos --geminiSummaryFor 202410,202411,202412
gos --gemtexterEnable --geminiSummaryFor 202410,202411,202412
gos --gemtexterEnable --geminiSummaryFor 202410,202411,202412 --geminiCapsules "foo.zone,paul.buetow.org"
/\_/\ /\_/\ ( o.o ) WHOA!! ( o.o ) > ^ < > ^ < / \ MOEEW! / \ /______\ /______\


package main
import "log"
type fun func() string
func (f fun) Bar() string {
return "Bar"
}
func main() {
var f fun = func() string {
return "Foo"
}
log.Println("Example 1: ", f())
log.Println("Example 2: ", f.Bar())
log.Println("Example 3: ", fun(f.Bar).Bar())
log.Println("Example 4: ", fun(fun(f.Bar).Bar).Bar())
}
❯ go run main.go 2025/02/07 22:56:14 Example 1: Foo 2025/02/07 22:56:14 Example 2: Bar 2025/02/07 22:56:14 Example 3: Bar 2025/02/07 22:56:14 Example 4: Bar
❯ touch Maß ❯ ls -l -rw-r--r--@ 1 paul wheel 0 Feb 7 23:02 Maß ❯ touch Mass ❯ ls -l -rw-r--r--@ 1 paul wheel 0 Feb 7 23:02 Maß ❯ rm Mass ❯ ls -l ❯ touch Mass ❯ ls -ltr -rw-r--r--@ 1 paul wheel 0 Feb 7 23:02 Mass ❯ rm Maß ❯ ls -l
ADFS::4.$.Documents.Techwriter.Myfile
arr = {10, 20, 30, 40, 50}
print(arr[1]) -- Accessing the first element
❯ lua foo.lua 10
# (C) 2006 by Paul C. Buetow
Christmas:{time;#!!!
Children: do tell $wishes;
Santa: for $each (@children) {
BEGIN { read $each, $their, wishes and study them; use Memoize#ing
} use constant gift, 'wrapping';
package Gifts; pack $each, gift and bless $each and goto deliver
or do import if not local $available,!!! HO, HO, HO;
redo Santa, pipe $gifts, to_childs;
redo Santa and do return if last one, is, delivered;
deliver: gift and require diagnostics if our $gifts ,not break;
do{ use NEXT; time; tied $gifts} if broken and dump the, broken, ones;
The_children: sleep and wait for (each %gift) and try { to => untie $gifts };
redo Santa, pipe $gifts, to_childs;
redo Santa and do return if last one, is, delivered;
The_christmas_tree: formline s/ /childrens/, $gifts;
alarm and warn if not exists $Christmas{ tree}, @t, $ENV{HOME};
write <<EMail
to the parents to buy a new christmas tree!!!!111
and send the
EMail
;wait and redo deliver until defined local $tree;
redo Santa, pipe $gifts, to_childs;
redo Santa and do return if last one, is, delivered ;}
END {} our $mission and do sleep until next Christmas ;}
__END__
This is perl, v5.8.8 built for i386-freebsd-64int


paul@f0: ~ % doas freebsd-update fetch paul@f0: ~ % doas freebsd-update install paul@f0: ~ % doas freebsd-update -r 14.2-RELEASE upgrade paul@f0: ~ % doas freebsd-update install paul@f0: ~ % doas shutdown -r now
paul@f0: ~ % doas freebsd-update install paul@f0: ~ % doas pkg update paul@f0: ~ % doas pkg upgrade paul@f0: ~ % doas shutdown -r now
paul@f0:~ % uname -a FreeBSD f0.lan.buetow.org 14.2-RELEASE FreeBSD 14.2-RELEASE releng/14.2-n269506-c8918d6c7412 GENERIC amd64


paul@f0: ~ % doas dmesg | grep UPS ugen0.2: <American Power Conversion Back-UPS BX750MI> at usbus0
paul@f0: ~ % doas install apcupsd
paul@f0:/usr/local/etc/apcupsd % diff -u apcupsd.conf.sample apcupsd.conf --- apcupsd.conf.sample 2024-11-01 16:40:42.000000000 +0200 +++ apcupsd.conf 2024-12-03 10:58:24.009501000 +0200 @@ -31,7 +31,7 @@ # 940-1524C, 940-0024G, 940-0095A, 940-0095B, # 940-0095C, 940-0625A, M-04-02-2000 # -UPSCABLE smart +UPSCABLE usb # To get apcupsd to work, in addition to defining the cable # above, you must also define a UPSTYPE, which corresponds to @@ -88,8 +88,10 @@ # that apcupsd binds to that particular unit # (helpful if you have more than one USB UPS). # -UPSTYPE apcsmart -DEVICE /dev/usv +UPSTYPE usb +DEVICE # POLLTIME <int> # Interval (in seconds) at which apcupsd polls the UPS for status. This
# If during a power failure, the remaining battery percentage # (as reported by the UPS) is below or equal to BATTERYLEVEL, # apcupsd will initiate a system shutdown. BATTERYLEVEL 5 # If during a power failure, the remaining runtime in minutes # (as calculated internally by the UPS) is below or equal to MINUTES, # apcupsd, will initiate a system shutdown. MINUTES 3
paul@f0:/usr/local/etc/apcupsd % doas sysrc apcupsd_enable=YES apcupsd_enable: -> YES paul@f0:/usr/local/etc/apcupsd % doas service apcupsd start Starting apcupsd.
paul@f0:~ % apcaccess APC : 001,035,0857 DATE : 2025-01-26 14:43:27 +0200 HOSTNAME : f0.lan.buetow.org VERSION : 3.14.14 (31 May 2016) freebsd UPSNAME : f0.lan.buetow.org CABLE : USB Cable DRIVER : USB UPS Driver UPSMODE : Stand Alone STARTTIME: 2025-01-26 14:43:25 +0200 MODEL : Back-UPS BX750MI STATUS : ONLINE LINEV : 230.0 Volts LOADPCT : 4.0 Percent BCHARGE : 100.0 Percent TIMELEFT : 65.3 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds SENSE : Medium LOTRANS : 145.0 Volts HITRANS : 295.0 Volts ALARMDEL : No alarm BATTV : 13.6 Volts LASTXFER : Automatic or explicit self test NUMXFERS : 0 TONBATT : 0 Seconds CUMONBATT: 0 Seconds XOFFBATT : N/A SELFTEST : NG STATFLAG : 0x05000008 SERIALNO : 9B2414A03599 BATTDATE : 2001-01-01 NOMINV : 230 Volts NOMBATTV : 12.0 Volts NOMPOWER : 410 Watts END APC : 2025-01-26 14:44:06 +0200
paul@f1:~ % apcaccess -h f0.lan.buetow.org | grep Percent LOADPCT : 12.0 Percent BCHARGE : 94.0 Percent MBATTCHG : 5 Percent
paul@f2:/usr/local/etc/apcupsd % diff -u apcupsd.conf.sample apcupsd.conf --- apcupsd.conf.sample 2024-11-01 16:40:42.000000000 +0200 +++ apcupsd.conf 2025-01-26 15:52:45.108469000 +0200 @@ -31,7 +31,7 @@ # 940-1524C, 940-0024G, 940-0095A, 940-0095B, # 940-0095C, 940-0625A, M-04-02-2000 # -UPSCABLE smart +UPSCABLE ether # To get apcupsd to work, in addition to defining the cable # above, you must also define a UPSTYPE, which corresponds to @@ -52,7 +52,6 @@ # Network Information Server. This is used if the # UPS powering your computer is connected to a # different computer for monitoring. -# # snmp hostname:port:vendor:community # SNMP network link to an SNMP-enabled UPS device. # Hostname is the ip address or hostname of the UPS @@ -88,8 +87,8 @@ # that apcupsd binds to that particular unit # (helpful if you have more than one USB UPS). # -UPSTYPE apcsmart -DEVICE /dev/usv +UPSTYPE net +DEVICE f0.lan.buetow.org:3551 # POLLTIME <int> # Interval (in seconds) at which apcupsd polls the UPS for status. This @@ -147,12 +146,12 @@ # If during a power failure, the remaining battery percentage # (as reported by the UPS) is below or equal to BATTERYLEVEL, # apcupsd will initiate a system shutdown. -BATTERYLEVEL 5 +BATTERYLEVEL 10 # If during a power failure, the remaining runtime in minutes # (as calculated internally by the UPS) is below or equal to MINUTES, # apcupsd, will initiate a system shutdown. -MINUTES 3 +MINUTES 6 # If during a power failure, the UPS has run on batteries for TIMEOUT # many seconds or longer, apcupsd will initiate a system shutdown.So I also ran the following commands on f1 and f2:
paul@f1:/usr/local/etc/apcupsd % doas sysrc apcupsd_enable=YES apcupsd_enable: -> YES paul@f1:/usr/local/etc/apcupsd % doas service apcupsd start Starting apcupsd.
paul@f1:~ % doas apcaccess | grep Percent LOADPCT : 5.0 Percent BCHARGE : 95.0 Percent MBATTCHG : 5 Percent
Broadcast Message from root@f0.lan.buetow.org
(no tty) at 15:03 EET...
Power failure. Running on UPS batteries.
paul@f0:/usr/local/etc/apcupsd % apcaccess -p TIMELEFT 63.9 Minutes
Broadcast Message from root@f0.lan.buetow.org
(no tty) at 15:08 EET...
*** FINAL System shutdown message from root@f0.lan.buetow.org ***
System going down IMMEDIATELY
apcupsd initiated shutdown
Jan 26 17:36:24 f2 apcupsd[2159]: Power failure. Jan 26 17:36:30 f2 apcupsd[2159]: Running on UPS batteries. Jan 26 17:36:30 f2 apcupsd[2159]: Battery charge below low limit. Jan 26 17:36:30 f2 apcupsd[2159]: Initiating system shutdown! Jan 26 17:36:30 f2 apcupsd[2159]: User logins prohibited Jan 26 17:36:32 f2 apcupsd[2159]: apcupsd exiting, signal 15 Jan 26 17:36:32 f2 apcupsd[2159]: apcupsd shutdown succeeded



[paul@earth]~/Downloads% sudo dd \ if=FreeBSD-14.1-RELEASE-amd64-bootonly.iso \ of=/dev/sda conv=sync

root@f0:~ # freebsd-update fetch root@f0:~ # freebsd-update install root@f0:~ # freebsd-update reboot
root@f0:~ # cat <<END >>/etc/hosts 192.168.1.130 f0 f0.lan f0.lan.buetow.org 192.168.1.131 f1 f1.lan f1.lan.buetow.org 192.168.1.132 f2 f2.lan f2.lan.buetow.org END
root@f0:~ # pkg install helix doas zfs-periodic uptimed
root@f0:~ # cp /usr/local/etc/doas.conf.sample /usr/local/etc/doas.conf
root@f0:~ # cat <<END >>/etc/periodic.conf daily_zfs_snapshot_enable="YES" daily_zfs_snapshot_pools="zroot" daily_zfs_snapshot_keep="7" weekly_zfs_snapshot_enable="YES" weekly_zfs_snapshot_pools="zroot" weekly_zfs_snapshot_keep="5" monthly_zfs_snapshot_enable="YES" monthly_zfs_snapshot_pools="zroot" monthly_zfs_snapshot_keep="6" END
root@f0:~ # cp /usr/local/mimecast/etc/uptimed.conf-dist \ /usr/local/mimecast/etc/uptimed.conf root@f0:~ # hx /usr/local/mimecast/etc/uptimed.conf
root@f0:~ # service uptimed enable root@f0:~ # service uptimed start
root@f0:~ # uprecords
# Uptime | System Boot up
----------------------------+---------------------------------------------------
-> 1 0 days, 00:07:34 | FreeBSD 14.1-RELEASE Mon Dec 2 12:21:44 2024
----------------------------+---------------------------------------------------
NewRec 0 days, 00:07:33 | since Mon Dec 2 12:21:44 2024
up 0 days, 00:07:34 | since Mon Dec 2 12:21:44 2024
down 0 days, 00:00:00 | since Mon Dec 2 12:21:44 2024
%up 100.000 | since Mon Dec 2 12:21:44 2024
paul@f0:~ % ifconfig re0
re0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
options=8209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE>
ether e8:ff:1e:d7:1c:ac
inet 192.168.1.130 netmask 0xffffff00 broadcast 192.168.1.255
inet6 fe80::eaff:1eff:fed7:1cac%re0 prefixlen 64 scopeid 0x1
inet6 fd22:c702:acb7:0:eaff:1eff:fed7:1cac prefixlen 64 detached autoconf
inet6 2a01:5a8:304:1d5c:eaff:1eff:fed7:1cac prefixlen 64 autoconf pltime 10800 vltime 14400
media: Ethernet autoselect (1000baseT <full-duplex>)
status: active
nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
paul@f0:~ % sysctl hw.physmem hw.physmem: 16902905856
paul@f0:~ % sysctl dev.cpu | grep freq: dev.cpu.3.freq: 705 dev.cpu.2.freq: 705 dev.cpu.1.freq: 604 dev.cpu.0.freq: 604
paul@f0:~ % doas pkg install ubench paul@f0:~ % rehash # For tcsh to find the newly installed command paul@f0:~ % ubench & paul@f0:~ % sysctl dev.cpu | grep freq: dev.cpu.3.freq: 2922 dev.cpu.2.freq: 2922 dev.cpu.1.freq: 2923 dev.cpu.0.freq: 2922




,.......... ..........,
,..,' '.' ',..,
,' ,' : ', ',
,' ,' : ', ',
,' ,' : ', ',
,' ,'............., : ,.............', ',
,' '............ '.' ............' ',
'''''''''''''''''';''';''''''''''''''''''
'''
-=[ typewriters ]=- 1/98
.-------.
.-------. _|~~ ~~ |_
_|~~ ~~ |_ .-------. =(_|_______|_)
=(_|_______|_)= _|~~ ~~ |_ |:::::::::| .-------.
|:::::::::| =(_|_______|_) |:::::::[]| _|~~ ~~ |_
|:::::::[]| |:::::::::| |o=======.| =(_|_______|_)
|o=======.| |:::::::[]| `"""""""""` |:::::::::|
jgs `"""""""""` |o=======.| |:::::::[]|
mod. by Paul Buetow `"""""""""` |o=======.|
`"""""""""`
<< template::inline::toc
declare -xr HTML_THEME_DIR=./extras/html/themes/simple
__..._ _...__
_..-" `Y` "-._
\ Once upon | /
\\ a time..| //
\\\ | ///
\\\ _..---.|.---.._ ///
jgs \\`_..---.Y.---.._`//
||====================================================================|| ||//$\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\//$\\|| ||(100)==================| FEDERAL SPONSOR NOTE |================(100)|| ||\\$// ~ '------========--------' \\$//|| ||<< / /$\ // ____ \\ \ >>|| ||>>| 12 //L\\ // ///..) \\ L38036133B 12 |<<|| ||<<| \\ // || <|| >\ || |>>|| ||>>| \$/ || $$ --/ || One Hundred |<<|| ||<<| L38036133B *\\ |\_/ //* series |>>|| ||>>| 12 *\\/___\_//* 1989 |<<|| ||<<\ Open Source ______/Franklin\________ Supporting />>|| ||//$\ ~| SPONSORING AND FUNDING |~ /$\\|| ||(100)=================== AWESOME OPEN SOURCE =================(100)|| ||\\$//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\\$//|| ||====================================================================||
,---,---,---,---,---,---,---,---,---,---,---,---,---,-------,
|1/2| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | + | ' | <- |
|---'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-----|
| ->| | Q | W | E | R | T | Y | U | I | O | P | ] | ^ | |
|-----',--',--',--',--',--',--',--',--',--',--',--',--'| |
| Caps | A | S | D | F | G | H | J | K | L | \ | [ | * | |
|----,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'---'----|
| | < | Z | X | C | V | B | N | M | , | . | - | |
|----'-,-',--'--,'---'---'---'---'---'---'-,-'---',--,------|
| ctrl | | alt | |altgr | | ctrl |
'------' '-----'--------------------------'------' '------'
Nieminen Mika





,.......... ..........,
,..,' '.' ',..,
,' ,' : ', ',
,' ,' : ', ',
,' ,' : ', ',
,' ,'............., : ,.............', ',
,' '............ '.' ............' ',
'''''''''''''''''';''';''''''''''''''''''
'''
/\_/\ WHOA!! ( o.o ) > ^ < / - \ / \ /______\ \
❯ traceroute -m 60 bad.horse traceroute to bad.horse (162.252.205.157), 60 hops max, 60 byte packets 1 _gateway (192.168.1.1) 5.237 ms 5.264 ms 6.009 ms 2 77-85-0-2.ip.btc-net.bg (77.85.0.2) 8.753 ms 7.112 ms 8.336 ms 3 212-39-69-103.ip.btc-net.bg (212.39.69.103) 9.434 ms 9.268 ms 9.986 ms 4 * * * 5 xe-1-2-0.mpr1.fra4.de.above.net (80.81.194.26) 39.812 ms 39.030 ms 39.772 ms 6 * ae12.cs1.fra6.de.eth.zayo.com (64.125.26.172) 123.576 ms * 7 * * * 8 * * * 9 ae10.cr1.lhr15.uk.eth.zayo.com (64.125.29.17) 119.097 ms 119.478 ms 120.767 ms 10 ae2.cr1.lhr11.uk.zip.zayo.com (64.125.24.140) 120.398 ms 121.147 ms 120.948 ms 11 * * * 12 ae25.mpr1.yyz1.ca.zip.zayo.com (64.125.23.117) 145.072 ms * 181.773 ms 13 ae5.mpr1.tor3.ca.zip.zayo.com (64.125.23.118) 168.239 ms 168.158 ms 168.137 ms 14 64.124.217.237.IDIA-265104-ZYO.zip.zayo.com (64.124.217.237) 168.026 ms 167.999 ms 165.451 ms 15 * * * 16 t00.toroc1.on.ca.sn11.net (162.252.204.2) 131.598 ms 131.308 ms 131.482 ms 17 bad.horse (162.252.205.130) 131.430 ms 145.914 ms 130.514 ms 18 bad.horse (162.252.205.131) 136.634 ms 145.295 ms 135.631 ms 19 bad.horse (162.252.205.132) 139.158 ms 148.363 ms 138.934 ms 20 bad.horse (162.252.205.133) 145.395 ms 148.054 ms 147.140 ms 21 he.rides.across.the.nation (162.252.205.134) 149.687 ms 147.731 ms 150.135 ms 22 the.thoroughbred.of.sin (162.252.205.135) 156.644 ms 155.155 ms 156.447 ms 23 he.got.the.application (162.252.205.136) 161.187 ms 162.318 ms 162.674 ms 24 that.you.just.sent.in (162.252.205.137) 166.763 ms 166.675 ms 164.243 ms 25 it.needs.evaluation (162.252.205.138) 172.073 ms 171.919 ms 171.390 ms 26 so.let.the.games.begin (162.252.205.139) 175.386 ms 174.180 ms 175.965 ms 27 a.heinous.crime (162.252.205.140) 180.857 ms 180.766 ms 180.192 ms 28 a.show.of.force (162.252.205.141) 187.942 ms 186.669 ms 186.986 ms 29 a.murder.would.be.nice.of.course (162.252.205.142) 191.349 ms 191.939 ms 190.740 ms 30 bad.horse (162.252.205.143) 195.425 ms 195.716 ms 196.186 ms 31 bad.horse (162.252.205.144) 199.238 ms 200.620 ms 200.318 ms 32 bad.horse (162.252.205.145) 207.554 ms 206.729 ms 205.201 ms 33 he-s.bad (162.252.205.146) 211.087 ms 211.649 ms 211.712 ms 34 the.evil.league.of.evil (162.252.205.147) 212.657 ms 216.777 ms 216.589 ms 35 is.watching.so.beware (162.252.205.148) 220.911 ms 220.326 ms 221.961 ms 36 the.grade.that.you.receive (162.252.205.149) 225.384 ms 225.696 ms 225.640 ms 37 will.be.your.last.we.swear (162.252.205.150) 232.312 ms 230.989 ms 230.919 ms 38 so.make.the.bad.horse.gleeful (162.252.205.151) 235.761 ms 235.291 ms 235.585 ms 39 or.he-ll.make.you.his.mare (162.252.205.152) 241.350 ms 239.407 ms 238.394 ms 40 o_o (162.252.205.153) 246.154 ms 247.650 ms 247.110 ms 41 you-re.saddled.up (162.252.205.154) 250.925 ms 250.401 ms 250.619 ms 42 there-s.no.recourse (162.252.205.155) 256.071 ms 251.154 ms 255.340 ms 43 it-s.hi-ho.silver (162.252.205.156) 260.152 ms 261.775 ms 261.544 ms 44 signed.bad.horse (162.252.205.157) 262.430 ms 261.410 ms 261.365 ms
#include <stdio.h>
int main(void) {
int array[5] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 5; i++)
printf("%d\n", array[i]);
for (int i = 0; i < 5; i++)
printf("%d\n", i[array]);
for (int i = 0; i < 5; i++)
printf("%d\n", *(i + array));
}
#include <stdio.h>
int main(void) {
int $array[5] = { 1, 2, 3, 4, 5 };
for (int $i = 0; $i < 5; $i++)
printf("%d\n", $array[$i]);
for (int $i = 0; $i < 5; $i++)
printf("%d\n", $i[$array]);
for (int $i = 0; $i < 5; $i++)
printf("%d\n", *($i + $array));
}
#!/usr/bin/ksh93
typeset -T Point_t=(
integer -h 'x coordinate' x=0
integer -h 'y coordinate' y=0
typeset -h 'point color' color="red"
function getcolor {
print -r ${_.color}
}
function setcolor {
_.color=$1
}
setxy() {
_.x=$1; _.y=$2
}
getxy() {
print -r "(${_.x},${_.y})"
}
)
Point_t point
echo "Initial coordinates are (${point.x},${point.y}). Color is ${point.color}"
point.setxy 5 6
point.setcolor blue
echo "New coordinates are ${point.getxy}. Color is ${point.getcolor}"
exit 0
package main
import "fmt"
func main() {
var i int
f := func() *int {
return &i
}
*f()++
fmt.Println(i)
}
def _token:
def _re($re; f):
( . as {$remain, $string_stack}
| $remain
| match($re; "m").string
| f as $token
| { result: ($token | del(.string_stack))
, remain: $remain[length:]
, string_stack:
( if $token.string_stack == null then $string_stack
else $token.string_stack
end
)
}
);
if .remain == "" then empty
else
( . as {$string_stack}
| _re("^\\s+"; {whitespace: .})
// _re("^#[^\n]*"; {comment: .})
// _re("^\\.[_a-zA-Z][_a-zA-Z0-9]*"; {index: .[1:]})
// _re("^[_a-zA-Z][_a-zA-Z0-9]*"; {ident: .})
// _re("^@[_a-zA-Z][_a-zA-Z0-9]*"; {at_ident: .})
// _re("^\\$[_a-zA-Z][_a-zA-Z0-9]*"; {binding: .})
# 1.23, .123, 123e2, 1.23e2, 123E2, 1.23e+2, 1.23E-2 or 123
// _re("^(?:[0-9]*\\.[0-9]+|[0-9]+)(?:[eE][-\\+]?[0-9]+)?"; {number: .})
// _re("^\"(?:[^\"\\\\]|\\\\.)*?\\\\\\(";
( .[1:-2]
| _unescape
| {string_start: ., string_stack: ($string_stack+["\\("])}
)
)
.
.
.
(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t] )+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?: \r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:( ?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0 31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\ >(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+ (?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?: (?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z |(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n) ?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\ r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n) ?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t] )*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])* )(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t] )+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*) *:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+ |\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r \n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?: \r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t >))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031 >+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\]( ?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(? :(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(? :\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(? :(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)? [ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]| \\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<> @,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|" (?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t] )*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\ ".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(? :[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[ \]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000- \031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|( ?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,; :\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([ ^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\" .\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\ >\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\ [\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\ r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\] |\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0 00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\ .|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@, ;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(? :[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])* (?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\". \[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[ ^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\] >))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*( ?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\ ".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:( ?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[ \["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t >)*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t >)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(? :\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+| \Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?: [^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\ >]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n) ?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[" ()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n) ?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<> @,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@, ;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t] )*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\ ".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)? (?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\". \[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?: \r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[ "()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t]) *))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]) +|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\ .(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z |(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:( ?:\r\n)?[ \t])*))*)?;\s*)
_______
|.-----.|
|| Tmux||
||_.-._||
`--)-(--`
__[=== o]___
|:::::::::::|\
jgs `-=========-`()
mod. by Paul B.
alias tm=tmux alias tl='tmux list-sessions' alias tn=tmux::new alias ta=tmux::attach alias tx=tmux::remote alias ts=tmux::search alias tssh=tmux::cluster_ssh
# Create new session and if alread exists attach to it
tmux::new () {
readonly session=$1
local date=date
if where gdate &>/dev/null; then
date=gdate
fi
tmux::cleanup_default
if [ -z "$session" ]; then
tmux::new T$($date +%s)
else
tmux new-session -d -s $session
tmux -2 attach-session -t $session || tmux -2 switch-client -t $session
fi
}
alias tn=tmux::new
tmux::cleanup_default () {
local s
tmux list-sessions | grep '^T.*: ' | grep -F -v attached |
cut -d: -f1 | while read -r s; do
echo "Killing $s"
tmux kill-session -t "$s"
done
}
tmux::attach () {
readonly session=$1
if [ -z "$session" ]; then
tmux attach-session || tmux::new
else
tmux attach-session -t $session || tmux::new $session
fi
}
alias ta=tmux::attach
tmux::remote () {
readonly server=$1
tmux new -s $server "ssh -t $server 'tmux attach-session || tmux'" || \
tmux attach-session -d -t $server
}
alias tr=tmux::remote
set-option -g prefix C-g
tmux::search () {
local -r session=$(tmux list-sessions | fzf | cut -d: -f1)
if [ -z "$TMUX" ]; then
tmux attach-session -t $session
else
tmux switch -t $session
fi
}
alias ts=tmux::search

tmux::cluster_ssh () {
if [ -f "$1" ]; then
tmux::tssh_from_file $1
return
fi
tmux::tssh_from_argument $@
}
alias tssh=tmux::cluster_ssh
tmux::tssh_from_argument () {
local -r session=$1; shift
local first_server=$1; shift
tmux new-session -d -s $session "ssh -t $first_server"
if ! tmux list-session | grep "^$session:"; then
echo "Could not create session $session"
return 2
fi
for server in "${@[@]}"; do
tmux split-window -t $session "tmux select-layout tiled; ssh -t $server"
done
tmux setw -t $session synchronize-panes on
tmux -2 attach-session -t $session | tmux -2 switch-client -t $session
}
bind-key p setw synchronize-panes off bind-key P setw synchronize-panes on
tmux::tssh_from_file () {
local -r serverlist=$1; shift
local -r session=$(basename $serverlist | cut -d. -f1)
tmux::tssh_from_argument $session $(awk '{ print $1} ' $serverlist | sed 's/.lan./.lan/g')
}
$ tssh fish blowfish.buetow.org fishfinger.buetow.org \
fishbone.buetow.org user@octopus.buetow.org
$ tssh manyservers.txt
bind-key -T copy-mode-vi 'v' send -X begin-selection bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel
source ~/.config/tmux/tmux.local.conf set-option -g allow-rename off set-option -g history-limit 100000 set-option -g status-bg '#444444' set-option -g status-fg '#ffa500' set-option -s escape-time 0
set-window-option -g mode-keys vi bind-key -T copy-mode-vi 'v' send -X begin-selection bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel
bind-key h select-pane -L bind-key j select-pane -D bind-key k select-pane -U bind-key l select-pane -R bind-key H resize-pane -L 5 bind-key J resize-pane -D 5 bind-key K resize-pane -U 5 bind-key L resize-pane -R 5
bind-key c new-window -c '#{pane_current_path}'
bind-key F new-window -n "session-switcher" "tmux list-sessions | fzf | cut -d: -f1 | xargs tmux switch-client -t"
bind-key T choose-tree

bind-key p setw synchronize-panes off bind-key P setw synchronize-panes on bind-key r source-file ~/.config/tmux/tmux.conf \; display-message "tmux.conf reloaded"
Art by Laura Brown .'`~~~~~~~~~~~`'. ( .'11 12 1'. ) | :10 \ 2: | | :9 @-> 3: | | :8 4; | '. '..7 6 5..' .' ~-------------~ ldb
Cluster :UK, :uk01 do
Customer.C1A1.segments.volumes.each do |volume|
puts volume.usage_stats
volume.move_off! if volume.over_subscribed?
end
end
,.......... ..........,
,..,' '.' ',..,
,' ,' : ', ',
,' ,' : ', ',
,' ,' : ', ',
,' ,'............., : ,.............', ',
,' '............ '.' ............' ',
'''''''''''''''''';''';''''''''''''''''''
'''
Art by Michael J. Penick (mod. by Paul B.)
ACME-sky
__________
/ nsd tower\ (
/____________\ (\) awk-ward
|:_:_:_:_:_| )) plant
|_:_,--.:_:| dig-bubble (\// )
|:_:|__|_:_| relayd-castle _ ) )) ((
_ |_ _ :_:| _ _ _ (_) (((( /)\`
| |_| |_| | _| | |_| |_| | o \\)) (( (
\_:_:_:_:/|_|_|_|\:_:_:_:_/ . (( ))))
|_,-._:_:_:_:_:_:_:_.-,_| )) ((//
|:|_|:_:_:,---,:_:_:|_|:| ,-. )/
|_:_:_:_,'puffy `,_:_:_:_| _ o ,;'))((
|:_:_:_/ _ | _ \_:_:_:| (_O (( ))
_____|_:_:_| (o)-(o) |_:_:_|--'`-. ,--. ksh under-water (((\'/
', ;|:_:_:| -( .-. )- |:_:_:| ', ; `--._\ /,---.~ goat \`))
. ` |_:_:_| \`-'/ |_:_:_|. ` . ` /()\.__( ) .,-----'`-\(( sed-root
', ;|:_:_:| `-' |:_:_:| ', ; ', ; `--'| \ ', ; ', ; ',')).,--
. ` MJP ` . ` . ` . ` . httpd-soil ` . . ` . ` . ` . ` . `
', ; ', ; ', ; ', ; ', ; ', ; ', ; ', ; ', ; ', ; ', ; ', ; ', ; ', ;
#!/bin/ksh
ZONES_DIR=/var/nsd/zones/master/
DEFAULT_MASTER=fishfinger.buetow.org
DEFAULT_STANDBY=blowfish.buetow.org
determine_master_and_standby () {
local master=$DEFAULT_MASTER
local standby=$DEFAULT_STANDBY
.
.
.
local -i health_ok=1
if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
echo "https://$master/index.txt IPv4 health check failed"
health_ok=0
elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
echo "https://$master/index.txt IPv6 health check failed"
health_ok=0
fi
if [ $health_ok -eq 0 ]; then
local tmp=$master
master=$standby
standby=$tmp
fi
.
.
.
}
fishfinger$ grep failover /var/nsd/zones/master/foo.zone.zone
300 IN A 46.23.94.99 ; Enable failover
300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
www 300 IN A 46.23.94.99 ; Enable failover
www 300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
standby 300 IN A 23.88.35.144 ; Enable failover
standby 300 IN AAAA 2a01:4f8:c17:20f1::42 ; Enable failover
transform () {
sed -E '
/IN A .*; Enable failover/ {
/^standby/! {
s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
}
/^standby/ {
s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
}
}
/IN AAAA .*; Enable failover/ {
/^standby/! {
s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
}
/^standby/ {
s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
}
}
/ ; serial/ {
s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
}
'
}
#! Race condition !#
if [ -f $zone_file.bak ]; then
mv $zone_file.bak $zone_file
fi
cat $zone_file | transform > $zone_file.new.tmp
grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
echo "Has zone $zone_file changed?"
if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
echo "The zone $zone_file hasn't changed"
rm $zone_file.*.tmp
return 0
fi
cp $zone_file $zone_file.bak
mv $zone_file.new.tmp $zone_file
rm $zone_file.*.tmp
echo "Reloading nsd"
nsd-control reload
if ! zone_is_ok $zone; then
echo "Rolling back $zone_file changes"
cp $zone_file $zone_file.invalid
mv $zone_file.bak $zone_file
echo "Reloading nsd"
nsd-control reload
zone_is_ok $zone
return 3
fi
for cleanup in invalid bak; do
if [ -f $zone_file.$cleanup ]; then
rm $zone_file.$cleanup
fi
done
echo "Failover of zone $zone to $MASTER completed"
return 1
# Weekly auto-failover for Let's Encrypt automation
local -i -r week_of_the_year=$(date +%U)
if [ $(( week_of_the_year % 2 )) -eq 0 ]; then
local tmp=$master
master=$standby
standby=$tmp
fi



FISHKISSFISHKIS
SFISHKISSFISHKISSFISH F
ISHK ISSFISHKISSFISHKISS FI
SHKISS FISHKISSFISHKISSFISS FIS
HKISSFISHKISSFISHKISSFISHKISSFISH KISS
FISHKISSFISHKISSFISHKISSFISHKISS FISHK
SSFISHKISSFISHKISSFISHKISSFISHKISSF
ISHKISSFISHKISSFISHKISSFISHKISSF ISHKI
SSFISHKISSFISHKISSFISHKISSFISHKIS SFIS
HKISSFISHKISSFISHKISSFISHKISS FIS
HKISSFISHKISSFISHKISSFISHK IS
SFISHKISSFISHKISSFISH K
ISSFISHKISSFISHK
$ doas installboot sd0 # Update the bootloader (not for every upgrade required) $ doas sysupgrade # Update all binaries (including Kernel)
$ doas sysmerge # Update system configuration files $ doas pkg_add -u # Update all packages $ doas reboot # Just in case, reboot one more time
..--""""----..
.-" ..--""""--.j-.
.-" .-" .--.""--..
.-" .-" ..--"-. \/ ;
.-" .-"_.--..--"" ..--' "-. :
.' .' / `. \..--"" __ _ \ ;
:.__.-" \ / .' ( )"-. Y
; ;: ( ) ( ). \
.': /:: : \ \
.'.-"\._ _.-" ; ; ( ) .-. ( ) \
" `.""" .j" : : \ ; ; \
bug /"""""/ ; ( ) "" :.( ) \
/\ / : \ \`.: _ \
: `. / ; `( ) (\/ :" \ \
\ `. : "-.(_)_.' t-' ;
\ `. ; ..--":
`. `. : ..--"" :
`. "-. ; ..--"" ;
`. "-.:_..--"" ..--"
`. : ..--""
"-. : ..--""
"-.;_..--""
'\ '\ '\ . . |>18>>
\ \ \ . ' . |
O>> O>> O>> . 'o |
\ .\. .. .\. .. . |
/\ . /\ . /\ . . |
/ / . / / .'. / / .' . |
jgs^^^^^^^`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Art by Joan Stark, mod. by Paul Buetow
#!/usr/bin/env bash
log () {
local -r level="$1"; shift
local -r message="$1"; shift
local -i pid="$$"
local -r callee=${FUNCNAME[1]}
local -r stamp=$(date +%Y%m%d-%H%M%S)
echo "$level|$stamp|$pid|$callee|$message" >&2
}
at_home_friday_evening () {
log INFO 'One Peperoni Pizza, please'
}
at_home_friday_evening
❯ ./logexample.sh INFO|20231210-082732|123002|at_home_friday_evening|One Peperoni Pizza, please

#!/usr/bin/env bash
outer() {
inner() {
echo 'Intel inside!'
}
inner
}
inner
outer
inner
❯ ./inner.sh /tmp/inner.sh: line 10: inner: command not found Intel inside! Intel inside!
#!/usr/bin/env bash
outer1() {
inner() {
echo 'Intel inside!'
}
inner
}
outer2() {
inner() {
echo 'Wintel inside!'
}
inner
}
outer1
inner
outer2
inner
❯ ./inner2.sh Intel inside! Intel inside! Wintel inside! Wintel inside!
#!/usr/bin/env bash
some_expensive_operations() {
echo "Doing expensive operations with '$1' from pid $$"
}
for i in {0..9}; do echo $i; done \
| xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
❯ ./xargs.sh bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found
#!/usr/bin/env bash
some_expensive_operations() {
echo "Doing expensive operations with '$1' from pid $$"
}
export -f some_expensive_operations
for i in {0..9}; do echo $i; done \
| xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
❯ ./xargs.sh Doing expensive operations with '0' from pid 132831 Doing expensive operations with '1' from pid 132832 Doing expensive operations with '2' from pid 132833 Doing expensive operations with '3' from pid 132834 Doing expensive operations with '4' from pid 132835 Doing expensive operations with '5' from pid 132836 Doing expensive operations with '6' from pid 132837 Doing expensive operations with '7' from pid 132838 Doing expensive operations with '8' from pid 132839 Doing expensive operations with '9' from pid 132840
#!/usr/bin/env bash
some_other_function() {
echo "$1"
}
some_expensive_operations() {
some_other_function "Doing expensive operations with '$1' from pid $$"
}
export -f some_expensive_operations
for i in {0..9}; do echo $i; done \
| xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
#!/usr/bin/env bash
foo() {
local foo=bar # Declare local/dynamic variable
bar
echo "$foo"
}
bar() {
echo "$foo"
foo=baz
}
foo=foo # Declare global variable
foo # Call function foo
echo "$foo"
❯ ./dynamic.sh bar baz foo
#!/usr/bin/env bash
declare -r foo=foo
declare -r bar=bar
if [ "$foo" = foo ]; then
if [ "$bar" = bar ]; then
echo ok1
fi
fi
if [ "$foo" = foo ] && [ "$bar" == bar ]; then
echo ok2a
fi
[ "$foo" = foo ] && [ "$bar" == bar ] && echo ok2b
if [[ "$foo" = foo && "$bar" == bar ]]; then
echo ok3a
fi
[[ "$foo" = foo && "$bar" == bar ]] && echo ok3b
if test "$foo" = foo && test "$bar" = bar; then
echo ok4a
fi
test "$foo" = foo && test "$bar" = bar && echo ok4b
❯ ./if.sh ok1 ok2a ok2b ok3a ok3b ok4a ok4b
#!/usr/bin/env bash # Single line comment # These are two single line # comments one after another : <<COMMENT This is another way a multi line comment could be written! COMMENT
#!/usr/bin/env bash echo foo echo echo baz >> $0 echo bar
❯ ./if.sh foo bar baz ❯ cat if.sh #!/usr/bin/env bash echo foo echo echo baz >> $0 echo bar echo baz
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⣾⠿⠿⠿⠶⠾⠿⠿⣿⣿⣿⣿⣿⣿⠿⠿⠶⠶⠿⠿⠿⣷⠀⠀⠀⠀ ⠀⠀⠀⣸⢿⣆⠀⠀⠀⠀⠀⠀⠀⠙⢿⡿⠉⠀⠀⠀⠀⠀⠀⠀⣸⣿⡆⠀⠀⠀ ⠀⠀⢠⡟⠀⢻⣆⠀⠀⠀⠀⠀⠀⠀⣾⣧⠀⠀⠀⠀⠀⠀⠀⣰⡟⠀⢻⡄⠀⠀ ⠀⢀⣾⠃⠀⠀⢿⡄⠀⠀⠀⠀⠀⢠⣿⣿⡀⠀⠀⠀⠀⠀⢠⡿⠀⠀⠘⣷⡀⠀ ⠀⣼⣏⣀⣀⣀⣈⣿⡀⠀⠀⠀⠀⣸⣿⣿⡇⠀⠀⠀⠀⢀⣿⣃⣀⣀⣀⣸⣧⠀ ⠀⢻⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⣿⣿⣿⣿⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⡿⠀ ⠀⠀⠉⠛⠛⠛⠋⠁⠀⠀⠀⠀⢸⣿⣿⣿⣿⡆⠀⠀⠀⠀⠈⠙⠛⠛⠛⠉⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠴⠶⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠶⠦⠀⠀
,.......... ..........,
,..,' '.' ',..,
,' ,' : ', ',
,' ,' : ', ',
,' ,' : ', ',
,' ,'............., : ,.............', ',
,' '............ '.' ............' ',
'''''''''''''''''';''';''''''''''''''''''
'''
___ .---------.._
______!fsc!_....-' .g8888888p. '-------....._
.' // .g8: :8p..---....___ \'.
| foo.zone // () d88: :88b|==========! !|
| // 888: :888|==========| !|
|___ \\_______'T88888888888P''----------'//|
| \ """"""""""""""""""""""""""""""""""/ |
| !...._____ .="""=. .[] ____...! |
| / ! .g$p. ! .[] : |
| ! : $$$$$ : .[] : |
| !irregular.ninja ! 'T$P' ! .[] '.|
| \__ "=._.=" .() __ |
|.--' '----._______________________.----' '--.|
'._____________________________________________.'
% sudo dnf install -y ImageMagick make git
% git clone https://codeberg.org/snonux/photoalbum Cloning into 'photoalbum'... remote: Enumerating objects: 1624, done. remote: Total 1624 (delta 0), reused 0 (delta 0), pack-reused 1624 Receiving objects: 100% (1624/1624), 193.36 KiB | 1.49 MiB/s, done. Resolving deltas: 100% (1227/1227), done. % cd photoalbum /home/paul/photoalbum % make cut -d' ' -f2 changelog | head -n 1 | sed 's/(//;s/)//' > .version test ! -d ./bin && mkdir ./bin || exit 0 sed "s/PHOTOALBUMVERSION/$(cat .version)/" src/photoalbum.sh > ./bin/photoalbum chmod 0755 ./bin/photoalbum % sudo make install test ! -d /usr/bin && mkdir -p /usr/bin || exit 0 cp ./bin/* /usr/bin test ! -d /usr/share/photoalbum/templates && mkdir -p /usr/share/photoalbum/templates || exit 0 cp -R ./share/templates /usr/share/photoalbum/ test ! -d /etc/default && mkdir -p /etc/default || exit 0 cp ./src/photoalbum.default.conf /etc/default/photoalbum
% photoalbum version This is Photoalbum Version 0.5.1
% mkdir irregular.ninja % cd irregular.ninja % # cp -Rpv ~/Photos/your-photos ./incoming
photoalbum clean|generate|version [rcfile] photoalbum photoalbum makemake
% photoalbum makemake You may now customize ./photoalbumrc and run make % cat Makefile all: photoalbum generate photoalbumrc clean: photoalbum clean photoalbumrc % cat photoalbumrc # The title of the photoalbum TITLE='A simple Photoalbum' # Thumbnail height geometry THUMBHEIGHT=300 # Normal geometry height (when viewing photo). Uncomment, to keep original size. HEIGHT=1200 # Max previews per page. MAXPREVIEWS=40 # Randomly shuffle all previews. # SHUFFLE=yes # Diverse directories, need to be full paths, not relative! INCOMING_DIR=$(pwd)/incoming DIST_DIR=$(pwd)/dist TEMPLATE_DIR=/usr/share/photoalbum/templates/default #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal # Includes a .tar of the incoming dir in the dist, can be yes or no TARBALL_INCLUDE=yes TARBALL_SUFFIX=.tar TAR_OPTS='-c' # Some debugging options #set -e #set -x
--- photoalbumrc 2023-10-29 21:42:00.894202045 +0200 +++ photoalbumrc.new 2023-06-04 10:40:08.030994440 +0300 @@ -1,23 +1,24 @@ # The title of the photoalbum -TITLE='A simple Photoalbum' +TITLE='Irregular.Ninja' # Thumbnail height geometry -THUMBHEIGHT=300 +THUMBHEIGHT=400 # Normal geometry height (when viewing photo). Uncomment, to keep original size. -HEIGHT=1200 +HEIGHT=1800 # Max previews per page. MAXPREVIEWS=40 -# Randomly shuffle all previews. -# SHUFFLE=yes +# Randomly shuffle +SHUFFLE=yes # Diverse directories, need to be full paths, not relative! -INCOMING_DIR=$(pwd)/incoming +INCOMING_DIR=~/Nextcloud/Photos/irregular.ninja DIST_DIR=$(pwd)/dist TEMPLATE_DIR=/usr/share/photoalbum/templates/default #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal # Includes a .tar of the incoming dir in the dist, can be yes or no -TARBALL_INCLUDE=yes +TARBALL_INCLUDE=no TARBALL_SUFFIX=.tar TAR_OPTS='-c'
% make photoalbum generate photoalbumrc Processing 1055079_cool-water-wallpapers-hd-hd-desktop-wal.jpg to /home/paul/irregular.ninja/dist/photos/1055079_cool-water-wallpapers-hd-hd-desktop-wal.jpg Processing 11271242324.jpg to /home/paul/irregular.ninja/dist/photos/11271242324.jpg Processing 11271306683.jpg to /home/paul/irregular.ninja/dist/photos/11271306683.jpg Processing 13950707932.jpg to /home/paul/irregular.ninja/dist/photos/13950707932.jpg Processing 14077406487.jpg to /home/paul/irregular.ninja/dist/photos/14077406487.jpg Processing 14859380100.jpg to /home/paul/irregular.ninja/dist/photos/14859380100.jpg Processing 14869239578.jpg to /home/paul/irregular.ninja/dist/photos/14869239578.jpg Processing 14879132910.jpg to /home/paul/irregular.ninja/dist/photos/14879132910.jpg . . . Generating /home/paul/irregular.ninja/dist/html/7-4.html Creating thumb /home/paul/irregular.ninja/dist/thumbs/20211130_091051.jpg Creating blur /home/paul/irregular.ninja/dist/blurs/20211130_091051.jpg Generating /home/paul/irregular.ninja/dist/html/page-7.html Generating /home/paul/irregular.ninja/dist/html/7-5.html Generating /home/paul/irregular.ninja/dist/html/7-5.html Generating /home/paul/irregular.ninja/dist/html/7-5.html Creating thumb /home/paul/irregular.ninja/dist/thumbs/DSCF0188.JPG Creating blur /home/paul/irregular.ninja/dist/blurs/DSCF0188.JPG Generating /home/paul/irregular.ninja/dist/html/page-7.html Generating /home/paul/irregular.ninja/dist/html/7-6.html Generating /home/paul/irregular.ninja/dist/html/7-6.html Generating /home/paul/irregular.ninja/dist/html/7-6.html Creating thumb /home/paul/irregular.ninja/dist/thumbs/P3500897-01.jpg Creating blur /home/paul/irregular.ninja/dist/blurs/P3500897-01.jpg . . . Generating /home/paul/irregular.ninja/dist/html/8-0.html Generating /home/paul/irregular.ninja/dist/html/8-41.html Generating /home/paul/irregular.ninja/dist/html/9-0.html Generating /home/paul/irregular.ninja/dist/html/9-41.html Generating /home/paul/irregular.ninja/dist/html/index.html Generating /home/paul/irregular.ninja/dist/.//index.html
% ls ./dist blurs html index.html photos thumbs
% rsync --delete -av ./dist/. admin@blowfish.buetow.org:/var/www/htdocs/irregular.ninja/
,_---~~~~~----._
_,,_,*^____ _____``*g*\"*,
____ _____ _ _ / __/ /' ^. / \ ^@q f
| _ \_ _|_ _(_) | @f | ((@| |@)) l 0 _/
| | | || |/ _` | | | \`/ \~____ / __ \_____/ \
| |_| || | (_| | | | | _l__l_ I
|____/ |_|\__,_|_|_| } [______] I
] | | | |
] ~ ~ |
| Let's tail those logs! |
| |
% dtail --servers serverlist.txt --grep INFO --files "/var/log/dserver/*.log"

% dtail --servers serverlist.txt --grep INFO "/var/log/dserver/*.log"
% dtail --servers serverlist.txt \
--files '/var/log/dserver/*.log' \
--query 'from STATS select sum($goroutines),sum($cgocalls),
last($time),max(lifetimeConnections)'

% dtail --servers serverlist.txt \
--files '/var/log/dserver/*.log' \
'from STATS select sum($goroutines),sum($cgocalls),
last($time),max(lifetimeConnections)'
% dtail --servers serverlist.txt \
--files '/var/log/dserver/*.log' \
--query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
lifetimeConnections group by $hostname order by max($cgocalls)'

% dtail --servers serverlist.txt \
--files '/var/log/dserver/*.log' \
--query 'from STATS select ... outfile append result.csv'
% dcat --servers serverlist.txt --files /etc/hostname

% dcat --servers serverlist.txt /etc/hostname
% dgrep --servers server1.example.org:2223 \
--files /etc/passwd \
--regex nologin

% dmap --servers serverlist.txt \
--files '/var/log/dserver/*.log' \
--query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
lifetimeConnections group by $hostname order by max($cgocalls)'

% dmap --files /var/log/dserver/dserver.log
--query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
lifetimeConnections group by $hostname order by max($cgocalls)'
% dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
lifetimeConnections group by $hostname order by max($cgocalls)' \
/var/log/dsever/dserver.log
% cat /var/log/dserver/dserver.log | \
dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
lifetimeConnections group by $hostname order by max($cgocalls)'
% cat example.csv name,lastname,age,profession Michael,Jordan,40,Basketball player Michael,Jackson,100,Singer Albert,Einstein,200,Physician % dmap --query 'select lastname,name where age > 40 logformat csv outfile result.csv' example.csv % cat result.csv lastname,name Jackson,Michael Einstein,Albert
% dtail /var/log/dserver/dserver.log
% dtail --logLevel trace /var/log/dserver/dserver.log
% dcat /etc/passwd
% dcat --plain /etc/passwd > /etc/test # Should show no differences. diff /etc/test /etc/passwd
% dgrep --regex ERROR --files /var/log/dserver/dsever.log
% dgrep --before 10 --after 10 --max 10 --grep ERROR /var/log/dserver/dsever.log
▓▓▓▓░░
DC on fire:
▓▓ ▓▓ ▓▓
░░ ░░ ▓▓▓▓ ██ ░░ ▓▓▓▓ ▓▓
▓▓░░░░ ░░ ▓▓▓▓ ▓▓░░ ▓▓▓▓
░░░░ ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓
▓▓░░ ▓▓▒▒▒▒▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓▓▓ ▓▓▒▒▒▒▓▓▓▓ ▓▓▓▓
██▓▓ ▓▓▒▒░░▒▒▓▓ ▓▓██ ▓▓▓▓▓▓ ▓▓▒▒▓▓ ▓▓▒▒░░▒▒▓▓ ██▓▓▓▓
▓▓▓▓██ ▓▓▒▒░░░░▒▒▓▓ ▓▓▓▓ ▓▓▒▒▒▒▓▓ ▓▓▒▒░░▒▒▓▓██▓▓ ▓▓▒▒░░░░▒▒▓▓ ▓▓▒▒▒▒▓▓
▓▓▒▒▒▒▓▓▓▓▒▒░░▒▒▓▓▓▓▓▓▒▒▒▒▓▓ ▓▓▓▓░░▒▒▓▓ ▓▓▒▒░░▒▒▓▓▒▒▒▒▓▓ ▓▓▒▒░░▒▒▓▓▓▓▓▓▓▓░░▒▒▓▓
▒▒░░▒▒▓▓▓▓▒▒░░▒▒▓▓▓▓▒▒░░▒▒▓▓ ▓▓▒▒░░▒▒▓▓ ▓▓░░░░▒▒▒▒░░░░▒▒██████▒▒░░▒▒██▓▓▓▓▒▒░░▒▒▓▓██
░░░░▒▒▓▓▒▒░░▒▒▓▓▓▓▓▓▒▒░░▒▒▓▓██▒▒░░░░▒▒▓▓ ▓▓▒▒░░▒▒▓▓▒▒▒▒░░▒▒▓▓▓▓▒▒░░▒▒▓▓▓▓▓▓▒▒░░░░▒▒▓▓▓▓
░░░░▒▒▓▓▒▒░░░░▓▓██▒▒░░░░▒▒▓▓██▒▒░░░░▒▒██▓▓▓▓▒▒░░▒▒▓▓▓▓▒▒░░░░▒▒▓▓▒▒░░░░██▓▓▓▓▒▒░░░░▒▒████
▒▒░░▒▒▓▓▓▓░░░░▒▒▓▓▒▒▒▒░░░░▒▒▓▓▓▓▒▒░░░░▒▒▓▓▓▓▒▒░░░░▒▒▓▓▒▒░░▒▒▓▓▓▓▓▓░░░░▒▒▓▓▓▓▓▓▒▒░░░░▒▒▓▓
▒▒░░▒▒▓▓▒▒▒▒░░▒▒██▒▒▒▒░░▒▒▒▒██▒▒▒▒░░░░░░▒▒▓▓▒▒░░░░▒▒▒▒░░░░▒▒████▒▒▒▒░░▒▒██▓▓▒▒▒▒░░░░░░▒▒
░░░░░░▒▒░░░░░░░░▒▒▒▒▒▒░░░░▒▒▒▒▒▒░░░░░░░░▒▒▒▒░░░░░░▒▒▒▒░░░░░░▒▒▒▒░░░░░░░░▒▒▒▒▒▒░░░░░░░░▒▒
░░░░░░░░░░▒▒░░░░░░░░░░░░░░░░░░░░░░░░▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒░░░░░░░░░░░░░░░░░░
-=[ typewriters ]=- 1/98
.-------.
.-------. _|~~ ~~ |_
_|~~ ~~ |_ .-------. =(_|_______|_)
=(_|_______|_)= _|~~ ~~ |_ |:::::::::|
|:::::::::| =(_|_______|_) |:::::::[]|
|:::::::[]| |:::::::::| |o=======.|
|o=======.| |:::::::[]| `"""""""""`
jgs `"""""""""` |o=======.|
mod. by Paul Buetow `"""""""""`
```bash if [ -n "$foo" ]; then echo "$foo" fi ```
if [ -n "$foo" ]; then echo "$foo" fi
declare -xr MASTODON_URI='https://fosstodon.org/@snonux'
=> https://fosstodon.org/@snonux Me at Mastodon
<a href='https://fosstodon.org/@snonux' rel='me'>Me at Mastodon</a>
,.......... ..........,
,..,' '.' ',..,
,' ,' : ', ',
,' ,' : ', ',
,' ,' : ', ',
,' ,'............., : ,.............', ',
,' '............ '.' ............' ',
'''''''''''''''''';''';''''''''''''''''''
'''

_____________________________ ____________________________
/ \ / \
| _______________________ || ______________________ |
| / \ || / \ |
| | # Alerts with status c| || | # Unhandled alerts: | |
| | hanged: | || | | |
| | | || | CRITICAL: Check Pizza| |
| | OK->CRITICAL: Check Pi| || | : Late delivery | |
| | zza: Late delivery | || | | |
| | | || | WARNING: Check Thirst| |
| | | || | : OutofKombuchaExcept| |
| \_______________________/ || \______________________/ |
| /|\ GOGIOS MONITOR 1 _ || /|\ GOGIOS MONITOR 2 _ |
\_____________________________/ \____________________________/
!_________________________! !________________________!
------------------------------------------------
ASCII art was modified by Paul Buetow
The original can be found at
https://asciiart.website/index.php?art=objects/computers
Subject: GOGIOS Report [C:2 W:0 U:0 OK:51] This is the recent Gogios report! # Alerts with status changed: OK->CRITICAL: Check ICMP4 vulcan.buetow.org: Check command timed out OK->CRITICAL: Check ICMP6 vulcan.buetow.org: Check command timed out # Unhandled alerts: CRITICAL: Check ICMP4 vulcan.buetow.org: Check command timed out CRITICAL: Check ICMP6 vulcan.buetow.org: Check command timed out Have a nice day!
git clone https://codeberg.org/snonux/gogios.git cd gogios go build -o gogios cmd/gogios/main.go doas cp gogios /usr/local/bin/gogios doas chmod 755 /usr/local/bin/gogios
export GOOS=openbsd export GOARCH=amd64 go build -o gogios cmd/gogios/main.go
doas adduser -group _gogios -batch _gogios doas usermod -d /var/run/gogios _gogios doas mkdir -p /var/run/gogios doas chown _gogios:_gogios /var/run/gogios doas chmod 750 /var/run/gogios
doas pkg_add monitoring-plugins doas pkg_add nrpe # If you want to execute checks remotely via NRPE.
echo 'This is a test email from OpenBSD.' | mail -s 'Test Email' your-email@example.com
{
"EmailTo": "paul@dev.buetow.org",
"EmailFrom": "gogios@buetow.org",
"CheckTimeoutS": 10,
"CheckConcurrency": 2,
"StateDir": "/var/run/gogios",
"Checks": {
"Check ICMP4 www.foo.zone": {
"Plugin": "/usr/local/libexec/nagios/check_ping",
"Args": [ "-H", "www.foo.zone", "-4", "-w", "50,10%", "-c", "100,15%" ],
"Retries": 3,
"RetryInterval": 10
},
"Check ICMP6 www.foo.zone": {
"Plugin": "/usr/local/libexec/nagios/check_ping",
"Args": [ "-H", "www.foo.zone", "-6", "-w", "50,10%", "-c", "100,15%" ],
"Retries": 3,
"RetryInterval": 10
},
"www.foo.zone HTTP IPv4": {
"Plugin": "/usr/local/libexec/nagios/check_http",
"Args": ["www.foo.zone", "-4"],
"DependsOn": ["Check ICMP4 www.foo.zone"]
},
"www.foo.zone HTTP IPv6": {
"Plugin": "/usr/local/libexec/nagios/check_http",
"Args": ["www.foo.zone", "-6"],
"DependsOn": ["Check ICMP6 www.foo.zone"]
}
"Check NRPE Disk Usage foo.zone": {
"Plugin": "/usr/local/libexec/nagios/check_nrpe",
"Args": ["-H", "foo.zone", "-c", "check_disk", "-p", "5666", "-4"]
}
}
}
doas -u _gogios /usr/local/bin/gogios -cfg /etc/gogios.json
*/5 8-22 * * * /usr/local/bin/gogios -cfg /etc/gogios.json 0 7 * * * /usr/local/bin/gogios -renotify -cfg /etc/gogios.json
,.......... ..........,
,..,' '.' ',..,
,' ,' : ', ',
,' ,' : ', ',
,' ,' : ', ',
,' ,'............., : ,.............', ',
,' '............ '.' ............' ',
'''''''''''''''''';''';''''''''''''''''''
'''
+-----+-----------------+-----------------------------+ | Pos | Host | Lifespan | +-----+-----------------+-----------------------------+ | 1. | dionysus | 8 years, 6 months, 17 days | | 2. | uranus | 7 years, 2 months, 16 days | | 3. | alphacentauri | 6 years, 9 months, 13 days | | 4. | *vulcan | 4 years, 5 months, 6 days | | 5. | sun | 3 years, 10 months, 2 days | | 6. | uugrn | 3 years, 5 months, 5 days | | 7. | deltavega | 3 years, 1 months, 21 days | | 8. | pluto | 2 years, 10 months, 30 days | | 9. | tauceti | 2 years, 3 months, 22 days | | 10. | callisto | 2 years, 3 months, 13 days | +-----+-----------------+-----------------------------+
$ raku guprecords.raku --stats=dir=$HOME/git/uprecords/stats --all
Top 20 Uptime's by Host +-----+-----------------+-----------------------------+ | Pos | Host | Uptime | +-----+-----------------+-----------------------------+ | 1. | *vulcan | 4 years, 5 months, 6 days | | 2. | uranus | 3 years, 11 months, 21 days | | 3. | sun | 3 years, 9 months, 26 days | | 4. | uugrn | 3 years, 5 months, 5 days | | 5. | deltavega | 3 years, 1 months, 21 days | | 6. | pluto | 2 years, 10 months, 29 days | | 7. | tauceti | 2 years, 3 months, 19 days | | 8. | tauceti-f | 1 years, 9 months, 18 days | | 9. | *ultramega15289 | 1 years, 8 months, 17 days | | 10. | *earth | 1 years, 5 months, 22 days | | 11. | *blowfish | 1 years, 4 months, 20 days | | 12. | ultramega8477 | 1 years, 3 months, 25 days | | 13. | host0 | 1 years, 3 months, 9 days | | 14. | tauceti-e | 1 years, 2 months, 20 days | | 15. | makemake | 1 years, 1 months, 6 days | | 16. | callisto | 0 years, 10 months, 31 days | | 17. | alphacentauri | 0 years, 10 months, 28 days | | 18. | london | 0 years, 9 months, 16 days | | 19. | twofish | 0 years, 8 months, 31 days | | 20. | *fishfinger | 0 years, 8 months, 17 days | +-----+-----------------+-----------------------------+
# Uptime | System Boot up
----------------------------+---------------------------------------------------
1 545 days, 17:58:15 | Linux 3.10.0-1160.15.2.e Sun Jul 25 19:32:25 2021
2 279 days, 10:12:14 | Linux 3.10.0-957.21.3.el Sun Jun 30 12:43:41 2019
3 161 days, 06:08:43 | Linux 3.10.0-1160.15.2.e Sun Feb 14 11:05:38 2021
4 107 days, 01:26:35 | Linux 3.10.0-957.1.3.el7 Thu Dec 20 09:29:13 2018
5 96 days, 21:13:49 | Linux 3.10.0-1127.13.1.e Sat Jul 25 17:56:22 2020
-> 6 89 days, 23:05:32 | Linux 3.10.0-1160.81.1.e Sun Jan 22 12:39:36 2023
7 63 days, 18:30:45 | Linux 3.10.0-957.10.1.el Sat Apr 27 18:12:43 2019
8 63 days, 06:53:33 | Linux 3.10.0-1127.8.2.el Sat May 23 10:41:08 2020
9 48 days, 11:44:49 | Linux 3.10.0-1062.18.1.e Sat Apr 4 22:56:07 2020
10 42 days, 08:00:13 | Linux 3.10.0-1127.19.1.e Sat Nov 7 11:47:33 2020
11 36 days, 22:57:19 | Linux 3.10.0-1160.6.1.el Sat Dec 19 19:47:57 2020
12 21 days, 06:16:28 | Linux 3.10.0-957.10.1.el Sat Apr 6 11:56:01 2019
13 12 days, 20:11:53 | Linux 3.10.0-1160.11.1.e Mon Jan 25 18:45:27 2021
14 7 days, 21:29:18 | Linux 3.10.0-1127.13.1.e Fri Oct 30 14:18:04 2020
15 6 days, 20:07:18 | Linux 3.10.0-1160.15.2.e Sun Feb 7 14:57:35 2021
16 1 day , 21:46:41 | Linux 3.10.0-957.1.3.el7 Tue Dec 18 11:42:19 2018
17 0 days, 01:25:57 | Linux 3.10.0-957.1.3.el7 Tue Dec 18 10:16:08 2018
18 0 days, 00:42:34 | Linux 3.10.0-1160.15.2.e Sun Jul 25 18:49:38 2021
19 0 days, 00:08:32 | Linux 3.10.0-1160.81.1.e Sun Jan 22 12:30:52 2023
----------------------------+---------------------------------------------------
1up in 6 days, 22:08:18 | at Sat Apr 29 10:53:25 2023
no1 in 455 days, 18:52:44 | at Sun Jul 21 07:37:51 2024
up 1586 days, 00:20:28 | since Tue Dec 18 10:16:08 2018
down 0 days, 01:08:32 | since Tue Dec 18 10:16:08 2018
%up 99.997 | since Tue Dec 18 10:16:08 2018