Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Metube docker-compose full

# File: docker-compose.yaml
# Project: metube
# Startdate: 2023-01-23
version: "3"
services:
  metube:
    image: alexta69/metube:latest
    container_name: metube
    restart: unless-stopped
    ports:
      - "8081:8081"
    volumes:
      - /mnt/public/Video/Downloads:/downloads
      - /home/metube/.cache:/.cache
    environment:
      # Most of this was suggested by readme. I added restrictfilenames to use only ascii and no spaces
      YTDL_OPTIONS: '{"writesubtitles": true, "subtitleslangs": ["en", "-live_chat"], "postprocessors": [{"key": "Exec", "exec_cmd": "chmod 0664", "when": "after_move"}, {"key": "FFmpegEmbedSubtitle", "already_have_subtitle": false}, {"key": "FFmpegMetadata", "add_chapters": true}], "restrictfilenames": true}'
      # personal preference; I like to include id, which also helps jellyfin
      OUTPUT_TEMPLATE: "%(title)s.%(id)s.%(ext)s"
      # prefix for reverse proxy in httpd metube.cnf
      URL_PREFIX: "/metube"
      # user and group public
      UID: 805300006
      GID: 805300006
  watchtower:
    container_name: watchtower
    image: containrrr/watchtower:latest
    restart: always
    ports:
      - 8082:8080
    command: --interval 86400 metube
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/timezone:/etc/timezone:ro
    environment:
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_LABEL_ENABLE=true
      - WATCHTOWER_INCLUDE_RESTARTING=true

Of course, the ytdl_options are what I wanted. The .cache mount was to help with some problem with some ffmpeg transcoding operations. I set that /home/metube/.cache to mode 0777, like a noob.

Find average volume change needed for album

x=0 ; for word in *.mp3 ; do x=$((x+1)) ; ffmpeg -i "${word}" -af "volumedetect" -vn -sn -dn -f null /dev/null 2>&1 | awk "BEGIN{OFS=\",\"} /mean_volume/{a=\$5} /max_volume/{b=\$5} END{print a,b}" | sed -r -e "s/^/${x},/;" ; done

And then I saw the whole list of max and mean volumes. So my minimum max_volume is -8.3, so I need to add this amount to each file. I think ffmpeg does not use fractional decibels, so I chose 9.

x=0 ; time for word in *.mp3 ; do x=$((x+1)) ; new="new${word}" ; ffmpeg -i "${word}" -af "volume=9dB" "${new}" ; done

Seven Wonders docker image: use local css and fonts

Overview

I hacked the seven-wonders docker image to not use external (and potentially-tracking) servers for font and stylesheet assets.

I opened up an issue upstream to see if this is something fixable during the build process to avoid this silliness.

Step by step

I fetched all non-local urls with browser developer tools.

steps taken

These are the steps taken to set up the seven-wonders docker image to use local assets and not leak personal info.

cd /var/www/seven-wonders-assets/
wget 'https://fonts.googleapis.com/css2?family=Acme&display=swap'
# modify css2?f* to use url /seven-wonders-assets/
wget 'https://fonts.gstatic.com/s/acme/v21/RrQfboBx-C5_bx0.ttf'
wget 'https://unpkg.com/normalize.css@%5E7.0.0'
wget 'https://unpkg.com/@blueprintjs/icons@%5E4.13.0/lib/css/blueprint-icons.css'
wget 'https://unpkg.com/@blueprintjs/core@%5E4.15.0/lib/css/blueprint.css'

I found app.jar with sudo ls -al /var/lib/docker/overlay2/*/*/app.jar and finding the exact filesize one that matched from docker exec -it seven_wonders ls -al /app.jar.

get app.jar from sudo cp -pi /var/lib/docker/overlay2/l/JTQPGSF4VGTC4UPZ4W2Y7JUOXI/app.jar ~/foo and with openjdk 17 installed, run:

cd ~/foo
jar xvf app.jar
vi BOOT-INF/classes/static/index.html

and modify it to use /seven-wonders-assets/ paths for all the files. I set css2 to just "css2" and renamed the file to omit the question mark and other parameter-type entries. Its whole contents are as follows.

<!doctype html>
<html lang="en">
 <head>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1">

   <!-- The .ico is for compatibliity with Safari, which doesn't support SVG -->
   <link rel="icon" href="./favicon.ico" sizes="48x48">
   <link rel="icon" href="./favicon.svg" sizes="any" type="image/svg+xml">

   <title>Seven Wonders</title>
   <link href='/seven-wonders-assets/css2' rel='stylesheet'>
   <!-- Style dependencies -->
   <link href="/seven-wonders-assets/normalize.css@^7.0.0" rel="stylesheet"/>
   <!-- Blueprint stylesheets -->
   <link href="/seven-wonders-assets/blueprint-icons.css" rel="stylesheet"/>
   <link href="/seven-wonders-assets/blueprint.css" rel="stylesheet"/>
 </head>
 <body>
   <div id="root"></div>
   <script src="sw-ui.js"></script>
 </body>
</html>

And now upload the updated file into app.jar

jar -uf app.jar BOOT-INF/classes/static/index.html

And send that file back to where it came from.

sudo cp -pi ~/foo/app.jar /var/lib/docker/overlay2/l/JTQPGSF4VGTC4UPZ4W2Y7JUOXI/app.jar

And restart my docker app, which is a systemd service.

time sudo systemctl restart seven-wonders

And confirm the jar is still updated.

docker exec -it seven_wonders ls -al /app.jar

And now this game works without leaking info to the font and unpkg servers.

Python trick: weighted random choice from arbitrary string

I wrote a crazy python snippet I wanted to share. Due to the wonders of the very high-level python language, this works in a mostly-straightforward way:

import random
choices = ["choice1","second","final"]
weight_string="20,80"
weights=[int(i) for i in weight_string.split(",")][0:len(choices)]+[0]*(len(choices)-len(weight_string.split(",")))
weighted_choice = random.choices(population=choices,weights=weights,k=1)[0]

What this does, in the most pythonic way possible, is for each entry in weight_string when split by commas, combined with a list (array) of zeroes that is as long as the number of the choices minus the number of entries of weight_string when split by commas. And only grab the first so many of them, equal to the number of choices.

Adding the [0]*(length) provides empty values in case the weight string does not have enough entries to match the number of choices.

This logic is entirely my own. After an Internet search revealed the existence of random.choices and its interface, I assembled the weights definition without any other existing textual reference.

Shell hack: docker-nfs-check

