Tag Archives: unix

Connect FreeBSD to FreeIPA/Red Hat Identity Management

Corporate needs are simple – one ring to rule them all place to get users from. On the open source path there are several ways to achieve that. Alongside ‘plain’ OpenLDAP there is also FreeIPA – which is open source and free version of the Red Hat Identity Management (IDM).


This guide will show you how to make basic FreeIPA install and connect a FreeBSD 13.1-RELEASE system to it.


The Table of Contents for this article looks as follows.

  • Connect FreeBSD to FreeIPA/Red Hat Identity Management
  • FreeIPA
    • FreeIPA Requirements
    • FreeIPA Setup
  • FreeBSD Client
    • FreeBSD Packages
    • FreeBSD Setup
    • FreeIPA/IDM Setup Part
    • Finish Setup with Web Browser in FreeIPA/IDM Page
    • FreeBSD FreeIPA Login Test
  • FreeBSD Jail as FreeIPA/IDM Client
    • Basic FreeBSD Jail Preparations
    • Configure FreeBSD Jail to Connect to FreeIPA/IDM Server
  • Linux FreeIPA/IDM Client
    • FreeIPA/IDM Setup Part
    • Linux FreeIPA/IDM Client Setup


As typical CentOS is dead (yes there is CentOS Stream available but its not a RHEL clone) I have two options here. Rocky Linux and Alma Linux. I will use the latter as it seems more popular and more up to date. In this guide the FreeIPA/IDM server will hosted on the Alma Linux 8.6 system.

To make things easier I installed that Alma Linux 8.6 with single 20GB / root on the /dev/sda1 partition. No separate /boot. No LVM. Just good old plain fucking simple single raw partition for everything. Seems no one does it these days πŸ™‚

[root@idm ~]# lsblk
sda      8:0    0   20G  0 disk
└─sda1   8:1    0   20G  0 part /

FreeIPA Requirements

The minimum hardware requirements for installing FreeIPA server are as follows.

CPU: 2
DNS: fully qualified domain name for FreeIPA
     must be resolvable from DNS server configured in system

For this installation I have used the network.

The FreeIPA/IDM server will get the IP.

The FreeIPA/IDM Linux client rhlike.vercorp.org will get the IP.

The FreeIPA/IDM FreeBSD client fbsd.vercorp.org will get the IP.

The FreeIPA/IDM FreeBSD client fbsdjail.vercorp.org will get the IP.

For lack of better ideas I have used vercorp.org/VERCORP.ORG as domain/realm names and idm.vercorp.org as the FreeIPA/IDM hostname.

Details of FreeIPA/IDM idm.vercorp.org system below.

hostname: idm.vercorp.org
  domain: vercorp.org
   realm: VERCORP.ORG

FreeBSD fbsd.vercorp.org system.

hostname: fbsd.vercorp.org

FreeBSD Jail fbsdjail.vercorp.org system.

hostname: fbsdjail.vercorp.org

If you are curious what is hidden in the IP – then its a typical Alma Linux that I first used to try if the FreeIPA/IDM works at all πŸ™‚

FreeIPA Setup

Because Anaconda is far from being a usable installer – this is how the only enp0s3 interface config looks like after manual intervention.

[root@idm ~]# cat /etc/sysconfig/network-scripts/ifcfg-enp0s3

Before we will go into setup procedures – we will update that Alma Linux system.

[root@idm ~]# yum update -y
[root@idm ~]# reboot

After the reboot we will disable the IPv6 stack for main interface (enp0s3) as FreeIPA installer has some problem with it. We do not need IPv6 here anyway so …

[root@idm ~]# cat << EOF >> /etc/sysctl.conf

Lets set our FreeIPA/IDM hostname if we missed that at the Anaconda installer part. We will also setup the system time zone.

[root@idm ~]# hostnamectl set-hostname idm.vercorp.org

[root@idm ~]# hostnamectl
   Static hostname: idm.vercorp.org
         Icon name: computer-vm
           Chassis: vm
        Machine ID: b8bfb8bcc23147eb9cc7b62c72a09c32
           Boot ID: 06158ef430d9467d959076ab4396314e
    Virtualization: oracle
  Operating System: AlmaLinux 8.6 (Sky Tiger)
       CPE OS Name: cpe:/o:almalinux:almalinux:8::baseos
            Kernel: Linux 4.18.0-372.26.1.el8_6.x86_64
      Architecture: x86-64

[root@idm ~]# timedatectl set-timezone Europe/Warsaw

[root@idm ~]# timedatectl set-local-rtc 0

[root@idm ~]#Β timedatectl
               Local time: Mon 2022-10-17 15:08:28 CEST
           Universal time: Mon 2022-10-17 13:08:28 UTC
                 RTC time: Sat 2022-10-15 00:28:10
                Time zone: Europe/Warsaw (CEST, +0200)
System clock synchronized: yes
              NTP service: inactive
          RTC in local TZ: no

Lets add the system IP and name to the /etc/hosts file now.

[root@idm ~]# echo "$( hostname -i | awk '{print $NF}' )   $( hostname ) $( hostname -s )" >> /etc/hosts

[root@idm ~]# grep idm /etc/hosts   idm.vercorp.org idm

[root@idm ~]# cat /etc/hosts   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6   idm.vercorp.org idm

We need to enable the FreeIPA/IDM module in yum(8).

[root@idm ~]# yum module list idm
Last metadata expiration check: 0:00:31 ago on Tue 18 Oct 2022 01:02:51 PM CEST.
AlmaLinux 8 - AppStream
Name  Stream      Profiles                                  Summary
idm   DL1         adtrust, client, common [d], dns, server  The Red Hat Enterprise Linux Identity Management system module
idm   client [d]  common [d]                                RHEL IdM long term support client module

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled

[root@idm ~]# yum module enable idm:DL1 -y
Last metadata expiration check: 0:01:06 ago on Tue 18 Oct 2022 01:02:51 PM CEST.
Dependencies resolved.
 Package                 Architecture           Version                  Repository              Size
Enabling module streams:
 389-ds                                         1.4
 httpd                                          2.4
 idm                                            DL1
 pki-core                                       10.6
 pki-deps                                       10.6

Transaction Summary


Some additional step needed.

[root@idm ~]# yum distro-sync
Last metadata expiration check: 0:10:07 ago on Mon 17 Oct 2022 03:14:32 PM CEST.
Dependencies resolved.
Nothing to do.

We will now install FreeIPA/IDM with DNS as this setup is the most simplistic one. We focus on FreeBSD part here in that article.

[root@idm ~]# yum install -y bind-utils chrony nc
[root@idm ~]# yum module install idm:DL1/dns -y

One can use the ‘interactive’ installer and answer ‘by hand’ for all the asked questions – but to be honest I prefer to type my command once and make it ‘happen’ altogether without my time wasted.

As you probably guessed – we will use the unattended mode for the FreeIPA/IDM installer.

[root@idm ~]# ipa-server-install \
    --domain vercorp.org \
    --realm VERCORP.ORG \
    --reverse-zone=0.0.10.in-addr.arpa. \
    --no-forwarders \
    --no-ntp \
    --setup-dns \
    --ds-password    [password] \
    --admin-password [password] \

Checking DNS domain 0.0.10.in-addr.arpa., please wait ...

The log file for this installation can be found in /var/log/ipaserver-install.log
This program will set up the IPA Server.
Version 4.9.8

This includes:
  * Configure a stand-alone CA (dogtag) for certificate management
  * Create and configure an instance of Directory Server
  * Create and configure a Kerberos Key Distribution Center (KDC)
  * Configure Apache (httpd)
  * Configure DNS (bind)
  * Configure SID generation
  * Configure the KDC to enable PKINIT

Excluded by options:
  * Configure the NTP client (chronyd)

Warning: skipping DNS resolution of host idm.vercorp.org
Checking DNS domain vercorp.org., please wait ...
Checking DNS domain 0.0.10.in-addr.arpa., please wait ...
Checking DNS domain 0.0.10.in-addr.arpa., please wait ...
Using reverse zone(s) 0.0.10.in-addr.arpa.
Trust is configured but no NetBIOS domain name found, setting it now.

The IPA Master Server will be configured with:
Hostname:       idm.vercorp.org
IP address(es):
Domain name:    vercorp.org
Realm name:     VERCORP.ORG

The CA will be configured with:
Subject DN:   CN=Certificate Authority,O=VERCORP.ORG
Subject base: O=VERCORP.ORG
Chaining:     self-signed

BIND DNS server will be configured to serve IPA domain with:
Forwarders:       No forwarders
Forward policy:   only
Reverse zone(s):  0.0.10.in-addr.arpa.

Disabled p11-kit-proxy
Configuring directory server (dirsrv). Estimated time: 30 seconds
  [1/41]: creating directory server instance
Validate installation settings ...
Create file system structures ...
Perform SELinux labeling ...
Create database backend: dc=vercorp,dc=org ...
Perform post-installation tasks ...
  [2/41]: tune ldbm plugin
  [3/41]: adding default schema
  [4/41]: enabling memberof plugin
  [5/41]: enabling winsync plugin
  [6/41]: configure password logging
  [7/41]: configuring replication version plugin
  [8/41]: enabling IPA enrollment plugin
  [9/41]: configuring uniqueness plugin
  [10/41]: configuring uuid plugin
  [11/41]: configuring modrdn plugin
  [12/41]: configuring DNS plugin
  [13/41]: enabling entryUSN plugin
  [14/41]: configuring lockout plugin
  [15/41]: configuring topology plugin
  [16/41]: creating indices
  [17/41]: enabling referential integrity plugin
  [18/41]: configuring certmap.conf
  [19/41]: configure new location for managed entries
  [20/41]: configure dirsrv ccache and keytab
  [21/41]: enabling SASL mapping fallback
  [22/41]: restarting directory server
  [23/41]: adding sasl mappings to the directory
  [24/41]: adding default layout
  [25/41]: adding delegation layout
  [26/41]: creating container for managed entries
  [27/41]: configuring user private groups
  [28/41]: configuring netgroups from hostgroups
  [29/41]: creating default Sudo bind user
  [30/41]: creating default Auto Member layout
  [31/41]: adding range check plugin
  [32/41]: creating default HBAC rule allow_all
  [33/41]: adding entries for topology management
  [34/41]: initializing group membership
  [35/41]: adding master entry
  [36/41]: initializing domain level
  [37/41]: configuring Posix uid/gid generation
  [38/41]: adding replication acis
  [39/41]: activating sidgen plugin
  [40/41]: activating extdom plugin
  [41/41]: configuring directory to start on boot
Done configuring directory server (dirsrv).
Configuring Kerberos KDC (krb5kdc)
  [1/10]: adding kerberos container to the directory
  [2/10]: configuring KDC
  [3/10]: initialize kerberos container
  [4/10]: adding default ACIs
  [5/10]: creating a keytab for the directory
  [6/10]: creating a keytab for the machine
  [7/10]: adding the password extension to the directory
  [8/10]: creating anonymous principal
  [9/10]: starting the KDC
  [10/10]: configuring KDC to start on boot
Done configuring Kerberos KDC (krb5kdc).
Configuring kadmin
  [1/2]: starting kadmin
  [2/2]: configuring kadmin to start on boot
Done configuring kadmin.
Configuring ipa-custodia
  [1/5]: Making sure custodia container exists
  [2/5]: Generating ipa-custodia config file
  [3/5]: Generating ipa-custodia keys
  [4/5]: starting ipa-custodia
  [5/5]: configuring ipa-custodia to start on boot
Done configuring ipa-custodia.
Configuring certificate server (pki-tomcatd). Estimated time: 3 minutes
  [1/29]: configuring certificate server instance
  [2/29]: stopping certificate server instance to update CS.cfg
  [3/29]: backing up CS.cfg
  [4/29]: Add ipa-pki-wait-running
  [5/29]: secure AJP connector
  [6/29]: reindex attributes
  [7/29]: exporting Dogtag certificate store pin
  [8/29]: disabling nonces
  [9/29]: set up CRL publishing
  [10/29]: enable PKIX certificate path discovery and validation
  [11/29]: authorizing RA to modify profiles
  [12/29]: authorizing RA to manage lightweight CAs
  [13/29]: Ensure lightweight CAs container exists
  [14/29]: Ensuring backward compatibility
  [15/29]: starting certificate server instance
  [16/29]: configure certmonger for renewals
  [17/29]: requesting RA certificate from CA
  [18/29]: publishing the CA certificate
  [19/29]: adding RA agent as a trusted user
  [20/29]: configure certificate renewals
  [21/29]: Configure HTTP to proxy connections
  [22/29]: updating IPA configuration
  [23/29]: enabling CA instance
  [24/29]: importing IPA certificate profiles
  [25/29]: migrating certificate profiles to LDAP
  [26/29]: adding default CA ACL
  [27/29]: adding 'ipa' CA entry
  [28/29]: configuring certmonger renewal for lightweight CAs
  [29/29]: deploying ACME service
Done configuring certificate server (pki-tomcatd).
Configuring directory server (dirsrv)
  [1/3]: configuring TLS for DS instance
  [2/3]: adding CA certificate entry
  [3/3]: restarting directory server
Done configuring directory server (dirsrv).
Configuring ipa-otpd
  [1/2]: starting ipa-otpd
  [2/2]: configuring ipa-otpd to start on boot
Done configuring ipa-otpd.
Configuring the web interface (httpd)
  [1/22]: stopping httpd
  [2/22]: backing up ssl.conf
  [3/22]: disabling nss.conf
  [4/22]: configuring mod_ssl certificate paths
  [5/22]: setting mod_ssl protocol list
  [6/22]: configuring mod_ssl log directory
  [7/22]: disabling mod_ssl OCSP
  [8/22]: adding URL rewriting rules
  [9/22]: configuring httpd
Nothing to do for configure_httpd_wsgi_conf
  [10/22]: setting up httpd keytab
  [11/22]: configuring Gssproxy
  [12/22]: setting up ssl
  [13/22]: configure certmonger for renewals
  [14/22]: publish CA cert
  [15/22]: clean up any existing httpd ccaches
  [16/22]: enable ccache sweep
  [17/22]: configuring SELinux for httpd
  [18/22]: create KDC proxy config
  [19/22]: enable KDC proxy
  [20/22]: starting httpd
  [21/22]: configuring httpd to start on boot
  [22/22]: enabling oddjobd
Done configuring the web interface (httpd).
Configuring Kerberos KDC (krb5kdc)
  [1/1]: installing X509 Certificate for PKINIT
Done configuring Kerberos KDC (krb5kdc).
Applying LDAP updates
Upgrading IPA:. Estimated time: 1 minute 30 seconds
  [1/10]: stopping directory server
  [2/10]: saving configuration
  [3/10]: disabling listeners
  [4/10]: enabling DS global lock
  [5/10]: disabling Schema Compat
  [6/10]: starting directory server
  [7/10]: upgrading server
  [8/10]: stopping directory server
  [9/10]: restoring configuration
  [10/10]: starting directory server
Restarting the KDC
dnssec-validation yes
Configuring DNS (named)
  [1/12]: generating rndc key file
  [2/12]: adding DNS container
  [3/12]: setting up our zone
  [4/12]: setting up reverse zone
  [5/12]: setting up our own record
  [6/12]: setting up records for other masters
  [7/12]: adding NS record to the zones
  [8/12]: setting up kerberos principal
  [9/12]: setting up named.conf
created new /etc/named.conf
created named user config '/etc/named/ipa-ext.conf'
created named user config '/etc/named/ipa-options-ext.conf'
created named user config '/etc/named/ipa-logging-ext.conf'
  [10/12]: setting up server configuration
  [11/12]: configuring named to start on boot
  [12/12]: changing resolv.conf to point to ourselves
Done configuring DNS (named).
Restarting the web server to pick up resolv.conf changes
Configuring DNS key synchronization service (ipa-dnskeysyncd)
  [1/7]: checking status
  [2/7]: setting up bind-dyndb-ldap working directory
  [3/7]: setting up kerberos principal
  [4/7]: setting up SoftHSM
  [5/7]: adding DNSSEC containers
  [6/7]: creating replica keys
  [7/7]: configuring ipa-dnskeysyncd to start on boot
Done configuring DNS key synchronization service (ipa-dnskeysyncd).
Restarting ipa-dnskeysyncd
Restarting named
Updating DNS system records
Configuring SID generation
  [1/8]: creating samba domain object
  [2/8]: adding admin(group) SIDs
  [3/8]: adding RID bases
  [4/8]: updating Kerberos config
'dns_lookup_kdc' already set to 'true', nothing to do.
  [5/8]: activating sidgen task
  [6/8]: restarting Directory Server to take MS PAC and LDAP plugins changes into account
  [7/8]: adding fallback group
  [8/8]: adding SIDs to existing users and groups
This step may take considerable amount of time, please wait..
Configuring client side components
This program will set up IPA client.
Version 4.9.8

Using existing certificate '/etc/ipa/ca.crt'.
Client hostname: idm.vercorp.org
DNS Domain: vercorp.org
IPA Server: idm.vercorp.org
BaseDN: dc=vercorp,dc=org

Configured /etc/sssd/sssd.conf
Systemwide CA database updated.
Adding SSH public key from /etc/ssh/ssh_host_ed25519_key.pub
Adding SSH public key from /etc/ssh/ssh_host_ecdsa_key.pub
Adding SSH public key from /etc/ssh/ssh_host_rsa_key.pub
SSSD enabled
Configured /etc/openldap/ldap.conf
Configured /etc/ssh/ssh_config
Configured /etc/ssh/sshd_config
Configuring vercorp.org as NIS domain.
Client configuration complete.
The ipa-client-install command was successful

Setup complete

