Irfanview on Linux


Irfanview is a fantastic image viewer and batch utility for the Windows platform. But did you know that you can run Irfanview on GNU/Linux, and this post will show you how to do that. There is a caveat, though: Irfanview is not open source. It’s freeware. That might turn off some people, but I still choose to use it. It’s unparalleled in the GNU world.
There are several ways to get Irfanview on a GNU/Linux system, and they all use Wine.

Installing Irfanview with Winetricks

Winetricks is a fancy helper script that makes repetitive tasks in wine easier. It has an option built-in for installing Irfanview. It’s a piece of cake.
Make sure you have wine with your package manager.
dnf install wine
Then download winetricks from the link above and run the install irfanview command.
./winetricks -q irfanview
The -q is for unattended install. If you want to adjust the settings, run it without the -q.
Observe that winetricks mentions installing mfc42.dll for you. That is needed for the installer only.

Installing Irfanview with a custom-rolled package

You can choose to install Irfanview by assembling a package from the rpm spec and debian control scripts I’ve assembled at
git pull
What is in the git repository is the source for just the packaging. The actual software source code is downloaded from official web sources upon building the rpm, and upon the installation of the dpkg file. As I said above, the software itself is freeware, so the source is not available for distribution.
A wrapper for rpmbuild and dpkg-deb is provided, as usr/share/irfan/build/pack.
Run ./pack rpm or ./pack deb and the system will build you the type of package you specified, provided you have the rpm-build or dpkg-dev package.
For the rpm, you might need to generate some directories:
mkdir -p ~/rpmbuild/SOURCES ~/rpmbuild/SPECS ~/rpmbuild/RPMS ~/rpmbuild/BUILD ~/rpmbuild/BUILDROOT
In fact, you should run all this, which will download from gitlab for you the package source.
mkdir -p ~/rpmbuild/SOURCES ~/rpmbuild/SPECS ~/rpmbuild/RPMS ~/rpmbuild/BUILD ~/rpmbuild/BUILDROOT
cd ~/rpmbuild/SOURCES
mkdir irfan-4.44-1; cd irfan-4.44-1
git init
git pull
cd irfan-4.44-1
usr/share/irfan/inc/pack rpm

The generated rpm will appear in ~/rpmbuild/RPMS/noarch.
Then you can run dnf install ./irfan-4.44-1.noarch.rpm.

The benefits of rolling your own package

The package provided on gitlab includes a menu shortcut to Irfanview, as well as mimetype defaults for jpg and png. You will be able to see Irfanview in the list of applications when you select a file in the file manager, right click, and select “Open with…” The winetricks option does not include that.


  1. Main irfanview site
  3. Main wine site
  4. Latest winetricks script
  5. Irfan rpm and deb package source

Find which package provides a file – Yum and Apt

Last updated 2019-06-26

Yum-based distros

On Fedora-like systems, the default package manager is yum (or dnf for Fedora 22+). The main way you use it is to install packages and auto-resolve the dependencies.

yum install irfan

Similarly, apt-get on the Debian family of GNU/Linux installs packages with this command.

apt-get install irfan

Now, let’s say you are looking for which package installs a particular file. The command for yum is:

yum provides */filename

If you want to use rpm, that is available too.

rpm -qf /etc/sudoers

Apt-based distros

On apt-based distros (Debian, Devuan, Ubuntu, etc.), you need to install the package apt-file before you can do similar lookup commands.

apt-get install apt-file

Now you can search with:

apt-file search */filename

You can use the lower-level package manager:

dpkg-query -S /usr/share/filename

Nagios plugin to count apache threads


At work I have a misbehaving web server. Sometimes it spawns the maximum number of apache threads (which has a hardcoded maximum of 256, no matter what you configure) and then occupies 100% of the processor. I have decided that the normal nagios checks for the http site and ssh and so on aren’t good enough for monitoring purposes.

So I wrote my own simple nagios check. And then I put it in an rpm for easy deployment.

The nagios check

Here is the code for check_apache_threads, although you can check the latest version at my github page.