I use docker containers that mount nfs mounts. Sometimes if the docker server comes up before the nfs server does, (and the systemd service dependency definitions don't work), then I want to bounce the services after I've gotten nfs working.

This affects things like my photo app (PhotoPrism) and metube which store files on the network share.

#!/bin/sh
# Startdate: 2023-07-18-3 11:00
# File: /usr/local/bin/docker-nfs-check
# Purpose: check nfs
# Usage:
#    must define DOCKER_SERVICE to run this. It loads /etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE} file to load the rest of the env vars
LOGFILE=/mnt/public/Support/Systems/server4/var/log/docker-nfs-check/log
exec 3>&1
{
   {
      {
         # initial loading of values
         test -z "${DOCKER_SERVICE}" && test -n "${1}" && DOCKER_SERVICE="${1}"
         test -z "${DOCKER_SERVICE}" && { printf '%s\n' "Fatal: need DOCKER_SERVICE set to a docker service to load env vars from /etc/sysconfig/docker-nfs-check/\${DOCKER_SERVICE} file." 1>&2 ; exit 1 ; }
         if ! test -f "/etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE}" ;
         then
            printf '%s\n' "Fatal: no file found for /etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE}. Aborted." 1>&2
            exit 1
         fi
         . "/etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE}"
         for word in DS_LINES DS_PATH DS_CONTAINER DS_USER DS_SERVICE ;
         do
            _var="$( eval "echo \$${word}" )"
            test -z "${_var}" && { printf '%s\n' "Fatal: need ${word} defined. Aborted." 1>&2 ; exit 1 ; }
         done
         # main
         output="$( sudo su - "${DS_USER}" -s /bin/bash -c "cd ${DS_PATH} ; docker-compose exec ${DS_CONTAINER} mount | awk \"\\\$5~/nfs/{print \\\$1,\\\$3}\" ;" )"
         # output should be ${DS_LINES} lines:
         # server3:/var/server3/shares/public/Images/photoprism-imported /photoprism/originals
         # server3:/var/server3/shares/public/Images/photos /photoprism/originals/photos
         if test "$( echo "${output}" | wc -l )" != "${DS_LINES}" ;
         then
            printf '%s\n' "restarting which is missing the nfs mounts."
            sudo systemctl restart "${DS_SERVICE}"
         else
            printf '%s\n' "All good:"
            printf '%s\n' "${output}"
         fi
      } 2>&1 1>&3 | sed -r -e "s/^/STDERR: /;"
   } 3>&1 2>&1
} | plecho ${DOCKER_SERVICE} | tee -a "${LOGFILE}"

It uses my favorite shell redirection spaghetti boilerplate code to prepend STDERR to standard error messages that all end up in the same place.

But inside all that, is the sauce of running the "mount" command and then restarting the docker container if the output is not as expected.

I use shell completion:

# File: /etc/bash_completion.d/docker-nfs-check
# vim: set syntax=sh:
# startdate: 2023-07-18-3 15:45
_docker_nfs_check() {
   local cur prev words cword;
   _init_completion || return
   _tmpfile1="$( mktemp )"
   # populate list
   find /etc/sysconfig/docker-nfs-check  -mindepth 1 -maxdepth 1 ! -type d ! -name '.*' -printf '%P\n' > "${_tmpfile1}"
   COMPREPLY=($( compgen -W "$( cat ${_tmpfile1} )" -- "$cur" ))
   command rm -rf "${_tmpfile1:-NOTHINGTODEL}" 1>/dev/null 2>&1
   return 0
} &&
complete -F _docker_nfs_check docker-nfs-check

And what it does is list the service definitions available in directory /etc/sysconfig/docker-nfs-check/.

# File: /etc/sysconfig/docker-nfs-check/photoprism
# dot-sourced by /usr/local/bin/docker-nfs-check
# To load this file, you must set DOCKER_SERVICE to match this filename.
# su to this user and then
DS_USER="photoprism"
# cd to this path
DS_PATH="/home/photoprism/photoprism"
# to run the docker-compose command on this container name
DS_CONTAINER="photoprism"
# how many lines should return from docker-compose exec ${this_filename} mount | grep nfs
DS_LINES=3
# if the lines are incorrect, restart this systemd service
DS_SERVICE="photoprism.service"

This is indeed a ridiculous hack and work-around, but it works for me. And clearly I'm running out of good blog topics I'm actually going to bother to write.

My kickstart for Rocky Linux 9 VMs

With all of the recent hullabaloo about IBM's Red Hat's destruction of their community goodwill, and more specifically AlmaLinux's plans, I have reconsidered my position for SELinux-based GNU/Linux.

Plus it has been a while since I've published my CentOS-based kickstart file. I had written one for AlmaLinux 9 but hadn't published it yet.

# File: /mnt/public/Support/Platforms/Rocky/a9-ks.cfg
# Locations:
#    /mnt/public/Support/Platforms/Rocky/a9-ks.cfg
# Author: bgstack15
# Startdate: 2017-06-02
# Title: Kickstart for Rocky Linux 9 for ipa.internal.com
# Purpose: To provide an easy installation for VMs and other systems in the Internal network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
#
#
#
#
#    2019-09-24 fork for CentOS 8
#    2020-11-08 update for 2004 iso
#
#
#
#
#    2022-03-18 change to AlmaLinux 8
#    2022-12-09 update to AlmaLinux 8.7, now required 3GB RAM for installation
#    2023-03-10 update to AlmaLinux 9
#    2023-07-17 update to Rocky Linux 9
# Usage with virt-install:
#    vm=r9-01a ; time sudo virt-install -n "${vm}" --memory 3072 --vcpus=1 --os-variant=centos8 --accelerate -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=30 -l /mnt/public/Support/SetupsBig/Linux/Rocky-9.2-x86_64-minimal.iso --initrd-inject=/mnt/public/Support/Platforms/Rocky/r9-ks.cfg --extra-args "inst.ks=file:/r9-ks.cfg SERVERNAME=${vm} NOTIFYEMAIL=bgstack15@gmail.com net.ifnames=0 biosdevname=0 inst.txt" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=r9-01a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    https://sysadmin.compxtreme.ro/automatically-set-the-hostname-during-kickstart-installation/
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt

#platform=x86, AMD64, or Intel EM64T
#version=DEVEL
# Keyboard layouts
keyboard 'us'
# Root password
rootpw --plaintext plaintextexamplepw
# my user
user --groups=wheel --name=bgstack15-local --password=$6$.gh9u7vg2HDJPPX/scrubbedpasswdentrygoeshere --iscrypted --gecos="bgstack15-local"

