Tag Archives: laptop

Quare FreeBSD?

I really wanted to make this article short … but I failed miserably. At least I tried to organize it well so one may get back to it after ‘some’ reading because its not a short lecture. I wanted to title it Why FreeBSD? but when you type that into your favorite duck.com search engine there are so many similar articles. I wanted it to have distinguished and unique name so I used Latin word for ‘why‘ which is ‘quare‘.

logo-freebsd

What FreeBSD can offer you that other operating systems does not? From all of the operating systems I used I find FreeBSD to suck the least. This post is not here to convince you to use or try FreeBSD – this you will have to do by yourself. This article will show you why FreeBSD is valuable or better alternative to other operating systems and is definitely not dying.

This is the Table of Contents for this article.

  • Base System
  • ZFS Boot Environments
  • Rescue
  • Audio
  • Jails
  • FreeBSD Ports Infrastructure
  • Updating/Building from Source
  • Storage
  • Init System
  • Linux Binary Compatibility
  • Simplicity
  • Evolution Instead Rewriting
  • Documentation
  • Community
  • Closing Thoughts

Base System

When you install a Linux system its just a bunch of RPM or DEB packages. For example of you install CentOS 7.8 Minimal variant you end up with several hundred RPM packages installed. After a week or month many of these packages will get updates sometimes making this CentOS system unusable or even unbootable (recent GRUB Boothole problem for example). On the contrary FreeBSD comes with a Base System concept. This means that when you install FreeBSD you install a minimal system as a whole. No packages or subsystems to be separately updated. Just whole Base System. That means that /boot /bin /sbin /usr /etc /lib /libexec /rescue directories are untouchable by any packages. When you decide to install packages (or build them using FreeBSD Ports) they will all fall into the /usr/local prefix. That means /usr/local/etc for configuration. The /usr/local/bin and /usr/local/sbin directories for binaries. The /usr/local/lib and /usr/local/libexec for libraries and so on. The FreeBSD Base System kernel modules are kept in the same dir along with the kernel in the /boot/kernel directory. To make things tidy all kernel modules that are provided by packages go into the /boot/modules dir. Everything has its place and its separated.

That is separation between Base System binaries (at /bin /sbin /usr/bin /usr/sbin dirs) and Third Party Packages maintained by pkg(8) and are located at /usr/local/bin and /usr/local/sbin dirs. We all know differences between bin (user) and sbin (root) binaries but in FreeBSD there is also another more UFS related separation. When there was only UFS filesystem in the FreeBSD world the /bin and /sbin binaries were available at boot after the root (/) filesystem was mounted and yet before /usrย  filesystem was mounted – this is historical (and still useful in the UFS setups) distinction dating to old UNIX days. In ZFS setups it does not matter as all files are on ZFS pool anyway.

The FreeBSD Base System separation also helps with another thing – if any package gets the ‘great’ idea to install new compiler named cc and override the default system compiler … or to add libraries/includes in such a way that makes it super hard to get back into a working system. If some random FreeBSD package would add libc.so to /usr/local/lib dir then you are covered and not prevented from running programs as usual because FreeBSD system binaries are linked to stuff in /usr/lib dir. This is why there is PATH variable on UNIX systems (and FreeBSD as well) to set which directories should be searched for binaries first. On FreeBSD by default its set search Base System binaries dirs first and then Third Party Packages later.

You can update (or not) the Base System separately from the installed packages with freebsd-update(8) command when using RELEASE or by recompiling with make buildworld and make installworld commands when using STABLE/CURRENT systems. When it comes to packages you can update them using the pkg(8) tool or portmaster when building from FreeBSD Ports tree under /usr/ports dir. That means that any packages updates will not touch your FreeBSD Base System at all. For example when you mess up (and I have done that in the beginning of my FreeBSD journey) the compiled ports and packages and you want to start over the only thing you have to do is remove /usr/local and /boot/modules and /var/db/pkg directories. That’s it. You are just reverted to your Base System and can start over. This is just not possible when using Linux system. Even with Gentoo that many concepts are based on FreeBSD ideas does not have Base System feature. This Base System also have additional feature. Because its separated from packages version no one stops you from running oldshool FreeBSD 9.0 from 2012 and install there latest Firefox 80 or LibreOffice 7.0. You can not install latest Firefox on Ubuntu from 2012 …

One may be ‘afraid’ that such Base System independent from installed packages would take more space but nothing far more from the truth. The fresh installed FreeBSD 12.1 system uses less then 1 GB of disk space and takes less then 75 MB of RAM with sshd(8) running. For the comparison fresh CentOS 7.8 install with ‘Minimal’ set chosen takes 1.1 GB of disk space and uses more then 100 MB RAM with sshd(8) running. Such CentOS system is really naked and really needs more packages to be usable while FreeBSD with its Base System is far more capable and powerful and comes along with builtin latest version of LLVM/CLANG compiler suite for example.

More on the Base System topic:

ZFS Boot Environments

I have talked about this many times and probably one time too less because Linux world still ignores this bless. Having ZFS Boot Environments its such a game changer that once you realize how powerful it is you will never want to use a system that does not support it. The idea is that you can snapshot a running system at any moment of time and then reboot into that moment (or snapshot) if something happened. Its perfect solution for upgrade or changes to the system. The FreeBSD systems are already well ‘protected’ from problems arising after updating the packages but ZFS Boot Environments takes this to a whole new level.

groundhog

Like in the movie Groundhog Day (1993) with ZFS Boot Environments you will have limitless chances to get your shit toghether. Even the Base System updates and changes are protected by it. You can even transport that Boot Environment by using zfs send and zfs recv commands to other system … or propagate it on many systems. You can create Jails containers from it … or install new version of FreeBSD in the new Boot Environment and reboot into it while still having your older ‘production’ system untouched.

More on the ZFS Boot Environments topic:

Rescue

When you really mess up to the point that even Base System concept or ZFS Boot Environments feature did not stopped you from killing your FreeBSD installation then there is one more level of rescue … the Rescue subsystem.

rescue

You have about 150 statically linked binaries available at your disposal for the rescue mission of that FreeBSD installation. You probably think now that if its so many binaries then it probably takes a lot of space … nothing far more from the truth. Its actually one static binary with hardlinks … and it takes whooping 11 MB of disk space.

# ls -lh /rescue | head -5
total 1118446
-r-xr-xr-x  146 root  wheel    11M 2020.02.19 21:10 [
-r-xr-xr-x  146 root  wheel    11M 2020.02.19 21:10 bectl
-r-xr-xr-x  146 root  wheel    11M 2020.02.19 21:10 bsdlabel
-r-xr-xr-x  146 root  wheel    11M 2020.02.19 21:10 bunzip2

They Rescue subsystem even contains such binaries as bectl(8) for ZFS Boot Environments management or zfs(8) and zpool(8) commands for the ZFS filesystem. Here is complete list of these binaries.

# ls /rescue
[           dd               fsck_ffs      init       mdmfs          ping      rtsol        unlink
bectl       devfs            fsck_msdosfs  ipf        mkdir          ping6     savecore     unlzma
bsdlabel    df               fsck_ufs      iscsictl   mknod          pkill     sed          unxz
bunzip2     dhclient         fsdb          iscsid     more           poweroff  setfacl      unzstd
bzcat       dhclient-script  fsirand       kenv       mount          ps        sh           vi
bzip2       disklabel        gbde          kill       mount_cd9660   pwd       shutdown     whoami
camcontrol  dmesg            geom          kldconfig  mount_msdosfs  rcorder   sleep        xz
cat         dump             getfacl       kldload    mount_nfs      rdump     spppcontrol  xzcat
ccdconfig   dumpfs           glabel        kldstat    mount_nullfs   realpath  stty         zcat
chflags     dumpon           gpart         kldunload  mount_udf      reboot    swapon       zdb
chgrp       echo             groups        ldconfig   mount_unionfs  red       sync         zfs
chio        ed               gunzip        less       mt             rescue    sysctl       zpool
chmod       ex               gzcat         link       mv             restore   tail         zstd
chown       expr             gzip          ln         nc             rm        tar          zstdcat
chroot      fastboot         halt          ls         newfs          rmdir     tcsh         zstdmt
clri        fasthalt         head          lzcat      newfs_msdos    route     tee          
cp          fdisk            hostname      lzma       nextboot       routed    test         
csh         fsck             id            md5        nos-tun        rrestore  tunefs       
date        fsck_4.2bsd      ifconfig      mdconfig   pgrep          rtquery   umount   

More on the Rescue topic:

Audio

Not many people expect from FreeBSD to shine in that department but it shines a lot here and not from yesterday but from decades. Remember when Linux got rid of the old OSS subsystem with one channel and came up with ‘great’ idea to write ALSA? I remember because I used Linux back then. Disaster is very polite word to describe Linux audio stack back then … and then PulseAudio came and whole Linux audio system got much worse. Back then because of that one OSS channel and many ALSA channels meant that ONLY ONE application with OSS backend could do the sound (for example WINE). But if another application would want to ‘make’ sound using OSS and you already have WINE started then it will be soundless because that one and only OSS channel was already taken. And remember that ALSA was so bad back then that KDE or GNOME made their own sound daemons mixing audio in userspace that were incompatible with each other. That means if you used KDE and GNOME apps back then you could have sound from GNOME apps but not from KDE apps or vice versa. One big fucking audio hell on Linux.

audio

Lets get back to FreeBSD audio then. What FreeBSD offered? A whooping 256 OSS channels mixed live in kernel for low latency. Everything audio related just worked out of the box – and still works today. You could have WINE or KDE/GNOME sound backends attached to their OSS channels and also ALSA apps getting their sound device without a problem. Even when you plugged a 5.1 surround system into FreeBSD it worked out of the box without any configuration and applications were able to use it immediately. That FreeBSD audio supremacy remains today as PulseAudio sound mixing in userspace while generally working incorporates large latency on Liunx compared to in kernel FreeBSD mixing with low latency.

Comrade meka suggested that FreeBSD is also the only OS which has virtual_oss that allows mixing/resampling/compressing in user space and allows one to have Bluetooth headphones and USB microphone represented as single sound card.

More on the Audio topic:

Jails

The FreeBSD Jails are one of the oldest OS Level Virtualization implementations dating back to 1999. Even the Solaris Zones/Containers came five years later in 2004.

containers

After Docker was introduced in Linux the term OS Level Virtualization became less used to the Containers term and now the FreeBSD Jails along with Solaris Zones/Containers are named 1st generation containers. But that naming nomenclature change does not make FreeBSD Jails less powerful. They are also really brain dead simple to use. You just need a directory – for example /jail/nextcloud – where you will extract the FreeBSD Base System for desired release version – for example base.txz from 12.1-RELEASE and create the Jail config in the /etc/jail.conf file as shown below.

# mkdir -p /jail/nextcloud
# fetch -o - http://ftp.freebsd.org/pub/FreeBSD/releases/amd64/12.1-RELEASE/base.txz | tar --unlink -xpJf - -C /jail/nextcloud
# cat /etc/jail.conf
nextcloud {
  host.hostname = nextcloud.local;
  ip4.addr = 10.0.0.100;
  path = /jail/nextcloud;
}

Now you can start you Jail right away.

# service jail onestart nextcloud
Starting jails: nextcloud.

Voila! Your FreeBSD Jail is already running.

# jls
   JID  IP Address      Hostname                      Path
     1  10.0.0.100      nextcloud.local               /jail/nextcloud

You can of course have a trimmed down version of FreeBSD Base System in the Jail if that is needed. The ZFS filesystem also helps here greatly because with zfs clone only your ‘base’ Jail will take space and only the changes you make to Jails created from it. Thanks to other FreeBSD subsystem – the Linux Binary Compatibility – you can also create a Linux Jail – for example running Devuan Jail.

The FreeBSD Jails are also very lightweight. You can boot and use about 1000 FreeBSD Jails on a single FreeBSD system with 4 GB RAM.

They are also very easy to debug and troubleshoot comparing even to plain Docker – not to even mention Kubernetes which requires whole team of highly skilled people to maintain.

The FreeBSD Jails may be configured/managed only by the Base System utilities such as jls(8)/jexec(8) but you can also select from many third party Jail management frameworks. From all available ones I would choose BastilleBSD because of their modern approach and many ready to use templates for all needed use cases.

More on the Jails topic:

FreeBSD Ports Infrastructure

This is one of another examples why FreeBSD rocks that much. When you install Ubuntu or CentOS in some version there is chance that you will end up with not latest versions of packages but with versions that were quite up-to-date when this distribution version was released. Its especially visible in the CentOS world (and its upstream enterprise source system from Red Hat) where packages are quite up-to-date when .0 (dot zero) release is published but are VERY outdated when .8 or .9 incarnation of that release is available. Not to even mention that Firefox for example is released every month …

packages

As I said before when describing the FreeBSD Base System the FreeBSD Ports (and packages built from it available through pkg(8)) are independent. That means that third party software from FreeBSD Ports is almost always up-to-date (or very close to it). You can even check it on the repology.org site for the details. Below you will find a ‘snapshot’ of the repology.org stats from time of writing this article. The ‘online’ table is very long so I copy/pasted just the systems relevant to the article.

repology

One of the other advantages of FreeBSD Ports is that it offers really MASSIVE amount of software counting 40354 ports when writing this article and still rising. Amount of ready to be installed packages are little smaller with more then 32000 available.

I once migrated for a while to OpenSolaris in 2009 on my Dell Latitude D630 laptop because I really liked all the Solaris features (including ZFS and ZFS Boot Environments that were not available on FreeBSD back then) and the OpenSolaris GNOME based desktop was pretty nice back then even with Time Slider feature for ZFS snapshots in the Nautilus file manager. I got working WiFi connection, sound was working, generally everything on my laptop was supported and working with OpenSolaris … but there was no software. Of course ‘large’ projects like GIMP or OpenOffice was available even in the default pkg(8) repository but not much else. There was less then 4000 packages back then on OpenSolaris while about 25000 packages on FreeBSD if I recall correctly.

You can also easily browse available FreeBSD Ports (and its options) on the web by using the https://freshports.org/ page.

ports

The count of FreeBSD Ports is one thing, the features is another. No matter which Linux distribution you are using you will find a software that was compiled and shipped without that needed flag that you desperately need. If you find such software on FreeBSD it ‘hurts’ only for a moment because you can VERY EASILY recompile that software with needed options and replace that ‘default’ package with yours. For example the FreeBSD project is afraid to provide packages of Lame because of existing MP3 patents, so multimedia/ffmpeg package is built without MP3 support (with --disable-libmp3lame flag). That is why I have my own audio/lame and multimedia/ffmpeg packages built with my configure options and that is very easy to achieve. You need to go to the /usr/ports/multimedia/ffmpeg dir type make config and select [x] LAME at the ncurses dialog. Your chosen options will be saved as plain /var/db/ports/multimedia_ffmpeg/options file. If you remove that file (or type make rmconfig) then these custom options will reset to defaults. Then you type make build deinstall install clean and your port with new options is ready and installed as package. Nothing more is needed. You can even lock that package from the pkg(8) upgrades with pkg lock -y ffmpeg command so it will not be modified later but its better to rebuild such packages everytime you do a pkg upgrade procedure because of libraries versions bump and changes. While its very easy and fast to create a script with these commands to make it more automated you can also use other parts of the FreeBSD Ports infrastructure – enter Poudriere (or Synth) – more on that in the next part.

You also do not have to configure each port that way (which could be PITA for large amount of ports) but you may specify your needed (OPTIONS_SET) or unwanted (OPTIONS_UNSET) parameters only once globally using the /etc/make.conf file. You can also specify which default versions of software you want to use, for example Apache 2.2 instead of 2.4 and PHP 7.0 instead of 7.2. You can find all default versions in the /usr/ports/Mk/bsd.default-versions.mk file. Once you setup these options you can build/rebuild or update your packages from FreeBSD Ports by portmaster(8) tool. Like on Gentoo Linux with USE flags. But this is the original. Gentoo took all/most of its ideas from FreeBSD system and its Ports infrastructure.

The Poudriere is a build framework that uses FreeBSD Ports and FreeBSD Jails to build requested packages in clean reproducible way. You can create whole new binary package repository for pkg(8) command to use with it. I mentioned Synth because while Poudriere is often used to produce whole package repository the Synth is usually used just to rebuild several packages that does not fit your needs.

There is one important things about FreeBSD Ports that is often misunderstood by newcomers. What is the difference between the Ports and packages that are fetched and installed by pkg(8) tool? Its quite simple. A package is just a build and installed port. Nothing more or less. When you use the binary packages using pkg(8) command you are using packages that someone (the FreeBSD project in that case) built for you from the FreeBSD Ports in some point in time. While FreeBSD strives to maintain as up-to-date built packages as possible its the nature of FreeBSD Ports that they are always more up-to-date then the built packages. That is why you may build and install a new version of needed packages by yourself using FreeBSD Ports. One may think of such usage when it comes to security holes. When some locally executed commands (like file(1) for example) has a security hole then its not critical for you to update it as fast as possible because that security hole can be harmless for you, but when new version of Firefox fixes very important security hole then its better to update from FreeBSD Ports version faster because waiting 2 days for the package to be built (along with other packages) can be too long.

More on the FreeBSD Ports topic:

Updating/Building from Source

While the FreeBSD Ports infrastructure is for third party software the FreeBSD Base System (or its parts) also can be easily and convenient build from source. The FreeBSD kernel config is also very small and simple. While Linux kernel config contains thousands of options – 4432 for example in the default CentOS 8.2 install the FreeBSD GENERIC config has about 20 times options less – only 260 options. But that does not saturate the topic. You can start with MINIMAL FreeBSD kernel config which has only 75 options specified.

Linux # grep -c '^CONFIG' /boot/config-$( uname -r )
4432

FreeBSD # grep -c -E '^(device|options)' /usr/src/sys/amd64/conf/GENERIC
260

FreeBSD # grep -c -E '^(device|options)' /usr/src/sys/amd64/conf/MINIMAL
75

… and its not only about smaller amount of options. Can you tell my how many steps (and which ones are required) to rebuild CentOS or Ubuntu for example without Bluetooth support?

code

On the contrary its very simple (and fast) on the FreeBSD side. While /etc/make.conf file is used to enable/disable Ports options the /etc/src.conf file is used to enable/disable FreeBSD Base System options while building it from source. To build FreeBSD without Bluetooth support just add WITHOUT_BLUETOOTH=yes to the /etc/src.conf file and type these to build it:

# beadm create safe
# cd /usr/src
# make buildworld kernel
# reboot
# cd /usr/src
# make installworld
# mergemaster -iU
# reboot

Voila! You now have FreeBSD without Bluetooth support … and if any of the steps failed or because of your lack of experience/expertise your FreeBSD system does not boot or is broken you can use tools from /rescue to try to fix it (or at least figure out what is broken) and when you do not want to cope with this jest select safe ZFS Boot Environment at the FreeBSD loader(8) to boot to the system before you started building modified version of FreeBSD. Yes, You are bulletproof here. While having 294 WITHOUT_X options and 125 WITH_X options you can really tune FreeBSD Base System to your needs.

# zgrep -c WITHOUT_ /usr/share/man/man5/src.conf.5.gz
294

# zgrep -c WITH_ /usr/share/man/man5/src.conf.5.gz
125

The big downside of updating FreeBSD by source is that you can not use the freebsd-update tools to do it … but nothing stops you from creating your own FreeBSD Update Server so you will be able to use freebsd-update by adding updates using a CURRENT or STABLE system instead of RELEASE. That process is described in the Build Your Own FreeBSD Update Server article of official FreeBSD documentation.

More on the FreeBSD Source Updates/Builds topic:

Storage

Storage is one of the parts where FreeBSD really shines. Lots of people adore FreeBSD for well integrated ZFS filesystem and its really true. ZFS in FreeBSD has always been first class citizen. Lately OpenZFS 2.0 has been also integrated from the upstream joint FreeBSD and Linux repository. More and more FreeBSD features and solutions are using ZFS features.

openzfs

Most of these people that like integrated ZFS in FreeBSD do not know about the FreeBSD GEOM modular disk transformation framework which provides various storage related features and utilities like software RAID0/RAID1/RAID10/RAID3/RAID5 configurations or transparent encryption of underlying devices with GELI/GDBE (like LUKS on Linux). It also allows transparent filesystem journaling for ANY filesystem with GJOURNAL (yes also for FAT32 or exFAT) or allows one to export block devices over network with GEOM GATE devices (like NFS for block devices).

storage

FreeBSD also has its own FUSE implementation which allows all these FUSE based filesystems to work natively on FreeBSD. While lots of Linux folks know DRBD probably very few of them knew that FreeBSD comes with its own DRBD like solution called HAST – which does exactly the same thing. While ZFS has a lot features and possibilities FreeBSD still maintains and develops fast and small memory footprint UFS filesystem which today is used either with Soft Updates (SU) or Journaled Soft Updates (SUJ) depending on the use case. For example 10 TB data on UFS filesystem with Journaled Soft Updates (SUJ) takes about 1 minute under fsck(8). These storage solutions are available from FreeBSD Base System alone. The FreeBSD Ports offers much more with distributed filesystems solutions such as CEPH, LeoFS, LizardFS or Minio for Amazon S3 compatible storage.

More on the Storage topic:

Init System

FreeBSD offers really simple yet very powerful init system. It has system wide config under /etc/rc.conf file when you can enable/disable needed services with service_enable=YES and service_enable=NO stanzas. You do not even need to launch vi(1) to add them – just type sysrc service_enable=YES and they are added to the /etc/rc.conf file. There are also default values and services that are enabled and you will find them – along with many comments – in the /etc/defaults/rc.conf file. Each FreeBSD service file has PROVIDE/REQUIRE stanzas which are then used to automatically order the services to start. Services that can be run in parallel are started in parallel to save time. For example its pointless to start sshd(8) daemon without network. To start or stop the serivice you need to type service sshd start or service sshd stop command. But when a service is not enabled in the /etc/rc.conf file then you need to used add onestart and onestop instead. The Base System separation remains here as FreeBSD Base System services are located at /etc/rc.d directory and third party applications from ports/packages are kept under /usr/local prefix which means /usr/local/etc/rc.d dir.

When using systemd(1) you never know how the services gonna start because it will be different each time. Zero determinism. On FreeBSD you know exactly which services will start when because they are always ordered in the same state according to the PROVIDE/REQUIRE stanzas. FreeBSD also offers tools that will tell you the exact order – rcorder(8) – which can be used for all services, Base System services or third party services separately. There is also service -r command that will show you what was the orfer at the boot time.

# rcorder /etc/rc.d/* | head
/etc/rc.d/growfs
/etc/rc.d/sysctl
/etc/rc.d/hostid
/etc/rc.d/zvol
/etc/rc.d/dumpon
/etc/rc.d/ddb
/etc/rc.d/geli
/etc/rc.d/gbde
/etc/rc.d/ccd
/etc/rc.d/swap

# rcorder /usr/local/etc/rc.d/* | tail
/usr/local/etc/rc.d/hald
/usr/local/etc/rc.d/git_daemon
/usr/local/etc/rc.d/fscd
/usr/local/etc/rc.d/cupsd
/usr/local/etc/rc.d/cups_browsed
/usr/local/etc/rc.d/clamav-clamd
/usr/local/etc/rc.d/clamav-milter
/usr/local/etc/rc.d/clamav-freshclam
/usr/local/etc/rc.d/avahi-dnsconfd
/usr/local/etc/rc.d/aria2

# rcorder /etc/rc.d/* /usr/local/etc/rc.d/* 2> | grep -C 3 sshd
/etc/rc.d/ubthidhci
/etc/rc.d/syscons
/etc/rc.d/swaplate
/etc/rc.d/sshd
/etc/rc.d/cron
/etc/rc.d/jail
/etc/rc.d/localpkg

Adding new service to FreeBSD is also very easy as template for new service is very small and simple.

#!/bin/sh

. /etc/rc.subr

name=dummy
rcvar=dummy_enable

start_cmd="${name}_start"
stop_cmd=":"

load_rc_config $name
: ${dummy_enable:=no}
: ${dummy_msg="Nothing started."}

dummy_start()
{
	echo "$dummy_msg"
}

run_rc_command "$1"

If its not simple enought for you there is dedicated FreeBSD article about writing them – Practical rc.d Scripting in BSD – available here.

More on the Init System topic:

Linux Binary Compatibility

While Linux can not be FreeBSD – the FreeBSD can be Linux – and its not some slow emulation – its implementation of Linux system calls. There was time when enterprises used to work with Linux only applications (not available on FreeBSD by then) using the Linux Binary Compatibility on FreeBSD because it was faster then running them natively on Linux – FreeBSD Used to Generate Spectacular Special Effects – an official FreeBSD Press Release about FreeBSD being used to generate spacial effects to the one of the best movies of all time – The Matrix (1999).

matrix

Today the LINUX_COMPAT is also natively fast and allows one to run Linux applications – even Linux games in X11 with hardware acceleration for graphics. Think of it as WINE but for Linux applications. It lives under /compat/linux directory. It even implements Linux /proc virtual filesystem which can be mounted at the /compat/linux/proc dir but its not mandatory. For any software that does not come with source code and works on Linux the Linux Binary Compatibility saves the day. For example the f.lux project. Before I got to know Redshift I used f.lux Linux binary using LINUX_COMPAT to suppress blue spectrum light from my FreeBSD screen. The Linux Binary Compatibility subsystem can also be used to run Linux bases FreeBSD Jails – with Devuan for example.

More on the Linux Binary Compatibility topic:

Simplicity

FreeBSD is simple but not coarse/ornery. For example as Linux the FreeBSD system also supports the /proc virtual filesystem but on FreeBSD its optional and not used by default while Linux could not live without it. But while Linux has mandatory /proc it also has another virtual filesystem residing under /sys … but why Linux people need two different virtual filesystems with similar purposes? Why they could not create everything under /proc as it already existed. That is big enigma for my sanity.

But /sys is not the end of that madness. Its just a beginning.

What about these?

  • securityfs
  • devpts
  • cgroup
  • pstore
  • bpf
  • configfs
  • selinuxfs
  • systemd-1
  • mqueue
  • debugfs
  • hugetlbfs

Take a look at the FreeBSD mount(8) output after the default install on ZFS.

FreeBSD # mount
zroot/ROOT/12.1 on / (zfs, local, noatime, nfsv4acls)
devfs on /dev (devfs, local, multilabel)
zroot/tmp on /tmp (zfs, local, noatime, nosuid, nfsv4acls)
zroot/var/mail on /var/mail (zfs, local, nfsv4acls)
zroot/usr/home on /usr/home (zfs, local, noatime, nfsv4acls)
zroot/var/crash on /var/crash (zfs, local, noatime, noexec, nosuid, nfsv4acls)
zroot/var/log on /var/log (zfs, local, noatime, noexec, nosuid, nfsv4acls)
zroot/var/audit on /var/audit (zfs, local, noatime, noexec, nosuid, nfsv4acls)
zroot/var/tmp on /var/tmp (zfs, local, noatime, nosuid, nfsv4acls)
zroot/usr/src on /usr/src (zfs, local, noatime, nfsv4acls)
zroot/usr/ports on /usr/ports (zfs, local, noatime, nosuid, nfsv4acls)

Several ZFS datasets and one virtual devfs filesystem for /dev directory. With install on UFS it would be similar with several UFS partitions mounted instead of ZFS datasets.

Take a look at the CentOS 8.2 installation with just one physical root (/) XFS filesystem.

[root@centos8 ~]# mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=919388k,nr_inodes=229847,mode=755)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime,seclabel)
bpf on /sys/fs/bpf type bpf (rw,nosuid,nodev,noexec,relatime,mode=700)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuset)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,memory)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,blkio)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,hugetlb)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpu,cpuacct)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,freezer)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,rdma)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,devices)
configfs on /sys/kernel/config type configfs (rw,relatime)
/dev/sda1 on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=34,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=17309)
mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel)
debugfs on /sys/kernel/debug type debugfs (rw,relatime,seclabel)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel,pagesize=2M)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,seclabel,size=187088k,mode=700)