Next steps:
  1. You must make sure these network ports are open:
    TCP Ports:
      * 80, 443: HTTP/HTTPS
      * 389, 636: LDAP/LDAPS
      * 88, 464: kerberos
      * 53: bind
    UDP Ports:
      * 88, 464: kerberos
      * 53: bind

  2. You can now obtain a kerberos ticket using the command: 'kinit admin'
     This ticket will allow you to use the IPA tools (e.g., ipa user-add)
     and the web user interface.
  3. Kerberos requires time synchronization between clients
     and servers for correct operation. You should consider enabling chronyd.

Be sure to back up the CA certificates stored in /root/cacert.p12
These files are required to create replicas. The password for these
files is the Directory Manager password
The ipa-server-install command was successful
[root@idm ~]#

Seems that all went well and now we have our FreeIPA/IDM installed.

Lets check several things.

[root@idm ~]# ipactl status
Directory Service: RUNNING
krb5kdc Service: RUNNING
kadmin Service: RUNNING
named Service: RUNNING
httpd Service: RUNNING
ipa-custodia Service: RUNNING
pki-tomcatd Service: RUNNING
ipa-otpd Service: RUNNING
ipa-dnskeysyncd Service: RUNNING
ipa: INFO: The ipactl command was successful

[root@idm ~]# systemctl list-unit-files | grep ipa | grep service
ipa-ccache-sweep.service                   disabled
ipa-custodia.service                       disabled
ipa-dnskeysyncd.service                    disabled
ipa-healthcheck.service                    disabled
ipa-ods-exporter.service                   disabled
ipa-otpd@.service                          static
ipa.service                                enabled

Seems to be installed and working.

What about the /etc/sssd/sssd.conf config.

[root@idm ~]# cat /etc/sssd/sssd.conf

id_provider = ipa
ipa_server_mode = True
ipa_server = idm.vercorp.org
ipa_domain = vercorp.org
ipa_hostname = idm.vercorp.org
auth_provider = ipa
chpass_provider = ipa
access_provider = ipa
cache_credentials = True
ldap_tls_cacert = /etc/ipa/ca.crt
krb5_store_password_if_offline = True
services = nss, pam, ifp, ssh, sudo

domains = vercorp.org
homedir_substring = /home
memcache_timeout = 600






allowed_uids = ipaapi, root


There is also /etc/ssh/ssh_config.d/04-ipa.conf file …

[root@idm ~]# cat /etc/ssh/ssh_config.d/04-ipa.conf
# IPA-related configuration changes to ssh_config
PubkeyAuthentication yes
GlobalKnownHostsFile /var/lib/sss/pubconf/known_hosts
#VerifyHostKeyDNS yes

# assumes that if a user does not have shell (/sbin/nologin),
# this will return nonzero exit code and proxy command will be ignored
Match exec true
  ProxyCommand /usr/bin/sss_ssh_knownhostsproxy -p %p %h

For some reason we need to manually enable and start the Apache HTTP server.

[root@idm ~]# systemctl enable --now httpd

You can now access the FreeIPA/IDM at your browser on the http://idm.vercorp.org address. If you use the IP then you will be redirected to the http://idm.vercorp.org address so make sure you have added that host to your local /etc/hosts file.



On the second screen you will see that I have already created the vermaden user.

FreeBSD Client

We will get straight into the point. After having FreeBSD 13.1-RELEASE installed in the most ‘default’ way in the bsdinstall(8) installer – the Auto ZFS road – we will now fetch the up to date FreeBSD Ports tree with portsnap(8) tool.

This is the main /etc/rc.conf config file.

# cat /etc/rc.conf
ifconfig_vtnet0="inet netmask"

FreeBSD Packages

We need to have FreeBSD Ports tree.

# portsnap auto

Lets check what is the current default SAMBA version on FreeBSD.

# grep -i samba /usr/ports/Mk/*default*
SAMBA_DEFAULT?=         4.12

To omit a lot of pointless compilation I will first install all precompiled packages – that would also install needed dependencies. Then we will rebuild just the several needed packages.

# pkg install krb5 sudo cyrus-sasl cyrus-sasl-gssapi pam_mkhomedir openldap26-client samba412

Settings in the /etc/make.conf file.

# cat /etc/make.conf
# USE /usr/ports/obj PLACE

WITH_GSSAPI=         yes

Lets configure the needed ports.

# \
for I in /usr/ports/security/sudo \
         /usr/ports/security/sssd \
         /usr/ports/security/krb5 \
         /usr/ports/security/cyrus-sasl2-gssapi \
         /usr/ports/security/pam_mkhomedir \
  make -C ${I} rmconfig

# \
for I in /usr/ports/security/sudo \
         /usr/ports/security/sssd \
         /usr/ports/security/krb5 \
         /usr/ports/security/cyrus-sasl2-gssapi \
         /usr/ports/security/pam_mkhomedir \
  make -C ${I} config-recursive

The curses(3X) selection will look more or less like these below.

=> security/sudo | OPTIONS___________________________________________________________________________
[x] AUDIT              Enable BSM audit support
[ ] DISABLE_AUTH       Do not require authentication by default
[ ] DISABLE_ROOT_SUDO  Do not allow root to run sudo
[ ] DOCS               Build and/or install documentation
[ ] EXAMPLES           Build and/or install examples
[ ] INSULTS            Enable insults on failures
[x] LDAP               LDAP protocol support
[ ] NLS                Native Language Support
[ ] NOARGS_SHELL       Run a shell if no arguments are given
[ ] OPIE               Enable one-time passwords (no PAM support)
[ ] PAM                Pluggable authentication module support
[ ] PYTHON             Enable python plugin support
[x] SSSD               Enable SSSD backend support.
=> security/sudo | Kerberos 5 Authentication (no PAM support)
( ) GSSAPI_BASE        GSSAPI support via base system (needs Kerberos)
( ) GSSAPI_HEIMDAL     GSSAPI support via security/heimdal
(*) GSSAPI_MIT         GSSAPI support via security/krb5

=> security/sssd | OPTIONS___________________________________________________________________________
[ ] DOCS  Build and/or install documentation
[x] SMB   Install IPA and AD providers (requires Samba4)

=> security/cyrus-sasl2-gssapi | OPTIONS_____________________________________________________________
( ) GSSAPI_BASE     GSSAPI support via base system (needs Kerberos)
( ) GSSAPI_HEIMDAL  GSSAPI support via security/heimdal
(*) GSSAPI_MIT      GSSAPI support via security/krb5

=> net/openldap26-client | OPTIONS___________________________________________________________________
[ ] DEBUG   Build with debugging support
[ ] DOCS    Build and/or install documentation
[ ] FETCH   Enable fetch(3) support
[x] GSSAPI  With GSSAPI support

=> security/krb5 | OPTIONS___________________________________________________________________________
[ ] DNS_FOR_REALM  Enable DNS lookups for Kerberos realm names
[ ] EXAMPLES       Build and/or install examples
[x] KRB5_HTML      Install krb5 HTML documentation
[x] KRB5_PDF       Install krb5 PDF documentation
[x] LDAP           LDAP protocol support
[ ] LMDB           OpenLDAP Lightning Memory-Mapped Database support
[ ] NLS            Native Language Support
=> security/krb5 | Command Line Editing for kadmin and ktutil
(*) READLINE       Command line editing via libreadline
( ) LIBEDIT        Command line editing via libedit

We can now check what options have been saved.

# cat /var/db/ports/security_sudo-sssd/options

# cat /var/db/ports/security_sssd/options

# cat /var/db/ports/security_cyrus-sasl2/options

# cat /var/db/ports/net_openldap26-client/options

# cat /var/db/ports/security_krb5/options
# This file is auto-generated by 'make config'.
# Options for krb5-1.20

… and build them.

# \
for I in /usr/ports/security/sudo \
         /usr/ports/security/sssd \
         /usr/ports/security/cyrus-sasl2-gssapi \
         /usr/ports/security/pam_mkhomedir \
         /usr/ports/net/openldap26-client \
  make -C ${I} build

… unsinstall them and create their packages.

# \
for I in /usr/ports/security/sudo \
         /usr/ports/security/sssd \
         /usr/ports/security/cyrus-sasl2-gssapi \
         /usr/ports/security/pam_mkhomedir \
         /usr/ports/net/openldap26-client \
  make -C ${I} deinstall package

After some time we have our built packages.

# find /usr/ports/obj/ -name \*.pkg

In the future I need to add some short guide to build them regularly with Synth or Poudriere πŸ™‚

Now we need to install these packages in quite nontypical way. One by one – in specified order. It will not be needed it we would have a separate additional pkg(8) repository with Poudriere build packages.

Our packages:

# ls -1 *.pkg

… and their install process.

# pkg install -y c-ares

# pkg add sssd-smb4-1.16.5_6.pkg

# pkg install -y cyrus-sasl-gssapi-2.1.28.pkg
New packages to be INSTALLED:
        cyrus-sasl: 2.1.28
        cyrus-sasl-gssapi: 2.1.28
        krb5: 1.20

# pkg delete -f -y krb5
Installed packages to be REMOVED:
        krb5: 1.20

# pkg add krb5-1.20.pkg

# pkg install -y sssd

# pkg add sudo-sssd-1.9.11p3.pkg

# pkg delete -f -y sssd
Installed packages to be REMOVED:
        sssd: 1.16.5_6

# pkg install ding-libs ldb21 nspr nss pcre samba412

# pkg add sssd-smb4-1.16.5_6.pkg

FreeBSD Setup

Create needed dirs.

# mkdir -p \
    /usr/local/etc/ipa \
    /var/log/sssd \
    /var/run/sss/private \

Set system hostname.

# hostname fbsd.vercorp.org

# hostname

Fetch the FreeIPA/IDM certificate.

# fetch -o /usr/local/etc/ipa/ca.crt

FreeIPA/IDM Setup Part

We need to execute several instructions on the FreeIPA/IDM to connect FreeBSD client to it.

Its adding the A and PTR records in DNS for the address and adding the fbsd.vercorp.org host.

We also need to generate the key for our fbsd.vercorp.org system.

[root@idm ~]# kinit admin
Password for admin@VERCORP.ORG:

[root@idm ~]# ipa dnsrecord-add vercorp.org fbsd --a-rec= --a-create-reverse
  Record name: fbsd
  A record:

[root@idm ~]# ipa host-add fbsd.vercorp.org
Added host "fbsd.vercorp.org"
  Host name: fbsd.vercorp.org
  Principal name: host/fbsd.vercorp.org@VERCORP.ORG
  Principal alias: host/fbsd.vercorp.org@VERCORP.ORG
  Password: False
  Keytab: False
  Managed by: fbsd.vercorp.org

[root@idm ~]# ipa-getkeytab -s idm.vercorp.org -p host/fbsd.vercorp.org@VERCORP.ORG -k /root/fbsd.vercorp.org.keytab
Keytab successfully retrieved and stored in: /root/fbsd.vercorp.org.keytab

Now we need to get ‘our’ key from FreeIPA/IDM server … along with proper /etc/hosts file.

# scp root@ /usr/local/etc/ipa/krb5.keytab

# cat << EOF > /etc/hosts
::1              localhost localhost.my.domain        localhost localhost.my.domain        idm.vercorp.org  idm        fbsd.vercorp.org fbsd

Now the /usr/local/etc/openldap/ldap.conf file.

# cat << EOF > /usr/local/etc/openldap/ldap.conf
BASE        dc=org,dc=vercorp
URI         ldap://idm.vercorp.org/
#DEREF      never
ssl         start_tls
TLS_CACERT  /usr/local/etc/ipa/ca.crt

… and /etc/krb5.conf file.

# cat << EOF > /etc/krb5.conf
  default_realm = VERCORP.ORG
  default_keytab_name = FILE:/usr/local/etc/ipa/krb5.keytab
  default_tkt_enctypes = aes256-cts des-cbc-crc aes128-cts arcfour-hmac
  default_tgs_enctypes = aes256-cts des-cbc-crc aes128-cts arcfour-hmac
  dns_lookup_realm = false
  dns_lookup_kdc = false
  rdns = false
  ticket_lifetime = 24h
  forwardable = yes

    kdc = idm.vercorp.org:88
    master_kdc = idm.vercorp.org:88
    admin_server = idm.vercorp.org:749
    default_domain = vercorp.org
    pkinit_anchors = FILE:/usr/local/etc/ipa/ca.crt

  .vercorp.org = VERCORP.ORG
  vercorp.org = VERCORP.ORG

  kdc = FILE:/var/log/krb5/krb5kdc.log
  admin_server = FILE:/var/log/krb5/kadmin.log
  kadmin_local = FILE:/var/log/krb5/kadmin_local.log
  default = FILE:/var/log/krb5/krb5lib.log

… and /usr/local/etc/sssd/sssd.conf file.

# cat << EOF > /usr/local/etc/sssd/sssd.conf

# debug_level = 9
cache_credentials = True
krb5_store_password_if_offline = True
krb5_realm = VERCORP.ORG
ipa_domain = vercorp.org
id_provider = ipa
auth_provider = ipa
access_provider = ipa
ipa_hostname = fbsd.vercorp.org
chpass_provider = ipa
ipa_server = _srv_, idm.vercorp.org
ldap_tls_cacert = /usr/local/etc/ipa/ca.crt
krb5_keytab = /usr/local/etc/ipa/krb5.keytab

services = nss, pam, ssh, sudo
config_file_version = 2
domains = vercorp.org

filter_users = root,toor
homedir_substring = /usr/home/%u


# debug_level = 0x3ff0


# chmod 600 /usr/local/etc/sssd/sssd.conf

FreeBSD have user account under /usr/home to make sure /home also points there.

# ln -s /usr/home /home

The automatic startup of sssd(8) daemon (not to confuse with sshd(8)) needs to be also configured.

# sysrc sssd_enable=YES
# service sssd start

We also need to configure /etc/nsswitch.conf file.

# cp /etc/nsswitch.conf /etc/nsswitch.conf.BCK

# diff -u /etc/nsswitch.conf.BCK /etc/nsswitch.conf
--- /etc/nsswitch.conf.BCK      2022-10-24 20:10:09.163251000 +0200
+++ /etc/nsswitch.conf  2022-10-24 20:10:57.207406000 +0200
@@ -2,15 +2,17 @@
 # nsswitch.conf(5) - name service switch configuration file
 # $FreeBSD$
-group: compat
+group: files sss
 group_compat: nis
 hosts: files dns
-netgroup: compat
+# netgroup: compat
 networks: files
-passwd: compat
+passwd: files sss
 passwd_compat: nis
 shells: files
 services: compat
 services_compat: nis
 protocols: files
 rpc: files
+sudoers: sss files
+netgroup: files

The final /etc/nsswitch.conf file looks as follows.

# cat /etc/nsswitch.conf
# nsswitch.conf(5) - name service switch configuration file
# $FreeBSD$
group: files sss
group_compat: nis
hosts: files dns
# netgroup: compat
networks: files
passwd: files sss
passwd_compat: nis
shells: files
services: compat
services_compat: nis
protocols: files
rpc: files
sudoers: sss files
netgroup: files

Now the /etc/pam.d/system file.

# cp /etc/pam.d/system /root/etc---pam.d---system.BCK

# diff -u  /root/etc---pam.d---system.BCK /etc/pam.d/system
--- /root/etc---pam.d---system.BCK      2022-10-24 20:13:05.546657000 +0200
+++ /etc/pam.d/system   2022-10-24 20:16:36.722666000 +0200
@@ -7,19 +7,23 @@
 # auth
 auth           sufficient      pam_opie.so             no_warn no_fake_prompts
 auth           requisite       pam_opieaccess.so       no_warn allow_local
-#auth          sufficient      pam_krb5.so             no_warn try_first_pass
+auth           sufficient      pam_krb5.so             no_warn try_first_pass
 #auth          sufficient      pam_ssh.so              no_warn try_first_pass
+auth           sufficient      /usr/local/lib/pam_sss.so       use_first_pass
 auth           required        pam_unix.so             no_warn try_first_pass nullok

 # account
 #account       required        pam_krb5.so
 account                required        pam_login_access.so
 account                required        pam_unix.so
+account                required        /usr/local/lib/pam_sss.so       ignore_unknown_user ignore_authinfo_unavail

 # session
 #session       optional        pam_ssh.so              want_agent
 session                required        pam_lastlog.so          no_fail
+session                required        /usr/local/lib/pam_mkhomedir.so mode=0700

 # password
 #password      sufficient      pam_krb5.so             no_warn try_first_pass
+password       sufficient      /usr/local/lib/pam_sss.so       use_authtok
 password       required        pam_unix.so             no_warn try_first_pass

The final /etc/pam.d/system file looks as follows.

# cat /etc/pam.d/system
# $FreeBSD$
# System-wide defaults

# auth
auth            sufficient      pam_opie.so             no_warn no_fake_prompts
auth            requisite       pam_opieaccess.so       no_warn allow_local
auth            sufficient      pam_krb5.so             no_warn try_first_pass
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
auth            sufficient      /usr/local/lib/pam_sss.so       use_first_pass
auth            required        pam_unix.so             no_warn try_first_pass nullok

# account
#account        required        pam_krb5.so
account         required        pam_login_access.so
account         required        pam_unix.so
account         required        /usr/local/lib/pam_sss.so       ignore_unknown_user ignore_authinfo_unavail

# session
#session        optional        pam_ssh.so              want_agent
session         required        pam_lastlog.so          no_fail
session         required        /usr/local/lib/pam_mkhomedir.so mode=0700

# password
#password       sufficient      pam_krb5.so             no_warn try_first_pass
password        sufficient      /usr/local/lib/pam_sss.so       use_authtok
password        required        pam_unix.so             no_warn try_first_pass

Now its time for /etc/pam.d/sshd file.

# cp /etc/pam.d/sshd /root/etc---pam.d---sshd.BCK