# System language
lang en_US.UTF-8
# Firewall configuration
firewall --enabled --ssh
# Reboot after installation
reboot
# Network information
%include /tmp/network.ks
# System timezone
timezone America/New_York --utc
# System authorization information, sha512 is now default in authselect in RHEL >= 8
#auth  --useshadow  --passalgo=sha512
# Use network installation instead of CDROM installation media
#url --url="https://download.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os"
url --url="http://server3/mirror/rocky/9/BaseOS/x86_64/os"

# Use text mode install
text
# SELinux configuration
selinux --enforcing
# Do not configure the X Window System
skipx

# Use all local repositories
repo --name=internalrpm --baseurl=http://server3/internal/repo/rpm/
repo --name=copr-bgstack15-stackrpms --baseurl=http://server3/mirror/copr-bgstack15-stackrpms/epel-9-$basearch/
repo --name=base --baseurl=http://server3/mirror/rocky/$releasever/BaseOS/$basearch/os/
repo --name=appstream --baseurl=http://server3/mirror/rocky/$releasever/AppStream/$basearch/os/
repo --name=extras --baseurl=http://server3/mirror/rocky/$releasever/extras/$basearch/os/
repo --name=epel --baseurl=http://server3/mirror/fedora/epel/9/Everything/$basearch

firstboot --disabled

# System bootloader configuration
bootloader --location=mbr
# Partition clearing information
clearpart --all --initlabel
# Disk partitioning information
autopart --type=lvm

%pre
echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname renameme.ipa.internal.com" > /tmp/network.ks
for x in $( cat /proc/cmdline );
do
   case $x in
      SERVERNAME*)
         eval $x
         echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname ${SERVERNAME}.ipa.internal.com" > /tmp/network.ks
      ;;
      NOTIFYEMAIL*)
         eval $x
         echo "${NOTIFYEMAIL}" > /mnt/sysroot/root/notifyemail.txt
      ;;
   esac
done
cp -p /run/install/repo/ca-ipa.internal.com.crt /etc/pki/ca-trust/source/anchors/ 2>/dev/null || :
wget http://server3/internal/certs/ca-ipa.internal.com.crt -O /etc/pki/ca-trust/source/anchors/ca-ipa.internal-wget.com.crt || :
update-ca-trust || :
%end

%post
(
   # Set temporary hostname
   #hostnamectl set-hostname renameme.ipa.internal.com;

   # Get local mirror root ca certificate
   wget http://server3/internal/certs/ca-ipa.internal.com.crt -O /etc/pki/ca-trust/source/anchors/ca-ipa.internal.com.crt && update-ca-trust

   # Get local mirror repositories
   wget http://server3/internal/repo/rpm/set-my-repos.sh --output-document /usr/local/sbin/set-my-repos.sh ; chmod +x /usr/local/sbin/set-my-repos.sh ; sh -x /usr/local/sbin/set-my-repos.sh

   # NONE TO REMOVE dnf -y remove dnfdragora ;
   yum clean all ;
   yum update -y ;

   # Remove graphical boot and add serial console
   sed -i -r -e '/^GRUB_CMDLINE_LINUX=/{s/(\s*)(rhgb|quiet)\s*/\1/g;};' -e '/^GRUB_CMDLINE_LINUX=/{s/(\s*)\"$/ console=ttyS0 console=tty1\"/;}' /etc/default/grub
   grub2-mkconfig > /boot/grub2/grub.cfg

   # No changes to graphical boot
   #

   # fix the mkhomedir problem
   systemctl enable oddjobd.service && systemctl start oddjobd.service

   # Personal customizations
   mkdir -p /mnt/bgstack15 /mnt/public
   su bgstack15-local -c "sudo /usr/bin/bgconf.py"
   echo ". bp" >> /home/bgstack15-local/.bashrc

   # this has to happen after a glibc update
   yum -y reinstall locale-en_BS || :
   for x in $( cat /proc/cmdline ) ;
   do
      case $x in
         SERVERNAME*|NOTIFYEMAIL*)
            eval $x
      ;;
      esac
   done

   # Send IP address to myself
   thisip="$( ifconfig 2>/dev/null | awk '/Bcast|broadcast/{print $2}' | tr -cd '[^0-9\.\n]' | head -n1 )"
   {
      echo "${SERVERNAME} has IP ${thisip}."
      echo "system finished kickstart at $( date "+%Y-%m-%d %T" )";
   } | s-nail -S "mta=smtp://server2.ipa.internal.com:25" -S from="root@$( hostname --fqdn ) <root@$( hostname --fqdn )>" \
      -s "${SERVERNAME} is ${thisip}" "${NOTIFYEMAIL}"

) >> /root/install.log 2>&1
%end

%packages
@core
@^minimal install
bc
bgconf
bgscripts-core
bind-utils
cifs-utils
cryptsetup
curl
dosfstools
epel-release
expect
firewalld
git
iotop
ipa-client
-iwl*-firmware
locale-en_BS
man
mlocate
net-tools
nfs-utils
p7zip
parted
postfix
python3-policycoreutils
rpm-build
rsync
s-nail
screen
strace
sysstat
tcpdump
telnet
vim
wget
yum-utils
%end

What's new

I switched to all Rocky Linux mirror! An interesting note is that anaconda for Rocky netinstalls use a $releasever of 9.2 and not 9, which broke epel and baseos repositories when trying to use an AlmaLinux mirror.

I finally bothered to read the man page about authselect something or other (which replaced authconfig), and the old --useshadow and --pasalgo=sha512 are defaults now and not required.

I decided to bother to add my main personal profile (stored in an rpm as a generlaly available shell command) command to my local user's bashrc so I get my preferred prompt.

I enforce reinstalling locale-en_BS which failed to exist correctly, which happens after a glibc update. I guess the netinst somehow already gets an out-of-date glibc. Not a big deal.

I learned that the population of file /mnt/sysroot/root/notifyemail.txt in the %pre section failed, so I just reevaluate /proc/cmdline and get the variables I want.

I also bothered to deal with whatever first mailx replacement I found that I could get working, and send my notification email through my local smtp server.

Devuan preseed, July 2023 edition

And here's the latest version of my [un?]popular series on Devuan GNU+Linux preseed virtual machine installations. I don't think a whole lot has changed really, except of course the Devuan release number.

