Wednesday, January 31, 2024

What's New in util-linux v2.40?

The util-linux v2.40-rc1 was released just a few days ago. Let's explore the new features introduced in this release.

We have a new small shared library in the project, liblastlog, to implement a replacement for the lastlog file and lastlog-related utils. The main goal is to fix the Y2038 issue and use a more advanced file format to store the log. The original lastlog implementation uses 32-bit time values and a file format where an entry location is based on UID, so on systems with huge UIDs, it creates a huge lastlog file (fortunately, a file with holes). The new library uses the SQLite3 library to store data. It makes things easy to extend, efficient, and fast. There is also the pam_lastlog2 module as a replacement for the original pam_lastlog. Thanks to Suse, namely Stefan Schubert and Thorsten Kukuk.

The library libuuid has also been improved to support 64-bit time.

The next big change is within libsmartcols. The library now supports filtering expressions and counters. The idea and first implementation come from Masatake Yamato; it was originally designed for lsfd, but we found it very useful to make it generic and usable for arbitrary applications, so now all the functionality is exported by the public library API.

Applications can utilize the filter before gathering all data for output, reducing resource usage and improving performance. This is important for tools like lsblk where gathering data can be time-consuming in some cases (for example, read details from partition tables, filesystems superblocks, or fetch data from udevd). The expressions use lazy evaluation, so only necessary data comes to the game.

The filter expression uses C-like format with human-readable aliases ("&&" alias "and"), for example:

# lsfd -Q 'TIMERFD.remaining < 0.5 && TIMERFD.remaining > 0.0'

It supports basic operators, including regular expressions for strings:

# lsfd -Q 'COMMAND =~ ".*qemu.*" && FD >= 0'

The parser is generated by flex and bison.

The expression can contain data from fields (columns) which will not be printed.

An extension to the expression are counters. The counter uses an aggregation function to count lines or summarize numbers (supported functions are count, min, max, and sum).

The counter is possible to restrict by expression, for example:

# lsfd --summary=only \ -C 'netlink sockets':'(NAME =~ "NETLINK:.*")' \ -C 'unix sockets':'(NAME =~ "UNIX:.*")' VALUE COUNTER 57 netlink sockets 1552 unix sockets

In future releases, I'd like to add the possibility to colorize data in libsmartcols tables based on expressions and cell types. For now, a very basic possibility is available in lsblk by using the "--highlight <expr>" command line option.

You probably know that in Linux we have more system clocks, but do you know any elegant way to see all the clocks? ;-) Ladies and gentlemen, welcome lsclocks, a new util-linux command.

# lsclocks ID NAME TYPE TIME RESOL ISO_TIME 0 realtime sys 1706702926.075958226 1ns 2024-01-31T12:08:46.075958226+00:00 1 monotonic sys 332686.333569506 1ns 1970-01-04T20:24:46.333569506+00:00 4 monotonic-raw sys 332685.732374681 1ns 1970-01-04T20:24:45.732374681+00:00 5 realtime-coarse sys 1706702926.074719228 1ms 2024-01-31T12:08:46.074719228+00:00 6 monotonic-coarse sys 332686.332298188 1ms 1970-01-04T20:24:46.332298188+00:00 7 boottime sys 435547.110588884 1ns 1970-01-06T00:59:07.110588884+00:00 8 realtime-alarm sys 1706702926.075996923 1ns 2024-01-31T12:08:46.075996923+00:00 9 boottime-alarm sys 435547.110592620 1ns 1970-01-06T00:59:07.110592620+00:00 11 tai sys 1706702963.076000869 1ns 2024-01-31T12:09:23.076000869+00:00

It can also read time from RTC, time offsets from namespaces, and process CPU time. Like all ls-like tools in util-linux, it supports parsable outputs, including JSON. Thanks to Thomas Weißschuh.

If you use systemd credentials system, then agetty(8) and login(1) can follow this system. For now, it's supported for autologin. Thanks to Daan De Meyer.

