Shell trick: use template file

If you want to use a POSIX shell for building files from templates, you can use a nifty trick shared on StackOverflow.

$ eval "cat <<EOF >outputfile
$( cat )
" 2>/dev/null

And can contain shell variables or even command substitution!

$ cat
[domain/$( hostname --domain )]

debug_level = 1
id_provider = ipa
ipa_server = _srv_, $( hostname --domain )
ipa_domain = $( hostname --domain )
ipa_hostname = $( hostname --fqdn )

This is a neat little trick, but should not be a regular substitute for better templating mechanisms like the jinja2 in ansible.

Use virt-install to fully automate the install for Devuan Ceres with preseed, March 2020 edition

I have previously written about using virt-install to automate installing a new Devuan GNU+Linux virtual machine in libvirt/qemu.

This article is the March 2020 edition, that uses devuan_ascii_2.1_amd64_dvd-1.iso which is the latest Devuan Ascii iso available.

With this new iso, a number of changes have been made to the image itself, that will interfere with the default settings of virt-install. The branding of the ISO file was updated, so now isoinfo shows “Devuan” in the name and not Debian.

$ isoinfo -J -i devuan_ascii_2.1_amd64_dvd-1.iso -x /.disk/info
Devuan GNU/Linux 2.1 (ascii) amd64 DVD1 - 2019-12-21 07:24:54 UTC

Virt-manager uses this identifying info to find the initramfs/initrd and kernel (“vmlinuz,” “linux,” or similar) to boot. With the branding change, the Devuan disc changed the name of its initrd for some reason.
I wrote a patch for /usr/share/virt-manager/virtinst/ for package virt-install-1.5.0-7.el7.noarch.

--- /usr/share/virt-manager/virtinst/	2020-02-20 21:06:53.515076802 -0500
+++ /usr/share/virt-manager/virtinst/	2020-02-20 21:41:17.649056883 -0500
@@ -1279,6 +1279,33 @@
         logging.debug("Didn't find any known codename in the URL string")
         return self.os_variant
+class DevuanDistro(DebianDistro):
+    name = "Devuan"
+    urldistro = "devuan"
+    def _is_install_cd(self):
+        # For install CDs
+        if not self._check_info(".disk/info"):
+            return False
+        if self.arch == "x86_64":
+            kernel_initrd_pair = ("linux",
+                                  "initrd.gz")
+        elif self.arch == "i686":
+            kernel_initrd_pair = ("install.386/vmlinuz",
+                                  "install.386/initrd.gz")
+        elif self.arch == "aarch64":
+            kernel_initrd_pair = ("install.a64/vmlinuz",
+                                  "install.a64/initrd.gz")
+        elif self.arch == "ppc64le":
+            kernel_initrd_pair = ("install/vmlinux",
+                                  "install/initrd.gz")
+        elif self.arch == "s390x":
+            kernel_initrd_pair = ("boot/linux_vm", "boot/root.bin")
+        else:
+            kernel_initrd_pair = ("install/vmlinuz", "install/initrd.gz")
+        self._hvm_kernel_paths += [kernel_initrd_pair]
+        self._xen_kernel_paths += [kernel_initrd_pair]
+        return True
 class UbuntuDistro(DebianDistro):

It’s clear that we are defining a number of architectures and the kernel and initrd pairs. I copied and altered the DebianDistro class to use the relevant info. I only tested with the x86_64 arch, but it should be easy for you to read the iso file for your architecture and adjust the other pairs as needed.
No word is out on if the initrd and kernel filenames will be static now in Devuan, so I have not tried to submit a patch upstream, who have refactored now anyway.
And now, here is my one-liner for installing with the following, updated preseed file.

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_ascii_2.1_amd64_dvd-1.iso --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg --extra-args "hostname=${vm} interface=auto" --debug --network type=bridge,source=br0 --noautoconsole

I usually omit the –no-autoconsole so my prompt returns after the VM has installed and rebooted.

Preseed file