# File: /mnt/public/Support/Platforms/devuan/preseed/preseed.cfg
# Locations:
#    /mnt/public/Support/Platforms/devuan/preseed/preseed.cfg
# Author: bgstack15
# Startdate: 2019-06-25
# Title: Preseed for devuan vms for ipa.internal.com
# Purpose: To provide an easy installation for VMs and other systems in the Internal network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
#    2019-06-25 fork from centos7-ks.cfg
#    2018-12-29 fix up repos and in-target conclusion stuff
#    2020-02-27 heavy rewrite to use ascii 2.1
#    2021-05-16 bump to chimaera which upgrades self to ceres
#    2023-01-20 kernel cmdline, remove newmoon
#    2023-02-28 add ssh_config EnableEscapeCommandline yes, disable apparmor for sssd
#    2023-06-26 add configure-postfix.sh
# Usage with virt-install:
#    vm=d2-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=debiantesting -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/devuan_daedalus_5.0.preview-20230116_amd64_netinstall.iso --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg --extra-args "NOTIFYEMAIL=bgstack15@gmail.com interface=auto netcfg/get_hostname=${vm}" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=d2-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    https://sysadmin.compxtreme.ro/automatically-set-the-hostname-during-kickstart-installation/
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt
#    https://serverfault.com/questions/481244/preseed-command-string-fail-with-newline-character-using-virt-install-initrd-inj
#    https://www.debian.org/releases/stable/i386/apbs01.html.en
#    https://github.com/jameswthorne/preseeds/blob/master/debian-7-wheezy-unattended.seed
#    syntax for --location https://www.queryxchange.com/q/1_908324/virt-install-preseed-not-working/
#    example preseed https://www.debian.org/releases/stable/example-preseed.txt
#    skip next dvd question https://unix.stackexchange.com/questions/409212/preseed-directive-to-skip-another-cd-dvd-scanning
#    grub problem caused by consolekit:amd64 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=915947#10
#    https://stackoverflow.com/questions/39861614/how-to-fully-automate-unattended-virt-install
#    https://www.debian.org/releases/stable/i386/apbs03.html.en
#    https://dev1galaxy.org/viewtopic.php?id=1853
#    https://www.cyberciti.biz/faq/howto-setup-serial-console-on-debian-linux/
#    https://github.com/virt-manager/virt-manager/blob/master/virtinst/install/urldetect.py
#    /mnt/public/Support/Platforms/devuan/fix-virt-manager.txt
#    https://dev1galaxy.org/viewtopic.php?id=3332
#    https://ubuntuforums.org/showthread.php?t=2387570
#    sudo debconf-get-selections -c /mnt/public/Support/Platforms/devuan/preseed/preseed.cfg
#    on d2-03a: sudo debconf-get-selections --installer
#    https://serverfault.com/questions/593388/unable-to-nfs-mount-in-debian-preseed-target/593389
#    https://preseed.debian.net/debian-preseed/sid/amd64-main-full.txt
#    https://bgstack15.ddns.net/blog/posts/2020/12/03/disable-apparmor-for-sssd/
# Improve:
#    discover how to send email, using postfix or sendmail. Don't care which, but exclude exim4.
#    echo "$( hostname ) has IP $( ip -4 -o a s eth0 | awk '{print $4}' | sed -r -e 's/\/.*$//' )" | 
# Dependencies:
#    configure-postfix uses my gmail+smtp+oauth2 postfix relay

d-i debian-installer/country string US
d-i debian-installer/keymap select us
d-i debian-installer/language string en
d-i debian-installer/locale string en_US
d-i localechooser/supported-locales string en_US.UTF-8

d-i keyboard-configuration/layoutcode string us
d-i keyboard-configuration/variantcode string
d-i keyboard-configuration/xkb-keymap select us

d-i netcfg/disable_autoconfig boolean false
# The hostname is supposed to come from the kernel cmdline in the virt-install invocation
#d-i netcfg/get_hostname string NONE
d-i netcfg/get_domain string ipa.internal.com
d-i netcfg/wireless_wep string
# disable asking for non-free firmware, because this is a vm and has none
d-i hw-detect/load_firmware boolean false

#d-i apt-setup/enable-source-repositories boolean false
# ORIGINAL d-i apt-setup/services-select multiselect security updates, release updates, backported software
d-i apt-setup/services-select multiselect release updates
d-i apt-setup/contrib boolean true
d-i apt-setup/disable-cdrom-entries boolean true
d-i apt-setup/non-free boolean true
d-i apt-setup/use_mirror boolean true
d-i mirror/country string manual
d-i mirror/http/directory string /merged
d-i mirror/http/hostname string deb.devuan.org
d-i mirror/http/proxy string
d-i mirror/protocol string http
d-i mirror/suite string testing

d-i apt-setup/cdrom/set-failed boolean false
d-i apt-setup/cdrom/set-first boolean false
d-i apt-setup/cdrom/set-next boolean false

## my repos and ceres
d-i apt-setup/local0/comment    string internaldeb
d-i apt-setup/local0/key        string http://www.example.com/internal/repo/deb/internaldeb.gpg
d-i apt-setup/local0/repository string http://www.example.com/internal/repo/deb/ /
d-i apt-setup/local1/comment    string devuan-deb
d-i apt-setup/local1/key        string http://www.example.com/internal/repo/deb/internaldeb.gpg
d-i apt-setup/local1/repository string http://www.example.com/internal/repo/devuan-deb/ /
d-i apt-setup/local2/comment    string ceres
d-i apt-setup/local2/key        string http://www.example.com/mirror/devuan/dists/ceres/Release.gpg
d-i apt-setup/local2/repository string http://www.example.com/mirror/devuan ceres main contrib non-free
#d-i apt-setup/local2/key        string http://pkgmaster.devuan.org/merged/dists/ceres/Release.gpg
#d-i apt-setup/local2/repository string http://pkgmaster.devuan.org/merged ceres main contrib non-free
d-i apt-setup/local3/comment    string obsmirror
d-i apt-setup/local3/key        string http://www.example.com/mirror/obs/Release.key
d-i apt-setup/local3/repository string http://www.example.com/mirror/obs/ /
d-i apt-setup/local4/comment    string obsmirror-gtk3-classic
d-i apt-setup/local4/key        string http://www.example.com/mirror/obs-gtk3-classic/Release.key
d-i apt-setup/local4/repository string http://www.example.com/mirror/obs-gtk3-classic/ /
# if for some reason I really need to turn off the gpg key check:
#d-i debian-installer/allow_unauthenticated boolean false

#tasksel tasksel/first multiselect standard, ssh-server
tasksel tasksel/first multiselect none

# adapted from /mnt/public/Support/Platforms/devuan/devuan.txt, main fluxbox desktop, but for a vm
# no xscreensaver, for a vm.
#d-i pkgsel/include string \
#   alsamixergui alttab apt-transport-https bgconf bgscripts bgscripts-core \
#   cifs-utils curl fluxbox freeipa-client git grub lightdm lightdm-gtk-greeter \
#   mlocate net-tools nfs-common ntpdate openssh-server \
#   p7zip palemoon palemoon-ublock-origin parted qemu-guest-agent rsync scite \
#   screen spice-vdagent strace sudo tcpdump vim vlc volumeicon-alsa waterfox \
#   xfce4-terminal xfe xserver-xorg-video-qxl fluxbox-themes-stackrpms
#d-i pkgsel/include string cifs-utils curl grub lightdm vim sudo vlc screen p7zip nfs-common
d-i pkgsel/include string openssh-server wget curl

