Subject: Re: readutmp should check for sd_booted() and not if /run/utmp exists

From: Bruno Haible <[email-masked]>
Date: Fri, 15 Sep 2023 14:30:58 +0200

[CCing bug-gnulib, because the readutmp code lives in gnulib]

Thorsten Kukuk wrote:
> if there is no /run/utmp file, /usr/bin/who falls back correctly to the
> systemd-logind interface and shows correct data.
> 
> But there are applications, which don't use the libc interface for
> reading/writing utmp entries, they have their own implementation. And
> this implementations create the file /run/utmp if this does not exist
> (glibc does not). Which means, /usr/bin/who shows sometimes wrong/incomplete
> data.
> 
> procps (especially w) and other packages don't check if /run/utmp exist
> or not, but use sd_booted(). e.g.:
> 
>  if (sd_booted() > 0) {
>     numuser = sd_get_sessions(NULL);
>   } else {
>     setutent();
>     while ((ut = getutent())) {
>       if ((ut->ut_type == USER_PROCESS) && (ut->ut_name[0] != '\0'))
>         numuser++;
>     }
>     endutent();
>   }
> 
> So if logind is running, logind is used, else /run/utmp.
> I think gnulib/coreutils should do the same. It's impossible to find and
> fix all the code writing utmp entries at their own, especially if this
> is 3rd party software and you don't have the source code. 

You are actually talking about three different things:
  (A) Calling sd_booted in addition to calling sd_get_sessions.
  (B) Using the /var/run/utmp file when systemd is not active.
  (C) Using the /var/run/utmp file when systemd is active but some
      applications use old APIs.

About (A)
=========

This is redundant, because when sd_booted() is <= 0, sd_get_sessions returns
NULL. This comes from the implementation, see
https://github.com/systemd/systemd/blob/main/src/libsystemd/sd-daemon/sd-daemon.c#L716

About (B)
=========

Is there any distro which has libsystemd installed (so that coreutils could
be built with -lsystemd) but where a different init system is used at boot time?

If not, the suggestion is pointless.

About (C)
=========

This is not the same as (B), because the existence of an "application" that uses
old APIs does not mean that sd_booted() will return <= 0.

> But there are applications, which don't use the libc interface for
> reading/writing utmp entries, they have their own implementation.

Which are these applications? The best approach is, obviously, to modernize
these applications by sending them patches. codesearch.debian.net is your
friend.

> It's impossible to find and
> fix all the code writing utmp entries at their own, especially if this
> is 3rd party software and you don't have the source code.

We should not let proprietary 3rd-party software prevent us from modernizing
the GNU system. This is the stance that the Linux kernel has taken more than
20 years ago, by defining a formal interface for kernel modules. If some
proprietary applications cause trouble, then the best approach is to ignore
it and thus increase the users' will to replace these proprietary applications
with free software.

A temporary proposal
====================

It is possible that, to get best results in the situation you describe, as
long as some applications use the old APIs, it is needed for readutmp to
combine (not choose among) the two approaches.

The best way to determine if this is true, IMO, would be to
  1) turn the compile-time switch in lib/readutmp.c:942 into a run-time switch.
  2) Add a '--traditional' option to 'who', 'pinky', 'uptime'.
  3) Wait for users to report problems, that is, situations where `who` and
     `who --traditional` disagree, with precise description of the problems.

Paul, Pádraig, what do you think?

Bruno