# diff -u /root/etc---pam.d---sshd.BCK /etc/pam.d/sshd
--- /root/etc---pam.d---sshd.BCK        2022-10-24 20:17:34.063630000 +0200
+++ /etc/pam.d/sshd     2022-10-24 20:19:16.165810000 +0200
@@ -7,8 +7,9 @@
 # auth
 auth           sufficient      pam_opie.so             no_warn no_fake_prompts
 auth           requisite       pam_opieaccess.so       no_warn allow_local
-#auth          sufficient      pam_krb5.so             no_warn try_first_pass
+auth           sufficient      pam_krb5.so             no_warn try_first_pass
 #auth          sufficient      pam_ssh.so              no_warn try_first_pass
+auth           sufficient      /usr/local/lib/pam_sss.so       use_first_pass
 auth           required        pam_unix.so             no_warn try_first_pass

 # account
@@ -16,11 +17,14 @@
 #account       required        pam_krb5.so
 account                required        pam_login_access.so
 account                required        pam_unix.so
+account                required        /usr/local/lib/pam_sss.so       ignore_unknown_user ignore_authinfo_unavail

 # session
 #session       optional        pam_ssh.so              want_agent
 session                required        pam_permit.so
+session                required        /usr/local/lib/pam_mkhomedir.so mode=0700

 # password
 #password      sufficient      pam_krb5.so             no_warn try_first_pass
+password       sufficient      /usr/local/lib/pam_sss.so       use_authtok
 password       required        pam_unix.so             no_warn try_first_pass

Final /etc/pam.d/sshd file below.

# cat /etc/pam.d/sshd
# $FreeBSD$
# PAM configuration for the "sshd" service

# auth
auth            sufficient      pam_opie.so             no_warn no_fake_prompts
auth            requisite       pam_opieaccess.so       no_warn allow_local
auth            sufficient      pam_krb5.so             no_warn try_first_pass
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
auth            sufficient      /usr/local/lib/pam_sss.so       use_first_pass
auth            required        pam_unix.so             no_warn try_first_pass

# account
account         required        pam_nologin.so
#account        required        pam_krb5.so
account         required        pam_login_access.so
account         required        pam_unix.so
account         required        /usr/local/lib/pam_sss.so       ignore_unknown_user ignore_authinfo_unavail

# session
#session        optional        pam_ssh.so              want_agent
session         required        pam_permit.so
session         required        /usr/local/lib/pam_mkhomedir.so mode=0700

# password
#password       sufficient      pam_krb5.so             no_warn try_first_pass
password        sufficient      /usr/local/lib/pam_sss.so       use_authtok
password        required        pam_unix.so             no_warn try_first_pass

Small modification in the /etc/ssh/ssh_config and /etc/ssh/sshd_config files.

# cat << EOF >> /etc/ssh/ssh_config
GSSAPIAuthentication yes

# cat << EOF >> /etc/ssh/sshd_config
GSSAPIAuthentication yes
UsePAM yes

Finish Setup with Web Browser in FreeIPA/IDM Page

Visit the https://idm.vercorp.org/ipa/ui/#/e/hbacrule/details/freebsd page.

Next create the HBAC Rule named freebsd as showed below.




… and the Sudo Rule named freebsd name.




FreeBSD FreeIPA Login Test

After all these time consuming and pointless instructions we can now finally try to login to our FreeBSD client.