d-i pkgsel/upgrade select none

popularity-contest popularity-contest/participate boolean true

d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string dns1.ipa.internal.com
d-i time/zone string America/New_York

# skip grub during main part, because we will do it in late_command
#d-i grub-installer/skip boolean true
#d-i grub-installer/skip-again boolean true
#d-i grub-installer/skip-confirm boolean true
#d-i grub-installer/confirm_skip boolean true
#d-i nobootloader/confirmation_common boolean true
d-i     choose-init/select_init select  sysvinit
d-i     choose-init/selected_sysvinit bool   true
grub-installer  grub-installer/choose_bootdev   select  /dev/vda

d-i lilo-installer/skip boolean true
#d-i grub-installer/with_other_os boolean true
d-i grub-installer/only_debian boolean true
d-i grub-installer/grub2_instead_of_grub_legacy boolean true
#d-i grub-installer/bootdev string /dev/vda
#d-i grub-installer/choose_bootdev select /dev/vda
#grub-installer grub-installer/force-efi-extra-removable boolean false

d-i passwd/root-password password plaintextexamplepw
d-i passwd/root-password-again password plaintextexamplepw

d-i partman-auto/choose_recipe select home
d-i partman-auto-crypto/erase_disks boolean false
d-i partman-auto/disk string /dev/vda
d-i partman-auto/init_automatically_partition select biggest_free
d-i partman-auto/method string lvm
d-i partman/choose_label string gpt
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/confirm_write_new_label boolean true
d-i partman/default_label string gpt
#d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-md/confirm_nooverwrite boolean true
#d-i partman/mount_style select uuid
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman-auto-lvm/guided_size string 100%

# Uncomment this to add multiarch configuration for i386
#d-i apt-setup/multiarch string i386

d-i passwd/make-user boolean true
d-i passwd/user-fullname string bgstack15-local
d-i passwd/username string bgstack15-local
d-i passwd/user-password-crypted password $6$BxyYQfM7A1TEeS6X$SEXAMPLE6.n6SU21s.ojeQ9F06AMcnEXAMPLEHTufeWXLpNu6EmpsDN7eEXAMPLEU4moiXVgzIiTJYXatdGBz0/
d-i passwd/user-default-groups string audio cdrom video

d-i finish-install/reboot_in_progress note
d-i cdrom-detect/eject boolean true

# additional application stuff just in case it works and is useful
# LDAP server URI:
d-i shared/ldapns/ldap-server   string  ldapi:///ipa.internal.com

d-i openssh-server/password-authentication  boolean true
d-i openssh-server/permit-root-login    boolean false

# Sometimes the update-devuan has to happen before the laundry list of packages, because upgrading from some stable release to Ceres causes package numbering-name mismatches.
d-i preseed/late_command string mkdir -p /target/etc/apt/sources.list.d /target/mnt/bgstack15 /target/mnt/public /target/etc/apt/sources.list.d /target/root/input ; touch /target/etc/apt/sources.list.d/empty ; cd /target/etc/apt ; \
   in-target apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" gpg grub-pc sudo ; \
   in-target curl --no-progress-meter --output /root/set-local-devuan-repo.sh http://www.example.com/internal/Support/Platforms/devuan/scripts/set-local-devuan-repo.sh ; in-target sh /root/set-local-devuan-repo.sh ; \
   in-target curl --no-progress-meter --output /root/input/52apt-file-stackrpms.conf http://www.example.com/internal/Support/Platforms/devuan/scripts/input/52apt-file-stackrpms.conf ; in-target curl --no-progress-meter --output /root/set-my-repos.sh http://www.example.com/internal/Support/Platforms/devuan/scripts/set-my-repos.sh ; in-target sh /root/set-my-repos.sh || : ; \
   in-target rm /etc/apt/trusted.gpg.d/ceres.gpg || : ; \
   in-target curl --no-progress-meter http://www.example.com/internal/certs/ca-ipa.internal.com.crt --output /usr/local/share/ca-certificates/ca-ipa.internal.com.crt && in-target update-ca-certificates || : ; \
   in-target wget -O /root/update-devuan.sh http://www.example.com/internal/Support/Platforms/devuan/scripts/update-devuan.sh ; in-target sh /root/update-devuan.sh preseed ; \
   in-target apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" alsamixergui alttab bgconf bgscripts bgscripts-core ca-certificates cifs-utils curl desktop-base fluxbox fluxbox-themes-stackrpms freeipa-client freeipa-helper git grub-pc gtk3-automnemonics gtk3-nocsd gtk3-nooverlayscrollbar krb5-auth-dialog librewolf logout-manager man mlocate net-tools nfs-common ntpdate p7zip parted postfix qemu-guest-agent rsync scite screen spice-vdagent strace sudo tcpdump ublock-origin-combined vim vlc volumeicon-alsa xdgmenumaker xfce4-terminal xfe xserver-xorg-input-libinput xserver-xorg-video-qxl ; \
   rm -f /target/etc/apt/sources.list.d/empty || : ; \
   in-target sed -i -r -e '/^\s*linux/s/(\s*console=.{1,7}[0-9])*\s*$/ console=tty0 console=ttyS0/;' /boot/grub/grub.cfg || : ; \
   in-target sed -i -r -e '/^\s*kernel/s/(\s*console=.{1,7}[0-9])*\s*$/ console=tty0 console=ttyS0/;' /boot/grub/menu.lst || : ; \
   in-target sed -i -r -e '$aT0:23:respawn:/sbin/getty -L ttyS0 9600 vt100' /etc/inittab ; \
   in-target apt-get update ; \
   in-target apt-get purge -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" consolekit exim4\* lxqt\* udev ; \
   in-target curl --no-progress-meter --output /root/lightdm-elogind.sh http://www.example.com/internal/Support/Platforms/devuan/scripts/lightdm-elogind.sh ; in-target sh /root/lightdm-elogind.sh -y ; \
   in-target su bgstack15-local -c "sudo /usr/bin/bgconf.py -d 10 1>/home/bgstack15-local/clone.log 2>&1" ; \
   in-target updateval -a -v /etc/ssh/ssh_config '^\s*EnableEscapeCommandline.*' 'EnableEscapeCommandline yes' ; \
   in-target ln -sf /etc/apparmor.d/usr.sbin.sssd /etc/apparmor.d/disable/ ; \
   in-target apparmor_parser -R /etc/apparmor.d/usr.sbin.sssd ; \
   in-target curl --no-progress-meter --output /root/configure-postfix.sh http://www.example.com/internal/Support/Platforms/devuan/scripts/configure-postfix.sh ; in-target sh /root/configure-postfix.sh ; \
   in-target curl --no-progress-meter --output /root/send-mail-ip-address.sh http://www.example.com/internal/Support/Platforms/devuan/scripts/send-mail-ip-address.sh ; in-target sh /root/send-mail-ip-address.sh bgstack15@gmail.com ;