Fuck me. Its even really hard to just find any REAL filesystem there … fortunately we can ask for only XFS filesystems to display.

[root@centos8 ~]# mount -t xfs
/dev/sda1 on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)

Lets get on the networking now. Lets assume that you want to make standard enterprise networking setup on a physical server with two interfaces aggregated together into highly available interface bond0 (lagg0 on FreeBSD) and then you want to put VLAN tag and IP address on that VLAN. The CentOS 7.x/8.x installer (Anaconda) will welcome you with this mess.

[root@centos7 ~]# ls -1 /etc/sysconfig/network-scripts/ifcfg-*
ifcfg-Bond_connection_1
ifcfg-eno49
ifcfg-eno49-1
ifcfg-eno50
ifcfg-eno50-1
ifcfg-VLAN_connection_1

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-Bond_connection_1
DEVICE=bond0
BONDING_OPTS="miimon=1 updelay=0 downdelay=0 mode=active-backup"
TYPE=Bond
BONDING_MASTER=yes
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_PRIVACY=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME="Bond connection 1"
UUID=ca85417f-8852-43bf-96ee-5bd3f0f83648
ONBOOT=yes

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eno49
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=eno49
UUID=2f60f50b-38ad-492a-b90a-ba736acf6792
DEVICE=eno49
ONBOOT=no

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eno49-1
HWADDR=xx:xx:xx:xx:xx:xx
TYPE=Ethernet
NAME=eno49
UUID=342b8494-126d-4f3a-b749-694c8c922aa1
DEVICE=eno49
ONBOOT=yes
MASTER=bond0
SLAVE=yes

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eno50
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=eno50
UUID=4fd36e24-1c6d-4a65-a316-7a14e9a92965
DEVICE=eno50
ONBOOT=no

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eno50-1
HWADDR=xx:xx:xx:xx:xx:xx
TYPE=Ethernet
NAME=eno50
UUID=a429b697-73c2-404d-9379-472cb3c35e06
DEVICE=eno50
ONBOOT=yes
MASTER=bond0
SLAVE=yes

[root@centos7 ~]# cat/etc/sysconfig/network-scripts/ifcfg-VLAN_connection_1
VLAN=yes
TYPE=Vlan
PHYSDEV=ca85417f-8852-43bf-96ee-5bd3f0f83648
VLAN_ID=601
REORDER_HDR=yes
GVRP=no
MVRP=no
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
IPADDR=10.20.30.40
PREFIX=24
GATEWAY=10.20.30.1
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_PRIVACY=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME="VLAN connection 1"
UUID=90f7a9bb-1443-4adf-a3eb-86a03b23ecfb
ONBOOT=yes

For the record – I have choosen ‘STATIC’ IPv4 address but installer made these interfaces to use DHCP and that STATIC address. That could be a bug but lets get to the point.

After manual fixing with vi(1) (and hour later) this is how it supposed to look.

[root@centos7 ~]# cat /etc/sysconfig/network
GATEWAY=10.20.30.1
NOZEROCONF=yes

[root@centos7 ~]# ls -1 /etc/sysconfig/network-scripts/ifcfg-*
ifcfg-bond0
ifcfg-bond0.601
ifcfg-eno49
ifcfg-eno50

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond0
BONDING_OPTS="miimon=1 updelay=0 downdelay=0 mode=active-backup"
TYPE=Bond
BONDING_MASTER=yes
BOOTPROTO=none
IPV4_FAILURE_FATAL=no
IPV6INIT=no
ONBOOT=yes

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-bond0.601
VLAN=yes
TYPE=Vlan
VLAN_ID=601
DEVICE=bond0.601
REORDER_HDR=yes
GVRP=no
MVRP=no
BOOTPROTO=none
IPADDR=10.20.30.40
PREFIX=24
IPV4_FAILURE_FATAL=no
IPV6INIT=no
ONBOOT=yes

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eno49
BOOTPROTO=none
IPV4_FAILURE_FATAL=no
IPV6INIT=no
TYPE=Ethernet
NAME=eno49
DEVICE=eno49
ONBOOT=yes
MASTER=bond0
SLAVE=yes

[root@centos7 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eno50
BOOTPROTO=none
IPV4_FAILURE_FATAL=no
IPV6INIT=no
TYPE=Ethernet
NAME=eno50
DEVICE=eno50
ONBOOT=yes
MASTER=bond0
SLAVE=yes

Better … but still takes A LOT OF SPACE and several files to cover that quite simple setup. Not to mention its level of complication and making that very error prone way. The same configuration on FreeBSD would take just 7 lines within single /etc/rc.conf file as shown below.

ifconfig_fxp0="up"
ifconfig_fxp1="up"
cloned_interfaces="lagg0"
ifconfig_lagg0="laggproto failover laggport fxp0 laggport fxp1"
vlans_lagg0="601"
ifconfig_lagg0_601="inet 10.20.30.40/24"
defaultrouter="10.20.30.1"

What about the boot process? FreeBSD boots from root on ZFS partition with just small 512 KB not mountable partition. No separate /boot device is needed. On the other side Linux always needs that separate /boot partition filled with GRUB modules. No matter if its ZFS or LVM. That is why implementation of ZFS Boot Environments is quite complicated on Linux bacause even if you have root on ZFS on a Linux system there is still unprotected /boot filesystem that can not be snapshoted with ZFS and has to be protected in old classic way which kill the idea of ZFS Boot Environments or Linux.

FreeBSD is really simple and well thought operating system. But also a very underestimated one.

Evolution Instead Rewriting

How many Linux tools or subsystems are abandoned or superseeded by new ones? Why the ifconfig(8) command was not updated with new options and instead a new ip(8) command was introduced? Same with netstat(8) being replaced by ss(8). Same with arp(8)/iwconfig/route(8) and many more. What about whole init system? The Linux world has been taken over by systemd(1) whenever you like it or not. Even distributions that have grown their mature init systems like Ubuntu with its Upstart has moved to systemd(1) altogether. The distributions that do not use it are very few and considered a niche today.

evolution

In the FreeBSD land on the countary such things happen only if there is no other way to implement new things. Its the last thing wanted in the FreeBSD. FreeBSD evolves and is developed with stability and backward compatibility in mind. Userland tools are grown and updated with new options instead of rewriting them over and over again. Not to mention how many new bugs are introduced by changing one tool to another.

More on the Evolution Instead Rewriting topic:

Documentation

Having system that can do almost anything but not knowing how to do that makes that system pretty useless (or at least pretty PITA to use). FreeBSD offers second to none documentation that is actively maintained and updated. Along with its legendary FreeBSD Handbook and FreeBSD FAQ the FreeBSD project also offers official FreeBSD Articles about various FreeBSD topics. The Man Pages are also very detailed and contain many examples. There is also FreeBSD Wiki page for work in progress documentation and ideas related to FreeBSD development and if you have any problems or questions related to FreeBSD there are official FreeBSD Forums and oldschool Mailing Lists available.

documentation

These were only the official project knowledge sources but there are also lots of FreeBSD books. Here are the best and up-to-date ones.

  • Absolute FreeBSD – Complete Guide to FreeBSD – 3nd Edition (2019)
  • Beginning Modern Unix (2018)
  • Book of PF – 3rd Edition (2015)
  • Design and Implementation of FreeBSD 11 Operating System – 2nd Edition (2015)
  • FreeBSD Device Drivers (2012)
  • FreeBSD Mastery – ZFS (2015)
  • FreeBSD Mastery – Advanced ZFS (2016)
  • FreeBSD Mastery – Storage Essentials (2014)
  • FreeBSD Mastery – Specialty Filesystems (2015)
  • FreeBSD Mastery – Jails (2019)

There are also two magazines that are dedicated to BSD and FreeBSD systems. Both are free and cover lots of interesting topics regarding FreeBSD.

With all this knowledge and support its really hard not to achieve what you need/want with FreeBSD system.

Community

Last but not least and I would say its even more important then good documentation (which FreeBSD has awesome). People that use FreeBSD do that conciously and are often experienced not only in FreeBSD land but also in topics related to other UNIX systems. Often they took long road of first using the Linux systems before finally setting on the FreeBSD land or they still do Linux adminitration for a living while resting using far more reasonable and sensible FreeBSD solution. I always find FreeBSD Community helpful and friendly. Always willingly helpful – especially towards newcommers. Even when you try to ‘force’ FreeBSD people to ‘fight’ in unjust/doubtful discussion they will reply with dignity and technical arguments instead of yelling at you.

The FreeBSD project even made several articles and Handbook chapters especially for Linux newcommers (or sometimes called systemd(1) refugees).

Closing Thoughts

I tried really hard to not make it a Linux rant but some may feel it that way – if so please remember that this was not my intention. FreeBSD like Linux and like any other operating system has its ups and downs. Hope that I showed you most interesting FreeBSD parts. I may add new sections here without a warning in the future ๐Ÿ™‚

EOF

ย 

FreeBSD Desktop โ€“ Part 21 โ€“ Configuration โ€“ Compton

In this article of the FreeBSD Desktop series I will talk Compton setup – the one that does not breaks, displays everything properly and does not consume 100% of your CPU time, as unfortunately Compton is a real bitch when it comes to proper setup.

The Compton is X11 compositor.

It allows the following features on X11 desktop:

  • transparent windows/menus/titlebars/borders
  • shadows and colored shadows
  • fading effects
  • background bluring

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.

Here is how example Compton looks in action.

compton

To install Compton on FreeBSD just use the default packages as shown below.

# pkg install compton

X11 Configuration

This is the graphics card configuration I have for X11:

% cat /usr/local/etc/X11/xorg.conf.d/card.conf
Section "Device"
  Identifier "Card0"
  Driver "modesetting"
  Option "DPMS"
  Option "AccelMethod" "glamor"
EndSection

… and the meritum of this article – the Compton config file:

% cat ~/.config/compton.conf
backend = "glx";
shadow = true;
no-dock-shadow = true;
clear-shadow = true;
shadow-radius = 12;
shadow-offset-x = -15;
shadow-offset-y = -15;
shadow-opacity = 0.7;
shadow-exclude = [
    "! name~=''",
    "name = 'Notification'",
    "name = 'Plank'",
    "name = 'Docky'",
    "name = 'Kupfer'",
    "name = 'xfce4-notifyd'",
    "name *= 'VLC'",
    "name *= 'compton'",
    "name *= 'Chromium'",
    "name *= 'Chrome'",
    "name *= 'Firefox'",
    "class_g = 'Conky'",
    "class_g = 'dzen'",
    "class_g = 'dzen2'",
    "class_g = 'Kupfer'",
    "class_g = 'Synapse'",
    "class_g ?= 'Notify-osd'",
    "class_g ?= 'Cairo-dock'",
    "class_g ?= 'Xfce4-notifyd'",
    "class_g ?= 'Xfce4-power-manager'"
];
shadow-ignore-shaped = false;
menu-opacity = 1;
inactive-opacity = 0.9;
active-opacity = 1;
frame-opacity = 0.9;
inactive-opacity-override = false;
alpha-step = 0.06;
blur-background-fixed = false;
blur-background-exclude = [
    "window_type = 'dock'",
    "window_type = 'desktop'"
];
fading = true;
fade-delta = 4;
fade-in-step = 0.03;
fade-out-step = 0.03;
fade-exclude = [ ];
mark-wmwin-focused = true;
mark-ovredir-focused = true;
use-ewmh-active-win = true;
detect-rounded-corners = true;
detect-client-opacity = true;
refresh-rate = 0;
vsync = "opengl-swc";
dbe = false;
paint-on-overlay = true;
sw-opti = false;
unredir-if-possible = true;
focus-exclude = [ ];
detect-transient = true;
detect-client-leader = true;
wintypes:
{
    tooltip =
    {
        fade = true;
        shadow = false;
        opacity = 0.85;
        focus = true;
    };
};

While the above config works very well I will also add same Compton configuration file but with comments.

% cat ~/.config/compton.conf
#################################
#
# Backend
#
#################################

# Backend to use: "xrender" or "glx".
# GLX backend is typically much faster but depends on a sane driver.
backend = "glx";

#################################
#
# GLX Backend
#
#################################

# GLX backend: Copy unmodified regions from front buffer instead of redrawing them all.
# Tests with nvidia-drivers show 10% decrease in performance when whole screen
# is modified but 20% increase when only 1/4 is modified.
# Tests on nouveau show terrible slowdown.
# Useful with --glx-swap-method as well.
# glx-copy-from-front = false;

# GLX backend: Use MESA_copy_sub_buffer to do partial screen update.
# Tests on nouveau shows 200% performance boost when only 1/4 of screen is updated.
# May break VSync and is not available on some drivers.
# Overrides --glx-copy-from-front.
# glx-use-copysubbuffermesa = true;

# GLX backend: Avoid rebinding pixmap on window damage.
# Probably could improve performance on rapid window content changes
# but is known to break things on some drivers (LLVMpipe).
# Recommended if it works.
# glx-no-rebind-pixmap = true;

# GLX backend: GLX buffer swap method we assume.
# Could be:
# - undefined (0)
# - copy (1)
# - exchange (2)
# - buffer-age (-1)
# The undefined is slowest and safest (default value).
# Copy is fastest but may fail on some drivers.
# buffer-age means auto-detect using GLX_EXT_buffer_age supported by some drivers.
# Useless with --glx-use-copysubbuffermesa.
# Partially breaks --resize-damage.
# Defaults to undefined.
# glx-swap-method = "undefined";

#################################
#
# Shadows
#
#################################

# Enabled client-side shadows on windows.
shadow = true;

# Do not draw shadows on DND windows.
# no-dnd-shadow = true;

# Avoid drawing shadows on dock/panel windows.
no-dock-shadow = true;

# Zero part of shadow's mask behind window. Fix some weirdness with ARGB windows.
clear-shadow = true;

# The blur radius for shadows. (default 12)
shadow-radius = 12;

# The left offset for shadows. (default -15)
shadow-offset-x = -15;

# The top offset for shadows. (default -15)
shadow-offset-y = -15;

# The translucency for shadows. (default .75)
shadow-opacity = 0.7;

# Set if you want different colour shadows
# shadow-red = 0.0;
# shadow-green = 0.0;
# shadow-blue = 0.0;

# The shadow exclude options are helpful if you have shadows enabled.
# Due to way compton draws its shadows certain applications will have
# visual glitches (most applications are fine - only apps that do weird
# things with xshapes or argb are affected).
# The "! name~=''" part excludes shadows on any "Unknown" windows.
# This prevents visual glitch with XFWM alt-tab switcher.
shadow-exclude = [
    "! name~=''",
    "name = 'Notification'",
    "name = 'Plank'",
    "name = 'Docky'",
    "name = 'Kupfer'",
    "name = 'xfce4-notifyd'",
    "name *= 'VLC'",
    "name *= 'compton'",
    "name *= 'Chromium'",
    "name *= 'Chrome'",
    "name *= 'Firefox'",
    "class_g = 'Conky'",
    "class_g = 'dzen'",
    "class_g = 'dzen2'",
    "class_g = 'Kupfer'",
    "class_g = 'Synapse'",
    "class_g ?= 'Notify-osd'",
    "class_g ?= 'Cairo-dock'",
    "class_g ?= 'Xfce4-notifyd'",
    "class_g ?= 'Xfce4-power-manager'"
];

# Avoid drawing shadow on all shaped windows (see also: --detect-rounded-corners)
shadow-ignore-shaped = false;

#################################
#
# Opacity
#
#################################

# Opacity for menu items.
menu-opacity = 1;

# Opacity for inactive windows.
inactive-opacity = 0.9;

# Opacity for active windows.
active-opacity = 1;

# Opacity for active frame of windows.
frame-opacity = 0.9;

# Opacity for inactive frame of windows.
inactive-opacity-override = false;

# Alpha step.
alpha-step = 0.06;

# Dim inactive windows. (0.0 - 1.0)
# inactive-dim = 0.2;

# Do not let dimness adjust based on window opacity.
# inactive-dim-fixed = true;

# Blur background of transparent windows. Bad performance with X Render backend.
# GLX backend is preferred.
# blur-background = true;

# Blur background of opaque windows with transparent frames as well.
# blur-background-frame = true;

# Do not let blur radius adjust based on window opacity.
blur-background-fixed = false;

# Blue exclude list.
blur-background-exclude = [
    "window_type = 'dock'",
    "window_type = 'desktop'"
];

#################################
#
# Fading
#
#################################

# Fade windows during opacity changes.
fading = true;

# The time between steps in fade in milliseconds (default 10).
fade-delta = 4;

# Opacity change between steps while fading in (default 0.028).
fade-in-step = 0.03;

# Opacity change between steps while fading out (default 0.03).
fade-out-step = 0.03;

# Fade windows in/out when opening/closing
# no-fading-openclose = true;

# Specify a list of conditions of windows that should not be faded.
fade-exclude = [ ];

#################################
#
# Other
#
#################################

# Try to detect WM windows and mark them as active.
mark-wmwin-focused = true;

# Mark all non-WM but override-redirect windows active (e.g. menus).
mark-ovredir-focused = true;

# Use EWMH _NET_WM_ACTIVE_WINDOW to determine which window is focused instead of
# using FocusIn/Out events. Usually more reliable but depends on EWMH-compliant WM.
use-ewmh-active-win = true;

# Detect rounded corners and treat them as rectangular when --shadow-ignore-shaped is on.
detect-rounded-corners = true;

# Detect _NET_WM_OPACITY on client windows useful for window managers not passing
# _NET_WM_OPACITY of client windows to frame windows. This prevents opacity ignore
# for some apps. Without this enabled xfce4-notifyd is 100% opacity no matter what.
detect-client-opacity = true;

# Specify refresh rate. With 0 compton will detect this with X RandR extension.
refresh-rate = 0;

# Set VSync method. VSync methods currently available:
# - none: No VSync
# - drm: VSync with DRM_IOCTL_WAIT_VBLANK. May only work on some drivers.
# - opengl: VSync with SGI_video_sync OpenGL extension. Only on some drivers.
# - opengl-oml: VSync with OML_sync_control OpenGL extension. Only on some drivers.
# - opengl-swc: VSync with SGI_swap_control OpenGL extension. Only on some drivers.
#               Works with GLX backend. Known to be most effective on many drivers.
#               Does not control paint timing - only buffer swap is affected.
#               Does not have effect of --sw-opti unlike other methods. Experimental.
# - opengl-mswc: Try to VSync with MESA_swap_control OpenGL extension.
#                Basically same as opengl-swc above except extension we use.
vsync = "opengl-swc";

# Enable DBE painting mode - use with VSync to (hopefully) eliminate tearing.
dbe = false;

# Painting on X Composite overlay window. Recommended.
paint-on-overlay = true;

# Limit repaint at most once every 1 / refresh_rate second to boost performance.
# This should not be used with --vsync drm/opengl/opengl-oml as they essentially does
# --sw-opti* job unless you wish to have lower refresh rate than actual value.
sw-opti = false;

# Unredirect all windows if full-screen window is detected to maximize performance
# for full-screen windows - like games. Known to cause flickering when
# redirecting/unredirecting windows. Paint-on-overlay may flicker less.
unredir-if-possible = true;

# Specify list of conditions of windows that should always be considered focused.
focus-exclude = [ ];

# Use WM_TRANSIENT_FOR to group windows in same group focused at same time.
detect-transient = true;

# Use WM_CLIENT_LEADER to group windows in same group focused at same time.
# WM_TRANSIENT_FOR has higher priority if --detect-transient is enabled too.
detect-client-leader = true;

#################################
#
# Window Type Settings
#
#################################

wintypes:
{
    tooltip =
    {
        # fade: Fade particular type of windows.
        fade = true;
        # shadow: Give those windows shadow
        shadow = false;
        # opacity: Default opacity for type of windows.
        opacity = 0.85;
        # focus: Whether to always consider windows of this type focused.
        focus = true;
    };
};


Not sure what else could I add here so this means the end of this article ๐Ÿ™‚

EOF

Run broot on FreeBSD

The broot file manager is quite fresh and nice approach to files and directories filtering/searching/view/manipulation/… and whatever else you call messing with files ๐Ÿ™‚

The broot tools is not yet available on the FreeBSD systems (as package or port).

This guide will show you how to built and install it on your FreeBSD system.

Here is how it looks in action.

Filter for jails.

broot-filter-jails.jpg

Filter for zfs.

broot-filter-zfs.jpg

It has ‘size mode’ when started with -s option similar to ncdu(1) tool.

broot-filter-size.jpg

You can also check the Feature Showcase section on their GitHub page – https://github.com/Canop/broot – available here.

Build

There are three steps to make it happen.

1. You need to install the rust package.

# pkg install rust

Then you need to type (as regular user) the cargo install broot command.

% cargo install broot

It will fail here:

broot-fail.jpg

You will need to apply this patch below:

% diff -u \
  /home/vermaden/.cargo/registry/src/github.com-1ecc6299db9ec823/crossterm-0.14.1/src/terminal/sys/unix.rs.ORG \
  /home/vermaden/.cargo/registry/src/github.com-1ecc6299db9ec823/crossterm-0.14.1/src/terminal/sys/unix.rs
--- /home/vermaden/.cargo/registry/src/github.com-1ecc6299db9ec823/crossterm-0.14.1/src/terminal/sys/unix.rs.ORG  2020-01-10 23:41:29.825912000 +0100
+++ /home/vermaden/.cargo/registry/src/github.com-1ecc6299db9ec823/crossterm-0.14.1/src/terminal/sys/unix.rs      2020-01-10 23:41:07.703471000 +0100
@@ -33,7 +33,7 @@
         ws_ypixel: 0,
     };
 