dmesg(1) parses caller-id from kernel messages and prints it. Thanks to Edward Chron. It can also now print timestamps in multiple formats at the same time for each message (--time-format may be specified more than once). Thanks to Rishabh Thukral.

Sounds strange, but sometimes the goal is to break things :-) For this purpose, we have introduced a new command "enosys". It can call an arbitrary program with disabled syscall. The same functionality provides, for example, strace, but it seems useful to have a tiny dedicated tool for this purpose. For example:

# enosys --syscall ioprio_get ionice ionice: ioprio_get failed: Function not implemented

Thanks to Thomas Weißschuh.

Atomicity matters in many cases. The new small command "exch" can atomically exchange paths between two files. Thanks to Masatake Yamato.

Again, your upstream CI tests have been improved. Every pull request has to pass 32 checks, including a static analyzer, fuzzing, build tests on multiple architectures (including riscv64, s390), and multiple distros (Ubuntu, Fedora). It undergoes building by GCC (versions 13 and 14) and Clang compilers, along with more than 300 regression tests and countless subtests.

And many, many other changes – the Release Notes file has approximately 1160 lines. Thanks to all contributors!



Thursday, June 1, 2023

util-linux v2.39: Improved Mount Interface and Exciting Updates

This release comes with dramatic changes, and the most noticeable change is the support for a new kernel mount API in libmount.

The classic mount(2) system call has been with us since the early days of Linux. This interface is quite simple: you specify the source, target, filesystem options, mount flags, and ask the kernel to do the job. Unfortunately, the interface is too simplistic. These days, attaching a filesystem requires multiple steps, and it's important for userspace to assist in these steps and receive feedback from the kernel after each one.

We are all familiar with the infamous error message:

mount: wrong fs type, bad option, bad superblock on /mnt missing
       codepage or helper program, or other error.

This error message can be quite cryptic. In this case, mount(8) attempted to guess a few possibilities for the EINVAL errno, but nothing seemed relevant, so it prints this error message.

With the new interface, after the syscall fsopen("nonsense", 0), we can inform the user that "mount -t nonsense" is a bad idea.

Please note that you can still see this generic error in mount(8) from v2.39, as the goal for this release was to adopt the new interface. Optimization will come in future releases, so please be patient.

The new kernel mount interface is a set of syscalls that use file descriptors as a glue between them. This kind of interface is open to new extensions (new syscalls), and userspace and filesystem developers don't have to try to explain the entire universe in a comma-separated mount options string.

File descriptors are a game changer. We have a file descriptor to configure the superblock (the filesystem itself) and another file descriptor to set VFS (Virtual File System) node attributes and attach the node to the VFS tree. The file descriptor remains usable even when you change a namespace, etc.

The important thing is that userspace applications (like the mount(8) command) can work with a filesystem that is not yet attached. It means that mount(8) configures the filesystem, sets VFS flags (such as noexec, ...), and then attaches everything to the VFS to make it visible to other processes in the same namespace.

This is elegant, for example, when you need to set VFS flags in multiple steps. You can now set only the node in one step and recursively set all submounts in another step using "ro,noexec=recursive" in the new mount(8).

It also allows previously impossible operations to be mixed together. For example, "mount --move -oro /mnt/A /mnt/B".

Let's delve into the details, for example, the strace output for "mount -t ext4 -o ro /dev/sdc1 /mnt/test":

Classic mount(8):

mount("/dev/sdc1", "/mnt/test", "ext4", MS_RDONLY, NULL);

New interface:

fsopen("ext4", FSOPEN_CLOEXEC) = 3  
fsconfig(3, FSCONFIG_SET_STRING, "source", "/dev/sdc1", 0) = 0 
fsconfig(3, FSCONFIG_SET_FLAG, "ro", NULL, 0) = 0 
fsconfig(3, FSCONFIG_CMD_CREATE, NULL, NULL, 0) = 0 
fsmount(3, FSMOUNT_CLOEXEC, 0) = 4 
mount_setattr(4,"", AT_EMPTY_PATH,{attr_set=MOUNT_ATTR_RDONLY, attr_clr=0, propagation=0}) = 0 
move_mount(4, "", AT_FDCWD, "/mnt/test", MOVE_MOUNT_F_EMPTY_PATH) = 0