Explanations

And of course, most of the logic is in all the included scripts.

File set-local-devuan-repo.sh

#!/bin/sh
# Startdate: 2020-03-12
# Purpose: Replace original devuan repos with my local devuan mirror
# History:
#    2021-01-27 remove prebuilt file. Just use heredoc
#    2023-02-28 add new repo section non-free-firmware
# Documentation:
# Use the network file if available, otherwise, use this hardcoded heredoc.
tf=/etc/apt/sources.list
touch "${tf}"
{
   cat <<'EOF'
# file: /mnt/public/Support/Platforms/devuan/sources.list
# date: 2023-02-28
# the 3 main ones: ascii main/security/updates
# uncomment all of them when needing winehq-staging for AoC.
# If using ascii, there are multiple lines: ascii ascii-security ascii-updates
#deb http://deb.devuan.org/merged ceres main contrib non-free non-free-firmware
deb http://www.example.com/mirror/devuan ceres main contrib non-free non-free-firmware
deb-src http://pkgmaster.devuan.org/merged ceres main
EOF
} > "${tf}"

File set-my-repos.sh

#!/bin/sh
# File: /mnt/public/Support/Platforms/devuan/set-my-repos.sh
# Location:
# Author: bgstack15
# Startdate: 2019-08-10 16:02
# Title: Script that Establishes the repos needed for Devuan
# Purpose: Set up the 3 repos I always need on devuan clients
# History:
#    2020-02-01 customize clients for devuan-archive
#    2020-10-23 add apt-file compatibility
#    2021-01-27 disable devuan-archive
# Usage:
#    sudo set-my-repos.sh
# Reference:
#    /mnt/public/Support/Platforms/devuan/devuan.txt
# Improve:
#    need to control the sources.list file itself to have the main, contrib, etc., for ceres.
# Documentation:
test -z "${ALLREPOSGLOB}" && ALLREPOSGLOB="/etc/apt/sources.list /etc/apt/sources.list.d/*"
test -z "${REPOSBASE}" && REPOSBASE="/etc/apt/sources.list.d"
test -z "${PREFSBASE}" && PREFSBASE="/etc/apt/preferences.d"
test -z "${ADDLCONFBASE}" && ADDLCONFBASE="/etc/apt/apt.conf.d"
# confirm key
confirm_key() {
   # call: confirm_key "${PRETTYNAME}" "${SEARCHPHRASE}" "${URL_OF_KEY}"
   ___ck_repo="${1}"
   ___ck_sp="${2}"
   ___ck_url="${3}"
   if apt-key list 2>/dev/null | grep -qe "${___ck_sp}" ;
   then
      :
   else
      # not found so please add it
      echo "Adding key for ${___ck_repo}" 1>&2
      #wget -O- "${___ck_url}" | sudo apt-key add -
      ___ck_keyfile="/etc/apt/trusted.gpg.d/$( echo "${___ck_repo}" | tr '[: ]' '_' ).gpg"
      wget -O- --quiet "${___ck_url}" | gpg --dearmor | sudo tee "${___ck_keyfile}" 1>/dev/null
   fi
}
# confirm repo
confirm_repo() {
   # call: confirm_repo "${PRETTYNAME}" "${SEARCHPHRASE}" "${SEARCHGLOB}" "${FULLSTRING}" "${PREFERRED_FILENAME}" "${OVERWRITE}"
   ___cr_repo="${1}"
   ___cr_sp="${2}"
   ___cr_sf="${3}"
   ___cr_full="${4}"
   ___cr_pref="${5}"
   ___cr_overwrite="${6}"
   if ! grep -E -qe "${___cr_sp}" ${___cr_sf} ;
   then
      # not found so please add it to preferred file
      echo "Adding repo ${___cr_repo}" 1>&2
      if test "${___cr_overwrite}" = "true" ;
      then
         # overwrite, instead of append
         echo "${___cr_full}" > "${REPOSBASE}/${___cr_pref:-99_misc.list}"
      else
         echo "${___cr_full}" >> "${REPOSBASE}/${___cr_pref:-99_misc.list}"
      fi
   fi
}
confirm_preferences() {
   # call: confirm_preferences "${PRETTYNAME}" "${FILENAME}" "{PACKAGE}" "${PIN_EXPRESSION}" "{PRIORITY}"
   ___cp_prettyname="${1}"
   ___cp_pref="${2}"
   ___cp_package="${3}"
   ___cp_pin_expression="${4}"
   ___cp_priority="${5}"
   ___cp_tempfile="$( mktemp )"
   {
      echo "Package: ${___cp_package}"
      echo "Pin: ${___cp_pin_expression}"
      echo "Pin-Priority: ${___cp_priority}"
   } > "${___cp_tempfile}"
   diff "${PREFSBASE}/${___cp_pref}" "${___cp_tempfile}" 1>/dev/null 2>&1 || {
      echo "Setting preferences for ${___cp_prettyname}"
      touch "${PREFSBASE}/${___cp_pref}" ; chmod 0644 "${PREFSBASE}/${___cp_pref}"
      cat "${___cp_tempfile}" > "${PREFSBASE}/${___cp_pref}"
   }
   rm -f "${___cp_tempfile:-NOTHINGTODEL}" 1>/dev/null 2>&1
}
# REPO 1: local internaldeb
confirm_key "internaldeb" "bgstack15.*www\.no-ip\.biz" "http://www.example.com/internal/repo/deb/internaldeb.gpg"
confirm_repo "internaldeb" "target.*internal\/repo\/deb" "${ALLREPOSGLOB}" "deb [target-=Contents-deb target+=Contents-stackrpms] http://www.example.com/internal/repo/deb/ /" "internaldeb.list" "true"
# REPO 2: local devuan-deb
confirm_key "devuan-deb" "bgstack15.*www\.no-ip\.biz" "http://www.example.com/internal/repo/deb/internaldeb.gpg"
confirm_repo "devuan-deb" "target.*internal\/repo\/devuan-deb" "${ALLREPOSGLOB}" "deb [target-=Contents-deb target+=Contents-stackrpms] http://www.example.com/internal/repo/devuan-deb/ /" "devuan-deb.list" "true"
# REPO 3: local obs
# Thankfully I re-sign this with my own key.
#confirm_key "OBS bgstack15" "bgstack15@build\.opensuse\.org" "https://download.opensuse.org/repositories/home:bgstack15/Debian_Unstable/Release.key"
#confirm_repo "OBS bgstack15" "repositories\/home:\/bgstack15\/Debian_Unstable" "${ALLREPOSGLOB}" "deb http://download.opensuse.org/repositories/home:/bgstack15/Debian_Unstable/ /" "home:bgstack15.list"
confirm_key "OBS bgstack15" "bgstack15@build\.opensuse\.org" "http://www.example.com/mirror/obs/Release.key"
confirm_repo "OBS bgstack15" "mirror\/obs" "${ALLREPOSGLOB}" "deb http://www.example.com/mirror/obs/ /" "home:bgstack15.list"
# REPO 4: local devuan-archive
# deprecated circa 2021-05
#confirm_key "devuan-archive" "bgstack15.*www\.no-ip\.biz" "http://www.example.com/internal/repo/deb/internaldeb.gpg"
#confirm_repo "devuan-archive" "target.*server1((\.ipa)?\.internal\.com)?(:180)?.*internal\/repo\/devuan-archive" "${ALLREPOSGLOB}" "deb [target-=Contents-deb target+=Contents-stackrpms] http://server1.ipa.internal.com:180/internal/repo/devuan-archive/ /" "devuan-archive.list" "true"
#confirm_preferences "devuan-archive" "puddletag" "*" "origin server1.ipa.internal.com" "700"
# REPO 5: local obs-aftermozilla key for non-local aftermozilla repo
# just the key
#confirm_key "OBS bgstack15 aftermozilla" "bgstack15@build\.opensuse\.org" "https://download.opensuse.org/repositories/home:bgstack15:aftermozilla/Debian_Unstable/Release.key"
# REPO 5: local obs-AfterMozilla
confirm_key "OBS bgstack15" "bgstack15@build\.opensuse\.org" "http://www.example.com/mirror/obs/Release.key"
confirm_repo "OBS bgstack15 AfterMozilla" "mirror\/obs-AfterMozilla" "${ALLREPOSGLOB}" "deb http://www.example.com/mirror/obs-AfterMozilla/ /" "home:bgstack15:AfterMozilla.list"
# REPO 6: local obs-gtk3-classic
confirm_key "OBS bgstack15" "bgstack15@build\.opensuse\.org" "http://www.example.com/mirror/obs/Release.key"
confirm_repo "OBS bgstack15 gtk3-classic" "mirror\/obs-gtk3-classic" "${ALLREPOSGLOB}" "deb http://www.example.com/mirror/obs-gtk3-classic/ /" "home:bgstack15:gtk3-classic.list"
# ADDITIONAL APT PREFS
# important for the [target] stuff to work on repos so apt-file can work
cp -p "$( dirname "$( readlink -f "${0}" )")/input/52apt-file-stackrpms.conf" "${ADDLCONFBASE}/"