-    if let Ok(true) = wrap_with_result(unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut size) }) {
+    if let Ok(true) = wrap_with_result(unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ.into(), &mut size) }) {
         Ok((size.ws_col, size.ws_row))
     } else {
         tput_size().ok_or_else(|| std::io::Error::last_os_error().into())

Then type cargo install broot command again. It will now properly compile.

% cargo install broot
    Updating crates.io index
  Downloaded broot v0.11.6
  Downloaded 1 crate (1.6 MB) in 2.89s
  Installing broot v0.11.6
   Compiling libc v0.2.66
   Compiling cfg-if v0.1.10
   Compiling lazy_static v1.4.0
   Compiling autocfg v0.1.7
   Compiling semver-parser v0.7.0
   Compiling autocfg v1.0.0
   Compiling proc-macro2 v1.0.7
   Compiling log v0.4.8
   Compiling scopeguard v1.0.0
   Compiling unicode-xid v0.2.0
   Compiling bitflags v1.2.1
   Compiling syn v1.0.13
   Compiling memchr v2.2.1
   Compiling arc-swap v0.4.4
   Compiling slab v0.4.2
   Compiling smallvec v1.1.0
   Compiling serde v1.0.104
   Compiling unicode-width v0.1.7
   Compiling regex-syntax v0.6.13
   Compiling ansi_term v0.11.0
   Compiling strsim v0.8.0
   Compiling vec_map v0.8.1
   Compiling id-arena v2.2.1
   Compiling custom_error v1.7.1
   Compiling glob v0.3.0
   Compiling open v1.3.2
   Compiling umask v0.1.8
   Compiling thread_local v1.0.0
   Compiling minimad v0.6.3
   Compiling lazy-regex v0.1.2
   Compiling semver v0.9.0
   Compiling lock_api v0.3.3
   Compiling crossbeam-utils v0.7.0
   Compiling crossbeam-epoch v0.8.0
   Compiling num-traits v0.2.11
   Compiling num-integer v0.1.42
   Compiling textwrap v0.11.0
   Compiling rustc_version v0.2.3
   Compiling memoffset v0.5.3
   Compiling iovec v0.1.4
   Compiling net2 v0.2.33
   Compiling dirs-sys v0.3.4
   Compiling parking_lot_core v0.7.0
   Compiling signal-hook-registry v1.2.0
   Compiling time v0.1.42
   Compiling atty v0.2.14
   Compiling users v0.9.1
   Compiling quote v1.0.2
   Compiling aho-corasick v0.7.6
   Compiling mio v0.6.21
   Compiling dirs v2.0.2
   Compiling directories v2.0.2
   Compiling parking_lot v0.10.0
   Compiling clap v2.33.0
   Compiling crossbeam-queue v0.2.1
   Compiling crossbeam-channel v0.4.0
   Compiling toml v0.5.5
   Compiling term v0.6.1
   Compiling regex v1.3.3
   Compiling signal-hook v0.1.12
   Compiling chrono v0.4.10
   Compiling crossterm v0.14.1
   Compiling simplelog v0.7.4
   Compiling crossbeam-deque v0.7.2
   Compiling thiserror-impl v1.0.9
   Compiling crossbeam v0.7.3
   Compiling thiserror v1.0.9
   Compiling termimad v0.8.9
   Compiling broot v0.11.6
    Finished release [optimized] target(s) in 4m 56s
  Installing /home/vermaden/.cargo/bin/broot
   Installed package `broot v0.11.6` (executable `broot`)
warning: be sure to add `/home/vermaden/.cargo/bin` to your PATH to be able to run the installed binaries

% echo $?
0

Install

Now go to the ~/.cargo/bin directory and copy the broot binary to some place that is set in your ${PATH} variable.

Then start new terminal (updated ${PATH} variable) and type broot command.

% cp ~/.cargo/bin/broot ~/scripts
% rehash
% broot

You will be asked if automatic setup of the br function should tool place. I agreed with y answer.

broot-first-run.jpg

Here are things generated by this process.

% find ~/.config/broot
/home/vermaden/.config/broot
/home/vermaden/.config/broot/conf.toml
/home/vermaden/.config/broot/launcher
/home/vermaden/.config/broot/launcher/installed-v1
/home/vermaden/.config/broot/launcher/bash
/home/vermaden/.config/broot/launcher/bash/br

% find ~/.local/share/broot
/home/vermaden/.local/share/broot
/home/vermaden/.local/share/broot/launcher
/home/vermaden/.local/share/broot/launcher/fish
/home/vermaden/.local/share/broot/launcher/fish/1.fish
/home/vermaden/.local/share/broot/launcher/bash
/home/vermaden/.local/share/broot/launcher/bash/1

As I use ZSH shell it also updates my ~/.zshrc file.

% tail -3 ~/.zshrc

source /home/vermaden/.config/broot/launcher/bash/br

Finished. You now have broot installed and ready to use.

broot-filter-bhyve.jpg

UPDATE 1 – Now No Patches Are Needed

Thanks to the broot author any patches are now not needed.

It builds and works out of the box.

broot-update-fixed

UPDATE 2 – Its in Ports/Packages Now

The broot file manager is now available via usual FreeBSD Ports and packages which makes this guide pointless ๐Ÿ™‚

Its available as misc/broot port.

EOF

ย 

FreeBSD Desktop – Part 20 – Configuration – Unlock Your Laptop with Phone

I really do not like the smart card ecosystem – probably because it will be a big PITA to setup such subsystem on FreeBSD to make it lock/unlock my laptop with a smart card – not to mention of it will be even possible because of probable lack of drivers for a laptop builtin smart card reader. I mention it because you can lock and unlock your laptop with such smart card in very fast way.

Some people use finger prints readers (for fast workstation/laptop unlock purpose) – but its the same case scenario as with smart card – the time needed to setup it properly. Not to mention that is not that fast anyway as I often see my colleagues swinging the finger over the fingerprint reader over and over again so it will finally work the 7th time …

… but you wan also lock and unlock your UNIX laptop with your phone – by just attaching it to your device – this is where the FreeBSD’s devd(8) subsystem come handy.

Today I will show you how to lock/unlock your laptop with your phone.

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.

Keep in mind that in order to make it work you need to attach the phone to laptop using cable that supports data transfer – it will not work with cables that only provide power for charging your phone.

Device Detection

First we need to detect what device will be your locker/unlocker.

Stop the devd(8) daemon.

# service devd stop
Stopping devd.
Waiting for PIDS: 71455.

Now start it in ‘foreground’ for debug purposes and then attach your phone. The command below with grep(1) will help you to find needed information.

# devd -d 2>&1 | grep --line-buffered 'Processing event' | grep --line-buffered DEVICE
Processing event '!system=USB subsystem=DEVICE type=ATTACH ugen=ugen2.3 cdev=ugen2.3 vendor=0x04e8 product=0x6860 devclass=0x00 devsubclass=0x00 sernum="31000e243eb5a12e" release=0x0400 mode=host port=2 parent=ugen2.2'

I have highlited the needed information.

Do not stop this process yet.

Now you know which device will be your locker/unlocker and what even the devd(8) daemon gets when you attach your phone.

Things to note hare are:

vendor=0x04e8
product=0x6860
sernum=31000e243eb5a12e

This data above is more then enough to unlock your workstation.

Now detach your phone from the computer. You will see the DETACH even similar to the one below.

Processing event '!system=USB subsystem=DEVICE type=DETACH ugen=ugen2.3 cdev=ugen2.3 vendor=0x04e8 product=0x6860 devclass=0x00 devsubclass=0x00 sernum="31000e243eb5a12e" release=0x0400 mode=host port=2 parent=ugen2.2'

Now you know the event that will be spawned when you detach your phone.

Stop the foreground devd(8) daemon and start the service traditionally.

# devd -d 2>&1 | grep --line-buffered 'Processing event' | grep --line-buffered DEVICE
Processing event '!system=USB subsystem=DEVICE type=ATTACH ugen=ugen2.3 cdev=ugen2.3 vendor=0x04e8 product=0x6860 devclass=0x00 devsubclass=0x00 sernum="31000e243eb5a12e" release=0x0400 mode=host port=2 parent=ugen2.2'
Processing event '!system=USB subsystem=DEVICE type=DETACH ugen=ugen2.3 cdev=ugen2.3 vendor=0x04e8 product=0x6860 devclass=0x00 devsubclass=0x00 sernum="31000e243eb5a12e" release=0x0400 mode=host port=2 parent=ugen2.2'
^C
# service devd start
Starting devd.

Commands for Events

Now, what action or command should be executed when you attach or detach your phone? That depends on which screen locker you are using on your X11 setup.

I for example use the mate-screensaver for this purpose.

The ATTACH event in my case would be to kill the current process mate-screensaver which will unlock the screen and then start it again for the next lock purposes – below is the command that I will run for the ATTACH event.

pkill -9 mate-screensaver && su -l vermaden -c 'env DISPLAY=:0 mate-screensaver' &

The DETACH event will be notifying the mate-screensaver to lock the screen – here is the command that will be used for that purpose.

su -l vermaden -c 'env DISPLAY=:0 mate-screensaver-command --lock' &

Implementation

Here is how the devd(8) config file for my phone would look like.

# cat /usr/local/etc/devd/phonelock.conf

# PHONE ATTACH - UNLOCK
notify 100 {
    match "system" "USB";
    match "subsystem" "DEVICE";
    match "type" "ATTACH";
    match "vendor" "0x04e8";
    match "product" "0x6860";
    match "sernum" "31000e243eb5a12e";
    action "pkill -9 mate-screensaver && su -l vermaden -c 'env DISPLAY=:0 mate-screensaver' &";
};

# PHONE DETACH - LOCK
notify 100 {
    match "system" "USB";
    match "subsystem" "DEVICE";
    match "type" "DETACH";
    match "vendor" "0x04e8";
    match "product" "0x6860";
    match "sernum" "31000e243eb5a12e";
    action "su -l vermaden -c 'env DISPLAY=:0 mate-screensaver-command --lock' &";
};

Now restart the devd(8) daemon so it will read new configuration files.

# service devd restart
Stopping devd.
Waiting for PIDS: 1458.
Starting devd.

Viola! Now you can lock and unlock your screen just by attaching or detaching your phone. I do not have any fancy video on how it behaves but you must trust me that is less then a second to lock and unlock the laptop now – be sure to keep and additional eye on your phone now, as it can unlock the access to all your files now ๐Ÿ™‚

You can of course use any USB device or even network actions – any event that is supported by the devd(8) daemon.

You can of course create such lock/unlock config when you attach/detach your phone and additionally configure power down action when you detach other USB device.

I forgot to mention it, that method does not disables the ‘classic’ password authentication – it just adds automatic screen lock/unlock when you attach your phone – you can still login (unlock) using just password on the mate-screensaver lock screen.

UPDATE 1 – Better devd Sniffing – Better Unlock Method

As oh5nxo from Reddit suggested its not needed to stop devd and start it in ‘debug’ mode – its easier just to attach to its ‘pipe’ with nc(1) tool.

# nc -U /var/run/devd.pipe

There is also no need to kill(1) the mate-screensaver command, its more elegant to just send the mate-screensaver-command --unlock command.

Below is the updated /usr/local/etc/devd/phonelock.conf config file for the devd(8) daemon.

# cat /usr/local/etc/devd/phonelock.conf

# PHONE ATTACH - UNLOCK
notify 100 {
    match "system" "USB";
    match "subsystem" "DEVICE";
    match "type" "ATTACH";
    match "vendor" "0x04e8";
    match "product" "0x6860";
    match "sernum" "33000e343fb4a42d";
    action "su -l vermaden -c 'env DISPLAY=:0 mate-screensaver-command --unlock' &";
};

# PHONE DETACH - LOCK
notify 100 {
    match "system" "USB";
    match "subsystem" "DEVICE";
    match "type" "DETACH";
    match "vendor" "0x04e8";
    match "product" "0x6860";
    match "sernum" "33000e343fb4a42d";
    action "su -l vermaden -c 'env DISPLAY=:0 mate-screensaver-command --lock' &";
};

EOF

FreeBSD Desktop – Part 19 – Configuration – Plank – Skippy-XD

Long time no see :). In this article of the FreeBSD Desktop series we will add Plank and Skippy-XD to the existing setup.

I will share with You Plank configuration along with theme that fits to the rest of the setup. Plank is an open implementation of the ideas that was brought to life by Mac OS X (macOS) Dock. We will also add Skippy-XD tool that implements Mac OS X (macOS) Expose ideas.

One my ask why use Plank while we already have Tint2 for similar purposes? While both support autohide I prefer to see Tint2 all the time to get basic/fast idea about what is launched on which desktop and have Plank hidden as it does not hurt and sometimes helps.

Here is both Mac OS X (macOS) Dock and Expose in action.

macosx-dock-expose.jpg

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.

To install both Plank and Skippy-XD on FreeBSD just use the default packages as shown below.

# pkg install skippy-xd plank

Plank

Here is how Plank dock composes with the rest of the setup.

shot-res-small

The Plank dock comes with graphical preferences window if needed but you need to launch it from the command line as plank --preferences command.

plank-prefs.jpg

Here is the used Plank theme which is kept in the ~/.local/share/plank/themes/vermaden/dock.theme file.


% grep '^[^#]' ~/.local/share/plank/themes/vermaden/dock.theme

[PlankTheme]
TopRoundness=0
BottomRoundness=0
LineWidth=0
OuterStrokeColor=0;;0;;0;;255
FillStartColor=40;;40;;40;;255
FillEndColor=40;;40;;40;;255
InnerStrokeColor=40;;40;;40;;255

[PlankDockTheme]
HorizPadding=0
TopPadding=1
BottomPadding=2
ItemPadding=2.5
IndicatorSize=10
IconShadowSize=0
UrgentBounceHeight=0
LaunchBounceHeight=0
FadeOpacity=0
ClickTime=300
UrgentBounceTime=600
LaunchBounceTime=600
ActiveTime=300
SlideTime=300
FadeTime=250
HideTime=150
GlowSize=24
GlowTime=10000
GlowPulseTime=2000
UrgentHueShift=150
ItemMoveTime=150
CascadeHide=true

[PlankDrawingDockTheme]
HorizPadding=0
ItemPadding=2.5
CascadeHide=true

And here are mine Plank dock settings which are kept in the ~/.config/plank/dock1/settings file.


% grep '^[^#]' ~/.config/plank/dock1/settings

[PlankDockPreferences]
CurrentWorkspaceOnly=false
IconSize=32
HideMode=0
UnhideDelay=0
HideDelay=0
Monitor=DP-1
DockItems=caja.dockitem;;leafpad.dockitem;;firefox.dockitem;;geany.dockitem;;thunderbird.dockitem;;galculator.dockitem;;deadbeef.dockitem;;transmission-gtk.dockitem;;pidgin.dockitem
Position=3
Offset=20
Theme=vermaden
Alignment=3
ItemsAlignment=3
LockItems=false
PressureReveal=false
PinnedOnly=false
AutoPinning=true
ShowDockItem=true
ZoomEnabled=false
ZoomPercent=150


Skippy-XD

You may wonder why the XD in the Skippy name. Its because Skippy started as a pure software solution – which unfortunately was quite slow – especially in the times when Skippy was introduced, and it was about a decade ago. Then Skippy developers rewrote it to use the – new then XDAMAGE module for X11 – from this change Skippy started to work almost instantly – and this was marked in its name and it remains to this date as Skippy-XD.

This is how Skippy-XD looks like.

skippy-xd.jpg

The Skippy-XD does not need/support themes – it just has a configuration file located at ~/.config/skippy-xd/skippy-xd.rc place.


% grep '^[^#]' ~/.config/skippy-xd/skippy-xd.rc