The steps in the interface are as follows:

  • Create a filesystem instance with fsopen()
  • Configure the filesystem with fsconfig()
  • Create a VFS node with fsmount()
  • Set VFS flags (e.g., read-only)
  • Attach the node to the tree (now it's visible to others)

Nothing is perfect. This change is so significant that it will take time to make it stable for all use cases. In some cases, the responsibility also lies with the kernel because filesystem drivers have to adopt the new interface as well. For example, btrfs does not work as expected if a SELinux context is specified between mount options, and libmount uses the classic mount(2) in this case.

Another consideration (for libmount) is backward compatibility. Let's imagine you boot an old kernel without the new interface. You probably assume functional mount(8), so libmount has to detect that the new syscalls are not available and switch back to the classic mount(2).

In the future, we could improve the mount(8) command-line interface to better reflect the mount process. Currently, we mix operation requests with mount options (e.g., -o remount,bind,ro). It would be nice to differentiate between VFS and filesystem operations. For example:

VFS operation (set /mnt and subdirectories to ro, exec):

   mount modify /mnt --recursive --set ro --unset noexec
FS operation (set superblock to ro, all instances will be ro):
   mount reconfigure /mnt -o ro 

What do you think about the "mount <oper> [options]" command-line interface?

And here are some other mount/libmount-related changes:

  • The classic writeable /etc/mtab is dead and no longer supported. Rest in peace.
  • Thanks to Christian Brauner, X-mount.idmap= is now supported, allowing you to change the ownership of all files under the mount node in the user's namespace.
  • We often use "auto" as the filesystem type in fstab, right? :-) It means we rely on libblkid/udev. In some cases, this freedom is unwanted. The new option specifies allowed or forbidden filesystem types.
  • mount(8) should now be less invasive and smarter when used on systems with an automounter and unreachable network filesystems. If you're a developer, consider using statx(AT_STATX_DONT_SYNC|AT_NO_AUTOMOUNT) as a replacement for the classic stat() if you only need very basic information about a file or directory.

Util-linux v2.39 is definitely not only about mount(8)/libmount:

  • It's time to learn something new with new commands:
    • blkpr(8) is a new command to run persistent reservations ioctls on a device (typically SCSI and NVMe disk).
    • waitpid(1) is a new command to wait for arbitrary processes.
    • pipesz(1) is a new command to set or examine pipe and FIFO buffer sizes.
  • lsfd(1), a modern Linux-only replacement for lsof, is one of the most actively developed codes in util-linux (thanks to Masatake YAMATO). It's now more user-friendly in the NAME and TYPE columns, supports pidfd, and improves network socket reporting. Try, for example, lsfd --inet -Q '(COMMAND == "systemd")'.
  • libblkid should be more robust, and now it verifies checksums for many RAIDs and filesystems to avoid automatically mounting obsolete or broken superblocks.

Significant changes have also been made to the util-linux test suite and our CI on GitHub. Thanks to Thomas Weißschuh for these and many other improvements.


Tuesday, June 25, 2019

util-linux v2.34 -- what's new?

The code of the popular command lsblk(8) has been completely rewritten. The result is more extendible and readable code. Now lsblk(8) keeps all block devices tree in memory before it's printed. It allows to modify and reorder the tree independently on the way how kernel (/sys filesystem) exports the tree to userspace. The new features based on this change are:
  • devices de-duplication (e.g. lsblk --dedup WWN); this is useful for example on systems with multi-path devices where the same device is accessible by more ways
  • M:N relationships without repeating devices (e.g. lsblk --merge); this feature is implemented by additional tree graph.