And supporting file 52apt-file-stackrpms.conf:

# File: /etc/apt/apt.preferences.d/52apt-file-stackrpms.conf
# Part of support devuan scripts
# This enables the flat apt repos in internal to be supported by apt-file
Acquire::IndexTargets {
    deb::Contents-stackrpms {
        MetaKey "Contents-$(ARCHITECTURE)";
        ShortDescription "Contents-$(ARCHITECTURE)";
        Description "$(RELEASE) $(ARCHITECTURE) Contents (deb)";

        flatMetaKey "Contents-$(ARCHITECTURE)";
        flatDescription "$(RELEASE) Contents (deb)";
        PDiffs "true";
        KeepCompressed "true";
        DefaultEnabled "false";
        Identifier "Contents-deb";
    };
};

File update-devuan.sh

I've talked about this before, but here's the current version in case it's different. You think I QA this stuff before I paste+scrub this contents?

#!/bin/sh
# File: update-devuan.sh
# Location: /mnt/public/Support/Platforms/devuan
# Author: bgstack15
# Startdate: 2019-07-01 18:48
# Title: The command to run for mostly-unattended updates on Devuan
# Purpose: Mostly-unattended apt-get dist-upgrade
# History:
#    2019-12-15 add the y/n if dist-upgrade will remove packages
#    2020-02-26 add --allow-downgrades for the libqt5core5a which was customized for freefilesync or similar
#    2023-02-28-3 19:47 add dbus-on which populates the dbus machine-id baloney for the dbus package
# Usage:
# Reference:
# Improve:
# Documentation:
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
test "${1}" = "preseed" && extrastring="--allow-downgrades"
mkdir -p ~/log
myupdate() {
   sudo dbus-on || :
   sudo apt-get update ;
   sudo DEBIAN_FRONTEND=noninteractive apt-get -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-overwrite" upgrade ;
   ___remove_count="$( yes no | sudo apt-get dist-upgrade 2>&1 | grep -oiE '[0-9]+ to remove' | grep -oE '[0-9]*' )"
   ___do_run="no"
   if test "${___remove_count}" = "0" ;
   then
      ___do_run="yes"
   else
      ___to_remove="$( yes no | sudo apt-get dist-upgrade 2>&1 | awk 'BEGIN{a=0} /^[ \s]/{ if(a==1)print;} /^[a-zA-Z]/ {if(/REMOVED/ || /NEW /){a=1;print} else {a=0}}' )"
      echo "${___to_remove}" 1>&2
      echo "WARNING: are you sure you want to do this [yN]? " 1>&2
      test -z "${extrastring}" && { read response ; } || ___do_run="yes"
      if test "$( echo "${response}" | cut -c1 2>/dev/null | tr '[A-Z]' '[a-z]' )" = "y" ; then ___do_run="yes" ; fi
   fi
   if test "${___do_run}" = "yes" ;
   then
      sudo DEBIAN_FRONTEND=noninteractive apt-get -q ${extrastring} -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-overwrite" dist-upgrade ;__f=$? ;
   fi
   date ; return ${__f} ;
} ; myupdate 2>&1 | tee -a ~/log/apt-get.upgrade.$( date "+%F" ).log

And dbus-on is a shell script from bgscripts that runs:

dbus-uuidgen | sudo tee /var/lib/dbus/machine-id 1>/dev/null 2>&1

File lightdm-elogind.sh

I'm not sure this script is necessary. It was necessary in the past, and it doesn't hurt anyway, so I still just run it.