[general]
distance = 50
useNetWMFullscreen = true
ignoreSkipTaskbar = true
updateFreq = 30.0
lazyTrans = true
pipePath = /tmp/skippy-xd-fifo
movePointerOnStart = true
movePointerOnSelect = true
movePointerOnRaise = true
switchDesktopOnActivate = true
useNameWindowPixmap = false
forceNameWindowPixmap = false
includeFrame = true
allowUpscale = true
showAllDesktops = true
showUnmapped = true
preferredIconSize = 32
clientDisplayModes = thumbnail icon filled none
iconFillSpec = orig mid mid #666666
fillSpec = orig mid mid #FFFFFF
background =

[xinerama]
showAll = true

[normal]
tint = black
tintOpacity = 0
opacity = 200

[highlight]
tint = #202020
tintOpacity = 64
opacity = 255

[tooltip]
show = true
followsMouse = true
offsetX = 20
offsetY = 20
align = left
border = #111111
background = #333333
opacity = 128
text = #eedddd
textShadow = none
font = ubuntu-10:weight=normal

[bindings]
miwMouse1 = focus
miwMouse2 = close-ewmh
miwMouse3 = iconify

One of the nice features of Skippy-XD is that you can configure it per desktop or globally per all currently existing virtual desktops. I also prefer to display window thumbnails only from the windows that exist on the current desktop. You can of course change that behavior with the Skippy-XD config file.

EOF

List Block Devices on FreeBSD lsblk(8) Style

When I have to work on Linux systems I usually miss many nice FreeBSD tools such as these for example to name the few:

  • sockstat
  • gstat
  • top -b -o res
  • top -m io -o total
  • usbconfig
  • rcorder
  • beadm/bectl
  • idprio/rtprio

… but sometimes – which rarely happens – Linux has some very useful tool that is not available on FreeBSD. An example of such tool is lsblk(8) that does one thing and does it quite well – lists block devices and their contents. It has some problems like listing a disk that is entirely used under ZFS pool on which lsblk(8) displays two partitions instead of information about ZFS just being there – but we all know how much in some circles the CDDL licensed ZFS is unloved in that GPL world.

Example lsblk(8) output from Linux system:

$ lsblk
NAME                         MAJ:MIN RM   SIZE RO TYPE   MOUNTPOINT
sr0                           11:0    1  1024M  0 rom
sda                            8:0    0 931.5G  0 disk
|-sda1                         8:1    0   500M  0 part   /boot
`-sda2                         8:2    0   931G  0 part
  |-vg_local-lv_root (dm-0)  253:0    0    50G  0 lvm    /
  |-vg_local-lv_swap (dm-1)  253:1    0  17.7G  0 lvm    [SWAP]
  `-vg_local-lv_home (dm-2)  253:2    0   1.8T  0 lvm    /home
sdc                            8:32   0 232.9G  0 disk
`-sdc1                         8:33   0 232.9G  0 part
  `-md1                        9:1    0 232.9G  0 raid10 /data
sdd                            8:48   0 232.9G  0 disk
`-sdd1                         8:49   0 232.9G  0 part
  `-md1                        9:1    0 232.9G  0 raid10 /data