# 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
# Purpose: To provide an easy installation for VMs and other systems in the Mersey 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
#    2019-12-29 fix up repos and in-target conclusion stuff
#    2020-02-27 heavy rewrite to use ascii 2.1
# 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_ascii_2.1_amd64_dvd-1.iso --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg --extra-args "hostname=${vm} interface=auto" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=d2-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt
#    syntax for --location
#    example preseed
#    skip next dvd question
#    grub problem caused by consolekit:amd64
#    /mnt/public/Support/Platforms/devuan/fix-virt-manager.txt
#    sudo debconf-get-selections -c /mnt/public/Support/Platforms/devuan/preseed/preseed.cfg
#    on d2-03a: sudo debconf-get-selections --installer
# 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/\/.*$//' )" | 
#    2020-02-24 add the kernel lines: console=ttyS0 console=tty1. Get this to work; use grub.cfg and "linux" line, not "kernel"

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
d-i netcfg/get_domain string
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/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
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 stack123deb
d-i apt-setup/local0/key        string
d-i apt-setup/local0/repository string /
d-i apt-setup/local1/comment    string devuan-deb
d-i apt-setup/local1/key        string
d-i apt-setup/local1/repository string /
d-i apt-setup/local2/comment    string ceres
d-i apt-setup/local2/key        string
d-i apt-setup/local2/repository string ceres main contrib non-free
#d-i apt-setup/local2/key        string
#d-i apt-setup/local2/repository string ceres main contrib non-free
d-i apt-setup/local3/comment    string obsmirror
d-i apt-setup/local3/key        string
d-i apt-setup/local3/repository string /
# 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 \
d-i pkgsel/include string openssh-server

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
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 somethingStrongHere
d-i passwd/root-password-again password somethingStrongHere

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

# 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$85aKM2DkiD5g9r3D$zkBcVES1Bzu.b5dBJxklSGgEJzswZBlVAyc9lUUIzMA2OLRH3PD2ZWE9Q40ztw/32OyDm2nF031hfE4s5LGuG1
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:///

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

d-i preseed/late_command string mkdir -p /target/etc/apt/sources.list.d /target/mnt/bgstack15 /target/mnt/public ; cd /target/etc/apt ; \
   in-target wget -O /Release.gpg ; in-target apt-key add /Release.gpg ; \
   echo "deb ceres main contrib non-free" > sources.list ; \
   in-target wget -O /stack123deb.gpg ; in-target apt-key add /stack123deb.gpg ; \
   echo "deb /" > sources.list.d/stack123deb.list ; \
   echo "deb /" > sources.list.d/devuan-deb.list ; \
   in-target wget -O /Release.key ; in-target apt-key add /Release.key ; \
   echo "deb /" > sources.list.d/home\:bgstack15.list ; \
   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 apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" 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 oddjob-mkhomedir=0.0.1-1 openssh-server p7zip palemoon-ublock-origin parted qemu-guest-agent rsync scite screen spice-vdagent strace sudo tcpdump vim vlc volumeicon-alsa xfce4-terminal xfe xserver-xorg-video-qxl fluxbox-themes-stackrpms xdgmenumaker man logout-manager freeipa-helper palemoon waterfox ; \
   in-target wget -O /usr/local/share/ca-certificates/ && update-ca-certificates || : ; \
   in-target su bgstack15-local -c "sudo /usr/bin/ -d 10 1>/home/bgstack15-local/clone.log 2>&1" ; \
   in-target wget -O /root/ ; in-target sh /root/ ; \
   in-target wget -O /root/ ; in-target sh /root/ ; \
   in-target wget -O /root/ ; in-target sh /root/ ; \
   in-target apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" postfix ; \
   in-target wget -O /root/ ; in-target sh /root/ preseed ; \
   in-target sed -i -r -e '/^\s*linux/s/(\s*console=.{1,7}[0-9])*\s*$/ console=tty0 console=ttyS0/;' /boot/grub/grub.cfg | grep -E '^\s*linux' ; \
   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 install -m0644 /mnt/public/Support/Platforms/devuan/sources.list /etc/apt/sources.list ; \