For example visualization of really complicated setup; thin provisioning pool with external snapshot (the pool is based on loop0 and it's created by metadata and data devices; the pool and loop1 are used for the snapshot).

$ lsblk --merge
       NAME                 MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
       loop0                  7:0    0 955.7M  0 loop  
   ┌┈▶ ├─test-thin-metadata 253:0    0     2M  0 dm    
   └┬▶ └─test-thin-data     253:1    0 953.7M  0 dm    
┌┈▶ └┈┈test-thin-pool       253:2    0 953.7M  0 dm    
┆      └─test-thin          253:3    0 190.8M  0 dm    
└┬▶    loop1                  7:1    0 190.8M  0 loop  
 └┈┈┈┈┈test-thin-extsnap    253:4    0 190.8M  0 dm    

The same situation with classic lsblk output:

$ lsblk
loop0                     7:0    0 955.7M  0 loop  
├─test-thin-metadata    253:0    0     2M  0 dm    
│ └─test-thin-pool      253:2    0 953.7M  0 dm    
│   ├─test-thin         253:3    0 190.8M  0 dm    
│   └─test-thin-extsnap 253:4    0 190.8M  0 dm    
└─test-thin-data        253:1    0 953.7M  0 dm    
  └─test-thin-pool      253:2    0 953.7M  0 dm    
    ├─test-thin         253:3    0 190.8M  0 dm    
    └─test-thin-extsnap 253:4    0 190.8M  0 dm    
loop1                     7:1    0 190.8M  0 loop  
└─test-thin-extsnap     253:4    0 190.8M  0 dm    

You can see that lsblk repeating test-thin and test-thin-extsnap, and loop1 seems unrelated for the setup at first glance.

The repeating of the block devices in the output is more annoying for multi-path devices. See another example in my previous blog:

I guess that FUSE user will be very happy with v2.34; finally the command umount(8) supports non-root user unmount for FUSE mounts. The requirement is FUSE specific user_id= in /proc/self/mountinfo for the filesystem. So, you do not have to call fuse specific umount tool, just use umount(8) as usually.

The command mount(8) now allows to use "--all -o remount" to remount all filesystems with specified or fstab options. It's possible to use filters (-t and -O).

The new command hardlink has been merged to util-linux. The command consolidates duplicate files via hardlinks. The current implementation is from Fedora, but in the next versions we will reuse also code from Debian fork to create one widely usable implementation.

The command lscpu(1) now prints more information about your CPU, for example 'Frequency boost' and 'Vulnerability' fields. The caches calculation has been modified to print summary from all system caches rather than per code numbers; and new command line option --caches lists details about CPU caches.

... and many another small changes :-) See complete release notes at

Thanks to Sami Kerola, Stanislav Brabec, Ruediger Meier and others!

Thursday, November 8, 2018

lsblk --merge

For uti-linux version v2.34 (next spring) I'm working on new lsblk. The goal is keep all devices as data structs in memory to have ability to modify or reorder the tree.

Now lsblk blindly follows slaves/holders links in /sys and in case of RAIDs or multi-path devices the output contains duplicate lines.

The new version will provide de-duplication (lsblk --dedup WWN) to completely remove unnecessary lines from output.

The another feature is possibility to use libsmartcols to specify group of lines and define children for the group. This allows to describe M:N relationships by chart without duplicate lines in output.

See the next example with one multi-path device and one RAID device.

$ lsblk --merge
      sda           8:0    0 223.6G  0 disk  
      ├─sda1        8:1    0   200M  0 part  /boot/efi
      ├─sda2        8:2    0   200M  0 part  /boot
      ├─sda3        8:3    0 130.3G  0 part  
      ├─sda4        8:4    0    50G  0 part  /