# File: /usr/lib64/nagios/plugins/check_apache_threads
# Author:
# Startdate: 2017-01-09 15:53
# Title: Nagios Check for Apache Threads
# Purpose: For a troublesome dmz wordpress host
# Package: nagios-plugins-apache-threads
# History:
# Usage:
# In nagios/nconf, use this checkcommand check command line: $USER1$/check_by_ssh -H $HOSTADDRESS$ -C "$USER1$/check_apache_threads -w $ARG1$ -c $ARG2$"
# Reference: general design /usr/lib64/nagios/plugins/check_sensors
# general design
# case -w
# Improve:
PROGNAME=`basename $0`
PROGPATH=`echo $0 | sed -e 's,[\\/][^\\/][^\\/]*$,,'`
print_usage() {
cat <<EOF
Usage: $PROGNAME -w <thresh_warn> -c <thresh_crit>
print_help() {
print_revision $PROGNAME $REVISION
echo ""
echo ""
echo "This plugin checks for the number of active apache threads."
echo ""
exit $STATE_OK
# Total httpd threads
tot_apache_threads="$( ps -ef | grep -ciE "httpd$" )"
while test -n "${1}";
case "$1" in
exit $STATE_OK
print_revision $PROGNAME $REVISION
exit $STATE_OK
-v | --verbose)
verbosity=$(( verbosity + 1 ))
-w | --warning | -c | --critical)
if [[ -z "$2" || "$2" = -* ]];
# Threshold not provided
echo "$PROGNAME: Option '$1' requires an argument."
elif [[ "$2" = +([0-9]) ]];
# Threshold is a number
# use for a percentage template, from reference 2
#elif [[ "$2" = +([0-9])% ]]; then
# # Threshold is a percentage
# thresh=$(( tot_mem * ${2%\%} / 100 ))
# Threshold is not a number or other valid input
echo "$PROGNAME: Threshold must be an integer."
case "$1" in *-w*) thresh_warn=$thresh;; *) thresh_crit=$thresh;; esac
shift 2
exit $STATE_OK
echo "$PROGNAME: Invalid option '$1'"
if test -z "$thresh_warn" || test -z "$thresh_crit";
# One or both values were unspecified
echo "$PROGNAME: Threshold not set"
elif test "$thresh_crit" -le "$thresh_warn";
echo "$PROGNAME: Critical value must be greater than warning value."
if test "$verbosity" -ge 2;
# Print debugging information
/bin/cat <<EOF
Debugging information:
Warning threshold: $thresh_warn
Critical threshold: $thresh_crit
Verbosity level: $verbosity
Apache threads: ${tot_apache_threads}
if test "${tot_apache_threads}" -gt "${thresh_crit}";
# too many apache threads
echo "APACHE CRITICAL - $tot_apache_threads"
elif test "${tot_apache_threads}" -gt "${thresh_warn}";
echo "APACHE WARNING - $tot_apache_threads"
# fine
echo "APACHE OK - $tot_apache_threads"
exit $STATE_OK

Walking through the code

I included the code above so it gets cached by web crawlers. You should look at the code on github so you get the proper indentations, and line numbers.

So the general format of this script I got from a local file, check_sensor, and Reference 1 below.

The call provides nagios-related definitions, including the exit codes that you see used like $STATE_OK.

The shell script is pretty self-explanatory, really. The variables are initialized and the actual checked value is calculated (ps -ef | grep httpd). About half the script (lines 51-100) is parsing the parameters, which is a nice, simple solution if you have predictable and simplified input (like from nagios) and you don’t do the proper parameter parsing that includes -XvalueofXhere with no space between the flag and the value.

Some sanity checking for threshholds (102-113) and debugging information if given enough verbosity (115-125), and then the actual results are determined in 127-140.

Final thoughts

The hardest part of using this plugin is not writing, using, or deploying the shell script. The hardest part is getting the script to run. To use this check properly, you actually need to write a nagios checkcommand like so:
$USER1$/check_by_ssh -H $HOSTADDRESS$ -C "$USER1$/check_apache_threads -w $ARG1$ -c $ARG2$"
With the arguments as the numbers for your thresholds. I used the values 50 and 150 for warning and critical.

Any questions?



  1. General design
  2. case -w

Moving the application installation directory for bgscripts


My bgscripts package in version 1.1-27 and before was installed in /usr/bgscripts. The more I thought about it, and the more I read the spec for FHS 3.0 (filesystem hierarchy standard) (PDF), the more I realized it should actually be in /usr/share/bgscripts.

Moving the files in the build directory was easy.

Wrapper script

But despite my symlinks in /usr/bin, which were easy to update, I have many, many hard-coded pathname calls of my scripts everywhere. So to mitigate the problem, I wrote a fancy wrapper script for regular scripts, including bup, send, bgscripts.bashrc, rdp, and treesize.

I needed to send myself a message with the various information about what script called the old location. I picked because that’s what it’s for– sending emails. I slapped in a bunch of diagnostic information and wrote a call to the new location.