For some reason, the pkgsel/include answer would not work here. Also, the native answers for custom apt repositories wouldn’t work, but it might have been implementation errors on my side. So I learned the tricky in-target or not in-target logic required to manipulate apt and install my phone book of packages.



My original conversation: Installing Devuan Ascii 2.1 with virt-install / Installation / Dev1 Galaxy Forum

Package for CentOS 7: gnupg2-2.2.18-2.el7

I have previously written about how I use debmirror on CentOS 7 to keep a local copy of the Devuan Ceres package pools.

A recent problem I discovered, is that the recent update of debmirror in CentOS 7 changed the way it uses gpgv to validate the Release and associated files that define an apt repo. The version of gnupg2 in el7 is not sufficient for how debmirror-2.33-1.el7 invokes gpgv, so debmirror always chokes out in the proper apt fashion, because it cannot trust the origin repository.

I took it upon myself to fork the Fedora sources for gnupg2 and related packages. With very minor changes, the packages compiled on el7 just fine! You can go connect to my COmmunity PRoject (copr) and upgrade these packages.

gnupg2.x86_64              2.2.18-2.el7
libassuan.x86_64           2.5.2-2.el7
libgcrypt-stackrpms.x86_64 1.8.5-1.el7
libgpg-error.x86_64        1.33-2.el7
libksba.x86_64             1.3.5-9.el7
npth.x86_64                1.6-2.el7

Using this version of gnupg2 will let debmirror operate correctly on CentOS 7. I seriously doubt many people in the world are running this kind of setup, but in case you are, here you go.

Makefile trick: deplist

I whipped together a snippet for a Makefile I plan on using more in the future.

This target, deplist, searches the entire source tree for my “# Dependencies:” tags, by distribution name, and lists them on standard out.

	@if test -z "$(DISTRO)" ; then echo "Please run \`make deplist\` with DISTRO= one of: `make deplist_opts 2>&1 1>/dev/null | xargs`. Aborted." ; exit 1 ; fi
	@grep -h --exclude='Makefile' --exclude-dir='doc' -A5 -riIE dependencies $(SRCDIR) | \
	   awk -v 'distro=$(DISTRO)' 'tolower($$0) ~ distro {$$1="";$$2="";print}' | \
	   awk 'BEGIN{cmd="xargs -n1"} $$0 !~ /\(/{print $$0 | cmd ; close(cmd);} $$0 ~ /\(/{print;}' | \
	   sort | uniq | sed -r -e 's/$$/$(SEPARATOR)/' | xargs

	@echo "el7" 1>&2
	@echo "devuan" 1>&2

And, of course, probably place these in your .PHONY list because these are not real files to be built.

.PHONY: clean install uninstall list deplist deplist_opts

Every file in the project that has an external dependency should have some comments in this format:

# Dependencies:
#    devuan: python3-tk python3-pil
#    el7: python36 python36-pil

To use this target in a debuild recipe, so that it will dynamically build the dpkg dependency list, use:

	printf "misc:Depends=" > debian/${APPNAME}.substvars
	make -C src deplist DISTRO=devuan SEPARATOR=',' | grep -vE 'make\[[0-9]' >> debian/${APPNAME}.substvars


Inspiration from rpm’s Dynamic Build Dependency feature.

Original research.

Grant multiple privileges with Powershell

I had to learn how to grant local security privileges programmatically. I found a solution (Script Grant “Log on as a service” rights by using PowerShell []) for granting one privilege.

I needed to grant multiple privileges to a service account, so I added a simple array and loop through them. I’m sure it’s inefficient, but for modifying under 10 lines from the original script, I can live with it.

And yes, of course I know that domain group policy can handle this better. This was just a quick-and-dirty fix for testing. And there’s nothing more permanent than temporary!

#written by Ingo Karstein,
#  v1.0, 01/03/2014
#  v1.1 2020-03-04