┌┈┄┄▶ └─sda5        8:5    0  42.9G  0 part  
┆     sdb           8:16   0  74.5G  0 disk  
┆     └─sdb1        8:17   0  74.5G  0 part  /home/archive
┆ ┌┈▶ sdc           8:32   0   100M  0 disk  
┆ ├┈▶ sdd           8:48   0   100M  0 disk  
┆ ├┈▶ sde           8:64   0   100M  0 disk  
┆ └┬▶ sdf           8:80   0   100M  0 disk  
┆  └┈┄mpatha      253:0    0   100M  0 mpath 
┆     ├─mpatha1   253:1    0    50M  0 part  
┆     └─mpatha2   253:2    0    49M  0 part  
┆     nvme0n1     259:0    0 223.6G  0 disk  
┆     ├─nvme0n1p1 259:1    0   7.8G  0 part  
┆     ├─nvme0n1p2 259:2    0   200G  0 part  /home
└┬┄┄▶ └─nvme0n1p3 259:3    0  15.8G  0 part  
 └┄┄┈┄md0           9:0    0  15.8G  0 raid1 
      ├─md0p1     259:4    0   100M  0 md    
      └─md0p2     259:5    0  15.7G  0 md    

The original lsblk output:
sda           8:0    0 223.6G  0 disk  
├─sda1        8:1    0   200M  0 part  /boot/efi
├─sda2        8:2    0   200M  0 part  /boot
├─sda3        8:3    0 130.3G  0 part  
├─sda4        8:4    0    50G  0 part  /
└─sda5        8:5    0  42.9G  0 part  
  └─md0       9:0    0  15.8G  0 raid1 
    ├─md0p1 259:4    0   100M  0 md    
    └─md0p2 259:5    0  15.7G  0 md    
sdb           8:16   0  74.5G  0 disk  
└─sdb1        8:17   0  74.5G  0 part  /home/archive
sdc           8:32   0   100M  0 disk  
└─mpatha    253:0    0   100M  0 mpath 
  ├─mpatha1 253:1    0    50M  0 part  
  └─mpatha2 253:2    0    49M  0 part  
sdd           8:48   0   100M  0 disk  
└─mpatha    253:0    0   100M  0 mpath 
  ├─mpatha1 253:1    0    50M  0 part  
  └─mpatha2 253:2    0    49M  0 part  
sde           8:64   0   100M  0 disk  
└─mpatha    253:0    0   100M  0 mpath 
  ├─mpatha1 253:1    0    50M  0 part  
  └─mpatha2 253:2    0    49M  0 part  
sdf           8:80   0   100M  0 disk  
└─mpatha    253:0    0   100M  0 mpath 
  ├─mpatha1 253:1    0    50M  0 part  
  └─mpatha2 253:2    0    49M  0 part  
nvme0n1     259:0    0 223.6G  0 disk  
├─nvme0n1p1 259:1    0   7.8G  0 part  
├─nvme0n1p2 259:2    0   200G  0 part  /home
└─nvme0n1p3 259:3    0  15.8G  0 part  
  └─md0       9:0    0  15.8G  0 raid1 
    ├─md0p1 259:4    0   100M  0 md    
    └─md0p2 259:5    0  15.7G  0 md    

The code is still not ready to merge to the master branch and some cosmetic changes are expected, but the idea is obvious I guess. (If you want to play with it see topic/lsblk branch in util-linux repository.)

Thursday, February 15, 2018

util-linux v2.32 -- what's new?

This release (rc1 now) is without dramatic changes and game-changing improvements.

We have again invested our time and love to make cal(1) more usable. The most visible change is possibility to specify calendar system.

The current (backwardly compatible) default is to use Gregorian calendar and Julian calendar for dates before September 1752 (British Empire calendar reform). Unfortunately, this default is pretty frustrating if you want to use cal(1) for old dates before 1752 and you don't want to follow UK calendar.

The new command line option --reform={Julian,Gregorian,iso,1752,...} allows to specify exclusively calendar system or reform date. The currently supported reform is only UK reform in 1752. In the next versions we will probably add support for another reforms as it's very region specific (for example 1584 in my country, 1873 in Japan and 1926 Turkey, etc.).