# Wrapper at legacy location for bgscripts. Sends alert and then continues the process.
while read flocation; do if test -x ${flocation} && test "$( ${flocation} --fcheck )" -ge 20161212; then frameworkscript="${flocation}"; break; fi; done <<EOFLOCATIONS
test -z "${frameworkscript}" && echo "$0: framework not found. Aborted." 1>&2 && exit 4
. ${frameworkscript} || echo "$0: framework did not run properly. Aborted." 1>&2
pwd="$( pwd )"
psout="$( ps -ef )"
parentprocess="$( ps -ef | grep -iE -- "${thisppid}" | grep -viE -- "grep.*-iE.*--" )"
/usr/share/bgscripts/ -hs "bgscripts alert ${server}: ${scriptfile}" <<EOF
----- Description -----
This alert means that script "${scriptfile}" was called, and you need to fix it because /usr/bgscripts/* has been deprecated and will be removed in a future version.
----- Debug info-----
pwd: ${pwd}
Scriptdir: ${scriptdir}
Scriptfile: ${scriptfile}
All parameters: $@
Server: ${server}
Now: ${now}
Thisos: ${thisos}
Thisflavor: ${thisflavor}
Thisppid: ${thisppid}
Parent process: ${parentprocess}
----- Process list -----
/usr/share/bgscripts/${scriptfile} "${@}"

So if something of mine calls /usr/bgscripts/bgscripts.bashrc, this wrapper script will throw an email alert, and then redirect the script call so workflows are not interrupted!

The very first production use of the wrapper script was when I logged onto my test Ubuntu box to conduct a deep-dive search (more on that in the next heading) of scripts that call I got an email right away, saying I had dot-sourced the bashrc script. Looking at the diagnostic info, I was reminded that I tended to hardcode into my ~/.bashrc the call to /usr/bgscripts/bgscripts.bashrc.

I have now updated that to point to /usr/bin/bp, so in the future it will point to wherever I want it to. However, I seriously doubt the location will change now. My package is now FHS 3.0 compliant, and I don’t want to break that.

Deep dive search

So, I wanted to conduct a deep-dive search of all shell scripts (defined by me as everything ending in .sh, because I almost always use the extension) on all systems that refer to, which is going to be the big hangup. So I whipped up this oneliner.
sudo updatedb; locate .sh | grep -iE "\.sh$" | grep -viE "\/usr\/src|\/usr\/share|\/usr\/lib|\/home\/.*\/rpmbuild/|\/home\/work\/.*clean" | xargs grep -iE "framework\.sh"

Now, an reading of my code shows that many of my scripts do a lookup for in various locations, including ./, ~/, /usr/local/bin/, and so on. You can observe this pattern in my wrapper script in this post.

So the serach will catch those, but I will recognize those blocks of code because they are just the filename on a separate line (in a here-doc) and as long as I see the /usr/libexec/bgscripts/ final resting place of framework, I’ll be satisfied.



  1. Filesystem hierarchy standard 3.0
  2. FHS 3.0 in pdf
  3. Here document

Grep odt file


In the GNU/Linux world, you spend a lot of time on the command line. Searching a text file is a piece of cake:
grep -iE "expression" file1

You might even use a gui, and inside that gui you might even use an open-source office suite for all those times that plain text isn’t enough. But what about when you want to search one of those odt files you vaguely remember is some form of xml?

Easy. You use unoconv or odt2txt (look those up in your package manager) and then grep the outputted file. Or you can use the –stdout option.

unoconv -f txt foo.odt

unoconv -f txt --stdout foo.odt | grep -iE "Joe Schmoe"


I first started tackling this problem by figuring out how to access the xml inside. I learned an odt file is zipped, but a tar xf didn’t help. Turns out it was some other compression, that unzip manages.

I also had to actually learn the tiniest bit of perl, as regular GNU grep (and I inferred sed) doesn’t do non-greedy wildcard matching.

So I got this super-complicated one-liner going before I decided to try a different approach and discovered the unoconv and odt2txt applications.

time unzip -p foo.odt content.xml | sed -e 's/\([^n]\)>\n(.*)<\/\1>/\2/;s/<text:h.*?>(.*)<\/text:h>/\1/;' -e 's/<style:(font-face|text-properties).*\/>//g;' | sed -e "s/'/\'/g;s/"/\"/g;s/<text:.*break\/>//g;"




  1. Unzipping an odt file
  2. Perl non-greedy wildcard matching