What FreeBSD offers in this department? The camcontrol(8) and geom(8) commands are available. You can also use gpart(8) command to list partitions. Below you will find output of these commands from my single disk laptop. Please note that because of WordPress limitations I need to change all > < characters to ] [ ones in the commands outputs.

# camcontrol devlist
[Samsung SSD 860 EVO mSATA 1TB RVT41B6Q]  at scbus1 target 0 lun 0 (ada0,pass0)

% geom disk list
Geom name: ada0
Providers:
1. Name: ada0
   Mediasize: 1000204886016 (932G)
   Sectorsize: 512
   Mode: r1w1e2
   descr: Samsung SSD 860 EVO mSATA 1TB
   lunid: 5002538e402b4ddd
   ident: S41PNB0K303632D
   rotationrate: 0
   fwsectors: 63
   fwheads: 1

# gpart show
=>        40  1953525088  ada0  GPT  (932G)
          40      409600     1  efi  (200M)
      409640        1024     2  freebsd-boot  (512K)
      410664         984        - free -  (492K)
      411648  1953112064     3  freebsd-zfs  (931G)
  1953523712        1416        - free -  (708K)

They provide needed information in acceptable manner but only on systems with small amount of disks. What if you would like to display a summary of all system drives contents? This is where lsblk.sh comes handy. While lsblk(8) has many interesting features like --perms/--scsi/--inverse modes I focused to provide only the basic feature – to list the system block devices and their contents. As I have long and pleasing experience with writing shell scripts such as sysutils/beadm or sysutils/automount I though that writing lsblk.sh may be a good idea. I actually ‘open-sourced’ or should I say shared that project/idea in 2016 in this thread lsblk(8) Command for FreeBSD on FreeBSD Forums but lack of time really slowed that ‘side project’ development pace. I finally got back to it to finish it.

The lsblk.sh is generally small and simple shell script which tales less then 400 SLOC.

lsblk

Here is example output of lsblk.sh command from my single disk laptop.

% lsblk.sh
DEVICE         MAJ:MIN  SIZE TYPE                      LABEL MOUNT
ada0             0:5b  932G GPT                           - -
  ada0p1         0:64  200M efi                    efiboot0 [UNMOUNTED]
  ada0p2         0:65  512K freebsd-boot           gptboot0 -
  [FREE]         -:-   492K -                             - -
  ada0p3         0:66  931G freebsd-zfs                zfs0 [ZFS]
  [FREE]         -:-   708K -                             - -


Same output in graphical window.

lolcat

Below you will find an example lsblk.sh output from server with two system SSD drives (da0/da1) and two HDD data drives (da2/da3).

# lsblk.sh
DEVICE         MAJ:MIN SIZE TYPE                      LABEL MOUNT
da0              0:be  224G GPT                           - -
  da0p1          0:15a 200M efi                    efiboot0 [UNMOUNTED]
  da0p2          0:15b 512K freebsd-boot           gptboot0 -
  [FREE]         -:-   492K -                             - -
  da0p3          0:15c 2.0G freebsd-swap              swap0 [UNMOUNTED]
  da0p4          0:15d 221G freebsd-zfs                zfs0 [ZFS]
  [FREE]         -:-   580K -                             - -
da1              0:bf  224G GPT                           - -
  da1p1          0:16a 200M efi                    efiboot1 [UNMOUNTED]
  da1p2          0:16b 512K freebsd-boot           gptboot1 -
  [FREE]         -:-   492K -                             - -
  da1p3          0:16c 2.0G freebsd-swap              swap1 [UNMOUNTED]
  da1p4          0:16d 221G freebsd-zfs                zfs1 [ZFS]
  [FREE]         -:-   580K -                             - -
da2              0:c0   11T GPT                           - -
  da2p1          0:16e  11T freebsd-zfs                   - [ZFS]
  [FREE]         -:-   1.0G -                             - -
da3              0:c1   11T GPT                           - -
  da3p1          0:16f  11T freebsd-zfs                   - [ZFS]
  [FREE]         -:-   1.0G -                             - -

Below you will find other examples from other systems I have tested lsblk.sh on.

lsblk.examples

While lsblk.sh is not the fastest script on Earth (because of all the needed parsing) it does its job quite well. If you would like to install it in your system just type the command below:

# fetch -o /usr/local/bin/lsblk https://raw.githubusercontent.com/vermaden/scripts/master/lsblk.sh
# chmod +x /usr/local/bin/lsblk
# hash -r || rehash
# lsblk

If I got time which other original Linux lsblk(8) subcommand/option/argument is worth adding to the lsblk.sh script? ๐Ÿ™‚

Regards.

UPDATE 1 – Added USAGE/HELP Information

Just added some usage information that can be displayed by specifying one of these as argument:

  • h
  • -h
  • --h
  • help
  • -help
  • --help

IMHO writing man page for such simple utility is needless. I think I will create dedicated man page when lsblk.sh tool will grow in size and options to comparable with the Linux lsblk(8) equivalent. Here is how it looks.

# lsblk.sh --help
usage:

  BASIC USAGE INFORMATION
  =======================
  # lsblk.sh [DISK]

example(s):

  LIST ALL BLOCK DEVICES IN SYSTEM
  --------------------------------
  # lsblk.sh
  DEVICE         MAJ:MIN SIZE TYPE                      LABEL MOUNT
  ada0             0:5b  932G GPT                           - -
    ada0p1         0:64  200M efi                    efiboot0 [UNMOUNTED]
    ada0p2         0:65  512K freebsd-boot           gptboot0 -
    [FREE]         -:-   492K -                             - -
    ada0p3         0:66  931G freebsd-zfs                zfs0 [ZFS]

  LIST ONLY da1 BLOCK DEVICE
  --------------------------
  # lsblk.sh da1
  DEVICE         MAJ:MIN SIZE TYPE                      LABEL MOUNT
  da1              0:80  2.0G MBR                           - -
    da1s1          0:80  2.0G freebsd                       - -
      da1s1a       0:81  1.0G freebsd-ufs                root /
      da1s1b       0:82  1.0G freebsd-swap               swap SWAP

hint(s):

  DISPLAY ALL DISKS IN SYSTEM
  ---------------------------
  # sysctl kern.disks
  kern.disks: ada0 da0 da1

Regards.

UPDATE 2 โ€“ Code Reorganization and 75% Rewrite

… at least this is what git(1) tries to tell me after commit message.

% git commit (...)
[master 12fd4aa] Rework entire flow. Split code into functions. Add many useful comments. In other words its 2.0 version.
 1 file changed, 494 insertions(+), 505 deletions(-)
 rewrite lsblk.sh (75%)

After several productive hours new incarnation of lsblk.sh is now available.

It has similar SLOC but its now smaller by a quarter … while doing more and with better accuracy. Great example why “less is more.”

% wc scripts/lsblk.sh.OLD
     491    2201   19721 scripts/lsblk.sh.OLD

% wc scripts/lsblk.sh
     494    1871   15472 scripts/lsblk.sh

Things that does not have simple solution are described below.

One of them is ‘double’ label for FAT filesystems. We have both /dev/gpt/efiboot0 label and FAT label is named EFISYS. We have to choose something here. As not all FAT filesystems have label I have chosen the GPT label.

% glabel status | grep ada0p1
  gpt/efiboot0     N/A  ada0p1
msdosfs/EFISYS     N/A  ada0p1

I was also not able to cover FUSE mounts. When you mount – for example – the /dev/da0 device as NTFS (with ntfs-3g) or exFAT (with mount.exfat) there is no visible difference in mount(8) output.

% mount -t fusefs
/dev/fuse on /mnt/ntfs (fusefs)
/dev/fuse on /mnt/exfat (fusefs)

When I mount such filesystem by my daemon (like sysutils/automount) I keep track of what device have been mounted to which directory in the /var/run/automount.state file. Then when I get the detach event for /dev/da0 device I know what to u(n)mount … but when I only have /dev/fuse device its just not possible.

… or maybe YOU know any way of extracting information from /dev/fuse (or generally from FUSE) what device is mounted where?

Now little presentation after update.

Here are various non ZFS filesystems mounted.

% mount -t nozfs
devfs on /dev (devfs, local, multilabel)
linprocfs on /compat/linux/proc (linprocfs, local)
tmpfs on /compat/linux/dev/shm (tmpfs, local)
/dev/label/ASD on /mnt/tmp (msdosfs, local)
/dev/fuse on /mnt/ntfs (fusefs)
/dev/md0s1f on /mnt/ufs.other (ufs, local)
/dev/gpt/OTHER on /mnt/fat.other (msdosfs, local)
/dev/md0s1a on /mnt/ufs (ufs, local)

… and here is how now lsblk.sh displays them.

% lsblk.sh
DEVICE         MAJ:MIN SIZE TYPE                      LABEL MOUNT
ada0             0:56  932G GPT                           - -
  ada0p1         0:64  200M efi                gpt/efiboot0 -
  ada0p2         0:65  512K freebsd-boot       gpt/gptboot0 -
  [FREE]         -:-   492K -                             - -
  ada0p3         0:66  931G freebsd-zfs                   - [ZFS]
  [FREE]         -:-   708K -                             - -
md0              0:28f 1.0G MBR                           - -
  md0s1          0:294 512M freebsd                       - -
    md0s1a       0:29a 100M freebsd-ufs                root /mnt/ufs
    md0s1b       0:29b  32M freebsd-swap         label/swap SWAP
    md0s1e       0:29c  64M freebsd-ufs                   - -
    md0s1f       0:29d 316M freebsd-ufs                   - /mnt/ufs.other
  md0s2          0:296 256M ntfs                          - -
  md0s3          0:297 256M fat32               msdosfs/ONE -
md1              0:2a4 1.0G msdosfs                   LARGE 
md2              0:298 2.0G GPT                           - -
  md2p1          0:29f 2.0G ms-basic-data         gpt/OTHER /mnt/fat.other

I used some file based memory devices for this. Now by default lsblk.sh also displays memory disks contents.

% mdconfig.sh -l
md0     vnode    1024M  /home/vermaden/FILE     
md2     vnode    2048M  /home/vermaden/FILE.GPT 
md1     vnode    1024M  /home/vermaden/FILER    

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

lsblk.2.0

Regards.

UPDATE 3 – Added geli(8) Support

I thought that adding geli(8) support may be useful. The latest lsblk.sh now avoids code duplication for MOUNT and LABEL detection (moved into single unified function). Also added more comments for code readability and some minor fixes … and its again smaller ๐Ÿ™‚

% wc lsblk.sh.1.0
     491    2201   19721 lsblk.sh.1.0

% wc lsblk.sh.2.0
     493    1861   15415 lsblk.sh.2.0

% wc lsblk.sh
     488    1820   15332 lsblk.sh

About 40% (according to git commit was changed this time (191 insertions and 196 deletions).

# git commit (...)
[master ec9985a] Add geli(8) support. Avoid code duplication and move MOUNT/LABEL detection into function. More comments. Minor fixes.
 1 file changed, 191 insertions(+), 196 deletions(-)

Also forgot to mention that now lsblk.sh thanks to smart optimizations (like not doing things twice and aggregating grep(1) | awk(1) pipes into single awk(1) queries) runs 3 times faster then the initial version ๐Ÿ™‚

New output with geli(8) support below.

lsblk.2.1.geli.png

Regards.

UPDATE 4 – Added fuse(8) Support

As I wrote in the UPDATE 2 keeping track of what is mounted and where under fuse(8) is very hard as all mounted devices magically become /dev/fuse after mount is done.

After little research I found that this information (what really is mounted where by using fuse(8) interface under FreeBSD) is available after mounting procfs filesystem under /proc. You just need to cat cmdline entry for all PIDs of ntfs-3g. Its not perfect but the information at least is available.

# mount -t procfs proc /proc

# ps ax | grep ntfs-3g
45995  -  Is      0:00.00 ntfs-3g /dev/md1s2 /mnt/ntfs
59607  -  Is      0:00.00 ntfs-3g /dev/md3 /mnt/ntfs.another
83323  -  Is      0:00.00 ntfs-3g /dev/md3 /mnt/ntfs.another

# pgrep ntfs-3g
59607
83323
45995

% pgrep ntfs-3g | while read I; do cat /proc/$I/cmdline; echo; done
ntfs-3g/dev/md3/mnt/ntfs.another
ntfs-3g/dev/md3/mnt/ntfs.another
ntfs-3g/dev/md1s2/mnt/ntfs

This was the code prototype that worked for fuse(8) mountpoints detection.

    if [ -e /proc/0/status ]
    then
      FUSE_MOUNTS=$(
        while read PID
        do
          cat /proc/${PID}/cmdline
          echo
        done << ________EOF
          $( pgrep ntfs-3g )
________EOF
)
      FUSE_MOUNTS=$( echo "${FUSE_MOUNTS}" | sort -u )
      FUSE_MOUNTS=$( echo "${FUSE_MOUNTS}" | sed 's|ntfs-3g||g' )
      FUSE_CHECKS=$( echo "${FUSE_MOUNTS}" | grep /dev/${TARGET}/ )
      if [ "${FUSE_CHECKS}" != "" ]
      then
        MOUNT=$( echo "${FUSE_CHECKS}" | sed "s|/dev/${TARGET}||g" )
      fi
    fi
  fi

… and I have just realized that I found new (better) way of getting that information without mounting /proc filesystem – all you need to do is to display the ntfs-3g processes with their command line arguments, for example like that:

% ps -p $( pgrep ntfs-3g | tr '\n' ',' | sed '$s/.$//' ) -o command | sed 1d
ntfs-3g /dev/md1s2 /mnt/ntfs
ntfs-3g /dev/md3 /mnt/ntfs.another
ntfs-3g /dev/md3 /mnt/ntfs.another

So after I also thought that its only for NTFS (ntfs-3g(8) process) I also added exFAT support by searching for mount.exfat PIDs as well. The fuse(8) mount point detection works now for both NTFS and exFAT filesystems … and code to support it is even shorter.

  # TRY fuse(8) MOUNTS FROM PROCESSES
  if [ "${MOUNT_FOUND}" != "1" ]
  then
    FUSE_PIDS=$( pgrep mount.exfat ntfs-3g | tr '\n' ',' | sed '$s/.$//' )
    FUSE_MOUNTS=$( ps -p "${FUSE_PIDS}" -o command | sed 1d | sort -u )
    MOUNT=$( echo "${FUSE_MOUNTS}" |  grep "/dev/${TARGET} " | awk '{print $3}' )
  fi

I also changed how MAJOR and MINOR numbers are displayed – from HEX to DEC – as it is on Linux. The FreeBSD’s ls(1) from Base System displays these as HEX – for example you will get 0x2af value:

% ls -l /dev/md4
crw-rw----  1 root  operator  0x2af 2019.09.29 05:18 /dev/md4

But do the same with GNU equivalent by using gls(1) from FreeBSD Ports (from sysutils/coreutils package) and it shows MAJOR and MINOR in DEC values. The gls(1) is just ls(1) from the Linux world but as ls(1) name is already ‘taken’ by FreeBSD’s Base System tool the FreeBSD developers/maintainers add ‘g’ letter (for GNU) to distinguish them.

% gls -l /dev/md4
crw-rw---- 1 root 2, 175 2019-09-29 05:18 /dev/md4

… and they are also easier/faster to get with stat(1) tool.

  MAJ=$( stat -f "%Hr" /dev/${DEV} )
  MIN=$( stat -f "%Lr" /dev/${DEV} )

Latest lsblk.sh looks like that now.

lsblk.2.3.fuse.NTFS.exFAT

… that is why I did not (yet) added lsblk.sh to the FreeBSD Ports. Several new versions with important features span across just two days ๐Ÿ™‚

Regards.

UPDATE 5 – Another 69% Rewrite

After messing with gpart(8) more I found that using its -p flag which is a game changer. The difference is that with -p flag it displays names along partitions – its no longer needed to find the PREFIX and ‘create’ partition names.

Default gpart(8) output.

# gpart show md0
=>     63  2097089  md0  MBR  (1.0G)
       63  1048576    1  freebsd  (512M)
  1048639   524288    2  ntfs  (256M)
  1572927   524225    3  fat32  (256M)

Output of gpart(8) with -p flag.

# gpart show -p md0
=>     63  2097089    md0  MBR  (1.0G)
       63  1048576  md0s1  freebsd  (512M)
  1048639   524288  md0s2  ntfs  (256M)
  1572927   524225  md0s3  fat32  (256M)

That discovery implicated a quite large rewrite of lsblk.sh. The git commit estimates this as 69% code rewrite.

# git commit (...)
(...)
 1 file changed, 487 insertions(+), 501 deletions(-)
 rewrite lsblk.sh (69%)

The latest lsblk.sh has now these features:

  • Previous bugs fixed.
  • Detects exFAT labels.
  • Is now 20% faster.
  • Has less 10% SLOC.
  • Has less 15% of code.
  • Handles bsdlabel(8) on entire device properly.
  • Handles exFAT on entire device properly.

The difference in code is shown below.

# wc lsblk.sh
     487    1791   13705 lsblk.sh

# wc lsblk.sh.OLD
     544    1931   16170 lsblk.sh.OLD

Latest lsblk.sh looks as usual but I now use ‘-‘ instead of ‘[UNMOUNTED]‘ one.

lsblk.2.5.gpart.exfat

EOF

Fix Broken Dependency on FreeBSD

Dunno about you but I update my packages often … and I have lots of them, more then 1000 actually.

% pkg info | wc -l
    1051

… but its not much, they are mostly dependencies to to software that I use.

For example I need Openbox and X11 but to use them I need 300+ dependencies in libraries and protocols, and its OK, that’s how it works … but sometimes after the upgrade one or two applications forbid to start because of missing dependency. I would sa that it happens one in twenty to thirty updates (1/20 – 1/30) which is very rare and even if it happens its very easy to solve. I also happened to me on Linux systems many times so its not FreeBSD only related, its just how open source desktop/laptop market works ๐Ÿ™‚

Today’s victim will be Chromium. I generally use Firefox but sometimes when a page behaves strangely in Firefox I verify this behavior in Chromium. I also use Chromium as file opener (or file browser should I say) for the *.htm/*.html/*.chm local files. But this time it forbid to start, so I went to the command line to check what went wrong.

% chrome
Shared object "libx264.so.155" not found, required by "libavcodec.so.58"

… a missing dependency in the form of libx264.so.155 library.

Reckless Symlink

This method is considered dangerous or quick and dirty way of fixing such problems – it can also introduce other problems by itself – but still – in many cases it temporary solves the problem.

… and its exactly that – a quick fix till the ffmpeg package finishes its rebuild – it takes longer then pkg upgrade command but when I need Chromium now its NOW, not later when ffmpeg package will be rebuilt. This problem is caused by lack of guts of the FreeBSD project to provide lame package. OpenBSD guys does not have problem with that but FreeBSD guys do, so to have MP3 support in ffmpeg you need to first manually build lame package and then select it as option in ffmpeg and again built is as package … and do that everytime you run pkg upgrade command … which is PITA to say the least.

This is why I use pkg-recompile.sh script for that purpose – to not do that โ€˜by handโ€™ everytime I update packages (which is about two times a week). This is the โ€˜workflowโ€™ if I can call it like that:

# pkg upgrade
# pkg-recompile.sh build

Lets verify it something else is not missing for Chromium then.

% which chrome
/usr/local/bin/chrome

% ldd /usr/local/bin/chrome
ldd: /usr/local/bin/chrome: not a dynamic executable

So /usr/local/bin/chrome is just a wrapper, let’s see what it contains.

% cat /usr/local/bin/chrome
#!/bin/sh

SYSCTL=kern.ipc.shm_allow_removed
if [ "`/sbin/sysctl -n $SYSCTL`" = 0 ] ; then
        cat << EOMSG
For correct operation, shared memory support has to be enabled
in Chromium by performing the following command as root :

sysctl $SYSCTL=1

To preserve this setting across reboots, append the following
to /etc/sysctl.conf :

$SYSCTL=1
EOMSG
        exit 1
fi
ulimit -c 0
exec /usr/local/share/chromium/chrome ${1+"$@"}

So our binary actually is /usr/local/share/chromium/chrome file, lets check it with ldd(8) then.

% ldd /usr/local/share/chromium/chrome
/usr/local/share/chromium/chrome:
        libthr.so.3 => /lib/libthr.so.3 (0x809b78000)
        libX11.so.6 => /usr/local/lib/libX11.so.6 (0x809da0000)
        libX11-xcb.so.1 => /usr/local/lib/libX11-xcb.so.1 (0x80a0df000)
        libxcb.so.1 => /usr/local/lib/libxcb.so.1 (0x80a2e0000)
        libXcomposite.so.1 => /usr/local/lib/libXcomposite.so.1 (0x80a506000)
        libXcursor.so.1 => /usr/local/lib/libXcursor.so.1 (0x80a708000)
        libXdamage.so.1 => /usr/local/lib/libXdamage.so.1 (0x80a913000)
        libXext.so.6 => /usr/local/lib/libXext.so.6 (0x80ab15000)
        libXfixes.so.3 => /usr/local/lib/libXfixes.so.3 (0x80ad26000)
        libXi.so.6 => /usr/local/lib/libXi.so.6 (0x80af2b000)
        libXrender.so.1 => /usr/local/lib/libXrender.so.1 (0x80b139000)
        libXtst.so.6 => /usr/local/lib/libXtst.so.6 (0x80b342000)
        libgmodule-2.0.so.0 => /usr/local/lib/libgmodule-2.0.so.0 (0x80b547000)
        libglib-2.0.so.0 => /usr/local/lib/libglib-2.0.so.0 (0x80b74a000)
        libgobject-2.0.so.0 => /usr/local/lib/libgobject-2.0.so.0 (0x80ba61000)
        libgthread-2.0.so.0 => /usr/local/lib/libgthread-2.0.so.0 (0x80bcab000)
        libintl.so.8 => /usr/local/lib/libintl.so.8 (0x80beac000)
        libnss3.so => /usr/local/lib/nss/libnss3.so (0x80c0b7000)
        libsmime3.so => /usr/local/lib/nss/libsmime3.so (0x80c3e3000)
        libnssutil3.so => /usr/local/lib/nss/libnssutil3.so (0x80c60d000)
        libplds4.so => /usr/local/lib/libplds4.so (0x80c83d000)
        libplc4.so => /usr/local/lib/libplc4.so (0x80ca40000)
        libnspr4.so => /usr/local/lib/libnspr4.so (0x80cc44000)
        libdl.so.1 => /usr/lib/libdl.so.1 (0x80ce83000)
        libcups.so.2 => /usr/local/lib/libcups.so.2 (0x80d084000)
        libxml2.so.2 => /usr/local/lib/libxml2.so.2 (0x80d315000)
        libfontconfig.so.1 => /usr/local/lib/libfontconfig.so.1 (0x80d6a8000)
        libdbus-1.so.3 => /usr/local/lib/libdbus-1.so.3 (0x80d8ef000)
        libexecinfo.so.1 => /usr/lib/libexecinfo.so.1 (0x80db40000)
        libkvm.so.7 => /lib/libkvm.so.7 (0x80dd43000)
        libutil.so.9 => /lib/libutil.so.9 (0x80df51000)
        libXss.so.1 => /usr/local/lib/libXss.so.1 (0x80e165000)
        libwebpdemux.so.2 => /usr/local/lib/libwebpdemux.so.2 (0x80e367000)
        libwebpmux.so.3 => /usr/local/lib/libwebpmux.so.3 (0x80e56b000)
        libwebp.so.7 => /usr/local/lib/libwebp.so.7 (0x80e775000)
        libfreetype.so.6 => /usr/local/lib/libfreetype.so.6 (0x80ea05000)
        libjpeg.so.8 => /usr/local/lib/libjpeg.so.8 (0x80ecbb000)
        libexpat.so.1 => /usr/local/lib/libexpat.so.1 (0x80ef4e000)
        libharfbuzz.so.0 => /usr/local/lib/libharfbuzz.so.0 (0x80f179000)
        libdrm.so.2 => /usr/local/lib/libdrm.so.2 (0x80f458000)
        libXrandr.so.2 => /usr/local/lib/libXrandr.so.2 (0x80f66b000)
        libgio-2.0.so.0 => /usr/local/lib/libgio-2.0.so.0 (0x80f875000)
        libavcodec.so.58 => /usr/local/lib/libavcodec.so.58 (0x80fe00000)
        libavformat.so.58 => /usr/local/lib/libavformat.so.58 (0x811800000)
        libavutil.so.56 => /usr/local/lib/libavutil.so.56 (0x811c52000)
        libopenh264.so.4 => /usr/local/lib/libopenh264.so.4 (0x811eca000)
        libasound.so.2 => /usr/local/lib/libasound.so.2 (0x8121da000)
        libsnappy.so.1 => /usr/local/lib/libsnappy.so.1 (0x8124de000)
        libopus.so.0 => /usr/local/lib/libopus.so.0 (0x8126e6000)
        libpangocairo-1.0.so.0 => /usr/local/lib/libpangocairo-1.0.so.0 (0x812956000)
        libpango-1.0.so.0 => /usr/local/lib/libpango-1.0.so.0 (0x812b63000)
        libcairo.so.2 => /usr/local/lib/libcairo.so.2 (0x812db1000)
        libGL.so.1 => /usr/local/lib/libGL.so.1 (0x8130d8000)
        libpci.so.3 => /usr/local/lib/libpci.so.3 (0x813366000)
        libatk-1.0.so.0 => /usr/local/lib/libatk-1.0.so.0 (0x813571000)
        libatk-bridge-2.0.so.0 => /usr/local/lib/libatk-bridge-2.0.so.0 (0x81379c000)
        libatspi.so.0 => /usr/local/lib/libatspi.so.0 (0x8139cc000)
        libFLAC.so.8 => /usr/local/lib/libFLAC.so.8 (0x813bfd000)
        libgtk-3.so.0 => /usr/local/lib/libgtk-3.so.0 (0x814000000)
        libgdk-3.so.0 => /usr/local/lib/libgdk-3.so.0 (0x8148b9000)
        libcairo-gobject.so.2 => /usr/local/lib/libcairo-gobject.so.2 (0x814bb0000)
        libgdk_pixbuf-2.0.so.0 => /usr/local/lib/libgdk_pixbuf-2.0.so.0 (0x814db8000)
        libxslt.so.1 => /usr/local/lib/libxslt.so.1 (0x814fdb000)
        libz.so.6 => /lib/libz.so.6 (0x815218000)
        liblzma.so.5 => /usr/lib/liblzma.so.5 (0x815430000)
        libm.so.5 => /lib/libm.so.5 (0x815659000)
        librt.so.1 => /usr/lib/librt.so.1 (0x815886000)
        libc++.so.1 => /usr/lib/libc++.so.1 (0x815a8c000)
        libcxxrt.so.1 => /lib/libcxxrt.so.1 (0x815d5a000)
        libc.so.7 => /lib/libc.so.7 (0x800823000)
        libXau.so.6 => /usr/local/lib/libXau.so.6 (0x815f79000)
        libXdmcp.so.6 => /usr/local/lib/libXdmcp.so.6 (0x81617c000)
        libiconv.so.2 => /usr/local/lib/libiconv.so.2 (0x816381000)
        libpcre.so.1 => /usr/local/lib/libpcre.so.1 (0x81667c000)
        libffi.so.6 => /usr/local/lib/libffi.so.6 (0x81691a000)
        libgnutls.so.30 => /usr/local/lib/libgnutls.so.30 (0x816b21000)
        libavahi-common.so.3 => /usr/local/lib/libavahi-common.so.3 (0x816ed4000)
        libavahi-client.so.3 => /usr/local/lib/libavahi-client.so.3 (0x8170e0000)
        libcrypt.so.5 => /lib/libcrypt.so.5 (0x8172ef000)
        libelf.so.2 => /lib/libelf.so.2 (0x81750e000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x817725000)
        libbz2.so.4 => /usr/lib/libbz2.so.4 (0x817934000)
        libgraphite2.so.3 => /usr/local/lib/libgraphite2.so.3 (0x817b48000)
        libswresample.so.3 => /usr/local/lib/libswresample.so.3 (0x817d71000)
        libvpx.so.6 => /usr/local/lib/libvpx.so.6 (0x818000000)
        libdav1d.so.1 => /usr/local/lib/libdav1d.so.1 (0x818411000)
        libmp3lame.so.0 => /usr/local/lib/libmp3lame.so.0 (0x818732000)
        libtheoraenc.so.1 => /usr/local/lib/libtheoraenc.so.1 (0x8189b3000)
        libtheoradec.so.1 => /usr/local/lib/libtheoradec.so.1 (0x818be2000)
        libvorbis.so.0 => /usr/local/lib/libvorbis.so.0 (0x818df3000)
        libvorbisenc.so.2 => /usr/local/lib/libvorbisenc.so.2 (0x819024000)
        libx264.so.155 => not found (0)
        libx265.so.170 => /usr/local/lib/libx265.so.170 (0x819400000)
        libxvidcore.so.4 => /usr/local/lib/libxvidcore.so.4 (0x819b4b000)
        libva.so.2 => /usr/local/lib/libva.so.2 (0x819e70000)
        libgmp.so.10 => /usr/local/lib/libgmp.so.10 (0x81a096000)
        libva-drm.so.2 => /usr/local/lib/libva-drm.so.2 (0x81a316000)
        libva-x11.so.2 => /usr/local/lib/libva-x11.so.2 (0x81a518000)
        libvdpau.so.1 => /usr/local/lib/libvdpau.so.1 (0x81a71d000)
        libpangoft2-1.0.so.0 => /usr/local/lib/libpangoft2-1.0.so.0 (0x81a920000)
        libfribidi.so.0 => /usr/local/lib/libfribidi.so.0 (0x81ab36000)
        libpixman-1.so.0 => /usr/local/lib/libpixman-1.so.0 (0x81ad4c000)
        libEGL.so.1 => /usr/local/lib/libEGL.so.1 (0x81b016000)
        libpng16.so.16 => /usr/local/lib/libpng16.so.16 (0x81b24e000)
        libxcb-shm.so.0 => /usr/local/lib/libxcb-shm.so.0 (0x81b489000)
        libxcb-render.so.0 => /usr/local/lib/libxcb-render.so.0 (0x81b68b000)
        libxcb-dri3.so.0 => /usr/local/lib/libxcb-dri3.so.0 (0x81b898000)
        libxcb-xfixes.so.0 => /usr/local/lib/libxcb-xfixes.so.0 (0x81ba9b000)
        libxcb-present.so.0 => /usr/local/lib/libxcb-present.so.0 (0x81bca2000)
        libxcb-sync.so.1 => /usr/local/lib/libxcb-sync.so.1 (0x81bea4000)
        libxshmfence.so.1 => /usr/local/lib/libxshmfence.so.1 (0x81c0aa000)
        libglapi.so.0 => /usr/local/lib/libglapi.so.0 (0x81c2ab000)
        libxcb-glx.so.0 => /usr/local/lib/libxcb-glx.so.0 (0x81c505000)
        libxcb-dri2.so.0 => /usr/local/lib/libxcb-dri2.so.0 (0x81c71e000)
        libXxf86vm.so.1 => /usr/local/lib/libXxf86vm.so.1 (0x81c922000)
        libogg.so.0 => /usr/local/lib/libogg.so.0 (0x81cb26000)
        libXinerama.so.1 => /usr/local/lib/libXinerama.so.1 (0x81cd2c000)
        libxkbcommon.so.0 => /usr/local/lib/libxkbcommon.so.0 (0x81cf2e000)
        libwayland-cursor.so.0 => /usr/local/lib/libwayland-cursor.so.0 (0x81d16b000)
        libwayland-egl.so.1 => /usr/local/lib/libwayland-egl.so.1 (0x81d372000)
        libwayland-client.so.0 => /usr/local/lib/libwayland-client.so.0 (0x81d573000)
        libepoxy.so.0 => /usr/local/lib/libepoxy.so.0 (0x81d782000)
        libp11-kit.so.0 => /usr/local/lib/libp11-kit.so.0 (0x81da91000)
        libtasn1.so.6 => /usr/local/lib/libtasn1.so.6 (0x81ddb2000)
        libnettle.so.6 => /usr/local/lib/libnettle.so.6 (0x81dfc7000)
        libhogweed.so.4 => /usr/local/lib/libhogweed.so.4 (0x81e1ff000)
        libidn2.so.0 => /usr/local/lib/libidn2.so.0 (0x81e435000)
        libunistring.so.2 => /usr/local/lib/libunistring.so.2 (0x81e653000)
        libgbm.so.1 => /usr/local/lib/libgbm.so.1 (0x81ea07000)
        libwayland-server.so.0 => /usr/local/lib/libwayland-server.so.0 (0x81ec15000)
        libepoll-shim.so.0 => /usr/local/lib/libepoll-shim.so.0 (0x81ee28000)

Lots of deps here, lets cut to the point with grep(1) as shown below.

% ldd /usr/local/share/chromium/chrome | grep found
        libx264.so.155 => not found (0)

Only one – libx264.so.155 – dependency is missing. Let’s fix it then.

% cd /usr/local/lib
% ls -l libx264.so*
lrwxr-xr-x  1 root  wheel       14 2019.03.19 02:11 libx264.so -> libx264.so.157
-rwxr-xr-x  1 root  wheel  2090944 2019.03.19 02:11 libx264.so.157

There is little newer version available libx264.so.157 so we will link to it with our ‘missing’ libx264.so.155 name.

# pwd
/usr/local/lib
# ln -s libx264.so libx264.so.155
# ls -l libx264.so*
lrwxr-xr-x  1 root  wheel       14 2019.03.19 02:11 libx264.so -> libx264.so.157
lrwxr-xr-x  1 root  wheel       10 2019.03.21 15:26 libx264.so.155 -> libx264.so
-rwxr-xr-x  1 root  wheel  2090944 2019.03.19 02:11 libx264.so.157

Chromium should be happy now.

% ldd /usr/local/share/chromium/chrome | grep found
% 

Zero not found results.

Let’s start Chromium then with chrome command.

% chrome

Starts as usual and everything works ๐Ÿ™‚

This whole process can be visualized with this simple screenshots below.

vermaden_2019-03-21_15-47-40.png

Using /etc/libmap.conf File

Instead making ad symlink – which will work globally – you can create the proper libmap.conf file with configuration only for /usr/local/share/chromium/chrome binary.

Here is the fix only for Chromium browser.

# cat /etc/libmap.conf

[/usr/local/share/chromium/chrome]
libx264.so.155 libx264.so

… and equivalent solution that works globally as symlink would be as follows.

# cat /etc/libmap.conf

libx264.so.155 libx264.so

Its also easier to migrate or mass populate such changes instead of copying a symlink.

Fixing Broken Dependency in pkg(8) Database

I already wrote about it in the Less Known pkg(8) Features article but its worth mentioning here for the completeness of options.

There was time when one missing dependency about vulnerable www/libxul19 package started to torture me for some time.

I was even desperate to compile everything with portmaster already.

I started with portmaster --check-depends command, but said no ‘n‘ when asked for fix as it will downgrade a lot of packages needlessly.

# portmaster --check-depends
(...)
Checking dependencies: evince
graphics/evince has a missing dependency: www/libxul19
(...)

>>> Missing package dependencies were detected.
>>> Found 1 issue(s) in total with your package database.

The following packages will be installed:

        Downgrading perl: 5.14.2_3 -> 5.14.2_2
        Downgrading glib: 2.34.3 -> 2.28.8_5
        Downgrading gio-fam-backend: 2.34.3 -> 2.28.8_1
        Downgrading libffi: 3.0.12 -> 3.0.11
        Downgrading gobject-introspection: 1.34.2 -> 0.10.8_3
        Downgrading atk: 2.6.0 -> 2.0.1
        Downgrading gdk-pixbuf2: 2.26.5 -> 2.23.5_3
        Downgrading pango: 1.30.1 -> 1.28.4_1
        Downgrading gtk-update-icon-cache: 2.24.17 -> 2.24.6_1
        Downgrading dbus: 1.6.8 -> 1.4.14_4
        Downgrading gtk: 2.24.17 -> 2.24.6_2
        Downgrading dbus-glib: 0.100.1 -> 0.94
        Installing libxul: 1.9.2.28_1

The installation will require 66 MB more space

38 MB to be downloaded

>>> Try to fix the missing dependencies [y/N]: n
>>> Summary of actions performed:

www/libxul19 dependency failed to be fixed

>>> There are still missing dependencies.
>>> You are advised to try fixing them manually.

>>> Also make sure to check 'pkg updating' for known issues.

Lets see what pkg(8) shows we have installed.

# pkg info | grep libxul
libxul-10.0.12                 Mozilla runtime package that can be used to bootstrap XUL+XPCOM apps

# pkg info -qoa | grep libxul
www/libxul

So the problem is that we have installed www/libxul instead of www/libxul19 and that is why portmaster (and not only) complains about it.

Before pkg(8) was introduced it was easy just to grep -r the entire /var/db/pkg directory with its ‘file database’ but now its quite more complicated as the package database is kept in SQLite database. Using pkg shell command You can connect to that database. Lets check what we can find there.

# pkg shell
SQLite version 3.7.13 2012-06-11 02:05:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .databases
seq  name             file
---  ---------------  ----------------------------------------------------------
0    main             /var/db/pkg/local.sqlite
sqlite> .tables
categories       licenses         pkg_directories  scripts
deps             mtree            pkg_groups       shlibs
directories      options          pkg_licenses     users
files            packages         pkg_shlibs
groups           pkg_categories   pkg_users
sqlite> .header on
sqlite> .mode column
sqlite> pragma table_info(deps);
cid         name        type        notnull     dflt_value  pk
----------  ----------  ----------  ----------  ----------  ----------
0           origin      TEXT        1                       1
1           name        TEXT        1                       0
2           version     TEXT        1                       0
3           package_id  INTEGER     0                       1
sqlite> .quit

So now we know that ‘deps‘ table is probably what we are looking for ;).

As pkg shell is quite limited for SQLite ‘browsing’ I will use the sqlite3 command itself. By limited I mean that You can not type pkg shell "select * from deps;" query, You first need to start pkg shell and then You can type your query.

# sqlite3 -column /var/db/pkg/local.sqlite "select * from deps;" | grep libxul
www/libxul19   libxul      1.9.2.28_1  104

The second column is name so lets try to use it.

sqlite3 -header -column /var/db/pkg/local.sqlite "select * from deps where name='libxul';"
origin        name        version     package_id
------------  ----------  ----------  ----------
www/libxul19  libxul      1.9.2.28_1  104

So now we have the ‘problematic’ dependency entry nailed, lets modify it a little to the real installed packages state.

# sqlite3 /var/db/pkg/local.sqlite "update deps set origin='www/libxul' where name='libxul';"
# sqlite3 /var/db/pkg/local.sqlite "update deps set version='10.0.12' where name='libxul';"

You can of course use the ‘official’ way by using the pkg shell command.

# pkg shell
SQLite version 3.7.13 2012-06-11 02:05:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> update deps set origin='www/libxul' where name='libxul';
sqlite> update deps set version='10.0.12' where name='libxul';
sqlite> .header on
sqlite> .mode column
sqlite> select * from deps where name='libxul';
origin      name        version     package_id
----------  ----------  ----------  ----------
www/libxul  libxul      10.0.12     104
sqlite> .quit

Now portmaster is happy and does not complain about any missing dependencies.

# portmaster --check-depends
(...)
Checking dependencies: zenity
Checking dependencies: zip
Checking dependencies: zsh
# 

Viola! Problem solved ๐Ÿ˜‰

… but pkg(8) has a tool for that already ๐Ÿ™‚

Its called pkg set and two most useful options from man pkg-set are.

  -n oldname:newname, --change-name oldname:newname
       Change the package name of a given dependency from oldname to newname.

(...)

  -o oldorigin:neworigin, --change-origin oldorigin:neworigin
       Change the port origin of a given dependency from oldorigin to neworigin.
       This corresponds to the port directory that the package originated from.
       Typically, this is only needed for upgrading a library or package that
       has MOVED or when the default version of a major port dependency changes.
       (DEPRECATED) Usually this will be explained in /usr/ports/UPDATING.
       Also see pkg-updating(8) and EXAMPLES.

In our case we would use pkg set -o www/libxul19:www/libxul command.

Not sure if it will solve that problem in the same way as I also updated the version in the database.

Use pkg_libchk from bsdadminscripts2 Package

There is also other way to fix/check for such problems – its the pkg_libchk from the bsdadminscripts2 package. Keep in mind that there are TWO conflicting (!) packages with bsdadminscripts in their name.

# pkg search bsdadmin
bsdadminscripts-6.1.1_8        Collection of administration scripts
bsdadminscripts2-0.2.1         BSD Administration Scripts 2

ย 

… and once you install bsdadminscripts2 you will not be able to install bsdadminscripts because they are conflicting. I already had bsdadminscripts2 installed and wanted to add bsdadminscripts to my system.

# pkg install bsdadminscripts
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (1 conflicting)
  - bsdadminscripts-6.1.1_8 conflicts with bsdadminscripts2-0.2.1 on /usr/local/sbin/distviper
Checking integrity... done (0 conflicting)
The following 2 package(s) will be affected (of 0 checked):

Installed packages to be REMOVED:
        bsdadminscripts2-0.2.1

New packages to be INSTALLED:
        bsdadminscripts: 6.1.1_8

Number of packages to be removed: 1
Number of packages to be installed: 1

Proceed with this action? [y/N]: n

Here is the description of the /usr/ports/ports-mgmt/bsdadminscripts2 port/package.

# cat /usr/ports/ports-mgmt/bsdadminscripts2/pkg-descr
This is a collection of scripts around the use of ports and packages.

It allows you to: 
- check library dependencies without producing false positives (pkg_libchk)
- lets you manage the autoremove flag for leaf packages (pkg_trim)
- remove obsolete or damaged distfiles (distviper)
- manage build flags (buildflags.conf)
- auto-create pkg-plist files taking port options into account (makeplist)

WWW: https://github.com/lonkamikaze/bsda2

There are exactly 4 tools in this package.

% pkg info -l bsdadminscripts2 | grep bin
        /usr/local/sbin/distviper
        /usr/local/sbin/makeplist
        /usr/local/sbin/pkg_libchk
        /usr/local/sbin/pkg_trim

Invoked without any arguments it will check all packages installed in a system.

# pkg_libchk
Jobs done:   35 of 1057
bhyve-firmware-1.0_1
bash-5.0.3
beadm-1.2.9_1

… so in order to make the ckecks only for Chromium you will need to specify chromium package with pkg_libchk chromium command.

The pkg_libchk allows you to fetch missing dependencies based on which package provides what files or create a list of the packages that need to be rebuilt.

Use Provides Database

You can also use ‘provides’ database from pkg(8) command.

% pkg provides lib/libx264.so
Name    : libx264-0.157.2945
Desc    : H.264/MPEG-4 AVC Video Encoding (Library)
Repo    : FreeBSD
Filename: /usr/local/lib/libx264.so.155
          /usr/local/lib/libx264.so

To learn how to setup ‘provides’ database for pkg(8) command check the Less Known pkg(8) Features article please.

UPDATE 1 – Rework Entire Article

The Roman philosopher Seneca once said – “While we teach, we learn.” – it is very true – especially for this article. After I posted it on various places people reminded my that its not the best way to just create symlink and that its not the best way to do it. I stand corrected and added additional sections and methods of fixing a broken dependency on a FreeBSD (or Linux/Illumos) system.

EOF

FreeBSD Desktop – Part 18 – Configuration – Global Dashboard

Many times I have found myself watching the various ‘debug’ commands like top/ps/mount/df or various log files like /var/log/messages or /var/log/automount.log when I thought something went wrong … or just takes little too long. I needed to open several terminal xterm(1) sessions (which is quite fast as I open them with [WIN]+[SPACE] and then [ENTER] but still …) and check what went wrong.

These actions tired my so I created a thing called Global Dashboard with all information I would ever need for such debugging.

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.

From all the commands that FreeBSD contains I have chosen these 12 ones:

  • mount -p
  • /var/log/automount.log
  • /var/log/messages
  • vmstat -i
  • usbconfig
  • ps axwww -o %cpu,rss,command
  • sockstat -l -4
  • top -m io -o total
  • gstat -p
  • df -g
  • pciconf -l
  • ifconfig

Make sure you have doas(1) installed and configured. The most basic way to do it is below. You will have to be in wheel group to make it work properly.

# pkg install doas
# echo 'permit nopass :wheel as root' > /usr/local/etc/doas.conf
# chmod 400 /usr/local/etc/doas.conf

Let me show you how it looks.

Here is the typical empty desktop with Global Dashboard disabled.

conky-off.png

… and here is the Global Dashboard enabled.

conky-on.png

For the sake of comfort I will use [Scroll Lock] key with xbindkeys to toggle between this ‘debug’ session on and off as I already use [Pause Break] key to Pause Any Application described in the Part 16 – Configuration – Pause Any Application episode of FreeBSD Desktop series.

scroll-lock.jpg

Conky

We will have to use older (1.9) version of Conky as the current one (1.10/1.11) are broken for anything serious.

We will use portdowngrade tool for that job.

First, lets install needed packages.

# pkg install portdowngrade conky xbindkeys

Assuming that you have up to date FreeBSD Ports tree in the /usr/ports directory – we see that current Conky version in the Ports is 1.11.

% cd /usr/ports/sysutils/conky
% cat distinfo 
TIMESTAMP = 1550919299
SHA256 (brndnmtthws-conky-v1.11.3_GH0.tar.gz) = 0140e749537d4d05bf33fbac436e54756faa26021e16f2bca418e9eeea724eb4
SIZE (brndnmtthws-conky-v1.11.3_GH0.tar.gz) = 2390099

We will now downgrade the Conky port to usable 1.9 version with portdowngrade utility. I already tried various Conky Port versions and the one that you are looking for is r419144 revision.

# cd /usr/ports/sysutils
# mv conky conky-1.11
# portdowngrade sysutils/conky | grep -C 17 r419144
------------------------------------------------------------------------
r422880 | madpilot | 2016-09-28 18:55:38 +0200 (Wed, 28 Sep 2016) | 13 lines

- Update conky and conky-awesome to 1.10.4
- Take maintainership [1]
- Options adapted to new version
- Removed LUA option since it's a mandatoory requirement now
- Use project own install target
- Fix installation of lua helper libraries
- Project moved to github
- in conky-awesome, properly use OPTIONS_EXCLUDE

PR:           212629
Submitted by: me
Approved by:  ntarmos@ceid.upatras.gr (former maintainer) [1]

------------------------------------------------------------------------
r419144 | pawel | 2016-07-26 20:57:23 +0200 (Tue, 26 Jul 2016) | 2 lines

Fix typo

------------------------------------------------------------------------
r419142 | pawel | 2016-07-26 20:40:20 +0200 (Tue, 26 Jul 2016) | 8 lines

- Add explicit IMPLIES between dependencies and simplify option handling [1]
- Convert to USES=localbase
- Switch some options helpers from LIB_DEPENDS to USE=xorg and USE=gnome

PR:           210414 [1] (based on)
Submitted by: elferdo@gmail.com
Approved by:  maintainer timeout

------------------------------------------------------------------------
r418767 | mat | 2016-07-19 13:04:13 +0200 (Tue, 19 Jul 2016) | 11 lines

We will now fetch the Conky port from r419144 revision – working 1.9 version.

# portdowngrade sysutils/conky r419144
A    conky/files
A    conky/Makefile
A    conky/files/patch-configure
A    conky/files/patch-lua-cairo.pkg
A    conky/files/patch-src-conky.c
A    conky/files/patch-src-freebsd.c
A    conky/files/patch-src-freebsd.h
A    conky/files/patch-src-fs.c
A    conky/pkg-descr
A    conky/distinfo
Checked out revision 419144.
You should be done-- now cd into conky and you can run
# make deinstall install clean

Please note that portdowngrade no longer modifies the ports tree; the
checked out port is at
/usr/ports/sysutils/conky

Done. Let’s verify that its the version we need.

% pwd
/usr/ports/sysutils
% cat conky-1.11/distinfo 
TIMESTAMP = 1550919299
SHA256 (brndnmtthws-conky-v1.11.3_GH0.tar.gz) = 0140e749537d4d05bf33fbac436e54756faa26021e16f2bca418e9eeea724eb4
SIZE (brndnmtthws-conky-v1.11.3_GH0.tar.gz) = 2390099

% cat conky/distinfo 
SHA256 (conky-1.9.0.tar.bz2) = baf1b550f135fbfb53e5e286a33aadc03a667d63bf6c4d52ba7637366295bb6f
SIZE (conky-1.9.0.tar.bz2) = 626555

Yup. We will now build a Conky 1.9 package (may be handy later).

# pwd
/usr/ports/sysutils
# cd conky
# pwd
/usr/ports/sysutils/conky
# make package
===>   conky-1.9.0_6 depends on file: /usr/local/sbin/pkg - found
=> conky-1.9.0.tar.bz2 doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://downloads.sourceforge.net/project/conky/conky/1.9.0/conky-1.9.0.tar.bz2
conky-1.9.0.tar.bz2                           100% of  611 kB  216 kBps 00m03s
===> Fetching all distfiles required by conky-1.9.0_6 for building
===>  Extracting for conky-1.9.0_6
=> SHA256 Checksum OK for conky-1.9.0.tar.bz2.
===>  Patching for conky-1.9.0_6
===>  Applying FreeBSD patches for conky-1.9.0_6
===>   conky-1.9.0_6 depends on executable: gmake - found
===>   conky-1.9.0_6 depends on package: libiconv>=1.14_11 - found
===>   conky-1.9.0_6 depends on package: pkgconf>=1.3.0_1 - found
===>   conky-1.9.0_6 depends on file: /usr/local/libdata/pkgconfig/x11.pc - found
===>   conky-1.9.0_6 depends on file: /usr/local/libdata/pkgconfig/xext.pc - found
===>   conky-1.9.0_6 depends on file: /usr/local/libdata/pkgconfig/xdamage.pc - found
===>   conky-1.9.0_6 depends on file: /usr/local/libdata/pkgconfig/xfixes.pc - found
===>   conky-1.9.0_6 depends on file: /usr/local/libdata/pkgconfig/xft.pc - found
===>  Configuring for conky-1.9.0_6
===>   FreeBSD 10 autotools fix applied to /usr/ports/obj/usr/ports/sysutils/conky/work/conky-1.9.0/config.rpath
(...)
====> Compressing man pages (compress-man)
===>  Building package for conky-1.9.0_6
===>  Cleaning for conky-1.9.0_6

… but where is our package, its not in the /usr/ports/sysutils/conky directory. Its not in the /usr/ports/distfiles dir either.

As I use WRKDIRPREFIX=${PORTSDIR}/obj option in the /etc/make.conf file it should be somewhere in the /usr/ports/obj then.

% grep WRKDIRPREFIX /etc/make.conf 
WRKDIRPREFIX=${PORTSDIR}/obj

Let’s find(1) it.

% find /usr/ports/obj -name conky\*txz
/usr/ports/obj/usr/ports/sysutils/conky/work/pkg/conky-1.9.0_6.txz

There. I will move it to /root directory to keep it.

# mv /usr/ports/obj/usr/ports/sysutils/conky/work/pkg/conky-1.9.0_6.txz /root

We will not clean up after the port/package building.

# make -C /usr/ports/sysutils/conky clean distclean
===>  Cleaning for conky-1.9.0_6
# 

We will now delete installed Conky 1.11 version and install our working 1.9 version.

# pkg delete conky
Checking integrity... done (0 conflicting)
Deinstallation has been requested for the following 1 packages (of 0 packages in the universe):

Installed packages to be REMOVED:
        conky-1.11.3

Number of packages to be removed: 1

Proceed with deinstalling packages? [y/N]: y
[1/1] Deinstalling conky-1.11.3...
[1/1] Deleting files for conky-1.11.3: 100%

# pkg add /root/conky-1.9.0_6.txz
Installing conky-1.9.0_6...
Extracting conky-1.9.0_6: 100%

Last check for the Conky version.

% conky --version
Conky 1.9.0 compiled Tue Mar 19 12:55:55 CET 2019 for FreeBSD 11.2-RELEASE-p9 (amd64)

Compiled in features:

System config file: /usr/local/etc/conky/conky.conf
Package library path: /usr/local/lib/conky

 X11:
  * Xdamage extension
  * XDBE (double buffer extension)
  * Xft
  * ARGB visual

 Music detection:

 General:
  * math
  * config-output

Great. We have needed Conky version.

By the way – did you thought how much work will it take to make the same on Debian or CentOS without the FreeBSD Ports infrastructure? ๐Ÿ™‚

Xbindkeys

The only needed configuration in the ~/.xbindkeysrc is this one below – it may be different for your keyboard so make sure to ‘catch’ needed key event.

% cat ~/.xbindkeysrc
# SCROLL LOCK | Scroll Lock
"~/scripts/desktop-debug.sh"
  m:0x0 + c:78

If you need more information about how Xbindkeys work then read the FreeBSD Desktop – Part 9 – Key Components – Keyboard/Mouse Shortcuts episode.

Scripts and Configs

This is the ~/scripts/desktop-debug.sh script.

#! /bin/sh

pgrep -q conky

case ${?} in
  (0) killall -9 conky ;;
  (1) ~/scripts/__openbox_restart_conky.sh ;;
esac

… and the ~/scripts/__openbox_restart_conky.sh script.

#! /bin/sh

VERSION=1.9
PROFILE=T420s

killall -9 conky

nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.1 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.2 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.3 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.4 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.5 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.6 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.7 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.8 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.9 &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.a &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.b &
nice -n 20 conky -c ~/.conkyrc.${VERSION}.${PROFILE}.LOG.c &

I use have several laptops so I need to distinguish which config files are used on which laptop, that is why I use PROFILE field – which is set to ThinkPad T420s in that example.

Here are the commands defined in these ~/.conkyrc.1.9.T420s.LOG.* files.

% grep exec ~/.conkyrc.1.9.T420s.LOG.*
.conkyrc.1.9.T420s.LOG.1:${color #eeeeee}${exec mount -p | awk '{print $1, $2, $3}' | column -t}
.conkyrc.1.9.T420s.LOG.2:${color #eeeeee}${exec tail -n 16 /var/log/automount.log}
.conkyrc.1.9.T420s.LOG.3:${color #eeeeee}${exec grep -v -E 'pulseaudio|message repeated|null_update_chw|route failed:|send_packet: |gen6_gt_|feeder_|cdce0: (Su|Re)' /var/log/messages | tail -16}
.conkyrc.1.9.T420s.LOG.4:${color #eeeeee}${exec vmstat -i}
.conkyrc.1.9.T420s.LOG.5:${color #eeeeee}${exec doas usbconfig}
.conkyrc.1.9.T420s.LOG.6:${color #eeeeee}${exec ps axwww -o %cpu,rss,command | head -1; ps axwww -o %cpu,rss,command | grep -v conky | grep -v '%CPU' | sort -n -r | head -15 }
.conkyrc.1.9.T420s.LOG.7:${color #eeeeee}${exec sockstat -l -4 | cut -c 1-50}
.conkyrc.1.9.T420s.LOG.8:${color #eeeeee}${exec top -m io -o total -b -s 1 -d 2 | grep -A 15 'PID USERNAME' | tail -n 16}
.conkyrc.1.9.T420s.LOG.9:${color #eeeeee}${exec gstat -p -I 345678}
.conkyrc.1.9.T420s.LOG.a:${color #eeeeee}${exec df -g | awk '{print $5,$6}' | column -t}
.conkyrc.1.9.T420s.LOG.b:${color #eeeeee}${exec pciconf -l}
.conkyrc.1.9.T420s.LOG.c:${color #eeeeee}${exec ifconfig -l -u | sed s/lo0//g | while read I; do ifconfig ${I}; done}

… and here is the diagram showing where these commands are placed.

I will use twelve (12) Conky configuration files for this purpose, each with one of the commands from above list.


 a df(1)       | b pciconf(8)             | c ifconfig(8)
---------------+--------------------------+---------------------
 7 sockstat(1) | 8 top(1)                 | 9 gstat(8)
---------------+--------------------------+---------------------
 4 vmstat(8)   | 5 usbconfig(8)           | 6 ps(1)
---------------+--------------------------+---------------------
 1 mount(8)    | 2 /var/log/automount.log | 3 /var/log/messages

Next are the full Conky configuration files.

~/.conkyrc.1.9.T420s.LOG.1

alignment                bottom_left
background               yes
gap_x                    3
gap_y                    3
minimum_size             279 193
maximum_width            280
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.1
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /sbin/mount -p
${color #eeeeee}${exec mount -p | awk '{print $1, $2, $3}' | column -t}

~/.conkyrc.1.9.T420s.LOG.2

alignment                bottom_left
background               yes
gap_x                    288
gap_y                    3
minimum_size             513 193
maximum_width            514
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.2
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /var/log/automount.log
${color #eeeeee}${exec tail -n 16 /var/log/automount.log}

~/.conkyrc.1.9.T420s.LOG.3

alignment                bottom_left
background               yes
gap_x                    807
gap_y                    3
minimum_size             789 193
maximum_width            790
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.3
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /var/log/messages
${color #eeeeee}${exec grep -v -E 'pulseaudio|message repeated|null_update_chw|route failed:|send_packet: |gen6_gt_|feeder_|cdce0: (Su|Re)' /var/log/messages | tail -16}

~/.conkyrc.1.9.T420s.LOG.4

alignment                bottom_left
background               yes
gap_x                    3
gap_y                    201
minimum_size             279 193
maximum_width            280
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.4
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /usr/bin/vmstat -i
${color #eeeeee}${exec vmstat -i}

~/.conkyrc.1.9.T420s.LOG.5

alignment                bottom_left
background               yes
gap_x                    288
gap_y                    201
minimum_size             513 193
maximum_width            514
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.5
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /usr/sbin/usbconfig
${color #eeeeee}${exec doas usbconfig}

~/.conkyrc.1.9.T420s.LOG.6

alignment                bottom_left
background               yes
gap_x                    807
gap_y                    201
minimum_size             789 193
maximum_width            790
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.6
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /bin/ps axwww -o %cpu,rss,command
${color #eeeeee}${exec ps axwww -o %cpu,rss,command | head -1; ps axwww -o %cpu,rss,command | grep -v conky | grep -v '%CPU' | sort -n -r | head -15 }

~/.conkyrc.1.9.T420s.LOG.7

alignment                bottom_left
background               yes
gap_x                    3
gap_y                    399
minimum_size             279 193
maximum_width            280
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.7
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /usr/bin/sockstat -l -4
${color #eeeeee}${exec sockstat -l -4 | cut -c 1-50}

~/.conkyrc.1.9.T420s.LOG.8

alignment                bottom_left
background               yes
gap_x                    288
gap_y                    399
minimum_size             513 193
maximum_width            514
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.8
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /usr/bin/top -m io -o total
${color #eeeeee}${exec top -m io -o total -b -s 1 -d 2 | grep -A 15 'PID USERNAME' | tail -n 16}

~/.conkyrc.1.9.T420s.LOG.9

alignment                bottom_left
background               yes
gap_x                    807
gap_y                    399
minimum_size             789 193
maximum_width            790
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.9
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /usr/sbin/gstat -p -I 300000
${color #eeeeee}${exec gstat -p -I 345678}

~/.conkyrc.1.9.T420s.LOG.a

alignment                bottom_left
background               yes
gap_x                    3
gap_y                    597
minimum_size             279 272
maximum_width            280
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.7
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /bin/df -g
${color #eeeeee}${exec df -g | awk '{print $5,$6}' | column -t}

~/.conkyrc.1.9.T420s.LOG.b

alignment                bottom_left
background               yes
gap_x                    288
gap_y                    597
minimum_size             513 272
maximum_width            514
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.8
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /usr/sbin/pciconf -l
${color #eeeeee}${exec pciconf -l}

~/.conkyrc.1.9.T420s.LOG.c

alignment                bottom_left
background               yes
gap_x                    807
gap_y                    597
minimum_size             789 272
maximum_width            790
double_buffer            yes
draw_outline             no
draw_shades              no
default_outline_color    444444
default_shade_color      444444
own_window               yes
own_window_class         conky
own_window_colour        222222
own_window_type          override
own_window_transparent   no
update_interval          2.9
use_xft                  yes
xftfont                  ubuntu mono-10
border_inner_margin      0
border_outer_margin      0
border_width             2

TEXT
${color #ee0000}% /sbin/ifconfig wlan0/em0/tun0
${color #eeeeee}${exec ifconfig -l -u | sed s/lo0//g | while read I; do ifconfig ${I}; done}

Thats a quite a lot configuration files but I think that this configuration done once will serve many many times in the future ๐Ÿ™‚

These Conky configuration files are suited for the 1600×900 resolution, you will have to modify values of the gap_x/gap_y/minimum_size/maximum_width parameters to make it fit into other resolution.

Initially I wanted to write a script/generator for that, but lets face it – I will not be able to properly cover each possible resolution ๐Ÿ™‚

UPDATE 2 – Latest Conky 1.11 Also Works

When I wrote this article I wrote that older Conky 1.9 version is needed (The conky-1.9.0_6 exactly which could be retrieved using portdowngrade sysutils/conky r419144 command).

Conky 1.10 introduced many bugs along with entirely new configuration format.

Latest Conky 1.11 (its conky-1.11.4_1 package on my box to be exact) works like a charm with Conky 1.9 configuration. It still has bug of NOT passing the mouse clicks to the desktop so of you want to make a left/middle/right click on the desktop aim on the place other then the Conky Dashboard space.

You can of course still follow the original article and fetch/build Conky with 1.9 version and have working left/middle/right mouse clicks on the desktop.

EOF

The Power to Serve – FreeBSD Power Management

This is the motto of the FreeBSD operating system – The Power to Serve – which also greatly fits for the topic of this article. Decade ago (yes time flies) I even made a wallpaper with this motto – still available on the DeviatArt page.

freebsd_the_power_to_serve_small.jpg

Time for FreeBSD article covering its power management features. It also applies to FreeBSD Desktop series but its not limited to it. Popular opinion seems to be that FreeBSD is so server oriented that it lacks any power management mechanisms. Nothing more far from the truth. While less important on the desktop (but will still lower your electricity bill) or servers it is desirable to properly configure power management on laptops to so they will have longer battery life and will run more quiet.

I write this as the FreeBSD Handbook does not cover all that information in the 11.13. Power and Resource Management chapter. The FreeBSD on Laptops article part 4. Power Management is from the ancient times of FreeBSD 10.1-RELEASE. There is some information on the FreeBSD Wiki page but parts of it are outdated.

FreeBSD offers many mechanisms in the power management department:

  • power off devices without attached driver
  • scale CPU frequency and power
  • supports CPU sleep states (C1/C1E/C2/C3/…)
  • enabling/disabling Turbo Mode available in most CPUs
  • per USB device power management options
  • SATA/AHCI channels/controllers power management
  • suspend/resume support (along with using laptop lid for it)
  • support for vendor specific tools that help to measure power management
  • tools and ACPI support for fan speed control
  • tools and ACPI support for setting screen brightness
  • battery capacity status and running time estimation
  • network interfaces power saving options

One word about different files for the settings in the FreeBSD system:

  • /etc/rc.conf – does not require reboot just daemons reloading
  • /etc/sysctl.conf – does not require reboot – you can set them at runtime
  • /boot/loader.conf – these settings REQUIRE reboot

Here is the Table of Contents (non-clickable) for the article.

  • Information
    • Battery
    • Battery Wear
    • CPU
    • lscpu(1)
    • dmesg(8)
  • CPU Frequency Scaling
    • powerd(8)
    • powerdxx(8)
    • C-States
    • CPU Turbo Mode
  • USB Devices
  • SATA/AHCI Power Management
  • Devices without Driver
    • Nvidia Optimus
  • Suspend and Resume
  • Network Interfaces
  • Vendor Tools
  • DTrace
  • Other
    • ZFS
    • Applications
  • Hardware
  • UPDATE 1 – Graphics Card Power Saving
  • UPDATE 2 – AMD CPU Temperatures
  • UPDATE 3 – Suspend/Resume Tips

Information

Let’s start by describing where to get needed information about current CPU speed, used C-states, current power management modes for USB devices, battery capacity and remaining time, etc.

Battery

To get battery information you can use the acpiconf(8) tool. This is the acpiconf(8) output for my main battery (in the ThinkPad T420s laptop) with AC power attached.

% acpiconf -i 0
Design capacity:        44000 mWh
Last full capacity:     37930 mWh
Technology:             secondary (rechargeable)
Design voltage:         11100 mV
Capacity (warn):        1896 mWh
Capacity (low):         200 mWh
Low/warn granularity:   1 mWh
Warn/full granularity:  1 mWh
Model number:           45N1037
Serial number:          28608
Type:                   LION
OEM info:               SANYO
State:                  high
Remaining capacity:     100%
Remaining time:         unknown
Present rate:           0 mW
Present voltage:        12495 mV

… and with AC power detached.

% acpiconf -i 0
Design capacity:        44000 mWh
Last full capacity:     37930 mWh
Technology:             secondary (rechargeable)
Design voltage:         11100 mV
Capacity (warn):        1896 mWh
Capacity (low):         200 mWh
Low/warn granularity:   1 mWh
Warn/full granularity:  1 mWh
Model number:           45N1037
Serial number:          28608
Type:                   LION
OEM info:               SANYO
State:                  high
Remaining capacity:     100%
Remaining time:         2:31
Present rate:           0 mW
Present voltage:        12492 mV

Now as AC power is detached from the laptop the Remaining time: field will show you remaining time estimation for this single battery shows as 2:31 here (two hours and thirty one minutes).

Below is acpiconf(8) output for my secondary battery (in ThinkPad T420s ultrabay instead of DVD drive).

% acpiconf -i 1
Design capacity:        31320 mWh
Last full capacity:     24510 mWh
Technology:             secondary (rechargeable)
Design voltage:         10800 mV
Capacity (warn):        1225 mWh
Capacity (low):         200 mWh
Low/warn granularity:   1 mWh
Warn/full granularity:  1 mWh
Model number:           45N1041
Serial number:            260
Type:                   LiP
OEM info:               SONY
State:                  high
Remaining capacity:     100%
Remaining time:         unknown
Present rate:           0 mW
Present voltage:        12082 mV

… and with AC power detached.

% acpiconf -i 1
Design capacity:        31320 mWh
Last full capacity:     24510 mWh
Technology:             secondary (rechargeable)
Design voltage:         10800 mV
Capacity (warn):        1225 mWh
Capacity (low):         200 mWh
Low/warn granularity:   1 mWh
Warn/full granularity:  1 mWh
Model number:           45N1041
Serial number:            260
Type:                   LiP
OEM info:               SONY
State:                  discharging
Remaining capacity:     98%
Remaining time:         1:36
Present rate:           14986 mW
Present voltage:        11810 mV

With AC power detached it shows the Remaining time: as 1:36 for the secondary battery.

So its total 4:07 time on battery estimated. The same time in minutes (247) will be shown in the sysctl(8) value named hw.acpi.battery.time as shown below.

% sysctl hw.acpi.battery.time
hw.acpi.battery.time: 247

You can also get more ‘complete’ battery information with below sysctl(8) values under hw.acpi.battery MIB.

% sysctl hw.acpi.battery
hw.acpi.battery.info_expire: 5
hw.acpi.battery.units: 2
hw.acpi.battery.state: 1
hw.acpi.battery.time: 247
hw.acpi.battery.life: 99

The hw.acpi.battery.time will show you ‘-1‘ value if you have AC power attached.

% sysctl hw.acpi.battery
hw.acpi.battery.info_expire: 5
hw.acpi.battery.units: 2
hw.acpi.battery.state: 0
hw.acpi.battery.time: -1
hw.acpi.battery.life: 100

Battery Wear

As time passes by batteries lose their ‘design’ capacity. After 1-2 years such battery can have only 70% or less of its original efficiency.

All the information needed to check that is provided by the acpiconf(8) command with Design capacity: and Last full capacity: values. I have made a battery-capacity.sh script that will tell you what the current battery efficiency is. Here is how it looks in action.

% battery-capacity.sh 0
Battery '0' model '45N1037' has efficiency: 86%

% battery-capacity.sh 1
Battery '1' model '45N1041' has efficiency: 78%

Here is the battery-capacity.sh script itself.

#! /bin/sh

if [ ${#} -ne 1 ]
then
  echo "usage: ${0##*/} BATTERY"
  exit
fi

if acpiconf -i ${1} 1> /dev/null 2> /dev/null
then
  DATA=$( acpiconf -i ${1} )
  MAX=$( echo "${DATA}" | grep '^Design\ capacity:'     | awk -F ':' '{print $2}' | tr -c -d '0-9' )
  NOW=$( echo "${DATA}" | grep '^Last\ full\ capacity:' | awk -F ':' '{print $2}' | tr -c -d '0-9' )
  MOD=$( echo "${DATA}" | grep '^Model\ number:'        | awk -F ':' '{print $2}' | awk '{print $1}' )
  echo -n "Battery '${1}' model '${MOD}' has efficiency: "
  printf '%1.0f%%\n' $( bc -l -e "scale = 2; ${NOW} / ${MAX} * 100" -e quit )
else
  echo "NOPE: Battery '${1}' does not exists on this system."
  echo "INFO: Most systems has only '0' or '1' batteries."
  exit 1
fi

CPU

To get information about current CPU’s you will have to use dev.cpu MIB or dev.cpu.0 for the first physical CPU core.

% sysctl dev.cpu.0
dev.cpu.0.cx_method: C1/hlt C2/io
dev.cpu.0.cx_usage_counters: 412905 0
dev.cpu.0.cx_usage: 100.00% 0.00% last 290us
dev.cpu.0.cx_lowest: C1
dev.cpu.0.cx_supported: C1/1/1 C2/3/104
dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140
dev.cpu.0.freq: 800
dev.cpu.0.%parent: acpi0
dev.cpu.0.%pnpinfo: _HID=none _UID=0
dev.cpu.0.%location: handle=\_PR_.CPU0
dev.cpu.0.%driver: cpu
dev.cpu.0.%desc: ACPI CPU

If you load the coretemp(4) kernel module with kldload(8) command you will get additional temperature information.

Below is same sysctl(8) dev.cpu.0 MIB with coretemp(4) kernel module loaded.

% sysctl dev.cpu.0
dev.cpu.0.temperature: 49.0C
dev.cpu.0.coretemp.throttle_log: 0
dev.cpu.0.coretemp.tjmax: 100.0C
dev.cpu.0.coretemp.resolution: 1
dev.cpu.0.coretemp.delta: 51
dev.cpu.0.cx_method: C1/hlt C2/io
dev.cpu.0.cx_usage_counters: 16549 0
dev.cpu.0.cx_usage: 100.00% 0.00% last 1489us
dev.cpu.0.cx_lowest: C1
dev.cpu.0.cx_supported: C1/1/1 C2/3/104
dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140
dev.cpu.0.freq: 800
dev.cpu.0.%parent: acpi0
dev.cpu.0.%pnpinfo: _HID=none _UID=0
dev.cpu.0.%location: handle=\_PR_.CPU0
dev.cpu.0.%driver: cpu
dev.cpu.0.%desc: ACPI CPU

Let me describe some most useful ones.

CPU core temperature.
dev.cpu.0.temperature: 49.0C

CPU supported C-states (C1 and C2 for this CPU).
dev.cpu.0.cx_supported: C1/1/1 C2/3/104

CPU statistics for C-states usage (only C1 state been used).
dev.cpu.0.cx_usage_counters: 16549 0
dev.cpu.0.cx_usage: 100.00% 0.00% last 1489us

CPU maximum (most deep) C state enabled.
dev.cpu.0.cx_lowest: C1

CPU supported frequency levels with power usage after the ‘/‘ character. The 2500/35000 can be read as 2.5 GHz frequency with 35 W power usage and 2501 is the Turbo Mode. The lowest is 800 MHz with about 9 W usage.
dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140

CPU current frequency (will vary when You use powerd(8) or powerdxx(8) daemon).
dev.cpu.0.freq: 800

The hw.acpi.thermal.tz0.temperature MIB will also show you current thermal zone temperature.

% sysctl hw.acpi.thermal.tz0.temperature
hw.acpi.thermal.tz0.temperature: 49.1C

To check how many cores you have use these commands.

% grep FreeBSD/SMP /var/run/dmesg.boot
FreeBSD/SMP: Multiprocessor System Detected: 2 CPUs
FreeBSD/SMP: 1 package(s) x 2 core(s)

% sysctl kern.smp.cpus
kern.smp.cpus: 2

If my description does not feel useful then you should also check the -d flag for sysctl(8) command as shown below.

% sysctl -d dev.cpu.0.freq
dev.cpu.0.freq: Current CPU frequency

lscpu(1)

There is also third party tool called lscpu(8) that will describe your CPU features and model. You will have to add it from packages.

# pkg install lscpu

To make lscpu(8) work the cpuctl(4) kernel module is needed.

Here is how it looks for my dual core CPU.

# kldload cpuctl
# lscpu
Architecture:            amd64
Byte Order:              Little Endian
Total CPU(s):            2
Thread(s) per core:      2
Core(s) per socket:      2
Socket(s):               0
Vendor:                  GenuineIntel
CPU family:              6
Model:                   42
Model name:              Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz
Stepping:                7
L1d cache:               32K
L1i cache:               32K
L2 cache:                256K
L3 cache:                3M
Flags:                   fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 cflsh ds acpi mmx fxsr sse sse2 ss htt tm pbe sse3 pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline aes xsave osxsave avx syscall nx rdtscp lm lahf_lm

dmesg(8)

Also dmesg(8) command (or /var/run/dmesg.boot file after longer uptime) covers your CPU model and features information.

% grep CPU /var/run/dmesg.boot
CPU: Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz (2491.97-MHz K8-class CPU)
FreeBSD/SMP: Multiprocessor System Detected: 2 CPUs
cpu0:  on acpi0
coretemp0:  on cpu0

CPU Frequency Scaling

For CPU scaling feature you may use the powerd(8) daemon available in the FreeBSD base system or powerdxx(8) from the FreeBSD Ports or packages. The powerdxx(8) daemon aims to better scale multicore systems and not turning all cores to high state when there is moderate load on the system but some people may prefer that approach to have full power available when they do anything and to save power when they do nothing. Thus powerd(8) is not better then powerdxx(8) or vice versa. They are just different so that gives you more options for your needs.

No matter which one you will choose it has to be configured in the /etc/rc.conf file.

powerd(8)

Here are the options for powerd(8) daemon.

powerd_enable=YES
powerd_flags="-n adaptive -a hiadaptive -b adaptive -m 800 -M 1600"

The -n option of for the unknown state – if for some reason the powerd(8) will not be able to determine if you are running on the AC power or battery. The -a is for AC power and -b for running on the battery. The adaptive setting is less ‘aggressive’ so its more battery time friendly. The hiadaptive is more aggressive this its preferred when you are running on AC power. The -m option sets minimum CPU frequency to be used and -M the maximum. Both in MHz units. Check powerd(8) man page for more details.

powerdxx(8)

First you will need to install it.

# pkg install powerdxx

Then its options are identical as those of powerd(8) daemon.

powerdxx_enable=YES
powerdxx_flags="-n adaptive -a hiadaptive -b adaptive -m 800 -M 1600"

Check the powerdxx(8) section above for the flags/parameters description.

Decade ago CPU frequency scaling on FreeBSD was not that ‘easy’ as it is now, you may check my old HOWTO: FreeBSD CPU Scaling and Power Saving in that topic from 2008.

C-States

The C-states can be configured in the /etc/rc.conf file with these options.

  • performance_cx_lowest
  • economy_cx_lowest

The economy_cx_lowest parameter is for running on battery and performance_cx_lowest parameter is for running on AC power. Both are set using the /etc/rc.d/power_profile script used by rc(8) subsystem. It sets the hw.acpi.cpu.cx_lowest parameter which sets/controls all dev.cpu.*.cx_lowest values. You can also track the changes in the /var/log/messages file when you attach/detach the AC power.

% tail -f /var/log/messages
Nov 28 13:14:42 t420s power_profile[48231]: changed to 'economy'
Nov 28 13:14:46 t420s power_profile[56835]: changed to 'performance'

Usually I jest use these values.

performance_cx_lowest=C1
economy_cx_lowest=Cmax

These settings above are generally sufficient for most systems. To check which C-states your CPU supports get the value of dev.cpu.0.cx_supported MIB.

% sysctl dev.cpu.0.cx_supported
dev.cpu.0.cx_supported: C1/1/1 C2/3/104

My CPU supports only C1 and C2 but yours may support more. I remember once when using some old Core 2 Duo laptop that the C2 state had quite ‘noticeable’ delay when getting back from C1 (running) state to C2 (sleep) state so following setting is needed. You do not use the performance_cx_lowest and economy_cx_lowest parameters. You set the first core to C1 and all other cores to C2. This way even on battery you have fully responsive system and all other cores may sleep and save energy.

For example if You would have 4 cores and your maximum (deepest) supported C-state would be C3, then you would put these into the /etc/sysctl.conf file.

% grep cx_lowest /etc/sysctl.conf
dev.cpu.0.cx_lowest=C1
dev.cpu.1.cx_lowest=C3
dev.cpu.2.cx_lowest=C3
dev.cpu.3.cx_lowest=C3

CPU Turbo Mode

There are two ways to enable Turbo mode. One way is to set powerd(8) or powerdxx(8) daemon with maximum frequency set above nominal CPU speed. For example if you have CPU described as dual-core 2.3 GHz then set the maximum speed with -M flag to 4000 for example (which would mean 4GHz). If you do not use CPU frequency scaling daemon then you will use dev.cpu.0.freq parameter with highest (first) value from the dev.cpu.0.freq_levels MIB.

Supported CPU frequency levels on my system.

% sysctl dev.cpu.0.freq_levels 
dev.cpu.0.freq_levels: 2501/35000 2500/35000 2200/29755 2000/26426 1800/23233 1600/20164 1400/17226 1200/14408 1000/11713 800/9140

The highest value (left) is 2501/35000 so I need to set dev.cpu.0.freq parameter with this value to use Turbo Mode. You need to only use the ‘frequency’ value part because if you paste it with power requirements description it will fail.

# sysctl dev.cpu.0.freq=2501/35000
sysctl: invalid integer '2501/35000'

This is how it should be used.

# sysctl dev.cpu.0.freq=2501
dev.cpu.0.freq: 800 -> 2501

USB Devices

To list attached USB devices use the usbconfig(8) tool.

% usbconfig
ugen1.1:  at usbus1, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=SAVE (0mA)
ugen2.1:  at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen0.1:  at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen2.2:  at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen0.2:  at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen0.3:  at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (100mA)
ugen2.3:  at usbus2, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)