Linux kernel supports multi-line log messages. Unfortunately, dmesg(1) support for this feature was insufficient. Now dmesg(1) provides better support and by new command line option --force-prefix allows to to print facility, level or timestamp information to each line of a multi-line message.

The command fallocate(1) --dig-holes has been significantly improved and it's faster more effective now (thanks to Vaclav Dolezal).

The command lscpu(1) provides more details about ARM CPUs now.

The command lsmem(1) supports memory zones now.

The command lsns(8) provides netnsid and nsfs columns now. ip(1) command allows to create network namespace, add logical name and ID for the namespace. Now all is visible by lsns(8). For example copy & past from our regression tests:

        NS TYPE NPROCS   PID USER     NETNSID NSFS                            COMMAND
4026532001 net     281     1 root  unassigned                                 /usr/lib/systemd/systemd --switched-root --system --deserialize 24
4026532400 net       1   795 rtkit unassigned                                 /usr/libexec/rtkit-daemon
4026532590 net       1  6707 root           0 /run/netns/LSNS-TEST-NETNSID-NS dd if=tests/output/lsns/FIFO-NETNSID bs=1 count=2 of=/dev/null

where dd(1) is running in the net namespace, and the namespace is by nsfs mounted on /run/netns/LSNS-TEST-NETNSID-NS. See for more details how to use ip(8) to setup this namespace.

The command rtcwake(8) has been improved to wait stdin to settle down before entering a system sleep. This is important on systems where wireless USB devices (mouse, keyboard, ...) generate "noise" for fraction of a second after rtcwake(8) execution.

The library libblkid has been extended to support LUKS2, Micron mpool, VDO and Atari partition table.

Thanks to all 43 contributors!

The next release v2.33 is planned for May 2018 (yes, the goal is to have 3-4 releases per year rather than 2 releases like in last years).

Thursday, October 19, 2017

util-linux v2.31 -- what's new?

uuidparse -- this is a new small command to get more information about UUIDs "hash". The command provides info about UUID type, variant and time. For example:

$ (uuidgen; uuidgen -t) | uuidparse
UUID                                  VARIANT TYPE       TIME
8f251893-d33a-40f7-9bb3-36988ec77527  DCE     random
66509634-b404-11e7-aa8e-7824af891670  DCE     time-based 2017-10-18 15:01:04,751570+0200

The command su has been refactored and extended to create pseudo terminal for the session (new option --pty). The reason is CVE-2016-2779, but the issue addressed by this CVE is pretty old and all the problem is silently ignored for for years on many places (on only su(1)). The core of the problem is that unprivileged user (within su(1) session) shares terminal file descriptor with original root's session. The new option --pty forces su(1) to create independent pseudo terminal for the session and than su(1) works as proxy between the terminals. The feature is experimental and not enabled by default (you have to use su --pty).

standard su session (all on pts/0):
24909 pts/0    S      0:02          \_ -bash                  
13607 pts/0    S      0:00              \_ su - kzak          
13608 pts/0    S      0:00                  \_ -bash          
13679 pts/0    R+     0:00                      \_ ps af      

su --pty session (root pts/0; user pts/5):
24909 pts/0    S      0:02          \_ -bash                  
13857 pts/0    S+     0:00              \_ su --pty - kzak    
13858 pts/5    Ss     0:00                  \_ -bash          
13921 pts/5    R+     0:00                      \_ ps af      

rfkill -- this is a new command in util-linux. The command was originally written by Johannes Berg and Marcel Holtmann and maintained for years as standalone package. We believe that it's better to maintain and distribute it with another commands on one place. The util-linux version is backwardly compatible with the original implementations. The command has been also improved (libsmartcols ouotput, etc.), the new default output:
# rfkill       
ID TYPE      DEVICE                   SOFT      HARD          
 0 bluetooth tpacpi_bluetooth_sw unblocked unblocked          
 1 wlan      phy0                unblocked unblocked          
 4 bluetooth hci0                  blocked unblocked

