Package for Devuan: myautomount


When I read DistroWatch a few weeks ago about Project Trident making it easier to access removable media, I was intrigued. And when I clicked through and read the announcement from Project Trident directly, it was even more fascinating! In the past, on the Devuan mailing lists and irc channels, I have seen references to some community members’ projects for auto-mounting removable media. I had never investigated them though. But this news article from a fascinating distro inspired me to dig around to find their implementation. I finally found it.

Discussion about trident-automount

The utility is written in Go. I have nothing specifically against Go, but I don’t feel like trying to find a compiler and learning how to package up Go applications. But the utility is simple enough that I was able to read it. Additionally, I felt that due to its wrapping around udevadm monitor, that it wasn’t doing anything that could not be done in shell. So I wrote my own version! But more on that in a minute.
The trident-automount utility creates xdg-style .desktop file for each “added” (discovered) attached block device. These .desktop files are placed presumably somewhere the Lumina desktop environment reads some of its menu entries.

Translating to my own implementation

I started off with an almost line-for-line translation to shell+coreutils. Watch the output of udevadm monitor, and generate .desktop files.

Adding extra bits

I decided that it wasn’t enough to add .desktop files; I wanted to re-implement the old-school non-free-OS removable media tray icon. I want to see a little icon appear when a flash drive is plugged in, and that icon provides a menu. Now, due to how autofs works especially with the short time-out as established by the trident-automount example, I don’t need dedicated buttons to umount anything. So my myautomount-trayicon menu entries will execute the xdg “Exec=” field, which is normally going to be the “xdg-open /browse/sdb2.” So yes, it relies on you having definitions for xdg-open to open your preferred file manager. I use xfe and sometimes Thunar (from Xfce).
And then I decided that I didn’t want to depend on GtkStatusIcon which has been “deprecated” for probably a decade by now. So I added to the trayicon python program the ability to use the XApp library! I added a boolean to the script which the admin can set. I did not yet make this a tunable in the makefile. I need to work on that.

Putting it all together

So now, my OBS space has a package you can install in Debian-family distros, including Devuan GNU+Linux! Myautomount does not depend on dbus or systemd. It relies on python3, autofs, and sudo. Go check it out! Or you can use the source code for whatever you want.

Apt show repositories for currently installed packages

Apt makes some things very difficult. If I want to see what repository a package comes from, I need this crazy oneliner.

apt-cache policy $( dpkg -l | awk '$1 ~ /^ii/ {print $2}' ) | awk '/^[^ ]+:$/{gsub(":$","",$0);a=$0;b="";c=""} /\*\*\*/ {b=$2} $1 == "500" {c=$2"/"$3} $1 == "100" {print a,b,c}'
xfonts-encodings 1:1.0.4-2
xfonts-utils 1:7.7+6
xml-core 0.18+nmu1
xmlto 0.0.28-2.1
xorg-sgml-doctools 1:1.11-1
yad 0.40.0-1
yasm 1.3.0-2+b1
zip 3.0-11+b1

This would have been a little easier with yum/dnf, but that’s not the point of today’s article.


And a quick count of packages for each repository:

apt-cache policy $( dpkg -l | awk '$1 ~ /^ii/ {print $2}' ) | awk '/^[^ ]+:$/{gsub(":$","",$0);a=$0;b="";c=""} /\*\*\*/ {b=$2} $1 == "500" {c=$2"/"$3} $1 == "100" {print a,b,c}' | \
   if test -n "${SUMMARIZE}" ;
      awk '$NF ~ /:\/\// {x[$NF]++} END {for(i in x) print i": "x[i]}'
$ SUMMARIZE=1 ~/bin/ 377 1979 2

Ignore the different releases mixed in there together. Let’s pretend I know what I’m doing!

LibreOffice 7 and the Tango Icon set

LibreOffice 7.0.0 has removed the Tango icon set, i.e., the default icon set for the toolbars in the past. Tango icons were from a project with an interesting history. These icons are still available as an extension (referense 2) you can go install.

I really wanted these icons back, so I adapted the deprecated Debian packaging (reference 4) information to build a package for myself. It is now hosted in my OBS repository for Devuan Ceres:
With current default icons:
LibreOffice 7.0.0 Writer with Colibre (default) icons
With the classic icons:
LibreOffice 7.0.0 Writer with Tango icons

To choose which icon style to use, select menu Tools -> Options…. Navigate in the tree to LibreOffice -> View. Select “Icon Style” drop-down and select the value you want.