You will see that pwr parameter (short for power) will show you current power setting which can be:

  • ON
  • OFF
  • SAVE

To set new USB power option for the ugen1.1 device also use the usbconfig(8) tool with the power_save parameter in the following way.

# usbconfig -u 1 -a 1 power_save

The USB power management does not have dedicated config file on FreeBSD so we will put them into universal /etc/rc.local file which is being run at the end of the start-up process managed by the rc(8) subsystem. Here is the added content with exception for the ‘Lenovo USB Receiver‘ which is my wireless mouse.

% grep -A 10 POWER /etc/rc.local
# POWER SAVE USB DEVICES
usbconfig \
  | grep -v 'Lenovo USB Receiver' \
  | awk '{print $1}' \
  | sed 's|ugen||'g \
  | tr -d : \
  | awk -F '.' '{print $1 " " $2 }' \
  | while read U A
    do
      usbconfig -u ${U} -a ${A} power_save 2> /dev/null
    done

It’s good idea to NOT save power for mouse or tracked devices because you will probably find it annoying to have to wait about a second each time you would like to use it. I use a for loop to set power saving for all USB devices except wireless USB mouse (identified as ‘Lenovo USB Receiver‘ device).

SATA/AHCI Power Management

FreeBSD offers AHCI channels power management via acpich(4) driver. These power management settings cen be set at boot using the hint.ahcich.*.pm_level parameter in the /boot/loader.conf file. I use configuration up to 8 channels while I only have three.