The library libuuid and command uuidgen support hash-based UUIDs v3 (md5) and v5 (sha1) as specified by RFC-4122 now. The library also provides UUID templates for dns, url, oid, or x500. For example:
$ uuidgen --sha1  --namespace @dns --name

and it's expected to use v3 and v5 UUIDs as hierarchy, so you can use this UUID (or arbitrary other UUID) as a namespace:
$ uuidgen --sha1  --namespace e361e3ab-32c6-58c4-8f00-01bee1ad27ec --name mystuff

I can imagine system where for example per-user or per-architecture partition UUIDs are based on this system. For example use UUID specific for the system root as --namespace and username as --name, or so. 

wipefs and libblkid have been improved to provide all possible string permutations for a device. It means that wipefs does not return the first detected signature, but it continues and tries another offsets for the signature. This is important for filesystems and partitions tables where the superblock is backuped on multiple places (e.g. GPT) or detectable by multiple independent ways (FATs). This all is possible without a device modification (the old version provides the same, but only in "wipe" mode). 

The libfdisk has been extended to use BLKPG ioctls to inform the kernel about changes. This means that cfdisk and fdisk will not force your kernel to reread all of the partition table, but untouched partitions may remain mounted and used by the system. The typical use-case is resizing the last partition on the system disk. 

You can use cfdisk to resize a partition. Yep, cool.

The hwclock command now significantly reduces system shutdown times by not reading the RTC before setting it (except when the --update-drift option is used). This also mitigates other potential shutdown and RTC setting problems caused by requiring an RTC read.

Friday, June 9, 2017

util-linux v2.30 -- what's new?

The command tailf is dead thing. (RIP ... years ago I had nice time to improve it with inotify:) You have to use "tail -f" from coreutils project.

blkzone -- this new command is excellent example of the open source collaboration. The command has been developed by people from WD, Seagate and SanDisk (thanks to Shaun Tancheff, Damien Le Moal and others). The goal is to have command line interface to run zone commands on block devices that support Zoned Block Commands (ZBC) or Zoned-device ATA Commands (ZAC). For now the supported zone commands are "reset" and "report". See for more details about zones.

fincore (file in core)-- this is nice useful command to get information about number of memory pages used by file content. For example my fulltext email DB:

# fincore ~/Mail/Maildir/.notmuch/xapian/*.DB
 60.1M  15392  4.6G /home/kzak/Mail/Maildir/.notmuch/xapian/position.DB
687.4M 175982  3.5G /home/kzak/Mail/Maildir/.notmuch/xapian/postlist.DB
  328K     82 18.6M /home/kzak/Mail/Maildir/.notmuch/xapian/record.DB
190.5M  48758  2.1G /home/kzak/Mail/Maildir/.notmuch/xapian/termlist.DB

Fortunately RAM is cheap :) Thanks to Masatake Yamato from Red Hat.

lsmem (list memory) and chmem (change memory) -- another new commands. The commands have been originally implemented in Perl for s390-tools, now re-implemented in C in more generic way and to be usable on another architectures too. (thanks to Clemens von Mann and Heiko Carstens from IBM.)

The command fallocate supports an "insert range" operation now.

We continue on hwclock cleanup, some things in the code have been simplified, dead and useless things removed. (thanks to J William Piggott)

The code behind "column -t|--table" uses libsmartcols now. This change dramatically increased number of available features for table formatting. Now it's possible to define header for columns, truncate text in cells, align text to the right, change order of columns, JSON output or create tree-like output. Now almost all libsmartcols features are available on command line, example:
pstree-like output:

 $ ps -h -o pid,ppid,comm | column --table --tree 3 --tree-id 1 --tree-parent 2 --table-hide 2 --table-right 1
 1799  bash
 2254  bash
28427  └─mutt
 4263    └─vim
 7409  bash