Package for devuan: powerkit

Powerkit is a neat FLOSS package for monitoring your battery status, and configuring actions associated with batteries and laptop lids.
And now it is available for Devuan ceres in my third-party repository! That first link is the build artifacts. Select this link for the nice download page.


Powerkit is a desktop-independent power manager. You can change settings for how long to wait before locking or suspending or hibernating, and control screen brightness.


I learned with this utility that my one laptop battery is actually treated as two separate batteries! My model uses a 3 cell+3 cell arrangement. I was shocked when I learned that my one invocation of cbatticon was dutifully monitoring just the first-reported battery, the one that drains first when off mains power. But there’s a second battery, as seen by GNU/Linux!
Powerkit status tab
Powerkit settings tab


I have been using cbatticon in my minimal Fluxbox window manager for a while now. I came across this nifty Powerkit utility and skipped it over at first because it requires QT 4.8+. With the recent removal of QT4 packages from Debian (the upstream for Devuan), and my ongoing efforts to maintain some binary packages from Debian’s past for QT4, just so I can install Puddletag, I did not feel like trying to actually build something that depends on QT4. I found, however, that the Arch community builds powerkit with QT5.
Armed with this information, I began my effort to build Powerkit for Devuan. While some of the Devuan target audience may not care about upower or dbus, I am willing to make a few compromises.

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.

Package for devuan: waterfox

In my Internet searching I have not found a Devuan-centric Waterfox classic package. So I decided to bundle it myself!
You can see the build info for it in OBS, as well as use the nice download page to get it for yourself. This build is for Devuan Ceres.

It excludes pulseaudio and dbus, which is why I call it “Devuan centric.” While the Open Build Service only offers Debian builds, the package will install just fine on Devuan ceres. If you are the more paranoid type, you can examine my sources and even build the package yourself on Devuan!


I follow a number of people on the Internet to learn packing tricks for dpkgs, or for how to build Waterfox. I know basically nothing about real software development, but I can build scripts pretty well, especially when I can follow good examples.

Install build dependencies from source files, dpkg and rpm

For a dpkg

cd $packagedir ;
sudo apt-get install ./${package}-build-deps*.deb

Source: ubuntu – Given a debian source package – How do I install the build-deps? – Server Fault

For an rpm

yum-builddep my-package.spec


dnf builddep my-package.spec

fedora – Automatically install build dependencies prior to building an RPM package – Stack Overflow/13228992#13228992

Mirror an OBS deb repository locally


I run an OBS repository for all my packages, and it is available at the main site:

But I wanted to mirror this for myself, so I don’t have to configure all my systems to point outward to get updates. I already host a Devuan ceres mirror for myself, and so mirroring this Open Build System repository is the last step to be self-hosting entirely for all systems except the mirror server.

I first dabbled with debmirror, but it kept wanting to try rsync despite my best configuration, plus it really insists on using the dists/ directory which isn’t used in the OBS deb repo design. So, I researched scraping down a whole site, and I found httrack which exists to serve a local copy of an Internet site. Bingo!

After a few hours of work, here is my solution for mirroring an OBS deb repo locally.


Create a user who will own the files and execute the httrack command, because httrack didn’t want to be run as root. Also, this new user can’t munge other data.

useradd obsmirror

Configure a script (available at gitlab)

# File: /etc/installed/
# License: CC-BY-SA 4.0
# Author: bgstack15
# Startdate: 2020-01-05 18:01
# 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:
# Usage:
#    in a cron job: /etc/cron.d/mirror.cron
#       50	12	*	*	*	root	/etc/installed/ 1>/dev/null 2>&1
# Reference:
#    man 1 httrack
# Improve:
#    use some text file as a list of recently-synced URLs, and if today's URL matches a recent one, then run the httrack with the --update flag. Probably keep a running list forever.
# Documentation:
#    Download the release key and trust it.
#       curl -s | apt-key add -
#    Use a sources.list.d/ file with contents:
#       deb /
# Dependencies:
#    binaries: curl httrack grep head tr sed awk chmod chown find rm ln
#    user: obsmirror