% grep ahcich /var/run/dmesg.boot
ahcich0:  at channel 0 on ahci0
ahcich1:  at channel 1 on ahci0
ahcich4:  at channel 4 on ahci0
ada0 at ahcich0 bus 0 scbus0 target 0 lun 0

That is because settings for non-existent devices are harmless and will not display any error messages but you will not have to use different settings for various systems which saves time. This is the hint.ahcich.*.pm_level description from the ahci(4) man page.

  hint.ahcich.X.pm_level

    controls SATA interface Power Management for the specified channel,
    allowing some power to be saved at the cost of additional command latency.

    Some controllers, such as ICH8, do not implement modes 2 and 3 with NCQ
    used. Because of artificial entering latency, performance degradation in
    modes 4 and 5 is much smaller then in modes 2 and 3.

Possible power management options are:

  • 0 – interface Power Management is disabled (default)
  • 1 – device is allowed to initiate PM state change, host is passive
  • 2 – host initiates PARTIAL PM state transition every time port becomes idle
  • 3 – host initiates SLUMBER PM state transition every time port becomes idle
  • 4 – driver initiates PARTIAL PM state transition 1ms after port becomes idle
  • 5 – driver initiates SLUMBER PM state transition 125ms after port becomes idle

Here are my setting from the /boot/loader.conf file.

# AHCI POWER MANAGEMENT FOR EVERY USED CHANNEL (ahcich 0-7)
  hint.ahcich.0.pm_level=5
  hint.ahcich.1.pm_level=5
  hint.ahcich.2.pm_level=5
  hint.ahcich.3.pm_level=5
  hint.ahcich.4.pm_level=5
  hint.ahcich.5.pm_level=5
  hint.ahcich.6.pm_level=5
  hint.ahcich.7.pm_level=5

Devices without Driver

FreeBSD has power saving option to not power devices that does not have attached driver. Its called hw.pci.do_power_nodriver and you can set it in the /boot/loader.conf file. Here is its description from then pci(4) man page.

  hw.pci.do_power_nodriver (Defaults to 0)

    Place devices into a low power state (D3) when
    a suitable device driver is not found.

It can be set to one of the following values:

  • 0 – All devices are left fully powered (defaults).
  • 1 – Like ‘2‘ except that storage controllers are also not powered down.
  • 2 – Powers down most devices (display/memory/peripherals not powered down).
  • 3 – Powers down all PCI devices without a device driver.

Here is my setting from the /boot/loader.conf file.

# POWER OFF DEVICES WITHOUT ATTACHED DRIVER
  hw.pci.do_power_nodriver=3

The pciconf(8) utility will show you what devices are in your system and which driver is attached to it. If no driver is attached you will see none*@ for such devices, as none0@ below. You can also check man page for most drivers like em(4) man page for em0 device or xhci(4) page for xhci0 device.