#!/bin/sh
# Reference: https://bgstack15.wordpress.com/2019/09/01/devuan-with-lightdm-and-xfce-will-not-let-user-reboot-or-shutdown-from-user-session/
# Startdate: 2019-08-11
# History:
#    2020-04-30 updated
# only for devuan ceres
unset YESSTRING
echo " ${@} " | grep -qE -e " -y " && export YESSTRING="-y"
sudo apt-get install "${YESSTRING}" --no-install-recommends policykit-1 libpam-elogind lightdm lightdm-gtk-greeter
sudo sed -i -r -e '/session\s+optional\s+pam_systemd\.so/s/systemd/elogind/;' /etc/pam.d/lightdm-greeter

File configure-postfix.sh

This is the newest thing I can think of. It sets up postfix to connect to my smtp relay on my network that handles the gmail oauth2 authentication.

#!/bin/sh
# Startdate: 2023-06-26-2 16:40
# Purpose: configure postfix, primarily for new VMs
# Documentation:
#    keep my network details out of the preseed.cfg
set -x
postconf -e 'relayhost = server2.ipa.internal.com'

File send-email-ip-address.sh

Looking at this now, I'm shocked and embarrassed in the complexity I've wrapped around sending an email.

#!/bin/sh
# File: send-mail-ip-address.sh
# Startdate: 2021-05-17 08:59
#
# Purpose: send email message from newly build VM to myself with new hostname and IP address
# Usage:
#    send-mail-ip-address.sh
# Dependencies:
#    bgscripts-core (>=1.5.0)
test -z "${ADDRESS}" && export ADDRESS="${1}" # use ADDRESS environment variable or else use first parameter
test -z "${ADDRESS}" && export ADDRESS=bgstack15@gmail.com
test -z "${SERVER}" && export SERVER="$( hostname --fqdn )"
# Ensure PATH contains /sbin and /usr/sbin for ip and sendmail (called by send)
echo "${PATH}" | grep -qE '^\/usr\/sbin|:\/usr\/sbin' || export PATH="${PATH}:/usr/sbin"
echo "${PATH}" | grep -qE '^\/sbin|:\/sbin'           || export PATH="${PATH}:/sbin"
# Modified and improved from bgscripts framework.sh 2021-02-16a
thisip="$( ip -4 -o a s | awk '$1 !~ /^lo$/ && $2 !~ /^lo$/ && ($1 ~ /^e/ || $2 ~/^e/) {print $3,$4}' | awk -F'/' '{print $1}' | tr -dc '[0-9\.]' )"
# Send message
{
   echo "${SERVER} has IP address ${thisip}."
   echo "system finished build at $( TZ=UTC date "+%FT%TZ" )"
# leave cat INFILE unquoted in case it is inaccessible
} | send -f "root@${SERVER}" -h -s "${SERVER} is ${thisip}" "${ADDRESS}"

Geeqie: add atril as action

The story

I have tried using geeqie as an alternative to Irfanview. It doesn't do everything Irfanview does, but I can at least use mostly native software most of the time.

So, I recently learned that geeqie does have the ability to navigate through paged documents (read: pdf files). But there's no default hotkeys (at least in Devuan GNU+Linux) for these functions, so the user must click through the menu. Instead of hijacking page up/down from their default values (next/previous file, which are also mapped to up/down arrow keys), I decided to make life difficult for myself.

I had seen the menu entries for plugins. And I noticed that my own custom package of Irfanview which follows the XDG standard for desktop menu entries is properly listed. So I read up on how to add an action, so I can open a file in atril, which is a fork of evince back when it was good (read: from the MATE team).

The solution involves placing file /usr/share/geeqie/applications/atril.desktop:

[Desktop Entry]
Type=Application
Version=1.0
Name=Atril Document Viewer
GenericName=Document Viewer
Comment=View multi-page documents
Exec=atril %U
Type=Application
Icon=atril
Categories=Graphics;Viewer;X-Geeqie;
Keywords=MATE;document;viewer;pdf;dvi;ps;xps;tiff;pixbuf;djvu;comics;
MimeType=application/pdf;application/x-bzpdf;application/x-gzpdf;application/x-xzpdf;application/postscript;application/x-bzpostscript;application/x-gzpostscript;image/x-eps;image/x-bzeps;image/x-gzeps;application/x-dvi;application/x-bzdvi;application/x-gzdvi;image/vnd.djvu;image/vnd.djvu+multipage;image/tiff;application/x-cbr;application/x-cbz;application/x-cb7;application/x-cbt;application/vnd.comicbook+zip;application/vnd-comicbook.rar;image/*;application/oxps;application/vnd.ms-xpsdocument;application/epub+zip;

Which I derived by removing the localization (sorry, i18n users) entries from the real .desktop file with a grep statement and also adding the important keywords Graphics, Viewer, and X-Geeqie for good measure.

I think it should have interpreted entries in ~/.local/share/geeqie/applications but I didn't test that.

I'll think I'll add this file to my deployment scripts.

x11vnc to login screen

One of my desktop systems which handles my dvd ripping is now very inconvenient to switch to on my kvm, so I just ssh in and log in to lightdm so my user has permissions to access the DVD drives. I don't get it, and I don't care. I just log in and then all the elogind (read: systemd) baloney works itself out somehow. Forget systemd and elogind and optical drive access.

sudo cp -p /var/run/lightdm/root/:0 /tmp/:0 ; sudo chown bgstack15:admins /tmp/:0
nohup x11vnc -display :0 -forever -auth /tmp/:0 &

And then just connect remmina to $HOST. Port 5900 is implied.

Explanation

Set up the (copy of the) xauth file to be modified by my user. Then run x11vnc with that auth file. Done.

References

  1. server - How to setup x11vnc to access with graphical login screen? - Ask Ubuntu

dnf summarize

I've been working on my Rocky Linux 9 vm kickstart installation process, and due to what is already available in my local Linux mirror server, I used some AlmaLinux sources. So not only did I have to make the symlinks for ln -s epel-9-x86_64 epel-9.2-x86_64 and ln -s 9 9.2 for my copr and epel mirrors, but I also see how many packages come from each source repo.

yum list installed | awk '{a[$NF]++} END{for(i in a){j=i;gsub(/@/,"",j);if(j!="Packages"){print j": "a[i]}}}' | sort

I don't have a cutesy shell function in my profile yet. It took me a while to remember that gsub outputs the number of substitutions. It modifies the third input value directly instead of outputting the changed string.

anaconda: 398
appstream: 297
AppStream: 6
base: 13
copr-bgstack15-stackrpms: 5
epel: 5
examplerpm: 1