logfile="/var/log/obsmirror/obsmirror.$( date "+%FT%H%M%S" ).log"
   test "${DEBUG:-NONE}" = "FULL" && set -x
   echo "logfile=${logfile}"

   mkdir -p "${workdir}" ; chmod "0711" "${workdir}" ; chown "${thisuser}:$( id -Gn obsmirror )" "${workdir}" 
   cd "${workdir}"
   # get page contents
   step1="$( curl -s -L "${inurl}/all" )"
   # get first listed package
   step2="$( echo "${step1}" | grep --color=always -oE 'href="[a-zA-Z0-9_.+\-]+\.deb"' | head -n1 | grep -oE '".*"' | tr -d '"' )"
   # get full url to a package
   step3="$( curl -s -I "${inurl}/all/${step2}" | awk '/Location:/ {print $2}' )"
   # get directory of the mirror to save down
   step4="$( echo "${step3}" | sed -r -e "s/all\/${step2}//;" -e 's/\s*$//;' )"
   # get domain of full url
   domainname="$( echo "${step3}" | grep -oE '(ht|f)tps?:\/\/[^\/]+\/' | cut -d'/' -f3 )"
   echo "TARGET URL: ${step4}"
   test -z "${DRYRUN}" && {
      # clean workdir of specific domain name in use right now.
      echo su "${thisuser}" -c "rm -rf \"${workdir:-SOMETHING}/${domainname:-SOMETHING}\""
      su "${thisuser}" -c "rm -rf \"${workdir:-SOMETHING}/${domainname:-SOMETHING}\"*"
      # have to skip the orig.tar.gz files because they are large and slow down the sync process significantly.
      echo su "${thisuser}" -c "httrack \"${step4}\" -*.orig.t* -v --mirror --update -s0 -r3 -%e0 \"${workdir}\""
      time su "${thisuser}" -c "httrack ${step4} -*.orig.t* -v --mirror --update -s0 -r3 -%e0 ${workdir}"
   # -s0 ignore robots.txt
   # -r3 only go down 3 links
   # -%e0 follow 0 links to external sites

   # find most recent directory of that level
   levelcount="$(( $( printf "%s" "${inurl}" | tr -dc '/' | wc -c ) - 1 ))"
   subdir="$( find "${workdir}" -mindepth "${levelcount}" -maxdepth "${levelcount}" -type d -name 'Debian_Unstable' -printf '%T@ %p\n' | sort -n -k1 | head -n1 | awk '{print $2}' )"

   # if the work directory actually synced
   if test -n "${subdir}" ;

      printf "%s " "DIRECTORY SIZE:"
      du -sxBM "${subdir:-.}"
      mkdir -p "$( dirname "${outdir}" )"
      # get current target of symlink
      current_target="$( find "${outdir}" -maxdepth 0 -type l -printf '%l\n' )"

      # if the current link is pointing to a different directory than this subdir
      if test "${current_target}" != "${subdir}" ;
         # then replace it with a link to this one
         test -L "${outdir}" && unlink "${outdir}"
         echo ln -sf "${subdir}" "${outdir}"
         ln -sf "${subdir}" "${outdir}"

      echo "ERROR: No subdir found, so cannot update the symlink."

   # disable the index.html with all the httrack comments and original site links
   find "${workdir}" -iname '*index.html' -exec rm {} +
} 2>&1 | tee -a "${logfile}"

And place this in cron!

#       50	12	*	*	*	root	/etc/installed/ 1>/dev/null 2>&1

Explanation of script

So the logic is a little convoluted, because the OBS front page actually redirects downloads to various mirrors where the files are kept. So I needed to learn what the actual site is, and then pull down that whole site.
I couldn’t just use httrack –getfiles because it makes just a flat directory, which breaks the Packages contents’ accuracy to the paths of the package files. But I didn’t want the whole complex directory structure, just the repository structure. So I make a symlink to it in my actual web contents location.

Package for devuan: chicago95-theme-all

Because self-promotion (erm, I mean… learning!) is the purpose of this blog, here is a package I have assembled from a nifty upstream: Chicago95!

You can go get it from the OBS repository now.

screenshot of XFCE with chicago95 theme in use
Screenshot from project

chicago95-theme-all is a metapackage that pulls in all the elements needed to configure your Devuan GNU+Linux system to look like a classic non-free OS from 1995!