% pciconf -l
hostb0@pci0:0:0:0:      class=0x060000 card=0x21d217aa chip=0x01048086 rev=0x09 hdr=0x00
vgapci0@pci0:0:2:0:     class=0x030000 card=0x21d217aa chip=0x01268086 rev=0x09 hdr=0x00
none0@pci0:0:22:0:      class=0x078000 card=0x21d217aa chip=0x1c3a8086 rev=0x04 hdr=0x00
em0@pci0:0:25:0:        class=0x020000 card=0x21ce17aa chip=0x15028086 rev=0x04 hdr=0x00
ehci0@pci0:0:26:0:      class=0x0c0320 card=0x21d217aa chip=0x1c2d8086 rev=0x04 hdr=0x00
hdac0@pci0:0:27:0:      class=0x040300 card=0x21d217aa chip=0x1c208086 rev=0x04 hdr=0x00
pcib1@pci0:0:28:0:      class=0x060400 card=0x21d217aa chip=0x1c108086 rev=0xb4 hdr=0x01
pcib2@pci0:0:28:1:      class=0x060400 card=0x21d217aa chip=0x1c128086 rev=0xb4 hdr=0x01
pcib3@pci0:0:28:3:      class=0x060400 card=0x21d217aa chip=0x1c168086 rev=0xb4 hdr=0x01
pcib4@pci0:0:28:4:      class=0x060400 card=0x21d217aa chip=0x1c188086 rev=0xb4 hdr=0x01
ehci1@pci0:0:29:0:      class=0x0c0320 card=0x21d217aa chip=0x1c268086 rev=0x04 hdr=0x00
isab0@pci0:0:31:0:      class=0x060100 card=0x21d217aa chip=0x1c4f8086 rev=0x04 hdr=0x00
ahci0@pci0:0:31:2:      class=0x010601 card=0x21d217aa chip=0x1c038086 rev=0x04 hdr=0x00
ichsmb0@pci0:0:31:3:    class=0x0c0500 card=0x21d217aa chip=0x1c228086 rev=0x04 hdr=0x00
iwn0@pci0:3:0:0:        class=0x028000 card=0x11118086 chip=0x42388086 rev=0x3e hdr=0x00
sdhci_pci0@pci0:5:0:0:  class=0x088000 card=0x21d217aa chip=0xe8221180 rev=0x07 hdr=0x00
xhci0@pci0:13:0:0:      class=0x0c0330 card=0x01941033 chip=0x01941033 rev=0x04 hdr=0x00

You can also use -v flag to get more detailed information.

% pciconf -l -v
(...)
xhci0@pci0:13:0:0:      class=0x0c0330 card=0x01941033 chip=0x01941033 rev=0x04 hdr=0x00
    vendor     = 'NEC Corporation'
    device     = 'uPD720200 USB 3.0 Host Controller'
    class      = serial bus
    subclass   = USB

Nvidia Optimus

If for some reason your BIOS/UEFI firmware does not allow you to disable Nvidia discrete graphics card you may use this script to disable it so it will not drain power from your system. It requires the acpi_call(4) kernel module which is provided by the acpi_call package.

# mkdir /root/bin
# cd /root/bin
# fetch https://people.freebsd.org/~xmj/turn_off_gpu.sh
# pkg install acpi_call
# kldload acpi_call
# chmod +x /root/bin/turn_off_gpu.sh
# /root/bin/turn_off_gpu.sh

You may add it to the /etc/rc.local file after the USB power saving options with this entry.

# DISABLE NVIDIA CARD
  /root/bin/turn_off_gpu.sh

It successd it will store the working ACPI call in the /root/.gpu_method file and execute it each next time.

Suspend and Resume

The biggest enemies of supend/resume mechanism are bugs in your BIOS/UEFI firmware for your hardware. Sometimes disabling Bluetooth helps – that is the option for ThinkPad T420s for example. To check which suspend modes are supported on your system check the hw.acpi.supported_sleep_state MIB from sysctl(8) subsystem.

% sysctl hw.acpi.supported_sleep_state
hw.acpi.supported_sleep_state: S3 S4 S5

To enter ACPI S3 sleep state (suspend) you can use acpiconf(8) tool or zzz(8) tool.

# zzz

… or with acpiconf(8) tool.

# acpiconf -s 3

Its exactly the same as stated in the zzz(8) man page.

You can also set sysctl(8) value that everytime you close your laptop lid your system will go to sleep. To achieve that put hw.acpi.lid_switch_state=S3 into the /etc/sysctl.conf file. No matter if you put you hardware to sleep by command or by closing the lid your laptop will resume after opening the lid. Of course if you haven’t closed the lid after the zzz(8) command you will either have to close and open the lid or push the power button to resume. Of course you may also suspend/resume desktops or even your backup server if it has its purpose. It’s not limited to laptops only.

There are also dedicated kernel modules for various vendor ACPI subsystems. Here they are:

  • /boot/kernel/acpi_asus_wmi.ko
  • /boot/kernel/acpi_asus.ko
  • /boot/kernel/acpi_dock.ko
  • /boot/kernel/acpi_fujitsu.ko
  • /boot/kernel/acpi_hp.ko
  • /boot/kernel/acpi_ibm.ko
  • /boot/kernel/acpi_panasonic.ko
  • /boot/kernel/acpi_sony.ko
  • /boot/kernel/acpi_toshiba.ko
  • /boot/kernel/acpi_video.ko
  • /boot/kernel/acpi_wmi.ko

For example if you have IBM/Lenovo ThinkPad the you will use the acpi_ibm.ko kernel module.

# kldload acpi_ibm

After loading each module you will get new sysctl(8) values for your use. For example related to fan speed, keyboard backlit or screen brightness. Below is new dev.acpi_ibm section in sysctl(8) after loading the acpi_ibm(4) kernel module.

% sysctl dev.acpi_ibm
dev.acpi_ibm.0.handlerevents: NONE
dev.acpi_ibm.0.mic_led: 0
dev.acpi_ibm.0.fan: 0
dev.acpi_ibm.0.fan_level: 0
dev.acpi_ibm.0.fan_speed: 0
dev.acpi_ibm.0.wlan: 1
dev.acpi_ibm.0.bluetooth: 0
dev.acpi_ibm.0.thinklight: 0
dev.acpi_ibm.0.mute: 0
dev.acpi_ibm.0.volume: 0
dev.acpi_ibm.0.lcd_brightness: 0
dev.acpi_ibm.0.hotkey: 1425
dev.acpi_ibm.0.eventmask: 134217727
dev.acpi_ibm.0.events: 1
dev.acpi_ibm.0.availmask: 134217727
dev.acpi_ibm.0.initialmask: 2060
dev.acpi_ibm.0.%parent: acpi0
dev.acpi_ibm.0.%pnpinfo: _HID=LEN0068 _UID=0
dev.acpi_ibm.0.%location: handle=\_SB_.PCI0.LPC_.EC__.HKEY
dev.acpi_ibm.0.%driver: acpi_ibm
dev.acpi_ibm.0.%desc: IBM ThinkPad ACPI Extras
dev.acpi_ibm.%parent: 

Here are descriptions of more interesting ones.

This one will turn the LED light on the Microphone mute button.
dev.acpi_ibm.0.mic_led

Select if you want to manage CPU fan (0) or leave it to the manufacturer defaults (1).
dev.acpi_ibm.0.fan

If CPU fan is enabled, set its speed.
dev.acpi_ibm.0.fan_level

This one will tell you how fast the CPU fan is spinning (in RPMs).
dev.acpi_ibm.0.fan_speed

Enable/disable WiFi (if its enabled in BIOS).
dev.acpi_ibm.0.wlan

Enable/disable Bluetooth (if its enabled in BIOS).
dev.acpi_ibm.0.bluetooth

Enable/disable ThinkLight.
dev.acpi_ibm.0.thinklight

Mute/unmute speakers.
dev.acpi_ibm.0.mute

Speakers volume.
dev.acpi_ibm.0.volume

Screen brightness.
dev.acpi_ibm.0.lcd_brightness

For most of the cases its not needed to use them as you will probably just use the vendor defined keyboard shortcuts (probably with Fn key) or vendor specific dedicated buttons. Sometimes you want to create/use your own setup or need custom keyboard shortcuts, or you want to control the fan speed depending on the CPU temperature other way then your vendor predefined it. This is when these dedicated ACPI kernel modules are most useful.

For example I recently thought that my CPU fan seems to be little louder then it should be so I created custom cron(8) based acpi-thinkpad-fan.sh script to use lower fan speeds or even lower quieter speeds when CPU temperature is low enough.

I will post it here. Maybe you will find it useful for your purposes. To describe it shortly it disables the fan when CPU temperature is below 50 (C) degrees, it sets it to level ‘1’ if its between 50 (C) and 60 (C) degrees and sets it to level ‘3’ when temperature reaches more then 60 (C) degrees.

#! /bin/sh

if ! kldstat | grep -q acpi_ibm.ko
then
  doas kldload acpi_ibm
fi

doas sysctl dev.acpi_ibm.0.fan=0 1> /dev/null 

TEMP=$( sysctl -n hw.acpi.thermal.tz0.temperature | awk -F'.' '{print $1}' )

if [ ${TEMP} -lt 50 ]
then
  doas sysctl dev.acpi_ibm.0.fan_level=0 1> /dev/null
  exit 0
fi

if [ ${TEMP} -lt 60 ]
then
  doas sysctl dev.acpi_ibm.0.fan_level=1 1> /dev/null
  exit 0
fi

if [ ${TEMP} -ge 60 ]
then
  doas sysctl dev.acpi_ibm.0.fan_level=3 1> /dev/null
  exit 0
fi

… and here is its crontab(5) entry:

% crontab -l
# ACPI/IBM/FAN
* * * * * ~/scripts/acpi-thinkpad-fan.sh

Network Interfaces

There is also ifconfig(8) option to save power if a driver supports such feature, its called powersave and its used like that.

# ifconfig wlan0 powersave

I use it in my network.sh network management script described broadly in the FreeBSD Network Management with network.sh article.

Vendor Tools

There are also vendor tools available on FreeBSD like powermon(8) for example. Remember that it requires cpuctl(4) kernel module to work.

# pkg install powermon
# kldload cpuctl
# powermon
                  Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz
                      (Arch: Sandy Bridge, Limit: 44W)



   5.11W [=======>                                                           ]



 Package:           Uncore:             x86 Cores:          GPU:
 Current: 5.11W     Current: 3.17W      Current: 1.73W      Current: 0.21W
 Total: 98.33J      Total: 60.86J       Total: 33.49J       Total: 3.98J

DTrace

The dynamic tracing framework that like ZFS found its way from Solaris/Illumos to FreeBSD may be also useful weapon in the battle for more time on your battery.

First add the dtrace-toolkit package.

# pkg install dtrace-toolkit

Your system stops saving energy or wakes CPU up because something needs to be run/done. To check what is run on your system you mostly run ps(1) or top(1) utilities but that will not show you what exactly is being started or how often something is being run. This is where DTrace comes with help.

We will use the /usr/share/dtrace/toolkit/execsnoop script from the dtrace-toolkit package. It will print EVERY COMMAND that is being run with all its arguments.It will remain silent when no commands are run, be advised.

Here is example output for my dzen2 toolbar update.

# /usr/local/share/dtrace-toolkit/execsnoop 
  UID    PID   PPID ARGS
 1000  97748  97509 /usr/local/bin/zsh -c ~/scripts/dzen2-update.sh > ~/.dzen2-fifo
 1000  97748      1 /bin/sh /home/vermaden/scripts/dzen2-update.sh
 1000  99157  97748 sysctl -n kern.smp.cpus
 1000    311  97748 ps ax -o %cpu,rss,command -c
 1000   3118   1521 awk -v SMP=200 /\ idle$/ {printf("%.1f%%",SMP-$1)}
 1000   4462  97748 date +%Y/%m/%d/%a/%H:%M
 1000   4801  97748 sysctl -n dev.cpu.0.freq
 1000   6009  97748 sysctl -n hw.acpi.thermal.tz0.temperature
 1000   6728  97748 sysctl -n vm.stats.vm.v_inactive_count
 1000   7043  97748 sysctl -n vm.stats.vm.v_free_count
 1000   7482  97748 sysctl -n vm.stats.vm.v_cache_count
 1000  10363   8568 bc -l
 1000  10863  10363 dc -x
 1000  13143   7773 grep --color -q ^\.
 1000  13798  97748 /bin/sh /home/vermaden/scripts/__conky_if_ip.sh
 1000  15089  14235 ifconfig -u
 1000  16439  14235 grep -v 127.0.0.1
 1000  17738  14235 grep -c inet 
 1000  19069  18612 ifconfig -l -u
 1000  19927  18612 sed s/lo0//g
 1000  20772  13798 ifconfig wlan0
 1000  23388  21410 grep ssid
 1000  24588  13798 grep -q "
 1000  25965  25282 awk /ssid/ {print $2}
 1000  27917  27217 awk /inet / {print $2}
 1000  29941  97748 /bin/sh /home/vermaden/scripts/__conky_if_gw.sh
 1000  32808  31412 route -n -4 -v get default
 1000  34012  31412 awk END{print $2}
 1000  34895  97748 /bin/sh /home/vermaden/scripts/__conky_if_dns.sh
 1000  36118  34895 awk /^nameserver/ {print $2; exit} /etc/resolv.conf
 1000  37628  97748 /bin/sh /home/vermaden/scripts/__conky_if_ping.sh dzen2
 1000  38829  37628 ping -c 1 -s 0 -t 1 -q 9.9.9.9
 1000  42079  41566 mixer -s vol
 1000  42177  41566 awk -F : {printf("%s",$2)}
 1000  44434  43254 zfs list -H -d 0 -o name,avail
 1000  45866  43254 awk {printf("%s/%s ",$1,$2)}
 1000  47004  97748 /bin/sh /home/vermaden/scripts/__conky_battery_separate.sh dzen2
 1000  48282  47004 sysctl -n hw.acpi.battery.units
 1000  49494  47004 sysctl -n hw.acpi.battery.life
 1000  49948  47004 sysctl -n hw.acpi.acline
 1000  52073  51441 acpiconf -i 0
 1000  53055  51441 awk /^State:/ {print $2}
 1000  53981  53186 acpiconf -i 0
 1000  55354  53186 awk /^Remaining capacity:/ {print $3}
 1000  55968  55631 acpiconf -i 1
 1000  57187  55631 awk /^State:/ {print $2}
 1000  58405  57471 acpiconf -i 1
 1000  59201  57471 awk /^Remaining capacity:/ {print $3}
 1000  60961  59252 bsdgrep -v -E (COMMAND|idle)$
 1000  63534  59252 head -3
 1000  62194  59252 sort -r -n
 1000  64629  59252 awk {printf("%s/%d%%/%.1fGB ",$3,$1,$2/1024/1024)}
 1000  64634  93198 tail -1 /home/vermaden/.dzen2-fifo

Lots of processes just to update the information on the top of the screen. That is why I refresh dzen2 information only every 5 minutes and if I want exact information and system status for current moment I just ‘click’ on then dzen2 bar to run all these commands and refresh itself.

This way using DTrace you will know if something unwanted does not steal you precious battery time. You may find such dzen2 config in my FreeBSD Desktop – Part 13 – Configuration – Dzen2 article.

Other

ZFS

By default ZFS will commit transaction group every 5 seconds and that is good default setting for the vfs.zfs.txg.timeout parameter. You may want to increase it a little if needed. To 10 for example. I say about that parameter mostly because lots of guides advice to set it to 1 for various performance reasons but keep in mind that setting it to 1 will prevent your disk (and CPU) from going to sleep thus draining more battery life.

If you want to mess with vfs.zfs.txg.timeout value set it in the /boot/loader.conf file.

Applications

To get more time on battery used applications are also crucial. For example Thunar uses less CPU time then Caja or Nautilus. The Geany text editor uses less CPU resources and memory then Scite or Gedit editors, even GVim takes more resouces. Not to mention that custom Openbox/Fluxbox/${YOUR_FAVORITE_WM} window manager based setup will consume a lot less CPU time then entire Gnome or Mate environment.

Hardware

It’s sometimes possible to literally buy more battery time. For example when you want to buy new SSD for you laptop then pick not the fastest one but the most power efficient one. You will probably not feel the performance difference anyway but you will appreciate more battery time.

Most RAM modules come with 1.5V current voltage but there is chance that your laptop may support low power DDR modules with 1.35V current thus increasing your battery time. Also keep in mind that each RAM stick uses about 0.5-1.0W of power so using single 8 GB RAM stick will provide you more battery time the the same 8 GB of memory using two 4 GB RAM modules. This also have performance drawback because with single RAM module you will not be able to use dual channel technology so you will limit you RAM speed. Some laptops have even 4 RAM slots (like ThinkPad W520 for example) so without losing anything you should use two 8 GB RAM sticks instead of four 4 GB RAM sticks for longer battery life.

It is sometimes possible to swap your DVD drive to internal secondary battery. Examples of such laptops are Dell Latitude D630, ThinkPad T420s or ThinkPad T500/W500. Sometimes vendors offer entire slice battery that will stick to the bottom of your laptop like slice battery for ThinkPad X220 or T420/T520/W520 laptops or for the 1st generation of ThinkPad X1 laptop.

Hope that this information will help you squeeze some battery time (or at least save some power) on FreeBSD ๐Ÿ™‚

UPDATE 1 – Graphics Card Power Saving

If You have the graphics/drm-kmod package installed you probably use the latest i915kms.ko kernel module.

To set maximum power management for integrated Intel graphics cards put these into the /boot/loader.conf file.

# INTEL DRM WITH graphics/drm-kmod PACKAGE (NEW)
# SKIP UNNECESSARY MODE SETS AT BOOT TIME 
  compat.linuxkpi.fastboot=1
# USE SEMAPHORES FOR INTER RING SYNC
  compat.linuxkpi.semaphores=1
# ENABLE POWER SAVING RENDER C-STATE 6
  compat.linuxkpi.enable_rc6=7
# ENABLE POWER SAVING DISPLAY C-STATES
  compat.linuxkpi.enable_dc=2
# ENABLE FRAME BUFFER COMPRESSION FOR POWER SAVINGS
  compat.linuxkpi.enable_fbc=1

In the past these settings below were used but they are not present anymore.

# INTEL DRM WITH graphics/drm-kmod PACKAGE (OLD)
  drm.i915.enable_rc6=7
  drm.i915.semaphores=1
  drm.i915.intel_iommu_enabled=1

UPDATE 2 – AMD CPU Temperatures

While the coretemp(4) kernel module is used for Intel CPUs the amdtemp(4) kernel module will provide additional temperature information for AMD CPUs.

UPDATE 3 – Suspend/Resume Tips

The biggest enemies of supend/resume subsystem are bugs in the BIOS/UEFI firmware. Sometimes disabling the Bluetooth helps – that is the option for the Lenovo ThinkPad T420s for example. On the Lenovo ThinkPad X240 it is disabling the TPM (Trusted Platform Module).

EOF

ย 

FreeBSD Desktop – Part 2.1 – Install FreeBSD 12

This article is an update/rewrite to the already published FreeBSD Desktop – Part 2 – Install. With the upcoming introduction of the FreeBSD 12.0-RELESE version new possibilities arise when it comes to installation. I already talked/showed that method in my ZFS Boot Environments Reloaded at NLUUG presentation but to make it more available and obvious part of my FreeBSD Desktop series I write about it again in dedicated article entry.

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.

Now (in FreeBSD 12.x) it is possible to install FreeBSD on GELI encrypted root on ZFS pool without any additional partitions or filesystems. No longer separate UFS or ZFS boot pool /boot filesystem is needed. And what is even more appealing such setup is supported both on UEFI and BIOS (also refereed as Legacy or CSM) systems. Such setup is also compatible with both new bectl(8) utility and the old proven beadm(8) tool. It is also nice that to make such setup you only need to choose the Auto ZFS option from the bsdinstall(8) so you will not have to do it by hand. I advice using GPT (BIOS+UEFI) as it will support both system types so when you are running BIOS system now and will move the disk to other system that boots with UEFI it will also just work out of the box.

The FreeBSD 12.0 is currently at the RC1 stage so we will use that one for below examples of such setup. The 12.0-RELEASE is expected to arise before Christmas if no significant problems or bugs will be found on the road to RC2 and RC3 editions.

For the record here is the FreeBSD 12.0-RC1 Availability information page and aggregated FreeBSD 12.0-RELEASE Release Notes for the upcoming new major FreeBSD version, but it is not yet complete/ready.

I will only show one install process that will work for both UEFI and BIOS systems – the crucial option here is GPT (BIOS+UEFI) to select (which is also the default one). The other option that You need to select is Yes for the Encryption part and also select the SWAP size. You may as well do not use swap and enter ‘0‘ here which means that SWAP partition will not be created. You may as well create ZFS ZVOL partition for SWAP on ZFS pool later or just create a file like /SWAP and enable it as SWAP. No matter which SWAP option you will choose if your system swaps then you are too low on memory and neither of these methods are better or worse then.

freebsd-install-01.png

freebsd-install-02.png

freebsd-install-03.png

One last thing about the default FreeBSD (no matter if 11.x or 12.x) ZFS dataset/filesystem layout. I showed it on my ZFS Boot Environments/ZFS Boot Environments Reloaded presentations but without any text comment as I talked it live.

By default both /var and /usr filesystems are part of the Boot Environment. They are protected and snapshoted during the beadm create newbe process (or by bectl(8) also). Its appears that /var and /usr are separate processes when you type zfs list commend as shown on the slide below.

zroot-layout-01.png

… but when you check the canmount parameter for all ZFS datasets, then it become obvious that /usr and /var are ’empty’ datasets (not mounted).

zroot-layout-02.png

… and also confirmation from theย df(1) tool.

zroot-layout-03.png

I asked FreeBSD Developers what is the reason for such construct and its for the mountpoint inheritance purposes. For example when zroot/usr has mountpoint set to /usr then when you create zroot/usr/local dataset, then it will automatically get the /usr/local for the mountpoint parameter by inheritance. At the first sight it may be misleading (I also got caught) but it makes sense when you think about it.

The only filesystems that are NOT included for the Boot Environment protection are these:

  • /usr/home
  • /usr/ports
  • /usr/src
  • /var/audit
  • /var/crash
  • /var/log
  • /var/mail
  • /var/tmp

While in most cases it is not needed to protect these in the Boot Environment protection if you want to also protect these type these two comments to move all the /usr/* and /var/* datasets/filesystems into the Boot Environment pool/ROOT/dataset. It will work on a running system without need for reboot, just make sure you use -u flag.

# zfs rename -u zroot/usr zroot/ROOT/default/usr
# zfs rename -u zroot/var zroot/ROOT/default/var

Now grab that FreeBSD ISO and install it the best possible way up to date ๐Ÿ™‚

You will probably want to get amd64 version which is suitable for both 64-bit AMD and Intel systems.

EOF

ย