10641  └─man
10657    └─less
16775  bash
11486  ├─ps
11487  └─column

 $ column /proc/diskstats --table --table-columns MAJ,MIN,NAME,READ-COMP,\
      --table-hide MAJ,MIN \
      --table-right 4,5,6,7,8,9,10,11,12,13,14 \
sda     13486466     149085  1288469300    9715620    45556082     7788088  1600182109   150180178        0  12935701  159902109
sda1         463        170       19002        131          91           0         161         331        0       334        462
sda2         778         16       63140        276         434         261      507574       12616        0      2382      12889
sda3    10710224     109592  1052352266    8018950    43983768     7022717  1153182094   126210185        0  11002854  134299501
sda4     1630396      32476    67166050    1039837     1197142      665798   343331344    23264993        0   2148041   24306932
sda5     1140435        241   168747746     655625      225373       73891   102920032      637906        0    627834    1293105
sda6        3703       6590       99512        691        4691       25421      240904        8418        0      6402       9108
sdb          448          0       22506       3088        1887           4         128         275        0      1449       3363
sdb1         404          0       19370       3035          12           4         128          60        0      1187       3095
loop0      22086          0      347311       2025       10738           0      844888        2226        0      1129       4265
loop1        947          0       26940        325        1100           0      133316         734        0       411       1058
md8            0          0           0          0           0           0           0           0        0         0          0

passwd in JSON:
 $ grep -v nologin /etc/passwd | \
     column --separator : --table --table-name passwd --json \
            --table-columns USERNAME,PWD,UID,GID,GECOS,HOME,SHELL \
            --table-hide PWD
   "passwd": [
      {"username": "root", "uid": "0", "gid": "0", "gecos": "root", "home": "/root", "shell": "/bin/bash"},
      {"username": "sync", "uid": "5", "gid": "0", "gecos": "sync", "home": "/sbin", "shell": "/bin/sync"},
      {"username": "shutdown", "uid": "6", "gid": "0", "gecos": "shutdown", "home": "/sbin", "shell": "/sbin/shutdown"},
      {"username": "halt", "uid": "7", "gid": "0", "gecos": "halt", "home": "/sbin", "shell": "/sbin/halt"},
      {"username": "kzak", "uid": "1000", "gid": "1000", "gecos": "Karel Zak,Home,,,", "home": "/home/kzak", "shell": "/bin/bash"},
      {"username": "gamer", "uid": "1001", "gid": "1001", "gecos": null, "home": "/home/gamer", "shell": "/bin/bash"},
      {"username": "test", "uid": "1002", "gid": "1002", "gecos": null, "home": "/home/test", "shell": "/bin/bash"}

findmnt-like output:
 $ column /proc/self/mountinfo \
     --table-order TARGET,SOURCE,TYPE,VFS-OPTS \
     --tree TARGET \
     --tree-id ID \
     --tree-parent PARENT
TARGET                             SOURCE       TYPE         VFS-OPTS
/                                  /dev/sda4    ext4         rw,relatime
├─/sys                             sysfs        sysfs        rw,nosuid,nodev,noexec,relatime
│ ├─/sys/kernel/security           securityfs   securityfs   rw,nosuid,nodev,noexec,relatime
│ ├─/sys/fs/cgroup                 tmpfs        tmpfs        ro,nosuid,nodev,noexec
│ │ ├─/sys/fs/cgroup/systemd       cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
│ │ ├─/sys/fs/cgroup/blkio         cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
│ │ ├─/sys/fs/cgroup/cpu,cpuacct   cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
│ │ ├─/sys/fs/cgroup/devices       cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
│ │ ├─/sys/fs/cgroup/hugetlb       cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
│ │ ├─/sys/fs/cgroup/pids          cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
│ │ ├─/sys/fs/cgroup/memory        cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
│ │ ├─/sys/fs/cgroup/cpuset        cgroup       cgroup       rw,nosuid,nodev,noexec,relatime
... and so on ... 
Thanks to all contributors. The next version v2.31 is planned for September 2017.