% ssh -l vermaden
(vermaden@ Password:
Last login: Mon Oct 24 21:06:36 2022 from
FreeBSD 13.1-RELEASE releng/13.1-n250148-fc952ac2212 GENERIC

Welcome to FreeBSD!

Release Notes, Errata: https://www.FreeBSD.org/releases/
Security Advisories:   https://www.FreeBSD.org/security/
FreeBSD Handbook:      https://www.FreeBSD.org/handbook/
FreeBSD FAQ:           https://www.FreeBSD.org/faq/
Questions List: https://lists.FreeBSD.org/mailman/listinfo/freebsd-questions/
FreeBSD Forums:        https://forums.FreeBSD.org/

Documents installed with the system are in the /usr/local/share/doc/freebsd/
directory, or can be installed later with:  pkg install en-freebsd-doc
For other languages, replace "en" with a language code like de or fr.

Show the version of FreeBSD installed:  freebsd-version ; uname -a
Please include that output and any error messages when posting questions.
Introduction to manual pages:  man man
FreeBSD directory layout:      man hier

To change this login announcement, see motd(5).
You can upload the dmesg of your system to help developers get an overview of commonly
used hardware and peripherals for FreeBSD. Use the curl package to upload it like this:
curl -v -d "nickname=$USER" -d "description=FreeBSD/$(uname -m) on \
$(kenv smbios.system.maker) $(kenv smbios.system.product)" -d "do=addd" \
--data-urlencode 'dmesg@/var/run/dmesg.boot' http://dmesgd.nycbug.org/index.cgi

vermaden@fbsd:~ $ :> ~/.hushlogin

vermaden@fbsd:~ $ id
uid=1408200003(vermaden) gid=1408200000(admins) groups=1408200000(admins)

vermaden@fbsd:~ $ pwd

vermaden@fbsd:~ $ grep vermaden /etc/passwd /etc/group
vermaden@fbsd:~ $

vermaden@fbsd:~ $ getent passwd vermaden
vermaden:*:1408200003:1408200000:vermaden vermaden:/home/vermaden:/bin/sh

vermaden@fbsd:~ $ sudo su -
Password for vermaden@VERCORP.ORG:

root@fbsd:~ # logout

vermaden@fbsd:~ $ sudo -i

root@fbsd:~ #

Strange … seems to work properly πŸ™‚

FreeBSD Jail as FreeIPA/IDM Client

As ‘full’ FreeBSD system is able to connect to the FreeIPA/IDM server we will not configure FreeBSD Jail to do the same.

The FreeIPA/IDM FreeBSD client fbsdjail.vercorp.orgwill get the IP.

Basic FreeBSD Jail Preparations

Lets setup the Jail for a start.

# mkdir -p /jail/fbsdjail /jail/BASE

# cd /jail/fbsdjail

# fetch -o /jail/BASE/13.1-RELEASE-base.txz https://download.freebsd.org/ftp/releases/amd64/13.1-RELEASE/base.txz

# tar --unlink -xvf ../BASE/13.1-RELEASE-base.txz

# cat << EOF > /etc/jail.conf
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_${name}_console.log";
  host.hostname = ${name};
  path = /jail/${name};

  fbsdjail {
    ip4.addr =;
    host.hostname = fbsdjail.vercorp.org;
    interface = wlan0;

# cat /etc/resolv.conf | tee /jail/fbsdjail/etc/resolv.conf

# echo fbsdjail.vercorp.org fbsdjail | tee -a /etc/hosts | tee -a /jail/fbsdjail/etc/hosts

# cat /etc/hosts /jail/fbsdjail/etc/hosts fbsdjail.vercorp.org fbsdjail fbsdjail.vercorp.org fbsdjail

# cat << EOF > /jail/fbsdjail/etc/rc.conf
# DAEMONS | yes


# sed -i '' s/quarterly/latest/g /jail/fbsdjail/etc/pkg/FreeBSD.conf

# grep latest /jail/fbsdjail/etc/pkg/FreeBSD.conf
  url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",

Now we can start our FreeBSD Jail.

# service jail onestart fbsdjail
Starting jails: fbsdjail.

# jls
   JID  IP Address      Hostname                      Path
     1       fbsdjail.vercorp.org          /jail/fbsdjail

# jls -v
   JID  Hostname                      Path
        Name                          State
        IP Address(es)
     1  fbsdjail.vercorp.org          /jail/fbsdjail
        fbsdjail                      ACTIVE

# jexec fbsdjail

root@fbsdjail:/ #

Our FreeBSD Jail works. Lets move to next steps.

Configure FreeBSD Jail to Connect to FreeIPA/IDM Server

I could not repaste all of the instructions above – the ones that we used for a ‘full’ FreeBSD system – but the same applies to a FreeBSD Jail. πŸ™‚

This means that earlier Basic FreeBSD Jail Preparations section covers all that is needed in case of ‘full’ FreeBSD versus FreeBSD Jail when it comes to the FreeIPA/IDM connection.

Linux FreeIPA/IDM Client

This article is not about Linux client – which is pretty straight-forward to connect to the FreeIPA/IDM server – but for the completness of the topic – here are the instructions I used to attach Alma Linux to the FreeIPA/IDM server.

Linux rhlike.vercorp.org system.

hostname: rhlike.vercorp.org

First – install the @idm:client and sssd packages.

client # yum -y install @idm:client sssd

FreeIPA/IDM Setup Part

Now – as earlier with FreeBSD – the FreeIPA/IDM part comes to play.

[root@idm ~]# kinit admin
Password for admin@VERCORP.ORG:

[root@idm ~]# klist
Ticket cache: KCM:0
Default principal: admin@VERCORP.ORG

Valid starting       Expires              Service principal
10/19/2022 13:33:52  10/20/2022 13:11:28  krbtgt/VERCORP.ORG@VERCORP.ORG

[root@idm ~]# ipa user-find
2 users matched
  User login: admin
  Last name: Administrator
  Home directory: /home/admin
  Login shell: /bin/bash
  Principal alias: admin@VERCORP.ORG, root@VERCORP.ORG
  UID: 1896600000
  GID: 1896600000
  Account disabled: False

  User login: vermaden
  First name: vermaden
  Last name: vermaden
  Home directory: /home/vermaden
  Login shell: /bin/sh
  Principal name: vermaden@VERCORP.ORG
  Principal alias: vermaden@VERCORP.ORG
  Email address: vermaden@vercorp.org
  UID: 1896600003
  GID: 1000
  Account disabled: False
Number of entries returned 2

[root@idm ~]# id vermaden
uid=1408200003(vermaden) gid=1408200000(admins) groups=1408200000(admins)

[root@idm ~]# ipa dnsrecord-add vercorp.org rhlike --a-rec
  Record name: rhlike
  A record:

We are done on the FreeIPA/IDM side.

Linux FreeIPA/IDM Client Setup

We will now continue our work on the Linux client.

client # echo "   idm.vercorp.org"    >> /etc/hosts

client # echo "   rhlike.vercorp.org" >> /etc/hosts

client # hostnamectl set-hostname rhlike.vercorp.org

client # cat /etc/hosts   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6   idm.vercorp.org   rhlike.vercorp.org

client # ipa-client-install --uninstall

client # ipa-client-install \
           --hostname=rhlike.vercorp.org \
           --mkhomedir \
           --server=idm.vercorp.org \
           --domain vercorp.org \
           --realm VERCORP.ORG

This program will set up IPA client.
Version 4.9.8

Autodiscovery of servers for failover cannot work with this configuration.
If you proceed with the installation, services will be configured to always access the discovered server for all operations and will not fail over to other servers in case of failure.
Proceed with fixed values and no DNS discovery? [no]: yes
Do you want to configure chrony with NTP server or pool address? [no]: no
Client hostname: rhlike.vercorp.org
DNS Domain: vercorp.org
IPA Server: idm.vercorp.org
BaseDN: dc=vercorp,dc=org

Continue to configure the system with these values? [no]: yes
Synchronizing time
No SRV records of NTP servers found and no NTP server or pool address was provided.
Using default chrony configuration.
Attempting to sync time with chronyc.
Time synchronization was successful.
User authorized to enroll computers: admin
Password for admin@VERCORP.ORG:
Successfully retrieved CA cert
    Subject:     CN=Certificate Authority,O=VERCORP.ORG
    Issuer:      CN=Certificate Authority,O=VERCORP.ORG
    Valid From:  2022-10-18 14:52:50
    Valid Until: 2042-10-18 14:52:50

Enrolled in IPA realm VERCORP.ORG
Created /etc/ipa/default.conf
Configured /etc/sssd/sssd.conf
Configured /etc/krb5.conf for IPA realm VERCORP.ORG
Systemwide CA database updated.
Hostname (rhlike.vercorp.org) does not have A/AAAA record.
Failed to update DNS records.
Missing A/AAAA record(s) for host rhlike.vercorp.org:
Missing reverse record(s) for address(es):
Adding SSH public key from /etc/ssh/ssh_host_ed25519_key.pub
Adding SSH public key from /etc/ssh/ssh_host_ecdsa_key.pub
Adding SSH public key from /etc/ssh/ssh_host_rsa_key.pub
Could not update DNS SSHFP records.
SSSD enabled
Configured /etc/openldap/ldap.conf
Configured /etc/ssh/ssh_config
Configured /etc/ssh/sshd_config
Configuring vercorp.org as NIS domain.
Client configuration complete.
The ipa-client-install command was successful

client # reboot

Now we will test how it goes with login against the FreeIPA/IDM server.

laptop % ssh -l vermaden
(vermaden@ Password:
(vermaden@ Password expired. Change your password now.
Current Password:
(vermaden@ New password:
(vermaden@ Retype new password:
Last failed login: Wed Oct 19 00:47:57 CEST 2022 from on ssh:notty
There was 1 failed login attempt since the last successful login.
/usr/bin/id: cannot find name for group ID 1000

[vermaden@rhlike ~]$ w
 00:48:16 up 29 min,  2 users,  load average: 0.22, 0.13, 0.16
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0         00:40   58.00s  0.03s  0.03s -bash
vermaden pts/1         00:48    0.00s  0.02s  0.01s w

[vermaden@rhlike ~]$ sudo su -

[root@rhlike ~]# getent passwd admin

[root@rhlike ~]# getent passwd vermaden
vermaden:*:1896600003:1000:vermaden vermaden:/home/vermaden:/bin/sh

Seems to work at least OK πŸ™‚

I do not have anything more to add to this guide.

If you have – then please let me know in comments πŸ™‚




Split Audio Files into Parts

I recently got in the need of splitting quite large amount of audio files into smaller equal parts. The first thought that came to my mind was – probably thousand or more people had similar problem in the past so its already solved – so I went directly to the web search engine.

The found solutions seem not that great or work partially only … or not work like I expected them to work. After looking at one of the possible solutions in a bash(1) script I started to modify it … but it turned out that writing my own solution was faster and easier … and simpler.

Today I will share with you my solution to automatically split audio files into small equal parts.

Existing Solutions

In my search for existing solutions I indeed found some tools that will allow me to achieve what I need. I will not try to talk them one after another.


The first one I found was the audio/mp3splt port (and package) available on FreeBSD. So I installed it with typical pkg(8) command as shown below.

# pkg install mp3splt

It installed properly … but returned Segmentation Fault instead of actually working. I even submitted a PR for that in the FreeBSD Bugzilla – 264866 – but no update till now.

Thus I removed that package and went to search for something that works.


Someone on some forum suggested using CD/DVD burning software – Brasero – because one of its features is audio splitting – so I installed the sysutils/brasero package now.

# pkg install brasero

It turns out that it really works. Some screenshots below.



… but that did not satisfied my because I wanted an automated/unattended solution instead of ‘clicking’ each file separately to split them. I also did not liked the fact that I needed to specify time in seconds.


Do not confuse with mentioned earlier mp3splt command. The mp3split is a unattended one created in a bash(1) script – https://diegosanchezp.github.io/blog/mp3split/ – available and described here. One of its downsides (for me) was that it needed additional external ‘list’ file with times and titles for the parts.

I did not wanted to write this each time so I generated a long enough list file that will cover any possible file no matter the length with the following loop.

% seq 0 10 10000 \
    | while read MIN
        seq 0 10 50 \
          | while read SEC
              echo ${MIN}:${SEC}
      done > list.txt

% head list.txt

I needed to split these audio files every 10 minutes. I redirected that output into the list.txt file. I then fetched and made executable the mentioned mp3split script.

% fetch https://raw.githubusercontent.com/diegosanchezp/mp3split/master/mp3split.sh

% chmod +x mp3split.sh

% ./mp3split.sh --help
zsh: ./mp3split.sh: bad interpreter: /bin/bash: no such file or directory

% head -1 ./mp3split.sh

So now we will have to remove linuxisms from the script. Lets hope its only the interpreter part.

% head -1 ./mp3split.sh
#! /usr/bin/env bash

% ./mp3split.sh --help
./mp3split.sh: illegal option -- -
Invalid option: -
  mp3split [OPTIONS] inputaudio tracklist
  -s: do a simulation without writing anything to disk
  -h: print this help
  -e extension: set output extension, if extension is equal to "" keep extension of input file
  The script will output all the splitted files in the
  current/working directory.

Better. Lets try to use it.

% ./mp3split.sh LARGE-AUDIO-FILE.mp3 list.txt

=== Begin to create mp3 split files ===
0:0.mp3: Protocol not found
Processed 0:0 to 0:10; 0:0.mp3
0:10.mp3: Protocol not found
Processed 0:10 to 0:20; 0:10.mp3
0:20.mp3: Protocol not found
Processed 0:20 to 0:30; 0:20.mp3
0:30.mp3: Protocol not found
Processed 0:30 to 0:40; 0:30.mp3
0:40.mp3: Protocol not found
Processed 0:40 to 0:50; 0:40.mp3
0:50.mp3: Protocol not found
Processed 0:50 to 10:0; 0:50.mp3
10:0.mp3: Protocol not found
Processed 10:0 to 10:10; 10:0.mp3
10:10.mp3: Protocol not found
Processed 10:10 to 10:20; 10:10.mp3
10:20.mp3: Protocol not found
Processed 10:20 to 10:30; 10:20.mp3
10:30.mp3: Protocol not found
Processed 10:30 to 10:40; 10:30.mp3
10:40.mp3: Protocol not found
Processed 10:40 to 10:50; 10:40.mp3
10:50.mp3: Protocol not found
Processed 10:50 to 20:0; 10:50.mp3
20:0.mp3: Protocol not found
Processed 20:0 to 20:10; 20:0.mp3
20:10.mp3: Protocol not found
Processed 20:10 to 20:20; 20:10.mp3
20:20.mp3: Protocol not found
Processed 20:20 to 20:30; 20:20.mp3

Some strange error message Protocol not found … after small investigation it turns out that two characters fix for the ffmpeg(1) command will do. The diff(1) is available below.

% diff -u mp3split.sh mp3split.sh.FIXED.sh
--- mp3split.sh 2022-06-25 22:34:25.499718000 +0200
+++ mp3split.sh.FIXED.sh        2022-06-25 22:37:45.580845000 +0200
@@ -25,7 +25,7 @@

   # Begin splitting files with ffmpeg
-  [ ! "$simulate" = true ] && ffmpeg -nostdin -y -loglevel error -i "$inputaudio" -ss "$start" -to "$end" -acodec copy "$outfile"
+  [ ! "$simulate" = true ] && ffmpeg -nostdin -y -loglevel error -i "$inputaudio" -ss "$start" -to "$end" -acodec copy ./"$outfile"

   echo "Processed $start to $end; $outfile"

Now lets try to use the fixed version.

% ./mp3split.sh.FIXED.sh LARGE-AUDIO-FILE.mp3 list.txt

=== Begin to create mp3 split files ===
Processed 0:0 to 0:10; 0:0.mp3
Processed 0:10 to 0:20; 0:10.mp3
Processed 0:20 to 0:30; 0:20.mp3
Processed 0:30 to 0:40; 0:30.mp3
Processed 0:40 to 0:50; 0:40.mp3
Processed 0:50 to 10:0; 0:50.mp3
Processed 10:0 to 10:10; 10:0.mp3
Processed 10:10 to 10:20; 10:10.mp3
Processed 10:20 to 10:30; 10:20.mp3
Processed 10:30 to 10:40; 10:30.mp3
Processed 10:40 to 10:50; 10:40.mp3
Processed 10:50 to 20:0; 10:50.mp3
Processed 20:0 to 20:10; 20:0.mp3
Processed 20:10 to 20:20; 20:10.mp3
Processed 20:20 to 20:30; 20:20.mp3
Processed 20:30 to 20:40; 20:30.mp3
Processed 20:40 to 20:50; 20:40.mp3
Processed 20:50 to 30:0; 20:50.mp3
Processed 30:0 to 30:10; 30:0.mp3
Processed 30:10 to 30:20; 30:10.mp3
Processed 30:20 to 30:30; 30:20.mp3
Processed 30:30 to 30:40; 30:30.mp3
Processed 30:40 to 30:50; 30:40.mp3
Processed 30:50 to 40:0; 30:50.mp3
Processed 40:0 to 40:10; 40:0.mp3
Processed 40:10 to 40:20; 40:10.mp3
Processed 40:20 to 40:30; 40:20.mp3
Processed 40:30 to 40:40; 40:30.mp3
Processed 40:40 to 40:50; 40:40.mp3
Processed 40:50 to 50:0; 40:50.mp3
Processed 50:0 to 50:10; 50:0.mp3
Processed 50:10 to 50:20; 50:10.mp3
Processed 50:20 to 50:30; 50:20.mp3
Processed 50:30 to 50:40; 50:30.mp3
Processed 50:40 to 50:50; 50:40.mp3
Invalid duration specification for to: 60:0
Processed 50:50 to 60:0; 50:50.mp3
Invalid duration specification for ss: 60:0
Processed 60:0 to 60:10; 60:0.mp3
Invalid duration specification for ss: 60:10
Processed 60:10 to 60:20; 60:10.mp3
Invalid duration specification for ss: 60:20
Processed 60:20 to 60:30; 60:20.mp3
Invalid duration specification for ss: 60:30
Processed 60:30 to 60:40; 60:30.mp3
Invalid duration specification for ss: 60:40
Processed 60:40 to 60:50; 60:40.mp3
Invalid duration specification for ss: 60:50
Processed 60:50 to 70:0; 60:50.mp3
Invalid duration specification for ss: 70:0
Processed 70:0 to 70:10; 70:0.mp3
Invalid duration specification for ss: 70:10
Processed 70:10 to 70:20; 70:10.mp3

Great … so after the file ended it will still try EVERY goddamn position from the list.txt file. It was also not able to reach the final ‘ending’ part without ‘visiting’ each time from the list.txt file. Enough is enough. I tried.

Custom Script Solution

After trying to modify the mp3split script even more I came to the conclusion that it will take less time to write my own solution from scratch … and this is exactly what I did. I wrote the audio-split.sh in POSIX /bin/sh interpreter for portability. After an hour later 50 lines of code did exactly what I needed – not counting the __usage() function for help information.


Here is the __usage() contents by the way.


The idea/needs were:

  • split large file automatically/unattended into equal parts
  • create new dir in which these parts are created
  • new dir must have same name as specified file (without extension)
  • each part will get a ' - xxx' suffix (like ' - 001' for first part) with original extension

… and they were met.

Here is the output of running audio-split.sh command.

% ffmpeg -i LARGE-AUDIO-FILE.mp3 2>&1 | grep Duration
  Duration: 00:44:55.99, start: 0.025057, bitrate: 171 kb/s

% audio-split.sh 10 LARGE-AUDIO-FILE.mp3

% du -sm LARGE-AUDIO-FILE.mp3
56      LARGE-AUDIO-FILE.mp3

% du -smc LARGE-AUDIO-FILE/*
56      total

The total size is the same (or similar in larger files). After listening to the parts I came to the conclusion that it works properly. The audio file is about 45 minutes long and the script created 4 10 minutes long files and 1 that is less then 5 minutes. Not sure if you also have such needs but if yes then you may now use another solution – audio-split.sh – for it πŸ™‚


Is FreeBSD a Real UNIX?

That question has been asked and answered many times … but the answer was not always obvious to everyone.

Also today is the FreeBSD day – FreeBSD was created exactly 29 years ago – also on 19th on June.

UNIX System

The first UNIX was the AT&T UNIX whose development started in 1969 at Bell Labs. Then AT&T licensed UNIX to outside parties in late 1970s which have life many UNIX variants like:

  • AIX from IBM
  • BSD (Berkeley Software Distribution) at University of California
  • SunOS/Solaris from Sun Microsystems
  • HP-UX from HP
  • Xenix from Microsoft

Of course AT&T also worked on UNIX and in the late 1980s jointly with Sun Microsystems they released the UNIX System V Release 4 (SVR4). Then in early 1990s the AT&T company sold its UNIX rights to Novell. Then Novell sold UNIX trademark to Open Group. This UNIX journey ends here as its Open Group ownership and they allow the use of the UNIX trademark for certified operating systems that comply with the Single UNIX Specification (SUS) (and pay $100 000 in the certification process).


The BSD UNIX had quite unusual version numbering with 1BSD, 2BSD, 3BSD for subsequent releases.

Below you will find most of them listed with some of their features.


  • run PDP-11
  • ex(1) editor


  • run PDP-11
  • vi(1) editor
  • C shell


  • run VAX-11
  • DEC VT100 terminal


  • run VAX-11
  • DARPA funding for CSRG
  • job control in C shell
  • delivermail(8) – antecedent of sendmail(8)
  • improved signals
  • Curses programming library


  • performance improvements
  • on par with VMS on many benchmarks


  • BBN preliminary TCP/IP implementation
  • Berkeley Fast File System
  • disk quotas
  • job control
  • run Motorola 68000
  • introduction of Daemon mascot



  • improved performance
  • more diverged TCP/IP implementation from BBN


  • move towards POSIX compliance
  • NFS implementation
  • status key (CTRL-T)
  • run HP 9000
  • named as “Greatest Software Ever Written”


  • most standard UNIX utilities reimplemented without AT&T code
  • nvi(1) – new vi(1)
  • only few AT&T files remained in kernel


  • all AT&T standard UNIX utilities reimplemented without AT&T code
  • nearly complete operating system that was freely distributable

386BSD (sometimes also called 386/BSD)

  • run Intel 80386
  • basically 4.3BSD-Net/2 ported to x86
  • base for NetBSD
  • base for FreeBSD on 1.0-2.2.8 releases

BSD/386 (later renamed BSD/OS) by BSDi

  • legal trouble with AT&T
  • AT&T USL versus BSDi lawsuit filed against 4.3BSD-Net/2
  • from 18,000 files only 3 had to be removed and 70 modified to show AT&T USL copyright.


  • released only to AT&T USL licensees


  • no longer requires AT&T USL license
  • contained other changes over 4.4BSD-Encumbered


  • last BSD UNIX release
  • after this release CSRG was dissolved
  • FreeBSD since 3.0 also used that code

Intel/x86 Port

The 386BSD UNIX (sometimes also called 386/BSD) was port of the 4.3BSD-Net/2 UNIX to the Intel/x86 architecture. Like recently FreeBSD added support for RISC-V or ARM64. When 386BSD UNIX existed – a group of people took that code and decided that they will develop it under FreeBSD name with their our own way of doing things like serving packages etc.

As you can see the FreeBSD UNIX is – with large simplification – nothing more then 4.3BSD-Net/2 ported to the x86 architecture. But can you call it UNIX? That depends.


Let me give you an example from other industry. Can you call Tesla a ‘car’? Yes. Why? Because no one has the copyright for the ‘car’ term. Now imagine this – some company owns the copyright to the ‘car’ term. Now you would not be allowed to call Tesla a ‘car’ without first asking that company for permission. Without such permission you could name Tesla only a car-like vehicle … or automobile – but not simply a ‘car’.

Lets get back to the computing world. Can you officially name FreeBSD a UNIX? No. That is because Open Group company owns copyright to the ‘UNIX’ term. You can call it only a UNIX-like system … but that does not mean its not UNIX. You just can not call it like that because of the lawyers.

NetBSD team also gave good example with their ‘duck’ explanation – https://mollari.netbsd.org/about/call-it-a-duck.html – available here.

Apple paid $100 000 to call their Mac OS X (now macOS) system a UNIX officially.

Linux UNIX

Can you call Linux a UNIX system? Depends which one πŸ™‚ Currently RHEL (Red Hat Enterprise Linux) is not a certified UNIX – Red Hat did not made the $100 000 worth official certification process with Open Group – you can not name RHEL a UNIX system … but RHEL fork can be called officially UNIX. The Inspur-UX is official UNIX because they did that $100 000 certification with Open Group. Probably because they thought that calling their RHEL fork ‘UNIX’ will make their business better.

Does it makes sense? No. But that is just business. Do not seek logic here. Money only.


Depends if you want the truth or just what the law officially allows πŸ™‚ If you want the truth then yes – FreeBSD is a UNIX system – same as NetBSD or OpenBSD for example. But if you want to obey the law then you can not name these systems UNIX.


Books About FreeBSD

There are many books in which FreeBSD is covered or it is the one of the main objectives of such book. Today I will guide you through these books. I will try to focus on more up to date ones because it would be pointless (beyond historical purposes) to read them now.

The Hateful Eight

I will start with official FreeBSD documentation – as it offers 8 different books for you to get to know that UNIX operating system better. The two most known are FreeBSD Handbook and FreeBSD FAQ. The FreeBSD Handbook covers all/most general topics about FreeBSD operating system setup and administration while FreeBSD FAQ tries to answer most popular questions about it – and does it quite well. There are also other books that are more developer oriented. Below you will find the list of all available eight books from the FreeBSD project.

FreeBSD Handbook https://freebsd.org/handbook
FreeBSD FAQ https://freebsd.org/faq
FreeBSD Architecture Handbook https://docs.freebsd.org/en/books/arch-handbook/
FreeBSD Developers Handbook https://docs.freebsd.org/en/books/developers-handbook/
FreeBSD Porters Handbook https://docs.freebsd.org/en/books/porters-handbook/
Design and Implementation of 4.4BSD Operating System https://docs.freebsd.org/en/books/design-44bsd/
Project Model for FreeBSD https://docs.freebsd.org/en/books/dev-model/
FreeBSD Documentation Project Primer for New Contributor https://docs.freebsd.org/en/books/fdp-primer/

Example FreeBSD Handbook page from PDF file below.


… and while you can download and read PDF files (there are also EPUB/HTML/TXT formats available for download) you can also read it online – this is how the FreeBSD FAQ looks online.


I sometimes miss that FreeBSD project does not deliver dedicated book in the same PDF/EPUB/HTML/TXT manner for the FreeBSD man pages as for example Solaris or AIX does. At least you can read them online on the https://man.freebsd.org/command page where you will put the needed man page in the place of ‘command’ word – for example the manual page for gstat(8) command is available at https://man.freebsd.org/gstat URL.

If there are two man pages with the same name like crontab(1) and crontab(5) for example then add the man page section number after the slash (/) at the end of URL like that https://man.freebsd.org/crontab/5 – this will solve that problem.

Below you can see the Solaris 10 – Man Pages Section 1M – System Administration Commands book with all Solaris administrative (1M) commands. For FreeBSD the administrative commands are at (8) section.


The Usual Suspects

The most known books that cover FreeBSD operating system aspects are the ones that are authored by Michael W. Lucas (in more recent titles sometimes accompanied by Allan Jude).

The most famous (and useful) one is the Absolute FreeBSD – Complete Guide to FreeBSD in its most recent 3nd Edition. It is quite recent as its from 2019 year. You can get it both in digital (PDF/EPUB) and traditional printed way. If you already read the FreeBSD Handbook and FreeBSD FAQ are wondering what you should get next to continue your FreeBSD journey then this book is the answer. It fill all the gaps and bring a lot of additional information that you will find very useful in your day to day life with FreeBSD system.


Several books later (not only technical) Michael W. Lucas started the FreeBSD Mastery series with many interesting books about FreeBSD. For the two that cover the ZFS filesystem Allan Jude is also a coauthor.


Here they are:

  • FreeBSD Mastery: Storage Essentials (2014)
  • FreeBSD Mastery: Specialty Filesystems (2015)
  • FreeBSD Mastery: ZFS (2015)
  • FreeBSD Mastery: Advanced ZFS (2016)
  • FreeBSD Mastery: Jails (2019)

If you are gonna read them – then also do it in that order sa they are listed above. You will need all that ‘introduction’ to get the most of FreeBSD Jails. Even Michael W. Lucas mentioned that you need to ‘do’ several other of his books to truly take advantage of all things written in the FreeBSD Mastery: Jails book. While the FreeBSD Mastery: Storage Essentials and FreeBSD Mastery: Specialty Filesystems are very close related to FreeBSD operating system the other two FreeBSD Mastery: ZFS and FreeBSD Mastery: Advanced ZFS have also a lot of general ZFS knowledge not only limited to FreeBSD operating system.

One additional word about the FreeBSD Mastery: Jails book as its quite ‘special’ in approach. For most parts of the FreeBSD operating system the FreeBSD Handbook covers some or most of the information and tasks needed to do convening particular topic. When it comes to FreeBSD Jails its not that simple anymore. There are two types of Jails. The ‘traditional’ Jails that use the host system network stack and the new ‘VNET’ Jails that bring their own – separate from the host – network stack. It gives you a lot more possibilities and features but it comes with only one downside. The official FreeBSD Handbook does not cover the ‘VNET’ Jails at all. Zero. Nada. Zip. None. You can get ‘some’ grasp about them from the FreeBSD man pages but that is definitely not enough. The ‘VNET’ Jails are of course production ready from many years but for some reason the missing chapter in the FreeBSD Handbook is still missing. That is the most important reason why you should get the FreeBSD Mastery: Jails book.

As we are in the FreeBSD Jails scope … I should also mention the FreeBSD Jails using VNETs book by Derik Ramirez from 2020.


Its not as ‘big’ as the FreeBSD Mastery: Jails but keep in mind that half of Michael W. Lucas content is about the iocage(8) framework … which is quite dead now unfortunately. The biggest upside of FreeBSD Jails using VNETs book is that it covers – as described in the book title – the VNET Jails. Also being released in 2020 its very up to date.

The Taste of Others

Written in 2018 by Manish Jain the book Beginning Modern Unix covers both FreeBSD and Linux operating systems at the same time.


It also beginner friendly and as author writes in Preparing for Part I“The structure is intended to make things simple for Windows users planning to migrate to FreeBSD/Linux.” I also really liked the author explanation in the Preface about why he choose BSD/FreeBSD and GNU/Linux (like that syntax by the way). You can find part of it below.


To be honest I like that ‘dual’ approach with sections showing how to achieve the same on two different (yet somewhat similar) operating systems. It may be useful especially when writing playbooks for various configuration management software like Ansible or Salt. I know that most of these configuration management systems provide their own ‘general’ integrations like ‘install packages’ on a system and then it uses pkg(8) on FreeBSD and yum(8) on CentOS but sometimes not all integrations are available or they are also sometimes broken or buggy. I have heard several times this already that its safer to rely on your own scripts and ‘raw’ commands instead of the ‘integration modules’ in many cases. Of course your millage may vary.

The Beginning Modern Unix book covers many desktop related topics but it also covers POSIX shell scripting and basic C programming which is very nice.

Another interesting ‘dual’ book is UNIX The Textbook from 2017 by Syed Mansoor Sarwar and Robert M. Koretsky authors.


In its 3rd Edition it covers both Solaris and FreeBSD (in a form of PC-BSD tho) systems. As Solaris by default uses GNOME and PC-BSD (while it existed) used KDE the book also covers a lot about these two desktop environments.


It is illustrated with many useful diagrams of how things work on UNIX system. Below you can check the pipe explanation.


Another good part of the book is that it also covers a lot of POSIX shell scripting and C programming techniques. Even covering things like writing simple servers, inter process communication, threads and a lot more. The book is really huge with almost 1400 pages of useful content. The book leave you at the end of each chapter with QUESTIONS AND PROBLEMS. This approach reminds me of the legendary The C Programming Language written by Brian Kernighan and Dennis Ritchie UNIX fathers where it was also present.

Next one is very well known UNIX and Linux System Administration Handbook by Evi Nemeth and Garth Snyder and Trent R. Hein and Ben Whaley … but it depends which version you get πŸ™‚


The 4th Edition is more conservative and covers Linux/Solaris/HP-UX/AIX systems. This is the description of which systems they have chosen in 2011 and why.


If you try to find FreeBSD there you will fail. They only mentioned it once and added that along with OpenBSD and NetBSD and that BSD systems “(…) enjoy somewhat less support from third-party software vendors.” See for yourself.


Lets now move 7 years forward to 2017 in which the 5th edition of the same UNIX and Linux System Administration Handbook book was released. Authors also changed a little with Dan Mackin being added to current lineup of authors of this book.


Besides modified cover I would risk a stance that its quite entirely different book right now. Its because the 5th Edition covers only Linux and … FreeBSD. No AIX. No Solaris. No HP-UX. Authors also added quite long justification on why they have chosen these operating systems and not the other ones. The time of oldschool UNIX dinosaurs that ruled for decades seem to slowly vanish. Its probably not without reason.

The last HP-UX version 11.31 (also known as 11i v3 variant) was released in 2007. Still uses ‘manual’ packages like in 1995. I like its ‘ecosystem’ tho. What I mean by that is that you can install and setup several HP-UX machines. Setup HP Serviceguard HA cluster on these machines and then make HP Virtual Machines or HP SRP Containers highly available between these hosts as Serviceguard services. I was fortunate enough to be able to see such 6 node cluster in action and it worked really well.

The last AIX version 7.2 was released in 2015 but I do not recall any ground braking features. Also AIX still does not have any modern package management and the most that IBM AIX developers could do was to adopt RPM database to add RPM packages along with the native ones. In 2021 the newer AIX 7.3 release also saw the light of day … but also without any groundbreaking features. In other words the last two AIX system releases fell only like a maintenance releases. While the HP-UX ‘ecosystem’ is ‘connected’ between their products and features its not that easy and simple in the AIX ‘POWER World’. For example its not possible to create similar setup with LPARs or WPARs that their high availability would be controlled by PowerHA cluster software. Even if you would create LPARs with purely virtual devices and storage from the SAN network. The POWER ecosystem offers a feature called Remote Restart for LPARs on HMC but its far from being close to what HP-UX ecosystem offers here.

As for Solaris … I think that Oracle taking over SUN is probably one of the worst things that could happen to Solaris. Oracle could extend and continue the OpenSolaris road started by SUN. It could move and expand Solaris to 21st century. Instead it also went the ‘maintenance’ road along with maximizing the cash outcome of Solaris ‘asset’ with 11.3 in 2015 and 11.4 in 2018 releases. Besides adding PF firewall from OpenBSD and Live Migration feature for Kernel Zones I do not recall any groundbreaking features to be added. Maybe some ZFS development but looking at what OpenZFS is achieving with each release these Oracle developments do not look ‘big’ at all. From what is known Oracle also fired most of SPARC and Solaris developers leaving only small teams to make it running in ‘maintenance mode’ up to 2034 to which Oracle promised to keep Solaris alive instead of moving forward with Solaris 12.0 which was even in alpha or beta state. I agree with authors statement in which they say that “The popularity of UNIX has been waning for some time, and most of the stalwart UNIX distributions (e.g., Solaris, HP-UX, and AIX) are no longer in common use.”

Below is the authors description why they have chosen the FreeBSD and Linux systems for the 5th Edition of their well respected and acknowledged book.


Back to FreeBSD world … and the authors quote why FreeBSD was included in this most recent version of their book – “The open source descendants of BSD are exceptions to this trend and continue to enjoy a cult following, particularly among operating system experts, free software evangelists, and security-minded administrators. In other words, some of the world’s foremost operating system authorities rely on the various BSD distributions. Apple’s macOS has a BSD heritage.” This most recent version is also little shorter with ‘only’ about 1200 pages while earlier edition topped at little over 1300. Keep in mind that newer edition covers Linux and FreeBSD while the older one had to describe and document to systems more.

Last but not least I should also mention the Book of PF – No Nonsense Guide to OpenBSD Firewall book by Peter N.M. Hansteen from 2015 in its most recent 3rd Edition.


While originally targeted at OpenBSD users the FreeBSD users will also be able to get a lot of useful knowledge about PF firewall that FreeBSD uses. Keep in mind that there are some syntax differences between OpenBSD and FreeBSD PF firewalls.

Source Code

Here you will find the books that are little less useful for sysadmins and more useful for developers and programmers. We will start with updated Design and Implementation of FreeBSD 11 Operating System from 2015 in 2nd Edition form. Written by one of the original BSD UNIX and FreeBSD developers Marshall Kirk McKusick along with other two FreeBSD developers George V. Neville-Neil and Robert N.M. Watson.


Its generally more up to date version of the official FreeBSD documentation available as Design and Implementation of 4.4BSD Operating System title from the FreeBSD project documentation page – which one of the authors is also Marshall Kirk McKusick. Is it worth to get it then? Absolutely. A lot have changed and many new technologies have been imported into FreeBSD source tree such as ZFS or DTrace or for example the ULE scheduler.

The final book that I would like to mention here is the FreeBSD Device Drivers book from 2012 written by Joseph Kong.


The book tries to achieve what it title says – to help you first understand and then modify or write your own device drivers. While it covers little older FreeBSD 8 version it is not a problem because the FreeBSD API and ABI change very slow and only when no other way is possible.

Another great tool for programmers and developers in the process of making FreeBSD better is book about DTrace – the dynamic tracing framework. The DTrace – Dynamic Tracing in Oracle Solaris, Mac OS X, and FreeBSD book.


Written by Brendan Gregg and Jim Mauro in 2011 greatly helps to jump into that topic in simple and straightforward way. Besides covering FreeBSD it also does cover Mac OS X, Solaris and even OpenSolaris. That means that it should also be useful for Illumos developers. The book contains a lot of DTrace scripts and examples on how to use that fantastic tool.

Another book that you may find useful in your FreeBSD programmer career is the Designing BSD Rootkits: An Introduction to Kernel Hacking book by Joseph Kong.


Written in 2007 still contains lots of up to date information for the FreeBSD hackers. While the term ‘rootkit’ may be taken ‘negatively’ the author itself describes the book by himself the best way – “Though rootkits have a fairly negative image, they can be used for both good and evil. Designing BSD Rootkits arms you with the knowledge you need to write offensive rootkits, to defend against malicious ones, and to explore the FreeBSD kernel and operating system in the process.” I agree with the author here. To be well protected against something you first need to know how that thing works. The book contains many code examples that you may compile and use and also build upon with your own ideas. Would recommend.

Gone with the Wind

If you know other FreeBSD related books then please let me know.

For those few that did not noticed – the titles of the headers are really great movies πŸ™‚

UNIX Mouse Shootout

While most hardcore UNIX users prefer keyboard shortcuts over anything else – and I often align with that view – I really do appreciate good mouse on my UNIX system. In the end its close to impossible to edit images in GIMP without mouse for example. This ‘shootout’ will definitely be subjective as it will be limited only to mice that I own(ed). I will not bore you with all the technical specifications of these devices – you can check them on your own.

Besides – UNIX has two copy/paste buffers instead of just one like in most systems. There is PRIMARY and SECONDARY buffers in X11 for mouse. One is used when you use Copy/Paste options from menus and/or keyboard shortcuts like [CTRL]+[C] and [CTRL]+[V] ones. The other one is used when you just SELECT the text. After releasing the left mouse button (and finishing the selection) you have that text stored in your SECONDARY buffer. You may now paste that with pressing the third/middle mouse button. But the PRIMARY buffer did not changed during that operation so you can also paste the other text you had in your PRIMARY buffer from the earlier [CTRL]+[C] operation. This makes mouse on UNIX more useful – definitely bigger then in other systems.

While Bluetooth is widely used on most mobile phones/tables and even cars now I do not find it desired as the only protocol for the mouse. I do not have anything against it when it comes as an additional possibility like with the Logitech M720 Triathlon mouse – its even nice that way – but I would not use mouse that the only possible way to connect/operate is by Bluetooth protocol. Maybe on a macOS UNIX but definitely not on FreeBSD UNIX πŸ™‚

AMIGA ‘Tank’ Mouse

The first mouse device that I used was the oldschool AMIGA ‘Tank’ Mouse which I used alongside my first computer – AMIGA A600. When I used it or played Cannon Fodder it felt more then up to the task but using only two buttons mouse (without any scroll and third button) in 2021 feels almost impossible for me.


It was possible to run AMIGA UNIX (also known as Amix) on AMIGA hardware. That was an AT&T Unix System V Release 4 developed as alternative to default AmigaOS but you needed Amiga A3000UX hardware for that.


Unfortunately the AMIGA A600 was not supported 😦

Lenovo and ThinkPad Twins

One of my older/earlier mouse models that I used were quite ‘identical’ mouse models Lenovo Wireless USB Mouse (0A36188) and ThinkPad Wireless USB Mouse (0A36193) – both made by Lenovo for the record. They have the same size and work mostly the same but the older one – ThinkPad model (0A36193) – had more responsive third button (the one under the wheel) – the Lenovo (0A36188) kinda needed real strength to press it – that was its downside.


I still own the ThinkPad one (0A36193) and use it from time to time when I travel – the two AA batteries allow quite long operation of more then a month – which is more then enough for my standards.

Its my first mouse that got additional buttons on the scroll wheel for left and right operations – I used it for volume control on my UNIX system which was (and still is) VERY convenient.

While I really like its/their small size – but after some longer use I really miss some more ergonomic shape under my hand. That means that it ‘will do’ for short periods of usage in travel situations but for long work use something more ergonomic then these.

Logitech Marathon M705 (GEN 1)

I got it after more then a year of using Lenovo and ThinkPad mice. It was real upgrade with quite nice profiled shape to the right hand. It was also quite heavy – but that was good – it felt really good to operate in hand. It was branded as very long to use without changing or charging the batteries and it really did provided in that department – I needed to change/charge the batteries maybe once a year or less often. It was also more precise then simple ThinkPad/Lenovo mouse.


The volume buttons from the wheel that I used on the Lenovo and ThinkPad mice was not quite possible here. While the mouse have these left/right buttons on the wheel they were clumsy and not very precise – so you loss more time trying to press them properly then doing it the other way. With Logitech M705 I ‘moved’ my volume controls to other two buttons that were available under the thumb button. Fortunately there are two of those additional buttons so it was perfect for volume up and volume down actions.

This is also the first mouse that allowed to toggle the wheel to be ‘clickless’ – you can literally spin it for several seconds without any resistance – it just keeps rolling itself – and to be honest – that is one of the features I now DEMAND from any mouse. It makes life so much better (and faster). Instead of scrolling many – many times to get where its needed – you just spin it once and wait till you get there – and even a lot faster then with ‘traditional’ clicking mouse wheel.

Another advantage of that approach is that tip of your finger does not hurt after all day long of scrolling … and if you need precision clicking wheel – then just toggle it and you can click-scroll as usual.

With LogitechΒ Marathon M705 mouse I also grow another ‘useful’ habit (or need) in a mouse. I started to use the lower thumb button to toggle between pause/play for my Deadbeef music player. Before that I used to switch to Workspace 3 where it plays music and press [C] key to toggle pause/play. After adding additional deadbeef --play-pause action to my xbindkeys(1) config now all I have to do to toggle between play and pause is to just push my thumb mouse button. Way faster πŸ™‚

Logitech Performance MX

After reading many comparisons with Logitech MX Master generations I finally settled on the Logitech Performance MX mouse. It is really big and that is really big advantage. It handles/lies really nice in a hand and being quite large and heavy it is very precise and you got ‘good’ feeling and confidence of using it. I really liked it till I got to know its two big downsides … first was the battery time. I needed to change/charge battery about once a week. That was REALLY disappointing. The other downside was that it was not able to properly operate on a flat WOOD surface (like on the photo below). Plain simple flat wood. All other mice worked well on this surface while this one did not. The marketed Darkfield sensor was useless. These were the two reasons that I got rid of it.


Same as with M705 the left/right buttons on the wheel were not very precise so I used the additional thumb buttons for volume management. The Logitech Performance MX mouse also comes with micro USB port at the front so you may use the mouse while you are charging it. Its real pity that Logitech did not used two (or even three) AA batteries for this mouse to make it last longer … but that would not resolve the Darkfield sensor not able to cope with movement on the wood πŸ™‚

Logitech Marathon M705 (GEN 2)

I have read a lot of hate and disappointment about the latest generation of Logitech Marathon M705 mouse. Also the lower thumb button is missing and currently it uses only one AA battery. It still provides very long time without the need to change/charge and its lighter now. Its neither bad nor good – its just different. The precision is similar but after using Logitech Performance MX you really miss that big size.


The second generation of M705 did not improved the left/right buttons on the wheel so I decided to stick with additional thumb buttons for volume management.

I also really missed that lower thumb button that is gone from the GEN 2 Logitech Marathon M705 mouse – needed to go back to my [C] routine …

Logitech Triathlon M720

I recently got the possibility to check and use the Logitech Triathlon M720 mouse and I must say that I am positively surprised. Its both Bluetooth and USB dongle mouse so you can choose which way you would like to connect it to your computers. The plural form is intended here as the Logitech M720 allows you to switch between 3 computers with additional dedicated button. It also got ‘back’ the lower thumb button that was missing on the latest generation of the Logitech M705 mouse. The light/white lower bottom of the mouse looks little strange though … but its kinda not visible when it is laying on the table.


The M720 has more precise left/right buttons on the wheel but I got so used to manage volume with my thumb that I currently keep these ‘wheel’ buttons unused.

Having the lower thumb button again I was also able to get back to my toggle play/pause Deadbeef operation. Yay!

Another useful use case I discovered recently is the ‘misuse’ of the button that switches between 3 computers. I started to use it to ‘suspend’ (generally off) the mouse if I do not want the mouse to ‘wake’ the screen – to not accidentally turn on the screen when I move the mouse accidentally. I mean – sometimes I turn off the screen (with shortcut that executes xset dpms force off command) and then I switch the mouse M720 mouse to channel number 2 to it will not be able to communicate with USB receiver and turn on my screen in again accidentally.


I never owned Logitech MX Master mouse. I used version ‘3’ for short time as one of my buddies own it and it felt quite similar to Logitech Performance MX in operation but not quite the same. Similar but different. I think that it would be comfortable but not sure about the precision on wood and battery time. Maybe I will got it some day and add an update here.


… but given the fact that Logitech MX Master mouse also has micro USB port at its front for charging I would suspect that battery time is also not that great. Similarly like the Logitech Triathlon M720 it also allows to switch its presence between 3 computers. There is also additional wheel for vertical scrolling. Never used that but maybe it would be useful in GIMP for example.


So what does a good UNIX mouse feature? I would summarize all the needed (or at least useful) feats in a list below.

  • needs to be at lest a little ergonomic
  • allows to toggle wheel between click and clickless operation
  • have additional buttons for custom actions
  • allows more then one month of work on batteries
  • works on different surfaces without a problem
  • has a USB dongle so Bluetooth is not needed

What other features you desire in mouse? I also thought about ‘vertical’ mouse type/shape and also about trackball. I tried my neighbor Logitech trackball several times but I am not sure I would get used to it after so many years of ricing the mice πŸ™‚

External Discussions


FreeBSD Desktop – Part 25 – Configuration – Random Terminal Theme

Some time ago when I was mostly writing about Openbox setup I also showed how to setup xterm(1) so it will start with new random theme with each start. Since then I reworked that feature a little and also added random theme and background selection for urxvt(1) terminal. This post will guide you through the needed steps to make that setup working.


You may want to check other articles in the FreeBSD Desktop series on the FreeBSD Desktop – Global Page where you will find links to all episodes of the series along with table of contents for each episode’s contents.

I already once wrote about random xterm(1) themes in the FreeBSD Desktop – Part 12 – Configuration – Openbox part – but I really wanted to expand that topic and also include other terminals.

After trying many terminal emulators – some more bulky like Konsole/GNOME Terminal/XFCE Terminal/MATE Terminal – some more lightweight like st(1)/rox-term(1)/eterm(1)/… – I always went back to the most old-school and basic one – good old xterm(1) terminal. Mostly because of its good compatibility with all UNIX systems – especially the older ones like IBM AIX or HP-UX. I do not remember last time when I had to manage these archaic systems but the respect for xterm(1) remains.


The other one that always got my attention was urxvt(1) terminal. Unfortunately it has some issues with fonts rendering – making larger spaces between the lines and making fonts bigger for example – but as I also like bitmap fonts like CLEAN or FIXED – so I use bitmap fonts for urxvt(1).

Recently also sakura(1) got my attention – but it’s theming possibilities are even more limited then xterm(1) with themes/colors hardcoded directly into the source code. That is why I will omit it in this article – but I mention it since its also nice terminal.

This is the Table of Contents for this article.

  • xterm(1)
    • Proper Font Selection
    • Selecting Text for Copy/Paste
    • Selection Buffers and Keyboard Shortcuts
    • Increase/Decrease Font Size on the Fly
    • Copy/Paste with [CTRL]+[SHIFT]+[C/V]
    • Interactive Menus
    • Random xterm(1) Theme
  • urxvt(1)
    • Tabbed Interface
    • Daemon and Client Mode
    • Random urxvt(1) Theme and Background
  • sakura(1)
    • Different sakura(1) Themes
  • RAM Usage Comparison
  • CPU Time Usage Comparison


First lest start with some reasonable configuration in the ~/.Xdefaults file. Alternatively some people use ~/.Xresources file. You can use any of them. Just pick one and stick to it.

! -----------------------------------------------------------------------------
  xterm*allowBoldFonts:     true
  xterm*allowWindowOps:     true
  xterm*boldMode:           false
  xterm*charClass:          33:48,35:48,37:48,43:48,45-47:48,64:48,95:48,126:48,35:48,58:48,63:48,61:48,44:48,38:48,59:48
  xterm*cursorBlink:        false
  xterm*cutNewline:         true
  xterm*faceName:           consolas
  xterm*faceSize:           11
  xterm*fastScroll:         true
  xterm*fullscreen:         false
  xterm*iconHint:           /home/vermaden/.icons/vermaden/xterm.xpm
  xterm*internalBorder:     1
  xterm*jumpScroll:         true
  xterm*keepSelection:      true
  xterm*loginShell:         true
  xterm*metaSendsEscape:    true
  xterm*multiScroll:        true
  xterm*omitTranslation:    fullscreen
  xterm*on4Clicks:          group
  xterm*on5Clicks:          page
  xterm*saveLines:          1024000
  xterm*scaleHeight:        1.0
  xterm*scrollKey:          true
  xterm*scrollTtyOutput:    false
  xterm*selectToClipboard:  true
  xterm*SimpleMenu*font:    -*-clean-*-*-*-*-*-*-*-*-*-*-iso8859-2
  xterm*termName:           xterm-256color
  xterm*title:              xterm
  xterm*veryBoldColors:     14
  xterm*VT100*geometry:     150x40
  xterm*VT100*translations: #override                                             \n\
                            <btn1up>: select-end(PRIMARY, CLIPBOARD, CUT_BUFFER0) \n\
                            Ctrl <key> minus: smaller-vt-font()                   \n\
                            Ctrl <key> plus: larger-vt-font()                     \n\
                            Ctrl Shift <key> C: copy-selection(CLIPBOARD)         \n\
                            Ctrl Shift <key> V: insert-selection(CLIPBOARD)

I will not discuss all possible settings as they are well described in the xterm(1) man page but I will comment some more useful and interesting ones.

Proper Font Selection

This advice is not limited to xterm(1) but its worth to mention it. Many times after adding fonts to my system – and renaming them to my ‘standard’ which looks like that one below I was asking myself how to properly specify the variant I need.

% ls -1 ~/.fonts/ubuntu-mono*

The answer to that question comes with fc-match(1) from fontconfig package. Check my ‘queries’ below.

% fc-match consolas:bold
consolas-bold.ttf: "Consolas" "Bold"

% fc-match consolas     
consolas.ttf: "Consolas" "Regular"

% fc-match consolas:bold:italic
consolas-bold-italic.ttf: "Consolas" "Bold Italic"

Selecting Text for Copy/Paste

The xterm*charClass defines which sets of characters should be treated the same when doing cut and paste. Especially with double-clicking the text. The setting above I use is based on 15 years of experience and seems to work best. You are of course encouraged to investigate the CHARACTER CLASSES section of the xterm(1) man page to read more on this topic.

The xterm*on4Clicks and xterm*on5Clicks are not used by default while xterm*on2Clicks are predefined as word and xterm*on3Clicks as line values. This is why I added them so you can select entire group with xterm*on4Clicks and entire page with xterm*on5Clicks option. Alternatively you can also use some fancy regex for some of these ‘CLICKS’ but I never thought about a REGEX that would be useful here – maybe you will come with something sensible.

Here are these ‘CLICKS’ in action.

First the xterm*on2Clicks with word selection. This is when the xterm*charClass is taken into account – what is word and that is not πŸ™‚


Then xterm*on3Clicks with line selection.


Now xterm*on4Clicks with group selection.


Finally the xterm*on5Clicks entire page selection.


Selection Buffers and Keyboard Shortcuts

The last interesting option is xterm.VT100.translations which is used for keyboard shortcuts.

The first one select-end(PRIMARY, CLIPBOARD, CUT_BUFFER0) is better described in the https://davidsimmons.com/soft/xtermhacks/ page from 2005. I will try to short the meritum here. The X11 applications have two different selection buffers:

CLIPBOARD – selection buffer used for cut/paste functions – you select/highlight text and then select Copy from context menu or use [CTRL]+[C] shortcut. Then you use Paste or [CTRL]+[C] shortcut.

PRIMARY – this one receives data when user selects/highlights text with mouse. None other operations such as Copy or Paste are needed. You end selecting the text and its already in PRIMARY buffer. You then paste it with MIDDLE mouse button.

Using the option above selecting/highlighting the text in xterm(1) copies the text into both selection buffers simultaneously. You can now either Paste it info Firefox or hit MIDDLE mouse button to paste it in other xterm(1) terminal. Best of both worlds.

If that setting does not suit you then use the xterm*selectToClipboard instead. When set to true it copies selected text to CLIPBOARD buffer and when set to false it copies selection to the PRIMARY one.

Increase/Decrease Font Size on the Fly

I always missed the shortcuts to decrease or increase font size on the fly in xterm(1) and for many years I believed that its just not possible and then I found some blog post (do not remember which one now of course) in which I found these settings and started to use them.

They are smaller-vt-font() and larger-vt-font() for decrease and increase respectively with [CTRL]+[-] and [CTRL]+[+] shortcuts – keep in mind that [SHIFT] is not used here.

Copy/Paste with [CTRL]+[SHIFT]+[C/V]

If by some reason you prefer to copy and paste by using [CTRL]+[SHIFT]+[C] and [CTRL]+[SHIFT]+[V] shortcuts then copy-selection(CLIPBOARD) and insert-selection(CLIPBOARD) will do the needed job here. As you probably guessed you can use PRIMARY instead of CLIPBOARD here if that is what you desire.

Interactive Menus

The xterm(1) comes with three different interactive menus. I will now show all three of them here with screenshots.

Menu displayed with clicking [CTRL]+[LEFT-MOUSE-BUTTON] in the terminal area.


Menu displayed with clicking [CTRL]+[MIDDLE-MOUSE-BUTTON] in the terminal area.


Menu displayed with clicking [CTRL]+[RIGHT-MOUSE-BUTTON] in the terminal area.


Random xterm(1) Theme

To have random xterm(1) theme on every startup you need four things:

I gathered all these themes all over the Internet, only the VERMADEN and VERMADEN-OLD themes are created by me.

Little preview of some of the included xterm(1) themes.


From now on to have random xterm(1) theme at each start always start it with ~/scripts/xterm.sh script. The script itself is not very complicated. It just draws random theme from the ~/.config/Xdefaults/themes dir – then loads the ~/.Xdefaults config – then merges the colors from chosen random theme – and finally starts new xterm(1) instance.



I use urxvt(1) less often but still sometimes I want to use bitmap fonts instead.


For a start here is the urxvt(1) configuration in the ~/.Xdefaults file.

! -----------------------------------------------------------------------------
  urxvt.letterSpace:    0.0
! urxvt.font:           xft:monaco:pixelsize=9,style=regular,minspace=True
  urxvt.font:           -*-clean-*-*-*-*-*-*-*-*-*-*-iso8859-2
  urxvt.boldFont:       -*-clean-*-*-*-*-*-*-*-*-*-*-iso8859-2
  urxvt.iconFile:       /home/vermaden/.icons/vermaden/xterm.xpm
  urxvt.geometry:       150x40
  urxvt.cutchars:       ,;
  urxvt.scrollBar:      false
  urxvt.imLocale:       en_US.UTF-8
  urxvt.loginShell:     true
  urxvt.saveLines:      1024000
  urxvt.inheritPixmap:  false
  urxvt.shading:        20
  urxvt.xftAntialias:   true
  urxvt.jumpScroll:     true
  urxvt.tintColor:      black
  urxvt.internalBorder: 2
  urxvt.cursorBlink:    false
  urxvt.cursorColor:    #dd9900
  urxvt.cursorColor2:   #000000
  urxvt.colorBD:        #dddddd
  urxvt.colorIT:        #bbbbbb
  urxvt.colorUL:        #999999
  urxvt.underlineColor: #999999

Tabbed Interface

To get tabs in urxvt(1) add the following option to the ~/.Xdefaults configuration file.

  urxvt.perl-ext-common:   default,tabbed

With this option you will open new tab with [SHIFT]+[DOWN] shortcut.

To switch between the tabs left and right use [CTRL]+[SHIFT]+[LEFT] and [CTRL]+[SHIFT]+[RIGHT] shortcut respectively.

You can also use [CTRL]+[LEFT] and [CTRL]+[RIGHT] to move current tab left and right.

The timeless [CTRL]+[D] – which of course is not a strictly urxvt(1) shortcut but a general shortcut for closing all terminals.


Daemon and Client Mode

The urxvt(1) can be run in special daemon mode where you start one urxvtd(1) server and many urxvtc(1) clients.

% urxvtd
rxvt-unicode daemon listening on /home/vermaden/.urxvt/urxvtd-w520.local.

Now you will start each new urxvt(1) terminal with urxvtc(1) command.

The drawback of that approach is that when urxvtd(1) dies or crashes then also all your urxvtc(1) client terminals disappear πŸ™‚

Random urxvt(1) Theme and Background

To have random urxvt(1) theme and background on every startup you need four things:

Little preview of some of the included urxvt(1) themes and backgrounds.


From now on to have random urxvt(1) theme at each start always start it with ~/scripts/urxvt.sh script. The script for urxvt(1) is little more advanced. First it draws random theme from the ~/.config/Xdefaults/themes dir – then checks if its DARK or LIGHT theme – then draws either random LIGHT or DARK background from the ~/.config/Xdefaults/urxvt dir – finally loads the ~/.Xdefaults config and then merges the colors from chosen LIGHT or DARK theme. Of course then it finally starts new urxvt(1) instance.



The more modern and GTK based sakura(1) also supports tabs. To open new tab use [CTRL]+[SHIFT]+[T] shortcut. To switch between the tabs use [CTRL]+[ALT]+[LEFT] and [CTRL]+[ALT]+[RIGHT] shortcuts. You can also move tab between left and right with [CTRL]+[SHIFT]+[LEFT] and [CTRL]+[SHIFT]+[RIGHT].


One things that sakura(1) impresses me is that you can scale down its window and then scale that window up and the contents that did not fit in the window after downscalling are back again in the terminal. Doing the same operation in xterm(1) or urxvt(1) terminals will result in these characters being lost. The output is also dynamically ‘fit’ into the new larger window while maintaining the new lines etc. Besides that nice feature it is small and fast and uses relatively small amount of RAM.


Different sakura(1) Themes

If you would also like to start sakura(1) with different theme everytime the options are quite limited here. The palettes and color sets are hardcoded into the sakura(1) source code.

I will not show you how to modify them using the FreeBSD Ports system.

The sakura(1) port is located at /usr/ports/x11/sakura directory. For the record – I use WRKDIRPREFIX option in the /etc/make.conf file. This means that when I type make extract in the /usr/ports/x11/sakura dir the work directory will not be created at /usr/ports/x11/sakura/work directory but at /usr/ports/obj/usr/ports/x11/sakura/work instead. That way I can clean my Ports tree fast by removing the /usr/ports/obj directory.

We will now extract and patch the sakura(1) port on FreeBSD.

% grep WRKDIRPREFIX /etc/make.conf

# cd /usr/ports/x11/sakura

# make patch

# cd /usr/ports/obj/$( pwd )/work/*/src || cd work/*/src

# pwd

# grep -m 1 DEFAULT_PALETTE sakura.c
#define DEFAULT_PALETTE "tango"

# grep -o -E '[a-z]+_palette\[PALETTE_SIZE\]' sakura.c

As you can see the default sakura(1) palette is Tango. Fortunately you can use palette=solarized_dark option in the ~/.config/sakura/sakura.conf config file to change it into Solarized Dark for example.

Besides hardcoded palettes sakura(1) also has several Color Sets.

If you would like to make random theme (from the hardcoded ones) for each start you would have to use this syntax with prepared dedicated config files for each palette.

% sakura --config-file ~/.config/sakura/sakura.solarized_dark.conf --colorset 1 
% sakura --config-file ~/.config/sakura/sakura.tango.conf          --colorset 3

I do not use sakura(1) that much so I was too lazy to write random startup theme script also for it πŸ™‚

Changing sakura(1) palette or color set manually is shown below.




RAM Usage Comparison

Just started xterm(1) terminal takes about 16 MB or RAM as you have seen on the urxvt(1) screenshots. The urxvt(1) started without tabs uses more then 2 TIMES of xterm(1) terminal RAM usage. The urxvt(1) started in tabbed mode uses more then 3 TIMES of xterm(1) terminal RAM usage. The sakura(1) also uses more then 3 TIMES of xterm(1) terminal RAM usage.

Table below shows RAM usage comparison. I have added more feature packed mate-terminal(1) to the list and also added the st(1) minimalistic terminal from Suckless project for compassion.

    64  mate-terminal
    53  sakura
    52  urxvt (tabbed)
    38  urxvt
    16  xterm
    12  st

CPU Time Usage Comparison

I also made simple benchmark of the CPU used. The ‘benchmark’ was to check how much time each terminal would take to print output ofΒ  dmesg | lolcat -b -r command. Here xterm(1) does not shine that much.

0:00.93  xterm
0:00.82  mate-terminal
0:00.52  sakura
0:00.43  urxvt
0:00.23  st

The above ‘benchmark’ was was quite ‘hard’ because of all the colors generated by lolcat(1) command. Lets try something more practical now. We will measure CPU time used to display out of the find find /usr/local/share/doc command.

0:01.34  xterm
0:01.18  mate-terminal
0:00.85  sakura
0:00.32  urxvt
0:00.28  st

Seems that lolcat(1) was not that ‘hard’. The st(1) minimalistic terminal really seems to suck less here πŸ™‚


Manage Contacts the UNIX Way

About two years ago my neighbor asked me a question – “How do you manage contacts on your devices?” – and that was my ‘a-ha’ moment in that topic – I do not. I do not at all. He had a problem of having an iPhone with iTunes and Android phone and wanted to manage contacts between them in one single sensible place. Finally he settled on some closed source freeware software which run on Windows. But that was not the answer – that was just the beginning – how to manage contacts the UNIX open source way?

I have tried to search for some open source software that is capable of doing that efficiently and without too much effort and PITA … and I failed miserably.

So as usual I came with my set of scripts that will do the job and after several years of using this ‘system’ I am quite satisfied with the results and PITA reduced to minimum.

Export from Phone

The VCF file (also called VCARD) exported from a mobile Android based phone looks like below.

% cat export.vcf
FN:herbert pierre hugues
FN:butcher (local)
FN:martin brundle (f1)

I have used colors to distinguish different contacts.

The most annoying field seems to be 'N' which tries to be smarter then needed – trying really hard to first put surname, then name, and then other names. The 'FN' field is a lot more useful here. The remaining fields as 'TEL' or 'EMAIL' does not try to outsmart us and work as desired. The VCARD of course starts with 'BEGIN:VCARD' and ends with 'END:VCARD', that is obvious. In 2015 when I initially wrote those scripts the Instant Messaging was still used by me. Now several years fast forward I use it very rarely, but its still in use. I keep this Instant Messaging number/account information in the VCARD 'X-QQ' field in which I use protocol:number notation and use it for all different Instant Messaging solutions. The 'gg:' is for example for the Polish solution called Gadu-Gadu.

I do not find this VCARD format readable, nor grepable/searchable, thus I convert it into the plain text file which looks like follows and is grep(1) and awk(1) friendly (columns separated by spaces).

====  =====  ==  ====  =====

Here is how the above VCARD information looks after converting it with my script to the plain text columns.

% contacts-convert-vcf-from.sh -t export.vcf | column -t > contacts
% cat contacts
NAME                                    PHONE                                                IM                MAIL                                                    NOTES
======================================  ===================================================  ================  ======================================================  =====
butcher-(local)                         555123457;225553457;451232421                        -                 -                                                       cheap
herbert-pierre-hugues                   555123456                                            -                 pierre@gmail.com                                        executive
martin-brundle-(f1)                     555987654;451232421                                  gg:32847916       -                                                       fast

The length of ‘=====’ underscores is defined/hardcoded in the scripts itself. Why hardcode this? For comparison purposes – more on that later. The entries are also sorted by name. I could embed/rework the script to contain also the column -t command but I did not saw the need to – but its of course possible.

Now – lets suppose you want to generate new VCARD with some of your contacts, then you could use grep(1) to filter out the unneeded entries, like that.

% grep -v butcher contacts > contacts.NOBUTCHER
% contacts-convert-vcf-to.sh contacts.NOBUTCHER > import.vcf
% cat import.vcf

FN:herbert pierre hugues

FN:martin brundle (f1)

Its obvious but the generated VCARD does not contain the 'butcher (local)' contact. You can now send this import.vcf file to your phone using email and then import these contacts as you would from any other VCARD shared with you.


I use three scripts to convert/export/import/check that data in VCARD form.

The contacts-convert-vcf-from.sh script as the name suggests converts VCARD data (VCF file) into the plain text information. but I also implemented the CSV method which may be useful for some people – to put that data into the spreadsheet.

% contacts-convert-vcf-from.sh
usage: contacts-convert-vcf-from.sh TYPE FILE
  TYPE: -c | --csv
        -p | --plain
        -t | --text

Here is example CSV output from the script.

% contacts-convert-vcf-from.sh -c export.vcf

The contacts-convert-vcf-to.sh script converts the plain text data into the VCARD format.

% contacts-convert-vcf-to.sh
usage: contacts-convert-vcf-to.sh FILE

The last contacts-check.sh script is used to find duplicated phone information within the plain text file. Many time I have found duplicated contacts with different names but with the same phone number.

% contacts-check.sh contacts | column -t
butcher-(local)      555123457;225553457;451232421  -            -  cheap
martin-brundle-(f1)  555987654;451232421            gg:32847916  -  fast

All of the three are available in my GitHub scripts page – https://github.com/vermaden/scripts/ – available here.

You can of course download them using command line like that.

% wget https://raw.githubusercontent.com/vermaden/scripts/master/contacts-check.sh
% wget https://raw.githubusercontent.com/vermaden/scripts/master/contacts-convert-vcf-from.sh
% wget https://raw.githubusercontent.com/vermaden/scripts/master/contacts-convert-vcf-to.sh
% chmod +x contacts-*

Updating Contacts

Its easy to maintain several contacts – no matter in which format – but when you grow to have about a 1000 of contacts (and I do) then you need to deal with it intelligently.

Not to mention that you can add a new contact on your phone (more often) but You can also update your local plain text contacts file.

This is where UNIX comes handy. You may use diff(1) to compare these ‘updates’ with following command.

% diff -u contacts contacts.NEW | egrep '^\-|^\+'
--- contacts            2019-12-13 15:29:23.541256000 +0100
+++ contacts.NEW        2019-12-13 15:29:36.087084000 +0100
-john-doe-the-third                      -                                                    -                 jogh.doe@gmail.com                                      -
+jan-kowalski                            555192384                                            gg:11844916       -                                                       slow

This way you know that there are two new contacts, one '-' from the local contacts file and one '+' from the plain text version generated from phone exported VCF file called contacts.NEW here.

You can also use vim(1) with its diff mode enabled by starting with -d flag as shown below.

% vim -d contacts contacts.NEW

Here is how it looks like.


… and we now get back to the amount of '====' used in the columns in the plain text file. If you keep the same amount of these each time, then diff is possible. If I would not put them there the column -t command would generate larger NAME column for example because of longer contact name – and because of additional space in the remaining contacts both diff(1) and vim(1) tools will show that all contacts are new.

This is how I manage the contacts the UNIX way, if you have more fun way of dealing with the contacts then please let me know πŸ™‚


Manage Photography the UNIX Way

After using UNIX for so many years you start to think the UNIX way. This article aims to automate and accelerate the flow of importing photos from camera and storing it for future use.

When I had a lot of time I shoot both RAW and JPEG images at the same time (RAW and JPEG file were written for every picture). Then I used one of the DxO Optics Pro/Raw Theraphee/Darktable applications to make these RAW files shine even more with mass conversion. Then I compared these to out of camera JPEG files and left only the one that suited me best. Its was probably the best way of having ‘the best version’ of each photo but it also took whole a lot of time. Now as I do not have that much time I needed to find a way to make this process fast and almost seamless.


I use SONY cameras because they are superior to other brands when it comes to price/performance ratio and also have some important features that are absent in other brands. For example SONY A-mount based cameras – SONY a68 camera offers just so much more for very small amount of money then any near Nikon or Canon competitor. If you want to get grip on these differences take a look at my SONY a68 review at DPReview site – https://www.dpreview.com/forums/thread/4152155 – available here.


Besides the price/performance ratio SONY cameras are just too fun/too comfortable to use something different – while providing similar or better results then Nikon/Canon competition. Take the viewfinder for example. Nikon/Canon cameras are ‘by default’ using the optical viewfinder and to switch to LCD panel you need to manually push a button and switch into the PAINFULLY SLOW (autofocus is actually unusable) mode called Live View … but if you want to use viewfinder again then you again need to switch that mode off with a button. How its implemented in SONY? SONY camera just automatically switches to EVF when you attach your eye to the viewfinder and switches back to LCD automatically when you take your eye off of it … and autofocus is same fast on both viewfinder and LCD. This is just one of the examples of course. For example Nikon cameras can not record movie when you are using viewfinder – you can only do it with LCD.


There is also SONY E-mount system which utilizes newer/different ideas – its generally much more expensive then older A-mount system but has even more features then Canon/Nikon cameras. One of the selling points of SONY E-mount cameras is also their small size – for which feature I recently switched from SONY a68 (A-mount) to SONY a5100 (E-mount) camera.


I basically use two SONY cameras.

The small and ultra portable SONY RX100 III which is probably the best pocket/compact camera in the world when it comes to price/performance ratio. As it has quite large 1 INCH sensor (2.7 crop factor) it allows to use high ISO values without that much noise which allows to shoot indoors in low light without much loss of quality. It also has tiltable flash which you can point to ceiling to get extra bounced light in low light situations indoors. This small gem generally has all the features that all SONY APS-C/Full Frame cameras have. Same menu interface with same features. Its not some small handicapped cripple like a lot of compact cameras. And its fast too. It even features EVF! It also features XAVC S 50 Mbit video codec which helps greatly in low light situations. Of course in good light conditions this camera shines even more. As it has 24-70mm f/1.8-2.8 light/fast lens it its very universal. The Full Frame depth of field equivalent is even better then most APS-C cameras because its f/4.9-7.6 Full Frame depth of field equivalent is better – for example – then SONY a6400 with its f/3.5-5.6 kit lens – which only has f/5.3-8.4 (because of 1.5 crop ratio for APS-C).


You can read more about depth of field equivalence here – https://www.dpreview.com/articles/2666934640/what-is-equivalence-and-why-should-i-care – a good article on DPReview explaining this.

The other SONY camera I used was SONY a68 with following lenses:

  • TAMRON 18-270mm f/3.5-5.6 – all-rounder
  • SONY 35mm f/1.8 – small bokeh low light friend
  • SIGMA 50-150mm f/2.8 – large bokeh friend
  • SAMYANG 85mm f/1.4 – manual focus bokeh master

… but as I checked my ‘habits’ it was that way most of the time:
– use/take small/portable SONY RX100 III because its convenient
– grab SONY a68 with 35mm f/1.8 at house for some bokeh pictures

If you are not sure what ‘bokeh’ means then please check Wikipedia article about it – https://en.wikipedia.org/wiki/Bokeh – available here.

I very rarely used other lenses. Which made me to think how to ‘optimize’ the SONY a68 A-mount camera. Also because SONY a68 built-in flash is not able to point up (to get extra light from ceiling indoors) I also needed dedicated external SONY HVL F20M flash on ISO hot shoe which made this large camera even bigger.

I checked the SONY portfolio and got older SONY a5100 E-mount camera instead. It has nice and fast autofocus from SONY a6000 camera along with XAVC S video codec and useful tiling LCD screen. It even has a touch screen which allows you to take a photo on the place when you touched the screen! It works similar in movies – just touch when you want it to focus. Its probably smallest SONY APS-C body – very close in size to SONY RX100 III … and I got SONY E-mount 35mm f/1.8 lens to it. I also missed 85mm f/1.4 lens so I take different route now. As E-mount system allows one to adapt older lenses with Lens Turbo adapters (about 0.7 ratio) I get an old used Minolta MD 56mm f/1.4 lens and E-mount to MD Lens Turbo adapter from ALIEXPRESS. This way I got small ultimate bokeh machine – with only one downside – manual autofocus – but SONY a5100 provides very nice implementation of Focus Peaking so its still a pleasure to use.


Of course SONY a5100 has its limitations – no viewfinder for example – but I VERY rarely used it anyway – of course intensive outdoor light can be problematic sometimes without EVF – but if someone wants to have EVF then one should get one of the SONY a6000/a6300/a6400/a6500 cameras – they are not much more larger and provide both EVF and hot shoe.


Generally SONY RX100 III when powered on its comparable in size with SONY a5100 with SONY 35mm f/1.8 lens. Its the powered off state and lens range (24-70mm on SONY RX100 III) that make a difference – the SONY RX100 III even fits in the pocket – SONY a5100 does not – maybe with SONY 20mm f/2.8 lens.

If you have quite more budget to spend I also recommend the SONY RX100 V/VA which also incorporates very fast phase detection autofocus and 4k video. The SONY RX100 IV only offers 4k video but still has slower contrast autofocus – thus its IMHO pointless to get it. For the record – the SONY RX100 III also uses slower contrast based autofocus and has video up to FullHD (1080p).


These cameras also share nice feat – they can be charged directly by attaching USB micro cable to them – very convenient – no need to provide dedicated external chargers for batteries. I really liked SONY a68 grip and lots of direct controls but I really like the size/compactness of SONY a5100. While SONY a5100 body weights 283 grams the SONY a68 is 690 grams – for the body alone. Add flash and larger lens to it and you get the idea.


Comparing to the other side the SONY RX100 III weights 290 grams while SONY a5100 wights 437 grams with SONY 35mm f/1.8 lens attached, not bad.

Gear Summary

I have settled on these two cameras for now.

  • SONY RX100 III – gives 24-70mm f/4.9-7.6 depth of field Full Frame equivalent
  • SONY a5100 with these lenses:
    • Sony 35mm f/1.8 OSS – gives 53mm f/2.7 depth of field Full Frame equivalent
    • Minolta MD 56mm f/1.4 with Lens Turbo 0.7x adapter – gives 59mm f/1.5 depth of field Full Frame equivalent


I switched off shooting RAW+JPEG images and now I only shoot EXTRA FINE JPEG images with Vivid profile and -0.7 EV (to not have over-burned images).

The 1st part is copying the images to new directory. That means pictures from DCIM directory and movies from PRIVATE directory.

Now the first two scripts come to play – to rename images to something useful. Each Picture and Video will have YYYY.MM.DD.HHMM(x) name.

These are made by these two scripts:

  • photo-rename-images.sh
  • photo-rename-movies.sh

Links to the scripts will be posted later in the article.

The photo-rename-images.sh uses jhead as dependency.

Now as we have everything named as it should be the size needs to be addressed. The videos will be converted using ffmpeg and images will be compressed to 92% JPEG quality with convert utility from ImageMagick suite.

  • photo-requality.sh
  • photo-movie-audio-ac3.sh

One may ask why convert JPEG from 99% to 92% and lose more quality even more? Well, you should check the differences – and one have to try really hard with very large zoom to find any. For most purposes these differences are negligible. You can also use larger value to have quite better quality and less storage savings -take photo-requality.sh 95 for example as consensus.

This is the comparison between original out of camera JPEG file and the same file compressed to 92% quality using convert utility. I was not able to stop any differences – maybe you will.


One may be also worried about quality loss in the videos as the size savings are that big. I also tried to find these differences and if its really hard to find them then storage savings are justified – at least for me.

I also recently added photo-flow.sh which takes two arguments. First is the device under which the camera SD card is mounted – its mmcsd0s1 on FreeBSD for most of the times. The second is directory ~/photo.NEW in which the pictures and videos will be dumped, renamed and (re)compressed.

I have put these scripts to my external (from WordPress) account on GitHub – https://github.com/vermaden/scripts – here they are:


As I attached the SD card from one of my cameras to my laptop it was automounted by my automount solution – described here – Automount Removable Media – as /media/mmcsd0s1 directory – that will be first argument for the import scripts. As I import new pictures to ~/photo.NEW directory – that will be the second argument for the import scripts.

Below you will find example output of such import/convertion process. It took about half an hour on 2011 dual-core laptop (ThinkPad T420s). I omitted/cut large parts of the same output with (…) chars in the output.

% photo-flow.sh /media/mmcsd0s1 ~/photo.NEW
/media/mmcsd0s1/DCIM/100MSDCF/DSC00390.JPG -> /home/vermaden/photo.NEW/2019.06.10.DUMP/DSC00390.JPG
/media/mmcsd0s1/DCIM/100MSDCF/DSC00391.JPG -> /home/vermaden/photo.NEW/2019.06.10.DUMP/DSC00391.JPG
/media/mmcsd0s1/DCIM/100MSDCF/DSC00393.JPG -> /home/vermaden/photo.NEW/2019.06.10.DUMP/DSC00393.JPG
/media/mmcsd0s1/DCIM/100MSDCF/DSC00462.JPG -> /home/vermaden/photo.NEW/2019.06.10.DUMP/DSC00462.JPG
/media/mmcsd0s1/DCIM/100MSDCF/DSC00463.JPG -> /home/vermaden/photo.NEW/2019.06.10.DUMP/DSC00463.JPG
/media/mmcsd0s1/DCIM/100MSDCF/DSC00464.JPG -> /home/vermaden/photo.NEW/2019.06.10.DUMP/DSC00464.JPG
/media/mmcsd0s1/PRIVATE/M4ROOT/CLIP/C0015.MP4 -> /home/vermaden/photo.NEW/2019.06.10.DUMP/C0015.MP4
/media/mmcsd0s1/PRIVATE/M4ROOT/CLIP/C0015M01.XML -> /home/vermaden/photo.NEW/2019.06.10.DUMP/C0015M01.XML

DSC00390.JPG --> 2019.05.08.0732.jpg
DSC00391.JPG --> 2019.05.08.0732a.jpg
DSC00393.JPG --> 2019.05.08.0732b.jpg
DSC00462.JPG --> 2019.06.07.2110c.jpg
DSC00463.JPG --> 2019.06.07.2110d.jpg
DSC00464.JPG --> 2019.06.07.2110e.jpg
C0015.MP4 -> 2019.06.01.2140.MP4
C0015M01.XML -> 2019.06.01.2140.XML
File './2019.05.22.0543.jpg' converted to '92' quality.
File './2019.06.07.0508a.jpg' converted to '92' quality.
File './2019.06.01.2141.jpg' converted to '92' quality.
File './2019.05.23.0124c.jpg' converted to '92' quality.
File './2019.06.01.2140e.jpg' converted to '92' quality.
File './2019.05.22.0548a.jpg' converted to '92' quality.
ffmpeg version 4.1.3 Copyright (c) 2000-2019 the FFmpeg developers
Guessed Channel Layout for Input Stream #0.1 : stereo
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '2019.06.01.2140.MP4':
    major_brand     : XAVC
    minor_version   : 16785407
    compatible_brands: XAVCmp42iso2
    creation_time   : 2019-06-01T19:40:52.000000Z
  Duration: 00:00:21.60, start: 0.000000, bitrate: 52049 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709/bt709/iec61966-2-4), 1920x1080 [SAR 1:1 DAR 16:9], 50101 kb/s, 50 fps, 50 tbr, 50k tbn, 100 tbc (default)
      creation_time   : 2019-06-01T19:40:52.000000Z
      handler_name    : Video Media Handler
      encoder         : AVC Coding
    Stream #0:1(und): Audio: pcm_s16be (twos / 0x736F7774), 48000 Hz, stereo, s16, 1536 kb/s (default)
      creation_time   : 2019-06-01T19:40:52.000000Z
      handler_name    : Sound Media Handler
    Stream #0:2(und): Data: none (rtmd / 0x646D7472), 409 kb/s (default)
      creation_time   : 2019-06-01T19:40:52.000000Z
      handler_name    : Timed Metadata Media Handler
      timecode        : 83:01:01;02
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (pcm_s16be (native) -> ac3 (native))
Press [q] to stop, [?] for help
[libx264 @ 0x80ddfb400] using SAR=1/1
[libx264 @ 0x80ddfb400] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264 @ 0x80ddfb400] profile High, level 4.2, 4:2:0, 8-bit
[libx264 @ 0x80ddfb400] 264 - core 157 - H.264/MPEG-4 AVC codec - Copyleft 2003-2018 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=1 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 vbv_maxrate=25000 vbv_bufsize=25000 crf_max=0.0 nal_hrd=none filler=0 ip_ratio=1.40 aq=1:1.00
Output #0, matroska, to '2019.06.01.2140.MP4.mkv':
    major_brand     : XAVC
    minor_version   : 16785407
    compatible_brands: XAVCmp42iso2
    encoder         : Lavf58.20.100
    Stream #0:0(und): Video: h264 (libx264) (H264 / 0x34363248), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=-1--1, 50 fps, 1k tbn, 50 tbc (default)
      creation_time   : 2019-06-01T19:40:52.000000Z
      handler_name    : Video Media Handler
      encoder         : Lavc58.35.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 25000000/0/0 buffer size: 25000000 vbv_delay: -1
    Stream #0:1(und): Audio: ac3 ([0] [0][0] / 0x2000), 48000 Hz, stereo, fltp, 160 kb/s (default)
      creation_time   : 2019-06-01T19:40:52.000000Z
      handler_name    : Sound Media Handler
      encoder         : Lavc58.35.100 ac3
frame= 1080 fps=4.1 q=31.0 Lsize=   30522kB time=00:00:21.59 bitrate=11578.4kbits/s speed=0.0815x    
video:30086kB audio:422kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.046764%

This is how the pictures look like imported and converted after running the import flow. We still have original 2019.06.01.2140.MP4 movie but we can delete it of course.

% exa ~/photo.NEW/2019.06.10.DUMP
2019.05.08.0732.jpg   2019.05.22.0548.jpg   2019.05.25.2111.jpg   2019.06.01.0914.jpg   2019.06.01.2140.jpg      2019.06.07.0509.jpg
2019.05.08.0732a.jpg  2019.05.22.0548a.jpg  2019.05.25.2111a.jpg  2019.06.01.0915.jpg   2019.06.01.2140.MP4      2019.06.07.0509a.jpg
2019.05.08.0732b.jpg  2019.05.22.0548b.jpg  2019.05.25.2111b.jpg  2019.06.01.2043.jpg   2019.06.01.2140.MP4.mkv  2019.06.07.0509b.jpg
2019.05.08.0733.jpg   2019.05.22.0549.jpg   2019.05.25.2111c.jpg  2019.06.01.2043a.jpg  2019.06.01.2140.XML      2019.06.07.2110.jpg
2019.05.22.0541.jpg   2019.05.22.0550.jpg   2019.05.27.0712.jpg   2019.06.01.2043b.jpg  2019.06.01.2140a.jpg     2019.06.07.2110a.jpg
2019.05.22.0541a.jpg  2019.05.22.0551.jpg   2019.05.27.0712a.jpg  2019.06.01.2043c.jpg  2019.06.01.2140b.jpg     2019.06.07.2110b.jpg
2019.05.22.0542.jpg   2019.05.23.0124.jpg   2019.05.27.0712b.jpg  2019.06.01.2043d.jpg  2019.06.01.2140c.jpg     2019.06.07.2110c.jpg
2019.05.22.0542a.jpg  2019.05.23.0124a.jpg  2019.05.27.0712c.jpg  2019.06.01.2043e.jpg  2019.06.01.2140d.jpg     2019.06.07.2110d.jpg
2019.05.22.0542b.jpg  2019.05.23.0124b.jpg  2019.05.27.0712d.jpg  2019.06.01.2043f.jpg  2019.06.01.2140e.jpg     2019.06.07.2110e.jpg
2019.05.22.0542c.jpg  2019.05.23.0124c.jpg  2019.05.27.0712e.jpg  2019.06.01.2043g.jpg  2019.06.01.2141.jpg
2019.05.22.0543.jpg   2019.05.23.1831.jpg   2019.05.27.0712f.jpg  2019.06.01.2043h.jpg  2019.06.01.2141a.jpg
2019.05.22.0543a.jpg  2019.05.25.2110.jpg   2019.05.27.0713.jpg   2019.06.01.2043i.jpg  2019.06.07.0508.jpg
2019.05.22.0543b.jpg  2019.05.25.2110a.jpg  2019.05.27.0713a.jpg  2019.06.01.2044.jpg   2019.06.07.0508a.jpg

These are differences in size before and after conversion – both for example picture and video.

% ls -lh ~/photo.NEW/2019.06.10.DUMP/2019.06.01.2140.MP4*
-rw-r--r--  1 vermaden  vermaden   134M 2019.06.01 21:41 /home/vermaden/photo.NEW/2019.06.10.DUMP/2019.06.01.2140.MP4
-rw-r--r--  1 vermaden  vermaden    30M 2019.06.10 22:57 /home/vermaden/photo.NEW/2019.06.10.DUMP/2019.06.01.2140.MP4.mkv

% ls -lh /media/mmcsd0s1/DCIM/100MSDCF/DSC00430.JPG ~/photo.NEW/2019.06.10.DUMP/2019.05.27.0712f.jpg
-rw-r--r--  1 vermaden  vermaden   4.4M 2019.06.10 22:53 /home/vermaden/photo.NEW/2019.06.10.DUMP/2019.05.27.0712f.jpg
-rw-r--r--  1 vermaden  vermaden   6.4M 2019.05.27 07:12 /media/mmcsd0s1/DCIM/100MSDCF/DSC00430.JPG

The best savings are in the video – more then 4 times smaller file. The pictures are about 30% smaller.

Totals of the size differences for the whole import are below. First the original dump from camera SD card.

% du -scm /media/mmcsd0s1/DCIM /media/mmcsd0s1/PRIVATE/M4ROOT/CLIP
400     /media/mmcsd0s1/DCIM
135     /media/mmcsd0s1/PRIVATE/M4ROOT/CLIP
534     total

… and converted/imported size.

% rm ~/photo.NEW/2019.06.10.DUMP/2019.06.01.2140.MP4

% du -scm /home/vermaden/photo.NEW/2019.06.10.DUMP/*jpg | tail -1
265     total

% du -scm /home/vermaden/photo.NEW/2019.06.10.DUMP/*mkv | tail -1
30      total

% du -scm ~/photo.NEW/2019.06.10.DUMP
295     /home/vermaden/photo.NEW/2019.06.10.DUMP
295     total

So after import and conversion the pictures went from 400 to 265 MB and movies (actually one movie) went from 135 to 30 MB. The most important thing is that I can import and convert this convent without any interactive and lengthy process.

These scripts (definitely the video renamer one) may be SONY related but nothing stops you from modifying them to the files provided by your camera manufacturer.

Feel free to share your photography flow πŸ™‚


Ghost in the Shell – Part 4

Long time no see. Its been a while since last post in the Ghost in the Shell series. Its also exactly one full year since I started this blog – from the first Ghost in the Shell series article – the Part 1 – that was published on 2018/03/15 day.

Today I would like to show you new pack of useful tricks and features for productive terminal/shell use. Lets start with something simple yet useful.

You may want to check other articles in the Ghost in the Shell series on the Ghost in the Shell – Global Page where you will find links to all episodes of the series along with table of contents for each episode’s contents.

Named Pipes

We all (or at least most :>) know and love pipes in UNIX. For the record – ls | grep match | awk '{print $3}' | sed 's/.jpg//g' – command ‘chains’ like that one πŸ™‚

What is a named pipe then? A manually defined pipe for special purposes. For example some applications – especially the so called Enterprise ones – often do not support UNIX pipes mechanisms – they only can dump something to a file. A great example of such Enterprise software is Oracle database whose dump command can only make dump to a file. With tool that supports UNIX pipes you would probably want to pipe that data to gzip(1)/xz(1) to compress it on the fly or even pipe it directly to ssh(1) to the Backup server for example, but not with Oracle.

This is where named pipes feature helps. We will create named pipe called /tmp/PIPE so Oracle’s dump command will be able to use it and on the other side of this pipe we will attach a pipe to gzip -9 command to compress that data on the fly.

Below example is from Linux system so mknod(1) command will be used. For example on FreeBSD you would use mkfifo(1) command for named pipe. Complete example of such named pipe is presented below.

root # cd /tmp
root # mknod /tmp/PIPE p
root # chown oracle:oinstall /tmp/PIPE
root # dd if=/tmp/PIPE bs=1M | gzip -9 > /mnt/oracle/oracle-database-backup.dmp.gz &

Now the /tmp/PIPE named pipe is ready to be used. When any process will start to write something to the /tmp/PIPE named pipe it will be automatically grabbed by dd(8) command and piped to the gzip(1) command that will compress that input and write it into the /mnt/oracle/oracle-database-backup.dmp.gz file.

Now we can start the Oracle dumping process with dump command.

root # su - oracle
oracle % dump file=/tmp/PIPE

When the dump command finishes its work you will find all your dumped data compressed in the /mnt/oracle/oracle-database-backup.dmp.gz file.

Other example of named pipes usage is my desktop dzen2 setup with unusual update schedule – described in detail in the FreeBSD Desktop – Part 13 – Configuration – Dzen2 article.

Modify Command Environment on the Fly

For most of the time we use export(1) builtin to export needed environment values that our command needs. You can then check what environment exported values are with the env(1) command of course … but you can use the same env(1) command to run any command with modified environment without exporting variables using export(1).

Here is brief example of this feature.

For the record – the gls(1) command is a GNU/Linux ls(1) command from sysutils/coreutils package/port but to make it work without name conflicts on FreeBSD where BSD ls(1) is also present it had to be renamed to gls(1).

% gls -l | head -1
total 8609K

% env LC_ALL=pl_PL.UTF-8 gls -l | head -1
razem 8609K

In the example above we run gls(1) command with default environment – I use en_US.UTF-8 locale daily. The second invocation with LC_ALL=pl_PL.UTF-8 modified environment made gls(1) command display its output in Polish (pl_PL.UTF-8) language. The word ‘razem‘ means ‘total‘ in Polish.

Other useful example may be using make(1) to build FreeBSD port with known vulnerabilities. By default FreeBSD’s build(7) system will not allow us to build such port (and that is good defaults) but if we know what we are doing we will use following spell.

# env DISABLE_VULNERABILITIES=yes make -C /usr/ports/security/bdes/ build install clean

Its also useful with commands that do not play well with UTF-8 input like tr(1) for example. When LC_ALL is set to en_US.UTF-8 it will throw an error upon as.

% tr -cd '0-9' < /dev/random | head -c 16
tr: Illegal byte sequence

We just wanted to generate random 16 numbers.

To make it work we will modify the LC_ALL environment for this invocation.

% env LC_ALL=C tr -cd '0-9' < /dev/random | head -c 16

Much better πŸ™‚

Other example with timezones using date(1) command and TZ variable as shown in the example below.

% date
Fri Mar 15 14:03:38 CET 2019

% env TZ=Australia/Darwin date 
Fri Mar 15 22:35:26 ACST 2019

The Real Path

The symlinks with ln(1) are very useful for many ways, to organize stuff, for quick fixes, for versioning … you will find tons of other use cases.

There is just one problem, if you make to many levels or symlinks or its just too much nested you do not know where you are anymore … this is where the realpath(1) comes handy. No matter how many levels of links you have made, it will tell you the truth – what is the current real path. The pwd(1) command will not help you here thou.

Here is a short example how it works.

% pwd
% ln -s /home/vermaden ASD
% cd ASD
% pwd
% realpath

Browsing the PATH

Many times I wanted to ‘browse’ through the PATH to search for something. As you possibly know the PATH variable stores paths that are colon (:) separated.

You can redefine the IFS variable which by default contains space ‘ ‘ which will work as field delimited for the for loop.

Here is the example.

% export IFS=":"

% for I in $( echo ${PATH} ); do echo ${I}; done

% for I in $( echo ${PATH} ); do find "${I}" -name ifconfig; done

The other way to do this is to use plain old tr tool to translate colons (:) into newlines (\n) so we will be able to use the while loop here.

Here is the tr(1) example.

% echo ${PATH} | tr ':' '\n' | while read I; do echo ${I}; done

% echo ${PATH} | tr ':' '\n' | while read I; do find ${I} -name dd; done

You can also achieve same thing using the Parameter Expansion in which we will change the colons (:) into newlines (\n) as shown in the example below.

% echo "${PATH//:/\n}"

# echo "${PATH//:/\n}" | while read I; do find ${I} -name camcontrol; done

Parameter Expansion

I will not show all possible Parameter Expansion methods – just the most useful ones.

The typical use is to get the extension of a file or to ’emulate’ basename(1) or dirname(1) commands – it will be faster to use Parameter Expansion instead of invoking these commands each time. Below are two tables showing what you will get from which Parameter Expansion method.

PARAMETER    RESULT                       DESC 
-----------  ---------------------------  --------------
${name}      kubica.polish.racing.legend  content
${name#*.}          polish.racing.legend  -
${name##*.}                       legend  extension
${name%%.*}  kubica                       -
${name%.*}   kubica.polish.racing         -

… and with slash (/) character.

PARAMETER    RESULT                       DESC 
-----------  ---------------------------  --------------
${name}      kubica/polish/racing/legend  content
${name#*/}          polish/racing/legend  -
${name##*/}                       legend  basename(1)
${name%%.*}  kubica                       root directory
${name%/*}   kubica/polish/racing         dirname(1)

You can also use Parameter Expansion methods to grab the protocol from an URL like shown below.

% URL="https://vermaden.wordpress.com"

% echo "${URL%%/*}"

Sort Human Readable Values

Its simple and easy to sort just numerical values, we use sort -n for that – but values sometimes comes in human readable form like 4G, 350M and 120K. To sort these properly you will have to use sort -h flag as shown in the example below.

% du -sh /usr/*
102M    /usr/bin
228G    /usr/home
9.0M    /usr/include
 53M    /usr/lib
 43M    /usr/lib32
116K    /usr/libdata
1.9M    /usr/libexec
365M    /usr/local
512B    /usr/obj
9.5M    /usr/sbin
 39M    /usr/share
251K    /usr/tests

% du -sh /usr/* | sort -h
512B    /usr/obj
116K    /usr/libdata
251K    /usr/tests
1.9M    /usr/libexec
9.0M    /usr/include
9.5M    /usr/sbin
 39M    /usr/share
 43M    /usr/lib32
 53M    /usr/lib
102M    /usr/bin
365M    /usr/local
228G    /usr/home

If the values are in the first column then its simple but what to do when the values are not in the first column? You will use -k parameter of sort(1) which takes which column to sort as argument. Needed example below sorted bu human readable values and on the second USED column.

% zfs list | sort -h -k 2
NAME                         USED  AVAIL  REFER  MOUNTPOINT
local/usr/obj                 88K   130G    88K  /usr/obj
local/var/cache/pkg          128K   130G   128K  /var/cache/pkg
local/var/cache              216K   130G    88K  none
local/var                    304K   130G    88K  none
sys/ROOT/11.1-RELEASE        482M  2.39G  6.04G  /
local/usr/ports              729M   130G   729M  /usr/ports
local/jail/nextcloud         927M   130G   897M  /jail/nextcloud
local/jail                  1.00G   130G   100M  /jail
local/usr/src               1.28G   130G  1.28G  /usr/src
local/usr                   1.99G   130G    88K  none
sys/ROOT/11.2-RELEASE       8.69G  2.39G  7.10G  /
sys/ROOT                    9.16G  2.39G    88K  none
sys                         9.17G  2.39G    88K  none
local/home                   281G   130G   281G  /home
local                        288G   130G    88K  none

Write a File from vi(1) with Different Rights

How many times you have opened a system configuration file like /etc/sysctl.conf or /etc/fstab in your favorite vi(1) editor, made some changes and then when you wanted to save it – no luck – you are trying to write to file owned by root with regular user … the Read-only file, not written; use ! to override. message will be displayed. Of course you can save that file somewhere else like your home directory and them move it with doas(1)/sudo(8)/su(8) help to original location and fix its rights … or you may do that in one step instead.

After opening a file with vi(1) and some changes to write a file with doas(1)/sudo(8) rights you just need to type this.

:w !doas tee %

Then exit the vi(1) editor with force.


Here is how it looks in the editor.

:w !doas tee %

File contents are displayed here.

Press any key to continue [: to enter more ex commands]: [ENTER]

Here is the ‘legend’ for that spell.

:      vi(1) prompt
w      write a file
!doas  invoke doas(1) command
tee    command that will be started using doas(1) command
%      tells vi(1) to use current filename

In this process the current vi(1) contents will be redirected using tee(1) with doas(1) rights to the current (open that you opened) filename.

Of course it also works in vim(1) or neovim(1) and if sudo(8) is your poison then just use sudo instead doas(1) there.

Search Contents of PDF Files

We all love plain text files then they can be searched using grep(1) for data that is interesting for us … but grep(1) does not work with PDF files … or should I say its pointless/useless to use grep(1) to search PDF files. Fortunately pdfgrep(1) command exists and works beautifully with PDF files – including colored output.

Recently FreeBSD Journal has been made free and you will like to search for bhyve articles in FreeBSD Journal issues then this is the command for you.

% cd books/unix-bsd-journal
% exa
FreeBSD Journal - 2014-01-02.pdf FreeBSD Journal - 2016-09-10.pdf
FreeBSD Journal - 2014-03-04.pdf FreeBSD Journal - 2016-11-12.pdf
FreeBSD Journal - 2014-05-06.pdf FreeBSD Journal - 2017-01-02.pdf
FreeBSD Journal - 2014-07-08.pdf FreeBSD Journal - 2017-03-04.pdf
FreeBSD Journal - 2014-09-10.pdf FreeBSD Journal - 2017-05-06.pdf
FreeBSD Journal - 2014-11-12.pdf FreeBSD Journal - 2017-07-08.pdf
FreeBSD Journal - 2015-01-02.pdf FreeBSD Journal - 2017-09-10.pdf
FreeBSD Journal - 2015-03-04.pdf FreeBSD Journal - 2017-11-12.pdf
FreeBSD Journal - 2015-05-06.pdf FreeBSD Journal - 2018-01-02.pdf
FreeBSD Journal - 2015-07-08.pdf FreeBSD Journal - 2018-03-04.pdf
FreeBSD Journal - 2015-09-10.pdf FreeBSD Journal - 2018-05-06.pdf
FreeBSD Journal - 2015-11-12.pdf FreeBSD Journal - 2018-07-08.pdf
FreeBSD Journal - 2016-01-02.pdf FreeBSD Journal - 2018-09-10.pdf
FreeBSD Journal - 2016-03-04.pdf FreeBSD Journal - 2018-11-12.pdf
FreeBSD Journal - 2016-05-06.pdf FreeBSD Journal - 2019-01-02.pdf
FreeBSD Journal - 2016-07-08.pdf

% pdfgrep -i -n bhyve *.pdf
FreeBSD Journal - 2014-01-02 - Old Release.pdf:6: machine hypervisors, such as BHy
FreeBSD Journal - 2014-01-02 - Old Release.pdf:6: BHyVe
FreeBSD Journal - 2014-01-02 - Old Release.pdf:6: BHyVe IS THE BSD Hypervisor, de
FreeBSD Journal - 2014-01-02 - Old Release.pdf:6: Grehan and Neel Natu. The desig
FreeBSD Journal - 2014-01-02 - Old Release.pdf:6: BHyVe requires Intel CPUs w
FreeBSD Journal - 2014-01-02 - Old Release.pdf:6: BHyVe appeared in FreeBSD 1
FreeBSD Journal - 2014-01-02.pdf:42: machine hypervisors, such as BHyVe, Virtual
FreeBSD Journal - 2014-01-02.pdf:42: BHyVe e d
FreeBSD Journal - 2014-01-02.pdf:42: BHyVe IS THE BSD Hypervisor, developed by P
FreeBSD Journal - 2014-01-02.pdf:42: Grehan and Neel Natu. The design goal of BH
FreeBSD Journal - 2014-01-02.pdf:42: BHyVe requires Intel CPUs with VT-x and
FreeBSD Journal - 2014-01-02.pdf:42: BHyVe appeared in FreeBSD 10-CURRENT in

Here is how it looks in the xterm(1) terminal.


Hope that today’s pack of spells will end up useful for you.


Wallpapers from Tech Pron

The Tech Pron at Twitter – @techno_pron – is a bot that posts aesthetic tech pics. Most of these computers pictures were made on a solid (or close to it) background color so I though it may be a cool idea to create wallpapers from them.

I have picked up 20 most interesting ones and made high resolution backgrounds of them. Here is their montage.


To download them all just follow this wallpapers-oldschool-machines.tar.gz file.

When needed use my random_wallpaper.sh handler from the https://github.com/vermaden/scripts repository to setup random wallpaper from directory.