$ apt-cache search chicago
chicago95-theme-all - XFCE Windows 95 Total Conversion
chicago95-theme-cursors - Mouse cursor themes for Chicago95
chicago95-theme-doc - Documentation for Chicago95
chicago95-theme-fonts - Fonts for Chicago95
chicago95-theme-greeter - Lightdm webkit greeter for Chicago95
chicago95-theme-gtk - GTK and WM themes for Chicago95
chicago95-theme-icons - Icon themes for Chicago95
chicago95-theme-login-sound - Login sound for Chicago95
chicago95-theme-plymouth - Plymouth theme for Chicago95
$ apt-cache policy chicago95-theme-all
  Installed: (none)
  Candidate: 0.0.1-1+devuan
  Version table:
     0.0.1-1+devuan 500
        500  Packages

Of course, like any other theme, you need to manually change your settings to use the theme. But these packages make it easy to install it so you can control the files with the package manager.


I was helping a family member set up a system to look like a particular non-free OS, and an old one was acceptable, and even preferred. After some research, I discovered a few good places to look for themes:

There were multiple options for the type of theme I wanted, but Chicago95 was the most cohesive and cleanly-installed set.

Customize binary package for Devuan

Devuan bans some packages so I need to host them myself, with the dependencies altered to work in Devuan. Specifically, I wrote this solution for python3-ipalib (python-ipalib originally, back in February 2019).

I wrote a process that helps Devuan join a freeipa domain. It involves manually manipulating the install dependencies for package python3-ipalib. There’s no need to rebuild the package; you can just alter the listed dependencies. This script turns the manual process into a single command.

# File: /mnt/public/www/example/repo/devuan-deb/
# License: CC-BY-SA 4.0
# Author: bgstack15
# Startdate: 2019-11-29 21:28
# Title: Script that Manipulates Dependencies for a Binary Dpkg
# Purpose: Download latest version of python3-ipalib and modify it for internal use
# History:
# Usage:
#    /mnt/public/www/example/repo/devuan-deb/
#    Next steps include running to update the apt repo.
# Reference:
#    Original research
#    dpkg-architecture --list-known
# Improve:
# Dependencies:
#    curl, dpkg-deb, sed, grep

#customize_package "${PACKAGE}" "${DEPENDS_REMOVE}" "${DEPENDS_ADD}" "${SOURCE_DIR}" "${OUT_DIR}"
customize_package() {
   # weaknesses: this might struggle with adding or removing "foobar (>= 0.1.1~bz2)" or other complex version numbers.

   # Learn latest version to fetch
   ___cp_newfile="$( curl -L -s "${___cp_source_dir}" | grep -oE ">${___cp_package}.*<\/a" | sed -r -e 's/^>//;' -e 's/<\/a$//;' )" echo "Discovered filename ${___cp_newfile}" curl -L -s "${___cp_source_dir}/${___cp_newfile}" -o "${___cp_newfile}" 1>/dev/null 2>&1
   mkdir -p "${___cp_tmpdir}"
   dpkg-deb -R "${___cp_newfile}" "${___cp_tmpdir}"

   # Remove the requested dependencies
   echo "${___cp_depends_remove}" | tr ',' '\n' | while read word ;
      if test "${word}" != "" ;
         echo "Removing dependency ${word}"
         sed -i -r -e "s/[:,]\s+${word}[^,]{0,13}(,)?/\1/;" "${___cp_tmpdir}/DEBIAN/control"

   # Add the requested dependencies
   echo "${___cp_depends_add}" | tr ',' '\n' | while read word ;
      if test "${word}" != "" ;
         echo "Adding dependency ${word}"
         sed -i -r -e "/^Depends:/s/$/, ${word}/" "${___cp_tmpdir}/DEBIAN/control"
   # Remove trailing comma, just in case
   sed -i -r -e '/^Depends:/s/,\s*$//;' "${___cp_tmpdir}/DEBIAN/control"

   # Calculate new file name
   ___cp_newfile2="$( echo "${___cp_newfile}" | sed -r -e 's/((_(amd64|i386|all))?\..{1,6})$/+stackrpms\1/;' )"
   dpkg-deb -b "${___cp_tmpdir}" "${___cp_newfile2}"

   # Move to outdir
   test -e "${___cp_newfile2}" && mv "${___cp_newfile2}" "${___cp_out_dir}/"

   # Clean up
   rm -rf "${___cp_tmpdir}" "${___cp_newfile}"

customize_package "${PACKAGE}" "${DEPENDS_REMOVE}" "${DEPENDS_ADD}" "${SOURCE_DIR}" "${OUT_DIR}"

If for some reason new packages come up with different dependencies I need to alter, it will just be a one-liner at the bottom.