# References
#    script found at
#    why to run this at all
#    additional priv names

## <--- Configure here if( [string]::IsNullOrEmpty($accountToAdd) ) { Write-Host "no account specified" exit } ## ---> End of Config

$sidstr = $null
try {
	$ntprincipal = new-object System.Security.Principal.NTAccount "$accountToAdd"
	$sid = $ntprincipal.Translate([System.Security.Principal.SecurityIdentifier])
	$sidstr = $sid.Value.ToString()
} catch {
	$sidstr = $null

Write-Host "Account: $($accountToAdd)" -ForegroundColor DarkCyan

if( [string]::IsNullOrEmpty($sidstr) ) {
	Write-Host "Account not found!" -ForegroundColor Red
	exit -1

Write-Host "Account SID: $($sidstr)" -ForegroundColor DarkCyan

$tmp = [System.IO.Path]::GetTempFileName()

Write-Host "Export current Local Security Policy" -ForegroundColor DarkCyan
secedit.exe /export /cfg "$($tmp)" 

$c = Get-Content -Path $tmp 

$RightsToGrant = @( "SeServiceLogonRight", "SeBatchLogonRight", "SeImpersonatePrivilege" )
$currentSetting = ""

ForEach ($thisRight in $RightsToGrant) {
	ForEach ($s in $c) {
		if( $s -like "$thisRight*") {
			$x = $s.split("=",[System.StringSplitOptions]::RemoveEmptyEntries)
			$currentSetting = $x[1].Trim()

	if( $currentSetting -notlike "*$($sidstr)*" ) {
		Write-Host "Modify Setting ""$thisRight""" -ForegroundColor DarkCyan
		if( [string]::IsNullOrEmpty($currentSetting) ) {
			$currentSetting = "*$($sidstr)"
		} else {
			$currentSetting = "*$($sidstr),$($currentSetting)"
		Write-Host "$currentSetting"
		$outfile = @"
[Privilege Rights]
$($thisRight) = $($currentSetting)

		$tmp2 = [System.IO.Path]::GetTempFileName()
		Write-Host "Import new settings to Local Security Policy" -ForegroundColor DarkCyan
		$outfile | Set-Content -Path $tmp2 -Encoding Unicode -Force

		#notepad.exe $tmp2
		Push-Location (Split-Path $tmp2)
		try {
			secedit.exe /configure /db "secedit.sdb" /cfg "$($tmp2)" /areas USER_RIGHTS 
			#write-host "secedit.exe /configure /db ""secedit.sdb"" /cfg ""$($tmp2)"" /areas USER_RIGHTS "
		} finally {	
	} else {
		Write-Host "NO ACTIONS REQUIRED! Account already in ""$thisRight""" -ForegroundColor DarkCyan


Write-Host "Done." -ForegroundColor DarkCyan

Mirror an OBS repository locally — update 1

Previously, I wrote about how to mirror an Open Build Service apt repository. The original script used httrack and some crazy logic.

Due to the unsatisfactory performance of the first version, I rewrote the entire script, twice! I am much more satisfied with my v3 of the script, which is hosting in the same place as before.

So this rewrite is in some ways way simpler than it was before.

Now, the script has a dedicated function for downloading a file, and it only does so if there is no checksum passed, or if the checksum of the local file is not the one passed to the function. How an apt repo works is it has checksums of all of its files in various metadata files, which are the only explicitly named files we download first. We loop through the filenames in the Packages file, and pass those filenames and checksums to the getter function. If the local file has the same checksum, we skip that file.

A flag exists for choosing to download the dpkg sources as well.

And then, for some reason I cannot quite explain, a few files of mine never downloaded and matched the checksums in the Package file. The deb files install, so they’re valid, and I trust my own repo. So I decided to just re-sign all the apt repo files. That is, I rebuild the apt repo entirely and then sign it with my own gpg key for my internal network.

And I finally split out the config into a config file so I can provide an example, and not store my actual data on the Internet!

# File: /etc/installed/
# Location:
# Author: bgstack15
# Startdate: 2020-03-03 08:43
# SPDX-License-Identifier: CC-BY-SA-4.0
# Title: Script that scrapes down OBS site to serve a copy to intranet
# Purpose: save down my OBS site so I can serve it locally
# History:
#    2020-01-05 v1: begin which used httrack
#    2020-02-28 v2: complete rewrite to exclude httrack
#    2020-03-03 v3: complete rewrite to get explicit files and loop through their contents, and rebuild apt repo
# Usage:
#    in a cron job: /etc/cron.d/mirror.cron
#       50	12	*	*	*	root	OBSMIRROR_CONF=/etc/installed/obsmirror.conf /etc/installed/ 1>/dev/null 2>&1
# Reference:
#    /mnt/public/www/repo/devuan-deb/
# Improve:
# Documentation:
#    Download the release key and trust it.
#       curl -s | apt-key add -
#    Use a sources.list.d/ file with contents:
#       deb /
# Dependencies:
#    binaries: wget sed awk
#    user: obsmirror
umask 0002

test -n "${OBSMIRROR_CONF}" && . "${OBSMIRROR_CONF}"
test -z "${logfile}" && logfile="/tmp/var/log/obsmirror/obsmirror.$( date "+%FT%H%M%S" ).log"
test -z "${inurl}" && inurl=""
test -z "${workdir}" && workdir=/tmp/obs
test -z "${thisuser}" && thisuser=obsmirror
# also use include_sources resign_repo gpg_passfile gpg_keyfile DEBUG

get_file() {
   # call: get_file "${tu}" "${md5sum}"
   tf="${workdir}/${tn}" ; tf="$( readlink -m "${tf}" )"
   td="$( dirname "${tf}" )"
   test -d "${td}" || mkdir -p "${td}"
   gotten="skipped   "
   if test -z "${DRYRUN}" ;
      if test -z "${___sum}" || test "$( md5sum "${tf}" 2>/dev/null | awk '{print $1}' )" != "${___sum}" ;
         wget --content-disposition --no-verbose --quiet -O "${tf}" "${___tu}" && gotten=DOWNLOADED
   test -n "${VERBOSE}" && echo "${gotten} ${___tu} -> ${tf}"

test -n "${VERBOSE}" && unset wget_verbose
   test "${DEBUG:-NONE}" = "FULL" && set -x
   echo "logfile=${logfile}"

   # These files define an apt repo
   for word in InRelease Packages Packages.gz Release Release.gpg Release.key Sources Sources.gz ;
      get_file "${inurl}/${word}"

   # loop through named packages and download them
   #for word in $( awk '/Filename:/{print $2}' "${workdir}/Packages" ) ;
   awk '/Filename:|MD5/{print $2}' "${workdir}/Packages" | xargs -n2 | while read word sum
      get_file "$( echo "${word}" | sed -r -e "s@^\.@${inurl}@;" )" "${sum}"
      #echo "a=${a}   b=${b}"

   # loop through dsc, orig.tar.gz, and debian.tar.xz files
   test -n "${include_sources}" && {
      for word in $( sed -n -r -e '/Files:/,/^\s*$/{/^ /p;}' ${workdir}/Sources | awk '{print $NF}' ) ;
         get_file "${inurl}/${word}"

   test -n "${resign_repo}" && {
      # rebuild release files
      cd "${repodir}"
      dpkg-scanpackages -m . > Packages
      gzip -9c < Packages > Packages.gz
      # create the Release file
      PKGS="$(wc -c Packages)"
      PKGS_GZ="$(wc -c Packages.gz)"
      old_headers1="$( grep -E '^(Archive|Codename|Origin|Label|Architectures):' Release )"
      old_headers2="$( grep -E '^(Description):' Release )"
      cat < Release
Date: $(date -u '+%a, %d %b %Y %T %Z')
 $(md5sum Packages  | cut -d" " -f1) $PKGS
 $(md5sum Packages.gz  | cut -d" " -f1) $PKGS_GZ
 $(sha1sum Packages  | cut -d" " -f1) $PKGS
 $(sha1sum Packages.gz  | cut -d" " -f1) $PKGS_GZ
 $(sha256sum Packages | cut -d" " -f1) $PKGS
 $(sha256sum Packages.gz | cut -d" " -f1) $PKGS_GZ
      test -e "${gpg_passfile}" && gpg --batch --yes --passphrase-file "${gpg_passfile}" --pinentry-mode loopback -abs -o Release.gpg Release
      test -e "${gpg_passfile}" && gpg --batch --yes --passphrase-file "${gpg_passfile}" --pinentry-mode loopback --clearsign -o InRelease Release
      # and because we are resigning it, replace Release.key with the one we used
      test -e "${gpg_keyfile}" && cp -p "${gpg_keyfile}" Release.key

   chown -R "${thisuser}:$( id -G "${thisuser}" | awk '{print $1}' )" "${workdir}"
} 2>&1 | tee -a "${logfile}"

Package for devuan: freefilesync

I already have a number of posts about FreeFileSync, an open-source software that provides a nice gui for managing file synchronization task and jobs.

While the project itself is open source, there is a non-free release available to monetary donors that includes a few additional features. The package for Devuan is the GPL release.

You can go check out the build artifacts for the dpkg on my OBS. To install the package, follow the instructions on the download page.

The FreeFileSync project does not publish a source tree. While the source is available in a standard tarball, no diffs are presented between versions. I participate in a group that does track the changes in code between FreeFileSync releases.

What’s really interesting to note is that the build available on the OBS uses gtk3, which has an instability in some of the icon functions. Unfortunately Debian, the upstream of Devuan GNU+Linux, has removed some of the more-stable gtk2 libs because gtk2 is really old.

If you are looking to compile FreeFileSync on Devuan with gtk2 bindings, you need these exact packages which are probably available at the Debian archive site.

  • libwxbase3.0-0v5_3.0.4+dfsg-14_amd64.deb
  • libwxbase3.0-0v5_3.0.4+dfsg-14_i386.deb
  • libwxbase3.0-dev_3.0.4+dfsg-14_amd64.deb
  • libwxbase3.0-dev_3.0.4+dfsg-14_i386.deb
  • libwxgtk3.0-0v5_3.0.4+dfsg-14_amd64.deb
  • libwxgtk3.0-0v5_3.0.4+dfsg-14_i386.deb
  • libwxgtk3.0-dev_3.0.4+dfsg-14_amd64.deb
  • libwxgtk3.0-dev_3.0.4+dfsg-14_i386.deb
  • wx3.0-headers_3.0.4+dfsg-14_all.deb

Package for devuan: xdgmenumaker

After a healthy discussion on the Devuan forum about how to get xdg-compliant menus for non-xdg-compliant window managers, I went and packaged up xdgmenumaker for Devuan!

You can go install this utility as an easy dpkg from my OBS, which includes a few of my own wrapper tools. One is a nice menu entry for rebuilding the fluxbox menus.

The nature of xdg menus is to use the system-wide /usr/share/applications directory and its contents, and also include your local ~/.local/share/applications (or other $XDG_DATA_DIRS/applications/ locations as defined), so using the system-wide xdg fluxbox menu would not be complete. Therefore, I highly recommend adding to your ~/.fluxbox/startup script:

/usr/bin/xdgmenumaker -f fluxbox -i > ~/.fluxbox/xdg-menu &

And adjust your ~/.fluxbox/menu file to include at least these entries:

[include] (.fluxbox/xdg-menu)
#[include] (/etc/xdgmenumaker/fluxbox)

I recommend the above commented line, because in case for some reason your per-user stuff is broken,
The dpkg I build provides a menu entry for reloading it, so you don’t have to go to the command line and run the above command.
screenshot showing "Update xdg menu (fluxbox)" menu entry